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