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