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.23"; 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,%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 90sub host { 91 my $me = shift; 92 ${*$me}{'net_nntp_host'}; 93} 94 95sub 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 110sub postok 111{ 112 @_ == 1 or croak 'usage: $nntp->postok()'; 113 my $nntp = shift; 114 ${*$nntp}{'net_nntp_post'} || 0; 115} 116 117sub 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 130sub 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 138sub 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 147sub 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 156sub 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 169sub 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 177sub 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 190sub 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 198sub 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 209sub 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 237sub 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 247sub 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 258sub 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 268sub list 269{ 270 @_ == 1 or croak 'usage: $nntp->list()'; 271 my $nntp = shift; 272 273 $nntp->_LIST 274 ? $nntp->_grouplist 275 : undef; 276} 277 278sub 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 293sub 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 314sub 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 324sub 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 334sub postfh { 335 my $nntp = shift; 336 return unless $nntp->_POST(); 337 return $nntp->tied_fh; 338} 339 340sub quit 341{ 342 @_ == 1 or croak 'usage: $nntp->quit()'; 343 my $nntp = shift; 344 345 $nntp->_QUIT; 346 $nntp->close; 347} 348 349sub 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 361sub 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 371sub 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 381sub 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 391sub 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 404sub 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 414sub 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 424sub 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 434sub 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 444sub reader 445{ 446 @_ == 1 or croak 'usage: $nntp->reader()'; 447 my $nntp = shift; 448 449 $nntp->_MODE('READER'); 450} 451 452sub 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 462sub 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 474sub 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 485sub 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 501sub 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 515sub 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 526sub 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 541sub _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 576sub _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 585sub _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 603sub _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 622sub _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 633sub _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 658sub _ARTICLE { shift->command('ARTICLE',@_)->response == CMD_OK } 659sub _AUTHINFO { shift->command('AUTHINFO',@_)->response } 660sub _BODY { shift->command('BODY',@_)->response == CMD_OK } 661sub _DATE { shift->command('DATE')->response == CMD_INFO } 662sub _GROUP { shift->command('GROUP',@_)->response == CMD_OK } 663sub _HEAD { shift->command('HEAD',@_)->response == CMD_OK } 664sub _HELP { shift->command('HELP',@_)->response == CMD_INFO } 665sub _IHAVE { shift->command('IHAVE',@_)->response == CMD_MORE } 666sub _LAST { shift->command('LAST')->response == CMD_OK } 667sub _LIST { shift->command('LIST',@_)->response == CMD_OK } 668sub _LISTGROUP { shift->command('LISTGROUP',@_)->response == CMD_OK } 669sub _NEWGROUPS { shift->command('NEWGROUPS',@_)->response == CMD_OK } 670sub _NEWNEWS { shift->command('NEWNEWS',@_)->response == CMD_OK } 671sub _NEXT { shift->command('NEXT')->response == CMD_OK } 672sub _POST { shift->command('POST',@_)->response == CMD_MORE } 673sub _QUIT { shift->command('QUIT',@_)->response == CMD_OK } 674sub _SLAVE { shift->command('SLAVE',@_)->response == CMD_OK } 675sub _STAT { shift->command('STAT',@_)->response == CMD_OK } 676sub _MODE { shift->command('MODE',@_)->response == CMD_OK } 677sub _XGTITLE { shift->command('XGTITLE',@_)->response == CMD_OK } 678sub _XHDR { shift->command('XHDR',@_)->response == CMD_OK } 679sub _XPAT { shift->command('XPAT',@_)->response == CMD_OK } 680sub _XPATH { shift->command('XPATH',@_)->response == CMD_OK } 681sub _XOVER { shift->command('XOVER',@_)->response == CMD_OK } 682sub _XROVER { shift->command('XROVER',@_)->response == CMD_OK } 683sub _XTHREAD { shift->unsupported } 684sub _XSEARCH { shift->unsupported } 685sub _XINDEX { shift->unsupported } 686 687## 688## IO/perl methods 689## 690 691sub DESTROY 692{ 693 my $nntp = shift; 694 defined(fileno($nntp)) && $nntp->quit 695} 696 697 6981; 699 700__END__ 701 702=head1 NAME 703 704Net::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 715C<Net::NNTP> is a class implementing a simple NNTP client in Perl as described 716in 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 724This is the constructor for a new Net::NNTP object. C<HOST> is the 725name of the remote host to which a NNTP connection is required. If not 726given then it may be passed as the C<Host> option described below. If no host is passed 727then two environment variables are checked, first C<NNTPSERVER> then 728C<NEWSHOST>, then C<Net::Config> is checked, and if a host is not found 729then C<news> is used. 730 731C<OPTIONS> are passed in a hash like fashion, using key and value pairs. 732Possible options are: 733 734B<Host> - NNTP host to connect to. It may be a single scalar, as defined for 735the C<PeerAddr> option in L<IO::Socket::INET>, or a reference to 736an array with hosts to try in turn. The L</host> method will return the value 737which was used to connect to the host. 738 739B<Timeout> - Maximum time, in seconds, to wait for a response from the 740NNTP server, a value of zero will cause all IO operations to block. 741(default: 120) 742 743B<Debug> - Enable the printing of debugging information to STDERR 744 745B<Reader> - If the remote server is INN then initially the connection 746will be to nnrpd, by default C<Net::NNTP> will issue a C<MODE READER> command 747so that the remote server becomes innd. If the C<Reader> option is given 748with a value of zero, then this command will not be sent and the 749connection will be left talking to nnrpd. 750 751=back 752 753=head1 METHODS 754 755Unless otherwise stated all methods return either a I<true> or I<false> 756value, with I<true> meaning that the operation was a success. When a method 757states that it returns a value, failure will be returned as I<undef> or an 758empty list. 759 760=over 4 761 762=item article ( [ MSGID|MSGNUM ], [FH] ) 763 764Retrieve the header, a blank line, then the body (text) of the 765specified article. 766 767If C<FH> is specified then it is expected to be a valid filehandle 768and the result will be printed to it, on success a true value will be 769returned. If C<FH> is not specified then the return value, on success, 770will be a reference to an array containg the article requested, each 771entry in the array will contain one line of the article. 772 773If no arguments are passed then the current article in the currently 774selected newsgroup is fetched. 775 776C<MSGNUM> is a numeric id of an article in the current newsgroup, and 777will change the current article pointer. C<MSGID> is the message id of 778an article as shown in that article's header. It is anticipated that the 779client will obtain the C<MSGID> from a list provided by the C<newnews> 780command, from references contained within another article, or from the 781message-id provided in the response to some other commands. 782 783If there is an error then C<undef> will be returned. 784 785=item body ( [ MSGID|MSGNUM ], [FH] ) 786 787Like C<article> but only fetches the body of the article. 788 789=item head ( [ MSGID|MSGNUM ], [FH] ) 790 791Like 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 799These are similar to article(), body() and head(), but rather than 800returning the requested data directly, they return a tied filehandle 801from which to read the article. 802 803=item nntpstat ( [ MSGID|MSGNUM ] ) 804 805The C<nntpstat> command is similar to the C<article> command except that no 806text is returned. When selecting by message number within a group, 807the C<nntpstat> command serves to set the "current article pointer" without 808sending text. 809 810Using the C<nntpstat> command to 811select by message-id is valid but of questionable value, since a 812selection by message-id does B<not> alter the "current article pointer". 813 814Returns the message-id of the "current article". 815 816=item group ( [ GROUP ] ) 817 818Set and/or get the current group. If C<GROUP> is not given then information 819is returned on the current group. 820 821In a scalar context it returns the group name. 822 823In an array context the return value is a list containing, the number 824of articles in the group, the number of the first article, the number 825of the last article and the group name. 826 827=item ihave ( MSGID [, MESSAGE ]) 828 829The C<ihave> command informs the server that the client has an article 830whose id is C<MSGID>. If the server desires a copy of that 831article, and C<MESSAGE> has been given the it will be sent. 832 833Returns I<true> if the server desires the article and C<MESSAGE> was 834successfully sent,if specified. 835 836If C<MESSAGE> is not specified then the message must be sent using the 837C<datasend> and C<dataend> methods from L<Net::Cmd> 838 839C<MESSAGE> can be either an array of lines or a reference to an array. 840 841=item last () 842 843Set the "current article pointer" to the previous article in the current 844newsgroup. 845 846Returns the message-id of the article. 847 848=item date () 849 850Returns the date on the remote server. This date will be in a UNIX time 851format (seconds since 1970) 852 853=item postok () 854 855C<postok> will return I<true> if the servers initial response indicated 856that it will allow posting. 857 858=item authinfo ( USER, PASS ) 859 860Authenticates to the server (using AUTHINFO USER / AUTHINFO PASS) 861using the supplied username and password. Please note that the 862password is sent in clear text to the server. This command should not 863be used with valuable passwords unless the connection to the server is 864somehow protected. 865 866=item list () 867 868Obtain information about all the active newsgroups. The results is a reference 869to a hash where the key is a group name and each value is a reference to an 870array. The elements in this array are:- the last article number in the group, 871the first article number in the group and any information flags about the group. 872 873=item newgroups ( SINCE [, DISTRIBUTIONS ]) 874 875C<SINCE> is a time value and C<DISTRIBUTIONS> is either a distribution 876pattern or a reference to a list of distribution patterns. 877The result is the same as C<list>, but the 878groups return will be limited to those created after C<SINCE> and, if 879specified, in one of the distribution areas in C<DISTRIBUTIONS>. 880 881=item newnews ( SINCE [, GROUPS [, DISTRIBUTIONS ]]) 882 883C<SINCE> is a time value. C<GROUPS> is either a group pattern or a reference 884to a list of group patterns. C<DISTRIBUTIONS> is either a distribution 885pattern or a reference to a list of distribution patterns. 886 887Returns a reference to a list which contains the message-ids of all news posted 888after C<SINCE>, that are in a groups which matched C<GROUPS> and a 889distribution which matches C<DISTRIBUTIONS>. 890 891=item next () 892 893Set the "current article pointer" to the next article in the current 894newsgroup. 895 896Returns the message-id of the article. 897 898=item post ( [ MESSAGE ] ) 899 900Post a new article to the news server. If C<MESSAGE> is specified and posting 901is allowed then the message will be sent. 902 903If C<MESSAGE> is not specified then the message must be sent using the 904C<datasend> and C<dataend> methods from L<Net::Cmd> 905 906C<MESSAGE> can be either an array of lines or a reference to an array. 907 908The message, either sent via C<datasend> or as the C<MESSAGE> 909parameter, must be in the format as described by RFC822 and must 910contain From:, Newsgroups: and Subject: headers. 911 912=item postfh () 913 914Post a new article to the news server using a tied filehandle. If 915posting is allowed, this method will return a tied filehandle that you 916can print() the contents of the article to be posted. You must 917explicitly close() the filehandle when you are finished posting the 918article, and the return value from the close() call will indicate 919whether the message was successfully posted. 920 921=item slave () 922 923Tell the remote server that I am not a user client, but probably another 924news server. 925 926=item quit () 927 928Quit the remote server and close the socket connection. 929 930=back 931 932=head2 Extension methods 933 934These methods use commands that are not part of the RFC977 documentation. Some 935servers may not support all of them. 936 937=over 4 938 939=item newsgroups ( [ PATTERN ] ) 940 941Returns a reference to a hash where the keys are all the group names which 942match C<PATTERN>, or all of the groups if no pattern is specified, and 943each value contains the description text for the group. 944 945=item distributions () 946 947Returns a reference to a hash where the keys are all the possible 948distribution names and the values are the distribution descriptions. 949 950=item subscriptions () 951 952Returns a reference to a list which contains a list of groups which 953are recommended for a new user to subscribe to. 954 955=item overview_fmt () 956 957Returns a reference to an array which contain the names of the fields returned 958by C<xover>. 959 960=item active_times () 961 962Returns a reference to a hash where the keys are the group names and each 963value is a reference to an array containing the time the groups was created 964and an identifier, possibly an Email address, of the creator. 965 966=item active ( [ PATTERN ] ) 967 968Similar to C<list> but only active groups that match the pattern are returned. 969C<PATTERN> can be a group pattern. 970 971=item xgtitle ( PATTERN ) 972 973Returns a reference to a hash where the keys are all the group names which 974match C<PATTERN> and each value is the description text for the group. 975 976=item xhdr ( HEADER, MESSAGE-SPEC ) 977 978Obtain the header field C<HEADER> for all the messages specified. 979 980The return value will be a reference 981to a hash where the keys are the message numbers and each value contains 982the text of the requested header for that message. 983 984=item xover ( MESSAGE-SPEC ) 985 986The return value will be a reference 987to a hash where the keys are the message numbers and each value contains 988a reference to an array which contains the overview fields for that 989message. 990 991The names of the fields can be obtained by calling C<overview_fmt>. 992 993=item xpath ( MESSAGE-ID ) 994 995Returns the path name to the file on the server which contains the specified 996message. 997 998=item xpat ( HEADER, PATTERN, MESSAGE-SPEC) 999 1000The result is the same as C<xhdr> except the is will be restricted to 1001headers where the text of the header matches C<PATTERN> 1002 1003=item xrover 1004 1005The XROVER command returns reference information for the article(s) 1006specified. 1007 1008Returns a reference to a HASH where the keys are the message numbers and the 1009values are the References: lines from the articles 1010 1011=item listgroup ( [ GROUP ] ) 1012 1013Returns a reference to a list of all the active messages in C<GROUP>, or 1014the current group if C<GROUP> is not specified. 1015 1016=item reader 1017 1018Tell the server that you are a reader and not another server. 1019 1020This is required by some servers. For example if you are connecting to 1021an INN server and you have transfer permission your connection will 1022be connected to the transfer daemon, not the NNTP daemon. Issuing 1023this command will cause the transfer daemon to hand over control 1024to the NNTP daemon. 1025 1026Some servers do not understand this command, but issuing it and ignoring 1027the response is harmless. 1028 1029=back 1030 1031=head1 UNSUPPORTED 1032 1033The following NNTP command are unsupported by the package, and there are 1034no 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 1047C<MESSAGE-SPEC> is either a single message-id, a single message number, or 1048a reference to a list of two message numbers. 1049 1050If C<MESSAGE-SPEC> is a reference to a list of two message numbers and the 1051second number in a range is less than or equal to the first then the range 1052represents all messages in the group after the first message number. 1053 1054B<NOTE> For compatibility reasons only with earlier versions of Net::NNTP 1055a message spec can be passed as a list of two numbers, this is deprecated 1056and a reference to the list should now be passed 1057 1058=item PATTERN 1059 1060The C<NNTP> protocol uses the C<WILDMAT> format for patterns. 1061The WILDMAT format was first developed by Rich Salz based on 1062the format used in the UNIX "find" command to articulate 1063file names. It was developed to provide a uniform mechanism 1064for matching patterns in the same manner that the UNIX shell 1065matches filenames. 1066 1067Patterns are implicitly anchored at the 1068beginning and end of each string when testing for a match. 1069 1070There are five pattern matching operations other than a strict 1071one-to-one match between the pattern and the source to be 1072checked for a match. 1073 1074The first is an asterisk C<*> to match any sequence of zero or more 1075characters. 1076 1077The second is a question mark C<?> to match any single character. The 1078third specifies a specific set of characters. 1079 1080The set is specified as a list of characters, or as a range of characters 1081where the beginning and end of the range are separated by a minus (or dash) 1082character, or as any combination of lists and ranges. The dash can 1083also be included in the set as a character it if is the beginning 1084or end of the set. This set is enclosed in square brackets. The 1085close square bracket C<]> may be used in a set if it is the first 1086character in the set. 1087 1088The fourth operation is the same as the 1089logical not of the third operation and is specified the same 1090way as the third with the addition of a caret character C<^> at 1091the beginning of the test string just inside the open square 1092bracket. 1093 1094The final operation uses the backslash character to 1095invalidate the special meaning of an open square bracket C<[>, 1096the asterisk, backslash or the question mark. Two backslashes in 1097sequence will result in the evaluation of the backslash as a 1098character with no special meaning. 1099 1100=over 4 1101 1102=item Examples 1103 1104=item C<[^]-]> 1105 1106matches any single character other than a close square 1107bracket or a minus sign/dash. 1108 1109=item C<*bdc> 1110 1111matches any string that ends with the string "bdc" 1112including the string "bdc" (without quotes). 1113 1114=item C<[0-9a-zA-Z]> 1115 1116matches any single printable alphanumeric ASCII character. 1117 1118=item C<a??d> 1119 1120matches any four character string which begins 1121with a and ends with d. 1122 1123=back 1124 1125=back 1126 1127=head1 SEE ALSO 1128 1129L<Net::Cmd> 1130 1131=head1 AUTHOR 1132 1133Graham Barr <gbarr@pobox.com> 1134 1135=head1 COPYRIGHT 1136 1137Copyright (c) 1995-1997 Graham Barr. All rights reserved. 1138This program is free software; you can redistribute it and/or modify 1139it under the same terms as Perl itself. 1140 1141=for html <hr> 1142 1143I<$Id: //depot/libnet/Net/NNTP.pm#18 $> 1144 1145=cut 1146