1/* uuconv.c
2   Convert one type of UUCP configuration file to another.
3
4   Copyright (C) 1991, 1992, 1993, 1994, 1995, 2002 Ian Lance Taylor
5
6   This file is part of the Taylor UUCP package.
7
8   This program is free software; you can redistribute it and/or
9   modify it under the terms of the GNU General Public License as
10   published by the Free Software Foundation; either version 2 of the
11   License, or (at your option) any later version.
12
13   This program 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   General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program; 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 uuconv_rcsid[] = "$Id: uuconv.c,v 1.30 2002/03/05 19:10:42 ian Rel $";
29#endif
30
31#include "getopt.h"
32
33/* Local functions.  */
34
35static void uvusage P((void));
36static void uvhelp P((void));
37static void uvwrite_time P((FILE *e, struct uuconf_timespan *qtime));
38static void uvwrite_string P((FILE *e, const char *zarg, const char *zcmd));
39static void uvwrite_size P((FILE *e, struct uuconf_timespan *qsize,
40			    const char *zcmd));
41static void uvwrite_boolean P((FILE *e, int iarg, const char *zcmd));
42static void uvwrite_string_array P((FILE *e, char **pz, const char *zcmd));
43static void uvwrite_chat_script P((FILE *e, char **pz));
44static void uvwrite_chat P((FILE *e, const struct uuconf_chat *qchat,
45			    const struct uuconf_chat *qlast,
46			    const char *zprefix, boolean fforce));
47static void uvwrite_proto_params P((FILE *e,
48				    const struct uuconf_proto_param *qparam,
49				    const char *zprefix));
50static void uvwrite_taylor_system P((FILE *e,
51				     const struct uuconf_system *qsys));
52static void uvwrite_v2_system P((FILE *e,
53				 const struct uuconf_system *qsys));
54static void uvwrite_hdb_system P((FILE *e,
55				  const struct uuconf_system *qsys));
56static boolean fvperm_string_cmp P((const char *z1, const char *z2));
57static boolean fvperm_array_cmp P((const char **pz1, const char **pz2));
58static void uvadd_perm P((struct shpermissions *qadd));
59static void uvwrite_perms P((void));
60static void uvwrite_perm_array P((FILE *e, const char **pz,
61				  const char *zcmd, size_t *pccol));
62static void uvwrite_perm_boolean P((FILE *e, int f, const char *zcmd,
63				    size_t *pccol, boolean fsendfiles));
64static void uvwrite_perm_rw_array P((FILE *e, const char **pz,
65				     const char *zcmd, size_t *pccol));
66static void uvwrite_perm_string P((FILE *e, const char *z, const char *zcmd,
67				   size_t *pccol));
68static int ivwrite_taylor_port P((struct uuconf_port *qport,
69				  pointer pinfo));
70static int ivwrite_v2_port P((struct uuconf_port *qport, pointer pinfo));
71static int ivwrite_hdb_port P((struct uuconf_port *qport, pointer pinfo));
72static void uvwrite_taylor_port P((FILE *e, struct uuconf_port *qport,
73				   const char *zprefix));
74static void uvwrite_taylor_dialer P((FILE *e, struct uuconf_dialer *qdialer,
75				     const char *zprefix));
76static void uvwrite_hdb_dialer P((FILE *e, struct uuconf_dialer *qdialer));
77static void uvuuconf_error P((pointer puuconf, int iret));
78
79/* The program name.  */
80const char *zProgram;
81
82/* A list of Permissions entries built when writing out HDB system
83   information.  */
84static struct shpermissions *qVperms;
85
86/* Type of configuration file.  */
87enum tconfig
88{
89  CONFIG_TAYLOR,
90  CONFIG_V2,
91  CONFIG_HDB
92};
93
94/* Long getopt options.  */
95static const struct option asVlongopts[] =
96{
97  { "input", required_argument, NULL, 'i' },
98  { "output", required_argument, NULL, 'o' },
99  { "program", required_argument, NULL, 'p' },
100  { "config", required_argument, NULL, 'I' },
101  { "debug", required_argument, NULL, 'x' },
102  { "version", no_argument, NULL, 'v' },
103  { "help", no_argument, NULL, 1 },
104  { NULL, 0, NULL, 0 }
105};
106
107int
108main (argc, argv)
109     int argc;
110     char **argv;
111{
112  /* -I: The configuration file name.  */
113  const char *zconfig = NULL;
114  /* -i: Input type.  */
115  const char *zinput = NULL;
116  /* -o: Output type.  */
117  const char *zoutput = NULL;
118  /* -p: Program name.  */
119  const char *zprogram = NULL;
120  int iopt;
121  enum tconfig tinput, toutput;
122  int iret;
123  pointer pinput;
124
125  if (argc < 1)
126  {
127      zProgram = "uuconv";
128      uvusage ();
129  }
130
131  zProgram = argv[0];
132
133  while ((iopt = getopt_long (argc, argv, "i:I:o:p:vx:", asVlongopts,
134			      (int *) NULL)) != EOF)
135    {
136      switch (iopt)
137	{
138	case 'i':
139	  /* Input type.  */
140	  zinput = optarg;
141	  break;
142
143	case 'o':
144	  /* Output type.  */
145	  zoutput = optarg;
146	  break;
147
148	case 'p':
149	  /* Program name.  */
150	  zprogram = optarg;
151	  break;
152
153	case 'I':
154	  /* Set the configuration file name.  */
155	  zconfig = optarg;
156	  break;
157
158	case 'x':
159	  /* Set the debugging level.  */
160	  break;
161
162	case 'v':
163	  /* Print version and exit.  */
164	  printf ("uuconv (Taylor UUCP) %s\n", VERSION);
165	  printf ("Copyright (C) 1991, 92, 93, 94, 1995, 2002 Ian Lance Taylor\n");
166	  printf ("This program is free software; you may redistribute it under the terms of\n");
167	  printf ("the GNU General Public LIcense.  This program has ABSOLUTELY NO WARRANTY.\n");
168	  exit (EXIT_SUCCESS);
169	  /*NOTREACHED*/
170
171	case 1:
172	  /* --help.  */
173	  uvhelp ();
174	  exit (EXIT_SUCCESS);
175	  /*NOTREACHED*/
176
177	case 0:
178	  /* Long option found, and flag value set.  */
179	  break;
180
181	default:
182	  uvusage ();
183	  break;
184	}
185    }
186
187  if (optind != argc
188      || zinput == NULL
189      || zoutput == NULL)
190    uvusage ();
191
192  if (strcasecmp (zinput, "taylor") == 0)
193    tinput = CONFIG_TAYLOR;
194  else if (strcasecmp (zinput, "v2") == 0)
195    tinput = CONFIG_V2;
196  else if (strcasecmp (zinput, "hdb") == 0)
197    tinput = CONFIG_HDB;
198  else
199    {
200      uvusage ();
201      tinput = CONFIG_TAYLOR;
202    }
203
204  if (strcasecmp (zoutput, "taylor") == 0)
205    toutput = CONFIG_TAYLOR;
206  else if (strcasecmp (zoutput, "v2") == 0)
207    toutput = CONFIG_V2;
208  else if (strcasecmp (zoutput, "hdb") == 0)
209    toutput = CONFIG_HDB;
210  else
211    {
212      uvusage ();
213      toutput = CONFIG_TAYLOR;
214    }
215
216  if (tinput == toutput)
217    uvusage ();
218
219  iret = UUCONF_SUCCESS;
220
221  /* Initialize the input.  */
222  pinput = NULL;
223  switch (tinput)
224    {
225    case CONFIG_TAYLOR:
226      iret = uuconf_taylor_init (&pinput, zprogram, zconfig);
227      break;
228    case CONFIG_V2:
229      iret = uuconf_v2_init (&pinput);
230      break;
231    case CONFIG_HDB:
232      iret = uuconf_hdb_init (&pinput, zprogram);
233      break;
234    }
235  if (iret != UUCONF_SUCCESS)
236    {
237      uvuuconf_error (pinput, iret);
238      exit (EXIT_FAILURE);
239    }
240
241  {
242    char **pzsystems;
243    char *zsys;
244    char abtaylor[sizeof ZCURDIR + sizeof SYSFILE - 1];
245    char abv2[sizeof ZCURDIR + sizeof V2_SYSTEMS - 1];
246    char abhdb[sizeof ZCURDIR + sizeof HDB_SYSTEMS - 1];
247    FILE *esys;
248    char **pz;
249
250    /* Get the list of systems.  */
251    switch (tinput)
252      {
253      case CONFIG_TAYLOR:
254	iret = uuconf_taylor_system_names (pinput, &pzsystems, FALSE);
255	break;
256      case CONFIG_V2:
257	iret = uuconf_v2_system_names (pinput, &pzsystems, FALSE);
258	break;
259      case CONFIG_HDB:
260	iret = uuconf_hdb_system_names (pinput, &pzsystems, FALSE);
261	break;
262      }
263    if (iret != UUCONF_SUCCESS)
264      uvuuconf_error (pinput, iret);
265    else
266      {
267	/* Open the sys file for the output type.  */
268	switch (toutput)
269	  {
270	  default:
271	  case CONFIG_TAYLOR:
272	    sprintf (abtaylor, "%s%s", ZCURDIR, SYSFILE);
273	    zsys = abtaylor;
274	    break;
275	  case CONFIG_V2:
276	    sprintf (abv2, "%s%s", ZCURDIR, V2_SYSTEMS);
277	    zsys = abv2;
278	    break;
279	  case CONFIG_HDB:
280	    sprintf (abhdb, "%s%s", ZCURDIR, HDB_SYSTEMS);
281	    zsys = abhdb;
282	    break;
283	  }
284	esys = fopen (zsys, "w");
285	if (esys == NULL)
286	  {
287	    fprintf (stderr, "uuchk:%s: ", zsys);
288	    perror ("fopen");
289	    exit (EXIT_FAILURE);
290	  }
291
292	fprintf (esys, "# %s file automatically generated by uuconv.\n",
293		 zsys);
294
295	/* Read and write each system.  We cheat and call the internal
296	   routines, so that we can easily detect default information and
297	   not write it out.  This isn't necessary, but it makes the output
298	   smaller and simpler.  */
299	for (pz = pzsystems; *pz != NULL; pz++)
300	  {
301	    struct uuconf_system ssys;
302
303	    switch (tinput)
304	      {
305	      case CONFIG_TAYLOR:
306		iret = _uuconf_itaylor_system_internal (pinput, *pz, &ssys);
307		break;
308	      case CONFIG_V2:
309		iret = _uuconf_iv2_system_internal (pinput, *pz, &ssys);
310		break;
311	      case CONFIG_HDB:
312		iret = _uuconf_ihdb_system_internal (pinput, *pz, &ssys);
313		break;
314	      }
315	    if (iret != UUCONF_SUCCESS)
316	      uvuuconf_error (pinput, iret);
317	    else
318	      {
319		switch (toutput)
320		  {
321		  case CONFIG_TAYLOR:
322		    uvwrite_taylor_system (esys, &ssys);
323		    break;
324		  case CONFIG_V2:
325		    uvwrite_v2_system (esys, &ssys);
326		    break;
327		  case CONFIG_HDB:
328		    uvwrite_hdb_system (esys, &ssys);
329		    break;
330		  }
331		if (toutput != CONFIG_HDB)
332		  (void) uuconf_system_free (pinput, &ssys);
333	      }
334	  }
335
336	if (toutput == CONFIG_HDB)
337	  uvwrite_perms ();
338
339	if (ferror (esys)
340	    || fclose (esys) == EOF)
341	  {
342	    fprintf (stderr, "uuchk:%s: error during output\n", zsys);
343	    exit (EXIT_FAILURE);
344	  }
345      }
346  }
347
348  {
349    /* Open the port file for the output type.  */
350    char *zport;
351    char abtaylor[sizeof ZCURDIR + sizeof PORTFILE - 1];
352    char abv2[sizeof ZCURDIR + sizeof V2_DEVICES - 1];
353    char abhdb[sizeof ZCURDIR + sizeof HDB_DEVICES - 1];
354    FILE *eport;
355    int (*piportfn) P((struct uuconf_port *, pointer));
356    struct uuconf_port sport;
357
358    switch (toutput)
359      {
360      default:
361      case CONFIG_TAYLOR:
362	sprintf (abtaylor, "%s%s", ZCURDIR, PORTFILE);
363	zport = abtaylor;
364	piportfn = ivwrite_taylor_port;
365	break;
366      case CONFIG_V2:
367	sprintf (abv2, "%s%s", ZCURDIR, V2_DEVICES);
368	zport = abv2;
369	piportfn = ivwrite_v2_port;
370	break;
371      case CONFIG_HDB:
372	sprintf (abhdb, "%s%s", ZCURDIR, HDB_DEVICES);
373	zport = abhdb;
374	piportfn = ivwrite_hdb_port;
375	break;
376      }
377    eport = fopen (zport, "w");
378    if (eport == NULL)
379      {
380	fprintf (stderr, "uuchk:%s: ", zport);
381	perror ("fopen");
382	exit (EXIT_FAILURE);
383      }
384
385    fprintf (eport, "# %s file automatically generated by uuconv.\n", zport);
386
387    switch (tinput)
388      {
389      case CONFIG_TAYLOR:
390	iret = uuconf_taylor_find_port (pinput, (const char *) NULL, 0L,
391					0L, piportfn, (pointer) eport,
392					&sport);
393	break;
394      case CONFIG_V2:
395	iret = uuconf_v2_find_port (pinput, (const char *) NULL, 0L, 0L,
396				    piportfn, (pointer) eport, &sport);
397	break;
398      case CONFIG_HDB:
399	iret = uuconf_hdb_find_port (pinput, (const char *) NULL, 0L, 0L,
400				     piportfn, (pointer) eport, &sport);
401	break;
402      }
403
404    if (iret != UUCONF_NOT_FOUND)
405      uvuuconf_error (pinput, iret);
406
407    if (ferror (eport)
408	|| fclose (eport) == EOF)
409      {
410	fprintf (stderr, "uuchk:%s: error during output\n", zport);
411	exit (EXIT_FAILURE);
412      }
413  }
414
415  /* V2 configuration files don't support dialers.  */
416  if (tinput != CONFIG_V2 && toutput != CONFIG_V2)
417    {
418      char **pzdialers;
419      char *zdialer;
420      char abtaylor[sizeof ZCURDIR + sizeof DIALFILE - 1];
421      char abhdb[sizeof ZCURDIR + sizeof HDB_DIALERS - 1];
422      FILE *edialer;
423      char **pz;
424
425      /* Get the list of dialers.  */
426      switch (tinput)
427	{
428	default:
429	case CONFIG_TAYLOR:
430	  iret = uuconf_taylor_dialer_names (pinput, &pzdialers);
431	  break;
432	case CONFIG_HDB:
433	  iret = uuconf_hdb_dialer_names (pinput, &pzdialers);
434	  break;
435	}
436      if (iret != UUCONF_SUCCESS)
437	uvuuconf_error (pinput, iret);
438      else
439	{
440	  /* Open the sys file for the output type.  */
441	  switch (toutput)
442	    {
443	    default:
444	    case CONFIG_TAYLOR:
445	      sprintf (abtaylor, "%s%s", ZCURDIR, DIALFILE);
446	      zdialer = abtaylor;
447	      break;
448	    case CONFIG_HDB:
449	      sprintf (abhdb, "%s%s", ZCURDIR, HDB_DIALERS);
450	      zdialer = abhdb;
451	      break;
452	    }
453	  edialer = fopen (zdialer, "w");
454	  if (edialer == NULL)
455	    {
456	      fprintf (stderr, "uuchk:%s: ", zdialer);
457	      perror ("fopen");
458	      exit (EXIT_FAILURE);
459	    }
460
461	  fprintf (edialer, "# %s file automatically generated by uuconv.\n",
462		   zdialer);
463
464	  /* Read and write each dialer.  */
465	  for (pz = pzdialers; *pz != NULL; pz++)
466	    {
467	      struct uuconf_dialer sdialer;
468
469	      switch (tinput)
470		{
471		default:
472		case CONFIG_TAYLOR:
473		  iret = uuconf_taylor_dialer_info (pinput, *pz, &sdialer);
474		  break;
475		case CONFIG_HDB:
476		  iret = uuconf_hdb_dialer_info (pinput, *pz, &sdialer);
477		  break;
478		}
479	      if (iret != UUCONF_SUCCESS)
480		uvuuconf_error (pinput, iret);
481	      else
482		{
483		  switch (toutput)
484		    {
485		    default:
486		    case CONFIG_TAYLOR:
487		      fprintf (edialer, "# Start of dialer %s\n",
488			       sdialer.uuconf_zname);
489		      fprintf (edialer, "dialer %s\n", sdialer.uuconf_zname);
490		      uvwrite_taylor_dialer (edialer, &sdialer, "");
491		      break;
492		    case CONFIG_HDB:
493		      uvwrite_hdb_dialer (edialer, &sdialer);
494		      break;
495		    }
496		  (void) uuconf_dialer_free (pinput, &sdialer);
497		}
498	    }
499
500	  if (ferror (edialer)
501	      || fclose (edialer) == EOF)
502	    {
503	      fprintf (stderr, "uuchk:%s: error during output\n", zdialer);
504	      exit (EXIT_FAILURE);
505	    }
506	}
507    }
508
509  exit (EXIT_SUCCESS);
510
511  /* Avoid complaints about not returning.  */
512  return 0;
513}
514
515/* Print out a usage message and die.  */
516
517static void
518uvusage ()
519{
520  fprintf (stderr, "Usage: %s -i input-type -o output-type [-p program]\n",
521	   zProgram);
522  fprintf (stderr, "Use %s --help for help\n", zProgram);
523  exit (EXIT_FAILURE);
524}
525
526/* Print a help message.  */
527
528static void
529uvhelp ()
530{
531  printf ("Taylor UUCP %s, copyright (C) 1991, 92, 93, 94, 1995, 2002 Ian Lance Taylor\n",
532	  VERSION);
533  printf ("Converts UUCP configuration files from one format to another.\n");
534  printf ("Usage: %s -i input -o output [-p program] [-I file]\n", zProgram);
535  printf (" -i,--input input: Set input type (one of taylor, v2, hdb)\n");
536  printf (" -o,--output output: Set output type (one of taylor, v2, hdb)\n");
537  printf (" -p,--program program: Program to convert (e.g., uucp or cu)\n");
538  printf (" -I,--config file: Set Taylor UUCP configuration file to use\n");
539  printf (" -v,--version: Print version and exit\n");
540  printf (" --help: Print help and exit\n");
541  printf ("Report bugs to taylor-uucp@gnu.org\n");
542}
543
544/* Write out a timespan.  */
545
546static void
547uvwrite_time (e, qtime)
548     FILE *e;
549     struct uuconf_timespan *qtime;
550{
551  if (qtime == NULL)
552    {
553      fprintf (e, "Never");
554      return;
555    }
556
557  if (qtime->uuconf_istart == 0 && qtime->uuconf_iend == 7 * 24 * 60)
558    {
559      fprintf (e, "Any");
560      return;
561    }
562
563  for (; qtime != NULL; qtime = qtime->uuconf_qnext)
564    {
565      int idaystart, idayend;
566      int ihourstart, ihourend;
567      int iminutestart, iminuteend;
568      const char * const zdays = "Su\0Mo\0Tu\0We\0Th\0Fr\0Sa";
569
570      idaystart = qtime->uuconf_istart / (24 * 60);
571      ihourstart = (qtime->uuconf_istart % (24 * 60)) / 60;
572      iminutestart = qtime->uuconf_istart % 60;
573      if (qtime->uuconf_iend >= 7 * 24 * 60)
574	qtime->uuconf_iend = 7 * 24 * 60 - 1;
575      idayend = qtime->uuconf_iend / (24 * 60);
576      ihourend = (qtime->uuconf_iend % (24 * 60)) / 60;
577      iminuteend = qtime->uuconf_iend % 60;
578      if (ihourend == 0 && iminuteend == 0)
579	--idayend;
580
581      if (idaystart == idayend)
582	fprintf (e, "%s%02d%02d-%02d%02d", zdays + idaystart * 3,
583		 ihourstart, iminutestart, ihourend, iminuteend);
584      else
585	{
586	  int i;
587
588	  fprintf (e, "%s%02d%02d-0000", zdays + idaystart * 3,
589		   ihourstart, iminutestart);
590	  for (i = idaystart + 1; i < idayend; i++)
591	    fprintf (e, ",%s", zdays + i * 3);
592	  if (ihourend != 0 || iminuteend != 0)
593	    fprintf (e, ",%s0000-%02d%02d", zdays + idayend * 3, ihourend,
594		     iminuteend);
595	}
596
597      if (qtime->uuconf_qnext != NULL)
598	fprintf (e, ",");
599    }
600}
601
602/* Some subroutines used when writing out Taylor UUCP configuration
603   files.  */
604
605/* Write a command with a string argument.  */
606
607static void
608uvwrite_string (e, zarg, zcmd)
609     FILE *e;
610     const char *zarg;
611     const char *zcmd;
612{
613  if (zarg != (const char *) &_uuconf_unset)
614    fprintf (e, "%s %s\n", zcmd, zarg == NULL ? (const char *) "" : zarg);
615}
616
617/* Write out a size restriction command.  */
618
619static void
620uvwrite_size (e, qtime, zcmd)
621     FILE *e;
622     struct uuconf_timespan *qtime;
623     const char *zcmd;
624{
625  if (qtime != (struct uuconf_timespan *) &_uuconf_unset)
626    {
627      for (; qtime != NULL; qtime = qtime->uuconf_qnext)
628	{
629	  fprintf (e, "%s %ld", zcmd, qtime->uuconf_ival);
630	  uvwrite_time (e, qtime);
631	  fprintf (e, "\n");
632	}
633    }
634}
635
636/* Write out a boolean argument with a string command.  If the value
637   is less than zero, than it was uninitialized and we don't write
638   anything.  */
639
640static void
641uvwrite_boolean (e, fval, zcmd)
642     FILE *e;
643     int fval;
644     const char *zcmd;
645{
646  if (fval >= 0)
647    fprintf (e, "%s %s\n", zcmd, fval > 0 ? "true" : "false");
648}
649
650/* Write out a string array as a single command.  */
651
652static void
653uvwrite_string_array (e, pz, zcmd)
654     FILE *e;
655     char **pz;
656     const char *zcmd;
657{
658  if (pz != (char **) &_uuconf_unset)
659    {
660      fprintf (e, "%s", zcmd);
661      if (pz != NULL)
662	for (; *pz != NULL; pz++)
663	  fprintf (e, " %s", *pz);
664      fprintf (e, "\n");
665    }
666}
667
668/* Write out a chat script.  Don't separate subsend/subexpect strings
669   by spaces.  */
670
671static void
672uvwrite_chat_script (e, pzarg)
673     FILE *e;
674     char **pzarg;
675{
676  char **pz;
677
678  if (pzarg == NULL || pzarg == (char **) &_uuconf_unset)
679    return;
680
681  for (pz = pzarg; *pz != NULL; pz++)
682    {
683      if ((*pz)[0] != '-' && pz != pzarg)
684	fprintf (e, " ");
685      fprintf (e, *pz);
686    }
687}
688
689/* Write out chat information.  If the qlast argument is not NULL,
690   then only values that are different from qlast should be written.
691   The fforce argument is used to get around a peculiar problem: if
692   the ``chat'' command is used with no arguments for a system, then
693   uuconf_pzchat will be NULL (not &_uuconf_unset) and the default
694   chat script will not be used.  We must distinguish this case from
695   the ``chat'' command not appearing at all for a port or dialer, in
696   which case the value will again be NULL.  In the former case we
697   must output a ``chat'' command, in the latter case we would prefer
698   not to.  */
699
700static void
701uvwrite_chat (e, q, qlast, zprefix, fforce)
702     FILE *e;
703     const struct uuconf_chat *q;
704     const struct uuconf_chat *qlast;
705     const char *zprefix;
706     boolean fforce;
707{
708  char **pz;
709  char ab[100];
710
711  if (q->uuconf_pzchat != (char **) &_uuconf_unset
712      && (qlast == NULL
713	  ? (fforce || q->uuconf_pzchat != NULL)
714	  : qlast->uuconf_pzchat != q->uuconf_pzchat))
715    {
716      fprintf (e, "%schat ", zprefix);
717      uvwrite_chat_script (e, q->uuconf_pzchat);
718      fprintf (e, "\n");
719    }
720
721  if (q->uuconf_pzprogram != (char **) &_uuconf_unset
722      && (qlast == NULL
723	  ? q->uuconf_pzprogram != NULL
724	  : qlast->uuconf_pzprogram != q->uuconf_pzprogram))
725    {
726      sprintf (ab, "%schat-program", zprefix);
727      uvwrite_string_array (e, q->uuconf_pzprogram, ab);
728    }
729
730  if (q->uuconf_ctimeout >= 0
731      && (qlast == NULL
732	  || qlast->uuconf_ctimeout != q->uuconf_ctimeout))
733    fprintf (e, "%schat-timeout %d\n", zprefix, q->uuconf_ctimeout);
734
735  if (q->uuconf_pzfail != NULL
736      && q->uuconf_pzfail != (char **) &_uuconf_unset
737      && (qlast == NULL
738	  || qlast->uuconf_pzfail != q->uuconf_pzfail))
739    for (pz = q->uuconf_pzfail; *pz != NULL; pz++)
740      fprintf (e, "%schat-fail %s\n", zprefix, *pz);
741
742  if (qlast == NULL || qlast->uuconf_fstrip != q->uuconf_fstrip)
743    {
744      sprintf (ab, "%schat-strip", zprefix);
745      uvwrite_boolean (e, q->uuconf_fstrip, ab);
746    }
747}
748
749/* Write out protocol parameters to a Taylor UUCP file.  */
750
751static void
752uvwrite_proto_params (e, qparams, zprefix)
753     FILE *e;
754     const struct uuconf_proto_param *qparams;
755     const char *zprefix;
756{
757  const struct uuconf_proto_param *qp;
758
759  if (qparams == NULL
760      || qparams == (struct uuconf_proto_param *) &_uuconf_unset)
761    return;
762
763  for (qp = qparams; qp->uuconf_bproto != '\0'; qp++)
764    {
765      const struct uuconf_proto_param_entry *qe;
766
767      for (qe = qp->uuconf_qentries; qe->uuconf_cargs > 0; qe++)
768	{
769	  int i;
770
771	  fprintf (e, "%sprotocol-parameter %c", zprefix, qp->uuconf_bproto);
772	  for (i = 0; i < qe->uuconf_cargs; i++)
773	    fprintf (e, " %s", qe->uuconf_pzargs[i]);
774	  fprintf (e, "\n");
775	}
776    }
777}
778
779/* Write out Taylor UUCP system information.  */
780
781static void
782uvwrite_taylor_system (e, q)
783     FILE *e;
784     const struct uuconf_system *q;
785{
786  char **pz;
787  const struct uuconf_system *qlast;
788
789  fprintf (e, "# Start of system %s\n", q->uuconf_zname);
790
791  fprintf (e, "system %s\n", q->uuconf_zname);
792  if (q->uuconf_pzalias != NULL
793      && q->uuconf_pzalias != (char **) &_uuconf_unset)
794    for (pz = q->uuconf_pzalias; *pz != NULL; pz++)
795      uvwrite_string (e, *pz, "alias");
796
797  for (qlast = NULL; q != NULL; qlast = q, q = q->uuconf_qalternate)
798    {
799      struct uuconf_timespan *qtime;
800
801      if (qlast != NULL)
802	{
803	  fprintf (e, "alternate");
804	  if (q->uuconf_zalternate != (char *) &_uuconf_unset
805	      && q->uuconf_zalternate != NULL)
806	    fprintf (e, " %s", q->uuconf_zalternate);
807	  fprintf (e, "\n");
808	}
809
810#define CHANGED(x) (qlast == NULL || qlast->x != q->x)
811
812      if (CHANGED (uuconf_qtimegrade)
813	  && (q->uuconf_qtimegrade
814	      != (struct uuconf_timespan *) &_uuconf_unset))
815	{
816	  if (q->uuconf_qtimegrade == NULL)
817	    fprintf (e, "time never\n");
818	  else
819	    {
820	      for (qtime = q->uuconf_qtimegrade;
821		   qtime != NULL;
822		   qtime = qtime->uuconf_qnext)
823		{
824		  if ((char) qtime->uuconf_ival == UUCONF_GRADE_LOW)
825		    fprintf (e, "time ");
826		  else
827		    fprintf (e, "timegrade %c ", (char) qtime->uuconf_ival);
828		  uvwrite_time (e, qtime);
829		  if (qtime->uuconf_cretry != 0)
830		    fprintf (e, " %d", qtime->uuconf_cretry);
831		  fprintf (e, "\n");
832		}
833	    }
834	}
835
836      if (CHANGED (uuconf_qcalltimegrade)
837	  && (q->uuconf_qcalltimegrade
838	      != (struct uuconf_timespan *) &_uuconf_unset))
839	{
840	  for (qtime = q->uuconf_qcalltimegrade;
841	       qtime != NULL;
842	       qtime = qtime->uuconf_qnext)
843	    {
844	      fprintf (e, "call-timegrade %c ", (char) qtime->uuconf_ival);
845	      uvwrite_time (e, qtime);
846	      fprintf (e, "\n");
847	    }
848	}
849
850      if (CHANGED (uuconf_qcalledtimegrade)
851	  && (q->uuconf_qcalledtimegrade
852	      != (struct uuconf_timespan *) &_uuconf_unset))
853	{
854	  for (qtime = q->uuconf_qcalledtimegrade;
855	       qtime != NULL;
856	       qtime = qtime->uuconf_qnext)
857	    {
858	      fprintf (e, "called-timegrade %c ", (char) qtime->uuconf_ival);
859	      uvwrite_time (e, qtime);
860	      fprintf (e, "\n");
861	    }
862	}
863
864      if (CHANGED (uuconf_qcall_local_size))
865	uvwrite_size (e, q->uuconf_qcall_local_size, "call-local-size");
866
867      if (CHANGED (uuconf_qcall_remote_size))
868	uvwrite_size (e, q->uuconf_qcall_remote_size, "call-remote-size");
869
870      if (CHANGED (uuconf_qcalled_local_size))
871	uvwrite_size (e, q->uuconf_qcalled_local_size, "called-local-size");
872
873      if (CHANGED (uuconf_qcalled_remote_size))
874	uvwrite_size (e, q->uuconf_qcalled_remote_size, "called-remote-size");
875
876      if (CHANGED (uuconf_ibaud) || CHANGED (uuconf_ihighbaud))
877	{
878	  if (q->uuconf_ibaud >= 0)
879	    {
880	      if (q->uuconf_ihighbaud > 0)
881		fprintf (e, "baud-range %ld %ld\n", q->uuconf_ibaud,
882			 q->uuconf_ihighbaud);
883	      else
884		fprintf (e, "baud %ld\n", q->uuconf_ibaud);
885	    }
886	}
887
888      if (CHANGED (uuconf_zport) || CHANGED (uuconf_qport))
889	{
890	  if (q->uuconf_zport != NULL
891	      && q->uuconf_zport != (char *) &_uuconf_unset)
892	    uvwrite_string (e, q->uuconf_zport, "port");
893	  else if (q->uuconf_qport != NULL
894		   && (q->uuconf_qport
895		       != (struct uuconf_port *) &_uuconf_unset))
896	    uvwrite_taylor_port (e, q->uuconf_qport, "port ");
897	}
898
899      if (CHANGED (uuconf_zphone))
900	{
901	  const char *zcmd;
902
903	  if (q->uuconf_qport != NULL
904	      && q->uuconf_qport != (struct uuconf_port *) &_uuconf_unset
905	      && (q->uuconf_qport->uuconf_ttype == UUCONF_PORTTYPE_TCP
906		  || q->uuconf_qport->uuconf_ttype == UUCONF_PORTTYPE_TLI))
907	    zcmd = "address";
908	  else
909	    zcmd = "phone";
910	  uvwrite_string (e, q->uuconf_zphone, zcmd);
911	}
912
913      uvwrite_chat (e, &q->uuconf_schat,
914		    (qlast == NULL
915		     ? (struct uuconf_chat *) NULL
916		     : &qlast->uuconf_schat),
917		    "", TRUE);
918
919      if (CHANGED (uuconf_zcall_login))
920	uvwrite_string (e, q->uuconf_zcall_login, "call-login");
921
922      if (CHANGED (uuconf_zcall_password))
923	uvwrite_string (e, q->uuconf_zcall_password, "call-password");
924
925      if (CHANGED (uuconf_zcalled_login))
926	uvwrite_string (e, q->uuconf_zcalled_login, "called-login");
927
928      if (CHANGED (uuconf_fcallback))
929	uvwrite_boolean (e, q->uuconf_fcallback, "callback");
930
931      if (CHANGED (uuconf_fsequence))
932	uvwrite_boolean (e, q->uuconf_fsequence, "sequence");
933
934      if (CHANGED (uuconf_zprotocols))
935	uvwrite_string (e, q->uuconf_zprotocols, "protocol");
936
937      if (CHANGED (uuconf_qproto_params))
938	uvwrite_proto_params (e, q->uuconf_qproto_params, "");
939
940      uvwrite_chat (e, &q->uuconf_scalled_chat,
941		    (qlast == NULL
942		     ? (struct uuconf_chat *) NULL
943		     : &qlast->uuconf_scalled_chat),
944		    "called-", FALSE);
945
946      if (CHANGED (uuconf_zdebug))
947	uvwrite_string (e, q->uuconf_zdebug, "debug");
948
949      if (CHANGED (uuconf_zmax_remote_debug))
950	uvwrite_string (e, q->uuconf_zmax_remote_debug, "max-remote-debug");
951
952      if ((CHANGED (uuconf_fsend_request)
953	   || CHANGED (uuconf_frec_request))
954	  && (q->uuconf_fsend_request >= 0
955	      || q->uuconf_frec_request >= 0))
956	{
957	  if (q->uuconf_fsend_request >= 0
958	      && (q->uuconf_fsend_request > 0
959		  ? q->uuconf_frec_request > 0
960		  : q->uuconf_frec_request == 0))
961	    uvwrite_boolean (e, q->uuconf_fsend_request, "request");
962	  else
963	    {
964	      uvwrite_boolean (e, q->uuconf_fsend_request, "send-request");
965	      uvwrite_boolean (e, q->uuconf_frec_request,
966			       "receive-request");
967	    }
968	}
969
970      if ((CHANGED (uuconf_fcall_transfer)
971	   || CHANGED (uuconf_fcalled_transfer))
972	  && (q->uuconf_fcall_transfer >= 0
973	      || q->uuconf_fcalled_transfer >= 0))
974	{
975	  if (q->uuconf_fcall_transfer >= 0
976	      && (q->uuconf_fcall_transfer > 0
977		  ? q->uuconf_fcalled_transfer > 0
978		  : q->uuconf_fcalled_transfer == 0))
979	    uvwrite_boolean (e, q->uuconf_fcall_transfer, "transfer");
980	  else
981	    {
982	      uvwrite_boolean (e, q->uuconf_fcall_transfer, "call-transfer");
983	      uvwrite_boolean (e, q->uuconf_fcalled_transfer,
984			       "called-transfer");
985	    }
986	}
987
988      if (CHANGED (uuconf_pzlocal_send))
989	uvwrite_string_array (e, q->uuconf_pzlocal_send, "local-send");
990
991      if (CHANGED (uuconf_pzremote_send))
992	uvwrite_string_array (e, q->uuconf_pzremote_send, "remote-send");
993
994      if (CHANGED (uuconf_pzlocal_receive))
995	uvwrite_string_array (e, q->uuconf_pzlocal_receive, "local-receive");
996
997      if (CHANGED (uuconf_pzremote_receive))
998	uvwrite_string_array (e, q->uuconf_pzremote_receive,
999			      "remote-receive");
1000
1001      if (CHANGED (uuconf_pzpath))
1002	uvwrite_string_array (e, q->uuconf_pzpath, "command-path");
1003
1004      if (CHANGED (uuconf_pzcmds))
1005	uvwrite_string_array (e, q->uuconf_pzcmds, "commands");
1006
1007      if (CHANGED (uuconf_cfree_space)
1008	  && q->uuconf_cfree_space >= 0)
1009	fprintf (e, "free-space %ld\n", q->uuconf_cfree_space);
1010
1011      if (CHANGED (uuconf_pzforward_from))
1012	uvwrite_string_array (e, q->uuconf_pzforward_from, "forward-from");
1013
1014      if (CHANGED (uuconf_pzforward_to))
1015	uvwrite_string_array (e, q->uuconf_pzforward_to, "forward-to");
1016
1017      if (CHANGED (uuconf_zpubdir))
1018	uvwrite_string (e, q->uuconf_zpubdir, "pubdir");
1019
1020      if (CHANGED (uuconf_zlocalname))
1021	uvwrite_string (e, q->uuconf_zlocalname, "myname");
1022    }
1023}
1024
1025/* Write out V2 system information.  */
1026
1027static void
1028uvwrite_v2_system (e, q)
1029     FILE *e;
1030     const struct uuconf_system *q;
1031{
1032  for (; q != NULL; q = q->uuconf_qalternate)
1033    {
1034      fprintf (e, "%s", q->uuconf_zname);
1035
1036      if (q->uuconf_qtimegrade != (struct uuconf_timespan *) &_uuconf_unset)
1037	{
1038	  fprintf (e, " ");
1039	  uvwrite_time (e, q->uuconf_qtimegrade);
1040
1041	  if (q->uuconf_zport != (char *) &_uuconf_unset
1042	      || q->uuconf_qport != (struct uuconf_port *) &_uuconf_unset)
1043	    {
1044	      struct uuconf_port *qp;
1045	      boolean ftcp;
1046
1047	      qp = q->uuconf_qport;
1048	      ftcp = (qp != (struct uuconf_port *) &_uuconf_unset
1049		      && qp != NULL
1050		      && qp->uuconf_ttype == UUCONF_PORTTYPE_TCP);
1051	      if (ftcp
1052		  || (q->uuconf_zport != NULL
1053		      && q->uuconf_zport != (char *) &_uuconf_unset))
1054		{
1055		  if (ftcp)
1056		    fprintf (e, " TCP");
1057		  else
1058		    fprintf (e, " %s", q->uuconf_zport);
1059
1060		  if (ftcp || q->uuconf_ibaud >= 0)
1061		    {
1062		      fprintf (e, " ");
1063		      if (ftcp)
1064			{
1065			  const char *zport;
1066
1067			  zport = qp->uuconf_u.uuconf_stcp.uuconf_zport;
1068			  if (zport == NULL)
1069			    zport = "uucp";
1070			  fprintf (e, "%s", zport);
1071			}
1072		      else
1073			fprintf (e, "%ld", q->uuconf_ibaud);
1074
1075		      if (q->uuconf_zphone != (char *) &_uuconf_unset
1076			  && q->uuconf_zphone != NULL)
1077			{
1078			  char **pzc;
1079
1080			  fprintf (e, " %s", q->uuconf_zphone);
1081			  pzc = q->uuconf_schat.uuconf_pzchat;
1082			  if (pzc != (char **) &_uuconf_unset
1083			      && pzc != NULL)
1084			    {
1085			      fprintf (e, " ");
1086			      uvwrite_chat_script (e, pzc);
1087			    }
1088			}
1089		    }
1090		}
1091	    }
1092	}
1093
1094      fprintf (e, "\n");
1095
1096      /* Here we should gather information to write out to USERFILE
1097	 and L.cmds, and perhaps some day we will.  It's much more
1098	 likely to happen if somebody else does it, though.  */
1099    }
1100}
1101
1102/* Write out HDB system information.  */
1103
1104static void
1105uvwrite_hdb_system (e, qsys)
1106     FILE *e;
1107     const struct uuconf_system *qsys;
1108{
1109  const struct uuconf_system *q;
1110  struct shpermissions sperm;
1111  char *azmachine[2];
1112  char *azlogname[2];
1113
1114  for (q = qsys; q != NULL; q = q->uuconf_qalternate)
1115    {
1116      if (q->uuconf_fcall)
1117	{
1118	  fprintf (e, "%s", q->uuconf_zname);
1119
1120	  if (q->uuconf_qtimegrade
1121	      != (struct uuconf_timespan *) &_uuconf_unset)
1122	    {
1123	      const char *zport;
1124
1125	      fprintf (e, " ");
1126	      uvwrite_time (e, q->uuconf_qtimegrade);
1127
1128	      zport = q->uuconf_zport;
1129	      if (q->uuconf_qport != NULL
1130		  && q->uuconf_qport != (struct uuconf_port *) &_uuconf_unset
1131		  && q->uuconf_qport->uuconf_ttype == UUCONF_PORTTYPE_TCP)
1132		zport = "TCP";
1133	      if (zport != NULL && zport != (char *) &_uuconf_unset)
1134		{
1135		  fprintf (e, " %s", zport);
1136		  if (q->uuconf_zprotocols != (char *) &_uuconf_unset
1137		      && q->uuconf_zprotocols != NULL)
1138		    fprintf (e, ",%s", q->uuconf_zprotocols);
1139
1140		  if (q->uuconf_ibaud >= 0
1141		      || q->uuconf_zphone != (char *) &_uuconf_unset)
1142		    {
1143		      fprintf (e, " ");
1144		      if (q->uuconf_ibaud < 0)
1145			fprintf (e, "Any");
1146		      else
1147			{
1148			  fprintf (e, "%ld", q->uuconf_ibaud);
1149			  if (q->uuconf_ihighbaud >= 0)
1150			    fprintf (e, "-%ld", q->uuconf_ihighbaud);
1151			}
1152
1153		      if (q->uuconf_zphone != (char *) &_uuconf_unset
1154			  && q->uuconf_zphone != NULL)
1155			{
1156			  char **pzc;
1157
1158			  fprintf (e, " %s", q->uuconf_zphone);
1159			  pzc = q->uuconf_schat.uuconf_pzchat;
1160			  if (pzc != (char **) &_uuconf_unset
1161			      && pzc != NULL)
1162			    {
1163			      fprintf (e, " ");
1164			      uvwrite_chat_script (e, pzc);
1165			    }
1166			}
1167		    }
1168		}
1169	    }
1170
1171	  fprintf (e, "\n");
1172	}
1173    }
1174
1175  /* Build a Permissions entry for this system.  There will be only
1176     one MACHINE entry for a given system.  */
1177
1178  for (q = qsys; q != NULL; q = q->uuconf_qalternate)
1179    if (q->uuconf_fcall)
1180      break;
1181
1182  if (q != NULL)
1183    {
1184      sperm.qnext = NULL;
1185      sperm.pzlogname = NULL;
1186      sperm.pzmachine = NULL;
1187      sperm.frequest = -1;
1188      sperm.fsendfiles = -1;
1189      sperm.pzread = NULL;
1190      sperm.pzwrite = NULL;
1191      sperm.fcallback = -1;
1192      sperm.pzcommands = NULL;
1193      sperm.pzvalidate = NULL;
1194      sperm.zmyname = NULL;
1195      sperm.zpubdir = NULL;
1196      sperm.pzalias = NULL;
1197
1198      azmachine[0] = q->uuconf_zname;
1199      azmachine[1] = NULL;
1200      sperm.pzmachine = azmachine;
1201      if (q->uuconf_fsend_request >= 0)
1202	sperm.frequest = q->uuconf_fsend_request;
1203      if (q->uuconf_pzremote_send != (char **) &_uuconf_unset
1204	  && q->uuconf_pzremote_send != NULL)
1205	sperm.pzread = q->uuconf_pzremote_send;
1206      if (q->uuconf_pzremote_receive != (char **) &_uuconf_unset
1207	  && q->uuconf_pzremote_receive != NULL)
1208	sperm.pzwrite = q->uuconf_pzremote_receive;
1209      if (q->uuconf_pzcmds != (char **) &_uuconf_unset
1210	  && q->uuconf_pzcmds != NULL)
1211	sperm.pzcommands = q->uuconf_pzcmds;
1212      if (q->uuconf_zlocalname != (char *) &_uuconf_unset
1213	  && q->uuconf_zlocalname != NULL)
1214	sperm.zmyname = q->uuconf_zlocalname;
1215      if (q->uuconf_zpubdir != (char *) &_uuconf_unset
1216	  && q->uuconf_zpubdir != NULL)
1217	sperm.zpubdir = q->uuconf_zpubdir;
1218      if (q->uuconf_pzalias != (char **) &_uuconf_unset
1219	  && q->uuconf_pzalias != NULL)
1220	sperm.pzalias = q->uuconf_pzalias;
1221
1222      if (q->uuconf_fcalled
1223	  && q->uuconf_zcalled_login != (char *) &_uuconf_unset
1224	  && q->uuconf_zcalled_login != NULL)
1225	{
1226	  azlogname[0] = q->uuconf_zcalled_login;
1227	  azlogname[1] = NULL;
1228	  sperm.pzlogname = azlogname;
1229	  if (q->uuconf_fcalled_transfer >= 0)
1230	    sperm.fsendfiles = q->uuconf_fcalled_transfer;
1231	  if (q->uuconf_fcallback >= 0)
1232	    sperm.fcallback = q->uuconf_fcallback;
1233	  sperm.pzvalidate = azmachine;
1234	}
1235
1236      uvadd_perm (&sperm);
1237    }
1238
1239  /* Now add a Permissions entry for each alternative that is not used
1240     for calling out.  */
1241  for (q = qsys; q != NULL; q = q->uuconf_qalternate)
1242    {
1243      if (! q->uuconf_fcalled || q->uuconf_fcall)
1244	continue;
1245
1246      sperm.qnext = NULL;
1247      sperm.pzlogname = NULL;
1248      sperm.pzmachine = NULL;
1249      sperm.frequest = -1;
1250      sperm.fsendfiles = -1;
1251      sperm.pzread = NULL;
1252      sperm.pzwrite = NULL;
1253      sperm.fcallback = -1;
1254      sperm.pzcommands = NULL;
1255      sperm.pzvalidate = NULL;
1256      sperm.zmyname = NULL;
1257      sperm.zpubdir = NULL;
1258      sperm.pzalias = NULL;
1259
1260      if (q->uuconf_zcalled_login != (char *) &_uuconf_unset
1261	  && q->uuconf_zcalled_login != NULL)
1262	azlogname[0] = q->uuconf_zcalled_login;
1263      else
1264	azlogname[0] = (char *) "OTHER";
1265      azlogname[1] = NULL;
1266      sperm.pzlogname = azlogname;
1267
1268      if (q->uuconf_fsend_request >= 0)
1269	sperm.frequest = q->uuconf_fsend_request;
1270      if (q->uuconf_fcalled_transfer >= 0)
1271	sperm.fsendfiles = q->uuconf_fcalled_transfer;
1272      if (q->uuconf_pzremote_send != (char **) &_uuconf_unset
1273	  && q->uuconf_pzremote_send != NULL)
1274	sperm.pzread = q->uuconf_pzremote_send;
1275      if (q->uuconf_pzremote_receive != (char **) &_uuconf_unset
1276	  && q->uuconf_pzremote_receive != NULL)
1277	sperm.pzwrite = q->uuconf_pzremote_receive;
1278      if (q->uuconf_fcallback >= 0)
1279	sperm.fcallback = q->uuconf_fcallback;
1280      if (q->uuconf_zlocalname != (char *) &_uuconf_unset
1281	  && q->uuconf_zlocalname != NULL)
1282	sperm.zmyname = q->uuconf_zlocalname;
1283      if (q->uuconf_zpubdir != (char *) &_uuconf_unset
1284	  && q->uuconf_zpubdir != NULL)
1285	sperm.zpubdir = q->uuconf_zpubdir;
1286
1287      uvadd_perm (&sperm);
1288    }
1289}
1290
1291/* Compare two strings from a Permissions entry, returning TRUE if
1292   they are the same.  */
1293
1294static boolean
1295fvperm_string_cmp (z1, z2)
1296     const char *z1;
1297     const char *z2;
1298{
1299  if (z1 == NULL)
1300    return z2 == NULL;
1301
1302  if (z2 == NULL)
1303    return FALSE;
1304
1305  return strcmp (z1, z2) == 0;
1306}
1307
1308/* Compare two arrays of strings from a Permissions entry, returning
1309   TRUE if they are the same.  */
1310
1311static boolean
1312fvperm_array_cmp (pz1, pz2)
1313     const char **pz1;
1314     const char **pz2;
1315{
1316  if (pz1 == NULL)
1317    return pz2 == NULL;
1318
1319  if (pz2 == NULL)
1320    return FALSE;
1321
1322  for (; *pz1 != NULL && *pz2 != NULL; pz1++, pz2++)
1323    if (strcmp (*pz1, *pz2) != 0)
1324      break;
1325
1326  return *pz1 == NULL && *pz2 == NULL;
1327}
1328
1329/* Add a Permissions entry to a global list, combining entries where
1330   possible.  */
1331
1332static void
1333uvadd_perm (qadd)
1334     struct shpermissions *qadd;
1335{
1336  struct shpermissions *qlook;
1337  struct shpermissions *qnew;
1338  int iret;
1339
1340  /* If there's no information, don't bother to add this entry.  */
1341  if (qadd->pzlogname == NULL
1342      && qadd->frequest < 0
1343      && qadd->fsendfiles < 0
1344      && qadd->pzread == NULL
1345      && qadd->pzwrite == NULL
1346      && qadd->fcallback < 0
1347      && qadd->pzcommands == NULL
1348      && qadd->pzvalidate == NULL
1349      && qadd->zmyname == NULL
1350      && qadd->zpubdir == NULL
1351      && qadd->pzalias == NULL)
1352    return;
1353
1354  for (qlook = qVperms; qlook != NULL; qlook = qlook->qnext)
1355    {
1356      /* See if we can merge qadd into qlook.  */
1357      if (qadd->pzlogname == NULL
1358	  ? qlook->pzlogname != NULL
1359	  : qlook->pzlogname == NULL)
1360	continue;
1361      if (qadd->pzmachine == NULL
1362	  ? qlook->pzmachine != NULL
1363	  : qlook->pzmachine == NULL)
1364	continue;
1365      if (qadd->frequest != qlook->frequest
1366	  || qadd->fsendfiles != qlook->fsendfiles
1367	  || qadd->fcallback != qlook->fcallback)
1368	continue;
1369      if (! fvperm_string_cmp (qadd->zmyname, qlook->zmyname)
1370	  || ! fvperm_string_cmp (qadd->zpubdir, qlook->zpubdir))
1371	continue;
1372      if (! fvperm_array_cmp ((const char **) qadd->pzread,
1373			      (const char **) qlook->pzread)
1374	  || ! fvperm_array_cmp ((const char **)  qadd->pzwrite,
1375				 (const char **) qlook->pzwrite)
1376	  || ! fvperm_array_cmp ((const char **) qadd->pzcommands,
1377				 (const char **) qlook->pzcommands))
1378	continue;
1379
1380      /* Merge qadd into qlook.  */
1381      if (qadd->pzmachine != NULL)
1382	{
1383	  iret = _uuconf_iadd_string ((struct sglobal *) NULL,
1384				      qadd->pzmachine[0], FALSE,
1385				      TRUE, &qlook->pzmachine,
1386				      (pointer) NULL);
1387	  if (iret != UUCONF_SUCCESS)
1388	    uvuuconf_error ((pointer) NULL, iret);
1389	}
1390      if (qadd->pzlogname != NULL)
1391	{
1392	  iret = _uuconf_iadd_string ((struct sglobal *) NULL,
1393				      qadd->pzlogname[0], FALSE,
1394				      TRUE, &qlook->pzlogname,
1395				      (pointer) NULL);
1396	  if (iret != UUCONF_SUCCESS)
1397	    uvuuconf_error ((pointer) NULL, iret);
1398	}
1399      if (qadd->pzalias != NULL)
1400	{
1401	  char **pz;
1402
1403	  for (pz = qadd->pzalias; *pz != NULL; pz++)
1404	    {
1405	      iret = _uuconf_iadd_string ((struct sglobal *) NULL,
1406					  *pz, FALSE, TRUE,
1407					  &qlook->pzalias, (pointer) NULL);
1408	      if (iret != UUCONF_SUCCESS)
1409		uvuuconf_error ((pointer) NULL, iret);
1410	    }
1411	}
1412
1413      return;
1414    }
1415
1416  /* We must add qadd as a new entry on the list, which means we must
1417     copy it into the heap.  */
1418
1419  qnew = (struct shpermissions *) malloc (sizeof (struct shpermissions));
1420  if (qnew == NULL)
1421    uvuuconf_error ((pointer) NULL, UUCONF_MALLOC_FAILED);
1422  *qnew = *qadd;
1423  if (qadd->pzmachine != NULL)
1424    {
1425      qnew->pzmachine = NULL;
1426      iret = _uuconf_iadd_string ((struct sglobal *) NULL,
1427				  qadd->pzmachine[0], FALSE,
1428				  FALSE, &qnew->pzmachine,
1429				  (pointer) NULL);
1430      if (iret != UUCONF_SUCCESS)
1431	uvuuconf_error ((pointer) NULL, iret);
1432    }
1433  if (qadd->pzlogname != NULL)
1434    {
1435      qnew->pzlogname = NULL;
1436      iret = _uuconf_iadd_string ((struct sglobal *) NULL,
1437				  qadd->pzlogname[0], FALSE,
1438				  FALSE, &qnew->pzlogname,
1439				  (pointer) NULL);
1440      if (iret != UUCONF_SUCCESS)
1441	uvuuconf_error ((pointer) NULL, iret);
1442    }
1443  if (qadd->pzvalidate != NULL)
1444    qnew->pzvalidate = qnew->pzmachine;
1445
1446  qnew->qnext = qVperms;
1447  qVperms = qnew;
1448}
1449
1450/* Write out the Permissions entries.  */
1451
1452static void
1453uvwrite_perms ()
1454{
1455  char ab[sizeof ZCURDIR + sizeof HDB_PERMISSIONS - 1];
1456  FILE *e;
1457  struct shpermissions *q;
1458
1459  sprintf (ab, "%s%s", ZCURDIR, HDB_PERMISSIONS);
1460  e = fopen (ab, "w");
1461  if (e == NULL)
1462    {
1463      fprintf (stderr, "uuchk:%s: ", ab);
1464      perror ("fopen");
1465      exit (EXIT_FAILURE);
1466    }
1467
1468  fprintf (e, "# Permissions file automatically generated by uuconv.\n");
1469
1470  for (q = qVperms; q != NULL; q = q->qnext)
1471    {
1472      size_t ccol;
1473
1474      ccol = 0;
1475      uvwrite_perm_array (e, (const char **) q->pzlogname, "LOGNAME", &ccol);
1476      uvwrite_perm_array (e, (const char **) q->pzmachine, "MACHINE", &ccol);
1477      uvwrite_perm_boolean (e, q->frequest, "REQUEST", &ccol, FALSE);
1478      uvwrite_perm_boolean (e, q->fsendfiles, "SENDFILES", &ccol, TRUE);
1479      uvwrite_perm_rw_array (e, (const char **) q->pzread, "READ", &ccol);
1480      uvwrite_perm_rw_array (e, (const char **) q->pzwrite, "WRITE", &ccol);
1481      uvwrite_perm_boolean (e, q->fcallback, "CALLBACK", &ccol, FALSE);
1482      uvwrite_perm_array (e, (const char **) q->pzcommands, "COMMANDS",
1483			  &ccol);
1484      uvwrite_perm_array (e, (const char **) q->pzvalidate, "VALIDATE",
1485			  &ccol);
1486      uvwrite_perm_string (e, q->zmyname, "MYNAME", &ccol);
1487      uvwrite_perm_string (e, q->zpubdir, "PUBDIR", &ccol);
1488      uvwrite_perm_array (e, (const char **) q->pzalias, "ALIAS", &ccol);
1489
1490      fprintf (e, "\n");
1491    }
1492
1493  if (ferror (e)
1494      || fclose (e) == EOF)
1495    {
1496      fprintf (stderr, "uuchk:%s: error during output\n", HDB_PERMISSIONS);
1497      exit (EXIT_FAILURE);
1498    }
1499}
1500
1501/* Write an array out to the Permissions file.  */
1502
1503static void
1504uvwrite_perm_array (e, pzarg, zcmd, pccol)
1505     FILE *e;
1506     const char **pzarg;
1507     const char *zcmd;
1508     size_t *pccol;
1509{
1510  size_t c;
1511  const char **pz;
1512
1513  if (pzarg == NULL)
1514    return;
1515
1516  c = strlen (zcmd) + 1;
1517
1518  for (pz = pzarg; *pz != NULL; pz++)
1519    c += strlen (*pz) + 1;
1520
1521  if (*pccol > 20 && c + *pccol > 75)
1522    {
1523      fprintf (e, " \\\n");
1524      *pccol = c - 1;
1525    }
1526  else
1527    {
1528      if (*pccol != 0)
1529	fprintf (e, " ");
1530      *pccol += c;
1531    }
1532
1533  fprintf (e, "%s=", zcmd);
1534  for (pz = pzarg; *pz != NULL; pz++)
1535    {
1536      if (pz != pzarg)
1537	fprintf (e, ":");
1538      fprintf (e, "%s", *pz);
1539    }
1540}
1541
1542/* Write a boolean value out to the Permissions file.  This may be
1543   either a yes/no boolean or a yes/call boolean (the latter is for
1544   SENDFILES).  */
1545
1546static void
1547uvwrite_perm_boolean (e, f, zcmd, pccol, fsendfiles)
1548     FILE *e;
1549     int f;
1550     const char *zcmd;
1551     size_t *pccol;
1552     boolean fsendfiles;
1553{
1554  const char *az[2];
1555
1556  if (f < 0)
1557    return;
1558
1559  if (f)
1560    az[0] = "yes";
1561  else
1562    az[0] = fsendfiles ? "call" : "no";
1563  az[1] = NULL;
1564
1565  uvwrite_perm_array (e, az, zcmd, pccol);
1566}
1567
1568/* Write a set of READ or WRITE entries to the Permissions file.  We
1569   have to separate out all entries that start with '!'.  */
1570
1571static void
1572uvwrite_perm_rw_array (e, pzarg, zcmd, pccol)
1573     FILE *e;
1574     const char **pzarg;
1575     const char *zcmd;
1576     size_t *pccol;
1577{
1578  size_t c;
1579  const char **pz, **pzcopy, **pzset;
1580
1581  if (pzarg == NULL)
1582    return;
1583
1584  c = 0;
1585  for (pz = pzarg; *pz != NULL; pz++)
1586    c++;
1587
1588  pzcopy = (const char **) malloc ((c + 1) * sizeof (char *));
1589  if (pzcopy == NULL)
1590    uvuuconf_error ((pointer) NULL, UUCONF_MALLOC_FAILED);
1591
1592  pzset = pzcopy;
1593  for (pz = pzarg; *pz != NULL; pz++)
1594    if ((*pz)[0] != '!')
1595      *pzset++ = *pz;
1596  *pzset = NULL;
1597
1598  if (pzset != pzcopy)
1599    uvwrite_perm_array (e, (const char **) pzcopy, zcmd, pccol);
1600
1601  pzset = pzcopy;
1602  for (pz = pzarg; *pz != NULL; pz++)
1603    if ((*pz)[0] == '!')
1604      *pzset++ = *pz;
1605  *pzset = NULL;
1606
1607  if (pzset != pzcopy)
1608    {
1609      char ab[20];
1610
1611      sprintf (ab, "NO%s", zcmd);
1612      uvwrite_perm_array (e, (const char **) pzcopy, ab, pccol);
1613    }
1614}
1615
1616/* Write a string out to the Permissions file.  */
1617
1618static void
1619uvwrite_perm_string (e, z, zcmd, pccol)
1620     FILE *e;
1621     const char *z;
1622     const char *zcmd;
1623     size_t *pccol;
1624{
1625  const char *az[2];
1626
1627  if (z == NULL)
1628    return;
1629
1630  az[0] = z;
1631  az[1] = NULL;
1632
1633  uvwrite_perm_array (e, az, zcmd, pccol);
1634}
1635
1636/* Write out a Taylor UUCP port.  This is called via uuconf_find_port;
1637   the pinfo argument is the port file.  */
1638
1639static int
1640ivwrite_taylor_port (qport, pinfo)
1641     struct uuconf_port *qport;
1642     pointer pinfo;
1643{
1644  FILE *e = (FILE *) pinfo;
1645
1646  fprintf (e, "port %s\n", qport->uuconf_zname);
1647
1648  uvwrite_taylor_port (e, qport, "");
1649
1650  /* Return UUCONF_NOT_FOUND to force uuconf_find_port to keep looking
1651     for ports.  */
1652  return UUCONF_NOT_FOUND;
1653}
1654
1655/* Write a port out to a Taylor UUCP configuration file.  This doesn't
1656   output the name, since it is called to output a specially defined
1657   port in the sys file.  */
1658
1659static void
1660uvwrite_taylor_port (e, qport, zprefix)
1661     FILE *e;
1662     struct uuconf_port *qport;
1663     const char *zprefix;
1664{
1665  const char *ztype;
1666  char ab[100];
1667
1668  switch (qport->uuconf_ttype)
1669    {
1670    default:
1671    case UUCONF_PORTTYPE_UNKNOWN:
1672      fprintf (stderr, "uuconv: Bad port type\n");
1673      exit (EXIT_FAILURE);
1674      break;
1675    case UUCONF_PORTTYPE_STDIN:
1676      ztype = "stdin";
1677      break;
1678    case UUCONF_PORTTYPE_MODEM:
1679      ztype = "modem";
1680      break;
1681    case UUCONF_PORTTYPE_DIRECT:
1682      ztype = "direct";
1683      break;
1684    case UUCONF_PORTTYPE_TCP:
1685      ztype = "tcp";
1686      break;
1687    case UUCONF_PORTTYPE_TLI:
1688      ztype = "tli";
1689      break;
1690    case UUCONF_PORTTYPE_PIPE:
1691      ztype = "pipe";
1692      break;
1693    }
1694
1695  fprintf (e, "%stype %s\n", zprefix, ztype);
1696
1697  if (qport->uuconf_zprotocols != NULL)
1698    fprintf (e, "%sprotocol %s\n", zprefix, qport->uuconf_zprotocols);
1699
1700  if (qport->uuconf_qproto_params != NULL)
1701    uvwrite_proto_params (e, qport->uuconf_qproto_params, zprefix);
1702
1703  if ((qport->uuconf_ireliable & UUCONF_RELIABLE_SPECIFIED) != 0)
1704    {
1705      sprintf (ab, "%sseven-bit", zprefix);
1706      uvwrite_boolean (e,
1707		       ((qport->uuconf_ireliable & UUCONF_RELIABLE_EIGHT)
1708			== 0),
1709		       ab);
1710      sprintf (ab, "%sreliable", zprefix);
1711      uvwrite_boolean (e,
1712		       ((qport->uuconf_ireliable & UUCONF_RELIABLE_RELIABLE)
1713			!= 0),
1714		       ab);
1715      sprintf (ab, "%shalf-duplex", zprefix);
1716      uvwrite_boolean (e,
1717		       ((qport->uuconf_ireliable & UUCONF_RELIABLE_FULLDUPLEX)
1718			== 0),
1719		       ab);
1720    }
1721
1722  if (qport->uuconf_zlockname != NULL)
1723    fprintf (e, "%slockname %s\n", zprefix, qport->uuconf_zlockname);
1724
1725  switch (qport->uuconf_ttype)
1726    {
1727    default:
1728      break;
1729    case UUCONF_PORTTYPE_MODEM:
1730      {
1731	struct uuconf_modem_port *qm;
1732
1733	qm = &qport->uuconf_u.uuconf_smodem;
1734	if (qm->uuconf_zdevice != NULL)
1735	  fprintf (e, "%sdevice %s\n", zprefix, qm->uuconf_zdevice);
1736	if (qm->uuconf_zdial_device != NULL)
1737	  fprintf (e, "%sdial-device %s\n", zprefix, qm->uuconf_zdial_device);
1738	if (qm->uuconf_ibaud != 0)
1739	  fprintf (e, "%sbaud %ld\n", zprefix, qm->uuconf_ibaud);
1740	if (qm->uuconf_ilowbaud != 0)
1741	  fprintf (e, "%sbaud-range %ld %ld\n", zprefix, qm->uuconf_ilowbaud,
1742		   qm->uuconf_ihighbaud);
1743	if (! qm->uuconf_fcarrier)
1744	  fprintf (e, "%scarrier false\n", zprefix);
1745	if (! qm->uuconf_fhardflow)
1746	  fprintf (e, "%shardflow false\n", zprefix);
1747	if (qm->uuconf_pzdialer != NULL)
1748	  {
1749	    if (qm->uuconf_pzdialer[1] == NULL)
1750	      fprintf (e, "%sdialer %s\n", zprefix, qm->uuconf_pzdialer[0]);
1751	    else
1752	      {
1753		sprintf (ab, "%sdialer-sequence", zprefix);
1754		uvwrite_string_array (e, qm->uuconf_pzdialer, ab);
1755	      }
1756	  }
1757	if (qm->uuconf_qdialer != NULL)
1758	  {
1759	    sprintf (ab, "%sdialer ", zprefix);
1760	    uvwrite_taylor_dialer (e, qm->uuconf_qdialer, ab);
1761	  }
1762      }
1763      break;
1764    case UUCONF_PORTTYPE_DIRECT:
1765      {
1766	struct uuconf_direct_port *qd;
1767
1768	qd = &qport->uuconf_u.uuconf_sdirect;
1769	if (qd->uuconf_zdevice != NULL)
1770	  fprintf (e, "%sdevice %s\n", zprefix, qd->uuconf_zdevice);
1771	if (qd->uuconf_ibaud != 0)
1772	  fprintf (e, "%sbaud %ld\n", zprefix, qd->uuconf_ibaud);
1773	if (qd->uuconf_fcarrier)
1774	  fprintf (e, "%scarrier true\n", zprefix);
1775	if (! qd->uuconf_fhardflow)
1776	  fprintf (e, "%shardflow false\n", zprefix);
1777      }
1778      break;
1779    case UUCONF_PORTTYPE_TCP:
1780      if (qport->uuconf_u.uuconf_stcp.uuconf_zport != NULL)
1781	fprintf (e, "%sservice %s\n", zprefix,
1782		 qport->uuconf_u.uuconf_stcp.uuconf_zport);
1783      if (qport->uuconf_u.uuconf_stcp.uuconf_pzdialer != NULL)
1784	{
1785	  sprintf (ab, "%sdialer-sequence", zprefix);
1786	  uvwrite_string_array (e,
1787				qport->uuconf_u.uuconf_stcp.uuconf_pzdialer,
1788				ab);
1789	}
1790      break;
1791    case UUCONF_PORTTYPE_TLI:
1792      {
1793	struct uuconf_tli_port *qt;
1794
1795	qt = &qport->uuconf_u.uuconf_stli;
1796	if (qt->uuconf_zdevice != NULL)
1797	  fprintf (e, "%sdevice %s\n", zprefix, qt->uuconf_zdevice);
1798	sprintf (ab, "%sstream", zprefix);
1799	uvwrite_boolean (e, qt->uuconf_fstream, ab);
1800	if (qt->uuconf_pzpush != NULL)
1801	  {
1802	    sprintf (ab, "%spush", zprefix);
1803	    uvwrite_string_array (e, qt->uuconf_pzpush, ab);
1804	  }
1805	if (qt->uuconf_pzdialer != NULL)
1806	  {
1807	    sprintf (ab, "%sdialer-sequence", zprefix);
1808	    uvwrite_string_array (e, qt->uuconf_pzdialer, ab);
1809	  }
1810	if (qt->uuconf_zservaddr != NULL)
1811	  fprintf (e, "%sserver-address %s\n", zprefix,
1812		   qt->uuconf_zservaddr);
1813      }
1814      break;
1815    case UUCONF_PORTTYPE_PIPE:
1816      {
1817	struct uuconf_pipe_port *qp;
1818
1819	qp = &qport->uuconf_u.uuconf_spipe;
1820	if (qp->uuconf_pzcmd != NULL)
1821	  {
1822	    sprintf (ab, "%scommad", zprefix);
1823	    uvwrite_string_array (e, qp->uuconf_pzcmd, ab);
1824	  }
1825      }
1826      break;
1827    }
1828}
1829
1830/* Write out a port to the V2 L-devices file.  This is called via
1831   uuconf_find_port.  */
1832
1833static int
1834ivwrite_v2_port (qport, pinfo)
1835     struct uuconf_port *qport;
1836     pointer pinfo;
1837{
1838  FILE *e = (FILE *) pinfo;
1839
1840  if (qport->uuconf_ttype == UUCONF_PORTTYPE_DIRECT)
1841    {
1842      fprintf (e, "DIR %s - %ld direct",
1843	       qport->uuconf_u.uuconf_sdirect.uuconf_zdevice,
1844	       qport->uuconf_u.uuconf_sdirect.uuconf_ibaud);
1845    }
1846  else if (qport->uuconf_ttype == UUCONF_PORTTYPE_MODEM)
1847    {
1848      fprintf (e, "%s %s ", qport->uuconf_zname,
1849	       qport->uuconf_u.uuconf_smodem.uuconf_zdevice);
1850      if (qport->uuconf_u.uuconf_smodem.uuconf_zdial_device != NULL)
1851	fprintf (e, "%s", qport->uuconf_u.uuconf_smodem.uuconf_zdial_device);
1852      else
1853	fprintf (e, "-");
1854      fprintf (e, " ");
1855      if (qport->uuconf_u.uuconf_smodem.uuconf_ilowbaud != 0L)
1856	fprintf (e, "%ld-%ld",
1857		 qport->uuconf_u.uuconf_smodem.uuconf_ilowbaud,
1858		 qport->uuconf_u.uuconf_smodem.uuconf_ihighbaud);
1859      else if (qport->uuconf_u.uuconf_smodem.uuconf_ibaud != 0L)
1860	fprintf (e, "%ld", qport->uuconf_u.uuconf_smodem.uuconf_ibaud);
1861      else
1862	fprintf (e, "Any");
1863      if (qport->uuconf_u.uuconf_smodem.uuconf_pzdialer != NULL)
1864	fprintf (e, " %s",
1865		 qport->uuconf_u.uuconf_smodem.uuconf_pzdialer[0]);
1866    }
1867  else
1868    {
1869      fprintf (e, "# Ignoring port %s with unsupported type",
1870	       qport->uuconf_zname);
1871    }
1872
1873  fprintf (e, "\n");
1874
1875  /* Return UUCONF_NOT_FOUND to force uuconf_find_port to keep looking
1876     for a port.  */
1877  return UUCONF_NOT_FOUND;
1878}
1879
1880/* Write out a port to the HDB Devices file.  This is called via
1881   uuconf_find_port.  */
1882
1883static int
1884ivwrite_hdb_port (qport, pinfo)
1885     struct uuconf_port *qport;
1886     pointer pinfo;
1887{
1888  FILE *e = (FILE *) pinfo;
1889
1890  if (qport->uuconf_ttype == UUCONF_PORTTYPE_DIRECT)
1891    {
1892      fprintf (e, "Direct");
1893      if (qport->uuconf_zprotocols != NULL)
1894	fprintf (e, ",%s", qport->uuconf_zprotocols);
1895      fprintf (e, " ");
1896      if (qport->uuconf_u.uuconf_sdirect.uuconf_zdevice != NULL)
1897	fprintf (e, "%s", qport->uuconf_u.uuconf_sdirect.uuconf_zdevice);
1898      else
1899	fprintf (e, "%s", qport->uuconf_zname);
1900      fprintf (e, " - %ld", qport->uuconf_u.uuconf_sdirect.uuconf_ibaud);
1901    }
1902  else if (qport->uuconf_ttype == UUCONF_PORTTYPE_MODEM)
1903    {
1904      fprintf (e, "%s", qport->uuconf_zname);
1905      if (qport->uuconf_zprotocols != NULL)
1906	fprintf (e, ",%s", qport->uuconf_zprotocols);
1907      fprintf (e, " ");
1908      if (qport->uuconf_u.uuconf_smodem.uuconf_zdevice != NULL)
1909	fprintf (e, "%s", qport->uuconf_u.uuconf_smodem.uuconf_zdevice);
1910      else
1911	fprintf (e, "%s", qport->uuconf_zname);
1912      fprintf (e, " ");
1913      if (qport->uuconf_u.uuconf_smodem.uuconf_zdial_device != NULL)
1914	fprintf (e, "%s", qport->uuconf_u.uuconf_smodem.uuconf_zdial_device);
1915      else
1916	fprintf (e, "-");
1917      fprintf (e, " ");
1918      if (qport->uuconf_u.uuconf_smodem.uuconf_ilowbaud != 0L)
1919	fprintf (e, "%ld-%ld",
1920		 qport->uuconf_u.uuconf_smodem.uuconf_ilowbaud,
1921		 qport->uuconf_u.uuconf_smodem.uuconf_ihighbaud);
1922      else if (qport->uuconf_u.uuconf_smodem.uuconf_ibaud != 0L)
1923	fprintf (e, "%ld", qport->uuconf_u.uuconf_smodem.uuconf_ibaud);
1924      else
1925	fprintf (e, "Any");
1926      if (qport->uuconf_u.uuconf_smodem.uuconf_pzdialer != NULL)
1927	{
1928	  char **pz;
1929
1930	  for (pz = qport->uuconf_u.uuconf_smodem.uuconf_pzdialer;
1931	       *pz != NULL;
1932	       pz++)
1933	    fprintf (e, " %s", *pz);
1934	}
1935    }
1936  else if (qport->uuconf_ttype == UUCONF_PORTTYPE_TCP)
1937    {
1938      char **pz;
1939
1940      fprintf (e, "TCP");
1941      if (qport->uuconf_zprotocols != NULL)
1942	fprintf (e, ",%s", qport->uuconf_zprotocols);
1943      fprintf (e, " ");
1944      if (qport->uuconf_u.uuconf_stcp.uuconf_zport == NULL)
1945	fprintf (e, "uucp");
1946      else
1947	fprintf (e, "%s", qport->uuconf_u.uuconf_stcp.uuconf_zport);
1948      fprintf (e, " - -");
1949      pz = qport->uuconf_u.uuconf_stcp.uuconf_pzdialer;
1950      if (pz != NULL)
1951	for (; *pz != NULL; pz++)
1952	  fprintf (e, " %s", *pz);
1953    }
1954  else if (qport->uuconf_ttype == UUCONF_PORTTYPE_TLI)
1955    {
1956      char **pz;
1957
1958      fprintf (e, "%s", qport->uuconf_zname);
1959      if (qport->uuconf_zprotocols != NULL)
1960	fprintf (e, ",%s", qport->uuconf_zprotocols);
1961      fprintf (e, " ");
1962      if (qport->uuconf_u.uuconf_stli.uuconf_zdevice != NULL)
1963	fprintf (e, "%s", qport->uuconf_u.uuconf_smodem.uuconf_zdevice);
1964      else
1965	fprintf (e, "-");
1966      fprintf (e, " - -");
1967      pz = qport->uuconf_u.uuconf_stli.uuconf_pzdialer;
1968      if (pz == NULL
1969	  || *pz == NULL
1970	  || (strcmp (*pz, "TLI") != 0
1971	      && strcmp (*pz, "TLIS") != 0))
1972	fprintf (e, " TLI%s \\D",
1973		 qport->uuconf_u.uuconf_stli.uuconf_fstream ? "S" : "");
1974      if (pz != NULL)
1975	for (; *pz != NULL; pz++)
1976	  fprintf (e, " %s", *pz);
1977    }
1978  else
1979    {
1980      fprintf (e, "# Ignoring port %s with unsupported type",
1981	       qport->uuconf_zname);
1982    }
1983
1984  fprintf (e, "\n");
1985
1986  /* Return UUCONF_NOT_FOUND to force uuconf_find_port to keep looking
1987     for a port.  */
1988  return UUCONF_NOT_FOUND;
1989}
1990
1991/* Write a dialer out to a Taylor UUCP configuration file.  This
1992   doesn't output the name, since it is called to output a specially
1993   defined dialer in the sys or port file.  */
1994
1995static void
1996uvwrite_taylor_dialer (e, qdialer, zprefix)
1997     FILE *e;
1998     struct uuconf_dialer *qdialer;
1999     const char *zprefix;
2000{
2001  char ab[100];
2002
2003  /* Reset default values, so we don't output them unnecessarily.  */
2004  if (qdialer->uuconf_schat.uuconf_ctimeout == 60)
2005    qdialer->uuconf_schat.uuconf_ctimeout = -1;
2006  if (qdialer->uuconf_schat.uuconf_fstrip)
2007    qdialer->uuconf_schat.uuconf_fstrip = -1;
2008  if (qdialer->uuconf_scomplete.uuconf_ctimeout == 60)
2009    qdialer->uuconf_scomplete.uuconf_ctimeout = -1;
2010  if (qdialer->uuconf_scomplete.uuconf_fstrip)
2011    qdialer->uuconf_scomplete.uuconf_fstrip = -1;
2012  if (qdialer->uuconf_sabort.uuconf_ctimeout == 60)
2013    qdialer->uuconf_sabort.uuconf_ctimeout = -1;
2014  if (qdialer->uuconf_sabort.uuconf_fstrip)
2015    qdialer->uuconf_sabort.uuconf_fstrip = -1;
2016
2017  uvwrite_chat (e, &qdialer->uuconf_schat, (struct uuconf_chat *) NULL,
2018		zprefix, FALSE);
2019  if (qdialer->uuconf_zdialtone != NULL
2020      && strcmp (qdialer->uuconf_zdialtone, ",") != 0)
2021    fprintf (e, "%sdialtone %s\n", zprefix, qdialer->uuconf_zdialtone);
2022  if (qdialer->uuconf_zpause != NULL
2023      && strcmp (qdialer->uuconf_zpause, ",") != 0)
2024    fprintf (e, "%spause %s\n", zprefix, qdialer->uuconf_zpause);
2025  if (! qdialer->uuconf_fcarrier)
2026    fprintf (e, "%scarrier false\n", zprefix);
2027  if (qdialer->uuconf_ccarrier_wait != 60)
2028    fprintf (e, "%scarrier-wait %d\n", zprefix,
2029	     qdialer->uuconf_ccarrier_wait);
2030  if (qdialer->uuconf_fdtr_toggle)
2031    fprintf (e, "%sdtr-toggle %s %s\n", zprefix,
2032	     qdialer->uuconf_fdtr_toggle ? "true" : "false",
2033	     qdialer->uuconf_fdtr_toggle_wait ? "true" : "false");
2034  sprintf (ab, "%scomplete-", zprefix);
2035  uvwrite_chat (e, &qdialer->uuconf_scomplete, (struct uuconf_chat *) NULL,
2036		ab, FALSE);
2037  sprintf (ab, "%sabort-", zprefix);
2038  uvwrite_chat (e, &qdialer->uuconf_sabort, (struct uuconf_chat *) NULL,
2039		ab, FALSE);
2040  if (qdialer->uuconf_qproto_params != NULL)
2041    uvwrite_proto_params (e, qdialer->uuconf_qproto_params, zprefix);
2042  if ((qdialer->uuconf_ireliable & UUCONF_RELIABLE_SPECIFIED) != 0)
2043    {
2044      sprintf (ab, "%sseven-bit", zprefix);
2045      uvwrite_boolean (e,
2046		       ((qdialer->uuconf_ireliable & UUCONF_RELIABLE_EIGHT)
2047			== 0),
2048		       ab);
2049      sprintf (ab, "%sreliable", zprefix);
2050      uvwrite_boolean (e,
2051		       ((qdialer->uuconf_ireliable & UUCONF_RELIABLE_RELIABLE)
2052			!= 0),
2053		       ab);
2054      sprintf (ab, "%shalf-duplex", zprefix);
2055      uvwrite_boolean (e,
2056		       ((qdialer->uuconf_ireliable
2057			 & UUCONF_RELIABLE_FULLDUPLEX) == 0),
2058		       ab);
2059    }
2060}
2061
2062/* Write a dialer out to an HDB configuration file.  */
2063
2064static void
2065uvwrite_hdb_dialer (e, qdialer)
2066     FILE *e;
2067     struct uuconf_dialer *qdialer;
2068{
2069  fprintf (e, "%s ", qdialer->uuconf_zname);
2070
2071  if (qdialer->uuconf_zdialtone != NULL)
2072    fprintf (e, "=%c", qdialer->uuconf_zdialtone[0]);
2073  if (qdialer->uuconf_zpause != NULL)
2074    fprintf (e, "-%c", qdialer->uuconf_zpause[0]);
2075
2076  if (qdialer->uuconf_schat.uuconf_pzchat != NULL)
2077    {
2078      if (qdialer->uuconf_zdialtone == NULL
2079	  && qdialer->uuconf_zpause == NULL)
2080	fprintf (e, "\"\"");
2081      fprintf (e, " ");
2082      uvwrite_chat_script (e, qdialer->uuconf_schat.uuconf_pzchat);
2083    }
2084
2085  fprintf (e, "\n");
2086}
2087
2088/* Display a uuconf error and exit.  */
2089
2090static void
2091uvuuconf_error (puuconf, iret)
2092     pointer puuconf;
2093     int iret;
2094{
2095  char ab[512];
2096
2097  (void) uuconf_error_string (puuconf, iret, ab, sizeof ab);
2098  if ((iret & UUCONF_ERROR_FILENAME) == 0)
2099    fprintf (stderr, "uuconv: %s\n", ab);
2100  else
2101    fprintf (stderr, "uuconv:%s\n", ab);
2102  if (UUCONF_ERROR_VALUE (iret) != UUCONF_FOPEN_FAILED)
2103    exit (EXIT_FAILURE);
2104}
2105