Source for file IMAPProtocol.php
Documentation is available at IMAPProtocol.php
// +----------------------------------------------------------------------+
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2003 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Author: Damian Alejandro Fernandez Sosa <damlists@cnba.uba.ar> |
// +----------------------------------------------------------------------+
require_once 'Net/Socket.php';
* Provides an implementation of the IMAP protocol using PEAR's
* @package Net_IMAP/Protocol
* @author Damian Alejandro Fernandez Sosa <damlists@cnba.uba.ar>
* The auth methods this class support
* The auth methods this class support
var $_serverAuthMethods = null;
* The the current mailbox
* The socket resource being used to connect to the IMAP server.
* To allow class debuging
* Command Number for IMAP commands
var $_unParsedReturn = false;
* _connected: checks if there is a connection made to a imap server or not
var $_serverSupportedCapabilities = null;
* Use UTF-7 funcionallity
//var $_useUTF_7 = false;
* Instantiates a new Net_IMAP object.
$this->_socket = new Net_Socket ();
* Include the Auth_SASL package. If the package is not available,
* we disable the authentication methods that depend upon it.
if ((@include_once 'Auth/SASL.php') == false ) {
* Attempt to connect to the IMAP server.
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
function cmdConnect($host= "localhost" , $port = 143 )
return new PEAR_Error ( 'already connected, logout first!' );
if ( PEAR ::isError ( $this->_socket->connect ( $host , $port ) ) ) {
return new PEAR_Error ( 'unable to open socket' );
if ( PEAR ::isError ( $this->_getRawResponse () ) ) {
return new PEAR_Error ( 'unable to open socket' );
$this->_connected = true;
* @return string Returns the CmdID and increment the counter
$this->_lastCmdID = "A000" . $this->_cmd_counter ;
return $this->_lastCmdID;
* @return string Returns the last cmdId
return $this->_lastCmdID;
* get current mailbox name
* @return string Returns the current mailbox
* Sets the debuging information on or off
* @param boolean True or false
* Send the given string of data to the server.
* @param string $data The string of data to send.
* @return mixed True on success or a PEAR_Error object on failure.
if($this->_socket->eof () ){
return new PEAR_Error ( 'Failed to write to socket: (connection lost!) ' );
if ( PEAR ::isError ( $error = $this->_socket->write ( $data ) ) ) {
return new PEAR_Error ( 'Failed to write to socket: ' .
// C: means this data was sent by the client (this class)
* Receive the given string of data from the server.
* @return mixed a line of response on success or a PEAR_Error object on failure.
if (PEAR ::isError ( $this->lastline = $this->_socket->gets ( 8192 ) ) ) {
return new PEAR_Error ('Failed to write to socket: ' .
$this->lastline->getMessage () );
// S: means this data was sent by the IMAP Server
echo "S: " . $this->lastline . "" ;
$this->dbgDialog.= "S: " . $this->lastline . "" ;
if( $this->lastline == '' ){
return new PEAR_Error ('Failed to receive from the socket: ' );
* Send a command to the server with an optional string of arguments.
* A carriage return / linefeed (CRLF) sequence will be appended to each
* command string before it is sent to the IMAP server.
* @param string $commandId The IMAP cmdID to send to the server.
* @param string $command The IMAP command to send to the server.
* @param string $args A string of optional arguments to append
* @return mixed The result of the _send() call.
function _putCMD ($commandId , $command, $args = '')
return $this->_send ( $commandId . " " . $command . ' ' . $args . "\r\n" );
return $this->_send ( $commandId . " " . $command . "\r\n" );
* Get a response from the server with an optional string of commandID.
* A carriage return / linefeed (CRLF) sequence will be appended to each
* command string before it is sent to the IMAP server.
* @param string $commandid The IMAP commandid retrive from the server.
* @return string The result response.
function _getRawResponse ($commandId = '*')
while ( !PEAR ::isError ( $this->_recvLn () ) ) {
$reply_code = strtok( $this->lastline , ' ' );
$arguments.= $this->lastline;
if ( !(strcmp( $commandId , $reply_code ) ) ) {
* get the "returning of the unparsed response" feature status
* @return boolean return if the unparsed response is returned or not
return $this->_unParsedReturn;
* set the "returning of the unparsed response" feature on or off
* @param boolean $status: true: feature is on
$this->_unParsedReturn = $status;
* Attempt to login to the iMAP server.
* @param string The userid to authenticate as.
* @param string The password to authenticate with.
* @return array Returns an array containing the response
$param=" \"$uid\" \"$pwd\"";
return $this->_genericCommand ('LOGIN', $param);
* Attempt to authenticate to the iMAP server.
* @param string The userid to authenticate as.
* @param string The password to authenticate with.
* @param string The cmdID.
* @return array Returns an array containing the response
if( !$this->_connected ){
return new PEAR_Error ('not connected!');
$cmdid = $this->_getCmdId ();
if ( PEAR ::isError ( $method = $this->_getBestAuthMethod ($userMethod) ) ) {
$result = $this->_authDigest_MD5 ( $uid , $pwd , $cmdid );
$result = $this->_authCRAM_MD5 ( $uid , $pwd ,$cmdid );
$result = $this->_authLOGIN ( $uid , $pwd , $cmdid );
$result = new PEAR_Error ( " $method is not a supported authentication method" );
$args = $this->_getRawResponse ( $cmdid );
return $this->_genericImapResponseParser ( $args , $cmdid );
/* Authenticates the user using the DIGEST-MD5 method.
* @param string The userid to authenticate as.
* @param string The password to authenticate with.
* @param string The cmdID.
* @return array Returns an array containing the response
function _authDigest_MD5 ($uid , $pwd , $cmdid)
if ( PEAR ::isError ($error = $this->_putCMD ( $cmdid ,"AUTHENTICATE" , "DIGEST-MD5") ) ) {
if (PEAR ::isError ( $args = $this->_recvLn () ) ) {
$this->_getNextToken ( $args , $plus );
$this->_getNextToken ( $args , $space );
$this->_getNextToken ( $args , $challenge );
$digest = &Auth_SASL ::factory ('digestmd5');
$auth_str = base64_encode($digest->getResponse ($uid, $pwd, $challenge,"localhost", "imap"));
if ( PEAR ::isError ( $error = $this->_send (" $auth_str\r\n" ))) {
if ( PEAR ::isError ( $args = $this->_recvLn () )) {
* We don't use the protocol's third step because IMAP doesn't allow
* subsequent authentication, so we just silently ignore it.
if ( PEAR ::isError ( $error = $this->_send ( "\r\n" ) ) ) {
/* Authenticates the user using the CRAM-MD5 method.
* @param string The userid to authenticate as.
* @param string The password to authenticate with.
* @param string The cmdID.
* @return array Returns an array containing the response
function _authCRAM_MD5 ($uid, $pwd, $cmdid)
if ( PEAR ::isError ($error = $this->_putCMD ( $cmdid ,"AUTHENTICATE" , "CRAM-MD5") ) ) {
if ( PEAR ::isError ( $args = $this->_recvLn () ) ) {
$this->_getNextToken ( $args , $plus );
$this->_getNextToken ( $args , $space );
$this->_getNextToken ( $args , $challenge );
$cram = &Auth_SASL ::factory ('crammd5');
$auth_str = base64_encode( $cram->getResponse ( $uid , $pwd , $challenge ) );
if ( PEAR ::isError ( $error = $this->_send ( $auth_str. "\r\n" ) ) ) {
/* Authenticates the user using the LOGIN method.
* @param string The userid to authenticate as.
* @param string The password to authenticate with.
* @param string The cmdID.
* @return array Returns an array containing the response
function _authLOGIN ($uid, $pwd, $cmdid)
if (PEAR ::isError ($error = $this->_putCMD ($cmdid,"AUTHENTICATE", "LOGIN"))) {
if (PEAR ::isError ($args = $this->_recvLn () )) {
$this->_getNextToken ( $args , $plus );
$this->_getNextToken ( $args , $space );
$this->_getNextToken ( $args , $challenge );
if ( PEAR ::isError ( $error = $this->_send ( $auth_str. "\r\n" ) ) ) {
if (PEAR ::isError ( $args = $this->_recvLn () ) ) {
if ( PEAR ::isError ($error = $this->_send ( $auth_str. "\r\n" ) ) ) {
* Returns the name of the best authentication method that the server
* @param string if !=null,authenticate with this method ($userMethod).
* @return mixed Returns a string containing the name of the best
* supported authentication method or a PEAR_Error object
* if a failure condition is encountered.
function _getBestAuthMethod ($userMethod = null )
if($userMethod != null ){
$methods[] = $userMethod;
if( ($methods != null ) && ($this->_serverAuthMethods != null )){
foreach ( $methods as $method ) {
if ( in_array( $method , $this->_serverAuthMethods ) ) {
$serverMethods= implode(',' ,$this->_serverAuthMethods);
return new PEAR_Error (" $method NOT supported authentication method!. This IMAP server " .
" supports these methods: $serverMethods, but I support $myMethods" );
return new PEAR_Error ("This IMAP server don't support any Auth methods");
* Attempt to disconnect from the iMAP server.
* @return array Returns an array containing the response
if( !$this->_connected ){
return new PEAR_Error ( 'not connected!' );
$cmdid = $this->_getCmdId ();
if ( PEAR ::isError ( $error = $this->_putCMD ( $cmdid , 'LOGOUT' ) ) ) {
if ( PEAR ::isError ($args = $this->_getRawResponse () ) ) {
if (PEAR ::isError ( $this->_socket->disconnect () ) ) {
return new PEAR_Error ('socket disconnect failed');
//return $this->_genericImapResponseParser($args,$cmdid);
* @return array Returns an array containing the response
return $this->_genericCommand ('NOOP');
* Send the CHECK command.
* @return array Returns an array containing the response
return $this->_genericCommand ('CHECK');
* Send the Select Mailbox Command
* @param string The mailbox to select.
* @return array Returns an array containing the response
if( !PEAR ::isError ( $ret= $this->_genericCommand ('SELECT', $mailbox_name) ) ){
* Send the EXAMINE Mailbox Command
* @param string The mailbox to examine.
* @return array Returns an array containing the response
$ret= $this->_genericCommand ('EXAMINE', $mailbox_name);
if(isset ( $ret["PARSED"] ) ){
for($i=0; $i< count($ret["PARSED"]); $i++ ){ $command= $ret["PARSED"][$i]["EXT"];
$parsed[key($command)]= $command[key($command)];
return array ("PARSED"=> $parsed,"RESPONSE"=> $ret["RESPONSE"]);
* Send the CREATE Mailbox Command
* @param string The mailbox to create.
* @return array Returns an array containing the response
return $this->_genericCommand ('CREATE', $mailbox_name);
* Send the RENAME Mailbox Command
* @param string The old mailbox name.
* @param string The new (renamed) mailbox name.
* @return array Returns an array containing the response
return $this->_genericCommand ('RENAME', " $mailbox_name $new_mailbox_name" );
* Send the DELETE Mailbox Command
* @param string The mailbox name to delete.
* @return array Returns an array containing the response
return $this->_genericCommand ('DELETE', $mailbox_name);
* Send the SUSCRIBE Mailbox Command
* @param string The mailbox name to suscribe.
* @return array Returns an array containing the response
return $this->_genericCommand ('SUBSCRIBE', $mailbox_name );
* Send the UNSUSCRIBE Mailbox Command
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
return $this->_genericCommand ('UNSUBSCRIBE', $mailbox_name );
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
return $this->_genericCommand ('FETCH' , " $msgset $fetchparam" );
* Send the CAPABILITY Command
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
$ret = $this->_genericCommand ( 'CAPABILITY' );
if(isset ( $ret["PARSED"] ) ){
$ret["PARSED"]= $ret["PARSED"][0 ]["EXT"]["CAPABILITY"];
//fill the $this->_serverAuthMethods and $this->_serverSupportedCapabilities arrays
foreach( $ret["PARSED"]["CAPABILITIES"] as $auth_method ){
$this->_serverAuthMethods[] = substr( $auth_method , 5 );
// Keep the capabilities response to use ir later
$this->_serverSupportedCapabilities = $ret["PARSED"]["CAPABILITIES"];
* Send the STATUS Mailbox Command
* @param string $mailbox the mailbox name
* @param string $request the request status it could be:
* MESSAGES | RECENT | UIDNEXT
* @return array Returns a Parsed Response
if( $request!= "MESSAGES" && $request!= "RECENT" && $request!= "UIDNEXT" &&
$request!= "UIDVALIDITY" && $request!= "UNSEEN" ){
$this->_prot_error (" request '$request' is invalid! see RFC2060!!!!" , __LINE__ , __FILE__ , false );
$ret = $this->_genericCommand ('STATUS', " $mailbox_name ($request)" );
if(isset ( $ret["PARSED"] ) ){
$ret['PARSED']= $ret["PARSED"][count($ret['PARSED'])-1 ]["EXT"];
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
function cmdList($mailbox_base, $mailbox)
return $this->_genericCommand ('LIST', " $mailbox_base $mailbox_name" );
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
function cmdLsub($mailbox_base, $mailbox)
return $this->_genericCommand ('LSUB', " $mailbox_base $mailbox_name" );
* Send the APPEND Command
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
function cmdAppend($mailbox, $msg , $flags_list = '' ,$time = '')
return new PEAR_Error ('not connected!');
$cmdid= $this->_getCmdId ();
// Falta el codigo para que flags list y time hagan algo!!
$param= sprintf("%s %s%s{%s+}\r\n%s",$mailbox_name,$flags_list,$time,$msg_size,$msg);
if (PEAR ::isError ($error = $this->_putCMD ($cmdid , 'APPEND' , $param ) ) ) {
$param= sprintf("%s %s%s{%s}\r\n",$mailbox_name,$flags_list,$time,$msg_size);
if (PEAR ::isError ($error = $this->_putCMD ($cmdid , 'APPEND' , $param ) ) ) {
if (PEAR ::isError ($error = $this->_recvLn () ) ) {
if (PEAR ::isError ($error = $this->_send ( $msg ) ) ) {
$args= $this->_getRawResponse ($cmdid);
$ret = $this->_genericImapResponseParser ($args,$cmdid);
* Send the CLOSE command.
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
return $this->_genericCommand ('CLOSE');
* Send the EXPUNGE command.
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
$ret= $this->_genericCommand ('EXPUNGE');
if(isset ( $ret["PARSED"] ) ){
foreach($parsed as $command){
if( strtoupper($command["COMMAND"]) == 'EXPUNGE' ){
$ret["PARSED"][$command["COMMAND"]][]= $command["NRO"];
$ret["PARSED"][$command["COMMAND"]]= $command["NRO"];
* Send the SEARCH command.
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
$_charset = "[$_charset] ";
$param=sprintf("%s%s",$charset,$search_cmd);
$ret = $this->_genericCommand ('SEARCH', $search_cmd );
if(isset ( $ret["PARSED"] ) ){
$ret["PARSED"]= $ret["PARSED"][0 ]["EXT"];
* Send the STORE command.
* @param string $message_set the sessage_set
* @param string $dataitem: the way we store the flags
* FLAGS: replace the flags whith $value
* FLAGS.SILENT: replace the flags whith $value but don't return untagged responses
* +FLAGS: Add the flags whith $value
* +FLAGS.SILENT: Add the flags whith $value but don't return untagged responses
* -FLAGS: Remove the flags whith $value
* -FLAGS.SILENT: Remove the flags whith $value but don't return untagged responses
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
function cmdStore($message_set, $dataitem, $value)
C: A003 STORE 2:4 +FLAGS (\Deleted)
S: * 2 FETCH FLAGS (\Deleted \Seen)
S: * 3 FETCH FLAGS (\Deleted)
S: * 4 FETCH FLAGS (\Deleted \Flagged \Seen)
S: A003 OK STORE completed
if( $dataitem!= "FLAGS" && $dataitem!= "FLAGS.SILENT" && $dataitem!= "+FLAGS" &&
$dataitem!= "+FLAGS.SILENT" && $dataitem!= "-FLAGS" && $dataitem!= "-FLAGS.SILENT" ){
$this->_prot_error (" dataitem '$dataitem' is invalid! see RFC2060!!!!" , __LINE__ , __FILE__ );
$param= sprintf("%s %s (%s)",$message_set,$dataitem,$value);
return $this->_genericCommand ('STORE', $param );
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
function cmdCopy($message_set, $mailbox)
return $this->_genericCommand ('COPY', sprintf("%s %s",$message_set,$mailbox_name) );
return $this->_genericCommand ('UID FETCH', sprintf("%s %s",$msgset,$fetchparam) );
return $this->_genericCommand ('UID COPY', sprintf("%s %s",$message_set,$mailbox_name) );
* Send the UID STORE command.
* @param string $message_set the sessage_set
* @param string $dataitem: the way we store the flags
* FLAGS: replace the flags whith $value
* FLAGS.SILENT: replace the flags whith $value but don't return untagged responses
* +FLAGS: Add the flags whith $value
* +FLAGS.SILENT: Add the flags whith $value but don't return untagged responses
* -FLAGS: Remove the flags whith $value
* -FLAGS.SILENT: Remove the flags whith $value but don't return untagged responses
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
C: A003 STORE 2:4 +FLAGS (\Deleted)
S: * 2 FETCH FLAGS (\Deleted \Seen)
S: * 3 FETCH FLAGS (\Deleted)
S: * 4 FETCH FLAGS (\Deleted \Flagged \Seen)
S: A003 OK STORE completed
if( $dataitem!= "FLAGS" && $dataitem!= "FLAGS.SILENT" && $dataitem!= "+FLAGS" &&
$dataitem!= "+FLAGS.SILENT" && $dataitem!= "-FLAGS" && $dataitem!= "-FLAGS.SILENT" ){
$this->_prot_error (" dataitem '$dataitem' is invalid! see RFC2060!!!!" , __LINE__ , __FILE__ );
return $this->_genericCommand ('UID STORE', sprintf("%s %s (%s)",$message_set,$dataitem,$value) );
* Send the SEARCH command.
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
$ret= $this->_genericCommand ('UID SEARCH', sprintf("%s",$search_cmd) );
if(isset ( $ret["PARSED"] ) ){
$ret["PARSED"]= $ret["PARSED"][0 ]["EXT"];
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
function cmdX($atom, $parameters)
return $this->_genericCommand (" X$atom" , $parameters );
/********************************************************************
*** HERE ENDS the RFC2060 IMAPS FUNCTIONS
*** AND BEGIN THE EXTENSIONS FUNCTIONS
********************************************************************/
/********************************************************************
*** RFC2087 IMAP4 QUOTA extension BEGINS HERE
********************************************************************/
//Check if the IMAP server has QUOTA support
return new PEAR_Error ("This IMAP server does not support QUOTA's! ");
$ret = $this->_genericCommand ('GETQUOTA', $mailbox_name );
if(isset ( $ret["PARSED"] ) ){
// remove the array index because the quota response returns only 1 line of output
$ret['PARSED']= $ret["PARSED"][0 ];
//Check if the IMAP server has QUOTA support
return new PEAR_Error ("This IMAP server does not support QUOTA's! ");
$ret = $this->_genericCommand ('GETQUOTAROOT', $mailbox_name );
if(isset ( $ret["PARSED"] ) ){
// remove the array index because the quota response returns only 1 line of output
$ret['PARSED']= $ret["PARSED"][0 ];
// TODO: implement the quota by number of emails!!
function cmdSetQuota($mailbox_name, $storageQuota = null ,$messagesQuota = null )
//Check if the IMAP server has QUOTA support
return new PEAR_Error ("This IMAP server does not support QUOTA's! ");
if( ($messagesQuota == null ) && ( $storageQuota == null ) ){
return new PEAR_Error ('$storageQuota and $messagesQuota parameters can\'t be both null if you want to use quota');
//Make the command request
$param= sprintf("%s (",$mailbox_name);
if($storageQuota != null ){
$param= sprintf("%sSTORAGE %s",$param,$storageQuota);
if( $messagesQuota != null ){
//if we have both types of quota on the same call we must append an space between
if($messagesQuota != null ){
$param= sprintf("%sMESSAGES %s",$param,$messagesQuota);
return $this->_genericCommand ('SETQUOTA', $param );
function cmdSetQuotaRoot($mailbox_name, $storageQuota = null ,$messagesQuota = null )
//Check if the IMAP server has QUOTA support
return new PEAR_Error ("This IMAP server does not support QUOTA's! ");
if( ($messagesQuota == null ) && ( $storageQuota == null ) ){
return new PEAR_Error ('$storageQuota and $messagesQuota parameters can\'t be both null if you want to use quota');
//Make the command request
$param= sprintf("%s (",$mailbox_name);
if($storageQuota != null ){
$param= sprintf("%sSTORAGE %s",$param,$storageQuota);
if( $messagesQuota != null ){
//if we have both types of quota on the same call we must append an space between
if($messagesQuota != null ){
$param= sprintf("%sMESSAGES %s",$param,$messagesQuota);
return $this->_genericCommand ('SETQUOTAROOT', $param );
/********************************************************************
*** RFC2087 IMAP4 QUOTA extension ENDS HERE
********************************************************************/
/********************************************************************
*** RFC2086 IMAP4 ACL extension BEGINS HERE
********************************************************************/
function cmdSetACL($mailbox_name, $user, $acl)
//Check if the IMAP server has ACL support
return new PEAR_Error ("This IMAP server does not support ACL's! ");
return $this->_genericCommand ('SETACL', sprintf("%s %s \"%s\"",$mailbox_name,$user_name,$acl) );
//Check if the IMAP server has ACL support
return new PEAR_Error ("This IMAP server does not support ACL's! ");
return $this->_genericCommand ('DELETEACL', sprintf("%s \"%s\"",$mailbox_name,$user) );
//Check if the IMAP server has ACL support
return new PEAR_Error ("This IMAP server does not support ACL's! ");
$ret = $this->_genericCommand ('GETACL', sprintf("%s",$mailbox_name) );
if(isset ( $ret["PARSED"] ) ){
$ret['PARSED']= $ret["PARSED"][0 ]["EXT"];
//Check if the IMAP server has ACL support
return new PEAR_Error ("This IMAP server does not support ACL's! ");
$ret = $this->_genericCommand ('LISTRIGHTS', sprintf("%s \"%s\"",$mailbox_name,$user) );
if(isset ( $ret["PARSED"] ) ){
$ret["PARSED"]= $ret["PARSED"][0 ]["EXT"];
//Check if the IMAP server has ACL support
return new PEAR_Error ("This IMAP server does not support ACL's! ");
$ret = $this->_genericCommand ('MYRIGHTS', sprintf("%s",$mailbox_name) );
if(isset ( $ret["PARSED"] ) ){
$ret["PARSED"]= $ret["PARSED"][0 ]["EXT"];
/********************************************************************
*** RFC2086 IMAP4 ACL extension ENDs HERE
********************************************************************/
/*******************************************************************************
*** draft-daboo-imap-annotatemore-05 IMAP4 ANNOTATEMORE extension BEGINS HERE
********************************************************************************/
// Check if the IMAP server has ANNOTATEMORE support
return new PEAR_Error ('This IMAP server does not support the ANNOTATEMORE extension!');
return new PEAR_Error ('Invalid $values argument passed to cmdSetAnnotation');
foreach ($values as $name => $value) {
$vallist .= " \"$name\" \"$value\" ";
$vallist = rtrim($vallist);
return $this->_genericCommand ('SETANNOTATION', sprintf('"%s" "%s" (%s)', $mailbox_name, $entry, $vallist));
// Check if the IMAP server has ANNOTATEMORE support
return new PEAR_Error ('This IMAP server does not support the ANNOTATEMORE extension!');
return new PEAR_Error ('Invalid $values argument passed to cmdDeleteAnnotation');
foreach ($values as $name) {
$vallist .= " \"$name\" NIL ";
$vallist = rtrim($vallist);
return $this->_genericCommand ('SETANNOTATION', sprintf('"%s" "%s" (%s)', $mailbox_name, $entry, $vallist));
// Check if the IMAP server has ANNOTATEMORE support
return new PEAR_Error ('This IMAP server does not support the ANNOTATEMORE extension!');
$entries = array ($entries);
foreach ($entries as $name) {
$entlist .= " \"$name\" ";
$entlist = rtrim($entlist);
if (count($entries) > 1 ) {
$values = array ($values);
foreach ($values as $name) {
$vallist .= " \"$name\" ";
$vallist = rtrim($vallist);
if (count($values) > 1 ) {
return $this->_genericCommand ('GETANNOTATION', sprintf('"%s" %s %s', $mailbox_name, $entlist, $vallist));
/*****************************************************************************
*** draft-daboo-imap-annotatemore-05 IMAP4 ANNOTATEMORE extension ENDs HERE
******************************************************************************/
/********************************************************************
*** HERE ENDS THE EXTENSIONS FUNCTIONS
*** AND BEGIN THE AUXILIARY FUNCTIONS
********************************************************************/
* tell if the server has capability $capability
if( $this->_serverAuthMethods == null ){
return $this->_serverAuthMethods;
* tell if the server has capability $capability
if( $this->_serverSupportedCapabilities == null ){
if($this->_serverSupportedCapabilities != null ){
if( in_array( $capability , $this->_serverSupportedCapabilities ) ){
* tell if the server has Quota support
* tell if the server has Quota support
* tell if the server has support for the ANNOTATEMORE extension
* Parses the responses like RFC822.SIZE and INTERNALDATE
* @param string the IMAP's server response
* @return string containing the parsed response
function _parseOneStringResponse (&$str, $line,$file)
$this->_parseSpace ($str , $line , $file );
$size = $this->_getNextToken ($str,$uid);
* Parses the FLAG response
* @param string the IMAP's server response
* @return Array containing the parsed response
function _parseFLAGSresponse (&$str)
$this->_parseSpace ($str , __LINE__ , __FILE__ );
$params_arr[] = $this->_arrayfy_content ($str);
for( $i = 0 ; $i < count($params_arr[0 ]) ; $i++ ){
$flags_arr[] = $params_arr[0 ][$i];
* Parses the BODY response
* @param string the IMAP's server response
* @return Array containing the parsed response
function _parseBodyResponse (&$str, $command){
$this->_parseSpace ($str , __LINE__ , __FILE__ );
while ($str[0 ] != ')' && $str!= ''){
$params_arr[] = $this->_arrayfy_content ($str);
* Makes the content an Array
* @param string the IMAP's server response
* @return Array containing the parsed response
function _arrayfy_content (&$str)
$this->_getNextToken ($str,$params);
$this->_getNextToken ($str,$params,false ,false );
while ( $str != '' && $params != ')'){
$params= $this->_arrayfy_content ( $params );
//I don't remove the colons (") to handle the case of retriving " "
// If I remove the colons the parser will interpret this field as an imap separator (space)
// instead of a valid field so I remove the colons here
//if params if empty (for example i'm parsing 2 quotes ("")
// I'll append an array entry to mantain compatibility
$this->_getNextToken ($str,$params,false ,false );
* Parses the BODY[],BODY[TEXT],.... responses
* @param string the IMAP's server response
* @return Array containing the parsed response
function _parseContentresponse (&$str, $command)
$this->_parseSpace ($str , __LINE__ , __FILE__ );
$size = $this->_getNextToken ($str,$content);
return array ( "CONTENT"=> $content , "CONTENT_SIZE" => $size );
* Parses the ENVELOPE response
* @param string the IMAP's server response
* @return Array containing the parsed response
function _parseENVELOPEresponse (&$str)
$this->_parseSpace ($str , __LINE__ , __FILE__ );
$this->_getNextToken ($str,$parenthesis);
if( $parenthesis != '(' ){
$this->_prot_error (" must be a '(' but is a '$parenthesis' !!!!" , __LINE__ , __FILE__ );
$this->_getNextToken ($str,$date);
$this->_parseSpace ($str , __LINE__ , __FILE__ );
// Get the email's Subject:
$this->_getNextToken ($str,$subject);
//$subject=$this->decode($subject);
$this->_parseSpace ($str , __LINE__ , __FILE__ );
$from_arr = $this->_getAddressList ($str);
$this->_parseSpace ($str , __LINE__ , __FILE__ );
$sender_arr = $this->_getAddressList ($str);
$this->_parseSpace ($str , __LINE__ , __FILE__ );
$reply_to_arr= $this->_getAddressList ($str);
$this->_parseSpace ($str , __LINE__ , __FILE__ );
$to_arr = $this->_getAddressList ($str);
$this->_parseSpace ($str , __LINE__ , __FILE__ );
$cc_arr = $this->_getAddressList ($str);
$this->_parseSpace ($str , __LINE__ , __FILE__ );
$bcc_arr = $this->_getAddressList ($str);
$this->_parseSpace ($str , __LINE__ , __FILE__ );
$this->_getNextToken ($str,$in_reply_to);
$this->_parseSpace ($str , __LINE__ , __FILE__ );
$this->_getNextToken ($str,$message_id);
$this->_getNextToken ($str,$parenthesis);
if( $parenthesis != ')' ){
$this->_prot_error (" must be a ')' but is a '$parenthesis' !!!!" , __LINE__ , __FILE__ );
return array ( "DATE"=> $date , "SUBJECT" => $subject,"FROM" => $from_arr,
"SENDER" => $sender_arr , "REPLY_TO" => $reply_to_arr, "TO" => $to_arr,
"CC" => $cc_arr, "BCC"=> $bcc_arr, "IN_REPLY_TO" => $in_reply_to, "MESSAGE_ID"=> $message_id );
* Parses the ARRDLIST as defined in RFC
* @param string the IMAP's server response
* @return Array containing the parsed response
function _getAddressList (&$str)
$params_arr = $this->_arrayfy_content ($str);
if( !isset ( $params_arr ) ){
$personal_name = $params_arr[0 ][0 ];
$at_domain_list = $params_arr[0 ][1 ];
$mailbox_name = $params_arr[0 ][2 ];
$host_name = $params_arr[0 ][3 ];
if( $mailbox_name!= '' && $host_name!= '' ){
$email= $mailbox_name . "@" . $host_name;
if(!isset ($personal_name)){
$rfc822_email= "<". $email . ">";
$rfc822_email= "\"". $personal_name . "\" <". $email . ">";
$email_arr[] = array ( "PERSONAL_NAME"=> $personal_name , "AT_DOMAIN_LIST"=> $at_domain_list ,
"MAILBOX_NAME"=> $this->utf_7_decode($mailbox_name), "HOST_NAME"=> $host_name,
"EMAIL"=> $email , "RFC822_EMAIL" => $rfc822_email );
* Utility funcion to find the closing parenthesis ")" Position it takes care of quoted ones
* @param string the IMAP's server response
* @return int containing the pos of the closing parenthesis ")"
function _getClosingBracesPos ($str_line, $startDelim = '(', $stopDelim = ')' )
// ignore all extra characters
// If inside of a string, skip string -- Boundary IDs and other
// things can have ) in them.
if ( $str_line[$pos] != $startDelim ) {
$this->_prot_error ("_getClosingParenthesisPos: must start with a '(' but is a '". $str_line[$pos] . "'!!!!\n" .
" STR_LINE:$str_line|size:$len|POS: $pos\n" , __LINE__ , __FILE__ );
for( $pos = 1 ; $pos < $len ; $pos++ ){
if ($str_line[$pos] == $stopDelim ) {
if ($str_line[$pos] == '"') {
while ( $str_line[$pos] != '"' && $pos < $len ) {
if ($str_line[$pos] == "\\" && $str_line[$pos + 1 ] == '"' )
if ($str_line[$pos] == "\\" && $str_line[$pos + 1 ] == "\\" )
if ( $str_line[$pos] == $startDelim ) {
$str_line_aux = substr( $str_line , $pos );
$pos_aux = $this->_getClosingBracesPos ( $str_line_aux );
if( $str_line[$pos] != $stopDelim ){
$this->_prot_error (" _getClosingBracesPos: must be a $stopDelim but is a '". $str_line[$pos] ." '|POS:$pos|STR_LINE:$str_line!!!!" , __LINE__ , __FILE__ );
* Utility funcion to get from here to the end of the line
* @param string the IMAP's server response
* @return string containing the string to the end of the line
function _getToEOL (&$str , $including = true )
$content= substr($str,0 ,$i + 1 );
for( $i = 0 ; $i < $len ; $i++ ){
if( $str[$i] == "\n" || $str[$i] == "\r")
$content = substr( $str ,0 , $i );
* Fetches the next IMAP token or parenthesis
* @param string the IMAP's server response
* @param string the next token
* @param boolean true: the parenthesis IS a token, false: I consider
* all the response in parenthesis as a token
* @return int containing the content size
function _getNextToken (&$str, &$content, $parenthesisIsToken=true ,$colonIsToken=true ){
if($str == '' || $len < 2 ){
if( ($posClosingBraces = $this->_getClosingBracesPos ($str, '{' , '}' )) == false ){
$this->_prot_error ("_getClosingBracesPos() error!!!" , __LINE__ , __FILE__ );
$this->_prot_error ("must be a number but is a '" . $strBytes . "'!!!!" , __LINE__ , __FILE__ );
if( $str[$posClosingBraces] != '}' ){
$this->_prot_error ("must be a '}' but is a '" . $str[$posClosingBraces] . "'!!!!" , __LINE__ , __FILE__ );
if( $str[$posClosingBraces + 1 ] != "\r" ){
$this->_prot_error ("must be a '\\r' but is a '" . $str[$posClosingBraces + 1 ] . "'!!!!" , __LINE__ , __FILE__ );
if( $str[$posClosingBraces + 2 ] != "\n" ){
$this->_prot_error ("must be a '\\n' but is a '" . $str[$posClosingBraces + 2 ] . "'!!!!" , __LINE__ , __FILE__ );
$content = substr( $str , $posClosingBraces + 3 , $strBytes );
if( strlen( $content ) != $strBytes ){
$this->_prot_error ("content size is ". strlen($content) . " but the string reports a size of $strBytes!!!\n" , __LINE__ , __FILE__ );
$content_size = $strBytes;
$str = substr( $str , $posClosingBraces + $strBytes + 3 );
for($pos=1; $pos< $len; $pos++ ){
if ( $str[$pos] == "\"" ) {
if ($str[$pos] == "\\" && $str[$pos + 1 ] == "\"" )
if ($str[$pos] == "\\" && $str[$pos + 1 ] == "\\" )
$this->_prot_error ("must be a '\"' but is a '" . $str[$pos] . "'!!!!" , __LINE__ , __FILE__ );
$content = substr( $str , 1 , $pos - 1 );
$str = substr( $str , $pos + 1 );
for($pos=1; $pos< $len; $pos++ ){
if ( $str[$pos] == "\"" ) {
if ($str[$pos] == "\\" && $str[$pos + 1 ] == "\"" )
if ($str[$pos] == "\\" && $str[$pos + 1 ] == "\\" )
$this->_prot_error ("must be a '\"' but is a '" . $str[$pos] . "'!!!!" , __LINE__ , __FILE__ );
$content = substr( $str , 0 , $pos + 1 );
$str = substr( $str , $pos + 1 );
$content = substr( $str , 0 , $pos );
$content = substr( $str , 0 , $pos );
if( $parenthesisIsToken == false ){
$pos = $this->_getClosingBracesPos ( $str );
$content_size = $pos + 1;
$content = substr( $str , 0 , $pos + 1 );
$str = substr( $str , $pos + 1 );
$content = substr( $str , 0 , $pos );
$content = substr( $str , 0 , $pos );
$content = substr( $str , 0 , $pos );
for( $pos = 0 ; $pos < $len ; $pos++ ){
if ( $str[$pos] == ' ' || $str[$pos] == "\r" || $str[$pos] == ')' || $str[$pos] == '(' || $str[$pos] == "\n" ) {
if ( $str[$pos] == "\\" && $str[$pos + 1 ] == ' ' )
if ( $str[$pos] == "\\" && $str[$pos + 1 ] == "\\" )
$content = substr( $str , 0 , 1 );
$content = substr( $str , 0 , $pos );
//if this is the end of the string... exit the switch
* Utility funcion to display to console the protocol errors
* @param string the error
* @param int the line producing the error
* @param string file where the error was produced
* @return string containing the error
function _prot_error ($str , $line , $file,$printError=true )
echo " $line,$file,PROTOCOL ERROR!:$str\n";
function _getEXTarray (&$str , $startDelim = '(' , $stopDelim = ')'){
/* I let choose the $startDelim and $stopDelim to allow parsing
the OK response so I also can parse a response like this
* OK [UIDNEXT 150] Predicted next UID
$this->_getNextToken ( $str , $parenthesis );
if( $parenthesis != $startDelim ){
$this->_prot_error (" must be a '$startDelim' but is a '$parenthesis' !!!!" , __LINE__ , __FILE__ );
while ( $parenthesis != $stopDelim && $str != '' ){
$this->_getNextToken ( $str , $token );
if( ( $ret = $this->_retrParsedResponse ( $str , $token ) ) != false ){
//$struct_arr[$token] = $ret;
if( $parenthesis != $stopDelim ){
$this->_prot_error (" 1_must be a '$stopDelim' but is a '$parenthesis' !!!!" , __LINE__ , __FILE__ );
function _retrParsedResponse ( &$str , $token, $previousToken = null )
//echo "\n\nTOKEN:$token\r\n";
return array ($token=> $this->_parseOneStringResponse ( $str,__LINE__ , __FILE__ ));
// case "RFC822.HEADER" :
return array ($token=> $this->_parseContentresponse ( $str , $token ));
return array ($token=> $this->_parseFLAGSresponse ( $str ));
return array ($token=> $this->_parseENVELOPEresponse ( $str ));
return array ($token=> $this->_parseOneStringResponse ( $str,__LINE__ , __FILE__ ));
return array ($token=> $this->_parseBodyResponse ( $str , $token ));
if( $previousToken != null ){
$aux["RECENT"]= $previousToken;
return array ($token=> $this->_parseOneStringResponse ( $str,__LINE__ , __FILE__ ));
return array ($token=> $previousToken);
return array ($token=> $token);
A tipical GETQUOTA DIALOG IS AS FOLLOWS
C: A0004 GETQUOTA user.damian
S: * QUOTA user.damian (STORAGE 1781460 4000000)
$mailbox = $this->_parseOneStringResponse ( $str,__LINE__ , __FILE__ );
$this->_parseSpace ( $str , __LINE__ , __FILE__ );
$this->_parseString ( $str , '(' , __LINE__ , __FILE__ );
$ret_aux = array ("MAILBOX"=> $this->utf_7_decode($mailbox) );
$this->_getNextToken ( $str , $quota_resp );
if( ( $ext = $this->_retrParsedResponse ( $str , $quota_resp )) == false ){
$this->_prot_error ("bogus response!!!!" , __LINE__ , __FILE__ );
$this->_getNextToken ( $str , $separator );
return array ($token=> $ret_aux);
$this->_parseSpace ( $str , __LINE__ , __FILE__ );
$this->_getNextToken ( $str , $quota_resp );
if( ( $ext = $this->_retrParsedResponse ( $str , $quota_resp )) == false ){
$this->_prot_error ("bogus response!!!!" , __LINE__ , __FILE__ );
$this->_parseString ( $str , ')' , __LINE__ , __FILE__ );
return array ($token=> $ret_aux);
A tipical GETQUOTA DIALOG IS AS FOLLOWS
C: A0004 GETQUOTA user.damian
S: * QUOTA user.damian (STORAGE 1781460 4000000)
$mailbox = $this->utf_7_decode($this->_parseOneStringResponse ( $str,__LINE__ , __FILE__ ));
$str_line = rtrim( substr( $this->_getToEOL ( $str , false ) , 0 ) );
$quotaroot = $this->_parseOneStringResponse ( $str_line,__LINE__ , __FILE__ );
$ret = @array ( "MAILBOX"=> $this->utf_7_decode($mailbox) , $token=> $quotaroot );
return array ($token=> $ret);
$used = $this->_parseOneStringResponse ( $str,__LINE__ , __FILE__ );
$qmax = $this->_parseOneStringResponse ( $str,__LINE__ , __FILE__ );
return array ($token=>array ("USED"=> $used, "QMAX" => $qmax));
$mused = $this->_parseOneStringResponse ( $str,__LINE__ , __FILE__ );
$mmax = $this->_parseOneStringResponse ( $str,__LINE__ , __FILE__ );
return array ($token=>array ("MUSED"=> $mused, "MMAX" => $mmax));
$this->_parseSpace ( $str ,__LINE__ ,__FILE__ );
// Get the parsed pathenthesis
$struct_arr = $this->_getEXTarray ( $str );
$this->_parseSpace ( $str , __LINE__ , __FILE__ );
$str_line = rtrim( substr( $this->_getToEOL ( $str , false ) , 0 ) );
$struct_arr["CAPABILITIES"] = explode( ' ' , $str_line );
return array ($token=> $struct_arr);
$mailbox = $this->_parseOneStringResponse ( $str,__LINE__ , __FILE__ );
$this->_parseSpace ( $str , __LINE__ , __FILE__ );
$ext = $this->_getEXTarray ( $str );
$struct_arr["ATTRIBUTES"] = $ext;
return array ($token=> $struct_arr);
$this->_parseSpace ( $str , __LINE__ , __FILE__ );
$params_arr = $this->_arrayfy_content ( $str );
$this->_parseSpace ( $str , __LINE__ , __FILE__ );
$this->_getNextToken ( $str , $hierarchydelim );
$this->_parseSpace ( $str,__LINE__ , __FILE__ );
$this->_getNextToken ( $str , $mailbox_name );
$result_array = array ( "NAME_ATTRIBUTES"=> $params_arr , "HIERACHY_DELIMITER"=> $hierarchydelim , "MAILBOX_NAME"=> $this->utf_7_decode($mailbox_name) );
return array ($token=> $result_array);
$this->_parseSpace ( $str , __LINE__ , __FILE__ );
$params_arr = $this->_arrayfy_content ( $str );
$this->_parseSpace ( $str , __LINE__ , __FILE__ );
$this->_getNextToken ( $str , $hierarchydelim );
$this->_parseSpace ( $str,__LINE__ , __FILE__ );
$this->_getNextToken ( $str , $mailbox_name );
$result_array = array ( "NAME_ATTRIBUTES"=> $params_arr , "HIERACHY_DELIMITER"=> $hierarchydelim , "MAILBOX_NAME"=> $this->utf_7_decode($mailbox_name) );
return array ($token=> $result_array);
$str_line = rtrim( substr( $this->_getToEOL ( $str , false ) , 1 ) );
$struct_arr["SEARCH_LIST"] = explode( ' ' , $str_line );
if(count($struct_arr["SEARCH_LIST"]) == 1 && $struct_arr["SEARCH_LIST"][0 ]== ''){
$struct_arr["SEARCH_LIST"]=null;
return array ($token=> $struct_arr);
parse the [ .... ] part of the response, use the method
_getEXTarray(&$str,'[',$stopDelim=']')
$str_line = rtrim( substr( $this->_getToEOL ( $str , false ) , 1 ) );
if($str_line[0 ] == '[' ){
$braceLen= $this->_getClosingBracesPos ($str_line, '[', ']' );
$str_aux= '('. substr($str_line,1 ,$braceLen -1 ). ')';
$ext_arr= $this->_getEXTarray ($str_aux);
//$ext_arr=array($token=>$this->_getEXTarray($str_aux));
//$ext_arr=array($token=>$str_line);
$result_array = $ext_arr;
parse the [ .... ] part of the response, use the method
_getEXTarray(&$str,'[',$stopDelim=']')
$str_line = rtrim( substr( $this->_getToEOL ( $str , false ) , 1 ) );
$result_array[] = @array ( "COMMAND"=> $token , "EXT"=> $str_line );
parse the [ .... ] part of the response, use the method
_getEXTarray(&$str,'[',$stopDelim=']')
$str_line = rtrim( substr( $this->_getToEOL ( $str , false ) , 1 ) );
$result_array[] = array ( "COMMAND"=> $token , "EXT"=> $str_line );
parse the [ .... ] part of the response, use the method
_getEXTarray(&$str,'[',$stopDelim=']')
$str_line = rtrim( substr( $this->_getToEOL ( $str , false ) , 1 ) );
$result_array[] = array ( "COMMAND"=> $command , "EXT"=> $str_line );
$this->_parseSpace ( $str ,__LINE__ , __FILE__ );
$this->_getNextToken ( $str , $mailbox );
$this->_parseSpace ( $str , __LINE__ , __FILE__ );
$this->_getNextToken ( $str , $user );
$this->_parseSpace ( $str , __LINE__ , __FILE__ );
$this->_getNextToken ( $str , $granted );
$result_array = @array ( "MAILBOX"=> $this->utf_7_decode($mailbox) , "USER"=> $user , "GRANTED"=> $granted , "UNGRANTED"=> $ungranted );
$this->_parseSpace ( $str , __LINE__ , __FILE__ );
$this->_getNextToken ( $str ,$mailbox );
$this->_parseSpace ( $str , __LINE__ , __FILE__ );
$this->_getNextToken ( $str , $granted );
$result_array = array ( "MAILBOX"=> $this->utf_7_decode($mailbox) , "GRANTED"=> $granted );
$this->_parseSpace ( $str , __LINE__ , __FILE__ );
$this->_getNextToken ( $str , $mailbox );
$this->_parseSpace ( $str , __LINE__ , __FILE__ );
for( $i = 0 ; $i < count( $acl_arr ) ; $i += 2 ){
$arr[] = array ( "USER"=> $acl_arr[$i] , "RIGHTS"=> $acl_arr[ $i + 1 ] );
$result_array = array ( "MAILBOX"=> $this->utf_7_decode($mailbox) , "USERS"=> $arr );
$this->_parseSpace ($str, __LINE__ , __FILE__ );
$this->_getNextToken ($str, $mailbox);
$this->_parseSpace ($str, __LINE__ , __FILE__ );
$this->_getNextToken ($str, $entry);
$this->_parseSpace ($str, __LINE__ , __FILE__ );
$attrs = $this->_arrayfy_content ($str);
$result_array = array ('MAILBOX' => $mailbox, 'ENTRY' => $entry , 'ATTRIBUTES' => $attrs);
$this->_prot_error ( "PROTOCOL ERROR!:str empty!!" , __LINE__ , __FILE__ );
$this->_prot_error ("OPENING PARENTHESIS ERROR!!!!!!!!!!!!!!!!!" , __LINE__ , __FILE__ );
//"CLOSING PARENTHESIS BREAK!!!!!!!"
$this->_prot_error ("BREAK!!!!!!!!!!!!!!!!!" , __LINE__ , __FILE__ );
// this can happen and we just ignore it
// This happens when - for example - fetch returns more than 1 parammeter
// for example you ask to get RFC822.SIZE and UID
//$this->_prot_error("SPACE BREAK!!!!!!!!!!!!!!!!!" , __LINE__ , __FILE__ );
//echo "BODYYYYYYY: $body_token\n";
//echo "BODYYYYYYY: $rfc822_token|$token\n";
if( $body_token == 'BODY[' || $body_token == 'BODY.' || $rfc822_token == 'RFC822.' ) {
//$this->_getNextToken( $str , $mailbox );
return array ($token=> $this->_parseContentresponse ( $str , $token ));
$this->_prot_error ( " UNIMPLEMMENTED! I don't know the parameter '$token' !!!" , __LINE__ , __FILE__ );
* Verifies that the next character IS a space
function _parseSpace (&$str,$line,$file, $printError = true )
This code repeats a lot in this class
so i make it a function to make all the code shorter
$this->_getNextToken ( $str , $space );
$this->_prot_error (" must be a ' ' but is a '$space' !!!!" , $line , $file,$printError );
function _parseString ( &$str , $char , $line , $file )
This code repeats a lot in this class
so i make it a function to make all the code shorter
$this->_getNextToken ( $str , $char_aux );
$this->_prot_error (" must be a $char but is a '$char_aux' !!!!" , $line , $file );
function _genericImapResponseParser ( &$str , $cmdid = null )
if( $this->_unParsedReturn ){
$this->_getNextToken ( $str , $token );
while ( $token != $cmdid && $str != '' ){
//if the token is + ignore the line
// TODO: verify that this is correct!!!
$this->_getToEOL ( $str );
$this->_getNextToken ( $str , $token );
$this->_parseString ( $str , ' ' , __LINE__ , __FILE__ );
$this->_getNextToken ( $str , $token );
$this->_getToEOL ( $str );
$this->_getNextToken ( $str , $token );
// The token is a NUMBER so I store it
$this->_parseSpace ( $str , __LINE__ , __FILE__ );
$this->_getNextToken ( $str , $command );
if( ( $ext_arr = $this->_retrParsedResponse ( $str , $command, $msg_nro ) ) == false ){
// if this bogus response cis a FLAGS () or EXPUNGE response
if( $command != 'FLAGS' && $command != 'EXPUNGE' ){
$this->_prot_error ("bogus response!!!!" , __LINE__ , __FILE__ , false );
$result_array[] = array ( "COMMAND"=> $command , "NRO"=> $msg_nro , "EXT"=> $ext_arr );
// OK the token is not a NUMBER so it MUST be a COMMAND
/* Call the parser return the array
take care of bogus responses!
if( ( $ext_arr = $this->_retrParsedResponse ( $str , $command ) ) == false ){
$this->_prot_error ( " bogus response!!!! (COMMAND:$command)" , __LINE__ , __FILE__ );
$result_array[] = array ( "COMMAND"=> $command , "EXT"=> $ext_arr );
$this->_getNextToken ( $str , $token );
if( $token != "\r\n" && $token != '' ){
$this->_prot_error (" PARSE ERROR!!! must be a '\\r\\n' here but is a '$token'!!!! (getting the next line)|STR:|$str|" , __LINE__ , __FILE__ );
$this->_getNextToken ( $str , $token );
//if the token is + ignore the line
// TODO: verify that this is correct!!!
$this->_getToEOL ( $str );
$this->_getNextToken ( $str , $token );
// OK we finish the UNTAGGED Response now we must parse the FINAL TAGGED RESPONSE
//TODO: make this a litle more elegant!
$this->_parseSpace ( $str , __LINE__ , __FILE__ , false );
$this->_getNextToken ( $str , $cmd_status );
$str_line = rtrim (substr( $this->_getToEOL ( $str ) , 1 ) );
$response["RESPONSE"]=array ( "CODE"=> $cmd_status , "STR_CODE"=> $str_line , "CMDID"=> $cmdid );
if( !empty ($result_array)){
$ret= array_merge($ret,array ("PARSED"=> $result_array) );
if( $this->_unParsedReturn ){
$unparsed["UNPARSED"]= $unparsed_str;
if( isset ($status_arr) ){
$status["STATUS"]= $status_arr;
function _genericCommand ($command, $params = '')
if( !$this->_connected ){
return new PEAR_Error ( " not connected! (CMD:$command)" );
$cmdid = $this->_getCmdId ();
$this->_putCMD ( $cmdid , $command , $params );
$args= $this->_getRawResponse ( $cmdid );
return $this->_genericImapResponseParser ( $args , $cmdid );
if($this->_useUTF_7 == false ){
//return imap_utf7_encode($str);
return new PEAR_Error ('error');
for ($i = 0; $i < strlen($str); $i++ ) {
//those chars should be base64 encoded
if ( ((ord($str[$i]) >= 39 ) and (ord($str[$i]) <= 126 )) or ((ord($str[$i]) >= 32 ) and (ord($str[$i]) <= 37 )) ) {
$encoded_utf7 = sprintf("%s%s",$encoded_utf7 , $str[$i]);
if (ord($str[$i]) == 38 ) {
$encoded_utf7 = sprintf("%s&-", $encoded_utf7 );
$base64_part = sprintf("%s%s",$base64_part , $str[$i]);
//$base64_part = sprintf("%s%s%s",$base64_part , chr(0) , $str[$i]);
if($this->_useUTF_7 == false ){
//return imap_utf7_decode($str);
for ($i = 0; $i < strlen($str); $i++ ) {
if ( strlen($base64_part) > 0 ) {
if ($base64_part == '&') {
$decoded_utf7 = sprintf("%s&" , $decoded_utf7 );
$decoded_utf7 = sprintf("%s%s", $decoded_utf7 , $next_part_decoded );
$base64_part = sprintf("%s%s", $base64_part , $str[$i] );
$decoded_utf7 = sprintf("%s%s", $decoded_utf7 , $str[$i] );
Documentation generated on Mon, 11 Mar 2019 13:54:09 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.
|