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