Fix -part option to mhshow/mhlist/mhstore to find sub-parts of the specified
[mmh] / uip / mhmisc.c
1
2 /*
3  * mhparse.c -- misc routines to process MIME messages
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 <errno.h>
14 #include <h/mime.h>
15 #include <h/mhparse.h>
16
17 extern int debugsw;
18
19 /*
20  * limit actions to specified parts or content types
21  */
22 int npart = 0;
23 int ntype = 0;
24 char *parts[NPARTS + 1];
25 char *types[NTYPES + 1];
26
27 int endian = 0;         /* little or big endian */
28 int userrs = 0;
29
30 static char *errs = NULL;
31
32
33 /*
34  * prototypes
35  */
36 int part_ok (CT, int);
37 int type_ok (CT, int);
38 void set_endian (void);
39 int make_intermediates (char *);
40 void content_error (char *, CT, char *, ...);
41 void flush_errors (void);
42
43
44 int
45 part_ok (CT ct, int sP)
46 {
47     char **ap;
48     int len;
49
50     if (npart == 0 || (ct->c_type == CT_MULTIPART && (sP || ct->c_subtype)))
51         return 1;
52
53     for (ap = parts; *ap; ap++) {
54         len = strlen(*ap);
55         if (!strncmp (*ap, ct->c_partno, len) &&
56                 (!ct->c_partno[len] || ct->c_partno[len] == '.' ))
57             return 1;
58     }
59
60     return 0;
61 }
62
63
64 int
65 type_ok (CT ct, int sP)
66 {
67     char **ap;
68     char buffer[BUFSIZ];
69     CI ci = &ct->c_ctinfo;
70
71     if (ntype == 0 || (ct->c_type == CT_MULTIPART && (sP || ct->c_subtype)))
72         return 1;
73
74     snprintf (buffer, sizeof(buffer), "%s/%s", ci->ci_type, ci->ci_subtype);
75     for (ap = types; *ap; ap++)
76         if (!strcasecmp (*ap, ci->ci_type) || !strcasecmp (*ap, buffer))
77             return 1;
78
79     return 0;
80 }
81
82
83 void
84 set_endian (void)
85 {
86     union {
87         long l;
88         char c[sizeof(long)];
89     } un;
90
91     un.l = 1;
92     endian = un.c[0] ? -1 : 1;
93     if (debugsw)
94         fprintf (stderr, "%s endian architecture\n",
95                 endian > 0 ? "big" : "little");
96 }
97
98
99 int
100 make_intermediates (char *file)
101 {
102     char *cp;
103
104     for (cp = file + 1; (cp = strchr(cp, '/')); cp++) {
105         struct stat st;
106
107         *cp = '\0';
108         if (stat (file, &st) == NOTOK) {
109             int answer;
110             char *ep;
111             if (errno != ENOENT) {
112                 advise (file, "error on directory");
113 losing_directory:
114                 *cp = '/';
115                 return NOTOK;
116             }
117
118             ep = concat ("Create directory \"", file, "\"? ", NULL);
119             answer = getanswer (ep);
120             free (ep);
121
122             if (!answer)
123                 goto losing_directory;
124             if (!makedir (file)) {
125                 advise (NULL, "unable to create directory %s", file);
126                 goto losing_directory;
127             }
128         }
129
130         *cp = '/';
131     }
132
133     return OK;
134 }
135
136
137 /*
138  * Construct error message for content
139  */
140
141 void
142 content_error (char *what, CT ct, char *fmt, ...)
143 {
144     va_list arglist;
145     int i, len, buflen;
146     char *bp, buffer[BUFSIZ];
147     CI ci;
148
149     bp = buffer;
150     buflen = sizeof(buffer);
151
152     if (userrs && invo_name && *invo_name) {
153         snprintf (bp, buflen, "%s: ", invo_name);
154         len = strlen (bp);
155         bp += len;
156         buflen -= len;
157     }
158
159     va_start (arglist, fmt);
160
161     vsnprintf (bp, buflen, fmt, arglist);
162     len = strlen (bp);
163     bp += len;
164     buflen -= len;
165
166     ci = &ct->c_ctinfo;
167
168     if (what) {
169         char *s;
170
171         if (*what) {
172             snprintf (bp, buflen, " %s: ", what);
173             len = strlen (bp);
174             bp += len;
175             buflen -= len;
176         }
177
178         if ((s = strerror (errno)))
179             snprintf (bp, buflen, "%s", s);
180         else
181             snprintf (bp, buflen, "Error %d", errno);
182
183         len = strlen (bp);
184         bp += len;
185         buflen -= len;
186     }
187
188     i = strlen (invo_name) + 2;
189
190     /* Now add content type and subtype */
191     snprintf (bp, buflen, "\n%*.*s(content %s/%s", i, i, "",
192         ci->ci_type, ci->ci_subtype);
193     len = strlen (bp);
194     bp += len;
195     buflen -= len;
196
197     /* Now add the message/part number */
198     if (ct->c_file) {
199         snprintf (bp, buflen, " in message %s", ct->c_file);
200         len = strlen (bp);
201         bp += len;
202         buflen -= len;
203
204         if (ct->c_partno) {
205             snprintf (bp, buflen, ", part %s", ct->c_partno);
206             len = strlen (bp);
207             bp += len;
208             buflen -= len;
209         }
210     }
211
212     snprintf (bp, buflen, ")");
213     len = strlen (bp);
214     bp += len;
215     buflen -= len;
216
217     if (userrs) {
218         *bp++ = '\n';
219         *bp = '\0';
220         buflen--;
221
222         errs = add (buffer, errs);
223     } else {
224         advise (NULL, "%s", buffer);
225     }
226 }
227
228
229 void
230 flush_errors (void)
231 {
232     if (errs) {
233         fflush (stdout);
234         fprintf (stderr, "%s", errs);
235         free (errs);
236         errs = NULL;
237     }
238 }