Send multipart/alternative messages using mail.
The new option --alternative is provided to change the content type of the composed message to multipart/alternative. The ~/ escape toggles the type between multipart/mixed and multipart/alternative. In messages of multipart/alternative type, the Content-Disposition header of all attachments is reset to "inline". * libmailutils/mime/mime.c (mu_mime_create): Bugfix: honour the MU_MIME_MULTIPART_ALT flag. * mail/mail.c: New option --alternative. * mail/mail.h (compose_env) <attlist,mime>: New members. (multipart_alternative): New global. (send_attach_file): Change return value. (escape_toggle_multipart_type): New proto. * mail/send.c (multipart_alternative): New global. Keep the list of attachments in compose_env_t. Make sure it is freed when no longer used. Implement the ~/ escape. * mail/table.c: New escape ~/ * mail/util.c: Use mu_strerror instead of strerror. * NEWS: Document changes to the mail utility * doc/texinfo/programs.texi: Likewise.
Showing
8 changed files
with
222 additions
and
83 deletions
1 | GNU mailutils NEWS -- history of user-visible changes. 2017-04-09 | 1 | GNU mailutils NEWS -- history of user-visible changes. 2017-04-13 |
2 | Copyright (C) 2002-2017 Free Software Foundation, Inc. | 2 | Copyright (C) 2002-2017 Free Software Foundation, Inc. |
3 | See the end of file for copying conditions. | 3 | See the end of file for copying conditions. |
4 | 4 | ||
... | @@ -88,6 +88,21 @@ defined. Instead, the following constants are defined in config.h: | ... | @@ -88,6 +88,21 @@ defined. Instead, the following constants are defined in config.h: |
88 | 88 | ||
89 | * movemail: new option --progress-meter | 89 | * movemail: new option --progress-meter |
90 | 90 | ||
91 | * mail: sending multipart messages | ||
92 | |||
93 | ** New option --alternative | ||
94 | |||
95 | When used with --attach or --attach-fd options, this option sets the | ||
96 | Content-Type of the constructed message to "multipart/alternative". | ||
97 | In the absense of this option, the type is "multipart/mixed". | ||
98 | |||
99 | ** New escape ~/ | ||
100 | |||
101 | New escape ~/ toggles the Content-Type of the message being composed | ||
102 | between "multipart/mixed" and "multipart/alternative". | ||
103 | |||
104 | The actual Content-Type is displayed by the ~l (list attachments) escape. | ||
105 | |||
91 | * scheme implementation of the Sieve language discontinued | 106 | * scheme implementation of the Sieve language discontinued |
92 | 107 | ||
93 | There's no reason to keep two different implementations of the Sieve | 108 | There's no reason to keep two different implementations of the Sieve | ... | ... |
... | @@ -3420,12 +3420,19 @@ To list the files attached so far, use the @samp{~l} escape: | ... | @@ -3420,12 +3420,19 @@ To list the files attached so far, use the @samp{~l} escape: |
3420 | 3420 | ||
3421 | @example | 3421 | @example |
3422 | ~l | 3422 | ~l |
3423 | multipart/mixed | ||
3423 | 1 myfile.html text/html base64 | 3424 | 1 myfile.html text/html base64 |
3424 | @end example | 3425 | @end example |
3425 | 3426 | ||
3426 | Each line of the listing contains the ordinal number of the attachment, | 3427 | The first line of the output shows the content type of the message. |
3428 | Each subsequent line contains the ordinal number of the attachment, | ||
3427 | the name of the file, content-type and transfer encoding used. | 3429 | the name of the file, content-type and transfer encoding used. |
3428 | 3430 | ||
3431 | @cindex ~/, mail escape | ||
3432 | The @samp{~/} escape toggles the content type bewteen | ||
3433 | @samp{multipart/mixed}, and @samp{multipart/alternative}. The new | ||
3434 | value of the content type is displayed on the screen. | ||
3435 | |||
3429 | @cindex ~^, mail escape | 3436 | @cindex ~^, mail escape |
3430 | The @samp{~^} escape removes attachments. Its argument is the number | 3437 | The @samp{~^} escape removes attachments. Its argument is the number |
3431 | of the attachment to remove, e.g.: | 3438 | of the attachment to remove, e.g.: |
... | @@ -3568,6 +3575,12 @@ either or both of them using the @option{--content-name} and | ... | @@ -3568,6 +3575,12 @@ either or both of them using the @option{--content-name} and |
3568 | affect only the next @option{--attach} (or @option{--attach-fd}, see | 3575 | affect only the next @option{--attach} (or @option{--attach-fd}, see |
3569 | below) option. | 3576 | below) option. |
3570 | 3577 | ||
3578 | By default, the message will be assigned the content type | ||
3579 | @samp{multipart/mixed}. To change it to @samp{multipart/alternative}, | ||
3580 | use the @option{--alternative} command line option. Using this option | ||
3581 | also sets the @samp{Content-Disposition} header of each attached | ||
3582 | message to @samp{inline}. | ||
3583 | |||
3571 | All the examples above will enter the usual interactive shell, | 3584 | All the examples above will enter the usual interactive shell, |
3572 | allowing you to compose the body of the message. If that's not | 3585 | allowing you to compose the body of the message. If that's not |
3573 | needed, the non-interactive use can be forced by redirecting | 3586 | needed, the non-interactive use can be forced by redirecting | ... | ... |
... | @@ -879,6 +879,9 @@ _mime_body_lines (mu_body_t body, size_t *plines) | ... | @@ -879,6 +879,9 @@ _mime_body_lines (mu_body_t body, size_t *plines) |
879 | return 0; | 879 | return 0; |
880 | } | 880 | } |
881 | 881 | ||
882 | #define MIME_MULTIPART_FLAGS \ | ||
883 | (MU_MIME_MULTIPART_MIXED|MU_MIME_MULTIPART_ALT) | ||
884 | |||
882 | int | 885 | int |
883 | mu_mime_create (mu_mime_t *pmime, mu_message_t msg, int flags) | 886 | mu_mime_create (mu_mime_t *pmime, mu_message_t msg, int flags) |
884 | { | 887 | { |
... | @@ -886,9 +889,19 @@ mu_mime_create (mu_mime_t *pmime, mu_message_t msg, int flags) | ... | @@ -886,9 +889,19 @@ mu_mime_create (mu_mime_t *pmime, mu_message_t msg, int flags) |
886 | int ret = 0; | 889 | int ret = 0; |
887 | size_t size; | 890 | size_t size; |
888 | mu_body_t body; | 891 | mu_body_t body; |
889 | 892 | ||
890 | if (pmime == NULL) | 893 | if (pmime == NULL) |
891 | return EINVAL; | 894 | return EINVAL; |
895 | |||
896 | switch (flags & MIME_MULTIPART_FLAGS) | ||
897 | { | ||
898 | case MIME_MULTIPART_FLAGS: | ||
899 | return EINVAL; | ||
900 | |||
901 | case 0: | ||
902 | flags |= MU_MIME_MULTIPART_MIXED; | ||
903 | } | ||
904 | |||
892 | *pmime = NULL; | 905 | *pmime = NULL; |
893 | if ((mime = calloc (1, sizeof (*mime))) == NULL) | 906 | if ((mime = calloc (1, sizeof (*mime))) == NULL) |
894 | return ENOMEM; | 907 | return ENOMEM; |
... | @@ -931,7 +944,7 @@ mu_mime_create (mu_mime_t *pmime, mu_message_t msg, int flags) | ... | @@ -931,7 +944,7 @@ mu_mime_create (mu_mime_t *pmime, mu_message_t msg, int flags) |
931 | } | 944 | } |
932 | else | 945 | else |
933 | { | 946 | { |
934 | mime->flags |= MIME_NEW_MESSAGE | MU_MIME_MULTIPART_MIXED; | 947 | mime->flags |= MIME_NEW_MESSAGE; |
935 | } | 948 | } |
936 | if (ret != 0) | 949 | if (ret != 0) |
937 | { | 950 | { | ... | ... |
... | @@ -146,9 +146,8 @@ cli_attach (struct mu_parseopt *po, struct mu_option *opt, char const *arg) | ... | @@ -146,9 +146,8 @@ cli_attach (struct mu_parseopt *po, struct mu_option *opt, char const *arg) |
146 | arg = NULL; | 146 | arg = NULL; |
147 | fd = 0; | 147 | fd = 0; |
148 | } | 148 | } |
149 | if (send_attach_file (fd, arg, content_filename, content_name, | 149 | send_attach_file (fd, arg, content_filename, content_name, |
150 | default_content_type, default_encoding)) | 150 | default_content_type, default_encoding); |
151 | exit (1); | ||
152 | 151 | ||
153 | free (content_name); | 152 | free (content_name); |
154 | content_name = NULL; | 153 | content_name = NULL; |
... | @@ -169,9 +168,8 @@ cli_attach_fd (struct mu_parseopt *po, struct mu_option *opt, char const *arg) | ... | @@ -169,9 +168,8 @@ cli_attach_fd (struct mu_parseopt *po, struct mu_option *opt, char const *arg) |
169 | exit (po->po_exit_error); | 168 | exit (po->po_exit_error); |
170 | } | 169 | } |
171 | 170 | ||
172 | if (send_attach_file (fd, NULL, content_filename, content_name, | 171 | send_attach_file (fd, NULL, content_filename, content_name, |
173 | default_content_type, default_encoding)) | 172 | default_content_type, default_encoding); |
174 | exit (1); | ||
175 | 173 | ||
176 | free (content_name); | 174 | free (content_name); |
177 | content_name = NULL; | 175 | content_name = NULL; |
... | @@ -240,6 +238,10 @@ static struct mu_option mail_options[] = { | ... | @@ -240,6 +238,10 @@ static struct mu_option mail_options[] = { |
240 | N_("append given header to the message being sent"), | 238 | N_("append given header to the message being sent"), |
241 | mu_c_string, NULL, cli_append }, | 239 | mu_c_string, NULL, cli_append }, |
242 | 240 | ||
241 | { "alternative", 0, NULL, MU_OPTION_DEFAULT, | ||
242 | N_("force multipart/alternative content type"), | ||
243 | mu_c_bool, &multipart_alternative }, | ||
244 | |||
243 | { "skip-empty-attachments", 0, NULL, MU_OPTION_DEFAULT, | 245 | { "skip-empty-attachments", 0, NULL, MU_OPTION_DEFAULT, |
244 | N_("skip attachments with empty body"), | 246 | N_("skip attachments with empty body"), |
245 | mu_c_bool, &skip_empty_attachments }, | 247 | mu_c_bool, &skip_empty_attachments }, | ... | ... |
... | @@ -99,10 +99,13 @@ typedef int function_t (int, char **); | ... | @@ -99,10 +99,13 @@ typedef int function_t (int, char **); |
99 | typedef struct compose_env | 99 | typedef struct compose_env |
100 | { | 100 | { |
101 | mu_header_t header; /* The message headers */ | 101 | mu_header_t header; /* The message headers */ |
102 | mu_stream_t compstr; /* Temporary compose stream */ | 102 | mu_stream_t compstr; /* Temporary compose stream */ |
103 | char **outfiles; /* Names of the output files. The message is to be | 103 | char **outfiles; /* Names of the output files. The message is to be |
104 | saved in each of these. */ | 104 | saved in each of these. */ |
105 | int nfiles; /* Number of output files */ | 105 | int nfiles; /* Number of output files */ |
106 | int alt; /* Use multipart/alternative type */ | ||
107 | mu_list_t attlist; /* Attachments */ | ||
108 | mu_mime_t mime; /* Associated MIME object */ | ||
106 | } compose_env_t; | 109 | } compose_env_t; |
107 | 110 | ||
108 | #define MAIL_COMMAND_COMMON_MEMBERS \ | 111 | #define MAIL_COMMAND_COMMON_MEMBERS \ |
... | @@ -174,7 +177,8 @@ extern const char *program_version; | ... | @@ -174,7 +177,8 @@ extern const char *program_version; |
174 | extern char *default_encoding; | 177 | extern char *default_encoding; |
175 | extern char *default_content_type; | 178 | extern char *default_content_type; |
176 | extern int skip_empty_attachments; | 179 | extern int skip_empty_attachments; |
177 | 180 | extern int multipart_alternative; | |
181 | |||
178 | /* Functions */ | 182 | /* Functions */ |
179 | extern int mail_alias (int argc, char **argv); | 183 | extern int mail_alias (int argc, char **argv); |
180 | extern int mail_alt (int argc, char **argv); /* command alternates */ | 184 | extern int mail_alt (int argc, char **argv); /* command alternates */ |
... | @@ -259,11 +263,11 @@ extern char *mail_expand_name (const char *name); | ... | @@ -259,11 +263,11 @@ extern char *mail_expand_name (const char *name); |
259 | 263 | ||
260 | extern void send_append_header (char const *text); | 264 | extern void send_append_header (char const *text); |
261 | extern void send_append_header2 (char const *name, char const *value, int mode); | 265 | extern void send_append_header2 (char const *name, char const *value, int mode); |
262 | extern int send_attach_file (int fd, | 266 | extern void send_attach_file (int fd, |
263 | const char *filename, | 267 | const char *filename, |
264 | const char *content_filename, | 268 | const char *content_filename, |
265 | const char *content_name, | 269 | const char *content_name, |
266 | const char *content_type, const char *encoding); | 270 | const char *content_type, const char *encoding); |
267 | 271 | ||
268 | extern int escape_check_args (int argc, char **argv, int minargs, int maxargs); | 272 | extern int escape_check_args (int argc, char **argv, int minargs, int maxargs); |
269 | 273 | ||
... | @@ -292,6 +296,8 @@ extern int escape_list_attachments (int argc, char **argv, | ... | @@ -292,6 +296,8 @@ extern int escape_list_attachments (int argc, char **argv, |
292 | extern int escape_attach (int argc, char **argv, compose_env_t *env); | 296 | extern int escape_attach (int argc, char **argv, compose_env_t *env); |
293 | extern int escape_remove_attachment (int argc, char **argv, | 297 | extern int escape_remove_attachment (int argc, char **argv, |
294 | compose_env_t *env); | 298 | compose_env_t *env); |
299 | extern int escape_toggle_multipart_type (int argc, char **argv, | ||
300 | compose_env_t *env); | ||
295 | 301 | ||
296 | enum | 302 | enum |
297 | { | 303 | { | ... | ... |
... | @@ -24,6 +24,8 @@ | ... | @@ -24,6 +24,8 @@ |
24 | static int isfilename (const char *); | 24 | static int isfilename (const char *); |
25 | static int msg_to_pipe (const char *cmd, mu_message_t msg); | 25 | static int msg_to_pipe (const char *cmd, mu_message_t msg); |
26 | 26 | ||
27 | int multipart_alternative; | ||
28 | |||
27 | 29 | ||
28 | /* Additional message headers */ | 30 | /* Additional message headers */ |
29 | struct add_header | 31 | struct add_header |
... | @@ -143,8 +145,6 @@ struct atchinfo | ... | @@ -143,8 +145,6 @@ struct atchinfo |
143 | int skip_empty; | 145 | int skip_empty; |
144 | }; | 146 | }; |
145 | 147 | ||
146 | static mu_list_t attlist; | ||
147 | |||
148 | static void | 148 | static void |
149 | atchinfo_free (void *p) | 149 | atchinfo_free (void *p) |
150 | { | 150 | { |
... | @@ -158,19 +158,63 @@ atchinfo_free (void *p) | ... | @@ -158,19 +158,63 @@ atchinfo_free (void *p) |
158 | free (ap); | 158 | free (ap); |
159 | } | 159 | } |
160 | 160 | ||
161 | static mu_list_t | ||
162 | attlist_new (void) | ||
163 | { | ||
164 | mu_list_t lst; | ||
165 | int rc = mu_list_create (&lst); | ||
166 | if (rc) | ||
167 | { | ||
168 | mu_diag_funcall (MU_DIAG_ERROR, "mu_list_create", NULL, rc); | ||
169 | exit (1); | ||
170 | } | ||
171 | mu_list_set_destroy_item (lst, atchinfo_free); | ||
172 | return lst; | ||
173 | } | ||
174 | |||
175 | static void | ||
176 | attlist_add (mu_list_t attlist, char *id, char const *encoding, | ||
177 | char const *content_type, char const *content_name, | ||
178 | char const *content_filename, | ||
179 | mu_stream_t stream, int skip_empty) | ||
180 | { | ||
181 | struct atchinfo *aptr; | ||
182 | int rc; | ||
183 | |||
184 | aptr = mu_alloc (sizeof (*aptr)); | ||
185 | |||
186 | aptr->id = id ? mu_strdup (id) : id; | ||
187 | aptr->encoding = mu_strdup (encoding); | ||
188 | aptr->content_type = mu_strdup (content_type ? | ||
189 | content_type : "application/octet-stream"); | ||
190 | aptr->name = content_name ? mu_strdup (content_name) : NULL; | ||
191 | aptr->filename = content_filename ? mu_strdup (content_filename) : NULL; | ||
192 | aptr->source = stream; | ||
193 | if (stream) | ||
194 | mu_stream_ref (stream); | ||
195 | aptr->skip_empty = skip_empty; | ||
196 | rc = mu_list_append (attlist, aptr); | ||
197 | if (rc) | ||
198 | { | ||
199 | mu_diag_funcall (MU_DIAG_ERROR, "mu_list_append", NULL, rc); | ||
200 | exit (1); | ||
201 | } | ||
202 | } | ||
203 | |||
161 | int | 204 | int |
162 | send_attach_file (int fd, | 205 | attlist_attach_file (mu_list_t *attlist_ptr, |
163 | const char *realname, | 206 | int fd, |
164 | const char *content_filename, const char *content_name, | 207 | const char *realname, |
165 | const char *content_type, const char *encoding) | 208 | const char *content_filename, const char *content_name, |
209 | const char *content_type, const char *encoding) | ||
166 | { | 210 | { |
167 | int rc; | 211 | int rc; |
168 | struct stat st; | 212 | struct stat st; |
169 | struct atchinfo *aptr; | ||
170 | mu_list_t list; | 213 | mu_list_t list; |
171 | mu_stream_t stream = NULL; | 214 | mu_stream_t stream = NULL; |
172 | char *id = NULL; | 215 | char *id = NULL; |
173 | 216 | mu_list_t attlist; | |
217 | |||
174 | if (fd >= 0) | 218 | if (fd >= 0) |
175 | { | 219 | { |
176 | rc = mu_fd_stream_create (&stream, NULL, fd, MU_STREAM_READ); | 220 | rc = mu_fd_stream_create (&stream, NULL, fd, MU_STREAM_READ); |
... | @@ -238,32 +282,75 @@ send_attach_file (int fd, | ... | @@ -238,32 +282,75 @@ send_attach_file (int fd, |
238 | return 1; | 282 | return 1; |
239 | } | 283 | } |
240 | 284 | ||
241 | if (!attlist) | 285 | if (!*attlist_ptr) |
242 | { | 286 | { |
243 | rc = mu_list_create (&attlist); | 287 | attlist = attlist_new (); |
244 | if (rc) | 288 | *attlist_ptr = attlist; |
245 | { | ||
246 | mu_diag_funcall (MU_DIAG_ERROR, "mu_list_create", NULL, rc); | ||
247 | exit (1); | ||
248 | } | ||
249 | mu_list_set_destroy_item (attlist, atchinfo_free); | ||
250 | } | 289 | } |
251 | aptr = mu_alloc (sizeof (*aptr)); | 290 | else |
291 | attlist = *attlist_ptr; | ||
292 | |||
293 | attlist_add (attlist, id, encoding, content_type, | ||
294 | content_name, content_filename, | ||
295 | stream, skip_empty_attachments); | ||
296 | if (stream) | ||
297 | mu_stream_unref (stream); | ||
298 | free (id); | ||
252 | 299 | ||
253 | aptr->id = id; | 300 | return 0; |
254 | aptr->encoding = mu_strdup (encoding); | 301 | } |
255 | aptr->content_type = mu_strdup (content_type ? | 302 | |
256 | content_type : "application/octet-stream"); | 303 | static int |
257 | aptr->name = content_name ? mu_strdup (content_name) : NULL; | 304 | attlist_helper (void *item, void *data) |
258 | aptr->filename = content_filename ? mu_strdup (content_filename) : NULL; | 305 | { |
259 | aptr->source = stream; | 306 | struct atchinfo *aptr = item; |
260 | aptr->skip_empty = skip_empty_attachments; | 307 | mu_list_t list = data; |
261 | rc = mu_list_append (attlist, aptr); | 308 | attlist_add (list, aptr->id, aptr->encoding, aptr->content_type, |
262 | if (rc) | 309 | aptr->name, aptr->filename, aptr->source, aptr->skip_empty); |
263 | { | 310 | return 0; |
264 | mu_diag_funcall (MU_DIAG_ERROR, "mu_list_append", NULL, rc); | 311 | } |
265 | exit (1); | 312 | |
266 | } | 313 | static mu_list_t |
314 | attlist_copy (mu_list_t src) | ||
315 | { | ||
316 | mu_list_t dst; | ||
317 | |||
318 | if (!src) | ||
319 | return NULL; | ||
320 | dst = attlist_new (); | ||
321 | mu_list_foreach (src, attlist_helper, dst); | ||
322 | return dst; | ||
323 | } | ||
324 | |||
325 | static mu_list_t attachment_list; | ||
326 | |||
327 | void | ||
328 | send_attach_file (int fd, | ||
329 | const char *realname, | ||
330 | const char *content_filename, const char *content_name, | ||
331 | const char *content_type, const char *encoding) | ||
332 | { | ||
333 | attlist_attach_file (&attachment_list, | ||
334 | fd, | ||
335 | realname, | ||
336 | content_filename, | ||
337 | content_name, | ||
338 | content_type, | ||
339 | encoding); | ||
340 | } | ||
341 | |||
342 | static void | ||
343 | report_multipart_type (compose_env_t *env) | ||
344 | { | ||
345 | mu_printf ("multipart/%s\n", env->alt ? "alternative" : "mixed"); | ||
346 | } | ||
347 | |||
348 | /* ~/ - toggle between multipart/mixed and multipart/alternative */ | ||
349 | int | ||
350 | escape_toggle_multipart_type (int argc, char **argv, compose_env_t *env) | ||
351 | { | ||
352 | env->alt = !env->alt; | ||
353 | report_multipart_type (env); | ||
267 | return 0; | 354 | return 0; |
268 | } | 355 | } |
269 | 356 | ||
... | @@ -273,8 +360,10 @@ escape_list_attachments (int argc, char **argv, compose_env_t *env) | ... | @@ -273,8 +360,10 @@ escape_list_attachments (int argc, char **argv, compose_env_t *env) |
273 | mu_iterator_t itr; | 360 | mu_iterator_t itr; |
274 | int i; | 361 | int i; |
275 | 362 | ||
276 | if (mu_list_is_empty (attlist) || | 363 | report_multipart_type (env); |
277 | mu_list_get_iterator (attlist, &itr)) | 364 | |
365 | if (mu_list_is_empty (env->attlist) || | ||
366 | mu_list_get_iterator (env->attlist, &itr)) | ||
278 | { | 367 | { |
279 | mu_printf ("%s\n", _("No attachments")); | 368 | mu_printf ("%s\n", _("No attachments")); |
280 | return 0; | 369 | return 0; |
... | @@ -308,8 +397,9 @@ escape_attach (int argc, char **argv, compose_env_t *env) | ... | @@ -308,8 +397,9 @@ escape_attach (int argc, char **argv, compose_env_t *env) |
308 | case 3: | 397 | case 3: |
309 | content_type = argv[2]; | 398 | content_type = argv[2]; |
310 | case 2: | 399 | case 2: |
311 | return send_attach_file (-1, argv[1], argv[1], argv[1], | 400 | return attlist_attach_file (&env->attlist, |
312 | content_type, encoding); | 401 | -1, argv[1], argv[1], argv[1], |
402 | content_type, encoding); | ||
313 | default: | 403 | default: |
314 | return escape_check_args (argc, argv, 2, 4); | 404 | return escape_check_args (argc, argv, 2, 4); |
315 | } | 405 | } |
... | @@ -332,21 +422,21 @@ escape_remove_attachment (int argc, char **argv, compose_env_t *env) | ... | @@ -332,21 +422,21 @@ escape_remove_attachment (int argc, char **argv, compose_env_t *env) |
332 | return 1; | 422 | return 1; |
333 | } | 423 | } |
334 | 424 | ||
335 | mu_list_count (attlist, &count); | 425 | mu_list_count (env->attlist, &count); |
336 | if (n == 0 || n > count) | 426 | if (n == 0 || n > count) |
337 | { | 427 | { |
338 | mu_error (_("index out of range")); | 428 | mu_error (_("index out of range")); |
339 | return 1; | 429 | return 1; |
340 | } | 430 | } |
341 | 431 | ||
342 | return mu_list_remove_nth (attlist, n - 1); | 432 | return mu_list_remove_nth (env->attlist, n - 1); |
343 | } | 433 | } |
344 | 434 | ||
345 | static int | 435 | static int |
346 | saveatt (void *item, void *data) | 436 | saveatt (void *item, void *data) |
347 | { | 437 | { |
348 | struct atchinfo *aptr = item; | 438 | struct atchinfo *aptr = item; |
349 | mu_mime_t mime = data; | 439 | compose_env_t *env = data; |
350 | mu_message_t part; | 440 | mu_message_t part; |
351 | mu_header_t hdr; | 441 | mu_header_t hdr; |
352 | int rc; | 442 | int rc; |
... | @@ -390,13 +480,15 @@ saveatt (void *item, void *data) | ... | @@ -390,13 +480,15 @@ saveatt (void *item, void *data) |
390 | return 0; | 480 | return 0; |
391 | } | 481 | } |
392 | 482 | ||
393 | mu_mime_get_num_parts (mime, &nparts); | 483 | mu_mime_get_num_parts (env->mime, &nparts); |
394 | mu_message_get_header (part, &hdr); | 484 | mu_message_get_header (part, &hdr); |
485 | if (env->alt) | ||
486 | mu_header_set_value (hdr, MU_HEADER_CONTENT_DISPOSITION, "inline", 1); | ||
395 | mu_rfc2822_msg_id (nparts, &p); | 487 | mu_rfc2822_msg_id (nparts, &p); |
396 | mu_header_set_value (hdr, MU_HEADER_CONTENT_ID, p, 1); | 488 | mu_header_set_value (hdr, MU_HEADER_CONTENT_ID, p, 1); |
397 | free (p); | 489 | free (p); |
398 | 490 | ||
399 | rc = mu_mime_add_part (mime, part); | 491 | rc = mu_mime_add_part (env->mime, part); |
400 | mu_message_unref (part); | 492 | mu_message_unref (part); |
401 | if (rc) | 493 | if (rc) |
402 | { | 494 | { |
... | @@ -418,7 +510,7 @@ add_body (mu_message_t inmsg, mu_iterator_t itr, mu_mime_t mime) | ... | @@ -418,7 +510,7 @@ add_body (mu_message_t inmsg, mu_iterator_t itr, mu_mime_t mime) |
418 | int rc; | 510 | int rc; |
419 | 511 | ||
420 | mu_message_get_body (inmsg, &body); | 512 | mu_message_get_body (inmsg, &body); |
421 | if (skip_empty_attachments) | 513 | if (skip_empty_attachments || multipart_alternative) |
422 | { | 514 | { |
423 | size_t size; | 515 | size_t size; |
424 | rc = mu_body_size (body, &size); | 516 | rc = mu_body_size (body, &size); |
... | @@ -483,7 +575,7 @@ add_body (mu_message_t inmsg, mu_iterator_t itr, mu_mime_t mime) | ... | @@ -483,7 +575,7 @@ add_body (mu_message_t inmsg, mu_iterator_t itr, mu_mime_t mime) |
483 | } | 575 | } |
484 | 576 | ||
485 | static int | 577 | static int |
486 | add_attachments (mu_message_t *pmsg, mu_mime_t *pmime) | 578 | add_attachments (compose_env_t *env, mu_message_t *pmsg) |
487 | { | 579 | { |
488 | mu_message_t inmsg, outmsg; | 580 | mu_message_t inmsg, outmsg; |
489 | mu_header_t inhdr, outhdr; | 581 | mu_header_t inhdr, outhdr; |
... | @@ -491,16 +583,15 @@ add_attachments (mu_message_t *pmsg, mu_mime_t *pmime) | ... | @@ -491,16 +583,15 @@ add_attachments (mu_message_t *pmsg, mu_mime_t *pmime) |
491 | mu_mime_t mime; | 583 | mu_mime_t mime; |
492 | int rc; | 584 | int rc; |
493 | 585 | ||
494 | if (mu_list_is_empty (attlist)) | 586 | if (mu_list_is_empty (env->attlist)) |
495 | { | 587 | return 0; |
496 | *pmime = NULL; | ||
497 | return 0; | ||
498 | } | ||
499 | 588 | ||
500 | inmsg = *pmsg; | 589 | inmsg = *pmsg; |
501 | 590 | ||
502 | /* Create a mime object */ | 591 | /* Create a mime object */ |
503 | rc = mu_mime_create (&mime, NULL, 0); | 592 | rc = mu_mime_create (&mime, NULL, |
593 | env->alt ? | ||
594 | MU_MIME_MULTIPART_ALT : MU_MIME_MULTIPART_MIXED); | ||
504 | if (rc) | 595 | if (rc) |
505 | { | 596 | { |
506 | mu_diag_funcall (MU_DIAG_ERROR, "mu_mime_create", NULL, rc); | 597 | mu_diag_funcall (MU_DIAG_ERROR, "mu_mime_create", NULL, rc); |
... | @@ -517,8 +608,10 @@ add_attachments (mu_message_t *pmsg, mu_mime_t *pmime) | ... | @@ -517,8 +608,10 @@ add_attachments (mu_message_t *pmsg, mu_mime_t *pmime) |
517 | return 1; | 608 | return 1; |
518 | } | 609 | } |
519 | 610 | ||
611 | env->mime = mime; | ||
612 | |||
520 | /* Add the respective attachments */ | 613 | /* Add the respective attachments */ |
521 | rc = mu_list_foreach (attlist, saveatt, mime); | 614 | rc = mu_list_foreach (env->attlist, saveatt, env); |
522 | if (rc) | 615 | if (rc) |
523 | { | 616 | { |
524 | mu_mime_destroy (&mime); | 617 | mu_mime_destroy (&mime); |
... | @@ -559,7 +652,6 @@ add_attachments (mu_message_t *pmsg, mu_mime_t *pmime) | ... | @@ -559,7 +652,6 @@ add_attachments (mu_message_t *pmsg, mu_mime_t *pmime) |
559 | mu_message_unref (inmsg); | 652 | mu_message_unref (inmsg); |
560 | 653 | ||
561 | *pmsg = outmsg; | 654 | *pmsg = outmsg; |
562 | *pmime = mime; | ||
563 | return 0; | 655 | return 0; |
564 | } | 656 | } |
565 | 657 | ||
... | @@ -785,6 +877,8 @@ void | ... | @@ -785,6 +877,8 @@ void |
785 | compose_init (compose_env_t *env) | 877 | compose_init (compose_env_t *env) |
786 | { | 878 | { |
787 | memset (env, 0, sizeof (*env)); | 879 | memset (env, 0, sizeof (*env)); |
880 | env->alt = multipart_alternative; | ||
881 | env->attlist = attlist_copy (attachment_list); | ||
788 | mu_list_foreach (add_header_list, seed_headers, env); | 882 | mu_list_foreach (add_header_list, seed_headers, env); |
789 | } | 883 | } |
790 | 884 | ||
... | @@ -873,6 +967,9 @@ compose_destroy (compose_env_t *env) | ... | @@ -873,6 +967,9 @@ compose_destroy (compose_env_t *env) |
873 | { | 967 | { |
874 | mu_header_destroy (&env->header); | 968 | mu_header_destroy (&env->header); |
875 | free (env->outfiles); | 969 | free (env->outfiles); |
970 | mu_mime_destroy (&env->mime); | ||
971 | mu_list_destroy (&env->attlist); | ||
972 | mu_stream_destroy (&env->compstr); | ||
876 | } | 973 | } |
877 | 974 | ||
878 | static int | 975 | static int |
... | @@ -1112,7 +1209,6 @@ mail_send0 (compose_env_t *env, int save_to) | ... | @@ -1112,7 +1209,6 @@ mail_send0 (compose_env_t *env, int save_to) |
1112 | if (rc) | 1209 | if (rc) |
1113 | { | 1210 | { |
1114 | mu_error (_("Cannot open temporary file: %s"), mu_strerror (rc)); | 1211 | mu_error (_("Cannot open temporary file: %s"), mu_strerror (rc)); |
1115 | mu_list_destroy (&attlist); | ||
1116 | return 1; | 1212 | return 1; |
1117 | } | 1213 | } |
1118 | 1214 | ||
... | @@ -1208,8 +1304,6 @@ mail_send0 (compose_env_t *env, int save_to) | ... | @@ -1208,8 +1304,6 @@ mail_send0 (compose_env_t *env, int save_to) |
1208 | if (int_cnt) | 1304 | if (int_cnt) |
1209 | { | 1305 | { |
1210 | save_dead_message_env (env); | 1306 | save_dead_message_env (env); |
1211 | mu_stream_destroy (&env->compstr); | ||
1212 | mu_list_destroy (&attlist); | ||
1213 | return 1; | 1307 | return 1; |
1214 | } | 1308 | } |
1215 | 1309 | ||
... | @@ -1225,7 +1319,6 @@ mail_send0 (compose_env_t *env, int save_to) | ... | @@ -1225,7 +1319,6 @@ mail_send0 (compose_env_t *env, int save_to) |
1225 | 1319 | ||
1226 | if (util_header_expand (&env->header) == 0) | 1320 | if (util_header_expand (&env->header) == 0) |
1227 | { | 1321 | { |
1228 | mu_mime_t mime = NULL; | ||
1229 | mu_message_t msg = NULL; | 1322 | mu_message_t msg = NULL; |
1230 | int status = 0; | 1323 | int status = 0; |
1231 | int sendit = (compose_header_get (env, MU_HEADER_TO, NULL) || | 1324 | int sendit = (compose_header_get (env, MU_HEADER_TO, NULL) || |
... | @@ -1246,7 +1339,7 @@ mail_send0 (compose_env_t *env, int save_to) | ... | @@ -1246,7 +1339,7 @@ mail_send0 (compose_env_t *env, int save_to) |
1246 | mu_message_set_header (msg, env->header, NULL); | 1339 | mu_message_set_header (msg, env->header, NULL); |
1247 | env->header = NULL; | 1340 | env->header = NULL; |
1248 | 1341 | ||
1249 | status = add_attachments (&msg, &mime); | 1342 | status = add_attachments (env, &msg); |
1250 | if (status) | 1343 | if (status) |
1251 | break; | 1344 | break; |
1252 | 1345 | ||
... | @@ -1323,14 +1416,10 @@ mail_send0 (compose_env_t *env, int save_to) | ... | @@ -1323,14 +1416,10 @@ mail_send0 (compose_env_t *env, int save_to) |
1323 | 1416 | ||
1324 | mu_stream_destroy (&env->compstr); | 1417 | mu_stream_destroy (&env->compstr); |
1325 | mu_message_destroy (&msg, NULL); | 1418 | mu_message_destroy (&msg, NULL); |
1326 | mu_mime_destroy (&mime); | ||
1327 | return status; | 1419 | return status; |
1328 | } | 1420 | } |
1329 | else | 1421 | else |
1330 | save_dead_message_env (env); | 1422 | save_dead_message_env (env); |
1331 | |||
1332 | mu_stream_destroy (&env->compstr); | ||
1333 | mu_list_destroy (&attlist); | ||
1334 | return 1; | 1423 | return 1; |
1335 | } | 1424 | } |
1336 | 1425 | ... | ... |
... | @@ -228,6 +228,7 @@ static const struct mail_escape_entry mail_escape_table[] = { | ... | @@ -228,6 +228,7 @@ static const struct mail_escape_entry mail_escape_table[] = { |
228 | {"-", "-", "-[mail-command]", escape_command }, | 228 | {"-", "-", "-[mail-command]", escape_command }, |
229 | {"+", "+", "+name [content-type [encoding]]", escape_attach }, | 229 | {"+", "+", "+name [content-type [encoding]]", escape_attach }, |
230 | {"^", "^", "^N", escape_remove_attachment }, | 230 | {"^", "^", "^N", escape_remove_attachment }, |
231 | {"/", "/", "/", escape_toggle_multipart_type }, | ||
231 | {"?", "?", "?", escape_help }, | 232 | {"?", "?", "?", escape_help }, |
232 | {"A", "A", "A", escape_sign }, | 233 | {"A", "A", "A", escape_sign }, |
233 | {"a", "a", "a", escape_sign }, | 234 | {"a", "a", "a", escape_sign }, | ... | ... |
... | @@ -706,7 +706,7 @@ util_save_outgoing (mu_message_t msg, char *savefile) | ... | @@ -706,7 +706,7 @@ util_save_outgoing (mu_message_t msg, char *savefile) |
706 | if (rc) | 706 | if (rc) |
707 | { | 707 | { |
708 | mu_error (_("Cannot create output mailbox `%s': %s"), | 708 | mu_error (_("Cannot create output mailbox `%s': %s"), |
709 | filename, strerror (rc)); | 709 | filename, mu_strerror (rc)); |
710 | free (filename); | 710 | free (filename); |
711 | return; | 711 | return; |
712 | } | 712 | } |
... | @@ -714,13 +714,13 @@ util_save_outgoing (mu_message_t msg, char *savefile) | ... | @@ -714,13 +714,13 @@ util_save_outgoing (mu_message_t msg, char *savefile) |
714 | rc = mu_mailbox_open (outbox, MU_STREAM_WRITE | MU_STREAM_CREAT); | 714 | rc = mu_mailbox_open (outbox, MU_STREAM_WRITE | MU_STREAM_CREAT); |
715 | if (rc) | 715 | if (rc) |
716 | mu_error (_("Cannot open output mailbox `%s': %s"), | 716 | mu_error (_("Cannot open output mailbox `%s': %s"), |
717 | filename, strerror (rc)); | 717 | filename, mu_strerror (rc)); |
718 | else | 718 | else |
719 | { | 719 | { |
720 | rc = mu_mailbox_append_message (outbox, msg); | 720 | rc = mu_mailbox_append_message (outbox, msg); |
721 | if (rc) | 721 | if (rc) |
722 | mu_error (_("Cannot append message to `%s': %s"), | 722 | mu_error (_("Cannot append message to `%s': %s"), |
723 | filename, strerror (rc)); | 723 | filename, mu_strerror (rc)); |
724 | } | 724 | } |
725 | 725 | ||
726 | mu_mailbox_close (outbox); | 726 | mu_mailbox_close (outbox); | ... | ... |
-
Please register or sign in to post a comment