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

网络编程

开发平台:

Unix_Linux

  1. /*
  2.  * Program: File 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: 25 August 1993
  13.  * Last Edited: 10 May 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 <signal.h>
  40. #include "mail.h"
  41. #include "osdep.h"
  42. #include <pwd.h>
  43. #include <sys/stat.h>
  44. #include <sys/time.h>
  45. #include "phile.h"
  46. #include "rfc822.h"
  47. #include "misc.h"
  48. #include "dummy.h"
  49. /* File routines */
  50. /* Driver dispatch used by MAIL */
  51. DRIVER philedriver = {
  52.   "phile", /* driver name */
  53. /* driver flags */
  54.   DR_LOCAL|DR_READONLY|DR_NOSTICKY,
  55.   (DRIVER *) NIL, /* next driver */
  56.   phile_valid, /* mailbox is valid for us */
  57.   phile_parameters, /* manipulate parameters */
  58.   phile_scan, /* scan mailboxes */
  59.   phile_list, /* list mailboxes */
  60.   phile_lsub, /* list subscribed mailboxes */
  61.   NIL, /* subscribe to mailbox */
  62.   NIL, /* unsubscribe from mailbox */
  63.   dummy_create, /* create mailbox */
  64.   dummy_delete, /* delete mailbox */
  65.   dummy_rename, /* rename mailbox */
  66.   NIL, /* status of mailbox */
  67.   phile_open, /* open mailbox */
  68.   phile_close, /* close mailbox */
  69.   NIL, /* fetch message "fast" attributes */
  70.   NIL, /* fetch message flags */
  71.   NIL, /* fetch overview */
  72.   phile_structure, /* fetch message envelopes */
  73.   phile_header, /* fetch message header only */
  74.   phile_text, /* fetch message body only */
  75.   NIL, /* fetch partial message text */
  76.   NIL, /* unique identifier */
  77.   NIL, /* message number */
  78.   NIL, /* modify flags */
  79.   NIL, /* per-message modify flags */
  80.   NIL, /* search for message based on criteria */
  81.   NIL, /* sort messages */
  82.   NIL, /* thread messages */
  83.   phile_ping, /* ping mailbox to see if still alive */
  84.   phile_check, /* check for new messages */
  85.   phile_expunge, /* expunge deleted messages */
  86.   phile_copy, /* copy messages to another mailbox */
  87.   phile_append, /* append string message to mailbox */
  88.   NIL /* garbage collect stream */
  89. };
  90. /* prototype stream */
  91. MAILSTREAM phileproto = {&philedriver};
  92. /* File validate mailbox
  93.  * Accepts: mailbox name
  94.  * Returns: our driver if name is valid, NIL otherwise
  95.  */
  96. DRIVER *phile_valid (char *name)
  97. {
  98.   char tmp[MAILTMPLEN];
  99.   return phile_isvalid (name,tmp) ? &philedriver : NIL;
  100. }
  101. /* File test for valid mailbox
  102.  * Accepts: mailbox name
  103.  * Returns: T if valid, NIL otherwise
  104.  */
  105. int phile_isvalid (char *name,char *tmp)
  106. {
  107.   struct stat sbuf;
  108.   char *s;
  109. /* INBOX never accepted, any other name is */
  110.   return ((s = mailboxfile (tmp,name)) && *s && !stat (s,&sbuf) &&
  111.   !(sbuf.st_mode & S_IFDIR) &&
  112. /* only allow empty files if #ftp */
  113.   (sbuf.st_size || ((*name == '#') &&
  114.     ((name[1] == 'f') || (name[1] == 'F')) &&
  115.     ((name[2] == 't') || (name[2] == 'T')) &&
  116.     ((name[3] == 'p') || (name[3] == 'P')) &&
  117.     (name[4] == '/'))));
  118. }
  119. /* File manipulate driver parameters
  120.  * Accepts: function code
  121.  *     function-dependent value
  122.  * Returns: function-dependent return value
  123.  */
  124. void *phile_parameters (long function,void *value)
  125. {
  126.   return NIL;
  127. }
  128. /* File mail scan mailboxes
  129.  * Accepts: mail stream
  130.  *     reference
  131.  *     pattern to search
  132.  *     string to scan
  133.  */
  134. void phile_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
  135. {
  136.   if (stream) dummy_scan (NIL,ref,pat,contents);
  137. }
  138. /* File list mailboxes
  139.  * Accepts: mail stream
  140.  *     reference
  141.  *     pattern to search
  142.  */
  143. void phile_list (MAILSTREAM *stream,char *ref,char *pat)
  144. {
  145.   if (stream) dummy_list (NIL,ref,pat);
  146. }
  147. /* File list subscribed mailboxes
  148.  * Accepts: mail stream
  149.  *     reference
  150.  *     pattern to search
  151.  */
  152. void phile_lsub (MAILSTREAM *stream,char *ref,char *pat)
  153. {
  154.   if (stream) dummy_lsub (NIL,ref,pat);
  155. }
  156. /* File open
  157.  * Accepts: Stream to open
  158.  * Returns: Stream on success, NIL on failure
  159.  */
  160. MAILSTREAM *phile_open (MAILSTREAM *stream)
  161. {
  162.   int i,k,fd;
  163.   unsigned long j,m;
  164.   char *s,tmp[MAILTMPLEN];
  165.   struct passwd *pw;
  166.   struct stat sbuf;
  167.   struct tm *t;
  168.   MESSAGECACHE *elt;
  169.   SIZEDTEXT *buf;
  170. /* return prototype for OP_PROTOTYPE call */
  171.   if (!stream) return &phileproto;
  172.   if (stream->local) fatal ("phile recycle stream");
  173. /* canonicalize the stream mailbox name */
  174.   mailboxfile (tmp,stream->mailbox);
  175.   fs_give ((void **) &stream->mailbox);
  176.   stream->mailbox = cpystr (tmp);
  177. /* open mailbox */
  178.   if (stat (tmp,&sbuf) || (fd = open (tmp,O_RDONLY,NIL)) < 0) {
  179.     sprintf (tmp,"Unable to open file %s",stream->mailbox);
  180.     mm_log (tmp,ERROR);
  181.     return NIL;
  182.   }
  183.   stream->local = fs_get (sizeof (PHILELOCAL));
  184.   mail_exists (stream,1); /* make sure upper level knows */
  185.   mail_recent (stream,1);
  186.   elt = mail_elt (stream,1); /* instantiate cache element */
  187.   elt->valid = elt->recent = T; /* mark valid flags */
  188.   stream->sequence++; /* bump sequence number */
  189.   stream->rdonly = T; /* make sure upper level knows readonly */
  190. /* instantiate a new envelope and body */
  191.   LOCAL->env = mail_newenvelope ();
  192.   LOCAL->body = mail_newbody ();
  193.   t = gmtime (&sbuf.st_mtime); /* get UTC time and Julian day */
  194.   i = t->tm_hour * 60 + t->tm_min;
  195.   k = t->tm_yday;
  196.   t = localtime(&sbuf.st_mtime);/* get local time */
  197. /* calculate time delta */
  198.   i = t->tm_hour * 60 + t->tm_min - i;
  199.   if (k = t->tm_yday - k) i += ((k < 0) == (abs (k) == 1)) ? -24*60 : 24*60;
  200.   k = abs (i); /* time from UTC either way */
  201.   elt->hours = t->tm_hour; elt->minutes = t->tm_min; elt->seconds = t->tm_sec;
  202.   elt->day = t->tm_mday; elt->month = t->tm_mon + 1;
  203.   elt->year = t->tm_year - (BASEYEAR - 1900);
  204.   elt->zoccident = (k == i) ? 0 : 1;
  205.   elt->zhours = k/60;
  206.   elt->zminutes = k % 60;
  207.   sprintf (tmp,"%s, %d %s %d %02d:%02d:%02d %c%02d%02d",
  208.    days[t->tm_wday],t->tm_mday,months[t->tm_mon],t->tm_year+1900,
  209.    t->tm_hour,t->tm_min,t->tm_sec,elt->zoccident ? '-' : '+',
  210.    elt->zhours,elt->zminutes);
  211. /* set up Date field */
  212.   LOCAL->env->date = cpystr (tmp);
  213. /* fill in From field from file owner */
  214.   LOCAL->env->from = mail_newaddr ();
  215.   if (pw = getpwuid (sbuf.st_uid)) strcpy (tmp,pw->pw_name);
  216.   else sprintf (tmp,"User-Number-%ld",(long) sbuf.st_uid);
  217.   LOCAL->env->from->mailbox = cpystr (tmp);
  218.   LOCAL->env->from->host = cpystr (mylocalhost ());
  219. /* set subject to be mailbox name */
  220.   LOCAL->env->subject = cpystr (stream->mailbox);
  221. /* slurp the data */
  222.   (buf = &elt->private.special.text)->size = sbuf.st_size;
  223.   read (fd,buf->data = (unsigned char *) fs_get (buf->size + 1),buf->size);
  224.   buf->data[buf->size] = '';
  225.   close (fd); /* close the file */
  226. /* analyze data type */
  227.   if (i = phile_type (buf->data,buf->size,&j)) {
  228.     LOCAL->body->type = TYPETEXT;
  229.     LOCAL->body->subtype = cpystr ("PLAIN");
  230.     if (!(i & PTYPECRTEXT)) { /* change Internet newline format as needed */
  231.       s = (char *) buf->data; /* make copy of UNIX-format string */
  232.       buf->data = NIL; /* zap the buffer */
  233.       buf->size = strcrlfcpy ((char **) &buf->data,&m,s,buf->size);
  234.       fs_give ((void **) &s); /* flush original UNIX-format string */
  235.     }
  236.     LOCAL->body->parameter = mail_newbody_parameter ();
  237.     LOCAL->body->parameter->attribute = cpystr ("charset");
  238.     LOCAL->body->parameter->value =
  239.       cpystr ((i & PTYPEISO2022JP) ? "ISO-2022-JP" :
  240.       (i & PTYPEISO2022KR) ? "ISO-2022-KR" :
  241.       (i & PTYPEISO2022CN) ? "ISO-2022-CN" :
  242.       (i & PTYPE8) ? "ISO-8859-1" : "US-ASCII");
  243.     LOCAL->body->encoding = (i & PTYPE8) ? ENC8BIT : ENC7BIT;
  244.     LOCAL->body->size.lines = j;
  245.   }
  246.   else { /* binary data */
  247.     LOCAL->body->type = TYPEAPPLICATION;
  248.     LOCAL->body->subtype = cpystr ("OCTET-STREAM");
  249.     LOCAL->body->parameter = mail_newbody_parameter ();
  250.     LOCAL->body->parameter->attribute = cpystr ("name");
  251.     LOCAL->body->parameter->value =
  252.       cpystr ((s = (strrchr (stream->mailbox,'/'))) ? s+1 : stream->mailbox);
  253.     LOCAL->body->encoding = ENCBASE64;
  254.     buf->data = rfc822_binary (s = (char *) buf->data,buf->size,&buf->size);
  255.     fs_give ((void **) &s); /* flush originary binary contents */
  256.   }
  257.   phile_header (stream,1,&j,NIL);
  258.   LOCAL->body->size.bytes = LOCAL->body->contents.text.size = buf->size;
  259.   elt->rfc822_size = j + buf->size;
  260. /* only one message ever... */
  261.   stream->uid_validity = sbuf.st_mtime;
  262.   stream->uid_last = elt->private.uid = 1;
  263.   return stream; /* return stream alive to caller */
  264. }
  265. /* File determine data type
  266.  * Accepts: data to examine
  267.  *     size of data
  268.  *     pointer to line count return
  269.  * Returns: PTYPE mask of data type
  270.  */
  271. int phile_type (unsigned char *s,unsigned long i,unsigned long *j)
  272. {
  273.   int ret = PTYPETEXT;
  274.   char *charvec = "bbbbbbbaaalaacaabbbbbbbbbbbebbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
  275.   *j = 0; /* no lines */
  276. /* check type of every character */
  277.   while (i--) switch (charvec[*s++]) {
  278.   case 'A':
  279.     ret |= PTYPE8; /* 8bit character */
  280.     break;
  281.   case 'a':
  282.     break; /* ASCII character */
  283.   case 'b':
  284.     return PTYPEBINARY; /* binary byte seen, stop immediately */
  285.   case 'c':
  286.     ret |= PTYPECRTEXT; /* CR indicates Internet text */
  287.     break;
  288.   case 'e': /* ESC */
  289.     if (*s == '$') { /* ISO-2022 sequence? */
  290.       switch (s[1]) {
  291.       case 'B': case '@': ret |= PTYPEISO2022JP; break;
  292.       case ')':
  293. switch (s[2]) {
  294. case 'A': case 'E': case 'G': ret |= PTYPEISO2022CN; break;
  295. case 'C': ret |= PTYPEISO2022KR; break;
  296. }
  297.       case '*':
  298. switch (s[2]) {
  299. case 'H': ret |= PTYPEISO2022CN; break;
  300. }
  301.       case '+':
  302. switch (s[2]) {
  303. case 'I': case 'J': case 'K': case 'L': case 'M':
  304.   ret |= PTYPEISO2022CN; break;
  305. }
  306.       }
  307.     }
  308.     break;
  309.   case 'l': /* newline */
  310.     (*j)++;
  311.     break;
  312.   }
  313.   return ret; /* return type of data */
  314. }
  315. /* File close
  316.  * Accepts: MAIL stream
  317.  *     close options
  318.  */
  319. void phile_close (MAILSTREAM *stream,long options)
  320. {
  321.   if (LOCAL) { /* only if a file is open */
  322.     fs_give ((void **) &mail_elt (stream,1)->private.special.text.data);
  323. /* nuke the local data */
  324.     fs_give ((void **) &stream->local);
  325.     stream->dtb = NIL; /* log out the DTB */
  326.   }
  327. }
  328. /* File fetch structure
  329.  * Accepts: MAIL stream
  330.  *     message # to fetch
  331.  *     pointer to return body
  332.  *     option flags
  333.  * Returns: envelope of this message, body returned in body value
  334.  *
  335.  * Fetches the "fast" information as well
  336.  */
  337. ENVELOPE *phile_structure (MAILSTREAM *stream,unsigned long msgno,BODY **body,
  338.    long flags)
  339. {
  340.   if (body) *body = LOCAL->body;
  341.   return LOCAL->env; /* return the envelope */
  342. }
  343. /* File fetch message header
  344.  * Accepts: MAIL stream
  345.  *     message # to fetch
  346.  *     pointer to returned header text length
  347.  *     option flags
  348.  * Returns: message header in RFC822 format
  349.  */
  350. char *phile_header (MAILSTREAM *stream,unsigned long msgno,
  351.     unsigned long *length,long flags)
  352. {
  353.   rfc822_header (LOCAL->tmp,LOCAL->env,LOCAL->body);
  354.   *length = strlen (LOCAL->tmp);
  355.   return LOCAL->tmp;
  356. }
  357. /* File fetch message text (body only)
  358.  * Accepts: MAIL stream
  359.  *     message # to fetch
  360.  *     pointer to returned stringstruct
  361.  *     option flags
  362.  * Returns: T, always
  363.  */
  364. long phile_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
  365. {
  366.   SIZEDTEXT *buf = &mail_elt (stream,msgno)->private.special.text;
  367.   if (!(flags &FT_PEEK)) { /* mark message as seen */
  368.     mail_elt (stream,msgno)->seen = T;
  369.     mm_flags (stream,msgno);
  370.   }
  371.   INIT (bs,mail_string,buf->data,buf->size);
  372.   return T;
  373. }
  374. /* File ping mailbox
  375.  * Accepts: MAIL stream
  376.  * Returns: T if stream alive, else NIL
  377.  * No-op for readonly files, since read/writer can expunge it from under us!
  378.  */
  379. long phile_ping (MAILSTREAM *stream)
  380. {
  381.   return T;
  382. }
  383. /* File check mailbox
  384.  * Accepts: MAIL stream
  385.  * No-op for readonly files, since read/writer can expunge it from under us!
  386.  */
  387. void phile_check (MAILSTREAM *stream)
  388. {
  389.   mm_log ("Check completed",NIL);
  390. }
  391. /* File expunge mailbox
  392.  * Accepts: MAIL stream
  393.  */
  394. void phile_expunge (MAILSTREAM *stream)
  395. {
  396.   mm_log ("Expunge ignored on readonly mailbox",NIL);
  397. }
  398. /* File copy message(s)
  399.  * Accepts: MAIL stream
  400.  *     sequence
  401.  *     destination mailbox
  402.  *     copy options
  403.  * Returns: T if copy successful, else NIL
  404.  */
  405. long phile_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
  406. {
  407.   char tmp[MAILTMPLEN];
  408.   mailproxycopy_t pc =
  409.     (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
  410.   if (pc) return (*pc) (stream,sequence,mailbox,options);
  411.   sprintf (tmp,"Can't copy - file "%s" is not in valid mailbox format",
  412.    stream->mailbox);
  413.   mm_log (tmp,ERROR);
  414.   return NIL;
  415. }
  416. /* File append message from stringstruct
  417.  * Accepts: MAIL stream
  418.  *     destination mailbox
  419.  *     stringstruct of messages to append
  420.  * Returns: T if append successful, else NIL
  421.  */
  422. long phile_append (MAILSTREAM *stream,char *mailbox,char *flags,char *date,
  423.    STRING *message)
  424. {
  425.   char tmp[MAILTMPLEN],file[MAILTMPLEN];
  426.   sprintf (tmp,"Can't append - file "%s" is not in valid mailbox format",
  427.    mailboxfile (file,mailbox));
  428.   mm_log (tmp,ERROR);
  429.   return NIL;
  430. }