home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / pine / pine3.07 / c-client / mail.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-05-06  |  27.2 KB  |  1,047 lines

  1. /*
  2.  * Program:    Mailbox Access 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:    22 November 1989
  13.  * Last Edited:    6 May 1992
  14.  *
  15.  * Copyright 1992 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.  
  36.  
  37. #include <ctype.h>
  38. #include <stdio.h>
  39. #if unix
  40. #include <sys/types.h>
  41. #endif
  42. #include "osdep.h"
  43. #include "mail.h"
  44. #include "misc.h"
  45.  
  46. DRIVER *maildrivers = NIL;    /* list of mail drivers */
  47. mailgets_t mailgets = NIL;    /* pointer to alternate gets function */
  48.  
  49. /* Default limited get string
  50.  * Accepts: readin function pointer
  51.  *        stream to use
  52.  *        number of bytes
  53.  * Returns: string read in, truncated if necessary
  54.  *
  55.  * This is a sample mailgets routine.  It simply truncates any data larger
  56.  * than MAXMESSAGESIZE.  On most systems, you generally don't use a mailgets
  57.  * routine at all, but on some systems (e.g. DOS) it's required to prevent the
  58.  * application from crashing.  This one is filled in by the os driver for any
  59.  * OS that requires a mailgets routine and the main program has not already
  60.  * supplied one, generally in tcp_open().
  61.  */
  62.  
  63. char *mm_gets (f,stream,size)
  64.     readfn_t f;
  65.     void *stream;
  66.     unsigned long size;
  67. {
  68.   char *s;
  69.   char tmp[MAILTMPLEN+1];
  70.   unsigned long i,j = 0;
  71.                 /* truncate? */
  72.   if (i = (size > MAXMESSAGESIZE)) {
  73.     sprintf (tmp,"%ld character literal truncated to %ld characters",
  74.          size,MAXMESSAGESIZE);
  75.     mm_log (tmp,WARN);        /* warn user */
  76.     i = size - MAXMESSAGESIZE;    /* number of bytes of slop */
  77.     size = MAXMESSAGESIZE;    /* maximum length string we can read */
  78.   }
  79.   s = (char *) fs_get (size + 1);
  80.   *s = '\0';            /* init in case getbuffer fails */
  81.   (*f) (stream,size,s);        /* get the literal */
  82.                 /* toss out everything after that */
  83.   while (i -= j) (*f) (stream,j = min ((long) MAILTMPLEN,i),tmp);
  84.   return s;
  85. }
  86.  
  87. /* Mail routines
  88.  *
  89.  *  mail_xxx routines are the interface between this module and the outside
  90.  * world.  Only these routines should be referenced by external callers.
  91.  *
  92.  *  Note that there is an important difference between a "sequence" and a
  93.  * "message #" (msgno).  A sequence is a string representing a sequence in
  94.  * {"n", "n:m", or combination separated by commas} format, whereas a msgno
  95.  * is a single integer.
  96.  *
  97.  */
  98.  
  99. /* Mail link driver
  100.  * Accepts: driver to add to list
  101.  */
  102.  
  103. void mail_link (driver)
  104.     DRIVER *driver;
  105. {
  106.   DRIVER **d = &maildrivers;
  107.   while (*d) d = &(*d)->next;    /* find end of list of drivers */
  108.   *d = driver;            /* put driver at the end */
  109.   driver->next = NIL;        /* this driver is the end of the list */
  110. }
  111.  
  112.  
  113. /* Mail find list of mailboxes
  114.  * Accepts: mail stream
  115.  *        pattern to search
  116.  */
  117.  
  118. void mail_find (stream,pat)
  119.     MAILSTREAM *stream;
  120.     char *pat;
  121. {
  122.   DRIVER **d = &maildrivers;
  123.                 /* if have a stream, do it for that stream */
  124.   if (stream && stream->dtb) (*stream->dtb->find) (stream,pat);
  125.                 /* otherwise do for all DTB's */
  126.   else do ((*d)->find) (NIL,pat);
  127.   while (*(d = &(*d)->next));    /* until at the end */
  128. }
  129.  
  130.  
  131. /* Mail find list of bboards
  132.  * Accepts: mail stream
  133.  *        pattern to search
  134.  */
  135.  
  136. void mail_find_bboards (stream,pat)
  137.     MAILSTREAM *stream;
  138.     char *pat;
  139. {
  140.   DRIVER **d = &maildrivers;
  141.   if (stream && stream->dtb) (*stream->dtb->find_bboard) (stream,pat);
  142.   else do ((*d)->find_bboard) (NIL,pat);
  143.   while (*(d = &(*d)->next));    /* until at the end */
  144. }
  145.  
  146. /* Mail open
  147.  * Accepts: candidate stream for recycling
  148.  *        mailbox name
  149.  *        initial debugging flag
  150.  * Returns: stream to use on success, NIL on failure
  151.  */
  152.  
  153. MAILSTREAM *mail_open (stream,name,debug)
  154.     MAILSTREAM *stream;
  155.     char *name;
  156.     long debug;
  157. {
  158.   long i;
  159.   char tmp[MAILTMPLEN];
  160.   DRIVER *factory = maildrivers ? (*maildrivers->valid) (name) : NIL;
  161.   if (factory) {        /* must have a factory */
  162.     if (!stream) {        /* instantiate stream if none to recycle */
  163.       stream = (MAILSTREAM *) fs_get (sizeof (MAILSTREAM));
  164.       stream->dtb = factory;    /* initialize stream fields */
  165.       stream->local = NIL;
  166.       stream->mailbox = cpystr (name);
  167.       stream->lock = stream->debug = stream->silent = stream->readonly =
  168.     stream->anonymous = NIL;
  169.       stream->use = stream->sequence = stream->gensym = stream->nmsgs =
  170.     stream->recent = 0;
  171.       stream->flagstring = NIL;
  172.       for (i = 0; i < NUSERFLAGS; ++i) stream->user_flags[i] = NIL;
  173.       stream->cache = NIL;    /* no cache */
  174.       stream->cachesize = 0;
  175.     }
  176.     else {            /* close driver if different from factory */
  177.       if (stream->dtb != factory) {
  178.     if (stream->dtb) (*stream->dtb->close) (stream);
  179.     stream->dtb = factory;    /* establish factory as our driver */
  180.     stream->local = NIL;    /* flush old driver's local data */
  181.       }
  182.                 /* clear old silent and readonly state */
  183.       stream->silent = stream->readonly = NIL;
  184.                 /* clean up old stream for recycling */
  185.       if (stream->mailbox) fs_give ((void **) &stream->mailbox);
  186.       stream->mailbox = cpystr (name);
  187.       mail_free_cache (&stream->cache,&stream->cachesize);
  188.     }
  189.     if (debug == 36) {        /* special hack from Tenex? */
  190.       stream->debug = NIL;    /* yes, no special debugging */
  191.       stream->silent = T;    /* request silence */
  192.     }
  193.                 /* a second grotesque hack */
  194.     else if (debug == 69) stream->anonymous = T;
  195.     else stream->debug = debug;    /* set to desired debugging state */
  196.                 /* have driver open, flush if failed */
  197.     if (!(*factory->open) (stream)) stream = mail_close (stream);
  198.   }
  199.   else if (debug != 36) {    /* not from Tenex internal please */
  200.     sprintf (tmp,"Unknown mailbox format: %.80s",name);
  201.     mm_log (tmp,ERROR);        /* give an error */
  202.   }
  203.   return stream;        /* return the stream */
  204. }
  205.  
  206. /* Mail close
  207.  * Accepts: mail stream
  208.  * Returns: NIL
  209.  */
  210.  
  211. MAILSTREAM *mail_close (stream)
  212.     MAILSTREAM *stream;
  213. {
  214.   long i;
  215.   if (stream) {            /* make sure argument given */
  216.                 /* do the driver's close action */
  217.     if (stream->dtb) (*stream->dtb->close) (stream);
  218.     stream->dtb = NIL;        /* disassociate from driver */
  219.     stream->local = NIL;    /* and driver's local data */
  220.     if (stream->mailbox) fs_give ((void **) &stream->mailbox);
  221.     stream->mailbox = NIL;
  222.     stream->sequence++;        /* invalidate sequence */
  223.     if (stream->flagstring) fs_give ((void **) &stream->flagstring);
  224.     stream->flagstring = NIL;
  225.     for (i = 0; i < NUSERFLAGS; ++i) stream->user_flags[i] = NIL;
  226.     mail_free_cache (&stream->cache,&stream->cachesize);
  227.                 /* finally free the stream's storage */
  228.     if (!stream->use) fs_give ((void **) &stream);
  229.   }
  230.   return NIL;
  231. }
  232.  
  233. /* Mail make handle
  234.  * Accepts: Mail stream
  235.  * Returns: handle
  236.  *
  237.  *  Handles provide a way to have multiple pointers to a stream yet allow the
  238.  * stream's owner to nuke it or recycle it.
  239.  */
  240.  
  241. MAILHANDLE *mail_makehandle (stream)
  242.     MAILSTREAM *stream;
  243. {
  244.   MAILHANDLE *handle = (MAILHANDLE *) fs_get (sizeof (MAILHANDLE));
  245.   handle->stream = stream;    /* copy stream */
  246.                 /* and its sequence */
  247.   handle->sequence = stream->sequence;
  248.   stream->use++;        /* let stream know another handle exists */
  249.   return handle;
  250. }
  251.  
  252.  
  253. /* Mail release handle
  254.  * Accepts: Mail handle
  255.  */
  256.  
  257. void mail_free_handle (handle)
  258.     MAILHANDLE **handle;
  259. {
  260.   MAILSTREAM *s;
  261.   if (*handle) {        /* only free if exists */
  262.                 /* resign stream, flush unreferenced zombies */
  263.     if ((!--(s = (*handle)->stream)->use) && !s->dtb) fs_give ((void **) &s);
  264.     fs_give ((void **) handle);    /* now flush the handle */
  265.   }
  266. }
  267.  
  268.  
  269. /* Mail get stream handle
  270.  * Accepts: Mail handle
  271.  * Returns: Mail stream or NIL if stream gone
  272.  */
  273.  
  274. MAILSTREAM *mail_stream (handle)
  275.     MAILHANDLE *handle;
  276. {
  277.   MAILSTREAM *s = handle->stream;
  278.   return (s->dtb && (handle->sequence == s->sequence)) ? s : NIL;
  279. }
  280.  
  281. /* Mail fetch cache element
  282.  * Accepts: Mail stream
  283.  *        message # to fetch
  284.  * Returns: cache element of this message
  285.  * Can also be used to create cache elements for new messages.
  286.  */
  287.  
  288. MESSAGECACHE *mail_elt (stream,msgno)
  289.     MAILSTREAM *stream;
  290.     long msgno;
  291. {
  292.   long i = msgno - 1;
  293.   if (msgno < 1) fatal ("mail_elt called for non-positive message number");
  294.   mail_cache (stream,msgno);    /* make sure cache is large enough */
  295.   if (!stream->cache[i]) {    /* if no cache entry, create it */
  296.     stream->cache[i] = (MESSAGECACHE *) fs_get (sizeof (MESSAGECACHE));
  297.                 /* initialize newly-created cache entry */
  298.     stream->cache[i]->lockcount = 1;
  299.     stream->cache[i]->msgno = msgno;
  300.     stream->cache[i]->internal_date = NIL;
  301.     stream->cache[i]->seen = stream->cache[i]->deleted =
  302.       stream->cache[i]->flagged = stream->cache[i]->answered =
  303.     stream->cache[i]->searched = stream->cache[i]->recent = NIL;
  304.     stream->cache[i]->user_flags = NIL;
  305.     stream->cache[i]->rfc822_size = 0;
  306.     stream->cache[i]->env = NIL;
  307.     stream->cache[i]->body = NIL;
  308.   }
  309.   return stream->cache[i];    /* return the cache element */
  310. }
  311.  
  312.  
  313. /* Mail make cache large enough for given number of messages
  314.  * Accepts: Mail stream
  315.  *        number of messages in cache
  316.  */
  317.  
  318. void mail_cache (stream,size)
  319.     MAILSTREAM *stream;
  320.     long size;
  321. {
  322.   size_t new;
  323.   unsigned long i = stream->cachesize;
  324.                 /* do nothing if size adequate */
  325.   if (size <= stream->cachesize) return;
  326.   new = (stream->cachesize = size + CACHEINCREMENT) * sizeof (MESSAGECACHE *);
  327.   if (stream->cache) fs_resize ((void **) &stream->cache,new);
  328.   else stream->cache = (MESSAGECACHE **) fs_get (new);
  329.                 /* init cache */
  330.   while (i < stream->cachesize) stream->cache[i++] = NIL;
  331. }
  332.  
  333. /* Mail fetch fast information
  334.  * Accepts: Mail stream
  335.  *        sequence
  336.  *
  337.  * Generally, mail_fetchenvelope is preferred
  338.  */
  339.  
  340. void mail_fetchfast (stream,sequence)
  341.     MAILSTREAM *stream;
  342.     char *sequence;
  343. {
  344.                   /* do the driver's action */
  345.   if (stream->dtb) (*stream->dtb->fetchfast) (stream,sequence);
  346. }
  347.  
  348.  
  349. /* Mail fetch flags
  350.  * Accepts: Mail stream
  351.  *        sequence
  352.  */
  353.  
  354. void mail_fetchflags (stream,sequence)
  355.     MAILSTREAM *stream;
  356.     char *sequence;
  357. {
  358.                   /* do the driver's action */
  359.   if (stream->dtb) (*stream->dtb->fetchflags) (stream,sequence);
  360. }
  361.  
  362.  
  363. /* Mail fetch envelope
  364.  * Accepts: Mail stream
  365.  *        message # to fetch
  366.  * Returns: envelope of this message
  367.  *
  368.  * Fetches the "fast" information as well
  369.  */
  370.  
  371. ENVELOPE *mail_fetchenvelope (stream,msgno)
  372.     MAILSTREAM *stream;
  373.     long msgno;
  374. {
  375.   if (msgno > stream->nmsgs)
  376.     fatal ("mail_fetchenvelope called for non-existent message number");
  377.                   /* do the driver's action */
  378.   return stream->dtb ? (*stream->dtb->fetchenvelope) (stream,msgno) : NIL;
  379. }
  380.  
  381. /* Mail fetch message header
  382.  * Accepts: Mail stream
  383.  *        message # to fetch
  384.  * Returns: message header in RFC822 format
  385.  */
  386.  
  387. char *mail_fetchheader (stream,msgno)
  388.     MAILSTREAM *stream;
  389.     long msgno;
  390. {
  391.   if (msgno > stream->nmsgs)
  392.     fatal ("mail_fetchheader called for non-existent message number");
  393.                   /* do the driver's action */
  394.   return stream->dtb ? (*stream->dtb->fetchheader) (stream,msgno) : "";
  395. }
  396.  
  397.  
  398. /* Mail fetch message text (only)
  399.     body only;
  400.  * Accepts: Mail stream
  401.  *        message # to fetch
  402.  * Returns: message text in RFC822 format
  403.  */
  404.  
  405. char *mail_fetchtext (stream,msgno)
  406.     MAILSTREAM *stream;
  407.     long msgno;
  408. {
  409.   if (msgno > stream->nmsgs)
  410.     fatal ("mail_fetchtext called for non-existent message number");
  411.                   /* do the driver's action */
  412.   return stream->dtb ? (*stream->dtb->fetchtext) (stream,msgno) : "";
  413. }
  414.  
  415.  
  416. /* Mail fetch message body as a structure
  417.  * Accepts: Mail stream
  418.  *        message # to fetch
  419.  *        section specifier (#.#.#...#)
  420.  *        pointer to returned length
  421.  * Returns: pointer to section of message body
  422.  */
  423.  
  424. char *mail_fetchbody (stream,m,sec,len)
  425.     MAILSTREAM *stream;
  426.     long m;
  427.     char *sec;
  428.     unsigned long *len;
  429. {
  430.   if (m > stream->nmsgs)
  431.     fatal ("mail_fetchbody called for non-existent message number");
  432.                   /* do the driver's action */
  433.   return stream->dtb ? (*stream->dtb->fetchbody) (stream,m,sec,len) : "";
  434. }
  435.  
  436. /* Mail fetch From string for menu
  437.  * Accepts: destination string
  438.  *        Mail stream
  439.  *        message # to fetch
  440.  *        desired string length
  441.  * Returns: string of requested length
  442.  */
  443.  
  444. void mail_fetchfrom (s,stream,msgno,length)
  445.     char *s;
  446.     MAILSTREAM *stream;
  447.     long msgno;
  448.     long length;
  449. {
  450.   char *t;
  451.   char tmp[MAILTMPLEN];
  452.   ENVELOPE *env = mail_fetchenvelope (stream,msgno);
  453.   memset (s,' ',length);    /* fill it with spaces */
  454.   s[length] = '\0';        /* tie off with null */
  455.                 /* get first from address from envelope */
  456.   if (env && env->from) {    /* if a personal name exists use it */
  457.     if (!(t = env->from->personal))
  458.       sprintf (t = tmp,"%s@%s",env->from->mailbox,env->from->host);
  459.     memcpy (s,t,min (length,(long) strlen (t)));
  460.   }
  461. }
  462.  
  463.  
  464. /* Mail fetch Subject string for menu
  465.  * Accepts: destination string
  466.  *        Mail stream
  467.  *        message # to fetch
  468.  *        desired string length
  469.  * Returns: string of no more than requested length
  470.  */
  471.  
  472. void mail_fetchsubject (s,stream,msgno,length)
  473.     char *s;
  474.     MAILSTREAM *stream;
  475.     long msgno;
  476.     long length;
  477. {
  478.   ENVELOPE *env = mail_fetchenvelope (stream,msgno);
  479.   memset (s,'\0',length+1);
  480.                 /* copy subject from envelope */
  481.   if (env && env->subject) strncpy (s,env->subject,length);
  482.   else *s = ' ';        /* if no subject then just a space */
  483. }
  484.  
  485. /* Mail set flag
  486.  * Accepts: Mail stream
  487.  *        sequence
  488.  *        flag(s)
  489.  */
  490.  
  491. void mail_setflag (stream,sequence,flag)
  492.     MAILSTREAM *stream;
  493.     char *sequence;
  494.     char *flag;
  495. {
  496.                   /* do the driver's action */
  497.   if (stream->dtb) (*stream->dtb->setflag) (stream,sequence,flag);
  498. }
  499.  
  500.  
  501. /* Mail clear flag
  502.  * Accepts: Mail stream
  503.  *        sequence
  504.  *        flag(s)
  505.  */
  506.  
  507. void mail_clearflag (stream,sequence,flag)
  508.     MAILSTREAM *stream;
  509.     char *sequence;
  510.     char *flag;
  511. {
  512.                   /* do the driver's action */
  513.   if (stream->dtb) (*stream->dtb->clearflag) (stream,sequence,flag);
  514. }
  515.  
  516.  
  517. /* Mail search for messages
  518.  * Accepts: Mail stream
  519.  *        search criteria
  520.  */
  521.  
  522. void mail_search (stream,criteria)
  523.     MAILSTREAM *stream;
  524.     char *criteria;
  525. {
  526.   long i = 1;
  527.   while (i <= stream->nmsgs) mail_elt (stream,i++)->searched = NIL;
  528.                   /* do the driver's action */
  529.   if (stream->dtb) (*stream->dtb->search) (stream,criteria);
  530. }
  531.  
  532.  
  533. /* Mail ping mailbox
  534.  * Accepts: Mail stream
  535.  * Returns: stream if still open else NIL
  536.  */
  537.  
  538. long mail_ping (stream)
  539.     MAILSTREAM *stream;
  540. {
  541.                   /* do the driver's action */
  542.   return stream->dtb ? (*stream->dtb->ping) (stream) : NIL;
  543. }
  544.  
  545. /* Mail check mailbox
  546.  * Accepts: Mail stream
  547.  */
  548.  
  549. void mail_check (stream)
  550.     MAILSTREAM *stream;
  551. {
  552.                   /* do the driver's action */
  553.   if (stream->dtb) (*stream->dtb->check) (stream);
  554. }
  555.  
  556.  
  557. /* Mail expunge mailbox
  558.  * Accepts: Mail stream
  559.  */
  560.  
  561. void mail_expunge (stream)
  562.     MAILSTREAM *stream;
  563. {
  564.                   /* do the driver's action */
  565.   if (stream->dtb) (*stream->dtb->expunge) (stream);
  566. }
  567.  
  568.  
  569. /* Mail copy message(s)
  570.     s;
  571.  * Accepts: Mail stream
  572.  *        sequence
  573.  *        destination mailbox
  574.  */
  575.  
  576. long mail_copy (stream,sequence,mailbox)
  577.     MAILSTREAM *stream;
  578.     char *sequence;
  579.     char *mailbox;
  580. {
  581.                   /* do the driver's action */
  582.   return stream->dtb ? (*stream->dtb->copy) (stream,sequence,mailbox) : NIL;
  583. }
  584.  
  585.  
  586. /* Mail move message(s)
  587.     s;
  588.  * Accepts: Mail stream
  589.  *        sequence
  590.  *        destination mailbox
  591.  */
  592.  
  593. long mail_move (stream,sequence,mailbox)
  594.     MAILSTREAM *stream;
  595.     char *sequence;
  596.     char *mailbox;
  597. {
  598.                   /* do the driver's action */
  599.   return stream->dtb ? (*stream->dtb->move) (stream,sequence,mailbox) : NIL;
  600. }
  601.  
  602. /* Mail garbage collect stream
  603.  * Accepts: Mail stream
  604.  *        garbage collection flags
  605.  */
  606.  
  607. void mail_gc (stream,gcflags)
  608.     MAILSTREAM *stream;
  609.     long gcflags;
  610. {
  611.   unsigned long i = 0;
  612.   MESSAGECACHE *elt;
  613.   if (gcflags & GC_ENV)        /* garbage collect envelopes? */
  614.     while (i < stream->nmsgs)
  615.       if ((elt = stream->cache[i++]) && elt->env) {
  616.     mail_free_envelope (&elt->env);
  617.     mail_free_body (&elt->body);
  618.       }
  619.                   /* do the driver's action */
  620.   if (stream->dtb) (*stream->dtb->gc) (stream,gcflags);
  621. }
  622.  
  623. /* Mail messages have been searched out
  624.  * Accepts: MAIL stream
  625.  *        message number
  626.  *
  627.  * Calls external "mm_searched" function to notify main program
  628.  */
  629.  
  630. void mail_searched (stream,msgno)
  631.     MAILSTREAM *stream;
  632.     long msgno;
  633. {
  634.                 /* mark as searched */
  635.   mail_elt (stream,msgno)->searched = T;
  636.   mm_searched (stream,msgno);    /* notify main program */
  637. }
  638.  
  639.  
  640. /* Mail n messages exist
  641.  * Accepts: MAIL stream
  642.  *        number of messages
  643.  *
  644.  * Calls external "mm_exists" function that notifies main program prior
  645.  * to updating the stream
  646.  */
  647.  
  648. void mail_exists (stream,nmsgs)
  649.     MAILSTREAM *stream;
  650.     long nmsgs;
  651. {
  652.   mail_cache (stream,nmsgs);    /* make sure cache is large enough */
  653.                 /* notify main program of change */
  654.   if (!stream->silent) mm_exists (stream,nmsgs);
  655.   stream->nmsgs = nmsgs;    /* update stream status */
  656. }
  657.  
  658. /* Mail n messages are recent
  659.  * Accepts: MAIL stream
  660.  *        number of recent messages
  661.  */
  662.  
  663. void mail_recent (stream,recent)
  664.     MAILSTREAM *stream;
  665.     long recent;
  666. {
  667.   stream->recent = recent;    /* update stream status */
  668. }
  669.  
  670.  
  671. /* Mail message n is expunged
  672.  * Accepts: MAIL stream
  673.  *        message #
  674.  *
  675.  * Calls external "mm_expunged" function that notifies main program prior
  676.  * to updating the stream
  677.  */
  678.  
  679. void mail_expunged (stream,msgno)
  680.     MAILSTREAM *stream;
  681.     long msgno;
  682. {
  683.   long i = msgno - 1;
  684.   if (stream->cache[i]) {    /* if an element is there */
  685.     stream->cache[i]->msgno = 0;/* invalidate its message number */
  686.                 /* maybe free this message element */
  687.     mail_free_elt (&stream->cache[i]);
  688.   }
  689.                 /* slide down remainder of cache */
  690.   for (i = msgno; i < stream->nmsgs; ++i)
  691.     if (stream->cache[i-1] = stream->cache[i]) stream->cache[i-1]->msgno = i;
  692.   stream->cache[stream->nmsgs-1] = NIL;
  693.   --stream->nmsgs;        /* update stream status */
  694.                 /* notify main program of change */
  695.   if (!stream->silent) mm_expunged (stream,msgno);
  696. }
  697.  
  698. /* Mail stream status routines */
  699.  
  700.  
  701. /* Mail lock stream
  702.  * Accepts: Mail stream
  703.  */
  704.  
  705. void mail_lock (stream)
  706.     MAILSTREAM *stream;
  707. {
  708.   if (stream->lock) fatal ("Lock when already locked");
  709.   else stream->lock = T;    /* lock stream */
  710. }
  711.  
  712.  
  713. /* Mail unlock stream
  714.  * Accepts: Mail stream
  715.  */
  716.  
  717. void mail_unlock (stream)
  718.     MAILSTREAM *stream;
  719. {
  720.   if (!stream->lock) fatal ("Unlock when not locked");
  721.   else stream->lock = NIL;    /* unlock stream */
  722. }
  723.  
  724.  
  725. /* Mail turn on debugging telemetry
  726.  * Accepts: Mail stream
  727.  */
  728.  
  729. void mail_debug (stream)
  730.     MAILSTREAM *stream;
  731. {
  732.   stream->debug = T;        /* turn on debugging telemetry */
  733. }
  734.  
  735.  
  736. /* Mail turn off debugging telemetry
  737.  * Accepts: Mail stream
  738.  */
  739.  
  740. void mail_nodebug (stream)
  741.     MAILSTREAM *stream;
  742. {
  743.   stream->debug = NIL;        /* turn off debugging telemetry */
  744. }
  745.  
  746. /* Mail parse sequence
  747.  * Accepts: MAIL stream
  748.  *        sequence to parse
  749.  * Returns: T if parse successful, else NIL
  750.  */
  751.  
  752. long mail_sequence (stream,sequence)
  753.     MAILSTREAM *stream;
  754.     char *sequence;
  755. {
  756.   long i,j,x;
  757.   for (i = 1; i <= stream->nmsgs; i++) mail_elt (stream,i)->sequence = NIL;
  758.   while (*sequence) {        /* while there is something to parse */
  759.                 /* parse and validate message number */
  760.     if (((i = (int) strtol ((const char *) sequence,&sequence,10)) < 1) ||
  761.     (i > stream->nmsgs)) {
  762.       mm_log ("Sequence invalid",ERROR);
  763.       return NIL;
  764.     }
  765.     switch (*sequence) {    /* see what the delimiter is */
  766.     case ':':            /* sequence range */
  767.                 /* parse end of range */
  768.       if (((j = (int) strtol ((const char *) ++sequence,&sequence,10)) < 1) ||
  769.       (j > stream->nmsgs) || (*sequence && *sequence++ != ',')) {
  770.     mm_log ("Sequence range invalid",ERROR);
  771.     return NIL;
  772.       }
  773.       if (i > j) {        /* swap the range if backwards */
  774.     x = i; i = j; j = x;
  775.       }
  776.                 /* mark each item in the sequence */
  777.       while (i <= j) mail_elt (stream,j--)->sequence = T;
  778.       break;
  779.     case ',':            /* single message */
  780.       ++sequence;        /* skip the delimiter, fall into end case */
  781.     case '\0':            /* end of sequence, mark this message */
  782.       mail_elt (stream,i)->sequence = T;
  783.       break;
  784.     default:            /* anything else is a syntax error! */
  785.       mm_log ("Syntax error in sequence",ERROR);
  786.       return NIL;
  787.     }
  788.   }
  789.   return T;            /* successfully parsed sequence */
  790. }
  791.  
  792. /* Mail data structure instantiation routines */
  793.  
  794.  
  795. /* Mail instantiate envelope
  796.  * Returns: new envelope
  797.  */
  798.  
  799. ENVELOPE *mail_newenvelope ()
  800. {
  801.   ENVELOPE *env = (ENVELOPE *) fs_get (sizeof (ENVELOPE));
  802.   env->remail = NIL;        /* initialize all fields */
  803.   env->return_path = NIL;
  804.   env->date = NIL;
  805.   env->subject = NIL;
  806.   env->from = env->sender = env->reply_to = env->to = env->cc = env->bcc = NIL;
  807.   env->in_reply_to = env->message_id = env->newsgroups = NIL;
  808.   return env;
  809. }
  810.  
  811.  
  812. /* Mail instantiate address
  813.  * Returns: new address
  814.  */
  815.  
  816. ADDRESS *mail_newaddr ()
  817. {
  818.   ADDRESS *adr = (ADDRESS *) fs_get (sizeof (ADDRESS));
  819.                 /* initialize all fields */
  820.   adr->personal = adr->adl = adr->mailbox = adr->host = adr->error = NIL;
  821.   adr->next = NIL;
  822.   return adr;
  823. }
  824.  
  825.  
  826. /* Mail instantiate body
  827.  * Returns: new body
  828.  */
  829.  
  830. BODY *mail_newbody ()
  831. {
  832.   return mail_initbody ((BODY *) fs_get (sizeof (BODY)));
  833. }
  834.  
  835. /* Mail initialize body
  836.  * Accepts: body
  837.  * Returns: body
  838.  */
  839.  
  840. BODY *mail_initbody (body)
  841.     BODY *body;
  842. {
  843.   body->type = TYPETEXT;    /* content type */
  844.   body->encoding = ENC7BIT;    /* content encoding */
  845.   body->subtype = body->id = body->description = NIL;
  846.   body->parameter = NIL;
  847.   body->contents.text = NIL;    /* no contents yet */
  848.   body->contents.binary = NIL;
  849.   body->contents.part = NIL;
  850.   body->contents.msg.env = NIL;
  851.   body->contents.msg.body = NIL;
  852.   body->contents.msg.text = NIL;
  853.   body->size.lines = body->size.bytes = body->size.ibytes = 0;
  854.   return body;
  855. }
  856.  
  857.  
  858. /* Mail instantiate body parameter
  859.  * Returns: new body part
  860.  */
  861.  
  862. PARAMETER *mail_newbody_parameter ()
  863. {
  864.   PARAMETER *parameter = (PARAMETER *) fs_get (sizeof (PARAMETER));
  865.   parameter->attribute = parameter->value = NIL;
  866.   parameter->next = NIL;    /* no next yet */
  867.   return parameter;
  868. }
  869.  
  870.  
  871. /* Mail instantiate body part
  872.  * Returns: new body part
  873.  */
  874.  
  875. PART *mail_newbody_part ()
  876. {
  877.   PART *part = (PART *) fs_get (sizeof (PART));
  878.   mail_initbody (&part->body);    /* initialize the body */
  879.   part->offset = 0;        /* no offset yet */
  880.   part->next = NIL;        /* no next yet */
  881.   return part;
  882. }
  883.  
  884. /* Mail garbage collection routines */
  885.  
  886.  
  887. /* Mail garbage collect body
  888.  * Accepts: pointer to body pointer
  889.  */
  890.  
  891. void mail_free_body (body)
  892.     BODY **body;
  893. {
  894.   if (*body) {            /* only free if exists */
  895.     mail_free_body_data (*body);/* free its data */
  896.     fs_give ((void **) body);    /* return body to free storage */
  897.   }
  898. }
  899.  
  900.  
  901. /* Mail garbage collect body data
  902.  * Accepts: body pointer
  903.  */
  904.  
  905. void mail_free_body_data (body)
  906.     BODY *body;
  907. {
  908.   if (body->subtype) fs_give ((void **) &body->subtype);
  909.   mail_free_body_parameter (&body->parameter);
  910.   if (body->id) fs_give ((void **) &body->id);
  911.   if (body->description) fs_give ((void **) &body->description);
  912.   switch (body->type) {        /* free contents */
  913.   case TYPETEXT:        /* unformatted text */
  914.     if (body->contents.text) fs_give ((void **) &body->contents.text);
  915.     break;
  916.   case TYPEMULTIPART:        /* multiple part */
  917.     mail_free_body_part (&body->contents.part);
  918.     break;
  919.   case TYPEMESSAGE:        /* encapsulated message */
  920.     mail_free_envelope (&body->contents.msg.env);
  921.     mail_free_body (&body->contents.msg.body);
  922.     if (body->contents.msg.text)
  923.       fs_give ((void **) &body->contents.msg.text);
  924.     break;
  925.   case TYPEAPPLICATION:        /* application data */
  926.   case TYPEAUDIO:        /* audio */
  927.   case TYPEIMAGE:        /* static image */
  928.   case TYPEVIDEO:        /* video */
  929.     if (body->contents.binary) fs_give (&body->contents.binary);
  930.     break;
  931.   default:
  932.     break;
  933.   }
  934. }
  935.  
  936. /* Mail garbage collect body parameter
  937.  * Accepts: pointer to body parameter pointer
  938.  */
  939.  
  940. void mail_free_body_parameter (parameter)
  941.     PARAMETER **parameter;
  942. {
  943.   if (*parameter) {        /* only free if exists */
  944.     if ((*parameter)->attribute) fs_give ((void **) &(*parameter)->attribute);
  945.     if ((*parameter)->value) fs_give ((void **) &(*parameter)->value);
  946.                 /* run down the list as necessary */
  947.     mail_free_body_parameter (&(*parameter)->next);
  948.                 /* return body part to free storage */
  949.     fs_give ((void **) parameter);
  950.   }
  951. }
  952.  
  953.  
  954. /* Mail garbage collect body part
  955.  * Accepts: pointer to body part pointer
  956.  */
  957.  
  958. void mail_free_body_part (part)
  959.     PART **part;
  960. {
  961.   if (*part) {            /* only free if exists */
  962.     mail_free_body_data (&(*part)->body);
  963.                 /* run down the list as necessary */
  964.     mail_free_body_part (&(*part)->next);
  965.     fs_give ((void **) part);    /* return body part to free storage */
  966.   }
  967. }
  968.  
  969. /* Mail garbage collect message cache
  970.  * Accepts: pointer to message cache pointer
  971.  *
  972.  * The message cache is set to NIL when this function finishes.
  973.  */
  974.  
  975. void mail_free_cache (cache,size)
  976.     MESSAGECACHE ***cache;
  977.     unsigned long *size;
  978. {
  979.   unsigned long i;
  980.                 /* free each array element */
  981.   for (i = 0; i < *size; ++i) mail_free_elt (&(*cache)[i]);
  982.   fs_give ((void **) cache);    /* return cache to free storage */
  983.   *size = 0;            /* note that cache is empty */
  984. }
  985.  
  986.  
  987. /* Mail garbage collect cache element
  988.  * Accepts: pointer to cache element pointer
  989.  */
  990.  
  991. void mail_free_elt (elt)
  992.     MESSAGECACHE **elt;
  993. {
  994.                 /* only free if exists and no sharers */
  995.   if (*elt && !--(*elt)->lockcount) {
  996.     if ((*elt)->internal_date) fs_give ((void **) &(*elt)->internal_date);
  997.     mail_free_envelope (&(*elt)->env);
  998.     mail_free_body (&(*elt)->body);
  999.     fs_give ((void **) elt);    /* return cache element to free storage */
  1000.   }
  1001.   else *elt = NIL;        /* else simply drop pointer */
  1002. }
  1003.  
  1004. /* Mail garbage collect envelope
  1005.  * Accepts: pointer to envelope pointer
  1006.  */
  1007.  
  1008. void mail_free_envelope (env)
  1009.     ENVELOPE **env;
  1010. {
  1011.   if (*env) {            /* only free if exists */
  1012.     if ((*env)->remail) fs_give ((void **) &(*env)->remail);
  1013.     mail_free_address (&(*env)->return_path);
  1014.     if ((*env)->date) fs_give ((void **) &(*env)->date);
  1015.     mail_free_address (&(*env)->from);
  1016.     mail_free_address (&(*env)->sender);
  1017.     mail_free_address (&(*env)->reply_to);
  1018.     if ((*env)->subject) fs_give ((void **) &(*env)->subject);
  1019.     mail_free_address (&(*env)->to);
  1020.     mail_free_address (&(*env)->cc);
  1021.     mail_free_address (&(*env)->bcc);
  1022.     if ((*env)->in_reply_to) fs_give ((void **) &(*env)->in_reply_to);
  1023.     if ((*env)->message_id) fs_give ((void **) &(*env)->message_id);
  1024.     if ((*env)->newsgroups) fs_give ((void **) &(*env)->newsgroups);
  1025.     fs_give ((void **) env);    /* return envelope to free storage */
  1026.   }
  1027. }
  1028.  
  1029.  
  1030. /* Mail garbage collect address
  1031.  * Accepts: pointer to address pointer
  1032.  */
  1033.  
  1034. void mail_free_address (address)
  1035.     ADDRESS **address;
  1036. {
  1037.   if (*address) {        /* only free if exists */
  1038.     if ((*address)->personal) fs_give ((void **) &(*address)->personal);
  1039.     if ((*address)->adl) fs_give ((void **) &(*address)->adl);
  1040.     if ((*address)->mailbox) fs_give ((void **) &(*address)->mailbox);
  1041.     if ((*address)->host) fs_give ((void **) &(*address)->host);
  1042.     if ((*address)->error) fs_give ((void **) &(*address)->error);
  1043.     mail_free_address (&(*address)->next);
  1044.     fs_give ((void **) address);/* return address to free storage */
  1045.   }
  1046. }
  1047.