home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / xfe / movemail.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  9.6 KB  |  348 lines

  1. /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18. /* 
  19.    movemail.c --- move mail between folders with file locking
  20.    Created: Spencer Murray <spence@netscape.com>, 15-Sep-95.
  21.  
  22.    The GNU movemail source used to ship with Netscape binaries.
  23.    To avoid GPL license issues, the movemail source will be
  24.    shipped separately from the Mozilla source.  -mcafee
  25.  
  26.  */
  27.  
  28.  
  29. /*
  30. #include <stdio.h>
  31. */
  32. #include <sys/types.h>
  33. #include <sys/stat.h>
  34. #include <fcntl.h>
  35. #include <unistd.h>
  36. #include <errno.h>
  37. #include <sys/wait.h>
  38.  
  39. #include "mozilla.h"
  40. #include "xfe.h"
  41.  
  42. #include <sys/errno.h>
  43. #if !defined(__FreeBSD__) && !defined(LINUX_GLIBC_2)
  44. extern char *sys_errlist[];
  45. extern int sys_nerr;
  46. #endif
  47.  
  48. /* for XP_GetString() */
  49. #include <xpgetstr.h>
  50. extern int XFE_CANT_MOVE_MAIL;
  51. extern int XFE_CANT_GET_NEW_MAIL_LOCK_FILE_EXISTS;
  52. extern int XFE_CANT_GET_NEW_MAIL_UNABLE_TO_CREATE_LOCK_FILE;
  53. extern int XFE_CANT_GET_NEW_MAIL_SYSTEM_ERROR;
  54. extern int XFE_CANT_MOVE_MAIL_UNABLE_TO_OPEN;
  55. extern int XFE_CANT_MOVE_MAIL_UNABLE_TO_READ;
  56. extern int XFE_CANT_MOVE_MAIL_UNABLE_TO_WRITE;
  57. extern int XFE_THERE_WERE_PROBLEMS_MOVING_MAIL;
  58. extern int XFE_THERE_WERE_PROBLEMS_MOVING_MAIL_EXIT_STATUS;
  59. extern int XFE_THERE_WERE_PROBLEMS_CLEANING_UP;
  60. extern int XFE_MOVEMAIL_FAILURE_SUFFIX;
  61. extern int XFE_UNKNOWN_ERROR_CODE;
  62. extern int XFE_MOVEMAIL_NO_MESSAGES;
  63. extern int XFE_MOVEMAIL_CANT_DELETE_LOCK;
  64.  
  65. #define TMP_SUFFIX ".nslock"
  66. #define LOCK_SUFFIX ".lock"
  67.  
  68. #define NAME_LEN 1024
  69.  
  70. #ifndef BUFSIZ
  71. #define BUFSIZ 1024
  72. #endif /* BUFSIZ */
  73.  
  74. static void
  75. fe_movemail_perror(MWContext *context, const char *message)
  76. {
  77.   int e = errno;
  78.   char *es = 0;
  79.   char *buf1 = 0;
  80.   char buf2[512];
  81.   char *suffix;
  82.   int L;
  83.  
  84.   XP_ASSERT(context);
  85.   if (!context) return;
  86.  
  87.   if ((unsigned)e < (unsigned)sys_nerr)
  88.     {
  89.       es = sys_errlist [e];
  90.     }
  91.   else
  92.     {
  93.       PR_snprintf (buf2, sizeof (buf2), XP_GetString( XFE_UNKNOWN_ERROR_CODE ),
  94.         errno);
  95.       es = buf2;
  96.     }
  97.  
  98.   suffix = XP_GetString(XFE_MOVEMAIL_FAILURE_SUFFIX);
  99.   if(!suffix) suffix = "";
  100.   if(!message) message = "";
  101.   L = XP_STRLEN(message) + XP_STRLEN(es) + XP_STRLEN(suffix) + 40;
  102.   buf1 = (char *) XP_ALLOC(L);
  103.   if(!buf1) return;
  104.   PR_snprintf (buf1, L-1, "%s\n%s\n\n%s", message, es, suffix);
  105.   FE_Alert (context, buf1);
  106.   XP_FREE(buf1);
  107. }
  108.  
  109.  
  110. int
  111. fe_MoveMail (MWContext *context, char *from, char *to)
  112. {
  113.   XP_Bool succeeded = FALSE;
  114.   char tmp_file[NAME_LEN];
  115.   char lock_file[NAME_LEN];
  116.   char spool_dir[NAME_LEN];
  117.   char *bp, buf[BUFSIZ];
  118.   char msgbuf[1024];
  119.   int from_fd = -1;
  120.   int to_fd = -1;
  121.   int tmp_fd = -1;
  122.   int nread, nwritten, nbytes, ntodo;
  123.   struct stat st;
  124.  
  125.   *lock_file = 0;
  126.  
  127.   if (!from || !to)
  128.     return FALSE;
  129.  
  130.   if (strlen(from) > NAME_LEN - 1) return FALSE;
  131.  
  132.   /* Make spool_dir be "/var/spool/mail" from "/var/spool/mail/$USER". */
  133.   strcpy(spool_dir, from);
  134.   while ((bp = strrchr(spool_dir, '/')) && bp[1] == '\0')
  135.     *bp = '\0';
  136.   if (!bp) return FALSE;
  137.   *bp = 0;
  138.  
  139.   /* If we can't write into the directory itself, we can't create files,
  140.      so we lose. */
  141.   if (access(spool_dir, R_OK|W_OK) < 0)
  142.     {
  143.       PR_snprintf(msgbuf, sizeof (msgbuf),
  144.           XP_GetString(XFE_CANT_MOVE_MAIL_UNABLE_TO_WRITE),
  145.           from);
  146.       fe_movemail_perror(context, msgbuf);
  147.       goto FAIL;
  148.     }
  149.  
  150.   /* If the mail-spool file doesn't exist, or is 0-length, bug out.
  151.    */
  152.   if (stat(from, &st) < 0 ||
  153.       st.st_size == 0)
  154.     {
  155.       FE_Alert (context, XP_GetString(XFE_MOVEMAIL_NO_MESSAGES));
  156.       goto FAIL;
  157.     }
  158.   
  159.   PR_snprintf(tmp_file, sizeof (tmp_file), "%s%s", from, TMP_SUFFIX);
  160.  
  161.   if (access(tmp_file, 0) == 0) {
  162.     /* The tmp file exists; try to get rid of it */
  163.  
  164.     if (unlink(tmp_file) < 0) {
  165.       PR_snprintf(msgbuf, sizeof (msgbuf),
  166.                   XP_GetString( XFE_CANT_GET_NEW_MAIL_LOCK_FILE_EXISTS ),
  167.                   tmp_file);
  168.       fe_movemail_perror(context, msgbuf);
  169.       goto FAIL;
  170.     }
  171.   }
  172.  
  173.   PR_snprintf(lock_file, sizeof (lock_file), "%s%s", from, LOCK_SUFFIX);
  174.  
  175.   while (1) {
  176.     int ret;
  177.  
  178.     /* First create a real file, $USER.nslock
  179.      */
  180.     tmp_fd = open(tmp_file, O_WRONLY|O_CREAT|O_EXCL, 0666);
  181.  
  182.     if (tmp_fd < 0) {
  183.       PR_snprintf(msgbuf, sizeof (msgbuf),
  184.               XP_GetString( XFE_CANT_GET_NEW_MAIL_UNABLE_TO_CREATE_LOCK_FILE ),
  185.               tmp_file);
  186.       fe_movemail_perror(context, msgbuf);
  187.       goto FAIL;
  188.     }
  189.     close(tmp_fd);
  190.     tmp_fd = -1;
  191.   
  192.     /* Then make a hard link from $USER.lock to $USER.nslock -- this is the
  193.        trick to make NFS behave synchronously.
  194.      */
  195.     ret = link(tmp_file, lock_file);
  196.  
  197.     /* Now we've (attempted to) make the link.  `ret' says whether it was
  198.        successful.  It would have failed if the lock was already being held.
  199.  
  200.        Regardless of whether it succeeded, we can now delete $USER.nslock
  201.        (the thing to which the hard-link points.)
  202.      */
  203.     if (unlink(tmp_file) < 0) {
  204.       PR_snprintf(msgbuf, sizeof (msgbuf),
  205.           /* This error message isn't quite right; what it really
  206.              means is "can't delete $MAIL.nslock", but I guess that
  207.              could only happen if some other user was the owner of
  208.              it?  Or if it was already gone?  Weird... */
  209.     XP_GetString(XFE_MOVEMAIL_CANT_DELETE_LOCK), tmp_file);
  210.       fe_movemail_perror(context, msgbuf);
  211.       goto FAIL;
  212.     }
  213.  
  214.     /* If we didn't obtain the lock (== make the hard-link), above, then
  215.        retry getting it until the file is 60 seconds old...   Then get
  216.        Guido to go over and bust its kneecaps.
  217.      */
  218.     if (ret < 0) {
  219.       sleep (1);
  220.       if (stat(lock_file, &st) >= 0) {
  221.     int current = time(NULL);
  222.     if (st.st_ctime < current - 60)
  223.       unlink (lock_file);
  224.       }
  225.     } else {
  226.       /* Got the lock - done waiting. */
  227.       break;
  228.     }
  229.   }
  230.  
  231.   /* All of this junk used to happen in a forked process, but that's not
  232.      necessary any more (actually, hasn't been for a long time) since we
  233.      no longer play any setuid/setgid games -- there is no gain to doing
  234.      this in another fork and waiting for it to complete.
  235.    */
  236.  
  237.   /* Open the mail spool file for input...
  238.    */
  239.   from_fd = open(from, O_RDWR, 0666);
  240.   if (from_fd < 0)
  241.     {
  242.       int err;
  243.       if (access(from, W_OK) < 0)  /* look again, for right error message */
  244.     err = XFE_CANT_MOVE_MAIL_UNABLE_TO_WRITE;
  245.       else if (access(from, 0) == 0)
  246.     err = XFE_CANT_MOVE_MAIL_UNABLE_TO_READ;
  247.       else
  248.     err = XFE_CANT_MOVE_MAIL_UNABLE_TO_OPEN;
  249.       PR_snprintf(msgbuf, sizeof (msgbuf), XP_GetString(err), from);
  250.       fe_movemail_perror(context, msgbuf);
  251.       goto FAIL;
  252.     }
  253.  
  254.   /* Open the destination file for output...
  255.    */
  256.   to_fd = open(to, O_WRONLY|O_CREAT|O_EXCL, 0666);
  257.   if (to_fd < 0) {
  258.     PR_snprintf(msgbuf, sizeof (msgbuf),
  259.         XP_GetString( XFE_CANT_MOVE_MAIL_UNABLE_TO_OPEN ),
  260.         to);
  261.     fe_movemail_perror(context, msgbuf);
  262.     goto FAIL;
  263.   }
  264.  
  265.   /* copy the file */
  266.  
  267.   nbytes = BUFSIZ;
  268.  
  269.   while (1) {
  270.     nread = read(from_fd, buf, nbytes);
  271.  
  272.     if (nread < 0) {
  273.       /* we're busted */
  274.       PR_snprintf(msgbuf, sizeof (msgbuf),
  275.           XP_GetString( XFE_CANT_MOVE_MAIL_UNABLE_TO_READ ), from);
  276.       fe_movemail_perror(context, msgbuf);
  277.       goto FAIL;
  278.     }
  279.  
  280.     if (!nread) {
  281.       /* we're done */
  282.       break;
  283.     }
  284.  
  285.     for (ntodo = nread, bp = buf;
  286.      ntodo > 0;
  287.      ntodo -= nwritten, bp += nwritten) {
  288.       nwritten = write(to_fd, bp, ntodo);
  289.  
  290.       if (nwritten < 0) {
  291.     PR_snprintf(msgbuf, sizeof (msgbuf),
  292.             XP_GetString( XFE_CANT_MOVE_MAIL_UNABLE_TO_WRITE ), to); 
  293.     fe_movemail_perror(context, msgbuf);
  294.     goto FAIL;
  295.       }
  296.     }
  297.   }
  298.  
  299.   /* if we made it this far, we're done copying the file contents.
  300.      First, close and sync the output file.
  301.    */
  302.  
  303.   if (fsync(to_fd) < 0 ||
  304.       close(to_fd) < 0)
  305.     {
  306.       PR_snprintf(msgbuf, sizeof (msgbuf),
  307.           XP_GetString( XFE_CANT_MOVE_MAIL_UNABLE_TO_WRITE ), to); 
  308.       fe_movemail_perror(context, msgbuf);
  309.       goto FAIL;
  310.     }
  311.   to_fd = -1;
  312.  
  313.   /* Now the output file is closed and sync'ed, so we can truncate the
  314.      spool file.
  315.    */
  316.   if (ftruncate(from_fd, (off_t)0) < 0)
  317.     {
  318.       PR_snprintf(msgbuf, sizeof (msgbuf),
  319.           XP_GetString( XFE_THERE_WERE_PROBLEMS_CLEANING_UP ),
  320.           from);
  321.       fe_movemail_perror(context, msgbuf);
  322.       goto FAIL;
  323.     }
  324.  
  325.   succeeded = TRUE;
  326.  
  327.  FAIL:
  328.  
  329.   if (to_fd >= 0) close(to_fd);
  330.   if (from_fd >= 0) close(from_fd);
  331.   if (tmp_fd >= 0) close(tmp_fd);
  332.  
  333.   /* Unlink the lock file.
  334.      If this fails, but we were otherwise successful, then whine about it.
  335.      Otherwise, we've already presented an error dialog about something else.
  336.    */
  337.   if (*lock_file && unlink(lock_file) < 0 && succeeded)
  338.     {
  339.       PR_snprintf(msgbuf, sizeof (msgbuf),
  340.           XP_GetString( XFE_THERE_WERE_PROBLEMS_CLEANING_UP ),
  341.           lock_file);
  342.       fe_movemail_perror(context, msgbuf);
  343.       succeeded = FALSE;
  344.     }
  345.  
  346.   return succeeded;
  347. }
  348.