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