/** * icmd_version - Parse 'version' command - Implements ::icommand_t */ static enum CommandResult icmd_version(struct Buffer *buf, struct Buffer *s, unsigned long data, struct Buffer *err) { char tempfile[PATH_MAX]; mutt_mktemp(tempfile, sizeof(tempfile)); FILE *fp_out = mutt_file_fopen(tempfile, "w"); if (!fp_out) { mutt_buffer_addstr(err, _("Could not create temporary file")); return MUTT_CMD_ERROR; } print_version(fp_out); mutt_file_fclose(&fp_out); struct Pager info = { 0 }; if (mutt_pager("version", tempfile, 0, &info) == -1) { mutt_buffer_addstr(err, _("Could not create temporary file")); return MUTT_CMD_ERROR; } return MUTT_CMD_SUCCESS; }
static void set_path (CONTEXT * ctx) { char tmppath[_POSIX_PATH_MAX]; /* Setup the right paths */ ctx->realpath = ctx->path; /* Uncompress to /tmp */ mutt_mktemp (tmppath); ctx->path = mem_malloc (str_len (tmppath) + 1); strcpy (ctx->path, tmppath); }
/* * This routine does RfC3676 space stuffing since it's a MUST. * Space stuffing means that we have to add leading spaces to * certain lines: * - lines starting with a space * - lines starting with 'From ' * This routine is only called once right after editing the * initial message so it's up to the user to take care of stuffing * when editing the message several times before actually sending it * * This is more or less a hack as it replaces the message's content with * a freshly created copy in a tempfile and modifies the file's mtime * so we don't trigger code paths watching for mtime changes */ void rfc3676_space_stuff (HEADER* hdr) { #if DEBUG int lc = 0; size_t len = 0; unsigned char c = '\0'; #endif FILE *in = NULL, *out = NULL; char buf[LONG_STRING]; char tmpfile[_POSIX_PATH_MAX]; if (!hdr || !hdr->content || !hdr->content->filename) return; dprint (2, (debugfile, "f=f: postprocess %s\n", hdr->content->filename)); if ((in = safe_fopen (hdr->content->filename, "r")) == NULL) return; mutt_mktemp (tmpfile, sizeof (tmpfile)); if ((out = safe_fopen (tmpfile, "w+")) == NULL) { safe_fclose (&in); return; } while (fgets (buf, sizeof (buf), in)) { if (ascii_strncmp ("From ", buf, 5) == 0 || buf[0] == ' ') { fputc (' ', out); #if DEBUG lc++; len = mutt_strlen (buf); if (len > 0) { c = buf[len-1]; buf[len-1] = '\0'; } dprint (4, (debugfile, "f=f: line %d needs space-stuffing: '%s'\n", lc, buf)); if (len > 0) buf[len-1] = c; #endif } fputs (buf, out); } safe_fclose (&in); safe_fclose (&out); mutt_set_mtime (hdr->content->filename, tmpfile); unlink (hdr->content->filename); mutt_str_replace (&hdr->content->filename, tmpfile); }
void mutt_help (int menu) { char t[_POSIX_PATH_MAX]; char buf[SHORT_STRING]; const char *desc; FILE *f; const struct binding_t *funcs; mutt_mktemp (t, sizeof (t)); funcs = km_get_table (menu); desc = mutt_getnamebyvalue (menu, Menus); if (!desc) desc = _("<UNKNOWN>"); do { if ((f = safe_fopen (t, "w")) == NULL) { mutt_perror (t); return; } dump_menu (f, menu); if (menu != MENU_EDITOR && menu != MENU_PAGER) { fputs (_("\nGeneric bindings:\n\n"), f); dump_menu (f, MENU_GENERIC); } fputs (_("\nUnbound functions:\n\n"), f); if (funcs) dump_unbound (f, funcs, Keymaps[menu], NULL); if (menu != MENU_PAGER) dump_unbound (f, OpGeneric, Keymaps[MENU_GENERIC], Keymaps[menu]); safe_fclose (&f); snprintf (buf, sizeof (buf), _("Help for %s"), desc); } while (mutt_do_pager (buf, t, M_PAGER_RETWINCH | M_PAGER_MARKER | M_PAGER_NSKIP | M_PAGER_NOWRAP, NULL) == OP_REFORMAT_WINCH); }
/** * setup_paths - Set the mailbox paths * @param m Mailbox to modify * @retval 0 Success * @retval -1 Error * * Save the compressed filename in mailbox->realpath. * Create a temporary filename and put its name in mailbox->path. * The temporary file is created to prevent symlink attacks. */ static int setup_paths(struct Mailbox *m) { if (!m) return -1; char tmp[PATH_MAX]; /* Setup the right paths */ mutt_str_strfcpy(m->realpath, m->path, sizeof(m->realpath)); /* We will uncompress to /tmp */ mutt_mktemp(tmp, sizeof(tmp)); mutt_str_strfcpy(m->path, tmp, sizeof(m->path)); FILE *fp = mutt_file_fopen(m->path, "w"); if (!fp) return -1; mutt_file_fclose(&fp); return 0; }
/** * icmd_set - Parse 'set' command to display config - Implements ::icommand_t */ static enum CommandResult icmd_set(struct Buffer *buf, struct Buffer *s, unsigned long data, struct Buffer *err) { char tempfile[PATH_MAX]; mutt_mktemp(tempfile, sizeof(tempfile)); FILE *fp_out = mutt_file_fopen(tempfile, "w"); if (!fp_out) { mutt_buffer_addstr(err, _("Could not create temporary file")); return MUTT_CMD_ERROR; } if (mutt_str_strcmp(s->data, "set all") == 0) { dump_config(Config, CS_DUMP_STYLE_NEO, 0, fp_out); } else if (mutt_str_strcmp(s->data, "set") == 0) { dump_config(Config, CS_DUMP_STYLE_NEO, CS_DUMP_ONLY_CHANGED, fp_out); } else { mutt_file_fclose(&fp_out); return MUTT_CMD_ERROR; } mutt_file_fclose(&fp_out); struct Pager info = { 0 }; if (mutt_pager("set", tempfile, 0, &info) == -1) { mutt_buffer_addstr(err, _("Could not create temporary file")); return MUTT_CMD_ERROR; } return MUTT_CMD_SUCCESS; }
/* returns -1 on error, 0 or the return code from mutt_do_pager() on success */ int mutt_view_attachment (FILE *fp, BODY *a, int flag, HEADER *hdr, ATTACHPTR **idx, short idxlen) { char tempfile[_POSIX_PATH_MAX] = ""; char pagerfile[_POSIX_PATH_MAX] = ""; int is_message; int use_mailcap; int use_pipe = 0; int use_pager = 1; char type[STRING]; char command[HUGE_STRING]; char descrip[STRING]; char *fname; rfc1524_entry *entry = NULL; int rc = -1; int unlink_tempfile = 0; is_message = mutt_is_message_type(a->type, a->subtype); if (WithCrypto && is_message && a->hdr && (a->hdr->security & ENCRYPT) && !crypt_valid_passphrase(a->hdr->security)) return (rc); use_mailcap = (flag == M_MAILCAP || (flag == M_REGULAR && mutt_needs_mailcap (a))); snprintf (type, sizeof (type), "%s/%s", TYPE (a), a->subtype); if (use_mailcap) { entry = rfc1524_new_entry (); if (!rfc1524_mailcap_lookup (a, type, entry, 0)) { if (flag == M_REGULAR) { /* fallback to view as text */ rfc1524_free_entry (&entry); mutt_error _("No matching mailcap entry found. Viewing as text."); flag = M_AS_TEXT; use_mailcap = 0; } else goto return_error; } } if (use_mailcap) { if (!entry->command) { mutt_error _("MIME type not defined. Cannot view attachment."); goto return_error; } strfcpy (command, entry->command, sizeof (command)); if (fp) { fname = safe_strdup (a->filename); mutt_sanitize_filename (fname, 1); } else fname = a->filename; if (rfc1524_expand_filename (entry->nametemplate, fname, tempfile, sizeof (tempfile))) { if (fp == NULL && mutt_strcmp(tempfile, a->filename)) { /* send case: the file is already there */ if (safe_symlink (a->filename, tempfile) == -1) { if (mutt_yesorno (_("Can't match nametemplate, continue?"), M_YES) == M_YES) strfcpy (tempfile, a->filename, sizeof (tempfile)); else goto return_error; } else unlink_tempfile = 1; } } else if (fp == NULL) /* send case */ strfcpy (tempfile, a->filename, sizeof (tempfile)); if (fp) { /* recv case: we need to save the attachment to a file */ FREE (&fname); if (mutt_save_attachment (fp, a, tempfile, 0, NULL) == -1) goto return_error; } use_pipe = rfc1524_expand_command (a, tempfile, type, command, sizeof (command)); use_pager = entry->copiousoutput; } if (use_pager) { if (fp && !use_mailcap && a->filename) { /* recv case */ strfcpy (pagerfile, a->filename, sizeof (pagerfile)); mutt_adv_mktemp (pagerfile, sizeof(pagerfile)); } else mutt_mktemp (pagerfile, sizeof (pagerfile)); } if (use_mailcap) { pid_t thepid = 0; int tempfd = -1, pagerfd = -1; if (!use_pager) mutt_endwin (NULL); if (use_pager || use_pipe) { if (use_pager && ((pagerfd = safe_open (pagerfile, O_CREAT | O_EXCL | O_WRONLY)) == -1)) { mutt_perror ("open"); goto return_error; } if (use_pipe && ((tempfd = open (tempfile, 0)) == -1)) { if(pagerfd != -1) close(pagerfd); mutt_perror ("open"); goto return_error; } if ((thepid = mutt_create_filter_fd (command, NULL, NULL, NULL, use_pipe ? tempfd : -1, use_pager ? pagerfd : -1, -1)) == -1) { if(pagerfd != -1) close(pagerfd); if(tempfd != -1) close(tempfd); mutt_error _("Cannot create filter"); goto return_error; } if (use_pager) { if (a->description) snprintf (descrip, sizeof (descrip), _("---Command: %-20.20s Description: %s"), command, a->description); else snprintf (descrip, sizeof (descrip), _("---Command: %-30.30s Attachment: %s"), command, type); } if ((mutt_wait_filter (thepid) || (entry->needsterminal && option (OPTWAITKEY))) && !use_pager) mutt_any_key_to_continue (NULL); if (tempfd != -1) close (tempfd); if (pagerfd != -1) close (pagerfd); } else { /* interactive command */ if (mutt_system (command) || (entry->needsterminal && option (OPTWAITKEY))) mutt_any_key_to_continue (NULL); } } else { /* Don't use mailcap; the attachment is viewed in the pager */ if (flag == M_AS_TEXT) { /* just let me see the raw data */ if (mutt_save_attachment (fp, a, pagerfile, 0, NULL)) goto return_error; } else { /* Use built-in handler */ set_option (OPTVIEWATTACH); /* disable the "use 'v' to view this part" * message in case of error */ if (mutt_decode_save_attachment (fp, a, pagerfile, M_DISPLAY, 0)) { unset_option (OPTVIEWATTACH); goto return_error; } unset_option (OPTVIEWATTACH); } if (a->description) strfcpy (descrip, a->description, sizeof (descrip)); else if (a->filename) snprintf (descrip, sizeof (descrip), _("---Attachment: %s: %s"), a->filename, type); else snprintf (descrip, sizeof (descrip), _("---Attachment: %s"), type); } /* We only reach this point if there have been no errors */ if (use_pager) { pager_t info; memset (&info, 0, sizeof (info)); info.fp = fp; info.bdy = a; info.ctx = Context; info.idx = idx; info.idxlen = idxlen; info.hdr = hdr; rc = mutt_do_pager (descrip, pagerfile, M_PAGER_ATTACHMENT | (is_message ? M_PAGER_MESSAGE : 0), &info); *pagerfile = '\0'; } else rc = 0; return_error: if (entry) rfc1524_free_entry (&entry); if (fp && tempfile[0]) mutt_unlink (tempfile); else if (unlink_tempfile) unlink(tempfile); if (pagerfile[0]) mutt_unlink (pagerfile); return rc; }
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 pgp_key_t pgp_select_key (pgp_key_t keys, ADDRESS * p, const char *s) { int keymax; pgp_uid_t **KeyTable; MUTTMENU *menu; int i, done = 0; char helpstr[LONG_STRING], buf[LONG_STRING], tmpbuf[STRING]; char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX]; FILE *fp, *devnull; pid_t thepid; pgp_key_t kp; pgp_uid_t *a; int (*f) (const void *, const void *); int unusable = 0; keymax = 0; KeyTable = NULL; for (i = 0, kp = keys; kp; kp = kp->next) { if (!option (OPTPGPSHOWUNUSABLE) && (kp->flags & KEYFLAG_CANTUSE)) { unusable = 1; continue; } for (a = kp->address; a; a = a->next) { if (!option (OPTPGPSHOWUNUSABLE) && (a->flags & KEYFLAG_CANTUSE)) { unusable = 1; continue; } if (i == keymax) { keymax += 5; safe_realloc (&KeyTable, sizeof (pgp_uid_t *) * keymax); } KeyTable[i++] = a; } } if (!i && unusable) { mutt_error _("All matching keys are expired, revoked, or disabled."); mutt_sleep (1); return NULL; } switch (PgpSortKeys & SORT_MASK) { case SORT_DATE: f = pgp_compare_date; break; case SORT_KEYID: f = pgp_compare_keyid; break; case SORT_ADDRESS: f = pgp_compare_address; break; case SORT_TRUST: default: f = pgp_compare_trust; break; } qsort (KeyTable, i, sizeof (pgp_uid_t *), f); helpstr[0] = 0; mutt_make_help (buf, sizeof (buf), _("Exit "), MENU_PGP, OP_EXIT); strcat (helpstr, buf); /* __STRCAT_CHECKED__ */ mutt_make_help (buf, sizeof (buf), _("Select "), MENU_PGP, OP_GENERIC_SELECT_ENTRY); strcat (helpstr, buf); /* __STRCAT_CHECKED__ */ mutt_make_help (buf, sizeof (buf), _("Check key "), MENU_PGP, OP_VERIFY_KEY); strcat (helpstr, buf); /* __STRCAT_CHECKED__ */ mutt_make_help (buf, sizeof (buf), _("Help"), MENU_PGP, OP_HELP); strcat (helpstr, buf); /* __STRCAT_CHECKED__ */ menu = mutt_new_menu (MENU_PGP); menu->max = i; menu->make_entry = pgp_entry; menu->help = helpstr; menu->data = KeyTable; if (p) snprintf (buf, sizeof (buf), _("PGP keys matching <%s>."), p->mailbox); else snprintf (buf, sizeof (buf), _("PGP keys matching \"%s\"."), s); menu->title = buf; kp = NULL; mutt_clear_error (); while (!done) { switch (mutt_menuLoop (menu)) { case OP_VERIFY_KEY: mutt_mktemp (tempfile, sizeof (tempfile)); if ((devnull = fopen ("/dev/null", "w")) == NULL) /* __FOPEN_CHECKED__ */ { mutt_perror _("Can't open /dev/null"); break; } if ((fp = safe_fopen (tempfile, "w")) == NULL) { safe_fclose (&devnull); mutt_perror _("Can't create temporary file"); break; } mutt_message _("Invoking PGP..."); snprintf (tmpbuf, sizeof (tmpbuf), "0x%s", pgp_fpr_or_lkeyid (pgp_principal_key (KeyTable[menu->current]->parent))); if ((thepid = pgp_invoke_verify_key (NULL, NULL, NULL, -1, fileno (fp), fileno (devnull), tmpbuf)) == -1) { mutt_perror _("Can't create filter"); unlink (tempfile); safe_fclose (&fp); safe_fclose (&devnull); } mutt_wait_filter (thepid); safe_fclose (&fp); safe_fclose (&devnull); mutt_clear_error (); snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"), pgp_keyid (pgp_principal_key (KeyTable[menu->current]->parent))); mutt_do_pager (cmd, tempfile, 0, NULL); menu->redraw = REDRAW_FULL; break; case OP_VIEW_ID: mutt_message ("%s", NONULL (KeyTable[menu->current]->addr)); break; case OP_GENERIC_SELECT_ENTRY: /* XXX make error reporting more verbose */ if (option (OPTPGPCHECKTRUST)) if (!pgp_key_is_valid (KeyTable[menu->current]->parent)) { mutt_error _("This key can't be used: expired/disabled/revoked."); break; } if (option (OPTPGPCHECKTRUST) && (!pgp_id_is_valid (KeyTable[menu->current]) || !pgp_id_is_strong (KeyTable[menu->current]))) { char *s = ""; char buff[LONG_STRING]; if (KeyTable[menu->current]->flags & KEYFLAG_CANTUSE) s = N_("ID is expired/disabled/revoked."); else switch (KeyTable[menu->current]->trust & 0x03) { case 0: s = N_("ID has undefined validity."); break; case 1: s = N_("ID is not valid."); break; case 2: s = N_("ID is only marginally valid."); break; } snprintf (buff, sizeof (buff), _("%s Do you really want to use the key?"), _(s)); if (mutt_yesorno (buff, M_NO) != M_YES) { mutt_clear_error (); break; } } # if 0 kp = pgp_principal_key (KeyTable[menu->current]->parent); # else kp = KeyTable[menu->current]->parent; # endif done = 1; break; case OP_EXIT: kp = NULL; done = 1; break; } } mutt_menuDestroy (&menu); FREE (&KeyTable); set_option (OPTNEEDREDRAW); return (kp); }
/* imap_read_headers: * Changed to read many headers instead of just one. It will return the * msgno of the last message read. It will return a value other than * msgend if mail comes in while downloading headers (in theory). */ int imap_read_headers (IMAP_DATA* idata, int msgbegin, int msgend) { CONTEXT* ctx; char *hdrreq = NULL; FILE *fp; char tempfile[_POSIX_PATH_MAX]; int msgno, idx = msgbegin - 1; IMAP_HEADER h; IMAP_STATUS* status; int rc, mfhrc, oldmsgcount; int fetchlast = 0; int maxuid = 0; static const char * const want_headers = "DATE FROM SUBJECT TO CC MESSAGE-ID REFERENCES CONTENT-TYPE CONTENT-DESCRIPTION IN-REPLY-TO REPLY-TO LINES LIST-POST X-LABEL"; progress_t progress; int retval = -1; #if USE_HCACHE char buf[LONG_STRING]; unsigned int *uid_validity = NULL; unsigned int *puidnext = NULL; unsigned int uidnext = 0; int evalhc = 0; #endif /* USE_HCACHE */ ctx = idata->ctx; if (mutt_bit_isset (idata->capabilities,IMAP4REV1)) { safe_asprintf (&hdrreq, "BODY.PEEK[HEADER.FIELDS (%s%s%s)]", want_headers, ImapHeaders ? " " : "", NONULL (ImapHeaders)); } else if (mutt_bit_isset (idata->capabilities,IMAP4)) { safe_asprintf (&hdrreq, "RFC822.HEADER.LINES (%s%s%s)", want_headers, ImapHeaders ? " " : "", NONULL (ImapHeaders)); } else { /* Unable to fetch headers for lower versions */ mutt_error _("Unable to fetch headers from this IMAP server version."); mutt_sleep (2); /* pause a moment to let the user see the error */ goto error_out_0; } /* instead of downloading all headers and then parsing them, we parse them * as they come in. */ mutt_mktemp (tempfile, sizeof (tempfile)); if (!(fp = safe_fopen (tempfile, "w+"))) { mutt_error (_("Could not create temporary file %s"), tempfile); mutt_sleep (2); goto error_out_0; } unlink (tempfile); /* make sure context has room to hold the mailbox */ while ((msgend) >= idata->ctx->hdrmax) mx_alloc_memory (idata->ctx); oldmsgcount = ctx->msgcount; idata->reopen &= ~(IMAP_REOPEN_ALLOW|IMAP_NEWMAIL_PENDING); idata->newMailCount = 0; #if USE_HCACHE idata->hcache = imap_hcache_open (idata, NULL); if (idata->hcache && !msgbegin) { uid_validity = mutt_hcache_fetch_raw (idata->hcache, "/UIDVALIDITY", imap_hcache_keylen); puidnext = mutt_hcache_fetch_raw (idata->hcache, "/UIDNEXT", imap_hcache_keylen); if (puidnext) { uidnext = *puidnext; FREE (&puidnext); } if (uid_validity && uidnext && *uid_validity == idata->uid_validity) evalhc = 1; FREE (&uid_validity); } if (evalhc) { /* L10N: Comparing the cached data with the IMAP server's data */ mutt_progress_init (&progress, _("Evaluating cache..."), MUTT_PROGRESS_MSG, ReadInc, msgend + 1); snprintf (buf, sizeof (buf), "UID FETCH 1:%u (UID FLAGS)", uidnext - 1); imap_cmd_start (idata, buf); rc = IMAP_CMD_CONTINUE; for (msgno = msgbegin; rc == IMAP_CMD_CONTINUE; msgno++) { mutt_progress_update (&progress, msgno + 1, -1); memset (&h, 0, sizeof (h)); h.data = safe_calloc (1, sizeof (IMAP_HEADER_DATA)); do { mfhrc = 0; rc = imap_cmd_step (idata); if (rc != IMAP_CMD_CONTINUE) { imap_free_header_data (&h.data); break; } /* hole in the header cache */ if (!evalhc) continue; if ((mfhrc = msg_fetch_header (ctx, &h, idata->buf, NULL)) == -1) continue; else if (mfhrc < 0) { imap_free_header_data (&h.data); break; } if (!h.data->uid) { dprint (2, (debugfile, "imap_read_headers: skipping hcache FETCH " "response for unknown message number %d\n", h.sid)); mfhrc = -1; continue; } idx++; ctx->hdrs[idx] = imap_hcache_get (idata, h.data->uid); if (ctx->hdrs[idx]) { ctx->hdrs[idx]->index = idx; /* messages which have not been expunged are ACTIVE (borrowed from mh * folders) */ ctx->hdrs[idx]->active = 1; ctx->hdrs[idx]->read = h.data->read; ctx->hdrs[idx]->old = h.data->old; ctx->hdrs[idx]->deleted = h.data->deleted; ctx->hdrs[idx]->flagged = h.data->flagged; ctx->hdrs[idx]->replied = h.data->replied; ctx->hdrs[idx]->changed = h.data->changed; /* ctx->hdrs[msgno]->received is restored from mutt_hcache_restore */ ctx->hdrs[idx]->data = (void *) (h.data); ctx->msgcount++; ctx->size += ctx->hdrs[idx]->content->length; } else { /* bad header in the cache, we'll have to refetch. */ dprint (3, (debugfile, "bad cache entry at %d, giving up\n", h.sid - 1)); imap_free_header_data(&h.data); evalhc = 0; idx--; } } while (rc != IMAP_CMD_OK && mfhrc == -1); if (rc == IMAP_CMD_OK) break; if ((mfhrc < -1) || ((rc != IMAP_CMD_CONTINUE) && (rc != IMAP_CMD_OK))) { imap_free_header_data (&h.data); imap_hcache_close (idata); goto error_out_1; } } /* could also look for first null header in case hcache is holey */ msgbegin = ctx->msgcount; } #endif /* USE_HCACHE */ mutt_progress_init (&progress, _("Fetching message headers..."), MUTT_PROGRESS_MSG, ReadInc, msgend + 1); for (msgno = msgbegin; msgno <= msgend ; msgno++) { mutt_progress_update (&progress, msgno + 1, -1); /* we may get notification of new mail while fetching headers */ if (msgno + 1 > fetchlast) { char *cmd; fetchlast = msgend + 1; safe_asprintf (&cmd, "FETCH %d:%d (UID FLAGS INTERNALDATE RFC822.SIZE %s)", msgno + 1, fetchlast, hdrreq); imap_cmd_start (idata, cmd); FREE (&cmd); } rewind (fp); memset (&h, 0, sizeof (h)); h.data = safe_calloc (1, sizeof (IMAP_HEADER_DATA)); /* this DO loop does two things: * 1. handles untagged messages, so we can try again on the same msg * 2. fetches the tagged response at the end of the last message. */ do { mfhrc = 0; rc = imap_cmd_step (idata); if (rc != IMAP_CMD_CONTINUE) break; if ((mfhrc = msg_fetch_header (ctx, &h, idata->buf, fp)) == -1) continue; else if (mfhrc < 0) break; if (!ftello (fp)) { dprint (2, (debugfile, "msg_fetch_header: ignoring fetch response with no body\n")); mfhrc = -1; msgend--; continue; } /* make sure we don't get remnants from older larger message headers */ fputs ("\n\n", fp); idx++; if (idx > msgend) { dprint (1, (debugfile, "imap_read_headers: skipping FETCH response for " "unknown message number %d\n", h.sid)); mfhrc = -1; idx--; continue; } /* May receive FLAGS updates in a separate untagged response (#2935) */ if (idx < ctx->msgcount) { dprint (2, (debugfile, "imap_read_headers: message %d is not new\n", h.sid)); idx--; continue; } ctx->hdrs[idx] = mutt_new_header (); ctx->hdrs[idx]->index = h.sid - 1; /* messages which have not been expunged are ACTIVE (borrowed from mh * folders) */ ctx->hdrs[idx]->active = 1; ctx->hdrs[idx]->read = h.data->read; ctx->hdrs[idx]->old = h.data->old; ctx->hdrs[idx]->deleted = h.data->deleted; ctx->hdrs[idx]->flagged = h.data->flagged; ctx->hdrs[idx]->replied = h.data->replied; ctx->hdrs[idx]->changed = h.data->changed; ctx->hdrs[idx]->received = h.received; ctx->hdrs[idx]->data = (void *) (h.data); if (maxuid < h.data->uid) maxuid = h.data->uid; rewind (fp); /* NOTE: if Date: header is missing, mutt_read_rfc822_header depends * on h.received being set */ ctx->hdrs[idx]->env = mutt_read_rfc822_header (fp, ctx->hdrs[idx], 0, 0); /* content built as a side-effect of mutt_read_rfc822_header */ ctx->hdrs[idx]->content->length = h.content_length; ctx->size += h.content_length; #if USE_HCACHE imap_hcache_put (idata, ctx->hdrs[idx]); #endif /* USE_HCACHE */ ctx->msgcount++; } while ((rc != IMAP_CMD_OK) && ((mfhrc == -1) || ((msgno + 1) >= fetchlast))); if ((mfhrc < -1) || ((rc != IMAP_CMD_CONTINUE) && (rc != IMAP_CMD_OK))) { imap_free_header_data (&h.data); #if USE_HCACHE imap_hcache_close (idata); #endif goto error_out_1; } /* in case we get new mail while fetching the headers */ if (idata->reopen & IMAP_NEWMAIL_PENDING) { msgend = idata->newMailCount - 1; while ((msgend) >= ctx->hdrmax) mx_alloc_memory (ctx); idata->reopen &= ~IMAP_NEWMAIL_PENDING; idata->newMailCount = 0; } } if (maxuid && (status = imap_mboxcache_get (idata, idata->mailbox, 0)) && (status->uidnext < maxuid + 1)) status->uidnext = maxuid + 1; #if USE_HCACHE mutt_hcache_store_raw (idata->hcache, "/UIDVALIDITY", &idata->uid_validity, sizeof (idata->uid_validity), imap_hcache_keylen); if (maxuid && idata->uidnext < maxuid + 1) { dprint (2, (debugfile, "Overriding UIDNEXT: %u -> %u\n", idata->uidnext, maxuid + 1)); idata->uidnext = maxuid + 1; } if (idata->uidnext > 1) mutt_hcache_store_raw (idata->hcache, "/UIDNEXT", &idata->uidnext, sizeof (idata->uidnext), imap_hcache_keylen); imap_hcache_close (idata); #endif /* USE_HCACHE */ if (ctx->msgcount > oldmsgcount) { mx_alloc_memory(ctx); mx_update_context (ctx, ctx->msgcount - oldmsgcount); } idata->reopen |= IMAP_REOPEN_ALLOW; retval = msgend; error_out_1: safe_fclose (&fp); error_out_0: FREE (&hdrreq); return retval; }
/* * Read header * returns: * 0 on success * -1 - connection lost, * -2 - invalid command or execution error, * -3 - error writing to tempfile */ static int pop_read_header(POP_DATA *pop_data, HEADER *h) { FILE *f; int ret, index; long length; char buf[LONG_STRING]; char tempfile[_POSIX_PATH_MAX]; mutt_mktemp(tempfile, sizeof(tempfile)); if (!(f = safe_fopen(tempfile, "w+"))) { mutt_perror(tempfile); return -3; } snprintf(buf, sizeof(buf), "LIST %d\r\n", h->refno); ret = pop_query(pop_data, buf, sizeof(buf)); if (ret == 0) { sscanf(buf, "+OK %d %ld", &index, &length); snprintf(buf, sizeof(buf), "TOP %d 0\r\n", h->refno); ret = pop_fetch_data(pop_data, buf, NULL, fetch_message, f); if (pop_data->cmd_top == 2) { if (ret == 0) { pop_data->cmd_top = 1; dprint(1, "pop_read_header: set TOP capability\n"); } if (ret == -2) { pop_data->cmd_top = 0; dprint(1, "pop_read_header: unset TOP capability\n"); snprintf(pop_data->err_msg, sizeof(pop_data->err_msg), _("Command TOP is not supported by server.")); } } } switch (ret) { case 0: { rewind(f); h->env = mutt_read_rfc822_header(f, h, 0, 0); h->content->length = length - h->content->offset + 1; rewind(f); while (!feof(f)) { h->content->length--; fgets(buf, sizeof(buf), f); } break; } case -2: { mutt_error("%s", pop_data->err_msg); break; } case -3: { mutt_error _("Can't write header to temporary file!"); break; } } safe_fclose(&f); unlink(tempfile); return ret; }
/** * icmd_bind - Parse 'bind' and 'macro' commands - Implements ::icommand_t */ static enum CommandResult icmd_bind(struct Buffer *buf, struct Buffer *s, unsigned long data, struct Buffer *err) { FILE *fp_out = NULL; char tempfile[PATH_MAX]; bool dump_all = false, bind = (data == 0); if (!MoreArgs(s)) dump_all = true; else mutt_extract_token(buf, s, 0); if (MoreArgs(s)) { /* More arguments potentially means the user is using the * ::command_t :bind command thus we delegate the task. */ return MUTT_CMD_ERROR; } struct Buffer *filebuf = mutt_buffer_alloc(4096); if (dump_all || (mutt_str_strcasecmp(buf->data, "all") == 0)) { dump_all_menus(filebuf, bind); } else { const int menu_index = mutt_map_get_value(buf->data, Menus); if (menu_index == -1) { mutt_buffer_printf(err, _("%s: no such menu"), buf->data); mutt_buffer_free(&filebuf); return MUTT_CMD_ERROR; } struct Mapping menu = { buf->data, menu_index }; dump_menu(filebuf, &menu, bind); } if (mutt_buffer_is_empty(filebuf)) { mutt_buffer_printf(err, _("%s: no %s for this menu"), dump_all ? "all" : buf->data, bind ? "binds" : "macros"); mutt_buffer_free(&filebuf); return MUTT_CMD_ERROR; } mutt_mktemp(tempfile, sizeof(tempfile)); fp_out = mutt_file_fopen(tempfile, "w"); if (!fp_out) { mutt_buffer_printf(err, _("Could not create temporary file %s"), tempfile); mutt_buffer_free(&filebuf); return MUTT_CMD_ERROR; } fputs(filebuf->data, fp_out); mutt_file_fclose(&fp_out); mutt_buffer_free(&filebuf); struct Pager info = { 0 }; if (mutt_pager((bind) ? "bind" : "macro", tempfile, 0, &info) == -1) { mutt_buffer_printf(err, _("Could not create temporary file %s"), tempfile); return MUTT_CMD_ERROR; } return MUTT_CMD_SUCCESS; }
/** * crypt_extract_keys_from_messages - Extract keys from a message * @param el List of Emails to process * * The extracted keys will be added to the user's keyring. */ void crypt_extract_keys_from_messages(struct EmailList *el) { char tempfname[PATH_MAX], *mbox = NULL; struct Address *tmp = NULL; if (!WithCrypto) return; mutt_mktemp(tempfname, sizeof(tempfname)); FILE *fp_out = mutt_file_fopen(tempfname, "w"); if (!fp_out) { mutt_perror(tempfname); return; } if (WithCrypto & APPLICATION_PGP) OptDontHandlePgpKeys = true; struct EmailNode *en = NULL; STAILQ_FOREACH(en, el, entries) { struct Email *e = en->email; mutt_parse_mime_message(Context->mailbox, e); if (e->security & SEC_ENCRYPT && !crypt_valid_passphrase(e->security)) { mutt_file_fclose(&fp_out); break; } if (((WithCrypto & APPLICATION_PGP) != 0) && (e->security & APPLICATION_PGP)) { mutt_copy_message_ctx(fp_out, Context->mailbox, e, MUTT_CM_DECODE | MUTT_CM_CHARCONV, 0); fflush(fp_out); mutt_endwin(); puts(_("Trying to extract PGP keys...\n")); crypt_pgp_invoke_import(tempfname); } if (((WithCrypto & APPLICATION_SMIME) != 0) && (e->security & APPLICATION_SMIME)) { if (e->security & SEC_ENCRYPT) { mutt_copy_message_ctx(fp_out, Context->mailbox, e, MUTT_CM_NOHEADER | MUTT_CM_DECODE_CRYPT | MUTT_CM_DECODE_SMIME, 0); } else mutt_copy_message_ctx(fp_out, Context->mailbox, e, 0, 0); fflush(fp_out); if (e->env->from) tmp = mutt_expand_aliases(e->env->from); else if (e->env->sender) tmp = mutt_expand_aliases(e->env->sender); mbox = tmp ? tmp->mailbox : NULL; if (mbox) { mutt_endwin(); puts(_("Trying to extract S/MIME certificates...")); crypt_smime_invoke_import(tempfname, mbox); tmp = NULL; } } rewind(fp_out); } mutt_file_fclose(&fp_out); if (isendwin()) mutt_any_key_to_continue(NULL); mutt_file_unlink(tempfname); if (WithCrypto & APPLICATION_PGP) OptDontHandlePgpKeys = false; }
/** * mutt_signed_handler - Verify a "multipart/signed" body - Implements ::handler_t */ int mutt_signed_handler(struct Body *a, struct State *s) { bool inconsistent = false; struct Body *b = a; struct Body **signatures = NULL; int sigcnt = 0; int rc = 0; if (!WithCrypto) return -1; a = a->parts; SecurityFlags signed_type = mutt_is_multipart_signed(b); if (signed_type == SEC_NO_FLAGS) { /* A null protocol value is already checked for in mutt_body_handler() */ state_printf(s, _("[-- Error: " "Unknown multipart/signed protocol %s --]\n\n"), mutt_param_get(&b->parameter, "protocol")); return mutt_body_handler(a, s); } if (!(a && a->next)) inconsistent = true; else { switch (signed_type) { case SEC_SIGN: if ((a->next->type != TYPE_MULTIPART) || (mutt_str_strcasecmp(a->next->subtype, "mixed") != 0)) { inconsistent = true; } break; case PGP_SIGN: if ((a->next->type != TYPE_APPLICATION) || (mutt_str_strcasecmp(a->next->subtype, "pgp-signature") != 0)) { inconsistent = true; } break; case SMIME_SIGN: if ((a->next->type != TYPE_APPLICATION) || ((mutt_str_strcasecmp(a->next->subtype, "x-pkcs7-signature") != 0) && (mutt_str_strcasecmp(a->next->subtype, "pkcs7-signature") != 0))) { inconsistent = true; } break; default: inconsistent = true; } } if (inconsistent) { state_attach_puts(_("[-- Error: " "Missing or bad-format multipart/signed signature" " --]\n\n"), s); return mutt_body_handler(a, s); } if (s->flags & MUTT_DISPLAY) { crypt_fetch_signatures(&signatures, a->next, &sigcnt); if (sigcnt) { char tempfile[PATH_MAX]; mutt_mktemp(tempfile, sizeof(tempfile)); bool goodsig = true; if (crypt_write_signed(a, s, tempfile) == 0) { for (int i = 0; i < sigcnt; i++) { if (((WithCrypto & APPLICATION_PGP) != 0) && (signatures[i]->type == TYPE_APPLICATION) && (mutt_str_strcasecmp(signatures[i]->subtype, "pgp-signature") == 0)) { if (crypt_pgp_verify_one(signatures[i], s, tempfile) != 0) goodsig = false; continue; } if (((WithCrypto & APPLICATION_SMIME) != 0) && (signatures[i]->type == TYPE_APPLICATION) && ((mutt_str_strcasecmp(signatures[i]->subtype, "x-pkcs7-signature") == 0) || (mutt_str_strcasecmp(signatures[i]->subtype, "pkcs7-signature") == 0))) { if (crypt_smime_verify_one(signatures[i], s, tempfile) != 0) goodsig = false; continue; } state_printf(s, _("[-- Warning: " "We can't verify %s/%s signatures. --]\n\n"), TYPE(signatures[i]), signatures[i]->subtype); } } mutt_file_unlink(tempfile); b->goodsig = goodsig; b->badsig = !goodsig; /* Now display the signed body */ state_attach_puts(_("[-- The following data is signed --]\n\n"), s); mutt_protected_headers_handler(a, s); FREE(&signatures); } else state_attach_puts(_("[-- Warning: Can't find any signatures. --]\n\n"), s); } rc = mutt_body_handler(a, s); if (s->flags & MUTT_DISPLAY && sigcnt) state_attach_puts(_("\n[-- End of signed data --]\n"), s); return rc; }
/** * mbox_mbox_sync - Implements MxOps::mbox_sync() */ static int mbox_mbox_sync(struct Mailbox *m, int *index_hint) { if (!m) return -1; struct MboxAccountData *adata = mbox_adata_get(m); if (!adata) return -1; char tempfile[PATH_MAX]; char buf[32]; int i, j; enum SortType save_sort = SORT_ORDER; int rc = -1; int need_sort = 0; /* flag to resort mailbox if new mail arrives */ int first = -1; /* first message to be written */ LOFF_T offset; /* location in mailbox to write changed messages */ struct stat statbuf; struct MUpdate *new_offset = NULL; struct MUpdate *old_offset = NULL; FILE *fp = NULL; struct Progress progress; char msgbuf[PATH_MAX + 64]; /* sort message by their position in the mailbox on disk */ if (C_Sort != SORT_ORDER) { save_sort = C_Sort; C_Sort = SORT_ORDER; mutt_mailbox_changed(m, MBN_RESORT); C_Sort = save_sort; need_sort = 1; } /* need to open the file for writing in such a way that it does not truncate * the file, so use read-write mode. */ adata->fp = freopen(m->path, "r+", adata->fp); if (!adata->fp) { mx_fastclose_mailbox(m); mutt_error(_("Fatal error! Could not reopen mailbox!")); return -1; } mutt_sig_block(); if (mbox_lock_mailbox(m, true, true) == -1) { mutt_sig_unblock(); mutt_error(_("Unable to lock mailbox")); goto bail; } /* Check to make sure that the file hasn't changed on disk */ i = mbox_mbox_check(m, index_hint); if ((i == MUTT_NEW_MAIL) || (i == MUTT_REOPENED)) { /* new mail arrived, or mailbox reopened */ rc = i; goto bail; } else if (i < 0) { /* fatal error */ return -1; } /* Create a temporary file to write the new version of the mailbox in. */ mutt_mktemp(tempfile, sizeof(tempfile)); int fd = open(tempfile, O_WRONLY | O_EXCL | O_CREAT, 0600); if ((fd == -1) || !(fp = fdopen(fd, "w"))) { if (fd != -1) { close(fd); unlink(tempfile); } mutt_error(_("Could not create temporary file")); goto bail; } /* find the first deleted/changed message. we save a lot of time by only * rewriting the mailbox from the point where it has actually changed. */ for (i = 0; (i < m->msg_count) && !m->emails[i]->deleted && !m->emails[i]->changed && !m->emails[i]->attach_del; i++) { } if (i == m->msg_count) { /* this means ctx->changed or m->msg_deleted was set, but no * messages were found to be changed or deleted. This should * never happen, is we presume it is a bug in neomutt. */ mutt_error( _("sync: mbox modified, but no modified messages (report this bug)")); mutt_debug(LL_DEBUG1, "no modified messages\n"); unlink(tempfile); goto bail; } /* save the index of the first changed/deleted message */ first = i; /* where to start overwriting */ offset = m->emails[i]->offset; /* the offset stored in the header does not include the MMDF_SEP, so make * sure we seek to the correct location */ if (m->magic == MUTT_MMDF) offset -= (sizeof(MMDF_SEP) - 1); /* allocate space for the new offsets */ new_offset = mutt_mem_calloc(m->msg_count - first, sizeof(struct MUpdate)); old_offset = mutt_mem_calloc(m->msg_count - first, sizeof(struct MUpdate)); if (!m->quiet) { snprintf(msgbuf, sizeof(msgbuf), _("Writing %s..."), m->path); mutt_progress_init(&progress, msgbuf, MUTT_PROGRESS_MSG, C_WriteInc, m->msg_count); } for (i = first, j = 0; i < m->msg_count; i++) { if (!m->quiet) mutt_progress_update(&progress, i, (int) (ftello(adata->fp) / (m->size / 100 + 1))); /* back up some information which is needed to restore offsets when * something fails. */ old_offset[i - first].valid = true; old_offset[i - first].hdr = m->emails[i]->offset; old_offset[i - first].body = m->emails[i]->content->offset; old_offset[i - first].lines = m->emails[i]->lines; old_offset[i - first].length = m->emails[i]->content->length; if (!m->emails[i]->deleted) { j++; if (m->magic == MUTT_MMDF) { if (fputs(MMDF_SEP, fp) == EOF) { mutt_perror(tempfile); unlink(tempfile); goto bail; } } /* save the new offset for this message. we add 'offset' because the * temporary file only contains saved message which are located after * 'offset' in the real mailbox */ new_offset[i - first].hdr = ftello(fp) + offset; if (mutt_copy_message_ctx(fp, m, m->emails[i], MUTT_CM_UPDATE, CH_FROM | CH_UPDATE | CH_UPDATE_LEN) != 0) { mutt_perror(tempfile); unlink(tempfile); goto bail; } /* Since messages could have been deleted, the offsets stored in memory * will be wrong, so update what we can, which is the offset of this * message, and the offset of the body. If this is a multipart message, * we just flush the in memory cache so that the message will be reparsed * if the user accesses it later. */ new_offset[i - first].body = ftello(fp) - m->emails[i]->content->length + offset; mutt_body_free(&m->emails[i]->content->parts); switch (m->magic) { case MUTT_MMDF: if (fputs(MMDF_SEP, fp) == EOF) { mutt_perror(tempfile); unlink(tempfile); goto bail; } break; default: if (fputs("\n", fp) == EOF) { mutt_perror(tempfile); unlink(tempfile); goto bail; } } } } if (fclose(fp) != 0) { fp = NULL; mutt_debug(LL_DEBUG1, "mutt_file_fclose (&) returned non-zero\n"); unlink(tempfile); mutt_perror(tempfile); goto bail; } fp = NULL; /* Save the state of this folder. */ if (stat(m->path, &statbuf) == -1) { mutt_perror(m->path); unlink(tempfile); goto bail; } fp = fopen(tempfile, "r"); if (!fp) { mutt_sig_unblock(); mx_fastclose_mailbox(m); mutt_debug(LL_DEBUG1, "unable to reopen temp copy of mailbox!\n"); mutt_perror(tempfile); FREE(&new_offset); FREE(&old_offset); return -1; } if ((fseeko(adata->fp, offset, SEEK_SET) != 0) || /* seek the append location */ /* do a sanity check to make sure the mailbox looks ok */ !fgets(buf, sizeof(buf), adata->fp) || ((m->magic == MUTT_MBOX) && !mutt_str_startswith(buf, "From ", CASE_MATCH)) || ((m->magic == MUTT_MMDF) && (mutt_str_strcmp(MMDF_SEP, buf) != 0))) { mutt_debug(LL_DEBUG1, "message not in expected position\n"); mutt_debug(LL_DEBUG1, "\tLINE: %s\n", buf); i = -1; } else { if (fseeko(adata->fp, offset, SEEK_SET) != 0) /* return to proper offset */ { i = -1; mutt_debug(LL_DEBUG1, "fseek() failed\n"); } else { /* copy the temp mailbox back into place starting at the first * change/deleted message */ if (!m->quiet) mutt_message(_("Committing changes...")); i = mutt_file_copy_stream(fp, adata->fp); if (ferror(adata->fp)) i = -1; } if (i == 0) { m->size = ftello(adata->fp); /* update the mailbox->size of the mailbox */ if ((m->size < 0) || (ftruncate(fileno(adata->fp), m->size) != 0)) { i = -1; mutt_debug(LL_DEBUG1, "ftruncate() failed\n"); } } } mutt_file_fclose(&fp); fp = NULL; mbox_unlock_mailbox(m); if ((mutt_file_fclose(&adata->fp) != 0) || (i == -1)) { /* error occurred while writing the mailbox back, so keep the temp copy around */ char savefile[PATH_MAX]; snprintf(savefile, sizeof(savefile), "%s/neomutt.%s-%s-%u", NONULL(C_Tmpdir), NONULL(Username), NONULL(ShortHostname), (unsigned int) getpid()); rename(tempfile, savefile); mutt_sig_unblock(); mx_fastclose_mailbox(m); mutt_pretty_mailbox(savefile, sizeof(savefile)); mutt_error(_("Write failed! Saved partial mailbox to %s"), savefile); FREE(&new_offset); FREE(&old_offset); return -1; } /* Restore the previous access/modification times */ mbox_reset_atime(m, &statbuf); /* reopen the mailbox in read-only mode */ adata->fp = fopen(m->path, "r"); if (!adata->fp) { unlink(tempfile); mutt_sig_unblock(); mx_fastclose_mailbox(m); mutt_error(_("Fatal error! Could not reopen mailbox!")); FREE(&new_offset); FREE(&old_offset); return -1; } /* update the offsets of the rewritten messages */ for (i = first, j = first; i < m->msg_count; i++) { if (!m->emails[i]->deleted) { m->emails[i]->offset = new_offset[i - first].hdr; m->emails[i]->content->hdr_offset = new_offset[i - first].hdr; m->emails[i]->content->offset = new_offset[i - first].body; m->emails[i]->index = j++; } } FREE(&new_offset); FREE(&old_offset); unlink(tempfile); /* remove partial copy of the mailbox */ mutt_sig_unblock(); if (C_CheckMboxSize) { struct Mailbox *tmp = mutt_find_mailbox(m->path); if (tmp && !tmp->has_new) mutt_update_mailbox(tmp); } return 0; /* signal success */ bail: /* Come here in case of disaster */ mutt_file_fclose(&fp); /* restore offsets, as far as they are valid */ if ((first >= 0) && old_offset) { for (i = first; (i < m->msg_count) && old_offset[i - first].valid; i++) { m->emails[i]->offset = old_offset[i - first].hdr; m->emails[i]->content->hdr_offset = old_offset[i - first].hdr; m->emails[i]->content->offset = old_offset[i - first].body; m->emails[i]->lines = old_offset[i - first].lines; m->emails[i]->content->length = old_offset[i - first].length; } } /* this is ok to call even if we haven't locked anything */ mbox_unlock_mailbox(m); mutt_sig_unblock(); FREE(&new_offset); FREE(&old_offset); adata->fp = freopen(m->path, "r", adata->fp); if (!adata->fp) { mutt_error(_("Could not reopen mailbox")); mx_fastclose_mailbox(m); return -1; } if (need_sort) { /* if the mailbox was reopened, the thread tree will be invalid so make * sure to start threading from scratch. */ mutt_mailbox_changed(m, MBN_RESORT); } return rc; }
/* return values: * 0 success * -1 failure */ int mbox_sync_mailbox(CONTEXT *ctx, int *index_hint) { char tempfile[_POSIX_PATH_MAX]; char buf[32]; int i, j, save_sort = SORT_ORDER; int rc = -1; int need_sort = 0; /* flag to resort mailbox if new mail arrives */ int first = -1; /* first message to be written */ LOFF_T offset; /* location in mailbox to write changed messages */ struct stat statbuf; struct m_update_t *newOffset = NULL; struct m_update_t *oldOffset = NULL; FILE *fp = NULL; progress_t progress; char msgbuf[STRING]; /* sort message by their position in the mailbox on disk */ if (Sort != SORT_ORDER) { save_sort = Sort; Sort = SORT_ORDER; mutt_sort_headers(ctx, 0); Sort = save_sort; need_sort = 1; } /* need to open the file for writing in such a way that it does not truncate * the file, so use read-write mode. */ if ((ctx->fp = freopen(ctx->path, "r+", ctx->fp)) == NULL) { mx_fastclose_mailbox(ctx); mutt_error _("Fatal error! Could not reopen mailbox!"); return -1; } mutt_block_signals(); if (mbox_lock_mailbox(ctx, 1, 1) == -1) { mutt_unblock_signals(); mutt_error _("Unable to lock mailbox!"); goto bail; } /* Check to make sure that the file hasn't changed on disk */ if (((i = mbox_check_mailbox(ctx, index_hint)) == M_NEW_MAIL) || (i == M_REOPENED)) { /* new mail arrived, or mailbox reopened */ need_sort = i; rc = i; goto bail; } else if (i < 0) /* fatal error */ return -1; /* Create a temporary file to write the new version of the mailbox in. */ mutt_mktemp(tempfile, sizeof(tempfile)); if (((i = open(tempfile, O_WRONLY | O_EXCL | O_CREAT, 0600)) == -1) || ((fp = fdopen(i, "w")) == NULL)) { if (-1 != i) { close(i); unlink(tempfile); } mutt_error _("Could not create temporary file!"); mutt_sleep(5); goto bail; } /* find the first deleted/changed message. we save a lot of time by only * rewriting the mailbox from the point where it has actually changed. */ for (i = 0; i < ctx->msgcount && !ctx->hdrs[i]->deleted && !ctx->hdrs[i]->changed && !ctx->hdrs[i]->attach_del; i++) ; if (i == ctx->msgcount) { /* this means ctx->changed or ctx->deleted was set, but no * messages were found to be changed or deleted. This should * never happen, is we presume it is a bug in mutt. */ mutt_error _( "sync: mbox modified, but no modified messages! (report this bug)"); mutt_sleep(5); /* the mutt_error /will/ get cleared! */ dprint(1, "mbox_sync_mailbox(): no modified messages.\n"); unlink(tempfile); goto bail; } /* save the index of the first changed/deleted message */ first = i; /* where to start overwriting */ offset = ctx->hdrs[i]->offset; /* the offset stored in the header does not include the MMDF_SEP, so make * sure we seek to the correct location */ if (ctx->magic == M_MMDF) offset -= (sizeof MMDF_SEP - 1); /* allocate space for the new offsets */ newOffset = (__typeof__(newOffset)) safe_calloc(ctx->msgcount - first, sizeof(struct m_update_t)); oldOffset = (__typeof__(oldOffset)) safe_calloc(ctx->msgcount - first, sizeof(struct m_update_t)); if (!ctx->quiet) { snprintf(msgbuf, sizeof(msgbuf), _("Writing %s..."), ctx->path); mutt_progress_init(&progress, msgbuf, M_PROGRESS_MSG, WriteInc, ctx->msgcount); } for (i = first, j = 0; i < ctx->msgcount; i++) { if (!ctx->quiet) mutt_progress_update(&progress, i, (int)(ftello(ctx->fp) / (ctx->size / 100 + 1))); /* * back up some information which is needed to restore offsets when * something fails. */ oldOffset[i - first].valid = 1; oldOffset[i - first].hdr = ctx->hdrs[i]->offset; oldOffset[i - first].body = ctx->hdrs[i]->content->offset; oldOffset[i - first].lines = ctx->hdrs[i]->lines; oldOffset[i - first].length = ctx->hdrs[i]->content->length; if (!ctx->hdrs[i]->deleted) { j++; if (ctx->magic == M_MMDF) { if (fputs(MMDF_SEP, fp) == EOF) { mutt_perror(tempfile); mutt_sleep(5); unlink(tempfile); goto bail; } } /* save the new offset for this message. we add `offset' because the * temporary file only contains saved message which are located *after * `offset' in the real mailbox */ newOffset[i - first].hdr = ftello(fp) + offset; if (mutt_copy_message(fp, ctx, ctx->hdrs[i], M_CM_UPDATE, CH_FROM | CH_UPDATE | CH_UPDATE_LEN) != 0) { mutt_perror(tempfile); mutt_sleep(5); unlink(tempfile); goto bail; } /* Since messages could have been deleted, the offsets stored in memory * will be wrong, so update what we can, which is the offset of this * message, and the offset of the body. If this is a multipart *message, * we just flush the in memory cache so that the message will be *reparsed * if the user accesses it later. */ newOffset[i - first].body = ftello(fp) - ctx->hdrs[i]->content->length + offset; mutt_free_body(&ctx->hdrs[i]->content->parts); switch (ctx->magic) { case M_MMDF: if (fputs(MMDF_SEP, fp) == EOF) { mutt_perror(tempfile); mutt_sleep(5); unlink(tempfile); goto bail; } break; default: if (fputs("\n", fp) == EOF) { mutt_perror(tempfile); mutt_sleep(5); unlink(tempfile); goto bail; } } } } if (fclose(fp) != 0) { fp = NULL; dprint(1, "mbox_sync_mailbox: safe_fclose (&) returned non-zero.\n"); unlink(tempfile); mutt_perror(tempfile); mutt_sleep(5); goto bail; } fp = NULL; /* Save the state of this folder. */ if (stat(ctx->path, &statbuf) == -1) { mutt_perror(ctx->path); mutt_sleep(5); unlink(tempfile); goto bail; } if ((fp = fopen(tempfile, "r")) == NULL) { mutt_unblock_signals(); mx_fastclose_mailbox(ctx); dprint(1, "mbox_sync_mailbox: unable to reopen temp copy of mailbox!\n"); mutt_perror(tempfile); mutt_sleep(5); return -1; } if ((fseeko(ctx->fp, offset, SEEK_SET) != 0) /* seek the append location */ ||/* do a sanity check to make sure the mailbox looks ok */ (fgets(buf, sizeof(buf), ctx->fp) == NULL) || ((ctx->magic == M_MBOX) && (mutt_strncmp("From ", buf, 5) != 0)) || ((ctx->magic == M_MMDF) && (mutt_strcmp(MMDF_SEP, buf) != 0))) { dprint(1, "mbox_sync_mailbox: message not in expected position."); dprint(1, "\tLINE: %s\n", buf); i = -1; } else { if (fseeko(ctx->fp, offset, SEEK_SET) != 0) { /* return to proper offset */ i = -1; dprint(1, "mbox_sync_mailbox: fseek() failed\n"); } else { /* copy the temp mailbox back into place starting at the first * change/deleted message */ if (!ctx->quiet) mutt_message _("Committing changes..."); i = mutt_copy_stream(fp, ctx->fp); if (ferror(ctx->fp)) i = -1; } if (i == 0) { ctx->size = ftello(ctx->fp); /* update the size of the mailbox */ ftruncate(fileno(ctx->fp), ctx->size); } } safe_fclose(&fp); fp = NULL; mbox_unlock_mailbox(ctx); if ((fclose(ctx->fp) != 0) || (i == -1)) { /* error occurred while writing the mailbox back, so keep the temp copy * around */ char savefile[_POSIX_PATH_MAX]; snprintf(savefile, sizeof(savefile), "%s/mutt.%s-%s-%u", NONULL(Tempdir), NONULL(Username), NONULL(Hostname), (unsigned int)getpid()); rename(tempfile, savefile); mutt_unblock_signals(); mx_fastclose_mailbox(ctx); mutt_pretty_mailbox(savefile, sizeof(savefile)); mutt_error(_("Write failed! Saved partial mailbox to %s"), savefile); mutt_sleep(5); return -1; } /* Restore the previous access/modification times */ mbox_reset_atime(ctx, &statbuf); /* reopen the mailbox in read-only mode */ if ((ctx->fp = fopen(ctx->path, "r")) == NULL) { unlink(tempfile); mutt_unblock_signals(); mx_fastclose_mailbox(ctx); mutt_error _("Fatal error! Could not reopen mailbox!"); return -1; } /* update the offsets of the rewritten messages */ for (i = first, j = first; i < ctx->msgcount; i++) { if (!ctx->hdrs[i]->deleted) { ctx->hdrs[i]->offset = newOffset[i - first].hdr; ctx->hdrs[i]->content->hdr_offset = newOffset[i - first].hdr; ctx->hdrs[i]->content->offset = newOffset[i - first].body; ctx->hdrs[i]->index = j++; } } safe_free(&newOffset); safe_free(&oldOffset); unlink(tempfile); /* remove partial copy of the mailbox */ mutt_unblock_signals(); return 0; /* signal success */ bail: /* Come here in case of disaster */ safe_fclose(&fp); /* restore offsets, as far as they are valid */ if ((first >= 0) && oldOffset) { for (i = first; i < ctx->msgcount && oldOffset[i - first].valid; i++) { ctx->hdrs[i]->offset = oldOffset[i - first].hdr; ctx->hdrs[i]->content->hdr_offset = oldOffset[i - first].hdr; ctx->hdrs[i]->content->offset = oldOffset[i - first].body; ctx->hdrs[i]->lines = oldOffset[i - first].lines; ctx->hdrs[i]->content->length = oldOffset[i - first].length; } } /* this is ok to call even if we haven't locked anything */ mbox_unlock_mailbox(ctx); mutt_unblock_signals(); safe_free(&newOffset); safe_free(&oldOffset); if ((ctx->fp = freopen(ctx->path, "r", ctx->fp)) == NULL) { mutt_error _("Could not reopen mailbox!"); mx_fastclose_mailbox(ctx); return -1; } if (need_sort) /* if the mailbox was reopened, the thread tree will be invalid so make * sure to start threading from scratch. */ mutt_sort_headers(ctx, (need_sort == M_REOPENED)); return rc; }
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); }
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); }
/* return 1 if require full screen redraw, 0 otherwise */ int mutt_compose_attachment (BODY *a) { char type[STRING]; char command[STRING]; char newfile[_POSIX_PATH_MAX] = ""; rfc1524_entry *entry = rfc1524_new_entry (); short unlink_newfile = 0; int rc = 0; snprintf (type, sizeof (type), "%s/%s", TYPE (a), a->subtype); if (rfc1524_mailcap_lookup (a, type, entry, M_COMPOSE)) { if (entry->composecommand || entry->composetypecommand) { if (entry->composetypecommand) strfcpy (command, entry->composetypecommand, sizeof (command)); else strfcpy (command, entry->composecommand, sizeof (command)); if (rfc1524_expand_filename (entry->nametemplate, a->filename, newfile, sizeof (newfile))) { dprint(1, (debugfile, "oldfile: %s\t newfile: %s\n", a->filename, newfile)); if (safe_symlink (a->filename, newfile) == -1) { if (mutt_yesorno (_("Can't match nametemplate, continue?"), M_YES) != M_YES) goto bailout; } else unlink_newfile = 1; } else strfcpy(newfile, a->filename, sizeof(newfile)); if (rfc1524_expand_command (a, newfile, type, command, sizeof (command))) { /* For now, editing requires a file, no piping */ mutt_error _("Mailcap compose entry requires %%s"); } else { int r; mutt_endwin (NULL); if ((r = mutt_system (command)) == -1) mutt_error (_("Error running \"%s\"!"), command); if (r != -1 && entry->composetypecommand) { BODY *b; FILE *fp, *tfp; char tempfile[_POSIX_PATH_MAX]; if ((fp = safe_fopen (a->filename, "r")) == NULL) { mutt_perror _("Failure to open file to parse headers."); goto bailout; } b = mutt_read_mime_header (fp, 0); if (b) { if (b->parameter) { mutt_free_parameter (&a->parameter); a->parameter = b->parameter; b->parameter = NULL; } if (b->description) { FREE (&a->description); a->description = b->description; b->description = NULL; } if (b->form_name) { FREE (&a->form_name); a->form_name = b->form_name; b->form_name = NULL; } /* Remove headers by copying out data to another file, then * copying the file back */ fseeko (fp, b->offset, 0); mutt_mktemp (tempfile, sizeof (tempfile)); if ((tfp = safe_fopen (tempfile, "w")) == NULL) { mutt_perror _("Failure to open file to strip headers."); goto bailout; } mutt_copy_stream (fp, tfp); safe_fclose (&fp); safe_fclose (&tfp); mutt_unlink (a->filename); if (mutt_rename_file (tempfile, a->filename) != 0) { mutt_perror _("Failure to rename file."); goto bailout; } mutt_free_body (&b); } } } } } else { rfc1524_free_entry (&entry); mutt_message (_("No mailcap compose entry for %s, creating empty file."), type); return 1; } rc = 1; bailout: if(unlink_newfile) unlink(newfile); rfc1524_free_entry (&entry); return rc; }
int mutt_print_attachment (FILE *fp, BODY *a) { char newfile[_POSIX_PATH_MAX] = ""; char type[STRING]; pid_t thepid; FILE *ifp, *fpout; short unlink_newfile = 0; snprintf (type, sizeof (type), "%s/%s", TYPE (a), a->subtype); if (rfc1524_mailcap_lookup (a, type, NULL, M_PRINT)) { char command[_POSIX_PATH_MAX+STRING]; rfc1524_entry *entry; int piped = FALSE; dprint (2, (debugfile, "Using mailcap...\n")); entry = rfc1524_new_entry (); rfc1524_mailcap_lookup (a, type, entry, M_PRINT); if (rfc1524_expand_filename (entry->nametemplate, a->filename, newfile, sizeof (newfile))) { if (!fp) { if (safe_symlink(a->filename, newfile) == -1) { if (mutt_yesorno (_("Can't match nametemplate, continue?"), M_YES) != M_YES) { rfc1524_free_entry (&entry); return 0; } strfcpy (newfile, a->filename, sizeof (newfile)); } else unlink_newfile = 1; } } /* in recv mode, save file to newfile first */ if (fp) mutt_save_attachment (fp, a, newfile, 0, NULL); strfcpy (command, entry->printcommand, sizeof (command)); piped = rfc1524_expand_command (a, newfile, type, command, sizeof (command)); mutt_endwin (NULL); /* interactive program */ if (piped) { if ((ifp = fopen (newfile, "r")) == NULL) { mutt_perror ("fopen"); rfc1524_free_entry (&entry); return (0); } if ((thepid = mutt_create_filter (command, &fpout, NULL, NULL)) < 0) { mutt_perror _("Can't create filter"); rfc1524_free_entry (&entry); safe_fclose (&ifp); return 0; } mutt_copy_stream (ifp, fpout); safe_fclose (&fpout); safe_fclose (&ifp); if (mutt_wait_filter (thepid) || option (OPTWAITKEY)) mutt_any_key_to_continue (NULL); } else { if (mutt_system (command) || option (OPTWAITKEY)) mutt_any_key_to_continue (NULL); } if (fp) mutt_unlink (newfile); else if (unlink_newfile) unlink(newfile); rfc1524_free_entry (&entry); return (1); } if (!ascii_strcasecmp ("text/plain", type) || !ascii_strcasecmp ("application/postscript", type)) { return (mutt_pipe_attachment (fp, a, NONULL(PrintCmd), NULL)); } else if (mutt_can_decode (a)) { /* decode and print */ int rc = 0; ifp = NULL; fpout = NULL; mutt_mktemp (newfile, sizeof (newfile)); if (mutt_decode_save_attachment (fp, a, newfile, M_PRINTING, 0) == 0) { dprint (2, (debugfile, "successfully decoded %s type attachment to %s\n", type, newfile)); if ((ifp = fopen (newfile, "r")) == NULL) { mutt_perror ("fopen"); goto bail0; } dprint (2, (debugfile, "successfully opened %s read-only\n", newfile)); mutt_endwin (NULL); if ((thepid = mutt_create_filter (NONULL(PrintCmd), &fpout, NULL, NULL)) < 0) { mutt_perror _("Can't create filter"); goto bail0; } dprint (2, (debugfile, "Filter created.\n")); mutt_copy_stream (ifp, fpout); safe_fclose (&fpout); safe_fclose (&ifp); if (mutt_wait_filter (thepid) != 0 || option (OPTWAITKEY)) mutt_any_key_to_continue (NULL); rc = 1; } bail0: safe_fclose (&ifp); safe_fclose (&fpout); mutt_unlink (newfile); return rc; } else { mutt_error _("I don't know how to print that!"); return 0; } }
int mutt_display_message (HEADER *cur) { char tempfile[_POSIX_PATH_MAX], buf[LONG_STRING]; int rc = 0, builtin = 0; int cmflags = M_CM_DECODE | M_CM_DISPLAY | M_CM_CHARCONV; FILE *fpout = NULL; FILE *fpfilterout = NULL; pid_t filterpid = -1; int res; snprintf (buf, sizeof (buf), "%s/%s", TYPE (cur->content), cur->content->subtype); mutt_parse_mime_message (Context, cur); mutt_message_hook (Context, cur, M_MESSAGEHOOK); /* see if crypto is needed for this message. if so, we should exit curses */ if (WithCrypto && cur->security) { if (cur->security & ENCRYPT) { if (cur->security & APPLICATION_SMIME) crypt_smime_getkeys (cur->env); if(!crypt_valid_passphrase(cur->security)) return 0; cmflags |= M_CM_VERIFY; } else if (cur->security & SIGN) { /* find out whether or not the verify signature */ if (query_quadoption (OPT_VERIFYSIG, _("Verify PGP signature?")) == M_YES) { cmflags |= M_CM_VERIFY; } } } if (cmflags & M_CM_VERIFY || cur->security & ENCRYPT) { if (cur->security & APPLICATION_PGP) { if (cur->env->from) crypt_pgp_invoke_getkeys (cur->env->from); crypt_invoke_message (APPLICATION_PGP); } if (cur->security & APPLICATION_SMIME) crypt_invoke_message (APPLICATION_SMIME); } mutt_mktemp (tempfile, sizeof (tempfile)); if ((fpout = safe_fopen (tempfile, "w")) == NULL) { mutt_error _("Could not create temporary file!"); return (0); } if (DisplayFilter && *DisplayFilter) { fpfilterout = fpout; fpout = NULL; /* mutt_endwin (NULL); */ filterpid = mutt_create_filter_fd (DisplayFilter, &fpout, NULL, NULL, -1, fileno(fpfilterout), -1); if (filterpid < 0) { mutt_error (_("Cannot create display filter")); safe_fclose (&fpfilterout); unlink (tempfile); return 0; } } if (!Pager || mutt_strcmp (Pager, "builtin") == 0) builtin = 1; else { struct hdr_format_info hfi; hfi.ctx = Context; hfi.pager_progress = ExtPagerProgress; hfi.hdr = cur; mutt_make_string_info (buf, sizeof (buf), NONULL(PagerFmt), &hfi, M_FORMAT_MAKEPRINT); fputs (buf, fpout); fputs ("\n\n", fpout); } res = mutt_copy_message (fpout, Context, cur, cmflags, (option (OPTWEED) ? (CH_WEED | CH_REORDER) : 0) | CH_DECODE | CH_FROM | CH_DISPLAY); if ((safe_fclose (&fpout) != 0 && errno != EPIPE) || res < 0) { mutt_error (_("Could not copy message")); if (fpfilterout != NULL) { mutt_wait_filter (filterpid); safe_fclose (&fpfilterout); } mutt_unlink (tempfile); return 0; } if (fpfilterout != NULL && mutt_wait_filter (filterpid) != 0) mutt_any_key_to_continue (NULL); safe_fclose (&fpfilterout); /* XXX - check result? */ if (WithCrypto) { /* update crypto information for this message */ cur->security &= ~(GOODSIGN|BADSIGN); cur->security |= crypt_query (cur->content); /* Remove color cache for this message, in case there are color patterns for both ~g and ~V */ cur->pair = 0; } if (builtin) { pager_t info; if (WithCrypto && (cur->security & APPLICATION_SMIME) && (cmflags & M_CM_VERIFY)) { if (cur->security & GOODSIGN) { if (!crypt_smime_verify_sender(cur)) mutt_message ( _("S/MIME signature successfully verified.")); else mutt_error ( _("S/MIME certificate owner does not match sender.")); } else if (cur->security & PARTSIGN) mutt_message (_("Warning: Part of this message has not been signed.")); else if (cur->security & SIGN || cur->security & BADSIGN) mutt_error ( _("S/MIME signature could NOT be verified.")); } if (WithCrypto && (cur->security & APPLICATION_PGP) && (cmflags & M_CM_VERIFY)) { if (cur->security & GOODSIGN) mutt_message (_("PGP signature successfully verified.")); else if (cur->security & PARTSIGN) mutt_message (_("Warning: Part of this message has not been signed.")); else if (cur->security & SIGN) mutt_message (_("PGP signature could NOT be verified.")); } /* Invoke the builtin pager */ memset (&info, 0, sizeof (pager_t)); info.hdr = cur; info.ctx = Context; rc = mutt_pager (NULL, tempfile, M_PAGER_MESSAGE, &info); } else { int r; mutt_endwin (NULL); snprintf (buf, sizeof (buf), "%s %s", NONULL(Pager), tempfile); if ((r = mutt_system (buf)) == -1) mutt_error (_("Error running \"%s\"!"), buf); unlink (tempfile); if (!option (OPTNOCURSES)) keypad (stdscr, TRUE); if (r != -1) mutt_set_flag (Context, cur, M_READ, 1); if (r != -1 && option (OPTPROMPTAFTER)) { mutt_unget_event (mutt_any_key_to_continue _("Command: "), 0); rc = km_dokey (MENU_PAGER); } else rc = 0; } return rc; }
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); }
static int edit_one_message (CONTEXT *ctx, HEADER *cur) { char tmp[_POSIX_PATH_MAX]; char buff[STRING]; int omagic; int oerrno; int rc; unsigned short o_read; unsigned short o_old; int of, cf; CONTEXT tmpctx; MESSAGE *msg; FILE *fp = NULL; struct stat sb; time_t mtime = 0; mutt_mktemp (tmp, sizeof (tmp)); omagic = DefaultMagic; DefaultMagic = MUTT_MBOX; rc = (mx_open_mailbox (tmp, MUTT_NEWFOLDER, &tmpctx) == NULL) ? -1 : 0; DefaultMagic = omagic; if (rc == -1) { mutt_error (_("could not create temporary folder: %s"), strerror (errno)); return -1; } rc = mutt_append_message (&tmpctx, ctx, cur, 0, CH_NOLEN | ((ctx->magic == MUTT_MBOX || ctx->magic == MUTT_MMDF) ? 0 : CH_NOSTATUS)); oerrno = errno; mx_close_mailbox (&tmpctx, NULL); if (rc == -1) { mutt_error (_("could not write temporary mail folder: %s"), strerror (oerrno)); goto bail; } if ((rc = stat (tmp, &sb)) == -1) { mutt_error (_("Can't stat %s: %s"), tmp, strerror (errno)); goto bail; } /* * 2002-09-05 [email protected] * The file the user is going to edit is not a real mbox, so we need to * truncate the last newline in the temp file, which is logically part of * the message separator, and not the body of the message. If we fail to * remove it, the message will grow by one line each time the user edits * the message. */ if (sb.st_size != 0 && truncate (tmp, sb.st_size - 1) == -1) { mutt_error (_("could not truncate temporary mail folder: %s"), strerror (errno)); goto bail; } mtime = mutt_decrease_mtime (tmp, &sb); mutt_edit_file (NONULL(Editor), tmp); if ((rc = stat (tmp, &sb)) == -1) { mutt_error (_("Can't stat %s: %s"), tmp, strerror (errno)); goto bail; } if (sb.st_size == 0) { mutt_message (_("Message file is empty!")); rc = 1; goto bail; } if (sb.st_mtime == mtime) { mutt_message (_("Message not modified!")); rc = 1; goto bail; } if ((fp = fopen (tmp, "r")) == NULL) { rc = -1; mutt_error (_("Can't open message file: %s"), strerror (errno)); goto bail; } if (mx_open_mailbox (ctx->path, MUTT_APPEND, &tmpctx) == NULL) { rc = -1; /* L10N: %s is from strerror(errno) */ mutt_error (_("Can't append to folder: %s"), strerror (errno)); goto bail; } of = 0; cf = ((tmpctx.magic == MUTT_MBOX || tmpctx.magic == MUTT_MMDF) ? 0 : CH_NOSTATUS); if (fgets (buff, sizeof (buff), fp) && is_from (buff, NULL, 0, NULL)) { if (tmpctx.magic == MUTT_MBOX || tmpctx.magic == MUTT_MMDF) cf = CH_FROM | CH_FORCE_FROM; } else of = MUTT_ADD_FROM; /* * XXX - we have to play games with the message flags to avoid * problematic behavior with maildir folders. * */ o_read = cur->read; o_old = cur->old; cur->read = cur->old = 0; msg = mx_open_new_message (&tmpctx, cur, of); cur->read = o_read; cur->old = o_old; if (msg == NULL) { mutt_error (_("Can't append to folder: %s"), strerror (errno)); mx_close_mailbox (&tmpctx, NULL); goto bail; } if ((rc = mutt_copy_hdr (fp, msg->fp, 0, sb.st_size, CH_NOLEN | cf, NULL)) == 0) { fputc ('\n', msg->fp); rc = mutt_copy_stream (fp, msg->fp); } rc = mx_commit_message (msg, &tmpctx); mx_close_message (&tmpctx, &msg); mx_close_mailbox (&tmpctx, NULL); bail: if (fp) safe_fclose (&fp); if (rc >= 0) unlink (tmp); if (rc == 0) { mutt_set_flag (Context, cur, MUTT_DELETE, 1); mutt_set_flag (Context, cur, MUTT_PURGE, 1); mutt_set_flag (Context, cur, MUTT_READ, 1); if (option (OPTDELETEUNTAG)) mutt_set_flag (Context, cur, MUTT_TAG, 0); } else if (rc == -1) mutt_message (_("Error. Preserving temporary file: %s"), tmp); return rc; }
int imap_fetch_message (CONTEXT *ctx, MESSAGE *msg, int msgno) { IMAP_DATA* idata; HEADER* h; ENVELOPE* newenv; char buf[LONG_STRING]; char path[_POSIX_PATH_MAX]; char *pc; long bytes; progress_t progressbar; int uid; int cacheno; IMAP_CACHE *cache; int read; int rc; /* Sam's weird courier server returns an OK response even when FETCH * fails. Thanks Sam. */ short fetched = 0; idata = (IMAP_DATA*) ctx->data; h = ctx->hdrs[msgno]; if ((msg->fp = msg_cache_get (idata, h))) { if (HEADER_DATA(h)->parsed) return 0; else goto parsemsg; } /* we still do some caching even if imap_cachedir is unset */ /* see if we already have the message in our cache */ cacheno = HEADER_DATA(h)->uid % IMAP_CACHE_LEN; cache = &idata->cache[cacheno]; if (cache->path) { /* don't treat cache errors as fatal, just fall back. */ if (cache->uid == HEADER_DATA(h)->uid && (msg->fp = fopen (cache->path, "r"))) return 0; else { unlink (cache->path); FREE (&cache->path); } } if (!isendwin()) mutt_message _("Fetching message..."); if (!(msg->fp = msg_cache_put (idata, h))) { cache->uid = HEADER_DATA(h)->uid; mutt_mktemp (path, sizeof (path)); cache->path = safe_strdup (path); if (!(msg->fp = safe_fopen (path, "w+"))) { FREE (&cache->path); return -1; } } /* mark this header as currently inactive so the command handler won't * also try to update it. HACK until all this code can be moved into the * command handler */ h->active = 0; snprintf (buf, sizeof (buf), "UID FETCH %u %s", HEADER_DATA(h)->uid, (mutt_bit_isset (idata->capabilities, IMAP4REV1) ? (option (OPTIMAPPEEK) ? "BODY.PEEK[]" : "BODY[]") : "RFC822")); imap_cmd_start (idata, buf); do { if ((rc = imap_cmd_step (idata)) != IMAP_CMD_CONTINUE) break; pc = idata->buf; pc = imap_next_word (pc); pc = imap_next_word (pc); if (!ascii_strncasecmp ("FETCH", pc, 5)) { while (*pc) { pc = imap_next_word (pc); if (pc[0] == '(') pc++; if (ascii_strncasecmp ("UID", pc, 3) == 0) { pc = imap_next_word (pc); uid = atoi (pc); if (uid != HEADER_DATA(h)->uid) mutt_error (_("The message index is incorrect. Try reopening the mailbox.")); } else if ((ascii_strncasecmp ("RFC822", pc, 6) == 0) || (ascii_strncasecmp ("BODY[]", pc, 6) == 0)) { pc = imap_next_word (pc); if (imap_get_literal_count(pc, &bytes) < 0) { imap_error ("imap_fetch_message()", buf); goto bail; } mutt_progress_init (&progressbar, _("Fetching message..."), MUTT_PROGRESS_SIZE, NetInc, bytes); if (imap_read_literal (msg->fp, idata, bytes, &progressbar) < 0) goto bail; /* pick up trailing line */ if ((rc = imap_cmd_step (idata)) != IMAP_CMD_CONTINUE) goto bail; pc = idata->buf; fetched = 1; } /* UW-IMAP will provide a FLAGS update here if the FETCH causes a * change (eg from \Unseen to \Seen). * Uncommitted changes in mutt take precedence. If we decide to * incrementally update flags later, this won't stop us syncing */ else if ((ascii_strncasecmp ("FLAGS", pc, 5) == 0) && !h->changed) { if ((pc = imap_set_flags (idata, h, pc)) == NULL) goto bail; } } } } while (rc == IMAP_CMD_CONTINUE); /* see comment before command start. */ h->active = 1; fflush (msg->fp); if (ferror (msg->fp)) { mutt_perror (cache->path); goto bail; } if (rc != IMAP_CMD_OK) goto bail; if (!fetched || !imap_code (idata->buf)) goto bail; msg_cache_commit (idata, h); parsemsg: /* Update the header information. Previously, we only downloaded a * portion of the headers, those required for the main display. */ rewind (msg->fp); /* It may be that the Status header indicates a message is read, but the * IMAP server doesn't know the message has been \Seen. So we capture * the server's notion of 'read' and if it differs from the message info * picked up in mutt_read_rfc822_header, we mark the message (and context * changed). Another possibility: ignore Status on IMAP?*/ read = h->read; newenv = mutt_read_rfc822_header (msg->fp, h, 0, 0); mutt_merge_envelopes(h->env, &newenv); /* see above. We want the new status in h->read, so we unset it manually * and let mutt_set_flag set it correctly, updating context. */ if (read != h->read) { h->read = read; mutt_set_flag (ctx, h, MUTT_NEW, read); } h->lines = 0; fgets (buf, sizeof (buf), msg->fp); while (!feof (msg->fp)) { h->lines++; fgets (buf, sizeof (buf), msg->fp); } h->content->length = ftell (msg->fp) - h->content->offset; /* This needs to be done in case this is a multipart message */ #if defined(HAVE_PGP) || defined(HAVE_SMIME) h->security = crypt_query (h->content); #endif mutt_clear_error(); rewind (msg->fp); HEADER_DATA(h)->parsed = 1; return 0; bail: safe_fclose (&msg->fp); imap_cache_del (idata, h); if (cache->path) { unlink (cache->path); FREE (&cache->path); } return -1; }
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; }
/* fetch message from POP server */ int pop_fetch_message(MESSAGE *msg, CONTEXT *ctx, int msgno) { int ret; void *uidl; char buf[LONG_STRING]; char path[_POSIX_PATH_MAX]; progress_t progressbar; POP_DATA *pop_data = (POP_DATA *)ctx->data; POP_CACHE *cache; HEADER *h = ctx->hdrs[msgno]; unsigned short bcache = 1; /* see if we already have the message in body cache */ if ((msg->fp = mutt_bcache_get(pop_data->bcache, h->data))) return 0; /* * see if we already have the message in our cache in * case $message_cachedir is unset */ cache = &pop_data->cache[h->index % POP_CACHE_LEN]; if (cache->path) { if (cache->index == h->index) { /* yes, so just return a pointer to the message */ msg->fp = fopen(cache->path, "r"); if (msg->fp) return 0; mutt_perror(cache->path); mutt_sleep(2); return -1; } else { /* clear the previous entry */ unlink(cache->path); safe_free(&cache->path); } } FOREVER { if (pop_reconnect(ctx) < 0) return -1; /* verify that massage index is correct */ if (h->refno < 0) { mutt_error _( "The message index is incorrect. Try reopening the mailbox."); mutt_sleep(2); return -1; } mutt_progress_init(&progressbar, _( "Fetching message..."), M_PROGRESS_SIZE, NetInc, h->content->length + h->content->offset - 1); /* see if we can put in body cache; use our cache as fallback */ if (!(msg->fp = mutt_bcache_put(pop_data->bcache, h->data, 1))) { /* no */ bcache = 0; mutt_mktemp(path, sizeof(path)); if (!(msg->fp = safe_fopen(path, "w+"))) { mutt_perror(path); mutt_sleep(2); return -1; } } snprintf(buf, sizeof(buf), "RETR %d\r\n", h->refno); ret = pop_fetch_data(pop_data, buf, &progressbar, fetch_message, msg->fp); if (ret == 0) break; safe_fclose(&msg->fp); /* if RETR failed (e.g. connection closed), be sure to remove either * the file in bcache or from POP's own cache since the next iteration * of the loop will re-attempt to put() the message */ if (!bcache) unlink(path); if (ret == -2) { mutt_error("%s", pop_data->err_msg); mutt_sleep(2); return -1; } if (ret == -3) { mutt_error _("Can't write message to temporary file!"); mutt_sleep(2); return -1; } } /* Update the header information. Previously, we only downloaded a * portion of the headers, those required for the main display. */ if (bcache) mutt_bcache_commit(pop_data->bcache, h->data); else { cache->index = h->index; cache->path = safe_strdup(path); } rewind(msg->fp); uidl = h->data; /* we replace envelop, key in subj_hash has to be updated as well */ if (ctx->subj_hash && h->env->real_subj) hash_delete(ctx->subj_hash, h->env->real_subj, h, NULL); mutt_free_envelope(&h->env); h->env = mutt_read_rfc822_header(msg->fp, h, 0, 0); if (ctx->subj_hash && h->env->real_subj) hash_insert(ctx->subj_hash, h->env->real_subj, h, 1); h->data = uidl; h->lines = 0; fgets(buf, sizeof(buf), msg->fp); while (!feof(msg->fp)) { ctx->hdrs[msgno]->lines++; fgets(buf, sizeof(buf), msg->fp); } h->content->length = ftello(msg->fp) - h->content->offset; /* This needs to be done in case this is a multipart message */ if (!WithCrypto) h->security = crypt_query(h->content); mutt_clear_error(); rewind(msg->fp); return 0; }
static int send_message (HEADER *msg) { char tempfile[_POSIX_PATH_MAX]; FILE *tempfp; int i; #ifdef USE_SMTP short old_write_bcc; #endif /* Write out the message in MIME form. */ mutt_mktemp (tempfile, sizeof (tempfile)); if ((tempfp = safe_fopen (tempfile, "w")) == NULL) return (-1); #ifdef USE_SMTP old_write_bcc = option (OPTWRITEBCC); if (SmtpUrl) unset_option (OPTWRITEBCC); #endif #ifdef MIXMASTER mutt_write_rfc822_header (tempfp, msg->env, msg->content, 0, msg->chain ? 1 : 0); #endif #ifndef MIXMASTER mutt_write_rfc822_header (tempfp, msg->env, msg->content, 0, 0); #endif #ifdef USE_SMTP if (old_write_bcc) set_option (OPTWRITEBCC); #endif fputc ('\n', tempfp); /* tie off the header. */ if ((mutt_write_mime_body (msg->content, tempfp) == -1)) { safe_fclose (&tempfp); unlink (tempfile); return (-1); } if (fclose (tempfp) != 0) { mutt_perror (tempfile); unlink (tempfile); return (-1); } #ifdef MIXMASTER if (msg->chain) return mix_send_message (msg->chain, tempfile); #endif #if USE_SMTP if (SmtpUrl) return mutt_smtp_send (msg->env->from, msg->env->to, msg->env->cc, msg->env->bcc, tempfile, (msg->content->encoding == ENC8BIT)); #endif /* USE_SMTP */ i = mutt_invoke_sendmail (msg->env->from, msg->env->to, msg->env->cc, msg->env->bcc, tempfile, (msg->content->encoding == ENC8BIT)); return (i); }
BODY *pgp_make_key_attachment (char *tempf) { BODY *att; char buff[LONG_STRING]; char tempfb[_POSIX_PATH_MAX], tmp[STRING]; FILE *tempfp; FILE *devnull; struct stat sb; pid_t thepid; pgp_key_t key; unset_option (OPTPGPCHECKTRUST); key = pgp_ask_for_key (_("Please enter the key ID: "), NULL, 0, PGP_PUBRING); if (!key) return NULL; snprintf (tmp, sizeof (tmp), "0x%s", pgp_fpr_or_lkeyid (pgp_principal_key (key))); pgp_free_key (&key); if (!tempf) { mutt_mktemp (tempfb, sizeof (tempfb)); tempf = tempfb; } if ((tempfp = safe_fopen (tempf, tempf == tempfb ? "w" : "a")) == NULL) { mutt_perror _("Can't create temporary file"); return NULL; } if ((devnull = fopen ("/dev/null", "w")) == NULL) /* __FOPEN_CHECKED__ */ { mutt_perror _("Can't open /dev/null"); safe_fclose (&tempfp); if (tempf == tempfb) unlink (tempf); return NULL; } mutt_message _("Invoking PGP..."); if ((thepid = pgp_invoke_export (NULL, NULL, NULL, -1, fileno (tempfp), fileno (devnull), tmp)) == -1) { mutt_perror _("Can't create filter"); unlink (tempf); safe_fclose (&tempfp); safe_fclose (&devnull); return NULL; } mutt_wait_filter (thepid); safe_fclose (&tempfp); safe_fclose (&devnull); att = mutt_new_body (); att->filename = safe_strdup (tempf); att->unlink = 1; att->use_disp = 0; att->type = TYPEAPPLICATION; att->subtype = safe_strdup ("pgp-keys"); snprintf (buff, sizeof (buff), _("PGP Key %s."), tmp); att->description = safe_strdup (buff); mutt_update_encoding (att); stat (tempf, &sb); att->length = sb.st_size; return att; }
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); }