3 * Prepare an email to be edited
6 * Copyright (C) 1999-2002 Thomas Roessler <roessler@does-not-exist.org>
9 * This program is free software: you can redistribute it and/or modify it under
10 * the terms of the GNU General Public License as published by the Free Software
11 * Foundation, either version 2 of the License, or (at your option) any later
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
24 * @page editmsg Prepare an email to be edited
26 * Prepare an email to be edited
38 #include "mutt/mutt.h"
39 #include "config/lib.h"
40 #include "email/lib.h"
52 * ev_message - Edit an email or view it in an external editor
53 * @param action Action to perform, e.g. #EVM_EDIT
56 * @retval 1 Message not modified
57 * @retval 0 Message edited successfully
60 static int ev_message(enum EvMessage action, struct Mailbox *m, struct Email *e)
67 mutt_mktemp(fname, sizeof(fname));
69 enum MailboxType omagic = C_MboxType;
70 C_MboxType = MUTT_MBOX;
72 struct Mailbox *m_fname = mx_path_resolve(fname);
73 struct Context *tmpctx = mx_mbox_open(m_fname, MUTT_NEWFOLDER);
79 mutt_error(_("could not create temporary folder: %s"), strerror(errno));
80 mailbox_free(&m_fname);
85 CH_NOLEN | ((m->magic == MUTT_MBOX || m->magic == MUTT_MMDF) ? 0 : CH_NOSTATUS);
86 rc = mutt_append_message(tmpctx->mailbox, m, e, 0, chflags);
89 mx_mbox_close(&tmpctx);
93 mutt_error(_("could not write temporary mail folder: %s"), strerror(oerrno));
97 rc = stat(fname, &sb);
100 mutt_error(_("Can't stat %s: %s"), fname, strerror(errno));
104 /* The file the user is going to edit is not a real mbox, so we need to
105 * truncate the last newline in the temp file, which is logically part of
106 * the message separator, and not the body of the message. If we fail to
107 * remove it, the message will grow by one line each time the user edits
110 if ((sb.st_size != 0) && (truncate(fname, sb.st_size - 1) == -1))
112 mutt_error(_("could not truncate temporary mail folder: %s"), strerror(errno));
116 if (action == EVM_VIEW)
118 /* remove write permissions */
119 rc = mutt_file_chmod_rm_stat(fname, S_IWUSR | S_IWGRP | S_IWOTH, &sb);
122 mutt_debug(LL_DEBUG1, "Could not remove write permissions of %s: %s",
123 fname, strerror(errno));
124 /* Do not bail out here as we are checking afterwards if we should adopt
125 * changes of the temporary file. */
129 /* Do not reuse the stat sb here as it is outdated. */
130 time_t mtime = mutt_file_decrease_mtime(fname, NULL);
132 mutt_edit_file(NONULL(C_Editor), fname);
134 rc = stat(fname, &sb);
137 mutt_error(_("Can't stat %s: %s"), fname, strerror(errno));
143 mutt_message(_("Message file is empty"));
148 if ((action == EVM_EDIT) && (sb.st_mtime == mtime))
150 mutt_message(_("Message not modified"));
155 if ((action == EVM_VIEW) && (sb.st_mtime != mtime))
157 mutt_message(_("Message of read-only mailbox modified! Ignoring changes."));
162 if (action == EVM_VIEW)
164 /* stop processing here and skip right to the end */
169 FILE *fp = fopen(fname, "r");
173 mutt_error(_("Can't open message file: %s"), strerror(errno));
177 tmpctx = mx_mbox_open(m, MUTT_APPEND);
181 /* L10N: %s is from strerror(errno) */
182 mutt_error(_("Can't append to folder: %s"), strerror(errno));
187 int cf = (((tmpctx->mailbox->magic == MUTT_MBOX) || (tmpctx->mailbox->magic == MUTT_MMDF)) ?
191 if (fgets(buf, sizeof(buf), fp) && is_from(buf, NULL, 0, NULL))
193 if ((tmpctx->mailbox->magic == MUTT_MBOX) || (tmpctx->mailbox->magic == MUTT_MMDF))
194 cf = CH_FROM | CH_FORCE_FROM;
199 /* XXX - we have to play games with the message flags to avoid
200 * problematic behavior with maildir folders. */
202 bool o_read = e->read;
206 struct Message *msg = mx_msg_open_new(tmpctx->mailbox, e, of);
212 mutt_error(_("Can't append to folder: %s"), strerror(errno));
213 mx_mbox_close(&tmpctx);
217 rc = mutt_copy_hdr(fp, msg->fp, 0, sb.st_size, CH_NOLEN | cf, NULL);
220 fputc('\n', msg->fp);
221 mutt_file_copy_stream(fp, msg->fp);
224 rc = mx_msg_commit(tmpctx->mailbox, msg);
225 mx_msg_close(tmpctx->mailbox, &msg);
227 mx_mbox_close(&tmpctx);
230 mutt_file_fclose(&fp);
237 mutt_set_flag(m, e, MUTT_DELETE, true);
238 mutt_set_flag(m, e, MUTT_PURGE, true);
239 mutt_set_flag(m, e, MUTT_READ, true);
242 mutt_set_flag(m, e, MUTT_TAG, false);
245 mutt_message(_("Error. Preserving temporary file: %s"), fname);
251 * mutt_ev_message - Edit or view a message
253 * @param el List of Emails
254 * @param action Action to perform, e.g. #EVM_EDIT
255 * @retval 1 Message not modified
256 * @retval 0 Message edited successfully
259 int mutt_ev_message(struct Mailbox *m, struct EmailList *el, enum EvMessage action)
261 struct EmailNode *en = NULL;
262 STAILQ_FOREACH(en, el, entries)
264 if (ev_message(action, m, en->email) == -1)