Include <config.h> instead of "config.h".
[bpt/emacs.git] / lib-src / movemail.c
index 9709202..0063e1d 100644 (file)
@@ -1,6 +1,6 @@
 /* movemail foo bar -- move file foo to file bar,
    locking file foo the way /bin/mail respects.
-   Copyright (C) 1986 Free Software Foundation, Inc.
+   Copyright (C) 1986, 1992 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -18,6 +18,18 @@ 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
+/* Important notice: defining MAIL_USE_FLOCK *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
+   *must agree* with the system's own conventions.
+   It is not a choice that is up to you.
+
+   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.  */
+
 /*
  * Modified January, 1986 by Michael R. Gretzinger (Project Athena)
  *
@@ -29,7 +41,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  * 
  * New module: popmail.c
  * Modified routines:
- *     main - added code within #ifdef MAIL_USE_POP; added setuid(getuid())
+ *     main - added code within #ifdef MAIL_USE_POP; added setuid (getuid ())
  *             after POP code. 
  * New routines in movemail.c:
  *     get_errmsg - return pointer to system error message
@@ -41,7 +53,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include <sys/file.h>
 #include <errno.h>
 #define NO_SHORTNAMES   /* Tell config not to load remap.h */
-#include "../src/config.h"
+#include <../src/config.h>
 
 #ifdef USG
 #include <fcntl.h>
@@ -68,8 +80,13 @@ extern int lk_open (), lk_close ();
 #undef write
 #undef close
 
+char *malloc ();
+char *strcpy ();
 char *concat ();
+char *xmalloc ();
+#ifndef errno
 extern int errno;
+#endif
 
 /* Nonzero means this is name of a lock file to delete on fatal error.  */
 char *delete_lockname;
@@ -80,7 +97,6 @@ main (argc, argv)
 {
   char *inname, *outname;
   int indesc, outdesc;
-  char buf[1024];
   int nread;
 
 #ifndef MAIL_USE_FLOCK
@@ -88,7 +104,7 @@ main (argc, argv)
   long now;
   int tem;
   char *lockname, *p;
-  char tempname[40];
+  char *tempname;
   int desc;
 #endif /* not MAIL_USE_FLOCK */
 
@@ -124,16 +140,19 @@ main (argc, argv)
   }
 
 #ifdef MAIL_USE_POP
-  if (!bcmp (inname, "po:", 3))
+  if (!strncmp (inname, "po:", 3))
     {
       int status; char *user;
 
-      user = (char *) rindex (inname, ':') + 1;
+      for (user = &inname[strlen (inname) - 1]; user >= inname; user--)
+       if (*user == ':')
+         break;
+
       status = popmail (user, outname);
       exit (status);
     }
 
-  setuid (getuid());
+  setuid (getuid ());
 #endif /* MAIL_USE_POP */
 
   /* Check access to input file.  */
@@ -144,15 +163,36 @@ main (argc, argv)
 #ifndef MAIL_USE_FLOCK
   /* 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.
+
+     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 /usr/spool/mail,
+     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_FLOCK in config.h or the s-*.h file
+     and recompile movemail.  If the s- file for your system
+     should define MAIL_USE_FLOCK but does not, send a bug report
+     to bug-gnu-emacs@prep.ai.mit.edu so we can fix it.  */
+
   lockname = concat (inname, ".lock", "");
-  strcpy (tempname, inname);
+  tempname = strcpy (xmalloc (strlen (inname)+1), inname);
   p = tempname + strlen (tempname);
   while (p != tempname && p[-1] != '/')
     p--;
   *p = 0;
   strcpy (p, "EXXXXXX");
   mktemp (tempname);
-  (void) unlink (tempname);
+  unlink (tempname);
 
   while (1)
     {
@@ -160,11 +200,11 @@ main (argc, argv)
       /* Give up if cannot do that.  */
       desc = open (tempname, O_WRONLY | O_CREAT, 0666);
       if (desc < 0)
-        pfatal_with_name (concat ("temporary file \"", tempname, "\""));
+        pfatal_with_name ("lock file--see source file etc/movemail.c");
       close (desc);
 
       tem = link (tempname, lockname);
-      (void) unlink (tempname);
+      unlink (tempname);
       if (tem >= 0)
        break;
       sleep (1);
@@ -174,7 +214,7 @@ main (argc, argv)
        {
          now = time (0);
          if (st.st_ctime < now - 60)
-           (void) unlink (lockname);
+           unlink (lockname);
        }
     }
 
@@ -193,7 +233,7 @@ main (argc, argv)
   if (indesc < 0)
     pfatal_with_name (inname);
 
-#if defined(BSD) || defined(XENIX)
+#if defined (BSD) || defined (XENIX)
   /* In case movemail is setuid to root, make sure the user can
      read the output file.  */
   /* This is desirable for all systems
@@ -211,39 +251,39 @@ main (argc, argv)
 #endif
 #endif /* MAIL_USE_FLOCK */
 
-  while (1)
-    {
-      nread = read (indesc, buf, sizeof buf);
-      if (nread != write (outdesc, buf, nread))
-       {
-         int saved_errno = errno;
-         (void) unlink (outname);
-         errno = saved_errno;
-         pfatal_with_name (outname);
-       }
-      if (nread < sizeof buf)
-       break;
-    }
+  {
+    char buf[1024];
+
+    while (1)
+      {
+       nread = read (indesc, buf, sizeof buf);
+       if (nread != write (outdesc, buf, nread))
+         {
+           int saved_errno = errno;
+           unlink (outname);
+           errno = saved_errno;
+           pfatal_with_name (outname);
+         }
+       if (nread < sizeof buf)
+         break;
+      }
+  }
 
 #ifdef BSD
-  fsync (outdesc);
+  if (fsync (outdesc) < 0)
+    pfatal_and_delete (outname);
 #endif
 
   /* Check to make sure no errors before we zap the inbox.  */
   if (close (outdesc) != 0)
-    {
-      int saved_errno = errno;
-      (void) unlink (outname);
-      errno = saved_errno;
-      pfatal_with_name (outname);
-  }
+    pfatal_and_delete (outname);
 
 #ifdef MAIL_USE_FLOCK
-#if defined(STRIDE) || defined(XENIX)
+#if defined (STRIDE) || defined (XENIX)
   /* Stride, xenix have file locking, but no ftruncate.  This mess will do. */
-  (void) close (open (inname, O_CREAT | O_TRUNC | O_RDWR, 0666));
+  close (open (inname, O_CREAT | O_TRUNC | O_RDWR, 0666));
 #else
-  (void) ftruncate (indesc, 0L);
+  ftruncate (indesc, 0L);
 #endif /* STRIDE or XENIX */
 #endif /* MAIL_USE_FLOCK */
 
@@ -255,9 +295,12 @@ main (argc, argv)
 
 #ifndef MAIL_USE_FLOCK
   /* Delete the input file; if we can't, at least get rid of its contents.  */
-  if (unlink (inname) < 0)
-    if (errno != ENOENT)
-      creat (inname, 0666);
+#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);
 #ifndef MAIL_USE_MMDF
   unlink (lockname);
 #endif /* not MAIL_USE_MMDF */
@@ -300,6 +343,22 @@ pfatal_with_name (name)
   fatal (s, name);
 }
 
+pfatal_and_delete (name)
+     char *name;
+{
+  extern int errno, sys_nerr;
+  extern char *sys_errlist[];
+  char *s;
+
+  if (errno < sys_nerr)
+    s = concat ("", sys_errlist[errno], " for %s");
+  else
+    s = "cannot open %s";
+
+  unlink (name);
+  fatal (s, name);
+}
+
 /* Return a newly-allocated string whose contents concatenate those of s1, s2, s3.  */
 
 char *
@@ -319,11 +378,11 @@ concat (s1, s2, s3)
 
 /* Like malloc but get fatal error if memory is exhausted.  */
 
-int
+char *
 xmalloc (size)
-     int size;
+     unsigned size;
 {
-  int result = malloc (size);
+  char *result = malloc (size);
   if (!result)
     fatal ("virtual memory exhausted", 0);
   return result;
@@ -337,6 +396,7 @@ xmalloc (size)
 #include <netinet/in.h>
 #include <netdb.h>
 #include <stdio.h>
+#include <pwd.h>
 
 #ifdef USG
 #include <fcntl.h>
@@ -372,6 +432,9 @@ popmail (user, outfile)
   register int i;
   int mbfi;
   FILE *mbf;
+  struct passwd *pw = (struct passwd *) getpwuid (getuid ());
+  if (pw == NULL)
+    fatal ("cannot determine user name");
 
   host = getenv ("MAILHOST");
   if (host == NULL)
@@ -381,29 +444,25 @@ popmail (user, outfile)
 
   if (pop_init (host) == NOTOK)
     {
-      error (Errmsg);
-      return 1;
+      fatal (Errmsg);
     }
 
   if (getline (response, sizeof response, sfi) != OK)
     {
-      error (response);
-      return 1;
+      fatal (response);
     }
 
-  if (pop_command ("USER %s", user) == NOTOK 
-      || pop_command ("RPOP %s", user) == NOTOK)
+  if (pop_command ("USER %s", user) == NOTOK
+      || pop_command ("RPOP %s", pw->pw_name) == NOTOK)
     {
-      error (Errmsg);
       pop_command ("QUIT");
-      return 1;
+      fatal (Errmsg);
     }
 
   if (pop_stat (&nmsgs, &nbytes) == NOTOK)
     {
-      error (Errmsg);
       pop_command ("QUIT");
-      return 1;
+      fatal (Errmsg);
     }
 
   if (!nmsgs)
@@ -416,18 +475,14 @@ popmail (user, outfile)
   if (mbfi < 0)
     {
       pop_command ("QUIT");
-      error ("Error in open: %s, %s", get_errmsg (), outfile);
-      return 1;
+      pfatal_and_delete (outfile);
     }
   fchown (mbfi, getuid (), -1);
 
   if ((mbf = fdopen (mbfi, "w")) == NULL)
     {
       pop_command ("QUIT");
-      error ("Error in fdopen: %s", get_errmsg ());
-      close (mbfi);
-      unlink (outfile);
-      return 1;
+      pfatal_and_delete (outfile);
     }
 
   for (i = 1; i <= nmsgs; i++)
@@ -435,29 +490,37 @@ popmail (user, outfile)
       mbx_delimit_begin (mbf);
       if (pop_retr (i, mbx_write, mbf) != OK)
        {
-         error (Errmsg);
          pop_command ("QUIT");
          close (mbfi);
-         return 1;
+         unlink (outfile);
+         fatal (Errmsg);
        }
       mbx_delimit_end (mbf);
       fflush (mbf);
     }
 
+  if (fsync (mbfi) < 0)
+    {
+      pop_command ("QUIT");
+      pfatal_and_delete (outfile);
+    }
+
+  if (close (mbfi) == -1)
+    {
+      pop_command ("QUIT");
+      pfatal_and_delete (outfile);
+    }
+
   for (i = 1; i <= nmsgs; i++)
     {
       if (pop_command ("DELE %d", i) == NOTOK)
        {
-         error (Errmsg);
-         pop_command ("QUIT");
-         close (mbfi);
-         return 1;
+         /* Better to ignore this failure.  */
        }
     }
 
   pop_command ("QUIT");
-  close (mbfi);
-  return 0;
+  return (0);
 }
 
 pop_init (host)
@@ -529,7 +592,8 @@ pop_command (fmt, a, b, c, d)
       return NOTOK;
     }
 
-  if (debug) fprintf (stderr, "<--- %s\n", buf);
+  if (debug)
+    fprintf (stderr, "<--- %s\n", buf);
   if (*buf != '+')
     {
       strcpy (Errmsg, buf);
@@ -547,8 +611,10 @@ pop_stat (nmsgs, nbytes)
 {
   char buf[128];
 
-  if (debug) fprintf (stderr, "---> STAT\n");
-  if (putline ("STAT", Errmsg, sfo) == NOTOK) return NOTOK;
+  if (debug)
+    fprintf (stderr, "---> STAT\n");
+  if (putline ("STAT", Errmsg, sfo) == NOTOK)
+    return NOTOK;
 
   if (getline (buf, sizeof buf, sfi) != OK)
     {
@@ -635,17 +701,14 @@ multiline (buf, n, f)
      register int n;
      FILE *f;
 {
-  if (getline (buf, n, f) != OK) return NOTOK;
+  if (getline (buf, n, f) != OK)
+    return NOTOK;
   if (*buf == '.')
     {
       if (*(buf+1) == NULL)
-       {
-         return DONE;
-       }
+       return DONE;
       else
-       {
-         strcpy (buf, buf+1);
-       }
+       strcpy (buf, buf+1);
     }
   return OK;
 }