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 *