Implement the following changes:
[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 (1);
161             case VERSIONSW:
162                 print_version(invo_name);
163                 done (1);
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     set_endian ();
258
259     if ((cp = getenv ("MM_NOASK")) && !strcmp (cp, "1"))
260         listsw  = 0;
261
262     /*
263      * Check if we've specified an additional profile
264      */
265     if ((cp = getenv ("MHBUILD"))) {
266         if ((fp = fopen (cp, "r"))) {
267             readconfig ((struct node **) 0, fp, cp, 0);
268             fclose (fp);
269         } else {
270             admonish ("", "unable to read $MHBUILD profile (%s)", cp);
271         }
272     }
273
274     /*
275      * Read the standard profile setup
276      */
277     if ((fp = fopen (cp = etcpath ("mhn.defaults"), "r"))) {
278         readconfig ((struct node **) 0, fp, cp, 0);
279         fclose (fp);
280     }
281
282     /* Check for public cache location */
283     if ((cache_public = context_find (nmhcache)) && *cache_public != '/')
284         cache_public = NULL;
285
286     /* Check for private cache location */
287     if (!(cache_private = context_find (nmhprivcache)))
288         cache_private = ".cache";
289     cache_private = getcpy (m_maildir (cache_private));
290
291     /*
292      * Check for storage directory.  If defined, we
293      * will store temporary files there.  Else we
294      * store them in standard nmh directory.
295      */
296     if ((cp = context_find (nmhstorage)) && *cp)
297         tmp = concat (cp, "/", invo_name, NULL);
298     else
299         tmp = add (m_maildir (invo_name), NULL);
300
301     if (!context_find ("path"))
302         free (path ("./", TFOLDER));
303
304     /* Check if we have a file to process */
305     if (!compfile)
306         adios (NULL, "need to specify a %s composition file", invo_name);
307
308     /*
309      * Process the composition file from standard input.
310      */
311     if (compfile[0] == '-' && compfile[1] == '\0') {
312         /* copy standard input to temporary file */
313         strncpy (infile, m_mktemp(invo_name, NULL, &fp), sizeof(infile));
314         while (fgets (buffer, BUFSIZ, stdin))
315             fputs (buffer, fp);
316         fclose (fp);
317         unlink_infile = 1;
318
319         /* build the content structures for MIME message */
320         ct = build_mime (infile, directives);
321         cts[0] = ct;
322         cts[1] = NULL;
323
324         /* output MIME message to this temporary file */
325         strncpy (outfile, m_mktemp(invo_name, NULL, &fp_out), sizeof(outfile));
326         unlink_outfile = 1;
327
328         /* output the message */
329         output_message_fp (ct, fp_out, outfile);
330         fclose(fp_out);
331
332         /* output the temp file to standard output */
333         if ((fp = fopen (outfile, "r")) == NULL)
334             adios (outfile, "unable to open");
335         while (fgets (buffer, BUFSIZ, fp))
336             fputs (buffer, stdout);
337         fclose (fp);
338
339         unlink (infile);
340         unlink_infile = 0;
341
342         unlink (outfile);
343         unlink_outfile = 0;
344
345         free_content (ct);
346         done (0);
347     }
348
349     /*
350      * Process the composition file from a file.
351      */
352
353     /* build the content structures for MIME message */
354     ct = build_mime (compfile, directives);
355     cts[0] = ct;
356     cts[1] = NULL;
357
358     /* output MIME message to this temporary file */
359     strncpy(outfile, m_mktemp2(compfile, invo_name, NULL, &fp_out),
360             sizeof(outfile));
361     unlink_outfile = 1;
362
363     /* output the message */
364     output_message_fp (ct, fp_out, outfile);
365     fclose(fp_out);
366
367     /*
368      * List the message info
369      */
370     if (listsw)
371         list_all_messages (cts, headsw, sizesw, verbosw, debugsw);
372
373     /* Rename composition draft */
374     snprintf (buffer, sizeof(buffer), "%s.orig", m_backup (compfile));
375     if (rename (compfile, buffer) == NOTOK) {
376         adios (compfile, "unable to rename comp draft %s to", buffer);
377     }
378
379     /* Rename output file to take its place */
380     if (rename (outfile, compfile) == NOTOK) {
381         advise (outfile, "unable to rename output %s to", compfile);
382         rename (buffer, compfile);
383         done (1);
384     }
385     unlink_outfile = 0;
386
387     free_content (ct);
388     done (0);
389     return 1;
390 }
391
392
393 static void
394 unlink_done (int status)
395 {
396     /*
397      * Check if we need to remove stray
398      * temporary files.
399      */
400     if (unlink_infile)
401         unlink (infile);
402     if (unlink_outfile)
403         unlink (outfile);
404
405     exit (status);
406 }