Movemail improved.
* movemail/movemail.c: New options: --ignore-errors and --program-id. (_compare_msgno): Remove now unneded static. (main): Handle --ignore-errors and --program-id settings. Optimize the main loop for the case when --uidls is given. Return 1 on errors. * doc/texinfo/programs.texi: Document new features.
Showing
2 changed files
with
191 additions
and
39 deletions
... | @@ -4369,7 +4369,7 @@ intended as a replacement for @command{movemail} from GNU Emacs. The | ... | @@ -4369,7 +4369,7 @@ intended as a replacement for @command{movemail} from GNU Emacs. The |
4369 | module. @xref{Rmail,,,emacs,Reading Mail with Rmail}, for detailed | 4369 | module. @xref{Rmail,,,emacs,Reading Mail with Rmail}, for detailed |
4370 | description of @code{Rmail} interface. | 4370 | description of @code{Rmail} interface. |
4371 | 4371 | ||
4372 | Mailutils version of @command{movemail} is completely | 4372 | Mailutils version of @command{movemail} is fully |
4373 | backward-compatible with its Emacs predecessor, so it should run | 4373 | backward-compatible with its Emacs predecessor, so it should run |
4374 | flawlessly with older versions of Emacs. Emacs versions | 4374 | flawlessly with older versions of Emacs. Emacs versions |
4375 | starting from 22.1 contain improved @code{Rmail} interface and | 4375 | starting from 22.1 contain improved @code{Rmail} interface and |
... | @@ -4401,6 +4401,57 @@ If @var{bool} is @samp{true}, reverse message sorting order. | ... | @@ -4401,6 +4401,57 @@ If @var{bool} is @samp{true}, reverse message sorting order. |
4401 | If @var{bool} is @samp{true}, output information used by Emacs rmail interface. | 4401 | If @var{bool} is @samp{true}, output information used by Emacs rmail interface. |
4402 | @end deffn | 4402 | @end deffn |
4403 | 4403 | ||
4404 | @deffn {Movemail Config} ignore-erros @var{bool} | ||
4405 | Continue moving messages after errors. By default, | ||
4406 | @command{mailfromd} exits immediately if it cannot copy a message. | ||
4407 | @end deffn | ||
4408 | |||
4409 | @deffn {Movemail Config} program-id @var{fmt} | ||
4410 | Set program identifier, i.e. a string which will prefix all | ||
4411 | diagnostic messages issued by the program. By default, program | ||
4412 | name is used. | ||
4413 | |||
4414 | The @var{fmt} is a format string that may contain references to the | ||
4415 | following macro variables (@FIXME-pxref{macro-variables}): | ||
4416 | |||
4417 | @table @code | ||
4418 | @item progname | ||
4419 | The program name. | ||
4420 | |||
4421 | @item source | ||
4422 | URL of the source mailbox. | ||
4423 | |||
4424 | @item source:user | ||
4425 | User part of the source mailbox URL. | ||
4426 | |||
4427 | @item source:host | ||
4428 | Host part of the source mailbox URL. | ||
4429 | |||
4430 | @item source:path | ||
4431 | Path part of the source mailbox URL. | ||
4432 | |||
4433 | @item dest | ||
4434 | URL of the destination mailbox | ||
4435 | |||
4436 | @item dest:user | ||
4437 | User part of the destination mailbox URL. | ||
4438 | |||
4439 | @item dest:host | ||
4440 | Host part of the destination mailbox URL. | ||
4441 | |||
4442 | @item dest:path | ||
4443 | Path part of the destination mailbox URL. | ||
4444 | @end table | ||
4445 | |||
4446 | Setting @code{program-id} may be necessary if several @code{movemail} | ||
4447 | instances are run simultaneously (e.g. invoked from a script) to | ||
4448 | discern between the instances. For example: | ||
4449 | |||
4450 | @smallexample | ||
4451 | program-id "$@{progname@}: $@{source@} => $@{dest@}" | ||
4452 | @end smallexample | ||
4453 | @end deffn | ||
4454 | |||
4404 | @deffn {Movemail Config} uidl @var{bool} | 4455 | @deffn {Movemail Config} uidl @var{bool} |
4405 | Avoid copying the message if a message with the same UIDL already | 4456 | Avoid copying the message if a message with the same UIDL already |
4406 | exists in the destination mailbox. | 4457 | exists in the destination mailbox. |
... | @@ -4494,11 +4545,18 @@ Following is the summary of available command line options: | ... | @@ -4494,11 +4545,18 @@ Following is the summary of available command line options: |
4494 | @item --emacs | 4545 | @item --emacs |
4495 | Output information used by Emacs rmail interface | 4546 | Output information used by Emacs rmail interface |
4496 | 4547 | ||
4548 | @item --ignore-errors | ||
4549 | Continue moving messages after an error occurs. | ||
4550 | |||
4497 | @item -p | 4551 | @item -p |
4498 | @itemx --preserve | 4552 | @itemx --preserve |
4499 | @itemx --keep-messages | 4553 | @itemx --keep-messages |
4500 | Preserve the source mailbox | 4554 | Preserve the source mailbox |
4501 | 4555 | ||
4556 | @item --program-id=@var{fmt} | ||
4557 | Set program identifier for diagnostic purposes. See @ref{Movemail | ||
4558 | Configuration,program-id}, for a detailed discussion of this feature. | ||
4559 | |||
4502 | @item -r | 4560 | @item -r |
4503 | @itemx --reverse | 4561 | @itemx --reverse |
4504 | Reverse the sorting order | 4562 | Reverse the sorting order | ... | ... |
... | @@ -37,13 +37,17 @@ const char *program_version = "movemail (" PACKAGE_STRING ")"; | ... | @@ -37,13 +37,17 @@ const char *program_version = "movemail (" PACKAGE_STRING ")"; |
37 | static char doc[] = N_("GNU movemail -- move messages across mailboxes."); | 37 | static char doc[] = N_("GNU movemail -- move messages across mailboxes."); |
38 | static char args_doc[] = N_("inbox-url destfile [POP-password]"); | 38 | static char args_doc[] = N_("inbox-url destfile [POP-password]"); |
39 | 39 | ||
40 | #define OPT_EMACS 256 | 40 | enum { |
41 | EMACS_OPTION=256, | ||
42 | IGNORE_ERRORS_OPTION, | ||
43 | PROGRAM_ID_OPTION | ||
44 | }; | ||
41 | 45 | ||
42 | static struct argp_option options[] = { | 46 | static struct argp_option options[] = { |
43 | { "preserve", 'p', NULL, 0, N_("preserve the source mailbox") }, | 47 | { "preserve", 'p', NULL, 0, N_("preserve the source mailbox") }, |
44 | { "keep-messages", 0, NULL, OPTION_ALIAS, NULL }, | 48 | { "keep-messages", 0, NULL, OPTION_ALIAS, NULL }, |
45 | { "reverse", 'r', NULL, 0, N_("reverse the sorting order") }, | 49 | { "reverse", 'r', NULL, 0, N_("reverse the sorting order") }, |
46 | { "emacs", OPT_EMACS, NULL, 0, | 50 | { "emacs", EMACS_OPTION, NULL, 0, |
47 | N_("output information used by Emacs rmail interface") }, | 51 | N_("output information used by Emacs rmail interface") }, |
48 | { "uidl", 'u', NULL, 0, | 52 | { "uidl", 'u', NULL, 0, |
49 | N_("use UIDLs to avoid downloading the same message twice") }, | 53 | N_("use UIDLs to avoid downloading the same message twice") }, |
... | @@ -51,6 +55,10 @@ static struct argp_option options[] = { | ... | @@ -51,6 +55,10 @@ static struct argp_option options[] = { |
51 | N_("increase verbosity level") }, | 55 | N_("increase verbosity level") }, |
52 | { "owner", 'P', N_("MODELIST"), 0, | 56 | { "owner", 'P', N_("MODELIST"), 0, |
53 | N_("control mailbox ownership") }, | 57 | N_("control mailbox ownership") }, |
58 | { "ignore-errors", IGNORE_ERRORS_OPTION, NULL, 0, | ||
59 | N_("try to continue after errors") }, | ||
60 | { "program-id", PROGRAM_ID_OPTION, N_("FMT"), 0, | ||
61 | N_("set program identifier for diagnostics (default: program name)") }, | ||
54 | { NULL, 0, NULL, 0, NULL, 0 } | 62 | { NULL, 0, NULL, 0, NULL, 0 } |
55 | }; | 63 | }; |
56 | 64 | ||
... | @@ -59,6 +67,8 @@ static int preserve_mail; | ... | @@ -59,6 +67,8 @@ static int preserve_mail; |
59 | static int emacs_mode; | 67 | static int emacs_mode; |
60 | static int uidl_option; | 68 | static int uidl_option; |
61 | static int verbose_option; | 69 | static int verbose_option; |
70 | static int ignore_errors; | ||
71 | static char *program_id_option; | ||
62 | 72 | ||
63 | enum set_ownership_mode | 73 | enum set_ownership_mode |
64 | { | 74 | { |
... | @@ -135,10 +145,18 @@ parse_opt (int key, char *arg, struct argp_state *state) | ... | @@ -135,10 +145,18 @@ parse_opt (int key, char *arg, struct argp_state *state) |
135 | verbose_option++; | 145 | verbose_option++; |
136 | break; | 146 | break; |
137 | 147 | ||
138 | case OPT_EMACS: | 148 | case EMACS_OPTION: |
139 | mu_argp_node_list_new (lst, "emacs", "yes"); | 149 | mu_argp_node_list_new (lst, "emacs", "yes"); |
140 | break; | 150 | break; |
141 | 151 | ||
152 | case IGNORE_ERRORS_OPTION: | ||
153 | mu_argp_node_list_new (lst, "ignore-errors", "yes"); | ||
154 | break; | ||
155 | |||
156 | case PROGRAM_ID_OPTION: | ||
157 | mu_argp_node_list_new (lst, "program-id", arg); | ||
158 | break; | ||
159 | |||
142 | case ARGP_KEY_INIT: | 160 | case ARGP_KEY_INIT: |
143 | mu_argp_node_list_init (&lst); | 161 | mu_argp_node_list_init (&lst); |
144 | break; | 162 | break; |
... | @@ -298,6 +316,10 @@ struct mu_cfg_param movemail_cfg_param[] = { | ... | @@ -298,6 +316,10 @@ struct mu_cfg_param movemail_cfg_param[] = { |
298 | N_("Use UIDLs to avoid downloading the same message twice.") }, | 316 | N_("Use UIDLs to avoid downloading the same message twice.") }, |
299 | { "verbose", mu_cfg_int, &verbose_option, 0, NULL, | 317 | { "verbose", mu_cfg_int, &verbose_option, 0, NULL, |
300 | N_("Set verbosity level.") }, | 318 | N_("Set verbosity level.") }, |
319 | { "ignore-errors", mu_cfg_bool, &ignore_errors, 0, NULL, | ||
320 | N_("Continue after an error.") }, | ||
321 | { "program-id", mu_cfg_string, &program_id_option, 0, NULL, | ||
322 | N_("Set program identifier string (default: program name)") }, | ||
301 | { "mailbox-ownership", mu_cfg_callback, NULL, 0, | 323 | { "mailbox-ownership", mu_cfg_callback, NULL, 0, |
302 | cb_mailbox_ownership, | 324 | cb_mailbox_ownership, |
303 | N_("Define a list of methods for setting mailbox ownership. Valid " | 325 | N_("Define a list of methods for setting mailbox ownership. Valid " |
... | @@ -633,25 +655,69 @@ _compare_uidls (const void *item, const void *value) | ... | @@ -633,25 +655,69 @@ _compare_uidls (const void *item, const void *value) |
633 | return strcmp (a->uidl, b->uidl); | 655 | return strcmp (a->uidl, b->uidl); |
634 | } | 656 | } |
635 | 657 | ||
636 | static int | 658 | #define __cat2__(a,b) a ## b |
637 | _compare_msgno (const void *item, const void *value) | 659 | #define DCL_VTX(what) \ |
638 | { | 660 | static int \ |
639 | const struct mu_uidl *a = item; | 661 | __cat2__(_vtx_,what) (const char *name, void *data, char **p) \ |
640 | const struct mu_uidl *b = value; | 662 | { \ |
641 | 663 | mu_url_t url = data; \ | |
642 | if (a->msgno < b->msgno) | 664 | int rc = __cat2__(mu_url_aget_,what) (url, p); \ |
643 | return -1; | 665 | if (rc == MU_ERR_NOENT) \ |
644 | if (a->msgno > b->msgno) | 666 | { \ |
645 | return 1; | 667 | *p = strdup (""); \ |
646 | return 0; | 668 | return 0; \ |
669 | } \ | ||
670 | return rc; \ | ||
647 | } | 671 | } |
648 | 672 | ||
649 | static int | 673 | DCL_VTX (host) |
650 | msgno_in_list (mu_list_t list, size_t num) | 674 | DCL_VTX (user) |
675 | DCL_VTX (path) | ||
676 | |||
677 | static void | ||
678 | set_program_id (const char *source_name, const char *dest_name) | ||
651 | { | 679 | { |
652 | struct mu_uidl t; | 680 | int rc; |
653 | t.msgno = num; | 681 | mu_vartab_t vtab; |
654 | return mu_list_locate (list, &t, NULL) == 0; | 682 | char *id; |
683 | mu_url_t url; | ||
684 | |||
685 | mu_vartab_create (&vtab); | ||
686 | mu_vartab_define (vtab, "progname", mu_program_name, 1); | ||
687 | mu_vartab_define (vtab, "source", source_name, 1); | ||
688 | rc = mu_mailbox_get_url (source, &url); | ||
689 | if (rc) | ||
690 | mu_diag_output (MU_DIAG_INFO, | ||
691 | _("cannot obtain source mailbox URL: %s"), | ||
692 | mu_strerror (rc)); | ||
693 | else | ||
694 | { | ||
695 | mu_vartab_define_exp (vtab, "source:user", _vtx_user, NULL, url); | ||
696 | mu_vartab_define_exp (vtab, "source:host", _vtx_host, NULL, url); | ||
697 | mu_vartab_define_exp (vtab, "source:path", _vtx_path, NULL, url); | ||
698 | } | ||
699 | |||
700 | mu_vartab_define (vtab, "dest", dest_name, 1); | ||
701 | rc = mu_mailbox_get_url (dest, &url); | ||
702 | if (rc) | ||
703 | mu_diag_output (MU_DIAG_INFO, | ||
704 | _("cannot obtain destination mailbox URL: %s"), | ||
705 | mu_strerror (rc)); | ||
706 | else | ||
707 | { | ||
708 | mu_vartab_define_exp (vtab, "dest:user", _vtx_user, NULL, url); | ||
709 | mu_vartab_define_exp (vtab, "dest:host", _vtx_host, NULL, url); | ||
710 | mu_vartab_define_exp (vtab, "dest:path", _vtx_path, NULL, url); | ||
711 | } | ||
712 | |||
713 | rc = mu_vartab_expand (vtab, program_id_option, &id); | ||
714 | mu_vartab_destroy (&vtab); | ||
715 | /* asprintf (&id, "%s: %s", mu_program_name, s); | ||
716 | free (s);*/ | ||
717 | /* FIXME: Don't use mu_set_program_name here, because it | ||
718 | plays wise with its argument. We need a mu_set_diag_prefix | ||
719 | function. */ | ||
720 | mu_program_name = id; | ||
655 | } | 721 | } |
656 | 722 | ||
657 | int | 723 | int |
... | @@ -660,6 +726,7 @@ main (int argc, char **argv) | ... | @@ -660,6 +726,7 @@ main (int argc, char **argv) |
660 | int index; | 726 | int index; |
661 | size_t i, total; | 727 | size_t i, total; |
662 | int rc = 0; | 728 | int rc = 0; |
729 | int errs = 0; | ||
663 | char *source_name, *dest_name; | 730 | char *source_name, *dest_name; |
664 | int flags; | 731 | int flags; |
665 | mu_list_t src_uidl_list = NULL; | 732 | mu_list_t src_uidl_list = NULL; |
... | @@ -707,6 +774,9 @@ main (int argc, char **argv) | ... | @@ -707,6 +774,9 @@ main (int argc, char **argv) |
707 | 774 | ||
708 | open_mailbox (&dest, dest_name, MU_STREAM_RDWR | MU_STREAM_CREAT, NULL); | 775 | open_mailbox (&dest, dest_name, MU_STREAM_RDWR | MU_STREAM_CREAT, NULL); |
709 | 776 | ||
777 | if (program_id_option) | ||
778 | set_program_id (source_name, dest_name); | ||
779 | |||
710 | rc = mu_mailbox_messages_count (source, &total); | 780 | rc = mu_mailbox_messages_count (source, &total); |
711 | if (rc) | 781 | if (rc) |
712 | { | 782 | { |
... | @@ -745,43 +815,67 @@ main (int argc, char **argv) | ... | @@ -745,43 +815,67 @@ main (int argc, char **argv) |
745 | } | 815 | } |
746 | mu_iterator_destroy (&itr); | 816 | mu_iterator_destroy (&itr); |
747 | mu_list_destroy (&dst_uidl_list); | 817 | mu_list_destroy (&dst_uidl_list); |
748 | mu_list_set_comparator (src_uidl_list, _compare_msgno); | 818 | mu_list_set_comparator (src_uidl_list, NULL); |
749 | } | 819 | } |
750 | 820 | ||
751 | if (reverse_order) | 821 | /* FIXME: Implementing a mailbox iterator would allow to merge the three |
822 | branches of this conditional. */ | ||
823 | if (src_uidl_list) | ||
752 | { | 824 | { |
753 | for (i = total; i > 0; i--) | 825 | mu_iterator_t itr; |
826 | |||
827 | rc = mu_list_get_iterator (src_uidl_list, &itr); | ||
828 | if (rc) | ||
754 | { | 829 | { |
755 | if (src_uidl_list && !msgno_in_list (src_uidl_list, i)) | 830 | mu_error(_("cannot get iterator: %s"), mu_strerror (rc)); |
831 | exit (1); | ||
832 | } | ||
833 | rc = mu_iterator_ctl (itr, mu_itrctl_set_direction, &reverse_order); | ||
834 | if (rc) | ||
756 | { | 835 | { |
757 | if (verbose_option > 1) | 836 | mu_error(_("cannot set iteration direction: %s"), mu_strerror (rc)); |
758 | mu_diag_output (MU_DIAG_INFO, _("ignoring message %lu"), | 837 | exit (1); |
759 | (unsigned long) i); | ||
760 | continue; | ||
761 | } | 838 | } |
762 | rc = move_message (source, dest, i); | 839 | for (mu_iterator_first (itr); !mu_iterator_is_done (itr); |
840 | mu_iterator_next (itr)) | ||
841 | { | ||
842 | struct mu_uidl *uidl; | ||
843 | |||
844 | mu_iterator_current (itr, (void **)&uidl); | ||
845 | rc = move_message (source, dest, uidl->msgno); | ||
763 | if (rc == 0) | 846 | if (rc == 0) |
764 | msg_count++; | 847 | msg_count++; |
848 | else if (!ignore_errors) | ||
849 | break; | ||
765 | else | 850 | else |
851 | errs = 1; | ||
852 | } | ||
853 | mu_iterator_destroy (&itr); | ||
854 | } | ||
855 | else if (reverse_order) | ||
856 | { | ||
857 | for (i = total; i > 0; i--) | ||
858 | { | ||
859 | rc = move_message (source, dest, i); | ||
860 | if (rc == 0) | ||
861 | msg_count++; | ||
862 | else if (!ignore_errors) | ||
766 | break; | 863 | break; |
864 | else | ||
865 | errs = 1; | ||
767 | } | 866 | } |
768 | } | 867 | } |
769 | else | 868 | else |
770 | { | 869 | { |
771 | for (i = 1; i <= total; i++) | 870 | for (i = 1; i <= total; i++) |
772 | { | 871 | { |
773 | if (src_uidl_list && !msgno_in_list (src_uidl_list, i)) | ||
774 | { | ||
775 | if (verbose_option > 1) | ||
776 | mu_diag_output (MU_DIAG_INFO, _("ignoring message %lu"), | ||
777 | (unsigned long) i); | ||
778 | continue; | ||
779 | } | ||
780 | rc = move_message (source, dest, i); | 872 | rc = move_message (source, dest, i); |
781 | if (rc == 0) | 873 | if (rc == 0) |
782 | msg_count++; | 874 | msg_count++; |
783 | else | 875 | else if (!ignore_errors) |
784 | break; | 876 | break; |
877 | else | ||
878 | errs = 1; | ||
785 | } | 879 | } |
786 | } | 880 | } |
787 | 881 | ||
... | @@ -791,7 +885,7 @@ main (int argc, char **argv) | ... | @@ -791,7 +885,7 @@ main (int argc, char **argv) |
791 | (unsigned long) msg_count); | 885 | (unsigned long) msg_count); |
792 | 886 | ||
793 | if (rc) | 887 | if (rc) |
794 | return rc; | 888 | return !!rc; |
795 | 889 | ||
796 | mu_mailbox_sync (dest); | 890 | mu_mailbox_sync (dest); |
797 | rc = mu_mailbox_close (dest); | 891 | rc = mu_mailbox_close (dest); |
... | @@ -804,5 +898,5 @@ main (int argc, char **argv) | ... | @@ -804,5 +898,5 @@ main (int argc, char **argv) |
804 | mu_mailbox_close (source); | 898 | mu_mailbox_close (source); |
805 | mu_mailbox_destroy (&source); | 899 | mu_mailbox_destroy (&source); |
806 | 900 | ||
807 | return rc; | 901 | return !(rc == 0 && errs == 0); |
808 | } | 902 | } | ... | ... |
-
Please register or sign in to post a comment