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); }
static void remove_from_list (LIST **l, const char *str) { LIST *p, *last = NULL; if (mutt_strcmp ("*", str) == 0) mutt_free_list (l); /* ``unCMD *'' means delete all current entries */ else { p = *l; last = NULL; while (p) { if (mutt_strcasecmp (str, p->data) == 0) { safe_free ((void **) &p->data); if (last) last->next = p->next; else (*l) = p->next; safe_free ((void **) &p); } else { last = p; p = p->next; } } } }
static void mutt_make_reference_headers (ENVELOPE *curenv, ENVELOPE *env, CONTEXT *ctx) { env->references = NULL; env->in_reply_to = NULL; if (!curenv) { HEADER *h; LIST **p = NULL, **q = NULL; int i; for(i = 0; i < ctx->vcount; i++) { h = ctx->hdrs[ctx->v2r[i]]; if (h->tagged) mutt_add_to_reference_headers (env, h->env, &p, &q); } } else mutt_add_to_reference_headers (env, curenv, NULL, NULL); /* if there's more than entry in In-Reply-To (i.e. message has multiple parents), don't generate a References: header as it's discouraged by RfC2822, sect. 3.6.4 */ if (ctx->tagged > 0 && env->in_reply_to && env->in_reply_to->next) mutt_free_list (&env->references); }
ADDRESS *mutt_expand_aliases (ADDRESS *a) { ADDRESS *t; LIST *expn = NULL; /* previously expanded aliases to avoid loops */ t = mutt_expand_aliases_r (a, &expn); mutt_free_list (&expn); return (mutt_remove_duplicates (t)); }
/* imap_free_idata: Release and clear storage in an IMAP_DATA structure. */ void imap_free_idata (IMAP_DATA** idata) { if (!idata) return; FREE (&(*idata)->capstr); mutt_free_list (&(*idata)->flags); FREE (&((*idata)->cmd.buf)); FREE (idata); }
void mutt_free_envelope (ENVELOPE **p) { if (!*p) return; rfc822_free_address (&(*p)->return_path); rfc822_free_address (&(*p)->to); rfc822_free_address (&(*p)->cc); rfc822_free_address (&(*p)->bcc); rfc822_free_address (&(*p)->sender); rfc822_free_address (&(*p)->from); rfc822_free_address (&(*p)->reply_to); rfc822_free_address (&(*p)->mail_followup_to); safe_free ((void **) &(*p)->subject); safe_free ((void **) &(*p)->message_id); safe_free ((void **) &(*p)->supersedes); safe_free ((void **) &(*p)->date); mutt_free_list (&(*p)->references); mutt_free_list (&(*p)->userhdrs); safe_free ((void **) p); }
void mutt_free_header (HEADER **h) { if(!h || !*h) return; mutt_free_envelope (&(*h)->env); mutt_free_body (&(*h)->content); safe_free ((void **) &(*h)->tree); safe_free ((void **) &(*h)->path); #ifdef MIXMASTER mutt_free_list (&(*h)->chain); #endif safe_free ((void **) h); }
/* imap_free_idata: Release and clear storage in an IMAP_DATA structure. */ void imap_free_idata (IMAP_DATA** idata) { if (!idata) return; FREE (&(*idata)->capstr); mutt_free_list (&(*idata)->flags); imap_mboxcache_free (*idata); mutt_buffer_free(&(*idata)->cmdbuf); FREE (&(*idata)->buf); mutt_bcache_close (&(*idata)->bcache); FREE (&(*idata)->cmds); FREE (idata); /* __FREE_CHECKED__ */ }
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); }
/* 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); }
pgp_key_t pgp_getkeybystr (char *p, short abilities, pgp_ring_t keyring) { LIST *hints = NULL; pgp_key_t keys; pgp_key_t matches = NULL; pgp_key_t *last = &matches; pgp_key_t k, kn; pgp_uid_t *a; short match; size_t l; const char *ps, *pl, *pfcopy, *phint; if ((l = mutt_strlen (p)) && p[l-1] == '!') p[l-1] = 0; mutt_message (_("Looking for keys matching \"%s\"..."), p); pfcopy = crypt_get_fingerprint_or_id (p, &phint, &pl, &ps); hints = pgp_add_string_to_hints (hints, phint); keys = pgp_get_candidates (keyring, hints); mutt_free_list (&hints); if (!keys) goto out; for (k = keys; k; k = kn) { kn = k->next; if (abilities && !(k->flags & abilities)) continue; /* This shouldn't happen, but keys without any addresses aren't selectable * in pgp_select_key(). */ if (!k->address) continue; match = 0; dprint (5, (debugfile, "pgp_getkeybystr: matching \"%s\" against key %s:\n", p, pgp_long_keyid (k))); if (!*p || (pfcopy && mutt_strcasecmp (pfcopy, k->fingerprint) == 0) || (pl && mutt_strcasecmp (pl, pgp_long_keyid (k)) == 0) || (ps && mutt_strcasecmp (ps, pgp_short_keyid (k)) == 0)) { dprint (5, (debugfile, "\t\tmatch.\n")); match = 1; } else { for (a = k->address; a; a = a->next) { dprint (5, (debugfile, "pgp_getkeybystr: matching \"%s\" against key %s, \"%s\":\n", p, pgp_long_keyid (k), NONULL (a->addr))); if (mutt_stristr (a->addr, p)) { dprint (5, (debugfile, "\t\tmatch.\n")); match = 1; break; } } } if (match) { *last = pgp_principal_key (k); kn = pgp_remove_key (&keys, *last); last = pgp_get_lastp (k); } } pgp_free_key (&keys); if (matches) { if ((k = pgp_select_key (matches, NULL, p))) pgp_remove_key (&matches, k); pgp_free_key (&matches); FREE (&pfcopy); if (l && !p[l-1]) p[l-1] = '!'; return k; } out: FREE (&pfcopy); if (l && !p[l-1]) p[l-1] = '!'; return NULL; }
pgp_key_t pgp_getkeybyaddr (ADDRESS * a, short abilities, pgp_ring_t keyring, int oppenc_mode) { ADDRESS *r, *p; LIST *hints = NULL; int multi = 0; int match; pgp_key_t keys, k, kn; pgp_key_t the_strong_valid_key = NULL; pgp_key_t a_valid_addrmatch_key = NULL; pgp_key_t matches = NULL; pgp_key_t *last = &matches; pgp_uid_t *q; if (a && a->mailbox) hints = pgp_add_string_to_hints (hints, a->mailbox); if (a && a->personal) hints = pgp_add_string_to_hints (hints, a->personal); if (! oppenc_mode ) mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox); keys = pgp_get_candidates (keyring, hints); mutt_free_list (&hints); if (!keys) return NULL; dprint (5, (debugfile, "pgp_getkeybyaddr: looking for %s <%s>.", a->personal, a->mailbox)); for (k = keys; k; k = kn) { kn = k->next; dprint (5, (debugfile, " looking at key: %s\n", pgp_keyid (k))); if (abilities && !(k->flags & abilities)) { dprint (5, (debugfile, " insufficient abilities: Has %x, want %x\n", k->flags, abilities)); continue; } match = 0; /* any match */ for (q = k->address; q; q = q->next) { r = rfc822_parse_adrlist (NULL, NONULL (q->addr)); for (p = r; p; p = p->next) { int validity = pgp_id_matches_addr (a, p, q); if (validity & PGP_KV_MATCH) /* something matches */ match = 1; if ((validity & PGP_KV_VALID) && (validity & PGP_KV_ADDR)) { if (validity & PGP_KV_STRONGID) { if (the_strong_valid_key && the_strong_valid_key != k) multi = 1; the_strong_valid_key = k; } else { a_valid_addrmatch_key = k; } } } rfc822_free_address (&r); } if (match) { *last = pgp_principal_key (k); kn = pgp_remove_key (&keys, *last); last = pgp_get_lastp (k); } } pgp_free_key (&keys); if (matches) { if (oppenc_mode) { if (the_strong_valid_key) { pgp_remove_key (&matches, the_strong_valid_key); k = the_strong_valid_key; } else if (a_valid_addrmatch_key) { pgp_remove_key (&matches, a_valid_addrmatch_key); k = a_valid_addrmatch_key; } else k = NULL; } else if (the_strong_valid_key && !multi) { /* * There was precisely one strong match on a valid ID. * * Proceed without asking the user. */ pgp_remove_key (&matches, the_strong_valid_key); k = the_strong_valid_key; } else { /* * Else: Ask the user. */ if ((k = pgp_select_key (matches, a, NULL))) pgp_remove_key (&matches, k); } pgp_free_key (&matches); return k; } return NULL; }
/* args: * ctx Context info, used when recalling a message to which * we reply. * hdr envelope/attachment info for recalled message * cur if message was a reply, `cur' is set to the message which * `hdr' is in reply to * fcc fcc for the recalled message * fcclen max length of fcc * * return vals: * -1 error/no messages * 0 normal exit * SENDREPLY recalled message is a reply */ int mutt_get_postponed (CONTEXT *ctx, HEADER *hdr, HEADER **cur, char *fcc, size_t fcclen) { HEADER *h; int code = SENDPOSTPONED; LIST *tmp; LIST *last = NULL; LIST *next; const char *p; int opt_delete; if (!Postponed) return (-1); if ((PostContext = mx_open_mailbox (Postponed, M_NOSORT, NULL)) == NULL) { PostCount = 0; mutt_error _("No postponed messages."); return (-1); } if (! PostContext->msgcount) { PostCount = 0; mx_close_mailbox (PostContext, NULL); FREE (&PostContext); mutt_error _("No postponed messages."); return (-1); } if (PostContext->msgcount == 1) { /* only one message, so just use that one. */ h = PostContext->hdrs[0]; } else if ((h = select_msg ()) == NULL) { mx_close_mailbox (PostContext, NULL); FREE (&PostContext); return (-1); } if (mutt_prepare_template (NULL, PostContext, hdr, h, 0) < 0) { mx_fastclose_mailbox (PostContext); FREE (&PostContext); return (-1); } /* finished with this message, so delete it. */ mutt_set_flag (PostContext, h, M_DELETE, 1); /* update the count for the status display */ PostCount = PostContext->msgcount - PostContext->deleted; /* avoid the "purge deleted messages" prompt */ opt_delete = quadoption (OPT_DELETE); set_quadoption (OPT_DELETE, M_YES); mx_close_mailbox (PostContext, NULL); set_quadoption (OPT_DELETE, opt_delete); FREE (&PostContext); for (tmp = hdr->env->userhdrs; tmp; ) { if (ascii_strncasecmp ("X-Mutt-References:", tmp->data, 18) == 0) { if (ctx) { /* if a mailbox is currently open, look to see if the orignal message the user attempted to reply to is in this mailbox */ p = skip_email_wsp(tmp->data + 18); if (!ctx->id_hash) ctx->id_hash = mutt_make_id_hash (ctx); *cur = hash_find (ctx->id_hash, p); } /* Remove the X-Mutt-References: header field. */ next = tmp->next; if (last) last->next = tmp->next; else hdr->env->userhdrs = tmp->next; tmp->next = NULL; mutt_free_list (&tmp); tmp = next; if (*cur) code |= SENDREPLY; } else if (ascii_strncasecmp ("X-Mutt-Fcc:", tmp->data, 11) == 0) { p = skip_email_wsp(tmp->data + 11); strfcpy (fcc, p, fcclen); mutt_pretty_mailbox (fcc, fcclen); /* remove the X-Mutt-Fcc: header field */ next = tmp->next; if (last) last->next = tmp->next; else hdr->env->userhdrs = tmp->next; tmp->next = NULL; mutt_free_list (&tmp); tmp = next; /* note that x-mutt-fcc was present. we do this because we want to add a * default fcc if the header was missing, but preserve the request of the * user to not make a copy if the header field is present, but empty. * see http://dev.mutt.org/trac/ticket/3653 */ code |= SENDPOSTPONEDFCC; } else if ((WithCrypto & APPLICATION_PGP) && (mutt_strncmp ("Pgp:", tmp->data, 4) == 0 /* this is generated * by old mutt versions */ || mutt_strncmp ("X-Mutt-PGP:", tmp->data, 11) == 0)) { hdr->security = mutt_parse_crypt_hdr (strchr (tmp->data, ':') + 1, 1, APPLICATION_PGP); hdr->security |= APPLICATION_PGP; /* remove the pgp field */ next = tmp->next; if (last) last->next = tmp->next; else hdr->env->userhdrs = tmp->next; tmp->next = NULL; mutt_free_list (&tmp); tmp = next; } else if ((WithCrypto & APPLICATION_SMIME) && mutt_strncmp ("X-Mutt-SMIME:", tmp->data, 13) == 0) { hdr->security = mutt_parse_crypt_hdr (strchr (tmp->data, ':') + 1, 1, APPLICATION_SMIME); hdr->security |= APPLICATION_SMIME; /* remove the smime field */ next = tmp->next; if (last) last->next = tmp->next; else hdr->env->userhdrs = tmp->next; tmp->next = NULL; mutt_free_list (&tmp); tmp = next; } #ifdef MIXMASTER else if (mutt_strncmp ("X-Mutt-Mix:", tmp->data, 11) == 0) { char *t; mutt_free_list (&hdr->chain); t = strtok (tmp->data + 11, " \t\n"); while (t) { hdr->chain = mutt_add_list (hdr->chain, t); t = strtok (NULL, " \t\n"); } next = tmp->next; if (last) last->next = tmp->next; else hdr->env->userhdrs = tmp->next; tmp->next = NULL; mutt_free_list (&tmp); tmp = next; } #endif else { last = tmp; tmp = tmp->next; } } if (option (OPTCRYPTOPPORTUNISTICENCRYPT)) crypt_opportunistic_encrypt (hdr); return (code); }
int main(int argc, char **argv) { char folder[_POSIX_PATH_MAX] = ""; int flags = 0; /* set default locale */ setlocale(LC_ALL, ""); /* initialization of main output routines with default values */ mutt_error = mutt_message = mutt_nocurses_error; /* parse command line options */ parse_argv(argc, argv); if (arg_version == 1) { show_version(); exit(RETURN_SUCCESS); } else if (arg_version == 2) { show_version_verbose(); exit(RETURN_SUCCESS); } if (arg_execute) { init(commands); is_mutt_init = true; } if (arg_expand_alias) { struct list_t *alias; if (!is_mutt_init) init(commands); for(alias = aliases; alias; alias = alias->next) { struct address *a = mutt_lookup_alias(alias->data); if (a) { printf("alias->data %s\n", alias->data); mutt_write_address_list(a, stdout, 0, 0); } } exit(RETURN_SUCCESS); } if (arg_query_conf) { if (!is_mutt_init) init(commands); if (queries) return mutt_query_variables(queries); exit(RETURN_SUCCESS); } if (arg_emulate_mailx) { sendflags |= SENDMAILX; } if (arg_mailbox) strfcpy(folder, arg_mailbox, sizeof(folder)); if (arg_mailbox_type) mx_set_magic(arg_mailbox_type); if (arg_resume_postponed) sendflags |= SENDPOSTPONED; /* no-curses for non-terminal session */ if (!isatty(STDIN_FILENO)) { set_bit(options, OPTNOCURSES); sendflags = SENDBATCH; } else { /* * This must come before mutt_init() because curses needs to be started * before calling the init_pair() function to set the color scheme. */ start_curses(); /* check whether terminal status is supported */ term_status = mutt_ts_capability(); } /* Initialize crypto backends. */ crypt_init(); if (!is_mutt_init) init(commands); if (!bit_val(options, OPTNOCURSES)) { SETCOLOR(MT_COLOR_NORMAL); clear(); mutt_error = mutt_curses_error; mutt_message = mutt_curses_message; } /* Create the Maildir directory if it doesn't exist */ if (!bit_val(options, OPTNOCURSES) && Maildir) { struct stat sb; char fpath[_POSIX_PATH_MAX]; char msg[STRING]; strfcpy(fpath, Maildir, sizeof(fpath)); mutt_expand_path(fpath, sizeof(fpath)); #if USE_IMAP /* we're not connected yet - skip mail folder creation */ if (!mx_is_imap(fpath)) #endif if (stat(fpath, &sb) == -1 && errno == ENOENT) { snprintf(msg, sizeof(msg), ("%s does not exist. Create it?"), Maildir); if (mutt_yesorno(msg, M_YES) == M_YES) if (mkdir(fpath, 0700) == -1 && errno != EEXIST) mutt_error( ("Can't create %s: %s."), Maildir, strerror(errno)); } } if (sendflags & SENDPOSTPONED) { if (!bit_val(options, OPTNOCURSES)) mutt_flushinp(); ci_send_message(SENDPOSTPONED, NULL, NULL, NULL, NULL); mutt_endwin(NULL); } else if (arg_subject || msg || sendflags || arg_include || attach) { FILE *fin = NULL; char buf[LONG_STRING]; char *tempfile = NULL, *infile = NULL; char *bodytext = NULL; int rv = 0; if (!bit_val(options, OPTNOCURSES)) mutt_flushinp(); if (!msg) msg = mutt_new_header(); if (!msg->env) msg->env = mutt_new_envelope(); for(; addr_to; addr_to = addr_to->next) { if (url_check_scheme(addr_to->data) == U_MAILTO) { if (url_parse_mailto(msg->env, &bodytext, addr_to->data) < 0) { if (!bit_val(options, OPTNOCURSES)) mutt_endwin(NULL); fputs(("Failed to parse mailto: link\n"), stderr); exit(RETURN_WRONG_ADDR); } } else msg->env->to = rfc822_parse_adrlist(msg->env->to, addr_to->data); } if (bit_val(options, OPTAUTOEDIT) && !msg->env->to && !msg->env->cc) { if (!bit_val(options, OPTNOCURSES)) mutt_endwin(NULL); fputs(("No recipients specified.\n"), stderr); exit(RETURN_ERR_ARG); } if (arg_subject) msg->env->subject = safe_strdup(arg_subject); if (arg_include) infile = arg_include; if (infile || bodytext) { if (infile) { if (mutt_strcmp("-", infile) == 0) fin = stdin; else { char path[_POSIX_PATH_MAX]; strfcpy(path, infile, sizeof(path)); mutt_expand_path(path, sizeof(path)); if ((fin = fopen(path, "r")) == NULL) { if (!bit_val(options, OPTNOCURSES)) mutt_endwin(NULL); perror(path); exit(RETURN_ERR_ARG); } } } mutt_mktemp(buf, sizeof(buf)); tempfile = safe_strdup(buf); /* TODO: is the following if still needed? */ if (tempfile) { FILE *fout; if ((fout = safe_fopen(tempfile, "w")) == NULL) { if (!bit_val(options, OPTNOCURSES)) mutt_endwin(NULL); perror(tempfile); safe_fclose(&fin); safe_free(&tempfile); exit(RETURN_ERR_ARG); } if (fin) mutt_copy_stream(fin, fout); else if (bodytext) fputs(bodytext, fout); safe_fclose(&fout); } if (fin && fin != stdin) safe_fclose(&fin); } safe_free(&bodytext); if (attach) { struct list_t *t = attach; struct body *a = NULL; while(t) { if (a) { a->next = mutt_make_file_attach(t->data); a = a->next; } else msg->content = a = mutt_make_file_attach(t->data); if (!a) { if (!bit_val(options, OPTNOCURSES)) mutt_endwin(NULL); fprintf(stderr, ("%s: unable to attach file.\n"), t->data); mutt_free_list(&attach); exit(RETURN_ERR_ARG); } t = t->next; } mutt_free_list(&attach); } rv = ci_send_message(sendflags, msg, tempfile, NULL, NULL); if (!bit_val(options, OPTNOCURSES)) mutt_endwin(NULL); if (rv) exit(RETURN_ERR_ARG); } else { if (!folder[0]) strfcpy(folder, NONULL(Spoolfile), sizeof(folder)); mutt_expand_path(folder, sizeof(folder)); mutt_str_replace(&CurrentFolder, folder); mutt_str_replace(&LastFolder, folder); mutt_folder_hook(folder); if ((Context = mx_open_mailbox(folder, flags, NULL)) || !arg_mailbox) { mutt_index_menu(); if (Context) safe_free(&Context); } #if USE_IMAP imap_logout_all(); #endif #if USE_SASL mutt_sasl_done(); #endif mutt_free_opts(); mutt_endwin(Errorbuf); } exit(RETURN_SUCCESS); }
pgp_key_t pgp_getkeybystr (char *p, short abilities, pgp_ring_t keyring) { LIST *hints = NULL; pgp_key_t keys; pgp_key_t matches = NULL; pgp_key_t *last = &matches; pgp_key_t k, kn; pgp_uid_t *a; short match; size_t l; const char *ps, *pl; if ((l = mutt_strlen (p)) && p[l-1] == '!') p[l-1] = 0; mutt_message (_("Looking for keys matching \"%s\"..."), p); hints = pgp_add_string_to_hints (hints, p); keys = pgp_get_candidates (keyring, hints); mutt_free_list (&hints); if (!keys) goto out; /* User input may be short or long key ID, independent of OPTPGPLONGIDS. * pgp_key_t->keyid should always contain a long key ID without 0x. * Strip leading "0x" before loops so it doesn't have to be done over and * over again, and prepare pl and ps to simplify logic in the loop's inner * condition. */ pl = (!mutt_strncasecmp (p, "0x", 2) ? p + 2 : p); ps = (mutt_strlen (pl) == 16 ? pl + 8 : pl); for (k = keys; k; k = kn) { kn = k->next; if (abilities && !(k->flags & abilities)) continue; /* This shouldn't happen, but keys without any addresses aren't selectable * in pgp_select_key(). */ if (!k->address) continue; match = 0; dprint (5, (debugfile, "pgp_getkeybystr: matching \"%s\" against key %s:\n", p, pgp_long_keyid (k))); /* If ps != pl it means a long ID (or name of 16 characters) was given, do * not attempt to match short IDs then. Also, it is unnecessary to try to * match pl against long IDs if ps == pl as pl could not be a long ID. */ if (!*p || (ps != pl && mutt_strcasecmp (pl, pgp_long_keyid (k)) == 0) || (ps == pl && mutt_strcasecmp (ps, pgp_short_keyid (k)) == 0)) { dprint (5, (debugfile, "\t\tmatch.\n")); match = 1; } else { for (a = k->address; a; a = a->next) { dprint (5, (debugfile, "pgp_getkeybystr: matching \"%s\" against key %s, \"%s\":\n", p, pgp_long_keyid (k), NONULL (a->addr))); if (mutt_stristr (a->addr, p)) { dprint (5, (debugfile, "\t\tmatch.\n")); match = 1; break; } } } if (match) { *last = pgp_principal_key (k); kn = pgp_remove_key (&keys, *last); last = pgp_get_lastp (k); } } pgp_free_key (&keys); if (matches) { if ((k = pgp_select_key (matches, NULL, p))) pgp_remove_key (&matches, k); pgp_free_key (&matches); if (l && !p[l-1]) p[l-1] = '!'; return k; } out: if (l && !p[l-1]) p[l-1] = '!'; return NULL; }
/* args: * ctx Context info, used when recalling a message to which * we reply. * hdr envelope/attachment info for recalled message * cur if message was a reply, `cur' is set to the message which * `hdr' is in reply to * fcc fcc for the recalled message * fcclen max length of fcc * * return vals: * -1 error/no messages * 0 normal exit * SENDREPLY recalled message is a reply */ int mutt_get_postponed (CONTEXT *ctx, HEADER *hdr, HEADER **cur, char *fcc, size_t fcclen) { HEADER *h; int code = SENDPOSTPONED; LIST *tmp; LIST *last = NULL; LIST *next; char *p; int opt_delete; #ifdef USE_IMAP char curpath[LONG_STRING]; int need_reopen = 0; #endif if (!Postponed) return (-1); #ifdef USE_IMAP /* if we're in an IMAP folder and the postponed folder is also IMAP, we may * need to take steps to avoid opening an additional connection to the same * server. */ if ((ctx && ctx->magic == M_IMAP) && mx_is_imap (Postponed)) { strfcpy (curpath, ctx->path, sizeof (curpath)); if (imap_select_mailbox (ctx, Postponed) < 0) return -1; need_reopen = 1; PostContext = ctx; } else #endif if ((PostContext = mx_open_mailbox (Postponed, M_NOSORT, NULL)) == NULL) { PostCount = 0; mutt_error _("No postponed messages."); return (-1); } if (! PostContext->msgcount) { PostCount = 0; mx_close_mailbox (PostContext, NULL); #ifdef USE_IMAP if (need_reopen) ctx = mx_open_mailbox (curpath, 0, PostContext); else #endif safe_free ((void **) &PostContext); mutt_error _("No postponed messages."); return (-1); } if (PostContext->msgcount == 1) { /* only one message, so just use that one. */ h = PostContext->hdrs[0]; } else if ((h = select_msg ()) == NULL) { mx_close_mailbox (PostContext, NULL); #ifdef USE_IMAP if (need_reopen) ctx = mx_open_mailbox (curpath, 0, PostContext); else #endif safe_free ((void **) &PostContext); return (-1); } if (mutt_prepare_template (NULL, PostContext, hdr, h, 0) < 0) { mx_fastclose_mailbox (PostContext); #ifdef USE_IMAP if (need_reopen) ctx = mx_open_mailbox (curpath, 0, NULL); else #endif safe_free ((void **) &PostContext); return (-1); } /* finished with this message, so delete it. */ mutt_set_flag (PostContext, h, M_DELETE, 1); /* update the count for the status display */ PostCount = PostContext->msgcount - PostContext->deleted; /* avoid the "purge deleted messages" prompt */ opt_delete = quadoption (OPT_DELETE); set_quadoption (OPT_DELETE, M_YES); mx_close_mailbox (PostContext, NULL); set_quadoption (OPT_DELETE, opt_delete); #ifdef USE_IMAP if (need_reopen) ctx = mx_open_mailbox (curpath, 0, PostContext); else #endif safe_free ((void **) &PostContext); for (tmp = hdr->env->userhdrs; tmp; ) { if (mutt_strncasecmp ("X-Mutt-References:", tmp->data, 18) == 0) { if (ctx) { /* if a mailbox is currently open, look to see if the orignal message the user attempted to reply to is in this mailbox */ p = tmp->data + 18; SKIPWS (p); *cur = hash_find (ctx->id_hash, p); } /* Remove the X-Mutt-References: header field. */ next = tmp->next; if (last) last->next = tmp->next; else hdr->env->userhdrs = tmp->next; tmp->next = NULL; mutt_free_list (&tmp); tmp = next; if (*cur) code |= SENDREPLY; } else if (mutt_strncasecmp ("X-Mutt-Fcc:", tmp->data, 11) == 0) { p = tmp->data + 11; SKIPWS (p); strfcpy (fcc, p, fcclen); mutt_pretty_mailbox (fcc); /* remove the X-Mutt-Fcc: header field */ next = tmp->next; if (last) last->next = tmp->next; else hdr->env->userhdrs = tmp->next; tmp->next = NULL; mutt_free_list (&tmp); tmp = next; } #ifdef HAVE_PGP else if (mutt_strncmp ("Pgp:", tmp->data, 4) == 0 /* this is generated * by old mutt versions */ || mutt_strncmp ("X-Mutt-PGP:", tmp->data, 11) == 0) { hdr->pgp = mutt_parse_pgp_hdr (strchr (tmp->data, ':') + 1, 1); /* remove the pgp field */ next = tmp->next; if (last) last->next = tmp->next; else hdr->env->userhdrs = tmp->next; tmp->next = NULL; mutt_free_list (&tmp); tmp = next; } #endif /* HAVE_PGP */ #ifdef MIXMASTER else if (mutt_strncmp ("X-Mutt-Mix:", tmp->data, 11) == 0) { char *t; mutt_free_list (&hdr->chain); t = strtok (tmp->data + 11, " \t\n"); while (t) { hdr->chain = mutt_add_list (hdr->chain, t); t = strtok (NULL, " \t\n"); } next = tmp->next; if (last) last->next = tmp->next; else hdr->env->userhdrs = tmp->next; tmp->next = NULL; mutt_free_list (&tmp); tmp = next; } #endif else { last = tmp; tmp = tmp->next; } } return (code); }
int mutt_prepare_template (FILE *fp, CONTEXT *ctx, HEADER *newhdr, HEADER *hdr, short weed) { MESSAGE *msg = NULL; char file[_POSIX_PATH_MAX]; LIST *p, **q; BODY *b; FILE *bfp; if (!fp && (msg = mx_open_message (ctx, hdr->msgno)) == NULL) return (-1); if (!fp) fp = msg->fp; bfp = fp; /* parse the message header and MIME structure */ fseek (fp, hdr->offset, 0); newhdr->offset = hdr->offset; newhdr->env = mutt_read_rfc822_header (fp, newhdr, 1, weed); newhdr->content->length = hdr->content->length; mutt_parse_part (fp, newhdr->content); /* weed user-agent, x-mailer - we don't want them here */ p = newhdr->env->userhdrs; q = &newhdr->env->userhdrs; while (p) { if (!strncasecmp (p->data, "x-mailer:", 9) || !strncasecmp (p->data, "user-agent:", 11)) { *q = p->next; p->next = NULL; mutt_free_list (&p); } else q = &p->next; p = *q; } safe_free ((void **) &newhdr->env->message_id); safe_free ((void **) &newhdr->env->mail_followup_to); #ifdef HAVE_PGP /* decrypt pgp/mime encoded messages */ if ((hdr->pgp & PGPENCRYPT) && mutt_is_multipart_encrypted (newhdr->content)) { newhdr->pgp |= PGPENCRYPT; if (!pgp_valid_passphrase()) goto err; mutt_message _("Invoking PGP..."); if (pgp_decrypt_mime (fp, &bfp, newhdr->content, &b) == -1) { err: mx_close_message (&msg); mutt_free_envelope (&newhdr->env); mutt_free_body (&newhdr->content); return -1; } mutt_free_body (&newhdr->content); newhdr->content = b; mutt_clear_error (); } /* * remove a potential multipart/signed layer - useful when * resending messages */ if (mutt_is_multipart_signed (newhdr->content)) { newhdr->pgp |= PGPSIGN; /* destroy the signature */ mutt_free_body (&newhdr->content->parts->next); newhdr->content = mutt_remove_multipart (newhdr->content); } #endif /* * We don't need no primary multipart. * Note: We _do_ preserve messages! * * XXX - we don't handle multipart/alternative in any * smart way when sending messages. However, one may * consider this a feature. * */ if (newhdr->content->type == TYPEMULTIPART) newhdr->content = mutt_remove_multipart (newhdr->content); /* create temporary files for all attachments */ for (b = newhdr->content; b; b = b->next) { /* what follows is roughly a receive-mode variant of * mutt_get_tmp_attachment () from muttlib.c */ file[0] = '\0'; if (b->filename) { strfcpy (file, b->filename, sizeof (file)); b->d_filename = safe_strdup (b->filename); } else /* avoid Content-Disposition: header with temporary filename */ b->use_disp = 0; mutt_adv_mktemp (file, sizeof(file)); if (mutt_save_attachment (bfp, b, file, 0, NULL) == -1) { mutt_free_envelope (&newhdr->env); mutt_free_body (&newhdr->content); if (bfp != fp) fclose (bfp); if (msg) mx_close_message (&msg); return -1; } mutt_str_replace (&b->filename, file); b->unlink = 1; if (mutt_is_text_type (b->type, b->subtype)) b->noconv = 1; mutt_stamp_attachment (b); mutt_free_body (&b->parts); if (b->hdr) b->hdr->content = NULL; /* avoid dangling pointer */ } /* that's it. */ if (bfp != fp) fclose (bfp); if (msg) mx_close_message (&msg); return 0; }
/* args: * ctx Context info, used when recalling a message to which * we reply. * hdr envelope/attachment info for recalled message * cur if message was a reply, `cur' is set to the message which * `hdr' is in reply to * fcc fcc for the recalled message * fcclen max length of fcc * * return vals: * -1 error/no messages * 0 normal exit * SENDREPLY recalled message is a reply */ int mutt_get_postponed (CONTEXT * ctx, HEADER * hdr, HEADER ** cur, char *fcc, size_t fcclen) { HEADER *h; int code = SENDPOSTPONED; LIST *tmp; LIST *last = NULL; LIST *next; char *p; int opt_delete; if (!Postponed) return (-1); if ((PostContext = mx_open_mailbox (Postponed, M_NOSORT, NULL)) == NULL) { PostCount = 0; mutt_error _("No postponed messages."); return (-1); } if (!PostContext->msgcount) { PostCount = 0; mx_close_mailbox (PostContext, NULL); mem_free (&PostContext); mutt_error _("No postponed messages."); return (-1); } if (PostContext->msgcount == 1) { /* only one message, so just use that one. */ h = PostContext->hdrs[0]; } else if ((h = select_msg ()) == NULL) { mx_close_mailbox (PostContext, NULL); mem_free (&PostContext); return (-1); } if (mutt_prepare_template (NULL, PostContext, hdr, h, 0) < 0) { mx_fastclose_mailbox (PostContext); mem_free (&PostContext); return (-1); } /* finished with this message, so delete it. */ mutt_set_flag (PostContext, h, M_DELETE, 1); /* and consider it saved, so that it won't be moved to the trash folder */ mutt_set_flag (PostContext, h, M_APPENDED, 1); /* update the count for the status display */ PostCount = PostContext->msgcount - PostContext->deleted; /* avoid the "purge deleted messages" prompt */ opt_delete = quadoption (OPT_DELETE); set_quadoption (OPT_DELETE, M_YES); mx_close_mailbox (PostContext, NULL); set_quadoption (OPT_DELETE, opt_delete); mem_free (&PostContext); for (tmp = hdr->env->userhdrs; tmp;) { if (ascii_strncasecmp ("X-Mutt-References:", tmp->data, 18) == 0) { if (ctx) { /* if a mailbox is currently open, look to see if the orignal message the user attempted to reply to is in this mailbox */ p = tmp->data + 18; SKIPWS (p); if (!ctx->id_hash) ctx->id_hash = mutt_make_id_hash (ctx); *cur = hash_find (ctx->id_hash, p); } /* Remove the X-Mutt-References: header field. */ next = tmp->next; if (last) last->next = tmp->next; else hdr->env->userhdrs = tmp->next; tmp->next = NULL; mutt_free_list (&tmp); tmp = next; if (*cur) code |= SENDREPLY; } else if (ascii_strncasecmp ("X-Mutt-Fcc:", tmp->data, 11) == 0) { p = tmp->data + 11; SKIPWS (p); strfcpy (fcc, p, fcclen); mutt_pretty_mailbox (fcc); /* remove the X-Mutt-Fcc: header field */ next = tmp->next; if (last) last->next = tmp->next; else hdr->env->userhdrs = tmp->next; tmp->next = NULL; mutt_free_list (&tmp); tmp = next; } else if ((WithCrypto & APPLICATION_PGP) && (str_ncmp ("Pgp:", tmp->data, 4) == 0 /* this is generated * by old mutt versions */ || str_ncmp ("X-Mutt-PGP:", tmp->data, 11) == 0)) { hdr->security = mutt_parse_crypt_hdr (strchr (tmp->data, ':') + 1, 1); hdr->security |= APPLICATION_PGP; /* remove the pgp field */ next = tmp->next; if (last) last->next = tmp->next; else hdr->env->userhdrs = tmp->next; tmp->next = NULL; mutt_free_list (&tmp); tmp = next; } else if ((WithCrypto & APPLICATION_SMIME) && str_ncmp ("X-Mutt-SMIME:", tmp->data, 13) == 0) { hdr->security = mutt_parse_crypt_hdr (strchr (tmp->data, ':') + 1, 1); hdr->security |= APPLICATION_SMIME; /* remove the smime field */ next = tmp->next; if (last) last->next = tmp->next; else hdr->env->userhdrs = tmp->next; tmp->next = NULL; mutt_free_list (&tmp); tmp = next; } #ifdef MIXMASTER else if (str_ncmp ("X-Mutt-Mix:", tmp->data, 11) == 0) { char *t; mutt_free_list (&hdr->chain); t = strtok (tmp->data + 11, " \t\n"); while (t) { hdr->chain = mutt_add_list (hdr->chain, t); t = strtok (NULL, " \t\n"); } next = tmp->next; if (last) last->next = tmp->next; else hdr->env->userhdrs = tmp->next; tmp->next = NULL; mutt_free_list (&tmp); tmp = next; } #endif else { last = tmp; tmp = tmp->next; } } return (code); }
void mix_make_chain (LIST **chainp, int *redraw) { LIST *p; MIXCHAIN *chain; int c_cur = 0, c_old = 0; short c_redraw = 1; REMAILER **type2_list = NULL; size_t ttll = 0; struct coord *coords = NULL; MUTTMENU *menu; char helpstr[LONG_STRING]; short loop = 1; int op; int i, j; char *t; if (!(type2_list = mix_type2_list (&ttll))) { mutt_error _("Can't get mixmaster's type2.list!"); return; } *redraw = REDRAW_FULL; chain = safe_calloc (sizeof (MIXCHAIN), 1); for (p = *chainp; p; p = p->next) mix_chain_add (chain, (char *) p->data, type2_list); mutt_free_list (chainp); /* safety check */ for (i = 0; i < chain->cl; i++) { if (chain->ch[i] >= ttll) chain->ch[i] = 0; } mix_screen_coordinates (type2_list, &coords, chain, 0); menu = mutt_new_menu (MENU_MIX); menu->max = ttll; menu->make_entry = mix_entry; menu->tag = NULL; menu->title = _("Select a remailer chain."); menu->data = type2_list; menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_MIX, RemailerHelp); menu->pagelen = MIX_VOFFSET - 1; while (loop) { if (menu->pagelen != MIX_VOFFSET - 1) { menu->pagelen = MIX_VOFFSET - 1; menu->redraw = REDRAW_FULL; } if (c_redraw) { mix_redraw_head (chain); mix_redraw_chain (type2_list, coords, chain, c_cur); c_redraw = 0; } else if (c_cur != c_old) { mix_redraw_ce (type2_list, coords, chain, c_old, 0); mix_redraw_ce (type2_list, coords, chain, c_cur, 1); } c_old = c_cur; switch ((op = mutt_menuLoop (menu))) { case OP_REDRAW: { menu_redraw_status (menu); mix_redraw_head (chain); mix_screen_coordinates (type2_list, &coords, chain, 0); mix_redraw_chain (type2_list, coords, chain, c_cur); menu->pagelen = MIX_VOFFSET - 1; break; } case OP_EXIT: { chain->cl = 0; loop = 0; break; } case OP_MIX_USE: { if (!chain->cl) { chain->cl++; chain->ch[0] = menu->current; mix_screen_coordinates (type2_list, &coords, chain, c_cur); c_redraw = 1; } if (chain->cl && chain->ch[chain->cl - 1] && (type2_list[chain->ch[chain->cl-1]]->caps & MIX_CAP_MIDDLEMAN)) { mutt_error ( _("Error: %s can't be used as the final remailer of a chain."), type2_list[chain->ch[chain->cl - 1]]->shortname); } else { loop = 0; } break; } case OP_GENERIC_SELECT_ENTRY: case OP_MIX_APPEND: { if (chain->cl < MAXMIXES && c_cur < chain->cl) c_cur++; } /* fallthrough */ case OP_MIX_INSERT: { if (chain->cl < MAXMIXES) { chain->cl++; for (i = chain->cl - 1; i > c_cur; i--) chain->ch[i] = chain->ch[i-1]; chain->ch[c_cur] = menu->current; mix_screen_coordinates (type2_list, &coords, chain, c_cur); c_redraw = 1; } else mutt_error ( _("Mixmaster chains are limited to %d elements."), MAXMIXES); break; } case OP_MIX_DELETE: { if (chain->cl) { chain->cl--; for (i = c_cur; i < chain->cl; i++) chain->ch[i] = chain->ch[i+1]; if (c_cur == chain->cl && c_cur) c_cur--; mix_screen_coordinates (type2_list, &coords, chain, c_cur); c_redraw = 1; } else { mutt_error _("The remailer chain is already empty."); } break; } case OP_MIX_CHAIN_PREV: { if (c_cur) c_cur--; else mutt_error _("You already have the first chain element selected."); break; } case OP_MIX_CHAIN_NEXT: { if (chain->cl && c_cur < chain->cl - 1) c_cur++; else mutt_error _("You already have the last chain element selected."); break; } } } mutt_menuDestroy (&menu); /* construct the remailer list */ if (chain->cl) { for (i = 0; i < chain->cl; i++) { if ((j = chain->ch[i])) t = type2_list[j]->shortname; else t = "*"; *chainp = mutt_add_list (*chainp, t); } } mix_free_type2_list (&type2_list); FREE (&coords); FREE (&chain); }
void mutt_edit_headers (const char *editor, const char *body, HEADER *msg, char *fcc, size_t fcclen) { char path[_POSIX_PATH_MAX]; /* tempfile used to edit headers + body */ char buffer[LONG_STRING]; char *p; FILE *ifp, *ofp; int i, keep; int in_reply_to = 0; /* did we see the in-reply-to field ? */ ENVELOPE *n; time_t mtime; struct stat st; LIST *cur, *last = NULL, *tmp; mutt_mktemp (path); if ((ofp = safe_fopen (path, "w")) == NULL) { mutt_perror (path); return; } mutt_write_rfc822_header (ofp, msg->env, NULL, 1, 0); fputc ('\n', ofp); /* tie off the header. */ /* now copy the body of the message. */ if ((ifp = fopen (body, "r")) == NULL) { mutt_perror (body); return; } mutt_copy_stream (ifp, ofp); fclose (ifp); fclose (ofp); if (stat (path, &st) == -1) { mutt_perror (path); return; } mtime = st.st_mtime; mutt_edit_file (editor, path); stat (path, &st); if (mtime == st.st_mtime) { dprint (1, (debugfile, "ci_edit_headers(): temp file was not modified.\n")); /* the file has not changed! */ mutt_unlink (path); return; } mutt_unlink (body); mutt_free_list (&msg->env->userhdrs); /* Read the temp file back in */ if ((ifp = fopen (path, "r")) == NULL) { mutt_perror (path); return; } if ((ofp = safe_fopen (body, "w")) == NULL) { /* intentionally leak a possible temporary file here */ fclose (ifp); mutt_perror (body); return; } n = mutt_read_rfc822_header (ifp, NULL, 1, 0); while ((i = fread (buffer, 1, sizeof (buffer), ifp)) > 0) fwrite (buffer, 1, i, ofp); fclose (ofp); fclose (ifp); mutt_unlink (path); /* restore old info. */ n->references = msg->env->references; msg->env->references = NULL; mutt_free_envelope (&msg->env); msg->env = n; mutt_expand_aliases_env (msg->env); /* search through the user defined headers added to see if either a * fcc: or attach-file: field was specified. */ cur = msg->env->userhdrs; while (cur) { keep = 1; /* keep track of whether or not we see the in-reply-to field. if we did * not, remove the references: field later so that we can generate a new * message based upon this one. */ if (mutt_strncasecmp ("in-reply-to. good thing you replied:", cur->data, 12) == 0) in_reply_to = 1; else if (fcc && mutt_strncasecmp ("fcc:", cur->data, 4) == 0) { p = cur->data + 4; SKIPWS (p); if (*p) { strfcpy (fcc, p, fcclen); mutt_pretty_mailbox (fcc); } keep = 0; } else if (mutt_strncasecmp ("attach file:", cur->data, 7) == 0) { BODY *body; BODY *parts; char *q; p = cur->data + 7; SKIPWS (p); if (*p) { if ((q = strpbrk (p, " \t"))) { mutt_substrcpy (path, p, q, sizeof (path)); SKIPWS (q); } else strfcpy (path, p, sizeof (path)); mutt_expand_path (path, sizeof (path)); if ((body = mutt_make_file_attach (path))) { body->description = safe_strdup (q); for (parts = msg->content; parts->next; parts = parts->next) ; parts->next = body; } else { mutt_pretty_mailbox (path); mutt_error (_("%s: unable to attach file. try again"), path); } } keep = 0; } #ifdef HAVE_PGP else if (mutt_strncasecmp ("pgp:", cur->data, 4) == 0) { msg->pgp = mutt_parse_pgp_hdr (cur->data + 4, 0); keep = 0; } #endif if (keep) { last = cur; cur = cur->next; } else { if (last) last->next = cur->next; else msg->env->userhdrs = cur->next; tmp = cur; cur = cur->next; tmp->next = NULL; mutt_free_list (&tmp); } } if (!in_reply_to) mutt_free_list (&msg->env->references); }