1 /* bbc.c - ZOTnet BBoard checker */
3 static char ident[] = "@(#)$Id: bbc.c,v 2.13 1993/02/26 21:58:57 jromine Exp $";
7 #include "../zotnet/bboards.h"
10 #include "../zotnet/mts.h"
15 #define sigmask(s) (1 << ((s) - 1))
20 #include <sys/types.h>
25 #include <sys/resource.h>
31 #define RCFILE ".bbrc"
37 static struct swit switches[] = {
69 "file BBoardsfile", 4,
109 struct bbcount *left;
110 struct bbcount *right;
117 static int changed = 0;
119 static int quitting = 0;
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;
129 static int didpop = OK;
131 static char *user = BBOARDS;
132 static char *host = NULL;
134 extern char response[];
136 extern char *getusr ();
137 static char **getip ();
140 TYPESIG sigser (), hupser ();
144 static TYPESIG tstpser ();
147 static char *rcfile=NULL;
150 static struct bbcount *bbc = NULL;
151 static struct bboard *bbl = NULL;
153 struct bbcount *add_count (), *seek_count ();
154 struct bboard *getbbaux (), *getbbvis ();
155 static void bbreset();
159 extern int called_bbc;
192 setlocale(LC_ALL, "");
194 invo_name = r1bindex (argv[0], '/');
196 mts_init (invo_name);
197 if (popbbhost && *popbbhost)
199 if (popbbuser && *popbbuser)
200 user = popbbuser, rpop = 0;
202 if ((cp = m_find (invo_name)) != NULL) {
203 ap = brkstring (cp = getcpy (cp), " ", "\n");
204 ap = copyip (ap, arguments);
208 (void) copyip (argv + 1, ap);
211 (void) setbbent (SB_STAY);
215 while (cp = *argp++) {
217 switch (smatch (++cp, switches)) {
219 ambigsw (cp, switches);
225 (void) sprintf (buffer,
226 "%s [bboards ...] [switches] [switches for mshproc]",
228 help (buffer, switches);
233 checksw = readsw = 0;
237 readsw = topicsw = 0;
241 checksw = topicsw = 0;
268 if (!(mshproc = *argp++) || *mshproc == '-')
269 adios (NULLCP, "missing argument to %s", argp[-2]);
273 if (!(rc = *argp++) || *rc == '-')
274 adios (NULLCP, "missing argument to %s", argp[-2]);
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 ());
288 if (!(user = *argp++) || *user == '-')
289 adios (NULLCP, "missing argument to %s", argp[-2]);
293 if (!(host = *argp++) || *host == '-')
294 adios (NULLCP, "missing argument to %s", argp[-2]);
307 adios (NULLCP, "too many bboards, starting with %s", cp);
315 host = NULL, didpop = OK;
317 (void) setuid (getuid ());
320 if (!m_find ("path"))
321 free (path ("./", TFOLDER));
325 for (bbp = 0; cp = bbs[bbp]; bbp++)
346 if (didpop != OK && pop_quit () == NOTOK)
347 adios (NULLCP, "%s", response);
358 register struct bboard *bb;
360 printf ("%16s %s %s\n", "BBoard", "Items",
361 verbosw ? "Interesting Facts" : "Last Update");
362 printf ("%16s %s %s\n", "------", "-----",
363 verbosw ? "-----------------" : "-----------");
365 for (bb = bbl ? bbl : getbbvis ();
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");
374 for (ap = bb -> bb_aka; *ap; ap++)
375 cp = add (*ap, cp ? add (", ", cp) : cp);
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);
393 printv ("Relay", bb -> bb_relay);
394 if (*bb -> bb_dist) {
396 (void) getbbdist (bb, action);
399 if (cp = getbberr ())
400 printv ("Error", cp);
402 printb (bb -> bb_flags & ~BB_SEEN);
416 (void) sprintf (buffer, "%s: ", key);
419 printf ("%*s%-*s", 25, "", 10, buffer);
421 printf ("%s", value);
422 (void) putchar ('\n');
426 int action (local, domain)
427 register char *local,
432 (void) sprintf (buffer, "%s@%s", local, domain);
433 printv (changed++ ? NULL : "Dist", buffer);
443 printv ("Flags", sprintb (buffer, flags, BBITS));
449 #define grammar(a,b,c) (a == 1 ? b : c)
450 #define plural(d) grammar(d, "", "s")
453 register struct bboard *bb;
455 for (bb = bbl; bb; bb = bb -> bb_link) {
456 diff = bb -> bb_maxima - bb -> bb_count;
459 printf ("%s -- %d item%s unseen\n",
460 bb -> bb_name, diff, plural (diff));
463 if (bb -> bb_maxima == 0)
464 printf ("%s -- empty\n", bb -> bb_name);
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 "));
472 printf ("%s -- %d item%s (all seen)\n",
473 bb -> bb_name, bb -> bb_maxima,
474 plural (bb -> bb_maxima));
476 printf ("%s -- %d item%s unseen\n",
477 bb -> bb_name, diff, plural (diff));
491 register struct bboard *bb;
493 vec[0] = r1bindex (mshproc, '/');
495 tstat = signal (SIGTSTP, tstpser);
498 for (bb = bbl; bb && !quitting; bb = bb -> bb_link) {
499 diff = bb -> bb_maxima - bb -> bb_count;
500 if (bb -> bb_maxima == 0) {
502 printf ("%s -- empty\n", bb -> bb_name);
508 "Oops! looks like someone reset %s -- assuming all unseen\n",
510 diff = bb -> bb_maxima;
513 if (verbosw || archivesw || diff > 0)
514 bbread (bb, vecp, vec);
517 printf ("%s -- %d item%s (all seen)\n",
518 bb -> bb_name, bb -> bb_maxima,
519 plural (bb -> bb_maxima));
524 (void) signal (SIGTSTP, tstat);
543 bbread (bb, vecp, vec)
544 register struct bboard *bb;
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);
568 if (pop_stat (&nmsgs, &nbytes) == NOTOK)
569 adios (NULLCP, "%s", response);
572 printf ("%s -- empty\n", bb -> bb_name);
575 if (pop_fd (buf4, buf5) == NOTOK)
576 adios (NULLCP, "%s", response);
580 if (stat (archivesw ? bb -> bb_archive : bb -> bb_file, &st) != NOTOK
585 if (pipe (pd) == NOTOK)
586 adios ("pipe", "unable to");
587 (void) sprintf (buf3, "%d", getpid ());
590 switch (child_id = fork ()) {
592 adios ("fork", "unable to");
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";
603 vec[vecp++] = "-idstop";
605 vec[vecp++] = "-idquit";
609 if (bb -> bb_flags & BB_REMOTE) {
610 vec[vecp++] = "-popread";
612 vec[vecp++] = "-popwrite";
616 vec[vecp++] = archivesw ? bb -> bb_archive : bb -> bb_file;
618 execvp (mshproc, vec);
619 fprintf (stderr, "unable to exec ");
628 (void) close (pd[1]);
629 pgmread (pd[0], child_id, bb);
632 (void) pidXwait (child_id, mshproc);
638 pgmread (pd, child_id, bb)
641 register struct bboard *bb;
646 TYPESIG (*estat) (), (*hstat) (), (*istat) (), (*qstat) (), (*tstat) ();
648 struct bbcount *selected;
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);
656 while ((n = read (pd, buffer, sizeof buffer)) == NOTOK && errno == EINTR)
659 (void) pidXwait (child_id, mshproc);
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);
669 if (sscanf (buffer, "%d %d", &i, &j) != 2 || i <= 0 || j <= 0)
672 if ((selected = seek_count (bbc, bb -> bb_name)) == NULL) {
673 bbc = add_count (bbc, bb -> bb_name, i);
678 if (i > selected -> count) {
679 selected -> count = i;
684 if (bb -> bb_maxima > j && i >= j)/* bbl... */
686 if (i != selected -> count) {
687 selected -> count = i;
700 (void) signal (i, sigser);
711 static int armed = 0;
714 (void) signal (i, hupser);
717 if (!armed++) /* tick tock... */
718 alarm ((unsigned int) 30);
732 if ((cp = rc ? rc : getenv ("MHBBRC")) && *cp) {
733 rcfile = path (cp, TFILE);
735 (void) m_putenv ("MHBBRC", rcfile);
738 rcfile = concat (mypath, "/", RCFILE, NULLCP);
740 if ((bbrc = fopen (rcfile, "r")) == NULL)
742 adios (rcfile, "unable to read");
746 for (state = FLD;;) {
747 switch (state = m_getfld (state, key, value, sizeof value, bbrc)) {
750 make_lower (key, key);
751 bbc = add_count (bbc, key, atoi (value));
757 admonish (NULLCP, "bad format: %s", rcfile);
765 if (ferror (bbrc) && !feof (bbrc))
766 admonish (rcfile, "error reading");
767 (void) fclose (bbrc);
773 TYPESIG (*hstat) (), (*istat) (), (*qstat) (), (*tstat) ();
779 hstat = signal (SIGHUP, SIG_IGN);
780 istat = signal (SIGINT, SIG_IGN);
781 qstat = signal (SIGQUIT, SIG_IGN);
782 tstat = signal (SIGTERM, SIG_IGN);
784 if ((bbrc = fopen (rcfile, "w")) == NULL)
785 adios (rcfile, "unable to write");
789 adios (rcfile, "error writing");
790 (void) fclose (bbrc);
792 (void) signal (SIGHUP, hstat);
793 (void) signal (SIGINT, istat);
794 (void) signal (SIGQUIT, qstat);
795 (void) signal (SIGTERM, tstat);
803 register struct bbcount *p;
808 fprintf (bbrc, "%s: %d\n", p -> key, p -> count);
809 rcput (bbrc, p -> left);
810 rcput (bbrc, p -> right);
816 static TYPESIG tstpser (sig)
820 #if defined(BSD42) && !defined(WAITINT)
829 waitpid(tstpid, &w, WUNTRACED);
831 while ((pid = wait3 (&w, WUNTRACED, (struct rusage *) 0)) != NOTOK
836 (void) signal (SIGTSTP, SIG_DFL);
838 (void) sigsetmask (sigblock (0) & ~sigmask (SIGTSTP));
841 (void) kill (getpid (), sig);
844 (void) sigblock (sigmask (SIGTSTP));
846 (void) signal (SIGTSTP, tstpser);
851 static void bbreset (bb, i)
852 register struct bboard *bb;
855 struct bbcount *selected;
858 if ((selected = seek_count (bbc, bb -> bb_name)) == NULL)
859 bbc = add_count (bbc, bb -> bb_name, i);
861 selected -> count = i;
866 struct bbcount *add_count (p, w, i)
867 register struct bbcount *p;
874 p = (struct bbcount *) malloc (sizeof *p);
876 adios (NULLCP,"insufficient memory");
877 p -> key = getcpy (w);
879 p -> left = p -> right = NULL;
882 if ((cond = strcmp (w, p -> key)) < 0)
883 p -> left = add_count (p -> left, w, i);
886 p -> right = add_count (p -> right, w, i);
892 struct bbcount *seek_count (p, w)
893 register struct bbcount *p;
898 if (p == NULL || (cond = strcmp (w, p -> key)) == 0)
901 return seek_count (cond < 0 ? p -> left : p -> right, w);
910 register int i = bbp;
916 if (!archivesw && ((cp = m_find ("bboards")) != NULL)) {
918 for (ap = brkstring (cp = getcpy (cp), " ", "\n"); *ap; ap++)
920 for (ap = getip (cp); *ap; ap++)
928 add_bb (bbs[i++], OK);
934 advise (NULLCP, "please fix the %s: entry in your %s file",
935 "bboards", mh_profile);
939 bbs[bbp++] = "system";
943 add_bb ("system", NOTOK);
945 add_bb ("general", NOTOK);
947 add_bb ("ics.system", NOTOK);
948 add_bb ("ics.general", NOTOK);
966 register struct bboard *bb;
967 static struct bboard *tail = NULL;
970 if ((bb = getbbaux (s)) == NULL)
974 adios (NULLCP, "no such bboard as '%s'", s);
976 if (bb -> bb_flags & BB_SEEN) {
978 admonish (NULLCP, "duplicate bboard '%s'", s);
983 bb -> bb_flags |= BB_SEEN;
986 tail -> bb_link = bb;
995 static struct bboard *Bhead = NULL;
996 static struct bboard *Btail = NULL;
1003 register struct bboard *bb;
1005 if (sscanf (s, "%s %d", name, &maxima) != 2)
1006 adios (NULLCP, "XTND2 botch: %s", s);
1008 if ((bb = (struct bboard *) calloc (1, sizeof *bb)) == NULL)
1009 adios (NULLCP, "insufficient memory");
1010 bb -> bb_name = getcpy (name);
1012 if (index(name, '.')) {
1014 bb -> bb_aka = getip (name);
1015 for (cp = *bb -> bb_aka; *cp; cp++)
1020 if ((bb -> bb_aka = (char **) calloc (1, sizeof *bb -> bb_aka)) == NULL)
1021 adios (NULLCP, "insufficient memory");
1022 *bb -> bb_aka = NULL;
1026 bb -> bb_file = bb -> bb_archive = bb -> bb_info = bb -> bb_map = "";
1027 bb -> bb_passwd = "";
1029 if ((bb -> bb_leader = (char **) calloc (1, sizeof *bb -> bb_leader))
1031 adios (NULLCP, "insufficient memory");
1032 *bb -> bb_leader = NULL;
1034 bb -> bb_leader = getip ("usenet");
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;
1042 bb -> bb_maxima = maxima;
1044 bb -> bb_next = bb -> bb_link = bb -> bb_chain = NULL;
1047 Btail -> bb_chain = bb;
1057 static int xtnd3 (s)
1060 static int bbs_int = 0;
1061 static struct bboard *bb;
1063 switch (bbs_int++) {
1065 for (bb = Bhead; bb; bb = bb -> bb_chain)
1066 if (strcmp (bb -> bb_name, s) == 0)
1069 adios (NULLCP, "XTND3 botch");
1071 free (bb -> bb_name);
1072 bb -> bb_name = getcpy (s);
1076 free ((char *) bb -> bb_aka);
1077 bb -> bb_aka = getip (s);
1080 bb -> bb_file = getcpy (s);
1083 bb -> bb_archive = getcpy (s);
1086 bb -> bb_info = getcpy (s);
1089 bb -> bb_map = getcpy (s);
1092 bb -> bb_passwd = getcpy (s);
1095 if (bb -> bb_leader)
1096 free ((char *) bb -> bb_leader);
1097 bb -> bb_leader = getip (s);
1100 bb -> bb_addr = getcpy (s);
1103 bb -> bb_request = getcpy (s);
1106 bb -> bb_relay = getcpy (s);
1110 free ((char *) bb -> bb_dist);
1111 bb -> bb_dist = getip (s);
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;
1119 bb -> bb_date = getcpy (s);
1128 static char **getip (s)
1135 for (p = ap = brkstring (getcpy (s), " ", "\n"); *p; p++)
1138 q = (char **) calloc ((unsigned) (p - ap + 1), sizeof *q);
1140 adios (NULLCP, "insufficient memory");
1142 for (p = ap, ap = q; *p; *q++ = *p++)
1151 static struct bboard *rover = NULL;
1153 struct bboard *getbbpop () {
1157 register struct bboard *bb;
1159 if (didpop != NOTOK && ((bb = getbbent ()) || !host))
1162 if (Bhead == NULL) {
1163 snoop = (cp = getenv ("MHPOPDEBUG")) && *cp;
1170 if (strcmp (user, popbbuser) == 0)
1173 ruserpass (host, &user, &pass);
1174 if (didpop != NOTOK)
1177 if (pop_init (host, user, pass, snoop, rpop) == NOTOK)
1178 adios (NULLCP, "%s", response);
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);
1191 rover = rover -> bb_chain;
1195 #define getbbent getbbpop
1200 struct bboard *getbbaux (s)
1204 int nlatch = host ? 1 : 0;
1207 register struct bbcount *selected;
1208 register struct bboard *bb;
1209 static struct bboard *head = NULL,
1212 for (bb = head; bb; bb = bb -> bb_next) {
1213 if (strcmp (bb -> bb_name, s) == 0)
1215 for (ap = bb -> bb_aka; *ap; ap++)
1216 if (strcmp (*ap, s) == 0)
1223 while (bb = getbbent ()) {
1224 if ((selected = seek_count (bbc, bb -> bb_name)) != NULL)
1225 bb -> bb_count = selected -> count;
1228 if (!(bb -> bb_flags & BB_REMOTE))
1230 if ((bb = getbbcpy (bb)) == NULL)
1231 adios (NULLCP, "insufficient memory");
1233 tail -> bb_next = bb;
1238 if (strcmp (bb -> bb_name, s) == 0) {
1240 bb -> bb_flags &= ~BB_SEEN;
1243 for (ap = bb -> bb_aka; *ap; ap++)
1244 if (strcmp (*ap, s) == 0)
1249 if (nlatch && pop_xtnd (xtnd2, "bboards %s", s) != NOTOK) {
1260 struct bboard *getbbvis () {
1261 register struct bboard *bb;
1263 while (bb = getbbent ())
1264 if (!(bb -> bb_flags & BB_INVIS)
1265 && (access (bb -> bb_file, 04) != NOTOK || errno != EACCES))