1/* tportc.c
2   Handle a Taylor UUCP port command.
3
4   Copyright (C) 1992, 1993, 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_tportc_rcsid[] = "$Id: tportc.c,v 1.18 2002/03/05 19:10:43 ian Rel $";
29#endif
30
31#include <errno.h>
32
33static int ipproto_param P((pointer pglobal, int argc, char **argv,
34			    pointer pvar, pointer pinfo));
35static int ipbaud_range P((pointer pglobal, int argc, char **argv,
36			   pointer pvar, pointer pinfo));
37static int ipdialer P((pointer pglobal, int argc, char **argv, pointer pvar,
38		       pointer pinfo));
39static int ipcunknown P((pointer pglobal, int argc, char **argv,
40			 pointer pvar, pointer pinfo));
41
42/* The string names of the port types.  This array corresponds to the
43   uuconf_porttype enumeration.  */
44
45static const char * const azPtype_names[] =
46{
47  NULL,
48  "stdin",
49  "modem",
50  "direct",
51  "tcp",
52  "tli",
53  "pipe"
54};
55
56#define CPORT_TYPES (sizeof azPtype_names / sizeof azPtype_names[0])
57
58/* The command table for generic port commands.  The "port" and "type"
59   commands are handled specially.  */
60static const struct cmdtab_offset asPort_cmds[] =
61{
62  { "protocol", UUCONF_CMDTABTYPE_STRING,
63      offsetof (struct uuconf_port, uuconf_zprotocols), NULL },
64  { "protocol-parameter", UUCONF_CMDTABTYPE_FN | 0,
65      offsetof (struct uuconf_port, uuconf_qproto_params), ipproto_param },
66  { "seven-bit", UUCONF_CMDTABTYPE_FN | 2,
67      offsetof (struct uuconf_port, uuconf_ireliable), _uuconf_iseven_bit },
68  { "reliable", UUCONF_CMDTABTYPE_FN | 2,
69      offsetof (struct uuconf_port, uuconf_ireliable), _uuconf_ireliable },
70  { "half-duplex", UUCONF_CMDTABTYPE_FN | 2,
71      offsetof (struct uuconf_port, uuconf_ireliable),
72      _uuconf_ihalf_duplex },
73  { "lockname", UUCONF_CMDTABTYPE_STRING,
74      offsetof (struct uuconf_port, uuconf_zlockname), NULL },
75  { NULL, 0, 0, NULL }
76};
77
78#define CPORT_CMDS (sizeof asPort_cmds / sizeof asPort_cmds[0])
79
80/* The stdin port command table.  */
81static const struct cmdtab_offset asPstdin_cmds[] =
82{
83  { NULL, 0, 0, NULL }
84};
85
86#define CSTDIN_CMDS (sizeof asPstdin_cmds / sizeof asPstdin_cmds[0])
87
88/* The modem port command table.  */
89static const struct cmdtab_offset asPmodem_cmds[] =
90{
91  { "device", UUCONF_CMDTABTYPE_STRING,
92      offsetof (struct uuconf_port, uuconf_u.uuconf_smodem.uuconf_zdevice),
93      NULL },
94  { "baud", UUCONF_CMDTABTYPE_LONG,
95      offsetof (struct uuconf_port, uuconf_u.uuconf_smodem.uuconf_ibaud),
96      NULL },
97  { "speed", UUCONF_CMDTABTYPE_LONG,
98      offsetof (struct uuconf_port, uuconf_u.uuconf_smodem.uuconf_ibaud),
99      NULL },
100  { "baud-range", UUCONF_CMDTABTYPE_FN | 3,
101      offsetof (struct uuconf_port, uuconf_u.uuconf_smodem), ipbaud_range },
102  { "speed-range", UUCONF_CMDTABTYPE_FN | 3,
103      offsetof (struct uuconf_port, uuconf_u.uuconf_smodem), ipbaud_range },
104  { "carrier", UUCONF_CMDTABTYPE_BOOLEAN,
105      offsetof (struct uuconf_port, uuconf_u.uuconf_smodem.uuconf_fcarrier),
106      NULL },
107  { "hardflow", UUCONF_CMDTABTYPE_BOOLEAN,
108      offsetof (struct uuconf_port, uuconf_u.uuconf_smodem.uuconf_fhardflow),
109      NULL },
110  { "dial-device", UUCONF_CMDTABTYPE_STRING,
111      offsetof (struct uuconf_port,
112		uuconf_u.uuconf_smodem.uuconf_zdial_device),
113      NULL },
114  { "dialer", UUCONF_CMDTABTYPE_FN | 0,
115      offsetof (struct uuconf_port, uuconf_u.uuconf_smodem), ipdialer },
116  { "dialer-sequence", UUCONF_CMDTABTYPE_FULLSTRING,
117      offsetof (struct uuconf_port, uuconf_u.uuconf_smodem.uuconf_pzdialer),
118      NULL },
119  { NULL, 0, 0, NULL }
120};
121
122#define CMODEM_CMDS (sizeof asPmodem_cmds / sizeof asPmodem_cmds[0])
123
124/* The direct port command table.  */
125static const struct cmdtab_offset asPdirect_cmds[] =
126{
127  { "device", UUCONF_CMDTABTYPE_STRING,
128      offsetof (struct uuconf_port, uuconf_u.uuconf_sdirect.uuconf_zdevice),
129      NULL },
130  { "baud", UUCONF_CMDTABTYPE_LONG,
131      offsetof (struct uuconf_port, uuconf_u.uuconf_sdirect.uuconf_ibaud),
132      NULL },
133  { "speed", UUCONF_CMDTABTYPE_LONG,
134      offsetof (struct uuconf_port, uuconf_u.uuconf_sdirect.uuconf_ibaud),
135      NULL },
136  { "carrier", UUCONF_CMDTABTYPE_BOOLEAN,
137      offsetof (struct uuconf_port, uuconf_u.uuconf_sdirect.uuconf_fcarrier),
138      NULL },
139  { "hardflow", UUCONF_CMDTABTYPE_BOOLEAN,
140      offsetof (struct uuconf_port, uuconf_u.uuconf_sdirect.uuconf_fhardflow),
141      NULL },
142  { NULL, 0, 0, NULL }
143};
144
145#define CDIRECT_CMDS (sizeof asPdirect_cmds / sizeof asPdirect_cmds[0])
146
147/* The TCP port command table.  */
148static const struct cmdtab_offset asPtcp_cmds[] =
149{
150  { "service", UUCONF_CMDTABTYPE_STRING,
151      offsetof (struct uuconf_port, uuconf_u.uuconf_stcp.uuconf_zport),
152      NULL },
153  { "version", UUCONF_CMDTABTYPE_INT,
154      offsetof (struct uuconf_port, uuconf_u.uuconf_stcp.uuconf_iversion),
155      NULL },
156  { "dialer-sequence", UUCONF_CMDTABTYPE_FULLSTRING,
157      offsetof (struct uuconf_port, uuconf_u.uuconf_stcp.uuconf_pzdialer),
158      NULL },
159  { NULL, 0, 0, NULL }
160};
161
162#define CTCP_CMDS (sizeof asPtcp_cmds / sizeof asPtcp_cmds[0])
163
164/* The TLI port command table.  */
165static const struct cmdtab_offset asPtli_cmds[] =
166{
167  { "device", UUCONF_CMDTABTYPE_STRING,
168      offsetof (struct uuconf_port, uuconf_u.uuconf_stli.uuconf_zdevice),
169      NULL },
170  { "stream", UUCONF_CMDTABTYPE_BOOLEAN,
171      offsetof (struct uuconf_port, uuconf_u.uuconf_stli.uuconf_fstream),
172      NULL },
173  { "push", UUCONF_CMDTABTYPE_FULLSTRING,
174      offsetof (struct uuconf_port, uuconf_u.uuconf_stli.uuconf_pzpush),
175      NULL },
176  { "dialer-sequence", UUCONF_CMDTABTYPE_FULLSTRING,
177      offsetof (struct uuconf_port, uuconf_u.uuconf_stli.uuconf_pzdialer),
178      NULL },
179  { "server-address", UUCONF_CMDTABTYPE_STRING,
180      offsetof (struct uuconf_port, uuconf_u.uuconf_stli.uuconf_zservaddr),
181      NULL },
182  { NULL, 0, 0, NULL }
183};
184
185#define CTLI_CMDS (sizeof asPtli_cmds / sizeof asPtli_cmds[0])
186
187/* The pipe port command table.  */
188static const struct cmdtab_offset asPpipe_cmds[] =
189{
190  { "command", UUCONF_CMDTABTYPE_FULLSTRING,
191      offsetof (struct uuconf_port, uuconf_u.uuconf_spipe.uuconf_pzcmd),
192      NULL },
193  { NULL, 0, 0, NULL}
194};
195
196#define CPIPE_CMDS (sizeof asPpipe_cmds / sizeof asPpipe_cmds[0])
197
198#undef max
199#define max(i1, i2) ((i1) > (i2) ? (i1) : (i2))
200#define CCMDS \
201  max (max (max (CPORT_CMDS, CSTDIN_CMDS), CMODEM_CMDS), \
202       max (max (CDIRECT_CMDS, CTCP_CMDS), max (CTLI_CMDS, CPIPE_CMDS)))
203
204/* Handle a command passed to a port from a Taylor UUCP configuration
205   file.  This can be called when reading either the port file or the
206   sys file.  The return value may have UUCONF_CMDTABRET_KEEP set, but
207   not UUCONF_CMDTABRET_EXIT.  It assigns values to the elements of
208   qport.  The first time this is called, qport->uuconf_zname and
209   qport->uuconf_palloc should be set and qport->uuconf_ttype should
210   be UUCONF_PORTTYPE_UNKNOWN.  */
211
212int
213_uuconf_iport_cmd (qglobal, argc, argv, qport)
214     struct sglobal *qglobal;
215     int argc;
216     char **argv;
217     struct uuconf_port *qport;
218{
219  boolean fgottype;
220  const struct cmdtab_offset *qcmds;
221  size_t ccmds;
222  struct uuconf_cmdtab as[CCMDS];
223  size_t i;
224  int iret;
225
226  fgottype = strcasecmp (argv[0], "type") == 0;
227
228  if (fgottype || qport->uuconf_ttype == UUCONF_PORTTYPE_UNKNOWN)
229    {
230      enum uuconf_porttype ttype;
231
232      /* We either just got a "type" command, or this is an
233	 uninitialized port.  If the first command to a port is not
234	 "type", it is assumed to be a modem port.  This
235	 implementation will actually permit "type" at any point, but
236	 will effectively discard any type specific information that
237	 appears before the "type" command.  This supports defaults,
238	 in that the default may be of a specific type while future
239	 ports in the same file may be of other types.  */
240      if (! fgottype)
241	ttype = UUCONF_PORTTYPE_MODEM;
242      else
243	{
244	  if (argc != 2)
245	    return UUCONF_SYNTAX_ERROR;
246
247	  for (i = 0; i < CPORT_TYPES; i++)
248	    if (azPtype_names[i] != NULL
249		&& strcasecmp (argv[1], azPtype_names[i]) == 0)
250	      break;
251
252	  if (i >= CPORT_TYPES)
253	    return UUCONF_SYNTAX_ERROR;
254
255	  ttype = (enum uuconf_porttype) i;
256	}
257
258      qport->uuconf_ttype = ttype;
259
260      switch (ttype)
261	{
262	default:
263	case UUCONF_PORTTYPE_STDIN:
264	  break;
265	case UUCONF_PORTTYPE_MODEM:
266	  qport->uuconf_u.uuconf_smodem.uuconf_zdevice = NULL;
267	  qport->uuconf_u.uuconf_smodem.uuconf_zdial_device = NULL;
268	  qport->uuconf_u.uuconf_smodem.uuconf_ibaud = 0L;
269	  qport->uuconf_u.uuconf_smodem.uuconf_ilowbaud = 0L;
270	  qport->uuconf_u.uuconf_smodem.uuconf_ihighbaud = 0L;
271	  qport->uuconf_u.uuconf_smodem.uuconf_fcarrier = TRUE;
272	  qport->uuconf_u.uuconf_smodem.uuconf_fhardflow = TRUE;
273	  qport->uuconf_u.uuconf_smodem.uuconf_pzdialer = NULL;
274	  qport->uuconf_u.uuconf_smodem.uuconf_qdialer = NULL;
275	  break;
276	case UUCONF_PORTTYPE_DIRECT:
277	  qport->uuconf_u.uuconf_sdirect.uuconf_zdevice = NULL;
278	  qport->uuconf_u.uuconf_sdirect.uuconf_ibaud = -1;
279	  qport->uuconf_u.uuconf_sdirect.uuconf_fcarrier = FALSE;
280	  qport->uuconf_u.uuconf_sdirect.uuconf_fhardflow = TRUE;
281	  break;
282	case UUCONF_PORTTYPE_TCP:
283	  qport->uuconf_u.uuconf_stcp.uuconf_zport = (char *) "uucp";
284	  qport->uuconf_u.uuconf_stcp.uuconf_iversion = 0;
285	  qport->uuconf_u.uuconf_stcp.uuconf_pzdialer = NULL;
286	  qport->uuconf_ireliable = (UUCONF_RELIABLE_SPECIFIED
287				     | UUCONF_RELIABLE_ENDTOEND
288				     | UUCONF_RELIABLE_RELIABLE
289				     | UUCONF_RELIABLE_EIGHT
290				     | UUCONF_RELIABLE_FULLDUPLEX);
291	  break;
292	case UUCONF_PORTTYPE_TLI:
293	  qport->uuconf_u.uuconf_stli.uuconf_zdevice = NULL;
294	  qport->uuconf_u.uuconf_stli.uuconf_fstream = FALSE;
295	  qport->uuconf_u.uuconf_stli.uuconf_pzpush = NULL;
296	  qport->uuconf_u.uuconf_stli.uuconf_pzdialer = NULL;
297	  qport->uuconf_u.uuconf_stli.uuconf_zservaddr = NULL;
298	  qport->uuconf_ireliable = (UUCONF_RELIABLE_SPECIFIED
299				     | UUCONF_RELIABLE_ENDTOEND
300				     | UUCONF_RELIABLE_RELIABLE
301				     | UUCONF_RELIABLE_EIGHT
302				     | UUCONF_RELIABLE_FULLDUPLEX);
303	  break;
304	case UUCONF_PORTTYPE_PIPE:
305	  qport->uuconf_u.uuconf_spipe.uuconf_pzcmd = NULL;
306	  break;
307	}
308
309      if (fgottype)
310	return UUCONF_CMDTABRET_CONTINUE;
311    }
312
313  /* See if this command is one of the generic ones.  */
314  qcmds = asPort_cmds;
315  ccmds = CPORT_CMDS;
316
317  for (i = 0; i < CPORT_CMDS - 1; i++)
318    if (strcasecmp (argv[0], asPort_cmds[i].zcmd) == 0)
319      break;
320
321  if (i >= CPORT_CMDS - 1)
322    {
323      /* It's not a generic command, so we must check the type
324	 specific commands.  */
325      switch (qport->uuconf_ttype)
326	{
327	case UUCONF_PORTTYPE_STDIN:
328	  qcmds = asPstdin_cmds;
329	  ccmds = CSTDIN_CMDS;
330	  break;
331	case UUCONF_PORTTYPE_MODEM:
332	  qcmds = asPmodem_cmds;
333	  ccmds = CMODEM_CMDS;
334	  break;
335	case UUCONF_PORTTYPE_DIRECT:
336	  qcmds = asPdirect_cmds;
337	  ccmds = CDIRECT_CMDS;
338	  break;
339	case UUCONF_PORTTYPE_TCP:
340	  qcmds = asPtcp_cmds;
341	  ccmds = CTCP_CMDS;
342	  break;
343	case UUCONF_PORTTYPE_TLI:
344	  qcmds = asPtli_cmds;
345	  ccmds = CTLI_CMDS;
346	  break;
347	case UUCONF_PORTTYPE_PIPE:
348	  qcmds = asPpipe_cmds;
349	  ccmds = CPIPE_CMDS;
350	  break;
351	default:
352	  return UUCONF_SYNTAX_ERROR;
353	}
354    }
355
356  /* Copy the command table onto the stack and modify it to point to
357     qport.  */
358  _uuconf_ucmdtab_base (qcmds, ccmds, (char *) qport, as);
359
360  iret = uuconf_cmd_args ((pointer) qglobal, argc, argv, as,
361			  (pointer) qport, ipcunknown, 0,
362			  qport->uuconf_palloc);
363
364  return iret &~ UUCONF_CMDTABRET_EXIT;
365}
366
367/* Handle the "protocol-parameter" command.  */
368
369static int
370ipproto_param (pglobal, argc, argv, pvar, pinfo)
371     pointer pglobal;
372     int argc;
373     char **argv;
374     pointer pvar;
375     pointer pinfo;
376{
377  struct sglobal *qglobal = (struct sglobal *) pglobal;
378  struct uuconf_proto_param **pqparam = (struct uuconf_proto_param **) pvar;
379  struct uuconf_port *qport = (struct uuconf_port *) pinfo;
380
381  return _uuconf_iadd_proto_param (qglobal, argc - 1, argv + 1, pqparam,
382				   qport->uuconf_palloc);
383}
384
385/* Handle the "baud-range" command.  */
386
387/*ARGSUSED*/
388static int
389ipbaud_range (pglobal, argc, argv, pvar, pinfo)
390     pointer pglobal;
391     int argc ATTRIBUTE_UNUSED;
392     char **argv;
393     pointer pvar;
394     pointer pinfo ATTRIBUTE_UNUSED;
395{
396  struct sglobal *qglobal = (struct sglobal *) pglobal;
397  struct uuconf_modem_port *qmodem = (struct uuconf_modem_port *) pvar;
398  int iret;
399
400  iret = _uuconf_iint (qglobal, argv[1],
401		       (pointer) &qmodem->uuconf_ilowbaud, FALSE);
402  if ((iret &~ UUCONF_CMDTABRET_KEEP) != UUCONF_SUCCESS)
403    return iret;
404
405  iret |= _uuconf_iint (qglobal, argv[2],
406			(pointer) &qmodem->uuconf_ihighbaud, FALSE);
407
408  return iret;
409}
410
411/* Handle the "dialer" command.  If there is one argument, this names
412   a dialer.  Otherwise, the remaining arguments form a command
413   describing the dialer.  */
414
415static int
416ipdialer (pglobal, argc, argv, pvar, pinfo)
417     pointer pglobal;
418     int argc;
419     char **argv;
420     pointer pvar;
421     pointer pinfo;
422{
423  struct sglobal *qglobal = (struct sglobal *) pglobal;
424  struct uuconf_modem_port *qmodem = (struct uuconf_modem_port *) pvar;
425  struct uuconf_port *qport = (struct uuconf_port *) pinfo;
426  int iret;
427
428  if (argc < 2)
429    return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT;
430
431  if (argc > 2)
432    {
433      if (qmodem->uuconf_qdialer == NULL)
434	{
435	  struct uuconf_dialer *qnew;
436	  size_t clen;
437
438	  qnew = ((struct uuconf_dialer *)
439		  uuconf_malloc (qport->uuconf_palloc,
440				  sizeof (struct uuconf_dialer)));
441	  if (qnew == NULL)
442	    {
443	      qglobal->ierrno = errno;
444	      return (UUCONF_MALLOC_FAILED
445		      | UUCONF_ERROR_ERRNO
446		      | UUCONF_CMDTABRET_EXIT);
447	    }
448
449	  _uuconf_uclear_dialer (qnew);
450
451	  if (qport->uuconf_zname == NULL)
452	    qnew->uuconf_zname = (char *) "default port file dialer";
453	  else
454	    {
455	      clen = strlen (qport->uuconf_zname);
456	      qnew->uuconf_zname =
457		(char *) uuconf_malloc (qport->uuconf_palloc,
458					clen + sizeof " dialer");
459	      if (qnew->uuconf_zname == NULL)
460		{
461		  qglobal->ierrno = errno;
462		  return (UUCONF_MALLOC_FAILED
463			  | UUCONF_ERROR_ERRNO
464			  | UUCONF_CMDTABRET_EXIT);
465		}
466
467	      memcpy ((pointer) qnew->uuconf_zname,
468		      (pointer) qport->uuconf_zname, clen);
469	      memcpy ((pointer) (qnew->uuconf_zname + clen),
470		      (pointer) " dialer", sizeof " dialer");
471	    }
472
473	  qnew->uuconf_palloc = qport->uuconf_palloc;
474
475	  qmodem->uuconf_qdialer = qnew;
476	}
477
478      iret = _uuconf_idialer_cmd (qglobal, argc - 1, argv + 1,
479				  qmodem->uuconf_qdialer);
480      if ((iret &~ UUCONF_CMDTABRET_KEEP) != UUCONF_SUCCESS)
481	iret |= UUCONF_CMDTABRET_EXIT;
482      return iret;
483    }
484  else
485    {
486      qmodem->uuconf_pzdialer = NULL;
487      iret = _uuconf_iadd_string (qglobal, argv[1], TRUE, FALSE,
488				  &qmodem->uuconf_pzdialer,
489				  qport->uuconf_palloc);
490      if (iret != UUCONF_SUCCESS)
491	iret |= UUCONF_CMDTABRET_EXIT;
492      return iret;
493    }
494}
495
496/* Give an error for an unknown port command.  */
497
498/*ARGSUSED*/
499static int
500ipcunknown (pglobal, argc, argv, pvar, pinfo)
501     pointer pglobal ATTRIBUTE_UNUSED;
502     int argc ATTRIBUTE_UNUSED;
503     char **argv ATTRIBUTE_UNUSED;
504     pointer pvar ATTRIBUTE_UNUSED;
505     pointer pinfo ATTRIBUTE_UNUSED;
506{
507  return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT;
508}
509