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

Source for file Client.php

Documentation is available at Client.php

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
  3. // +-----------------------------------------------------------------------+
  4. // |                                                                       |
  5. // |                  http://www.heino.gehlsen.dk/software/license         |
  6. // |                                                                       |
  7. // +-----------------------------------------------------------------------+
  8. // |                                                                       |
  9. // | This work (including software, documents, or other related items) is  |
  10. // | being provided by the copyright holders under the following license.  |
  11. // | By obtaining, using and/or copying this work, you (the licensee)      |
  12. // | agree that you have read, understood, and will comply with the        |
  13. // | following terms and conditions:                                       |
  14. // |                                                                       |
  15. // | Permission to use, copy, modify, and distribute this software and     |
  16. // | its documentation, with or without modification, for any purpose and  |
  17. // | without fee or royalty is hereby granted, provided that you include   |
  18. // | the following on ALL copies of the software and documentation or      |
  19. // | portions thereof, including modifications, that you make:             |
  20. // |                                                                       |
  21. // | 1. The full text of this NOTICE in a location viewable to users of    |
  22. // |    the redistributed or derivative work.                              |
  23. // |                                                                       |
  24. // | 2. Any pre-existing intellectual property disclaimers, notices, or    |
  25. // |    terms and conditions. If none exist, a short notice of the         |
  26. // |    following form (hypertext is preferred, text is permitted) should  |
  27. // |    be used within the body of any redistributed or derivative code:   |
  28. // |     http://www.heino.gehlsen.dk/software/license"                     |
  29. // |                                                                       |
  30. // | 3. Notice of any changes or modifications to the files, including     |
  31. // |    the date changes were made. (We recommend you provide URIs to      |
  32. // |    the location from which the code is derived.)                      |
  33. // |                                                                       |
  34. // | THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT    |
  35. // | HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED,    |
  36. // | INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR        |
  37. // | FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE    |
  38. // | OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY PATENTS,           |
  39. // | COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.                               |
  40. // |                                                                       |
  41. // | COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT,        |
  42. // | SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE        |
  43. // | SOFTWARE OR DOCUMENTATION.                                            |
  44. // |                                                                       |
  45. // | The name and trademarks of copyright holders may NOT be used in       |
  46. // | advertising or publicity pertaining to the software without specific, |
  47. // | written prior permission. Title to copyright in this software and any |
  48. // | associated documentation will at all times remain with copyright      |
  49. // | holders.                                                              |
  50. // |                                                                       |
  51. // +-----------------------------------------------------------------------+
  52. // |                                                                       |
  53. // | except for the references to the copyright holder, which has either   |
  54. // | been changes or removed.                                              |
  55. // |                                                                       |
  56. // +-----------------------------------------------------------------------+
  57. // $Id: Client.php,v 1.3.4.7 2005/10/20 17:20:53 heino Exp $
  58.  
  59. require_once 'PEAR.php';
  60. require_once 'Net/Socket.php';
  61. require_once 'Net/NNTP/Protocol/Responsecode.php';
  62.  
  63. // {{{ constants
  64.  
  65. /**
  66.  * Default host
  67.  *
  68.  * @access     public
  69.  */
  70. define('NET_NNTP_PROTOCOL_CLIENT_DEFAULT_HOST''localhost');
  71.  
  72. /**
  73.  * Default port
  74.  *
  75.  * @access     public
  76.  */
  77. define('NET_NNTP_PROTOCOL_CLIENT_DEFAULT_PORT''119');
  78.  
  79. // }}}
  80. // {{{ Net_NNTP_Protocol_Client
  81.  
  82. /**
  83.  * Low level NNTP Client
  84.  *
  85.  * Implements the client part of the NNTP standard acording to:
  86.  *  - RFC 977,
  87.  *  - RFC 2980,
  88.  *  - RFC 850/1036, and
  89.  *  - RFC 822/2822
  90.  *
  91.  * Each NNTP command is represented by a method: cmd*()
  92.  *
  93.  * WARNING: The Net_NNTP_Protocol_Client class is considered an internal class
  94.  *          (and should therefore currently not be extended directly outside of
  95.  *          the Net_NNTP package). Therefore its API is NOT required to be fully
  96.  *          stable, for as long as such changes doesn't affect the public API of
  97.  *          the Net_NNTP_Client class, which is considered stable.
  98.  *
  99.  * @category   Net
  100.  * @package    Net_NNTP
  101.  * @author     Heino H. Gehlsen <heino@gehlsen.dk>
  102.  * @version    $Id: Client.php,v 1.3.4.7 2005/10/20 17:20:53 heino Exp $
  103.  * @access     private
  104.  * @see        Net_NNTP_Client
  105.  * @since      Class available since Release 0.11.0
  106.  */
  107. class Net_NNTP_Protocol_Client
  108. {
  109.     // {{{ properties
  110.  
  111.     /**
  112.      * The socket resource being used to connect to the NNTP server.
  113.      *
  114.      * @var resource 
  115.      * @access private
  116.      */
  117.     var $_socket = null;
  118.  
  119.     /**
  120.      * Contains the last recieved status response code and text
  121.      *
  122.      * @var array 
  123.      * @access private
  124.      */
  125.     var $_currentStatusResponse = null;
  126.  
  127.     /**
  128.      * Whether to enable internal debug messages.
  129.      *
  130.      * @var     bool 
  131.      * @access  private
  132.      */
  133.     var $_debug = false;
  134.  
  135.     // }}}
  136.     // {{{ constructor
  137.         
  138.     /**
  139.      * Constructor
  140.      *
  141.      * @access public
  142.      */
  143.     function Net_NNTP_Protocol_Client({
  144.         $this->_socket = new Net_Socket();
  145.     }
  146.  
  147.     // }}}
  148.     // {{{ Connect()
  149.  
  150.     /**
  151.      * Connect to a NNTP server
  152.      *
  153.      * @param optional string $host The address of the NNTP-server to connect to, defaults to 'localhost'.
  154.      * @param optional int $port The port number to connect to, defaults to 119.
  155.      *
  156.      * @return mixed (bool) on success (true when posting allowed, otherwise false) or (object) pear_error on failure
  157.      * @access protected
  158.      */
  159.     function connect($host = NET_NNTP_PROTOCOL_CLIENT_DEFAULT_HOST$port = NET_NNTP_PROTOCOL_CLIENT_DEFAULT_PORT)
  160.     {
  161.         if ($this->isConnected() ) {
  162.             return PEAR::throwError('Already connected, disconnect first!'null);
  163.         }
  164.  
  165.         // Open Connection
  166.         $R @$this->_socket->connect($host$portfalse15);
  167.         if (PEAR::isError($R)) {
  168.             return PEAR::throwError('Could not connect to the server'null$R->getMessage());
  169.         }
  170.  
  171.         // Retrive the server's initial response.
  172.         $response $this->_getStatusResponse();
  173.         if (PEAR::isError($response)) {
  174.             return $response;
  175.         }
  176.  
  177.         switch ($response{
  178.             case NET_NNTP_PROTOCOL_RESPONSECODE_READY_POSTING_ALLOWED// 200, Posting allowed
  179.                 // TODO: Set some variable
  180.                 return true;
  181.                 break;
  182.             case NET_NNTP_PROTOCOL_RESPONSECODE_READY_POSTING_PROHIBITED// 201, Posting NOT allowed
  183.                 // TODO: Set some variable
  184.                 return false;
  185.                 break;
  186.             case 400:
  187.                 return PEAR::throwError('Server refused connection'$response$this->currentStatusResponse());
  188.                 break;
  189.             case NET_NNTP_PROTOCOL_RESPONSECODE_NOT_PERMITTED// 502, 'access restriction or permission denied' / service permanently unavailable
  190.                 return PEAR::throwError('Server refused connection'$response$this->currentStatusResponse());
  191.                 break;
  192.             default:
  193.                 return $this->_handleUnexpectedResponse($response);
  194.         }
  195.     }
  196.  
  197.     // }}}
  198.     // {{{ disconnect()
  199.  
  200.     /**
  201.      * alias for cmdQuit()
  202.      *
  203.      * @access protected
  204.      */
  205.     function disconnect()
  206.     {
  207.         return $this->cmdQuit();
  208.     }
  209.  
  210.     // }}}
  211.     // {{{ cmdQuit()
  212.  
  213.     /**
  214.      * Disconnect from the NNTP server
  215.      *
  216.      * @return mixed (bool) true on success or (object) pear_error on failure
  217.      * @access protected
  218.      */
  219.     function cmdQuit()
  220.     {
  221.         // Tell the server to close the connection
  222.         $response $this->_sendCommand('QUIT');
  223.         if (PEAR::isError($response)) {
  224.             return $response;
  225.         }
  226.     
  227.         switch ($response{
  228.             case 205: // RFC977: 'closing connection - goodbye!'
  229.                 // If socket is still open, close it.
  230.                 if ($this->isConnected()) {
  231.                     $this->_socket->disconnect();
  232.                 }
  233.                 return true;
  234.                 break;
  235.             default:
  236.                 return $this->_handleUnexpectedResponse($response);
  237.         }
  238.     }
  239.  
  240.     // }}}
  241.  
  242.     /**
  243.      * The authentication process i not yet standarized but used any way
  244.      * (http://www.mibsoftware.com/userkt/nntpext/index.html).
  245.      */
  246.      
  247.     // {{{ cmdAuthinfo()
  248.  
  249.     /**
  250.      * Authenticate using 'original' method
  251.      *
  252.      * @param string $user The username to authenticate as.
  253.      * @param string $pass The password to authenticate with.
  254.      *
  255.      * @return mixed (bool) true on success or (object) pear_error on failure
  256.      * @access protected
  257.      */
  258.     function cmdAuthinfo($user$pass)
  259.     {
  260.         // Send the username
  261.         $response $this->_sendCommand('AUTHINFO user '.$user);
  262.         if (PEAR::isError($response)) {
  263.             return $response;
  264.         }
  265.  
  266.         // Send the password, if the server asks
  267.         if (($response == 381&& ($pass !== null)) {
  268.             // Send the password
  269.             $response $this->_sendCommand('AUTHINFO pass '.$pass);
  270.             if (PEAR::isError($response)) {
  271.                 return $response;
  272.             }
  273.         }
  274.  
  275.         switch ($response{
  276.             case 281: // RFC2980: 'Authentication accepted'
  277.                 return true;
  278.                 break;
  279.             case 381: // RFC2980: 'More authentication information required'
  280.                 return PEAR::throwError('Authentication uncompleted'$response$this->currentStatusResponse());
  281.                 break;
  282.             case 482: // RFC2980: 'Authentication rejected'
  283.                 return PEAR::throwError('Authentication rejected'$response$this->currentStatusResponse());
  284.                 break;
  285.             case 502: // RFC2980: 'No permission'
  286.                 return PEAR::throwError('Authentication rejected'$response$this->currentStatusResponse());
  287.                 break;
  288. //            case 500:
  289. //            case 501:
  290. //                return PEAR::throwError('Authentication failed', $response, $this->currentStatusResponse());
  291. //                break;
  292.             default:
  293.                 return $this->_handleUnexpectedResponse($response);
  294.         }
  295.     }
  296.     
  297.     // }}}
  298.     // {{{ cmdAuthinfoSimple()
  299.  
  300.     /**
  301.      * Authenticate using 'simple' method
  302.      *
  303.      * @param string $user The username to authenticate as.
  304.      * @param string $pass The password to authenticate with.
  305.      *
  306.      * @return mixed (bool) true on success or (object) pear_error on failure
  307.      * @access protected
  308.      */
  309.     function cmdAuthinfoSimple($user$pass)
  310.     {
  311.         return PEAR::throwError("The auth mode: 'simple' is has not been implemented yet"null);
  312.     }
  313.     
  314.     // }}}
  315.     // {{{ cmdAuthinfoGeneric()
  316.  
  317.     /**
  318.      * Authenticate using 'generic' method
  319.      *
  320.      * @param string $user The username to authenticate as.
  321.      * @param string $pass The password to authenticate with.
  322.      *
  323.      * @return mixed (bool) true on success or (object) pear_error on failure
  324.      * @access protected
  325.      */
  326.     function cmdAuthinfoGeneric($user$pass)
  327.     {
  328.         return PEAR::throwError("The auth mode: 'generic' is has not been implemented yet"null);
  329.     }
  330.     
  331.     // }}}
  332.     // {{{ cmdModeReader()
  333.  
  334.     /**
  335.      *
  336.      *
  337.      * @return mixed (bool) true when posting allowed, false when postind disallowed or (object) pear_error on failure
  338.      * @access protected
  339.      */
  340.     function cmdModeReader()
  341.     {
  342.         // tell the newsserver we want an article
  343.         $response $this->_sendCommand('MODE READER');
  344.         if (PEAR::isError($response)) {
  345.             return $response;
  346.         }
  347.     
  348.         switch ($response{
  349.             case NET_NNTP_PROTOCOL_RESPONSECODE_READY_POSTING_ALLOWED// 200, RFC2980: 'Hello, you can post'
  350.                 return true;
  351.                 break;
  352.             case NET_NNTP_PROTOCOL_RESPONSECODE_READY_POSTING_PROHIBITED// 201, RFC2980: 'Hello, you can't post'
  353.                 return false;
  354.                 break;
  355.             case NET_NNTP_PROTOCOL_RESPONSECODE_NOT_PERMITTED// 502, 'access restriction or permission denied' / service permanently unavailable
  356.                 return PEAR::throwError('Connection being closed, since service so permanently unavailable'$response$this->currentStatusResponse());
  357.                 break;
  358.             default:
  359.                 return $this->_handleUnexpectedResponse($response);
  360.         }
  361.     }
  362.  
  363.     // }}}
  364.     // {{{ cmdNext()
  365.  
  366.     /**
  367.      * 
  368.      *
  369.      * @return 
  370.      * @access protected
  371.      */
  372.     function cmdNext($ret = 0)
  373.     {
  374.         // 
  375.         $response $this->_sendCommand('NEXT');
  376.         if (PEAR::isError($response)) {
  377.             return $response;
  378.         }
  379.  
  380.         switch ($response{
  381.             case NET_NNTP_PROTOCOL_RESPONSECODE_ARTICLE_SELECTED// 223, RFC977: 'n a article retrieved - request text separately (n = article number, a = unique article id)'
  382.                 $response_arr split(' 'trim($this->currentStatusResponse()));
  383.  
  384.                 $data = array('number' => (int) $response_arr[0],
  385.                           'id' =>  (string) $response_arr[1]);
  386.  
  387.                 switch ($ret{
  388.                     case 0:
  389.                         return $data;
  390.                         break;
  391.                     case 1:
  392.                         return $data['number'];
  393.                         break;
  394.                     case 2:
  395.                         return $data['id'];
  396.                         break;
  397.                 }
  398.                 break;
  399.             case NET_NNTP_PROTOCOL_RESPONSECODE_NO_GROUP_SELECTED// 412, RFC977: 'no newsgroup selected'
  400.                 return PEAR::throwError('No newsgroup has been selected'$response$this->currentStatusResponse());
  401.                 break;
  402.             case NET_NNTP_PROTOCOL_RESPONSECODE_NO_ARTICLE_SELECTED// 420, RFC977: 'no current article has been selected'
  403.                 return PEAR::throwError('No current article has been selected'$response$this->currentStatusResponse());
  404.                 break;
  405.             case NET_NNTP_PROTOCOL_RESPONSECODE_NO_NEXT_ARTICLE// 421, RFC977: 'no next article in this group'
  406.                 return PEAR::throwError('No next article in this group'$response$this->currentStatusResponse());
  407.                 break;
  408.             default:
  409.                 return $this->_handleUnexpectedResponse($response);
  410.         }
  411.     }
  412.  
  413.     // }}}
  414.     // {{{ cmdLast()
  415.  
  416.     /**
  417.      * 
  418.      *
  419.      * @return 
  420.      * @access protected
  421.      */
  422.     function cmdLast($ret = 0)
  423.     {
  424.         // 
  425.         $response $this->_sendCommand('LAST');
  426.         if (PEAR::isError($response)) {
  427.             return $response;
  428.         }
  429.  
  430.         switch ($response{
  431.             case NET_NNTP_PROTOCOL_RESPONSECODE_ARTICLE_SELECTED// 223, RFC977: 'n a article retrieved - request text separately (n = article number, a = unique article id)'
  432.                 $response_arr split(' 'trim($this->currentStatusResponse()));
  433.  
  434.                 $data = array('number' => (int) $response_arr[0],
  435.                           'id' =>  (string) $response_arr[1]);
  436.  
  437.                 switch ($ret{
  438.                     case 0:
  439.                         return $data;
  440.                         break;
  441.                     case 1:
  442.                         return $data['number'];
  443.                         break;
  444.                     case 2:
  445.                         return $data['id'];
  446.                         break;
  447.                 }
  448.                 break;
  449.             case NET_NNTP_PROTOCOL_RESPONSECODE_NO_GROUP_SELECTED// 412, RFC977: 'no newsgroup selected'
  450.                 return PEAR::throwError('No newsgroup has been selected'$response$this->currentStatusResponse());
  451.                 break;
  452.             case NET_NNTP_PROTOCOL_RESPONSECODE_NO_ARTICLE_SELECTED// 420, RFC977: 'no current article has been selected'
  453.                 return PEAR::throwError('No current article has been selected'$response$this->currentStatusResponse());
  454.                 break;
  455.             case NET_NNTP_PROTOCOL_RESPONSECODE_NO_PREVIOUS_ARTICLE// 422, RFC977: 'no previous article in this group'
  456.                 return PEAR::throwError('No previous article in this group'$response$this->currentStatusResponse());
  457.                 break;
  458.             default:
  459.                 return $this->_handleUnexpectedResponse($response);
  460.         }
  461.     }
  462.  
  463.     // }}}
  464.     // {{{ cmdStat
  465.  
  466.     /**
  467.      * 
  468.      *
  469.      * @param mixed $article 
  470.      *
  471.      * @return mixed (???) ??? on success or (object) pear_error on failure
  472.      * @access protected
  473.      */
  474.     function cmdStat($article$ret = 0)
  475.     {
  476.         // tell the newsserver we want an article
  477.         $response $this->_sendCommand('STAT '.$article);
  478.         if (PEAR::isError($response)) {
  479.             return $response;
  480.         }
  481.  
  482.         switch ($response{
  483.             case NET_NNTP_PROTOCOL_RESPONSECODE_ARTICLE_SELECTED// 223, RFC977: 'n <a> article retrieved - request text separately' (actually not documented, but copied from the ARTICLE command)
  484.                 $response_arr split(' 'trim($this->currentStatusResponse()));
  485.  
  486.                 $data = array('number' => (int) $response_arr[0],
  487.                           'id' =>  (string) $response_arr[1]);
  488.  
  489.                 switch ($ret{
  490.                     case 0:
  491.                   return $data;
  492.                         break;
  493.                     case 1:
  494.                         return $data['number'];
  495.                         break;
  496.                     case 2:
  497.                         return $data['id'];
  498.                         break;
  499.         }
  500.         
  501.                 break;
  502.             case NET_NNTP_PROTOCOL_RESPONSECODE_NO_GROUP_SELECTED// 412, RFC977: 'no newsgroup has been selected' (actually not documented, but copied from the ARTICLE command)
  503.                 return PEAR::throwError('No newsgroup has been selected'$response$this->currentStatusResponse());
  504.                 break;
  505.             case NET_NNTP_PROTOCOL_RESPONSECODE_NO_SUCH_ARTICLE_NUMBER// 423, RFC977: 'no such article number in this group' (actually not documented, but copied from the ARTICLE command)
  506.                 return PEAR::throwError('No such article number in this group'$response$this->currentStatusResponse());
  507.                 break;
  508.             case NET_NNTP_PROTOCOL_RESPONSECODE_NO_SUCH_ARTICLE_ID// 430, RFC977: 'no such article found' (actually not documented, but copied from the ARTICLE command)
  509.                 return PEAR::throwError('No such article found'$response$this->currentStatusResponse());
  510.                 break;
  511.             default:
  512.                 return $this->_handleUnexpectedResponse($response);
  513.         }
  514.     }
  515.  
  516.     // }}}
  517.     // {{{ cmdArticle()
  518.  
  519.     /**
  520.      * Get an article from the currently open connection.
  521.      *
  522.      * @param mixed $article Either a message-id or a message-number of the article to fetch. If null or '', then use current article.
  523.      *
  524.      * @return mixed (array) article on success or (object) pear_error on failure
  525.      * @access protected
  526.      */
  527.     function cmdArticle($article)
  528.     {
  529.         // tell the newsserver we want an article
  530.         $response $this->_sendCommand('ARTICLE '.$article);
  531.         if (PEAR::isError($response)) {
  532.             return $response;
  533.         }
  534.     
  535.         switch ($response{
  536.             case NET_NNTP_PROTOCOL_RESPONSECODE_ARTICLE_FOLLOWS:  // 220, RFC977: 'n <a> article retrieved - head and body follow (n = article number, <a> = message-id)'
  537.                 $data $this->_getTextResponse();
  538.                 if (PEAR::isError($data)) {
  539.                     return $data;
  540.                 }
  541.                 return $data;
  542.                 break;
  543.             case NET_NNTP_PROTOCOL_RESPONSECODE_NO_GROUP_SELECTED// 412, RFC977: 'no newsgroup has been selected'
  544.                 return PEAR::throwError('No newsgroup has been selected'$response$this->currentStatusResponse());
  545.                 break;
  546.             case NET_NNTP_PROTOCOL_RESPONSECODE_NO_ARTICLE_SELECTED// 420, RFC977: 'no current article has been selected'
  547.                 return PEAR::throwError('No current article has been selected'$response$this->currentStatusResponse());
  548.                 break;
  549.             case NET_NNTP_PROTOCOL_RESPONSECODE_NO_SUCH_ARTICLE_NUMBER// 423, RFC977: 'no such article number in this group'
  550.                 return PEAR::throwError('No such article number in this group'$response$this->currentStatusResponse());
  551.                 break;
  552.             case NET_NNTP_PROTOCOL_RESPONSECODE_NO_SUCH_ARTICLE_ID// 430, RFC977: 'no such article found'
  553.                 return PEAR::throwError('No such article found'$response$this->currentStatusResponse());
  554.                 break;
  555.             default:
  556.                 return $this->_handleUnexpectedResponse($response);
  557.         }
  558.     }
  559.  
  560.     // }}}
  561.     // {{{ cmdHead()
  562.  
  563.     /**
  564.      * Get the headers of an article from the currently open connection.
  565.      *
  566.      * @param mixed $article Either a message-id or a message-number of the article to fetch the headers from. If null or '', then use current article.
  567.      *
  568.      * @return mixed (array) headers on success or (object) pear_error on failure
  569.      * @access protected
  570.      */
  571.     function cmdHead($article)
  572.     {
  573.         // tell the newsserver we want the header of an article
  574.         $response $this->_sendCommand('HEAD '.$article);
  575.         if (PEAR::isError($response)) {
  576.             return $response;
  577.         }
  578.  
  579.         switch ($response{
  580.             case NET_NNTP_PROTOCOL_RESPONSECODE_HEAD_FOLLOWS:     // 221, RFC977: 'n <a> article retrieved - head follows'
  581.                 $data $this->_getTextResponse();
  582.                 if (PEAR::isError($data)) {
  583.                     return $data;
  584.             }
  585.                 return $data;
  586.                 break;
  587.             case NET_NNTP_PROTOCOL_RESPONSECODE_NO_GROUP_SELECTED// 412, RFC977: 'no newsgroup has been selected'
  588.                 return PEAR::throwError('No newsgroup has been selected'$response$this->currentStatusResponse());
  589.                 break;
  590.             case NET_NNTP_PROTOCOL_RESPONSECODE_NO_ARTICLE_SELECTED// 420, RFC977: 'no current article has been selected'
  591.                 return PEAR::throwError('No current article has been selected'$response$this->currentStatusResponse());
  592.                 break;
  593.             case NET_NNTP_PROTOCOL_RESPONSECODE_NO_SUCH_ARTICLE_NUMBER// 423, RFC977: 'no such article number in this group'
  594.                 return PEAR::throwError('No such article number in this group'$response$this->currentStatusResponse());
  595.                 break;
  596.             case NET_NNTP_PROTOCOL_RESPONSECODE_NO_SUCH_ARTICLE_ID// 430, RFC977: 'no such article found'
  597.                 return PEAR::throwError('No such article found'$response$this->currentStatusResponse());
  598.                 break;
  599.             default:
  600.                 return $this->_handleUnexpectedResponse($response);
  601.         }
  602.     }
  603.  
  604.     // }}}
  605.     // {{{ cmdBody()
  606.  
  607.     /**
  608.      * Get the body of an article from the currently open connection.
  609.      *
  610.      * @param mixed $article Either a message-id or a message-number of the article to fetch the body from. If null or '', then use current article.
  611.      *
  612.      * @return mixed (array) body on success or (object) pear_error on failure
  613.      * @access protected
  614.      */
  615.     function cmdBody($article)
  616.     {
  617.         // tell the newsserver we want the body of an article
  618.         $response $this->_sendCommand('BODY '.$article);
  619.         if (PEAR::isError($response)) {
  620.             return $response;
  621.         }
  622.  
  623.         switch ($response{
  624.             case NET_NNTP_PROTOCOL_RESPONSECODE_BODY_FOLLOWS:     // 222, RFC977: 'n <a> article retrieved - body follows'
  625.                 $data $this->_getTextResponse();
  626.                 if (PEAR::isError($data)) {
  627.                     return $data;
  628.                 }
  629.                 return $data;
  630.                 break;
  631.             case NET_NNTP_PROTOCOL_RESPONSECODE_NO_GROUP_SELECTED// 412, RFC977: 'no newsgroup has been selected'
  632.                 return PEAR::throwError('No newsgroup has been selected'$response$this->currentStatusResponse());
  633.                 break;
  634.             case NET_NNTP_PROTOCOL_RESPONSECODE_NO_ARTICLE_SELECTED// 420, RFC977: 'no current article has been selected'
  635.                 return PEAR::throwError('No current article has been selected'$response$this->currentStatusResponse());
  636.                 break;
  637.             case NET_NNTP_PROTOCOL_RESPONSECODE_NO_SUCH_ARTICLE_NUMBER// 423, RFC977: 'no such article number in this group'
  638.                 return PEAR::throwError('No such article number in this group'$response$this->currentStatusResponse());
  639.                 break;
  640.             case NET_NNTP_PROTOCOL_RESPONSECODE_NO_SUCH_ARTICLE_ID// 430, RFC977: 'no such article found'
  641.                 return PEAR::throwError('No such article found'$response$this->currentStatusResponse());
  642.                 break;
  643.             default:
  644.                 return $this->_handleUnexpectedResponse($response);
  645.         }
  646.     }
  647.  
  648.     // }}}
  649.     // {{{ cmdPost()
  650.  
  651.     /**
  652.      * Post an article to a newsgroup.
  653.      *
  654.      * Among the aditional headers you might think of adding could be:
  655.      * "NNTP-Posting-Host: <ip-of-author>", which should contain the IP-adress
  656.      * of the author of the post, so the message can be traced back to him.
  657.      * "Organization: <org>" which contain the name of the organization
  658.      * the post originates from.
  659.      *
  660.      * @param string $newsgroup The newsgroup to post to.
  661.      * @param string $subject The subject of the post.
  662.      * @param string $body The body of the post itself.
  663.      * @param string $from Name + email-adress of sender.
  664.      * @param optional string $aditional Aditional headers to send.
  665.      *
  666.      * @return mixed (bool) true on success or (object) pear_error on failure
  667.      * @access protected
  668.      */
  669.     function cmdPost($newsgroup$subject$body$from$aditional '')
  670.     {
  671.         // tell the newsserver we want to post an article
  672.         $response $this->_sendCommand('POST');
  673.         if (PEAR::isError($response)) {
  674.             return $response;
  675.         }
  676.  
  677.     if ($response == NET_NNTP_PROTOCOL_RESPONSECODE_POSTING_SEND// 340, RFC977: 'send article to be posted. End with <CR-LF>.<CR-LF>'
  678.  
  679.             // should be presented in the format specified by RFC850
  680.         
  681.             $this->_socket->write("Newsgroups: $newsgroup\r\n");
  682.             $this->_socket->write("Subject: $subject\r\n");
  683.             $this->_socket->write("From: $from\r\n");
  684.             $this->_socket->write("X-poster: PEAR::Net_NNTP\r\n");
  685.             $this->_socket->write("$aditional\r\n");
  686.             $this->_socket->write("\r\n");
  687.             $this->_socket->write("$body\r\n");
  688.             $this->_socket->write(".\r\n");
  689.  
  690.             // Retrive server's response.
  691.             $response $this->_getStatusResponse();
  692.             if (PEAR::isError($response)) {
  693.                 return $response;
  694.             }
  695.         }
  696.  
  697.         switch ($response{
  698.             case NET_NNTP_PROTOCOL_RESPONSECODE_POSTING_SUCCESS// 240, RFC977: 'article posted ok'
  699.                 return true;
  700.                 break;
  701.             case NET_NNTP_PROTOCOL_RESPONSECODE_POSTING_SEND// 340, RFC977: 'send article to be posted. End with <CR-LF>.<CR-LF>'
  702.                 // This should not happen here!
  703.                 return PEAR::throwError('Unknown error during post'$response$this->currentStatusResponse());
  704.                 break;
  705.             case NET_NNTP_PROTOCOL_RESPONSECODE_POSTING_PROHIBITED// 440, RFC977: 'posting not allowed'
  706.                 return PEAR::throwError('Posting not allowed'$response$this->currentStatusResponse());
  707.                 break;
  708.             case NET_NNTP_PROTOCOL_RESPONSECODE_POSTING_FAILURE// 441, RFC977: 'posting failed'
  709.                 return PEAR::throwError('Posting failed'$response$this->currentStatusResponse());
  710.                 break;
  711.             default:
  712.                 return $this->_handleUnexpectedResponse($response);
  713.         }
  714.     }
  715.  
  716.     // }}}
  717.     // {{{ cmdGroup()
  718.  
  719.     /**
  720.      * Selects a news group (issue a GROUP command to the server)
  721.      *
  722.      * @param string $newsgroup The newsgroup name
  723.      *
  724.      * @return mixed (array) groupinfo on success or (object) pear_error on failure
  725.      * @access protected
  726.      */
  727.     function cmdGroup($newsgroup)
  728.     {
  729.         $response $this->_sendCommand('GROUP '.$newsgroup);
  730.         if (PEAR::isError($response)) {
  731.             return $response;
  732.         }
  733.  
  734.         switch ($response{
  735.             case NET_NNTP_PROTOCOL_RESPONSECODE_GROUP_SELECTED// 211, RFC977: 'n f l s group selected'
  736.                 $response_arr split(' 'trim($this->currentStatusResponse()));
  737.  
  738.                 $data = array();
  739.                 $data['count'$response_arr[0];
  740.                 $data['first'$response_arr[1];
  741.                 $data['last']  $response_arr[2];
  742.                 $data['group'$response_arr[3];
  743.  
  744.                 return $data;
  745.                 break;
  746.             case NET_NNTP_PROTOCOL_RESPONSECODE_NO_SUCH_GROUP// 411, RFC977: 'no such news group'
  747.                 return PEAR::throwError('No such news group'$response$this->currentStatusResponse());
  748.                 break;
  749.             default:
  750.                 return $this->_handleUnexpectedResponse($response);
  751.         }
  752.     }
  753.  
  754.     // }}}
  755.     // {{{ cmdList()
  756.  
  757.     /**
  758.      * Fetches a list of all avaible newsgroups
  759.      *
  760.      * @return mixed (array) nested array with informations about existing newsgroups on success or (object) pear_error on failure
  761.      * @access protected
  762.      */
  763.     function cmdList()
  764.     {
  765.         $response $this->_sendCommand('LIST');
  766.         if (PEAR::isError($response)){
  767.             return $response;
  768.         }
  769.  
  770.         switch ($response{
  771.             case NET_NNTP_PROTOCOL_RESPONSECODE_GROUPS_FOLLOW// 215, RFC977: 'list of newsgroups follows'
  772.                 $data $this->_getTextResponse();
  773.                 if (PEAR::isError($data)) {
  774.                     return $data;
  775.                 }
  776.                 foreach($data as $line{
  777.                     $arr explode(' 'trim($line));
  778.  
  779.                     $group = array('group' => $arr[0],
  780.                                    'last' => $arr[1],
  781.                                    'first' => $arr[2],
  782.                                    'posting' => $arr[3]);
  783.  
  784.                     $groups[$group['group']] $group;
  785.                 }
  786.                 return $groups;
  787.                 break;
  788.             default:
  789.                 return $this->_handleUnexpectedResponse($response);
  790.         }
  791.     }
  792.  
  793.     // }}}
  794.     // {{{ cmdListNewsgroups()
  795.  
  796.     /**
  797.      * Fetches a list of (all) avaible newsgroup descriptions.
  798.      *
  799.      * @param string $wildmat Wildmat of the groups, that is to be listed, defaults to null;
  800.      *
  801.      * @return mixed (array) nested array with description of existing newsgroups on success or (object) pear_error on failure
  802.      * @access protected
  803.      */
  804.     function cmdListNewsgroups($wildmat = null)
  805.     {
  806.         if (is_null($wildmat)) {
  807.             $command 'LIST NEWSGROUPS';
  808.         else {
  809.             $command 'LIST NEWSGROUPS ' $wildmat;
  810.         }
  811.  
  812.         $response $this->_sendCommand($command);
  813.         if (PEAR::isError($response)){
  814.             return $response;
  815.         }
  816.  
  817.         switch ($response{
  818.             case NET_NNTP_PROTOCOL_RESPONSECODE_GROUPS_FOLLOW// 215, RFC2980: 'information follows'
  819.                 $data $this->_getTextResponse();
  820.                 if (PEAR::isError($data)) {
  821.                     return $data;
  822.                 }
  823.  
  824.                 foreach($data as $line{
  825.                     preg_match("/^(.*?)\s(.*?$)/"trim($line)$matches);
  826.                     $groups[$matches[1]] = (string) $matches[2];
  827.                 }
  828.  
  829.                 return $groups;
  830.             break;
  831.             case 503: // RFC2980: 'program error, function not performed'
  832.                 return PEAR::throwError('Internal server error, function not performed'$response$this->currentStatusResponse());
  833.                 break;
  834.             default:
  835.                 return $this->_handleUnexpectedResponse($response);
  836.         }
  837.     }
  838.  
  839.     // }}}
  840.     /**
  841.      * Fetches a list of (all) avaible newsgroup descriptions.
  842.      * Depresated as of RFC2980.
  843.      *
  844.      * @param string $wildmat Wildmat of the groups, that is to be listed, defaults to '*';
  845.      *
  846.      * @return mixed (array) nested array with description of existing newsgroups on success or (object) pear_error on failure
  847.      * @access protected
  848.      */
  849.     function cmdXGTitle($wildmat '*')
  850.     {
  851.         $response $this->_sendCommand('XGTITLE '.$wildmat);
  852.         if (PEAR::isError($response)){
  853.             return $response;
  854.         }
  855.  
  856.         switch ($response{
  857.             case 282: // RFC2980: 'list of groups and descriptions follows'
  858.                 $data $this->_getTextResponse();
  859.                 if (PEAR::isError($data)) {
  860.                     return $data;
  861.                 }
  862.  
  863.                 foreach($data as $line{
  864.                     preg_match("/^(.*?)\s(.*?$)/"trim($line)$matches);
  865.                     $groups[$matches[1]] = (string) $matches[2];
  866.                 }
  867.  
  868.                 return $groups;
  869.                 break;
  870.           
  871.             case 481: // RFC2980: 'Groups and descriptions unavailable'
  872.                 return PEAR::throwError('Groups and descriptions unavailable'$response$this->currentStatusResponse());
  873.                 break;
  874.             default:
  875.                 return $this->_handleUnexpectedResponse($response);
  876.         }
  877.     }
  878.  
  879.     // }}}
  880.     // {{{ cmdNewgroups()
  881.  
  882.     /**
  883.      * Fetches a list of all newsgroups created since a specified date.
  884.      *
  885.      * @param int $time Last time you checked for groups (timestamp).
  886.      * @param optional string $distributions
  887.      *
  888.      * @return mixed (array) nested array with informations about existing newsgroups on success or (object) pear_error on failure
  889.      * @access protected
  890.      */
  891.     function cmdNewgroups($time$distributions = null)
  892.     {
  893.     $date date('ymd His'$time);
  894.  
  895.         if (is_null($distributions)) {
  896.             $command 'NEWGROUPS ' $date ' GMT';
  897.         else {
  898.             $command 'NEWGROUPS ' $date ' GMT <' $distributions '>';
  899.         }
  900.  
  901.         $response $this->_sendCommand($command);
  902.         if (PEAR::isError($response)){
  903.             return $response;
  904.         }
  905.  
  906.         switch ($response{
  907.             case NET_NNTP_PROTOCOL_RESPONSECODE_NEW_GROUPS_FOLLOW// 231, REF977: 'list of new newsgroups follows'
  908.                 $groups = array();
  909.                 foreach($this->_getTextResponse(as $line{
  910.                     $arr explode(' '$line);
  911.                     $groups[$arr[0]]['group'$arr[0];
  912.                     $groups[$arr[0]]['last'$arr[1];
  913.                     $groups[$arr[0]]['first'$arr[2];
  914.                     $groups[$arr[0]]['posting'$arr[3];
  915.                 }
  916.                 return $groups;
  917.                 break;
  918.             default:
  919.                 return $this->_handleUnexpectedResponse($response);
  920.         }
  921.     }
  922.  
  923.     // }}}
  924.     // {{{ cmdListOverviewFmt()
  925.  
  926.     /**
  927.      * Returns a list of avaible headers which are send from newsserver to client for every news message
  928.      *
  929.      * @return mixed (array) of header names on success or (object) pear_error on failure
  930.      * @access protected
  931.      */
  932.     function cmdListOverviewFmt()
  933.     {
  934.         $response $this->_sendCommand('LIST OVERVIEW.FMT');
  935.         if (PEAR::isError($response)){
  936.             return $response;
  937.         }
  938.  
  939.         switch ($response{
  940.             case NET_NNTP_PROTOCOL_RESPONSECODE_GROUPS_FOLLOW// 215, RFC2980: 'information follows'
  941.                 $data $this->_getTextResponse();
  942.                 if (PEAR::isError($data)) {
  943.                     return $data;
  944.                 }
  945.  
  946.                 $format = array('number');
  947.                 // XXX Use the splitHeaders() algorithm for supporting
  948.                 //     multiline headers?
  949.                 foreach ($data as $line{
  950.                     $line explode(':'trim($line));
  951.                     $format[$line[0];
  952.                 }
  953.                 return $format;
  954.                 break;
  955.             case 503: // RFC2980: 'program error, function not performed'
  956.                 return PEAR::throwError('Internal server error, function not performed'$response$this->currentStatusResponse());
  957.                 break;
  958.             default:
  959.                 return $this->_handleUnexpectedResponse($response);
  960.         }
  961.     }
  962.  
  963.     // }}}
  964.     // {{{ cmdXOver()
  965.  
  966.     /**
  967.      * Fetch message header from message number $first until $last
  968.      *
  969.      * The format of the returned array is:
  970.      * $messages[message_id][header_name]
  971.      *
  972.      * @param optional string $range articles to fetch
  973.      *
  974.      * @return mixed (array) nested array of message and there headers on success or (object) pear_error on failure
  975.      * @access protected
  976.      */
  977.     function cmdXOver($range = null)
  978.     {
  979.     // deprecated API (the code _is_ still in alpha state)
  980.         if (func_num_args(> 1 {
  981.             die('The second parameter in cmdXOver() has been deprecated! Use x-y instead...');
  982.         }
  983.  
  984.         $format $this->cmdListOverviewFmt();
  985.         if (PEAR::isError($format)){
  986.             return $formt;
  987.         }
  988.  
  989.         if (is_null($range)) {
  990.         $command 'XOVER';
  991.         else {
  992.             $command 'XOVER ' $range;
  993.         }
  994.  
  995.         $response $this->_sendCommand($command);
  996.         if (PEAR::isError($response)){
  997.             return $response;
  998.         }
  999.  
  1000.         switch ($response{
  1001.             case NET_NNTP_PROTOCOL_RESPONSECODE_OVERVIEW_FOLLOWS// 224, RFC2980: 'Overview information follows'
  1002.                 $data $this->_getTextResponse();
  1003.                 if (PEAR::isError($data)) {
  1004.                     return $data;
  1005.                 }
  1006.                 $messages = array();
  1007.                 foreach($data as $line{
  1008.                     $i=0;
  1009.                     foreach(explode("\t"trim($line)) as $line{
  1010.                         $message[$format[$i++]] $line;
  1011.                     }
  1012.                     $messages[$message['Message-ID']] $message;
  1013.                 }
  1014.                 return $messages;
  1015.                 break;
  1016.             case NET_NNTP_PROTOCOL_RESPONSECODE_NO_GROUP_SELECTED// 412, RFC2980: 'No news group current selected'
  1017.                 return PEAR::throwError('No news group current selected'$response$this->currentStatusResponse());
  1018.                 break;
  1019.             case NET_NNTP_PROTOCOL_RESPONSECODE_NO_ARTICLE_SELECTED// 420, RFC2980: 'No article(s) selected'
  1020.                 return PEAR::throwError('No article(s) selected'$response$this->currentStatusResponse());
  1021.                 break;
  1022.             case 502: // RFC2980: 'no permission'
  1023.                 return PEAR::throwError('No permission'$response$this->currentStatusResponse());
  1024.                 break;
  1025.             default:
  1026.                 return $this->_handleUnexpectedResponse($response);
  1027.         }
  1028.     }
  1029.     
  1030.     // }}}
  1031.     // {{{ cmdXROver()
  1032.  
  1033.     /**
  1034.      * Fetch message references from message number $first to $last
  1035.      *
  1036.      * @param optional string $range articles to fetch
  1037.      *
  1038.      * @return mixed (array) assoc. array of message references on success or (object) pear_error on failure
  1039.      * @access protected
  1040.      */
  1041.     function cmdXROver($range = null)
  1042.     {
  1043.     // Warn about deprecated API (the code _is_ still in alpha state)
  1044.         if (func_num_args(> 1 {
  1045.             die('The second parameter in cmdXROver() has been deprecated! Use x-y instead...');
  1046.         }
  1047.  
  1048.         if (is_null($range)) {
  1049.         $command 'XROVER';
  1050.         else {
  1051.             $command 'XROVER ' $range;
  1052.         }
  1053.  
  1054.         $response $this->_sendCommand($command);
  1055.         if (PEAR::isError($response)){
  1056.             return $response;
  1057.         }
  1058.  
  1059.         switch ($response{
  1060.             case NET_NNTP_PROTOCOL_RESPONSECODE_OVERVIEW_FOLLOWS// 224, RFC2980: 'Overview information follows'
  1061.                 $data $this->_getTextResponse();
  1062.                 if (PEAR::isError($data)) {
  1063.                     return $data;
  1064.                 }
  1065.  
  1066.                 foreach($data as $line{
  1067.  
  1068.                     $references preg_split("/ +/"trim($line)-1PREG_SPLIT_NO_EMPTY);
  1069.  
  1070.                     $id array_shift($references);
  1071.  
  1072.                     $messages[$id$references;
  1073.                 }
  1074.                 return $messages;
  1075.                 break;
  1076.             case NET_NNTP_PROTOCOL_RESPONSECODE_NO_GROUP_SELECTED// 412, RFC2980: 'No news group current selected'
  1077.                 return PEAR::throwError('No news group current selected'$response$this->currentStatusResponse());
  1078.                 break;
  1079.             case NET_NNTP_PROTOCOL_RESPONSECODE_NO_ARTICLE_SELECTED// 420, RFC2980: 'No article(s) selected'
  1080.                 return PEAR::throwError('No article(s) selected'$response$this->currentStatusResponse());
  1081.                 break;
  1082.             case 502: // RFC2980: 'no permission'
  1083.                 return PEAR::throwError('No permission'$response$this->currentStatusResponse());
  1084.                 break;
  1085.             default:
  1086.                 return $this->_handleUnexpectedResponse($response);
  1087.         }
  1088.     }
  1089.  
  1090.     // }}}
  1091.     // {{{ cmdListgroup()
  1092.  
  1093.     /**
  1094.      *
  1095.      *
  1096.      * @param string $newsgroup 
  1097.      *
  1098.      * @return optional mixed (array) on success or (object) pear_error on failure
  1099.      * @access protected
  1100.      */
  1101.     function cmdListgroup($newsgroup = null)
  1102.     {
  1103.  
  1104.         if (is_null($range)) {
  1105.         $command 'LISTGROUP';
  1106.     else {
  1107.             $command 'LISTGROUP ' $newsgroup;
  1108.         }
  1109.  
  1110.         $response $this->_sendCommand($command);
  1111.         if (PEAR::isError($response)){
  1112.             return $response;
  1113.         }
  1114.  
  1115.         switch ($response{
  1116.             case NET_NNTP_PROTOCOL_RESPONSECODE_GROUP_SELECTED// 211, RFC2980: 'list of article numbers follow'
  1117.  
  1118.                 $articles $this->_getTextResponse();
  1119.                 if (PEAR::isError($articles)) {
  1120.                     return $articles;
  1121.                 }
  1122.  
  1123.                 $data = array('count' => $response_arr[0],
  1124.                               'first' => $response_arr[1],
  1125.                               'last' => $response_arr[2],
  1126.                               'group' => $response_arr[3],
  1127.                               'articles' => $articles);
  1128.  
  1129.                 return $data;
  1130.                 break;
  1131.             case NET_NNTP_PROTOCOL_RESPONSECODE_NO_GROUP_SELECTED// 412, RFC2980: 'Not currently in newsgroup'
  1132.                 return PEAR::throwError('Not currently in newsgroup'$response$this->currentStatusResponse());
  1133.                 break;
  1134.             case 502: // RFC2980: 'no permission'
  1135.                 return PEAR::throwError('No permission'$response$this->currentStatusResponse());
  1136.                 break;
  1137.             default:
  1138.                 return $this->_handleUnexpectedResponse($response);
  1139.         }
  1140.     }
  1141.  
  1142.     // }}}
  1143.     // {{{ cmdNewnews()
  1144.  
  1145.     /**
  1146.      *
  1147.      *
  1148.      * @param timestamp $time 
  1149.      * @param mixed $newsgroups (string or array of strings)
  1150.      * @param mixed $distribution (string or array of strings)
  1151.      *
  1152.      * @return mixed 
  1153.      * @access protected
  1154.      */
  1155.     function cmdNewnews($time$newsgroups$distribution = null)
  1156.     {
  1157.         $date date('ymd His'$time);
  1158.  
  1159.         if (is_array()) {
  1160.             $newsgroups implode(','$newsgroups);
  1161.         }
  1162.     
  1163.  
  1164.         if (is_null($distribution)) {
  1165.             $command 'NEWNEWS ' $newsgroups ' ' $date ' GMT';
  1166.         else {
  1167.             if (is_array()) {
  1168.             $distribution implode(','$distribution);
  1169.             }
  1170.  
  1171.             $command 'NEWNEWS ' $newsgroups ' ' $date ' GMT <' $distribution '>';
  1172.         }
  1173.  
  1174.     // TODO: the lenght of the request string may not exceed 510 chars
  1175.     
  1176.         $response $this->_sendCommand($command);
  1177.         if (PEAR::isError($response)){
  1178.             return $response;
  1179.         }
  1180.  
  1181.         switch ($response{
  1182.             case NET_NNTP_PROTOCOL_RESPONSECODE_NEW_ARTICLES_FOLLOW// 230, RFC977: 'list of new articles by message-id follows'
  1183.                 $messages = array();
  1184.                 foreach($this->_getTextResponse(as $line{
  1185.                     $messages[$line;
  1186.                 }
  1187.                 return $messages;
  1188.                 break;
  1189.             default:
  1190.                 return $this->_handleUnexpectedResponse($response);
  1191.         }
  1192.     }
  1193.  
  1194.     // }}}
  1195.     // {{{ cmdDate()
  1196.  
  1197.     /**
  1198.      * Get the date from the newsserver format of returned date
  1199.      *
  1200.      * @param bool $timestap when false function returns string, and when true function returns int/timestamp.
  1201.      *
  1202.      * @return mixed (string) 'YYYYMMDDhhmmss' / (int) timestamp on success or (object) pear_error on failure
  1203.      * @access protected
  1204.      */
  1205.     function cmdDate($timestamp = false)
  1206.     {
  1207.         $response $this->_sendCommand('DATE');
  1208.         if (PEAR::isError($response)){
  1209.             return $response;
  1210.         }
  1211.  
  1212.         switch ($response{
  1213.             case NET_NNTP_PROTOCOL_RESPONSECODE_SERVER_DATE// 111, RFC2980: 'YYYYMMDDhhmmss'
  1214.                 $d $this->currentStatusResponse();
  1215.                 if ($timestamp === false{
  1216.                     return (string) $d;        
  1217.                 else {
  1218.                     return (int) strtotime(substr($d08).' '.$d[8].$d[9].':'.$d[10].$d[11].':'.$d[12].$d[13]);
  1219.                 }
  1220.                 break;
  1221.             default:
  1222.                 return $this->_handleUnexpectedResponse($response);
  1223.         }
  1224.     }
  1225.     // }}}
  1226.     // {{{ isConnected()
  1227.  
  1228.     /**
  1229.      * Test whether we are connected or not.
  1230.      *
  1231.      * @return bool true or false
  1232.      * @access protected
  1233.      */
  1234.     function isConnected()
  1235.     {
  1236.         return (is_resource($this->_socket->fp&& (!$this->_socket->eof()));
  1237.     }
  1238.  
  1239.     // }}}
  1240.     // {{{ setDebug()
  1241.  
  1242.     /**
  1243.      * Sets the debuging information on or off
  1244.      *
  1245.      * @param boolean $debug True or false
  1246.      *
  1247.      * @return bool previos state
  1248.      * @access protected
  1249.      */
  1250.     function setDebug($debug = true)
  1251.     {
  1252.         $tmp $this->_debug;
  1253.         $this->_debug $debug;
  1254.         return $tmp;
  1255.     }
  1256.  
  1257.     // }}}
  1258.     // {{{ _handleUnexpectedResponse()
  1259.  
  1260.     /**
  1261.      *
  1262.      *
  1263.      * @param int $code Status code number
  1264.      * @param string $text Status text
  1265.      *
  1266.      * @return mixed 
  1267.      * @access private
  1268.      */
  1269.     function _handleUnexpectedResponse($code = null$text = null)
  1270.     {
  1271.         if ($code === null{
  1272.             $code $this->_currentStatusResponse[0];
  1273.     }
  1274.  
  1275.         if ($text === null{
  1276.             $text $this->currentStatusResponse();
  1277.     }
  1278.  
  1279.         return PEAR::throwError('Unexpected response'$code$text);
  1280.     }
  1281.  
  1282.     // }}}
  1283.     // {{{ _getStatusResponse()
  1284.  
  1285.     /**
  1286.      * Get servers status response after a command.
  1287.      *
  1288.      * @return mixed (int) statuscode on success or (object) pear_error on failure
  1289.      * @access private
  1290.      */
  1291.     function _getStatusResponse()
  1292.     {
  1293.         // Retrieve a line (terminated by "\r\n") from the server.
  1294.         $response $this->_socket->gets(256);
  1295.         if (PEAR::isError($response) ) {
  1296.             return PEAR::throwError('Failed to read from socket!'null$response->getMessage());
  1297.         }
  1298.  
  1299.         if ($this->_debug{
  1300.             echo "S: $response\r\n";
  1301.         }
  1302.  
  1303.         // Trim the start of the response in case of misplased whitespace (should not be needen!!!)
  1304.         $response ltrim($response);
  1305.  
  1306.         $this->_currentStatusResponse = array(
  1307.                                               (int) substr($response03),
  1308.                                               (string) rtrim(substr($response4))
  1309.                                              );
  1310.  
  1311.         return $this->_currentStatusResponse[0];
  1312.     }
  1313.     
  1314.     // }}}
  1315.     // {{{ currentStatusResponse()
  1316.  
  1317.     /**
  1318.      *
  1319.      *
  1320.      * @return string status text
  1321.      * @access private
  1322.      */
  1323.     function currentStatusResponse()
  1324.     {
  1325.         return $this->_currentStatusResponse[1];
  1326.     }
  1327.     
  1328.     // }}}
  1329.     // {{{ _getTextResponse()
  1330.  
  1331.     /**
  1332.      * Retrieve textural data
  1333.      *
  1334.      * Get data until a line with only a '.' in it is read and return data.
  1335.      *
  1336.      * @return mixed (array) text response on success or (object) pear_error on failure
  1337.      * @access private
  1338.      */
  1339.     function _getTextResponse()
  1340.     {
  1341.         $data = array();
  1342.         $line '';
  1343.     
  1344.         // Continue until connection is lost
  1345.         while(!$this->_socket->eof()) {
  1346.  
  1347.             // Retrieve and append up to 1024 characters from the server.
  1348.             $line .= $this->_socket->gets(1024)
  1349.             if (PEAR::isError($line) ) {
  1350.                 return PEAR::throwError'Failed to read from socket!'null$line->getMessage());
  1351.             }
  1352.         
  1353.             // Continue if the line is not terminated by CRLF
  1354.             if (substr($line-2!= "\r\n" || strlen($line< 2{
  1355.                 continue;
  1356.             }
  1357.  
  1358.             // Validate recieved line
  1359.             if (false{
  1360.                 // Lines should/may not be longer than 998+2 chars (RFC2822 2.3)
  1361.                 if (strlen($line> 1000{
  1362.                     return PEAR::throwError('Invalid line recieved!'null);
  1363.                 }
  1364.             }
  1365.  
  1366.             // Remove CRLF from the end of the line
  1367.             $line substr($line0-2);
  1368.  
  1369.             // Check if the line terminates the textresponse
  1370.             if ($line == '.'{
  1371.                 // return all previous lines
  1372.                 return $data;
  1373.                 break;
  1374.             }
  1375.  
  1376.             // If 1st char is '.' it's doubled (NNTP/RFC977 2.4.1)
  1377.             if (substr($line02== '..'{
  1378.                 $line substr($line1);
  1379.             }
  1380.             
  1381.             // Add the line to the array of lines
  1382.             $data[$line;
  1383.  
  1384.             // Reset/empty $line
  1385.             $line '';
  1386.         }
  1387.  
  1388.         return PEAR::throwError('Data stream not terminated with period'null);
  1389.     }
  1390.  
  1391.     // }}}
  1392.     // {{{ _sendCommand()
  1393.  
  1394.     /**
  1395.      * Send command
  1396.      *
  1397.      * Send a command to the server. A carriage return / linefeed (CRLF) sequence
  1398.      * will be appended to each command string before it is sent to the IMAP server.
  1399.      *
  1400.      * @param string $cmd The command to launch, ie: "ARTICLE 1004853"
  1401.      *
  1402.      * @return mixed (int) response code on success or (object) pear_error on failure
  1403.      * @access private
  1404.      */
  1405.     function _sendCommand($cmd)
  1406.     {
  1407.         // NNTP/RFC977 only allows command up to 512 (-2) chars.
  1408.         if (!strlen($cmd> 510{
  1409.             return PEAR::throwError('Failed to write to socket! (Command to long - max 510 chars)');
  1410.         }
  1411.  
  1412.         // Check if connected
  1413.         if (!$this->isConnected()) {
  1414.             return PEAR::throwError('Failed to write to socket! (connection lost!)');
  1415.         }
  1416.  
  1417.         // Send the command
  1418.         $R $this->_socket->writeLine($cmd);
  1419.         if PEAR::isError($R) ) {
  1420.             return PEAR::throwError('Failed to write to socket!'null$R->getMessage());
  1421.         }
  1422.     
  1423.         if ($this->_debug{
  1424.             echo "C: $cmd\r\n";
  1425.         }
  1426.  
  1427.         return $this->_getStatusResponse();
  1428.     }
  1429.     
  1430.     // }}}
  1431.  
  1432. }
  1433.  
  1434. // }}}
  1435.  
  1436. ?>

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