diff -r 6d08f4a05d93 -r 3145852acc89 releasing/cbrtools/perl/Net/NNTP.pm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/releasing/cbrtools/perl/Net/NNTP.pm Fri Jun 25 18:37:20 2010 +0800 @@ -0,0 +1,1122 @@ +# Net::NNTP.pm +# +# Copyright (c) 1995-1997 Graham Barr . All rights reserved. +# This program is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. + +package Net::NNTP; + +use strict; +use vars qw(@ISA $VERSION $debug); +use IO::Socket; +use Net::Cmd; +use Carp; +use Time::Local; +use Net::Config; + +$VERSION = "2.22"; # $Id: //depot/libnet/Net/NNTP.pm#18 $ +@ISA = qw(Net::Cmd IO::Socket::INET); + +sub new +{ + my $self = shift; + my $type = ref($self) || $self; + my $host = shift if @_ % 2; + my %arg = @_; + my $obj; + + $host ||= $ENV{NNTPSERVER} || $ENV{NEWSHOST}; + + my $hosts = defined $host ? [ $host ] : $NetConfig{nntp_hosts}; + + @{$hosts} = qw(news) + unless @{$hosts}; + + my $h; + foreach $h (@{$hosts}) + { + $obj = $type->SUPER::new(PeerAddr => ($host = $h), + PeerPort => $arg{Port} || 'nntp(119)', + Proto => 'tcp', + Timeout => defined $arg{Timeout} + ? $arg{Timeout} + : 120 + ) and last; + } + + return undef + unless defined $obj; + + ${*$obj}{'net_nntp_host'} = $host; + + $obj->autoflush(1); + $obj->debug(exists $arg{Debug} ? $arg{Debug} : undef); + + unless ($obj->response() == CMD_OK) + { + $obj->close; + return undef; + } + + my $c = $obj->code; + my @m = $obj->message; + + unless(exists $arg{Reader} && $arg{Reader} == 0) { + # if server is INN and we have transfer rights the we are currently + # talking to innd not nnrpd + if($obj->reader) + { + # If reader suceeds the we need to consider this code to determine postok + $c = $obj->code; + } + else + { + # I want to ignore this failure, so restore the previous status. + $obj->set_status($c,\@m); + } + } + + ${*$obj}{'net_nntp_post'} = $c == 200 ? 1 : 0; + + $obj; +} + +sub debug_text +{ + my $nntp = shift; + my $inout = shift; + my $text = shift; + + if((ref($nntp) and $nntp->code == 350 and $text =~ /^(\S+)/) + || ($text =~ /^(authinfo\s+pass)/io)) + { + $text = "$1 ....\n" + } + + $text; +} + +sub postok +{ + @_ == 1 or croak 'usage: $nntp->postok()'; + my $nntp = shift; + ${*$nntp}{'net_nntp_post'} || 0; +} + +sub article +{ + @_ >= 1 && @_ <= 3 or croak 'usage: $nntp->article( [ MSGID ], [ FH ] )'; + my $nntp = shift; + my @fh; + + @fh = (pop) if @_ == 2 || (@_ && ref($_[0]) || ref(\$_[0]) eq 'GLOB'); + + $nntp->_ARTICLE(@_) + ? $nntp->read_until_dot(@fh) + : undef; +} + +sub articlefh { + @_ >= 1 && @_ <= 2 or croak 'usage: $nntp->articlefh( [ MSGID ] )'; + my $nntp = shift; + + return unless $nntp->_ARTICLE(@_); + return $nntp->tied_fh; +} + +sub authinfo +{ + @_ == 3 or croak 'usage: $nntp->authinfo( USER, PASS )'; + my($nntp,$user,$pass) = @_; + + $nntp->_AUTHINFO("USER",$user) == CMD_MORE + && $nntp->_AUTHINFO("PASS",$pass) == CMD_OK; +} + +sub authinfo_simple +{ + @_ == 3 or croak 'usage: $nntp->authinfo( USER, PASS )'; + my($nntp,$user,$pass) = @_; + + $nntp->_AUTHINFO('SIMPLE') == CMD_MORE + && $nntp->command($user,$pass)->response == CMD_OK; +} + +sub body +{ + @_ >= 1 && @_ <= 3 or croak 'usage: $nntp->body( [ MSGID ], [ FH ] )'; + my $nntp = shift; + my @fh; + + @fh = (pop) if @_ == 2 || (@_ && ref($_[0]) || ref(\$_[0]) eq 'GLOB'); + + $nntp->_BODY(@_) + ? $nntp->read_until_dot(@fh) + : undef; +} + +sub bodyfh +{ + @_ >= 1 && @_ <= 2 or croak 'usage: $nntp->bodyfh( [ MSGID ] )'; + my $nntp = shift; + return unless $nntp->_BODY(@_); + return $nntp->tied_fh; +} + +sub head +{ + @_ >= 1 && @_ <= 3 or croak 'usage: $nntp->head( [ MSGID ], [ FH ] )'; + my $nntp = shift; + my @fh; + + @fh = (pop) if @_ == 2 || (@_ && ref($_[0]) || ref(\$_[0]) eq 'GLOB'); + + $nntp->_HEAD(@_) + ? $nntp->read_until_dot(@fh) + : undef; +} + +sub headfh +{ + @_ >= 1 && @_ <= 2 or croak 'usage: $nntp->headfh( [ MSGID ] )'; + my $nntp = shift; + return unless $nntp->_HEAD(@_); + return $nntp->tied_fh; +} + +sub nntpstat +{ + @_ == 1 || @_ == 2 or croak 'usage: $nntp->nntpstat( [ MSGID ] )'; + my $nntp = shift; + + $nntp->_STAT(@_) && $nntp->message =~ /(<[^>]+>)/o + ? $1 + : undef; +} + + +sub group +{ + @_ == 1 || @_ == 2 or croak 'usage: $nntp->group( [ GROUP ] )'; + my $nntp = shift; + my $grp = ${*$nntp}{'net_nntp_group'} || undef; + + return $grp + unless(@_ || wantarray); + + my $newgrp = shift; + + return wantarray ? () : undef + unless $nntp->_GROUP($newgrp || $grp || "") + && $nntp->message =~ /(\d+)\s+(\d+)\s+(\d+)\s+(\S+)/; + + my($count,$first,$last,$group) = ($1,$2,$3,$4); + + # group may be replied as '(current group)' + $group = ${*$nntp}{'net_nntp_group'} + if $group =~ /\(/; + + ${*$nntp}{'net_nntp_group'} = $group; + + wantarray + ? ($count,$first,$last,$group) + : $group; +} + +sub help +{ + @_ == 1 or croak 'usage: $nntp->help()'; + my $nntp = shift; + + $nntp->_HELP + ? $nntp->read_until_dot + : undef; +} + +sub ihave +{ + @_ >= 2 or croak 'usage: $nntp->ihave( MESSAGE-ID [, MESSAGE ])'; + my $nntp = shift; + my $mid = shift; + + $nntp->_IHAVE($mid) && $nntp->datasend(@_) + ? @_ == 0 || $nntp->dataend + : undef; +} + +sub last +{ + @_ == 1 or croak 'usage: $nntp->last()'; + my $nntp = shift; + + $nntp->_LAST && $nntp->message =~ /(<[^>]+>)/o + ? $1 + : undef; +} + +sub list +{ + @_ == 1 or croak 'usage: $nntp->list()'; + my $nntp = shift; + + $nntp->_LIST + ? $nntp->_grouplist + : undef; +} + +sub newgroups +{ + @_ >= 2 or croak 'usage: $nntp->newgroups( SINCE [, DISTRIBUTIONS ])'; + my $nntp = shift; + my $time = _timestr(shift); + my $dist = shift || ""; + + $dist = join(",", @{$dist}) + if ref($dist); + + $nntp->_NEWGROUPS($time,$dist) + ? $nntp->_grouplist + : undef; +} + +sub newnews +{ + @_ >= 2 && @_ <= 4 or + croak 'usage: $nntp->newnews( SINCE [, GROUPS [, DISTRIBUTIONS ]])'; + my $nntp = shift; + my $time = _timestr(shift); + my $grp = @_ ? shift : $nntp->group; + my $dist = shift || ""; + + $grp ||= "*"; + $grp = join(",", @{$grp}) + if ref($grp); + + $dist = join(",", @{$dist}) + if ref($dist); + + $nntp->_NEWNEWS($grp,$time,$dist) + ? $nntp->_articlelist + : undef; +} + +sub next +{ + @_ == 1 or croak 'usage: $nntp->next()'; + my $nntp = shift; + + $nntp->_NEXT && $nntp->message =~ /(<[^>]+>)/o + ? $1 + : undef; +} + +sub post +{ + @_ >= 1 or croak 'usage: $nntp->post( [ MESSAGE ] )'; + my $nntp = shift; + + $nntp->_POST() && $nntp->datasend(@_) + ? @_ == 0 || $nntp->dataend + : undef; +} + +sub postfh { + my $nntp = shift; + return unless $nntp->_POST(); + return $nntp->tied_fh; +} + +sub quit +{ + @_ == 1 or croak 'usage: $nntp->quit()'; + my $nntp = shift; + + $nntp->_QUIT; + $nntp->close; +} + +sub slave +{ + @_ == 1 or croak 'usage: $nntp->slave()'; + my $nntp = shift; + + $nntp->_SLAVE; +} + +## +## The following methods are not implemented by all servers +## + +sub active +{ + @_ == 1 || @_ == 2 or croak 'usage: $nntp->active( [ PATTERN ] )'; + my $nntp = shift; + + $nntp->_LIST('ACTIVE',@_) + ? $nntp->_grouplist + : undef; +} + +sub active_times +{ + @_ == 1 or croak 'usage: $nntp->active_times()'; + my $nntp = shift; + + $nntp->_LIST('ACTIVE.TIMES') + ? $nntp->_grouplist + : undef; +} + +sub distributions +{ + @_ == 1 or croak 'usage: $nntp->distributions()'; + my $nntp = shift; + + $nntp->_LIST('DISTRIBUTIONS') + ? $nntp->_description + : undef; +} + +sub distribution_patterns +{ + @_ == 1 or croak 'usage: $nntp->distributions()'; + my $nntp = shift; + + my $arr; + local $_; + + $nntp->_LIST('DISTRIB.PATS') && ($arr = $nntp->read_until_dot) + ? [grep { /^\d/ && (chomp, $_ = [ split /:/ ]) } @$arr] + : undef; +} + +sub newsgroups +{ + @_ == 1 || @_ == 2 or croak 'usage: $nntp->newsgroups( [ PATTERN ] )'; + my $nntp = shift; + + $nntp->_LIST('NEWSGROUPS',@_) + ? $nntp->_description + : undef; +} + +sub overview_fmt +{ + @_ == 1 or croak 'usage: $nntp->overview_fmt()'; + my $nntp = shift; + + $nntp->_LIST('OVERVIEW.FMT') + ? $nntp->_articlelist + : undef; +} + +sub subscriptions +{ + @_ == 1 or croak 'usage: $nntp->subscriptions()'; + my $nntp = shift; + + $nntp->_LIST('SUBSCRIPTIONS') + ? $nntp->_articlelist + : undef; +} + +sub listgroup +{ + @_ == 1 || @_ == 2 or croak 'usage: $nntp->listgroup( [ GROUP ] )'; + my $nntp = shift; + + $nntp->_LISTGROUP(@_) + ? $nntp->_articlelist + : undef; +} + +sub reader +{ + @_ == 1 or croak 'usage: $nntp->reader()'; + my $nntp = shift; + + $nntp->_MODE('READER'); +} + +sub xgtitle +{ + @_ == 1 || @_ == 2 or croak 'usage: $nntp->xgtitle( [ PATTERN ] )'; + my $nntp = shift; + + $nntp->_XGTITLE(@_) + ? $nntp->_description + : undef; +} + +sub xhdr +{ + @_ >= 2 && @_ <= 4 or croak 'usage: $nntp->xhdr( HEADER, [ MESSAGE-SPEC ] )'; + my $nntp = shift; + my $hdr = shift; + my $arg = _msg_arg(@_); + + $nntp->_XHDR($hdr, $arg) + ? $nntp->_description + : undef; +} + +sub xover +{ + @_ == 2 || @_ == 3 or croak 'usage: $nntp->xover( MESSAGE-SPEC )'; + my $nntp = shift; + my $arg = _msg_arg(@_); + + $nntp->_XOVER($arg) + ? $nntp->_fieldlist + : undef; +} + +sub xpat +{ + @_ == 4 || @_ == 5 or croak '$nntp->xpat( HEADER, PATTERN, MESSAGE-SPEC )'; + my $nntp = shift; + my $hdr = shift; + my $pat = shift; + my $arg = _msg_arg(@_); + + $pat = join(" ", @$pat) + if ref($pat); + + $nntp->_XPAT($hdr,$arg,$pat) + ? $nntp->_description + : undef; +} + +sub xpath +{ + @_ == 2 or croak 'usage: $nntp->xpath( MESSAGE-ID )'; + my($nntp,$mid) = @_; + + return undef + unless $nntp->_XPATH($mid); + + my $m; ($m = $nntp->message) =~ s/^\d+\s+//o; + my @p = split /\s+/, $m; + + wantarray ? @p : $p[0]; +} + +sub xrover +{ + @_ == 2 || @_ == 3 or croak 'usage: $nntp->xrover( MESSAGE-SPEC )'; + my $nntp = shift; + my $arg = _msg_arg(@_); + + $nntp->_XROVER($arg) + ? $nntp->_description + : undef; +} + +sub date +{ + @_ == 1 or croak 'usage: $nntp->date()'; + my $nntp = shift; + + $nntp->_DATE && $nntp->message =~ /(\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)/ + ? timegm($6,$5,$4,$3,$2-1,$1 - 1900) + : undef; +} + + +## +## Private subroutines +## + +sub _msg_arg +{ + my $spec = shift; + my $arg = ""; + + if(@_) + { + carp "Depriciated passing of two message numbers, " + . "pass a reference" + if $^W; + $spec = [ $spec, $_[0] ]; + } + + if(defined $spec) + { + if(ref($spec)) + { + $arg = $spec->[0]; + if(defined $spec->[1]) + { + $arg .= "-" + if $spec->[1] != $spec->[0]; + $arg .= $spec->[1] + if $spec->[1] > $spec->[0]; + } + } + else + { + $arg = $spec; + } + } + + $arg; +} + +sub _timestr +{ + my $time = shift; + my @g = reverse((gmtime($time))[0..5]); + $g[1] += 1; + $g[0] %= 100; + sprintf "%02d%02d%02d %02d%02d%02d GMT", @g; +} + +sub _grouplist +{ + my $nntp = shift; + my $arr = $nntp->read_until_dot or + return undef; + + my $hash = {}; + my $ln; + + foreach $ln (@$arr) + { + my @a = split(/[\s\n]+/,$ln); + $hash->{$a[0]} = [ @a[1,2,3] ]; + } + + $hash; +} + +sub _fieldlist +{ + my $nntp = shift; + my $arr = $nntp->read_until_dot or + return undef; + + my $hash = {}; + my $ln; + + foreach $ln (@$arr) + { + my @a = split(/[\t\n]/,$ln); + my $m = shift @a; + $hash->{$m} = [ @a ]; + } + + $hash; +} + +sub _articlelist +{ + my $nntp = shift; + my $arr = $nntp->read_until_dot; + + chomp(@$arr) + if $arr; + + $arr; +} + +sub _description +{ + my $nntp = shift; + my $arr = $nntp->read_until_dot or + return undef; + + my $hash = {}; + my $ln; + + foreach $ln (@$arr) + { + chomp($ln); + + $hash->{$1} = $ln + if $ln =~ s/^\s*(\S+)\s*//o; + } + + $hash; + +} + +## +## The commands +## + +sub _ARTICLE { shift->command('ARTICLE',@_)->response == CMD_OK } +sub _AUTHINFO { shift->command('AUTHINFO',@_)->response } +sub _BODY { shift->command('BODY',@_)->response == CMD_OK } +sub _DATE { shift->command('DATE')->response == CMD_INFO } +sub _GROUP { shift->command('GROUP',@_)->response == CMD_OK } +sub _HEAD { shift->command('HEAD',@_)->response == CMD_OK } +sub _HELP { shift->command('HELP',@_)->response == CMD_INFO } +sub _IHAVE { shift->command('IHAVE',@_)->response == CMD_MORE } +sub _LAST { shift->command('LAST')->response == CMD_OK } +sub _LIST { shift->command('LIST',@_)->response == CMD_OK } +sub _LISTGROUP { shift->command('LISTGROUP',@_)->response == CMD_OK } +sub _NEWGROUPS { shift->command('NEWGROUPS',@_)->response == CMD_OK } +sub _NEWNEWS { shift->command('NEWNEWS',@_)->response == CMD_OK } +sub _NEXT { shift->command('NEXT')->response == CMD_OK } +sub _POST { shift->command('POST',@_)->response == CMD_MORE } +sub _QUIT { shift->command('QUIT',@_)->response == CMD_OK } +sub _SLAVE { shift->command('SLAVE',@_)->response == CMD_OK } +sub _STAT { shift->command('STAT',@_)->response == CMD_OK } +sub _MODE { shift->command('MODE',@_)->response == CMD_OK } +sub _XGTITLE { shift->command('XGTITLE',@_)->response == CMD_OK } +sub _XHDR { shift->command('XHDR',@_)->response == CMD_OK } +sub _XPAT { shift->command('XPAT',@_)->response == CMD_OK } +sub _XPATH { shift->command('XPATH',@_)->response == CMD_OK } +sub _XOVER { shift->command('XOVER',@_)->response == CMD_OK } +sub _XROVER { shift->command('XROVER',@_)->response == CMD_OK } +sub _XTHREAD { shift->unsupported } +sub _XSEARCH { shift->unsupported } +sub _XINDEX { shift->unsupported } + +## +## IO/perl methods +## + +sub DESTROY +{ + my $nntp = shift; + defined(fileno($nntp)) && $nntp->quit +} + + +1; + +__END__ + +=head1 NAME + +Net::NNTP - NNTP Client class + +=head1 SYNOPSIS + + use Net::NNTP; + + $nntp = Net::NNTP->new("some.host.name"); + $nntp->quit; + +=head1 DESCRIPTION + +C is a class implementing a simple NNTP client in Perl as described +in RFC977. C inherits its communication methods from C + +=head1 CONSTRUCTOR + +=over 4 + +=item new ( [ HOST ] [, OPTIONS ]) + +This is the constructor for a new Net::NNTP object. C is the +name of the remote host to which a NNTP connection is required. If not +given two environment variables are checked, first C then +C, then C is checked, and if a host is not found +then C is used. + +C are passed in a hash like fashion, using key and value pairs. +Possible options are: + +B - Maximum time, in seconds, to wait for a response from the +NNTP server, a value of zero will cause all IO operations to block. +(default: 120) + +B - Enable the printing of debugging information to STDERR + +B - If the remote server is INN then initially the connection +will be to nnrpd, by default C will issue a C command +so that the remote server becomes innd. If the C option is given +with a value of zero, then this command will not be sent and the +connection will be left talking to nnrpd. + +=back + +=head1 METHODS + +Unless otherwise stated all methods return either a I or I +value, with I meaning that the operation was a success. When a method +states that it returns a value, failure will be returned as I or an +empty list. + +=over 4 + +=item article ( [ MSGID|MSGNUM ], [FH] ) + +Retrieve the header, a blank line, then the body (text) of the +specified article. + +If C is specified then it is expected to be a valid filehandle +and the result will be printed to it, on success a true value will be +returned. If C is not specified then the return value, on success, +will be a reference to an array containg the article requested, each +entry in the array will contain one line of the article. + +If no arguments are passed then the current article in the currently +selected newsgroup is fetched. + +C is a numeric id of an article in the current newsgroup, and +will change the current article pointer. C is the message id of +an article as shown in that article's header. It is anticipated that the +client will obtain the C from a list provided by the C +command, from references contained within another article, or from the +message-id provided in the response to some other commands. + +If there is an error then C will be returned. + +=item body ( [ MSGID|MSGNUM ], [FH] ) + +Like C
but only fetches the body of the article. + +=item head ( [ MSGID|MSGNUM ], [FH] ) + +Like C
but only fetches the headers for the article. + +=item articlefh ( [ MSGID|MSGNUM ] ) + +=item bodyfh ( [ MSGID|MSGNUM ] ) + +=item headfh ( [ MSGID|MSGNUM ] ) + +These are similar to article(), body() and head(), but rather than +returning the requested data directly, they return a tied filehandle +from which to read the article. + +=item nntpstat ( [ MSGID|MSGNUM ] ) + +The C command is similar to the C
command except that no +text is returned. When selecting by message number within a group, +the C command serves to set the "current article pointer" without +sending text. + +Using the C command to +select by message-id is valid but of questionable value, since a +selection by message-id does B alter the "current article pointer". + +Returns the message-id of the "current article". + +=item group ( [ GROUP ] ) + +Set and/or get the current group. If C is not given then information +is returned on the current group. + +In a scalar context it returns the group name. + +In an array context the return value is a list containing, the number +of articles in the group, the number of the first article, the number +of the last article and the group name. + +=item ihave ( MSGID [, MESSAGE ]) + +The C command informs the server that the client has an article +whose id is C. If the server desires a copy of that +article, and C has been given the it will be sent. + +Returns I if the server desires the article and C was +successfully sent,if specified. + +If C is not specified then the message must be sent using the +C and C methods from L + +C can be either an array of lines or a reference to an array. + +=item last () + +Set the "current article pointer" to the previous article in the current +newsgroup. + +Returns the message-id of the article. + +=item date () + +Returns the date on the remote server. This date will be in a UNIX time +format (seconds since 1970) + +=item postok () + +C will return I if the servers initial response indicated +that it will allow posting. + +=item authinfo ( USER, PASS ) + +=item list () + +Obtain information about all the active newsgroups. The results is a reference +to a hash where the key is a group name and each value is a reference to an +array. The elements in this array are:- the last article number in the group, +the first article number in the group and any information flags about the group. + +=item newgroups ( SINCE [, DISTRIBUTIONS ]) + +C is a time value and C is either a distribution +pattern or a reference to a list of distribution patterns. +The result is the same as C, but the +groups return will be limited to those created after C and, if +specified, in one of the distribution areas in C. + +=item newnews ( SINCE [, GROUPS [, DISTRIBUTIONS ]]) + +C is a time value. C is either a group pattern or a reference +to a list of group patterns. C is either a distribution +pattern or a reference to a list of distribution patterns. + +Returns a reference to a list which contains the message-ids of all news posted +after C, that are in a groups which matched C and a +distribution which matches C. + +=item next () + +Set the "current article pointer" to the next article in the current +newsgroup. + +Returns the message-id of the article. + +=item post ( [ MESSAGE ] ) + +Post a new article to the news server. If C is specified and posting +is allowed then the message will be sent. + +If C is not specified then the message must be sent using the +C and C methods from L + +C can be either an array of lines or a reference to an array. + +The message, either sent via C or as the C +parameter, must be in the format as described by RFC822 and must +contain From:, Newsgroups: and Subject: headers. + +=item postfh () + +Post a new article to the news server using a tied filehandle. If +posting is allowed, this method will return a tied filehandle that you +can print() the contents of the article to be posted. You must +explicitly close() the filehandle when you are finished posting the +article, and the return value from the close() call will indicate +whether the message was successfully posted. + +=item slave () + +Tell the remote server that I am not a user client, but probably another +news server. + +=item quit () + +Quit the remote server and close the socket connection. + +=back + +=head2 Extension methods + +These methods use commands that are not part of the RFC977 documentation. Some +servers may not support all of them. + +=over 4 + +=item newsgroups ( [ PATTERN ] ) + +Returns a reference to a hash where the keys are all the group names which +match C, or all of the groups if no pattern is specified, and +each value contains the description text for the group. + +=item distributions () + +Returns a reference to a hash where the keys are all the possible +distribution names and the values are the distribution descriptions. + +=item subscriptions () + +Returns a reference to a list which contains a list of groups which +are recommended for a new user to subscribe to. + +=item overview_fmt () + +Returns a reference to an array which contain the names of the fields returned +by C. + +=item active_times () + +Returns a reference to a hash where the keys are the group names and each +value is a reference to an array containing the time the groups was created +and an identifier, possibly an Email address, of the creator. + +=item active ( [ PATTERN ] ) + +Similar to C but only active groups that match the pattern are returned. +C can be a group pattern. + +=item xgtitle ( PATTERN ) + +Returns a reference to a hash where the keys are all the group names which +match C and each value is the description text for the group. + +=item xhdr ( HEADER, MESSAGE-SPEC ) + +Obtain the header field C
for all the messages specified. + +The return value will be a reference +to a hash where the keys are the message numbers and each value contains +the text of the requested header for that message. + +=item xover ( MESSAGE-SPEC ) + +The return value will be a reference +to a hash where the keys are the message numbers and each value contains +a reference to an array which contains the overview fields for that +message. + +The names of the fields can be obtained by calling C. + +=item xpath ( MESSAGE-ID ) + +Returns the path name to the file on the server which contains the specified +message. + +=item xpat ( HEADER, PATTERN, MESSAGE-SPEC) + +The result is the same as C except the is will be restricted to +headers where the text of the header matches C + +=item xrover + +The XROVER command returns reference information for the article(s) +specified. + +Returns a reference to a HASH where the keys are the message numbers and the +values are the References: lines from the articles + +=item listgroup ( [ GROUP ] ) + +Returns a reference to a list of all the active messages in C, or +the current group if C is not specified. + +=item reader + +Tell the server that you are a reader and not another server. + +This is required by some servers. For example if you are connecting to +an INN server and you have transfer permission your connection will +be connected to the transfer daemon, not the NNTP daemon. Issuing +this command will cause the transfer daemon to hand over control +to the NNTP daemon. + +Some servers do not understand this command, but issuing it and ignoring +the response is harmless. + +=back + +=head1 UNSUPPORTED + +The following NNTP command are unsupported by the package, and there are +no plans to do so. + + AUTHINFO GENERIC + XTHREAD + XSEARCH + XINDEX + +=head1 DEFINITIONS + +=over 4 + +=item MESSAGE-SPEC + +C is either a single message-id, a single message number, or +a reference to a list of two message numbers. + +If C is a reference to a list of two message numbers and the +second number in a range is less than or equal to the first then the range +represents all messages in the group after the first message number. + +B For compatibility reasons only with earlier versions of Net::NNTP +a message spec can be passed as a list of two numbers, this is deprecated +and a reference to the list should now be passed + +=item PATTERN + +The C protocol uses the C format for patterns. +The WILDMAT format was first developed by Rich Salz based on +the format used in the UNIX "find" command to articulate +file names. It was developed to provide a uniform mechanism +for matching patterns in the same manner that the UNIX shell +matches filenames. + +Patterns are implicitly anchored at the +beginning and end of each string when testing for a match. + +There are five pattern matching operations other than a strict +one-to-one match between the pattern and the source to be +checked for a match. + +The first is an asterisk C<*> to match any sequence of zero or more +characters. + +The second is a question mark C to match any single character. The +third specifies a specific set of characters. + +The set is specified as a list of characters, or as a range of characters +where the beginning and end of the range are separated by a minus (or dash) +character, or as any combination of lists and ranges. The dash can +also be included in the set as a character it if is the beginning +or end of the set. This set is enclosed in square brackets. The +close square bracket C<]> may be used in a set if it is the first +character in the set. + +The fourth operation is the same as the +logical not of the third operation and is specified the same +way as the third with the addition of a caret character C<^> at +the beginning of the test string just inside the open square +bracket. + +The final operation uses the backslash character to +invalidate the special meaning of an open square bracket C<[>, +the asterisk, backslash or the question mark. Two backslashes in +sequence will result in the evaluation of the backslash as a +character with no special meaning. + +=over 4 + +=item Examples + +=item C<[^]-]> + +matches any single character other than a close square +bracket or a minus sign/dash. + +=item C<*bdc> + +matches any string that ends with the string "bdc" +including the string "bdc" (without quotes). + +=item C<[0-9a-zA-Z]> + +matches any single printable alphanumeric ASCII character. + +=item C + +matches any four character string which begins +with a and ends with d. + +=back + +=back + +=head1 SEE ALSO + +L + +=head1 AUTHOR + +Graham Barr + +=head1 COPYRIGHT + +Copyright (c) 1995-1997 Graham Barr. All rights reserved. +This program is free software; you can redistribute it and/or modify +it under the same terms as Perl itself. + +=for html
+ +I<$Id: //depot/libnet/Net/NNTP.pm#18 $> + +=cut