home *** CD-ROM | disk | FTP | other *** search
/ Super Net 1 / SUPERNET_1.iso / PC / OTROS / EXTRAS / UUCODE / UUPC / TEST / UPC12ES3.ZIP / UUCP / uux.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-24  |  42.8 KB  |  1,237 lines

  1. /*--------------------------------------------------------------------*/
  2. /*          u u x . c                                                 */
  3. /*                                                                    */
  4. /*          Queue remote commands for UUCP under UUPC/extended        */
  5. /*--------------------------------------------------------------------*/
  6.  
  7. /*--------------------------------------------------------------------*/
  8. /*       Changes Copyright (c) 1989-1993 by Kendra Electronic         */
  9. /*       Wonderworks.                                                 */
  10. /*                                                                    */
  11. /*       All rights reserved except those explicitly granted by       */
  12. /*       the UUPC/extended license agreement.                         */
  13. /*--------------------------------------------------------------------*/
  14.  
  15. /*--------------------------------------------------------------------*/
  16. /*                          RCS Information                           */
  17. /*--------------------------------------------------------------------*/
  18.  
  19. /*
  20.  *    $Id: uux.c 1.10 1993/10/24 19:42:48 rhg Exp $
  21.  *
  22.  *    Revision history:
  23.  *    $Log: uux.c $
  24.  * Revision 1.10  1993/10/24  19:42:48  rhg
  25.  * Generalized support for UUX'ed commands
  26.  *
  27.  * Revision 1.9  1993/10/12  01:33:59  ahd
  28.  * Normalize comments to PL/I style
  29.  *
  30.  * Revision 1.8  1993/10/03  20:43:08  ahd
  31.  * Normalize comments to C++ double slash
  32.  *
  33.  * Revision 1.7  1993/10/01  01:17:44  ahd
  34.  * Additional correct from Richard Gumpertz
  35.  *
  36.  * Revision 1.6  1993/09/28  01:38:19  ahd
  37.  * Corrections from Robert H. Gumpertz (rhg@cps.com)
  38.  *
  39.  * Revision 1.5  1993/09/20  04:48:25  ahd
  40.  * TCP/IP support from Dave Watt
  41.  * 't' protocol support
  42.  * OS/2 2.x support (BC++ 1.0 for OS/2)
  43.  *
  44.  */
  45.  
  46. /*
  47.       Program:    uux.c              27 August 1991
  48.       Author:     Mitch Mitchell
  49.       Email:      mitch@harlie.lonestar.org
  50.  
  51.       Much of this code is shamelessly taken from extant code in
  52.       UUPC/Extended.
  53.  
  54.       Usage:      uux [ options ] command-string
  55.  
  56.                Where [ options ] are:
  57.  
  58.      -aname    Use name as the user identification replacing the initiator
  59.                user-id.  (Notification will be returned to the user.)
  60.  
  61.      -b        Return whatever standard input was provided to the uux command
  62.                if the exit status is non-zero.
  63.  
  64.      -c        Do not copy local file to the spool directory for transfer to
  65.                the remote machine (default).
  66.  
  67.      -C        Force the copy of local files to the spool directory for
  68.                transfer.
  69.  
  70.      -e        Remote system should use sh to execute commands.
  71.  
  72.      -E        Remote system should use exec to execute commands.
  73.  
  74.      -ggrade   Grade is a single letter/number; lower ASCII sequence
  75.                characters will cause the job to be transmitted earlier during
  76.                a particular conversation.
  77.  
  78.      -j        Output the jobid ASCII string on the standard output which is
  79.                the job identification.  This job identification can be used by
  80.                uustat to obtain the status or terminate a job.
  81.  
  82.      -n        Do not notify the user if the command fails.
  83.  
  84.      -p        The standard input to uux is made the standard input to the
  85.                command-string.
  86.  
  87.      -r        Do not start the file transfer, just queue the job.
  88.                (Currently uux does not attempt to start the transfer
  89.                 regardless of the presense of this option).
  90.  
  91.      -sfile    Report status of the transfer in file.
  92.  
  93.      -xdebug_level
  94.                Produce debugging output on the standard output.  The
  95.                debug_level is a number between 0 and ??; higher numbers give
  96.                more detailed information.
  97.  
  98.      -z        Send success notification to the user.
  99.  
  100.  
  101.       The command-string is made up of one or more arguments that
  102.       look like a normal command line, except that the command and
  103.       filenames may be prefixed by system-name!.  A null
  104.       system-name is interpreted as the local system.
  105.  
  106. */
  107.  
  108. /*--------------------------------------------------------------------*/
  109. /*         System include files                                       */
  110. /*--------------------------------------------------------------------*/
  111.  
  112. #include <stdio.h>
  113. #include <io.h>
  114. #include <string.h>
  115. #include <time.h>
  116. #include <stdlib.h>
  117. #include <fcntl.h>
  118. #include <sys/types.h>
  119. #include <sys/stat.h>
  120.  
  121. #ifdef _Windows
  122. #include <windows.h>
  123. #endif
  124.  
  125. /*--------------------------------------------------------------------*/
  126. /*         Local include files                                        */
  127. /*--------------------------------------------------------------------*/
  128.  
  129. #include  "lib.h"
  130. #include  "hlib.h"
  131. #include  "getopt.h"
  132. #include  "getseq.h"
  133. #include  "expath.h"
  134. #include  "import.h"
  135. #include  "pushpop.h"
  136. #include  "hostable.h"
  137. #include  "security.h"
  138. #include  "timestmp.h"
  139.  
  140. #ifdef _Windows
  141. #include "winutil.h"
  142. #include "logger.h"
  143. #endif
  144.  
  145. /*--------------------------------------------------------------------*/
  146. /*        Define current file name for panic() and printerr()         */
  147. /*--------------------------------------------------------------------*/
  148.  
  149. currentfile();
  150.  
  151. /*--------------------------------------------------------------------*/
  152. /*                          Global variables                          */
  153. /*--------------------------------------------------------------------*/
  154.  
  155. typedef enum {
  156.           FLG_USE_USERID,
  157.           FLG_OUTPUT_JOBID,
  158.           FLG_READ_STDIN,
  159.           FLG_QUEUE_ONLY,
  160.           FLG_NOTIFY_SUCCESS,
  161.           FLG_NONOTIFY_FAIL,
  162.           FLG_COPY_SPOOL,
  163.           FLG_RETURN_STDIN,
  164.           FLG_STATUS_FILE,
  165.           FLG_USE_EXEC,
  166.           FLG_MAXIMUM
  167.        } UuxFlags;
  168.  
  169. typedef enum {
  170.       DATA_FILE   = 0,        /* Normal data file passed argument     */
  171.       INPUT_FILE  = 1,        /* Redirected stdin file                 */
  172.       OUTPUT_FILE = 2         /* Redirected stdout file               */
  173.       } FileType;
  174.  
  175. static boolean flags[FLG_MAXIMUM] = {
  176.                                         FALSE,
  177.                                         FALSE,
  178.                                         FALSE,
  179.                                         FALSE,
  180.                                         FALSE,
  181.                                         FALSE,
  182.                                         FALSE,
  183.                                         FALSE,
  184.                                         FALSE,
  185.                                         FALSE
  186.                                     };
  187. static char* st_out = NULL;
  188. static char* user_id = NULL;
  189. static char  grade = 'Z';          /* Default grade of service        */
  190.  
  191. static char  job_id[15];
  192.  
  193. static char* spool_fmt = SPOOLFMT;
  194. static char* dataf_fmt = DATAFFMT;
  195.  
  196. static char* send_cmd  = "S %s %s %s - %s 0666\n";
  197.  
  198. /*--------------------------------------------------------------------*/
  199. /*                        Internal prototypes                         */
  200. /*--------------------------------------------------------------------*/
  201.  
  202. void main(int  argc, char  **argv);
  203. static void usage( void );
  204. static char *SwapSlash(char *p);
  205. static boolean cp(char *from, char *to);
  206. static boolean split_path(char *path,
  207.                           char *system,
  208.                           char *file,
  209.                           boolean expand,
  210.                           char *default_sys);
  211. static boolean CopyData( const char *input, const char *output);
  212.  
  213. static boolean do_uuxqt(char *job_name, char *src_syst, char *src_file, char *dest_syst, char *dest_file);
  214.  
  215. static boolean do_copy(char *src_syst, char *src_file, char *dest_syst, char *dest_file);
  216.  
  217. static boolean do_remote(int optind, int argc, char **argv);
  218. static void preamble(FILE* stream);
  219. static char subseq( void );
  220.  
  221. /*--------------------------------------------------------------------*/
  222. /*    u s a g e                                                       */
  223. /*                                                                    */
  224. /*    Report flags used by program                                    */
  225. /*--------------------------------------------------------------------*/
  226.  
  227. static void usage()
  228. {
  229.    fprintf(stderr, "Usage: uux\t[-c|-C] [-e|-E] [-b] [-gGRADE] "
  230.                    "[-p] [-j] [-n] [-r] [-sFILE]\\\n"
  231.                    "\t\t[-aNAME] [-z] [-] [-xDEBUG_LEVEL] "
  232.                    "command-string\n");
  233. }
  234.  
  235.  
  236. /*--------------------------------------------------------------------*/
  237. /*    s w a p s l a s h                                               */
  238. /*                                                                    */
  239. /*    Change backslash in a directory path to forward slash           */
  240. /*--------------------------------------------------------------------*/
  241.  
  242. static char *SwapSlash(char *p)
  243. {
  244.    char *q = p;
  245.  
  246.    while (*q) {
  247.       if (*q ==  '\\')
  248.          *q = '/';
  249.       q++;
  250.    }
  251.    return p;
  252. };
  253.  
  254. /*--------------------------------------------------------------------*/
  255. /*    c p                                                             */
  256. /*                                                                    */
  257. /*    Copy Local Files                                                */
  258. /*--------------------------------------------------------------------*/
  259.  
  260. static boolean cp(char *from, char *to)
  261. {
  262.    int  fd_from, fd_to;
  263.    int  nr;
  264.    int  nw = -1;
  265.    char buf[BUFSIZ];            /* faster if we alloc a big buffer    */
  266.  
  267.    /* This would be even faster if we determined that both files
  268.       were on the same device, dos >= 3.0, and used the dos move
  269.       function */
  270.  
  271.    if ((fd_from = open(from, O_RDONLY | O_BINARY)) == -1)
  272.       return FALSE;        /* failed                                  */
  273.  
  274.    /* what if the to is a directory? */
  275.    /* possible with local source & dest uucp */
  276.  
  277.    if ((fd_to = open(to, O_CREAT | O_BINARY | O_WRONLY, S_IWRITE | S_IREAD)) == -1) {
  278.       close(fd_from);
  279.       return FALSE;        /* failed                                  */
  280.       /* NOTE - this assumes all the required directories exist!      */
  281.    }
  282.  
  283.    while  ((nr = read(fd_from, buf, sizeof buf)) > 0 &&
  284.       (nw = write(fd_to, buf, nr)) == nr)
  285.       ;
  286.  
  287.    close(fd_to);
  288.    close(fd_from);
  289.  
  290.    if (nr != 0 || nw == -1)
  291.       return FALSE;        /* failed in copy                          */
  292.    return TRUE;
  293. }
  294.  
  295.  
  296. /*--------------------------------------------------------------------*/
  297. /*    C o p y D a t a                                                 */
  298. /*                                                                    */
  299. /*    Copy data into its final resting spot                           */
  300. /*--------------------------------------------------------------------*/
  301.  
  302. static boolean CopyData( const char *input, const char *output)
  303. {
  304.    FILE    *datain;
  305.    FILE    *dataout;
  306.    char     buf[BUFSIZ];
  307.    boolean  status = TRUE;
  308.    size_t   len;
  309.  
  310.    if ( (dataout = FOPEN(output, "w", BINARY_MODE)) == NULL )
  311.    {
  312.       printerr(output);
  313.       printmsg(0,"uux: Cannot open spool file \"%s\" for output",
  314.                output);
  315.       return FALSE;
  316.    }
  317.  
  318. /*--------------------------------------------------------------------*/
  319. /*                      Verify the input opened                       */
  320. /*--------------------------------------------------------------------*/
  321.  
  322.    if (input == NULL)
  323.    {
  324.       datain = stdin;
  325.       setmode(fileno(datain), O_BINARY);   /* Don't die on control-Z, etc  */
  326.    }
  327.    else
  328.       datain = FOPEN(input, "r", BINARY_MODE);
  329.  
  330.    if (datain == NULL) {
  331.       printerr(input);
  332.       printmsg(0,"Unable to open input file \"%s\"",
  333.                (input == NULL ? "stdin" : input));
  334.       fclose(dataout);
  335.       return FALSE;
  336.    } /* datain */
  337.  
  338. /*--------------------------------------------------------------------*/
  339. /*                       Loop to copy the data                        */
  340. /*--------------------------------------------------------------------*/
  341.  
  342.    while ( (len = fread( buf, 1, BUFSIZ, datain)) != 0)
  343.    {
  344.       if ( fwrite( buf, 1, len, dataout ) != len)     /* I/O error?   */
  345.       {
  346.          printerr("dataout");
  347.          printmsg(0,"I/O error on \"%s\"", output);
  348.          fclose(dataout);
  349.          return FALSE;
  350.       } /* if */
  351.    } /* while */
  352.  
  353. /*--------------------------------------------------------------------*/
  354. /*                      Close up shop and return                      */
  355. /*--------------------------------------------------------------------*/
  356.  
  357.    if (ferror(datain))        /* Clean end of file on input?           */
  358.    {
  359.       printerr(input);
  360.       clearerr(datain);
  361.       status = FALSE;
  362.    }
  363.  
  364.    if (input != NULL)
  365.        fclose(datain);
  366.  
  367.    fclose(dataout);
  368.    return status;
  369.  
  370. } /* CopyData */
  371.  
  372. /*--------------------------------------------------------------------*/
  373. /*    s p l i t _ p a t h                                             */
  374. /*--------------------------------------------------------------------*/
  375.  
  376. static boolean split_path(char *path,
  377.                           char *sysname,
  378.                           char *file,
  379.                           boolean expand,
  380.                           char *default_sys )
  381. {
  382.       char *p_left;
  383.       char *p_right;
  384.       char *p = path;
  385.  
  386.       *sysname = *file = '\0';    /* init to nothing                  */
  387.  
  388. /*--------------------------------------------------------------------*/
  389. /*                if path is wildcarded then error                    */
  390. /*--------------------------------------------------------------------*/
  391.  
  392.    if (strcspn(path, "*?[") < strlen(path))
  393.    {
  394.       printmsg(0,"uux - Wildcards not allowed in operand: %s",p );
  395.       return FALSE;
  396.    }
  397.  
  398. /*--------------------------------------------------------------------*/
  399. /*                        Find the first bangs                        */
  400. /*--------------------------------------------------------------------*/
  401.  
  402.    p_left = strchr(p, '!');         /* look for the first bang        */
  403.  
  404. /*--------------------------------------------------------------------*/
  405. /*   If no bangs, then the file is on the remote system.  We hope.    */
  406. /*--------------------------------------------------------------------*/
  407.  
  408.    if ( p_left == NULL )
  409.    {
  410.       strcpy( file, p);       /* Entire string is file name           */
  411.  
  412.       strcpy( sysname, default_sys );   /* Use default system name     */
  413.  
  414.       if ( equal(sysname, E_nodename ) &&
  415.            expand &&
  416.            (expand_path(file, NULL, E_homedir, NULL) == NULL))
  417.          return FALSE;     /* expand_path will delivery any needed
  418.                                  nasty-gram to user                  */
  419.  
  420.       return TRUE;
  421.  
  422.    } /* if ( p_left == NULL ) */
  423.  
  424. /*--------------------------------------------------------------------*/
  425. /*                         Find the last bang                         */
  426. /*--------------------------------------------------------------------*/
  427.  
  428.    p_right = strrchr(p, '!');       /* look for the last bang         */
  429.  
  430. /*--------------------------------------------------------------------*/
  431. /*    If the first bang is the first character, it's a local file     */
  432. /*--------------------------------------------------------------------*/
  433.  
  434.       if (p_left == p)                 /* First character in path?     */
  435.       {                                /* Yes --> not a remote path   */
  436.  
  437.          if ( p_left != p_right )      /* More bangs?                 */
  438.          {
  439.             printmsg(0,"uux - Invalid syntax for local file: %s", p );
  440.             return FALSE;              /* Yes --> I don't grok this   */
  441.          }
  442.  
  443.          strcpy(file, p+1);            /* Just return filename        */
  444.  
  445.          if ( expand && (expand_path(file, NULL, E_homedir, NULL) == NULL))
  446.             return FALSE;     /* expand_path will delivery any needed
  447.                                  nasty-gram to user                  */
  448.          strcpy(sysname, E_nodename);
  449.          return TRUE;
  450.       } /* p_left == p */
  451.  
  452. /*--------------------------------------------------------------------*/
  453. /*             It's not a local file, continue processing             */
  454. /*--------------------------------------------------------------------*/
  455.  
  456.       strcpy(file, p_right + 1);      /* and thats our filename        */
  457.  
  458.       strncpy(sysname, p, p_left - p); /* and we have a system thats not us  */
  459.       sysname[p_left - p] = '\0';
  460.  
  461. /*--------------------------------------------------------------------*/
  462. /*              Now see if there is an intermediate path              */
  463. /*--------------------------------------------------------------------*/
  464.  
  465.       if (p_left != p_right)
  466.       {
  467.  
  468.           printmsg(0, "uux - Intermediate system %.*s not supported",
  469.                      p_right - (p_left + 1), p_left + 1);
  470.           return FALSE;
  471.  
  472.       } /* if (p_left != p_right) */
  473.  
  474.       return TRUE;                     /* and we're done              */
  475.  
  476. } /* split_path */
  477.  
  478. /*--------------------------------------------------------------------*/
  479. /*    d o _ u u x q t                                                 */
  480. /*                                                                    */
  481. /*    Generate a UUXQT command file for local system                  */
  482. /*--------------------------------------------------------------------*/
  483.  
  484. static boolean do_uuxqt(char *job_name,
  485.                         char *src_syst,
  486.                         char *src_file,
  487.                         char *dest_syst,
  488.                         char *dest_file)
  489. {
  490.    long seqno = 0;
  491.    char *seq  = NULL;
  492.    FILE *stream;              /* For writing out data                 */
  493.  
  494.    char msfile[FILENAME_MAX]; /* MS-DOS format name of files           */
  495.    char msname[22];           /* MS-DOS format w/o path name           */
  496.    char ixfile[15];           /* eXecute file for local system,
  497.                                  UNIX format name for local system    */
  498.  
  499. /*--------------------------------------------------------------------*/
  500. /*          Create the UNIX format of the file names we need          */
  501. /*--------------------------------------------------------------------*/
  502.  
  503.    seqno = getseq();
  504.    seq = JobNumber( seqno );
  505.  
  506.    sprintf(ixfile, spool_fmt, 'X', E_nodename, grade , seq);
  507.  
  508. /*--------------------------------------------------------------------*/
  509. /*                     create local X (xqt) file                      */
  510. /*--------------------------------------------------------------------*/
  511.  
  512.    importpath( msname, ixfile, E_nodename);
  513.    mkfilename( msfile, E_spooldir, msname);
  514.  
  515.    if ( (stream = FOPEN(msfile, "w", BINARY_MODE)) == NULL ) {
  516.       printerr(msfile);
  517.       printmsg(0, "uux: cannot open X file %s", msfile);
  518.       return FALSE;
  519.    } /* if */
  520.  
  521.    fprintf(stream, "# third party request, job id\n" );
  522.    fprintf(stream, "J %s\n",               job_name );
  523.    fprintf(stream, "F %s/%s/%s %s\n",      E_spooldir, src_syst, dest_file,
  524.                                           src_file );
  525.    fprintf(stream, "C uucp -C %s %s!%s\n", src_file, dest_syst, dest_file );
  526.    fclose (stream);
  527.  
  528.    return TRUE;
  529.  
  530. } /* do_uuxqt */
  531.  
  532. /*--------------------------------------------------------------------*/
  533. /*    d o _ c o p y                                                   */
  534. /*                                                                    */
  535. /*    At this point only one of the systems can be remote and only    */
  536. /*    1 hop away.  All the rest have been filtered out                */
  537. /*--------------------------------------------------------------------*/
  538.  
  539. static boolean do_copy(char *src_syst,
  540.                        char *src_file,
  541.                        char *dest_syst,
  542.                        char *dest_file)
  543. {
  544.       char    tmfile[25];               /* Unix style name for c file  */
  545.       char    idfile[25];       /* Unix style name for data file copy  */
  546.       char    work[66];             /* temp area for filename hacking  */
  547.       char    icfilename[66];               /* our hacked c file path  */
  548.       char    idfilename[66];               /* our hacked d file path  */
  549.  
  550.       struct  stat    statbuf;
  551.  
  552.       long    int     sequence;
  553.       char    *remote_syst;    /* Non-local system in copy            */
  554.       char    *sequence_s;
  555.       FILE        *cfile;
  556.  
  557.       sequence = getseq();
  558.       sequence_s = JobNumber( sequence );
  559.  
  560.       remote_syst =  equal(src_syst, E_nodename) ? dest_syst : src_syst;
  561.  
  562.       sprintf(tmfile, spool_fmt, 'C', remote_syst, grade, sequence_s);
  563.       importpath(work, tmfile, remote_syst);
  564.       mkfilename(icfilename, E_spooldir, work);
  565.  
  566.       if (!equal(src_syst, E_nodename))
  567.       {
  568.          if (expand_path(dest_file, NULL, E_homedir, NULL) == NULL)
  569.             return FALSE;
  570.  
  571.          SwapSlash(src_file);
  572.  
  573.          printmsg(1, "uux - from \"%s\" - control = %s", src_syst,
  574.                   tmfile);
  575.          if ((cfile = FOPEN(icfilename, "a",TEXT_MODE)) == NULL)  {
  576.             printerr( icfilename );
  577.             printmsg(0, "uux: cannot append to %s\n", icfilename);
  578.             return FALSE;
  579.          }
  580.  
  581.          fprintf(cfile, "R %s %s %s -c D.0 0666 %s\n",
  582.                         src_file, dest_file,
  583.                         E_mailbox,
  584.                         flags[FLG_USE_USERID] ? user_id : E_mailbox);
  585.  
  586.  
  587.          fclose(cfile);
  588.          return TRUE;
  589.       }
  590.       else if (!equal(dest_syst, E_nodename))  {
  591.  
  592.          printmsg(1,"uux - spool %s - execute %s",
  593.                   flags[FLG_COPY_SPOOL] ? "on" : "off",
  594.                   flags[FLG_QUEUE_ONLY] ? "do" : "don't");
  595.          printmsg(1,"     - dest m/c = %s  sequence = %ld  control = %s",
  596.                   dest_syst, sequence, tmfile);
  597.  
  598.          if (expand_path(src_file, NULL, E_homedir, NULL) == NULL)
  599.             return FALSE;
  600.  
  601.          SwapSlash(dest_file);
  602.  
  603.          if (stat(src_file, &statbuf) != 0)  {
  604.             printerr( src_file );
  605.             return FALSE;
  606.          }
  607.  
  608.          if (statbuf.st_mode & S_IFDIR)  {
  609.             printf("uux - directory name \"%s\" illegal\n",
  610.                     src_file );
  611.             return FALSE;
  612.          }
  613.  
  614.          if (flags[FLG_COPY_SPOOL]) {
  615.             sprintf(idfile , dataf_fmt, 'D', E_nodename, sequence_s,
  616.                               subseq());
  617.             importpath(work, idfile, remote_syst);
  618.             mkfilename(idfilename, E_spooldir, work);
  619.  
  620.             /* Do we need a MKDIR here for the system? */
  621.  
  622.             if (!cp(src_file, idfilename))  {
  623.                printmsg(0, "copy \"%s\" to \"%s\" failed",
  624.                   src_file, idfilename);           /* copy data        */
  625.                return FALSE;
  626.             }
  627.          }
  628.          else
  629.             strcpy(idfile, "D.0");
  630.  
  631.          if ((cfile = FOPEN(icfilename, "a",TEXT_MODE)) == NULL)
  632.          {
  633.             printerr( icfilename );
  634.             printf("uux: cannot append to %s\n", icfilename);
  635.             return FALSE;
  636.          } /* if ((cfile = FOPEN(icfilename, "a",TEXT_MODE)) == NULL) */
  637.  
  638.          fprintf(cfile, "S %s %s %s -%s %s 0666 %s\n",
  639.                         src_file, dest_file,
  640.                         E_mailbox,
  641.                         flags[FLG_COPY_SPOOL] ? "c" : "",
  642.                         idfile,
  643.                         flags[FLG_USE_USERID] ? user_id : E_mailbox);
  644.  
  645.          fclose(cfile);
  646.  
  647.          return TRUE;
  648.       }
  649.       else {
  650.          if (expand_path(src_file, NULL, E_homedir, NULL) == NULL)
  651.             return FALSE;
  652.  
  653.          if (expand_path(dest_file, NULL, E_homedir, NULL) == NULL)
  654.             return FALSE;
  655.  
  656.          if (strcmp(src_file, dest_file) == 0)
  657.          {
  658.             printmsg(0, "%s %s - same file; can't copy\n",
  659.                   src_file, dest_file);
  660.             return FALSE;
  661.          } /* if (strcmp(src_file, dest_file) == 0) */
  662.  
  663.          return(cp(src_file, dest_file));
  664.       } /* else */
  665. } /* do_copy */
  666.  
  667. /*--------------------------------------------------------------------*/
  668. /*    p r e a m b l e                                                 */
  669. /*                                                                    */
  670. /*    write the execute file preamble based on the global flags       */
  671. /*--------------------------------------------------------------------*/
  672.  
  673. static void preamble(FILE* stream)
  674. {
  675.  
  676.    fprintf(stream, "U %s %s\n", E_mailbox, E_nodename);
  677.  
  678.    if (flags[FLG_RETURN_STDIN]) {
  679.        fprintf(stream, "# return input on abnormal exit\n");
  680.        fprintf(stream, "B\n");
  681.    }
  682.  
  683.    if (flags[FLG_NOTIFY_SUCCESS]) {
  684.        fprintf(stream, "# return status on success\n");
  685.        fprintf(stream, "n\n");
  686.    }
  687.  
  688.    if (flags[FLG_NONOTIFY_FAIL]) {
  689.        fprintf(stream, "# don't return status on failure\n");
  690.        fprintf(stream, "N\n");
  691.    } else {
  692.        fprintf(stream, "# return status on failure\n");
  693.        fprintf(stream, "Z\n");
  694.    }
  695.  
  696.    if (flags[FLG_USE_EXEC]) {
  697.        fprintf(stream, "# use exec to execute\n");
  698.        fprintf(stream, "E\n");
  699.    } else {
  700.        fprintf(stream, "# use sh execute\n");
  701.        fprintf(stream, "e\n");
  702.    }
  703.  
  704.    if (flags[FLG_STATUS_FILE]) {
  705.       fprintf(stream, "M %s\n", st_out );
  706.    }
  707.  
  708.    if (flags[FLG_USE_USERID]) {
  709.        fprintf(stream, "# return address for status or input return\n");
  710.        fprintf(stream, "R %s\n", user_id );
  711.    }
  712.  
  713.    fprintf(stream, "# job id for status reporting\n");
  714.    fprintf(stream, "J %s\n", job_id );
  715.    return;
  716. } /* preamble */
  717.  
  718. /*--------------------------------------------------------------------*/
  719. /*    d o _ r e m o t e                                               */
  720. /*                                                                    */
  721. /*   gather data files to ship to execution system and build X file   */
  722. /*--------------------------------------------------------------------*/
  723.  
  724. static boolean do_remote(int optind, int argc, char **argv)
  725. {
  726.    FILE    *stream;           /* For writing out data                 */
  727.    char    *sequence_s;
  728.  
  729.    boolean s_remote;
  730.    boolean d_remote;
  731.    boolean i_remote = FALSE;
  732.    boolean o_remote = FALSE;
  733.    boolean p_remote = FALSE;
  734.  
  735.    long    sequence;
  736.  
  737.    char    src_system[100];
  738.    char    dest_system[100];
  739.    char    src_file[FILENAME_MAX];
  740.    char    dest_file[FILENAME_MAX];
  741.  
  742.    char    command[BUFSIZ];
  743.  
  744.    char    msfile[FILENAME_MAX];    /* MS-DOS format name of files     */
  745.    char    msname[22];              /* MS-DOS format w/o path name     */
  746.  
  747.    char    tmfile[15];        /* Call file, UNIX format name           */
  748.    char    lxfile[15];        /* eXecute file for remote system,
  749.                                  UNIX format name for local system */
  750.    char    rxfile[15];        /* Remote system UNIX name of eXecute
  751.                                  file                              */
  752.    char    lifile[15];        /* Data file, UNIX format name           */
  753.    char    rifile[15];        /* Data file name on remote system,
  754.                                  UNIX format                       */
  755.    char* jobid_fmt = &spool_fmt[3];
  756.  
  757.  
  758. /*--------------------------------------------------------------------*/
  759. /*    Get the remote system and command to execute on that system     */
  760. /*--------------------------------------------------------------------*/
  761.  
  762.    if (!split_path(argv[optind++], dest_system, command, FALSE, E_nodename))
  763.    {
  764.       printmsg(0, "uux - illegal syntax %s", argv[--optind]);
  765.       return FALSE;
  766.    }
  767.  
  768.    d_remote = equal(dest_system, E_nodename) ? FALSE : TRUE ;
  769.  
  770. /*--------------------------------------------------------------------*/
  771. /*        OK - we have a destination system - do we know him?         */
  772. /*--------------------------------------------------------------------*/
  773.  
  774.    if ((d_remote) && (checkreal(dest_system) == BADHOST))
  775.    {
  776.       printmsg(0, "uux - bad system: %s", dest_system);
  777.       return FALSE;
  778.    }
  779.  
  780.    printmsg(9,"xsys -> %s", dest_system);
  781.    printmsg(9, "system \"%s\", rest \"%s\"", dest_system, command);
  782.  
  783.    sequence = getseq();
  784.    sequence_s = JobNumber( sequence );
  785.  
  786.    sprintf(job_id, jobid_fmt, dest_system, grade, sequence_s);
  787.  
  788. /*--------------------------------------------------------------------*/
  789. /*                     create remote X (xqt) file                     */
  790. /*--------------------------------------------------------------------*/
  791.  
  792.    sprintf(rxfile, dataf_fmt, 'X', E_nodename, sequence_s, subseq());
  793.    sprintf(lxfile, dataf_fmt, d_remote ? 'D' : 'X', E_nodename,
  794.            sequence_s, subseq());
  795.  
  796.    importpath( msname, lxfile, dest_system);
  797.    mkfilename( msfile, E_spooldir, msname);
  798.  
  799.    if ( (stream = FOPEN(msfile, "w", BINARY_MODE)) == NULL ) {
  800.       printerr(msfile);
  801.       printmsg(0, "uux: cannot open X file %s", msfile);
  802.       return FALSE;
  803.    } /* if */
  804.  
  805.    preamble(stream);
  806.  
  807. /*--------------------------------------------------------------------*/
  808. /*           Process options for the remote command                   */
  809. /*--------------------------------------------------------------------*/
  810.  
  811.    for (; optind < argc; optind++)
  812.    {
  813.  
  814.       FileType f_remote = DATA_FILE;
  815.       char *remote_file;
  816.  
  817.       switch (*argv[optind])
  818.       {
  819.  
  820.       case '-':
  821.          strcat(command," ");
  822.          strcat(command,argv[optind]);
  823.          printmsg(9, "prm -> %s", argv[optind]);
  824.          continue;
  825.  
  826.       case '<':
  827.          if (p_remote) {
  828.             printmsg(0, "uux - input file specified after pipe");
  829.             return FALSE;
  830.          }
  831.          else if (i_remote) {
  832.             printmsg(0, "uux - multiple input files specified");
  833.             return FALSE;
  834.          }
  835.          else
  836.             i_remote = TRUE;
  837.          f_remote = INPUT_FILE;
  838.          printmsg(9, "prm -> %c", *argv[optind]);
  839.          if (!*++argv[optind])
  840.             if (++optind >= argc)
  841.             {
  842.                printmsg(0, "uux - no input file specified after <");
  843.                return FALSE;
  844.             }
  845.          break;
  846.  
  847.       case '>':
  848.          if (o_remote) {
  849.             printmsg(0, "uux - multiple output files specified");
  850.             return FALSE;
  851.          } else
  852.             o_remote = TRUE;
  853.          f_remote = OUTPUT_FILE;
  854.          printmsg(9, "prm -> %c", *argv[optind]);
  855.          if (!*++argv[optind])
  856.              if (++optind >= argc)
  857.              {
  858.                 printmsg(0, "uux - no output file specified after >");
  859.                 return FALSE;
  860.              }
  861.          break;
  862.  
  863.        case '|':
  864.           if (o_remote) {
  865.              printmsg(0, "uux - pipe specified after output file");
  866.              return FALSE;
  867.           } else
  868.              p_remote = TRUE;
  869.           printmsg(9, "prm -> %c", *argv[optind]);
  870.           if (!*++argv[optind])
  871.              if (++optind >= argc)
  872.              {
  873.                 printmsg(0, "uux - no command specified after |");
  874.                 return FALSE;
  875.              }
  876.           if (strchr(argv[optind], '!'))
  877.           {
  878.              printmsg(0, "uux - no host name allowed after |");
  879.              return FALSE;
  880.           }
  881.           strcat(command," | ");
  882.           strcat(command, argv[optind]);
  883.           continue;
  884.  
  885.        case '(':
  886.        {
  887.           size_t len = strlen(argv[optind] + 1);
  888.  
  889.           if (argv[optind][len] != ')')
  890.           {
  891.              printmsg(0, "uux - missing close parenthesis in %s",
  892.                          argv[optind] + 1);
  893.              return FALSE;
  894.           }
  895.           argv[optind][len] = '\0';
  896.        }
  897.  
  898.           printmsg(9, "prm -> %s", argv[optind]);
  899.           strcat(command," ");
  900.           strcat(command, argv[optind] + 1);
  901.           continue;
  902.  
  903.        /* default: fall through */
  904.       } /* switch (*argv[optind]) */
  905.  
  906.  
  907.       printmsg(9, "prm -> %s", argv[optind]);
  908.  
  909. /*--------------------------------------------------------------------*/
  910. /*        Hmmm.  Do we want the remote to have DOS style path?        */
  911. /*--------------------------------------------------------------------*/
  912.  
  913.       if (!split_path(argv[optind], src_system, src_file, FALSE, dest_system))
  914.       {
  915.          printmsg(0, "uux - illegal syntax %s", argv[optind]);
  916.          return FALSE;
  917.       } /* if (!split_path()) */
  918.  
  919.       s_remote = equal(src_system, E_nodename) ? FALSE : TRUE ;
  920.  
  921. /*--------------------------------------------------------------------*/
  922. /*                   Do we know the source system?                    */
  923. /*--------------------------------------------------------------------*/
  924.  
  925.       if ((s_remote) && (checkreal(src_system) == BADHOST))
  926.       {
  927.          printmsg(0, "uux - bad system %s\n", src_system);
  928.          return FALSE;
  929.       } /* if ((s_remote) && (checkreal(src_system) == BADHOST)) */
  930.  
  931.       if (f_remote == OUTPUT_FILE)
  932.       {
  933.          fprintf(stream, "O %s %s\n", src_file,
  934.              (equal(src_system, dest_system) ? " " : src_system) );
  935.          continue;
  936.       } /* if (f_remote == OUTPUT_FILE) */
  937.  
  938.       remote_file = src_file;
  939.       if (!equal(src_system, dest_system))
  940.       {
  941.          remote_file += strlen(src_file);
  942.          while (remote_file > src_file  /* Keep trailing / and :  */
  943.                 && (*--remote_file == '/'
  944.                     /* || *remote_file == '\\' */
  945.                     || *remote_file == ':'))
  946.             ;
  947.          while (remote_file > src_file  /* Stop at other / and :  */
  948.                 && remote_file[-1] != '/'
  949.                 /* && remote_file[-1] != '\\' */
  950.                 && remote_file[-1] != ':')
  951.             --remote_file;
  952.          /* remote_file is now src_file without any leading drive/path */
  953.       } /* if (!equal(src_system, dest_system)) */
  954.  
  955.       if (f_remote == DATA_FILE)
  956.       {
  957.  
  958.          strcat(command, " ");
  959.          strcat(command, remote_file);
  960.  
  961.       } /* if (f_remote == DATA_FILE) */
  962.  
  963. /*--------------------------------------------------------------------*/
  964. /*    if both source & dest are not the same we must copy src_file    */
  965. /*--------------------------------------------------------------------*/
  966.  
  967.       if ( !equal(src_system, dest_system) )
  968.       {
  969.  
  970.          sprintf(dest_file, dataf_fmt, 'D', src_system, sequence_s, subseq());
  971.  
  972.          if (f_remote == DATA_FILE)
  973.             fprintf(stream, "F %s %s\n", dest_file, remote_file);
  974.          else
  975.             fprintf(stream, "F %s\nI %s\n", dest_file, dest_file );
  976.  
  977. /*--------------------------------------------------------------------*/
  978. /*      if source is remote and dest is local copy source to local    */
  979. /*      if source is local and dest is remote copy source to remote   */
  980. /*--------------------------------------------------------------------*/
  981.  
  982.          if ((s_remote && !d_remote) || (!s_remote && d_remote))
  983.          {
  984.             if (!do_copy(src_system, src_file, dest_system, dest_file))
  985.                return FALSE;
  986.          } /* if ((s_remote && !d_remote) || (!s_remote && d_remote)) */
  987.  
  988. /*--------------------------------------------------------------------*/
  989. /*      if both source & dest are on remote nodes we need uuxqt       */
  990. /*--------------------------------------------------------------------*/
  991.  
  992.          else if (s_remote && d_remote)
  993.          {
  994.             if (!do_uuxqt(job_id,
  995.                           src_system,
  996.                           remote_file,
  997.                           dest_system,
  998.                           dest_file))
  999.                return FALSE;
  1000.  
  1001.             if (!do_copy(src_system, src_file, E_nodename, dest_file))
  1002.                return FALSE;
  1003.  
  1004.          } /* else if (s_remote && d_remote) */
  1005.  
  1006.             continue;
  1007.       } /* if ( !equal(src_system, dest_system) ) */
  1008.       else if (f_remote == INPUT_FILE)
  1009.          fprintf(stream, "I %s\n", src_file);
  1010.  
  1011.       printmsg(4, "system \"%s\", rest \"%s\"", src_system, src_file);
  1012.  
  1013.    } /* for (; optind < argc; optind++) */
  1014.  
  1015. /*--------------------------------------------------------------------*/
  1016. /*  Create the data file if any to send to the remote system          */
  1017. /*--------------------------------------------------------------------*/
  1018.  
  1019.    if (flags[FLG_READ_STDIN]) {
  1020.       if (i_remote) {
  1021.          printmsg(0, "uux - multiple input files specified");
  1022.          return FALSE;
  1023.       }
  1024.  
  1025.       sprintf(rifile, dataf_fmt, 'D', E_nodename, sequence_s, subseq());
  1026.       sprintf(lifile, dataf_fmt, 'D', E_nodename, sequence_s, subseq());
  1027.  
  1028.       importpath(msname, lifile, dest_system);
  1029.       mkfilename(msfile, E_spooldir, msname);
  1030.  
  1031.       if (!CopyData( NULL, msfile )) {
  1032.          remove( msfile );
  1033.          return FALSE;
  1034.       }
  1035.  
  1036.       fprintf(stream, "F %s\n", rifile);
  1037.       fprintf(stream, "I %s\n", rifile);
  1038.    }
  1039.  
  1040. /*--------------------------------------------------------------------*/
  1041. /*           here finish writing parameters to the X file             */
  1042. /*--------------------------------------------------------------------*/
  1043.  
  1044.    printmsg(4, "command \"%s\"", command);
  1045.  
  1046.  
  1047.    fprintf(stream, "C %s\n", command);
  1048.    fclose(stream);
  1049.  
  1050. /*--------------------------------------------------------------------*/
  1051. /*                     create local C (call) file                     */
  1052. /*--------------------------------------------------------------------*/
  1053.  
  1054.    if (d_remote) {
  1055.       sprintf(tmfile, spool_fmt, 'C', dest_system,  grade, sequence_s);
  1056.       importpath( msname, tmfile, dest_system);
  1057.       mkfilename( msfile, E_spooldir, msname);
  1058.  
  1059.       if ( (stream = FOPEN(msfile, "a",TEXT_MODE)) == NULL) {
  1060.          printerr( msname );
  1061.          printmsg(0, "uux: cannot write/append to C file %s", msfile);
  1062.          return FALSE;
  1063.       }
  1064.  
  1065.       if (flags[FLG_READ_STDIN])
  1066.          fprintf(stream, send_cmd, lifile, rifile, E_mailbox, lifile);
  1067.  
  1068.       fprintf(stream, send_cmd, lxfile, rxfile, E_mailbox, lxfile);
  1069.  
  1070.       fclose(stream);
  1071.    }
  1072.    return TRUE;
  1073. } /* do_remote */
  1074.  
  1075. /*--------------------------------------------------------------------*/
  1076. /*    m a i n                                                         */
  1077. /*                                                                    */
  1078. /*    main program                                                    */
  1079. /*--------------------------------------------------------------------*/
  1080.  
  1081. void main(int  argc, char  **argv)
  1082. {
  1083.    int         c;
  1084.    extern char *optarg;
  1085.    extern int   optind;
  1086.  
  1087. /*--------------------------------------------------------------------*/
  1088. /*     Report our version number and date/time compiled               */
  1089. /*--------------------------------------------------------------------*/
  1090.  
  1091.    debuglevel = 0;
  1092.    banner( argv );
  1093.  
  1094. #if defined(__CORE__)
  1095.    copywrong = strdup(copyright);
  1096.    checkref(copywrong);
  1097. #endif
  1098.  
  1099.    if (!configure( B_UUCP ))
  1100.       exit(1);   /* system configuration failed */
  1101.  
  1102.    user_id = E_mailbox;
  1103.  
  1104. /*--------------------------------------------------------------------*/
  1105. /*        Process our arguments                                       */
  1106. /*--------------------------------------------------------------------*/
  1107.  
  1108. /*--------------------------------------------------------------------*
  1109.  *
  1110.  *   -aname    Use name as the user identification replacing the initiator
  1111.  *   -b        Return whatever standard input was provided to the uux command
  1112.  *   -c        Do not copy local file to the spool directory for transfer to
  1113.  *   -C        Force the copy of local files to the spool directory for
  1114.  *   -E        run job using exec
  1115.  *   -e        run job using sh
  1116.  *   -ggrade   Grade is a single letter number; lower ASCII sequence
  1117.  *   -j        Output the jobid ASCII string on the standard output which is
  1118.  *   -n        Do not notify the user if the command fails.
  1119.  *   -p        Same as -:  The standard input to uux is made the standard
  1120.  *   -r        Do not start the file transfer, just queue the job.
  1121.  *   -sfile    Report status of the transfer in file.
  1122.  *   -xdebug_level
  1123.  *   -z        Send success notification to the user.
  1124.  *
  1125. /*--------------------------------------------------------------------*/
  1126.  
  1127.    while ((c = getopt(argc, argv, "-a:bcCEejg:nprs:x:z")) !=  EOF)
  1128.       switch(c) {
  1129.       case '-':
  1130.          flags[FLG_READ_STDIN] = TRUE;
  1131.          break;
  1132.       case 'a':
  1133.          flags[FLG_USE_USERID] = TRUE;
  1134.          user_id = optarg;
  1135.          break;
  1136.       case 'b':
  1137.          flags[FLG_RETURN_STDIN] = TRUE;
  1138.          break;
  1139.       case 'c':               /* don't spool                          */
  1140.          flags[FLG_COPY_SPOOL] = FALSE;
  1141.          break;
  1142.       case 'C':               /* force spool                          */
  1143.          flags[FLG_COPY_SPOOL] = TRUE;
  1144.          break;
  1145.       case 'E':               /* use exec to execute                  */
  1146.          flags[FLG_USE_EXEC] = TRUE;
  1147.          break;
  1148.       case 'e':               /* use sh to execute                    */
  1149.          flags[FLG_USE_EXEC] = FALSE;
  1150.          break;
  1151.       case 'j':               /* output job id to stdout              */
  1152.          flags[FLG_OUTPUT_JOBID] = TRUE;
  1153.          break;
  1154.       case 'n':               /* do not notify user if command fails  */
  1155.          flags[FLG_NONOTIFY_FAIL] = TRUE;
  1156.          break;
  1157.       case 'p':
  1158.          flags[FLG_READ_STDIN] = TRUE;
  1159.          break;
  1160.       case 'r':               /* queue job only                       */
  1161.          flags[FLG_QUEUE_ONLY] = TRUE;
  1162.          break;
  1163.       case 'z':
  1164.          flags[FLG_NOTIFY_SUCCESS] = TRUE;
  1165.          break;
  1166.       case 'g':               /* set grade of transfer                 */
  1167.          grade = *optarg;
  1168.          break;
  1169.       case 's':               /* report status of transfer to file     */
  1170.          flags[FLG_STATUS_FILE] = TRUE;
  1171.          st_out = optarg;
  1172.          break;
  1173.       case 'x':
  1174.          debuglevel = atoi( optarg );
  1175.          break;
  1176.       case '?':
  1177.          usage();
  1178.          exit(1);
  1179.          break;
  1180.       default:
  1181.          printmsg(0, "uux - bad argument from getopt \"%c\"", c);
  1182.          exit(1);
  1183.          break;
  1184.    }
  1185.  
  1186.    if (argc - optind < 1)     /* Verify we have at least a command     */
  1187.    {
  1188.       printmsg(0,"uux - no command to execute!");
  1189.       usage();
  1190.       exit(1);
  1191.    }
  1192.  
  1193. #if defined(_Windows)
  1194.    openlog( NULL );
  1195.    atexit( CloseEasyWin );               /* Auto-close EasyWin on exit  */
  1196. #endif
  1197.  
  1198.    if (!do_remote(optind, argc, argv))
  1199.    {
  1200.       printmsg(0, "uux command failed");
  1201.       exit(1);
  1202.    };
  1203.  
  1204.    if (flags[FLG_OUTPUT_JOBID])
  1205.        printf("%s\n", job_id);
  1206.  
  1207.    exit(0);
  1208. } /* main */
  1209.  
  1210. /*--------------------------------------------------------------------*/
  1211. /*    s u b s e q                                                    */
  1212. /*                                                                    */
  1213. /*    Generate a valid sub-sequence number                            */
  1214. /*--------------------------------------------------------------------*/
  1215.  
  1216. static char subseq( void )
  1217. {
  1218.    static char next = '0' - 1;
  1219.  
  1220.    switch( next )
  1221.    {
  1222.       case '9':
  1223.          next = 'A';
  1224.          break;
  1225.  
  1226.       case 'Z':
  1227.          next = 'a';
  1228.          break;
  1229.  
  1230.       default:
  1231.          next += 1;
  1232.    } /* switch */
  1233.  
  1234.    return next;
  1235.  
  1236. } /* subseq */
  1237.