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