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