movemail: various improvements.
New configuration options allow to specify the maximum number of messages to be copied and control the actions of movemail when an error occurs while appending a message. * movemail/movemail.c (ONERROR_OPTION,MAX_MESSAGES_OPTION): New option codes. (options): New options --onerror and --max-messages. (max_messages_option, onerror_flags): New variable. (ONERROR_SKIP, ONERROR_DELETE, ONERROR_COUNT): New defines. (parse_opt): Handle ONERROR_OPTION. (cb_onerror): New callback. (movemail_cfg_param): New configuration statements: "max-messages" and "onerror". (move_message): Delete the message if ONERROR_DELETE is set. (main): Handle the limit on the number of processed messages and onerror flags. Use mu_mailbox_expunge instead of mu_mailbox_flush. This preserves the attributes of not processed options (in case max_messages_option is not 0) and speeds up the things considerably, especially on huge mailboxes.
Showing
1 changed file
with
139 additions
and
25 deletions
... | @@ -36,7 +36,9 @@ static char args_doc[] = N_("inbox-url destfile [POP-password]"); | ... | @@ -36,7 +36,9 @@ static char args_doc[] = N_("inbox-url destfile [POP-password]"); |
36 | enum { | 36 | enum { |
37 | EMACS_OPTION=256, | 37 | EMACS_OPTION=256, |
38 | IGNORE_ERRORS_OPTION, | 38 | IGNORE_ERRORS_OPTION, |
39 | PROGRAM_ID_OPTION | 39 | PROGRAM_ID_OPTION, |
40 | MAX_MESSAGES_OPTION, | ||
41 | ONERROR_OPTION | ||
40 | }; | 42 | }; |
41 | 43 | ||
42 | static struct argp_option options[] = { | 44 | static struct argp_option options[] = { |
... | @@ -53,8 +55,12 @@ static struct argp_option options[] = { | ... | @@ -53,8 +55,12 @@ static struct argp_option options[] = { |
53 | N_("control mailbox ownership") }, | 55 | N_("control mailbox ownership") }, |
54 | { "ignore-errors", IGNORE_ERRORS_OPTION, NULL, 0, | 56 | { "ignore-errors", IGNORE_ERRORS_OPTION, NULL, 0, |
55 | N_("try to continue after errors") }, | 57 | N_("try to continue after errors") }, |
58 | { "onerror", ONERROR_OPTION, N_("KW[,KW...]"), 0, | ||
59 | N_("what to do on errors") }, | ||
56 | { "program-id", PROGRAM_ID_OPTION, N_("FMT"), 0, | 60 | { "program-id", PROGRAM_ID_OPTION, N_("FMT"), 0, |
57 | N_("set program identifier for diagnostics (default: program name)") }, | 61 | N_("set program identifier for diagnostics (default: program name)") }, |
62 | { "max-messages", MAX_MESSAGES_OPTION, N_("NUMBER"), 0, | ||
63 | N_("process at most NUMBER messages") }, | ||
58 | { NULL, 0, NULL, 0, NULL, 0 } | 64 | { NULL, 0, NULL, 0, NULL, 0 } |
59 | }; | 65 | }; |
60 | 66 | ||
... | @@ -65,6 +71,14 @@ static int uidl_option; | ... | @@ -65,6 +71,14 @@ static int uidl_option; |
65 | static int verbose_option; | 71 | static int verbose_option; |
66 | static int ignore_errors; | 72 | static int ignore_errors; |
67 | static char *program_id_option; | 73 | static char *program_id_option; |
74 | static size_t max_messages_option; | ||
75 | |||
76 | /* These bits tell what to do when an error occurs: */ | ||
77 | #define ONERROR_SKIP 0x01 /* Skip to the next message */ | ||
78 | #define ONERROR_DELETE 0x02 /* Delete the source message */ | ||
79 | #define ONERROR_COUNT 0x04 /* Count it as processed */ | ||
80 | |||
81 | static int onerror_flags; | ||
68 | 82 | ||
69 | enum set_ownership_mode | 83 | enum set_ownership_mode |
70 | { | 84 | { |
... | @@ -149,6 +163,14 @@ parse_opt (int key, char *arg, struct argp_state *state) | ... | @@ -149,6 +163,14 @@ parse_opt (int key, char *arg, struct argp_state *state) |
149 | mu_argp_node_list_new (lst, "ignore-errors", "yes"); | 163 | mu_argp_node_list_new (lst, "ignore-errors", "yes"); |
150 | break; | 164 | break; |
151 | 165 | ||
166 | case ONERROR_OPTION: | ||
167 | mu_argp_node_list_new (lst, "onerror", arg); | ||
168 | break; | ||
169 | |||
170 | case MAX_MESSAGES_OPTION: | ||
171 | mu_argp_node_list_new (lst, "max-messages", arg); | ||
172 | break; | ||
173 | |||
152 | case PROGRAM_ID_OPTION: | 174 | case PROGRAM_ID_OPTION: |
153 | mu_argp_node_list_new (lst, "program-id", arg); | 175 | mu_argp_node_list_new (lst, "program-id", arg); |
154 | break; | 176 | break; |
... | @@ -288,6 +310,49 @@ cb_mailbox_ownership (void *data, mu_config_value_t *val) | ... | @@ -288,6 +310,49 @@ cb_mailbox_ownership (void *data, mu_config_value_t *val) |
288 | return 0; | 310 | return 0; |
289 | } | 311 | } |
290 | 312 | ||
313 | static int | ||
314 | cb_onerror (void *data, mu_config_value_t *val) | ||
315 | { | ||
316 | struct mu_wordsplit ws; | ||
317 | static struct mu_kwd onerror_kw[] = { | ||
318 | { "skip", ONERROR_SKIP }, | ||
319 | { "delete", ONERROR_DELETE }, | ||
320 | { "count", ONERROR_COUNT }, | ||
321 | { NULL } | ||
322 | }; | ||
323 | int i, flag; | ||
324 | |||
325 | if (mu_cfg_assert_value_type (val, MU_CFG_STRING)) | ||
326 | return 1; | ||
327 | ws.ws_delim = ","; | ||
328 | if (mu_wordsplit (val->v.string, &ws, | ||
329 | MU_WRDSF_NOVAR | MU_WRDSF_NOCMD | | ||
330 | MU_WRDSF_DELIM | MU_WRDSF_WS)) | ||
331 | { | ||
332 | mu_error (_("cannot split argument: %s"), mu_wordsplit_strerror (&ws)); | ||
333 | return 1; | ||
334 | } | ||
335 | for (i = 0; i < ws.ws_wordc; i++) | ||
336 | { | ||
337 | int clr = 0; | ||
338 | char *name = ws.ws_wordv[i]; | ||
339 | |||
340 | if (strncmp (name, "no", 2) == 0) | ||
341 | { | ||
342 | clr = 1; | ||
343 | name += 2; | ||
344 | } | ||
345 | if (mu_kwd_xlat_name (onerror_kw, name, &flag)) | ||
346 | mu_error (_("unknown keyword: %s"), ws.ws_wordv[i]); | ||
347 | if (clr) | ||
348 | onerror_flags &= ~flag; | ||
349 | else | ||
350 | onerror_flags |= flag; | ||
351 | } | ||
352 | mu_wordsplit_free (&ws); | ||
353 | return 0; | ||
354 | } | ||
355 | |||
291 | struct mu_cfg_param movemail_cfg_param[] = { | 356 | struct mu_cfg_param movemail_cfg_param[] = { |
292 | { "preserve", mu_cfg_bool, &preserve_mail, 0, NULL, | 357 | { "preserve", mu_cfg_bool, &preserve_mail, 0, NULL, |
293 | N_("Do not remove messages from the source mailbox.") }, | 358 | N_("Do not remove messages from the source mailbox.") }, |
... | @@ -299,8 +364,6 @@ struct mu_cfg_param movemail_cfg_param[] = { | ... | @@ -299,8 +364,6 @@ struct mu_cfg_param movemail_cfg_param[] = { |
299 | N_("Use UIDLs to avoid downloading the same message twice.") }, | 364 | N_("Use UIDLs to avoid downloading the same message twice.") }, |
300 | { "verbose", mu_cfg_int, &verbose_option, 0, NULL, | 365 | { "verbose", mu_cfg_int, &verbose_option, 0, NULL, |
301 | N_("Set verbosity level.") }, | 366 | N_("Set verbosity level.") }, |
302 | { "ignore-errors", mu_cfg_bool, &ignore_errors, 0, NULL, | ||
303 | N_("Continue after an error.") }, | ||
304 | { "program-id", mu_cfg_string, &program_id_option, 0, NULL, | 367 | { "program-id", mu_cfg_string, &program_id_option, 0, NULL, |
305 | N_("Set program identifier string (default: program name)") }, | 368 | N_("Set program identifier string (default: program name)") }, |
306 | { "mailbox-ownership", mu_cfg_callback, NULL, 0, | 369 | { "mailbox-ownership", mu_cfg_callback, NULL, 0, |
... | @@ -312,6 +375,16 @@ struct mu_cfg_param movemail_cfg_param[] = { | ... | @@ -312,6 +375,16 @@ struct mu_cfg_param movemail_cfg_param[] = { |
312 | " set-id=UID[:GID] set supplied UID and GID\n" | 375 | " set-id=UID[:GID] set supplied UID and GID\n" |
313 | " set-name=USER make destination mailbox owned by USER"), | 376 | " set-name=USER make destination mailbox owned by USER"), |
314 | N_("methods: list") }, | 377 | N_("methods: list") }, |
378 | { "max-messages", mu_cfg_size, &max_messages_option, 0, NULL, | ||
379 | N_("Copy at most <count> messages."), | ||
380 | N_("count") }, | ||
381 | { "ignore-errors", mu_cfg_bool, &ignore_errors, 0, NULL, | ||
382 | N_("Continue after an error.") }, | ||
383 | { "onerror", mu_cfg_callback, NULL, 0, cb_onerror, | ||
384 | N_("What to do after an error. Argument is a comma-separated list of:\n" | ||
385 | " skip - skip to the next message\n" | ||
386 | " delete - delete this one and to the next message\n" | ||
387 | " count - count this message as processed") }, | ||
315 | { NULL } | 388 | { NULL } |
316 | }; | 389 | }; |
317 | 390 | ||
... | @@ -437,7 +510,8 @@ move_message (mu_mailbox_t src, mu_mailbox_t dst, size_t msgno) | ... | @@ -437,7 +510,8 @@ move_message (mu_mailbox_t src, mu_mailbox_t dst, size_t msgno) |
437 | { | 510 | { |
438 | mu_error (_("cannot append message %lu: %s"), | 511 | mu_error (_("cannot append message %lu: %s"), |
439 | (unsigned long) msgno, mu_strerror (rc)); | 512 | (unsigned long) msgno, mu_strerror (rc)); |
440 | return rc; | 513 | if (!(onerror_flags & ONERROR_DELETE)) |
514 | return rc; | ||
441 | } | 515 | } |
442 | if (!preserve_mail) | 516 | if (!preserve_mail) |
443 | { | 517 | { |
... | @@ -770,6 +844,9 @@ main (int argc, char **argv) | ... | @@ -770,6 +844,9 @@ main (int argc, char **argv) |
770 | return 1; | 844 | return 1; |
771 | } | 845 | } |
772 | 846 | ||
847 | if (ignore_errors) | ||
848 | onerror_flags |= ONERROR_SKIP; | ||
849 | |||
773 | if (emacs_mode) | 850 | if (emacs_mode) |
774 | { | 851 | { |
775 | /* Undo the effect of configuration options that may affect | 852 | /* Undo the effect of configuration options that may affect |
... | @@ -805,10 +882,22 @@ main (int argc, char **argv) | ... | @@ -805,10 +882,22 @@ main (int argc, char **argv) |
805 | } | 882 | } |
806 | 883 | ||
807 | if (verbose_option) | 884 | if (verbose_option) |
808 | mu_diag_output (MU_DIAG_INFO, | 885 | { |
809 | _("number of messages in source mailbox: %lu"), | 886 | mu_diag_output (MU_DIAG_INFO, |
810 | (unsigned long) total); | 887 | _("number of messages in source mailbox: %lu"), |
811 | 888 | (unsigned long) total); | |
889 | if (max_messages_option) | ||
890 | mu_diag_output (MU_DIAG_INFO, | ||
891 | reverse_order ? | ||
892 | ngettext ("will process last %lu message", | ||
893 | "will process last %lu messages", | ||
894 | max_messages_option) : | ||
895 | ngettext ("will process first %lu message", | ||
896 | "will process first %lu messages", | ||
897 | max_messages_option), | ||
898 | (unsigned long) max_messages_option); | ||
899 | } | ||
900 | |||
812 | if (uidl_option) | 901 | if (uidl_option) |
813 | { | 902 | { |
814 | mu_iterator_t itr; | 903 | mu_iterator_t itr; |
... | @@ -864,11 +953,19 @@ main (int argc, char **argv) | ... | @@ -864,11 +953,19 @@ main (int argc, char **argv) |
864 | mu_iterator_current (itr, (void **)&uidl); | 953 | mu_iterator_current (itr, (void **)&uidl); |
865 | rc = move_message (source, dest, uidl->msgno); | 954 | rc = move_message (source, dest, uidl->msgno); |
866 | if (rc == 0) | 955 | if (rc == 0) |
867 | msg_count++; | 956 | { |
868 | else if (!ignore_errors) | 957 | ++msg_count; |
869 | break; | 958 | } |
959 | else if (onerror_flags) | ||
960 | { | ||
961 | if (onerror_flags & ONERROR_COUNT) | ||
962 | ++msg_count; | ||
963 | errs = 1; | ||
964 | } | ||
870 | else | 965 | else |
871 | errs = 1; | 966 | break; |
967 | if (max_messages_option && msg_count >= max_messages_option) | ||
968 | break; | ||
872 | } | 969 | } |
873 | mu_iterator_destroy (&itr); | 970 | mu_iterator_destroy (&itr); |
874 | } | 971 | } |
... | @@ -878,11 +975,19 @@ main (int argc, char **argv) | ... | @@ -878,11 +975,19 @@ main (int argc, char **argv) |
878 | { | 975 | { |
879 | rc = move_message (source, dest, i); | 976 | rc = move_message (source, dest, i); |
880 | if (rc == 0) | 977 | if (rc == 0) |
881 | msg_count++; | 978 | { |
882 | else if (!ignore_errors) | 979 | ++msg_count; |
883 | break; | 980 | } |
981 | else if (onerror_flags) | ||
982 | { | ||
983 | if (onerror_flags & ONERROR_COUNT) | ||
984 | ++msg_count; | ||
985 | errs = 1; | ||
986 | } | ||
884 | else | 987 | else |
885 | errs = 1; | 988 | break; |
989 | if (max_messages_option && msg_count >= max_messages_option) | ||
990 | break; | ||
886 | } | 991 | } |
887 | } | 992 | } |
888 | else | 993 | else |
... | @@ -891,11 +996,19 @@ main (int argc, char **argv) | ... | @@ -891,11 +996,19 @@ main (int argc, char **argv) |
891 | { | 996 | { |
892 | rc = move_message (source, dest, i); | 997 | rc = move_message (source, dest, i); |
893 | if (rc == 0) | 998 | if (rc == 0) |
894 | msg_count++; | 999 | { |
895 | else if (!ignore_errors) | 1000 | ++msg_count; |
896 | break; | 1001 | } |
1002 | else if (onerror_flags) | ||
1003 | { | ||
1004 | if (onerror_flags & ONERROR_COUNT) | ||
1005 | ++msg_count; | ||
1006 | errs = 1; | ||
1007 | } | ||
897 | else | 1008 | else |
898 | errs = 1; | 1009 | break; |
1010 | if (max_messages_option && msg_count >= max_messages_option) | ||
1011 | break; | ||
899 | } | 1012 | } |
900 | } | 1013 | } |
901 | 1014 | ||
... | @@ -903,17 +1016,18 @@ main (int argc, char **argv) | ... | @@ -903,17 +1016,18 @@ main (int argc, char **argv) |
903 | mu_diag_output (MU_DIAG_INFO, | 1016 | mu_diag_output (MU_DIAG_INFO, |
904 | _("number of processed messages: %lu"), | 1017 | _("number of processed messages: %lu"), |
905 | (unsigned long) msg_count); | 1018 | (unsigned long) msg_count); |
906 | 1019 | ||
907 | if (rc) | 1020 | if (errs && !(onerror_flags & (ONERROR_DELETE|ONERROR_COUNT))) |
908 | return !!rc; | 1021 | /* FIXME: mailboxes are not properly closed */ |
909 | 1022 | return 1; | |
1023 | |||
910 | mu_mailbox_sync (dest); | 1024 | mu_mailbox_sync (dest); |
911 | rc = mu_mailbox_close (dest); | 1025 | rc = mu_mailbox_close (dest); |
912 | mu_mailbox_destroy (&dest); | 1026 | mu_mailbox_destroy (&dest); |
913 | if (rc) | 1027 | if (rc) |
914 | mu_error (_("cannot close destination mailbox: %s"), mu_strerror (rc)); | 1028 | mu_error (_("cannot close destination mailbox: %s"), mu_strerror (rc)); |
915 | else if (!preserve_mail) | 1029 | else if (!preserve_mail) |
916 | mu_mailbox_flush (source, 1); | 1030 | mu_mailbox_expunge (source); |
917 | 1031 | ||
918 | mu_mailbox_close (source); | 1032 | mu_mailbox_close (source); |
919 | mu_mailbox_destroy (&source); | 1033 | mu_mailbox_destroy (&source); | ... | ... |
-
Please register or sign in to post a comment