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

Documentation generated on Mon, 11 Mar 2019 15:41:21 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.