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