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