X-Git-Url: http://git.chise.org/gitweb/?p=chise%2Fxemacs-chise.git.1;a=blobdiff_plain;f=lib-src%2Fmovemail.c;h=941ada90596c1daeb76bc3cc0c05144a6be9bc65;hp=0419719577c79bc973024fe95e5d2ec87580ef26;hb=716cfba952c1dc0d2cf5c968971f3780ba728a89;hpb=6883ee56ec887c2c48abe5b06b5e66aa74031910 diff --git a/lib-src/movemail.c b/lib-src/movemail.c index 0419719..941ada9 100644 --- a/lib-src/movemail.c +++ b/lib-src/movemail.c @@ -1,35 +1,41 @@ /* movemail foo bar -- move file foo to file bar, - locking file foo the way /bin/mail respects. + locking file foo. Copyright (C) 1986, 1992, 1993, 1994, 1996 Free Software Foundation, Inc. -This file is part of GNU Emacs. +This file is part of XEmacs. -GNU Emacs is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. +XEmacs is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. -GNU Emacs is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +XEmacs is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. You should have received a copy of the GNU General Public License -along with GNU Emacs; see the file COPYING. If not, write to +along with XEmacs; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +Boston, MA 02111-1307, USA. -/* Important notice: defining MAIL_USE_FLOCK or MAIL_USE_LOCKF *will - cause loss of mail* if you do it on a system that does not normally - use flock as its way of interlocking access to inbox files. The - setting of MAIL_USE_FLOCK and MAIL_USE_LOCKF *must agree* with the - system's own conventions. It is not a choice that is up to you. + Please mail bugs and suggestions to the XEmacs maintainer. +*/ - So, if your system uses lock files rather than flock, then the only way - you can get proper operation is to enable movemail to write lockfiles there. - This means you must either give that directory access modes - that permit everyone to write lockfiles in it, or you must make movemail - a setuid or setgid program. */ +/* Important notice: + * + * You *must* coordinate the locking method used by movemail with that + * used by your mail delivery agent, as well as that of the other mail + * user agents on your system. movemail allows you to do this at run + * time via the -m flag. Moreover, it uses a default determined by + * the MAIL_LOCK_DOT, MAIL_LOCK_LOCKF, MAIL_LOCK_FLOCK, + * MAIL_LOCK_LOCKING, and MAIL_LOCK_MMDF preprocessor settings. + */ + +/* + * Mike Sperber reorganized + * everything that has to with locking in December 1999. + */ /* * Modified January, 1986 by Michael R. Gretzinger (Project Athena) @@ -55,22 +61,30 @@ Boston, MA 02111-1307, USA. */ */ #define NO_SHORTNAMES /* Tell config not to load remap.h */ -#include <../src/config.h> +#define DONT_ENCAPSULATE +#include #include #include -#include #include #include +#include "../src/sysfile.h" #include "../src/syswait.h" +#ifndef WINDOWSNT #include "../src/systime.h" +#endif #include #include +#include "getopt.h" #ifdef MAIL_USE_POP #include "pop.h" +#include "../src/regex.h" #endif +extern char *optarg; +extern int optind, opterr; + #ifndef HAVE_STRERROR -static char * strerror (int errnum); +char * strerror (int errnum); #endif /* HAVE_STRERROR */ #ifdef MSDOS @@ -98,7 +112,7 @@ static char * strerror (int errnum); #include #endif /* WINDOWSNT */ -#if defined (HAVE_UNISTD_H) || defined (USG) +#if defined (HAVE_UNISTD_H) #include #endif /* unistd.h */ #ifndef F_OK @@ -108,23 +122,15 @@ static char * strerror (int errnum); #define R_OK 4 #endif /* No F_OK */ -#if defined (HAVE_FCNTL_H) || defined (USG) +#if defined (HAVE_FCNTL_H) #include #endif /* fcntl.h */ -#if defined (XENIX) || defined (WINDOWSNT) +#ifdef HAVE_LOCKING #include #endif -#ifdef MAIL_USE_LOCKF -#define MAIL_USE_SYSTEM_LOCK -#endif - -#ifdef MAIL_USE_FLOCK -#define MAIL_USE_SYSTEM_LOCK -#endif - -#ifdef MAIL_USE_MMDF +#ifdef HAVE_MMDF extern int lk_open (), lk_close (); #endif @@ -136,58 +142,179 @@ extern int lk_open (), lk_close (); static void fatal (char *, char*); static void error (char *, char *, char *); +static void usage(int); static void pfatal_with_name (char *); static void pfatal_and_delete (char *); static char *concat (char *, char *, char *); static long *xmalloc (unsigned int); #ifdef MAIL_USE_POP static int popmail (char *, char *, char *); -static int pop_retr (popserver server, int msgno, int (*action)(), void *arg); +static int pop_retr (popserver server, int msgno, + int (*action)(char *, FILE *), FILE *arg); static int mbx_write (char *, FILE *); static int mbx_delimit_begin (FILE *); static int mbx_delimit_end (FILE *); +static struct re_pattern_buffer* compile_regex (char* regexp_pattern); +static int pop_search_top (popserver server, int msgno, int lines, + struct re_pattern_buffer* regexp); +#endif + +int verbose=0; +#ifdef MAIL_USE_POP +int reverse=0; +int keep_messages=0; +struct re_pattern_buffer* regexp_pattern=0; +int match_lines=10; #endif -/* Nonzero means this is name of a lock file to delete on fatal error. */ -char *delete_lockname; +#define VERBOSE(x) if (verbose) { printf x; fflush(stdout); } + +struct option longopts[] = +{ + { "inbox", required_argument, NULL, 'i' }, + { "outfile", required_argument, NULL, 'o' }, +#ifdef MAIL_USE_POP + { "password", required_argument, NULL, 'p' }, + { "reverse-pop-order", no_argument, NULL, 'x' }, + { "keep-messages", no_argument, NULL, 'k' }, + { "regex", required_argument, NULL, 'r' }, + { "match-lines", required_argument, NULL, 'l' }, +#endif + { "lock-method", required_argument, NULL, 'm' }, + { "help", no_argument, NULL, 'h' }, + { "verbose", no_argument, NULL, 'v' }, + { 0 } +}; + +#define DOTLOCKING 0 +#define FLOCKING 1 +#define LOCKFING 2 +#define MMDF 3 +#define LOCKING 4 + +#if defined(MAIL_LOCK_FLOCK) && defined(HAVE_FLOCK) +#define DEFAULT_LOCKING FLOCKING +#elif defined(MAIL_LOCK_LOCKF) && defined(HAVE_LOCKF) +#define DEFAULT_LOCKING LOCKFING +#elif defined(MAIL_LOCK_MMDF) && defined(HAVE_MMDF) +#define DEFAULT_LOCKING MMDF +#elif defined(MAIL_LOCK_LOCKING) && defined(HAVE_LOCKING) +#define DEFAULT_LOCKING LOCKING +#else +#define DEFAULT_LOCKING DOTLOCKING +#endif + +static void lock_dot(char *); +static void unlock_dot(char *); +static int parse_lock_method(char *); +static char *unparse_lock_method(int); int main (int argc, char *argv[]) { - char *inname, *outname; + char *inname=0, *outname=0, *poppass=0; #ifndef DISABLE_DIRECT_ACCESS int indesc, outdesc; int nread; int status; #endif -#ifndef MAIL_USE_SYSTEM_LOCK - struct stat st; - long now; - int tem; - char *lockname, *p; - char *tempname; - int desc; -#endif /* not MAIL_USE_SYSTEM_LOCK */ + int lock_method = DEFAULT_LOCKING; - delete_lockname = 0; + char *maybe_lock_env; - if (argc < 3) + maybe_lock_env = getenv("EMACSLOCKMETHOD"); + if (maybe_lock_env) { - fprintf (stderr, "Usage: movemail inbox destfile [POP-password]\n"); - exit(1); + printf("maybe-lock_env: %s\n", maybe_lock_env); + lock_method = parse_lock_method(maybe_lock_env); + } + + for (;;) + { +#ifdef MAIL_USE_POP + char* optstring = "i:o:m:p:l:r:xvhk"; +#else + char* optstring = "i:o:m:vh"; +#endif + int opt = getopt_long (argc, argv, optstring, longopts, 0); + + if (opt == EOF) + break; + + switch (opt) + { + case 0: + break; + case 1: /* one of the standard arguments seen */ + if (!inname) + inname = optarg; + else if (!outname) + outname = optarg; + else + poppass = optarg; + break; + + case 'i': /* infile */ + inname = optarg; + break; + + case 'o': /* outfile */ + outname = optarg; + break; +#ifdef MAIL_USE_POP + case 'p': /* pop password */ + poppass = optarg; + break; + case 'k': keep_messages=1; break; + case 'x': reverse = 1; break; + case 'l': /* lines to match */ + match_lines = atoi (optarg); + break; + + case 'r': /* regular expression */ + regexp_pattern = compile_regex (optarg); + break; +#endif + + case 'm': + lock_method = parse_lock_method(optarg); + break; + case 'h': + usage(lock_method); + exit(0); + case 'v': + verbose = 1; + break; + } } - inname = argv[1]; - outname = argv[2]; + while (optind < argc) + { + if (!inname) + inname = argv[optind]; + else if (!outname) + outname = argv[optind]; + else + poppass = argv[optind]; + optind++; + } + + if (!inname || !outname) + { + usage(lock_method); + exit(1); + } -#ifdef MAIL_USE_MMDF - mmdf_init (argv[0]); +#ifdef HAVE_MMDF + if (lock_method == MMDF) + mmdf_init (argv[0]); #endif if (*outname == 0) fatal ("Destination file name is empty", 0); + VERBOSE(("checking access to output file\n")); /* Check access to output file. */ if (access (outname, F_OK) == 0 && access (outname, W_OK) != 0) pfatal_with_name (outname); @@ -210,11 +337,13 @@ main (int argc, char *argv[]) #ifdef MAIL_USE_POP if (!strncmp (inname, "po:", 3)) { - int retcode = popmail (inname + 3, outname, argc > 3 ? argv[3] : NULL); + int retcode = popmail (inname + 3, outname, poppass); exit (retcode); } +#ifndef WINDOWSNT setuid (getuid ()); +#endif #endif /* MAIL_USE_POP */ #ifndef DISABLE_DIRECT_ACCESS @@ -223,121 +352,83 @@ main (int argc, char *argv[]) if (access (inname, R_OK | W_OK) != 0) pfatal_with_name (inname); -#ifndef MAIL_USE_MMDF -#ifndef MAIL_USE_SYSTEM_LOCK - /* Use a lock file named after our first argument with .lock appended: - If it exists, the mail file is locked. */ - /* Note: this locking mechanism is *required* by the mailer - (on systems which use it) to prevent loss of mail. - - On systems that use a lock file, extracting the mail without locking - WILL occasionally cause loss of mail due to timing errors! - - So, if creation of the lock file fails - due to access permission on the mail spool directory, - you simply MUST change the permission - and/or make movemail a setgid program - so it can create lock files properly. - - You might also wish to verify that your system is one - which uses lock files for this purpose. Some systems use other methods. - - If your system uses the `flock' system call for mail locking, - define MAIL_USE_SYSTEM_LOCK in config.h or the s-*.h file - and recompile movemail. If the s- file for your system - should define MAIL_USE_SYSTEM_LOCK but does not, send a bug report - to bug-gnu-emacs@prep.ai.mit.edu so we can fix it. */ - - lockname = concat (inname, ".lock", ""); - tempname = (char *) xmalloc (strlen (inname) + strlen ("EXXXXXX") + 1); - strcpy (tempname, inname); - p = tempname + strlen (tempname); - while (p != tempname && !IS_DIRECTORY_SEP (p[-1])) - p--; - *p = 0; - strcpy (p, "EXXXXXX"); - mktemp (tempname); - unlink (tempname); - while (1) + if (fork () == 0) { - /* Create the lock file, but not under the lock file name. */ - /* Give up if cannot do that. */ - desc = open (tempname, O_WRONLY | O_CREAT | O_EXCL, 0666); - if (desc < 0) - { - char *message = (char *) xmalloc (strlen (tempname) + 50); - sprintf (message, "%s--see source file lib-src/movemail.c", - tempname); - pfatal_with_name (message); - } - close (desc); + setuid (getuid ()); - tem = link (tempname, lockname); - unlink (tempname); - if (tem >= 0) - break; - sleep (1); + VERBOSE(("opening input file\n")); - /* If lock file is five minutes old, unlock it. - Five minutes should be good enough to cope with crashes - and wedgitude, and long enough to avoid being fooled - by time differences between machines. */ - if (stat (lockname, &st) >= 0) + switch (lock_method) { - now = time (0); - if (st.st_ctime < now - 300) - unlink (lockname); + case DOTLOCKING: + indesc = open (inname, O_RDONLY); + break; +#ifdef HAVE_LOCKF + case LOCKFING: + indesc = open (inname, O_RDWR); + break; +#endif +#ifdef HAVE_FLOCK + case FLOCKING: + indesc = open (inname, O_RDWR); + break; +#endif +#ifdef HAVE_LOCKING + case LOCKING: + indesc = open (inname, O_RDWR); + break; +#endif +#ifdef HAVE_MMDF + case MMDF: + indesc = lk_open (inname, O_RDONLY, 0, 0, 10); + break; +#endif + default: abort(); } - } - - delete_lockname = lockname; -#endif /* not MAIL_USE_SYSTEM_LOCK */ -#endif /* not MAIL_USE_MMDF */ - - if (fork () == 0) - { - setuid (getuid ()); - -#ifndef MAIL_USE_MMDF -#ifdef MAIL_USE_SYSTEM_LOCK - indesc = open (inname, O_RDWR); -#else /* if not MAIL_USE_SYSTEM_LOCK */ - indesc = open (inname, O_RDONLY); -#endif /* not MAIL_USE_SYSTEM_LOCK */ -#else /* MAIL_USE_MMDF */ - indesc = lk_open (inname, O_RDONLY, 0, 0, 10); -#endif /* MAIL_USE_MMDF */ if (indesc < 0) pfatal_with_name (inname); -#if defined (BSD) || defined (XENIX) +#ifdef HAVE_UMASK /* In case movemail is setuid to root, make sure the user can read the output file. */ - /* This is desirable for all systems - but I don't want to assume all have the umask system call */ umask (umask (0) & 0333); -#endif /* BSD or Xenix */ +#endif + outdesc = open (outname, O_WRONLY | O_CREAT | O_EXCL, 0666); if (outdesc < 0) pfatal_with_name (outname); -#ifdef MAIL_USE_SYSTEM_LOCK -#ifdef MAIL_USE_LOCKF - if (lockf (indesc, F_LOCK, 0) < 0) pfatal_with_name (inname); -#else /* not MAIL_USE_LOCKF */ -#ifdef XENIX - if (locking (indesc, LK_RLCK, 0L) < 0) pfatal_with_name (inname); -#else -#ifdef WINDOWSNT - if (locking (indesc, LK_RLCK, -1L) < 0) pfatal_with_name (inname); -#else - if (flock (indesc, LOCK_EX) < 0) pfatal_with_name (inname); + + VERBOSE(("locking input file\n")); + + switch (lock_method) + { +#ifdef HAVE_LOCKF + case LOCKFING: + if (lockf (indesc, F_LOCK, 0) < 0) + pfatal_with_name (inname); + break; +#endif +#ifdef HAVE_FLOCK + case FLOCKING: + if (flock (indesc, LOCK_EX) < 0) + pfatal_with_name (inname); + break; #endif +#ifdef HAVE_LOCKING + case LOCKING: + if (locking (indesc, LK_RLCK, -1L) < 0) + pfatal_with_name (inname); + break; #endif -#endif /* not MAIL_USE_LOCKF */ -#endif /* MAIL_USE_SYSTEM_LOCK */ + case DOTLOCKING: + lock_dot(inname); + break; + } + VERBOSE(("copying input file to output file\n")); + { char buf[1024]; @@ -356,7 +447,7 @@ main (int argc, char *argv[]) } } -#ifdef BSD +#ifdef HAVE_FSYNC if (fsync (outdesc) < 0) pfatal_and_delete (outname); #endif @@ -365,31 +456,29 @@ main (int argc, char *argv[]) if (close (outdesc) != 0) pfatal_and_delete (outname); -#ifdef MAIL_USE_SYSTEM_LOCK -#if defined (STRIDE) || defined (XENIX) || defined (WINDOWSNT) - /* Stride, xenix have file locking, but no ftruncate. This mess will do. */ - close (open (inname, O_CREAT | O_TRUNC | O_RDWR, 0666)); -#else - ftruncate (indesc, 0L); -#endif /* STRIDE or XENIX */ -#endif /* MAIL_USE_SYSTEM_LOCK */ + VERBOSE(("deleting or truncating input file\n")); -#ifdef MAIL_USE_MMDF - lk_close (indesc, 0, 0, 0); + switch (lock_method) + { + case LOCKFING: + case FLOCKING: + case LOCKING: +#ifdef HAVE_FTRUNCATE + ftruncate (indesc, 0L); #else - close (indesc); + close (open (inname, O_CREAT | O_TRUNC | O_RDWR, 0666)); #endif - -#ifndef MAIL_USE_SYSTEM_LOCK - /* Delete the input file; if we can't, at least get rid of its - contents. */ -#ifdef MAIL_UNLINK_SPOOL - /* This is generally bad to do, because it destroys the permissions - that were set on the file. Better to just empty the file. */ - if (unlink (inname) < 0 && errno != ENOENT) -#endif /* MAIL_UNLINK_SPOOL */ - creat (inname, 0600); -#endif /* not MAIL_USE_SYSTEM_LOCK */ + close (indesc); + break; +#ifdef HAVE_MMDF + case MMDF: + lk_close (indesc, 0, 0, 0); + break; +#endif + case DOTLOCKING: + creat (inname, 0600); + break; + } exit (0); } @@ -400,22 +489,162 @@ main (int argc, char *argv[]) else if (WEXITSTATUS (status) != 0) exit (WEXITSTATUS (status)); -#if !defined (MAIL_USE_MMDF) && !defined (MAIL_USE_SYSTEM_LOCK) - unlink (lockname); -#endif /* not MAIL_USE_MMDF and not MAIL_USE_SYSTEM_LOCK */ + if (lock_method == DOTLOCKING) + unlock_dot(inname); -#endif /* ! DISABLE_DIRECT_ACCESS */ +#endif /* not DISABLE_DIRECT_ACCESS */ return 0; } - + +static void +usage(int lock_method) +{ + printf ("Usage: movemail [-rvxkh] [-l lines ] [-m method ] [-i] inbox [-o] destfile [[-p] POP-password]\n"); + printf("where method is one of: dot"); +#ifdef HAVE_LOCKF + printf(", lockf"); +#endif +#ifdef HAVE_FLOCK + printf(", flock"); +#endif +#ifdef HAVE_MMDF + printf(", mmdf"); +#endif +#ifdef HAVE_LOCKING + printf(", locking"); +#endif + printf("\nDefault is: %s\n", unparse_lock_method(lock_method)); + +} + +static char * +unparse_lock_method(int lock_method) +{ + switch (lock_method) + { + case DOTLOCKING: return "dot"; + case FLOCKING: return "flock"; + case LOCKFING: return "lockf"; + case LOCKING: return "locking"; + case MMDF: return "mmdf"; + default: abort();return 0; + } +} + +static int +parse_lock_method(char *method_name) +{ + if (!strcmp("dot", method_name) || !strcmp("file", method_name)) + return DOTLOCKING; +#ifdef HAVE_LOCKF + else if (!strcmp("lockf", method_name)) + return LOCKFING; +#endif +#ifdef HAVE_FLOCK + else if (!strcmp("flock", method_name)) + return FLOCKING; +#endif +#ifdef HAVE_MMDF + else if (!strcmp("mmdf", method_name)) + return MMDF; +#endif +#ifdef HAVE_LOCKING + else if (!strcmp("locking", method_name)) + return LOCKING; +#endif + else + fatal("invalid lock method: %s", method_name); + return 0; /* unreached */ +} + +static char * +dot_filename(char *filename) +{ + return concat (filename, ".lock", ""); +} + +static char *dotlock_filename = NULL; + +static void +lock_dot(char *filename) +{ + struct stat st; + long now; + int tem; + char *lockname, *p; + char *tempname; + int desc; + + dotlock_filename = (char *) xmalloc(strlen(filename) + 1); + + /* Use a lock file named after our first argument with .lock appended: + If it exists, the mail file is locked. */ + + lockname = dot_filename(filename); + tempname = (char *) xmalloc (strlen (filename) + strlen ("EXXXXXX") + 1); + strcpy (tempname, filename); + p = tempname + strlen (tempname); + while (p != tempname && !IS_DIRECTORY_SEP (p[-1])) + p--; + *p = 0; + strcpy (p, "EXXXXXX"); + mktemp (tempname); + unlink (tempname); + + for (;;) + { + /* Create the lock file, but not under the lock file name. */ + /* Give up if cannot do that. */ + desc = open (tempname, O_WRONLY | O_CREAT | O_EXCL, 0666); + if (desc < 0) + { + char *message = (char *) xmalloc (strlen (tempname) + 50); + sprintf (message, "%s--see source file lib-src/movemail.c", + tempname); + pfatal_with_name (message); + } + close (desc); + + tem = link (tempname, lockname); + unlink (tempname); + if (tem >= 0) + break; + sleep (1); + + /* If lock file is five minutes old, unlock it. + Five minutes should be good enough to cope with crashes + and wedgitude, and long enough to avoid being fooled + by time differences between machines. */ + if (stat (lockname, &st) >= 0) + { + now = time (0); + if (st.st_ctime < now - 300) + unlink (lockname); + } + } + strcpy(dotlock_filename, filename); +} + +static void +unlock_dot(char *filename) +{ + unlink(dot_filename(filename)); +} + +static void +maybe_unlock_dot(void) +{ + if (dotlock_filename) + unlock_dot(dotlock_filename); +} + /* Print error message and exit. */ static void fatal (char *s1, char *s2) { - if (delete_lockname) - unlink (delete_lockname); + maybe_unlock_dot(); error (s1, s2, NULL); exit (1); } @@ -471,7 +700,7 @@ xmalloc (unsigned int size) fatal ("virtual memory exhausted", 0); return result; } - + /* This is the guts of the interface to the Post Office Protocol. */ #ifdef MAIL_USE_POP @@ -487,9 +716,9 @@ xmalloc (unsigned int size) #include #include -#define NOTOK (-1) -#define OK 0 -#define DONE 1 +#define POP_ERROR (-1) +#define POP_RETRIEVED (0) +#define POP_DONE (1) char *progname; FILE *sfi; @@ -502,11 +731,13 @@ static int popmail (char *user, char *outfile, char *password) { int nmsgs, nbytes; - register int i; + register int i, idx; int mbfi; + short* retrieved_list; FILE *mbf; popserver server; + VERBOSE(("opening server\n")); server = pop_open (0, user, password, POP_NO_GETPASS); if (! server) { @@ -514,6 +745,7 @@ popmail (char *user, char *outfile, char *password) return (1); } + VERBOSE(("stat'ing messages\n")); if (pop_stat (server, &nmsgs, &nbytes)) { error (pop_error, NULL, NULL); @@ -522,10 +754,15 @@ popmail (char *user, char *outfile, char *password) if (!nmsgs) { + VERBOSE(("closing server\n")); pop_close (server); return (0); } + /* build a retrieved table */ + retrieved_list = (short*) xmalloc (sizeof (short) * (nmsgs+1)); + memset (retrieved_list, 0, sizeof (short) * (nmsgs+1)); + mbfi = open (outfile, O_WRONLY | O_CREAT | O_EXCL, 0666); if (mbfi < 0) { @@ -533,8 +770,8 @@ popmail (char *user, char *outfile, char *password) error ("Error in open: %s, %s", strerror (errno), outfile); return (1); } -#ifndef __CYGWIN32__ - fchown (mbfi, getuid (), -1); +#if !defined(__CYGWIN32__) && !defined(WINDOWSNT) + fchown (mbfi, getuid (), (gid_t) -1); #endif if ((mbf = fdopen (mbfi, "wb")) == NULL) @@ -546,23 +783,35 @@ popmail (char *user, char *outfile, char *password) return (1); } - for (i = 1; i <= nmsgs; i++) + for (idx = 0; idx < nmsgs; idx++) { - mbx_delimit_begin (mbf); - if (pop_retr (server, i, mbx_write, mbf) != OK) - { - error (Errmsg, NULL, NULL); - close (mbfi); - return (1); - } - mbx_delimit_end (mbf); - fflush (mbf); - if (ferror (mbf)) + i = reverse ? nmsgs - idx : idx + 1; + VERBOSE(("checking message %d \n", i)); + + if (!regexp_pattern + || + pop_search_top (server, i, match_lines, regexp_pattern) == POP_RETRIEVED) { - error ("Error in fflush: %s", strerror (errno), NULL); - pop_close (server); - close (mbfi); - return (1); + VERBOSE(("retrieving message %d \n", i)); + mbx_delimit_begin (mbf); + if (pop_retr (server, i, mbx_write, mbf) != POP_RETRIEVED) + { + error (Errmsg, NULL, NULL); + close (mbfi); + return (1); + } + + retrieved_list[i]=1; + + mbx_delimit_end (mbf); + fflush (mbf); + if (ferror (mbf)) + { + error ("Error in fflush: %s", strerror (errno), NULL); + pop_close (server); + close (mbfi); + return (1); + } } } @@ -572,7 +821,7 @@ popmail (char *user, char *outfile, char *password) * directories have lost mail when over quota because these checks were * not made in previous versions of movemail. */ -#ifdef BSD +#ifdef HAVE_FSYNC if (fsync (mbfi) < 0) { error ("Error in fsync: %s", strerror (errno), NULL); @@ -586,16 +835,24 @@ popmail (char *user, char *outfile, char *password) return (1); } - for (i = 1; i <= nmsgs; i++) + if (!keep_messages) { - if (pop_delete (server, i)) + for (i = 1; i <= nmsgs; i++) { - error (pop_error, NULL, NULL); - pop_close (server); - return (1); + if (retrieved_list[i] == 1) + { + VERBOSE(("deleting message %d \n", i)); + if (pop_delete (server, i)) + { + error (pop_error, NULL, NULL); + pop_close (server); + return (1); + } + } } } + VERBOSE(("closing server \n")); if (pop_quit (server)) { error (pop_error, NULL, NULL); @@ -606,7 +863,7 @@ popmail (char *user, char *outfile, char *password) } static int -pop_retr (popserver server, int msgno, int (*action)(), void *arg) +pop_retr (popserver server, int msgno, int (*action)(char *, FILE *), FILE *arg) { char *line; int ret; @@ -615,7 +872,7 @@ pop_retr (popserver server, int msgno, int (*action)(), void *arg) { strncpy (Errmsg, pop_error, sizeof (Errmsg)); Errmsg[sizeof (Errmsg)-1] = '\0'; - return (NOTOK); + return (POP_ERROR); } while (! (ret = pop_retrieve_next (server, &line))) @@ -623,11 +880,57 @@ pop_retr (popserver server, int msgno, int (*action)(), void *arg) if (! line) break; - if ((*action)(line, arg) != OK) + if ((*action)(line, arg) != POP_RETRIEVED) { strcpy (Errmsg, strerror (errno)); pop_close (server); - return (NOTOK); + return (POP_ERROR); + } + } + + if (ret) + { + strncpy (Errmsg, pop_error, sizeof (Errmsg)); + Errmsg[sizeof (Errmsg)-1] = '\0'; + return (POP_ERROR); + } + + return (POP_RETRIEVED); +} + +/* search the top lines of each message looking for a match */ +static int +pop_search_top (popserver server, int msgno, int lines, struct re_pattern_buffer* regexp) +{ + char *line; + int ret; + int match = POP_DONE; + + if (pop_top_first (server, msgno, lines, &line)) + { + strncpy (Errmsg, pop_error, sizeof (Errmsg)); + Errmsg[sizeof (Errmsg)-1] = '\0'; + return (POP_ERROR); + } + + while (! (ret = pop_top_next (server, &line))) + { + if (! line) + break; + + /* VERBOSE (("checking %s\n", line));*/ + if (match != POP_RETRIEVED) + { + if ((ret = re_match (regexp, line, strlen (line), 0, 0)) == -2 ) + { + strcpy (Errmsg, "error in regular expression"); + pop_close (server); + return (POP_ERROR); + } + else if (ret >=0) + { + match = POP_RETRIEVED; + } } } @@ -635,10 +938,10 @@ pop_retr (popserver server, int msgno, int (*action)(), void *arg) { strncpy (Errmsg, pop_error, sizeof (Errmsg)); Errmsg[sizeof (Errmsg)-1] = '\0'; - return (NOTOK); + return (POP_ERROR); } - return (OK); + return match; } /* Do this as a macro instead of using strcmp to save on execution time. */ @@ -654,35 +957,61 @@ mbx_write (char *line, FILE *mbf) if (IS_FROM_LINE (line)) { if (fputc ('>', mbf) == EOF) - return (NOTOK); + return (POP_ERROR); } if (fputs (line, mbf) == EOF) - return (NOTOK); + return (POP_ERROR); if (fputc (0x0a, mbf) == EOF) - return (NOTOK); - return (OK); + return (POP_ERROR); + return (POP_RETRIEVED); } static int mbx_delimit_begin (FILE *mbf) { if (fputs ("\f\n0, unseen,,\n", mbf) == EOF) - return (NOTOK); - return (OK); + return (POP_ERROR); + return (POP_RETRIEVED); } static int mbx_delimit_end (FILE *mbf) { if (putc ('\037', mbf) == EOF) - return (NOTOK); - return (OK); + return (POP_ERROR); + return (POP_RETRIEVED); } +/* Turn a name, which is an ed-style (but Emacs syntax) regular + expression, into a real regular expression by compiling it. */ +static struct re_pattern_buffer* +compile_regex (char* pattern) +{ + char *err; + struct re_pattern_buffer *patbuf=0; + + patbuf = (struct re_pattern_buffer*) xmalloc (sizeof (struct re_pattern_buffer)); + patbuf->translate = NULL; + patbuf->fastmap = NULL; + patbuf->buffer = NULL; + patbuf->allocated = 0; + + err = (char*) re_compile_pattern (pattern, strlen (pattern), patbuf); + if (err != NULL) + { + error ("%s while compiling pattern", err, NULL); + return 0; + } + + return patbuf; +} + + + #endif /* MAIL_USE_POP */ - + #ifndef HAVE_STRERROR -static char * +char * strerror (int errnum) { extern char *sys_errlist[];