home *** CD-ROM | disk | FTP | other *** search
/ back2roots/padua / padua.7z / padua / uucp / duucp-1.17 / AU-117b4-src.lha / src / uucico / uucico.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-02  |  50.3 KB  |  2,390 lines

  1. /*
  2.  *  UUCICO.C
  3.  *
  4.  *  (C) Copyright 1987 by John Gilmore.
  5.  *  Copying and use of this program are controlled by the terms of the Free
  6.  *  Software Foundation's GNU Emacs General Public License.
  7.  *
  8.  *  This *MUST* be compiled with 32-bit ints.
  9.  *
  10.  *  Derived from:
  11.  *  i[$]uuslave.c     1.7 08/12/85 14:04:20
  12.  *  which came from the ACGNJ BBS system at +1 201 753 9758.  Original
  13.  *  author unknown.
  14.  *
  15.  *  Ported to Amiga by William Loftus
  16.  *  Amiga Changes Copyright 1988 by William Loftus.  All rights reserved.
  17.  *  Additional Major Changes (c)Copyright 1989-91 by Matthew Dillon, All rights reserved
  18.  *  Additional Changes (alternate send-expect) by Chris Hind Genly),
  19.  *    (c)Copyright 1991 by Chris Hind Genly, All rights Reserved
  20.  *  Xferstat support copyright 1992 by John Bickers.
  21.  *  Major changes copyright 1992, 1993 by Steve Drew.
  22.  *  Major changes copyright 1993, 1994 by Michael B. Smith.
  23.  *
  24.  *  Everyone's has reserved all their rights. So there.
  25.  */
  26.  
  27. #include <errno.h>
  28. #include "includes.h"           /* System include files, system dependent */
  29. #include "uucp.h"               /* Uucp definitions and parameters */
  30. #include <log.h>
  31. #include "version.h"
  32. #include <owndevunit.h>
  33.  
  34. IDENT (".30");
  35.  
  36. static const char
  37.     ver [] = "$VER: UUCICO 1.17.30 (2.6.94)",
  38.     Copyright [] = COPYRIGHT;
  39.  
  40. #define PROTOF_SHEREEQUALS  0x0001  /*    ProtoHacks  */
  41.  
  42. Prototype int getname (int);
  43. Prototype int get_proto (void);
  44. Prototype int instr (char *, int, int);
  45. Prototype int inline (int, char *, int);
  46. Prototype int twrite (const char *, int);
  47. Prototype void xlat_str (char *);
  48. Prototype int read_ctl (void);
  49. Prototype int do_outbound (void);
  50. Prototype int call_system (char *, int);
  51. Prototype int call_sysline (char *);
  52. Prototype int do_session (int);
  53. Prototype int top_level (int);
  54. Prototype int do_one_slave (void);
  55. Prototype int do_one_master (void);
  56. Prototype int yesno (char, int, int);
  57. Prototype int host_send_file (char *);
  58. Prototype int host_receive_file (char *);
  59. Prototype int local_send_file (char *, int *);
  60. Prototype int local_receive_file (void);
  61. Prototype int receive_file (FILE *, char *, char *, char *, int);
  62. Prototype int send_file (FILE *);
  63.  
  64. Prototype int BigGOpt;
  65. Prototype int BytesIn;
  66. Prototype int BytesOut;
  67. Prototype int debug;
  68. Prototype int DoAttempt;
  69. Prototype int ExitCode;
  70. Prototype int Getty;
  71. Prototype int IgnoreCD;
  72. Prototype int IgnoreDTR;
  73. Prototype int NoDelay;
  74. Prototype int OldPri;
  75. Prototype int Overide;
  76. Prototype int PacketTimeout;
  77. Prototype int PriMode;
  78. Prototype int ProtoHacks;
  79. Prototype int SegSize;
  80. Prototype int SendExpectTimeout;
  81. Prototype int SevenWire;
  82. Prototype int UseSubDirs;
  83. Prototype int VarPackets;
  84. Prototype int WindowSize;
  85.  
  86. Prototype char *uuspool;
  87.  
  88. void LogTimes (int);
  89. void mail_notify (char *from, char *real, char *subject);
  90. void uuxqt (void);
  91.  
  92. #define MAX_FLAGS    40
  93.  
  94. char
  95.     ttynam [NAMESIZE],        /* Name of tty we use as serial port */
  96.     srcnam [NAMESIZE],        /* Source file name */
  97.     dstnam [NAMESIZE],        /* Dest file name */
  98.     who    [NAMESIZE] = "-",        /* Who sent the file */
  99.     flags  [MAX_FLAGS],        /* Flags from file xfer cmd */
  100.     temp   [NAMESIZE];        /* Temp file name */
  101.  
  102. int
  103.     _bufsiz = 8192,         /* stdio buffer size */
  104.     ignore_time_restrictions = 0,    /* Call out even if L.sys sez no */
  105.     mode;                /* File mode from file xfer cmd */
  106.  
  107. char
  108.     host_name [MAX_HOST] = "AmigaUUCP", /* Other guy's host name */
  109.     our_name  [MAX_HOST],        /* Our uucp hostname from UULib:Config */
  110.     *uuspool;
  111.  
  112. int
  113.     UUXqtInterval = 0,  /* > 0 means start UUXqt every this many X.* files */
  114.     UUXqtPriority = -1, /* run UUXqt at this priority */
  115.     debug          = -1, /* -1 indicates not set by command line or ctl file */
  116.     f_wait          = 0,  /* wait for a call (-w) or calls (-w -e) after outbnd */
  117.     loop          = 0,  /* Loop accepting logins if tty name specified */
  118.     Overide       = 0,  /* overide modem protocol */
  119.     Getty          = 0,  /* we were -Getty initiated */
  120.     IgnoreCD      = 0,  /* xgetc() should ignore carrier */
  121.     OurNameOv     = 0,  /* use specified hostname as "us" */
  122.     WindowSize    = 999,
  123.     SegSize       = 2,
  124.     NoReScan      = 0,  /* do not rescan for work after error   */
  125.     SevenWire     = 0,  /* RTS/CTS */
  126.     XDebug          = 0,  /* do not pass debug parameter to remote    */
  127.     ExitCode      = 0,
  128.     PacketTimeout = 0,
  129.     DebugHandshake= 0,
  130.     SendExpectTimeout = SENDEXPECT_TO,
  131.     ProtoHacks,        /* protocol hack for Mac UUCP  */
  132.     PriMode,        /* up our priority by one at start, down when done */
  133.     OldPri,         /* what our starting priority is */
  134.     IgnoreDTR = 0,        /* ignore Data Terminal Ready on send() */
  135.     DoAttempt = 0,        /* don't wait on LockDevUnit(), quit instead */
  136.     BigGOpt,        /* call for 'G' proto, not 'g' */
  137.     BytesIn,        /* how many bytes received */
  138.     BytesOut,        /* how many bytes sent */
  139.     UseSubDirs = 0,     /* use system sub-directories in UUSpool: */
  140.     NoDelay = 0,        /* immediately check for more data at port */
  141.     VarPackets = 0,     /* calculate most efficient GIO packet size */
  142.     UUXqtHostname = 0;  /* tell UUXQT what hostname to use */
  143. time_t
  144.     TimeBegin1,
  145.     TimeBegin2;
  146. int
  147.     copynotify;  /* mail notify bits */
  148. char
  149.     mailsub [NAMESIZE + 100];
  150.  
  151. #define CTRLFILE(f) (f [1] == '.' && (f [0] == 'D' || f [0] == 'X' || f [0] == 'C'))
  152.  
  153. struct Library
  154.     *OwnDevUnitBase = NULL;
  155.  
  156. #define MAX_STRING    200    /* Max length string to send/expect */
  157. #define MSGO2IDX    6
  158.  
  159. /* We print these prompts */
  160.  
  161. char
  162.     msgo0    [] = "login: ",
  163.     msgo1    [] = "Password:",
  164.     msgo2    [10 + MAX_HOST] = { "\20Shere" },   /*  NO =    */
  165.     msgo3    [] = "\20ROK\0",
  166.     msgo3a    [] = "\20P",
  167.     msgo3bg [] = "\20Pg\0",
  168.     msgo3bG [] = "\20PG\0",
  169.     msgo4    [] = "\20OOOOOOO\0";
  170.  
  171. /* We expect to receive these strings */
  172.  
  173. char
  174.     msgi0  [] = "uucp\r",
  175.     msgi1  [] = "s8000\r",
  176.      /* msgi2  [] = "\20S*\0", We now scan it specially FIXME */
  177.     msgi3g [] = "\20Ug\0",
  178.     msgi3G [] = "\20UG\0",
  179.     msgi4  [] = "OOOOOO";
  180.  
  181. /*
  182.  * Protocol switch data structure
  183.  */
  184.  
  185. #define turnon    gturnon
  186. #define rdmsg    grdmsg
  187. #define wrmsg    gwrmsg
  188. #define rddata    grddata
  189. #define wrdata    gwrdata
  190. #define turnoff gturnoff
  191.  
  192. int
  193. getname (int isshere)
  194. {
  195.     int
  196.         data,
  197.         count = 0;
  198.     static char
  199.         msgi [MAX_STRING + SLOP];  /* Incoming trash buffer */
  200.  
  201.     /* Read data until null character */
  202.  
  203.     while ((data = xgetc (BYTE_TO, 0)) != EOF) {
  204.         data &= 0x7F;
  205.         if (data == 020)
  206.             break;
  207.     }
  208.  
  209.     if (data == EOF)
  210.         return FAIL;
  211.  
  212.     while ((data = xgetc (BYTE_TO, 0)) != EOF && (data & 0x7F)) {
  213.         data &= 0x7F;
  214.         if (count == 0 && data != 'S')
  215.             continue;
  216.         if (count > sizeof (msgi) - 2)
  217.             continue;
  218.         if (data == 0x0A)    /*  hack fix for tuvie ? */
  219.             break;
  220.         msgi [count++] = (char) data;
  221.     }
  222.     msgi [count] = 0;
  223.  
  224.     if (debug > 8)
  225.         printf ("GETNAME MSG (%d): %s\n", count, msgi);
  226.  
  227.     if (msgi [0] != 'S')
  228.         return FAIL;
  229.  
  230.     if (isshere) {
  231.         for (count = 1; msgi[count] && msgi[count] != '='; ++count)
  232.             ;
  233.         if (msgi [count] == '=')
  234.             ++count;
  235.     }
  236.     else {
  237.         count = 1;
  238.     }
  239.  
  240.     if (msgi [count]) {
  241.         strncpy (host_name, msgi + count, MAX_HOST-1);
  242.         host_name [MAX_HOST-1] = '\0';
  243.         if (debug > 8)
  244.             printf ("Compare host names: '%s' '%s'\n", host_name, msgi + count);
  245.     }
  246.  
  247.     strtok (host_name, " \t");     /*  put \0 after hostname */
  248.  
  249.     ulog (-1, "Hostname is '%s'", host_name);
  250.  
  251.     return SUCCESS;
  252. }
  253.  
  254. /*
  255.  *  get_proto() checks the list of protos given by the foreign machine
  256.  *  checking for 'g' (which is the only proto we have).  Use only in master
  257.  *  mode.
  258.  */
  259.  
  260. int
  261. get_proto (void)
  262. {
  263.     int
  264.         data;
  265.  
  266.     while ((data = xgetc (BYTE_TO, 0)) != EOF) {
  267.         data &= 0x7F;
  268.         if (data == 0)
  269.             break;
  270.         if (data == 'g')
  271.             return SUCCESS;
  272.     }
  273.  
  274.     return FAIL;
  275. }
  276.  
  277. /*
  278.  * Medium level input routine.
  279.  *
  280.  * Look for an input string for the send-expect sequence.
  281.  * Return 0 for matching string, 1 for timeout before we found it.
  282.  * FIXME:  we only time out if the other end stops sending.  If it
  283.  *       keeps sending, we keep listening forever.
  284.  */
  285.  
  286. int
  287. instr (char *s, int n, int to)
  288. {
  289.     int
  290.         i,
  291.         data,
  292.         count = 0,
  293.         j;
  294.     static char
  295.         msgi [512];  /* Incoming trash buffer */
  296.  
  297.     if (to == 0)
  298.         /* 'to' is timeout */
  299.         to = BYTE_TO;
  300.  
  301.     if (debug > 8) {
  302.         printf ("Expecting '");
  303.         for (i = 0; i < n; i++)
  304.             printc (s [i]);
  305.         printf ("'\n");
  306.     }
  307.  
  308.     if (DebugHandshake) {
  309.         printf ("recvd (len %ld, to %ld): '", n, to);
  310.         fflush (stdout);
  311.     }
  312.  
  313.     while ((data = xgetc (to, 0)) != EOF) {
  314.         data &= 0x7F;
  315.  
  316.         msgi [count++] = data;
  317.  
  318.         if (DebugHandshake) {
  319.             printc (data);
  320.             fflush (stdout);
  321.         }
  322.  
  323.         if (count == sizeof (msgi)) {     /*  throw away first half */
  324.             count = sizeof (msgi) / 2;
  325.             bcopy (msgi + sizeof (msgi) / 2, msgi, sizeof (msgi) / 2);
  326.         }
  327.  
  328.         if (count >= n) {
  329.             for (i = n - 1, j = count - 1; i >= 0; i--, j--) {
  330.                 if (*(s+i) != msgi [j])
  331.                     break;
  332.             }
  333.             if (i < 0) {
  334.                 if (debug > 8)
  335.                     printf ("\n");
  336.                 if (DebugHandshake)
  337.                     printf ("' (GOTIT!)\n");
  338.                 return SUCCESS;
  339.             }
  340.         }
  341.     }
  342.  
  343.     if (DebugHandshake)
  344.         printf ("' (TIMEOUT!)\n");
  345.  
  346.     if (debug > 8)
  347.         printf ("\n");
  348.  
  349.     msgi [count] = '\0';
  350.  
  351.     return FAIL;
  352. }
  353.  
  354. /*
  355.  * Medium level input routine.
  356.  *
  357.  *  input a line, return -1 on timeout condition else 0
  358.  */
  359.  
  360. int
  361. inline (int to, char *buf, int max)
  362. {
  363.     int
  364.         c,
  365.         i = 0;
  366.  
  367.     --max;
  368.     if (to == 0)
  369.         to = BYTE_TO;
  370.  
  371.     if (debug > 8 || DebugHandshake) {
  372.         printf ("Inline: ");
  373.         fflush (stdout);
  374.     }
  375.  
  376.     while ((c = xgetc (to, 0)) != EOF && i < max) {
  377.         if (c == '\n' || c == '\r')
  378.             break;
  379.         if (debug > 8 || DebugHandshake)
  380.             printf ("%c", c);
  381.         buf [i++] = c;
  382.     }
  383.     if (debug > 8 || DebugHandshake)
  384.         printf (" (%d c=%d)\n", i, c);
  385.  
  386.     buf [i] = 0;
  387.  
  388.     if (c == EOF)
  389.         return -1;
  390.  
  391.     return 0;
  392. }
  393.  
  394. /*
  395.  * Debugging hack for stuff written to the modem.
  396.  */
  397.  
  398. int
  399. twrite (const char *s, int n)
  400. {
  401.     int
  402.         i;
  403.  
  404.     if (debug > 8) {
  405.         printf ("Wrote:  ");
  406.         for (i = 0; i < n; i++)
  407.             printc (s [i]);
  408.         printf ("\n");
  409.     }
  410.  
  411.     return xwrite (s, n);
  412. }
  413.  
  414. void
  415. myexit (void)
  416. {
  417.     if (PriMode) {
  418.         struct Task
  419.             *task = FindTask (NULL);
  420.  
  421.         SetTaskPri (task, OldPri);
  422.     }
  423.  
  424.     UnLockFiles ();
  425.  
  426.     if (OwnDevUnitBase) {
  427.         CloseLibrary (OwnDevUnitBase);
  428.         OwnDevUnitBase = NULL;
  429.     }
  430.  
  431.     return;
  432. }
  433.  
  434. /*
  435.  * MAIN ROUTINE.
  436.  *
  437.  * This is called at program startup.  It parses the arguments to the
  438.  * program (if any) and sets up to receive a call on the modem.
  439.  *
  440.  * If there are no arguments, we assume the caller is already on standard
  441.  * input, waiting to do uucp protocols (past the login prompt), and we
  442.  * just handle one caller.
  443.  *
  444.  * If there is an argument, it is the name of the tty device where we
  445.  * should listen for multiple callers and handle login and password.
  446.  */
  447.  
  448. int
  449. main (int argc, char **argv)
  450. {
  451.     char
  452.         *poll_sys = NULL;        /* System name to poll, or none */
  453.     int
  454.         i,
  455.         rmode = 0;            /* 1 = master, 0 = slave        */
  456.     static const char
  457.         odu_name [] = { ODU_NAME };
  458.  
  459.     LogProgram = argv [0];
  460.     LogHost = host_name;
  461.     LogWho    = who;
  462.  
  463.     signal (SIGINT, sigint);
  464.     atexit (myexit);
  465.  
  466.     if ((OwnDevUnitBase = OpenLibrary (odu_name, 0)) == NULL) {
  467.         fprintf (stderr, "Unable to open %s\n", odu_name);
  468.         ulog (-1, "ERROR: cannot open %s", odu_name);
  469.         exit (20);
  470.     }
  471.  
  472.     /* FIXME, use getopt */
  473.     /* scan command line arguments, kinda kludgy but it works */
  474.  
  475.     for (i = 1; i < argc; ++i) {
  476.         char
  477.             *ptr = argv [i];
  478.  
  479.         if (*ptr != '-') {
  480.             fprintf (stderr, "%s: warning, extra args ignored: %s\n", argv [0], argv [i]);
  481.             ulog (-1, "WARNING: extra args ignored: %s", argv [i]);
  482.             break;
  483.         }
  484.         ptr += 2;
  485.         switch (ptr [-1]) {
  486.             case 'N':
  487.                 {
  488.                 int
  489.                     len;
  490.                 char
  491.                     *p = *ptr ? ptr : argv [++i];
  492.  
  493.                 if ((len = strlen (p)) > (MAX_HOST - 1))
  494.                     len = MAX_HOST - 1;
  495.  
  496.                 our_name [len] = '\0';
  497.                 strncpy (our_name, p, len);
  498.  
  499.                 OurNameOv = 1;
  500.                 }
  501.  
  502.                 break;
  503.             case 'D':       /*  Serial Device   */
  504.                 {
  505.                 char
  506.                     *p;
  507.  
  508.                 /* could be any of:
  509.                 **    -Dserial.sevice
  510.                 **    -D serial.device
  511.                 **    -DEVICE serial.device
  512.                 **    -DEVICEserial.device
  513.                 */
  514.                 if (strnicmp (ptr, "EVICE", 5) == 0)
  515.                     ptr += 5;
  516.                 p = *ptr ? ptr : argv [++i];
  517.                 DeviceName = p;
  518.                 }
  519.                 break;
  520.             case 'U':       /*  Serial Unit     */
  521.                 {
  522.                 char
  523.                     *p;
  524.  
  525.                 /* could be any of:
  526.                 **    -U0
  527.                 **    -U 0
  528.                 **    -UNIT 0
  529.                 **    -UNIT0
  530.                 */
  531.                 if (strnicmp (ptr, "NIT", 3) == 0)
  532.                     ptr += 3;
  533.                 p = *ptr ? ptr : argv [++i];
  534.                 DeviceUnit = atoi (p);
  535.                 }
  536.                 break;
  537.             case 'p':       /*  protocol hacks  */
  538.                 if (strcmp (ptr, "ri") == 0) {   /*  -pri    */
  539.                     struct Task
  540.                         *task = FindTask (NULL);
  541.  
  542.                     PriMode = 1;
  543.                     OldPri = SetTaskPri (task, 5);
  544.                     SetTaskPri (task, OldPri + 1);
  545.                 }
  546.                 else
  547.                 if (strcmp (ptr, "G") == 0) {
  548.                     /*
  549.                      *  XXX in development, does NOT work yet!
  550.                      */
  551.  
  552.                     BigGOpt = 1;
  553.                 }
  554.                 else
  555.                 if (strcmp (ptr, "g") == 0) {
  556.                     /*
  557.                     ** allow direct specification of 'g'
  558.                     */
  559.                     BigGOpt = 0;
  560.                 }
  561.                 else
  562.                 if (strcmp (ptr, "ackets") == 0) {
  563.                     VarPackets = 1;
  564.                 }
  565.                 else {                  /*  -proto  */
  566.                     char
  567.                         *p = (*ptr && *ptr >= '0' && *ptr <= '9') ? ptr : argv [++i];
  568.  
  569.                     ProtoHacks |= atoi (p);
  570.                 }
  571.                 break;
  572.             case 'Q':
  573.                 UUXqtHostname = 1;
  574.                 break;
  575.             case 'g':
  576.             case 'G':
  577.                 /* careful! could be "-GETTY" or "-getty" */
  578.                 Getty = 1;
  579.                 break;
  580.             case 'h':
  581.                 IgnoreCD = 1;
  582.                 break;
  583.             case 'w':
  584.                 ++f_wait;
  585.                 break;
  586.             case 'r':
  587.                 {
  588.                 char
  589.                     *p = *ptr ? ptr : argv [++i];
  590.  
  591.                 rmode = atoi (p);
  592.                 }
  593.                 break;
  594.             case 'X':
  595.                 XDebug = 1;
  596.                 /* FALLTHROUGH */
  597.             case 'x':
  598.                 if (*ptr == 'x') {
  599.                     DebugHandshake = 1;
  600.                     break;
  601.                 }
  602.  
  603.                 debug = atoi (*ptr ? ptr : argv [++i]);
  604.                 LogLevel = debug;
  605.                 LogToStdout = 0;
  606.                 printf ("uucico: debug level set to %d\n", debug);
  607.                 break;
  608.             case 'o':
  609.                 Overide = 1;
  610.                 break;
  611.             case 'n':
  612.                 if (*ptr && strcmp ("odelay", ptr) == 0) {
  613.                     NoDelay = 1;
  614.                     break;
  615.                 }
  616.  
  617.                 WindowSize = atoi (*ptr ? ptr : argv [++i]);
  618.                 if ((WindowSize < 1) || (WindowSize > 7)) {
  619.                     fprintf (stderr, "%s: warning, -n must be between 1 and 7: %ld\n", argv [0], WindowSize);
  620.                     ulog (-1, "WARNING: -n must be between 1 and 7: %ld", WindowSize);
  621.                     WindowSize = 1;
  622.                 }
  623.                 break;
  624.             case 'P':
  625.                 {
  626.                 char
  627.                     *p = *ptr ? ptr : argv [++i];
  628.  
  629.                 SegSize = atoi (p);
  630.                 if ((SegSize < 2) || (SegSize > 8)) {
  631.                     fprintf (stderr, "%s: warning, -P must be between 2 and 8: %ld\n", argv [0], SegSize);
  632.                     ulog (-1, "WARNING: -P must be between 2 and 8: %ld", SegSize);
  633.                     SegSize = 2;
  634.                 }
  635.                 }
  636.                 break;
  637.             case 'b':
  638.                 system (GetConfigProgram (BATCHNEWS));
  639.                 break;
  640.             case 'S':
  641.                 ignore_time_restrictions++;
  642.                 /* FALLTHROUGH */
  643.             case 's':
  644.                 {
  645.                 char
  646.                     *p = *ptr ? ptr : argv [++i];
  647.  
  648.                 poll_sys = p;
  649.                 }
  650.                 break;
  651.             case 'e':
  652.                 ++loop;
  653.                 break;
  654.             case 't':
  655.                 {
  656.                 char
  657.                     *p = *ptr ? ptr : argv [++i];
  658.  
  659.                 PacketTimeout = atoi (p);
  660.                 }
  661.                 break;
  662.             case 'T':
  663.                 {
  664.                 char
  665.                     *p = *ptr ? ptr : argv [++i];
  666.  
  667.                 SendExpectTimeout = atoi (p);
  668.                 }
  669.                 break;
  670.             case '7':
  671.                 SevenWire = 1;
  672.                 break;
  673.             case 'd':
  674.                 /* could be:
  675.                 **    -d0
  676.                 **    -d 0
  677.                 **    -d -other_arg
  678.                 */
  679.                 if (*ptr)
  680.                     IgnoreDTR = !atoi (ptr);
  681.                 else {
  682.                     if (isdigit (*argv [i + 1]))
  683.                         IgnoreDTR = !atoi (argv [++i]);
  684.                     else
  685.                         IgnoreDTR = 1;
  686.                 }
  687.                 break;
  688.             case 'H':
  689.                 IgnoreCD = 1;
  690.                 Overide = 1;
  691.                 break;
  692.             case 'B':
  693.                 {
  694.                 char
  695.                     *p = *ptr ? ptr : argv [++i];
  696.  
  697.                 /* throw away baud rate argument */
  698.                 }
  699.                 break;
  700.             case 'A':
  701.                 DoAttempt = 1;
  702.                 break;
  703.             default:
  704.                 fprintf (stderr, "uucico: warning, bad flag %s\n", argv [i]);
  705.                 ulog (-1, "WARNING: bad argument %s", argv [i]);
  706.                 break;
  707.         }
  708.     }
  709.  
  710.     read_ctl ();
  711.  
  712.     if (DeviceName)
  713.         sprintf (ttynam, "%s/%ld", DeviceName, DeviceUnit);
  714.  
  715.     /*
  716.      * If running via getty/login, our debug stdout had better
  717.      * go to a file, not to the usual stdout!
  718.      */
  719.  
  720.     if (debug > 0 && Getty) {
  721.         freopen ("T:uucico.log", "a", stdout);
  722.     }
  723.  
  724.     /* Timestamp the long debug log */
  725.  
  726.     if (debug > 0) {
  727.         long
  728.             clock;
  729.  
  730.         time (&clock);
  731.         printf ("\nuucico log for '%s' starting %s\n",
  732.             ttynam, ctime (&clock));
  733.     }
  734.  
  735.     /* Log our presence so we humans reading the logs can find the
  736.        entries created by uuslave. */
  737.  
  738.     ulog (-1, "Startup %s", VERSION);
  739.  
  740.     amiga_setup ();
  741.     modem_init ();
  742.  
  743.     if (poll_sys) {
  744.         if (*poll_sys == '\0')
  745.             poll_sys = NULL;
  746.  
  747.         if (call_system (poll_sys, rmode) == FAIL)
  748.             ExitCode = 5;
  749.  
  750.         if (!f_wait)
  751.             goto end;
  752.     }
  753.     else {
  754.         if (rmode) {
  755.             if (do_outbound () == FAIL)
  756.                 ExitCode = 5;
  757.             if (!f_wait)
  758.                 goto end;
  759.         }
  760.     }
  761.  
  762.     do {
  763.         /*
  764.          *  Set up serial channel, wait for incoming call.
  765.          */
  766.  
  767.         DEBUG (0, "\nRestarting\n", 0);
  768.  
  769.         if (Getty == 0 && Overide == 0)
  770.             openline ();
  771.  
  772.         do_session (Getty);
  773.         LogTimes (0);
  774.         hangup ();
  775.         DEBUG (0, "\nEnd of call\n", 0);
  776.     } while (loop && !Getty);
  777.  
  778. end:
  779.     cleanup ();
  780.     return ExitCode;
  781. }
  782.  
  783. /*
  784.  * translate embedded escape characters
  785.  */
  786.  
  787. void
  788. xlat_str (char *msg)
  789. {
  790.     int
  791.         i  = 0,
  792.         cr = 1;
  793.  
  794.     if (DebugHandshake)
  795.         printf ("Send = '%s'\n", msg);
  796.  
  797.     while (msg [i]) {
  798.         if (msg [i] == '\\') {
  799.             switch (msg [++i]) {
  800.                 case 'r':            /* carriage return */
  801.                     twrite ("\r", 1);
  802.                     break;
  803.                 case 'n':            /* line feed */
  804.                     twrite ("\n", 1);
  805.                     break;
  806.                 case '\\':           /* back slash */
  807.                     twrite ("\\", 1);
  808.                     break;
  809.                 case 't':            /* tab */
  810.                     twrite ("\t", 1);
  811.                     break;
  812.                 case 'b':
  813.                     SendBreak ();
  814.                     break;
  815.                 case 'd':            /* delay */
  816.                     Delay (180);
  817.                     break;
  818.                 case 's':            /* space */
  819.                     twrite (" ", 1);
  820.                     break;
  821.                 case 'c':            /* no CR at end */
  822.                     cr = 0;
  823.                     break;
  824.                 default:        /* don't know so skip it */
  825.                     break;
  826.             }
  827.             ++i;
  828.         }
  829.         else {
  830.             twrite (msg + i, 1);
  831.             ++i;
  832.         }
  833.     }
  834.     if (cr) {
  835.         twrite ("\r", 1);
  836.     }
  837.     return;
  838. }
  839.  
  840. /*
  841.  * Get some parameters from the configuration file (used to be uucp.ctl)
  842.  */
  843.  
  844. int
  845. read_ctl (void)
  846. {
  847.     const char
  848.         *nodename = FindConfig (NODENAME),
  849.         *debugstr = FindConfig (DEBUGNAME),
  850.         *uuxqtint = FindConfig (UUXQTINTERVAL),
  851.         *uuxqtpri = FindConfig (UUXQTPRIORITY),
  852.         *tmp;
  853.  
  854.     if (nodename && OurNameOv == 0)
  855.         strcpy ((char *) our_name, nodename);
  856.     if (debugstr && debug < 0)
  857.         debug = atoi (debugstr);
  858.     if (uuxqtint)
  859.         UUXqtInterval = atoi (uuxqtint);
  860.     if (uuxqtpri)
  861.         UUXqtPriority = atoi (uuxqtpri);
  862.  
  863.     tmp = GetConfig (USESUBDIRS, "n");
  864.     if (*tmp == 'y' || *tmp == 'Y' || *tmp == '1')
  865.         UseSubDirs = 1;
  866.  
  867.     uuspool = GetConfigDir (UUSPOOL);
  868.  
  869.     /*
  870.      * sd, get copy notify bits
  871.      *
  872.      *  1 - notify of send failures that will not be retried (ie denied)
  873.      *  2 - notify of send failures that will be retried (ie protocol errors)
  874.      *  4 - notify of successfull outgoing file copy (uucp'd copies only)
  875.      *  8 - notify of incoming file (uucp'd file copies only)
  876.      * 16 - notify of incoming failure of anykind
  877.      *
  878.      * i.e., set to 31 for all features.
  879.      * mail is sent to username config entry for incoming file and to
  880.      * originator of outgoing file copies (usually the same username)
  881.      */
  882.  
  883. #define NOTIFY_FAILED    1
  884. #define NOTIFY_RETRY    2
  885. #define NOTIFY_SUCCESS    4
  886. #define NOTIFY_INCOMING 8
  887. #define NOTIFY_INCOMING_FAILURE 16
  888.  
  889.     tmp = FindConfig ("CopyNotify");
  890.     if (tmp) {
  891.         copynotify = atoi (tmp);
  892.     }
  893.  
  894.     return 1;
  895. }
  896.  
  897. /*
  898.  *  Search spool queues for work, call the systems we need to call.
  899.  *
  900.  *  return FAIL if any system has failed, SUCCESS otherwise.
  901.  */
  902.  
  903. int
  904. do_outbound (void)
  905. {
  906.     return call_system (NULL, 1);
  907. }
  908.  
  909. /*
  910.  *  Call a specific system, or all systems that have work pending.
  911.  *
  912.  *  If a failure occurs with any system, return FAIL, else return
  913.  *  SUCCESS.
  914.  */
  915.  
  916. int
  917. call_system (char *sys, int ifworkpend)
  918. {
  919.     FILE
  920.         *lsys;
  921.     static char
  922.         buf [MAX_LSYS],
  923.         sysnam [MAX_HOST],
  924.         prev_name [MAX_HOST];
  925.     int
  926.         called = FAIL,
  927.         status = SUCCESS;
  928.  
  929.     /*
  930.      * Unix uucico just reads the directory, and calls the systems
  931.      * in the order of the files in the directory.    We want more
  932.      * control than that, though I'm not sure that L.sys order is
  933.      * best either.  For example, in the first call after 11PM,
  934.      * I'd like to call the sites that haven't been callable before
  935.      * 11PM first, and finish up with the ones I've been able to call
  936.      * all day.  FIXME.
  937.      */
  938.  
  939.     if (!(lsys = fopen (MakeConfigPath (UULIB, "L.sys"), "r"))) {
  940.         DEBUG (0, "uucico: can't open L.sys, errno %d\n", errno);
  941.         return FAIL;
  942.     }
  943.     sysnam [0] = '\0';               /* Initially, no previous sys */
  944.  
  945.     /* Once per system in L.sys... */
  946.     /* FIXME, handle continuation lines (trailing "\") */
  947.  
  948.     while (fgets (buf, sizeof buf, lsys)) {
  949.         if (buf [0] == '#' || buf [0] == '\n')
  950.             continue;
  951.  
  952.         /*
  953.          * Grab the system name.  If same as previous, and
  954.          * the previous call worked, skip it.
  955.          */
  956.  
  957.         strcpy (prev_name, sysnam);
  958.         sscanf (buf, "%s", sysnam);
  959.         if (strcmp (sysnam, prev_name) == 0) {
  960.             if (called == SUCCESS)
  961.                 continue;
  962.         }
  963.  
  964.         /*
  965.          * If a system name was specified, skip til we find it
  966.          * If none was specified, only call if there is work.
  967.          */
  968.  
  969.         if (sys) {
  970.             if (strcmp (sys, sysnam))
  971.                 continue;
  972.             if (ifworkpend && work_scan (sysnam) == 0) {
  973.                 ulog (-1, "No work for system %s", sysnam);
  974.                 called = SUCCESS;
  975.                 continue;
  976.             }
  977.         }
  978.         else {
  979.             DEBUG (3, "searching for outbound to %s\n", sysnam);
  980.             if (work_scan (sysnam) == 0) {
  981.                 DEBUG (3,"no work for %s\n", sysnam);
  982.                 called = SUCCESS;    /* Don't try further */
  983.                 continue;
  984.             }
  985.             DEBUG (2, "uucico: found work for %s\n", sysnam);
  986.         }
  987.  
  988.         /*
  989.          *  call system.  If calling a single system and it succeeds, break
  990.          *  out of loop.  If calling a single system with multiple L.Sys
  991.          *  lines, a later success overides an initial failure in terms of
  992.          *  the return code.
  993.          *
  994.          *  If calling all systems any failure causes a failure return code
  995.          *  XXX FIXME, handling multiple L.Sys entries for same system ???
  996.          */
  997.  
  998.         called = call_sysline (buf);
  999.  
  1000.         if (sys) {
  1001.             status = called;
  1002.             if (called == SUCCESS)
  1003.                 break;
  1004.         }
  1005.         else {
  1006.             if (called == FAIL)
  1007.                 status = FAIL;
  1008.         }
  1009.     }
  1010.     fclose (lsys);
  1011.  
  1012.     if (sys && called == FAIL && status == SUCCESS) {
  1013.         ulog (-1, "Unknown system '%s'", sys);
  1014.     }
  1015.  
  1016.     return status;
  1017. }
  1018.  
  1019. /*
  1020.  *  Call out to a system, given its L.sys line.
  1021.  *
  1022.  *  Return FAIL if any failure occurs, SUCCESS if all went well.
  1023.  */
  1024.  
  1025. int
  1026. call_sysline (char *lsysline)
  1027. {
  1028.     static char
  1029.         tempname [MAX_HOST + 30 + SLOP];
  1030.     char
  1031.         *pnum,
  1032.         *sysnam,
  1033.         *times,
  1034.         *acu,
  1035.         *sbaud,
  1036.         *telno,
  1037.         *send,
  1038.         *expct,
  1039.         *expct1,
  1040.         *errm;
  1041.     int
  1042.         baud,
  1043.         sendexpectok,
  1044.         r;
  1045.  
  1046.     who [0] = '-';
  1047.     who [1] = '\0';    /* No user now (for logit) */
  1048.  
  1049.     /* FIXME, use the values it is ignoring here */
  1050.  
  1051.     sysnam = strtok (lsysline, " \t"); /* System */
  1052.     times  = strtok (NULL, " \t");     /* Time   */
  1053.     acu    = strtok (NULL, " \t");     /* ACU    */
  1054.     sbaud  = strtok (NULL, " \t");     /* Baud   */
  1055.     telno  = strtok (NULL, " \t");     /* phone  */
  1056.  
  1057.     strcpy (host_name, sysnam);
  1058.  
  1059.     if (ignore_time_restrictions == 0) {
  1060.         if (CheckTimeRestrictions (times) == FAIL) {
  1061.             ulog (-1, "Wrong Time To Call %s", sysnam);
  1062.             return FAIL;
  1063.         }
  1064.     }
  1065.  
  1066.     baud = atoi (sbaud);
  1067.  
  1068.     /* FIXME, acu not implemented in Devices file */
  1069.     /* AmigaUUCP uses -D and -U instead.          */
  1070.  
  1071.     DEBUG (4, "Opening outgoing line %s\n", acu);
  1072.  
  1073.     if (openout (acu, baud) != SUCCESS)
  1074.         return FAIL;
  1075.  
  1076.     /* sd added telno logging */
  1077.     for (pnum = (telno + strlen (telno)) -1 ; pnum > telno; --pnum) {
  1078.         if (isalpha (*pnum)) {
  1079.             ++pnum;
  1080.             break;
  1081.         }
  1082.     }
  1083.  
  1084.     if (Overide == 0) {
  1085.         char
  1086.             *errmsg;
  1087.  
  1088.         if (errmsg = dial_nbr (telno)) {
  1089.             ulog (-1, "FAILED call to %s (%s): %s", host_name, pnum, errmsg);
  1090.             return FAIL;
  1091.         }
  1092.     }
  1093.  
  1094.     TimeBegin1 = time (NULL);
  1095.     TimeBegin2 = 0;
  1096.     BytesIn = 0;
  1097.     BytesOut= 0;
  1098.  
  1099.     /* FIXME, log tty, baud rate, ... */
  1100.  
  1101.     ulog (-1, "DIALED %s (%s)", host_name, pnum);
  1102.  
  1103.     /*
  1104.      * Process send-expect strings.
  1105.      * FIXME, deal with "-", BREAK, etc.
  1106.      */
  1107.  
  1108.     if (DebugHandshake)
  1109.         puts ("CONNECTED, running send-expect strings");
  1110.  
  1111.     sendexpectok = TRUE;
  1112.  
  1113.     do {
  1114.         expct = strtok (NULL, " \t");
  1115.         if (expct == NULL)
  1116.             break;
  1117.  
  1118.         expct1 = strtokp (&expct, "-");
  1119.  
  1120.         while (expct1) {
  1121.             if (expct1 [0] != '"' || expct1 [1] != '"' || expct1 [2] != '\0') {
  1122.                 if (instr (expct1, strlen (expct1), SendExpectTimeout) == SUCCESS)
  1123.                     break;
  1124.             }
  1125.             else {
  1126.                 if (DebugHandshake)
  1127.                     puts ("Expect Nothing");
  1128.                 break;
  1129.             }
  1130.             /*
  1131.              *  expect failed, check for alternates
  1132.              */
  1133.  
  1134.             errm = expct1;
  1135.             if (expct1 = strtokp (&expct, "-")) {
  1136.                 xlat_str (expct1);
  1137.             }
  1138.             else {
  1139.                 sendexpectok = FALSE;
  1140.                 strtok ("", " ");
  1141.                 break;
  1142.             }
  1143.             expct1 = strtokp (&expct, "-");
  1144.         }
  1145.         if (sendexpectok == FALSE) {
  1146.             ulog (1, "Send/Expect failure");
  1147.             break;
  1148.         }
  1149.         if (send = strtok (NULL, " \t\n")) {
  1150.             xlat_str (send);
  1151.         }
  1152.     } while (send);
  1153.  
  1154.     TimeBegin2 = time (NULL);
  1155.  
  1156.     if (sendexpectok)
  1157.         ulog (-1, "SUCCEEDED call to %s", host_name);
  1158.     else {
  1159.         ulog (-1, "FAILED call to %s.  Expected %s", host_name, errm);
  1160.         goto bort1;
  1161.     }
  1162.  
  1163.     if (getname (1))     /*  get name         */
  1164.         goto bort1;
  1165.  
  1166.     /*  send response   */
  1167.     sprintf (tempname, "\20S%s -Q0 -x%d\0", our_name, XDebug ? 0 : debug);
  1168.     twrite (tempname, strlen (tempname) + 1); /* Including null */
  1169.  
  1170.     /* wait for ok message, wait for protocol request
  1171.      * send protocol 'g' response */
  1172.  
  1173.     /* FIXME, we don't actually wait for the ROK message, since
  1174.      * it is immediately followed by the Pprotos message.  We
  1175.      * currently just look for a Pg message.  This needs work.
  1176.      */
  1177.  
  1178.     if (instr (msgo3a, sizeof (msgo3a) - 1, 0) != SUCCESS) {
  1179.         if (get_proto () != SUCCESS)
  1180.                goto bort1;
  1181.     }
  1182.  
  1183.     if (BigGOpt)
  1184.         twrite (msgi3G, sizeof (msgi3G) - 1);
  1185.     else
  1186.         twrite (msgi3g, sizeof (msgi3g) - 1);
  1187.  
  1188.     ResetGIO (); /* reset GIO protocol   */
  1189.  
  1190.     if (turnon (1))
  1191.         goto bort1;
  1192.  
  1193.     ulog (-1, "OK Startup");
  1194.  
  1195.     xferinit (host_name);
  1196.     xfer.flags |= XFERF_OUTGOING;
  1197.  
  1198.     r = top_level (1);
  1199.     hangup ();
  1200.  
  1201.     xfer.time_stop = time (NULL);
  1202.  
  1203.     if (r == FAIL) {    /* sd */
  1204.         ulog (-1, "Conversation FAILED");
  1205.     }
  1206.     xferstat (pnum, (r == FAIL) ? "# Conversation FAILED => LOGFILE" :  NULL);
  1207.  
  1208.     LogTimes (r);
  1209.     return r;
  1210.  
  1211. bort1:
  1212.     reset_modem ();
  1213.     LogTimes (FAIL);
  1214.     return FAIL;
  1215. }
  1216.  
  1217. void
  1218. LogTimes (int r)
  1219. {
  1220.     time_t
  1221.         e = time (NULL),
  1222.         t1 = (TimeBegin1) ? e - TimeBegin1 : 0,
  1223.         t2 = (TimeBegin2) ? e - TimeBegin2 : 0;
  1224.     FILE
  1225.         *fi;
  1226.     char
  1227.         *logFile = MakeConfigPath (UUSPOOL, "TimeLog"),
  1228.         buf [64];
  1229.  
  1230.     if (fi = fopen (logFile, "a")) {
  1231.         strftime (buf, sizeof (buf), "%d-%b-%y", localtime (&e));
  1232.         fprintf (fi, "%s %02d:%02d %2d:%02d in=%-8d out=%-8d %s\n",
  1233.             buf,
  1234.             e / 3600 % 24, e / 60 % 60,
  1235.             t2 / 60, t2 % 60,
  1236.             BytesIn,
  1237.             BytesOut,
  1238.             host_name
  1239.         );
  1240.         fclose (fi);
  1241.     }
  1242.  
  1243.     return;
  1244. }
  1245.  
  1246. /* Handle a single uucp [slave] login session */
  1247.  
  1248. int
  1249. do_session (int ontheline)
  1250. {
  1251.     int
  1252.         r;
  1253.  
  1254.     TimeBegin1 = 0;
  1255.     TimeBegin2 = time (NULL);
  1256.     BytesIn = 0;
  1257.     BytesOut = 0;
  1258.  
  1259.     if (ontheline == 0) {
  1260.         /* output login request, verify uucp */
  1261.         twrite (msgo0, sizeof (msgo0) - 1);
  1262.         if (instr (msgi0, sizeof (msgi0) - 1, 0) != SUCCESS) {
  1263.             fprintf (stderr, "%s: invalid login name\n", LogProgram);
  1264.             goto bort;
  1265.         }
  1266.  
  1267.         /* output password request, verify s8000 */
  1268.         twrite (msgo1,sizeof (msgo1) - 1);
  1269.         if (instr (msgi1, sizeof (msgi1) - 1, 0) != SUCCESS) {
  1270.             fprintf (stderr, "%s: invalid password\n", LogProgram);
  1271.             goto bort;
  1272.         }
  1273.  
  1274.         printf ("uucico: correct login\n");
  1275.     }
  1276.  
  1277.     /*
  1278.      *  send Shere=<myhost>
  1279.      *
  1280.      *  Apparently mac UUCP has a bug that only allows 7
  1281.      *  char host names, and it fails if it gets shere=<myhost>
  1282.      *  where <myhost> is > 7 chars.
  1283.      *
  1284.      *  Apparently some implementations of AmigaUUCP do not accept
  1285.      *  an SHere with an =<myhost>, so this is disabled unless -p1 is used.
  1286.      */
  1287.  
  1288.     if (ProtoHacks & PROTOF_SHEREEQUALS)
  1289.         sprintf (msgo2 + MSGO2IDX, "=%s", our_name);
  1290.     twrite (msgo2, strlen (msgo2) + 1);
  1291.  
  1292.     /*
  1293.      *  get \020S<host> -Qn n   (??)
  1294.      */
  1295.  
  1296.     if (getname (0))
  1297.         goto bort;
  1298.  
  1299.     /* output ok message, output protocol request, wait for response */
  1300.  
  1301.     twrite (msgo3, sizeof (msgo3) - 1);
  1302.  
  1303.     /* FIXME, make the protocol list here, and use it */
  1304.  
  1305.     if (BigGOpt)
  1306.         twrite (msgo3bG, sizeof (msgo3bG) - 1);
  1307.     else
  1308.         twrite (msgo3bg, sizeof (msgo3bg) - 1);
  1309.  
  1310.     if (BigGOpt) {
  1311.         if (instr (msgi3G, sizeof (msgi3G) - 1, 0) != SUCCESS)
  1312.             goto bort;
  1313.     }
  1314.     else {
  1315.         if (instr (msgi3g, sizeof (msgi3g) - 1, 0) != SUCCESS)
  1316.             goto bort;
  1317.     }
  1318.  
  1319.     ResetGIO ();    /* reset GIO protocol    */
  1320.  
  1321.     if (turnon (0))
  1322.         goto bort;
  1323.  
  1324.     ulog (-1, "OK Startup");
  1325.  
  1326.     xferinit (host_name);
  1327.  
  1328.     r = top_level (0);
  1329.  
  1330.     xfer.time_stop = time (NULL);
  1331.  
  1332.     if (r == FAIL) {    /* sd */
  1333.         ulog (-1, "Conversation FAILED");
  1334.     }
  1335.  
  1336.     xferstat (NULL, (r == FAIL) ? "# Conversation FAILED => LOGFILE" :  NULL);
  1337.  
  1338. bort:
  1339.     if (debug > 0)
  1340.         printf ("uucico: call complete\n");
  1341.     return 1;
  1342. }
  1343.  
  1344. /*
  1345.  * Handle transactions "at top level", as Unix uucp's debug log says.
  1346.  *
  1347.  * As master, we scan our queues for work and send requests to the
  1348.  * other side.    When done, we send a hangup request and switch to slave mode.
  1349.  *
  1350.  * As slave, we accept requests from the other side; when it is done,
  1351.  * it sends a hangup request, and we switch to master mode, if we have
  1352.  * any work queued up for that system.
  1353.  *
  1354.  * This repeats as long as either side has work to do.    When all the
  1355.  * queued work is done, we agree to hang up, terminate the packet protocol,
  1356.  * and return to the caller.  (We still haven't hung up the phone line yet.)
  1357.  *
  1358.  * A curious feature of the hangup protocol is that it is not a simple
  1359.  * question-answer.  The master says "H", asking about hangup.  The
  1360.  * slave responds "HY" saying OK.  The master then says "HY" also,
  1361.  * then both of them hang up.  Maybe this is to make sure the first HY
  1362.  * got ack'ed?  Anyway, an "H" is reported as HANGUP and an "HY" as
  1363.  * HANGNOW.  After we send an HY, we go back to listening for commands;
  1364.  * if the master sends something other than HY, we'll do it.
  1365.  */
  1366.  
  1367. #define HANGUP        2        /* Signal to switch master/slave roles */
  1368. #define HANGNOW     3        /* Signal to hang up now */
  1369. #define COPYFAIL    4        /* File copy failed */
  1370.  
  1371. int
  1372. top_level (int master_mode)
  1373. {
  1374.     static char
  1375.         buf [MAXMSGLEN];      /* For hangup responses */
  1376.  
  1377.     if (master_mode) {
  1378.         work_scan (host_name);      /* Kick off queue scan */
  1379.         goto master;
  1380.     }
  1381.  
  1382.     for (;;) {
  1383. slave:                /*    SLAVE SIDE  */
  1384.         set_dir (host_name);
  1385.  
  1386.         for (;;) {
  1387.             DEBUG (4, "*** TOP *** - slave\n", 0);
  1388.             switch (do_one_slave ()) {
  1389.                 case SUCCESS:
  1390.                     break;
  1391.                 case FAIL:
  1392.                     DEBUG (4, "*** DO_ONE_SLAVE FAIL *** - slave\n", 0);
  1393.                     return FAIL;
  1394.                 case HANGUP:
  1395.                     if (work_scan (host_name)) {
  1396.                         if (wrmsg ("HN") != SUCCESS) {
  1397.                             DEBUG (4, "*** WRMSG HN FAIL *** - slave\n", 0);
  1398.                             return FAIL;
  1399.                         }
  1400.                         goto master;
  1401.                     }
  1402.                     else {
  1403.                         if (wrmsg ("HY") != SUCCESS) {
  1404.                             DEBUG (4, "*** WRMSG HY FAIL *** - slave\n", 0);
  1405.                             return FAIL;
  1406.                         }
  1407.                         break;        /*    go to master mode */
  1408.                     }
  1409.                 case HANGNOW:
  1410.                     goto quit;
  1411.             }
  1412.         }
  1413.  
  1414. master:     /*    MASTER SIDE */
  1415.         for (;;) {
  1416.             DEBUG (4, "*** TOP *** - master\n", 0);
  1417.             switch (do_one_master ()) {
  1418.                 case SUCCESS:
  1419.                     break;
  1420.                 case FAIL:
  1421.                     DEBUG (4, "*** DO_ONE_MASTER FAIL *** - master\n", 0);
  1422.                     return FAIL;
  1423.                 case HANGUP:
  1424.                     /* We wrote an H command, what's the resp? */
  1425.                     if (rdmsg (buf, MAXMSGLEN) != SUCCESS) {
  1426.                         DEBUG (4, "*** RDMSG HANGUP FAIL *** - master\n", 0);
  1427.                         return FAIL;
  1428.                     }
  1429.                     if (buf [0] != 'H') {
  1430.                         DEBUG (4, "*** RDMSG HANGUP != 'H' *** - master\n", 0);
  1431.                         return FAIL;
  1432.                     }
  1433.                     if (buf [1] == 'N') {
  1434.                         goto slave;
  1435.                     }
  1436.                     else {
  1437.                         /*
  1438.                          *  send final HY?  not sure if this should happen, will
  1439.                          *  necessarily fail if the other side does not expect
  1440.                          *  it so do not return... continue on w/ exit code.
  1441.                          *
  1442.                          *  however, reduce timeout parameters
  1443.                          */
  1444.  
  1445.                         ++ReducedTimeout;
  1446.                         wrmsg ("HY");
  1447.                         --ReducedTimeout;
  1448.                         goto quit;
  1449.                     }
  1450.             }
  1451.         }
  1452.     }
  1453.  
  1454. quit:
  1455.     /* Shut down the packet protocol */
  1456.  
  1457.     turnoff ();
  1458.  
  1459.     /* Write the closing sequence */
  1460.  
  1461.     twrite (msgo4, sizeof (msgo4) - 1);
  1462.     instr (msgi4, sizeof (msgi4) - 1, 0);
  1463.  
  1464.     twrite (msgo4, sizeof (msgo4) - 1);
  1465.  
  1466.     strcpy (who, "-");
  1467.     ulog (-1, "OK Conversation complete");
  1468.  
  1469.     return SUCCESS;   /* Go byebye */
  1470. }
  1471.  
  1472. /*
  1473.  * We are slave; get a command from the other side and execute it.
  1474.  *
  1475.  * Result is SUCCESS, FAIL, HANGUP, or HANGNOW.
  1476.  */
  1477.  
  1478. int
  1479. do_one_slave (void)
  1480. {
  1481.     static char
  1482.         msg [MAXMSGLEN];        /* Master's message to us */
  1483.  
  1484.     /* Get master's command */
  1485.     if (rdmsg (msg, MAXMSGLEN) != SUCCESS)
  1486.         return FAIL;
  1487.  
  1488.     /* Print it for easy debugging */
  1489.     DEBUG (5,"\nCommand: %s\n\n", msg);
  1490.  
  1491.     switch (msg [0]) {
  1492.         case 'S':
  1493.             if (msg [1] != ' ')
  1494.                 break;
  1495.             return host_send_file (msg);
  1496.         case 'R':
  1497.             if (msg [1] != ' ')
  1498.                 break;
  1499.             return host_receive_file (msg);
  1500.         case 'X':
  1501.             break;
  1502.         case 'H':
  1503.             if (msg [1] == '\0')
  1504.                 return HANGUP;
  1505.             if (msg [1] == 'Y')
  1506.                 return HANGNOW;
  1507.             if (msg [1] == 'N')
  1508.                 return SUCCESS;     /* Ignore HN to slave */
  1509.             break;
  1510.     }
  1511.  
  1512.     /* Unrecognized packet from the other end */
  1513.  
  1514.     DEBUG (0, "Bad control packet refused: %s\n", msg);
  1515.  
  1516.     if (ExitCode < 2)
  1517.         ExitCode = 2;
  1518.  
  1519.     return yesno (msg [0], 0, 0);
  1520. }
  1521.  
  1522. /*
  1523.  *  Do one piece of work as master.
  1524.  *
  1525.  *  FIXME:  we don't handle the flags, e.g. -c, properly!
  1526.  *
  1527.  *  Now only dequeues queue file if all transfers were successful.
  1528.  */
  1529.  
  1530. int
  1531. do_one_master (void)
  1532. {
  1533.     FILE
  1534.         *fd;
  1535.     char
  1536.         *sname;
  1537.     static char
  1538.         cmnd [256],         /* Command character */
  1539.         buf [256],
  1540.         notify [NAMESIZE];     /* A bit large...FIXME */
  1541.     int
  1542.         fail = SUCCESS,
  1543.         failAction = SUCCESS,
  1544.         failaccum = 0,
  1545.         num,
  1546.         delmeflag,
  1547.         di = 0;
  1548.     char
  1549.         *delList [16];         /* delete files list    */
  1550.  
  1551.     /*
  1552.      *  Get the next work item.  If no work left re-scan the directory
  1553.      *  just to be sure, and if still no work then do the right thing.
  1554.      */
  1555.  
  1556.     sname = work_next ();
  1557.     if (!sname && NoReScan == 0) {
  1558.         if (work_scan (host_name))
  1559.             sname = work_next ();
  1560.     }
  1561.     if (!sname) {
  1562.         /* No more work, time to hang up. */
  1563.         if (wrmsg ("H") != SUCCESS)
  1564.             return FAIL;
  1565.         return HANGUP;
  1566.     }
  1567.  
  1568.     DEBUG (2, "Request file %s\n", sname);
  1569.  
  1570.     LockFile (sname);
  1571.  
  1572.     fd = fopen (sname, "r");
  1573.     if (fd == NULL) {
  1574.         UnLockFile (sname);
  1575.         DEBUG (0, "uucico: couldn't open %s\n", sname);
  1576.         return SUCCESS;
  1577.     }
  1578.  
  1579.     while (fgets (buf, sizeof (buf), fd)) {
  1580.         DEBUG (3, "Queued request: %s", buf);
  1581.  
  1582.         if (buf [1] != ' ')
  1583.             goto badnum;
  1584.  
  1585.         num = sscanf (buf, "%s %s %s %s %s %s %o\n",
  1586.             cmnd, srcnam, dstnam, who, flags, temp, &mode, notify
  1587.             );
  1588.  
  1589.         switch (cmnd [0]) {
  1590.             case 'S':
  1591.                 if (num < 7 || num > 8)
  1592.                     goto badnum;
  1593.                 fail = local_send_file (buf, &delmeflag);
  1594.                 if (delmeflag) {
  1595.                     if (di == sizeof (delList) / sizeof (delList [0])) {
  1596.                         ulog (-1, "Too many source files in Cmd file! %s", sname);
  1597.                     }
  1598.                     else {
  1599.                         delList [di] = malloc (strlen (temp) + 1);
  1600.                         strcpy (delList [di], temp);
  1601.                         ++di;
  1602.                     }
  1603.                 }
  1604.                 break;
  1605.             case 'R':
  1606.                 if (num != 5) {
  1607.                     ulog (1, "ERROR: Invalid scanf %ld/5 :%s:%s:%s\n", num, cmnd, srcnam, dstnam);
  1608.                     goto badnum;
  1609.                 }
  1610.                 fail = local_receive_file ();
  1611.                 break;
  1612.             default:
  1613. badnum:
  1614.                 ulog (-1, "Illegal Work Request (%s): %s", sname, buf);
  1615.                 fail = REFUSED;
  1616.                 break;
  1617.         }
  1618.  
  1619.         switch (fail) {
  1620.             case SUCCESS:
  1621.                 break;
  1622.             case FAIL:
  1623.                 ++failaccum;
  1624.                 if (failAction == SUCCESS)
  1625.                     failAction = FAIL;
  1626.                 ulog (-1, "Protocol Failure at (%s): %s", sname, buf);
  1627.                 NoReScan = 1;
  1628.                 break;
  1629.             case REFUSED:
  1630.                 ++failaccum;
  1631.                 failAction = REFUSED;
  1632.                 ulog (-1, "Work Refused (%s): %s", sname, buf);
  1633.                 break;
  1634.         }
  1635.     }
  1636.     fclose (fd);
  1637.  
  1638.     switch (failAction) {
  1639.         case SUCCESS:
  1640.             while (di) {
  1641.                 --di;
  1642.                 remove (delList [di]);
  1643.                 free (delList [di]);
  1644.             }
  1645.             fail = remove (sname);
  1646.             UnLockFile (sname);
  1647.             if (fail != 0) {
  1648.                 ulog (-1, "Unable to remove work file %s", sname);
  1649.                 DEBUG (0, "Can't remove, errno %d\n", errno);
  1650.             }
  1651.             else {
  1652.                 DEBUG (4, "Removed work file %s\n", sname);
  1653.             }
  1654.             break;
  1655.         case FAIL:
  1656.             UnLockFile (sname);
  1657.             break;
  1658.         case REFUSED:
  1659.             UnLockFile (sname);
  1660.             strcpy (buf, sname);
  1661.             {
  1662.                 int
  1663.                     i;
  1664.  
  1665.                 for (i = strlen (buf); i >= 0 && buf [i] != ':' && buf [i] != '/'; --i)
  1666.                     ;
  1667.                 ++i;
  1668.                 if ((buf [i] | 0x20) == 'c')
  1669.                     buf [i] = 'E';
  1670.             }
  1671.             if (strcmp (sname, buf) == 0) {
  1672.                 ulog (-1, "Removing %s", sname);
  1673.                 remove (sname);
  1674.             }
  1675.             else {
  1676.                 ulog (-1, "Renaming %s to %s", sname, buf);
  1677.                 rename (sname, buf);
  1678.             }
  1679.             break;
  1680.     }
  1681.  
  1682.     if (failAction == FAIL)
  1683.         return FAIL;
  1684.  
  1685.     return SUCCESS;
  1686. }
  1687.  
  1688. /*
  1689.  *  Send a yes/no packet
  1690.  */
  1691.  
  1692. int
  1693. yesno (char c, int true, int err)
  1694. {
  1695.     static char
  1696.         buf [21];
  1697.  
  1698.     buf [0] = c;
  1699.     buf [1] = true ? 'Y' : 'N';
  1700.     buf [2] = 0;
  1701.     if (err && !true)
  1702.         sprintf (buf + 2, "%ld", err);
  1703.  
  1704.     return wrmsg (buf);
  1705. }
  1706.  
  1707. /*
  1708.  *  SLAVE MODE, Master wishes to send a file to us
  1709.  *
  1710.  *  SECURITY:    If file is not in list of allowed directories
  1711.  *        disallow transfer.  UUSPOOL:   is always in the
  1712.  *        list.
  1713.  *
  1714.  *        If file is for UUSPOOL: (the current dir), disallow "C." files
  1715.  *        NOTE: success return and file redirected to T: as this can
  1716.  *        occur only if somebody purposefully is trying to break us.
  1717.  *
  1718.  *        NOTE: for received files to UUSPOOL: (no path element),
  1719.  *        case insensitivity munging will occur.    UUXQT will handle
  1720.  *        name translations for X. files so we do not modify their
  1721.  *        contents.
  1722.  *
  1723.  *  Return 0 = success
  1724.  */
  1725.  
  1726. int
  1727. host_send_file (char *msg)
  1728. {
  1729.     FILE
  1730.         *fddsk;            /* Disk file pointer */
  1731.     static char
  1732.         cmnd [256];         /* Command character */
  1733.     int
  1734.         r,
  1735.         nor = 0;
  1736.  
  1737.     sscanf (msg, "%s %s %s %s %s %s %o",
  1738.         cmnd, srcnam, dstnam, who, flags, temp, &mode);
  1739.  
  1740.     ulog (-1, "REQUESTED %s", msg);
  1741.     munge_filename (dstnam, dstnam);    /* Translate to local name    */
  1742.     mungecase_filename (dstnam, dstnam);    /* Handle case insensitivity  */
  1743.     strcpy (temp, TmpFileName (dstnam));    /* Create a handy temp file   */
  1744.  
  1745.     if (SecurityDisallow (dstnam, 'w')) {
  1746.         ulog (-1, "REQUEST FAILED -- SECURITY");
  1747.         return yesno ('S', 0, 4);
  1748.     }
  1749.  
  1750.     if (SecurityDisallow (dstnam, 'c') > 0) {
  1751.         ulog (-1, "REQUEST FAILED -- SECURITY, REMOTE TRIED TO SEND");
  1752.         ulog (-1, "US A COMMAND FILE: %s, FILE COPIED TO T:Bad-Cmd", dstnam);
  1753.         strcpy (dstnam, "T:Bad-Cmd");
  1754.         nor = 1;
  1755.     }
  1756.  
  1757.     /* FIXME: deal with file modes now that we fopen. */
  1758.  
  1759.     LockFile (temp);
  1760.  
  1761.     fddsk = fopen (temp, "wb" /*, mode|0600 */);
  1762.     if (fddsk == NULL) {
  1763.         UnLockFile (temp);
  1764.         /* Can't open file -- send error response */
  1765.         if (debug > 0) {
  1766.             fprintf (stderr, "Cannot open temp file %s (%s) for writing, errno=%ld\n",
  1767.                  temp, dstnam, errno);
  1768.         }
  1769.         ulog (-1, "REQUEST FAILED -- cannot open temp file %s (destination %s) for writing, errno %ld",
  1770.             temp, dstnam, errno);
  1771.         return yesno ('S', 0, 4);
  1772.     }
  1773.  
  1774.     /* FIXME: Are the above permissions right?? */
  1775.     /* FIXME: Should we create directories for the file? */
  1776.  
  1777.     if (yesno ('S', 1, 0) != SUCCESS) {
  1778.         fclose (fddsk);
  1779.         unlink (temp);
  1780.         UnLockFile (temp);
  1781.         return FAIL;
  1782.     }
  1783.     r = receive_file (fddsk, temp, dstnam, srcnam, nor);
  1784.     UnLockFile (temp);
  1785.  
  1786.     /*
  1787.      * sd
  1788.      * Notify username of incoming file, cept if D. or X. or C. ctrl files.
  1789.      * Notify of any incoming failure (if NOTIFY_INCOMING_FAILURE bit set)
  1790.      */
  1791.     {
  1792.         static char
  1793.             from [80];
  1794.  
  1795.         sprintf (from, "%s!%s", host_name, who);
  1796.         if (r == SUCCESS && ((copynotify & NOTIFY_INCOMING)
  1797.                  && !CTRLFILE (dstnam))) {
  1798.             sprintf (mailsub, "NEW FILE: %s", dstnam);
  1799.             mail_notify (from, who, mailsub);
  1800.         }
  1801.         else
  1802.             if (r != SUCCESS && (copynotify & NOTIFY_INCOMING_FAILURE)) {
  1803.                 sprintf (mailsub, "INCOMING FAILURE: %s", dstnam);
  1804.                 mail_notify (from, who, mailsub);
  1805.             }
  1806.     }
  1807.  
  1808.     return r;
  1809. }
  1810.  
  1811. /*
  1812.  *  SLAVE MODE, Master wants us to send a file to it
  1813.  *
  1814.  *  SECURITY:    If file is not in list of allowed directories
  1815.  *        disallow transfer.  UUSPOOL:   is always in the
  1816.  *        list.
  1817.  *
  1818.  *  0 = success
  1819.  */
  1820.  
  1821. int
  1822. host_receive_file (char *msg)
  1823. {
  1824.     FILE
  1825.         *fddsk;     /* Disk file descriptor */
  1826.     int
  1827.         x;
  1828.     static char
  1829.         cmnd [256];           /* Command character */
  1830.  
  1831.     ulog (-1, "REQUESTED %s", msg);
  1832.  
  1833.     sscanf (msg, "%s %s %s", cmnd, srcnam, dstnam);
  1834.     munge_filename (srcnam, temp);
  1835.  
  1836.     if (SecurityDisallow (temp, 'r')) {
  1837.         ulog (-1, "COPY FAILED -- SECURITY");
  1838.         return yesno ('R', 0, 4);
  1839.     }
  1840.  
  1841.     fddsk = fopen (temp, "rb");              /* Try to open the file */
  1842.     if (fddsk == NULL) {
  1843.         /* File didn't open, sigh. */
  1844.         ulog (-1, "DENIED - can't open %s (%s, errno %ld)", temp, srcnam, errno);
  1845.         return yesno ('R', 0, 2);
  1846.     }
  1847.  
  1848.     if (yesno ('R', 1, 0) != SUCCESS) {
  1849.         fclose (fddsk);
  1850.         return (FAIL);
  1851.     }
  1852.  
  1853.     x = send_file (fddsk);
  1854.  
  1855.     /*
  1856.      *  if copy failed, we don't care since the master asked for the file
  1857.      *  and knows the result if it failed.
  1858.      */
  1859.  
  1860.     if (x == COPYFAIL)
  1861.         return SUCCESS;
  1862.  
  1863.     return x;
  1864. }
  1865.  
  1866. /*
  1867.  *  MASTER MODE, We want to send a file.
  1868.  *
  1869.  *  Return FAIL, SUCCESS, or COPYFAIL.
  1870.  *
  1871.  *  SUCCESS is returned either if the file was not found locally (local
  1872.  *  error, and the queued transfer should be flushed) or if it was moved
  1873.  *  successfully.  COPYFAIL indicates that the queued transfer should be
  1874.  *  left queued, and later retried.  FIXME, there are several failure points
  1875.  *  in the transaction and we need finer control here.
  1876.  */
  1877.  
  1878. int
  1879. local_send_file (char *workstr, int *delmeflag)
  1880. {
  1881.     static char
  1882.         buf [MAXMSGLEN];   /* Used for both xmit and receive */
  1883.     FILE
  1884.         *fddsk;        /* Disk file descriptor */
  1885.     int
  1886.         res;            /* Result and file removal status */
  1887.  
  1888.     *delmeflag = 0;
  1889.  
  1890.     /* WHY are temp and srcnam switched?  FIXME!  And no notify? */
  1891.  
  1892.     sprintf (buf, "S %s %s %s %s %s 0%o %s",
  1893.         temp, dstnam, who, flags, srcnam, mode, who
  1894.     );
  1895.  
  1896.     ulog (-1, "REQUEST %s", buf);
  1897.  
  1898.     if (strchr (flags, 'c')) {
  1899.         munge_filename (srcnam, temp);
  1900.     }
  1901.     else {
  1902.         munge_filename (temp, temp);
  1903.     }
  1904.     LockFile (temp);
  1905.     fddsk = fopen (temp, "rb");
  1906.     if (fddsk == NULL) {
  1907.         UnLockFile (temp);
  1908.         /* FIXME -- handle queued request for nonexistent file */
  1909.         if (debug > 0)
  1910.             fprintf (stderr, "Can't open file %s (%s), errno=%ld\n",
  1911.                  temp, srcnam, errno);
  1912.         ulog (-1, "NOT FOUND %s (source %s) errno %ld",
  1913.             temp, srcnam, errno);
  1914.         /*
  1915.          * sd: Notify of failure, file to send could not be found
  1916.          */
  1917.         sprintf (mailsub, "FAILED: Can't open %s",srcnam);
  1918.  
  1919.         if (copynotify & NOTIFY_FAILED)
  1920.             mail_notify ("uucico", "uucico", mailsub);
  1921.  
  1922.         /* return COPYFAIL;*/
  1923.         return SUCCESS;     /*    assume file previously sent */
  1924.     }
  1925.  
  1926.     /* Tell the other side we want to send this file */
  1927.  
  1928.     if (wrmsg (buf) != SUCCESS) {
  1929.         fclose (fddsk);
  1930.         UnLockFile (temp);
  1931.         return FAIL;
  1932.     }
  1933.  
  1934.     /* See what they have to say about it */
  1935.  
  1936.     if (rdmsg (buf, MAXMSGLEN) != SUCCESS) {
  1937.         fclose (fddsk);
  1938.         UnLockFile (temp);
  1939.         return FAIL;
  1940.     }
  1941.     if ((buf [0] != 'S') || (buf [1] != 'Y')) {
  1942.         ulog (-1, "REQUEST DENIED %s", buf);
  1943.         fclose (fddsk);
  1944.         UnLockFile (temp);
  1945.         /*
  1946.          * sd - send mail indicating request was denied
  1947.          */
  1948.         sprintf (mailsub, "REFUSED by %s: %s", host_name, dstnam);
  1949.         if (copynotify & NOTIFY_FAILED)
  1950.             mail_notify ("uucico", "uucico", mailsub);
  1951.  
  1952.         return REFUSED;
  1953.     }
  1954.  
  1955.     res = send_file (fddsk); /* FAIL, SUCCESS, or COPYFAIL */
  1956.  
  1957.     /*
  1958.      * sd - since our caller does not seem to pay any attention to
  1959.      * COPYFAIL, it defaults to success?? It also reties on FAIL.
  1960.      * Without this patch, sending files can be lost and assume sent ok
  1961.      * even though may of failed due to protocol errors.
  1962.      */
  1963.     if (res == COPYFAIL)
  1964.         res = FAIL;
  1965.  
  1966.     /*
  1967.      * sd - send mail indicating copy failed.
  1968.      */
  1969.     if (res != SUCCESS) {
  1970.         sprintf (mailsub,"COPY FAILED: (will retry) to %s!%s from %s",
  1971.             host_name, dstnam, srcnam);
  1972.         if (copynotify & NOTIFY_RETRY)
  1973.             mail_notify ("uucico", "uucico", mailsub);
  1974.     }
  1975.     else
  1976.         if (!CTRLFILE (srcnam)) {
  1977.             sprintf (mailsub,"COPY DONE: %s!%s from %s",
  1978.                 host_name, dstnam, srcnam);
  1979.             if (copynotify & NOTIFY_SUCCESS)
  1980.                 mail_notify ("uucico", "uucico", mailsub);
  1981.         }
  1982.  
  1983.     UnLockFile (temp);
  1984.  
  1985.     /* don't delete if file was the original or an error occurred */
  1986.     if (res != SUCCESS || strchr (flags, 'c')) {
  1987.         return res;
  1988.     }
  1989.  
  1990.     /* Delete the source file if it was just a copy */
  1991.     *delmeflag = 1;
  1992.  
  1993.     return    res;
  1994. }
  1995.  
  1996. /*
  1997.  *  MASTER MODE, We wish to receive a specific file so we ask for it
  1998.  *
  1999.  *  Return 0 = success
  2000.  */
  2001.  
  2002. int
  2003. local_receive_file (void)
  2004. {
  2005.     static char
  2006.         buf [MAXMSGLEN];
  2007.     FILE
  2008.         *fddsk;            /* Disk file pointer */
  2009.     int
  2010.         r;
  2011.  
  2012.     /* FIXME, test dest file access before we ask for it. */
  2013.  
  2014. #if 0
  2015.     sprintf (buf, "R %s %s %s %s %s 0%o %s",
  2016.         srcnam, dstnam, who, flags, temp, mode, who
  2017.     };
  2018. #else
  2019.     sprintf (buf, "R %s %s %s %s",
  2020.         srcnam, dstnam, who, flags
  2021.     );
  2022. #endif
  2023.  
  2024.     munge_filename (dstnam, dstnam);       /* tlate to local name      */
  2025.     strcpy (temp, TmpFileName (dstnam));       /* Create a handy temp file */
  2026.  
  2027.     /* FIXME: deal with file modes now that we fopen. */
  2028.     /* FIXME: Are the above permissions right?? */
  2029.     /* FIXME: Should we create directories for the file? */
  2030.  
  2031.     LockFile (temp);
  2032.     fddsk = fopen (temp, "wb" /*, mode|060 */);
  2033.  
  2034.     if (fddsk == NULL) {
  2035.         UnLockFile (temp);
  2036.         /* Can't open temp file -- send error response */
  2037.         if (debug > 0) {
  2038.             fprintf (stderr, "Cannot open temp file %s (%s) for writing, errno=%ld\n",
  2039.                 temp, dstnam, errno);
  2040.         }
  2041.         ulog (-1, "REQUEST FAILED -- cannot open temp file %s (dstnam %s) for writing, errno %ld",
  2042.             temp, dstnam, errno);
  2043.         return FAIL;
  2044.     }
  2045.  
  2046.     ulog (-1, "REQUEST %s", buf);
  2047.     if (wrmsg (buf) != SUCCESS) {
  2048.         fclose (fddsk);
  2049.         UnLockFile (temp);
  2050.         fprintf (stderr, "problem sending request '%s'\n", buf);
  2051.         ulog (-1, "REQUEST FAILED: couldn't request '%s'", buf);
  2052.         return FAIL;
  2053.     }
  2054.  
  2055.     /* See what the other side has to say about it */
  2056.  
  2057.     if (rdmsg (buf, MAXMSGLEN) != SUCCESS) {
  2058.         fclose (fddsk);
  2059.         UnLockFile (temp);
  2060.         ulog (-1, "REQUEST FAILED: read failure '%s'", buf);
  2061.         return FAIL;
  2062.     }
  2063.  
  2064.     if ((buf [0] != 'R') || (buf [1] != 'Y')) {
  2065.         ulog (-1, "REQUEST DENIED %s", buf);
  2066.         fclose (fddsk);
  2067.         UnLockFile (temp);
  2068.         /*
  2069.          * sd - send mail indicating request was denied
  2070.          */
  2071.         sprintf (mailsub, "REFUSED by %s: %s", host_name, srcnam);
  2072.         if (copynotify & NOTIFY_FAILED)
  2073.             mail_notify ("uucico", "uucico", mailsub);
  2074.         return REFUSED;
  2075.     }
  2076.  
  2077.     r = receive_file (fddsk, temp, dstnam, srcnam, 0);
  2078.     UnLockFile (temp);
  2079.     /*
  2080.      * sd - send mail indicating copy failed.
  2081.      */
  2082.     if (r != SUCCESS) {
  2083.         sprintf (mailsub, "COPY FAILED: (will retry) %s!%s", host_name, srcnam);
  2084.         if (copynotify & NOTIFY_RETRY)
  2085.             mail_notify ("uucico", "uucico", mailsub);
  2086.     }
  2087.     else {
  2088.         sprintf (mailsub, "COPY DONE: %s!%s to %s", host_name, srcnam, dstnam);
  2089.         if (copynotify & NOTIFY_SUCCESS)
  2090.             mail_notify ("uucico", "uucico", mailsub);
  2091.     }
  2092.     return r;
  2093. }
  2094.  
  2095. /*
  2096.  *  General receive file
  2097.  */
  2098.  
  2099. int
  2100. receive_file (FILE *fddsk, char *temp, char *dstnam, char *srcnam, int norename)
  2101. {
  2102.     int
  2103.         filesize,    /* size of file we receive */
  2104.         status,     /* result status */
  2105.         error = 0;    /* No errors so far */
  2106.     time_t
  2107.         t1,        /* start receive */
  2108.         t2;        /* finish receive */
  2109.  
  2110.     Tot_Packets = Tot_Retries = 0;
  2111.     time (&t1);
  2112.  
  2113.     if (rddata (fddsk) != SUCCESS)
  2114.         error++;
  2115.  
  2116.     time (&t2);
  2117.     t2 -= t1;
  2118.     if (t2 <= 0)
  2119.         t2 = 1;
  2120.  
  2121.     filesize = ftell (fddsk);
  2122.  
  2123.     xfer.files_recv++;
  2124.     xfer.fbytes_recv += filesize;
  2125.  
  2126.     if (Tot_Retries) {
  2127.         ulog (-1, "Retransmitted/Total Packets: %d/%d", Tot_Retries, Tot_Packets);
  2128.     }
  2129.  
  2130.     status = fclose (fddsk);     /* Make sure the data got here */
  2131.  
  2132.     if (status != 0) {
  2133.         error++;
  2134.         DEBUG (0, "fclose errno=%d\n", errno);
  2135.     }
  2136.  
  2137.     /*
  2138.      *  Move the file from its temp location to its real location,
  2139.      *  This needs to be able to copy a file if a simple rename
  2140.      *  does not suffice.  Should create directories if necesary.
  2141.      *  should use source name if target is a directory (i.e. no
  2142.      *  target source name
  2143.      */
  2144.  
  2145.     ulog (5, "temp name '%s', dstnam '%s'", temp, dstnam);
  2146.     unlink (dstnam);
  2147.  
  2148.     if (norename) {     /*    for security redirect    */
  2149.         status = 0;
  2150.     }
  2151.     else {
  2152.         status = rename (temp, dstnam);
  2153.         if (status < 0) {
  2154.             /*
  2155.             **  Section originally from 'wusel@hactar.hanse.de'
  2156.             **
  2157.             **  Changed slightly by 'mbs@adastra.cvl.va.us'.
  2158.             **
  2159.             **  STILL doesn't try to copy like it should on failure.
  2160.             **  (required to be able to use T: as temp directory -- FIXME)
  2161.             **
  2162.             **  Determine if the remote left off dstnam, as some
  2163.             **  Unices do when sending several files at once. Try
  2164.             **  to find out dstnam by strchr()'ing in srcnam.
  2165.             **  May need some work -- FIXME!
  2166.             */
  2167.             static char
  2168.                 newnam [NAMESIZE],
  2169.                 *ptr;
  2170.             int
  2171.                 dstlen = strlen (dstnam);
  2172.  
  2173.             if (dstnam [dstlen - 1] == '/' || dstnam [dstlen - 1] == ':') {
  2174.                 ptr = strrchr (srcnam, '/');
  2175.                 if (!ptr)
  2176.                     ptr = strrchr (srcnam, ':');
  2177.                 if (ptr)
  2178.                     ptr++;
  2179.                 else
  2180.                     ptr = srcnam;
  2181.                 strcpy (newnam, dstnam);
  2182.                 strcpy (newnam + dstlen, ptr);
  2183.                 status = rename (temp, newnam);
  2184.                 if (status < 0) {
  2185.                     ulog (-1, "rename to %s failed, deleting file and trying again", newnam);
  2186.                     remove (newnam);
  2187.                     status = rename (temp, newnam);
  2188.                 }
  2189.             }
  2190.             else {
  2191.                 ulog (-1, "RENAME TO %s FAILED, DELETING FILE AND TRYING AGAIN", dstnam);
  2192.                 remove (dstnam);
  2193.                 status = rename (temp, dstnam);
  2194.             }
  2195.         }
  2196.     }
  2197.  
  2198.     if (status) {
  2199.         /* Oops! Failure. :( */
  2200.         error++;
  2201.         ulog (-1, "Cannot rename() file '%s' to '%s', errno %ld",
  2202.             temp, dstnam, errno);
  2203.     }
  2204.  
  2205.     ulog (-1, "COPY %s (%ld bytes, %ld cps)", error ? "FAILED" : "SUCCEEDED",
  2206.         filesize, (filesize / (int) t2));
  2207.  
  2208.     /*
  2209.     **  Section originally from 'wusel@hactar.hanse.de'.
  2210.     **
  2211.     **  Changed slightly by 'mbs@adastra.cvl.va.us'.
  2212.     **
  2213.     **  Try to run UUXqt while transfer is still in process. The number
  2214.     **  of file pairs that need to be received is controlled by the
  2215.     **  configuration entry "UUXqtInterval".
  2216.     */
  2217.     if (UUXqtInterval) {
  2218.         static int
  2219.             xfiles = 0;
  2220.         int
  2221.             c = (int) (((unsigned char *) dstnam) [0]);
  2222.  
  2223.         if (dstnam [1] == '.' && (c == 'x' || c == 'X')) {
  2224.             ++xfiles;
  2225.             if ((xfiles % UUXqtInterval) == 0) {
  2226.                 ulog (-1, "Started UUXqt after %ld jobs", xfiles);
  2227.                 uuxqt ();
  2228.             }
  2229.         }
  2230.     }
  2231.  
  2232.     return yesno ('C', error == 0, 5);
  2233. }
  2234.  
  2235. /*
  2236.  * general file send routine
  2237.  * Return SUCCESS, FAIL, or COPYFAIL.
  2238.  */
  2239.  
  2240. int
  2241. send_file (FILE *fddsk)
  2242. {
  2243.     static char
  2244.         ansbuf [MAXMSGLEN];
  2245.     int
  2246.         filesize,
  2247.         s;
  2248.     time_t
  2249.         t1,
  2250.         t2;
  2251.  
  2252.     Tot_Packets = Tot_Retries = 0;
  2253.  
  2254.     time (&t1);
  2255.     s = wrdata (fddsk);
  2256.     time (&t2);
  2257.  
  2258.     t2 -= t1;
  2259.     if (t2 <= 0)
  2260.         t2 = 1;
  2261.  
  2262.     filesize = ftell (fddsk);
  2263.  
  2264.     xfer.files_send++;
  2265.     xfer.fbytes_send += filesize;
  2266.  
  2267.     if (Tot_Retries) {
  2268.         ulog (-1, "Retransmitted/Total Packets: %ld/%ld", Tot_Retries, Tot_Packets);
  2269.     }
  2270.     ulog (-1, "Transmission rate for %ld bytes is %ld CPS", filesize, (filesize / (int) t2));
  2271.  
  2272.     fclose (fddsk);
  2273.  
  2274.     if (s != SUCCESS) {
  2275.         return COPYFAIL;
  2276.     }
  2277.  
  2278.     /* Await the "CY" or "CNddd" packet, and toss it. */
  2279.  
  2280.     for (;;) {
  2281.         if (rdmsg (ansbuf, MAXMSGLEN) != SUCCESS)
  2282.             return FAIL;
  2283.  
  2284.         if (ansbuf [0] != 'C') {
  2285.             DEBUG (0, "\nDidn't get 'CY' or 'CN', got %s\n", ansbuf);
  2286.             /* and loop looking for C message */
  2287.         }
  2288.         else
  2289.             if (ansbuf [1] == 'Y') {
  2290.                 ulog (-1, "REQUESTED %s", ansbuf);
  2291.                 return SUCCESS;
  2292.             }
  2293.             else {
  2294.                 ulog (-1, "COPY FAILED %s", ansbuf);
  2295.                 return COPYFAIL;
  2296.             }
  2297.     }
  2298.  
  2299.     /* NOTREACHED */
  2300.     return COPYFAIL;
  2301. }
  2302.  
  2303.  
  2304. void
  2305. mail_notify (char *from, char *real, char *subject)
  2306. {
  2307.     char
  2308.         mailcmd [NAMESIZE + 100];
  2309.     const char
  2310.         *to = "postmaster",
  2311.         *sendmail = GetConfigProgram (SENDMAIL);
  2312.  
  2313.     if (strlen (subject) > 200)
  2314.         subject [200] = '\0';  /* CLI input limits */
  2315.  
  2316.     sprintf (mailcmd,
  2317.         "run %s <nil: >nil: -f %s -R \"%s\" -t %s -s \"%s\" -raw",
  2318.         sendmail, from, real, to, subject);
  2319.  
  2320.     Execute (mailcmd, 0, 0);
  2321.  
  2322.     return;
  2323. }
  2324.  
  2325. void
  2326. uuxqt (void)
  2327. {
  2328.     const char
  2329.         *UUXqt = GetConfigProgram (UUXQT);
  2330.     char
  2331.         *ptr;
  2332.     int
  2333.         freeme = 0;
  2334.  
  2335.     if (UUXqtHostname) {
  2336.         ptr = malloc (strlen (UUXqt) + 2 + strlen (host_name));
  2337.         if (ptr) {
  2338.             freeme = 1;
  2339.             sprintf (ptr, "%s %s", UUXqt, host_name);
  2340.         }
  2341.     }
  2342.     else
  2343.         ptr = UUXqt;
  2344.  
  2345.     if (DOSBase->dl_lib.lib_Version < 37) {
  2346.         struct Task
  2347.             *me = FindTask (NULL);
  2348.         int
  2349.             freep = 0,
  2350.             old;
  2351.         char
  2352.             *p;
  2353.  
  2354.         p = malloc (strlen (ptr) + 50);
  2355.         if (p) {
  2356.             freep = 1;
  2357.             sprintf (p, "run <nil: >nil: %s", ptr);
  2358.         }
  2359.         else
  2360.             p = ptr;
  2361.  
  2362.         old = SetTaskPri (me, UUXqtPriority);
  2363.         Execute (p, 0, 0);
  2364.         SetTaskPri (me, old);
  2365.  
  2366.         if (freep)
  2367.             free (p);
  2368.  
  2369.     }
  2370.     else {
  2371.         /* 2.04+ */
  2372.         SystemTags (ptr,
  2373.             SYS_Asynch,    1,
  2374.             SYS_Input,    0,
  2375.             SYS_Output,    0,
  2376.             SYS_UserShell,    1,
  2377.             NP_CloseInput,    0,
  2378.             NP_CloseOutput, 0,
  2379.             NP_Priority,    UUXqtPriority,
  2380.             NP_Cli,     1,
  2381.             TAG_DONE);
  2382.  
  2383.     }
  2384.  
  2385.     if (freeme)
  2386.         free (ptr);
  2387.  
  2388.     return;
  2389. }
  2390.