1 Create mutt_write_postponed, de-bastardize mutt_write_fcc
3 This patch breaks the postponement code out of mutt_write_fcc. To
4 prevent duplicating lots of code between the functions, there are
5 a couple of new static functions: mutt_start_message and
8 In the process, a few bugs are fixed:
10 * Calculate lines and content-length prior to mx_open_new_message.
11 That way the error path doesn't have to abort a partly written
12 message, removing this questionable line of code:
13 mx_commit_message (msg, &f); /* XXX - really? */
15 * Call set_noconv_flags in the error path of mutt_write_postponed.
16 Previously it was only called in the success path.
18 * Don't write "Status: RO" on postponed messages.
20 Signed-off-by: Aron Griffis <agriffis@n01se.net>
22 diff -r 962bfe47cc13 -r bffd60d2ac16 compose.c
23 --- a/compose.c Mon Apr 27 18:53:40 2009 -0400
24 +++ b/compose.c Tue Apr 28 11:17:28 2009 -0400
26 if (msg->content->next)
27 msg->content = mutt_make_multipart (msg->content);
29 - if (mutt_write_fcc (fname, msg, NULL, 0, NULL) < 0)
30 + if (mutt_write_fcc (fname, msg) < 0)
31 msg->content = mutt_remove_multipart (msg->content);
33 mutt_message _("Message written.");
34 diff -r 962bfe47cc13 -r bffd60d2ac16 protos.h
35 --- a/protos.h Mon Apr 27 18:53:40 2009 -0400
36 +++ b/protos.h Tue Apr 28 11:17:28 2009 -0400
38 void mutt_update_num_postponed (void);
39 int mutt_wait_filter (pid_t);
40 int mutt_which_case (const char *);
41 -int mutt_write_fcc (const char *path, HEADER *hdr, const char *msgid, int, char *);
42 +int mutt_write_fcc (const char *path, HEADER *hdr);
43 +int mutt_write_postponed (const char *path, HEADER *hdr, const char *msgid, char *fcc);
44 int mutt_write_mime_body (BODY *, FILE *);
45 int mutt_write_mime_header (BODY *, FILE *);
46 int mutt_write_one_header (FILE *fp, const char *tag, const char *value, const char *pfx, int wraplen, int flags);
47 diff -r 962bfe47cc13 -r bffd60d2ac16 send.c
48 --- a/send.c Mon Apr 27 18:53:40 2009 -0400
49 +++ b/send.c Tue Apr 28 11:17:28 2009 -0400
51 mutt_prepare_envelope (msg->env, 0);
52 mutt_env_to_idna (msg->env, NULL, NULL); /* Handle bad IDNAs the next time. */
54 - if (!Postponed || mutt_write_fcc (NONULL (Postponed), msg, (cur && (flags & SENDREPLY)) ? cur->env->message_id : NULL, 1, fcc) < 0)
55 + if (!Postponed || mutt_write_postponed (NONULL (Postponed), msg, (cur && (flags & SENDREPLY)) ? cur->env->message_id : NULL, fcc) < 0)
57 msg->content = mutt_remove_multipart (msg->content);
58 decode_descriptions (msg->content);
60 * message was first postponed.
62 msg->received = time (NULL);
63 - if (mutt_write_fcc (fcc, msg, NULL, 0, NULL) == -1)
64 + if (mutt_write_fcc (fcc, msg) == -1)
67 * Error writing FCC, we should abort sending.
68 diff -r 962bfe47cc13 -r bffd60d2ac16 sendlib.c
69 --- a/sendlib.c Mon Apr 27 18:53:40 2009 -0400
70 +++ b/sendlib.c Tue Apr 28 11:17:28 2009 -0400
71 @@ -2503,6 +2505,165 @@
72 rfc2047_decode (&env->x_label);
75 +static int count_length_lines (FILE *fp, LOFF_T *content_lengthp, int *linesp)
77 + char sasha[LONG_STRING];
80 + /* count the number of lines */
81 + while (fgets (sasha, sizeof (sasha), fp) != NULL)
87 + *content_lengthp = (LOFF_T) ftello (fp);
92 +/* state maintained between mutt_start_message and
93 + * mutt_finish_message, opaque to callers.
95 +struct mutt_message_handle
98 + char tempfile[_POSIX_PATH_MAX];
99 + LOFF_T content_length;
105 +static struct mutt_message_handle *
106 +mutt_start_message (const char *path, HEADER *hdr,
107 + CONTEXT *ctxp, MESSAGE **msgp, int passthru)
109 + struct mutt_message_handle *mh;
111 + if (mx_open_mailbox (path, M_APPEND | M_QUIET, ctxp) == NULL)
113 + dprint (1, (debugfile, "mutt_start_message: unable to open mailbox %s"
114 + "in append-mode, aborting.\n", path));
118 + mh = safe_calloc (1, sizeof (*mh));
119 + mh->passthru = passthru;
121 + if (ctxp->magic == M_MMDF || ctxp->magic == M_MBOX)
123 + /* remember new mail status before appending message */
124 + stat (path, &mh->st);
127 + /* need to add a Content-Length field to avoid problems
128 + * where a line in the message body begins with "From "
130 + mutt_mktemp (mh->tempfile, sizeof (mh->tempfile));
131 + mh->tempfp = safe_fopen (mh->tempfile, "w+");
134 + mutt_perror (mh->tempfile);
135 + dprint (1, (debugfile, "mutt_start_message: failed "
136 + "to open tempfile, aborting.\n"));
140 + mutt_write_mime_body (hdr->content, mh->tempfp);
142 + /* make sure the last line ends with a newline. Emacs doesn't ensure
143 + * this will happen, and it can cause problems parsing the mailbox
146 + fseek (mh->tempfp, -1, 2);
147 + if (fgetc (mh->tempfp) != '\n')
149 + fseek (mh->tempfp, 0, 2);
150 + fputc ('\n', mh->tempfp);
152 + if (fflush (mh->tempfp) || ferror (mh->tempfp))
154 + dprint (1, (debugfile, "mutt_start_message: failed "
155 + "to write tempfile, aborting.\n"));
159 + rewind (mh->tempfp);
161 + if (count_length_lines (mh->tempfp, &mh->content_length, &mh->lines))
163 + mutt_perror (mh->tempfile);
164 + dprint (1, (debugfile, "mutt_start_message: failed "
165 + "to count message length, aborting.\n"));
171 + if ((*msgp = mx_open_new_message (ctxp, hdr, M_ADD_FROM)) == NULL)
173 + dprint (1, (debugfile, "mutt_start_message: mx_open_new_message "
174 + "failed in %s, aborting.\n", path));
180 + /* error message already provided, just clean up */
183 + safe_fclose (&mh->tempfp);
184 + unlink (mh->tempfile);
187 + mx_close_mailbox (ctxp, NULL);
191 +static int mutt_finish_message (struct mutt_message_handle *mh,
192 + const char *path, HEADER *hdr,
193 + CONTEXT *ctxp, MESSAGE **msgp, int skip_buffy)
199 + fprintf ((*msgp)->fp, "Content-Length: " OFF_T_FMT "\n", mh->content_length);
200 + fprintf ((*msgp)->fp, "Lines: %d\n\n", mh->lines); /* NOTE double newline */
202 + /* copy the body */
203 + rewind (mh->tempfp);
204 + ret = mutt_copy_stream (mh->tempfp, (*msgp)->fp);
205 + if (safe_fclose (&mh->tempfp))
208 + /* if there was an error, leave the temp version */
210 + unlink (mh->tempfile);
216 + fputc ('\n', (*msgp)->fp); /* finish off the header */
217 + ret = mutt_write_mime_body (hdr->content, (*msgp)->fp);
219 + skip_buffy = 1; /* only needed for file-based mailboxes */
222 + ret |= mx_commit_message (*msgp, ctxp);
223 + mx_close_message (msgp);
224 + mx_close_mailbox (ctxp, NULL);
227 + mutt_buffy_cleanup (path, &mh->st);
234 static int _mutt_bounce_message (FILE *fp, HEADER *h, ADDRESS *to, const char *resent_from,
237 @@ -2664,81 +2823,60 @@
241 -int mutt_write_fcc (const char *path, HEADER *hdr, const char *msgid, int post, char *fcc)
242 +int mutt_write_fcc (const char *path, HEADER *hdr)
244 + struct mutt_message_handle *mh;
247 - char tempfile[_POSIX_PATH_MAX];
248 - FILE *tempfp = NULL;
249 - int r, need_buffy_cleanup = 0;
251 - char buf[SHORT_STRING];
254 - set_noconv_flags (hdr->content, 1);
256 - if (mx_open_mailbox (path, M_APPEND | M_QUIET, &f) == NULL)
257 + hdr->read = 1; /* make sure to put it in the `cur' directory (maildir) */
259 + mh = mutt_start_message (path, hdr, &f, &msg, 0);
263 + mutt_write_rfc822_header (msg->fp, hdr->env, hdr->content, 0, 0);
264 + fprintf (msg->fp, "Status: RO\n");
266 + return mutt_finish_message (mh, path, hdr, &f, &msg, 0);
269 +int mutt_write_postponed (const char *path, HEADER *hdr, const char *msgid, char *fcc)
271 + struct mutt_message_handle *mh;
276 + hdr->read = 0; /* make sure to put it in the `new' directory (maildir) */
277 + set_noconv_flags (hdr->content, 1);
279 + mh = mutt_start_message (path, hdr, &f, &msg, 0);
282 - dprint (1, (debugfile, "mutt_write_fcc(): unable to open mailbox %s in append-mode, aborting.\n",
285 + set_noconv_flags (hdr->content, 0);
289 - /* We need to add a Content-Length field to avoid problems where a line in
290 - * the message body begins with "From "
292 - if (f.magic == M_MMDF || f.magic == M_MBOX)
294 - mutt_mktemp (tempfile, sizeof (tempfile));
295 - if ((tempfp = safe_fopen (tempfile, "w+")) == NULL)
297 - mutt_perror (tempfile);
298 - mx_close_mailbox (&f, NULL);
301 - /* remember new mail status before appending message */
302 - need_buffy_cleanup = 1;
305 + mutt_write_rfc822_header (msg->fp, hdr->env, hdr->content, -1, 0);
307 - hdr->read = !post; /* make sure to put it in the `cur' directory (maildir) */
308 - if ((msg = mx_open_new_message (&f, hdr, M_ADD_FROM)) == NULL)
310 - mx_close_mailbox (&f, NULL);
314 - /* post == 1 => postpone message. Set mode = -1 in mutt_write_rfc822_header()
315 - * post == 0 => Normal mode. Set mode = 0 in mutt_write_rfc822_header()
317 - mutt_write_rfc822_header (msg->fp, hdr->env, hdr->content, post ? -post : 0, 0);
319 - /* (postponment) if this was a reply of some sort, <msgid> contians the
320 + /* if this was a reply of some sort, <msgid> contains the
321 * Message-ID: of message replied to. Save it using a special X-Mutt-
322 * header so it can be picked up if the message is recalled at a later
323 * point in time. This will allow the message to be marked as replied if
324 * the same mailbox is still open.
328 fprintf (msg->fp, "X-Mutt-References: %s\n", msgid);
330 - /* (postponment) save the Fcc: using a special X-Mutt- header so that
331 + /* save the Fcc: using a special X-Mutt- header so that
332 * it can be picked up when the message is recalled
336 fprintf (msg->fp, "X-Mutt-Fcc: %s\n", fcc);
338 - if (f.magic == M_MMDF || f.magic == M_MBOX)
339 - fprintf (msg->fp, "Status: RO\n");
341 - /* mutt_write_rfc822_header() only writes out a Date: header with
342 - * mode == 0, i.e. _not_ postponment; so write out one ourself */
344 - fprintf (msg->fp, "%s", mutt_make_date (buf, sizeof (buf)));
346 - /* (postponment) if the mail is to be signed or encrypted, save this info */
347 - if ((WithCrypto & APPLICATION_PGP)
348 - && post && (hdr->security & APPLICATION_PGP))
349 + /* if the mail is to be signed or encrypted, save this info */
350 + if ((WithCrypto & APPLICATION_PGP) && (hdr->security & APPLICATION_PGP))
352 fputs ("X-Mutt-PGP: ", msg->fp);
353 if (hdr->security & ENCRYPT)
354 @@ -2754,9 +2898,8 @@
355 fputc ('\n', msg->fp);
358 - /* (postponment) if the mail is to be signed or encrypted, save this info */
359 - if ((WithCrypto & APPLICATION_SMIME)
360 - && post && (hdr->security & APPLICATION_SMIME))
361 + /* if the mail is to be signed or encrypted, save this info */
362 + if ((WithCrypto & APPLICATION_SMIME) && (hdr->security & APPLICATION_SMIME))
364 fputs ("X-Mutt-SMIME: ", msg->fp);
365 if (hdr->security & ENCRYPT) {
366 @@ -2775,84 +2718,20 @@
370 - /* (postponement) if the mail is to be sent through a mixmaster
371 + /* if the mail is to be sent through a mixmaster
372 * chain, save that information
375 - if (post && hdr->chain && hdr->chain)
380 fputs ("X-Mutt-Mix:", msg->fp);
381 for (p = hdr->chain; p; p = p->next)
382 fprintf (msg->fp, " %s", (char *) p->data);
384 fputc ('\n', msg->fp);
390 - char sasha[LONG_STRING];
393 - mutt_write_mime_body (hdr->content, tempfp);
395 - /* make sure the last line ends with a newline. Emacs doesn't ensure
396 - * this will happen, and it can cause problems parsing the mailbox
399 - fseek (tempfp, -1, 2);
400 - if (fgetc (tempfp) != '\n')
402 - fseek (tempfp, 0, 2);
403 - fputc ('\n', tempfp);
407 - if (ferror (tempfp))
409 - dprint (1, (debugfile, "mutt_write_fcc(): %s: write failed.\n", tempfile));
410 - safe_fclose (&tempfp);
412 - mx_commit_message (msg, &f); /* XXX - really? */
413 - mx_close_message (&msg);
414 - mx_close_mailbox (&f, NULL);
418 - /* count the number of lines */
420 - while (fgets (sasha, sizeof (sasha), tempfp) != NULL)
422 - fprintf (msg->fp, "Content-Length: " OFF_T_FMT "\n", (LOFF_T) ftello (tempfp));
423 - fprintf (msg->fp, "Lines: %d\n\n", lines);
425 - /* copy the body and clean up */
427 - r = mutt_copy_stream (tempfp, msg->fp);
428 - if (fclose (tempfp) != 0)
430 - /* if there was an error, leave the temp version */
436 - fputc ('\n', msg->fp); /* finish off the header */
437 - r = mutt_write_mime_body (hdr->content, msg->fp);
440 - if (mx_commit_message (msg, &f) != 0)
442 - mx_close_message (&msg);
443 - mx_close_mailbox (&f, NULL);
445 - if (!post && need_buffy_cleanup)
446 - mutt_buffy_cleanup (path, &st);
449 - set_noconv_flags (hdr->content, 0);
452 + ret = mutt_finish_message (mh, path, hdr, &f, &msg, 0);
453 + set_noconv_flags (hdr->content, 0);