Added all of the MH sources, including RCS files, in
[mmh] / docs / historical / mh-6.8.5 / uip / rcvdist.c
1 /* rcvdist.c - a rcvmail program to distribute messages */
2 #ifndef lint
3 static char ident[] = "@(#)$Id: rcvdist.c,v 1.10 1992/12/15 00:20:22 jromine Exp $";
4 #endif  /* lint */
5
6 #include "../h/mh.h"
7 #include "../h/formatsbr.h"
8 #include "../h/rcvmail.h"
9 #include "../zotnet/tws.h"
10 #include <stdio.h>
11 #ifdef LOCALE
12 #include        <locale.h>
13 #endif
14
15 /* \f */
16
17 static struct swit switches[] = {
18 #define FORMSW  0
19     "form formfile",  4,
20
21 #define HELPSW  1
22     "help", 4,
23
24     NULL, 0
25 };
26
27 /* \f */
28
29 static char backup[BUFSIZ] = "";
30 static char drft[BUFSIZ] = "";
31 static char tmpfil[BUFSIZ] = "";
32
33 static rcvdistout();
34 /* \f */
35
36 /* ARGSUSED */
37
38 main (argc, argv)
39 int     argc;
40 char  **argv;
41 {
42     int     i,
43             child_id,
44             vecp = 1;
45     char   *addrs = NULL,
46            *cp,
47            *form = NULL,
48             buf[100],
49           **ap,
50           **argp,
51            *arguments[MAXARGS],
52            *vec[MAXARGS];
53     register    FILE * fp;
54
55 #ifdef LOCALE
56         setlocale(LC_ALL, "");
57 #endif
58     invo_name = r1bindex (argv[0], '/');
59     mts_init (invo_name);
60     if ((cp = m_find (invo_name)) != NULL) {
61         ap = brkstring (cp = getcpy (cp), " ", "\n");
62         ap = copyip (ap, arguments);
63     }
64     else
65         ap = arguments;
66     (void) copyip (argv + 1, ap);
67     argp = arguments;
68
69 /* \f */
70
71     while (cp = *argp++) {
72         if (*cp == '-')
73             switch (smatch (++cp, switches)) {
74                 case AMBIGSW: 
75                     ambigsw (cp, switches);
76                     done (1);
77                 case UNKWNSW: 
78                     vec[vecp++] = --cp;
79                     continue;
80                 case HELPSW: 
81                     (void) sprintf (buf,
82                             "%s [switches] [switches for postproc] address ...",
83                             invo_name);
84                     help (buf, switches);
85                     done (1);
86
87                 case FORMSW: 
88                     if (!(form = *argp++) || *form == '-')
89                         adios (NULLCP, "missing argument to %s", argp[-2]);
90                     continue;
91             }
92         addrs = addrs ? add (cp, add (", ", addrs)) : getcpy (cp);
93     }
94
95 /* \f */
96
97     if (addrs == NULL)
98         adios (NULLCP, "usage: %s [switches] [switches for postproc] address ...",
99             invo_name);
100
101     (void) umask (~m_gmprot ());
102     (void) strcpy (tmpfil, m_tmpfil (invo_name));
103     if ((fp = fopen (tmpfil, "w+")) == NULL)
104         adios (tmpfil, "unable to create");
105     (void) cpydata (fileno (stdin), fileno (fp), "message", tmpfil);
106     (void) fseek (fp, 0L, 0);
107     (void) strcpy (drft, m_tmpfil (invo_name));
108     rcvdistout (fp, form, addrs);
109     (void) fclose (fp);
110
111     if (distout (drft, tmpfil, backup) == NOTOK)
112         done (1);
113
114     vec[0] = r1bindex (postproc, '/');
115     vec[vecp++] = "-dist";
116     vec[vecp++] = drft;
117     vec[vecp] = NULL;
118
119     for (i = 0; (child_id = fork ()) == NOTOK && i < 5; i++)
120         sleep (5);
121     switch (child_id) {
122         case NOTOK: 
123             admonish (NULLCP, "unable to fork");/* fall */
124         case OK: 
125             execvp (postproc, vec);
126             fprintf (stderr, "unable to exec ");
127             perror (postproc);
128             _exit (1);
129
130         default: 
131             done (pidXwait (child_id, postproc));
132     }
133 /* NOTREACHED */
134 }
135
136 /* \f */
137
138 /* very similar to routine in replsbr.c */
139
140 #define SBUFSIZ 256
141
142 static int outputlinelen = OUTPUTLINELEN;
143
144 static struct format *fmt;
145
146 static int ncomps = 0;
147 static char **compbuffers = 0;
148 static struct comp **used_buf = 0;
149
150 static int dat[5];
151
152 static char *addrcomps[] = {
153     "from",
154     "sender",
155     "reply-to",
156     "to",
157     "cc",
158     "bcc",
159     "resent-from",
160     "resent-sender",
161     "resent-reply-to",
162     "resent-to",
163     "resent-cc",
164     "resent-bcc",
165     NULL
166 };
167
168
169 static  rcvdistout (inb, form, addrs)
170 register FILE *inb;
171 char   *form,
172        *addrs;
173 {
174     register int    char_read = 0,
175                     format_len,
176                     i,
177                     state;
178     register char  *tmpbuf,
179                   **nxtbuf,
180                   **ap;
181     char   *cp,
182            *scanl,
183             name[NAMESZ];
184     register struct comp   *cptr,
185                           **savecomp;
186     FILE   *out;
187
188     if ((out = fopen (drft, "w")) == NULL)
189         adios (drft, "unable to create");
190     
191     cp = new_fs (form ? form : rcvdistcomps, NULLCP, NULLCP);
192     format_len = strlen (cp);
193     ncomps = fmt_compile (cp, &fmt) + 1;
194     if ((nxtbuf = compbuffers = (char **)
195             calloc ((unsigned) ncomps, sizeof (char *)))
196             == (char **)NULL)
197         adios (NULLCP, "unable to allocate component buffers");
198     if ((savecomp = used_buf = (struct comp **)
199             calloc ((unsigned) (ncomps + 1), sizeof (struct comp *)))
200             == (struct comp **) NULL)
201         adios (NULLCP, "unable to allocate component buffer stack");
202     savecomp += ncomps + 1;
203     *--savecomp = 0;
204
205     for (i = ncomps; i--;)
206         if ((*nxtbuf++ = malloc (SBUFSIZ)) == NULL)
207             adios (NULLCP, "unable to allocate component buffer");
208     nxtbuf = compbuffers;
209     tmpbuf = *nxtbuf++;
210
211     for (ap = addrcomps; *ap; ap++) {
212         FINDCOMP (cptr, *ap);
213         if (cptr)
214             cptr -> c_type |= CT_ADDR;
215     }
216
217     FINDCOMP (cptr, "addresses");
218     if (cptr)
219         cptr -> c_text = addrs;
220
221     for (state = FLD;;) {
222         switch (state = m_getfld (state, name, tmpbuf, SBUFSIZ, inb)) {
223             case FLD: 
224             case FLDPLUS: 
225                 if (cptr = wantcomp[CHASH (name)])
226                     do {
227                         if (uleq (name, cptr -> c_name)) {
228                             char_read += msg_count;
229                             if (!cptr -> c_text) {
230                                 cptr -> c_text = tmpbuf;
231                                 *--savecomp = cptr;
232                                 tmpbuf = *nxtbuf++;
233                             }
234                             else {
235                                 i = strlen (cp = cptr -> c_text) - 1;
236                                 if (cp[i] == '\n')
237                                     if (cptr -> c_type & CT_ADDR) {
238                                         cp[i] = 0;
239                                         cp = add (",\n\t", cp);
240                                     }
241                                     else
242                                         cp = add ("\t", cp);
243                                 cptr -> c_text = add (tmpbuf, cp);
244                             }
245                             while (state == FLDPLUS) {
246                                 state = m_getfld (state, name, tmpbuf,
247                                                   SBUFSIZ, inb);
248                                 cptr -> c_text = add (tmpbuf, cptr -> c_text);
249                                 char_read += msg_count;
250                             }
251                             break;
252                         }
253                     } while (cptr = cptr -> c_next);
254
255                 while (state == FLDPLUS)
256                     state = m_getfld (state, name, tmpbuf, SBUFSIZ, inb);
257                 break;
258
259             case LENERR: 
260             case FMTERR: 
261             case BODY: 
262             case FILEEOF: 
263                 goto finished;
264
265             default: 
266                 adios (NULLCP, "m_getfld() returned %d", state);
267         }
268     }
269 finished: ;
270
271     i = format_len + char_read + 256;
272     scanl = malloc ((unsigned) i + 2);
273     dat[0] = dat[1] = dat[2] = dat[4] = 0;
274     dat[3] = outputlinelen;
275     (void) fmtscan (fmt, scanl, i, dat);
276     fputs (scanl, out);
277
278     if (ferror (out))
279         adios (drft, "error writing");
280     (void) fclose (out);
281
282     free (scanl);
283     for (nxtbuf = compbuffers, i = ncomps; cptr = *savecomp++; nxtbuf++, i--)
284         free (cptr -> c_text);
285     while (i-- > 0)
286         free (*nxtbuf++);
287     free ((char *) compbuffers);
288     free ((char *) used_buf);
289 }
290
291 /* \f */
292
293 void done (status)
294 register int     status;
295 {
296     if (backup[0])
297         (void) unlink (backup);
298     if (drft[0])
299         (void) unlink (drft);
300     if (tmpfil[0])
301         (void) unlink (tmpfil);
302
303     exit (status ? RCV_MBX : RCV_MOK);
304 }