home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World of Computer Software
/
World_Of_Computer_Software-02-385-Vol-1of3.iso
/
u
/
uucico_s.lha
/
uucico.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-12-20
|
47KB
|
2,010 lines
/*
* 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.
*
* 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
*
* Added variable packetsize (-Pn). <CB>
*
* JJB - Xferstat support (patches posted to .patches).
*
* sd: - Added Mail notify on failure/success file copies
* - Added Packet retry logging and Force failure if > %25 in error.
* - Added 8K (setvbuf) to buffer writes to disk.
* - Fixed bug with send_file returning COPYFAIL (lost files on send)
* - Logging of number dailed to logfile
* - Record device used and phone number dailed in xferstat
* - Added Converstation failed msgs & failed msg to xferstat
*/
#include "includes.h" /* System include files, system dependent */
#include "uucp.h" /* Uucp definitions and parameters */
#include <log.h>
#include "version.h"
#include <owndevunit.h>
#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 short ProtoHacks;
Prototype short PriMode;
Prototype short OldPri;
Prototype short BigGOpt;
Prototype short IgnoreDTR;
Prototype int PacketTimeout;
Prototype int SendExpectTimeout;
Prototype int ExitCode;
Prototype long BytesIn;
Prototype long BytesOut;
void LogTimes(short);
#define MAX_FLAGS 40
extern int errno;
IDENT(".23 sd.1");
char *ver= "$VER: 1.16.23.sd.1";
static char *Copyright = COPYRIGHT;
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 ourpid = 0, /* Our process ID */
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 */
char our_name[MAX_HOST]; /* Our uucp hostname, set from usenet.ctl */
char path[128];
int debug = -1; /* -1 indicates not set by command line or ctl file */
int f_wait = 0; /* wait for a call (-w) or calls (-w -e) after outbnd */
int loop = 0; /* Loop accepting logins if tty name specified */
int Overide = 0; /* overide modem protocol */
int Getty = 0; /* -Getty initiated */
int IgnoreCD= 0; /* xgetc() should ignore carrier? */
int OurNameOv= 0;
int WindowSize = 999;
int SegSize = 2;
int NoReScan = 0; /* do not rescan for work after error */
int SevenWire= 0;
int XDebug = 0; /* do not pass debug parameter to remote */
int DebugHandshake = 0;
int PacketTimeout = 0;
int SendExpectTimeout = SENDEXPECT_TO;
int ExitCode = 0;
short ProtoHacks; /* protocol hacks */
short PriMode;
short OldPri;
short IgnoreDTR = 0;
short DoAttempt = 0;
short BigGOpt;
long BytesIn;
long BytesOut;
time_t TimeBegin1;
time_t 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;
#define MAX_STRING 200 /* Max length string to send/expect */
#define MSGO2IDX 6
/* We print these prompts */
char msgo0[] = "login: ";
char msgo1[] = "Password:";
char msgo2[10+MAX_HOST] = { "\20Shere" }; /* NO = */
char msgo3[] = "\20ROK\0";
char msgo3a[]= "\20P";
char msgo3bg[]= "\20Pg\0";
char msgo3bG[]= "\20PG\0";
char msgo4[] = "\20OOOOOOO\0";
/* We expect to receive these strings */
char msgi0[] = "uucp\r";
char msgi1[] = "s8000\r";
/* char msgi2[] = "\20S*\0"; We now scan it specially FIXME */
char msgi3g[] = "\20Ug\0";
char msgi3G[] = "\20UG\0";
char 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(isshere)
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)) != EOF) {
data &= 0x7F;
if (data == 020)
break;
}
if (data == EOF)
return FAIL;
while ((data = xgetc(BYTE_TO)) != 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]) {
if (debug > 8)
printf("Compare host names: '%s' '%s'\n", host_name, msgi + count);
strcpy (host_name, msgi + count);
}
strtok(host_name, " \t"); /* put \0 after hostname */
if (debug > 8)
printf("Hostname is '%s'\n", host_name);
return SUCCESS;
}
/*
* get_proto() checks the list of protos given by the foriegn machine
* checking for 'g' (which is the only proto we have). Use only in master
* mode.
*/
int
get_proto()
{
int data;
while ((data = xgetc(BYTE_TO)) != 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.
*/
instr(s, n, to)
char *s;
int n;
int to; /* timeout */
{
int data,count,j;
int i;
static char msgi[512]; /* Incoming trash buffer */
count = 0;
if (to == 0)
to = BYTE_TO;
if (debug > 8) {
printf("Expecting ");
for (i = 0; i < n; i++)
printc(s[i]);
printf("\n");
}
if (DebugHandshake) {
printf("recvd: '");
fflush(stdout);
}
while ((data = xgetc(to)) != EOF) {
data &= 0x7F;
msgi[count++] = data;
if (DebugHandshake) {
if (data < 0x20)
printf("^%c", data + '@');
else
printf("%c", 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(0);
}
}
}
if (DebugHandshake)
printf("' (TIMEOUT!)\n");
if (debug > 8)
printf("\n");
msgi[count] = (char)0;
return(1);
}
/*
* Medium level input routine.
*
* input a line, return -1 on timeout condition else 0
*/
inline(to, buf, max)
int to;
char *buf;
int max;
{
short c;
short i = 0;
--max;
if (to == 0)
to = BYTE_TO;
if (debug > 8 || DebugHandshake) {
printf("Inline: ");
fflush(stdout);
}
while ((c = xgetc(to)) != 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(s, n)
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()
{
if (PriMode) {
long task = FindTask(NULL);
SetTaskPri(task, OldPri);
}
UnLockFiles();
if (OwnDevUnitBase) {
CloseLibrary(OwnDevUnitBase);
OwnDevUnitBase = NULL;
}
}
/*
* 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.
*/
main(argc,argv)
int argc;
char *argv[];
{
int i;
char *poll_sys = (char *)NULL; /* System name to poll, or none */
short rmode = 0; /* 1 = master, 0 = slave */
LogProgram = "uucico";
LogHost = host_name;
LogWho = who;
signal(SIGINT, sigint);
atexit(myexit);
if ((OwnDevUnitBase = OpenLibrary(ODU_NAME, 0)) == NULL) {
printf("Unable to open %s\n", 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 != '-') {
printf("uucico: warning, extra args ignored: %s\n", argv[i]);
break;
}
ptr += 2;
switch (ptr[-1]) {
case 'N':
strcpy(our_name, ptr);
OurNameOv = 1;
break;
case 'D': /* Serial Device */
{
extern char *DeviceName;
DeviceName = argv[++i];
}
break;
case 'U': /* Serial Unit */
{
extern long DeviceUnit;
DeviceUnit = ((*ptr >= '0' && *ptr <= '9') ? atoi(ptr) : atoi(argv[++i]));
}
break;
case 'p': /* protocol hacks */
if (strcmp(ptr, "ri") == 0) { /* -pri */
long 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 { /* -proto */
ProtoHacks |= (*ptr) ? atoi(ptr) : atoi(argv[++i]);
}
break;
case 'g':
case 'G':
Getty = 1;
break;
case 'h':
IgnoreCD = 1;
break;
case 'w':
++f_wait;
break;
case 'r':
rmode = atoi(&argv[i][2]);
break;
case 'X':
XDebug = 1;
case 'x':
if (argv[i][2] == 'x') {
DebugHandshake = 1;
break;
}
debug = atoi(&argv[i][2]);
LogLevel = debug;
LogToStdout = 0;
printf("uucico: debug level set to %d\n", debug);
break;
case 'o':
Overide = 1;
break;
case 'n':
WindowSize = (*ptr) ? atoi(ptr) : 1;
break;
case 'P':
SegSize = (*ptr) ? atoi(ptr) : 1;
break;
case 'b':
system(GetConfigProgram(BATCHNEWS));
break;
case 'S':
ignore_time_restrictions++;
case 's':
poll_sys = &argv[i][2];
break;
case 'e':
++loop;
break;
case 't':
PacketTimeout = (*ptr) ? atoi(ptr) : atoi(argv[++i]);
break;
case 'T':
SendExpectTimeout = (*ptr) ? atoi(ptr) : atoi(argv[++i]);
break;
case '7':
SevenWire = 1;
break;
case 'd':
IgnoreDTR = (*ptr) ? !atoi(ptr) : 1;
break;
case 'H':
IgnoreCD = 1;
Overide = 1;
break;
case 'B':
i++; /* throw away baud rate argument */
break;
case 'A':
DoAttempt = 1;
break;
default:
printf("uucico: warning, bad flag %s\n", argv[i]);
break;
}
}
/* If argument provided, use it as name of comm port */
/* FIXME, this needs some thought. */
getcwd(path,128);
if (chdir(GetConfigDir(UUSPOOL))) {
perror("Can't chdir to Spool directory");
exit(2);
}
read_ctl();
/*
* 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:uuslave.log", "a", stdout);
}
/*setvbuf(stdout, NULL, _IOLBF, 0);*/
/* Timestamp the long debug log */
if (debug > 0) {
long clock;
time(&clock);
printf("\014\nuuslave log on tty '%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 = (char *)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(msg)
char *msg;
{
int i = 0;
int cr = 1;
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);
}
}
/*
* Read the control file and grab a few parameters.
*/
int
read_ctl()
{
char *nodename = FindConfig(NODENAME);
char *debugstr = FindConfig(DEBUGNAME);
char *tmp;
if (nodename && OurNameOv == 0)
strcpy(our_name, nodename);
if (debugstr && debug < 0)
debug = atoi(debugstr);
/*
* 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
*
* ie 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()
{
return call_system((char *)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(sys, ifworkpend)
char *sys;
{
FILE *lsys;
static char buf[MAX_LSYS];
static char sysnam[MAX_HOST];
static char prev_name[MAX_HOST];
int called = FAIL;
int 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);
(void) sscanf(buf, "%s", sysnam);
if (!strcmp(sysnam, prev_name)) {
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) != 0)
continue;
if (ifworkpend && !work_scan(sysnam)) {
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)) {
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);
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(lsysline)
char *lsysline;
{
static char tempname[MAX_HOST + 30 + SLOP];
char *sysnam,
*times,
*acu,
*sbaud,
*telno,
*send,
*expct,
*expct1,
*errm;
int baud, sendexpectok;
int r;
char *pnum;
who[0] = '-'; who[1] = '\0'; /* No user now (for logit) */
/* FIXME, use the values it is ignoring here */
sysnam = strtok(lsysline, " \t");
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);
/* FIX ME, acu not implemented ? */
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 = (char *)strtok((char *)NULL, " \t");
if (expct == NULL)
break;
if (DebugHandshake)
printf("Expect = %s\n", expct);
expct1 = strtokp(&expct, "-");
while (expct1) {
if (expct1[0] != '"' || expct1[1] != '"' || expct1[2] != '\0') {
if (DebugHandshake)
printf("Expect %s\n", expct1);
if (instr(expct1, strlen(expct1), SendExpectTimeout) == SUCCESS)
break;
} else {
if (DebugHandshake)
puts("Expect Nothing");
break;
}
/*
* expect failed, check for alternates
*/
errm = expct1;
if (expct1 = (char *)strtokp(&expct, "-")) {
if (DebugHandshake)
printf("Send = %s\n", expct1);
xlat_str(expct1);
} else {
sendexpectok = FALSE;
strtok("", " ");
break;
}
expct1 = strtokp(&expct, "-");
}
if (send = (char*)strtok((char *)NULL, " \t\n")) {
if (DebugHandshake)
printf("Send %s\n", send);
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.
* FIXME, WE CAN'T TALK TO SITES THAT SUPPORT more than 'g'.
*/
if (instr(msgo3a, sizeof(msgo3a)-1, 0)) {
if (!get_proto())
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:
hangup();
LogTimes(FAIL);
return (FAIL);
}
void
LogTimes(r)
short r;
{
time_t e = time(NULL);
time_t t1 = (TimeBegin1) ? e - TimeBegin1 : 0;
time_t t2 = (TimeBegin2) ? e - TimeBegin2 : 0;
FILE *fi;
char *logFile = MakeConfigPath(UUSPOOL, "TimeLog");
char 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);
}
}
/* Handle a single uucp [slave] login session */
int
do_session(ontheline)
int ontheline;
{
TimeBegin1 = 0;
TimeBegin2 = time(NULL);
BytesIn = 0;
BytesOut= 0;
int r;
if (ontheline == 0) {
/* output login request, verify uucp */
twrite(msgo0,sizeof(msgo0)-1);
if (instr(msgi0, sizeof(msgi0)-1, 0)) {
printf("uucico: invalid login name\n");
goto bort;
}
/* output password request, verify s8000 */
twrite(msgo1,sizeof(msgo1)-1);
if (instr(msgi1, sizeof(msgi1)-1, 0)) {
printf("uucico: invalid password\n");
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))
goto bort;
} else {
if (instr(msgi3g, sizeof(msgi3g)-1, 0))
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(master_mode)
int master_mode;
{
static char buf[MAXMSGLEN]; /* For hangup responses */
if (master_mode) {
(void) work_scan(host_name); /* Kick off queue scan */
goto master;
}
for (;;) {
slave: /* SLAVE SIDE */
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);
(void) 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()
{
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()
{
FILE *fd;
char *sname;
static char cmnd[256]; /* Command character */
static char buf[256];
int fail = SUCCESS;
int failAction = SUCCESS;
int failaccum = 0;
int num;
int delmeflag;
static char notify[NAMESIZE]; /* A bit large...FIXME */
char *delList[16]; /* delete files list */
short di = 0;
/*
* 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) {
if (debug > 7)
printf("Invalid scanf %d/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);
{
short 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(c, true, err)
char c;
int true;
int err;
{
char buf[21];
buf[0] = c;
buf[1] = true? 'Y': 'N';
buf[2] = 0;
if (err && !true)
sprintf(buf+2,"%d", 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(msg)
char *msg;
{
FILE *fddsk; /* Disk file pointer */
static char cmnd[256]; /* Command character */
int r;
int 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) {
printf("Cannot open temp file %s (%s) for writing, errno=%d\n",
temp,
dstnam,
errno
);
}
ulog(-1, "REQUEST FAILED -- TEMP FILE");
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)
*/
{
char from[80];
char *GetUserName();
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(msg)
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. */
if (debug > 0) {
printf("Cannot open file %s (%s) for reading, errno=%d\n",
temp, srcnam, errno
);
}
ulog(-1, "DENIED CAN'T OPEN %s", temp);
return(yesno('R', 0, 2));
}
if (yesno('R',1, 0) != SUCCESS) {
fclose(fddsk);
return(FAIL);
}
x = send_file(fddsk);
/*
* if copy failed, don't care since 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(workstr, delmeflag)
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)
printf("Can't open file %s (%s), errno=%d\n",
temp,
srcnam,
errno
);
ulog(-1, "NOT FOUND %s", temp);
/*
* 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);
}
/* Delete the source file if it was just a copy */
if (res != SUCCESS) {
UnLockFile(temp);
return res;
}
if (strchr(flags, 'c')) { /* If copied direct from source */
UnLockFile(temp);
return res; /* ...just return. */
}
*delmeflag = 1;
UnLockFile(temp);
return (res);
}
/*
* MASTER MODE, We wish to receive a specific file so we ask for it
*
* Return 0 = success
*/
int
local_receive_file()
{
static char buf[MAXMSGLEN];
FILE *fddsk; /* Disk file pointer */
int r;
/* FIXME, test dest file access before we ask for it. */
sprintf(buf,"R %s %s %s %s %s 0%o %s",
srcnam, dstnam, who, flags, temp, mode, who
);
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) {
printf("Cannot open temp file %s (%s) for writing, errno=%d\n",
temp,
dstnam,
errno
);
}
ulog(-1, "REQUEST FAILED -- TEMPFILE %s", temp);
return FAIL;
}
ulog(-1, "REQUEST %s", buf);
if (wrmsg(buf) != SUCCESS) {
fclose(fddsk);
UnLockFile(temp);
printf("uucico: problem sending request\n");
return (FAIL);
}
/* See what the other side has to say about it */
if (rdmsg(buf, MAXMSGLEN) != SUCCESS) {
fclose(fddsk);
UnLockFile(temp);
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(fddsk, temp, dstnam, srcnam, norename)
FILE *fddsk;
char *temp, *dstnam, *srcnam;
{
int status;
int error = 0; /* No errors so far */
extern long Tot_Retries;
extern long Tot_Packets;
static char *fbuf = NULL;
Tot_Packets = Tot_Retries = 0;
if (fbuf == NULL) fbuf = malloc(8192); /* just call malloc once, and reuse*/
if (fbuf) setvbuf(fddsk,fbuf,_IOFBF,8192);
if (rddata(fddsk) != SUCCESS)
error++;
xfer.files_recv++;
xfer.fbytes_recv += ftell(fddsk);
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
*/
unlink(dstnam);
if (norename) { /* for security redirect */
status = 0;
} else {
status = rename(temp, dstnam);
if (status < 0) {
ulog(-1, "RENAME TO %s FAILED, DELETING FILE AND TRYING AGAIN", dstnam);
remove(dstnam);
status = rename(temp, dstnam);
}
}
if (status != 0) {
error++;
if (debug > 0) {
printf("Cannot rename file %s to %s, errno=%d\n",
temp, dstnam, errno);
}
}
ulog(-1, "COPY %s", error ? "FAILED": "SUCCEEDED");
return(yesno('C', error == 0, 5));
}
/*
* general file send routine
* Return SUCCESS, FAIL, or COPYFAIL.
*/
int
send_file(fddsk)
FILE *fddsk; /* Disk file pointer */
{
static char ansbuf[MAXMSGLEN];
int s;
extern long Tot_Packets;
extern long Tot_Retries;
Tot_Packets = Tot_Retries = 0;
s = wrdata(fddsk);
xfer.files_send++;
xfer.fbytes_send += ftell(fddsk);
if (Tot_Retries) {
ulog(-1,"Retransmitted/Total Packets: %d/%d",Tot_Retries,Tot_Packets);
}
if (s != SUCCESS) {
fclose(fddsk);
return COPYFAIL;
}
fclose(fddsk);
/* 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);
}
}
return (COPYFAIL); /* NOTREACHED */
}
mail_notify(from,real,subject)
char *from;
char *real;
char *subject;
{
char mailcmd[NAMESIZE+100];
char *to = "postmaster";
/*
* should really inquire on SENDMAIL variable in config file
*/
char *sendmail = "sendmail";
if (strlen(subject) > 200) subject[200] = '\0'; /* cli input limits */
sprintf(mailcmd, "%s <nil: >nil: -f %s -R \"%s\" -t %s -s \"%s\"",
sendmail,from,real,to,subject);
Execute(mailcmd,NULL,NULL);
}