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