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