PageRenderTime 60ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/www/lib/Net_NNTP/NNTP/Client.php

https://github.com/vikjon0/newznab
PHP | 1549 lines | 524 code | 187 blank | 838 comment | 119 complexity | fccc847a882bbfbb286739cee08ce790 MD5 | raw file
Possible License(s): GPL-3.0
  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
  3. /**
  4. *
  5. *
  6. * PHP versions 4 and 5
  7. *
  8. * <pre>
  9. * +-----------------------------------------------------------------------+
  10. * | |
  11. * | W3CÆ SOFTWARE NOTICE AND LICENSE |
  12. * | http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231 |
  13. * | |
  14. * | This work (and included software, documentation such as READMEs, |
  15. * | or other related items) is being provided by the copyright holders |
  16. * | under the following license. By obtaining, using and/or copying |
  17. * | this work, you (the licensee) agree that you have read, understood, |
  18. * | and will comply with the following terms and conditions. |
  19. * | |
  20. * | Permission to copy, modify, and distribute this software and its |
  21. * | documentation, with or without modification, for any purpose and |
  22. * | without fee or royalty is hereby granted, provided that you include |
  23. * | the following on ALL copies of the software and documentation or |
  24. * | portions thereof, including modifications: |
  25. * | |
  26. * | 1. The full text of this NOTICE in a location viewable to users |
  27. * | of the redistributed or derivative work. |
  28. * | |
  29. * | 2. Any pre-existing intellectual property disclaimers, notices, |
  30. * | or terms and conditions. If none exist, the W3C Software Short |
  31. * | Notice should be included (hypertext is preferred, text is |
  32. * | permitted) within the body of any redistributed or derivative |
  33. * | code. |
  34. * | |
  35. * | 3. Notice of any changes or modifications to the files, including |
  36. * | the date changes were made. (We recommend you provide URIs to |
  37. * | the location from which the code is derived.) |
  38. * | |
  39. * | THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT |
  40. * | HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, |
  41. * | INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR |
  42. * | FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE |
  43. * | OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY PATENTS, |
  44. * | COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. |
  45. * | |
  46. * | COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, |
  47. * | SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE |
  48. * | SOFTWARE OR DOCUMENTATION. |
  49. * | |
  50. * | The name and trademarks of copyright holders may NOT be used in |
  51. * | advertising or publicity pertaining to the software without |
  52. * | specific, written prior permission. Title to copyright in this |
  53. * | software and any associated documentation will at all times |
  54. * | remain with copyright holders. |
  55. * | |
  56. * +-----------------------------------------------------------------------+
  57. * </pre>
  58. *
  59. * @category Net
  60. * @package Net_NNTP
  61. * @author Heino H. Gehlsen <heino@gehlsen.dk>
  62. * @copyright 2002-2005 Heino H. Gehlsen <heino@gehlsen.dk>. All Rights Reserved.
  63. * @license http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231 W3CÆ SOFTWARE NOTICE AND LICENSE
  64. * @version CVS: $Id: Client.php 302639 2010-08-22 16:14:38Z heino $
  65. * @link http://pear.php.net/package/Net_NNTP
  66. * @see
  67. *
  68. * @filesource
  69. */
  70. /**
  71. *
  72. */
  73. require_once 'Protocol/Client.php';
  74. // {{{ Net_NNTP_Client
  75. /**
  76. * Implementation of the client side of NNTP (Network News Transfer Protocol)
  77. *
  78. * The Net_NNTP_Client class is a frontend class to the Net_NNTP_Protocol_Client class.
  79. *
  80. * @category Net
  81. * @package Net_NNTP
  82. * @version package: 1.5.0a1 (alpha)
  83. * @version api: 0.8.1 (alpha)
  84. * @access public
  85. * @see Net_NNTP_Protocol_Client
  86. */
  87. class Net_NNTP_Client extends Net_NNTP_Protocol_Client
  88. {
  89. // {{{ properties
  90. /**
  91. * Information summary about the currently selected group.
  92. *
  93. * @var array
  94. * @access private
  95. */
  96. var $_selectedGroupSummary = null;
  97. /**
  98. *
  99. *
  100. * @var array
  101. * @access private
  102. * @since 1.3.0
  103. */
  104. var $_overviewFormatCache = null;
  105. // }}}
  106. // {{{ constructor
  107. /**
  108. * Constructor
  109. *
  110. * <b>Usage example:</b>
  111. * {@example docs/examples/phpdoc/constructor.php}
  112. *
  113. * @access public
  114. */
  115. function Net_NNTP_Client()
  116. {
  117. parent::Net_NNTP_Protocol_Client();
  118. }
  119. // }}}
  120. // {{{ connect()
  121. /**
  122. * Connect to a server.
  123. *
  124. * xxx
  125. *
  126. * <b>Usage example:</b>
  127. * {@example docs/examples/phpdoc/connect.php}
  128. *
  129. * @param string $host (optional) The hostname og IP-address of the NNTP-server to connect to, defaults to localhost.
  130. * @param mixed $encryption (optional) false|'tls'|'ssl', defaults to false.
  131. * @param int $port (optional) The port number to connect to, defaults to 119 or 563 dependng on $encryption.
  132. * @param int $timeout (optional)
  133. *
  134. * @return mixed <br>
  135. * - (bool) True when posting allowed, otherwise false
  136. * - (object) Pear_Error on failure
  137. * @access public
  138. * @see Net_NNTP_Client::disconnect()
  139. * @see Net_NNTP_Client::authenticate()
  140. */
  141. function connect($host = null, $encryption = null, $port = null, $timeout = null)
  142. {
  143. // v1.0.x API
  144. if (is_int($encryption)) {
  145. trigger_error('You are using deprecated API v1.0 in Net_NNTP_Client: connect() !', E_USER_NOTICE);
  146. $port = $encryption;
  147. $encryption = null;
  148. }
  149. return parent::connect($host, $encryption, $port, $timeout);
  150. }
  151. // }}}
  152. // {{{ disconnect()
  153. /**
  154. * Disconnect from server.
  155. *
  156. * @return mixed <br>
  157. * - (bool)
  158. * - (object) Pear_Error on failure
  159. * @access public
  160. * @see Net_NNTP_Client::connect()
  161. */
  162. function disconnect()
  163. {
  164. return parent::disconnect();
  165. }
  166. // }}}
  167. // {{{ quit()
  168. /**
  169. * Deprecated alias for disconnect().
  170. *
  171. * @access public
  172. * @deprecated
  173. * @ignore
  174. */
  175. function quit()
  176. {
  177. return $this->disconnect();
  178. }
  179. // }}}
  180. // {{{ authenticate()
  181. /**
  182. * Authenticate.
  183. *
  184. * xxx
  185. *
  186. * <b>Non-standard!</b><br>
  187. * This method uses non-standard commands, which is not part
  188. * of the original RFC977, but has been formalized in RFC2890.
  189. *
  190. * <b>Usage example:</b>
  191. * {@example docs/examples/phpdoc/authenticate.php}
  192. *
  193. * @param string $user The username
  194. * @param string $pass The password
  195. *
  196. * @return mixed <br>
  197. * - (bool) True on successful authentification, otherwise false
  198. * - (object) Pear_Error on failure
  199. * @access public
  200. * @see Net_NNTP_Client::connect()
  201. */
  202. function authenticate($user, $pass)
  203. {
  204. // Username is a must...
  205. if ($user == null) {
  206. return $this->throwError('No username supplied', null);
  207. }
  208. return $this->cmdAuthinfo($user, $pass);
  209. }
  210. // }}}
  211. // {{{ selectGroup()
  212. /**
  213. * Selects a group.
  214. *
  215. * Moves the servers 'currently selected group' pointer to the group
  216. * a new group, and returns summary information about it.
  217. *
  218. * <b>Non-standard!</b><br>
  219. * When using the second parameter,
  220. * This method uses non-standard commands, which is not part
  221. * of the original RFC977, but has been formalized in RFC2890.
  222. *
  223. * <b>Usage example:</b>
  224. * {@example docs/examples/phpdoc/selectGroup.php}
  225. *
  226. * @param string $group Name of the group to select
  227. * @param mixed $articles (optional) experimental! When true the article numbers is returned in 'articles'
  228. *
  229. * @return mixed <br>
  230. * - (array) Summary about the selected group
  231. * - (object) Pear_Error on failure
  232. * @access public
  233. * @see Net_NNTP_Client::getGroups()
  234. * @see Net_NNTP_Client::group()
  235. * @see Net_NNTP_Client::first()
  236. * @see Net_NNTP_Client::last()
  237. * @see Net_NNTP_Client::count()
  238. */
  239. function selectGroup($group, $articles = false)
  240. {
  241. // Select group (even if $articles is set, since many servers does not select groups when the listgroup command is run)
  242. $summary = $this->cmdGroup($group);
  243. if (PEAR::isError($summary)) {
  244. return $summary;
  245. }
  246. // Store group info in the object
  247. $this->_selectedGroupSummary = $summary;
  248. //
  249. if ($articles !== false) {
  250. $summary2 = $this->cmdListgroup($group, ($articles === true ? null : $articles));
  251. if (PEAR::isError($summary2)) {
  252. return $summary2;
  253. }
  254. // Make sure the summary array is correct...
  255. if ($summary2['group'] == $group) {
  256. $summary = $summary2;
  257. // ... even if server does not include summary in status reponce.
  258. } else {
  259. $summary['articles'] = $summary2['articles'];
  260. }
  261. }
  262. return $summary;
  263. }
  264. // }}}
  265. // {{{ selectPreviousArticle()
  266. /**
  267. * Select the previous article.
  268. *
  269. * Select the previous article in current group.
  270. *
  271. * <b>Usage example:</b>
  272. * {@example docs/examples/phpdoc/selectPreviousArticle.php}
  273. *
  274. * @param int $_ret (optional) Experimental
  275. *
  276. * @return mixed <br>
  277. * - (integer) Article number, if $ret=0 (default)
  278. * - (string) Message-id, if $ret=1
  279. * - (array) Both article number and message-id, if $ret=-1
  280. * - (bool) False if no prevoius article exists
  281. * - (object) Pear_Error on failure
  282. * @access public
  283. * @see Net_NNTP_Client::selectArticle()
  284. * @see Net_NNTP_Client::selectNextArticle()
  285. */
  286. function selectPreviousArticle($_ret = 0)
  287. {
  288. $response = $this->cmdLast();
  289. if (PEAR::isError($response)) {
  290. return false;
  291. }
  292. switch ($_ret) {
  293. case -1:
  294. return array('Number' => (int) $response[0], 'Message-ID' => (string) $response[1]);
  295. break;
  296. case 0:
  297. return (int) $response[0];
  298. break;
  299. case 1:
  300. return (string) $response[1];
  301. break;
  302. default:
  303. error(); // ...
  304. }
  305. }
  306. // }}}
  307. // {{{ selectNextArticle()
  308. /**
  309. * Select the next article.
  310. *
  311. * Select the next article in current group.
  312. *
  313. * <b>Usage example:</b>
  314. * {@example docs/examples/phpdoc/selectNextArticle.php}
  315. *
  316. * @param int $_ret (optional) Experimental
  317. *
  318. * @return mixed <br>
  319. * - (integer) Article number, if $ret=0 (default)
  320. * - (string) Message-id, if $ret=1
  321. * - (array) Both article number and message-id, if $ret=-1
  322. * - (bool) False if no further articles exist
  323. * - (object) Pear_Error on unexpected failure
  324. * @access public
  325. * @see Net_NNTP_Client::selectArticle()
  326. * @see Net_NNTP_Client::selectPreviousArticle()
  327. */
  328. function selectNextArticle($_ret = 0)
  329. {
  330. $response = $this->cmdNext();
  331. if (PEAR::isError($response)) {
  332. return $response;
  333. }
  334. switch ($_ret) {
  335. case -1:
  336. return array('Number' => (int) $response[0], 'Message-ID' => (string) $response[1]);
  337. break;
  338. case 0:
  339. return (int) $response[0];
  340. break;
  341. case 1:
  342. return (string) $response[1];
  343. break;
  344. default:
  345. error(); // ...
  346. }
  347. }
  348. // }}}
  349. // {{{ selectArticle()
  350. /**
  351. * Selects an article by article message-number.
  352. *
  353. * xxx
  354. *
  355. * <b>Usage example:</b>
  356. * {@example docs/examples/phpdoc/selectArticle.php}
  357. *
  358. * @param mixed $article The message-number (on the server) of
  359. * the article to select as current article.
  360. * @param int $_ret (optional) Experimental
  361. *
  362. * @return mixed <br>
  363. * - (integer) Article number
  364. * - (bool) False if article doesn't exists
  365. * - (object) Pear_Error on failure
  366. * @access public
  367. * @see Net_NNTP_Client::selectNextArticle()
  368. * @see Net_NNTP_Client::selectPreviousArticle()
  369. */
  370. function selectArticle($article = null, $_ret = 0)
  371. {
  372. $response = $this->cmdStat($article);
  373. if (PEAR::isError($response)) {
  374. return $response;
  375. }
  376. switch ($ret) {
  377. case -1:
  378. return array('Number' => (int) $response[0], 'Message-ID' => (string) $response[1]);
  379. break;
  380. case 0:
  381. return (int) $response[0];
  382. break;
  383. case 1:
  384. return (string) $response[1];
  385. break;
  386. default:
  387. error(); // ...
  388. }
  389. }
  390. // }}}
  391. // {{{ getArticle()
  392. /**
  393. * Fetch article into transfer object.
  394. *
  395. * Select an article based on the arguments, and return the entire
  396. * article (raw data).
  397. *
  398. * <b>Usage example:</b>
  399. * {@example docs/examples/phpdoc/getArticle.php}
  400. *
  401. * @param mixed $article (optional) Either the message-id or the
  402. * message-number on the server of the
  403. * article to fetch.
  404. * @param bool $implode (optional) When true the result array
  405. * is imploded to a string, defaults to
  406. * false.
  407. *
  408. * @return mixed <br>
  409. * - (array) Complete article (when $implode is false)
  410. * - (string) Complete article (when $implode is true)
  411. * - (object) Pear_Error on failure
  412. * @access public
  413. * @see Net_NNTP_Client::getHeader()
  414. * @see Net_NNTP_Client::getBody()
  415. */
  416. function getArticle($article = null, $implode = false)
  417. {
  418. // v1.1.x API
  419. if (is_string($implode)) {
  420. trigger_error('You are using deprecated API v1.1 in Net_NNTP_Client: getHeader() !', E_USER_NOTICE);
  421. $class = $implode;
  422. $implode = false;
  423. if (!class_exists($class)) {
  424. return $this->throwError("Class '$class' does not exist!");
  425. }
  426. }
  427. $data = $this->cmdArticle($article);
  428. if (PEAR::isError($data)) {
  429. return $data;
  430. }
  431. if ($implode == true) {
  432. $data = implode("\r\n", $data);
  433. }
  434. // v1.1.x API
  435. if (isset($class)) {
  436. return $obj = new $class($data);
  437. }
  438. //
  439. return $data;
  440. }
  441. // }}}
  442. // {{{ getHeader()
  443. /**
  444. * Fetch article header.
  445. *
  446. * Select an article based on the arguments, and return the article
  447. * header (raw data).
  448. *
  449. * <b>Usage example:</b>
  450. * {@example docs/examples/phpdoc/getHeader.php}
  451. *
  452. * @param mixed $article (optional) Either message-id or message
  453. * number of the article to fetch.
  454. * @param bool $implode (optional) When true the result array
  455. * is imploded to a string, defaults to
  456. * false.
  457. *
  458. * @return mixed <br>
  459. * - (bool) False if article does not exist
  460. * - (array) Header fields (when $implode is false)
  461. * - (string) Header fields (when $implode is true)
  462. * - (object) Pear_Error on failure
  463. * @access public
  464. * @see Net_NNTP_Client::getArticle()
  465. * @see Net_NNTP_Client::getBody()
  466. */
  467. function getHeader($article = null, $implode = false)
  468. {
  469. // v1.1.x API
  470. if (is_string($implode)) {
  471. trigger_error('You are using deprecated API v1.1 in Net_NNTP_Client: getHeader() !', E_USER_NOTICE);
  472. $class = $implode;
  473. $implode = false;
  474. if (!class_exists($class)) {
  475. return $this->throwError("Class '$class' does not exist!");
  476. }
  477. }
  478. $data = $this->cmdHead($article);
  479. if (PEAR::isError($data)) {
  480. return $data;
  481. }
  482. if ($implode == true) {
  483. $data = implode("\r\n", $data);
  484. }
  485. // v1.1.x API
  486. if (isset($class)) {
  487. return $obj = new $class($data);
  488. }
  489. //
  490. return $data;
  491. }
  492. // }}}
  493. // {{{ getBody()
  494. /**
  495. * Fetch article body.
  496. *
  497. * Select an article based on the arguments, and return the article
  498. * body (raw data).
  499. *
  500. * <b>Usage example:</b>
  501. * {@example docs/examples/phpdoc/getBody.php}
  502. *
  503. * @param mixed $article (optional) Either the message-id or the
  504. * message-number on the server of the
  505. * article to fetch.
  506. * @param bool $implode (optional) When true the result array
  507. * is imploded to a string, defaults to
  508. * false.
  509. *
  510. * @return mixed <br>
  511. * - (array) Message body (when $implode is false)
  512. * - (string) Message body (when $implode is true)
  513. * - (object) Pear_Error on failure
  514. * @access public
  515. * @see Net_NNTP_Client::getHeader()
  516. * @see Net_NNTP_Client::getArticle()
  517. */
  518. function getBody($article = null, $implode = false)
  519. {
  520. // v1.1.x API
  521. if (is_string($implode)) {
  522. trigger_error('You are using deprecated API v1.1 in Net_NNTP_Client: getHeader() !', E_USER_NOTICE);
  523. $class = $implode;
  524. $implode = false;
  525. if (!class_exists($class)) {
  526. return $this->throwError("Class '$class' does not exist!");
  527. }
  528. }
  529. $data = $this->cmdBody($article);
  530. if (PEAR::isError($data)) {
  531. return $data;
  532. }
  533. if ($implode == true) {
  534. $data = implode("\r\n", $data);
  535. }
  536. // v1.1.x API
  537. if (isset($class)) {
  538. return $obj = new $class($data);
  539. }
  540. //
  541. return $data;
  542. }
  543. // }}}
  544. // {{{ post()
  545. /**
  546. * Post a raw article to a number of groups.
  547. *
  548. * <b>Usage example:</b>
  549. * {@example docs/examples/phpdoc/post.php}
  550. *
  551. * @param mixed $article <br>
  552. * - (string) Complete article in a ready to send format (lines terminated by LFCR etc.)
  553. * - (array) First key is the article header, second key is article body - any further keys are ignored !!!
  554. * - (mixed) Something 'callable' (which must return otherwise acceptable data as replacement)
  555. *
  556. * @return mixed <br>
  557. * - (string) Server response
  558. * - (object) Pear_Error on failure
  559. * @access public
  560. * @ignore
  561. */
  562. function post($article)
  563. {
  564. // API v1.0
  565. if (func_num_args() >= 4) {
  566. //
  567. trigger_error('You are using deprecated API v1.0 in Net_NNTP_Client: post() !', E_USER_NOTICE);
  568. //
  569. $groups = func_get_arg(0);
  570. $subject = func_get_arg(1);
  571. $body = func_get_arg(2);
  572. $from = func_get_arg(3);
  573. $additional = func_get_arg(4);
  574. return $this->mail($groups, $subject, $body, "From: $from\r\n" . $additional);
  575. }
  576. // Only accept $article if array or string
  577. if (!is_array($article) && !is_string($article)) {
  578. return $this->throwError('Ups', null, 0);
  579. }
  580. // Check if server will receive an article
  581. $post = $this->cmdPost();
  582. if (PEAR::isError($post)) {
  583. return $post;
  584. }
  585. // Get article data from callback function
  586. if (is_callable($article)) {
  587. $article = call_user_func($article);
  588. }
  589. // Actually send the article
  590. return $this->cmdPost2($article);
  591. }
  592. // }}}
  593. // {{{ mail()
  594. /**
  595. * Post an article to a number of groups - using same parameters as PHP's mail() function.
  596. *
  597. * Among the aditional headers you might think of adding could be:
  598. * "From: <author-email-address>", which should contain the e-mail address
  599. * of the author of the article.
  600. * Or "Organization: <org>" which contain the name of the organization
  601. * the post originates from.
  602. * Or "NNTP-Posting-Host: <ip-of-author>", which should contain the IP-address
  603. * of the author of the post, so the message can be traced back to him.
  604. *
  605. * <b>Usage example:</b>
  606. * {@example docs/examples/phpdoc/mail.php}
  607. *
  608. * @param string $groups The groups to post to.
  609. * @param string $subject The subject of the article.
  610. * @param string $body The body of the article.
  611. * @param string $additional (optional) Additional header fields to send.
  612. *
  613. * @return mixed <br>
  614. * - (string) Server response
  615. * - (object) Pear_Error on failure
  616. * @access public
  617. */
  618. function mail($groups, $subject, $body, $additional = null)
  619. {
  620. // Check if server will receive an article
  621. $post = $this->cmdPost();
  622. if (PEAR::isError($post)) {
  623. return $post;
  624. }
  625. // Construct header
  626. $header = "Newsgroups: $groups\r\n";
  627. $header .= "Subject: $subject\r\n";
  628. $header .= "X-poster: PEAR::Net_NNTP v@package_version@ (@package_state@)\r\n";
  629. if ($additional !== null) {
  630. $header .= $additional;
  631. }
  632. $header .= "\r\n";
  633. // Actually send the article
  634. return $this->cmdPost2(array($header, $body));
  635. }
  636. // }}}
  637. // {{{ getDate()
  638. /**
  639. * Get the server's internal date
  640. *
  641. * <b>Non-standard!</b><br>
  642. * This method uses non-standard commands, which is not part
  643. * of the original RFC977, but has been formalized in RFC2890.
  644. *
  645. * <b>Usage example:</b>
  646. * {@example docs/examples/phpdoc/getDate.php}
  647. *
  648. * @param int $format (optional) Determines the format of returned date:
  649. * - 0: return string
  650. * - 1: return integer/timestamp
  651. * - 2: return an array('y'=>year, 'm'=>month,'d'=>day)
  652. *
  653. * @return mixed <br>
  654. * - (mixed)
  655. * - (object) Pear_Error on failure
  656. * @access public
  657. */
  658. function getDate($format = 1)
  659. {
  660. $date = $this->cmdDate();
  661. if (PEAR::isError($date)) {
  662. return $date;
  663. }
  664. switch ($format) {
  665. case 0:
  666. return $date;
  667. break;
  668. case 1:
  669. return strtotime(substr($date, 0, 8).' '.substr($date, 8, 2).':'.substr($date, 10, 2).':'.substr($date, 12, 2));
  670. break;
  671. case 2:
  672. return array('y' => substr($date, 0, 4),
  673. 'm' => substr($date, 4, 2),
  674. 'd' => substr($date, 6, 2));
  675. break;
  676. default:
  677. error();
  678. }
  679. }
  680. // }}}
  681. // {{{ getNewGroups()
  682. /**
  683. * Get new groups since a date.
  684. *
  685. * Returns a list of groups created on the server since the specified date
  686. * and time.
  687. *
  688. * <b>Usage example:</b>
  689. * {@example docs/examples/phpdoc/getNewGroups.php}
  690. *
  691. * @param mixed $time <br>
  692. * - (integer) A timestamp
  693. * - (string) Somthing parseable by strtotime() like '-1 week'
  694. * @param string $distributions (optional)
  695. *
  696. * @return mixed <br>
  697. * - (array)
  698. * - (object) Pear_Error on failure
  699. * @access public
  700. */
  701. function getNewGroups($time, $distributions = null)
  702. {
  703. switch (true) {
  704. case is_integer($time):
  705. break;
  706. case is_string($time):
  707. $time = strtotime($time);
  708. if ($time === false || ($time === -1 && version_compare(php_version(), '5.1.0', '<'))) {
  709. return $this->throwError('$time could not be converted into a timestamp!', null, 0);
  710. }
  711. break;
  712. default:
  713. trigger_error('$time must be either a string or an integer/timestamp!', E_USER_ERROR);
  714. }
  715. return $this->cmdNewgroups($time, $distributions);
  716. }
  717. // }}}
  718. // {{{ getNewArticles()
  719. /**
  720. * Get new articles since a date.
  721. *
  722. * Returns a list of message-ids of new articles (since the specified date
  723. * and time) in the groups whose names match the wildmat
  724. *
  725. * <b>Usage example:</b>
  726. * {@example docs/examples/phpdoc/getNewArticles.php}
  727. *
  728. * @param mixed $time <br>
  729. * - (integer) A timestamp
  730. * - (string) Somthing parseable by strtotime() like '-1 week'
  731. * @param string $groups (optional)
  732. * @param string $distributions (optional)
  733. *
  734. * @return mixed <br>
  735. * - (array)
  736. * - (object) Pear_Error on failure
  737. * @access public
  738. * @since 1.3.0
  739. */
  740. function getNewArticles($time, $groups = '*', $distribution = null)
  741. {
  742. switch (true) {
  743. case is_integer($time):
  744. break;
  745. case is_string($time):
  746. $time = strtotime($time);
  747. if ($time === false || ($time === -1 && version_compare(php_version(), '5.1.0', '<'))) {
  748. return $this->throwError('$time could not be converted into a timestamp!', null, 0);
  749. }
  750. break;
  751. default:
  752. trigger_error('$time must be either a string or an integer/timestamp!', E_USER_ERROR);
  753. }
  754. return $this->cmdNewnews($time, $groups, $distribution);
  755. }
  756. // }}}
  757. // {{{ getGroups()
  758. /**
  759. * Fetch valid groups.
  760. *
  761. * Returns a list of valid groups (that the client is permitted to select)
  762. * and associated information.
  763. *
  764. * <b>Usage example:</b>
  765. * {@example docs/examples/phpdoc/getGroups.php}
  766. *
  767. * @return mixed <br>
  768. * - (array) Nested array with information about every valid group
  769. * - (object) Pear_Error on failure
  770. * @access public
  771. * @see Net_NNTP_Client::getDescriptions()
  772. * @see Net_NNTP_Client::selectGroup()
  773. */
  774. function getGroups($wildmat = null)
  775. {
  776. $backup = false;
  777. // Get groups
  778. $groups = $this->cmdListActive($wildmat);
  779. if (PEAR::isError($groups)) {
  780. switch ($groups->getCode()) {
  781. case 500:
  782. case 501:
  783. $backup = true;
  784. break;
  785. default:
  786. return $groups;
  787. }
  788. }
  789. //
  790. if ($backup == true) {
  791. //
  792. if (!is_null($wildmat)) {
  793. return $this->throwError("The server does not support the 'LIST ACTIVE' command, and the 'LIST' command does not support the wildmat parameter!", null, null);
  794. }
  795. //
  796. $groups2 = $this->cmdList();
  797. if (PEAR::isError($groups2)) {
  798. // Ignore...
  799. } else {
  800. $groups = $groups2;
  801. }
  802. }
  803. if (PEAR::isError($groups)) {
  804. return $groups;
  805. }
  806. return $groups;
  807. }
  808. // }}}
  809. // {{{ getDescriptions()
  810. /**
  811. * Fetch all known group descriptions.
  812. *
  813. * Fetches a list of known group descriptions - including groups which
  814. * the client is not permitted to select.
  815. *
  816. * <b>Non-standard!</b><br>
  817. * This method uses non-standard commands, which is not part
  818. * of the original RFC977, but has been formalized in RFC2890.
  819. *
  820. * <b>Usage example:</b>
  821. * {@example docs/examples/phpdoc/getDescriptions.php}
  822. *
  823. * @param mixed $wildmat (optional)
  824. *
  825. * @return mixed <br>
  826. * - (array) Associated array with descriptions of known groups
  827. * - (object) Pear_Error on failure
  828. * @access public
  829. * @see Net_NNTP_Client::getGroups()
  830. */
  831. function getDescriptions($wildmat = null)
  832. {
  833. if (is_array($wildmat)) {
  834. $wildmat = implode(',', $wildmat);
  835. }
  836. // Get group descriptions
  837. $descriptions = $this->cmdListNewsgroups($wildmat);
  838. if (PEAR::isError($descriptions)) {
  839. return $descriptions;
  840. }
  841. // TODO: add xgtitle as backup
  842. return $descriptions;
  843. }
  844. // }}}
  845. // {{{ getOverview()
  846. /**
  847. * Fetch an overview of article(s) in the currently selected group.
  848. *
  849. * Returns the contents of all the fields in the database for a number
  850. * of articles specified by either article-numnber range, a message-id,
  851. * or nothing (indicating currently selected article).
  852. *
  853. * The first 8 fields per article is always as follows:
  854. * - 'Number' - '0' or the article number of the currently selected group.
  855. * - 'Subject' - header content.
  856. * - 'From' - header content.
  857. * - 'Date' - header content.
  858. * - 'Message-ID' - header content.
  859. * - 'References' - header content.
  860. * - ':bytes' - metadata item.
  861. * - ':lines' - metadata item.
  862. *
  863. * The server may send more fields form it's database...
  864. *
  865. * <b>Non-standard!</b><br>
  866. * This method uses non-standard commands, which is not part
  867. * of the original RFC977, but has been formalized in RFC2890.
  868. *
  869. * <b>Usage example:</b>
  870. * {@example docs/examples/phpdoc/getOverview.php}
  871. *
  872. * @param mixed $range (optional)
  873. * - '<message number>'
  874. * - '<message number>-<message number>'
  875. * - '<message number>-'
  876. * - '<message-id>'
  877. * @param boolean $_names (optional) experimental parameter! Use field names as array kays
  878. * @param boolean $_forceNames (optional) experimental parameter!
  879. *
  880. * @return mixed <br>
  881. * - (array) Nested array of article overview data
  882. * - (object) Pear_Error on failure
  883. * @access public
  884. * @see Net_NNTP_Client::getHeaderField()
  885. * @see Net_NNTP_Client::getOverviewFormat()
  886. */
  887. function getOverview($range = null, $_names = true, $_forceNames = true)
  888. {
  889. // API v1.0
  890. switch (true) {
  891. // API v1.3
  892. case func_num_args() != 2:
  893. case is_bool(func_get_arg(1)):
  894. case !is_int(func_get_arg(1)) || (is_string(func_get_arg(1)) && ctype_digit(func_get_arg(1))):
  895. case !is_int(func_get_arg(0)) || (is_string(func_get_arg(0)) && ctype_digit(func_get_arg(0))):
  896. break;
  897. default:
  898. //
  899. trigger_error('You are using deprecated API v1.0 in Net_NNTP_Client: getOverview() !', E_USER_NOTICE);
  900. // Fetch overview via API v1.3
  901. $overview = $this->getOverview(func_get_arg(0) . '-' . func_get_arg(1), true, false);
  902. if (PEAR::isError($overview)) {
  903. return $overview;
  904. }
  905. // Create and return API v1.0 compliant array
  906. $articles = array();
  907. foreach ($overview as $article) {
  908. // Rename 'Number' field into 'number'
  909. $article = array_merge(array('number' => array_shift($article)), $article);
  910. // Use 'Message-ID' field as key
  911. $articles[$article['Message-ID']] = $article;
  912. }
  913. return $articles;
  914. }
  915. // Fetch overview from server
  916. $overview = $this->cmdXOver($range);
  917. if (PEAR::isError($overview)) {
  918. return $overview;
  919. }
  920. // Use field names from overview format as keys?
  921. if ($_names) {
  922. // Already cached?
  923. if (is_null($this->_overviewFormatCache)) {
  924. // Fetch overview format
  925. $format = $this->getOverviewFormat($_forceNames, true);
  926. if (PEAR::isError($format)){
  927. return $format;
  928. }
  929. // Prepend 'Number' field
  930. $format = array_merge(array('Number' => false), $format);
  931. // Cache format
  932. $this->_overviewFormatCache = $format;
  933. //
  934. } else {
  935. $format = $this->_overviewFormatCache;
  936. }
  937. // Loop through all articles
  938. foreach ($overview as $key => $article) {
  939. // Copy $format
  940. $f = $format;
  941. // Field counter
  942. $i = 0;
  943. // Loop through forld names in format
  944. foreach ($f as $tag => $full) {
  945. //
  946. $f[$tag] = $article[$i++];
  947. // If prefixed by field name, remove it
  948. if ($full === true) {
  949. $f[$tag] = ltrim( substr($f[$tag], strpos($f[$tag], ':') + 1), " \t");
  950. }
  951. }
  952. // Replace article
  953. $overview[$key] = $f;
  954. }
  955. }
  956. //
  957. switch (true) {
  958. // Expect one article
  959. case is_null($range);
  960. case is_int($range);
  961. case is_string($range) && ctype_digit($range):
  962. case is_string($range) && substr($range, 0, 1) == '<' && substr($range, -1, 1) == '>':
  963. if (count($overview) == 0) {
  964. return false;
  965. } else {
  966. return reset($overview);
  967. }
  968. break;
  969. // Expect multiple articles
  970. default:
  971. return $overview;
  972. }
  973. }
  974. // }}}
  975. // {{{ getOverviewFormat()
  976. /**
  977. * Fetch names of fields in overview database
  978. *
  979. * Returns a description of the fields in the database for which it is consistent.
  980. *
  981. * <b>Non-standard!</b><br>
  982. * This method uses non-standard commands, which is not part
  983. * of the original RFC977, but has been formalized in RFC2890.
  984. *
  985. * <b>Usage example:</b>
  986. * {@example docs/examples/phpdoc/getOveriewFormat.php}
  987. *
  988. * @return mixed <br>
  989. * - (array) Overview field names
  990. * - (object) Pear_Error on failure
  991. * @access public
  992. * @see Net_NNTP_Client::getOverview()
  993. */
  994. function getOverviewFormat($_forceNames = true, $_full = false)
  995. {
  996. $format = $this->cmdListOverviewFmt();
  997. if (PEAR::isError($format)) {
  998. return $format;
  999. }
  1000. // Force name of first seven fields
  1001. if ($_forceNames) {
  1002. array_splice($format, 0, 7);
  1003. $format = array_merge(array('Subject' => false,
  1004. 'From' => false,
  1005. 'Date' => false,
  1006. 'Message-ID' => false,
  1007. 'References' => false,
  1008. ':bytes' => false,
  1009. ':lines' => false), $format);
  1010. }
  1011. if ($_full) {
  1012. return $format;
  1013. } else {
  1014. return array_keys($format);
  1015. }
  1016. }
  1017. // }}}
  1018. // {{{ getHeaderField()
  1019. /**
  1020. * Fetch content of a header field from message(s).
  1021. *
  1022. * Retreives the content of specific header field from a number of messages.
  1023. *
  1024. * <b>Non-standard!</b><br>
  1025. * This method uses non-standard commands, which is not part
  1026. * of the original RFC977, but has been formalized in RFC2890.
  1027. *
  1028. * <b>Usage example:</b>
  1029. * {@example docs/examples/phpdoc/getHeaderField.php}
  1030. *
  1031. * @param string $field The name of the header field to retreive
  1032. * @param mixed $range (optional)
  1033. * '<message number>'
  1034. * '<message number>-<message number>'
  1035. * '<message number>-'
  1036. * '<message-id>'
  1037. *
  1038. * @return mixed <br>
  1039. * - (array) Nested array of
  1040. * - (object) Pear_Error on failure
  1041. * @access public
  1042. * @see Net_NNTP_Client::getOverview()
  1043. * @see Net_NNTP_Client::getReferences()
  1044. */
  1045. function getHeaderField($field, $range = null)
  1046. {
  1047. $fields = $this->cmdXHdr($field, $range);
  1048. if (PEAR::isError($fields)) {
  1049. return $fields;
  1050. }
  1051. //
  1052. switch (true) {
  1053. // Expect one article
  1054. case is_null($range);
  1055. case is_int($range);
  1056. case is_string($range) && ctype_digit($range):
  1057. case is_string($range) && substr($range, 0, 1) == '<' && substr($range, -1, 1) == '>':
  1058. if (count($fields) == 0) {
  1059. return false;
  1060. } else {
  1061. return reset($fields);
  1062. }
  1063. break;
  1064. // Expect multiple articles
  1065. default:
  1066. return $fields;
  1067. }
  1068. }
  1069. // }}}
  1070. // {{{ getGroupArticles()
  1071. /**
  1072. *
  1073. *
  1074. * <b>Non-standard!</b><br>
  1075. * This method uses non-standard commands, which is not part
  1076. * of the original RFC977, but has been formalized in RFC2890.
  1077. *
  1078. * <b>Usage example:</b>
  1079. * {@example docs/examples/phpdoc/getGroupArticles.php}
  1080. *
  1081. * @param mixed $range (optional) Experimental!
  1082. *
  1083. * @return mixed <br>
  1084. * - (array)
  1085. * - (object) Pear_Error on failure
  1086. * @access public
  1087. * @since 1.3.0
  1088. */
  1089. function getGroupArticles($range = null)
  1090. {
  1091. $summary = $this->cmdListgroup();
  1092. if (PEAR::isError($summary)) {
  1093. return $summary;
  1094. }
  1095. // Update summary cache if group was also 'selected'
  1096. if ($summary['group'] !== null) {
  1097. $this->_selectedGroupSummary($summary);
  1098. }
  1099. //
  1100. return $summary['articles'];
  1101. }
  1102. // }}}
  1103. // {{{ getReferences()
  1104. /**
  1105. * Fetch reference header field of message(s).
  1106. *
  1107. * Retrieves the content of the references header field of messages via
  1108. * either the XHDR ord the XROVER command.
  1109. *
  1110. * Identical to getHeaderField('References').
  1111. *
  1112. * <b>Non-standard!</b><br>
  1113. * This method uses non-standard commands, which is not part
  1114. * of the original RFC977, but has been formalized in RFC2890.
  1115. *
  1116. * <b>Usage example:</b>
  1117. * {@example docs/examples/phpdoc/getReferences.php}
  1118. *
  1119. * @param mixed $range (optional)
  1120. * '<message number>'
  1121. * '<message number>-<message number>'
  1122. * '<message number>-'
  1123. * '<message-id>'
  1124. *
  1125. * @return mixed <br>
  1126. * - (array) Nested array of references
  1127. * - (object) Pear_Error on failure
  1128. * @access public
  1129. * @see Net_NNTP_Client::getHeaderField()
  1130. */
  1131. function getReferences($range = null)
  1132. {
  1133. $backup = false;
  1134. $references = $this->cmdXHdr('References', $range);
  1135. if (PEAR::isError($references)) {
  1136. switch ($references->getCode()) {
  1137. case 500:
  1138. case 501:
  1139. $backup = true;
  1140. break;
  1141. default:
  1142. return $references;
  1143. }
  1144. }
  1145. if (true && (is_array($references) && count($references) == 0)) {
  1146. $backup = true;
  1147. }
  1148. if ($backup == true) {
  1149. $references2 = $this->cmdXROver($range);
  1150. if (PEAR::isError($references2)) {
  1151. // Ignore...
  1152. } else {
  1153. $references = $references2;
  1154. }
  1155. }
  1156. if (PEAR::isError($references)) {
  1157. return $references;
  1158. }
  1159. if (is_array($references)) {
  1160. foreach ($references as $key => $val) {
  1161. $references[$key] = preg_split("/ +/", trim($val), -1, PREG_SPLIT_NO_EMPTY);
  1162. }
  1163. }
  1164. //
  1165. switch (true) {
  1166. // Expect one article
  1167. case is_null($range);
  1168. case is_int($range);
  1169. case is_string($range) && ctype_digit($range):
  1170. case is_string($range) && substr($range, 0, 1) == '<' && substr($range, -1, 1) == '>':
  1171. if (count($references) == 0) {
  1172. return false;
  1173. } else {
  1174. return reset($references);
  1175. }
  1176. break;
  1177. // Expect multiple articles
  1178. default:
  1179. return $references;
  1180. }
  1181. }
  1182. // }}}
  1183. // {{{ count()
  1184. /**
  1185. * Number of articles in currently selected group
  1186. *
  1187. * <b>Usage example:</b>
  1188. * {@example docs/examples/phpdoc/count.php}
  1189. *
  1190. * @return mixed <br>
  1191. * - (string) the number of article in group
  1192. * - (object) Pear_Error on failure
  1193. * @access public
  1194. * @see Net_NNTP_Client::group()
  1195. * @see Net_NNTP_Client::first()
  1196. * @see Net_NNTP_Client::last()
  1197. * @see Net_NNTP_Client::selectGroup()
  1198. * @ignore
  1199. */
  1200. function count()
  1201. {
  1202. return $this->_selectedGroupSummary['count'];
  1203. }
  1204. // }}}
  1205. // {{{ last()
  1206. /**
  1207. * Maximum article number in currently selected group
  1208. *
  1209. * <b>Usage example:</b>
  1210. * {@example docs/examples/phpdoc/last.php}
  1211. *
  1212. * @return mixed <br>
  1213. * - (string) the last article's number
  1214. * - (object) Pear_Error on failure
  1215. * @access public
  1216. * @see Net_NNTP_Client::first()
  1217. * @see Net_NNTP_Client::group()
  1218. * @see Net_NNTP_Client::count()
  1219. * @see Net_NNTP_Client::selectGroup()
  1220. * @ignore
  1221. */
  1222. function last()
  1223. {
  1224. return $this->_selectedGroupSummary['last'];
  1225. }
  1226. // }}}
  1227. // {{{ first()
  1228. /**
  1229. * Minimum article number in currently selected group
  1230. *
  1231. * <b>Usage example:</b>
  1232. * {@example docs/examples/phpdoc/first.php}
  1233. *
  1234. * @return mixed <br>
  1235. * - (string) the first article's number
  1236. * - (object) Pear_Error on failure
  1237. * @access public
  1238. * @see Net_NNTP_Client::last()
  1239. * @see Net_NNTP_Client::group()
  1240. * @see Net_NNTP_Client::count()
  1241. * @see Net_NNTP_Client::selectGroup()
  1242. * @ignore
  1243. */
  1244. function first()
  1245. {
  1246. return $this->_selectedGroupSummary['first'];
  1247. }
  1248. // }}}
  1249. // {{{ group()
  1250. /**
  1251. * Currently selected group
  1252. *
  1253. * <b>Usage example:</b>
  1254. * {@example docs/examples/phpdoc/group.php}
  1255. *
  1256. * @return mixed <br>
  1257. * - (string) group name
  1258. * - (object) Pear_Error on failure
  1259. * @access public
  1260. * @see Net_NNTP_Client::first()
  1261. * @see Net_NNTP_Client::last()
  1262. * @see Net_NNTP_Client::count()
  1263. * @see Net_NNTP_Client::selectGroup()
  1264. * @ignore
  1265. */
  1266. function group()
  1267. {
  1268. return $this->_selectedGroupSummary['group'];
  1269. }
  1270. // }}}
  1271. // {{{ isConnected()
  1272. /**
  1273. * Test whether a connection is currently open or closed.
  1274. *
  1275. * @return bool True if connected, otherwise false
  1276. * @access public
  1277. * @see Net_NNTP_Client::connect()
  1278. * @see Net_NNTP_Client::quit()
  1279. * @deprecated since v1.3.0 due to use of protected method: Net_NNTP_Protocol_Client::isConnected()
  1280. * @ignore
  1281. */
  1282. function isConnected()
  1283. {
  1284. trigger_error('You are using deprecated API v1.0 in Net_NNTP_Client: isConnected() !', E_USER_NOTICE);
  1285. return parent::_isConnected();
  1286. }
  1287. // }}}
  1288. // {{{ getArticleRaw()
  1289. /**
  1290. * Deprecated alias for getArticle()
  1291. *
  1292. * @deprecated
  1293. * @ignore
  1294. */
  1295. function getArticleRaw($article, $implode = false)
  1296. {
  1297. trigger_error('You are using deprecated API v1.0 in Net_NNTP_Client: getArticleRaw() !', E_USER_NOTICE);
  1298. return $this->getArticle($article, $implode);
  1299. }
  1300. // }}}
  1301. // {{{ getHeaderRaw()
  1302. /**
  1303. * Deprecated alias for getHeader()
  1304. *
  1305. * @deprecated
  1306. * @ignore
  1307. */
  1308. function getHeaderRaw($article = null, $implode = false)
  1309. {
  1310. trigger_error('You are using deprecated API v1.0 in Net_NNTP_Client: getHeaderRaw() !', E_USER_NOTICE);
  1311. return $this->getHeader($article, $implode);
  1312. }
  1313. // }}}
  1314. // {{{ getBodyRaw()
  1315. /**
  1316. * Deprecated alias for getBody()
  1317. *
  1318. * @deprecated
  1319. * @ignore
  1320. */
  1321. function getBodyRaw($article = null, $implode = false)
  1322. {
  1323. trigger_error('You are using deprecated API v1.0 in Net_NNTP_Client: getBodyRaw() !', E_USER_NOTICE);
  1324. return $this->getBody($article, $implode);
  1325. }
  1326. // }}}
  1327. // {{{ getNewNews()
  1328. /**
  1329. * Deprecated alias for getNewArticles()
  1330. *
  1331. * @deprecated
  1332. * @ignore
  1333. */
  1334. function getNewNews($time, $groups = '*', $distribution = null)
  1335. {
  1336. trigger_error('You are using deprecated API v1.1 in Net_NNTP_Client: getNewNews() !', E_USER_NOTICE);
  1337. return $this->getNewArticles($time, $groups, $distribution);
  1338. }
  1339. // }}}
  1340. // {{{ getReferencesOverview()
  1341. /**
  1342. * Deprecated alias for getReferences()
  1343. *
  1344. * @deprecated
  1345. * @ignore
  1346. */
  1347. function getReferencesOverview($first, $last)
  1348. {
  1349. trigger_error('You are using deprecated API v1.0 in Net_NNTP_Client: getReferencesOverview() !', E_USER_NOTICE);
  1350. return $this->getReferences($first . '-' . $last);
  1351. }
  1352. // }}}
  1353. }
  1354. // }}}
  1355. /*
  1356. * Local variables:
  1357. * tab-width: 4
  1358. * c-basic-offset: 4
  1359. * c-hanging-comment-ender-p: nil
  1360. * End:
  1361. */
  1362. ?>