home *** CD-ROM | disk | FTP | other *** search
- /*
- * UUCICO.C
- *
- * (C) Copyright 1987 by John Gilmore.
- * Copying and use of this program are controlled by the terms of the Free
- * Software Foundation's GNU Emacs General Public License.
- *
- * This *MUST* be compiled with 32-bit ints.
- *
- * Derived from:
- * i[$]uuslave.c 1.7 08/12/85 14:04:20
- * which came from the ACGNJ BBS system at +1 201 753 9758. Original
- * author unknown.
- *
- * Ported to Amiga by William Loftus
- * Amiga Changes Copyright 1988 by William Loftus. All rights reserved.
- * Additional Major Changes (c)Copyright 1989-91 by Matthew Dillon, All rights reserved
- * Additional Changes (alternate send-expect) by Chris Hind Genly),
- * (c)Copyright 1991 by Chris Hind Genly, All rights Reserved
- * Xferstat support copyright 1992 by John Bickers.
- * Major changes copyright 1992, 1993 by Steve Drew.
- * Major changes copyright 1993, 1994 by Michael B. Smith.
- *
- * Everyone's has reserved all their rights. So there.
- */
-
- #include <errno.h>
- #include "includes.h" /* System include files, system dependent */
- #include "uucp.h" /* Uucp definitions and parameters */
- #include <log.h>
- #include "version.h"
- #include <owndevunit.h>
-
- IDENT (".30");
-
- static const char
- ver [] = "$VER: UUCICO 1.17.30 (2.6.94)",
- Copyright [] = COPYRIGHT;
-
- #define PROTOF_SHEREEQUALS 0x0001 /* ProtoHacks */
-
- Prototype int getname (int);
- Prototype int get_proto (void);
- Prototype int instr (char *, int, int);
- Prototype int inline (int, char *, int);
- Prototype int twrite (const char *, int);
- Prototype void xlat_str (char *);
- Prototype int read_ctl (void);
- Prototype int do_outbound (void);
- Prototype int call_system (char *, int);
- Prototype int call_sysline (char *);
- Prototype int do_session (int);
- Prototype int top_level (int);
- Prototype int do_one_slave (void);
- Prototype int do_one_master (void);
- Prototype int yesno (char, int, int);
- Prototype int host_send_file (char *);
- Prototype int host_receive_file (char *);
- Prototype int local_send_file (char *, int *);
- Prototype int local_receive_file (void);
- Prototype int receive_file (FILE *, char *, char *, char *, int);
- Prototype int send_file (FILE *);
-
- Prototype int BigGOpt;
- Prototype int BytesIn;
- Prototype int BytesOut;
- Prototype int debug;
- Prototype int DoAttempt;
- Prototype int ExitCode;
- Prototype int Getty;
- Prototype int IgnoreCD;
- Prototype int IgnoreDTR;
- Prototype int NoDelay;
- Prototype int OldPri;
- Prototype int Overide;
- Prototype int PacketTimeout;
- Prototype int PriMode;
- Prototype int ProtoHacks;
- Prototype int SegSize;
- Prototype int SendExpectTimeout;
- Prototype int SevenWire;
- Prototype int UseSubDirs;
- Prototype int VarPackets;
- Prototype int WindowSize;
-
- Prototype char *uuspool;
-
- void LogTimes (int);
- void mail_notify (char *from, char *real, char *subject);
- void uuxqt (void);
-
- #define MAX_FLAGS 40
-
- char
- ttynam [NAMESIZE], /* Name of tty we use as serial port */
- srcnam [NAMESIZE], /* Source file name */
- dstnam [NAMESIZE], /* Dest file name */
- who [NAMESIZE] = "-", /* Who sent the file */
- flags [MAX_FLAGS], /* Flags from file xfer cmd */
- temp [NAMESIZE]; /* Temp file name */
-
- int
- _bufsiz = 8192, /* stdio buffer size */
- ignore_time_restrictions = 0, /* Call out even if L.sys sez no */
- mode; /* File mode from file xfer cmd */
-
- char
- host_name [MAX_HOST] = "AmigaUUCP", /* Other guy's host name */
- our_name [MAX_HOST], /* Our uucp hostname from UULib:Config */
- *uuspool;
-
- int
- UUXqtInterval = 0, /* > 0 means start UUXqt every this many X.* files */
- UUXqtPriority = -1, /* run UUXqt at this priority */
- debug = -1, /* -1 indicates not set by command line or ctl file */
- f_wait = 0, /* wait for a call (-w) or calls (-w -e) after outbnd */
- loop = 0, /* Loop accepting logins if tty name specified */
- Overide = 0, /* overide modem protocol */
- Getty = 0, /* we were -Getty initiated */
- IgnoreCD = 0, /* xgetc() should ignore carrier */
- OurNameOv = 0, /* use specified hostname as "us" */
- WindowSize = 999,
- SegSize = 2,
- NoReScan = 0, /* do not rescan for work after error */
- SevenWire = 0, /* RTS/CTS */
- XDebug = 0, /* do not pass debug parameter to remote */
- ExitCode = 0,
- PacketTimeout = 0,
- DebugHandshake= 0,
- SendExpectTimeout = SENDEXPECT_TO,
- ProtoHacks, /* protocol hack for Mac UUCP */
- PriMode, /* up our priority by one at start, down when done */
- OldPri, /* what our starting priority is */
- IgnoreDTR = 0, /* ignore Data Terminal Ready on send() */
- DoAttempt = 0, /* don't wait on LockDevUnit(), quit instead */
- BigGOpt, /* call for 'G' proto, not 'g' */
- BytesIn, /* how many bytes received */
- BytesOut, /* how many bytes sent */
- UseSubDirs = 0, /* use system sub-directories in UUSpool: */
- NoDelay = 0, /* immediately check for more data at port */
- VarPackets = 0, /* calculate most efficient GIO packet size */
- UUXqtHostname = 0; /* tell UUXQT what hostname to use */
- time_t
- TimeBegin1,
- TimeBegin2;
- int
- copynotify; /* mail notify bits */
- char
- mailsub [NAMESIZE + 100];
-
- #define CTRLFILE(f) (f [1] == '.' && (f [0] == 'D' || f [0] == 'X' || f [0] == 'C'))
-
- struct Library
- *OwnDevUnitBase = NULL;
-
- #define MAX_STRING 200 /* Max length string to send/expect */
- #define MSGO2IDX 6
-
- /* We print these prompts */
-
- char
- msgo0 [] = "login: ",
- msgo1 [] = "Password:",
- msgo2 [10 + MAX_HOST] = { "\20Shere" }, /* NO = */
- msgo3 [] = "\20ROK\0",
- msgo3a [] = "\20P",
- msgo3bg [] = "\20Pg\0",
- msgo3bG [] = "\20PG\0",
- msgo4 [] = "\20OOOOOOO\0";
-
- /* We expect to receive these strings */
-
- char
- msgi0 [] = "uucp\r",
- msgi1 [] = "s8000\r",
- /* msgi2 [] = "\20S*\0", We now scan it specially FIXME */
- msgi3g [] = "\20Ug\0",
- msgi3G [] = "\20UG\0",
- msgi4 [] = "OOOOOO";
-
- /*
- * Protocol switch data structure
- */
-
- #define turnon gturnon
- #define rdmsg grdmsg
- #define wrmsg gwrmsg
- #define rddata grddata
- #define wrdata gwrdata
- #define turnoff gturnoff
-
- int
- getname (int isshere)
- {
- int
- data,
- count = 0;
- static char
- msgi [MAX_STRING + SLOP]; /* Incoming trash buffer */
-
- /* Read data until null character */
-
- while ((data = xgetc (BYTE_TO, 0)) != EOF) {
- data &= 0x7F;
- if (data == 020)
- break;
- }
-
- if (data == EOF)
- return FAIL;
-
- while ((data = xgetc (BYTE_TO, 0)) != EOF && (data & 0x7F)) {
- data &= 0x7F;
- if (count == 0 && data != 'S')
- continue;
- if (count > sizeof (msgi) - 2)
- continue;
- if (data == 0x0A) /* hack fix for tuvie ? */
- break;
- msgi [count++] = (char) data;
- }
- msgi [count] = 0;
-
- if (debug > 8)
- printf ("GETNAME MSG (%d): %s\n", count, msgi);
-
- if (msgi [0] != 'S')
- return FAIL;
-
- if (isshere) {
- for (count = 1; msgi[count] && msgi[count] != '='; ++count)
- ;
- if (msgi [count] == '=')
- ++count;
- }
- else {
- count = 1;
- }
-
- if (msgi [count]) {
- strncpy (host_name, msgi + count, MAX_HOST-1);
- host_name [MAX_HOST-1] = '\0';
- if (debug > 8)
- printf ("Compare host names: '%s' '%s'\n", host_name, msgi + count);
- }
-
- strtok (host_name, " \t"); /* put \0 after hostname */
-
- ulog (-1, "Hostname is '%s'", host_name);
-
- return SUCCESS;
- }
-
- /*
- * get_proto() checks the list of protos given by the foreign machine
- * checking for 'g' (which is the only proto we have). Use only in master
- * mode.
- */
-
- int
- get_proto (void)
- {
- int
- data;
-
- while ((data = xgetc (BYTE_TO, 0)) != EOF) {
- data &= 0x7F;
- if (data == 0)
- break;
- if (data == 'g')
- return SUCCESS;
- }
-
- return FAIL;
- }
-
- /*
- * Medium level input routine.
- *
- * Look for an input string for the send-expect sequence.
- * Return 0 for matching string, 1 for timeout before we found it.
- * FIXME: we only time out if the other end stops sending. If it
- * keeps sending, we keep listening forever.
- */
-
- int
- instr (char *s, int n, int to)
- {
- int
- i,
- data,
- count = 0,
- j;
- static char
- msgi [512]; /* Incoming trash buffer */
-
- if (to == 0)
- /* 'to' is timeout */
- to = BYTE_TO;
-
- if (debug > 8) {
- printf ("Expecting '");
- for (i = 0; i < n; i++)
- printc (s [i]);
- printf ("'\n");
- }
-
- if (DebugHandshake) {
- printf ("recvd (len %ld, to %ld): '", n, to);
- fflush (stdout);
- }
-
- while ((data = xgetc (to, 0)) != EOF) {
- data &= 0x7F;
-
- msgi [count++] = data;
-
- if (DebugHandshake) {
- printc (data);
- fflush (stdout);
- }
-
- if (count == sizeof (msgi)) { /* throw away first half */
- count = sizeof (msgi) / 2;
- bcopy (msgi + sizeof (msgi) / 2, msgi, sizeof (msgi) / 2);
- }
-
- if (count >= n) {
- for (i = n - 1, j = count - 1; i >= 0; i--, j--) {
- if (*(s+i) != msgi [j])
- break;
- }
- if (i < 0) {
- if (debug > 8)
- printf ("\n");
- if (DebugHandshake)
- printf ("' (GOTIT!)\n");
- return SUCCESS;
- }
- }
- }
-
- if (DebugHandshake)
- printf ("' (TIMEOUT!)\n");
-
- if (debug > 8)
- printf ("\n");
-
- msgi [count] = '\0';
-
- return FAIL;
- }
-
- /*
- * Medium level input routine.
- *
- * input a line, return -1 on timeout condition else 0
- */
-
- int
- inline (int to, char *buf, int max)
- {
- int
- c,
- i = 0;
-
- --max;
- if (to == 0)
- to = BYTE_TO;
-
- if (debug > 8 || DebugHandshake) {
- printf ("Inline: ");
- fflush (stdout);
- }
-
- while ((c = xgetc (to, 0)) != EOF && i < max) {
- if (c == '\n' || c == '\r')
- break;
- if (debug > 8 || DebugHandshake)
- printf ("%c", c);
- buf [i++] = c;
- }
- if (debug > 8 || DebugHandshake)
- printf (" (%d c=%d)\n", i, c);
-
- buf [i] = 0;
-
- if (c == EOF)
- return -1;
-
- return 0;
- }
-
- /*
- * Debugging hack for stuff written to the modem.
- */
-
- int
- twrite (const char *s, int n)
- {
- int
- i;
-
- if (debug > 8) {
- printf ("Wrote: ");
- for (i = 0; i < n; i++)
- printc (s [i]);
- printf ("\n");
- }
-
- return xwrite (s, n);
- }
-
- void
- myexit (void)
- {
- if (PriMode) {
- struct Task
- *task = FindTask (NULL);
-
- SetTaskPri (task, OldPri);
- }
-
- UnLockFiles ();
-
- if (OwnDevUnitBase) {
- CloseLibrary (OwnDevUnitBase);
- OwnDevUnitBase = NULL;
- }
-
- return;
- }
-
- /*
- * MAIN ROUTINE.
- *
- * This is called at program startup. It parses the arguments to the
- * program (if any) and sets up to receive a call on the modem.
- *
- * If there are no arguments, we assume the caller is already on standard
- * input, waiting to do uucp protocols (past the login prompt), and we
- * just handle one caller.
- *
- * If there is an argument, it is the name of the tty device where we
- * should listen for multiple callers and handle login and password.
- */
-
- int
- main (int argc, char **argv)
- {
- char
- *poll_sys = NULL; /* System name to poll, or none */
- int
- i,
- rmode = 0; /* 1 = master, 0 = slave */
- static const char
- odu_name [] = { ODU_NAME };
-
- LogProgram = argv [0];
- LogHost = host_name;
- LogWho = who;
-
- signal (SIGINT, sigint);
- atexit (myexit);
-
- if ((OwnDevUnitBase = OpenLibrary (odu_name, 0)) == NULL) {
- fprintf (stderr, "Unable to open %s\n", odu_name);
- ulog (-1, "ERROR: cannot open %s", odu_name);
- exit (20);
- }
-
- /* FIXME, use getopt */
- /* scan command line arguments, kinda kludgy but it works */
-
- for (i = 1; i < argc; ++i) {
- char
- *ptr = argv [i];
-
- if (*ptr != '-') {
- fprintf (stderr, "%s: warning, extra args ignored: %s\n", argv [0], argv [i]);
- ulog (-1, "WARNING: extra args ignored: %s", argv [i]);
- break;
- }
- ptr += 2;
- switch (ptr [-1]) {
- case 'N':
- {
- int
- len;
- char
- *p = *ptr ? ptr : argv [++i];
-
- if ((len = strlen (p)) > (MAX_HOST - 1))
- len = MAX_HOST - 1;
-
- our_name [len] = '\0';
- strncpy (our_name, p, len);
-
- OurNameOv = 1;
- }
-
- break;
- case 'D': /* Serial Device */
- {
- char
- *p;
-
- /* could be any of:
- ** -Dserial.sevice
- ** -D serial.device
- ** -DEVICE serial.device
- ** -DEVICEserial.device
- */
- if (strnicmp (ptr, "EVICE", 5) == 0)
- ptr += 5;
- p = *ptr ? ptr : argv [++i];
- DeviceName = p;
- }
- break;
- case 'U': /* Serial Unit */
- {
- char
- *p;
-
- /* could be any of:
- ** -U0
- ** -U 0
- ** -UNIT 0
- ** -UNIT0
- */
- if (strnicmp (ptr, "NIT", 3) == 0)
- ptr += 3;
- p = *ptr ? ptr : argv [++i];
- DeviceUnit = atoi (p);
- }
- break;
- case 'p': /* protocol hacks */
- if (strcmp (ptr, "ri") == 0) { /* -pri */
- struct Task
- *task = FindTask (NULL);
-
- PriMode = 1;
- OldPri = SetTaskPri (task, 5);
- SetTaskPri (task, OldPri + 1);
- }
- else
- if (strcmp (ptr, "G") == 0) {
- /*
- * XXX in development, does NOT work yet!
- */
-
- BigGOpt = 1;
- }
- else
- if (strcmp (ptr, "g") == 0) {
- /*
- ** allow direct specification of 'g'
- */
- BigGOpt = 0;
- }
- else
- if (strcmp (ptr, "ackets") == 0) {
- VarPackets = 1;
- }
- else { /* -proto */
- char
- *p = (*ptr && *ptr >= '0' && *ptr <= '9') ? ptr : argv [++i];
-
- ProtoHacks |= atoi (p);
- }
- break;
- case 'Q':
- UUXqtHostname = 1;
- break;
- case 'g':
- case 'G':
- /* careful! could be "-GETTY" or "-getty" */
- Getty = 1;
- break;
- case 'h':
- IgnoreCD = 1;
- break;
- case 'w':
- ++f_wait;
- break;
- case 'r':
- {
- char
- *p = *ptr ? ptr : argv [++i];
-
- rmode = atoi (p);
- }
- break;
- case 'X':
- XDebug = 1;
- /* FALLTHROUGH */
- case 'x':
- if (*ptr == 'x') {
- DebugHandshake = 1;
- break;
- }
-
- debug = atoi (*ptr ? ptr : argv [++i]);
- LogLevel = debug;
- LogToStdout = 0;
- printf ("uucico: debug level set to %d\n", debug);
- break;
- case 'o':
- Overide = 1;
- break;
- case 'n':
- if (*ptr && strcmp ("odelay", ptr) == 0) {
- NoDelay = 1;
- break;
- }
-
- WindowSize = atoi (*ptr ? ptr : argv [++i]);
- if ((WindowSize < 1) || (WindowSize > 7)) {
- fprintf (stderr, "%s: warning, -n must be between 1 and 7: %ld\n", argv [0], WindowSize);
- ulog (-1, "WARNING: -n must be between 1 and 7: %ld", WindowSize);
- WindowSize = 1;
- }
- break;
- case 'P':
- {
- char
- *p = *ptr ? ptr : argv [++i];
-
- SegSize = atoi (p);
- if ((SegSize < 2) || (SegSize > 8)) {
- fprintf (stderr, "%s: warning, -P must be between 2 and 8: %ld\n", argv [0], SegSize);
- ulog (-1, "WARNING: -P must be between 2 and 8: %ld", SegSize);
- SegSize = 2;
- }
- }
- break;
- case 'b':
- system (GetConfigProgram (BATCHNEWS));
- break;
- case 'S':
- ignore_time_restrictions++;
- /* FALLTHROUGH */
- case 's':
- {
- char
- *p = *ptr ? ptr : argv [++i];
-
- poll_sys = p;
- }
- break;
- case 'e':
- ++loop;
- break;
- case 't':
- {
- char
- *p = *ptr ? ptr : argv [++i];
-
- PacketTimeout = atoi (p);
- }
- break;
- case 'T':
- {
- char
- *p = *ptr ? ptr : argv [++i];
-
- SendExpectTimeout = atoi (p);
- }
- break;
- case '7':
- SevenWire = 1;
- break;
- case 'd':
- /* could be:
- ** -d0
- ** -d 0
- ** -d -other_arg
- */
- if (*ptr)
- IgnoreDTR = !atoi (ptr);
- else {
- if (isdigit (*argv [i + 1]))
- IgnoreDTR = !atoi (argv [++i]);
- else
- IgnoreDTR = 1;
- }
- break;
- case 'H':
- IgnoreCD = 1;
- Overide = 1;
- break;
- case 'B':
- {
- char
- *p = *ptr ? ptr : argv [++i];
-
- /* throw away baud rate argument */
- }
- break;
- case 'A':
- DoAttempt = 1;
- break;
- default:
- fprintf (stderr, "uucico: warning, bad flag %s\n", argv [i]);
- ulog (-1, "WARNING: bad argument %s", argv [i]);
- break;
- }
- }
-
- read_ctl ();
-
- if (DeviceName)
- sprintf (ttynam, "%s/%ld", DeviceName, DeviceUnit);
-
- /*
- * If running via getty/login, our debug stdout had better
- * go to a file, not to the usual stdout!
- */
-
- if (debug > 0 && Getty) {
- freopen ("T:uucico.log", "a", stdout);
- }
-
- /* Timestamp the long debug log */
-
- if (debug > 0) {
- long
- clock;
-
- time (&clock);
- printf ("\nuucico log for '%s' starting %s\n",
- ttynam, ctime (&clock));
- }
-
- /* Log our presence so we humans reading the logs can find the
- entries created by uuslave. */
-
- ulog (-1, "Startup %s", VERSION);
-
- amiga_setup ();
- modem_init ();
-
- if (poll_sys) {
- if (*poll_sys == '\0')
- poll_sys = NULL;
-
- if (call_system (poll_sys, rmode) == FAIL)
- ExitCode = 5;
-
- if (!f_wait)
- goto end;
- }
- else {
- if (rmode) {
- if (do_outbound () == FAIL)
- ExitCode = 5;
- if (!f_wait)
- goto end;
- }
- }
-
- do {
- /*
- * Set up serial channel, wait for incoming call.
- */
-
- DEBUG (0, "\nRestarting\n", 0);
-
- if (Getty == 0 && Overide == 0)
- openline ();
-
- do_session (Getty);
- LogTimes (0);
- hangup ();
- DEBUG (0, "\nEnd of call\n", 0);
- } while (loop && !Getty);
-
- end:
- cleanup ();
- return ExitCode;
- }
-
- /*
- * translate embedded escape characters
- */
-
- void
- xlat_str (char *msg)
- {
- int
- i = 0,
- cr = 1;
-
- if (DebugHandshake)
- printf ("Send = '%s'\n", msg);
-
- while (msg [i]) {
- if (msg [i] == '\\') {
- switch (msg [++i]) {
- case 'r': /* carriage return */
- twrite ("\r", 1);
- break;
- case 'n': /* line feed */
- twrite ("\n", 1);
- break;
- case '\\': /* back slash */
- twrite ("\\", 1);
- break;
- case 't': /* tab */
- twrite ("\t", 1);
- break;
- case 'b':
- SendBreak ();
- break;
- case 'd': /* delay */
- Delay (180);
- break;
- case 's': /* space */
- twrite (" ", 1);
- break;
- case 'c': /* no CR at end */
- cr = 0;
- break;
- default: /* don't know so skip it */
- break;
- }
- ++i;
- }
- else {
- twrite (msg + i, 1);
- ++i;
- }
- }
- if (cr) {
- twrite ("\r", 1);
- }
- return;
- }
-
- /*
- * Get some parameters from the configuration file (used to be uucp.ctl)
- */
-
- int
- read_ctl (void)
- {
- const char
- *nodename = FindConfig (NODENAME),
- *debugstr = FindConfig (DEBUGNAME),
- *uuxqtint = FindConfig (UUXQTINTERVAL),
- *uuxqtpri = FindConfig (UUXQTPRIORITY),
- *tmp;
-
- if (nodename && OurNameOv == 0)
- strcpy ((char *) our_name, nodename);
- if (debugstr && debug < 0)
- debug = atoi (debugstr);
- if (uuxqtint)
- UUXqtInterval = atoi (uuxqtint);
- if (uuxqtpri)
- UUXqtPriority = atoi (uuxqtpri);
-
- tmp = GetConfig (USESUBDIRS, "n");
- if (*tmp == 'y' || *tmp == 'Y' || *tmp == '1')
- UseSubDirs = 1;
-
- uuspool = GetConfigDir (UUSPOOL);
-
- /*
- * sd, get copy notify bits
- *
- * 1 - notify of send failures that will not be retried (ie denied)
- * 2 - notify of send failures that will be retried (ie protocol errors)
- * 4 - notify of successfull outgoing file copy (uucp'd copies only)
- * 8 - notify of incoming file (uucp'd file copies only)
- * 16 - notify of incoming failure of anykind
- *
- * i.e., set to 31 for all features.
- * mail is sent to username config entry for incoming file and to
- * originator of outgoing file copies (usually the same username)
- */
-
- #define NOTIFY_FAILED 1
- #define NOTIFY_RETRY 2
- #define NOTIFY_SUCCESS 4
- #define NOTIFY_INCOMING 8
- #define NOTIFY_INCOMING_FAILURE 16
-
- tmp = FindConfig ("CopyNotify");
- if (tmp) {
- copynotify = atoi (tmp);
- }
-
- return 1;
- }
-
- /*
- * Search spool queues for work, call the systems we need to call.
- *
- * return FAIL if any system has failed, SUCCESS otherwise.
- */
-
- int
- do_outbound (void)
- {
- return call_system (NULL, 1);
- }
-
- /*
- * Call a specific system, or all systems that have work pending.
- *
- * If a failure occurs with any system, return FAIL, else return
- * SUCCESS.
- */
-
- int
- call_system (char *sys, int ifworkpend)
- {
- FILE
- *lsys;
- static char
- buf [MAX_LSYS],
- sysnam [MAX_HOST],
- prev_name [MAX_HOST];
- int
- called = FAIL,
- status = SUCCESS;
-
- /*
- * Unix uucico just reads the directory, and calls the systems
- * in the order of the files in the directory. We want more
- * control than that, though I'm not sure that L.sys order is
- * best either. For example, in the first call after 11PM,
- * I'd like to call the sites that haven't been callable before
- * 11PM first, and finish up with the ones I've been able to call
- * all day. FIXME.
- */
-
- if (!(lsys = fopen (MakeConfigPath (UULIB, "L.sys"), "r"))) {
- DEBUG (0, "uucico: can't open L.sys, errno %d\n", errno);
- return FAIL;
- }
- sysnam [0] = '\0'; /* Initially, no previous sys */
-
- /* Once per system in L.sys... */
- /* FIXME, handle continuation lines (trailing "\") */
-
- while (fgets (buf, sizeof buf, lsys)) {
- if (buf [0] == '#' || buf [0] == '\n')
- continue;
-
- /*
- * Grab the system name. If same as previous, and
- * the previous call worked, skip it.
- */
-
- strcpy (prev_name, sysnam);
- sscanf (buf, "%s", sysnam);
- if (strcmp (sysnam, prev_name) == 0) {
- if (called == SUCCESS)
- continue;
- }
-
- /*
- * If a system name was specified, skip til we find it
- * If none was specified, only call if there is work.
- */
-
- if (sys) {
- if (strcmp (sys, sysnam))
- continue;
- if (ifworkpend && work_scan (sysnam) == 0) {
- ulog (-1, "No work for system %s", sysnam);
- called = SUCCESS;
- continue;
- }
- }
- else {
- DEBUG (3, "searching for outbound to %s\n", sysnam);
- if (work_scan (sysnam) == 0) {
- DEBUG (3,"no work for %s\n", sysnam);
- called = SUCCESS; /* Don't try further */
- continue;
- }
- DEBUG (2, "uucico: found work for %s\n", sysnam);
- }
-
- /*
- * call system. If calling a single system and it succeeds, break
- * out of loop. If calling a single system with multiple L.Sys
- * lines, a later success overides an initial failure in terms of
- * the return code.
- *
- * If calling all systems any failure causes a failure return code
- * XXX FIXME, handling multiple L.Sys entries for same system ???
- */
-
- called = call_sysline (buf);
-
- if (sys) {
- status = called;
- if (called == SUCCESS)
- break;
- }
- else {
- if (called == FAIL)
- status = FAIL;
- }
- }
- fclose (lsys);
-
- if (sys && called == FAIL && status == SUCCESS) {
- ulog (-1, "Unknown system '%s'", sys);
- }
-
- return status;
- }
-
- /*
- * Call out to a system, given its L.sys line.
- *
- * Return FAIL if any failure occurs, SUCCESS if all went well.
- */
-
- int
- call_sysline (char *lsysline)
- {
- static char
- tempname [MAX_HOST + 30 + SLOP];
- char
- *pnum,
- *sysnam,
- *times,
- *acu,
- *sbaud,
- *telno,
- *send,
- *expct,
- *expct1,
- *errm;
- int
- baud,
- sendexpectok,
- r;
-
- who [0] = '-';
- who [1] = '\0'; /* No user now (for logit) */
-
- /* FIXME, use the values it is ignoring here */
-
- sysnam = strtok (lsysline, " \t"); /* System */
- times = strtok (NULL, " \t"); /* Time */
- acu = strtok (NULL, " \t"); /* ACU */
- sbaud = strtok (NULL, " \t"); /* Baud */
- telno = strtok (NULL, " \t"); /* phone */
-
- strcpy (host_name, sysnam);
-
- if (ignore_time_restrictions == 0) {
- if (CheckTimeRestrictions (times) == FAIL) {
- ulog (-1, "Wrong Time To Call %s", sysnam);
- return FAIL;
- }
- }
-
- baud = atoi (sbaud);
-
- /* FIXME, acu not implemented in Devices file */
- /* AmigaUUCP uses -D and -U instead. */
-
- DEBUG (4, "Opening outgoing line %s\n", acu);
-
- if (openout (acu, baud) != SUCCESS)
- return FAIL;
-
- /* sd added telno logging */
- for (pnum = (telno + strlen (telno)) -1 ; pnum > telno; --pnum) {
- if (isalpha (*pnum)) {
- ++pnum;
- break;
- }
- }
-
- if (Overide == 0) {
- char
- *errmsg;
-
- if (errmsg = dial_nbr (telno)) {
- ulog (-1, "FAILED call to %s (%s): %s", host_name, pnum, errmsg);
- return FAIL;
- }
- }
-
- TimeBegin1 = time (NULL);
- TimeBegin2 = 0;
- BytesIn = 0;
- BytesOut= 0;
-
- /* FIXME, log tty, baud rate, ... */
-
- ulog (-1, "DIALED %s (%s)", host_name, pnum);
-
- /*
- * Process send-expect strings.
- * FIXME, deal with "-", BREAK, etc.
- */
-
- if (DebugHandshake)
- puts ("CONNECTED, running send-expect strings");
-
- sendexpectok = TRUE;
-
- do {
- expct = strtok (NULL, " \t");
- if (expct == NULL)
- break;
-
- expct1 = strtokp (&expct, "-");
-
- while (expct1) {
- if (expct1 [0] != '"' || expct1 [1] != '"' || expct1 [2] != '\0') {
- if (instr (expct1, strlen (expct1), SendExpectTimeout) == SUCCESS)
- break;
- }
- else {
- if (DebugHandshake)
- puts ("Expect Nothing");
- break;
- }
- /*
- * expect failed, check for alternates
- */
-
- errm = expct1;
- if (expct1 = strtokp (&expct, "-")) {
- xlat_str (expct1);
- }
- else {
- sendexpectok = FALSE;
- strtok ("", " ");
- break;
- }
- expct1 = strtokp (&expct, "-");
- }
- if (sendexpectok == FALSE) {
- ulog (1, "Send/Expect failure");
- break;
- }
- if (send = strtok (NULL, " \t\n")) {
- xlat_str (send);
- }
- } while (send);
-
- TimeBegin2 = time (NULL);
-
- if (sendexpectok)
- ulog (-1, "SUCCEEDED call to %s", host_name);
- else {
- ulog (-1, "FAILED call to %s. Expected %s", host_name, errm);
- goto bort1;
- }
-
- if (getname (1)) /* get name */
- goto bort1;
-
- /* send response */
- sprintf (tempname, "\20S%s -Q0 -x%d\0", our_name, XDebug ? 0 : debug);
- twrite (tempname, strlen (tempname) + 1); /* Including null */
-
- /* wait for ok message, wait for protocol request
- * send protocol 'g' response */
-
- /* FIXME, we don't actually wait for the ROK message, since
- * it is immediately followed by the Pprotos message. We
- * currently just look for a Pg message. This needs work.
- */
-
- if (instr (msgo3a, sizeof (msgo3a) - 1, 0) != SUCCESS) {
- if (get_proto () != SUCCESS)
- goto bort1;
- }
-
- if (BigGOpt)
- twrite (msgi3G, sizeof (msgi3G) - 1);
- else
- twrite (msgi3g, sizeof (msgi3g) - 1);
-
- ResetGIO (); /* reset GIO protocol */
-
- if (turnon (1))
- goto bort1;
-
- ulog (-1, "OK Startup");
-
- xferinit (host_name);
- xfer.flags |= XFERF_OUTGOING;
-
- r = top_level (1);
- hangup ();
-
- xfer.time_stop = time (NULL);
-
- if (r == FAIL) { /* sd */
- ulog (-1, "Conversation FAILED");
- }
- xferstat (pnum, (r == FAIL) ? "# Conversation FAILED => LOGFILE" : NULL);
-
- LogTimes (r);
- return r;
-
- bort1:
- reset_modem ();
- LogTimes (FAIL);
- return FAIL;
- }
-
- void
- LogTimes (int r)
- {
- time_t
- e = time (NULL),
- t1 = (TimeBegin1) ? e - TimeBegin1 : 0,
- t2 = (TimeBegin2) ? e - TimeBegin2 : 0;
- FILE
- *fi;
- char
- *logFile = MakeConfigPath (UUSPOOL, "TimeLog"),
- buf [64];
-
- if (fi = fopen (logFile, "a")) {
- strftime (buf, sizeof (buf), "%d-%b-%y", localtime (&e));
- fprintf (fi, "%s %02d:%02d %2d:%02d in=%-8d out=%-8d %s\n",
- buf,
- e / 3600 % 24, e / 60 % 60,
- t2 / 60, t2 % 60,
- BytesIn,
- BytesOut,
- host_name
- );
- fclose (fi);
- }
-
- return;
- }
-
- /* Handle a single uucp [slave] login session */
-
- int
- do_session (int ontheline)
- {
- int
- r;
-
- TimeBegin1 = 0;
- TimeBegin2 = time (NULL);
- BytesIn = 0;
- BytesOut = 0;
-
- if (ontheline == 0) {
- /* output login request, verify uucp */
- twrite (msgo0, sizeof (msgo0) - 1);
- if (instr (msgi0, sizeof (msgi0) - 1, 0) != SUCCESS) {
- fprintf (stderr, "%s: invalid login name\n", LogProgram);
- goto bort;
- }
-
- /* output password request, verify s8000 */
- twrite (msgo1,sizeof (msgo1) - 1);
- if (instr (msgi1, sizeof (msgi1) - 1, 0) != SUCCESS) {
- fprintf (stderr, "%s: invalid password\n", LogProgram);
- goto bort;
- }
-
- printf ("uucico: correct login\n");
- }
-
- /*
- * send Shere=<myhost>
- *
- * Apparently mac UUCP has a bug that only allows 7
- * char host names, and it fails if it gets shere=<myhost>
- * where <myhost> is > 7 chars.
- *
- * Apparently some implementations of AmigaUUCP do not accept
- * an SHere with an =<myhost>, so this is disabled unless -p1 is used.
- */
-
- if (ProtoHacks & PROTOF_SHEREEQUALS)
- sprintf (msgo2 + MSGO2IDX, "=%s", our_name);
- twrite (msgo2, strlen (msgo2) + 1);
-
- /*
- * get \020S<host> -Qn n (??)
- */
-
- if (getname (0))
- goto bort;
-
- /* output ok message, output protocol request, wait for response */
-
- twrite (msgo3, sizeof (msgo3) - 1);
-
- /* FIXME, make the protocol list here, and use it */
-
- if (BigGOpt)
- twrite (msgo3bG, sizeof (msgo3bG) - 1);
- else
- twrite (msgo3bg, sizeof (msgo3bg) - 1);
-
- if (BigGOpt) {
- if (instr (msgi3G, sizeof (msgi3G) - 1, 0) != SUCCESS)
- goto bort;
- }
- else {
- if (instr (msgi3g, sizeof (msgi3g) - 1, 0) != SUCCESS)
- goto bort;
- }
-
- ResetGIO (); /* reset GIO protocol */
-
- if (turnon (0))
- goto bort;
-
- ulog (-1, "OK Startup");
-
- xferinit (host_name);
-
- r = top_level (0);
-
- xfer.time_stop = time (NULL);
-
- if (r == FAIL) { /* sd */
- ulog (-1, "Conversation FAILED");
- }
-
- xferstat (NULL, (r == FAIL) ? "# Conversation FAILED => LOGFILE" : NULL);
-
- bort:
- if (debug > 0)
- printf ("uucico: call complete\n");
- return 1;
- }
-
- /*
- * Handle transactions "at top level", as Unix uucp's debug log says.
- *
- * As master, we scan our queues for work and send requests to the
- * other side. When done, we send a hangup request and switch to slave mode.
- *
- * As slave, we accept requests from the other side; when it is done,
- * it sends a hangup request, and we switch to master mode, if we have
- * any work queued up for that system.
- *
- * This repeats as long as either side has work to do. When all the
- * queued work is done, we agree to hang up, terminate the packet protocol,
- * and return to the caller. (We still haven't hung up the phone line yet.)
- *
- * A curious feature of the hangup protocol is that it is not a simple
- * question-answer. The master says "H", asking about hangup. The
- * slave responds "HY" saying OK. The master then says "HY" also,
- * then both of them hang up. Maybe this is to make sure the first HY
- * got ack'ed? Anyway, an "H" is reported as HANGUP and an "HY" as
- * HANGNOW. After we send an HY, we go back to listening for commands;
- * if the master sends something other than HY, we'll do it.
- */
-
- #define HANGUP 2 /* Signal to switch master/slave roles */
- #define HANGNOW 3 /* Signal to hang up now */
- #define COPYFAIL 4 /* File copy failed */
-
- int
- top_level (int master_mode)
- {
- static char
- buf [MAXMSGLEN]; /* For hangup responses */
-
- if (master_mode) {
- work_scan (host_name); /* Kick off queue scan */
- goto master;
- }
-
- for (;;) {
- slave: /* SLAVE SIDE */
- set_dir (host_name);
-
- for (;;) {
- DEBUG (4, "*** TOP *** - slave\n", 0);
- switch (do_one_slave ()) {
- case SUCCESS:
- break;
- case FAIL:
- DEBUG (4, "*** DO_ONE_SLAVE FAIL *** - slave\n", 0);
- return FAIL;
- case HANGUP:
- if (work_scan (host_name)) {
- if (wrmsg ("HN") != SUCCESS) {
- DEBUG (4, "*** WRMSG HN FAIL *** - slave\n", 0);
- return FAIL;
- }
- goto master;
- }
- else {
- if (wrmsg ("HY") != SUCCESS) {
- DEBUG (4, "*** WRMSG HY FAIL *** - slave\n", 0);
- return FAIL;
- }
- break; /* go to master mode */
- }
- case HANGNOW:
- goto quit;
- }
- }
-
- master: /* MASTER SIDE */
- for (;;) {
- DEBUG (4, "*** TOP *** - master\n", 0);
- switch (do_one_master ()) {
- case SUCCESS:
- break;
- case FAIL:
- DEBUG (4, "*** DO_ONE_MASTER FAIL *** - master\n", 0);
- return FAIL;
- case HANGUP:
- /* We wrote an H command, what's the resp? */
- if (rdmsg (buf, MAXMSGLEN) != SUCCESS) {
- DEBUG (4, "*** RDMSG HANGUP FAIL *** - master\n", 0);
- return FAIL;
- }
- if (buf [0] != 'H') {
- DEBUG (4, "*** RDMSG HANGUP != 'H' *** - master\n", 0);
- return FAIL;
- }
- if (buf [1] == 'N') {
- goto slave;
- }
- else {
- /*
- * send final HY? not sure if this should happen, will
- * necessarily fail if the other side does not expect
- * it so do not return... continue on w/ exit code.
- *
- * however, reduce timeout parameters
- */
-
- ++ReducedTimeout;
- wrmsg ("HY");
- --ReducedTimeout;
- goto quit;
- }
- }
- }
- }
-
- quit:
- /* Shut down the packet protocol */
-
- turnoff ();
-
- /* Write the closing sequence */
-
- twrite (msgo4, sizeof (msgo4) - 1);
- instr (msgi4, sizeof (msgi4) - 1, 0);
-
- twrite (msgo4, sizeof (msgo4) - 1);
-
- strcpy (who, "-");
- ulog (-1, "OK Conversation complete");
-
- return SUCCESS; /* Go byebye */
- }
-
- /*
- * We are slave; get a command from the other side and execute it.
- *
- * Result is SUCCESS, FAIL, HANGUP, or HANGNOW.
- */
-
- int
- do_one_slave (void)
- {
- static char
- msg [MAXMSGLEN]; /* Master's message to us */
-
- /* Get master's command */
- if (rdmsg (msg, MAXMSGLEN) != SUCCESS)
- return FAIL;
-
- /* Print it for easy debugging */
- DEBUG (5,"\nCommand: %s\n\n", msg);
-
- switch (msg [0]) {
- case 'S':
- if (msg [1] != ' ')
- break;
- return host_send_file (msg);
- case 'R':
- if (msg [1] != ' ')
- break;
- return host_receive_file (msg);
- case 'X':
- break;
- case 'H':
- if (msg [1] == '\0')
- return HANGUP;
- if (msg [1] == 'Y')
- return HANGNOW;
- if (msg [1] == 'N')
- return SUCCESS; /* Ignore HN to slave */
- break;
- }
-
- /* Unrecognized packet from the other end */
-
- DEBUG (0, "Bad control packet refused: %s\n", msg);
-
- if (ExitCode < 2)
- ExitCode = 2;
-
- return yesno (msg [0], 0, 0);
- }
-
- /*
- * Do one piece of work as master.
- *
- * FIXME: we don't handle the flags, e.g. -c, properly!
- *
- * Now only dequeues queue file if all transfers were successful.
- */
-
- int
- do_one_master (void)
- {
- FILE
- *fd;
- char
- *sname;
- static char
- cmnd [256], /* Command character */
- buf [256],
- notify [NAMESIZE]; /* A bit large...FIXME */
- int
- fail = SUCCESS,
- failAction = SUCCESS,
- failaccum = 0,
- num,
- delmeflag,
- di = 0;
- char
- *delList [16]; /* delete files list */
-
- /*
- * Get the next work item. If no work left re-scan the directory
- * just to be sure, and if still no work then do the right thing.
- */
-
- sname = work_next ();
- if (!sname && NoReScan == 0) {
- if (work_scan (host_name))
- sname = work_next ();
- }
- if (!sname) {
- /* No more work, time to hang up. */
- if (wrmsg ("H") != SUCCESS)
- return FAIL;
- return HANGUP;
- }
-
- DEBUG (2, "Request file %s\n", sname);
-
- LockFile (sname);
-
- fd = fopen (sname, "r");
- if (fd == NULL) {
- UnLockFile (sname);
- DEBUG (0, "uucico: couldn't open %s\n", sname);
- return SUCCESS;
- }
-
- while (fgets (buf, sizeof (buf), fd)) {
- DEBUG (3, "Queued request: %s", buf);
-
- if (buf [1] != ' ')
- goto badnum;
-
- num = sscanf (buf, "%s %s %s %s %s %s %o\n",
- cmnd, srcnam, dstnam, who, flags, temp, &mode, notify
- );
-
- switch (cmnd [0]) {
- case 'S':
- if (num < 7 || num > 8)
- goto badnum;
- fail = local_send_file (buf, &delmeflag);
- if (delmeflag) {
- if (di == sizeof (delList) / sizeof (delList [0])) {
- ulog (-1, "Too many source files in Cmd file! %s", sname);
- }
- else {
- delList [di] = malloc (strlen (temp) + 1);
- strcpy (delList [di], temp);
- ++di;
- }
- }
- break;
- case 'R':
- if (num != 5) {
- ulog (1, "ERROR: Invalid scanf %ld/5 :%s:%s:%s\n", num, cmnd, srcnam, dstnam);
- goto badnum;
- }
- fail = local_receive_file ();
- break;
- default:
- badnum:
- ulog (-1, "Illegal Work Request (%s): %s", sname, buf);
- fail = REFUSED;
- break;
- }
-
- switch (fail) {
- case SUCCESS:
- break;
- case FAIL:
- ++failaccum;
- if (failAction == SUCCESS)
- failAction = FAIL;
- ulog (-1, "Protocol Failure at (%s): %s", sname, buf);
- NoReScan = 1;
- break;
- case REFUSED:
- ++failaccum;
- failAction = REFUSED;
- ulog (-1, "Work Refused (%s): %s", sname, buf);
- break;
- }
- }
- fclose (fd);
-
- switch (failAction) {
- case SUCCESS:
- while (di) {
- --di;
- remove (delList [di]);
- free (delList [di]);
- }
- fail = remove (sname);
- UnLockFile (sname);
- if (fail != 0) {
- ulog (-1, "Unable to remove work file %s", sname);
- DEBUG (0, "Can't remove, errno %d\n", errno);
- }
- else {
- DEBUG (4, "Removed work file %s\n", sname);
- }
- break;
- case FAIL:
- UnLockFile (sname);
- break;
- case REFUSED:
- UnLockFile (sname);
- strcpy (buf, sname);
- {
- int
- i;
-
- for (i = strlen (buf); i >= 0 && buf [i] != ':' && buf [i] != '/'; --i)
- ;
- ++i;
- if ((buf [i] | 0x20) == 'c')
- buf [i] = 'E';
- }
- if (strcmp (sname, buf) == 0) {
- ulog (-1, "Removing %s", sname);
- remove (sname);
- }
- else {
- ulog (-1, "Renaming %s to %s", sname, buf);
- rename (sname, buf);
- }
- break;
- }
-
- if (failAction == FAIL)
- return FAIL;
-
- return SUCCESS;
- }
-
- /*
- * Send a yes/no packet
- */
-
- int
- yesno (char c, int true, int err)
- {
- static char
- buf [21];
-
- buf [0] = c;
- buf [1] = true ? 'Y' : 'N';
- buf [2] = 0;
- if (err && !true)
- sprintf (buf + 2, "%ld", err);
-
- return wrmsg (buf);
- }
-
- /*
- * SLAVE MODE, Master wishes to send a file to us
- *
- * SECURITY: If file is not in list of allowed directories
- * disallow transfer. UUSPOOL: is always in the
- * list.
- *
- * If file is for UUSPOOL: (the current dir), disallow "C." files
- * NOTE: success return and file redirected to T: as this can
- * occur only if somebody purposefully is trying to break us.
- *
- * NOTE: for received files to UUSPOOL: (no path element),
- * case insensitivity munging will occur. UUXQT will handle
- * name translations for X. files so we do not modify their
- * contents.
- *
- * Return 0 = success
- */
-
- int
- host_send_file (char *msg)
- {
- FILE
- *fddsk; /* Disk file pointer */
- static char
- cmnd [256]; /* Command character */
- int
- r,
- nor = 0;
-
- sscanf (msg, "%s %s %s %s %s %s %o",
- cmnd, srcnam, dstnam, who, flags, temp, &mode);
-
- ulog (-1, "REQUESTED %s", msg);
- munge_filename (dstnam, dstnam); /* Translate to local name */
- mungecase_filename (dstnam, dstnam); /* Handle case insensitivity */
- strcpy (temp, TmpFileName (dstnam)); /* Create a handy temp file */
-
- if (SecurityDisallow (dstnam, 'w')) {
- ulog (-1, "REQUEST FAILED -- SECURITY");
- return yesno ('S', 0, 4);
- }
-
- if (SecurityDisallow (dstnam, 'c') > 0) {
- ulog (-1, "REQUEST FAILED -- SECURITY, REMOTE TRIED TO SEND");
- ulog (-1, "US A COMMAND FILE: %s, FILE COPIED TO T:Bad-Cmd", dstnam);
- strcpy (dstnam, "T:Bad-Cmd");
- nor = 1;
- }
-
- /* FIXME: deal with file modes now that we fopen. */
-
- LockFile (temp);
-
- fddsk = fopen (temp, "wb" /*, mode|0600 */);
- if (fddsk == NULL) {
- UnLockFile (temp);
- /* Can't open file -- send error response */
- if (debug > 0) {
- fprintf (stderr, "Cannot open temp file %s (%s) for writing, errno=%ld\n",
- temp, dstnam, errno);
- }
- ulog (-1, "REQUEST FAILED -- cannot open temp file %s (destination %s) for writing, errno %ld",
- temp, dstnam, errno);
- return yesno ('S', 0, 4);
- }
-
- /* FIXME: Are the above permissions right?? */
- /* FIXME: Should we create directories for the file? */
-
- if (yesno ('S', 1, 0) != SUCCESS) {
- fclose (fddsk);
- unlink (temp);
- UnLockFile (temp);
- return FAIL;
- }
- r = receive_file (fddsk, temp, dstnam, srcnam, nor);
- UnLockFile (temp);
-
- /*
- * sd
- * Notify username of incoming file, cept if D. or X. or C. ctrl files.
- * Notify of any incoming failure (if NOTIFY_INCOMING_FAILURE bit set)
- */
- {
- static char
- from [80];
-
- sprintf (from, "%s!%s", host_name, who);
- if (r == SUCCESS && ((copynotify & NOTIFY_INCOMING)
- && !CTRLFILE (dstnam))) {
- sprintf (mailsub, "NEW FILE: %s", dstnam);
- mail_notify (from, who, mailsub);
- }
- else
- if (r != SUCCESS && (copynotify & NOTIFY_INCOMING_FAILURE)) {
- sprintf (mailsub, "INCOMING FAILURE: %s", dstnam);
- mail_notify (from, who, mailsub);
- }
- }
-
- return r;
- }
-
- /*
- * SLAVE MODE, Master wants us to send a file to it
- *
- * SECURITY: If file is not in list of allowed directories
- * disallow transfer. UUSPOOL: is always in the
- * list.
- *
- * 0 = success
- */
-
- int
- host_receive_file (char *msg)
- {
- FILE
- *fddsk; /* Disk file descriptor */
- int
- x;
- static char
- cmnd [256]; /* Command character */
-
- ulog (-1, "REQUESTED %s", msg);
-
- sscanf (msg, "%s %s %s", cmnd, srcnam, dstnam);
- munge_filename (srcnam, temp);
-
- if (SecurityDisallow (temp, 'r')) {
- ulog (-1, "COPY FAILED -- SECURITY");
- return yesno ('R', 0, 4);
- }
-
- fddsk = fopen (temp, "rb"); /* Try to open the file */
- if (fddsk == NULL) {
- /* File didn't open, sigh. */
- ulog (-1, "DENIED - can't open %s (%s, errno %ld)", temp, srcnam, errno);
- return yesno ('R', 0, 2);
- }
-
- if (yesno ('R', 1, 0) != SUCCESS) {
- fclose (fddsk);
- return (FAIL);
- }
-
- x = send_file (fddsk);
-
- /*
- * if copy failed, we don't care since the master asked for the file
- * and knows the result if it failed.
- */
-
- if (x == COPYFAIL)
- return SUCCESS;
-
- return x;
- }
-
- /*
- * MASTER MODE, We want to send a file.
- *
- * Return FAIL, SUCCESS, or COPYFAIL.
- *
- * SUCCESS is returned either if the file was not found locally (local
- * error, and the queued transfer should be flushed) or if it was moved
- * successfully. COPYFAIL indicates that the queued transfer should be
- * left queued, and later retried. FIXME, there are several failure points
- * in the transaction and we need finer control here.
- */
-
- int
- local_send_file (char *workstr, int *delmeflag)
- {
- static char
- buf [MAXMSGLEN]; /* Used for both xmit and receive */
- FILE
- *fddsk; /* Disk file descriptor */
- int
- res; /* Result and file removal status */
-
- *delmeflag = 0;
-
- /* WHY are temp and srcnam switched? FIXME! And no notify? */
-
- sprintf (buf, "S %s %s %s %s %s 0%o %s",
- temp, dstnam, who, flags, srcnam, mode, who
- );
-
- ulog (-1, "REQUEST %s", buf);
-
- if (strchr (flags, 'c')) {
- munge_filename (srcnam, temp);
- }
- else {
- munge_filename (temp, temp);
- }
- LockFile (temp);
- fddsk = fopen (temp, "rb");
- if (fddsk == NULL) {
- UnLockFile (temp);
- /* FIXME -- handle queued request for nonexistent file */
- if (debug > 0)
- fprintf (stderr, "Can't open file %s (%s), errno=%ld\n",
- temp, srcnam, errno);
- ulog (-1, "NOT FOUND %s (source %s) errno %ld",
- temp, srcnam, errno);
- /*
- * sd: Notify of failure, file to send could not be found
- */
- sprintf (mailsub, "FAILED: Can't open %s",srcnam);
-
- if (copynotify & NOTIFY_FAILED)
- mail_notify ("uucico", "uucico", mailsub);
-
- /* return COPYFAIL;*/
- return SUCCESS; /* assume file previously sent */
- }
-
- /* Tell the other side we want to send this file */
-
- if (wrmsg (buf) != SUCCESS) {
- fclose (fddsk);
- UnLockFile (temp);
- return FAIL;
- }
-
- /* See what they have to say about it */
-
- if (rdmsg (buf, MAXMSGLEN) != SUCCESS) {
- fclose (fddsk);
- UnLockFile (temp);
- return FAIL;
- }
- if ((buf [0] != 'S') || (buf [1] != 'Y')) {
- ulog (-1, "REQUEST DENIED %s", buf);
- fclose (fddsk);
- UnLockFile (temp);
- /*
- * sd - send mail indicating request was denied
- */
- sprintf (mailsub, "REFUSED by %s: %s", host_name, dstnam);
- if (copynotify & NOTIFY_FAILED)
- mail_notify ("uucico", "uucico", mailsub);
-
- return REFUSED;
- }
-
- res = send_file (fddsk); /* FAIL, SUCCESS, or COPYFAIL */
-
- /*
- * sd - since our caller does not seem to pay any attention to
- * COPYFAIL, it defaults to success?? It also reties on FAIL.
- * Without this patch, sending files can be lost and assume sent ok
- * even though may of failed due to protocol errors.
- */
- if (res == COPYFAIL)
- res = FAIL;
-
- /*
- * sd - send mail indicating copy failed.
- */
- if (res != SUCCESS) {
- sprintf (mailsub,"COPY FAILED: (will retry) to %s!%s from %s",
- host_name, dstnam, srcnam);
- if (copynotify & NOTIFY_RETRY)
- mail_notify ("uucico", "uucico", mailsub);
- }
- else
- if (!CTRLFILE (srcnam)) {
- sprintf (mailsub,"COPY DONE: %s!%s from %s",
- host_name, dstnam, srcnam);
- if (copynotify & NOTIFY_SUCCESS)
- mail_notify ("uucico", "uucico", mailsub);
- }
-
- UnLockFile (temp);
-
- /* don't delete if file was the original or an error occurred */
- if (res != SUCCESS || strchr (flags, 'c')) {
- return res;
- }
-
- /* Delete the source file if it was just a copy */
- *delmeflag = 1;
-
- return res;
- }
-
- /*
- * MASTER MODE, We wish to receive a specific file so we ask for it
- *
- * Return 0 = success
- */
-
- int
- local_receive_file (void)
- {
- static char
- buf [MAXMSGLEN];
- FILE
- *fddsk; /* Disk file pointer */
- int
- r;
-
- /* FIXME, test dest file access before we ask for it. */
-
- #if 0
- sprintf (buf, "R %s %s %s %s %s 0%o %s",
- srcnam, dstnam, who, flags, temp, mode, who
- };
- #else
- sprintf (buf, "R %s %s %s %s",
- srcnam, dstnam, who, flags
- );
- #endif
-
- munge_filename (dstnam, dstnam); /* tlate to local name */
- strcpy (temp, TmpFileName (dstnam)); /* Create a handy temp file */
-
- /* FIXME: deal with file modes now that we fopen. */
- /* FIXME: Are the above permissions right?? */
- /* FIXME: Should we create directories for the file? */
-
- LockFile (temp);
- fddsk = fopen (temp, "wb" /*, mode|060 */);
-
- if (fddsk == NULL) {
- UnLockFile (temp);
- /* Can't open temp file -- send error response */
- if (debug > 0) {
- fprintf (stderr, "Cannot open temp file %s (%s) for writing, errno=%ld\n",
- temp, dstnam, errno);
- }
- ulog (-1, "REQUEST FAILED -- cannot open temp file %s (dstnam %s) for writing, errno %ld",
- temp, dstnam, errno);
- return FAIL;
- }
-
- ulog (-1, "REQUEST %s", buf);
- if (wrmsg (buf) != SUCCESS) {
- fclose (fddsk);
- UnLockFile (temp);
- fprintf (stderr, "problem sending request '%s'\n", buf);
- ulog (-1, "REQUEST FAILED: couldn't request '%s'", buf);
- return FAIL;
- }
-
- /* See what the other side has to say about it */
-
- if (rdmsg (buf, MAXMSGLEN) != SUCCESS) {
- fclose (fddsk);
- UnLockFile (temp);
- ulog (-1, "REQUEST FAILED: read failure '%s'", buf);
- return FAIL;
- }
-
- if ((buf [0] != 'R') || (buf [1] != 'Y')) {
- ulog (-1, "REQUEST DENIED %s", buf);
- fclose (fddsk);
- UnLockFile (temp);
- /*
- * sd - send mail indicating request was denied
- */
- sprintf (mailsub, "REFUSED by %s: %s", host_name, srcnam);
- if (copynotify & NOTIFY_FAILED)
- mail_notify ("uucico", "uucico", mailsub);
- return REFUSED;
- }
-
- r = receive_file (fddsk, temp, dstnam, srcnam, 0);
- UnLockFile (temp);
- /*
- * sd - send mail indicating copy failed.
- */
- if (r != SUCCESS) {
- sprintf (mailsub, "COPY FAILED: (will retry) %s!%s", host_name, srcnam);
- if (copynotify & NOTIFY_RETRY)
- mail_notify ("uucico", "uucico", mailsub);
- }
- else {
- sprintf (mailsub, "COPY DONE: %s!%s to %s", host_name, srcnam, dstnam);
- if (copynotify & NOTIFY_SUCCESS)
- mail_notify ("uucico", "uucico", mailsub);
- }
- return r;
- }
-
- /*
- * General receive file
- */
-
- int
- receive_file (FILE *fddsk, char *temp, char *dstnam, char *srcnam, int norename)
- {
- int
- filesize, /* size of file we receive */
- status, /* result status */
- error = 0; /* No errors so far */
- time_t
- t1, /* start receive */
- t2; /* finish receive */
-
- Tot_Packets = Tot_Retries = 0;
- time (&t1);
-
- if (rddata (fddsk) != SUCCESS)
- error++;
-
- time (&t2);
- t2 -= t1;
- if (t2 <= 0)
- t2 = 1;
-
- filesize = ftell (fddsk);
-
- xfer.files_recv++;
- xfer.fbytes_recv += filesize;
-
- if (Tot_Retries) {
- ulog (-1, "Retransmitted/Total Packets: %d/%d", Tot_Retries, Tot_Packets);
- }
-
- status = fclose (fddsk); /* Make sure the data got here */
-
- if (status != 0) {
- error++;
- DEBUG (0, "fclose errno=%d\n", errno);
- }
-
- /*
- * Move the file from its temp location to its real location,
- * This needs to be able to copy a file if a simple rename
- * does not suffice. Should create directories if necesary.
- * should use source name if target is a directory (i.e. no
- * target source name
- */
-
- ulog (5, "temp name '%s', dstnam '%s'", temp, dstnam);
- unlink (dstnam);
-
- if (norename) { /* for security redirect */
- status = 0;
- }
- else {
- status = rename (temp, dstnam);
- if (status < 0) {
- /*
- ** Section originally from 'wusel@hactar.hanse.de'
- **
- ** Changed slightly by 'mbs@adastra.cvl.va.us'.
- **
- ** STILL doesn't try to copy like it should on failure.
- ** (required to be able to use T: as temp directory -- FIXME)
- **
- ** Determine if the remote left off dstnam, as some
- ** Unices do when sending several files at once. Try
- ** to find out dstnam by strchr()'ing in srcnam.
- ** May need some work -- FIXME!
- */
- static char
- newnam [NAMESIZE],
- *ptr;
- int
- dstlen = strlen (dstnam);
-
- if (dstnam [dstlen - 1] == '/' || dstnam [dstlen - 1] == ':') {
- ptr = strrchr (srcnam, '/');
- if (!ptr)
- ptr = strrchr (srcnam, ':');
- if (ptr)
- ptr++;
- else
- ptr = srcnam;
- strcpy (newnam, dstnam);
- strcpy (newnam + dstlen, ptr);
- status = rename (temp, newnam);
- if (status < 0) {
- ulog (-1, "rename to %s failed, deleting file and trying again", newnam);
- remove (newnam);
- status = rename (temp, newnam);
- }
- }
- else {
- ulog (-1, "RENAME TO %s FAILED, DELETING FILE AND TRYING AGAIN", dstnam);
- remove (dstnam);
- status = rename (temp, dstnam);
- }
- }
- }
-
- if (status) {
- /* Oops! Failure. :( */
- error++;
- ulog (-1, "Cannot rename() file '%s' to '%s', errno %ld",
- temp, dstnam, errno);
- }
-
- ulog (-1, "COPY %s (%ld bytes, %ld cps)", error ? "FAILED" : "SUCCEEDED",
- filesize, (filesize / (int) t2));
-
- /*
- ** Section originally from 'wusel@hactar.hanse.de'.
- **
- ** Changed slightly by 'mbs@adastra.cvl.va.us'.
- **
- ** Try to run UUXqt while transfer is still in process. The number
- ** of file pairs that need to be received is controlled by the
- ** configuration entry "UUXqtInterval".
- */
- if (UUXqtInterval) {
- static int
- xfiles = 0;
- int
- c = (int) (((unsigned char *) dstnam) [0]);
-
- if (dstnam [1] == '.' && (c == 'x' || c == 'X')) {
- ++xfiles;
- if ((xfiles % UUXqtInterval) == 0) {
- ulog (-1, "Started UUXqt after %ld jobs", xfiles);
- uuxqt ();
- }
- }
- }
-
- return yesno ('C', error == 0, 5);
- }
-
- /*
- * general file send routine
- * Return SUCCESS, FAIL, or COPYFAIL.
- */
-
- int
- send_file (FILE *fddsk)
- {
- static char
- ansbuf [MAXMSGLEN];
- int
- filesize,
- s;
- time_t
- t1,
- t2;
-
- Tot_Packets = Tot_Retries = 0;
-
- time (&t1);
- s = wrdata (fddsk);
- time (&t2);
-
- t2 -= t1;
- if (t2 <= 0)
- t2 = 1;
-
- filesize = ftell (fddsk);
-
- xfer.files_send++;
- xfer.fbytes_send += filesize;
-
- if (Tot_Retries) {
- ulog (-1, "Retransmitted/Total Packets: %ld/%ld", Tot_Retries, Tot_Packets);
- }
- ulog (-1, "Transmission rate for %ld bytes is %ld CPS", filesize, (filesize / (int) t2));
-
- fclose (fddsk);
-
- if (s != SUCCESS) {
- return COPYFAIL;
- }
-
- /* Await the "CY" or "CNddd" packet, and toss it. */
-
- for (;;) {
- if (rdmsg (ansbuf, MAXMSGLEN) != SUCCESS)
- return FAIL;
-
- if (ansbuf [0] != 'C') {
- DEBUG (0, "\nDidn't get 'CY' or 'CN', got %s\n", ansbuf);
- /* and loop looking for C message */
- }
- else
- if (ansbuf [1] == 'Y') {
- ulog (-1, "REQUESTED %s", ansbuf);
- return SUCCESS;
- }
- else {
- ulog (-1, "COPY FAILED %s", ansbuf);
- return COPYFAIL;
- }
- }
-
- /* NOTREACHED */
- return COPYFAIL;
- }
-
-
- void
- mail_notify (char *from, char *real, char *subject)
- {
- char
- mailcmd [NAMESIZE + 100];
- const char
- *to = "postmaster",
- *sendmail = GetConfigProgram (SENDMAIL);
-
- if (strlen (subject) > 200)
- subject [200] = '\0'; /* CLI input limits */
-
- sprintf (mailcmd,
- "run %s <nil: >nil: -f %s -R \"%s\" -t %s -s \"%s\" -raw",
- sendmail, from, real, to, subject);
-
- Execute (mailcmd, 0, 0);
-
- return;
- }
-
- void
- uuxqt (void)
- {
- const char
- *UUXqt = GetConfigProgram (UUXQT);
- char
- *ptr;
- int
- freeme = 0;
-
- if (UUXqtHostname) {
- ptr = malloc (strlen (UUXqt) + 2 + strlen (host_name));
- if (ptr) {
- freeme = 1;
- sprintf (ptr, "%s %s", UUXqt, host_name);
- }
- }
- else
- ptr = UUXqt;
-
- if (DOSBase->dl_lib.lib_Version < 37) {
- struct Task
- *me = FindTask (NULL);
- int
- freep = 0,
- old;
- char
- *p;
-
- p = malloc (strlen (ptr) + 50);
- if (p) {
- freep = 1;
- sprintf (p, "run <nil: >nil: %s", ptr);
- }
- else
- p = ptr;
-
- old = SetTaskPri (me, UUXqtPriority);
- Execute (p, 0, 0);
- SetTaskPri (me, old);
-
- if (freep)
- free (p);
-
- }
- else {
- /* 2.04+ */
- SystemTags (ptr,
- SYS_Asynch, 1,
- SYS_Input, 0,
- SYS_Output, 0,
- SYS_UserShell, 1,
- NP_CloseInput, 0,
- NP_CloseOutput, 0,
- NP_Priority, UUXqtPriority,
- NP_Cli, 1,
- TAG_DONE);
-
- }
-
- if (freeme)
- free (ptr);
-
- return;
- }
-