/* elmo - ELectronic Mail Operator Copyright (C) 2003, 2004 rzyjontko This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ---------------------------------------------------------------------- Different sring manipulation routines. */ /**************************************************************************** * IMPLEMENTATION HEADERS ****************************************************************************/ #include #include #include #include "eprintf.h" #include "mail.h" #include "xmalloc.h" #include "wrapbox.h" #include "misc.h" #include "keymap.h" #include "str.h" #include "gettext.h" #include "mime.h" #include "rstring.h" #include "property.h" /**************************************************************************** * IMPLEMENTATION PRIVATE DEFINITIONS / ENUMERATIONS / SIMPLE TYPEDEFS ****************************************************************************/ #define FIRST_ALLOC 20 enum justify { JUSTIFY_LEFT = 0, JUSTIFY_RIGHT = 1}; /**************************************************************************** * IMPLEMENTATION PRIVATE CLASS PROTOTYPES / EXTERNAL CLASS REFERENCES ****************************************************************************/ /**************************************************************************** * IMPLEMENTATION PRIVATE STRUCTURES / UTILITY CLASSES ****************************************************************************/ /** * This structure describes formatting sequence (i.e. %-020n) * everything between % and the first letter is used to format * a string. * In the example above -020 means that we want the desired string * be exactly 20 characters long, filled with spaces (leading 0), * and justified to right (dash). * * To be more precise: * len = 20 * character = 'n' * fill = YES * justify = JUSTIFY_RIGHT */ struct fmt_seq { int fs_len; int len; char character; struct { enum yes_no fill : 1; enum justify justify : 1; } flags; }; /**************************************************************************** * IMPLEMENTATION REQUIRED EXTERNAL REFERENCES (AVOID) ****************************************************************************/ /**************************************************************************** * IMPLEMENTATION PRIVATE DATA ****************************************************************************/ /**************************************************************************** * INTERFACE DATA ****************************************************************************/ /**************************************************************************** * IMPLEMENTATION PRIVATE FUNCTION PROTOTYPES ****************************************************************************/ /**************************************************************************** * IMPLEMENTATION PRIVATE FUNCTIONS ****************************************************************************/ static void eval_fmt_seq (struct fmt_seq *fs, const char *s) { char *rest; fs->fs_len = 0; fs->len = 0; fs->character = '\0'; fs->flags.fill = NO; fs->flags.justify = JUSTIFY_LEFT; if (*s != '%') return; s++; if (*s == '-'){ fs->flags.justify = JUSTIFY_RIGHT; s++; fs->fs_len++; } if (*s == '0'){ fs->flags.fill = YES; s++; fs->fs_len++; } if (isdigit (*s)){ fs->len = strtol (s, &rest, 10); if (rest) fs->fs_len += rest - s; s = rest; } fs->character = *s; fs->fs_len++; } static void put_string_fs (str_t *s, const char *t, struct fmt_seq *fs) { int spaces; int t_len; int w_len; if (fs->len < 0) fs->len = 0; if (! t) t = ""; t_len = strlen (t); if (t_len <= fs->len){ w_len = t_len; spaces = fs->len - t_len; } else if (fs->len != 0){ w_len = fs->len; spaces = 0; } else { w_len = t_len; spaces = 0; } if (fs->flags.justify == JUSTIFY_LEFT){ str_put_string_len (s, t, w_len); if (fs->flags.fill) str_put_nchar (s, ' ', spaces); } else { if (fs->flags.fill) str_put_nchar (s, ' ', spaces); str_put_string_len (s, t, w_len); } } /** * Suppose a mail: * From: Johnny Masta Killa * To: Bob The Ripper * Subject: Bow before me! * Date: Wed, 7 May 2003 15:36:46 +0200 * */ static int put_mail_special (str_t *s, const char *fmt, mail_t *mail) { int size; char *date; struct fmt_seq fs; eval_fmt_seq (&fs, fmt); switch (fs.character){ case '%': str_put_char (s, '%'); break; /* Johnny Masta Killa */ case 'f': put_string_fs (s, address_name (mail->from), &fs); break; /* Johnny Masta Killa */ case 'F': if (mail->from) put_string_fs (s, mail->from->full, &fs); else put_string_fs (s, NULL, &fs); break; /* Bob The Ripper */ case 't': if (mail->to) put_string_fs (s, address_name (mail->to->array[0]), &fs); else put_string_fs (s, NULL, &fs); break; /* Bob The Ripper */ case 'T': if (mail->to && mail->to->count) put_string_fs (s, mail->to->array[0]->full, &fs); else put_string_fs (s, NULL, &fs); break; /* Wed, 7 May 2003 15:36:46 +0200 */ case 'd': put_string_fs (s, mail->date_str, &fs); break; /* 07 May */ case 'D': date = date_string ("%b %d", mail->date); put_string_fs (s, date, &fs); xfree (date); break; /* Bow before me! */ case 's': put_string_fs (s, mail->subject, &fs); break; /* JMK */ case 'i': if (mail->from) put_string_fs (s, mail->from->initials, &fs); else put_string_fs (s, NULL, &fs); break; /* (3.5K) */ case 'S': size = wrapbox_mail_size (mail); put_string_fs (s, human_size (size), &fs); break; /* these are flags */ case '$': if (mail->flags & FLAG_FLAGGED) str_put_char (s, 'F'); else if (mail->flags & FLAG_READ) str_put_char (s, ' '); else if (mail->flags & FLAG_OLD) str_put_char (s, 'O'); else str_put_char (s, 'N'); if (mail->flags & FLAG_TRASHED) str_put_char (s, 'D'); else if (mail->flags & FLAG_FETCHED) str_put_char (s, 'F'); else if (mail->flags & FLAG_ANSWERED) str_put_char (s, 'r'); else if (mail->flags & FLAG_PASSED) str_put_char (s, 'f'); else str_put_char (s, ' '); break; /* attachments indicator */ case '?': str_put_char (s, mime_attachment_indicator (mail->mime)); break; /* spam indicator */ case '#': if (mail->flags & FLAG_SPAM) str_put_char (s, '#'); else if (mail->flags & FLAG_LEGITIMATE || mail->flags & FLAG_NOSPAM) str_put_char (s, ' '); else str_put_char (s, '?'); break; } return fs.fs_len; } static int put_mail_special_desc (str_t *s, const char *fmt) { struct fmt_seq fs; eval_fmt_seq (&fs, fmt); switch (fs.character){ case '%': str_put_char (s, '%'); break; case 'f': case 'F': put_string_fs (s, _("From"), &fs); break; case 't': case 'T': put_string_fs (s, _("To"), &fs); break; case 'd': case 'D': put_string_fs (s, _("Date "), &fs); break; case 's': put_string_fs (s, _("Subject"), &fs); break; case 'i': put_string_fs (s, _("Initials"), &fs); break; case 'S': put_string_fs (s, _("Size"), &fs); break; case '$': str_put_string_len (s, " ", 2); break; case '?': str_put_char (s, ' '); break; case '#': str_put_char (s, ' '); break; } return fs.fs_len; } static int put_command_special (str_t *s, const char *fmt, const eprintf_command_t *cmd) { struct fmt_seq fs; eval_fmt_seq (&fs, fmt); switch (fs.character){ case '%': str_put_char (s, '%'); break; case 'p': put_string_fs (s, cmd->command, & fs); break; case 'f': put_string_fs (s, cmd->fname, & fs); break; case 'm': put_string_fs (s, cmd->mime_type, & fs); break; case 'l': str_sprintf (s, "%d", cmd->lineno); break; case 'c': str_sprintf (s, "%d", cmd->col); break; case 'o': str_sprintf (s, "%d", cmd->pos); break; } return fs.fs_len; } static int put_addr_special (str_t *s, const char *fmt, address_t *addr) { char *tmp; struct fmt_seq fs; eval_fmt_seq (&fs, fmt); switch (fs.character){ case '%': str_put_char (s, '%'); break; case 'n': put_string_fs (s, addr->name, &fs); break; case 'e': put_string_fs (s, addr->email, &fs); break; case 'o': if (addr->flags.bits.official) str_put_char (s, 'o'); else str_put_char (s, ' '); break; case 'f': if (addr->flags.bits.foreign) str_put_char (s, 'f'); else str_put_char (s, ' '); break; case 's': if (addr->flags.bits.sex == SEX_MALE) str_put_char (s, 'M'); else if (addr->flags.bits.sex == SEX_FEMALE) str_put_char (s, 'F'); else str_put_char (s, '?'); break; case 'g': if (addr->groups == NULL) put_string_fs (s, NULL, & fs); else { tmp = rstring_flatten (addr->groups, ", "); put_string_fs (s, tmp, & fs); xfree (tmp); } break; } return fs.fs_len; } static int put_addr_desc_special (str_t *s, const char *fmt) { struct fmt_seq fs; eval_fmt_seq (& fs, fmt); switch (fs.character){ case '%': str_put_char (s, '%'); break; case 'n': put_string_fs (s, _("Name"), & fs); break; case 'e': put_string_fs (s, _("Email"), & fs); break; case 'o': str_put_char (s, ' '); break; case 'f': str_put_char (s, ' '); break; case 's': str_put_char (s, ' '); break; case 'g': put_string_fs (s, _("Groups"), & fs); break; } return fs.fs_len; } static int put_key_special (str_t *s, const char *fmt, struct key *key, int meta) { struct fmt_seq fs; eval_fmt_seq (&fs, fmt); switch (fs.character){ case '%': str_put_char (s, '%'); break; case 'k': if (key == NULL) put_string_fs (s, NULL, & fs); else put_string_fs (s, key2string (key->key, meta), &fs); break; case 'f': if (key == NULL || key->exec == NULL) put_string_fs (s, NULL, & fs); else put_string_fs (s, key->exec->name, &fs); break; case 'd': if (key == NULL || key->exec == NULL) put_string_fs (s, NULL, & fs); else put_string_fs (s, key->exec->desc, &fs); break; } return fs.fs_len; } static int put_box_special (str_t *s, const char *fmt, const char *box) { int unread; char buf[16]; struct fmt_seq fs; eval_fmt_seq (& fs, fmt); switch (fs.character){ case '%': str_put_char (s, '%'); break; case 'n': put_string_fs (s, box, & fs); break; case 't': sprintf (buf, "%d", wrapbox_box_mail_count (box, NULL)); put_string_fs (s, buf, & fs); break; case 'u': wrapbox_box_mail_count (box, & unread); sprintf (buf, "%d", unread); put_string_fs (s, buf, & fs); break; } return fs.fs_len; } static int put_mime_special (str_t *s, const char *fmt, mime_t *mime) { char *fname; char *enc; char *type; struct fmt_seq fs; eval_fmt_seq (& fs, fmt); switch (fs.character){ case '%': str_put_char (s, '%'); break; case 'f': if (mime->file_name == NULL) fname = ""; else { fname = strrchr (mime->file_name, '/'); if (fname) fname++; else fname = mime->file_name; } put_string_fs (s, fname, & fs); break; case 't': type = (mime->type) ? mime->type : "text/plain"; put_string_fs (s, type, & fs); break; case 's': put_string_fs (s, human_size (mime->off_end - mime->off_start), & fs); break; case 'c': if (mime->charset) put_string_fs (s, mime->charset, & fs); break; case 'C': if (mime->charset){ str_put_char (s, ','); str_put_char (s, ' '); fs.len -= 2; put_string_fs (s, mime->charset, & fs); } break; case 'e': put_string_fs (s, mime_encoding_str (mime), & fs); break; case 'E': enc = mime_encoding_str (mime); if (enc && *enc){ str_put_char (s, ','); str_put_char (s, ' '); fs.len -= 2; put_string_fs (s, enc, & fs); } break; } return fs.fs_len; } static int put_rstring_special (str_t *s, const char *fmt, rstring_t *values) { int num; char *txt; struct fmt_seq fs; eval_fmt_seq (& fs, fmt); if (islower (fs.character)){ num = fs.character - 'a'; if (num < values->count){ txt = property_get (values->array[num]); put_string_fs (s, txt, & fs); xfree (txt); } } else { switch (fs.character){ case '%': str_put_char (s, '%'); break; } } return fs.fs_len; } static void substitute_mail (const char *fmt, mail_t *mail, str_t *str) { int fs_len; const char *seek; for (seek = fmt; *seek; seek++){ if (*seek == '%'){ fs_len = put_mail_special (str, seek, mail); seek += fs_len; } else str_put_char (str, *seek); } } static void substitute_mail_desc (const char *fmt, str_t *str) { int fs_len; const char *seek; for (seek = fmt; *seek; seek++){ if (*seek == '%'){ fs_len = put_mail_special_desc (str, seek); seek += fs_len; } else str_put_char (str, *seek); } str_put_string (str, _("Subject")); } static char * substitute_command (const char *fmt, const eprintf_command_t *cmd) { int fs_len; const char *seek; str_t *str = str_create (); for (seek = fmt; *seek; seek++){ if (*seek == '%'){ fs_len = put_command_special (str, seek, cmd); seek += fs_len; } else str_put_char (str, *seek); } return str_finished (str); } static void substitute_addr (const char *fmt, address_t *addr, str_t *str) { int fs_len; const char *seek; for (seek = fmt; *seek; seek++){ if (*seek == '%'){ fs_len = put_addr_special (str, seek, addr); seek += fs_len; } else str_put_char (str, *seek); } } static void substitute_addr_desc (const char *fmt, str_t *str) { int fs_len; const char *seek; for (seek = fmt; *seek; seek++){ if (*seek == '%'){ fs_len = put_addr_desc_special (str, seek); seek += fs_len; } else str_put_char (str, *seek); } } static char * substitute_key (const char *fmt, struct key *key, int meta) { str_t *str = str_create (); int fs_len; const char *seek; for (seek = fmt; *seek; seek++){ if (*seek == '%'){ fs_len = put_key_special (str, seek, key, meta); seek += fs_len; } else str_put_char (str, *seek); } return str_finished (str); } static void substitute_box (const char *fmt, const char *box, str_t *str) { const char *seek; int fs_len; for (seek = fmt; *seek; seek++){ if (*seek == '%'){ fs_len = put_box_special (str, seek, box); seek += fs_len; } else str_put_char (str, *seek); } } static void substitute_mime (const char *fmt, mime_t *mime, str_t *str) { const char *seek; int fs_len; for (seek = fmt; *seek; seek++){ if (*seek == '%'){ fs_len = put_mime_special (str, seek, mime); seek += fs_len; } else str_put_char (str, *seek); } } static char * substitute_rstring (const char *fmt, rstring_t *values) { str_t *str = str_create (); int fs_len; const char *seek; for (seek = fmt; *seek; seek++){ if (*seek == '%'){ fs_len = put_rstring_special (str, seek, values); seek += fs_len; } else str_put_char (str, *seek); } return str_finished (str); } /**************************************************************************** * INTERFACE FUNCTIONS ****************************************************************************/ void eprintf_mail_str (const char *fmt, mail_t *mail, str_t *str) { str_clear (str); substitute_mail (fmt, mail, str); } char * eprintf_mail (const char *fmt, mail_t *mail) { str_t *str = str_create (); substitute_mail (fmt, mail, str); return str_finished (str); } void eprintf_mail_desc (const char *fmt, str_t *str) { str_clear (str); substitute_mail_desc (fmt, str); } char * eprintf_command (const char *fmt, const eprintf_command_t *cmd) { char *result; result = substitute_command (fmt, cmd); return result; } void eprintf_addr_str (const char *fmt, address_t *addr, str_t *str) { str_clear (str); substitute_addr (fmt, addr, str); } void eprintf_addr_desc (const char *fmt, str_t *str) { str_clear (str); substitute_addr_desc (fmt, str); } char * eprintf_key (const char *fmt, struct key *key, int meta) { char *result; result = substitute_key (fmt, key, meta); return result; } void eprintf_box_str (const char *fmt, const char *box, str_t *str) { str_clear (str); substitute_box (fmt, box, str); } void eprintf_mime_str (const char *fmt, mime_t *mime, str_t *str) { str_clear (str); substitute_mime (fmt, mime, str); } char * eprintf_rstring (const char *fmt, rstring_t *values) { char *result; result = substitute_rstring (fmt, values); return result; } /**************************************************************************** * INTERFACE CLASS BODIES ****************************************************************************/ /**************************************************************************** * * END MODULE eprintf.c * ****************************************************************************/