Fix minor coding style issues (whitespace)
[mmh] / uip / forw.c
1 /*
2 ** forw.c -- forward a message, or group of messages.
3 **
4 ** This code is Copyright (c) 2002, by the authors of nmh.  See the
5 ** COPYRIGHT file in the root directory of the nmh distribution for
6 ** complete copyright information.
7 */
8
9 #include <h/mh.h>
10 #include <fcntl.h>
11 #include <h/fmt_scan.h>
12 #include <h/tws.h>
13 #include <h/utils.h>
14
15
16 #define IFORMAT  "digest-issue-%s"
17 #define VFORMAT  "digest-volume-%s"
18
19 static struct swit switches[] = {
20 #define ANNOSW  0
21         { "annotate", 0 },
22 #define NANNOSW  1
23         { "noannotate", 2 },
24 #define EDITRSW  2
25         { "editor editor", 0 },
26 #define FORMSW  3
27         { "form formfile", 0 },
28 #define DGSTSW  4
29         { "digest list", 0 },
30 #define ISSUESW  5
31         { "issue number", 0 },
32 #define VOLUMSW  6
33         { "volume number", 0 },
34 #define WHATSW  7
35         { "whatnowproc program", 0 },
36 #define VERSIONSW  8
37         { "Version", 0 },
38 #define HELPSW  9
39         { "help", 0 },
40 #define BILDSW  10
41         { "build", 5 },  /* interface from mhe */
42         { NULL, 0 }
43 };
44
45 static char drft[BUFSIZ];
46 static struct msgs *mp = NULL;
47
48
49 /*
50 ** static prototypes
51 */
52 static void add_forw_hdr(char *);
53 static int build_form(char *, char *, int, int);
54
55
56 int
57 main(int argc, char **argv)
58 {
59         int msgp = 0, anot = 0;
60         int issue = 0, volume = 0;
61         int in;
62         int out, msgnum;
63         char *cp, *cwd, *maildir;
64         char *digest = NULL, *ed = NULL;
65         char *folder = NULL;
66         char *form = NULL, buf[BUFSIZ], value[10];
67         char **argp, **arguments, *msgs[MAXARGS];
68         char *fmtstr;
69         int buildsw = 0;
70
71         setlocale(LC_ALL, "");
72         invo_name = mhbasename(argv[0]);
73
74         /* read user profile/context */
75         context_read();
76
77         arguments = getarguments(invo_name, argc, argv, 1);
78         argp = arguments;
79
80         while ((cp = *argp++)) {
81                 if (*cp == '-') {
82                         switch (smatch(++cp, switches)) {
83                         case AMBIGSW:
84                                 ambigsw(cp, switches);
85                                 done(1);
86                         case UNKWNSW:
87                                 adios(NULL, "-%s unknown", cp);
88
89                         case HELPSW:
90                                 snprintf(buf, sizeof(buf), "%s [+folder] [msgs] [switches]", invo_name);
91                                 print_help(buf, switches, 1);
92                                 done(1);
93                         case VERSIONSW:
94                                 print_version(invo_name);
95                                 done(1);
96
97                         case ANNOSW:
98                                 anot++;
99                                 continue;
100                         case NANNOSW:
101                                 anot = 0;
102                                 continue;
103
104                         case EDITRSW:
105                                 if (!(ed = *argp++) || *ed == '-')
106                                         adios(NULL, "missing argument to %s",
107                                                         argp[-2]);
108                                 continue;
109
110                         case WHATSW:
111                                 if (!(whatnowproc = *argp++) ||
112                                                 *whatnowproc == '-')
113                                         adios(NULL, "missing argument to %s",
114                                                         argp[-2]);
115                                 continue;
116
117                         case BILDSW:
118                                 buildsw++;
119                                 continue;
120
121                         case FORMSW:
122                                 if (!(form = *argp++) || *form == '-')
123                                         adios(NULL, "missing argument to %s",
124                                                         argp[-2]);
125                                 continue;
126
127                         case DGSTSW:
128                                 if (!(digest = *argp++) || *digest == '-')
129                                         adios(NULL, "missing argument to %s",
130                                                         argp[-2]);
131                                 //mime = 0;
132                                 continue;
133                         case ISSUESW:
134                                 if (!(cp = *argp++) || *cp == '-')
135                                         adios(NULL, "missing argument to %s",
136                                                         argp[-2]);
137                                 if ((issue = atoi(cp)) < 1)
138                                         adios(NULL, "bad argument %s %s",
139                                                         argp[-2], cp);
140                                 continue;
141                         case VOLUMSW:
142                                 if (!(cp = *argp++) || *cp == '-')
143                                         adios(NULL, "missing argument to %s",
144                                                         argp[-2]);
145                                 if ((volume = atoi(cp)) < 1)
146                                         adios(NULL, "bad argument %s %s",
147                                                         argp[-2], cp);
148                                 continue;
149                         }
150                 }
151                 if (*cp == '+' || *cp == '@') {
152                         if (folder)
153                                 adios(NULL, "only one folder at a time!");
154                         else
155                                 folder = getcpy(expandfol(cp));
156                 } else {
157                         msgs[msgp++] = cp;
158                 }
159         }
160
161         cwd = getcpy(pwd());
162         strncpy(drft, buildsw ? toabsdir("draft") : m_draft(seq_beyond),
163                         sizeof(drft));
164         /*
165         ** FIXME: (concerning MHE support (buildsw) only)
166         ** There's no check if the draft already exists. mmh has removed
167         ** this case by having the draft folder. I won't add code only to
168         ** handle this legacy issue for MHE. -- meillo@marmaro.de 2012-05
169         */
170
171         /*
172         ** Forwarding a message.
173         */
174         if (!msgp)
175                 msgs[msgp++] = seq_cur;
176         if (!folder)
177                 folder = getcurfol();
178         maildir = toabsdir(folder);
179
180         if (chdir(maildir) == NOTOK)
181                 adios(maildir, "unable to change directory to");
182
183         /* read folder and create message structure */
184         if (!(mp = folder_read(folder)))
185                 adios(NULL, "unable to read folder %s", folder);
186
187         /* check for empty folder */
188         if (mp->nummsg == 0)
189                 adios(NULL, "no messages in %s", folder);
190
191         /* parse all the message ranges/sequences and set SELECTED */
192         for (msgnum = 0; msgnum < msgp; msgnum++)
193                 if (!m_convert(mp, msgs[msgnum]))
194                         done(1);
195         seq_setprev(mp);  /* set the previous sequence */
196
197         if ((out = creat(drft, m_gmprot())) == NOTOK)
198                 adios(drft, "unable to create");
199
200         /* Open form (component) file. */
201         if (digest) {
202                 if (issue == 0) {
203                         snprintf(buf, sizeof(buf), IFORMAT, digest);
204                         if (volume == 0 && (cp = context_find(buf))
205                                         && ((issue = atoi(cp)) < 0))
206                                 issue = 0;
207                         issue++;
208                 }
209                 if (volume == 0) {
210                         snprintf(buf, sizeof(buf), VFORMAT, digest);
211                         if ((cp = context_find(buf)) == NULL ||
212                                         (volume = atoi(cp)) <= 0)
213                                 volume = 1;
214                 }
215                 if (!form)
216                         form = digestcomps;
217                 in = build_form(form, digest, volume, issue);
218                 cpydata(in, out, form, drft);
219                 close(in);
220         } else {
221                 fmtstr = new_fs(form, forwcomps);
222                 if (write(out, fmtstr, strlen(fmtstr)) != (int)strlen(fmtstr)) {
223                         adios(drft, "error writing");
224                 }
225         }
226         close(out);
227
228         add_forw_hdr(drft);
229
230         if (digest) {
231                 snprintf(buf, sizeof(buf), IFORMAT, digest);
232                 snprintf(value, sizeof(value), "%d", issue);
233                 context_replace(buf, getcpy(value));
234                 snprintf(buf, sizeof(buf), VFORMAT, digest);
235                 snprintf(value, sizeof(value), "%d", volume);
236                 context_replace(buf, getcpy(value));
237         }
238
239         context_replace(curfolder, folder); /* update current folder */
240         seq_setcur(mp, mp->lowsel);  /* update current message */
241         seq_save(mp);  /* synchronize sequences */
242         context_save();  /* save the context file */
243
244         if (buildsw)
245                 done(0);
246         what_now(ed, NOUSE, drft, NULL, 0, mp,
247                 anot ? "Forwarded" : NULL, cwd);
248         done(1);
249         return 1;
250 }
251
252
253 /*
254 ** Create an attachment header for the to be forward messages.
255 */
256 static void
257 add_forw_hdr(char *draft)
258 {
259         int msgnum;
260         char buf[BUFSIZ];
261         char *vec[MAXARGS];
262         int vecp = 0;
263
264         vec[vecp++] = "anno";
265         vec[vecp++] = "-append";
266         vec[vecp++] = "-nodate";
267         vec[vecp++] = draft;
268         vec[vecp++] = "-comp";
269         vec[vecp++] = attach_hdr;
270         vec[vecp++] = "-text";
271         snprintf(buf, sizeof buf, "+%s", mp->foldpath);
272         for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
273                 if (!is_selected(mp, msgnum)) {
274                         continue;
275                 }
276                 if (strlen(buf) + 1 + strlen(m_name(msgnum)) + 1
277                                 > sizeof buf) {
278                         adios(NULL, "Attachment header line too long. "
279                                         "Forward less messages.");
280                 }
281                 strcat(buf, " ");
282                 strcat(buf, m_name(msgnum));
283         }
284         vec[vecp++] = buf;
285         vec[vecp] = NULL;
286         if (execprog(*vec, vec) != 0) {
287                 advise(NULL, "unable to add attachment header");
288         }
289 }
290
291
292 static int
293 build_form(char *form, char *digest, int volume, int issue)
294 {
295         int in;
296         int fmtsize;
297         register char *fmtstr;
298         char *line, tmpfil[BUFSIZ];
299         FILE *tmp;
300         register struct comp *cptr;
301         struct format *fmt;
302         int dat[5];
303         char *cp = NULL;
304
305         /* Get new format string */
306         fmtstr = new_fs(form, NULL);
307         fmtsize = strlen(fmtstr) + 256;
308
309         /* Compile format string */
310         fmt_compile(fmtstr, &fmt);
311
312         FINDCOMP(cptr, "digest");
313         if (cptr)
314                 cptr->c_text = digest;
315         FINDCOMP(cptr, "date");
316         if (cptr)
317                 cptr->c_text = getcpy(dtimenow());
318
319         dat[0] = issue;
320         dat[1] = volume;
321         dat[2] = 0;
322         dat[3] = fmtsize;
323         dat[4] = 0;
324
325         cp = m_mktemp2(NULL, invo_name, NULL, &tmp);
326         if (cp == NULL) adios("forw", "unable to create temporary file");
327         strncpy(tmpfil, cp, sizeof(tmpfil));
328         unlink(tmpfil);
329         if ((in = dup(fileno(tmp))) == NOTOK)
330                 adios("dup", "unable to");
331
332         line = mh_xmalloc((unsigned) fmtsize);
333         fmt_scan(fmt, line, fmtsize, dat);
334         fputs(line, tmp);
335         free(line);
336         if (fclose(tmp))
337                 adios(tmpfil, "error writing");
338
339         lseek(in, (off_t) 0, SEEK_SET);
340         return in;
341 }