backport of the trunk egw-pear/Net/ IMAP classes, since they provide some more stability regarding the parsing of messages

This commit is contained in:
Klaus Leithoff 2008-10-07 10:00:07 +00:00
parent 64a409adae
commit d57d1fb157
2 changed files with 79 additions and 25 deletions

View File

@ -381,19 +381,44 @@ class Net_IMAP extends Net_IMAPProtocol {
$message_set="1:*";
}
if($uidFetch) {
$ret=$this->cmdUidFetch($message_set,"(RFC822.SIZE UID FLAGS ENVELOPE INTERNALDATE BODY.PEEK[HEADER.FIELDS (CONTENT-TYPE)])");
#error_log("egw-pear::NET::IMAP:getSummary->fetch by UID ".$message_set);
$ret=$this->cmdUidFetch($message_set,"(RFC822.SIZE UID FLAGS ENVELOPE INTERNALDATE BODY.PEEK[HEADER.FIELDS (CONTENT-TYPE X-PRIORITY)])");
} else {
$ret=$this->cmdFetch($message_set,"(RFC822.SIZE UID FLAGS ENVELOPE INTERNALDATE BODY.PEEK[HEADER.FIELDS (CONTENT-TYPE)])");
#error_log("egw-pear::NET::IMAP:getSummary->fetch message ".$message_set);
$ret=$this->cmdFetch($message_set,"(RFC822.SIZE UID FLAGS ENVELOPE INTERNALDATE BODY.PEEK[HEADER.FIELDS (CONTENT-TYPE X-PRIORITY)])");
}
#error_log(print_r($ret['PARSED'][0],true));
#$ret=$this->cmdFetch($message_set,"(RFC822.SIZE UID FLAGS ENVELOPE INTERNALDATE BODY[1.MIME])");
if (PEAR::isError($ret)) {
return $ret;
}
if(strtoupper($ret["RESPONSE"]["CODE"]) != "OK"){
return new PEAR_Error($ret["RESPONSE"]["CODE"] . ", " . $ret["RESPONSE"]["STR_CODE"]);
if (PEAR::isError($ret) || strtoupper($ret["RESPONSE"]["CODE"]) != "OK") {
error_log("egw-pear::NET::IMAP:getSummary->error after Fetch for message(s):".$message_set." Trying to retrieve single messages.");
unset($ret);
# if there is an error, while retrieving the information for the whole list, try to retrieve the info one by one, to be more error tolerant
foreach (explode(',',$message_set) as $msgid) {
$retloop=$this->cmdUidFetch($msgid,"(RFC822.SIZE UID FLAGS ENVELOPE INTERNALDATE BODY.PEEK[HEADER.FIELDS (CONTENT-TYPE X-PRIORITY)])");
if (PEAR::isError($retloop)|| strtoupper($retloop["RESPONSE"]["CODE"]) != "OK") {
# log the error, and create a dummy-message as placeholder, this may hold the possibility to read the message anyway
error_log("egw-pear::NET::IMAP:getSummary->error after Fetch for message with id:".$msgid);
error_log($ret["RESPONSE"]["CODE"] . ", " . $ret["RESPONSE"]["STR_CODE"]);
$ret['PARSED'][]=array('COMMAND'=>"FETCH",'EXT'=>array('UID'=>$msgid,'ENVELOPE'=>array('SUBJECT'=>"[FELAMIMAIL:ERROR]can not parse this message(header).",)));
} else {
#error_log(print_r($retloop['PARSED'][0],true));
# renew the response for every message retrieved, since the returnvalue is structured that way
$ret['RESPONSE']=$retloop['RESPONSE'];
$ret['PARSED'][]=$retloop['PARSED'][0];
}
unset($retloop);
}
#return $ret;
}
# this seems to be obsolet, since errors while retrieving header informations are 'covered' above
#if(strtoupper($ret["RESPONSE"]["CODE"]) != "OK"){
# error_log("egw-pear::NET::IMAP:getSummary->ResponseCode not OK");
# return new PEAR_Error($ret["RESPONSE"]["CODE"] . ", " . $ret["RESPONSE"]["STR_CODE"]);
#}
#print "<hr>"; var_dump($ret["PARSED"]); print "<hr>";
#print "<hr>";
#error_log("egw-pear::NET::IMAP:getSummary->".print_r($ret["PARSED"],TRUE));
#print "<hr>";
if(isset( $ret["PARSED"] ) ){
for($i=0; $i<count($ret["PARSED"]) ; $i++){
@ -403,14 +428,22 @@ class Net_IMAP extends Net_IMAPProtocol {
$a['FLAGS']=$ret["PARSED"][$i]['EXT']['FLAGS'];
$a['INTERNALDATE']=$ret["PARSED"][$i]['EXT']['INTERNALDATE'];
$a['SIZE']=$ret["PARSED"][$i]['EXT']['RFC822.SIZE'];
if(isset($ret["PARSED"][$i]['EXT']['BODY[HEADER.FIELDS (CONTENT-TYPE)]']['CONTENT'])) {
if(preg_match('/^content-type: (.*);/iU', $ret["PARSED"][$i]['EXT']['BODY[HEADER.FIELDS (CONTENT-TYPE)]']['CONTENT'], $matches)) {
if(isset($ret["PARSED"][$i]['EXT']['BODY[HEADER.FIELDS (CONTENT-TYPE X-PRIORITY)]']['CONTENT'])) {
if(preg_match('/content-type: (.*);/iU', $ret["PARSED"][$i]['EXT']['BODY[HEADER.FIELDS (CONTENT-TYPE X-PRIORITY)]']['CONTENT'], $matches)) {
$a['MIMETYPE']=strtolower($matches[1]);
}
} elseif (isset($ret["PARSED"][$i]['EXT']['BODY[HEADER.FIELDS ("CONTENT-TYPE")]']['CONTENT'])) {
// fetch the priority [CONTENT] => X-Priority: 5\r\nContent-Type: multipart/alternative;\r\n\tboundary="b1_61838a67749ca51b425e42489adced98"\r\n\r\n\n
if(preg_match('/x-priority: ([0-9])/iU', $ret["PARSED"][$i]['EXT']['BODY[HEADER.FIELDS (CONTENT-TYPE X-PRIORITY)]']['CONTENT'], $matches)) {
$a['PRIORITY']=strtolower($matches[1]);
}
} elseif (isset($ret["PARSED"][$i]['EXT']['BODY[HEADER.FIELDS ("CONTENT-TYPE" "X-PRIORITY")]']['CONTENT'])) {
// some versions of cyrus send "CONTENT-TYPE" and CONTENT-TYPE only
if (preg_match('/^content-type: (.*);/iU', $ret["PARSED"][$i]['EXT']['BODY[HEADER.FIELDS ("CONTENT-TYPE")]']['CONTENT'], $matches)) {
if (preg_match('/content-type: (.*);/iU', $ret["PARSED"][$i]['EXT']['BODY[HEADER.FIELDS ("CONTENT-TYPE" "X-PRIORITY")]']['CONTENT'], $matches)) {
$a['MIMETYPE']=strtolower($matches[1]);
}
// fetch the priority [CONTENT] => X-Priority: 5\r\nContent-Type: multipart/alternative;\r\n\tboundary="b1_61838a67749ca51b425e42489adced98"\r\n\r\n\n
if (preg_match('/x-priority: ([0-9])/iU', $ret["PARSED"][$i]['EXT']['BODY[HEADER.FIELDS ("CONTENT-TYPE" "X-PRIORITY")]']['CONTENT'], $matches)) {
$a['PRIORITY']=strtolower($matches[1]);
}
}
$env[]=$a;
@ -1218,7 +1251,7 @@ class Net_IMAP extends Net_IMAPProtocol {
* @param string $mailbox mailbox name to append to (default is current mailbox)
* @param string $flags_list set flags appended message
*
* @return mixed true on success / Pear_Error on failure
* @return mixed true (or the uid of the created message) on success / Pear_Error on failure
*
* @access public
* @since 1.0
@ -1232,9 +1265,16 @@ class Net_IMAP extends Net_IMAPProtocol {
if (PEAR::isError($ret)) {
return $ret;
}
if(strtoupper($ret["RESPONSE"]["CODE"]) != "OK"){
return new PEAR_Error($ret["RESPONSE"]["CODE"] . ", " . $ret["RESPONSE"]["STR_CODE"]);
}
// the expected response is something like that: [APPENDUID 1160024220 12] Completed
// the uid of the created message is the number just before the closing bracket
$retcode = explode(' ',$ret["RESPONSE"]["STR_CODE"]);
$retcode = explode(']',$retcode[2]);
if (intval($retcode[0]) > 0) return $retcode[0];
// this should never happen, exept the parsed response is not as expected
return true;
}
@ -1636,7 +1676,7 @@ class Net_IMAP extends Net_IMAPProtocol {
* @access public
* @since 1.0
*/
function getFlags( $msg_id = null )
function getFlags( $msg_id = null , $uidStore = false)
{
// You can also provide an array of numbers to those emails
if( $msg_id != null){
@ -1648,9 +1688,13 @@ class Net_IMAP extends Net_IMAPProtocol {
}else{
$message_set="1:*";
}
if ($uidStore == true ) {
$ret = $this->cmdUidFetch($message_set, 'FLAGS');
} else {
$ret = $this->cmdFetch($message_set, 'FLAGS');
}
if (PEAR::isError($ret = $this->cmdFetch($message_set, 'FLAGS'))) {
if (PEAR::isError($ret)) {
return $ret;
}
if(strtoupper($ret["RESPONSE"]["CODE"]) != "OK"){
@ -1686,6 +1730,7 @@ class Net_IMAP extends Net_IMAPProtocol {
*/
function setFlags($msg_id, $flags, $mod = 'set', $uidStore = false)
{
#error_log("egw-pear::Net::setFlags");
// you can also provide an array of numbers to those emails
if ($msg_id == 'all') {
$message_set = '1:*';
@ -1719,7 +1764,7 @@ class Net_IMAP extends Net_IMAPProtocol {
return new PEAR_Error('wrong input $mod');
break;
}
#error_log("egw-pear::Net::setFlags for Message: ".print_r($message_set,true)."->".$flaglist);
if($uidStore == true) {
$ret=$this->cmdUidStore($message_set, $dataitem, $flaglist);
} else {

View File

@ -538,7 +538,7 @@ class Net_IMAPProtocol {
*/
function _authDigest_MD5($uid , $pwd , $cmdid)
{
class_exists('Auth_SASL') || require_once 'Auth/SASL.php';
if ( PEAR::isError($error = $this->_putCMD( $cmdid ,"AUTHENTICATE" , "DIGEST-MD5") ) ) {
return $error;
}
@ -596,7 +596,7 @@ class Net_IMAPProtocol {
function _authCRAM_MD5($uid, $pwd, $cmdid)
{
class_exists('Auth_SASL') || require_once 'Auth/SASL.php';
if ( PEAR::isError($error = $this->_putCMD( $cmdid ,"AUTHENTICATE" , "CRAM-MD5") ) ) {
return $error;
@ -854,8 +854,11 @@ class Net_IMAPProtocol {
$ret=$this->_genericCommand('EXAMINE', $mailbox_name);
$parsed='';
if(isset( $ret["PARSED"] ) ){
for($i=0;$i<count($ret["PARSED"]); $i++){ $command=$ret["PARSED"][$i]["EXT"];
$parsed[key($command)]=$command[key($command)];
for($i=0;$i<count($ret["PARSED"]); $i++){
if (array_key_exists("EXT",$ret["PARSED"][$i]) && is_array($ret["PARSED"][$i]["EXT"])) {
$command=$ret["PARSED"][$i]["EXT"];
$parsed[key($command)]=$command[key($command)];
}
}
}
return array("PARSED"=>$parsed,"RESPONSE"=>$ret["RESPONSE"]);
@ -1204,7 +1207,7 @@ class Net_IMAPProtocol {
function cmdExpunge()
{
$ret=$this->_genericCommand('EXPUNGE');
if (PEAR::isError($ret)) return new PEAR_Error('could not Expunge!');
if(isset( $ret["PARSED"] ) ){
$parsed=$ret["PARSED"];
unset($ret["PARSED"]);
@ -2343,12 +2346,16 @@ class Net_IMAPProtocol {
if ($str[$pos] !== '"') return false; // start condition failed
$pos++;
$delimCount=0;
while($str[$pos] !== '"' && $pos < $len) {
// this is a fix to stop before the delimiter, in broken string messages containing an odd number of double quotes
// the idea is to check for a stopDelimited followed by eiter a new startDelimiter or an other stopDelimiter
// that allows to have something like '"Name (Nick)" <email>' containing one delimiter
if ($str[$pos] === $stopDelim && ($str[$pos+1] === $startDelim || $str[$pos+1] === $stopDelim)) {
// if you have something like "Name ((something))" we must count the delimiters (and hope that they are not unbalanced too)
// and check if we have a negative amount of delimiters or no delimiters to meet the stop condition, before we run into a closing double quote
if ($str[$pos] === $startDelim) $delimCount++;
if ($str[$pos] === $stopDelim) $delimCount--;
if ($str[$pos] === $stopDelim && ($str[$pos+1] === $startDelim || ($str[$pos+1] === $stopDelim && $delimCount<=0))) {
$pos--; // stopDelimited need to be parsed outside!
return false;
}
@ -2559,6 +2566,7 @@ class Net_IMAPProtocol {
}
break;
}
#error_log("egw-pear::NET::IMAPProtocoll:_getNextToken:".$str);
return $content_size;
}
@ -3065,7 +3073,7 @@ class Net_IMAPProtocol {
}
$this->_getNextToken($str, $token);
#error_log(" egw-pear::NET::IMAPProtocoll:_genericIMAPResponseParser: After retrieving the first token:".$token);
while ($token != $cmdid && $str != '') {
if ($token == '+' ) {
//if the token is + ignore the line
@ -3169,6 +3177,7 @@ class Net_IMAPProtocol {
$cmdid = $this->_getCmdId();
$this->_putCMD( $cmdid , $command , $params );
$args=$this->_getRawResponse( $cmdid );
#error_log("egw-pear::NET::IMAPProtocoll:_genericCommand:".$command." result:".print_r($args,TRUE));
return $this->_genericImapResponseParser( $args , $cmdid );
}