Added all of the MH sources, including RCS files, in
[mmh] / docs / historical / mh-6.8.5 / uip / rmail.c
1 /* rmail.c - replacement for /bin/rmail */
2 #ifndef lint
3 static char ident[] = "@(#)$Id: rmail.c,v 1.3 1993/08/25 17:27:43 jromine Exp $";
4 #endif  lint
5
6 /* This program has a long, long history.  It started as UCB's rmail, and
7    was then modified by OBrien@Rand-Unix to run with MMDF.  Then DpK@Brl
8    re-wrote it, and SmB@Unc hacked it up a bit.  After that
9    MRose.UCI@Rand-Relay upgraded it to use the nifty MF (mail filtering)
10    system.  Finally, the latter stripped it down to work with MH.
11
12    This program should be used ONLY if you have both "mts mh" and "uucp on"
13    set in your MH configuration.
14  */
15
16
17 #include "../h/mh.h"
18 #include "../h/addrsbr.h"
19 #include "../zotnet/mf.h"
20 #include "../zotnet/tws.h"
21 #include <stdio.h>
22 #include "../zotnet/mts.h"
23 #include <signal.h>
24 #ifdef LOCALE
25 #include        <locale.h>
26 #endif
27
28
29 #define ADDROK  0               /* okay to use post to deliver message */
30 #define UUCP    1               /* okay to use uux to deliver message */
31 #define RETURN  2               /* message loses */
32
33 /* \f */
34 int     pbroke;                 /* broken-pipe flag */
35 int     rtnflag;                /* note was sent back */
36
37 char    date[BUFSIZ];           /* date of origination from uucp header */
38 char    from[BUFSIZ];           /* accumulated path of sender */
39 char    origsys[BUFSIZ];        /* originating system */
40 char    origpath[BUFSIZ];       /* path from us to originating system */
41 char    usrfrm[BUFSIZ];         /* the 822 version of from[] */
42 char    Mailsys[BUFSIZ];        /* address of the mail agent */
43 char    overseer[BUFSIZ];       /* address of the watchdog */
44
45 char    mmdf[BUFSIZ];           /* filtered mail file */
46
47 char   *rtnmessage[] = {
48     "   Your message has been intercepted trying to access\n",
49     "a restricted access host (e.g. an ARPANET host).  A copy\n",
50     "of your message has been sent to the system administrators.\n",
51     "The text of your message follows.\n\n",
52     NULL
53 };
54
55 char    rtnbegin[] =
56         " ---------------- Returned Mail Follows --------------\n";
57 char    rtnend[] =
58         "  --------------- End of Returned Mail ---------------\n";
59
60 char   *oopsmessage[] = {
61     "\n\n\tThe system administrators (%s) have been informed of\n",
62     "the problem, but have not been given a copy of your message.\n\n",
63     NULL
64 };
65
66 FILE * fromf;                   /* UUCP "From lines */
67 FILE * msgf;                    /* message text */
68 FILE * pipef;                   /* output for "post" or "uux" */
69
70
71 int     pipeser ();
72
73
74 off_t    lseek ();
75
76 /* \f */
77
78 main (argc, argv)
79 int     argc;
80 char  **argv;
81 {
82     int     cpyback;
83     char   *cp,
84            *fromptr,
85             fromwhom[BUFSIZ],
86             linebuf[BUFSIZ],
87             sys[BUFSIZ];
88
89 #ifdef LOCALE
90         setlocale(LC_ALL, "");
91 #endif
92     invo_name = r1bindex (*argv, '/');
93     m_foil (NULLCP);
94     mts_init (invo_name);
95
96     if (argc < 2)
97         adios (NULLCP, "usage: %s user [user ...]", invo_name);
98     (void) umask (0);
99     (void) setgid (1);
100     (void) setuid (1);
101
102     (void) sprintf (Mailsys, "%s@%s", Mailer, LocalName ());
103     if (Overseer == NULL)
104         Overseer = Mailsys;
105     if (index (Overseer, '@') == NULL) {
106         (void) sprintf (overseer, "%s@%s", Overseer, LocalName ());
107         Overseer = overseer;
108     }
109
110     (void) mktemp (Errtmp);
111     if (freopen (Errtmp, "w", stderr) == NULL)
112         adios (Errtmp, "unable to create");
113     (void) dup2 (fileno (stderr), fileno (stdout));
114
115     (void) mktemp (Msgtmp);
116     if ((msgf = fdopen (creat (Msgtmp, Tmpmode), "w")) == NULL)
117         adios (Msgtmp, "unable to create");
118
119     (void) mktemp (Fromtmp);
120     if ((fromf = fdopen (creat (Fromtmp, Tmpmode), "w")) == NULL)
121         adios (Fromtmp, "unable to create");
122
123 /* \f */
124
125     for (;;) {
126         if (fgets (linebuf, sizeof linebuf, stdin) == NULL)
127             break;
128         if (strncmp (linebuf, "From ", 5)
129                 && strncmp (linebuf, ">From ", 6))
130             break;
131
132         if (linebuf[0] != '>')
133             fputs (">", fromf);
134         fputs (linebuf, fromf);
135         cp = index (linebuf, ' ');
136         fromptr = ++cp;
137         cp = index (cp, ' ');
138         *cp++ = NULL;
139         (void) strcpy (fromwhom, fromptr);
140         (void) strncpy (date, cp, 24);
141
142         for (;;) {
143             if ((cp = index (cp + 1, 'r')) == NULL) {
144                 if ((cp = rindex (fromwhom, '!')) != NULL) {
145                     char   *p;
146                     *cp = NULL;
147                     if ((p = rindex (fromwhom, '!')) != NULL)
148                         (void) strcpy (origsys, p + 1);
149                     else
150                         (void) strcpy (origsys, fromwhom);
151                     (void) strcat (from, fromwhom);
152                     (void) strcat (from, "!");
153                     (void) strcpy (fromwhom, cp + 1);
154                     goto out;
155                 }
156                 (void) strcpy (sys, SystemName ());
157                 (void) strcat (from, sys);
158                 (void) strcpy (origsys, sys);
159                 (void) strcat (from, "!");
160                 goto out;
161             }
162             if (strncmp (cp, "remote from ", 12) == 0)
163                 break;
164         }
165
166         (void) sscanf (cp, "remote from %s", sys);
167         (void) strcat (from, sys);
168         (void) strcpy (origsys, sys);
169         (void) strcat (from, "!");
170 out:    ;
171     }
172     if (fromwhom[0] == NULL)
173         adios (NULLCP, "no from line");
174
175 /* \f */
176
177     (void) strcpy (origpath, from);
178     (void) strcat (from, fromwhom);
179     get_mmdf_addr (from, usrfrm);
180     if ((cp = rindex (usrfrm, '<')) != NULL) {
181         (void) strcpy (usrfrm, ++cp);   /* sigh */
182         if ((cp = rindex (usrfrm, '>')) != NULL)
183             *cp = NULL;
184     }
185     if (usrfrm[0] == NULL)
186         (void) sprintf (usrfrm, "%s!%s%%%s@%s%c",
187                 SystemName (), from, UucpChan (), LocalName (), NULL);
188
189     fputs (linebuf, msgf);
190     if (txtcpy (stdin, msgf) == NOTOK)
191         fputs ("\n  *** Problem during receipt from UUCP ***\n", msgf);
192
193     (void) freopen (Msgtmp, "r", msgf);
194     (void) freopen (Fromtmp, "r", fromf);
195     (void) unlink (Fromtmp);
196     mmdf[0] = NULL;
197
198     cpyback = 0;
199     for (argv++; --argc > 0;) {
200         rewind (fromf);
201         rewind (msgf);
202         rtnflag = 0;
203         if (deliver (*argv++) == NOTOK && !rtnflag)
204             cpyback++;
205     }
206
207     (void) fflush (stderr);
208     (void) fflush (stdout);
209
210     if (cpyback) {
211         rcpy ();
212         zcpy ();
213     }
214
215     (void) unlink (Msgtmp);
216     if (mmdf[0])
217         (void) unlink (mmdf);
218     (void) unlink (Errtmp);
219
220     exit (0);
221 }
222
223 /* \f */
224
225 deliver (to)
226 char   *to;
227 {
228     int     i,
229             replyval;
230     char    tmpfil[BUFSIZ];
231
232     switch (adrcheck (to)) {
233         case ADDROK: 
234             if (mmdf[0] == NULL && filter () == NOTOK)
235                 (void) strcpy (mmdf, Msgtmp);
236             replyval = xpost (to, mmdf);
237             break;
238
239         case UUCP: 
240             if ((replyval = xuucp (to)) == NOTOK)
241                 break;
242
243             if ((replyval = txtcpy (fromf, pipef)) != NOTOK)
244                 replyval = txtcpy (msgf, pipef);
245             i = (pclose (pipef) >> 8) & 0xff;
246             if (replyval != NOTOK)
247                 replyval = (i != 0 ? NOTOK : OK);
248             break;
249
250 /* \f */
251
252         case RETURN: 
253             rtnflag++;
254             switch (adrcheck (from)) {
255                 case ADDROK: 
256                 case RETURN: 
257                     (void) strcpy (tmpfil, "/tmp/rmailXXXXXX");
258                     (void) unlink (mktemp (tmpfil));
259                     if ((pipef = fdopen (creat (tmpfil, Tmpmode), "w")) == NULL)
260                         return NOTOK;
261
262                     fprintf (pipef, "Date: %s\nFrom: %s\n",
263                             dtimenow (), Mailsys);
264                     fprintf (pipef, "To: %s\ncc: %s\n", from, Overseer);
265                     rtnmesg (to);
266                     (void) fclose (pipef);
267
268                     replyval = xpost (from, tmpfil);
269                     (void) unlink (tmpfil);
270                     break;
271
272                 case UUCP: 
273                     if ((replyval = xuucp (from)) == NOTOK)
274                         break;
275
276                     fprintf (pipef, "To: %s\ncc: %s\n", from, Overseer);
277                     rtnmesg (to);
278                     i = (pclose (pipef) >> 8) & 0xff;
279                     if (replyval != NOTOK)
280                         replyval = (i != 0 ? NOTOK : OK);
281                     break;
282             }
283             if (Syscpy) {
284                 (void) strcpy (tmpfil, "/tmp/rmailXXXXXX");
285                 (void) unlink (mktemp (tmpfil));
286                 if ((pipef = fdopen (creat (tmpfil, Tmpmode), "w")) == NULL)
287                     return NOTOK;
288
289                 fprintf (pipef, "Date: %s\nFrom: %s\n",
290                         dtimenow (), Mailsys);
291                 fprintf (pipef, "To: %s\ncc: %s\n", usrfrm, Overseer);
292                 rtnmesg (to);
293                 (void) fclose (pipef);
294
295                 replyval = xpost (Overseer, tmpfil);
296                 (void) unlink (tmpfil);
297             }
298             break;
299     }
300
301     return replyval;
302 }
303
304 /* \f */
305
306 adrcheck (adr)
307 char   *adr;
308 {
309     int     type;
310     char   *cp,
311             host[BUFSIZ];
312     struct mailname *mp;
313
314     if ((cp = getname (adr)) == NULL)
315         return RETURN;
316     mp = getm (cp, NULLCP, 0, AD_HOST, NULLCP);
317     while (getname (""))
318         continue;
319     if (mp == NULL)
320         return RETURN;
321
322     type = mp -> m_type;
323     (void) strcpy (host, mp -> m_host);
324     mnfree (mp);
325     if (mp -> m_mbox == NULL)
326         return RETURN;
327
328     switch (type) {
329         case LOCALHOST: 
330             return ADDROK;
331
332         case UUCPHOST: 
333             return (strcmp (host, SystemName ()) ? UUCP : ADDROK);
334
335         default: 
336             if (lookup (origsys, Okhosts) == OK)
337                 return ADDROK;
338             return (okhost (host) == NOTOK ? RETURN : ADDROK);
339     }
340 }
341
342 /* \f */
343
344 okhost (host)
345 char   *host;
346 {
347     return (lookup (origsys, Okhosts) == OK
348             || lookup (host, Okhosts) == OK
349             || lookup (host, Okdests) == OK ? OK : NOTOK);
350 }
351
352
353 lookup (what, where)
354 char   *what,
355        *where;
356 {
357     char   *cp,
358             entry[BUFSIZ];
359     FILE * lookf;
360
361     if ((lookf = fopen (where, "r")) == NULL)
362         return NOTOK;
363     while (fgets (entry, sizeof entry, lookf) != NULL) {
364         cp = entry;
365         while (*cp != '\n' && *cp != ' ' && *cp != '\t')
366             cp++;
367         *cp = NULL;
368         if (uleq (what, entry)) {
369             (void) fclose (lookf);
370             return OK;
371         }
372     }
373     (void) fclose (lookf);
374
375     return NOTOK;
376 }
377
378
379 /* \f */
380
381 rtnmesg (badadr)
382 char   *badadr;
383 {
384     int     i;
385
386     fprintf (pipef, "Subject: Illegal Address (%s)\n\n", badadr);
387     for (i = 0; rtnmessage[i]; i++)
388         fputs (rtnmessage[i], pipef);
389     fputs (rtnbegin, pipef);
390
391     rewind (fromf);
392     (void) txtcpy (fromf, pipef);
393     rewind (msgf);
394     (void) txtcpy (msgf, pipef);
395
396     fputs (rtnend, pipef);
397 }
398
399
400 txtcpy (frm, to)
401 FILE * frm, *to;
402 {
403     int     nread;
404     char    buffer[BUFSIZ];
405
406     while (!pbroke
407             && (nread = fread (buffer, sizeof (*buffer), BUFSIZ, frm)) > 0)
408         (void) fwrite (buffer, sizeof (*buffer), nread, to);
409
410     return (ferror (frm) ? NOTOK : OK);
411 }
412
413 /* \f */
414
415 xpost (addr, file)
416 char   *addr,
417        *file;
418 {
419     int     i,
420             child_id;
421
422     for (i = 0; (child_id = fork ()) == NOTOK && i < 5; i++)
423         sleep (5);
424     switch (child_id) {
425         case NOTOK: 
426             return NOTOK;
427
428         case OK: 
429             execlp (postproc, r1bindex (postproc, '/'),
430                     "-deliver", addr, file, NULLCP);
431             fprintf (stderr, "unable to exec ");
432             perror (postproc);
433             _exit (1);
434
435         default: 
436             return (pidwait (child_id, OK) ? NOTOK : OK);
437     }
438 }
439
440 /* \f */
441
442 xuucp (to)
443 char   *to;
444 {
445     char   *cp,
446             buffer[BUFSIZ],
447             cmdstr[BUFSIZ];
448
449     (void) strcpy (buffer, to);
450     if (cp = index (buffer, '!'))
451         *cp++ = NULL;
452     else {
453         fprintf (stderr, "internal error -- %s has no host\n", to);
454         return NOTOK;
455     }
456     (void) sprintf (cmdstr, "uux -p %s!rmail \\(%s\\)", buffer, cp);
457
458     if ((pipef = popen (cmdstr, "w")) == NULL)
459         return NOTOK;
460
461     (void) signal (SIGPIPE, pipeser);
462     pbroke = 0;
463
464     return OK;
465 }
466
467 /* \f */
468
469 #ifdef  BSD42
470 /* ARGSUSED */
471 #endif  BSD42
472
473 static int  pipeser (i)
474 int     i;
475 {
476 #ifndef BSD42
477     (void) signal (i, SIG_IGN);
478 #endif  BSD42
479
480     pbroke = 1;
481 }
482
483 /* \f */
484
485 rcpy () {
486     int     i;
487     char    buffer[BUFSIZ],
488             tmpfil[BUFSIZ];
489     FILE * fp;
490
491     (void) strcpy (tmpfil, "/tmp/rmailXXXXXX");
492     (void) unlink (mktemp (tmpfil));
493     if ((pipef = fdopen (creat (tmpfil, Tmpmode), "w")) == NULL)
494         return;
495
496     fprintf (pipef, "Date: %s\nFrom: %s\n", dtimenow (), Mailsys);
497     fprintf (pipef, "To: %s\n", usrfrm);
498     fprintf (pipef, "\nProblems sending mail:\n\n");
499     i = 0;
500     if ((fp = fopen (Errtmp, "r")) != NULL) {
501         while (fgets (buffer, sizeof buffer, fp) != NULL) {
502             if (ferror (pipef))
503                 break;
504             fputs (buffer, pipef);
505             i++;
506         }
507     }
508     if (i == 0)
509         fprintf (pipef, "\tunknown problem\n");
510     for (i = 0; oopsmessage[i]; i++)
511         fprintf (pipef, oopsmessage[i], Overseer);
512     fputs (rtnbegin, pipef);
513
514     rewind (fromf);
515     (void) txtcpy (fromf, pipef);
516     rewind (msgf);
517     (void) txtcpy (msgf, pipef);
518
519     fputs (rtnend, pipef);
520     (void) fclose (pipef);
521
522     (void) xpost (usrfrm, tmpfil);
523     (void) unlink (tmpfil);
524 }
525
526 /* \f */
527
528 zcpy () {
529     int     i;
530     char    buffer[BUFSIZ],
531             tmpfil[BUFSIZ];
532     FILE * fp;
533
534     (void) strcpy (tmpfil, "/tmp/rmailXXXXXX");
535     (void) unlink (mktemp (tmpfil));
536     if ((pipef = fdopen (creat (tmpfil, Tmpmode), "w")) == NULL)
537         return;
538
539     fprintf (pipef, "Date: %s\nFrom: %s\n", dtimenow (), Mailsys);
540     fprintf (pipef, "To: %s\n", Mailsys);
541     fprintf (pipef, "\nProblems sending mail for %s (aka %s):\n\n",
542             from, usrfrm);
543
544     i = 0;
545     if ((fp = fopen (Errtmp, "r")) != NULL) {
546         while (fgets (buffer, sizeof buffer, fp) != NULL) {
547             if (ferror (pipef))
548                 break;
549             fputs (buffer, pipef);
550             i = 1;
551         }
552         (void) fclose (fp);
553         if (i == 0)
554             fprintf (pipef, "\tunknown problem\n");
555     }
556     else
557         fprintf (pipef, "\tunable to open %s\n", Errtmp);
558     (void) fclose (pipef);
559
560     (void) xpost (Mailsys, tmpfil);
561     (void) unlink (tmpfil);
562 }
563
564 /* \f */
565
566 filter () {
567     int     i,
568             fd,
569             td;
570     char    tmpfil[BUFSIZ],
571             mmdfil[BUFSIZ];
572     FILE * out;
573
574     (void) strcpy (tmpfil, "/tmp/rmailXXXXXX");
575     (void) unlink (mktemp (tmpfil));
576     if ((fd = creat (tmpfil, Tmpmode)) == NOTOK)
577         return NOTOK;
578     (void) close (fd);
579     if ((fd = open (tmpfil, 2)) == NOTOK)
580         return NOTOK;
581     if ((out = fdopen (fd, "w")) == NULL) {
582         (void) close (fd);
583         return NOTOK;
584     }
585     if ((td = dup (fd)) == NOTOK) {
586         (void) close (fd);
587         return NOTOK;
588     }
589
590     fprintf (out, "From %s %s\n", from, date);
591     if (txtcpy (msgf, out) == NOTOK) {
592         (void) close (fd);
593         (void) close (td);
594         return NOTOK;
595     }
596     (void) fclose (out);
597     (void) lseek (td, (off_t)0, 0);
598
599     (void) strcpy (mmdfil, "/tmp/mmdfXXXXXX");
600     (void) unlink (mktemp (mmdfil));
601     if ((fd = creat (mmdfil, Tmpmode)) == NOTOK) {
602         (void) close (td);
603         (void) unlink (tmpfil);
604         return NOTOK;
605     }
606     if ((fd = open (mmdfil, 2)) == NOTOK) {
607         (void) close (td);
608         (void) unlink (tmpfil);
609         return NOTOK;
610     }
611
612 /* \f */
613
614     switch (i = uucp2mmdf (td, fd, TRUE)) {
615         case OK: 
616             (void) strcpy (mmdf, mmdfil);
617             break;
618
619         default: 
620             mmdf[0] = NULL;
621             break;
622     }
623     (void) close (td);
624     (void) unlink (tmpfil);
625     (void) close (fd);
626
627     return (i != OK ? NOTOK : OK);
628 }
629
630 /* \f */
631
632 get_mmdf_addr (addr, to)
633 char   *addr,
634        *to;
635 {
636     struct adrx *adrxp;
637
638     *to = NULL;
639     if ((adrxp = seekadrx (addr)) == NULL)
640         return;
641
642     addr_convert (adrxp, to, TRUE);
643     while (seekadrx (NULLCP))
644         continue;
645 }