home *** CD-ROM | disk | FTP | other *** search
/ Netscape Plug-Ins Developer's Kit / Netscape_Plug-Ins_Developers_Kit.iso / SOFTWARE / lsoft / unix / common.tz / common / lsv_amin.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-01-15  |  21.1 KB  |  766 lines

  1. /******************************************************************************
  2.  *                                                                            *
  3.  * LISTSERV V2 - Standalone incoming mail interface (unix)                    *
  4.  *                                                                            *
  5.  *         Copyright L-Soft international 1994 - All rights reserved          *
  6.  *                                                                            *
  7.  * Syntax: add entries to /etc/aliases using either of the following forms    *
  8.  *                                                                            *
  9.  *         listserv: "|/.../lsv_amin spool_dir listserv"                      *
  10.  *         listserv: "|/.../lsv_amin -t listserv"                             *
  11.  *                                                                            *
  12.  * Where "..." represents the path to the executable (which should run with   *
  13.  * setuid listserv rather than root, for increased security), "spool_dir" is  *
  14.  * the absolute path to the LISTSERV spool directory, and the third parameter *
  15.  * is a copy of the userid the entry is for (the name before the colon). If   *
  16.  * no spool directory is specified, the default (defined in the Makefile and  *
  17.  * also in lsv_amin.h) will be used.                                          *
  18.  *                                                                            *
  19.  * You must define entries for the reserved addresses LISTSERV and            *
  20.  * owner-LISTSERV. In addition, for each list you must define entries for     *
  21.  * listname, owner-listname, listname-request and listname-server. Example:   *
  22.  *                                                                            *
  23.  *  listserv: "|/usr/listserv/lsv_amin -t listserv"                           *
  24.  *  owner-listserv: "|/usr/listserv/lsv_amin -t owner-listserv"               *
  25.  *                                                                            *
  26.  *  test-l: "|/usr/listserv/lsv_amin -t test-l"                               *
  27.  *  test-l-request: "|/usr/listserv/lsv_amin -t test-l-request"               *
  28.  *  test-l-server: "|/usr/listserv/lsv_amin -t test-l-server"                 *
  29.  *  owner-test-l: "|/usr/listserv/lsv_amin -t owner-test-l"                   *
  30.  *                                                                            *
  31.  *****************************************************************************/
  32.  
  33. #include <sys/types.h>
  34. #include <stdio.h>
  35. #include <string.h>
  36. #include <errno.h>
  37. #include <time.h>
  38. #include <sys/stat.h>
  39. #include <syslog.h>
  40. #include <signal.h>
  41.  
  42. typedef unsigned char LSV_char;
  43. #include "lsv_amin.h"
  44.  
  45. #define Err_Invalid 200
  46. #define Err_BadSyntax 201
  47. #define Err_SysCallFailed 202
  48. #define Err_NoFilename 203
  49.  
  50. #define P_SCAN 0
  51. #define P_DONE 1
  52. #define P_NEW 2
  53. #define P_ERR 3
  54. #define P_CONT 4
  55.  
  56. #define TIME_LEN 8
  57. #define TIME_CONV "%.8x"
  58. #define PROC_LEN 5
  59. #define PROC_CONV "%.6x"
  60. #define MAXTRIES 10
  61. #define JOB_EXT ".job"
  62. #define JOB_PRE "in"
  63. #define LISTSERV "LISTSERV"
  64. #define PROGNAME "lsv_amin"
  65. #define PROGVER "1.0b"
  66. #define REPORT_IND "X-REPORT-TYPE:"
  67.  
  68. #define SM1_Delim "----- Transcript of session follows -----"
  69. #define SM2_Delim "--- The transcript of the session follows ---"
  70. #define SM3_Delim "----- The following addresses had delivery problems -----"
  71. #define SM_Cont "..."
  72. #define SM_UOpen "(expanded from:"
  73. #define SM_UClose ")"
  74.  
  75. #define XRHeader \
  76. "X-Report-Type: Nondelivery; boundary=\"> Error description:\""
  77.  
  78. static LSV_char L_TA2E[] = {
  79.  /* 0 */ 0x00,0x01,0x02,0x03,0x37,0x2D,0x2E,0x2F,
  80.          0x16,0x05,0x25,0x0B,0x0C,0x0D,0x0E,0x0F,
  81.  /* 1 */ 0x10,0x11,0x12,0x13,0x3C,0x3D,0x32,0x26,
  82.          0x18,0x19,0x3F,0x27,0x1C,0x1D,0x1E,0x1F,
  83.  /* 2 */ 0x40,0x5A,0x7F,0x7B,0x5B,0x6C,0x50,0x7D,
  84.          0x4D,0x5D,0x5C,0x4E,0x6B,0x60,0x4B,0x61,
  85.  /* 3 */ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,
  86.          0xF8,0xF9,0x7A,0x5E,0x4C,0x7E,0x6E,0x6F,
  87.  /* 4 */ 0x7C,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,
  88.          0xC8,0xC9,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,
  89.  /* 5 */ 0xD7,0xD8,0xD9,0xE2,0xE3,0xE4,0xE5,0xE6,
  90.          0xE7,0xE8,0xE9,0xAD,0xE0,0xBD,0x5F,0x6D,
  91.  /* 6 */ 0x79,0x81,0x82,0x83,0x84,0x85,0x86,0x87,
  92.          0x88,0x89,0x91,0x92,0x93,0x94,0x95,0x96,
  93.  /* 7 */ 0x97,0x98,0x99,0xA2,0xA3,0xA4,0xA5,0xA6,
  94.          0xA7,0xA8,0xA9,0xC0,0x4F,0xD0,0xA1,0x07,
  95.  /* 8 */ 0x20,0x21,0x22,0x23,0x24,0x2A,0x06,0x17,
  96.          0x28,0x29,0x15,0x2B,0x2C,0x09,0x0A,0x1B,
  97.  /* 9 */ 0x30,0x31,0x1A,0x33,0x34,0x35,0x36,0x08,
  98.          0x38,0x39,0x3A,0x3B,0x04,0x14,0x3E,0xE1,
  99.  /* A */ 0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,
  100.          0x49,0x51,0x52,0x53,0x54,0x55,0x56,0x57,
  101.  /* B */ 0x58,0x59,0x62,0x63,0x64,0x65,0x66,0x67,
  102.          0x68,0x69,0x70,0x71,0x72,0x73,0x74,0x75,
  103.  /* C */ 0x76,0x77,0x78,0x80,0x8A,0x8B,0x8C,0x8D,
  104.          0x8E,0x8F,0x90,0x9A,0x9B,0x9C,0x9D,0x9E,
  105.  /* D */ 0x9F,0xA0,0xAA,0xAB,0xAC,0xBB,0xAE,0xAF,
  106.          0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,
  107.  /* E */ 0xB8,0xB9,0xBA,0x4A,0xBC,0xFC,0xBE,0xBF,
  108.          0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xDA,0xDB,
  109.  /* F */ 0xDC,0xDD,0xDE,0xDF,0xEA,0xEB,0xEC,0xED,
  110.          0xEE,0xEF,0xFA,0xFB,0x6A,0xFD,0xFE,0xFF
  111. };
  112.  
  113. char *LSV_ErrFields[] =
  114. { "--> Error description:",
  115.   "Error-For: ",
  116.   "Error-Code:",
  117.   "Error-Text:",
  118.   "Error-End: "
  119. };
  120.  
  121. struct err_entry {
  122.   int msg_num;
  123.   char *msg_text;
  124. };
  125.  
  126. struct err_entry err_repos[] =
  127. {  {  Err_Invalid,
  128.       "Program error.*"
  129.    },
  130.  
  131.    {  Err_BadSyntax,
  132. #ifdef MAIL_PP
  133.       "Syntax is, lsv_amin spool-directory to-user from-user"
  134. #else
  135.       "Syntax is, lsv_amin spool-directory to-user"
  136. #endif
  137.    },
  138.  
  139.    {  Err_SysCallFailed,
  140.       "An unknown system call failed.*"
  141.    },
  142.  
  143.    {  Err_NoFilename,
  144.       "The incoming mail directory is full."
  145.    }
  146. };
  147.  
  148. char *user = "", *routine_in_err = "";
  149. LSV_char buf[ 65537];
  150.  
  151. /* - STREXTR -
  152.  * String parser.
  153.  */
  154. int strextr( buff, pre, pos, skip, rsize, result, sc_end)
  155. char *buff, *pre, *pos, *skip, *result, **sc_end;
  156. int rsize;
  157.  
  158. { int rc = 0, off;
  159.   char *ch, *start, *wk;
  160.  
  161.   for( ch = buff; !rc && *ch; )  
  162.   { for( off = 0; *(pre + off) && *(pre + off) == *(ch + off); off++) ;
  163.     rc = !*(pre + off);
  164.     if( !rc) ch++;
  165.     else ch += off;
  166.   }
  167.   rc = *ch;
  168.  
  169.   if( rc && *skip)
  170.   { for( rc = 0; !rc && *ch; )
  171.     { for( rc = 1, wk = skip; rc && *wk; wk++)
  172.         rc = *wk != *ch;
  173.       if( !rc) ch++;
  174.     }
  175.     rc = *ch;
  176.   }
  177.   start = ch;
  178.  
  179.   if( rc)
  180.   { if( *pos)
  181.     { for( rc = 0; !rc && *ch; )
  182.       { for( off = 0; *(pos + off) && *(pos + off) == *(ch + off); off++) ;
  183.         rc = !*( pos + off);
  184.         if( !rc) ch++;
  185.       }
  186.       if( (rc = ch - start) > rsize - 1) rc = rsize - 1;
  187.       if( rc > 0) strncpy( result, start, rc);
  188.       if( rc >= 0) result[ rc] = '\0';
  189.       *sc_end = ch + off; 
  190.       if( *(pos + off)) rc = -rc;
  191.     }
  192.     else
  193.     { rc = strlen( start);
  194.       *sc_end = start + rc;
  195.       if( rc > rsize - 1) rc = rsize - 1;
  196.       if( rc > 0) strncpy( result, start, rc);
  197.       if( rc >= 0) result[ rc] = '\0';
  198.       rc = -rc;
  199.     }
  200.   }
  201.  
  202.   return rc;
  203. }
  204.  
  205. /* - ERR_LOOKUP -
  206.  * Translate mail delivery errors to LISTSERV error codes.
  207.  */
  208. int err_lookup( reason)
  209. char *reason;
  210. {
  211.   int rc = -1, wh = 0;
  212.   struct SM_Err_type *next, *last;
  213.  
  214.   last = (struct SM_Err_type *)((int) err_list + sizeof err_list);
  215.  
  216.   for( next = err_list; next < last && rc == -1; next++)
  217.     if( !strncmp( reason, next->err_msg, strlen( next->err_msg)))
  218.      rc = next->err_type;
  219.  
  220.   if( rc == -1) rc = err_list[ 0].err_type;
  221.  
  222.   return rc;  
  223. }
  224.  
  225. /* - PUTSTR_EBC -
  226.  * Convert '\0' terminated string of ASCII characters to EBCDIC and
  227.  * write them to a file.
  228.  */
  229. void putstr_EBC( st, file)
  230. LSV_char *st;
  231. FILE *file;
  232. {
  233.   LSV_char *ch;
  234.   int l;
  235.  
  236. #ifdef DBG_ASCII
  237.   fprintf( file, "%s\n", st);
  238.   fprintf( stdout, "%s\n", st);
  239. #else
  240.   l = strlen(st);
  241.   putc(l >> 8, file);
  242.   putc(l & 255, file);
  243.  
  244.   for( ch = st; *ch; ch++)
  245.     if( fputc( L_TA2E[ *ch], file) == EOF) syscall_failed( "fputc");
  246. #endif
  247.  
  248.   return;
  249. }
  250.  
  251. /* - HAS_LSVERR -
  252.  * Scan message text for existing LISTSERV style error indicators.
  253.  */
  254. int has_LSVErr( st)
  255. LSV_char *st;
  256. {
  257.   static LSV_char **mlevel = 0, **last = 0;
  258.  
  259.   if( !last) 
  260.   {
  261.     mlevel = (LSV_char **) LSV_ErrFields;
  262.     last = (LSV_char **) ((int) LSV_ErrFields + (sizeof LSV_ErrFields));
  263.     last--;
  264.   }
  265.  
  266.   if( *st && *st != '\n' && *st != ' ' && *st != '\t' && mlevel < last)
  267.   {
  268.     if( !strncmp( st, *mlevel, strlen( *mlevel))) mlevel++;
  269.     else mlevel = (LSV_char **) LSV_ErrFields;
  270.   }
  271.  
  272.   return mlevel >= last;  
  273. }
  274.  
  275. /* - PUTBLOCK_EBC -
  276.  * Scan a block of text for '\n' terminated lines, and write each out
  277.  * as a separate EBCDIC record.
  278.  */
  279. LSV_char *putblock_EBC( pool, out)
  280. LSV_char *pool;
  281. FILE *out;
  282. {
  283.   LSV_char *start, *EOR;
  284.  
  285.   for( start = pool, EOR = start; *EOR; )
  286.   {
  287.     for( ; *EOR && *EOR != '\n'; EOR++) ;
  288.     if( *EOR == '\n')
  289.     {
  290.       *EOR = '\0';
  291.       putstr_EBC( start, out);
  292.       *(EOR++) = '\n';
  293.       start = EOR;
  294.     }
  295.   }
  296.  
  297.   return start;
  298. }
  299.  
  300. /* - PARSE_SM_RESP -
  301.  * Check a line of text for Sendmail style delivery errors, then extract
  302.  * the reason for the error, and the failing address.
  303.  */
  304. void parse_SM_resp( pos, addr, asize, reason, rsize)
  305. LSV_char *pos, *addr, *reason;
  306. int asize, rsize;
  307. {
  308.   LSV_char *next, trash, *s_addr = &trash, *s_reason = &trash, test[ 200];
  309.   int l_addr = sizeof trash, l_reason = sizeof trash;
  310.   static int has_LSVErr = 0;
  311.  
  312.   if( !*addr)
  313.   {
  314.     s_addr = addr;
  315.     l_addr = asize;
  316.   } 
  317.   if( !*reason)
  318.   {
  319.     s_reason = reason;
  320.     l_reason = rsize;
  321.   } 
  322.  
  323.   if( strextr( pos, SM_UOpen, SM_UClose, " ", sizeof test, test, &next) > 0)
  324.     if( !strextr( test, "<", ">", " ", l_addr, s_addr, &next))
  325.       strncpy( s_addr, test, l_addr);
  326.  
  327.   strextr( pos, "", " ", " ", sizeof test, test, &next);
  328.   if( *test == '5' && strlen( test) == 3)
  329.   {
  330.     if( strextr( next, "<", ">", " ", l_addr, s_addr, &next))
  331.       strextr( next, "...", "\n", " \n\t", l_reason, s_reason, &next);
  332.     else
  333.     {
  334.       strextr( next, "", "...", " \t", l_addr, s_addr, &next);
  335.       strextr( next, "", "\n", " \n\t", l_reason, s_reason, &next);
  336.     }
  337.   }
  338.   if( !strcmp( test, "<<<"))
  339.   {
  340.     strextr( pos+4, "", " ", " ", sizeof test, test, &next);
  341.     if( *test == '5' && strlen( test) == 3)
  342.     {
  343.       if( strextr( next, "<", ">", " ", l_addr, s_addr, &next))
  344.         strextr( next, "...", "\n", " \n\t", l_reason, s_reason, &next);
  345.       else
  346.       {
  347.         strextr( next, "", "...", " \t", l_addr, s_addr, &next);
  348.         strextr( next, "", "\n", " \n\t", l_reason, s_reason, &next);
  349.       }
  350.     }
  351.     else if( !strcmp( test, "RCPT"))
  352.       strextr( pos, "<<<", "\n", " ", l_reason, s_reason, &next);
  353.   }
  354.   else (void) strextr( pos, "uux:", "\n", " \t", l_reason, s_reason, &next);
  355.  
  356.   if( *s_addr) for( next = s_addr + strlen( s_addr) - 1; 
  357.                     next >= s_addr && (*next == ' ' || *next == '\n');
  358.                     *(next--) = '\0') ;
  359.  
  360.   return;
  361. }
  362.  
  363. /* - SCAN_MSG -
  364.  * Scan mail intended for an owner-* type address for Sendmail errors and
  365.  * convert them to LISTSERV edible mail delivery indicators.
  366.  */
  367. void scan_msg( out)
  368. FILE *out;
  369. {
  370.   int in_hdr = 1, copy_asis = 0, psize, pfree, rl = 0, stat = P_SCAN, line;
  371.   LSV_char *pool, *ch, *pos, *start;
  372.   char *XReport, address[ 200], reason[ 200], *test, *AppendMSG;
  373.  
  374.   AppendMSG = (char *) malloc( sizeof ErrInsert);
  375.   strcpy( AppendMSG, ErrInsert);
  376.   XReport = (char *) malloc( sizeof REPORT_IND);
  377.   strcpy( XReport, REPORT_IND);
  378.   test = (char *) malloc( sizeof SM_Cont);
  379.   strcpy( test, SM_Cont);
  380.  
  381.   psize = MAX_BODY_BUFFER * 1024;
  382.   pool = (LSV_char *) malloc( psize);
  383.   if( !pool) syscall_failed( "malloc");
  384.   pfree = psize;
  385.   *address = '\0';
  386.   *reason = '\0';
  387.  
  388.   for(; in_hdr && !copy_asis && stat != P_DONE; )
  389.   {
  390.     if( !fgets( pool, psize, stdin))
  391.       stat = P_DONE;
  392.     else
  393.     {
  394.       for( pos= pool; *pos && (*pos == ' ' || *pos == '\n'); pos++) ;
  395.       if( !*pos) in_hdr = 0;
  396.       else
  397.       {
  398.         for( ch = (LSV_char *) XReport, pos = pool, copy_asis = 1;
  399.           copy_asis && *ch && *pos; )
  400.           if( *(ch++) != toupper( *(pos++))) copy_asis = 0;
  401.         (void) putblock_EBC( pool, out);
  402.       }
  403.     }
  404.   }
  405.  
  406.   if( stat == P_DONE) rl = -1;
  407.   else if( copy_asis) putstr_EBC( "\n", out);
  408.   else
  409.   {
  410.     pos = pool;
  411.     for( line= 0; line <= MAX_BODY_LINES && stat != P_DONE && stat != P_ERR; 
  412.       line++)
  413.     {
  414.       if( !fgets( pos, pfree, stdin)) 
  415.       {
  416.         rl = -1;
  417.         if( stat == P_CONT) (void) parse_SM_resp( start, address,
  418.           sizeof address, reason, sizeof reason);
  419.         stat = P_DONE;
  420.       }
  421.       else rl = strlen( pos);
  422.  
  423.       if( has_LSVErr( pos))
  424.       {
  425.         putstr_EBC( XRHeader, out);
  426.         *reason = '\0';
  427.         *address = '\0';
  428.         stat = P_DONE;
  429.       }
  430.       else if( stat == P_SCAN)
  431.       {
  432.         for(; *pos != '\0' && *pos != '\n' && (*pos == ' ' || *pos == '\t'); 
  433.           pos++) ;
  434.         if( !strncmp( pos, SM1_Delim, (sizeof SM1_Delim) - 1) ||
  435.           !strncmp( pos, SM2_Delim, (sizeof SM2_Delim) - 1) ||
  436.           !strncmp( pos, SM3_Delim, (sizeof SM3_Delim) - 1)) stat = P_NEW;
  437.       }
  438.       else if( stat == P_NEW)
  439.       {
  440.         stat = P_CONT;
  441.         start = pos;
  442.       }
  443.       else if( stat == P_CONT)
  444.       {
  445.         *test = '\0';
  446.         (void) strextr( pos, "", " ", " \t", sizeof test, test, &ch);
  447.         if( strcmp( SM_Cont, test))
  448.         {
  449.           *test = *pos;
  450.           *pos = '\0';
  451.           (void) parse_SM_resp( start, address, sizeof address, reason,
  452.             sizeof reason);
  453.           *pos = *test;
  454.           if( *reason && *address) stat = P_DONE;
  455.           else start = pos;
  456.         }
  457.       }
  458.  
  459.       if( rl >= 0)
  460.       {
  461.         pos += strlen( pos);
  462.         pfree -= rl;
  463.         if( pfree <= 1 && *(pos - 1) != '\n')
  464.         {
  465.           syslog( LOG_ERR, "**Warning** Buffer exhausted, consider \
  466. increasing MAX_BODY_BUFFER");
  467.           fprintf( stderr, "**Warning** Buffer exhausted, consider \
  468. increasing MAX_BODY_BUFFER.\n");
  469.           *reason = '\0';
  470.           *address = '\0';
  471.           stat = P_ERR;
  472.           pos = putblock_EBC( pool, out);
  473.           if( pos)
  474.           {
  475.  /* Try to salvage the partial line in the buffer without splitting it. */
  476.             strncpy( buf, pos, sizeof buf);
  477.             pos = buf + strlen( buf);
  478.             fgets( pos, (sizeof buf) - strlen( buf), stdin);
  479.             putstr_EBC( buf, out);
  480.             *pool = '\0';
  481.           }
  482.         }
  483.       } 
  484.  
  485.       if( *reason && *address)
  486.       {
  487.         putstr_EBC( XRHeader, out); 
  488.         (void) putblock_EBC( AppendMSG, out);
  489.         sprintf( buf, "%s\n%s %s\n%s %d\n%s %s\n\n%s %s\n", LSV_ErrFields[ 0],
  490.           LSV_ErrFields[ 1], address, LSV_ErrFields[ 2], err_lookup( reason), 
  491.           LSV_ErrFields[ 3], reason, LSV_ErrFields[ 4], "One error reported.");
  492.         (void) putblock_EBC( buf, out);
  493.       }
  494.     }
  495.  
  496.     if( stat != P_ERR) putstr_EBC( "\n", out);
  497.     if( *pool) (void) putblock_EBC( pool, out);
  498.   }
  499.  
  500.   if( rl >= 0) for(; fgets( pool, psize, stdin); ) 
  501.     putblock_EBC( pool, out);
  502.  
  503.   return;
  504. }
  505.  
  506. /* - FILE_EXISTS -
  507.  * Return 1/0 indicating whether or not the indicated file exists.
  508.  */
  509. int file_exists( path)
  510. char *path;
  511. {
  512.   struct stat stat_buff;
  513.  
  514.   return( !lstat( path, &stat_buff));
  515. }
  516.  
  517. /* - SYSCALL_FAILED -
  518.  * Save the name of the system call that bombed and log the error.
  519.  */
  520. syscall_failed( which)
  521. char *which;
  522. {
  523.   routine_in_err = which;
  524.   err_exit( Err_SysCallFailed);
  525.  
  526.   exit( Err_SysCallFailed);  /* Shouldn't get here! */
  527. }
  528.  
  529. /* - ERR_EXIT -
  530.  * Construct an appropriate error message and log it to stderr and syslog.
  531.  */
  532. err_exit( rc)
  533. int rc;
  534. {
  535.   int last_entry, wh = 0;
  536.   char *msg = "";
  537.  
  538.   if( *user != '\0')
  539.   {
  540.     syslog( LOG_ERR, "Unable to deliver mail to: %s", user);
  541.     fprintf( stderr, "lsv_amin: Unable to deliver mail to: %s\n", user);
  542.   }
  543.  
  544.   if( rc == Err_SysCallFailed)
  545.   {
  546.     msg = (char *)malloc( 80);
  547.     if( *routine_in_err == '\0') msg = "An unknown system call failed.*";
  548.     else sprintf( msg, "A call to %s() failed.*", routine_in_err);
  549.   }
  550.   else
  551.   {
  552.     last_entry = (int)err_repos + sizeof( err_repos);
  553.  
  554.     for( ; (int)&err_repos[ wh] < last_entry && *msg == '\0'; wh++)
  555.       if( rc == err_repos[ wh].msg_num) msg = err_repos[ wh].msg_text;
  556.  
  557.     if( *msg == '\0') msg = err_repos[ 0].msg_text;
  558.   }
  559.  
  560.   if( msg[ strlen( msg) - 1] == '*')
  561.   {
  562.     msg[ strlen( msg) - 1] = '\0';
  563.     syslog( LOG_ERR, "**Error(%d)** %s", errno, msg);
  564.     fprintf( stderr, "lsv_amin: **Error(%d)** %s\n", errno, msg);
  565.   }
  566.   else
  567.   {
  568.     syslog( LOG_ERR, "**Error** %s", msg);
  569.     fprintf( stderr, "lsv_amin: **Error** %s\n", msg);
  570.   }
  571.  
  572.   closelog();
  573.   exit( rc);
  574. }
  575.  
  576. /* - LSV_AMIN -
  577.  */
  578. main( narg, args)
  579. int narg;
  580. char **args;
  581. {
  582.   long staging, proc;
  583.   int ii, ntry, plen, ch, xam, xown;
  584.   char *conv, *fsuffix, *final, *workfile, *fprefix, *w, *r, Fromline[1024],
  585.     *fromid = "", uid[256], *spool_dir = "", **which, *def_spool, *callname;
  586.   time_t now;
  587.   FILE *out = 0, *pidfile;
  588.  
  589.   fsuffix = (char *) malloc( sizeof JOB_EXT);
  590.   strcpy( fsuffix, JOB_EXT);
  591.   fprefix = (char *) malloc( sizeof JOB_PRE);
  592.   strcpy( fprefix, JOB_PRE);
  593.   def_spool = (char *) malloc( sizeof SPOOL_DIR);
  594.   strcpy( def_spool, SPOOL_DIR);
  595.  
  596.   openlog( "LSV:lsv_amin", LOG_PID, LOG_FACILITY);
  597.  
  598.   callname = args[ 0];
  599.   for( w = callname; *w; w++) if( *w == '/') callname = w + 1;
  600.   if( strcmp( callname, PROGNAME)) user = callname;
  601.  
  602.   if( narg > 1)
  603.   {
  604.     if( !strcmp( args[ 1], "-v"))
  605.     {
  606.       fprintf( stdout, "%s release %s\n", PROGNAME, PROGVER);
  607.       exit( 0);
  608.     }
  609.  
  610.     if( *args[ 1] == '-') which = 0;
  611.     else which = &spool_dir;
  612.   }
  613.  
  614.   for( ii= 1; ii < narg; ii++)
  615.   {
  616.     w = args[ ii];
  617.     if( which) 
  618.     {
  619.       *which = w;
  620.       which = 0;
  621.     }
  622. #ifdef MAIL_PP
  623.     else if( !strcmp( w, "-f")) which = &fromid;
  624. #endif
  625.     else if( !strcmp( w, "-s")) which = &spool_dir;
  626.     else if( !strcmp( w, "-t")) which = &user;
  627.     else
  628.     {
  629.       if( *spool_dir == '\0') spool_dir = w;
  630.       else if( *user == '\0') user = w;
  631. #ifdef MAIL_PP
  632.       else if( *fromid == '\0') fromid = w;
  633. #endif
  634.       else (void) err_exit( Err_BadSyntax);
  635.       which = 0;
  636.     }
  637.   }
  638.  
  639.   if( !*spool_dir) spool_dir = def_spool;
  640. #ifdef MAIL_PP
  641.   if( !*fromid || !*user) (void) err_exit( Err_BadSyntax);
  642. #else
  643.   if( !*user) (void) err_exit( Err_BadSyntax);
  644. #endif
  645.  
  646. #ifdef DBG_ASCII
  647.   fprintf( stdout, "To<%s> Sp<%s>\n", user, spool_dir);
  648. #endif
  649.  
  650.   for (r = user, w = uid; *r; *w++ = toupper(*r), r++);
  651.   *w = '\0';
  652.  
  653.   workfile = (char *)malloc( strlen( spool_dir) + TIME_LEN + PROC_LEN +
  654.     strlen( fprefix) + 3);
  655.   final = (char *)malloc( strlen( spool_dir) + TIME_LEN + PROC_LEN +
  656.     strlen( fsuffix) + 3);
  657.   conv = (char *)malloc( (sizeof staging) * 2 + 1);
  658.  
  659.   strcpy( final, spool_dir);
  660.   if( final[ (ii = strlen( final)) - 1] != '/')
  661.   {
  662.     final[ ii] = '/';
  663.     final[ ii + 1] = '\0';
  664.   }
  665.   plen = strlen( final);
  666.  
  667.   for( ntry = 1; ntry <= MAXTRIES && !out; ntry++)
  668.   {
  669.     final[ plen] = '\0';
  670.     strcat( final, fprefix);
  671.  
  672.     time( &now);
  673.     sprintf( conv, TIME_CONV, (staging = now));
  674.     strcat( final, (conv + strlen( conv)) - TIME_LEN);
  675.  
  676.     sprintf( conv, PROC_CONV, getpid());
  677.     strcat( final, (conv + strlen( conv)) - (PROC_LEN + 1));
  678.     final[ strlen( final) - (PROC_LEN + 1)] = '-';
  679.  
  680.     strcpy( workfile, final);
  681.     strcat( final, fsuffix);
  682.  
  683.     if( !file_exists( workfile) && !file_exists( final))
  684.     {
  685.       if( !(out = fopen( workfile, "w"))) syscall_failed( "fopen");
  686.     }
  687.     else sleep( 1);
  688.   }
  689.  
  690.   if( out)
  691.   {
  692.     if( fwrite("*LSV-V*", 7, 1, out) <= 0) syscall_failed( "fwrite");
  693.     for( w = user; *w; *w++ = tolower( *w)) ;
  694.  
  695.     /* See if it is an administrative (owner-xxx/xxx-request) message */
  696.     xown = !strncmp(user, "owner-", 6);
  697.     xam = xown || !strncmp(w - 8, "-request", 8) ||
  698.       !strncmp(w - 7, "-server", 7);
  699.     /* Format and write the header */
  700.     sprintf(buf, "1 M %s %s *MAILER* INCOMING MAIL",
  701.                  uid,
  702.                  (xam || !strcmp(uid, LISTSERV)) ? "STANDARD" :
  703.                                                    "$NOJOB$");
  704.  
  705.     ii = strlen(buf);
  706. #ifndef DBG_ASCII
  707.     putc(ii >> 8, out);
  708.     putc(ii & 255, out);
  709.     fwrite(buf, ii, 1, out);
  710.     putc(0, out);
  711.     putc(0, out);
  712. #else
  713.     fwrite(buf, ii, 1, out);
  714.     fputc( '\n', out);
  715.     fputc( '\n', stdout);
  716. #endif
  717.  
  718.     /* For administrative messages, generate X-ADMMAIL JCL */
  719. #ifndef MAIL_PP
  720.     fgets(Fromline, sizeof(Fromline), stdin);
  721. #endif
  722.     if (xam) {
  723.     putstr_EBC("// JOB Echo=No", out);
  724. #ifndef MAIL_PP
  725.     for (fromid = Fromline; *fromid && *fromid++ != ' ';);
  726. #endif
  727.     for (w = fromid; *w && *w != ' ' && *w != '\n'; w++);
  728.     *w = '\0';
  729.         if( *fromid == '<' && fromid[ strlen( fromid) - 1] == '>')
  730.         {
  731.           fromid[ strlen( fromid) - 1] = '\0';
  732.           fromid++;
  733.         }
  734.     sprintf(buf, "X-ADMMAIL %s %s", user, fromid);
  735.     putstr_EBC(buf, out);
  736.     putstr_EBC("//DATA DD *,EOF", out);
  737.     }
  738.  
  739.     /* If this is going to an owner-* type address, try to convert the
  740.      * mail delivery error to something LISTSERV can act on.
  741.      */
  742.     if( xown) scan_msg( out);
  743.     else for (; fgets(buf, sizeof(buf), stdin);) {
  744.         buf[strlen(buf) - 1] = '\0';
  745.         putstr_EBC(buf, out);
  746.           }
  747.  
  748.     if( fclose( out)) syscall_failed( "fclose");
  749.     if( link( workfile, final)) syscall_failed( "link");
  750.     if( unlink( workfile)) syscall_failed( "unlink");
  751.  
  752.     syslog( LOG_INFO, "Mail for %s (from %d/%d) delivered to LISTSERV.",
  753.       user, getuid(), geteuid());
  754.  
  755.     sprintf(buf, "%s/listserv.PID", spool_dir);
  756.     if (pidfile = fopen(buf, "r")) {
  757.         fscanf(pidfile, "%lu\n", &proc);
  758.         kill(proc, SIGUSR1);
  759.         fclose(pidfile);
  760.     }
  761.   }
  762.   else err_exit( Err_NoFilename);
  763.  
  764.   exit( 0);
  765. }
  766.