home *** CD-ROM | disk | FTP | other *** search
/ back2roots/padua / padua.7z / padua / uucp / auucp+-1.02 / fuucp_plus_src.lzh / uucico / uucico.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-11-21  |  33.0 KB  |  1,488 lines

  1.  
  2. /*
  3.  *  UUCICO.C
  4.  *
  5.  *  $Header: Beta:src/uucp/src/uucico/RCS/uucico.c,v 1.1 90/02/02 11:56:01 dillon Exp Locker: dillon $
  6.  *
  7.  *  (C) Copyright 1987 by John Gilmore.
  8.  *  Copying and use of this program are controlled by the terms of the Free
  9.  *  Software Foundation's GNU Emacs General Public License.
  10.  *
  11.  *  Derived from:
  12.  *  i[$]uuslave.c     1.7 08/12/85 14:04:20
  13.  *  which came from the ACGNJ BBS system at +1 201 753 9758.  Original
  14.  *  author unknown.
  15.  *
  16.  *  Ported to Amiga by William Loftus
  17.  *  Amiga Changes Copyright 1988 by William Loftus.  All rights reserved.
  18.  *  Additional Major Changes (c)Copyright 1989 by Matthew Dillon, All rights reserved
  19.  *
  20.  * 14-Oct-89, moved modem_init() to before poll_sys.
  21.  *
  22.  * -r option       (-r1 does a call out to all systems we have mail for)
  23.  * -D[EVICE] dev    sets serial device name (automatic from Getty)
  24.  * -U[NIT] unit     sets unit name (automatic from Getty)
  25.  * -h0            Ignore CD (carrier detect)
  26.  * -7
  27.  */
  28.  
  29.  
  30. #include "includes.h"           /* System include files, system dependent */
  31. #include "uucp.h"               /* Uucp definitions and parameters */
  32. #include <log.h>
  33. #include <dos.h>
  34. #include "version.h"
  35.  
  36. Prototype   int getname(int);
  37. Prototype   int get_proto(void);
  38. Prototype   int instr(char *, int);
  39. Prototype   int twrite(const char *, int);
  40. Prototype   void xlat_str(char *, char *);
  41. Prototype   int read_ctl(void);
  42. Prototype   int do_outbound(void);
  43. Prototype   int call_system(char *, int);
  44. Prototype   int call_sysline(char *);
  45. Prototype   int do_session(int);
  46. Prototype   int top_level(int);
  47. Prototype   int do_one_slave(void);
  48. Prototype   int do_one_master(void);
  49. Prototype   int yesno(char, int, int);
  50. Prototype   int host_send_file(char *);
  51. Prototype   int host_receive_file(char *);
  52. Prototype   int local_send_file(char *, int *);
  53. Prototype   int local_receive_file(void);
  54. Prototype   int receive_file(FILE *, char *, char *, char *, int);
  55. Prototype   int send_file(FILE *);
  56. Prototype   void main(int, char **);
  57.  
  58. #define MAX_FLAGS    40
  59.  
  60. extern int errno;
  61.  
  62.  
  63. static char *version20 = "$VER: uucico 1.21 (23 Sep 90)\n\r";
  64.  
  65. char    ttynam[NAMESIZE],        /* Name of tty we use as serial port */
  66.     srcnam[NAMESIZE],        /* Source file name */
  67.     dstnam[NAMESIZE],        /* Dest file name */
  68.     who[NAMESIZE] = "-",            /* Who sent the file */
  69.     flags[MAX_FLAGS],        /* Flags from file xfer cmd */
  70.     temp[NAMESIZE];         /* Temp file name */
  71.  
  72. int    ourpid = 0,            /* Our process ID */
  73.     ignore_time_restrictions = 0,    /* Call out even if L.sys sez no */
  74.     mode;                /* File mode from file xfer cmd */
  75.  
  76. char  host_name[MAX_HOST] = "AmigaUUCP Plus";  /* Other guy's host name */
  77. char  our_name[MAX_HOST];    /* Our uucp hostname, set from usenet.ctl */
  78. char  path[128];
  79. int   debug   = -1;    /* -1 indicates not set by command line or ctl file */
  80. int   f_wait  = 0;    /* wait for a call (-w) or calls (-w -e) after outbnd */
  81. int   loop    = 0;    /* Loop accepting logins if tty name specified */
  82. int   curtemp = 0;
  83. int   Overide = 0;    /* overide modem protocol        */
  84. int   Getty   = 0;    /* -Getty initiated            */
  85. int   IgnoreCD= 0;    /* xgetc() should ignore carrier?   */
  86. int   OurNameOv= 0;
  87. int   WindowOne= 0;
  88. int   SevenWire= 0;
  89. int   XDebug  = 0;    /* do not pass debug parameter to remote    */
  90.  
  91. #define MAX_STRING    200    /* Max length string to send/expect */
  92.  
  93. #define MSGO2IDX    7
  94.  
  95. /* We print these prompts */
  96.  
  97. char msgo0[] = "login: ";
  98. char msgo1[] = "Password:";
  99. char msgo2[10+MAX_HOST] = { "\20Shere" };   /*  NO =    */
  100. char msgo3[] = "\20ROK\0";
  101. char msgo3a[]= "\20P";
  102. char msgo3b[]= "\20Pg\0";
  103. char msgo4[] = "\20OOOOOOO\0";
  104.  
  105. /* We expect to receive these strings */
  106.  
  107. char msgi0[] = "uucp\r";
  108. char msgi1[] = "s8000\r";
  109. /* char msgi2[] = "\20S*\0"; We now scan it specially FIXME */
  110. char msgi3[] = "\20Ug\0";
  111. char msgi4[] = "OOOOOO";
  112.  
  113. /*
  114.  * Protocol switch data structure
  115.  */
  116.  
  117. #define turnon    gturnon
  118. #define rdmsg    grdmsg
  119. #define wrmsg    gwrmsg
  120. #define rddata    grddata
  121. #define wrdata    gwrdata
  122. #define turnoff gturnoff
  123.  
  124. int
  125. getname(isshere)
  126. int isshere;
  127. {
  128.     int data, count = 0;
  129.     static char msgi[MAX_STRING+SLOP];    /* Incoming trash buffer */
  130.  
  131.     /* Read data until null character */
  132.  
  133.     while ((data = xgetc(BYTE_TO)) != EOF) {
  134.     data &= 0x7F;
  135.     if (data == 020)
  136.         break;
  137.     }
  138.     if (data == EOF)
  139.     return FAIL;
  140.  
  141.     while ((data = xgetc(BYTE_TO)) != EOF && (data & 0x7F)) {
  142.     data &= 0x7F;
  143.     if (count == 0 && data != 'S')
  144.         continue;
  145.     if (count > sizeof(msgi) - 2)
  146.         continue;
  147.     msgi[count++] = (char)data;
  148.     }
  149.     msgi[count] = 0;
  150.  
  151.     if (debug > 8)
  152.     printf("GETNAME MSG (%d): %s\n", count, msgi);
  153.  
  154.     if (msgi[0] != 'S')
  155.     return FAIL;
  156.     if (isshere) {
  157.     for (count = 1; msgi[count] && msgi[count] != '='; ++count);
  158.     if (msgi[count] == '=')
  159.         ++count;
  160.     } else {
  161.     count = 1;
  162.     }
  163.     if (msgi[count]) {
  164.     if (debug > 8)
  165.         printf("Compare host names: '%s' '%s'\n", host_name, msgi + count);
  166.     strcpy (host_name, msgi + count);
  167.     }
  168.     strtok(host_name, " \t");     /*  put \0 after hostname */
  169.     if (debug > 8)
  170.     printf("Hostname is '%s'\n", host_name);
  171.     return SUCCESS;
  172. }
  173.  
  174. /*
  175.  *  get_proto() checks the list of protos given by the foriegn machine
  176.  *  checking for 'g' (which is the only proto we have).  Use only in master
  177.  *  mode.
  178.  */
  179.  
  180. int
  181. get_proto()
  182. {
  183.     int data;
  184.  
  185.     while ((data = xgetc(BYTE_TO)) != EOF) {
  186.     data &= 0x7F;
  187.     if (data == 0)
  188.         break;
  189.     if (data == 'g')
  190.         return(SUCCESS);
  191.     }
  192.     return FAIL;
  193. }
  194.  
  195. /*
  196.  * Medium level input routine.
  197.  *
  198.  * Look for an input string for the send-expect sequence.
  199.  * Return 0 for matching string, 1 for timeout before we found it.
  200.  * FIXME:  we only time out if the other end stops sending.  If it
  201.  *       keeps sending, we keep listening forever.
  202.  */
  203.  
  204. instr(s, n)
  205. char *s;
  206. int n;
  207. {
  208.     int data,count,j;
  209.     int i;
  210.     static char msgi[512];  /* Incoming trash buffer */
  211.  
  212.     count = 0;
  213.  
  214.     if (debug > 8) {
  215.     printf("Expecting ");
  216.     for (i = 0; i < n; i++)
  217.         printc(s[i]);
  218.     printf("\n");
  219.     }
  220.  
  221.     while ((data = xgetc(BYTE_TO)) != EOF) {
  222.     msgi[count++] = (char)data & 0x7F;
  223.  
  224.     if (count == sizeof(msgi)) {    /*  throw away first half */
  225.         count = sizeof(msgi) / 2;
  226.         bcopy(msgi + sizeof(msgi) / 2, msgi, sizeof(msgi) / 2);
  227.     }
  228.  
  229.     if (count >= n) {
  230.         for (i = n - 1, j = count - 1; i >= 0; i--, j--) {
  231.         if (*(s+i) != msgi[j])
  232.             break;
  233.         }
  234.         if (i < 0) {
  235.         if (debug > 8)
  236.             printf("\n");
  237.         return(0);
  238.         }
  239.     }
  240.     }
  241.  
  242.     if (debug > 8)
  243.     printf("\n");
  244.     msgi[count] = (char)0;
  245.     return(1);
  246. }
  247.  
  248. /*
  249.  * Debugging hack for stuff written to the modem.
  250.  */
  251.  
  252. int
  253. twrite(s, n)
  254. const char *s;
  255. int  n;
  256. {
  257.     int i;
  258.  
  259.     if (debug > 8) {
  260.     printf("Wrote:  ");
  261.     for (i = 0; i < n; i++)
  262.         printc(s[i]);
  263.     printf("\n");
  264.     }
  265.     return xwrite(s, n);
  266. }
  267.  
  268. /*
  269.  * MAIN ROUTINE.
  270.  *
  271.  * This is called at program startup.  It parses the arguments to the
  272.  * program (if any) and sets up to receive a call on the modem.
  273.  *
  274.  * If there are no arguments, we assume the caller is already on standard
  275.  * input, waiting to do uucp protocols (past the login prompt), and we
  276.  * just handle one caller.
  277.  *
  278.  * If there is an argument, it is the name of the tty device where we
  279.  * should listen for multiple callers and handle login and password.
  280.  */
  281.  
  282. void
  283. main(argc, argv)
  284. int argc;
  285. char *argv[];
  286. {
  287.     int     i;
  288.     char    *poll_sys = (char *)NULL;   /* System name to poll, or none */
  289.     short   rmode = 0;            /* 1 = master, 0 = slave    */
  290.  
  291.     LogProgram = "uucico";
  292.     LogHost = host_name;
  293.     LogWho  = who;
  294.  
  295.     onbreak(sigint);
  296.  
  297.     /* FIXME, use getopt */
  298.     /* scan command line arguments, kinda kludgy but it works */
  299.  
  300.     for (i = 1; i < argc; ++i) {
  301.     if (argv[i][0] != '-') {
  302.         printf("uucico: warning, extra args ignored: %s\n", argv[i]);
  303.         break;
  304.     }
  305.     switch (argv[i][1]) {
  306.     case 'N':
  307.         strcpy(our_name, argv[i] + 2);
  308.         OurNameOv = 1;
  309.         break;
  310.     case 'D':       /*  Serial Device   */
  311.         {
  312.         extern char *DeviceName;
  313.         DeviceName = argv[++i];
  314.         }
  315.         break;
  316.     case 'U':       /*  Serial Unit     */
  317.         {
  318.         extern long DeviceUnit;
  319.         DeviceUnit = atoi(argv[++i]);
  320.         }
  321.         break;
  322.     case 'g':
  323.     case 'G':
  324.         Getty = 1;
  325.         break;
  326.     case 'h':
  327.         IgnoreCD = atoi(argv[i] + 2);
  328.         break;
  329.     case 'w':
  330.         ++f_wait;
  331.         break;
  332.     case 'r':
  333.         rmode = atoi(&argv[i][2]);
  334.         break;
  335.     case 'X':
  336.         XDebug = 1;
  337.     case 'x':
  338.         debug = atoi(&argv[i][2]);
  339.         LogLevel = debug;
  340.         LogToStdout = 1;
  341.         printf("uucico: debug level set to %d\n", debug);
  342.         break;
  343.     case 'o':
  344.         Overide = 1;
  345.         break;
  346.     case 'n':
  347.         WindowOne = 1;  /*    force windowing mode to size=1     */
  348.         break;
  349.     case 'S':
  350.         ignore_time_restrictions++;
  351.     case 's':
  352.         poll_sys = &argv[i][2];
  353.         break;
  354.     case 'e':
  355.         ++loop;
  356.         break;
  357.     /* Is -t needed for MSDOS?  Why?  -- hoptoad!gnu */
  358.     case 't':
  359.         curtemp++;
  360.         printf("uucico: using ~uutemp.$$$ for temp file\n");
  361.         break;
  362.     case '7':
  363.         SevenWire = 1;
  364.         break;
  365.     default:
  366.         printf("uucico: warning, bad flag %s\n", argv[i]);
  367.         break;
  368.     }
  369.     }
  370.  
  371.     /* If argument provided, use it as name of comm port */
  372.  
  373.     /* FIXME, this needs some thought. */
  374.  
  375.     getcwd(path,128);
  376.     if (chdir(GetConfigDir(UUSPOOL))) {
  377.     perror("Can't chdir to Spool directory");
  378.     exit(2);
  379.     }
  380.  
  381.     read_ctl();
  382.  
  383.     /*
  384.      * If running via getty/login, our debug stdout had better
  385.      * go to a file, not to the usual stdout!
  386.      */
  387.  
  388.     if (debug > 0 && Getty) {
  389.     freopen("T:uuslave.log", "a", stdout);
  390.     }
  391.  
  392.     /*setvbuf(stdout, NULL, _IOLBF, 0);*/
  393.  
  394.     /* Timestamp the long debug log */
  395.  
  396.     if (debug > 0) {
  397.     long clock;
  398.  
  399.     time(&clock);
  400.     printf("\014\nuuslave log on tty '%s' starting %s\n",
  401.         ttynam, ctime(&clock));
  402.     }
  403.  
  404.     /* Log our presence so we humans reading the logs can find the
  405.        entries created by uuslave. */
  406.  
  407.     ulog(-1, "Startup %s", VERSION);
  408.  
  409.     amiga_setup();
  410.  
  411.     modem_init();
  412.  
  413.     if (poll_sys) {
  414.     if (*poll_sys == '\0')
  415.         poll_sys = (char *)NULL;
  416.     call_system(poll_sys, rmode);
  417.     if (!f_wait)
  418.         goto end;
  419.     } else {
  420.     if (rmode) {
  421.         do_outbound();
  422.         if (!f_wait)
  423.         goto end;
  424.     }
  425.     }
  426.  
  427.     do {
  428.     /*
  429.      *  Set up serial channel, wait for incoming call.
  430.      */
  431.     DEBUG(0, "\nRestarting\n", 0);
  432.  
  433.     if (Getty == 0 && Overide == 0)
  434.         openline();
  435.  
  436.     do_session(Getty);
  437.  
  438.     hangup();
  439.     DEBUG(0, "\nEnd of call\n", 0);
  440.     } while (loop && !Getty);
  441.  
  442. end:
  443.     cleanup();
  444. }
  445.  
  446. /*
  447.  * translate embedded escape characters
  448.  */
  449.  
  450. void
  451. xlat_str(msg, out)
  452. char    *msg;
  453. char    *out;
  454. {
  455.     int i  = 0;
  456.     int cr = 1;
  457.     /*int j  = 0;*/
  458.  
  459.     while (msg[i]) {
  460.     if (msg[i] == '\\') {
  461.         switch (msg[++i]) {
  462.         case 'r':            /* carriage return */
  463.         twrite("\r", 1);
  464.         /*out[j++] = 0x0d;*/
  465.         break;
  466.         case 'n':            /* line feed */
  467.         twrite("\n", 1);
  468.         /*out[j++] = 0x0a;*/
  469.         break;
  470.         case '\\':           /* back slash */
  471.         twrite("\\", 1);
  472.         /*out[j++] = '\\';*/
  473.         break;
  474.         case 't':            /* tab */
  475.         twrite("\t", 1);
  476.         /*out[j++] = '\t';*/
  477.         break;
  478.         case 'b':
  479.         SendBreak();
  480.         break;
  481.         case 'd':            /* delay */
  482.         Delay(180);
  483.         break;
  484.         case 's':            /* space */
  485.         twrite(" ", 1);
  486.         /*out[j++] = ' ';*/
  487.         break;
  488.         case 'c':            /* no CR at end */
  489.         cr = 0;
  490.         break;
  491.         default:        /* don't know so skip it */
  492.         break;
  493.         }
  494.         ++i;
  495.     } else {
  496.         twrite(msg + i, 1);
  497.         ++i;
  498.         /*out[j++] = msg[i++];*/
  499.     }
  500.     }
  501.     if (cr) {
  502.     twrite("\r", 1);
  503.     /*out[j++] = 0x0d;*/
  504.     }
  505.     /*out[j] = '\0';*/
  506. }
  507.  
  508. /*
  509.  * Read the control file and grab a few parameters.
  510.  */
  511.  
  512. int
  513. read_ctl()
  514. {
  515.     char *nodename = FindConfig(NODENAME);
  516.     char *debugstr = FindConfig(DEBUGNAME);
  517.  
  518.     if (nodename && OurNameOv == 0)
  519.     strcpy(our_name, nodename);
  520.     if (debugstr && debug < 0)
  521.     debug = atoi(debugstr);
  522.     return (1);
  523. }
  524.  
  525. /*
  526.  * Search spool queues for work, call the systems we need to call.
  527.  */
  528.  
  529. int
  530. do_outbound()
  531. {
  532.     return call_system((char *)NULL, 1);
  533. }
  534.  
  535. /*
  536.  * Call a specific system, or all systems that have work pending.
  537.  */
  538.  
  539. int
  540. call_system(sys, ifworkpend)
  541. char    *sys;
  542. {
  543.     FILE    *lsys;
  544.     static char buf[MAX_LSYS];
  545.     static char sysnam[MAX_HOST];
  546.     static char prev_name[MAX_HOST];
  547.     int     called = FAIL;
  548.  
  549.     /*
  550.      * Unix uucico just reads the directory, and calls the systems
  551.      * in the order of the files in the directory.  We want more
  552.      * control than that, though I'm not sure that L.sys order is
  553.      * best either.  For example, in the first call after 11PM,
  554.      * I'd like to call the sites that haven't been callable before
  555.      * 11PM first, and finish up with the ones I've been able to call
  556.      * all day.  FIXME.
  557.      */
  558.  
  559.     if (! (lsys = fopen(MakeConfigPath(UULIB, "L.sys"), "r"))) {
  560.     DEBUG(0, "uucico: can't open L.sys, errno %d\n", errno);
  561.     return 0;
  562.     }
  563.     sysnam[0] = '\0';               /* Initially, no previous sys */
  564.  
  565.     /* Once per system in L.sys... */
  566.     /* FIXME, handle continuation lines (trailing "\") */
  567.  
  568.     while (fgets(buf, sizeof buf, lsys)) {
  569.     if (buf[0] == '#' || buf[0] == '\n')
  570.         continue;
  571.  
  572.     /*
  573.      * Grab the system name.  If same as previous, and
  574.      * the previous call worked, skip it.
  575.      */
  576.  
  577.     strcpy(prev_name, sysnam);
  578.     (void) sscanf(buf, "%s", sysnam);
  579.     if (!strcmp(sysnam, prev_name)) {
  580.         if (called == SUCCESS)
  581.         continue;
  582.     }
  583.  
  584.     /*
  585.      * If a system name was specified, skip til we find it
  586.      * If none was specified, only call if there is work.
  587.      */
  588.  
  589.     if (sys) {
  590.         if (strcmp(sys, sysnam) != 0)
  591.         continue;
  592.         if (ifworkpend && !work_scan(sysnam)) {
  593.         ulog(-1, "No work for system %s", sysnam);
  594.         called = SUCCESS;
  595.         continue;
  596.         }
  597.     } else {
  598.         DEBUG(3,"searching for outbound to %s\n", sysnam);
  599.         if (!work_scan(sysnam)) {
  600.         DEBUG(3,"no work for %s\n", sysnam);
  601.         called = SUCCESS;    /* Don't try further */
  602.         continue;
  603.         }
  604.         DEBUG(2, "uucico: found work for %s\n", sysnam);
  605.     }
  606.  
  607.     called = call_sysline(buf);
  608.  
  609.     if (called == SUCCESS && sys)
  610.         break;
  611.     }
  612.  
  613.     fclose(lsys);
  614.     if (called == FAIL && sys)
  615.     DEBUG(0, "Could not call system %s\n", sys);
  616.     return 0;
  617. }
  618.  
  619. /*
  620.  *  Call out to a system, given its L.sys line.
  621.  */
  622.  
  623. int
  624. call_sysline(lsysline)
  625. char *lsysline;
  626. {
  627.     static char    tempname[MAX_HOST + 30 + SLOP];
  628.     static char    strbuf[MAX_STRING+SLOP];
  629.     char    *sysnam,
  630.         *times,
  631.         *acu,
  632.         *sbaud,
  633.         *telno,
  634.         *send,
  635.         *expct;
  636.     int     baud;
  637.  
  638.     who[0] = '-'; who[1] = '\0';    /* No user now (for logit) */
  639.  
  640.     /* FIXME, use the values it is ignoring here */
  641.  
  642.     sysnam = strtok(lsysline, " \t");
  643.     times =  strtok(NULL, " \t");   /* Time */
  644.     acu =    strtok(NULL, " \t");   /* ACU  */
  645.     sbaud =  strtok(NULL, " \t");   /* Baud */
  646.     telno =  strtok(NULL," \t");    /* phone*/
  647.  
  648.     strcpy(host_name, sysnam);
  649.  
  650.     if (ignore_time_restrictions == 0) {
  651.     if (CheckTimeRestrictions(times) == FAIL) {
  652.         ulog(-1, "Wrong Time To Call %s", sysnam);
  653.         return(FAIL);
  654.     }
  655.     }
  656.  
  657.     baud = atoi(sbaud);
  658.  
  659.     /*    FIX ME, acu not implemented ?    */
  660.     DEBUG(4, "Opening outgoing line %s\n", acu);
  661.     if (openout(acu, baud) != SUCCESS)
  662.     return FAIL;
  663.  
  664.     if (Overide == 0) {
  665.     if (dial_nbr(telno)) {
  666.         ulog(-1, "FAILED call to %s", host_name);
  667.         return FAIL;
  668.     }
  669.     }
  670.  
  671.     /* FIXME, log tty, baud rate, ... */
  672.     ulog(-1, "DIALED %s", host_name);
  673.  
  674.     /*
  675.      * Process send-expect strings.
  676.      * FIXME, deal with "-", BREAK, etc.
  677.      */
  678.  
  679.     while (send = (char*)strtok((char *)NULL, " \t")) {
  680.     if (send[0] != '"' || send[1] != '"' || send[2] != '\0') {
  681.         if (instr(send, strlen(send)))
  682.             goto bort1;
  683.     }
  684.  
  685.     if (expct = (char*)strtok((char *)NULL, " \t")) {
  686.         /* FIXME secondary strings, e.g. ogin:-EOT-ogin: */
  687.         xlat_str(expct, strbuf);
  688.  
  689.         /*twrite(strbuf, strlen(strbuf));*/
  690.     }
  691.     }
  692.  
  693.     /*
  694.      * FIXME, there should be a way to detect login/passwd
  695.      * failure here and keep doing the script rather than
  696.      * continuing to expect Shere at another login: prompt.
  697.      */
  698.  
  699.     ulog(-1, "SUCCEEDED call to %s", host_name);
  700.  
  701.  
  702.     if (getname(1))         /*  get name        */
  703.     goto bort1;
  704.                 /*    send response    */
  705.     sprintf(tempname, "\20S%s -Q0 -x%d\0", our_name, (XDebug) ? 0 : debug);
  706.     twrite(tempname, strlen(tempname)+1); /* Including null */
  707.  
  708.     /* wait for ok message, wait for protocol request
  709.      * send protocol 'g' response */
  710.     /* FIXME, we don't actually wait for the ROK message, since
  711.      * it is immediately followed by the Pprotos message.  We
  712.      * currently just look for a Pg message.  This needs work.
  713.      * FIXME, WE CAN'T TALK TO SITES THAT SUPPORT more than 'g'.
  714.      */
  715.  
  716.     if (instr(msgo3a, sizeof(msgo3a)-1)) {
  717.     if (!get_proto())
  718.        goto bort1;
  719.     }
  720.  
  721.  
  722.     twrite( msgi3, sizeof(msgi3)-1);
  723.  
  724.     ResetGIO();                         /* reset GIO protocol   */
  725.  
  726.     if (turnon(1))
  727.     goto bort1;
  728.  
  729.     ulog(-1, "OK Startup");
  730.  
  731.     top_level(1);
  732.     hangup();
  733.     return SUCCESS;
  734.  
  735. bort1:
  736.     hangup();
  737.     return FAIL;
  738. }
  739.  
  740. /* Handle a single uucp [slave] login session */
  741.  
  742. int
  743. do_session(ontheline)
  744. int ontheline;
  745. {
  746.     if (ontheline == 0) {
  747.     /* output login request, verify uucp */
  748.     twrite(msgo0,sizeof(msgo0)-1);
  749.     if (instr(msgi0,sizeof(msgi0)-1)) {
  750.         printf("uucico: invalid login name\n");
  751.         goto bort;
  752.     }
  753.  
  754.     /* output password request, verify s8000 */
  755.     twrite(msgo1,sizeof(msgo1)-1);
  756.     if (instr(msgi1,sizeof(msgi1)-1)) {
  757.         printf("uucico: invalid password\n");
  758.         goto bort;
  759.     }
  760.  
  761.     printf("uucico: correct login\n");
  762.     }
  763.  
  764.     /*
  765.      *    send Shere=<myhost>
  766.      *
  767.      *    Apparently mac UUCP has a bug that only allows 7
  768.      *    char host names, and it fails if it gets shere=<myhost>
  769.      *    where <myhost> is > 7 chars.
  770.      */
  771.  
  772.     /*strcpy(msgo2 + MSGO2IDX, our_name);*/
  773.     twrite(msgo2,strlen(msgo2)+1);
  774.  
  775.     /*
  776.      *    get \020S<host> -Qn n    (??)
  777.      */
  778.  
  779.     if (getname(0))
  780.     goto bort;
  781.  
  782.     /* output ok message, output protocol request, wait for response */
  783.  
  784.     twrite(msgo3,sizeof(msgo3)-1);
  785.  
  786.     /* FIXME, make the protocol list here, and use it */
  787.     twrite(msgo3b,sizeof(msgo3b)-1);
  788.     if (instr(msgi3,sizeof(msgi3)-1))
  789.         goto bort;
  790.  
  791.     ResetGIO();                         /* reset GIO protocol   */
  792.  
  793.     if (turnon(0))
  794.     goto bort;
  795.  
  796.     ulog(-1, "OK Startup");
  797.     top_level(0);
  798.  
  799. bort:
  800.     if (debug > 0)
  801.     printf("uucico: call complete\n");
  802.     return (1);
  803. }
  804.  
  805. /*
  806.  * Handle transactions "at top level", as Unix uucp's debug log says.
  807.  *
  808.  * As master, we scan our queues for work and send requests to the
  809.  * other side.    When done, we send a hangup request and switch to slave mode.
  810.  *
  811.  * As slave, we accept requests from the other side; when it is done,
  812.  * it sends a hangup request, and we switch to master mode, if we have
  813.  * any work queued up for that system.
  814.  *
  815.  * This repeats as long as either side has work to do.    When all the
  816.  * queued work is done, we agree to hang up, terminate the packet protocol,
  817.  * and return to the caller.  (We still haven't hung up the phone line yet.)
  818.  *
  819.  * A curious feature of the hangup protocol is that it is not a simple
  820.  * question-answer.  The master says "H", asking about hangup.  The
  821.  * slave responds "HY" saying OK.  The master then says "HY" also,
  822.  * then both of them hang up.  Maybe this is to make sure the first HY
  823.  * got ack'ed?  Anyway, an "H" is reported as HANGUP and an "HY" as
  824.  * HANGNOW.  After we send an HY, we go back to listening for commands;
  825.  * if the master sends something other than HY, we'll do it.
  826.  */
  827.  
  828. #define HANGUP    2        /* Signal to switch master/slave roles */
  829. #define HANGNOW 3        /* Signal to hang up now */
  830. #define COPYFAIL    4    /* File copy failed */
  831.  
  832. int
  833. top_level(master_mode)
  834. int master_mode;
  835. {
  836.     static char    buf[MAXMSGLEN];    /* For hangup responses */
  837.  
  838.  
  839.     if (master_mode) {
  840.     (void) work_scan(host_name);    /* Kick off queue scan */
  841.     goto master;
  842.     }
  843.  
  844.     for (;;) {
  845.     slave:            /*  SLAVE SIDE    */
  846.     for (;;) {
  847.         DEBUG(4, "*** TOP *** - slave\n", 0);
  848.         switch (do_one_slave()) {
  849.         case SUCCESS:
  850.         break;
  851.         case FAIL:
  852.         return FAIL;
  853.         case HANGUP:
  854.         if (work_scan(host_name)) {
  855.             if (wrmsg("HN"))
  856.             return FAIL;
  857.             goto master;
  858.         } else {
  859.             if (wrmsg("HY"))
  860.             return FAIL;
  861.             break;    /*  go to master mode */
  862.         }
  863.         case HANGNOW:
  864.         goto quit;
  865.         }
  866.     }
  867.     master:    /*  MASTER SIDE */
  868.     for (;;) {
  869.         DEBUG(4, "*** TOP *** - master\n", 0);
  870.         switch (do_one_master()) {
  871.         case SUCCESS:
  872.         break;
  873.         case FAIL:
  874.         return FAIL;
  875.         case HANGUP:
  876.         /* We wrote an H command, what's the resp? */
  877.         if (rdmsg(buf, MAXMSGLEN) != SUCCESS) {
  878.             return FAIL;
  879.         }
  880.         if (buf[0] != 'H')
  881.             return FAIL;
  882.         if (buf[1] == 'N')
  883.             goto slave;
  884.         else {
  885.             /* Write the final HY */
  886.             if (wrmsg("HY"))
  887.             return FAIL;
  888.             goto quit;
  889.         }
  890.         }
  891.     }
  892.     }
  893.  
  894. quit:
  895.     /* Shut down the packet protocol */
  896.  
  897.     turnoff();
  898.  
  899.     /* Write the closing sequence */
  900.  
  901.     twrite(msgo4, sizeof(msgo4)-1);
  902.     (void) instr(msgi4, sizeof(msgi4)-1);
  903.  
  904.     twrite(msgo4, sizeof(msgo4)-1);
  905.  
  906.     strcpy(who, "-");
  907.     ulog(-1, "OK Conversation complete");
  908.  
  909.     return SUCCESS;   /* Go byebye */
  910. }
  911.  
  912. /*
  913.  * We are slave; get a command from the other side and execute it.
  914.  *
  915.  * Result is SUCCESS, FAIL, HANGUP, or HANGNOW.
  916.  */
  917.  
  918. int
  919. do_one_slave()
  920. {
  921.     static char msg[MAXMSGLEN];        /* Master's message to us */
  922.  
  923.     /* Get master's command */
  924.     if (rdmsg(msg, MAXMSGLEN) != SUCCESS)
  925.     return FAIL;
  926.  
  927.     /* Print it for easy debugging */
  928.     DEBUG(5,"\nCommand: %s\n\n", msg);
  929.  
  930.     switch (msg[0]) {
  931.     case 'S':
  932.     if (msg[1] != ' ')
  933.         break;
  934.     return host_send_file(msg);
  935.     case 'R':
  936.     if (msg[1] != ' ')
  937.         break;
  938.     return host_receive_file(msg);
  939.     case 'X':
  940.     /*
  941.      * Cause uuxqt to run (on certain files?)
  942.      * See Protocol.doc for sketchy details.
  943.      */
  944.     break;
  945.     case 'H':
  946.     if (msg[1] == '\0') return HANGUP;
  947.     if (msg[1] == 'Y')  return HANGNOW;
  948.     if (msg[1] == 'N')  return SUCCESS;     /* Ignore HN to slave */
  949.     break;
  950.     }
  951.  
  952.     /* Unrecognized packet from the other end */
  953.  
  954.     DEBUG(0, "Bad control packet refused: %s\n", msg);
  955.     if (yesno(msg[0], 0, 0))        /* FIXME: return error code */
  956.     return FAIL;
  957.     return SUCCESS;
  958. }
  959.  
  960. /*
  961.  *  Do one piece of work as master.
  962.  *
  963.  *  FIXME:  we don't handle the flags, e.g. -c, properly!
  964.  *
  965.  *  Now only dequeues queue file if all transfers were successful.
  966.  */
  967.  
  968. int
  969. do_one_master()
  970. {
  971.     FILE    *fd;
  972.     char    *sname;
  973.     static char cmnd[256];        /* Command character */
  974.     static char buf[256];
  975.     int     fail = SUCCESS;
  976.     int     failaccum = 0;
  977.     int     num;
  978.     int     delmeflag;
  979.     static char notify[NAMESIZE];   /* A bit large...FIXME */
  980.     char    *delList[16];        /* delete files list   */
  981.     short   di = 0;
  982.  
  983.     /* FIXME: do the notify stuff */
  984.  
  985.     sname = work_next();
  986.     if (!sname) {
  987.     /* No more work, time to hang up. */
  988.     if (wrmsg("H"))
  989.         return FAIL;
  990.     return HANGUP;
  991.     }
  992.  
  993.     DEBUG(2, "Request file %s\n", sname);
  994.  
  995.     LockFile(sname);
  996.  
  997.     fd = fopen(sname, "r");
  998.     if (fd == NULL) {
  999.     UnLockFile(sname);
  1000.     DEBUG(0, "uucico: couldn't open %s\n", sname);
  1001.     return SUCCESS;
  1002.     }
  1003.  
  1004.     while (fgets(buf, sizeof buf, fd)) {
  1005.     DEBUG(3, "Queued request: %s", buf);
  1006.  
  1007.     if (buf[1] != ' ')
  1008.         goto badnum;
  1009.  
  1010.     num = sscanf(buf, "%s %s %s %s %s %s %o\n",
  1011.         cmnd, srcnam, dstnam, who, flags, temp, &mode, notify
  1012.     );
  1013.  
  1014.     switch (cmnd[0]) {
  1015.     case 'S':
  1016.         if (num < 7 || num > 8)
  1017.         goto badnum;
  1018.         fail = local_send_file(buf, &delmeflag);
  1019.         if (delmeflag) {
  1020.         if (di == sizeof(delList)/sizeof(delList[0])) {
  1021.             ulog(-1, "Too many source files in Cmd file! %s", sname);
  1022.         } else {
  1023.             delList[di] = malloc(strlen(temp) + 1);
  1024.             strcpy(delList[di], temp);
  1025.             ++di;
  1026.         }
  1027.         }
  1028.         break;
  1029.     case 'R':
  1030.         if (num != 5) {
  1031.         if (debug > 7)
  1032.             printf("Invalid scanf %d/5 :%s:%s:%s\n", num, cmnd, srcnam, dstnam);
  1033.         goto badnum;
  1034.         }
  1035.         fail = local_receive_file();
  1036.         break;
  1037.     default:
  1038.     badnum:
  1039.         DEBUG(0, "Unknown/invalid queued request: %s\n", buf);
  1040.         ++fail;
  1041.         break;
  1042.     }
  1043.     if (fail != SUCCESS)
  1044.         ++failaccum;
  1045.  
  1046.     /* FIXME, what does uucp do if one of N xfers fails? */
  1047.  
  1048.     if (fail == FAIL) {
  1049.         ulog(-1, "Error in work file %s", sname);
  1050.         ulog(-1, "Bad line is: %s", buf);
  1051.     }
  1052.     }
  1053.     fclose(fd);
  1054.  
  1055.     /*
  1056.      *    If we successfuly copied everything zap the queue file
  1057.      *    and any local data files...
  1058.      */
  1059.  
  1060.     if (failaccum == 0) {
  1061.     while (di) {
  1062.         --di;
  1063.         remove(delList[di]);
  1064.         free(delList[di]);
  1065.     }
  1066.     fail = remove(sname);
  1067.     UnLockFile(sname);
  1068.     if (fail != 0) {
  1069.         ulog(-1, "Unable to remove work file %s", sname);
  1070.         DEBUG(0, "Can't remove, errno %d\n", errno);
  1071.     } else {
  1072.         DEBUG(4, "Removed work file %s\n", sname);
  1073.     }
  1074.     } else {
  1075.     UnLockFile(sname);
  1076.     }
  1077.     return SUCCESS;
  1078. }
  1079.  
  1080. /* Send a "yes or no" packet with character 'c'. */
  1081.  
  1082. int
  1083. yesno(c, true, err)
  1084. char c;
  1085. int true;
  1086. int err;
  1087. {
  1088.     char buf[21];
  1089.  
  1090.     buf[0] = c;
  1091.     buf[1] = true? 'Y': 'N';
  1092.     buf[2] = 0;
  1093.     if (err && !true)
  1094.     sprintf(buf+2,"%d", err);
  1095.  
  1096.     return wrmsg(buf);
  1097. }
  1098.  
  1099. /*
  1100.  *  SLAVE MODE, Master wishes to send a file to us
  1101.  *
  1102.  *  SECURITY:    If file is not in list of allowed directories
  1103.  *        disallow transfer.  UUSPOOL:   is always in the
  1104.  *        list.
  1105.  *
  1106.  *        If file is for UUSPOOL: (the current dir), disallow "C." files
  1107.  *        NOTE: success return and file redirected to T: as this can
  1108.  *        occur only if somebody purposefully is trying to break us.
  1109.  *
  1110.  *  Return 0 = success
  1111.  */
  1112.  
  1113. int
  1114. host_send_file(msg)
  1115. char  *msg;
  1116. {
  1117.     FILE *fddsk;            /* Disk file pointer */
  1118.     static char cmnd[256];        /* Command character */
  1119.     int r;
  1120.     int nor = 0;
  1121.  
  1122.     sscanf(msg,"%s %s %s %s %s %s %o",
  1123.         cmnd, srcnam, dstnam, who, flags, temp, &mode);
  1124.  
  1125.     ulog(-1, "REQUESTED %s", msg);
  1126.     munge_filename(dstnam, dstnam);           /* Translate to local name */
  1127.     strcpy (temp, TmpFileName(dstnam));       /* Create a handy temp file */
  1128.  
  1129.     if (SecurityDisallow(dstnam, 'w')) {
  1130.     ulog(-1, "REQUEST FAILED -- SECURITY");
  1131.     if (yesno('S', 0, 4))
  1132.         return FAIL;
  1133.     return SUCCESS;
  1134.     }
  1135.     if (SecurityDisallow(dstnam, 'c') > 0) {
  1136.     ulog(-1, "REQUEST FAILED -- SECURITY, REMOTE TRIED TO SEND");
  1137.     ulog(-1, "US A COMMAND FILE: %s, FILE COPIED TO T:Bad-Cmd", dstnam);
  1138.     strcpy(dstnam, "T:Bad-Cmd");
  1139.     nor = 1;
  1140.     }
  1141.  
  1142.     /* FIXME: deal with file modes now that we fopen. */
  1143.  
  1144.     LockFile(temp);
  1145.  
  1146.     fddsk = fopen(temp, "wb" /*, mode|0600 */);
  1147.     if (fddsk == NULL) {
  1148.     UnLockFile(temp);
  1149.     /* Can't open file -- send error response */
  1150.     if (debug > 0) {
  1151.         printf("Cannot open temp file %s (%s) for writing, errno=%d\n",
  1152.         temp,
  1153.         dstnam,
  1154.         errno
  1155.         );
  1156.     }
  1157.     ulog(-1, "REQUEST FAILED -- TEMP FILE");
  1158.     if (yesno('S', 0, 4))
  1159.         return FAIL;
  1160.     return SUCCESS;
  1161.     }
  1162.  
  1163.     /* FIXME: Are the above permissions right?? */
  1164.     /* FIXME: Should we create directories for the file? */
  1165.  
  1166.     if (yesno('S',1, 0)) {  /* Say yes */
  1167.     fclose(fddsk);
  1168.     unlink(temp);
  1169.     UnLockFile(temp);
  1170.     return 1;
  1171.     }
  1172.     r = receive_file(fddsk, temp, dstnam, srcnam, nor);
  1173.     UnLockFile(temp);
  1174.     return(r);
  1175. }
  1176.  
  1177. /*
  1178.  *  SLAVE MODE, Master wants us to send a file to it
  1179.  *
  1180.  *  SECURITY:    If file is not in list of allowed directories
  1181.  *        disallow transfer.  UUSPOOL:   is always in the
  1182.  *        list.
  1183.  *
  1184.  *  0 = sucess
  1185.  */
  1186.  
  1187. int
  1188. host_receive_file(msg)
  1189. char  *msg;
  1190. {
  1191.     FILE *fddsk;     /* Disk file descriptor */
  1192.     int x;
  1193.     static char cmnd[256];        /* Command character */
  1194.  
  1195.     ulog(-1, "REQUESTED %s", msg);
  1196.  
  1197.     sscanf(msg,"%s %s %s",cmnd,srcnam,dstnam);
  1198.     munge_filename(srcnam, temp);
  1199.  
  1200.     if (SecurityDisallow(temp, 'r')) {
  1201.     ulog(-1, "COPY FAILED -- SECURITY");
  1202.     if (yesno('S', 0, 4))
  1203.         return FAIL;
  1204.     return SUCCESS;
  1205.     }
  1206.  
  1207.     fddsk = fopen(temp, "rb");              /* Try to open the file */
  1208.     if (fddsk == NULL) {
  1209.     /* File didn't open, sigh. */
  1210.     if (debug > 0) {
  1211.         printf("Cannot open file %s (%s) for reading, errno=%d\n",
  1212.         temp, srcnam, errno
  1213.         );
  1214.     }
  1215.     ulog(-1, "DENIED CAN'T OPEN %s", temp);
  1216.     if (yesno('R', 0, 2))
  1217.         return 1;
  1218.     return 0;
  1219.     }
  1220.  
  1221.     if (yesno('R',1, 0)) {  /* Say yes */
  1222.     fclose(fddsk);
  1223.     return 1;
  1224.     }
  1225.  
  1226.     x = send_file(fddsk);
  1227.  
  1228.     switch (x) {
  1229.     default:
  1230.     return x;
  1231.     case COPYFAIL:
  1232.     /* We don't care if the copy failed, since the master
  1233.        asked for the file and knows the result. */
  1234.     return SUCCESS;
  1235.     }
  1236.     return 1;
  1237. }
  1238.  
  1239. /*
  1240.  *  MASTER MODE, We want to send a file.
  1241.  *
  1242.  *  Return FAIL, SUCCESS, or COPYFAIL.
  1243.  *
  1244.  *  SUCCESS is returned either if the file was not found locally (local
  1245.  *  error, and the queued transfer should be flushed) or if it was moved
  1246.  *  successfully.  COPYFAIL indicates that the queued transfer should be
  1247.  *  left queued, and later retried.  FIXME, there are several failure points
  1248.  *  in the transaction (see Protocol.doc) and we need finer control here.
  1249.  */
  1250.  
  1251. int
  1252. local_send_file(workstr, delmeflag)
  1253. char *workstr;
  1254. int *delmeflag;
  1255. {
  1256.     static char buf[MAXMSGLEN];    /* Used for both xmit and receive */
  1257.     FILE *fddsk;        /* Disk file descriptor */
  1258.     int res;            /* Result and file removal status */
  1259.  
  1260.     *delmeflag = 0;
  1261.  
  1262.     /* WHY are temp and srcnam switched?  FIXME!  And no notify? */
  1263.  
  1264.     sprintf(buf,"S %s %s %s %s %s 0%o %s",
  1265.     temp, dstnam, who, flags, srcnam, mode, who
  1266.     );
  1267.  
  1268.     ulog(-1, "REQUEST %s", buf);
  1269.  
  1270.     if (strchr(flags, 'c')) {
  1271.     munge_filename(srcnam, temp);
  1272.     } else {
  1273.     munge_filename(temp, temp);
  1274.     }
  1275.     LockFile(temp);
  1276.     fddsk = fopen(temp, "rb");
  1277.     if (fddsk == NULL) {
  1278.     UnLockFile(temp);
  1279.     /* FIXME -- handle queued request for nonexistent file */
  1280.     if (debug > 0)
  1281.         printf("Can't open file %s (%s), errno=%d\n",
  1282.         temp,
  1283.         srcnam,
  1284.         errno
  1285.         );
  1286.     ulog(-1, "NOT FOUND %s", temp);
  1287.     /* return COPYFAIL;*/
  1288.     return SUCCESS;     /*    assume file previously sent */
  1289.     }
  1290.  
  1291.     /* Tell the other side we want to send this file */
  1292.  
  1293.     if (wrmsg(buf) != SUCCESS) {
  1294.     DEBUG(0, "problem sending request\n", 0);
  1295.     fclose(fddsk);
  1296.     UnLockFile(temp);
  1297.     return FAIL;
  1298.     }
  1299.  
  1300.     /* See what they have to say about it */
  1301.  
  1302.     if (rdmsg(buf, MAXMSGLEN) != SUCCESS) {
  1303.     fclose(fddsk);
  1304.     UnLockFile(temp);
  1305.     return FAIL;
  1306.     }
  1307.     if ((buf[0] != 'S') || (buf[1] != 'Y')) {
  1308.     ulog(-1, "REQUEST DENIED %s", buf);
  1309.     fclose(fddsk);
  1310.     UnLockFile(temp);
  1311.     return FAIL;
  1312.     }
  1313.     res = send_file(fddsk); /* FAIL, SUCCESS, or COPYFAIL */
  1314.  
  1315.     /* Delete the source file if it was just a copy */
  1316.  
  1317.     if (res != SUCCESS) {
  1318.     UnLockFile(temp);
  1319.     return res;
  1320.     }
  1321.     if (strchr(flags, 'c')) {   /* If copied direct from source */
  1322.     UnLockFile(temp);
  1323.     return res;        /* ...just return. */
  1324.     }
  1325.     *delmeflag = 1;
  1326.     UnLockFile(temp);
  1327.  
  1328.     return res;
  1329. }
  1330.  
  1331. /*
  1332.  *  MASTER MODE, We wish to receive a specific file so we ask for it
  1333.  *
  1334.  *  Return 0 = success
  1335.  */
  1336.  
  1337. int
  1338. local_receive_file()
  1339. {
  1340.     static char buf[MAXMSGLEN];
  1341.     FILE *fddsk;            /* Disk file pointer */
  1342.     int r;
  1343.  
  1344.     /* FIXME, test dest file access before we ask for it. */
  1345.  
  1346.     sprintf(buf,"R %s %s %s %s %s 0%o %s",
  1347.     srcnam, dstnam, who, flags, temp, mode, who
  1348.     );
  1349.  
  1350.     munge_filename(dstnam, dstnam);           /* tlate to local name      */
  1351.     strcpy (temp, TmpFileName(dstnam));       /* Create a handy temp file */
  1352.  
  1353.     /* FIXME: deal with file modes now that we fopen. */
  1354.     /* FIXME: Are the above permissions right?? */
  1355.     /* FIXME: Should we create directories for the file? */
  1356.  
  1357.     LockFile(temp);
  1358.     fddsk = fopen(temp, "wb" /*, mode|060 */);
  1359.  
  1360.     if (fddsk == NULL) {
  1361.     UnLockFile(temp);
  1362.     /* Can't open temp file -- send error response */
  1363.     if (debug > 0) {
  1364.         printf("Cannot open temp file %s (%s) for writing, errno=%d\n",
  1365.         temp,
  1366.         dstnam,
  1367.         errno
  1368.         );
  1369.     }
  1370.     ulog(-1, "REQUEST FAILED -- TEMPFILE");
  1371.     return FAIL;
  1372.     }
  1373.  
  1374.     ulog(-1, "REQUEST %s", buf);
  1375.     if (wrmsg(buf) != SUCCESS) {
  1376.     fclose(fddsk);
  1377.     UnLockFile(temp);
  1378.     printf("uucico: problem sending request\n");
  1379.     return FAIL;
  1380.     }
  1381.  
  1382.     /* See what the other side has to say about it */
  1383.  
  1384.     if (rdmsg(buf, MAXMSGLEN) != SUCCESS) {
  1385.     fclose(fddsk);
  1386.     UnLockFile(temp);
  1387.     return FAIL;
  1388.     }
  1389.     if ((buf[0] != 'R') || (buf[1] != 'Y')) {
  1390.     ulog(-1, "REQUEST DENIED %s", buf);
  1391.     fclose(fddsk);
  1392.     UnLockFile(temp);
  1393.     return SUCCESS; /* FIXME, should do something more here */
  1394.     }
  1395.  
  1396.     r = receive_file(fddsk, temp, dstnam, srcnam, 0);
  1397.     UnLockFile(temp);
  1398.     return(r);
  1399. }
  1400.  
  1401. /*
  1402.  *  General receive file
  1403.  */
  1404.  
  1405. int
  1406. receive_file(fddsk, temp, dstnam, srcnam, norename)
  1407. FILE *fddsk;
  1408. char    *temp, *dstnam, *srcnam;
  1409. {
  1410.     int status;
  1411.     int error = 0;            /* No errors so far */
  1412.  
  1413.     if (rddata(fddsk) != SUCCESS)
  1414.     error++;
  1415.     status = fclose(fddsk);         /* Make sure the data got here */
  1416.     if (status != 0) {
  1417.     error++;
  1418.     DEBUG(0, "fclose errno=%d\n", errno);
  1419.     }
  1420.  
  1421.     /*
  1422.      *    Move the file from its temp location to its real location,
  1423.      *    This needs to be able to copy a file if a simple rename
  1424.      *    does not suffice.  Should create directories if necesary.
  1425.      *    should use source ]name if target is a directory (i.e. no
  1426.      *    target source name
  1427.      */
  1428.  
  1429.     unlink(dstnam);
  1430.  
  1431.     if (norename)       /*  for security redirect   */
  1432.     status = 0;
  1433.     else
  1434.     status = rename(temp, dstnam);
  1435.  
  1436.     if (status != 0) {
  1437.     error++;
  1438.     if (debug > 0) {
  1439.         printf("Cannot rename file %s to %s, errno=%d\n",
  1440.         temp, dstnam, errno);
  1441.     }
  1442.     }
  1443.  
  1444.     ulog(-1, "COPY %s", error ? "FAILED": "SUCCEEDED");
  1445.  
  1446.     if (yesno('C', error == 0, 5))  /* Send yes or no */
  1447.     return FAIL;
  1448.  
  1449.     return SUCCESS;
  1450. }
  1451.  
  1452. /*
  1453.  * general file send routine
  1454.  * Return SUCCESS, FAIL, or COPYFAIL.
  1455.  */
  1456.  
  1457. int
  1458. send_file(fddsk)
  1459. FILE *fddsk;     /* Disk file pointer */
  1460. {
  1461.     static char ansbuf[MAXMSGLEN];
  1462.  
  1463.     if (wrdata(fddsk) != SUCCESS) {
  1464.     fclose(fddsk);
  1465.     return COPYFAIL;
  1466.     }
  1467.     fclose(fddsk);
  1468.  
  1469.     /* Await the "CY" or "CNddd" packet, and toss it. */
  1470.  
  1471.     while (1) {
  1472.     if (rdmsg(ansbuf, MAXMSGLEN) != SUCCESS)
  1473.         return COPYFAIL;
  1474.     if (ansbuf[0] != 'C') {
  1475.         DEBUG(0,"\nDidn't get 'CY' or 'CN', got %s\n", ansbuf);
  1476.         /* and loop looking for C message */
  1477.     } else if (ansbuf[1] == 'Y') {
  1478.         ulog(-1, "REQUESTED %s", ansbuf);
  1479.         return SUCCESS;
  1480.     } else {
  1481.         ulog(-1, "COPY FAILED %s", ansbuf);
  1482.         return COPYFAIL;
  1483.     }
  1484.     }
  1485.     return COPYFAIL;
  1486. }
  1487.  
  1488.