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