Add/update copyright notice in all source code files.
[mmh] / uip / comp.c
1
2 /*
3  * comp.c -- compose 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 <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;
76     char *cp, *cwd, *maildir, *dfolder = NULL;
77     char *ed = NULL, *file = NULL, *form = NULL;
78     char *folder = NULL, *msg = NULL, buf[BUFSIZ];
79     char drft[BUFSIZ], **argp, **arguments;
80     struct msgs *mp = NULL;
81     struct stat st;
82
83 #ifdef LOCALE
84     setlocale(LC_ALL, "");
85 #endif
86     invo_name = r1bindex (argv[0], '/');
87
88     /* read user profile/context */
89     context_read();
90
91     arguments = getarguments (invo_name, argc, argv, 1);
92     argp = arguments;
93
94     while ((cp = *argp++)) {
95         if (*cp == '-') {
96             switch (smatch (++cp, switches)) {
97                 case AMBIGSW: 
98                     ambigsw (cp, switches);
99                     done (1);
100                 case UNKWNSW: 
101                     adios (NULL, "-%s unknown", cp);
102
103                 case HELPSW: 
104                     snprintf (buf, sizeof(buf), "%s [+folder] [msg] [switches]",
105                         invo_name);
106                     print_help (buf, switches, 1);
107                     done (1);
108                 case VERSIONSW:
109                     print_version(invo_name);
110                     done (1);
111
112                 case EDITRSW: 
113                     if (!(ed = *argp++) || *ed == '-')
114                         adios (NULL, "missing argument to %s", argp[-2]);
115                     nedit = 0;
116                     continue;
117                 case NEDITSW: 
118                     nedit++;
119                     continue;
120
121                 case WHATSW: 
122                     if (!(whatnowproc = *argp++) || *whatnowproc == '-')
123                         adios (NULL, "missing argument to %s", argp[-2]);
124                     nwhat = 0;
125                     continue;
126                 case NWHATSW: 
127                     nwhat++;
128                     continue;
129
130                 case FORMSW: 
131                     if (!(form = *argp++) || *form == '-')
132                         adios (NULL, "missing argument to %s", argp[-2]);
133                     continue;
134
135                 case USESW: 
136                     use++;
137                     continue;
138                 case NUSESW: 
139                     use = NOUSE;
140                     continue;
141
142                 case FILESW:    /* compatibility */
143                     if (file)
144                         adios (NULL, "only one file at a time!");
145                     if (!(file = *argp++) || *file == '-')
146                         adios (NULL, "missing argument to %s", argp[-2]);
147                     isdf = NOTOK;
148                     continue;
149
150                 case DFOLDSW: 
151                     if (dfolder)
152                         adios (NULL, "only one draft folder at a time!");
153                     if (!(cp = *argp++) || *cp == '-')
154                         adios (NULL, "missing argument to %s", argp[-2]);
155                     dfolder = path (*cp == '+' || *cp == '@' ? cp + 1 : cp,
156                             *cp != '@' ? TFOLDER : TSUBCWF);
157                     continue;
158                 case DMSGSW: 
159                     if (file)
160                         adios (NULL, "only one draft message at a time!");
161                     if (!(file = *argp++) || *file == '-')
162                         adios (NULL, "missing argument to %s", argp[-2]);
163                     continue;
164                 case NDFLDSW: 
165                     dfolder = NULL;
166                     isdf = NOTOK;
167                     continue;
168             }
169         }
170         if (*cp == '+' || *cp == '@') {
171             if (folder)
172                 adios (NULL, "only one folder at a time!");
173             else
174                 folder = path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF);
175         } else {
176             if (msg)
177                 adios (NULL, "only one message at a time!");
178             else
179                 msg = cp;
180         }
181     }
182
183     cwd = getcpy (pwd ());
184
185     if (!context_find ("path"))
186         free (path ("./", TFOLDER));
187
188     /*
189      * Check if we are using a draft folder
190      * and have specified a message in it.
191      */
192     if ((dfolder || context_find ("Draft-Folder")) && !folder && msg && !file) {
193         file = msg;
194         msg = NULL;
195     }
196     if (form && (folder || msg))
197             adios (NULL, "can't mix forms and folders/msgs");
198
199     if (folder || msg) {
200         /*
201          * Use a message as the "form" for the new message.
202          */
203         if (!msg)
204             msg = "cur";
205         if (!folder)
206             folder = getfolder (1);
207         maildir = m_maildir (folder);
208
209         if (chdir (maildir) == NOTOK)
210             adios (maildir, "unable to change directory to");
211
212         /* read folder and create message structure */
213         if (!(mp = folder_read (folder)))
214             adios (NULL, "unable to read folder %s", folder);
215
216         /* check for empty folder */
217         if (mp->nummsg == 0)
218             adios (NULL, "no messages in %s", folder);
219
220         /* parse the message range/sequence/name and set SELECTED */
221         if (!m_convert (mp, msg))
222             done (1);
223         seq_setprev (mp);       /* set the previous-sequence */
224
225         if (mp->numsel > 1)
226             adios (NULL, "only one message at a time!");
227
228         if ((in = open (form = getcpy (m_name (mp->lowsel)), O_RDONLY)) == NOTOK)
229             adios (form, "unable to open message");
230     } else {
231         /*
232          * Open a component or forms file
233          */
234         if (form) {
235             if ((in = open (etcpath (form), O_RDONLY)) == NOTOK)
236                 adios (form, "unable to open form file");
237         } else {
238             if ((in = open (etcpath (components), O_RDONLY)) == NOTOK)
239                 adios (components, "unable to open default components file");
240             form = components;
241         }
242     }
243
244 try_it_again:
245     strncpy (drft, m_draft (dfolder, file, use, &isdf), sizeof(drft));
246
247     /*
248      * Check if we have an existing draft
249      */
250     if ((out = open (drft, O_RDONLY)) != NOTOK) {
251         i = fdcompare (in, out);
252         close (out);
253
254         /*
255          * If we have given -use flag, or if the
256          * draft is just the same as the components
257          * file, then no need to ask any questions.
258          */
259         if (use || i)
260             goto edit_it;
261
262         if (stat (drft, &st) == NOTOK)
263             adios (drft, "unable to stat");
264         printf ("Draft \"%s\" exists (%ld bytes).", drft, (long) st.st_size);
265         for (i = LISTDSW; i != YESW;) {
266             if (!(argp = getans ("\nDisposition? ", isdf ? aqrunl : aqrul)))
267                 done (1);
268             switch (i = smatch (*argp, isdf ? aqrunl : aqrul)) {
269                 case NOSW: 
270                     done (0);
271                 case NEWSW: 
272                     file = NULL;
273                     use = NOUSE;
274                     goto try_it_again;
275                 case YESW: 
276                     break;
277                 case USELSW:
278                     use++;
279                     goto edit_it;
280                 case LISTDSW: 
281                     showfile (++argp, drft);
282                     break;
283                 case REFILSW: 
284                     if (refile (++argp, drft) == 0)
285                         i = YESW;
286                     break;
287                 default: 
288                     advise (NULL, "say what?");
289                     break;
290             }
291         }
292     } else {
293         if (use)
294             adios (drft, "unable to open");
295     }
296
297     if ((out = creat (drft, m_gmprot ())) == NOTOK)
298         adios (drft, "unable to create");
299     cpydata (in, out, form, drft);
300     close (in);
301     close (out);
302
303 edit_it:
304     context_save ();    /* save the context file */
305
306     if (nwhat)
307         done (0);
308     what_now (ed, nedit, use, drft, NULL, 0, NULLMP, NULL, 0, cwd);
309     return done (1);
310 }