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