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