Net_POP3
[ class tree: Net_POP3 ] [ index: Net_POP3 ] [ all elements ]

Source for file POP3.php

Documentation is available at POP3.php

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

Documentation generated on Mon, 11 Mar 2019 14:22:47 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.