1 /* syssub.c
2    System information subroutines.
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_syssub_rcsid[] = "$FreeBSD$";
29 #endif
30 
31 #include <errno.h>
32 
33 /* This macro operates on every string (char *) field in struct
34    uuconf_system.  */
35 #define SYSTEM_STRINGS(OP) \
36   do \
37     { \
38       OP (uuconf_zname); \
39       OP (uuconf_zalternate); \
40       OP (uuconf_zdebug); \
41       OP (uuconf_zmax_remote_debug); \
42       OP (uuconf_zphone); \
43       OP (uuconf_zcall_login); \
44       OP (uuconf_zcall_password); \
45       OP (uuconf_zcalled_login); \
46       OP (uuconf_zprotocols); \
47       OP (uuconf_zpubdir); \
48       OP (uuconf_zlocalname); \
49     } \
50   while (0)
51 
52 /* This macro operates on every string array (char **) field in struct
53    uuconf_system.  */
54 #define SYSTEM_STRING_ARRAYS(OP) \
55   do \
56     { \
57       OP (uuconf_pzalias); \
58       OP (uuconf_pzlocal_send); \
59       OP (uuconf_pzremote_send); \
60       OP (uuconf_pzlocal_receive); \
61       OP (uuconf_pzremote_receive); \
62       OP (uuconf_pzpath); \
63       OP (uuconf_pzcmds); \
64       OP (uuconf_pzforward_from); \
65       OP (uuconf_pzforward_to); \
66       OP (uuconf_schat.uuconf_pzchat); \
67       OP (uuconf_schat.uuconf_pzprogram); \
68       OP (uuconf_schat.uuconf_pzfail); \
69       OP (uuconf_scalled_chat.uuconf_pzchat); \
70       OP (uuconf_scalled_chat.uuconf_pzprogram); \
71       OP (uuconf_scalled_chat.uuconf_pzfail); \
72     } \
73   while (0)
74 
75 /* This macro operations on every timespan pointer (struct
76    uuconf_timespan *) in struct uuconf_system.  */
77 #define SYSTEM_TIMESPANS(OP) \
78   do \
79     { \
80       OP (uuconf_qtimegrade); \
81       OP (uuconf_qcalltimegrade); \
82       OP (uuconf_qcalledtimegrade); \
83       OP (uuconf_qcall_local_size); \
84       OP (uuconf_qcall_remote_size); \
85       OP (uuconf_qcalled_local_size); \
86       OP (uuconf_qcalled_remote_size); \
87     } \
88   while (0)
89 
90 /* This macro operates on every boolean value (of type int, although
91    some type int are not boolean) field in uuconf_system.  */
92 #define SYSTEM_BOOLEANS(OP) \
93   do \
94     { \
95       OP (uuconf_fcall); \
96       OP (uuconf_fcalled); \
97       OP (uuconf_fcallback); \
98       OP (uuconf_fsequence); \
99       OP (uuconf_fsend_request); \
100       OP (uuconf_frec_request); \
101       OP (uuconf_fcall_transfer); \
102       OP (uuconf_fcalled_transfer); \
103       OP (uuconf_schat.uuconf_fstrip); \
104       OP (uuconf_scalled_chat.uuconf_fstrip); \
105     } \
106   while (0)
107 
108 /* This macro operates on every generic integer (type int or long) in
109    uuconf_system.  */
110 #define SYSTEM_INTEGERS(OP) \
111   do \
112     { \
113       OP (uuconf_cmax_retries); \
114       OP (uuconf_csuccess_wait); \
115       OP (uuconf_ibaud); \
116       OP (uuconf_ihighbaud); \
117       OP (uuconf_cfree_space); \
118       OP (uuconf_schat.uuconf_ctimeout); \
119       OP (uuconf_scalled_chat.uuconf_ctimeout); \
120       OP (uuconf_cmax_file_time); \
121     } \
122   while (0)
123 
124 /* There is no macro for uuconf_qalternate, uuconf_zport,
125    uuconf_qport, uuconf_qproto_params, or uuconf_palloc.  */
126 
127 /* Clear the contents of a struct uuconf_system.  */
128 
129 void
_uuconf_uclear_system(q)130 _uuconf_uclear_system (q)
131      struct uuconf_system *q;
132 {
133 #define CLEAR(x) q->x = (char *) &_uuconf_unset
134   SYSTEM_STRINGS (CLEAR);
135 #undef CLEAR
136 #define CLEAR(x) q->x = (char **) &_uuconf_unset
137   SYSTEM_STRING_ARRAYS (CLEAR);
138 #undef CLEAR
139 #define CLEAR(x) q->x = (struct uuconf_timespan *) &_uuconf_unset
140   SYSTEM_TIMESPANS (CLEAR);
141 #undef CLEAR
142 #define CLEAR(x) q->x = -1
143   SYSTEM_BOOLEANS (CLEAR);
144   SYSTEM_INTEGERS (CLEAR);
145 #undef CLEAR
146   q->uuconf_qalternate = NULL;
147   q->uuconf_zport = (char *) &_uuconf_unset;
148   q->uuconf_qport = (struct uuconf_port *) &_uuconf_unset;
149   q->uuconf_qproto_params = (struct uuconf_proto_param *) &_uuconf_unset;
150   q->uuconf_palloc = NULL;
151 }
152 
153 /* Default the contents of one struct uuconf_system to the contents of
154    another.  This default alternate by alternate.  Any additional
155    alternates in q default to the last alternate of qdefault.  If the
156    faddalternates arguments is TRUE, additional alternates or qdefault
157    are added to q; these alternates are copies of the first alternate
158    of q, and defaults are set from the additional alternates of
159    qdefault.  */
160 
161 int
_uuconf_isystem_default(qglobal,qset,qdefault,faddalternates)162 _uuconf_isystem_default (qglobal, qset, qdefault, faddalternates)
163      struct sglobal *qglobal;
164      struct uuconf_system *qset;
165      struct uuconf_system *qdefault;
166      boolean faddalternates;
167 {
168   struct uuconf_system *qalt;
169 
170   if (qset->uuconf_palloc != qdefault->uuconf_palloc)
171     qset->uuconf_palloc =
172       _uuconf_pmalloc_block_merge (qset->uuconf_palloc,
173 				   qdefault->uuconf_palloc);
174 
175   /* If we are adding alternates from the default, make sure we have
176      at least as many alternates in qset as we do in qdefault.  Each
177      new alternate we create gets initialized to the first alternate
178      of the system.  */
179   if (faddalternates)
180     {
181       struct uuconf_system **pq, *qdef;
182 
183       for (qdef = qdefault, pq = &qset;
184 	   qdef != NULL;
185 	   qdef = qdef->uuconf_qalternate, pq = &(*pq)->uuconf_qalternate)
186 	{
187 	  if (*pq == NULL)
188 	    {
189 	      *pq = ((struct uuconf_system *)
190 		     uuconf_malloc (qset->uuconf_palloc,
191 				    sizeof (struct uuconf_system)));
192 	      if (*pq == NULL)
193 		{
194 		  qglobal->ierrno = errno;
195 		  return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
196 		}
197 	      **pq = *qset;
198 	      (*pq)->uuconf_qalternate = NULL;
199 	    }
200 	}
201     }
202 
203   for (qalt = qset; qalt != NULL; qalt = qalt->uuconf_qalternate)
204     {
205 #define DEFAULT(x) \
206   if (qalt->x == (char *) &_uuconf_unset) qalt->x = qdefault->x
207       SYSTEM_STRINGS (DEFAULT);
208 #undef DEFAULT
209 #define DEFAULT(x) \
210   if (qalt->x == (char **) &_uuconf_unset) qalt->x = qdefault->x
211       SYSTEM_STRING_ARRAYS (DEFAULT);
212 #undef DEFAULT
213 #define DEFAULT(x) \
214   if (qalt->x == (struct uuconf_timespan *) &_uuconf_unset) \
215     qalt->x = qdefault->x
216       SYSTEM_TIMESPANS (DEFAULT);
217 #undef DEFAULT
218 #define DEFAULT(x) if (qalt->x < 0) qalt->x = qdefault->x
219       SYSTEM_BOOLEANS (DEFAULT);
220       SYSTEM_INTEGERS (DEFAULT);
221 #undef DEFAULT
222 
223       /* We only copy over zport if both zport and qport are NULL,
224 	 because otherwise a default zport would override a specific
225 	 qport.  */
226       if (qalt->uuconf_zport == (char *) &_uuconf_unset
227 	  && qalt->uuconf_qport == (struct uuconf_port *) &_uuconf_unset)
228 	qalt->uuconf_zport = qdefault->uuconf_zport;
229       if (qalt->uuconf_qport == (struct uuconf_port *) &_uuconf_unset)
230 	qalt->uuconf_qport = qdefault->uuconf_qport;
231 
232       if (qalt->uuconf_qproto_params
233 	  == (struct uuconf_proto_param *) &_uuconf_unset)
234 	qalt->uuconf_qproto_params = qdefault->uuconf_qproto_params;
235       else if (qdefault->uuconf_qproto_params != NULL)
236 	{
237 	  int cnew, ca;
238 	  struct uuconf_proto_param *qd, *qa;
239 
240 	  /* Merge in the default protocol parameters, so that a
241 	     system with 'g' protocol parameters won't lose the
242 	     default 'i' protocol parameters.  */
243 	  ca = 0;
244 	  cnew = 0;
245 	  for (qd = qdefault->uuconf_qproto_params;
246 	       qd->uuconf_bproto != '\0';
247 	       qd++)
248 	    {
249 	      int c;
250 
251 	      c = 0;
252 	      for (qa = qalt->uuconf_qproto_params;
253 		   (qa->uuconf_bproto != '\0'
254 		    && qa->uuconf_bproto != qd->uuconf_bproto);
255 		   qa++)
256 		++c;
257 	      if (qa->uuconf_bproto == '\0')
258 		{
259 		  ++cnew;
260 		  ca = c;
261 		}
262 	    }
263 
264 	  if (cnew > 0)
265 	    {
266 	      struct uuconf_proto_param *qnew;
267 
268 	      qnew = ((struct uuconf_proto_param *)
269 		      uuconf_malloc (qset->uuconf_palloc,
270 				     ((ca + cnew + 1)
271 				      * sizeof (struct uuconf_proto_param))));
272 	      if (qnew == NULL)
273 		{
274 		  qglobal->ierrno = errno;
275 		  return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
276 		}
277 	      memcpy ((pointer) qnew, (pointer) qalt->uuconf_qproto_params,
278 		      ca * sizeof (struct uuconf_proto_param));
279 	      cnew = 0;
280 	      for (qd = qdefault->uuconf_qproto_params;
281 		   qd->uuconf_bproto != '\0';
282 		   qd++)
283 		{
284 		  for (qa = qalt->uuconf_qproto_params;
285 		       (qa->uuconf_bproto != '\0'
286 			&& qa->uuconf_bproto != qd->uuconf_bproto);
287 		       qa++)
288 		    ;
289 		  if (qa->uuconf_bproto == '\0')
290 		    {
291 		      qnew[ca + cnew] = *qd;
292 		      ++cnew;
293 		    }
294 		}
295 	      qnew[ca + cnew].uuconf_bproto = '\0';
296 	      uuconf_free (qset->uuconf_palloc, qalt->uuconf_qproto_params);
297 	      qalt->uuconf_qproto_params = qnew;
298 	    }
299 	}
300 
301       if (qdefault->uuconf_qalternate != NULL)
302 	qdefault = qdefault->uuconf_qalternate;
303     }
304 
305   return UUCONF_SUCCESS;
306 }
307 
308 /* Put in the basic defaults.  This ensures that the fields are valid
309    on every uuconf_system structure.  */
310 
311 int
_uuconf_isystem_basic_default(qglobal,q)312 _uuconf_isystem_basic_default (qglobal, q)
313      struct sglobal *qglobal;
314      register struct uuconf_system *q;
315 {
316   int iret;
317 
318   iret = UUCONF_SUCCESS;
319 
320   for (; q != NULL && iret == UUCONF_SUCCESS; q = q->uuconf_qalternate)
321     {
322       /* The default of 26 allowable retries is traditional.  */
323       if (q->uuconf_cmax_retries < 0)
324 	q->uuconf_cmax_retries = 26;
325       if (q->uuconf_schat.uuconf_pzchat == (char **) &_uuconf_unset)
326 	{
327 	  q->uuconf_schat.uuconf_pzchat = NULL;
328 	  iret = _uuconf_iadd_string (qglobal, (char *) "\"\"", FALSE,
329 				      FALSE,
330 				      &q->uuconf_schat.uuconf_pzchat,
331 				      q->uuconf_palloc);
332 	  if (iret != UUCONF_SUCCESS)
333 	    return iret;
334 	  iret = _uuconf_iadd_string (qglobal, (char *) "\\r\\c", FALSE,
335 				      FALSE,
336 				      &q->uuconf_schat.uuconf_pzchat,
337 				      q->uuconf_palloc);
338 	  if (iret != UUCONF_SUCCESS)
339 	    return iret;
340 	  iret = _uuconf_iadd_string (qglobal, (char *) "ogin:", FALSE,
341 				      FALSE,
342 				      &q->uuconf_schat.uuconf_pzchat,
343 				      q->uuconf_palloc);
344 	  if (iret != UUCONF_SUCCESS)
345 	    return iret;
346 	  iret = _uuconf_iadd_string (qglobal, (char *) "-BREAK", FALSE,
347 				      FALSE,
348 				      &q->uuconf_schat.uuconf_pzchat,
349 				      q->uuconf_palloc);
350 	  if (iret != UUCONF_SUCCESS)
351 	    return iret;
352 	  iret = _uuconf_iadd_string (qglobal, (char *) "-ogin:", FALSE,
353 				      FALSE,
354 				      &q->uuconf_schat.uuconf_pzchat,
355 				      q->uuconf_palloc);
356 	  if (iret != UUCONF_SUCCESS)
357 	    return iret;
358 	  iret = _uuconf_iadd_string (qglobal, (char *) "-BREAK", FALSE,
359 				      FALSE,
360 				      &q->uuconf_schat.uuconf_pzchat,
361 				      q->uuconf_palloc);
362 	  if (iret != UUCONF_SUCCESS)
363 	    return iret;
364 	  iret = _uuconf_iadd_string (qglobal, (char *) "-ogin:", FALSE,
365 				      FALSE,
366 				      &q->uuconf_schat.uuconf_pzchat,
367 				      q->uuconf_palloc);
368 	  if (iret != UUCONF_SUCCESS)
369 	    return iret;
370 	  iret = _uuconf_iadd_string (qglobal, (char *) "\\L", FALSE,
371 				      FALSE,
372 				      &q->uuconf_schat.uuconf_pzchat,
373 				      q->uuconf_palloc);
374 	  if (iret != UUCONF_SUCCESS)
375 	    return iret;
376 	  iret = _uuconf_iadd_string (qglobal, (char *) "word:", FALSE,
377 				      FALSE,
378 				      &q->uuconf_schat.uuconf_pzchat,
379 				      q->uuconf_palloc);
380 	  if (iret != UUCONF_SUCCESS)
381 	    return iret;
382 	  iret = _uuconf_iadd_string (qglobal, (char *) "\\P", FALSE,
383 				      FALSE,
384 				      &q->uuconf_schat.uuconf_pzchat,
385 				      q->uuconf_palloc);
386 	  if (iret != UUCONF_SUCCESS)
387 	    return iret;
388 	}
389       if (q->uuconf_schat.uuconf_ctimeout < 0)
390 	q->uuconf_schat.uuconf_ctimeout = 10;
391       if (q->uuconf_schat.uuconf_fstrip < 0)
392 	q->uuconf_schat.uuconf_fstrip = TRUE;
393       if (q->uuconf_scalled_chat.uuconf_ctimeout < 0)
394 	q->uuconf_scalled_chat.uuconf_ctimeout = 60;
395       if (q->uuconf_scalled_chat.uuconf_fstrip < 0)
396 	q->uuconf_scalled_chat.uuconf_fstrip = TRUE;
397       if (q->uuconf_fsend_request < 0)
398 	q->uuconf_fsend_request = TRUE;
399       if (q->uuconf_frec_request < 0)
400 	q->uuconf_frec_request = TRUE;
401       if (q->uuconf_fcall_transfer < 0)
402 	q->uuconf_fcall_transfer = TRUE;
403       if (q->uuconf_fcalled_transfer < 0)
404 	q->uuconf_fcalled_transfer = TRUE;
405       if (q->uuconf_pzlocal_send == (char **) &_uuconf_unset)
406 	{
407 	  q->uuconf_pzlocal_send = NULL;
408 	  iret = _uuconf_iadd_string (qglobal, (char *) ZROOTDIR, FALSE,
409 				      FALSE, &q->uuconf_pzlocal_send,
410 				      q->uuconf_palloc);
411 	  if (iret != UUCONF_SUCCESS)
412 	    return iret;
413 	}
414       if (q->uuconf_pzremote_send == (char **) &_uuconf_unset)
415 	{
416 	  q->uuconf_pzremote_send = NULL;
417 	  iret = _uuconf_iadd_string (qglobal, (char *) "~", FALSE, FALSE,
418 				      &q->uuconf_pzremote_send,
419 				      q->uuconf_palloc);
420 	  if (iret != UUCONF_SUCCESS)
421 	    return iret;
422 	}
423       if (q->uuconf_pzlocal_receive == (char **) &_uuconf_unset)
424 	{
425 	  q->uuconf_pzlocal_receive = NULL;
426 	  iret = _uuconf_iadd_string (qglobal, (char *) "~", FALSE, FALSE,
427 				      &q->uuconf_pzlocal_receive,
428 				      q->uuconf_palloc);
429 	  if (iret != UUCONF_SUCCESS)
430 	    return iret;
431 	}
432       if (q->uuconf_pzremote_receive == (char **) &_uuconf_unset)
433 	{
434 	  q->uuconf_pzremote_receive = NULL;
435 	  iret = _uuconf_iadd_string (qglobal, (char *) "~", FALSE, FALSE,
436 				      &q->uuconf_pzremote_receive,
437 				      q->uuconf_palloc);
438 	  if (iret != UUCONF_SUCCESS)
439 	    return iret;
440 	}
441 
442       if (q->uuconf_pzpath == (char **) &_uuconf_unset)
443 	{
444 	  char *zdup;
445 	  char **pz;
446 	  size_t csplit;
447 	  int c;
448 
449 	  zdup = (char *) uuconf_malloc (q->uuconf_palloc, sizeof CMDPATH);
450 	  if (zdup == NULL)
451 	    {
452 	      qglobal->ierrno = errno;
453 	      return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
454 	    }
455 
456 	  memcpy ((pointer) zdup, (pointer) CMDPATH, sizeof CMDPATH);
457 	  pz = NULL;
458 	  csplit = 0;
459 	  if ((c = _uuconf_istrsplit (zdup, '\0', &pz, &csplit)) < 0)
460 	    {
461 	      qglobal->ierrno = errno;
462 	      return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
463 	    }
464 	  q->uuconf_pzpath = (char **) uuconf_malloc (q->uuconf_palloc,
465 						      ((c + 1)
466 						       * sizeof (char *)));
467 	  if (q->uuconf_pzpath == NULL)
468 	    {
469 	      qglobal->ierrno = errno;
470 	      return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
471 	    }
472 	  memcpy ((pointer) q->uuconf_pzpath, (pointer) pz,
473 		  c * sizeof (char *));
474 	  q->uuconf_pzpath[c] = NULL;
475 	  free ((pointer) pz);
476 	}
477 
478       if (q->uuconf_pzcmds == (char **) &_uuconf_unset)
479 	{
480 	  q->uuconf_pzcmds = ((char **)
481 			      uuconf_malloc (q->uuconf_palloc,
482 					     3 * sizeof (const char *)));
483 	  if (q->uuconf_pzcmds == NULL)
484 	    {
485 	      qglobal->ierrno = errno;
486 	      return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
487 	    }
488 	  q->uuconf_pzcmds[0] = (char *) "rnews";
489 	  q->uuconf_pzcmds[1] = (char *) "rmail";
490 	  q->uuconf_pzcmds[2] = NULL;
491 	}
492 
493       if (q->uuconf_cfree_space < 0)
494 	q->uuconf_cfree_space = DEFAULT_FREE_SPACE;
495 
496       if (q->uuconf_zpubdir == (const char *) &_uuconf_unset)
497 	q->uuconf_zpubdir = qglobal->qprocess->zpubdir;
498 
499 #define SET(x) if (q->x == (char *) &_uuconf_unset) q->x = NULL
500       SYSTEM_STRINGS(SET);
501 #undef SET
502 #define SET(x) if (q->x == (char **) &_uuconf_unset) q->x = NULL
503       SYSTEM_STRING_ARRAYS(SET);
504 #undef SET
505 #define SET(x) \
506   if (q->x == (struct uuconf_timespan *) &_uuconf_unset) q->x = NULL
507       SYSTEM_TIMESPANS (SET);
508 #undef SET
509 #define SET(x) if (q->x < 0) q->x = 0
510       SYSTEM_BOOLEANS (SET);
511       SYSTEM_INTEGERS (SET);
512 #undef SET
513 
514       if (q->uuconf_zport == (char *) &_uuconf_unset)
515 	q->uuconf_zport = NULL;
516       if (q->uuconf_qport == (struct uuconf_port *) &_uuconf_unset)
517 	q->uuconf_qport = NULL;
518       if (q->uuconf_qproto_params
519 	  == (struct uuconf_proto_param *) &_uuconf_unset)
520 	q->uuconf_qproto_params = NULL;
521     }
522 
523   return iret;
524 }
525