Import a copy of Markus Schnalke's master's thesis: The Modern Mail Handler.
[mmh] / docs / historical / mh-6.8.5 / uip / sbboards.c
1 #ifndef SPOP
2 /* sbboards.c - MH style mailer to write to a ZOTnet BBoard */
3 #else   SPOP
4 /* spop.c - MH style mailer to write to a POP subscriber */
5 #endif  SPOP
6 #ifndef lint
7 static char ident[] = "@(#)$Id: sbboards.c,v 1.9 1993/08/25 17:27:54 jromine Exp $";
8 #endif  lint
9
10 #ifndef SPOP
11
12 /* This program acts like the MMDF ch_bboards channel: it does local
13    delivery to a ZOTnet BBoard and/or addition re-distribution to other
14    recipients of the BBoard.  This program can function both as a SendMail
15    mailer and an MH .mh_receive file, depending on whether SENDMTS or
16    MHMTS is set.  Currently, the MHMTS version of this program does not do
17    re-distribution.
18
19    This program should be used ONLY if you have "bboards on" set in your
20    MH configuration, and if you have "mts sendmail" or "mts mh" set as well.
21  */
22
23 #else   SPOP
24
25 /* This program acts like the MMDF-II ch_pop channel: it does local
26    delivery for non-local users.  These users are known as POP subscribers
27    and use the Post Office Protocol with a POP server in order to access
28    their maildrop.
29  */
30
31 #endif  SPOP
32
33 #undef  DISTRIBUTE
34 #ifdef  SENDMTS
35 #ifndef SPOP
36 #define DISTRIBUTE
37 #endif  not SPOP
38 #endif  SENDMTS
39
40 #include "../h/mh.h"
41 #ifndef SPOP
42 #include "../h/addrsbr.h"
43 #endif  not SPOP
44 #include "../h/dropsbr.h"
45 #include "../zotnet/bboards.h"
46 #include "../zotnet/tws.h"
47 #include <stdio.h>
48 #include "../zotnet/mts.h"
49 #include <pwd.h>
50 #ifndef SYS5
51 #include <sysexits.h>
52 #else   SYS5
53 #define EX_CANTCREAT    1
54 #define EX_IOERR        1
55 #define EX_NOINPUT      1
56 #define EX_NOUSER       1
57 #define EX_OK           0
58 #define EX_OSERR        1
59 #define EX_OSFILE       1
60 #define EX_UNAVAILABLE  1
61 #define EX_USAGE        1
62 #endif  SYS5
63 #ifdef  DISTRIBUTE
64 #include "../mts/sendmail/smail.h"
65 #endif  DISTRIBUTE
66 #ifdef LOCALE
67 #include        <locale.h>
68 #endif
69
70
71 #define NBB     100
72
73 #ifndef SPOP
74 #define ENTITY  "bboard"
75 #else   SPOP
76 #define ENTITY  "subscriber"
77 #endif  SPOP
78
79 /* \f */
80
81 static int  bb_fderr;
82
83 static int  bb_uid;
84 static int  bb_gid;
85
86 static int    dst_rcpt ();
87
88
89 #ifndef SPOP
90 static char bb_from[BUFSIZ];
91 static char bb_head[BUFSIZ];
92 static char bb_home[BUFSIZ];
93 static char bb_time[BUFSIZ];
94 #ifdef  DISTRIBUTE
95 static char bb_rept[BUFSIZ];
96 #endif  DISTRIBUTE
97 #else   SPOP
98 #define bb_head NULLCP
99 #endif  SPOP
100
101 static struct bboard  *bb[NBB];
102
103
104 off_t   lseek ();
105
106 #ifndef __STDC__
107 #ifdef  SYS5
108 struct passwd  *getpwnam ();
109 #endif  /* SYS5 */
110 #endif
111
112 #ifndef SPOP
113 static int      mbx_init();
114 #endif
115 #ifdef  DISTRIBUTE
116 static int      distribute(), notify(), encap(),
117                 dst_init(), dst_text(),
118                 dst_end(), dst_lose(), dst_adrs();
119 #endif
120
121 /* hack */
122 #define adios   my_adios
123 static  localmail(), arginit();
124 static int      lose(), copyfile();
125 static void     adios();
126 /* \f */
127
128 /* ARGSUSED */
129
130 main (argc, argv, envp)
131 int     argc;
132 char  **argv,
133       **envp;
134 {
135     int     fd;
136     char    tmpfil[BUFSIZ];
137
138 #ifdef LOCALE
139         setlocale(LC_ALL, "");
140 #endif
141 #ifdef  MHMTS
142     if (argc != 5)
143         adios (EX_USAGE, NULL, "you lose really big");
144 #endif  MHMTS
145     arginit (argv);
146
147     fflush (stdout);
148     discard (stdout);           /* XXX: reference discard to help loader */
149
150     fd = copyfile (fileno (stdin), tmpfil);
151     (void) unlink (tmpfil);
152
153     localmail (fd);
154 #ifdef  DISTRIBUTE
155     distribute (fd);
156     notify (fd);
157 #endif  DISTRIBUTE
158
159     exit (EX_OK);
160 }
161
162 /* \f */
163
164 static  localmail (fd)
165 int     fd;
166 {
167     int     i,
168             md;
169     register struct bboard  *bp;
170
171     for (i = 0; bp = bb[i]; i++)
172         if (bp -> bb_file && *bp -> bb_file) {
173             (void) lseek (fd, (off_t)0, 0);
174 #ifndef SPOP
175             if ((md = mbx_open (bp -> bb_file, bb_uid, bb_gid, BBMODE))
176 #else   SPOP
177             if ((md = mbx_open (bp -> bb_file, bb_uid, bb_gid, POMODE))
178 #endif  SPOP
179                     == NOTOK) {
180                 (void) lose ("unable to open %s", bp -> bb_file);
181                 continue;
182             }
183 #ifndef SPOP
184             if (mbx_init (bp) != NOTOK)
185 #endif  not SPOP
186                 (void) mbx_copy (bp -> bb_file, md, fd, 1, bb_head, 0);
187             (void) mbx_close (bp -> bb_file, md);
188         }
189 }
190
191 /* \f */
192
193 #ifndef SPOP
194 static int  mbx_init (bp)
195 register struct bboard  *bp;
196 {
197     int     fd,
198             clear;
199     register struct bboard  *ip;
200     register FILE *fp;
201
202     if ((fd = mbx_Xopen (bp -> bb_info, bb_uid, bb_gid, BBMODE, &clear))
203             == NOTOK)
204         return lose ("unable to lock and open %s", bp -> bb_info);
205     if ((fp = fdopen (fd, "w")) == NULL) {
206         (void) mbx_close (bp -> bb_info, fd);
207         return lose ("unable to fdopen %s", bp -> bb_info);
208     }
209
210     if ((ip = getbbnam (bp -> bb_name)) == NULL) {
211         (void) lkfclose (fp, bp -> bb_info);
212         return lose ("unable to get information on BBoard %s", bp -> bb_name);
213     }
214     (void) strcpy (bb_time, dtimenow ());
215     (void) sprintf (bb_head, "BBoard-ID: %d\nBB-Posted: %s\n",
216             bp -> bb_maxima = ++ip -> bb_maxima, bb_time);
217
218     fprintf (fp, "%d\n%s\n", bp -> bb_maxima, bb_time);
219     (void) lkfclose (fp, bp -> bb_info);
220
221     return OK;
222 }
223 #endif  not SPOP
224
225 /* \f */
226
227 #ifdef  DISTRIBUTE
228 static  distribute (fd)
229 int     fd;
230 {
231     int     i;
232     register struct bboard  *bp;
233
234     for (i = 0; bp = bb[i]; i++)
235         if (bp -> bb_dist && *bp -> bb_dist)
236             break;
237     if (bp == NULL)
238         return;
239
240     if (dst_init () == NOTOK) {
241         dst_lose ();
242         return;
243     }
244     for (i = 0; bp = bb[i]; i++)
245         if (bp -> bb_dist && *bp -> bb_dist)
246             if (dst_adrs (bp) == NOTOK) {
247                 dst_lose ();
248                 return;
249             }
250     if (dst_text (fd) == NOTOK || dst_end () == NOTOK)
251         dst_lose ();
252 }
253
254 /* \f */
255
256 static int  dst_init ()
257 {
258     int     retval;
259
260     if (rp_isbad (retval = sm_init (NULLCP, NULLCP, 0, 0, 0, 0, 0))
261             || rp_isbad (retval = sm_winit (S_MAIL, bb_from)))
262         return lose ("problem initializing SendMail; %s",
263                 rp_string (retval));
264
265     return OK;
266 }
267
268 /* \f */
269
270 static int  dst_adrs (bp)
271 register struct bboard  *bp;
272 {
273     if (getbbdist (bp, dst_rcpt))
274         return lose ("getbbdist failed: %s", getbberr ());
275
276     return OK;
277 }
278
279 /* \f */
280
281 static int  dst_rcpt (mbox, host)
282 register char   *mbox,
283                 *host;
284 {
285     int     retval;
286
287     switch (retval = sm_wadr (mbox, host, NULLCP)) {
288         case RP_OK:
289             return OK;
290
291         case RP_NO:
292         case RP_USER:
293             (void) lose ("%s@%s: loses; %s", mbox, host, rp_string (retval));
294             return OK;          /* fail-soft */
295
296         default:
297             return lose ("%s@%s: unexpected response; %s",
298                     mbox, host, rp_string (retval));
299     }
300 }
301
302 /* \f */
303
304 static int  dst_text (fd)
305 int     fd;
306 {
307     int     i,
308             retval;
309     char    buffer[BUFSIZ];
310
311     if (rp_isbad (retval = sm_waend ()))
312         return lose ("problem ending addresses; %s", rp_string (retval));
313
314     (void) lseek (fd, (off_t)0, 0);
315     while ((i = read (fd, buffer, sizeof buffer)) > 0)
316         if (rp_isbad (retval = sm_wtxt (buffer, i)))
317             return lose ("problem writing text; %s", rp_string (retval));
318
319     return (i != NOTOK ? OK : lose ("error reading from file"));
320 }
321
322 /* \f */
323
324 static int  dst_end ()
325 {
326     int     retval;
327
328     switch (retval = sm_wtend ()) {
329         case RP_OK:
330             (void) sm_end (OK);
331             return OK;
332
333         case RP_NO:
334         case RP_NDEL:
335             return lose ("posting failed; %s", rp_string (retval));
336
337         default:
338             return lose ("unexpected response; %s", rp_string (retval));
339     }
340 }
341
342 /* \f */
343
344 static  dst_lose ()
345 {
346     (void) sm_end (NOTOK);
347 }
348
349 /* \f */
350
351 /* VARARGS1 */
352
353 static int  lose (fmt, a, b, c, d)
354 char   *fmt,
355        *a,
356        *b,
357        *c,
358        *d;
359 {
360     int     fd,
361             i;
362     char   *bp,
363             buffer[BUFSIZ];
364
365     if (bb_fderr == NOTOK) {
366         if ((fd = open ("/dev/null", 0)) == NOTOK)
367             adios (EX_OSERR, "/dev/null", "unable to open");
368         bb_fderr = copyfile (fd, bb_rept);
369     }
370
371     (void) sprintf (bp = buffer, fmt, a, b, c, d);
372     bp += strlen (bp);
373     bp += strlen (strcpy(bp, "\n"));
374     i = bp - buffer;
375     if (write (bb_fderr, buffer, i) != i)
376         adios (EX_IOERR, bb_rept, "error writing");
377
378     return NOTOK;
379 }
380
381 /* \f */
382
383 static  notify (fd)
384 int     fd;
385 {
386     int     i;
387     char    buffer[BUFSIZ];
388
389     if (bb_fderr == NOTOK)
390         return;
391
392     if (rp_isbad (sm_init (NULLCP, NULLCP, 0, 0, 0, 0, 0))
393             || rp_isbad (sm_winit (S_MAIL, bb_from)))
394         goto sm_err;
395
396     switch (sm_wadr (bb_from, NULLCP, NULLCP)) {
397         case RP_OK:
398             for (i = 0; bb[i]; i++) {
399                 (void) sprintf (buffer, "local-%s-request", bb[i] -> bb_name);
400                 (void) sm_wadr (buffer, LocalName (), NULLCP);
401             }
402             break;
403
404         default:
405             goto sm_err;
406     }
407
408     if (rp_isbad (sm_waend ()))
409         goto sm_err;
410
411     (void) sprintf (buffer,
412             "Date: %s\nFrom: %s\nTo: %s\nSubject: BBoards Failure\n\n",
413             dtimenow (), bb_from, bb_from);
414     if (rp_isbad (sm_wtxt (buffer, strlen (buffer))))
415         goto sm_err;
416
417     for (i = 0; bb[i]; i++) {
418         (void) sprintf (buffer, "BBoard %s\n", bb[i] -> bb_name);
419         if (rp_isbad (sm_wtxt (buffer, strlen (buffer))))
420             goto sm_err;
421     }
422
423     (void) lseek (bb_fderr, (off_t)0, 0);
424     while ((i = read (bb_fderr, buffer, sizeof buffer)) > 0)
425         if (rp_isbad (sm_wtxt (buffer, i)))
426             goto sm_err;
427
428     (void) strcpy (buffer, "\n------- Forwarded Message\n\n");
429     if (rp_isbad (sm_wtxt (buffer, strlen (buffer))) || encap (fd) == NOTOK)
430         goto sm_err;
431     (void) strcpy (buffer, "\n------- End of Forwarded Message\n\n");
432     if (rp_isbad (sm_wtxt (buffer, strlen (buffer))))
433         goto sm_err;
434
435     switch (sm_wtend ()) {
436         case RP_OK:
437             (void) unlink (bb_rept);
438             (void) sm_end (OK);
439             return;
440
441         default:
442     sm_err: ;
443             adios (EX_UNAVAILABLE, NULLCP,
444                     "failed and unable to post advisory, see %s for details",
445                     bb_rept);
446     }
447 }
448
449 /* \f */
450
451 /* very similar to sbr/cpydgst.c */
452
453 #define S1      0
454 #define S2      1
455
456 #define output(c)       if (bp >= dp) flush (), *bp++ = c; else *bp++ = c
457 #define flush()         if ((j = bp - outbuf) \
458                                 && rp_isbad (sm_wtxt (outbuf, j))) \
459                             return NOTOK; \
460                         else \
461                             bp = outbuf
462
463 static int  encap (fd)
464 register int    fd;
465 {
466     register int    i,
467                     state;
468     register char  *cp,
469                    *ep;
470     char    buffer[BUFSIZ];
471     register int    j;
472     register char  *bp,
473                    *dp;
474     char    outbuf[BUFSIZ];
475
476     (void) lseek (fd, (off_t)0, 0);
477
478     dp = (bp = outbuf) + sizeof outbuf;
479     for (state = S1; (i = read (fd, buffer, sizeof buffer)) > 0;)
480         for (ep = (cp = buffer) + i; cp < ep; cp++) {
481             if (*cp == NULL)
482                 continue;
483             switch (state) {
484                 case S1: 
485                     if (*cp == '-') {
486                         output ('-');
487                         output (' ');
488                     }
489                     state = S2; /* fall */
490
491                 case S2: 
492                     output (*cp);
493                     if (*cp == '\n')
494                         state = S1;
495                     break;
496             }
497         }
498
499     if (i == NOTOK)
500         return NOTOK;
501     flush ();
502
503     return OK;
504 }
505 #endif  DISTRIBUTE
506
507 /* \f */
508
509 #ifndef DISTRIBUTE
510 /* VARARGS1 */
511
512 static int  lose (fmt, a, b, c, d)
513 char   *fmt,
514        *a,
515        *b,
516        *c,
517        *d;
518 {
519     adios (EX_UNAVAILABLE, NULLCP, fmt, a, b, c, d);/* NOTREACHED */
520 }
521 #endif  not DISTRIBUTE
522
523 /* \f */
524
525 static  arginit (vec)
526 register char  **vec;
527 {
528     register int    i;
529 #ifdef  MHMTS
530     register char  *ap;
531 #endif  MHMTS
532     char    addr[BUFSIZ];
533     register struct bboard *bp;
534     register struct passwd *pw;
535
536     invo_name = r1bindex (*vec++, '/');
537     m_foil (NULLCP);
538     mts_init (invo_name);
539
540 #ifndef SPOP
541     if ((pw = getpwnam (BBOARDS)) == NULL)
542         adios (EX_OSFILE, NULLCP, "no entry for ~%s", BBOARDS);
543 #else   SPOP
544     if ((pw = getpwnam (POPUID)) == NULL || !setpwinfo (pw, POPDB, 1))
545         adios (EX_OSFILE, NULLCP, "%s", pw ? getbberr () : "POP user-id unknown");
546 #endif  SPOP
547
548     if (pw -> pw_uid != geteuid ())
549 #ifndef SPOP
550     adios (EX_OSERR, NULLCP, "not running setuid to %s", BBOARDS);
551 #else   SPOP
552     adios (EX_OSERR, NULLCP, "not running setuid to %s", POPUID);
553 #endif  SPOP
554
555     bb_uid = pw -> pw_uid;
556     bb_gid = pw -> pw_gid;
557 #ifndef SPOP
558     (void) strcpy (bb_from, adrsprintf (pw -> pw_name, LocalName ()));
559     (void) strcpy (bb_home, pw -> pw_dir);
560 #endif  not SPOP
561
562 #ifdef  MHMTS
563     vec += 3;
564 #endif  MHMTS
565     if (*vec == NULL)
566         adios (EX_USAGE, NULLCP, "usage: %s %s [%s ...]",
567                 invo_name, ENTITY, ENTITY);
568
569     for (i = 0; *vec; vec++) {
570 #ifdef  MHMTS
571         if (ap = index (*vec, '.'))
572             *vec = ++ap;
573 #endif  MHMTS
574         make_lower (addr, *vec);
575
576         if ((bp = getbbnam (addr)) == NULL
577                 && (bp = getbbaka (addr)) == NULL)
578             adios (EX_NOUSER, NULLCP, "no such %s as %s", ENTITY, *vec);
579         if ((bb[i++] = getbbcpy (bp)) == NULL)
580             adios (EX_UNAVAILABLE, NULLCP, "insufficient memory on %s", *vec);
581
582         if (i >= NBB - 1)
583             adios (EX_USAGE, NULLCP, "too many %ss, starting with %s",
584                     ENTITY, *vec);
585     }
586     bb[i] = NULL;
587
588     (void) umask (0022);
589
590     bb_fderr = NOTOK;
591 }
592
593 /* \f */
594
595 static int  copyfile (qd, tmpfil)
596 int     qd;
597 register char   *tmpfil;
598 {
599     int     i,
600             fd;
601     char    buffer[BUFSIZ];
602
603     (void) strcpy (tmpfil, m_tmpfil (invo_name));
604     if ((fd = creat (tmpfil, 0600)) == NOTOK)
605         adios (EX_CANTCREAT, tmpfil, "unable to create");
606     (void) close (fd);
607     if ((fd = open (tmpfil, 2)) == NOTOK)
608         adios (EX_NOINPUT, tmpfil, "unable to re-open");
609
610     (void) lseek (qd, (off_t)0, 0);
611     while ((i = read (qd, buffer, sizeof buffer)) > 0)
612         if (write (fd, buffer, i) != i)
613             adios (EX_IOERR, tmpfil, "error writing");
614     if (i == NOTOK)
615         adios (EX_IOERR, "input", "error reading");
616
617     (void) lseek (fd, (off_t)0, 0);
618
619     return fd;
620 }
621
622 /* \f */
623
624 /* VARARGS3 */
625
626 #ifdef  MHMTS
627 /* ARGSUSED */
628 #endif  MHMTS
629
630 static  void adios (code, what, fmt, a, b, c, d, e, f)
631 int     code;
632 char   *what,
633        *fmt,
634        *a,
635        *b,
636        *c,
637        *d,
638        *e,
639        *f;
640 {
641     advise (what, fmt, a, b, c, d, e, f);
642 #ifdef  SENDMTS
643     done (code);
644 #endif  SENDMTS
645 #ifdef  MHMTS
646     done (1);
647 #endif  MHMTS
648 }