Added all of the MH sources, including RCS files, in
[mmh] / docs / historical / mh-6.8.5 / uip / bbc.c
1 /* bbc.c - ZOTnet BBoard checker */
2 #ifndef lint
3 static char ident[] = "@(#)$Id: bbc.c,v 2.13 1993/02/26 21:58:57 jromine Exp $";
4 #endif  lint
5
6 #include "../h/mh.h"
7 #include "../zotnet/bboards.h"
8 #include <stdio.h>
9 #ifdef  BPOP
10 #include "../zotnet/mts.h"
11 #endif  BPOP
12 #include <errno.h>
13 #include <signal.h>
14 #ifndef sigmask
15 #define sigmask(s)      (1 << ((s) - 1))
16 #endif  not sigmask
17 #ifdef  ridge
18 #undef  SIGTSTP
19 #endif  ridge
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #ifdef  SIGTSTP
23 #include <sys/wait.h>
24 #include <sys/time.h>
25 #include <sys/resource.h>
26 #endif  SIGTSTP
27 #ifdef LOCALE
28 #include        <locale.h>
29 #endif
30
31 #define RCFILE  ".bbrc"
32
33 #define NBB     100
34
35 /* \f */
36
37 static struct swit switches[] = {
38 #define TOPICSW 0
39     "topics", 6,
40 #define CHECKSW 1
41     "check", 5,
42 #define READSW  2
43     "read", 4,
44
45 #define QUIETSW 3
46     "quiet", 4,
47 #define VERBOSW 4
48     "verbose", 4,
49
50 #define ARCHSW  5
51     "archive", 4,
52 #define NOARCH  6
53     "noarchive", 3,
54
55 #define PROTSW  7
56     "protocol", 4,
57 #define NPROTSW 8
58     "noprotocol", 3,
59
60 #define PROGSW  9
61     "mshproc program", 4,
62
63 #define RCSW    10
64     "rcfile rcfile", 4,
65 #define NRCSW   11
66     "norcfile", 3,
67
68 #define FILESW  12
69     "file BBoardsfile", 4,
70 #define USERSW  13
71     "user BBoardsuser",
72 #ifndef NNTP
73         4,
74 #else   NNTP
75         -4,
76 #endif  NNTP
77
78 #define HOSTSW  14
79     "host host",
80 #ifndef BPOP
81     -4,
82 #else   BPOP
83     4,
84 #endif  BPOP
85 #define RPOPSW  15
86     "rpop",
87 #ifndef RPOP
88         -4,
89 #else   RPOP
90         4,
91 #endif  RPOP
92 #define NRPOPSW 16
93     "norpop",
94 #ifndef RPOP
95         -6,
96 #else   RPOP
97         6,
98 #endif  RPOP
99
100 #define HELPSW  17
101     "help", 4,
102
103     NULL, NULL
104 };
105
106 struct bbcount {
107     char   *key;
108     int     count;
109     struct bbcount *left;
110     struct bbcount *right;
111 };
112
113 /* \f */
114
115 extern int  errno;
116
117 static int  changed = 0;
118 static int  oops = 0;
119 static int  quitting = 0;
120
121 static int  archivesw = 0;
122 static int  checksw = 0;
123 static int  protsw = 1;
124 static int  quietsw = 0;
125 static int  readsw = 0;
126 static int  topicsw = 0;
127 static int  verbosw = 0;
128
129 static int  didpop = OK;
130 static int  rpop = 1;
131 static char *user = BBOARDS;
132 static char *host = NULL;
133 #ifdef  BPOP
134 extern char response[];
135
136 extern char   *getusr ();
137 static char  **getip ();
138 #endif  BPOP
139
140 TYPESIG sigser (), hupser ();
141 int     action ();
142 #ifdef  SIGTSTP
143 int     tstpid;
144 static  TYPESIG tstpser ();
145 #endif  SIGTSTP
146
147 static char *rcfile=NULL;
148
149
150 static struct bbcount  *bbc = NULL;
151 static struct bboard   *bbl = NULL;
152
153 struct bbcount *add_count (), *seek_count ();
154 struct bboard *getbbaux (), *getbbvis ();
155 static  void    bbreset();
156
157 #ifdef  UCL
158 extern  char       *bbs[];
159 extern  int        called_bbc;
160 static  int bbp;
161 #endif  UCL
162 /* \f */
163
164 /* ARGSUSED */
165
166 main (argc, argv)
167 int     argc;
168 char  **argv;
169 {
170 #ifndef UCL
171     int     bbp = 0,
172             vecp = 1;
173 #else   UCL
174     int    vecp = 1;
175 #endif  UCL
176     char   *cp,
177            *rc=NULL,
178           **ap,
179           **argp,
180             buffer[80],
181            *arguments[MAXARGS],
182 #ifndef UCL
183            *bbs[NBB + 1],
184 #endif  UCL
185            *vec[MAXARGS];
186 #ifdef  UCL
187     called_bbc = 1;
188     bbp = 0;
189 #endif  UCL
190
191 #ifdef LOCALE
192         setlocale(LC_ALL, "");
193 #endif
194     invo_name = r1bindex (argv[0], '/');
195 #ifdef  BPOP
196     mts_init (invo_name);
197     if (popbbhost && *popbbhost)
198         host = popbbhost;
199     if (popbbuser && *popbbuser)
200         user = popbbuser, rpop = 0;
201 #endif  BPOP
202     if ((cp = m_find (invo_name)) != NULL) {
203         ap = brkstring (cp = getcpy (cp), " ", "\n");
204         ap = copyip (ap, arguments);
205     }
206     else
207         ap = arguments;
208     (void) copyip (argv + 1, ap);
209     argp = arguments;
210
211     (void) setbbent (SB_STAY);
212
213 /* \f */
214
215     while (cp = *argp++) {
216         if (*cp == '-')
217             switch (smatch (++cp, switches)) {
218                 case AMBIGSW: 
219                     ambigsw (cp, switches);
220                     done (1);
221                 case UNKWNSW: 
222                    vec[vecp++] = --cp;
223                    continue;
224                 case HELPSW: 
225                     (void) sprintf (buffer,
226                         "%s [bboards ...] [switches] [switches for mshproc]",
227                         invo_name);
228                     help (buffer, switches);
229                     done (1);
230
231                 case TOPICSW: 
232                     topicsw++;
233                     checksw = readsw = 0;
234                     continue;
235                 case CHECKSW: 
236                     checksw++;
237                     readsw = topicsw = 0;
238                     continue;
239                 case READSW: 
240                     readsw++;
241                     checksw = topicsw = 0;
242                     continue;
243
244                 case ARCHSW: 
245                     archivesw++;
246                     continue;
247                 case NOARCH: 
248                     archivesw = 0;
249                     continue;
250
251                 case PROTSW: 
252                     protsw++;
253                     continue;
254                 case NPROTSW: 
255                     protsw = 0;
256                     continue;
257
258                 case QUIETSW: 
259                     quietsw++;
260                     verbosw = 0;
261                     continue;
262                 case VERBOSW: 
263                     verbosw++;
264                     quietsw = 0;
265                     continue;
266
267                 case PROGSW:
268                     if (!(mshproc = *argp++) || *mshproc == '-')
269                         adios (NULLCP, "missing argument to %s", argp[-2]);
270                     continue;
271
272                 case RCSW:
273                     if (!(rc = *argp++) || *rc == '-')
274                         adios (NULLCP, "missing argument to %s", argp[-2]);
275                     continue;
276                 case NRCSW:
277                     rc = NULL;
278                     continue;
279
280                 case FILESW:
281                     if (!(cp = *argp++) || *cp == '-')
282                         adios (NULLCP, "missing argument to %s", argp[-2]);
283                     if (!setbbinfo (user, cp, 1))
284                         adios (NULLCP, "setbbinfo(%s, %s, 1) failed -- %s",
285                                 user, cp, getbberr ());
286                     continue;
287                 case USERSW:
288                     if (!(user = *argp++) || *user == '-')
289                         adios (NULLCP, "missing argument to %s", argp[-2]);
290                     continue;
291
292                 case HOSTSW:
293                     if (!(host = *argp++) || *host == '-')
294                         adios (NULLCP, "missing argument to %s", argp[-2]);
295                     didpop = NOTOK;
296                     continue;
297                 case RPOPSW:
298                     rpop++;
299                     continue;
300                 case NRPOPSW:
301                     rpop = 0;
302                     continue;
303             }
304         if (bbp < NBB)
305             bbs[bbp++] = cp;
306         else
307             adios (NULLCP, "too many bboards, starting with %s", cp);
308     }
309     bbs[bbp] = NULL;
310
311 /* \f */
312
313 #ifdef  BPOP
314     if (host && !*host)
315         host = NULL, didpop = OK;
316     if (!host || !rpop)
317         (void) setuid (getuid ());
318 #endif  BPOP
319
320     if (!m_find ("path"))
321         free (path ("./", TFOLDER));
322
323     rcinit (rc);
324
325     for (bbp = 0; cp = bbs[bbp]; bbp++)
326         add_bb (cp, NOTOK);
327
328 #ifdef UCL
329     if (topicsw) {
330         called_bbc = 0;
331         topics ();
332         }
333 #else
334     if (topicsw)
335         topics ();
336 #endif
337     else {
338         default_bboards ();
339         if (checksw)
340             check ();
341         else
342             process (vecp, vec);
343     }
344
345 #ifdef  BPOP
346     if (didpop != OK && pop_quit () == NOTOK)
347         adios (NULLCP, "%s", response);
348 #endif  BPOP
349
350     done (0);
351 }
352
353 /* \f */
354
355 topics () {
356     register char  *cp,
357                   **ap;
358     register struct bboard *bb;
359
360     printf ("%16s %s   %s\n", "BBoard", "Items",
361             verbosw ? "Interesting Facts" : "Last Update");
362     printf ("%16s %s   %s\n", "------", "-----",
363             verbosw ? "-----------------" : "-----------");
364
365     for (bb = bbl ? bbl : getbbvis ();
366             bb;
367             bb = bbl ? bb -> bb_link : getbbvis ()) {
368         printf ("%16s %5d   %s\n",
369                 bb -> bb_name, bb -> bb_maxima,
370                 bb -> bb_date ? bb -> bb_date : "no deliveries");
371         if (verbosw) {
372             if (*bb -> bb_aka) {
373                 cp = NULL;
374                 for (ap = bb -> bb_aka; *ap; ap++)
375                     cp = add (*ap, cp ? add (", ", cp) : cp);
376                 printv ("AKA", cp);
377                 free (cp);
378             }
379
380             printv ("Leaders", *bb -> bb_leader);
381             for (ap = bb -> bb_leader + 1; *ap; ap++)
382                 printv (NULLCP, *ap);
383             printv ("File", bb -> bb_file);
384             printv ("Archive", bb -> bb_archive);
385             printv ("Info", bb -> bb_info);
386             printv ("Map", bb -> bb_map);
387             printv ("Password", bb -> bb_passwd);
388             if (strcmp (bb -> bb_name, bb -> bb_addr))
389                 printv ("Address", bb -> bb_addr);
390             if (strcmp (*bb -> bb_leader, bb -> bb_request))
391                 printv ("Request", bb -> bb_request);
392             if (*bb -> bb_relay)
393                 printv ("Relay", bb -> bb_relay);
394             if (*bb -> bb_dist) {
395                 changed = 0;
396                 (void) getbbdist (bb, action);
397                 if (!changed)
398                     printv ("Dist", "");
399                 if (cp = getbberr ())
400                     printv ("Error", cp);
401             }
402             printb (bb -> bb_flags & ~BB_SEEN);
403         }
404     }
405 }
406
407 /* \f */
408
409 printv (key, value)
410 register char   *key,
411                 *value;
412 {
413     char    buffer[BUFSIZ];
414
415     if (key)
416         (void) sprintf (buffer, "%s: ", key);
417     else
418         buffer[0] = '\0';
419     printf ("%*s%-*s", 25, "", 10, buffer);
420     if (value && *value)
421         printf ("%s", value);
422     (void) putchar ('\n');
423 }
424
425
426 int     action (local, domain)
427 register char   *local,
428                 *domain;
429 {
430     char    buffer[BUFSIZ];
431
432     (void) sprintf (buffer, "%s@%s", local, domain);
433     printv (changed++ ? NULL : "Dist", buffer);
434     return 0;
435 }
436
437
438 printb (flags)
439 unsigned int flags;
440 {
441     char buffer[BUFSIZ];
442
443     printv ("Flags", sprintb (buffer, flags, BBITS));
444 }
445
446 /* \f */
447
448 check () {
449 #define grammar(a,b,c)  (a == 1 ? b : c)
450 #define plural(d)       grammar(d, "", "s")
451
452     int     diff;
453     register struct bboard  *bb;
454
455     for (bb = bbl; bb; bb = bb -> bb_link) {
456         diff = bb -> bb_maxima - bb -> bb_count;
457         if (quietsw) {
458             if (diff > 0)
459                 printf ("%s -- %d item%s unseen\n",
460                         bb -> bb_name, diff, plural (diff));
461         }
462         else
463             if (bb -> bb_maxima == 0)
464                 printf ("%s -- empty\n", bb -> bb_name);
465             else
466                 if (bb -> bb_count == 0)
467                     printf ("%s -- %d item%sseen)\n",
468                             bb -> bb_name, bb -> bb_maxima,
469                             grammar (bb -> bb_maxima, " (un", "s (none "));
470                 else
471                     if (diff <= 0)
472                         printf ("%s -- %d item%s (all seen)\n",
473                                 bb -> bb_name, bb -> bb_maxima,
474                                 plural (bb -> bb_maxima));
475                     else
476                         printf ("%s -- %d item%s unseen\n",
477                                 bb -> bb_name, diff, plural (diff));
478     }
479 }
480
481 /* \f */
482
483 process (vecp, vec)
484 int     vecp;
485 char   *vec[];
486 {
487     int     diff;
488 #ifdef  SIGTSTP
489     TYPESIG         (*tstat) ();
490 #endif  SIGTSTP
491     register struct bboard *bb;
492
493     vec[0] = r1bindex (mshproc, '/');
494 #ifdef  SIGTSTP
495     tstat = signal (SIGTSTP, tstpser);
496 #endif  SIGTSTP
497
498     for (bb = bbl; bb && !quitting; bb = bb -> bb_link) {
499         diff = bb -> bb_maxima - bb -> bb_count;
500         if (bb -> bb_maxima == 0) {
501             if (!quietsw)
502                 printf ("%s -- empty\n", bb -> bb_name);
503             continue;
504         }
505         else {
506             if (diff < 0) {
507                 printf (
508                 "Oops! looks like someone reset %s -- assuming all unseen\n",
509                     bb -> bb_name);
510                 diff = bb -> bb_maxima;
511                 bbreset (bb, 0);
512             }
513             if (verbosw || archivesw || diff > 0)
514                 bbread (bb, vecp, vec);
515             else
516                 if (!quietsw)
517                     printf ("%s -- %d item%s (all seen)\n",
518                             bb -> bb_name, bb -> bb_maxima,
519                             plural (bb -> bb_maxima));
520         }
521     };
522
523 #ifdef  SIGTSTP
524     (void) signal (SIGTSTP, tstat);
525 #endif  SIGTSTP
526     rcend ();
527 }
528
529 /* \f */
530
531 #ifdef  BPOP
532 /* ARGSUSED */
533
534 static int  xtnd1 (s)
535 char   *s;
536 {
537     return OK;
538 }
539 #endif  BPOP
540
541 /* \f */
542
543 bbread (bb, vecp, vec)
544 register struct bboard  *bb;
545 int     vecp;
546 char   *vec[];
547 {
548     int     child_id,
549             pd[2];
550     char    buf1[BUFSIZ],
551             buf2[BUFSIZ],
552             buf3[BUFSIZ];
553 #ifdef  BPOP
554     int     nmsgs,
555             nbytes;
556     char    buf4[BUFSIZ],
557             buf5[BUFSIZ];
558 #endif  BPOP
559     struct stat st;
560
561 #ifdef  BPOP
562     if (bb -> bb_flags & BB_REMOTE) {
563         if (pop_xtnd (xtnd1, "%s %s", archivesw ? "archive" : "bboards",
564                         bb -> bb_name) == NOTOK) {
565             advise (NULLCP, "%s", response);
566             return;
567         }
568         if (pop_stat (&nmsgs, &nbytes) == NOTOK)
569             adios (NULLCP, "%s", response);
570         if (nmsgs == 0) {
571             if (verbosw)
572                 printf ("%s -- empty\n", bb -> bb_name);
573             return;
574         }
575         if (pop_fd (buf4, buf5) == NOTOK)
576             adios (NULLCP, "%s", response);
577     }
578     else
579 #endif  BPOP
580     if (stat (archivesw ? bb -> bb_archive : bb -> bb_file, &st) != NOTOK
581             && st.st_size == 0)
582         return;
583
584     if (protsw) {
585         if (pipe (pd) == NOTOK)
586             adios ("pipe", "unable to");
587         (void) sprintf (buf3, "%d", getpid ());
588     }
589
590     switch (child_id = fork ()) {
591         case NOTOK: 
592             adios ("fork", "unable to");
593
594         case OK: 
595             if (protsw) {
596                 (void) close (pd[0]);
597                 (void) sprintf (buf1, "%d", bb -> bb_count + 1);
598                 (void) sprintf (buf2, "%d", pd[1]);
599                 vec[vecp++] = "-idname";
600                 vec[vecp++] = bb -> bb_name;
601                 vec[vecp++] = "-idstart";
602                 vec[vecp++] = buf1;
603                 vec[vecp++] = "-idstop";
604                 vec[vecp++] = buf2;
605                 vec[vecp++] = "-idquit";
606                 vec[vecp++] = buf3;
607             }
608 #ifdef  BPOP
609             if (bb -> bb_flags & BB_REMOTE) {
610                 vec[vecp++] = "-popread";
611                 vec[vecp++] = buf4;
612                 vec[vecp++] = "-popwrite";
613                 vec[vecp++] = buf5;
614             }
615 #endif  BPOP
616             vec[vecp++] = archivesw ? bb -> bb_archive : bb -> bb_file;
617             vec[vecp] = NULL;
618             execvp (mshproc, vec);
619             fprintf (stderr, "unable to exec ");
620             perror (mshproc);
621             _exit (-1);
622
623         default: 
624 #ifdef  SIGTSTP
625             tstpid = child_id;
626 #endif  SIGTSTP
627             if (protsw) {
628                 (void) close (pd[1]);
629                 pgmread (pd[0], child_id, bb);
630             }
631             else
632                 (void) pidXwait (child_id, mshproc);
633     }
634 }
635
636 /* \f */
637
638 pgmread (pd, child_id, bb)
639 int     pd,
640         child_id;
641 register struct bboard  *bb;
642 {
643     int     i,
644             j,
645             n;
646     TYPESIG (*estat) (), (*hstat) (), (*istat) (), (*qstat) (), (*tstat) ();
647     char    buffer[BUFSIZ];
648     struct bbcount *selected;
649
650     estat = signal (SIGEMT, sigser);
651     hstat = signal (SIGHUP, hupser);
652     istat = signal (SIGINT, SIG_IGN);
653     qstat = signal (SIGQUIT, SIG_IGN);
654     tstat = signal (SIGTERM, sigser);
655
656     while ((n = read (pd, buffer, sizeof buffer)) == NOTOK && errno == EINTR)
657         continue;
658     (void) close (pd);
659     (void) pidXwait (child_id, mshproc);
660
661     (void) signal (SIGEMT, estat);
662     (void) signal (SIGHUP, hstat);
663     (void) signal (SIGINT, istat);
664     (void) signal (SIGQUIT, qstat);
665     (void) signal (SIGTERM, tstat);
666
667     if (n <= 0)
668         return;
669     if (sscanf (buffer, "%d %d", &i, &j) != 2 || i <= 0 || j <= 0)
670         return;
671
672     if ((selected = seek_count (bbc, bb -> bb_name)) == NULL) {
673         bbc = add_count (bbc, bb -> bb_name, i);
674         changed++;
675     }
676     else
677         if (archivesw) {
678             if (i > selected -> count) {
679                 selected -> count = i;
680                 changed++;
681             }
682         }
683         else {
684             if (bb -> bb_maxima > j && i >= j)/* bbl... */
685                 i = bb -> bb_maxima;
686             if (i != selected -> count) {
687                 selected -> count = i;
688                 changed++;
689             }
690         }
691 }
692
693
694 /* ARGSUSED */
695
696 TYPESIG sigser (i)
697 int     i;
698 {
699 #ifndef BSD42
700     (void) signal (i, sigser);
701 #endif  not BSD42
702     quitting++;
703 }
704
705
706 /* ARGSUSED */
707
708 TYPESIG hupser (i)
709 int     i;
710 {
711     static int armed = 0;
712
713 #ifndef BSD42
714     (void) signal (i, hupser);
715 #endif
716
717     if (!armed++)               /* tick tock... */
718         alarm ((unsigned int) 30);
719 }
720
721 /* \f */
722
723 rcinit (rc)
724 register char  *rc;
725 {
726     int     state;
727     register char  *cp;
728     char    key[NAMESZ],
729             value[BUFSIZ];
730     register FILE  *bbrc;
731
732     if ((cp = rc ? rc : getenv ("MHBBRC")) && *cp) {
733         rcfile = path (cp, TFILE);
734         if (*cp != '/')
735             (void) m_putenv ("MHBBRC", rcfile);
736     }
737     else
738         rcfile = concat (mypath, "/", RCFILE, NULLCP);
739
740     if ((bbrc = fopen (rcfile, "r")) == NULL)
741         if (cp && *cp)
742             adios (rcfile, "unable to read");
743         else
744             return;
745
746     for (state = FLD;;) {
747         switch (state = m_getfld (state, key, value, sizeof value, bbrc)) {
748             case FLD: 
749             case FLDEOF: 
750                 make_lower (key, key);
751                 bbc = add_count (bbc, key, atoi (value));
752                 if (state == FLDEOF)
753                     break;
754                 continue;
755
756             default: 
757                 admonish (NULLCP, "bad format: %s", rcfile);
758             case FILEEOF:
759                 break;
760         }
761
762         break;
763     }
764
765     if (ferror (bbrc) && !feof (bbrc))
766         admonish (rcfile, "error reading");
767     (void) fclose (bbrc);
768 }
769
770 /* \f */
771
772 rcend () {
773     TYPESIG (*hstat) (), (*istat) (), (*qstat) (), (*tstat) ();
774     register FILE *bbrc;
775
776     if (!changed)
777         return;
778
779     hstat = signal (SIGHUP, SIG_IGN);
780     istat = signal (SIGINT, SIG_IGN);
781     qstat = signal (SIGQUIT, SIG_IGN);
782     tstat = signal (SIGTERM, SIG_IGN);
783
784     if ((bbrc = fopen (rcfile, "w")) == NULL)
785         adios (rcfile, "unable to write");
786     rcput (bbrc, bbc);
787
788     if (ferror (bbrc))
789         adios (rcfile, "error writing");
790     (void) fclose (bbrc);
791
792     (void) signal (SIGHUP, hstat);
793     (void) signal (SIGINT, istat);
794     (void) signal (SIGQUIT, qstat);
795     (void) signal (SIGTERM, tstat);
796
797     changed = 0;
798 }
799
800
801 rcput (bbrc, p)
802 register FILE *bbrc;
803 register struct bbcount *p;
804 {
805     if (p == NULL)
806         return;
807
808     fprintf (bbrc, "%s: %d\n", p -> key, p -> count);
809     rcput (bbrc, p -> left);
810     rcput (bbrc, p -> right);
811 }
812
813 /* \f */
814
815 #ifdef  SIGTSTP
816 static TYPESIG  tstpser (sig)
817 int     sig;
818 {
819     int     pid;
820 #if defined(BSD42) && !defined(WAITINT)
821     union wait w;
822 #else
823     int w;
824 #endif
825
826     rcend ();
827
828 #ifdef SVR4
829     waitpid(tstpid, &w, WUNTRACED);
830 #else
831     while ((pid = wait3 (&w, WUNTRACED, (struct rusage *) 0)) != NOTOK
832             && pid != tstpid)
833         continue;
834 #endif
835
836     (void) signal (SIGTSTP, SIG_DFL);
837 #ifdef  BSD42
838     (void) sigsetmask (sigblock (0) & ~sigmask (SIGTSTP));
839 #endif  BSD42
840
841     (void) kill (getpid (), sig);
842
843 #ifdef  BSD42
844     (void) sigblock (sigmask (SIGTSTP));
845 #endif  BSD42
846     (void) signal (SIGTSTP, tstpser);
847 }
848 #endif  SIGTSTP
849
850 /* \f */
851 static  void    bbreset (bb, i)
852 register struct bboard  *bb;
853 int i;
854 {
855     struct bbcount *selected;
856
857     bb -> bb_count = i;
858     if ((selected = seek_count (bbc, bb -> bb_name)) == NULL)
859         bbc = add_count (bbc, bb -> bb_name, i);
860     else
861         selected -> count = i;
862
863     changed++;
864 }
865
866 struct bbcount *add_count (p, w, i)
867 register struct bbcount *p;
868 register char   *w;
869 int     i;
870 {
871     int     cond;
872
873     if (p == NULL) {
874         p = (struct bbcount *) malloc (sizeof *p);
875         if (p == NULL)
876             adios (NULLCP,"insufficient memory");
877         p -> key = getcpy (w);
878         p -> count = i;
879         p -> left = p -> right = NULL;
880     }
881     else
882         if ((cond = strcmp (w, p -> key)) < 0)
883             p -> left = add_count (p -> left, w, i);
884         else
885             if (cond > 0)
886                 p -> right = add_count (p -> right, w, i);
887
888     return p;
889 }
890
891
892 struct bbcount *seek_count (p, w)
893 register struct bbcount *p;
894 register char   *w;
895 {
896     int     cond;
897
898     if (p == NULL || (cond = strcmp (w, p -> key)) == 0)
899         return p;
900     else
901         return seek_count (cond < 0 ? p -> left : p -> right, w);
902 }
903
904 /* \f */
905
906 default_bboards () {
907     register char  *cp,
908                   **ap;
909 #ifdef  UCL
910     register int    i = bbp;
911 #endif  UCL
912
913     if (bbl != NULL)
914         return;
915
916     if (!archivesw && ((cp = m_find ("bboards")) != NULL)) {
917 #ifndef BPOP
918         for (ap = brkstring (cp = getcpy (cp), " ", "\n"); *ap; ap++)
919 #else   BPOP
920         for (ap = getip (cp); *ap; ap++)
921 #endif  BPOP
922 #ifndef UCL
923             add_bb (*ap, OK);
924 #else   UCL
925             bbs[bbp++] = *ap;
926         bbs[bbp] = NULL;
927         while (i < bbp)
928             add_bb (bbs[i++], OK);
929 #endif  UCL
930 #ifndef BPOP
931         free (cp);
932 #endif  not BPOP
933         if (oops)
934             advise (NULLCP, "please fix the %s: entry in your %s file",
935                 "bboards", mh_profile);
936     }
937     else {
938 #ifdef  UCL
939         bbs[bbp++] = "system";
940         bbs[bbp] = NULL;
941 #endif  UCL
942 #ifndef NNTP
943         add_bb ("system", NOTOK);
944 #else   NNTP
945         add_bb ("general", NOTOK);
946 #ifdef  UCI
947         add_bb ("ics.system", NOTOK);
948         add_bb ("ics.general", NOTOK);
949 #endif  UCI
950 #endif  NNTP
951     }
952 #ifdef  UCL
953     bbs[bbp] = NULL;
954 #endif  UCL
955
956     if (bbl == NULL)
957         done (1);
958 }
959
960 /* \f */
961
962 add_bb (s, hush)
963 register char   *s;
964 int     hush;
965 {
966     register struct bboard  *bb;
967     static struct bboard   *tail = NULL;
968
969     make_lower (s, s);
970     if ((bb = getbbaux (s)) == NULL)
971         if (hush == OK)
972             return;
973         else
974             adios (NULLCP, "no such bboard as '%s'", s);
975
976     if (bb -> bb_flags & BB_SEEN) {
977         if (hush == OK) {
978             admonish (NULLCP, "duplicate bboard '%s'", s);
979             oops++;
980         }
981         return;
982     }
983     bb -> bb_flags |= BB_SEEN;
984
985     if (tail != NULL)
986         tail -> bb_link = bb;
987     if (bbl == NULL)
988         bbl = bb;
989     tail = bb;
990 }
991
992 /* \f */
993
994 #ifdef  BPOP
995 static struct bboard   *Bhead = NULL;
996 static struct bboard   *Btail = NULL;
997
998 static int xtnd2 (s)
999 char   *s;
1000 {
1001     int     maxima;
1002     char    name[BUFSIZ];
1003     register struct bboard *bb;
1004
1005     if (sscanf (s, "%s %d", name, &maxima) != 2)
1006         adios (NULLCP, "XTND2 botch: %s", s);
1007
1008     if ((bb = (struct bboard   *) calloc (1, sizeof *bb)) == NULL)
1009         adios (NULLCP, "insufficient memory");
1010     bb -> bb_name = getcpy (name);
1011 #ifdef  NNTP
1012     if (index(name, '.')) {
1013         char *cp;
1014         bb -> bb_aka = getip (name);
1015         for (cp = *bb -> bb_aka; *cp; cp++)
1016             if (*cp == '.')
1017                 *cp = '-';
1018     } else {
1019 #endif
1020     if ((bb -> bb_aka = (char **) calloc (1, sizeof *bb -> bb_aka)) == NULL)
1021         adios (NULLCP, "insufficient memory");
1022     *bb -> bb_aka = NULL;
1023 #ifdef  NNTP
1024     }
1025 #endif  NNTP
1026     bb -> bb_file = bb -> bb_archive = bb -> bb_info = bb -> bb_map = "";
1027     bb -> bb_passwd = "";
1028 #ifndef NNTP
1029     if ((bb -> bb_leader = (char **) calloc (1, sizeof *bb -> bb_leader))
1030             == NULL)
1031         adios (NULLCP, "insufficient memory");
1032     *bb -> bb_leader = NULL;
1033 #else   NNTP
1034     bb -> bb_leader = getip ("usenet");
1035 #endif  NNTP
1036     bb -> bb_addr = bb -> bb_request = bb -> bb_relay = "";
1037     if ((bb -> bb_dist = (char **) calloc (1, sizeof *bb -> bb_dist)) == NULL)
1038         adios (NULLCP, "insufficient memory");
1039     *bb -> bb_dist = NULL;
1040     bb -> bb_flags = BB_REMOTE;
1041     bb -> bb_count = 0;
1042     bb -> bb_maxima = maxima;
1043     bb -> bb_date = "";
1044     bb -> bb_next = bb -> bb_link = bb -> bb_chain = NULL;
1045
1046     if (Btail != NULL)
1047         Btail -> bb_chain = bb;
1048     if (Bhead == NULL)
1049         Bhead = bb;
1050     Btail = bb;
1051
1052     return OK;
1053 }
1054
1055 /* \f */
1056
1057 static int xtnd3 (s)
1058 char   *s;
1059 {
1060     static int  bbs_int = 0;
1061     static struct bboard   *bb;
1062
1063     switch (bbs_int++) {
1064         case 0: 
1065             for (bb = Bhead; bb; bb = bb -> bb_chain)
1066                 if (strcmp (bb -> bb_name, s) == 0)
1067                     break;
1068             if (bb == NULL)
1069                 adios (NULLCP, "XTND3 botch");
1070
1071             free (bb -> bb_name);
1072             bb -> bb_name = getcpy (s);
1073             break;
1074         case 1: 
1075             if (bb -> bb_aka)
1076                 free ((char *) bb -> bb_aka);
1077             bb -> bb_aka = getip (s);
1078             break;
1079         case 2: 
1080             bb -> bb_file = getcpy (s);
1081             break;
1082         case 3: 
1083             bb -> bb_archive = getcpy (s);
1084             break;
1085         case 4: 
1086             bb -> bb_info = getcpy (s);
1087             break;
1088         case 5: 
1089             bb -> bb_map = getcpy (s);
1090             break;
1091         case 6: 
1092             bb -> bb_passwd = getcpy (s);
1093             break;
1094         case 7: 
1095             if (bb -> bb_leader)
1096                 free ((char *) bb -> bb_leader);
1097             bb -> bb_leader = getip (s);
1098             break;
1099         case 8: 
1100             bb -> bb_addr = getcpy (s);
1101             break;
1102         case 9: 
1103             bb -> bb_request = getcpy (s);
1104             break;
1105         case 10: 
1106             bb -> bb_relay = getcpy (s);
1107             break;
1108         case 11: 
1109             if (bb -> bb_dist)
1110                 free ((char *) bb -> bb_dist);
1111             bb -> bb_dist = getip (s);
1112             break;
1113         case 12: 
1114             bb -> bb_flags = bb -> bb_maxima = 0;
1115             (void) sscanf (s, "%o %d", &bb -> bb_flags, &bb -> bb_maxima);
1116             bb -> bb_flags |= BB_REMOTE;
1117             break;
1118         case 13: 
1119             bb -> bb_date = getcpy (s);
1120             bbs_int = 0;
1121             break;
1122     }
1123
1124     return OK;
1125 }
1126
1127
1128 static char **getip (s)
1129 char   *s;
1130 {
1131     register char **ap,
1132                   **p,
1133                   **q;
1134
1135     for (p = ap = brkstring (getcpy (s), " ", "\n"); *p; p++)
1136         continue;
1137
1138     q = (char **) calloc ((unsigned) (p - ap + 1), sizeof *q);
1139     if (q == NULL)
1140         adios (NULLCP, "insufficient memory");
1141
1142     for (p = ap, ap = q; *p; *q++ = *p++)
1143         continue;
1144     *q = NULL;
1145
1146     return ap;
1147 }
1148
1149 /* \f */
1150
1151 static struct bboard   *rover = NULL;
1152
1153 struct bboard  *getbbpop () {
1154     int     snoop;
1155     char   *cp,
1156            *pass = NULL;
1157     register struct bboard *bb;
1158
1159     if (didpop != NOTOK && ((bb = getbbent ()) || !host))
1160         return bb;
1161
1162     if (Bhead == NULL) {
1163         snoop = (cp = getenv ("MHPOPDEBUG")) && *cp;
1164         if (rpop) {
1165             if (user == NULL)
1166                 user = getusr ();
1167             pass = getusr ();
1168         }
1169         else
1170             if (strcmp (user, popbbuser) == 0)
1171                 pass = user;
1172             else
1173                 ruserpass (host, &user, &pass);
1174         if (didpop != NOTOK)
1175             didpop = DONE;
1176
1177         if (pop_init (host, user, pass, snoop, rpop) == NOTOK)
1178             adios (NULLCP, "%s", response);
1179         if (rpop)
1180             (void) setuid (getuid ());
1181         if (pop_xtnd (xtnd2, "bboards") == NOTOK)
1182             adios (NULLCP, "%s", response);
1183         if (topicsw && verbosw) /* could optimize here */
1184             for (bb = Bhead; bb; bb = bb -> bb_chain)
1185                 if (pop_xtnd (xtnd3, "x-bboards %s", bb -> bb_name) == NOTOK)
1186                     adios (NULLCP, "%s", response);
1187         rover = Bhead;
1188     }
1189
1190     if (bb = rover)
1191         rover = rover -> bb_chain;
1192     return bb;
1193 }
1194
1195 #define getbbent        getbbpop
1196 #endif  BPOP
1197
1198 /* \f */
1199
1200 struct bboard *getbbaux (s)
1201 register char   *s;
1202 {
1203 #ifdef  BPOP
1204     int     nlatch = host ? 1 : 0;
1205 #endif  BPOP
1206     register char  **ap;
1207     register struct bbcount *selected;
1208     register struct bboard *bb;
1209     static struct bboard   *head = NULL,
1210                            *tail = NULL;
1211
1212     for (bb = head; bb; bb = bb -> bb_next) {
1213         if (strcmp (bb -> bb_name, s) == 0)
1214             return bb;
1215         for (ap = bb -> bb_aka; *ap; ap++)
1216             if (strcmp (*ap, s) == 0)
1217                 return bb;
1218     }
1219
1220 #ifdef  BPOP
1221 one_more_time: ;
1222 #endif  BPOP
1223     while (bb = getbbent ()) {
1224         if ((selected = seek_count (bbc, bb -> bb_name)) != NULL)
1225             bb -> bb_count = selected -> count;
1226
1227 #ifdef  BPOP
1228         if (!(bb -> bb_flags & BB_REMOTE))
1229 #endif  BPOP
1230         if ((bb = getbbcpy (bb)) == NULL)
1231             adios (NULLCP, "insufficient memory");
1232         if (tail != NULL)
1233             tail -> bb_next = bb;
1234         if (head == NULL)
1235             head = bb;
1236         tail = bb;
1237
1238         if (strcmp (bb -> bb_name, s) == 0) {
1239 found_it: ;
1240             bb -> bb_flags &= ~BB_SEEN;
1241             return bb;
1242         }
1243         for (ap = bb -> bb_aka; *ap; ap++)
1244             if (strcmp (*ap, s) == 0)
1245                 goto found_it;
1246     }
1247
1248 #ifdef  BPOP
1249     if (nlatch && pop_xtnd (xtnd2, "bboards %s", s) != NOTOK) {
1250         rover = Bhead;
1251         nlatch = 0;
1252         goto one_more_time;
1253     }
1254 #endif  BPOP
1255
1256     return NULL;
1257 }
1258
1259
1260 struct bboard *getbbvis () {
1261     register struct bboard *bb;
1262
1263     while (bb = getbbent ())
1264         if (!(bb -> bb_flags & BB_INVIS)
1265                 && (access (bb -> bb_file, 04) != NOTOK || errno != EACCES))
1266             break;
1267
1268     return bb;
1269 }