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