fbe2b2c6c5a86fe1efac1542c6b77fab661cf533
[mmh] / uip / mhbuild.c
1
2 /*
3  * mhbuild.c -- expand/translate MIME composition files
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 #include <h/signals.h>
15 #include <h/md5.h>
16 #include <errno.h>
17 #include <signal.h>
18 #include <h/mts.h>
19 #include <h/tws.h>
20 #include <h/mime.h>
21 #include <h/mhparse.h>
22 #include <h/mhcachesbr.h>
23 #include <h/utils.h>
24
25 #ifdef HAVE_SYS_WAIT_H
26 # include <sys/wait.h>
27 #endif
28
29 static struct swit switches[] = {
30 #define CHECKSW                 0
31     { "check", 0 },
32 #define NCHECKSW                1
33     { "nocheck", 0 },
34 #define EBCDICSW                2
35     { "ebcdicsafe", 0 },
36 #define NEBCDICSW               3
37     { "noebcdicsafe", 0 },
38 #define HEADSW                  4
39     { "headers", 0 },
40 #define NHEADSW                 5
41     { "noheaders", 0 },
42 #define LISTSW                  6
43     { "list", 0 },
44 #define NLISTSW                 7
45     { "nolist", 0 },
46 #define SIZESW                  8
47     { "realsize", 0 },
48 #define NSIZESW                 9
49     { "norealsize", 0 },
50 #define RFC934SW               10
51     { "rfc934mode", 0 },
52 #define NRFC934SW              11
53     { "norfc934mode", 0 },
54 #define VERBSW                 12
55     { "verbose", 0 },
56 #define NVERBSW                13
57     { "noverbose", 0 },
58 #define RCACHESW               14
59     { "rcache policy", 0 },
60 #define WCACHESW               15
61     { "wcache policy", 0 },
62 #define CONTENTIDSW            16
63     { "contentid", 0 },
64 #define NCONTENTIDSW           17
65     { "nocontentid", 0 },
66 #define VERSIONSW              18
67     { "version", 0 },
68 #define HELPSW                 19
69     { "help", 0 },
70 #define DEBUGSW                20
71     { "debug", -5 },
72     { NULL, 0 }
73 };
74
75
76 /* mhbuildsbr.c */
77 extern char *tmp;       /* directory to place temp files */
78
79 /* mhcachesbr.c */
80 extern int rcachesw;
81 extern int wcachesw;
82 extern char *cache_public;
83 extern char *cache_private;
84
85 int debugsw = 0;
86 int verbosw = 0;
87
88 int ebcdicsw = 0;
89 int listsw   = 0;
90 int rfc934sw = 0;
91 int contentidsw = 1;
92
93 /*
94  * Temporary files
95  */
96 static char infile[BUFSIZ];
97 static int unlink_infile  = 0;
98
99 static char outfile[BUFSIZ];
100 static int unlink_outfile = 0;
101
102 static void unlink_done (int) NORETURN;
103
104 /* mhbuildsbr.c */
105 CT build_mime (char *);
106 int output_message (CT, char *);
107 int output_message_fp (CT, FILE *, char*);
108
109 /* mhlistsbr.c */
110 int list_all_messages (CT *, int, int, int, int);
111
112 /* mhmisc.c */
113 void set_endian (void);
114
115 /* mhfree.c */
116 void free_content (CT);
117
118
119 int
120 main (int argc, char **argv)
121 {
122     int sizesw = 1, headsw = 1;
123     int *icachesw;
124     char *cp, buf[BUFSIZ];
125     char buffer[BUFSIZ], *compfile = NULL;
126     char **argp, **arguments;
127     CT ct, cts[2];
128     FILE *fp = NULL;
129     FILE *fp_out = NULL;
130
131     done=unlink_done;
132
133 #ifdef LOCALE
134     setlocale(LC_ALL, "");
135 #endif
136     invo_name = r1bindex (argv[0], '/');
137
138     /* read user profile/context */
139     context_read();
140
141     arguments = getarguments (invo_name, argc, argv, 1);
142     argp = arguments;
143
144     while ((cp = *argp++)) {
145         if (cp[0] == '-' && cp[1] == '\0') {
146             if (compfile)
147                 adios (NULL, "cannot specify both standard input and a file");
148             else
149                 compfile = cp;
150             listsw = 0;         /* turn off -list if using standard in/out */
151             verbosw = 0;        /* turn off -verbose listings */
152             break;
153         }
154         if (*cp == '-') {
155             switch (smatch (++cp, switches)) {
156             case AMBIGSW: 
157                 ambigsw (cp, switches);
158                 done (1);
159             case UNKWNSW: 
160                 adios (NULL, "-%s unknown", cp);
161
162             case HELPSW: 
163                 snprintf (buf, sizeof(buf), "%s [switches] file", invo_name);
164                 print_help (buf, switches, 1);
165                 done (1);
166             case VERSIONSW:
167                 print_version(invo_name);
168                 done (1);
169
170             case RCACHESW:
171                 icachesw = &rcachesw;
172                 goto do_cache;
173             case WCACHESW:
174                 icachesw = &wcachesw;
175             do_cache: ;
176                 if (!(cp = *argp++) || *cp == '-')
177                     adios (NULL, "missing argument to %s", argp[-2]);
178                 switch (*icachesw = smatch (cp, caches)) {
179                 case AMBIGSW:
180                     ambigsw (cp, caches);
181                     done (1);
182                 case UNKWNSW:
183                     adios (NULL, "%s unknown", cp);
184                 default:
185                     break;
186                 }
187                 continue;
188
189             case CHECKSW:
190                 checksw++;
191                 continue;
192             case NCHECKSW:
193                 checksw = 0;
194                 continue;
195
196             case EBCDICSW:
197                 ebcdicsw++;
198                 continue;
199             case NEBCDICSW:
200                 ebcdicsw = 0;
201                 continue;
202
203             case HEADSW:
204                 headsw++;
205                 continue;
206             case NHEADSW:
207                 headsw = 0;
208                 continue;
209
210             case LISTSW:
211                 listsw++;
212                 continue;
213             case NLISTSW:
214                 listsw = 0;
215                 continue;
216
217             case RFC934SW:
218                 rfc934sw++;
219                 continue;
220             case NRFC934SW:
221                 rfc934sw = 0;
222                 continue;
223
224             case SIZESW:
225                 sizesw++;
226                 continue;
227             case NSIZESW:
228                 sizesw = 0;
229                 continue;
230
231             case CONTENTIDSW:
232                 contentidsw = 1;
233                 continue;
234             case NCONTENTIDSW:
235                 contentidsw = 0;
236                 continue;
237
238             case VERBSW: 
239                 verbosw++;
240                 continue;
241             case NVERBSW: 
242                 verbosw = 0;
243                 continue;
244             case DEBUGSW:
245                 debugsw = 1;
246                 continue;
247             }
248         }
249         if (compfile)
250             adios (NULL, "only one composition file allowed");
251         else
252             compfile = cp;
253     }
254
255     set_endian ();
256
257     if ((cp = getenv ("MM_NOASK")) && !strcmp (cp, "1"))
258         listsw  = 0;
259
260     /*
261      * Check if we've specified an additional profile
262      */
263     if ((cp = getenv ("MHBUILD"))) {
264         if ((fp = fopen (cp, "r"))) {
265             readconfig ((struct node **) 0, fp, cp, 0);
266             fclose (fp);
267         } else {
268             admonish ("", "unable to read $MHBUILD profile (%s)", cp);
269         }
270     }
271
272     /*
273      * Read the standard profile setup
274      */
275     if ((fp = fopen (cp = etcpath ("mhn.defaults"), "r"))) {
276         readconfig ((struct node **) 0, fp, cp, 0);
277         fclose (fp);
278     }
279
280     /* Check for public cache location */
281     if ((cache_public = context_find (nmhcache)) && *cache_public != '/')
282         cache_public = NULL;
283
284     /* Check for private cache location */
285     if (!(cache_private = context_find (nmhprivcache)))
286         cache_private = ".cache";
287     cache_private = getcpy (m_maildir (cache_private));
288
289     /*
290      * Check for storage directory.  If defined, we
291      * will store temporary files there.  Else we
292      * store them in standard nmh directory.
293      */
294     if ((cp = context_find (nmhstorage)) && *cp)
295         tmp = concat (cp, "/", invo_name, NULL);
296     else
297         tmp = add (m_maildir (invo_name), NULL);
298
299     if (!context_find ("path"))
300         free (path ("./", TFOLDER));
301
302     /* Check if we have a file to process */
303     if (!compfile)
304         adios (NULL, "need to specify a %s composition file", invo_name);
305
306     /*
307      * Process the composition file from standard input.
308      */
309     if (compfile[0] == '-' && compfile[1] == '\0') {
310         /* copy standard input to temporary file */
311         strncpy (infile, m_mktemp(invo_name, NULL, &fp), sizeof(infile));
312         while (fgets (buffer, BUFSIZ, stdin))
313             fputs (buffer, fp);
314         fclose (fp);
315         unlink_infile = 1;
316
317         /* build the content structures for MIME message */
318         ct = build_mime (infile);
319         cts[0] = ct;
320         cts[1] = NULL;
321
322         /* output MIME message to this temporary file */
323         strncpy (outfile, m_mktemp(invo_name, NULL, &fp_out), sizeof(outfile));
324         unlink_outfile = 1;
325
326         /* output the message */
327         output_message_fp (ct, fp_out, outfile);
328         fclose(fp_out);
329
330         /* output the temp file to standard output */
331         if ((fp = fopen (outfile, "r")) == NULL)
332             adios (outfile, "unable to open");
333         while (fgets (buffer, BUFSIZ, fp))
334             fputs (buffer, stdout);
335         fclose (fp);
336
337         unlink (infile);
338         unlink_infile = 0;
339
340         unlink (outfile);
341         unlink_outfile = 0;
342
343         free_content (ct);
344         done (0);
345     }
346
347     /*
348      * Process the composition file from a file.
349      */
350
351     /* build the content structures for MIME message */
352     ct = build_mime (compfile);
353     cts[0] = ct;
354     cts[1] = NULL;
355
356     /* output MIME message to this temporary file */
357     strncpy(outfile, m_mktemp2(compfile, invo_name, NULL, &fp_out),
358             sizeof(outfile));
359     unlink_outfile = 1;
360
361     /* output the message */
362     output_message_fp (ct, fp_out, outfile);
363     fclose(fp_out);
364
365     /*
366      * List the message info
367      */
368     if (listsw)
369         list_all_messages (cts, headsw, sizesw, verbosw, debugsw);
370
371     /* Rename composition draft */
372     snprintf (buffer, sizeof(buffer), "%s.orig", m_backup (compfile));
373     if (rename (compfile, buffer) == NOTOK) {
374         adios (compfile, "unable to rename comp draft %s to", buffer);
375     }
376
377     /* Rename output file to take its place */
378     if (rename (outfile, compfile) == NOTOK) {
379         advise (outfile, "unable to rename output %s to", compfile);
380         rename (buffer, compfile);
381         done (1);
382     }
383     unlink_outfile = 0;
384
385     free_content (ct);
386     done (0);
387     return 1;
388 }
389
390
391 static void
392 unlink_done (int status)
393 {
394     /*
395      * Check if we need to remove stray
396      * temporary files.
397      */
398     if (unlink_infile)
399         unlink (infile);
400     if (unlink_outfile)
401         unlink (outfile);
402
403     exit (status);
404 }