Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 384 lines (315 sloc) 8.556 kb
fc6b8f9 Implement RFC 2231.
Thomas Roessler authored
1 /*
82cb256 @bcully Update copyrights. Closes #3016.
bcully authored
2 * Copyright (C) 1999-2001 Thomas Roessler <roessler@does-not-exist.org>
fc6b8f9 Implement RFC 2231.
Thomas Roessler authored
3 *
4 * This program is free software; you can redistribute it
5 * and/or modify it under the terms of the GNU General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later
8 * version.
9 *
10 * This program is distributed in the hope that it will be
11 * useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
13 * PURPOSE. See the GNU General Public License for more
14 * details.
15 *
16 * You should have received a copy of the GNU General Public
17 * License along with this program; if not, write to the Free
4ebd1cc @bcully Update FSF address (via sed, I hope nothing got mangled). Closes: #2071.
bcully authored
18 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
62255b8 @bcully Gah, forgot the zip code when updating the FSF address...
bcully authored
19 * Boston, MA 02110-1301, USA.
fc6b8f9 Implement RFC 2231.
Thomas Roessler authored
20 */
21
22 /*
23 * Yet another MIME encoding for header data. This time, it's
24 * parameters, specified in RFC 2231, and modeled after the
25 * encoding used in URLs.
26 *
27 * Additionally, continuations and encoding are mixed in an, errrm,
28 * interesting manner.
29 *
30 */
31
bd77e36 @bcully Add config.h to the top of every C file that could possibly want it.
bcully authored
32 #if HAVE_CONFIG_H
33 # include "config.h"
34 #endif
35
fc6b8f9 Implement RFC 2231.
Thomas Roessler authored
36 #include "mutt.h"
37 #include "mime.h"
38 #include "charset.h"
39 #include "rfc2047.h"
40 #include "rfc2231.h"
41
42 #include <ctype.h>
43 #include <string.h>
44 #include <stdlib.h>
45
46 struct rfc2231_parameter
47 {
48 char *attribute;
49 char *value;
50 int index;
51 int encoded;
52 struct rfc2231_parameter
53 *next;
54 };
55
56 static char *rfc2231_get_charset (char *, char *, size_t);
57 static struct rfc2231_parameter *rfc2231_new_parameter (void);
07473c2 String conversion patch from EGE.
Thomas Roessler authored
58 static void rfc2231_decode_one (char *, char *);
fc6b8f9 Implement RFC 2231.
Thomas Roessler authored
59 static void rfc2231_free_parameter (struct rfc2231_parameter **);
60 static void rfc2231_join_continuations (PARAMETER **, struct rfc2231_parameter *);
61 static void rfc2231_list_insert (struct rfc2231_parameter **, struct rfc2231_parameter *);
62
ab67939 Ignore empty MIME parameters.
Thomas Roessler authored
63 static void purge_empty_parameters (PARAMETER **headp)
64 {
65 PARAMETER *p, *q, **last;
66
67 for (last = headp, p = *headp; p; p = q)
68 {
69 q = p->next;
70 if (!p->attribute || !p->value)
71 {
72 *last = q;
73 p->next = NULL;
74 mutt_free_parameter (&p);
75 }
76 else
77 last = &p->next;
78 }
79 }
80
81
fc6b8f9 Implement RFC 2231.
Thomas Roessler authored
82 void rfc2231_decode_parameters (PARAMETER **headp)
83 {
84 PARAMETER *head = NULL;
85 PARAMETER **last;
86 PARAMETER *p, *q;
87
88 struct rfc2231_parameter *conthead = NULL;
89 struct rfc2231_parameter *conttmp;
90
91 char *s, *t;
92 char charset[STRING];
93
94 int encoded;
95 int index;
5b1d07b Some rather cosmetic changes.
Thomas Roessler authored
96 short dirty = 0; /* set to 1 when we may have created
97 * empty parameters.
98 */
99
fc6b8f9 Implement RFC 2231.
Thomas Roessler authored
100 if (!headp) return;
ab67939 Ignore empty MIME parameters.
Thomas Roessler authored
101
102 purge_empty_parameters (headp);
fc6b8f9 Implement RFC 2231.
Thomas Roessler authored
103
104 for (last = &head, p = *headp; p; p = q)
105 {
106 q = p->next;
107
108 if (!(s = strchr (p->attribute, '*')))
109 {
110
111 /*
112 * Using RFC 2047 encoding in MIME parameters is explicitly
113 * forbidden by that document. Nevertheless, it's being
114 * generated by some software, including certain Lotus Notes to
115 * Internet Gateways. So we actually decode it.
116 */
117
e989f71 Catch a segmenatation fault. Note that this is not the real fix for
Thomas Roessler authored
118 if (option (OPTRFC2047PARAMS) && p->value && strstr (p->value, "=?"))
5b6b2a3 rfc2047_decode change from EGE.
Thomas Roessler authored
119 rfc2047_decode (&p->value);
ae16478 Updated $assumed_charset patch (closes: #2218).
TAKIZAWA Takashi authored
120 else if (AssumedCharset && *AssumedCharset)
121 convert_nonmime_string (&p->value);
fc6b8f9 Implement RFC 2231.
Thomas Roessler authored
122
123 *last = p;
124 last = &p->next;
125 p->next = NULL;
126 }
127 else if (*(s + 1) == '\0')
128 {
129 *s = '\0';
130
131 s = rfc2231_get_charset (p->value, charset, sizeof (charset));
07473c2 String conversion patch from EGE.
Thomas Roessler authored
132 rfc2231_decode_one (p->value, s);
db993da Change charset-hook's behaviour.
Thomas Roessler authored
133 mutt_convert_string (&p->value, charset, Charset, M_ICONV_HOOK_FROM);
7ca9603 Fix #2173.
TAKAHASHI Tamotsu authored
134 mutt_filter_unprintable (&p->value);
07473c2 String conversion patch from EGE.
Thomas Roessler authored
135
fc6b8f9 Implement RFC 2231.
Thomas Roessler authored
136 *last = p;
137 last = &p->next;
138 p->next = NULL;
5b1d07b Some rather cosmetic changes.
Thomas Roessler authored
139
140 dirty = 1;
fc6b8f9 Implement RFC 2231.
Thomas Roessler authored
141 }
142 else
143 {
144 *s = '\0'; s++; /* let s point to the first character of index. */
9c64747 Some functions/macros like isspace take an int and require the
Vincent Lefevre authored
145 for (t = s; *t && isdigit ((unsigned char) *t); t++)
fc6b8f9 Implement RFC 2231.
Thomas Roessler authored
146 ;
147 encoded = (*t == '*');
148 *t = '\0';
149
150 index = atoi (s);
151
152 conttmp = rfc2231_new_parameter ();
153 conttmp->attribute = p->attribute;
154 conttmp->value = p->value;
155 conttmp->encoded = encoded;
156 conttmp->index = index;
157
158 p->attribute = NULL;
159 p->value = NULL;
cbab567 Replace safe_free calls by the FREE macro.
Thomas Roessler authored
160 FREE (&p);
fc6b8f9 Implement RFC 2231.
Thomas Roessler authored
161
162 rfc2231_list_insert (&conthead, conttmp);
163 }
164 }
165
166 if (conthead)
5b1d07b Some rather cosmetic changes.
Thomas Roessler authored
167 {
fc6b8f9 Implement RFC 2231.
Thomas Roessler authored
168 rfc2231_join_continuations (last, conthead);
5b1d07b Some rather cosmetic changes.
Thomas Roessler authored
169 dirty = 1;
170 }
fc6b8f9 Implement RFC 2231.
Thomas Roessler authored
171
172 *headp = head;
ab67939 Ignore empty MIME parameters.
Thomas Roessler authored
173
5b1d07b Some rather cosmetic changes.
Thomas Roessler authored
174 if (dirty)
175 purge_empty_parameters (headp);
fc6b8f9 Implement RFC 2231.
Thomas Roessler authored
176 }
177
178 static struct rfc2231_parameter *rfc2231_new_parameter (void)
179 {
180 return safe_calloc (sizeof (struct rfc2231_parameter), 1);
181 }
182
183 static void rfc2231_free_parameter (struct rfc2231_parameter **p)
184 {
185 if (*p)
186 {
cbab567 Replace safe_free calls by the FREE macro.
Thomas Roessler authored
187 FREE (&(*p)->attribute);
188 FREE (&(*p)->value);
850e0a9 Avoid safe_free() usage and add security checks
Rocco Rutte authored
189 FREE (p); /* __FREE_CHECKED__ */
fc6b8f9 Implement RFC 2231.
Thomas Roessler authored
190 }
191 }
192
193 static char *rfc2231_get_charset (char *value, char *charset, size_t chslen)
194 {
195 char *t, *u;
196
197 if (!(t = strchr (value, '\'')))
198 {
199 charset[0] = '\0';
200 return value;
201 }
202
203 *t = '\0';
204 strfcpy (charset, value, chslen);
205
206 if ((u = strchr (t + 1, '\'')))
207 return u + 1;
208 else
209 return t + 1;
210 }
211
07473c2 String conversion patch from EGE.
Thomas Roessler authored
212 static void rfc2231_decode_one (char *dest, char *src)
fc6b8f9 Implement RFC 2231.
Thomas Roessler authored
213 {
214 char *d;
215
216 for (d = dest; *src; src++)
217 {
9c64747 Some functions/macros like isspace take an int and require the
Vincent Lefevre authored
218 if (*src == '%' &&
219 isxdigit ((unsigned char) *(src + 1)) &&
220 isxdigit ((unsigned char) *(src + 2)))
fc6b8f9 Implement RFC 2231.
Thomas Roessler authored
221 {
222 *d++ = (hexval (*(src + 1)) << 4) | (hexval (*(src + 2)));
223 src += 2;
224 }
225 else
226 *d++ = *src;
227 }
228
229 *d = '\0';
230 }
231
232 /* insert parameter into an ordered list.
233 *
234 * Primary sorting key: attribute
235 * Secondary sorting key: index
236 */
237
238 static void rfc2231_list_insert (struct rfc2231_parameter **list,
239 struct rfc2231_parameter *par)
240 {
241 struct rfc2231_parameter **last = list;
242 struct rfc2231_parameter *p = *list, *q;
243 int c;
244
245 while (p)
246 {
247 last = &p->next;
248 q = p; p = p->next;
249
250 c = strcmp (par->value, q->value);
251 if ((c > 0) || (c == 0 && par->index >= q->index))
252 break;
253 }
254
255 par->next = p;
256 *last = par;
257 }
258
259 /* process continuation parameters */
260
261 static void rfc2231_join_continuations (PARAMETER **head,
262 struct rfc2231_parameter *par)
263 {
264 struct rfc2231_parameter *q;
265
266 char attribute[STRING];
267 char charset[STRING];
268 char *value = NULL;
269 char *valp;
270 int encoded;
271
272 size_t l, vl;
273
274 while (par)
275 {
276 value = NULL; l = 0;
277
278 strfcpy (attribute, par->attribute, sizeof (attribute));
279
280 if ((encoded = par->encoded))
281 valp = rfc2231_get_charset (par->value, charset, sizeof (charset));
282 else
283 valp = par->value;
284
285 do
286 {
287 if (encoded && par->encoded)
07473c2 String conversion patch from EGE.
Thomas Roessler authored
288 rfc2231_decode_one (par->value, valp);
fc6b8f9 Implement RFC 2231.
Thomas Roessler authored
289
290 vl = strlen (par->value);
291
0be4889 As the ones of you who compile with new gcc's probably have noticed,
Mads Martin Joergensen authored
292 safe_realloc (&value, l + vl + 1);
aa17120 Going through possible security problems with a fine comb. If you
Thomas Roessler authored
293 strcpy (value + l, par->value); /* __STRCPY_CHECKED__ */
fc6b8f9 Implement RFC 2231.
Thomas Roessler authored
294 l += vl;
295
296 q = par->next;
297 rfc2231_free_parameter (&par);
298 if ((par = q))
299 valp = par->value;
300 } while (par && !strcmp (par->attribute, attribute));
301
302 if (value)
303 {
07473c2 String conversion patch from EGE.
Thomas Roessler authored
304 if (encoded)
db993da Change charset-hook's behaviour.
Thomas Roessler authored
305 mutt_convert_string (&value, charset, Charset, M_ICONV_HOOK_FROM);
fc6b8f9 Implement RFC 2231.
Thomas Roessler authored
306 *head = mutt_new_parameter ();
307 (*head)->attribute = safe_strdup (attribute);
308 (*head)->value = value;
309 head = &(*head)->next;
310 }
311 }
312 }
313
762d375 Do character set selection for RFC2231 encodings. From EGE, but
Thomas Roessler authored
314 int rfc2231_encode_string (char **pd)
fc6b8f9 Implement RFC 2231.
Thomas Roessler authored
315 {
762d375 Do character set selection for RFC2231 encodings. From EGE, but
Thomas Roessler authored
316 int ext = 0, encode = 0;
317 char *charset, *s, *t, *e, *d = 0;
318 size_t slen, dlen = 0;
fc6b8f9 Implement RFC 2231.
Thomas Roessler authored
319
e910119 Detect pure 7bit data and don't encode them. This helps a bit in
Thomas Roessler authored
320 /*
321 * A shortcut to detect pure 7bit data.
322 *
323 * This should prevent the worst when character set handling
324 * is flawed.
325 */
326
327 for (s = *pd; *s; s++)
328 if (*s & 0x80)
329 break;
330
331 if (!*s)
762d375 Do character set selection for RFC2231 encodings. From EGE, but
Thomas Roessler authored
332 return 0;
e910119 Detect pure 7bit data and don't encode them. This helps a bit in
Thomas Roessler authored
333
762d375 Do character set selection for RFC2231 encodings. From EGE, but
Thomas Roessler authored
334 if (!Charset || !SendCharset ||
335 !(charset = mutt_choose_charset (Charset, SendCharset,
336 *pd, strlen (*pd), &d, &dlen)))
fc6b8f9 Implement RFC 2231.
Thomas Roessler authored
337 {
2a9fb2f Replace "unknown" by "unknown-8bit".
Thomas Roessler authored
338 charset = safe_strdup (Charset ? Charset : "unknown-8bit");
a0f5767 Let check_sec.sh check for use of the unsafe malloc, realloc, free,
Thomas Roessler authored
339 d = *pd;
340 dlen = strlen (d);
fc6b8f9 Implement RFC 2231.
Thomas Roessler authored
341 }
342
2731400 Add a character set comparison function.
Thomas Roessler authored
343 if (!mutt_is_us_ascii (charset))
762d375 Do character set selection for RFC2231 encodings. From EGE, but
Thomas Roessler authored
344 encode = 1;
345
346 for (s = d, slen = dlen; slen; s++, slen--)
347 if (*s < 0x20 || *s >= 0x7f)
348 encode = 1, ++ext;
ccbcddb Little fix from EGE.
Thomas Roessler authored
349 else if (strchr (MimeSpecials, *s) || strchr ("*'%", *s))
762d375 Do character set selection for RFC2231 encodings. From EGE, but
Thomas Roessler authored
350 ++ext;
351
352 if (encode)
fc6b8f9 Implement RFC 2231.
Thomas Roessler authored
353 {
762d375 Do character set selection for RFC2231 encodings. From EGE, but
Thomas Roessler authored
354 e = safe_malloc (dlen + 2*ext + strlen (charset) + 3);
ae2af4f Fix and/or check more fishy code.
Thomas Roessler authored
355 sprintf (e, "%s''", charset); /* __SPRINTF_CHECKED__ */
762d375 Do character set selection for RFC2231 encodings. From EGE, but
Thomas Roessler authored
356 t = e + strlen (e);
357 for (s = d, slen = dlen; slen; s++, slen--)
ccbcddb Little fix from EGE.
Thomas Roessler authored
358 if (*s < 0x20 || *s >= 0x7f ||
359 strchr (MimeSpecials, *s) || strchr ("*'%", *s))
fc6b8f9 Implement RFC 2231.
Thomas Roessler authored
360 {
762d375 Do character set selection for RFC2231 encodings. From EGE, but
Thomas Roessler authored
361 sprintf (t, "%%%02X", (unsigned char)*s);
fc6b8f9 Implement RFC 2231.
Thomas Roessler authored
362 t += 3;
363 }
364 else
365 *t++ = *s;
366 *t = '\0';
367
762d375 Do character set selection for RFC2231 encodings. From EGE, but
Thomas Roessler authored
368 if (d != *pd)
cbab567 Replace safe_free calls by the FREE macro.
Thomas Roessler authored
369 FREE (&d);
850e0a9 Avoid safe_free() usage and add security checks
Rocco Rutte authored
370 FREE (pd); /* __FREE_CHECKED__ */
762d375 Do character set selection for RFC2231 encodings. From EGE, but
Thomas Roessler authored
371 *pd = e;
372 }
373 else if (d != *pd)
374 {
850e0a9 Avoid safe_free() usage and add security checks
Rocco Rutte authored
375 FREE (pd); /* __FREE_CHECKED__ */
762d375 Do character set selection for RFC2231 encodings. From EGE, but
Thomas Roessler authored
376 *pd = d;
fc6b8f9 Implement RFC 2231.
Thomas Roessler authored
377 }
a0f5767 Let check_sec.sh check for use of the unsafe malloc, realloc, free,
Thomas Roessler authored
378
cbab567 Replace safe_free calls by the FREE macro.
Thomas Roessler authored
379 FREE (&charset);
a0f5767 Let check_sec.sh check for use of the unsafe malloc, realloc, free,
Thomas Roessler authored
380
fc6b8f9 Implement RFC 2231.
Thomas Roessler authored
381 return encode;
382 }
a0f5767 Let check_sec.sh check for use of the unsafe malloc, realloc, free,
Thomas Roessler authored
383
Something went wrong with that request. Please try again.