]> diplodocus.org Git - nmh/blob - uip/rcvdist.c
73c86b39d631b57e3be0cc9b09546e512947b573
[nmh] / uip / rcvdist.c
1 /* rcvdist.c -- asynchronously redistribute messages
2 *
3 * This code is Copyright (c) 2002, by the authors of nmh. See the
4 * COPYRIGHT file in the root directory of the nmh distribution for
5 * complete copyright information.
6 */
7
8 #include "h/mh.h"
9 #include "sbr/cpydata.h"
10 #include "sbr/context_find.h"
11 #include "sbr/ambigsw.h"
12 #include "sbr/pidstatus.h"
13 #include "sbr/print_version.h"
14 #include "sbr/print_help.h"
15 #include "sbr/arglist.h"
16 #include "sbr/error.h"
17 #include "h/fmt_scan.h"
18 #include "h/rcvmail.h"
19 #include "h/tws.h"
20 #include "h/mts.h"
21 #include "h/done.h"
22 #include "h/utils.h"
23 #include "sbr/m_mktemp.h"
24
25 #define RCVDIST_SWITCHES \
26 X("form formfile", 4, FORMSW) \
27 X("version", 0, VERSIONSW) \
28 X("help", 0, HELPSW) \
29
30 #define X(sw, minchars, id) id,
31 DEFINE_SWITCH_ENUM(RCVDIST);
32 #undef X
33
34 #define X(sw, minchars, id) { sw, minchars, id },
35 DEFINE_SWITCH_ARRAY(RCVDIST, switches);
36 #undef X
37
38 static char backup[BUFSIZ] = "";
39 static char drft[BUFSIZ] = "";
40 static char tmpfil[BUFSIZ] = "";
41
42 /*
43 * prototypes
44 */
45 static void rcvdistout (FILE *, char *, char *);
46 static void unlink_done (int) NORETURN;
47
48
49 int
50 main (int argc, char **argv)
51 {
52 pid_t child_id;
53 int vecp;
54 char *addrs = NULL, *cp, *form = NULL, buf[BUFSIZ], *program;
55 char **argp, **arguments, **vec;
56 FILE *fp;
57 char *tfile = NULL;
58
59 if (nmh_init(argv[0], true, false)) { return 1; }
60
61 set_done(unlink_done);
62
63 /*
64 * Configure this now, since any unknown switches to rcvdist get
65 * sent to postproc
66 */
67
68 vec = argsplit(postproc, &program, &vecp);
69
70 mts_init ();
71 arguments = getarguments (invo_name, argc, argv, 1);
72 argp = arguments;
73
74 while ((cp = *argp++)) {
75 if (*cp == '-') {
76 switch (smatch (++cp, switches)) {
77 case AMBIGSW:
78 ambigsw (cp, switches);
79 done (1);
80 case UNKWNSW:
81 vec[vecp++] = --cp;
82 continue;
83
84 case HELPSW:
85 snprintf (buf, sizeof(buf),
86 "%s [switches] [switches for postproc] address ...",
87 invo_name);
88 print_help (buf, switches, 1);
89 done (0);
90 case VERSIONSW:
91 print_version(invo_name);
92 done (0);
93
94 case FORMSW:
95 if (!(form = *argp++) || *form == '-')
96 die("missing argument to %s", argp[-2]);
97 continue;
98 }
99 }
100 addrs = addrs ? add (cp, add (", ", addrs)) : mh_xstrdup(cp);
101 }
102
103 if (addrs == NULL)
104 die("usage: %s [switches] [switches for postproc] address ...",
105 invo_name);
106
107 umask (~m_gmprot ());
108
109 if ((tfile = m_mktemp2(NULL, invo_name, NULL, &fp)) == NULL) {
110 die("unable to create temporary file in %s", get_temp_dir());
111 }
112 strncpy (tmpfil, tfile, sizeof(tmpfil));
113
114 cpydata (fileno (stdin), fileno (fp), "message", tmpfil);
115 fseek (fp, 0L, SEEK_SET);
116
117 if ((tfile = m_mktemp2(NULL, invo_name, NULL, NULL)) == NULL) {
118 die("unable to create temporary file in %s", get_temp_dir());
119 }
120 strncpy (drft, tfile, sizeof(tmpfil));
121
122 rcvdistout (fp, form, addrs);
123 fclose (fp);
124
125 if (distout (drft, tmpfil, backup) == NOTOK)
126 done (1);
127
128 vec[vecp++] = "-dist";
129 if ((cp = context_find ("mhlproc"))) {
130 vec[vecp++] = "-mhlproc";
131 vec[vecp++] = cp;
132 }
133 vec[vecp++] = drft;
134 vec[vecp] = NULL;
135
136 child_id = fork();
137 switch (child_id) {
138 case NOTOK:
139 adios("fork", "failed:");
140
141 case OK:
142 execvp (program, vec);
143 fprintf (stderr, "unable to exec ");
144 perror (postproc);
145 _exit (1);
146
147 default:
148 done (pidXwait(child_id, postproc));
149 }
150
151 return 0; /* dead code to satisfy the compiler */
152 }
153
154 /* very similar to routine in replsbr.c */
155
156 static int outputlinelen = OUTPUTLINELEN;
157
158 static struct format *fmt;
159
160 static int dat[5];
161
162 static char *addrcomps[] = {
163 "from",
164 "sender",
165 "reply-to",
166 "to",
167 "cc",
168 "bcc",
169 "resent-from",
170 "resent-sender",
171 "resent-reply-to",
172 "resent-to",
173 "resent-cc",
174 "resent-bcc",
175 NULL
176 };
177
178
179 static void
180 rcvdistout (FILE *inb, char *form, char *addrs)
181 {
182 int char_read = 0, format_len, i, state;
183 char **ap;
184 char *cp, name[NAMESZ], tmpbuf[NMH_BUFSIZ];
185 charstring_t scanl;
186 struct comp *cptr;
187 FILE *out;
188 m_getfld_state_t gstate;
189
190 if (!(out = fopen (drft, "w")))
191 adios (drft, "unable to create");
192
193 /* get new format string */
194 cp = new_fs (form ? form : rcvdistcomps, NULL, NULL);
195 format_len = strlen (cp);
196 fmt_compile (cp, &fmt, 1);
197
198 for (ap = addrcomps; *ap; ap++) {
199 cptr = fmt_findcomp (*ap);
200 if (cptr)
201 cptr->c_type |= CT_ADDR;
202 }
203
204 cptr = fmt_findcomp ("addresses");
205 if (cptr)
206 cptr->c_text = addrs;
207
208 gstate = m_getfld_state_init(inb);
209 for (;;) {
210 int msg_count = sizeof tmpbuf;
211 switch (state = m_getfld2(&gstate, name, tmpbuf, &msg_count)) {
212 case FLD:
213 case FLDPLUS:
214 i = fmt_addcomptext(name, tmpbuf);
215 if (i != -1) {
216 char_read += msg_count;
217 while (state == FLDPLUS) {
218 msg_count = sizeof tmpbuf;
219 state = m_getfld2(&gstate, name, tmpbuf, &msg_count);
220 fmt_appendcomp(i, name, tmpbuf);
221 char_read += msg_count;
222 }
223 }
224
225 while (state == FLDPLUS) {
226 msg_count = sizeof tmpbuf;
227 state = m_getfld2(&gstate, name, tmpbuf, &msg_count);
228 }
229 break;
230
231 case LENERR:
232 case FMTERR:
233 case BODY:
234 case FILEEOF:
235 goto finished;
236
237 default:
238 die("m_getfld2() returned %d", state);
239 }
240 }
241 finished: ;
242 m_getfld_state_destroy (&gstate);
243
244 i = format_len + char_read + 256;
245 scanl = charstring_create (i + 2);
246 dat[0] = dat[1] = dat[2] = dat[4] = 0;
247 dat[3] = outputlinelen;
248 fmt_scan (fmt, scanl, i, dat, NULL);
249 fputs (charstring_buffer (scanl), out);
250
251 if (ferror (out))
252 adios (drft, "error writing");
253 fclose (out);
254
255 charstring_free (scanl);
256 fmt_free(fmt, 1);
257 }
258
259
260 static void NORETURN
261 unlink_done (int status)
262 {
263 if (backup[0])
264 (void) m_unlink (backup);
265 if (drft[0])
266 (void) m_unlink (drft);
267 if (tmpfil[0])
268 (void) m_unlink (tmpfil);
269
270 exit (status ? RCV_MBX : RCV_MOK);
271 }