xref: /386bsd/usr/src/libexec/uucp/sysinf.c (revision a2142627)
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
103 char 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 
113 /* Whether we accept calls from unknown systems.  */
114 boolean fUnknown_ok = FALSE;
115 
116 /* Information we hold for an unknown system.  */
117 struct ssysteminfo sUnknown;
118 
119 /* Information we hold for the local system.  */
120 struct ssysteminfo sLocalsys;
121 
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.  */
130 static 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.  */
134 static boolean fIfirst;
135 
136 /* This structure holds system information as it is gathered.  */
137 static struct ssysteminfo sIhold;
138 
139 /* Default information.  */
140 static struct ssysteminfo sIdefault;
141 
142 /* The name of the next system.  */
143 static char *zInext_system;
144 
145 /* The list of alternates to draw from.  */
146 static struct ssysteminfo *qIalternates;
147 
148 /* Whether to use default alternates.  */
149 static 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.  */
161 static boolean fIclear_alias;
162 static boolean fIclear_alternate;
163 static boolean fIclear_time;
164 static boolean fIclear_calltimegrade;
165 static boolean fIclear_call_local_size;
166 static boolean fIclear_call_remote_size;
167 static boolean fIclear_called_local_size;
168 static boolean fIclear_called_remote_size;
169 static boolean fIclear_port;
170 static boolean fIclear_chat_fail;
171 static boolean fIclear_proto_param;
172 static 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 
179 CMDTABFN (ticlear);
180 CMDTABFN (tisystem);
181 CMDTABFN (tialias);
182 CMDTABFN (tialternate);
183 CMDTABFN (titime);
184 CMDTABFN (titimegrade);
185 CMDTABFN (ticall_local_size);
186 CMDTABFN (ticall_remote_size);
187 CMDTABFN (ticalled_local_size);
188 CMDTABFN (ticalled_remote_size);
189 CMDTABFN (titimetable);
190 CMDTABFN (tiport);
191 CMDTABFN (tichat);
192 CMDTABFN (ticalled_login);
193 CMDTABFN (tiproto_param);
194 CMDTABFN (tirequest);
195 CMDTABFN (titransfer);
196 
197 #undef CMDTABFN
198 
199 /* The commands accepted from the system information file.  */
200 
201 static 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 
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*/
271 static enum tcmdtabret
ticlear(argc,argv,pvar,zerr)272 ticlear (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*/
286 static enum tcmdtabret
tisystem(argc,argv,pvar,zerr)287 tisystem (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*/
329 static enum tcmdtabret
tialias(argc,argv,pvar,zerr)330 tialias (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 
353 static struct ssysteminfo sIalternate;
354 
355 /*ARGSUSED*/
356 static enum tcmdtabret
tialternate(argc,argv,pvar,zerr)357 tialternate (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*/
462 static enum tcmdtabret
titime(argc,argv,pvar,zerr)463 titime (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 
485 static enum tcmdtabret
titimegrade(argc,argv,pvar,zerr)486 titimegrade (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 
549 static enum tcmdtabret tiadd_size P((int argc, char **argv,
550 				     const char *zerr, boolean *pf,
551 				     char **pz));
552 
553 static enum tcmdtabret
tiadd_size(argc,argv,zerr,pf,pz)554 tiadd_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*/
591 static enum tcmdtabret
ticall_local_size(argc,argv,pvar,zerr)592 ticall_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*/
605 static enum tcmdtabret
ticall_remote_size(argc,argv,pvar,zerr)606 ticall_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*/
619 static enum tcmdtabret
ticalled_local_size(argc,argv,pvar,zerr)620 ticalled_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*/
633 static enum tcmdtabret
ticalled_remote_size(argc,argv,pvar,zerr)634 ticalled_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*/
647 static enum tcmdtabret
titimetable(argc,argv,pvar,zerr)648 titimetable (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*/
661 static enum tcmdtabret
tiport(argc,argv,pvar,zerr)662 tiport (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 
738 static enum tcmdtabret
tichat(argc,argv,pvar,zerr)739 tichat (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*/
768 static enum tcmdtabret
ticalled_login(argc,argv,pvar,zerr)769 ticalled_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*/
792 static enum tcmdtabret
tiproto_param(argc,argv,pvar,zerr)793 tiproto_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*/
813 static enum tcmdtabret
tirequest(argc,argv,pvar,zerr)814 tirequest (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*/
843 static enum tcmdtabret
titransfer(argc,argv,pvar,zerr)844 titransfer (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 
874 static void
uiset_clear(falternate)875 uiset_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 
897 /* Set up the default values advertised in the documentation.  */
898 
899 void
uset_system_defaults(qsys)900 uset_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 
956 /* Variables to store the loaded system information.  */
957 
958 static boolean fIhave_systems;
959 static int cIsystems;
960 static struct ssysteminfo *pasIsystems;
961 
962 /* Read information about all systems.  */
963 
964 static void uiread_systems P((void));
965 
966 static void
uiread_systems()967 uiread_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 
1176 void
uread_all_system_info(pc,ppas)1177 uread_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 
1190 boolean
fread_system_info(zsystem,qsys)1191 fread_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 
1252 /* Prepare to read commands defining unknown systems.  */
1253 
1254 void
uiunknown_start()1255 uiunknown_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 
1270 enum tcmdtabret
tiunknown(argc,argv,pvar,zerr)1271 tiunknown (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 
1286 void
uiunknown_end()1287 uiunknown_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 
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 
1310 void
uisetup_localsys()1311 uisetup_localsys ()
1312 {
1313   uset_system_defaults (&sLocalsys);
1314   sLocalsys.zname = zLocalname;
1315 }
1316 
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 
1321 const char *
ztranslate_system(zsystem)1322 ztranslate_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 
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 
1349 struct silogpass
1350 {
1351   char **pzlog;
1352   char **pzpass;
1353 };
1354 
1355 static enum tcmdtabret tilog_pass P((int argc, char **argv, pointer pvar,
1356 				     const char *zerr));
1357 
1358 /*ARGSUSED*/
1359 static enum tcmdtabret
tilog_pass(argc,argv,pvar,zerr)1360 tilog_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 
1377 boolean
fcallout_login(qsys,pzlog,pzpass)1378 fcallout_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 
1422 #if HAVE_TAYLOR_CONFIG
1423 
1424 /* Check whether a login name and password gathered by the UUCP program
1425    itself are correct.  */
1426 
1427 static enum tcmdtabret ticheck_login P((int argc, char **argv,
1428 					pointer pvar, const char *zerr));
1429 
1430 /*ARGSUSED*/
1431 static enum tcmdtabret
ticheck_login(argc,argv,pvar,zerr)1432 ticheck_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 
1446 boolean
fcheck_login(zuser,zpass)1447 fcheck_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 
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 
1509 static struct schat_info sChat;
1510 
1511 static enum tcmdtabret tcchat_fail P((int argc, char **argv,
1512 				      pointer pvar,
1513 				      const char *zerr));
1514 
1515 static 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 
1526 enum tcmdtabret
tprocess_chat_cmd(argc,argv,pvar,zerr)1527 tprocess_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 
1556 static enum tcmdtabret
tcchat_fail(argc,argv,pvar,zerr)1557 tcchat_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 
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 
1575 enum tcmdtabret
tadd_proto_param(pc,pq,zerr,cargs,azargs)1576 tadd_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 
1646 void
uapply_proto_params(bproto,qcmds,c,pas)1647 uapply_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 
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 
1682 static 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 
1694 void
uadd_validate(zlogname,cmachines,pazmachines)1695 uadd_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 
1731 boolean
fcheck_validate(zlogname,zmachine)1732 fcheck_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 
1755 /* The variables which hold the array of timetables.  */
1756 
1757 int cTtable;
1758 struct stimetable *pasTtable;
1759 
1760 /* Initialize the table of timetables as advertised in the
1761    documentation.  */
1762 
1763 void
uinittimetables()1764 uinittimetables ()
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 
1780 void
uaddtimetable(zname,ztime)1781 uaddtimetable (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 }
1795