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