]> diplodocus.org Git - nmh/blob - uip/mhmisc.c
pending-release-notes: add mhshow's "-prefer", and mh-format's %(kibi/kilo)
[nmh] / uip / mhmisc.c
1
2 /*
3 * mhparse.c -- misc routines to process MIME messages
4 *
5 * This code is Copyright (c) 2002, by the authors of nmh. See the
6 * COPYRIGHT file in the root directory of the nmh distribution for
7 * complete copyright information.
8 */
9
10 #include <h/mh.h>
11 #include <h/mime.h>
12 #include <h/mhparse.h>
13 #include <h/utils.h>
14
15 extern int debugsw;
16
17 /*
18 * limit actions to specified parts or content types
19 */
20 int npart = 0;
21 int ntype = 0;
22 char *parts[NPARTS + 1];
23 char *types[NTYPES + 1];
24
25 int userrs = 0;
26
27 static char *errs = NULL;
28
29
30 /*
31 * prototypes
32 */
33 int part_ok (CT);
34 int part_exact(CT ct);
35 int type_ok (CT, int);
36 void content_error (char *, CT, char *, ...);
37 void flush_errors (void);
38
39
40 int
41 part_ok (CT ct)
42 {
43 char **ap;
44 int len;
45
46 /* a part is "ok", i.e., should be processed, if:
47 - there were no -part arguments
48 - this part is a multipart
49 */
50 if (npart == 0 || ct->c_type == CT_MULTIPART) {
51 return 1;
52 }
53
54 /* or if:
55 - this part is a an exact match for any -part option
56 - this part is a sub-part of any -part option
57 */
58 for (ap = parts; *ap; ap++) {
59 len = strlen(*ap);
60 if (!strncmp (*ap, ct->c_partno, len) &&
61 (!ct->c_partno[len] || ct->c_partno[len] == '.' )) {
62 return 1;
63 }
64 }
65
66 return 0;
67 }
68
69 int
70 part_exact(CT ct)
71 {
72 char **ap;
73
74 if (!ct->c_partno)
75 return 0;
76
77 for (ap = parts; *ap; ap++) {
78 if (!strcmp (*ap, ct->c_partno)) {
79 return 1;
80 }
81 }
82
83 return 0;
84 }
85
86
87 int
88 type_ok (CT ct, int sP)
89 {
90 char **ap;
91 char buffer[BUFSIZ];
92 CI ci = &ct->c_ctinfo;
93
94 if (ntype == 0 || (ct->c_type == CT_MULTIPART && (sP || ct->c_subtype)))
95 return 1;
96
97 snprintf (buffer, sizeof(buffer), "%s/%s", ci->ci_type, ci->ci_subtype);
98 for (ap = types; *ap; ap++)
99 if (!strcasecmp (*ap, ci->ci_type) || !strcasecmp (*ap, buffer))
100 return 1;
101
102 return 0;
103 }
104
105
106 /*
107 * Returns true if this content is marked as "inline".
108 *
109 * Technically we should check parent content to see if they have
110 * disposition to use as a default, but we don't right now. Maybe
111 * later ....
112 */
113
114 int
115 is_inline(CT ct)
116 {
117 /*
118 * If there isn't any disposition at all, it's "inline". Obviously
119 * if it's "inline", then it's inline. RFC 2183 says if it's an unknown
120 * disposition, treat it as 'attachment'.
121 */
122
123 if (! ct->c_dispo_type || strcasecmp(ct->c_dispo_type, "inline") == 0)
124 return 1;
125 else
126 return 0;
127 }
128
129 int
130 make_intermediates (char *file)
131 {
132 char *cp;
133
134 for (cp = file + 1; (cp = strchr(cp, '/')); cp++) {
135 struct stat st;
136
137 *cp = '\0';
138 if (stat (file, &st) == NOTOK) {
139 int answer;
140 char *ep;
141 if (errno != ENOENT) {
142 advise (file, "error on directory");
143 losing_directory:
144 *cp = '/';
145 return NOTOK;
146 }
147
148 ep = concat ("Create directory \"", file, "\"? ", NULL);
149 answer = getanswer (ep);
150 free (ep);
151
152 if (!answer)
153 goto losing_directory;
154 if (!makedir (file)) {
155 advise (NULL, "unable to create directory %s", file);
156 goto losing_directory;
157 }
158 }
159
160 *cp = '/';
161 }
162
163 return OK;
164 }
165
166
167 /*
168 * Construct error message for content
169 */
170
171 void
172 content_error (char *what, CT ct, char *fmt, ...)
173 {
174 va_list arglist;
175 int i, len, buflen;
176 char *bp, buffer[BUFSIZ];
177 CI ci;
178
179 bp = buffer;
180 buflen = sizeof(buffer);
181
182 if (userrs && invo_name && *invo_name) {
183 snprintf (bp, buflen, "%s: ", invo_name);
184 len = strlen (bp);
185 bp += len;
186 buflen -= len;
187 }
188
189 va_start (arglist, fmt);
190
191 vsnprintf (bp, buflen, fmt, arglist);
192 len = strlen (bp);
193 bp += len;
194 buflen -= len;
195
196 ci = &ct->c_ctinfo;
197
198 if (what) {
199 char *s;
200
201 if (*what) {
202 snprintf (bp, buflen, " %s: ", what);
203 len = strlen (bp);
204 bp += len;
205 buflen -= len;
206 }
207
208 if ((s = strerror (errno)))
209 snprintf (bp, buflen, "%s", s);
210 else
211 snprintf (bp, buflen, "Error %d", errno);
212
213 len = strlen (bp);
214 bp += len;
215 buflen -= len;
216 }
217
218 i = strlen (invo_name) + 2;
219
220 /* Now add content type and subtype */
221 snprintf (bp, buflen, "\n%*.*s(content %s/%s", i, i, "",
222 ci->ci_type, ci->ci_subtype);
223 len = strlen (bp);
224 bp += len;
225 buflen -= len;
226
227 /* Now add the message/part number */
228 if (ct->c_file) {
229 snprintf (bp, buflen, " in message %s", ct->c_file);
230 len = strlen (bp);
231 bp += len;
232 buflen -= len;
233
234 if (ct->c_partno) {
235 snprintf (bp, buflen, ", part %s", ct->c_partno);
236 len = strlen (bp);
237 bp += len;
238 buflen -= len;
239 }
240 }
241
242 snprintf (bp, buflen, ")");
243 len = strlen (bp);
244 bp += len;
245 buflen -= len;
246
247 if (userrs) {
248 *bp++ = '\n';
249 *bp = '\0';
250 buflen--;
251
252 errs = add (buffer, errs);
253 } else {
254 advise (NULL, "%s", buffer);
255 }
256 }
257
258
259 void
260 flush_errors (void)
261 {
262 if (errs) {
263 fflush (stdout);
264 fprintf (stderr, "%s", errs);
265 free (errs);
266 errs = NULL;
267 }
268 }