X-Git-Url: http://git.madism.org/?p=apps%2Fmadmutt.git;a=blobdiff_plain;f=muttlib.c;h=9afd5cd6dd04c717037ae4713934b9e97a0d7859;hp=4efa41b3be8db273828b18cda73111275b12d249;hb=f3cbb9f51357972f6e74244494236a41dc4d84cd;hpb=e131de5b5f40e0a4100a17cf128ba56424003176 diff --git a/muttlib.c b/muttlib.c index 4efa41b..9afd5cd 100644 --- a/muttlib.c +++ b/muttlib.c @@ -8,56 +8,28 @@ * please see the file GPL in the top level source directory. */ -#if HAVE_CONFIG_H -# include "config.h" -#endif +#include + +#include +#include + +#include +#include +#include +#include +#include +#include "alias.h" #include "mutt.h" -#include "ascii.h" -#include "buffer.h" -#include "enter.h" -#include "mutt_curses.h" -#include "mime.h" -#include "mx.h" -#include "url.h" #include "attach.h" -#include "reldate.h" #include "version.h" -#ifdef USE_IMAP -#include "imap.h" -#include "imap/mx_imap.h" -#endif - -#include "mutt_crypt.h" - -#include "lib/mem.h" -#include "lib/intl.h" -#include "lib/str.h" -#include "lib/debug.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -BODY *mutt_new_body (void) -{ - BODY *p = (BODY *) mem_calloc (1, sizeof (BODY)); +#include - p->disposition = DISPATTACH; - p->use_disp = 1; - return (p); -} +#include +#define SW (option(OPTMBOXPANE)?SidebarWidth:0) /* Modified by blong to accept a "suggestion" for file name. If * that file exists, then construct one with unique name but @@ -65,639 +37,168 @@ BODY *mutt_new_body (void) * Renamed to mutt_adv_mktemp so I only have to change where it's * called, and not all possible cases. */ -void mutt_adv_mktemp (const char* dir, char *s, size_t l) +void mutt_adv_mktemp (const char* dir, char *s, ssize_t l) { - char buf[_POSIX_PATH_MAX]; - char tmp[_POSIX_PATH_MAX]; - char *period; - size_t sl; - struct stat sb; - - strfcpy (buf, dir && *dir ? dir : NONULL (Tempdir), sizeof (buf)); - mutt_expand_path (buf, sizeof (buf)); - if (s[0] == '\0') { - snprintf (s, l, "%s/muttXXXXXX", buf); - mktemp (s); - } - else { - strfcpy (tmp, s, sizeof (tmp)); - mutt_sanitize_filename (tmp, 1); - snprintf (s, l, "%s/%s", buf, tmp); - if (lstat (s, &sb) == -1 && errno == ENOENT) - return; - if ((period = strrchr (tmp, '.')) != NULL) - *period = 0; - snprintf (s, l, "%s/%s.XXXXXX", buf, tmp); - mktemp (s); - if (period != NULL) { - *period = '.'; - sl = str_len (s); - strfcpy (s + sl, period, l - sl); - } - } -} - -/* create a send-mode duplicate from a receive-mode body */ - -int mutt_copy_body (FILE * fp, BODY ** tgt, BODY * src) -{ - char tmp[_POSIX_PATH_MAX]; - BODY *b; - - PARAMETER *par, **ppar; - - short use_disp; - - if (src->filename) { - use_disp = 1; - strfcpy (tmp, src->filename, sizeof (tmp)); - } - else { - use_disp = 0; - tmp[0] = '\0'; - } + int fd; - mutt_adv_mktemp (NULL, tmp, sizeof (tmp)); - if (mutt_save_attachment (fp, src, tmp, 0, NULL) == -1) - return -1; - - *tgt = mutt_new_body (); - b = *tgt; - - memcpy (b, src, sizeof (BODY)); - b->parts = NULL; - b->next = NULL; - - b->filename = str_dup (tmp); - b->use_disp = use_disp; - b->unlink = 1; - - if (mutt_is_text_part (b)) - b->noconv = 1; - - b->xtype = str_dup (b->xtype); - b->subtype = str_dup (b->subtype); - b->form_name = str_dup (b->form_name); - b->filename = str_dup (b->filename); - b->d_filename = str_dup (b->d_filename); - b->description = str_dup (b->description); - - /* - * we don't seem to need the HEADER structure currently. - * XXX - this may change in the future - */ - - if (b->hdr) - b->hdr = NULL; - - /* copy parameters */ - for (par = b->parameter, ppar = &b->parameter; par; - ppar = &(*ppar)->next, par = par->next) { - *ppar = mutt_new_parameter (); - (*ppar)->attribute = str_dup (par->attribute); - (*ppar)->value = str_dup (par->value); - } - - mutt_stamp_attachment (b); - - return 0; -} - - - -void mutt_free_body (BODY ** p) -{ - BODY *a = *p, *b; - - while (a) { - b = a; - a = a->next; - - if (b->parameter) - mutt_free_parameter (&b->parameter); - if (b->unlink && b->filename) { - debug_print (1, ("unlinking %s.\n", b->filename)); - unlink (b->filename); + fd = m_tempfd(s, l, m_strisempty(dir) ? NONULL(Tempdir) : dir, s); + if (fd < 0) { + *s = '\0'; + } else { + close(fd); + unlink(s); } - else if (b->filename) - debug_print (1, ("not unlinking %s.\n", b->filename)); - - mem_free (&b->filename); - mem_free (&b->content); - mem_free (&b->xtype); - mem_free (&b->subtype); - mem_free (&b->description); - mem_free (&b->form_name); - - if (b->hdr) { - /* Don't free twice (b->hdr->content = b->parts) */ - b->hdr->content = NULL; - mutt_free_header (&b->hdr); - } - - if (b->parts) - mutt_free_body (&b->parts); - - mem_free (&b); - } - - *p = 0; -} - -void mutt_free_parameter (PARAMETER ** p) -{ - PARAMETER *t = *p; - PARAMETER *o; - - while (t) { - mem_free (&t->attribute); - mem_free (&t->value); - o = t; - t = t->next; - mem_free (&o); - } - *p = 0; -} - -HEADER *mutt_dup_header (HEADER * h) -{ - HEADER *hnew; - - hnew = mutt_new_header (); - memcpy (hnew, h, sizeof (HEADER)); - return hnew; -} - -void mutt_free_header (HEADER ** h) -{ - if (!h || !*h) - return; - mutt_free_envelope (&(*h)->env); - mutt_free_body (&(*h)->content); - mem_free (&(*h)->maildir_flags); - mem_free (&(*h)->tree); - mem_free (&(*h)->path); -#ifdef MIXMASTER - mutt_free_list (&(*h)->chain); -#endif -#if defined USE_POP || defined USE_IMAP || defined USE_NNTP - mem_free (&(*h)->data); -#endif - mem_free (h); } /* returns true if the header contained in "s" is in list "t" */ -int mutt_matches_ignore (const char *s, LIST * t) +int mutt_matches_ignore (const char *s, string_list_t * t) { for (; t; t = t->next) { - if (!ascii_strncasecmp (s, t->data, str_len (t->data)) + if (!ascii_strncasecmp (s, t->data, m_strlen(t->data)) || *t->data == '*') return 1; } return 0; } -/* prepend the path part of *path to *link */ -void mutt_expand_link (char *newpath, const char *path, const char *link) +ssize_t _mutt_expand_path(char *s, ssize_t slen, int rx) { - const char *lb = NULL; - size_t len; + char p[_POSIX_PATH_MAX] = ""; + char tmp[_POSIX_PATH_MAX]; + const char *tail = ""; - /* link is full path */ - if (*link == '/') { - strfcpy (newpath, link, _POSIX_PATH_MAX); - return; - } - - if ((lb = strrchr (path, '/')) == NULL) { - /* no path in link */ - strfcpy (newpath, link, _POSIX_PATH_MAX); - return; - } - - len = lb - path + 1; - memcpy (newpath, path, len); - strfcpy (newpath + len, link, _POSIX_PATH_MAX - len); -} + do { + const address_t *alias; -char *mutt_expand_path (char *s, size_t slen) -{ - return _mutt_expand_path (s, slen, 0); -} - -char *_mutt_expand_path (char *s, size_t slen, int rx) -{ - char p[_POSIX_PATH_MAX] = ""; - char q[_POSIX_PATH_MAX] = ""; - char tmp[_POSIX_PATH_MAX]; - char *t; + switch (*s) { + case '~': + if (s[1] == '/' || s[1] == '\0') { + m_strcpy(p, sizeof(p), Homedir); + tail = s + 1; + } else { + struct passwd *pw; + tail = m_strchrnul(s + 1, '/'); - char *tail = ""; + m_strncpy(tmp, sizeof(tmp), s + 1, tail - s - 1); - int recurse = 0; + if ((pw = getpwnam(tmp))) { + m_strcpy(p, sizeof(p), pw->pw_dir); + } else { + /* user not found! */ + tail = s; + } + } + break; + + case '=': + case '+': + /* if folder = imap[s]://host/: don't append slash */ + if (imap_is_magic(NONULL(Maildir), NULL) == M_IMAP + && Maildir[m_strlen(Maildir) - 1] == '/') { + m_strcpy(p, sizeof(p), Maildir); + } else { + snprintf(p, sizeof(p), "%s/", NONULL(Maildir)); + } - do { - recurse = 0; + tail = s + 1; + break; + + /* elm compatibility, @ expands alias to user name */ + + case '@': + if ((alias = alias_lookup(s + 1))) { + HEADER h; + header_init(&h); + h.env = envelope_new(); + h.env->from = h.env->to = (address_t *)alias; + mutt_default_save(p, sizeof (p), &h); + h.env->from = h.env->to = NULL; + header_wipe(&h); + + if (*p != '@') { + /* recurse iff the result do not starts with '@' */ + m_strcpy(s, slen, p); + continue; + } + } + break; + + case '>': + m_strcpy(p, sizeof(p), Inbox); + tail = s + 1; + break; + + case '<': + m_strcpy(p, sizeof(p), Outbox); + tail = s + 1; + break; + + case '!': + if (s[1] == '!') { + m_strcpy(p, sizeof(p), LastFolder); + tail = s + 2; + } else { + m_strcpy(p, sizeof(p), Spoolfile); + tail = s + 1; + } + break; - switch (*s) { - case '~': - { - if (*(s + 1) == '/' || *(s + 1) == 0) { - strfcpy (p, NONULL (Homedir), sizeof (p)); - tail = s + 1; - } - else { - struct passwd *pw; + case '-': + m_strcpy(p, sizeof(p), NONULL(LastFolder)); + tail = s + 1; + break; - if ((t = strchr (s + 1, '/'))) - *t = 0; + case '^': + m_strcpy(p, sizeof(p), NONULL(CurrentFolder)); + tail = s + 1; + break; - if ((pw = getpwnam (s + 1))) { - strfcpy (p, pw->pw_dir, sizeof (p)); - if (t) { - *t = '/'; - tail = t; - } - else - tail = ""; - } - else { - /* user not found! */ - if (t) - *t = '/'; + default: *p = '\0'; tail = s; - } - } - } - break; - - case '=': - case '+': - { -#ifdef USE_IMAP - /* if folder = imap[s]://host/: don't append slash */ - if (imap_is_magic (NONULL (Maildir), NULL) == M_IMAP && - Maildir[str_len (Maildir) - 1] == '/') - strfcpy (p, NONULL (Maildir), sizeof (p)); - else -#endif - snprintf (p, sizeof (p), "%s/", NONULL (Maildir)); - - tail = s + 1; - } - break; - - /* elm compatibility, @ expands alias to user name */ - - case '@': - { - HEADER *h; - ADDRESS *alias; - - if ((alias = mutt_lookup_alias (s + 1))) { - h = mutt_new_header (); - h->env = mutt_new_envelope (); - h->env->from = h->env->to = alias; - mutt_default_save (p, sizeof (p), h); - h->env->from = h->env->to = NULL; - mutt_free_header (&h); - /* Avoid infinite recursion if the resulting folder starts with '@' */ - if (*p != '@') - recurse = 1; - - tail = ""; } - } - break; - - case '>': - { - strfcpy (p, NONULL (Inbox), sizeof (p)); - tail = s + 1; - } - break; - - case '<': - { - strfcpy (p, NONULL (Outbox), sizeof (p)); - tail = s + 1; - } - break; - - case '!': - { - if (*(s + 1) == '!') { - strfcpy (p, NONULL (LastFolder), sizeof (p)); - tail = s + 2; - } - else { - strfcpy (p, NONULL (Spoolfile), sizeof (p)); - tail = s + 1; - } - } - break; - - case '-': - { - strfcpy (p, NONULL (LastFolder), sizeof (p)); - tail = s + 1; - } - break; - - case '^': - { - strfcpy (p, NONULL (CurrentFolder), sizeof (p)); - tail = s + 1; - } - break; - - default: - { - *p = '\0'; - tail = s; - } + } while (0); + + if (rx) { + char q[_POSIX_PATH_MAX]; + rx_sanitize_string(q, sizeof(q), p); + snprintf(tmp, sizeof(tmp), "%s%s", q, tail); + } else { + snprintf(tmp, sizeof(tmp), "%s%s", p, tail); } - if (rx && *p && !recurse) { - mutt_rx_sanitize_string (q, sizeof (q), p); - snprintf (tmp, sizeof (tmp), "%s%s", q, tail); - } - else - snprintf (tmp, sizeof (tmp), "%s%s", p, tail); - - strfcpy (s, tmp, slen); - } - while (recurse); - - return (s); + return m_strcpy(s, slen, tmp); } -/* Extract the real name from /etc/passwd's GECOS field. - * When set, honor the regular expression in GecosMask, - * otherwise assume that the GECOS field is a - * comma-separated list. - * Replace "&" by a capitalized version of the user's login - * name. - */ - -char *mutt_gecos_name (char *dest, size_t destlen, struct passwd *pw) +void mutt_mktemp(char *s) { - regmatch_t pat_match[1]; - size_t pwnl; - int idx; - char *p; - - if (!pw || !pw->pw_gecos) - return NULL; - - memset (dest, 0, destlen); - - if (GecosMask.rx) { - if (regexec (GecosMask.rx, pw->pw_gecos, 1, pat_match, 0) == 0) - strfcpy (dest, pw->pw_gecos + pat_match[0].rm_so, - MIN (pat_match[0].rm_eo - pat_match[0].rm_so + 1, destlen)); - } - else if ((p = strchr (pw->pw_gecos, ','))) - strfcpy (dest, pw->pw_gecos, MIN (destlen, p - pw->pw_gecos + 1)); - else - strfcpy (dest, pw->pw_gecos, destlen); - - pwnl = str_len (pw->pw_name); - - for (idx = 0; dest[idx]; idx++) { - if (dest[idx] == '&') { - memmove (&dest[idx + pwnl], &dest[idx + 1], - MAX (destlen - idx - pwnl - 1, 0)); - memcpy (&dest[idx], pw->pw_name, MIN (destlen - idx - 1, pwnl)); - dest[idx] = toupper ((unsigned char) dest[idx]); + int fd = m_tempfd(s, _POSIX_PATH_MAX, NONULL(Tempdir), NULL); + if (fd < 0) { + *s = '\0'; + } else { + close(fd); + unlink(s); } - } - - return dest; -} - - -char *mutt_get_parameter (const char *s, PARAMETER * p) -{ - for (; p; p = p->next) - if (ascii_strcasecmp (s, p->attribute) == 0) - return (p->value); - - return NULL; -} - -void mutt_set_parameter (const char *attribute, const char *value, - PARAMETER ** p) -{ - PARAMETER *q; - - if (!value) { - mutt_delete_parameter (attribute, p); - return; - } - - for (q = *p; q; q = q->next) { - if (ascii_strcasecmp (attribute, q->attribute) == 0) { - str_replace (&q->value, value); - return; - } - } - - q = mutt_new_parameter (); - q->attribute = str_dup (attribute); - q->value = str_dup (value); - q->next = *p; - *p = q; -} - -void mutt_delete_parameter (const char *attribute, PARAMETER ** p) -{ - PARAMETER *q; - - for (q = *p; q; p = &q->next, q = q->next) { - if (ascii_strcasecmp (attribute, q->attribute) == 0) { - *p = q->next; - q->next = NULL; - mutt_free_parameter (&q); - return; - } - } -} - -/* returns 1 if Mutt can't display this type of data, 0 otherwise */ -int mutt_needs_mailcap (BODY * m) -{ - switch (m->type) { - case TYPETEXT: - - if (!ascii_strcasecmp ("plain", m->subtype) || - !ascii_strcasecmp ("rfc822-headers", m->subtype) || - !ascii_strcasecmp ("enriched", m->subtype)) - return 0; - break; - - case TYPEAPPLICATION: - if ((WithCrypto & APPLICATION_PGP) && mutt_is_application_pgp (m)) - return 0; - if ((WithCrypto & APPLICATION_SMIME) && mutt_is_application_smime (m)) - return 0; - break; - - case TYPEMULTIPART: - case TYPEMESSAGE: - return 0; - } - - return 1; -} - -int mutt_is_text_part (BODY * b) -{ - int t = b->type; - char *s = b->subtype; - - if ((WithCrypto & APPLICATION_PGP) && mutt_is_application_pgp (b)) - return 0; - - if (t == TYPETEXT) - return 1; - - if (t == TYPEMESSAGE) { - if (!ascii_strcasecmp ("delivery-status", s)) - return 1; - } - - if ((WithCrypto & APPLICATION_PGP) && t == TYPEAPPLICATION) { - if (!ascii_strcasecmp ("pgp-keys", s)) - return 1; - } - - return 0; -} - -void mutt_free_envelope (ENVELOPE ** p) -{ - if (!*p) - return; - rfc822_free_address (&(*p)->return_path); - rfc822_free_address (&(*p)->from); - rfc822_free_address (&(*p)->to); - rfc822_free_address (&(*p)->cc); - rfc822_free_address (&(*p)->bcc); - rfc822_free_address (&(*p)->sender); - rfc822_free_address (&(*p)->reply_to); - rfc822_free_address (&(*p)->mail_followup_to); - - mem_free (&(*p)->list_post); - mem_free (&(*p)->subject); - /* real_subj is just an offset to subject and shouldn't be freed */ - mem_free (&(*p)->message_id); - mem_free (&(*p)->supersedes); - mem_free (&(*p)->date); - mem_free (&(*p)->x_label); - mem_free (&(*p)->organization); -#ifdef USE_NNTP - mem_free (&(*p)->newsgroups); - mem_free (&(*p)->xref); - mem_free (&(*p)->followup_to); - mem_free (&(*p)->x_comment_to); -#endif - - mutt_buffer_free (&(*p)->spam); - mutt_free_list (&(*p)->references); - mutt_free_list (&(*p)->in_reply_to); - mutt_free_list (&(*p)->userhdrs); - mem_free (p); -} - -/* move all the headers from extra not present in base into base */ -void mutt_merge_envelopes(ENVELOPE* base, ENVELOPE** extra) -{ - /* copies each existing element if necessary, and sets the element - * to NULL in the source so that mutt_free_envelope doesn't leave us - * with dangling pointers. */ -#define MOVE_ELEM(h) if (!base->h) { base->h = (*extra)->h; (*extra)->h = NULL; } - MOVE_ELEM(return_path); - MOVE_ELEM(from); - MOVE_ELEM(to); - MOVE_ELEM(cc); - MOVE_ELEM(bcc); - MOVE_ELEM(sender); - MOVE_ELEM(reply_to); - MOVE_ELEM(mail_followup_to); - MOVE_ELEM(list_post); - MOVE_ELEM(message_id); - MOVE_ELEM(supersedes); - MOVE_ELEM(date); - MOVE_ELEM(x_label); - if (!base->refs_changed) { - MOVE_ELEM(references); - } - if (!base->irt_changed) { - MOVE_ELEM(in_reply_to); - } - /* real_subj is subordinate to subject */ - if (!base->subject) { - base->subject = (*extra)->subject; - base->real_subj = (*extra)->real_subj; - (*extra)->subject = NULL; - (*extra)->real_subj = NULL; - } - /* spam and user headers should never be hashed, and the new envelope may - * have better values. Use new versions regardless. */ - mutt_buffer_free (&base->spam); - mutt_free_list (&base->userhdrs); - MOVE_ELEM(spam); - MOVE_ELEM(userhdrs); -#undef MOVE_ELEM - - mutt_free_envelope(extra); -} - -void _mutt_mktemp (char *s, const char *src, int line) -{ - - snprintf (s, _POSIX_PATH_MAX, "%s/muttng-%s-%d-%d-%d-%x%x", NONULL (Tempdir), - NONULL (Hostname), (int) getuid (), (int) getpid (), Counter++, - (unsigned int) rand(), (unsigned int) rand()); - debug_print (1, ("%s:%d: mutt_mktemp returns \"%s\".\n", src, line, s)); - unlink (s); -} - -void mutt_free_alias (ALIAS ** p) -{ - ALIAS *t; - - while (*p) { - t = *p; - *p = (*p)->next; - mem_free (&t->name); - rfc822_free_address (&t->addr); - mem_free (&t); - } } /* collapse the pathname using ~ or = when possible */ void mutt_pretty_mailbox (char *s) { char *p = s, *q = s; - size_t len; + ssize_t len; url_scheme_t scheme; scheme = url_check_scheme (s); -#ifdef USE_IMAP if (scheme == U_IMAP || scheme == U_IMAPS) { imap_pretty_mailbox (s); return; } -#endif /* if s is an url, only collapse path component */ if (scheme != U_UNKNOWN) { p = strchr (s, ':') + 1; - if (!strncmp (p, "//", 2)) + if (!m_strncmp (p, "//", 2)) q = strchr (p + 2, '/'); if (!q) q = strchr (p, '\0'); @@ -719,102 +220,28 @@ void mutt_pretty_mailbox (char *s) } *q = 0; - if (str_ncmp (s, Maildir, (len = str_len (Maildir))) == 0 && + if (m_strncmp(s, Maildir, (len = m_strlen(Maildir))) == 0 && s[len] == '/') { *s++ = '='; - memmove (s, s + len, str_len (s + len) + 1); + memmove (s, s + len, m_strlen(s + len) + 1); } - else if (str_ncmp (s, Homedir, (len = str_len (Homedir))) == 0 && + else if (m_strncmp(s, Homedir, (len = m_strlen(Homedir))) == 0 && s[len] == '/') { *s++ = '~'; - memmove (s, s + len - 1, str_len (s + len - 1) + 1); + memmove (s, s + len - 1, m_strlen(s + len - 1) + 1); } } -void mutt_pretty_size (char *s, size_t len, long n) -{ - if (n == 0) - strfcpy (s, "0K", len); - else if (n < 10189) /* 0.1K - 9.9K */ - snprintf (s, len, "%3.1fK", (n < 103) ? 0.1 : n / 1024.0); - else if (n < 1023949) { /* 10K - 999K */ - /* 51 is magic which causes 10189/10240 to be rounded up to 10 */ - snprintf (s, len, "%ldK", (n + 51) / 1024); - } - else if (n < 10433332) /* 1.0M - 9.9M */ - snprintf (s, len, "%3.1fM", n / 1048576.0); - else { /* 10M+ */ - - /* (10433332 + 52428) / 1048576 = 10 */ - snprintf (s, len, "%ldM", (n + 52428) / 1048576); - } -} - -void mutt_expand_file_fmt (char *dest, size_t destlen, const char *fmt, - const char *src) -{ - char tmp[LONG_STRING]; - - mutt_quote_filename (tmp, sizeof (tmp), src); - mutt_expand_fmt (dest, destlen, fmt, tmp); -} - -void mutt_expand_fmt (char *dest, size_t destlen, const char *fmt, - const char *src) -{ - const char *p; - char *d; - size_t slen; - int found = 0; - - slen = str_len (src); - destlen--; - - for (p = fmt, d = dest; destlen && *p; p++) { - if (*p == '%') { - switch (p[1]) { - case '%': - *d++ = *p++; - destlen--; - break; - case 's': - found = 1; - strfcpy (d, src, destlen + 1); - d += destlen > slen ? slen : destlen; - destlen -= destlen > slen ? slen : destlen; - p++; - break; - default: - *d++ = *p; - destlen--; - break; - } - } - else { - *d++ = *p; - destlen--; - } - } - - *d = '\0'; - - if (!found && destlen > 0) { - str_cat (dest, destlen, " "); - str_cat (dest, destlen, src); - } - -} - /* return 0 on success, -1 on abort, 1 on error */ int mutt_check_overwrite (const char *attname, const char *path, - char *fname, size_t flen, int *append, + char *fname, ssize_t flen, int *append, char **directory) { int rc = 0; char tmp[_POSIX_PATH_MAX]; struct stat st; - strfcpy (fname, path, flen); + m_strcpy(fname, flen, path); if (access (fname, F_OK) != 0) return 0; if (stat (fname, &st) != 0) @@ -825,23 +252,22 @@ int mutt_check_overwrite (const char *attname, const char *path, (_("File is a directory, save under it? [(y)es, (n)o, (a)ll]"), _("yna"))) { case 3: /* all */ - str_replace (directory, fname); + m_strreplace(directory, fname); break; case 1: /* yes */ - mem_free (directory); + p_delete(directory); break; case -1: /* abort */ - mem_free (directory); + p_delete(directory); return -1; case 2: /* no */ - mem_free (directory); + p_delete(directory); return 1; } } else - if ((rc = - mutt_yesorno (_("File is a directory, save under it?"), - M_YES)) != M_YES) + if ((rc = mutt_yesorno(_("File is a directory, save under it?"), + M_YES)) != M_YES) return (rc == M_NO) ? 1 : -1; if (!attname || !attname[0]) { @@ -849,10 +275,10 @@ int mutt_check_overwrite (const char *attname, const char *path, if (mutt_get_field (_("File under directory: "), tmp, sizeof (tmp), M_FILE | M_CLEAR) != 0 || !tmp[0]) return (-1); - mutt_concat_path (fname, path, tmp, flen); + mutt_concat_path(fname, flen, path, tmp); } else - mutt_concat_path (fname, path, mutt_basename (attname), flen); + mutt_concat_path(fname, flen, path, mutt_basename(attname)); } if (*append == 0 && access (fname, F_OK) == 0) { @@ -875,55 +301,35 @@ int mutt_check_overwrite (const char *attname, const char *path, return 0; } -void mutt_save_path (char *d, size_t dsize, ADDRESS * a) +void mutt_save_path(char *d, ssize_t dsize, address_t *a) { - if (a && a->mailbox) { - strfcpy (d, a->mailbox, dsize); - if (!option (OPTSAVEADDRESS)) { - char *p; + if (a && a->mailbox) { + m_strcpy(d, dsize, a->mailbox); - if ((p = strpbrk (d, "%@"))) - *p = 0; + if (!option(OPTSAVEADDRESS)) { + char *p = strpbrk(d, "%@"); + if (p) + *p = '\0'; + } + m_strtolower(d); + } else { + *d = '\0'; } - str_tolower (d); - } - else - *d = 0; } -void mutt_safe_path (char *s, size_t l, ADDRESS * a) +void mutt_safe_path(char *s, ssize_t l, address_t *a) { - char *p; - - mutt_save_path (s, l, a); - for (p = s; *p; p++) - if (*p == '/' || ISSPACE (*p) || !IsPrint ((unsigned char) *p)) - *p = '_'; -} + mutt_save_path(s, l, a); -/* counts how many characters in s can be skipped while none of the - * characters of c appears */ -int mutt_skipchars (const char *s, const char *c) -{ - int ret = 0; - const char *p = s; - - while (s && *s) { - register const char *t = c; - - while (t && *t) { - if (*t == *s) - return (ret); - t++; + while (*s) { + if (*s == '/' || ISSPACE(*s) || !isprint((unsigned char)*s)) + *s = '_'; + s++; } - ret++; - s++; - } - return (str_len (p)); } void mutt_FormatString (char *dest, /* output buffer */ - size_t destlen, /* output buffer len */ + ssize_t destlen, /* output buffer len */ const char *src, /* template string */ format_t * callback, /* callback for processing */ unsigned long data, /* callback data */ @@ -931,7 +337,7 @@ void mutt_FormatString (char *dest, /* output buffer */ { /* callback flags */ char prefix[SHORT_STRING], buf[LONG_STRING], *cp, *wptr = dest, ch; char ifstring[SHORT_STRING], elsestring[SHORT_STRING]; - size_t wlen, count, len, col, wid; + ssize_t wlen, wid, count, col, len; prefix[0] = '\0'; destlen--; /* save room for the terminal \0 */ @@ -958,7 +364,7 @@ void mutt_FormatString (char *dest, /* output buffer */ /* eat the format string */ cp = prefix; count = 0; - while (count < sizeof (prefix) && + while (count < ssizeof (prefix) && (isdigit ((unsigned char) *src) || *src == '.' || *src == '-')) { *cp++ = *src++; @@ -980,7 +386,7 @@ void mutt_FormatString (char *dest, /* output buffer */ /* eat the `if' part of the string */ cp = ifstring; count = 0; - while (count < sizeof (ifstring) && *src && *src != '?' + while (count < ssizeof (ifstring) && *src && *src != '?' && *src != '&') { *cp++ = *src++; count++; @@ -992,7 +398,7 @@ void mutt_FormatString (char *dest, /* output buffer */ src++; /* skip the & */ cp = elsestring; count = 0; - while (count < sizeof (elsestring) && *src && *src != '?') { + while (count < ssizeof (elsestring) && *src && *src != '?') { *cp++ = *src++; count++; } @@ -1013,13 +419,11 @@ void mutt_FormatString (char *dest, /* output buffer */ if (DrawFullLine || option (OPTSTATUSONTOP)) count = (COLS < destlen ? COLS : destlen); else - count = - ((COLS - SidebarWidth) < - destlen ? (COLS - SidebarWidth) : destlen); + count = ((COLS - SW) < destlen ? (COLS - SW) : destlen); if (count > col) { count -= col; /* how many columns left on this line */ mutt_FormatString (buf, sizeof (buf), src, callback, data, flags); - wid = str_len (buf); + wid = m_strlen(buf); if (count > wid) { count -= wid; /* how many chars to pad */ memset (wptr, ch, count); @@ -1050,12 +454,12 @@ void mutt_FormatString (char *dest, /* output buffer */ break; /* skip rest of input */ } else { - short tolower = 0; + short lower = 0; short nodots = 0; while (ch == '_' || ch == ':') { if (ch == '_') - tolower = 1; + lower = 1; else if (ch == ':') nodots = 1; @@ -1067,8 +471,8 @@ void mutt_FormatString (char *dest, /* output buffer */ callback (buf, sizeof (buf), ch, src, prefix, ifstring, elsestring, data, flags); - if (tolower) - str_tolower (buf); + if (lower) + m_strtolower(buf); if (nodots) { char *p = buf; @@ -1077,7 +481,7 @@ void mutt_FormatString (char *dest, /* output buffer */ *p = '_'; } - if ((len = str_len (buf)) + wlen > destlen) + if ((len = m_strlen(buf)) + wlen > destlen) len = (destlen - wlen > 0) ? (destlen - wlen) : 0; memcpy (wptr, buf, len); @@ -1115,62 +519,18 @@ void mutt_FormatString (char *dest, /* output buffer */ col++; } else { - unsigned int bar = mutt_skipchars (src, "%\\"); - char *bar2 = mem_malloc (bar + 1); + unsigned int bar = strcspn(src, "%\\"); + char *bar2 = p_dupstr(src, bar); - strfcpy (bar2, src, bar + 1); while (bar--) { *wptr++ = *src++; wlen++; } col += mutt_strwidth (bar2); - mem_free (&bar2); + p_delete(&bar2); } } *wptr = 0; - -#if 0 - if (flags & M_FORMAT_MAKEPRINT) { - /* Make sure that the string is printable by changing all non-printable - chars to dots, or spaces for non-printable whitespace */ - for (cp = dest; *cp; cp++) - if (!IsPrint (*cp) && !((flags & M_FORMAT_TREE) && (*cp <= M_TREE_MAX))) - *cp = isspace ((unsigned char) *cp) ? ' ' : '.'; - } -#endif -} - -/* This function allows the user to specify a command to read stdout from in - place of a normal file. If the last character in the string is a pipe (|), - then we assume it is a commmand to run instead of a normal file. */ -FILE *mutt_open_read (const char *path, pid_t * thepid) -{ - FILE *f; - struct stat s; - - int len = str_len (path); - - if (path[len - 1] == '|') { - /* read from a pipe */ - - char *s = str_dup (path); - - s[len - 1] = 0; - mutt_endwin (NULL); - *thepid = mutt_create_filter (s, NULL, &f, NULL); - mem_free (&s); - } - else { - if (stat (path, &s) < 0) - return (NULL); - if (S_ISDIR (s.st_mode)) { - errno = EINVAL; - return (NULL); - } - f = fopen (path, "r"); - *thepid = -1; - } - return (f); } /* returns 0 if OK to proceed, -1 to abort, 1 to retry */ @@ -1183,13 +543,11 @@ int mutt_save_confirm (const char *s, struct stat *st) magic = mx_get_magic (s); -#ifdef USE_POP if (magic == M_POP) { mutt_error _("Can't save message to POP mailbox."); return 1; } -#endif #ifdef USE_NNTP if (magic == M_NNTP) { @@ -1201,7 +559,7 @@ int mutt_save_confirm (const char *s, struct stat *st) if (magic > 0 && !mx_access (s, W_OK)) { if (option (OPTCONFIRMAPPEND) && - (!TrashPath || (str_cmp (s, TrashPath) != 0))) { + (!TrashPath || (m_strcmp(s, TrashPath) != 0))) { /* if we're appending to the trash, there's no point in asking */ snprintf (tmp, sizeof (tmp), _("Append messages to %s?"), s); if ((rc = mutt_yesorno (tmp, M_YES)) == M_NO) @@ -1216,11 +574,8 @@ int mutt_save_confirm (const char *s, struct stat *st) mutt_error (_("%s is not a mailbox!"), s); return 1; } - } - else { -#ifdef USE_IMAP + } else { if (magic != M_IMAP) -#endif /* execute the block unconditionally if we don't use imap */ { st->st_mtime = 0; st->st_atime = 0; @@ -1233,8 +588,7 @@ int mutt_save_confirm (const char *s, struct stat *st) else if (rc == -1) ret = -1; } - } - else { + } else { mutt_perror (s); return 1; } @@ -1245,44 +599,9 @@ int mutt_save_confirm (const char *s, struct stat *st) return (ret); } -void mutt_display_sanitize (char *s) -{ - for (; *s; s++) { - if (!IsPrint (*s)) - *s = '?'; - } -} - void mutt_sleep (short s) { - if (SleepTime > s) - sleep (SleepTime); - else if (s) - sleep (s); -} - -/* Decrease a file's modification time by 1 second */ - -time_t mutt_decrease_mtime (const char *f, struct stat *st) -{ - struct utimbuf utim; - struct stat _st; - time_t mtime; - - if (!st) { - if (stat (f, &_st) == -1) - return -1; - st = &_st; - } - - if ((mtime = st->st_mtime) == time (NULL)) { - mtime -= 1; - utim.actime = mtime; - utim.modtime = mtime; - utime (f, &utim); - } - - return mtime; + sleep(MAX(s, SleepTime)); } const char *mutt_make_version (int full) @@ -1290,105 +609,21 @@ const char *mutt_make_version (int full) static char vstring[STRING]; if (full) - snprintf (vstring, sizeof (vstring), "Mutt-ng %s (based " - "on Mutt 1.5.10/%s)", MUTT_VERSION, ReleaseDate); + snprintf (vstring, sizeof (vstring), + "Madmutt/%s-r%s (based on Mutt 1.5.11)", + MUTT_VERSION, MUTT_REVISION); else - snprintf (vstring, sizeof (vstring), "mutt-ng/%s", MUTT_VERSION); + snprintf (vstring, sizeof (vstring), "Madmutt/%s-%s", + MUTT_VERSION, MUTT_REVISION); return vstring; } -void mutt_free_spam_list (SPAM_LIST ** list) -{ - SPAM_LIST *p; - - if (!list) - return; - while (*list) { - p = *list; - *list = (*list)->next; - rx_free (&p->rx); - mem_free(&p->template); - mem_free(&p); - } -} - -int mutt_match_spam_list (const char *s, SPAM_LIST * l, char *text, int x) -{ - static regmatch_t *pmatch = NULL; - static int nmatch = 0; - int i, n, tlen; - char *p; - - if (!s) - return 0; - - tlen = 0; - - for (; l; l = l->next) { - /* If this pattern needs more matches, expand pmatch. */ - if (l->nmatch > nmatch) { - mem_realloc (&pmatch, l->nmatch * sizeof (regmatch_t)); - nmatch = l->nmatch; - } - - /* Does this pattern match? */ - if (regexec - (l->rx->rx, s, (size_t) l->nmatch, (regmatch_t *) pmatch, - (int) 0) == 0) { - debug_print (5, ("%s matches %s\n%d subst", s, l->rx->pattern, l->rx->rx->re_nsub)); - - /* Copy template into text, with substitutions. */ - for (p = l->template; *p;) { - if (*p == '%') { - n = atoi (++p); /* find pmatch index */ - while (isdigit (*p)) - ++p; /* skip subst token */ - for (i = pmatch[n].rm_so; (i < pmatch[n].rm_eo) && (tlen < x); i++) - text[tlen++] = s[i]; - } - else { - text[tlen++] = *p++; - } - } - text[tlen] = '\0'; - debug_print (5, ("\"%s\"\n", text)); - return 1; - } - } - - return 0; -} - -int mutt_cmp_header (const HEADER * h1, const HEADER * h2) { - if (h1 && h2) { - if (h1->received != h2->received || - h1->date_sent != h2->date_sent || - h1->content->length != h2->content->length || - h1->lines != h2->lines || - h1->zhours != h2->zhours || - h1->zminutes != h2->zminutes || - h1->zoccident != h2->zoccident || - h1->mime != h2->mime || - !mutt_cmp_env (h1->env, h2->env) || - !mutt_cmp_body (h1->content, h2->content)) - return (0); - else - return (1); - } - else { - if (h1 == NULL && h2 == NULL) - return (1); - else - return (0); - } -} - /* return 1 if address lists are strictly identical */ -int mutt_cmp_addr (const ADDRESS * a, const ADDRESS * b) +static int mutt_cmp_addr (const address_t * a, const address_t * b) { while (a && b) { - if (str_cmp (a->mailbox, b->mailbox) || - str_cmp (a->personal, b->personal)) + if (m_strcmp(a->mailbox, b->mailbox) || + m_strcmp(a->personal, b->personal)) return (0); a = a->next; @@ -1400,10 +635,10 @@ int mutt_cmp_addr (const ADDRESS * a, const ADDRESS * b) return (1); } -int mutt_cmp_list (const LIST * a, const LIST * b) +static int mutt_cmp_list (const string_list_t * a, const string_list_t * b) { while (a && b) { - if (str_cmp (a->data, b->data)) + if (m_strcmp(a->data, b->data)) return (0); a = a->next; @@ -1415,11 +650,11 @@ int mutt_cmp_list (const LIST * a, const LIST * b) return (1); } -int mutt_cmp_env (const ENVELOPE * e1, const ENVELOPE * e2) +static int mutt_cmp_env (const ENVELOPE * e1, const ENVELOPE * e2) { if (e1 && e2) { - if (str_cmp (e1->message_id, e2->message_id) || - str_cmp (e1->subject, e2->subject) || + if (m_strcmp(e1->message_id, e2->message_id) || + m_strcmp(e1->subject, e2->subject) || !mutt_cmp_list (e1->references, e2->references) || !mutt_cmp_addr (e1->from, e2->from) || !mutt_cmp_addr (e1->sender, e2->sender) || @@ -1439,30 +674,219 @@ int mutt_cmp_env (const ENVELOPE * e1, const ENVELOPE * e2) } } -int mutt_cmp_param (const PARAMETER * p1, const PARAMETER * p2) -{ - while (p1 && p2) { - if (str_cmp (p1->attribute, p2->attribute) || - str_cmp (p1->value, p2->value)) - return (0); - - p1 = p1->next; - p2 = p2->next; - } - if (p1 || p2) - return (0); - - return (1); -} - -int mutt_cmp_body (const BODY * b1, const BODY * b2) +static int mutt_cmp_body (const BODY * b1, const BODY * b2) { if (b1->type != b2->type || b1->encoding != b2->encoding || - str_cmp (b1->subtype, b2->subtype) || - str_cmp (b1->description, b2->description) || - !mutt_cmp_param (b1->parameter, b2->parameter) || + m_strcmp(b1->subtype, b2->subtype) || + m_strcmp(b1->description, b2->description) || + !parameter_equal(b1->parameter, b2->parameter) || b1->length != b2->length) return (0); return (1); } +int mutt_cmp_header (const HEADER * h1, const HEADER * h2) { + if (h1 && h2) { + if (h1->received != h2->received || + h1->date_sent != h2->date_sent || + h1->content->length != h2->content->length || + h1->lines != h2->lines || + h1->zhours != h2->zhours || + h1->zminutes != h2->zminutes || + h1->zoccident != h2->zoccident || + h1->mime != h2->mime || + !mutt_cmp_env (h1->env, h2->env) || + !mutt_cmp_body (h1->content, h2->content)) + return (0); + else + return (1); + } + else { + if (h1 == NULL && h2 == NULL) + return (1); + else + return (0); + } +} + + +int mutt_extract_token(BUFFER *dest, BUFFER *tok, int flags) +{ + char ch; + char qc = 0; /* quote char */ + char *pc; + + /* reset the destination pointer to the beginning of the buffer */ + dest->dptr = dest->data; + + tok->dptr = vskipspaces(tok->dptr); + while ((ch = *tok->dptr)) { + if (!qc) { + if ((ISSPACE(ch) && !(flags & M_TOKEN_SPACE)) + || (ch == '#' && !(flags & M_TOKEN_COMMENT)) + || (ch == '=' && (flags & M_TOKEN_EQUAL)) + || (ch == ';' && !(flags & M_TOKEN_SEMICOLON)) + || ((flags & M_TOKEN_PATTERN) && strchr("~=!|", ch))) + { + break; + } + } + + tok->dptr++; + + if (ch == qc) { + qc = 0; /* end of quote */ + } else + if (!qc && (ch == '\'' || ch == '"') && !(flags & M_TOKEN_QUOTE)) { + qc = ch; + } else + if (ch == '\\' && qc != '\'') { + if (!*tok->dptr) + return -1; /* premature end of token */ + + switch (ch = *tok->dptr++) { + case 'c': + case 'C': + if (!*tok->dptr) + return -1; /* premature end of token */ + mutt_buffer_addch(dest, + (ascii_toupper(*tok->dptr) - 'A' + 1) & 0x7f); + tok->dptr++; + break; + case 'r': + mutt_buffer_addch(dest, '\r'); + break; + case 'n': + mutt_buffer_addch(dest, '\n'); + break; + case 't': + mutt_buffer_addch(dest, '\t'); + break; + case 'f': + mutt_buffer_addch(dest, '\f'); + break; + case 'e': + mutt_buffer_addch(dest, '\033'); + break; + default: + if (isdigit((unsigned char)ch) + && isdigit((unsigned char)*tok->dptr) + && isdigit((unsigned char)*(tok->dptr + 1))) + { + mutt_buffer_addch(dest, (ch << 6) + (*tok->dptr << 3) + + *(tok->dptr + 1) - 3504); + tok->dptr += 2; + } else { + mutt_buffer_addch(dest, ch); + } + } + } else + if (ch == '^' && (flags & M_TOKEN_CONDENSE)) { + if (!*tok->dptr) + return -1; /* premature end of token */ + ch = *tok->dptr++; + if (ch == '^') { + mutt_buffer_addch(dest, ch); + } else + if (ch == '[') { + mutt_buffer_addch(dest, '\033'); + } else + if (isalpha((unsigned char)ch)) { + mutt_buffer_addch(dest, ascii_toupper(ch) - 'A' + 1); + } else { + mutt_buffer_addch(dest, '^'); + mutt_buffer_addch(dest, ch); + } + } else + if (ch == '`' && (!qc || qc == '"')) { + FILE *fp; + pid_t pid; + char *cmd, *ptr; + ssize_t expnlen; + BUFFER expn; + int line = 0; + + pc = tok->dptr; + do { + if ((pc = strpbrk(pc, "\\`"))) { + /* skip any quoted chars */ + if (*pc == '\\') + pc += 2; + } + } while (pc && *pc != '`'); + if (!pc) { + return (-1); + } + + cmd = p_dupstr(tok->dptr, pc - tok->dptr); + if ((pid = mutt_create_filter(cmd, NULL, &fp, NULL)) < 0) { + p_delete(&cmd); + return -1; + } + p_delete(&cmd); + + tok->dptr = pc + 1; + + /* read line */ + p_clear(&expn, 1); + expn.data = mutt_read_line(NULL, &expn.dsize, fp, &line); + m_fclose(&fp); + mutt_wait_filter(pid); + + /* if we got output, make a new string consiting of the shell ouptput + plus whatever else was left on the original line */ + /* BUT: If this is inside a quoted string, directly add output to + * the token */ + if (expn.data && qc) { + mutt_buffer_addstr(dest, expn.data); + p_delete(&expn.data); + } else + if (expn.data) { + expnlen = m_strlen(expn.data); + tok->dsize = expnlen + m_strlen(tok->dptr) + 1; + ptr = xmalloc(tok->dsize); + memcpy(ptr, expn.data, expnlen); + m_strcpy(ptr + expnlen, tok->dsize - expnlen, tok->dptr); + if (tok->destroy) + p_delete(&tok->data); + tok->data = ptr; + tok->dptr = ptr; + tok->destroy = 1; /* mark that the caller should destroy this data */ + ptr = NULL; + p_delete(&expn.data); + } + } else + if (ch == '$' && (!qc || qc == '"') + && (*tok->dptr == '{' || isalpha((unsigned char)*tok->dptr))) + { + char *env = NULL, *var = NULL; + + if (*tok->dptr == '{') { + tok->dptr++; + if ((pc = strchr (tok->dptr, '}'))) { + var = p_dupstr(tok->dptr, pc - tok->dptr); + tok->dptr = pc + 1; + } + } else { + for (pc = tok->dptr; isalnum((unsigned char)*pc) || *pc == '_'; + pc++); + var = p_dupstr(tok->dptr, pc - tok->dptr); + tok->dptr = pc; + } + if (var) { + char tmp[STRING]; + if ((env = getenv (var)) + || (mutt_option_value (var, tmp, sizeof (tmp)) && (env = tmp))) + { + mutt_buffer_addstr (dest, env); + } + } + p_delete(&var); + } else { + mutt_buffer_addch(dest, ch); + } + } + mutt_buffer_addch(dest, 0); /* terminate the string */ + tok->dptr = vskipspaces(tok->dptr); + return 0; +}