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