NeoMutt  2018-07-16 +952-a2da0a
Teaching an old dog new tricks
DOXYGEN
editmsg.c File Reference

Prepare an email to be edited. More...

#include "config.h"
#include <errno.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#include "mutt/mutt.h"
#include "config/lib.h"
#include "email/lib.h"
#include "mutt.h"
#include "context.h"
#include "copy.h"
#include "curs_lib.h"
#include "globals.h"
#include "mailbox.h"
#include "muttlib.h"
#include "mx.h"
#include "protos.h"
+ Include dependency graph for editmsg.c:

Go to the source code of this file.

Functions

static int edit_or_view_one_message (bool edit, struct Mailbox *m, struct Email *cur)
 Edit an email or view it in an external editor. More...
 
int edit_or_view_message (bool edit, struct Context *ctx, struct Email *e)
 Edit an email or view it in an external editor. More...
 
int mutt_edit_message (struct Context *ctx, struct Email *e)
 Edit a message. More...
 
int mutt_view_message (struct Context *ctx, struct Email *e)
 Edit a message. More...
 

Detailed Description

Prepare an email to be edited.

Authors
  • Thomas Roessler

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file editmsg.c.

Function Documentation

static int edit_or_view_one_message ( bool  edit,
struct Mailbox m,
struct Email cur 
)
static

Edit an email or view it in an external editor.

Parameters
edittrue if the message should be editable. If false, changes to the message (in the editor) will be ignored.
mMailbox
curEmail
Return values
1Message not modified
0Message edited successfully
-1Error

Definition at line 61 of file editmsg.c.

62 {
63  char tmp[PATH_MAX];
64  char buf[STRING];
65  enum MailboxType omagic;
66  int oerrno;
67  int rc;
68 
69  bool o_read;
70  bool o_old;
71 
72  int of, cf;
73 
74  struct Message *msg = NULL;
75 
76  FILE *fp = NULL;
77 
78  struct stat sb;
79  time_t mtime = 0;
80 
81  mutt_mktemp(tmp, sizeof(tmp));
82 
83  omagic = MboxType;
85 
86  struct Context *tmpctx = mx_mbox_open(NULL, tmp, MUTT_NEWFOLDER);
87 
88  MboxType = omagic;
89 
90  if (!tmpctx)
91  {
92  mutt_error(_("could not create temporary folder: %s"), strerror(errno));
93  return -1;
94  }
95 
96  const int chflags =
97  CH_NOLEN | ((m->magic == MUTT_MBOX || m->magic == MUTT_MMDF) ? 0 : CH_NOSTATUS);
98  rc = mutt_append_message(tmpctx->mailbox, m, cur, 0, chflags);
99  oerrno = errno;
100 
101  mx_mbox_close(&tmpctx, NULL);
102 
103  if (rc == -1)
104  {
105  mutt_error(_("could not write temporary mail folder: %s"), strerror(oerrno));
106  goto bail;
107  }
108 
109  rc = stat(tmp, &sb);
110  if (rc == -1)
111  {
112  mutt_error(_("Can't stat %s: %s"), tmp, strerror(errno));
113  goto bail;
114  }
115 
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
120  * the message.
121  */
122  if (sb.st_size != 0 && truncate(tmp, sb.st_size - 1) == -1)
123  {
124  mutt_error(_("could not truncate temporary mail folder: %s"), strerror(errno));
125  goto bail;
126  }
127 
128  if (!edit)
129  {
130  /* remove write permissions */
131  rc = mutt_file_chmod_rm_stat(tmp, S_IWUSR | S_IWGRP | S_IWOTH, &sb);
132  if (rc == -1)
133  {
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. */
137  }
138  }
139 
140  /* Do not reuse the stat sb here as it is outdated. */
141  mtime = mutt_file_decrease_mtime(tmp, NULL);
142 
144 
145  rc = stat(tmp, &sb);
146  if (rc == -1)
147  {
148  mutt_error(_("Can't stat %s: %s"), tmp, strerror(errno));
149  goto bail;
150  }
151 
152  if (sb.st_size == 0)
153  {
154  mutt_message(_("Message file is empty"));
155  rc = 1;
156  goto bail;
157  }
158 
159  if (edit && sb.st_mtime == mtime)
160  {
161  mutt_message(_("Message not modified"));
162  rc = 1;
163  goto bail;
164  }
165 
166  if (!edit && sb.st_mtime != mtime)
167  {
168  mutt_message(_("Message of read-only mailbox modified! Ignoring changes."));
169  rc = 1;
170  goto bail;
171  }
172 
173  if (!edit)
174  {
175  /* stop processing here and skip right to the end */
176  rc = 1;
177  goto bail;
178  }
179 
180  fp = fopen(tmp, "r");
181  if (!fp)
182  {
183  rc = -1;
184  mutt_error(_("Can't open message file: %s"), strerror(errno));
185  goto bail;
186  }
187 
188  tmpctx = mx_mbox_open(m, NULL, MUTT_APPEND);
189  if (!tmpctx)
190  {
191  rc = -1;
192  /* L10N: %s is from strerror(errno) */
193  mutt_error(_("Can't append to folder: %s"), strerror(errno));
194  goto bail;
195  }
196 
197  of = 0;
198  cf = (((tmpctx->mailbox->magic == MUTT_MBOX) || (tmpctx->mailbox->magic == MUTT_MMDF)) ?
199  0 :
200  CH_NOSTATUS);
201 
202  if (fgets(buf, sizeof(buf), fp) && is_from(buf, NULL, 0, NULL))
203  {
204  if ((tmpctx->mailbox->magic == MUTT_MBOX) || (tmpctx->mailbox->magic == MUTT_MMDF))
205  cf = CH_FROM | CH_FORCE_FROM;
206  }
207  else
208  of = MUTT_ADD_FROM;
209 
210  /* XXX - we have to play games with the message flags to avoid
211  * problematic behavior with maildir folders. */
212 
213  o_read = cur->read;
214  o_old = cur->old;
215  cur->read = false;
216  cur->old = false;
217  msg = mx_msg_open_new(tmpctx->mailbox, cur, of);
218  cur->read = o_read;
219  cur->old = o_old;
220 
221  if (!msg)
222  {
223  mutt_error(_("Can't append to folder: %s"), strerror(errno));
224  mx_mbox_close(&tmpctx, NULL);
225  goto bail;
226  }
227 
228  rc = mutt_copy_hdr(fp, msg->fp, 0, sb.st_size, CH_NOLEN | cf, NULL);
229  if (rc == 0)
230  {
231  fputc('\n', msg->fp);
232  mutt_file_copy_stream(fp, msg->fp);
233  }
234 
235  rc = mx_msg_commit(tmpctx->mailbox, msg);
236  mx_msg_close(tmpctx->mailbox, &msg);
237 
238  mx_mbox_close(&tmpctx, NULL);
239 
240 bail:
241  if (fp)
242  mutt_file_fclose(&fp);
243 
244  if (rc >= 0)
245  unlink(tmp);
246 
247  if (rc == 0)
248  {
252 
253  if (DeleteUntag)
255  }
256  else if (rc == -1)
257  mutt_message(_("Error. Preserving temporary file: %s"), tmp);
258 
259  return rc;
260 }
#define MUTT_APPEND
open mailbox for appending messages
Definition: mx.h:50
The "current" mailbox.
Definition: context.h:36
#define NONULL(x)
Definition: string2.h:39
#define mutt_message(...)
Definition: logging.h:87
Messages to be deleted.
Definition: mutt.h:118
WHERE char * Editor
Config: External command to use as an email editor.
Definition: globals.h:110
&#39;mmdf&#39; Mailbox type
Definition: magic.h:38
#define CH_FROM
retain the "From " message separator?
Definition: copy.h:51
#define _(a)
Definition: message.h:28
#define CH_NOSTATUS
suppress the status and x-status fields
Definition: copy.h:53
int mutt_copy_hdr(FILE *in, FILE *out, LOFF_T off_start, LOFF_T off_end, int flags, const char *prefix)
Copy header from one file to another.
Definition: copy.c:72
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1187
bool read
Definition: email.h:49
struct Context * mx_mbox_open(struct Mailbox *m, const char *path, int flags)
Open a mailbox and parse it.
Definition: mx.c:254
struct Mailbox * mailbox
Definition: context.h:50
bool old
Definition: email.h:48
enum MailboxType magic
mailbox type
Definition: mailbox.h:99
WHERE bool DeleteUntag
Config: Untag messages when they are marked for deletion.
Definition: globals.h:211
Tagged messages.
Definition: mutt.h:123
struct Message * mx_msg_open_new(struct Mailbox *m, struct Email *e, int flags)
Open a new message.
Definition: mx.c:1053
int mx_mbox_close(struct Context **pctx, int *index_hint)
Save changes and close mailbox.
Definition: mx.c:568
#define CH_FORCE_FROM
give CH_FROM precedence over CH_WEED?
Definition: copy.h:61
&#39;mbox&#39; Mailbox type
Definition: magic.h:37
#define mutt_mktemp(a, b)
Definition: muttlib.h:71
A local copy of an email.
Definition: mx.h:81
int mutt_file_copy_stream(FILE *fin, FILE *fout)
Copy the contents of one file into another.
Definition: file.c:264
#define PATH_MAX
Definition: mutt.h:46
MailboxType
Supported mailbox formats.
Definition: magic.h:33
Messages to be purged (bypass trash)
Definition: mutt.h:120
time_t mutt_file_decrease_mtime(const char *f, struct stat *st)
Decrease a file&#39;s modification time by 1 second.
Definition: file.c:884
#define mutt_set_flag(a, b, c, d)
Definition: protos.h:54
#define CH_NOLEN
don&#39;t write Content-Length: and Lines:
Definition: copy.h:59
Messages that have been read.
Definition: mutt.h:116
#define STRING
Definition: string2.h:35
int mutt_file_fclose(FILE **f)
Close a FILE handle (and NULL the pointer)
Definition: file.c:149
#define mutt_error(...)
Definition: logging.h:88
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition: mx.c:1166
FILE * fp
pointer to the message data
Definition: mx.h:83
bool is_from(const char *s, char *path, size_t pathlen, time_t *tp)
Is a string a &#39;From&#39; header line?
Definition: from.c:49
int mutt_file_chmod_rm_stat(const char *path, mode_t mode, struct stat *st)
Remove permissions from a file.
Definition: file.c:1044
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
#define MUTT_NEWFOLDER
create a new folder - same as MUTT_APPEND, but uses mutt_file_fopen() with mode "w" for mbox-style fo...
Definition: mx.h:53
short MboxType
Config: Default type for creating new mailboxes.
Definition: mx.c:92
#define MUTT_ADD_FROM
add a From_ line
Definition: mx.h:64
void mutt_edit_file(const char *editor, const char *file)
Let the user edit a file.
Definition: curs_lib.c:308
int mutt_append_message(struct Mailbox *dest, struct Mailbox *src, struct Email *e, int cmflags, int chflags)
Append a message.
Definition: copy.c:862

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

int edit_or_view_message ( bool  edit,
struct Context ctx,
struct Email e 
)

Edit an email or view it in an external editor.

Parameters
edittrue: Edit the email; false: view the email
ctxMailbox Context
eEmail
Return values
1Message not modified
0Message edited successfully
-1Error

Definition at line 271 of file editmsg.c.

272 {
273  if (e)
274  return edit_or_view_one_message(edit, ctx->mailbox, e);
275 
276  for (int i = 0; i < ctx->mailbox->msg_count; i++)
277  {
278  if (!message_is_tagged(ctx, i))
279  continue;
280 
281  if (edit_or_view_one_message(edit, ctx->mailbox, ctx->mailbox->hdrs[i]) == -1)
282  return -1;
283  }
284 
285  return 0;
286 }
int msg_count
total number of messages
Definition: mailbox.h:86
struct Email ** hdrs
Definition: mailbox.h:93
struct Mailbox * mailbox
Definition: context.h:50
bool message_is_tagged(struct Context *ctx, int index)
Is a message in the index tagged (and within limit)
Definition: curs_lib.c:1236
static int edit_or_view_one_message(bool edit, struct Mailbox *m, struct Email *cur)
Edit an email or view it in an external editor.
Definition: editmsg.c:61

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

int mutt_edit_message ( struct Context ctx,
struct Email e 
)

Edit a message.

Parameters
ctxMailbox Context
eEmail
Return values
1Message not modified
0Message edited successfully
-1Error

Definition at line 296 of file editmsg.c.

297 {
298  return edit_or_view_message(true, ctx, e); /* true means edit */
299 }
int edit_or_view_message(bool edit, struct Context *ctx, struct Email *e)
Edit an email or view it in an external editor.
Definition: editmsg.c:271

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

int mutt_view_message ( struct Context ctx,
struct Email e 
)

Edit a message.

Parameters
ctxMailbox Context
eEmail
Return values
1Message not modified
0Message edited successfully
-1Error

Definition at line 309 of file editmsg.c.

310 {
311  return edit_or_view_message(false, ctx, e); /* false means only view */
312 }
int edit_or_view_message(bool edit, struct Context *ctx, struct Email *e)
Edit an email or view it in an external editor.
Definition: editmsg.c:271

+ Here is the call graph for this function:

+ Here is the caller graph for this function: