This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Double double test test header header
[perl5.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.20"; # $Id: //depot/libnet/Net/NNTP.pm#14 $
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      if(defined $spec->[1])
519       {
520        $arg .= "-"
521           if $spec->[1] != $spec->[0];
522        $arg .= $spec->[1]
523           if $spec->[1] > $spec->[0];
524       }
525     }
526    else
527     {
528      $arg = $spec;
529     }
530   }
531
532  $arg;
533 }
534
535 sub _timestr
536 {
537  my $time = shift;
538  my @g = reverse((gmtime($time))[0..5]);
539  $g[1] += 1;
540  $g[0] %= 100;
541  sprintf "%02d%02d%02d %02d%02d%02d GMT", @g;
542 }
543
544 sub _grouplist
545 {
546  my $nntp = shift;
547  my $arr = $nntp->read_until_dot or
548     return undef;
549
550  my $hash = {};
551  my $ln;
552
553  foreach $ln (@$arr)
554   {
555    my @a = split(/[\s\n]+/,$ln);
556    $hash->{$a[0]} = [ @a[1,2,3] ];
557   }
558
559  $hash;
560 }
561
562 sub _fieldlist
563 {
564  my $nntp = shift;
565  my $arr = $nntp->read_until_dot or
566     return undef;
567
568  my $hash = {};
569  my $ln;
570
571  foreach $ln (@$arr)
572   {
573    my @a = split(/[\t\n]/,$ln);
574    my $m = shift @a;
575    $hash->{$m} = [ @a ];
576   }
577
578  $hash;
579 }
580
581 sub _articlelist
582 {
583  my $nntp = shift;
584  my $arr = $nntp->read_until_dot;
585
586  chomp(@$arr)
587     if $arr;
588
589  $arr;
590 }
591
592 sub _description
593 {
594  my $nntp = shift;
595  my $arr = $nntp->read_until_dot or
596     return undef;
597
598  my $hash = {};
599  my $ln;
600
601  foreach $ln (@$arr)
602   {
603    chomp($ln);
604
605    $hash->{$1} = $ln
606     if $ln =~ s/^\s*(\S+)\s*//o;
607   }
608
609  $hash;
610
611 }
612
613 ##
614 ## The commands
615 ##
616
617 sub _ARTICLE   { shift->command('ARTICLE',@_)->response == CMD_OK }
618 sub _AUTHINFO  { shift->command('AUTHINFO',@_)->response }
619 sub _BODY      { shift->command('BODY',@_)->response == CMD_OK }
620 sub _DATE      { shift->command('DATE')->response == CMD_INFO }
621 sub _GROUP     { shift->command('GROUP',@_)->response == CMD_OK }
622 sub _HEAD      { shift->command('HEAD',@_)->response == CMD_OK }
623 sub _HELP      { shift->command('HELP',@_)->response == CMD_INFO }
624 sub _IHAVE     { shift->command('IHAVE',@_)->response == CMD_MORE }
625 sub _LAST      { shift->command('LAST')->response == CMD_OK }
626 sub _LIST      { shift->command('LIST',@_)->response == CMD_OK }
627 sub _LISTGROUP { shift->command('LISTGROUP',@_)->response == CMD_OK }
628 sub _NEWGROUPS { shift->command('NEWGROUPS',@_)->response == CMD_OK }
629 sub _NEWNEWS   { shift->command('NEWNEWS',@_)->response == CMD_OK }
630 sub _NEXT      { shift->command('NEXT')->response == CMD_OK }
631 sub _POST      { shift->command('POST',@_)->response == CMD_MORE }
632 sub _QUIT      { shift->command('QUIT',@_)->response == CMD_OK }
633 sub _SLAVE     { shift->command('SLAVE',@_)->response == CMD_OK }
634 sub _STAT      { shift->command('STAT',@_)->response == CMD_OK }
635 sub _MODE      { shift->command('MODE',@_)->response == CMD_OK }
636 sub _XGTITLE   { shift->command('XGTITLE',@_)->response == CMD_OK }
637 sub _XHDR      { shift->command('XHDR',@_)->response == CMD_OK }
638 sub _XPAT      { shift->command('XPAT',@_)->response == CMD_OK }
639 sub _XPATH     { shift->command('XPATH',@_)->response == CMD_OK }
640 sub _XOVER     { shift->command('XOVER',@_)->response == CMD_OK }
641 sub _XROVER    { shift->command('XROVER',@_)->response == CMD_OK }
642 sub _XTHREAD   { shift->unsupported }
643 sub _XSEARCH   { shift->unsupported }
644 sub _XINDEX    { shift->unsupported }
645
646 ##
647 ## IO/perl methods
648 ##
649
650 sub DESTROY
651 {
652  my $nntp = shift;
653  defined(fileno($nntp)) && $nntp->quit
654 }
655
656
657 1;
658
659 __END__
660
661 =head1 NAME
662
663 Net::NNTP - NNTP Client class
664
665 =head1 SYNOPSIS
666
667     use Net::NNTP;
668
669     $nntp = Net::NNTP->new("some.host.name");
670     $nntp->quit;
671
672 =head1 DESCRIPTION
673
674 C<Net::NNTP> is a class implementing a simple NNTP client in Perl as described
675 in RFC977. C<Net::NNTP> inherits its communication methods from C<Net::Cmd>
676
677 =head1 CONSTRUCTOR
678
679 =over 4
680
681 =item new ( [ HOST ] [, OPTIONS ])
682
683 This is the constructor for a new Net::NNTP object. C<HOST> is the
684 name of the remote host to which a NNTP connection is required. If not
685 given two environment variables are checked, first C<NNTPSERVER> then
686 C<NEWSHOST>, then C<Net::Config> is checked, and if a host is not found
687 then C<news> is used.
688
689 C<OPTIONS> are passed in a hash like fashion, using key and value pairs.
690 Possible options are:
691
692 B<Timeout> - Maximum time, in seconds, to wait for a response from the
693 NNTP server, a value of zero will cause all IO operations to block.
694 (default: 120)
695
696 B<Debug> - Enable the printing of debugging information to STDERR
697
698 B<Reader> - If the remote server is INN then initially the connection
699 will be to nnrpd, by default C<Net::NNTP> will issue a C<MODE READER> command
700 so that the remote server becomes innd. If the C<Reader> option is given
701 with a value of zero, then this command will not be sent and the
702 connection will be left talking to nnrpd.
703
704 =back
705
706 =head1 METHODS
707
708 Unless otherwise stated all methods return either a I<true> or I<false>
709 value, with I<true> meaning that the operation was a success. When a method
710 states that it returns a value, failure will be returned as I<undef> or an
711 empty list.
712
713 =over 4
714
715 =item article ( [ MSGID|MSGNUM ], [FH] )
716
717 Retrieve the header, a blank line, then the body (text) of the
718 specified article. 
719
720 If C<FH> is specified then it is expected to be a valid filehandle
721 and the result will be printed to it, on sucess a true value will be
722 returned. If C<FH> is not specified then the return value, on sucess,
723 will be a reference to an array containg the article requested, each
724 entry in the array will contain one line of the article.
725
726 If no arguments are passed then the current article in the currently
727 selected newsgroup is fetched.
728
729 C<MSGNUM> is a numeric id of an article in the current newsgroup, and
730 will change the current article pointer.  C<MSGID> is the message id of
731 an article as shown in that article's header.  It is anticipated that the
732 client will obtain the C<MSGID> from a list provided by the C<newnews>
733 command, from references contained within another article, or from the
734 message-id provided in the response to some other commands.
735
736 If there is an error then C<undef> will be returned.
737
738 =item body ( [ MSGID|MSGNUM ], [FH] )
739
740 Like C<article> but only fetches the body of the article.
741
742 =item head ( [ MSGID|MSGNUM ], [FH] )
743
744 Like C<article> but only fetches the headers for the article.
745
746 =item nntpstat ( [ MSGID|MSGNUM ] )
747
748 The C<nntpstat> command is similar to the C<article> command except that no
749 text is returned.  When selecting by message number within a group,
750 the C<nntpstat> command serves to set the "current article pointer" without
751 sending text.
752
753 Using the C<nntpstat> command to
754 select by message-id is valid but of questionable value, since a
755 selection by message-id does B<not> alter the "current article pointer".
756
757 Returns the message-id of the "current article".
758
759 =item group ( [ GROUP ] )
760
761 Set and/or get the current group. If C<GROUP> is not given then information
762 is returned on the current group.
763
764 In a scalar context it returns the group name.
765
766 In an array context the return value is a list containing, the number
767 of articles in the group, the number of the first article, the number
768 of the last article and the group name.
769
770 =item ihave ( MSGID [, MESSAGE ])
771
772 The C<ihave> command informs the server that the client has an article
773 whose id is C<MSGID>.  If the server desires a copy of that
774 article, and C<MESSAGE> has been given the it will be sent.
775
776 Returns I<true> if the server desires the article and C<MESSAGE> was
777 successfully sent,if specified.
778
779 If C<MESSAGE> is not specified then the message must be sent using the
780 C<datasend> and C<dataend> methods from L<Net::Cmd>
781
782 C<MESSAGE> can be either an array of lines or a reference to an array.
783
784 =item last ()
785
786 Set the "current article pointer" to the previous article in the current
787 newsgroup.
788
789 Returns the message-id of the article.
790
791 =item date ()
792
793 Returns the date on the remote server. This date will be in a UNIX time
794 format (seconds since 1970)
795
796 =item postok ()
797
798 C<postok> will return I<true> if the servers initial response indicated
799 that it will allow posting.
800
801 =item authinfo ( USER, PASS )
802
803 =item list ()
804
805 Obtain information about all the active newsgroups. The results is a reference
806 to a hash where the key is a group name and each value is a reference to an
807 array. The elements in this array are:- the last article number in the group,
808 the first article number in the group and any information flags about the group.
809
810 =item newgroups ( SINCE [, DISTRIBUTIONS ])
811
812 C<SINCE> is a time value and C<DISTRIBUTIONS> is either a distribution
813 pattern or a reference to a list of distribution patterns.
814 The result is the same as C<list>, but the
815 groups return will be limited to those created after C<SINCE> and, if
816 specified, in one of the distribution areas in C<DISTRIBUTIONS>. 
817
818 =item newnews ( SINCE [, GROUPS [, DISTRIBUTIONS ]])
819
820 C<SINCE> is a time value. C<GROUPS> is either a group pattern or a reference
821 to a list of group patterns. C<DISTRIBUTIONS> is either a distribution
822 pattern or a reference to a list of distribution patterns.
823
824 Returns a reference to a list which contains the message-ids of all news posted
825 after C<SINCE>, that are in a groups which matched C<GROUPS> and a
826 distribution which matches C<DISTRIBUTIONS>.
827
828 =item next ()
829
830 Set the "current article pointer" to the next article in the current
831 newsgroup.
832
833 Returns the message-id of the article.
834
835 =item post ( [ MESSAGE ] )
836
837 Post a new article to the news server. If C<MESSAGE> is specified and posting
838 is allowed then the message will be sent.
839
840 If C<MESSAGE> is not specified then the message must be sent using the
841 C<datasend> and C<dataend> methods from L<Net::Cmd>
842
843 C<MESSAGE> can be either an array of lines or a reference to an array.
844
845 =item slave ()
846
847 Tell the remote server that I am not a user client, but probably another
848 news server.
849
850 =item quit ()
851
852 Quit the remote server and close the socket connection.
853
854 =back
855
856 =head2 Extension methods
857
858 These methods use commands that are not part of the RFC977 documentation. Some
859 servers may not support all of them.
860
861 =over 4
862
863 =item newsgroups ( [ PATTERN ] )
864
865 Returns a reference to a hash where the keys are all the group names which
866 match C<PATTERN>, or all of the groups if no pattern is specified, and
867 each value contains the description text for the group.
868
869 =item distributions ()
870
871 Returns a reference to a hash where the keys are all the possible
872 distribution names and the values are the distribution descriptions.
873
874 =item subscriptions ()
875
876 Returns a reference to a list which contains a list of groups which
877 are recommended for a new user to subscribe to.
878
879 =item overview_fmt ()
880
881 Returns a reference to an array which contain the names of the fields returned
882 by C<xover>.
883
884 =item active_times ()
885
886 Returns a reference to a hash where the keys are the group names and each
887 value is a reference to an array containing the time the groups was created
888 and an identifier, possibly an Email address, of the creator.
889
890 =item active ( [ PATTERN ] )
891
892 Similar to C<list> but only active groups that match the pattern are returned.
893 C<PATTERN> can be a group pattern.
894
895 =item xgtitle ( PATTERN )
896
897 Returns a reference to a hash where the keys are all the group names which
898 match C<PATTERN> and each value is the description text for the group.
899
900 =item xhdr ( HEADER, MESSAGE-SPEC )
901
902 Obtain the header field C<HEADER> for all the messages specified. 
903
904 The return value will be a reference
905 to a hash where the keys are the message numbers and each value contains
906 the text of the requested header for that message.
907
908 =item xover ( MESSAGE-SPEC )
909
910 The return value will be a reference
911 to a hash where the keys are the message numbers and each value contains
912 a reference to an array which contains the overview fields for that
913 message.
914
915 The names of the fields can be obtained by calling C<overview_fmt>.
916
917 =item xpath ( MESSAGE-ID )
918
919 Returns the path name to the file on the server which contains the specified
920 message.
921
922 =item xpat ( HEADER, PATTERN, MESSAGE-SPEC)
923
924 The result is the same as C<xhdr> except the is will be restricted to
925 headers where the text of the header matches C<PATTERN>
926
927 =item xrover
928
929 The XROVER command returns reference information for the article(s)
930 specified.
931
932 Returns a reference to a HASH where the keys are the message numbers and the
933 values are the References: lines from the articles
934
935 =item listgroup ( [ GROUP ] )
936
937 Returns a reference to a list of all the active messages in C<GROUP>, or
938 the current group if C<GROUP> is not specified.
939
940 =item reader
941
942 Tell the server that you are a reader and not another server.
943
944 This is required by some servers. For example if you are connecting to
945 an INN server and you have transfer permission your connection will
946 be connected to the transfer daemon, not the NNTP daemon. Issuing
947 this command will cause the transfer daemon to hand over control
948 to the NNTP daemon.
949
950 Some servers do not understand this command, but issuing it and ignoring
951 the response is harmless.
952
953 =back
954
955 =head1 UNSUPPORTED
956
957 The following NNTP command are unsupported by the package, and there are
958 no plans to do so.
959
960     AUTHINFO GENERIC
961     XTHREAD
962     XSEARCH
963     XINDEX
964
965 =head1 DEFINITIONS
966
967 =over 4
968
969 =item MESSAGE-SPEC
970
971 C<MESSAGE-SPEC> is either a single message-id, a single message number, or
972 a reference to a list of two message numbers.
973
974 If C<MESSAGE-SPEC> is a reference to a list of two message numbers and the
975 second number in a range is less than or equal to the first then the range
976 represents all messages in the group after the first message number.
977
978 B<NOTE> For compatibility reasons only with earlier versions of Net::NNTP
979 a message spec can be passed as a list of two numbers, this is deprecated
980 and a reference to the list should now be passed
981
982 =item PATTERN
983
984 The C<NNTP> protocol uses the C<WILDMAT> format for patterns.
985 The WILDMAT format was first developed by Rich Salz based on
986 the format used in the UNIX "find" command to articulate
987 file names. It was developed to provide a uniform mechanism
988 for matching patterns in the same manner that the UNIX shell
989 matches filenames.
990
991 Patterns are implicitly anchored at the
992 beginning and end of each string when testing for a match.
993
994 There are five pattern matching operations other than a strict
995 one-to-one match between the pattern and the source to be
996 checked for a match.
997
998 The first is an asterisk C<*> to match any sequence of zero or more
999 characters.
1000
1001 The second is a question mark C<?> to match any single character. The
1002 third specifies a specific set of characters.
1003
1004 The set is specified as a list of characters, or as a range of characters
1005 where the beginning and end of the range are separated by a minus (or dash)
1006 character, or as any combination of lists and ranges. The dash can
1007 also be included in the set as a character it if is the beginning
1008 or end of the set. This set is enclosed in square brackets. The
1009 close square bracket C<]> may be used in a set if it is the first
1010 character in the set.
1011
1012 The fourth operation is the same as the
1013 logical not of the third operation and is specified the same
1014 way as the third with the addition of a caret character C<^> at
1015 the beginning of the test string just inside the open square
1016 bracket.
1017
1018 The final operation uses the backslash character to
1019 invalidate the special meaning of an open square bracket C<[>,
1020 the asterisk, backslash or the question mark. Two backslashes in
1021 sequence will result in the evaluation of the backslash as a
1022 character with no special meaning.
1023
1024 =over 4
1025
1026 =item Examples
1027
1028 =item C<[^]-]>
1029
1030 matches any single character other than a close square
1031 bracket or a minus sign/dash.
1032
1033 =item C<*bdc>
1034
1035 matches any string that ends with the string "bdc"
1036 including the string "bdc" (without quotes).
1037
1038 =item C<[0-9a-zA-Z]>
1039
1040 matches any single printable alphanumeric ASCII character.
1041
1042 =item C<a??d>
1043
1044 matches any four character string which begins
1045 with a and ends with d.
1046
1047 =back
1048
1049 =back
1050
1051 =head1 SEE ALSO
1052
1053 L<Net::Cmd>
1054
1055 =head1 AUTHOR
1056
1057 Graham Barr <gbarr@pobox.com>
1058
1059 =head1 COPYRIGHT
1060
1061 Copyright (c) 1995-1997 Graham Barr. All rights reserved.
1062 This program is free software; you can redistribute it and/or modify
1063 it under the same terms as Perl itself.
1064
1065 =for html <hr>
1066
1067 I<$Id: //depot/libnet/Net/NNTP.pm#14 $>
1068
1069 =cut