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