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) unlink (b->filename); safe_free ((void **) &b->filename); safe_free ((void **) &b->content); safe_free ((void **) &b->xtype); safe_free ((void **) &b->subtype); safe_free ((void **) &b->description); safe_free ((void **) &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); safe_free ((void **) &b); } *p = 0; }
HEADER * mutt_hcache_restore(const unsigned char *d, HEADER ** oh) { int off = 0; HEADER *h = mutt_new_header(); int convert = !Charset_is_utf8; /* skip validate */ off += sizeof (validate); /* skip crc */ off += sizeof (unsigned int); memcpy(h, d + off, sizeof (HEADER)); off += sizeof (HEADER); h->env = mutt_new_envelope(); restore_envelope(h->env, d, &off, convert); h->content = mutt_new_body(); restore_body(h->content, d, &off, convert); restore_char(&h->maildir_flags, d, &off, convert); /* this is needed for maildir style mailboxes */ if (oh) { h->old = (*oh)->old; h->path = safe_strdup((*oh)->path); mutt_free_header(oh); } return h; }
static void maildir_free_entry(struct maildir **md) { if(!md || !*md) return; safe_free((void **) &(*md)->canon_fname); if((*md)->h) mutt_free_header(&(*md)->h); safe_free((void **) md); }
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); } 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; }
int mh_check_mailbox(CONTEXT *ctx, int *index_hint) { char buf[_POSIX_PATH_MAX], b1[LONG_STRING], b2[LONG_STRING]; struct stat st, st_cur; short modified = 0, have_new = 0, occult = 0; struct maildir *md, *p; struct maildir **last; HASH *fnames; int i, j; if(!option (OPTCHECKNEW)) return 0; if(ctx->magic == M_MH) { strfcpy(buf, ctx->path, sizeof(buf)); if(stat(buf, &st) == -1) return -1; /* create .mh_sequences when there isn't one. */ snprintf (buf, sizeof (buf), "%s/.mh_sequences", ctx->path); if (stat (buf, &st_cur) == -1) { if (errno == ENOENT) { char *tmp; FILE *fp = NULL; if (mh_mkstemp (ctx, &fp, &tmp) == 0) { safe_fclose (&fp); if (safe_rename (tmp, buf) == -1) unlink (tmp); safe_free ((void **) &tmp); } if (stat (buf, &st_cur) == -1) modified = 1; } else modified = 1; } } else if(ctx->magic == M_MAILDIR) { snprintf(buf, sizeof(buf), "%s/new", ctx->path); if(stat(buf, &st) == -1) return -1; snprintf(buf, sizeof(buf), "%s/cur", ctx->path); if(stat(buf, &st_cur) == -1) /* XXX - name is bad. */ modified = 1; } if(!modified && ctx->magic == M_MAILDIR && st_cur.st_mtime > ctx->mtime_cur) modified = 1; if(!modified && ctx->magic == M_MH && (st.st_mtime > ctx->mtime || st_cur.st_mtime > ctx->mtime_cur)) modified = 1; if(modified || (ctx->magic == M_MAILDIR && st.st_mtime > ctx->mtime)) have_new = 1; if(!modified && !have_new) return 0; ctx->mtime_cur = st_cur.st_mtime; ctx->mtime = st.st_mtime; #if 0 if(Sort != SORT_ORDER) { short old_sort; old_sort = Sort; Sort = SORT_ORDER; mutt_sort_headers(ctx, 1); Sort = old_sort; } #endif md = NULL; last = &md; if(ctx->magic == M_MAILDIR) { if(have_new) maildir_parse_dir(ctx, &last, "new", NULL); if(modified) maildir_parse_dir(ctx, &last, "cur", NULL); } else if(ctx->magic == M_MH) { struct mh_sequences mhs; memset (&mhs, 0, sizeof (mhs)); maildir_parse_dir (ctx, &last, NULL, NULL); mh_read_sequences (&mhs, ctx->path); mh_update_maildir (md, &mhs); mhs_free_sequences (&mhs); } /* check for modifications and adjust flags */ fnames = hash_create (1031); for(p = md; p; p = p->next) { if(ctx->magic == M_MAILDIR) { maildir_canon_filename(b2, p->h->path, sizeof(b2)); p->canon_fname = safe_strdup(b2); } else p->canon_fname = safe_strdup(p->h->path); hash_insert(fnames, p->canon_fname, p, 0); } for(i = 0; i < ctx->msgcount; i++) { ctx->hdrs[i]->active = 0; if(ctx->magic == M_MAILDIR) maildir_canon_filename(b1, ctx->hdrs[i]->path, sizeof(b1)); else strfcpy(b1, ctx->hdrs[i]->path, sizeof(b1)); dprint(2, (debugfile, "%s:%d: mh_check_mailbox(): Looking for %s.\n", __FILE__, __LINE__, b1)); if((p = hash_find(fnames, b1)) && p->h && mbox_strict_cmp_headers(ctx->hdrs[i], p->h)) { /* found the right message */ dprint(2, (debugfile, "%s:%d: Found. Flags before: %s%s%s%s%s\n", __FILE__, __LINE__, ctx->hdrs[i]->flagged ? "f" : "", ctx->hdrs[i]->deleted ? "D" : "", ctx->hdrs[i]->replied ? "r" : "", ctx->hdrs[i]->old ? "O" : "", ctx->hdrs[i]->read ? "R" : "")); if(mutt_strcmp(ctx->hdrs[i]->path, p->h->path)) mutt_str_replace (&ctx->hdrs[i]->path, p->h->path); if(modified) { if(!ctx->hdrs[i]->changed) { mutt_set_flag (ctx, ctx->hdrs[i], M_FLAG, p->h->flagged); mutt_set_flag (ctx, ctx->hdrs[i], M_REPLIED, p->h->replied); mutt_set_flag (ctx, ctx->hdrs[i], M_READ, p->h->read); } mutt_set_flag(ctx, ctx->hdrs[i], M_OLD, p->h->old); } ctx->hdrs[i]->active = 1; dprint(2, (debugfile, "%s:%d: Flags after: %s%s%s%s%s\n", __FILE__, __LINE__, ctx->hdrs[i]->flagged ? "f" : "", ctx->hdrs[i]->deleted ? "D" : "", ctx->hdrs[i]->replied ? "r" : "", ctx->hdrs[i]->old ? "O" : "", ctx->hdrs[i]->read ? "R" : "")); mutt_free_header(&p->h); } else if (ctx->magic == M_MAILDIR && !modified && !strncmp("cur/", ctx->hdrs[i]->path, 4)) { /* If the cur/ part wasn't externally modified for a maildir * type folder, assume the message is still active. Actually, * we simply don't know. */ ctx->hdrs[i]->active = 1; } else if (modified || (ctx->magic == M_MAILDIR && !strncmp("new/", ctx->hdrs[i]->path, 4))) { /* Mailbox was modified, or a new message vanished. */ /* Note: This code will _not_ apply for a new message which * is just moved to cur/, as this would modify cur's time * stamp and lead to modified == 1. Thus, we'd have parsed * the complete folder above, and the message would have * been found in the look-up table. */ dprint(2, (debugfile, "%s:%d: Not found. Flags were: %s%s%s%s%s\n", __FILE__, __LINE__, ctx->hdrs[i]->flagged ? "f" : "", ctx->hdrs[i]->deleted ? "D" : "", ctx->hdrs[i]->replied ? "r" : "", ctx->hdrs[i]->old ? "O" : "", ctx->hdrs[i]->read ? "R" : "")); occult = 1; } } /* destroy the file name hash */ hash_destroy(&fnames, NULL); /* If we didn't just get new mail, update the tables. */ if(modified || occult) { short old_sort; int old_count; #ifndef LIBMUTT if (Sort != SORT_ORDER) { old_sort = Sort; Sort = SORT_ORDER; mutt_sort_headers (ctx, 1); Sort = old_sort; } #endif old_count = ctx->msgcount; for (i = 0, j = 0; i < old_count; i++) { if (ctx->hdrs[i]->active && index_hint && *index_hint == i) *index_hint = j; if (ctx->hdrs[i]->active) ctx->hdrs[i]->index = j++; } mx_update_tables(ctx, 0); } /* Incorporate new messages */ maildir_move_to_context(ctx, &md); return (modified || occult) ? M_REOPENED : have_new ? M_NEW_MAIL : 0; }
static void append_message(CONTEXT *ctx, notmuch_query_t *q, notmuch_message_t *msg, int dedup) { char *newpath = NULL; const char *path; HEADER *h = NULL; /* deduplicate */ if (dedup && get_mutt_header(ctx, msg)) { get_ctxdata(ctx)->ignmsgcount++; nm_progress_update(ctx, q); dprint(2, (debugfile, "nm: ignore id=%s, already in the context\n", notmuch_message_get_message_id(msg))); return; } path = get_message_last_filename(msg); if (!path) return; dprint(2, (debugfile, "nm: appending message, i=%d, id=%s, path=%s\n", ctx->msgcount, notmuch_message_get_message_id(msg), path)); if (ctx->msgcount >= ctx->hdrmax) { dprint(2, (debugfile, "nm: allocate mx memory\n")); mx_alloc_memory(ctx); } if (access(path, F_OK) == 0) h = maildir_parse_message(M_MAILDIR, path, 0, NULL); else { /* maybe moved try find it... */ char *folder = get_folder_from_path(path); if (folder) { FILE *f = maildir_open_find_message(folder, path, &newpath); if (f) { h = maildir_parse_stream(M_MAILDIR, f, newpath, 0, NULL); fclose(f); dprint(1, (debugfile, "nm: not up-to-date: %s -> %s\n", path, newpath)); } } FREE(&folder); } if (!h) { dprint(1, (debugfile, "nm: failed to parse message: %s\n", path)); goto done; } if (init_header(h, newpath ? newpath : path, msg) != 0) { mutt_free_header(&h); dprint(1, (debugfile, "nm: failed to append header!\n")); goto done; } h->active = 1; h->index = ctx->msgcount; ctx->size += h->content->length + h->content->offset - h->content->hdr_offset; ctx->hdrs[ctx->msgcount] = h; ctx->msgcount++; if (newpath) { /* remember that file has been moved -- nm_sync() will update the DB */ struct nm_hdrdata *hd = (struct nm_hdrdata *) h->data; if (hd) { dprint(1, (debugfile, "nm: remember obsolete path: %s\n", path)); hd->oldpath = safe_strdup(path); } } nm_progress_update(ctx, q); done: FREE(&newpath); }
/* returns 0 on success, -1 on error */ int mutt_decode_save_attachment (FILE *fp, BODY *m, char *path, int displaying, int flags) { STATE s; unsigned int saved_encoding = 0; BODY *saved_parts = NULL; HEADER *saved_hdr = NULL; memset (&s, 0, sizeof (s)); s.flags = displaying; if (flags == M_SAVE_APPEND) s.fpout = fopen (path, "a"); else if (flags == M_SAVE_OVERWRITE) s.fpout = fopen (path, "w"); /* __FOPEN_CHECKED__ */ else s.fpout = safe_fopen (path, "w"); if (s.fpout == NULL) { mutt_perror ("fopen"); return (-1); } if (fp == NULL) { /* When called from the compose menu, the attachment isn't parsed, * so we need to do it here. */ struct stat st; if (stat (m->filename, &st) == -1) { mutt_perror ("stat"); safe_fclose (&s.fpout); return (-1); } if ((s.fpin = fopen (m->filename, "r")) == NULL) { mutt_perror ("fopen"); return (-1); } saved_encoding = m->encoding; if (!is_multipart (m)) m->encoding = ENC8BIT; m->length = st.st_size; m->offset = 0; saved_parts = m->parts; saved_hdr = m->hdr; mutt_parse_part (s.fpin, m); if (m->noconv || is_multipart (m)) s.flags |= M_CHARCONV; } else { s.fpin = fp; s.flags |= M_CHARCONV; } mutt_body_handler (m, &s); safe_fclose (&s.fpout); if (fp == NULL) { m->length = 0; m->encoding = saved_encoding; if (saved_parts) { mutt_free_header (&m->hdr); m->parts = saved_parts; m->hdr = saved_hdr; } safe_fclose (&s.fpin); } return (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; char *tail = ""; int recurse = 0; do { recurse = 0; switch (*s) { case '~': { if (*(s + 1) == '/' || *(s + 1) == 0) { strfcpy (p, NONULL(Homedir), sizeof (p)); tail = s + 1; } else { struct passwd *pw; if ((t = strchr (s + 1, '/'))) *t = 0; 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 = '/'; *p = '\0'; tail = s; } } } break; case '=': case '+': { #ifdef USE_IMAP /* special case: folder = {host}: don't append slash */ if (mx_is_imap (NONULL (Maildir)) && Maildir[strlen (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; default: { *p = '\0'; tail = s; } } 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); }
int ci_send_message (int flags, /* send mode */ HEADER *msg, /* template to use for new message */ char *tempfile, /* file specified by -i or -H */ CONTEXT *ctx, /* current mailbox */ HEADER *cur) /* current message */ { char buffer[LONG_STRING]; char fcc[_POSIX_PATH_MAX] = ""; /* where to copy this message */ FILE *tempfp = NULL; BODY *pbody; int i, killfrom = 0; int fcc_error = 0; int free_clear_content = 0; BODY *save_content = NULL; BODY *clear_content = NULL; char *pgpkeylist = NULL; /* save current value of "pgp_sign_as" */ char *signas = NULL; char *tag = NULL, *err = NULL; char *ctype; int rv = -1; if (!flags && !msg && quadoption (OPT_RECALL) != M_NO && mutt_num_postponed (1)) { /* If the user is composing a new message, check to see if there * are any postponed messages first. */ if ((i = query_quadoption (OPT_RECALL, _("Recall postponed message?"))) == -1) return rv; if(i == M_YES) flags |= SENDPOSTPONED; } if ((WithCrypto & APPLICATION_PGP) && (flags & SENDPOSTPONED)) signas = safe_strdup(PgpSignAs); /* Delay expansion of aliases until absolutely necessary--shouldn't * be necessary unless we are prompting the user or about to execute a * send-hook. */ if (!msg) { msg = mutt_new_header (); if (flags == SENDPOSTPONED) { if ((flags = mutt_get_postponed (ctx, msg, &cur, fcc, sizeof (fcc))) < 0) goto cleanup; } if (flags & (SENDPOSTPONED|SENDRESEND)) { if ((tempfp = safe_fopen (msg->content->filename, "a+")) == NULL) { mutt_perror (msg->content->filename); goto cleanup; } } if (!msg->env) msg->env = mutt_new_envelope (); } /* Parse and use an eventual list-post header */ if ((flags & SENDLISTREPLY) && cur && cur->env && cur->env->list_post) { /* Use any list-post header as a template */ url_parse_mailto (msg->env, NULL, cur->env->list_post); /* We don't let them set the sender's address. */ rfc822_free_address (&msg->env->from); } if (! (flags & (SENDKEY | SENDPOSTPONED | SENDRESEND))) { pbody = mutt_new_body (); pbody->next = msg->content; /* don't kill command-line attachments */ msg->content = pbody; if (!(ctype = safe_strdup (ContentType))) ctype = safe_strdup ("text/plain"); mutt_parse_content_type (ctype, msg->content); FREE (&ctype); msg->content->unlink = 1; msg->content->use_disp = 0; msg->content->disposition = DISPINLINE; if (!tempfile) { mutt_mktemp (buffer, sizeof (buffer)); tempfp = safe_fopen (buffer, "w+"); msg->content->filename = safe_strdup (buffer); } else { tempfp = safe_fopen (tempfile, "a+"); msg->content->filename = safe_strdup (tempfile); } if (!tempfp) { dprint(1,(debugfile, "newsend_message: can't create tempfile %s (errno=%d)\n", msg->content->filename, errno)); mutt_perror (msg->content->filename); goto cleanup; } } /* this is handled here so that the user can match ~f in send-hook */ if (cur && option (OPTREVNAME) && !(flags & (SENDPOSTPONED|SENDRESEND))) { /* we shouldn't have to worry about freeing `msg->env->from' before * setting it here since this code will only execute when doing some * sort of reply. the pointer will only be set when using the -H command * line option. * * We shouldn't have to worry about alias expansion here since we are * either replying to a real or postponed message, therefore no aliases * should exist since the user has not had the opportunity to add * addresses to the list. We just have to ensure the postponed messages * have their aliases expanded. */ msg->env->from = set_reverse_name (cur->env); } if (! (flags & (SENDPOSTPONED|SENDRESEND))) { if ((flags & (SENDREPLY | SENDFORWARD)) && ctx && envelope_defaults (msg->env, ctx, cur, flags) == -1) goto cleanup; if (option (OPTHDRS)) process_user_recips (msg->env); /* Expand aliases and remove duplicates/crossrefs */ mutt_expand_aliases_env (msg->env); if (flags & SENDREPLY) mutt_fix_reply_recipients (msg->env); if (! (flags & (SENDMAILX|SENDBATCH)) && ! (option (OPTAUTOEDIT) && option (OPTEDITHDRS)) && ! ((flags & SENDREPLY) && option (OPTFASTREPLY))) { if (edit_envelope (msg->env) == -1) goto cleanup; } /* the from address must be set here regardless of whether or not * $use_from is set so that the `~P' (from you) operator in send-hook * patterns will work. if $use_from is unset, the from address is killed * after send-hooks are evaulated */ if (!msg->env->from) { msg->env->from = mutt_default_from (); killfrom = 1; } if ((flags & SENDREPLY) && cur) { /* change setting based upon message we are replying to */ mutt_message_hook (ctx, cur, M_REPLYHOOK); /* * set the replied flag for the message we are generating so that the * user can use ~Q in a send-hook to know when reply-hook's are also * being used. */ msg->replied = 1; } /* change settings based upon recipients */ mutt_message_hook (NULL, msg, M_SENDHOOK); /* * Unset the replied flag from the message we are composing since it is * no longer required. This is done here because the FCC'd copy of * this message was erroneously get the 'R'eplied flag when stored in * a maildir-style mailbox. */ msg->replied = 0; if (! (flags & SENDKEY)) { if (option (OPTTEXTFLOWED) && msg->content->type == TYPETEXT && !ascii_strcasecmp (msg->content->subtype, "plain")) mutt_set_parameter ("format", "flowed", &msg->content->parameter); } /* $use_from and/or $from might have changed in a send-hook */ if (killfrom) { rfc822_free_address (&msg->env->from); if (option (OPTUSEFROM) && !(flags & (SENDPOSTPONED|SENDRESEND))) msg->env->from = mutt_default_from (); killfrom = 0; } if (option (OPTHDRS)) process_user_header (msg->env); if (flags & SENDBATCH) mutt_copy_stream (stdin, tempfp); if (option (OPTSIGONTOP) && ! (flags & (SENDMAILX|SENDKEY|SENDBATCH)) && Editor && mutt_strcmp (Editor, "builtin") != 0) append_signature (tempfp); /* include replies/forwarded messages, unless we are given a template */ if (!tempfile && (ctx || !(flags & (SENDREPLY|SENDFORWARD))) && generate_body (tempfp, msg, flags, ctx, cur) == -1) goto cleanup; if (!option (OPTSIGONTOP) && ! (flags & (SENDMAILX|SENDKEY|SENDBATCH)) && Editor && mutt_strcmp (Editor, "builtin") != 0) append_signature (tempfp); } /* * This hook is even called for postponed messages, and can, e.g., be * used for setting the editor, the sendmail path, or the * envelope sender. */ mutt_message_hook (NULL, msg, M_SEND2HOOK); /* wait until now to set the real name portion of our return address so that $realname can be set in a send-hook */ if (msg->env->from && !msg->env->from->personal && !(flags & (SENDRESEND|SENDPOSTPONED))) msg->env->from->personal = safe_strdup (Realname); if (!((WithCrypto & APPLICATION_PGP) && (flags & SENDKEY))) safe_fclose (&tempfp); if (flags & SENDMAILX) { if (mutt_builtin_editor (msg->content->filename, msg, cur) == -1) goto cleanup; } else if (! (flags & SENDBATCH)) { struct stat st; time_t mtime = mutt_decrease_mtime (msg->content->filename, NULL); mutt_update_encoding (msg->content); /* * Select whether or not the user's editor should be called now. We * don't want to do this when: * 1) we are sending a key/cert * 2) we are forwarding a message and the user doesn't want to edit it. * This is controlled by the quadoption $forward_edit. However, if * both $edit_headers and $autoedit are set, we want to ignore the * setting of $forward_edit because the user probably needs to add the * recipients. */ if (! (flags & SENDKEY) && ((flags & SENDFORWARD) == 0 || (option (OPTEDITHDRS) && option (OPTAUTOEDIT)) || query_quadoption (OPT_FORWEDIT, _("Edit forwarded message?")) == M_YES)) { /* If the this isn't a text message, look for a mailcap edit command */ if (mutt_needs_mailcap (msg->content)) { if (!mutt_edit_attachment (msg->content)) goto cleanup; } else if (!Editor || mutt_strcmp ("builtin", Editor) == 0) mutt_builtin_editor (msg->content->filename, msg, cur); else if (option (OPTEDITHDRS)) { mutt_env_to_local (msg->env); mutt_edit_headers (Editor, msg->content->filename, msg, fcc, sizeof (fcc)); mutt_env_to_idna (msg->env, NULL, NULL); } else { mutt_edit_file (Editor, msg->content->filename); if (stat (msg->content->filename, &st) == 0) { if (mtime != st.st_mtime) fix_end_of_file (msg->content->filename); } else mutt_perror (msg->content->filename); } /* If using format=flowed, perform space stuffing. Avoid stuffing when * recalling a postponed message where the stuffing was already * performed. If it has already been performed, the format=flowed * parameter will be present. */ if (option (OPTTEXTFLOWED) && msg->content->type == TYPETEXT && !ascii_strcasecmp("plain", msg->content->subtype)) { char *p = mutt_get_parameter("format", msg->content->parameter); if (ascii_strcasecmp("flowed", NONULL(p))) rfc3676_space_stuff (msg); } mutt_message_hook (NULL, msg, M_SEND2HOOK); } if (! (flags & (SENDPOSTPONED | SENDFORWARD | SENDKEY | SENDRESEND))) { if (stat (msg->content->filename, &st) == 0) { /* if the file was not modified, bail out now */ if (mtime == st.st_mtime && !msg->content->next && query_quadoption (OPT_ABORT, _("Abort unmodified message?")) == M_YES) { mutt_message _("Aborted unmodified message."); goto cleanup; } } else mutt_perror (msg->content->filename); } } /* * Set the message security unless: * 1) crypto support is not enabled (WithCrypto==0) * 2) pgp: header field was present during message editing with $edit_headers (msg->security != 0) * 3) we are resending a message * 4) we are recalling a postponed message (don't override the user's saved settings) * 5) we are in mailx mode * 6) we are in batch mode * * This is done after allowing the user to edit the message so that security * settings can be configured with send2-hook and $edit_headers. */ if (WithCrypto && (msg->security == 0) && !(flags & (SENDBATCH | SENDMAILX | SENDPOSTPONED | SENDRESEND))) { if (option (OPTCRYPTAUTOSIGN)) msg->security |= SIGN; if (option (OPTCRYPTAUTOENCRYPT)) msg->security |= ENCRYPT; if (option (OPTCRYPTREPLYENCRYPT) && cur && (cur->security & ENCRYPT)) msg->security |= ENCRYPT; if (option (OPTCRYPTREPLYSIGN) && cur && (cur->security & SIGN)) msg->security |= SIGN; if (option (OPTCRYPTREPLYSIGNENCRYPTED) && cur && (cur->security & ENCRYPT)) msg->security |= SIGN; if (WithCrypto & APPLICATION_PGP && (msg->security & (ENCRYPT | SIGN))) { if (option (OPTPGPAUTOINLINE)) msg->security |= INLINE; if (option (OPTPGPREPLYINLINE) && cur && (cur->security & INLINE)) msg->security |= INLINE; } if (msg->security) { /* * When replying / forwarding, use the original message's * crypto system. According to the documentation, * smime_is_default should be disregarded here. * * Problem: At least with forwarding, this doesn't really * make much sense. Should we have an option to completely * disable individual mechanisms at run-time? */ if (cur) { if ((WithCrypto & APPLICATION_PGP) && option (OPTCRYPTAUTOPGP) && (cur->security & APPLICATION_PGP)) msg->security |= APPLICATION_PGP; else if ((WithCrypto & APPLICATION_SMIME) && option (OPTCRYPTAUTOSMIME) && (cur->security & APPLICATION_SMIME)) msg->security |= APPLICATION_SMIME; } /* * No crypto mechanism selected? Use availability + smime_is_default * for the decision. */ if (!(msg->security & (APPLICATION_SMIME | APPLICATION_PGP))) { if ((WithCrypto & APPLICATION_SMIME) && option (OPTCRYPTAUTOSMIME) && option (OPTSMIMEISDEFAULT)) msg->security |= APPLICATION_SMIME; else if ((WithCrypto & APPLICATION_PGP) && option (OPTCRYPTAUTOPGP)) msg->security |= APPLICATION_PGP; else if ((WithCrypto & APPLICATION_SMIME) && option (OPTCRYPTAUTOSMIME)) msg->security |= APPLICATION_SMIME; } } /* No permissible mechanisms found. Don't sign or encrypt. */ if (!(msg->security & (APPLICATION_SMIME|APPLICATION_PGP))) msg->security = 0; } /* specify a default fcc. if we are in batchmode, only save a copy of * the message if the value of $copy is yes or ask-yes */ if (!fcc[0] && !(flags & (SENDPOSTPONED)) && (!(flags & SENDBATCH) || (quadoption (OPT_COPY) & 0x1))) { /* set the default FCC */ if (!msg->env->from) { msg->env->from = mutt_default_from (); killfrom = 1; /* no need to check $use_from because if the user specified a from address it would have already been set by now */ } mutt_select_fcc (fcc, sizeof (fcc), msg); if (killfrom) { rfc822_free_address (&msg->env->from); killfrom = 0; } } mutt_update_encoding (msg->content); if (! (flags & (SENDMAILX | SENDBATCH))) { main_loop: fcc_error = 0; /* reset value since we may have failed before */ mutt_pretty_mailbox (fcc, sizeof (fcc)); i = mutt_compose_menu (msg, fcc, sizeof (fcc), cur); if (i == -1) { /* abort */ mutt_message _("Mail not sent."); goto cleanup; } else if (i == 1) { /* postpone the message until later. */ if (msg->content->next) msg->content = mutt_make_multipart (msg->content); /* * make sure the message is written to the right part of a maildir * postponed folder. */ msg->read = 0; msg->old = 0; encode_descriptions (msg->content, 1); mutt_prepare_envelope (msg->env, 0); mutt_env_to_idna (msg->env, NULL, NULL); /* Handle bad IDNAs the next time. */ if (!Postponed || mutt_write_fcc (NONULL (Postponed), msg, (cur && (flags & SENDREPLY)) ? cur->env->message_id : NULL, 1, fcc) < 0) { msg->content = mutt_remove_multipart (msg->content); decode_descriptions (msg->content); mutt_unprepare_envelope (msg->env); goto main_loop; } mutt_update_num_postponed (); mutt_message _("Message postponed."); goto cleanup; } } if (!has_recips (msg->env->to) && !has_recips (msg->env->cc) && !has_recips (msg->env->bcc)) { if (! (flags & SENDBATCH)) { mutt_error _("No recipients are specified!"); goto main_loop; } else { puts _("No recipients were specified."); goto cleanup; } } if (mutt_env_to_idna (msg->env, &tag, &err)) { mutt_error (_("Bad IDN in \"%s\": '%s'"), tag, err); FREE (&err); if (!(flags & SENDBATCH)) goto main_loop; else goto cleanup; } if (!msg->env->subject && ! (flags & SENDBATCH) && (i = query_quadoption (OPT_SUBJECT, _("No subject, abort sending?"))) != M_NO) { /* if the abort is automatic, print an error message */ if (quadoption (OPT_SUBJECT) == M_YES) mutt_error _("No subject specified."); goto main_loop; } if (msg->content->next) msg->content = mutt_make_multipart (msg->content); /* * Ok, we need to do it this way instead of handling all fcc stuff in * one place in order to avoid going to main_loop with encoded "env" * in case of error. Ugh. */ encode_descriptions (msg->content, 1); /* * Make sure that clear_content and free_clear_content are * properly initialized -- we may visit this particular place in * the code multiple times, including after a failed call to * mutt_protect(). */ clear_content = NULL; free_clear_content = 0; if (WithCrypto) { if (msg->security) { /* save the decrypted attachments */ clear_content = msg->content; if ((crypt_get_keys (msg, &pgpkeylist) == -1) || mutt_protect (msg, pgpkeylist) == -1) { msg->content = mutt_remove_multipart (msg->content); FREE (&pgpkeylist); decode_descriptions (msg->content); goto main_loop; } encode_descriptions (msg->content, 0); } /* * at this point, msg->content is one of the following three things: * - multipart/signed. In this case, clear_content is a child. * - multipart/encrypted. In this case, clear_content exists * independently * - application/pgp. In this case, clear_content exists independently. * - something else. In this case, it's the same as clear_content. */ /* This is ugly -- lack of "reporting back" from mutt_protect(). */ if (clear_content && (msg->content != clear_content) && (msg->content->parts != clear_content)) free_clear_content = 1; } if (!option (OPTNOCURSES) && !(flags & SENDMAILX)) mutt_message _("Sending message..."); mutt_prepare_envelope (msg->env, 1); /* save a copy of the message, if necessary. */ mutt_expand_path (fcc, sizeof (fcc)); /* Don't save a copy when we are in batch-mode, and the FCC * folder is on an IMAP server: This would involve possibly lots * of user interaction, which is not available in batch mode. * * Note: A patch to fix the problems with the use of IMAP servers * from non-curses mode is available from Brendan Cully. However, * I'd like to think a bit more about this before including it. */ #ifdef USE_IMAP if ((flags & SENDBATCH) && fcc[0] && mx_is_imap (fcc)) fcc[0] = '\0'; #endif if (*fcc && mutt_strcmp ("/dev/null", fcc) != 0) { BODY *tmpbody = msg->content; BODY *save_sig = NULL; BODY *save_parts = NULL; if (WithCrypto && msg->security && option (OPTFCCCLEAR)) msg->content = clear_content; /* check to see if the user wants copies of all attachments */ if (query_quadoption (OPT_FCCATTACH, _("Save attachments in Fcc?")) != M_YES && msg->content->type == TYPEMULTIPART) { if (WithCrypto && (mutt_strcmp (msg->content->subtype, "encrypted") == 0 || mutt_strcmp (msg->content->subtype, "signed") == 0)) { if (clear_content->type == TYPEMULTIPART) { if(!(msg->security & ENCRYPT) && (msg->security & SIGN)) { /* save initial signature and attachments */ save_sig = msg->content->parts->next; save_parts = clear_content->parts->next; } /* this means writing only the main part */ msg->content = clear_content->parts; if (mutt_protect (msg, pgpkeylist) == -1) { /* we can't do much about it at this point, so * fallback to saving the whole thing to fcc */ msg->content = tmpbody; save_sig = NULL; goto full_fcc; } save_content = msg->content; } } else msg->content = msg->content->parts; } full_fcc: if (msg->content) { /* update received time so that when storing to a mbox-style folder * the From_ line contains the current time instead of when the * message was first postponed. */ msg->received = time (NULL); if (mutt_write_fcc (fcc, msg, NULL, 0, NULL) == -1) { /* * Error writing FCC, we should abort sending. */ fcc_error = 1; } } msg->content = tmpbody; if (WithCrypto && save_sig) { /* cleanup the second signature structures */ if (save_content->parts) { mutt_free_body (&save_content->parts->next); save_content->parts = NULL; } mutt_free_body (&save_content); /* restore old signature and attachments */ msg->content->parts->next = save_sig; msg->content->parts->parts->next = save_parts; } else if (WithCrypto && save_content) { /* destroy the new encrypted body. */ mutt_free_body (&save_content); } } /* * Don't attempt to send the message if the FCC failed. Just pretend * the send failed as well so we give the user a chance to fix the * error. */ if (fcc_error || (i = send_message (msg)) < 0) { if (!(flags & SENDBATCH)) { if (!WithCrypto) ; else if ((msg->security & ENCRYPT) || ((msg->security & SIGN) && msg->content->type == TYPEAPPLICATION)) { mutt_free_body (&msg->content); /* destroy PGP data */ msg->content = clear_content; /* restore clear text. */ } else if ((msg->security & SIGN) && msg->content->type == TYPEMULTIPART) { mutt_free_body (&msg->content->parts->next); /* destroy sig */ msg->content = mutt_remove_multipart (msg->content); } msg->content = mutt_remove_multipart (msg->content); decode_descriptions (msg->content); mutt_unprepare_envelope (msg->env); goto main_loop; } else { puts _("Could not send the message."); goto cleanup; } } else if (!option (OPTNOCURSES) && ! (flags & SENDMAILX)) mutt_message (i == 0 ? _("Mail sent.") : _("Sending in background.")); if (WithCrypto && (msg->security & ENCRYPT)) FREE (&pgpkeylist); if (WithCrypto && free_clear_content) mutt_free_body (&clear_content); /* set 'replied' flag only if the user didn't change/remove In-Reply-To: and References: headers during edit */ if (flags & SENDREPLY) { if (cur && ctx) mutt_set_flag (ctx, cur, M_REPLIED, is_reply (cur, msg)); else if (!(flags & SENDPOSTPONED) && ctx && ctx->tagged) { for (i = 0; i < ctx->vcount; i++) if (ctx->hdrs[ctx->v2r[i]]->tagged) mutt_set_flag (ctx, ctx->hdrs[ctx->v2r[i]], M_REPLIED, is_reply (ctx->hdrs[ctx->v2r[i]], msg)); } } rv = 0; cleanup: if ((WithCrypto & APPLICATION_PGP) && (flags & SENDPOSTPONED)) { if(signas) { FREE (&PgpSignAs); PgpSignAs = signas; } } safe_fclose (&tempfp); mutt_free_header (&msg); return rv; }
int mutt_reopen_mailbox(CONTEXT *ctx, int *index_hint) { int (*cmp_headers) (const HEADER *, const HEADER *) = NULL; HEADER **old_hdrs; int old_msgcount; int msg_mod = 0; int index_hint_set; int i, j; int rc = -1; /* silent operations */ ctx->quiet = 1; if (!ctx->quiet) mutt_message _("Reopening mailbox..."); /* our heuristics require the old mailbox to be unsorted */ if (Sort != SORT_ORDER) { short old_sort; old_sort = Sort; Sort = SORT_ORDER; mutt_sort_headers(ctx, 1); Sort = old_sort; } old_hdrs = NULL; old_msgcount = 0; /* simulate a close */ if (ctx->id_hash) hash_destroy(&ctx->id_hash, NULL); if (ctx->subj_hash) hash_destroy(&ctx->subj_hash, NULL); mutt_clear_threads(ctx); safe_free(&ctx->v2r); if (ctx->readonly) { for (i = 0; i < ctx->msgcount; i++) mutt_free_header(&(ctx->hdrs[i])); /* nothing to do! */ safe_free(&ctx->hdrs); } else { /* save the old headers */ old_msgcount = ctx->msgcount; old_hdrs = ctx->hdrs; ctx->hdrs = NULL; } ctx->hdrmax = 0; /* force allocation of new headers */ ctx->msgcount = 0; ctx->vcount = 0; ctx->tagged = 0; ctx->deleted = 0; ctx->new_messages = 0; ctx->unread = 0; ctx->flagged = 0; ctx->changed = 0; ctx->id_hash = NULL; ctx->subj_hash = NULL; switch (ctx->magic) { case M_MBOX: case M_MMDF: cmp_headers = mbox_strict_cmp_headers; safe_fclose(&ctx->fp); if (!(ctx->fp = safe_fopen(ctx->path, "r"))) rc = -1; else rc = ((ctx->magic == M_MBOX) ? mbox_parse_mailbox : mmdf_parse_mailbox)(ctx); break; default: rc = -1; break; } if (rc == -1) { /* free the old headers */ for (j = 0; j < old_msgcount; j++) mutt_free_header(&(old_hdrs[j])); safe_free(&old_hdrs); ctx->quiet = 0; return -1; } /* now try to recover the old flags */ index_hint_set = (index_hint == NULL); if (!ctx->readonly) { for (i = 0; i < ctx->msgcount; i++) { int found = 0; /* some messages have been deleted, and new messages have been * appended at the end; the heuristic is that old messages have then * "advanced" towards the beginning of the folder, so we begin the * search at index "i" */ for (j = i; j < old_msgcount; j++) { if (old_hdrs[j] == NULL) continue; if (cmp_headers(ctx->hdrs[i], old_hdrs[j])) { found = 1; break; } } if (!found) { for (j = 0; j < i && j < old_msgcount; j++) { if (old_hdrs[j] == NULL) continue; if (cmp_headers(ctx->hdrs[i], old_hdrs[j])) { found = 1; break; } } } if (found) { /* this is best done here */ if (!index_hint_set && (*index_hint == j)) *index_hint = i; if (old_hdrs[j]->changed) { /* Only update the flags if the old header was changed; * otherwise, the header may have been modified externally, * and we don't want to lose _those_ changes */ mutt_set_flag(ctx, ctx->hdrs[i], M_FLAG, old_hdrs[j]->flagged); mutt_set_flag(ctx, ctx->hdrs[i], M_REPLIED, old_hdrs[j]->replied); mutt_set_flag(ctx, ctx->hdrs[i], M_OLD, old_hdrs[j]->old); mutt_set_flag(ctx, ctx->hdrs[i], M_READ, old_hdrs[j]->read); } mutt_set_flag(ctx, ctx->hdrs[i], M_DELETE, old_hdrs[j]->deleted); mutt_set_flag(ctx, ctx->hdrs[i], M_TAG, old_hdrs[j]->tagged); /* we don't need this header any more */ mutt_free_header(&(old_hdrs[j])); } } /* free the remaining old headers */ for (j = 0; j < old_msgcount; j++) { if (old_hdrs[j]) { mutt_free_header(&(old_hdrs[j])); msg_mod = 1; } } safe_free(&old_hdrs); } ctx->quiet = 0; return (ctx->changed || msg_mod) ? M_REOPENED : M_NEW_MAIL; }
void mutt_attach_reply (FILE * fp, struct header *hdr, ATTACHPTR ** idx, short idxlen, struct body * cur, int flags) { short mime_reply_any = 0; short nattach = 0; struct header *parent = NULL; struct header *tmphdr = NULL; short i; STATE st; char tmpbody[_POSIX_PATH_MAX]; FILE *tmpfp; char prefix[SHORT_STRING]; int rc; if (check_all_msg (idx, idxlen, cur, 0) == -1) { nattach = count_tagged (idx, idxlen); if ((parent = find_parent (idx, idxlen, cur, nattach)) == NULL) parent = hdr; } if (nattach > 1 && !check_can_decode (idx, idxlen, cur)) { if ((rc = query_quadoption (OPT_MIMEFWDREST, ("Can't decode all tagged attachments. MIME-encapsulate the others?"))) == -1) return; else if (rc == M_YES) mime_reply_any = 1; } else if (nattach == 1) mime_reply_any = 1; tmphdr = mutt_new_header (); tmphdr->env = mutt_new_envelope (); if (attach_reply_envelope_defaults (tmphdr->env, idx, idxlen, parent ? parent : (cur ? cur->hdr : NULL), flags) == -1) { mutt_free_header (&tmphdr); return; } mutt_mktemp (tmpbody, sizeof (tmpbody)); if ((tmpfp = safe_fopen (tmpbody, "w")) == NULL) { mutt_error (("Can't create %s."), tmpbody); mutt_free_header (&tmphdr); return; } if (!parent) { if (cur) attach_include_reply (fp, tmpfp, cur->hdr, flags); else { for (i = 0; i < idxlen; i++) { if (idx[i]->content->tagged) attach_include_reply (fp, tmpfp, idx[i]->content->hdr, flags); } } } else { mutt_make_attribution (Context, parent, tmpfp); memset (&st, 0, sizeof (STATE)); st.fpin = fp; st.fpout = tmpfp; if (!bit_val(options, OPTTEXTFLOWED)) _mutt_make_string (prefix, sizeof (prefix), NONULL (Prefix), Context, parent, 0); else strfcpy (prefix, ">", sizeof (prefix)); st.prefix = prefix; st.flags = M_CHARCONV; if (bit_val(options, OPTWEED)) st.flags |= M_WEED; if (bit_val(options, OPTHEADER)) include_header (1, fp, parent, tmpfp, prefix); if (cur) { if (mutt_can_decode (cur)) { mutt_body_handler (cur, &st); state_putc ('\n', &st); } else mutt_copy_body (fp, &tmphdr->content, cur); } else { for (i = 0; i < idxlen; i++) { if (idx[i]->content->tagged && mutt_can_decode (idx[i]->content)) { mutt_body_handler (idx[i]->content, &st); state_putc ('\n', &st); } } } mutt_make_post_indent (Context, parent, tmpfp); if (mime_reply_any && !cur && copy_problematic_attachments (fp, &tmphdr->content, idx, idxlen, 0) == NULL) { mutt_free_header (&tmphdr); safe_fclose (&tmpfp); return; } } safe_fclose (&tmpfp); if (ci_send_message (flags, tmphdr, tmpbody, NULL, parent ? parent : (cur ? cur->hdr : NULL)) == 0) mutt_set_flag (Context, hdr, M_REPLIED, 1); }
static void attach_forward_msgs (FILE * fp, struct header *hdr, ATTACHPTR ** idx, short idxlen, struct body * cur) { struct header *curhdr = NULL; struct header *tmphdr; short i; int rc; struct body **last; char tmpbody[_POSIX_PATH_MAX]; FILE *tmpfp = NULL; int cmflags = 0; int chflags = CH_XMIT; if (cur) curhdr = cur->hdr; else { for (i = 0; i < idxlen; i++) if (idx[i]->content->tagged) { curhdr = idx[i]->content->hdr; break; } } tmphdr = mutt_new_header (); tmphdr->env = mutt_new_envelope (); mutt_make_forward_subject (tmphdr->env, Context, curhdr); tmpbody[0] = '\0'; if ((rc = query_quadoption (OPT_MIMEFWD, ("Forward MIME encapsulated?"))) == M_NO) { /* no MIME encapsulation */ mutt_mktemp (tmpbody, sizeof (tmpbody)); if (!(tmpfp = safe_fopen (tmpbody, "w"))) { mutt_error (("Can't create %s."), tmpbody); mutt_free_header (&tmphdr); return; } if (bit_val(options, OPTFORWQUOTE)) { chflags |= CH_PREFIX; cmflags |= M_CM_PREFIX; } if (bit_val(options, OPTFORWDECODE)) { cmflags |= M_CM_DECODE | M_CM_CHARCONV; if (bit_val(options, OPTWEED)) { chflags |= CH_WEED | CH_REORDER; cmflags |= M_CM_WEED; } } if (cur) { /* mutt_message_hook (cur->hdr, M_MESSAGEHOOK); */ mutt_forward_intro (tmpfp, cur->hdr); _mutt_copy_message (tmpfp, fp, cur->hdr, cur->hdr->content, cmflags, chflags); mutt_forward_trailer (tmpfp); } else { for (i = 0; i < idxlen; i++) { if (idx[i]->content->tagged) { /* mutt_message_hook (idx[i]->content->hdr, M_MESSAGEHOOK); */ mutt_forward_intro (tmpfp, idx[i]->content->hdr); _mutt_copy_message (tmpfp, fp, idx[i]->content->hdr, idx[i]->content->hdr->content, cmflags, chflags); mutt_forward_trailer (tmpfp); } } } safe_fclose (&tmpfp); } else if (rc == M_YES) /* do MIME encapsulation - we don't need to do much here */ { last = &tmphdr->content; if (cur) mutt_copy_body (fp, last, cur); else { for (i = 0; i < idxlen; i++) if (idx[i]->content->tagged) { mutt_copy_body (fp, last, idx[i]->content); last = &((*last)->next); } } } else mutt_free_header (&tmphdr); ci_send_message (0, tmphdr, *tmpbody ? tmpbody : NULL, NULL, curhdr); }
static void attach_forward_bodies (FILE * fp, struct header * hdr, ATTACHPTR ** idx, short idxlen, struct body * cur, short nattach) { short i; short mime_fwd_all = 0; short mime_fwd_any = 1; struct header *parent = NULL; struct header *tmphdr = NULL; struct body **last; char tmpbody[_POSIX_PATH_MAX]; FILE *tmpfp = NULL; char prefix[STRING]; int rc = 0; STATE st; /* * First, find the parent message. * Note: This could be made an option by just * putting the following lines into an if block. */ parent = find_parent (idx, idxlen, cur, nattach); if (parent == NULL) parent = hdr; tmphdr = mutt_new_header (); tmphdr->env = mutt_new_envelope (); mutt_make_forward_subject (tmphdr->env, Context, parent); mutt_mktemp (tmpbody, sizeof (tmpbody)); if ((tmpfp = safe_fopen (tmpbody, "w")) == NULL) { mutt_error (("Can't open temporary file %s."), tmpbody); return; } mutt_forward_intro (tmpfp, parent); /* prepare the prefix here since we'll need it later. */ if (bit_val(options, OPTFORWQUOTE)) { if (!bit_val(options, OPTTEXTFLOWED)) _mutt_make_string (prefix, sizeof (prefix), NONULL (Prefix), Context, parent, 0); else strfcpy (prefix, ">", sizeof (prefix)); } include_header (bit_val(options, OPTFORWQUOTE), fp, parent, tmpfp, prefix); /* * Now, we have prepared the first part of the message body: The * original message's header. * * The next part is more interesting: either include the message bodies, * or attach them. */ if ((!cur || mutt_can_decode (cur)) && (rc = query_quadoption (OPT_MIMEFWD, ("Forward as attachments?"))) == M_YES) mime_fwd_all = 1; else if (rc == -1) goto bail; /* * shortcut MIMEFWDREST when there is only one attachment. Is * this intuitive? */ if (!mime_fwd_all && !cur && (nattach > 1) && !check_can_decode (idx, idxlen, cur)) { if ((rc = query_quadoption (OPT_MIMEFWDREST, ("Can't decode all tagged attachments. MIME-forward the others?"))) == -1) goto bail; else if (rc == M_NO) mime_fwd_any = 0; } /* initialize a state structure */ memset (&st, 0, sizeof (st)); if (bit_val(options, OPTFORWQUOTE)) st.prefix = prefix; st.flags = M_CHARCONV; if (bit_val(options, OPTWEED)) st.flags |= M_WEED; st.fpin = fp; st.fpout = tmpfp; /* where do we append new MIME parts? */ last = &tmphdr->content; if (cur) { /* single body case */ if (!mime_fwd_all && mutt_can_decode (cur)) { mutt_body_handler (cur, &st); state_putc ('\n', &st); } else { if (mutt_copy_body (fp, last, cur) == -1) goto bail; last = &((*last)->next); } } else { /* multiple body case */ if (!mime_fwd_all) { for (i = 0; i < idxlen; i++) { if (idx[i]->content->tagged && mutt_can_decode (idx[i]->content)) { mutt_body_handler (idx[i]->content, &st); state_putc ('\n', &st); } } } if (mime_fwd_any && copy_problematic_attachments (fp, last, idx, idxlen, mime_fwd_all) == NULL) goto bail; } mutt_forward_trailer (tmpfp); safe_fclose (&tmpfp); tmpfp = NULL; /* now that we have the template, send it. */ ci_send_message (0, tmphdr, tmpbody, NULL, parent); return; bail: if (tmpfp) { safe_fclose (&tmpfp); mutt_unlink (tmpbody); } mutt_free_header (&tmphdr); }
/* * Read headers * returns: * 0 on success * -1 - connection lost, * -2 - invalid command or execution error, * -3 - error writing to tempfile */ static int pop_fetch_headers(CONTEXT *ctx) { int i, ret, old_count, new_count, deleted; unsigned short hcached = 0, bcached; POP_DATA *pop_data = (POP_DATA *)ctx->data; progress_t progress; time(&pop_data->check_time); pop_data->clear_cache = 0; for (i = 0; i < ctx->msgcount; i++) ctx->hdrs[i]->refno = -1; old_count = ctx->msgcount; ret = pop_fetch_data(pop_data, "UIDL\r\n", NULL, fetch_uidl, ctx); new_count = ctx->msgcount; ctx->msgcount = old_count; if (pop_data->cmd_uidl == 2) { if (ret == 0) { pop_data->cmd_uidl = 1; dprint(1, "pop_fetch_headers: set UIDL capability\n"); } if ((ret == -2) && (pop_data->cmd_uidl == 2)) { pop_data->cmd_uidl = 0; dprint(1, "pop_fetch_headers: unset UIDL capability\n"); snprintf(pop_data->err_msg, sizeof(pop_data->err_msg), _("Command UIDL is not supported by server.")); } } if (!ctx->quiet) mutt_progress_init(&progress, _("Fetching message headers..."), M_PROGRESS_MSG, ReadInc, new_count - old_count); if (ret == 0) { for (i = 0, deleted = 0; i < old_count; i++) { if (ctx->hdrs[i]->refno == -1) { ctx->hdrs[i]->deleted = 1; deleted++; } } if (deleted > 0) { mutt_error(_( "%d messages have been lost. Try reopening the mailbox."), deleted); mutt_sleep(2); } for (i = old_count; i < new_count; i++) { if (!ctx->quiet) mutt_progress_update(&progress, i + 1 - old_count, -1); if ((ret = pop_read_header(pop_data, ctx->hdrs[i])) < 0) break; /* * faked support for flags works like this: * - if 'hcached' is 1, we have the message in our hcache: * - if we also have a body: read * - if we don't have a body: old * (if $mark_old is set which is maybe wrong as * $mark_old should be considered for syncing the * folder and not when opening it XXX) * - if 'hcached' is 0, we don't have the message in our hcache: * - if we also have a body: read * - if we don't have a body: new */ bcached = mutt_bcache_exists(pop_data->bcache, ctx->hdrs[i]->data) == 0; ctx->hdrs[i]->old = 0; ctx->hdrs[i]->read = 0; if (hcached) { if (bcached) ctx->hdrs[i]->read = 1; else if (option(OPTMARKOLD)) ctx->hdrs[i]->old = 1; } else { if (bcached) ctx->hdrs[i]->read = 1; } ctx->msgcount++; } if (i > old_count) mx_update_context(ctx, i - old_count); } if (ret < 0) { for (i = ctx->msgcount; i < new_count; i++) mutt_free_header(&ctx->hdrs[i]); return ret; } /* after putting the result into our structures, * clean up cache, i.e. wipe messages deleted outside * the availability of our cache */ if (option(OPTMESSAGECACHECLEAN)) mutt_bcache_list(pop_data->bcache, msg_cache_check, (void *)ctx); mutt_clear_error(); return new_count - old_count; }
/* * Read headers * returns: * 0 on success * -1 - conection lost, * -2 - invalid command or execution error, * -3 - error writing to tempfile */ static int pop_fetch_headers (CONTEXT *ctx) { int i, ret, old_count, new_count, deleted; unsigned short hcached = 0, bcached; POP_DATA *pop_data = (POP_DATA *)ctx->data; progress_t progress; #ifdef USE_HCACHE header_cache_t *hc = NULL; void *data; hc = pop_hcache_open (pop_data, ctx->path); #endif time (&pop_data->check_time); pop_data->clear_cache = 0; for (i = 0; i < ctx->msgcount; i++) ctx->hdrs[i]->refno = -1; old_count = ctx->msgcount; ret = pop_fetch_data (pop_data, "UIDL\r\n", NULL, fetch_uidl, ctx); new_count = ctx->msgcount; ctx->msgcount = old_count; if (pop_data->cmd_uidl == 2) { if (ret == 0) { pop_data->cmd_uidl = 1; dprint (1, (debugfile, "pop_fetch_headers: set UIDL capability\n")); } if (ret == -2 && pop_data->cmd_uidl == 2) { pop_data->cmd_uidl = 0; dprint (1, (debugfile, "pop_fetch_headers: unset UIDL capability\n")); snprintf (pop_data->err_msg, sizeof (pop_data->err_msg), _("Command UIDL is not supported by server.")); } } if (!ctx->quiet) mutt_progress_init (&progress, _("Fetching message headers..."), M_PROGRESS_MSG, ReadInc, new_count - old_count); if (ret == 0) { for (i = 0, deleted = 0; i < old_count; i++) { if (ctx->hdrs[i]->refno == -1) { ctx->hdrs[i]->deleted = 1; deleted++; } } if (deleted > 0) { mutt_error (_("%d messages have been lost. Try reopening the mailbox."), deleted); mutt_sleep (2); } for (i = old_count; i < new_count; i++) { if (!ctx->quiet) mutt_progress_update (&progress, i + 1 - old_count, -1); #if USE_HCACHE if ((data = mutt_hcache_fetch (hc, ctx->hdrs[i]->data, strlen))) { char *uidl = safe_strdup (ctx->hdrs[i]->data); int refno = ctx->hdrs[i]->refno; int index = ctx->hdrs[i]->index; /* * - POP dynamically numbers headers and relies on h->refno * to map messages; so restore header and overwrite restored * refno with current refno, same for index * - h->data needs to a separate pointer as it's driver-specific * data freed separately elsewhere * (the old h->data should point inside a malloc'd block from * hcache so there shouldn't be a memleak here) */ HEADER *h = mutt_hcache_restore ((unsigned char *) data, NULL); mutt_free_header (&ctx->hdrs[i]); ctx->hdrs[i] = h; ctx->hdrs[i]->refno = refno; ctx->hdrs[i]->index = index; ctx->hdrs[i]->data = uidl; ret = 0; hcached = 1; } else #endif if ((ret = pop_read_header (pop_data, ctx->hdrs[i])) < 0) break; #if USE_HCACHE else { mutt_hcache_store (hc, ctx->hdrs[i]->data, ctx->hdrs[i], 0, strlen, M_GENERATE_UIDVALIDITY); } FREE(&data); #endif /* * faked support for flags works like this: * - if 'hcached' is 1, we have the message in our hcache: * - if we also have a body: read * - if we don't have a body: old * (if $mark_old is set which is maybe wrong as * $mark_old should be considered for syncing the * folder and not when opening it XXX) * - if 'hcached' is 0, we don't have the message in our hcache: * - if we also have a body: read * - if we don't have a body: new */ bcached = mutt_bcache_exists (pop_data->bcache, ctx->hdrs[i]->data) == 0; ctx->hdrs[i]->old = 0; ctx->hdrs[i]->read = 0; if (hcached) { if (bcached) ctx->hdrs[i]->read = 1; else if (option (OPTMARKOLD)) ctx->hdrs[i]->old = 1; } else { if (bcached) ctx->hdrs[i]->read = 1; } ctx->msgcount++; } if (i > old_count) mx_update_context (ctx, i - old_count); } #if USE_HCACHE mutt_hcache_close (hc); #endif if (ret < 0) { for (i = ctx->msgcount; i < new_count; i++) mutt_free_header (&ctx->hdrs[i]); return ret; } /* after putting the result into our structures, * clean up cache, i.e. wipe messages deleted outside * the availability of our cache */ if (option (OPTMESSAGECACHECLEAN)) mutt_bcache_list (pop_data->bcache, msg_cache_check, (void*)ctx); mutt_clear_error (); return (new_count - old_count); }