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

Documentation generated on Mon, 11 Mar 2019 13:52:17 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.