home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2008 February / PCWFEB08.iso / Software / Resources / Developers / XAMPP 1.5.4 / Windows installer / xampp-win32-1.5.4-installer.exe / xampp / php / pear / Net / IMAPProtocol.php < prev    next >
Encoding:
PHP Script  |  2005-12-02  |  83.3 KB  |  3,049 lines

  1. <?php
  2. //
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 4                                                        |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2003 The PHP Group                                |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.02 of the PHP license,      |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available at through the world-wide-web at                           |
  11. // | http://www.php.net/license/2_02.txt.                                 |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Author: Damian Alejandro Fernandez Sosa <damlists@cnba.uba.ar>       |
  17. // +----------------------------------------------------------------------+
  18. require_once 'Net/Socket.php';
  19.  
  20.  
  21.  
  22. /**
  23.  * Provides an implementation of the IMAP protocol using PEAR's
  24.  * Net_Socket:: class.
  25.  *
  26.  * @package Net_IMAP/Protocol
  27.  * @author  Damian Alejandro Fernandez Sosa <damlists@cnba.uba.ar>
  28.  */
  29. class Net_IMAPProtocol {
  30.  
  31.  
  32.     /**
  33.     * The auth methods this class support
  34.     * @var array
  35.     */
  36.     var $supportedAuthMethods=array('DIGEST-MD5', 'CRAM-MD5', 'LOGIN');
  37.  
  38.  
  39.     /**
  40.     * The auth methods this class support
  41.     * @var array
  42.     */
  43.     var $supportedSASLAuthMethods=array('DIGEST-MD5', 'CRAM-MD5');
  44.  
  45.      /**
  46.      * _serverAuthMethods
  47.      * @var boolean
  48.      */
  49.     var $_serverAuthMethods = null;
  50.  
  51.  
  52.     /**
  53.      * The the current mailbox
  54.      * @var string
  55.      */
  56.     var $currentMailbox = "INBOX" ;
  57.  
  58.  
  59.     /**
  60.      * The socket resource being used to connect to the IMAP server.
  61.      * @var resource
  62.      */
  63.     var $_socket = null;
  64.  
  65.      /**
  66.      * To allow class debuging
  67.      * @var boolean
  68.      */
  69.     var $_debug = false;
  70.  
  71.     var $dbgDialog = '';
  72.  
  73.      /**
  74.      * Command Number
  75.      * @var int
  76.      */
  77.     var $_cmd_counter = 1;
  78.  
  79.  
  80.      /**
  81.      * Command Number for IMAP commands
  82.      * @var int
  83.      */
  84.     var $_lastCmdID = 1;
  85.  
  86.      /**
  87.      * Command Number
  88.      * @var boolean
  89.      */
  90.     var $_unParsedReturn = false;
  91.  
  92.  
  93.  
  94.      /**
  95.      * _connected: checks if there is a connection made to a imap server or not
  96.      * @var boolean
  97.      */
  98.     var $_connected = false;
  99.      /**
  100.      * Capabilities
  101.      * @var boolean
  102.      */
  103.     var $_serverSupportedCapabilities = null;
  104.  
  105.  
  106.  
  107.      /**
  108.      * Use UTF-7 funcionallity
  109.      * @var boolean
  110.      */
  111.     //var $_useUTF_7 = false;
  112.     var $_useUTF_7 = true;
  113.  
  114.  
  115.  
  116.     /**
  117.      * Constructor
  118.      *
  119.      * Instantiates a new Net_IMAP object.
  120.      *
  121.      * @since  1.0
  122.      */
  123.     function Net_IMAPProtocol()
  124.     {
  125.         $this->_socket = new Net_Socket();
  126.  
  127.         /*
  128.          * Include the Auth_SASL package.  If the package is not available,
  129.          * we disable the authentication methods that depend upon it.
  130.          */
  131.  
  132.  
  133.         if ((@include_once 'Auth/SASL.php') == false) {
  134.             foreach($this->supportedSASLAuthMethods as $SASLMethod){
  135.                 $pos = array_search( $SASLMethod , $this->supportedAuthMethods);
  136.                 unset($this->supportedAuthMethods[$pos]);
  137.             }
  138.         }
  139.  
  140.     }
  141.  
  142.  
  143.     /**
  144.      * Attempt to connect to the IMAP server.
  145.      *
  146.      * @return mixed Returns a PEAR_Error with an error message on any
  147.      *               kind of failure, or true on success.
  148.      * @access public
  149.      * @since  1.0
  150.      */
  151.     function cmdConnect($host= "localhost"  , $port = 143)
  152.     {
  153.         if( $this->_connected ){
  154.             return new PEAR_Error( 'already connected, logout first!' );
  155.         }
  156.         if ( PEAR::isError( $this->_socket->connect( $host , $port ) ) ) {
  157.             return new PEAR_Error( 'unable to open socket' );
  158.         }
  159.         if ( PEAR::isError( $this->_getRawResponse() ) ) {
  160.             return new PEAR_Error( 'unable to open socket' );
  161.         }
  162.         $this->_connected = true;
  163.         return true;
  164.     }
  165.  
  166.  
  167.     /**
  168.      * get the cmd ID
  169.      *
  170.      * @return string Returns the CmdID and increment the counter
  171.      *
  172.      * @access private
  173.      * @since  1.0
  174.      */
  175.     function _getCmdId()
  176.     {
  177.         $this->_lastCmdID = "A000" . $this->_cmd_counter ;
  178.         $this->_cmd_counter++;
  179.         return $this->_lastCmdID;
  180.     }
  181.  
  182.  
  183.     /**
  184.      * get the last cmd ID
  185.      *
  186.      * @return string Returns the last cmdId
  187.      *
  188.      * @access public
  189.      * @since  1.0
  190.      */
  191.     function getLastCmdId()
  192.     {
  193.         return $this->_lastCmdID;
  194.     }
  195.  
  196.  
  197.  
  198.  
  199.     /**
  200.      * get current mailbox name
  201.      *
  202.      * @return string Returns the current mailbox
  203.      *
  204.      * @access public
  205.      * @since  1.0
  206.      */
  207.     function getCurrentMailbox()
  208.     {
  209.         return $this->currentMailbox;
  210.     }
  211.  
  212.  
  213.  
  214.  
  215.     /**
  216.      * Sets the debuging information on or off
  217.      *
  218.      * @param boolean True or false
  219.      *
  220.      * @return nothing
  221.      * @access public
  222.      * @since  1.0
  223.      */
  224.     function setDebug($debug = true)
  225.     {
  226.         $this->_debug = $debug;
  227.     }
  228.  
  229.  
  230.     function getDebugDialog()
  231.     {
  232.         return $this->dbgDialog;
  233.     }
  234.  
  235.  
  236.  
  237.     /**
  238.      * Send the given string of data to the server.
  239.      *
  240.      * @param   string  $data    The string of data to send.
  241.      *
  242.      * @return  mixed   True on success or a PEAR_Error object on failure.
  243.      *
  244.      * @access  private
  245.      * @since  1.0
  246.      */
  247.     function _send($data)
  248.     {
  249.         if($this->_socket->eof() ){
  250.             return new PEAR_Error( 'Failed to write to socket: (connection lost!) ' );
  251.         }
  252.         if ( PEAR::isError( $error = $this->_socket->write( $data ) ) ) {
  253.  
  254.             return new PEAR_Error( 'Failed to write to socket: ' .
  255.                                   $error->getMessage() );
  256.         }
  257.  
  258.         if( $this->_debug ){
  259.             // C: means this data was sent by  the client (this class)
  260.             echo "C: $data";
  261.             $this->dbgDialog.="C: $data";
  262.         }
  263.         return true;
  264.     }
  265.  
  266.     /**
  267.      * Receive the given string of data from the server.
  268.      *
  269.      * @return  mixed   a line of response on success or a PEAR_Error object on failure.
  270.      *
  271.      * @access  private
  272.      * @since  1.0
  273.      */
  274.     function _recvLn()
  275.     {
  276.  
  277.         if (PEAR::isError( $this->lastline = $this->_socket->gets( 8192 ) ) ) {
  278.             return new PEAR_Error('Failed to write to socket: ' .
  279.                                               $this->lastline->getMessage() );
  280.         }
  281.         if($this->_debug){
  282.             // S: means this data was sent by  the IMAP Server
  283.             echo "S: " . $this->lastline . "" ;
  284.             $this->dbgDialog.="S: " . $this->lastline . "" ;
  285.         }
  286.         if( $this->lastline == '' ){
  287.             return new PEAR_Error('Failed to receive from the  socket: '  );
  288.         }
  289.         return $this->lastline;
  290.     }
  291.  
  292.  
  293.  
  294.  
  295.  
  296.     /**
  297.      * Send a command to the server with an optional string of arguments.
  298.      * A carriage return / linefeed (CRLF) sequence will be appended to each
  299.      * command string before it is sent to the IMAP server.
  300.      *
  301.      * @param   string  $commandId  The IMAP cmdID to send to the server.
  302.      * @param   string  $command    The IMAP command to send to the server.
  303.      * @param   string  $args       A string of optional arguments to append
  304.      *                              to the command.
  305.      *
  306.      * @return  mixed   The result of the _send() call.
  307.      *
  308.      * @access  private
  309.      * @since  1.0
  310.      */
  311.     function _putCMD($commandId , $command, $args = '')
  312.     {
  313.         if ( !empty( $args ) ) {
  314.             return $this->_send( $commandId . " " . $command . ' ' . $args . "\r\n" );
  315.         }
  316.         return $this->_send( $commandId . " " . $command . "\r\n" );
  317.     }
  318.  
  319.  
  320.  
  321.  
  322.  
  323.  
  324.     /**
  325.      * Get a response from the server with an optional string of commandID.
  326.      * A carriage return / linefeed (CRLF) sequence will be appended to each
  327.      * command string before it is sent to the IMAP server.
  328.      *
  329.      * @param   string  $commandid    The IMAP commandid retrive from the server.
  330.      *
  331.      * @return  string   The result response.
  332.      *
  333.      * @access  private
  334.      */
  335.     function _getRawResponse($commandId = '*')
  336.     {
  337.        $arguments = '';
  338.        while ( !PEAR::isError( $this->_recvLn() ) ) {
  339.            $reply_code = strtok( $this->lastline , ' ' );
  340.            $arguments.= $this->lastline;
  341.            if ( !(strcmp( $commandId , $reply_code ) ) ) {
  342.            return $arguments;
  343.            }
  344.        }
  345.        return $arguments;
  346.      }
  347.  
  348.  
  349.  
  350.  
  351.  
  352.      /**
  353.      * get the "returning of the unparsed response" feature status
  354.      *
  355.      * @return boolean return if the unparsed response is returned or not
  356.      *
  357.      * @access public
  358.      * @since  1.0
  359.      *
  360.      */
  361.     function getUnparsedResponse()
  362.     {
  363.         return $this->_unParsedReturn;
  364.     }
  365.  
  366.  
  367.  
  368.  
  369.  
  370.  
  371.      /**
  372.      * set the "returning of the unparsed response" feature on or off
  373.      *
  374.      * @param  boolean  $status: true: feature is on
  375.      * @return nothing
  376.      *
  377.      * @access public
  378.      * @since  1.0
  379.      */
  380.     function setUnparsedResponse($status)
  381.     {
  382.         $this->_unParsedReturn = $status;
  383.     }
  384.  
  385.  
  386.  
  387.  
  388.  
  389.  
  390.     /**
  391.      * Attempt to login to the iMAP server.
  392.      *
  393.      * @param string The userid to authenticate as.
  394.      * @param string The password to authenticate with.
  395.      *
  396.      * @return array Returns an array containing the response
  397.      *
  398.      * @access public
  399.      * @since  1.0
  400.      */
  401.     function cmdLogin($uid , $pwd)
  402.     {
  403.         $param="\"$uid\" \"$pwd\"";
  404.         return $this->_genericCommand('LOGIN', $param);
  405.     }
  406.  
  407.  
  408.  
  409.  
  410.  
  411.  
  412.     /**
  413.      * Attempt to authenticate to the iMAP server.
  414.      * @param string The userid to authenticate as.
  415.      * @param string The password to authenticate with.
  416.      * @param string The cmdID.
  417.      *
  418.      * @return array Returns an array containing the response
  419.      *
  420.      * @access public
  421.      * @since  1.0
  422.      */
  423.     function cmdAuthenticate($uid , $pwd , $userMethod = null)
  424.     {
  425.  
  426.         if( !$this->_connected ){
  427.             return new PEAR_Error('not connected!');
  428.         }
  429.  
  430.         $cmdid = $this->_getCmdId();
  431.  
  432.  
  433.         if ( PEAR::isError( $method = $this->_getBestAuthMethod($userMethod) ) ) {
  434.             return $method;
  435.         }
  436.  
  437.  
  438.         switch ($method) {
  439.             case 'DIGEST-MD5':
  440.                 $result = $this->_authDigest_MD5( $uid , $pwd , $cmdid );
  441.                 break;
  442.             case 'CRAM-MD5':
  443.                 $result = $this->_authCRAM_MD5( $uid , $pwd ,$cmdid );
  444.                 break;
  445.             case 'LOGIN':
  446.                 $result = $this->_authLOGIN( $uid , $pwd , $cmdid );
  447.                 break;
  448.  
  449.             default :
  450.                 $result = new PEAR_Error( "$method is not a supported authentication method" );
  451.                 break;
  452.         }
  453.  
  454.         $args = $this->_getRawResponse( $cmdid );
  455.         return $this->_genericImapResponseParser( $args , $cmdid );
  456.  
  457.     }
  458.  
  459.  
  460.  
  461.  
  462.  
  463.  
  464.  
  465.  
  466.      /* Authenticates the user using the DIGEST-MD5 method.
  467.      *
  468.      * @param string The userid to authenticate as.
  469.      * @param string The password to authenticate with.
  470.      * @param string The cmdID.
  471.      *
  472.      * @return array Returns an array containing the response
  473.      *
  474.      * @access private
  475.      * @since  1.0
  476.      */
  477.     function _authDigest_MD5($uid , $pwd , $cmdid)
  478.     {
  479.  
  480.         if ( PEAR::isError($error = $this->_putCMD( $cmdid ,"AUTHENTICATE" , "DIGEST-MD5") ) ) {
  481.             return $error;
  482.         }
  483.  
  484.         if (PEAR::isError( $args = $this->_recvLn() ) ) {
  485.             return $args;
  486.         }
  487.  
  488.         $this->_getNextToken( $args , $plus );
  489.  
  490.         $this->_getNextToken( $args , $space );
  491.  
  492.         $this->_getNextToken( $args , $challenge );
  493.  
  494.         $challenge = base64_decode( $challenge );
  495.  
  496.         $digest = &Auth_SASL::factory('digestmd5');
  497.  
  498.         $auth_str = base64_encode($digest->getResponse($uid, $pwd, $challenge,"localhost", "imap"));
  499.  
  500.         if ( PEAR::isError( $error = $this->_send("$auth_str\r\n"))) {
  501.             return $error;
  502.         }
  503.  
  504.         if ( PEAR::isError( $args = $this->_recvLn() )) {
  505.             return $args;
  506.         }
  507.         /*
  508.          * We don't use the protocol's third step because IMAP doesn't allow
  509.          * subsequent authentication, so we just silently ignore it.
  510.          */
  511.         if ( PEAR::isError( $error = $this->_send( "\r\n" ) ) ) {
  512.             return $error;
  513.         }
  514.     }
  515.  
  516.  
  517.  
  518.  
  519.  
  520.  
  521.  
  522.  
  523.      /* Authenticates the user using the CRAM-MD5 method.
  524.      *
  525.      * @param string The userid to authenticate as.
  526.      * @param string The password to authenticate with.
  527.      * @param string The cmdID.
  528.      *
  529.      * @return array Returns an array containing the response
  530.      *
  531.      * @access private
  532.      * @since  1.0
  533.      */
  534.     function _authCRAM_MD5($uid, $pwd, $cmdid)
  535.     {
  536.  
  537.  
  538.  
  539.         if ( PEAR::isError($error = $this->_putCMD( $cmdid ,"AUTHENTICATE" , "CRAM-MD5") ) ) {
  540.             return $error;
  541.         }
  542.  
  543.         if ( PEAR::isError( $args = $this->_recvLn() ) ) {
  544.             return $args;
  545.         }
  546.  
  547.         $this->_getNextToken( $args , $plus );
  548.  
  549.         $this->_getNextToken( $args , $space );
  550.  
  551.         $this->_getNextToken( $args , $challenge );
  552.  
  553.         $challenge = base64_decode( $challenge );
  554.  
  555.         $cram = &Auth_SASL::factory('crammd5');
  556.  
  557.         $auth_str = base64_encode( $cram->getResponse( $uid , $pwd , $challenge ) );
  558.  
  559.         if ( PEAR::isError( $error = $this->_send( $auth_str."\r\n" ) ) ) {
  560.             return $error;
  561.         }
  562.  
  563.     }
  564.  
  565.  
  566.  
  567.  
  568.  
  569.  
  570.  
  571.  
  572.  
  573.      /* Authenticates the user using the LOGIN method.
  574.      *
  575.      * @param string The userid to authenticate as.
  576.      * @param string The password to authenticate with.
  577.      * @param string The cmdID.
  578.      *
  579.      * @return array Returns an array containing the response
  580.      *
  581.      * @access private
  582.      * @since  1.0
  583.      */
  584.     function _authLOGIN($uid, $pwd, $cmdid)
  585.     {
  586.  
  587.         if (PEAR::isError($error = $this->_putCMD($cmdid,"AUTHENTICATE", "LOGIN"))) {
  588.             return $error;
  589.         }
  590.  
  591.         if (PEAR::isError($args = $this->_recvLn() )) {
  592.             return $args;
  593.         }
  594.  
  595.         $this->_getNextToken( $args , $plus );
  596.  
  597.         $this->_getNextToken( $args , $space );
  598.  
  599.         $this->_getNextToken( $args , $challenge );
  600.  
  601.         $challenge = base64_decode( $challenge );
  602.  
  603.         $auth_str = base64_encode( "$uid" );
  604.  
  605.         if ( PEAR::isError( $error = $this->_send( $auth_str."\r\n" ) ) ) {
  606.             return $error;
  607.         }
  608.  
  609.         if (PEAR::isError( $args = $this->_recvLn() ) ) {
  610.             return $args;
  611.         }
  612.  
  613.         $auth_str = base64_encode( "$pwd" );
  614.  
  615.         if ( PEAR::isError($error = $this->_send( $auth_str."\r\n" ) ) ) {
  616.             return $error;
  617.         }
  618.  
  619.     }
  620.  
  621.  
  622.  
  623.  
  624.  
  625.  
  626.  
  627.  
  628.     /**
  629.      * Returns the name of the best authentication method that the server
  630.      * has advertised.
  631.      *
  632.      * @param string if !=null,authenticate with this method ($userMethod).
  633.      *
  634.      * @return mixed    Returns a string containing the name of the best
  635.      *                  supported authentication method or a PEAR_Error object
  636.      *                  if a failure condition is encountered.
  637.      * @access private
  638.      * @since  1.0
  639.      */
  640.     function _getBestAuthMethod($userMethod = null)
  641.     {
  642.        $this->cmdCapability();
  643.  
  644.         if($userMethod != null ){
  645.  
  646.             $methods = array();
  647.  
  648.             $methods[] = $userMethod;
  649.  
  650.         }else{
  651.             $methods = $this->supportedAuthMethods;
  652.         }
  653.  
  654.         if( ($methods != null) && ($this->_serverAuthMethods != null)){
  655.             foreach ( $methods as $method ) {
  656.                 if ( in_array( $method , $this->_serverAuthMethods ) ) {
  657.                     return $method;
  658.                 }
  659.             }
  660.             $serverMethods=implode(',' ,$this->_serverAuthMethods);
  661.             $myMethods=implode(',' ,$this->supportedAuthMethods);
  662.             return new PEAR_Error("$method NOT supported authentication method!. This IMAP server " .
  663.                 "supports these methods: $serverMethods, but I support $myMethods");
  664.         }else{
  665.             return new PEAR_Error("This IMAP server don't support any Auth methods");
  666.         }
  667.     }
  668.  
  669.  
  670.  
  671.  
  672.  
  673.  
  674.  
  675.  
  676.  
  677.     /**
  678.      * Attempt to disconnect from the iMAP server.
  679.      *
  680.      * @return array Returns an array containing the response
  681.      *
  682.      * @access public
  683.      * @since  1.0
  684.      */
  685.     function cmdLogout()
  686.     {
  687.         if( !$this->_connected ){
  688.             return new PEAR_Error( 'not connected!' );
  689.         }
  690.  
  691.         $cmdid = $this->_getCmdId();
  692.         if ( PEAR::isError( $error = $this->_putCMD( $cmdid , 'LOGOUT' ) ) ) {
  693.             return $error;
  694.         }
  695.         if ( PEAR::isError($args = $this->_getRawResponse() ) ) {
  696.             return $args;
  697.         }
  698.         if (PEAR::isError( $this->_socket->disconnect() ) ) {
  699.             return new PEAR_Error('socket disconnect failed');
  700.         }
  701.  
  702.         return $args;
  703.         // not for now
  704.         //return $this->_genericImapResponseParser($args,$cmdid);
  705.  
  706.     }
  707.  
  708.  
  709.  
  710.  
  711.  
  712.     /**
  713.      * Send the NOOP command.
  714.      *
  715.      * @return array Returns an array containing the response
  716.      *
  717.      * @access public
  718.      * @since  1.0
  719.      */
  720.     function cmdNoop()
  721.     {
  722.         return $this->_genericCommand('NOOP');
  723.     }
  724.  
  725.  
  726.  
  727.  
  728.  
  729.  
  730.  
  731.  
  732.  
  733.     /**
  734.      * Send the CHECK command.
  735.      *
  736.      * @return array Returns an array containing the response
  737.      *
  738.      * @access public
  739.      * @since  1.0
  740.      */
  741.     function cmdCheck()
  742.     {
  743.         return $this->_genericCommand('CHECK');
  744.     }
  745.  
  746.  
  747.  
  748.  
  749.  
  750.  
  751.  
  752.  
  753.  
  754.  
  755.     /**
  756.      * Send the  Select Mailbox Command
  757.      *
  758.      * @param string The mailbox to select.
  759.      *
  760.      * @return array Returns an array containing the response
  761.      *
  762.      * @access public
  763.      * @since  1.0
  764.      */
  765.     function cmdSelect($mailbox)
  766.     {
  767.         $mailbox_name=sprintf("\"%s\"",$this->utf_7_encode($mailbox) );
  768.         if( !PEAR::isError( $ret= $this->_genericCommand('SELECT', $mailbox_name) ) ){
  769.             $this->currentMailbox  = $mailbox;
  770.         }
  771.         return $ret;
  772.     }
  773.  
  774.  
  775.  
  776.  
  777.  
  778.  
  779.  
  780.  
  781.  
  782.  
  783.     /**
  784.      * Send the  EXAMINE  Mailbox Command
  785.      *
  786.      * @param string The mailbox to examine.
  787.      * @return array Returns an array containing the response
  788.      *
  789.      * @access public
  790.      * @since  1.0
  791.      */
  792.     function cmdExamine($mailbox)
  793.     {
  794.  
  795.         $mailbox_name=sprintf("\"%s\"",$this->utf_7_encode($mailbox) );
  796.         $ret=$this->_genericCommand('EXAMINE', $mailbox_name);
  797.         $parsed='';
  798.         if(isset( $ret["PARSED"] ) ){
  799.             for($i=0;$i<count($ret["PARSED"]); $i++){ $command=$ret["PARSED"][$i]["EXT"];
  800.                     $parsed[key($command)]=$command[key($command)];
  801.             }
  802.         }
  803.         return array("PARSED"=>$parsed,"RESPONSE"=>$ret["RESPONSE"]);
  804.     }
  805.  
  806.  
  807.  
  808.  
  809.  
  810.  
  811.  
  812.     /**
  813.      * Send the  CREATE Mailbox Command
  814.      *
  815.      * @param string The mailbox to create.
  816.      * @return array Returns an array containing the response
  817.      *
  818.      * @access public
  819.      * @since  1.0
  820.      */
  821.     function cmdCreate($mailbox)
  822.     {
  823.         $mailbox_name=sprintf("\"%s\"",$this->utf_7_encode($mailbox) );
  824.         return $this->_genericCommand('CREATE', $mailbox_name);
  825.     }
  826.  
  827.  
  828.  
  829.  
  830.  
  831.  
  832.  
  833.     /**
  834.      * Send the  RENAME Mailbox Command
  835.      *
  836.      * @param string The old mailbox name.
  837.      * @param string The new (renamed) mailbox name.
  838.      *
  839.      * @return array Returns an array containing the response
  840.      *
  841.      * @access public
  842.      * @since  1.0
  843.      */
  844.     function cmdRename($mailbox, $new_mailbox)
  845.     {
  846.         $mailbox_name=sprintf("\"%s\"",$this->utf_7_encode($mailbox) );
  847.         $new_mailbox_name=sprintf("\"%s\"",$this->utf_7_encode($new_mailbox) );
  848.         return $this->_genericCommand('RENAME', "$mailbox_name $new_mailbox_name" );
  849.     }
  850.  
  851.  
  852.  
  853.  
  854.  
  855.  
  856.  
  857.  
  858.     /**
  859.      * Send the  DELETE Mailbox Command
  860.      *
  861.      * @param string The mailbox name to delete.
  862.      *
  863.      * @return array Returns an array containing the response
  864.      *
  865.      * @access public
  866.      * @since  1.0
  867.      */
  868.     function cmdDelete($mailbox)
  869.     {
  870.         $mailbox_name=sprintf("\"%s\"",$this->utf_7_encode($mailbox) );
  871.         return $this->_genericCommand('DELETE', $mailbox_name);
  872.     }
  873.  
  874.  
  875.  
  876.  
  877.  
  878.  
  879.  
  880.     /**
  881.      * Send the  SUSCRIBE  Mailbox Command
  882.      *
  883.      * @param string The mailbox name to suscribe.
  884.      *
  885.      * @return array Returns an array containing the response
  886.      *
  887.      * @access public
  888.      * @since  1.0
  889.      */
  890.     function cmdSubscribe($mailbox)
  891.     {
  892.         $mailbox_name=sprintf("\"%s\"",$this->utf_7_encode($mailbox) );
  893.         return $this->_genericCommand('SUBSCRIBE', $mailbox_name );
  894.     }
  895.  
  896.  
  897.  
  898.  
  899.  
  900.  
  901.  
  902.  
  903.     /**
  904.      * Send the  UNSUSCRIBE  Mailbox Command
  905.      *
  906.      * @return mixed Returns a PEAR_Error with an error message on any
  907.      *               kind of failure, or true on success.
  908.      * @access public
  909.      * @since  1.0
  910.      */
  911.     function cmdUnsubscribe($mailbox)
  912.     {
  913.         $mailbox_name=sprintf("\"%s\"",$this->utf_7_encode($mailbox) );
  914.         return $this->_genericCommand('UNSUBSCRIBE', $mailbox_name );
  915.     }
  916.  
  917.  
  918.  
  919.  
  920.  
  921.  
  922.  
  923.  
  924.     /**
  925.      * Send the  FETCH Command
  926.      *
  927.      * @return mixed Returns a PEAR_Error with an error message on any
  928.      *               kind of failure, or true on success.
  929.      * @access public
  930.      * @since  1.0
  931.      */
  932.     function cmdFetch($msgset, $fetchparam)
  933.     {
  934.         return $this->_genericCommand('FETCH' , "$msgset $fetchparam" );
  935.     }
  936.  
  937.  
  938.  
  939.  
  940.  
  941.  
  942.  
  943.     /**
  944.      * Send the  CAPABILITY Command
  945.      *
  946.      * @return mixed Returns a PEAR_Error with an error message on any
  947.      *               kind of failure, or true on success.
  948.      * @access public
  949.      * @since  1.0
  950.      */
  951.     function cmdCapability()
  952.     {
  953.         $ret = $this->_genericCommand( 'CAPABILITY' );
  954.  
  955.         if(isset( $ret["PARSED"] ) ){
  956.             $ret["PARSED"]=$ret["PARSED"][0]["EXT"]["CAPABILITY"];
  957.             //fill the $this->_serverAuthMethods and $this->_serverSupportedCapabilities arrays
  958.             foreach( $ret["PARSED"]["CAPABILITIES"] as $auth_method ){
  959.                 if( strtoupper( substr( $auth_method , 0 ,5 ) ) == "AUTH=" )
  960.                     $this->_serverAuthMethods[] = substr( $auth_method , 5 );
  961.             }
  962.             // Keep the capabilities response to use ir later
  963.             $this->_serverSupportedCapabilities = $ret["PARSED"]["CAPABILITIES"];
  964.         }
  965.  
  966.         return $ret;
  967.     }
  968.  
  969.  
  970.  
  971.  
  972.  
  973.  
  974.  
  975.  
  976.  
  977.  
  978.     /**
  979.      * Send the  STATUS Mailbox Command
  980.      *
  981.      * @param string $mailbox the mailbox name
  982.      * @param string $request the request status it could be:
  983.      *              MESSAGES | RECENT | UIDNEXT
  984.      *              UIDVALIDITY | UNSEEN
  985.      * @return array Returns a Parsed Response
  986.      *
  987.      * @access public
  988.      * @since  1.0
  989.      */
  990.     function cmdStatus($mailbox, $request)
  991.     {
  992.  
  993.         $mailbox_name=sprintf("\"%s\"",$this->utf_7_encode($mailbox) );
  994.  
  995.         if( $request!="MESSAGES" && $request!="RECENT" && $request!="UIDNEXT" &&
  996.             $request!="UIDVALIDITY" && $request!="UNSEEN" ){
  997.             // TODO:  fix this error!
  998.             $this->_prot_error("request '$request' is invalid! see RFC2060!!!!" , __LINE__ , __FILE__, false );
  999.         }
  1000.         $ret = $this->_genericCommand('STATUS', "$mailbox_name ($request)" );
  1001.         if(isset( $ret["PARSED"] ) ){
  1002.             $ret['PARSED']=$ret["PARSED"][count($ret['PARSED'])-1]["EXT"];
  1003.         }
  1004.         return $ret;
  1005.     }
  1006.  
  1007.  
  1008.  
  1009.  
  1010.  
  1011.  
  1012.     /**
  1013.      * Send the  LIST  Command
  1014.      *
  1015.      * @return mixed Returns a PEAR_Error with an error message on any
  1016.      *               kind of failure, or true on success.
  1017.      * @access public
  1018.      * @since  1.0
  1019.      */
  1020.     function cmdList($mailbox_base, $mailbox)
  1021.     {
  1022.         $mailbox_name=sprintf("\"%s\"",$this->utf_7_encode($mailbox) );
  1023.         $mailbox_base=sprintf("\"%s\"",$this->utf_7_encode($mailbox_base) );
  1024.         return $this->_genericCommand('LIST', "$mailbox_base $mailbox_name" );
  1025.     }
  1026.  
  1027.  
  1028.  
  1029.  
  1030.  
  1031.  
  1032.     /**
  1033.      * Send the  LSUB  Command
  1034.      *
  1035.      * @return mixed Returns a PEAR_Error with an error message on any
  1036.      *               kind of failure, or true on success.
  1037.      * @access public
  1038.      * @since  1.0
  1039.      */
  1040.     function cmdLsub($mailbox_base, $mailbox)
  1041.     {
  1042.         $mailbox_name=sprintf("\"%s\"",$this->utf_7_encode($mailbox) );
  1043.         $mailbox_base=sprintf("\"%s\"",$this->utf_7_encode($mailbox_base) );
  1044.         return $this->_genericCommand('LSUB', "$mailbox_base $mailbox_name" );
  1045.     }
  1046.  
  1047.  
  1048.  
  1049.  
  1050.  
  1051.  
  1052.     /**
  1053.      * Send the  APPEND  Command
  1054.      *
  1055.      * @return mixed Returns a PEAR_Error with an error message on any
  1056.      *               kind of failure, or true on success.
  1057.      * @access public
  1058.      * @since  1.0
  1059.      */
  1060.     function cmdAppend($mailbox, $msg , $flags_list = '' ,$time = '')
  1061.     {
  1062.         if(!$this->_connected){
  1063.             return new PEAR_Error('not connected!');
  1064.         }
  1065.  
  1066.  
  1067.         $cmdid=$this->_getCmdId();
  1068.         $msg_size=strlen($msg);
  1069.  
  1070.         $mailbox_name=sprintf("\"%s\"",$this->utf_7_encode($mailbox) );
  1071.         // TODO:
  1072.         // Falta el codigo para que flags list y time hagan algo!!
  1073.         if( $this->hasCapability( "LITERAL+" ) == true ){
  1074.             $param=sprintf("%s %s%s{%s+}\r\n%s",$mailbox_name,$flags_list,$time,$msg_size,$msg);
  1075.             if (PEAR::isError($error = $this->_putCMD($cmdid , 'APPEND' , $param ) ) ) {
  1076.                 return $error;
  1077.             }
  1078.         }else{
  1079.             $param=sprintf("%s %s%s{%s}\r\n",$mailbox_name,$flags_list,$time,$msg_size);
  1080.             if (PEAR::isError($error = $this->_putCMD($cmdid , 'APPEND' , $param ) ) ) {
  1081.             return $error;
  1082.             }
  1083.             if (PEAR::isError($error = $this->_recvLn() ) ) {
  1084.             return $error;
  1085.             }
  1086.  
  1087.             if (PEAR::isError($error = $this->_send( $msg ) ) ) {
  1088.             return $error;
  1089.             }
  1090.         }
  1091.  
  1092.  
  1093.         $args=$this->_getRawResponse($cmdid);
  1094.         $ret = $this->_genericImapResponseParser($args,$cmdid);
  1095.         return $ret;
  1096.     }
  1097.  
  1098.  
  1099.  
  1100.     /**
  1101.      * Send the CLOSE command.
  1102.      *
  1103.      * @return mixed Returns a PEAR_Error with an error message on any
  1104.      *               kind of failure, or true on success.
  1105.      * @access public
  1106.      * @since  1.0
  1107.      */
  1108.     function cmdClose()
  1109.     {
  1110.         return $this->_genericCommand('CLOSE');
  1111.     }
  1112.  
  1113.  
  1114.  
  1115.  
  1116.  
  1117.  
  1118.     /**
  1119.      * Send the EXPUNGE command.
  1120.      *
  1121.      * @return mixed Returns a PEAR_Error with an error message on any
  1122.      *               kind of failure, or true on success.
  1123.      * @access public
  1124.      * @since  1.0
  1125.      */
  1126.     function cmdExpunge()
  1127.     {
  1128.         $ret=$this->_genericCommand('EXPUNGE');
  1129.  
  1130.         if(isset( $ret["PARSED"] ) ){
  1131.            $parsed=$ret["PARSED"];
  1132.             unset($ret["PARSED"]);
  1133.             foreach($parsed as $command){
  1134.                 if( strtoupper($command["COMMAND"]) == 'EXPUNGE' ){
  1135.                         $ret["PARSED"][$command["COMMAND"]][]=$command["NRO"];
  1136.                 }else{
  1137.                         $ret["PARSED"][$command["COMMAND"]]=$command["NRO"];
  1138.                 }
  1139.             }
  1140.         }
  1141.         return $ret;
  1142.     }
  1143.  
  1144.  
  1145.  
  1146.  
  1147.  
  1148.  
  1149.  
  1150.     /**
  1151.      * Send the SEARCH command.
  1152.      *
  1153.      * @return mixed Returns a PEAR_Error with an error message on any
  1154.      *               kind of failure, or true on success.
  1155.      * @access public
  1156.      * @since  1.0
  1157.      */
  1158.  
  1159.     function cmdSearch($search_cmd)
  1160.     {
  1161.         /*        if($_charset != '' )
  1162.                     $_charset = "[$_charset] ";
  1163.                 $param=sprintf("%s%s",$charset,$search_cmd);
  1164.         */
  1165.         $ret = $this->_genericCommand('SEARCH', $search_cmd );
  1166.         if(isset( $ret["PARSED"] ) ){
  1167.             $ret["PARSED"]=$ret["PARSED"][0]["EXT"];
  1168.         }
  1169.         return $ret;
  1170.     }
  1171.  
  1172.  
  1173.  
  1174.  
  1175.  
  1176.  
  1177.     /**
  1178.      * Send the STORE command.
  1179.      *
  1180.      * @param string $message_set  the sessage_set
  1181.      * @param string $dataitem: the way we store the flags
  1182.      *          FLAGS: replace the flags whith $value
  1183.      *          FLAGS.SILENT: replace the flags whith $value but don't return untagged responses
  1184.      *
  1185.      *          +FLAGS: Add the flags whith $value
  1186.      *          +FLAGS.SILENT: Add the flags whith $value but don't return untagged responses
  1187.      *
  1188.      *          -FLAGS: Remove the flags whith $value
  1189.      *          -FLAGS.SILENT: Remove the flags whith $value but don't return untagged responses
  1190.      *
  1191.      * @param string $value
  1192.      * @return mixed Returns a PEAR_Error with an error message on any
  1193.      *               kind of failure, or true on success.
  1194.      * @access public
  1195.      * @since  1.0
  1196.      */
  1197.  
  1198.     function cmdStore($message_set, $dataitem, $value)
  1199.     {
  1200.         /* As said in RFC2060...
  1201.         C: A003 STORE 2:4 +FLAGS (\Deleted)
  1202.         S: * 2 FETCH FLAGS (\Deleted \Seen)
  1203.         S: * 3 FETCH FLAGS (\Deleted)
  1204.         S: * 4 FETCH FLAGS (\Deleted \Flagged \Seen)
  1205.         S: A003 OK STORE completed
  1206.         */
  1207.         if( $dataitem!="FLAGS" && $dataitem!="FLAGS.SILENT" && $dataitem!="+FLAGS" &&
  1208.             $dataitem!="+FLAGS.SILENT" && $dataitem!="-FLAGS" && $dataitem!="-FLAGS.SILENT" ){
  1209.             $this->_prot_error("dataitem '$dataitem' is invalid! see RFC2060!!!!" , __LINE__ , __FILE__ );
  1210.         }
  1211.         $param=sprintf("%s %s (%s)",$message_set,$dataitem,$value);
  1212.         return $this->_genericCommand('STORE', $param );
  1213.     }
  1214.  
  1215.  
  1216.  
  1217.  
  1218.  
  1219.  
  1220.  
  1221.     /**
  1222.      * Send the COPY command.
  1223.      *
  1224.      * @return mixed Returns a PEAR_Error with an error message on any
  1225.      *               kind of failure, or true on success.
  1226.      * @access public
  1227.      * @since  1.0
  1228.      */
  1229.  
  1230.     function cmdCopy($message_set, $mailbox)
  1231.     {
  1232.         $mailbox_name=sprintf("\"%s\"",$this->utf_7_encode($mailbox) );
  1233.         return $this->_genericCommand('COPY', sprintf("%s %s",$message_set,$mailbox_name) );
  1234.     }
  1235.  
  1236.  
  1237.  
  1238.  
  1239.  
  1240.  
  1241.  
  1242.  
  1243.  
  1244.  
  1245.  
  1246.  
  1247.  
  1248.     function cmdUidFetch($msgset, $fetchparam)
  1249.     {
  1250.         return $this->_genericCommand('UID FETCH', sprintf("%s %s",$msgset,$fetchparam) );
  1251.     }
  1252.  
  1253.  
  1254.  
  1255.  
  1256.  
  1257.  
  1258.  
  1259.  
  1260.     function cmdUidCopy($message_set, $mailbox)
  1261.     {
  1262.         $mailbox_name=sprintf("\"%s\"",$this->utf_7_encode($mailbox) );
  1263.         return $this->_genericCommand('UID COPY', sprintf("%s %s",$message_set,$mailbox_name) );
  1264.     }
  1265.  
  1266.  
  1267.  
  1268.  
  1269.  
  1270.  
  1271.  
  1272.  
  1273.      /**
  1274.      * Send the UID STORE command.
  1275.      *
  1276.      * @param string $message_set  the sessage_set
  1277.      * @param string $dataitem: the way we store the flags
  1278.      *          FLAGS: replace the flags whith $value
  1279.      *          FLAGS.SILENT: replace the flags whith $value but don't return untagged responses
  1280.      *
  1281.      *          +FLAGS: Add the flags whith $value
  1282.      *          +FLAGS.SILENT: Add the flags whith $value but don't return untagged responses
  1283.      *
  1284.      *          -FLAGS: Remove the flags whith $value
  1285.      *          -FLAGS.SILENT: Remove the flags whith $value but don't return untagged responses
  1286.      *
  1287.      * @param string $value
  1288.      * @return mixed Returns a PEAR_Error with an error message on any
  1289.      *               kind of failure, or true on success.
  1290.      * @access public
  1291.      * @since  1.0
  1292.      */
  1293.  
  1294.     function cmdUidStore($message_set, $dataitem, $value)
  1295.     {
  1296.         /* As said in RFC2060...
  1297.         C: A003 STORE 2:4 +FLAGS (\Deleted)
  1298.         S: * 2 FETCH FLAGS (\Deleted \Seen)
  1299.         S: * 3 FETCH FLAGS (\Deleted)
  1300.         S: * 4 FETCH FLAGS (\Deleted \Flagged \Seen)
  1301.         S: A003 OK STORE completed
  1302.         */
  1303.         if( $dataitem!="FLAGS" && $dataitem!="FLAGS.SILENT" && $dataitem!="+FLAGS" &&
  1304.             $dataitem!="+FLAGS.SILENT" && $dataitem!="-FLAGS" && $dataitem!="-FLAGS.SILENT" ){
  1305.             $this->_prot_error("dataitem '$dataitem' is invalid! see RFC2060!!!!" , __LINE__ , __FILE__ );
  1306.         }
  1307.         return $this->_genericCommand('UID STORE', sprintf("%s %s (%s)",$message_set,$dataitem,$value) );
  1308.     }
  1309.  
  1310.  
  1311.  
  1312.  
  1313.  
  1314.  
  1315.  
  1316.  
  1317.  
  1318.  
  1319.     /**
  1320.      * Send the SEARCH command.
  1321.      *
  1322.      * @return mixed Returns a PEAR_Error with an error message on any
  1323.      *               kind of failure, or true on success.
  1324.      * @access public
  1325.      * @since  1.0
  1326.      */
  1327.  
  1328.     function cmdUidSearch($search_cmd)
  1329.     {
  1330.         $ret=$this->_genericCommand('UID SEARCH', sprintf("%s",$search_cmd) );
  1331.         if(isset( $ret["PARSED"] ) ){
  1332.             $ret["PARSED"]=$ret["PARSED"][0]["EXT"];
  1333.         }
  1334.         return $ret;
  1335.     }
  1336.  
  1337.  
  1338.  
  1339.  
  1340.  
  1341.  
  1342.  
  1343.  
  1344.  
  1345.  
  1346.  
  1347.     /**
  1348.      * Send the X command.
  1349.      *
  1350.      * @return mixed Returns a PEAR_Error with an error message on any
  1351.      *               kind of failure, or true on success.
  1352.      * @access public
  1353.      * @since  1.0
  1354.      */
  1355.  
  1356.     function cmdX($atom, $parameters)
  1357.     {
  1358.         return $this->_genericCommand("X$atom", $parameters );
  1359.     }
  1360.  
  1361.  
  1362.  
  1363.  
  1364.  
  1365.  
  1366.  
  1367.  
  1368. /********************************************************************
  1369. ***
  1370. ***             HERE ENDS the RFC2060 IMAPS FUNCTIONS
  1371. ***             AND BEGIN THE EXTENSIONS FUNCTIONS
  1372. ***
  1373. ********************************************************************/
  1374.  
  1375.  
  1376.  
  1377.  
  1378.  
  1379.  
  1380.  
  1381. /********************************************************************
  1382. ***             RFC2087 IMAP4 QUOTA extension BEGINS HERE
  1383. ********************************************************************/
  1384.  
  1385.  
  1386.     /**
  1387.      * Send the GETQUOTA command.
  1388.      *
  1389.      * @param string $mailbox_name the mailbox name to query for quota data
  1390.      * @return mixed Returns a PEAR_Error with an error message on any
  1391.      *               kind of failure, or quota data on success
  1392.      * @access public
  1393.      * @since  1.0
  1394.      */
  1395.  
  1396.     function cmdGetQuota($mailbox_name)
  1397.     {
  1398.  
  1399.  
  1400.         //Check if the IMAP server has QUOTA support
  1401.         if( ! $this->hasQuotaSupport() ){
  1402.             return new PEAR_Error("This IMAP server does not support QUOTA's! ");
  1403.         }
  1404.         $mailbox_name=sprintf("%s",$this->utf_7_encode($mailbox_name) );
  1405.         $ret = $this->_genericCommand('GETQUOTA', $mailbox_name );
  1406.         if(isset( $ret["PARSED"] ) ){
  1407.         // remove the array index because the quota response returns only 1 line of output
  1408.             $ret['PARSED']=$ret["PARSED"][0];
  1409.         }
  1410.         return $ret;
  1411.     }
  1412.  
  1413.  
  1414.     /**
  1415.      * Send the GETQUOTAROOT command.
  1416.      *
  1417.      * @param string $mailbox_name the mailbox name to query for quota data
  1418.      * @return mixed Returns a PEAR_Error with an error message on any
  1419.      *               kind of failure, or quota data on success
  1420.      * @access public
  1421.      * @since  1.0
  1422.      */
  1423.  
  1424.     function cmdGetQuotaRoot($mailbox_name)
  1425.     {
  1426.         //Check if the IMAP server has QUOTA support
  1427.         if( ! $this->hasQuotaSupport() ){
  1428.             return new PEAR_Error("This IMAP server does not support QUOTA's! ");
  1429.         }
  1430.         $mailbox_name=sprintf("%s",$this->utf_7_encode($mailbox_name) );
  1431.         $ret = $this->_genericCommand('GETQUOTAROOT', $mailbox_name );
  1432.  
  1433.         if(isset( $ret["PARSED"] ) ){
  1434.         // remove the array index because the quota response returns only 1 line of output
  1435.             $ret['PARSED']=$ret["PARSED"][0];
  1436.         }
  1437.         return $ret;
  1438.     }
  1439.  
  1440.  
  1441.  
  1442.  
  1443.     /**
  1444.      * Send the SETQUOTA command.
  1445.      *
  1446.      * @param string $mailbox_name the mailbox name to query for quota data
  1447.      * @param string $storageQuota sets the max number of bytes this mailbox can handle
  1448.      * @param string $messagesQuota sets the max number of messages this mailbox can handle
  1449.      * @return mixed Returns a PEAR_Error with an error message on any
  1450.      *               kind of failure, or quota data on success
  1451.      * @access public
  1452.      * @since  1.0
  1453.      */
  1454. // TODO:  implement the quota by number of emails!!
  1455.     function cmdSetQuota($mailbox_name, $storageQuota = null ,$messagesQuota = null )
  1456.     {
  1457.         //Check if the IMAP server has QUOTA support
  1458.         if( ! $this->hasQuotaSupport() ){
  1459.             return new PEAR_Error("This IMAP server does not support QUOTA's! ");
  1460.         }
  1461.  
  1462.         if( ($messagesQuota == null) && ( $storageQuota == null) ){
  1463.             return new PEAR_Error('$storageQuota and $messagesQuota parameters can\'t be both null if you want to use quota');
  1464.         }
  1465.         $mailbox_name=sprintf("\"%s\"",$this->utf_7_encode($mailbox_name) );
  1466.         //Make the command request
  1467.         $param=sprintf("%s (",$mailbox_name);
  1468.         if($storageQuota != null ){
  1469.             $param=sprintf("%sSTORAGE %s",$param,$storageQuota);
  1470.             if( $messagesQuota != null ){
  1471.                 //if we have both types of quota on the same call we must append an space between
  1472.                 // those parameters
  1473.                 $param=sprintf("%s ",$param);
  1474.             }
  1475.         }
  1476.         if($messagesQuota != null ){
  1477.             $param=sprintf("%sMESSAGES %s",$param,$messagesQuota);
  1478.  
  1479.         }
  1480.         $param=sprintf("%s)",$param);
  1481.  
  1482.         return $this->_genericCommand('SETQUOTA', $param );
  1483.     }
  1484.  
  1485.  
  1486.  
  1487.     /**
  1488.      * Send the SETQUOTAROOT command.
  1489.      *
  1490.      * @param string $mailbox_name the mailbox name to query for quota data
  1491.      * @param string $storageQuota sets the max number of bytes this mailbox can handle
  1492.      * @param string $messagesQuota sets the max number of messages this mailbox can handle
  1493.      * @return mixed Returns a PEAR_Error with an error message on any
  1494.      *               kind of failure, or quota data on success
  1495.      * @access public
  1496.      * @since  1.0
  1497.      */
  1498.     function cmdSetQuotaRoot($mailbox_name, $storageQuota = null ,$messagesQuota = null)
  1499.     {
  1500.         //Check if the IMAP server has QUOTA support
  1501.         if( ! $this->hasQuotaSupport() ){
  1502.             return new PEAR_Error("This IMAP server does not support QUOTA's! ");
  1503.         }
  1504.  
  1505.         if( ($messagesQuota == null) && ( $storageQuota == null) ){
  1506.             return new PEAR_Error('$storageQuota and $messagesQuota parameters can\'t be both null if you want to use quota');
  1507.         }
  1508.         $mailbox_name=sprintf("\"%s\"",$this->utf_7_encode($mailbox_name) );
  1509.         //Make the command request
  1510.         $param=sprintf("%s (",$mailbox_name);
  1511.         if($storageQuota != null ){
  1512.             $param=sprintf("%sSTORAGE %s",$param,$storageQuota);
  1513.             if( $messagesQuota != null ){
  1514.                 //if we have both types of quota on the same call we must append an space between
  1515.                 // those parameters
  1516.                 $param=sprintf("%s ",$param);
  1517.             }
  1518.         }
  1519.         if($messagesQuota != null ){
  1520.             $param=sprintf("%sMESSAGES %s",$param,$messagesQuota);
  1521.  
  1522.         }
  1523.         $param=sprintf("%s)",$param);
  1524.  
  1525.         return $this->_genericCommand('SETQUOTAROOT', $param );
  1526.     }
  1527.  
  1528.  
  1529.  
  1530. /********************************************************************
  1531. ***             RFC2087 IMAP4 QUOTA extension ENDS HERE
  1532. ********************************************************************/
  1533.  
  1534.  
  1535.  
  1536.  
  1537.  
  1538.  
  1539. /********************************************************************
  1540. ***             RFC2086 IMAP4 ACL extension BEGINS HERE
  1541. ********************************************************************/
  1542.  
  1543.  
  1544.  
  1545.  
  1546.     function cmdSetACL($mailbox_name, $user, $acl)
  1547.     {
  1548.  
  1549.         //Check if the IMAP server has ACL support
  1550.         if( ! $this->hasAclSupport() ){
  1551.             return new PEAR_Error("This IMAP server does not support ACL's! ");
  1552.         }
  1553.         $mailbox_name=sprintf("\"%s\"",$this->utf_7_encode($mailbox_name) );
  1554.         $user_name=sprintf("\"%s\"",$this->utf_7_encode($user) );
  1555.         if(is_array($acl)){
  1556.             $acl=implode('',$acl);
  1557.         }
  1558.         return $this->_genericCommand('SETACL', sprintf("%s %s \"%s\"",$mailbox_name,$user_name,$acl) );
  1559.     }
  1560.  
  1561.  
  1562.  
  1563.  
  1564.  
  1565.  
  1566.     function cmdDeleteACL($mailbox_name, $user)
  1567.     {
  1568.         //Check if the IMAP server has ACL support
  1569.         if( ! $this->hasAclSupport() ){
  1570.             return new PEAR_Error("This IMAP server does not support ACL's! ");
  1571.         }
  1572.         $mailbox_name=sprintf("\"%s\"",$this->utf_7_encode($mailbox_name) );
  1573.         
  1574.         return $this->_genericCommand('DELETEACL', sprintf("%s \"%s\"",$mailbox_name,$user) );
  1575.     }
  1576.  
  1577.  
  1578.  
  1579.  
  1580.  
  1581.  
  1582.  
  1583.  
  1584.  
  1585.     function cmdGetACL($mailbox_name)
  1586.     {
  1587.         //Check if the IMAP server has ACL support
  1588.         if( ! $this->hasAclSupport() ){
  1589.             return new PEAR_Error("This IMAP server does not support ACL's! ");
  1590.         }
  1591.         $mailbox_name=sprintf("\"%s\"",$this->utf_7_encode($mailbox_name) );
  1592.         $ret = $this->_genericCommand('GETACL', sprintf("%s",$mailbox_name) );
  1593.         if(isset( $ret["PARSED"] ) ){
  1594.             $ret['PARSED']=$ret["PARSED"][0]["EXT"];
  1595.  
  1596.         }
  1597.         return $ret;
  1598.    }
  1599.  
  1600.  
  1601.  
  1602.  
  1603.  
  1604.  
  1605.  
  1606.     function cmdListRights($mailbox_name, $user)
  1607.     {
  1608.         //Check if the IMAP server has ACL support
  1609.         if( ! $this->hasAclSupport() ){
  1610.             return new PEAR_Error("This IMAP server does not support ACL's! ");
  1611.         }
  1612.         $mailbox_name=sprintf("\"%s\"",$this->utf_7_encode($mailbox_name) );
  1613.         $ret = $this->_genericCommand('LISTRIGHTS', sprintf("%s \"%s\"",$mailbox_name,$user) );
  1614.         if(isset( $ret["PARSED"] ) ){
  1615.             $ret["PARSED"]=$ret["PARSED"][0]["EXT"];
  1616.         }
  1617.         return $ret;
  1618.     }
  1619.  
  1620.  
  1621.  
  1622.  
  1623.  
  1624.  
  1625.  
  1626.  
  1627.  
  1628.     function cmdMyRights($mailbox_name)
  1629.     {
  1630.         //Check if the IMAP server has ACL support
  1631.         if( ! $this->hasAclSupport() ){
  1632.             return new PEAR_Error("This IMAP server does not support ACL's! ");
  1633.         }
  1634.         $mailbox_name=sprintf("\"%s\"",$this->utf_7_encode($mailbox_name) );
  1635.         $ret = $this->_genericCommand('MYRIGHTS', sprintf("%s",$mailbox_name) );
  1636.         if(isset( $ret["PARSED"] ) ){
  1637.             $ret["PARSED"]=$ret["PARSED"][0]["EXT"];
  1638.         }
  1639.         return $ret;
  1640.     }
  1641.  
  1642.  
  1643. /********************************************************************
  1644. ***             RFC2086 IMAP4 ACL extension ENDs HERE
  1645. ********************************************************************/
  1646.  
  1647.  
  1648.  
  1649.  
  1650.  
  1651.  
  1652.  
  1653.  
  1654.  
  1655.  
  1656.  
  1657.  
  1658. /*******************************************************************************
  1659. ***  draft-daboo-imap-annotatemore-05 IMAP4 ANNOTATEMORE extension BEGINS HERE
  1660. ********************************************************************************/
  1661.  
  1662.  
  1663.  
  1664.     function cmdSetAnnotation($mailbox_name, $entry, $values)
  1665.     {
  1666.         // Check if the IMAP server has ANNOTATEMORE support
  1667.         if(!$this->hasAnnotateMoreSupport()) {
  1668.             return new PEAR_Error('This IMAP server does not support the ANNOTATEMORE extension!');
  1669.         }
  1670.         if (!is_array($values)) {
  1671.             return new PEAR_Error('Invalid $values argument passed to cmdSetAnnotation');
  1672.         }
  1673.  
  1674.         $vallist = '';
  1675.         foreach ($values as $name => $value) {
  1676.             $vallist .= "\"$name\" \"$value\" ";
  1677.         }
  1678.         $vallist = rtrim($vallist);
  1679.  
  1680.         return $this->_genericCommand('SETANNOTATION', sprintf('"%s" "%s" (%s)', $mailbox_name, $entry, $vallist));
  1681.     }
  1682.  
  1683.  
  1684.  
  1685.  
  1686.  
  1687.  
  1688.  
  1689.  
  1690.  
  1691.  
  1692.  
  1693.  
  1694.  
  1695.     function cmdDeleteAnnotation($mailbox_name, $entry, $values)
  1696.     {
  1697.         // Check if the IMAP server has ANNOTATEMORE support
  1698.         if(!$this->hasAnnotateMoreSupport()) {
  1699.             return new PEAR_Error('This IMAP server does not support the ANNOTATEMORE extension!');
  1700.         }
  1701.         if (!is_array($values)) {
  1702.             return new PEAR_Error('Invalid $values argument passed to cmdDeleteAnnotation');
  1703.         }
  1704.  
  1705.         $vallist = '';
  1706.         foreach ($values as $name) {
  1707.             $vallist .= "\"$name\" NIL ";
  1708.         }
  1709.         $vallist = rtrim($vallist);
  1710.  
  1711.         return $this->_genericCommand('SETANNOTATION', sprintf('"%s" "%s" (%s)', $mailbox_name, $entry, $vallist));
  1712.     }
  1713.  
  1714.  
  1715.  
  1716.  
  1717.  
  1718.  
  1719.  
  1720.  
  1721.  
  1722.  
  1723.  
  1724.  
  1725.     function cmdGetAnnotation($mailbox_name, $entries, $values)
  1726.     {
  1727.         // Check if the IMAP server has ANNOTATEMORE support
  1728.         if(!$this->hasAnnotateMoreSupport()) {
  1729.             return new PEAR_Error('This IMAP server does not support the ANNOTATEMORE extension!');
  1730.         }
  1731.  
  1732.         $entlist = '';
  1733.  
  1734.        if (!is_array($entries)) {
  1735.             $entries = array($entries);
  1736.        }
  1737.  
  1738.         foreach ($entries as $name) {
  1739.             $entlist .= "\"$name\" ";
  1740.         }
  1741.         $entlist = rtrim($entlist);
  1742.         if (count($entries) > 1) {
  1743.             $entlist = "($entlist)";
  1744.         }
  1745.  
  1746.  
  1747.  
  1748.         $vallist = '';
  1749.         if (!is_array($values)) {
  1750.             $values = array($values);
  1751.         }
  1752.  
  1753.         foreach ($values as $name) {
  1754.             $vallist .= "\"$name\" ";
  1755.         }
  1756.         $vallist = rtrim($vallist);
  1757.         if (count($values) > 1) {
  1758.             $vallist = "($vallist)";
  1759.         }
  1760.  
  1761.         return $this->_genericCommand('GETANNOTATION', sprintf('"%s" %s %s', $mailbox_name, $entlist, $vallist));
  1762.    }
  1763.  
  1764.  
  1765. /*****************************************************************************
  1766. ***  draft-daboo-imap-annotatemore-05 IMAP4 ANNOTATEMORE extension ENDs HERE
  1767. ******************************************************************************/
  1768.  
  1769.  
  1770.  
  1771.  
  1772.  
  1773.  
  1774.  
  1775. /********************************************************************
  1776. ***
  1777. ***             HERE ENDS THE EXTENSIONS FUNCTIONS
  1778. ***             AND BEGIN THE AUXILIARY FUNCTIONS
  1779. ***
  1780. ********************************************************************/
  1781.  
  1782.  
  1783.  
  1784.  
  1785.  
  1786.     /**
  1787.     * tell if the server has capability $capability
  1788.     *
  1789.     * @return true or false
  1790.     *
  1791.     * @access public
  1792.     * @since  1.0
  1793.     */
  1794.     function getServerAuthMethods()
  1795.     {
  1796.         if( $this->_serverAuthMethods == null ){
  1797.             $this->cmdCapability();
  1798.             return $this->_serverAuthMethods;
  1799.         }
  1800.         return false;
  1801.     }
  1802.  
  1803.  
  1804.  
  1805.  
  1806.  
  1807.  
  1808.  
  1809.     /**
  1810.     * tell if the server has capability $capability
  1811.     *
  1812.     * @return true or false
  1813.     *
  1814.     * @access public
  1815.     * @since  1.0
  1816.     */
  1817.     function hasCapability($capability)
  1818.     {
  1819.         if( $this->_serverSupportedCapabilities == null ){
  1820.             $this->cmdCapability();
  1821.         }
  1822.         if($this->_serverSupportedCapabilities != null ){
  1823.             if( in_array( $capability , $this->_serverSupportedCapabilities ) ){
  1824.                 return true;
  1825.             }
  1826.         }
  1827.         return false;
  1828.     }
  1829.  
  1830.  
  1831.  
  1832.     /**
  1833.     * tell if the server has Quota support
  1834.     *
  1835.     * @return true or false
  1836.     *
  1837.     * @access public
  1838.     * @since  1.0
  1839.     */
  1840.     function hasQuotaSupport()
  1841.     {
  1842.         return $this->hasCapability('QUOTA');
  1843.     }
  1844.  
  1845.  
  1846.  
  1847.  
  1848.  
  1849.     /**
  1850.     * tell if the server has Quota support
  1851.     *
  1852.     * @return true or false
  1853.     *
  1854.     * @access public
  1855.     * @since  1.0
  1856.     */
  1857.     function hasAclSupport()
  1858.     {
  1859.         return $this->hasCapability('ACL');
  1860.     }
  1861.  
  1862.  
  1863.  
  1864.  
  1865.  
  1866.     /**
  1867.     * tell if the server has support for the ANNOTATEMORE extension
  1868.     *
  1869.     * @return true or false
  1870.     *
  1871.     * @access public
  1872.     * @since  1.0
  1873.     */
  1874.     function hasAnnotateMoreSupport()
  1875.     {
  1876.         return $this->hasCapability('ANNOTATEMORE');
  1877.     }
  1878.  
  1879.  
  1880.  
  1881.  
  1882.  
  1883.  
  1884.  
  1885.  
  1886.  
  1887.  
  1888.     /**
  1889.     * Parses the responses like RFC822.SIZE and INTERNALDATE
  1890.     *
  1891.     * @param string the IMAP's server response
  1892.     *
  1893.     * @return string containing  the parsed response
  1894.     * @access private
  1895.     * @since  1.0
  1896.     */
  1897.  
  1898.     function _parseOneStringResponse(&$str, $line,$file)
  1899.     {
  1900.         $this->_parseSpace($str , $line , $file );
  1901.         $size = $this->_getNextToken($str,$uid);
  1902.         return $uid;
  1903.     }
  1904.  
  1905.  
  1906.     /**
  1907.     * Parses the FLAG response
  1908.     *
  1909.     * @param string the IMAP's server response
  1910.     *
  1911.     * @return Array containing  the parsed  response
  1912.     * @access private
  1913.     * @since  1.0
  1914.     */
  1915.     function _parseFLAGSresponse(&$str)
  1916.     {
  1917.         $this->_parseSpace($str , __LINE__ , __FILE__ );
  1918.         $params_arr[] = $this->_arrayfy_content($str);
  1919.         $flags_arr=array();
  1920.         for( $i = 0 ; $i < count($params_arr[0]) ; $i++ ){
  1921.             $flags_arr[] = $params_arr[0][$i];
  1922.         }
  1923.         return $flags_arr;
  1924.     }
  1925.  
  1926.  
  1927.  
  1928.  
  1929.  
  1930.     /**
  1931.     * Parses the BODY response
  1932.     *
  1933.     * @param string the IMAP's server response
  1934.     *
  1935.     * @return Array containing  the parsed  response
  1936.     * @access private
  1937.     * @since  1.0
  1938.     */
  1939.  
  1940.     function _parseBodyResponse(&$str, $command){
  1941.  
  1942.             $this->_parseSpace($str , __LINE__ , __FILE__ );
  1943.             while($str[0] != ')' && $str!=''){
  1944.                 $params_arr[] = $this->_arrayfy_content($str);
  1945.             }
  1946.  
  1947.             return $params_arr;
  1948.     }
  1949.  
  1950.  
  1951.  
  1952.  
  1953.  
  1954.  
  1955.     /**
  1956.     * Makes the content an Array
  1957.     *
  1958.     * @param string the IMAP's server response
  1959.     *
  1960.     * @return Array containing  the parsed  response
  1961.     * @access private
  1962.     * @since  1.0
  1963.     */
  1964.     function _arrayfy_content(&$str)
  1965.     {
  1966.         $params_arr=array();
  1967.         $this->_getNextToken($str,$params);
  1968.         if($params != '(' ){
  1969.             return $params;
  1970.         }
  1971.         $this->_getNextToken($str,$params,false,false);
  1972.         while ( $str != '' && $params != ')'){
  1973.                 if($params != '' ){
  1974.                     if($params[0] == '(' ){
  1975.                         $params=$this->_arrayfy_content( $params );
  1976.                     }
  1977.                     if($params != ' ' ){
  1978.                         //I don't remove the colons (") to handle the case of retriving " "
  1979.                         // If I remove the colons the parser will interpret this field as an imap separator (space)
  1980.                         // instead of a valid field so I remove the colons here
  1981.                         if($params=='""'){
  1982.                             $params='';
  1983.                         }else{
  1984.                             if($params[0]=='"'){
  1985.                                 $params=substr($params,1,strlen($params)-2);
  1986.                             }
  1987.                         }
  1988.                         $params_arr[]=$params;
  1989.                     }
  1990.                 }else{
  1991.                     //if params if empty (for example i'm parsing 2 quotes ("")
  1992.                     // I'll append an array entry to mantain compatibility
  1993.                     $params_arr[]=$params;
  1994.                 }
  1995.                 $this->_getNextToken($str,$params,false,false);
  1996.         }
  1997.         return $params_arr;
  1998.     }
  1999.  
  2000.  
  2001.  
  2002.  
  2003.     /**
  2004.     * Parses the BODY[],BODY[TEXT],.... responses
  2005.     *
  2006.     * @param string the IMAP's server response
  2007.     *
  2008.     * @return Array containing  the parsed  response
  2009.     * @access private
  2010.     * @since  1.0
  2011.     */
  2012.     function _parseContentresponse(&$str, $command)
  2013.     {
  2014.         $content = '';
  2015.         $this->_parseSpace($str , __LINE__ , __FILE__ );
  2016.         $size  =$this->_getNextToken($str,$content);
  2017.         return array( "CONTENT"=> $content , "CONTENT_SIZE" =>$size );
  2018.     }
  2019.  
  2020.  
  2021.  
  2022.  
  2023.  
  2024.  
  2025.  
  2026.  
  2027.     /**
  2028.     * Parses the ENVELOPE response
  2029.     *
  2030.     * @param string the IMAP's server response
  2031.     *
  2032.     * @return Array containing  the parsed  response
  2033.     * @access private
  2034.     * @since  1.0
  2035.     */
  2036.     function _parseENVELOPEresponse(&$str)
  2037.     {
  2038.         $content = '';
  2039.         $this->_parseSpace($str , __LINE__ , __FILE__ );
  2040.  
  2041.         $this->_getNextToken($str,$parenthesis);
  2042.         if( $parenthesis != '(' ){
  2043.                 $this->_prot_error("must be a '(' but is a '$parenthesis' !!!!" , __LINE__ , __FILE__ );
  2044.         }
  2045.         // Get the email's Date
  2046.         $this->_getNextToken($str,$date);
  2047.  
  2048.         $this->_parseSpace($str , __LINE__ , __FILE__ );
  2049.  
  2050.         // Get the email's Subject:
  2051.         $this->_getNextToken($str,$subject);
  2052.         //$subject=$this->decode($subject);
  2053.  
  2054.         $this->_parseSpace($str , __LINE__ , __FILE__ );
  2055.  
  2056.         //FROM LIST;
  2057.         $from_arr = $this->_getAddressList($str);
  2058.  
  2059.         $this->_parseSpace($str , __LINE__ , __FILE__ );
  2060.  
  2061.         //"SENDER LIST\n";
  2062.         $sender_arr = $this->_getAddressList($str);
  2063.  
  2064.         $this->_parseSpace($str , __LINE__ , __FILE__ );
  2065.  
  2066.         //"REPLY-TO LIST\n";
  2067.         $reply_to_arr=$this->_getAddressList($str);
  2068.  
  2069.         $this->_parseSpace($str , __LINE__ , __FILE__ );
  2070.  
  2071.         //"TO LIST\n";
  2072.         $to_arr = $this->_getAddressList($str);
  2073.  
  2074.         $this->_parseSpace($str , __LINE__ , __FILE__ );
  2075.  
  2076.         //"CC LIST\n";
  2077.         $cc_arr = $this->_getAddressList($str);
  2078.  
  2079.         $this->_parseSpace($str , __LINE__ , __FILE__ );
  2080.  
  2081.         //"BCC LIST|$str|\n";
  2082.         $bcc_arr = $this->_getAddressList($str);
  2083.  
  2084.         $this->_parseSpace($str , __LINE__ , __FILE__ );
  2085.  
  2086.         $this->_getNextToken($str,$in_reply_to);
  2087.  
  2088.         $this->_parseSpace($str , __LINE__ , __FILE__ );
  2089.  
  2090.         $this->_getNextToken($str,$message_id);
  2091.  
  2092.         $this->_getNextToken($str,$parenthesis);
  2093.  
  2094.         if( $parenthesis != ')' ){
  2095.             $this->_prot_error("must be a ')' but is a '$parenthesis' !!!!" , __LINE__ , __FILE__ );
  2096.         }
  2097.  
  2098.         return array( "DATE"=> $date , "SUBJECT" => $subject,"FROM" => $from_arr,
  2099.             "SENDER" => $sender_arr , "REPLY_TO" => $reply_to_arr, "TO" => $to_arr,
  2100.             "CC" =>$cc_arr, "BCC"=> $bcc_arr, "IN_REPLY_TO" =>$in_reply_to, "MESSAGE_ID"=>$message_id  );
  2101.     }
  2102.  
  2103.  
  2104.  
  2105.  
  2106.  
  2107.     /**
  2108.     * Parses the ARRDLIST as defined in RFC
  2109.     *
  2110.     * @param string the IMAP's server response
  2111.     *
  2112.     * @return Array containing  the parsed  response
  2113.     * @access private
  2114.     * @since  1.0
  2115.     */
  2116.     function _getAddressList(&$str)
  2117.     {
  2118.         $params_arr = $this->_arrayfy_content($str);
  2119.         if( !isset( $params_arr ) ){
  2120.             return $params_arr;
  2121.         }
  2122.  
  2123.  
  2124.         if( is_array($params_arr) ){
  2125.             $personal_name  = $params_arr[0][0];
  2126.             $at_domain_list = $params_arr[0][1];
  2127.             $mailbox_name   = $params_arr[0][2];
  2128.             $host_name      = $params_arr[0][3];
  2129.             if( $mailbox_name!='' && $host_name!='' ){
  2130.                 $email=$mailbox_name . "@" . $host_name;
  2131.             }else{
  2132.                 $email=false;
  2133.             }
  2134.             if($email==false){
  2135.                 $rfc822_email=false;
  2136.             }else{
  2137.                 if(!isset($personal_name)){
  2138.                     $rfc822_email= "<". $email . ">";
  2139.                 }else{
  2140.                     $rfc822_email= "\"". $personal_name ."\" <". $email . ">";
  2141.                 }
  2142.             }
  2143.             $email_arr[] = array ( "PERSONAL_NAME"=> $personal_name , "AT_DOMAIN_LIST"=>$at_domain_list ,
  2144.                                    "MAILBOX_NAME"=> $this->utf_7_decode($mailbox_name), "HOST_NAME"=> $host_name,
  2145.                                    "EMAIL"=>$email , "RFC822_EMAIL" => $rfc822_email );
  2146.             return $email_arr;
  2147.         }
  2148.  
  2149.         return array();
  2150.     }
  2151.  
  2152.  
  2153.  
  2154.  
  2155.  
  2156.  
  2157.  
  2158.     /**
  2159.     * Utility funcion to find the closing parenthesis ")" Position it takes care of quoted ones
  2160.     *
  2161.     * @param string the IMAP's server response
  2162.     *
  2163.     * @return int containing  the pos of the closing parenthesis ")"
  2164.     * @access private
  2165.     * @since  1.0
  2166.     */
  2167.     function _getClosingBracesPos($str_line, $startDelim ='(', $stopDelim = ')' )
  2168.     {
  2169.         $len = strlen( $str_line );
  2170.         $pos = 0;
  2171.         // ignore all extra characters
  2172.         // If inside of a string, skip string -- Boundary IDs and other
  2173.         // things can have ) in them.
  2174.         if ( $str_line[$pos] != $startDelim ) {
  2175.             $this->_prot_error("_getClosingParenthesisPos: must start with a '(' but is a '". $str_line[$pos] ."'!!!!\n" .
  2176.                 "STR_LINE:$str_line|size:$len|POS: $pos\n" , __LINE__ , __FILE__ );
  2177.             return( $len );
  2178.         }
  2179.         for( $pos = 1 ; $pos < $len ; $pos++ ){
  2180.             if ($str_line[$pos] == $stopDelim ) {
  2181.                 break;
  2182.             }
  2183.             if ($str_line[$pos] == '"') {
  2184.                 $pos++;
  2185.                 while ( $str_line[$pos] != '"' && $pos < $len ) {
  2186.                     if ($str_line[$pos] == "\\" && $str_line[$pos + 1 ] == '"' )
  2187.                         $pos++;
  2188.                     if ($str_line[$pos] == "\\" && $str_line[$pos + 1 ] == "\\" )
  2189.                         $pos++;
  2190.                     $pos++;
  2191.                 }
  2192.             }
  2193.             if ( $str_line[$pos] == $startDelim ) {
  2194.                 $str_line_aux = substr( $str_line , $pos );
  2195.                 $pos_aux = $this->_getClosingBracesPos( $str_line_aux );
  2196.                 $pos+=$pos_aux;
  2197.             }
  2198.         }
  2199.         if( $str_line[$pos] != $stopDelim ){
  2200.             $this->_prot_error("_getClosingBracesPos: must be a $stopDelim but is a '". $str_line[$pos] ."'|POS:$pos|STR_LINE:$str_line!!!!" , __LINE__ , __FILE__ );
  2201.         }
  2202.  
  2203.         if( $pos >= $len )
  2204.             return false;
  2205.         return $pos;
  2206.     }
  2207.  
  2208.  
  2209.  
  2210.  
  2211.  
  2212.  
  2213.     /**
  2214.     * Utility funcion to get from here to the end of the line
  2215.     *
  2216.     * @param string the IMAP's server response
  2217.     *
  2218.     * @return string containing  the string to the end of the line
  2219.     * @access private
  2220.     * @since  1.0
  2221.     */
  2222.  
  2223.     function _getToEOL(&$str , $including = true)
  2224.     {
  2225.         $len = strlen( $str );
  2226.         if( $including ){
  2227.             for($i=0;$i<$len;$i++){
  2228.                 if( $str[$i] =="\n" )
  2229.                     break;
  2230.             }
  2231.             $content=substr($str,0,$i + 1);
  2232.             $str=substr($str,$i + 1);
  2233.             return $content;
  2234.  
  2235.         }else{
  2236.             for( $i = 0 ; $i < $len ; $i++ ){
  2237.                 if( $str[$i] =="\n" || $str[$i] == "\r")
  2238.                     break;
  2239.             }
  2240.             $content = substr( $str ,0 , $i );
  2241.             $str = substr( $str , $i );
  2242.             return $content;
  2243.         }
  2244.     }
  2245.  
  2246.  
  2247.  
  2248.  
  2249.     /**
  2250.     * Fetches the next IMAP token or parenthesis
  2251.     *
  2252.     * @param string the IMAP's server response
  2253.     * @param string the next token
  2254.     * @param boolean true: the parenthesis IS a token, false: I consider
  2255.     *        all the response in parenthesis as a token
  2256.     *
  2257.     * @return int containing  the content size
  2258.     * @access private
  2259.     * @since  1.0
  2260.     */
  2261.  
  2262.  
  2263.     function _getNextToken(&$str, &$content, $parenthesisIsToken=true,$colonIsToken=true){
  2264.         $len = strlen($str);
  2265.         $pos = 0;
  2266.         $content_size = false;
  2267.         $content = false;
  2268.         if($str == '' || $len < 2 ){
  2269.             $content=$str;
  2270.             return $len;
  2271.         }
  2272.         switch( $str[0] ){
  2273.         case '{':
  2274.             if( ($posClosingBraces = $this->_getClosingBracesPos($str, '{' , '}' )) == false ){
  2275.                 $this->_prot_error("_getClosingBracesPos() error!!!" , __LINE__ , __FILE__ );
  2276.             }
  2277.             if(! is_numeric( ( $strBytes = substr( $str , 1 , $posClosingBraces - 1) ) ) ){
  2278.                 $this->_prot_error("must be a number but is a '" . $strBytes ."'!!!!" , __LINE__ , __FILE__ );
  2279.             }
  2280.             if( $str[$posClosingBraces] != '}' ){
  2281.                 $this->_prot_error("must be a '}'  but is a '" . $str[$posClosingBraces] ."'!!!!" , __LINE__ , __FILE__ );
  2282.             }
  2283.             if( $str[$posClosingBraces + 1] != "\r" ){
  2284.                 $this->_prot_error("must be a '\\r'  but is a '" . $str[$posClosingBraces + 1] ."'!!!!" , __LINE__ , __FILE__ );
  2285.             }
  2286.             if( $str[$posClosingBraces + 2] != "\n" ){
  2287.                 $this->_prot_error("must be a '\\n'  but is a '" . $str[$posClosingBraces + 2] ."'!!!!" , __LINE__ , __FILE__ );
  2288.             }
  2289.             $content = substr( $str , $posClosingBraces + 3 , $strBytes );
  2290.             if( strlen( $content ) != $strBytes ){
  2291.                 $this->_prot_error("content size is ". strlen($content) . " but the string reports a size of $strBytes!!!\n" , __LINE__ , __FILE__ );
  2292.             }
  2293.             $content_size = $strBytes;
  2294.             //Advance the string
  2295.             $str = substr( $str , $posClosingBraces + $strBytes + 3 );
  2296.             break;
  2297.         case '"':
  2298.             if($colonIsToken){
  2299.                 for($pos=1;$pos<$len;$pos++){
  2300.                     if ( $str[$pos] == "\"" ) {
  2301.                         break;
  2302.                     }
  2303.                     if ($str[$pos] == "\\" && $str[$pos + 1 ] == "\"" )
  2304.                         $pos++;
  2305.                     if ($str[$pos] == "\\" && $str[$pos + 1 ] == "\\" )
  2306.                         $pos++;
  2307.                 }
  2308.                 if($str[$pos] != '"' ){
  2309.                     $this->_prot_error("must be a '\"'  but is a '" . $str[$pos] ."'!!!!" , __LINE__ , __FILE__ );
  2310.                 }
  2311.                 $content_size = $pos;
  2312.                 $content = substr( $str , 1 , $pos - 1 );
  2313.                 //Advance the string
  2314.                 $str = substr( $str , $pos + 1 );
  2315.             }else{
  2316.                 for($pos=1;$pos<$len;$pos++){
  2317.                     if ( $str[$pos] == "\"" ) {
  2318.                         break;
  2319.                     }
  2320.                     if ($str[$pos] == "\\" && $str[$pos + 1 ] == "\"" )
  2321.                         $pos++;
  2322.                     if ($str[$pos] == "\\" && $str[$pos + 1 ] == "\\" )
  2323.                         $pos++;
  2324.                 }
  2325.                 if($str[$pos] != '"' ){
  2326.                     $this->_prot_error("must be a '\"'  but is a '" . $str[$pos] ."'!!!!" , __LINE__ , __FILE__ );
  2327.                 }
  2328.                 $content_size = $pos;
  2329.                 $content = substr( $str , 0 , $pos + 1 );
  2330.                 //Advance the string
  2331.                 $str = substr( $str , $pos + 1 );
  2332.  
  2333.             }
  2334.             break;
  2335.  
  2336.         case "\r":
  2337.             $pos = 1;
  2338.             if( $str[1] == "\n")
  2339.                 $pos++;
  2340.             $content_size = $pos;
  2341.             $content = substr( $str , 0 , $pos );
  2342.             $str = substr( $str , $pos );
  2343.             break;
  2344.         case "\n":
  2345.             $pos = 1;
  2346.             $content_size = $pos;
  2347.             $content = substr( $str , 0 , $pos );
  2348.             $str = substr( $str , $pos );
  2349.             break;
  2350.         case '(':
  2351.             if( $parenthesisIsToken == false ){
  2352.                 $pos = $this->_getClosingBracesPos( $str );
  2353.                 $content_size = $pos + 1;
  2354.                 $content = substr( $str , 0 , $pos + 1 );
  2355.                 $str = substr( $str , $pos + 1 );
  2356.             }else{
  2357.                 $pos = 1;
  2358.                 $content_size = $pos;
  2359.                 $content = substr( $str , 0 , $pos );
  2360.                 $str = substr( $str , $pos );
  2361.             }
  2362.             break;
  2363.         case ')':
  2364.             $pos = 1;
  2365.             $content_size = $pos;
  2366.             $content = substr( $str , 0 , $pos );
  2367.             $str = substr( $str , $pos );
  2368.             break;
  2369.         case ' ':
  2370.             $pos = 1;
  2371.             $content_size = $pos;
  2372.             $content = substr( $str , 0 , $pos );
  2373.             $str = substr( $str , $pos );
  2374.             break;
  2375.         default:
  2376.             for( $pos = 0 ; $pos < $len ; $pos++ ){
  2377.                 if ( $str[$pos] == ' ' || $str[$pos] == "\r" || $str[$pos] == ')' || $str[$pos] == '(' || $str[$pos] == "\n" ) {
  2378.                     break;
  2379.                 }
  2380.                 if ( $str[$pos] == "\\" && $str[$pos + 1 ] == ' '  )
  2381.                     $pos++;
  2382.                 if ( $str[$pos] == "\\" && $str[$pos + 1 ] == "\\" )
  2383.                     $pos++;
  2384.             }
  2385.             //Advance the string
  2386.             if( $pos == 0 ){
  2387.                 $content_size = 1;
  2388.                 $content = substr( $str , 0 , 1 );
  2389.                 $str = substr( $str , 1 );
  2390.             }else{
  2391.                 $content_size = $pos;
  2392.                 $content = substr( $str , 0 , $pos );
  2393.                 if($pos < $len){
  2394.                     $str = substr( $str , $pos  );
  2395.                 }else{
  2396.                 //if this is the end of the string... exit the switch
  2397.                     break;
  2398.                 }
  2399.  
  2400.  
  2401.             }
  2402.             break;
  2403.         }
  2404.         return $content_size;
  2405.     }
  2406.  
  2407.  
  2408.  
  2409.  
  2410.  
  2411.  
  2412.     /**
  2413.     * Utility funcion to display to console the protocol errors
  2414.     *
  2415.     * @param string the error
  2416.     * @param int the line producing the error
  2417.     * @param string file where the error was produced
  2418.     *
  2419.     * @return string containing  the error
  2420.     * @access private
  2421.     * @since  1.0
  2422.     */
  2423.     function _prot_error($str , $line , $file,$printError=true)
  2424.     {
  2425.         if($printError){
  2426.             echo "$line,$file,PROTOCOL ERROR!:$str\n";
  2427.         }
  2428.     }
  2429.  
  2430.  
  2431.  
  2432.  
  2433.  
  2434.  
  2435.  
  2436.     function _getEXTarray(&$str , $startDelim = '(' , $stopDelim = ')'){
  2437.         /* I let choose the $startDelim  and $stopDelim to allow parsing
  2438.            the OK response  so I also can parse a response like this
  2439.            * OK [UIDNEXT 150] Predicted next UID
  2440.         */
  2441.         $this->_getNextToken( $str , $parenthesis );
  2442.         if( $parenthesis != $startDelim ){
  2443.             $this->_prot_error("must be a '$startDelim' but is a '$parenthesis' !!!!" , __LINE__ , __FILE__ );
  2444.         }
  2445.         $parenthesis = '';
  2446.         $struct_arr = array();
  2447.         while( $parenthesis != $stopDelim && $str != '' ){
  2448.             // The command
  2449.             $this->_getNextToken( $str , $token );
  2450.             $token = strtoupper( $token );
  2451.  
  2452.             if( ( $ret = $this->_retrParsedResponse( $str , $token ) ) != false ){
  2453.                 //$struct_arr[$token] = $ret;
  2454.                 $struct_arr=array_merge($struct_arr, $ret);
  2455.             }
  2456.  
  2457.             $parenthesis=$token;
  2458.  
  2459.         }//While
  2460.  
  2461.        if( $parenthesis != $stopDelim  ){
  2462.             $this->_prot_error("1_must be a '$stopDelim' but is a '$parenthesis' !!!!" , __LINE__ , __FILE__ );
  2463.        }
  2464.         return $struct_arr;
  2465.     }
  2466.  
  2467.  
  2468.  
  2469.  
  2470.  
  2471.     function _retrParsedResponse( &$str , $token, $previousToken = null)
  2472.     {
  2473.  
  2474.     //echo "\n\nTOKEN:$token\r\n";
  2475.         switch( $token ){
  2476.         case "RFC822.SIZE" :
  2477.             return array($token=>$this->_parseOneStringResponse( $str,__LINE__ , __FILE__ ));
  2478.             break;
  2479. //        case "RFC822.TEXT" :
  2480.  
  2481. //        case "RFC822.HEADER" :
  2482.  
  2483.  
  2484.         case "RFC822" :
  2485.             return array($token=>$this->_parseContentresponse( $str , $token ));
  2486.             break;
  2487.         case "FLAGS" :
  2488.  
  2489.         case "PERMANENTFLAGS" :
  2490.             return array($token=>$this->_parseFLAGSresponse( $str ));
  2491.             break;
  2492.  
  2493.         case "ENVELOPE" :
  2494.             return array($token=>$this->_parseENVELOPEresponse( $str ));
  2495.             break;
  2496.         case "EXPUNGE" :
  2497.             return false;
  2498.             break;
  2499.  
  2500.         case "UID" :
  2501.  
  2502.         case "UIDNEXT" :
  2503.  
  2504.         case "UIDVALIDITY" :
  2505.  
  2506.         case "UNSEEN" :
  2507.  
  2508.         case "MESSAGES" :
  2509.  
  2510.         case "UIDNEXT" :
  2511.  
  2512.         case "UIDVALIDITY" :
  2513.  
  2514.         case "UNSEEN" :
  2515.  
  2516.         case "INTERNALDATE" :
  2517.             return array($token=>$this->_parseOneStringResponse( $str,__LINE__ , __FILE__ ));
  2518.             break;
  2519.         case "BODY" :
  2520.  
  2521.         case "BODYSTRUCTURE" :
  2522.             return array($token=>$this->_parseBodyResponse( $str , $token ));
  2523.             break;
  2524.         case "RECENT" :
  2525.             if( $previousToken != null ){
  2526.                 $aux["RECENT"]=$previousToken;
  2527.                 return $aux;
  2528.             }else{
  2529.                 return array($token=>$this->_parseOneStringResponse( $str,__LINE__ , __FILE__ ));
  2530.             }
  2531.             break;
  2532.  
  2533.         case "EXISTS" :
  2534.             return array($token=>$previousToken);
  2535.             break;
  2536.         case "READ-WRITE" :
  2537.  
  2538.         case "READ-ONLY" :
  2539.             return array($token=>$token);
  2540.             break;
  2541.         case "QUOTA" :
  2542.             /*
  2543.             A tipical GETQUOTA DIALOG IS AS FOLLOWS
  2544.  
  2545.                 C: A0004 GETQUOTA user.damian
  2546.                 S: * QUOTA user.damian (STORAGE 1781460 4000000)
  2547.                 S: A0004 OK Completed
  2548.             */
  2549.  
  2550.             $mailbox = $this->_parseOneStringResponse( $str,__LINE__ , __FILE__ );
  2551.             $this->_parseSpace( $str , __LINE__ , __FILE__ );
  2552.             $this->_parseString( $str , '(' , __LINE__ , __FILE__ );
  2553.  
  2554.             $ret_aux = array("MAILBOX"=>$this->utf_7_decode($mailbox) );
  2555.             $this->_getNextToken( $str , $quota_resp );
  2556.             if( ( $ext = $this->_retrParsedResponse( $str , $quota_resp )) == false){
  2557.                     $this->_prot_error("bogus response!!!!" , __LINE__ , __FILE__ );
  2558.             }
  2559.             $ret_aux=array_merge($ret_aux,$ext);
  2560.  
  2561.             $this->_getNextToken( $str , $separator );
  2562.             if( $separator == ')' ){
  2563.                 return array($token=>$ret_aux);
  2564.             }
  2565.  
  2566.  
  2567.             $this->_parseSpace( $str , __LINE__ , __FILE__ );
  2568.  
  2569.             $this->_getNextToken( $str , $quota_resp );
  2570.             if( ( $ext = $this->_retrParsedResponse( $str , $quota_resp )) == false){
  2571.                     $this->_prot_error("bogus response!!!!" , __LINE__ , __FILE__ );
  2572.             }
  2573.             $ret_aux=array_merge($ret_aux,$ext);
  2574.  
  2575.             $this->_parseString( $str , ')' , __LINE__ , __FILE__ );
  2576.             return array($token=>$ret_aux);
  2577.             break;
  2578.  
  2579.         case "QUOTAROOT" :
  2580.             /*
  2581.             A tipical GETQUOTA DIALOG IS AS FOLLOWS
  2582.  
  2583.                 C: A0004 GETQUOTA user.damian
  2584.                 S: * QUOTA user.damian (STORAGE 1781460 4000000)
  2585.                 S: A0004 OK Completed
  2586.             */
  2587.             $mailbox = $this->utf_7_decode($this->_parseOneStringResponse( $str,__LINE__ , __FILE__ ));
  2588.  
  2589.             $str_line = rtrim( substr( $this->_getToEOL( $str , false ) , 0 ) );
  2590.  
  2591.             $quotaroot = $this->_parseOneStringResponse( $str_line,__LINE__ , __FILE__ );
  2592.             $ret = @array( "MAILBOX"=>$this->utf_7_decode($mailbox) , $token=>$quotaroot );
  2593.             return array($token=>$ret);
  2594.             break;
  2595.         case "STORAGE" :
  2596.                 $used = $this->_parseOneStringResponse( $str,__LINE__ , __FILE__ );
  2597.                 $qmax = $this->_parseOneStringResponse( $str,__LINE__ , __FILE__ );
  2598.                 return array($token=>array("USED"=> $used, "QMAX" => $qmax));
  2599.         break;
  2600.         case "MESSAGE" :
  2601.                 $mused = $this->_parseOneStringResponse( $str,__LINE__ , __FILE__ );
  2602.                 $mmax = $this->_parseOneStringResponse( $str,__LINE__ , __FILE__ );
  2603.                 return array($token=>array("MUSED"=> $mused, "MMAX" => $mmax));
  2604.         break;
  2605.         case "FETCH" :
  2606.                 $this->_parseSpace( $str  ,__LINE__  ,__FILE__ );
  2607.                 // Get the parsed pathenthesis
  2608.                 $struct_arr = $this->_getEXTarray( $str );
  2609.                 return $struct_arr;
  2610.             break;
  2611.         case "CAPABILITY" :
  2612.                 $this->_parseSpace( $str , __LINE__ , __FILE__ );
  2613.                 $str_line = rtrim( substr( $this->_getToEOL( $str , false ) , 0 ) );
  2614.                 $struct_arr["CAPABILITIES"] = explode( ' ' , $str_line );
  2615.                 return array($token=>$struct_arr);
  2616.             break;
  2617.         case "STATUS" :
  2618.                 $mailbox = $this->_parseOneStringResponse( $str,__LINE__ , __FILE__ );
  2619.                 $this->_parseSpace( $str , __LINE__ , __FILE__ );
  2620.                 $ext = $this->_getEXTarray( $str );
  2621.                 $struct_arr["MAILBOX"] = $this->utf_7_decode($mailbox);
  2622.                 $struct_arr["ATTRIBUTES"] = $ext;
  2623.                 return array($token=>$struct_arr);
  2624.             break;
  2625.         case "LIST" :
  2626.                 $this->_parseSpace( $str , __LINE__ , __FILE__ );
  2627.                 $params_arr = $this->_arrayfy_content( $str );
  2628.  
  2629.                 $this->_parseSpace( $str , __LINE__ , __FILE__ );
  2630.                 $this->_getNextToken( $str , $hierarchydelim );
  2631.  
  2632.                 $this->_parseSpace( $str,__LINE__ , __FILE__);
  2633.                 $this->_getNextToken( $str , $mailbox_name );
  2634.  
  2635.                 $result_array = array( "NAME_ATTRIBUTES"=>$params_arr , "HIERACHY_DELIMITER"=>$hierarchydelim , "MAILBOX_NAME"=>  $this->utf_7_decode($mailbox_name) );
  2636.                 return array($token=>$result_array);
  2637.             break;
  2638.         case "LSUB" :
  2639.                 $this->_parseSpace( $str , __LINE__ , __FILE__ );
  2640.                 $params_arr = $this->_arrayfy_content( $str );
  2641.  
  2642.                 $this->_parseSpace( $str , __LINE__ , __FILE__ );
  2643.                 $this->_getNextToken( $str , $hierarchydelim );
  2644.  
  2645.                 $this->_parseSpace( $str,__LINE__ , __FILE__);
  2646.                 $this->_getNextToken( $str , $mailbox_name );
  2647.  
  2648.                 $result_array = array( "NAME_ATTRIBUTES"=>$params_arr , "HIERACHY_DELIMITER"=>$hierarchydelim , "MAILBOX_NAME"=> $this->utf_7_decode($mailbox_name) );
  2649.                 return array($token=>$result_array);
  2650.             break;
  2651.  
  2652.             case "SEARCH" :
  2653.                 $str_line = rtrim( substr( $this->_getToEOL( $str , false ) , 1) );
  2654.                 $struct_arr["SEARCH_LIST"] = explode( ' ' , $str_line );
  2655.                 if(count($struct_arr["SEARCH_LIST"]) == 1 && $struct_arr["SEARCH_LIST"][0]==''){
  2656.                     $struct_arr["SEARCH_LIST"]=null;
  2657.                 }
  2658.                 return array($token=>$struct_arr);
  2659.             break;
  2660.             case "OK" :
  2661.                 /* TODO:
  2662.                     parse the [ .... ] part of the response, use the method
  2663.                     _getEXTarray(&$str,'[',$stopDelim=']')
  2664.  
  2665.                 */
  2666.                 $str_line = rtrim( substr( $this->_getToEOL( $str , false ) , 1 ) );
  2667.                 if($str_line[0] == '[' ){
  2668.                     $braceLen=$this->_getClosingBracesPos($str_line, '[', ']' );
  2669.                     $str_aux='('. substr($str_line,1,$braceLen -1). ')';
  2670.                     $ext_arr=$this->_getEXTarray($str_aux);
  2671.                     //$ext_arr=array($token=>$this->_getEXTarray($str_aux));
  2672.                 }else{
  2673.                     $ext_arr=$str_line;
  2674.                     //$ext_arr=array($token=>$str_line);
  2675.                 }
  2676.                 $result_array =  $ext_arr;
  2677.                 return $result_array;
  2678.                 break;
  2679.         case "NO" :
  2680.         /* TODO:
  2681.             parse the [ .... ] part of the response, use the method
  2682.             _getEXTarray(&$str,'[',$stopDelim=']')
  2683.  
  2684.         */
  2685.  
  2686.             $str_line = rtrim( substr( $this->_getToEOL( $str , false ) , 1 ) );
  2687.             $result_array[] = @array( "COMMAND"=>$token , "EXT"=>$str_line );
  2688.             return $result_array;
  2689.             break;
  2690.         case "BAD" :
  2691.         /* TODO:
  2692.             parse the [ .... ] part of the response, use the method
  2693.             _getEXTarray(&$str,'[',$stopDelim=']')
  2694.  
  2695.         */
  2696.  
  2697.             $str_line = rtrim( substr( $this->_getToEOL( $str , false ) , 1 ) );
  2698.             $result_array[] = array( "COMMAND"=>$token , "EXT"=>$str_line );
  2699.             return $result_array;
  2700.             break;
  2701.         case "BYE" :
  2702.         /* TODO:
  2703.             parse the [ .... ] part of the response, use the method
  2704.             _getEXTarray(&$str,'[',$stopDelim=']')
  2705.  
  2706.         */
  2707.  
  2708.             $str_line = rtrim( substr( $this->_getToEOL( $str , false ) , 1 ) );
  2709.             $result_array[] = array( "COMMAND"=>$command , "EXT"=> $str_line );
  2710.             return $result_array;
  2711.             break;
  2712.  
  2713.         case "LISTRIGHTS" :
  2714.                 $this->_parseSpace( $str ,__LINE__ , __FILE__ );
  2715.                 $this->_getNextToken( $str , $mailbox );
  2716.                 $this->_parseSpace( $str , __LINE__ , __FILE__ );
  2717.                 $this->_getNextToken( $str , $user );
  2718.                 $this->_parseSpace( $str , __LINE__ , __FILE__ );
  2719.                 $this->_getNextToken( $str , $granted );
  2720.  
  2721.                 $ungranted = explode( ' ' , rtrim( substr( $this->_getToEOL( $str , false ) , 1 ) ) );
  2722.  
  2723.                 $result_array = @array( "MAILBOX"=>$this->utf_7_decode($mailbox) , "USER"=>$user , "GRANTED"=>$granted , "UNGRANTED"=>$ungranted );
  2724.                 return $result_array;
  2725.             break;
  2726.  
  2727.         case "MYRIGHTS" :
  2728.                 $this->_parseSpace( $str , __LINE__ , __FILE__ );
  2729.                 $this->_getNextToken( $str ,$mailbox );
  2730.                 $this->_parseSpace( $str , __LINE__ , __FILE__ );
  2731.                 $this->_getNextToken( $str , $granted );
  2732.  
  2733.                 $result_array = array( "MAILBOX"=>$this->utf_7_decode($mailbox) , "GRANTED"=>$granted );
  2734.                 return $result_array;
  2735.             break;
  2736.  
  2737.         case "ACL" :
  2738.                 $this->_parseSpace( $str , __LINE__ , __FILE__ );
  2739.                 $this->_getNextToken( $str , $mailbox );
  2740.                 $this->_parseSpace( $str , __LINE__ , __FILE__ );
  2741.                 $acl_arr = explode( ' ' , rtrim( substr( $this->_getToEOL( $str , false ) , 0 ) ) );
  2742.  
  2743.                 for( $i = 0 ; $i < count( $acl_arr ) ; $i += 2 ){
  2744.                     $arr[] = array( "USER"=>$acl_arr[$i] , "RIGHTS"=>$acl_arr[ $i + 1 ] );
  2745.                 }
  2746.  
  2747.                 $result_array = array( "MAILBOX"=>$this->utf_7_decode($mailbox) , "USERS"=>$arr );
  2748.                 return $result_array;
  2749.             break;
  2750.  
  2751.         case "ANNOTATION" :
  2752.                 $this->_parseSpace($str, __LINE__, __FILE__);
  2753.                 $this->_getNextToken($str, $mailbox);
  2754.  
  2755.                 $this->_parseSpace($str, __LINE__, __FILE__);
  2756.                 $this->_getNextToken($str, $entry);
  2757.  
  2758.                 $this->_parseSpace($str, __LINE__, __FILE__);
  2759.                 $attrs = $this->_arrayfy_content($str);
  2760.  
  2761.                 $result_array = array('MAILBOX' => $mailbox, 'ENTRY' => $entry , 'ATTRIBUTES' => $attrs);
  2762.                 return $result_array;
  2763.             break;
  2764.  
  2765.         case "":
  2766.             $this->_prot_error( "PROTOCOL ERROR!:str empty!!" , __LINE__ , __FILE__ );
  2767.             break;
  2768.         case "(":
  2769.             $this->_prot_error("OPENING PARENTHESIS ERROR!!!!!!!!!!!!!!!!!" , __LINE__ , __FILE__ );
  2770.             break;
  2771.         case ")":
  2772.             //"CLOSING PARENTHESIS BREAK!!!!!!!"
  2773.             break;
  2774.         case "\r\n":
  2775.             $this->_prot_error("BREAK!!!!!!!!!!!!!!!!!" , __LINE__ , __FILE__ );
  2776.             break;
  2777.         case ' ':
  2778.             // this can happen and we just ignore it
  2779.             // This happens when - for example - fetch returns more than 1 parammeter
  2780.             // for example you ask to get RFC822.SIZE and UID
  2781.             //$this->_prot_error("SPACE BREAK!!!!!!!!!!!!!!!!!" , __LINE__ , __FILE__ );
  2782.             break;
  2783.         default:
  2784.             $body_token=strtoupper(substr($token,0,5));
  2785.             //echo "BODYYYYYYY: $body_token\n";
  2786.             $rfc822_token=strtoupper(substr($token,0,7));
  2787.             //echo "BODYYYYYYY: $rfc822_token|$token\n";
  2788.  
  2789.             if( $body_token == 'BODY[' || $body_token == 'BODY.' || $rfc822_token == 'RFC822.' ) {
  2790.                 //echo "TOKEN:$token\n";
  2791.                 //$this->_getNextToken( $str , $mailbox );
  2792.                 return array($token=>$this->_parseContentresponse( $str , $token ));
  2793.             }else{
  2794.                 $this->_prot_error( "UNIMPLEMMENTED! I don't know the parameter '$token' !!!" , __LINE__ , __FILE__ );
  2795.             }
  2796.             break;
  2797.         }
  2798.         return false;
  2799. }
  2800.  
  2801.  
  2802.  
  2803.  
  2804.  
  2805.  
  2806.     /*
  2807.     * Verifies that the next character IS a space
  2808.     */
  2809.     function _parseSpace(&$str,$line,$file, $printError = true)
  2810.     {
  2811.     /*
  2812.         This code repeats a lot in this class
  2813.         so i make it a function to make all the code shorter
  2814.     */
  2815.         $this->_getNextToken( $str , $space );
  2816.         if( $space != ' ' ){
  2817.             $this->_prot_error("must be a ' ' but is a '$space' !!!!" , $line , $file,$printError );
  2818.         }
  2819.         return $space;
  2820.     }
  2821.  
  2822.  
  2823.  
  2824.  
  2825.  
  2826.  
  2827.     function _parseString( &$str , $char , $line , $file )
  2828.     {
  2829.     /*
  2830.         This code repeats a lot in this class
  2831.         so i make it a function to make all the code shorter
  2832.     */
  2833.         $this->_getNextToken( $str , $char_aux );
  2834.         if( strtoupper($char_aux) != strtoupper( $char ) ){
  2835.             $this->_prot_error("must be a $char but is a '$char_aux' !!!!", $line , $file );
  2836.         }
  2837.         return $char_aux;
  2838.     }
  2839.  
  2840.  
  2841.  
  2842.  
  2843.  
  2844.     function _genericImapResponseParser( &$str , $cmdid = null )
  2845.     {
  2846.  
  2847.         $result_array=array();
  2848.         if( $this->_unParsedReturn ){
  2849.             $unparsed_str = $str;
  2850.         }
  2851.  
  2852.         $this->_getNextToken( $str , $token );
  2853.  
  2854.         while( $token != $cmdid && $str != '' ){
  2855.         if($token == "+" ){
  2856.         //if the token  is + ignore the line
  2857.         // TODO: verify that this is correct!!!
  2858.             $this->_getToEOL( $str );
  2859.             $this->_getNextToken( $str , $token );
  2860.         }
  2861.  
  2862.             $this->_parseString( $str , ' ' , __LINE__ , __FILE__ );
  2863.  
  2864.             $this->_getNextToken( $str , $token );
  2865.         if( $token == '+' ){
  2866.             $this->_getToEOL( $str );
  2867.             $this->_getNextToken( $str , $token );
  2868.         }else
  2869.             if( is_numeric( $token ) ){
  2870.                 // The token is a NUMBER so I store it
  2871.                 $msg_nro = $token;
  2872.                 $this->_parseSpace( $str , __LINE__ , __FILE__ );
  2873.  
  2874.                 // I get the command
  2875.                 $this->_getNextToken( $str , $command );
  2876.  
  2877.                 if( ( $ext_arr = $this->_retrParsedResponse( $str , $command, $msg_nro ) ) == false ){
  2878.                 //  if this bogus response cis a FLAGS () or EXPUNGE response
  2879.                 // the ignore it
  2880.                     if( $command != 'FLAGS' && $command != 'EXPUNGE' ){
  2881.                         $this->_prot_error("bogus response!!!!" , __LINE__ , __FILE__, false);
  2882.                     }
  2883.                 }
  2884.                 $result_array[] = array( "COMMAND"=>$command , "NRO"=>$msg_nro , "EXT"=>$ext_arr );
  2885.             }else{
  2886.                 // OK the token is not a NUMBER so it MUST be a COMMAND
  2887.                 $command = $token;
  2888.  
  2889.                 /* Call the parser return the array
  2890.                     take care of bogus responses!
  2891.                 */
  2892.  
  2893.                 if( ( $ext_arr = $this->_retrParsedResponse( $str , $command ) ) == false ){
  2894.                     $this->_prot_error( "bogus response!!!! (COMMAND:$command)" , __LINE__ , __FILE__ );
  2895.                 }
  2896.                 $result_array[] = array( "COMMAND"=>$command , "EXT"=>$ext_arr );
  2897.  
  2898.  
  2899.             }
  2900.  
  2901.  
  2902.             $this->_getNextToken( $str , $token );
  2903.  
  2904.             $token = strtoupper( $token );
  2905.             if( $token != "\r\n" && $token != '' ){
  2906.                 $this->_prot_error("PARSE ERROR!!! must be a '\\r\\n' here  but is a '$token'!!!! (getting the next line)|STR:|$str|" , __LINE__ , __FILE__ );
  2907.             }
  2908.             $this->_getNextToken( $str , $token );
  2909.  
  2910.             if($token == "+" ){
  2911.                 //if the token  is + ignore the line
  2912.                 // TODO: verify that this is correct!!!
  2913.                 $this->_getToEOL( $str );
  2914.                 $this->_getNextToken( $str , $token );
  2915.             }
  2916.         }//While
  2917.         // OK we finish the UNTAGGED Response now we must parse the FINAL TAGGED RESPONSE
  2918.         //TODO: make this a litle more elegant!
  2919.  
  2920.         $this->_parseSpace( $str , __LINE__ , __FILE__, false );
  2921.  
  2922.         $this->_getNextToken( $str , $cmd_status );
  2923.  
  2924.         $str_line = rtrim (substr( $this->_getToEOL( $str ) , 1 ) );
  2925.  
  2926.  
  2927.         $response["RESPONSE"]=array( "CODE"=>$cmd_status , "STR_CODE"=>$str_line , "CMDID"=>$cmdid );
  2928.  
  2929.         $ret=$response;
  2930.         if( !empty($result_array)){
  2931.             $ret=array_merge($ret,array("PARSED"=>$result_array) );
  2932.         }
  2933.  
  2934.         if( $this->_unParsedReturn ){
  2935.             $unparsed["UNPARSED"]=$unparsed_str;
  2936.             $ret=array_merge($ret,$unparsed);
  2937.         }
  2938.  
  2939.  
  2940.         if( isset($status_arr) ){
  2941.             $status["STATUS"]=$status_arr;
  2942.             $ret=array_merge($ret,$status);
  2943.         }
  2944.         return $ret;
  2945.  
  2946. }
  2947.  
  2948.  
  2949.  
  2950.  
  2951.     function _genericCommand($command, $params = '')
  2952.     {
  2953.         if( !$this->_connected ){
  2954.             return new PEAR_Error( "not connected! (CMD:$command)" );
  2955.         }
  2956.         $cmdid = $this->_getCmdId();
  2957.         $this->_putCMD( $cmdid , $command , $params );
  2958.         $args=$this->_getRawResponse( $cmdid );
  2959.         return $this->_genericImapResponseParser( $args , $cmdid );
  2960.     }
  2961.  
  2962.  
  2963.  
  2964.      function utf_7_encode($str)
  2965.     {
  2966.         if($this->_useUTF_7 == false ){
  2967.             return $str;
  2968.         }
  2969.         //return imap_utf7_encode($str);
  2970.  
  2971.         $encoded_utf7 = '';
  2972.         $base64_part  = '';
  2973.     if(is_array($str)){
  2974.         return new PEAR_Error('error');
  2975.     }
  2976.  
  2977.  
  2978.         for ($i = 0; $i < strlen($str); $i++) {
  2979.             //those chars should be base64 encoded
  2980.             if ( ((ord($str[$i]) >= 39 ) and (ord($str[$i]) <= 126 )) or ((ord($str[$i]) >= 32 ) and (ord($str[$i]) <= 37 )) ) {
  2981.                 if ($base64_part) {
  2982.                     $encoded_utf7 = sprintf("%s&%s-", $encoded_utf7, str_replace('=', '',base64_encode($base64_part))  );
  2983.                     $base64_part = '';
  2984.                 }
  2985.                 $encoded_utf7 = sprintf("%s%s",$encoded_utf7 , $str[$i]);
  2986.             } else {
  2987.                 //handle &
  2988.                 if (ord($str[$i]) == 38 ) {
  2989.                     if ($base64_part) {
  2990.                         $encoded_utf7 = sprintf("%s&%s-", $encoded_utf7, str_replace('=', '',base64_encode($base64_part))  );
  2991.                         $base64_part = '';
  2992.                     }
  2993.                     $encoded_utf7 = sprintf("%s&-", $encoded_utf7 );
  2994.                 } else {
  2995.                     $base64_part = sprintf("%s%s",$base64_part  , $str[$i]);
  2996.                     //$base64_part = sprintf("%s%s%s",$base64_part , chr(0) , $str[$i]);
  2997.                 }
  2998.             }
  2999.         }
  3000.         if ($base64_part) {
  3001.             $encoded_utf7 = sprintf("%s&%s-", $encoded_utf7, str_replace('=', '',base64_encode($base64_part))   );
  3002.             $base64_part = '';
  3003.         }
  3004.         return $encoded_utf7;
  3005.     }
  3006.  
  3007.  
  3008.     function utf_7_decode($str)
  3009.     {
  3010.  
  3011.         if($this->_useUTF_7 == false ){
  3012.             return $str;
  3013.         }
  3014.  
  3015.         //return imap_utf7_decode($str);
  3016.  
  3017.         $base64_part = '';
  3018.         $decoded_utf7 = '';
  3019.  
  3020.         for ($i = 0; $i < strlen($str); $i++) {
  3021.             if ( strlen($base64_part) > 0 ) {
  3022.                 if ($str[$i] == '-') {
  3023.                     if ($base64_part == '&') {
  3024.                         $decoded_utf7 = sprintf("%s&" , $decoded_utf7 );
  3025.                     } else {
  3026.                         $next_part_decoded= base64_decode( substr( $base64_part, 1 ) ) ;
  3027.                         $decoded_utf7 = sprintf("%s%s", $decoded_utf7 , $next_part_decoded );
  3028.                     }
  3029.                     $base64_part = '';
  3030.  
  3031.                 } else {
  3032.                     $base64_part = sprintf("%s%s", $base64_part , $str[$i] );
  3033.                 }
  3034.             } else {
  3035.                 if ($str[$i] == '&') {
  3036.                     $base64_part = '&';
  3037.                 } else {
  3038.                     $decoded_utf7 = sprintf("%s%s", $decoded_utf7 , $str[$i] );
  3039.                 }
  3040.             }
  3041.         }
  3042.         return $decoded_utf7;
  3043.     }
  3044.  
  3045.  
  3046.  
  3047. }//Class
  3048. ?>
  3049.