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