2e8cf0f782e789bdadd8dd35cd078093779d70a9
2 /********************************************************************************
3 * include/NetNNTP.inc.php : NNTP subroutines
4 * -------------------------
6 * This file is part of the banana distribution
7 * Copyright: See COPYING files that comes with this distribution
8 ********************************************************************************/
11 * implements some basic functions for NNTP protocol
15 /** socket filehandle */
17 /** posting allowed */
19 /** last NNTP error code */
21 /** last NNTP error text */
25 * @param $_host STRING NNTP host
26 * @param $_timeout INTEGER socket timeout
27 * @param $_reader BOOLEAN sends a "MODE READER" at connection if true
30 function nntp($_url, $_timeout=120, $_reader=true
)
33 $url = parse_url($_url);
34 $this->ns
= fsockopen($url['host'], $url['port'], $errno, $errstr, $_timeout);
40 $result = $this->gline();
41 $this->posting
= (substr($result, 0, 3)=="200");
42 if ($_reader && ($result{0}=="2")) {
43 $this->pline("MODE READER\r\n");
44 $result = $this->gline();
45 $this->posting
= ($result{0}=="200");
47 if ($result{0}=="2" && $url['user'] && $url['user']!='anonymous') {
48 return $this->authinfo($url['user'], $url['pass']);
50 return ($result{0}=="2");
55 /** get a line from server
61 return trim(fgets($this->ns
, 1200));
64 /** puts a line on server
65 * @param STRING $_line line to put
68 function pline($_line)
70 return fputs($this->ns
, $_line, strlen($_line));
73 # strict NNTP Functions [RFC 977]
74 # see http://www.faqs.org/rfcs/rfc977.html
77 * @param $_user STRING login
78 * @param $_pass INTEGER password
79 * @return BOOLEAN true if authentication was successful
82 function authinfo($_user, $_pass)
84 $user = preg_replace("/(\r|\n)/", "", $_user);
85 $pass = preg_replace("/(\r|\n)/", "", $_pass);
86 $this->pline("AUTHINFO USER $user\r\n");
88 $this->pline("AUTHINFO PASS $pass\r\n");
89 $result=$this->gline();
90 if ($result{0}!="2") {
91 $this->lasterrorcode
= substr($result, 0, 3);
92 $this->lasterrortext
= substr($result, 4);
98 /** retrieves an article
99 * MSGID is a numeric ID a shown in article's headers. MSGNUM is a
100 * server-dependent ID (see X-Ref on many servers) and retriving
101 * an article by this way will change the current article pointer.
102 * If an error occur, false is returned.
103 * @param $_msgid STRING MSGID or MSGNUM of article
104 * @return ARRAY lines of the article
109 function article($_msgid="")
111 $msgid = preg_replace("/(\r|\n)/", "", $_msgid);
112 $this->pline("ARTICLE $msgid\r\n");
113 $result = $this->gline();
114 if ($result{0} != '2') {
115 $this->lasterrorcode
= substr($result, 0, 3);
116 $this->lasterrortext
= substr($result, 4);
119 $result = $this->gline();
120 while ($result != ".") {
122 $result = $this->gline();
128 * if an error occur, false is returned
129 * @param $_message STRING message to post
130 * @return STRING MSGID of article
133 function post($_message)
135 if (is_array($_message)) {
136 $message=join("\n", $_message);
140 $this->pline("POST \r\n");
141 $result=$this->gline();
142 if ($result{0} != '3') {
143 $this->lasterrorcode
= substr($result, 0, 3);
144 $this->lasterrortext
= substr($result, 4);
147 $this->pline($message."\r\n.\r\n");
148 $result = $this->gline();
149 if ($result{0} != '2') {
150 $this->lasterrorcode
= substr($result, 0, 3);
151 $this->lasterrortext
= substr($result, 4);
154 if ($result{0} == '2') {
155 if (preg_match("/(<[^@>]+@[^@>]+>)/", $result, $regs)) {
164 /** fetches the body of an article
165 * params are the same as article
166 * @param $_msgid STRING MSGID or MSGNUM of article
167 * @return ARRAY lines of the article
172 function body($_msgid="")
174 $msgid = preg_replace("/(\r|\n)/", "", $_msgid);
175 $this->pline("BODY $msgid\r\n");
176 $result = $this->gline();
177 if ($result{0} != '2') {
178 $this->lasterrorcode
= substr($result, 0, 3);
179 $this->lasterrortext
= substr($result, 4);
182 $result = $this->gline();
183 while ($result != ".") {
185 $result = $this->gline();
190 /** fetches the headers of an article
191 * params are the same as article
192 * @param $_msgid STRING MSGID or MSGNUM of article
193 * @return ARRAY lines of the article
198 function head($_msgid="")
200 $msgid = preg_replace("/(\r|\n)/", "", $_msgid);
201 $this->pline("HEAD $msgid\r\n");
202 $result = $this->gline();
203 if ($result{0}!="2") {
204 $this->lasterrorcode
= substr($result, 0, 3);
205 $this->lasterrortext
= substr($result, 4);
208 $result = $this->gline();
209 while ($result != ".") {
211 $result = $this->gline();
216 /** set current group
217 * @param $_group STRING
218 * @return ARRAY array : nb of articles in group, MSGNUM of first article, MSGNUM of last article, and group name
221 function group($_group)
223 $group = preg_replace("/(\r|\n)/", "", $_group);
224 $this->pline("GROUP $group\r\n");
225 $line = $this->gline();
227 $this->lasterrorcode
= substr($line, 0, 3);
228 $this->lasterrortext
= substr($line, 4);
231 if (preg_match("/^2\d{2} (\d+) (\d+) (\d+) ([^ ]+)/", $line, $regs)) {
232 return array($regs[1], $regs[2], $regs[3], $regs[4]);
237 /** set the article pointer to the previous article in current group
238 * @return STRING MSGID of article
244 $this->pline("LAST \r\n");
245 $line = $this->gline();
247 $this->lasterrorcode
= substr($result, 0, 3);
248 $this->lasterrortext
= substr($result, 4);
251 if (preg_match("/^2\d{2} \d+ <([^>]+)>/", $line, $regs)) {
252 return "<{$regs[1]}>";
257 /** set the article pointer to the next article in current group
258 * @return STRING MSGID of article
264 $this->pline("NEXT \r\n");
265 $line = $this->gline();
267 $this->lasterrorcode
= substr($result, 0, 3);
268 $this->lasterrortext
= substr($result, 4);
271 if (preg_match("/^2\d{2} \d+ <([^>]+)>/", $line, $regs)) {
272 return "<{$regs[1]}>";
277 /** set the current article pointer
278 * @param $_msgid STRING MSGID or MSGNUM of article
279 * @return BOOLEAN true if authentication was successful, error code otherwise
284 function nntpstat($_msgid)
286 $msgid = preg_replace("/(\r|\n)/", "", $_msgid);
287 $this->pline("STAT $msgid\r\n");
288 $line = $this->gline();
290 $this->lasterrorcode
= substr($result, 0, 3);
291 $this->lasterrortext
= substr($result, 4);
294 if (preg_match("/^2\d{2} \d+ <([^>]+)>/", $line, $regs)) {
295 return "<{$regs[1]}>";
300 /** returns true if posting is allowed
301 * @return BOOLEAN true if posting is allowed lines
306 return ($this->posting
);
309 /** gets information about all active newsgroups
310 * @return ARRAY group name => (MSGNUM of first article, MSGNUM of last article, NNTP flags)
316 $this->pline("LIST\r\n");
317 if (substr($this->gline(), 0, 1)!="2") return false
;
318 $result = $this->gline();
319 while ($result != ".") {
320 preg_match("/([^ ]+) (\d+) (\d+) (.)/", $result, $regs);
321 $array[$regs[1]] = array(intval($regs[2]), intval($regs[3]), intval($regs[4]));
322 $result = $this->gline();
327 /** get information about recent newsgroups
328 * same as list, but information are limited to newgroups created after $_since
329 * @param $_since INTEGER unix timestamp
330 * @param $_distributions STRING distributions
331 * @return ARRAY same format as liste
335 function newgroups($_since, $_distributions="")
337 #assume $_since is a unix timestamp
338 $distributions = preg_replace("/(\r|\n)/", "", $_distributions);
339 $this->pline("NEWGROUPS ".gmdate("ymd His", $_since)
340 ." GMT $distributions\r\n");
341 if (substr($this->gline(), 0, 1)!="2") {
344 $result = $this->gline();
346 while ($result != ".") {
347 preg_match("/([^ ]+) (\d+) (\d+) (.)/", $result, $regs);
348 $array[$regs[1]] = array(intval($regs[2]), intval($regs[3]), intval($regs[4]));
349 $result = $this->gline();
354 /** gets a list of new articles
355 * @param $_since INTEGER unix timestamp
356 * @parma $_groups STRING pattern of intersting groups
357 * @return ARRAY MSGID of new articles
360 function newnews($_since, $_groups="*", $_distributions="")
362 $distributions = preg_replace("/(\r|\n)/", "", $_distributions);
363 $groups = preg_replace("/(\r|\n)/", "", $_groups);
365 #assume $since is a unix timestamp
366 $this->pline("NEWNEWS $_groups ".gmdate("ymd His", $_since)." GMT $distributions\r\n");
367 if (substr($this->gline(), 0, 1)!="2") {
370 $result = $this->gline();
371 while ($result != ".") {
373 $result = $this->gline();
378 /** Tell the remote server that I am not a user client, but probably another news server
379 * @return BOOLEAN true if sucessful
384 $this->pline("SLAVE \r\n");
385 return (substr($this->gline(), 0, 1)=="2");
388 /** implements IHAVE method
389 * @param $_msgid STRING MSGID of article
390 * @param $_message STRING article
394 function ihave($_msgid, $_message=false
)
396 $msgid = preg_replace("/(\r|\n)/", "", $_msgid);
397 if (is_array($message)) {
398 $message = join("\n", $_message);
400 $message = $_message;
402 $this->pline("IHAVE $msgid \r\n");
403 $result = $this->gline();
404 if ($message && ($result{0}=="3")) {
405 $this->pline("$message\r\n.\r\n");
406 $result = $this->gline();
408 return ($result{0}=="2");
411 /** closes connection to server
416 $this->pline("QUIT\r\n");
421 # NNTP Extensions [RFC 2980]
423 /** Returns the date on the remote server
424 * @return INTEGER timestamp
429 $this->pline("DATE \r\n");
430 $result = $this->gline();
431 if (preg_match("/^111 (\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})$/", $result, $r)) {
432 return gmmktime($r[4], $r[5], $r[6], $r[2], $r[3], $r[1]);
437 /** returns group descriptions
438 * @param $_pattern STRING pattern of intersting groups
439 * @return ARRAY group name => description
442 function xgtitle($_pattern="*")
444 $pattern = preg_replace("/[\r\n]/", "", $_pattern);
445 $this->pline("XGTITLE $pattern \r\n");
446 if (substr($this->gline(), 0, 1)!="2") return false
;
447 $result = $this->gline();
448 while ($result != ".") {
449 preg_match("/([^ \t]+)[ \t]+(.+)$/", $result, $regs);
450 $array[$regs[1]] = $regs[2];
451 $result = $this->gline();
456 /** obtain the header field $hdr for all the messages specified
457 * @param $_hdr STRING name of the header (eg: 'From')
458 * @param $_range STRING range of articles
459 * @return ARRAY MSGNUM => header value
462 function xhdr($_hdr, $_range="")
464 $hdr = preg_replace("/(\r|\n)/", "", $_hdr);
465 $range = preg_replace("/(\r|\n)/", "", $_range);
466 $this->pline("XHDR $hdr $range \r\n");
467 if (substr($this->gline(), 0, 1)!="2") {
472 while (($result = $this->gline()) != '.') {
473 preg_match("/([^ \t]+) (.*)$/", $result, $regs);
474 $array[$regs[1]] = $regs[2];
479 /** obtain the header field $_hdr matching $_pat for all the messages specified
480 * @param $_hdr STRING name of the header (eg: 'From')
481 * @param $_range STRING range of articles
482 * @param $_pat STRING pattern
483 * @return ARRAY MSGNUM => header value
486 function xpat($_hdr, $_range, $_pat)
488 $hdr = preg_replace("/(\r|\n)/", "", $_hdr);
489 $range = preg_replace("/(\r|\n)/", "", $_range);
490 $pat = preg_replace("/(\r|\n)/", "", $_pat);
491 $this->pline("XPAT $hdr $range $pat\r\n");
492 if (substr($this->gline(), 0, 1)!="2") {
495 $result = $this->gline();
496 while ($result != ".") {
497 preg_match("/([^ \t]+) (.*)$/", $result, $regs);
498 $array[$regs[1]] = $regs[2];
499 $result = $this->gline();