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