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