1 /* tsinfo.c
2    Get information about a system from the Taylor UUCP configuration files.
3 
4    Copyright (C) 1992, 1993, 1995, 2002 Ian Lance Taylor
5 
6    This file is part of the Taylor UUCP uuconf library.
7 
8    This library is free software; you can redistribute it and/or
9    modify it under the terms of the GNU Library General Public License
10    as published by the Free Software Foundation; either version 2 of
11    the License, or (at your option) any later version.
12 
13    This library 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    Library General Public License for more details.
17 
18    You should have received a copy of the GNU Library General Public
19    License along with this library; if not, write to the Free Software
20    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
21 
22    The author of the program may be contacted at ian@airs.com.
23    */
24 
25 #include "uucnfi.h"
26 
27 #if USE_RCS_ID
28 const char _uuconf_tsinfo_rcsid[] = "$FreeBSD$";
29 #endif
30 
31 #include <errno.h>
32 #include <ctype.h>
33 
34 #ifndef SEEK_SET
35 #define SEEK_SET 0
36 #endif
37 
38 static void uiset_call P((struct uuconf_system *qsys));
39 static int iisizecmp P((long i1, long i2));
40 
41 /* Local functions needed to parse the system information file.  */
42 
43 #define CMDTABFN(z) \
44   static int z P((pointer, int, char **, pointer, pointer))
45 
46 CMDTABFN (iisystem);
47 CMDTABFN (iialias);
48 CMDTABFN (iialternate);
49 CMDTABFN (iidefault_alternates);
50 CMDTABFN (iitime);
51 CMDTABFN (iitimegrade);
52 CMDTABFN (iisize);
53 CMDTABFN (iibaud_range);
54 CMDTABFN (iiport);
55 CMDTABFN (iichat);
56 CMDTABFN (iidebug);
57 CMDTABFN (iicalled_login);
58 CMDTABFN (iiproto_param);
59 CMDTABFN (iirequest);
60 CMDTABFN (iitransfer);
61 CMDTABFN (iiforward);
62 CMDTABFN (iiunknown);
63 
64 #undef CMDTABFN
65 
66 /* We have to pass a fair amount of information in and out of the
67    various system commands.  Using global variables would make the
68    code non-reentrant, so we instead pass a pointer to single
69    structure as the pinfo argument to the system commands.  */
70 
71 struct sinfo
72 {
73   /* The system information we're building up.  */
74   struct uuconf_system *qsys;
75   /* Whether any alternates have been used.  */
76   boolean falternates;
77   /* A list of the previous alternates.  */
78   struct uuconf_system salternate;
79   /* Whether to use extra alternates from the file wide defaults.  */
80   int fdefault_alternates;
81 };
82 
83 /* The command table for system commands.  */
84 static const struct cmdtab_offset asIcmds[] =
85 {
86   { "system", UUCONF_CMDTABTYPE_FN | 2, (size_t) -1, iisystem },
87   { "alias", UUCONF_CMDTABTYPE_FN | 2, (size_t) -1, iialias },
88   { "alternate", UUCONF_CMDTABTYPE_FN | 0, (size_t) -1, iialternate },
89   { "default-alternates", UUCONF_CMDTABTYPE_FN | 2, (size_t) -1,
90       iidefault_alternates },
91   { "time", UUCONF_CMDTABTYPE_FN | 0,
92       offsetof (struct uuconf_system, uuconf_qtimegrade), iitime },
93   { "timegrade", UUCONF_CMDTABTYPE_FN | 0,
94       offsetof (struct uuconf_system, uuconf_qtimegrade), iitimegrade },
95   { "max-retries", UUCONF_CMDTABTYPE_INT,
96       offsetof (struct uuconf_system, uuconf_cmax_retries), NULL },
97   { "success-wait", UUCONF_CMDTABTYPE_INT,
98       offsetof (struct uuconf_system, uuconf_csuccess_wait), NULL },
99   { "call-timegrade", UUCONF_CMDTABTYPE_FN | 3,
100       offsetof (struct uuconf_system, uuconf_qcalltimegrade), iitimegrade },
101   { "called-timegrade", UUCONF_CMDTABTYPE_FN | 3,
102       offsetof (struct uuconf_system, uuconf_qcalledtimegrade), iitimegrade },
103   { "call-local-size", UUCONF_CMDTABTYPE_FN | 3,
104       offsetof (struct uuconf_system, uuconf_qcall_local_size), iisize },
105   { "call-remote-size", UUCONF_CMDTABTYPE_FN | 3,
106       offsetof (struct uuconf_system, uuconf_qcall_remote_size), iisize },
107   { "called-local-size", UUCONF_CMDTABTYPE_FN | 3,
108       offsetof (struct uuconf_system, uuconf_qcalled_local_size), iisize },
109   { "called-remote-size", UUCONF_CMDTABTYPE_FN | 3,
110       offsetof (struct uuconf_system, uuconf_qcalled_remote_size), iisize },
111   { "timetable", UUCONF_CMDTABTYPE_FN | 3, (size_t) -1, _uuconf_itimetable },
112   { "baud", UUCONF_CMDTABTYPE_LONG,
113       offsetof (struct uuconf_system, uuconf_ibaud), NULL },
114   { "speed", UUCONF_CMDTABTYPE_LONG,
115       offsetof (struct uuconf_system, uuconf_ibaud), NULL },
116   { "baud-range", UUCONF_CMDTABTYPE_FN | 3, 0, iibaud_range },
117   { "speed-range", UUCONF_CMDTABTYPE_FN | 3, 0, iibaud_range },
118   { "port", UUCONF_CMDTABTYPE_FN | 0, (size_t) -1, iiport },
119   { "phone", UUCONF_CMDTABTYPE_STRING,
120       offsetof (struct uuconf_system, uuconf_zphone), NULL },
121   { "address", UUCONF_CMDTABTYPE_STRING,
122       offsetof (struct uuconf_system, uuconf_zphone), NULL },
123   { "chat", UUCONF_CMDTABTYPE_PREFIX | 0,
124       offsetof (struct uuconf_system, uuconf_schat), iichat },
125   { "call-login", UUCONF_CMDTABTYPE_STRING,
126       offsetof (struct uuconf_system, uuconf_zcall_login), NULL },
127   { "call-password", UUCONF_CMDTABTYPE_STRING,
128       offsetof (struct uuconf_system, uuconf_zcall_password), NULL },
129   { "called-login", UUCONF_CMDTABTYPE_FN | 0,
130       offsetof (struct uuconf_system, uuconf_zcalled_login), iicalled_login },
131   { "callback", UUCONF_CMDTABTYPE_BOOLEAN,
132       offsetof (struct uuconf_system, uuconf_fcallback), NULL },
133   { "sequence", UUCONF_CMDTABTYPE_BOOLEAN,
134       offsetof (struct uuconf_system, uuconf_fsequence), NULL },
135   { "protocol", UUCONF_CMDTABTYPE_STRING,
136       offsetof (struct uuconf_system, uuconf_zprotocols), NULL },
137   { "protocol-parameter", UUCONF_CMDTABTYPE_FN | 0,
138       offsetof (struct uuconf_system, uuconf_qproto_params), iiproto_param },
139   { "called-chat", UUCONF_CMDTABTYPE_PREFIX | 0,
140       offsetof (struct uuconf_system, uuconf_scalled_chat), iichat },
141   { "debug", UUCONF_CMDTABTYPE_FN | 0,
142       offsetof (struct uuconf_system, uuconf_zdebug), iidebug },
143   { "max-remote-debug", UUCONF_CMDTABTYPE_STRING,
144       offsetof (struct uuconf_system, uuconf_zmax_remote_debug), NULL },
145   { "send-request", UUCONF_CMDTABTYPE_BOOLEAN,
146       offsetof (struct uuconf_system, uuconf_fsend_request), NULL },
147   { "receive-request", UUCONF_CMDTABTYPE_BOOLEAN,
148       offsetof (struct uuconf_system, uuconf_frec_request), NULL },
149   { "request", UUCONF_CMDTABTYPE_FN | 2, (size_t) -1, iirequest },
150   { "call-transfer", UUCONF_CMDTABTYPE_BOOLEAN,
151       offsetof (struct uuconf_system, uuconf_fcall_transfer), NULL },
152   { "called-transfer", UUCONF_CMDTABTYPE_BOOLEAN,
153       offsetof (struct uuconf_system, uuconf_fcalled_transfer), NULL },
154   { "transfer", UUCONF_CMDTABTYPE_FN | 2, (size_t) -1, iitransfer },
155   { "local-send", UUCONF_CMDTABTYPE_FULLSTRING,
156       offsetof (struct uuconf_system, uuconf_pzlocal_send), NULL },
157   { "remote-send", UUCONF_CMDTABTYPE_FULLSTRING,
158       offsetof (struct uuconf_system, uuconf_pzremote_send), NULL },
159   { "local-receive", UUCONF_CMDTABTYPE_FULLSTRING,
160       offsetof (struct uuconf_system, uuconf_pzlocal_receive), NULL },
161   { "remote-receive", UUCONF_CMDTABTYPE_FULLSTRING,
162       offsetof (struct uuconf_system, uuconf_pzremote_receive), NULL },
163   { "command-path", UUCONF_CMDTABTYPE_FULLSTRING,
164       offsetof (struct uuconf_system, uuconf_pzpath), NULL },
165   { "commands", UUCONF_CMDTABTYPE_FULLSTRING,
166       offsetof (struct uuconf_system, uuconf_pzcmds), NULL },
167   { "free-space", UUCONF_CMDTABTYPE_LONG,
168       offsetof (struct uuconf_system, uuconf_cfree_space), NULL },
169   { "forward-from", UUCONF_CMDTABTYPE_FULLSTRING,
170       offsetof (struct uuconf_system, uuconf_pzforward_from), NULL },
171   { "forward-to", UUCONF_CMDTABTYPE_FULLSTRING,
172       offsetof (struct uuconf_system, uuconf_pzforward_to), NULL },
173   { "forward", UUCONF_CMDTABTYPE_FN | 0, (size_t) -1, iiforward },
174   { "pubdir", UUCONF_CMDTABTYPE_STRING,
175       offsetof (struct uuconf_system, uuconf_zpubdir), NULL },
176   { "myname", UUCONF_CMDTABTYPE_STRING,
177       offsetof (struct uuconf_system, uuconf_zlocalname), NULL },
178   { "max-file-time", UUCONF_CMDTABTYPE_LONG,
179       offsetof (struct uuconf_system, uuconf_cmax_file_time), NULL },
180   { NULL, 0, 0, NULL }
181 };
182 
183 #define CSYSTEM_CMDS (sizeof asIcmds / sizeof asIcmds[0])
184 
185 /* Get information about the system zsystem from the Taylor UUCP
186    configuration files.  Sets *qsys.  This does not ensure that all
187    default information is set.  */
188 
189 int
_uuconf_itaylor_system_internal(qglobal,zsystem,qsys)190 _uuconf_itaylor_system_internal (qglobal, zsystem, qsys)
191      struct sglobal *qglobal;
192      const char *zsystem;
193      struct uuconf_system *qsys;
194 {
195   int iret;
196   struct stsysloc *qloc;
197   struct uuconf_cmdtab as[CSYSTEM_CMDS];
198   struct sinfo si;
199   struct uuconf_system sdefaults;
200 
201   if (! qglobal->qprocess->fread_syslocs)
202     {
203       iret = _uuconf_iread_locations (qglobal);
204       if (iret != UUCONF_SUCCESS)
205 	return iret;
206     }
207 
208   /* Find the system in the list of locations.  */
209   for (qloc = qglobal->qprocess->qsyslocs; qloc != NULL; qloc = qloc->qnext)
210     if (qloc->zname[0] == zsystem[0]
211 	&& strcmp (qloc->zname, zsystem) == 0)
212       break;
213   if (qloc == NULL)
214     return UUCONF_NOT_FOUND;
215 
216   /* If this is an alias, then the real system is the next non-alias
217      in the list.  */
218   while (qloc->falias)
219     {
220       qloc = qloc->qnext;
221       if (qloc == NULL)
222 	return UUCONF_NOT_FOUND;
223     }
224 
225   _uuconf_ucmdtab_base (asIcmds, CSYSTEM_CMDS, (char *) qsys, as);
226 
227   rewind (qloc->e);
228 
229   /* Read the file wide defaults from the start of the file.  */
230   _uuconf_uclear_system (qsys);
231 
232   si.qsys = qsys;
233   si.falternates = FALSE;
234   si.fdefault_alternates = TRUE;
235   qsys->uuconf_palloc = uuconf_malloc_block ();
236   if (qsys->uuconf_palloc == NULL)
237     {
238       qglobal->ierrno = errno;
239       return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
240     }
241 
242   iret = uuconf_cmd_file ((pointer) qglobal, qloc->e, as, (pointer) &si,
243 			  iiunknown, UUCONF_CMDTABFLAG_BACKSLASH,
244 			  qsys->uuconf_palloc);
245   if (iret != UUCONF_SUCCESS)
246     {
247       qglobal->zfilename = qloc->zfile;
248       return iret | UUCONF_ERROR_FILENAME;
249     }
250 
251   if (! si.falternates)
252     uiset_call (qsys);
253   else
254     {
255       /* Attach the final alternate.  */
256       iret = iialternate ((pointer) qglobal, 0, (char **) NULL,
257 			  (pointer) NULL, (pointer) &si);
258       if (iret != UUCONF_SUCCESS)
259 	return iret;
260     }
261 
262   /* Save off the defaults.  */
263   sdefaults = *qsys;
264 
265   /* Advance to the information for the system we want.  */
266   if (fseek (qloc->e, qloc->iloc, SEEK_SET) != 0)
267     {
268       qglobal->ierrno = errno;
269       qglobal->zfilename = qloc->zfile;
270       return (UUCONF_FSEEK_FAILED
271 	      | UUCONF_ERROR_ERRNO
272 	      | UUCONF_ERROR_FILENAME);
273     }
274 
275   /* Read in the system we want.  */
276   _uuconf_uclear_system (qsys);
277   qsys->uuconf_zname = (char *) qloc->zname;
278   qsys->uuconf_palloc = sdefaults.uuconf_palloc;
279 
280   si.falternates = FALSE;
281 
282   iret = uuconf_cmd_file (qglobal, qloc->e, as, (pointer) &si, iiunknown,
283 			  UUCONF_CMDTABFLAG_BACKSLASH, qsys->uuconf_palloc);
284   qglobal->ilineno += qloc->ilineno;
285 
286   if (iret == UUCONF_SUCCESS)
287     {
288       if (! si.falternates)
289 	uiset_call (qsys);
290       else
291 	iret = iialternate ((pointer) qglobal, 0, (char **) NULL,
292 			    (pointer) NULL, (pointer) &si);
293     }
294 
295   /* Merge in the defaults.  */
296   if (iret == UUCONF_SUCCESS)
297     iret = _uuconf_isystem_default (qglobal, qsys, &sdefaults,
298 				    si.fdefault_alternates);
299 
300   /* The first alternate is always available for calling in.  It is
301      always available for calling out if it has some way to choose a
302      port (this would normally be set by uiset_call anyhow, but it
303      won't be if all the port information comes from the defaults).  */
304   if (iret == UUCONF_SUCCESS)
305     {
306       qsys->uuconf_fcalled = TRUE;
307       if (qsys->uuconf_zport != (char *) &_uuconf_unset
308 	  || qsys->uuconf_qport != (struct uuconf_port *) &_uuconf_unset
309 	  || qsys->uuconf_ibaud >= 0
310 	  || qsys->uuconf_zphone != (char *) &_uuconf_unset)
311 	qsys->uuconf_fcall = TRUE;
312     }
313 
314   if (iret != UUCONF_SUCCESS)
315     {
316       qglobal->zfilename = qloc->zfile;
317       iret |= UUCONF_ERROR_FILENAME;
318     }
319 
320   return iret;
321 }
322 
323 /* Set the fcall and fcalled field for the system.  This marks a
324    particular alternate for use when calling out or calling in.  This
325    is where we implement the semantics described in the documentation:
326    a change to a relevant field implies that the alternate is used.
327    If all the relevant fields are unchanged, the alternate is not
328    used.  */
329 
330 static void
uiset_call(qsys)331 uiset_call (qsys)
332      struct uuconf_system *qsys;
333 {
334   qsys->uuconf_fcall =
335     (qsys->uuconf_qtimegrade != (struct uuconf_timespan *) &_uuconf_unset
336      || qsys->uuconf_zport != (char *) &_uuconf_unset
337      || qsys->uuconf_qport != (struct uuconf_port *) &_uuconf_unset
338      || qsys->uuconf_ibaud >= 0
339      || qsys->uuconf_zphone != (char *) &_uuconf_unset
340      || qsys->uuconf_schat.uuconf_pzchat != (char **) &_uuconf_unset
341      || qsys->uuconf_schat.uuconf_pzprogram != (char **) &_uuconf_unset);
342 
343   qsys->uuconf_fcalled =
344     qsys->uuconf_zcalled_login != (char *) &_uuconf_unset;
345 }
346 
347 /* Handle the "system" command.  Because we skip directly to the
348    system we want to read, a "system" command means we've reached the
349    end of it.  */
350 
351 static int
iisystem(pglobal,argc,argv,pvar,pinfo)352 iisystem (pglobal, argc, argv, pvar, pinfo)
353      pointer pglobal ATTRIBUTE_UNUSED;
354      int argc ATTRIBUTE_UNUSED;
355      char **argv ATTRIBUTE_UNUSED;
356      pointer pvar ATTRIBUTE_UNUSED;
357      pointer pinfo ATTRIBUTE_UNUSED;
358 {
359   return UUCONF_CMDTABRET_EXIT;
360 }
361 
362 /* Handle the "alias" command.  */
363 
364 /*ARGSUSED*/
365 static int
iialias(pglobal,argc,argv,pvar,pinfo)366 iialias (pglobal, argc, argv, pvar, pinfo)
367      pointer pglobal;
368      int argc ATTRIBUTE_UNUSED;
369      char **argv;
370      pointer pvar ATTRIBUTE_UNUSED;
371      pointer pinfo;
372 {
373   struct sglobal *qglobal = (struct sglobal *) pglobal;
374   struct sinfo *qinfo = (struct sinfo *) pinfo;
375   int iret;
376 
377   iret = _uuconf_iadd_string (qglobal, argv[1], TRUE, FALSE,
378 			      &qinfo->qsys->uuconf_pzalias,
379 			      qinfo->qsys->uuconf_palloc);
380   if (iret != UUCONF_SUCCESS)
381     iret |= UUCONF_CMDTABRET_EXIT;
382   return iret;
383 }
384 
385 /* Handle the "alternate" command.  The information just read is in
386    sIhold.  If this is the first "alternate" command for this system,
387    we save off the current information in sIalternate.  Otherwise we
388    default this information to sIalternate, and then add it to the end
389    of the list of alternates in sIalternate.  */
390 
391 static int
iialternate(pglobal,argc,argv,pvar,pinfo)392 iialternate (pglobal, argc, argv, pvar, pinfo)
393      pointer pglobal;
394      int argc;
395      char **argv;
396      pointer pvar ATTRIBUTE_UNUSED;
397      pointer pinfo;
398 {
399   struct sglobal *qglobal = (struct sglobal *) pglobal;
400   struct sinfo *qinfo = (struct sinfo *) pinfo;
401 
402   uiset_call (qinfo->qsys);
403 
404   if (! qinfo->falternates)
405     {
406       qinfo->salternate = *qinfo->qsys;
407       qinfo->falternates = TRUE;
408     }
409   else
410     {
411       int iret;
412       struct uuconf_system *qnew, **pq;
413 
414       iret = _uuconf_isystem_default (qglobal, qinfo->qsys,
415 				      &qinfo->salternate, FALSE);
416       if (iret != UUCONF_SUCCESS)
417 	return iret | UUCONF_CMDTABRET_EXIT;
418       qnew = ((struct uuconf_system *)
419 	      uuconf_malloc (qinfo->qsys->uuconf_palloc,
420 			      sizeof (struct uuconf_system)));
421       if (qnew == NULL)
422 	{
423 	  qglobal->ierrno = errno;;
424 	  return (UUCONF_MALLOC_FAILED
425 		  | UUCONF_ERROR_ERRNO
426 		  | UUCONF_CMDTABRET_EXIT);
427 	}
428       *qnew = *qinfo->qsys;
429       for (pq = &qinfo->salternate.uuconf_qalternate;
430 	   *pq != NULL;
431 	   pq = &(*pq)->uuconf_qalternate)
432 	;
433       *pq = qnew;
434     }
435 
436   /* If this is the last alternate command, move the information back
437      to qinfo->qsys.  */
438   if (argc == 0)
439     *qinfo->qsys = qinfo->salternate;
440   else
441     {
442       _uuconf_uclear_system (qinfo->qsys);
443       qinfo->qsys->uuconf_zname = qinfo->salternate.uuconf_zname;
444       qinfo->qsys->uuconf_palloc = qinfo->salternate.uuconf_palloc;
445       if (argc > 1)
446 	{
447 	  qinfo->qsys->uuconf_zalternate = argv[1];
448 	  return UUCONF_CMDTABRET_KEEP;
449 	}
450     }
451 
452   return UUCONF_CMDTABRET_CONTINUE;
453 }
454 
455 /* Handle the "default-alternates" command.  This just takes a boolean
456    argument which is used to set the fdefault_alternates field of the
457    sinfo structure.  */
458 
459 /*ARGSUSED*/
460 static int
iidefault_alternates(pglobal,argc,argv,pvar,pinfo)461 iidefault_alternates (pglobal, argc, argv, pvar, pinfo)
462      pointer pglobal;
463      int argc ATTRIBUTE_UNUSED;
464      char **argv;
465      pointer pvar ATTRIBUTE_UNUSED;
466      pointer pinfo;
467 {
468   struct sglobal *qglobal = (struct sglobal *) pglobal;
469   struct sinfo *qinfo = (struct sinfo *) pinfo;
470 
471   return _uuconf_iboolean (qglobal, argv[1], &qinfo->fdefault_alternates);
472 }
473 
474 /* Handle the "time" command.  We do this by turning it into a
475    "timegrade" command with a grade of BGRADE_LOW.  The first argument
476    is a time string, and the optional second argument is the retry
477    time.  */
478 
479 /*ARGSUSED*/
480 static int
iitime(pglobal,argc,argv,pvar,pinfo)481 iitime (pglobal, argc, argv, pvar, pinfo)
482      pointer pglobal;
483      int argc;
484      char **argv;
485      pointer pvar;
486      pointer pinfo;
487 {
488   char *aznew[4];
489   char ab[2];
490 
491   if (argc != 2 && argc != 3)
492     return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT;
493 
494   aznew[0] = argv[0];
495   ab[0] = UUCONF_GRADE_LOW;
496   ab[1] = '\0';
497   aznew[1] = ab;
498   aznew[2] = argv[1];
499   if (argc > 2)
500     aznew[3] = argv[2];
501 
502   return iitimegrade (pglobal, argc + 1, aznew, pvar, pinfo);
503 }
504 
505 /* Handle the "timegrade" command by calling _uuconf_itime_parse with
506    appropriate ival (the work grade) and cretry (the retry time)
507    arguments.  */
508 
509 static int
iitimegrade(pglobal,argc,argv,pvar,pinfo)510 iitimegrade (pglobal, argc, argv, pvar, pinfo)
511      pointer pglobal;
512      int argc;
513      char **argv;
514      pointer pvar;
515      pointer pinfo;
516 {
517   struct sglobal *qglobal = (struct sglobal *) pglobal;
518   struct uuconf_timespan **pqspan = (struct uuconf_timespan **) pvar;
519   struct sinfo *qinfo = (struct sinfo *) pinfo;
520   int cretry;
521   int iret;
522 
523   if (argc < 3 || argc > 4)
524     return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT;
525 
526   if (argv[1][1] != '\0' || ! UUCONF_GRADE_LEGAL (argv[1][0]))
527     return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT;
528 
529   if (argc == 3)
530     cretry = 0;
531   else
532     {
533       iret = _uuconf_iint (qglobal, argv[3], (pointer) &cretry, TRUE);
534       if (iret != UUCONF_SUCCESS)
535 	return iret;
536     }
537 
538   iret = _uuconf_itime_parse (qglobal, argv[2], (long) argv[1][0],
539 			      cretry, _uuconf_itime_grade_cmp, pqspan,
540 			      qinfo->qsys->uuconf_palloc);
541   if (iret != UUCONF_SUCCESS)
542     iret |= UUCONF_CMDTABRET_EXIT;
543   return iret;
544 }
545 
546 /* Handle the "baud-range" command, also known as "speed-range".  */
547 
548 static int
iibaud_range(pglobal,argc,argv,pvar,pinfo)549 iibaud_range (pglobal, argc, argv, pvar, pinfo)
550      pointer pglobal;
551      int argc ATTRIBUTE_UNUSED;
552      char **argv;
553      pointer pvar;
554      pointer pinfo ATTRIBUTE_UNUSED;
555 {
556   struct sglobal *qglobal = (struct sglobal *) pglobal;
557   struct uuconf_system *qsys = (struct uuconf_system *) pvar;
558   int iret;
559 
560   iret = _uuconf_iint (qglobal, argv[1], (pointer) &qsys->uuconf_ibaud,
561 		       FALSE);
562   if (iret != UUCONF_SUCCESS)
563     return iret;
564   return _uuconf_iint (qglobal, argv[2], (pointer) &qsys->uuconf_ihighbaud,
565 		       FALSE);
566 }
567 
568 /* Handle one of the size commands ("call-local-size", etc.).  The
569    first argument is a number of bytes, and the second argument is a
570    time string.  The pvar argument points to the string array to which
571    we add this new string.  */
572 
573 /*ARGSUSED*/
574 static int
iisize(pglobal,argc,argv,pvar,pinfo)575 iisize (pglobal, argc, argv, pvar, pinfo)
576      pointer pglobal;
577      int argc ATTRIBUTE_UNUSED;
578      char **argv;
579      pointer pvar;
580      pointer pinfo;
581 {
582   struct sglobal *qglobal = (struct sglobal *) pglobal;
583   struct uuconf_timespan **pqspan = (struct uuconf_timespan **) pvar;
584   struct sinfo *qinfo = (struct sinfo *) pinfo;
585   long ival;
586   int iret;
587 
588   iret = _uuconf_iint (qglobal, argv[1], (pointer) &ival, FALSE);
589   if (iret != UUCONF_SUCCESS)
590     return iret;
591 
592   iret = _uuconf_itime_parse (qglobal, argv[2], ival, 0, iisizecmp,
593 			      pqspan, qinfo->qsys->uuconf_palloc);
594   if (iret != UUCONF_SUCCESS)
595     iret |= UUCONF_CMDTABRET_EXIT;
596   return iret;
597 }
598 
599 /* A comparison function for sizes to pass to _uuconf_itime_parse.  */
600 
601 static int
iisizecmp(i1,i2)602 iisizecmp (i1, i2)
603      long i1;
604      long i2;
605 {
606   /* We can't just return i1 - i2 because that would be a long.  */
607   if (i1 < i2)
608     return -1;
609   else if (i1 == i2)
610     return 0;
611   else
612     return 1;
613 }
614 
615 /* Handle the "port" command.  If there is one argument, this names a
616    port.  Otherwise, the remaining arguments form a command describing
617    the port.  */
618 
619 /*ARGSUSED*/
620 static int
iiport(pglobal,argc,argv,pvar,pinfo)621 iiport (pglobal, argc, argv, pvar, pinfo)
622      pointer pglobal;
623      int argc;
624      char **argv;
625      pointer pvar ATTRIBUTE_UNUSED;
626      pointer pinfo;
627 {
628   struct sglobal *qglobal = (struct sglobal *) pglobal;
629   struct sinfo *qinfo = (struct sinfo *) pinfo;
630 
631   if (argc < 2)
632     return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT;
633   else if (argc == 2)
634     {
635       qinfo->qsys->uuconf_zport = argv[1];
636       return UUCONF_CMDTABRET_KEEP;
637     }
638   else
639     {
640       int iret;
641 
642       if (qinfo->qsys->uuconf_qport
643 	  == (struct uuconf_port *) &_uuconf_unset)
644 	{
645 	  struct uuconf_port *qnew;
646 
647 	  qnew = ((struct uuconf_port *)
648 		  uuconf_malloc (qinfo->qsys->uuconf_palloc,
649 				  sizeof (struct uuconf_port)));
650 	  if (qnew == NULL)
651 	    {
652 	      qglobal->ierrno = errno;
653 	      return (UUCONF_MALLOC_FAILED
654 		      | UUCONF_ERROR_ERRNO
655 		      | UUCONF_CMDTABRET_EXIT);
656 	    }
657 
658 	  _uuconf_uclear_port (qnew);
659 
660 	  if (qinfo->qsys->uuconf_zname == NULL)
661 	    qnew->uuconf_zname = (char *) "default system file port";
662 	  else
663 	    {
664 	      char *zname;
665 	      size_t clen;
666 
667 	      clen = strlen (qinfo->qsys->uuconf_zname);
668 	      zname = (char *) uuconf_malloc (qinfo->qsys->uuconf_palloc,
669 					      clen + sizeof "system  port");
670 	      if (zname == NULL)
671 		{
672 		  qglobal->ierrno = errno;
673 		  return (UUCONF_MALLOC_FAILED
674 			  | UUCONF_ERROR_ERRNO
675 			  | UUCONF_CMDTABRET_EXIT);
676 		}
677 
678 	      memcpy ((pointer) zname, (pointer) "system ",
679 		      sizeof "system " - 1);
680 	      memcpy ((pointer) (zname + sizeof "system " - 1),
681 		      (pointer) qinfo->qsys->uuconf_zname,
682 		      clen);
683 	      memcpy ((pointer) (zname + sizeof "system " - 1 + clen),
684 		      (pointer) " port", sizeof " port");
685 
686 	      qnew->uuconf_zname = zname;
687 	    }
688 
689 	  qnew->uuconf_palloc = qinfo->qsys->uuconf_palloc;
690 
691 	  qinfo->qsys->uuconf_qport = qnew;
692 	}
693 
694       iret = _uuconf_iport_cmd (qglobal, argc - 1, argv + 1,
695 				qinfo->qsys->uuconf_qport);
696       if (UUCONF_ERROR_VALUE (iret) != UUCONF_SUCCESS)
697 	iret |= UUCONF_CMDTABRET_EXIT;
698       return iret;
699     }
700 }
701 
702 /* Handle the "chat" and "called-chat" set of commands.  These just
703    hand off to the generic chat script function.  */
704 
705 static int
iichat(pglobal,argc,argv,pvar,pinfo)706 iichat (pglobal, argc, argv, pvar, pinfo)
707      pointer pglobal;
708      int argc;
709      char **argv;
710      pointer pvar;
711      pointer pinfo;
712 {
713   struct sglobal *qglobal = (struct sglobal *) pglobal;
714   struct sinfo *qinfo = (struct sinfo *) pinfo;
715   struct uuconf_chat *qchat = (struct uuconf_chat *) pvar;
716   int iret;
717 
718   iret = _uuconf_ichat_cmd (qglobal, argc, argv, qchat,
719 			    qinfo->qsys->uuconf_palloc);
720   if (UUCONF_ERROR_VALUE (iret) != UUCONF_SUCCESS)
721     iret |= UUCONF_CMDTABRET_EXIT;
722   return iret;
723 }
724 
725 /* Local interface to the _uuconf_idebug_cmd function, which handles
726    the "debug" command.  */
727 
728 static int
iidebug(pglobal,argc,argv,pvar,pinfo)729 iidebug (pglobal, argc, argv, pvar, pinfo)
730      pointer pglobal;
731      int argc;
732      char **argv;
733      pointer pvar;
734      pointer pinfo;
735 {
736   struct sglobal *qglobal = (struct sglobal *) pglobal;
737   struct sinfo *qinfo = (struct sinfo *) pinfo;
738   char **pzdebug = (char **) pvar;
739 
740   return _uuconf_idebug_cmd (qglobal, pzdebug, argc, argv,
741 			     qinfo->qsys->uuconf_palloc);
742 }
743 
744 /* Handle the "called-login" command.  This only needs to be in a
745    function because there can be additional arguments listing the
746    remote systems which are permitted to use this login name.  The
747    additional arguments are not actually handled here; they are
748    handled by uuconf_taylor_system_names, which already has to go
749    through all the system files.  */
750 
751 /*ARGSUSED*/
752 static int
iicalled_login(pglobal,argc,argv,pvar,pinfo)753 iicalled_login (pglobal, argc, argv, pvar, pinfo)
754      pointer pglobal ATTRIBUTE_UNUSED;
755      int argc;
756      char **argv;
757      pointer pvar;
758      pointer pinfo ATTRIBUTE_UNUSED;
759 {
760   char **pz = (char **) pvar;
761 
762   if (argc < 2)
763     return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT;
764   *pz = argv[1];
765   return UUCONF_CMDTABRET_KEEP;
766 }
767 
768 /* Handle the "protocol-parameter" command.  This just hands off to
769    the generic protocol parameter handler.  */
770 
771 static int
iiproto_param(pglobal,argc,argv,pvar,pinfo)772 iiproto_param (pglobal, argc, argv, pvar, pinfo)
773      pointer pglobal;
774      int argc;
775      char **argv;
776      pointer pvar;
777      pointer pinfo;
778 {
779   struct sglobal *qglobal = (struct sglobal *) pglobal;
780   struct uuconf_proto_param **pqparam = (struct uuconf_proto_param **) pvar;
781   struct sinfo *qinfo = (struct sinfo *) pinfo;
782 
783   if (*pqparam == (struct uuconf_proto_param *) &_uuconf_unset)
784     *pqparam = NULL;
785   return _uuconf_iadd_proto_param (qglobal, argc - 1, argv + 1, pqparam,
786 				   qinfo->qsys->uuconf_palloc);
787 }
788 
789 /* Handle the "request" command.  This is equivalent to specifying
790    both "call-request" and "called-request".  */
791 
792 /*ARGSUSED*/
793 static int
iirequest(pglobal,argc,argv,pvar,pinfo)794 iirequest (pglobal, argc, argv, pvar, pinfo)
795      pointer pglobal;
796      int argc ATTRIBUTE_UNUSED;
797      char **argv;
798      pointer pvar ATTRIBUTE_UNUSED;
799      pointer pinfo;
800 {
801   struct sglobal *qglobal = (struct sglobal *) pglobal;
802   struct sinfo *qinfo = (struct sinfo *) pinfo;
803   int iret;
804 
805   iret = _uuconf_iboolean (qglobal, argv[1],
806 			   &qinfo->qsys->uuconf_fsend_request);
807   if (UUCONF_ERROR_VALUE (iret) == UUCONF_SUCCESS)
808     qinfo->qsys->uuconf_frec_request = qinfo->qsys->uuconf_fsend_request;
809 
810   return iret;
811 }
812 
813 /* Handle the "transfer" command.  This is equivalent to specifying
814    both "call-transfer" and "called-transfer".  */
815 
816 /*ARGSUSED*/
817 static int
iitransfer(pglobal,argc,argv,pvar,pinfo)818 iitransfer (pglobal, argc, argv, pvar, pinfo)
819      pointer pglobal;
820      int argc ATTRIBUTE_UNUSED;
821      char **argv;
822      pointer pvar ATTRIBUTE_UNUSED;
823      pointer pinfo;
824 {
825   struct sglobal *qglobal = (struct sglobal *) pglobal;
826   struct sinfo *qinfo = (struct sinfo *) pinfo;
827   int iret;
828 
829   iret = _uuconf_iboolean (qglobal, argv[1],
830 			   &qinfo->qsys->uuconf_fcall_transfer);
831   if (UUCONF_ERROR_VALUE (iret) == UUCONF_SUCCESS)
832     qinfo->qsys->uuconf_fcalled_transfer = qinfo->qsys->uuconf_fcall_transfer;
833 
834   return iret;
835 }
836 
837 /* Handle the "forward" command.  This is equivalent to specifying
838    both "forward-from" and "forward-to".  */
839 
840 /*ARGSUSED*/
841 static int
iiforward(pglobal,argc,argv,pvar,pinfo)842 iiforward (pglobal, argc, argv, pvar, pinfo)
843      pointer pglobal;
844      int argc;
845      char **argv;
846      pointer pvar ATTRIBUTE_UNUSED;
847      pointer pinfo;
848 {
849   struct sglobal *qglobal = (struct sglobal *) pglobal;
850   struct sinfo *qinfo = (struct sinfo *) pinfo;
851   struct uuconf_system *qsys;
852   int i;
853   int iret;
854 
855   qsys = qinfo->qsys;
856   qsys->uuconf_pzforward_from = NULL;
857   qsys->uuconf_pzforward_to = NULL;
858   for (i = 1; i < argc; i++)
859     {
860       iret = _uuconf_iadd_string (qglobal, argv[i], FALSE, FALSE,
861 				  &qsys->uuconf_pzforward_to,
862 				  qsys->uuconf_palloc);
863       if (iret != UUCONF_SUCCESS)
864 	return iret | UUCONF_CMDTABRET_KEEP | UUCONF_CMDTABRET_EXIT;
865       iret = _uuconf_iadd_string (qglobal, argv[i], FALSE, FALSE,
866 				  &qsys->uuconf_pzforward_from,
867 				  qsys->uuconf_palloc);
868       if (iret != UUCONF_SUCCESS)
869 	return iret | UUCONF_CMDTABRET_KEEP | UUCONF_CMDTABRET_EXIT;
870     }
871 
872   return UUCONF_CMDTABRET_KEEP;
873 }
874 
875 /* Handle an unknown command.  This should probably be done more
876    intelligently.  */
877 
878 /*ARGSUSED*/
879 static int
iiunknown(pglobal,argc,argv,pvar,pinfo)880 iiunknown (pglobal, argc, argv, pvar, pinfo)
881      pointer pglobal ATTRIBUTE_UNUSED;
882      int argc ATTRIBUTE_UNUSED;
883      char **argv ATTRIBUTE_UNUSED;
884      pointer pvar ATTRIBUTE_UNUSED;
885      pointer pinfo ATTRIBUTE_UNUSED;
886 {
887   return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT;
888 }
889 
890 /* Return information for an unknown system.  It would be better to
891    put this in a different file, but it would require breaking several
892    functions out of this file.  Perhaps I will do it sometime.  */
893 
894 int
uuconf_taylor_system_unknown(pglobal,qsys)895 uuconf_taylor_system_unknown (pglobal, qsys)
896      pointer pglobal;
897      struct uuconf_system *qsys;
898 {
899   struct sglobal *qglobal = (struct sglobal *) pglobal;
900   struct uuconf_cmdtab as[CSYSTEM_CMDS];
901   struct sinfo si;
902   struct sunknown *q;
903   int iret;
904 
905   if (qglobal->qprocess->qunknown == NULL)
906     return UUCONF_NOT_FOUND;
907 
908   _uuconf_ucmdtab_base (asIcmds, CSYSTEM_CMDS, (char *) qsys, as);
909 
910   _uuconf_uclear_system (qsys);
911 
912   si.qsys = qsys;
913   si.falternates = FALSE;
914   si.fdefault_alternates = TRUE;
915   qsys->uuconf_palloc = uuconf_malloc_block ();
916   if (qsys->uuconf_palloc == NULL)
917     {
918       qglobal->ierrno = errno;
919       return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
920     }
921 
922   for (q = qglobal->qprocess->qunknown; q != NULL; q = q->qnext)
923     {
924       iret = uuconf_cmd_args (pglobal, q->cargs, q->pzargs, as,
925 			      (pointer) &si, iiunknown,
926 			      UUCONF_CMDTABFLAG_BACKSLASH,
927 			      qsys->uuconf_palloc);
928       iret &=~ UUCONF_CMDTABRET_KEEP;
929       if (UUCONF_ERROR_VALUE (iret) != UUCONF_SUCCESS)
930 	{
931 	  qglobal->zfilename = qglobal->qprocess->zconfigfile;
932 	  qglobal->ilineno = q->ilineno;
933 	  return ((iret &~ UUCONF_CMDTABRET_EXIT)
934 		  | UUCONF_ERROR_FILENAME
935 		  | UUCONF_ERROR_LINENO);
936 	}
937       if ((iret & UUCONF_CMDTABRET_EXIT) != 0)
938 	break;
939     }
940 
941   if (! si.falternates)
942     uiset_call (qsys);
943   else
944     {
945       iret = iialternate (pglobal, 0, (char **) NULL, (pointer) NULL,
946 			  (pointer) &si);
947       if (iret != UUCONF_SUCCESS)
948 	return iret;
949     }
950 
951   /* The first alternate is always available for calling in.  */
952   qsys->uuconf_fcalled = TRUE;
953 
954   return _uuconf_isystem_basic_default (qglobal, qsys);
955 }
956