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