=?utf-8?q?Compatibilit=C3=83=C2=A9=20php5
[banana.git] / banana / NetNNTP.inc.php
CommitLineData
bb3b9f8e 1<?php
2/********************************************************************************
3* include/NetNNTP.inc.php : NNTP subroutines
4* -------------------------
5*
6* This file is part of the banana distribution
7* Copyright: See COPYING files that comes with this distribution
8********************************************************************************/
9
10/** Class NNTP
11 * implements some basic functions for NNTP protocol
12 */
d4c19591 13class nntp
14{
e785d91c 15 /** socket filehandle */
16 var $ns;
e785d91c 17 /** posting allowed */
18 var $posting;
19 /** last NNTP error code */
20 var $lasterrorcode;
21 /** last NNTP error text */
22 var $lasterrortext;
bb3b9f8e 23
e785d91c 24 /** constructor
25 * @param $_host STRING NNTP host
26 * @param $_timeout INTEGER socket timeout
e785d91c 27 * @param $_reader BOOLEAN sends a "MODE READER" at connection if true
28 */
29
2dbc0167 30 function nntp($_url, $_timeout=120, $_reader=true)
d4c19591 31 {
2dbc0167 32 $url['port'] = 119;
33 $url = parse_url($_url);
34 $this->ns = fsockopen($url['host'], $url['port'], $errno, $errstr, $_timeout);
e785d91c 35 if (!$this->ns) {
d81ff988 36 return null;
e785d91c 37 }
2dbc0167 38
e785d91c 39 $result = $this->gline();
40 $this->posting = (substr($result, 0, 3)=="200");
41 if ($_reader && ($result{0}=="2")) {
42 $this->pline("MODE READER\r\n");
43 $result = $this->gline();
44 $this->posting = ($result{0}=="200");
45 }
2dbc0167 46 if ($result{0}=="2" && $url['user'] && $url['user']!='anonymous') {
47 return $this->authinfo($url['user'], $url['pass']);
48 }
e785d91c 49 return ($result{0}=="2");
bb3b9f8e 50 }
bb3b9f8e 51
2dbc0167 52# Socket functions
53
54 /** get a line from server
55 * @return STRING
56 */
57
58 function gline()
59 {
65d96b1f 60 return rtrim(fgets($this->ns, 1200));
2dbc0167 61 }
62
63 /** puts a line on server
64 * @param STRING $_line line to put
65 */
66
67 function pline($_line)
68 {
69 return fputs($this->ns, $_line, strlen($_line));
70 }
71
bb3b9f8e 72# strict NNTP Functions [RFC 977]
73# see http://www.faqs.org/rfcs/rfc977.html
74
e785d91c 75 /** authentification
76 * @param $_user STRING login
77 * @param $_pass INTEGER password
78 * @return BOOLEAN true if authentication was successful
79 */
80
d4c19591 81 function authinfo($_user, $_pass)
82 {
e785d91c 83 $user = preg_replace("/(\r|\n)/", "", $_user);
84 $pass = preg_replace("/(\r|\n)/", "", $_pass);
85 $this->pline("AUTHINFO USER $user\r\n");
86 $this->gline();
87 $this->pline("AUTHINFO PASS $pass\r\n");
88 $result=$this->gline();
89 if ($result{0}!="2") {
90 $this->lasterrorcode = substr($result, 0, 3);
91 $this->lasterrortext = substr($result, 4);
92 return false;
93 }
bb3b9f8e 94 return true;
bb3b9f8e 95 }
e785d91c 96
97 /** retrieves an article
98 * MSGID is a numeric ID a shown in article's headers. MSGNUM is a
99 * server-dependent ID (see X-Ref on many servers) and retriving
100 * an article by this way will change the current article pointer.
101 * If an error occur, false is returned.
102 * @param $_msgid STRING MSGID or MSGNUM of article
103 * @return ARRAY lines of the article
104 * @see body
105 * @see head
106 */
107
d4c19591 108 function article($_msgid="")
109 {
e785d91c 110 $msgid = preg_replace("/(\r|\n)/", "", $_msgid);
111 $this->pline("ARTICLE $msgid\r\n");
112 $result = $this->gline();
113 if ($result{0} != '2') {
114 $this->lasterrorcode = substr($result, 0, 3);
115 $this->lasterrortext = substr($result, 4);
116 return false;
117 }
118 $result = $this->gline();
119 while ($result != ".") {
120 $array[] = $result;
121 $result = $this->gline();
122 }
123 return $array;
bb3b9f8e 124 }
e785d91c 125
126 /** post a message
127 * if an error occur, false is returned
128 * @param $_message STRING message to post
129 * @return STRING MSGID of article
130 */
131
d4c19591 132 function post($_message)
133 {
e785d91c 134 if (is_array($_message)) {
135 $message=join("\n", $_message);
136 } else {
137 $message=$_message;
138 }
139 $this->pline("POST \r\n");
140 $result=$this->gline();
141 if ($result{0} != '3') {
142 $this->lasterrorcode = substr($result, 0, 3);
143 $this->lasterrortext = substr($result, 4);
144 return false;
145 }
146 $this->pline($message."\r\n.\r\n");
147 $result = $this->gline();
148 if ($result{0} != '2') {
149 $this->lasterrorcode = substr($result, 0, 3);
150 $this->lasterrortext = substr($result, 4);
151 return false;
152 }
153 if ($result{0} == '2') {
154 if (preg_match("/(<[^@>]+@[^@>]+>)/", $result, $regs)) {
155 return $regs[0];
156 } else {
157 return true;
158 }
159 }
160 return false;
bb3b9f8e 161 }
e785d91c 162
163 /** fetches the body of an article
164 * params are the same as article
165 * @param $_msgid STRING MSGID or MSGNUM of article
166 * @return ARRAY lines of the article
167 * @see article
168 * @see head
169 */
170
d4c19591 171 function body($_msgid="")
172 {
e785d91c 173 $msgid = preg_replace("/(\r|\n)/", "", $_msgid);
174 $this->pline("BODY $msgid\r\n");
175 $result = $this->gline();
176 if ($result{0} != '2') {
177 $this->lasterrorcode = substr($result, 0, 3);
178 $this->lasterrortext = substr($result, 4);
179 return false;
180 }
41cf00eb 181 $array = Array();
182 while (($result = $this->gline()) != ".") {
e785d91c 183 $array[] = $result;
e785d91c 184 }
185 return $array;
bb3b9f8e 186 }
e785d91c 187
188 /** fetches the headers of an article
189 * params are the same as article
190 * @param $_msgid STRING MSGID or MSGNUM of article
191 * @return ARRAY lines of the article
192 * @see article
193 * @see body
194 */
195
d4c19591 196 function head($_msgid="")
197 {
e785d91c 198 $msgid = preg_replace("/(\r|\n)/", "", $_msgid);
199 $this->pline("HEAD $msgid\r\n");
200 $result = $this->gline();
201 if ($result{0}!="2") {
202 $this->lasterrorcode = substr($result, 0, 3);
203 $this->lasterrortext = substr($result, 4);
204 return false;
205 }
206 $result = $this->gline();
207 while ($result != ".") {
208 $array[] = $result;
209 $result = $this->gline();
210 }
211 return $array;
bb3b9f8e 212 }
e785d91c 213
214 /** set current group
215 * @param $_group STRING
216 * @return ARRAY array : nb of articles in group, MSGNUM of first article, MSGNUM of last article, and group name
217 */
218
d4c19591 219 function group($_group)
220 {
e785d91c 221 $group = preg_replace("/(\r|\n)/", "", $_group);
222 $this->pline("GROUP $group\r\n");
223 $line = $this->gline();
224 if ($line{0}!="2") {
225 $this->lasterrorcode = substr($line, 0, 3);
226 $this->lasterrortext = substr($line, 4);
227 return false;
228 }
229 if (preg_match("/^2\d{2} (\d+) (\d+) (\d+) ([^ ]+)/", $line, $regs)) {
230 return array($regs[1], $regs[2], $regs[3], $regs[4]);
231 }
11873d85 232 return false;
bb3b9f8e 233 }
e785d91c 234
235 /** set the article pointer to the previous article in current group
236 * @return STRING MSGID of article
237 * @see next
238 */
239
d4c19591 240 function last()
241 {
e785d91c 242 $this->pline("LAST \r\n");
243 $line = $this->gline();
244 if ($line{0}!="2") {
245 $this->lasterrorcode = substr($result, 0, 3);
246 $this->lasterrortext = substr($result, 4);
247 return false;
248 }
249 if (preg_match("/^2\d{2} \d+ <([^>]+)>/", $line, $regs)) {
250 return "<{$regs[1]}>";
251 }
11873d85 252 return false;
bb3b9f8e 253 }
e785d91c 254
255 /** set the article pointer to the next article in current group
256 * @return STRING MSGID of article
257 * @see last
258 */
259
d4c19591 260 function next()
261 {
e785d91c 262 $this->pline("NEXT \r\n");
263 $line = $this->gline();
264 if ($line{0}!="2") {
265 $this->lasterrorcode = substr($result, 0, 3);
266 $this->lasterrortext = substr($result, 4);
267 return false;
268 }
269 if (preg_match("/^2\d{2} \d+ <([^>]+)>/", $line, $regs)) {
270 return "<{$regs[1]}>";
271 }
11873d85 272 return false;
bb3b9f8e 273 }
e785d91c 274
275 /** set the current article pointer
276 * @param $_msgid STRING MSGID or MSGNUM of article
277 * @return BOOLEAN true if authentication was successful, error code otherwise
278 * @see article
279 * @see body
280 */
281
d4c19591 282 function nntpstat($_msgid)
283 {
e785d91c 284 $msgid = preg_replace("/(\r|\n)/", "", $_msgid);
285 $this->pline("STAT $msgid\r\n");
286 $line = $this->gline();
287 if ($line{0}!="2") {
288 $this->lasterrorcode = substr($result, 0, 3);
289 $this->lasterrortext = substr($result, 4);
290 return false;
291 }
292 if (preg_match("/^2\d{2} \d+ <([^>]+)>/", $line, $regs)) {
293 return "<{$regs[1]}>";
294 }
295 return false;
bb3b9f8e 296 }
e785d91c 297
298 /** returns true if posting is allowed
299 * @return BOOLEAN true if posting is allowed lines
300 */
301
d4c19591 302 function postok()
303 {
e785d91c 304 return ($this->posting);
bb3b9f8e 305 }
e785d91c 306
b035d759 307 /** retreive the group list
308 * @return ARRAY group name => (MSGNUM of first article, MSGNUM of last article, NNTP flags)
309 * @see newgroups, liste
310 */
311 function _grouplist()
312 {
313 global $banana;
314
315 if (substr($this->gline(), 0, 1)!="2") {
316 return false;
317 }
318 $result = $this->gline();
319 $array = Array();
320 while ($result != ".") {
321 preg_match("/([^ ]+) (\d+) (\d+) (.)/", $result, $regs);
322 if (!isset($banana->grp_pattern) || preg_match('@'.$banana->grp_pattern.'@', $regs[1])) {
323 $array[$regs[1]] = array(intval($regs[2]), intval($regs[3]), intval($regs[4]));
324 }
325 $result = $this->gline();
326 }
327 return $array;
328 }
329
e785d91c 330 /** gets information about all active newsgroups
331 * @return ARRAY group name => (MSGNUM of first article, MSGNUM of last article, NNTP flags)
332 * @see newgroups
333 */
334
d4c19591 335 function liste()
336 {
e785d91c 337 $this->pline("LIST\r\n");
b035d759 338 return $this->_grouplist();
bb3b9f8e 339 }
e785d91c 340
341 /** get information about recent newsgroups
342 * same as list, but information are limited to newgroups created after $_since
343 * @param $_since INTEGER unix timestamp
344 * @param $_distributions STRING distributions
345 * @return ARRAY same format as liste
346 * @see liste
347 */
348
d4c19591 349 function newgroups($_since, $_distributions="")
350 {
e785d91c 351#assume $_since is a unix timestamp
352 $distributions = preg_replace("/(\r|\n)/", "", $_distributions);
353 $this->pline("NEWGROUPS ".gmdate("ymd His", $_since)
354 ." GMT $distributions\r\n");
b035d759 355 return $this->_grouplist();
bb3b9f8e 356 }
e785d91c 357
358 /** gets a list of new articles
359 * @param $_since INTEGER unix timestamp
360 * @parma $_groups STRING pattern of intersting groups
361 * @return ARRAY MSGID of new articles
362 */
363
d4c19591 364 function newnews($_since, $_groups="*", $_distributions="")
365 {
e785d91c 366 $distributions = preg_replace("/(\r|\n)/", "", $_distributions);
367 $groups = preg_replace("/(\r|\n)/", "", $_groups);
368 $array = array();
369#assume $since is a unix timestamp
370 $this->pline("NEWNEWS $_groups ".gmdate("ymd His", $_since)." GMT $distributions\r\n");
371 if (substr($this->gline(), 0, 1)!="2") {
372 return false;
373 }
65d96b1f 374 while (($result = $this->gline()) != ".") {
375 $array[] = $result;
e785d91c 376 }
377 return $array;
bb3b9f8e 378 }
e785d91c 379
380 /** Tell the remote server that I am not a user client, but probably another news server
381 * @return BOOLEAN true if sucessful
382 */
383
d4c19591 384 function slave()
385 {
e785d91c 386 $this->pline("SLAVE \r\n");
387 return (substr($this->gline(), 0, 1)=="2");
bb3b9f8e 388 }
e785d91c 389
390 /** implements IHAVE method
391 * @param $_msgid STRING MSGID of article
392 * @param $_message STRING article
393 * @return BOOLEAN
394 */
395
d4c19591 396 function ihave($_msgid, $_message=false)
397 {
e785d91c 398 $msgid = preg_replace("/(\r|\n)/", "", $_msgid);
399 if (is_array($message)) {
400 $message = join("\n", $_message);
401 } else {
402 $message = $_message;
403 }
404 $this->pline("IHAVE $msgid \r\n");
405 $result = $this->gline();
406 if ($message && ($result{0}=="3")) {
407 $this->pline("$message\r\n.\r\n");
408 $result = $this->gline();
409 }
410 return ($result{0}=="2");
bb3b9f8e 411 }
e785d91c 412
413 /** closes connection to server
414 */
415
d4c19591 416 function quit()
417 {
e785d91c 418 $this->pline("QUIT\r\n");
419 $this->gline();
420 fclose($this->ns);
bb3b9f8e 421 }
bb3b9f8e 422
423# NNTP Extensions [RFC 2980]
424
e785d91c 425 /** Returns the date on the remote server
426 * @return INTEGER timestamp
427 */
428
d4c19591 429 function date()
430 {
e785d91c 431 $this->pline("DATE \r\n");
432 $result = $this->gline();
433 if (preg_match("/^111 (\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})$/", $result, $r)) {
434 return gmmktime($r[4], $r[5], $r[6], $r[2], $r[3], $r[1]);
435 }
436 return false;
bb3b9f8e 437 }
e785d91c 438
439 /** returns group descriptions
440 * @param $_pattern STRING pattern of intersting groups
441 * @return ARRAY group name => description
442 */
443
d4c19591 444 function xgtitle($_pattern="*")
445 {
2dbc0167 446 $pattern = preg_replace("/[\r\n]/", "", $_pattern);
e785d91c 447 $this->pline("XGTITLE $pattern \r\n");
448 if (substr($this->gline(), 0, 1)!="2") return false;
449 $result = $this->gline();
450 while ($result != ".") {
2dbc0167 451 preg_match("/([^ \t]+)[ \t]+(.+)$/", $result, $regs);
452 $array[$regs[1]] = $regs[2];
e785d91c 453 $result = $this->gline();
454 }
455 return $array;
bb3b9f8e 456 }
e785d91c 457
458 /** obtain the header field $hdr for all the messages specified
459 * @param $_hdr STRING name of the header (eg: 'From')
460 * @param $_range STRING range of articles
461 * @return ARRAY MSGNUM => header value
462 */
463
d4c19591 464 function xhdr($_hdr, $_range="")
465 {
e785d91c 466 $hdr = preg_replace("/(\r|\n)/", "", $_hdr);
467 $range = preg_replace("/(\r|\n)/", "", $_range);
468 $this->pline("XHDR $hdr $range \r\n");
469 if (substr($this->gline(), 0, 1)!="2") {
470 return false;
471 }
11873d85 472
e785d91c 473 $array = array();
11873d85 474 while (($result = $this->gline()) != '.') {
e785d91c 475 preg_match("/([^ \t]+) (.*)$/", $result, $regs);
476 $array[$regs[1]] = $regs[2];
e785d91c 477 }
478 return $array;
bb3b9f8e 479 }
e785d91c 480
481 /** obtain the header field $_hdr matching $_pat for all the messages specified
482 * @param $_hdr STRING name of the header (eg: 'From')
483 * @param $_range STRING range of articles
484 * @param $_pat STRING pattern
485 * @return ARRAY MSGNUM => header value
486 */
487
d4c19591 488 function xpat($_hdr, $_range, $_pat)
489 {
e785d91c 490 $hdr = preg_replace("/(\r|\n)/", "", $_hdr);
491 $range = preg_replace("/(\r|\n)/", "", $_range);
492 $pat = preg_replace("/(\r|\n)/", "", $_pat);
493 $this->pline("XPAT $hdr $range $pat\r\n");
494 if (substr($this->gline(), 0, 1)!="2") {
495 return false;
496 }
497 $result = $this->gline();
498 while ($result != ".") {
499 preg_match("/([^ \t]+) (.*)$/", $result, $regs);
500 $array[$regs[1]] = $regs[2];
501 $result = $this->gline();
502 }
503 return $array;
5d502f47 504 }
bb3b9f8e 505}
506
507?>