Upgrade to libnet 1.21
[p5sagit/p5-mst-13.2.git] / lib / Net / NNTP.pm
CommitLineData
406c51ee 1# Net::NNTP.pm
2#
3# Copyright (c) 1995-1997 Graham Barr <gbarr@pobox.com>. All rights reserved.
4# This program is free software; you can redistribute it and/or
5# modify it under the same terms as Perl itself.
6
7package Net::NNTP;
8
9use strict;
10use vars qw(@ISA $VERSION $debug);
11use IO::Socket;
12use Net::Cmd;
13use Carp;
14use Time::Local;
15use Net::Config;
16
b3f6f6a6 17$VERSION = "2.24";
406c51ee 18@ISA = qw(Net::Cmd IO::Socket::INET);
19
b3f6f6a6 20
21sub new {
22 my $self = shift;
23 my $type = ref($self) || $self;
24 my ($host, %arg);
25 if (@_ % 2) {
26 $host = shift;
27 %arg = @_;
28 }
29 else {
30 %arg = @_;
31 $host = delete $arg{Host};
32 }
33 my $obj;
34
35 $host ||= $ENV{NNTPSERVER} || $ENV{NEWSHOST};
36
37 my $hosts = defined $host ? [$host] : $NetConfig{nntp_hosts};
38
39 @{$hosts} = qw(news)
40 unless @{$hosts};
41
42 my $h;
43 foreach $h (@{$hosts}) {
44 $obj = $type->SUPER::new(
45 PeerAddr => ($host = $h),
46 PeerPort => $arg{Port} || 'nntp(119)',
47 Proto => 'tcp',
48 Timeout => defined $arg{Timeout}
49 ? $arg{Timeout}
50 : 120
51 )
52 and last;
406c51ee 53 }
54
b3f6f6a6 55 return undef
56 unless defined $obj;
406c51ee 57
b3f6f6a6 58 ${*$obj}{'net_nntp_host'} = $host;
406c51ee 59
b3f6f6a6 60 $obj->autoflush(1);
61 $obj->debug(exists $arg{Debug} ? $arg{Debug} : undef);
406c51ee 62
b3f6f6a6 63 unless ($obj->response() == CMD_OK) {
64 $obj->close;
65 return undef;
406c51ee 66 }
67
b3f6f6a6 68 my $c = $obj->code;
69 my @m = $obj->message;
70
71 unless (exists $arg{Reader} && $arg{Reader} == 0) {
72
73 # if server is INN and we have transfer rights the we are currently
74 # talking to innd not nnrpd
75 if ($obj->reader) {
686337f3 76
b3f6f6a6 77 # If reader suceeds the we need to consider this code to determine postok
78 $c = $obj->code;
406c51ee 79 }
b3f6f6a6 80 else {
81
82 # I want to ignore this failure, so restore the previous status.
83 $obj->set_status($c, \@m);
406c51ee 84 }
b3f6f6a6 85 }
406c51ee 86
b3f6f6a6 87 ${*$obj}{'net_nntp_post'} = $c == 200 ? 1 : 0;
406c51ee 88
b3f6f6a6 89 $obj;
406c51ee 90}
91
b3f6f6a6 92
f92f3fcb 93sub host {
b3f6f6a6 94 my $me = shift;
95 ${*$me}{'net_nntp_host'};
f92f3fcb 96}
97
406c51ee 98
b3f6f6a6 99sub debug_text {
100 my $nntp = shift;
101 my $inout = shift;
102 my $text = shift;
103
104 if ( (ref($nntp) and $nntp->code == 350 and $text =~ /^(\S+)/)
105 || ($text =~ /^(authinfo\s+pass)/io))
406c51ee 106 {
b3f6f6a6 107 $text = "$1 ....\n";
406c51ee 108 }
109
b3f6f6a6 110 $text;
406c51ee 111}
112
b3f6f6a6 113
114sub postok {
115 @_ == 1 or croak 'usage: $nntp->postok()';
116 my $nntp = shift;
117 ${*$nntp}{'net_nntp_post'} || 0;
406c51ee 118}
119
406c51ee 120
b3f6f6a6 121sub article {
122 @_ >= 1 && @_ <= 3 or croak 'usage: $nntp->article( [ MSGID ], [ FH ] )';
123 my $nntp = shift;
124 my @fh;
125
126 @fh = (pop) if @_ == 2 || (@_ && (ref($_[0]) || ref(\$_[0]) eq 'GLOB'));
406c51ee 127
b3f6f6a6 128 $nntp->_ARTICLE(@_)
406c51ee 129 ? $nntp->read_until_dot(@fh)
130 : undef;
131}
132
b3f6f6a6 133
12df23ee 134sub articlefh {
b3f6f6a6 135 @_ >= 1 && @_ <= 2 or croak 'usage: $nntp->articlefh( [ MSGID ] )';
136 my $nntp = shift;
12df23ee 137
b3f6f6a6 138 return unless $nntp->_ARTICLE(@_);
139 return $nntp->tied_fh;
12df23ee 140}
141
406c51ee 142
b3f6f6a6 143sub authinfo {
144 @_ == 3 or croak 'usage: $nntp->authinfo( USER, PASS )';
145 my ($nntp, $user, $pass) = @_;
146
147 $nntp->_AUTHINFO("USER", $user) == CMD_MORE
148 && $nntp->_AUTHINFO("PASS", $pass) == CMD_OK;
406c51ee 149}
150
406c51ee 151
b3f6f6a6 152sub authinfo_simple {
153 @_ == 3 or croak 'usage: $nntp->authinfo( USER, PASS )';
154 my ($nntp, $user, $pass) = @_;
155
156 $nntp->_AUTHINFO('SIMPLE') == CMD_MORE
157 && $nntp->command($user, $pass)->response == CMD_OK;
406c51ee 158}
159
406c51ee 160
b3f6f6a6 161sub body {
162 @_ >= 1 && @_ <= 3 or croak 'usage: $nntp->body( [ MSGID ], [ FH ] )';
163 my $nntp = shift;
164 my @fh;
165
166 @fh = (pop) if @_ == 2 || (@_ && ref($_[0]) || ref(\$_[0]) eq 'GLOB');
406c51ee 167
b3f6f6a6 168 $nntp->_BODY(@_)
406c51ee 169 ? $nntp->read_until_dot(@fh)
170 : undef;
171}
172
b3f6f6a6 173
174sub bodyfh {
175 @_ >= 1 && @_ <= 2 or croak 'usage: $nntp->bodyfh( [ MSGID ] )';
176 my $nntp = shift;
177 return unless $nntp->_BODY(@_);
178 return $nntp->tied_fh;
12df23ee 179}
180
406c51ee 181
b3f6f6a6 182sub head {
183 @_ >= 1 && @_ <= 3 or croak 'usage: $nntp->head( [ MSGID ], [ FH ] )';
184 my $nntp = shift;
185 my @fh;
406c51ee 186
b3f6f6a6 187 @fh = (pop) if @_ == 2 || (@_ && ref($_[0]) || ref(\$_[0]) eq 'GLOB');
188
189 $nntp->_HEAD(@_)
406c51ee 190 ? $nntp->read_until_dot(@fh)
191 : undef;
192}
193
b3f6f6a6 194
195sub headfh {
196 @_ >= 1 && @_ <= 2 or croak 'usage: $nntp->headfh( [ MSGID ] )';
197 my $nntp = shift;
198 return unless $nntp->_HEAD(@_);
199 return $nntp->tied_fh;
12df23ee 200}
201
406c51ee 202
b3f6f6a6 203sub nntpstat {
204 @_ == 1 || @_ == 2 or croak 'usage: $nntp->nntpstat( [ MSGID ] )';
205 my $nntp = shift;
206
207 $nntp->_STAT(@_) && $nntp->message =~ /(<[^>]+>)/o
406c51ee 208 ? $1
209 : undef;
210}
211
212
b3f6f6a6 213sub group {
214 @_ == 1 || @_ == 2 or croak 'usage: $nntp->group( [ GROUP ] )';
215 my $nntp = shift;
216 my $grp = ${*$nntp}{'net_nntp_group'} || undef;
406c51ee 217
b3f6f6a6 218 return $grp
219 unless (@_ || wantarray);
406c51ee 220
b3f6f6a6 221 my $newgrp = shift;
406c51ee 222
b3f6f6a6 223 return wantarray ? () : undef
224 unless $nntp->_GROUP($newgrp || $grp || "")
225 && $nntp->message =~ /(\d+)\s+(\d+)\s+(\d+)\s+(\S+)/;
406c51ee 226
b3f6f6a6 227 my ($count, $first, $last, $group) = ($1, $2, $3, $4);
406c51ee 228
b3f6f6a6 229 # group may be replied as '(current group)'
230 $group = ${*$nntp}{'net_nntp_group'}
406c51ee 231 if $group =~ /\(/;
232
b3f6f6a6 233 ${*$nntp}{'net_nntp_group'} = $group;
406c51ee 234
b3f6f6a6 235 wantarray
236 ? ($count, $first, $last, $group)
406c51ee 237 : $group;
238}
239
406c51ee 240
b3f6f6a6 241sub help {
242 @_ == 1 or croak 'usage: $nntp->help()';
243 my $nntp = shift;
244
245 $nntp->_HELP
406c51ee 246 ? $nntp->read_until_dot
247 : undef;
248}
249
406c51ee 250
b3f6f6a6 251sub ihave {
252 @_ >= 2 or croak 'usage: $nntp->ihave( MESSAGE-ID [, MESSAGE ])';
253 my $nntp = shift;
254 my $mid = shift;
255
256 $nntp->_IHAVE($mid) && $nntp->datasend(@_)
406c51ee 257 ? @_ == 0 || $nntp->dataend
258 : undef;
259}
260
406c51ee 261
b3f6f6a6 262sub last {
263 @_ == 1 or croak 'usage: $nntp->last()';
264 my $nntp = shift;
265
266 $nntp->_LAST && $nntp->message =~ /(<[^>]+>)/o
406c51ee 267 ? $1
268 : undef;
269}
270
406c51ee 271
b3f6f6a6 272sub list {
273 @_ == 1 or croak 'usage: $nntp->list()';
274 my $nntp = shift;
275
276 $nntp->_LIST
406c51ee 277 ? $nntp->_grouplist
278 : undef;
279}
280
406c51ee 281
b3f6f6a6 282sub newgroups {
283 @_ >= 2 or croak 'usage: $nntp->newgroups( SINCE [, DISTRIBUTIONS ])';
284 my $nntp = shift;
285 my $time = _timestr(shift);
286 my $dist = shift || "";
287
288 $dist = join(",", @{$dist})
406c51ee 289 if ref($dist);
290
b3f6f6a6 291 $nntp->_NEWGROUPS($time, $dist)
406c51ee 292 ? $nntp->_grouplist
293 : undef;
294}
295
b3f6f6a6 296
297sub newnews {
298 @_ >= 2 && @_ <= 4
299 or croak 'usage: $nntp->newnews( SINCE [, GROUPS [, DISTRIBUTIONS ]])';
300 my $nntp = shift;
301 my $time = _timestr(shift);
302 my $grp = @_ ? shift: $nntp->group;
303 my $dist = shift || "";
304
305 $grp ||= "*";
306 $grp = join(",", @{$grp})
406c51ee 307 if ref($grp);
308
b3f6f6a6 309 $dist = join(",", @{$dist})
406c51ee 310 if ref($dist);
311
b3f6f6a6 312 $nntp->_NEWNEWS($grp, $time, $dist)
406c51ee 313 ? $nntp->_articlelist
314 : undef;
315}
316
406c51ee 317
b3f6f6a6 318sub next {
319 @_ == 1 or croak 'usage: $nntp->next()';
320 my $nntp = shift;
321
322 $nntp->_NEXT && $nntp->message =~ /(<[^>]+>)/o
406c51ee 323 ? $1
324 : undef;
325}
326
406c51ee 327
b3f6f6a6 328sub post {
329 @_ >= 1 or croak 'usage: $nntp->post( [ MESSAGE ] )';
330 my $nntp = shift;
331
332 $nntp->_POST() && $nntp->datasend(@_)
406c51ee 333 ? @_ == 0 || $nntp->dataend
334 : undef;
335}
336
b3f6f6a6 337
12df23ee 338sub postfh {
339 my $nntp = shift;
340 return unless $nntp->_POST();
341 return $nntp->tied_fh;
342}
343
406c51ee 344
b3f6f6a6 345sub quit {
346 @_ == 1 or croak 'usage: $nntp->quit()';
347 my $nntp = shift;
348
349 $nntp->_QUIT;
350 $nntp->close;
406c51ee 351}
352
406c51ee 353
b3f6f6a6 354sub slave {
355 @_ == 1 or croak 'usage: $nntp->slave()';
356 my $nntp = shift;
357
358 $nntp->_SLAVE;
406c51ee 359}
360
361##
362## The following methods are not implemented by all servers
363##
364
406c51ee 365
b3f6f6a6 366sub active {
367 @_ == 1 || @_ == 2 or croak 'usage: $nntp->active( [ PATTERN ] )';
368 my $nntp = shift;
369
370 $nntp->_LIST('ACTIVE', @_)
406c51ee 371 ? $nntp->_grouplist
372 : undef;
373}
374
406c51ee 375
b3f6f6a6 376sub active_times {
377 @_ == 1 or croak 'usage: $nntp->active_times()';
378 my $nntp = shift;
379
380 $nntp->_LIST('ACTIVE.TIMES')
406c51ee 381 ? $nntp->_grouplist
382 : undef;
383}
384
406c51ee 385
b3f6f6a6 386sub distributions {
387 @_ == 1 or croak 'usage: $nntp->distributions()';
388 my $nntp = shift;
389
390 $nntp->_LIST('DISTRIBUTIONS')
406c51ee 391 ? $nntp->_description
392 : undef;
393}
394
406c51ee 395
b3f6f6a6 396sub distribution_patterns {
397 @_ == 1 or croak 'usage: $nntp->distributions()';
398 my $nntp = shift;
399
400 my $arr;
401 local $_;
406c51ee 402
b3f6f6a6 403 $nntp->_LIST('DISTRIB.PATS')
404 && ($arr = $nntp->read_until_dot)
405 ? [grep { /^\d/ && (chomp, $_ = [split /:/]) } @$arr]
406c51ee 406 : undef;
407}
408
406c51ee 409
b3f6f6a6 410sub newsgroups {
411 @_ == 1 || @_ == 2 or croak 'usage: $nntp->newsgroups( [ PATTERN ] )';
412 my $nntp = shift;
413
414 $nntp->_LIST('NEWSGROUPS', @_)
406c51ee 415 ? $nntp->_description
416 : undef;
417}
418
406c51ee 419
b3f6f6a6 420sub overview_fmt {
421 @_ == 1 or croak 'usage: $nntp->overview_fmt()';
422 my $nntp = shift;
423
424 $nntp->_LIST('OVERVIEW.FMT')
425 ? $nntp->_articlelist
426 : undef;
406c51ee 427}
428
406c51ee 429
b3f6f6a6 430sub subscriptions {
431 @_ == 1 or croak 'usage: $nntp->subscriptions()';
432 my $nntp = shift;
433
434 $nntp->_LIST('SUBSCRIPTIONS')
406c51ee 435 ? $nntp->_articlelist
436 : undef;
437}
438
406c51ee 439
b3f6f6a6 440sub listgroup {
441 @_ == 1 || @_ == 2 or croak 'usage: $nntp->listgroup( [ GROUP ] )';
442 my $nntp = shift;
443
444 $nntp->_LISTGROUP(@_)
406c51ee 445 ? $nntp->_articlelist
446 : undef;
447}
448
406c51ee 449
b3f6f6a6 450sub reader {
451 @_ == 1 or croak 'usage: $nntp->reader()';
452 my $nntp = shift;
453
454 $nntp->_MODE('READER');
406c51ee 455}
456
406c51ee 457
b3f6f6a6 458sub xgtitle {
459 @_ == 1 || @_ == 2 or croak 'usage: $nntp->xgtitle( [ PATTERN ] )';
460 my $nntp = shift;
461
462 $nntp->_XGTITLE(@_)
406c51ee 463 ? $nntp->_description
464 : undef;
465}
466
406c51ee 467
b3f6f6a6 468sub xhdr {
469 @_ >= 2 && @_ <= 4 or croak 'usage: $nntp->xhdr( HEADER, [ MESSAGE-SPEC ] )';
470 my $nntp = shift;
471 my $hdr = shift;
472 my $arg = _msg_arg(@_);
473
474 $nntp->_XHDR($hdr, $arg)
475 ? $nntp->_description
476 : undef;
406c51ee 477}
478
406c51ee 479
b3f6f6a6 480sub xover {
481 @_ == 2 || @_ == 3 or croak 'usage: $nntp->xover( MESSAGE-SPEC )';
482 my $nntp = shift;
483 my $arg = _msg_arg(@_);
484
485 $nntp->_XOVER($arg)
486 ? $nntp->_fieldlist
487 : undef;
406c51ee 488}
489
406c51ee 490
b3f6f6a6 491sub xpat {
492 @_ == 4 || @_ == 5 or croak '$nntp->xpat( HEADER, PATTERN, MESSAGE-SPEC )';
493 my $nntp = shift;
494 my $hdr = shift;
495 my $pat = shift;
496 my $arg = _msg_arg(@_);
497
498 $pat = join(" ", @$pat)
406c51ee 499 if ref($pat);
500
b3f6f6a6 501 $nntp->_XPAT($hdr, $arg, $pat)
502 ? $nntp->_description
503 : undef;
406c51ee 504}
505
406c51ee 506
b3f6f6a6 507sub xpath {
508 @_ == 2 or croak 'usage: $nntp->xpath( MESSAGE-ID )';
509 my ($nntp, $mid) = @_;
510
511 return undef
512 unless $nntp->_XPATH($mid);
406c51ee 513
b3f6f6a6 514 my $m;
515 ($m = $nntp->message) =~ s/^\d+\s+//o;
516 my @p = split /\s+/, $m;
406c51ee 517
b3f6f6a6 518 wantarray ? @p : $p[0];
406c51ee 519}
520
406c51ee 521
b3f6f6a6 522sub xrover {
523 @_ == 2 || @_ == 3 or croak 'usage: $nntp->xrover( MESSAGE-SPEC )';
524 my $nntp = shift;
525 my $arg = _msg_arg(@_);
526
527 $nntp->_XROVER($arg)
528 ? $nntp->_description
529 : undef;
406c51ee 530}
531
406c51ee 532
b3f6f6a6 533sub date {
534 @_ == 1 or croak 'usage: $nntp->date()';
535 my $nntp = shift;
536
537 $nntp->_DATE
538 && $nntp->message =~ /(\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)/
539 ? timegm($6, $5, $4, $3, $2 - 1, $1 - 1900)
406c51ee 540 : undef;
541}
542
543
544##
545## Private subroutines
546##
547
406c51ee 548
b3f6f6a6 549sub _msg_arg {
550 my $spec = shift;
551 my $arg = "";
552
553 if (@_) {
554 carp "Depriciated passing of two message numbers, " . "pass a reference"
555 if $^W;
556 $spec = [$spec, $_[0]];
406c51ee 557 }
558
b3f6f6a6 559 if (defined $spec) {
560 if (ref($spec)) {
561 $arg = $spec->[0];
562 if (defined $spec->[1]) {
563 $arg .= "-"
564 if $spec->[1] != $spec->[0];
565 $arg .= $spec->[1]
566 if $spec->[1] > $spec->[0];
686337f3 567 }
406c51ee 568 }
b3f6f6a6 569 else {
570 $arg = $spec;
406c51ee 571 }
572 }
573
b3f6f6a6 574 $arg;
406c51ee 575}
576
b3f6f6a6 577
578sub _timestr {
579 my $time = shift;
580 my @g = reverse((gmtime($time))[0 .. 5]);
581 $g[1] += 1;
582 $g[0] %= 100;
583 sprintf "%02d%02d%02d %02d%02d%02d GMT", @g;
406c51ee 584}
585
406c51ee 586
b3f6f6a6 587sub _grouplist {
588 my $nntp = shift;
589 my $arr = $nntp->read_until_dot
590 or return undef;
406c51ee 591
b3f6f6a6 592 my $hash = {};
593 my $ln;
594
595 foreach $ln (@$arr) {
596 my @a = split(/[\s\n]+/, $ln);
597 $hash->{$a[0]} = [@a[1, 2, 3]];
406c51ee 598 }
599
b3f6f6a6 600 $hash;
406c51ee 601}
602
406c51ee 603
b3f6f6a6 604sub _fieldlist {
605 my $nntp = shift;
606 my $arr = $nntp->read_until_dot
607 or return undef;
406c51ee 608
b3f6f6a6 609 my $hash = {};
610 my $ln;
611
612 foreach $ln (@$arr) {
613 my @a = split(/[\t\n]/, $ln);
614 my $m = shift @a;
615 $hash->{$m} = [@a];
406c51ee 616 }
617
b3f6f6a6 618 $hash;
406c51ee 619}
620
406c51ee 621
b3f6f6a6 622sub _articlelist {
623 my $nntp = shift;
624 my $arr = $nntp->read_until_dot;
625
626 chomp(@$arr)
406c51ee 627 if $arr;
628
b3f6f6a6 629 $arr;
406c51ee 630}
631
406c51ee 632
b3f6f6a6 633sub _description {
634 my $nntp = shift;
635 my $arr = $nntp->read_until_dot
636 or return undef;
637
638 my $hash = {};
639 my $ln;
406c51ee 640
b3f6f6a6 641 foreach $ln (@$arr) {
642 chomp($ln);
406c51ee 643
b3f6f6a6 644 $hash->{$1} = $ln
645 if $ln =~ s/^\s*(\S+)\s*//o;
406c51ee 646 }
647
b3f6f6a6 648 $hash;
406c51ee 649
650}
651
652##
653## The commands
654##
655
b3f6f6a6 656
657sub _ARTICLE { shift->command('ARTICLE', @_)->response == CMD_OK }
658sub _AUTHINFO { shift->command('AUTHINFO', @_)->response }
659sub _BODY { shift->command('BODY', @_)->response == CMD_OK }
406c51ee 660sub _DATE { shift->command('DATE')->response == CMD_INFO }
b3f6f6a6 661sub _GROUP { shift->command('GROUP', @_)->response == CMD_OK }
662sub _HEAD { shift->command('HEAD', @_)->response == CMD_OK }
663sub _HELP { shift->command('HELP', @_)->response == CMD_INFO }
664sub _IHAVE { shift->command('IHAVE', @_)->response == CMD_MORE }
406c51ee 665sub _LAST { shift->command('LAST')->response == CMD_OK }
b3f6f6a6 666sub _LIST { shift->command('LIST', @_)->response == CMD_OK }
667sub _LISTGROUP { shift->command('LISTGROUP', @_)->response == CMD_OK }
668sub _NEWGROUPS { shift->command('NEWGROUPS', @_)->response == CMD_OK }
669sub _NEWNEWS { shift->command('NEWNEWS', @_)->response == CMD_OK }
406c51ee 670sub _NEXT { shift->command('NEXT')->response == CMD_OK }
b3f6f6a6 671sub _POST { shift->command('POST', @_)->response == CMD_MORE }
672sub _QUIT { shift->command('QUIT', @_)->response == CMD_OK }
673sub _SLAVE { shift->command('SLAVE', @_)->response == CMD_OK }
674sub _STAT { shift->command('STAT', @_)->response == CMD_OK }
675sub _MODE { shift->command('MODE', @_)->response == CMD_OK }
676sub _XGTITLE { shift->command('XGTITLE', @_)->response == CMD_OK }
677sub _XHDR { shift->command('XHDR', @_)->response == CMD_OK }
678sub _XPAT { shift->command('XPAT', @_)->response == CMD_OK }
679sub _XPATH { shift->command('XPATH', @_)->response == CMD_OK }
680sub _XOVER { shift->command('XOVER', @_)->response == CMD_OK }
681sub _XROVER { shift->command('XROVER', @_)->response == CMD_OK }
406c51ee 682sub _XTHREAD { shift->unsupported }
683sub _XSEARCH { shift->unsupported }
684sub _XINDEX { shift->unsupported }
685
686##
687## IO/perl methods
688##
689
b3f6f6a6 690
691sub DESTROY {
692 my $nntp = shift;
693 defined(fileno($nntp)) && $nntp->quit;
406c51ee 694}
695
696
6971;
698
699__END__
700
701=head1 NAME
702
703Net::NNTP - NNTP Client class
704
705=head1 SYNOPSIS
706
707 use Net::NNTP;
686337f3 708
406c51ee 709 $nntp = Net::NNTP->new("some.host.name");
710 $nntp->quit;
711
712=head1 DESCRIPTION
713
714C<Net::NNTP> is a class implementing a simple NNTP client in Perl as described
715in RFC977. C<Net::NNTP> inherits its communication methods from C<Net::Cmd>
716
717=head1 CONSTRUCTOR
718
719=over 4
720
721=item new ( [ HOST ] [, OPTIONS ])
722
723This is the constructor for a new Net::NNTP object. C<HOST> is the
724name of the remote host to which a NNTP connection is required. If not
f92f3fcb 725given then it may be passed as the C<Host> option described below. If no host is passed
726then two environment variables are checked, first C<NNTPSERVER> then
406c51ee 727C<NEWSHOST>, then C<Net::Config> is checked, and if a host is not found
728then C<news> is used.
729
730C<OPTIONS> are passed in a hash like fashion, using key and value pairs.
731Possible options are:
732
f92f3fcb 733B<Host> - NNTP host to connect to. It may be a single scalar, as defined for
734the C<PeerAddr> option in L<IO::Socket::INET>, or a reference to
735an array with hosts to try in turn. The L</host> method will return the value
736which was used to connect to the host.
737
406c51ee 738B<Timeout> - Maximum time, in seconds, to wait for a response from the
739NNTP server, a value of zero will cause all IO operations to block.
740(default: 120)
741
742B<Debug> - Enable the printing of debugging information to STDERR
743
744B<Reader> - If the remote server is INN then initially the connection
745will be to nnrpd, by default C<Net::NNTP> will issue a C<MODE READER> command
746so that the remote server becomes innd. If the C<Reader> option is given
747with a value of zero, then this command will not be sent and the
748connection will be left talking to nnrpd.
749
750=back
751
752=head1 METHODS
753
754Unless otherwise stated all methods return either a I<true> or I<false>
755value, with I<true> meaning that the operation was a success. When a method
756states that it returns a value, failure will be returned as I<undef> or an
757empty list.
758
759=over 4
760
761=item article ( [ MSGID|MSGNUM ], [FH] )
762
763Retrieve the header, a blank line, then the body (text) of the
764specified article.
765
766If C<FH> is specified then it is expected to be a valid filehandle
a6d05634 767and the result will be printed to it, on success a true value will be
768returned. If C<FH> is not specified then the return value, on success,
3c4b39be 769will be a reference to an array containing the article requested, each
406c51ee 770entry in the array will contain one line of the article.
771
772If no arguments are passed then the current article in the currently
773selected newsgroup is fetched.
774
775C<MSGNUM> is a numeric id of an article in the current newsgroup, and
776will change the current article pointer. C<MSGID> is the message id of
777an article as shown in that article's header. It is anticipated that the
778client will obtain the C<MSGID> from a list provided by the C<newnews>
779command, from references contained within another article, or from the
780message-id provided in the response to some other commands.
781
782If there is an error then C<undef> will be returned.
783
784=item body ( [ MSGID|MSGNUM ], [FH] )
785
786Like C<article> but only fetches the body of the article.
787
788=item head ( [ MSGID|MSGNUM ], [FH] )
789
790Like C<article> but only fetches the headers for the article.
791
12df23ee 792=item articlefh ( [ MSGID|MSGNUM ] )
793
794=item bodyfh ( [ MSGID|MSGNUM ] )
795
796=item headfh ( [ MSGID|MSGNUM ] )
797
798These are similar to article(), body() and head(), but rather than
799returning the requested data directly, they return a tied filehandle
800from which to read the article.
801
406c51ee 802=item nntpstat ( [ MSGID|MSGNUM ] )
803
804The C<nntpstat> command is similar to the C<article> command except that no
805text is returned. When selecting by message number within a group,
806the C<nntpstat> command serves to set the "current article pointer" without
807sending text.
808
809Using the C<nntpstat> command to
810select by message-id is valid but of questionable value, since a
811selection by message-id does B<not> alter the "current article pointer".
812
813Returns the message-id of the "current article".
814
815=item group ( [ GROUP ] )
816
817Set and/or get the current group. If C<GROUP> is not given then information
818is returned on the current group.
819
820In a scalar context it returns the group name.
821
822In an array context the return value is a list containing, the number
823of articles in the group, the number of the first article, the number
824of the last article and the group name.
825
826=item ihave ( MSGID [, MESSAGE ])
827
828The C<ihave> command informs the server that the client has an article
829whose id is C<MSGID>. If the server desires a copy of that
830article, and C<MESSAGE> has been given the it will be sent.
831
832Returns I<true> if the server desires the article and C<MESSAGE> was
833successfully sent,if specified.
834
835If C<MESSAGE> is not specified then the message must be sent using the
836C<datasend> and C<dataend> methods from L<Net::Cmd>
837
838C<MESSAGE> can be either an array of lines or a reference to an array.
839
840=item last ()
841
842Set the "current article pointer" to the previous article in the current
843newsgroup.
844
845Returns the message-id of the article.
846
847=item date ()
848
849Returns the date on the remote server. This date will be in a UNIX time
850format (seconds since 1970)
851
852=item postok ()
853
854C<postok> will return I<true> if the servers initial response indicated
855that it will allow posting.
856
857=item authinfo ( USER, PASS )
858
f92f3fcb 859Authenticates to the server (using AUTHINFO USER / AUTHINFO PASS)
860using the supplied username and password. Please note that the
861password is sent in clear text to the server. This command should not
862be used with valuable passwords unless the connection to the server is
863somehow protected.
864
406c51ee 865=item list ()
866
867Obtain information about all the active newsgroups. The results is a reference
868to a hash where the key is a group name and each value is a reference to an
686337f3 869array. The elements in this array are:- the last article number in the group,
870the first article number in the group and any information flags about the group.
406c51ee 871
872=item newgroups ( SINCE [, DISTRIBUTIONS ])
873
874C<SINCE> is a time value and C<DISTRIBUTIONS> is either a distribution
875pattern or a reference to a list of distribution patterns.
876The result is the same as C<list>, but the
877groups return will be limited to those created after C<SINCE> and, if
878specified, in one of the distribution areas in C<DISTRIBUTIONS>.
879
880=item newnews ( SINCE [, GROUPS [, DISTRIBUTIONS ]])
881
882C<SINCE> is a time value. C<GROUPS> is either a group pattern or a reference
883to a list of group patterns. C<DISTRIBUTIONS> is either a distribution
884pattern or a reference to a list of distribution patterns.
885
886Returns a reference to a list which contains the message-ids of all news posted
887after C<SINCE>, that are in a groups which matched C<GROUPS> and a
888distribution which matches C<DISTRIBUTIONS>.
889
890=item next ()
891
892Set the "current article pointer" to the next article in the current
893newsgroup.
894
895Returns the message-id of the article.
896
897=item post ( [ MESSAGE ] )
898
899Post a new article to the news server. If C<MESSAGE> is specified and posting
900is allowed then the message will be sent.
901
902If C<MESSAGE> is not specified then the message must be sent using the
903C<datasend> and C<dataend> methods from L<Net::Cmd>
904
905C<MESSAGE> can be either an array of lines or a reference to an array.
906
dea4d7df 907The message, either sent via C<datasend> or as the C<MESSAGE>
908parameter, must be in the format as described by RFC822 and must
909contain From:, Newsgroups: and Subject: headers.
910
12df23ee 911=item postfh ()
912
913Post a new article to the news server using a tied filehandle. If
914posting is allowed, this method will return a tied filehandle that you
915can print() the contents of the article to be posted. You must
916explicitly close() the filehandle when you are finished posting the
917article, and the return value from the close() call will indicate
918whether the message was successfully posted.
919
406c51ee 920=item slave ()
921
922Tell the remote server that I am not a user client, but probably another
923news server.
924
925=item quit ()
926
927Quit the remote server and close the socket connection.
928
929=back
930
931=head2 Extension methods
932
933These methods use commands that are not part of the RFC977 documentation. Some
934servers may not support all of them.
935
936=over 4
937
938=item newsgroups ( [ PATTERN ] )
939
940Returns a reference to a hash where the keys are all the group names which
941match C<PATTERN>, or all of the groups if no pattern is specified, and
942each value contains the description text for the group.
943
944=item distributions ()
945
946Returns a reference to a hash where the keys are all the possible
947distribution names and the values are the distribution descriptions.
948
949=item subscriptions ()
950
951Returns a reference to a list which contains a list of groups which
952are recommended for a new user to subscribe to.
953
954=item overview_fmt ()
955
956Returns a reference to an array which contain the names of the fields returned
957by C<xover>.
958
959=item active_times ()
960
961Returns a reference to a hash where the keys are the group names and each
962value is a reference to an array containing the time the groups was created
963and an identifier, possibly an Email address, of the creator.
964
965=item active ( [ PATTERN ] )
966
967Similar to C<list> but only active groups that match the pattern are returned.
968C<PATTERN> can be a group pattern.
969
970=item xgtitle ( PATTERN )
971
972Returns a reference to a hash where the keys are all the group names which
973match C<PATTERN> and each value is the description text for the group.
974
975=item xhdr ( HEADER, MESSAGE-SPEC )
976
977Obtain the header field C<HEADER> for all the messages specified.
978
979The return value will be a reference
980to a hash where the keys are the message numbers and each value contains
981the text of the requested header for that message.
982
983=item xover ( MESSAGE-SPEC )
984
985The return value will be a reference
986to a hash where the keys are the message numbers and each value contains
987a reference to an array which contains the overview fields for that
988message.
989
990The names of the fields can be obtained by calling C<overview_fmt>.
991
992=item xpath ( MESSAGE-ID )
993
994Returns the path name to the file on the server which contains the specified
995message.
996
997=item xpat ( HEADER, PATTERN, MESSAGE-SPEC)
998
999The result is the same as C<xhdr> except the is will be restricted to
1000headers where the text of the header matches C<PATTERN>
1001
1002=item xrover
1003
1004The XROVER command returns reference information for the article(s)
1005specified.
1006
1007Returns a reference to a HASH where the keys are the message numbers and the
1008values are the References: lines from the articles
1009
1010=item listgroup ( [ GROUP ] )
1011
1012Returns a reference to a list of all the active messages in C<GROUP>, or
1013the current group if C<GROUP> is not specified.
1014
1015=item reader
1016
1017Tell the server that you are a reader and not another server.
1018
1019This is required by some servers. For example if you are connecting to
1020an INN server and you have transfer permission your connection will
1021be connected to the transfer daemon, not the NNTP daemon. Issuing
1022this command will cause the transfer daemon to hand over control
1023to the NNTP daemon.
1024
1025Some servers do not understand this command, but issuing it and ignoring
1026the response is harmless.
1027
1028=back
1029
1030=head1 UNSUPPORTED
1031
1032The following NNTP command are unsupported by the package, and there are
1033no plans to do so.
1034
1035 AUTHINFO GENERIC
1036 XTHREAD
1037 XSEARCH
1038 XINDEX
1039
1040=head1 DEFINITIONS
1041
1042=over 4
1043
1044=item MESSAGE-SPEC
1045
1046C<MESSAGE-SPEC> is either a single message-id, a single message number, or
1047a reference to a list of two message numbers.
1048
1049If C<MESSAGE-SPEC> is a reference to a list of two message numbers and the
1050second number in a range is less than or equal to the first then the range
1051represents all messages in the group after the first message number.
1052
1053B<NOTE> For compatibility reasons only with earlier versions of Net::NNTP
1054a message spec can be passed as a list of two numbers, this is deprecated
1055and a reference to the list should now be passed
1056
1057=item PATTERN
1058
1059The C<NNTP> protocol uses the C<WILDMAT> format for patterns.
1060The WILDMAT format was first developed by Rich Salz based on
1061the format used in the UNIX "find" command to articulate
1062file names. It was developed to provide a uniform mechanism
1063for matching patterns in the same manner that the UNIX shell
1064matches filenames.
1065
1066Patterns are implicitly anchored at the
1067beginning and end of each string when testing for a match.
1068
1069There are five pattern matching operations other than a strict
1070one-to-one match between the pattern and the source to be
1071checked for a match.
1072
1073The first is an asterisk C<*> to match any sequence of zero or more
1074characters.
1075
1076The second is a question mark C<?> to match any single character. The
1077third specifies a specific set of characters.
1078
1079The set is specified as a list of characters, or as a range of characters
1080where the beginning and end of the range are separated by a minus (or dash)
1081character, or as any combination of lists and ranges. The dash can
1082also be included in the set as a character it if is the beginning
1083or end of the set. This set is enclosed in square brackets. The
1084close square bracket C<]> may be used in a set if it is the first
1085character in the set.
1086
1087The fourth operation is the same as the
1088logical not of the third operation and is specified the same
1089way as the third with the addition of a caret character C<^> at
1090the beginning of the test string just inside the open square
1091bracket.
1092
1093The final operation uses the backslash character to
d1be9408 1094invalidate the special meaning of an open square bracket C<[>,
406c51ee 1095the asterisk, backslash or the question mark. Two backslashes in
1096sequence will result in the evaluation of the backslash as a
1097character with no special meaning.
1098
1099=over 4
1100
1101=item Examples
1102
1103=item C<[^]-]>
1104
1105matches any single character other than a close square
1106bracket or a minus sign/dash.
1107
1108=item C<*bdc>
1109
1110matches any string that ends with the string "bdc"
1111including the string "bdc" (without quotes).
1112
1113=item C<[0-9a-zA-Z]>
1114
1115matches any single printable alphanumeric ASCII character.
1116
1117=item C<a??d>
1118
1119matches any four character string which begins
1120with a and ends with d.
1121
1122=back
1123
1124=back
1125
1126=head1 SEE ALSO
1127
1128L<Net::Cmd>
1129
1130=head1 AUTHOR
1131
1132Graham Barr <gbarr@pobox.com>
1133
1134=head1 COPYRIGHT
1135
1136Copyright (c) 1995-1997 Graham Barr. All rights reserved.
1137This program is free software; you can redistribute it and/or modify
1138it under the same terms as Perl itself.
1139
1140=cut