#include "uucp.h"
#if USE_RCS_ID
const char send_rcsid[] = "$Id: send.c,v 1.57 2002/03/05 19:10:41 ian Rel $";
#endif
#include <errno.h>
#include "uudefs.h"
#include "uuconf.h"
#include "system.h"
#include "prot.h"
#include "trans.h"
struct ssendinfo
{
char *zmail;
char *zfile;
long cbytes;
boolean flocal;
boolean fspool;
boolean fsent;
boolean fnever;
char *zexec;
char *zconfirm;
};
static void usfree_send P((struct stransfer *qtrans));
static boolean flocal_send_fail P((struct scmd *qcmd,
struct sdaemon *qdaemon,
const char *zwhy));
static boolean flocal_send_request P((struct stransfer *qtrans,
struct sdaemon *qdaemon));
static boolean flocal_send_await_reply P((struct stransfer *qtrans,
struct sdaemon *qdaemon,
const char *zdata, size_t cdata));
static boolean flocal_send_cancelled P((struct stransfer *qtrans,
struct sdaemon *qdaemon));
static boolean flocal_send_open_file P((struct stransfer *qtrans,
struct sdaemon *qdaemon));
static boolean fremote_rec_fail P((struct sdaemon *qdaemon,
enum tfailure twhy, int iremote));
static boolean fremote_rec_fail_send P((struct stransfer *qtrans,
struct sdaemon *qdaemon));
static boolean fremote_rec_reply P((struct stransfer *qtrans,
struct sdaemon *qdaemon));
static boolean fsend_file_end P((struct stransfer *qtrans,
struct sdaemon *qdaemon));
static boolean fsend_await_confirm P((struct stransfer *qtrans,
struct sdaemon *qdaemon,
const char *zdata, size_t cdata));
static boolean fsend_exec_file_init P((struct stransfer *qtrans,
struct sdaemon *qdaemon));
static void usadd_exec_line P((char **pz, size_t *pcalc, size_t *pclen,
int bcmd, const char *z1, const char *z2,
boolean fquote));
static boolean fsend_exec_file P((struct stransfer *qtrans,
struct sdaemon *qdaemon));
static void
usfree_send (qtrans)
struct stransfer *qtrans;
{
struct ssendinfo *qinfo = (struct ssendinfo *) qtrans->pinfo;
if (qinfo != NULL)
{
ubuffree (qinfo->zmail);
ubuffree (qinfo->zfile);
ubuffree (qinfo->zexec);
ubuffree (qinfo->zconfirm);
xfree (qtrans->pinfo);
}
utransfree (qtrans);
}
boolean
flocal_send_file_init (qdaemon, qcmd)
struct sdaemon *qdaemon;
struct scmd *qcmd;
{
const struct uuconf_system *qsys;
boolean fspool;
char *zfile;
long cbytes;
struct ssendinfo *qinfo;
struct stransfer *qtrans;
qsys = qdaemon->qsys;
if (qdaemon->fcaller
? ! qsys->uuconf_fcall_transfer
: ! qsys->uuconf_fcalled_transfer)
{
if (! qsys->uuconf_fcall_transfer
&& ! qsys->uuconf_fcalled_transfer)
return flocal_send_fail (qcmd, qdaemon,
"not permitted to transfer files");
return TRUE;
}
if (strchr (qcmd->zoptions, 'C') == NULL
&& ! fspool_file (qcmd->zfrom))
{
fspool = FALSE;
if (! fin_directory_list (qcmd->zfrom,
qsys->uuconf_pzlocal_send,
qsys->uuconf_zpubdir, TRUE,
TRUE, qcmd->zuser))
return flocal_send_fail (qcmd, qdaemon, "not permitted to send");
zfile = zbufcpy (qcmd->zfrom);
}
else
{
fspool = TRUE;
zfile = zsysdep_spool_file_name (qsys, qcmd->ztemp, qcmd->pseq);
if (zfile == NULL)
return FALSE;
}
cbytes = csysdep_size (zfile);
if (cbytes < 0)
{
ubuffree (zfile);
if (cbytes != -1)
return flocal_send_fail (qcmd, qdaemon, "can not get size");
if (! fspool)
return flocal_send_fail (qcmd, qdaemon, "does not exist");
(void) fsysdep_did_work (qcmd->pseq);
return TRUE;
}
if (qdaemon->clocal_size != -1
&& qdaemon->clocal_size < cbytes)
{
ubuffree (zfile);
if (qdaemon->cmax_ever == -2)
{
long c1, c2;
c1 = cmax_size_ever (qsys->uuconf_qcall_local_size);
c2 = cmax_size_ever (qsys->uuconf_qcalled_local_size);
if (c1 > c2)
qdaemon->cmax_ever = c1;
else
qdaemon->cmax_ever = c2;
}
if (qdaemon->cmax_ever != -1
&& qdaemon->cmax_ever < qcmd->cbytes)
return flocal_send_fail (qcmd, qdaemon, "too large to send");
return TRUE;
}
qinfo = (struct ssendinfo *) xmalloc (sizeof (struct ssendinfo));
if (strchr (qcmd->zoptions, 'm') == NULL)
qinfo->zmail = NULL;
else
qinfo->zmail = zbufcpy (qcmd->zuser);
qinfo->zfile = zfile;
qinfo->cbytes = cbytes;
qinfo->flocal = strchr (qcmd->zuser, '!') == NULL;
qinfo->fspool = fspool;
qinfo->fsent = FALSE;
qinfo->zexec = NULL;
qinfo->zconfirm = NULL;
qtrans = qtransalc (qcmd);
qtrans->psendfn = flocal_send_request;
qtrans->pinfo = (pointer) qinfo;
return fqueue_local (qdaemon, qtrans);
}
static boolean
flocal_send_fail (qcmd, qdaemon, zwhy)
struct scmd *qcmd;
struct sdaemon *qdaemon;
const char *zwhy;
{
if (zwhy != NULL)
{
const char *zfrom;
char *zfree;
const char *ztemp;
if (qcmd->bcmd != 'E')
{
zfrom = qcmd->zfrom;
zfree = NULL;
}
else
{
zfree = zbufalc (strlen (qcmd->zfrom)
+ sizeof " (execution of \"\")"
+ strlen (qcmd->zcmd));
sprintf (zfree, "%s (execution of \"%s\")", qcmd->zfrom,
qcmd->zcmd);
zfrom = zfree;
}
ulog (LOG_ERROR, "%s: %s", zfrom, zwhy);
if (strchr (qcmd->zuser, '!') == NULL)
ztemp = zsysdep_save_temp_file (qcmd->pseq);
else
ztemp = NULL;
(void) fmail_transfer (FALSE, qcmd->zuser, (const char *) NULL,
zwhy, zfrom, (const char *) NULL,
qcmd->zto, qdaemon->qsys->uuconf_zname, ztemp);
ubuffree (zfree);
}
(void) fsysdep_did_work (qcmd->pseq);
return TRUE;
}
static boolean
flocal_send_request (qtrans, qdaemon)
struct stransfer *qtrans;
struct sdaemon *qdaemon;
{
struct ssendinfo *qinfo = (struct ssendinfo *) qtrans->pinfo;
boolean fquote;
const struct scmd *qcmd;
struct scmd squoted;
const char *znotify;
char absize[20];
char *zsend;
boolean fret;
if (qdaemon->cmax_receive != -1
&& qdaemon->cmax_receive < qinfo->cbytes)
{
fret = flocal_send_fail (&qtrans->s, qdaemon, "too large for receiver");
usfree_send (qtrans);
return fret;
}
if (! fsysdep_file_exists (qinfo->zfile))
{
(void) fsysdep_did_work (qtrans->s.pseq);
usfree_send (qtrans);
return TRUE;
}
qtrans->fcmd = TRUE;
qtrans->psendfn = flocal_send_open_file;
qtrans->precfn = flocal_send_await_reply;
if (qdaemon->cchans > 1)
fret = fqueue_send (qdaemon, qtrans);
else
fret = fqueue_receive (qdaemon, qtrans);
if (! fret)
return FALSE;
fquote = fcmd_needs_quotes (&qtrans->s);
if (! fquote)
qcmd = &qtrans->s;
else
{
if ((qdaemon->ifeatures & FEATURE_QUOTES) == 0)
{
fret = flocal_send_fail (&qtrans->s, qdaemon,
"remote system does not support required quoting");
usfree_send (qtrans);
return fret;
}
uquote_cmd (&qtrans->s, &squoted);
qcmd = &squoted;
}
znotify = qcmd->znotify;
if (znotify == NULL)
znotify = "";
if ((qdaemon->ifeatures & FEATURE_SIZES) != 0
|| (qcmd->bcmd == 'E'
&& (qdaemon->ifeatures & FEATURE_EXEC) != 0))
{
if (*znotify == '\0')
znotify = "\"\"";
}
else
{
if (strcmp (znotify, "\"\"") == 0)
znotify = "";
}
if ((qdaemon->ifeatures & FEATURE_SIZES) == 0
&& (qcmd->bcmd != 'E'
|| (qdaemon->ifeatures & FEATURE_EXEC) == 0))
absize[0] = '\0';
else if ((qdaemon->ifeatures & FEATURE_V103) == 0)
sprintf (absize, "0x%lx", (unsigned long) qinfo->cbytes);
else
sprintf (absize, "%ld", qinfo->cbytes);
zsend = zbufalc (strlen (qcmd->zfrom) + strlen (qcmd->zto)
+ strlen (qcmd->zuser) + strlen (qcmd->zoptions)
+ strlen (qcmd->ztemp) + strlen (znotify)
+ strlen (absize)
+ (qcmd->zcmd != NULL ? strlen (qcmd->zcmd) : 0)
+ 50);
if (qcmd->bcmd == 'E'
&& (qdaemon->ifeatures & FEATURE_EXEC) != 0)
{
sprintf (zsend, "E %s %s %s -%s %s 0%o %s %s %s", qcmd->zfrom,
qcmd->zto, qcmd->zuser, qcmd->zoptions,
qcmd->ztemp, qcmd->imode, znotify, absize,
qcmd->zcmd);
}
else
{
const char *zoptions, *zdummy;
if (qcmd->bcmd != 'E')
zoptions = qcmd->zoptions;
else if (strchr (qcmd->zoptions, 'C') != NULL)
{
zoptions = "";
}
else
zoptions = "c";
if ((qdaemon->ifeatures & FEATURE_SVR4) != 0)
zdummy = " dummy ";
else
zdummy = " ";
sprintf (zsend, "S %s %s %s -%s %s 0%o %s%s%s", qcmd->zfrom,
qcmd->zto, qcmd->zuser, zoptions,
qcmd->ztemp, qcmd->imode, znotify, zdummy,
absize);
}
fret = (*qdaemon->qproto->pfsendcmd) (qdaemon, zsend, qtrans->ilocal,
qtrans->iremote);
ubuffree (zsend);
if (fquote)
ufree_quoted_cmd (&squoted);
return fret;
}
static boolean
flocal_send_await_reply (qtrans, qdaemon, zdata, cdata)
struct stransfer *qtrans;
struct sdaemon *qdaemon;
const char *zdata;
size_t cdata ATTRIBUTE_UNUSED;
{
struct ssendinfo *qinfo = (struct ssendinfo *) qtrans->pinfo;
char bcmd;
if (qtrans->s.bcmd == 'E'
&& (qdaemon->ifeatures & FEATURE_EXEC) != 0)
bcmd = 'E';
else
bcmd = 'S';
if (zdata[0] != bcmd
|| (zdata[1] != 'Y' && zdata[1] != 'N'))
{
ulog (LOG_ERROR, "%s: Bad response to %c request: \"%s\"",
qtrans->s.zfrom, bcmd, zdata);
usfree_send (qtrans);
return FALSE;
}
if (zdata[1] == 'N')
{
const char *zerr;
boolean fnever;
fnever = TRUE;
if (zdata[2] == '2')
zerr = "permission denied by remote";
else if (zdata[2] == '4')
{
zerr = "remote cannot create work files";
fnever = FALSE;
}
else if (zdata[2] == '6')
{
zerr = "too large for remote now";
fnever = FALSE;
}
else if (zdata[2] == '7')
{
zerr = "too large for remote";
}
else if (zdata[2] == '8')
{
zerr = NULL;
}
else if (zdata[2] == '9')
{
zerr = "too many channels for remote";
fnever = FALSE;
if (qdaemon->cchans > 2)
--qdaemon->cchans;
}
else
zerr = "unknown reason";
if (! fnever
|| (qtrans->s.bcmd == 'E'
&& (qdaemon->ifeatures & FEATURE_EXEC) == 0
&& qinfo->zexec == NULL))
{
if (qtrans->s.bcmd == 'E')
ulog (LOG_ERROR, "%s (execution of \"%s\"): %s",
qtrans->s.zfrom, qtrans->s.zcmd, zerr);
else
ulog (LOG_ERROR, "%s: %s", qtrans->s.zfrom, zerr);
}
else
{
if (! flocal_send_fail (&qtrans->s, qdaemon, zerr))
return FALSE;
}
if (qdaemon->cchans == 1 || qinfo->fsent)
{
if (fnever
&& qtrans->s.bcmd == 'E'
&& (qdaemon->ifeatures & FEATURE_EXEC) == 0
&& qinfo->zexec == NULL)
return fsend_exec_file_init (qtrans, qdaemon);
usfree_send (qtrans);
return TRUE;
}
else
{
if (qtrans->fsendfile && ! ffileseekend (qtrans->e))
{
ulog (LOG_ERROR, "seek to end: %s", strerror (errno));
usfree_send (qtrans);
return FALSE;
}
qtrans->psendfn = flocal_send_cancelled;
qtrans->precfn = NULL;
qinfo->fnever = fnever;
return fqueue_send (qdaemon, qtrans);
}
}
if (zdata[2] != '\0')
{
long cskip;
cskip = strtol ((char *) (zdata + 2), (char **) NULL, 0);
if (cskip > 0 && qtrans->ipos < cskip)
{
if (qtrans->fsendfile && ! qinfo->fsent)
{
if (! ffileseek (qtrans->e, cskip))
{
ulog (LOG_ERROR, "seek: %s", strerror (errno));
usfree_send (qtrans);
return FALSE;
}
}
qtrans->ipos = cskip;
}
}
qtrans->fcmd = TRUE;
qtrans->precfn = fsend_await_confirm;
if (qinfo->fsent)
return fqueue_receive (qdaemon, qtrans);
else if (qdaemon->cchans <= 1)
return fqueue_send (qdaemon, qtrans);
else
return TRUE;
}
static boolean
flocal_send_open_file (qtrans, qdaemon)
struct stransfer *qtrans;
struct sdaemon *qdaemon;
{
struct ssendinfo *qinfo = (struct ssendinfo *) qtrans->pinfo;
const char *zuser;
if (qinfo->zexec == NULL)
{
zuser = qtrans->s.zuser;
if (strchr (zuser, '!') != NULL)
zuser = NULL;
qtrans->e = esysdep_open_send (qdaemon->qsys, qinfo->zfile,
! qinfo->fspool, zuser);
if (! ffileisopen (qtrans->e))
{
(void) fmail_transfer (FALSE, qtrans->s.zuser,
(const char *) NULL,
"cannot open file",
qtrans->s.zfrom, (const char *) NULL,
qtrans->s.zto,
qdaemon->qsys->uuconf_zname,
(qinfo->flocal
? zsysdep_save_temp_file (qtrans->s.pseq)
: (const char *) NULL));
(void) fsysdep_did_work (qtrans->s.pseq);
usfree_send (qtrans);
return FALSE;
}
}
if (qtrans->ipos > 0)
{
if (qinfo->zexec != NULL)
{
if (qtrans->ipos > qtrans->cbytes)
qtrans->ipos = qtrans->cbytes;
}
else
{
if (! ffileseek (qtrans->e, qtrans->ipos))
{
ulog (LOG_ERROR, "seek: %s", strerror (errno));
usfree_send (qtrans);
return FALSE;
}
}
}
if (qinfo->zexec == NULL)
{
const char *zsend;
char *zalc;
if (qtrans->s.bcmd != 'E')
{
zsend = qtrans->s.zfrom;
zalc = NULL;
}
else
{
zalc = zbufalc (strlen (qtrans->s.zcmd) + sizeof " ()"
+ strlen (qtrans->s.zfrom));
sprintf (zalc, "%s (%s)", qtrans->s.zcmd, qtrans->s.zfrom);
zsend = zalc;
}
qtrans->zlog = zbufalc (sizeof "Sending ( bytes resume at )"
+ strlen (zsend) + 50);
sprintf (qtrans->zlog, "Sending %s (%ld bytes", zsend, qinfo->cbytes);
if (qtrans->ipos > 0)
sprintf (qtrans->zlog + strlen (qtrans->zlog), " resume at %ld",
qtrans->ipos);
strcat (qtrans->zlog, ")");
ubuffree (zalc);
}
if (qdaemon->qproto->pffile != NULL)
{
boolean fhandled;
if (! (*qdaemon->qproto->pffile) (qdaemon, qtrans, TRUE, TRUE,
qinfo->cbytes - qtrans->ipos,
&fhandled))
{
usfree_send (qtrans);
return FALSE;
}
if (fhandled)
return TRUE;
}
if (qinfo->zexec != NULL)
qtrans->psendfn = fsend_exec_file;
else
{
qtrans->fsendfile = TRUE;
qtrans->psendfn = fsend_file_end;
}
return fqueue_send (qdaemon, qtrans);
}
static boolean
flocal_send_cancelled (qtrans, qdaemon)
struct stransfer *qtrans;
struct sdaemon *qdaemon;
{
struct ssendinfo *qinfo = (struct ssendinfo *) qtrans->pinfo;
if (qinfo->fnever
&& qtrans->s.bcmd == 'E'
&& (qdaemon->ifeatures & FEATURE_EXEC) == 0
&& qinfo->zexec == NULL)
return fsend_exec_file_init (qtrans, qdaemon);
usfree_send (qtrans);
return TRUE;
}
boolean
fremote_rec_file_init (qdaemon, qcmd, iremote)
struct sdaemon *qdaemon;
struct scmd *qcmd;
int iremote;
{
const struct uuconf_system *qsys;
char *zfile;
boolean fbadname;
long cbytes;
unsigned int imode;
openfile_t e;
struct ssendinfo *qinfo;
struct stransfer *qtrans;
qsys = qdaemon->qsys;
if (! qsys->uuconf_fsend_request)
{
ulog (LOG_ERROR, "%s: not permitted to send files to remote",
qcmd->zfrom);
return fremote_rec_fail (qdaemon, FAILURE_PERM, iremote);
}
if (fspool_file (qcmd->zfrom))
{
ulog (LOG_ERROR, "%s: not permitted to send", qcmd->zfrom);
return fremote_rec_fail (qdaemon, FAILURE_PERM, iremote);
}
zfile = zsysdep_local_file (qcmd->zfrom, qsys->uuconf_zpubdir, &fbadname);
if (zfile == NULL && fbadname)
{
ulog (LOG_ERROR, "%s: bad local file name", qcmd->zfrom);
return fremote_rec_fail (qdaemon, FAILURE_PERM, iremote);
}
if (zfile != NULL)
{
char *zbased;
zbased = zsysdep_add_base (zfile, qcmd->zto);
ubuffree (zfile);
zfile = zbased;
}
if (zfile == NULL)
return fremote_rec_fail (qdaemon, FAILURE_PERM, iremote);
if (! fin_directory_list (zfile, qsys->uuconf_pzremote_send,
qsys->uuconf_zpubdir, TRUE, TRUE,
(const char *) NULL))
{
ulog (LOG_ERROR, "%s: not permitted to send", zfile);
ubuffree (zfile);
return fremote_rec_fail (qdaemon, FAILURE_PERM, iremote);
}
cbytes = csysdep_size (zfile);
if (cbytes != -1
&& ((qcmd->cbytes != -1 && qcmd->cbytes < cbytes)
|| (qdaemon->cremote_size != -1
&& qdaemon->cremote_size < cbytes)
|| (qdaemon->cmax_receive != -1
&& qdaemon->cmax_receive < cbytes)))
{
ulog (LOG_ERROR, "%s: too large to send", zfile);
ubuffree (zfile);
return fremote_rec_fail (qdaemon, FAILURE_SIZE, iremote);
}
imode = ixsysdep_file_mode (zfile);
e = esysdep_open_send (qsys, zfile, TRUE, (const char *) NULL);
if (! ffileisopen (e))
{
ubuffree (zfile);
return fremote_rec_fail (qdaemon, FAILURE_OPEN, iremote);
}
if (qcmd->ipos > 0)
{
if (! ffileseek (e, qcmd->ipos))
{
ulog (LOG_ERROR, "seek: %s", strerror (errno));
ubuffree (zfile);
return FALSE;
}
}
qinfo = (struct ssendinfo *) xmalloc (sizeof (struct ssendinfo));
qinfo->zmail = NULL;
qinfo->zfile = zfile;
qinfo->cbytes = cbytes;
qinfo->flocal = FALSE;
qinfo->fspool = FALSE;
qinfo->fsent = FALSE;
qinfo->zexec = NULL;
qinfo->zconfirm = NULL;
qtrans = qtransalc (qcmd);
qtrans->psendfn = fremote_rec_reply;
qtrans->iremote = iremote;
qtrans->pinfo = (pointer) qinfo;
qtrans->e = e;
qtrans->ipos = qcmd->ipos;
qtrans->s.imode = imode;
return fqueue_remote (qdaemon, qtrans);
}
static boolean
fremote_rec_reply (qtrans, qdaemon)
struct stransfer *qtrans;
struct sdaemon *qdaemon;
{
struct ssendinfo *qinfo = (struct ssendinfo *) qtrans->pinfo;
char absend[50];
qtrans->fsendfile = TRUE;
qtrans->psendfn = fsend_file_end;
qtrans->fcmd = TRUE;
qtrans->precfn = fsend_await_confirm;
if (! fqueue_send (qdaemon, qtrans))
return FALSE;
qtrans->zlog = zbufalc (sizeof "Sending ( bytes) "
+ strlen (qtrans->s.zfrom) + 25);
sprintf (qtrans->zlog, "Sending %s (%ld bytes)", qtrans->s.zfrom,
qinfo->cbytes);
if (qdaemon->frequest_hangup)
DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO,
"fremote_rec_reply: Requesting remote to transfer control");
sprintf (absend, "RY 0%o%s 0x%lx%s", qtrans->s.imode,
qdaemon->frequest_hangup ? "M" : "",
(unsigned long) qinfo->cbytes,
qdaemon->frequest_hangup ? "M" : "");
if (! (*qdaemon->qproto->pfsendcmd) (qdaemon, absend, qtrans->ilocal,
qtrans->iremote))
{
(void) ffileclose (qtrans->e);
qtrans->e = EFILECLOSED;
return FALSE;
}
if (qdaemon->qproto->pffile != NULL)
{
boolean fhandled;
if (! (*qdaemon->qproto->pffile) (qdaemon, qtrans, TRUE, TRUE,
qinfo->cbytes, &fhandled))
{
usfree_send (qtrans);
return FALSE;
}
}
return TRUE;
}
static boolean
fremote_rec_fail (qdaemon, twhy, iremote)
struct sdaemon *qdaemon;
enum tfailure twhy;
int iremote;
{
enum tfailure *ptinfo;
struct stransfer *qtrans;
ptinfo = (enum tfailure *) xmalloc (sizeof (enum tfailure));
*ptinfo = twhy;
qtrans = qtransalc ((struct scmd *) NULL);
qtrans->psendfn = fremote_rec_fail_send;
qtrans->iremote = iremote;
qtrans->pinfo = (pointer) ptinfo;
return fqueue_remote (qdaemon, qtrans);
}
static boolean
fremote_rec_fail_send (qtrans, qdaemon)
struct stransfer *qtrans;
struct sdaemon *qdaemon;
{
enum tfailure *ptinfo = (enum tfailure *) qtrans->pinfo;
const char *z;
int ilocal, iremote;
switch (*ptinfo)
{
case FAILURE_PERM:
case FAILURE_OPEN:
z = "RN2";
break;
case FAILURE_SIZE:
z = "RN6";
break;
default:
z = "RN";
break;
}
ilocal = qtrans->ilocal;
iremote = qtrans->iremote;
xfree (qtrans->pinfo);
utransfree (qtrans);
return (*qdaemon->qproto->pfsendcmd) (qdaemon, z, ilocal, iremote);
}
static boolean
fsend_file_end (qtrans, qdaemon)
struct stransfer *qtrans;
struct sdaemon *qdaemon;
{
struct ssendinfo *qinfo = (struct ssendinfo *) qtrans->pinfo;
if (qdaemon->qproto->pffile != NULL)
{
boolean fhandled;
if (! (*qdaemon->qproto->pffile) (qdaemon, qtrans, FALSE, TRUE,
(long) -1, &fhandled))
{
usfree_send (qtrans);
return FALSE;
}
if (fhandled)
return TRUE;
}
qinfo->fsent = TRUE;
if (qinfo->zconfirm != NULL)
return fsend_await_confirm (qtrans, qdaemon, qinfo->zconfirm,
strlen (qinfo->zconfirm) + 1);
return fqueue_receive (qdaemon, qtrans);
}
static boolean
fsend_await_confirm (qtrans, qdaemon, zdata, cdata)
struct stransfer *qtrans;
struct sdaemon *qdaemon;
const char *zdata;
size_t cdata ATTRIBUTE_UNUSED;
{
struct ssendinfo *qinfo = (struct ssendinfo *) qtrans->pinfo;
boolean fnever;
const char *zerr;
if (! qinfo->fsent)
{
qinfo->zconfirm = zbufcpy (zdata);
return TRUE;
}
if (qinfo->zexec == NULL)
{
(void) ffileclose (qtrans->e);
qtrans->e = EFILECLOSED;
}
fnever = FALSE;
if (zdata[0] != 'C'
|| (zdata[1] != 'Y' && zdata[1] != 'N'))
{
zerr = "bad confirmation from remote";
ulog (LOG_ERROR, "%s: %s \"%s\"", qtrans->s.zfrom, zerr, zdata);
}
else if (zdata[1] == 'N')
{
fnever = TRUE;
if (zdata[2] == '5')
{
zerr = "file could not be stored in final location";
ulog (LOG_ERROR, "%s: %s", qtrans->s.zfrom, zerr);
}
else
{
zerr = "file send failed for unknown reason";
ulog (LOG_ERROR, "%s: %s \"%s\"", qtrans->s.zfrom, zerr, zdata);
}
}
else
{
zerr = NULL;
if (zdata[2] == 'M' && qdaemon->fmaster)
{
DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO,
"fsend_await_confirm: Remote has requested transfer of control");
qdaemon->fhangup_requested = TRUE;
}
}
ustats (zerr == NULL, qtrans->s.zuser, qdaemon->qsys->uuconf_zname,
TRUE, qtrans->cbytes, qtrans->isecs, qtrans->imicros,
qdaemon->fcaller);
qdaemon->csent += qtrans->cbytes;
if (zerr == NULL)
{
if (qtrans->s.bcmd == 'E'
&& (qdaemon->ifeatures & FEATURE_EXEC) == 0
&& qinfo->zexec == NULL)
return fsend_exec_file_init (qtrans, qdaemon);
if (qinfo->zmail != NULL && *qinfo->zmail != '\0')
(void) fmail_transfer (TRUE, qtrans->s.zuser, qinfo->zmail,
(const char *) NULL,
qtrans->s.zfrom, (const char *) NULL,
qtrans->s.zto, qdaemon->qsys->uuconf_zname,
(const char *) NULL);
if (qtrans->s.pseq != NULL)
(void) fsysdep_did_work (qtrans->s.pseq);
}
else
{
if (fnever && qinfo->flocal)
{
(void) fmail_transfer (FALSE, qtrans->s.zuser, qinfo->zmail,
zerr, qtrans->s.zfrom, (const char *) NULL,
qtrans->s.zto, qdaemon->qsys->uuconf_zname,
zsysdep_save_temp_file (qtrans->s.pseq));
(void) fsysdep_did_work (qtrans->s.pseq);
}
}
usfree_send (qtrans);
return TRUE;
}
static boolean
fsend_exec_file_init (qtrans, qdaemon)
struct stransfer *qtrans;
struct sdaemon *qdaemon;
{
struct ssendinfo *qinfo = (struct ssendinfo *) qtrans->pinfo;
char *zxqtfile;
char abtname[CFILE_NAME_LEN];
char abxname[CFILE_NAME_LEN];
char *z;
size_t calc, clen;
boolean fquote;
z = NULL;
calc = 0;
clen = 0;
fquote = fcmd_needs_quotes (&qtrans->s);
if (fquote)
usadd_exec_line (&z, &calc, &clen, 'Q', "", "", TRUE);
usadd_exec_line (&z, &calc, &clen, 'U', qtrans->s.zuser,
qdaemon->zlocalname, fquote);
usadd_exec_line (&z, &calc, &clen, 'F', qtrans->s.zto, "", fquote);
usadd_exec_line (&z, &calc, &clen, 'I', qtrans->s.zto, "", fquote);
if (strchr (qtrans->s.zoptions, 'N') != NULL)
usadd_exec_line (&z, &calc, &clen, 'N', "", "", fquote);
if (strchr (qtrans->s.zoptions, 'Z') != NULL)
usadd_exec_line (&z, &calc, &clen, 'Z', "", "", fquote);
if (strchr (qtrans->s.zoptions, 'R') != NULL)
usadd_exec_line (&z, &calc, &clen, 'R', qtrans->s.znotify, "", fquote);
if (strchr (qtrans->s.zoptions, 'e') != NULL)
usadd_exec_line (&z, &calc, &clen, 'e', "", "", fquote);
if (! fquote)
usadd_exec_line (&z, &calc, &clen, 'C', qtrans->s.zcmd, "", FALSE);
else
{
char *zquoted;
zquoted = zquote_cmd_string (qtrans->s.zcmd, TRUE);
usadd_exec_line (&z, &calc, &clen, 'C', zquoted, "", FALSE);
ubuffree (zquoted);
}
qinfo->zexec = z;
qinfo->cbytes = clen;
zxqtfile = zsysdep_data_file_name (qdaemon->qsys, qdaemon->zlocalname,
BDEFAULT_UUX_GRADE, TRUE, abtname,
(char *) NULL, abxname);
if (zxqtfile == NULL)
{
usfree_send (qtrans);
return FALSE;
}
ubuffree (zxqtfile);
ubuffree ((char *) qtrans->s.zfrom);
qtrans->s.zfrom = zbufcpy (abtname);
ubuffree ((char *) qtrans->s.zto);
qtrans->s.zto = zbufcpy (abxname);
ubuffree ((char *) qtrans->s.zoptions);
qtrans->s.zoptions = zbufcpy ("C");
ubuffree ((char *) qtrans->s.ztemp);
qtrans->s.ztemp = zbufcpy (abtname);
qtrans->psendfn = flocal_send_request;
qtrans->precfn = NULL;
qtrans->ipos = 0;
qtrans->cbytes = 0;
qtrans->isecs = 0;
qtrans->imicros = 0;
qinfo->fsent = FALSE;
ubuffree (qinfo->zconfirm);
qinfo->zconfirm = NULL;
return fqueue_send (qdaemon, qtrans);
}
static void
usadd_exec_line (pz, pcalc, pclen, bcmd, z1, z2, fquote)
char **pz;
size_t *pcalc;
size_t *pclen;
int bcmd;
const char *z1;
const char *z2;
boolean fquote;
{
char *z1q;
char *z2q;
size_t c1, c2;
char *znew;
z1q = NULL;
z2q = NULL;
if (fquote)
{
if (*z1 != '\0')
{
z1q = zquote_cmd_string (z1, FALSE);
z1 = z1q;
}
if (*z2 != '\0')
{
z2q = zquote_cmd_string (z2, FALSE);
z2 = z2q;
}
}
c1 = strlen (z1);
c2 = strlen (z2);
if (*pclen + c1 + c2 + 4 >= *pcalc)
{
*pcalc += c1 + c2 + 100;
znew = zbufalc (*pcalc);
if (*pclen > 0)
{
memcpy (znew, *pz, *pclen);
ubuffree (*pz);
}
*pz = znew;
}
znew = *pz + *pclen;
*znew++ = bcmd;
if (*z1 != '\0')
{
*znew++ = ' ';
memcpy (znew, z1, c1);
znew += c1;
if (*z2 != '\0')
{
*znew++ = ' ';
memcpy (znew, z2, c2);
znew += c2;
}
}
if (fquote)
{
ubuffree (z1q);
ubuffree (z2q);
}
*znew++ = '\n';
*pclen = znew - *pz;
}
static boolean
fsend_exec_file (qtrans, qdaemon)
struct stransfer *qtrans;
struct sdaemon *qdaemon;
{
struct ssendinfo *qinfo = (struct ssendinfo *) qtrans->pinfo;
char *zdata;
size_t cdata;
size_t csend;
zdata = (*qdaemon->qproto->pzgetspace) (qdaemon, &cdata);
if (zdata == NULL)
{
usfree_send (qtrans);
return FALSE;
}
csend = qinfo->cbytes - qtrans->ipos;
if (csend > cdata)
csend = cdata;
memcpy (zdata, qinfo->zexec + qtrans->ipos, csend);
if (! (*qdaemon->qproto->pfsenddata) (qdaemon, zdata, csend,
qtrans->ilocal, qtrans->iremote,
qtrans->ipos))
{
usfree_send (qtrans);
return FALSE;
}
qtrans->cbytes += csend;
qtrans->ipos += csend;
if (csend == 0)
return fsend_file_end (qtrans, qdaemon);
return TRUE;
}