X-Git-Url: http://git.madism.org/?p=apps%2Fmadmutt.git;a=blobdiff_plain;f=muttlib.c;h=efb991bc35805474589648939802fe1ef5f6590d;hp=27cbdbd9d394e4bcc6f7954c960995903de4592e;hb=3984877e812b0ba73b84539d231aeca3c2de6b9b;hpb=723f7ae3f24f7881c9ce87abf933cd5bec4ac0bc diff --git a/muttlib.c b/muttlib.c index 27cbdbd..efb991b 100644 --- a/muttlib.c +++ b/muttlib.c @@ -8,36 +8,20 @@ * 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 -#include -#include +#include +#include #include -#include -#include -#include -#include -#include -#include -#include -#include - #include #include #include +#include + +#include "alias.h" #include "mutt.h" #include "mx.h" #include "attach.h" @@ -51,28 +35,18 @@ #define SW (option(OPTMBOXPANE)?SidebarWidth:0) -BODY *mutt_new_body (void) -{ - BODY *p = p_new(BODY, 1); - - p->disposition = DISPATTACH; - p->use_disp = 1; - return (p); -} - - /* Modified by blong to accept a "suggestion" for file name. If * that file exists, then construct one with unique name but * keep any extension. This might fail, I guess. * 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; + ssize_t sl; struct stat sb; m_strcpy(buf, sizeof(buf), m_strisempty(dir) ? NONULL(Tempdir) : dir); @@ -106,7 +80,7 @@ int mutt_copy_body (FILE * fp, BODY ** tgt, BODY * src) char tmp[_POSIX_PATH_MAX]; BODY *b; - PARAMETER *par, **ppar; + parameter_t *par, **ppar; short use_disp; @@ -123,7 +97,7 @@ int mutt_copy_body (FILE * fp, BODY ** tgt, BODY * src) if (mutt_save_attachment (fp, src, tmp, 0, NULL) == -1) return -1; - *tgt = mutt_new_body (); + *tgt = body_new(); b = *tgt; memcpy (b, src, sizeof (BODY)); @@ -165,58 +139,8 @@ int mutt_copy_body (FILE * fp, BODY ** tgt, BODY * src) return 0; } - - -void mutt_free_body (BODY ** p) -{ - BODY *a = *p, *b; - - while (a) { - b = a; - a = a->next; - - if (b->parameter) - parameter_delete(&b->parameter); - if (b->unlink && b->filename) { - debug_print (1, ("unlinking %s.\n", b->filename)); - unlink (b->filename); - } - else if (b->filename) - debug_print (1, ("not unlinking %s.\n", b->filename)); - - p_delete(&b->filename); - p_delete(&b->content); - p_delete(&b->xtype); - p_delete(&b->subtype); - p_delete(&b->description); - p_delete(&b->form_name); - - if (b->hdr) { - /* Don't free twice (b->hdr->content = b->parts) */ - b->hdr->content = NULL; - header_delete(&b->hdr); - } - - if (b->parts) - mutt_free_body (&b->parts); - - p_delete(&b); - } - - *p = 0; -} - -HEADER *mutt_dup_header (HEADER * h) -{ - HEADER *hnew; - - hnew = header_new(); - memcpy (hnew, h, sizeof (HEADER)); - return hnew; -} - /* 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, m_strlen(t->data)) @@ -226,35 +150,12 @@ int mutt_matches_ignore (const char *s, LIST * t) return 0; } -/* prepend the path part of *path to *lnk */ -void mutt_expand_link (char *newpath, const char *path, const char *lnk) -{ - const char *lb = NULL; - size_t len; - - /* lnk is full path */ - if (*lnk == '/') { - m_strcpy(newpath, _POSIX_PATH_MAX, lnk); - return; - } - - if ((lb = strrchr (path, '/')) == NULL) { - /* no path in lnk */ - m_strcpy(newpath, _POSIX_PATH_MAX, lnk); - return; - } - - len = lb - path + 1; - memcpy (newpath, path, len); - m_strcpy(newpath + len, _POSIX_PATH_MAX - len, lnk); -} - -char *mutt_expand_path (char *s, size_t slen) +char *mutt_expand_path (char *s, ssize_t slen) { return _mutt_expand_path (s, slen, 0); } -char *_mutt_expand_path (char *s, size_t slen, int rx) +char *_mutt_expand_path (char *s, ssize_t slen, int rx) { char p[_POSIX_PATH_MAX] = ""; char q[_POSIX_PATH_MAX] = ""; @@ -320,9 +221,10 @@ char *_mutt_expand_path (char *s, size_t slen, int rx) case '@': { HEADER *h; + /* FIXME: BUG ? */ address_t *alias; - if ((alias = alias_lookup(Aliases, s + 1))) { + if ((alias = alias_lookup(s + 1))) { h = header_new(); h->env = envelope_new(); h->env->from = h->env->to = alias; @@ -400,155 +302,12 @@ char *_mutt_expand_path (char *s, size_t slen, int rx) return (s); } -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) { - m_strreplace(&q->value, value); - return; - } - } - - q = parameter_new(); - q->attribute = m_strdup(attribute); - q->value = m_strdup(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; - parameter_delete(&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 (mutt_is_application_pgp (m)) - return 0; - if (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 (mutt_is_application_pgp (b)) - return 0; - - if (t == TYPETEXT) - return 1; - - if (t == TYPEMESSAGE) { - if (!ascii_strcasecmp ("delivery-status", s)) - return 1; - } - - if (t == TYPEAPPLICATION) { - if (!ascii_strcasecmp ("pgp-keys", s)) - return 1; - } - - return 0; -} - -/* 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 envelope_delete 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 - - envelope_delete(extra); -} - -void _mutt_mktemp (char *s, const char *src, int line) +void mutt_mktemp (char *s) { snprintf (s, _POSIX_PATH_MAX, "%s/madmutt-%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); } @@ -556,7 +315,7 @@ void _mutt_mktemp (char *s, const char *src, int line) 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); @@ -603,7 +362,7 @@ void mutt_pretty_mailbox (char *s) } } -void mutt_pretty_size (char *s, size_t len, long n) +void mutt_pretty_size (char *s, ssize_t len, long n) { if (n == 0) m_strcpy(s, len, "0K"); @@ -622,64 +381,52 @@ void mutt_pretty_size (char *s, size_t len, long n) } } -void mutt_expand_file_fmt (char *dest, size_t destlen, const char *fmt, - const char *src) +void mutt_expand_file_fmt(char *dest, ssize_t destlen, + const char *fmt, const char *src) { - char tmp[LONG_STRING]; + char tmp[LONG_STRING]; - mutt_quote_filename (tmp, sizeof (tmp), src); - mutt_expand_fmt (dest, destlen, fmt, tmp); + 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) +void mutt_expand_fmt(char *dst, ssize_t dlen, + const char *fmt, const char *src) { - const char *p; - char *d; - size_t slen; - int found = 0; - - slen = m_strlen(src); - destlen--; - - for (p = fmt, d = dest; destlen && *p; p++) { - if (*p == '%') { - switch (p[1]) { - case '%': - *d++ = *p++; - destlen--; - break; - case 's': - found = 1; - m_strcpy(d, destlen + 1, src); - d += destlen > slen ? slen : destlen; - destlen -= destlen > slen ? slen : destlen; - p++; - break; - default: - *d++ = *p; - destlen--; - break; - } - } - else { - *d++ = *p; - destlen--; + ssize_t pos = 0; + int found = 0; + + while (*fmt && pos < dlen - 1) { + if (*fmt == '%') { + switch (*++fmt) { + case 's': + found = 1; + pos += m_strcpy(dst + pos, dlen - pos, src); + break; + + case '%': + dst[pos++] = *fmt++; + break; + + default: + dst[pos++] = '%'; + break; + } + } else { + dst[pos++] = *fmt++; + } } - } - - *d = '\0'; - - if (!found && destlen > 0) { - m_strcat(dest, destlen, " "); - m_strcat(dest, destlen, src); - } + dst[pos] = '\0'; + if (!found) { + pos += m_strcpy(dst + pos, dlen - pos, " "); + pos += m_strcpy(dst + pos, dlen - pos, 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; @@ -747,51 +494,31 @@ int mutt_check_overwrite (const char *attname, const char *path, return 0; } -void mutt_save_path (char *d, size_t dsize, address_t * a) +void mutt_save_path(char *d, ssize_t dsize, address_t *a) { - if (a && a->mailbox) { - m_strcpy(d, dsize, a->mailbox); - 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'; } - m_strtolower(d); - } - else - *d = 0; } -void mutt_safe_path (char *s, size_t l, address_t * a) +void mutt_safe_path(char *s, ssize_t l, address_t *a) { - char *p; + mutt_save_path(s, l, a); - mutt_save_path (s, l, a); - for (p = s; *p; p++) - if (*p == '/' || ISSPACE (*p) || !IsPrint ((unsigned char) *p)) - *p = '_'; -} - -/* 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 (m_strlen(p)); } void mutt_FormatString (char *dest, /* output buffer */ @@ -985,7 +712,7 @@ void mutt_FormatString (char *dest, /* output buffer */ col++; } else { - unsigned int bar = mutt_skipchars (src, "%\\"); + unsigned int bar = strcspn(src, "%\\"); char *bar2 = p_dupstr(src, bar); while (bar--) { @@ -1003,39 +730,12 @@ void mutt_FormatString (char *dest, /* output buffer */ /* 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))) + 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) -{ - int len = m_strlen(path); - FILE *f; - - if (path[len - 1] == '|') { - char *s = m_strdup(path); - - /* read from a pipe */ - - s[len - 1] = 0; - mutt_endwin (NULL); - *thepid = mutt_create_filter (s, NULL, &f, NULL); - p_delete(&s); - } else { - f = fopen (path, "r"); - if (!f) - return NULL; - *thepid = -1; - } - - return (f); -} - /* returns 0 if OK to proceed, -1 to abort, 1 to retry */ int mutt_save_confirm (const char *s, struct stat *st) { @@ -1104,20 +804,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); + sleep(MAX(s, SleepTime)); } /* Decrease a file's modification time by 1 second */ @@ -1143,18 +832,6 @@ time_t mutt_decrease_mtime (const char *f, struct stat *st) return mtime; } -/* sets mtime of 'to' to mtime of 'from' */ -void mutt_set_mtime (const char* from, const char* to) { - struct utimbuf utim; - struct stat st; - - if (stat (from, &st) != -1) { - utim.actime = st.st_mtime; - utim.modtime = st.st_mtime; - utime (to, &utim); - } -} - const char *mutt_make_version (int full) { static char vstring[STRING]; @@ -1204,11 +881,8 @@ int mutt_match_spam_list (const char *s, SPAM_LIST * l, char *text, int x) } /* 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)); - + if (regexec(l->rx->rx, s, l->nmatch, (regmatch_t *)pmatch, (int) 0) == 0) + { /* Copy template into text, with substitutions. */ for (p = l->template; *p;) { if (*p == '%') { @@ -1223,7 +897,6 @@ int mutt_match_spam_list (const char *s, SPAM_LIST * l, char *text, int x) } } text[tlen] = '\0'; - debug_print (5, ("\"%s\"\n", text)); return 1; } } @@ -1231,32 +904,8 @@ int mutt_match_spam_list (const char *s, SPAM_LIST * l, char *text, int x) 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_t * a, const address_t * b) +static int mutt_cmp_addr (const address_t * a, const address_t * b) { while (a && b) { if (m_strcmp(a->mailbox, b->mailbox) || @@ -1272,7 +921,7 @@ int mutt_cmp_addr (const address_t * a, const address_t * 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 (m_strcmp(a->data, b->data)) @@ -1287,7 +936,7 @@ 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 (m_strcmp(e1->message_id, e2->message_id) || @@ -1311,30 +960,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 (m_strcmp(p1->attribute, p2->attribute) || - m_strcmp(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 || m_strcmp(b1->subtype, b2->subtype) || m_strcmp(b1->description, b2->description) || - !mutt_cmp_param (b1->parameter, b2->parameter) || + !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); + 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); + strcpy(ptr + expnlen, tok->dptr); /* __STRCPY_CHECKED__ */ + 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; +}