home *** CD-ROM | disk | FTP | other *** search
/ Super Net 1 / SUPERNET_1.iso / PC / OTROS / EXTRAS / UUCODE / UUPC / TEST / UPC12ES3.ZIP / UUCP / uuxqt.c < prev   
Encoding:
C/C++ Source or Header  |  1993-11-13  |  58.2 KB  |  1,729 lines

  1. /*
  2.       Program:    uuxqt.c              23 September 1991
  3.       Author:     Mitch Mitchell
  4.       Email:      mitch@harlie.lonestar.org
  5.  
  6.       This is a re-write of the (much cleaner) UUXQT.C originally
  7.       distributed with UUPC/Extended.  The modifications were
  8.       intended primarily to lay a foundation for support for the
  9.       more advanced features of UUX.
  10.  
  11.       Richard H. Gumpertz (RHG@CPS.COM) built upon that foundation
  12.       and added most of the code necessary for implementing UUXQT
  13.       correctly, but there may still be many minor problems.
  14.  
  15.       Usage:      uuxqt -xDEBUG -sSYSTEM
  16. */
  17.  
  18. /*--------------------------------------------------------------------*/
  19. /*       Changes Copyright (c) 1989-1993 by Kendra Electronic         */
  20. /*       Wonderworks.                                                 */
  21. /*                                                                    */
  22. /*       All rights reserved except those explicitly granted by       */
  23. /*       the UUPC/extended license agreement.                         */
  24. /*--------------------------------------------------------------------*/
  25.  
  26. /*--------------------------------------------------------------------*/
  27. /*                          RCS Information                           */
  28. /*--------------------------------------------------------------------*/
  29.  
  30. /*
  31.  *    $Id: uuxqt.c 1.27 1993/11/13 17:43:26 ahd Exp $
  32.  *
  33.  *    Revision history:
  34.  *    $Log: uuxqt.c $
  35.  * Revision 1.27  1993/11/13  17:43:26  ahd
  36.  * Update command line limit of RMAIL for 32 bit operating systems
  37.  *
  38.  * Revision 1.26  1993/11/06  13:04:13  ahd
  39.  * Don't use more than 8 characters in XQT directory name
  40.  *
  41.  * Revision 1.25  1993/10/31  19:04:03  ahd
  42.  * Use special name for NUL under Windows NT
  43.  *
  44.  * Revision 1.24  1993/10/30  17:23:37  ahd
  45.  * Drop extra tzset() call
  46.  *
  47.  * Revision 1.23  1993/10/30  17:19:50  rhg
  48.  * Additional clean up for UUX support
  49.  *
  50.  * Revision 1.22  1993/10/24  21:51:14  ahd
  51.  * Drop unmigrated changes
  52.  *
  53.  * Revision 1.21  1993/10/24  19:42:48  rhg
  54.  * Generalized support for UUX'ed commands
  55.  *
  56.  * Revision 1.20  1993/10/24  12:48:56  ahd
  57.  * Trap RNEWS bad return code
  58.  *
  59.  * Revision 1.19  1993/10/12  01:34:47  ahd
  60.  * Normalize comments to PL/I style
  61.  *
  62.  * Revision 1.18  1993/10/03  22:10:24  ahd
  63.  * Use signed for length of parameters
  64.  *
  65.  * Revision 1.17  1993/10/03  20:43:08  ahd
  66.  * Normalize comments to C++ double slash
  67.  *
  68.  * Revision 1.16  1993/09/29  23:29:56  ahd
  69.  * Add xqtrootdir for UUXQT
  70.  *
  71.  * Revision 1.15  1993/09/20  04:48:25  ahd
  72.  * TCP/IP support from Dave Watt
  73.  * 't' protocol support
  74.  * OS/2 2.x support (BC++ 1.0 for OS/2)
  75.  *
  76.  * Revision 1.14  1993/08/03  03:35:58  ahd
  77.  * Correct path pointer to initialized variable
  78.  *
  79.  * Revision 1.13  1993/08/03  03:11:49  ahd
  80.  * Initialize buffer for shell() in non-Windows environment
  81.  *
  82.  * Revision 1.12  1993/07/31  16:27:49  ahd
  83.  * Changes in support of Robert Denny's Windows support
  84.  *
  85.  * Revision 1.11  1993/07/24  03:40:55  ahd
  86.  * Agressively trap carriage returns at ends of lines (from X.* files
  87.  * being edited by elves with DOS editors!)
  88.  *
  89.  * Revision 1.10  1993/07/20  21:45:37  ahd
  90.  * Don't delete file after -2 abort from UUXQT
  91.  *
  92.  * Revision 1.9  1993/06/26  16:01:48  ahd
  93.  * Normalize white space used to parse strings
  94.  *
  95.  * Revision 1.8  1993/06/13  14:06:00  ahd
  96.  * Correct off-by-one error in RMAIL arg parse loop which crashed UUXQT
  97.  * on long system names
  98.  *
  99.  * Revision 1.7  1993/04/11  00:35:46  ahd
  100.  * Global edits for year, TEXT, etc.
  101.  *
  102.  * Revision 1.6  1993/04/05  04:35:40  ahd
  103.  * Use timestamp/file size information returned by directory search
  104.  *
  105.  * Revision 1.5  1992/11/25  12:59:17  ahd
  106.  * Change NUL to /dev/nul to prevent ImportPath() mangling.
  107.  *
  108.  * Revision 1.4  1992/11/23  03:56:06  ahd
  109.  * Selected fixes for use of generlized uux commands
  110.  *
  111.  * Revision 1.3  1992/11/19  03:03:33  ahd
  112.  * drop rcsid
  113.  */
  114.  
  115. /*--------------------------------------------------------------------*/
  116. /*                        System include files                        */
  117. /*--------------------------------------------------------------------*/
  118.  
  119. #include <stdio.h>
  120. #include <stdlib.h>
  121. #include <string.h>
  122. #include <ctype.h>
  123. #include <errno.h>
  124. #include <time.h>
  125. #include <fcntl.h>
  126. #include <process.h>
  127. #include <sys/types.h>
  128. #include <sys/stat.h>
  129. #include <io.h>
  130.  
  131. #ifdef _Windows
  132. #include <windows.h>
  133. #endif
  134.  
  135. /*--------------------------------------------------------------------*/
  136. /*                    UUPC/extended include files                     */
  137. /*--------------------------------------------------------------------*/
  138.  
  139. #include "lib.h"
  140. #include "arpadate.h"
  141. #include "dater.h"
  142. #include "expath.h"
  143. #include "getopt.h"
  144. #include "getseq.h"
  145. #include "hlib.h"
  146. #include "hostable.h"
  147. #include "import.h"
  148. #include "lock.h"
  149. #include "logger.h"
  150. #include "pushpop.h"
  151. #include "readnext.h"
  152. #include "security.h"
  153. #include "timestmp.h"
  154. #include "usertabl.h"
  155. #include "execute.h"
  156.  
  157. #ifdef _Windows
  158. #include "winutil.h"
  159. #endif
  160.  
  161. currentfile();
  162.  
  163. /*--------------------------------------------------------------------*/
  164. /*                      Execution flag defines                        */
  165. /*--------------------------------------------------------------------*/
  166.  
  167. typedef enum {
  168.         X_OUTPUT,     /* 'O' return output to "outnode"       */
  169.         X_FAILED,     /* 'Z' send status if command failed    */
  170.         X_SUCCESS,    /* 'n' send status if command succeeded */
  171.         X_INPUT,      /* 'B' return command input on error    */
  172.         X_USEEXEC,    /* 'E' process command using exec(2)    */
  173.         X_STATFIL,    /* 'M' return status to file on remote  */
  174.  
  175.         S_CORRUPT,
  176.         S_NOREAD,
  177.         S_NOWRITE,
  178.  
  179.         F_CORRUPT,
  180.         F_NOCHDIR,
  181.         F_NOCOPY,
  182.         F_BADF,
  183.  
  184.         E_NORMAL,
  185.         E_NOACC,
  186.         E_SIGNAL,
  187.         E_STATUS,
  188.         E_NOEXE,
  189.         E_FAILED,
  190.  
  191.         UU_LAST
  192.  
  193.         } UU_FLAGS;
  194.  
  195. /*--------------------------------------------------------------------*/
  196. /*                          Global Variables                          */
  197. /*--------------------------------------------------------------------*/
  198.  
  199. static char *spool_fmt = SPOOLFMT;
  200. static char *dataf_fmt = DATAFFMT;
  201.  
  202. /*--------------------------------------------------------------------*/
  203. /*                        Internal prototypes                         */
  204. /*--------------------------------------------------------------------*/
  205.  
  206. static void usage( void );
  207.  
  208. static boolean copylocal(const char *from, const char *to);
  209.  
  210. static boolean do_uuxqt( const char *sysname );
  211.  
  212. static void process( const char *fname,
  213.                      const char *remote,
  214.                      const char *executeDirectory);
  215.  
  216. char **create_environment(const char *logname,
  217.                           const char *requestor);
  218.  
  219. static void delete_environment( char **envp);
  220.  
  221. static boolean AppendData( const char *input, FILE* dataout);
  222.  
  223. static boolean do_copy( char *localfile,
  224.                        const char *rmtsystem,
  225.                        const char *remotefile,
  226.                        const char *requestor,
  227.                        const boolean success );
  228.  
  229. static void ReportResults(const int   status,
  230.                           const char *input,
  231.                                 char *output,
  232.                           const char *command,
  233.                           const char *job_id,
  234.                           const time_t jtime,
  235.                           const char *requestor,
  236.                           const char *outnode,
  237.                           const char *outname,
  238.                           const boolean xflag[],
  239.                           const char *statfil,
  240.                           const char *machine,
  241.                           const char *user);
  242.  
  243. static int shell(char *command,
  244.                  const char *inname,
  245.                  const char *outname,
  246.                  const char *remotename,
  247.                  boolean xflag[]);
  248.  
  249. static boolean MailStatus(char *tempfile,
  250.                           char *address,
  251.                           char *subject);
  252.  
  253. /*--------------------------------------------------------------------*/
  254. /*    m a i n                                                         */
  255. /*                                                                    */
  256. /*    Main program                                                    */
  257. /*--------------------------------------------------------------------*/
  258.  
  259. void main( int argc, char **argv)
  260. {
  261.    int c;
  262.    extern char *optarg;
  263.    extern int   optind;
  264.    char *sysname = "all";
  265.  
  266. /*--------------------------------------------------------------------*/
  267. /*     Report our version number and date/time compiled               */
  268. /*--------------------------------------------------------------------*/
  269.  
  270.    debuglevel = 1;
  271.    banner( argv );
  272.  
  273. #if defined(__CORE__)
  274.    copywrong = strdup(copyright);
  275.    checkref(copywrong);
  276. #endif
  277.  
  278. /*--------------------------------------------------------------------*/
  279. /*        Process our arguments                                       */
  280. /*--------------------------------------------------------------------*/
  281.  
  282.    while ((c = getopt(argc, argv, "s:x:")) !=  EOF)
  283.       switch(c) {
  284.  
  285.       case 's':
  286.          sysname = optarg;
  287.          break;
  288.  
  289.       case 'x':
  290.          debuglevel = atoi( optarg );
  291.          break;
  292.  
  293.       case '?':
  294.          usage();
  295.          exit(1);
  296.          break;
  297.  
  298.       default:
  299.          printmsg(0, "uuxqt - invalid option -%c", c);
  300.          usage();
  301.          exit(2);
  302.          break;
  303.       }
  304.  
  305.    if (optind != argc) {
  306.       fputs("Extra parameter(s) at end.\n", stderr);
  307.       usage();
  308.       exit(2);
  309.    }
  310.  
  311. /*--------------------------------------------------------------------*/
  312. /*                             Initialize                             */
  313. /*--------------------------------------------------------------------*/
  314.  
  315.    if (!configure( B_UUXQT ))
  316.       exit(1);   /* system configuration failed */
  317.  
  318. /*--------------------------------------------------------------------*/
  319. /*                  Switch to the spooling directory                  */
  320. /*--------------------------------------------------------------------*/
  321.  
  322.    PushDir( E_spooldir );
  323.    atexit( PopDir );
  324.  
  325. /*--------------------------------------------------------------------*/
  326. /*                     Initialize logging file                        */
  327. /*--------------------------------------------------------------------*/
  328.  
  329.    openlog( NULL );
  330.  
  331.    checkuser( E_mailbox  );   /* Force User Table to initialize        */
  332.    checkreal( E_mailserv );   /* Force Host Table to initialize        */
  333.  
  334.    if (!LoadSecurity())
  335.    {
  336.       printmsg(0,"Unable to initialize security, see previous message");
  337.       exit(2);
  338.    } /* if (!LoadSecurity()) */
  339.  
  340. #if defined(_Windows)
  341.    atexit( CloseEasyWin );               /* Auto-close EasyWin on exit  */
  342. #endif
  343.  
  344. /*--------------------------------------------------------------------*/
  345. /*                Set up search path for our programs                 */
  346. /*--------------------------------------------------------------------*/
  347.  
  348.    if ( E_uuxqtpath != NULL )
  349.    {
  350.       char buf[BUFSIZ];
  351.       char *p;
  352.       sprintf(buf,"PATH=%s", E_uuxqtpath);
  353.       p = newstr(buf);
  354.  
  355.       if (putenv( p ))
  356.       {
  357.          printmsg(0,"Unable to set path \"%s\"", p);
  358.          panic();
  359.       } /* if (putenv( p )) */
  360.  
  361.    } /* if ( E_uuxqtpath != NULL ) */
  362.  
  363. /*--------------------------------------------------------------------*/
  364. /*              Disable OS/2 undelete support if desired              */
  365. /*--------------------------------------------------------------------*/
  366.  
  367.    if ( !bflag[ F_UNDELETE ] )
  368.       putenv( "DELDIR=");
  369.  
  370. /*--------------------------------------------------------------------*/
  371. /*    Actually invoke the processing routine for the eXecute files    */
  372. /*--------------------------------------------------------------------*/
  373.  
  374.    do_uuxqt( sysname );
  375.    if( equal( sysname , "all" ) )
  376.        do_uuxqt( E_nodename );
  377.  
  378.    exit(0);
  379.  
  380. } /* main */
  381.  
  382. /*--------------------------------------------------------------------*/
  383. /*    d o _ u u x q t                                                 */
  384. /*                                                                    */
  385. /*    Processing incoming eXecute (X.*) files for a remote system     */
  386. /*--------------------------------------------------------------------*/
  387.  
  388. static boolean do_uuxqt( const char *sysname )
  389. {
  390.    struct HostTable *hostp;
  391.    static char uu_machine[] = UU_MACHINE "=";
  392.    char hostenv[sizeof uu_machine + 25 + 2];
  393.    char executeDirectory[FILENAME_MAX];
  394.    char *pattern;
  395.  
  396. /*--------------------------------------------------------------------*/
  397. /*                 Determine if we have a valid host                  */
  398. /*--------------------------------------------------------------------*/
  399.  
  400.    if( !equal( sysname , "all" ) ) {
  401.       if (equal( sysname , E_nodename ))
  402.           hostp = checkname( sysname );
  403.       else
  404.           hostp = checkreal( sysname );
  405.  
  406.       if (hostp  ==  BADHOST) {
  407.          printmsg(0, "Unknown host \"%s\".", sysname );
  408.          exit(1);
  409.       }
  410.  
  411.    } else
  412.         hostp = nexthost( TRUE );
  413.  
  414. /*--------------------------------------------------------------------*/
  415. /*                Define mask for execution directory                 */
  416. /*--------------------------------------------------------------------*/
  417.  
  418.    if (( E_xqtRootDir == NULL ) || equali( E_xqtRootDir, E_spooldir ))
  419.       sprintf( executeDirectory, "%s/%%.8s/XQT", E_spooldir );
  420.                                  /* Nice parallel construction        */
  421.    else
  422.       sprintf( executeDirectory, "%s/XQT/%%.8s", E_xqtRootDir);
  423.                                  /* Fewer directories than if we      */
  424.                                  /* use the spool version              */
  425.  
  426.    pattern = newstr( executeDirectory );  /* Save pattern for posterity  */
  427.  
  428. /*--------------------------------------------------------------------*/
  429. /*             Outer loop for processing different hosts              */
  430. /*--------------------------------------------------------------------*/
  431.  
  432.    while  (hostp != BADHOST)
  433.    {
  434.       char fname[FILENAME_MAX];
  435.       boolean locked = FALSE;
  436.  
  437. /*--------------------------------------------------------------------*/
  438. /*                Initialize security for this remote                 */
  439. /*--------------------------------------------------------------------*/
  440.  
  441.       if ( !equal(sysname, E_nodename) &&
  442.            (securep = GetSecurity( hostp )) == NULL )
  443.          printmsg(0,"No security defined for \"%s\","
  444.                   " cannot process X.* files",
  445.                   hostp->hostname );
  446.       else {
  447.  
  448. /*--------------------------------------------------------------------*/
  449. /*              Set up environment for the machine name               */
  450. /*--------------------------------------------------------------------*/
  451.  
  452.          sprintf(hostenv,"%s%.25s", uu_machine, hostp->hostname);
  453.  
  454.          if (putenv( hostenv ))
  455.          {
  456.             printmsg(0,"Unable to set environment \"%s\"",hostenv);
  457.             panic();
  458.          }
  459.  
  460.          sprintf(executeDirectory , pattern, hostp->hostname );
  461.          printmsg(5,"Execute directory is %s", executeDirectory );
  462.  
  463. /*--------------------------------------------------------------------*/
  464. /*           Inner loop for processing files from one host            */
  465. /*--------------------------------------------------------------------*/
  466.  
  467.          while (readnext(fname, hostp->hostname, "X", NULL, NULL, NULL) )
  468.          {
  469.             if ( locked || LockSystem( hostp->hostname , B_UUXQT ))
  470.             {
  471.                process( fname , hostp->hostname, executeDirectory );
  472.                locked = TRUE;
  473.             }
  474.             else
  475.                break;               /* We didn't get the lock         */
  476.  
  477.          } /* while */
  478.  
  479.          if ( locked )
  480.             UnlockSystem();
  481.  
  482.       } /* else if */
  483.  
  484. /*--------------------------------------------------------------------*/
  485. /*                        Restore environment                         */
  486. /*--------------------------------------------------------------------*/
  487.  
  488.       putenv( uu_machine );   /* Reset to empty string                 */
  489.  
  490. /*--------------------------------------------------------------------*/
  491. /*    If processing all hosts, step to the next host in the queue     */
  492. /*--------------------------------------------------------------------*/
  493.  
  494.       if( equal(sysname,"all") )
  495.          hostp = nexthost( FALSE );
  496.       else
  497.          hostp = BADHOST;
  498.  
  499.    } /*while nexthost*/
  500.  
  501.    return FALSE;
  502.  
  503. } /* do_uuxqt */
  504.  
  505. /*--------------------------------------------------------------------*/
  506. /*    p r o c e s s                                                   */
  507. /*                                                                    */
  508. /*    Process a single execute file                                   */
  509. /*--------------------------------------------------------------------*/
  510.  
  511. static void process( const char *fname,
  512.                      const char *remote,
  513.                      const char *executeDirectory)
  514. {
  515.    char *command = NULL,
  516.         *input = NULL,
  517.         *output = NULL,
  518.         *job_id = NULL,
  519.         line[BUFSIZ];
  520.    char hostfile[FILENAME_MAX];
  521.    boolean skip = FALSE;
  522.    boolean reject = FALSE;
  523.    FILE *fxqt;
  524.    int status = 0;      /* initialized ONLY to suppress compiler warning */
  525.  
  526.    char *outnode = NULL;
  527.    char *outname = NULL;
  528.    char *user = NULL;
  529.    char *requestor = NULL;
  530.    char *statfil = NULL;
  531.    char *machine = NULL;
  532.  
  533.    struct F_list {
  534.       struct F_list *next;
  535.       char *spoolname;
  536.       char *xqtname;
  537.    } *F_list = NULL;
  538.  
  539.    boolean xflag[UU_LAST - 1] = { 0 };
  540.    time_t jtime = time(NULL);
  541.  
  542. /*--------------------------------------------------------------------*/
  543. /*                         Open the X.* file                          */
  544. /*--------------------------------------------------------------------*/
  545.  
  546.    if ( (fxqt = FOPEN(fname, "r", BINARY_MODE)) == NULL)
  547.    {
  548.       printerr(fname);
  549.       return;
  550.    }
  551.    else
  552.       printmsg(2, "processing %s", fname);
  553.  
  554. /*--------------------------------------------------------------------*/
  555. /*                  Begin loop to read the X.* file                   */
  556. /*--------------------------------------------------------------------*/
  557.  
  558.    while (!skip & (fgets(line, BUFSIZ, fxqt) != NULL))
  559.    {
  560.       char *cp;
  561.  
  562.       if ( (cp = strchr(line, '\n')) != NULL )
  563.          *cp = '\0';
  564.  
  565.       printmsg(5, "Input read: %s", line);
  566.  
  567. /*--------------------------------------------------------------------*/
  568. /*            Process the input line according to its type            */
  569. /*--------------------------------------------------------------------*/
  570.  
  571.       switch (*line)
  572.       {
  573.  
  574.       case '#':
  575.          break;
  576.  
  577. /*--------------------------------------------------------------------*/
  578. /*                  User which submitted the command                  */
  579. /*--------------------------------------------------------------------*/
  580.  
  581.       case 'U':
  582.          if ( (cp = strtok(line + 1, WHITESPACE)) == NULL )
  583.          {
  584.             printmsg(0,"No user on U line in file \"%s\"", fname );
  585.             reject = xflag[F_CORRUPT] = TRUE;
  586.             break;
  587.          }
  588.  
  589.          user = strdup(cp);
  590.          checkref(user);
  591.                                     /* Get the system name            */
  592.          if ( (cp = strtok(NULL, WHITESPACE)) == NULL)
  593.          {                          /* Did we get a string?           */
  594.             printmsg(2,"No node on U line in file \"%s\"", fname );
  595.             cp = (char *) remote;
  596.          }
  597.          else if (!equal(cp,remote))
  598.          {
  599.             printmsg(2,"Node on U line in file \"%s\" doesn't match remote",
  600.                      fname );
  601.             cp = (char * ) remote;
  602.          };
  603.          machine = newstr(cp);
  604.  
  605.          break;
  606.  
  607. /*--------------------------------------------------------------------*/
  608. /*                       Input file for command                       */
  609. /*--------------------------------------------------------------------*/
  610.  
  611.       case 'I':
  612.          cp = strtok(line + 1, WHITESPACE );
  613.          if ( cp == NULL )
  614.          {
  615.             printmsg(0,"No input file name on I line");
  616.             reject = xflag[F_CORRUPT] = TRUE;
  617.             break;
  618.          }
  619.  
  620.          if (equaln(cp,"D.",2)
  621.              && (strchr(cp, '/') == NULL)
  622.              && (strchr(cp, '\\') == NULL))
  623.          {
  624.             char temp[FILENAME_MAX];
  625.  
  626.             importpath(temp, cp, remote);
  627.             mkfilename(hostfile, E_spooldir, temp);
  628.          }
  629.          else
  630.          {
  631.             strcpy(hostfile, cp);
  632.             expand_path(hostfile, E_pubdir/*??*/, E_pubdir, NULL);
  633.  
  634.             if (!equal(remote, E_nodename))
  635.             /* Should the preceding "if (...)" be deleted?  --RHG */
  636.                if (!ValidateFile( hostfile, ALLOW_READ))
  637.                {
  638.                   reject = xflag[S_NOREAD] = TRUE;
  639.                   break;
  640.                }
  641.          }
  642.  
  643.          input = strdup(hostfile);
  644.          checkref(input);
  645.  
  646.          break;
  647.  
  648. /*--------------------------------------------------------------------*/
  649. /*                      Output file for command                       */
  650. /*--------------------------------------------------------------------*/
  651.  
  652.       case 'O':
  653.          cp = strtok(line + 1, WHITESPACE);
  654.          if ( cp == NULL )
  655.          {
  656.             printmsg(0,"No output file name on O line");
  657.             reject = xflag[F_CORRUPT] = TRUE;
  658.             break;
  659.          }
  660.  
  661.          strcpy(hostfile, cp);
  662.  
  663.          cp = strtok(NULL, WHITESPACE);
  664.          if ( cp != NULL && !equal(cp, E_nodename) )
  665.          {                /* Did we get a string indicating ANOTHER host? */
  666.             outnode = strdup(cp);
  667.             checkref(outnode);
  668.             checkreal(outnode);
  669.          }
  670.          else
  671.          {
  672.             expand_path(hostfile, E_pubdir/*??*/, E_pubdir, NULL);
  673.  
  674.             if (!equal(remote, E_nodename))
  675.             /* Should the preceding "if (...)" be deleted?  --RHG */
  676.                if (ValidateFile( hostfile, ALLOW_WRITE))
  677.                /* Taylor/GNU uuxqt also rejects it if the output would be in
  678.                   E_spooldir (to keep people from setting up phony requests).
  679.                   I am not sure whether we want to do likewise.  --RHG */
  680.                {
  681.                   reject = xflag[S_NOWRITE] = TRUE;
  682.                   break;
  683.                }
  684.          }
  685.  
  686.          outname = strdup(hostfile);
  687.          checkref(outname);
  688.          xflag[X_OUTPUT] = TRUE;  /* return output to "outnode"   */
  689.  
  690.          break;
  691.  
  692. /*--------------------------------------------------------------------*/
  693. /*                         Command to execute                         */
  694. /*--------------------------------------------------------------------*/
  695.  
  696.       case 'C':
  697.          cp = line + 1 + strspn(line + 1, WHITESPACE);
  698.          if ( *cp == '\0' )
  699.          {
  700.             printmsg(0,"No command name on C line");
  701.             reject = xflag[F_CORRUPT] = TRUE;
  702.             break;
  703.          }
  704.          command = strdup( cp );
  705.          checkref(command);
  706.  
  707.          break;
  708.  
  709. /*--------------------------------------------------------------------*/
  710. /*                      Job Id for status reporting                   */
  711. /*--------------------------------------------------------------------*/
  712.  
  713.       case 'J':
  714.          if ( (cp = strtok(line + 1, WHITESPACE)) == NULL )
  715.          {
  716.             printmsg(0,"No job id on J line in file \"%s\"", fname );
  717.             reject = xflag[F_CORRUPT] = TRUE;
  718.             break;
  719.          }
  720.  
  721.          job_id = strdup( cp );
  722.          checkref( job_id );
  723.  
  724.          break;
  725.  
  726. /*--------------------------------------------------------------------*/
  727. /*                 Check that a required file exists                  */
  728. /*--------------------------------------------------------------------*/
  729.  
  730.       case 'F':
  731.          cp = strtok(line + 1, WHITESPACE);
  732.          if (cp == NULL)
  733.          {
  734.             printmsg(0,"Missing F parameter in file \"%s\", command rejected",
  735.                        fname);
  736.             reject = xflag[F_CORRUPT] = TRUE;
  737.             break;
  738.          }
  739.  
  740.          if (equaln(cp,"D.",2)
  741.              && (strchr(cp,'/') == NULL)
  742.              && (strchr(cp,'\\') == NULL))
  743.          {
  744.             char temp[FILENAME_MAX];
  745.             struct F_list *p;
  746.  
  747.             importpath(temp, cp, remote);
  748.             mkfilename(hostfile, E_spooldir, temp);
  749.  
  750.             if ( access( hostfile, 0 ))   /* Does the host file exist?   */
  751.             {                             /* No --> Skip the file        */
  752.                printmsg(0,"Missing file %s (%s) for %s, command skipped",
  753.                         cp, hostfile, fname);
  754.                skip = TRUE;
  755.                break;
  756.             }
  757.  
  758.             p = malloc(sizeof *F_list);
  759.             checkref(p);
  760.             p->next = F_list;
  761.             F_list = p;
  762.  
  763.             F_list->spoolname = strdup(hostfile);
  764.             checkref(F_list->spoolname);
  765.  
  766.             F_list->xqtname = NULL;
  767.          }
  768.          else
  769.          {
  770.             printmsg(0,"Invalid F parameter in file \"%s\", command rejected",
  771.                        fname);
  772.             reject = xflag[F_BADF] = TRUE;
  773.             break;
  774.          }
  775.  
  776.          cp = strtok(NULL, WHITESPACE);
  777.          if (cp != NULL)
  778.          {
  779.             if (!ValidDOSName(cp, FALSE))
  780.             {  /* Illegal filename --> reject the whole request */
  781.                printmsg(0,"Illegal filename \"%s\" in file \"%s\", command rejected",
  782.                           cp, fname);
  783.                reject = xflag[F_BADF] = TRUE;
  784.                break;
  785.             }
  786.             else
  787.             {
  788.                mkfilename(hostfile, executeDirectory, cp);
  789.                F_list->xqtname = strdup(hostfile);
  790.                checkref(F_list->xqtname);
  791.             }
  792.          }
  793.  
  794.          break;
  795.  
  796. /*--------------------------------------------------------------------*/
  797. /*             Requestor name (overrides user name, above)            */
  798. /*--------------------------------------------------------------------*/
  799.  
  800.       case 'R':
  801.          if ( (cp = strtok(line + 1, WHITESPACE)) == NULL )
  802.          {
  803.             printmsg(0,"No requestor on R line in file \"%s\"", fname );
  804.             reject = xflag[F_CORRUPT] = TRUE;
  805.             break;
  806.          }
  807.  
  808.          requestor = strdup(cp);
  809.          checkref(requestor);
  810.  
  811.          break;
  812.  
  813. /*--------------------------------------------------------------------*/
  814. /*        Status file name to return info to on remote node           */
  815. /*--------------------------------------------------------------------*/
  816.  
  817.       case 'M':
  818.          if ( (cp = strtok(line + 1, WHITESPACE)) == NULL )
  819.          {
  820.             printmsg(0,"No file name on M line in file \"%s\"", fname);
  821.             break;
  822.          }
  823.  
  824.          statfil = strdup(cp);
  825.          checkref(statfil);
  826.          xflag[X_STATFIL] = TRUE;    /* return status to remote file  */
  827.  
  828.          break;
  829.  
  830. /*--------------------------------------------------------------------*/
  831. /*                            Flag fields                             */
  832. /*--------------------------------------------------------------------*/
  833.  
  834.       case 'Z': xflag[X_FAILED] = TRUE;   /* send status if command failed  */
  835.          break;
  836.  
  837.       case 'N': xflag[X_FAILED] = FALSE;  /* send NO status if command failed */
  838.          break;
  839.  
  840.       case 'n': xflag[X_SUCCESS] = TRUE;  /* send status if command succeeded */
  841.          break;
  842.  
  843.       case 'z': xflag[X_SUCCESS] = FALSE; /* NO status if command succeeded */
  844.          break;
  845.  
  846.       case 'B': xflag[X_INPUT] = TRUE;    /* return command input on error  */
  847.          break;
  848.  
  849.       case 'e': xflag[X_USEEXEC] = FALSE; /* process command using sh(1)    */
  850.          break;
  851.  
  852.       case 'E': xflag[X_USEEXEC] = TRUE;  /* process command using exec(2)  */
  853.          break;
  854.  
  855. /*--------------------------------------------------------------------*/
  856. /*                    Quietly ignore unknown fields                   */
  857. /*--------------------------------------------------------------------*/
  858.  
  859.       default :
  860.          break;
  861.  
  862.       } /* switch */
  863.    } /* while (!skip & (fgets(line, BUFSIZ, fxqt) != NULL)) */
  864.  
  865.    if ( fxqt != NULL )
  866.       fclose(fxqt);
  867.  
  868.  
  869.    if ((command == NULL) && !skip)
  870.    {
  871.       printmsg(0,"No command supplied for X.* file %s, rejected", fname);
  872.       reject = xflag[F_CORRUPT] = TRUE;
  873.    }
  874.  
  875. /*--------------------------------------------------------------------*/
  876. /*           We have the data for this command; process it            */
  877. /*--------------------------------------------------------------------*/
  878.  
  879.    if ( !skip )
  880.    {
  881.       if ( !reject )
  882.       {
  883.          if ( user == NULL )
  884.          {
  885.             user = strdup("uucp"); /* User if none given              */
  886.             checkref(user);
  887.          }
  888.  
  889.          if (requestor == NULL)
  890.          {
  891.             requestor = strdup(user);
  892.             checkref(requestor);
  893.          }
  894.  
  895.          if (input == NULL)
  896.          {
  897. #ifdef WIN32
  898.             input = strdup("NUL:");
  899. #else
  900.             input = strdup("/dev/nul"); /* NOTE: DOS uses only one L in NUL */
  901. #endif
  902.          }
  903.  
  904.          output = mktempname(NULL, "OUT");
  905.  
  906.          printmsg(equaln(command,RMAIL,5) ? 2 : 0,
  907.                   "uuxqt: executing \"%s\" for user \"%s\" at  \"%s\"",
  908.                       command, user, machine);
  909.  
  910. /*--------------------------------------------------------------------*/
  911. /*           Copy the input files to the execution directory          */
  912. /*--------------------------------------------------------------------*/
  913.  
  914.          /* Make sure the directory exists before we copy the files */
  915.          PushDir(executeDirectory);
  916.  
  917.          {
  918.             struct F_list *p;
  919.  
  920.             for (p = F_list; p != NULL; p = p->next)
  921.             {
  922.                if (p->xqtname != NULL)
  923.                   if (!copylocal(p->spoolname, p->xqtname))
  924.                   {
  925.                      /* Should we try again later in case its a temporary
  926.                         error like execute directory on a full disk?  For
  927.                         now, just reject it completely. */
  928.                      printmsg(0, "Copy \"%s\" to \"%s\" failed",
  929.                                  p->spoolname, p->xqtname);
  930.                      reject = xflag[F_NOCOPY] = TRUE;
  931.                      break;
  932.                   }
  933.             } /* for ( ;; ) */
  934.         }
  935.  
  936. /*--------------------------------------------------------------------*/
  937. /*            Create the environment and run the command(s)           */
  938. /*--------------------------------------------------------------------*/
  939.  
  940.          if (!reject)
  941.          {
  942.             char *pipe;
  943.             char **envp = create_environment("uucp", requestor);
  944.             char *cmd = strdup(command);        /* shell clobbers its arg */
  945.             checkref(cmd);
  946.  
  947.             /* The following code INTENTIONALLY ignores quoting of '|'
  948.                (with \ or "..." or '...') because we can't count on the DOS
  949.                shell (or spawnlp, etc.) to also handle quoting of '|' the
  950.                exact same way (or even at all).  We also prohibit '<' and '>'
  951.                for similar reasons.  (By the way, uux should have changed
  952.                I/O redirecting '<' and '>' to I and O lines, respectively.) */
  953.  
  954.             if (strchr(cmd, '<') != NULL || strchr(cmd, '>') != NULL)
  955.             {
  956.                printmsg(0,"The characters \'<\' and \'>\' are not supported in remote commands");
  957.                reject = xflag[F_CORRUPT] = TRUE;
  958.             }
  959.             else if ((pipe = strchr(cmd, '|')) == NULL) /* Any pipes? */
  960.                status = shell(cmd, input, output, remote, xflag); /* No */
  961.             else
  962.             { /* We currently do pipes by simulating them using files */
  963.                char *pipefile = mktempname(NULL, "PIP");
  964.                char *next_cmd = cmd; /* initialized ONLY to suppress compiler warning */
  965.  
  966.                *pipe = '\0';
  967.                status = shell(cmd, input, pipefile, remote, xflag);
  968.                /* *pipe = '|'; */
  969.  
  970.                while (status == 0
  971.                       && (pipe = strchr(next_cmd = pipe + 1, '|')) != NULL)
  972.                {
  973.                   /* Swap the output and pipe files for the next pass */
  974.                   char *p = pipefile; pipefile = output; output = p;
  975.  
  976.                   xflag[E_NORMAL] = FALSE;
  977.                   *pipe = '\0';
  978.                   status = shell(next_cmd, output, pipefile, remote, xflag);
  979.                   /* *pipe = '|'; */
  980.                }
  981.  
  982.                if (status == 0)
  983.                {
  984.                   xflag[E_NORMAL] = FALSE;
  985.                   status = shell(next_cmd, pipefile, output, remote, xflag);
  986.                }
  987.  
  988.                unlink(pipefile);
  989.                free(pipefile);
  990.             }
  991.  
  992.             free(cmd);
  993.             delete_environment(envp);
  994.          }
  995.  
  996. /*--------------------------------------------------------------------*/
  997. /*                  Clean up files after the command                  */
  998. /*--------------------------------------------------------------------*/
  999.  
  1000.          PopDir();
  1001.  
  1002.          {
  1003.             struct F_list *p;
  1004.  
  1005.             for (p = F_list; p != NULL; p = p->next)
  1006.                if (p->xqtname != NULL)
  1007.                   unlink(p->xqtname);
  1008.          }
  1009.  
  1010.       } /* if (!reject) */
  1011.  
  1012.       {
  1013.          struct F_list *p;
  1014.  
  1015.          for (p = F_list; p != NULL; p = p->next)
  1016.             unlink(p->spoolname);
  1017.       }
  1018.  
  1019.       ReportResults( status, input, output, command, job_id,
  1020.                      jtime, requestor, outnode, outname, xflag,
  1021.                      statfil, machine, user);
  1022.  
  1023.       if (!reject)
  1024.          unlink(output);
  1025.  
  1026.       unlink(fname);
  1027.  
  1028.    } /* (!skip) */
  1029.  
  1030. /*--------------------------------------------------------------------*/
  1031. /*              Free various temporary character strings              */
  1032. /*--------------------------------------------------------------------*/
  1033.  
  1034.    while (F_list != NULL)
  1035.    {
  1036.       struct F_list *next;
  1037.  
  1038.       free(F_list->spoolname);
  1039.       if (F_list->xqtname != NULL)
  1040.          free(F_list->xqtname);
  1041.  
  1042.       next = F_list->next;
  1043.       free(F_list);
  1044.       F_list = next;
  1045.    }
  1046.  
  1047.    if (command    != NULL) free(command);
  1048.    if (input      != NULL) free(input);
  1049.    if (job_id     != NULL) free(job_id);
  1050.    if (outnode    != NULL) free(outnode);
  1051.    if (output     != NULL) free(output);
  1052.    if (requestor  != NULL) free(requestor);
  1053.    if (statfil    != NULL) free(statfil);
  1054.    if (user       != NULL) free(user);
  1055.  
  1056. } /* process */
  1057.  
  1058. /*--------------------------------------------------------------------*/
  1059. /*    s h e l l                                                       */
  1060. /*                                                                    */
  1061. /*    Simulate a Unix command                                         */
  1062. /*--------------------------------------------------------------------*/
  1063.  
  1064. static int shell(char *command,
  1065.                  const char *inname,
  1066.                  const char *outname,
  1067.                  const char *remotename,
  1068.                  boolean xflag[])
  1069. {
  1070.    int    result = 0;
  1071.  
  1072. #if defined(BIT32ENV)
  1073.    char   commandBuf[1024];   /* New OS/2, Windows NT environments   */
  1074. #elif defined(__TURBOC__)
  1075.    char   commandBuf[128];    /* Original DOS environment            */
  1076. #else
  1077.    char   commandBuf[255];    /* Maybe MS C DOS, or OS/2 1.x         */
  1078. #endif
  1079.  
  1080.    char   *cmdname;
  1081.    char   *parameters;
  1082.  
  1083.    if (xflag[X_USEEXEC])
  1084.       printmsg(2, "exec(2) not supported, executing using spawn");
  1085.  
  1086. /*--------------------------------------------------------------------*/
  1087. /*         Determine the command name and parameters, if any          */
  1088. /*--------------------------------------------------------------------*/
  1089.  
  1090.    cmdname = strtok( command, WHITESPACE );
  1091.    parameters = strtok( NULL, "\r\n" );
  1092.  
  1093.    if ( parameters != NULL )
  1094.    {
  1095.       parameters += strspn(parameters, WHITESPACE); /* drop leading whitespace */
  1096.  
  1097.       if ( *parameters == '\0' )
  1098.          parameters = NULL;
  1099.       else
  1100.       {
  1101.          /* MISSING CODE: we should check the parameters to see that all file
  1102.             references are legitimate.  What do other implementations of uuxqt
  1103.             do for this access check?  Maybe check for READ access if a path
  1104.             is specified but accept anything that isn't a pathname (such as a
  1105.             username for an RMAIL command)?  I'm not yet completely sure.
  1106.  
  1107.             Taylor/GNU uuxqt seems to check for both READ and WRITE access
  1108.             if it starts with a '/' and also rejects most (but not all) names
  1109.             containing "..".
  1110.  
  1111.             Also, what quoting conventions should we follow when parsing?
  1112.             The DOS COMMAND.COM certainly does not handle \-style quoting,
  1113.             for example, so we don't want to get fooled by handling such here.
  1114.  
  1115.                                                                       --RHG */
  1116.       }
  1117.    } /* if ( parameters != NULL ) */
  1118.  
  1119. /*--------------------------------------------------------------------*/
  1120. /*    Verify we support the command, and get it's real name, if so    */
  1121. /*--------------------------------------------------------------------*/
  1122.  
  1123.    if ( (!equal(remotename, E_nodename)) && (!ValidateCommand( cmdname )) )
  1124.    {
  1125.       printmsg(0,"Command \"%s\" not allowed at this site", cmdname);
  1126.       xflag[E_NOEXE] = TRUE;
  1127.       return 99;
  1128.    }
  1129.  
  1130. /*--------------------------------------------------------------------*/
  1131. /*               We support the command; execute it                   */
  1132. /*--------------------------------------------------------------------*/
  1133.  
  1134.    fflush(logfile);
  1135.  
  1136. /*--------------------------------------------------------------------*/
  1137. /*               RNEWS may be special, handle it if so                */
  1138. /*--------------------------------------------------------------------*/
  1139.  
  1140.    if (equal(cmdname,RNEWS) &&
  1141.        bflag[F_WINDOWS] &&
  1142.        ( inname != NULL ))       /* rnews w/input?                    */
  1143.    {
  1144.       strcpy( commandBuf, "-f " );
  1145.       strcat( commandBuf, inname );
  1146.       parameters = commandBuf;   /* We explicitly ignore all parameters  */
  1147.                                  /* on the RNEWS command              */
  1148.  
  1149.       result = execute( RNEWS,
  1150.                         commandBuf,
  1151.                         NULL,
  1152.                         outname,
  1153.                         TRUE,
  1154.                         FALSE );
  1155.    }
  1156.  
  1157. /*--------------------------------------------------------------------*/
  1158. /*        RMAIL is special, we need to break up the parameters        */
  1159. /*--------------------------------------------------------------------*/
  1160.  
  1161.    else if (equal(cmdname,RMAIL) && ( inname != NULL )) /* rmail w/input?  */
  1162.    {
  1163.       parameters = strtok( parameters, WHITESPACE );
  1164.  
  1165.       while (( parameters != NULL ) && (result != -1 ))
  1166.       {
  1167.  
  1168.          boolean firstPass = TRUE;
  1169.          int left;
  1170.  
  1171.          int rlen = IsDOS() ? 126 : sizeof commandBuf - 2;
  1172.  
  1173. #ifdef _Windows
  1174.          if ( bflag[F_WINDOWS] )
  1175.          {
  1176.             strcpy( commandBuf, "-f ");
  1177.             strcat( commandBuf, inname);
  1178.             strcat( commandBuf, " ");
  1179.          }
  1180.          else
  1181.             *commandBuf = '\0';
  1182. #else
  1183.          *commandBuf = '\0';
  1184. #endif
  1185.          rlen -= strlen( commandBuf ) + strlen( RMAIL ) + 1;
  1186.  
  1187. /*--------------------------------------------------------------------*/
  1188. /*                   Copy addresses into the buffer                   */
  1189. /*--------------------------------------------------------------------*/
  1190.  
  1191.          left = rlen - strlen( parameters );
  1192.  
  1193.          while ((parameters != NULL) && (left > 0))
  1194.          {
  1195.             char *next = strtok( NULL, "");
  1196.  
  1197.             if ( *parameters == '-')   /* Option flag for mail?        */
  1198.                printmsg(0,"Disallowed option %s ignored",parameters);
  1199.             else {                     /* Not option, add to param list  */
  1200.                strcat( commandBuf, " ");
  1201.                strcat( commandBuf, parameters );
  1202.                rlen -= strlen( parameters ) + 1;
  1203.                firstPass = FALSE;
  1204.             }
  1205.  
  1206. /*--------------------------------------------------------------------*/
  1207. /*                       Step to next parameter                       */
  1208. /*--------------------------------------------------------------------*/
  1209.  
  1210.             if ( next == NULL )
  1211.                parameters = NULL;
  1212.             else
  1213.                parameters = strtok( next, WHITESPACE );
  1214.  
  1215.          } /* while ( parameters != NULL ) */
  1216.  
  1217.          if (firstPass)       /* Did we process at least one addr?     */
  1218.          {                    /* No --> Serious problem!              */
  1219.             printmsg(0,
  1220.                      "Address \"%s\" too long (%d chars)!  %d available, short fall would be %d",
  1221.                       parameters,
  1222.                       strlen(parameters),
  1223.                       rlen,
  1224.                       left );
  1225.  
  1226.             panic();
  1227.          } /* if (*commandBuf = '\0') */
  1228.  
  1229.       } /* while */
  1230.  
  1231. /*--------------------------------------------------------------------*/
  1232. /*               Execute one command line of addresses                */
  1233. /*--------------------------------------------------------------------*/
  1234.  
  1235.       result = execute( RMAIL,
  1236.                         commandBuf,
  1237.                         bflag[F_WINDOWS] ? NULL : inname,
  1238.                         outname,
  1239.                         TRUE,
  1240.                         FALSE );
  1241.  
  1242.       if ( result != 0 )    /* Did command execution fail?            */
  1243.       {
  1244.          printmsg(0,"shell: command \"%s %s\" returned error code %d",
  1245.                cmdname, commandBuf, result);
  1246.          panic();
  1247.       }
  1248.  
  1249.    } /* if (equal(cmdname,RMAIL) && ( inname != NULL )) */
  1250.    else
  1251.       result = execute( cmdname,
  1252.                         parameters,
  1253.                         inname,
  1254.                         outname,
  1255.                         TRUE,
  1256.                         FALSE );
  1257.  
  1258. /*--------------------------------------------------------------------*/
  1259. /*                    Determine result of command                     */
  1260. /*--------------------------------------------------------------------*/
  1261.  
  1262.    if ( result == 0 )
  1263.       xflag[E_NORMAL] = TRUE;
  1264.    else if ( equal(cmdname, RNEWS) )
  1265.                            /* Did command execution fail?            */
  1266.    {
  1267.       printmsg(0,"shell: command %s returned error code %d",
  1268.             cmdname, result);
  1269.       panic();
  1270.    }
  1271.    else if ( result > 0 )
  1272.       xflag[E_STATUS] = TRUE;
  1273.  
  1274.    fflush(logfile);
  1275.  
  1276.    return result;
  1277.  
  1278. } /* shell */
  1279.  
  1280. /*--------------------------------------------------------------------*/
  1281. /*    u s a g e                                                       */
  1282. /*                                                                    */
  1283. /*    Report how to run this program                                  */
  1284. /*--------------------------------------------------------------------*/
  1285.  
  1286. static void usage( void )
  1287. {
  1288.    fputs("Usage: uuxqt [-xDEBUG] [-sSYSTEM]", stderr);
  1289.    exit(1);
  1290. } /* usage */
  1291.  
  1292. /*--------------------------------------------------------------------*/
  1293. /*    c o p y l o c a l                                               */
  1294. /*                                                                    */
  1295. /*    Copy Local Files                                                */
  1296. /*--------------------------------------------------------------------*/
  1297.  
  1298. static boolean copylocal(const char *from, const char *to)
  1299. {
  1300.       int  fd_from, fd_to;
  1301.       int  nr;
  1302.       int  nw = -1;
  1303.       char buf[BUFSIZ];            /* faster if we alloc a big buffer  */
  1304.  
  1305.       /* This would be even faster if we determined that both files
  1306.          were on the same device, dos >= 3.0, and used the dos move
  1307.          function EXCEPT that we want a COPY, not a MOVE! */
  1308.  
  1309.       if ((fd_from = open(from, O_RDONLY | O_BINARY)) == -1)
  1310.          return FALSE;        /* failed                                */
  1311.  
  1312.       /* what if the to is a directory? */
  1313.       /* possible with local source & dest uucp */
  1314.  
  1315.       if ((fd_to = open(to, O_CREAT | O_BINARY | O_WRONLY, S_IWRITE | S_IREAD)) == -1) {
  1316.          close(fd_from);
  1317.          return FALSE;        /* failed                                */
  1318.          /* NOTE - this assumes all the required directories exist!  */
  1319.       }
  1320.  
  1321.       while  ((nr = read(fd_from, buf, sizeof buf)) > 0 &&
  1322.          (nw = write(fd_to, buf, nr)) == nr)
  1323.          ;
  1324.  
  1325.       close(fd_to);
  1326.       close(fd_from);
  1327.  
  1328.       if (nr != 0 || nw == -1)
  1329.          return FALSE;        /* failed in copy                       */
  1330.       return TRUE;
  1331. } /* copylocal */
  1332.  
  1333. /*--------------------------------------------------------------------*/
  1334. /*    c r e a t e _ e n v i r o n m e n t                             */
  1335. /*                                                                    */
  1336. /*    Create the environment array for subprocesses                   */
  1337. /*--------------------------------------------------------------------*/
  1338.  
  1339. char **create_environment(const char *logname,
  1340.                           const char *requestor)
  1341. {
  1342.    char buffer[MAXADDR + 20];
  1343.    int subscript = 0;
  1344.    char **envp = (char **) malloc(sizeof(char *) * 3);
  1345.  
  1346.    checkref(envp);
  1347.  
  1348. /*--------------------------------------------------------------------*/
  1349. /*              "Current" user id processing the request              */
  1350. /*--------------------------------------------------------------------*/
  1351.  
  1352.    if ( logname != NULL )
  1353.    {
  1354.      sprintf(buffer,"%s=%s", LOGNAME, logname);
  1355.      envp[subscript] = strdup(buffer);
  1356.      checkref(envp[subscript++]);
  1357.    }
  1358.  
  1359. /*--------------------------------------------------------------------*/
  1360. /*               user id/nodename of original requestor               */
  1361. /*--------------------------------------------------------------------*/
  1362.  
  1363.    if ( requestor != NULL )
  1364.    {
  1365.       sprintf(buffer,"%s=%s",UU_USER, requestor);
  1366.       envp[subscript] =  strdup(buffer);
  1367.       checkref(envp[subscript++]);
  1368.    }
  1369.  
  1370.    envp[subscript] =  NULL;   /* Terminate the list                    */
  1371.  
  1372. /*--------------------------------------------------------------------*/
  1373. /*               Now put the data into our environment                */
  1374. /*--------------------------------------------------------------------*/
  1375.  
  1376.    while( subscript-- > 0)
  1377.    {
  1378.       if (putenv( envp[subscript] ))
  1379.       {
  1380.          printmsg(0,"Unable to set environment \"%s\"",envp[subscript]);
  1381.          panic();
  1382.       }
  1383.    } /* while */
  1384.  
  1385.    return envp;
  1386. } /* create_environment */
  1387.  
  1388. /*--------------------------------------------------------------------*/
  1389. /*    d e l e t e  _ e n v i r o n m e n t                            */
  1390. /*                                                                    */
  1391. /*    Delete variables inserted by create_enviroment                  */
  1392. /*                                                                    */
  1393. /*    Our environment goes away when we are done executing we; just   */
  1394. /*    clean up the environment because we are freeing the storage     */
  1395. /*--------------------------------------------------------------------*/
  1396.  
  1397. static void delete_environment( char **envp )
  1398. {
  1399.    int subscript = 0;
  1400.  
  1401.    while ( envp[subscript] != NULL )
  1402.    {
  1403.       char *equal = strchr(envp[subscript]  , '=' );
  1404.       *++equal = '\0';        /* Terminate the string                 */
  1405.       if (putenv( envp[subscript] ))
  1406.       {
  1407.          printmsg(0,"Unable to reset environment \"%s\"",envp[subscript]);
  1408.          panic();
  1409.       }
  1410.       free( envp[subscript++] );
  1411.    }
  1412.  
  1413.    free( envp );
  1414. } /* delete_environment */
  1415.  
  1416.  
  1417. /*--------------------------------------------------------------------*/
  1418. /*    d o _ c o p y                                                   */
  1419. /*                                                                    */
  1420. /*    Send a file to remote node via uucp                             */
  1421. /*--------------------------------------------------------------------*/
  1422.  
  1423. static boolean do_copy(char *localfile,
  1424.                        const char *rmtsystem,
  1425.                        const char *remotefile,
  1426.                        const char *requestor,
  1427.                        const boolean success )
  1428. {
  1429.       if (rmtsystem == NULL) {
  1430.           copylocal(localfile, remotefile);
  1431.       } else {
  1432.           char    tmfile[FILENAME_MAX];  /* Unix style name for c file  */
  1433.           char    idfile[FILENAME_MAX];  /* Unix style name for data file copy  */
  1434.           char    work[FILENAME_MAX]; /* temp area for filename hacking  */
  1435.           char    icfilename[FILENAME_MAX];  /* our hacked c file path  */
  1436.           char    idfilename[FILENAME_MAX];  /* our hacked d file path  */
  1437.  
  1438.           struct  stat    statbuf;
  1439.  
  1440.           long    int     sequence;
  1441.           static  char    subseq = 'A';
  1442.           char   *sequence_s;
  1443.           FILE   *cfile;
  1444.  
  1445.  
  1446.           sequence = getseq();
  1447.           sequence_s = JobNumber( sequence );
  1448.  
  1449.           sprintf(tmfile, spool_fmt, 'C', rmtsystem, 'Z', sequence_s);
  1450.           importpath(work, tmfile, rmtsystem);
  1451.           mkfilename(icfilename, E_spooldir, work);
  1452.  
  1453.           if (stat((char *) localfile, &statbuf) != 0)  {
  1454.               printerr( localfile );
  1455.               return FALSE;
  1456.           }
  1457.  
  1458.           sprintf(idfile , dataf_fmt, 'D', E_nodename, sequence_s,
  1459.                   (char) subseq++ );
  1460.           importpath(work, idfile, rmtsystem);
  1461.           mkfilename(idfilename, E_spooldir, work);
  1462.  
  1463.           if (!copylocal(localfile, idfilename))  {
  1464.              printmsg(0, "Copy \"%s\" to \"%s\" failed", localfile, idfilename);
  1465.              return FALSE;
  1466.           }
  1467.  
  1468.           if ((cfile = FOPEN(icfilename, "a",TEXT_MODE)) == NULL)  {
  1469.              printerr( icfilename );
  1470.              printf("cannot append to %s\n", icfilename);
  1471.              return FALSE;
  1472.           }
  1473.  
  1474.           fprintf(cfile, success ? "S %s %s uucp -n %s 0666 %s\n"
  1475.                                  : "S %s %s uucp - %s 0666\n",
  1476.                          localfile, remotefile, idfile, requestor);
  1477.  
  1478.           fclose(cfile);
  1479.     };
  1480.  
  1481.     return TRUE;
  1482. } /* do_copy */
  1483.  
  1484. /*--------------------------------------------------------------------*/
  1485. /*    R e p o r t R e s u l t s                                       */
  1486. /*                                                                    */
  1487. /*    report results of command execution as specified by flags in    */
  1488. /*    X.* file.                                                       */
  1489. /*--------------------------------------------------------------------*/
  1490.  
  1491. static void ReportResults(const int status,
  1492.                           const char *input,
  1493.                                 char *output,
  1494.                           const char *command,
  1495.                           const char *job_id,
  1496.                           const time_t jtime,
  1497.                           const char *requestor,
  1498.                           const char *outnode,
  1499.                           const char *outname,
  1500.                           const boolean xflag[],
  1501.                           const char *statfil,
  1502.                           const char *machine,
  1503.                           const char *user)
  1504. {
  1505.    char address[MAXADDR];
  1506.    char subject[80];
  1507.    FILE *mailtmp = NULL;
  1508.    char *tempmail;
  1509.  
  1510.  
  1511.    if (!(xflag[X_FAILED] | xflag[X_SUCCESS] |
  1512.          xflag[X_INPUT]  | xflag[X_STATFIL] ))
  1513.    {  /* default actions */
  1514.       return;
  1515.    }
  1516.  
  1517.    tempmail = mktempname(NULL, "TMP");
  1518.  
  1519.    if ((mailtmp = FOPEN(tempmail, "w+", BINARY_MODE)) == NULL) {
  1520.       printerr(tempmail);
  1521.       return;
  1522.    }
  1523.  
  1524.    sprintf(subject, "\"[uucp job %s (%s)]\"", job_id, dater(jtime, NULL) );
  1525.  
  1526.    fprintf(mailtmp,"remote execution\n");
  1527.    fprintf(mailtmp,"%s\n", command);
  1528.  
  1529. #ifdef BETA_TEST
  1530.    strcpy(address,"postmaster");
  1531. #else
  1532.    if (equal(machine, E_nodename))
  1533.       strcpy(address, requestor);
  1534.    else
  1535.       sprintf(address,"%s!%s", machine, requestor);
  1536. #endif
  1537.  
  1538.    if (xflag[E_NORMAL])
  1539.    {                        /* command succeded, process appropriate flags */
  1540.  
  1541.       fprintf(mailtmp,"exited normally\n");
  1542.  
  1543.       if (xflag[X_OUTPUT])
  1544.          do_copy(output, outnode, outname, requestor, xflag[X_SUCCESS]);
  1545.  
  1546.       fclose(mailtmp);
  1547.  
  1548.       if (xflag[X_SUCCESS]) {
  1549.          if (xflag[X_STATFIL]) {
  1550.             do_copy(tempmail, outnode, statfil, requestor, xflag[X_SUCCESS]);
  1551.          } else {
  1552.             MailStatus(tempmail, address, subject);
  1553.          }
  1554.       }
  1555.  
  1556.    } else {            /* command failed, process appropriate flags   */
  1557.      if (xflag[F_CORRUPT])
  1558.         fprintf(mailtmp,"the X file was badly formatted\n");
  1559.      if (xflag[S_NOREAD])
  1560.         fprintf(mailtmp,"stdin was denied read permission\n");
  1561.      if (xflag[S_NOWRITE])
  1562.         fprintf(mailtmp,"stdout was denied write permission\n");
  1563.      if (xflag[F_NOCHDIR])
  1564.         fprintf(mailtmp,"unable to change directory to the execution directory\n");
  1565.      if (xflag[F_NOCOPY])
  1566.         fprintf(mailtmp,"unable to copy file(s) to the execution directory\n");
  1567.      if (xflag[F_BADF])
  1568.         fprintf(mailtmp,"invalid file name\n");
  1569.      if (xflag[E_NOACC])
  1570.          fprintf(mailtmp,"file access denied to %s!%s\n", machine, user);
  1571.      if (xflag[E_NOEXE])
  1572.         fprintf(mailtmp,"execution permission denied to %s!%s\n",
  1573.                 machine, requestor);
  1574.      if (xflag[E_SIGNAL])
  1575.         fprintf(mailtmp,"terminated by signal\n");
  1576.      if (xflag[E_STATUS])
  1577.         fprintf(mailtmp,"exited with status %d\n", status);
  1578.      if (xflag[E_FAILED])
  1579.         fprintf(mailtmp,"failed completely\n");
  1580.  
  1581.      if (xflag[E_STATUS])
  1582.      {
  1583.         if (xflag[X_FAILED])
  1584.         {
  1585.            if (xflag[X_INPUT])
  1586.            {
  1587.               fprintf(mailtmp,"===== stdin was ");
  1588.  
  1589.               if (xflag[S_CORRUPT])
  1590.                   fprintf(mailtmp,"unreadable =====\n");
  1591.               else if (!xflag[S_NOREAD])
  1592.               {
  1593.                   fprintf(mailtmp,"=====\n");
  1594.                   AppendData( input, mailtmp);
  1595.               };
  1596.  
  1597.            }
  1598.  
  1599.            fprintf(mailtmp,"===== stderr is unavailable =====\n");
  1600.         }
  1601.      }
  1602.  
  1603.      fclose(mailtmp);
  1604.  
  1605.      if (xflag[X_STATFIL]) {
  1606.          do_copy(tempmail, outnode, statfil, requestor, xflag[X_SUCCESS]);
  1607.      } else {
  1608.          MailStatus(tempmail, address, subject);
  1609.      }
  1610.  
  1611.    }
  1612.  
  1613.    unlink(tempmail);
  1614.    return;
  1615. } /* ReportResults */
  1616.  
  1617. /*--------------------------------------------------------------------*/
  1618. /* A p p e n d D a t a                                                */
  1619. /*                                                                    */
  1620. /* Append data to output file                                         */
  1621. /*--------------------------------------------------------------------*/
  1622.  
  1623. static boolean AppendData( const char *input, FILE* dataout)
  1624. {
  1625.    FILE    *datain;
  1626.    char     buf[BUFSIZ];
  1627.    boolean  status = TRUE;
  1628.  
  1629. /*--------------------------------------------------------------------*/
  1630. /*                      Verify the input opened                       */
  1631. /*--------------------------------------------------------------------*/
  1632.  
  1633.    if (input == NULL)
  1634.       return FALSE;
  1635.    else
  1636.       datain = FOPEN(input, "r",TEXT_MODE);
  1637.  
  1638.    if (datain == NULL) {
  1639.       printerr(input);
  1640.       printmsg(0,"Unable to open input file \"%s\"", input);
  1641.       return FALSE;
  1642.    } /* datain */
  1643.  
  1644. /*--------------------------------------------------------------------*/
  1645. /*                       Loop to copy the data                        */
  1646. /*--------------------------------------------------------------------*/
  1647.  
  1648.    while (fgets(buf, BUFSIZ, datain) != 0)
  1649.    {
  1650.       if (fputs(buf, dataout) == EOF)     /* I/O error?               */
  1651.       {
  1652.          printmsg(0,"AppendData: I/O error on output file");
  1653.          printerr("dataout");
  1654.          fclose(datain);
  1655.          return FALSE;
  1656.       } /* if */
  1657.    } /* while */
  1658.  
  1659. /*--------------------------------------------------------------------*/
  1660. /*                      Close up shop and return                      */
  1661. /*--------------------------------------------------------------------*/
  1662.  
  1663.    if (ferror(datain))        /* Clean end of file on input?           */
  1664.    {
  1665.       printerr(input);
  1666.       clearerr(datain);
  1667.       status = FALSE;
  1668.    }
  1669.  
  1670.    fclose(datain);
  1671.    return status;
  1672.  
  1673. } /* AppendData */
  1674.  
  1675. /*--------------------------------------------------------------------*/
  1676. /*    M a i l S t a t u s                                             */
  1677. /*                                                                    */
  1678. /*    Send text in a mailbag file to address(es) specified by line.   */
  1679. /*--------------------------------------------------------------------*/
  1680.  
  1681. static boolean MailStatus(char *tempfile,
  1682.                           char *address,
  1683.                           char *subject)
  1684. {
  1685.    boolean status;
  1686.    char **envp;
  1687.    char buf[BUFSIZ];
  1688.  
  1689. /*--------------------------------------------------------------------*/
  1690. /*                            Invoke RMAIL                            */
  1691. /*--------------------------------------------------------------------*/
  1692.  
  1693.    envp = create_environment( "uucp", NULL );
  1694.  
  1695.    strcpy(buf, "-w -f " );
  1696.    strcat(buf, tempfile );
  1697.    if ( subject != NULL )
  1698.    {
  1699.       strcat(buf, " -s " );
  1700.       strcat(buf, subject );
  1701.    }
  1702.    strcat( buf, " " );
  1703.    strcat( buf, address );
  1704.  
  1705.    status = execute( RMAIL, buf, NULL, NULL, TRUE, FALSE );
  1706.  
  1707.    delete_environment( envp );
  1708.  
  1709. /*--------------------------------------------------------------------*/
  1710. /*                       Report errors, if any                        */
  1711. /*--------------------------------------------------------------------*/
  1712.  
  1713.    if ( status < 0 )
  1714.    {
  1715.       printerr( RMAIL );
  1716.       printmsg(0,"Unable to execute rmail; status not delivered.");
  1717.    }
  1718.    else if ( status > 0 )
  1719.       printmsg(0, "Rmail returned error;\
  1720.  status delivery may be incomplete.");
  1721.  
  1722. /*--------------------------------------------------------------------*/
  1723. /*                          Return to caller                          */
  1724. /*--------------------------------------------------------------------*/
  1725.  
  1726.    return (status == 0 );
  1727.  
  1728. } /*MailStatus*/
  1729.