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