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