Added -clobber switch to mhstore(1) [Bug #11160].
[mmh] / docs / historical / mh-6.8.5 / zotnet / mf / mmuu.c
1 /* mmuu.c - routines to filter MMDF to UUCP 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
35 static char buffer[BUFSIZ],
36             tmpbuf[BUFSIZ];
37
38 long    time ();
39 char   *ctime ();
40
41 /* \f */
42
43 /* 
44  *    mmdf2uucp() - given a file descriptor to a mmdf 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     mmdf2uucp (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 = mmuu (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 static int  mmuu (in, out, nodelim)
87 FILE   *in,
88        *out;
89 int     nodelim;
90 {
91     int     i,
92             tmp_fd;
93     FILE   *tmp;
94
95     for (tmp_fd = NOTOK;;) {
96         if ((i = mmdf_file (&tmp_fd, in, &tmp, nodelim)) == DONE)
97             break;
98         else
99             if (i != OK)
100                 return i;
101         if ((i = mmdf_headers (tmp, out, nodelim)) != OK)
102             return mmdf_die (i, tmp, in, out, nodelim);
103         if ((i = mmdf_text (tmp, out, nodelim)) != OK)
104             return mmdf_die (i, tmp, in, out, nodelim);
105     }
106
107     fflush (out);
108
109     return (ferror (in) || ferror (out) ? MFERR : MFOK);
110 }
111
112 /* \f */
113
114 static int  mmdf_file (tmp_fd, in, tmp, nodelim)
115 int    *tmp_fd,
116         nodelim;
117 FILE * in, **tmp;
118 {
119     int     done,
120             fd;
121     char    tmpfil[LINESIZ];
122     FILE * out;
123
124     if (nodelim)
125         if (*tmp_fd != NOTOK)
126             return DONE;
127         else
128             if ((*tmp_fd = dup (fileno (in))) == NOTOK)
129                 return MFERR;
130             else
131                 if ((*tmp = fdopen (*tmp_fd, "r")) == NULL) {
132                     close (*tmp_fd);
133                     return MFERR;
134                 }
135                 else
136                     return OK;
137
138     if (fgets (tmpbuf, sizeof tmpbuf, in) == NULL)
139         return DONE;
140     if (!isdlm1 (tmpbuf))
141         return MFDLM;
142
143     strcpy (tmpfil, "/tmp/mmuuXXXXXX");
144     unlink (mktemp (tmpfil));
145     if ((fd = creat (tmpfil, TMPMODE)) == NOTOK)
146         return MFERR;
147     close (fd);
148
149     if ((fd = open (tmpfil, 2)) == NOTOK)
150         return MFERR;
151     if ((out = fdopen (fd, "w")) == NULL) {
152         close (fd);
153         return MFERR;
154     }
155     unlink (tmpfil);
156
157     if ((*tmp_fd = dup (fd)) == NOTOK) {
158         close (fd);
159         return MFERR;
160     }
161     if ((*tmp = fdopen (*tmp_fd, "r")) == NULL) {
162         close (fd);
163         close (*tmp_fd);
164         return MFERR;
165     }
166
167 /* \f */
168
169     for (done = FALSE;;) {
170         if (fgets (tmpbuf, sizeof tmpbuf, in) == NULL)
171             return MFDLM;
172         if (done && isdlm2 (tmpbuf))
173             break;
174         done = tmpbuf[strlen (tmpbuf) - 1] == '\n';
175         fputs (tmpbuf, out);
176     }
177
178     fclose (out);
179     fseek (*tmp, 0L, 0);
180     return OK;
181 }
182
183 /* \f */
184
185 static int  mmdf_headers (in, out, nodelim)
186             FILE * in, *out;
187 int     nodelim;
188 {
189     int     fd,
190             i,
191             tmp_fd;
192     char   *cp,
193             line[BUFSIZ],
194             from[LINESIZ],
195             date[LINESIZ],
196             tmpfil[LINESIZ];
197     FILE * tmp;
198
199     *from = *date = NULL;
200
201     strcpy (tmpfil, "/tmp/mmuuXXXXXX");
202     unlink (mktemp (tmpfil));
203     if ((fd = creat (tmpfil, TMPMODE)) == NOTOK)
204         return MFERR;
205     close (fd);
206     if ((tmp_fd = open (tmpfil, 2)) == NOTOK)
207         return MFERR;
208     unlink (tmpfil);
209
210     if ((fd = dup (tmp_fd)) == NOTOK) {
211         close (tmp_fd);
212         return MFERR;
213     }
214     if ((tmp = fdopen (fd, "w")) == NULL) {
215         close (tmp_fd);
216         close (fd);
217         return MFERR;
218     }
219
220     for (;;) {
221         switch (do_header (from, date, in, tmp)) {
222             case NOTOK: 
223                 close (tmp_fd);
224                 fclose (tmp);
225                 return MFHDR;
226
227             case OK: 
228                 continue;
229
230             case DONE: 
231                 fclose (tmp);
232                 break;
233         }
234         break;
235     }
236
237 /* \f */
238
239     if (*date == NULL || *from == NULL) {
240         if (*date)
241             strcpy (buffer, "No (valid) From: field found in message\n");
242         else
243             if (*from)
244                 strcpy (buffer, "No (valid) Date: field found in message\n");
245             else
246                 strcpy (buffer,
247                         "No (valid) From: or Date: fields found in message\n");
248         if (nodelim) {
249             if (*date == NULL) {
250                 long clock;
251
252                 time (&clock);
253                 sprintf (date, "%.24s", ctime (&clock));
254             }
255             if (*from == NULL)
256                 sprintf (from, "%s!%s", SystemName (), getusr ());
257         }
258         else
259             return MFHDR;
260     }
261     else
262         buffer[0] = NULL;
263         
264     if (nodelim && (cp = index (from, '!')) != NULL) {
265         *cp++ = NULL;
266         fprintf (out, "From %s %s remote from %s\n", cp, date, from);
267     }
268     else
269         fprintf (out, "From %s %s\n", from, date);
270
271     fprintf (out, "Munged: from %s to %s; %s\n",
272             LocalName (), SystemName (), dtimenow ());
273     if (buffer[0])
274         fprintf (out, "Illegal-Field: %s", buffer);
275     
276     if ((tmp = fdopen (tmp_fd, "r")) == NULL) {
277         close (tmp_fd);
278         return MFERR;
279     }
280     fseek (tmp, 0L, 0);
281
282     while ((i = fread (line, sizeof *line, sizeof line, tmp)) > 0)
283         fwrite (line, sizeof *line, i, out);
284     putc ('\n', out);           /* separate headers from body */
285     fclose (tmp);
286
287     return OK;
288 }
289
290 /* \f */
291
292 static int  mmdf_text (in, out, nodelim)
293 int     nodelim;
294 FILE * in, *out;
295 {
296     int     i;
297
298     if (feof (in))              /* probably no body */
299         putc ('\n', out);
300     else
301         while ((i = fread (buffer, sizeof *buffer, sizeof buffer, in)) > 0)
302             fwrite (buffer, sizeof *buffer, i, out);
303
304     if (!nodelim)
305         putc ('\n', out);
306     fclose (in);
307
308     return OK;
309 }
310
311 /* \f */
312
313 static int  do_header (from, date, in, out)
314 char   *from,
315        *date;
316 FILE * in, *out;
317 {
318     int     i,
319             margin,
320             some,
321             spat,
322             pos;
323     char   *bp,
324            *cp,
325            *pp,
326             line[BUFSIZ];
327     struct adrx *adrxp;
328     struct header  *hl;
329
330     if ((i = mfgets (in, &bp)) != OK)
331         return i;
332
333     if ((cp = index (bp, ':')) == NULL) {
334         fprintf (out, "Illegal-Field: %s\n", bp);
335         return OK;
336     }
337
338     *cp = NULL;
339     for (hl = &headers[0]; hl -> h_name; hl++)
340         if (lequal (hl -> h_name, bp))
341             break;
342
343 /* \f */
344
345     switch (hl -> h_type) {
346         case HOTHR: 
347             *cp = ':';
348             fprintf (out, "%s\n", bp);
349             break;
350
351         case HDATE: 
352             pp = ++cp;
353             if (*date != NULL || !lequal (hl -> h_name, "Date"))
354                 return OK;
355             date_convert (pp, date);
356             if (*date == NULL)
357                 fprintf (out,
358                         "Illegal-Object: %s: %s -- illegal date construct\n",
359                         hl -> h_name, pp);
360             break;
361
362         case HFROM: 
363             pp = ++cp;
364             if (*from != NULL)
365                 return OK;
366             if ((adrxp = getadrx (pp)) == NULL) {
367                 fprintf (out, "Illegal-Object: %s: %s -- %s\n",
368                         hl -> h_name, pp, "no address");
369                 return OK;      /* catch errors later (possibly) */
370             }
371             addr_convert (adrxp, from, TRUE);
372             if (*from == NULL)
373                 fprintf (out, "Illegal-Object: %s: %s -- %s\n",
374                         hl -> h_name, adrxp -> text, adrxp -> err);
375             while (getadrx (NULL))
376                 continue;
377             break;
378
379         case HADDR: 
380         case HSNDR: 
381             spat = 0;
382             some = FALSE;
383             pp = ++cp;
384             margin = pos = strlen (hl -> h_name) + 2;
385             while (adrxp = getadrx (pp)) {
386                 addr_convert (adrxp, line, FALSE);
387                 if (line[0] != NULL) {
388                     if (!spat++)
389                         fprintf (out, "%s: ", hl -> h_name);
390                     if (some++)
391                         fputs (", ", out), pos += 2;
392                     if (pos + strlen (line) >= OWIDTH) {
393                         fprintf (out, "\n%*s", margin, " ");
394                         pos = margin;
395                     }
396                     fputs (line, out);
397                     pos += strlen (line);
398                 }
399                 else {
400                     if (spat)
401                         putc ('\n', out);
402                     fprintf (out, "Illegal-Object: %s: %s -- %s\n",
403                             hl -> h_name, adrxp -> text, adrxp -> err);
404                     spat = 0;
405                     some = FALSE;
406                     pos = margin;
407                 }
408             }
409             if (spat)
410                 putc ('\n', out);
411             break;
412
413         default: 
414             return NOTOK;
415     }
416
417     return OK;
418 }
419
420 /* \f */
421
422 static addr_convert (adrxp, to, notice)
423 struct adrx *adrxp;
424 char   *to;
425 int     notice;
426 {
427     int     mboxlen,
428             uucplen;
429     char   *cp,
430             tmp[LINESIZ],
431             uucp[LINESIZ];
432     static char path[LINESIZ] = "";
433
434     if (path[0] == NULL)
435         strcpy (path, LocalName ());
436
437     if (adrxp -> err || !adrxp -> mbox) {
438         *to = NULL;
439         return;
440     }
441     if (notice)
442         strcpy (path, adrxp -> host ? adrxp -> host : LocalName ());
443
444     if (adrxp -> host == NULL)
445         if (index (adrxp -> mbox, '!') != NULL)
446             strcpy (tmp, adrxp -> mbox);
447         else
448             if (lequal (path, LocalName ()))
449                 sprintf (tmp, "%s!%s", SystemName (), adrxp -> mbox);
450             else
451                 sprintf (tmp, "%s!%s@%s", SystemName (), adrxp -> mbox, path);
452     else
453         if (index (adrxp -> mbox, '!') == NULL)
454             sprintf (tmp, "%s!%s@%s",
455                     SystemName (), adrxp -> mbox, adrxp -> host);
456         else {
457             sprintf (uucp, "%%%s", UucpChan ());
458             uucplen = strlen (uucp);
459             cp = (lequal (LocalName (), adrxp -> host)
460                     && (mboxlen = strlen (adrxp -> mbox) - uucplen) > 0)
461                 ? (adrxp -> mbox) + mboxlen : NULL;
462             if (lequal (uucp, cp))
463                 sprintf (tmp, "%.*s", mboxlen, adrxp -> mbox);
464             else
465                 if ((cp = index (adrxp -> host, '.'))
466                         && lequal (UucpChan (), cp + 1))
467                     sprintf (tmp, "%.*s!%s",
468                         cp - adrxp -> host, adrxp -> host, adrxp -> mbox);
469             else
470                 if (lequal (adrxp -> host, UucpChan ()))
471                     strcpy (tmp, adrxp -> mbox);
472             else {
473                 sprintf (uucp, "%s!", SystemName ());
474                 uucplen = strlen (uucp);
475                 if (strncmp (uucp, adrxp -> mbox, uucplen))
476                     sprintf (tmp, "%s!%s@%s",
477                             SystemName (), adrxp -> mbox, adrxp -> host);
478                 else
479                     sprintf (tmp, "%s@%s", adrxp -> mbox, adrxp -> host);
480             }
481         }
482
483     strcpy (to, tmp);
484 }
485
486 /* \f */
487
488 static  date_convert (from, to)
489 char   *from,
490        *to;
491 {
492     char   *cp;
493
494     if ((cp = dctime (dparsetime (from))) != NULL)
495         sprintf (to, "%.24s", cp);
496     else
497         *to = NULL;
498 }
499
500 /* \f */
501
502 static int  mmdf_die (error, in1, in2, out, nodelim)
503 int     error,
504         nodelim;
505 FILE * in1, *in2, *out;
506 {
507     int     i;
508     long    clock;
509     char    date[LINESIZ];
510
511     if (nodelim) {
512         fclose (in1);
513         return error;
514     }
515
516     switch (error) {
517         case MFTXT: 
518             putc ('\n', out);
519             break;
520     }
521
522     time (&clock);
523     sprintf (date, "%.24s", ctime (&clock));
524     fprintf (out, "From %s %s\nSubject: %s %s\n\n",
525             getusr (), date, "Bad MMDF mailbox - error in",
526             error == MFHDR ? "Header" : error == MFTXT ? "Body" : "Mailbox");
527
528     fprintf (out, "%s: %s\n%s\n--------\n",
529             "Error detected at line", buffer, "Message being processed");
530     fseek (in1, 0L, 0);
531     while ((i = fread (buffer, sizeof *buffer, sizeof buffer, in1)) > 0)
532         fwrite (buffer, sizeof *buffer, i, out);
533     fclose (in1);
534
535     if (!feof (in2)) {
536         fprintf (out, "--------\n%s\n--------\n%s",
537                 "Remainder of unfiltered mailbox follows", tmpbuf);
538         while ((i = fread (buffer, sizeof *buffer, sizeof buffer, in2)) > 0)
539             fwrite (buffer, sizeof *buffer, i, out);
540     }
541
542     fprintf (out, "--------\n\n");
543     fflush (out);
544
545     return error;
546 }