/** * mh_mbox_open_append - Implements MxOps::mbox_open_append() */ static int mh_mbox_open_append(struct Mailbox *m, OpenMailboxFlags flags) { if (!m) return -1; if (!(flags & MUTT_APPENDNEW)) { return 0; } if (mkdir(m->path, S_IRWXU)) { mutt_perror(m->path); return -1; } char tmp[PATH_MAX]; snprintf(tmp, sizeof(tmp), "%s/.mh_sequences", m->path); const int i = creat(tmp, S_IRWXU); if (i == -1) { mutt_perror(tmp); rmdir(m->path); return -1; } close(i); return 0; }
/** * mbox_mbox_open - Implements MxOps::mbox_open() */ static int mbox_mbox_open(struct Mailbox *m) { if (init_mailbox(m) != 0) return -1; struct MboxAccountData *adata = mbox_adata_get(m); if (!adata) return -1; adata->fp = fopen(m->path, "r+"); if (!adata->fp) { mutt_perror(m->path); return -1; } mutt_sig_block(); if (mbox_lock_mailbox(m, false, true) == -1) { mutt_sig_unblock(); return -1; } int rc; if (m->magic == MUTT_MBOX) rc = mbox_parse_mailbox(m); else if (m->magic == MUTT_MMDF) rc = mmdf_parse_mailbox(m); else rc = -1; mutt_file_touch_atime(fileno(adata->fp)); mbox_unlock_mailbox(m); mutt_sig_unblock(); return rc; }
/** * lock_realpath - Try to lock the ctx->realpath * @param m Mailbox to lock * @param excl Lock exclusively? * @retval true Success (locked or readonly) * @retval false Error (can't lock the file) * * Try to (exclusively) lock the mailbox. If we succeed, then we mark the * mailbox as locked. If we fail, but we didn't want exclusive rights, then * the mailbox will be marked readonly. */ static bool lock_realpath(struct Mailbox *m, bool excl) { if (!m || !m->compress_info) return false; struct CompressInfo *ci = m->compress_info; if (ci->locked) return true; if (excl) ci->fp_lock = fopen(m->realpath, "a"); else ci->fp_lock = fopen(m->realpath, "r"); if (!ci->fp_lock) { mutt_perror(m->realpath); return false; } int r = mutt_file_lock(fileno(ci->fp_lock), excl, true); if (r == 0) ci->locked = true; else if (excl) { mutt_file_fclose(&ci->fp_lock); m->readonly = true; return true; } return r == 0; }
static int mh_mkstemp (CONTEXT *dest, FILE **fp, char **tgt) { int fd; char path[_POSIX_PATH_MAX]; FOREVER { snprintf (path, _POSIX_PATH_MAX, "%s/.mutt-%s-%d-%d", dest->path, NONULL (Hostname), (int) getpid (), Counter++); if ((fd = open (path, O_WRONLY | O_EXCL | O_CREAT, 0600)) == -1) { if (errno != EEXIST) { mutt_perror (path); return -1; } } else { *tgt = safe_strdup (path); break; } } if ((*fp = fdopen (fd, "w")) == NULL) { FREE (tgt); close (fd); unlink (path); return (-1); } return 0; }
/* open a mbox or mmdf style mailbox */ int mbox_open_mailbox(CONTEXT *ctx) { int rc; if ((ctx->fp = fopen(ctx->path, "r")) == NULL) { mutt_perror(ctx->path); return -1; } mutt_block_signals(); if (mbox_lock_mailbox(ctx, 0, 1) == -1) { mutt_unblock_signals(); return -1; } if (ctx->magic == M_MBOX) rc = mbox_parse_mailbox(ctx); else if (ctx->magic == M_MMDF) rc = mmdf_parse_mailbox(ctx); else rc = -1; mbox_unlock_mailbox(ctx); mutt_unblock_signals(); return rc; }
/** * mbox_mbox_open_append - Implements MxOps::mbox_open_append() */ static int mbox_mbox_open_append(struct Mailbox *m, OpenMailboxFlags flags) { if (!m) return -1; if (init_mailbox(m) != 0) return -1; struct MboxAccountData *adata = mbox_adata_get(m); if (!adata) return -1; adata->fp = mutt_file_fopen(m->path, (flags & MUTT_NEWFOLDER) ? "w" : "a"); if (!adata->fp) { mutt_perror(m->path); return -1; } if (mbox_lock_mailbox(m, true, true) != false) { mutt_error(_("Couldn't lock %s"), m->path); mutt_file_fclose(&adata->fp); return -1; } fseek(adata->fp, 0, SEEK_END); return 0; }
int mh_open_new_message (MESSAGE *msg, CONTEXT *dest, HEADER *hdr) { int fd; char path[_POSIX_PATH_MAX]; FOREVER { snprintf (path, _POSIX_PATH_MAX, "%s/.mutt-%s-%d-%d", dest->path, NONULL (Hostname), (int) getpid (), Counter++); if ((fd = open (path, O_WRONLY | O_EXCL | O_CREAT, 0600)) == -1) { if (errno != EEXIST) { mutt_perror (path); return -1; } } else { msg->path = safe_strdup (path); break; } } if ((msg->fp = fdopen (fd, "w")) == NULL) { FREE (&msg->path); close (fd); unlink (path); return (-1); } return 0; }
static int maildir_sync_message (CONTEXT *ctx, int msgno) { HEADER *h = ctx->hdrs[msgno]; if (h->attach_del) { /* when doing attachment deletion, fall back to the MH case. */ if (mh_rewrite_message (ctx, msgno) != 0) return (-1); } else { /* we just have to rename the file. */ char newpath[_POSIX_PATH_MAX]; char partpath[_POSIX_PATH_MAX]; char fullpath[_POSIX_PATH_MAX]; char oldpath[_POSIX_PATH_MAX]; char suffix[16]; char *p; if ((p = strrchr (h->path, '/')) == NULL) { dprint (1, (debugfile, "maildir_sync_message: %s: unable to find subdir!\n", h->path)); return (-1); } p++; strfcpy (newpath, p, sizeof (newpath)); /* kill the previous flags */ if ((p = strchr (newpath, ':')) != NULL) *p = 0; maildir_flags (suffix, sizeof (suffix), h); snprintf (partpath, sizeof (partpath), "%s/%s%s", (h->read || h->old) ? "cur" : "new", newpath, suffix); snprintf (fullpath, sizeof (fullpath), "%s/%s", ctx->path, partpath); snprintf (oldpath, sizeof (oldpath), "%s/%s", ctx->path, h->path); if (mutt_strcmp (fullpath, oldpath) == 0) { /* message hasn't really changed */ return 0; } /* record that the message is possibly marked as trashed on disk */ h->trash = h->deleted; if (rename (oldpath, fullpath) != 0) { mutt_perror ("rename"); return (-1); } mutt_str_replace (&h->path, partpath); } return (0); }
int maildir_open_new_message (MESSAGE *msg, CONTEXT *dest, HEADER *hdr) { int fd; char path[_POSIX_PATH_MAX]; char suffix[16]; char subdir[16]; if (hdr) { short deleted = hdr->deleted; hdr->deleted = 0; maildir_flags (suffix, sizeof (suffix), hdr); hdr->deleted = deleted; } else *suffix = '\0'; if (hdr && (hdr->read || hdr->old)) strfcpy (subdir, "cur", sizeof (subdir)); else strfcpy (subdir, "new", sizeof (subdir)); FOREVER { snprintf (path, _POSIX_PATH_MAX, "%s/tmp/%s.%ld.%d_%d.%s%s", dest->path, subdir, time (NULL), getpid (), Counter++, NONULL (Hostname), suffix); dprint (2, (debugfile, "maildir_open_new_message (): Trying %s.\n", path)); if ((fd = open (path, O_WRONLY | O_EXCL | O_CREAT, 0600)) == -1) { if (errno != EEXIST) { mutt_perror (path); return -1; } } else { dprint (2, (debugfile, "maildir_open_new_message (): Success.\n")); msg->path = safe_strdup (path); break; } } if ((msg->fp = fdopen (fd, "w")) == NULL) { FREE (&msg->path); close (fd); unlink (path); return (-1); } return 0; }
/* return 0 on success, -1 on failure */ int mutt_sync_compressed (CONTEXT * ctx) { char *cmd; int rc = 0; FILE *fp; COMPRESS_INFO *ci = (COMPRESS_INFO *) ctx->compressinfo; if (!ctx->quiet) mutt_message (_("Compressing %s..."), ctx->realpath); cmd = get_compression_cmd (ci->close, ctx); if (cmd == NULL) return (-1); if ((fp = fopen (ctx->realpath, "a")) == NULL) { mutt_perror (ctx->realpath); mem_free (&cmd); return (-1); } mutt_block_signals (); if (mbox_lock_compressed (ctx, fp, 1, 1) == -1) { fclose (fp); mutt_unblock_signals (); mutt_error _("Unable to lock mailbox!"); store_size (ctx); mem_free (&cmd); return (-1); } debug_print (2, ("CompressCommand: '%s'\n", cmd)); endwin (); fflush (stdout); sprintf (echo_cmd, _("echo Compressing %s..."), ctx->realpath); mutt_system (echo_cmd); if (mutt_system (cmd)) { mutt_any_key_to_continue (NULL); mutt_error (_ ("%s: Error compressing mailbox! Original mailbox deleted, uncompressed one kept!\n"), ctx->path); rc = -1; } mbox_unlock_compressed (ctx, fp); mutt_unblock_signals (); fclose (fp); mem_free (&cmd); store_size (ctx); return (rc); }
/* returns 1 if OK to proceed, 0 to abort */ int mutt_save_confirm (const char *s, struct stat *st) { char tmp[_POSIX_PATH_MAX]; int ret = 1; int magic = 0; magic = mx_get_magic (s); if (stat (s, st) != -1) { if (magic == -1) { mutt_error (_("%s is not a mailbox!"), s); return 0; } if (option (OPTCONFIRMAPPEND)) { snprintf (tmp, sizeof (tmp), _("Append messages to %s?"), s); if (mutt_yesorno (tmp, 1) < 1) ret = 0; } } else { #ifdef USE_IMAP if (magic != M_IMAP) #endif /* execute the block unconditionally if we don't use imap */ { st->st_mtime = 0; st->st_atime = 0; if (errno == ENOENT) { if (option (OPTCONFIRMCREATE)) { snprintf (tmp, sizeof (tmp), _("Create %s?"), s); if (mutt_yesorno (tmp, 1) < 1) ret = 0; } } else { mutt_perror (s); return 0; } } } CLEARLINE (LINES-1); return (ret); }
/** * mmdf_msg_commit - Implements MxOps::msg_commit() */ static int mmdf_msg_commit(struct Mailbox *m, struct Message *msg) { if (fputs(MMDF_SEP, msg->fp) == EOF) return -1; if ((fflush(msg->fp) == EOF) || (fsync(fileno(msg->fp)) == -1)) { mutt_perror(_("Can't write message")); return -1; } return 0; }
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); }
int maildir_commit_message (CONTEXT *ctx, MESSAGE *msg, HEADER *hdr) { char subdir[4]; char suffix[16]; char path[_POSIX_PATH_MAX]; char full[_POSIX_PATH_MAX]; char *s; if (safe_fclose (&msg->fp) != 0) return -1; /* extract the subdir */ s = strrchr (msg->path, '/') + 1; strfcpy (subdir, s, 4); /* extract the flags */ if ((s = strchr (s, ':'))) strfcpy (suffix, s, sizeof (suffix)); else suffix[0] = '\0'; /* construct a new file name. */ FOREVER { snprintf (path, _POSIX_PATH_MAX, "%s/%ld.%d_%d.%s%s", subdir, time (NULL), getpid(), Counter++, NONULL (Hostname), suffix); snprintf (full, _POSIX_PATH_MAX, "%s/%s", ctx->path, path); dprint (2, (debugfile, "maildir_commit_message (): renaming %s to %s.\n", msg->path, full)); if (safe_rename (msg->path, full) == 0) { if (hdr) mutt_str_replace (&hdr->path, path); FREE (&msg->path); return 0; } else if (errno != EEXIST) { mutt_perror (ctx->path); return -1; } } }
/** * socket_preconnect - Execute a command before opening a socket * @retval 0 Success * @retval >0 An errno, e.g. EPERM */ static int socket_preconnect(void) { if (!C_Preconnect) return 0; mutt_debug(LL_DEBUG2, "Executing preconnect: %s\n", C_Preconnect); const int rc = mutt_system(C_Preconnect); mutt_debug(LL_DEBUG2, "Preconnect result: %d\n", rc); if (rc != 0) { const int save_errno = errno; mutt_perror(_("Preconnect command failed")); return save_errno; } return 0; }
/** * crypt_write_signed - Write the message body/part * @param a Body to write * @param s State to use * @param tempfile File to write to * @retval 0 Success * @retval -1 Error * * Body/part A described by state S to the given TEMPFILE. */ int crypt_write_signed(struct Body *a, struct State *s, const char *tempfile) { FILE *fp = NULL; bool hadcr; size_t bytes; if (!WithCrypto) return -1; fp = mutt_file_fopen(tempfile, "w"); if (!fp) { mutt_perror(tempfile); return -1; } fseeko(s->fp_in, a->hdr_offset, SEEK_SET); bytes = a->length + a->offset - a->hdr_offset; hadcr = false; while (bytes > 0) { const int c = fgetc(s->fp_in); if (c == EOF) break; bytes--; if (c == '\r') hadcr = true; else { if ((c == '\n') && !hadcr) fputc('\r', fp); hadcr = false; } fputc(c, fp); } mutt_file_fclose(&fp); return 0; }
static int socket_preconnect (void) { int rc; int save_errno; if (mutt_strlen (Preconnect)) { dprint (2, (debugfile, "Executing preconnect: %s\n", Preconnect)); rc = mutt_system (Preconnect); dprint (2, (debugfile, "Preconnect result: %d\n", rc)); if (rc) { save_errno = errno; mutt_perror (_("Preconnect command failed.")); mutt_sleep (1); return save_errno; } } return 0; }
int mutt_get_tmp_attachment (BODY *a) { char type[STRING]; char tempfile[_POSIX_PATH_MAX]; rfc1524_entry *entry = rfc1524_new_entry(); FILE *fpin = NULL, *fpout = NULL; struct stat st; if(a->unlink) return 0; snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype); rfc1524_mailcap_lookup(a, type, entry, 0); rfc1524_expand_filename(entry->nametemplate, a->filename, tempfile, sizeof(tempfile)); rfc1524_free_entry(&entry); if(stat(a->filename, &st) == -1) return -1; if((fpin = fopen(a->filename, "r")) && (fpout = safe_fopen(tempfile, "w"))) /* __FOPEN_CHECKED__ */ { mutt_copy_stream (fpin, fpout); mutt_str_replace (&a->filename, tempfile); a->unlink = 1; if(a->stamp >= st.st_mtime) mutt_stamp_attachment(a); } else mutt_perror(fpin ? tempfile : a->filename); if(fpin) safe_fclose (&fpin); if(fpout) safe_fclose (&fpout); return a->unlink ? 0 : -1; }
static int _mh_commit_message (CONTEXT *ctx, MESSAGE *msg, HEADER *hdr, short updseq) { DIR *dirp; struct dirent *de; char *cp, *dep; unsigned int n, hi = 0; char path[_POSIX_PATH_MAX]; char tmp[16]; if (safe_fclose (&msg->fp) != 0) return -1; if ((dirp = opendir (ctx->path)) == NULL) { mutt_perror (ctx->path); return (-1); } /* figure out what the next message number is */ while ((de = readdir (dirp)) != NULL) { dep = de->d_name; if (*dep == ',') dep++; cp = dep; while (*cp) { if (!isdigit ((unsigned char) *cp)) break; cp++; } if (!*cp) { n = atoi (dep); if (n > hi) hi = n; } } closedir (dirp); /* * Now try to rename the file to the proper name. * * Note: We may have to try multiple times, until we find a free * slot. */ FOREVER { hi++; snprintf (tmp, sizeof (tmp), "%d", hi); snprintf (path, sizeof (path), "%s/%s", ctx->path, tmp); if (safe_rename (msg->path, path) == 0) { if (hdr) mutt_str_replace (&hdr->path, tmp); FREE (&msg->path); break; } else if (errno != EEXIST) { mutt_perror (ctx->path); return -1; } } if (updseq) mh_sequences_add_one (ctx, hi, !msg->flags.read, msg->flags.flagged, msg->flags.replied); return 0; }
/* return values: * * 1 message should be postponed * 0 normal exit * -1 abort message */ int mutt_compose_menu (HEADER *msg, /* structure for new message */ char *fcc, /* where to save a copy of the message */ size_t fcclen, HEADER *cur, /* current message */ int flags) { char helpstr[LONG_STRING]; char buf[LONG_STRING]; char fname[_POSIX_PATH_MAX]; MUTTMENU *menu; ATTACHPTR **idx = NULL; short idxlen = 0; short idxmax = 0; int i, close = 0; int r = -1; /* return value */ int op = 0; int loop = 1; int fccSet = 0; /* has the user edited the Fcc: field ? */ CONTEXT *ctx = NULL, *this = NULL; /* Sort, SortAux could be changed in mutt_index_menu() */ int oldSort, oldSortAux; struct stat st; mutt_attach_init (msg->content); idx = mutt_gen_attach_list (msg->content, -1, idx, &idxlen, &idxmax, 0, 1); menu = mutt_new_menu (MENU_COMPOSE); menu->offset = HDR_ATTACH; menu->max = idxlen; menu->make_entry = snd_entry; menu->tag = mutt_tag_attach; menu->data = idx; menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_COMPOSE, ComposeHelp); while (loop) { switch (op = mutt_menuLoop (menu)) { case OP_REDRAW: draw_envelope (msg, fcc); menu->offset = HDR_ATTACH; menu->pagelen = LINES - HDR_ATTACH - 2; break; case OP_COMPOSE_EDIT_FROM: menu->redraw = edit_address_list (HDR_FROM, &msg->env->from); mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_COMPOSE_EDIT_TO: menu->redraw = edit_address_list (HDR_TO, &msg->env->to); if (option (OPTCRYPTOPPORTUNISTICENCRYPT)) { crypt_opportunistic_encrypt (msg); redraw_crypt_lines (msg); } mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_COMPOSE_EDIT_BCC: menu->redraw = edit_address_list (HDR_BCC, &msg->env->bcc); if (option (OPTCRYPTOPPORTUNISTICENCRYPT)) { crypt_opportunistic_encrypt (msg); redraw_crypt_lines (msg); } mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_COMPOSE_EDIT_CC: menu->redraw = edit_address_list (HDR_CC, &msg->env->cc); if (option (OPTCRYPTOPPORTUNISTICENCRYPT)) { crypt_opportunistic_encrypt (msg); redraw_crypt_lines (msg); } mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_COMPOSE_EDIT_SUBJECT: if (msg->env->subject) strfcpy (buf, msg->env->subject, sizeof (buf)); else buf[0] = 0; if (mutt_get_field ("Subject: ", buf, sizeof (buf), 0) == 0) { mutt_str_replace (&msg->env->subject, buf); move (HDR_SUBJECT, HDR_XOFFSET); if (msg->env->subject) mutt_paddstr (W, msg->env->subject); else clrtoeol(); } mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_COMPOSE_EDIT_REPLY_TO: menu->redraw = edit_address_list (HDR_REPLYTO, &msg->env->reply_to); mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_COMPOSE_EDIT_FCC: strfcpy (buf, fcc, sizeof (buf)); if (mutt_get_field ("Fcc: ", buf, sizeof (buf), M_FILE | M_CLEAR) == 0) { strfcpy (fcc, buf, fcclen); mutt_pretty_mailbox (fcc, fcclen); move (HDR_FCC, HDR_XOFFSET); mutt_paddstr (W, fcc); fccSet = 1; } MAYBE_REDRAW (menu->redraw); mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_COMPOSE_EDIT_MESSAGE: if (Editor && (mutt_strcmp ("builtin", Editor) != 0) && !option (OPTEDITHDRS)) { mutt_edit_file (Editor, msg->content->filename); mutt_update_encoding (msg->content); menu->redraw = REDRAW_FULL; mutt_message_hook (NULL, msg, M_SEND2HOOK); break; } /* fall through */ case OP_COMPOSE_EDIT_HEADERS: if (mutt_strcmp ("builtin", Editor) != 0 && (op == OP_COMPOSE_EDIT_HEADERS || (op == OP_COMPOSE_EDIT_MESSAGE && option (OPTEDITHDRS)))) { char *tag = NULL, *err = NULL; mutt_env_to_local (msg->env); mutt_edit_headers (NONULL (Editor), msg->content->filename, msg, fcc, fcclen); if (mutt_env_to_intl (msg->env, &tag, &err)) { mutt_error (_("Bad IDN in \"%s\": '%s'"), tag, err); FREE (&err); } if (option (OPTCRYPTOPPORTUNISTICENCRYPT)) crypt_opportunistic_encrypt (msg); } else { /* this is grouped with OP_COMPOSE_EDIT_HEADERS because the attachment list could change if the user invokes ~v to edit the message with headers, in which we need to execute the code below to regenerate the index array */ mutt_builtin_editor (msg->content->filename, msg, cur); } mutt_update_encoding (msg->content); /* attachments may have been added */ if (idxlen && idx[idxlen - 1]->content->next) { for (i = 0; i < idxlen; i++) { FREE (&idx[i]->tree); FREE (&idx[i]); } idxlen = 0; idx = mutt_gen_attach_list (msg->content, -1, idx, &idxlen, &idxmax, 0, 1); menu->data = idx; menu->max = idxlen; } menu->redraw = REDRAW_FULL; mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_COMPOSE_ATTACH_KEY: if (!(WithCrypto & APPLICATION_PGP)) break; if (idxlen == idxmax) { safe_realloc (&idx, sizeof (ATTACHPTR *) * (idxmax += 5)); menu->data = idx; } idx[idxlen] = (ATTACHPTR *) safe_calloc (1, sizeof (ATTACHPTR)); if ((idx[idxlen]->content = crypt_pgp_make_key_attachment(NULL)) != NULL) { update_idx (menu, idx, idxlen++); menu->redraw |= REDRAW_INDEX; } else FREE (&idx[idxlen]); menu->redraw |= REDRAW_STATUS; if (option(OPTNEEDREDRAW)) { menu->redraw = REDRAW_FULL; unset_option(OPTNEEDREDRAW); } mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_COMPOSE_ATTACH_FILE: { char *prompt, **files; int error, numfiles; fname[0] = 0; prompt = _("Attach file"); numfiles = 0; files = NULL; if (_mutt_enter_fname (prompt, fname, sizeof (fname), &menu->redraw, 0, 1, &files, &numfiles) == -1 || *fname == '\0') break; if (idxlen + numfiles >= idxmax) { safe_realloc (&idx, sizeof (ATTACHPTR *) * (idxmax += 5 + numfiles)); menu->data = idx; } error = 0; if (numfiles > 1) mutt_message _("Attaching selected files..."); for (i = 0; i < numfiles; i++) { char *att = files[i]; idx[idxlen] = (ATTACHPTR *) safe_calloc (1, sizeof (ATTACHPTR)); idx[idxlen]->unowned = 1; idx[idxlen]->content = mutt_make_file_attach (att); if (idx[idxlen]->content != NULL) update_idx (menu, idx, idxlen++); else { error = 1; mutt_error (_("Unable to attach %s!"), att); FREE (&idx[idxlen]); } } FREE (&files); if (!error) mutt_clear_error (); menu->redraw |= REDRAW_INDEX | REDRAW_STATUS; } mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_COMPOSE_ATTACH_MESSAGE: { char *prompt; HEADER *h; fname[0] = 0; prompt = _("Open mailbox to attach message from"); if (Context) { strfcpy (fname, NONULL (Context->path), sizeof (fname)); mutt_pretty_mailbox (fname, sizeof (fname)); } if (mutt_enter_fname (prompt, fname, sizeof (fname), &menu->redraw, 1) == -1 || !fname[0]) break; mutt_expand_path (fname, sizeof (fname)); #ifdef USE_IMAP if (!mx_is_imap (fname)) #endif #ifdef USE_POP if (!mx_is_pop (fname)) #endif /* check to make sure the file exists and is readable */ if (access (fname, R_OK) == -1) { mutt_perror (fname); break; } menu->redraw = REDRAW_FULL; ctx = mx_open_mailbox (fname, M_READONLY, NULL); if (ctx == NULL) { mutt_error (_("Unable to open mailbox %s"), fname); break; } if (!ctx->msgcount) { mx_close_mailbox (ctx, NULL); FREE (&ctx); mutt_error _("No messages in that folder."); break; } this = Context; /* remember current folder and sort methods*/ oldSort = Sort; oldSortAux = SortAux; Context = ctx; set_option(OPTATTACHMSG); mutt_message _("Tag the messages you want to attach!"); close = mutt_index_menu (); unset_option(OPTATTACHMSG); if (!Context) { /* go back to the folder we started from */ Context = this; /* Restore old $sort and $sort_aux */ Sort = oldSort; SortAux = oldSortAux; menu->redraw |= REDRAW_INDEX | REDRAW_STATUS; break; } if (idxlen + Context->tagged >= idxmax) { safe_realloc (&idx, sizeof (ATTACHPTR *) * (idxmax += 5 + Context->tagged)); menu->data = idx; } for (i = 0; i < Context->msgcount; i++) { h = Context->hdrs[i]; if (h->tagged) { idx[idxlen] = (ATTACHPTR *) safe_calloc (1, sizeof (ATTACHPTR)); idx[idxlen]->content = mutt_make_message_attach (Context, h, 1); if (idx[idxlen]->content != NULL) update_idx (menu, idx, idxlen++); else { mutt_error _("Unable to attach!"); FREE (&idx[idxlen]); } } } menu->redraw |= REDRAW_FULL; if (close == OP_QUIT) mx_close_mailbox (Context, NULL); else mx_fastclose_mailbox (Context); FREE (&Context); /* go back to the folder we started from */ Context = this; /* Restore old $sort and $sort_aux */ Sort = oldSort; SortAux = oldSortAux; } mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_DELETE: CHECK_COUNT; if (idx[menu->current]->unowned) idx[menu->current]->content->unlink = 0; if (delete_attachment (menu, &idxlen, menu->current) == -1) break; mutt_update_tree (idx, idxlen); if (idxlen) { if (menu->current > idxlen - 1) menu->current = idxlen - 1; } else menu->current = 0; if (menu->current == 0) msg->content = idx[0]->content; menu->redraw |= REDRAW_STATUS; mutt_message_hook (NULL, msg, M_SEND2HOOK); break; #define CURRENT idx[menu->current]->content case OP_COMPOSE_TOGGLE_RECODE: { CHECK_COUNT; if (!mutt_is_text_part (CURRENT)) { mutt_error (_("Recoding only affects text attachments.")); break; } CURRENT->noconv = !CURRENT->noconv; if (CURRENT->noconv) mutt_message (_("The current attachment won't be converted.")); else mutt_message (_("The current attachment will be converted.")); menu->redraw = REDRAW_CURRENT; mutt_message_hook (NULL, msg, M_SEND2HOOK); break; } #undef CURRENT case OP_COMPOSE_EDIT_DESCRIPTION: CHECK_COUNT; strfcpy (buf, idx[menu->current]->content->description ? idx[menu->current]->content->description : "", sizeof (buf)); /* header names should not be translated */ if (mutt_get_field ("Description: ", buf, sizeof (buf), 0) == 0) { mutt_str_replace (&idx[menu->current]->content->description, buf); menu->redraw = REDRAW_CURRENT; } mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_COMPOSE_UPDATE_ENCODING: CHECK_COUNT; if (menu->tagprefix) { BODY *top; for (top = msg->content; top; top = top->next) { if (top->tagged) mutt_update_encoding (top); } menu->redraw = REDRAW_FULL; } else { mutt_update_encoding(idx[menu->current]->content); menu->redraw = REDRAW_CURRENT | REDRAW_STATUS; } mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_COMPOSE_TOGGLE_DISPOSITION: /* toggle the content-disposition between inline/attachment */ idx[menu->current]->content->disposition = (idx[menu->current]->content->disposition == DISPINLINE) ? DISPATTACH : DISPINLINE; menu->redraw = REDRAW_CURRENT; break; case OP_EDIT_TYPE: CHECK_COUNT; { mutt_edit_content_type (NULL, idx[menu->current]->content, NULL); /* this may have been a change to text/something */ mutt_update_encoding (idx[menu->current]->content); menu->redraw = REDRAW_CURRENT; } mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_COMPOSE_EDIT_ENCODING: CHECK_COUNT; strfcpy (buf, ENCODING (idx[menu->current]->content->encoding), sizeof (buf)); if (mutt_get_field ("Content-Transfer-Encoding: ", buf, sizeof (buf), 0) == 0 && buf[0]) { if ((i = mutt_check_encoding (buf)) != ENCOTHER && i != ENCUUENCODED) { idx[menu->current]->content->encoding = i; menu->redraw = REDRAW_CURRENT | REDRAW_STATUS; mutt_clear_error(); } else mutt_error _("Invalid encoding."); } mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_COMPOSE_SEND_MESSAGE: /* Note: We don't invoke send2-hook here, since we want to leave * users an opportunity to change settings from the ":" prompt. */ if(check_attachments(idx, idxlen) != 0) { menu->redraw = REDRAW_FULL; break; } #ifdef MIXMASTER if (msg->chain && mix_check_message (msg) != 0) break; #endif if (!fccSet && *fcc) { if ((i = query_quadoption (OPT_COPY, _("Save a copy of this message?"))) == -1) break; else if (i == M_NO) *fcc = 0; } loop = 0; r = 0; break; case OP_COMPOSE_EDIT_FILE: CHECK_COUNT; mutt_edit_file (NONULL(Editor), idx[menu->current]->content->filename); mutt_update_encoding (idx[menu->current]->content); menu->redraw = REDRAW_CURRENT | REDRAW_STATUS; mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_COMPOSE_TOGGLE_UNLINK: CHECK_COUNT; idx[menu->current]->content->unlink = !idx[menu->current]->content->unlink; #if 0 /* OPTRESOLVE is otherwise ignored on this menu. * Where's the bug? */ if (option (OPTRESOLVE) && menu->current + 1 < menu->max) menu->current++; # endif menu->redraw = REDRAW_INDEX; /* No send2hook since this doesn't change the message. */ break; case OP_COMPOSE_GET_ATTACHMENT: CHECK_COUNT; if(menu->tagprefix) { BODY *top; for(top = msg->content; top; top = top->next) { if(top->tagged) mutt_get_tmp_attachment(top); } menu->redraw = REDRAW_FULL; } else if (mutt_get_tmp_attachment(idx[menu->current]->content) == 0) menu->redraw = REDRAW_CURRENT; /* No send2hook since this doesn't change the message. */ break; case OP_COMPOSE_RENAME_FILE: CHECK_COUNT; strfcpy (fname, idx[menu->current]->content->filename, sizeof (fname)); mutt_pretty_mailbox (fname, sizeof (fname)); if (mutt_get_field (_("Rename to: "), fname, sizeof (fname), M_FILE) == 0 && fname[0]) { if (stat(idx[menu->current]->content->filename, &st) == -1) { /* L10N: "stat" is a system call. Do "man 2 stat" for more information. */ mutt_error (_("Can't stat %s: %s"), fname, strerror (errno)); break; } mutt_expand_path (fname, sizeof (fname)); if(mutt_rename_file (idx[menu->current]->content->filename, fname)) break; mutt_str_replace (&idx[menu->current]->content->filename, fname); menu->redraw = REDRAW_CURRENT; if(idx[menu->current]->content->stamp >= st.st_mtime) mutt_stamp_attachment(idx[menu->current]->content); } mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_COMPOSE_NEW_MIME: { char type[STRING]; char *p; int itype; FILE *fp; CLEARLINE (LINES-1); fname[0] = 0; if (mutt_get_field (_("New file: "), fname, sizeof (fname), M_FILE) != 0 || !fname[0]) continue; mutt_expand_path (fname, sizeof (fname)); /* Call to lookup_mime_type () ? maybe later */ type[0] = 0; if (mutt_get_field ("Content-Type: ", type, sizeof (type), 0) != 0 || !type[0]) continue; if (!(p = strchr (type, '/'))) { mutt_error _("Content-Type is of the form base/sub"); continue; } *p++ = 0; if ((itype = mutt_check_mime_type (type)) == TYPEOTHER) { mutt_error (_("Unknown Content-Type %s"), type); continue; } if (idxlen == idxmax) { safe_realloc (&idx, sizeof (ATTACHPTR *) * (idxmax += 5)); menu->data = idx; } idx[idxlen] = (ATTACHPTR *) safe_calloc (1, sizeof (ATTACHPTR)); /* Touch the file */ if (!(fp = safe_fopen (fname, "w"))) { mutt_error (_("Can't create file %s"), fname); FREE (&idx[idxlen]); continue; } safe_fclose (&fp); if ((idx[idxlen]->content = mutt_make_file_attach (fname)) == NULL) { mutt_error _("What we have here is a failure to make an attachment"); continue; } update_idx (menu, idx, idxlen++); idx[menu->current]->content->type = itype; mutt_str_replace (&idx[menu->current]->content->subtype, p); idx[menu->current]->content->unlink = 1; menu->redraw |= REDRAW_INDEX | REDRAW_STATUS; if (mutt_compose_attachment (idx[menu->current]->content)) { mutt_update_encoding (idx[menu->current]->content); menu->redraw = REDRAW_FULL; } } mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_COMPOSE_EDIT_MIME: CHECK_COUNT; if (mutt_edit_attachment (idx[menu->current]->content)) { mutt_update_encoding (idx[menu->current]->content); menu->redraw = REDRAW_FULL; } mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_VIEW_ATTACH: case OP_DISPLAY_HEADERS: CHECK_COUNT; mutt_attach_display_loop (menu, op, NULL, NULL, NULL, &idx, &idxlen, NULL, 0); menu->redraw = REDRAW_FULL; /* no send2hook, since this doesn't modify the message */ break; case OP_SAVE: CHECK_COUNT; mutt_save_attachment_list (NULL, menu->tagprefix, menu->tagprefix ? msg->content : idx[menu->current]->content, NULL, menu); MAYBE_REDRAW (menu->redraw); /* no send2hook, since this doesn't modify the message */ break; case OP_PRINT: CHECK_COUNT; mutt_print_attachment_list (NULL, menu->tagprefix, menu->tagprefix ? msg->content : idx[menu->current]->content); /* no send2hook, since this doesn't modify the message */ break; case OP_PIPE: case OP_FILTER: CHECK_COUNT; mutt_pipe_attachment_list (NULL, menu->tagprefix, menu->tagprefix ? msg->content : idx[menu->current]->content, op == OP_FILTER); if (op == OP_FILTER) /* cte might have changed */ menu->redraw = menu->tagprefix ? REDRAW_FULL : REDRAW_CURRENT; menu->redraw |= REDRAW_STATUS; mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_EXIT: if ((i = query_quadoption (OPT_POSTPONE, _("Postpone this message?"))) == M_NO) { for (i = 0; i < idxlen; i++) if (idx[i]->unowned) idx[i]->content->unlink = 0; if (!(flags & M_COMPOSE_NOFREEHEADER)) { while (idxlen-- > 0) { /* avoid freeing other attachments */ idx[idxlen]->content->next = NULL; idx[idxlen]->content->parts = NULL; mutt_free_body (&idx[idxlen]->content); FREE (&idx[idxlen]->tree); FREE (&idx[idxlen]); } FREE (&idx); idxlen = 0; idxmax = 0; } r = -1; loop = 0; break; } else if (i == -1) break; /* abort */ /* fall through to postpone! */ case OP_COMPOSE_POSTPONE_MESSAGE: if(check_attachments(idx, idxlen) != 0) { menu->redraw = REDRAW_FULL; break; } loop = 0; r = 1; break; case OP_COMPOSE_ISPELL: endwin (); snprintf (buf, sizeof (buf), "%s -x %s", NONULL(Ispell), msg->content->filename); if (mutt_system (buf) == -1) mutt_error (_("Error running \"%s\"!"), buf); else { mutt_update_encoding (msg->content); menu->redraw |= REDRAW_STATUS; } break; case OP_COMPOSE_WRITE_MESSAGE: fname[0] = '\0'; if (Context) { strfcpy (fname, NONULL (Context->path), sizeof (fname)); mutt_pretty_mailbox (fname, sizeof (fname)); } if (idxlen) msg->content = idx[0]->content; if (mutt_enter_fname (_("Write message to mailbox"), fname, sizeof (fname), &menu->redraw, 1) != -1 && fname[0]) { mutt_message (_("Writing message to %s ..."), fname); mutt_expand_path (fname, sizeof (fname)); if (msg->content->next) msg->content = mutt_make_multipart (msg->content); if (mutt_write_fcc (fname, msg, NULL, 0, NULL) < 0) msg->content = mutt_remove_multipart (msg->content); else mutt_message _("Message written."); } break; case OP_COMPOSE_PGP_MENU: if (!(WithCrypto & APPLICATION_PGP)) break; if ((WithCrypto & APPLICATION_SMIME) && (msg->security & APPLICATION_SMIME)) { if (msg->security & (ENCRYPT | SIGN)) { if (mutt_yesorno (_("S/MIME already selected. Clear & continue ? "), M_YES) != M_YES) { mutt_clear_error (); break; } msg->security &= ~(ENCRYPT | SIGN); } msg->security &= ~APPLICATION_SMIME; msg->security |= APPLICATION_PGP; crypt_opportunistic_encrypt (msg); redraw_crypt_lines (msg); } msg->security = crypt_pgp_send_menu (msg, &menu->redraw); redraw_crypt_lines (msg); mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_FORGET_PASSPHRASE: crypt_forget_passphrase (); break; case OP_COMPOSE_SMIME_MENU: if (!(WithCrypto & APPLICATION_SMIME)) break; if ((WithCrypto & APPLICATION_PGP) && (msg->security & APPLICATION_PGP)) { if (msg->security & (ENCRYPT | SIGN)) { if (mutt_yesorno (_("PGP already selected. Clear & continue ? "), M_YES) != M_YES) { mutt_clear_error (); break; } msg->security &= ~(ENCRYPT | SIGN); } msg->security &= ~APPLICATION_PGP; msg->security |= APPLICATION_SMIME; crypt_opportunistic_encrypt (msg); redraw_crypt_lines (msg); } msg->security = crypt_smime_send_menu(msg, &menu->redraw); redraw_crypt_lines (msg); mutt_message_hook (NULL, msg, M_SEND2HOOK); break; #ifdef MIXMASTER case OP_COMPOSE_MIX: mix_make_chain (&msg->chain, &menu->redraw); mutt_message_hook (NULL, msg, M_SEND2HOOK); break; #endif } /* Draw formatted compose status line */ if (menu->redraw & REDRAW_STATUS) { compose_status_line (buf, sizeof (buf), 0, menu, NONULL(ComposeFormat)); move(option (OPTSTATUSONTOP) ? 0 : LINES-2, 0); SETCOLOR (MT_COLOR_STATUS); mutt_paddstr (COLS, buf); NORMAL_COLOR; menu->redraw &= ~REDRAW_STATUS; } } mutt_menuDestroy (&menu); if (idxlen) { msg->content = idx[0]->content; for (i = 0; i < idxlen; i++) { idx[i]->content->aptr = NULL; FREE (&idx[i]->tree); FREE (&idx[i]); } } else msg->content = NULL; FREE (&idx); return (r); }
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); }
/* returns 1 on success, 0 on error */ int mutt_pipe_attachment (FILE *fp, BODY *b, const char *path, char *outfile) { pid_t thepid; int out = -1; int rv = 0; if (outfile && *outfile) if ((out = safe_open (outfile, O_CREAT | O_EXCL | O_WRONLY)) < 0) { mutt_perror ("open"); return 0; } mutt_endwin (NULL); if (fp) { /* recv case */ STATE s; memset (&s, 0, sizeof (STATE)); if (outfile && *outfile) thepid = mutt_create_filter_fd (path, &s.fpout, NULL, NULL, -1, out, -1); else thepid = mutt_create_filter (path, &s.fpout, NULL, NULL); if (thepid < 0) { mutt_perror _("Can't create filter"); goto bail; } s.fpin = fp; mutt_decode_attachment (b, &s); safe_fclose (&s.fpout); } else { /* send case */ FILE *ifp, *ofp; if ((ifp = fopen (b->filename, "r")) == NULL) { mutt_perror ("fopen"); if (outfile && *outfile) { close (out); unlink (outfile); } return 0; } if (outfile && *outfile) thepid = mutt_create_filter_fd (path, &ofp, NULL, NULL, -1, out, -1); else thepid = mutt_create_filter (path, &ofp, NULL, NULL); if (thepid < 0) { mutt_perror _("Can't create filter"); safe_fclose (&ifp); goto bail; } mutt_copy_stream (ifp, ofp); safe_fclose (&ofp); safe_fclose (&ifp); } rv = 1; bail: if (outfile && *outfile) close (out); /* * check for error exit from child process */ if (mutt_wait_filter (thepid) != 0) rv = 0; if (rv == 0 || option (OPTWAITKEY)) mutt_any_key_to_continue (NULL); return rv; }
/* 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; }
/* returns 0 on success, -1 on error */ int mutt_save_attachment (FILE *fp, BODY *m, char *path, int flags, HEADER *hdr) { if (fp) { /* recv mode */ if(hdr && m->hdr && m->encoding != ENCBASE64 && m->encoding != ENCQUOTEDPRINTABLE && mutt_is_message_type(m->type, m->subtype)) { /* message type attachments are written to mail folders. */ char buf[HUGE_STRING]; HEADER *hn; CONTEXT ctx; MESSAGE *msg; int chflags = 0; int r = -1; hn = m->hdr; hn->msgno = hdr->msgno; /* required for MH/maildir */ hn->read = 1; fseeko (fp, m->offset, 0); if (fgets (buf, sizeof (buf), fp) == NULL) return -1; if (mx_open_mailbox(path, M_APPEND | M_QUIET, &ctx) == NULL) return -1; if ((msg = mx_open_new_message (&ctx, hn, is_from (buf, NULL, 0, NULL) ? 0 : M_ADD_FROM)) == NULL) { mx_close_mailbox(&ctx, NULL); return -1; } if (ctx.magic == M_MBOX || ctx.magic == M_MMDF) chflags = CH_FROM | CH_UPDATE_LEN; chflags |= (ctx.magic == M_MAILDIR ? CH_NOSTATUS : CH_UPDATE); if (_mutt_copy_message (msg->fp, fp, hn, hn->content, 0, chflags) == 0 && mx_commit_message (msg, &ctx) == 0) r = 0; else r = -1; mx_close_message (&msg); mx_close_mailbox (&ctx, NULL); return r; } else { /* In recv mode, extract from folder and decode */ STATE s; memset (&s, 0, sizeof (s)); s.flags |= M_CHARCONV; if ((s.fpout = mutt_save_attachment_open (path, flags)) == NULL) { mutt_perror ("fopen"); mutt_sleep (2); return (-1); } fseeko ((s.fpin = fp), m->offset, 0); mutt_decode_attachment (m, &s); if (fclose (s.fpout) != 0) { mutt_perror ("fclose"); mutt_sleep (2); return (-1); } } } else { /* In send mode, just copy file */ FILE *ofp, *nfp; if ((ofp = fopen (m->filename, "r")) == NULL) { mutt_perror ("fopen"); return (-1); } if ((nfp = mutt_save_attachment_open (path, flags)) == NULL) { mutt_perror ("fopen"); safe_fclose (&ofp); return (-1); } if (mutt_copy_stream (ofp, nfp) == -1) { mutt_error _("Write fault!"); safe_fclose (&ofp); safe_fclose (&nfp); return (-1); } safe_fclose (&ofp); safe_fclose (&nfp); } return 0; }
int mutt_slow_close_compressed (CONTEXT * ctx) { FILE *fp; const char *append; char *cmd; COMPRESS_INFO *ci = (COMPRESS_INFO *) ctx->compressinfo; debug_print (2, ("called on '%s'\n", ctx->path)); if (!(ctx->append && ((append = get_append_command (ctx->realpath, ctx)) || (append = ci->close)))) { /* if we can not or should not append, * we only have to remove the compressed info, because sync was already * called */ mutt_fast_close_compressed (ctx); return (0); } if (ctx->fp) fclose (ctx->fp); ctx->fp = NULL; if (!ctx->quiet) { if (append == ci->close) mutt_message (_("Compressing %s..."), ctx->realpath); else mutt_message (_("Compressed-appending to %s..."), ctx->realpath); } cmd = get_compression_cmd (append, ctx); if (cmd == NULL) return (-1); if ((fp = fopen (ctx->realpath, "a")) == NULL) { mutt_perror (ctx->realpath); mem_free (&cmd); return (-1); } mutt_block_signals (); if (mbox_lock_compressed (ctx, fp, 1, 1) == -1) { fclose (fp); mutt_unblock_signals (); mutt_error _("Unable to lock mailbox!"); mem_free (&cmd); return (-1); } debug_print (2, ("CompressCmd: '%s'\n", cmd)); endwin (); fflush (stdout); if (append == ci->close) sprintf (echo_cmd, _("echo Compressing %s..."), ctx->realpath); else sprintf (echo_cmd, _("echo Compressed-appending to %s..."), ctx->realpath); mutt_system (echo_cmd); if (mutt_system (cmd)) { mutt_any_key_to_continue (NULL); mutt_error (_ (" %s: Error compressing mailbox! Uncompressed one kept!\n"), ctx->path); mem_free (&cmd); mbox_unlock_compressed (ctx, fp); mutt_unblock_signals (); fclose (fp); return (-1); } mbox_unlock_compressed (ctx, fp); mutt_unblock_signals (); fclose (fp); remove_file (ctx); restore_path (ctx); mem_free (&cmd); mem_free (&ctx->compressinfo); return (0); }
int mutt_open_read_compressed (CONTEXT * ctx) { char *cmd; FILE *fp; int rc; COMPRESS_INFO *ci = set_compress_info (ctx); if (!ci->open) { ctx->magic = 0; mem_free (ctx->compressinfo); return (-1); } if (!ci->close || access (ctx->path, W_OK) != 0) ctx->readonly = 1; set_path (ctx); store_size (ctx); if (!ctx->quiet) mutt_message (_("Decompressing %s..."), ctx->realpath); cmd = get_compression_cmd (ci->open, ctx); if (cmd == NULL) return (-1); debug_print (2, ("DecompressCmd: '%s'\n", cmd)); if ((fp = fopen (ctx->realpath, "r")) == NULL) { mutt_perror (ctx->realpath); mem_free (&cmd); return (-1); } mutt_block_signals (); if (mbox_lock_compressed (ctx, fp, 0, 1) == -1) { fclose (fp); mutt_unblock_signals (); mutt_error _("Unable to lock mailbox!"); mem_free (&cmd); return (-1); } endwin (); fflush (stdout); sprintf (echo_cmd, _("echo Decompressing %s..."), ctx->realpath); mutt_system (echo_cmd); rc = mutt_system (cmd); mbox_unlock_compressed (ctx, fp); mutt_unblock_signals (); fclose (fp); if (rc) { mutt_any_key_to_continue (NULL); ctx->magic = 0; mem_free (ctx->compressinfo); mutt_error (_("Error executing: %s : unable to open the mailbox!\n"), cmd); } mem_free (&cmd); if (rc) return (-1); if (mutt_check_mailbox_compressed (ctx)) return (-1); ctx->magic = mx_get_magic (ctx->path); return (0); }
int imap_append_message (CONTEXT *ctx, MESSAGE *msg) { IMAP_DATA* idata; FILE *fp; char buf[LONG_STRING]; char mbox[LONG_STRING]; char mailbox[LONG_STRING]; char internaldate[IMAP_DATELEN]; char imap_flags[SHORT_STRING]; size_t len; progress_t progressbar; size_t sent; int c, last; IMAP_MBOX mx; int rc; idata = (IMAP_DATA*) ctx->data; if (imap_parse_path (ctx->path, &mx)) return -1; imap_fix_path (idata, mx.mbox, mailbox, sizeof (mailbox)); if (!*mailbox) strfcpy (mailbox, "INBOX", sizeof (mailbox)); if ((fp = fopen (msg->path, "r")) == NULL) { mutt_perror (msg->path); goto fail; } /* currently we set the \Seen flag on all messages, but probably we * should scan the message Status header for flag info. Since we're * already rereading the whole file for length it isn't any more * expensive (it'd be nice if we had the file size passed in already * by the code that writes the file, but that's a lot of changes. * Ideally we'd have a HEADER structure with flag info here... */ for (last = EOF, len = 0; (c = fgetc(fp)) != EOF; last = c) { if(c == '\n' && last != '\r') len++; len++; } rewind (fp); mutt_progress_init (&progressbar, _("Uploading message..."), MUTT_PROGRESS_SIZE, NetInc, len); imap_munge_mbox_name (idata, mbox, sizeof (mbox), mailbox); imap_make_date (internaldate, msg->received); imap_flags[0] = imap_flags[1] = 0; if (msg->flags.read) safe_strcat (imap_flags, sizeof (imap_flags), " \\Seen"); if (msg->flags.replied) safe_strcat (imap_flags, sizeof (imap_flags), " \\Answered"); if (msg->flags.flagged) safe_strcat (imap_flags, sizeof (imap_flags), " \\Flagged"); if (msg->flags.draft) safe_strcat (imap_flags, sizeof (imap_flags), " \\Draft"); snprintf (buf, sizeof (buf), "APPEND %s (%s) \"%s\" {%lu}", mbox, imap_flags + 1, internaldate, (unsigned long) len); imap_cmd_start (idata, buf); do rc = imap_cmd_step (idata); while (rc == IMAP_CMD_CONTINUE); if (rc != IMAP_CMD_RESPOND) { char *pc; dprint (1, (debugfile, "imap_append_message(): command failed: %s\n", idata->buf)); pc = idata->buf + SEQLEN; SKIPWS (pc); pc = imap_next_word (pc); mutt_error ("%s", pc); mutt_sleep (1); safe_fclose (&fp); goto fail; } for (last = EOF, sent = len = 0; (c = fgetc(fp)) != EOF; last = c) { if (c == '\n' && last != '\r') buf[len++] = '\r'; buf[len++] = c; if (len > sizeof(buf) - 3) { sent += len; flush_buffer(buf, &len, idata->conn); mutt_progress_update (&progressbar, sent, -1); } } if (len) flush_buffer(buf, &len, idata->conn); mutt_socket_write (idata->conn, "\r\n"); safe_fclose (&fp); do rc = imap_cmd_step (idata); while (rc == IMAP_CMD_CONTINUE); if (!imap_code (idata->buf)) { char *pc; dprint (1, (debugfile, "imap_append_message(): command failed: %s\n", idata->buf)); pc = idata->buf + SEQLEN; SKIPWS (pc); pc = imap_next_word (pc); mutt_error ("%s", pc); mutt_sleep (1); goto fail; } FREE (&mx.mbox); return 0; fail: FREE (&mx.mbox); return -1; }
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 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; } }
/* returns 0 on success, -1 on error */ int mutt_decode_save_attachment (FILE *fp, BODY *m, char *path, int displaying, int flags) { STATE s; unsigned int saved_encoding = 0; BODY *saved_parts = NULL; HEADER *saved_hdr = NULL; memset (&s, 0, sizeof (s)); s.flags = displaying; if (flags == M_SAVE_APPEND) s.fpout = fopen (path, "a"); else if (flags == M_SAVE_OVERWRITE) s.fpout = fopen (path, "w"); /* __FOPEN_CHECKED__ */ else s.fpout = safe_fopen (path, "w"); if (s.fpout == NULL) { mutt_perror ("fopen"); return (-1); } if (fp == NULL) { /* When called from the compose menu, the attachment isn't parsed, * so we need to do it here. */ struct stat st; if (stat (m->filename, &st) == -1) { mutt_perror ("stat"); safe_fclose (&s.fpout); return (-1); } if ((s.fpin = fopen (m->filename, "r")) == NULL) { mutt_perror ("fopen"); return (-1); } saved_encoding = m->encoding; if (!is_multipart (m)) m->encoding = ENC8BIT; m->length = st.st_size; m->offset = 0; saved_parts = m->parts; saved_hdr = m->hdr; mutt_parse_part (s.fpin, m); if (m->noconv || is_multipart (m)) s.flags |= M_CHARCONV; } else { s.fpin = fp; s.flags |= M_CHARCONV; } mutt_body_handler (m, &s); safe_fclose (&s.fpout); if (fp == NULL) { m->length = 0; m->encoding = saved_encoding; if (saved_parts) { mutt_free_header (&m->hdr); m->parts = saved_parts; m->hdr = saved_hdr; } safe_fclose (&s.fpin); } return (0); }