Fork of FusionPBX but with LDAP kinda working
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

902 lines
20 KiB

2 years ago
  1. <?php
  2. /*
  3. * rfc822_addresses.php
  4. *
  5. * @(#) $Id: rfc822_addresses.php,v 1.13 2010/04/08 20:09:23 mlemos Exp $
  6. *
  7. */
  8. /*
  9. {metadocument}<?xml version="1.0" encoding="ISO-8859-1" ?>
  10. <class>
  11. <package>net.manuellemos.mimeparser</package>
  12. <version>@(#) $Id: rfc822_addresses.php,v 1.13 2010/04/08 20:09:23 mlemos Exp $</version>
  13. <copyright>Copyright (C) Manuel Lemos 2006 - 2008</copyright>
  14. <title>RFC 822 e-mail addresses parser</title>
  15. <author>Manuel Lemos</author>
  16. <authoraddress>mlemos-at-acm.org</authoraddress>
  17. <documentation>
  18. <idiom>en</idiom>
  19. <purpose>Parse e-mail addresses from headers of <link>
  20. <url>http://www.ietf.org/rfc/rfc822.txt</url>
  21. <data>RFC 822</data>
  22. </link> compliant e-mail messages.</purpose>
  23. <usage>Use the function <functionlink>ParseAddressList</functionlink>
  24. function to retrieve the list of e-mail addresses contained in
  25. e-mail message headers like <tt>From</tt>, <tt>To</tt>, <tt>Cc</tt>
  26. or <tt>Bcc</tt>.</usage>
  27. </documentation>
  28. {/metadocument}
  29. */
  30. class rfc822_addresses_class
  31. {
  32. /* Private variables */
  33. var $v = '';
  34. /* Public variables */
  35. /*
  36. {metadocument}
  37. <variable>
  38. <name>error</name>
  39. <type>STRING</type>
  40. <value></value>
  41. <documentation>
  42. <purpose>Store the message that is returned when an error
  43. occurs.</purpose>
  44. <usage>Check this variable to understand what happened when a call to
  45. any of the class functions has failed.<paragraphbreak />
  46. This class uses cumulative error handling. This means that if one
  47. class functions that may fail is called and this variable was
  48. already set to an error message due to a failure in a previous call
  49. to the same or other function, the function will also fail and does
  50. not do anything.<paragraphbreak />
  51. This allows programs using this class to safely call several
  52. functions that may fail and only check the failure condition after
  53. the last function call.<paragraphbreak />
  54. Just set this variable to an empty string to clear the error
  55. condition.</usage>
  56. </documentation>
  57. </variable>
  58. {/metadocument}
  59. */
  60. var $error = '';
  61. /*
  62. {metadocument}
  63. <variable>
  64. <name>error_position</name>
  65. <type>INTEGER</type>
  66. <value>-1</value>
  67. <documentation>
  68. <purpose>Point to the position of the message data or file that
  69. refers to the last error that occurred.</purpose>
  70. <usage>Check this variable to determine the relevant position of the
  71. message when a parsing error occurs.</usage>
  72. </documentation>
  73. </variable>
  74. {/metadocument}
  75. */
  76. var $error_position = -1;
  77. /*
  78. {metadocument}
  79. <variable>
  80. <name>ignore_syntax_errors</name>
  81. <type>BOOLEAN</type>
  82. <value>1</value>
  83. <documentation>
  84. <purpose>Specify whether the class should ignore syntax errors in
  85. malformed addresses.</purpose>
  86. <usage>Set this variable to <booleanvalue>0</booleanvalue> if it is
  87. necessary to verify whether message data may be corrupted due to
  88. to eventual bugs in the program that generated the
  89. message.<paragraphbreak />
  90. Currently the class only ignores some types of syntax errors.
  91. Other syntax errors may still cause the
  92. <functionlink>ParseAddressList</functionlink> to fail.</usage>
  93. </documentation>
  94. </variable>
  95. {/metadocument}
  96. */
  97. var $ignore_syntax_errors=1;
  98. /*
  99. {metadocument}
  100. <variable>
  101. <name>warnings</name>
  102. <type>HASH</type>
  103. <value></value>
  104. <documentation>
  105. <purpose>Return a list of positions of the original message that
  106. contain syntax errors.</purpose>
  107. <usage>Check this variable to retrieve eventual message syntax
  108. errors that were ignored when the
  109. <variablelink>ignore_syntax_errors</variablelink> is set to
  110. <booleanvalue>1</booleanvalue>.<paragraphbreak />
  111. The indexes of this array are the positions of the errors. The
  112. array values are the corresponding syntax error messages.</usage>
  113. </documentation>
  114. </variable>
  115. {/metadocument}
  116. */
  117. var $warnings=array();
  118. /* Private functions */
  119. Function SetError($error)
  120. {
  121. $this->error = $error;
  122. return(0);
  123. }
  124. Function SetPositionedError($error, $position)
  125. {
  126. $this->error_position = $position;
  127. return($this->SetError($error));
  128. }
  129. Function SetWarning($warning, $position)
  130. {
  131. $this->warnings[$position]=$warning;
  132. return(1);
  133. }
  134. Function SetPositionedWarning($error, $position)
  135. {
  136. if(!$this->ignore_syntax_errors)
  137. return($this->SetPositionedError($error, $position));
  138. return($this->SetWarning($error, $position));
  139. }
  140. Function QDecode($p, &$value, &$encoding)
  141. {
  142. $encoding = $charset = null;
  143. $s = 0;
  144. $decoded = '';
  145. $l = strlen($value);
  146. while($s < $l)
  147. {
  148. if(GetType($q = strpos($value, '=?', $s)) != 'integer')
  149. {
  150. if($s == 0)
  151. return(1);
  152. if($s < $l)
  153. $decoded .= substr($value, $s);
  154. break;
  155. }
  156. if($s < $q)
  157. $decoded .= substr($value, $s, $q - $s);
  158. $q += 2;
  159. if(GetType($c = strpos($value, '?', $q)) != 'integer'
  160. || $q == $c)
  161. return($this->SetPositionedWarning('invalid Q-encoding character set', $p + $q));
  162. if(IsSet($charset))
  163. {
  164. $another_charset = strtolower(substr($value, $q, $c - $q));
  165. if(strcmp($charset, $another_charset)
  166. && strcmp($another_charset, 'ascii'))
  167. return($this->SetWarning('it is not possible to decode an encoded value using mixed character sets into a single value', $p + $q));
  168. }
  169. else
  170. {
  171. $charset = strtolower(substr($value, $q, $c - $q));
  172. if(!strcmp($charset, 'ascii'))
  173. $charset = null;
  174. }
  175. ++$c;
  176. if(GetType($t = strpos($value, '?', $c)) != 'integer'
  177. || $c==$t)
  178. return($this->SetPositionedWarning('invalid Q-encoding type', $p + $c));
  179. $type = strtolower(substr($value, $c, $t - $c));
  180. ++$t;
  181. if(GetType($e = strpos($value, '?=', $t)) != 'integer')
  182. return($this->SetPositionedWarning('invalid Q-encoding encoded data', $p + $e));
  183. switch($type)
  184. {
  185. case 'q':
  186. for($s = $t; $s<$e;)
  187. {
  188. switch($b = $value[$s])
  189. {
  190. case '=':
  191. $h = HexDec($hex = strtolower(substr($value, $s + 1, 2)));
  192. if($s + 3 > $e
  193. || strcmp(sprintf('%02x', $h), $hex))
  194. return($this->SetPositionedWarning('invalid Q-encoding q encoded data', $p + $s));
  195. $decoded .= chr($h);
  196. $s += 3;
  197. break;
  198. case '_':
  199. $decoded .= ' ';
  200. ++$s;
  201. break;
  202. default:
  203. $decoded .= $b;
  204. ++$s;
  205. }
  206. }
  207. break;
  208. case 'b':
  209. if($e <= $t
  210. || strlen($binary = base64_decode($data = substr($value, $t, $e - $t))) == 0
  211. || GetType($binary) != 'string')
  212. return($this->SetPositionedWarning('invalid Q-encoding b encoded data', $p + $t));
  213. $decoded .= $binary;
  214. $s = $e;
  215. break;
  216. default:
  217. return($this->SetPositionedWarning('Q-encoding '.$type.' is not yet supported', $p + $c));
  218. }
  219. $s += 2;
  220. }
  221. $value = $decoded;
  222. $encoding = $charset;
  223. return(1);
  224. }
  225. Function ParseCText(&$p, &$c_text)
  226. {
  227. $c_text = null;
  228. $v = $this->v;
  229. if($p<strlen($v)
  230. && GetType(strchr("\t\r\n ()\\\0", $c = $v[$p])) != 'string'
  231. && Ord($c)<128)
  232. {
  233. $c_text = $c;
  234. ++$p;
  235. }
  236. return(1);
  237. }
  238. Function ParseQText(&$p, &$q_text)
  239. {
  240. $q_text = null;
  241. $v = $this->v;
  242. if($p>strlen($v)
  243. || GetType(strchr("\t\r\n \"\\\0", $c = $v[$p])) == 'string')
  244. return(1);
  245. if(Ord($c) >= 128)
  246. {
  247. if(!$this->ignore_syntax_errors)
  248. return(1);
  249. $this->SetPositionedWarning('it was used an unencoded 8 bit character', $p);
  250. }
  251. $q_text = $c;
  252. ++$p;
  253. return(1);
  254. }
  255. Function ParseQuotedPair(&$p, &$quoted_pair)
  256. {
  257. $quoted_pair = null;
  258. $v = $this->v;
  259. $l = strlen($v);
  260. if($p+1 < $l
  261. && !strcmp($v[$p], '\\')
  262. && GetType(strchr("\r\n\0", $c = $v[$p + 1])) != 'string'
  263. && Ord($c)<128)
  264. {
  265. $quoted_pair = $c;
  266. $p += 2;
  267. }
  268. return(1);
  269. }
  270. Function ParseCContent(&$p, &$c_content)
  271. {
  272. $c_content = null;
  273. $c = $p;
  274. if(!$this->ParseQuotedPair($c, $content))
  275. return(0);
  276. if(!IsSet($content))
  277. {
  278. if(!$this->ParseCText($c, $content))
  279. return(0);
  280. if(!IsSet($content))
  281. {
  282. if(!$this->ParseComment($c, $content))
  283. return(0);
  284. if(!IsSet($content))
  285. return(1);
  286. }
  287. }
  288. $c_content = $content;
  289. $p = $c;
  290. return(1);
  291. }
  292. Function SkipWhiteSpace(&$p)
  293. {
  294. $v = $this->v;
  295. $l = strlen($v);
  296. for(;$p<$l; ++$p)
  297. {
  298. switch($v[$p])
  299. {
  300. case ' ':
  301. case "\n":
  302. case "\r":
  303. case "\t":
  304. break;
  305. default:
  306. return(1);
  307. }
  308. }
  309. return(1);
  310. }
  311. Function ParseComment(&$p, &$comment)
  312. {
  313. $comment = null;
  314. $v = $this->v;
  315. $l = strlen($v);
  316. $c = $p;
  317. if($c >= $l
  318. || strcmp($v[$c], '('))
  319. return(1);
  320. ++$c;
  321. for(; $c < $l;)
  322. {
  323. if(!$this->SkipWhiteSpace($c))
  324. return(0);
  325. if(!$this->ParseCContent($c, $c_content))
  326. return(0);
  327. if(!IsSet($c_content))
  328. break;
  329. }
  330. if(!$this->SkipWhiteSpace($c))
  331. return(0);
  332. if($c >= $l
  333. || strcmp($v[$c], ')'))
  334. return(1);
  335. ++$c;
  336. $comment = substr($v, $p, $c - $p);
  337. $p = $c;
  338. return(1);
  339. }
  340. Function SkipCommentGetWhiteSpace(&$p, &$space)
  341. {
  342. $v = $this->v;
  343. $l = strlen($v);
  344. for($space = '';$p<$l;)
  345. {
  346. switch($w = $v[$p])
  347. {
  348. case ' ':
  349. case "\n":
  350. case "\r":
  351. case "\t":
  352. ++$p;
  353. $space .= $w;
  354. break;
  355. case '(':
  356. if(!$this->ParseComment($p, $comment))
  357. return(0);
  358. default:
  359. return(1);
  360. }
  361. }
  362. return(1);
  363. }
  364. Function SkipCommentWhiteSpace(&$p)
  365. {
  366. $v = $this->v;
  367. $l = strlen($v);
  368. for(;$p<$l;)
  369. {
  370. switch($w = $v[$p])
  371. {
  372. case ' ':
  373. case "\n":
  374. case "\r":
  375. case "\t":
  376. ++$p;
  377. break;
  378. case '(':
  379. if(!$this->ParseComment($p, $comment))
  380. return(0);
  381. default:
  382. return(1);
  383. }
  384. }
  385. return(1);
  386. }
  387. Function ParseQContent(&$p, &$q_content)
  388. {
  389. $q_content = null;
  390. $q = $p;
  391. if(!$this->ParseQuotedPair($q, $content))
  392. return(0);
  393. if(!IsSet($content))
  394. {
  395. if(!$this->ParseQText($q, $content))
  396. return(0);
  397. if(!IsSet($content))
  398. return(1);
  399. }
  400. $q_content = $content;
  401. $p = $q;
  402. return(1);
  403. }
  404. Function ParseAtom(&$p, &$atom, $dot)
  405. {
  406. $atom = null;
  407. $v = $this->v;
  408. $l = strlen($v);
  409. $a = $p;
  410. if(!$this->SkipCommentGetWhiteSpace($a, $space))
  411. return(0);
  412. $match = '/^([-'.($dot ? '.' : '').'A-Za-z0-9!#$&\'*+\\/=?^_{|}~]+)/';
  413. for($s = $a;$a < $l;)
  414. {
  415. if(preg_match($match, substr($this->v, $a), $m))
  416. $a += strlen($m[1]);
  417. elseif(Ord($v[$a]) < 128)
  418. break;
  419. elseif(!$this->SetPositionedWarning('it was used an unencoded 8 bit character', $a))
  420. return(0);
  421. else
  422. ++$a;
  423. }
  424. if($s == $a)
  425. return(1);
  426. $atom = $space.substr($this->v, $s, $a - $s);
  427. if(!$this->SkipCommentGetWhiteSpace($a, $space))
  428. return(0);
  429. $atom .= $space;
  430. $p = $a;
  431. return(1);
  432. }
  433. Function ParseQuotedString(&$p, &$quoted_string)
  434. {
  435. $quoted_string = null;
  436. $v = $this->v;
  437. $l = strlen($v);
  438. $s = $p;
  439. if(!$this->SkipCommentWhiteSpace($s))
  440. return(0);
  441. if($s >= $l
  442. || strcmp($v[$s], '"'))
  443. return(1);
  444. ++$s;
  445. for($string = '';$s < $l;)
  446. {
  447. $w = $s;
  448. if(!$this->SkipWhiteSpace($s))
  449. return(0);
  450. if($w != $s)
  451. $string .= substr($v, $w, $s - $w);
  452. if(!$this->ParseQContent($s, $q_content))
  453. return(0);
  454. if(!IsSet($q_content))
  455. break;
  456. $string .= $q_content;
  457. }
  458. $w = $s;
  459. if(!$this->SkipWhiteSpace($s))
  460. return(0);
  461. if($w != $s)
  462. $string .= substr($v, $w, $s - $w);
  463. if($s >= $l
  464. || strcmp($v[$s], '"'))
  465. return(1);
  466. ++$s;
  467. if(!$this->SkipCommentWhiteSpace($s))
  468. return(0);
  469. $quoted_string = $string;
  470. $p = $s;
  471. return(1);
  472. }
  473. Function ParseWord(&$p, &$word)
  474. {
  475. $word = null;
  476. if(!$this->ParseQuotedString($p, $word))
  477. return(0);
  478. if(IsSet($word))
  479. return(1);
  480. if(!$this->ParseAtom($p, $word, 0))
  481. return(0);
  482. return(1);
  483. }
  484. Function ParseObsPhrase(&$p, &$obs_phrase)
  485. {
  486. $obs_phrase = null;
  487. $v = $this->v;
  488. $l = strlen($v);
  489. $ph = $p;
  490. if(!$this->ParseWord($ph, $word))
  491. return(0);
  492. $string = $word;
  493. for(;;)
  494. {
  495. if(!$this->ParseWord($ph, $word))
  496. return(0);
  497. if(IsSet($word))
  498. {
  499. $string .= $word;
  500. continue;
  501. }
  502. $w = $ph;
  503. if(!$this->SkipCommentGetWhiteSpace($ph, $space))
  504. return(0);
  505. if($w != $ph)
  506. {
  507. $string .= $space;
  508. continue;
  509. }
  510. if($ph >= $l
  511. || strcmp($v[$ph], '.'))
  512. break;
  513. $string .= '.';
  514. ++$ph;
  515. }
  516. $obs_phrase = $string;
  517. $p = $ph;
  518. return(1);
  519. }
  520. Function ParsePhrase(&$p, &$phrase)
  521. {
  522. $phrase = null;
  523. if(!$this->ParseObsPhrase($p, $phrase))
  524. return(0);
  525. if(IsSet($phrase))
  526. return(1);
  527. $ph = $p;
  528. if(!$this->ParseWord($ph, $word))
  529. return(0);
  530. $string = $word;
  531. for(;;)
  532. {
  533. if(!$this->ParseWord($ph, $word))
  534. return(0);
  535. if(!IsSet($word))
  536. break;
  537. $string .= $word;
  538. }
  539. $phrase = $string;
  540. $p = $ph;
  541. return(1);
  542. }
  543. Function ParseAddrSpec(&$p, &$addr_spec)
  544. {
  545. $addr_spec = null;
  546. $v = $this->v;
  547. $l = strlen($v);
  548. $a = $p;
  549. if(!$this->ParseQuotedString($a, $local_part))
  550. return(0);
  551. if(!IsSet($local_part))
  552. {
  553. if(!$this->ParseAtom($a, $local_part, 1))
  554. return(0);
  555. $local_part = trim($local_part);
  556. }
  557. if($a >= $l
  558. || strcmp($v[$a], '@'))
  559. return(1);
  560. ++$a;
  561. if(!$this->ParseAtom($a, $domain, 1))
  562. return(0);
  563. if(!IsSet($domain))
  564. return(1);
  565. $addr_spec = $local_part.'@'.trim($domain);
  566. $p = $a;
  567. return(1);
  568. }
  569. Function ParseAngleAddr(&$p, &$addr)
  570. {
  571. $addr = null;
  572. $v = $this->v;
  573. $l = strlen($v);
  574. $a = $p;
  575. if(!$this->SkipCommentWhiteSpace($a))
  576. return(0);
  577. if($a >= $l
  578. || strcmp($v[$a], '<'))
  579. return(1);
  580. ++$a;
  581. if(!$this->ParseAddrSpec($a, $addr_spec))
  582. return(0);
  583. if($a >= $l
  584. || strcmp($v[$a], '>'))
  585. return(1);
  586. ++$a;
  587. if(!$this->SkipCommentWhiteSpace($a))
  588. return(0);
  589. $addr = $addr_spec;
  590. $p = $a;
  591. return(1);
  592. }
  593. Function ParseName(&$p, &$address)
  594. {
  595. $address = null;
  596. $a = $p;
  597. if(!$this->ParsePhrase($a, $display_name))
  598. return(0);
  599. if(IsSet($display_name))
  600. {
  601. if(!$this->QDecode($p, $display_name, $encoding))
  602. return(0);
  603. $address['name'] = trim($display_name);
  604. if(IsSet($encoding))
  605. $address['encoding'] = $encoding;
  606. }
  607. $p = $a;
  608. return(1);
  609. }
  610. Function ParseNameAddr(&$p, &$address)
  611. {
  612. $address = null;
  613. $a = $p;
  614. if(!$this->ParsePhrase($a, $display_name))
  615. return(0);
  616. if(!$this->ParseAngleAddr($a, $addr))
  617. return(0);
  618. if(!IsSet($addr))
  619. return(1);
  620. $address = array('address'=>$addr);
  621. if(IsSet($display_name))
  622. {
  623. if(!$this->QDecode($p, $display_name, $encoding))
  624. return(0);
  625. $address['name'] = trim($display_name);
  626. if(IsSet($encoding))
  627. $address['encoding'] = $encoding;
  628. }
  629. $p = $a;
  630. return(1);
  631. }
  632. Function ParseAddrNameAddr(&$p, &$address)
  633. {
  634. $address = null;
  635. $a = $p;
  636. if(!$this->ParseAddrSpec($a, $display_name))
  637. return(0);
  638. if(!IsSet($display_name))
  639. return(1);
  640. if(!$this->ParseAngleAddr($a, $addr))
  641. return(0);
  642. if(!IsSet($addr))
  643. return(1);
  644. if(!$this->QDecode($p, $display_name, $encoding))
  645. return(0);
  646. $address = array(
  647. 'address'=>$addr,
  648. 'name' => trim($display_name)
  649. );
  650. if(IsSet($encoding))
  651. $address['encoding'] = $encoding;
  652. $p = $a;
  653. return(1);
  654. }
  655. Function ParseMailbox(&$p, &$address)
  656. {
  657. $address = null;
  658. if($this->ignore_syntax_errors)
  659. {
  660. $a = $p;
  661. if(!$this->ParseAddrNameAddr($p, $address))
  662. return(0);
  663. if(IsSet($address))
  664. return($this->SetPositionedWarning('it was specified an unquoted address as name', $a));
  665. }
  666. if(!$this->ParseNameAddr($p, $address))
  667. return(0);
  668. if(IsSet($address))
  669. return(1);
  670. if(!$this->ParseAddrSpec($p, $addr_spec))
  671. return(0);
  672. if(IsSet($addr_spec))
  673. {
  674. $address = array('address'=>$addr_spec);
  675. return(1);
  676. }
  677. $a = $p;
  678. if($this->ignore_syntax_errors
  679. && $this->ParseName($p, $address)
  680. && IsSet($address))
  681. return($this->SetPositionedWarning('it was specified a name without an address', $a));
  682. return(1);
  683. }
  684. Function ParseMailboxGroup(&$p, &$mailbox_group)
  685. {
  686. $v = $this->v;
  687. $l = strlen($v);
  688. $g = $p;
  689. if(!$this->ParseMailbox($g, $address))
  690. return(0);
  691. if(!IsSet($address))
  692. return(1);
  693. $addresses = array($address);
  694. for(;$g < $l;)
  695. {
  696. if(strcmp($v[$g], ','))
  697. break;
  698. ++$g;
  699. if(!$this->ParseMailbox($g, $address))
  700. return(0);
  701. if(!IsSet($address))
  702. return(1);
  703. $addresses[] = $address;
  704. }
  705. $mailbox_group = $addresses;
  706. $p = $g;
  707. return(1);
  708. }
  709. Function ParseGroup(&$p, &$address)
  710. {
  711. $address = null;
  712. $v = $this->v;
  713. $l = strlen($v);
  714. $g = $p;
  715. if(!$this->ParsePhrase($g, $display_name))
  716. return(0);
  717. if(!IsSet($display_name)
  718. || $g >= $l
  719. || strcmp($v[$g], ':'))
  720. return(1);
  721. ++$g;
  722. if(!$this->ParseMailboxGroup($g, $mailbox_group))
  723. return(0);
  724. if(!IsSet($mailbox_group))
  725. {
  726. if(!$this->SkipCommentWhiteSpace($g))
  727. return(0);
  728. $mailbox_group = array();
  729. }
  730. if($g >= $l
  731. || strcmp($v[$g], ';'))
  732. return(1);
  733. $c = ++$g;
  734. if($this->SkipCommentWhiteSpace($g)
  735. && $g > $c
  736. && !$this->SetPositionedWarning('it were used invalid comments after a group of addresses', $c))
  737. return(0);
  738. if(!$this->QDecode($p, $display_name, $encoding))
  739. return(0);
  740. $address = array(
  741. 'name'=>$display_name,
  742. 'group'=>$mailbox_group
  743. );
  744. if(IsSet($encoding))
  745. $address['encoding'] = $encoding;
  746. $p = $g;
  747. return(1);
  748. }
  749. Function ParseAddress(&$p, &$address)
  750. {
  751. $address = null;
  752. if(!$this->ParseGroup($p, $address))
  753. return(0);
  754. if(!IsSet($address))
  755. {
  756. if(!$this->ParseMailbox($p, $address))
  757. return(0);
  758. }
  759. return(1);
  760. }
  761. /* Public functions */
  762. /*
  763. {metadocument}
  764. <function>
  765. <name>ParseAddressList</name>
  766. <type>BOOLEAN</type>
  767. <documentation>
  768. <purpose>Parse and extract e-mail addresses eventually from headers
  769. of an e-mail message.</purpose>
  770. <usage>Pass a string value with a list of e-mail addresses to the
  771. <argumentlink>
  772. <function>ParseAddressList</function>
  773. <argument>value</argument>
  774. </argumentlink>. The <argumentlink>
  775. <function>ParseAddressList</function>
  776. <argument>addresses</argument>
  777. </argumentlink> returns the list of e-mail addresses found.</usage>
  778. <returnvalue>This function returns <booleanvalue>1</booleanvalue> if
  779. the specified value is parsed successfully. Otherwise,
  780. check the variables <variablelink>error</variablelink> and
  781. <variablelink>error_position</variablelink> to determine what
  782. error occurred and the relevant value position.</returnvalue>
  783. </documentation>
  784. <argument>
  785. <name>value</name>
  786. <type>STRING</type>
  787. <documentation>
  788. <purpose>String with a list of e-mail addresses to parse.</purpose>
  789. </documentation>
  790. </argument>
  791. <argument>
  792. <name>addresses</name>
  793. <type>ARRAY</type>
  794. <out />
  795. <documentation>
  796. <purpose>Return the list of parsed e-mail addresses.
  797. Each entry in the list is an associative array.<paragraphbreak />
  798. For normal addresses, this associative array has the entry
  799. <stringvalue>address</stringvalue> set to the e-mail address.
  800. If the address has an associated name, it is stored in the
  801. entry <stringvalue>name</stringvalue>.<paragraphbreak />
  802. For address groups, there is the entry
  803. <stringvalue>name</stringvalue>.
  804. The group addresses list are stored in the entry
  805. <stringvalue>group</stringvalue> as an array. The structure of
  806. the group addresses list array is the same as this addresses
  807. list array argument.</purpose>
  808. </documentation>
  809. </argument>
  810. <do>
  811. {/metadocument}
  812. */
  813. Function ParseAddressList($value, &$addresses)
  814. {
  815. $this->warnings = array();
  816. $addresses = array();
  817. $this->v = $v = $value;
  818. $l = strlen($v);
  819. $p = 0;
  820. if(!$this->ParseAddress($p, $address))
  821. return(0);
  822. if(!IsSet($address))
  823. return($this->SetPositionedError('it was not specified a valid address', $p));
  824. $addresses[] = $address;
  825. while($p < $l)
  826. {
  827. if(strcmp($v[$p], ',')
  828. && !$this->SetPositionedWarning('multiple addresses must be separated by commas: ', $p))
  829. return(0);
  830. ++$p;
  831. if(!$this->ParseAddress($p, $address))
  832. return(0);
  833. if(!IsSet($address))
  834. return($this->SetPositionedError('it was not specified a valid address after comma', $p));
  835. $addresses[] = $address;
  836. }
  837. return(1);
  838. }
  839. /*
  840. {metadocument}
  841. </do>
  842. </function>
  843. {/metadocument}
  844. */
  845. };
  846. /*
  847. {metadocument}
  848. </class>
  849. {/metadocument}
  850. */
  851. ?>