Commit 2428c02e 2428c02ed615f68711f7553641b430a7160f7f0a by Sergey Poznyakoff

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.
1 parent 4b30e617
...@@ -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);
......