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/email.h"
51 * edit_or_view_one_message - Edit an email or view it in an external editor
52 * @param edit true if the message should be editable. If false, changes
53 * to the message (in the editor) will be ignored.
55 * @param cur Header of email
56 * @retval 1 Message not modified
57 * @retval 0 Message edited successfully
60 static int edit_or_view_one_message(bool edit, struct Context *ctx, struct Header *cur)
73 struct Context tmpctx;
74 struct Message *msg = NULL;
81 mutt_mktemp(tmp, sizeof(tmp));
86 rc = (mx_mbox_open(tmp, MUTT_NEWFOLDER, &tmpctx) == NULL) ? -1 : 0;
92 mutt_error(_("could not create temporary folder: %s"), strerror(errno));
96 rc = mutt_append_message(
98 CH_NOLEN | ((ctx->magic == MUTT_MBOX || ctx->magic == MUTT_MMDF) ? 0 : CH_NOSTATUS));
101 mx_mbox_close(&tmpctx, NULL);
105 mutt_error(_("could not write temporary mail folder: %s"), strerror(oerrno));
112 mutt_error(_("Can't stat %s: %s"), tmp, strerror(errno));
116 /* The file the user is going to edit is not a real mbox, so we need to
117 * truncate the last newline in the temp file, which is logically part of
118 * the message separator, and not the body of the message. If we fail to
119 * remove it, the message will grow by one line each time the user edits
122 if (sb.st_size != 0 && truncate(tmp, sb.st_size - 1) == -1)
124 mutt_error(_("could not truncate temporary mail folder: %s"), strerror(errno));
130 /* remove write permissions */
131 rc = mutt_file_chmod_rm_stat(tmp, S_IWUSR | S_IWGRP | S_IWOTH, &sb);
134 mutt_debug(1, "Could not remove write permissions of %s: %s", tmp, strerror(errno));
135 /* Do not bail out here as we are checking afterwards if we should adopt
136 * changes of the temporary file. */
140 /* Do not reuse the stat sb here as it is outdated. */
141 mtime = mutt_file_decrease_mtime(tmp, NULL);
143 mutt_edit_file(NONULL(Editor), tmp);
148 mutt_error(_("Can't stat %s: %s"), tmp, strerror(errno));
154 mutt_message(_("Message file is empty!"));
159 if (edit && sb.st_mtime == mtime)
161 mutt_message(_("Message not modified!"));
166 if (!edit && sb.st_mtime != mtime)
168 mutt_message(_("Message of read-only mailbox modified! Ignoring changes."));
175 /* stop processing here and skip right to the end */
180 fp = fopen(tmp, "r");
184 mutt_error(_("Can't open message file: %s"), strerror(errno));
188 if (mx_mbox_open(ctx->path, MUTT_APPEND, &tmpctx) == NULL)
191 /* L10N: %s is from strerror(errno) */
192 mutt_error(_("Can't append to folder: %s"), strerror(errno));
197 cf = ((tmpctx.magic == MUTT_MBOX || tmpctx.magic == MUTT_MMDF) ? 0 : CH_NOSTATUS);
199 if (fgets(buf, sizeof(buf), fp) && is_from(buf, NULL, 0, NULL))
201 if (tmpctx.magic == MUTT_MBOX || tmpctx.magic == MUTT_MMDF)
202 cf = CH_FROM | CH_FORCE_FROM;
207 /* XXX - we have to play games with the message flags to avoid
208 * problematic behavior with maildir folders. */
212 cur->read = cur->old = false;
213 msg = mx_msg_open_new(&tmpctx, cur, of);
219 mutt_error(_("Can't append to folder: %s"), strerror(errno));
220 mx_mbox_close(&tmpctx, NULL);
224 rc = mutt_copy_hdr(fp, msg->fp, 0, sb.st_size, CH_NOLEN | cf, NULL);
227 fputc('\n', msg->fp);
228 mutt_file_copy_stream(fp, msg->fp);
231 rc = mx_msg_commit(&tmpctx, msg);
232 mx_msg_close(&tmpctx, &msg);
234 mx_mbox_close(&tmpctx, NULL);
238 mutt_file_fclose(&fp);
245 mutt_set_flag(Context, cur, MUTT_DELETE, 1);
246 mutt_set_flag(Context, cur, MUTT_PURGE, 1);
247 mutt_set_flag(Context, cur, MUTT_READ, 1);
250 mutt_set_flag(Context, cur, MUTT_TAG, 0);
253 mutt_message(_("Error. Preserving temporary file: %s"), tmp);
259 * edit_or_view_message - Edit an email or view it in an external editor
260 * @param edit true: Edit the email; false: view the email
261 * @param ctx Mailbox Context
262 * @param hdr Email Header
263 * @retval 1 Message not modified
264 * @retval 0 Message edited successfully
267 int edit_or_view_message(bool edit, struct Context *ctx, struct Header *hdr)
270 return edit_or_view_one_message(edit, ctx, hdr);
272 for (int i = 0; i < ctx->msgcount; i++)
274 if (!message_is_tagged(ctx, i))
277 if (edit_or_view_one_message(edit, ctx, ctx->hdrs[i]) == -1)
285 * mutt_edit_message - Edit a message
286 * @param ctx Mailbox Context
287 * @param hdr Email Header
288 * @retval 1 Message not modified
289 * @retval 0 Message edited successfully
292 int mutt_edit_message(struct Context *ctx, struct Header *hdr)
294 return edit_or_view_message(true, ctx, hdr); /* true means edit */
298 * mutt_view_message - Edit a message
299 * @param ctx Mailbox Context
300 * @param hdr Email Header
301 * @retval 1 Message not modified
302 * @retval 0 Message edited successfully
305 int mutt_view_message(struct Context *ctx, struct Header *hdr)
307 return edit_or_view_message(false, ctx, hdr); /* false means only view */