mutt stable branch with some hacks
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at jcs 471 lines 11 kB view raw
1/* 2 * Copyright (C) 1999-2001 Thomas Roessler <roessler@does-not-exist.org> 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 18 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA. 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 32#if HAVE_CONFIG_H 33# include "config.h" 34#endif 35 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 46struct rfc2231_parameter 47{ 48 char *attribute; 49 char *value; 50 int index; 51 int encoded; 52 struct rfc2231_parameter *next; 53}; 54 55static char *rfc2231_get_charset (char *, char *, size_t); 56static struct rfc2231_parameter *rfc2231_new_parameter (void); 57static void rfc2231_decode_one (char *, char *); 58static void rfc2231_free_parameter (struct rfc2231_parameter **); 59static void rfc2231_join_continuations (PARAMETER **, struct rfc2231_parameter *); 60static void rfc2231_list_insert (struct rfc2231_parameter **, struct rfc2231_parameter *); 61 62static void purge_empty_parameters (PARAMETER **headp) 63{ 64 PARAMETER *p, *q, **last; 65 66 for (last = headp, p = *headp; p; p = q) 67 { 68 q = p->next; 69 if (!p->attribute || !p->value) 70 { 71 *last = q; 72 p->next = NULL; 73 mutt_free_parameter (&p); 74 } 75 else 76 last = &p->next; 77 } 78} 79 80 81void rfc2231_decode_parameters (PARAMETER **headp) 82{ 83 PARAMETER *head = NULL; 84 PARAMETER **last; 85 PARAMETER *p, *q; 86 87 struct rfc2231_parameter *conthead = NULL; 88 struct rfc2231_parameter *conttmp; 89 90 char *s, *t; 91 char charset[STRING]; 92 93 int encoded; 94 int index; 95 short dirty = 0; /* set to 1 when we may have created 96 * empty parameters. 97 */ 98 99 if (!headp) return; 100 101 purge_empty_parameters (headp); 102 103 for (last = &head, p = *headp; p; p = q) 104 { 105 q = p->next; 106 107 if (!(s = strchr (p->attribute, '*'))) 108 { 109 110 /* 111 * Using RFC 2047 encoding in MIME parameters is explicitly 112 * forbidden by that document. Nevertheless, it's being 113 * generated by some software, including certain Lotus Notes to 114 * Internet Gateways. So we actually decode it. 115 */ 116 117 if (option (OPTRFC2047PARAMS) && p->value && strstr (p->value, "=?")) 118 rfc2047_decode (&p->value); 119 else if (AssumedCharset) 120 convert_nonmime_string (&p->value); 121 122 *last = p; 123 last = &p->next; 124 p->next = NULL; 125 } 126 else if (*(s + 1) == '\0') 127 { 128 *s = '\0'; 129 130 s = rfc2231_get_charset (p->value, charset, sizeof (charset)); 131 rfc2231_decode_one (p->value, s); 132 mutt_convert_string (&p->value, charset, Charset, MUTT_ICONV_HOOK_FROM); 133 mutt_filter_unprintable (&p->value); 134 135 *last = p; 136 last = &p->next; 137 p->next = NULL; 138 139 dirty = 1; 140 } 141 else 142 { 143 *s = '\0'; s++; /* let s point to the first character of index. */ 144 for (t = s; *t && isdigit ((unsigned char) *t); t++) 145 ; 146 encoded = (*t == '*'); 147 *t = '\0'; 148 149 /* RFC 2231 says that the index starts at 0 and increments by 1, 150 thus an overflow should never occur in a valid message, thus 151 the value INT_MAX in case of overflow does not really matter 152 (the goal is just to avoid undefined behavior). */ 153 if (mutt_atoi (s, &index)) 154 index = INT_MAX; 155 156 conttmp = rfc2231_new_parameter (); 157 conttmp->attribute = p->attribute; 158 conttmp->value = p->value; 159 conttmp->encoded = encoded; 160 conttmp->index = index; 161 162 p->attribute = NULL; 163 p->value = NULL; 164 FREE (&p); 165 166 rfc2231_list_insert (&conthead, conttmp); 167 } 168 } 169 170 if (conthead) 171 { 172 rfc2231_join_continuations (last, conthead); 173 dirty = 1; 174 } 175 176 *headp = head; 177 178 if (dirty) 179 purge_empty_parameters (headp); 180} 181 182static struct rfc2231_parameter *rfc2231_new_parameter (void) 183{ 184 return safe_calloc (sizeof (struct rfc2231_parameter), 1); 185} 186 187static void rfc2231_free_parameter (struct rfc2231_parameter **p) 188{ 189 if (*p) 190 { 191 FREE (&(*p)->attribute); 192 FREE (&(*p)->value); 193 FREE (p); /* __FREE_CHECKED__ */ 194 } 195} 196 197static char *rfc2231_get_charset (char *value, char *charset, size_t chslen) 198{ 199 char *t, *u; 200 201 if (!(t = strchr (value, '\''))) 202 { 203 charset[0] = '\0'; 204 return value; 205 } 206 207 *t = '\0'; 208 strfcpy (charset, value, chslen); 209 210 if ((u = strchr (t + 1, '\''))) 211 return u + 1; 212 else 213 return t + 1; 214} 215 216static void rfc2231_decode_one (char *dest, char *src) 217{ 218 char *d; 219 220 for (d = dest; *src; src++) 221 { 222 if (*src == '%' && 223 isxdigit ((unsigned char) *(src + 1)) && 224 isxdigit ((unsigned char) *(src + 2))) 225 { 226 *d++ = (hexval (*(src + 1)) << 4) | (hexval (*(src + 2))); 227 src += 2; 228 } 229 else 230 *d++ = *src; 231 } 232 233 *d = '\0'; 234} 235 236/* insert parameter into an ordered list. 237 * 238 * Primary sorting key: attribute 239 * Secondary sorting key: index 240 */ 241 242static void rfc2231_list_insert (struct rfc2231_parameter **list, 243 struct rfc2231_parameter *par) 244{ 245 struct rfc2231_parameter **last = list; 246 struct rfc2231_parameter *p = *list; 247 int c; 248 249 while (p) 250 { 251 c = strcmp (par->attribute, p->attribute); 252 if ((c < 0) || (c == 0 && par->index <= p->index)) 253 break; 254 255 last = &p->next; 256 p = p->next; 257 } 258 259 par->next = p; 260 *last = par; 261} 262 263/* process continuation parameters */ 264 265static void rfc2231_join_continuations (PARAMETER **head, 266 struct rfc2231_parameter *par) 267{ 268 struct rfc2231_parameter *q; 269 270 char attribute[STRING]; 271 char charset[STRING]; 272 char *value = NULL; 273 char *valp; 274 int encoded; 275 276 size_t l, vl; 277 278 while (par) 279 { 280 value = NULL; l = 0; 281 282 strfcpy (attribute, par->attribute, sizeof (attribute)); 283 284 if ((encoded = par->encoded)) 285 valp = rfc2231_get_charset (par->value, charset, sizeof (charset)); 286 else 287 valp = par->value; 288 289 do 290 { 291 if (encoded && par->encoded) 292 rfc2231_decode_one (par->value, valp); 293 294 vl = strlen (par->value); 295 296 safe_realloc (&value, l + vl + 1); 297 strcpy (value + l, par->value); /* __STRCPY_CHECKED__ */ 298 l += vl; 299 300 q = par->next; 301 rfc2231_free_parameter (&par); 302 if ((par = q)) 303 valp = par->value; 304 } while (par && !strcmp (par->attribute, attribute)); 305 306 if (value) 307 { 308 if (encoded) 309 mutt_convert_string (&value, charset, Charset, MUTT_ICONV_HOOK_FROM); 310 *head = mutt_new_parameter (); 311 (*head)->attribute = safe_strdup (attribute); 312 (*head)->value = value; 313 head = &(*head)->next; 314 } 315 } 316} 317 318PARAMETER *rfc2231_encode_string (const char *attribute, char *value) 319{ 320 int encode = 0, add_quotes = 0, free_src_value = 0; 321 int split = 0, continuation_number = 0; 322 size_t dest_value_len = 0, max_value_len = 0, cur_value_len = 0; 323 char *cur, *charset = NULL, *src_value = NULL; 324 PARAMETER *result = NULL, *current, **lastp; 325 BUFFER *cur_attribute, *cur_value; 326 327 cur_attribute = mutt_buffer_pool_get (); 328 cur_value = mutt_buffer_pool_get (); 329 330 /* 331 * Perform charset conversion 332 */ 333 for (cur = value; *cur; cur++) 334 if (*cur < 0x20 || *cur >= 0x7f) 335 { 336 encode = 1; 337 break; 338 } 339 340 if (encode) 341 { 342 if (Charset && SendCharset) 343 charset = mutt_choose_charset (Charset, SendCharset, 344 value, mutt_strlen (value), 345 &src_value, NULL); 346 if (src_value) 347 free_src_value = 1; 348 if (!charset) 349 charset = safe_strdup (Charset ? Charset : "unknown-8bit"); 350 } 351 if (!src_value) 352 src_value = value; 353 354 /* 355 * Count the size the resultant value will need in total. 356 */ 357 if (encode) 358 dest_value_len = mutt_strlen (charset) + 2; /* charset'' prefix */ 359 360 for (cur = src_value; *cur; cur++) 361 { 362 dest_value_len++; 363 364 if (encode) 365 { 366 /* These get converted to %xx so need a total of three chars */ 367 if (*cur < 0x20 || *cur >= 0x7f || 368 strchr (MimeSpecials, *cur) || 369 strchr ("*'%", *cur)) 370 { 371 dest_value_len += 2; 372 } 373 } 374 else 375 { 376 /* rfc822_cat() will add outer quotes if it finds MimeSpecials. */ 377 if (!add_quotes && strchr (MimeSpecials, *cur)) 378 add_quotes = 1; 379 /* rfc822_cat() will add a backslash if it finds '\' or '"'. */ 380 if (*cur == '\\' || *cur == '"') 381 dest_value_len++; 382 } 383 } 384 385 /* 386 * Determine if need to split into parameter value continuations 387 */ 388 max_value_len = 389 78 - /* rfc suggested line length */ 390 1 - /* Leading tab on continuation line */ 391 mutt_strlen (attribute) - /* attribute */ 392 (encode ? 1 : 0) - /* '*' encoding marker */ 393 1 - /* '=' */ 394 (add_quotes ? 2 : 0) - /* "...." */ 395 1; /* ';' */ 396 397 if (max_value_len < 30) 398 max_value_len = 30; 399 400 if (dest_value_len > max_value_len) 401 { 402 split = 1; 403 max_value_len -= 4; /* '*n' continuation number and extra encoding 404 * space to keep loop below simpler */ 405 } 406 407 /* 408 * Generate list of parameter continuations. 409 */ 410 lastp = &result; 411 cur = src_value; 412 if (encode) 413 { 414 mutt_buffer_printf (cur_value, "%s''", charset); 415 cur_value_len = mutt_buffer_len (cur_value); 416 } 417 418 while (*cur) 419 { 420 *lastp = current = mutt_new_parameter (); 421 lastp = &current->next; 422 mutt_buffer_strcpy (cur_attribute, attribute); 423 if (split) 424 mutt_buffer_add_printf (cur_attribute, "*%d", continuation_number++); 425 if (encode) 426 mutt_buffer_addch (cur_attribute, '*'); 427 428 while (*cur && (!split || cur_value_len < max_value_len)) 429 { 430 if (encode) 431 { 432 if (*cur < 0x20 || *cur >= 0x7f || 433 strchr (MimeSpecials, *cur) || 434 strchr ("*'%", *cur)) 435 { 436 mutt_buffer_add_printf (cur_value, "%%%02X", (unsigned char)*cur); 437 cur_value_len += 3; 438 } 439 else 440 { 441 mutt_buffer_addch (cur_value, *cur); 442 cur_value_len++; 443 } 444 } 445 else 446 { 447 mutt_buffer_addch (cur_value, *cur); 448 cur_value_len++; 449 if (*cur == '\\' || *cur == '"') 450 cur_value_len++; 451 } 452 453 cur++; 454 } 455 456 current->attribute = safe_strdup (mutt_b2s (cur_attribute)); 457 current->value = safe_strdup (mutt_b2s (cur_value)); 458 459 mutt_buffer_clear (cur_value); 460 cur_value_len = 0; 461 } 462 463 mutt_buffer_pool_release (&cur_attribute); 464 mutt_buffer_pool_release (&cur_value); 465 466 FREE (&charset); 467 if (free_src_value) 468 FREE (&src_value); 469 470 return result; 471}