Improve the --skip-empty-attachment functionality
This also includes small bugfixes in the MIME library code. The --skip-empty-attachment option now affects the original body as well. If the option is in effect, and the body is empty, it will not be included to the composed message. * libmailutils/mime/mime.c (_mime_body_stream_read): Return EOF if there are no parts in the message. (mu_mime_get_num_parts): If message is not multipart, report 1 part without setting mime->nmtp_parts. Setting it caused coredump in other MIME functions (namely, in mu_mime_add_part. * mail/send.c (add_body): New function. Adds original body to the MIME, honoring the --skip-empty-attachment option. * doc/texinfo/programs.texi: Update.
Showing
3 changed files
with
111 additions
and
28 deletions
... | @@ -3048,7 +3048,9 @@ Sets the return email address for outgoing mail. | ... | @@ -3048,7 +3048,9 @@ Sets the return email address for outgoing mail. |
3048 | @itemx --no-skip-empty-attachments | 3048 | @itemx --no-skip-empty-attachments |
3049 | Don't create attachments that would have zero-size body. This | 3049 | Don't create attachments that would have zero-size body. This |
3050 | option affects all attachments created by @option{--attach} and | 3050 | option affects all attachments created by @option{--attach} and |
3051 | @option{--attach-fd} options appearing after it in the command line. | 3051 | @option{--attach-fd} options appearing after it in the command line, |
3052 | as well as the body of the original message. | ||
3053 | |||
3052 | To cancel its effect, use the @option{--no-skip-empty-attachments} option. | 3054 | To cancel its effect, use the @option{--no-skip-empty-attachments} option. |
3053 | 3055 | ||
3054 | @item -s @var{subj} | 3056 | @item -s @var{subj} |
... | @@ -3542,7 +3544,38 @@ The option @option{--skip-empty-attachments} instructs @command{mail} | ... | @@ -3542,7 +3544,38 @@ The option @option{--skip-empty-attachments} instructs @command{mail} |
3542 | to skip creating attachments that would have zero-size body. This | 3544 | to skip creating attachments that would have zero-size body. This |
3543 | option affects all attachments created by @option{--attach} and | 3545 | option affects all attachments created by @option{--attach} and |
3544 | @option{--attach-fd} options appearing after it in the command line. | 3546 | @option{--attach-fd} options appearing after it in the command line. |
3545 | To cancel its effect, use the @option{--no-skip-empty-attachments} option. | 3547 | It also affects the handling of the original message body. To cancel |
3548 | its effect, use the @option{--no-skip-empty-attachments} option. | ||
3549 | |||
3550 | Here are some examples illustrating how it works. | ||
3551 | |||
3552 | First, consider the following command line | ||
3553 | |||
3554 | @example | ||
3555 | $ mail --attach=archive.tar </dev/null | ||
3556 | @end example | ||
3557 | |||
3558 | Assume that @file{archive.tar} is not empty. | ||
3559 | |||
3560 | This will create a MIME message of two parts: the first part having | ||
3561 | @samp{text/html} type and empty body, and the second part of type | ||
3562 | @samp{application/octet-stream}, with the content copied from the file | ||
3563 | @file{archive.tar}. | ||
3564 | |||
3565 | Now, if you do: | ||
3566 | |||
3567 | @example | ||
3568 | $ mail --attach=archive.tar --skip-empty-attachments </dev/null | ||
3569 | @end example | ||
3570 | |||
3571 | @noindent | ||
3572 | then the created MIME message will contain only one part: that | ||
3573 | containing @file{archive.tar}. | ||
3574 | |||
3575 | If the file @file{archive.tar} has zero length, the resulting archive | ||
3576 | will still contain the @samp{application/octet-stream} part of zero | ||
3577 | length. However, if you place the @option{--skip-empty-attachments} | ||
3578 | option before @option{--attach}, then the produced message will be empty. | ||
3546 | 3579 | ||
3547 | The following Perl program serves as an example of using | 3580 | The following Perl program serves as an example of using |
3548 | @command{mail} from a script to construct a MIME message on the fly. | 3581 | @command{mail} from a script to construct a MIME message on the fly. | ... | ... |
... | @@ -662,7 +662,10 @@ _mime_body_stream_read (mu_stream_t stream, char *buf, size_t buflen, size_t *nb | ... | @@ -662,7 +662,10 @@ _mime_body_stream_read (mu_stream_t stream, char *buf, size_t buflen, size_t *nb |
662 | size_t total = 0; | 662 | size_t total = 0; |
663 | 663 | ||
664 | if (mime->nmtp_parts == 0) | 664 | if (mime->nmtp_parts == 0) |
665 | return EINVAL; | 665 | { |
666 | *nbytes = 0; | ||
667 | return 0; | ||
668 | } | ||
666 | 669 | ||
667 | if ((ret = _mime_set_content_type (mime)) == 0) | 670 | if ((ret = _mime_set_content_type (mime)) == 0) |
668 | { | 671 | { |
... | @@ -1055,7 +1058,10 @@ mu_mime_get_num_parts (mu_mime_t mime, size_t *nmtp_parts) | ... | @@ -1055,7 +1058,10 @@ mu_mime_get_num_parts (mu_mime_t mime, size_t *nmtp_parts) |
1055 | return (ret); | 1058 | return (ret); |
1056 | } | 1059 | } |
1057 | else | 1060 | else |
1058 | mime->nmtp_parts = 1; | 1061 | { |
1062 | *nmtp_parts = 1; | ||
1063 | return 0; | ||
1064 | } | ||
1059 | } | 1065 | } |
1060 | *nmtp_parts = mime->nmtp_parts; | 1066 | *nmtp_parts = mime->nmtp_parts; |
1061 | return (ret); | 1067 | return (ret); | ... | ... |
... | @@ -408,50 +408,52 @@ saveatt (void *item, void *data) | ... | @@ -408,50 +408,52 @@ saveatt (void *item, void *data) |
408 | } | 408 | } |
409 | 409 | ||
410 | static int | 410 | static int |
411 | add_attachments (mu_message_t *pmsg, mu_mime_t *pmime) | 411 | add_body (mu_message_t inmsg, mu_iterator_t itr, mu_mime_t mime) |
412 | { | 412 | { |
413 | mu_message_t inmsg, outmsg, part; | ||
414 | mu_body_t body; | 413 | mu_body_t body; |
415 | mu_header_t inhdr, outhdr; | 414 | mu_message_t part; |
416 | mu_iterator_t itr; | ||
417 | mu_mime_t mime; | ||
418 | mu_stream_t str, output; | 415 | mu_stream_t str, output; |
419 | int rc; | 416 | mu_header_t outhdr; |
420 | char *p; | 417 | char *p; |
418 | int rc; | ||
421 | 419 | ||
422 | if (mu_list_is_empty (attlist)) | 420 | mu_message_get_body (inmsg, &body); |
421 | if (skip_empty_attachments) | ||
423 | { | 422 | { |
424 | *pmime = NULL; | 423 | size_t size; |
424 | rc = mu_body_size (body, &size); | ||
425 | if (rc) | ||
426 | { | ||
427 | mu_diag_funcall (MU_DIAG_ERROR, "mu_body_size", NULL, rc); | ||
428 | return -1; | ||
429 | } | ||
430 | if (size == 0) | ||
425 | return 0; | 431 | return 0; |
426 | } | 432 | } |
427 | 433 | ||
428 | inmsg = *pmsg; | 434 | /* Add original message as the first part */ |
429 | 435 | ||
430 | /* Create a mime object */ | 436 | /* 1. Create the part and obtain a reference to its stream */ |
431 | rc = mu_mime_create (&mime, NULL, 0); | 437 | if ((rc = mu_message_create (&part, NULL)) == 0) |
432 | if (rc) | ||
433 | { | 438 | { |
434 | mu_diag_funcall (MU_DIAG_ERROR, "mu_mime_create", NULL, rc); | 439 | mu_body_t pbody; |
435 | return 1; | ||
436 | } | ||
437 | 440 | ||
438 | /* Add original message as its first part */ | 441 | mu_message_get_body (part, &pbody); |
439 | /* 1. Create the part and obtain a reference to its stream */ | 442 | mu_body_get_streamref (pbody, &output); |
440 | mu_message_create (&part, NULL); | 443 | } |
441 | mu_message_get_body (part, &body); | 444 | else |
442 | mu_body_get_streamref (body, &output); | 445 | { |
446 | mu_diag_funcall (MU_DIAG_ERROR, "mu_message_create", NULL, rc); | ||
447 | return -1; | ||
448 | } | ||
443 | 449 | ||
444 | /* 2. Get original body stream and copy it out to the part's body */ | 450 | /* 2. Get original body stream and copy it out to the part's body */ |
445 | mu_message_get_body (inmsg, &body); | ||
446 | mu_body_get_streamref (body, &str); | 451 | mu_body_get_streamref (body, &str); |
447 | mu_stream_copy (output, str, 0, NULL); | 452 | mu_stream_copy (output, str, 0, NULL); |
448 | 453 | ||
449 | mu_stream_close (output); | 454 | mu_stream_close (output); |
450 | mu_stream_destroy (&output); | 455 | mu_stream_destroy (&output); |
451 | 456 | ||
452 | mu_message_get_header (inmsg, &inhdr); | ||
453 | mu_header_get_iterator (inhdr, &itr); | ||
454 | |||
455 | /* 3. Copy "Content-*" headers from the original message */ | 457 | /* 3. Copy "Content-*" headers from the original message */ |
456 | mu_message_get_header (part, &outhdr); | 458 | mu_message_get_header (part, &outhdr); |
457 | for (mu_iterator_first (itr); !mu_iterator_is_done (itr); | 459 | for (mu_iterator_first (itr); !mu_iterator_is_done (itr); |
... | @@ -477,11 +479,50 @@ add_attachments (mu_message_t *pmsg, mu_mime_t *pmime) | ... | @@ -477,11 +479,50 @@ add_attachments (mu_message_t *pmsg, mu_mime_t *pmime) |
477 | mu_mime_add_part (mime, part); | 479 | mu_mime_add_part (mime, part); |
478 | mu_message_unref (part); | 480 | mu_message_unref (part); |
479 | 481 | ||
482 | return 0; | ||
483 | } | ||
484 | |||
485 | static int | ||
486 | add_attachments (mu_message_t *pmsg, mu_mime_t *pmime) | ||
487 | { | ||
488 | mu_message_t inmsg, outmsg; | ||
489 | mu_header_t inhdr, outhdr; | ||
490 | mu_iterator_t itr; | ||
491 | mu_mime_t mime; | ||
492 | int rc; | ||
493 | |||
494 | if (mu_list_is_empty (attlist)) | ||
495 | { | ||
496 | *pmime = NULL; | ||
497 | return 0; | ||
498 | } | ||
499 | |||
500 | inmsg = *pmsg; | ||
501 | |||
502 | /* Create a mime object */ | ||
503 | rc = mu_mime_create (&mime, NULL, 0); | ||
504 | if (rc) | ||
505 | { | ||
506 | mu_diag_funcall (MU_DIAG_ERROR, "mu_mime_create", NULL, rc); | ||
507 | return 1; | ||
508 | } | ||
509 | |||
510 | mu_message_get_header (inmsg, &inhdr); | ||
511 | mu_header_get_iterator (inhdr, &itr); | ||
512 | |||
513 | if (add_body (inmsg, itr, mime)) | ||
514 | { | ||
515 | mu_mime_destroy (&mime); | ||
516 | mu_iterator_destroy (&itr); | ||
517 | return 1; | ||
518 | } | ||
519 | |||
480 | /* Add the respective attachments */ | 520 | /* Add the respective attachments */ |
481 | rc = mu_list_foreach (attlist, saveatt, mime); | 521 | rc = mu_list_foreach (attlist, saveatt, mime); |
482 | if (rc) | 522 | if (rc) |
483 | { | 523 | { |
484 | mu_mime_destroy (&mime); | 524 | mu_mime_destroy (&mime); |
525 | mu_iterator_destroy (&itr); | ||
485 | return 1; | 526 | return 1; |
486 | } | 527 | } |
487 | 528 | ||
... | @@ -492,6 +533,7 @@ add_attachments (mu_message_t *pmsg, mu_mime_t *pmime) | ... | @@ -492,6 +533,7 @@ add_attachments (mu_message_t *pmsg, mu_mime_t *pmime) |
492 | { | 533 | { |
493 | mu_diag_funcall (MU_DIAG_ERROR, "mu_mime_get_message", NULL, rc); | 534 | mu_diag_funcall (MU_DIAG_ERROR, "mu_mime_get_message", NULL, rc); |
494 | mu_mime_destroy (&mime); | 535 | mu_mime_destroy (&mime); |
536 | mu_iterator_destroy (&itr); | ||
495 | return 1; | 537 | return 1; |
496 | } | 538 | } |
497 | 539 | ||
... | @@ -515,6 +557,7 @@ add_attachments (mu_message_t *pmsg, mu_mime_t *pmime) | ... | @@ -515,6 +557,7 @@ add_attachments (mu_message_t *pmsg, mu_mime_t *pmime) |
515 | 557 | ||
516 | mu_message_unref (outmsg); | 558 | mu_message_unref (outmsg); |
517 | mu_message_unref (inmsg); | 559 | mu_message_unref (inmsg); |
560 | |||
518 | *pmsg = outmsg; | 561 | *pmsg = outmsg; |
519 | *pmime = mime; | 562 | *pmime = mime; |
520 | return 0; | 563 | return 0; |
... | @@ -1193,6 +1236,7 @@ mail_send0 (compose_env_t *env, int save_to) | ... | @@ -1193,6 +1236,7 @@ mail_send0 (compose_env_t *env, int save_to) |
1193 | status = mu_message_create (&msg, NULL); | 1236 | status = mu_message_create (&msg, NULL); |
1194 | if (status) | 1237 | if (status) |
1195 | break; | 1238 | break; |
1239 | |||
1196 | /* Fill the body. */ | 1240 | /* Fill the body. */ |
1197 | mu_stream_seek (env->compstr, 0, MU_SEEK_SET, NULL); | 1241 | mu_stream_seek (env->compstr, 0, MU_SEEK_SET, NULL); |
1198 | status = fill_body (msg, env->compstr); | 1242 | status = fill_body (msg, env->compstr); | ... | ... |
-
Please register or sign in to post a comment