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