home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / system / mail / delivery / deliver.tz / deliver / dest.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-07  |  6.0 KB  |  302 lines

  1. /* $Header: dest.c,v 2.5 90/03/06 12:21:10 chip Exp $
  2.  *
  3.  * Operations on the list of mail destinations.
  4.  *
  5.  * $Log:    dest.c,v $
  6.  * Revision 2.5  90/03/06  12:21:10  chip
  7.  * Move logging into log.c and address parsing into addr.c.
  8.  * New: error delivery file for messages that fail.
  9.  * Major rearrangement of delivery file code.
  10.  * 
  11.  * Revision 2.4  90/02/23  16:35:53  chip
  12.  * \Fix problems determining legality of user references.
  13.  * 
  14.  * Revision 2.3  90/02/23  14:16:42  chip
  15.  * Support "#!" in delivery files.
  16.  * Support "user|program" and "user?error" from delivery files.
  17.  * Improve debugging and error message formatting.
  18.  * Rearrange code for clarity.
  19.  * 
  20.  * Revision 2.2  89/09/29  18:17:57  network
  21.  * Save message when delivery file produces no output,
  22.  * unless delivery file output the "DROP" string.
  23.  * Don't recopy temp files for sys and post-user delfiles.
  24.  * 
  25.  * Revision 2.1  89/06/09  12:25:22  network
  26.  * Update RCS revisions.
  27.  * 
  28.  * Revision 1.5  89/06/09  12:23:45  network
  29.  * Baseline for 2.0 release.
  30.  * 
  31.  */
  32.  
  33. #include "deliver.h"
  34.  
  35. /*
  36.  * Local data.
  37.  */
  38.  
  39. static  DEST    deadhead = { &deadhead, &deadhead };
  40. #define HEADPTR    (&deadhead)
  41.  
  42. /*
  43.  * Local functions.
  44.  */
  45.  
  46. static    int    destcmp();
  47. static    int    ptrcmp();
  48.  
  49. /*----------------------------------------------------------------------
  50.  * Consider mail to the given user as undeliverable.
  51.  */
  52.  
  53. dest_undel(name)
  54. char    *name;
  55. {
  56.     (void) dest(name, CL_MBOX, MBX_UNDEL);
  57. }
  58.  
  59. /*----------------------------------------------------------------------
  60.  * Add a new destination to the list (unless it already exists).
  61.  * Return pointer to DEST.
  62.  */
  63.  
  64. DEST *
  65. dest(name, class, s)
  66. char    *name;
  67. DCLASS    class;
  68. char    *s;
  69. {
  70.     DEST    *d;
  71.  
  72.     /* Make sure that parameter is provided when it's needed. */
  73.  
  74.     if ((class == CL_MBOX || class == CL_PROG) != (s != NULL))
  75.         return NULL;
  76.  
  77.     /* Look for an already-existing copy of the given destination. */
  78.  
  79.     for (d = HEADPTR->d_next; d != HEADPTR; d = d->d_next)
  80.     {
  81.         if (d->d_class != class)
  82.             continue;
  83.  
  84.         if (strcmp(d->d_name, name) != 0)
  85.             continue;
  86.  
  87.         if (s && strcmp(d->d_param, s) != 0)
  88.             continue;
  89.  
  90.         /*
  91.          * Like, gnarly, dude!  It's already in the chain!
  92.          */
  93.  
  94.         return d;
  95.     }
  96.  
  97.     /*
  98.      * The given dest isn't in the list, so we have to add it.
  99.      */
  100.  
  101.     d = (DEST *) zalloc(sizeof(DEST));
  102.     d->d_class = class;
  103.     d->d_state = ST_WORKING;
  104.     d->d_name = copystr(name);
  105.     d->d_param = s ? copystr(s) : NULL;
  106.  
  107.     /*
  108.      * Check address for validity.
  109.      */
  110.  
  111.     if (!addr_clean(name))
  112.         dest_err(d, E_IVADDR);
  113.     else if (class != CL_UUCP && name_context(name) == NULL)
  114.         dest_err(d, E_NSUSER);
  115.  
  116.     /*
  117.      * Put new address at the end of of the chain.
  118.      * (This is important!  Other code depends on it.)
  119.      */
  120.  
  121.     d->d_prev = HEADPTR->d_prev;
  122.     d->d_next = HEADPTR;
  123.     d->d_prev->d_next = d;
  124.     d->d_next->d_prev = d;
  125.  
  126.     return d;
  127. }
  128.  
  129. /*----------------------------------------------------------------------
  130.  * Return pointer to first DEST in the list.
  131.  */
  132.  
  133. DEST *
  134. first_dest()
  135. {
  136.     if (HEADPTR->d_next != HEADPTR)
  137.         return HEADPTR->d_next;
  138.  
  139.     return NULL;
  140. }
  141.  
  142. /*----------------------------------------------------------------------
  143.  * Return pointer to next DEST in the list, or NULL.
  144.  */
  145.  
  146. DEST *
  147. next_dest(d)
  148. DEST    *d;
  149. {
  150.     if (d && (d = d->d_next) != HEADPTR)
  151.         return d;
  152.  
  153.     return NULL;
  154. }
  155.  
  156. /*----------------------------------------------------------------------
  157.  * Return the number of destinations in the list.
  158.  */
  159.  
  160. int
  161. dest_count()
  162. {
  163.     DEST    *d;
  164.     int    count;
  165.  
  166.     count = 0;
  167.     for (d = HEADPTR->d_next; d && d != HEADPTR; d = d->d_next)
  168.         ++count;
  169.  
  170.     return count;
  171. }
  172.  
  173. /*----------------------------------------------------------------------
  174.  * Return an allocated array of DEST pointers, or NULL if none.
  175.  * The given integer is set to the array size.
  176.  * Note that the caller must FREE this array when he's done.
  177.  */
  178.  
  179. DEST **
  180. dest_array(countp)
  181. int    *countp;
  182. {
  183.     DEST    **dv, *d;
  184.     int    i, count;
  185.  
  186.     if ((count = dest_count()) <= 0)
  187.     {
  188.         *countp = 0;
  189.         return NULL;
  190.     }
  191.  
  192.     dv = (DEST **) zalloc(count * sizeof(DEST *));
  193.  
  194.     i = 0;
  195.     for (d = HEADPTR->d_next; d && d != HEADPTR; d = d->d_next)
  196.     {
  197.         if (i < count)
  198.             dv[i++] = d;
  199.     }
  200.  
  201.     qsort((char *)dv, count, sizeof(dv[0]), destcmp);
  202.  
  203.     *countp = count;
  204.     return dv;
  205. }
  206.  
  207. /*----------------------------------------------------------------------
  208.  * Compare two DEST pointers, for output sorting.
  209.  */
  210.  
  211. static int
  212. destcmp(p1, p2)
  213. char    *p1, *p2;
  214. {
  215.     DEST    *d1, *d2;
  216.     int    cmp;
  217.  
  218.     d1 = *(DEST **)p1;
  219.     d2 = *(DEST **)p2;
  220.  
  221. #if 0
  222.     /* Errors go last. */
  223.     if ((d1->d_state == ST_ERROR) != (d2->d_state == ST_ERROR))
  224.         return (d1->d_state == ST_ERROR) ? 1 : -1;
  225. #endif
  226.  
  227. #if 0
  228.     /* By class. */
  229.     if ((cmp = (int)d1->d_class - (int)d2->d_class) != 0)
  230.         return (cmp < 0) ? -1 : 1;
  231. #endif
  232.  
  233.     /* By user name. */
  234.     if ((cmp = ptrcmp(d1->d_name, d2->d_name)) != 0)
  235.         return cmp;
  236.  
  237.     /* By mailbox/program. */
  238.     if ((cmp = ptrcmp(d1->d_param, d2->d_param)) != 0)
  239.         return cmp;
  240.  
  241.     return 0;
  242. }
  243.  
  244. /*----------------------------------------------------------------------
  245.  * Compare two pointers, either of which may be NULL.
  246.  */
  247.  
  248. static int
  249. ptrcmp(p, q)
  250. char    *p, *q;
  251. {
  252.     if (p == q)
  253.         return 0;
  254.     if (p == NULL)
  255.         return -1;
  256.     if (q == NULL)
  257.         return 1;
  258.     return strcmp(p, q);
  259. }
  260.  
  261. /*----------------------------------------------------------------------
  262.  * Return a destination's error message.
  263.  */
  264.  
  265. char *
  266. derrmsg(d)
  267. DEST    *d;
  268. {
  269.     static  char    unknown_buf[40];
  270.     static  char    no_error[] = "no error?!";
  271.  
  272.     if (!d || d->d_state != ST_ERROR)
  273.         return no_error;
  274.  
  275.     switch (d->d_error)
  276.     {
  277.     case E_IVADDR:
  278.         return "Invalid address string";
  279.     case E_NSUSER:
  280.         return "No such user";
  281.     case E_NSHOST:
  282.         return "No such UUCP host";
  283.     case E_CTPERM:
  284.         return "No permissions for that context";
  285.     case E_CTLOST:
  286.         return "Context lost (should never happen)";
  287.     case E_MBOX:
  288.         return "Can't write to mailbox";
  289.     case E_PROG:
  290.         return "Subprocess reported failure when exiting";
  291.     case E_PIPE:
  292.         return "Subprocess died while reading its standard input";
  293.     case E_DFONLY:
  294.         return "Address not valid from command line";
  295.     case E_ERRMSG:
  296.         return d->d_errmsg ? d->d_errmsg : no_error;
  297.     }
  298.  
  299.     (void) sprintf(unknown_buf, "Unknown error %d", d->d_error);
  300.     return unknown_buf;
  301. }
  302.