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