Add support for a -subject switch to comp.
[mmh] / uip / repl.c
1
2 /*
3  * repl.c -- reply to a message
4  *
5  * This code is Copyright (c) 2002, by the authors of nmh.  See the
6  * COPYRIGHT file in the root directory of the nmh distribution for
7  * complete copyright information.
8  */
9
10 #include <h/mh.h>
11 #include <h/utils.h>
12
13
14 static struct swit switches[] = {
15 #define GROUPSW                0
16     { "group", 0 },
17 #define NGROUPSW               1
18     { "nogroup", 0 },
19 #define ANNOSW                 2
20     { "annotate", 0 },
21 #define NANNOSW                3
22     { "noannotate", 0 },
23 #define CCSW                   4
24     { "cc all|to|cc|me", 0 },
25 #define NCCSW                  5
26     { "nocc type", 0 },
27 #define DFOLDSW                6
28     { "draftfolder +folder", 0 },
29 #define DMSGSW                 7
30     { "draftmessage msg", 0 },
31 #define NDFLDSW                8
32     { "nodraftfolder", 0 },
33 #define EDITRSW                9
34     { "editor editor", 0 },
35 #define NEDITSW               10
36     { "noedit", 0 },
37 #define FCCSW                 11
38     { "fcc folder", 0 },
39 #define FILTSW                12
40     { "filter filterfile", 0 },
41 #define FORMSW                13
42     { "form formfile", 0 },
43 #define FRMTSW                14
44     { "format", 5 },
45 #define NFRMTSW               15
46     { "noformat", 7 },
47 #define INPLSW                16
48     { "inplace", 0 },
49 #define NINPLSW               17
50     { "noinplace", 0 },
51 #define MIMESW                18
52     { "mime", 0 },
53 #define NMIMESW               19
54     { "nomime", 0 },
55 #define QURYSW                20
56     { "query", 0 },
57 #define NQURYSW               21
58     { "noquery", 0 },
59 #define WHATSW                22
60     { "whatnowproc program", 0 },
61 #define NWHATSW               23
62     { "nowhatnowproc", 0 },
63 #define WIDTHSW               24
64     { "width columns", 0 },
65 #define VERSIONSW             25
66     { "version", 0 },
67 #define HELPSW                26
68     { "help", 0 },
69 #define FILESW                27
70     { "file file", 4 },                 /* interface from msh */
71 #define BILDSW                28
72     { "build", 5 },                     /* interface from mhe */
73
74     { NULL, 0 }
75 };
76
77 static struct swit ccswitches[] = {
78 #define CTOSW   0
79     { "to", 0 },
80 #define CCCSW   1
81     { "cc", 0 },
82 #define CMESW   2
83     { "me", 0 },
84 #define CALSW   3
85     { "all", 0 },
86     { NULL, 0 }
87 };
88
89 static struct swit aqrnl[] = {
90 #define NOSW         0
91     { "quit", 0 },
92 #define YESW         1
93     { "replace", 0 },
94 #define LISTDSW      2
95     { "list", 0 },
96 #define REFILSW      3
97     { "refile +folder", 0 },
98 #define NEWSW        4
99     { "new", 0 },
100     { NULL, 0 }
101 };
102
103 static struct swit aqrl[] = {
104     { "quit", 0 },
105     { "replace", 0 },
106     { "list", 0 },
107     { "refile +folder", 0 },
108     { NULL, 0 }
109 };
110
111 short ccto = -1;                /* global for replsbr */
112 short cccc = -1;
113 short ccme = -1;
114 short querysw = 0;
115
116 short outputlinelen = OUTPUTLINELEN;
117 short groupreply = 0;           /* Is this a group reply?        */
118
119 int mime = 0;                   /* include original as MIME part */
120 char *form   = NULL;            /* form (components) file        */
121 char *filter = NULL;            /* message filter file           */
122 char *fcc    = NULL;            /* folders to add to Fcc: header */
123
124
125 /*
126  * prototypes
127  */
128 void docc (char *, int);
129
130
131 int
132 main (int argc, char **argv)
133 {
134     int i, isdf = 0;
135     int anot = 0, inplace = 1;
136     int nedit = 0, nwhat = 0;
137     char *cp, *cwd, *dp, *maildir, *file = NULL;
138     char *folder = NULL, *msg = NULL, *dfolder = NULL;
139     char *dmsg = NULL, *ed = NULL, drft[BUFSIZ], buf[BUFSIZ];
140     char **argp, **arguments;
141     struct msgs *mp = NULL;
142     struct stat st;
143     FILE *in;
144
145     int buildsw = 0;
146
147 #ifdef LOCALE
148     setlocale(LC_ALL, "");
149 #endif
150     invo_name = r1bindex (argv[0], '/');
151
152     /* read user profile/context */
153     context_read();
154
155     arguments = getarguments (invo_name, argc, argv, 1);
156     argp = arguments;
157
158     while ((cp = *argp++)) {
159         if (*cp == '-') {
160             switch (smatch (++cp, switches)) {
161                 case AMBIGSW: 
162                     ambigsw (cp, switches);
163                     done (1);
164                 case UNKWNSW: 
165                     adios (NULL, "-%s unknown", cp);
166
167                 case HELPSW: 
168                     snprintf (buf, sizeof(buf), "%s: [+folder] [msg] [switches]",
169                         invo_name);
170                     print_help (buf, switches, 1);
171                     done (0);
172                 case VERSIONSW:
173                     print_version(invo_name);
174                     done (1);
175
176                 case GROUPSW:
177                     groupreply++;
178                     continue;
179                 case NGROUPSW:
180                     groupreply = 0;
181                     continue;
182
183                 case ANNOSW: 
184                     anot++;
185                     continue;
186                 case NANNOSW: 
187                     anot = 0;
188                     continue;
189
190                 case CCSW: 
191                     if (!(cp = *argp++) || *cp == '-')
192                         adios (NULL, "missing argument to %s", argp[-2]);
193                     docc (cp, 1);
194                     continue;
195                 case NCCSW: 
196                     if (!(cp = *argp++) || *cp == '-')
197                         adios (NULL, "missing argument to %s", argp[-2]);
198                     docc (cp, 0);
199                     continue;
200
201                 case EDITRSW: 
202                     if (!(ed = *argp++) || *ed == '-')
203                         adios (NULL, "missing argument to %s", argp[-2]);
204                     nedit = 0;
205                     continue;
206                 case NEDITSW:
207                     nedit++;
208                     continue;
209                     
210                 case WHATSW: 
211                     if (!(whatnowproc = *argp++) || *whatnowproc == '-')
212                         adios (NULL, "missing argument to %s", argp[-2]);
213                     nwhat = 0;
214                     continue;
215                 case BILDSW: 
216                     buildsw++;  /* fall... */
217                 case NWHATSW: 
218                     nwhat++;
219                     continue;
220
221                 case FCCSW: 
222                     if (!(cp = *argp++) || *cp == '-')
223                         adios (NULL, "missing argument to %s", argp[-2]);
224                     dp = NULL;
225                     if (*cp == '@')
226                         cp = dp = path (cp + 1, TSUBCWF);
227                     if (fcc)
228                         fcc = add (", ", fcc);
229                     fcc = add (cp, fcc);
230                     if (dp)
231                         free (dp);
232                     continue;
233
234                 case FILESW: 
235                     if (file)
236                         adios (NULL, "only one file at a time!");
237                     if (!(cp = *argp++) || *cp == '-')
238                         adios (NULL, "missing argument to %s", argp[-2]);
239                     file = path (cp, TFILE);
240                     continue;
241                 case FILTSW:
242                     if (!(cp = *argp++) || *cp == '-')
243                         adios (NULL, "missing argument to %s", argp[-2]);
244                     filter = getcpy (etcpath (cp));
245                     mime = 0;
246                     continue;
247                 case FORMSW: 
248                     if (!(form = *argp++) || *form == '-')
249                         adios (NULL, "missing argument to %s", argp[-2]);
250                     continue;
251
252                 case FRMTSW: 
253                     filter = getcpy (etcpath (mhlreply));
254                     mime = 0;
255                     continue;
256                 case NFRMTSW: 
257                     filter = NULL;
258                     continue;
259
260                 case INPLSW: 
261                     inplace++;
262                     continue;
263                 case NINPLSW: 
264                     inplace = 0;
265                     continue;
266
267                 case MIMESW:
268                     mime++;
269                     filter = NULL;
270                     continue;
271                 case NMIMESW:
272                     mime = 0;
273                     continue;
274
275                 case QURYSW: 
276                     querysw++;
277                     continue;
278                 case NQURYSW: 
279                     querysw = 0;
280                     continue;
281
282                 case WIDTHSW: 
283                     if (!(cp = *argp++) || *cp == '-')
284                         adios (NULL, "missing argument to %s", argp[-2]);
285                     if ((outputlinelen = atoi (cp)) < 10)
286                         adios (NULL, "impossible width %d", outputlinelen);
287                     continue;
288
289                 case DFOLDSW: 
290                     if (dfolder)
291                         adios (NULL, "only one draft folder at a time!");
292                     if (!(cp = *argp++) || *cp == '-')
293                         adios (NULL, "missing argument to %s", argp[-2]);
294                     dfolder = path (*cp == '+' || *cp == '@' ? cp + 1 : cp,
295                                     *cp != '@' ? TFOLDER : TSUBCWF);
296                     continue;
297                 case DMSGSW:
298                     if (dmsg)
299                         adios (NULL, "only one draft message at a time!");
300                     if (!(dmsg = *argp++) || *dmsg == '-')
301                         adios (NULL, "missing argument to %s", argp[-2]);
302                     continue;
303                 case NDFLDSW: 
304                     dfolder = NULL;
305                     isdf = NOTOK;
306                     continue;
307             }
308         }
309         if (*cp == '+' || *cp == '@') {
310             if (folder)
311                 adios (NULL, "only one folder at a time!");
312             else
313                 folder = pluspath (cp);
314         } else {
315             if (msg)
316                 adios (NULL, "only one message at a time!");
317             else
318                 msg = cp;
319         }
320     }
321
322     if (ccto == -1) 
323         ccto = groupreply;
324     if (cccc == -1)
325         cccc = groupreply;
326     if (ccme == -1)
327         ccme = groupreply;
328
329     cwd = getcpy (pwd ());
330
331     if (!context_find ("path"))
332         free (path ("./", TFOLDER));
333     if (file && (msg || folder))
334         adios (NULL, "can't mix files and folders/msgs");
335
336 try_it_again:
337
338     strncpy (drft, buildsw ? m_maildir ("reply")
339                           : m_draft (dfolder, NULL, NOUSE, &isdf), sizeof(drft));
340
341     /* Check if a draft exists */
342     if (!buildsw && stat (drft, &st) != NOTOK) {
343         printf ("Draft \"%s\" exists (%ld bytes).", drft, (long) st.st_size);
344         for (i = LISTDSW; i != YESW;) {
345             if (!(argp = getans ("\nDisposition? ", isdf ? aqrnl : aqrl)))
346                 done (1);
347             switch (i = smatch (*argp, isdf ? aqrnl : aqrl)) {
348                 case NOSW: 
349                     done (0);
350                 case NEWSW: 
351                     dmsg = NULL;
352                     goto try_it_again;
353                 case YESW: 
354                     break;
355                 case LISTDSW: 
356                     showfile (++argp, drft);
357                     break;
358                 case REFILSW: 
359                     if (refile (++argp, drft) == 0)
360                         i = YESW;
361                     break;
362                 default: 
363                     advise (NULL, "say what?");
364                     break;
365             }
366         }
367     }
368
369     if (file) {
370         /*
371          * We are replying to a file.
372          */
373         anot = 0;       /* we don't want to annotate a file */
374     } else {
375         /*
376          * We are replying to a message.
377          */
378         if (!msg)
379             msg = "cur";
380         if (!folder)
381             folder = getfolder (1);
382         maildir = m_maildir (folder);
383
384         if (chdir (maildir) == NOTOK)
385             adios (maildir, "unable to change directory to");
386
387         /* read folder and create message structure */
388         if (!(mp = folder_read (folder)))
389             adios (NULL, "unable to read folder %s", folder);
390
391         /* check for empty folder */
392         if (mp->nummsg == 0)
393             adios (NULL, "no messages in %s", folder);
394
395         /* parse the message range/sequence/name and set SELECTED */
396         if (!m_convert (mp, msg))
397             done (1);
398         seq_setprev (mp);       /* set the previous-sequence */
399
400         if (mp->numsel > 1)
401             adios (NULL, "only one message at a time!");
402
403         context_replace (pfolder, folder);      /* update current folder   */
404         seq_setcur (mp, mp->lowsel);    /* update current message  */
405         seq_save (mp);                  /* synchronize sequences   */
406         context_save ();                        /* save the context file   */
407     }
408
409     msg = file ? file : getcpy (m_name (mp->lowsel));
410
411     if ((in = fopen (msg, "r")) == NULL)
412         adios (msg, "unable to open");
413
414     /* find form (components) file */
415     if (!form) {
416         if (groupreply)
417             form = etcpath (replgroupcomps);
418         else
419             form = etcpath (replcomps);
420     }
421
422     replout (in, msg, drft, mp, outputlinelen, mime, form, filter, fcc);
423     fclose (in);
424
425     if (nwhat)
426         done (0);
427     what_now (ed, nedit, NOUSE, drft, msg, 0, mp,
428             anot ? "Replied" : NULL, inplace, cwd);
429     done (1);
430     return 1;
431 }
432
433 void
434 docc (char *cp, int ccflag)
435 {
436     switch (smatch (cp, ccswitches)) {
437         case AMBIGSW: 
438             ambigsw (cp, ccswitches);
439             done (1);
440         case UNKWNSW: 
441             adios (NULL, "-%scc %s unknown", ccflag ? "" : "no", cp);
442
443         case CTOSW: 
444             ccto = ccflag;
445             break;
446
447         case CCCSW: 
448             cccc = ccflag;
449             break;
450
451         case CMESW: 
452             ccme = ccflag;
453             break;
454
455         case CALSW: 
456             ccto = cccc = ccme = ccflag;
457             break;
458     }
459 }