1045 lines
24 KiB
C
1045 lines
24 KiB
C
/* config.c
|
||
Read the configuration file.
|
||
|
||
Copyright (C) 1991, 1992 Ian Lance Taylor
|
||
|
||
This file is part of the Taylor UUCP package.
|
||
|
||
This program is free software; you can redistribute it and/or
|
||
modify it under the terms of the GNU General Public License as
|
||
published by the Free Software Foundation; either version 2 of the
|
||
License, or (at your option) any later version.
|
||
|
||
This program is distributed in the hope that it will be useful, but
|
||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
General Public License for more details.
|
||
|
||
You should have received a copy of the GNU General Public License
|
||
along with this program; if not, write to the Free Software
|
||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||
|
||
The author of the program may be contacted at ian@airs.com or
|
||
c/o AIRS, P.O. Box 520, Waltham, MA 02254.
|
||
|
||
$Log: config.c,v $
|
||
Revision 1.1.1.1 1993/03/21 09:45:37 cgd
|
||
initial import of 386bsd-0.1 sources
|
||
|
||
Revision 1.29 1992/03/28 22:06:38 ian
|
||
Michael I Bushnell: renamed enum tstatus to avoid header file conflict
|
||
|
||
Revision 1.28 1992/03/28 21:47:55 ian
|
||
David J. MacKenzie: allow backslash to quote newline in config files
|
||
|
||
Revision 1.27 1992/03/28 04:26:12 ian
|
||
David J. MacKenzie: cMaxuuxqts is independent of HAVE_TAYLOR_CONFIG
|
||
|
||
Revision 1.26 1992/03/18 23:12:37 ian
|
||
Handle CMDTABTYPE_FULLSTRING correctly if there are no arguments
|
||
|
||
Revision 1.25 1992/03/17 01:03:03 ian
|
||
Miscellaneous cleanup
|
||
|
||
Revision 1.24 1992/03/12 19:54:43 ian
|
||
Debugging based on types rather than number
|
||
|
||
Revision 1.23 1992/03/11 22:06:37 ian
|
||
Marty Shannon: added max-uuxqts command
|
||
|
||
Revision 1.22 1992/03/09 05:08:16 ian
|
||
Added status for wrong time to call, not used if system can't be called
|
||
|
||
Revision 1.21 1992/03/04 21:39:04 ian
|
||
Local variables in igradecmp have to be integers
|
||
|
||
Revision 1.20 1992/03/03 06:06:48 ian
|
||
T. William Wells: don't complain about missing configuration files
|
||
|
||
Revision 1.19 1992/02/29 01:06:59 ian
|
||
Chip Salzenberg: recheck file permissions before sending
|
||
|
||
Revision 1.18 1992/02/24 04:58:47 ian
|
||
Only permit files to be received into directories that are world-writeable
|
||
|
||
Revision 1.17 1992/02/08 03:54:18 ian
|
||
Include <string.h> only in <uucp.h>, added 1992 copyright
|
||
|
||
Revision 1.16 1992/01/15 07:06:29 ian
|
||
Set configuration directory in Makefile rather than sysdep.h
|
||
|
||
Revision 1.15 1992/01/14 04:04:17 ian
|
||
Chip Salzenberg: strcmp is a macro on AIX
|
||
|
||
Revision 1.14 1991/12/29 04:04:18 ian
|
||
Added a bunch of extern definitions
|
||
|
||
Revision 1.13 1991/12/29 01:54:46 ian
|
||
Terry Gardner: allow a # character to be quoted in a configuration file
|
||
|
||
Revision 1.12 1991/12/22 20:57:57 ian
|
||
Added externs for strcasecmp or strncasecmp
|
||
|
||
Revision 1.11 1991/12/18 03:54:14 ian
|
||
Made error messages to terminal appear more normal
|
||
|
||
Revision 1.10 1991/12/15 03:42:33 ian
|
||
Added tprocess_chat_cmd for all chat commands, and added CMDTABTYPE_PREFIX
|
||
|
||
Revision 1.9 1991/12/13 22:43:06 ian
|
||
Don't continually allocate and free the list of arguments
|
||
|
||
Revision 1.8 1991/12/09 18:39:46 ian
|
||
Richard Todd: the pushed back line is specific to a particular multi file
|
||
|
||
Revision 1.7 1991/12/09 16:59:48 ian
|
||
Richard Todd: don't warn if special "#" command is unrecognized
|
||
|
||
Revision 1.6 1991/12/07 18:05:20 ian
|
||
Franc,ois Pinard: no limit to number of arguments
|
||
|
||
Revision 1.5 1991/12/03 02:38:26 ian
|
||
Don't treat numbers with leading zeroes as octal
|
||
|
||
Revision 1.4 1991/12/01 19:35:38 ian
|
||
David Nugent: read V2 and BNU files by default even with TAYLOR_CONFIG
|
||
|
||
Revision 1.3 1991/11/26 02:04:49 ian
|
||
Bob Denny: add explicit extern for strcmp and strcasecmp
|
||
|
||
Revision 1.2 1991/09/19 02:38:21 ian
|
||
Chip Salzenberg: V2 and BNU dialcodes files are relative to CONFIGLIB
|
||
|
||
Revision 1.1 1991/09/10 19:38:34 ian
|
||
Initial revision
|
||
|
||
*/
|
||
|
||
#include "uucp.h"
|
||
|
||
#if USE_RCS_ID
|
||
char config_rcsid[] = "$Id: config.c,v 1.1.1.1 1993/03/21 09:45:37 cgd Exp $";
|
||
#endif
|
||
|
||
#include <ctype.h>
|
||
#include <errno.h>
|
||
|
||
#include "system.h"
|
||
#include "sysdep.h"
|
||
|
||
/* Some systems make strcmp a macro, which screws us up since we want
|
||
to declare it since we will take its address later. */
|
||
#undef strcmp
|
||
#undef strncmp
|
||
|
||
/* External functions. */
|
||
extern int strcmp (), strncmp (), strcasecmp (), strncasecmp ();
|
||
extern int fclose ();
|
||
|
||
/* Local functions. */
|
||
|
||
static void umulti_pushback P((struct smulti_file *, char *));
|
||
|
||
/* Status strings. These must match enum tstatus_type. */
|
||
|
||
const char *azStatus[] =
|
||
{
|
||
"Conversation complete",
|
||
"Port unavailable",
|
||
"Dial failed",
|
||
"Login failed",
|
||
"Handshake failed",
|
||
"Call failed",
|
||
"Talking",
|
||
"Wrong time to call"
|
||
};
|
||
|
||
/* Local node name. */
|
||
const char *zLocalname;
|
||
|
||
/* Spool directory. */
|
||
const char *zSpooldir = SPOOLDIR;
|
||
|
||
#if DEBUG > 1
|
||
/* Debugging level. */
|
||
int iDebug = 0;
|
||
|
||
/* Debugging file name. */
|
||
const char *zDebugfile = DEBUGFILE;
|
||
#endif
|
||
|
||
/* Public directory. */
|
||
const char *zPubdir = PUBDIR;
|
||
|
||
/* Log file name. */
|
||
const char *zLogfile = LOGFILE;
|
||
|
||
/* Statistics file name. */
|
||
const char *zStatfile = STATFILE;
|
||
|
||
/* Dialcode file names. */
|
||
char *zDialcodefile;
|
||
|
||
/* The maximum number of uuxqt processes which may be running at one
|
||
time. If this is zero, there is no limit. */
|
||
int cMaxuuxqts;
|
||
|
||
#if HAVE_TAYLOR_CONFIG
|
||
|
||
/* System file names. */
|
||
char *zSysfile;
|
||
|
||
/* Port file names. */
|
||
char *zPortfile;
|
||
|
||
/* Dialer file names. */
|
||
char *zDialfile;
|
||
|
||
/* Call out login and password file names. */
|
||
char *zCallfile;
|
||
|
||
/* Call in login and password file names. */
|
||
char *zPwdfile;
|
||
|
||
/* Command table used to parse the configuration file. */
|
||
|
||
static enum tcmdtabret tcadd P((int argc, char **argv, pointer pvar,
|
||
const char *zerr));
|
||
|
||
const struct scmdtab asCmds[] =
|
||
{
|
||
/* System name. */
|
||
{ "nodename", CMDTABTYPE_STRING, (pointer) &zLocalname, NULL },
|
||
{ "hostname", CMDTABTYPE_STRING, (pointer) &zLocalname, NULL },
|
||
{ "uuname", CMDTABTYPE_STRING, (pointer) &zLocalname, NULL },
|
||
/* Spool directory. */
|
||
{ "spool", CMDTABTYPE_STRING, (pointer) &zSpooldir, NULL },
|
||
/* System information files. */
|
||
{ "sysfile", CMDTABTYPE_FN | 0, (pointer) &zSysfile, tcadd },
|
||
/* Port files. */
|
||
{ "portfile", CMDTABTYPE_FN | 0, (pointer) &zPortfile, tcadd },
|
||
/* Dial files. */
|
||
{ "dialfile", CMDTABTYPE_FN | 0, (pointer) &zDialfile, tcadd },
|
||
/* Dialcode files. */
|
||
{ "dialcodefile", CMDTABTYPE_FN | 0, (pointer) &zDialcodefile, tcadd },
|
||
/* Public directory. */
|
||
{ "pubdir", CMDTABTYPE_STRING, (pointer) &zPubdir, NULL },
|
||
/* Call out login name and password files. */
|
||
{ "callfile", CMDTABTYPE_FN | 0, (pointer) &zCallfile, tcadd },
|
||
/* Call in login name and password files. */
|
||
{ "passwdfile", CMDTABTYPE_FN | 0, (pointer) &zPwdfile, tcadd },
|
||
/* Log file. */
|
||
{ "logfile", CMDTABTYPE_STRING, (pointer) &zLogfile, NULL },
|
||
/* Statistics file. */
|
||
{ "statfile", CMDTABTYPE_STRING, (pointer) &zStatfile, NULL },
|
||
#if DEBUG > 1
|
||
/* Debugging file. */
|
||
{ "debugfile", CMDTABTYPE_STRING, (pointer) &zDebugfile, NULL },
|
||
/* Debugging level. */
|
||
{ "debug", CMDTABTYPE_FN | 0, (pointer) &iDebug, tidebug_parse },
|
||
#endif
|
||
/* Command for unknown system. */
|
||
{ "unknown", CMDTABTYPE_FN, NULL, tiunknown },
|
||
/* Maximum number of uuxqt processes. */
|
||
{ "max-uuxqts", CMDTABTYPE_INT, (pointer) &cMaxuuxqts, NULL },
|
||
#if HAVE_V2_CONFIG
|
||
{ "v2-files", CMDTABTYPE_BOOLEAN, (pointer) &fV2, NULL },
|
||
#endif
|
||
#if HAVE_BNU_CONFIG
|
||
{ "bnu-files", CMDTABTYPE_BOOLEAN, (pointer) &fBnu, NULL },
|
||
#endif
|
||
/* End marker. */
|
||
{ NULL, 0, NULL, NULL }
|
||
};
|
||
|
||
/* Add strings to a string variable, separating with spaces. */
|
||
|
||
/*ARGSUSED*/
|
||
static enum tcmdtabret
|
||
tcadd (argc, argv, pvar, zerr)
|
||
int argc;
|
||
char **argv;
|
||
pointer pvar;
|
||
const char *zerr;
|
||
{
|
||
int i;
|
||
|
||
for (i = 1; i < argc; i++)
|
||
uadd_string ((char **) pvar, argv[i], ' ');
|
||
return CMDTABRET_FREE;
|
||
}
|
||
|
||
#endif /* HAVE_TAYLOR_CONFIG */
|
||
|
||
/* Process commands from a stdio file according to a command table.
|
||
The character '#' introduces a comment. Exactly one of e and
|
||
qmulti must be NULL. If we get the first line of a multi file, we
|
||
attempt to process the command "#"; this command will not arise
|
||
from a normal command file, and lets the caller take special action
|
||
at the start of a new file. If we are reading with zmulti_gets, we
|
||
ignore the zerr argument and instead use the name of the file. */
|
||
|
||
void
|
||
uprocesscmds (e, qmulti, qcmds, zerr, iflags)
|
||
FILE *e;
|
||
struct smulti_file *qmulti;
|
||
const struct scmdtab *qcmds;
|
||
const char *zerr;
|
||
int iflags;
|
||
{
|
||
while (TRUE)
|
||
{
|
||
static char **pzargs;
|
||
static int calloc_args;
|
||
char *zget, *z;
|
||
int cargs;
|
||
enum tcmdtabret t;
|
||
char **pzhold_args;
|
||
int chold_alloc_args;
|
||
|
||
if (e != NULL)
|
||
zget = zfgets (e, (iflags & CMDFLAG_BACKSLASH) != 0);
|
||
else
|
||
{
|
||
boolean ffirst;
|
||
|
||
zget = zmulti_gets (qmulti, &ffirst, &zerr,
|
||
(iflags & CMDFLAG_BACKSLASH) != 0);
|
||
if (zget != NULL && ffirst)
|
||
{
|
||
char *zargs;
|
||
|
||
zargs = (char *) "#";
|
||
t = tprocess_one_cmd (1, &zargs, qcmds, zerr,
|
||
iflags &~ CMDFLAG_WARNUNRECOG);
|
||
if (t == CMDTABRET_EXIT || t == CMDTABRET_FREE_AND_EXIT)
|
||
{
|
||
umulti_pushback (qmulti, zget);
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (zget == NULL)
|
||
return;
|
||
|
||
/* Any # character not preceeded by a backslash starts a
|
||
comment. */
|
||
z = zget;
|
||
while ((z = strchr (z, '#')) != NULL)
|
||
{
|
||
if (z == zget || *(z - 1) != '\\')
|
||
{
|
||
*z = '\0';
|
||
break;
|
||
}
|
||
/* Remove the backslash. */
|
||
xmemmove (z - 1, z, strlen (z) + 1);
|
||
}
|
||
|
||
z = zget;
|
||
cargs = 0;
|
||
while (TRUE)
|
||
{
|
||
while (*z != '\0' && isspace (BUCHAR (*z)))
|
||
z++;
|
||
|
||
if (*z == '\0')
|
||
break;
|
||
|
||
if (cargs >= calloc_args)
|
||
{
|
||
calloc_args += 10;
|
||
pzargs = (char **) xrealloc ((pointer) pzargs,
|
||
calloc_args * sizeof (char *));
|
||
}
|
||
|
||
pzargs[cargs] = z;
|
||
++cargs;
|
||
|
||
while (*z != '\0' && ! isspace (BUCHAR (*z)))
|
||
z++;
|
||
|
||
if (*z == '\0')
|
||
break;
|
||
|
||
*z++ = '\0';
|
||
}
|
||
|
||
if (cargs <= 0)
|
||
{
|
||
xfree ((pointer) zget);
|
||
continue;
|
||
}
|
||
|
||
/* Save off the static variables to allow this function to
|
||
be called recursively. */
|
||
pzhold_args = pzargs;
|
||
chold_alloc_args = calloc_args;
|
||
pzargs = NULL;
|
||
calloc_args = 0;
|
||
|
||
t = tprocess_one_cmd (cargs, pzhold_args, qcmds, zerr, iflags);
|
||
|
||
if (pzargs != NULL)
|
||
xfree ((pointer) pzargs);
|
||
pzargs = pzhold_args;
|
||
calloc_args = chold_alloc_args;
|
||
|
||
if (t == CMDTABRET_FREE || t == CMDTABRET_FREE_AND_EXIT)
|
||
xfree ((pointer) zget);
|
||
if (t == CMDTABRET_EXIT || t == CMDTABRET_FREE_AND_EXIT)
|
||
return;
|
||
}
|
||
}
|
||
|
||
/* Process a single command. */
|
||
|
||
enum tcmdtabret
|
||
tprocess_one_cmd (cargs, azargs, qcmds, zerr, iflags)
|
||
int cargs;
|
||
char **azargs;
|
||
const struct scmdtab *qcmds;
|
||
const char *zerr;
|
||
int iflags;
|
||
{
|
||
const struct scmdtab *q;
|
||
int (*pfcmp) P((const char *, const char *));
|
||
|
||
if ((iflags & CMDFLAG_CASESIGNIFICANT) != 0)
|
||
pfcmp = strcmp;
|
||
else
|
||
pfcmp = strcasecmp;
|
||
|
||
for (q = qcmds; q->zcmd != NULL; q++)
|
||
{
|
||
int itype;
|
||
int callowed;
|
||
|
||
itype = TTYPE_CMDTABTYPE (q->itype);
|
||
if (itype != CMDTABTYPE_PREFIX)
|
||
{
|
||
if ((*pfcmp) (q->zcmd, azargs[0]) != 0)
|
||
continue;
|
||
}
|
||
else
|
||
{
|
||
int clen;
|
||
|
||
clen = strlen (q->zcmd);
|
||
if ((iflags & CMDFLAG_CASESIGNIFICANT) != 0)
|
||
{
|
||
if (strncmp (q->zcmd, azargs[0], clen) != 0)
|
||
continue;
|
||
}
|
||
else
|
||
{
|
||
if (strncasecmp (q->zcmd, azargs[0], clen) != 0)
|
||
continue;
|
||
}
|
||
}
|
||
|
||
callowed = CARGS_CMDTABTYPE (q->itype);
|
||
if (callowed != 0 && callowed != cargs)
|
||
{
|
||
if (zerr != NULL)
|
||
ulog (LOG_ERROR, "%s: %s: Wrong number of arguments",
|
||
zerr, q->zcmd);
|
||
return CMDTABRET_FREE;
|
||
}
|
||
else if (itype == TTYPE_CMDTABTYPE (CMDTABTYPE_STRING))
|
||
{
|
||
if (cargs != 1 && cargs != 2)
|
||
{
|
||
if (zerr != NULL)
|
||
ulog (LOG_ERROR, "%s: %s: Wrong number of arguments",
|
||
zerr, q->zcmd);
|
||
return CMDTABRET_FREE;
|
||
}
|
||
if (cargs == 1)
|
||
*(const char **) q->pvar = "";
|
||
else
|
||
*(const char **) q->pvar = azargs[1];
|
||
return CMDTABRET_CONTINUE;
|
||
}
|
||
else if (itype == TTYPE_CMDTABTYPE (CMDTABTYPE_INT)
|
||
|| itype == TTYPE_CMDTABTYPE (CMDTABTYPE_LONG))
|
||
{
|
||
long i;
|
||
char *zend;
|
||
|
||
i = strtol (azargs[1], &zend, 10);
|
||
if (*zend != '\0')
|
||
{
|
||
if (zerr != NULL)
|
||
ulog (LOG_ERROR, "%s: %s: Bad number", zerr,
|
||
q->zcmd);
|
||
return CMDTABRET_FREE;
|
||
}
|
||
if (itype == TTYPE_CMDTABTYPE (CMDTABTYPE_INT))
|
||
* (int *) q->pvar = (int) i;
|
||
else
|
||
* (long *) q->pvar = i;
|
||
|
||
return CMDTABRET_FREE;
|
||
}
|
||
else if (itype == TTYPE_CMDTABTYPE (CMDTABTYPE_BOOLEAN))
|
||
{
|
||
char b;
|
||
|
||
b = azargs[1][0];
|
||
if (b == 'y' || b == 'Y' || b == 't' || b == 'T')
|
||
* (boolean *) q->pvar = TRUE;
|
||
else if (b == 'n' || b == 'N' || b == 'f' || b == 'F')
|
||
* (boolean *) q->pvar = FALSE;
|
||
else if (zerr != NULL)
|
||
ulog (LOG_ERROR, "%s: %s: Bad boolean", zerr,
|
||
q->zcmd);
|
||
return CMDTABRET_FREE;
|
||
}
|
||
else if (itype == TTYPE_CMDTABTYPE (CMDTABTYPE_FULLSTRING))
|
||
{
|
||
int i, clen;
|
||
char *zset;
|
||
|
||
/* Use all the arguments separated by a ' '
|
||
character. */
|
||
|
||
clen = 1;
|
||
for (i = 1; i < cargs; i++)
|
||
clen += strlen (azargs[i]) + 1;
|
||
|
||
zset = (char *) xmalloc (clen);
|
||
*zset = '\0';
|
||
for (i = 1; i < cargs - 1; i++)
|
||
{
|
||
strcat (zset, azargs[i]);
|
||
strcat (zset, " ");
|
||
}
|
||
if (i < cargs)
|
||
strcat (zset, azargs[i]);
|
||
|
||
* (const char **) q->pvar = zset;
|
||
|
||
return CMDTABRET_FREE;
|
||
}
|
||
else if (itype == TTYPE_CMDTABTYPE (CMDTABTYPE_FN)
|
||
|| itype == TTYPE_CMDTABTYPE (CMDTABTYPE_PREFIX))
|
||
return (*q->ptfn) (cargs, azargs, q->pvar, zerr);
|
||
else
|
||
{
|
||
#if DEBUG > 0
|
||
ulog (LOG_FATAL, "tprocess_one_cmd: Can't happen (0x%x)",
|
||
itype);
|
||
#endif
|
||
return CMDTABRET_FREE;
|
||
}
|
||
}
|
||
|
||
if ((iflags & CMDFLAG_WARNUNRECOG) != 0
|
||
&& zerr != NULL)
|
||
ulog (LOG_ERROR, "%s: Unrecognized command %s", zerr, azargs[0]);
|
||
|
||
return CMDTABRET_FREE;
|
||
}
|
||
|
||
/* Read the configuration file. If we can't open the configuration file,
|
||
and we're trying to read the default, don't report an error. This
|
||
permits people to not have a configuration file at all if they are
|
||
satisfied with the compiled in defaults. */
|
||
|
||
void
|
||
uread_config (zname)
|
||
const char *zname;
|
||
{
|
||
#if HAVE_TAYLOR_CONFIG
|
||
|
||
FILE *e;
|
||
char *zdefault;
|
||
|
||
zdefault = (char *) alloca (sizeof NEWCONFIGLIB + sizeof CONFIGFILE);
|
||
sprintf (zdefault, "%s%s", NEWCONFIGLIB, CONFIGFILE);
|
||
|
||
/* On UNIX we will be probably be running suid to uucp. We don't want
|
||
to let somebody run us and specify some arbitrary file as the
|
||
configuration file, since that might let them examine files they
|
||
have no access to. */
|
||
if (zname != NULL
|
||
&& strcmp (zname, zdefault) != 0
|
||
&& ! fsysdep_other_config (zname))
|
||
{
|
||
ulog (LOG_ERROR, "Can't read %s; using %s", zname, zdefault);
|
||
zname = zdefault;
|
||
}
|
||
|
||
if (zname == NULL)
|
||
zname = zdefault;
|
||
|
||
e = fopen (zname, "r");
|
||
if (e == NULL)
|
||
{
|
||
if (strcmp (zname, zdefault) != 0)
|
||
{
|
||
fprintf (stderr, "%s: %s: %s\n", abProgram, zname,
|
||
strerror (errno));
|
||
/* We haven't yet called usysdep_initialize, so it should be
|
||
safe to just exit. */
|
||
exit (EXIT_FAILURE);
|
||
}
|
||
/* Just use defaults. */
|
||
}
|
||
else
|
||
{
|
||
uiunknown_start ();
|
||
uprocesscmds (e, (struct smulti_file *) NULL, asCmds, zname,
|
||
CMDFLAG_BACKSLASH);
|
||
(void) fclose (e);
|
||
uiunknown_end ();
|
||
}
|
||
|
||
#else /* ! HAVE_TAYLOR_CONFIG */
|
||
|
||
uiunknown_start ();
|
||
uiunknown_end ();
|
||
|
||
#endif /* ! HAVE_TAYLOR_CONFIG */
|
||
|
||
if (zLocalname == NULL)
|
||
{
|
||
zLocalname = zsysdep_local_name ();
|
||
if (zLocalname == NULL)
|
||
{
|
||
fprintf (stderr, "%s: Can't get local node name\n", abProgram);
|
||
exit (EXIT_FAILURE);
|
||
}
|
||
}
|
||
|
||
uisetup_localsys ();
|
||
|
||
#if HAVE_TAYLOR_CONFIG
|
||
|
||
/* Get the defaults for the file names. */
|
||
|
||
#define SETDEFAULT(z, zfile) \
|
||
if (z == NULL) \
|
||
{ \
|
||
z = (char *) xmalloc (sizeof NEWCONFIGLIB + sizeof zfile - 1); \
|
||
strcpy (z, NEWCONFIGLIB); \
|
||
strcat (z, zfile); \
|
||
if (! fsysdep_file_exists (z)) \
|
||
{ \
|
||
xfree ((pointer) z); \
|
||
z = NULL; \
|
||
} \
|
||
}
|
||
|
||
SETDEFAULT (zSysfile, SYSFILE);
|
||
SETDEFAULT (zPortfile, PORTFILE);
|
||
SETDEFAULT (zDialfile, DIALFILE);
|
||
SETDEFAULT (zDialcodefile, DIALCODEFILE);
|
||
SETDEFAULT (zPwdfile, PASSWDFILE);
|
||
SETDEFAULT (zCallfile, CALLFILE);
|
||
|
||
#endif /* HAVE_TAYLOR_CONFIG */
|
||
|
||
#if HAVE_BNU_CONFIG
|
||
/* If we are supposed to read standard BNU files, read Sysfiles to
|
||
get any nonstandard file names. */
|
||
if (fBnu)
|
||
ubnu_read_sysfiles ();
|
||
#endif /* HAVE_BNU_CONFIG */
|
||
|
||
/* The format of the dialcodes file is the same for all systems, so
|
||
if additional configuration are being used we add the files in
|
||
here to save having to do it when the dialcodes file is read. */
|
||
|
||
#if HAVE_V2_CONFIG
|
||
if (fV2)
|
||
{
|
||
char *z;
|
||
|
||
z = (char *) alloca (sizeof OLDCONFIGLIB + sizeof V2_DIALCODES);
|
||
sprintf (z, "%s%s", OLDCONFIGLIB, V2_DIALCODES);
|
||
uadd_string (&zDialcodefile, z, ' ');
|
||
}
|
||
#endif /* HAVE_V2_CONFIG */
|
||
|
||
#if HAVE_BNU_CONFIG
|
||
if (fBnu)
|
||
{
|
||
char *z;
|
||
|
||
z = (char *) alloca (sizeof OLDCONFIGLIB + sizeof BNU_DIALCODES);
|
||
sprintf (z, "%s%s", OLDCONFIGLIB, BNU_DIALCODES);
|
||
uadd_string (&zDialcodefile, z, ' ');
|
||
}
|
||
#endif /* HAVE_BNU_CONFIG */
|
||
}
|
||
|
||
/* Add a string to a list of strings separated by a separator
|
||
character. */
|
||
|
||
void
|
||
uadd_string (pz, z, bsep)
|
||
char **pz;
|
||
const char *z;
|
||
int bsep;
|
||
{
|
||
if (*pz == NULL)
|
||
*pz = xstrdup (z);
|
||
else
|
||
{
|
||
int clen;
|
||
|
||
clen = strlen (*pz);
|
||
*pz = (char *) xrealloc ((pointer) *pz, clen + strlen (z) + 2);
|
||
(*pz)[clen] = (char) bsep;
|
||
strcpy (*pz + clen + 1, z);
|
||
}
|
||
}
|
||
|
||
#if DEBUG > 1
|
||
|
||
/* Parse a debugging string. This may be a simple number, which sets
|
||
the given number of bits in iDebug, or it may be a series of single
|
||
letters. */
|
||
|
||
static const char * const azDebug_names[] = DEBUG_NAMES;
|
||
|
||
int
|
||
idebug_parse (z)
|
||
const char *z;
|
||
{
|
||
char *zend;
|
||
int i, iret;
|
||
char *zcopy, *ztok;
|
||
|
||
i = (int) strtol (z, &zend, 0);
|
||
if (*zend == '\0')
|
||
{
|
||
if (i > 15)
|
||
i = 15;
|
||
else if (i < 0)
|
||
i = 0;
|
||
return (1 << i) - 1;
|
||
}
|
||
|
||
zcopy = (char *) alloca (strlen (z) + 1);
|
||
strcpy (zcopy, z);
|
||
|
||
iret = 0;
|
||
|
||
for (ztok = strtok (zcopy, ",");
|
||
ztok != NULL;
|
||
ztok = strtok ((char *) NULL, ","))
|
||
{
|
||
if (strcasecmp (ztok, "all") == 0)
|
||
{
|
||
iret = DEBUG_MAX;
|
||
break;
|
||
}
|
||
for (i = 0; azDebug_names[i] != NULL; i++)
|
||
{
|
||
if (strncasecmp (ztok, azDebug_names[i],
|
||
strlen (azDebug_names[i])) == 0)
|
||
{
|
||
iret |= 1 << i;
|
||
break;
|
||
}
|
||
}
|
||
if (azDebug_names[i] == NULL)
|
||
ulog (LOG_ERROR, "Unrecognized debugging option \"%s\"",
|
||
ztok);
|
||
}
|
||
|
||
return iret;
|
||
}
|
||
|
||
/* Parse a debugging string in a configuration file. The pvar
|
||
arguments points to the field to set. */
|
||
|
||
/*ARGSUSED*/
|
||
enum tcmdtabret
|
||
tidebug_parse (argc, argv, pvar, zerr)
|
||
int argc;
|
||
char **argv;
|
||
pointer pvar;
|
||
const char *zerr;
|
||
{
|
||
int *pidebug = (int *) pvar;
|
||
int i;
|
||
|
||
if (argc == 2 &&
|
||
strncasecmp (argv[1], DEBUG_NONE, strlen (DEBUG_NONE)) == 0)
|
||
{
|
||
*pidebug = 0;
|
||
return CMDTABRET_FREE;
|
||
}
|
||
|
||
for (i = 1; i < argc; i++)
|
||
*pidebug |= idebug_parse (argv[i]);
|
||
|
||
return CMDTABRET_FREE;
|
||
}
|
||
|
||
#endif /* DEBUG > 1 */
|
||
|
||
/* Given a file name that may actually be several file names each
|
||
separated with a single space character, we want to be able to read
|
||
lines from them as though they were catenated to form a single
|
||
file. This set of routines allows us to do that easily, although
|
||
only for one set of files at a time. One line can be pushed back,
|
||
which can be convenient for the first line of a file. */
|
||
|
||
struct smulti_file
|
||
{
|
||
/* Names of next files to open. */
|
||
char *z;
|
||
/* String to free up when done. */
|
||
char *zfree;
|
||
/* Current file. */
|
||
FILE *e;
|
||
/* Current file name. */
|
||
char *zname;
|
||
/* Next line to return. */
|
||
char *znext;
|
||
};
|
||
|
||
struct smulti_file *
|
||
qmulti_open (znames)
|
||
const char *znames;
|
||
{
|
||
struct smulti_file *qret;
|
||
|
||
qret = (struct smulti_file *) xmalloc (sizeof (struct smulti_file));
|
||
qret->z = qret->zfree = xstrdup (znames);
|
||
qret->zname = NULL;
|
||
qret->e = NULL;
|
||
qret->znext = NULL;
|
||
|
||
return qret;
|
||
}
|
||
|
||
/* Read the next line from a multiply opened set of files. */
|
||
|
||
char *
|
||
zmulti_gets (q, pffirst, pzname, fbackslash)
|
||
struct smulti_file *q;
|
||
boolean *pffirst;
|
||
const char **pzname;
|
||
boolean fbackslash;
|
||
{
|
||
if (pffirst != NULL)
|
||
*pffirst = FALSE;
|
||
|
||
if (q->znext != NULL)
|
||
{
|
||
char *z;
|
||
|
||
z = q->znext;
|
||
q->znext = NULL;
|
||
return z;
|
||
}
|
||
|
||
while (TRUE)
|
||
{
|
||
char *z;
|
||
|
||
if (q->e != NULL)
|
||
{
|
||
char *zret;
|
||
|
||
zret = zfgets (q->e, fbackslash);
|
||
if (zret != NULL)
|
||
{
|
||
if (pzname != NULL)
|
||
*pzname = q->zname;
|
||
return zret;
|
||
}
|
||
|
||
if (fclose (q->e) != 0)
|
||
{
|
||
ulog (LOG_ERROR, "fclose: %s", strerror (errno));
|
||
q->e = NULL;
|
||
return NULL;
|
||
}
|
||
|
||
q->e = NULL;
|
||
}
|
||
|
||
if (*q->z == '\0')
|
||
return NULL;
|
||
|
||
z = q->z;
|
||
q->z += strcspn (z, " ");
|
||
if (*q->z != '\0')
|
||
*q->z++ = '\0';
|
||
|
||
q->e = fopen (z, "r");
|
||
if (q->e == NULL)
|
||
{
|
||
ulog (LOG_ERROR, "fopen (%s): %s", z, strerror (errno));
|
||
return NULL;
|
||
}
|
||
|
||
if (pffirst != NULL)
|
||
*pffirst = TRUE;
|
||
q->zname = z;
|
||
}
|
||
}
|
||
|
||
/* Push back a line so that it is read by the next call to
|
||
zmulti_gets. This is sometimes used on the first line of a file in
|
||
uprocesscmds. */
|
||
|
||
static void
|
||
umulti_pushback (q, z)
|
||
struct smulti_file *q;
|
||
char *z;
|
||
{
|
||
#if DEBUG > 0
|
||
if (q->znext != NULL)
|
||
ulog (LOG_FATAL, "umulti_pushback: Can't happen");
|
||
#endif
|
||
q->znext = z;
|
||
}
|
||
|
||
/* Close the multiple file, even though a read is in progress. If
|
||
zmulti_gets returns NULL, the files will have been closed. */
|
||
|
||
boolean
|
||
fmulti_close (q)
|
||
struct smulti_file *q;
|
||
{
|
||
boolean fret;
|
||
|
||
fret = TRUE;
|
||
|
||
if (q->e != NULL)
|
||
{
|
||
if (fclose (q->e) != 0)
|
||
{
|
||
ulog (LOG_ERROR, "fclose: %s", strerror (errno));
|
||
fret = FALSE;
|
||
}
|
||
}
|
||
|
||
xfree ((pointer) q->zfree);
|
||
xfree ((pointer) q);
|
||
|
||
return fret;
|
||
}
|
||
|
||
/* See whether a file is in a directory list, and make sure the user
|
||
has appropriate access. */
|
||
|
||
boolean
|
||
fin_directory_list (qsys, zfile, zdirs, fcheck, freadable, zuser)
|
||
const struct ssysteminfo *qsys;
|
||
const char *zfile;
|
||
const char *zdirs;
|
||
boolean fcheck;
|
||
boolean freadable;
|
||
const char *zuser;
|
||
{
|
||
char *zcopy;
|
||
boolean fmatch;
|
||
|
||
zcopy = (char *) alloca (strlen (zdirs) + 1);
|
||
strcpy (zcopy, zdirs);
|
||
|
||
fmatch = FALSE;
|
||
|
||
while (*zcopy != '\0')
|
||
{
|
||
char *z;
|
||
|
||
z = zcopy + strcspn (zcopy, " ");
|
||
if (*z == '\0')
|
||
--z;
|
||
else
|
||
*z = '\0';
|
||
|
||
if (*zcopy == '!')
|
||
{
|
||
if (fsysdep_in_directory (qsys, zfile, zcopy + 1, FALSE,
|
||
FALSE, (const char *) NULL))
|
||
fmatch = FALSE;
|
||
}
|
||
else
|
||
{
|
||
if (fsysdep_in_directory (qsys, zfile, zcopy, fcheck,
|
||
freadable, zuser))
|
||
fmatch = TRUE;
|
||
}
|
||
|
||
zcopy = z + 1;
|
||
}
|
||
|
||
return fmatch;
|
||
}
|
||
|
||
/* See whether a file is a spool file. Spool file names are specially
|
||
crafted to hand around to other UUCP packages. They always begin
|
||
with 'C', 'D' or 'X', and the second character is always a period.
|
||
The remaining characters are any character that could appear in a
|
||
system name. */
|
||
|
||
boolean
|
||
fspool_file (zfile)
|
||
const char *zfile;
|
||
{
|
||
const char *z;
|
||
|
||
if (*zfile != 'C' && *zfile != 'D' && *zfile != 'X')
|
||
return FALSE;
|
||
if (zfile[1] != '.')
|
||
return FALSE;
|
||
for (z = zfile + 2; *z != '\0'; z++)
|
||
if (! isalnum (BUCHAR (*z)) && *z != '_' && *z != '-' && *z != '.')
|
||
return FALSE;
|
||
return TRUE;
|
||
}
|
||
|
||
/* Compare two grades, returning < 0 if the first should be executed
|
||
before the second, == 0 if they are the same, and > 0 if the first
|
||
should be executed after the second. This code assumes that the
|
||
upper case letters appear in sequence and the lower case letters
|
||
appear in sequence. */
|
||
|
||
int
|
||
igradecmp (barg1, barg2)
|
||
int barg1;
|
||
int barg2;
|
||
{
|
||
int b1, b2;
|
||
|
||
/* Make sure the arguments are unsigned. */
|
||
b1 = (int) BUCHAR (barg1);
|
||
b2 = (int) BUCHAR (barg2);
|
||
|
||
if (isdigit (b1))
|
||
{
|
||
if (isdigit (b2))
|
||
return b1 - b2;
|
||
else
|
||
return -1;
|
||
}
|
||
else if (isupper (b1))
|
||
{
|
||
if (isdigit (b2))
|
||
return 1;
|
||
else if (isupper (b2))
|
||
return b1 - b2;
|
||
else
|
||
return -1;
|
||
}
|
||
else
|
||
{
|
||
if (! islower (b2))
|
||
return 1;
|
||
else
|
||
return b1 - b2;
|
||
}
|
||
}
|