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