386BSD 0.1 development
[unix-history] / usr / src / libexec / uucp / sysinf.c
CommitLineData
af364716
WJ
1/* sysinf.c
2 Functions to read system information for the UUCP package.
3
4 Copyright (C) 1991, 1992 Ian Lance Taylor
5
6 This file is part of the Taylor UUCP package.
7
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2 of the
11 License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22 The author of the program may be contacted at ian@airs.com or
23 c/o AIRS, P.O. Box 520, Waltham, MA 02254.
24
25 $Log: sysinf.c,v $
26 Revision 1.24 1992/04/02 22:51:09 ian
27 Add gcc 2.0 format checking to ulog, and fixed discovered problems
28
29 Revision 1.23 1992/03/30 04:49:10 ian
30 Niels Baggesen: added debugging types abnormal and uucp-proto
31
32 Revision 1.22 1992/03/28 21:47:55 ian
33 David J. MacKenzie: allow backslash to quote newline in config files
34
35 Revision 1.21 1992/03/28 20:31:55 ian
36 Franc,ois Pinard: allow a name to be given to an alternate
37
38 Revision 1.20 1992/03/24 17:18:33 ian
39 Fixed handling of alternates in file-wide defaults
40
41 Revision 1.19 1992/03/16 04:30:57 ian
42 Permit a retry time for the time and timegrade commands
43
44 Revision 1.18 1992/03/13 16:17:42 ian
45 Chip Salzenberg: set default login chat script timeout to 10 seconds
46
47 Revision 1.17 1992/03/12 19:54:43 ian
48 Debugging based on types rather than number
49
50 Revision 1.16 1992/03/09 20:14:37 ian
51 Ted Lindgreen: added max-remote-debug command
52
53 Revision 1.15 1992/03/07 02:56:30 ian
54 Rewrote time routines
55
56 Revision 1.14 1992/03/03 06:06:48 ian
57 T. William Wells: don't complain about missing configuration files
58
59 Revision 1.13 1992/02/23 19:50:50 ian
60 Handle READ and WRITE in Permissions correctly
61
62 Revision 1.12 1992/02/08 03:54:18 ian
63 Include <string.h> only in <uucp.h>, added 1992 copyright
64
65 Revision 1.11 1992/01/13 05:17:30 ian
66 Mike Park: wrong number of arguments to ulog call
67
68 Revision 1.10 1992/01/07 15:23:50 ian
69 Niels Baggesen: allocate number of protocol parameters correctly
70
71 Revision 1.9 1991/12/28 03:49:23 ian
72 Added HAVE_MEMFNS and HAVE_BFNS; changed uses of memset to bzero
73
74 Revision 1.8 1991/12/23 05:15:54 ian
75 David Nugent: set debugging level for a specific system
76
77 Revision 1.7 1991/12/17 17:08:02 ian
78 Marc Unangst: allow true and false for boolean strings as documented
79
80 Revision 1.6 1991/12/15 04:17:11 ian
81 Added chat-seven-bit command to control parity bit stripping
82
83 Revision 1.5 1991/12/15 03:42:33 ian
84 Added tprocess_chat_cmd for all chat commands, and added CMDTABTYPE_PREFIX
85
86 Revision 1.4 1991/11/13 20:38:00 ian
87 Added TCP port type for connections over TCP
88
89 Revision 1.3 1991/11/12 19:47:04 ian
90 Add called-chat set of commands to run a chat script on an incoming call
91
92 Revision 1.2 1991/11/11 23:47:24 ian
93 Added chat-program to run a program to do a chat script
94
95 Revision 1.1 1991/09/10 19:40:31 ian
96 Initial revision
97
98 */
99
100#include "uucp.h"
101
102#if USE_RCS_ID
103char sysinf_rcsid[] = "$Id: sysinf.c,v 1.24 1992/04/02 22:51:09 ian Rel $";
104#endif
105
106#include <ctype.h>
107#include <errno.h>
108
109#include "port.h"
110#include "system.h"
111#include "uutime.h"
112\f
113/* Whether we accept calls from unknown systems. */
114boolean fUnknown_ok = FALSE;
115
116/* Information we hold for an unknown system. */
117struct ssysteminfo sUnknown;
118
119/* Information we hold for the local system. */
120struct ssysteminfo sLocalsys;
121\f
122#if HAVE_TAYLOR_CONFIG
123
124/* I don't find the system file format used by either V2 or BNU UUCP
125 very intuitive, so I've developed my own format. This replaces the
126 files L.sys and USERFILE for V2, and Systems and Permissions for
127 BNU. The complete format is described in a separate document. */
128
129/* Some local functions. */
130static void uiset_clear P((boolean falternate));
131
132/* Set when we read the first line of a new file, to indicate that a
133 new set of defaults should be gathered. */
134static boolean fIfirst;
135
136/* This structure holds system information as it is gathered. */
137static struct ssysteminfo sIhold;
138
139/* Default information. */
140static struct ssysteminfo sIdefault;
141
142/* The name of the next system. */
143static char *zInext_system;
144
145/* The list of alternates to draw from. */
146static struct ssysteminfo *qIalternates;
147
148/* Whether to use default alternates. */
149static boolean fIdefault_alternates;
150
151/* There are several commands for which we want to take the default if
152 provided, but we don't want to add to the default. For example,
153 each system can have multiple time specifications (using different
154 grades), which is implemented by adding each new time specification
155 to the previous ones. We want to allow default time specifications.
156 However, if a system has time specifications, we don't want to add
157 its time specifications to the default ones. We handle this with a
158 set of boolean variables which we set to tell the adding functions
159 to ignore any existing entry; when an entry has been added, the
160 boolean variable is cleared. */
161static boolean fIclear_alias;
162static boolean fIclear_alternate;
163static boolean fIclear_time;
164static boolean fIclear_calltimegrade;
165static boolean fIclear_call_local_size;
166static boolean fIclear_call_remote_size;
167static boolean fIclear_called_local_size;
168static boolean fIclear_called_remote_size;
169static boolean fIclear_port;
170static boolean fIclear_chat_fail;
171static boolean fIclear_proto_param;
172static boolean fIclear_called_chat_fail;
173
174/* Local functions needed to parse the system information file. */
175
176#define CMDTABFN(z) \
177 static enum tcmdtabret z P((int, char **, pointer, const char *))
178
179CMDTABFN (ticlear);
180CMDTABFN (tisystem);
181CMDTABFN (tialias);
182CMDTABFN (tialternate);
183CMDTABFN (titime);
184CMDTABFN (titimegrade);
185CMDTABFN (ticall_local_size);
186CMDTABFN (ticall_remote_size);
187CMDTABFN (ticalled_local_size);
188CMDTABFN (ticalled_remote_size);
189CMDTABFN (titimetable);
190CMDTABFN (tiport);
191CMDTABFN (tichat);
192CMDTABFN (ticalled_login);
193CMDTABFN (tiproto_param);
194CMDTABFN (tirequest);
195CMDTABFN (titransfer);
196
197#undef CMDTABFN
198
199/* The commands accepted from the system information file. */
200
201static const struct scmdtab asIcmds[] =
202{
203 { "#", CMDTABTYPE_FN | 1, NULL, ticlear },
204 { "system", CMDTABTYPE_FN | 2, NULL, tisystem },
205 { "alias", CMDTABTYPE_FN | 2, NULL, tialias },
206 { "alternate", CMDTABTYPE_FN | 0, NULL, tialternate },
207 { "default-alternates", CMDTABTYPE_BOOLEAN,
208 (pointer) &fIdefault_alternates, NULL },
209 { "time", CMDTABTYPE_FN | 0, NULL, titime },
210 { "timegrade", CMDTABTYPE_FN | 0, (pointer) &sIhold.ztime, titimegrade },
211 { "call-timegrade", CMDTABTYPE_FN | 3, (pointer) &sIhold.zcalltimegrade,
212 titimegrade },
213 { "call-local-size", CMDTABTYPE_FN | 3, NULL, ticall_local_size },
214 { "call-remote-size", CMDTABTYPE_FN | 3, NULL, ticall_remote_size },
215 { "called-local-size", CMDTABTYPE_FN | 3, NULL, ticalled_local_size },
216 { "called-remote-size", CMDTABTYPE_FN | 3, NULL, ticalled_remote_size },
217 { "timetable", CMDTABTYPE_FN | 3, NULL, titimetable },
218 { "baud", CMDTABTYPE_LONG, (pointer) &sIhold.ibaud, NULL },
219 { "speed", CMDTABTYPE_LONG, (pointer) &sIhold.ibaud, NULL },
220 { "port", CMDTABTYPE_FN | 0, NULL, tiport },
221 { "phone", CMDTABTYPE_STRING, (pointer) &sIhold.zphone, NULL },
222 { "address", CMDTABTYPE_STRING, (pointer) &sIhold.zphone, NULL },
223 { "chat", CMDTABTYPE_PREFIX | 0, (pointer) &sIhold.schat, tichat },
224 { "call-login", CMDTABTYPE_STRING, (pointer) &sIhold.zcall_login, NULL },
225 { "call-password", CMDTABTYPE_STRING, (pointer) &sIhold.zcall_password,
226 NULL },
227 { "called-login", CMDTABTYPE_FN | 0, NULL, ticalled_login },
228 { "callback", CMDTABTYPE_BOOLEAN, (pointer) &sIhold.fcallback, NULL },
229 { "sequence", CMDTABTYPE_BOOLEAN, (pointer) &sIhold.fsequence, NULL },
230 { "protocol", CMDTABTYPE_STRING, (pointer) &sIhold.zprotocols, NULL },
231 { "protocol-parameter", CMDTABTYPE_FN | 0, NULL, tiproto_param },
232 { "called-chat", CMDTABTYPE_PREFIX | 0, (pointer) &sIhold.scalled_chat,
233 tichat },
234#if DEBUG > 1
235 { "debug", CMDTABTYPE_FN | 0, (pointer) &sIhold.idebug, tidebug_parse },
236 { "max-remote-debug", CMDTABTYPE_FN | 0,
237 (pointer) &sIhold.imax_remote_debug, tidebug_parse },
238#endif
239 { "call-request", CMDTABTYPE_BOOLEAN, (pointer) &sIhold.fcall_request,
240 NULL },
241 { "called-request", CMDTABTYPE_BOOLEAN, (pointer) &sIhold.fcalled_request,
242 NULL },
243 { "request", CMDTABTYPE_FN | 2, NULL, tirequest },
244 { "call-transfer", CMDTABTYPE_BOOLEAN, (pointer) &sIhold.fcall_transfer,
245 NULL },
246 { "called-transfer", CMDTABTYPE_BOOLEAN,
247 (pointer) &sIhold.fcalled_transfer, NULL },
248 { "transfer", CMDTABTYPE_FN | 2, NULL, titransfer },
249 { "local-send", CMDTABTYPE_FULLSTRING, (pointer) &sIhold.zlocal_send,
250 NULL },
251 { "remote-send", CMDTABTYPE_FULLSTRING, (pointer) &sIhold.zremote_send,
252 NULL },
253 { "local-receive", CMDTABTYPE_FULLSTRING,
254 (pointer) &sIhold.zlocal_receive, NULL },
255 { "remote-receive", CMDTABTYPE_FULLSTRING,
256 (pointer) &sIhold.zremote_receive, NULL },
257 { "command-path", CMDTABTYPE_FULLSTRING, (pointer) &sIhold.zpath, NULL },
258 { "commands", CMDTABTYPE_FULLSTRING, (pointer) &sIhold.zcmds, NULL },
259 { "free-space", CMDTABTYPE_LONG, (pointer) &sIhold.cfree_space, NULL },
260 { "forwardto", CMDTABTYPE_FULLSTRING, (pointer) &sIhold.zforwardto, NULL },
261 { "forward-to", CMDTABTYPE_FULLSTRING, (pointer) &sIhold.zforwardto, NULL },
262 { "pubdir", CMDTABTYPE_STRING, (pointer) &sIhold.zpubdir, NULL },
263 { "myname", CMDTABTYPE_STRING, (pointer) &sIhold.zlocalname, NULL },
264 { NULL, 0, NULL, NULL }
265};
266\f
267/* This is called for the first line of each file. It clears the
268 defaults, so that each file has a different set. */
269
270/*ARGSUSED*/
271static enum tcmdtabret
272ticlear (argc, argv, pvar, zerr)
273 int argc;
274 char **argv;
275 pointer pvar;
276 const char *zerr;
277{
278 fIfirst = TRUE;
279 return CMDTABRET_FREE_AND_EXIT;
280}
281
282/* Process the system command. We store away the system name and exit
283 out of processing commands to let the main loop handle it. */
284
285/*ARGSUSED*/
286static enum tcmdtabret
287tisystem (argc, argv, pvar, zerr)
288 int argc;
289 char **argv;
290 pointer pvar;
291 const char *zerr;
292{
293 const char *z;
294
295 /* System names may only contain alphanumeric characters,
296 underscores, dashes and dots, and they may not begin with a dot,
297 at least for now. */
298 for (z = argv[1]; *z != '\0'; z++)
299 {
300 if (! isalnum (BUCHAR (*z))
301 && *z != '_'
302 && *z != '-'
303 && (*z != '.' || z == argv[1]))
304 {
305 ulog (LOG_ERROR, "%s: %s %s: Illegal character in system name",
306 zerr, argv[0], argv[1]);
307 return CMDTABRET_FREE;
308 }
309 }
310
311 if (strlen (argv[1]) > cSysdep_max_name_len)
312 {
313 ulog (LOG_ERROR, "System name \"%s\" too long (max %d)", argv[1],
314 cSysdep_max_name_len);
315 return CMDTABRET_FREE;
316 }
317
318 zInext_system = argv[1];
319
320 DEBUG_MESSAGE1 (DEBUG_CONFIG,
321 "tisystem: Reading system %s", zInext_system);
322
323 return CMDTABRET_EXIT;
324}
325
326/* Process the alias command. */
327
328/*ARGSUSED*/
329static enum tcmdtabret
330tialias (argc, argv, pvar, zerr)
331 int argc;
332 char **argv;
333 pointer pvar;
334 const char *zerr;
335{
336 if (fIclear_alias)
337 {
338 sIhold.zalias = NULL;
339 fIclear_alias = FALSE;
340 }
341 uadd_string (&sIhold.zalias, argv[1], ' ');
342 return CMDTABRET_FREE;
343}
344
345/* Process the alternate command. The current information is in
346 sIhold. We link this onto a chain of alternates starting at
347 sIalternate. We then set up sIhold with the defaults for the next
348 alternate. qIalternates holds the list of alternates for the
349 file-wide defaults, and we use to set up sIhold. We also call
350 uiset_clear to set all the fIclear_* variables so that commands
351 like ``time'' know that they should ignore any existing entry. */
352
353static struct ssysteminfo sIalternate;
354
355/*ARGSUSED*/
356static enum tcmdtabret
357tialternate (argc, argv, pvar, zerr)
358 int argc;
359 char **argv;
360 pointer pvar;
361 const char *zerr;
362{
363 if (fIclear_alternate)
364 {
365 sIalternate = sIhold;
366 fIclear_alternate = FALSE;
367 }
368 else
369 {
370 struct ssysteminfo *qnew;
371 struct ssysteminfo **pq;
372
373 qnew = (struct ssysteminfo *) xmalloc (sizeof (struct ssysteminfo));
374 *qnew = sIhold;
375 for (pq = &sIalternate.qalternate; *pq != NULL; pq = &(*pq)->qalternate)
376 ;
377 *pq = qnew;
378 sIhold = sIalternate;
379 sIhold.qalternate = NULL;
380 }
381
382 /* Clear the name of the next alternate. */
383 sIhold.zalternate = NULL;
384
385 /* Now, if there is a default alternate to base this on, we must
386 override everything not changed before the first ``alternate''
387 command to the default alternate. */
388 if (fIdefault_alternates
389 && qIalternates != NULL)
390 {
391 if (qIalternates->zalternate != NULL)
392 sIhold.zalternate = qIalternates->zalternate;
393
394#define TEST(x) \
395 if (sIhold.x == sIdefault.x) \
396 sIhold.x = qIalternates->x;
397
398 TEST (ztime);
399 TEST (zcalltimegrade);
400 TEST (zcall_local_size);
401 TEST (zcall_remote_size);
402 TEST (zcalled_local_size);
403 TEST (zcalled_remote_size);
404 TEST (ibaud);
405 TEST (zport);
406 TEST (qport);
407 TEST (zphone);
408 TEST (schat.zchat);
409 TEST (schat.zprogram);
410 TEST (schat.ctimeout);
411 TEST (schat.zfail);
412 TEST (zcall_login);
413 TEST (zcalled_login);
414 TEST (fcallback);
415 TEST (zprotocols);
416 TEST (cproto_params);
417 TEST (qproto_params);
418 TEST (scalled_chat.zchat);
419 TEST (scalled_chat.zprogram);
420 TEST (scalled_chat.ctimeout);
421 TEST (scalled_chat.zfail);
422#if DEBUG > 1
423 TEST (idebug);
424 TEST (imax_remote_debug);
425#endif
426 TEST (fcall_request);
427 TEST (fcalled_request);
428 TEST (fcall_transfer);
429 TEST (fcalled_transfer);
430 TEST (zlocal_send);
431 TEST (zcalled_local_send);
432 TEST (zremote_send);
433 TEST (zcalled_remote_send);
434 TEST (zlocal_receive);
435 TEST (zcalled_local_receive);
436 TEST (zremote_receive);
437 TEST (zcalled_remote_receive);
438 TEST (zpath);
439 TEST (zcmds);
440 TEST (cfree_space);
441 TEST (zforwardto);
442 TEST (zpubdir);
443 TEST (zlocalname);
444
445#undef TEST
446
447 qIalternates = qIalternates->qalternate;
448 }
449
450 /* If there is a name for this alternate, put it in. */
451 if (argc > 1)
452 sIhold.zalternate = xstrdup (argv[1]);
453
454 uiset_clear (TRUE);
455
456 return CMDTABRET_FREE;
457}
458
459/* Process the time command. */
460
461/*ARGSUSED*/
462static enum tcmdtabret
463titime (argc, argv, pvar, zerr)
464 int argc;
465 char **argv;
466 pointer pvar;
467 const char *zerr;
468{
469 char *pznew[4];
470 char ab[2];
471
472 pznew[0] = argv[0];
473 ab[0] = 'z';
474 ab[1] = '\0';
475 pznew[1] = ab;
476 pznew[2] = argv[1];
477 if (argc > 2)
478 pznew[3] = argv[2];
479
480 return titimegrade (argc + 1, pznew, (pointer) &sIhold.ztime, zerr);
481}
482
483/* Process the timegrade and the call-timegrade commands. */
484
485static enum tcmdtabret
486titimegrade (argc, argv, pvar, zerr)
487 int argc;
488 char **argv;
489 pointer pvar;
490 const char *zerr;
491{
492 char **pztime = (char **) pvar;
493 int clen;
494 char *z;
495
496 if (argc < 3 || argc > 4)
497 {
498 ulog (LOG_ERROR, "%s: %s: Wrong number of arguments", zerr, argv[0]);
499 return CMDTABRET_FREE;
500 }
501
502 if (argv[1][1] != '\0' || ! FGRADE_LEGAL (argv[1][0]))
503 {
504 ulog (LOG_ERROR, "%s: %s: Illegal grade '%s'", zerr, argv[0],
505 argv[1]);
506 return CMDTABRET_FREE;
507 }
508
509 /* We should probably check whether the time string is legal. A
510 timegrade string is a single character grade, then a time string,
511 then an optional semicolon and a retry time. */
512
513 clen = strlen (argv[2]) + 2;
514 if (argc > 3)
515 clen += strlen (argv[3]) + 1;
516 z = (char *) alloca (clen);
517 *z = argv[1][0];
518 strcpy (z + 1, argv[2]);
519 if (argc > 3)
520 {
521 strcat (z, ";");
522 strcat (z, argv[3]);
523 }
524
525 if (pztime == &sIhold.ztime)
526 {
527 if (fIclear_time)
528 {
529 *pztime = NULL;
530 fIclear_time = FALSE;
531 }
532 }
533 else
534 {
535 if (fIclear_calltimegrade)
536 {
537 *pztime = NULL;
538 fIclear_calltimegrade = FALSE;
539 }
540 }
541
542 uadd_string (pztime, z, ' ');
543
544 return CMDTABRET_FREE;
545}
546
547/* Add a size command. */
548
549static enum tcmdtabret tiadd_size P((int argc, char **argv,
550 const char *zerr, boolean *pf,
551 char **pz));
552
553static enum tcmdtabret
554tiadd_size (argc, argv, zerr, pf, pz)
555 int argc;
556 char **argv;
557 const char *zerr;
558 boolean *pf;
559 char **pz;
560{
561 long cbytes;
562 char *zend;
563 char *zarg;
564
565 cbytes = strtol (argv[1], &zend, 10);
566 if (*zend != '\0')
567 {
568 ulog (LOG_ERROR, "%s: %s: Bad number", zerr, argv[0]);
569 return CMDTABRET_FREE;
570 }
571
572 /* We should check the legality of the time string here. */
573
574 if (*pf)
575 {
576 *pz = NULL;
577 *pf = FALSE;
578 }
579
580 zarg = (char *) alloca (strlen (argv[2]) + 20);
581 sprintf (zarg, "%ld %s", cbytes, argv[2]);
582
583 uadd_string (pz, zarg, ' ');
584
585 return CMDTABRET_FREE;
586}
587
588/* Process the call-local-size command. */
589
590/*ARGSUSED*/
591static enum tcmdtabret
592ticall_local_size (argc, argv, pvar, zerr)
593 int argc;
594 char **argv;
595 pointer pvar;
596 const char *zerr;
597{
598 return tiadd_size (argc, argv, zerr, &fIclear_call_local_size,
599 &sIhold.zcall_local_size);
600}
601
602/* Process the call-remote-size command. */
603
604/*ARGSUSED*/
605static enum tcmdtabret
606ticall_remote_size (argc, argv, pvar, zerr)
607 int argc;
608 char **argv;
609 pointer pvar;
610 const char *zerr;
611{
612 return tiadd_size (argc, argv, zerr, &fIclear_call_remote_size,
613 &sIhold.zcall_remote_size);
614}
615
616/* Process the called-local-size command. */
617
618/*ARGSUSED*/
619static enum tcmdtabret
620ticalled_local_size (argc, argv, pvar, zerr)
621 int argc;
622 char **argv;
623 pointer pvar;
624 const char *zerr;
625{
626 return tiadd_size (argc, argv, zerr, &fIclear_called_local_size,
627 &sIhold.zcalled_local_size);
628}
629
630/* Process the called-remote-size command. */
631
632/*ARGSUSED*/
633static enum tcmdtabret
634ticalled_remote_size (argc, argv, pvar, zerr)
635 int argc;
636 char **argv;
637 pointer pvar;
638 const char *zerr;
639{
640 return tiadd_size (argc, argv, zerr, &fIclear_called_remote_size,
641 &sIhold.zcalled_remote_size);
642}
643
644/* Process the timetable command. */
645
646/*ARGSUSED*/
647static enum tcmdtabret
648titimetable (argc, argv, pvar, zerr)
649 int argc;
650 char **argv;
651 pointer pvar;
652 const char *zerr;
653{
654 uaddtimetable (argv[1], argv[2]);
655 return CMDTABRET_CONTINUE;
656}
657
658/* Process the port command. */
659
660/*ARGSUSED*/
661static enum tcmdtabret
662tiport (argc, argv, pvar, zerr)
663 int argc;
664 char **argv;
665 pointer pvar;
666 const char *zerr;
667{
668 if (argc < 2)
669 {
670 ulog (LOG_ERROR, "%s: %s: Wrong number of arguments", zerr, argv[0]);
671 return CMDTABRET_FREE;
672 }
673
674 if (fIclear_port)
675 {
676 sIhold.zport = NULL;
677 sIhold.qport = NULL;
678 fIclear_port = FALSE;
679 }
680
681 if (argc > 2)
682 {
683 enum tcmdtabret tret;
684
685 if (sIhold.zport != NULL)
686 {
687 ulog (LOG_ERROR,
688 "%s: %s: Ignoring port specification following port name",
689 zerr, argv[0]);
690 return CMDTABRET_FREE;
691 }
692 tret = tprocess_port_cmd (argc - 1, argv + 1, (pointer) &sIhold.qport,
693 zerr);
694 if (sIhold.qport != NULL && sIhold.qport->zname == NULL)
695 {
696 char *zname;
697
698 if (sIhold.zname == NULL)
699 sIhold.qport->zname = "default system file port";
700 else
701 {
702 zname = (char *) alloca (strlen (sIhold.zname)
703 + sizeof "system port");
704 sprintf (zname, "system %s port", sIhold.zname);
705 sIhold.qport->zname = xstrdup (zname);
706 }
707 }
708
709#if DEBUG > 1
710 if (sIhold.qport != NULL)
711 DEBUG_MESSAGE2 (DEBUG_CONFIG,
712 "tiport: Command %s to port %s", argv[1],
713 sIhold.qport->zname);
714#endif
715
716 return tret;
717 }
718 else
719 {
720 if (sIhold.qport != NULL)
721 {
722 ulog (LOG_ERROR,
723 "%s: %s: Ignoring port name following port specification",
724 zerr, argv[0]);
725 return CMDTABRET_FREE;
726 }
727
728 sIhold.zport = argv[1];
729
730 return CMDTABRET_CONTINUE;
731 }
732}
733
734/* Process one of the chat commands. We have a special version for
735 systems just so that we clear out the chat failure strings. It
736 would be nice if there were a cleaner way to do this. */
737
738static enum tcmdtabret
739tichat (argc, argv, pvar, zerr)
740 int argc;
741 char **argv;
742 pointer pvar;
743 const char *zerr;
744{
745 if (strcmp (argv[0], "chat-fail") == 0)
746 {
747 if (fIclear_chat_fail)
748 {
749 sIhold.schat.zfail = NULL;
750 fIclear_chat_fail = FALSE;
751 }
752 }
753 else if (strcmp (argv[0], "called-chat-fail") == 0)
754 {
755 if (fIclear_called_chat_fail)
756 {
757 sIhold.scalled_chat.zfail = NULL;
758 fIclear_called_chat_fail = FALSE;
759 }
760 }
761
762 return tprocess_chat_cmd (argc, argv, pvar, zerr);
763}
764
765/* Process the called-login command. */
766
767/*ARGSUSED*/
768static enum tcmdtabret
769ticalled_login (argc, argv, pvar, zerr)
770 int argc;
771 char **argv;
772 pointer pvar;
773 const char *zerr;
774{
775 if (argc < 2)
776 {
777 ulog (LOG_ERROR, "%s: %s: Wrong number of arguments", zerr, argv[0]);
778 return CMDTABRET_FREE;
779 }
780
781 sIhold.zcalled_login = argv[1];
782
783 if (argc > 2)
784 uadd_validate (argv[1], argc - 2, (const char **) argv + 2);
785
786 return CMDTABRET_CONTINUE;
787}
788
789/* Process the protocol parameter command. */
790
791/*ARGSUSED*/
792static enum tcmdtabret
793tiproto_param (argc, argv, pvar, zerr)
794 int argc;
795 char **argv;
796 pointer pvar;
797 const char *zerr;
798{
799 if (fIclear_proto_param)
800 {
801 sIhold.cproto_params = 0;
802 sIhold.qproto_params = NULL;
803 fIclear_proto_param = FALSE;
804 }
805
806 return tadd_proto_param (&sIhold.cproto_params, &sIhold.qproto_params,
807 zerr, argc - 1, argv + 1);
808}
809
810/* Process the request command. */
811
812/*ARGSUSED*/
813static enum tcmdtabret
814tirequest (argc, argv, pvar, zerr)
815 int argc;
816 char **argv;
817 pointer pvar;
818 const char *zerr;
819{
820 char b;
821 boolean fset;
822
823 b = argv[1][0];
824 if (b == 'y' || b == 'Y' || b == 't' || b == 'T')
825 fset = TRUE;
826 else if (b == 'n' || b == 'N' || b == 'f' || b == 'F')
827 fset = FALSE;
828 else
829 {
830 ulog (LOG_ERROR, "%s: %s: %s: Bad boolean", zerr, argv[0], argv[1]);
831 return CMDTABRET_FREE;
832 }
833
834 sIhold.fcall_request = fset;
835 sIhold.fcalled_request = fset;
836
837 return CMDTABRET_FREE;
838}
839
840/* Process the transfer command. */
841
842/*ARGSUSED*/
843static enum tcmdtabret
844titransfer (argc, argv, pvar, zerr)
845 int argc;
846 char **argv;
847 pointer pvar;
848 const char *zerr;
849{
850 char b;
851 boolean fset;
852
853 b = argv[1][0];
854 if (b == 'y' || b == 'Y' || b == 't' || b == 'T')
855 fset = TRUE;
856 else if (b == 'n' || b == 'N' || b == 'f' || b == 'F')
857 fset = FALSE;
858 else
859 {
860 ulog (LOG_ERROR, "%s: %s: %s: Bad boolean", zerr, argv[0], argv[1]);
861 return CMDTABRET_FREE;
862 }
863
864 sIhold.fcall_transfer = fset;
865 sIhold.fcalled_transfer = fset;
866
867 return CMDTABRET_FREE;
868}
869
870/* Mark all the contents of sIhold to be cleared before they are set.
871 If the falternate argument is TRUE, then only prepare to clear
872 those contents that should be cleared for an alternate. */
873
874static void
875uiset_clear (falternate)
876 boolean falternate;
877{
878 if (! falternate)
879 {
880 fIclear_alias = TRUE;
881 fIclear_alternate = TRUE;
882 }
883 fIclear_time = TRUE;
884 fIclear_calltimegrade = TRUE;
885 fIclear_call_local_size = TRUE;
886 fIclear_call_remote_size = TRUE;
887 fIclear_called_local_size = TRUE;
888 fIclear_called_remote_size = TRUE;
889 fIclear_port = TRUE;
890 fIclear_chat_fail = TRUE;
891 fIclear_proto_param = TRUE;
892 fIclear_called_chat_fail = TRUE;
893}
894
895#endif /* HAVE_TAYLOR_CONFIG */
896\f
897/* Set up the default values advertised in the documentation. */
898
899void
900uset_system_defaults (qsys)
901 struct ssysteminfo *qsys;
902{
903 qsys->zname = NULL;
904 qsys->zalias = NULL;
905 qsys->qalternate = NULL;
906 qsys->zalternate = NULL;
907 qsys->ztime = xmalloc (1 + sizeof "Never");
908 sprintf (qsys->ztime, "%cNever", BGRADE_LOW);
909 qsys->zcalltimegrade = NULL;
910 qsys->zcall_local_size = NULL;
911 qsys->zcall_remote_size = NULL;
912 qsys->zcalled_local_size = NULL;
913 qsys->zcalled_remote_size = NULL;
914 qsys->ibaud = 0L;
915 qsys->ihighbaud = 0L;
916 qsys->zport = NULL;
917 qsys->zphone = NULL;
918 qsys->qport = NULL;
919 INIT_CHAT (&qsys->schat);
920 qsys->schat.zchat =
921 (char *) "\"\" \\r\\c ogin:-BREAK-ogin:-BREAK-ogin: \\L word: \\P";
922 qsys->schat.ctimeout = 10;
923 qsys->zcall_login = NULL;
924 qsys->zcall_password = NULL;
925 qsys->zcalled_login = NULL;
926 qsys->fcallback = FALSE;
927 qsys->fsequence = FALSE;
928 qsys->zprotocols = NULL;
929 qsys->cproto_params = 0;
930 qsys->qproto_params = NULL;
931 INIT_CHAT (&qsys->scalled_chat);
932#if DEBUG > 1
933 qsys->idebug = 0;
934 qsys->imax_remote_debug = DEBUG_ABNORMAL | DEBUG_CHAT | DEBUG_HANDSHAKE;
935#endif
936 qsys->fcall_request = TRUE;
937 qsys->fcalled_request = TRUE;
938 qsys->fcall_transfer = TRUE;
939 qsys->fcalled_transfer = TRUE;
940 qsys->zlocal_send = ZROOTDIR;
941 qsys->zcalled_local_send = NULL;
942 qsys->zremote_send = "~";
943 qsys->zcalled_remote_send = NULL;
944 qsys->zlocal_receive = "~";
945 qsys->zcalled_local_receive = NULL;
946 qsys->zremote_receive = "~";
947 qsys->zcalled_remote_receive = NULL;
948 qsys->zpath = CMDPATH;
949 qsys->zcmds = "rnews rmail";
950 qsys->cfree_space = DEFAULT_FREE_SPACE;
951 qsys->zforwardto = NULL;
952 qsys->zpubdir = NULL;
953 qsys->zlocalname = NULL;
954}
955\f
956/* Variables to store the loaded system information. */
957
958static boolean fIhave_systems;
959static int cIsystems;
960static struct ssysteminfo *pasIsystems;
961
962/* Read information about all systems. */
963
964static void uiread_systems P((void));
965
966static void
967uiread_systems ()
968{
969 if (fIhave_systems)
970 return;
971
972 fIhave_systems = TRUE;
973
974#if HAVE_TAYLOR_CONFIG
975 if (zSysfile == NULL)
976 {
977 boolean fmore;
978
979 /* Only warn about a missing file if we aren't going to read the
980 V2 or BNU files. */
981 fmore = FALSE;
982#if HAVE_V2_CONFIG
983 if (fV2)
984 fmore = TRUE;
985#endif
986#if HAVE_BNU_CONFIG
987 if (fBnu)
988 fmore = TRUE;
989#endif
990 if (! fmore)
991 {
992 ulog (LOG_ERROR, "%s%s: file not found", NEWCONFIGLIB,
993 SYSFILE);
994 return;
995 }
996 }
997 else
998 {
999 struct smulti_file *qmulti;
1000 int calc;
1001 boolean fdefaults, fsystem;
1002 struct ssysteminfo *qalternates;
1003
1004 qmulti = qmulti_open (zSysfile);
1005 if (qmulti != NULL)
1006 {
1007 calc = 0;
1008 fdefaults = FALSE;
1009 fsystem = FALSE;
1010 qalternates = NULL;
1011
1012 fIfirst = FALSE;
1013 zInext_system = NULL;
1014
1015 while (TRUE)
1016 {
1017 qIalternates = qalternates;
1018 fIdefault_alternates = TRUE;
1019
1020 /* Read commands. This will exit when it encounters the
1021 start of a file (which it will when we first start
1022 reading) and when it reads a ``system'' command. */
1023 uprocesscmds ((FILE *) NULL, qmulti, asIcmds,
1024 (const char *) NULL,
1025 CMDFLAG_WARNUNRECOG | CMDFLAG_BACKSLASH);
1026
1027 /* The handling of alternates can get complex. Before
1028 we start reading a system, fIclear_alternate is set
1029 to TRUE (this is done in uiset_clear). After we have
1030 finished reading a system, then if fIclear_alternate
1031 is still TRUE then no ``alternate'' command was used
1032 and the system information is in sIhold. Otherwise,
1033 if fIclear_alternate is FALSE, an ``alternate''
1034 command was used and we must call tialternate one
1035 more time; after this final call to tialternate, the
1036 system information will be in sIalternate.
1037
1038 The final call to tialternate is needed because each
1039 occurrence of the ``alternate'' command links the
1040 previous alternate into sIalternate and sets up
1041 sIhold with the defaults for the next alternate. The
1042 final call will link the last alternate into
1043 sIalternate. */
1044
1045 if (fdefaults)
1046 {
1047 /* We were reading default information. Save it. */
1048 if (fIclear_alternate)
1049 sIdefault = sIhold;
1050 else
1051 {
1052 (void) tialternate (0, (char **) NULL,
1053 (pointer) NULL, "alternate");
1054 sIdefault = sIalternate;
1055 }
1056 qalternates = sIdefault.qalternate;
1057 sIdefault.qalternate = NULL;
1058 fdefaults = FALSE;
1059 }
1060 else if (fsystem)
1061 {
1062 /* We just either finished a file or encountered a
1063 ``system'' command after we had started reading a
1064 system. Finish up the information for the system
1065 we were reading. */
1066 if (cIsystems >= calc)
1067 {
1068 calc += 10;
1069 pasIsystems =
1070 ((struct ssysteminfo *)
1071 xrealloc ((pointer) pasIsystems,
1072 calc * sizeof (struct ssysteminfo)));
1073 }
1074
1075 /* We must now attach any remaining default
1076 alternates. */
1077 if (fIdefault_alternates)
1078 {
1079 while (qIalternates != NULL)
1080 (void) tialternate (0, (char **) NULL,
1081 (pointer) NULL, "alternate");
1082 }
1083
1084 if (fIclear_alternate)
1085 pasIsystems[cIsystems] = sIhold;
1086 else
1087 {
1088 (void) tialternate (0, (char **) NULL,
1089 (pointer) NULL, "alternate");
1090 pasIsystems[cIsystems] = sIalternate;
1091 }
1092
1093 ++cIsystems;
1094
1095 fsystem = FALSE;
1096 }
1097
1098 if (fIfirst)
1099 {
1100 /* We just started reading a new file. Reset the
1101 default information. The next time around the
1102 loop we will read the default information. */
1103 uset_system_defaults (&sIhold);
1104 uiset_clear (FALSE);
1105 qalternates = NULL;
1106 fdefaults = TRUE;
1107 fIfirst = FALSE;
1108 }
1109 else if (zInext_system != NULL)
1110 {
1111 /* We just encountered a ``system'' command. Save
1112 the name, reset the system information to the
1113 defaults, and go on to read the system
1114 information. */
1115 sIhold = sIdefault;
1116 sIhold.zname = zInext_system;
1117 uiset_clear (FALSE);
1118 fsystem = TRUE;
1119 zInext_system = NULL;
1120 }
1121 else
1122 {
1123 /* We have reached the end of the files to read. */
1124 break;
1125 }
1126 }
1127
1128 (void) fmulti_close (qmulti);
1129 }
1130 }
1131#endif /* HAVE_TAYLOR_CONFIG */
1132
1133#if HAVE_V2_CONFIG
1134 if (fV2)
1135 {
1136 int cv2;
1137 struct ssysteminfo *pasv2;
1138
1139 uv2_read_systems (&cv2, &pasv2);
1140 if (cv2 > 0)
1141 {
1142 pasIsystems =
1143 ((struct ssysteminfo *)
1144 xrealloc ((pointer) pasIsystems,
1145 (cIsystems + cv2) * sizeof (struct ssysteminfo)));
1146 memcpy (pasIsystems + cIsystems, pasv2,
1147 cv2 * sizeof (struct ssysteminfo));
1148 cIsystems += cv2;
1149 }
1150 }
1151#endif /* HAVE_V2_CONFIG */
1152
1153#if HAVE_BNU_CONFIG
1154 if (fBnu)
1155 {
1156 int cbnu;
1157 struct ssysteminfo *pasbnu;
1158
1159 ubnu_read_systems (&cbnu, &pasbnu);
1160 if (cbnu > 0)
1161 {
1162 pasIsystems =
1163 ((struct ssysteminfo *)
1164 xrealloc ((pointer) pasIsystems,
1165 (cIsystems + cbnu) * sizeof (struct ssysteminfo)));
1166 memcpy (pasIsystems + cIsystems, pasbnu,
1167 cbnu * sizeof (struct ssysteminfo));
1168 cIsystems += cbnu;
1169 }
1170 }
1171#endif /* HAVE_BNU_CONFIG */
1172}
1173
1174/* Get information about all systems. */
1175
1176void
1177uread_all_system_info (pc, ppas)
1178 int *pc;
1179 struct ssysteminfo **ppas;
1180{
1181 if (! fIhave_systems)
1182 uiread_systems ();
1183
1184 *pc = cIsystems;
1185 *ppas = pasIsystems;
1186}
1187
1188/* Get information about a specific system. */
1189
1190boolean
1191fread_system_info (zsystem, qsys)
1192 const char *zsystem;
1193 struct ssysteminfo *qsys;
1194{
1195 int i;
1196
1197 DEBUG_MESSAGE1 (DEBUG_CONFIG,
1198 "fread_system_info: Reading information for system %s",
1199 zsystem);
1200
1201 if (! fIhave_systems)
1202 uiread_systems ();
1203
1204 for (i = 0; i < cIsystems; i++)
1205 {
1206 char *z;
1207
1208 if (strcmp (zsystem, pasIsystems[i].zname) == 0)
1209 {
1210 *qsys = pasIsystems[i];
1211
1212 DEBUG_MESSAGE1 (DEBUG_CONFIG,
1213 "fread_system_info: Got information for system %s",
1214 qsys->zname);
1215
1216 return TRUE;
1217 }
1218
1219 z = pasIsystems[i].zalias;
1220 if (z == NULL)
1221 continue;
1222 while (TRUE)
1223 {
1224 char *znext;
1225
1226 znext = z + strcspn (z, " ");
1227 if (strncmp (zsystem, z, znext - z) == 0)
1228 {
1229 *qsys = pasIsystems[i];
1230
1231 DEBUG_MESSAGE1 (DEBUG_CONFIG,
1232 "fread_system_info: Got system %s",
1233 qsys->zname);
1234
1235 return TRUE;
1236 }
1237 z = znext;
1238 if (*z == ' ')
1239 ++z;
1240 else
1241 break;
1242 }
1243 }
1244
1245 DEBUG_MESSAGE1 (DEBUG_CONFIG,
1246 "fread_system_info: Could not find system %s",
1247 zsystem);
1248
1249 return FALSE;
1250}
1251\f
1252/* Prepare to read commands defining unknown systems. */
1253
1254void
1255uiunknown_start ()
1256{
1257#if HAVE_TAYLOR_CONFIG
1258 uset_system_defaults (&sIhold);
1259 uiset_clear (FALSE);
1260#else /* ! HAVE_TAYLOR_CONFIG */
1261 uset_system_defaults (&sUnknown);
1262#endif /* ! HAVE_TAYLOR_CONFIG */
1263}
1264
1265#if HAVE_TAYLOR_CONFIG
1266
1267/* Process a command defining unknown systems. This is actually
1268 called from the main configuration file, not the system file. */
1269
1270enum tcmdtabret
1271tiunknown (argc, argv, pvar, zerr)
1272 int argc;
1273 char **argv;
1274 pointer pvar;
1275 const char *zerr;
1276{
1277 fUnknown_ok = TRUE;
1278 return tprocess_one_cmd (argc - 1, argv + 1, asIcmds, zerr,
1279 CMDFLAG_WARNUNRECOG);
1280}
1281
1282#endif /* HAVE_TAYLOR_CONFIG */
1283
1284/* Finish up after all commands defining unknwon systems. */
1285
1286void
1287uiunknown_end ()
1288{
1289#if HAVE_TAYLOR_CONFIG
1290 if (fUnknown_ok)
1291 {
1292 /* Add the final alternate. */
1293 if (fIclear_alternate)
1294 sUnknown = sIhold;
1295 else
1296 {
1297 (void) tialternate (0, (char **) NULL, (pointer) NULL, "alternate");
1298 sUnknown = sIalternate;
1299 }
1300 }
1301#endif /* HAVE_TAYLOR_CONFIG */
1302}
1303\f
1304/* Initialize the local system information. Perhaps it would be
1305 desirable to allow the user to customize this as well. This is
1306 called after the configuration file has been read in and the system
1307 name has been determined. Only a few elements of this structure
1308 are ever actually used, probably just zname and zremote_receive. */
1309
1310void
1311uisetup_localsys ()
1312{
1313 uset_system_defaults (&sLocalsys);
1314 sLocalsys.zname = zLocalname;
1315}
1316\f
1317/* Translate a system name into something we can use locally. This should
1318 be more intelligent than it is. Right now we just truncate the name;
1319 if this matches the name of another system, we reject the call. */
1320
1321const char *
1322ztranslate_system (zsystem)
1323 const char *zsystem;
1324{
1325 char *z;
1326 struct ssysteminfo s;
1327
1328 if (strlen (zsystem) <= cSysdep_max_name_len)
1329 return zsystem;
1330 z = (char *) xmalloc (cSysdep_max_name_len + 1);
1331 strncpy (z, zsystem, cSysdep_max_name_len);
1332 z[cSysdep_max_name_len] = '\0';
1333 if (fread_system_info (z, &s))
1334 {
1335 xfree ((pointer) z);
1336 return NULL;
1337 }
1338 return z;
1339}
1340\f
1341#if HAVE_TAYLOR_CONFIG
1342
1343/* Get the login name and password for a system out of the call file.
1344 The call file is simple a sequence of lines. The first word on
1345 each line is the system name, the second word is the login name,
1346 and the third word is the password. We read it using uprocesscmds,
1347 since it's easy. */
1348
1349struct silogpass
1350{
1351 char **pzlog;
1352 char **pzpass;
1353};
1354
1355static enum tcmdtabret tilog_pass P((int argc, char **argv, pointer pvar,
1356 const char *zerr));
1357
1358/*ARGSUSED*/
1359static enum tcmdtabret
1360tilog_pass (argc, argv, pvar, zerr)
1361 int argc;
1362 char **argv;
1363 pointer pvar;
1364 const char *zerr;
1365{
1366 struct silogpass *q = (struct silogpass *) pvar;
1367
1368 *q->pzlog = xstrdup (argv[1]);
1369 *q->pzpass = xstrdup (argv[2]);
1370 return CMDTABRET_FREE_AND_EXIT;
1371}
1372
1373#endif /* HAVE_TAYLOR_CONFIG */
1374
1375/* Get the login name and password to use for a system. */
1376
1377boolean
1378fcallout_login (qsys, pzlog, pzpass)
1379 const struct ssysteminfo *qsys;
1380 char **pzlog;
1381 char **pzpass;
1382{
1383 *pzlog = NULL;
1384 *pzpass = NULL;
1385
1386#if HAVE_TAYLOR_CONFIG
1387 {
1388 struct smulti_file *qmulti;
1389 struct scmdtab as[2];
1390 struct silogpass s;
1391
1392 qmulti = qmulti_open (zCallfile);
1393 if (qmulti == NULL)
1394 return FALSE;
1395
1396 s.pzlog = pzlog;
1397 s.pzpass = pzpass;
1398
1399 as[0].zcmd = qsys->zname;
1400 as[0].itype = CMDTABTYPE_FN | 3;
1401 as[0].pvar = (pointer)&s;
1402 as[0].ptfn = tilog_pass;
1403
1404 as[1].zcmd = NULL;
1405
1406 uprocesscmds ((FILE *) NULL, qmulti, as, (const char *) NULL,
1407 CMDFLAG_BACKSLASH);
1408
1409 (void) fmulti_close (qmulti);
1410 }
1411#endif /* HAVE_TAYLOR_CONFIG */
1412
1413 if (*pzlog == NULL)
1414 {
1415 ulog (LOG_ERROR, "No call out login for system %s", qsys->zname);
1416 return FALSE;
1417 }
1418
1419 return TRUE;
1420}
1421\f
1422#if HAVE_TAYLOR_CONFIG
1423
1424/* Check whether a login name and password gathered by the UUCP program
1425 itself are correct. */
1426
1427static enum tcmdtabret ticheck_login P((int argc, char **argv,
1428 pointer pvar, const char *zerr));
1429
1430/*ARGSUSED*/
1431static enum tcmdtabret
1432ticheck_login (argc, argv, pvar, zerr)
1433 int argc;
1434 char **argv;
1435 pointer pvar;
1436 const char *zerr;
1437{
1438 char **pz = (char **) pvar;
1439
1440 *pz = xstrdup (argv[1]);
1441 return CMDTABRET_FREE_AND_EXIT;
1442}
1443
1444#endif /* HAVE_TAYLOR_CONFIG */
1445
1446boolean
1447fcheck_login (zuser, zpass)
1448 const char *zuser;
1449 const char *zpass;
1450{
1451#if HAVE_TAYLOR_CONFIG
1452 struct smulti_file *qmulti;
1453 struct scmdtab as[2];
1454 char *zfilepass;
1455 boolean fok;
1456
1457 if (zPwdfile == NULL)
1458 {
1459 ulog (LOG_ERROR, "%s%s: file not found", NEWCONFIGLIB,
1460 PASSWDFILE);
1461 return FALSE;
1462 }
1463
1464 qmulti = qmulti_open (zPwdfile);
1465 if (qmulti == NULL)
1466 return FALSE;
1467
1468 zfilepass = NULL;
1469
1470 as[0].zcmd = zuser;
1471 as[0].itype = CMDTABTYPE_FN | 2;
1472 as[0].pvar = (pointer)&zfilepass;
1473 as[0].ptfn = ticheck_login;
1474
1475 as[1].zcmd = NULL;
1476
1477 uprocesscmds ((FILE *) NULL, qmulti, as, (const char *) NULL,
1478 CMDFLAG_CASESIGNIFICANT | CMDFLAG_BACKSLASH);
1479
1480 (void) fmulti_close (qmulti);
1481
1482 fok = zfilepass != NULL && strcmp (zfilepass, zpass) == 0;
1483
1484 if (zfilepass != NULL)
1485 {
1486 bzero (zfilepass, strlen (zfilepass));
1487 xfree ((pointer) zfilepass);
1488 }
1489
1490 if (! fok)
1491 ulog (LOG_ERROR, "Bad login");
1492
1493 return fok;
1494
1495#else /* HAVE_TAYLOR_CONFIG */
1496
1497 ulog (LOG_ERROR, "Not compiled to accept logins");
1498 return FALSE;
1499
1500#endif /* HAVE_TAYLOR_CONFIG */
1501}
1502\f
1503#if HAVE_TAYLOR_CONFIG
1504
1505/* Process a chat command. These are done as prefix commands. We set
1506 it up such that argv[0] will contain the string "chat" and we must
1507 look after that point to see what command to execute. */
1508
1509static struct schat_info sChat;
1510
1511static enum tcmdtabret tcchat_fail P((int argc, char **argv,
1512 pointer pvar,
1513 const char *zerr));
1514
1515static const struct scmdtab asChatcmds[] =
1516{
1517 { "chat", CMDTABTYPE_FULLSTRING, (pointer) &sChat.zchat, NULL },
1518 { "chat-program", CMDTABTYPE_FULLSTRING, (pointer) &sChat.zprogram,
1519 NULL },
1520 { "chat-timeout", CMDTABTYPE_INT, (pointer) &sChat.ctimeout, NULL },
1521 { "chat-fail", CMDTABTYPE_FN | 2, NULL, tcchat_fail },
1522 { "chat-seven-bit", CMDTABTYPE_BOOLEAN, (pointer) &sChat.fstrip, NULL },
1523 { NULL, 0, NULL, NULL }
1524};
1525
1526enum tcmdtabret
1527tprocess_chat_cmd (argc, argv, pvar, zerr)
1528 int argc;
1529 char **argv;
1530 pointer pvar;
1531 const char *zerr;
1532{
1533 struct schat_info *qchat = (struct schat_info *) pvar;
1534 char *zchat;
1535 enum tcmdtabret t;
1536
1537 zchat = strstr (argv[0], "chat");
1538
1539#if DEBUG > 0
1540 if (zchat == NULL)
1541 ulog (LOG_FATAL, "tprocess_chat_cmd: Can't happen");
1542#endif
1543
1544 argv[0] = zchat;
1545
1546 sChat = *qchat;
1547 t = tprocess_one_cmd (argc, argv, asChatcmds, zerr,
1548 CMDFLAG_WARNUNRECOG);
1549 *qchat = sChat;
1550
1551 return t;
1552}
1553
1554/* Add a new chat failure string. */
1555
1556static enum tcmdtabret
1557tcchat_fail (argc, argv, pvar, zerr)
1558 int argc;
1559 char **argv;
1560 pointer pvar;
1561 const char *zerr;
1562{
1563 uadd_string (&sChat.zfail, argv[1], ' ');
1564 return CMDTABRET_FREE;
1565}
1566
1567#endif /* HAVE_TAYLOR_CONFIG */
1568\f
1569#if HAVE_TAYLOR_CONFIG
1570
1571/* Add a protocol parameter entry. The pc parameter points to the
1572 number of protocol parameter entries, and the pq parameter points
1573 to the array of protocol parameters. */
1574
1575enum tcmdtabret
1576tadd_proto_param (pc, pq, zerr, cargs, azargs)
1577 int *pc;
1578 struct sproto_param **pq;
1579 const char *zerr;
1580 int cargs;
1581 char **azargs;
1582{
1583 int i;
1584 struct sproto_param *q;
1585 int ientry;
1586 int icopy;
1587
1588 if (cargs < 1)
1589 {
1590 ulog (LOG_ERROR, "%s: protocol-parameter: Not enough arguments", zerr);
1591 return CMDTABRET_FREE;
1592 }
1593 if (azargs[0][1] != '\0')
1594 {
1595 ulog (LOG_ERROR,
1596 "%s: protocol-parameter: Protocol names are single characters",
1597 zerr);
1598 return CMDTABRET_FREE;
1599 }
1600
1601 q = NULL;
1602 ientry = 0;
1603
1604 for (i = 0; i < *pc; i++)
1605 {
1606 if ((*pq)[i].bproto == azargs[0][0])
1607 {
1608 q = &(*pq)[i];
1609 ientry = q->centries;
1610 ++q->centries;
1611 q->qentries =
1612 ((struct sproto_param_entry *)
1613 xrealloc ((pointer) q->qentries,
1614 (q->centries * sizeof (struct sproto_param_entry))));
1615 break;
1616 }
1617 }
1618
1619 if (i >= *pc)
1620 {
1621 ++(*pc);
1622 *pq = ((struct sproto_param *)
1623 xrealloc ((pointer) *pq,
1624 (*pc * sizeof (struct sproto_param))));
1625 q = &(*pq)[*pc - 1];
1626 q->bproto = azargs[0][0];
1627 q->centries = 1;
1628 q->qentries = ((struct sproto_param_entry *)
1629 xmalloc (sizeof (struct sproto_param_entry)));
1630 ientry = 0;
1631 }
1632
1633 q->qentries[ientry].cargs = cargs - 1;
1634 q->qentries[ientry].azargs =
1635 (char **) xmalloc ((cargs - 1) * sizeof (char *));
1636 for (icopy = 0; icopy < cargs - 1; icopy++)
1637 q->qentries[ientry].azargs[icopy] = azargs[icopy + 1];
1638
1639 return CMDTABRET_CONTINUE;
1640}
1641
1642#endif /* HAVE_TAYLOR_CONFIG */
1643
1644/* Apply some protocol parameters, given the current protocol. */
1645
1646void
1647uapply_proto_params (bproto, qcmds, c, pas)
1648 int bproto;
1649 struct scmdtab *qcmds;
1650 int c;
1651 struct sproto_param *pas;
1652{
1653 int i;
1654 struct sproto_param *q;
1655
1656 for (i = 0, q = pas;
1657 i < c;
1658 i++, q++)
1659 {
1660 if (q->bproto == (char) bproto)
1661 {
1662 char ab[sizeof "g protocol parameters"];
1663 struct sproto_param_entry *qentry;
1664 int ientry;
1665
1666 sprintf (ab, "%c protocol parameters", bproto);
1667 q = &pas[i];
1668 for (ientry = 0, qentry = &q->qentries[0];
1669 ientry < q->centries;
1670 ientry++, qentry++)
1671 (void) tprocess_one_cmd (qentry->cargs, qentry->azargs,
1672 qcmds, ab, CMDFLAG_WARNUNRECOG);
1673 return;
1674 }
1675 }
1676}
1677\f
1678/* Maintain a list of systems which are permitted to log in using a
1679 particular login name. This is the VALIDATE entry from the BNU
1680 Permissions file. */
1681
1682static struct svalidate
1683{
1684 struct svalidate *qnext;
1685 const char *zlogname;
1686 int cmachines;
1687 const char *azmachines[1];
1688} *qIvalidate;
1689
1690/* Add an entry to the validation list. This assumes that it does not
1691 have to copy the login name or the machine names. It does copy the
1692 array of machines names. */
1693
1694void
1695uadd_validate (zlogname, cmachines, pazmachines)
1696 const char *zlogname;
1697 int cmachines;
1698 const char **pazmachines;
1699{
1700 struct svalidate **pq, *q;
1701
1702 for (pq = &qIvalidate; *pq != NULL; pq = &(*pq)->qnext)
1703 {
1704 if (strcmp ((*pq)->zlogname, zlogname) == 0)
1705 {
1706 *pq = ((struct svalidate *)
1707 xrealloc ((pointer) *pq,
1708 sizeof (struct svalidate)
1709 + (((*pq)->cmachines + cmachines - 1)
1710 * sizeof (const char *))));
1711 memcpy ((*pq)->azmachines + (*pq)->cmachines, pazmachines,
1712 cmachines * sizeof (const char *));
1713 (*pq)->cmachines += cmachines;
1714 return;
1715 }
1716 }
1717
1718 q = (struct svalidate *) xmalloc (sizeof (struct svalidate)
1719 + ((cmachines - 1)
1720 * sizeof (const char *)));
1721 q->qnext = qIvalidate;
1722 q->zlogname = zlogname;
1723 memcpy (q->azmachines, pazmachines,
1724 cmachines * sizeof (const char *));
1725 q->cmachines = cmachines;
1726 qIvalidate = q;
1727}
1728
1729/* Check whether a particular login name/machine name is valid. */
1730
1731boolean
1732fcheck_validate (zlogname, zmachine)
1733 const char *zlogname;
1734 const char *zmachine;
1735{
1736 struct svalidate *q;
1737
1738 for (q = qIvalidate; q != NULL; q = q->qnext)
1739 {
1740 if (strcmp (q->zlogname, zlogname) == 0)
1741 {
1742 int i;
1743
1744 for (i = 0; i < q->cmachines; i++)
1745 if (strcmp (q->azmachines[i], zmachine) == 0)
1746 return TRUE;
1747
1748 return FALSE;
1749 }
1750 }
1751
1752 return TRUE;
1753}
1754\f
1755/* The variables which hold the array of timetables. */
1756
1757int cTtable;
1758struct stimetable *pasTtable;
1759
1760/* Initialize the table of timetables as advertised in the
1761 documentation. */
1762
1763void
1764uinittimetables ()
1765{
1766 pasTtable = (struct stimetable *) xmalloc (3 * sizeof (struct stimetable));
1767 pasTtable[0].zname = "Evening";
1768 pasTtable[0].ztime = "Wk1705-0755,Sa,Su";
1769 pasTtable[1].zname = "Night";
1770 pasTtable[1].ztime = "Wk2305-0755,Sa,Su2305-1655";
1771 pasTtable[2].zname = "NonPeak";
1772 pasTtable[2].ztime = "Wk1805-0655,Sa,Su";
1773 cTtable = 3;
1774}
1775
1776/* Add a new timetable entry. This assumes it can take control of the
1777 strings it is passed, so they must not be on the stack and if they
1778 have been allocated they must not be freed. */
1779
1780void
1781uaddtimetable (zname, ztime)
1782 const char *zname;
1783 const char *ztime;
1784{
1785 if (pasTtable == NULL)
1786 uinittimetables ();
1787
1788 pasTtable = ((struct stimetable *)
1789 xrealloc ((pointer) pasTtable,
1790 (cTtable + 1) * sizeof (struct stimetable)));
1791 pasTtable[cTtable].zname = zname;
1792 pasTtable[cTtable].ztime = ztime;
1793 ++cTtable;
1794}