Update libnet to CPAN version 3.01
authorChris 'BinGOs' Williams <chris@bingosnet.co.uk>
Fri, 10 Oct 2014 12:37:54 +0000 (13:37 +0100)
committerChris 'BinGOs' Williams <chris@bingosnet.co.uk>
Fri, 10 Oct 2014 12:37:54 +0000 (13:37 +0100)
  [DELTA]

libnet 3.01  -- Thu Oct 09 2014

  * Require IO::Socket::SSL >= 1.999 to protect against a bad version (0.30) of
    IO::Socket::IP and hopefully fix another bunch of CPAN Testers failures.

libnet 3.00  -- Thu Oct 09 2014

  * Skip Perl Critic, Pod and Pod Coverage tests unless AUTHOR_TESTING.
    [Resolves CPAN RT#99399]
  * Synchronize all $VERSIONs to the distribution's version number, bumping that
    to 3.00 so that no $VERSIONs end up going backwards.

libnet 1.30  -- Wed Oct 08 2014

  * Sigh. Fix PAUSE indexing problem again. Net::SMTP::SSL is already used by
    Net-SMTP-SSL.

libnet 1.29  -- Wed Oct 08 2014

  * Fix PAUSE indexing problem. Net::POP3::_SSLified and Net::SMTP::_SSLified
    are already used by Net-SSLGlue.

libnet 1.28  -- Wed Oct 08 2014

  * Improve code()/message() initialization and error handling in Net::Cmd
    [Tom Metro; resolves CPAN RT#14875]
  * Don't use the ALLO command on FTP servers that don't support it.  [Resolves
    CPAN RT#95717]
  * Stop Makefile.PL from requiring interactive configuration when running via
    cpan, cpanp or cpanm: just accept all defaults in these cases, as when
    running non-interactively.  [Resolves CPAN RT#48966]
  * Add optional POD coverage testing.
  * Add optional POD testing.
  * Add optional Perl::Critic testing.
  * Make code Perl::Critic clean.
  * Move Net/*.pm into lib/Net/ sub-directory within distribution. This is the
    usual layout style these days.
  * Change Net::SMTP::auth() so that it now falls back to another supported AUTH
    method if a given AUTH method fails.  [Ivan Baktsheev; closes PR#3]
  * Change Net::SMTP::auth() so that it uses the SMTP AUTH mechanism(s)
    specified in the Authen::SASL object if one is provided instead of a
    username.   If a plain text username is specified then use the first
    reported SMTP AUTH method supported, as usual.  [Ewen McNeill; resolves CPAN
    RT#58002]
  * Add support for IPv6 and SSL to Net::FTP, Net::NNTP, Net::POP3 and
    Net::SMTP.  These features are only available if the user has

      a recent IO::Socket::SSL for SSL support
      a recent IO::Socket::IP or an older IO::Socket::INET6 for IPv6 support

    If no SSL module is available it will work as before, but attempts to use
    the SSL functionality will result in an error message.  If no IPv6 modules
    are available it will just use IPv4 as before.  With IPv6 modules installed
    one can of course still access IPv4 hosts.
    [Steffen Ullrich; resolves CPAN RT#93823]

41 files changed:
MANIFEST
Porting/Maintainers.pl
cpan/libnet/Config.eg [deleted file]
cpan/libnet/Hostname.pm.eg [deleted file]
cpan/libnet/Makefile.PL
cpan/libnet/Net/FTP/E.pm [deleted file]
cpan/libnet/Net/FTP/L.pm [deleted file]
cpan/libnet/lib/Net/Cmd.pm [moved from cpan/libnet/Net/Cmd.pm with 76% similarity]
cpan/libnet/lib/Net/Config.pm [moved from cpan/libnet/Net/Config.pm with 93% similarity]
cpan/libnet/lib/Net/Domain.pm [moved from cpan/libnet/Net/Domain.pm with 85% similarity]
cpan/libnet/lib/Net/FTP.pm [moved from cpan/libnet/Net/FTP.pm with 80% similarity]
cpan/libnet/lib/Net/FTP/A.pm [moved from cpan/libnet/Net/FTP/A.pm with 93% similarity]
cpan/libnet/lib/Net/FTP/E.pm [new file with mode: 0644]
cpan/libnet/lib/Net/FTP/I.pm [moved from cpan/libnet/Net/FTP/I.pm with 87% similarity]
cpan/libnet/lib/Net/FTP/L.pm [new file with mode: 0644]
cpan/libnet/lib/Net/FTP/dataconn.pm [moved from cpan/libnet/Net/FTP/dataconn.pm with 58% similarity]
cpan/libnet/lib/Net/NNTP.pm [moved from cpan/libnet/Net/NNTP.pm with 86% similarity]
cpan/libnet/lib/Net/Netrc.pm [moved from cpan/libnet/Net/Netrc.pm with 88% similarity]
cpan/libnet/lib/Net/POP3.pm [moved from cpan/libnet/Net/POP3.pm with 83% similarity]
cpan/libnet/lib/Net/SMTP.pm [moved from cpan/libnet/Net/SMTP.pm with 83% similarity]
cpan/libnet/lib/Net/Time.pm [moved from cpan/libnet/Net/Time.pm with 78% similarity]
cpan/libnet/lib/Net/libnetFAQ.pod [moved from cpan/libnet/Net/libnetFAQ.pod with 93% similarity]
cpan/libnet/t/config.t
cpan/libnet/t/datasend.t
cpan/libnet/t/external/ftp-ssl.t [new file with mode: 0644]
cpan/libnet/t/external/pop3-ssl.t [new file with mode: 0644]
cpan/libnet/t/external/smtp-ssl.t [new file with mode: 0644]
cpan/libnet/t/ftp.t
cpan/libnet/t/hostname.t
cpan/libnet/t/libnet_t.pl
cpan/libnet/t/netrc.t
cpan/libnet/t/nntp.t
cpan/libnet/t/nntp_ipv6.t [new file with mode: 0644]
cpan/libnet/t/nntp_ssl.t [new file with mode: 0644]
cpan/libnet/t/pop3_ipv6.t [new file with mode: 0644]
cpan/libnet/t/pop3_ssl.t [new file with mode: 0644]
cpan/libnet/t/require.t
cpan/libnet/t/smtp.t
cpan/libnet/t/smtp_ipv6.t [new file with mode: 0644]
cpan/libnet/t/smtp_ssl.t [new file with mode: 0644]
cpan/libnet/t/time.t

index ef6cf27..25705c1 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -1419,32 +1419,39 @@ cpan/JSON-PP/t/115_tie_ixhash.t
 cpan/JSON-PP/t/116_incr_parse_fixed.t
 cpan/JSON-PP/t/_unicode_handling.pm
 cpan/JSON-PP/t/zero-mojibake.t
-cpan/libnet/Config.eg          libnet
-cpan/libnet/Hostname.pm.eg     libnet
+cpan/libnet/lib/Net/Cmd.pm
+cpan/libnet/lib/Net/Config.pm
+cpan/libnet/lib/Net/Domain.pm
+cpan/libnet/lib/Net/FTP/A.pm
+cpan/libnet/lib/Net/FTP/dataconn.pm
+cpan/libnet/lib/Net/FTP/E.pm
+cpan/libnet/lib/Net/FTP/I.pm
+cpan/libnet/lib/Net/FTP/L.pm
+cpan/libnet/lib/Net/FTP.pm
+cpan/libnet/lib/Net/libnetFAQ.pod
+cpan/libnet/lib/Net/Netrc.pm
+cpan/libnet/lib/Net/NNTP.pm
+cpan/libnet/lib/Net/POP3.pm
+cpan/libnet/lib/Net/SMTP.pm
+cpan/libnet/lib/Net/Time.pm
 cpan/libnet/Makefile.PL
-cpan/libnet/Net/Cmd.pm         libnet
-cpan/libnet/Net/Config.pm      libnet
-cpan/libnet/Net/Domain.pm      libnet
-cpan/libnet/Net/FTP/A.pm       libnet
-cpan/libnet/Net/FTP/dataconn.pm        libnet
-cpan/libnet/Net/FTP/E.pm       libnet
-cpan/libnet/Net/FTP/I.pm       libnet
-cpan/libnet/Net/FTP/L.pm       libnet
-cpan/libnet/Net/FTP.pm         libnet
-cpan/libnet/Net/libnetFAQ.pod  libnet
-cpan/libnet/Net/Netrc.pm       libnet
-cpan/libnet/Net/NNTP.pm                libnet
-cpan/libnet/Net/POP3.pm                libnet
-cpan/libnet/Net/SMTP.pm                libnet
-cpan/libnet/Net/Time.pm                libnet
 cpan/libnet/t/config.t         libnet
 cpan/libnet/t/datasend.t       libnet
+cpan/libnet/t/external/ftp-ssl.t
+cpan/libnet/t/external/pop3-ssl.t
+cpan/libnet/t/external/smtp-ssl.t
 cpan/libnet/t/ftp.t            libnet
 cpan/libnet/t/hostname.t       libnet
 cpan/libnet/t/libnet_t.pl      libnet
 cpan/libnet/t/netrc.t          libnet
+cpan/libnet/t/nntp_ipv6.t
+cpan/libnet/t/nntp_ssl.t
 cpan/libnet/t/nntp.t           libnet
+cpan/libnet/t/pop3_ipv6.t
+cpan/libnet/t/pop3_ssl.t
 cpan/libnet/t/require.t                libnet
+cpan/libnet/t/smtp_ipv6.t
+cpan/libnet/t/smtp_ssl.t
 cpan/libnet/t/smtp.t           libnet
 cpan/libnet/t/time.t           libnet
 cpan/Locale-Codes/lib/Locale/Codes/API.pod     Locale::Codes documentation
index 8114d9e..2d0cb24 100755 (executable)
@@ -690,7 +690,7 @@ use File::Glob qw(:case);
     },
 
     'libnet' => {
-        'DISTRIBUTION' => 'SHAY/libnet-1.27.tar.gz',
+        'DISTRIBUTION' => 'SHAY/libnet-3.01.tar.gz',
         'FILES'        => q[cpan/libnet],
         'EXCLUDED'     => [
             qw( Configure
diff --git a/cpan/libnet/Config.eg b/cpan/libnet/Config.eg
deleted file mode 100644 (file)
index 8202315..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-package Net::Config;
-
-require Exporter;
-use vars qw(@ISA @EXPORT %NetConfig);
-use strict;
-
-@EXPORT = qw(%NetConfig);
-@ISA = qw(Exporter);
-
-# WARNING  WARNING  WARNING  WARNING  WARNING  WARNING  WARNING
-# WARNING  WARNING  WARNING  WARNING  WARNING  WARNING  WARNING
-#
-# Below this line is auto-generated, *ANY* changes will be lost
-
-%NetConfig = (
-        # the followinf parameters are all lists of hosts for the
-        # respective protocols.
-        nntp_hosts => [],
-        snpp_hosts => [],
-        pop3_hosts => [],
-        smtp_hosts => [],
-        ph_hosts => [],
-        daytime_hosts => [],
-        time_hosts => [],
-
-        # your internet domain
-        inet_domain => undef,
-
-        # If you have an ftp proxy firewall (not an http firewall)
-        # then set this to the name of the firewall
-        ftp_firewall => undef,
-
-        # set if all connections done via the firewall should use
-        # passive data connections
-        ftp_ext_passive => 0,
-
-        # set if all connections not done via the firewall should use
-        # passive data connections
-        ftp_int_passive => 0,
-
-        # If set the make test will attempt to connect to the hosts above
-        test_hosts => 0,
-
-        # Used during Configure (which you are not using) to do
-        # DNS lookups to ensure hosts exist
-        test_exist => 0,
-
-);
-1;
diff --git a/cpan/libnet/Hostname.pm.eg b/cpan/libnet/Hostname.pm.eg
deleted file mode 100644 (file)
index 4736c1a..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-#
-
-package Sys::Hostname;
-
-use Net::Domain qw(hostname);
-use Carp;
-
-require Exporter;
-@ISA = qw(Exporter);
-@EXPORT = qw(hostname);
-
-carp "deprecated package 'Sys::Hostname', use Net::Domain" if $^W;
-
-1;
index 7e21e3c..30bbd73 100644 (file)
@@ -23,6 +23,10 @@ use warnings;
 use ExtUtils::MakeMaker 6.64;
 use ExtUtils::MakeMaker qw(WriteMakefile);
 
+## no critic (Subroutines::ProhibitSubroutinePrototypes)
+
+sub running_under_cpan();
+
 #===============================================================================
 # INITIALIZATION
 #===============================================================================
@@ -42,13 +46,25 @@ MAIN: {
     my %prereq_pms = ();
     $prereq_pms{'Convert::EBCDIC'} = '0.06' if $^O eq 'os390';
 
+    my $xt = 'n';
+    if (not running_under_cpan()) {
+        $xt = prompt("Should I do external tests?\n" .
+                     "These tests will fail if there is no internet" .
+                     " connection or if a firewall\n" .
+                     "blocks or modifies some traffic.\n" .
+                     "[y/N]", 'n');
+    }
+
+    my $tests = 't/*.t';
+    $tests .= ' t/external/*.t' if $xt =~ m/^y/io;
+
     WriteMakefile(
         NAME     => 'Net',
         DISTNAME => 'libnet',
         ABSTRACT => 'Collection of network protocol modules',
         AUTHOR   => 'Graham Barr <gbarr@pobox.com>, Steve Hay <shay@cpan.org>',
         LICENSE  => 'perl_5',
-        VERSION  => '1.27',
+        VERSION  => '3.01',
 
         META_MERGE => {
             'meta-spec' => {
@@ -84,6 +100,62 @@ MAIN: {
                             }
                         }
                     }
+                },
+
+                SSL => {
+                    description => 'SSL support',
+                    prereqs => {
+                        runtime => {
+                            requires => {
+                                'IO::Socket::SSL' => '1.999'
+                            }
+                        }
+                    }
+                },
+
+                IPv6 => {
+                    description => 'IPv6 support',
+                    prereqs => {
+                        runtime => {
+                            requires => {
+                                'IO::Socket::IP' => '0.20'
+                            # or IO::Socket::INET6 2.62
+                            }
+                        }
+                    }
+                },
+
+                critictest => {
+                    description => 'Perl::Critic testing',
+                    prereqs => {
+                        test => {
+                            requires => {
+                                'Test::Perl::Critic' => '0'
+                            }
+                        }
+                    }
+                },
+
+                podtest => {
+                    description => 'POD testing',
+                    prereqs => {
+                        test => {
+                            requires => {
+                                'Test::Pod' => '1.00'
+                            }
+                        }
+                    }
+                },
+
+                podcoveragetest => {
+                    description => 'POD coverage testing',
+                    prereqs => {
+                        test => {
+                            requires => {
+                                'Test::Pod::Coverage' => '0.08'
+                            }
+                        }
+                    }
                 }
             }
         },
@@ -101,7 +173,8 @@ MAIN: {
         },
 
         TEST_REQUIRES => {
-            'Cwd' => '0'
+            'Config' => '0',
+            'Cwd'    => '0'
         },
 
         PREREQ_PM => {
@@ -118,6 +191,7 @@ MAIN: {
             'Socket'         => '1.3',
             'Symbol'         => '0',
             'Time::Local'    => '0',
+            'constant'       => '0',
             'strict'         => '0',
             'vars'           => '0'
         },
@@ -128,6 +202,10 @@ MAIN: {
             FILES => $CfgFile
         },
 
+        test => {
+            TESTS => $tests
+        },
+
         dist => {
             PREOP   => 'find $(DISTVNAME) -type d -print|xargs chmod 0755 && ' .
                        'find $(DISTVNAME) -type f -print|xargs chmod 0644',
@@ -142,10 +220,30 @@ MAIN: {
 
 sub MY::post_initialize {
     my $self = shift;
+
     return '' if $self->{PERL_CORE};
-    system(($^O eq 'VMS' ? 'mcr ': ()), $^X, 'Configure') unless -f $CfgFile;
+
+    if (not -f $CfgFile) {
+        my @args = qw(Configure);
+        push @args, '-d' if $ENV{PERL5_CPAN_IS_RUNNING}     ||
+                            $ENV{PERL5_CPANPLUS_IS_RUNNING} ||
+                            $ENV{PERL5_CPANM_IS_RUNNING};
+        system(($^O eq 'VMS' ? 'mcr ': ()), $^X, @args)
+    }
+
     $self->{PM}{$CfgFile} = $self->catfile('$(INST_LIBDIR)',$CfgPath);
+
     return '';
 }
 
 #===============================================================================
+# SUBROUTINES
+#===============================================================================
+
+sub running_under_cpan() {
+    return $ENV{PERL5_CPAN_IS_RUNNING}     || # cpan
+           $ENV{PERL5_CPANPLUS_IS_RUNNING} || # cpanp
+           $ENV{PERL5_CPANM_IS_RUNNING};      # cpanm
+}
+
+#===============================================================================
diff --git a/cpan/libnet/Net/FTP/E.pm b/cpan/libnet/Net/FTP/E.pm
deleted file mode 100644 (file)
index d480cd7..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-package Net::FTP::E;
-
-require Net::FTP::I;
-
-@ISA = qw(Net::FTP::I);
-$VERSION = "0.01";
-
-1;
diff --git a/cpan/libnet/Net/FTP/L.pm b/cpan/libnet/Net/FTP/L.pm
deleted file mode 100644 (file)
index f7423cb..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-package Net::FTP::L;
-
-require Net::FTP::I;
-
-@ISA = qw(Net::FTP::I);
-$VERSION = "0.01";
-
-1;
similarity index 76%
rename from cpan/libnet/Net/Cmd.pm
rename to cpan/libnet/lib/Net/Cmd.pm
index d1a1fed..c71a789 100644 (file)
@@ -1,17 +1,21 @@
 # Net::Cmd.pm
 #
-# Copyright (c) 1995-2006 Graham Barr <gbarr@pobox.com>. All rights reserved.
+# Versions up to 2.29_1 Copyright (c) 1995-2006 Graham Barr <gbarr@pobox.com>.
+# All rights reserved.
+# Changes in Version 2.29_2 onwards Copyright (C) 2013-2014 Steve Hay.  All
+# rights reserved.
 # This program is free software; you can redistribute it and/or
 # modify it under the same terms as Perl itself.
 
 package Net::Cmd;
 
-require 5.001;
-require Exporter;
+use 5.008001;
 
 use strict;
-use vars qw(@ISA @EXPORT $VERSION);
+use warnings;
+
 use Carp;
+use Exporter;
 use Symbol 'gensym';
 
 BEGIN {
@@ -37,23 +41,23 @@ BEGIN {
   }
 }
 
-$VERSION = "2.30";
-@ISA     = qw(Exporter);
-@EXPORT  = qw(CMD_INFO CMD_OK CMD_MORE CMD_REJECT CMD_ERROR CMD_PENDING);
+our $VERSION = "3.01";
+our @ISA     = qw(Exporter);
+our @EXPORT  = qw(CMD_INFO CMD_OK CMD_MORE CMD_REJECT CMD_ERROR CMD_PENDING);
 
+use constant CMD_INFO    => 1;
+use constant CMD_OK      => 2;
+use constant CMD_MORE    => 3;
+use constant CMD_REJECT  => 4;
+use constant CMD_ERROR   => 5;
+use constant CMD_PENDING => 0;
 
-sub CMD_INFO    {1}
-sub CMD_OK      {2}
-sub CMD_MORE    {3}
-sub CMD_REJECT  {4}
-sub CMD_ERROR   {5}
-sub CMD_PENDING {0}
+use constant DEF_REPLY_CODE => 421;
 
 my %debug = ();
 
 my $tr = $^O eq 'os390' ? Convert::EBCDIC->new() : undef;
 
-
 sub toebcdic {
   my $cmd = shift;
 
@@ -78,7 +82,7 @@ sub toascii {
 
 
 sub _print_isa {
-  no strict qw(refs);
+  no strict 'refs'; ## no critic (TestingAndDebugging::ProhibitNoStrict)
 
   my $pkg = shift;
   my $cmd = $pkg;
@@ -169,7 +173,7 @@ sub code {
 
   my $cmd = shift;
 
-  ${*$cmd}{'net_cmd_code'} = "000"
+  ${*$cmd}{'net_cmd_code'} = $cmd->DEF_REPLY_CODE
     unless exists ${*$cmd}{'net_cmd_code'};
 
   ${*$cmd}{'net_cmd_code'};
@@ -191,7 +195,7 @@ sub set_status {
   my $cmd = shift;
   my ($code, $resp) = @_;
 
-  $resp = [$resp]
+  $resp = defined $resp ? [$resp] : []
     unless ref($resp);
 
   (${*$cmd}{'net_cmd_code'}, ${*$cmd}{'net_cmd_resp'}) = ($code, $resp);
@@ -200,14 +204,38 @@ sub set_status {
 }
 
 
-sub command {
+
+sub _set_status_timeout {
   my $cmd = shift;
+  my $pkg = ref($cmd) || $cmd;
+
+  $cmd->set_status($cmd->DEF_REPLY_CODE, "[$pkg] Timeout");
+  carp(ref($cmd) . ": " . (caller(1))[3] . "(): timeout") if $cmd->debug;
+}
+
+sub _set_status_closed {
+  my $cmd = shift;
+  my $pkg = ref($cmd) || $cmd;
+
+  $cmd->set_status($cmd->DEF_REPLY_CODE, "[$pkg] Connection closed");
+  carp(ref($cmd) . ": " . (caller(1))[3]
+    . "(): unexpected EOF on command channel: $!") if $cmd->debug;
+}
 
-  unless (defined fileno($cmd)) {
-    $cmd->set_status("599", "Connection closed");
-    return $cmd;
+sub _is_closed {
+  my $cmd = shift;
+  if (!defined fileno($cmd)) {
+     $cmd->_set_status_closed;
+     return 1;
   }
+  return 0;
+}
 
+sub command {
+  my $cmd = shift;
+
+  return $cmd
+    if $cmd->_is_closed;
 
   $cmd->dataend()
     if (exists ${*$cmd}{'net_cmd_last_ch'});
@@ -229,14 +257,14 @@ sub command {
     my $len = length $str;
     my $swlen;
 
-    $cmd->close
-      unless (defined($swlen = syswrite($cmd, $str, $len)) && $swlen == $len);
-
     $cmd->debug_print(1, $str)
       if ($cmd->debug);
 
-    ${*$cmd}{'net_cmd_resp'} = [];       # the response
-    ${*$cmd}{'net_cmd_code'} = "000";    # Made this one up :-)
+    unless (defined($swlen = syswrite($cmd,$str,$len)) && $swlen == $len) {
+      $cmd->close;
+      $cmd->_set_status_closed;
+      return $cmd;
+    }
   }
 
   $cmd;
@@ -254,8 +282,8 @@ sub ok {
 sub unsupported {
   my $cmd = shift;
 
-  ${*$cmd}{'net_cmd_resp'} = ['Unsupported command'];
-  ${*$cmd}{'net_cmd_code'} = 580;
+  $cmd->set_status(580, 'Unsupported command');
+
   0;
 }
 
@@ -269,11 +297,11 @@ sub getline {
     if scalar(@{${*$cmd}{'net_cmd_lines'}});
 
   my $partial = defined(${*$cmd}{'net_cmd_partial'}) ? ${*$cmd}{'net_cmd_partial'} : "";
-  my $fd      = fileno($cmd);
 
-  return undef
-    unless defined $fd;
+  return
+    if $cmd->_is_closed;
 
+  my $fd = fileno($cmd);
   my $rin = "";
   vec($rin, $fd, 1) = 1;
 
@@ -286,10 +314,9 @@ sub getline {
     my $select_ret = select($rout = $rin, undef, undef, $timeout);
     if ($select_ret > 0) {
       unless (sysread($cmd, $buf = "", 1024)) {
-        carp(ref($cmd) . ": Unexpected EOF on command channel")
-          if $cmd->debug;
         $cmd->close;
-        return undef;
+        $cmd->_set_status_closed;
+        return;
       }
 
       substr($buf, 0, 0) = $partial;    ## prepend from last sysread
@@ -302,9 +329,8 @@ sub getline {
 
     }
     else {
-      my $msg = $select_ret ? "Error or Interrupted: $!" : "Timeout";
-      carp("$cmd: $msg") if ($cmd->debug);
-      return undef;
+      $cmd->_set_status_timeout;
+      return;
     }
   }
 
@@ -339,7 +365,7 @@ sub response {
   my $cmd = shift;
   my ($code, $more) = (undef) x 2;
 
-  ${*$cmd}{'net_cmd_resp'} ||= [];
+  $cmd->set_status($cmd->DEF_REPLY_CODE, undef); # initialize the response
 
   while (1) {
     my $str = $cmd->getline();
@@ -352,9 +378,10 @@ sub response {
 
     ($code, $more) = $cmd->parse_response($str);
     unless (defined $code) {
+      carp("$cmd: response(): parse error in '$str'") if ($cmd->debug);
       $cmd->ungetline($str);
       $@ = $str;   # $@ used as tunneling hack
-      last;
+      return CMD_ERROR;
     }
 
     ${*$cmd}{'net_cmd_code'} = $code;
@@ -364,7 +391,7 @@ sub response {
     last unless ($more);
   }
 
-  return undef unless defined $code;
+  return unless defined $code;
   substr($code, 0, 1);
 }
 
@@ -375,7 +402,7 @@ sub read_until_dot {
   my $arr = [];
 
   while (1) {
-    my $str = $cmd->getline() or return undef;
+    my $str = $cmd->getline() or return;
 
     $cmd->debug_print(0, $str)
       if ($cmd->debug & 4);
@@ -405,7 +432,8 @@ sub datasend {
   # $line is a string (in internal UTF-8)
   utf8::encode($line) if is_utf8($line);
 
-  return 0 unless defined(fileno($cmd));
+  return 0
+    if $cmd->_is_closed;
 
   my $last_ch = ${*$cmd}{'net_cmd_last_ch'};
 
@@ -455,16 +483,17 @@ sub datasend {
     if ((defined $s and $s > 0) or -f $cmd)    # -f for testing on win32
     {
       my $w = syswrite($cmd, $line, $len, $offset);
-      unless (defined($w)) {
-        carp("$cmd: $!") if $cmd->debug;
-        return undef;
+      unless (defined($w) && $w == $len) {
+        $cmd->close;
+        $cmd->_set_status_closed;
+        return;
       }
       $len -= $w;
       $offset += $w;
     }
     else {
-      carp("$cmd: Timeout") if ($cmd->debug);
-      return undef;
+      $cmd->_set_status_timeout;
+      return;
     }
   }
 
@@ -477,7 +506,8 @@ sub rawdatasend {
   my $arr  = @_ == 1 && ref($_[0]) ? $_[0] : \@_;
   my $line = join("", @$arr);
 
-  return 0 unless defined(fileno($cmd));
+  return 0
+    if $cmd->_is_closed;
 
   return 1
     unless length($line);
@@ -498,16 +528,17 @@ sub rawdatasend {
     my $wout;
     if (select(undef, $wout = $win, undef, $timeout) > 0) {
       my $w = syswrite($cmd, $line, $len, $offset);
-      unless (defined($w)) {
-        carp("$cmd: $!") if $cmd->debug;
-        return undef;
+      unless (defined($w) && $w == $len) {
+        $cmd->close;
+        $cmd->_set_status_closed;
+        return;
       }
       $len -= $w;
       $offset += $w;
     }
     else {
-      carp("$cmd: Timeout") if ($cmd->debug);
-      return undef;
+      $cmd->_set_status_timeout;
+      return;
     }
   }
 
@@ -518,7 +549,8 @@ sub rawdatasend {
 sub dataend {
   my $cmd = shift;
 
-  return 0 unless defined(fileno($cmd));
+  return 0
+    if $cmd->_is_closed;
 
   my $ch = ${*$cmd}{'net_cmd_last_ch'};
   my $tosend;
@@ -537,7 +569,14 @@ sub dataend {
   $cmd->debug_print(1, ".\n")
     if ($cmd->debug);
 
-  syswrite($cmd, $tosend, length $tosend);
+  my $len = length $tosend;
+  my $w = syswrite($cmd, $tosend, $len);
+  unless (defined($w) && $w == $len)
+  {
+    $cmd->close;
+    $cmd->_set_status_closed;
+    return 0;
+  }
 
   delete ${*$cmd}{'net_cmd_last_ch'};
 
@@ -659,12 +698,12 @@ debug level for a given class.
 
 Returns the text message returned from the last command. In a scalar
 context it returns a single string, in a list context it will return
-each line as a separate element
+each line as a separate element. (See L<PSEUDO RESPONSES> below.)
 
 =item code ()
 
 Returns the 3-digit code from the last command. If a command is pending
-then the value 0 is returned
+then the value 0 is returned. (See L<PSEUDO RESPONSES> below.)
 
 =item ok ()
 
@@ -705,21 +744,21 @@ Print debugging information. C<DIR> denotes the direction I<true> being
 data being sent to the server. Calls C<debug_text> before printing to
 STDERR.
 
-=item debug_text ( TEXT )
+=item debug_text ( DIR, TEXT )
 
 This method is called to print debugging information. TEXT is
-the text being sent. The method should return the text to be printed
+the text being sent. The method should return the text to be printed.
 
 This is primarily meant for the use of modules such as FTP where passwords
 are sent, but we do not want to display them in the debugging information.
 
 =item command ( CMD [, ARGS, ... ])
 
-Send a command to the command server. All arguments a first joined with
+Send a command to the command server. All arguments are first joined with
 a space character and CRLF is appended, this string is then sent to the
 command server.
 
-Returns undef upon failure
+Returns undef upon failure.
 
 =item unsupported ()
 
@@ -729,14 +768,14 @@ Returns zero.
 =item response ()
 
 Obtain a response from the server. Upon success the most significant digit
-of the status code is returned. Upon failure, timeout etc., I<undef> is
+of the status code is returned. Upon failure, timeout etc., I<CMD_ERROR> is
 returned.
 
 =item parse_response ( TEXT )
 
 This method is called by C<response> as a method with one argument. It should
 return an array of 2 values, the 3-digit status code and a flag which is true
-when this is part of a multi-line response and this line is not the list.
+when this is part of a multi-line response and this line is not the last.
 
 =item getline ()
 
@@ -774,6 +813,44 @@ See the Net::POP3 and Net::SMTP modules for examples of this.
 
 =back
 
+=head1 PSEUDO RESPONSES
+
+Normally the values returned by C<message()> and C<code()> are
+obtained from the remote server, but in a few circumstances, as
+detailed below, C<Net::Cmd> will return values that it sets. You
+can alter this behavior by overriding DEF_REPLY_CODE() to specify
+a different default reply code, or overriding one of the specific
+error handling methods below.
+
+=over 4
+
+=item Initial value
+
+Before any command has executed or if an unexpected error occurs
+C<code()> will return "421" (temporary connection failure) and
+C<message()> will return undef.
+
+=item Connection closed
+
+If the underlying C<IO::Handle> is closed, or if there are
+any read or write failures, the file handle will be forced closed,
+and C<code()> will return "421" (temporary connection failure)
+and C<message()> will return "[$pkg] Connection closed"
+(where $pkg is the name of the class that subclassed C<Net::Cmd>).
+The _set_status_closed() method can be overridden to set a different
+message (by calling set_status()) or otherwise trap this error.
+
+=item Timeout
+
+If there is a read or write timeout C<code()> will return "421"
+(temporary connection failure) and C<message()> will return
+"[$pkg] Timeout" (where $pkg is the name of the class
+that subclassed C<Net::Cmd>). The _set_status_timeout() method
+can be overridden to set a different message (by calling set_status())
+or otherwise trap this error.
+
+=back
+
 =head1 EXPORTS
 
 C<Net::Cmd> exports six subroutines, five of these, C<CMD_INFO>, C<CMD_OK>,
@@ -782,11 +859,17 @@ of C<response> and C<status>. The sixth is C<CMD_PENDING>.
 
 =head1 AUTHOR
 
-Graham Barr <gbarr@pobox.com>
+Graham Barr E<lt>F<gbarr@pobox.com>E<gt>
+
+Steve Hay E<lt>F<shay@cpan.org>E<gt> is now maintaining libnet as of version
+1.22_02
 
 =head1 COPYRIGHT
 
-Copyright (c) 1995-2006 Graham Barr. All rights reserved.
+Versions up to 2.29_1 Copyright (c) 1995-2006 Graham Barr. All rights reserved.
+Changes in Version 2.29_2 onwards Copyright (C) 2013-2014 Steve Hay.  All rights
+reserved.
+
 This program is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself.
 
similarity index 93%
rename from cpan/libnet/Net/Config.pm
rename to cpan/libnet/lib/Net/Config.pm
index f9d04e1..cdb5956 100644 (file)
@@ -1,23 +1,31 @@
 # Net::Config.pm
 #
-# Copyright (c) 2000 Graham Barr <gbarr@pobox.com>. All rights reserved.
+# Versions up to 1.11 Copyright (c) 2000 Graham Barr <gbarr@pobox.com>.
+# All rights reserved.
+# Changes in Version 1.11_01 onwards Copyright (C) 2013-2014 Steve Hay.  All
+# rights reserved.
 # This program is free software; you can redistribute it and/or
 # modify it under the same terms as Perl itself.
 
 package Net::Config;
 
-require Exporter;
-use vars qw(@ISA @EXPORT %NetConfig $VERSION $CONFIGURE $LIBNET_CFG);
-use Socket qw(inet_aton inet_ntoa);
+use 5.008001;
+
 use strict;
+use warnings;
+
+use Exporter;
+use Socket qw(inet_aton inet_ntoa);
 
-@EXPORT  = qw(%NetConfig);
-@ISA     = qw(Net::LocalCfg Exporter);
-$VERSION = "1.14";
+our @EXPORT  = qw(%NetConfig);
+our @ISA     = qw(Net::LocalCfg Exporter);
+our $VERSION = "3.01";
+
+our($CONFIGURE, $LIBNET_CFG);
 
 eval { local $SIG{__DIE__}; require Net::LocalCfg };
 
-%NetConfig = (
+our %NetConfig = (
   nntp_hosts      => [],
   snpp_hosts      => [],
   pop3_hosts      => [],
@@ -36,6 +44,8 @@ eval { local $SIG{__DIE__}; require Net::LocalCfg };
 #
 # Try to get as much configuration info as possible from InternetConfig
 #
+{
+## no critic (BuiltinFunctions::ProhibitStringyEval)
 $^O eq 'MacOS' and eval <<TRY_INTERNET_CONFIG;
 use Mac::InternetConfig;
 
@@ -56,6 +66,7 @@ my %nc = (
 \@NetConfig{keys %nc} = values %nc;
 }
 TRY_INTERNET_CONFIG
+}
 
 my $file = __FILE__;
 my $ref;
@@ -112,7 +123,6 @@ sub requires_firewall {
   return 0;
 }
 
-use vars qw(*is_external);
 *is_external = \&requires_firewall;
 
 1;
@@ -153,7 +163,7 @@ C<Net::LocalCfg> so you can override these methods if you want.
 
 =over 4
 
-=item requires_firewall HOST
+=item requires_firewall ( HOST )
 
 Attempts to determine if a given host is outside your firewall. Possible
 return values are.
similarity index 85%
rename from cpan/libnet/Net/Domain.pm
rename to cpan/libnet/lib/Net/Domain.pm
index 5b964c3..df76e88 100644 (file)
@@ -1,22 +1,26 @@
 # Net::Domain.pm
 #
-# Copyright (c) 1995-1998 Graham Barr <gbarr@pobox.com>. All rights reserved.
+# Versions up to 2.21 Copyright (c) 1995-1998 Graham Barr <gbarr@pobox.com>.
+# All rights reserved.
+# Changes in Version 2.22 onwards Copyright (C) 2013-2014 Steve Hay.  All rights
+# reserved.
 # This program is free software; you can redistribute it and/or
 # modify it under the same terms as Perl itself.
 
 package Net::Domain;
 
-require Exporter;
+use 5.008001;
 
-use Carp;
 use strict;
-use vars qw($VERSION @ISA @EXPORT_OK);
-use Net::Config;
+use warnings;
 
-@ISA       = qw(Exporter);
-@EXPORT_OK = qw(hostname hostdomain hostfqdn domainname);
+use Carp;
+use Exporter;
+use Net::Config;
 
-$VERSION = "2.23";
+our @ISA       = qw(Exporter);
+our @EXPORT_OK = qw(hostname hostdomain hostfqdn domainname);
+our $VERSION = "3.01";
 
 my ($host, $domain, $fqdn) = (undef, undef, undef);
 
@@ -63,12 +67,12 @@ sub _hostname {
       my $tmp = "\0" x 256;    ## preload scalar
       eval {
         package main;
-        require "syscall.ph";
+        require "syscall.ph"; ## no critic (Modules::RequireBarewordIncludes)
         defined(&main::SYS_gethostname);
         }
         || eval {
         package main;
-        require "sys/syscall.ph";
+        require "sys/syscall.ph"; ## no critic (Modules::RequireBarewordIncludes)
         defined(&main::SYS_gethostname);
         }
         and $host =
@@ -124,15 +128,14 @@ sub _hostdomain {
   # calls to gethostbyname, and therefore DNS lookups. This helps
   # those on dialup systems.
 
-  local *RES;
   local ($_);
 
-  if (open(RES, "/etc/resolv.conf")) {
-    while (<RES>) {
+  if (open(my $res, '<', "/etc/resolv.conf")) {
+    while (<$res>) {
       $domain = $1
         if (/\A\s*(?:domain|search)\s+(\S+)/);
     }
-    close(RES);
+    close($res);
 
     return $domain
       if (defined $domain);
@@ -151,11 +154,11 @@ sub _hostdomain {
       my $tmp = "\0" x 256;    ## preload scalar
       eval {
         package main;
-        require "syscall.ph";
+        require "syscall.ph"; ## no critic (Modules::RequireBarewordIncludes)
         }
         || eval {
         package main;
-        require "sys/syscall.ph";
+        require "sys/syscall.ph"; ## no critic (Modules::RequireBarewordIncludes)
         }
         and $dom =
         (syscall(&main::SYS_getdomainname, $tmp, 256) == 0)
@@ -190,8 +193,7 @@ sub _hostdomain {
     next unless @info;
 
     # look at real name & aliases
-    my $site;
-    foreach $site ($info[0], split(/ /, $info[1])) {
+    foreach my $site ($info[0], split(/ /, $info[1])) {
       if (rindex($site, ".") > 0) {
 
         # Extract domain from FQDN
@@ -342,12 +344,18 @@ Returns the remainder of the FQDN after the I<hostname> has been removed.
 
 =head1 AUTHOR
 
-Graham Barr <gbarr@pobox.com>.
-Adapted from Sys::Hostname by David Sundstrom <sunds@asictest.sc.ti.com>
+Graham Barr E<lt>F<gbarr@pobox.com>E<gt>.
+Adapted from Sys::Hostname by David Sundstrom E<lt>F<sunds@asictest.sc.ti.com>E<gt>
+
+Steve Hay E<lt>F<shay@cpan.org>E<gt> is now maintaining libnet as of version
+1.22_02
 
 =head1 COPYRIGHT
 
-Copyright (c) 1995-1998 Graham Barr. All rights reserved.
+Versions up to 2.21 Copyright (c) 1995-1998 Graham Barr. All rights reserved.
+Changes in Version 2.22 onwards Copyright (C) 2013-2014 Steve Hay.  All rights
+reserved.
+
 This program is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself.
 
similarity index 80%
rename from cpan/libnet/Net/FTP.pm
rename to cpan/libnet/lib/Net/FTP.pm
index 8107ef7..39e1e74 100644 (file)
@@ -1,6 +1,9 @@
 # Net::FTP.pm
 #
-# Copyright (c) 1995-2004 Graham Barr <gbarr@pobox.com>. All rights reserved.
+# Versions up to 2.77_2 Copyright (c) 1995-2004 Graham Barr <gbarr@pobox.com>.
+# All rights reserved.
+# Changes in Version 2.77_3 onwards Copyright (C) 2013-2014 Steve Hay.  All
+# rights reserved.
 # This program is free software; you can redistribute it and/or
 # modify it under the same terms as Perl itself.
 #
 
 package Net::FTP;
 
-require 5.001;
+use 5.008001;
 
 use strict;
-use vars qw(@ISA $VERSION);
-use Carp;
+use warnings;
 
-use Socket 1.3;
+use Carp;
+use Fcntl qw(O_WRONLY O_RDONLY O_APPEND O_CREAT O_TRUNC);
 use IO::Socket;
-use Time::Local;
 use Net::Cmd;
 use Net::Config;
-use Fcntl qw(O_WRONLY O_RDONLY O_APPEND O_CREAT O_TRUNC);
-
-$VERSION = '2.79';
-@ISA     = qw(Exporter Net::Cmd IO::Socket::INET);
-
-# Someday I will "use constant", when I am not bothered to much about
-# compatibility with older releases of perl
-
-use vars qw($TELNET_IAC $TELNET_IP $TELNET_DM);
-($TELNET_IAC, $TELNET_IP, $TELNET_DM) = (255, 244, 242);
+use Socket 1.3;
+use Time::Local;
 
+our $VERSION = '3.01';
 
+our $IOCLASS;
 BEGIN {
-
-  # make a constant so code is fast'ish
-  my $is_os390 = $^O eq 'os390';
-  *trEBCDIC = sub () {$is_os390}
+  # Code for detecting if we can use SSL
+  my $ssl_class = eval {
+    require IO::Socket::SSL;
+    # first version with default CA on most platforms
+    IO::Socket::SSL->VERSION(1.999);
+  } && 'IO::Socket::SSL';
+
+  my $nossl_warn = !$ssl_class &&
+    'To use SSL please install IO::Socket::SSL with version>=1.999';
+
+  # Code for detecting if we can use IPv6
+  my $inet6_class = eval {
+    require IO::Socket::IP;
+    IO::Socket::IP->VERSION(0.20);
+  } && 'IO::Socket::IP' || eval {
+    require IO::Socket::INET6;
+    IO::Socket::INET6->VERSION(2.62);
+  } && 'IO::Socket::INET6';
+
+  sub can_ssl   { $ssl_class };
+  sub can_inet6 { $inet6_class };
+
+  $IOCLASS = $ssl_class || $inet6_class || 'IO::Socket::INET';
 }
 
+our @ISA = ('Exporter','Net::Cmd',$IOCLASS);
+
+use constant TELNET_IAC => 255;
+use constant TELNET_IP  => 244;
+use constant TELNET_DM  => 242;
+
+use constant EBCDIC => $^O eq 'os390';
 
 sub new {
   my $pkg = shift;
@@ -71,16 +93,32 @@ sub new {
     }
   }
 
+  my %tlsargs;
+  if (can_ssl()) {
+    # for name verification strip port from domain:port, ipv4:port, [ipv6]:port
+    (my $hostname = $host) =~s{(?<!:):\d+$}{};
+    %tlsargs = (
+      SSL_verifycn_scheme => 'ftp',
+      SSL_verifycn_name => $hostname,
+      # reuse SSL session of control connection in data connections
+      SSL_session_cache => Net::FTP::_SSL_SingleSessionCache->new,
+    );
+    # user defined SSL arg
+    $tlsargs{$_} = $arg{$_} for(grep { m{^SSL_} } keys %arg);
+
+  } elsif ($arg{SSL}) {
+    croak("IO::Socket::SSL >= 1.999 needed for SSL support");
+  }
+
   my $ftp = $pkg->SUPER::new(
     PeerAddr  => $peer,
-    PeerPort  => $arg{Port} || 'ftp(21)',
+    PeerPort  => $arg{Port} || ($arg{SSL} ? 'ftps(990)' : 'ftp(21)'),
     LocalAddr => $arg{'LocalAddr'},
     Proto     => 'tcp',
-    Timeout   => defined $arg{Timeout}
-    ? $arg{Timeout}
-    : 120
-    )
-    or return undef;
+    Timeout   => defined $arg{Timeout} ? $arg{Timeout} : 120,
+    %tlsargs,
+    $arg{SSL} ? ():( SSL_startHandshake => 0 ),
+  ) or return;
 
   ${*$ftp}{'net_ftp_host'}    = $host;                             # Remote hostname
   ${*$ftp}{'net_ftp_type'}    = 'A';                               # ASCII/binary/etc mode
@@ -99,6 +137,12 @@ sub new {
     : defined $fire            ? $NetConfig{ftp_ext_passive}
     : $NetConfig{ftp_int_passive};    # Whew! :-)
 
+  ${*$ftp}{net_ftp_tlsargs} = \%tlsargs if %tlsargs;
+  if ($arg{SSL}) {
+    ${*$ftp}{net_ftp_tlsprot} = 'P';
+    ${*$ftp}{net_ftp_tlsdirect} = 1;
+  }
+
   $ftp->hash(exists $arg{Hash} ? $arg{Hash} : 0, 1024);
 
   $ftp->autoflush(1);
@@ -223,10 +267,9 @@ sub size {
   }
   elsif ($ftp->supported("STAT")) {
     my @msg;
-    return undef
+    return
       unless $ftp->_STAT($file) && (@msg = $ftp->message) == 3;
-    my $line;
-    foreach $line (@msg) {
+    foreach my $line (@msg) {
       return (split(/\s+/, $line))[4]
         if $line =~ /^[-rwxSsTt]{10}/;
     }
@@ -242,6 +285,35 @@ sub size {
 }
 
 
+sub starttls {
+  my $ftp = shift;
+  can_ssl() or croak("IO::Socket::SSL >= 1.999 needed for SSL support");
+  $ftp->is_SSL and croak("called starttls within SSL session");
+  $ftp->_AUTH('TLS') == CMD_OK or return;
+
+  $ftp->connect_SSL or return;
+  $ftp->prot('P');
+  return 1;
+}
+
+sub prot {
+  my ($ftp,$prot) = @_;
+  $prot eq 'C' or $prot eq 'P' or croak("prot must by C or P");
+  $ftp->_PBSZ(0) or return;
+  $ftp->_PROT($prot) or return;
+  ${*$ftp}{net_ftp_tlsprot} = $prot;
+  return 1;
+}
+
+sub stoptls {
+  my $ftp = shift;
+  $ftp->is_SSL or croak("called stoptls outside SSL session");
+  ${*$ftp}{net_ftp_tlsdirect} and croak("cannot stoptls direct SSL session");
+  $ftp->_CCC() or return;
+  $ftp->stop_SSL();
+  return 1;
+}
+
 sub login {
   my ($ftp, $user, $pass, $acct) = @_;
   my ($ok, $ruser, $fwtype);
@@ -400,7 +472,7 @@ sub type {
   return $oldval
     unless (defined $type);
 
-  return undef
+  return
     unless ($ftp->_TYPE($type, @_));
 
   ${*$ftp}{'net_ftp_type'} = join(" ", $type, @_);
@@ -417,8 +489,8 @@ sub alloc {
   return $oldval
     unless (defined $size);
 
-  return undef
-    unless ($ftp->_ALLO($size, @_));
+  return
+    unless ($ftp->supported("ALLO") and $ftp->_ALLO($size, @_));
 
   ${*$ftp}{'net_ftp_allo'} = join(" ", $size, @_);
 
@@ -429,9 +501,9 @@ sub alloc {
 sub abort {
   my $ftp = shift;
 
-  send($ftp, pack("CCC", $TELNET_IAC, $TELNET_IP, $TELNET_IAC), MSG_OOB);
+  send($ftp, pack("CCC", TELNET_IAC, TELNET_IP, TELNET_IAC), MSG_OOB);
 
-  $ftp->command(pack("C", $TELNET_DM) . "ABOR");
+  $ftp->command(pack("C", TELNET_DM) . "ABOR");
 
   ${*$ftp}{'net_ftp_dataconn'}->close()
     if defined ${*$ftp}{'net_ftp_dataconn'};
@@ -463,7 +535,7 @@ sub get {
   delete ${*$ftp}{'net_ftp_pasv'};
 
   $data = $ftp->retr($remote)
-    or return undef;
+    or return;
 
   if ($localfd) {
     $loc = $local;
@@ -474,7 +546,7 @@ sub get {
     unless (sysopen($loc, $local, O_CREAT | O_WRONLY | ($rest ? O_APPEND: O_TRUNC))) {
       carp "Cannot open Local file $local: $!\n";
       $data->abort;
-      return undef;
+      return;
     }
   }
 
@@ -482,7 +554,7 @@ sub get {
     carp "Cannot binmode Local file $local: $!\n";
     $data->abort;
     close($loc) unless $localfd;
-    return undef;
+    return;
   }
 
   $buf = '';
@@ -497,7 +569,7 @@ sub get {
   while (1) {
     last unless $len = $data->read($buf, $blksize);
 
-    if (trEBCDIC && $ftp->type ne 'I') {
+    if (EBCDIC && $ftp->type ne 'I') {
       $buf = $ftp->toebcdic($buf);
       $len = length($buf);
     }
@@ -512,7 +584,7 @@ sub get {
       $data->abort;
       close($loc)
         unless $localfd;
-      return undef;
+      return;
     }
   }
 
@@ -521,14 +593,14 @@ sub get {
   unless ($localfd) {
     unless (close($loc)) {
       carp "Cannot close file $local (perhaps disk space) $!\n";
-      return undef;
+      return;
     }
   }
 
   unless ($data->close())    # implied $ftp->response
   {
     carp "Unable to close datastream";
-    return undef;
+    return;
   }
 
   return $local;
@@ -587,15 +659,14 @@ sub rmdir {
   # Get a list of all the files in the directory
   my @filelist = grep { !/^\.{1,2}$/ } $ftp->ls($dir);
 
-  return undef
+  return
     unless @filelist;    # failed, it is probably not a directory
 
   return $ftp->delete($dir)
     if @filelist == 1 and $dir eq $filelist[0];
 
   # Go thru and delete each file or the directory
-  my $file;
-  foreach $file (map { m,/, ? $_ : "$dir/$_" } @filelist) {
+  foreach my $file (map { m,/, ? $_ : "$dir/$_" } @filelist) {
     next                 # successfully deleted the file
       if $ftp->delete($file);
 
@@ -622,7 +693,7 @@ sub restart {
 
   ${*$ftp}{'net_ftp_rest'} = $where;
 
-  return undef;
+  return;
 }
 
 
@@ -632,7 +703,7 @@ sub mkdir {
   my ($ftp, $dir, $recurse) = @_;
 
   $ftp->_MKD($dir) || $recurse
-    or return undef;
+    or return;
 
   my $path = $dir;
 
@@ -728,20 +799,20 @@ sub _store_cmd {
 
     unless (sysopen($loc, $local, O_RDONLY)) {
       carp "Cannot open Local file $local: $!\n";
-      return undef;
+      return;
     }
   }
 
   if ($ftp->type eq 'I' && !binmode($loc)) {
     carp "Cannot binmode Local file $local: $!\n";
-    return undef;
+    return;
   }
 
   delete ${*$ftp}{'net_ftp_port'};
   delete ${*$ftp}{'net_ftp_pasv'};
 
   $sock = $ftp->_data_cmd($cmd, grep { defined } $remote)
-    or return undef;
+    or return;
 
   $remote = ($ftp->message =~ /\w+\s*:\s*(.*)/)[0]
     if 'STOU' eq uc $cmd;
@@ -756,7 +827,7 @@ sub _store_cmd {
   while (1) {
     last unless $len = read($loc, $buf = "", $blksize);
 
-    if (trEBCDIC && $ftp->type ne 'I') {
+    if (EBCDIC && $ftp->type ne 'I') {
       $buf = $ftp->toascii($buf);
       $len = length($buf);
     }
@@ -773,7 +844,7 @@ sub _store_cmd {
       close($loc)
         unless $localfd;
       print $hashh "\n" if $hashh;
-      return undef;
+      return;
     }
   }
 
@@ -783,7 +854,7 @@ sub _store_cmd {
     unless $localfd;
 
   $sock->close()
-    or return undef;
+    or return;
 
   if ('STOU' eq uc $cmd and $ftp->message =~ m/unique\s+file\s*name\s*:\s*(.*)\)|"(.*)"/) {
     require File::Basename;
@@ -795,38 +866,41 @@ sub _store_cmd {
 
 
 sub port {
-  @_ == 1 || @_ == 2 or croak 'usage: $ftp->port([PORT])';
-
-  my ($ftp, $port) = @_;
-  my $ok;
-
-  delete ${*$ftp}{'net_ftp_intern_port'};
-
-  unless (defined $port) {
+    @_ == 1 || @_ == 2 or croak 'usage: $self->port([PORT])';
+    return _eprt('PORT',@_);
+}
 
-    # create a Listen socket at same address as the command socket
+sub eprt {
+  @_ == 1 || @_ == 2 or croak 'usage: $self->eprt([PORT])';
+  return _eprt('EPRT',@_);
+}
 
-    ${*$ftp}{'net_ftp_listen'} ||= IO::Socket::INET->new(
-      Listen    => 5,
-      Proto     => 'tcp',
+sub _eprt {
+  my ($cmd,$ftp,$port) = @_;
+  delete ${*$ftp}{net_ftp_intern_port};
+  unless ($port) {
+    my $listen = ${*$ftp}{net_ftp_listen} ||= $IOCLASS->new(
+      Listen    => 1,
       Timeout   => $ftp->timeout,
       LocalAddr => $ftp->sockhost,
+      can_ssl() ? (
+       %{ ${*$ftp}{net_ftp_tlsargs} },
+       SSL_startHandshake => 0,
+      ):(),
     );
-
-    my $listen = ${*$ftp}{'net_ftp_listen'};
-
-    my ($myport, @myaddr) = ($listen->sockport, split(/\./, $listen->sockhost));
-
-    $port = join(',', @myaddr, $myport >> 8, $myport & 0xff);
-
-    ${*$ftp}{'net_ftp_intern_port'} = 1;
+    ${*$ftp}{net_ftp_intern_port} = 1;
+    my $fam = ($listen->sockdomain == AF_INET) ? 1:2;
+    if ( $cmd eq 'EPRT' || $fam == 2 ) {
+      $port = "|$fam|".$listen->sockhost."|".$listen->sockport."|";
+      $cmd = 'EPRT';
+    } else {
+      my $p = $listen->sockport;
+      $port = join(',',split(m{\.},$listen->sockhost),$p >> 8,$p & 0xff);
+    }
   }
-
-  $ok = $ftp->_PORT($port);
-
-  ${*$ftp}{'net_ftp_port'} = $port;
-
-  $ok;
+  my $ok = $cmd eq 'EPRT' ? $ftp->_EPRT($port) : $ftp->_PORT($port);
+  ${*$ftp}{net_ftp_port} = $port if $ok;
+  return $ok;
 }
 
 
@@ -835,14 +909,27 @@ sub dir { shift->_list_cmd("LIST", @_); }
 
 
 sub pasv {
-  @_ == 1 or croak 'usage: $ftp->pasv()';
-
   my $ftp = shift;
+  @_ and croak 'usage: $ftp->port()';
+  return $ftp->epsv if $ftp->sockdomain != AF_INET;
+  delete ${*$ftp}{net_ftp_intern_port};
+
+  if ( $ftp->_PASV &&
+    $ftp->message =~ m{(\d+,\d+,\d+,\d+),(\d+),(\d+)} ) {
+    my $port = 256 * $2 + $3;
+    ( my $ip = $1 ) =~s{,}{.}g;
+    return ${*$ftp}{net_ftp_pasv} = [ $ip,$port ];
+  }
+  return;
+}
 
-  delete ${*$ftp}{'net_ftp_intern_port'};
+sub epsv {
+  my $ftp = shift;
+  @_ and croak 'usage: $ftp->epsv()';
+  delete ${*$ftp}{net_ftp_intern_port};
 
-  $ftp->_PASV && $ftp->message =~ /(\d+(,\d+)+)/
-    ? ${*$ftp}{'net_ftp_pasv'} = $1
+  $ftp->_EPSV && $ftp->message =~ m{\(([\x33-\x7e])\1\1(\d+)\1\)}
+    ? ${*$ftp}{net_ftp_pasv} = [ $ftp->peerhost, $2 ]
     : undef;
 }
 
@@ -869,7 +956,7 @@ sub supported {
     unless $ftp->_HELP($cmd);
 
   my $text = $ftp->message;
-  if ($text =~ /following\s+commands/i) {
+  if ($text =~ /following.+commands/i) {
     $text =~ s/^.*\n//;
     while ($text =~ /(\*?)(\w+)(\*?)/sg) {
       $hash->{"\U$2"} = !length("$1$3");
@@ -926,41 +1013,51 @@ sub _extract_path {
 
 
 sub _dataconn {
-  my $ftp  = shift;
-  my $data = undef;
-  my $pkg  = "Net::FTP::" . $ftp->type;
-
-  eval "require " . $pkg;
-
+  my $ftp = shift;
+  my $pkg = "Net::FTP::" . $ftp->type;
+  eval "require " . $pkg ## no critic (BuiltinFunctions::ProhibitStringyEval)
+    or croak("cannot load $pkg required for type ".$ftp->type);
   $pkg =~ s/ /_/g;
-
-  delete ${*$ftp}{'net_ftp_dataconn'};
-
-  if (defined ${*$ftp}{'net_ftp_pasv'}) {
-    my @port = map { 0 + $_ } split(/,/, ${*$ftp}{'net_ftp_pasv'});
-
-    $data = $pkg->new(
-      PeerAddr  => join(".", @port[0 .. 3]),
-      PeerPort  => $port[4] * 256 + $port[5],
-      LocalAddr => ${*$ftp}{'net_ftp_localaddr'},
-      Proto     => 'tcp',
-      Timeout   => $ftp->timeout
-    );
-  }
-  elsif (defined ${*$ftp}{'net_ftp_listen'}) {
-    $data = ${*$ftp}{'net_ftp_listen'}->accept($pkg);
-    close(delete ${*$ftp}{'net_ftp_listen'});
+  delete ${*$ftp}{net_ftp_dataconn};
+
+  my $conn;
+  my $pasv = ${*$ftp}{net_ftp_pasv};
+  if ($pasv) {
+    $conn = $pkg->new(
+      PeerAddr  => $pasv->[0],
+      PeerPort  => $pasv->[1],
+      LocalAddr => ${*$ftp}{net_ftp_localaddr},
+      Timeout   => $ftp->timeout,
+      can_ssl() ? (
+       SSL_startHandshake => 0,
+       $ftp->is_SSL ? (
+         SSL_reuse_ctx => $ftp,
+         SSL_verifycn_name => ${*$ftp}{net_ftp_tlsargs}{SSL_verifycn_name},
+       ) :( %{${*$ftp}{net_ftp_tlsargs}} ),
+      ):(),
+    ) or return;
+  } elsif (my $listen =  delete ${*$ftp}{net_ftp_listen}) {
+    $conn = $listen->accept($pkg) or return;
+    $conn->timeout($ftp->timeout);
+    close($listen);
+  } else {
+    croak("no listener in active mode");
   }
 
-  if ($data) {
-    ${*$data} = "";
-    $data->timeout($ftp->timeout);
-    ${*$ftp}{'net_ftp_dataconn'} = $data;
-    ${*$data}{'net_ftp_cmd'}     = $ftp;
-    ${*$data}{'net_ftp_blksize'} = ${*$ftp}{'net_ftp_blksize'};
+  if (( ${*$ftp}{net_ftp_tlsprot} || '') eq 'P') {
+    if ($conn->connect_SSL) {
+      # SSL handshake ok
+    } else {
+      carp("failed to ssl upgrade dataconn: $IO::Socket::SSL::SSL_ERROR");
+      return;
+    }
   }
 
-  $data;
+  ${*$ftp}{net_ftp_dataconn} = $conn;
+  ${*$conn} = "";
+  ${*$conn}{net_ftp_cmd} = $ftp;
+  ${*$conn}{net_ftp_blksize} = ${*$ftp}{net_ftp_blksize};
+  return $conn;
 }
 
 
@@ -991,7 +1088,7 @@ sub _list_cmd {
 
   $data->close();
 
-  if (trEBCDIC) {
+  if (EBCDIC) {
     for (@$list) { $_ = $ftp->toebcdic($_) }
   }
 
@@ -1008,7 +1105,7 @@ sub _data_cmd {
   my $where = delete ${*$ftp}{'net_ftp_rest'} || 0;
   my $arg;
 
-  for $arg (@_) {
+  for my $arg (@_) {
     croak("Bad argument '$arg'\n")
       if $arg =~ /[\r\n]/s;
   }
@@ -1017,27 +1114,28 @@ sub _data_cmd {
     && !defined ${*$ftp}{'net_ftp_pasv'}
     && !defined ${*$ftp}{'net_ftp_port'})
   {
-    my $data = undef;
-
-    return undef unless defined $ftp->pasv;
-    $data = $ftp->_dataconn() or return undef;
+    return unless defined $ftp->pasv;
 
     if ($where and !$ftp->_REST($where)) {
       my ($status, $message) = ($ftp->status, $ftp->message);
       $ftp->abort;
       $ftp->set_status($status, $message);
-      return undef;
+      return;
     }
 
+    # first send command, then open data connection
+    # otherwise the peer might not do a full accept (with SSL
+    # handshake if PROT P)
     $ftp->command($cmd, @_);
+    my $data = $ftp->_dataconn();
     if (CMD_INFO == $ftp->response()) {
       $data->reading
-        if $cmd =~ /RETR|LIST|NLST/;
+       if $data && $cmd =~ /RETR|LIST|NLST/;
       return $data;
     }
-    $data->_close;
+    $data->_close if $data;
 
-    return undef;
+    return;
   }
 
   $ok = $ftp->port
@@ -1047,12 +1145,14 @@ sub _data_cmd {
   $ok = $ftp->_REST($where)
     if $ok && $where;
 
-  return undef
+  return
     unless $ok;
 
-  if ($cmd =~ /(STOR|APPE|STOU)/ and exists ${*$ftp}{net_ftp_allo}) {
+  if ($cmd =~ /(STOR|APPE|STOU)/ and exists ${*$ftp}{net_ftp_allo} and
+      $ftp->supported("ALLO"))
+  {
     $ftp->_ALLO(delete ${*$ftp}{net_ftp_allo})
-      or return undef;
+      or return;
   }
 
   $ftp->command($cmd, @_);
@@ -1077,7 +1177,7 @@ sub _data_cmd {
 
   close(delete ${*$ftp}{'net_ftp_listen'});
 
-  return undef;
+  return;
 }
 
 ##
@@ -1139,19 +1239,19 @@ sub pasv_xfer {
     unless (defined $dfile);
 
   my $port = $sftp->pasv
-    or return undef;
+    or return;
 
   $dftp->port($port)
-    or return undef;
+    or return;
 
-  return undef
+  return
     unless ($unique ? $dftp->stou($dfile) : $dftp->stor($dfile));
 
   unless ($sftp->retr($sfile) && $sftp->response == CMD_INFO) {
     $sftp->retr($sfile);
     $dftp->abort;
     $dftp->response();
-    return undef;
+    return;
   }
 
   $dftp->pasv_wait($sftp);
@@ -1170,10 +1270,10 @@ sub pasv_wait {
   my $dres = $ftp->response();
   my $sres = $non_pasv->response();
 
-  return undef
+  return
     unless $dres == CMD_OK && $sres == CMD_OK;
 
-  return undef
+  return
     unless $ftp->ok() && $non_pasv->ok();
 
   return $1
@@ -1214,7 +1314,7 @@ sub cmd { shift->command(@_)->response() }
 
 ########################################
 #
-# RFC959 commands
+# RFC959 + RFC2428 + RFC4217 commands
 #
 
 
@@ -1238,6 +1338,11 @@ sub _SIZE { shift->command("SIZE", @_)->response() == CMD_OK }
 sub _HELP { shift->command("HELP", @_)->response() == CMD_OK }
 sub _STAT { shift->command("STAT", @_)->response() == CMD_OK }
 sub _FEAT { shift->command("FEAT", @_)->response() == CMD_OK }
+sub _PBSZ { shift->command("PBSZ", @_)->response() == CMD_OK }
+sub _PROT { shift->command("PROT", @_)->response() == CMD_OK }
+sub _CCC  { shift->command("CCC", @_)->response() == CMD_OK }
+sub _EPRT { shift->command("EPRT", @_)->response() == CMD_OK }
+sub _EPSV { shift->command("EPSV", @_)->response() == CMD_OK }
 sub _APPE { shift->command("APPE", @_)->response() == CMD_INFO }
 sub _LIST { shift->command("LIST", @_)->response() == CMD_INFO }
 sub _NLST { shift->command("NLST", @_)->response() == CMD_INFO }
@@ -1269,6 +1374,26 @@ sub _SYST { shift->unsupported(@_) }
 sub _STRU { shift->unsupported(@_) }
 sub _REIN { shift->unsupported(@_) }
 
+{
+  # Session Cache with single entry
+  # used to make sure that we reuse same session for control and data channels
+  package Net::FTP::_SSL_SingleSessionCache;
+  sub new { my $x; return bless \$x,shift }
+  sub add_session {
+    my ($cache,$key,$session) = @_;
+    Net::SSLeay::SESSION_free($$cache) if $$cache;
+    $$cache = $session;
+  }
+  sub get_session {
+    my $cache = shift;
+    return $$cache
+  }
+  sub DESTROY {
+    my $cache = shift;
+    Net::SSLeay::SESSION_free($$cache) if $$cache;
+  }
+}
+
 1;
 
 __END__
@@ -1330,7 +1455,9 @@ EBCDIC format.  Binary (also known as image) format sends the data as
 a contiguous bit stream.  Byte format transfers the data as bytes, the
 values of which remain the same regardless of differences in byte size
 between the two machines (in theory - in practice you should only use
-this if you really know what you're doing).
+this if you really know what you're doing).  This class does not support
+the EBCDIC or byte formats, and will default to binary instead if they
+are attempted.
 
 =head1 CONSTRUCTOR
 
@@ -1352,7 +1479,6 @@ the C<PeerAddr> option in L<IO::Socket::INET>, or a reference to
 an array with hosts to try in turn. The L</host> method will return the value
 which was used to connect to the host.
 
-
 B<Firewall> - The name of a machine which acts as an FTP firewall. This can be
 overridden by an environment variable C<FTP_FIREWALL>. If specified, and the
 given host cannot be directly connected to, then the
@@ -1371,6 +1497,13 @@ transfers. (defaults to 10240)
 B<Port> - The port number to connect to on the remote machine for the
 FTP connection
 
+B<SSL> - If the connection should be done from start with SSL, contrary to later
+upgrade with C<starttls>.
+
+B<SSL_*> - SSL arguments which will be applied when upgrading the control or
+data connection to SSL. You can use SSL arguments as documented in
+L<IO::Socket::SSL>, but it will usually use the right arguments already.
+
 B<Timeout> - Set a timeout value in seconds (defaults to 120)
 
 B<Debug> - debug level (see the debug method in L<Net::Cmd>)
@@ -1427,6 +1560,33 @@ will be used for password.
 If the connection is via a firewall then the C<authorize> method will
 be called with no arguments.
 
+=item starttls ()
+
+Upgrade existing plain connection to SSL.
+The SSL arguments have to be given in C<new> already because they are needed for
+data connections too.
+
+=item stoptls ()
+
+Downgrade existing SSL connection back to plain.
+This is needed to work with some FTP helpers at firewalls, which need to see the
+PORT and PASV commands and responses to dynamically open the necessary ports.
+In this case C<starttls> is usually only done to protect the authorization.
+
+=item prot ( LEVEL )
+
+Set what type of data channel protection the client and server will be using.
+Only C<LEVEL>s "C" (clear) and "P" (private) are supported.
+
+=item host ()
+
+Returns the value used by the constructor, and passed to IO::Socket::INET,
+to connect to the host.
+
+=item account( ACCT )
+
+Set a string identifying the user's account.
+
 =item authorize ( [AUTH [, RESP]])
 
 This is a protocol used by some firewall ftp proxies. It is used
@@ -1439,17 +1599,21 @@ Send a SITE command to the remote server and wait for a response.
 
 Returns most significant digit of the response code.
 
-=item ascii
+=item ascii ()
 
 Transfer file in ASCII. CRLF translation will be done if required
 
-=item binary
+=item binary ()
 
 Transfer file in binary mode. No transformation will be done.
 
 B<Hint>: If both server and client machines use the same line ending for
 text files, then it will be faster to transfer all files in binary mode.
 
+=item type ( [ TYPE ] )
+
+Set or get if files will be transferred in ASCII or binary mode.
+
 =item rename ( OLDNAME, NEWNAME )
 
 Rename a file on the remote FTP server from C<OLDNAME> to C<NEWNAME>. This
@@ -1664,16 +1828,19 @@ C<put_unique> and those that do not require data connections.
 =over 4
 
 =item port ( [ PORT ] )
+=item eprt ( [ PORT ] )
 
-Send a C<PORT> command to the server. If C<PORT> is specified then it is sent
-to the server. If not, then a listen socket is created and the correct information
-sent to the server.
+Send a C<PORT> (IPv4) or C<EPRT> (IPv6) command to the server. If C<PORT> is
+specified then it is sent to the server. If not, then a listen socket is created
+and the correct information sent to the server.
 
 =item pasv ()
+=item epsv ()
 
-Tell the server to go into passive mode. Returns the text that represents the
-port on which the server is listening, this text is in a suitable form to
-sent to another ftp server using the C<port> method.
+Tell the server to go into passive mode (C<pasv> for IPv4, C<epsv> for IPv6).
+Returns the text that represents the port on which the server is listening, this
+text is in a suitable form to send to another ftp server using the C<port> or
+C<eprt> method.
 
 =back
 
@@ -1723,49 +1890,21 @@ Returns most significant digit of the response code.
 B<WARNING> This call should only be used on commands that do not require
 data connections. Misuse of this method can hang the connection.
 
-=back
-
-=head1 THE dataconn CLASS
-
-Some of the methods defined in C<Net::FTP> return an object which will
-be derived from this class.The dataconn class itself is derived from
-the C<IO::Socket::INET> class, so any normal IO operations can be performed.
-However the following methods are defined in the dataconn class and IO should
-be performed using these.
-
-=over 4
-
-=item read ( BUFFER, SIZE [, TIMEOUT ] )
+=item can_inet6 ()
 
-Read C<SIZE> bytes of data from the server and place it into C<BUFFER>, also
-performing any <CRLF> translation necessary. C<TIMEOUT> is optional, if not
-given, the timeout value from the command connection will be used.
+Returns whether we can use IPv6.
 
-Returns the number of bytes read before any <CRLF> translation.
+=item can_ssl ()
 
-=item write ( BUFFER, SIZE [, TIMEOUT ] )
+Returns whether we can use SSL.
 
-Write C<SIZE> bytes of data from C<BUFFER> to the server, also
-performing any <CRLF> translation necessary. C<TIMEOUT> is optional, if not
-given, the timeout value from the command connection will be used.
-
-Returns the number of bytes written before any <CRLF> translation.
-
-=item bytes_read ()
-
-Returns the number of bytes read so far.
-
-=item abort ()
-
-Abort the current data transfer.
-
-=item close ()
+=back
 
-Close the data connection and get a response from the FTP server. Returns
-I<true> if the connection was closed successfully and the first digit of
-the response from the server was a '2'.
+=head1 THE dataconn CLASS
 
-=back
+Some of the methods defined in C<Net::FTP> return an object which will
+be derived from the C<Net::FTP::dataconn> class. See L<Net::FTP::dataconn> for
+more details.
 
 =head1 UNIMPLEMENTED
 
@@ -1820,15 +1959,21 @@ run of your program which does yield the problem.
 
 =head1 AUTHOR
 
-Graham Barr <gbarr@pobox.com>
+Graham Barr E<lt>F<gbarr@pobox.com>E<gt>
+
+Steve Hay E<lt>F<shay@cpan.org>E<gt> is now maintaining libnet as of version
+1.22_02
 
 =head1 SEE ALSO
 
-L<Net::Netrc>
-L<Net::Cmd>
+L<Net::Netrc>,
+L<Net::Cmd>,
+L<IO::Socket::SSL>
 
-ftp(1), ftpd(8), RFC 959
+ftp(1), ftpd(8), RFC 959, RFC 2428, RFC 4217
 http://www.ietf.org/rfc/rfc959.txt
+http://www.ietf.org/rfc/rfc2428.txt
+http://www.ietf.org/rfc/rfc4217.txt
 
 =head1 USE EXAMPLES
 
@@ -1854,7 +1999,10 @@ Roderick Schertler <roderick@gate.net> - for various inputs
 
 =head1 COPYRIGHT
 
-Copyright (c) 1995-2004 Graham Barr. All rights reserved.
+Versions up to 2.77_2 Copyright (c) 1995-2004 Graham Barr. All rights reserved.
+Changes in Version 2.77_3 onwards Copyright (C) 2013-2014 Steve Hay.  All rights
+reserved.
+
 This program is free software; you can redistribute it and/or modify it
 under the same terms as Perl itself.
 
similarity index 93%
rename from cpan/libnet/Net/FTP/A.pm
rename to cpan/libnet/lib/Net/FTP/A.pm
index c117d69..02574ee 100644 (file)
@@ -3,15 +3,19 @@
 ##
 
 package Net::FTP::A;
+
+use 5.008001;
+
 use strict;
-use vars qw(@ISA $buf $VERSION);
-use Carp;
+use warnings;
 
-require Net::FTP::dataconn;
+use Carp;
+use Net::FTP::dataconn;
 
-@ISA     = qw(Net::FTP::dataconn);
-$VERSION = "1.19";
+our @ISA     = qw(Net::FTP::dataconn);
+our $VERSION = "3.01";
 
+our $buf;
 
 sub read {
   my $data = shift;
@@ -42,7 +46,7 @@ sub read {
           : undef;
       }
       else {
-        return undef
+        return
           unless defined $n;
 
         ${*$data}{'net_ftp_eof'} = 1;
@@ -100,7 +104,7 @@ sub write {
 
     $off += $wrote;
     $wrote = syswrite($data, substr($tmp, $off), $len > $blksize ? $blksize : $len);
-    return undef
+    return
       unless defined($wrote);
     $len -= $wrote;
   }
diff --git a/cpan/libnet/lib/Net/FTP/E.pm b/cpan/libnet/lib/Net/FTP/E.pm
new file mode 100644 (file)
index 0000000..accfa08
--- /dev/null
@@ -0,0 +1,13 @@
+package Net::FTP::E;
+
+use 5.008001;
+
+use strict;
+use warnings;
+
+use Net::FTP::I;
+
+our @ISA = qw(Net::FTP::I);
+our $VERSION = "3.01";
+
+1;
similarity index 87%
rename from cpan/libnet/Net/FTP/I.pm
rename to cpan/libnet/lib/Net/FTP/I.pm
index 449bb99..14be581 100644 (file)
@@ -4,14 +4,18 @@
 
 package Net::FTP::I;
 
-use vars qw(@ISA $buf $VERSION);
-use Carp;
+use 5.008001;
+
+use strict;
+use warnings;
 
-require Net::FTP::dataconn;
+use Carp;
+use Net::FTP::dataconn;
 
-@ISA     = qw(Net::FTP::dataconn);
-$VERSION = "1.12";
+our @ISA     = qw(Net::FTP::dataconn);
+our $VERSION = "3.01";
 
+our $buf;
 
 sub read {
   my $data = shift;
@@ -30,7 +34,7 @@ sub read {
     $blksize = $size if $size > $blksize;
 
     unless ($n = sysread($data, ${*$data}, $blksize, length ${*$data})) {
-      return undef unless defined $n;
+      return unless defined $n;
       ${*$data}{'net_ftp_eof'} = 1;
     }
   }
@@ -69,7 +73,7 @@ sub write {
       or croak "Timeout";
 
     my $n = syswrite($data, $buf, $sent > $blksize ? $blksize : $sent, $off);
-    return undef unless defined($n);
+    return unless defined($n);
     $sent -= $n;
     $off += $n;
   }
diff --git a/cpan/libnet/lib/Net/FTP/L.pm b/cpan/libnet/lib/Net/FTP/L.pm
new file mode 100644 (file)
index 0000000..6c1b70e
--- /dev/null
@@ -0,0 +1,13 @@
+package Net::FTP::L;
+
+use 5.008001;
+
+use strict;
+use warnings;
+
+use Net::FTP::I;
+
+our @ISA = qw(Net::FTP::I);
+our $VERSION = "3.01";
+
+1;
similarity index 58%
rename from cpan/libnet/Net/FTP/dataconn.pm
rename to cpan/libnet/lib/Net/FTP/dataconn.pm
index 3f93668..bcb7df6 100644 (file)
@@ -4,14 +4,19 @@
 
 package Net::FTP::dataconn;
 
+use 5.008001;
+
+use strict;
+use warnings;
+
 use Carp;
-use vars qw(@ISA $timeout $VERSION);
-use Net::Cmd;
 use Errno;
+use Net::Cmd;
 
-$VERSION = '0.12';
-@ISA     = qw(IO::Socket::INET);
+our $VERSION = '3.01';
 
+$Net::FTP::IOCLASS or die "please load Net::FTP before Net::FTP::dataconn";
+our @ISA = $Net::FTP::IOCLASS;
 
 sub reading {
   my $data = shift;
@@ -125,3 +130,53 @@ sub bytes_read {
 }
 
 1;
+
+__END__
+
+=head1 NAME
+
+Net::FTP::dataconn - FTP Client data connection class
+
+=head1 DESCRIPTION
+
+Some of the methods defined in C<Net::FTP> return an object which will
+be derived from this class. The dataconn class itself is derived from
+the C<IO::Socket::INET> class, so any normal IO operations can be performed.
+However the following methods are defined in the dataconn class and IO should
+be performed using these.
+
+=over 4
+
+=item read ( BUFFER, SIZE [, TIMEOUT ] )
+
+Read C<SIZE> bytes of data from the server and place it into C<BUFFER>, also
+performing any <CRLF> translation necessary. C<TIMEOUT> is optional, if not
+given, the timeout value from the command connection will be used.
+
+Returns the number of bytes read before any <CRLF> translation.
+
+=item write ( BUFFER, SIZE [, TIMEOUT ] )
+
+Write C<SIZE> bytes of data from C<BUFFER> to the server, also
+performing any <CRLF> translation necessary. C<TIMEOUT> is optional, if not
+given, the timeout value from the command connection will be used.
+
+Returns the number of bytes written before any <CRLF> translation.
+
+=item bytes_read ()
+
+Returns the number of bytes read so far.
+
+=item abort ()
+
+Abort the current data transfer.
+
+=item close ()
+
+Close the data connection and get a response from the FTP server. Returns
+I<true> if the connection was closed successfully and the first digit of
+the response from the server was a '2'.
+
+=back
+
+=cut
similarity index 86%
rename from cpan/libnet/Net/NNTP.pm
rename to cpan/libnet/lib/Net/NNTP.pm
index 07c3737..4df5b97 100644 (file)
@@ -1,21 +1,50 @@
 # Net::NNTP.pm
 #
-# Copyright (c) 1995-1997 Graham Barr <gbarr@pobox.com>. All rights reserved.
+# Versions up to 2.24_1 Copyright (c) 1995-1997 Graham Barr <gbarr@pobox.com>.
+# All rights reserved.
+# Changes in Version 2.25 onwards Copyright (C) 2013-2014 Steve Hay.  All rights
+# reserved.
 # This program is free software; you can redistribute it and/or
 # modify it under the same terms as Perl itself.
 
 package Net::NNTP;
 
+use 5.008001;
+
 use strict;
-use vars qw(@ISA $VERSION $debug);
+use warnings;
+
+use Carp;
 use IO::Socket;
 use Net::Cmd;
-use Carp;
-use Time::Local;
 use Net::Config;
+use Time::Local;
+
+our $VERSION = "3.01";
+
+# Code for detecting if we can use SSL
+my $ssl_class = eval {
+  require IO::Socket::SSL;
+  # first version with default CA on most platforms
+  IO::Socket::SSL->VERSION(1.999);
+} && 'IO::Socket::SSL';
+
+my $nossl_warn = !$ssl_class &&
+  'To use SSL please install IO::Socket::SSL with version>=1.999';
+
+# Code for detecting if we can use IPv6
+my $inet6_class = eval {
+  require IO::Socket::IP;
+  IO::Socket::IP->VERSION(0.20);
+} && 'IO::Socket::IP' || eval {
+  require IO::Socket::INET6;
+  IO::Socket::INET6->VERSION(2.62);
+} && 'IO::Socket::INET6';
+
+sub can_ssl   { $ssl_class };
+sub can_inet6 { $inet6_class };
 
-$VERSION = "2.26";
-@ISA     = qw(Net::Cmd IO::Socket::INET);
+our @ISA = ('Net::Cmd', $ssl_class || $inet6_class || 'IO::Socket::INET');
 
 
 sub new {
@@ -40,20 +69,34 @@ sub new {
     unless @{$hosts};
 
   my %connect = ( Proto => 'tcp');
-  my $o;
-  foreach $o (qw(LocalAddr Timeout)) {
+
+  if ($ssl_class) {
+    $connect{SSL_verifycn_scheme} = 'nntp';
+    $connect{$_} = $arg{$_} for(grep { m{^SSL_} } keys %arg);
+    if ($arg{SSL}) {
+      # SSL from start
+      $arg{Port} ||= 563;
+    } else {
+      # upgrade later with STARTTLS
+      $connect{SSL_startHandshake} = 0;
+    }
+  } elsif ($arg{SSL}) {
+    die $nossl_warn;
+  }
+
+  foreach my $o (qw(LocalAddr Timeout)) {
     $connect{$o} = $arg{$o} if exists $arg{$o};
   }
   $connect{Timeout} = 120 unless defined $connect{Timeout};
   $connect{PeerPort} = $arg{Port} || 'nntp(119)';
-  my $h;
-  foreach $h (@{$hosts}) {
+  foreach my $h (@{$hosts}) {
     $connect{PeerAddr} = $h;
+    $connect{SSL_verifycn_name} = $arg{SSL_verifycn_name} || $h if $ssl_class;
     $obj = $type->SUPER::new(%connect)
       and last;
   }
 
-  return undef
+  return
     unless defined $obj;
 
   ${*$obj}{'net_nntp_host'} = $connect{PeerAddr};
@@ -63,7 +106,7 @@ sub new {
 
   unless ($obj->response() == CMD_OK) {
     $obj->close;
-    return undef;
+    return;
   }
 
   my $c = $obj->code;
@@ -119,6 +162,15 @@ sub postok {
 }
 
 
+sub starttls {
+  my $self = shift;
+  $ssl_class or die $nossl_warn;
+  $self->is_SSL and croak("NNTP connection is already in SSL mode");
+  $self->_STARTTLS or return;
+  $self->connect_SSL;
+}
+
+
 sub article {
   @_ >= 1 && @_ <= 3 or croak 'usage: $nntp->article( [ MSGID ], [ FH ] )';
   my $nntp = shift;
@@ -403,6 +455,7 @@ sub distribution_patterns {
   my $arr;
   local $_;
 
+  ## no critic (ControlStructures::ProhibitMutatingListFunctions)
   $nntp->_LIST('DISTRIB.PATS')
     && ($arr = $nntp->read_until_dot)
     ? [grep { /^\d/ && (chomp, $_ = [split /:/]) } @$arr]
@@ -511,7 +564,7 @@ sub xpath {
   @_ == 2 or croak 'usage: $nntp->xpath( MESSAGE-ID )';
   my ($nntp, $mid) = @_;
 
-  return undef
+  return
     unless $nntp->_XPATH($mid);
 
   my $m;
@@ -590,12 +643,11 @@ sub _timestr {
 sub _grouplist {
   my $nntp = shift;
   my $arr  = $nntp->read_until_dot
-    or return undef;
+    or return;
 
   my $hash = {};
-  my $ln;
 
-  foreach $ln (@$arr) {
+  foreach my $ln (@$arr) {
     my @a = split(/[\s\n]+/, $ln);
     $hash->{$a[0]} = [@a[1, 2, 3]];
   }
@@ -607,12 +659,11 @@ sub _grouplist {
 sub _fieldlist {
   my $nntp = shift;
   my $arr  = $nntp->read_until_dot
-    or return undef;
+    or return;
 
   my $hash = {};
-  my $ln;
 
-  foreach $ln (@$arr) {
+  foreach my $ln (@$arr) {
     my @a = split(/[\t\n]/, $ln);
     my $m = shift @a;
     $hash->{$m} = [@a];
@@ -636,12 +687,11 @@ sub _articlelist {
 sub _description {
   my $nntp = shift;
   my $arr  = $nntp->read_until_dot
-    or return undef;
+    or return;
 
   my $hash = {};
-  my $ln;
 
-  foreach $ln (@$arr) {
+  foreach my $ln (@$arr) {
     chomp($ln);
 
     $hash->{$1} = $ln
@@ -674,6 +724,7 @@ sub _NEXT      { shift->command('NEXT')->response == CMD_OK }
 sub _POST      { shift->command('POST', @_)->response == CMD_MORE }
 sub _QUIT      { shift->command('QUIT', @_)->response == CMD_OK }
 sub _SLAVE     { shift->command('SLAVE', @_)->response == CMD_OK }
+sub _STARTTLS  { shift->command("STARTTLS")->response() == CMD_MORE }
 sub _STAT      { shift->command('STAT', @_)->response == CMD_OK }
 sub _MODE      { shift->command('MODE', @_)->response == CMD_OK }
 sub _XGTITLE   { shift->command('XGTITLE', @_)->response == CMD_OK }
@@ -712,10 +763,18 @@ Net::NNTP - NNTP Client class
     $nntp = Net::NNTP->new("some.host.name");
     $nntp->quit;
 
+    # start with SSL, e.g. nntps
+    $nntp = Net::NNTP->new("some.host.name", SSL => 1);
+
+    # start with plain and upgrade to SSL
+    $nntp = Net::NNTP->new("some.host.name");
+    $nntp->starttls;
+
+
 =head1 DESCRIPTION
 
 C<Net::NNTP> is a class implementing a simple NNTP client in Perl as described
-in RFC977.
+in RFC977 and RFC4642.
 
 The Net::NNTP class is a subclass of Net::Cmd and IO::Socket::INET.
 
@@ -740,6 +799,14 @@ the C<PeerAddr> option in L<IO::Socket::INET>, or a reference to
 an array with hosts to try in turn. The L</host> method will return the value
 which was used to connect to the host.
 
+B<Port> - port to connect to.
+Default - 119 for plain NNTP and 563 for immediate SSL (nntps).
+
+B<SSL> - If the connection should be done from start with SSL, contrary to later
+upgrade with C<starttls>.
+You can use SSL arguments as documented in L<IO::Socket::SSL>, but it will
+usually use the right arguments already.
+
 B<Timeout> - Maximum time, in seconds, to wait for a response from the
 NNTP server, a value of zero will cause all IO operations to block.
 (default: 120)
@@ -772,6 +839,16 @@ documented here.
 
 =over 4
 
+=item host ()
+
+Returns the value used by the constructor, and passed to IO::Socket::INET,
+to connect to the host.
+
+=item starttls ()
+
+Upgrade existing plain connection to SSL.
+Any arguments necessary for SSL must be given in C<new> already.
+
 =item article ( [ MSGID|MSGNUM ], [FH] )
 
 Retrieve the header, a blank line, then the body (text) of the
@@ -837,6 +914,11 @@ In an array context the return value is a list containing, the number
 of articles in the group, the number of the first article, the number
 of the last article and the group name.
 
+=item help ( )
+
+Request help text (a short summary of commands that are understood by this
+implementation) from the server. Returns the text or undef upon failure.
+
 =item ihave ( MSGID [, MESSAGE ])
 
 The C<ihave> command informs the server that the client has an article
@@ -870,11 +952,17 @@ that it will allow posting.
 
 =item authinfo ( USER, PASS )
 
-Authenticates to the server (using AUTHINFO USER / AUTHINFO PASS)
-using the supplied username and password.  Please note that the
-password is sent in clear text to the server.  This command should not
-be used with valuable passwords unless the connection to the server is
-somehow protected.
+Authenticates to the server (using the original AUTHINFO USER / AUTHINFO PASS
+form, defined in RFC2980) using the supplied username and password.  Please
+note that the password is sent in clear text to the server.  This command
+should not be used with valuable passwords unless the connection to the server
+is somehow protected.
+
+=item authinfo_simple ( USER, PASS )
+
+Authenticates to the server (using the proposed NNTP V2 AUTHINFO SIMPLE form,
+defined and deprecated in RFC2980) using the supplied username and password.
+As with L</authinfo> the password is sent in clear text.
 
 =item list ()
 
@@ -940,6 +1028,14 @@ news server.
 
 Quit the remote server and close the socket connection.
 
+=item can_inet6 ()
+
+Returns whether we can use IPv6.
+
+=item can_ssl ()
+
+Returns whether we can use SSL.
+
 =back
 
 =head2 Extension methods
@@ -960,6 +1056,13 @@ each value contains the description text for the group.
 Returns a reference to a hash where the keys are all the possible
 distribution names and the values are the distribution descriptions.
 
+=item distribution_patterns ()
+
+Returns a reference to an array where each element, itself an array
+reference, consists of the three fields of a line of the distrib.pats list
+maintained by some NNTP servers, namely: a weight, a wildmat and a value
+which the client may use to construct a Distribution header.
+
 =item subscriptions ()
 
 Returns a reference to a list which contains a list of groups which
@@ -1013,7 +1116,7 @@ message.
 The result is the same as C<xhdr> except the is will be restricted to
 headers where the text of the header matches C<PATTERN>
 
-=item xrover
+=item xrover ()
 
 The XROVER command returns reference information for the article(s)
 specified.
@@ -1026,7 +1129,7 @@ values are the References: lines from the articles
 Returns a reference to a list of all the active messages in C<GROUP>, or
 the current group if C<GROUP> is not specified.
 
-=item reader
+=item reader ()
 
 Tell the server that you are a reader and not another server.
 
@@ -1139,15 +1242,22 @@ with a and ends with d.
 
 =head1 SEE ALSO
 
-L<Net::Cmd>
+L<Net::Cmd>,
+L<IO::Socket::SSL>
 
 =head1 AUTHOR
 
-Graham Barr <gbarr@pobox.com>
+Graham Barr E<lt>F<gbarr@pobox.com>E<gt>
+
+Steve Hay E<lt>F<shay@cpan.org>E<gt> is now maintaining libnet as of version
+1.22_02
 
 =head1 COPYRIGHT
 
-Copyright (c) 1995-1997 Graham Barr. All rights reserved.
+Versions up to 2.24_1 Copyright (c) 1995-1997 Graham Barr. All rights reserved.
+Changes in Version 2.25 onwards Copyright (C) 2013-2014 Steve Hay.  All rights
+reserved.
+
 This program is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself.
 
similarity index 88%
rename from cpan/libnet/Net/Netrc.pm
rename to cpan/libnet/lib/Net/Netrc.pm
index fbe8d6d..11fef3b 100644 (file)
@@ -1,23 +1,30 @@
 # Net::Netrc.pm
 #
-# Copyright (c) 1995-1998 Graham Barr <gbarr@pobox.com>. All rights reserved.
+# Versions up to 2.13 Copyright (c) 1995-1998 Graham Barr <gbarr@pobox.com>.
+# All rights reserved.
+# Changes in Version 2.13_01 onwards Copyright (C) 2013-2014 Steve Hay.  All
+# rights reserved.
 # This program is free software; you can redistribute it and/or
 # modify it under the same terms as Perl itself.
 
 package Net::Netrc;
 
-use Carp;
+use 5.008001;
+
 use strict;
+use warnings;
+
+use Carp;
 use FileHandle;
-use vars qw($VERSION $TESTING);
 
-$VERSION = "2.14";
+our $VERSION = "3.01";
 
-my %netrc = ();
+our $TESTING;
 
+my %netrc = ();
 
 sub _readrc {
-  my $host = shift;
+  my($class, $host) = @_;
   my ($home, $file);
 
   if ($^O eq "MacOS") {
@@ -56,7 +63,7 @@ sub _readrc {
     my @stat = stat($file);
 
     if (@stat) {
-      if ($stat[2] & 077) {
+      if ($stat[2] & 077) { ## no critic (ValuesAndExpressions::ProhibitLeadingZeros)
         carp "Bad permissions: $file";
         return;
       }
@@ -90,7 +97,7 @@ sub _readrc {
       while (@tok) {
         if ($tok[0] eq "default") {
           shift(@tok);
-          $mach = bless {};
+          $mach = bless {}, $class;
           $netrc{default} = [$mach];
 
           next TOKEN;
@@ -103,7 +110,7 @@ sub _readrc {
 
         if ($tok eq "machine") {
           my $host = shift @tok;
-          $mach = bless {machine => $host};
+          $mach = bless {machine => $host}, $class;
 
           $netrc{$host} = []
             unless exists($netrc{$host});
@@ -132,9 +139,9 @@ sub _readrc {
 
 
 sub lookup {
-  my ($pkg, $mach, $login) = @_;
+  my ($class, $mach, $login) = @_;
 
-  _readrc()
+  $class->_readrc()
     unless exists $netrc{default};
 
   $mach ||= 'default';
@@ -143,12 +150,11 @@ sub lookup {
 
   if (exists $netrc{$mach}) {
     if (defined $login) {
-      my $m;
-      foreach $m (@{$netrc{$mach}}) {
+      foreach my $m (@{$netrc{$mach}}) {
         return $m
           if (exists $m->{login} && $m->{login} eq $login);
       }
-      return undef;
+      return;
     }
     return $netrc{$mach}->[0];
   }
@@ -156,7 +162,7 @@ sub lookup {
   return $netrc{default}->[0]
     if defined $netrc{default};
 
-  return undef;
+  return;
 }
 
 
@@ -317,16 +323,22 @@ Return a list of login, password and account information for the netrc entry
 
 =head1 AUTHOR
 
-Graham Barr <gbarr@pobox.com>
+Graham Barr E<lt>F<gbarr@pobox.com>E<gt>
+
+Steve Hay E<lt>F<shay@cpan.org>E<gt> is now maintaining libnet as of version
+1.22_02
 
 =head1 SEE ALSO
 
-L<Net::Netrc>
+L<Net::Netrc>,
 L<Net::Cmd>
 
 =head1 COPYRIGHT
 
-Copyright (c) 1995-1998 Graham Barr. All rights reserved.
+Versions up to 2.13 Copyright (c) 1995-1998 Graham Barr. All rights reserved.
+Changes in Version 2.13_01 onwards Copyright (C) 2013-2014 Steve Hay.  All
+rights reserved.
+
 This program is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself.
 
similarity index 83%
rename from cpan/libnet/Net/POP3.pm
rename to cpan/libnet/lib/Net/POP3.pm
index 4b94a11..d568d94 100644 (file)
@@ -1,22 +1,49 @@
 # Net::POP3.pm
 #
-# Copyright (c) 1995-2004 Graham Barr <gbarr@pobox.com>. All rights reserved.
+# Versions up to 2.29 Copyright (c) 1995-2004 Graham Barr <gbarr@pobox.com>.
+# All rights reserved.
+# Changes in Version 2.29_01 onwards Copyright (C) 2013-2014 Steve Hay.  All
+# rights reserved.
 # This program is free software; you can redistribute it and/or
 # modify it under the same terms as Perl itself.
 
 package Net::POP3;
 
+use 5.008001;
+
 use strict;
+use warnings;
+
+use Carp;
 use IO::Socket;
-use vars qw(@ISA $VERSION $debug);
 use Net::Cmd;
-use Carp;
 use Net::Config;
 
-$VERSION = "2.31";
+our $VERSION = "3.01";
 
-@ISA = qw(Net::Cmd IO::Socket::INET);
+# Code for detecting if we can use SSL
+my $ssl_class = eval {
+  require IO::Socket::SSL;
+  # first version with default CA on most platforms
+  IO::Socket::SSL->VERSION(1.999);
+} && 'IO::Socket::SSL';
 
+my $nossl_warn = !$ssl_class &&
+  'To use SSL please install IO::Socket::SSL with version>=1.999';
+
+# Code for detecting if we can use IPv6
+my $inet6_class = eval {
+  require IO::Socket::IP;
+  IO::Socket::IP->VERSION(0.20);
+} && 'IO::Socket::IP' || eval {
+  require IO::Socket::INET6;
+  IO::Socket::INET6->VERSION(2.62);
+} && 'IO::Socket::INET6';
+
+sub can_ssl   { $ssl_class };
+sub can_inet6 { $inet6_class };
+
+our @ISA = ('Net::Cmd', $inet6_class || 'IO::Socket::INET');
 
 sub new {
   my $self = shift;
@@ -34,23 +61,35 @@ sub new {
   my $obj;
   my @localport = exists $arg{ResvPort} ? (LocalPort => $arg{ResvPort}) : ();
 
-  my $h;
-  foreach $h (@{$hosts}) {
+  if ($arg{SSL}) {
+    # SSL from start
+    die $nossl_warn if !$ssl_class;
+    $arg{Port} ||= 995;
+  }
+
+  $arg{Timeout} = 120 if ! defined $arg{Timeout};
+
+  foreach my $h (@{$hosts}) {
     $obj = $type->SUPER::new(
       PeerAddr => ($host = $h),
       PeerPort => $arg{Port} || 'pop3(110)',
       Proto => 'tcp',
       @localport,
-      Timeout => defined $arg{Timeout}
-      ? $arg{Timeout}
-      : 120
+      Timeout => $arg{Timeout},
       )
       and last;
   }
 
-  return undef
+  return
     unless defined $obj;
 
+  ${*$obj}{'net_pop3_arg'} = \%arg;
+  if ($arg{SSL}) {
+    Net::POP3::_SSL->start_SSL($obj,
+      SSL_verifycn_name => $host,%arg
+    ) or return;
+  }
+
   ${*$obj}{'net_pop3_host'} = $host;
 
   $obj->autoflush(1);
@@ -58,7 +97,7 @@ sub new {
 
   unless ($obj->response() == CMD_OK) {
     $obj->close();
-    return undef;
+    return;
   }
 
   ${*$obj}{'net_pop3_banner'} = $obj->message;
@@ -93,6 +132,16 @@ sub login {
     and $me->pass($pass);
 }
 
+sub starttls {
+  my $self = shift;
+  $ssl_class or die $nossl_warn;
+  $self->_STLS or return;
+  Net::POP3::_SSL->start_SSL($self,
+    %{ ${*$self}{'net_pop3_arg'} }, # (ssl) args given in new
+    @_   # more (ssl) args
+  ) or return;
+  return 1;
+}
 
 sub apop {
   @_ >= 1 && @_ <= 3 or croak 'usage: $pop3->apop( USER, PASS )';
@@ -108,10 +157,10 @@ sub apop {
   }
   else {
     carp "You need to install Digest::MD5 or MD5 to use the APOP command";
-    return undef;
+    return;
   }
 
-  return undef
+  return
     unless ($banner = (${*$me}{'net_pop3_banner'} =~ /(<.*>)/)[0]);
 
   if (@_ <= 2) {
@@ -120,7 +169,7 @@ sub apop {
 
   $md->add($banner, $pass);
 
-  return undef
+  return
     unless ($me->_APOP($user, $md->hexdigest));
 
   $me->_get_mailbox_count();
@@ -138,7 +187,7 @@ sub pass {
 
   my ($me, $pass) = @_;
 
-  return undef
+  return
     unless ($me->_PASS($pass));
 
   $me->_get_mailbox_count();
@@ -165,7 +214,7 @@ sub reset {
 sub last {
   @_ == 1 or croak 'usage: $obj->last()';
 
-  return undef
+  return
     unless $_[0]->_LAST && $_[0]->message =~ /(\d+)/;
 
   return $1;
@@ -176,7 +225,7 @@ sub top {
   @_ == 2 || @_ == 3 or croak 'usage: $pop3->top( MSGNUM [, NUMLINES ])';
   my $me = shift;
 
-  return undef
+  return
     unless $me->_TOP($_[0], $_[1] || 0);
 
   $me->read_until_dot;
@@ -198,7 +247,7 @@ sub list {
   @_ == 1 || @_ == 2 or croak 'usage: $pop3->list( [ MSGNUM ] )';
   my $me = shift;
 
-  return undef
+  return
     unless $me->_LIST(@_);
 
   if (@_) {
@@ -207,7 +256,7 @@ sub list {
   }
 
   my $info = $me->read_until_dot
-    or return undef;
+    or return;
 
   my %hash = map { (/(\d+)\D+(\d+)/) } @$info;
 
@@ -219,7 +268,7 @@ sub get {
   @_ == 2 or @_ == 3 or croak 'usage: $pop3->get( MSGNUM [, FH ])';
   my $me = shift;
 
-  return undef
+  return
     unless $me->_RETR(shift);
 
   $me->read_until_dot(@_);
@@ -249,16 +298,15 @@ sub uidl {
   my $uidl;
 
   $me->_UIDL(@_)
-    or return undef;
+    or return;
   if (@_) {
     $uidl = ($me->message =~ /\d+\s+([\041-\176]+)/)[0];
   }
   else {
     my $ref = $me->read_until_dot
-      or return undef;
-    my $ln;
+      or return;
     $uidl = {};
-    foreach $ln (@$ref) {
+    foreach my $ln (@$ref) {
       my ($msg, $uid) = $ln =~ /^\s*(\d+)\s+([\041-\176]+)/;
       $uidl->{$msg} = $uid;
     }
@@ -323,6 +371,7 @@ sub _PING { shift->command('PING', $_[0])->response() == CMD_OK }
 sub _RPOP { shift->command('RPOP', $_[0])->response() == CMD_OK }
 sub _LAST { shift->command('LAST'       )->response() == CMD_OK }
 sub _CAPA { shift->command('CAPA'       )->response() == CMD_OK }
+sub _STLS { shift->command("STLS",     )->response() == CMD_OK }
 
 
 sub quit {
@@ -349,7 +398,7 @@ sub DESTROY {
 
 sub response {
   my $cmd  = shift;
-  my $str  = $cmd->getline() or return undef;
+  my $str  = $cmd->getline() or return;
   my $code = "500";
 
   $cmd->debug_print(0, $str)
@@ -520,6 +569,24 @@ sub banner {
   return ${*$this}{'net_pop3_banner'};
 }
 
+{
+  package Net::POP3::_SSL;
+  our @ISA = ( $ssl_class ? ($ssl_class):(), 'Net::POP3' );
+  sub starttls { die "POP3 connection is already in SSL mode" }
+  sub start_SSL {
+    my ($class,$pop3,%arg) = @_;
+    delete @arg{ grep { !m{^SSL_} } keys %arg };
+    ( $arg{SSL_verifycn_name} ||= $pop3->host )
+       =~s{(?<!:):[\w()]+$}{}; # strip port
+    $arg{SSL_verifycn_scheme} ||= 'pop3';
+    my $ok = $class->SUPER::start_SSL($pop3,%arg);
+    $@ = $ssl_class->errstr if !$ok;
+    return $ok;
+  }
+}
+
+
+
 1;
 
 __END__
@@ -535,6 +602,7 @@ Net::POP3 - Post Office Protocol 3 Client class (RFC1939)
     # Constructors
     $pop = Net::POP3->new('pop3host');
     $pop = Net::POP3->new('pop3host', Timeout => 60);
+    $pop = Net::POP3->new('pop3host', SSL => 1, Timeout => 60);
 
     if ($pop->login($username, $password) > 0) {
       my $msgnums = $pop->list; # hashref of msgnum => size
@@ -580,6 +648,14 @@ the C<PeerAddr> option in L<IO::Socket::INET>, or a reference to
 an array with hosts to try in turn. The L</host> method will return the value
 which was used to connect to the host.
 
+B<Port> - port to connect to.
+Default - 110 for plain POP3 and 995 for POP3s (direct SSL).
+
+B<SSL> - If the connection should be done from start with SSL, contrary to later
+upgrade with C<starttls>.
+You can use SSL arguments as documented in L<IO::Socket::SSL>, but it will
+usually use the right arguments already.
+
 B<ResvPort> - If given then the socket for the C<Net::POP3> object
 will be bound to the local port given using C<bind> when the socket is
 created.
@@ -604,6 +680,11 @@ documented here.
 
 =over 4
 
+=item host ()
+
+Returns the value used by the constructor, and passed to IO::Socket::INET,
+to connect to the host.
+
 =item auth ( USERNAME, PASSWORD )
 
 Attempt SASL authentication.
@@ -629,6 +710,12 @@ will give a true value in a boolean context, but zero in a numeric context.
 
 If there was an error authenticating the user then I<undef> will be returned.
 
+=item starttls ( SSLARGS )
+
+Upgrade existing plain connection to SSL.
+You can use SSL arguments as documented in L<IO::Socket::SSL>, but it will
+usually use the right arguments already.
+
 =item apop ( [ USER [, PASS ]] )
 
 Authenticate with the server identifying as C<USER> with password C<PASS>.
@@ -718,6 +805,14 @@ status of all messages to not be deleted.
 Quit and close the connection to the remote POP3 server. Any messages marked
 as deleted will be deleted from the remote mailbox.
 
+=item can_inet6 ()
+
+Returns whether we can use IPv6.
+
+=item can_ssl ()
+
+Returns whether we can use SSL.
+
 =back
 
 =head1 NOTES
@@ -729,15 +824,22 @@ means that any messages marked to be deleted will not be.
 =head1 SEE ALSO
 
 L<Net::Netrc>,
-L<Net::Cmd>
+L<Net::Cmd>,
+L<IO::Socket::SSL>
 
 =head1 AUTHOR
 
-Graham Barr <gbarr@pobox.com>
+Graham Barr E<lt>F<gbarr@pobox.com>E<gt>
+
+Steve Hay E<lt>F<shay@cpan.org>E<gt> is now maintaining libnet as of version
+1.22_02
 
 =head1 COPYRIGHT
 
-Copyright (c) 1995-2003 Graham Barr. All rights reserved.
+Versions up to 2.29 Copyright (c) 1995-2004 Graham Barr. All rights reserved.
+Changes in Version 2.29_01 onwards Copyright (C) 2013-2014 Steve Hay.  All
+rights reserved.
+
 This program is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself.
 
similarity index 83%
rename from cpan/libnet/Net/SMTP.pm
rename to cpan/libnet/lib/Net/SMTP.pm
index 3d193a4..841373e 100644 (file)
@@ -1,25 +1,50 @@
 # Net::SMTP.pm
 #
-# Copyright (c) 1995-2004 Graham Barr <gbarr@pobox.com>. All rights reserved.
+# Versions up to 2.31_1 Copyright (c) 1995-2004 Graham Barr <gbarr@pobox.com>.
+# All rights reserved.
+# Changes in Version 2.31_2 onwards Copyright (C) 2013-2014 Steve Hay.  All
+# rights reserved.
 # This program is free software; you can redistribute it and/or
 # modify it under the same terms as Perl itself.
 
 package Net::SMTP;
 
-require 5.001;
+use 5.008001;
 
 use strict;
-use vars qw($VERSION @ISA);
-use Socket 1.3;
+use warnings;
+
 use Carp;
 use IO::Socket;
 use Net::Cmd;
 use Net::Config;
+use Socket 1.3;
+
+our $VERSION = "3.01";
+
+# Code for detecting if we can use SSL
+my $ssl_class = eval {
+  require IO::Socket::SSL;
+  # first version with default CA on most platforms
+  IO::Socket::SSL->VERSION(1.999);
+} && 'IO::Socket::SSL';
 
-$VERSION = "2.34";
+my $nossl_warn = !$ssl_class &&
+  'To use SSL please install IO::Socket::SSL with version>=1.999';
 
-@ISA = qw(Net::Cmd IO::Socket::INET);
+# Code for detecting if we can use IPv6
+my $inet6_class = eval {
+  require IO::Socket::IP;
+  IO::Socket::IP->VERSION(0.20);
+} && 'IO::Socket::IP' || eval {
+  require IO::Socket::INET6;
+  IO::Socket::INET6->VERSION(2.62);
+} && 'IO::Socket::INET6';
 
+sub can_ssl   { $ssl_class };
+sub can_inet6 { $inet6_class };
+
+our @ISA = ('Net::Cmd', $inet6_class || 'IO::Socket::INET');
 
 sub new {
   my $self = shift;
@@ -33,27 +58,39 @@ sub new {
     %arg  = @_;
     $host = delete $arg{Host};
   }
+
+  if ($arg{SSL}) {
+    # SSL from start
+    die $nossl_warn if !$ssl_class;
+    $arg{Port} ||= 465;
+  }
+
   my $hosts = defined $host ? $host : $NetConfig{smtp_hosts};
   my $obj;
 
-  my $h;
-  foreach $h (@{ref($hosts) ? $hosts : [$hosts]}) {
+  $arg{Timeout} = 120 if ! defined $arg{Timeout};
+
+  foreach my $h (@{ref($hosts) ? $hosts : [$hosts]}) {
     $obj = $type->SUPER::new(
       PeerAddr => ($host = $h),
       PeerPort => $arg{Port} || 'smtp(25)',
       LocalAddr => $arg{LocalAddr},
       LocalPort => $arg{LocalPort},
       Proto     => 'tcp',
-      Timeout   => defined $arg{Timeout}
-      ? $arg{Timeout}
-      : 120
+      Timeout   => $arg{Timeout}
       )
       and last;
   }
 
-  return undef
+  return
     unless defined $obj;
 
+  ${*$obj}{'net_smtp_arg'} = \%arg;
+  if ($arg{SSL}) {
+    Net::SMTP::_SSL->start_SSL($obj,SSL_verifycn_name => $host,%arg)
+      or return;
+  }
+
   $obj->autoflush(1);
 
   $obj->debug(exists $arg{Debug} ? $arg{Debug} : undef);
@@ -62,7 +99,7 @@ sub new {
     my $err = ref($obj) . ": " . $obj->code . " " . $obj->message;
     $obj->close();
     $@ = $err;
-    return undef;
+    return;
   }
 
   ${*$obj}{'net_smtp_exact_addr'} = $arg{ExactAddresses};
@@ -75,7 +112,7 @@ sub new {
     my $err = ref($obj) . ": " . $obj->code . " " . $obj->message;
     $obj->close();
     $@ = $err;
-    return undef;
+    return;
   }
 
   $obj;
@@ -128,7 +165,10 @@ sub auth {
 
   if (ref($username) and UNIVERSAL::isa($username, 'Authen::SASL')) {
     $sasl = $username;
-    $sasl->mechanism($mechanisms);
+    my $requested_mechanisms = $sasl->mechanism();
+    if (! defined($requested_mechanisms) || $requested_mechanisms eq '') {
+      $sasl->mechanism($mechanisms);
+    }
   }
   else {
     die "auth(username, password)" if not length $username;
@@ -138,14 +178,30 @@ sub auth {
         user     => $username,
         pass     => $password,
         authname => $username,
-      }
+      },
+      debug => $self->debug
     );
   }
 
-  # We should probably allow the user to pass the host, but I don't
-  # currently know and SASL mechanisms that are used by smtp that need it
-  my $client = $sasl->client_new('smtp', ${*$self}{'net_smtp_host'}, 0);
-  my $str    = $client->client_start;
+  my $client;
+  my $str;
+  do {
+    if ($client) {
+      # $client mechanism failed, so we need to exclude this mechanism from list
+      my $failed_mechanism = $client->mechanism;
+      $self->debug_text("Auth mechanism failed: $failed_mechanism")
+        if $self->debug;
+      $mechanisms =~ s/\b\Q$failed_mechanism\E\b//;
+      last unless $mechanisms =~ /\S/;
+    }
+    $sasl->mechanism($mechanisms);
+    
+    # We should probably allow the user to pass the host, but I don't
+    # currently know and SASL mechanisms that are used by smtp that need it
+
+    $client = $sasl->client_new('smtp', ${*$self}{'net_smtp_host'}, 0);
+    $str    = $client->client_start;
+  } while (!defined $str);
 
   # We don't support sasl mechanisms that encrypt the socket traffic.
   # todo that we would really need to change the ISA hierarchy
@@ -177,8 +233,7 @@ sub hello {
 
   if ($ok) {
     my $h = ${*$me}{'net_smtp_esmtp'} = {};
-    my $ln;
-    foreach $ln (@msg) {
+    foreach my $ln (@msg) {
       $h->{uc $1} = $2
         if $ln =~ /([-\w]+)\b[= \t]*([^\n]*)/;
     }
@@ -188,12 +243,26 @@ sub hello {
       if $ok = $me->_HELO($domain);
   }
 
-  return undef unless $ok;
+  return unless $ok;
+  ${*$me}{net_smtp_hello_domain} = $domain;
 
   $msg[0] =~ /\A\s*(\S+)/;
   return ($1 || " ");
 }
 
+sub starttls {
+  my $self = shift;
+  $ssl_class or die $nossl_warn;
+  $self->_STARTTLS or return;
+  Net::SMTP::_SSL->start_SSL($self,
+    %{ ${*$self}{'net_smtp_arg'} }, # (ssl) args given in new
+    @_   # more (ssl) args
+  ) or return;
+
+  # another hello after starttls to read new ESMTP capabilities
+  return $self->hello(${*$self}{net_smtp_hello_domain});
+}
+
 
 sub supports {
   my $self = shift;
@@ -399,8 +468,7 @@ sub recipient {
   }
 
   my @ok;
-  my $addr;
-  foreach $addr (@_) {
+  foreach my $addr (@_) {
     if ($smtp->_RCPT("TO:" . _addr($smtp, $addr) . $opts)) {
       push(@ok, $addr) if $skip_bad;
     }
@@ -531,6 +599,26 @@ sub _BDAT { shift->command("BDAT", @_) }
 sub _TURN { shift->unsupported(@_); }
 sub _ETRN { shift->command("ETRN", @_)->response() == CMD_OK }
 sub _AUTH { shift->command("AUTH", @_)->response() == CMD_OK }
+sub _STARTTLS { shift->command("STARTTLS")->response() == CMD_OK }
+
+
+{
+  package Net::SMTP::_SSL;
+  our @ISA = ( $ssl_class ? ($ssl_class):(), 'Net::SMTP' );
+  sub starttls { die "SMTP connection is already in SSL mode" }
+  sub start_SSL {
+    my ($class,$smtp,%arg) = @_;
+    delete @arg{ grep { !m{^SSL_} } keys %arg };
+    ( $arg{SSL_verifycn_name} ||= $smtp->host )
+       =~s{(?<!:):[\w()]+$}{}; # strip port
+    $arg{SSL_verifycn_scheme} ||= 'smtp';
+    my $ok = $class->SUPER::start_SSL($smtp,%arg);
+    $@ = $ssl_class->errstr if !$ok;
+    return $ok;
+  }
+}
+
+
 
 1;
 
@@ -621,9 +709,15 @@ B<Host> - SMTP host to connect to. It may be a single scalar (hostname[:port]),
 as defined for the C<PeerAddr> option in L<IO::Socket::INET>, or a reference to
 an array with hosts to try in turn. The L</host> method will return the value
 which was used to connect to the host.
+Format - C<PeerHost> from L<IO::Socket::INET> new method.
 
-B<Port> - port to connect to. Format - C<PeerHost> from L<IO::Socket::INET> new method.
-Default - 25.
+B<Port> - port to connect to.
+Default - 25 for plain SMTP and 465 for immediate SSL.
+
+B<SSL> - If the connection should be done from start with SSL, contrary to later
+upgrade with C<starttls>.
+You can use SSL arguments as documented in L<IO::Socket::SSL>, but it will
+usually use the right arguments already.
 
 B<LocalAddr> and B<LocalPort> - These parameters are passed directly
 to IO::Socket to allow binding the socket to a local port.
@@ -655,6 +749,14 @@ Example:
                            Debug   => 1,
                           );
 
+    # the same with direct SSL
+    $smtp = Net::SMTP->new('mailhost',
+                          Hello => 'my.mail.domain',
+                          Timeout => 30,
+                          Debug   => 1,
+                          SSL     => 1,
+                         );
+
     # Connect to the default server from Net::config
     $smtp = Net::SMTP->new(
                            Hello => 'my.mail.domain',
@@ -702,6 +804,12 @@ to connect to the host.
 
 Request a queue run for the DOMAIN given.
 
+=item starttls ( SSLARGS )
+
+Upgrade existing plain connection to SSL.
+You can use SSL arguments as documented in L<IO::Socket::SSL>, but it will
+usually use the right arguments already.
+
 =item auth ( USERNAME, PASSWORD )
 
 Attempt SASL authentication. Requires Authen::SASL module.
@@ -828,6 +936,13 @@ If C<DATA> is not specified then the result will indicate that the server
 wishes the data to be sent. The data must then be sent using the C<datasend>
 and C<dataend> methods described in L<Net::Cmd>.
 
+=item bdat ( DATA )
+
+=item bdatlast ( DATA )
+
+Use the alternate DATA command "BDAT" of the data chunking service extension
+defined in RFC1830 for efficiently sending large MIME messages.
+
 =item expand ( ADDRESS )
 
 Request the server to expand the given address Returns an array
@@ -848,6 +963,14 @@ Request help text from the server. Returns the text or undef upon failure
 
 Send the QUIT command to the remote SMTP server and close the socket connection.
 
+=item can_inet6 ()
+
+Returns whether we can use IPv6.
+
+=item can_ssl ()
+
+Returns whether we can use SSL.
+
 =back
 
 =head1 ADDRESSES
@@ -868,15 +991,22 @@ accept the address surrounded by angle brackets.
 
 =head1 SEE ALSO
 
-L<Net::Cmd>
+L<Net::Cmd>,
+L<IO::Socket::SSL>
 
 =head1 AUTHOR
 
-Graham Barr <gbarr@pobox.com>
+Graham Barr E<lt>F<gbarr@pobox.com>E<gt>
+
+Steve Hay E<lt>F<shay@cpan.org>E<gt> is now maintaining libnet as of version
+1.22_02
 
 =head1 COPYRIGHT
 
-Copyright (c) 1995-2004 Graham Barr. All rights reserved.
+Versions up to 2.31_1 Copyright (c) 1995-2004 Graham Barr. All rights reserved.
+Changes in Version 2.31_2 onwards Copyright (C) 2013-2014 Steve Hay.  All rights
+reserved.
+
 This program is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself.
 
similarity index 78%
rename from cpan/libnet/Net/Time.pm
rename to cpan/libnet/lib/Net/Time.pm
index 6b3b641..54ca52a 100644 (file)
@@ -1,26 +1,31 @@
 # Net::Time.pm
 #
-# Copyright (c) 1995-2004 Graham Barr <gbarr@pobox.com>. All rights reserved.
+# Versions up to 2.10 Copyright (c) 1995-2004 Graham Barr <gbarr@pobox.com>.
+# All rights reserved.
+# Changes in Version 2.11 onwards Copyright (C) 2014 Steve Hay.  All rights
+# reserved.
 # This program is free software; you can redistribute it and/or
 # modify it under the same terms as Perl itself.
 
 package Net::Time;
 
+use 5.008001;
+
 use strict;
-use vars qw($VERSION @ISA @EXPORT_OK $TIMEOUT);
+use warnings;
+
 use Carp;
+use Exporter;
+use IO::Select;
 use IO::Socket;
-require Exporter;
 use Net::Config;
-use IO::Select;
 
-@ISA       = qw(Exporter);
-@EXPORT_OK = qw(inet_time inet_daytime);
+our @ISA       = qw(Exporter);
+our @EXPORT_OK = qw(inet_time inet_daytime);
 
-$VERSION = "2.11";
-
-$TIMEOUT = 120;
+our $VERSION = "3.01";
 
+our $TIMEOUT = 120;
 
 sub _socket {
   my ($pname, $pnum, $host, $proto, $timeout) = @_;
@@ -33,9 +38,9 @@ sub _socket {
 
   my $me;
 
-  foreach $host (@$hosts) {
+  foreach my $addr (@$hosts) {
     $me = IO::Socket::INET->new(
-      PeerAddr => $host,
+      PeerAddr => $addr,
       PeerPort => $port,
       Proto    => $proto
       )
@@ -57,11 +62,11 @@ sub _socket {
 
 
 sub inet_time {
-  my $s      = _socket('time', 37, @_) || return undef;
+  my $s      = _socket('time', 37, @_) || return;
   my $buf    = '';
   my $offset = 0 | 0;
 
-  return undef
+  return
     unless defined $s->recv($buf, length(pack("N", 0)));
 
   # unpack, we | 0 to ensure we have an unsigned
@@ -87,7 +92,7 @@ sub inet_time {
 
 
 sub inet_daytime {
-  my $s   = _socket('daytime', 13, @_) || return undef;
+  my $s   = _socket('daytime', 13, @_) || return;
   my $buf = '';
 
   defined($s->recv($buf, 1024))
@@ -140,11 +145,17 @@ C<udp>. The result will be an ASCII string or I<undef> upon failure.
 
 =head1 AUTHOR
 
-Graham Barr <gbarr@pobox.com>
+Graham Barr E<lt>F<gbarr@pobox.com>E<gt>
+
+Steve Hay E<lt>F<shay@cpan.org>E<gt> is now maintaining libnet as of version
+1.22_02
 
 =head1 COPYRIGHT
 
-Copyright (c) 1995-2004 Graham Barr. All rights reserved.
+Versions up to 2.11 Copyright (c) 1995-2004 Graham Barr. All rights reserved.
+Changes in Version 2.11 onwards Copyright (C) 2014 Steve Hay.  All rights
+reserved.
+
 This program is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself.
 
similarity index 93%
rename from cpan/libnet/Net/libnetFAQ.pod
rename to cpan/libnet/lib/Net/libnetFAQ.pod
index 78efe8c..dc1b33e 100644 (file)
@@ -45,24 +45,24 @@ the internet community.
 
 =head2 Which version of perl do I need ?
 
-libnet has been know to work with versions of perl from 5.002 onwards. However
-if your release of perl is prior to perl5.004 then you will need to
-obtain and install the IO distribution from CPAN. If you have perl5.004
-or later then you will have the IO modules in your installation already,
-but CPAN may contain updates.
+This version of libnet requires Perl 5.8.1 or higher.
 
 =head2 What other modules do I need ?
 
-The only modules you will need installed are the modules from the IO
-distribution. If you have perl5.004 or later you will already have
-these modules.
+No non-core modules are required for normal use, except on os390,
+which requires Convert::EBCDIC.
+
+Authen::SASL is required for AUTH support.
+
+IO::Socket::SSL version 1.999 or higher is required for SSL support.
+
+IO::Socket::IP version 0.20 or IO::Socket::INET6 version 2.62 is
+required for IPv6 support.
 
 =head2 What machines support libnet ?
 
 libnet itself is an entirely perl-code distribution so it should work
-on any machine that perl runs on. However IO may not work
-with some machines and earlier releases of perl. But this
-should not be the case with perl version 5.004 or later.
+on any machine that perl runs on.
 
 =head2 Where can I get the latest libnet release
 
index 3a34251..d686ab1 100644 (file)
@@ -1,16 +1,17 @@
-#!./perl -w
+#!perl
+
+use 5.008001;
+
+use strict;
+use warnings;
 
 BEGIN {
-    if ($ENV{PERL_CORE}) {
-        chdir 't' if -d 't';
-        @INC = '../lib';
-    }
-    if (!eval "require Socket") {
+    if (!eval { require Socket; 1 }) {
         print "1..0 # no Socket\n"; exit 0;
     }
     undef *{Socket::inet_aton};
     undef *{Socket::inet_ntoa};
-    if (ord('A') == 193 && !eval "require Convert::EBCDIC") {
+    if (ord('A') == 193 && !eval { require Convert::EBCDIC; 1 }) {
         print "1..0 # EBCDIC but no Convert::EBCDIC\n"; exit 0;
     }
     $INC{'Socket.pm'} = 1;
@@ -20,7 +21,7 @@ package Socket;
 
 sub import {
         my $pkg = caller();
-        no strict 'refs';
+        no strict 'refs'; ## no critic (TestingAndDebugging::ProhibitNoStrict)
         *{ $pkg . '::inet_aton' } = \&inet_aton;
         *{ $pkg . '::inet_ntoa' } = \&inet_ntoa;
 }
index f642340..cdbdc29 100644 (file)
@@ -1,14 +1,15 @@
-#!./perl -w
+#!perl
+
+use 5.008001;
+
+use strict;
+use warnings;
 
 BEGIN {
-    if ($ENV{PERL_CORE}) {
-        chdir 't' if -d 't';
-        @INC = '../lib';
-    }
-    if (!eval "require Socket") {
+    if (!eval { require Socket; 1 }) {
         print "1..0 # no Socket\n"; exit 0;
     }
-    if (ord('A') == 193 && !eval "require Convert::EBCDIC") {
+    if (ord('A') == 193 && !eval { require Convert::EBCDIC; 1 }) {
         print "1..0 # EBCDIC but no Convert::EBCDIC\n"; exit 0;
     }
 }
@@ -18,7 +19,7 @@ BEGIN {
 
   use IO::File;
   use Net::Cmd;
-  @ISA = qw(Net::Cmd IO::File);
+  our @ISA = qw(Net::Cmd IO::File);
 
   sub timeout { 0 }
 
diff --git a/cpan/libnet/t/external/ftp-ssl.t b/cpan/libnet/t/external/ftp-ssl.t
new file mode 100644 (file)
index 0000000..3036630
--- /dev/null
@@ -0,0 +1,173 @@
+#!perl
+
+use 5.008001;
+
+use strict;
+use warnings;
+
+use Net::FTP;
+use Test::More;
+use File::Temp;
+use IO::Socket::INET;
+
+my $server = 'test.rebex.net';
+my $debug = 0;
+
+plan skip_all => "no SSL support" if ! Net::FTP->can_ssl;
+require IO::Socket::SSL;
+
+
+# first try to connect w/o ftp
+# plain
+diag( "connect inet to $server:21" );
+IO::Socket::INET->new( "$server:21" ) or do {
+    plan skip_all => "$server:21 not reachable";
+};
+
+# ssl to the right host
+diag( "connect inet to $server:990" );
+my $sock = IO::Socket::INET->new( "$server:990") or do {
+    plan skip_all => "$server:990 not reachable";
+};
+
+# now we need CAs
+my $cafh = File::Temp->new( UNLINK => 0, SUFFIX => '.crt' );
+my %sslargs = ( SSL_ca_file => $cafh->filename );
+print $cafh <DATA>;
+close($cafh);
+
+diag( "upgrade to ssl $server:990" );
+IO::Socket::SSL->start_SSL($sock,
+    SSL_verify_mode => 1,
+    SSL_verifycn_name => $server,
+    SSL_verifycn_scheme => 'ftp',
+    %sslargs,
+) or do {
+    plan skip_all => "$server:990 not upgradable to SSL: ".
+       $IO::Socket::SSL::SSL_ERROR;
+};
+
+plan tests => 9;
+
+# first direct SSL
+diag( "connect ftp over ssl to $server" );
+my $ftp = Net::FTP->new($server,
+    SSL => 1,
+    %sslargs,
+    Debug => $debug,
+    Passive => 1,
+);
+ok($ftp,"ftp ssl connect $server");
+$ftp->login("anonymous",'net-sslglue-ftp@test.perl')
+    or die "login to $server failed";
+diag("logged in");
+# check that we can talk on connection
+ok(~~$ftp->ls,"directory listing protected");
+$ftp->prot('C');
+ok(~~$ftp->ls,"directory listing clear");
+
+# then TLS upgrade inside plain connection
+$ftp = Net::FTP->new($server,
+    Passive => 1,
+    Debug => $debug,
+    %sslargs
+);
+ok($ftp,"ftp plain connect $server");
+my $ok = $ftp->starttls;
+ok($ok,"ssl upgrade");
+$ftp->login("anonymous",'net-sslglue-ftp@test.perl')
+    or die "login to $server failed";
+diag("logged in");
+# check that we can talk on connection
+ok(~~$ftp->ls,"directory listing protected");
+$ftp->prot('C');
+ok(~~$ftp->ls,"directory listing clear");
+$ok = $ftp->stoptls;
+ok($ok,"ssl downgrade");
+ok(~~$ftp->ls,"directory listing after downgrade");
+
+
+__DATA__
+# Subject: C=IL, O=StartCom Ltd., OU=Secure Digital Certificate Signing, CN=StartCom Class 2 Primary Intermediate Server CA
+# Issuer:  C=IL, O=StartCom Ltd., OU=Secure Digital Certificate Signing, CN=StartCom Certification Authority
+-----BEGIN CERTIFICATE-----
+MIIGNDCCBBygAwIBAgIBGjANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW
+MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg
+Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkwHhcNMDcxMDI0MjA1NzA5WhcNMTcxMDI0MjA1NzA5WjCB
+jDELMAkGA1UEBhMCSUwxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4xKzApBgNVBAsT
+IlNlY3VyZSBEaWdpdGFsIENlcnRpZmljYXRlIFNpZ25pbmcxODA2BgNVBAMTL1N0
+YXJ0Q29tIENsYXNzIDIgUHJpbWFyeSBJbnRlcm1lZGlhdGUgU2VydmVyIENBMIIB
+IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4k85L6GMmoWtCA4IPlfyiAEh
+G5SpbOK426oZGEY6UqH1D/RujOqWjJaHeRNAUS8i8gyLhw9l33F0NENVsTUJm9m8
+H/rrQtCXQHK3Q5Y9upadXVACHJuRjZzArNe7LxfXyz6CnXPrB0KSss1ks3RVG7RL
+hiEs93iHMuAW5Nq9TJXqpAp+tgoNLorPVavD5d1Bik7mb2VsskDPF125w2oLJxGE
+d2H2wnztwI14FBiZgZl1Y7foU9O6YekO+qIw80aiuckfbIBaQKwn7UhHM7BUxkYa
+8zVhwQIpkFR+ZE3EMFICgtffziFuGJHXuKuMJxe18KMBL47SLoc6PbQpZ4rEAwID
+AQABo4IBrTCCAakwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD
+VR0OBBYEFBHbI0X9VMxqcW+EigPXvvcBLyaGMB8GA1UdIwQYMBaAFE4L7xqkQFul
+F2mHMMo0aEPQQa7yMGYGCCsGAQUFBwEBBFowWDAnBggrBgEFBQcwAYYbaHR0cDov
+L29jc3Auc3RhcnRzc2wuY29tL2NhMC0GCCsGAQUFBzAChiFodHRwOi8vd3d3LnN0
+YXJ0c3NsLmNvbS9zZnNjYS5jcnQwWwYDVR0fBFQwUjAnoCWgI4YhaHR0cDovL3d3
+dy5zdGFydHNzbC5jb20vc2ZzY2EuY3JsMCegJaAjhiFodHRwOi8vY3JsLnN0YXJ0
+c3NsLmNvbS9zZnNjYS5jcmwwgYAGA1UdIAR5MHcwdQYLKwYBBAGBtTcBAgEwZjAu
+BggrBgEFBQcCARYiaHR0cDovL3d3dy5zdGFydHNzbC5jb20vcG9saWN5LnBkZjA0
+BggrBgEFBQcCARYoaHR0cDovL3d3dy5zdGFydHNzbC5jb20vaW50ZXJtZWRpYXRl
+LnBkZjANBgkqhkiG9w0BAQUFAAOCAgEAnQfh7pB2MWcWRXCMy4SLS1doRKWJwfJ+
+yyiL9edwd9W29AshYKWhdHMkIoDW2LqNomJdCTVCKfs5Y0ULpLA4Gmj0lRPM4EOU
+7Os5GuxXKdmZbfWEzY5zrsncavqenRZkkwjHHMKJVJ53gJD2uSl26xNnSFn4Ljox
+uMnTiOVfTtIZPUOO15L/zzi24VuKUx3OrLR2L9j3QGPV7mnzRX2gYsFhw3XtsntN
+rCEnME5ZRmqTF8rIOS0Bc2Vb6UGbERecyMhK76F2YC2uk/8M1TMTn08Tzt2G8fz4
+NVQVqFvnhX76Nwn/i7gxSZ4Nbt600hItuO3Iw/G2QqBMl3nf/sOjn6H0bSyEd6Si
+BeEX/zHdmvO4esNSwhERt1Axin/M51qJzPeGmmGSTy+UtpjHeOBiS0N9PN7WmrQQ
+oUCcSyrcuNDUnv3xhHgbDlePaVRCaHvqoO91DweijHOZq1X1BwnSrzgDapADDC+P
+4uhDwjHpb62H5Y29TiyJS1HmnExUdsASgVOb7KD8LJzaGJVuHjgmQid4YAjff20y
+6NjAbx/rJnWfk/x7G/41kNxTowemP4NVCitOYoIlzmYwXSzg+RkbdbmdmFamgyd6
+0Y+NWZP8P3PXLrQsldiL98l+x/ydrHIEH9LMF/TtNGCbnkqXBP7dcg5XVFEGcE3v
+qhykguAzx/Q=
+-----END CERTIFICATE-----
+# Subject: C=IL, O=StartCom Ltd., OU=Secure Digital Certificate Signing, CN=StartCom Certification Authority
+# Issuer:  C=IL, O=StartCom Ltd., OU=Secure Digital Certificate Signing, CN=StartCom Certification Authority
+-----BEGIN CERTIFICATE-----
+MIIHhzCCBW+gAwIBAgIBLTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEW
+MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg
+Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM3WhcNMzYwOTE3MTk0NjM2WjB9
+MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi
+U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh
+cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA
+A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk
+pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf
+OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C
+Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT
+Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi
+HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM
+Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w
++2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+
+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3
+Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B
+26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID
+AQABo4ICEDCCAgwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD
+VR0OBBYEFE4L7xqkQFulF2mHMMo0aEPQQa7yMB8GA1UdIwQYMBaAFE4L7xqkQFul
+F2mHMMo0aEPQQa7yMIIBWgYDVR0gBIIBUTCCAU0wggFJBgsrBgEEAYG1NwEBATCC
+ATgwLgYIKwYBBQUHAgEWImh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5w
+ZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL2ludGVybWVk
+aWF0ZS5wZGYwgc8GCCsGAQUFBwICMIHCMCcWIFN0YXJ0IENvbW1lcmNpYWwgKFN0
+YXJ0Q29tKSBMdGQuMAMCAQEagZZMaW1pdGVkIExpYWJpbGl0eSwgcmVhZCB0aGUg
+c2VjdGlvbiAqTGVnYWwgTGltaXRhdGlvbnMqIG9mIHRoZSBTdGFydENvbSBDZXJ0
+aWZpY2F0aW9uIEF1dGhvcml0eSBQb2xpY3kgYXZhaWxhYmxlIGF0IGh0dHA6Ly93
+d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgG
+CWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1
+dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAgEAjo/n3JR5fPGFf59Jb2vKXfuM/gTF
+wWLRfUKKvFO3lANmMD+x5wqnUCBVJX92ehQN6wQOQOY+2IirByeDqXWmN3PH/UvS
+Ta0XQMhGvjt/UfzDtgUx3M2FIk5xt/JxXrAaxrqTi3iSSoX4eA+D/i+tLPfkpLst
+0OcNOrg+zvZ49q5HJMqjNTbOx8aHmNrs++myziebiMMEofYLWWivydsQD032ZGNc
+pRJvkrKTlMeIFw6Ttn5ii5B/q06f/ON1FE8qMt9bDeD1e5MNq6HPh+GlBEXoPBKl
+CcWw0bdT82AUuoVpaiF8H3VhFyAXe2w7QSlc4axa0c2Mm+tgHRns9+Ww2vl5GKVF
+P0lDV9LdJNUso/2RjSe15esUBppMeyG7Oq0wBhjA2MFrLH9ZXF2RsXAiV+uKa0hK
+1Q8p7MZAwC+ITGgBF3f0JBlPvfrhsiAhS90a2Cl9qrjeVOwhVYBsHvUwyKMQ5bLm
+KhQxw4UtjJixhlpPiVktucf3HMiKf8CdBUrmQk9io20ppB+Fq9vlgcitKj1MXVuE
+JnHEhV5xJMqlG2zYYdMa4FTbzrqpMrUi9nNBCV24F10OD5mQ1kfabwo6YigUZ4LZ
+8dCAWZvLMdibD4x3TrVoivJs9iQOLWxwxXPR3hTQcY+203sC9uO41Alua551hDnm
+fyWl8kgAwKQB2j8=
+-----END CERTIFICATE-----
diff --git a/cpan/libnet/t/external/pop3-ssl.t b/cpan/libnet/t/external/pop3-ssl.t
new file mode 100644 (file)
index 0000000..554a8db
--- /dev/null
@@ -0,0 +1,58 @@
+#!perl
+
+use 5.008001;
+
+use strict;
+use warnings;
+
+use Net::POP3;
+use Test::More;
+
+my $host = 'pop.gmx.net';
+my $debug = 0;
+
+plan skip_all => "no SSL support" if ! Net::POP3->can_ssl;
+{
+no warnings 'once';
+plan skip_all => "no verified SSL connection to $host:995 - $@" if ! eval {
+  IO::Socket::SSL->new(PeerAddr => "$host:995", Timeout => 10)
+    || die($IO::Socket::SSL::SSL_ERROR||$!);
+};
+}
+
+plan tests => 2;
+
+SKIP: {
+  diag( "connect inet to $host:110" );
+  skip "no inet connect to $host:110",1 
+    if ! IO::Socket::INET->new(PeerAddr => "$host:110", Timeout => 10);
+  my $pop3 = Net::POP3->new($host, Debug => $debug, Timeout => 10)
+    or skip "normal POP3 failed: $@",1;
+  skip "no STARTTLS support",1 if $pop3->message !~/STARTTLS/;
+
+  if (!$pop3->starttls) {
+    fail("starttls failed: ".$pop3->code." $@")
+  } else {
+    # we now should have access to SSL stuff
+    my $cipher = eval { $pop3->get_cipher };
+    if (!$cipher) {
+      fail("after starttls: not an SSL object");
+    } elsif ( $pop3->quit ) {
+      pass("starttls + quit ok, cipher=$cipher");
+    } else {
+      fail("quit after starttls failed: ".$pop3->code);
+    }
+  }
+}
+
+
+my $pop3 = Net::POP3->new($host, SSL => 1, Timeout => 10, Debug => $debug);
+# we now should have access to SSL stuff
+my $cipher = eval { $pop3->get_cipher };
+if (!$cipher) {
+  fail("after ssl connect: not an SSL object");
+} elsif ( $pop3->quit ) {
+  pass("ssl connect ok, cipher=$cipher");
+} else {
+  fail("quit after direct ssl failed: ".$pop3->code);
+}
diff --git a/cpan/libnet/t/external/smtp-ssl.t b/cpan/libnet/t/external/smtp-ssl.t
new file mode 100644 (file)
index 0000000..ccacbae
--- /dev/null
@@ -0,0 +1,57 @@
+#!perl
+
+use 5.008001;
+
+use strict;
+use warnings;
+
+use Net::SMTP;
+use Test::More;
+
+my $host = 'mail.gmx.net';
+my $debug = 0;
+
+plan skip_all => "no SSL support" if ! Net::SMTP->can_ssl;
+{
+no warnings 'once';
+plan skip_all => "no verified SSL connection to $host:465 - $@" if ! eval {
+  IO::Socket::SSL->new("$host:465")
+    || die($IO::Socket::SSL::SSL_ERROR||$!);
+};
+}
+
+plan tests => 2;
+
+SKIP: {
+  diag( "connect inet to $host:25" );
+  skip "no inet connect to $host:25",1 if ! IO::Socket::INET->new("$host:25");
+  my $smtp = Net::SMTP->new($host, Debug => $debug)
+    or skip "normal SMTP failed: $@",1;
+  skip "no STARTTLS support",1 if $smtp->message !~/STARTTLS/;
+
+  if (!$smtp->starttls) {
+    fail("starttls failed: ".$smtp->code." $@")
+  } else {
+    # we now should have access to SSL stuff
+    my $cipher = eval { $smtp->get_cipher };
+    if (!$cipher) {
+      fail("after starttls: not an SSL object");
+    } elsif ( $smtp->quit ) {
+      pass("starttls + quit ok, cipher=$cipher");
+    } else {
+      fail("quit after starttls failed: ".$smtp->code);
+    }
+  }
+}
+
+
+my $smtp = Net::SMTP->new($host, SSL => 1, Debug => $debug);
+# we now should have access to SSL stuff
+my $cipher = eval { $smtp->get_cipher };
+if (!$cipher) {
+  fail("after ssl connect: not an SSL object");
+} elsif ( $smtp->quit ) {
+  pass("ssl connect ok, cipher=$cipher");
+} else {
+  fail("quit after direct ssl failed: ".$smtp->code);
+}
index 0c1b0e3..288cdbc 100644 (file)
@@ -1,14 +1,15 @@
-#!./perl -w
+#!perl
+
+use 5.008001;
+
+use strict;
+use warnings;
 
 BEGIN {
-    unless (-d 'blib') {
-        chdir 't' if -d 't';
-        @INC = '../lib';
-    }
-    if (!eval "require Socket") {
+    if (!eval { require Socket; 1 }) {
         print "1..0 # Skip: no Socket module\n"; exit 0;
     }
-    if (ord('A') == 193 && !eval "require Convert::EBCDIC") {
+    if (ord('A') == 193 && !eval { require Convert::EBCDIC; 1 }) {
         print "1..0 # Skip: EBCDIC but no Convert::EBCDIC\n"; exit 0;
     }
 }
@@ -29,7 +30,7 @@ unless($NetConfig{test_hosts}) {
 my $t = 1;
 print "1..7\n";
 
-$ftp = Net::FTP->new($NetConfig{ftp_testhost})
+my $ftp = Net::FTP->new($NetConfig{ftp_testhost})
         or (print("not ok 1\n"), exit);
 
 printf "ok %d\n",$t++;
@@ -49,12 +50,14 @@ $ftp->cwd('/pub') or do {
   print "not ";
 };
 
+my $data;
 if ($data = $ftp->stor('libnet.tst')) {
   my $text = "abc\ndef\nqwe\n";
   printf "ok %d\n",$t++;
   $data->write($text,length $text);
   $data->close;
   $data = $ftp->retr('libnet.tst');
+  my $buf;
   $data->read($buf,length $text);
   $data->close;
   print "not " unless $text eq $buf;
index f486bb4..25f1cda 100644 (file)
@@ -1,14 +1,15 @@
-#!./perl -w
+#!perl
+
+use 5.008001;
+
+use strict;
+use warnings;
 
 BEGIN {
-    unless (-d 'blib') {
-        chdir 't' if -d 't';
-        @INC = '../lib';
-    }
-    if (!eval "require Socket") {
+    if (!eval { require Socket; 1 }) {
         print "1..0 # no Socket\n"; exit 0;
     }
-    if (ord('A') == 193 && !eval "require Convert::EBCDIC") {
+    if (ord('A') == 193 && !eval { require Convert::EBCDIC; 1 }) {
         print "1..0 # EBCDIC but no Convert::EBCDIC\n"; exit 0;
     }
 }
@@ -23,7 +24,7 @@ unless($NetConfig{test_hosts}) {
 
 print "1..5\n";
 
-$domain = domainname();
+my $domain = domainname();
 
 if(defined $domain && $domain ne "") {
  print "ok 1 - defined, non-empty domainname\n";
@@ -52,7 +53,7 @@ my @dummy = grep { defined hostname() and hostname() eq $_ } @domain;
   : print "not ok 3\n";
 
 my $name = hostname();
-my $domain = hostdomain();
+$domain = hostdomain();
 if(defined $domain && defined $name && $name ne "" && $domain ne "") {
     hostfqdn() eq $name . "." . $domain ? print "ok 4\n" : print "not ok 4\n";
     domainname() eq $name . "." . $domain ? print "ok 5\n" : print "not ok 5\n";} else {
index 9337dd1..cc512ca 100644 (file)
@@ -1,3 +1,7 @@
+use 5.008001;
+
+use strict;
+use warnings;
 
 my $number = 0;
 sub ok {
index bb97244..1149bb8 100644 (file)
@@ -1,20 +1,19 @@
-#!./perl
+#!perl
+
+use 5.008001;
+
+use strict;
+use warnings;
 
 BEGIN {
-    if ($ENV{PERL_CORE}) {
-        chdir 't' if -d 't';
-        @INC = '../lib';
-    }
-    if (!eval "require Socket") {
+    if (!eval { require Socket; 1 }) {
         print "1..0 # no Socket\n"; exit 0;
     }
-    if (ord('A') == 193 && !eval "require Convert::EBCDIC") {
+    if (ord('A') == 193 && !eval { require Convert::EBCDIC; 1 }) {
         print "1..0 # EBCDIC but no Convert::EBCDIC\n"; exit 0;
     }
 }
 
-use strict;
-
 use Cwd;
 print "1..20\n";
 
@@ -48,7 +47,7 @@ $Net::Netrc::TESTING=$Net::Netrc::TESTING=1;
 
 SKIP: {
         skip('incompatible stat() handling for OS', 4), next SKIP 
-                if ($^O =~ /os2|win32|macos|cygwin/i or $] < 5.005);
+                if $^O =~ /os2|win32|macos|cygwin/i;
 
         my $warn;
         local $SIG{__WARN__} = sub {
@@ -56,8 +55,8 @@ SKIP: {
         };
 
         # add write access for group/other
-        $stat[2] = 077;
-        ok( !defined(Net::Netrc::_readrc()),
+        $stat[2] = 077; ## no critic (ValuesAndExpressions::ProhibitLeadingZeros)
+        ok( !defined(Net::Netrc->_readrc()),
                 '_readrc() should not read world-writable file' );
         ok( scalar($warn =~ /^Bad permissions:/),
                 '... and should warn about it' );
@@ -66,7 +65,7 @@ SKIP: {
         $stat[2] = 0;
 
         if ($<) { 
-          ok( !defined(Net::Netrc::_readrc()), 
+          ok( !defined(Net::Netrc->_readrc()),
               '_readrc() should not read file owned by someone else' ); 
           ok( scalar($warn =~ /^Not owner:/),
                 '... and should warn about it' ); 
@@ -93,7 +92,7 @@ macdef
 LINES
 
 # having set several lines and the uid, this should succeed
-is( Net::Netrc::_readrc(), 1, '_readrc() should succeed now' );
+is( Net::Netrc->_readrc(), 1, '_readrc() should succeed now' );
 
 # on 'foo', the login is 'nigol'
 is( Net::Netrc->lookup('foo')->{login}, 'nigol', 
index 643cfc8..303aac4 100644 (file)
@@ -1,14 +1,15 @@
-#!./perl -w
+#!perl
+
+use 5.008001;
+
+use strict;
+use warnings;
 
 BEGIN {
-    unless (-d 'blib') {
-        chdir 't' if -d 't';
-        @INC = '../lib';
-    }
-    if (!eval "require Socket") {
+    if (!eval { require Socket; 1 }) {
         print "1..0 # no Socket\n"; exit 0;
     }
-    if (ord('A') == 193 && !eval "require Convert::EBCDIC") {
+    if (ord('A') == 193 && !eval { require Convert::EBCDIC; 1 }) {
         print "1..0 # EBCDIC but no Convert::EBCDIC\n"; exit 0;
     }
 }
@@ -26,13 +27,13 @@ print "1..4\n";
 
 my $i = 1;
 
-$nntp = Net::NNTP->new(Debug => 0)
+my $nntp = Net::NNTP->new(Debug => 0)
         or (print("not ok 1\n"), exit);
 
 print "ok 1\n";
 
-my $grp;
-foreach $grp (qw(test alt.test control news.announce.newusers)) {
+my @grp;
+foreach my $grp (qw(test alt.test control news.announce.newusers)) {
     @grp = $nntp->group($grp);
     last if @grp;
 }
diff --git a/cpan/libnet/t/nntp_ipv6.t b/cpan/libnet/t/nntp_ipv6.t
new file mode 100644 (file)
index 0000000..fbb1458
--- /dev/null
@@ -0,0 +1,66 @@
+#!perl
+
+use 5.008001;
+
+use strict;
+use warnings;
+
+use Config;
+use File::Temp 'tempfile';
+use Net::NNTP;
+use Test::More;
+
+my $debug = 0; # Net::NNTP->new( Debug => .. )
+
+my $inet6class = Net::NNTP->can_inet6;
+plan skip_all => "no IPv6 support found in Net::NNTP" if ! $inet6class;
+
+plan skip_all => "fork not supported on this platform"
+  unless $Config::Config{d_fork} || $Config::Config{d_pseudofork} ||
+    (($^O eq 'MSWin32' || $^O eq 'NetWare') and
+     $Config::Config{useithreads} and
+     $Config::Config{ccflags} =~ /-DPERL_IMPLICIT_SYS/);
+
+my $srv = $inet6class->new(
+  LocalAddr => '::1',
+  Listen => 10
+);
+plan skip_all => "cannot create listener on ::1: $!" if ! $srv;
+my $host = $srv->sockhost;
+my $port = $srv->sockport;
+diag("server on $host port $port");
+
+plan tests => 1;
+
+defined( my $pid = fork()) or die "fork failed: $!";
+exit(nntp_server()) if ! $pid;
+
+my $cl = Net::NNTP->new(Host => $host, Port => $port,, Debug => $debug);
+diag("created Net::NNTP object");
+if (!$cl) {
+  fail("IPv6 NNTP connect failed");
+} else {
+  $cl->quit;
+  pass("IPv6 success");
+}
+wait;
+
+sub nntp_server {
+  my $ssl = shift;
+  my $cl = $srv->accept or die "accept failed: $!";
+  print $cl "200 nntp.example.com\r\n";
+  while (<$cl>) {
+    my ($cmd,$arg) = m{^(\S+)(?: +(.*))?\r\n} or die $_;
+    $cmd = uc($cmd);
+    if ($cmd eq 'QUIT' ) {
+      print $cl "205 bye\r\n";
+      last;
+    } elsif ( $cmd eq 'MODE' ) {
+      print $cl "201 Posting denied\r\n";
+    } else {
+      diag("received unknown command: $cmd");
+      print "500 unknown cmd\r\n";
+    }
+  }
+  diag("NNTP dialog done");
+}
diff --git a/cpan/libnet/t/nntp_ssl.t b/cpan/libnet/t/nntp_ssl.t
new file mode 100644 (file)
index 0000000..55cdc16
--- /dev/null
@@ -0,0 +1,131 @@
+#!perl
+
+use 5.008001;
+
+use strict;
+use warnings;
+
+use Config;
+use File::Temp 'tempfile';
+use Net::NNTP;
+use Test::More;
+
+my $debug = 0; # Net::NNTP Debug => ..
+
+my $parent = 0;
+
+plan skip_all => "no SSL support found in Net::NNTP" if ! Net::NNTP->can_ssl;
+
+plan skip_all => "fork not supported on this platform"
+  unless $Config::Config{d_fork} || $Config::Config{d_pseudofork} ||
+    (($^O eq 'MSWin32' || $^O eq 'NetWare') and
+     $Config::Config{useithreads} and
+     $Config::Config{ccflags} =~ /-DPERL_IMPLICIT_SYS/);
+
+plan skip_all => "incomplete or version of IO::Socket::SSL"
+  if ! eval { require IO::Socket::SSL::Utils };
+
+my $srv = IO::Socket::INET->new(
+  LocalAddr => '127.0.0.1',
+  Listen => 10
+);
+plan skip_all => "cannot create listener on localhost: $!" if ! $srv;
+my $host = $srv->sockhost;
+my $port = $srv->sockport;
+
+plan tests => 2;
+
+my ($ca,$key) = IO::Socket::SSL::Utils::CERT_create( CA => 1 );
+my ($fh,$cafile) = tempfile();
+print $fh IO::Socket::SSL::Utils::PEM_cert2string($ca);
+close($fh);
+
+$parent = $$;
+END { unlink($cafile) if $$ == $parent }
+
+my ($cert) = IO::Socket::SSL::Utils::CERT_create(
+  subject => { CN => 'nntp.example.com' },
+  issuer_cert => $ca, issuer_key => $key,
+  key => $key
+);
+
+test(1); # direct ssl
+test(0); # starttls
+
+
+sub test {
+  my $ssl = shift;
+  defined( my $pid = fork()) or die "fork failed: $!";
+  exit(nntp_server($ssl)) if ! $pid;
+  nntp_client($ssl);
+  wait;
+}
+
+
+sub nntp_client {
+  my $ssl = shift;
+  my %sslopt = (
+    SSL_verifycn_name => 'nntp.example.com',
+    SSL_ca_file => $cafile
+  );
+  $sslopt{SSL} = 1 if $ssl;
+  my $cl = Net::NNTP->new(
+    Host => $host,
+    Port => $port,
+    Debug => $debug,
+    %sslopt,
+  );
+  diag("created Net::NNTP object");
+  if (!$cl) {
+    fail( ($ssl ? "SSL ":"" )."NNTP connect failed");
+  } elsif ($ssl) {
+    $cl->quit;
+    pass("SSL NNTP connect success");
+  } elsif ( ! $cl->starttls ) {
+    no warnings 'once';
+    fail("starttls failed: $IO::Socket::SSL::SSL_ERROR");
+  } else {
+    $cl->quit;
+    pass("starttls success");
+  }
+}
+
+sub nntp_server {
+  my $ssl = shift;
+  my $cl = $srv->accept or die "accept failed: $!";
+  my %sslargs = (
+    SSL_server => 1,
+    SSL_cert => $cert,
+    SSL_key => $key,
+  );
+  if ( $ssl ) {
+    if ( ! IO::Socket::SSL->start_SSL($cl, %sslargs)) {
+      diag("initial ssl handshake with client failed");
+      return;
+    }
+  }
+
+  print $cl "200 nntp.example.com\r\n";
+  while (<$cl>) {
+    my ($cmd,$arg) = m{^(\S+)(?: +(.*))?\r\n} or die $_;
+    $cmd = uc($cmd);
+    if ($cmd eq 'QUIT' ) {
+      print $cl "205 bye\r\n";
+      last;
+    } elsif ( $cmd eq 'MODE' ) {
+      print $cl "201 Posting denied\r\n";
+    } elsif ( ! $ssl and $cmd eq 'STARTTLS' ) {
+      print $cl "382 Continue with TLS negotiation\r\n";
+      if ( ! IO::Socket::SSL->start_SSL($cl, %sslargs)) {
+       diag("initial ssl handshake with client failed");
+       return;
+      }
+      $ssl = 1;
+    } else {
+      diag("received unknown command: $cmd");
+      print "500 unknown cmd\r\n";
+    }
+  }
+
+  diag("NNTP dialog done");
+}
diff --git a/cpan/libnet/t/pop3_ipv6.t b/cpan/libnet/t/pop3_ipv6.t
new file mode 100644 (file)
index 0000000..004a642
--- /dev/null
@@ -0,0 +1,66 @@
+#!perl
+
+use 5.008001;
+
+use strict;
+use warnings;
+
+use Config;
+use File::Temp 'tempfile';
+use Net::POP3;
+use Test::More;
+
+my $debug = 0; # Net::POP3->new( Debug => .. )
+
+my $inet6class = Net::POP3->can_inet6;
+plan skip_all => "no IPv6 support found in Net::POP3" if ! $inet6class;
+
+plan skip_all => "fork not supported on this platform"
+  unless $Config::Config{d_fork} || $Config::Config{d_pseudofork} ||
+    (($^O eq 'MSWin32' || $^O eq 'NetWare') and
+     $Config::Config{useithreads} and
+     $Config::Config{ccflags} =~ /-DPERL_IMPLICIT_SYS/);
+
+my $srv = $inet6class->new(
+  LocalAddr => '::1',
+  Listen => 10
+);
+plan skip_all => "cannot create listener on ::1: $!" if ! $srv;
+my $saddr = "[".$srv->sockhost."]".':'.$srv->sockport;
+diag("server on $saddr");
+
+plan tests => 1;
+
+defined( my $pid = fork()) or die "fork failed: $!";
+exit(pop3_server()) if ! $pid;
+
+my $cl = Net::POP3->new($saddr, Debug => $debug);
+diag("created Net::POP3 object");
+if (!$cl) {
+  fail("IPv6 POP3 connect failed");
+} else {
+  $cl->quit;
+  pass("IPv6 success");
+}
+wait;
+
+sub pop3_server {
+  my $cl = $srv->accept or die "accept failed: $!";
+  print $cl "+OK localhost ready\r\n";
+  while (<$cl>) {
+    my ($cmd,$arg) = m{^(\S+)(?: +(.*))?\r\n} or die $_;
+    $cmd = uc($cmd);
+    if ($cmd eq 'QUIT' ) {
+      print $cl "+OK bye\r\n";
+      last;
+    } elsif ( $cmd eq 'CAPA' ) {
+      print $cl "+OK\r\n".
+       ".\r\n";
+    } else {
+      diag("received unknown command: $cmd");
+      print "-ERR unknown cmd\r\n";
+    }
+  }
+
+  diag("POP3 dialog done");
+}
diff --git a/cpan/libnet/t/pop3_ssl.t b/cpan/libnet/t/pop3_ssl.t
new file mode 100644 (file)
index 0000000..2d02331
--- /dev/null
@@ -0,0 +1,131 @@
+#!perl
+
+use 5.008001;
+
+use strict;
+use warnings;
+
+use Config;
+use File::Temp 'tempfile';
+use Net::POP3;
+use Test::More;
+
+my $debug = 0; # Net::POP3 Debug => ..
+
+my $parent = 0;
+
+plan skip_all => "no SSL support found in Net::POP3" if ! Net::POP3->can_ssl;
+
+plan skip_all => "fork not supported on this platform"
+  unless $Config::Config{d_fork} || $Config::Config{d_pseudofork} ||
+    (($^O eq 'MSWin32' || $^O eq 'NetWare') and
+     $Config::Config{useithreads} and
+     $Config::Config{ccflags} =~ /-DPERL_IMPLICIT_SYS/);
+
+plan skip_all => "incomplete or to old version of IO::Socket::SSL" if ! eval {
+  require IO::Socket::SSL
+    && IO::Socket::SSL->VERSION(1.999)
+    && require IO::Socket::SSL::Utils
+    && defined &IO::Socket::SSL::Utils::CERT_create;
+};
+
+my $srv = IO::Socket::INET->new(
+  LocalAddr => '127.0.0.1',
+  Listen => 10
+);
+plan skip_all => "cannot create listener on localhost: $!" if ! $srv;
+my $saddr = $srv->sockhost.':'.$srv->sockport;
+
+plan tests => 2;
+
+my ($ca,$key) = IO::Socket::SSL::Utils::CERT_create( CA => 1 );
+my ($fh,$cafile) = tempfile();
+print $fh IO::Socket::SSL::Utils::PEM_cert2string($ca);
+close($fh);
+
+$parent = $$;
+END { unlink($cafile) if $$ == $parent }
+
+my ($cert) = IO::Socket::SSL::Utils::CERT_create(
+  subject => { CN => 'pop3.example.com' },
+  issuer_cert => $ca, issuer_key => $key,
+  key => $key
+);
+
+test(1); # direct ssl
+test(0); # starttls
+
+
+sub test {
+  my $ssl = shift;
+  defined( my $pid = fork()) or die "fork failed: $!";
+  exit(pop3_server($ssl)) if ! $pid;
+  pop3_client($ssl);
+  wait;
+}
+
+
+sub pop3_client {
+  my $ssl = shift;
+  my %sslopt = (
+    SSL_verifycn_name => 'pop3.example.com',
+    SSL_ca_file => $cafile
+  );
+  $sslopt{SSL} = 1 if $ssl;
+  my $cl = Net::POP3->new($saddr, %sslopt, Debug => $debug);
+  diag("created Net::POP3 object");
+  if (!$cl) {
+    fail( ($ssl ? "SSL ":"" )."POP3 connect failed");
+  } elsif ($ssl) {
+    $cl->quit;
+    pass("SSL POP3 connect success");
+  } elsif ( ! $cl->starttls ) {
+    no warnings 'once';
+    fail("starttls failed: $IO::Socket::SSL::SSL_ERROR");
+  } else {
+    $cl->quit;
+    pass("starttls success");
+  }
+}
+
+sub pop3_server {
+  my $ssl = shift;
+  my $cl = $srv->accept or die "accept failed: $!";
+  my %sslargs = (
+    SSL_server => 1,
+    SSL_cert => $cert,
+    SSL_key => $key,
+  );
+  if ( $ssl ) {
+    if ( ! IO::Socket::SSL->start_SSL($cl, %sslargs)) {
+      diag("initial ssl handshake with client failed");
+      return;
+    }
+  }
+
+  print $cl "+OK localhost ready\r\n";
+  while (<$cl>) {
+    my ($cmd,$arg) = m{^(\S+)(?: +(.*))?\r\n} or die $_;
+    $cmd = uc($cmd);
+    if ($cmd eq 'QUIT' ) {
+      print $cl "+OK bye\r\n";
+      last;
+    } elsif ( $cmd eq 'CAPA' ) {
+      print $cl "+OK\r\n".
+       ( $ssl ? "" : "STLS\r\n" ).
+       ".\r\n";
+    } elsif ( ! $ssl and $cmd eq 'STLS' ) {
+      print $cl "+OK starting ssl\r\n";
+      if ( ! IO::Socket::SSL->start_SSL($cl, %sslargs)) {
+       diag("initial ssl handshake with client failed");
+       return;
+      }
+      $ssl = 1;
+    } else {
+      diag("received unknown command: $cmd");
+      print "-ERR unknown cmd\r\n";
+    }
+  }
+
+  diag("POP3 dialog done");
+}
index 973ed41..a48951a 100644 (file)
@@ -1,14 +1,15 @@
-#!./perl -w
+#!perl
+
+use 5.008001;
+
+use strict;
+use warnings;
 
 BEGIN {
-    unless (-d 'blib') {
-        chdir 't' if -d 't';
-        @INC = '../lib';
-    }
-    if (!eval "require Socket") {
+    if (!eval { require Socket; 1 }) {
         print "1..0 # no Socket\n"; exit 0;
     }
-    if (ord('A') == 193 && !eval "require Convert::EBCDIC") {
+    if (ord('A') == 193 && !eval { require Convert::EBCDIC; 1 }) {
         print "1..0 # EBCDIC but no Convert::EBCDIC\n"; exit 0;
     }
 }
index 6daef31..634390f 100644 (file)
@@ -1,14 +1,15 @@
-#!./perl -w
+#!perl
+
+use 5.008001;
+
+use strict;
+use warnings;
 
 BEGIN {
-    unless (-d 'blib') {
-        chdir 't' if -d 't';
-        @INC = '../lib';
-    }
-    if (!eval "require Socket") {
+    if (!eval { require Socket; 1 }) {
         print "1..0 # no Socket\n"; exit 0;
     }
-    if (ord('A') == 193 && !eval "require Convert::EBCDIC") {
+    if (ord('A') == 193 && eval { require Convert::EBCDIC; 1 }) {
         print "1..0 # EBCDIC but no Convert::EBCDIC\n"; exit 0;
     }
 }
@@ -25,7 +26,7 @@ print "1..3\n";
 
 my $i = 1;
 
-$smtp = Net::SMTP->new(Debug => 0)
+my $smtp = Net::SMTP->new(Debug => 0)
         or (print("not ok 1\n"), exit);
 
 print "ok 1\n";
diff --git a/cpan/libnet/t/smtp_ipv6.t b/cpan/libnet/t/smtp_ipv6.t
new file mode 100644 (file)
index 0000000..78a14fe
--- /dev/null
@@ -0,0 +1,68 @@
+#!perl
+
+use 5.008001;
+
+use strict;
+use warnings;
+
+use Config;
+use File::Temp 'tempfile';
+use Net::SMTP;
+use Test::More;
+
+my $debug = 0; # Net::SMTP->new( Debug => .. )
+
+my $inet6class = Net::SMTP->can_inet6;
+plan skip_all => "no IPv6 support found in Net::SMTP" if ! $inet6class;
+
+plan skip_all => "fork not supported on this platform"
+  unless $Config::Config{d_fork} || $Config::Config{d_pseudofork} ||
+    (($^O eq 'MSWin32' || $^O eq 'NetWare') and
+     $Config::Config{useithreads} and
+     $Config::Config{ccflags} =~ /-DPERL_IMPLICIT_SYS/);
+
+my $srv = $inet6class->new(
+  LocalAddr => '::1',
+  Listen => 10
+);
+plan skip_all => "cannot create listener on ::1: $!" if ! $srv;
+my $saddr = "[".$srv->sockhost."]".':'.$srv->sockport;
+diag("server on $saddr");
+
+plan tests => 1;
+
+defined( my $pid = fork()) or die "fork failed: $!";
+exit(smtp_server()) if ! $pid;
+
+my $cl = Net::SMTP->new($saddr, Debug => $debug);
+diag("created Net::SMTP object");
+if (!$cl) {
+  fail("IPv6 SMTP connect failed");
+} else {
+  $cl->quit;
+  pass("IPv6 success");
+}
+wait;
+
+sub smtp_server {
+  my $cl = $srv->accept or die "accept failed: $!";
+  print $cl "220 welcome\r\n";
+  while (<$cl>) {
+    my ($cmd,$arg) = m{^(\S+)(?: +(.*))?\r\n} or die $_;
+    $cmd = uc($cmd);
+    if ($cmd eq 'QUIT' ) {
+      print $cl "250 bye\r\n";
+      last;
+    } elsif ( $cmd eq 'HELO' ) {
+      print $cl "250 localhost\r\n";
+    } elsif ( $cmd eq 'EHLO' ) {
+      print $cl "250-localhost\r\n".
+       "250 HELP\r\n";
+    } else {
+      diag("received unknown command: $cmd");
+      print "500 unknown cmd\r\n";
+    }
+  }
+
+  diag("SMTP dialog done");
+}
diff --git a/cpan/libnet/t/smtp_ssl.t b/cpan/libnet/t/smtp_ssl.t
new file mode 100644 (file)
index 0000000..3686eb6
--- /dev/null
@@ -0,0 +1,133 @@
+#!perl
+
+use 5.008001;
+
+use strict;
+use warnings;
+
+use Config;
+use File::Temp 'tempfile';
+use Net::SMTP;
+use Test::More;
+
+my $debug = 0; # Net::SMTP Debug => ..
+
+my $parent = 0;
+
+plan skip_all => "no SSL support found in Net::SMTP" if ! Net::SMTP->can_ssl;
+
+plan skip_all => "fork not supported on this platform"
+  unless $Config::Config{d_fork} || $Config::Config{d_pseudofork} ||
+    (($^O eq 'MSWin32' || $^O eq 'NetWare') and
+     $Config::Config{useithreads} and
+     $Config::Config{ccflags} =~ /-DPERL_IMPLICIT_SYS/);
+
+plan skip_all => "incomplete or to old version of IO::Socket::SSL" if ! eval {
+  require IO::Socket::SSL
+    && IO::Socket::SSL->VERSION(1.999)
+    && require IO::Socket::SSL::Utils
+    && defined &IO::Socket::SSL::Utils::CERT_create;
+};
+
+my $srv = IO::Socket::INET->new(
+  LocalAddr => '127.0.0.1',
+  Listen => 10
+);
+plan skip_all => "cannot create listener on localhost: $!" if ! $srv;
+my $saddr = $srv->sockhost.':'.$srv->sockport;
+
+plan tests => 2;
+
+my ($ca,$key) = IO::Socket::SSL::Utils::CERT_create( CA => 1 );
+my ($fh,$cafile) = tempfile();
+print $fh IO::Socket::SSL::Utils::PEM_cert2string($ca);
+close($fh);
+
+$parent = $$;
+END { unlink($cafile) if $$ == $parent }
+
+my ($cert) = IO::Socket::SSL::Utils::CERT_create(
+  subject => { CN => 'smtp.example.com' },
+  issuer_cert => $ca, issuer_key => $key,
+  key => $key
+);
+
+test(1); # direct ssl
+test(0); # starttls
+
+
+sub test {
+  my $ssl = shift;
+  defined( my $pid = fork()) or die "fork failed: $!";
+  exit(smtp_server($ssl)) if ! $pid;
+  smtp_client($ssl);
+  wait;
+}
+
+
+sub smtp_client {
+  my $ssl = shift;
+  my %sslopt = (
+    SSL_verifycn_name => 'smtp.example.com',
+    SSL_ca_file => $cafile
+  );
+  $sslopt{SSL} = 1 if $ssl;
+  my $cl = Net::SMTP->new($saddr, %sslopt, Debug => $debug);
+  diag("created Net::SMTP object");
+  if (!$cl) {
+    fail( ($ssl ? "SSL ":"" )."SMTP connect failed");
+  } elsif ($ssl) {
+    $cl->quit;
+    pass("SSL SMTP connect success");
+  } elsif ( ! $cl->starttls ) {
+    no warnings 'once';
+    fail("starttls failed: $IO::Socket::SSL::SSL_ERROR");
+  } else {
+    $cl->quit;
+    pass("starttls success");
+  }
+}
+
+sub smtp_server {
+  my $ssl = shift;
+  my $cl = $srv->accept or die "accept failed: $!";
+  my %sslargs = (
+    SSL_server => 1,
+    SSL_cert => $cert,
+    SSL_key => $key,
+  );
+  if ( $ssl ) {
+    if ( ! IO::Socket::SSL->start_SSL($cl, %sslargs)) {
+      diag("initial ssl handshake with client failed");
+      return;
+    }
+  }
+
+  print $cl "220 welcome\r\n";
+  while (<$cl>) {
+    my ($cmd,$arg) = m{^(\S+)(?: +(.*))?\r\n} or die $_;
+    $cmd = uc($cmd);
+    if ($cmd eq 'QUIT' ) {
+      print $cl "250 bye\r\n";
+      last;
+    } elsif ( $cmd eq 'HELO' ) {
+      print $cl "250 localhost\r\n";
+    } elsif ( $cmd eq 'EHLO' ) {
+      print $cl "250-localhost\r\n".
+       ( $ssl ? "" : "250-STARTTLS\r\n" ).
+       "250 HELP\r\n";
+    } elsif ( ! $ssl and $cmd eq 'STARTTLS' ) {
+      print $cl "250 starting ssl\r\n";
+      if ( ! IO::Socket::SSL->start_SSL($cl, %sslargs)) {
+       diag("initial ssl handshake with client failed");
+       return;
+      }
+      $ssl = 1;
+    } else {
+      diag("received unknown command: $cmd");
+      print "500 unknown cmd\r\n";
+    }
+  }
+
+  diag("SMTP dialog done");
+}
index 224b640..43b0e0e 100644 (file)
@@ -1,14 +1,15 @@
-#!./perl -w
+#!perl
+
+use 5.008001;
+
+use strict;
+use warnings;
 
 BEGIN {
-    if ($ENV{PERL_CORE}) {
-        chdir 't' if -d 't';
-        @INC = '../lib';
-    }
-    if (!eval "require Socket") {
+    if (!eval { require Socket; 1 }) {
         print "1..0 # no Socket\n"; exit 0;
     }
-    if (ord('A') == 193 && !eval "require Convert::EBCDIC") {
+    if (ord('A') == 193 && !eval { require Convert::EBCDIC; 1 }) {
         print "1..0 # EBCDIC but no Convert::EBCDIC\n"; exit 0;
     }
     $INC{'IO/Socket.pm'} = 1;