/**
* Rfc822Header.class.php
*
- * Copyright (c) 2003 The SquirrelMail Project Team
+ * Copyright (c) 2003-2005 The SquirrelMail Project Team
* Licensed under the GNU GPL. For full terms see the file COPYING.
*
* This contains functions needed to handle mime messages.
*
- * $Id$
+ * @version $Id$
+ * @package squirrelmail
*/
-/*
- * rdc822_header class
+/**
* input: header_string or array
+ * @package squirrelmail
*/
class Rfc822Header {
- var $date = '',
+ var $date = -1,
$subject = '',
$from = array(),
$sender = '',
$reply_to = array(),
+ $mail_followup_to = array(),
$to = array(),
$cc = array(),
$bcc = array(),
$priority = 3,
$dnt = '',
$encoding = '',
+ $content_id = '',
+ $content_desc = '',
$mlist = array(),
$more_headers = array(); /* only needed for constructing headers
in smtp.php */
if (is_array($hdr)) {
$hdr = implode('', $hdr);
}
- /* First we unfold the header */
- $hdr = trim(str_replace(array("\r\n\t", "\r\n "),array('', ''), $hdr));
+ /* First we replace \r\n by \n and unfold the header */
+ $hdr = trim(str_replace(array("\r\n", "\n\t", "\n "),array("\n", ' ', ' '), $hdr));
/* Now we can make a new header array with */
/* each element representing a headerline */
- $hdr = explode("\r\n" , $hdr);
+ $hdr = explode("\n" , $hdr);
foreach ($hdr as $line) {
$pos = strpos($line, ':');
if ($pos > 0) {
case 'reply-to':
$this->reply_to = $this->parseAddress($value, true);
break;
+ case 'mail-followup-to':
+ $this->mail_followup_to = $this->parseAddress($value, true);
+ break;
case 'to':
$this->to = $this->parseAddress($value, true);
break;
$value = $this->stripComments($value);
$this->parseDisposition($value);
break;
+ case 'content-transfer-encoding':
+ $this->encoding = $value;
+ break;
+ case 'content-description':
+ $this->content_desc = $value;
+ break;
+ case 'content-id':
+ $value = $this->stripComments($value);
+ $this->content_id = $value;
+ break;
case 'user-agent':
case 'x-mailer':
$this->xmailer = $value;
break;
case 'x-priority':
- $this->priority = $value;
+ case 'importance':
+ case 'priority':
+ $this->priority = $this->parsePriority($value);
break;
case 'list-post':
$value = $this->stripComments($value);
$this->mlist('post', $value);
break;
case 'list-reply':
- $value = $this->stripComments($value);
+ $value = $this->stripComments($value);
$this->mlist('reply', $value);
break;
case 'list-subscribe':
- $value = $this->stripComments($value);
+ $value = $this->stripComments($value);
$this->mlist('subscribe', $value);
break;
case 'list-unsubscribe':
function getAddressTokens($address) {
$aTokens = array();
- $aAddress = array();
$aSpecials = array('(' ,'<' ,',' ,';' ,':');
$aReplace = array(' (',' <',' ,',' ;',' :');
$address = str_replace($aSpecials,$aReplace,$address);
$i = $iEnd;
}
$sToken = str_replace($aReplace, $aSpecials,$sToken);
- $aTokens[] = $sToken;
+ if ($sToken) $aTokens[] = $sToken;
break;
case '"':
$iEnd = strpos($address,$cChar,$i+1);
// check the next token in case comments appear in the middle of email addresses
$prevToken = end($aTokens);
if (!in_array($prevToken,$aSpecials,true)) {
- if (isset($address{$i+1}) && !in_array($address{$i+1},$aSpecials,true)) {
+ if ($i+1<strlen($address) && !in_array($address{$i+1},$aSpecials,true)) {
$iEnd = strpos($address,' ',$i+1);
if ($iEnd) {
$sNextToken = trim(substr($address,$i+1,$iEnd - $i -1));
$i = $iEnd-1;
} else {
- $sToken = trim(substr($address,$i+1));
+ $sNextToken = trim(substr($address,$i+1));
$i = $iCnt;
}
// remove the token
array_pop($aTokens);
// create token and add it again
$sNewToken = $prevToken . $sNextToken;
- $aTokens[] = $sNewToken;
+ if($sNewToken) $aTokens[] = $sNewToken;
}
}
$sToken = str_replace($aReplace, $aSpecials,$sToken);
- $aTokens[] = $sToken;
+ if ($sToken) $aTokens[] = $sToken;
break;
case ',':
case ':':
}
if (count($aStack)) {
$sPersonal = trim(implode('',$aStack));
- } else {
+ } else {
$sPersonal = '';
}
if (!$sPersonal && count($aComment)) {
}
/*
- * parseAddress: recursive function for parsing address strings and store
+ * parseAddress: recursive function for parsing address strings and store
* them in an address stucture object.
* input: $address = string
* $ar = boolean (return array instead of only the
* first element)
* $addr_ar = array with parsed addresses // obsolete
* $group = string // obsolete
- * $host = string (default domainname in case of
+ * $host = string (default domainname in case of
* addresses without a domainname)
* $lookup = callback function (for lookup address
* strings which are probably nicks
- * (without @ ) )
+ * (without @ ) )
* output: array with addressstructure objects or only one
* address_structure object.
* personal name: encoded: =?charset?Q|B?string?=
function parseAddress($address,$ar=false,$aAddress=array(),$sGroup='',$sHost='',$lookup=false) {
$aTokens = $this->getAddressTokens($address);
- $sPersonal = $sEmail = $sComment = $sGroup = '';
+ $sPersonal = $sEmail = $sGroup = '';
$aStack = $aComment = array();
foreach ($aTokens as $sToken) {
$cChar = $sToken{0};
case '=':
case '"':
case ' ':
- $aStack[] = $sToken;
+ $aStack[] = $sToken;
break;
case '(':
$aComment[] = substr($sToken,1,-1);
$oAddr = end($aAddress);
if(!$oAddr || ((isset($oAddr)) && !$oAddr->mailbox && !$oAddr->personal)) {
$sEmail = $sGroup . ':;';
- }
+ }
$aAddress[] = $this->createAddressObject($aStack,$aComment,$sEmail,$sGroup);
$sGroup = '';
$aStack = $aComment = array();
case ',':
$aAddress[] = $this->createAddressObject($aStack,$aComment,$sEmail,$sGroup);
break;
- case ':':
+ case ':':
$sGroup = trim(implode(' ',$aStack));
$sGroup = preg_replace('/\s+/',' ',$sGroup);
$aStack = array();
break;
case '>':
/* skip */
- break;
+ break;
default: $aStack[] = $sToken; break;
}
}
if ($sHost && $oAddr->mailbox) {
$oAddr->host = $sHost;
}
+ } else if (!$grouplookup && !$oAddr->host) {
+ if ($sHost && $oAddr->mailbox) {
+ $oAddr->host = $sHost;
+ }
}
}
if (!$aAddrBookAddress && $oAddr->mailbox) {
$aProcessedAddress[] = $oAddr;
} else {
- $aProcessedAddress = array_merge($aProcessedAddress,$aAddrBookAddress);
+ $aProcessedAddress = array_merge($aProcessedAddress,$aAddrBookAddress);
}
}
- if ($ar) {
+ if ($ar) {
return $aProcessedAddress;
} else {
return $aProcessedAddress[0];
}
- }
+ }
+
+ /**
+ * Normalise the different Priority headers into a uniform value,
+ * namely that of the X-Priority header (1, 3, 5). Supports:
+ * Prioirty, X-Priority, Importance.
+ * X-MS-Mail-Priority is not parsed because it always coincides
+ * with one of the other headers.
+ *
+ * NOTE: this is actually a duplicate from the function in
+ * functions/imap_messages. I'm not sure if it's ok here to call
+ * that function?
+ */
+ function parsePriority($value) {
+ $value = strtolower(array_shift(split('/\w/',trim($value))));
+ if ( is_numeric($value) ) {
+ return $value;
+ }
+ if ( $value == 'urgent' || $value == 'high' ) {
+ return 1;
+ } elseif ( $value == 'non-urgent' || $value == 'low' ) {
+ return 5;
+ }
+ // default is normal priority
+ return 3;
+ }
function parseContentType($value) {
$pos = strpos($value, ';');
}
$this->content_type = $content_type;
}
-
+
/* RFC2184 */
- function processParameters($aParameters) {
+ function processParameters($aParameters) {
$aResults = array();
- $aCharset = array();
- // handle multiline parameters
+ $aCharset = array();
+ // handle multiline parameters
foreach($aParameters as $key => $value) {
- if ($iPos = strpos($key,'*')) {
- $sKey = substr($key,0,$iPos);
- if (!isset($aResults[$sKey])) {
- $aResults[$sKey] = $value;
- if (substr($key,-1) == '*') { // parameter contains language/charset info
- $aCharset[] = $sKey;
- }
- } else {
- $aResults[$sKey] .= $value;
- }
- }
+ if ($iPos = strpos($key,'*')) {
+ $sKey = substr($key,0,$iPos);
+ if (!isset($aResults[$sKey])) {
+ $aResults[$sKey] = $value;
+ if (substr($key,-1) == '*') { // parameter contains language/charset info
+ $aCharset[] = $sKey;
+ }
+ } else {
+ $aResults[$sKey] .= $value;
+ }
+ } else {
+ $aResults[$key] = $value;
+ }
+ }
+ foreach ($aCharset as $key) {
+ $value = $aResults[$key];
+ // extract the charset & language
+ $charset = substr($value,0,strpos($value,"'"));
+ $value = substr($value,strlen($charset)+1);
+ $language = substr($value,0,strpos($value,"'"));
+ $value = substr($value,strlen($charset)+1);
+ // FIX ME What's the status of charset decode with language information ????
+ $value = charset_decode($charset,$value);
+ $aResults[$key] = $value;
}
- foreach ($aCharset as $key) {
- $value = $aResults[$key];
- // extract the charset & language
- $charset = substr($value,0,strpos($value,"'"));
- $value = substr($value,strlen($charset)+1);
- $language = substr($value,0,strpos($value,"'"));
- $value = substr($value,strlen($charset)+1);
- // FIX ME What's the status of charset decode with language information ????
- $value = charset_decode($charset,$value);
- $aResults[$key] = $value;
- }
- return $aResults;
+ return $aResults;
}
function parseProperties($value) {
if ($pos > 0) {
$key = trim(substr($prop, 0, $pos));
$val = trim(substr($prop, $pos+1));
- if ($val{0} == '"') {
+ if (strlen($val) > 0 && $val{0} == '"') {
$val = substr($val, 1, -1);
}
$propResultArray[$key] = $val;
if (is_array($arr)) {
foreach($arr as $arg) {
if ($this->getAddr_s($arg, $separator, $encoded)) {
- $s .= $separator . $result;
+ $s .= $separator;
}
}
$s = ($s ? substr($s, 2) : $s);
}
return $arr;
}
-
+
function findAddress($address, $recurs = false) {
$result = false;
if (is_array($address)) {
$i=0;
foreach($address as $argument) {
$match = $this->findAddress($argument, true);
- $last = end($match);
if ($match[1]) {
return $i;
} else {
$result = $i;
}
}
- ++$i;
+ ++$i;
}
} else {
if (!is_array($this->cc)) $this->cc = array();
return true;
} else {
return false;
- }
+ }
}
//exit;
return $result;
}
}
-?>
+?>
\ No newline at end of file