Added -clobber switch to mhstore(1) [Bug #11160].
[mmh] / docs / historical / mh-6.8.5 / zotnet / mf / uumm.c
1 /* uumm.c - routines to filter UUCP to MMDF mailboxes */
2
3 #include "mf.h"
4 #include "../tws/tws.h"
5 #include <stdio.h>
6 #include "../mts/mts.h"
7 #include <ctype.h>
8 #include <sys/types.h>
9 #include <sys/stat.h>
10
11 /* \f */
12
13 static struct header {
14     char   *h_name;
15     int     h_type;
16 }                       headers[] = {
17                             "From", HFROM,
18                             "Sender", HSNDR,
19                             "Reply-To", HADDR,
20                             "To", HADDR,
21                             "cc", HADDR,
22                             "Bcc", HADDR,
23                             "Resent-From", HADDR,
24                             "Resent-Sender", HADDR,
25                             "Resent-Reply-To", HADDR,
26                             "Resent-To", HADDR,
27                             "Resent-cc", HADDR,
28                             "Resent-Bcc", HADDR,
29                             "Date", HDATE,
30                             "Resent-Date", HDATE,
31                             NULL, HOTHR
32 };
33
34 static char buffer[BUFSIZ],
35             tmpbuf[BUFSIZ];
36
37 char   *shrink ();
38
39 long    time ();
40
41 /* \f */
42
43 /*
44  *    uucp2mmdf() - given a file descriptor to a uucp mailbox, filter
45  *    its contents to the file descriptor for a mmdf mailbox.  Returns
46  *    non-zero on error (see mf.h for values)
47  *
48  *    It is assumed that the caller will have made sure that the necessary
49  *    locking has been performed on the output fd.
50  */
51
52 int     uucp2mmdf (infd, outfd, nodelim)
53 int     infd,
54         outfd,
55         nodelim;
56 {
57     int     fd,
58             result;
59     struct stat st;
60     FILE * in, *out;
61
62     if (fstat (infd, &st) == NOTOK || fstat (outfd, &st) == NOTOK)
63         return MFPRM;
64     if ((in = fdopen (infd, "r")) == NULL
65             || (out = fdopen (outfd, "w")) == NULL)
66         return MFSIO;
67
68     result = uumm (in, out, nodelim);
69
70     /* for STDIO - free up some fp:s */
71     fd = dup (fileno (in));
72     fclose (in);
73     dup2 (fd, infd);
74     close (fd);
75
76     fd = dup (fileno (out));
77     fclose (out);
78     dup2 (fd, outfd);
79     close (fd);
80
81     return result;
82 }
83
84 /* \f */
85
86 int     uumm (in, out, nodelim)
87 FILE   *in,
88        *out;
89 int     nodelim;
90 {
91     int     i,
92             tmp_fd;
93     char    from[LINESIZ],
94             date[LINESIZ];
95     FILE   *tmp;
96
97     for (tmp_fd = NOTOK;;) {
98         if ((i = uucp_file (&tmp_fd, in, &tmp, nodelim)) == DONE)
99             break;
100         else
101             if (i != OK)
102                 return i;
103         if ((i = uucp_from (from, date, tmp)) != OK)
104             return uucp_die (i, tmp, in, out, nodelim);
105         if ((i = uucp_headers (from, date, tmp, out, nodelim)) != OK)
106             return uucp_die (i, tmp, in, out, nodelim);
107         if ((i = uucp_text (tmp, out, nodelim)) != OK)
108             return uucp_die (i, tmp, in, out, nodelim);
109     }
110
111     fflush (out);
112
113     return (ferror (in) || ferror (out) ? MFERR : MFOK);
114 }
115
116 /* \f */
117
118 static int  uucp_file (tmp_fd, in, tmp, nodelim)
119 int    *tmp_fd,
120         nodelim;
121 FILE * in, **tmp;
122 {
123     int     done,
124             fd;
125     char    tmpfil[LINESIZ];
126     FILE * out;
127
128     if (nodelim)
129         if (*tmp_fd != NOTOK)
130             return DONE;
131         else
132             if ((*tmp_fd = dup (fileno (in))) == NOTOK)
133                 return MFERR;
134             else
135                 if ((*tmp = fdopen (*tmp_fd, "r")) == NULL) {
136                     close (*tmp_fd);
137                     return MFERR;
138                 }
139                 else
140                     return OK;
141
142     if (*tmp_fd == NOTOK && fgets (tmpbuf, sizeof tmpbuf, in) == NULL)
143         return DONE;
144     else
145         if (feof (in))
146             return DONE;
147
148     strcpy (tmpfil, "/tmp/uummXXXXXX");
149     unlink (mktemp (tmpfil));
150     if ((fd = creat (tmpfil, TMPMODE)) == NOTOK)
151         return MFERR;
152     close (fd);
153
154     if ((fd = open (tmpfil, 2)) == NOTOK)
155         return MFERR;
156     if ((out = fdopen (fd, "w")) == NULL) {
157         close (fd);
158         return MFERR;
159     }
160     unlink (tmpfil);
161
162     if ((*tmp_fd = dup (fd)) == NOTOK) {
163         close (fd);
164         return MFERR;
165     }
166     if ((*tmp = fdopen (*tmp_fd, "r")) == NULL) {
167         close (fd);
168         close (*tmp_fd);
169         return MFERR;
170     }
171
172 /* \f */
173
174     for (done = FALSE;;) {
175         if (done)
176             if (isfrom (tmpbuf))
177                 break;
178             else
179                 putc ('\n', out);
180         done = tmpbuf[0] == '\n';
181         if (!done)
182             fputs (tmpbuf, out);
183         if (fgets (tmpbuf, sizeof tmpbuf, in) == NULL)
184             break;
185     }
186
187     fclose (out);
188     fseek (*tmp, 0L, 0);
189     return OK;
190 }
191
192 /* \f */
193
194 /* We might want to attempt recovery here.  Forget it. */
195
196 static int  uucp_from (from, date, in)
197 char   *from,
198        *date;
199 FILE * in;
200 {
201     char   *cp,
202            *pp,
203             fromwhom[LINESIZ];
204     struct adrx *adrxp;
205
206     if (fgets (buffer, sizeof buffer, in) == NULL || !isfrom (buffer))
207         return MFROM;
208     if (buffer[strlen (buffer) - 1] == '\n')
209         buffer[strlen (buffer) - 1] = NULL;
210     if ((cp = index (buffer, ' ')) == NULL)
211         return MFROM;
212     pp = ++cp;
213     if ((cp = index (cp, ' ')) == NULL)
214         return MFROM;
215     *cp++ = NULL;
216     strcpy (fromwhom, pp);
217     while (isspace (*cp))
218         cp++;
219     sprintf (date, "%.24s", cp);
220
221     for (;;) {
222         if ((cp = index (cp + 1, 'r')) == NULL) {
223             if (index (fromwhom, '!') || index (fromwhom, '@'))
224                 strcpy (from, fromwhom);
225             else
226                 sprintf (from, "%s!%s", SystemName (), fromwhom);
227             break;
228         }
229         if (strncmp (cp, "remote from ", 12) == 0) {
230             *cp = NULL;
231             sprintf (from, "%s!%s", cp + 12, fromwhom);
232             break;
233         }
234     }
235
236     if ((adrxp = seekadrx (from)) == NULL)
237         return MFROM;
238     addr_convert (adrxp, from, TRUE);
239     while (seekadrx (NULL))
240         continue;
241     if (from[0] == NULL)
242         return MFROM;
243     date_convert (date, date);
244     return (date[0] != NULL ? OK : MFROM);
245 }
246
247 /* \f */
248
249 static int  uucp_headers (from, date, in, out, nodelim)
250 int     nodelim;
251 char   *from,
252        *date;
253 FILE * in, *out;
254 {
255     int     i,
256             seen_from,
257             seen_sender,
258             seen_date;
259
260     seen_from = seen_sender = seen_date = 0;
261     if (!nodelim)
262         fputs (mmdlm1, out);
263
264     fprintf (out, "Munged: from %s to %s; %s\n",
265             SystemName (), LocalName (), dtimenow ());
266
267     for (;;) {
268         switch (do_header (&seen_from, &seen_sender, &seen_date, in, out)) {
269             case NOTOK: 
270                 return MFHDR;
271
272             case OK: 
273                 continue;
274
275             case DONE: 
276                 break;
277         }
278         break;
279     }
280                                 /* extra newline separates headers and body */
281     fprintf (out, "%sDate: %s\n%s: %s\n\n",
282             seen_date ? "UUCP-" : NULL, date,
283             seen_from ? (seen_sender ? "UUCP-Sender" : "Sender") : "From",
284             from);
285
286     return OK;
287 }
288
289 /* \f */
290
291 static int  uucp_text (in, out, nodelim)
292 int     nodelim;
293 FILE * in, *out;
294 {
295     if (feof (in))              /* probably no body */
296         putc ('\n', out);
297     else
298         while (fgets (buffer, sizeof buffer, in) != NULL) {
299             if (!nodelim && isdlm2 (buffer))
300                 buffer[0]++;
301             fputs (buffer, out);
302         }
303
304     if (!nodelim)
305         fputs (mmdlm2, out);
306     fclose (in);
307
308     return OK;
309 }
310
311 /* \f */
312
313 static int  do_header (seen_from, seen_sender, seen_date, in, out)
314 int    *seen_from,
315        *seen_sender,
316        *seen_date;
317 FILE * in, *out;
318 {
319     int     i,
320             margin,
321             some,
322             spat,
323             pos;
324     char   *bp,
325            *cp,
326            *pp,
327             line[BUFSIZ];
328     struct adrx *adrxp;
329     struct header  *hl;
330
331     if ((i = mfgets (in, &bp)) != OK)
332         return i;
333
334     if ((cp = index (bp, ':')) == NULL) {
335         fprintf (out, "Illegal-Field: %s\n", bp);
336         return OK;
337     }
338
339     *cp = NULL;
340     for (hl = &headers[0]; hl -> h_name; hl++)
341         if (lequal (hl -> h_name, bp))
342             break;
343
344 /* \f */
345
346     switch (hl -> h_type) {
347         case HDATE: 
348             if (lequal (hl -> h_name, "Date"))
349                 (*seen_date)++;
350             for (pp = cp + 1; isspace (*pp); pp++)
351                 continue;
352             date_convert (pp, line);
353             if (line[0] == NULL)
354                 fprintf (out, "Illegal-Object: %s: %s -- %s\n",
355                         hl -> h_name, pp, "illegal date construct");
356             else
357                 fprintf (out, "%s: %s\n", hl -> h_name, line);
358             break;
359             
360         case HOTHR: 
361             *cp = ':';
362             fprintf (out, "%s\n", bp);
363             break;
364
365         case HFROM: 
366         case HSNDR: 
367             if (hl -> h_type == HFROM)
368                 (*seen_from)++;
369             else
370                 (*seen_sender)++;
371         case HADDR: 
372             spat = 0;
373             some = FALSE;
374             pp = ++cp;
375             margin = pos = strlen (hl -> h_name) + 2;
376             while (adrxp = seekadrx (pp)) {
377                 addr_convert (adrxp, line, FALSE);
378                 if (line[0] != NULL) {
379                     if (!spat++)
380                         fprintf (out, "%s: ", hl -> h_name);
381                     if (some++)
382                         fputs (", ", out), pos += 2;
383                     if (pos + strlen (line) >= OWIDTH) {
384                         fprintf (out, "\n%*s", margin, " ");
385                         pos = margin;
386                     }
387                     fputs (line, out);
388                     pos += strlen (line);
389                 }
390                 else {
391                     if (spat)
392                         putc ('\n', out);
393                     fprintf (out, "Illegal-Object: %s: %s -- %s\n",
394                             hl -> h_name, adrxp -> text, adrxp -> err);
395                     spat = 0;
396                     some = FALSE;
397                     pos = margin;
398                 }
399             }
400             if (spat)
401                 putc ('\n', out);
402             break;
403
404         default: 
405             return NOTOK;
406     }
407
408     return OK;
409 }
410
411 /* \f */
412
413 addr_convert (adrxp, to, notice)
414 struct adrx *adrxp;
415 char   *to;
416 int     notice;
417 {
418     int     addrlen,
419             uucplen;
420     char   *cp,
421            *wp,
422             addr[BUFSIZ],
423             tmp[LINESIZ],
424             uucp[LINESIZ];
425     static char path[LINESIZ] = "";
426
427     if (adrxp -> err || !adrxp -> mbox) {
428         *to = NULL;
429         return;
430     }
431     if (notice)
432         if ((cp = rindex (adrxp -> mbox, '!')) != NULL)
433             sprintf (path, "%.*s!", cp - adrxp -> mbox, adrxp -> mbox);
434         else
435             path[0] = NULL;
436
437     sprintf (addr, "%s%s", path, adrxp -> mbox);
438     sprintf (uucp, "%s!", SystemName ());
439     uucplen = strlen (uucp);
440     if ((addrlen = strlen (addr) - uucplen - 1) >= 0)
441         for (cp = addr + addrlen; cp >= addr; cp--)
442             if (strncmp (cp, uucp, uucplen) == NULL) {
443                 if (cp != addr && *(cp - 1) != '!')
444                     continue;
445                 strcpy (addr, cp + uucplen);
446                 break;
447             }
448
449 /* \f */
450
451     if (adrxp -> host == NULL) {
452         cp = shrink (addr);
453 #ifdef  MMDFMTS
454         sprintf (uucp, "%s%%%s@%s", cp, UucpChan (), LocalName ());
455 #else   MMDFMTS
456         if (wp = index (adrxp -> mbox, '!'))
457             sprintf (uucp, "%s@%.*s.%s",
458                 wp + 1, wp - adrxp -> mbox, adrxp -> mbox, UucpChan ());
459         else
460             sprintf (uucp, "%s@%s.%s",
461                 adrxp -> mbox, SystemName (), UucpChan ());
462 #endif  MMDFMTS
463         if (strcmp (adrxp -> mbox, cp))
464             sprintf (tmp, "\"%s\" <%s>", adrxp -> mbox, uucp);
465         else
466             strcpy (tmp, uucp);
467     }
468     else
469         if ((wp = rindex (adrxp -> mbox, '!')) == NULL)
470             sprintf (tmp, "%s@%s", adrxp -> mbox, adrxp -> host);
471         else {
472             sprintf (uucp, "%%%s", UucpChan ());
473             uucplen = strlen (uucp);
474             cp = (lequal (LocalName (), adrxp -> host)
475                     && (addrlen = strlen (addr) - uucplen) > 0)
476                 ? addr + addrlen : NULL;
477             if (lequal (uucp, cp))
478                 sprintf (tmp, "%s@%s", shrink (addr), adrxp -> host);
479             else {
480                 if (lequal (adrxp -> mbox, ++wp))
481                     sprintf (tmp, "%s@%s", wp, adrxp -> host);
482                 else
483                     sprintf (tmp, "\"%s\" <%s@%s>", adrxp -> mbox,
484                             wp, adrxp -> host);
485             }
486         }
487
488     strcpy (to, tmp);
489 }
490
491 /* \f */
492
493 static char *shrink (addr)
494 char   *addr;
495 {
496     int     i,
497             j;
498     char   *cp,
499            *pp,
500            *wp,
501            *xp;
502     static char r1[BUFSIZ],
503                 r2[BUFSIZ];
504
505     sprintf (r2, "%s!", SystemName ());
506     i = strlen (r2);
507     if ((j = strlen (addr) - i - 1) >= 0)
508         for (cp = &addr[j]; cp >= addr; cp--)
509             if (strncmp (cp, r2, i) == NULL) {
510                 if (cp != addr && *(cp - 1) != '!')
511                     continue;
512                 strcpy (addr, cp + i);
513                 break;
514             }
515
516     if ((cp = rindex (addr, '!')) == NULL) {
517         sprintf (r1, "%s%s", r2, addr);
518         return r1;
519     }
520     *cp++ = NULL;
521
522     if ((pp = rindex (addr, '!')) == NULL) {
523         *--cp = '!';
524         strcpy (r1, addr);
525         return r1;
526     }
527     strcpy (r1, cp);
528
529     while ((pp = rindex (addr, '!')) != NULL) {
530         for (pp++, xp = addr; (wp = index (xp, '!')) != NULL;) {
531             *wp = NULL;
532             if (strcmp (pp, xp)) {
533                 *wp++ = '!';
534                 xp = wp;
535             }
536             else {
537                 pp = xp;
538                 break;
539             }
540         }
541         sprintf (r2, "%s!%s", pp, r1);
542         strcpy (r1, r2);
543         if (--pp > addr)
544             *pp = NULL;
545     }
546
547 /* \f */
548
549     if ((wp = index (r1, '!')) != NULL) {
550         *wp = NULL;
551         strcpy (r2, r1);
552         *wp = '!';
553         if (strcmp (addr, r2)) {
554             sprintf (r2, "%s!%s", addr, r1);
555             strcpy (r1, r2);
556         }
557     }
558
559     return r1;
560 }
561
562 /* \f */
563
564 date_convert (from, to)
565 char    from[],
566        *to;
567 {
568     static int  zone = -1,
569                 flags = TW_NULL;
570     char    date[LINESIZ];
571     struct tws *tw;
572
573     if (dparsetime (from))      /* might be OK as is */
574         strcpy (date, from);
575     else
576         if (isdigit (from[20])) {
577             if (zone == -1) {
578                 if (tw = dtwstime ()) {
579                     zone = tw -> tw_zone;
580                     flags = tw -> tw_flags;
581                 }
582                 else
583                     zone = 0, flags = TW_NULL;
584             }
585             sprintf (date, "%.3s, %.2s %.3s %.2s %.2s:%.2s:%.2s %s",
586                     from + 0, from + 8, from + 4, from + 22, from + 11,
587                     from + 14, from + 17, dtimezone (zone, flags));
588         }
589         else
590             sprintf (date, "%.3s, %.2s %.3s %.2s %.2s:%.2s:%.2s %s",
591                     from + 0, from + 8, from + 4, from + 26, from + 11,
592                     from + 14, from + 17, from + 20);
593
594     strcpy (to, date);
595 }
596
597 /* \f */
598
599 static int  uucp_die (error, in1, in2, out, nodelim)
600 int     error,
601         nodelim;
602 FILE * in1, *in2, *out;
603 {
604     long    clock;
605     char    date[LINESIZ];
606
607     if (nodelim) {
608         fclose (in1);
609         return error;
610     }
611
612     switch (error) {
613         case MFHDR: 
614             putc ('\n', out);
615         case MFTXT: 
616             fprintf (out, "\n%s", mmdlm2);
617             break;
618     }
619
620     time (&clock);
621     sprintf (date, "%.*s", sizeof date - 1, dtime (&clock));
622     fprintf (out, "%sFrom: %s <%s@%s>\nDate: %s\nSubject: %s %s\n\n",
623             mmdlm1, "UUCP to MMDF filter", getusr (), LocalName (), date,
624             "Bad UUCP mailbox - error in",
625             error == MFHDR ? "Header" : error == MFTXT ? "Body" : "Mailbox");
626
627     fprintf (out, "%s: %s\n%s\n--------\n",
628             "Error detected at line", buffer, "Message being processed");
629     fseek (in1, 0L, 0);
630     while (fgets (buffer, sizeof buffer, in1) != NULL) {
631         if (isdlm2 (buffer))
632             buffer[0]++;
633         fputs (buffer, out);
634     }
635     fclose (in1);
636
637     if (!feof (in2)) {
638         fprintf (out, "--------\n%s\n--------\n%s",
639                 "Remainder of unfiltered mailbox follows", tmpbuf);
640         while (fgets (buffer, sizeof buffer, in2) != NULL) {
641             if (isdlm2 (buffer))
642                 buffer[0]++;
643             fputs (buffer, out);
644         }
645     }
646
647     fprintf (out, "--------\n%s", mmdlm2);
648     fflush (out);
649
650     return error;
651 }