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