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