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
28const char _uuconf_tsinfo_rcsid[] = "$Id: tsinfo.c,v 1.21 2002/03/05 19:10:43 ian Rel $";
29#endif
30
31#include <errno.h>
32#include <ctype.h>
33
34#ifndef SEEK_SET
35#define SEEK_SET 0
36#endif
37
38static void uiset_call P((struct uuconf_system *qsys));
39static 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
46CMDTABFN (iisystem);
47CMDTABFN (iialias);
48CMDTABFN (iialternate);
49CMDTABFN (iidefault_alternates);
50CMDTABFN (iitime);
51CMDTABFN (iitimegrade);
52CMDTABFN (iisize);
53CMDTABFN (iibaud_range);
54CMDTABFN (iiport);
55CMDTABFN (iichat);
56CMDTABFN (iidebug);
57CMDTABFN (iicalled_login);
58CMDTABFN (iiproto_param);
59CMDTABFN (iirequest);
60CMDTABFN (iitransfer);
61CMDTABFN (iiforward);
62CMDTABFN (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
71struct 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.  */
84static 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
189int
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
330static void
331uiset_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
351static int
352iisystem (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*/
365static int
366iialias (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
391static int
392iialternate (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*/
460static int
461iidefault_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*/
480static int
481iitime (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
509static int
510iitimegrade (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
548static int
549iibaud_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*/
574static int
575iisize (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
601static int
602iisizecmp (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*/
620static int
621iiport (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
705static int
706iichat (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
728static int
729iidebug (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*/
752static int
753iicalled_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
771static int
772iiproto_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*/
793static int
794iirequest (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*/
817static int
818iitransfer (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*/
841static int
842iiforward (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*/
879static int
880iiunknown (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
894int
895uuconf_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