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 = MboxType;
71 struct Mailbox *m_fname = mx_path_resolve(fname);
72 struct Context *tmpctx = mx_mbox_open(m_fname, NULL, MUTT_NEWFOLDER);
77 mutt_error(_("could not create temporary folder: %s"), strerror(errno));
78 mailbox_free(&m_fname);
83 CH_NOLEN | ((m->magic == MUTT_MBOX || m->magic == MUTT_MMDF) ? 0 : CH_NOSTATUS);
84 rc = mutt_append_message(tmpctx->mailbox, m, e, 0, chflags);
87 mx_mbox_close(&tmpctx);
91 mutt_error(_("could not write temporary mail folder: %s"), strerror(oerrno));
95 rc = stat(fname, &sb);
98 mutt_error(_("Can't stat %s: %s"), fname, strerror(errno));
102 /* The file the user is going to edit is not a real mbox, so we need to
103 * truncate the last newline in the temp file, which is logically part of
104 * the message separator, and not the body of the message. If we fail to
105 * remove it, the message will grow by one line each time the user edits
108 if ((sb.st_size != 0) && (truncate(fname, sb.st_size - 1) == -1))
110 mutt_error(_("could not truncate temporary mail folder: %s"), strerror(errno));
114 if (action == EVM_VIEW)
116 /* remove write permissions */
117 rc = mutt_file_chmod_rm_stat(fname, S_IWUSR | S_IWGRP | S_IWOTH, &sb);
120 mutt_debug(1, "Could not remove write permissions of %s: %s", fname, strerror(errno));
121 /* Do not bail out here as we are checking afterwards if we should adopt
122 * changes of the temporary file. */
126 /* Do not reuse the stat sb here as it is outdated. */
127 time_t mtime = mutt_file_decrease_mtime(fname, NULL);
129 mutt_edit_file(NONULL(Editor), fname);
131 rc = stat(fname, &sb);
134 mutt_error(_("Can't stat %s: %s"), fname, strerror(errno));
140 mutt_message(_("Message file is empty"));
145 if ((action == EVM_EDIT) && (sb.st_mtime == mtime))
147 mutt_message(_("Message not modified"));
152 if ((action == EVM_VIEW) && (sb.st_mtime != mtime))
154 mutt_message(_("Message of read-only mailbox modified! Ignoring changes."));
159 if (action == EVM_VIEW)
161 /* stop processing here and skip right to the end */
166 FILE *fp = fopen(fname, "r");
170 mutt_error(_("Can't open message file: %s"), strerror(errno));
174 tmpctx = mx_mbox_open(m, NULL, MUTT_APPEND);
178 /* L10N: %s is from strerror(errno) */
179 mutt_error(_("Can't append to folder: %s"), strerror(errno));
184 int cf = (((tmpctx->mailbox->magic == MUTT_MBOX) || (tmpctx->mailbox->magic == MUTT_MMDF)) ?
188 if (fgets(buf, sizeof(buf), fp) && is_from(buf, NULL, 0, NULL))
190 if ((tmpctx->mailbox->magic == MUTT_MBOX) || (tmpctx->mailbox->magic == MUTT_MMDF))
191 cf = CH_FROM | CH_FORCE_FROM;
196 /* XXX - we have to play games with the message flags to avoid
197 * problematic behavior with maildir folders. */
199 bool o_read = e->read;
203 struct Message *msg = mx_msg_open_new(tmpctx->mailbox, e, of);
209 mutt_error(_("Can't append to folder: %s"), strerror(errno));
210 mx_mbox_close(&tmpctx);
214 rc = mutt_copy_hdr(fp, msg->fp, 0, sb.st_size, CH_NOLEN | cf, NULL);
217 fputc('\n', msg->fp);
218 mutt_file_copy_stream(fp, msg->fp);
221 rc = mx_msg_commit(tmpctx->mailbox, msg);
222 mx_msg_close(tmpctx->mailbox, &msg);
224 mx_mbox_close(&tmpctx);
227 mutt_file_fclose(&fp);
234 mutt_set_flag(m, e, MUTT_DELETE, 1);
235 mutt_set_flag(m, e, MUTT_PURGE, 1);
236 mutt_set_flag(m, e, MUTT_READ, 1);
239 mutt_set_flag(m, e, MUTT_TAG, 0);
242 mutt_message(_("Error. Preserving temporary file: %s"), fname);
248 * mutt_ev_message - Edit or view a message
250 * @param el List of Emails
251 * @param action Action to perform, e.g. #EVM_EDIT
252 * @retval 1 Message not modified
253 * @retval 0 Message edited successfully
256 int mutt_ev_message(struct Mailbox *m, struct EmailList *el, enum EvMessage action)
258 struct EmailNode *en = NULL;
259 STAILQ_FOREACH(en, el, entries)
261 if (ev_message(action, m, en->email) == -1)