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