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