Upgrade to version 1.05
[unix-history] / gnu / libexec / uucp / libuuconf / hsinfo.c
CommitLineData
41c799d4
C
1/* hsinfo.c
2 Get information about a system from the HDB configuration files.
3
3469b437 4 Copyright (C) 1992, 1993 Ian Lance Taylor
41c799d4
C
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., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22 The author of the program may be contacted at ian@airs.com or
3469b437 23 c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
41c799d4
C
24 */
25
26#include "uucnfi.h"
27
28#if USE_RCS_ID
3469b437 29const char _uuconf_hsinfo_rcsid[] = "$Id: hsinfo.c,v 1.10 1994/01/30 21:14:29 ian Rel $";
41c799d4
C
30#endif
31
32#include <errno.h>
33#include <ctype.h>
34\f
35static int ihadd_machine_perm P((struct sglobal *qglobal,
36 struct uuconf_system *qsys,
37 struct shpermissions *qperm));
38static int ihadd_logname_perm P((struct sglobal *qglobal,
39 struct uuconf_system *qsys,
40 struct shpermissions *qperm));
41\f
42/* Get the information for a particular system from the HDB
43 configuration files. This does not make sure that all the default
44 values are set. */
45
46int
47_uuconf_ihdb_system_internal (qglobal, zsystem, qsys)
48 struct sglobal *qglobal;
49 const char *zsystem;
50 struct uuconf_system *qsys;
51{
52 int iret;
53 struct shpermissions *qperm;
54 char *zline;
55 size_t cline;
56 char **pzsplit;
57 size_t csplit;
58 char **pzcomma;
59 size_t ccomma;
60 pointer pblock;
61 char **pz;
62 boolean ffound_machine, ffound_login;
63 struct shpermissions *qother_machine;
64 struct uuconf_system *qalt;
65
66 if (! qglobal->qprocess->fhdb_read_permissions)
67 {
68 iret = _uuconf_ihread_permissions (qglobal);
69 if (iret != UUCONF_SUCCESS)
70 return iret;
71 }
72
73 /* First look through the Permissions information to see if this is
74 an alias for some system. I assume that an alias applies to the
75 first name in the corresponding MACHINE entry. */
76
77 for (qperm = qglobal->qprocess->qhdb_permissions;
78 qperm != NULL;
79 qperm = qperm->qnext)
80 {
81 if (qperm->pzalias == NULL
82 || qperm->pzmachine == NULL
83 || qperm->pzalias == (char **) &_uuconf_unset
84 || qperm->pzmachine == (char **) &_uuconf_unset)
85 continue;
86
87 for (pz = qperm->pzalias; *pz != NULL; pz++)
88 {
89 if (strcmp (*pz, zsystem) == 0)
90 {
91 zsystem = qperm->pzmachine[0];
92 break;
93 }
94 }
95 if (*pz != NULL)
96 break;
97 }
98
99 zline = NULL;
100 cline = 0;
101 pzsplit = NULL;
102 csplit = 0;
103 pzcomma = NULL;
104 ccomma = 0;
105
106 pblock = NULL;
107
108 iret = UUCONF_SUCCESS;
109
110 for (pz = qglobal->qprocess->pzhdb_systems; *pz != NULL; pz++)
111 {
112 FILE *e;
113 int cchars;
114
3469b437
AC
115 qglobal->ilineno = 0;
116
41c799d4
C
117 e = fopen (*pz, "r");
118 if (e == NULL)
119 {
120 if (FNO_SUCH_FILE ())
121 continue;
122 qglobal->ierrno = errno;
123 iret = UUCONF_FOPEN_FAILED | UUCONF_ERROR_ERRNO;
124 break;
125 }
126
41c799d4
C
127 while ((cchars = _uuconf_getline (qglobal, &zline, &cline, e)) > 0)
128 {
129 int ctoks, ctimes, i;
130 struct uuconf_system *qset;
131 char *z, *zretry;
132 int cretry;
133
134 ++qglobal->ilineno;
135
136 --cchars;
137 if (zline[cchars] == '\n')
138 zline[cchars] = '\0';
139 if (isspace (BUCHAR (zline[0])) || zline[0] == '#')
140 continue;
141
142 ctoks = _uuconf_istrsplit (zline, '\0', &pzsplit, &csplit);
143 if (ctoks < 0)
144 {
145 qglobal->ierrno = errno;
146 iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
147 break;
148 }
149
150 /* If this isn't the system we're looking for, keep reading
151 the file. */
152 if (ctoks < 1
153 || strcmp (zsystem, pzsplit[0]) != 0)
154 continue;
155
156 /* If this is the first time we've found the system, we want
157 to set *qsys directly. Otherwise, we allocate a new
158 alternate. */
159 if (pblock == NULL)
160 {
161 pblock = uuconf_malloc_block ();
162 if (pblock == NULL)
163 {
164 qglobal->ierrno = errno;
165 iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
166 break;
167 }
168 _uuconf_uclear_system (qsys);
169 qsys->uuconf_palloc = pblock;
170 qset = qsys;
171 }
172 else
173 {
174 struct uuconf_system **pq;
175
176 qset = ((struct uuconf_system *)
177 uuconf_malloc (pblock, sizeof (struct uuconf_system)));
178 if (qset == NULL)
179 {
180 qglobal->ierrno = errno;
181 iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
182 break;
183 }
184 _uuconf_uclear_system (qset);
185 for (pq = &qsys->uuconf_qalternate;
186 *pq != NULL;
187 pq = &(*pq)->uuconf_qalternate)
188 ;
189 *pq = qset;
190 }
191
192 /* Add this line to the memory block we are building for the
193 system. */
194 if (uuconf_add_block (pblock, zline) != 0)
195 {
196 qglobal->ierrno = errno;
197 iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
198 break;
199 }
200
201 zline = NULL;
202 cline = 0;
203
204 /* The format of a line in Systems is
205 system time device speed phone chat
206 For example,
207 airs Any ACU 9600 5551212 ogin: foo pass: bar
208 */
209
210 /* Get the system name. */
211
212 qset->uuconf_zname = pzsplit[0];
213 qset->uuconf_fcall = TRUE;
214 qset->uuconf_fcalled = FALSE;
215
216 if (ctoks < 2)
217 continue;
218
219 /* A time string is "time/grade,time/grade;retry". A
220 missing grade is taken as BGRADE_LOW. */
221 zretry = strchr (pzsplit[1], ';');
222 if (zretry == NULL)
223 cretry = 0;
224 else
225 {
226 *zretry = '\0';
227 cretry = (int) strtol (zretry + 1, (char **) NULL, 10);
228 }
229
230 ctimes = _uuconf_istrsplit (pzsplit[1], ',', &pzcomma, &ccomma);
231 if (ctimes < 0)
232 {
233 qglobal->ierrno = errno;
234 iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
235 break;
236 }
237
238 for (i = 0; i < ctimes; i++)
239 {
240 char *zslash;
241 char bgrade;
242
243 z = pzcomma[i];
244 zslash = strchr (z, '/');
245 if (zslash == NULL)
246 bgrade = UUCONF_GRADE_LOW;
247 else
248 {
249 *zslash = '\0';
250 bgrade = zslash[1];
251 if (! UUCONF_GRADE_LEGAL (bgrade))
252 bgrade = UUCONF_GRADE_LOW;
253 }
254
255 iret = _uuconf_itime_parse (qglobal, z, (long) bgrade,
256 cretry, _uuconf_itime_grade_cmp,
257 &qset->uuconf_qtimegrade,
258 pblock);
259 if (iret != UUCONF_SUCCESS)
260 break;
3469b437
AC
261
262 /* Treat any time/grade setting as both a timegrade and
263 a call-timegrade. */
264 if (bgrade != UUCONF_GRADE_LOW)
265 qset->uuconf_qcalltimegrade = qset->uuconf_qtimegrade;
41c799d4
C
266 }
267
268 if (iret != UUCONF_SUCCESS)
269 break;
270
271 if (ctoks < 3)
272 continue;
273
274 /* Pick up the device name. It can be followed by a comma
275 and a list of protocols. */
276 qset->uuconf_zport = pzsplit[2];
277 z = strchr (pzsplit[2], ',');
278 if (z != NULL)
279 {
280 qset->uuconf_zprotocols = z + 1;
281 *z = '\0';
282 }
283
284 if (ctoks < 4)
285 continue;
286
287 /* The speed entry can be a numeric speed, or a range of
288 speeds, or "Any", or "-". If it starts with a letter,
289 the initial nonnumeric prefix is a modem class, which
290 gets appended to the port name. */
291 z = pzsplit[3];
292 if (strcasecmp (z, "Any") != 0
293 && strcmp (z, "-") != 0)
294 {
295 char *zend;
296
297 while (*z != '\0' && ! isdigit (BUCHAR (*z)))
298 ++z;
299
300 qset->uuconf_ibaud = strtol (z, &zend, 10);
301 if (*zend == '-')
302 qset->uuconf_ihighbaud = strtol (zend + 1, (char **) NULL,
303 10);
304
305 if (z != pzsplit[3])
306 {
307 size_t cport, cclass;
308
309 cport = strlen (pzsplit[2]);
310 cclass = z - pzsplit[3];
311 qset->uuconf_zport = uuconf_malloc (pblock,
312 cport + cclass + 1);
313 if (qset->uuconf_zport == NULL)
314 {
315 qglobal->ierrno = errno;
316 iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
317 break;
318 }
319 memcpy ((pointer) qset->uuconf_zport, (pointer) pzsplit[2],
320 cport);
321 memcpy ((pointer) (qset->uuconf_zport + cport),
322 (pointer) pzsplit[3], cclass);
323 qset->uuconf_zport[cport + cclass] = '\0';
324 }
325 }
326
327 if (ctoks < 5)
328 continue;
329
330 /* Get the phone number. */
331 qset->uuconf_zphone = pzsplit[4];
332
333 if (ctoks < 6)
334 continue;
335
336 /* Get the chat script. We just hand this off to the chat
337 script processor, so that it will parse subsend and
338 subexpect strings correctly. */
339 pzsplit[4] = (char *) "chat";
340 iret = _uuconf_ichat_cmd (qglobal, ctoks - 4, pzsplit + 4,
341 &qset->uuconf_schat, pblock);
342 iret &=~ UUCONF_CMDTABRET_KEEP;
343 if (iret != UUCONF_SUCCESS)
344 break;
345 }
346
347 (void) fclose (e);
348
349 if (iret != UUCONF_SUCCESS)
350 break;
351 }
352
353 if (zline != NULL)
354 free ((pointer) zline);
355 if (pzsplit != NULL)
356 free ((pointer) pzsplit);
357 if (pzcomma != NULL)
358 free ((pointer) pzcomma);
359
360 if (iret != UUCONF_SUCCESS)
361 {
362 qglobal->zfilename = *pz;
3469b437 363 return iret | UUCONF_ERROR_FILENAME | UUCONF_ERROR_LINENO;
41c799d4
C
364 }
365
366 if (pblock == NULL)
367 return UUCONF_NOT_FOUND;
368
369 /* Now we have to put in the Permissions information. The relevant
370 Permissions entries are those with this system in the MACHINE
371 list and (if this system does not have a VALIDATE entry) those
372 with a LOGNAME list but no MACHINE list. If no entry is found
373 with this system in the MACHINE list, then we must look for an
374 entry with "OTHER" in the MACHINE list. */
375 ffound_machine = FALSE;
376 ffound_login = FALSE;
377 qother_machine = NULL;
378 for (qperm = qglobal->qprocess->qhdb_permissions;
379 qperm != NULL;
380 qperm = qperm->qnext)
381 {
382 boolean fmachine;
383
384 /* MACHINE=OTHER is recognized specially. It appears that OTHER
385 need only be recognized by itself, not when combined with
386 other machine names. */
387 if (qother_machine == NULL
388 && qperm->pzmachine != NULL
389 && qperm->pzmachine != (char **) &_uuconf_unset
390 && qperm->pzmachine[0][0] == 'O'
391 && strcmp (qperm->pzmachine[0], "OTHER") == 0)
392 qother_machine = qperm;
393
394 /* If this system is named in a MACHINE entry, we must add the
395 appropriate information to every alternate that could be used
396 for calling out. */
397 fmachine = FALSE;
398 if (! ffound_machine
399 && qperm->pzmachine != NULL
400 && qperm->pzmachine != (char **) &_uuconf_unset)
401 {
402 for (pz = qperm->pzmachine; *pz != NULL; pz++)
403 {
404 if ((*pz)[0] == zsystem[0]
405 && strcmp (*pz, zsystem) == 0)
406 {
407 for (qalt = qsys;
408 qalt != NULL;
409 qalt = qalt->uuconf_qalternate)
410 {
411 if (qalt->uuconf_fcall)
412 {
413 iret = ihadd_machine_perm (qglobal, qalt, qperm);
414 if (iret != UUCONF_SUCCESS)
415 return iret;
416 }
417 }
418
419 fmachine = TRUE;
420 ffound_machine = TRUE;
421
422 break;
423 }
424 }
425 }
426
427 /* A LOGNAME line applies to this machine if it is listed in the
428 corresponding VALIDATE entry, or if it is not listed in any
429 VALIDATE entry. On this pass through the Permissions entry
430 we pick up the information if the system appears in a
431 VALIDATE entry; if it does not, we make another pass to put
432 in all the LOGNAME lines. */
433 if (qperm->pzlogname != NULL
434 && qperm->pzlogname != (char **) &_uuconf_unset
435 && qperm->pzvalidate != NULL
436 && qperm->pzvalidate != (char **) &_uuconf_unset)
437 {
438 for (pz = qperm->pzvalidate; *pz != NULL; ++pz)
439 if ((*pz)[0] == zsystem[0]
440 && strcmp (*pz, zsystem) == 0)
441 break;
442 if (*pz != NULL)
443 {
444 for (pz = qperm->pzlogname; *pz != NULL; ++pz)
445 {
446 /* If this LOGNAME line is also a matching MACHINE
447 line, we can add the LOGNAME permissions to the
448 first alternate. Otherwise, we must create a new
449 alternate. We cannot put a LOGNAME line in the
450 first alternate if MACHINE does not match,
451 because certain permissions (e.g. READ) may be
452 specified by both types of lines, and we must use
453 LOGNAME entries only when accepting calls and
454 MACHINE entries only when placing calls. */
455 if (fmachine
456 && (qsys->uuconf_zcalled_login == NULL
457 || (qsys->uuconf_zcalled_login
458 == (char *) &_uuconf_unset)))
459 {
460 qsys->uuconf_zcalled_login = *pz;
461 iret = ihadd_logname_perm (qglobal, qsys, qperm);
462 }
463 else
464 {
465 struct uuconf_system *qnew;
466 struct uuconf_system **pq;
467
468 qnew = ((struct uuconf_system *)
469 uuconf_malloc (pblock,
470 sizeof (struct uuconf_system)));
471 if (qnew == NULL)
472 {
473 qglobal->ierrno = errno;
474 return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
475 }
476
477 *qnew = *qsys;
478 qnew->uuconf_qalternate = NULL;
479 for (pq = &qsys->uuconf_qalternate;
480 *pq != NULL;
481 pq = &(*pq)->uuconf_qalternate)
482 ;
483 *pq = qnew;
484
485 qnew->uuconf_zcalled_login = *pz;
486 qnew->uuconf_fcall = FALSE;
487 iret = ihadd_logname_perm (qglobal, qnew, qperm);
488 }
489
490 if (iret != UUCONF_SUCCESS)
491 return iret;
492 }
493
494 ffound_login = TRUE;
495 }
496 }
497 }
498
499 /* If we didn't find an entry for the machine, we must use the
500 MACHINE=OTHER entry, if any. */
501 if (! ffound_machine && qother_machine != NULL)
502 {
503 for (qalt = qsys; qalt != NULL; qalt = qalt->uuconf_qalternate)
504 {
505 if (qalt->uuconf_fcall)
506 {
507 iret = ihadd_machine_perm (qglobal, qalt, qother_machine);
508 if (iret != UUCONF_SUCCESS)
509 return iret;
510 }
511 }
512 }
513
514 /* If this system was not listed in any VALIDATE entry, then we must
515 add a called-login for each LOGNAME entry in Permissions. */
516 if (! ffound_login)
517 {
518 for (qperm = qglobal->qprocess->qhdb_permissions;
519 qperm != NULL;
520 qperm = qperm->qnext)
521 {
522 if (qperm->pzlogname == NULL
523 || qperm->pzlogname == (char **) &_uuconf_unset)
524 continue;
525
526 for (pz = qperm->pzlogname; *pz != NULL; pz++)
527 {
528 struct uuconf_system *qnew;
529 struct uuconf_system **pq;
530
531 qnew = ((struct uuconf_system *)
532 uuconf_malloc (pblock,
533 sizeof (struct uuconf_system)));
534 if (qnew == NULL)
535 {
536 qglobal->ierrno = errno;
537 return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
538 }
539
540 *qnew = *qsys;
541 qnew->uuconf_qalternate = NULL;
542 for (pq = &qsys->uuconf_qalternate;
543 *pq != NULL;
544 pq = &(*pq)->uuconf_qalternate)
545 ;
546 *pq = qnew;
547
548 /* We recognize LOGNAME=OTHER specially, although this
549 appears to be an SCO innovation. */
550 if (strcmp (*pz, "OTHER") == 0)
551 qnew->uuconf_zcalled_login = (char *) "ANY";
552 else
553 qnew->uuconf_zcalled_login = *pz;
554 qnew->uuconf_fcall = FALSE;
555 iret = ihadd_logname_perm (qglobal, qnew, qperm);
556 if (iret != UUCONF_SUCCESS)
557 return iret;
558 }
559 }
560 }
561
562 /* HDB permits local requests to receive to any directory, which is
563 not the default put in by _uuconf_isystem_basic_default. We set
564 it here instead. */
565 for (qalt = qsys; qalt != NULL; qalt = qalt->uuconf_qalternate)
566 {
567 iret = _uuconf_iadd_string (qglobal, (char *) ZROOTDIR,
568 FALSE, FALSE,
569 &qalt->uuconf_pzlocal_receive,
570 pblock);
571 if (iret != UUCONF_SUCCESS)
572 return iret;
573 }
574
575 /* HDB does not have a maximum number of retries if a retry time is
576 given in the time field. */
577 if (qsys->uuconf_qtimegrade != NULL
578 && qsys->uuconf_qtimegrade != (struct uuconf_timespan *) &_uuconf_unset
579 && qsys->uuconf_qtimegrade->uuconf_cretry > 0)
580 qsys->uuconf_cmax_retries = 0;
581
582 return UUCONF_SUCCESS;
583}
584\f
585/* Add the settings of a MACHINE line in Permissions to a system. */
586
587/*ARGSIGNORED*/
588static int
589ihadd_machine_perm (qglobal, qsys, qperm)
590 struct sglobal *qglobal;
591 struct uuconf_system *qsys;
592 struct shpermissions *qperm;
593{
594 if (qperm->frequest >= 0)
595 qsys->uuconf_fsend_request = qperm->frequest;
596 else
597 qsys->uuconf_fsend_request = FALSE;
598 qsys->uuconf_pzremote_send = qperm->pzread;
599 qsys->uuconf_pzremote_receive = qperm->pzwrite;
600 qsys->uuconf_pzcmds = qperm->pzcommands;
601 qsys->uuconf_zlocalname = qperm->zmyname;
602 qsys->uuconf_zpubdir = qperm->zpubdir;
603 qsys->uuconf_pzalias = qperm->pzalias;
604
605 return UUCONF_SUCCESS;
606}
607
608/* Add the settings of a LOGNAME line in Permissions to a system. */
609
610/*ARGSIGNORED*/
611static int
612ihadd_logname_perm (qglobal, qsys, qperm)
613 struct sglobal *qglobal;
614 struct uuconf_system *qsys;
615 struct shpermissions *qperm;
616{
617 qsys->uuconf_fcalled = TRUE;
618 if (qperm->frequest >= 0)
619 qsys->uuconf_fsend_request = qperm->frequest;
620 else
621 qsys->uuconf_fsend_request = FALSE;
622 qsys->uuconf_fcalled_transfer = qperm->fsendfiles;
623 qsys->uuconf_pzremote_send = qperm->pzread;
624 qsys->uuconf_pzremote_receive = qperm->pzwrite;
625 qsys->uuconf_fcallback = qperm->fcallback;
626 qsys->uuconf_zlocalname = qperm->zmyname;
627 qsys->uuconf_zpubdir = qperm->zpubdir;
628
629 return UUCONF_SUCCESS;
630}