Mercurial > hg > xemacs-beta
comparison lib-src/movemail.c @ 377:d883f39b8495 r21-2b4
Import from CVS: tag r21-2b4
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:05:42 +0200 |
parents | cc15677e0335 |
children | 8626e4521993 |
comparison
equal
deleted
inserted
replaced
376:e2295b4d9f2e | 377:d883f39b8495 |
---|---|
63 #include <errno.h> | 63 #include <errno.h> |
64 #include "../src/syswait.h" | 64 #include "../src/syswait.h" |
65 #include "../src/systime.h" | 65 #include "../src/systime.h" |
66 #include <stdlib.h> | 66 #include <stdlib.h> |
67 #include <string.h> | 67 #include <string.h> |
68 #include "getopt.h" | |
68 #ifdef MAIL_USE_POP | 69 #ifdef MAIL_USE_POP |
69 #include "pop.h" | 70 #include "pop.h" |
70 #endif | 71 #include <regex.h> |
72 #endif | |
73 | |
74 extern char *optarg; | |
75 extern int optind, opterr; | |
71 | 76 |
72 #ifndef HAVE_STRERROR | 77 #ifndef HAVE_STRERROR |
73 static char * strerror (int errnum); | 78 static char * strerror (int errnum); |
74 #endif /* HAVE_STRERROR */ | 79 #endif /* HAVE_STRERROR */ |
75 | 80 |
144 static int popmail (char *, char *, char *); | 149 static int popmail (char *, char *, char *); |
145 static int pop_retr (popserver server, int msgno, int (*action)(), void *arg); | 150 static int pop_retr (popserver server, int msgno, int (*action)(), void *arg); |
146 static int mbx_write (char *, FILE *); | 151 static int mbx_write (char *, FILE *); |
147 static int mbx_delimit_begin (FILE *); | 152 static int mbx_delimit_begin (FILE *); |
148 static int mbx_delimit_end (FILE *); | 153 static int mbx_delimit_end (FILE *); |
154 static struct re_pattern_buffer* compile_regex (char* regexp_pattern); | |
155 static int pop_search_top (popserver server, int msgno, int lines, | |
156 struct re_pattern_buffer* regexp); | |
149 #endif | 157 #endif |
150 | 158 |
151 /* Nonzero means this is name of a lock file to delete on fatal error. */ | 159 /* Nonzero means this is name of a lock file to delete on fatal error. */ |
152 char *delete_lockname; | 160 char *delete_lockname; |
153 | 161 |
162 int verbose=0; | |
163 #ifdef MAIL_USE_POP | |
164 int reverse=0; | |
165 int keep_messages=0; | |
166 struct re_pattern_buffer* regexp_pattern=0; | |
167 int match_lines=10; | |
168 #endif | |
169 | |
170 #define VERBOSE(x) if (verbose) { printf x; fflush(stdout); } | |
171 | |
172 struct option longopts[] = | |
173 { | |
174 { "inbox", required_argument, NULL, 'i' }, | |
175 { "outfile", required_argument, NULL, 'o' }, | |
176 #ifdef MAIL_USE_POP | |
177 { "password", required_argument, NULL, 'p' }, | |
178 { "reverse-pop-order", no_argument, NULL, 'x' }, | |
179 { "keep-messages", no_argument, NULL, 'k' }, | |
180 { "regex", required_argument, NULL, 'r' }, | |
181 { "match-lines", required_argument, NULL, 'l' }, | |
182 #endif | |
183 { "verbose", no_argument, NULL, 'v' }, | |
184 { 0 } | |
185 }; | |
186 | |
154 int | 187 int |
155 main (int argc, char *argv[]) | 188 main (int argc, char *argv[]) |
156 { | 189 { |
157 char *inname, *outname; | 190 char *inname=0, *outname=0, *poppass=0; |
158 #ifndef DISABLE_DIRECT_ACCESS | 191 #ifndef DISABLE_DIRECT_ACCESS |
159 int indesc, outdesc; | 192 int indesc, outdesc; |
160 int nread; | 193 int nread; |
161 int status; | 194 int status; |
162 #endif | 195 #endif |
170 int desc; | 203 int desc; |
171 #endif /* not MAIL_USE_SYSTEM_LOCK */ | 204 #endif /* not MAIL_USE_SYSTEM_LOCK */ |
172 | 205 |
173 delete_lockname = 0; | 206 delete_lockname = 0; |
174 | 207 |
175 if (argc < 3) | 208 while (1) |
176 { | 209 { |
177 fprintf (stderr, "Usage: movemail inbox destfile [POP-password]\n"); | 210 #ifdef MAIL_USE_POP |
211 char* optstring = "i:o:p:l:r:xvk"; | |
212 #else | |
213 char* optstring = "i:o:v"; | |
214 #endif | |
215 int opt = getopt_long (argc, argv, optstring, longopts, 0); | |
216 | |
217 if (opt == EOF) | |
218 break; | |
219 | |
220 switch (opt) | |
221 { | |
222 case 0: | |
223 break; | |
224 case 1: /* one of the standard arguments seen */ | |
225 if (!inname) | |
226 inname = optarg; | |
227 else if (!outname) | |
228 outname = optarg; | |
229 else | |
230 poppass = optarg; | |
231 break; | |
232 | |
233 case 'i': /* infile */ | |
234 inname = optarg; | |
235 break; | |
236 | |
237 case 'o': /* outfile */ | |
238 outname = optarg; | |
239 break; | |
240 #ifdef MAIL_USE_POP | |
241 case 'p': /* pop password */ | |
242 poppass = optarg; | |
243 break; | |
244 case 'k': keep_messages=1; break; | |
245 case 'x': reverse = 1; break; | |
246 case 'l': /* lines to match */ | |
247 match_lines = atoi (optarg); | |
248 break; | |
249 | |
250 case 'r': /* regular expression */ | |
251 regexp_pattern = compile_regex (optarg); | |
252 break; | |
253 #endif | |
254 case 'v': verbose = 1; break; | |
255 } | |
256 } | |
257 | |
258 while (optind < argc) | |
259 { | |
260 if (!inname) | |
261 inname = argv[optind]; | |
262 else if (!outname) | |
263 outname = argv[optind]; | |
264 else | |
265 poppass = argv[optind]; | |
266 optind++; | |
267 } | |
268 | |
269 if (!inname || !outname) | |
270 { | |
271 fprintf (stderr, "Usage: movemail [-rvxk] [-l lines ] [-i] inbox [-o] destfile [[-p] POP-password]\n"); | |
178 exit(1); | 272 exit(1); |
179 } | 273 } |
180 | |
181 inname = argv[1]; | |
182 outname = argv[2]; | |
183 | 274 |
184 #ifdef MAIL_USE_MMDF | 275 #ifdef MAIL_USE_MMDF |
185 mmdf_init (argv[0]); | 276 mmdf_init (argv[0]); |
186 #endif | 277 #endif |
187 | 278 |
208 } | 299 } |
209 | 300 |
210 #ifdef MAIL_USE_POP | 301 #ifdef MAIL_USE_POP |
211 if (!strncmp (inname, "po:", 3)) | 302 if (!strncmp (inname, "po:", 3)) |
212 { | 303 { |
213 int retcode = popmail (inname + 3, outname, argc > 3 ? argv[3] : NULL); | 304 int retcode = popmail (inname + 3, outname, poppass); |
214 exit (retcode); | 305 exit (retcode); |
215 } | 306 } |
216 | 307 |
217 setuid (getuid ()); | 308 setuid (getuid ()); |
218 #endif /* MAIL_USE_POP */ | 309 #endif /* MAIL_USE_POP */ |
485 #include <winsock.h> | 576 #include <winsock.h> |
486 #endif | 577 #endif |
487 #include <stdio.h> | 578 #include <stdio.h> |
488 #include <pwd.h> | 579 #include <pwd.h> |
489 | 580 |
490 #define NOTOK (-1) | 581 #define POP_ERROR (-1) |
491 #define OK 0 | 582 #define POP_RETRIEVED (0) |
492 #define DONE 1 | 583 #define POP_DONE (1) |
493 | 584 |
494 char *progname; | 585 char *progname; |
495 FILE *sfi; | 586 FILE *sfi; |
496 FILE *sfo; | 587 FILE *sfo; |
497 char ibuffer[BUFSIZ]; | 588 char ibuffer[BUFSIZ]; |
500 | 591 |
501 static int | 592 static int |
502 popmail (char *user, char *outfile, char *password) | 593 popmail (char *user, char *outfile, char *password) |
503 { | 594 { |
504 int nmsgs, nbytes; | 595 int nmsgs, nbytes; |
505 register int i; | 596 register int i, idx; |
506 int mbfi; | 597 int mbfi; |
598 short* retrieved_list; | |
507 FILE *mbf; | 599 FILE *mbf; |
508 popserver server; | 600 popserver server; |
509 | 601 |
602 VERBOSE(("opening server\r")); | |
510 server = pop_open (0, user, password, POP_NO_GETPASS); | 603 server = pop_open (0, user, password, POP_NO_GETPASS); |
511 if (! server) | 604 if (! server) |
512 { | 605 { |
513 error (pop_error, NULL, NULL); | 606 error (pop_error, NULL, NULL); |
514 return (1); | 607 return (1); |
515 } | 608 } |
516 | 609 |
610 VERBOSE(("stat'ing messages\r")); | |
517 if (pop_stat (server, &nmsgs, &nbytes)) | 611 if (pop_stat (server, &nmsgs, &nbytes)) |
518 { | 612 { |
519 error (pop_error, NULL, NULL); | 613 error (pop_error, NULL, NULL); |
520 return (1); | 614 return (1); |
521 } | 615 } |
522 | 616 |
523 if (!nmsgs) | 617 if (!nmsgs) |
524 { | 618 { |
619 VERBOSE(("closing server\n")); | |
525 pop_close (server); | 620 pop_close (server); |
526 return (0); | 621 return (0); |
527 } | 622 } |
623 | |
624 /* build a retrieved table */ | |
625 retrieved_list = (short*) xmalloc (sizeof (short) * (nmsgs+1)); | |
626 memset (retrieved_list, 0, sizeof (short) * (nmsgs+1)); | |
528 | 627 |
529 mbfi = open (outfile, O_WRONLY | O_CREAT | O_EXCL, 0666); | 628 mbfi = open (outfile, O_WRONLY | O_CREAT | O_EXCL, 0666); |
530 if (mbfi < 0) | 629 if (mbfi < 0) |
531 { | 630 { |
532 pop_close (server); | 631 pop_close (server); |
544 close (mbfi); | 643 close (mbfi); |
545 unlink (outfile); | 644 unlink (outfile); |
546 return (1); | 645 return (1); |
547 } | 646 } |
548 | 647 |
549 for (i = 1; i <= nmsgs; i++) | 648 for (idx = 0; idx < nmsgs; idx++) |
550 { | 649 { |
551 mbx_delimit_begin (mbf); | 650 i = reverse ? nmsgs - idx : idx + 1; |
552 if (pop_retr (server, i, mbx_write, mbf) != OK) | 651 VERBOSE(("checking message %d \r", i)); |
652 | |
653 if (!regexp_pattern | |
654 || | |
655 pop_search_top (server, i, match_lines, regexp_pattern) == POP_RETRIEVED) | |
553 { | 656 { |
554 error (Errmsg, NULL, NULL); | 657 VERBOSE(("retrieving message %d \r", i)); |
555 close (mbfi); | 658 mbx_delimit_begin (mbf); |
556 return (1); | 659 if (pop_retr (server, i, mbx_write, mbf) != POP_RETRIEVED) |
557 } | 660 { |
558 mbx_delimit_end (mbf); | 661 error (Errmsg, NULL, NULL); |
559 fflush (mbf); | 662 close (mbfi); |
560 if (ferror (mbf)) | 663 return (1); |
561 { | 664 } |
562 error ("Error in fflush: %s", strerror (errno), NULL); | 665 |
563 pop_close (server); | 666 retrieved_list[i]=1; |
564 close (mbfi); | 667 |
565 return (1); | 668 mbx_delimit_end (mbf); |
669 fflush (mbf); | |
670 if (ferror (mbf)) | |
671 { | |
672 error ("Error in fflush: %s", strerror (errno), NULL); | |
673 pop_close (server); | |
674 close (mbfi); | |
675 return (1); | |
676 } | |
566 } | 677 } |
567 } | 678 } |
568 | 679 |
569 /* On AFS, a call to write only modifies the file in the local | 680 /* On AFS, a call to write only modifies the file in the local |
570 * workstation's AFS cache. The changes are not written to the server | 681 * workstation's AFS cache. The changes are not written to the server |
584 { | 695 { |
585 error ("Error in close: %s", strerror (errno), NULL); | 696 error ("Error in close: %s", strerror (errno), NULL); |
586 return (1); | 697 return (1); |
587 } | 698 } |
588 | 699 |
589 for (i = 1; i <= nmsgs; i++) | 700 if (!keep_messages) |
590 { | 701 { |
591 if (pop_delete (server, i)) | 702 for (i = 1; i <= nmsgs; i++) |
592 { | 703 { |
593 error (pop_error, NULL, NULL); | 704 if (retrieved_list[i] == 1) |
594 pop_close (server); | 705 { |
595 return (1); | 706 VERBOSE(("deleting message %d \r", i)); |
707 if (pop_delete (server, i)) | |
708 { | |
709 error (pop_error, NULL, NULL); | |
710 pop_close (server); | |
711 return (1); | |
712 } | |
713 } | |
596 } | 714 } |
597 } | 715 } |
598 | 716 |
717 VERBOSE(("closing server \n")); | |
599 if (pop_quit (server)) | 718 if (pop_quit (server)) |
600 { | 719 { |
601 error (pop_error, NULL, NULL); | 720 error (pop_error, NULL, NULL); |
602 return (1); | 721 return (1); |
603 } | 722 } |
613 | 732 |
614 if (pop_retrieve_first (server, msgno, &line)) | 733 if (pop_retrieve_first (server, msgno, &line)) |
615 { | 734 { |
616 strncpy (Errmsg, pop_error, sizeof (Errmsg)); | 735 strncpy (Errmsg, pop_error, sizeof (Errmsg)); |
617 Errmsg[sizeof (Errmsg)-1] = '\0'; | 736 Errmsg[sizeof (Errmsg)-1] = '\0'; |
618 return (NOTOK); | 737 return (POP_ERROR); |
619 } | 738 } |
620 | 739 |
621 while (! (ret = pop_retrieve_next (server, &line))) | 740 while (! (ret = pop_retrieve_next (server, &line))) |
622 { | 741 { |
623 if (! line) | 742 if (! line) |
624 break; | 743 break; |
625 | 744 |
626 if ((*action)(line, arg) != OK) | 745 if ((*action)(line, arg) != POP_RETRIEVED) |
627 { | 746 { |
628 strcpy (Errmsg, strerror (errno)); | 747 strcpy (Errmsg, strerror (errno)); |
629 pop_close (server); | 748 pop_close (server); |
630 return (NOTOK); | 749 return (POP_ERROR); |
631 } | 750 } |
632 } | 751 } |
633 | 752 |
634 if (ret) | 753 if (ret) |
635 { | 754 { |
636 strncpy (Errmsg, pop_error, sizeof (Errmsg)); | 755 strncpy (Errmsg, pop_error, sizeof (Errmsg)); |
637 Errmsg[sizeof (Errmsg)-1] = '\0'; | 756 Errmsg[sizeof (Errmsg)-1] = '\0'; |
638 return (NOTOK); | 757 return (POP_ERROR); |
639 } | 758 } |
640 | 759 |
641 return (OK); | 760 return (POP_RETRIEVED); |
761 } | |
762 | |
763 /* search the top lines of each message looking for a match */ | |
764 static int | |
765 pop_search_top (popserver server, int msgno, int lines, struct re_pattern_buffer* regexp) | |
766 { | |
767 char *line; | |
768 int ret; | |
769 int match = POP_DONE; | |
770 | |
771 if (pop_top_first (server, msgno, lines, &line)) | |
772 { | |
773 strncpy (Errmsg, pop_error, sizeof (Errmsg)); | |
774 Errmsg[sizeof (Errmsg)-1] = '\0'; | |
775 return (POP_ERROR); | |
776 } | |
777 | |
778 while (! (ret = pop_top_next (server, &line))) | |
779 { | |
780 if (! line) | |
781 break; | |
782 | |
783 /* VERBOSE (("checking %s\n", line));*/ | |
784 if (match != POP_RETRIEVED) | |
785 { | |
786 if ((ret = re_match (regexp, line, strlen (line), 0, 0)) == -2 ) | |
787 { | |
788 strcpy (Errmsg, "error in regular expression"); | |
789 pop_close (server); | |
790 return (POP_ERROR); | |
791 } | |
792 else if (ret >=0) | |
793 { | |
794 match = POP_RETRIEVED; | |
795 } | |
796 } | |
797 } | |
798 | |
799 if (ret) | |
800 { | |
801 strncpy (Errmsg, pop_error, sizeof (Errmsg)); | |
802 Errmsg[sizeof (Errmsg)-1] = '\0'; | |
803 return (POP_ERROR); | |
804 } | |
805 | |
806 return match; | |
642 } | 807 } |
643 | 808 |
644 /* Do this as a macro instead of using strcmp to save on execution time. */ | 809 /* Do this as a macro instead of using strcmp to save on execution time. */ |
645 #define IS_FROM_LINE(a) ((a[0] == 'F') \ | 810 #define IS_FROM_LINE(a) ((a[0] == 'F') \ |
646 && (a[1] == 'r') \ | 811 && (a[1] == 'r') \ |
652 mbx_write (char *line, FILE *mbf) | 817 mbx_write (char *line, FILE *mbf) |
653 { | 818 { |
654 if (IS_FROM_LINE (line)) | 819 if (IS_FROM_LINE (line)) |
655 { | 820 { |
656 if (fputc ('>', mbf) == EOF) | 821 if (fputc ('>', mbf) == EOF) |
657 return (NOTOK); | 822 return (POP_ERROR); |
658 } | 823 } |
659 if (fputs (line, mbf) == EOF) | 824 if (fputs (line, mbf) == EOF) |
660 return (NOTOK); | 825 return (POP_ERROR); |
661 if (fputc (0x0a, mbf) == EOF) | 826 if (fputc (0x0a, mbf) == EOF) |
662 return (NOTOK); | 827 return (POP_ERROR); |
663 return (OK); | 828 return (POP_RETRIEVED); |
664 } | 829 } |
665 | 830 |
666 static int | 831 static int |
667 mbx_delimit_begin (FILE *mbf) | 832 mbx_delimit_begin (FILE *mbf) |
668 { | 833 { |
669 if (fputs ("\f\n0, unseen,,\n", mbf) == EOF) | 834 if (fputs ("\f\n0, unseen,,\n", mbf) == EOF) |
670 return (NOTOK); | 835 return (POP_ERROR); |
671 return (OK); | 836 return (POP_RETRIEVED); |
672 } | 837 } |
673 | 838 |
674 static int | 839 static int |
675 mbx_delimit_end (FILE *mbf) | 840 mbx_delimit_end (FILE *mbf) |
676 { | 841 { |
677 if (putc ('\037', mbf) == EOF) | 842 if (putc ('\037', mbf) == EOF) |
678 return (NOTOK); | 843 return (POP_ERROR); |
679 return (OK); | 844 return (POP_RETRIEVED); |
680 } | 845 } |
846 | |
847 /* Turn a name, which is an ed-style (but Emacs syntax) regular | |
848 expression, into a real regular expression by compiling it. */ | |
849 static struct re_pattern_buffer* | |
850 compile_regex (char* regexp_pattern) | |
851 { | |
852 char *err; | |
853 struct re_pattern_buffer *patbuf=0; | |
854 | |
855 patbuf = (struct re_pattern_buffer*) xmalloc (sizeof (struct re_pattern_buffer)); | |
856 patbuf->translate = NULL; | |
857 patbuf->fastmap = NULL; | |
858 patbuf->buffer = NULL; | |
859 patbuf->allocated = 0; | |
860 | |
861 err = (char*) re_compile_pattern (regexp_pattern, strlen (regexp_pattern), patbuf); | |
862 if (err != NULL) | |
863 { | |
864 error ("%s while compiling pattern", err, NULL); | |
865 return 0; | |
866 } | |
867 | |
868 return patbuf; | |
869 } | |
870 | |
871 | |
681 | 872 |
682 #endif /* MAIL_USE_POP */ | 873 #endif /* MAIL_USE_POP */ |
683 | 874 |
684 #ifndef HAVE_STRERROR | 875 #ifndef HAVE_STRERROR |
685 static char * | 876 static char * |