PHP Classes

File: example/lib/rfc822_addresses.php

Recommend this page to a friend!
  Classes of Vivek Muthal   Viv OAuth IMAP   example/lib/rfc822_addresses.php   Download  
File: example/lib/rfc822_addresses.php
Role: Example script
Content type: text/plain
Description: Example script
Class: Viv OAuth IMAP
Access messages in IMAP server using OAuth token
Author: By
Last change: Update of example/lib/rfc822_addresses.php
Date: 6 days ago
Size: 21,080 bytes
 

Contents

Class file image Download
<?php /* * rfc822_addresses.php * * @(#) $Id: rfc822_addresses.php,v 1.15 2011/10/29 09:11:50 mlemos Exp $ * */ /* {metadocument}<?xml version="1.0" encoding="ISO-8859-1" ?> <class> <package>net.manuellemos.mimeparser</package> <version>@(#) $Id: rfc822_addresses.php,v 1.15 2011/10/29 09:11:50 mlemos Exp $</version> <copyright>Copyright (C) Manuel Lemos 2006 - 2008</copyright> <title>RFC 822 e-mail addresses parser</title> <author>Manuel Lemos</author> <authoraddress>mlemos-at-acm.org</authoraddress> <documentation> <idiom>en</idiom> <purpose>Parse e-mail addresses from headers of <link> <url>http://www.ietf.org/rfc/rfc822.txt</url> <data>RFC 822</data> </link> compliant e-mail messages.</purpose> <usage>Use the function <functionlink>ParseAddressList</functionlink> function to retrieve the list of e-mail addresses contained in e-mail message headers like <tt>From</tt>, <tt>To</tt>, <tt>Cc</tt> or <tt>Bcc</tt>.</usage> </documentation> {/metadocument} */ class rfc822_addresses_class { /* Private variables */ var $v = ''; /* Public variables */ /* {metadocument} <variable> <name>error</name> <type>STRING</type> <value></value> <documentation> <purpose>Store the message that is returned when an error occurs.</purpose> <usage>Check this variable to understand what happened when a call to any of the class functions has failed.<paragraphbreak /> This class uses cumulative error handling. This means that if one class functions that may fail is called and this variable was already set to an error message due to a failure in a previous call to the same or other function, the function will also fail and does not do anything.<paragraphbreak /> This allows programs using this class to safely call several functions that may fail and only check the failure condition after the last function call.<paragraphbreak /> Just set this variable to an empty string to clear the error condition.</usage> </documentation> </variable> {/metadocument} */ var $error = ''; /* {metadocument} <variable> <name>error_position</name> <type>INTEGER</type> <value>-1</value> <documentation> <purpose>Point to the position of the message data or file that refers to the last error that occurred.</purpose> <usage>Check this variable to determine the relevant position of the message when a parsing error occurs.</usage> </documentation> </variable> {/metadocument} */ var $error_position = -1; /* {metadocument} <variable> <name>ignore_syntax_errors</name> <type>BOOLEAN</type> <value>1</value> <documentation> <purpose>Specify whether the class should ignore syntax errors in malformed addresses.</purpose> <usage>Set this variable to <booleanvalue>0</booleanvalue> if it is necessary to verify whether message data may be corrupted due to to eventual bugs in the program that generated the message.<paragraphbreak /> Currently the class only ignores some types of syntax errors. Other syntax errors may still cause the <functionlink>ParseAddressList</functionlink> to fail.</usage> </documentation> </variable> {/metadocument} */ var $ignore_syntax_errors=1; /* {metadocument} <variable> <name>warnings</name> <type>HASH</type> <value></value> <documentation> <purpose>Return a list of positions of the original message that contain syntax errors.</purpose> <usage>Check this variable to retrieve eventual message syntax errors that were ignored when the <variablelink>ignore_syntax_errors</variablelink> is set to <booleanvalue>1</booleanvalue>.<paragraphbreak /> The indexes of this array are the positions of the errors. The array values are the corresponding syntax error messages.</usage> </documentation> </variable> {/metadocument} */ var $warnings=array(); /* Private functions */ Function SetError($error) { $this->error = $error; return(0); } Function SetPositionedError($error, $position) { $this->error_position = $position; return($this->SetError($error)); } Function SetWarning($warning, $position) { $this->warnings[$position]=$warning; return(1); } Function SetPositionedWarning($error, $position) { if(!$this->ignore_syntax_errors) return($this->SetPositionedError($error, $position)); return($this->SetWarning($error, $position)); } Function QDecode($p, &$value, &$encoding) { $encoding = $charset = null; $s = 0; $decoded = ''; $l = strlen($value); while($s < $l) { if(GetType($q = strpos($value, '=?', $s)) != 'integer') { if($s == 0) return(1); if($s < $l) $decoded .= substr($value, $s); break; } if($s < $q) $decoded .= substr($value, $s, $q - $s); $q += 2; if(GetType($c = strpos($value, '?', $q)) != 'integer' || $q == $c) return($this->SetPositionedWarning('invalid Q-encoding character set', $p + $q)); if(IsSet($charset)) { $another_charset = strtolower(substr($value, $q, $c - $q)); if(strcmp($charset, $another_charset) && strcmp($another_charset, 'ascii')) return($this->SetWarning('it is not possible to decode an encoded value using mixed character sets into a single value', $p + $q)); } else { $charset = strtolower(substr($value, $q, $c - $q)); if(!strcmp($charset, 'ascii')) $charset = null; } ++$c; if(GetType($t = strpos($value, '?', $c)) != 'integer' || $c==$t) return($this->SetPositionedWarning('invalid Q-encoding type', $p + $c)); $type = strtolower(substr($value, $c, $t - $c)); ++$t; if(GetType($e = strpos($value, '?=', $t)) != 'integer') return($this->SetPositionedWarning('invalid Q-encoding encoded data', $p + $e)); switch($type) { case 'q': for($s = $t; $s<$e;) { switch($b = $value[$s]) { case '=': $h = HexDec($hex = strtolower(substr($value, $s + 1, 2))); if($s + 3 > $e || strcmp(sprintf('%02x', $h), $hex)) return($this->SetPositionedWarning('invalid Q-encoding q encoded data', $p + $s)); $decoded .= chr($h); $s += 3; break; case '_': $decoded .= ' '; ++$s; break; default: $decoded .= $b; ++$s; } } break; case 'b': if($e <= $t || strlen($binary = base64_decode($data = substr($value, $t, $e - $t))) == 0 || GetType($binary) != 'string') return($this->SetPositionedWarning('invalid Q-encoding b encoded data', $p + $t)); $decoded .= $binary; $s = $e; break; default: return($this->SetPositionedWarning('Q-encoding '.$type.' is not yet supported', $p + $c)); } $s += 2; $s += strspn($value, " \t", $s); } $value = $decoded; $encoding = $charset; return(1); } Function ParseCText(&$p, &$c_text) { $c_text = null; $v = $this->v; if($p<strlen($v) && GetType(strchr("\t\r\n ()\\\0", $c = $v[$p])) != 'string' && Ord($c)<128) { $c_text = $c; ++$p; } return(1); } Function ParseQText(&$p, &$q_text) { $q_text = null; $v = $this->v; if($p>strlen($v) || GetType(strchr("\t\r\n \"\\\0", $c = $v[$p])) == 'string') return(1); if(Ord($c) >= 128) { if(!$this->ignore_syntax_errors) return(1); $this->SetPositionedWarning('it was used an unencoded 8 bit character', $p); } $q_text = $c; ++$p; return(1); } Function ParseQuotedPair(&$p, &$quoted_pair) { $quoted_pair = null; $v = $this->v; $l = strlen($v); if($p+1 < $l && !strcmp($v[$p], '\\') && GetType(strchr("\r\n\0", $c = $v[$p + 1])) != 'string' && Ord($c)<128) { $quoted_pair = $c; $p += 2; } return(1); } Function ParseCContent(&$p, &$c_content) { $c_content = null; $c = $p; if(!$this->ParseQuotedPair($c, $content)) return(0); if(!IsSet($content)) { if(!$this->ParseCText($c, $content)) return(0); if(!IsSet($content)) { if(!$this->ParseComment($c, $content)) return(0); if(!IsSet($content)) return(1); } } $c_content = $content; $p = $c; return(1); } Function SkipWhiteSpace(&$p) { $v = $this->v; $l = strlen($v); for(;$p<$l; ++$p) { switch($v[$p]) { case ' ': case "\n": case "\r": case "\t": break; default: return(1); } } return(1); } Function ParseComment(&$p, &$comment) { $comment = null; $v = $this->v; $l = strlen($v); $c = $p; if($c >= $l || strcmp($v[$c], '(')) return(1); ++$c; for(; $c < $l;) { if(!$this->SkipWhiteSpace($c)) return(0); if(!$this->ParseCContent($c, $c_content)) return(0); if(!IsSet($c_content)) break; } if(!$this->SkipWhiteSpace($c)) return(0); if($c >= $l || strcmp($v[$c], ')')) return(1); ++$c; $comment = substr($v, $p, $c - $p); $p = $c; return(1); } Function SkipCommentGetWhiteSpace(&$p, &$space) { $v = $this->v; $l = strlen($v); for($space = '';$p<$l;) { switch($w = $v[$p]) { case ' ': case "\n": case "\r": case "\t": ++$p; $space .= $w; break; case '(': if(!$this->ParseComment($p, $comment)) return(0); default: return(1); } } return(1); } Function SkipCommentWhiteSpace(&$p) { $v = $this->v; $l = strlen($v); for(;$p<$l;) { switch($w = $v[$p]) { case ' ': case "\n": case "\r": case "\t": ++$p; break; case '(': if(!$this->ParseComment($p, $comment)) return(0); default: return(1); } } return(1); } Function ParseQContent(&$p, &$q_content) { $q_content = null; $q = $p; if(!$this->ParseQuotedPair($q, $content)) return(0); if(!IsSet($content)) { if(!$this->ParseQText($q, $content)) return(0); if(!IsSet($content)) return(1); } $q_content = $content; $p = $q; return(1); } Function ParseAtom(&$p, &$atom, $dot) { $atom = null; $v = $this->v; $l = strlen($v); $a = $p; if(!$this->SkipCommentGetWhiteSpace($a, $space)) return(0); $match = '/^([-'.($dot ? '.' : '').'A-Za-z0-9!#$&\'*+\\/=?^_{|}~]+)/'; for($s = $a;$a < $l;) { if(preg_match($match, substr($this->v, $a), $m)) $a += strlen($m[1]); elseif(Ord($v[$a]) < 128) break; elseif(!$this->SetPositionedWarning('it was used an unencoded 8 bit character', $a)) return(0); else ++$a; } if($s == $a) return(1); $atom = $space.substr($this->v, $s, $a - $s); if(!$this->SkipCommentGetWhiteSpace($a, $space)) return(0); $atom .= $space; $p = $a; return(1); } Function ParseQuotedString(&$p, &$quoted_string) { $quoted_string = null; $v = $this->v; $l = strlen($v); $s = $p; if(!$this->SkipCommentWhiteSpace($s)) return(0); if($s >= $l || strcmp($v[$s], '"')) return(1); ++$s; for($string = '';$s < $l;) { $w = $s; if(!$this->SkipWhiteSpace($s)) return(0); if($w != $s) $string .= substr($v, $w, $s - $w); if(!$this->ParseQContent($s, $q_content)) return(0); if(!IsSet($q_content)) break; $string .= $q_content; } $w = $s; if(!$this->SkipWhiteSpace($s)) return(0); if($w != $s) $string .= substr($v, $w, $s - $w); if($s >= $l || strcmp($v[$s], '"')) return(1); ++$s; if(!$this->SkipCommentWhiteSpace($s)) return(0); $quoted_string = $string; $p = $s; return(1); } Function ParseWord(&$p, &$word, &$escape) { $word = null; if(!$this->ParseQuotedString($p, $word)) return(0); if(IsSet($word)) return(1); for($w = '';;) { $last = $w; if(!$this->ParseAtom($p, $atom, 0)) return(0); if(IsSet($atom)) $w .= $atom; if($this->ignore_syntax_errors) { $e = $p; if(!$this->ParseQuotedPair($p, $quoted_pair)) return(0); if(IsSet($quoted_pair)) { $w .= $quoted_pair; if(!IsSet($escape)) $escape = $e; } } if($last === $w) break; } if(strlen($w)) $word = $w; return(1); } Function ParseObsPhrase(&$p, &$obs_phrase, &$escape) { $obs_phrase = null; $v = $this->v; $l = strlen($v); $ph = $p; if(!$this->ParseWord($ph, $word, $escape)) return(0); $string = $word; for(;;) { if(!$this->ParseWord($ph, $word, $escape)) return(0); if(IsSet($word)) { $string .= $word; continue; } $w = $ph; if(!$this->SkipCommentGetWhiteSpace($ph, $space)) return(0); if($w != $ph) { $string .= $space; continue; } if($ph >= $l || strcmp($v[$ph], '.')) break; $string .= '.'; ++$ph; } $obs_phrase = $string; $p = $ph; return(1); } Function ParsePhrase(&$p, &$phrase, &$escape) { $phrase = null; if(!$this->ParseObsPhrase($p, $phrase, $escape)) return(0); if(IsSet($phrase)) return(1); $ph = $p; if(!$this->ParseWord($ph, $word, $escape)) return(0); $string = $word; for(;;) { if(!$this->ParseWord($ph, $word, $escape)) return(0); if(!IsSet($word)) break; $string .= $word; } $phrase = $string; $p = $ph; return(1); } Function ParseAddrSpec(&$p, &$addr_spec) { $addr_spec = null; $v = $this->v; $l = strlen($v); $a = $p; if(!$this->ParseQuotedString($a, $local_part)) return(0); if(!IsSet($local_part)) { if(!$this->ParseAtom($a, $local_part, 1)) return(0); $local_part = trim($local_part); } if($a >= $l || strcmp($v[$a], '@')) return(1); ++$a; if(!$this->ParseAtom($a, $domain, 1)) return(0); if(!IsSet($domain)) return(1); $addr_spec = $local_part.'@'.trim($domain); $p = $a; return(1); } Function ParseAngleAddr(&$p, &$addr) { $addr = null; $v = $this->v; $l = strlen($v); $a = $p; if(!$this->SkipCommentWhiteSpace($a)) return(0); if($a >= $l || strcmp($v[$a], '<')) return(1); ++$a; if(!$this->ParseAddrSpec($a, $addr_spec)) return(0); if($a >= $l || strcmp($v[$a], '>')) return(1); ++$a; if(!$this->SkipCommentWhiteSpace($a)) return(0); $addr = $addr_spec; $p = $a; return(1); } Function ParseName(&$p, &$address) { $address = $escape = null; $a = $p; if(!$this->ParsePhrase($a, $display_name, $escape)) return(0); if(IsSet($display_name)) { if(IsSet($escape) && !$this->SetPositionedWarning('it was used an escape character outside a quoted value', $escape)) return(0); if(!$this->QDecode($p, $display_name, $encoding)) return(0); $address['name'] = trim($display_name); if(IsSet($encoding)) $address['encoding'] = $encoding; } $p = $a; return(1); } Function ParseNameAddr(&$p, &$address) { $address = $escape = null; $a = $p; if(!$this->ParsePhrase($a, $display_name, $escape)) return(0); if(!$this->ParseAngleAddr($a, $addr)) return(0); if(!IsSet($addr)) return(1); $address = array('address'=>$addr); if(IsSet($display_name)) { if(IsSet($escape) && !$this->SetPositionedWarning('it was used an escape character outside a quoted value', $escape)) return(0); if(!$this->QDecode($p, $display_name, $encoding)) return(0); $address['name'] = trim($display_name); if(IsSet($encoding)) $address['encoding'] = $encoding; } $p = $a; return(1); } Function ParseAddrNameAddr(&$p, &$address) { $address = null; $a = $p; if(!$this->ParseAddrSpec($a, $display_name)) return(0); if(!IsSet($display_name)) return(1); if(!$this->ParseAngleAddr($a, $addr)) return(0); if(!IsSet($addr)) return(1); if(!$this->QDecode($p, $display_name, $encoding)) return(0); $address = array( 'address'=>$addr, 'name' => trim($display_name) ); if(IsSet($encoding)) $address['encoding'] = $encoding; $p = $a; return(1); } Function ParseMailbox(&$p, &$address) { $address = null; if($this->ignore_syntax_errors) { $a = $p; if(!$this->ParseAddrNameAddr($p, $address)) return(0); if(IsSet($address)) return($this->SetPositionedWarning('it was specified an unquoted address as name', $a)); } if(!$this->ParseNameAddr($p, $address)) return(0); if(IsSet($address)) return(1); if(!$this->ParseAddrSpec($p, $addr_spec)) return(0); if(IsSet($addr_spec)) { $address = array('address'=>$addr_spec); return(1); } $a = $p; if($this->ignore_syntax_errors && $this->ParseName($p, $address) && IsSet($address)) return($this->SetPositionedWarning('it was specified a name without an address', $a)); return(1); } Function ParseMailboxGroup(&$p, &$mailbox_group) { $v = $this->v; $l = strlen($v); $g = $p; if(!$this->ParseMailbox($g, $address)) return(0); if(!IsSet($address)) return(1); $addresses = array($address); for(;$g < $l;) { if(strcmp($v[$g], ',')) break; ++$g; if(!$this->ParseMailbox($g, $address)) return(0); if(!IsSet($address)) return(1); $addresses[] = $address; } $mailbox_group = $addresses; $p = $g; return(1); } Function ParseGroup(&$p, &$address) { $address = $escape = null; $v = $this->v; $l = strlen($v); $g = $p; if(!$this->ParsePhrase($g, $display_name, $escape)) return(0); if(!IsSet($display_name) || $g >= $l || strcmp($v[$g], ':')) return(1); ++$g; if(!$this->ParseMailboxGroup($g, $mailbox_group)) return(0); if(!IsSet($mailbox_group)) { if(!$this->SkipCommentWhiteSpace($g)) return(0); $mailbox_group = array(); } if($g >= $l || strcmp($v[$g], ';')) return(1); $c = ++$g; if($this->SkipCommentWhiteSpace($g) && $g > $c && !$this->SetPositionedWarning('it were used invalid comments after a group of addresses', $c)) return(0); if(IsSet($escape) && !$this->SetPositionedWarning('it was used an escape character outside a quoted value', $escape)) return(0); if(!$this->QDecode($p, $display_name, $encoding)) return(0); $address = array( 'name'=>$display_name, 'group'=>$mailbox_group ); if(IsSet($encoding)) $address['encoding'] = $encoding; $p = $g; return(1); } Function ParseAddress(&$p, &$address) { $address = null; if(!$this->ParseGroup($p, $address)) return(0); if(!IsSet($address)) { if(!$this->ParseMailbox($p, $address)) return(0); } return(1); } /* Public functions */ /* {metadocument} <function> <name>ParseAddressList</name> <type>BOOLEAN</type> <documentation> <purpose>Parse and extract e-mail addresses eventually from headers of an e-mail message.</purpose> <usage>Pass a string value with a list of e-mail addresses to the <argumentlink> <function>ParseAddressList</function> <argument>value</argument> </argumentlink>. The <argumentlink> <function>ParseAddressList</function> <argument>addresses</argument> </argumentlink> returns the list of e-mail addresses found.</usage> <returnvalue>This function returns <booleanvalue>1</booleanvalue> if the specified value is parsed successfully. Otherwise, check the variables <variablelink>error</variablelink> and <variablelink>error_position</variablelink> to determine what error occurred and the relevant value position.</returnvalue> </documentation> <argument> <name>value</name> <type>STRING</type> <documentation> <purpose>String with a list of e-mail addresses to parse.</purpose> </documentation> </argument> <argument> <name>addresses</name> <type>ARRAY</type> <out /> <documentation> <purpose>Return the list of parsed e-mail addresses. Each entry in the list is an associative array.<paragraphbreak /> For normal addresses, this associative array has the entry <stringvalue>address</stringvalue> set to the e-mail address. If the address has an associated name, it is stored in the entry <stringvalue>name</stringvalue>.<paragraphbreak /> For address groups, there is the entry <stringvalue>name</stringvalue>. The group addresses list are stored in the entry <stringvalue>group</stringvalue> as an array. The structure of the group addresses list array is the same as this addresses list array argument.</purpose> </documentation> </argument> <do> {/metadocument} */ Function ParseAddressList($value, &$addresses) { $this->warnings = array(); $addresses = array(); $this->v = $v = $value; $l = strlen($v); $p = 0; if(!$this->ParseAddress($p, $address)) return(0); if(!IsSet($address)) return($this->SetPositionedError('it was not specified a valid address', $p)); $addresses[] = $address; while($p < $l) { if(strcmp($v[$p], ',') && !$this->SetPositionedWarning('multiple addresses must be separated by commas: ', $p)) return(0); ++$p; if(!$this->ParseAddress($p, $address)) return(0); if(!IsSet($address)) return($this->SetPositionedError('it was not specified a valid address after comma', $p)); $addresses[] = $address; } return(1); } /* {metadocument} </do> </function> {/metadocument} */ }; /* {metadocument} </class> {/metadocument} */ ?>