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