Reformated comments and long lines
[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/mts.h>
16 #include <h/tws.h>
17 #include <h/mime.h>
18 #include <h/mhparse.h>
19 #include <h/mhcachesbr.h>
20 #include <h/utils.h>
21
22 #ifdef HAVE_SYS_WAIT_H
23 # include <sys/wait.h>
24 #endif
25
26 static struct swit switches[] = {
27 #define CHECKSW  0
28         { "check", 0 },
29 #define NCHECKSW  1
30         { "nocheck", 0 },
31 #define EBCDICSW  2
32         { "ebcdicsafe", 0 },
33 #define NEBCDICSW  3
34         { "noebcdicsafe", 0 },
35 #define HEADSW  4
36         { "headers", 0 },
37 #define NHEADSW  5
38         { "noheaders", 0 },
39 #define LISTSW  6
40         { "list", 0 },
41 #define NLISTSW  7
42         { "nolist", 0 },
43 #define SIZESW  8
44         { "realsize", 0 },
45 #define NSIZESW  9
46         { "norealsize", 0 },
47 #define RFC934SW  10
48         { "rfc934mode", 0 },
49 #define NRFC934SW  11
50         { "norfc934mode", 0 },
51 #define VERBSW  12
52         { "verbose", 0 },
53 #define NVERBSW  13
54         { "noverbose", 0 },
55 #define RCACHESW  14
56         { "rcache policy", 0 },
57 #define WCACHESW  15
58         { "wcache policy", 0 },
59 #define CONTENTIDSW  16
60         { "contentid", 0 },
61 #define NCONTENTIDSW  17
62         { "nocontentid", 0 },
63 #define VERSIONSW  18
64         { "version", 0 },
65 #define HELPSW  19
66         { "help", 0 },
67 #define DEBUGSW  20
68         { "debug", -5 },
69         { NULL, 0 }
70 };
71
72
73 /* mhbuildsbr.c */
74 extern char *tmp;  /* directory to place temp files */
75
76 /* mhcachesbr.c */
77 extern int rcachesw;
78 extern int wcachesw;
79 extern char *cache_public;
80 extern char *cache_private;
81
82 int debugsw = 0;
83 int verbosw = 0;
84
85 int ebcdicsw = 0;
86 int listsw   = 0;
87 int rfc934sw = 0;
88 int contentidsw = 1;
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 static void unlink_done (int) NORETURN;
100
101 /* mhbuildsbr.c */
102 CT build_mime (char *);
103 int output_message (CT, char *);
104 int output_message_fp (CT, FILE *, char*);
105
106 /* mhlistsbr.c */
107 int list_all_messages (CT *, int, int, int, int);
108
109 /* mhmisc.c */
110 void set_endian (void);
111
112 /* mhfree.c */
113 void free_content (CT);
114
115
116 int
117 main (int argc, char **argv)
118 {
119         int sizesw = 1, headsw = 1;
120         int *icachesw;
121         char *cp, buf[BUFSIZ];
122         char buffer[BUFSIZ], *compfile = NULL;
123         char **argp, **arguments;
124         CT ct, cts[2];
125         FILE *fp = NULL;
126         FILE *fp_out = NULL;
127
128         done = unlink_done;
129
130 #ifdef LOCALE
131         setlocale(LC_ALL, "");
132 #endif
133         invo_name = r1bindex (argv[0], '/');
134
135         /* read user profile/context */
136         context_read();
137
138         arguments = getarguments (invo_name, argc, argv, 1);
139         argp = arguments;
140
141         while ((cp = *argp++)) {
142                 if (cp[0] == '-' && cp[1] == '\0') {
143                         if (compfile)
144                                 adios (NULL, "cannot specify both standard input and a file");
145                         else
146                                 compfile = cp;
147                         listsw = 0;  /* turn off -list if using std in/out */
148                         verbosw = 0;  /* turn off -verbose listings */
149                         break;
150                 }
151                 if (*cp == '-') {
152                         switch (smatch (++cp, switches)) {
153                         case AMBIGSW:
154                                 ambigsw (cp, switches);
155                                 done (1);
156                         case UNKWNSW:
157                                 adios (NULL, "-%s unknown", cp);
158
159                         case HELPSW:
160                                 snprintf (buf, sizeof(buf), "%s [switches] file", invo_name);
161                                 print_help (buf, switches, 1);
162                                 done (1);
163                         case VERSIONSW:
164                                 print_version(invo_name);
165                                 done (1);
166
167                         case RCACHESW:
168                                 icachesw = &rcachesw;
169                                 goto do_cache;
170                         case WCACHESW:
171                                 icachesw = &wcachesw;
172                         do_cache: ;
173                                 if (!(cp = *argp++) || *cp == '-')
174                                         adios (NULL, "missing argument to %s", 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"))
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)", cp);
266                 }
267         }
268
269         /*
270         ** Read the standard profile setup
271         */
272         if ((fp = fopen (cp = etcpath ("mhn.defaults"), "r"))) {
273                 readconfig ((struct node **) 0, fp, cp, 0);
274                 fclose (fp);
275         }
276
277         /* Check for public cache location */
278         if ((cache_public = context_find (nmhcache)) && *cache_public != '/')
279                 cache_public = NULL;
280
281         /* Check for private cache location */
282         if (!(cache_private = context_find (nmhprivcache)))
283                 cache_private = ".cache";
284         cache_private = getcpy (m_maildir (cache_private));
285
286         /*
287         ** Check for storage directory.  If defined, we
288         ** will store temporary files there.  Else we
289         ** store them in standard nmh directory.
290         */
291         if ((cp = context_find (nmhstorage)) && *cp)
292                 tmp = concat (cp, "/", invo_name, NULL);
293         else
294                 tmp = add (m_maildir (invo_name), NULL);
295
296         if (!context_find ("path"))
297                 free (path ("./", TFOLDER));
298
299         /* Check if we have a file to process */
300         if (!compfile)
301                 adios (NULL, "need to specify a %s composition file", invo_name);
302
303         /*
304         ** Process the composition file from standard input.
305         */
306         if (compfile[0] == '-' && compfile[1] == '\0') {
307                 /* copy standard input to temporary file */
308                 strncpy (infile, m_mktemp(invo_name, NULL, &fp), 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), sizeof(outfile));
321                 unlink_outfile = 1;
322
323                 /* output the message */
324                 output_message_fp (ct, fp_out, outfile);
325                 fclose(fp_out);
326
327                 /* output the temp file to standard output */
328                 if ((fp = fopen (outfile, "r")) == NULL)
329                         adios (outfile, "unable to open");
330                 while (fgets (buffer, BUFSIZ, fp))
331                         fputs (buffer, stdout);
332                 fclose (fp);
333
334                 unlink (infile);
335                 unlink_infile = 0;
336
337                 unlink (outfile);
338                 unlink_outfile = 0;
339
340                 free_content (ct);
341                 done (0);
342         }
343
344         /*
345         ** Process the composition file from a file.
346         */
347
348         /* build the content structures for MIME message */
349         ct = build_mime (compfile);
350         cts[0] = ct;
351         cts[1] = NULL;
352
353         /* output MIME message to this temporary file */
354         strncpy(outfile, m_mktemp2(compfile, invo_name, NULL, &fp_out),
355                         sizeof(outfile));
356         unlink_outfile = 1;
357
358         /* output the message */
359         output_message_fp (ct, fp_out, outfile);
360         fclose(fp_out);
361
362         /*
363         ** List the message info
364         */
365         if (listsw)
366                 list_all_messages (cts, headsw, sizesw, verbosw, debugsw);
367
368         /* Rename composition draft */
369         snprintf (buffer, sizeof(buffer), "%s.orig", m_backup (compfile));
370         if (rename (compfile, buffer) == NOTOK) {
371                 adios (compfile, "unable to rename comp draft %s to", buffer);
372         }
373
374         /* Rename output file to take its place */
375         if (rename (outfile, compfile) == NOTOK) {
376                 advise (outfile, "unable to rename output %s to", compfile);
377                 rename (buffer, compfile);
378                 done (1);
379         }
380         unlink_outfile = 0;
381
382         free_content (ct);
383         done (0);
384         return 1;
385 }
386
387
388 static void
389 unlink_done (int status)
390 {
391         /*
392         ** Check if we need to remove stray temporary files.
393         */
394         if (unlink_infile)
395                 unlink (infile);
396         if (unlink_outfile)
397                 unlink (outfile);
398
399         exit (status);
400 }