Simple Groupware PHP Cross Reference Groupware Applications

Source: /src/lib/mail/POP3.php - 1146 lines - 34105 bytes - Summary - Text - Print

Description: +----------------------------- IMPORTANT ------------------------------+ | Usage of this class compared to native php extensions such as IMAP   | | is slow and may be feature deficient. If available you are STRONGLY  | | recommended to use the php extensions.                               | +----------------------------------------------------------------------+

   1  <?php
   2  // +-----------------------------------------------------------------------+
   3  // | Copyright (c) 2002, Richard Heyes                                     |
   4  // | All rights reserved.                                                  |
   5  // |                                                                       |
   6  // | Redistribution and use in source and binary forms, with or without    |
   7  // | modification, are permitted provided that the following conditions    |
   8  // | are met:                                                              |
   9  // |                                                                       |
  10  // | o Redistributions of source code must retain the above copyright      |
  11  // |   notice, this list of conditions and the following disclaimer.       |
  12  // | o Redistributions in binary form must reproduce the above copyright   |
  13  // |   notice, this list of conditions and the following disclaimer in the |
  14  // |   documentation and/or other materials provided with the distribution.|
  15  // | o The names of the authors may not be used to endorse or promote      |
  16  // |   products derived from this software without specific prior written  |
  17  // |   permission.                                                         |
  18  // |                                                                       |
  19  // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS   |
  20  // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT     |
  21  // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
  22  // | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT  |
  23  // | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
  24  // | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT      |
  25  // | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
  26  // | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
  27  // | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT   |
  28  // | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
  29  // | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  |
  30  // |                                                                       |
  31  // +-----------------------------------------------------------------------+
  32  // | Author: Richard Heyes <richard@phpguru.org>                           |
  33  // | Co-Author: Damian Fernandez Sosa <damlists@cnba.uba.ar>               |
  34  // +-----------------------------------------------------------------------+
  35  //
  36  // $Id: POP3.php 232731 2007-03-27 13:16:02Z cweiske $
  37  
  38  require_once('lib/pear/Socket.php');
  39  
  40  /**
  41  *  +----------------------------- IMPORTANT ------------------------------+
  42  *  | Usage of this class compared to native php extensions such as IMAP   |
  43  *  | is slow and may be feature deficient. If available you are STRONGLY  |
  44  *  | recommended to use the php extensions.                               |
  45  *  +----------------------------------------------------------------------+
  46  *
  47  * POP3 Access Class
  48  *
  49  * For usage see the example script
  50  */
  51  
  52  define('NET_POP3_STATE_DISCONNECTED',  1, true);
  53  define('NET_POP3_STATE_AUTHORISATION', 2, true);
  54  define('NET_POP3_STATE_TRANSACTION',   4, true);
  55  
  56  class Net_POP3
  57  {
  58  
  59      /**
  60      * Some basic information about the mail drop
  61      * garnered from the STAT command
  62      *
  63      * @var array
  64      */
  65      var $_maildrop;
  66  
  67      /**
  68      * Used for APOP to store the timestamp
  69      *
  70      * @var string
  71      */
  72      var $_timestamp;
  73  
  74      /**
  75      * Timeout that is passed to the socket object
  76      *
  77      * @var integer
  78      */
  79      var $_timeout;
  80  
  81      /**
  82      * Socket object
  83      *
  84      * @var object
  85      */
  86      var $_socket;
  87  
  88      /**
  89      * Current state of the connection. Used with the
  90      * constants defined above.
  91      *
  92      * @var integer
  93      */
  94      var $_state;
  95  
  96      /**
  97      * Hostname to connect to
  98      *
  99      * @var string
 100      */
 101      var $_host;
 102  
 103      /**
 104      * Port to connect to
 105      *
 106      * @var integer
 107      */
 108      var $_port;
 109  
 110      /**
 111      * To allow class debuging
 112      * @var boolean
 113      */
 114      var $_debug = DEBUG_POP3;
 115  
 116      /**
 117      * The auth methods this class support
 118      * @var array
 119      */
 120      //var $supportedAuthMethods=array('DIGEST-MD5', 'CRAM-MD5', 'APOP' , 'PLAIN' , 'LOGIN', 'USER');
 121      //Disabling DIGEST-MD5 for now
 122      var $supportedAuthMethods=array( 'CRAM-MD5', 'APOP' , 'PLAIN' , 'LOGIN', 'USER');
 123      //var $supportedAuthMethods=array( 'CRAM-MD5', 'PLAIN' , 'LOGIN');
 124      //var $supportedAuthMethods=array( 'PLAIN' , 'LOGIN');
 125  
 126      /**
 127      * The auth methods this class support
 128      * @var array
 129      */
 130      var $supportedSASLAuthMethods=array('DIGEST-MD5', 'CRAM-MD5');
 131  
 132      /**
 133      * The capability response
 134      * @var array
 135      */
 136      var $_capability;
 137  
 138     /**
 139      * Constructor. Sets up the object variables, and instantiates
 140      * the socket object.
 141      *
 142      */
 143      function Net_POP3()
 144      {
 145          $this->_timestamp =  ''; // Used for APOP
 146          $this->_maildrop  =  array();
 147          $this->_timeout   =  3;
 148          $this->_state     =  NET_POP3_STATE_DISCONNECTED;
 149          $this->_socket    =  new Net_Socket();
 150          /*
 151          * Include the Auth_SASL package.  If the package is not available,
 152          * we disable the authentication methods that depend upon it.
 153          */
 154          if ((include_once 'lib/pear/SASL.php') == false) {
 155              if($this->_debug){
 156                  echo "AUTH_SASL NOT PRESENT!\n";
 157              }
 158              foreach($this->supportedSASLAuthMethods as $SASLMethod){
 159                  $pos = array_search( $SASLMethod, $this->supportedAuthMethods );
 160                  if($this->_debug){
 161                      echo "DISABLING METHOD $SASLMethod\n";
 162                  }
 163                  unset($this->supportedAuthMethods[$pos]);
 164              }
 165          }
 166      }
 167  
 168      /**
 169      * Handles the errors the class can find
 170      * on the server
 171      *
 172      * @access private
 173      * @return PEAR_Error
 174      */
 175      function _raiseError($msg, $code =-1)
 176      {
 177      return PEAR::raiseError($msg, $code);
 178      }
 179  
 180      
 181      /**
 182      * Connects to the given host on the given port.
 183      * Also looks for the timestamp in the greeting
 184      * needed for APOP authentication
 185      *
 186      * @param  string $host Hostname/IP address to connect to
 187      * @param  string $port Port to use to connect to on host
 188      * @return bool  Success/Failure
 189      */
 190      function connect($host = 'localhost', $port = 110)
 191      {
 192          $this->_host = $host;
 193          $this->_port = $port;
 194  
 195          $result = $this->_socket->connect($host, $port, false, $this->_timeout);
 196          if ($result === true) {
 197              $data = $this->_recvLn();
 198  
 199              if( $this->_checkResponse($data) ){
 200              // if the response begins with '+OK' ...
 201  //            if (@substr(strtoupper($data), 0, 3) == '+OK') {
 202                  // Check for string matching apop timestamp
 203                  if (preg_match('/<.+@.+>/U', $data, $matches)) {
 204                      $this->_timestamp = $matches[0];
 205                  }
 206                  $this->_maildrop = array();
 207                  $this->_state    = NET_POP3_STATE_AUTHORISATION;
 208  
 209                  return true;
 210              }
 211          }
 212  
 213          $this->_socket->disconnect();
 214          return false;
 215      }
 216  
 217      /**
 218      * Disconnect function. Sends the QUIT command
 219      * and closes the socket.
 220      *
 221      * @return bool Success/Failure
 222      */
 223      function disconnect()
 224      {
 225          return $this->_cmdQuit();
 226      }
 227  
 228      /**
 229      * Performs the login procedure. If there is a timestamp
 230      * stored, APOP will be tried first, then basic USER/PASS.
 231      *
 232      * @param  string $user Username to use
 233      * @param  string $pass Password to use
 234      * @param  mixed $apop Whether to try APOP first, if used as string you can select the auth methd to use ( $pop3->login('validlogin', 'validpass', "CRAM-MD5");
 235      *          Valid methods are: 'DIGEST-MD5','CRAM-MD5','LOGIN','PLAIN','APOP','USER' 
 236      * @return mixed  true on Success/ PEAR_ERROR on error
 237      */
 238      function login($user, $pass, $apop = true)
 239      {
 240          if ($this->_state == NET_POP3_STATE_AUTHORISATION) {
 241  
 242              if(PEAR::isError($ret= $this->_cmdAuthenticate($user , $pass , $apop ) ) ){
 243                  return $ret;
 244              }
 245              if( ! PEAR::isError($ret)){
 246                  $this->_state = NET_POP3_STATE_TRANSACTION;
 247                  return true;
 248              }
 249  
 250          }
 251          return $this->_raiseError('Generic login error' , 1);
 252      }
 253  
 254      /**
 255      * Parses the response from the capability command. Stores
 256      * the result in $this->_capability
 257      *
 258      * @access private
 259      */
 260      function _parseCapability()
 261      {
 262  
 263          if(!PEAR::isError($data = $this->_sendCmd('CAPA'))){
 264              $data = $this->_getMultiline();
 265          }else {
 266              // CAPA command not supported, reset data var
 267              //  to avoid Notice errors of preg_split on an object
 268              $data = '';
 269          }
 270          $data = preg_split('/\r?\n/', $data, -1, PREG_SPLIT_NO_EMPTY);
 271  
 272          for ($i = 0; $i < count($data); $i++) {
 273  
 274              $capa='';
 275              if (preg_match('/^([a-z,\-]+)( ((.*))|$)$/i', $data[$i], $matches)) {
 276  
 277                  $capa=strtolower($matches[1]);
 278                  switch ($capa) {
 279                      case 'implementation':
 280                          $this->_capability['implementation'] = $matches[3];
 281                          break;
 282                      case 'sasl':
 283                          if (isset($matches[3])) $this->_capability['sasl'] = preg_split('/\s+/', $matches[3]);
 284                          break;
 285                      default :
 286                          $this->_capability[$capa] = $matches[2];
 287                          break;
 288                  }
 289              }
 290          }
 291      }
 292  
 293      /**
 294       * Returns the name of the best authentication method that the server
 295       * has advertised.
 296       *
 297       * @param string if !=null,authenticate with this method ($userMethod).
 298       *
 299       * @return mixed    Returns a string containing the name of the best
 300       *                  supported authentication method or a PEAR_Error object
 301       *                  if a failure condition is encountered.
 302       * @access private
 303       * @since  1.0
 304       */
 305      function _getBestAuthMethod($userMethod = null)
 306      {
 307  /*
 308         return 'USER';
 309         return 'APOP';
 310         return 'DIGEST-MD5';
 311         return 'CRAM-MD5';
 312  */
 313  
 314          $this->_parseCapability();
 315  
 316          //unset($this->_capability['sasl']);
 317  
 318         if( isset($this->_capability['sasl']) ){
 319             $serverMethods=$this->_capability['sasl'];
 320         }else{
 321              $serverMethods=array('USER');
 322              // Check for timestamp before attempting APOP
 323              if ($this->_timestamp != null)
 324              {
 325                  $serverMethods[] = 'APOP';
 326              }
 327         }
 328  
 329          if($userMethod !== null && $userMethod !== true ){
 330              $methods = array();
 331              $methods[] = $userMethod;
 332              return $userMethod;
 333          }else{
 334              $methods = $this->supportedAuthMethods;
 335          }
 336  
 337          if( ($methods != null) && ($serverMethods != null)){
 338  
 339              foreach ( $methods as $method ) {
 340  
 341                  if ( in_array( $method , $serverMethods ) ) {
 342                      return $method;
 343                  }
 344              }
 345              $serverMethods=implode(',' , $serverMethods );
 346              $myMethods=implode(',' ,$this->supportedAuthMethods);
 347              return $this->_raiseError("$method NOT supported authentication method!. This server " .
 348                  "supports these methods: $serverMethods, but I support $myMethods");
 349          }else{
 350              return $this->_raiseError("This server don't support any Auth methods");
 351          }
 352      }
 353  
 354      /**
 355      * Handles the authentication using any known method
 356       *
 357       * @param string The userid to authenticate as.
 358       * @param string The password to authenticate with.
 359       * @param string The method to use ( if $usermethod == '' then the class chooses the best method (the stronger is the best ) )
 360       *
 361       * @return mixed  string or PEAR_Error
 362       * @access private
 363       * @since  1.0
 364       */
 365      function _cmdAuthenticate($uid , $pwd , $userMethod = null )
 366      {
 367  
 368          if ( PEAR::isError( $method = $this->_getBestAuthMethod($userMethod) ) ) {
 369              return $method;
 370          }
 371  
 372          if (!in_array($userMethod, $this->supportedAuthMethods)) {
 373              return $this->_raiseError(
 374                  'Authentication method "' . $userMethod . '" is not supported.'
 375              );
 376          }
 377  
 378          switch ($method) {
 379              case 'DIGEST-MD5':
 380                  $result = $this->_authDigest_MD5( $uid , $pwd );
 381                  break;
 382              case 'CRAM-MD5':
 383                  $result = $this->_authCRAM_MD5( $uid , $pwd );
 384                  break;
 385              case 'LOGIN':
 386                  $result = $this->_authLOGIN( $uid , $pwd );
 387                  break;
 388              case 'PLAIN':
 389                  $result = $this->_authPLAIN( $uid , $pwd );
 390                  break;
 391              case 'APOP':
 392                  $result = $this->_cmdApop( $uid , $pwd );
 393                  // if APOP fails fallback to USER auth
 394                  if( PEAR::isError( $result ) ){
 395                      //echo "APOP FAILED!!!\n";
 396                      $result=$this->_authUSER( $uid , $pwd );
 397                  }
 398                  break;
 399              case 'USER':
 400                  $result = $this->_authUSER( $uid , $pwd );
 401              break;
 402  
 403              default :
 404                  $result = $this->_raiseError( "$method is not a supported authentication method" );
 405                  break;
 406          }
 407          return $result;
 408      }
 409  
 410      /**
 411      * Authenticates the user using the USER-PASS method.
 412       *
 413       * @param string The userid to authenticate as.
 414       * @param string The password to authenticate with.
 415       *
 416       * @return mixed    true on success or PEAR_Error on failure
 417       *
 418       * @access private
 419       * @since  1.0
 420       */
 421      function _authUSER($user, $pass  )
 422      {
 423          if ( PEAR::isError($ret=$this->_cmdUser($user) ) ){
 424              return $ret;
 425          }
 426          if ( PEAR::isError($ret=$this->_cmdPass($pass) ) ){
 427              return $ret;
 428          }
 429          return true;
 430      }
 431  
 432      /**
 433      * Authenticates the user using the PLAIN method.
 434       *
 435       * @param string The userid to authenticate as.
 436       * @param string The password to authenticate with.
 437       *
 438       * @return array Returns an array containing the response
 439       *
 440       * @access private
 441       * @since  1.0
 442       */
 443      function _authPLAIN($user, $pass  )
 444      {
 445          $cmd=sprintf('AUTH PLAIN %s', base64_encode( chr(0) . $user . chr(0) . $pass ) );
 446  
 447          if ( PEAR::isError( $ret = $this->_send($cmd) ) ) {
 448              return $ret;
 449          }
 450          if ( PEAR::isError( $challenge = $this->_recvLn() ) ){
 451              return $challenge;
 452          }
 453          if( PEAR::isError($ret=$this->_checkResponse($challenge) )){
 454              return $ret;
 455          }
 456          
 457          return true;
 458      }
 459  
 460      /**
 461      * Authenticates the user using the PLAIN method.
 462       *
 463       * @param string The userid to authenticate as.
 464       * @param string The password to authenticate with.
 465       *
 466       * @return array Returns an array containing the response
 467       *
 468       * @access private
 469       * @since  1.0
 470       */
 471      function _authLOGIN($user, $pass  )
 472      {
 473          $this->_send('AUTH LOGIN');
 474  
 475          if ( PEAR::isError( $challenge = $this->_recvLn() ) ) {
 476              return $challenge;
 477          }
 478          if( PEAR::isError($ret=$this->_checkResponse($challenge) )){
 479              return $ret;
 480          }
 481  
 482          if ( PEAR::isError( $ret = $this->_send(sprintf('%s', base64_encode($user))) ) ) {
 483              return $ret;
 484          }
 485  
 486          if ( PEAR::isError( $challenge = $this->_recvLn() ) ) {
 487              return $challenge;
 488          }
 489          if( PEAR::isError($ret=$this->_checkResponse($challenge) )){
 490              return $ret;
 491          }
 492  
 493          if ( PEAR::isError( $ret = $this->_send(sprintf('%s', base64_encode($pass))) ) ) {
 494              return $ret;
 495          }
 496  
 497          if ( PEAR::isError( $challenge = $this->_recvLn() ) ) {
 498              return $challenge;
 499          }
 500          return $this->_checkResponse($challenge);
 501      }
 502  
 503      /**
 504      * Authenticates the user using the CRAM-MD5 method.
 505       *
 506       * @param string The userid to authenticate as.
 507       * @param string The password to authenticate with.
 508       *
 509       * @return array Returns an array containing the response
 510       *
 511       * @access private
 512       * @since  1.0
 513       */
 514      function _authCRAM_MD5($uid, $pwd )
 515      {
 516          if ( PEAR::isError( $ret = $this->_send( 'AUTH CRAM-MD5' ) ) ) {
 517              return $ret;
 518          }
 519  
 520          if ( PEAR::isError( $challenge = $this->_recvLn() ) ) {
 521              return $challenge;
 522          }
 523          if( PEAR::isError($ret=$this->_checkResponse($challenge) )){
 524              return $ret;
 525          }
 526  
 527          // remove '+ '
 528          
 529          $challenge=substr($challenge,2);
 530          
 531          $challenge = base64_decode( $challenge );
 532  
 533          $cram = &Auth_SASL::factory('crammd5');
 534          $auth_str = base64_encode( $cram->getResponse( $uid , $pwd , $challenge ) );
 535  
 536          if ( PEAR::isError($error = $this->_send( $auth_str ) ) ) {
 537              return $error;
 538          }
 539          if ( PEAR::isError( $ret = $this->_recvLn() ) ) {
 540              return $ret;
 541          }
 542          //echo "RET:$ret\n";
 543          return $this->_checkResponse($ret);
 544      }
 545  
 546      /**
 547      * Authenticates the user using the DIGEST-MD5 method.
 548       *
 549       * @param string The userid to authenticate as.
 550       * @param string The password to authenticate with.
 551       * @param string The efective user
 552       *
 553       * @return array Returns an array containing the response
 554       *
 555       * @access private
 556       * @since  1.0
 557       */
 558      function _authDigest_MD5($uid, $pwd)
 559      {
 560          if ( PEAR::isError( $ret = $this->_send( 'AUTH DIGEST-MD5' ) ) ) {
 561              return $ret;
 562          }
 563  
 564          if ( PEAR::isError( $challenge = $this->_recvLn() ) ) {
 565              return $challenge;
 566          }
 567          if( PEAR::isError($ret=$this->_checkResponse($challenge) )){
 568              return $ret;
 569          }
 570  
 571          // remove '+ '
 572          $challenge=substr($challenge,2);
 573  
 574          $challenge = base64_decode( $challenge );
 575          $digest = &Auth_SASL::factory('digestmd5');
 576          $auth_str = base64_encode($digest->getResponse($uid, $pwd, $challenge, "localhost", "pop3" ));
 577  
 578          if ( PEAR::isError($error = $this->_send( $auth_str ) ) ) {
 579              return $error;
 580          }
 581  
 582          if ( PEAR::isError( $challenge = $this->_recvLn() ) ) {
 583              return $challenge;
 584          }
 585          if( PEAR::isError($ret=$this->_checkResponse($challenge) )){
 586              return $ret;
 587          }
 588           /*
 589           * We don't use the protocol's third step because POP3 doesn't allow
 590           * subsequent authentication, so we just silently ignore it.
 591           */
 592  
 593          if ( PEAR::isError( $challenge = $this->_send("\r\n") ) ) {
 594              return $challenge ;
 595          }
 596          
 597          if ( PEAR::isError( $challenge = $this->_recvLn() ) ) {
 598              return $challenge;
 599          }
 600          
 601          return $this->_checkResponse($challenge);
 602      }
 603  
 604      /**
 605      * Sends the APOP command
 606      *
 607      * @param  $user Username to send
 608      * @param  $pass Password to send
 609      * @return bool Success/Failure
 610      */
 611      function _cmdApop($user, $pass)
 612      {
 613          if ($this->_state == NET_POP3_STATE_AUTHORISATION) {
 614  
 615              if (!empty($this->_timestamp)) {
 616                  if(PEAR::isError($data = $this->_sendCmd('APOP ' . $user . ' ' . md5($this->_timestamp . $pass)) ) ){
 617                      return $data;
 618                  }
 619                  $this->_state = NET_POP3_STATE_TRANSACTION;
 620                  return true;
 621              }
 622          }
 623          return $this->_raiseError('Not In NET_POP3_STATE_AUTHORISATION State1');
 624      }
 625  
 626      /**
 627      * Returns the raw headers of the specified message.
 628      *
 629      * @param  integer $msg_id Message number
 630      * @return mixed   Either raw headers or false on error
 631      */
 632      function getRawHeaders($msg_id)
 633      {
 634          if ($this->_state == NET_POP3_STATE_TRANSACTION) {
 635              return $this->_cmdTop($msg_id, 0);
 636          }
 637  
 638          return false;
 639      }
 640  
 641      /**
 642      * Returns the  headers of the specified message in an
 643      * associative array. Array keys are the header names, array
 644      * values are the header values. In the case of multiple headers
 645      * having the same names, eg Received:, the array value will be
 646      * an indexed array of all the header values.
 647      *
 648      * @param  integer $msg_id Message number
 649      * @return mixed   Either array of headers or false on error
 650      */
 651      function getParsedHeaders($msg_id)
 652      {
 653          $headers = array();
 654          if ($this->_state == NET_POP3_STATE_TRANSACTION) {
 655  
 656              $raw_headers = rtrim($this->getRawHeaders($msg_id));
 657  
 658              $raw_headers = preg_replace("/\r\n[ \t]+/", ' ', $raw_headers); // Unfold headers
 659              $raw_headers = explode("\r\n", $raw_headers);
 660              foreach ($raw_headers as $value) {
 661                  $name  = strtolower(substr($value, 0, $pos = strpos($value, ':')));
 662                  $value = ltrim(substr($value, $pos + 1));
 663                  if ($name=="subject" or $name=="to" or $name=="from") $value = modify::decode_subject($value);
 664                  if (isset($headers[$name]) AND is_array($headers[$name])) {
 665                      $headers[$name][] = $value;
 666                  } elseif (isset($headers[$name])) {
 667                      $headers[$name] = array($headers[$name], $value);
 668                  } else {
 669                      $headers[$name] = $value;
 670                  }
 671              }
 672  
 673              return $headers;
 674          }
 675  
 676          return false;
 677      }
 678  
 679      /**
 680      * Returns the body of the message with given message number.
 681      *
 682      * @param  integer $msg_id Message number
 683      * @return mixed   Either message body or false on error
 684      */
 685      function getBody($msg_id)
 686      {
 687          if ($this->_state == NET_POP3_STATE_TRANSACTION) {
 688              $msg = $this->_cmdRetr($msg_id);
 689              return substr($msg, strpos($msg, "\r\n\r\n")+4);
 690          }
 691  
 692          return false;
 693      }
 694  
 695      /**
 696      * Returns the entire message with given message number.
 697      *
 698      * @param  integer $msg_id Message number
 699      * @return mixed   Either entire message or false on error
 700      */
 701      function getMsg($msg_id)
 702      {
 703          if ($this->_state == NET_POP3_STATE_TRANSACTION) {
 704              return $this->_cmdRetr($msg_id);
 705          }
 706  
 707          return false;
 708      }
 709  
 710      /**
 711      * Returns the size of the maildrop
 712      *
 713      * @return mixed Either size of maildrop or false on error
 714      */
 715      function getSize()
 716      {
 717          if ($this->_state == NET_POP3_STATE_TRANSACTION) {
 718              if (isset($this->_maildrop['size'])) {
 719                  return $this->_maildrop['size'];
 720              } else {
 721                  list(, $size) = $this->_cmdStat();
 722                  return $size;
 723              }
 724          }
 725  
 726          return false;
 727      }
 728  
 729      /**
 730      * Returns number of messages in this maildrop
 731      *
 732      * @return mixed Either number of messages or false on error
 733      */
 734      function numMsg()
 735      {
 736          if ($this->_state == NET_POP3_STATE_TRANSACTION) {
 737              if (isset($this->_maildrop['num_msg'])) {
 738                  return $this->_maildrop['num_msg'];
 739              } else {
 740                  list($num_msg, ) = $this->_cmdStat();
 741                  return $num_msg;
 742              }
 743          }
 744  
 745          return false;
 746      }
 747  
 748      /**
 749      * Marks a message for deletion. Only will be deleted if the
 750      * disconnect() method is called.
 751      *
 752      * @param  integer $msg_id Message to delete
 753      * @return bool Success/Failure
 754      */
 755      function deleteMsg($msg_id)
 756      {
 757          if ($this->_state == NET_POP3_STATE_TRANSACTION) {
 758              return $this->_cmdDele($msg_id);
 759          }
 760  
 761          return false;
 762      }
 763  
 764      /**
 765      * Combination of LIST/UIDL commands, returns an array
 766      * of data
 767      *
 768      * @param  integer $msg_id Optional message number
 769      * @return mixed Array of data or false on error
 770      */
 771      function getListing($msg_id = null)
 772      {
 773      
 774          if ($this->_state == NET_POP3_STATE_TRANSACTION) {
 775              if (!isset($msg_id)){
 776              
 777                  $list=array();
 778                  if (($list = $this->_cmdList())) {
 779                      if (($uidl = $this->_cmdUidl())) {
 780                          foreach ($uidl as $i => $value) {
 781                              $list[$i]['uidl'] = $value['uidl'];
 782                          }
 783                      }
 784                      return $list;
 785                  }else{
 786                      return array();
 787                  }
 788              } else {
 789                  if ($list = $this->_cmdList($msg_id) AND $uidl = $this->_cmdUidl($msg_id)) {
 790                      return array_merge($list, $uidl);
 791                  }
 792              }
 793          }
 794  
 795          return false;
 796      }
 797  
 798      /**
 799      * Sends the USER command
 800      *
 801      * @param  string $user Username to send
 802      * @return bool  Success/Failure
 803      */
 804      function _cmdUser($user)
 805      {
 806          if ($this->_state == NET_POP3_STATE_AUTHORISATION) {
 807              return $this->_sendCmd('USER ' . $user);
 808          }
 809          return $this->_raiseError('Not In NET_POP3_STATE_AUTHORISATION State');
 810      }
 811  
 812      /**
 813      * Sends the PASS command
 814      *
 815      * @param  string $pass Password to send
 816      * @return bool  Success/Failure
 817      */
 818      function _cmdPass($pass)
 819      {
 820          if ($this->_state == NET_POP3_STATE_AUTHORISATION) {
 821              return $this->_sendCmd('PASS ' . $pass);
 822          }
 823          return $this->_raiseError('Not In NET_POP3_STATE_AUTHORISATION State');
 824      }
 825  
 826      /**
 827      * Sends the STAT command
 828      *
 829      * @return mixed Indexed array of number of messages and
 830      *               maildrop size, or false on error.
 831      */
 832      function _cmdStat()
 833      {
 834          if ($this->_state == NET_POP3_STATE_TRANSACTION) {
 835              if(!PEAR::isError($data = $this->_sendCmd('STAT'))){
 836                  $size = 0;
 837                  $msg_num = 0;
 838                  sscanf($data, '+OK %d %d', $msg_num, $size);
 839                  $this->_maildrop['num_msg'] = $msg_num;
 840                  $this->_maildrop['size']    = $size;
 841  
 842                  return array($msg_num, $size);
 843              }
 844          }
 845          return false;
 846      }
 847  
 848      /**
 849      * Sends the LIST command
 850      *
 851      * @param  integer $msg_id Optional message number
 852      * @return mixed   Indexed array of msg_id/msg size or
 853      *                 false on error
 854      */
 855      function _cmdList($msg_id = null)
 856      {
 857          $return=array();
 858          if ($this->_state == NET_POP3_STATE_TRANSACTION) {
 859              if (!isset($msg_id)) {
 860                  if(!PEAR::isError($data = $this->_sendCmd('LIST') )){
 861                      $data = $this->_getMultiline();
 862                      $data = explode("\r\n", $data);                    
 863                      foreach ($data as $line) {
 864                          if($line !=''){
 865                              $size = 0;
 866                              sscanf($line, '%s %s', $msg_id, $size);
 867                              $return[] = array('msg_id' => $msg_id, 'size' => $size);
 868                          }
 869                      }
 870                      return $return;
 871                  }
 872              } else {
 873                  if(!PEAR::isError($data = $this->_sendCmd('LIST ' . $msg_id))){
 874                      if($data!=''){
 875                          sscanf($data, '+OK %d %d', $msg_id, $size);
 876                          return array('msg_id' => $msg_id, 'size' => $size);
 877                      }
 878                      return array();
 879                  }
 880              }
 881          }
 882          
 883  
 884          return false;
 885      }
 886  
 887      /**
 888      * Sends the RETR command
 889      *
 890      * @param  integer $msg_id The message number to retrieve
 891      * @return mixed   The message or false on error
 892      */
 893      function _cmdRetr($msg_id)
 894      {
 895          if ($this->_state == NET_POP3_STATE_TRANSACTION) {
 896              if(!PEAR::isError($data = $this->_sendCmd('RETR ' . $msg_id) )){
 897                  $data = $this->_getMultiline();
 898                  return $data;
 899              }
 900          }
 901  
 902          return false;
 903      }
 904  
 905      /**
 906      * Sends the DELE command
 907      *
 908      * @param  integer $msg_id Message number to mark as deleted
 909      * @return bool Success/Failure
 910      */
 911      function _cmdDele($msg_id)
 912      {
 913          if ($this->_state == NET_POP3_STATE_TRANSACTION) {
 914              return $this->_sendCmd('DELE ' . $msg_id);
 915          }
 916  
 917          return false;
 918      }
 919  
 920      /**
 921      * Sends the NOOP command
 922      *
 923      * @return bool Success/Failure
 924      */
 925      function _cmdNoop()
 926      {
 927          if ($this->_state == NET_POP3_STATE_TRANSACTION) {
 928              if(!PEAR::isError($this->_sendCmd('NOOP'))){
 929                  return true;
 930              }
 931          }
 932  
 933          return false;
 934      }
 935  
 936      /**
 937      * Sends the RSET command
 938      *
 939      * @return bool Success/Failure
 940      */
 941      function _cmdRset()
 942      {
 943          if ($this->_state == NET_POP3_STATE_TRANSACTION) {
 944              if(!PEAR::isError($this->_sendCmd('RSET'))){
 945                  return true;
 946              }
 947          }
 948  
 949          return false;
 950      }
 951  
 952      /**
 953      * Sends the QUIT command
 954      *
 955      * @return bool Success/Failure
 956      */
 957      function _cmdQuit()
 958      {
 959          $data = $this->_sendCmd('QUIT');
 960          $this->_state = NET_POP3_STATE_DISCONNECTED;
 961          $this->_socket->disconnect();
 962  
 963          return (bool)$data;
 964      }
 965  
 966      /**
 967      * Sends the TOP command
 968      *
 969      * @param  integer  $msg_id    Message number
 970      * @param  integer  $num_lines Number of lines to retrieve
 971      * @return mixed Message data or false on error
 972      */
 973      function _cmdTop($msg_id, $num_lines)
 974      {
 975          if ($this->_state == NET_POP3_STATE_TRANSACTION) {
 976  
 977              if(!PEAR::isError($this->_sendCmd('TOP ' . $msg_id . ' ' . $num_lines))){
 978                  return $this->_getMultiline();
 979              }
 980          }
 981  
 982          return false;
 983      }
 984  
 985      /**
 986      * Sends the UIDL command
 987      *
 988      * @param  integer $msg_id Message number
 989      * @return mixed indexed array of msg_id/uidl or false on error
 990      */
 991      function _cmdUidl($msg_id = null)
 992      {
 993          if ($this->_state == NET_POP3_STATE_TRANSACTION) {
 994  
 995              if (!isset($msg_id)) {
 996                  if(!PEAR::isError($data = $this->_sendCmd('UIDL') )){
 997                      $data = $this->_getMultiline();
 998                      $data = explode("\r\n", $data);
 999                      foreach ($data as $line) {
1000                          $uidl = 0;
1001                          sscanf($line, '%d %s', $msg_id, $uidl);
1002                          $return[] = array('msg_id' => $msg_id, 'uidl' => $uidl);
1003                      }
1004  
1005                      return $return;
1006                  }
1007              } else {
1008                  $uidl = 0;
1009                  $data = $this->_sendCmd('UIDL ' . $msg_id);
1010                  sscanf($data, '+OK %d %s', $msg_id, $uidl);
1011                  return array('msg_id' => $msg_id, 'uidl' => $uidl);
1012              }
1013          }
1014  
1015          return false;
1016      }
1017  
1018      /**
1019      * Sends a command, checks the reponse, and
1020      * if good returns the reponse, other wise
1021      * returns false.
1022      *
1023      * @param  string $cmd  Command to send (\r\n will be appended)
1024      * @return mixed First line of response if successful, otherwise false
1025      */
1026      function _sendCmd($cmd)
1027      {
1028          if (PEAR::isError($result = $this->_send($cmd) )){
1029              return $result ;
1030          }
1031  
1032          if (PEAR::isError($data = $this->_recvLn() )){
1033              return $data;
1034          }
1035          
1036          if ( strtoupper(substr($data, 0, 3)) == '+OK') {
1037              return $data;
1038          }
1039          
1040          
1041          return $this->_raiseError($data);
1042      }
1043  
1044      /**
1045      * Reads a multiline reponse and returns the data
1046      *
1047      * @return string The reponse.
1048      */
1049      function _getMultiline()
1050      {
1051          $data = '';
1052          while(!PEAR::isError($tmp = $this->_recvLn() ) ) {
1053              if($tmp == '.' || $tmp == "\n."){
1054                  return substr($data, 0, -2);
1055              }
1056              if (substr($tmp, 0, 2) == '..') {
1057                  $tmp = substr($tmp, 1);
1058              }
1059              $data .= $tmp . "\r\n";
1060          }
1061          return substr($data, 0, -2);
1062      }
1063  
1064     /**
1065      * Sets the bebug state
1066      *
1067      * @param  bool $debug 
1068      * @access public
1069      * @return void
1070      */
1071      function setDebug($debug=true)
1072      {
1073          $this->_debug=$debug;
1074      }
1075  
1076     /**
1077       * Send the given string of data to the server.
1078       *
1079       * @param   string  $data       The string of data to send.
1080       *
1081       * @return  mixed   True on success or a PEAR_Error object on failure.
1082       *
1083       * @access  private
1084       * @since   1.0
1085       */
1086      function _send($data)
1087      {
1088          if ($this->_debug) {
1089              echo "C: ".htmlspecialchars($data)."\n";
1090          }
1091  
1092          if (PEAR::isError($error = $this->_socket->writeLine($data))) {
1093              return $this->_raiseError('Failed to write to socket: ' . $error->getMessage());
1094          }
1095          return true;
1096      }
1097  
1098       /**
1099       * Receive the given string of data from the server.
1100       *
1101       * @return  mixed   a line of response on success or a PEAR_Error object on failure.
1102       *
1103       * @access  private
1104       * @since  1.0
1105       */
1106      function _recvLn()
1107      {
1108          if (PEAR::isError( $lastline = $this->_socket->readLine( 8192 ) ) ) {
1109              return $this->_raiseError('Failed to read from socket: ' . $this->lastline->getMessage());
1110          }
1111          if($this->_debug){
1112              // S: means this data was sent by  the POP3 Server
1113              echo "S:".htmlspecialchars($lastline)."\n" ;
1114          }
1115          return $lastline;
1116      }
1117  
1118       /**
1119       * Checks de server Response
1120       *
1121       * @param  string $response the response
1122       * @return  mixed   true on success or a PEAR_Error object on failure.
1123       *
1124       * @access  private
1125       * @since  1.3.3
1126       */
1127      function _checkResponse($response)
1128      {
1129          if (@substr(strtoupper($response), 0, 3) == '+OK') {
1130              return true;
1131          }else{
1132              if (@substr(strtoupper($response), 0, 4) == '-ERR') {
1133                  return $this->_raiseError($response);
1134              }else{
1135                  if (@substr(strtoupper($response), 0, 2) == '+ ') {
1136                      return true;
1137                  }
1138              }
1139      
1140          }
1141          return $this->_raiseError("Unknown Response ($response)");
1142      }
1143  
1144  }
1145  
1146  ?>

title

Description

title

Description

title

Description

title

title

Body