#include "uucp.h"
#if USE_RCS_ID
const char rec_rcsid[] = "$Id: rec.c,v 1.48 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"
#define CASSUMED_FILE_SIZE (10240)
struct srecinfo
{
char *zmail;
char *zfile;
char *ztemp;
boolean fspool;
boolean flocal;
boolean freceived;
boolean freplied;
boolean fmoved;
};
struct srecfailinfo
{
enum tfailure twhy;
boolean fsent;
boolean freceived;
};
static void urrec_free P((struct stransfer *qtrans));
static boolean flocal_rec_fail P((struct stransfer *qtrans,
struct scmd *qcmd,
const struct uuconf_system *qsys,
const char *zwhy));
static boolean flocal_rec_send_request P((struct stransfer *qtrans,
struct sdaemon *qdaemon));
static boolean flocal_rec_await_reply P((struct stransfer *qtrans,
struct sdaemon *qdaemon,
const char *zdata,
size_t cdata));
static boolean fremote_send_reply P((struct stransfer *qtrans,
struct sdaemon *qdaemon));
static boolean fremote_send_fail P((struct sdaemon *qdaemon,
struct scmd *qcmd,
enum tfailure twhy,
int iremote));
static boolean fremote_send_fail_send P((struct stransfer *qtrans,
struct sdaemon *qdaemon));
static boolean fremote_discard P((struct stransfer *qtrans,
struct sdaemon *qdaemon,
const char *zdata, size_t cdata));
static boolean frec_file_end P((struct stransfer *qtrans,
struct sdaemon *qdaemon,
const char *zdata, size_t cdata));
static boolean frec_file_send_confirm P((struct stransfer *qtrans,
struct sdaemon *qdaemon));
static void
urrec_free (qtrans)
struct stransfer *qtrans;
{
struct srecinfo *qinfo = (struct srecinfo *) qtrans->pinfo;
if (qinfo != NULL)
{
ubuffree (qinfo->zmail);
ubuffree (qinfo->zfile);
ubuffree (qinfo->ztemp);
xfree (qtrans->pinfo);
}
utransfree (qtrans);
}
boolean
flocal_rec_file_init (qdaemon, qcmd)
struct sdaemon *qdaemon;
struct scmd *qcmd;
{
const struct uuconf_system *qsys;
boolean fspool;
char *zfile;
struct srecinfo *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_rec_fail ((struct stransfer *) NULL, qcmd, qsys,
"not permitted to request files");
return TRUE;
}
fspool = fspool_file (qcmd->zto);
if (fspool)
{
pointer puuconf;
int iuuconf;
const char *zlocalname;
struct uuconf_system slocalsys;
if (qcmd->zto[0] != 'D'
|| strchr (qcmd->zoptions, '9') == NULL)
return flocal_rec_fail ((struct stransfer *) NULL, qcmd, qsys,
"not permitted to receive");
puuconf = qdaemon->puuconf;
iuuconf = uuconf_localname (puuconf, &zlocalname);
if (iuuconf == UUCONF_NOT_FOUND)
{
zlocalname = zsysdep_localname ();
if (zlocalname == NULL)
return FALSE;
}
else if (iuuconf != UUCONF_SUCCESS)
{
ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
return FALSE;
}
iuuconf = uuconf_system_info (puuconf, zlocalname, &slocalsys);
if (iuuconf == UUCONF_NOT_FOUND)
{
iuuconf = uuconf_system_local (puuconf, &slocalsys);
if (iuuconf != UUCONF_SUCCESS)
{
ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
return FALSE;
}
slocalsys.uuconf_zname = (char *) zlocalname;
}
else if (iuuconf != UUCONF_SUCCESS)
{
ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
return FALSE;
}
zfile = zsysdep_spool_file_name (&slocalsys, qcmd->zto, qcmd->pseq);
(void) uuconf_system_free (puuconf, &slocalsys);
if (zfile == NULL)
return FALSE;
}
else
{
zfile = zsysdep_add_base (qcmd->zto, qcmd->zfrom);
if (zfile == NULL)
return FALSE;
if (! fin_directory_list (zfile, qsys->uuconf_pzlocal_receive,
qsys->uuconf_zpubdir, TRUE,
FALSE, qcmd->zuser))
{
ubuffree (zfile);
return flocal_rec_fail ((struct stransfer *) NULL, qcmd, qsys,
"not permitted to receive");
}
if (strchr (qcmd->zoptions, 'f') == NULL)
{
if (! fsysdep_make_dirs (zfile, TRUE))
{
ubuffree (zfile);
return flocal_rec_fail ((struct stransfer *) NULL, qcmd,
qsys, "cannot create directories");
}
}
}
qinfo = (struct srecinfo *) xmalloc (sizeof (struct srecinfo));
if (strchr (qcmd->zoptions, 'm') == NULL)
qinfo->zmail = NULL;
else
qinfo->zmail = zbufcpy (qcmd->zuser);
qinfo->zfile = zfile;
qinfo->ztemp = NULL;
qinfo->fspool = fspool;
qinfo->flocal = TRUE;
qinfo->freceived = FALSE;
qinfo->freplied = TRUE;
qtrans = qtransalc (qcmd);
qtrans->psendfn = flocal_rec_send_request;
qtrans->pinfo = (pointer) qinfo;
return fqueue_local (qdaemon, qtrans);
}
static boolean
flocal_rec_fail (qtrans, qcmd, qsys, zwhy)
struct stransfer *qtrans;
struct scmd *qcmd;
const struct uuconf_system *qsys;
const char *zwhy;
{
if (zwhy != NULL)
{
ulog (LOG_ERROR, "%s: %s", qcmd->zfrom, zwhy);
(void) fmail_transfer (FALSE, qcmd->zuser, (const char *) NULL, zwhy,
qcmd->zfrom, qsys->uuconf_zname,
qcmd->zto, (const char *) NULL,
(const char *) NULL);
(void) fsysdep_did_work (qcmd->pseq);
}
if (qtrans != NULL)
urrec_free (qtrans);
return TRUE;
}
static boolean
flocal_rec_send_request (qtrans, qdaemon)
struct stransfer *qtrans;
struct sdaemon *qdaemon;
{
struct srecinfo *qinfo = (struct srecinfo *) qtrans->pinfo;
long cbytes, cbytes2;
boolean fquote;
const struct scmd *qcmd;
struct scmd squoted;
size_t clen;
char *zsend;
boolean fret;
qinfo->ztemp = zsysdep_receive_temp (qdaemon->qsys, qinfo->zfile,
(const char *) NULL,
(qdaemon->qproto->frestart
&& (qdaemon->ifeatures
& FEATURE_RESTART) != 0));
if (qinfo->ztemp == NULL)
{
urrec_free (qtrans);
return FALSE;
}
qtrans->fcmd = TRUE;
qtrans->precfn = flocal_rec_await_reply;
if (! fqueue_receive (qdaemon, qtrans))
return FALSE;
cbytes = csysdep_bytes_free (qinfo->ztemp);
cbytes2 = csysdep_bytes_free (qinfo->zfile);
if (cbytes < cbytes2)
cbytes = cbytes2;
if (cbytes != -1)
{
cbytes -= qdaemon->qsys->uuconf_cfree_space;
if (cbytes < 0)
cbytes = 0;
}
if (qdaemon->clocal_size != -1
&& (cbytes == -1 || qdaemon->clocal_size < cbytes))
cbytes = qdaemon->clocal_size;
fquote = fcmd_needs_quotes (&qtrans->s);
if (! fquote)
qcmd = &qtrans->s;
else
{
if ((qdaemon->ifeatures & FEATURE_QUOTES) == 0)
return flocal_rec_fail (qtrans, &qtrans->s, qdaemon->qsys,
"remote system does not support required quoting");
uquote_cmd (&qtrans->s, &squoted);
qcmd = &squoted;
}
clen = (strlen (qcmd->zfrom) + strlen (qcmd->zto)
+ strlen (qcmd->zuser) + strlen (qcmd->zoptions) + 30);
zsend = zbufalc (clen);
if ((qdaemon->ifeatures & FEATURE_SIZES) == 0)
sprintf (zsend, "R %s %s %s -%s", qcmd->zfrom, qcmd->zto,
qcmd->zuser, qcmd->zoptions);
else if ((qdaemon->ifeatures & FEATURE_V103) == 0)
sprintf (zsend, "R %s %s %s -%s 0x%lx", qcmd->zfrom, qcmd->zto,
qcmd->zuser, qcmd->zoptions, (unsigned long) cbytes);
else
sprintf (zsend, "R %s %s %s -%s %ld", qcmd->zfrom, qcmd->zto,
qcmd->zuser, qcmd->zoptions, cbytes);
fret = (*qdaemon->qproto->pfsendcmd) (qdaemon, zsend, qtrans->ilocal,
qtrans->iremote);
ubuffree (zsend);
if (fquote)
ufree_quoted_cmd (&squoted);
return fret;
}
static boolean
flocal_rec_await_reply (qtrans, qdaemon, zdata, cdata)
struct stransfer *qtrans;
struct sdaemon *qdaemon;
const char *zdata;
size_t cdata ATTRIBUTE_UNUSED;
{
struct srecinfo *qinfo = (struct srecinfo *) qtrans->pinfo;
const char *zlog;
char *zend;
if (zdata[0] != 'R'
|| (zdata[1] != 'Y' && zdata[1] != 'N'))
{
ulog (LOG_ERROR, "%s: bad response to receive request: \"%s\"",
qtrans->s.zfrom, zdata);
urrec_free (qtrans);
return FALSE;
}
if (zdata[1] == 'N')
{
boolean fnever;
const char *zerr;
fnever = TRUE;
if (zdata[2] == '2')
zerr = "no such file";
else if (zdata[2] == '6')
{
zerr = "too large to receive now";
fnever = FALSE;
}
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)
return flocal_rec_fail (qtrans, &qtrans->s, qdaemon->qsys, zerr);
ulog (LOG_ERROR, "%s: %s", qtrans->s.zfrom, zerr);
urrec_free (qtrans);
return TRUE;
}
qtrans->s.imode = (unsigned int) strtol ((char *) (zdata + 2),
&zend, 8);
if (qtrans->s.imode == 0)
qtrans->s.imode = 0666;
if (*zend == 'M' && qdaemon->fmaster)
{
DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO,
"flocal_rec_await_reply: Remote has requested transfer of control");
qdaemon->fhangup_requested = TRUE;
}
qtrans->e = esysdep_open_receive (qdaemon->qsys, qinfo->zfile,
(const char *) NULL, qinfo->ztemp,
(long *) NULL);
if (! ffileisopen (qtrans->e))
return flocal_rec_fail (qtrans, &qtrans->s, qdaemon->qsys,
"cannot open file");
if (qinfo->fspool)
zlog = qtrans->s.zto;
else
zlog = qinfo->zfile;
qtrans->zlog = zbufalc (sizeof "Receiving " + strlen (zlog));
sprintf (qtrans->zlog, "Receiving %s", zlog);
if (qdaemon->qproto->pffile != NULL)
{
boolean fhandled;
if (! (*qdaemon->qproto->pffile) (qdaemon, qtrans, TRUE, FALSE,
(long) -1, &fhandled))
return flocal_rec_fail (qtrans, &qtrans->s, qdaemon->qsys,
(const char *) NULL);
if (fhandled)
return TRUE;
}
qtrans->frecfile = TRUE;
qtrans->psendfn = frec_file_send_confirm;
qtrans->precfn = frec_file_end;
return fqueue_receive (qdaemon, qtrans);
}
boolean
frec_check_free (qtrans, cfree_space)
struct stransfer *qtrans;
long cfree_space;
{
struct srecinfo *qinfo = (struct srecinfo *) qtrans->pinfo;
long cfree1, cfree2;
cfree1 = csysdep_bytes_free (qinfo->ztemp);
cfree2 = csysdep_bytes_free (qinfo->zfile);
if (cfree1 < cfree2)
cfree1 = cfree2;
if (cfree1 != -1 && cfree1 < cfree_space)
{
ulog (LOG_ERROR, "%s: too big to receive now", qinfo->zfile);
return FALSE;
}
return TRUE;
}
boolean
fremote_send_file_init (qdaemon, qcmd, iremote)
struct sdaemon *qdaemon;
struct scmd *qcmd;
int iremote;
{
const struct uuconf_system *qsys;
boolean fspool;
char *zfile;
openfile_t e;
char *ztemp;
long cbytes, cbytes2;
long crestart;
struct srecinfo *qinfo;
struct stransfer *qtrans;
const char *zlog;
qsys = qdaemon->qsys;
if (! qsys->uuconf_frec_request)
{
ulog (LOG_ERROR, "%s: not permitted to receive files from remote",
qcmd->zfrom);
return fremote_send_fail (qdaemon, qcmd, FAILURE_PERM, iremote);
}
fspool = fspool_file (qcmd->zto);
if ((fspool && qcmd->zto[0] == 'C')
|| (qcmd->bcmd == 'E'
&& (! fspool || qcmd->zto[0] != 'D')))
{
ulog (LOG_ERROR, "%s: not permitted to receive", qcmd->zfrom);
return fremote_send_fail (qdaemon, qcmd, FAILURE_PERM, iremote);
}
if (fsysdep_already_received (qsys, qcmd->zto, qcmd->ztemp))
return fremote_send_fail (qdaemon, qcmd, FAILURE_RECEIVED, iremote);
if (fspool)
{
zfile = zsysdep_spool_file_name (qsys, qcmd->zto, (pointer) NULL);
if (zfile == NULL)
return FALSE;
}
else
{
boolean fbadname;
zfile = zsysdep_local_file (qcmd->zto, qsys->uuconf_zpubdir,
&fbadname);
if (zfile == NULL && fbadname)
{
ulog (LOG_ERROR, "%s: bad local file name", qcmd->zto);
return fremote_send_fail (qdaemon, qcmd, FAILURE_PERM, iremote);
}
if (zfile != NULL)
{
char *zadd;
zadd = zsysdep_add_base (zfile, qcmd->zfrom);
ubuffree (zfile);
zfile = zadd;
}
if (zfile == NULL)
return FALSE;
if (! fin_directory_list (zfile, qsys->uuconf_pzremote_receive,
qsys->uuconf_zpubdir, TRUE,
FALSE, (const char *) NULL))
{
ulog (LOG_ERROR, "%s: not permitted to receive", zfile);
ubuffree (zfile);
return fremote_send_fail (qdaemon, qcmd, FAILURE_PERM, iremote);
}
if (strchr (qcmd->zoptions, 'f') == NULL)
{
if (! fsysdep_make_dirs (zfile, TRUE))
{
ubuffree (zfile);
return fremote_send_fail (qdaemon, qcmd, FAILURE_OPEN,
iremote);
}
}
}
ztemp = zsysdep_receive_temp (qsys, zfile, qcmd->ztemp,
(qdaemon->qproto->frestart
&& (qdaemon->ifeatures
& FEATURE_RESTART) != 0));
cbytes = csysdep_bytes_free (ztemp);
cbytes2 = csysdep_bytes_free (zfile);
if (cbytes < cbytes2)
cbytes = cbytes2;
if (cbytes != -1)
{
cbytes -= qsys->uuconf_cfree_space;
if (cbytes < 0)
cbytes = 0;
}
if (qdaemon->cremote_size != -1
&& (cbytes == -1 || qdaemon->cremote_size < cbytes))
cbytes = qdaemon->cremote_size;
if (cbytes != -1)
{
long csize;
csize = qcmd->cbytes;
if (csize == -1)
csize = CASSUMED_FILE_SIZE;
if (cbytes < csize)
{
ulog (LOG_ERROR, "%s: too big to receive", zfile);
ubuffree (ztemp);
ubuffree (zfile);
return fremote_send_fail (qdaemon, qcmd, FAILURE_SIZE, iremote);
}
}
crestart = -1;
e = esysdep_open_receive (qsys, zfile, qcmd->ztemp, ztemp,
((qdaemon->qproto->frestart
&& (qdaemon->ifeatures
& FEATURE_RESTART) != 0)
? &crestart
: (long *) NULL));
if (! ffileisopen (e))
{
ubuffree (ztemp);
ubuffree (zfile);
return fremote_send_fail (qdaemon, qcmd, FAILURE_OPEN, iremote);
}
if (crestart > 0)
{
DEBUG_MESSAGE1 (DEBUG_UUCP_PROTO,
"fremote_send_file_init: Restarting receive from %ld",
crestart);
if (! ffileseek (e, crestart))
{
ulog (LOG_ERROR, "seek: %s", strerror (errno));
(void) ffileclose (e);
ubuffree (ztemp);
ubuffree (zfile);
return FALSE;
}
}
qinfo = (struct srecinfo *) xmalloc (sizeof (struct srecinfo));
if (strchr (qcmd->zoptions, 'n') == NULL)
qinfo->zmail = NULL;
else
qinfo->zmail = zbufcpy (qcmd->znotify);
qinfo->zfile = zfile;
qinfo->ztemp = ztemp;
qinfo->fspool = fspool;
qinfo->flocal = FALSE;
qinfo->freceived = FALSE;
qinfo->freplied = FALSE;
qtrans = qtransalc (qcmd);
qtrans->psendfn = fremote_send_reply;
qtrans->precfn = frec_file_end;
qtrans->iremote = iremote;
qtrans->pinfo = (pointer) qinfo;
qtrans->frecfile = TRUE;
qtrans->e = e;
if (crestart > 0)
qtrans->ipos = crestart;
if (qcmd->bcmd == 'E')
zlog = qcmd->zcmd;
else
{
if (qinfo->fspool)
zlog = qcmd->zto;
else
zlog = qinfo->zfile;
}
qtrans->zlog = zbufalc (sizeof "Receiving ( bytes resume at )"
+ strlen (zlog) + 50);
sprintf (qtrans->zlog, "Receiving %s", zlog);
if (crestart > 0 || qcmd->cbytes > 0)
{
strcat (qtrans->zlog, " (");
if (qcmd->cbytes > 0)
{
sprintf (qtrans->zlog + strlen (qtrans->zlog), "%ld bytes",
qcmd->cbytes);
if (crestart > 0)
strcat (qtrans->zlog, " ");
}
if (crestart > 0)
sprintf (qtrans->zlog + strlen (qtrans->zlog), "resume at %ld",
crestart);
strcat (qtrans->zlog, ")");
}
return fqueue_remote (qdaemon, qtrans);
}
static boolean
fremote_send_reply (qtrans, qdaemon)
struct stransfer *qtrans;
struct sdaemon *qdaemon;
{
struct srecinfo *qinfo = (struct srecinfo *) qtrans->pinfo;
boolean fret;
char ab[50];
qtrans->psendfn = frec_file_send_confirm;
if (qinfo->freceived)
fret = fqueue_send (qdaemon, qtrans);
else
fret = fqueue_receive (qdaemon, qtrans);
if (! fret)
return FALSE;
ab[0] = qtrans->s.bcmd;
ab[1] = 'Y';
if (qtrans->ipos <= 0)
ab[2] = '\0';
else
sprintf (ab + 2, " 0x%lx", (unsigned long) qtrans->ipos);
qinfo->freplied = TRUE;
if (! (*qdaemon->qproto->pfsendcmd) (qdaemon, ab, qtrans->ilocal,
qtrans->iremote))
{
(void) ffileclose (qtrans->e);
qtrans->e = EFILECLOSED;
(void) remove (qinfo->ztemp);
return FALSE;
}
if (qdaemon->qproto->pffile != NULL)
{
boolean fhandled;
if (! (*qdaemon->qproto->pffile) (qdaemon, qtrans, TRUE, FALSE,
(long) -1, &fhandled))
{
(void) remove (qinfo->ztemp);
urrec_free (qtrans);
return FALSE;
}
}
return TRUE;
}
static boolean
fremote_send_fail (qdaemon, qcmd, twhy, iremote)
struct sdaemon *qdaemon;
struct scmd *qcmd;
enum tfailure twhy;
int iremote;
{
struct srecfailinfo *qinfo;
struct stransfer *qtrans;
qinfo = (struct srecfailinfo *) xmalloc (sizeof (struct srecfailinfo));
qinfo->twhy = twhy;
qinfo->fsent = FALSE;
qinfo->freceived = qdaemon->cchans <= 1;
qtrans = qtransalc (qcmd);
qtrans->psendfn = fremote_send_fail_send;
qtrans->precfn = fremote_discard;
qtrans->iremote = iremote;
qtrans->pinfo = (pointer) qinfo;
return fqueue_remote (qdaemon, qtrans);
}
static boolean
fremote_send_fail_send (qtrans, qdaemon)
struct stransfer *qtrans;
struct sdaemon *qdaemon;
{
struct srecfailinfo *qinfo = (struct srecfailinfo *) qtrans->pinfo;
char ab[4];
int ilocal, iremote;
ab[0] = qtrans->s.bcmd;
ab[1] = 'N';
switch (qinfo->twhy)
{
case FAILURE_PERM:
ab[2] = '2';
break;
case FAILURE_OPEN:
ab[2] = '4';
break;
case FAILURE_SIZE:
ab[2] = '6';
break;
case FAILURE_RECEIVED:
usent_receive_ack (qdaemon, qtrans);
ab[2] = '8';
break;
default:
ab[2] = '\0';
break;
}
ab[3] = '\0';
ilocal = qtrans->ilocal;
iremote = qtrans->iremote;
if (! qinfo->freceived)
{
qinfo->fsent = TRUE;
if (! fqueue_receive (qdaemon, qtrans))
return FALSE;
}
else
{
xfree (qtrans->pinfo);
utransfree (qtrans);
}
return (*qdaemon->qproto->pfsendcmd) (qdaemon, ab, ilocal, iremote);
}
static boolean
fremote_discard (qtrans, qdaemon, zdata, cdata)
struct stransfer *qtrans;
struct sdaemon *qdaemon ATTRIBUTE_UNUSED;
const char *zdata ATTRIBUTE_UNUSED;
size_t cdata;
{
struct srecfailinfo *qinfo = (struct srecfailinfo *) qtrans->pinfo;
DEBUG_MESSAGE1 (DEBUG_UUCP_PROTO,
"fremote_discard: Discarding %lu bytes",
(unsigned long) cdata);
if (cdata != 0)
return TRUE;
qinfo->freceived = TRUE;
if (qinfo->fsent)
{
xfree (qtrans->pinfo);
utransfree (qtrans);
}
return TRUE;
}
static boolean
frec_file_end (qtrans, qdaemon, zdata, cdata)
struct stransfer *qtrans;
struct sdaemon *qdaemon;
const char *zdata ATTRIBUTE_UNUSED;
size_t cdata ATTRIBUTE_UNUSED;
{
struct srecinfo *qinfo = (struct srecinfo *) qtrans->pinfo;
char *zalc;
const char *zerr;
boolean fnever;
DEBUG_MESSAGE3 (DEBUG_UUCP_PROTO, "frec_file_end: %s to %s (freplied %s)",
qtrans->s.zfrom, qtrans->s.zto,
qinfo->freplied ? "TRUE" : "FALSE");
if (qdaemon->qproto->pffile != NULL)
{
boolean fhandled;
if (! (*qdaemon->qproto->pffile) (qdaemon, qtrans, FALSE, FALSE,
(long) -1, &fhandled))
{
(void) remove (qinfo->ztemp);
urrec_free (qtrans);
return FALSE;
}
if (fhandled)
return TRUE;
}
qinfo->freceived = TRUE;
fnever = FALSE;
zalc = NULL;
if (! fsysdep_sync (qtrans->e, qtrans->s.zto))
{
zerr = strerror (errno);
(void) ffileclose (qtrans->e);
qtrans->e = EFILECLOSED;
(void) remove (qinfo->ztemp);
}
else if (! ffileclose (qtrans->e))
{
zerr = strerror (errno);
ulog (LOG_ERROR, "%s: close: %s", qtrans->s.zto, zerr);
(void) remove (qinfo->ztemp);
qtrans->e = EFILECLOSED;
}
else
{
qtrans->e = EFILECLOSED;
if (! fsysdep_move_file (qinfo->ztemp, qinfo->zfile, qinfo->fspool,
FALSE, ! qinfo->fspool,
(qinfo->flocal
? qtrans->s.zuser
: (const char *) NULL)))
{
long cspace;
cspace = csysdep_bytes_free (qinfo->ztemp);
if (cspace == -1)
cspace = FREE_SPACE_DELTA;
cspace -= (qdaemon->qsys->uuconf_cfree_space
+ qdaemon->qsys->uuconf_cfree_space / 2);
if (cspace < 0)
{
(void) remove (qinfo->ztemp);
zerr = "could not move to final location";
}
else
{
const char *az[20];
int i;
zalc = zbufalc (sizeof "could not move to final location (left as )"
+ strlen (qinfo->ztemp));
sprintf (zalc, "could not move to final location (left as %s)",
qinfo->ztemp);
zerr = zalc;
i = 0;
az[i++] = "The file\n\t";
az[i++] = qinfo->ztemp;
az[i++] =
"\nwas saved because the move to the final location failed.\n";
az[i++] = "See the UUCP logs for more details.\n";
az[i++] = "The file transfer was from\n\t";
az[i++] = qdaemon->qsys->uuconf_zname;
az[i++] = "!";
az[i++] = qtrans->s.zfrom;
az[i++] = "\nto\n\t";
az[i++] = qtrans->s.zto;
az[i++] = "\nand was requested by\n\t";
az[i++] = qtrans->s.zuser;
az[i++] = "\n";
(void) fsysdep_mail (OWNER, "UUCP temporary file saved", i, az);
}
ulog (LOG_ERROR, "%s: %s", qinfo->zfile, zerr);
fnever = TRUE;
}
else
{
if (! qinfo->fspool)
{
unsigned int imode;
if ((qtrans->s.imode & 0111) != 0)
imode = 0777;
else
imode = 0666;
(void) fsysdep_change_mode (qinfo->zfile, imode);
}
zerr = NULL;
}
}
ustats (zerr == NULL, qtrans->s.zuser, qdaemon->qsys->uuconf_zname,
FALSE, qtrans->cbytes, qtrans->isecs, qtrans->imicros,
qdaemon->fcaller);
qdaemon->creceived += qtrans->cbytes;
if (zerr == NULL)
{
if (qinfo->zmail != NULL && *qinfo->zmail != '\0')
(void) fmail_transfer (TRUE, qtrans->s.zuser, qinfo->zmail,
(const char *) NULL,
qtrans->s.zfrom, qdaemon->qsys->uuconf_zname,
qtrans->s.zto, (const char *) NULL,
(const char *) NULL);
if (qtrans->s.pseq != NULL)
(void) fsysdep_did_work (qtrans->s.pseq);
if (! qinfo->flocal)
{
(void) fsysdep_remember_reception (qdaemon->qsys, qtrans->s.zto,
qtrans->s.ztemp);
}
}
else
{
if (qinfo->flocal && fnever)
{
(void) fmail_transfer (FALSE, qtrans->s.zuser, qinfo->zmail,
zerr, qtrans->s.zfrom,
qdaemon->qsys->uuconf_zname,
qtrans->s.zto, (const char *) NULL,
(const char *) NULL);
(void) fsysdep_did_work (qtrans->s.pseq);
}
}
ubuffree (zalc);
if (qtrans->s.bcmd == 'E' && zerr == NULL)
{
char *zxqt, *zxqtfile, *ztemp;
FILE *e;
boolean fbad;
zxqt = zbufcpy (qtrans->s.zto);
zxqt[0] = 'X';
zxqtfile = zsysdep_spool_file_name (qdaemon->qsys, zxqt,
(pointer) NULL);
ubuffree (zxqt);
if (zxqtfile == NULL)
{
urrec_free (qtrans);
return FALSE;
}
e = NULL;
ztemp = zsysdep_receive_temp (qdaemon->qsys, zxqtfile, "D.0",
(qdaemon->qproto->frestart
&& (qdaemon->ifeatures
& FEATURE_RESTART) != 0));
if (ztemp != NULL)
e = esysdep_fopen (ztemp, FALSE, FALSE, TRUE);
if (e == NULL)
{
ubuffree (zxqtfile);
ubuffree (ztemp);
urrec_free (qtrans);
return FALSE;
}
if (! fcmd_needs_quotes (&qtrans->s))
{
fprintf (e, "U %s %s\n", qtrans->s.zuser,
qdaemon->qsys->uuconf_zname);
fprintf (e, "F %s\n", qtrans->s.zto);
fprintf (e, "I %s\n", qtrans->s.zto);
if (strchr (qtrans->s.zoptions, 'R') != NULL)
fprintf (e, "R %s\n", qtrans->s.znotify);
fprintf (e, "C %s\n", qtrans->s.zcmd);
}
else
{
char *z1;
char *z2;
fprintf (e, "Q\n");
z1 = zquote_cmd_string (qtrans->s.zuser, FALSE);
z2 = zquote_cmd_string (qdaemon->qsys->uuconf_zname, FALSE);
fprintf (e, "U %s %s\n", z1, z2);
ubuffree (z1);
ubuffree (z2);
z1 = zquote_cmd_string (qtrans->s.zto, FALSE);
fprintf (e, "F %s\n", z1);
fprintf (e, "I %s\n", z1);
ubuffree (z1);
if (strchr (qtrans->s.zoptions, 'R') != NULL)
{
z1 = zquote_cmd_string (qtrans->s.znotify, FALSE);
fprintf (e, "R %s\n", z1);
ubuffree (z1);
}
z1 = zquote_cmd_string (qtrans->s.zcmd, TRUE);
fprintf (e, "C %s\n", z1);
ubuffree (z1);
}
if (strchr (qtrans->s.zoptions, 'N') != NULL)
fprintf (e, "N\n");
if (strchr (qtrans->s.zoptions, 'Z') != NULL)
fprintf (e, "Z\n");
if (strchr (qtrans->s.zoptions, 'e') != NULL)
fprintf (e, "e\n");
fbad = FALSE;
if (! fstdiosync (e, ztemp))
{
(void) fclose (e);
(void) remove (ztemp);
fbad = TRUE;
}
if (! fbad)
{
if (fclose (e) == EOF)
{
ulog (LOG_ERROR, "fclose: %s", strerror (errno));
(void) remove (ztemp);
fbad = TRUE;
}
}
if (! fbad)
{
if (! fsysdep_move_file (ztemp, zxqtfile, TRUE, FALSE, FALSE,
(const char *) NULL))
{
(void) remove (ztemp);
fbad = TRUE;
}
}
ubuffree (zxqtfile);
ubuffree (ztemp);
if (fbad)
{
urrec_free (qtrans);
return FALSE;
}
}
if (zerr == NULL
&& (qtrans->s.bcmd == 'E'
|| (qinfo->fspool && qtrans->s.zto[0] == 'X')))
{
++qdaemon->cxfiles_received;
if (qdaemon->irunuuxqt > 0
&& qdaemon->cxfiles_received >= qdaemon->irunuuxqt)
{
if (fspawn_uuxqt (TRUE, qdaemon->qsys->uuconf_zname,
qdaemon->zconfig))
qdaemon->cxfiles_received = 0;
}
}
qinfo->fmoved = zerr == NULL;
if (qinfo->freplied)
return fqueue_send (qdaemon, qtrans);
return TRUE;
}
static boolean
frec_file_send_confirm (qtrans, qdaemon)
struct stransfer *qtrans;
struct sdaemon *qdaemon;
{
struct srecinfo *qinfo = (struct srecinfo *) qtrans->pinfo;
const char *zsend;
int ilocal, iremote;
if (! qinfo->fmoved)
zsend = "CN5";
else if (! qdaemon->frequest_hangup)
zsend = "CY";
else
{
#if DEBUG > 0
if (qdaemon->fmaster)
ulog (LOG_FATAL, "frec_file_send_confirm: Can't happen");
#endif
DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO,
"frec_send_file_confirm: Requesting remote to transfer control");
zsend = "CYM";
}
if (! qinfo->flocal && qinfo->fmoved)
usent_receive_ack (qdaemon, qtrans);
ilocal = qtrans->ilocal;
iremote = qtrans->iremote;
urrec_free (qtrans);
return (*qdaemon->qproto->pfsendcmd) (qdaemon, zsend, ilocal, iremote);
}
boolean
frec_discard_temp (qdaemon, qtrans)
struct sdaemon *qdaemon;
struct stransfer *qtrans;
{
struct srecinfo *qinfo = (struct srecinfo *) qtrans->pinfo;
if ((qdaemon->ifeatures & FEATURE_RESTART) == 0
|| qtrans->s.ztemp == NULL
|| qtrans->s.ztemp[0] != 'D'
|| strcmp (qtrans->s.ztemp, "D.0") == 0)
(void) remove (qinfo->ztemp);
return TRUE;
}