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

网络编程

开发平台:

Unix_Linux

  1. /*
  2.  * Program: Dummy routines for NT
  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: 24 May 1993
  13.  * Last Edited: 4 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 <ctype.h>
  36. #include <stdio.h>
  37. #include <errno.h>
  38. #include <fcntl.h>
  39. #include <direct.h>
  40. #include "mail.h"
  41. #include "osdep.h"
  42. #include <sysstat.h>
  43. #include <dos.h>
  44. #include "dummy.h"
  45. #include "misc.h"
  46. /* Dummy routines */
  47. /* Driver dispatch used by MAIL */
  48. DRIVER dummydriver = {
  49.   "dummy", /* driver name */
  50.   DR_LOCAL|DR_MAIL, /* driver flags */
  51.   (DRIVER *) NIL, /* next driver */
  52.   dummy_valid, /* mailbox is valid for us */
  53.   dummy_parameters, /* manipulate parameters */
  54.   dummy_scan, /* scan mailboxes */
  55.   dummy_list, /* list mailboxes */
  56.   dummy_lsub, /* list subscribed mailboxes */
  57.   dummy_subscribe, /* subscribe to mailbox */
  58.   NIL, /* unsubscribe from mailbox */
  59.   dummy_create, /* create mailbox */
  60.   dummy_delete, /* delete mailbox */
  61.   dummy_rename, /* rename mailbox */
  62.   NIL, /* status of mailbox */
  63.   dummy_open, /* open mailbox */
  64.   dummy_close, /* close mailbox */
  65.   NIL, /* fetch message "fast" attributes */
  66.   NIL, /* fetch message flags */
  67.   NIL, /* fetch overview */
  68.   NIL, /* fetch message structure */
  69.   NIL, /* fetch header */
  70.   NIL, /* fetch text */
  71.   NIL, /* fetch message data */
  72.   NIL, /* unique identifier */
  73.   NIL, /* message number from UID */
  74.   NIL, /* modify flags */
  75.   NIL, /* per-message modify flags */
  76.   NIL, /* search for message based on criteria */
  77.   NIL, /* sort messages */
  78.   NIL, /* thread messages */
  79.   dummy_ping, /* ping mailbox to see if still alive */
  80.   dummy_check, /* check for new messages */
  81.   dummy_expunge, /* expunge deleted messages */
  82.   dummy_copy, /* copy messages to another mailbox */
  83.   dummy_append, /* append string message to mailbox */
  84.   NIL /* garbage collect stream */
  85. };
  86. /* prototype stream */
  87. MAILSTREAM dummyproto = {&dummydriver};
  88. /* Dummy validate mailbox
  89.  * Accepts: mailbox name
  90.  * Returns: our driver if name is valid, NIL otherwise
  91.  */
  92. DRIVER *dummy_valid (char *name)
  93. {
  94.   char *s,tmp[MAILTMPLEN];
  95.   struct stat sbuf;
  96. /* must be valid local mailbox */
  97.   if (!(name && *name && (*name != '{'))) return NIL;
  98. /* no trailing  */
  99.   if ((s = strrchr (mailboxfile (tmp,name),'\')) && !s[1]) *s = '';
  100.   return (!tmp[0] || !stat (tmp,&sbuf)) ? &dummydriver : NIL;
  101. }
  102. /* Dummy manipulate driver parameters
  103.  * Accepts: function code
  104.  *     function-dependent value
  105.  * Returns: function-dependent return value
  106.  */
  107. void *dummy_parameters (long function,void *value)
  108. {
  109.   return value;
  110. }
  111. /* Dummy scan mailboxes
  112.  * Accepts: mail stream
  113.  *     reference
  114.  *     pattern to search
  115.  *     string to scan
  116.  */
  117. void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
  118. {
  119.   char *s,test[MAILTMPLEN],file[MAILTMPLEN];
  120.   long i = 0;
  121.   if (!pat || !*pat) { /* empty pattern? */
  122.     if (dummy_canonicalize (test,ref,"*")) {
  123. /* tie off name at root */
  124.       if (s = strchr (test,'\')) *++s = '';
  125.       else test[0] = '';
  126.       dummy_listed (stream,'\',test,LATT_NOSELECT,NIL);
  127.     }
  128.   }
  129. /* get canonical form of name */
  130.   else if (dummy_canonicalize (test,ref,pat)) {
  131. /* found any wildcards? */
  132.     if (s = strpbrk (test,"%*")) {
  133. /* yes, copy name up to that point */
  134.       strncpy (file,test,(size_t) (i = s - test));
  135.       file[i] = ''; /* tie off */
  136.     }
  137.     else strcpy (file,test); /* use just that name then */
  138. /* find directory name */
  139.     if (s = strrchr (file,'\')) {
  140.       *++s = ''; /* found, tie off at that point */
  141.       s = file;
  142.     }
  143. /* silly case */
  144.     else if (file[0] == '#') s = file;
  145. /* do the work */
  146.     dummy_list_work (stream,s,test,contents,0);
  147.     if (pmatch ("INBOX",test)) /* always an INBOX */
  148.       dummy_listed (stream,NIL,"INBOX",LATT_NOINFERIORS,contents);
  149.   }
  150. }
  151. /* Dummy list mailboxes
  152.  * Accepts: mail stream
  153.  *     reference
  154.  *     pattern to search
  155.  */
  156. void dummy_list (MAILSTREAM *stream,char *ref,char *pat)
  157. {
  158.   dummy_scan (stream,ref,pat,NIL);
  159. }
  160. /* Dummy list subscribed mailboxes
  161.  * Accepts: mail stream
  162.  *     reference
  163.  *     pattern to search
  164.  */
  165. void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat)
  166. {
  167.   void *sdb = NIL;
  168.   char *s,*t,test[MAILTMPLEN],tmp[MAILTMPLEN];
  169.   int showuppers = pat[strlen (pat) - 1] == '%';
  170. /* get canonical form of name */
  171.   if (dummy_canonicalize (test,ref,pat) && (s = sm_read (&sdb))) do
  172.     if (*s != '{') {
  173.       if (pmatch_full (ucase (strcpy (tmp,s)),test,'\')) {
  174. if (pmatch (tmp,"INBOX")) mm_lsub (stream,NIL,s,LATT_NOINFERIORS);
  175. else mm_lsub (stream,'\',s,NIL);
  176.       }
  177.       else while (showuppers && (t = strrchr (s,'\'))) {
  178. *t = ''; /* tie off the name */
  179. if (pmatch_full (ucase (strcpy (tmp,s)),test,'\'))
  180.   mm_lsub (stream,'\',s,LATT_NOSELECT);
  181.       }
  182.     }
  183.   while (s = sm_read (&sdb)); /* until no more subscriptions */
  184. }
  185. /* Dummy subscribe to mailbox
  186.  * Accepts: mail stream
  187.  *     mailbox to add to subscription list
  188.  * Returns: T on success, NIL on failure
  189.  */
  190. long dummy_subscribe (MAILSTREAM *stream,char *mailbox)
  191. {
  192.   char *s,tmp[MAILTMPLEN];
  193.   struct stat sbuf;
  194. /* must be valid local mailbox */
  195.   if ((s = mailboxfile (tmp,mailbox)) && *s && !stat (s,&sbuf) &&
  196.       ((sbuf.st_mode & S_IFMT) == S_IFREG)) return sm_subscribe (mailbox);
  197.   sprintf (tmp,"Can't subscribe %s: not a mailbox",mailbox);
  198.   mm_log (tmp,ERROR);
  199.   return NIL;
  200. }
  201. /* Dummy list mailboxes worker routine
  202.  * Accepts: mail stream
  203.  *     directory name to search
  204.  *     search pattern
  205.  *     string to scan
  206.  *     search level
  207.  */
  208. void dummy_list_work (MAILSTREAM *stream,char *dir,char *pat,char *contents,
  209.       long level)
  210. {
  211.   struct _finddata_t f;
  212.   struct stat sbuf;
  213.   long fhandle;
  214.   char tmp[MAILTMPLEN],tmpx[MAILTMPLEN],tmpy[MAILTMPLEN];
  215.   char *base = (dir && ((dir[0] == '\') || (dir[1] == ':'))) ?
  216.     NIL : myhomedir ();
  217. /* build name */
  218.   if (base) sprintf (tmpx,"%s\",base);
  219.   else tmpx[0] = '';
  220.   if (dir) strcat (tmpx,dir);
  221. /* punt if bogus name */
  222.   if (!mailboxfile (tmp,tmpx)) return;
  223. /* make directory wildcard */
  224.   strcat (tmp,(tmp[strlen (tmp) -1] == '\') ? "*.*" : "\*.*");
  225. /* do nothing if can't open directory */
  226.   if ((fhandle = _findfirst (tmp,&f)) >= 0) {  
  227. /* list it if not at top-level */
  228.     if (!level && dir && pmatch_full (ucase (strcpy (tmpy,dir)),pat,'\'))
  229.       dummy_listed (stream,'\',dir,LATT_NOSELECT,contents);
  230. /* scan directory */
  231.     if (tmpx[strlen (tmpx) - 1] == '\') do
  232.       if ((f.name[0] != '.') ||
  233.   (f.name[1] && ((f.name[1] != '.') || f.name[2]))) {
  234. if (base) sprintf (tmpx,"%s\",base);
  235. else tmpx[0] = '';
  236. if (dir) sprintf (tmpx + strlen (tmpx),"%s%s",dir,f.name);
  237. else strcat (tmpx,f.name);
  238. /* see if name is useful */
  239. if (dir) sprintf (tmp,"%s%s",dir,f.name);
  240. else strcpy (tmp,f.name);
  241. /* make sure useful and can get info */
  242. if ((pmatch_full (ucase (tmp),pat,'\') ||
  243.      pmatch_full (strcat (tmp,"\"),pat,'\') || dmatch (tmp,pat,'\'))
  244.     && !stat (mailboxfile (tmp,tmpx),&sbuf)) {
  245. /* now make name we'd return */
  246.   if (dir) sprintf (tmp,"%s%s",dir,f.name);
  247.   else strcpy (tmp,f.name);
  248. /* only interested in file type */
  249.   switch (sbuf.st_mode &= S_IFMT) {
  250.   case S_IFDIR: /* directory? */
  251.     if (pmatch_full (ucase (strcpy (tmpy,tmp)),pat,'\')) {
  252.       dummy_listed (stream,'\',tmp,LATT_NOSELECT,contents);
  253.       strcat (tmp,"\");/* set up for dmatch call */
  254.       strcat (tmpy,"\");
  255.     }
  256.     else { /* try again with trailing / */
  257.       strcat (tmp,"\");
  258.       strcat (tmpy,"\");
  259.       if (pmatch_full (tmpy,pat,'\'))
  260. dummy_listed (stream,'\',tmp,LATT_NOSELECT,contents);
  261.     }
  262.     if (dmatch (tmpy,pat,'\') &&
  263. (level < (long) mail_parameters (NIL,GET_LISTMAXLEVEL,NIL)))
  264.       dummy_list_work (stream,tmp,pat,contents,level+1);
  265.     break;
  266.   case S_IFREG: /* ordinary name */
  267.     if (pmatch_full (ucase (strcpy (tmpy,tmp)),pat,'\') &&
  268. !pmatch ("INBOX",tmpy))
  269.       dummy_listed (stream,'\',tmp,LATT_NOINFERIORS,contents);
  270.     break;
  271.   }
  272. }
  273.       }
  274.     while (!_findnext (fhandle,&f));
  275.     _findclose(fhandle);
  276.   }
  277. }
  278. /* Mailbox found
  279.  * Accepts: hierarchy delimiter
  280.  *     mailbox name
  281.  *     attributes
  282.  *     contents to search before calling mm_list()
  283.  * Returns: T, always
  284.  */
  285. #define BUFSIZE 4*MAILTMPLEN
  286. long dummy_listed (MAILSTREAM *stream,char delimiter,char *name,
  287.    long attributes,char *contents)
  288. {
  289.   struct stat sbuf;
  290.   int fd;
  291.   long csiz,ssiz,bsiz;
  292.   char *buf,tmp[MAILTMPLEN];
  293.   if (contents) { /* want to search contents? */
  294. /* forget it if can't select or open */
  295.     if ((attributes & LATT_NOSELECT) || !(csiz = strlen (contents)) ||
  296. stat (dummy_file (tmp,name),&sbuf) || (csiz > sbuf.st_size) ||
  297. ((fd = open (tmp,O_RDONLY,NIL)) < 0)) return T;
  298. /* get buffer including slop */    
  299.     buf = (char *) fs_get (BUFSIZE + (ssiz = 4 * ((csiz / 4) + 1)) + 1);
  300.     memset (buf,'',ssiz); /* no slop area the first time */
  301.     while (sbuf.st_size) { /* until end of file */
  302.       read (fd,buf+ssiz,bsiz = min (sbuf.st_size,BUFSIZE));
  303.       if (search ((unsigned char *) buf,bsiz+ssiz,
  304.   (unsigned char *) contents,csiz)) break;
  305.       memcpy (buf,buf+BUFSIZE,ssiz);
  306.       sbuf.st_size -= bsiz; /* note that we read that much */
  307.     }
  308.     fs_give ((void **) &buf); /* flush buffer */
  309.     close (fd); /* finished with file */
  310.     if (!sbuf.st_size) return T;/* not found */
  311.   }
  312. /* notify main program */
  313.   mm_list (stream,delimiter,name,attributes);
  314.   return T;
  315. }
  316. /* Dummy create mailbox
  317.  * Accepts: mail stream
  318.  *     mailbox name to create
  319.  * Returns: T on success, NIL on failure
  320.  */
  321. long dummy_create (MAILSTREAM *stream,char *mailbox)
  322. {
  323.   char tmp[MAILTMPLEN];
  324.   if (strcmp (ucase (strcpy (tmp,mailbox)),"INBOX") && dummy_file(tmp,mailbox))
  325.     return dummy_create_path (stream,tmp);
  326.   sprintf (tmp,"Can't create %s: invalid name",mailbox);
  327.   mm_log (tmp,ERROR);
  328.   return NIL;
  329. }
  330. /* Dummy create path
  331.  * Accepts: mail stream
  332.  *     path name name to create
  333.  * Returns: T on success, NIL on failure
  334.  */
  335. long dummy_create_path (MAILSTREAM *stream,char *path)
  336. {
  337.   struct stat sbuf;
  338.   char c,*s,tmp[MAILTMPLEN];
  339.   int fd;
  340.   long ret = NIL;
  341.   char *t = strrchr (path,'\');
  342.   char *pt = (path[1] == ':') ? path + 2 : path;
  343.   int wantdir = t && !t[1];
  344.   if (wantdir) *t = ''; /* flush trailing delimiter for directory */
  345. /* found superior to this name? */
  346.   if ((s = strrchr (pt,'\')) && (s != pt)) {
  347.     strncpy (tmp,path,(size_t) (s - path));
  348.     tmp[s - path] = ''; /* make directory name for stat */
  349.     c = *++s; /* tie off in case need to recurse */
  350.     *s = '';
  351. /* name doesn't exist, create it */
  352.     if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
  353. !dummy_create_path (stream,path)) return NIL;
  354.     *s = c; /* restore full name */
  355.   }
  356.   if (wantdir) { /* want to create directory? */
  357.     ret = !mkdir (path);
  358.     *t = '\'; /* restore directory delimiter */
  359.   }
  360. /* create file */
  361.   else if ((fd = open (path,O_WRONLY|O_CREAT|O_EXCL,S_IREAD|S_IWRITE)) >= 0)
  362.     ret = !close (fd); /* close file */
  363.   if (!ret) { /* error? */
  364.     sprintf (tmp,"Can't create mailbox node %s: %s",path,strerror (errno));
  365.     mm_log (tmp,ERROR);
  366.   }
  367.   return ret; /* return status */
  368. }
  369. /* Dummy delete mailbox
  370.  * Accepts: mail stream
  371.  *     mailbox name to delete
  372.  * Returns: T on success, NIL on failure
  373.  */
  374. long dummy_delete (MAILSTREAM *stream,char *mailbox)
  375. {
  376.   struct stat sbuf;
  377.   char *s,tmp[MAILTMPLEN];
  378. /* no trailing  */
  379.   if ((s = strrchr (dummy_file (tmp,mailbox),'\')) && !s[1]) *s = '';
  380.   if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) == S_IFDIR) ?
  381.       rmdir (tmp) : unlink (tmp)) {
  382.     sprintf (tmp,"Can't delete mailbox %s: %s",mailbox,strerror (errno));
  383.     mm_log (tmp,ERROR);
  384.     return NIL;
  385.   }
  386.   return T; /* return success */
  387. }
  388. /* Mail rename mailbox
  389.  * Accepts: mail stream
  390.  *     old mailbox name
  391.  *     new mailbox name
  392.  * Returns: T on success, NIL on failure
  393.  */
  394. long dummy_rename (MAILSTREAM *stream,char *old,char *newname)
  395. {
  396.   struct stat sbuf;
  397.   char c,*s,tmp[MAILTMPLEN],mbx[MAILTMPLEN];
  398.   long ret = NIL;
  399. /* no trailing  allowed */
  400.   if (!(s = dummy_file (mbx,newname)) || ((s = strrchr (s,'\')) && !s[1])) {
  401.     sprintf (mbx,"Can't rename %s to %s: invalid name",old,newname);
  402.     mm_log (mbx,ERROR);
  403.     return NIL;
  404.   }
  405. /* found superior to destination name? */
  406.   if (s && (s != mbx) && ((mbx[1] != ':') || (s != mbx + 2))) {
  407.     c = s[1]; /* remember character after delimiter */
  408.     *s = s[1] = ''; /* tie off name at delimiter */
  409. /* name doesn't exist, create it */
  410.     if (stat (mbx,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) {
  411.       *s = '\'; /* restore delimiter */
  412.       if (!dummy_create (stream,mbx)) return NIL;
  413.     }
  414.     else *s = '\'; /* restore delimiter */
  415.     s[1] = c; /* restore character after delimiter */
  416.   }
  417. /* rename of non-ex INBOX creates dest */
  418.   if (!strcmp (ucase (strcpy (tmp,old)),"INBOX") &&
  419.       stat (dummy_file (tmp,old),&sbuf)) return dummy_create (NIL,mbx);
  420.   if (rename (dummy_file (tmp,old),mbx)) {
  421.     sprintf (tmp,"Can't rename mailbox %s to %s: %s",old,newname,
  422.      strerror (errno));
  423.     mm_log (tmp,ERROR);
  424.     return NIL;
  425.   }
  426.   return LONGT; /* return success */
  427. }
  428. /* Dummy open
  429.  * Accepts: stream to open
  430.  * Returns: stream on success, NIL on failure
  431.  */
  432. MAILSTREAM *dummy_open (MAILSTREAM *stream)
  433. {
  434.   int fd;
  435.   char err[MAILTMPLEN],tmp[MAILTMPLEN];
  436.   struct stat sbuf;
  437. /* OP_PROTOTYPE call */
  438.   if (!stream) return &dummyproto;
  439.   err[0] = ''; /* no error message yet */
  440. /* can we open the file? */
  441.   if ((fd = open (dummy_file (tmp,stream->mailbox),O_RDONLY,NIL)) < 0) {
  442. /* no, error unless INBOX */
  443.     if (strcmp (ucase (strcpy (tmp,stream->mailbox)),"INBOX"))
  444.       sprintf (err,"%s: %s",strerror (errno),stream->mailbox);
  445.   }
  446.   else { /* file had better be empty then */
  447.     fstat (fd,&sbuf); /* sniff at its size */
  448.     close (fd);
  449.     if (sbuf.st_size) /* bogus format if non-empty */
  450.       sprintf (err,"%s (file %s) is not in valid mailbox format",
  451.        stream->mailbox,tmp);
  452.   }
  453.   if (err[0]) { /* if an error happened */
  454.     mm_log (err,stream->silent ? WARN : ERROR);
  455.     return NIL;
  456.   }
  457.   else if (!stream->silent) { /* only if silence not requested */
  458.     mail_exists (stream,0); /* say there are 0 messages */
  459.     mail_recent (stream,0); /* and certainly no recent ones! */
  460.     stream->uid_validity = 1;
  461.   }
  462.   stream->inbox = T; /* note that it's an INBOX */
  463.   return stream; /* return success */
  464. }
  465. /* Dummy close
  466.  * Accepts: MAIL stream
  467.  *     options
  468.  */
  469. void dummy_close (MAILSTREAM *stream,long options)
  470. {
  471. /* return silently */
  472. }
  473. /* Dummy ping mailbox
  474.  * Accepts: MAIL stream
  475.  * Returns: T if stream alive, else NIL
  476.  */
  477. long dummy_ping (MAILSTREAM *stream)
  478. {
  479. /* time to do another test? */
  480.   if (time (0) >= ((time_t) (stream->gensym + 30))) {
  481.     MAILSTREAM *test = mail_open (NIL,stream->mailbox,OP_PROTOTYPE);
  482.     if (!test) return NIL; /* can't get a prototype?? */
  483.     if (test->dtb == stream->dtb) {
  484.       stream->gensym = time (0);/* still hasn't changed */
  485.       return T; /* try again later */
  486.     }
  487. /* looks like a new driver? */
  488.     if (!(test = mail_open (NIL,stream->mailbox,NIL))) return NIL;
  489.     mail_close ((MAILSTREAM *) /* flush resources used by dummy stream */
  490. memcpy (fs_get (sizeof (MAILSTREAM)),stream,
  491. sizeof (MAILSTREAM)));
  492. /* swap the streams */
  493.     memcpy (stream,test,sizeof (MAILSTREAM));
  494.     fs_give ((void **) &test); /* flush test now that copied */
  495.   }
  496.   return T;
  497. }
  498. /* Dummy check mailbox
  499.  * Accepts: MAIL stream
  500.  * No-op for readonly files, since read/writer can expunge it from under us!
  501.  */
  502. void dummy_check (MAILSTREAM *stream)
  503. {
  504.   dummy_ping (stream); /* invoke ping */
  505. }
  506. /* Dummy expunge mailbox
  507.  * Accepts: MAIL stream
  508.  */
  509. void dummy_expunge (MAILSTREAM *stream)
  510. {
  511. /* return silently */
  512. }
  513. /* Dummy copy message(s)
  514.  * Accepts: MAIL stream
  515.  *     sequence
  516.  *     destination mailbox
  517.  *     options
  518.  * Returns: T if copy successful, else NIL
  519.  */
  520. long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
  521. {
  522.   if ((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
  523.       mail_sequence (stream,sequence)) fatal ("Impossible dummy_copy");
  524.   return NIL;
  525. }
  526. /* Dummy append message string
  527.  * Accepts: mail stream
  528.  *     destination mailbox
  529.  *     optional flags
  530.  *     optional date
  531.  *     stringstruct of message to append
  532.  * Returns: T on success, NIL on failure
  533.  */
  534. long dummy_append (MAILSTREAM *stream,char *mailbox,char *flags,char *date,
  535.    STRING *message)
  536. {
  537.   struct stat sbuf;
  538.   int fd = -1;
  539.   int e;
  540.   char tmp[MAILTMPLEN];
  541.   MAILSTREAM *ts = default_proto (T);
  542.   if ((strcmp (ucase (strcpy (tmp,mailbox)),"INBOX")) &&
  543.    ((fd = open (dummy_file (tmp,mailbox),O_RDONLY,NIL)) < 0)) {
  544.     if ((e = errno) == ENOENT) /* failed, was it no such file? */
  545.       mm_notify (stream,"[TRYCREATE] Must create mailbox before append",
  546.  (long) NIL);
  547.     sprintf (tmp,"%s: %s",strerror (e),mailbox);
  548.     mm_log (tmp,ERROR); /* pass up error */
  549.     return NIL; /* always fails */
  550.   }
  551.   if (fd >= 0) { /* found file? */
  552.     fstat (fd,&sbuf); /* get its size */
  553.     close (fd); /* toss out the fd */
  554.     if (sbuf.st_size) ts = NIL; /* non-empty file? */
  555.   }
  556.   if (ts) return (*ts->dtb->append) (stream,mailbox,flags,date,message);
  557.   sprintf (tmp,"Indeterminate mailbox format: %s",mailbox);
  558.   mm_log (tmp,ERROR);
  559.   return NIL;
  560. }
  561. /* Dummy mail generate file string
  562.  * Accepts: temporary buffer to write into
  563.  *     mailbox name string
  564.  * Returns: local file string or NIL if failure
  565.  */
  566. char *dummy_file (char *dst,char *name)
  567. {
  568.   char *s = mailboxfile (dst,name);
  569. /* return our standard inbox */
  570.   return (s && !*s) ? strcpy (dst,sysinbox ()) : s;
  571. }
  572. /* Dummy canonicalize name
  573.  * Accepts: buffer to write name
  574.  *     reference
  575.  *     pattern
  576.  * Returns: T if success, NIL if failure
  577.  */
  578. long dummy_canonicalize (char *tmp,char *ref,char *pat)
  579. {
  580.   char dev[4];
  581. /* initially no device */
  582.   dev[0] = dev[1] = dev[2] = dev[3] = '';
  583.   if (ref) switch (*ref) { /* preliminary reference check */
  584.   case '{': /* remote names not allowed */
  585.     return NIL; /* disallowed */
  586.   case '': /* empty reference string */
  587.     break;
  588.   default: /* all other names */
  589.     if (ref[1] == ':') { /* start with device name? */
  590.       dev[0] = *ref++; dev[1] = *ref++;
  591.     }
  592.     break;
  593.   }
  594.   if (pat[1] == ':') { /* device name in pattern? */
  595.     dev[0] = *pat++; dev[1] = *pat++;
  596.     ref = NIL; /* ignore reference */
  597.   }
  598.   switch (*pat) {
  599.   case '#': /* namespace names */
  600.     if (mailboxfile (tmp,pat)) strcpy (tmp,pat);
  601.     else return NIL; /* unknown namespace */
  602.     break;
  603.   case '{': /* remote names not allowed */
  604.     return NIL;
  605.   case '\': /* rooted name */
  606.     ref = NIL; /* ignore reference */
  607.     break;
  608.   }
  609. /* make sure device names are rooted */
  610.   if (dev[0] && (*(ref ? ref : pat) != '\')) dev[2] = '\';
  611. /* build name */
  612.   sprintf (tmp,"%s%s%s",dev,ref ? ref : "",pat);
  613.   ucase (tmp); /* force upper case */
  614.   return T;
  615. }