b84632bd1a5c4347cb85191a0538e54e13c67e70
[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 NWHATSW  9
39         { "nowhatnowproc", 0 },
40 #define VERSIONSW  10
41         { "version", 0 },
42 #define HELPSW  11
43         { "help", 0 },
44
45 #ifdef MHE
46 #define BILDSW  12
47         { "build", 5 },  /* interface from mhe */
48 #endif /* MHE */
49
50         { NULL, 0 }
51 };
52
53 static char drft[BUFSIZ];
54 static struct msgs *mp = NULL;
55
56
57 /*
58 ** static prototypes
59 */
60 static void add_forw_hdr(char *);
61 static int build_form(char *, char *, int, int);
62
63
64 int
65 main(int argc, char **argv)
66 {
67         int msgp = 0, anot = 0;
68         int issue = 0, volume = 0;
69         int nedit = 0, nwhat = 0, in;
70         int out, msgnum;
71         char *cp, *cwd, *maildir;
72         char *digest = NULL, *ed = NULL;
73         char *folder = NULL;
74         char *form = NULL, buf[BUFSIZ], value[10];
75         char **argp, **arguments, *msgs[MAXARGS];
76
77 #ifdef MHE
78         int buildsw = 0;
79 #endif /* MHE */
80
81 #ifdef LOCALE
82         setlocale(LC_ALL, "");
83 #endif
84         invo_name = mhbasename(argv[0]);
85
86         /* read user profile/context */
87         context_read();
88
89         arguments = getarguments(invo_name, argc, argv, 1);
90         argp = arguments;
91
92         while ((cp = *argp++)) {
93                 if (*cp == '-') {
94                         switch (smatch(++cp, switches)) {
95                         case AMBIGSW:
96                                 ambigsw(cp, switches);
97                                 done(1);
98                         case UNKWNSW:
99                                 adios(NULL, "-%s unknown", cp);
100
101                         case HELPSW:
102                                 snprintf(buf, sizeof(buf), "%s [+folder] [msgs] [switches]", invo_name);
103                                 print_help(buf, switches, 1);
104                                 done(1);
105                         case VERSIONSW:
106                                 print_version(invo_name);
107                                 done(1);
108
109                         case ANNOSW:
110                                 anot++;
111                                 continue;
112                         case NANNOSW:
113                                 anot = 0;
114                                 continue;
115
116                         case EDITRSW:
117                                 if (!(ed = *argp++) || *ed == '-')
118                                         adios(NULL, "missing argument to %s",
119                                                         argp[-2]);
120                                 nedit = 0;
121                                 continue;
122                         case NEDITSW:
123                                 nedit++;
124                                 continue;
125
126                         case WHATSW:
127                                 if (!(whatnowproc = *argp++) ||
128                                                 *whatnowproc == '-')
129                                         adios(NULL, "missing argument to %s",
130                                                         argp[-2]);
131                                 nwhat = 0;
132                                 continue;
133 #ifdef MHE
134                         case BILDSW:
135                                 buildsw++;  /* fall... */
136 #endif /* MHE */
137                         case NWHATSW:
138                                 nwhat++;
139                                 continue;
140
141                         case FORMSW:
142                                 if (!(form = *argp++) || *form == '-')
143                                         adios(NULL, "missing argument to %s",
144                                                         argp[-2]);
145                                 continue;
146
147                         case DGSTSW:
148                                 if (!(digest = *argp++) || *digest == '-')
149                                         adios(NULL, "missing argument to %s",
150                                                         argp[-2]);
151                                 //mime = 0;
152                                 continue;
153                         case ISSUESW:
154                                 if (!(cp = *argp++) || *cp == '-')
155                                         adios(NULL, "missing argument to %s",
156                                                         argp[-2]);
157                                 if ((issue = atoi(cp)) < 1)
158                                         adios(NULL, "bad argument %s %s",
159                                                         argp[-2], cp);
160                                 continue;
161                         case VOLUMSW:
162                                 if (!(cp = *argp++) || *cp == '-')
163                                         adios(NULL, "missing argument to %s",
164                                                         argp[-2]);
165                                 if ((volume = atoi(cp)) < 1)
166                                         adios(NULL, "bad argument %s %s",
167                                                         argp[-2], cp);
168                                 continue;
169                         }
170                 }
171                 if (*cp == '+' || *cp == '@') {
172                         if (folder)
173                                 adios(NULL, "only one folder at a time!");
174                         else
175                                 folder = getcpy(expandfol(cp));
176                 } else {
177                         msgs[msgp++] = cp;
178                 }
179         }
180
181         cwd = getcpy(pwd());
182
183 #ifdef MHE
184         strncpy(drft, buildsw ? toabsdir("draft")
185                 : m_draft(seq_beyond), sizeof(drft));
186 #else
187         strncpy(drft, m_draft(seq_beyond), sizeof(drft));
188 #endif /* MHE */
189
190         /*
191         ** Forwarding a message.
192         */
193         if (!msgp)
194                 msgs[msgp++] = seq_cur;
195         if (!folder)
196                 folder = getcurfol();
197         maildir = toabsdir(folder);
198
199         if (chdir(maildir) == NOTOK)
200                 adios(maildir, "unable to change directory to");
201
202         /* read folder and create message structure */
203         if (!(mp = folder_read(folder)))
204                 adios(NULL, "unable to read folder %s", folder);
205
206         /* check for empty folder */
207         if (mp->nummsg == 0)
208                 adios(NULL, "no messages in %s", folder);
209
210         /* parse all the message ranges/sequences and set SELECTED */
211         for (msgnum = 0; msgnum < msgp; msgnum++)
212                 if (!m_convert(mp, msgs[msgnum]))
213                         done(1);
214         seq_setprev(mp);  /* set the previous sequence */
215
216         /* Open form (component) file. */
217         if (digest) {
218                 if (issue == 0) {
219                         snprintf(buf, sizeof(buf), IFORMAT, digest);
220                         if (volume == 0 && (cp = context_find(buf))
221                                         && ((issue = atoi(cp)) < 0))
222                                 issue = 0;
223                         issue++;
224                 }
225                 if (volume == 0)
226                         snprintf(buf, sizeof(buf), VFORMAT, digest);
227                 if ((cp = context_find(buf)) == NULL ||
228                                 (volume = atoi(cp)) <= 0)
229                         volume = 1;
230                 if (!form)
231                         form = digestcomps;
232                 in = build_form(form, digest, volume, issue);
233         } else
234                 in = open_form(&form, forwcomps);
235
236         if ((out = creat(drft, m_gmprot())) == NOTOK)
237                 adios(drft, "unable to create");
238
239         /*
240         ** copy the components into the draft
241         */
242         cpydata(in, out, form, drft);
243         close(in);
244         close(out);
245         add_forw_hdr(drft);
246
247         if (digest) {
248                 snprintf(buf, sizeof(buf), IFORMAT, digest);
249                 snprintf(value, sizeof(value), "%d", issue);
250                 context_replace(buf, getcpy(value));
251                 snprintf(buf, sizeof(buf), VFORMAT, digest);
252                 snprintf(value, sizeof(value), "%d", volume);
253                 context_replace(buf, getcpy(value));
254         }
255
256         context_replace(curfolder, folder); /* update current folder */
257         seq_setcur(mp, mp->lowsel);  /* update current message */
258         seq_save(mp);  /* synchronize sequences */
259         context_save();  /* save the context file */
260
261         if (nwhat)
262                 done(0);
263         what_now(ed, nedit, NOUSE, drft, NULL, 0, mp,
264                 anot ? "Forwarded" : NULL, cwd);
265         done(1);
266         return 1;
267 }
268
269
270 /*
271 ** Create an attachment header for the to be forward messages.
272 */
273 static void
274 add_forw_hdr(char *draft)
275 {
276         int msgnum;
277         char buffer[BUFSIZ];
278
279         snprintf(buffer, sizeof(buffer), "+%s", mp->foldpath);
280         for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
281                 if (!is_selected(mp, msgnum)) {
282                         continue;
283                 }
284                 /* TODO: improve the code */
285                 strncat(buffer, " ", sizeof(buffer)-strlen(buffer)-1);
286                 strncat(buffer, m_name(msgnum),
287                                 sizeof(buffer)-strlen(buffer)-1);
288         }
289         annotate(draft, attach_hdr, buffer, 0, -2, 1);
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 *nfs;
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         nfs = new_fs(form, NULL, NULL);
308         fmtsize = strlen(nfs) + 256;
309
310         /* Compile format string */
311         fmt_compile(nfs, &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(0));
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 }