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