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