Beginning support for mh-format support in comp(1). Includes changes to
[mmh] / uip / comp.c
1
2 /*
3  * comp.c -- compose 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 #include <h/fmt_scan.h>
13 #include <fcntl.h>
14
15 static struct swit switches[] = {
16 #define DFOLDSW                0
17     { "draftfolder +folder", 0 },
18 #define DMSGSW                 1
19     { "draftmessage msg", 0 },
20 #define NDFLDSW                2
21     { "nodraftfolder", 0 },
22 #define EDITRSW                3
23     { "editor editor", 0 },
24 #define NEDITSW                4
25     { "noedit", 0 },
26 #define FILESW                 5
27     { "file file", 0 },
28 #define FORMSW                 6
29     { "form formfile", 0 },
30 #define USESW                  7
31     { "use", 0 },
32 #define NUSESW                 8
33     { "nouse", 0 },
34 #define WHATSW                 9
35     { "whatnowproc program", 0 },
36 #define NWHATSW               10
37     { "nowhatnowproc", 0 },
38 #define VERSIONSW             11
39     { "version", 0 },
40 #define HELPSW                12
41     { "help", 0 },
42     { NULL, 0 }
43 };
44
45 static struct swit aqrunl[] = {
46 #define NOSW          0
47     { "quit", 0 },
48 #define YESW          1
49     { "replace", 0 },
50 #define USELSW        2
51     { "use", 0 },
52 #define LISTDSW       3
53     { "list", 0 },
54 #define REFILSW       4
55     { "refile +folder", 0 },
56 #define NEWSW         5
57     { "new", 0 },
58     { NULL, 0 }
59 };
60
61 static struct swit aqrul[] = {
62     { "quit", 0 },
63     { "replace", 0 },
64     { "use", 0 },
65     { "list", 0 },
66     { "refile", 0 },
67     { NULL, 0 }
68 };
69
70
71 int
72 main (int argc, char **argv)
73 {
74     int use = NOUSE, nedit = 0, nwhat = 0;
75     int i, in, isdf = 0, out, dat[5], ncomps, format_len;
76     int outputlinelen = OUTPUTLINELEN;
77     char *cp, *cwd, *maildir, *dfolder = NULL;
78     char *ed = NULL, *file = NULL, *form = NULL;
79     char *folder = NULL, *msg = NULL, buf[BUFSIZ];
80     char drft[BUFSIZ], **argp, **arguments;
81     struct msgs *mp = NULL;
82     struct format *fmt;
83     struct stat st;
84
85 #ifdef LOCALE
86     setlocale(LC_ALL, "");
87 #endif
88     invo_name = r1bindex (argv[0], '/');
89
90     /* read user profile/context */
91     context_read();
92
93     arguments = getarguments (invo_name, argc, argv, 1);
94     argp = arguments;
95
96     while ((cp = *argp++)) {
97         if (*cp == '-') {
98             switch (smatch (++cp, switches)) {
99                 case AMBIGSW: 
100                     ambigsw (cp, switches);
101                     done (1);
102                 case UNKWNSW: 
103                     adios (NULL, "-%s unknown", cp);
104
105                 case HELPSW: 
106                     snprintf (buf, sizeof(buf), "%s [+folder] [msg] [switches]",
107                         invo_name);
108                     print_help (buf, switches, 1);
109                     done (1);
110                 case VERSIONSW:
111                     print_version(invo_name);
112                     done (1);
113
114                 case EDITRSW: 
115                     if (!(ed = *argp++) || *ed == '-')
116                         adios (NULL, "missing argument to %s", argp[-2]);
117                     nedit = 0;
118                     continue;
119                 case NEDITSW: 
120                     nedit++;
121                     continue;
122
123                 case WHATSW: 
124                     if (!(whatnowproc = *argp++) || *whatnowproc == '-')
125                         adios (NULL, "missing argument to %s", argp[-2]);
126                     nwhat = 0;
127                     continue;
128                 case NWHATSW: 
129                     nwhat++;
130                     continue;
131
132                 case FORMSW: 
133                     if (!(form = *argp++) || *form == '-')
134                         adios (NULL, "missing argument to %s", argp[-2]);
135                     continue;
136
137                 case USESW: 
138                     use++;
139                     continue;
140                 case NUSESW: 
141                     use = NOUSE;
142                     continue;
143
144                 case FILESW:    /* compatibility */
145                     if (file)
146                         adios (NULL, "only one file at a time!");
147                     if (!(file = *argp++) || *file == '-')
148                         adios (NULL, "missing argument to %s", argp[-2]);
149                     isdf = NOTOK;
150                     continue;
151
152                 case DFOLDSW: 
153                     if (dfolder)
154                         adios (NULL, "only one draft folder at a time!");
155                     if (!(cp = *argp++) || *cp == '-')
156                         adios (NULL, "missing argument to %s", argp[-2]);
157                     dfolder = path (*cp == '+' || *cp == '@' ? cp + 1 : cp,
158                             *cp != '@' ? TFOLDER : TSUBCWF);
159                     continue;
160                 case DMSGSW: 
161                     if (file)
162                         adios (NULL, "only one draft message at a time!");
163                     if (!(file = *argp++) || *file == '-')
164                         adios (NULL, "missing argument to %s", argp[-2]);
165                     continue;
166                 case NDFLDSW: 
167                     dfolder = NULL;
168                     isdf = NOTOK;
169                     continue;
170             }
171         }
172         if (*cp == '+' || *cp == '@') {
173             if (folder)
174                 adios (NULL, "only one folder at a time!");
175             else
176                 folder = pluspath (cp);
177         } else {
178             if (msg)
179                 adios (NULL, "only one message at a time!");
180             else
181                 msg = cp;
182         }
183     }
184
185     cwd = getcpy (pwd ());
186
187     if (!context_find ("path"))
188         free (path ("./", TFOLDER));
189
190     /*
191      * Check if we are using a draft folder
192      * and have specified a message in it.
193      */
194     if ((dfolder || context_find ("Draft-Folder")) && !folder && msg && !file) {
195         file = msg;
196         msg = NULL;
197     }
198     if (form && (folder || msg))
199             adios (NULL, "can't mix forms and folders/msgs");
200
201     cp = NULL;
202
203     if (folder || msg) {
204         /*
205          * Use a message as the "form" for the new message.
206          */
207         if (!msg)
208             msg = "cur";
209         if (!folder)
210             folder = getfolder (1);
211         maildir = m_maildir (folder);
212
213         if (chdir (maildir) == NOTOK)
214             adios (maildir, "unable to change directory to");
215
216         /* read folder and create message structure */
217         if (!(mp = folder_read (folder)))
218             adios (NULL, "unable to read folder %s", folder);
219
220         /* check for empty folder */
221         if (mp->nummsg == 0)
222             adios (NULL, "no messages in %s", folder);
223
224         /* parse the message range/sequence/name and set SELECTED */
225         if (!m_convert (mp, msg))
226             done (1);
227         seq_setprev (mp);       /* set the previous-sequence */
228
229         if (mp->numsel > 1)
230             adios (NULL, "only one message at a time!");
231
232         if ((in = open (form = getcpy (m_name (mp->lowsel)), O_RDONLY)) == NOTOK)
233             adios (form, "unable to open message");
234     } else {
235         if (! form)
236             form = components;
237
238         cp = new_fs(form, NULL, NULL);
239         format_len = strlen(cp);
240         ncomps = fmt_compile(cp, &fmt);
241         if (ncomps > 0) {
242             adios(NULL, "format components not supported when using comp");
243         }
244     }
245
246 try_it_again:
247     strncpy (drft, m_draft (dfolder, file, use, &isdf), sizeof(drft));
248
249     /*
250      * Check if we have an existing draft
251      */
252     if ((out = open (drft, O_RDONLY)) != NOTOK) {
253         i = fdcompare (in, out);
254         close (out);
255
256         /*
257          * If we have given -use flag, or if the
258          * draft is just the same as the components
259          * file, then no need to ask any questions.
260          */
261         if (use || i)
262             goto edit_it;
263
264         if (stat (drft, &st) == NOTOK)
265             adios (drft, "unable to stat");
266         printf ("Draft \"%s\" exists (%ld bytes).", drft, (long) st.st_size);
267         for (i = LISTDSW; i != YESW;) {
268             if (!(argp = getans ("\nDisposition? ", isdf ? aqrunl : aqrul)))
269                 done (1);
270             switch (i = smatch (*argp, isdf ? aqrunl : aqrul)) {
271                 case NOSW: 
272                     done (0);
273                 case NEWSW: 
274                     file = NULL;
275                     use = NOUSE;
276                     goto try_it_again;
277                 case YESW: 
278                     break;
279                 case USELSW:
280                     use++;
281                     goto edit_it;
282                 case LISTDSW: 
283                     showfile (++argp, drft);
284                     break;
285                 case REFILSW: 
286                     if (refile (++argp, drft) == 0)
287                         i = YESW;
288                     break;
289                 default: 
290                     advise (NULL, "say what?");
291                     break;
292             }
293         }
294     } else {
295         if (use)
296             adios (drft, "unable to open");
297     }
298
299     if ((out = creat (drft, m_gmprot ())) == NOTOK)
300         adios (drft, "unable to create");
301     if (cp) {
302         char *scanl;
303
304         i = format_len + 1024;
305         scanl = mh_xmalloc((size_t) i + 2);
306         dat[0] = 0;
307         dat[1] = 0;
308         dat[2] = 0;
309         dat[3] = outputlinelen;
310         dat[4] = 0;
311         fmt_scan(fmt, scanl, i, dat);
312         write(out, scanl, strlen(scanl));
313         free(scanl);
314     } else {
315         cpydata (in, out, form, drft);
316         close (in);
317     }
318     close (out);
319
320 edit_it:
321     context_save ();    /* save the context file */
322
323     if (nwhat)
324         done (0);
325     what_now (ed, nedit, use, drft, NULL, 0, NULLMP, NULL, 0, cwd);
326     done (1);
327     return 1;
328 }