Initial revision
[mmh] / zotnet / bboards / getbbent.c
1
2 /*
3  * getbbent.c -- subroutines for accessing the BBoards file
4  *
5  * $Id$
6  */
7
8 #include <h/nmh.h>
9
10 #ifdef MMDFONLY
11 # include <util.h>
12 # include <mmdf.h>
13 # include <strings.h>
14 #endif  /* MMDFONLY */
15
16 #include <pwd.h>
17 #include <grp.h>
18 #include <bboards.h>
19
20 #ifdef HAVE_CRYPT_H
21 # include <crypt.h>
22 #endif
23
24 #ifdef HAVE_UNISTD_H
25 # include <unistd.h>
26 #endif
27
28 #ifndef MMDFONLY
29 # define NOTOK  (-1)
30 # define OK     0
31 #endif
32
33 #define MaxBBAka  100
34 #define MaxBBLdr  100
35 #define MaxBBDist 100
36
37 #define NCOLON  9               /* currently 10 fields per entry */
38
39 #define COLON   ':'
40 #define COMMA   ','
41 #define NEWLINE '\n'
42
43 #define ARCHIVE "archive"
44 #define CNTFILE ".cnt"
45 #define DSTFILE ".dist"
46 #define MAPFILE ".map"
47
48 static int BBuid = -1;
49
50 static unsigned int BBflags = SB_NULL;
51
52 static char BBName[BUFSIZ] = BBOARDS;
53 static char BBDir[BUFSIZ] = "";
54 static char BBData[BUFSIZ] = "";
55
56 static FILE *BBfile = NULL;
57
58 static struct bboard BB;
59 static struct bboard *bb = &BB;
60
61 static int BBload = 1;
62
63 static char BBFile[BUFSIZ];
64 static char BBArchive[BUFSIZ];
65 static char BBInfo[BUFSIZ];
66 static char BBMap[BUFSIZ];
67 static char *BBAkas[MaxBBAka];
68 static char *BBLeaders[MaxBBLdr];
69 static char *BBDists[MaxBBDist];
70 static char BBAddr[BUFSIZ];
71 static char BBRequest[BUFSIZ];
72 static char BBDate[BUFSIZ];
73 static char BBErrors[BUFSIZ];
74
75 #ifdef MMDFONLY
76 extern LLog *logptr;
77 #endif
78
79 #ifdef UCL
80 int called_bbc = 0;
81 char *bbs[101];
82 #endif
83
84
85 /*
86  * static prototypes
87  */
88 static int setbbaux (char *, char *);
89 static int setpwaux (struct passwd *, char *);
90 static void BBread (void);
91 static int getbbitem (struct bboard *, char *, int (*)());
92 static int  bblose (char *, ...);
93 static char *bbskip (char *, char);
94 static char *getcpy (char *);
95
96
97 int
98 setbbfile (char *file, int f)
99 {
100     if (BBuid == -1)
101         return setbbinfo (BBOARDS, file, f);
102
103     strncpy (BBData, file, sizeof(BBData));
104
105     BBflags = SB_NULL;
106     endbbent ();
107
108     return setbbent (f);
109 }
110
111
112 int
113 setbbinfo (char *user, char *file, int f)
114 {
115     register struct passwd *pw;
116
117     if ((pw = getpwnam (user)) == NULL) {
118         snprintf (BBErrors, sizeof(BBErrors), "unknown user: %s", user);
119         return 0;
120     }
121
122     return setpwinfo (pw, file, f);
123 }
124
125
126 int
127 setpwinfo (struct passwd *pw, char *file, int f)
128 {
129     if (!setpwaux (pw, file))
130         return 0;
131
132     BBflags = SB_NULL;
133     endbbent ();
134
135     return setbbent (f);
136 }
137
138
139 static int
140 setbbaux (char *name, char *file)
141 {
142     register struct passwd *pw;
143
144     if ((pw = getpwnam (name)) == NULL) {
145         snprintf (BBErrors, sizeof(BBErrors), "unknown user: %s", name);
146         return 0;
147     }
148
149     return setpwaux (pw, file);
150 }
151
152
153 static int
154 setpwaux (struct passwd *pw, char *file)
155 {
156     strncpy (BBName, pw->pw_name, sizeof(BBName));
157     BBuid = pw->pw_uid;
158     strncpy (BBDir, pw->pw_dir, sizeof(BBDir));
159     snprintf (BBData, sizeof(BBData), "%s/%s",
160             *file != '/' ? BBDir : "",
161             *file != '/' ? file : file + 1);
162
163     BBflags = SB_NULL;
164
165     return 1;
166 }
167
168
169 int
170 setbbent (int f)
171 {
172     if (BBfile == NULL) {
173         if (BBuid == -1 && !setbbaux (BBOARDS, BBDB))
174             return 0;
175
176         if ((BBfile = fopen (BBData, "r")) == NULL) {
177             snprintf (BBErrors, sizeof(BBErrors), "unable to open: %s", BBData);
178             return 0;
179         }
180     }
181     else
182         rewind (BBfile);
183
184     BBflags |= f;
185     return (BBfile != NULL);
186 }
187
188
189 int
190 endbbent (void)
191 {
192     if (BBfile != NULL && !(BBflags & SB_STAY)) {
193         fclose (BBfile);
194         BBfile = NULL;
195     }
196
197     return 1;
198 }
199
200
201 long
202 getbbtime (void)
203 {
204     struct stat st;
205
206     if (BBfile == NULL) {
207         if (BBuid == -1 && !setbbaux (BBOARDS, BBDB))
208             return 0;
209
210         if (stat (BBData, &st) == NOTOK) {
211             snprintf (BBErrors, sizeof(BBErrors), "unable to stat: %s", BBData);
212             return 0;
213         }
214     } else {
215         if (fstat (fileno (BBfile), &st) == NOTOK) {
216             snprintf (BBErrors, sizeof(BBErrors), "unable to fstat: %s", BBData);
217             return 0;
218         }
219     }
220
221     return ((long) st.st_mtime);
222 }
223
224
225 struct bboard *
226 getbbent (void)
227 {
228     register int count;
229     register char *p, *q, *r, *d, *f, **s;
230     static char line[BUFSIZ];
231
232     if (BBfile == NULL && !setbbent (SB_NULL))
233         return NULL;
234
235 retry: ;
236     if ((p = fgets (line, sizeof line, BBfile)) == NULL)
237         return NULL;
238
239     for (q = p, count = 0; *q != 0 && *q != NEWLINE; q++)
240         if (*q == COLON)
241             count++;
242
243     if (count != NCOLON) {
244 #ifdef  MMDFONLY
245         if (q = strchr(p, NEWLINE))
246             *q = 0;
247         ll_log (logptr, LLOGTMP, "bad entry in %s: %s", BBData, p);
248 #endif  /* MMDFONLY */
249         goto retry;
250     }
251     
252     bb->bb_name = p;
253     p = q = bbskip (p, COLON);
254     p = bb->bb_file = bbskip (p, COLON);
255     bb->bb_archive = bb->bb_info = bb->bb_map = "";
256     p = bb->bb_passwd = bbskip (p, COLON);
257     p = r = bbskip (p, COLON);
258     p = bb->bb_addr = bbskip (p, COLON);
259     p = bb->bb_request = bbskip (p, COLON);
260     p = bb->bb_relay = bbskip (p, COLON);
261     p = d = bbskip (p, COLON);
262     p = f = bbskip (p, COLON);
263     bbskip (p, NEWLINE);
264
265     s = bb->bb_aka = BBAkas;
266     while (*q) {
267         *s++ = q;
268         q = bbskip (q, COMMA);
269     }
270     *s = 0;
271
272     s = bb->bb_leader = BBLeaders;
273     if (*r == 0) {
274         if (!(BBflags & SB_FAST)) {
275             *s++ = BBName;
276             *s = 0;
277         }
278     }
279     else {
280         while (*r) {
281             *s++ = r;
282             r = bbskip (r, COMMA);
283         }
284         *s = 0;
285     }
286
287     s = bb->bb_dist = BBDists;
288     while (*d) {
289         *s++ = d;
290         d = bbskip (d, COMMA);
291     }
292     *s = 0;
293
294     if (*f)
295         sscanf (f, "%o", &bb->bb_flags);
296     else
297         bb->bb_flags = BB_NULL;
298     bb->bb_count = bb->bb_maxima = 0;
299     bb->bb_date = NULL;
300     bb->bb_next = bb->bb_link = bb->bb_chain = NULL;
301
302 #ifdef UCL
303         /*
304          * Only do a BBread on bboards that the user has expressed an
305          * interest in, if we were called by bbc.
306          */
307     if (BBload) {
308         register char **ap, *cp;
309         register int bbp;
310
311         if (called_bbc == 0)
312                 BBread();
313         else {
314             for (bbp = 0; cp = bbs[bbp]; bbp++) {
315                 if (!strcmp(bb->bb_name, cp)) {
316                         BBread();
317                         break;
318                         }
319                 for (ap = bb->bb_aka; *ap; ap++)
320                         if (!strcmp(*ap, cp)) {
321                                 BBread();
322                                 break;
323                                 }
324                 }
325             }
326         }
327 #else
328     if (BBload)
329         BBread ();
330 #endif
331
332     return bb;
333 }
334
335
336 struct bboard *
337 getbbnam (char *name)
338 {
339     register struct bboard *b = NULL;
340
341     if (!setbbent (SB_NULL))
342         return NULL;
343     BBload = 0;
344     while ((b = getbbent ()) && strcmp (name, b->bb_name))
345         continue;
346     BBload = 1;
347     endbbent ();
348
349     if (b != NULL)
350         BBread ();
351
352     return b;
353 }
354
355
356 struct bboard *
357 getbbaka (char *aka)
358 {
359     register char **ap;
360     register struct bboard *b = NULL;
361
362     if (!setbbent (SB_NULL))
363         return NULL;
364     BBload = 0;
365     while ((b = getbbent ()) != NULL)
366         for (ap = b->bb_aka; *ap; ap++)
367             if (strcmp (aka, *ap) == 0)
368                 goto hit;
369 hit: ;
370     BBload = 1;
371     endbbent ();
372
373     if (b != NULL)
374         BBread ();
375
376     return b;
377 }
378
379
380 static void
381 BBread (void)
382 {
383     register int i;
384     register char *cp, *dp, *p, *r;
385     char prf[BUFSIZ];
386     static char line[BUFSIZ];
387     register FILE * info;
388
389     if (BBflags & SB_FAST)
390         return;
391
392     p = strchr(bb->bb_request, '@');
393     r = strchr(bb->bb_addr, '@');
394     BBRequest[0] = 0;
395
396     if (*bb->bb_request == '-')
397         if (p == NULL && r && *r == '@')
398             snprintf (BBRequest, sizeof(BBRequest), "%s%s%s", bb->bb_name, bb->bb_request, r);
399         else
400             snprintf (BBRequest, sizeof(BBRequest), "%s%s", bb->bb_name, bb->bb_request);
401     else
402         if (p == NULL && r && *r == '@' && *bb->bb_request)
403             snprintf (BBRequest, sizeof(BBRequest), "%s%s", bb->bb_request, r);
404
405     if (BBRequest[0])
406         bb->bb_request = BBRequest;
407     else
408         if (*bb->bb_request == 0)
409             bb->bb_request = *bb->bb_addr ? bb->bb_addr
410                 : bb->bb_leader[0];
411
412     if (*bb->bb_addr == '@') {
413         snprintf (BBAddr, sizeof(BBAddr), "%s%s", bb->bb_name, bb->bb_addr);
414         bb->bb_addr = BBAddr;
415     }
416     else
417         if (*bb->bb_addr == 0)
418             bb->bb_addr = bb->bb_name;
419
420     if (*bb->bb_file == 0)
421         return;
422     if (*bb->bb_file != '/') {
423         snprintf (BBFile, sizeof(BBFile), "%s/%s", BBDir, bb->bb_file);
424         bb->bb_file = BBFile;
425     }
426
427     if ((cp = strrchr(bb->bb_file, '/')) == NULL || *++cp == 0) {
428         strcpy (prf, "");
429         cp = bb->bb_file;
430     } else {
431         snprintf (prf, sizeof(prf), "%.*s", cp - bb->bb_file, bb->bb_file);
432     }
433     if ((dp = strchr(cp, '.')) == NULL)
434         dp = cp + strlen (cp);
435
436     snprintf (BBArchive, sizeof(BBArchive), "%s%s/%s", prf, ARCHIVE, cp);
437     bb->bb_archive = BBArchive;
438     snprintf (BBInfo, sizeof(BBInfo), "%s.%.*s%s", prf, dp - cp, cp, CNTFILE);
439     bb->bb_info = BBInfo;
440     snprintf (BBMap, sizeof(BBMap), "%s.%.*s%s", prf, dp - cp, cp, MAPFILE);
441     bb->bb_map = BBMap;
442
443     if ((info = fopen (bb->bb_info, "r")) == NULL)
444         return;
445
446     if (fgets (line, sizeof line, info) && (i = atoi (line)) > 0)
447         bb->bb_maxima = (unsigned) i;
448     if (!feof (info) && fgets (line, sizeof line, info)) {
449         strncpy (BBDate, line, sizeof(BBData));
450         if ((cp = strchr(BBDate, NEWLINE)))
451             *cp = 0;
452         bb->bb_date = BBDate;
453     }
454
455     fclose (info);
456 }
457
458
459 int
460 ldrbb (struct bboard *b)
461 {
462     register char *p, **q, **r;
463     static uid_t uid = 0;
464     static gid_t gid = 0;
465     static char username[10] = "";
466     register struct passwd *pw;
467     register struct group  *gr;
468
469     if (b == NULL)
470         return 0;
471     if (BBuid == -1 && !setbbaux (BBOARDS, BBDB))
472         return 0;
473
474     if (username[0] == 0) {
475         if ((pw = getpwuid (uid = getuid ())) == NULL)
476             return 0;
477         gid = getgid ();
478         strncpy (username, pw->pw_name, sizeof(username));
479     }
480
481     if (uid == BBuid)
482         return 1;
483
484     q = b->bb_leader;
485     while ((p = *q++))
486         if (*p == '=') {
487             if ((gr = getgrnam (++p)) == NULL)
488                 continue;
489             if (gid == gr->gr_gid)
490                 return 1;
491             r = gr->gr_mem;
492             while ((p = *r++))
493                 if (strcmp (username, p) == 0)
494                     return 1;
495         }
496         else
497             if (strcmp (username, p) == 0)
498                 return 1;
499
500     return 0;
501 }
502
503
504 int
505 ldrchk (struct bboard *b)
506 {
507     if (b == NULL)
508         return 0;
509
510     if (*b->bb_passwd == 0)
511         return 1;
512
513     if (strcmp (b->bb_passwd,
514                 crypt (getpass ("Password: "), b->bb_passwd)) == 0)
515         return 1;
516
517     fprintf (stderr, "Sorry\n");
518     return 0;
519 }
520
521
522 struct bboard *
523 getbbcpy (struct bboard *bp)
524 {
525     register char **p, **q;
526     register struct bboard *b;
527
528     if (bp == NULL)
529         return NULL;
530
531     b = (struct bboard *) malloc ((unsigned) sizeof *b);
532     if (b == NULL)
533         return NULL;
534
535     b->bb_name = getcpy (bp->bb_name);
536     b->bb_file = getcpy (bp->bb_file);
537     b->bb_archive = getcpy (bp->bb_archive);
538     b->bb_info = getcpy (bp->bb_info);
539     b->bb_map = getcpy (bp->bb_map);
540     b->bb_passwd = getcpy (bp->bb_passwd);
541     b->bb_flags = bp->bb_flags;
542     b->bb_count = bp->bb_count;
543     b->bb_maxima = bp->bb_maxima;
544     b->bb_date = getcpy (bp->bb_date);
545     b->bb_addr = getcpy (bp->bb_addr);
546     b->bb_request = getcpy (bp->bb_request);
547     b->bb_relay = getcpy (bp->bb_relay);
548
549     for (p = bp->bb_aka; *p; p++)
550         continue;
551     b->bb_aka =
552         q = (char **) calloc ((unsigned) (p - bp->bb_aka + 1), sizeof *q);
553     if (q == NULL)
554         return NULL;
555     for (p = bp->bb_aka; *p; *q++ = getcpy (*p++))
556         continue;
557     *q = NULL;
558
559     for (p = bp->bb_leader; *p; p++)
560         continue;
561     b->bb_leader =
562         q = (char **) calloc ((unsigned) (p - bp->bb_leader + 1), sizeof *q);
563     if (q == NULL)
564         return NULL;
565     for (p = bp->bb_leader; *p; *q++ = getcpy (*p++))
566         continue;
567     *q = NULL;
568
569     for (p = bp->bb_dist; *p; p++)
570         continue;
571     b->bb_dist = 
572         q = (char **) calloc ((unsigned) (p - bp->bb_dist + 1), sizeof *q);
573     if (q == NULL)
574         return NULL;
575     for (p = bp->bb_dist; *p; *q++ = getcpy (*p++))
576         continue;
577     *q = NULL;
578
579     b->bb_next = bp->bb_next;
580     b->bb_link = bp->bb_link;
581     b->bb_chain = bp->bb_chain;
582
583     return b;
584 }
585
586
587 int
588 getbbdist (struct bboard  *bb, int (*action)())
589 {
590     register int result;
591     register char **dp;
592
593     BBErrors[0] = 0;
594     for (dp = bb->bb_dist; *dp; dp++)
595         if ((result = getbbitem (bb, *dp, action)))
596             return result;
597
598     return result;
599 }
600
601 char *
602 getbberr (void)
603 {
604     return (BBErrors[0] ? BBErrors : NULL);
605 }
606
607
608 static int
609 getbbitem (struct bboard *bb, char *item, int (*action)())
610 {
611     register int result;
612     register char *cp, *dp, *hp, *np;
613     char mbox[BUFSIZ],
614          buffer[BUFSIZ],
615          file[BUFSIZ],
616          host[BUFSIZ],
617          prf[BUFSIZ];
618     register FILE *fp;
619
620     switch (*item) {
621         case '*': 
622             switch (*++item) {
623                 case '/': 
624                     hp = item;
625                     break;
626
627                 case 0: 
628                     if ((cp = strrchr(bb->bb_file, '/')) == NULL || *++cp == 0) {
629                         strcpy (prf, "");
630                         cp = bb->bb_file;
631                     } else {
632                         snprintf (prf, sizeof(prf), "%.*s", cp - bb->bb_file, bb->bb_file);
633                     }
634                     if ((dp = strchr(cp, '.')) == NULL)
635                         dp = cp + strlen (cp);
636                     snprintf (file, sizeof(file), "%s.%.*s%s", prf, dp - cp, cp, DSTFILE);
637                     hp = file;
638                     break;
639
640                 default: 
641                     snprintf (file, sizeof(file), "%s/%s", BBDir, item);
642                     hp = file;
643                     break;
644             }
645
646             if ((fp = fopen (hp, "r")) == NULL)
647                 return bblose ("unable to read file %s", hp);
648             while (fgets (buffer, sizeof buffer, fp)) {
649                 if ((np = strchr(buffer, '\n')))
650                     *np = 0;
651                 if ((result = getbbitem (bb, buffer, action))) {
652                     fclose (fp);
653                     bblose ("error with file %s, item %s", hp, buffer);
654                     return result;
655                 }
656             }
657             fclose (fp);
658             return OK;
659
660         default: 
661             if ((hp = strrchr(item, '@'))) {
662                 *hp++ = 0;
663                 strncpy (mbox, item, sizeof(mbox));
664                 strncpy (host, hp, sizeof(host));
665                 *--hp = '@';
666             }
667             else {
668                 snprintf (mbox, sizeof(mbox), "%s%s", DISTADR, bb->bb_name);
669                 strncpy (host, item, sizeof(host));
670             }
671             if ((result = (*action) (mbox, host)))
672                 bblose ("action (%s, %s) returned 0%o", mbox, host, result);
673             return result;
674     }
675 }
676
677
678 static int
679 bblose (char *fmt, ...)
680 {
681     va_list ap;
682
683     va_start(ap, fmt);
684     if (BBErrors[0] == 0)
685         vsnprintf (BBErrors, sizeof(BBErrors), fmt, ap);
686
687     va_end(ap);
688     return NOTOK;
689 }
690
691
692 void
693 make_lower (char *s1, char *s2)
694 {
695     if (!s1 || !s2)
696         return;
697
698     for (; *s2; s2++)
699         *s1++ = isupper (*s2) ? tolower (*s2) : *s2;
700     *s1 = 0;
701 }
702
703
704 static char *
705 bbskip (char *p, char c)
706 {
707     if (p == NULL)
708         return NULL;
709
710     while (*p && *p != c)
711         p++;
712     if (*p)
713         *p++ = 0;
714
715     return p;
716 }
717
718
719 static char *
720 getcpy (char *s)
721 {
722     register char *p;
723     size_t len;
724
725     if (s == NULL)
726         return NULL;
727
728     len = strlen (s) + 1;
729     if ((p = malloc (len)))
730         memcpy (p, s, len);
731     return p;
732 }
733