#include "uucp.h"
#if USE_RCS_ID
const char uucico_rcsid[] = "$Id: uucico.c,v 1.204 2003/05/29 06:00:49 ian Rel $";
#endif
#include <ctype.h>
#if HAVE_LIMITS_H
#include <limits.h>
#else
#define LONG_MAX 2147483647L
#endif
#include "getopt.h"
#include "uudefs.h"
#include "uuconf.h"
#include "conn.h"
#include "prot.h"
#include "trans.h"
#include "system.h"
#if HAVE_ENCRYPTED_PASSWORDS
#ifndef crypt
extern char *crypt ();
#endif
#endif
#ifdef __COHERENT__
#define COHERENT_C_OPTION 1
#else
#define COHERENT_C_OPTION 0
#endif
#define TCP_PROTO \
(UUCONF_RELIABLE_ENDTOEND \
| UUCONF_RELIABLE_RELIABLE \
| UUCONF_RELIABLE_EIGHT)
static const struct sprotocol asProtocols[] =
{
{ 't', TCP_PROTO, 1, TRUE,
asTproto_params, ftstart, ftshutdown, ftsendcmd, ztgetspace,
ftsenddata, ftwait, ftfile },
{ 'e', TCP_PROTO, 1, TRUE,
asEproto_params, festart, feshutdown, fesendcmd, zegetspace,
fesenddata, fewait, fefile },
{ 'i', UUCONF_RELIABLE_EIGHT, 7, TRUE,
asIproto_params, fistart, fishutdown, fisendcmd, zigetspace,
fisenddata, fiwait, NULL },
{ 'a', UUCONF_RELIABLE_EIGHT, 1, TRUE,
asZproto_params, fzstart, fzshutdown, fzsendcmd, zzgetspace,
fzsenddata, fzwait, fzfile },
{ 'g', UUCONF_RELIABLE_EIGHT, 1, TRUE,
asGproto_params, fgstart, fgshutdown, fgsendcmd, zggetspace,
fgsenddata, fgwait, NULL },
{ 'G', UUCONF_RELIABLE_EIGHT, 1, TRUE,
asGproto_params, fbiggstart, fgshutdown, fgsendcmd, zggetspace,
fgsenddata, fgwait, NULL },
{ 'j', UUCONF_RELIABLE_EIGHT, 7, TRUE,
asIproto_params, fjstart, fjshutdown, fisendcmd, zigetspace,
fisenddata, fiwait, NULL },
{ 'f', UUCONF_RELIABLE_RELIABLE, 1, FALSE,
asFproto_params, ffstart, ffshutdown, ffsendcmd, zfgetspace,
ffsenddata, ffwait, fffile },
{ 'v', UUCONF_RELIABLE_EIGHT, 1, TRUE,
asGproto_params, fvstart, fgshutdown, fgsendcmd, zggetspace,
fgsenddata, fgwait, NULL },
{ 'y', UUCONF_RELIABLE_RELIABLE | UUCONF_RELIABLE_EIGHT, 1, TRUE,
asYproto_params, fystart, fyshutdown, fysendcmd, zygetspace,
fysenddata, fywait, fyfile }
};
#define CPROTOCOLS (sizeof asProtocols / sizeof asProtocols[0])
static boolean fLocked_system;
static struct uuconf_system sLocked_system;
static struct sdaemon sDaemon;
static struct sconnection *qConn;
static pointer pUuconf;
struct spass
{
boolean fmatched;
boolean flocked;
struct sconnection *qconn;
};
static void uusage P((void));
static void uhelp P((void));
static void uabort P((void));
static boolean fcall P((pointer puuconf, const char *zconfig, boolean fuuxqt,
const struct uuconf_system *qsys,
struct uuconf_port *qport, boolean fifwork,
boolean fforce, boolean fdetach,
boolean fquiet, boolean ftrynext));
static boolean fconn_call P((struct sdaemon *qdaemon,
struct uuconf_port *qport,
struct sstatus *qstat, int cretry,
boolean *pfcalled));
static boolean fdo_call P((struct sdaemon *qdaemon,
struct sstatus *qstat,
const struct uuconf_dialer *qdialer,
boolean *pfcalled, enum tstatus_type *pterr));
static int iuport_lock P((struct uuconf_port *qport, pointer pinfo));
static boolean flogin_prompt P((pointer puuconf, const char *zconfig,
boolean fuuxqt, struct sconnection *qconn,
const char *zlogin, const char **pzsystem));
static int icallin_cmp P((int iwhich, pointer pinfo, const char *zfile));
static boolean faccept_call P((pointer puuconf, const char *zconfig,
boolean fuuxqt, const char *zlogin,
struct sconnection *qconn,
const char **pzsystem));
static void uaccept_call_cleanup P((pointer puuconf,
struct uuconf_system *qfreesys,
struct uuconf_port *qport,
struct uuconf_port *qfreeport,
char *zloc));
static void uapply_proto_params P((pointer puuconf, int bproto,
struct uuconf_cmdtab *qcmds,
struct uuconf_proto_param *pas));
static boolean fsend_uucp_cmd P((struct sconnection *qconn,
const char *z));
static char *zget_uucp_cmd P((struct sconnection *qconn,
boolean frequired, boolean fstrip));
static char *zget_typed_line P((struct sconnection *qconn,
boolean fstrip));
static const struct option asLongopts[] =
{
{ "quiet", no_argument, NULL, 2 },
{ "ifwork", no_argument, NULL, 'C' },
{ "nodetach", no_argument, NULL, 'D' },
{ "loop", no_argument, NULL, 'e' },
{ "force", no_argument, NULL, 'f'},
{ "stdin", required_argument, NULL, 'i' },
{ "prompt", no_argument, NULL, 'l' },
{ "port", required_argument, NULL, 'p' },
{ "nouuxqt", no_argument, NULL, 'q' },
{ "master", no_argument, NULL, 3 },
{ "slave", no_argument, NULL, 4 },
{ "system", required_argument, NULL, 's' },
{ "login", required_argument, NULL, 'u' },
{ "wait", no_argument, NULL, 'w' },
{ "try-next", no_argument, NULL, 'z' },
{ "config", required_argument, NULL, 'I' },
{ "debug", required_argument, NULL, 'x' },
{ "version", no_argument, NULL, 'v' },
{ "help", no_argument, NULL, 1 },
{ NULL, 0, NULL, 0 }
};
int
main (argc, argv)
int argc;
char **argv;
{
boolean fquiet = FALSE;
boolean fifwork = FALSE;
boolean fdetach = TRUE;
boolean fendless = FALSE;
boolean fforce = FALSE;
enum uuconf_porttype tstdintype = UUCONF_PORTTYPE_STDIN;
const char *zconfig = NULL;
boolean flogin = FALSE;
const char *zport = NULL;
boolean fuuxqt = TRUE;
boolean fmaster = FALSE;
const char *zsystem = NULL;
const char *zlogin = NULL;
boolean fwait = FALSE;
boolean ftrynext = FALSE;
const char *zopts;
int iopt;
struct uuconf_port *qport;
struct uuconf_port sport;
boolean fret = TRUE;
pointer puuconf;
int iuuconf;
#if DEBUG > 1
int iholddebug;
#endif
if (argc < 1)
{
zProgram = "uucico";
uusage ();
}
zProgram = argv[0];
if (*zProgram == '-')
++zProgram;
#if COHERENT_C_OPTION
zopts = "c:CDefi:I:lp:qr:s:S:u:x:X:vwz";
#else
zopts = "cCDefi:I:lp:qr:s:S:u:x:X:vwz";
#endif
while ((iopt = getopt_long (argc, argv, zopts,
asLongopts, (int *) NULL)) != EOF)
{
#if COHERENT_C_OPTION
if (iopt == 'c')
{
iopt = 's';
fifwork = TRUE;
}
#endif
switch (iopt)
{
case 2:
case 'c':
fquiet = TRUE;
break;
case 'C':
fifwork = TRUE;
break;
case 'D':
fdetach = FALSE;
break;
case 'e':
fendless = TRUE;
break;
case 'f':
fforce = TRUE;
break;
case 'i':
if (strcasecmp (optarg, "tli") != 0)
fprintf (stderr, "%s: unsupported port type \"%s\"\n",
zProgram, optarg);
else
{
#if HAVE_TLI
tstdintype = UUCONF_PORTTYPE_TLI;
#else
fprintf (stderr, "%s: not compiled with TLI support\n",
zProgram);
#endif
}
break;
case 'l':
flogin = TRUE;
break;
case 'p':
zport = optarg;
break;
case 'q':
fuuxqt = FALSE;
break;
case 'r':
if (strcmp (optarg, "1") == 0)
fmaster = TRUE;
else if (strcmp (optarg, "0") == 0)
fmaster = FALSE;
else
uusage ();
break;
case 's':
zsystem = optarg;
fmaster = TRUE;
break;
case 'S':
zsystem = optarg;
fforce = TRUE;
fmaster = TRUE;
break;
case 'u':
if (fsysdep_privileged ())
zlogin = optarg;
else
fprintf (stderr,
"%s: ignoring command line login name: not a privileged user\n",
zProgram);
break;
case 'w':
fwait = TRUE;
break;
case 'z':
ftrynext = TRUE;
break;
case 'I':
if (fsysdep_other_config (optarg))
zconfig = optarg;
break;
case 'x':
case 'X':
#if DEBUG > 1
iDebug |= idebug_parse (optarg);
#endif
break;
case 'v':
printf ("uucico (Taylor UUCP) %s\n", VERSION);
printf ("Copyright (C) 1991, 92, 93, 94, 1995, 2002, 2003 Ian Lance Taylor\n");
printf ("This program is free software; you may redistribute it under the terms of\n");
printf ("the GNU General Public LIcense. This program has ABSOLUTELY NO WARRANTY.\n");
exit (EXIT_SUCCESS);
case 4:
fmaster = FALSE;
break;
case 3:
fmaster = TRUE;
break;
case 1:
uhelp ();
exit (EXIT_SUCCESS);
case 0:
break;
default:
uusage ();
}
}
if (optind != argc)
uusage ();
if (fwait && zport == NULL)
{
fprintf (stderr, "%s: -w requires -p", zProgram);
uusage ();
}
iuuconf = uuconf_init (&puuconf, (const char *) NULL, zconfig);
if (iuuconf != UUCONF_SUCCESS)
ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
pUuconf = puuconf;
#if DEBUG > 1
{
const char *zdebug;
iuuconf = uuconf_debuglevel (puuconf, &zdebug);
if (iuuconf != UUCONF_SUCCESS)
ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
if (zdebug != NULL)
iDebug |= idebug_parse (zdebug);
}
#endif
if (zport == NULL)
qport = NULL;
else
{
iuuconf = uuconf_find_port (puuconf, zport, (long) 0, (long) 0,
(int (*) P((struct uuconf_port *,
pointer))) NULL,
(pointer) NULL, &sport);
if (iuuconf == UUCONF_NOT_FOUND)
ulog (LOG_FATAL, "%s: port not found", zport);
else if (iuuconf != UUCONF_SUCCESS)
ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
qport = &sport;
}
#ifdef SIGINT
usysdep_signal (SIGINT);
#endif
#ifdef SIGHUP
usysdep_signal (SIGHUP);
#endif
#ifdef SIGQUIT
usysdep_signal (SIGQUIT);
#endif
#ifdef SIGTERM
usysdep_signal (SIGTERM);
#endif
#ifdef SIGPIPE
usysdep_signal (SIGPIPE);
#endif
usysdep_initialize (puuconf, INIT_SUID);
ulog_to_file (puuconf, TRUE);
ulog_fatal_fn (uabort);
if (fmaster)
{
if (zsystem != NULL)
{
iuuconf = uuconf_system_info (puuconf, zsystem,
&sLocked_system);
if (iuuconf == UUCONF_NOT_FOUND)
ulog (LOG_FATAL, "%s: System not found", zsystem);
else if (iuuconf != UUCONF_SUCCESS)
ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
if (fdetach &&
(qport == NULL
|| qport->uuconf_ttype != UUCONF_PORTTYPE_STDIN))
usysdep_detach ();
ulog_system (sLocked_system.uuconf_zname);
#if DEBUG > 1
iholddebug = iDebug;
if (sLocked_system.uuconf_zdebug != NULL)
iDebug |= idebug_parse (sLocked_system.uuconf_zdebug);
#endif
if (! fsysdep_lock_system (&sLocked_system))
{
ulog (LOG_ERROR, "System already locked");
fret = FALSE;
}
else
{
fLocked_system = TRUE;
fret = fcall (puuconf, zconfig, fuuxqt, &sLocked_system, qport,
fifwork, fforce, fdetach, fquiet, ftrynext);
if (fLocked_system)
{
(void) fsysdep_unlock_system (&sLocked_system);
fLocked_system = FALSE;
}
}
#if DEBUG > 1
iDebug = iholddebug;
#endif
ulog_system ((const char *) NULL);
(void) uuconf_system_free (puuconf, &sLocked_system);
}
else
{
char **pznames, **pz;
int c, i;
boolean fdidone;
fret = TRUE;
fdidone = FALSE;
iuuconf = uuconf_system_names (puuconf, &pznames, 0);
if (iuuconf != UUCONF_SUCCESS)
ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
c = 0;
for (pz = pznames; *pz != NULL; pz++)
c++;
srand ((unsigned int) ixsysdep_time ((long *) NULL));
for (i = c - 1; i > 0; i--)
{
int iuse;
char *zhold;
iuse = rand () % (i + 1);
zhold = pznames[i];
pznames[i] = pznames[iuse];
pznames[iuse] = zhold;
}
for (pz = pznames; *pz != NULL && ! FGOT_SIGNAL (); pz++)
{
iuuconf = uuconf_system_info (puuconf, *pz,
&sLocked_system);
if (iuuconf != UUCONF_SUCCESS)
{
ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
xfree ((pointer) *pz);
continue;
}
if (fsysdep_has_work (&sLocked_system))
{
fdidone = TRUE;
if (fdetach
&& (qport == NULL
|| qport->uuconf_ttype != UUCONF_PORTTYPE_STDIN))
usysdep_detach ();
ulog_system (sLocked_system.uuconf_zname);
#if DEBUG > 1
iholddebug = iDebug;
if (sLocked_system.uuconf_zdebug != NULL)
iDebug |= idebug_parse (sLocked_system.uuconf_zdebug);
#endif
if (! fsysdep_lock_system (&sLocked_system))
{
ulog (LOG_ERROR, "System already locked");
fret = FALSE;
}
else
{
fLocked_system = TRUE;
if (! fcall (puuconf, zconfig, fuuxqt, &sLocked_system,
qport, TRUE, fforce, fdetach, fquiet,
ftrynext))
fret = FALSE;
afSignal[INDEXSIG_SIGHUP] = FALSE;
if (fLocked_system)
{
(void) fsysdep_unlock_system (&sLocked_system);
fLocked_system = FALSE;
}
}
#if DEBUG > 1
iDebug = iholddebug;
#endif
ulog_system ((const char *) NULL);
}
(void) uuconf_system_free (puuconf, &sLocked_system);
xfree ((pointer) *pz);
}
xfree ((pointer) pznames);
if (! fdidone && ! fquiet)
ulog (LOG_NORMAL, "No work");
}
if (fwait)
{
fendless = TRUE;
fmaster = FALSE;
}
}
if (! fmaster)
{
struct sconnection sconn;
boolean flocked;
fret = TRUE;
zsystem = NULL;
if (! fconn_init (qport, &sconn, tstdintype))
fret = FALSE;
if (qport != NULL)
{
if (fdetach
&& qport->uuconf_ttype != UUCONF_PORTTYPE_STDIN)
usysdep_detach ();
}
if (fconn_lock (&sconn, TRUE, FALSE))
flocked = TRUE;
else
{
flocked = FALSE;
ulog (LOG_ERROR, "%s: Port already locked",
qport->uuconf_zname);
fret = FALSE;
}
if (fret)
{
if (! fconn_open (&sconn, (long) 0, (long) 0, TRUE, FALSE))
fret = FALSE;
qConn = &sconn;
}
if (fret)
{
if (fendless)
{
while (! FGOT_SIGNAL ()
&& flogin_prompt (puuconf, zconfig, fuuxqt, &sconn,
(const char *) NULL,
(const char **) NULL))
{
if (! fconn_close (&sconn, puuconf,
(struct uuconf_dialer *) NULL,
TRUE)
|| ! fconn_open (&sconn, (long) 0, (long) 0, TRUE,
FALSE))
break;
}
fret = FALSE;
}
else
{
if (flogin)
fret = flogin_prompt (puuconf, zconfig, fuuxqt, &sconn,
zlogin, &zsystem);
else
{
#if DEBUG > 1
iholddebug = iDebug;
#endif
if (zlogin == NULL)
zlogin = zsysdep_login_name ();
fret = faccept_call (puuconf, zconfig, fuuxqt, zlogin,
&sconn, &zsystem);
#if DEBUG > 1
iDebug = iholddebug;
#endif
}
}
}
if (qConn != NULL)
{
if (! fconn_close (&sconn, puuconf, (struct uuconf_dialer *) NULL,
fret))
fret = FALSE;
qConn = NULL;
}
if (flocked)
(void) fconn_unlock (&sconn);
uconn_free (&sconn);
}
ulog_close ();
ustats_close ();
if (afSignal[INDEXSIG_SIGTERM])
fuuxqt = FALSE;
if (fuuxqt)
{
int irunuuxqt;
iuuconf = uuconf_runuuxqt (puuconf, &irunuuxqt);
if (iuuconf != UUCONF_SUCCESS)
ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
else if (irunuuxqt == UUCONF_RUNUUXQT_ONCE)
{
if (fdetach)
usysdep_detach ();
if (! fspawn_uuxqt (FALSE, zsystem, zconfig))
fret = FALSE;
}
}
usysdep_exit (fret);
return 0;
}
static void
uusage ()
{
fprintf (stderr, "Usage: %s [options]\n", zProgram);
fprintf (stderr, "Use %s --help for help\n", zProgram);
exit (EXIT_FAILURE);
}
static void
uhelp ()
{
printf ("Taylor UUCP %s, copyright (C) 1991, 92, 93, 94, 1995, 2002 Ian Lance Taylor\n",
VERSION);
printf ("Usage: %s [options]\n", zProgram);
printf (" -s,-S,--system system: Call system (-S implies -f)\n");
printf (" -f,--force: Force call despite system status\n");
printf (" -r state: 1 for master, 0 for slave (default)\n");
printf (" --master: Act as master\n");
printf (" --slave: Act as slave (default)\n");
printf (" -p,--port port: Specify port\n");
printf (" -l,--prompt: Prompt for login name and password\n");
printf (" -e,--loop: Endless loop of login prompts and daemon execution\n");
printf (" -w,--wait: After calling out, wait for incoming calls\n");
printf (" -q,--nouuxqt: Don't start uuxqt when done\n");
printf (" -c,--quiet: Don't log bad time or no work warnings\n");
printf (" -C,--ifwork: Only call named system if there is work\n");
printf (" -D,--nodetach: Don't detach from controlling terminal\n");
printf (" -u,--login: Set login name (privileged users only)\n");
printf (" -i,--stdin type: Type of standard input (only TLI supported)\n");
printf (" -z,--try-next: If a call fails, try the next alternate\n");
printf (" -x,-X,--debug debug: Set debugging level\n");
#if HAVE_TAYLOR_CONFIG
printf (" -I,--config file: Set configuration file to use\n");
#endif
printf (" -v,--version: Print version and exit\n");
printf (" --help: Print help and exit\n");
printf ("Report bugs to taylor-uucp@gnu.org\n");
}
static void
uabort ()
{
if (fLocked_system)
ufailed (&sDaemon);
ulog_user ((const char *) NULL);
if (qConn != NULL)
{
(void) fconn_close (qConn, pUuconf, (struct uuconf_dialer *) NULL,
FALSE);
(void) fconn_unlock (qConn);
uconn_free (qConn);
}
if (fLocked_system)
{
(void) fsysdep_unlock_system (&sLocked_system);
fLocked_system = FALSE;
}
ulog_system ((const char *) NULL);
ulog_close ();
ustats_close ();
usysdep_exit (FALSE);
}
#define SECS_PER_DAY ((long) 24 * (long) 60 * (long) 60)
static boolean
fcall (puuconf, zconfig, fuuxqt, qorigsys, qport, fifwork, fforce, fdetach,
fquiet, ftrynext)
pointer puuconf;
const char *zconfig;
boolean fuuxqt;
const struct uuconf_system *qorigsys;
struct uuconf_port *qport;
boolean fifwork;
boolean fforce;
boolean fdetach;
boolean fquiet;
boolean ftrynext;
{
struct sstatus sstat;
long inow;
boolean fbadtime, fnevertime, ffoundwork;
const struct uuconf_system *qsys;
if (! fsysdep_get_status (qorigsys, &sstat, (boolean *) NULL))
return FALSE;
ubuffree (sstat.zstring);
inow = ixsysdep_time ((long *) NULL);
if (! fforce)
{
if (qorigsys->uuconf_cmax_retries > 0
&& sstat.cretries >= qorigsys->uuconf_cmax_retries
&& sstat.ilast <= inow
&& sstat.ilast + SECS_PER_DAY > inow)
{
ulog (LOG_ERROR, "Too many retries");
return FALSE;
}
if ((sstat.ttype == STATUS_COMPLETE
? sstat.ilast + qorigsys->uuconf_csuccess_wait > inow
: sstat.ilast + sstat.cwait > inow)
&& sstat.ilast <= inow)
{
ulog (LOG_NORMAL, "Retry time not reached");
return FALSE;
}
}
sDaemon.puuconf = puuconf;
sDaemon.zconfig = zconfig;
if (! fuuxqt)
sDaemon.irunuuxqt = UUCONF_RUNUUXQT_NEVER;
else
{
int iuuconf;
iuuconf = uuconf_runuuxqt (puuconf, &sDaemon.irunuuxqt);
if (iuuconf != UUCONF_SUCCESS)
ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
}
fbadtime = TRUE;
fnevertime = TRUE;
ffoundwork = FALSE;
for (qsys = qorigsys; qsys != NULL; qsys = qsys->uuconf_qalternate)
{
int cretry;
boolean fany, fret, fcalled;
if (FGOT_SIGNAL ())
return FALSE;
if (! qsys->uuconf_fcall || qsys->uuconf_qtimegrade == NULL)
continue;
if (qport != NULL
&& (qsys->uuconf_qport != NULL
|| (qsys->uuconf_zport != NULL
&& strcmp (qport->uuconf_zname, qsys->uuconf_zport) != 0)))
{
const struct uuconf_system *ql;
for (ql = qsys->uuconf_qalternate;
ql != NULL;
ql = ql->uuconf_qalternate)
{
if (ql->uuconf_qport == NULL
&& ql->uuconf_zport != NULL
&& strcmp (ql->uuconf_zport, qport->uuconf_zname) == 0)
break;
}
if (ql != NULL)
continue;
}
fnevertime = FALSE;
if (! ftimespan_match (qsys->uuconf_qtimegrade, (long *) NULL,
&cretry))
continue;
fbadtime = FALSE;
sDaemon.qsys = qsys;
sDaemon.zlocalname = NULL;
sDaemon.qconn = NULL;
sDaemon.qproto = NULL;
sDaemon.cchans = 1;
sDaemon.clocal_size = -1;
sDaemon.cremote_size = -1;
sDaemon.cmax_ever = -2;
sDaemon.cmax_receive = -1;
sDaemon.csent = 0;
sDaemon.creceived = 0;
sDaemon.cxfiles_received = 0;
sDaemon.ifeatures = 0;
sDaemon.frequest_hangup = FALSE;
sDaemon.fhangup_requested = FALSE;
sDaemon.fhangup = FALSE;
sDaemon.fmaster = TRUE;
sDaemon.fcaller = TRUE;
sDaemon.ireliable = 0;
sDaemon.bgrade = '\0';
if (! fqueue (&sDaemon, &fany))
return FALSE;
if (fifwork && ! fany)
{
uclear_queue (&sDaemon);
continue;
}
ffoundwork = TRUE;
fret = fconn_call (&sDaemon, qport, &sstat, cretry, &fcalled);
uclear_queue (&sDaemon);
if (fret)
return TRUE;
if (fcalled && ! ftrynext)
return FALSE;
if (fdetach)
{
(void) fsysdep_unlock_system (&sLocked_system);
fLocked_system = FALSE;
usysdep_detach ();
if (! fsysdep_lock_system (&sLocked_system))
return FALSE;
fLocked_system = TRUE;
}
}
if (fbadtime)
{
if (! fquiet)
ulog (LOG_NORMAL, "Wrong time to call");
if (! fnevertime)
{
sstat.ttype = STATUS_WRONG_TIME;
sstat.ilast = inow;
sstat.cwait = 0;
(void) fsysdep_set_status (qorigsys, &sstat);
}
}
else if (! ffoundwork)
{
if (! fquiet)
ulog (LOG_NORMAL, "No work");
return TRUE;
}
return FALSE;
}
static boolean
fconn_call (qdaemon, qport, qstat, cretry, pfcalled)
struct sdaemon *qdaemon;
struct uuconf_port *qport;
struct sstatus *qstat;
int cretry;
boolean *pfcalled;
{
pointer puuconf;
const struct uuconf_system *qsys;
struct uuconf_port sport;
struct sconnection sconn;
enum tstatus_type terr;
boolean fret;
puuconf = qdaemon->puuconf;
qsys = qdaemon->qsys;
*pfcalled = FALSE;
afSignal[INDEXSIG_SIGHUP] = FALSE;
if (qport == NULL)
qport = qsys->uuconf_qport;
if (qport != NULL)
{
if (! fconn_init (qport, &sconn, UUCONF_PORTTYPE_UNKNOWN))
return FALSE;
if (! fconn_lock (&sconn, FALSE, FALSE))
{
ulog (LOG_ERROR, "%s: Port already locked",
qport->uuconf_zname);
return FALSE;
}
}
else
{
struct spass s;
int iuuconf;
s.fmatched = FALSE;
s.flocked = FALSE;
s.qconn = &sconn;
iuuconf = uuconf_find_port (puuconf, qsys->uuconf_zport,
qsys->uuconf_ibaud,
qsys->uuconf_ihighbaud,
iuport_lock, (pointer) &s,
&sport);
if (iuuconf == UUCONF_NOT_FOUND)
{
if (! s.fmatched)
ulog (LOG_ERROR, "No matching ports");
else
{
ulog (LOG_ERROR, "All matching ports in use");
qstat->ttype = STATUS_PORT_FAILED;
qstat->ilast = ixsysdep_time ((long *) NULL);
if (cretry == 0)
qstat->cwait = CRETRY_WAIT (qstat->cretries);
else
qstat->cwait = cretry * 60;
(void) fsysdep_set_status (qsys, qstat);
}
return FALSE;
}
else if (iuuconf != UUCONF_SUCCESS)
{
ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
if (s.flocked)
{
(void) fconn_unlock (&sconn);
uconn_free (&sconn);
}
return FALSE;
}
}
if (! fconn_open (&sconn, qsys->uuconf_ibaud, qsys->uuconf_ihighbaud,
FALSE, FALSE))
{
terr = STATUS_PORT_FAILED;
fret = FALSE;
}
else
{
struct uuconf_dialer *qdialer;
struct uuconf_dialer sdialer;
enum tdialerfound tdialer;
if (qsys->uuconf_zalternate == NULL)
ulog (LOG_NORMAL, "Calling system %s (port %s)", qsys->uuconf_zname,
zLdevice == NULL ? (char *) "unknown" : zLdevice);
else
ulog (LOG_NORMAL, "Calling system %s (alternate %s, port %s)",
qsys->uuconf_zname, qsys->uuconf_zalternate,
zLdevice == NULL ? (char *) "unknown" : zLdevice);
qdialer = NULL;
if (! fconn_dial (&sconn, puuconf, qsys, qsys->uuconf_zphone,
&sdialer, &tdialer))
{
tdialer = DIALERFOUND_FALSE;
terr = STATUS_DIAL_FAILED;
fret = FALSE;
}
else
{
qdaemon->qconn = &sconn;
if (tdialer == DIALERFOUND_FALSE)
qdialer = NULL;
else
qdialer = &sdialer;
fret = fdo_call (qdaemon, qstat, qdialer, pfcalled, &terr);
}
(void) fconn_close (&sconn, puuconf, qdialer, fret);
if (tdialer == DIALERFOUND_FREE)
(void) uuconf_dialer_free (puuconf, &sdialer);
}
if (! fret)
{
DEBUG_MESSAGE2 (DEBUG_HANDSHAKE, "Call failed: %d (%s)",
(int) terr, azStatus[(int) terr]);
qstat->ttype = terr;
qstat->cretries++;
qstat->ilast = ixsysdep_time ((long *) NULL);
if (cretry == 0)
qstat->cwait = CRETRY_WAIT (qstat->cretries);
else
qstat->cwait = cretry * 60;
(void) fsysdep_set_status (qsys, qstat);
}
(void) fconn_unlock (&sconn);
uconn_free (&sconn);
if (qport == NULL)
(void) uuconf_port_free (puuconf, &sport);
return fret;
}
static boolean
fdo_call (qdaemon, qstat, qdialer, pfcalled, pterr)
struct sdaemon *qdaemon;
struct sstatus *qstat;
const struct uuconf_dialer *qdialer;
boolean *pfcalled;
enum tstatus_type *pterr;
{
pointer puuconf;
const struct uuconf_system *qsys;
struct sconnection *qconn;
int iuuconf;
int istrip;
boolean fstrip;
const char *zport;
char *zstr;
long istart_time;
char *zlog;
puuconf = qdaemon->puuconf;
qsys = qdaemon->qsys;
qconn = qdaemon->qconn;
iuuconf = uuconf_strip (puuconf, &istrip);
if (iuuconf != UUCONF_SUCCESS)
{
ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
return FALSE;
}
fstrip = (istrip & UUCONF_STRIP_PROTO) != 0;
*pterr = STATUS_LOGIN_FAILED;
if (qconn->qport == NULL)
zport = "unknown";
else
zport = qconn->qport->uuconf_zname;
if (! fchat (qconn, puuconf, &qsys->uuconf_schat, qsys,
(const struct uuconf_dialer *) NULL,
(const char *) NULL, FALSE, zport,
iconn_baud (qconn)))
return FALSE;
*pfcalled = TRUE;
istart_time = ixsysdep_time ((long *) NULL);
*pterr = STATUS_HANDSHAKE_FAILED;
zstr = zget_uucp_cmd (qconn, TRUE, fstrip);
if (zstr == NULL)
return FALSE;
if (strncmp (zstr, "Shere", 5) != 0)
{
ulog (LOG_ERROR, "Bad startup string (expected \"Shere\" got \"%s\")",
zstr);
ubuffree (zstr);
return FALSE;
}
ulog (LOG_NORMAL, "Login successful");
qstat->ttype = STATUS_TALKING;
qstat->ilast = ixsysdep_time ((long *) NULL);
qstat->cretries = 0;
qstat->cwait = 0;
if (! fsysdep_set_status (qsys, qstat))
return FALSE;
if (zstr[5] == '=')
{
const char *zheresys;
size_t clen;
int icmp;
zheresys = zstr + 6;
clen = strlen (zheresys);
if (clen == 7 || clen == 14)
icmp = strncmp (zheresys, qsys->uuconf_zname, clen);
else
icmp = strcmp (zheresys, qsys->uuconf_zname);
if (icmp != 0)
{
if (qsys->uuconf_pzalias != NULL)
{
char **pz;
for (pz = qsys->uuconf_pzalias; *pz != NULL; pz++)
{
if (clen == 7 || clen == 14)
icmp = strncmp (zheresys, *pz, clen);
else
icmp = strcmp (zheresys, *pz);
if (icmp == 0)
break;
}
}
if (icmp != 0)
{
ulog (LOG_ERROR, "Called wrong system (%s)", zheresys);
ubuffree (zstr);
return FALSE;
}
}
}
#if DEBUG > 1
else if (zstr[5] != '\0')
DEBUG_MESSAGE1 (DEBUG_HANDSHAKE,
"fdo_call: Strange Shere: %s", zstr);
#endif
ubuffree (zstr);
{
long ival;
char bgrade;
char *zsend;
boolean fret;
if (! ftimespan_match (qsys->uuconf_qcalltimegrade, &ival,
(int *) NULL))
bgrade = '\0';
else
bgrade = (char) ival;
if (qsys->uuconf_zlocalname != NULL)
qdaemon->zlocalname = qsys->uuconf_zlocalname;
else
{
iuuconf = uuconf_localname (puuconf, &qdaemon->zlocalname);
if (iuuconf == UUCONF_NOT_FOUND)
{
qdaemon->zlocalname = zsysdep_localname ();
if (qdaemon->zlocalname == NULL)
return FALSE;
}
else if (iuuconf != UUCONF_SUCCESS)
{
ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
return FALSE;
}
}
zsend = zbufalc (strlen (qdaemon->zlocalname) + 70);
if (! qsys->uuconf_fsequence)
{
if (bgrade == '\0')
sprintf (zsend, "S%s -R -N0%o", qdaemon->zlocalname,
(unsigned int) (FEATURE_SIZES
| FEATURE_EXEC
| FEATURE_RESTART
| FEATURE_QUOTES));
else
sprintf (zsend, "S%s -p%c -vgrade=%c -R -N0%o",
qdaemon->zlocalname, bgrade, bgrade,
(unsigned int) (FEATURE_SIZES
| FEATURE_EXEC
| FEATURE_RESTART
| FEATURE_QUOTES));
}
else
{
long iseq;
iseq = ixsysdep_get_sequence (qsys);
if (iseq < 0)
return FALSE;
if (bgrade == '\0')
sprintf (zsend, "S%s -Q%ld -R -N0%o", qdaemon->zlocalname, iseq,
(unsigned int) (FEATURE_SIZES
| FEATURE_EXEC
| FEATURE_RESTART
| FEATURE_QUOTES));
else
sprintf (zsend, "S%s -Q%ld -p%c -vgrade=%c -R -N0%o",
qdaemon->zlocalname, iseq, bgrade, bgrade,
(unsigned int) (FEATURE_SIZES
| FEATURE_EXEC
| FEATURE_RESTART
| FEATURE_QUOTES));
}
fret = fsend_uucp_cmd (qconn, zsend);
ubuffree (zsend);
if (! fret)
return FALSE;
}
zstr = zget_uucp_cmd (qconn, TRUE, fstrip);
if (zstr == NULL)
return FALSE;
if (zstr[0] != 'R')
{
ulog (LOG_ERROR, "Bad response to handshake string (%s)",
zstr);
ubuffree (zstr);
return FALSE;
}
if (strncmp (zstr + 1, "OKN", sizeof "OKN" - 1) == 0)
{
if (zstr[sizeof "ROKN" - 1] == '\0')
qdaemon->ifeatures |= FEATURE_SIZES | FEATURE_V103;
else
qdaemon->ifeatures |= (int) strtol (zstr + sizeof "ROKN" - 1,
(char **) NULL, 0);
}
else if (strncmp (zstr + 1, "OK", sizeof "OK" - 1) == 0)
{
if (zstr[sizeof "ROK" - 1] != '\0')
{
char *zopt;
zopt = zstr + sizeof "ROK" - 1;
while (*zopt != '\0')
{
char b;
long c;
char *zend;
b = *zopt++;
if (isspace (b) || b != '-')
continue;
switch (*zopt)
{
case 'R':
qdaemon->ifeatures |= (FEATURE_RESTART
| FEATURE_SVR4
| FEATURE_SIZES);
break;
case 'U':
c = strtol (zopt, &zend, 0);
if (c > 0 && c <= LONG_MAX / (long) 512)
qdaemon->cmax_receive = c * (long) 512;
zopt = zend;
break;
}
while (*zopt != '\0' && ! isspace (*zopt))
++zopt;
}
}
}
else if (strcmp (zstr + 1, "CB") == 0)
{
ulog (LOG_NORMAL, "Remote system will call back");
qstat->ttype = STATUS_COMPLETE;
(void) fsysdep_set_status (qsys, qstat);
ubuffree (zstr);
return TRUE;
}
else
{
ulog (LOG_ERROR, "Handshake failed (%s)", zstr + 1);
ubuffree (zstr);
return FALSE;
}
ubuffree (zstr);
zstr = zget_uucp_cmd (qconn, TRUE, fstrip);
if (zstr == NULL)
return FALSE;
if (zstr[0] != 'P')
{
ulog (LOG_ERROR, "Bad protocol handshake (%s)", zstr);
ubuffree (zstr);
return FALSE;
}
if (qconn->qport != NULL
&& (qconn->qport->uuconf_ireliable & UUCONF_RELIABLE_SPECIFIED) != 0)
qdaemon->ireliable = qconn->qport->uuconf_ireliable;
if (qdialer != NULL
&& (qdialer->uuconf_ireliable & UUCONF_RELIABLE_SPECIFIED) != 0)
{
if (qdaemon->ireliable != 0)
qdaemon->ireliable &= qdialer->uuconf_ireliable;
else
qdaemon->ireliable = qdialer->uuconf_ireliable;
}
if (qdaemon->ireliable == 0)
qdaemon->ireliable = (UUCONF_RELIABLE_RELIABLE
| UUCONF_RELIABLE_EIGHT
| UUCONF_RELIABLE_FULLDUPLEX
| UUCONF_RELIABLE_SPECIFIED);
{
size_t i;
char ab[5];
i = CPROTOCOLS;
if (qsys->uuconf_zprotocols != NULL
|| (qconn->qport != NULL
&& qconn->qport->uuconf_zprotocols != NULL))
{
const char *zproto;
if (qsys->uuconf_zprotocols != NULL)
zproto = qsys->uuconf_zprotocols;
else
zproto = qconn->qport->uuconf_zprotocols;
for (; *zproto != '\0'; zproto++)
{
if (strchr (zstr + 1, *zproto) != NULL)
{
for (i = 0; i < CPROTOCOLS; i++)
if (asProtocols[i].bname == *zproto)
break;
if (i < CPROTOCOLS)
break;
}
}
}
else
{
for (i = 0; i < CPROTOCOLS; i++)
{
int ipr;
ipr = asProtocols[i].ireliable;
if ((ipr & qdaemon->ireliable) != ipr)
continue;
if (strchr (zstr + 1, asProtocols[i].bname) != NULL)
break;
}
}
ubuffree (zstr);
if (i >= CPROTOCOLS)
{
(void) fsend_uucp_cmd (qconn, "UN");
ulog (LOG_ERROR, "No mutually supported protocols");
return FALSE;
}
qdaemon->qproto = &asProtocols[i];
if ((qdaemon->ireliable & UUCONF_RELIABLE_FULLDUPLEX) == 0)
qdaemon->cchans = 1;
else
qdaemon->cchans = asProtocols[i].cchans;
sprintf (ab, "U%c", qdaemon->qproto->bname);
if (! fsend_uucp_cmd (qconn, ab))
return FALSE;
}
if (qdaemon->qproto->qcmds != NULL)
{
if (qsys->uuconf_qproto_params != NULL)
uapply_proto_params (puuconf, qdaemon->qproto->bname,
qdaemon->qproto->qcmds,
qsys->uuconf_qproto_params);
if (qconn->qport != NULL
&& qconn->qport->uuconf_qproto_params != NULL)
uapply_proto_params (puuconf, qdaemon->qproto->bname,
qdaemon->qproto->qcmds,
qconn->qport->uuconf_qproto_params);
if (qdialer != NULL
&& qdialer->uuconf_qproto_params != NULL)
uapply_proto_params (puuconf, qdaemon->qproto->bname,
qdaemon->qproto->qcmds,
qdialer->uuconf_qproto_params);
}
if (! (*qdaemon->qproto->pfstart) (qdaemon, &zlog))
return FALSE;
if (zlog == NULL)
{
zlog = zbufalc (sizeof "protocol ''" + 1);
sprintf (zlog, "protocol '%c'", qdaemon->qproto->bname);
}
ulog (LOG_NORMAL, "Handshake successful (%s)", zlog);
ubuffree (zlog);
*pterr = STATUS_FAILED;
{
boolean fret;
long iend_time;
fret = floop (qdaemon);
if (fsend_uucp_cmd (qconn, "OOOOOO")
&& fsend_uucp_cmd (qconn, "OOOOOO"))
{
int i, fdone;
for (i = 0; i < 25; i++)
{
zstr = zget_uucp_cmd (qconn, FALSE, fstrip);
if (zstr == NULL)
break;
fdone = strstr (zstr, "OOOOOO") != NULL;
ubuffree (zstr);
if (fdone)
break;
}
}
iend_time = ixsysdep_time ((long *) NULL);
ulog (LOG_NORMAL, "Call complete (%ld seconds %ld bytes %ld bps)",
iend_time - istart_time,
qdaemon->csent + qdaemon->creceived,
(iend_time != istart_time
? (qdaemon->csent + qdaemon->creceived) / (iend_time - istart_time)
: 0));
if (fret)
{
qstat->ttype = STATUS_COMPLETE;
qstat->ilast = iend_time;
(void) fsysdep_set_status (qsys, qstat);
}
if (qdaemon->irunuuxqt == UUCONF_RUNUUXQT_PERCALL
|| (qdaemon->irunuuxqt > 0 && qdaemon->cxfiles_received > 0))
(void) fspawn_uuxqt (TRUE, qdaemon->qsys->uuconf_zname,
qdaemon->zconfig);
return fret;
}
}
static int
iuport_lock (qport, pinfo)
struct uuconf_port *qport;
pointer pinfo;
{
struct spass *q = (struct spass *) pinfo;
q->fmatched = TRUE;
if (! fconn_init (qport, q->qconn, UUCONF_PORTTYPE_UNKNOWN))
return UUCONF_NOT_FOUND;
else if (! fconn_lock (q->qconn, FALSE, FALSE))
{
uconn_free (q->qconn);
return UUCONF_NOT_FOUND;
}
else
{
q->flocked = TRUE;
return UUCONF_SUCCESS;
}
}
struct scallin_info
{
const char *zuser;
const char *zpass;
};
static boolean
flogin_prompt (puuconf, zconfig, fuuxqt, qconn, zlogin, pzsystem)
pointer puuconf;
const char *zconfig;
boolean fuuxqt;
struct sconnection *qconn;
const char *zlogin;
const char **pzsystem;
{
int iuuconf;
int istrip;
boolean fstrip;
char *zuser, *zpass;
boolean fret;
struct scallin_info s;
if (pzsystem != NULL)
*pzsystem = NULL;
DEBUG_MESSAGE0 (DEBUG_HANDSHAKE, "flogin_prompt: Waiting for login");
iuuconf = uuconf_strip (puuconf, &istrip);
if (iuuconf != UUCONF_SUCCESS)
{
ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
return FALSE;
}
fstrip = (istrip & UUCONF_STRIP_LOGIN) != 0;
zuser = NULL;
if (zlogin == NULL)
{
do
{
ubuffree (zuser);
if (! fconn_write (qconn, "login: ", sizeof "login: " - 1))
return FALSE;
zuser = zget_typed_line (qconn, fstrip);
}
while (zuser != NULL && *zuser == '\0');
if (zuser == NULL)
return TRUE;
zlogin = zuser;
}
if (! fconn_write (qconn, "Password:", sizeof "Password:" - 1))
{
ubuffree (zuser);
return FALSE;
}
zpass = zget_typed_line (qconn, fstrip);
if (zpass == NULL)
{
ubuffree (zuser);
return TRUE;
}
fret = TRUE;
s.zuser = zlogin;
s.zpass = zpass;
iuuconf = uuconf_callin (puuconf, icallin_cmp, &s);
ubuffree (zpass);
if (iuuconf == UUCONF_NOT_FOUND)
ulog (LOG_ERROR, "Bad login");
else if (iuuconf != UUCONF_SUCCESS)
{
ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
fret = FALSE;
}
else
{
#if DEBUG > 1
int iholddebug;
#endif
#if DEBUG > 1
iholddebug = iDebug;
#endif
(void) faccept_call (puuconf, zconfig, fuuxqt, zlogin, qconn, pzsystem);
#if DEBUG > 1
iDebug = iholddebug;
#endif
}
ubuffree (zuser);
return fret;
}
static int
icallin_cmp (iwhich, pinfo, zfile)
int iwhich;
pointer pinfo;
const char *zfile;
{
struct scallin_info *qinfo = (struct scallin_info *) pinfo;
char *zcopy;
int icmp;
#if HAVE_ENCRYPTED_PASSWORDS
if (iwhich != 0)
return strcmp (crypt (qinfo->zpass, zfile), zfile) == 0;
#endif
zcopy = zbufcpy (zfile);
(void) cescape (zcopy);
if (iwhich == 0)
icmp = strcmp (qinfo->zuser, zcopy);
else
icmp = strcmp (qinfo->zpass, zcopy);
ubuffree (zcopy);
return icmp == 0;
}
static boolean
faccept_call (puuconf, zconfig, fuuxqt, zlogin, qconn, pzsystem)
pointer puuconf;
const char *zconfig;
boolean fuuxqt;
const char *zlogin;
struct sconnection *qconn;
const char **pzsystem;
{
long istart_time;
int iuuconf;
int istrip;
boolean fstrip;
const char *zport;
struct uuconf_port *qport;
struct uuconf_port sport;
struct uuconf_dialer *qdialer;
struct uuconf_dialer sdialer;
boolean ftcp_port;
char *zsend, *zspace;
boolean fret;
char *zstr;
struct uuconf_system ssys;
const struct uuconf_system *qsys;
const struct uuconf_system *qany;
char *zloc;
struct sstatus sstat;
boolean fgotseq, fgotn;
size_t i;
char *zlog;
char *zgrade;
if (pzsystem != NULL)
*pzsystem = NULL;
ulog (LOG_NORMAL, "Incoming call (login %s port %s)", zlogin,
zLdevice == NULL ? (char *) "unknown" : zLdevice);
istart_time = ixsysdep_time ((long *) NULL);
iuuconf = uuconf_strip (puuconf, &istrip);
if (iuuconf != UUCONF_SUCCESS)
{
ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
uaccept_call_cleanup (puuconf, (struct uuconf_system *) NULL,
(struct uuconf_port *) NULL,
&sport, (char *) NULL);
return FALSE;
}
fstrip = (istrip & UUCONF_STRIP_PROTO) != 0;
if (qconn->qport != NULL)
{
qport = qconn->qport;
zport = qport->uuconf_zname;
ftcp_port = FALSE;
}
else
{
zport = zsysdep_port_name (&ftcp_port);
if (zport == NULL)
{
qport = NULL;
zport = "unknown";
}
else
{
iuuconf = uuconf_find_port (puuconf, zport, (long) 0, (long) 0,
(int (*) P((struct uuconf_port *,
pointer pinfo))) NULL,
(pointer) NULL,
&sport);
if (iuuconf == UUCONF_NOT_FOUND)
qport = NULL;
else if (iuuconf != UUCONF_SUCCESS)
{
ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
uaccept_call_cleanup (puuconf, (struct uuconf_system *) NULL,
(struct uuconf_port *) NULL,
&sport, (char *) NULL);
return FALSE;
}
else
qport = &sport;
}
}
qdialer = NULL;
if (qport != NULL)
{
if (qport->uuconf_ttype == UUCONF_PORTTYPE_MODEM)
{
if (qport->uuconf_u.uuconf_smodem.uuconf_pzdialer != NULL)
{
const char *zdialer;
zdialer = qport->uuconf_u.uuconf_smodem.uuconf_pzdialer[0];
iuuconf = uuconf_dialer_info (puuconf, zdialer, &sdialer);
if (iuuconf == UUCONF_SUCCESS)
qdialer = &sdialer;
}
else
qdialer = qport->uuconf_u.uuconf_smodem.uuconf_qdialer;
}
else if (qport->uuconf_ttype == UUCONF_PORTTYPE_TCP
|| (qport->uuconf_ttype == UUCONF_PORTTYPE_TLI
&& (qport->uuconf_ireliable
& UUCONF_RELIABLE_SPECIFIED) == 0))
ftcp_port = TRUE;
}
sDaemon.puuconf = puuconf;
sDaemon.zconfig = zconfig;
if (! fuuxqt)
sDaemon.irunuuxqt = UUCONF_RUNUUXQT_NEVER;
else
{
iuuconf = uuconf_runuuxqt (puuconf, &sDaemon.irunuuxqt);
if (iuuconf != UUCONF_SUCCESS)
ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
}
sDaemon.qsys = NULL;
sDaemon.zlocalname = NULL;
sDaemon.qconn = qconn;
sDaemon.qproto = NULL;
sDaemon.cchans = 1;
sDaemon.clocal_size = -1;
sDaemon.cremote_size = -1;
sDaemon.cmax_ever = -2;
sDaemon.cmax_receive = -1;
sDaemon.csent = 0;
sDaemon.creceived = 0;
sDaemon.cxfiles_received = 0;
sDaemon.ifeatures = 0;
sDaemon.frequest_hangup = FALSE;
sDaemon.fhangup_requested = FALSE;
sDaemon.fhangup = FALSE;
sDaemon.fmaster = FALSE;
sDaemon.fcaller = FALSE;
sDaemon.ireliable = 0;
sDaemon.bgrade = UUCONF_GRADE_LOW;
iuuconf = uuconf_login_localname (puuconf, zlogin, &zloc);
if (iuuconf == UUCONF_SUCCESS)
sDaemon.zlocalname = zloc;
else if (iuuconf == UUCONF_NOT_FOUND)
{
sDaemon.zlocalname = zsysdep_localname ();
if (sDaemon.zlocalname == NULL)
{
uaccept_call_cleanup (puuconf, (struct uuconf_system *) NULL,
qport, &sport, (char *) NULL);
return FALSE;
}
}
else
{
ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
uaccept_call_cleanup (puuconf, (struct uuconf_system *) NULL,
qport, &sport, (char *) NULL);
return FALSE;
}
zsend = zbufalc (strlen (sDaemon.zlocalname) + sizeof "Shere=");
sprintf (zsend, "Shere=%s", sDaemon.zlocalname);
fret = fsend_uucp_cmd (qconn, zsend);
ubuffree (zsend);
if (! fret)
{
uaccept_call_cleanup (puuconf, (struct uuconf_system *) NULL,
qport, &sport, zloc);
return FALSE;
}
zstr = zget_uucp_cmd (qconn, TRUE, fstrip);
if (zstr == NULL)
{
uaccept_call_cleanup (puuconf, (struct uuconf_system *) NULL,
qport, &sport, zloc);
return FALSE;
}
if (zstr[0] != 'S')
{
ulog (LOG_ERROR, "Bad introduction string");
ubuffree (zstr);
uaccept_call_cleanup (puuconf, (struct uuconf_system *) NULL,
qport, &sport, zloc);
return FALSE;
}
zspace = strchr (zstr, ' ');
if (zspace != NULL)
*zspace = '\0';
iuuconf = uuconf_system_info (puuconf, zstr + 1, &ssys);
if (iuuconf == UUCONF_NOT_FOUND)
{
char *zscript;
iuuconf = uuconf_remote_unknown (puuconf, &zscript);
if (iuuconf == UUCONF_SUCCESS)
{
if (! fsysdep_unknown_caller (zscript, zstr + 1))
{
xfree ((pointer) zscript);
(void) fsend_uucp_cmd (qconn, "RYou are unknown to me");
ubuffree (zstr);
uaccept_call_cleanup (puuconf, (struct uuconf_system *) NULL,
qport, &sport, zloc);
return FALSE;
}
xfree ((pointer) zscript);
}
else if (iuuconf != UUCONF_NOT_FOUND)
{
ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
ubuffree (zstr);
uaccept_call_cleanup (puuconf, (struct uuconf_system *) NULL,
qport, &sport, zloc);
return FALSE;
}
if (! funknown_system (puuconf, zstr + 1, &ssys))
{
(void) fsend_uucp_cmd (qconn, "RYou are unknown to me");
ulog (LOG_ERROR, "Call from unknown system %s", zstr + 1);
ubuffree (zstr);
uaccept_call_cleanup (puuconf, (struct uuconf_system *) NULL,
qport, &sport, zloc);
return FALSE;
}
}
else if (iuuconf != UUCONF_SUCCESS)
{
ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
ubuffree (zstr);
uaccept_call_cleanup (puuconf, (struct uuconf_system *) NULL,
qport, &sport, zloc);
return FALSE;
}
qany = NULL;
for (qsys = &ssys; qsys != NULL; qsys = qsys->uuconf_qalternate)
{
if (! qsys->uuconf_fcalled)
continue;
if (qsys->uuconf_zcalled_login == NULL
|| strcmp (qsys->uuconf_zcalled_login, "ANY") == 0)
{
if (qany == NULL)
qany = qsys;
}
else if (strcmp (qsys->uuconf_zcalled_login, zlogin) == 0)
break;
}
if (qsys == NULL && qany != NULL)
{
iuuconf = uuconf_validate (puuconf, qany, zlogin);
if (iuuconf == UUCONF_SUCCESS)
qsys = qany;
else if (iuuconf != UUCONF_NOT_FOUND)
{
ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
ubuffree (zstr);
uaccept_call_cleanup (puuconf, &ssys, qport, &sport, zloc);
return FALSE;
}
}
if (qsys == NULL)
{
(void) fsend_uucp_cmd (qconn, "RLOGIN");
ulog (LOG_ERROR, "System %s used wrong login name %s",
zstr + 1, zlogin);
ubuffree (zstr);
uaccept_call_cleanup (puuconf, &ssys, qport, &sport, zloc);
return FALSE;
}
sDaemon.qsys = qsys;
if (pzsystem != NULL)
*pzsystem = zbufcpy (qsys->uuconf_zname);
ulog_system (qsys->uuconf_zname);
#if DEBUG > 1
if (qsys->uuconf_zdebug != NULL)
iDebug |= idebug_parse (qsys->uuconf_zdebug);
#endif
if (qsys->uuconf_fcallback)
{
(void) fsend_uucp_cmd (qconn, "RCB");
ulog (LOG_NORMAL, "Will call back");
sstat.ttype = STATUS_COMPLETE;
sstat.cretries = 0;
sstat.ilast = ixsysdep_time ((long *) NULL);
sstat.cwait = 0;
(void) fsysdep_set_status (qsys, &sstat);
ubuffree (zsysdep_spool_commands (qsys, UUCONF_GRADE_HIGH, 0,
(const struct scmd *) NULL,
(boolean *) NULL));
ubuffree (zstr);
uaccept_call_cleanup (puuconf, &ssys, qport, &sport, zloc);
return TRUE;
}
if (! fsysdep_lock_system (qsys))
{
if (qsys->uuconf_fsequence)
{
(void) ixsysdep_get_sequence (qsys);
}
(void) fsend_uucp_cmd (qconn, "RLCK");
ulog (LOG_ERROR, "System already locked");
ubuffree (zstr);
uaccept_call_cleanup (puuconf, &ssys, qport, &sport, zloc);
return FALSE;
}
sLocked_system = *qsys;
fLocked_system = TRUE;
sstat.ttype = STATUS_TALKING;
sstat.cretries = 0;
sstat.ilast = ixsysdep_time ((long *) NULL);
sstat.cwait = 0;
(void) fsysdep_set_status (qsys, &sstat);
fgotseq = FALSE;
fgotn = FALSE;
if (zspace != NULL)
{
char **paz;
char **pzset;
++zspace;
paz = (char **) xmalloc ((strlen (zspace) / 2 + 2) * sizeof (char *));
pzset = paz;
*pzset++ = NULL;
while (TRUE)
{
while (*zspace != '\0' && isspace (BUCHAR (*zspace)))
++zspace;
if (*zspace == '\0')
break;
*pzset++ = zspace;
++zspace;
while (*zspace != '\0' && ! isspace (BUCHAR (*zspace)))
++zspace;
if (*zspace == '\0')
break;
*zspace++ = '\0';
}
if (pzset != paz + 1)
{
int iopt;
*pzset = NULL;
optind = 0;
opterr = 0;
while ((iopt = getopt (pzset - paz, paz,
"N::p:Q:RU:v:x:")) != EOF)
{
long iseq;
long c;
char b;
int iwant;
switch (iopt)
{
case 'N':
fgotn = TRUE;
if (optarg == NULL)
sDaemon.ifeatures |= FEATURE_SIZES | FEATURE_V103;
else
sDaemon.ifeatures |= (int) strtol (optarg,
(char **) NULL,
0);
break;
case 'p':
if (UUCONF_GRADE_LEGAL (optarg[0]))
sDaemon.bgrade = optarg[0];
break;
case 'Q':
iseq = strtol (optarg, (char **) NULL, 10);
if (qsys->uuconf_fsequence
&& iseq != ixsysdep_get_sequence (qsys))
{
(void) fsend_uucp_cmd (qconn, "RBADSEQ");
ulog (LOG_ERROR, "Out of sequence call rejected");
sstat.ttype = STATUS_FAILED;
(void) fsysdep_set_status (qsys, &sstat);
xfree ((pointer) paz);
ubuffree (zstr);
uaccept_call_cleanup (puuconf, &ssys, qport, &sport,
zloc);
return FALSE;
}
fgotseq = TRUE;
break;
case 'R':
sDaemon.ifeatures |= FEATURE_RESTART;
break;
case 'U':
c = strtol (optarg, (char **) NULL, 0);
if (c > 0 && c < LONG_MAX / (long) 512)
sDaemon.cmax_receive = c * (long) 512;
break;
case 'v':
if (strncmp (optarg, "grade=", sizeof "grade=" - 1) == 0)
{
b = optarg[sizeof "grade=" - 1];
if (UUCONF_GRADE_LEGAL (b))
sDaemon.bgrade = b;
}
break;
case 'x':
iwant = (int) strtol (optarg, (char **) NULL, 10);
#if DEBUG > 1
if (iwant <= 9)
iwant = (1 << iwant) - 1;
if (qsys->uuconf_zmax_remote_debug != NULL)
iwant &= idebug_parse (qsys->uuconf_zmax_remote_debug);
else
iwant &= DEBUG_ABNORMAL | DEBUG_CHAT | DEBUG_HANDSHAKE;
if ((iDebug | iwant) != iDebug)
{
iDebug |= iwant;
ulog (LOG_NORMAL, "Setting debugging mode to 0%o",
iDebug);
}
#endif
break;
default:
break;
}
}
}
xfree ((pointer) paz);
}
ubuffree (zstr);
if (qsys->uuconf_fsequence && ! fgotseq)
{
(void) fsend_uucp_cmd (qconn, "RBADSEQ");
ulog (LOG_ERROR, "No sequence number (call rejected)");
sstat.ttype = STATUS_FAILED;
(void) fsysdep_set_status (qsys, &sstat);
uaccept_call_cleanup (puuconf, &ssys, qport, &sport, zloc);
return FALSE;
}
{
char ab[20];
const char *zreply;
if (! fgotn)
{
if ((sDaemon.ifeatures & FEATURE_RESTART) == 0)
zreply = "ROK";
else
{
sDaemon.ifeatures |= FEATURE_SVR4 | FEATURE_SIZES;
zreply = "ROK -R";
}
}
else if ((sDaemon.ifeatures & FEATURE_V103) != 0)
zreply = "ROKN";
else
{
sprintf (ab, "ROKN0%o",
(unsigned int) (FEATURE_SIZES
| FEATURE_EXEC
| FEATURE_RESTART
| FEATURE_QUOTES));
zreply = ab;
}
if (! fsend_uucp_cmd (qconn, zreply))
{
sstat.ttype = STATUS_FAILED;
(void) fsysdep_set_status (qsys, &sstat);
uaccept_call_cleanup (puuconf, &ssys, qport, &sport, zloc);
return FALSE;
}
}
if (ftcp_port)
sDaemon.ireliable = (UUCONF_RELIABLE_SPECIFIED
| UUCONF_RELIABLE_ENDTOEND
| UUCONF_RELIABLE_RELIABLE
| UUCONF_RELIABLE_EIGHT
| UUCONF_RELIABLE_FULLDUPLEX);
else
{
if (qport != NULL
&& (qport->uuconf_ireliable & UUCONF_RELIABLE_SPECIFIED) != 0)
sDaemon.ireliable = qport->uuconf_ireliable;
if (qdialer != NULL
&& (qdialer->uuconf_ireliable & UUCONF_RELIABLE_SPECIFIED) != 0)
{
if (sDaemon.ireliable != 0)
sDaemon.ireliable &= qdialer->uuconf_ireliable;
else
sDaemon.ireliable = qdialer->uuconf_ireliable;
}
if (sDaemon.ireliable == 0)
sDaemon.ireliable = (UUCONF_RELIABLE_RELIABLE
| UUCONF_RELIABLE_EIGHT
| UUCONF_RELIABLE_FULLDUPLEX
| UUCONF_RELIABLE_SPECIFIED);
}
if (qsys->uuconf_zprotocols != NULL ||
(qport != NULL && qport->uuconf_zprotocols != NULL))
{
const char *zprotos;
if (qsys->uuconf_zprotocols != NULL)
zprotos = qsys->uuconf_zprotocols;
else
zprotos = qport->uuconf_zprotocols;
zsend = zbufalc (strlen (zprotos) + 2);
sprintf (zsend, "P%s", zprotos);
}
else
{
char *zset;
zsend = zbufalc (CPROTOCOLS + 2);
zset = zsend;
*zset++ = 'P';
for (i = 0; i < CPROTOCOLS; i++)
{
int ipr;
ipr = asProtocols[i].ireliable;
if ((ipr & sDaemon.ireliable) != ipr)
continue;
*zset++ = asProtocols[i].bname;
}
*zset = '\0';
}
fret = fsend_uucp_cmd (qconn, zsend);
ubuffree (zsend);
if (! fret)
{
sstat.ttype = STATUS_FAILED;
(void) fsysdep_set_status (qsys, &sstat);
uaccept_call_cleanup (puuconf, &ssys, qport, &sport, zloc);
return FALSE;
}
zstr = zget_uucp_cmd (qconn, TRUE, fstrip);
if (zstr == NULL)
{
sstat.ttype = STATUS_FAILED;
(void) fsysdep_set_status (qsys, &sstat);
uaccept_call_cleanup (puuconf, &ssys, qport, &sport, zloc);
return FALSE;
}
if (zstr[0] != 'U')
{
ulog (LOG_ERROR, "Bad protocol response string");
sstat.ttype = STATUS_FAILED;
(void) fsysdep_set_status (qsys, &sstat);
ubuffree (zstr);
uaccept_call_cleanup (puuconf, &ssys, qport, &sport, zloc);
return FALSE;
}
if (zstr[1] == 'N')
{
ulog (LOG_ERROR, "No supported protocol");
sstat.ttype = STATUS_FAILED;
(void) fsysdep_set_status (qsys, &sstat);
ubuffree (zstr);
uaccept_call_cleanup (puuconf, &ssys, qport, &sport, zloc);
return FALSE;
}
for (i = 0; i < CPROTOCOLS; i++)
if (asProtocols[i].bname == zstr[1])
break;
ubuffree (zstr);
if (i >= CPROTOCOLS)
{
ulog (LOG_ERROR, "No supported protocol");
sstat.ttype = STATUS_FAILED;
(void) fsysdep_set_status (qsys, &sstat);
uaccept_call_cleanup (puuconf, &ssys, qport, &sport, zloc);
return FALSE;
}
sDaemon.qproto = &asProtocols[i];
if ((sDaemon.ireliable & UUCONF_RELIABLE_FULLDUPLEX) == 0)
sDaemon.cchans = 1;
else
sDaemon.cchans = asProtocols[i].cchans;
if (! fchat (qconn, puuconf, &qsys->uuconf_scalled_chat, qsys,
(const struct uuconf_dialer *) NULL, (const char *) NULL,
FALSE, zport, iconn_baud (qconn)))
{
sstat.ttype = STATUS_FAILED;
sstat.ilast = ixsysdep_time ((long *) NULL);
(void) fsysdep_set_status (qsys, &sstat);
uaccept_call_cleanup (puuconf, &ssys, qport, &sport, zloc);
return FALSE;
}
if (sDaemon.qproto->qcmds != NULL)
{
if (qsys->uuconf_qproto_params != NULL)
uapply_proto_params (puuconf, sDaemon.qproto->bname,
sDaemon.qproto->qcmds,
qsys->uuconf_qproto_params);
if (qport != NULL
&& qport->uuconf_qproto_params != NULL)
uapply_proto_params (puuconf, sDaemon.qproto->bname,
sDaemon.qproto->qcmds,
qport->uuconf_qproto_params);
if (qdialer != NULL
&& qdialer->uuconf_qproto_params != NULL)
uapply_proto_params (puuconf, sDaemon.qproto->bname,
sDaemon.qproto->qcmds,
qdialer->uuconf_qproto_params);
}
if (qdialer == &sdialer)
(void) uuconf_dialer_free (puuconf, &sdialer);
if (! (*sDaemon.qproto->pfstart) (&sDaemon, &zlog)
|| ! fqueue (&sDaemon, (boolean *) NULL))
{
uclear_queue (&sDaemon);
sstat.ttype = STATUS_FAILED;
sstat.ilast = ixsysdep_time ((long *) NULL);
(void) fsysdep_set_status (qsys, &sstat);
uaccept_call_cleanup (puuconf, &ssys, qport, &sport, zloc);
return FALSE;
}
if (zlog == NULL)
{
zlog = zbufalc (sizeof "protocol ''" + 1);
sprintf (zlog, "protocol '%c'", sDaemon.qproto->bname);
}
zgrade = zbufalc (sizeof "grade " + 1);
if (sDaemon.bgrade == UUCONF_GRADE_LOW)
*zgrade = '\0';
else
sprintf (zgrade, "grade %c ", sDaemon.bgrade);
#if HAVE_HDB_LOGGING
ulog (LOG_NORMAL, "Handshake successful (login %s port %s %s%s)",
zlogin,
zLdevice == NULL ? "unknown" : zLdevice,
zgrade, zlog);
#else
ulog (LOG_NORMAL, "Handshake successful (%s%s)", zgrade, zlog);
#endif
ubuffree (zlog);
ubuffree (zgrade);
{
long iend_time;
fret = floop (&sDaemon);
if (fsend_uucp_cmd (qconn, "OOOOOOO")
&& fsend_uucp_cmd (qconn, "OOOOOOO"))
{
int fdone;
for (i = 0; i < 25; i++)
{
zstr = zget_uucp_cmd (qconn, FALSE, fstrip);
if (zstr == NULL)
break;
fdone = strstr (zstr, "OOOOOO") != NULL;
ubuffree (zstr);
if (fdone)
break;
}
}
iend_time = ixsysdep_time ((long *) NULL);
ulog (LOG_NORMAL, "Call complete (%ld seconds %ld bytes %ld bps)",
iend_time - istart_time,
sDaemon.csent + sDaemon.creceived,
(iend_time != istart_time
? (sDaemon.csent + sDaemon.creceived) / (iend_time - istart_time)
: 0));
uclear_queue (&sDaemon);
if (fret)
sstat.ttype = STATUS_COMPLETE;
else
sstat.ttype = STATUS_FAILED;
sstat.ilast = iend_time;
(void) fsysdep_set_status (qsys, &sstat);
if (sDaemon.irunuuxqt == UUCONF_RUNUUXQT_PERCALL
|| (sDaemon.irunuuxqt > 0 && sDaemon.cxfiles_received > 0))
(void) fspawn_uuxqt (TRUE, qsys->uuconf_zname, zconfig);
uaccept_call_cleanup (puuconf, &ssys, qport, &sport, zloc);
return fret;
}
}
static void
uaccept_call_cleanup (puuconf, qfreesys, qport, qfreeport, zloc)
pointer puuconf ATTRIBUTE_UNUSED;
struct uuconf_system *qfreesys;
struct uuconf_port *qport;
struct uuconf_port *qfreeport;
char *zloc;
{
if (fLocked_system)
{
(void) fsysdep_unlock_system (&sLocked_system);
fLocked_system = FALSE;
}
if (qfreesys != NULL)
(void) uuconf_system_free (puuconf, qfreesys);
if (qport == qfreeport)
(void) uuconf_port_free (puuconf, qfreeport);
xfree ((pointer) zloc);
ulog_system ((const char *) NULL);
}
static void
uapply_proto_params (puuconf, bproto, qcmds, pas)
pointer puuconf;
int bproto;
struct uuconf_cmdtab *qcmds;
struct uuconf_proto_param *pas;
{
struct uuconf_proto_param *qp;
for (qp = pas; qp->uuconf_bproto != '\0'; qp++)
{
if (qp->uuconf_bproto == bproto)
{
struct uuconf_proto_param_entry *qe;
for (qe = qp->uuconf_qentries; qe->uuconf_cargs > 0; qe++)
{
int iuuconf;
iuuconf = uuconf_cmd_args (puuconf, qe->uuconf_cargs,
qe->uuconf_pzargs, qcmds,
(pointer) NULL,
(uuconf_cmdtabfn) NULL, 0,
(pointer) NULL);
if (UUCONF_ERROR_VALUE (iuuconf) != UUCONF_SUCCESS)
{
ulog (LOG_ERROR, "Error in %c protocol parameters",
bproto);
ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
}
}
break;
}
}
}
static boolean
fsend_uucp_cmd (qconn, z)
struct sconnection *qconn;
const char *z;
{
size_t cwrite;
char *zalc;
boolean fret;
DEBUG_MESSAGE1 (DEBUG_HANDSHAKE, "fsend_uucp_cmd: Sending \"%s\"", z);
cwrite = strlen (z) + 2;
zalc = zbufalc (cwrite);
zalc[0] = '\020';
memcpy (zalc + 1, z, cwrite - 1);
fret = fconn_write (qconn, zalc, cwrite);
ubuffree (zalc);
return fret;
}
#define CTIMEOUT (120)
#define CSHORTTIMEOUT (10)
#define CINCREMENT (100)
static char *
zget_uucp_cmd (qconn, frequired, fstrip)
struct sconnection *qconn;
boolean frequired;
boolean fstrip;
{
char *zalc;
size_t calc;
size_t cgot;
boolean fintro;
long iendtime;
int ctimeout;
#if DEBUG > 1
int cchars;
int iolddebug;
#endif
iendtime = ixsysdep_time ((long *) NULL);
if (frequired)
iendtime += CTIMEOUT;
else
iendtime += CSHORTTIMEOUT;
#if DEBUG > 1
cchars = 0;
iolddebug = iDebug;
if (FDEBUGGING (DEBUG_HANDSHAKE))
{
ulog (LOG_DEBUG_START, "zget_uucp_cmd: Got \"");
iDebug &=~ (DEBUG_INCOMING | DEBUG_PORT);
}
#endif
zalc = NULL;
calc = 0;
cgot = 0;
fintro = FALSE;
while ((ctimeout = (int) (iendtime - ixsysdep_time ((long *) NULL))) > 0)
{
int b;
b = breceive_char (qconn, ctimeout, frequired);
if (b < 0)
{
#if DEBUG > 1
if (FDEBUGGING (DEBUG_HANDSHAKE))
{
ulog (LOG_DEBUG_END, "\" (%s)",
b == -1 ? "timeout" : "error");
iDebug = iolddebug;
}
#endif
if (b == -1 && frequired)
ulog (LOG_ERROR, "Timeout");
ubuffree (zalc);
return NULL;
}
if (fstrip)
b &= 0x7f;
#if DEBUG > 1
if (FDEBUGGING (DEBUG_HANDSHAKE))
{
char ab[5];
++cchars;
if (cchars > 60)
{
ulog (LOG_DEBUG_END, "\"");
ulog (LOG_DEBUG_START, "zget_uucp_cmd: Got \"");
cchars = 0;
}
(void) cdebug_char (ab, b);
ulog (LOG_DEBUG_CONTINUE, "%s", ab);
}
#endif
if (! fintro)
{
if (b == '\020')
fintro = TRUE;
continue;
}
if (b == '\020')
{
cgot = 0;
continue;
}
if (b == '\r' || b == '\n')
b = '\0';
if (cgot >= calc)
{
char *znew;
calc += CINCREMENT;
znew = zbufalc (calc);
if (cgot > 0)
memcpy (znew, zalc, cgot);
ubuffree (zalc);
zalc = znew;
}
zalc[cgot] = (char) b;
++cgot;
if (b == '\0')
{
#if DEBUG > 1
if (FDEBUGGING (DEBUG_HANDSHAKE))
{
ulog (LOG_DEBUG_END, "\"");
iDebug = iolddebug;
}
#endif
return zalc;
}
}
#if DEBUG > 1
if (FDEBUGGING (DEBUG_HANDSHAKE))
{
ulog (LOG_DEBUG_END, "\" (timeout)");
iDebug = iolddebug;
}
#endif
ubuffree (zalc);
if (frequired)
ulog (LOG_ERROR, "Timeout");
return NULL;
}
static char *
zget_typed_line (qconn, fstrip)
struct sconnection *qconn;
boolean fstrip;
{
static boolean flastcr;
char *zalc;
size_t calc;
size_t cgot;
#if DEBUG > 1
int cchars;
int iolddebug;
cchars = 0;
iolddebug = iDebug;
if (FDEBUGGING (DEBUG_CHAT))
{
ulog (LOG_DEBUG_START, "zget_typed_line: Got \"");
iDebug &=~ (DEBUG_INCOMING | DEBUG_PORT);
}
#endif
zalc = NULL;
calc = 0;
cgot = 0;
while (TRUE)
{
int b;
b = breceive_char (qconn, CTIMEOUT, FALSE);
if (b == -2 || FGOT_SIGNAL ())
{
#if DEBUG > 1
if (FDEBUGGING (DEBUG_CHAT))
{
ulog (LOG_DEBUG_END, "\" (error)");
iDebug = iolddebug;
}
#endif
ubuffree (zalc);
flastcr = FALSE;
return NULL;
}
if (b == -1)
{
flastcr = FALSE;
continue;
}
if (fstrip)
b &= 0x7f;
#if DEBUG > 1
if (FDEBUGGING (DEBUG_CHAT))
{
char ab[5];
++cchars;
if (cchars > 60)
{
ulog (LOG_DEBUG_END, "\"");
ulog (LOG_DEBUG_START, "zget_typed_line: Got \"");
cchars = 0;
}
(void) cdebug_char (ab, b);
ulog (LOG_DEBUG_CONTINUE, "%s", ab);
}
#endif
if (b == '\n' && cgot == 0 && flastcr)
{
flastcr = FALSE;
continue;
}
flastcr = FALSE;
if (cgot >= calc)
{
char *znew;
calc += CINCREMENT;
znew = zbufalc (calc);
if (cgot > 0)
memcpy (znew, zalc, cgot);
ubuffree (zalc);
zalc = znew;
}
if (b == '\n')
b = '\0';
else if (b == '\r')
{
flastcr = TRUE;
b = '\0';
}
zalc[cgot] = (char) b;
++cgot;
if (b == '\0')
{
#if DEBUG > 1
if (FDEBUGGING (DEBUG_CHAT))
{
ulog (LOG_DEBUG_END, "\"");
iDebug = iolddebug;
}
#endif
return zalc;
}
}
}
boolean
fspawn_uuxqt (ffork, zsys, zconfig)
boolean ffork;
const char *zsys ATTRIBUTE_UNUSED;
const char *zconfig;
{
char *zconfigarg;
boolean fret;
if (zconfig == NULL)
zconfigarg = NULL;
else
{
zconfigarg = zbufalc (sizeof "-I" + strlen (zconfig));
sprintf (zconfigarg, "-I%s", zconfig);
}
fret = fsysdep_run (ffork, "uuxqt", zconfigarg, (const char *) NULL);
ubuffree (zconfigarg);
return fret;
}