Back to index

lightning-sunbird  0.9+nobinonly
movemail.c
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Originally Created by Spencer Murray <spence@netscape.com>, 15-Sep-95.
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include <stdio.h>
00040 #include <sys/types.h>
00041 #include <sys/stat.h>
00042 #include <fcntl.h>
00043 #include <unistd.h>
00044 #include <errno.h>
00045 #include <sys/wait.h>
00046 
00047 typedef int XP_Bool;
00048 
00049 #define TRUE 1
00050 #define FALSE 0
00051 
00052 #define LINUX_GLIBC_2
00053 
00054 #include <sys/errno.h>
00055 #if !defined(__FreeBSD__) && !defined(MACLINUX) && !defined(LINUX_GLIBC_2)
00056 extern char *sys_errlist[];
00057 extern int sys_nerr;
00058 #endif
00059 
00060 int XFE_CANT_MOVE_MAIL = 0;
00061 int XFE_CANT_GET_NEW_MAIL_LOCK_FILE_EXISTS = 0;
00062 int XFE_CANT_GET_NEW_MAIL_UNABLE_TO_CREATE_LOCK_FILE = 0;
00063 int XFE_CANT_GET_NEW_MAIL_SYSTEM_ERROR = 0;
00064 int XFE_CANT_MOVE_MAIL_UNABLE_TO_OPEN = 0;
00065 int XFE_CANT_MOVE_MAIL_UNABLE_TO_READ = 0;
00066 int XFE_CANT_MOVE_MAIL_UNABLE_TO_WRITE = 0;
00067 int XFE_THERE_WERE_PROBLEMS_MOVING_MAIL = 0;
00068 int XFE_THERE_WERE_PROBLEMS_MOVING_MAIL_EXIT_STATUS = 0;
00069 int XFE_THERE_WERE_PROBLEMS_CLEANING_UP = 0;
00070 int XFE_MOVEMAIL_FAILURE_SUFFIX = 0;
00071 int XFE_UNKNOWN_ERROR_CODE = 0;
00072 int XFE_MOVEMAIL_NO_MESSAGES = 0;
00073 int XFE_MOVEMAIL_CANT_DELETE_LOCK = 0;
00074 
00075 #define TMP_SUFFIX ".nslock"
00076 #define LOCK_SUFFIX ".lock"
00077 
00078 #define NAME_LEN 1024
00079 
00080 #ifndef BUFSIZ
00081 #define BUFSIZ 1024
00082 #endif /* BUFSIZ */
00083 
00084 char *XP_GetString(int i) {
00085   return NULL;
00086 }
00087   
00088 static void
00089 fe_movemail_perror(const char *message)
00090 {
00091   int e = errno;
00092   char *es = 0;
00093   char *buf1 = 0;
00094   char buf2[512];
00095   char *suffix;
00096   int L;
00097 
00098   if ((unsigned)e < (unsigned)sys_nerr)
00099     {
00100       es = sys_errlist [e];
00101     }
00102   else
00103     {
00104       snprintf (buf2, sizeof (buf2), XP_GetString( XFE_UNKNOWN_ERROR_CODE ),
00105               errno);
00106        printf("XFE_UNKNOWN_ERROR_CODE\n");
00107       es = buf2;
00108     }
00109 
00110   suffix = XP_GetString(XFE_MOVEMAIL_FAILURE_SUFFIX);
00111   printf("XFE_MOVEMAIL_FAILURE_SUFFIX\n");
00112   if(!suffix) suffix = "";
00113   if(!message) message = "";
00114   L = strlen(message) + strlen(es) + strlen(suffix) + 40;
00115   buf1 = (char *) malloc(L);
00116   if(!buf1) return;
00117   snprintf (buf1, L-1, "%s\n%s\n\n%s", message, es, suffix);
00118 #if 0
00119   FE_Alert (buf1);
00120 #endif
00121   free(buf1);
00122 }
00123 
00124 
00125 int
00126 fe_MoveMail (char *from, char *to)
00127 {
00128   XP_Bool succeeded = FALSE;
00129   char tmp_file[NAME_LEN];
00130   char lock_file[NAME_LEN];
00131   char spool_dir[NAME_LEN];
00132   char *bp, buf[BUFSIZ];
00133   char msgbuf[1024];
00134   int from_fd = -1;
00135   int to_fd = -1;
00136   int tmp_fd = -1;
00137   int nread, nwritten, nbytes, ntodo;
00138   struct stat st;
00139 
00140   *lock_file = 0;
00141 
00142   if (!from || !to)
00143     return FALSE;
00144 
00145   if (strlen(from) > NAME_LEN - 1) return FALSE;
00146 
00147   /* Make spool_dir be "/var/spool/mail" from "/var/spool/mail/$USER". */
00148   strcpy(spool_dir, from);
00149   while ((bp = strrchr(spool_dir, '/')) && bp[1] == '\0')
00150     *bp = '\0';
00151   if (!bp) return FALSE;
00152   *bp = 0;
00153 
00154   printf("%s\n", spool_dir);
00155 
00156   /* If we can't write into the directory itself, we can't create files,
00157      so we lose. */
00158   if (access(spool_dir, R_OK|W_OK) < 0)
00159     {
00160       snprintf(msgbuf, sizeof (msgbuf),
00161                 XP_GetString(XFE_CANT_MOVE_MAIL_UNABLE_TO_WRITE),
00162                 from);
00163        printf("XFE_CANT_MOVE_MAIL_UNABLE_TO_WRITE\n");
00164       fe_movemail_perror(msgbuf);
00165       goto FAIL;
00166     }
00167 
00168   /* If the mail-spool file doesn't exist, or is 0-length, bug out.
00169    */
00170   if (stat(from, &st) < 0 ||
00171       st.st_size == 0)
00172     {
00173 #if 0
00174       NET_Progress (XP_GetString(XFE_MOVEMAIL_NO_MESSAGES));
00175 #endif
00176       goto FAIL;
00177     }
00178   
00179   snprintf(tmp_file, sizeof (tmp_file), "%s%s", from, TMP_SUFFIX);
00180 
00181   if (access(tmp_file, 0) == 0) {
00182     /* The tmp file exists; try to get rid of it */
00183 
00184     if (unlink(tmp_file) < 0) {
00185       snprintf(msgbuf, sizeof (msgbuf),
00186                   XP_GetString( XFE_CANT_GET_NEW_MAIL_LOCK_FILE_EXISTS ),
00187                   tmp_file);
00188       fe_movemail_perror(msgbuf);
00189       goto FAIL;
00190     }
00191   }
00192 
00193   snprintf(lock_file, sizeof (lock_file), "%s%s", from, LOCK_SUFFIX);
00194 
00195   while (1) {
00196     int ret;
00197 
00198     /* First create a real file, $USER.nslock
00199      */
00200     tmp_fd = open(tmp_file, O_WRONLY|O_CREAT|O_EXCL, 0666);
00201 
00202     if (tmp_fd < 0) {
00203       snprintf(msgbuf, sizeof (msgbuf),
00204               XP_GetString( XFE_CANT_GET_NEW_MAIL_UNABLE_TO_CREATE_LOCK_FILE ),
00205               tmp_file);
00206       fe_movemail_perror(msgbuf);
00207       goto FAIL;
00208     }
00209     close(tmp_fd);
00210     tmp_fd = -1;
00211   
00212     /* Then make a hard link from $USER.lock to $USER.nslock -- this is the
00213        trick to make NFS behave synchronously.
00214      */
00215     ret = link(tmp_file, lock_file);
00216 
00217     /* Now we've (attempted to) make the link.  `ret' says whether it was
00218        successful.  It would have failed if the lock was already being held.
00219 
00220        Regardless of whether it succeeded, we can now delete $USER.nslock
00221        (the thing to which the hard-link points.)
00222      */
00223     if (unlink(tmp_file) < 0) {
00224       snprintf(msgbuf, sizeof (msgbuf),
00225                 /* This error message isn't quite right; what it really
00226                    means is "can't delete $MAIL.nslock", but I guess that
00227                    could only happen if some other user was the owner of
00228                    it?  Or if it was already gone?  Weird... */
00229        XP_GetString(XFE_MOVEMAIL_CANT_DELETE_LOCK), tmp_file);
00230        printf("XFE_MOVEMAIL_CANT_DELETE_LOCK\n");
00231       fe_movemail_perror(msgbuf);
00232       goto FAIL;
00233     }
00234 
00235     /* If we didn't obtain the lock (== make the hard-link), above, then
00236        retry getting it until the file is 60 seconds old...   Then get
00237        Guido to go over and bust its kneecaps.
00238      */
00239     if (ret < 0) {
00240       sleep (1);
00241       if (stat(lock_file, &st) >= 0) {
00242        int current = time(NULL);
00243        if (st.st_ctime < current - 60)
00244          unlink (lock_file);
00245       }
00246     } else {
00247       /* Got the lock - done waiting. */
00248       break;
00249     }
00250   }
00251 
00252   /* All of this junk used to happen in a forked process, but that's not
00253      necessary any more (actually, hasn't been for a long time) since we
00254      no longer play any setuid/setgid games -- there is no gain to doing
00255      this in another fork and waiting for it to complete.
00256    */
00257 
00258   /* Open the mail spool file for input...
00259    */
00260   from_fd = open(from, O_RDWR, 0666);
00261   if (from_fd < 0)
00262     {
00263       int err;
00264       if (access(from, W_OK) < 0)  /* look again, for right error message */
00265        err = XFE_CANT_MOVE_MAIL_UNABLE_TO_WRITE;
00266       else if (access(from, 0) == 0)
00267        err = XFE_CANT_MOVE_MAIL_UNABLE_TO_READ;
00268       else
00269        err = XFE_CANT_MOVE_MAIL_UNABLE_TO_OPEN;
00270       snprintf(msgbuf, sizeof (msgbuf), XP_GetString(err), from);
00271       fe_movemail_perror(msgbuf);
00272       goto FAIL;
00273     }
00274 
00275   /* Open the destination file for output...
00276    */
00277   to_fd = open(to, O_WRONLY|O_CREAT|O_EXCL, 0666);
00278   if (to_fd < 0) {
00279     snprintf(msgbuf, sizeof (msgbuf),
00280               XP_GetString( XFE_CANT_MOVE_MAIL_UNABLE_TO_OPEN ),
00281               to);
00282     fe_movemail_perror(msgbuf);
00283     goto FAIL;
00284   }
00285 
00286   /* copy the file */
00287 
00288   nbytes = BUFSIZ;
00289 
00290   while (1) {
00291     nread = read(from_fd, buf, nbytes);
00292 
00293     if (nread < 0) {
00294       /* we're busted */
00295       snprintf(msgbuf, sizeof (msgbuf),
00296                 XP_GetString( XFE_CANT_MOVE_MAIL_UNABLE_TO_READ ), from);
00297       fe_movemail_perror(msgbuf);
00298       goto FAIL;
00299     }
00300 
00301     if (!nread) {
00302       /* we're done */
00303       break;
00304     }
00305 
00306     for (ntodo = nread, bp = buf;
00307         ntodo > 0;
00308         ntodo -= nwritten, bp += nwritten) {
00309       nwritten = write(to_fd, bp, ntodo);
00310 
00311       if (nwritten < 0) {
00312        snprintf(msgbuf, sizeof (msgbuf),
00313                   XP_GetString( XFE_CANT_MOVE_MAIL_UNABLE_TO_WRITE ), to); 
00314        fe_movemail_perror(msgbuf);
00315        goto FAIL;
00316       }
00317     }
00318   }
00319 
00320   /* if we made it this far, we're done copying the file contents.
00321      First, close and sync the output file.
00322    */
00323 
00324   if (fsync(to_fd) < 0 ||
00325       close(to_fd) < 0)
00326     {
00327       snprintf(msgbuf, sizeof (msgbuf),
00328                 XP_GetString( XFE_CANT_MOVE_MAIL_UNABLE_TO_WRITE ), to); 
00329       fe_movemail_perror(msgbuf);
00330       goto FAIL;
00331     }
00332   to_fd = -1;
00333 
00334   /* Now the output file is closed and sync'ed, so we can truncate the
00335      spool file.
00336    */
00337   if (ftruncate(from_fd, (off_t)0) < 0)
00338     {
00339       snprintf(msgbuf, sizeof (msgbuf),
00340                 XP_GetString( XFE_THERE_WERE_PROBLEMS_CLEANING_UP ),
00341                 from);
00342       fe_movemail_perror(msgbuf);
00343       goto FAIL;
00344     }
00345 
00346   succeeded = TRUE;
00347 
00348  FAIL:
00349 
00350   if (to_fd >= 0) close(to_fd);
00351   if (from_fd >= 0) close(from_fd);
00352   if (tmp_fd >= 0) close(tmp_fd);
00353 
00354   /* Unlink the lock file.
00355      If this fails, but we were otherwise successful, then whine about it.
00356      Otherwise, we've already presented an error dialog about something else.
00357    */
00358   if (*lock_file && unlink(lock_file) < 0 && succeeded)
00359     {
00360       snprintf(msgbuf, sizeof (msgbuf),
00361                 XP_GetString( XFE_THERE_WERE_PROBLEMS_CLEANING_UP ),
00362                 lock_file);
00363       fe_movemail_perror(msgbuf);
00364       succeeded = FALSE;
00365     }
00366 
00367   return succeeded;
00368 }
00369 
00370 main()
00371 {
00372   fe_MoveMail ("/var/spool/mail/localguy","/home/localguy/mozilla.mail-recovery");
00373 }