mutt stable branch with some hacks
at jcs 924 lines 20 kB view raw
1/* 2 * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org> 3 * Copyright (C) 2011-2013 Michael R. Elkins <me@mutt.org> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 */ 19 20#if HAVE_CONFIG_H 21# include "config.h" 22#endif 23 24#include <string.h> 25#include <stdlib.h> 26 27#ifndef TESTING 28#include "mutt.h" 29#else 30#define safe_strdup strdup 31#define safe_malloc malloc 32#define FREE(x) safe_free(x) 33#define strfcpy(a,b,c) {if (c) {strncpy(a,b,c);a[c-1]=0;}} 34#define LONG_STRING 1024 35#include "rfc822.h" 36#endif 37 38#include "mutt_idna.h" 39 40#define terminate_string(a, b, c) \ 41 do \ 42 { \ 43 if ((b) < (c)) \ 44 a[(b)] = 0; \ 45 else \ 46 a[(c)] = 0; \ 47 } while (0) 48 49#define terminate_buffer(a, b) terminate_string(a, b, sizeof (a) - 1) 50 51const char RFC822Specials[] = "@.,:;<>[]\\\"()"; 52#define is_special(x) strchr(RFC822Specials,x) 53 54int RFC822Error = 0; 55 56/* these must defined in the same order as the numerated errors given in rfc822.h */ 57const char * const RFC822Errors[] = { 58 "out of memory", 59 "mismatched parenthesis", 60 "mismatched quotes", 61 "bad route in <>", 62 "bad address in <>", 63 "bad address spec" 64}; 65 66void rfc822_dequote_comment (char *s) 67{ 68 char *w = s; 69 70 for (; *s; s++) 71 { 72 if (*s == '\\') 73 { 74 if (!*++s) 75 break; /* error? */ 76 *w++ = *s; 77 } 78 else if (*s != '\"') 79 { 80 if (w != s) 81 *w = *s; 82 w++; 83 } 84 } 85 *w = 0; 86} 87 88static void free_address (ADDRESS *a) 89{ 90 FREE(&a->personal); 91 FREE(&a->mailbox); 92#ifdef EXACT_ADDRESS 93 FREE(&a->val); 94#endif 95 FREE(&a); 96} 97 98int rfc822_remove_from_adrlist (ADDRESS **a, const char *mailbox) 99{ 100 ADDRESS *p, *last = NULL, *t; 101 int rv = -1; 102 103 p = *a; 104 last = NULL; 105 while (p) 106 { 107 if (ascii_strcasecmp (mailbox, p->mailbox) == 0) 108 { 109 if (last) 110 last->next = p->next; 111 else 112 (*a) = p->next; 113 t = p; 114 p = p->next; 115 free_address (t); 116 rv = 0; 117 } 118 else 119 { 120 last = p; 121 p = p->next; 122 } 123 } 124 125 return (rv); 126} 127 128void rfc822_free_address (ADDRESS **p) 129{ 130 ADDRESS *t; 131 132 while (*p) 133 { 134 t = *p; 135 *p = (*p)->next; 136#ifdef EXACT_ADDRESS 137 FREE (&t->val); 138#endif 139 FREE (&t->personal); 140 FREE (&t->mailbox); 141 FREE (&t); 142 } 143} 144 145static const char * 146parse_comment (const char *s, 147 char *comment, size_t *commentlen, size_t commentmax) 148{ 149 int level = 1; 150 151 while (*s && level) 152 { 153 if (*s == '(') 154 level++; 155 else if (*s == ')') 156 { 157 if (--level == 0) 158 { 159 s++; 160 break; 161 } 162 } 163 else if (*s == '\\') 164 { 165 if (!*++s) 166 break; 167 } 168 if (*commentlen < commentmax) 169 comment[(*commentlen)++] = *s; 170 s++; 171 } 172 if (level) 173 { 174 RFC822Error = ERR_MISMATCH_PAREN; 175 return NULL; 176 } 177 return s; 178} 179 180static const char * 181parse_quote (const char *s, char *token, size_t *tokenlen, size_t tokenmax) 182{ 183 while (*s) 184 { 185 if (*tokenlen < tokenmax) 186 token[*tokenlen] = *s; 187 if (*s == '\\') 188 { 189 if (!*++s) 190 break; 191 192 if (*tokenlen < tokenmax) 193 token[*tokenlen] = *s; 194 } 195 else if (*s == '"') 196 return (s + 1); 197 (*tokenlen)++; 198 s++; 199 } 200 RFC822Error = ERR_MISMATCH_QUOTE; 201 return NULL; 202} 203 204static const char * 205next_token (const char *s, char *token, size_t *tokenlen, size_t tokenmax) 206{ 207 if (*s == '(') 208 return (parse_comment (s + 1, token, tokenlen, tokenmax)); 209 if (*s == '"') 210 return (parse_quote (s + 1, token, tokenlen, tokenmax)); 211 if (*s && is_special (*s)) 212 { 213 if (*tokenlen < tokenmax) 214 token[(*tokenlen)++] = *s; 215 return (s + 1); 216 } 217 while (*s) 218 { 219 if (is_email_wsp(*s) || is_special (*s)) 220 break; 221 if (*tokenlen < tokenmax) 222 token[(*tokenlen)++] = *s; 223 s++; 224 } 225 return s; 226} 227 228static const char * 229parse_mailboxdomain (const char *s, const char *nonspecial, 230 char *mailbox, size_t *mailboxlen, size_t mailboxmax, 231 char *comment, size_t *commentlen, size_t commentmax) 232{ 233 const char *ps; 234 235 while (*s) 236 { 237 s = skip_email_wsp(s); 238 if (! *s) 239 return s; 240 241 if (strchr (nonspecial, *s) == NULL && is_special (*s)) 242 return s; 243 244 if (*s == '(') 245 { 246 if (*commentlen && *commentlen < commentmax) 247 comment[(*commentlen)++] = ' '; 248 ps = next_token (s, comment, commentlen, commentmax); 249 } 250 else 251 ps = next_token (s, mailbox, mailboxlen, mailboxmax); 252 if (!ps) 253 return NULL; 254 s = ps; 255 } 256 257 return s; 258} 259 260static const char * 261parse_address (const char *s, 262 char *token, size_t *tokenlen, size_t tokenmax, 263 char *comment, size_t *commentlen, size_t commentmax, 264 ADDRESS *addr) 265{ 266 s = parse_mailboxdomain (s, ".\"(\\", 267 token, tokenlen, tokenmax, 268 comment, commentlen, commentmax); 269 if (!s) 270 return NULL; 271 272 if (*s == '@') 273 { 274 if (*tokenlen < tokenmax) 275 token[(*tokenlen)++] = '@'; 276 s = parse_mailboxdomain (s + 1, ".([]\\", 277 token, tokenlen, tokenmax, 278 comment, commentlen, commentmax); 279 if (!s) 280 return NULL; 281 } 282 283 terminate_string (token, *tokenlen, tokenmax); 284 addr->mailbox = safe_strdup (token); 285 286 if (*commentlen && !addr->personal) 287 { 288 terminate_string (comment, *commentlen, commentmax); 289 addr->personal = safe_strdup (comment); 290 } 291 292 return s; 293} 294 295static const char * 296parse_route_addr (const char *s, 297 char *comment, size_t *commentlen, size_t commentmax, 298 ADDRESS *addr) 299{ 300 char token[LONG_STRING]; 301 size_t tokenlen = 0; 302 303 s = skip_email_wsp(s); 304 305 /* find the end of the route */ 306 if (*s == '@') 307 { 308 while (s && *s == '@') 309 { 310 if (tokenlen < sizeof (token) - 1) 311 token[tokenlen++] = '@'; 312 s = parse_mailboxdomain (s + 1, ",.\\[](", token, 313 &tokenlen, sizeof (token) - 1, 314 comment, commentlen, commentmax); 315 } 316 if (!s || *s != ':') 317 { 318 RFC822Error = ERR_BAD_ROUTE; 319 return NULL; /* invalid route */ 320 } 321 322 if (tokenlen < sizeof (token) - 1) 323 token[tokenlen++] = ':'; 324 s++; 325 } 326 327 if ((s = parse_address (s, token, &tokenlen, sizeof (token) - 1, comment, commentlen, commentmax, addr)) == NULL) 328 return NULL; 329 330 if (*s != '>') 331 { 332 RFC822Error = ERR_BAD_ROUTE_ADDR; 333 return NULL; 334 } 335 336 if (!addr->mailbox) 337 addr->mailbox = safe_strdup ("@"); 338 339 s++; 340 return s; 341} 342 343static const char * 344parse_addr_spec (const char *s, 345 char *comment, size_t *commentlen, size_t commentmax, 346 ADDRESS *addr) 347{ 348 char token[LONG_STRING]; 349 size_t tokenlen = 0; 350 351 s = parse_address (s, token, &tokenlen, sizeof (token) - 1, comment, commentlen, commentmax, addr); 352 if (s && *s && *s != ',' && *s != ';') 353 { 354 RFC822Error = ERR_BAD_ADDR_SPEC; 355 return NULL; 356 } 357 return s; 358} 359 360static void 361add_addrspec (ADDRESS **top, ADDRESS **last, const char *phrase, 362 char *comment, size_t *commentlen, size_t commentmax) 363{ 364 ADDRESS *cur = rfc822_new_address (); 365 366 if (parse_addr_spec (phrase, comment, commentlen, commentmax, cur) == NULL) 367 { 368 rfc822_free_address (&cur); 369 return; 370 } 371 372 if (*last) 373 (*last)->next = cur; 374 else 375 *top = cur; 376 *last = cur; 377} 378 379ADDRESS *rfc822_parse_adrlist (ADDRESS *top, const char *s) 380{ 381 int ws_pending, nl; 382#ifdef EXACT_ADDRESS 383 const char *begin; 384#endif 385 const char *ps; 386 char comment[LONG_STRING], phrase[LONG_STRING]; 387 size_t phraselen = 0, commentlen = 0; 388 ADDRESS *cur, *last = NULL; 389 390 RFC822Error = 0; 391 392 last = top; 393 while (last && last->next) 394 last = last->next; 395 396 ws_pending = is_email_wsp (*s); 397 if ((nl = mutt_strlen (s))) 398 nl = s[nl - 1] == '\n'; 399 400 s = skip_email_wsp(s); 401#ifdef EXACT_ADDRESS 402 begin = s; 403#endif 404 while (*s) 405 { 406 if (*s == ',') 407 { 408 if (phraselen) 409 { 410 terminate_buffer (phrase, phraselen); 411 add_addrspec (&top, &last, phrase, comment, &commentlen, sizeof (comment) - 1); 412 } 413 else if (commentlen && last && !last->personal) 414 { 415 terminate_buffer (comment, commentlen); 416 last->personal = safe_strdup (comment); 417 } 418 419#ifdef EXACT_ADDRESS 420 if (last && !last->val) 421 last->val = mutt_substrdup (begin, s); 422#endif 423 commentlen = 0; 424 phraselen = 0; 425 s++; 426#ifdef EXACT_ADDRESS 427 begin = skip_email_wsp(s); 428#endif 429 } 430 else if (*s == '(') 431 { 432 if (commentlen && commentlen < sizeof (comment) - 1) 433 comment[commentlen++] = ' '; 434 if ((ps = next_token (s, comment, &commentlen, sizeof (comment) - 1)) == NULL) 435 { 436 rfc822_free_address (&top); 437 return NULL; 438 } 439 s = ps; 440 } 441 else if (*s == '"') 442 { 443 if (phraselen && phraselen < sizeof (phrase) - 1) 444 phrase[phraselen++] = ' '; 445 if ((ps = parse_quote (s + 1, phrase, &phraselen, sizeof (phrase) - 1)) == NULL) 446 { 447 rfc822_free_address (&top); 448 return NULL; 449 } 450 s = ps; 451 } 452 else if (*s == ':') 453 { 454 cur = rfc822_new_address (); 455 terminate_buffer (phrase, phraselen); 456 cur->mailbox = safe_strdup (phrase); 457 cur->group = 1; 458 459 if (last) 460 last->next = cur; 461 else 462 top = cur; 463 last = cur; 464 465#ifdef EXACT_ADDRESS 466 last->val = mutt_substrdup (begin, s); 467#endif 468 469 phraselen = 0; 470 commentlen = 0; 471 s++; 472#ifdef EXACT_ADDRESS 473 begin = skip_email_wsp(s); 474#endif 475 } 476 else if (*s == ';') 477 { 478 if (phraselen) 479 { 480 terminate_buffer (phrase, phraselen); 481 add_addrspec (&top, &last, phrase, comment, &commentlen, sizeof (comment) - 1); 482 } 483 else if (commentlen && last && !last->personal) 484 { 485 terminate_buffer (comment, commentlen); 486 last->personal = safe_strdup (comment); 487 } 488#ifdef EXACT_ADDRESS 489 if (last && !last->val) 490 last->val = mutt_substrdup (begin, s); 491#endif 492 493 /* add group terminator */ 494 cur = rfc822_new_address (); 495 if (last) 496 { 497 last->next = cur; 498 last = cur; 499 } 500 501 phraselen = 0; 502 commentlen = 0; 503#ifdef EXACT_ADDRESS 504 begin = s; 505#endif 506 s++; 507 } 508 else if (*s == '<') 509 { 510 terminate_buffer (phrase, phraselen); 511 cur = rfc822_new_address (); 512 if (phraselen) 513 cur->personal = safe_strdup (phrase); 514 if ((ps = parse_route_addr (s + 1, comment, &commentlen, sizeof (comment) - 1, cur)) == NULL) 515 { 516 rfc822_free_address (&top); 517 rfc822_free_address (&cur); 518 return NULL; 519 } 520 521 if (last) 522 last->next = cur; 523 else 524 top = cur; 525 last = cur; 526 527 phraselen = 0; 528 commentlen = 0; 529 s = ps; 530 } 531 else 532 { 533 if (phraselen && phraselen < sizeof (phrase) - 1 && ws_pending) 534 phrase[phraselen++] = ' '; 535 if ((ps = next_token (s, phrase, &phraselen, sizeof (phrase) - 1)) == NULL) 536 { 537 rfc822_free_address (&top); 538 return NULL; 539 } 540 s = ps; 541 } 542 ws_pending = is_email_wsp(*s); 543 s = skip_email_wsp(s); 544 } 545 546 if (phraselen) 547 { 548 terminate_buffer (phrase, phraselen); 549 terminate_buffer (comment, commentlen); 550 add_addrspec (&top, &last, phrase, comment, &commentlen, sizeof (comment) - 1); 551 } 552 else if (commentlen && last && !last->personal) 553 { 554 terminate_buffer (comment, commentlen); 555 last->personal = safe_strdup (comment); 556 } 557#ifdef EXACT_ADDRESS 558 if (last) 559 last->val = mutt_substrdup (begin, s - nl < begin ? begin : s - nl); 560#endif 561 562 return top; 563} 564 565void rfc822_qualify (ADDRESS *addr, const char *host) 566{ 567 char *p; 568 569 for (; addr; addr = addr->next) 570 if (!addr->group && addr->mailbox && strchr (addr->mailbox, '@') == NULL) 571 { 572 p = safe_malloc (mutt_strlen (addr->mailbox) + mutt_strlen (host) + 2); 573 sprintf (p, "%s@%s", addr->mailbox, host); /* __SPRINTF_CHECKED__ */ 574 FREE (&addr->mailbox); 575 addr->mailbox = p; 576 } 577} 578 579void 580rfc822_cat (char *buf, size_t buflen, const char *value, const char *specials) 581{ 582 if (strpbrk (value, specials)) 583 { 584 char tmp[256], *pc = tmp; 585 size_t tmplen = sizeof (tmp) - 3; 586 587 *pc++ = '"'; 588 for (; *value && tmplen > 1; value++) 589 { 590 if (*value == '\\' || *value == '"') 591 { 592 *pc++ = '\\'; 593 tmplen--; 594 } 595 *pc++ = *value; 596 tmplen--; 597 } 598 *pc++ = '"'; 599 *pc = 0; 600 strfcpy (buf, tmp, buflen); 601 } 602 else 603 strfcpy (buf, value, buflen); 604} 605 606void rfc822_write_address_single (char *buf, size_t buflen, ADDRESS *addr, 607 int display) 608{ 609 size_t len; 610 char *pbuf = buf; 611 char *pc; 612 613 if (!addr) 614 return; 615 616 buflen--; /* save room for the terminal nul */ 617 618#ifdef EXACT_ADDRESS 619 if (addr->val) 620 { 621 if (!buflen) 622 goto done; 623 strfcpy (pbuf, addr->val, buflen); 624 len = mutt_strlen (pbuf); 625 pbuf += len; 626 buflen -= len; 627 if (addr->group) 628 { 629 if (!buflen) 630 goto done; 631 *pbuf++ = ':'; 632 buflen--; 633 *pbuf = 0; 634 } 635 return; 636 } 637#endif 638 639 if (addr->personal) 640 { 641 if (strpbrk (addr->personal, RFC822Specials)) 642 { 643 if (!buflen) 644 goto done; 645 *pbuf++ = '"'; 646 buflen--; 647 for (pc = addr->personal; *pc && buflen > 0; pc++) 648 { 649 if (*pc == '"' || *pc == '\\') 650 { 651 *pbuf++ = '\\'; 652 buflen--; 653 } 654 if (!buflen) 655 goto done; 656 *pbuf++ = *pc; 657 buflen--; 658 } 659 if (!buflen) 660 goto done; 661 *pbuf++ = '"'; 662 buflen--; 663 } 664 else 665 { 666 if (!buflen) 667 goto done; 668 strfcpy (pbuf, addr->personal, buflen); 669 len = mutt_strlen (pbuf); 670 pbuf += len; 671 buflen -= len; 672 } 673 674 if (!buflen) 675 goto done; 676 *pbuf++ = ' '; 677 buflen--; 678 } 679 680 if (addr->personal || (addr->mailbox && *addr->mailbox == '@')) 681 { 682 if (!buflen) 683 goto done; 684 *pbuf++ = '<'; 685 buflen--; 686 } 687 688 if (addr->mailbox) 689 { 690 if (!buflen) 691 goto done; 692 if (ascii_strcmp (addr->mailbox, "@") && !display) 693 { 694 strfcpy (pbuf, addr->mailbox, buflen); 695 len = mutt_strlen (pbuf); 696 } 697 else if (ascii_strcmp (addr->mailbox, "@") && display) 698 { 699 strfcpy (pbuf, mutt_addr_for_display (addr), buflen); 700 len = mutt_strlen (pbuf); 701 } 702 else 703 { 704 *pbuf = '\0'; 705 len = 0; 706 } 707 pbuf += len; 708 buflen -= len; 709 710 if (addr->personal || (addr->mailbox && *addr->mailbox == '@')) 711 { 712 if (!buflen) 713 goto done; 714 *pbuf++ = '>'; 715 buflen--; 716 } 717 718 if (addr->group) 719 { 720 if (!buflen) 721 goto done; 722 *pbuf++ = ':'; 723 buflen--; 724 if (!buflen) 725 goto done; 726 *pbuf++ = ' '; 727 buflen--; 728 } 729 } 730 else 731 { 732 if (!buflen) 733 goto done; 734 *pbuf++ = ';'; 735 buflen--; 736 } 737done: 738 /* no need to check for length here since we already save space at the 739 beginning of this routine */ 740 *pbuf = 0; 741} 742 743/* note: it is assumed that `buf' is nul terminated! */ 744int rfc822_write_address (char *buf, size_t buflen, ADDRESS *addr, int display) 745{ 746 char *pbuf = buf; 747 size_t len = mutt_strlen (buf); 748 749 buflen--; /* save room for the terminal nul */ 750 751 if (len > 0) 752 { 753 if (len > buflen) 754 return pbuf - buf; /* safety check for bogus arguments */ 755 756 pbuf += len; 757 buflen -= len; 758 if (!buflen) 759 goto done; 760 *pbuf++ = ','; 761 buflen--; 762 if (!buflen) 763 goto done; 764 *pbuf++ = ' '; 765 buflen--; 766 } 767 768 for (; addr && buflen > 0; addr = addr->next) 769 { 770 /* use buflen+1 here because we already saved space for the trailing 771 nul char, and the subroutine can make use of it */ 772 rfc822_write_address_single (pbuf, buflen + 1, addr, display); 773 774 /* this should be safe since we always have at least 1 char passed into 775 the above call, which means `pbuf' should always be nul terminated */ 776 len = mutt_strlen (pbuf); 777 pbuf += len; 778 buflen -= len; 779 780 /* if there is another address, and its not a group mailbox name or 781 group terminator, add a comma to separate the addresses */ 782 if (addr->next && addr->next->mailbox && !addr->group) 783 { 784 if (!buflen) 785 goto done; 786 *pbuf++ = ','; 787 buflen--; 788 if (!buflen) 789 goto done; 790 *pbuf++ = ' '; 791 buflen--; 792 } 793 } 794done: 795 *pbuf = 0; 796 return pbuf - buf; 797} 798 799/* this should be rfc822_cpy_adr */ 800ADDRESS *rfc822_cpy_adr_real (ADDRESS *addr) 801{ 802 ADDRESS *p = rfc822_new_address (); 803 804#ifdef EXACT_ADDRESS 805 p->val = safe_strdup (addr->val); 806#endif 807 p->personal = safe_strdup (addr->personal); 808 p->mailbox = safe_strdup (addr->mailbox); 809 p->group = addr->group; 810 p->is_intl = addr->is_intl; 811 p->intl_checked = addr->intl_checked; 812 return p; 813} 814 815/* this should be rfc822_cpy_adrlist */ 816ADDRESS *rfc822_cpy_adr (ADDRESS *addr, int prune) 817{ 818 ADDRESS *top = NULL, *last = NULL; 819 820 for (; addr; addr = addr->next) 821 { 822 if (prune && addr->group && (!addr->next || !addr->next->mailbox)) 823 { 824 /* ignore this element of the list */ 825 } 826 else if (last) 827 { 828 last->next = rfc822_cpy_adr_real (addr); 829 last = last->next; 830 } 831 else 832 top = last = rfc822_cpy_adr_real (addr); 833 } 834 return top; 835} 836 837/* append list 'b' to list 'a' and return the last element in the new list */ 838ADDRESS *rfc822_append (ADDRESS **a, ADDRESS *b, int prune) 839{ 840 ADDRESS *tmp = *a; 841 842 while (tmp && tmp->next) 843 tmp = tmp->next; 844 if (!b) 845 return tmp; 846 if (tmp) 847 tmp->next = rfc822_cpy_adr (b, prune); 848 else 849 tmp = *a = rfc822_cpy_adr (b, prune); 850 while (tmp && tmp->next) 851 tmp = tmp->next; 852 return tmp; 853} 854 855/* incomplete. Only used to thwart the APOP MD5 attack (#2846). */ 856int rfc822_valid_msgid (const char *msgid) 857{ 858 /* msg-id = "<" addr-spec ">" 859 * addr-spec = local-part "@" domain 860 * local-part = word *("." word) 861 * word = atom / quoted-string 862 * atom = 1*<any CHAR except specials, SPACE and CTLs> 863 * CHAR = ( 0.-127. ) 864 * specials = "(" / ")" / "<" / ">" / "@" 865 / "," / ";" / ":" / "\" / <"> 866 / "." / "[" / "]" 867 * SPACE = ( 32. ) 868 * CTLS = ( 0.-31., 127.) 869 * quoted-string = <"> *(qtext/quoted-pair) <"> 870 * qtext = <any CHAR except <">, "\" and CR> 871 * CR = ( 13. ) 872 * quoted-pair = "\" CHAR 873 * domain = sub-domain *("." sub-domain) 874 * sub-domain = domain-ref / domain-literal 875 * domain-ref = atom 876 * domain-literal = "[" *(dtext / quoted-pair) "]" 877 */ 878 879 unsigned int l, i; 880 881 if (!msgid || !*msgid) 882 return -1; 883 884 l = mutt_strlen (msgid); 885 if (l < 5) /* <atom@atom> */ 886 return -1; 887 if (msgid[0] != '<' || msgid[l-1] != '>') 888 return -1; 889 if (!(strrchr (msgid, '@'))) 890 return -1; 891 892 /* TODO: complete parser */ 893 for (i = 0; i < l; i++) 894 if ((unsigned char)msgid[i] > 127) 895 return -1; 896 897 return 0; 898} 899 900#ifdef TESTING 901int safe_free (void **p) /* __SAFE_FREE_CHECKED__ */ 902{ 903 free(*p); /* __MEM_CHECKED__ */ 904 *p = 0; 905} 906 907int main (int argc, char **argv) 908{ 909 ADDRESS *list; 910 char buf[256]; 911# if 0 912 char *str = "michael, Michael Elkins <me@mutt.org>, testing a really complex address: this example <@contains.a.source.route,@with.multiple.hosts:address@example.com>;, lothar@of.the.hillpeople (lothar)"; 913# else 914 char *str = "a b c "; 915# endif 916 917 list = rfc822_parse_adrlist (NULL, str); 918 buf[0] = 0; 919 rfc822_write_address (buf, sizeof (buf), list); 920 rfc822_free_address (&list); 921 puts (buf); 922 exit (0); 923} 924#endif