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

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