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