Mercurial > hg > xemacs-beta
diff lib-src/movemail.c @ 70:131b0175ea99 r20-0b30
Import from CVS: tag r20-0b30
author | cvs |
---|---|
date | Mon, 13 Aug 2007 09:02:59 +0200 |
parents | 05472e90ae02 |
children | 7d55a9ba150c |
line wrap: on
line diff
--- a/lib-src/movemail.c Mon Aug 13 09:00:04 2007 +0200 +++ b/lib-src/movemail.c Mon Aug 13 09:02:59 2007 +0200 @@ -1,6 +1,6 @@ /* movemail foo bar -- move file foo to file bar, locking file foo the way /bin/mail respects. - Copyright (C) 1986, 1992, 1993, 1994, 1996 Free Software Foundation, Inc. + Copyright (C) 1986, 1992, 1993, 1994 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -16,9 +16,11 @@ You should have received a copy of the GNU General Public License along with GNU Emacs; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +the Free the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* Synched up with: FSF 19.28. */ + /* 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 @@ -34,7 +36,7 @@ /* * Modified January, 1986 by Michael R. Gretzinger (Project Athena) * - * Added POP (Post Office Protocol) service. When compiled -DMAIL_USE_POP + * Added POP (Post Office Protocol) service. When compiled -DPOP * movemail will accept input filename arguments of the form * "po:username". This will cause movemail to open a connection to * a pop server running on $MAILHOST (environment variable). Movemail @@ -47,71 +49,45 @@ * New routines in movemail.c: * get_errmsg - return pointer to system error message * - * Modified August, 1993 by Jonathan Kamens (OpenVision Technologies) - * - * Move all of the POP code into a separate file, "pop.c". - * Use strerror instead of get_errmsg. - * */ #define NO_SHORTNAMES /* Tell config not to load remap.h */ #include <../src/config.h> +#include <stdlib.h> +#include <unistd.h> +#include <time.h> /* for time() */ +#include <stdio.h> /* for printf() */ +#include <string.h> /* strcpy() */ + #include <sys/types.h> #include <sys/stat.h> #include <sys/file.h> -#include <stdio.h> #include <errno.h> -#include "../src/syswait.h" -#include "../src/systime.h" -#include <stdlib.h> -#include <string.h> -#ifdef MAIL_USE_POP -#include "pop.h" -#endif - -#ifndef HAVE_STRERROR -static char * strerror (int errnum); -#endif /* HAVE_STRERROR */ +#include <../src/syswait.h> #ifdef MSDOS #undef access #endif /* MSDOS */ -#ifndef DIRECTORY_SEP -#define DIRECTORY_SEP '/' -#endif -#ifndef IS_DIRECTORY_SEP -#define IS_DIRECTORY_SEP(_c_) ((_c_) == DIRECTORY_SEP) -#endif - -#ifdef WINDOWSNT -#undef access -#undef unlink -#define fork() 0 -#define sys_wait(var) (*(var) = 0) -/* Unfortunately, Samba doesn't seem to properly lock Unix files even - though the locking call succeeds (and indeed blocks local access from - other NT programs). If you have direct file access using an NFS - client or something other than Samba, the locking call might work - properly - make sure it does before you enable this! */ -#define DISABLE_DIRECT_ACCESS -#endif /* WINDOWSNT */ - -#if defined (HAVE_UNISTD_H) || defined (USG) +#ifdef USG +#include <fcntl.h> #include <unistd.h> -#endif /* unistd.h */ +#if defined (sun) +#include <stdlib.h> +#endif /* sun */ #ifndef F_OK #define F_OK 0 #define X_OK 1 #define W_OK 2 #define R_OK 4 -#endif /* No F_OK */ +#endif +#endif /* USG */ -#if defined (HAVE_FCNTL_H) || defined (USG) -#include <fcntl.h> -#endif /* fcntl.h */ +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif -#if defined (XENIX) || defined (WINDOWSNT) +#ifdef XENIX #include <sys/locking.h> #endif @@ -133,30 +109,33 @@ #undef write #undef close -static void fatal (char *, char*); -static void error (char *, char *, char *); -static void pfatal_with_name (char *); -static void pfatal_and_delete (char *); -static char *concat (char *, char *, char *); -static long *xmalloc (unsigned int); -static int popmail (char *, char *, char *); -#ifdef MAIL_USE_POP -static int pop_retr (popserver server, int msgno, int (*action)(), int arg); +static char *concat (CONST char *s1, CONST char *s2, CONST char *s3); +static void *xmalloc (unsigned int size); +#ifndef errno +extern int errno; #endif -static int mbx_write (char *, FILE *); -static int mbx_delimit_begin (FILE *); -static int mbx_delimit_end (FILE *); + +static void error (CONST char *s1, CONST char *s2, CONST char *s3); +static void fatal (CONST char *s1, CONST char *s2); +static void pfatal_with_name (CONST char *name); +static void pfatal_and_delete (CONST char *name); + +#ifndef HAVE_STRERROR +char *strerror (int); +#endif /* Nonzero means this is name of a lock file to delete on fatal error. */ char *delete_lockname; -int -main (int argc, char *argv[]) +void +main (argc, argv) + int argc; + char **argv; { char *inname, *outname; int indesc, outdesc; int nread; - int status; + WAITTYPE status; #ifndef MAIL_USE_SYSTEM_LOCK struct stat st; @@ -170,10 +149,7 @@ delete_lockname = 0; if (argc < 3) - { - fprintf (stderr, "Usage: movemail inbox destfile [POP-password]\n"); - exit(1); - } + fatal ("two arguments required", ""); inname = argv[1]; outname = argv[2]; @@ -182,49 +158,48 @@ mmdf_init (argv[0]); #endif - if (*outname == 0) - fatal ("Destination file name is empty", 0); - /* Check access to output file. */ if (access (outname, F_OK) == 0 && access (outname, W_OK) != 0) pfatal_with_name (outname); - /* Also check that outname's directory is writable to the real uid. */ + /* Also check that outname's directory is writeable to the real uid. */ { char *buf = (char *) xmalloc (strlen (outname) + 1); - char *cp; + char *p; strcpy (buf, outname); - cp = buf + strlen (buf); - while (cp > buf && !IS_DIRECTORY_SEP (cp[-1])) - *--cp = 0; - if (cp == buf) - *cp++ = '.'; + p = buf + strlen (buf); + while (p > buf && p[-1] != '/') + *--p = 0; + if (p == buf) + *p++ = '.'; if (access (buf, W_OK) != 0) pfatal_with_name (buf); free (buf); } #ifdef MAIL_USE_POP - if (!strncmp (inname, "po:", 3)) + if (!memcmp (inname, "po:", 3)) { - int status; + int status; char *user; - status = popmail (inname + 3, outname, argc > 3 ? argv[3] : NULL); + for (user = &inname[strlen (inname) - 1]; user >= inname; user--) + if (*user == ':') + break; + + status = popmail (user, outname); exit (status); } setuid (getuid ()); #endif /* MAIL_USE_POP */ -#ifndef DISABLE_DIRECT_ACCESS - /* Check access to input file. */ 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: + /* Use a lock file named /usr/spool/mail/$USER.lock: 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. @@ -233,7 +208,7 @@ 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, + due to access permission on /usr/spool/mail, you simply MUST change the permission and/or make movemail a setgid program so it can create lock files properly. @@ -251,7 +226,7 @@ tempname = (char *) xmalloc (strlen (inname) + strlen ("EXXXXXX") + 1); strcpy (tempname, inname); p = tempname + strlen (tempname); - while (p != tempname && !IS_DIRECTORY_SEP (p[-1])) + while (p != tempname && p[-1] != '/') p--; *p = 0; strcpy (p, "EXXXXXX"); @@ -264,12 +239,7 @@ /* 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); - } + pfatal_with_name ("lock file--see source file lib-src/movemail.c"); close (desc); tem = link (tempname, lockname); @@ -278,15 +248,12 @@ 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 lock file is a minute old, unlock it. */ if (stat (lockname, &st) >= 0) { now = time (0); - if (st.st_ctime < now - 300) - unlink (lockname); + if (st.st_ctime < now - 60) + unlink (lockname); } } @@ -328,12 +295,8 @@ #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); #endif -#endif #endif /* not MAIL_USE_LOCKF */ #endif /* MAIL_USE_SYSTEM_LOCK */ @@ -365,7 +328,7 @@ pfatal_and_delete (outname); #ifdef MAIL_USE_SYSTEM_LOCK -#if defined (STRIDE) || defined (XENIX) || defined (WINDOWSNT) +#if defined (STRIDE) || defined (XENIX) /* Stride, xenix have file locking, but no ftruncate. This mess will do. */ close (open (inname, O_CREAT | O_TRUNC | O_RDWR, 0666)); #else @@ -396,50 +359,55 @@ wait (&status); if (!WIFEXITED (status)) exit (1); - else if (WEXITSTATUS (status) != 0) - exit (WEXITSTATUS (status)); + else if (WRETCODE (status) != 0) + exit (WRETCODE (status)); #if !defined (MAIL_USE_MMDF) && !defined (MAIL_USE_SYSTEM_LOCK) unlink (lockname); #endif /* not MAIL_USE_MMDF and not MAIL_USE_SYSTEM_LOCK */ - -#endif /* ! DISABLE_DIRECT_ACCESS */ - - return 0; + exit (0); } /* Print error message and exit. */ static void -fatal (char *s1, char *s2) +fatal (s1, s2) + CONST char *s1, *s2; { if (delete_lockname) + error (s1, s2, ""); unlink (delete_lockname); - error (s1, s2, NULL); exit (1); } /* Print error message. `s1' is printf control string, `s2' is arg for it. */ static void -error (char *s1, char *s2, char *s3) +error (s1, s2, s3) + CONST char *s1, *s2, *s3; { - fprintf (stderr, "movemail: "); - fprintf (stderr, s1, s2, s3); - fprintf (stderr, "\n"); + printf ("movemail: "); + printf (s1, s2, s3); + printf ("\n"); } static void -pfatal_with_name (char *name) +pfatal_with_name (name) + CONST char *name; { - char *s = concat ("", strerror (errno), " for %s"); + char *s; + + s = concat ("", strerror (errno), " for %s"); fatal (s, name); } static void -pfatal_and_delete (char *name) +pfatal_and_delete (name) + CONST char *name; { - char *s = concat ("", strerror (errno), " for %s"); + char *s; + + s = concat ("", strerror (errno), " for %s"); unlink (name); fatal (s, name); } @@ -447,7 +415,8 @@ /* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */ static char * -concat (char *s1, char *s2, char *s3) +concat (s1, s2, s3) + CONST char *s1, *s2, *s3; { int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3); char *result = (char *) xmalloc (len1 + len2 + len3 + 1); @@ -462,12 +431,13 @@ /* Like malloc but get fatal error if memory is exhausted. */ -static long * -xmalloc (unsigned int size) +static void * +xmalloc (size) + unsigned int size; { - long *result = (long *) malloc (size); + void *result = (void *) malloc (size); if (!result) - fatal ("virtual memory exhausted", 0); + fatal ("virtual memory exhausted", (char *) 0); return result; } @@ -475,17 +445,21 @@ #ifdef MAIL_USE_POP -#ifndef WINDOWSNT #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> -#else -#undef _WINSOCKAPI_ -#include <winsock.h> -#endif #include <stdio.h> #include <pwd.h> +#ifdef USG +#include <fcntl.h> +/* Cancel substitutions made by config.h for Emacs. */ +#undef open +#undef read +#undef write +#undef close +#endif /* USG */ + #define NOTOK (-1) #define OK 0 #define DONE 1 @@ -493,197 +467,352 @@ char *progname; FILE *sfi; FILE *sfo; -char ibuffer[BUFSIZ]; -char obuffer[BUFSIZ]; char Errmsg[80]; -static int -popmail (char *user, char *outfile, char *password) +static int debug = 0; + +char *get_errmsg (); +char *getenv (); +int mbx_write (); + +int +popmail (user, outfile) + char *user; + char *outfile; { + char *host; int nmsgs, nbytes; + char response[128]; register int i; int mbfi; FILE *mbf; - char *getenv (); - int mbx_write (); - popserver server; - extern char *strerror (); + struct passwd *pw = (struct passwd *) getpwuid (getuid ()); + if (pw == NULL) + fatal ("cannot determine user name"); - server = pop_open (0, user, password, POP_NO_GETPASS); - if (! server) + host = getenv ("MAILHOST"); + if (host == NULL) { - error (pop_error, NULL, NULL); - return (1); + fatal ("no MAILHOST defined"); + } + + if (pop_init (host) == NOTOK) + { + fatal (Errmsg); } - if (pop_stat (server, &nmsgs, &nbytes)) + if (getline (response, sizeof response, sfi) != OK) + { + fatal (response); + } + + if (pop_command ("USER %s", user) == NOTOK + || pop_command ("RPOP %s", pw->pw_name) == NOTOK) { - error (pop_error, NULL, NULL); - return (1); + pop_command ("QUIT"); + fatal (Errmsg); + } + + if (pop_stat (&nmsgs, &nbytes) == NOTOK) + { + pop_command ("QUIT"); + fatal (Errmsg); } if (!nmsgs) - { - pop_close (server); - return (0); - } + { + pop_command ("QUIT"); + return 0; + } mbfi = open (outfile, O_WRONLY | O_CREAT | O_EXCL, 0666); if (mbfi < 0) - { - pop_close (server); - error ("Error in open: %s, %s", strerror (errno), outfile); - return (1); - } + { + pop_command ("QUIT"); + pfatal_and_delete (outfile); + } fchown (mbfi, getuid (), -1); - if ((mbf = fdopen (mbfi, "wb")) == NULL) + if ((mbf = fdopen (mbfi, "w")) == NULL) { - pop_close (server); - error ("Error in fdopen: %s", strerror (errno), NULL); - close (mbfi); - unlink (outfile); - return (1); + pop_command ("QUIT"); + pfatal_and_delete (outfile); } - for (i = 1; i <= nmsgs; i++) + for (i = 1; i <= nmsgs; i++) { mbx_delimit_begin (mbf); - if (pop_retr (server, i, mbx_write, mbf) != OK) - { - error (Errmsg, NULL, NULL); - close (mbfi); - return (1); - } + if (pop_retr (i, mbx_write, mbf) != OK) + { + pop_command ("QUIT"); + close (mbfi); + unlink (outfile); + fatal (Errmsg); + } mbx_delimit_end (mbf); fflush (mbf); - if (ferror (mbf)) - { - error ("Error in fflush: %s", strerror (errno), NULL); - pop_close (server); - close (mbfi); - return (1); - } } - /* On AFS, a call to write only modifies the file in the local - * workstation's AFS cache. The changes are not written to the server - * until a call to fsync or close is made. Users with AFS home - * directories have lost mail when over quota because these checks were - * not made in previous versions of movemail. */ - -#ifdef BSD if (fsync (mbfi) < 0) { - error ("Error in fsync: %s", strerror (errno), NULL); - return (1); + pop_command ("QUIT"); + pfatal_and_delete (outfile); } -#endif if (close (mbfi) == -1) { - error ("Error in close: %s", strerror (errno), NULL); - return (1); + pop_command ("QUIT"); + pfatal_and_delete (outfile); } - for (i = 1; i <= nmsgs; i++) + for (i = 1; i <= nmsgs; i++) { - if (pop_delete (server, i)) - { - error (pop_error, NULL, NULL); - pop_close (server); - return (1); - } + if (pop_command ("DELE %d", i) == NOTOK) + { + /* Better to ignore this failure. */ + } } - if (pop_quit (server)) - { - error (pop_error, NULL, NULL); - return (1); - } - + pop_command ("QUIT"); return (0); } -static int -pop_retr (popserver server, int msgno, int (*action)(), int arg) +int +pop_init (host) + char *host; { - char *line; - int ret; + register struct hostent *hp; + register struct servent *sp; + int lport = IPPORT_RESERVED - 1; + struct sockaddr_in sin; + register int s; + + hp = gethostbyname (host); + if (hp == NULL) + { + sprintf (Errmsg, "MAILHOST unknown: %s", host); + return NOTOK; + } + + sp = getservbyname ("pop", "tcp"); + if (sp == 0) + { + strcpy (Errmsg, "tcp/pop: unknown service"); + return NOTOK; + } - if (pop_retrieve_first (server, msgno, &line)) + sin.sin_family = hp->h_addrtype; + memcpy ((char *)&sin.sin_addr, hp->h_addr, hp->h_length); + sin.sin_port = sp->s_port; + s = rresvport (&lport); + if (s < 0) + { + sprintf (Errmsg, "error creating socket: %s", get_errmsg ()); + return NOTOK; + } + + if (connect (s, (char *)&sin, sizeof sin) < 0) { - strncpy (Errmsg, pop_error, sizeof (Errmsg)); - Errmsg[sizeof (Errmsg)-1] = '\0'; - return (NOTOK); + sprintf (Errmsg, "error during connect: %s", get_errmsg ()); + close (s); + return NOTOK; + } + + sfi = fdopen (s, "r"); + sfo = fdopen (s, "w"); + if (sfi == NULL || sfo == NULL) + { + sprintf (Errmsg, "error in fdopen: %s", get_errmsg ()); + close (s); + return NOTOK; } - while (! (ret = pop_retrieve_next (server, &line))) - { - if (! line) - break; + return OK; +} + +int +pop_command (fmt, a, b, c, d) + char *fmt; +{ + char buf[128]; + char errmsg[64]; - if ((*action)(line, arg) != OK) - { - strcpy (Errmsg, strerror (errno)); - pop_close (server); - return (NOTOK); - } + sprintf (buf, fmt, a, b, c, d); + + if (debug) fprintf (stderr, "---> %s\n", buf); + if (putline (buf, Errmsg, sfo) == NOTOK) return NOTOK; + + if (getline (buf, sizeof buf, sfi) != OK) + { + strcpy (Errmsg, buf); + return NOTOK; } - if (ret) + if (debug) fprintf (stderr, "<--- %s\n", buf); + if (*buf != '+') + { + strcpy (Errmsg, buf); + return NOTOK; + } + else { - strncpy (Errmsg, pop_error, sizeof (Errmsg)); - Errmsg[sizeof (Errmsg)-1] = '\0'; - return (NOTOK); + return OK; + } +} + + +pop_stat (nmsgs, nbytes) + int *nmsgs, *nbytes; +{ + char buf[128]; + + if (debug) fprintf (stderr, "---> STAT\n"); + if (putline ("STAT", Errmsg, sfo) == NOTOK) + return NOTOK; + + if (getline (buf, sizeof buf, sfi) != OK) + { + strcpy (Errmsg, buf); + return NOTOK; } - return (OK); + if (debug) fprintf (stderr, "<--- %s\n", buf); + if (*buf != '+') + { + strcpy (Errmsg, buf); + return NOTOK; + } + else + { + sscanf (buf, "+OK %d %d", nmsgs, nbytes); + return OK; + } } -/* Do this as a macro instead of using strcmp to save on execution time. */ -#define IS_FROM_LINE(a) ((a[0] == 'F') \ - && (a[1] == 'r') \ - && (a[2] == 'o') \ - && (a[3] == 'm') \ - && (a[4] == ' ')) - -static int -mbx_write (char *line, FILE *mbf) +pop_retr (msgno, action, arg) + int (*action)(); { - if (IS_FROM_LINE (line)) + char buf[128]; + + sprintf (buf, "RETR %d", msgno); + if (debug) fprintf (stderr, "%s\n", buf); + if (putline (buf, Errmsg, sfo) == NOTOK) return NOTOK; + + if (getline (buf, sizeof buf, sfi) != OK) { - if (fputc ('>', mbf) == EOF) - return (NOTOK); + strcpy (Errmsg, buf); + return NOTOK; } - if (fputs (line, mbf) == EOF) - return (NOTOK); - if (fputc (0x0a, mbf) == EOF) - return (NOTOK); - return (OK); + + while (1) + { + switch (multiline (buf, sizeof buf, sfi)) + { + case OK: + (*action)(buf, arg); + break; + case DONE: + return OK; + case NOTOK: + strcpy (Errmsg, buf); + return NOTOK; + } + } } -static int -mbx_delimit_begin (FILE *mbf) +getline (buf, n, f) + char *buf; + register int n; + FILE *f; { - if (fputs ("\f\n0, unseen,,\n", mbf) == EOF) - return (NOTOK); - return (OK); + register char *p; + int c; + + p = buf; + while (--n > 0 && (c = fgetc (f)) != EOF) + if ((*p++ = c) == '\n') break; + + if (ferror (f)) + { + strcpy (buf, "error on connection"); + return NOTOK; + } + + if (c == EOF && p == buf) + { + strcpy (buf, "connection closed by foreign host"); + return DONE; + } + + *p = NULL; + if (*--p == '\n') *p = NULL; + if (*--p == '\r') *p = NULL; + return OK; } -static int -mbx_delimit_end (FILE *mbf) +multiline (buf, n, f) + char *buf; + register int n; + FILE *f; +{ + if (getline (buf, n, f) != OK) return NOTOK; + if (*buf == '.') + { + if (*(buf+1) == NULL) + return DONE; + else + strcpy (buf, buf+1); + } + return OK; +} + +char * +get_errmsg () +{ + return strerror (errno); +} + +putline (buf, err, f) + char *buf; + char *err; + FILE *f; { - if (putc ('\037', mbf) == EOF) - return (NOTOK); - return (OK); + fprintf (f, "%s\r\n", buf); + fflush (f); + if (ferror (f)) + { + strcpy (err, "lost connection"); + return NOTOK; + } + return OK; +} + +mbx_write (line, mbf) + char *line; + FILE *mbf; +{ + fputs (line, mbf); + fputc (0x0a, mbf); +} + +mbx_delimit_begin (mbf) + FILE *mbf; +{ + fputs ("\f\n0, unseen,,\n", mbf); +} + +mbx_delimit_end (mbf) + FILE *mbf; +{ + putc ('\037', mbf); } #endif /* MAIL_USE_POP */ #ifndef HAVE_STRERROR -static char * -strerror (int errnum) +char * +strerror (errnum) + int errnum; { extern char *sys_errlist[]; extern int sys_nerr;