mbox.c
上传用户:ycwykj01
上传日期:2007-01-04
资源大小:1819k
文件大小:11k
源码类别:

网络编程

开发平台:

Unix_Linux

  1. /*
  2.  * Program: MBOX mail routines
  3.  *
  4.  * Author: Mark Crispin
  5.  * Networks and Distributed Computing
  6.  * Computing & Communications
  7.  * University of Washington
  8.  * Administration Building, AG-44
  9.  * Seattle, WA  98195
  10.  * Internet: MRC@CAC.Washington.EDU
  11.  *
  12.  * Date: 10 March 1992
  13.  * Last Edited: 21 September 1999
  14.  *
  15.  * Copyright 1999 by the University of Washington
  16.  *
  17.  *  Permission to use, copy, modify, and distribute this software and its
  18.  * documentation for any purpose and without fee is hereby granted, provided
  19.  * that the above copyright notice appears in all copies and that both the
  20.  * above copyright notice and this permission notice appear in supporting
  21.  * documentation, and that the name of the University of Washington not be
  22.  * used in advertising or publicity pertaining to distribution of the software
  23.  * without specific, written prior permission.  This software is made
  24.  * available "as is", and
  25.  * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
  26.  * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
  27.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
  28.  * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
  29.  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  30.  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
  31.  * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
  32.  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  33.  *
  34.  */
  35. #include <stdio.h>
  36. #include <ctype.h>
  37. #include <errno.h>
  38. extern int errno; /* just in case */
  39. #include "mail.h"
  40. #include "osdep.h"
  41. #include <sys/stat.h>
  42. #include <sys/time.h>
  43. #include "mbox.h"
  44. #include "unix.h"
  45. #include "misc.h"
  46. #include "dummy.h"
  47. /* MBOX mail routines */
  48. /* Driver dispatch used by MAIL */
  49. DRIVER mboxdriver = {
  50.   "mbox", /* driver name */
  51.   DR_LOCAL|DR_MAIL, /* driver flags */
  52.   (DRIVER *) NIL, /* next driver */
  53.   mbox_valid, /* mailbox is valid for us */
  54.   unix_parameters, /* manipulate parameters */
  55.   unix_scan, /* scan mailboxes */
  56.   unix_list, /* find mailboxes */
  57.   unix_lsub, /* find subscribed mailboxes */
  58.   NIL, /* subscribe to mailbox */
  59.   NIL, /* unsubscribe from mailbox */
  60.   mbox_create, /* create mailbox */
  61.   mbox_delete, /* delete mailbox */
  62.   mbox_rename, /* rename mailbox */
  63.   mbox_status, /* status of mailbox */
  64.   mbox_open, /* open mailbox */
  65.   unix_close, /* close mailbox */
  66.   NIL, /* fetch message "fast" attributes */
  67.   NIL, /* fetch message flags */
  68.   NIL, /* fetch overview */
  69.   NIL, /* fetch message structure */
  70.   unix_header, /* fetch message header */
  71.   unix_text, /* fetch message body */
  72.   NIL, /* fetch partial message text */
  73.   NIL, /* unique identifier */
  74.   NIL, /* message number */
  75.   NIL, /* modify flags */
  76.   unix_flagmsg, /* per-message modify flags */
  77.   NIL, /* search for message based on criteria */
  78.   NIL, /* sort messages */
  79.   NIL, /* thread messages */
  80.   mbox_ping, /* ping mailbox to see if still alive */
  81.   mbox_check, /* check for new messages */
  82.   mbox_expunge, /* expunge deleted messages */
  83.   unix_copy, /* copy messages to another mailbox */
  84.   mbox_append, /* append string message to mailbox */
  85.   NIL /* garbage collect stream */
  86. };
  87. /* prototype stream */
  88. MAILSTREAM mboxproto = {&mboxdriver};
  89. /* MBOX mail validate mailbox
  90.  * Accepts: mailbox name
  91.  * Returns: our driver if name is valid, NIL otherwise
  92.  */
  93. DRIVER *mbox_valid (char *name)
  94. {
  95. /* only INBOX, mbox must exist */
  96.   if (((name[1] == 'N') || (name[1] == 'n')) &&
  97.       ((name[2] == 'B') || (name[2] == 'b')) &&
  98.       ((name[3] == 'O') || (name[3] == 'o')) &&
  99.       ((name[4] == 'X') || (name[4] == 'x')) && !name[5] &&
  100.       (unix_valid ("mbox") || !errno) &&
  101.       (unix_valid (sysinbox()) || !errno || (errno == ENOENT)))
  102.     return &mboxdriver;
  103.   return NIL; /* can't win (yet, anyway) */
  104. }
  105. /* MBOX mail create mailbox
  106.  * Accepts: MAIL stream
  107.  *     mailbox name to create
  108.  * Returns: T on success, NIL on failure
  109.  */
  110. long mbox_create (MAILSTREAM *stream,char *mailbox)
  111. {
  112.   return unix_create (NIL,"mbox");
  113. }
  114. /* MBOX mail delete mailbox
  115.  * Accepts: MAIL stream
  116.  *     mailbox name to delete
  117.  * Returns: T on success, NIL on failure
  118.  */
  119. long mbox_delete (MAILSTREAM *stream,char *mailbox)
  120. {
  121.   return mbox_rename (stream,mailbox,NIL);
  122. }
  123. /* MBOX mail rename mailbox
  124.  * Accepts: MAIL stream
  125.  *     old mailbox name
  126.  *     new mailbox name (or NIL for delete)
  127.  * Returns: T on success, NIL on failure
  128.  */
  129. long mbox_rename (MAILSTREAM *stream,char *old,char *newname)
  130. {
  131.   char tmp[MAILTMPLEN];
  132.   long ret = unix_rename (stream,"~/mbox",newname);
  133. /* recreate file if renamed INBOX */
  134.   if (ret) unix_create (NIL,"mbox");
  135.   else mm_log (tmp,ERROR); /* log error */
  136.   return ret; /* return success */
  137. }
  138. /* MBOX Mail status
  139.  * Accepts: mail stream
  140.  *     mailbox name
  141.  *     status flags
  142.  * Returns: T on success, NIL on failure
  143.  */
  144. long mbox_status (MAILSTREAM *stream,char *mbx,long flags)
  145. {
  146.   MAILSTATUS status;
  147.   unsigned long i;
  148.   MAILSTREAM *tstream = NIL;
  149.   MAILSTREAM *systream = NIL;
  150. /* make temporary stream (unless this mbx) */
  151.   if (!stream && !(stream = tstream =
  152.    mail_open (NIL,mbx,OP_READONLY|OP_SILENT))) return NIL;
  153.   status.flags = flags; /* return status values */
  154.   status.messages = stream->nmsgs;
  155.   status.recent = stream->recent;
  156.   if (flags & SA_UNSEEN) /* must search to get unseen messages */
  157.     for (i = 1,status.unseen = 0; i <= stream->nmsgs; i++)
  158.       if (!mail_elt (stream,i)->seen) status.unseen++;
  159.   status.uidnext = stream->uid_last + 1;
  160.   status.uidvalidity = stream->uid_validity;
  161.   if (!status.recent && /* calculate post-snarf results */
  162.       (systream = mail_open (NIL,sysinbox (),OP_READONLY|OP_SILENT))) {
  163.     status.messages += systream->nmsgs;
  164.     status.recent += systream->recent;
  165.     if (flags & SA_UNSEEN) /* must search to get unseen messages */
  166.       for (i = 1; i <= systream->nmsgs; i++)
  167. if (!mail_elt (systream,i)->seen) status.unseen++;
  168. /* kludge but probably good enough */
  169.     status.uidnext += systream->nmsgs;
  170.   }
  171. /* pass status to main program */
  172.   mm_status (stream,mbx,&status);
  173.   if (tstream) mail_close (tstream);
  174.   if (systream) mail_close (systream);
  175.   return T; /* success */
  176. }
  177. /* MBOX mail open
  178.  * Accepts: stream to open
  179.  * Returns: stream on success, NIL on failure
  180.  */
  181. MAILSTREAM *mbox_open (MAILSTREAM *stream)
  182. {
  183.   unsigned long i = 1;
  184.   unsigned long recent = 0;
  185.   char tmp[MAILTMPLEN];
  186. /* return prototype for OP_PROTOTYPE call */
  187.   if (!stream) return &mboxproto;
  188. /* change mailbox file name */
  189.   sprintf (tmp,"%s/mbox",myhomedir ());
  190.   fs_give ((void **) &stream->mailbox);
  191.   stream->mailbox = cpystr (tmp);
  192. /* open mailbox, snarf new mail */
  193.   if (!(unix_open (stream) && mbox_ping (stream))) return NIL;
  194.   stream->inbox = T; /* mark that this is an INBOX */
  195. /* notify upper level of mailbox sizes */
  196.   mail_exists (stream,stream->nmsgs);
  197.   while (i <= stream->nmsgs) if (mail_elt (stream,i++)->recent) ++recent;
  198.   mail_recent (stream,recent); /* including recent messages */
  199.   return stream;
  200. }
  201. /* MBOX mail ping mailbox
  202.  * Accepts: MAIL stream
  203.  * Returns: T if stream alive, else NIL
  204.  * No-op for readonly files, since read/writer can expunge it from under us!
  205.  */
  206. static int snarfed = 0; /* number of snarfs */
  207. long mbox_ping (MAILSTREAM *stream)
  208. {
  209.   int sfd;
  210.   unsigned long size;
  211.   struct stat sbuf;
  212.   char *s;
  213.   DOTLOCK lock,lockx;
  214. /* time to try snarf and sysinbox non-empty? */
  215.   if (LOCAL && !stream->rdonly && !stream->lock &&
  216.       (time (0) > (LOCAL->lastsnarf + 30)) &&
  217.       !stat (sysinbox (),&sbuf) && sbuf.st_size) {
  218. /* yes, open and lock sysinbox */
  219.     if ((sfd = unix_lock (sysinbox (),O_RDWR,NIL,&lockx,LOCK_EX)) >= 0) {
  220. /* locked sysinbox in good format? */
  221.       if (fstat (sfd,&sbuf) || !(size = sbuf.st_size) ||
  222.   !unix_isvalid_fd (sfd)) {
  223. sprintf (LOCAL->buf,"Mail drop %s is not in standard Unix format",
  224.  sysinbox ());
  225. mm_log (LOCAL->buf,ERROR);
  226.       }
  227. /* sysinbox good, parse and excl-lock mbox */
  228.       else if (unix_parse (stream,&lock,LOCK_EX)) {
  229. lseek (sfd,0,L_SET); /* read entire sysinbox into memory */
  230. read (sfd,s = (char *) fs_get (size + 1),size);
  231. s[size] = ''; /* tie it off */
  232. /* append to end of mbox */
  233. lseek (LOCAL->fd,LOCAL->filesize,L_SET);
  234. /* copy to mbox */
  235. if ((write (LOCAL->fd,s,size) < 0) || fsync (LOCAL->fd)) {
  236.   sprintf (LOCAL->buf,"New mail move failed: %s",strerror (errno));
  237.   mm_log (LOCAL->buf,ERROR);
  238. /* revert mbox to previous size */
  239.   ftruncate (LOCAL->fd,LOCAL->filesize);
  240. }
  241. /* sysinbox better not have changed */
  242. else if (fstat (sfd,&sbuf) || (size != sbuf.st_size)) {
  243.   sprintf (LOCAL->buf,"Mail drop %s lock failure, old=%lu now=%lu",
  244.    sysinbox (),size,(unsigned long) sbuf.st_size);
  245.   mm_log (LOCAL->buf,ERROR);
  246. /* revert mbox to previous size */
  247.   ftruncate (LOCAL->fd,LOCAL->filesize);
  248.   /* Believe it or not, a Singaporean government system actually had
  249.    * symlinks from /var/mail/user to ~user/mbox.  To compound this
  250.    * error, they used an SVR4 system; BSD and OSF locks would have
  251.    * prevented it but not SVR4 locks.
  252.    */
  253.   if (!fstat (sfd,&sbuf) && (size == sbuf.st_size))
  254.     syslog (LOG_ALERT,"File %s and %s are the same file!",
  255.     sysinbox,stream->mailbox);
  256. }
  257. else { /* data copied OK */
  258.   ftruncate (sfd,0); /* truncate sysinbox to zero bytes */
  259.   if (!snarfed++) { /* have we snarfed before? */
  260. /* syslog if server, else mm_log() */
  261.     sprintf (LOCAL->buf,"Moved %lu bytes of new mail to %s from %s",
  262.      size,stream->mailbox,sysinbox ());
  263.     if (strcmp ((char *) mail_parameters (NIL,GET_SERVICENAME,NIL),
  264. "unknown"))
  265.       syslog (LOG_INFO,"%s host= %s",LOCAL->buf,tcp_clienthost ());
  266.     else mm_log (LOCAL->buf,WARN);
  267.   }
  268. }
  269. /* done with sysinbox text */
  270. fs_give ((void **) &s);
  271. /* all done with mbox */
  272. unix_unlock (LOCAL->fd,stream,&lock);
  273. mail_unlock (stream); /* unlock the stream */
  274. mm_nocritical (stream); /* done with critical */
  275.       }
  276. /* all done with sysinbox */
  277.       unix_unlock (sfd,NIL,&lockx);
  278.     }
  279.     LOCAL->lastsnarf = time (0);/* note time of last snarf */
  280.   }
  281.   return unix_ping (stream); /* do the unix routine now */
  282. }
  283. /* MBOX mail check mailbox
  284.  * Accepts: MAIL stream
  285.  */
  286. void mbox_check (MAILSTREAM *stream)
  287. {
  288. /* do local ping, then do unix routine */
  289.   if (mbox_ping (stream)) unix_check (stream);
  290. }
  291. /* MBOX mail expunge mailbox
  292.  * Accepts: MAIL stream
  293.  */
  294. void mbox_expunge (MAILSTREAM *stream)
  295. {
  296.   unix_expunge (stream); /* do expunge */
  297.   mbox_ping (stream); /* do local ping */
  298. }
  299. /* MBOX mail append message from stringstruct
  300.  * Accepts: MAIL stream
  301.  *     destination mailbox
  302.  *     initial flags
  303.  *     internal date
  304.  *     stringstruct of messages to append
  305.  * Returns: T if append successful, else NIL
  306.  */
  307. long mbox_append (MAILSTREAM *stream,char *mailbox,char *flags,char *date,
  308.   STRING *message)
  309. {
  310.   return unix_append (stream,"mbox",flags,date,message);
  311. }