0byt3m1n1
Path:
/
data
/
applications
/
aps.bak
/
tikiwiki
/
1.9.7-31
/
htdocs
/
lib
/
pear
/
[
Home
]
File: NNTP.php
<?php // // +----------------------------------------------------------------------+ // | PHP Version 4 | // +----------------------------------------------------------------------+ // | Copyright (c) 1997-2002 The PHP Group | // +----------------------------------------------------------------------+ // | This source file is subject to version 2.0 of the PHP license, | // | that is bundled with this package in the file LICENSE, and is | // | available at through the world-wide-web at | // | http://www.php.net/license/2_02.txt. | // | If you did not receive a copy of the PHP license and are unable to | // | obtain it through the world-wide-web, please send a note to | // | license@php.net so we can mail you a copy immediately. | // +----------------------------------------------------------------------+ // | Authors: Martin Kaltoft <martin@nitro.dk> | // | Tomas V.V.Cox <cox@idecnet.com> | // | | // +----------------------------------------------------------------------+ // // $Id: NNTP.php,v 1.1 2003/08/07 01:53:07 rossta Exp $ require_once 'PEAR.php'; define('PEAR_NNTP_ALL', 0); define('PEAR_NNTP_NAMES', 1); define('PEAR_NNTP_LIST', 2); /* NNTP Authentication modes */ define('PEAR_NNTP_AUTHORIGINAL', 'original'); define('PEAR_NNTP_AUTHSIMPLE', 'simple'); define('PEAR_NNTP_AUTHGENERIC', 'generic'); /** * The NNTP:: class fetches UseNet news articles acording to the standard * based on RFC 1036. * * @version 0.2 * @author Martin Kaltoft <martin@nitro.dk> * @author Tomas V.V.Cox <cox@idecnet.com> */ class Net_NNTP extends PEAR { var $max = ''; var $min = ''; var $user = null; var $pass = null; var $authmode = null; /** File pointer of the nntp-connection */ var $fp = null; /** * Output or not debug information * @see Net_Nntp::set_debug() */ var $_debug = false; /** * Connect to the newsserver * * @param string $nntpserver The adress of the NNTP-server to connect to. * @param int $port (optional) the port-number to connect to, defaults to 119. * @param string $user (optional) The user name to authenticate with * @param string $pass (optional) The password * @param string $authmode (optional) The authentication mode * @return mixed True on success or Pear Error object on failure * @see Net_Nntp::authenticate() * @access public */ function connect($nntpserver, $port = 119, $user = null, $pass = null, $authmode = PEAR_NNTP_AUTHORIGINAL) { $fp = @fsockopen($nntpserver, $port, $errno, $errstr, 15); if (!is_resource($fp)) { return $this->raiseError("Could not connect to NNTP-server $nntpserver"); } socket_set_blocking($fp, true); if (!$fp) { return $this->raiseError('Not connected'); } $response = fgets($fp, 128); if ($this->_debug) { print "<< $response\n"; } $this->fp = $fp; $this->user = $user; $this->pass = $pass; $this->authmode = $authmode; return true; } /** * Connect to the newsserver, and issue a GROUP command * Once connection is prepared, we can only fetch articles from one group * at a time, to fetch from another group, a new connection has to be made. * * This is to avoid the GROUP command for every article, as it is very * ressource intensive on the newsserver especially when used for * groups with many articles. * * @param string $nntpserver The adress of the NNTP-server to connect to. * @param int $port (optional) the port-number to connect to, defaults to 119. * @param string $newsgroup The name of the newsgroup to use. * @param string $user (optional) The user name to authenticate with * @param string $pass (optional) The password * @param string $authmode (optional) The authentication mode * @return mixed True on success or Pear Error object on failure * @see Net_Nntp::authenticate() * @access public * @deprecated Use connect() instead */ function prepareConnection($nntpserver, $port = 119, $newsgroup, $user = null, $pass = null, $authmode = PEAR_NNTP_AUTHORIGINAL) { /* connect to the server */ $err = $this->connect($nntpserver, $port, $user, $pass, $authmode); if (PEAR::isError($err)) { return $err; } /* issue a GROUP command */ $r = $this->command("GROUP $newsgroup"); if (PEAR::isError($r) || $this->responseCode($r) > 299) { return $this->raiseError($r); } $response_arr = split(' ', $r); $this->max = $response_arr[3]; $this->min = $response_arr[2]; return true; } /** * @deprecated */ function prepare_connection($nntpserver, $port = 119, $newsgroup, $user = null, $pass = null, $authmode = PEAR_NNTP_AUTHORIGINAL) { return $this->prepareConnection($nntpserver, $port, $newsgroup, $user, $pass, $authmode); } /** * Auth process (not yet standarized but used any way) * http://www.mibsoftware.com/userkt/nntpext/index.html * * @param string $user The user name * @param string $pass (optional) The password if needed * @param string $mode Authinfo form: original, simple, generic * @return mixed (bool) true on success or Pear Error obj on fail * @access public */ function authenticate($user = null, $pass = null, $mode = PEAR_NNTP_AUTHORIGINAL) { if ($user === null) { return $this->raiseError('Authentication required but no user supplied'); } switch ($mode) { case PEAR_NNTP_AUTHORIGINAL: /* 281 Authentication accepted 381 More authentication information required 480 Authentication required 482 Authentication rejected 502 No permission */ $response = $this->command("AUTHINFO user $user", false); if ($this->responseCode($response) != 281) { if ($this->responseCode($response) == 381 && $pass !== null) { $response = $this->command("AUTHINFO pass $pass", false); } } if ($this->responseCode($response) != 281) { return $this->raiseError("Authentication failed: $response"); } return true; break; case PEAR_NNTP_AUTHSIMPLE: case PEAR_NNTP_AUTHGENERIC: default: $this->raiseError("The auth mode: $mode isn't implemented"); } } /** * Get an article from the currently open connection. * To get articles from another newsgroup a new prepare_connection() - * call has to be made with apropriate parameters * * @param mixed $article Either the message-id or the message-number on the server of the article to fetch * @return string the article * @access public */ function getArticle($article) { /* tell the newsserver we want an article */ $r = $this->command("ARTICLE $article"); if (PEAR::isError($r) || $this->responseCode($r) > 299) { return $this->raiseError($r); } $post = null; while (!feof($this->fp)) { $line = trim(fgets($this->fp, 256)); if ($line == ".") { break; } else { $post .= $line ."\n"; } } return $post; } /** * @deprecated */ function get_article($article) { return $this->getArticle($article); } /** * Post an article to a newsgroup. * Among the aditional headers you might think of adding could be: * "NNTP-Posting-Host: <ip-of-author>", which should contain the IP-adress * of the author of the post, so the message can be traced back to him. * Or "Organization: <org>" which contain the name of the organization * the post originates from. * * @param string $subject The subject of the post. * @param string $newsgroup The newsgroup to post to. * @param string $from Name + email-adress of sender. * @param string $body The body of the post itself. * @param string $aditionak (optional) Aditional headers to send. * @return string server response * @access public */ function post($subject, $newsgroup, $from, $body, $aditional = "") { if (!@is_resource($this->fp)) { return $this->raiseError('Not connected'); } /* tell the newsserver we want to post an article */ fputs($this->fp, "POST\n"); /* The servers' response */ $response = trim(fgets($this->fp, 128)); fputs($this->fp, "From: $from\n"); fputs($this->fp, "Newsgroups: $newsgroup\n"); fputs($this->fp, "Subject: $subject\n"); fputs($this->fp, "X-poster: nntp_fetcher (0.1) by Martin Kaltoft\n"); fputs($this->fp, "$aditional\n"); fputs($this->fp, "\n$body\n.\n"); /* The servers' response */ $response = trim(fgets($this->fp, 128)); return $response; } /** * Get the headers of an article from the currently open connection * To get the headers of an article from another newsgroup, a new * prepare_connection()-call has to be made with apropriate parameters * * @param string $article Either a message-id or a message-number of the article to fetch the headers from. * @return array Header * @access public */ function getHeaders($article) { /* tell the newsserver we want an article */ $r = $this->command("HEAD $article"); if (PEAR::isError($r) || $this->responseCode($r) > 299) { return $this->raiseError($r); } $headers = ''; while(!feof($this->fp)) { $line = trim(fgets($this->fp, 256)); if ($line == '.') { break; } else { $headers .= $line . "\n"; } } return $headers; } /** * @deprecated */ function get_headers($article) { return $this->getHeaders($article); } /** * Returns the headers of a given article in the form of * an associative array. Ex: * array( * 'From' => 'foo@bar.com (Foo Smith)', * 'Subject' => 'Re: Using NNTP class', * .... * ); * * @param $article string Article number or id * @return array Assoc array with headers names as key or Pear obj error * @access public */ function splitHeaders($article) { $headers = $this->get_headers($article); if (PEAR::isError($headers)) { return $headers; } $lines = explode("\n", $headers); foreach ($lines as $line) { $line = trim($line); if (($pos = strpos($line, ':')) !== false) { $head = substr($line, 0, $pos); $ret[$head] = ltrim(substr($line, $pos+1)); // if the field was longer than 256 chars, look also in the next line // XXX a better way to discover that than strpos? } else { $ret[$head] .= $line; } } if (isset($ret['References'])) { $ret['References'] = explode (' ', $ret['References']); } return $ret; } /** * @deprecated */ function split_headers($article) { return $this->splitHeaders($article); } /** * Get the body of an article from the currently open connection. * To get the body of an article from another newsgroup, a new * prepare_connection()-call has to be made with apropriate parameters * * @param string $article Either a message-id or a message-number of the article to fetch the headers from. * @access public */ function getBody($article) { /* tell the newsserver we want an article */ $r = $this->command("BODY $article"); if (PEAR::isError($r) || $this->responseCode($r) > 299) { return $this->raiseError($r); } $body = null; while (!feof($this->fp)) { $line = trim(fgets($this->fp, 256)); if ($line == '.') { break; } else { $body .= $line ."\n"; } } return $body; } /** * @deprecated */ function get_body($article) { return $this->getBody($article); } /** * Get data until a line with only a '.' in it is read and return data. * * @return string data * @access private * @author Morgan Christiansson <mog@linux.nu> */ function _getData() { $body = array(); while(!feof($this->fp)) { $line = trim(fgets($this->fp, 256)); if ($line == '.') { break; } else { $body[] = $line; } } return $body; } /** * @deprecated */ function get_data() { return $this->_getData(); } /** * Selects a news group (issue a GROUP command to the server) * * @param string $newsgroup The newsgroup name * @return mixed Array on success or Pear Error object on failure */ function selectGroup($newsgroup) { $r = $this->command("GROUP $newsgroup"); if (PEAR::isError($r) || $this->responseCode($r) > 299) { return $this->raiseError($r); } $response_arr = split(' ', $r); $this->max = $response_arr[3]; $this->min = $response_arr[2]; return array( "first" => $response_arr[2], "last" => $response_arr[3] ); } /** * @deprecated */ function select_group($newsgroup) { return $this->selectGroup($newsgroup); } /** * Fetches a list of all avaible newsgroups * * @param int $fetch PEAR_NNTP_ALL PEAR_NNTP_NAMES PEAR_NNTP_LIST * @return array nested array with informations about * existing newsgroups * @author Morgan Christiansson <mog@linux.nu> */ function getGroups($fetch = true) { $this->command("LIST"); foreach($this->_getData() as $line) { $arr = explode(" ",$line); $groups[$arr[0]]["group"] = $arr[0]; $groups[$arr[0]]["last"] = $arr[1]; $groups[$arr[0]]["first"] = $arr[2]; $groups[$arr[0]]["posting_allowed"] = $arr[3]; } $this->command("LIST NEWSGROUPS"); foreach($this->_getData() as $line) { preg_match("/^(.*?)\s(.*?$)/",$line,$matches); $groups[$matches[1]]["desc"] = $matches[2]; } return $groups; } /** * @deprecated */ function get_groups($fetch=true) { return $this->getGroups($fetch); } /** * Returns a list of avaible headers * which are send from newsserver to client * for every news message * * @return array header names * @access public */ function getOverviewFmt() { $this->command("LIST OVERVIEW.FMT"); $format = array("number"); // XXX Use the splitHeaders() algorithm for supporting // multiline headers? foreach ($body = $this->_getData() as $line) { $line = current(explode(":",$line)); $format[] = $line; } return $format; } /** * @deprecated */ function get_overview_fmt() { return $this->getOverviewFmt(); } /** * Fetch message header * from message number $first until $last * * The format of the returned array is: * $messages[message_id][header_name] * * @param integer $first first article to fetch * @param integer $last last article to fetch * @return array nested array of message and * there headers * @access public */ function getOverview($first,$last) { $format = $this->getOverviewFmt(); $this->command("XOVER $first-$last"); foreach($this->_getData() as $line) { $i=0; foreach(explode("\t",$line) as $line) { $message[$format[$i++]] = $line; } $messages[$message["Message-ID"]] = $message; } $this->command("XROVER $first-$last"); foreach($this->_getData() as $line) { $i=0; foreach(explode("\t",$line) as $line) { $message[$format[$i++]] = $line; } $messages[$message["Message-ID"]] = $message; } return $messages; } /** * @deprecated */ function get_overview($first,$last) { return $this->getOverview($first, $last); } /** * Get the date from the newsserver * format of returned date: * $date['y'] - year * $date['m'] - month * $date['d'] - day * * @return array date * @access public */ function date() { $r = $this->command('DATE'); if (PEAR::isError($r) || $this->responseCode($r) > 299) { return $this->raiseError($r); } $data = explode(' ',$r); $date['y']=substr($data[1],0,4); $date['m']=substr($data[1],4,2); $date['d']=substr($data[1],6,2); return $date; } /** * Maximum article number in current group * * @return integer maximum * @access public */ function max() { if (!@is_resource($this->fp)) { return $this->raiseError('Not connected'); } return $this->max; } /** * Minimum article number in current group * * @return integer minimum * @access public */ function min() { if (!@is_resource($this->fp)) { return $this->raiseError('Not connected'); } return $this->min; } /** * Test whether we are connected or not. * * @return bool true or false * @access public */ function isConnected() { if (@is_resource($this->fp)) { return true; } return false; } /** * @deprecated */ function is_connected() { return $this->isConnected(); } /** * Close connection to the newsserver * * @access public */ function quit() { $this->command("QUIT"); fclose($this->fp); } /** * returns the response code * of a newsserver command * * @param string $response newsserver answer * @return integer response code * @access public */ function responseCode($response) { $parts = explode(' ', ltrim($response)); return (int) $parts[0]; } /** * sets debug on or off * * @param boolean $on true=on, false=off * @access public */ function setDebug($on = true) { $this->_debug = $on; } /** * @deprecated */ function set_debug($on = true) { return $this->setDebug(); } /** * Issue a command to the NNTP server * * @param string $cmd The command to launch, ie: "ARTICLE 1004853" * @param bool $testauth Test or not the auth * @return mixed True on success or Pear Error object on failure * @access public */ function command($cmd, $testauth = true) { if (!@is_resource($this->fp)) { return $this->raiseError('Not connected'); } fputs($this->fp, "$cmd\r\n"); if ($this->_debug) { print ">> $cmd\n"; } $response = fgets($this->fp, 128); if ($this->_debug) { print "<< $response\n"; } // From the spec: "In all cases, clients must provide // this information when requested by the server. Servers are // not required to accept authentication information that is // volunteered by the client" $code = $this->responseCode($response); if ($testauth && ($code == 450 || $code == 480)) { $error = $this->authenticate($this->user, $this->pass, $this->authmode); if (PEAR::isError($error)) { return $error; } /* re-issue the command */ $response = $this->command($cmd, false); } return $response; } } ?>