Commit 8ad47471 8ad474712f6758cdff637c5391867706957dfd74 by Sergey Poznyakoff

Implement --attach option in mail; fix dead.letter functionality

* NEWS: Update.
* doc/imprimatur: Upgrade.
* libmailutils/mime/attachment.c (mu_message_create_attachment): Bugfixes.
* mail/mail.c: New options --attach, --content-type and
--encoding.
* mail/mail.h (default_encoding, default_content_type): New externs.
(send_attach_file): New proto.
* mail/send.c (send_attach_file): New function.
(save_dead_message_env): New function.
(save_dead_message): Rewrite.
(mail_send0): Attach files, if requested.
1 parent ca45a7aa
1 GNU mailutils NEWS -- history of user-visible changes. 2012-06-07 1 GNU mailutils NEWS -- history of user-visible changes. 2012-07-18
2 Copyright (C) 2002-2012 Free Software Foundation, Inc. 2 Copyright (C) 2002-2012 Free Software Foundation, Inc.
3 See the end of file for copying conditions. 3 See the end of file for copying conditions.
4 4
...@@ -82,7 +82,7 @@ are not used to avoid compromising security. ...@@ -82,7 +82,7 @@ are not used to avoid compromising security.
82 82
83 See <http://mailutils.org/wiki/debug_level>. 83 See <http://mailutils.org/wiki/debug_level>.
84 84
85 ** Imap4d undergone a lot of changes to comply to existing RFCs 85 ** Imap4d underwent a lot of changes to comply to existing RFCs
86 86
87 ** Pop3d and imap4d allow for mailbox-independent compulsory locking 87 ** Pop3d and imap4d allow for mailbox-independent compulsory locking
88 88
...@@ -114,6 +114,27 @@ header field with the given date. ...@@ -114,6 +114,27 @@ header field with the given date.
114 114
115 See <http://mailutils.org/wiki/Timestamp_(Sieve_test)>. 115 See <http://mailutils.org/wiki/Timestamp_(Sieve_test)>.
116 116
117 ** mail: sending attachments
118
119 The mail[x] utility now allows for sending attachments. Any number of
120 files can be attached to the composed letter by using the `--attach'
121 (`-A') options. The files will be attached in the same order in which
122 they appear in the command line. By default, each attachment is
123 assigned the content type "application/octet-stream" and is encoded
124 using Base64. This can be changed using the `--content-type' and
125 `--encoding' options. These options affect all attachments that
126 appear after them in the command line, until next occurrence of the
127 same option or end of command line, whichever occurs first. For
128 example:
129
130 mail -A prog --encoding quoted-printable --content-type text/c \
131 -A main.c -A ext.h
132
133 Here, the file "prog" will be attached witg the content type
134 "application/octet-stream" and encoding base64, while the files
135 "main.c" and "ext.h" will be marked with content type "text/c" and
136 encoded using "quoted-printable" algorithm.
137
117 ** MH: improved compatibility with other implementations 138 ** MH: improved compatibility with other implementations
118 139
119 ** MH inc: new option --moveto 140 ** MH inc: new option --moveto
...@@ -181,12 +202,29 @@ imap4d, pop3d, comsat) will be built. Its counterpart, ...@@ -181,12 +202,29 @@ imap4d, pop3d, comsat) will be built. Its counterpart,
181 `--enable-build-clients' controls whether client utilities will be 202 `--enable-build-clients' controls whether client utilities will be
182 built. 203 built.
183 204
205 The effect of both options is overridden by the `--enable-build-*'
206 options for particular components. For example, to build only
207 the "mail" utility:
208
209 ./configure --disable-build-clients --enable-build-mail
210
211 ** The --with-mailbindir option
212
213 This option changes installation directory for the "mail" utility.
214
184 ** DBM options 215 ** DBM options
185 216
186 It is normally not needed to specify --with-gdbm, --with-berkeley-db 217 It is normally not needed to specify --with-gdbm, --with-berkeley-db
187 or --with-ndbm explicitly. Configuration will automatically pick up 218 or --with-ndbm explicitly. Configuration will automatically pick up
188 all available DBM libraries it can use. 219 all available DBM libraries it can use.
189 220
221 The option `--with-dbm' can be used to enable or disable building of
222 all available DBM interfaces. Its effect is overridden by `--with-*'
223 options for particular interfaces. For example, to build only GDBM
224 (even if another databases are supported by the system):
225
226 ./configure --without-dbm --with-gdbm
227
190 ** Nntp client is not yet implemented 228 ** Nntp client is not yet implemented
191 229
192 ** Link with GSASL by default 230 ** Link with GSASL by default
......
imprimatur @ f32ef198
1 Subproject commit 04255b6d5551952b4e0c94da15988f573e3e9fc4 1 Subproject commit f32ef1983968e755cd580b06e369476d7e7f88b6
......
...@@ -88,12 +88,15 @@ mu_message_create_attachment (const char *content_type, const char *encoding, ...@@ -88,12 +88,15 @@ mu_message_create_attachment (const char *content_type, const char *encoding,
88 "Content-Transfer-Encoding: %s\n" 88 "Content-Transfer-Encoding: %s\n"
89 "Content-Disposition: attachment; filename=%s\n\n", 89 "Content-Disposition: attachment; filename=%s\n\n",
90 content_type, name, encoding, name); 90 content_type, name, encoding, name);
91 if (ret) 91 if (ret == 0)
92 { 92 {
93 if ((ret = mu_header_create (&hdr, header, 93 if ((ret = mu_header_create (&hdr, header,
94 strlen (header))) == 0) 94 strlen (header))) == 0)
95 { 95 {
96 mu_stream_t bstr;
96 mu_message_get_body (*newmsg, &body); 97 mu_message_get_body (*newmsg, &body);
98 mu_body_get_streamref (body, &bstr);
99
97 if ((ret = mu_file_stream_create (&fstream, filename, 100 if ((ret = mu_file_stream_create (&fstream, filename,
98 MU_STREAM_READ)) == 0) 101 MU_STREAM_READ)) == 0)
99 { 102 {
...@@ -101,10 +104,12 @@ mu_message_create_attachment (const char *content_type, const char *encoding, ...@@ -101,10 +104,12 @@ mu_message_create_attachment (const char *content_type, const char *encoding,
101 MU_FILTER_ENCODE, 104 MU_FILTER_ENCODE,
102 MU_STREAM_READ)) == 0) 105 MU_STREAM_READ)) == 0)
103 { 106 {
104 mu_body_set_stream (body, tstream, *newmsg); 107 mu_stream_copy (bstr, tstream, 0, NULL);
108 mu_stream_unref (tstream);
105 mu_message_set_header (*newmsg, hdr, NULL); 109 mu_message_set_header (*newmsg, hdr, NULL);
106 } 110 }
107 } 111 }
112 mu_stream_unref (bstr);
108 free (header); 113 free (header);
109 } 114 }
110 } 115 }
......
...@@ -32,6 +32,8 @@ static char doc[] = N_("GNU mail -- process mail messages.\n" ...@@ -32,6 +32,8 @@ static char doc[] = N_("GNU mail -- process mail messages.\n"
32 static char args_doc[] = N_("[address...]\n-f [OPTION...] [file]\n--file [OPTION...] [file]\n--file=file [OPTION...]"); 32 static char args_doc[] = N_("[address...]\n-f [OPTION...] [file]\n--file [OPTION...] [file]\n--file=file [OPTION...]");
33 33
34 #define F_OPTION 256 34 #define F_OPTION 256
35 #define F_ENCODING 257
36 #define F_CONTENT_TYPE 258
35 37
36 static struct argp_option options[] = { 38 static struct argp_option options[] = {
37 { NULL, 'f', NULL, OPTION_HIDDEN, NULL, 0 }, 39 { NULL, 'f', NULL, OPTION_HIDDEN, NULL, 0 },
...@@ -57,6 +59,12 @@ static struct argp_option options[] = { ...@@ -57,6 +59,12 @@ static struct argp_option options[] = {
57 N_("append given header to the message being sent"), 0}, 59 N_("append given header to the message being sent"), 0},
58 {"exec", 'E', N_("COMMAND"), 0, 60 {"exec", 'E', N_("COMMAND"), 0,
59 N_("execute COMMAND"), 0 }, 61 N_("execute COMMAND"), 0 },
62 {"encoding", F_ENCODING, N_("NAME"), 0,
63 N_("set encoding for subsequent --attach options"), 0 },
64 {"content-type", F_CONTENT_TYPE, N_("TYPE"), 0,
65 N_("set content type for subsequent --attach options"), 0 },
66 {"attach", 'A', N_("FILE"), 0,
67 N_("attach FILE"), 0 },
60 { NULL, 0, NULL, 0, NULL, 0 } 68 { NULL, 0, NULL, 0, NULL, 0 }
61 }; 69 };
62 70
...@@ -85,6 +93,17 @@ parse_opt (int key, char *arg, struct argp_state *state) ...@@ -85,6 +93,17 @@ parse_opt (int key, char *arg, struct argp_state *state)
85 send_append_header (arg); 93 send_append_header (arg);
86 break; 94 break;
87 95
96 case 'A':
97 args->hint |= HINT_SEND_MODE;
98 if (send_attach_file (arg))
99 exit (1);
100 break;
101
102 case F_CONTENT_TYPE:
103 free (default_content_type);
104 default_content_type = mu_strdup (arg);
105 break;
106
88 case 'e': 107 case 'e':
89 util_cache_command (&command_list, "setq mode=exist"); 108 util_cache_command (&command_list, "setq mode=exist");
90 break; 109 break;
...@@ -140,6 +159,11 @@ parse_opt (int key, char *arg, struct argp_state *state) ...@@ -140,6 +159,11 @@ parse_opt (int key, char *arg, struct argp_state *state)
140 util_cache_command (&command_list, "%s", arg); 159 util_cache_command (&command_list, "%s", arg);
141 break; 160 break;
142 161
162 case F_ENCODING:
163 free (default_encoding);
164 default_encoding = mu_strdup (arg);
165 break;
166
143 case 'F': 167 case 'F':
144 util_cache_command (&command_list, "set byname"); 168 util_cache_command (&command_list, "set byname");
145 break; 169 break;
......
...@@ -171,6 +171,8 @@ extern mu_mailbox_t mbox; ...@@ -171,6 +171,8 @@ extern mu_mailbox_t mbox;
171 extern size_t total; 171 extern size_t total;
172 extern int interactive; 172 extern int interactive;
173 extern const char *program_version; 173 extern const char *program_version;
174 extern char *default_encoding;
175 extern char *default_content_type;
174 176
175 /* Functions */ 177 /* Functions */
176 extern int mail_alias (int argc, char **argv); 178 extern int mail_alias (int argc, char **argv);
...@@ -256,6 +258,7 @@ extern char *mail_expand_name (const char *name); ...@@ -256,6 +258,7 @@ extern char *mail_expand_name (const char *name);
256 258
257 extern void send_append_header (char *text); 259 extern void send_append_header (char *text);
258 extern void send_append_header2 (char *name, char *value, int mode); 260 extern void send_append_header2 (char *name, char *value, int mode);
261 extern int send_attach_file (const char *name);
259 262
260 extern int escape_shell (int argc, char **argv, compose_env_t *env); 263 extern int escape_shell (int argc, char **argv, compose_env_t *env);
261 extern int escape_command (int argc, char **argv, compose_env_t *env); 264 extern int escape_command (int argc, char **argv, compose_env_t *env);
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
15 along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ 15 along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
16 16
17 #include "mail.h" 17 #include "mail.h"
18 #include <mailutils/mime.h>
18 #include <sys/types.h> 19 #include <sys/types.h>
19 #include <sys/stat.h> 20 #include <sys/stat.h>
20 #include <fcntl.h> 21 #include <fcntl.h>
...@@ -129,6 +130,233 @@ mail_sendheader (int argc, char **argv) ...@@ -129,6 +130,233 @@ mail_sendheader (int argc, char **argv)
129 return 0; 130 return 0;
130 } 131 }
131 132
133 /* Attachments */
134 struct atchinfo
135 {
136 char *encoding;
137 char *content_type;
138 char *filename;
139 };
140
141 static mu_list_t attlist;
142
143 char *default_encoding;
144 char *default_content_type;
145
146 static void
147 atchinfo_free (void *p)
148 {
149 struct atchinfo *ap = p;
150 free (ap->encoding);
151 free (ap->content_type);
152 free (ap->filename);
153 free (ap);
154 }
155
156 int
157 send_attach_file (const char *name)
158 {
159 int rc;
160 struct stat st;
161 struct atchinfo *aptr;
162
163 if (stat (name, &st))
164 {
165 if (errno == ENOENT)
166 {
167 mu_error (_("%s: file does not exist"), name);
168 return 1;
169 }
170 else
171 {
172 mu_error (_("%s: cannot stat: %s"), name, mu_strerror (errno));
173 return 1;
174 }
175 }
176
177 if (!S_ISREG (st.st_mode))
178 {
179 mu_error (_("%s: not a regular file"), name);
180 return 1;
181 }
182
183 if (!attlist)
184 {
185 rc = mu_list_create (&attlist);
186 if (rc)
187 {
188 mu_diag_funcall (MU_DIAG_ERROR, "mu_list_create", NULL, rc);
189 exit (1);
190 }
191 mu_list_set_destroy_item (attlist, atchinfo_free);
192 }
193 aptr = mu_alloc (sizeof (*aptr));
194 aptr->encoding = mu_strdup (default_encoding ?
195 default_encoding : "base64");
196 aptr->content_type = mu_strdup (default_content_type ?
197 default_content_type :
198 "application/octet-stream");
199 aptr->filename = mu_strdup (name);
200 rc = mu_list_append (attlist, aptr);
201 if (rc)
202 {
203 mu_diag_funcall (MU_DIAG_ERROR, "mu_list_append", NULL, rc);
204 exit (1);
205 }
206 return 0;
207 }
208
209 static int
210 saveatt (void *item, void *data)
211 {
212 struct atchinfo *aptr = item;
213 mu_mime_t mime = data;
214 mu_message_t part;
215 mu_header_t hdr;
216 int rc;
217 size_t nparts;
218 char *p;
219
220 rc = mu_message_create_attachment (aptr->content_type, aptr->encoding,
221 aptr->filename, &part);
222 if (rc)
223 {
224 mu_error (_("cannot attach \"%s\": %s"), aptr->filename,
225 mu_strerror (rc));
226 return 1;
227 }
228
229 mu_mime_get_num_parts (mime, &nparts);
230 mu_message_get_header (part, &hdr);
231 mu_rfc2822_msg_id (nparts, &p);
232 mu_header_set_value (hdr, MU_HEADER_CONTENT_ID, p, 1);
233 free (p);
234
235 rc = mu_mime_add_part (mime, part);
236 mu_message_unref (part);
237 if (rc)
238 {
239 mu_diag_funcall (MU_DIAG_ERROR, "mu_mime_add_part", aptr->filename, rc);
240 return 1;
241 }
242
243 return 0;
244 }
245
246 static int
247 add_attachments (mu_message_t *pmsg, mu_mime_t *pmime)
248 {
249 mu_message_t inmsg, outmsg, part;
250 mu_body_t body;
251 mu_header_t inhdr, outhdr;
252 mu_iterator_t itr;
253 mu_mime_t mime;
254 mu_stream_t str, output;
255 int rc;
256 char *p;
257
258 if (mu_list_is_empty (attlist))
259 {
260 *pmime = NULL;
261 return 0;
262 }
263
264 inmsg = *pmsg;
265
266 /* Create a mime object */
267 rc = mu_mime_create (&mime, NULL, 0);
268 if (rc)
269 {
270 mu_diag_funcall (MU_DIAG_ERROR, "mu_mime_create", NULL, rc);
271 return 1;
272 }
273
274 /* Add original message as its first part */
275 /* 1. Create the part and obtain a reference to its stream */
276 mu_message_create (&part, NULL);
277 mu_message_get_body (part, &body);
278 mu_body_get_streamref (body, &output);
279
280 /* 2. Get original body stream and copy it out to the part's body */
281 mu_message_get_body (inmsg, &body);
282 mu_body_get_streamref (body, &str);
283 mu_stream_copy (output, str, 0, NULL);
284
285 mu_stream_close (output);
286 mu_stream_destroy (&output);
287
288 mu_message_get_header (inmsg, &inhdr);
289 mu_header_get_iterator (inhdr, &itr);
290
291 /* 3. Copy "Content-*" headers from the original message */
292 mu_message_get_header (part, &outhdr);
293 for (mu_iterator_first (itr); !mu_iterator_is_done (itr);
294 mu_iterator_next (itr))
295 {
296 const char *name, *value;
297
298 if (mu_iterator_current_kv (itr, (const void **)&name,
299 (void**)&value) == 0)
300 {
301 if (mu_c_strncasecmp (name, "Content-", 8) == 0)
302 mu_header_set_value (outhdr, name, value, 0);
303 }
304 }
305
306 /* 4. Add the content type and content ID headers. */
307 mu_header_set_value (outhdr, MU_HEADER_CONTENT_TYPE, "text/plain", 0);
308 mu_rfc2822_msg_id (0, &p);
309 mu_header_set_value (outhdr, MU_HEADER_CONTENT_ID, p, 1);
310 free (p);
311
312 /* 5. Add part to the mime object */
313 mu_mime_add_part (mime, part);
314 mu_message_unref (part);
315
316 /* Add the respective attachments */
317 rc = mu_list_foreach (attlist, saveatt, mime);
318 if (rc)
319 {
320 mu_mime_destroy (&mime);
321 return 1;
322 }
323
324 /* Get the resulting message */
325 rc = mu_mime_get_message (mime, &outmsg);
326
327 if (rc)
328 {
329 mu_diag_funcall (MU_DIAG_ERROR, "mu_mime_get_message", NULL, rc);
330 mu_mime_destroy (&mime);
331 return 1;
332 }
333
334 /* Copy rest of headers from the original message */
335 mu_message_get_header (outmsg, &outhdr);
336 for (mu_iterator_first (itr); !mu_iterator_is_done (itr);
337 mu_iterator_next (itr))
338 {
339 const char *name, *value;
340
341 if (mu_iterator_current_kv (itr, (const void **)&name,
342 (void**)&value) == 0)
343 {
344 if (mu_c_strcasecmp (name, MU_HEADER_MIME_VERSION) == 0 ||
345 mu_c_strncasecmp (name, "Content-", 8) == 0)
346 continue;
347 mu_header_append (outhdr, name, value);
348 }
349 }
350 mu_iterator_destroy (&itr);
351
352 mu_message_unref (outmsg);
353 mu_message_unref (inmsg);
354 *pmsg = outmsg;
355 *pmime = mime;
356 return 0;
357 }
358
359
132 360
133 /* Send-related commands */ 361 /* Send-related commands */
134 362
...@@ -342,17 +570,21 @@ fill_body (mu_message_t msg, mu_stream_t instr) ...@@ -342,17 +570,21 @@ fill_body (mu_message_t msg, mu_stream_t instr)
342 } 570 }
343 571
344 static int 572 static int
345 save_dead_message (compose_env_t *env) 573 save_dead_message_env (compose_env_t *env)
346 { 574 {
347 if (mailvar_get (NULL, "save", mailvar_type_boolean, 0) == 0) 575 if (mailvar_get (NULL, "save", mailvar_type_boolean, 0) == 0)
348 { 576 {
349 mu_stream_t dead_letter; 577 mu_stream_t dead_letter, str;
350 int rc; 578 int rc;
579 time_t t;
580 struct tm *tm;
351 const char *name = getenv ("DEAD"); 581 const char *name = getenv ("DEAD");
582 char *sender;
352 583
353 /* FIXME: Use MU_STREAM_APPEND if appenddeadletter, instead of the 584 /* FIXME: Use MU_STREAM_APPEND if appenddeadletter, instead of the
354 stream manipulations below */ 585 stream manipulations below */
355 rc = mu_file_stream_create (&dead_letter, name, MU_STREAM_WRITE); 586 rc = mu_file_stream_create (&dead_letter, name,
587 MU_STREAM_CREAT|MU_STREAM_WRITE);
356 if (rc) 588 if (rc)
357 { 589 {
358 mu_error (_("Cannot open file %s: %s"), name, strerror (rc)); 590 mu_error (_("Cannot open file %s: %s"), name, strerror (rc));
...@@ -364,8 +596,73 @@ save_dead_message (compose_env_t *env) ...@@ -364,8 +596,73 @@ save_dead_message (compose_env_t *env)
364 else 596 else
365 mu_stream_truncate (dead_letter, 0); 597 mu_stream_truncate (dead_letter, 0);
366 598
599 time (&t);
600 tm = gmtime (&t);
601 sender = mu_get_user_email (NULL);
602 if (!sender)
603 sender = mu_strdup ("UNKNOWN");
604 mu_stream_printf (dead_letter, "From %s ", sender);
605 free (sender);
606 mu_c_streamftime (dead_letter, "%c%n", tm, NULL);
607
608 if (mu_header_get_streamref (env->header, &str) == 0)
609 {
610 mu_stream_copy (dead_letter, str, 0, NULL);
611 mu_stream_unref (str);
612 }
613 else
614 mu_stream_write (dead_letter, "\n", 1, NULL);
615
367 mu_stream_seek (env->compstr, 0, MU_SEEK_SET, NULL); 616 mu_stream_seek (env->compstr, 0, MU_SEEK_SET, NULL);
368 mu_stream_copy (dead_letter, env->compstr, 0, NULL); 617 mu_stream_copy (dead_letter, env->compstr, 0, NULL);
618 mu_stream_write (dead_letter, "\n", 1, NULL);
619 mu_stream_destroy (&dead_letter);
620 }
621 return 0;
622 }
623
624 static int
625 save_dead_message (mu_message_t msg)
626 {
627 if (mailvar_get (NULL, "save", mailvar_type_boolean, 0) == 0)
628 {
629 mu_stream_t dead_letter, str;
630 int rc;
631 time_t t;
632 struct tm *tm;
633 const char *name = getenv ("DEAD");
634 char *sender;
635
636 /* FIXME: Use MU_STREAM_APPEND if appenddeadletter, instead of the
637 stream manipulations below */
638 rc = mu_file_stream_create (&dead_letter, name,
639 MU_STREAM_CREAT|MU_STREAM_WRITE);
640 if (rc)
641 {
642 mu_error (_("Cannot open file %s: %s"), name, strerror (rc));
643 return 1;
644 }
645 if (mailvar_get (NULL, "appenddeadletter",
646 mailvar_type_boolean, 0) == 0)
647 mu_stream_seek (dead_letter, 0, MU_SEEK_END, NULL);
648 else
649 mu_stream_truncate (dead_letter, 0);
650
651 time (&t);
652 tm = gmtime (&t);
653 sender = mu_get_user_email (NULL);
654 if (!sender)
655 sender = mu_strdup ("UNKNOWN");
656 mu_stream_printf (dead_letter, "From %s ", sender);
657 free (sender);
658 mu_c_streamftime (dead_letter, "%c%n", tm, NULL);
659
660 if (mu_message_get_streamref (msg, &str) == 0)
661 {
662 mu_stream_copy (dead_letter, str, 0, NULL);
663 mu_stream_unref (str);
664 }
665 mu_stream_write (dead_letter, "\n", 1, NULL);
369 mu_stream_destroy (&dead_letter); 666 mu_stream_destroy (&dead_letter);
370 } 667 }
371 return 0; 668 return 0;
...@@ -445,6 +742,7 @@ mail_send0 (compose_env_t *env, int save_to) ...@@ -445,6 +742,7 @@ mail_send0 (compose_env_t *env, int save_to)
445 if (rc) 742 if (rc)
446 { 743 {
447 mu_error (_("Cannot open temporary file: %s"), mu_strerror (rc)); 744 mu_error (_("Cannot open temporary file: %s"), mu_strerror (rc));
745 mu_list_destroy (&attlist);
448 return 1; 746 return 1;
449 } 747 }
450 748
...@@ -541,8 +839,9 @@ mail_send0 (compose_env_t *env, int save_to) ...@@ -541,8 +839,9 @@ mail_send0 (compose_env_t *env, int save_to)
541 /* If interrupted, dump the file to dead.letter. */ 839 /* If interrupted, dump the file to dead.letter. */
542 if (int_cnt) 840 if (int_cnt)
543 { 841 {
544 save_dead_message (env); 842 save_dead_message_env (env);
545 mu_stream_destroy (&env->compstr); 843 mu_stream_destroy (&env->compstr);
844 mu_list_destroy (&attlist);
546 return 1; 845 return 1;
547 } 846 }
548 847
...@@ -558,18 +857,30 @@ mail_send0 (compose_env_t *env, int save_to) ...@@ -558,18 +857,30 @@ mail_send0 (compose_env_t *env, int save_to)
558 857
559 if (util_header_expand (&env->header) == 0) 858 if (util_header_expand (&env->header) == 0)
560 { 859 {
860 mu_mime_t mime = NULL;
561 mu_message_t msg = NULL; 861 mu_message_t msg = NULL;
562 int rc;
563 int status = 0; 862 int status = 0;
564 863 int sendit = (compose_header_get (env, MU_HEADER_TO, NULL) ||
565 mu_message_create (&msg, NULL); 864 compose_header_get (env, MU_HEADER_CC, NULL) ||
566 865 compose_header_get (env, MU_HEADER_BCC, NULL));
866 do
867 {
868 status = mu_message_create (&msg, NULL);
869 if (status)
870 break;
567 /* Fill the body. */ 871 /* Fill the body. */
568 mu_stream_seek (env->compstr, 0, MU_SEEK_SET, NULL); 872 mu_stream_seek (env->compstr, 0, MU_SEEK_SET, NULL);
569 rc = fill_body (msg, env->compstr); 873 status = fill_body (msg, env->compstr);
874 if (status)
875 break;
876
877 mu_message_set_header (msg, env->header, NULL);
878 env->header = NULL;
879
880 status = add_attachments (&msg, &mime);
881 if (status)
882 break;
570 883
571 if (rc == 0)
572 {
573 /* Save outgoing message */ 884 /* Save outgoing message */
574 if (save_to) 885 if (save_to)
575 { 886 {
...@@ -628,30 +939,29 @@ mail_send0 (compose_env_t *env, int save_to) ...@@ -628,30 +939,29 @@ mail_send0 (compose_env_t *env, int save_to)
628 } 939 }
629 940
630 /* Do we need to Send the message on the wire? */ 941 /* Do we need to Send the message on the wire? */
631 if (status == 0 && 942 if (status == 0 && sendit)
632 (compose_header_get (env, MU_HEADER_TO, NULL) ||
633 compose_header_get (env, MU_HEADER_CC, NULL) ||
634 compose_header_get (env, MU_HEADER_BCC, NULL)))
635 { 943 {
636 mu_message_set_header (msg, env->header, NULL);
637 env->header = NULL;
638 status = send_message (msg); 944 status = send_message (msg);
639 if (status) 945 if (status)
640 { 946 {
641 mu_error (_("cannot send message: %s"), 947 mu_error (_("cannot send message: %s"),
642 mu_strerror (status)); 948 mu_strerror (status));
643 save_dead_message (env); 949 save_dead_message (msg);
644 } 950 }
645 } 951 }
646 } 952 }
953 while (0);
954
647 mu_stream_destroy (&env->compstr); 955 mu_stream_destroy (&env->compstr);
648 mu_message_destroy (&msg, NULL); 956 mu_message_destroy (&msg, NULL);
957 mu_mime_destroy (&mime);
649 return status; 958 return status;
650 } 959 }
651 else 960 else
652 save_dead_message (env); 961 save_dead_message_env (env);
653 962
654 mu_stream_destroy (&env->compstr); 963 mu_stream_destroy (&env->compstr);
964 mu_list_destroy (&attlist);
655 return 1; 965 return 1;
656 } 966 }
657 967
......