1/* vport.c
2   Find a port in the V2 configuration files.
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_vport_rcsid[] = "$Id: vport.c,v 1.12 2002/03/05 19:10:43 ian Rel $";
29#endif
30
31#include <errno.h>
32#include <ctype.h>
33
34/* Find a port in the V2 configuration files by name, baud rate, and
35   special purpose function.  */
36
37int
38uuconf_v2_find_port (pglobal, zname, ibaud, ihighbaud, pifn, pinfo, qport)
39     pointer pglobal;
40     const char *zname;
41     long ibaud;
42     long ihighbaud ATTRIBUTE_UNUSED;
43     int (*pifn) P((struct uuconf_port *, pointer));
44     pointer pinfo;
45     struct uuconf_port *qport;
46{
47  struct sglobal *qglobal = (struct sglobal *) pglobal;
48  FILE *e;
49  char *zline;
50  size_t cline;
51  char **pzsplit;
52  size_t csplit;
53  int iret;
54  int cchars;
55
56  e = fopen (qglobal->qprocess->zv2devices, "r");
57  if (e == NULL)
58    {
59      if (FNO_SUCH_FILE ())
60	return UUCONF_NOT_FOUND;
61      qglobal->ierrno = errno;
62      qglobal->zfilename = qglobal->qprocess->zv2devices;
63      return (UUCONF_FOPEN_FAILED
64	      | UUCONF_ERROR_ERRNO
65	      | UUCONF_ERROR_FILENAME);
66    }
67
68  zline = NULL;
69  cline = 0;
70  pzsplit = NULL;
71  csplit = 0;
72
73  iret = UUCONF_NOT_FOUND;
74
75  qglobal->ilineno = 0;
76
77  while ((cchars = getline (&zline, &cline, e)) > 0)
78    {
79      int ctoks;
80      char *zend;
81      long ilow, ihigh;
82      pointer pblock;
83
84      ++qglobal->ilineno;
85
86      iret = UUCONF_NOT_FOUND;
87
88      --cchars;
89      if (zline[cchars] == '\n')
90	zline[cchars] = '\0';
91      zline[strcspn (zline, "#")] = '\0';
92
93      ctoks = _uuconf_istrsplit (zline, '\0', &pzsplit, &csplit);
94      if (ctoks < 0)
95	{
96	  qglobal->ierrno = errno;
97	  iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
98	  break;
99	}
100
101      /* An entry in L-devices is
102
103	 type device dial-device baud dialer
104
105	 The type (normally "ACU") is treated as the name.  */
106
107      /* If there aren't enough entries, ignore the line; this
108	 should probably do something more useful.  */
109      if (ctoks < 4)
110	continue;
111
112      /* Make sure the name matches any argument.  */
113      if (zname != NULL
114	  && strcmp (pzsplit[0], zname) != 0)
115	continue;
116
117      /* Get the baud rate.  */
118      ilow = strtol (pzsplit[3], &zend, 10);
119      if (*zend == '-')
120	ihigh = strtol (zend + 1, (char **) NULL, 10);
121      else
122	ihigh = ilow;
123
124      /* Make sure the baud rate matches any argument.  */
125      if (ibaud != 0
126	  && ilow != 0
127	  && (ilow > ibaud || ihigh < ibaud))
128	continue;
129
130      /* Now we must construct the port information, so that we can
131	 pass it to pifn.  The port type is determined by it's name,
132	 unfortunately.  The name "DIR" is used for a direct port, and
133	 anything else for a modem port.  */
134      pblock = NULL;
135      _uuconf_uclear_port (qport);
136      qport->uuconf_zname = pzsplit[0];
137      if (strcmp (pzsplit[0], "DIR") == 0)
138	{
139	  qport->uuconf_ttype = UUCONF_PORTTYPE_DIRECT;
140	  qport->uuconf_u.uuconf_sdirect.uuconf_zdevice = pzsplit[1];
141	  qport->uuconf_u.uuconf_sdirect.uuconf_ibaud = ilow;
142	  qport->uuconf_u.uuconf_sdirect.uuconf_fcarrier = FALSE;
143	  qport->uuconf_u.uuconf_sdirect.uuconf_fhardflow = TRUE;
144	}
145      else
146	{
147	  qport->uuconf_ttype = UUCONF_PORTTYPE_MODEM;
148	  qport->uuconf_u.uuconf_smodem.uuconf_zdevice = pzsplit[1];
149	  if (strcmp (pzsplit[2], "-") != 0)
150	    qport->uuconf_u.uuconf_smodem.uuconf_zdial_device = pzsplit[2];
151	  else
152	    qport->uuconf_u.uuconf_smodem.uuconf_zdial_device = NULL;
153	  if (ilow == ihigh)
154	    {
155	      qport->uuconf_u.uuconf_smodem.uuconf_ibaud = ilow;
156	      qport->uuconf_u.uuconf_smodem.uuconf_ilowbaud = 0L;
157	      qport->uuconf_u.uuconf_smodem.uuconf_ihighbaud = 0L;
158	    }
159	  else
160	    {
161	      qport->uuconf_u.uuconf_smodem.uuconf_ibaud = 0L;
162	      qport->uuconf_u.uuconf_smodem.uuconf_ilowbaud = ilow;
163	      qport->uuconf_u.uuconf_smodem.uuconf_ihighbaud = ihigh;
164	    }
165	  qport->uuconf_u.uuconf_smodem.uuconf_fcarrier = TRUE;
166	  qport->uuconf_u.uuconf_smodem.uuconf_fhardflow = TRUE;
167	  if (ctoks < 5)
168	    qport->uuconf_u.uuconf_smodem.uuconf_pzdialer = NULL;
169	  else
170	    {
171	      size_t c;
172	      char **pzd;
173
174	      /* We support dialer/token pairs, although normal V2
175		 doesn't.  */
176	      pblock = uuconf_malloc_block ();
177	      if (pblock == NULL)
178		{
179		  qglobal->ierrno = errno;
180		  iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
181		  break;
182		}
183	      c = (ctoks - 4) * sizeof (char *);
184	      pzd = (char **) uuconf_malloc (pblock, c + sizeof (char *));
185	      if (pzd == NULL)
186		{
187		  qglobal->ierrno = errno;
188		  uuconf_free_block (pblock);
189		  iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
190		  break;
191		}
192	      memcpy ((pointer) pzd, (pointer) (pzsplit + 4), c);
193	      pzd[ctoks - 4] = NULL;
194
195	      qport->uuconf_u.uuconf_smodem.uuconf_pzdialer = pzd;
196	    }
197	  qport->uuconf_u.uuconf_smodem.uuconf_qdialer = NULL;
198	}
199
200      if (pifn != NULL)
201	{
202	  iret = (*pifn) (qport, pinfo);
203	  if (iret != UUCONF_SUCCESS)
204	    {
205	      if (pblock != NULL)
206		uuconf_free_block (pblock);
207	      if (iret != UUCONF_NOT_FOUND)
208		break;
209	      continue;
210	    }
211	}
212
213      /* This is the port we want.  */
214      if (pblock == NULL)
215	{
216	  pblock = uuconf_malloc_block ();
217	  if (pblock == NULL)
218	    {
219	      qglobal->ierrno = errno;
220	      iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
221	      break;
222	    }
223	}
224
225      if (uuconf_add_block (pblock, zline) != 0)
226	{
227	  qglobal->ierrno = errno;
228	  uuconf_free_block (pblock);
229	  iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
230	  break;
231	}
232      zline = NULL;
233
234      qport->uuconf_palloc = pblock;
235
236      break;
237    }
238
239  (void) fclose (e);
240
241  if (zline != NULL)
242    free ((pointer) zline);
243  if (pzsplit != NULL)
244    free ((pointer) pzsplit);
245
246  if (iret != UUCONF_SUCCESS && iret != UUCONF_NOT_FOUND)
247    {
248      qglobal->zfilename = qglobal->qprocess->zv2devices;
249      iret |= UUCONF_ERROR_FILENAME | UUCONF_ERROR_LINENO;
250    }
251
252  return iret;
253}
254