The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package Apache2::DocServer;
use strict;
use warnings;
use DBI;
use File::Spec::Functions;
use CPAN::Search::Lite::Query;
use mod_perl 1.999022;     # sanity check for a recent version
use Apache2::Const -compile => qw(OK REDIRECT SERVER_ERROR 
                                 TAKE1 RSRC_CONF ACCESS_CONF);
use Apache2::Module ();
use Apache2::RequestRec ();
our $VERSION = 0.77;

my @directives = (
                  {name      => 'DocServer_db',
                   errmsg    => 'database name',
                   args_how  => Apache2::Const::TAKE1,
                   req_override => Apache2::Const::RSRC_CONF | Apache2::Const::ACCESS_CONF,
                  },
                  {name      => 'DocServer_user',
                   errmsg    => 'user to log in as',
                   args_how  => Apache2::Const::TAKE1,
                   req_override => Apache2::Const::RSRC_CONF | Apache2::Const::ACCESS_CONF,
                  },
                  {name      => 'DocServer_pod_root',
                   errmsg    => 'root directory of pod files',
                   args_how  => Apache2::Const::TAKE1,
                   req_override => Apache2::Const::RSRC_CONF | Apache2::Const::ACCESS_CONF,
                  },
                  {name      => 'DocServer_passwd',
                   errmsg    => 'password for user',
                   args_how  => Apache2::Const::TAKE1,
                   req_override => Apache2::Const::RSRC_CONF | Apache2::Const::ACCESS_CONF,
                  },
                  {name      => 'DocServer_max_results',
                   errmsg    => 'maximum number of results',
                   args_how  => Apache2::Const::TAKE1,
                   req_override => Apache2::Const::RSRC_CONF | Apache2::Const::ACCESS_CONF,
                  },
                 );
Apache2::Module::add(__PACKAGE__, \@directives);

my ($query, $cfg, $r, $max_results);

sub get_doc {
  my ($class, $mod) = @_;
  $mod =~ s!(\.pm|\.pod)$!!;
  return unless ($mod =~ m!^[\w:\.\-]+$!);
  $r = Apache->request;
  $cfg = Apache2::Module::get_config(__PACKAGE__, 
                                    $r->server,
                                    $r->per_dir_config) || { };

  $max_results ||= $cfg->{max_results} || 200;
  $query ||= CPAN::Search::Lite::Query->new(db => $cfg->{db},
                                            user => $cfg->{user},
                                            passwd => $cfg->{passwd},
                                            max_results => $max_results);
  my $fields = [qw(doc dist_name)];
  $query->query(mode => 'module', name => $mod, fields => $fields);
  my $results = $query->{results};
  return unless $results;
  my ($doc, $dist_name) = ($results->{doc}, $results->{dist_name});
  return unless ($doc and $dist_name);
    
  my $base = catfile $cfg->{pod_root}, $dist_name, (split '::', $mod);
  my $file;
  for my $ext ('.pm', '.pod') {
    my $trial = $base . $ext;
    if (-f $trial) {
      $file = $trial;
      last;
    }
  }
  return unless $file;
  open (my $fh, $file) or return;
  my @lines = <$fh>;
  close $fh;
  return \@lines;
}

sub get_readme {
  my ($class, $dist) = @_;
  return unless ($dist =~ m!^[\w:\.\-]+$!);
  $r ||= Apache->request;
  $cfg ||= Apache2::Module->get_config(__PACKAGE__, 
                                      $r->server,
                                      $r->per_dir_config) || { };
  
  $max_results ||= $cfg->{max_results} || 200;
  $query ||= CPAN::Search::Lite::Query->new(db => $cfg->{db},
                                            user => $cfg->{user},
                                            passwd => $cfg->{passwd},
                                            max_results => $max_results);
  my $fields = [qw(readme)];
  $query->query(mode => 'dist', name => $dist, fields => $fields);
  my $results = $query->{results};
  return unless ($results and $results->{readme});
  
  my $file = catfile $cfg->{pod_root}, $dist, 'README';
  return unless (-f $file);
  open (my $fh, $file) or return;
  my @lines = <$fh>;
  close $fh;
  return \@lines;
}

sub DocServer_db {
  my ($cfg, $parms, $db) = @_;
  $cfg->{ db } = $db;
}

sub DocServer_user {
  my ($cfg, $parms, $user) = @_;
  $cfg->{ user } = $user;
}

sub DocServer_passwd {
  my ($cfg, $parms, $passwd) = @_;
  $cfg->{ passwd } = $passwd;
}

sub DocServer_max_results {
  my ($cfg, $parms, $max_results) = @_;
  $cfg->{ max_results } = $max_results;
}

sub DocServer_pod_root {
  my ($cfg, $parms, $pod_root) = @_;
  $cfg->{ pod_root } = $pod_root;
}


1;

__END__

=head1 NAME

Apache2::DocServer - mod_perl 2 soap server for soap-enhanced perldoc

=head1 DESCRIPTION

This module provides a mod_perl 2 soap-based service to
C<Pod::Perldocs>. The necessary Apache2 directives are

 PerlLoadModule Apache2::DocServer

 DocServer_db database_name
 DocServer_user user_name
 DocServer_passwd password_for_above_user
 DocServer_pod_root "/Path/to/pod/root"

 <Location /docserver>
   SetHandler perl-script
   PerlResponseHandler Apache2::SOAP
   PerlSetVar dispatch_to "D:/Perl/site/lib/Apache2, Apache2::DocServer"
 </Location>

where C<Apache::SOAP> is included in version 0.69 and above of
the C<SOAP::Lite> distribution. See the C<perldocs> script in
this distribution for an example of it's use.

=head1 SEE ALSO

L<Pod::Perldocs>.

=cut