Apache-RSS

 view release on metacpan or  search on metacpan

lib/Apache/RSS.pm  view on Meta::CPAN

package Apache::RSS;
# $Id: RSS.pm,v 1.6 2002/05/30 14:08:03 ikechin Exp $

use strict;
use Apache::Constants qw(:common &OPT_INDEXES &DECLINE_CMD);
use Time::Piece;
use XML::RSS;
use DirHandle;
use URI;
use DynaLoader ();
use Apache::ModuleConfig;
use Apache::Util qw(escape_html);
use vars qw($VERSION);

$VERSION = '0.05';

if($ENV{MOD_PERL}) {
    no strict;
    @ISA = qw(DynaLoader);
    __PACKAGE__->bootstrap($VERSION);
}

sub handler($$){
    my($class, $r) = @_;
    my $cfg = Apache::ModuleConfig->get($r) || {};
    # check permission
    unless (-d $r->filename) {
	return DECLINED;
    }
    my %args = $r->args;
    unless ($args{index} && $args{index} eq 'rss') {
	return DECLINED;
    }
    if (!($r->allow_options & OPT_INDEXES)) {
	$r->log_reason("Options Indexes is off in this directory", $r->filename);
	return FORBIDDEN;
    }

    my $base   = base_uri($r);
    my @items  = open_dir($r, $cfg, $base);
    my $sorter = build_sorter(\%args);
    @items = sort { $sorter->($a, $b) } @items;

    my $rss = create_rss($r, $cfg, \@items, $base);
    # send content
    $r->send_http_header('text/xml');
    $r->print($rss->as_string);
    return OK;
}

sub base_uri {
    my $r = shift;
    my $base = URI->new($r->uri, "http");
    $base->host($r->hostname);
    $base->port($r->server->port) if $r->server->port != 80;
    $base->scheme('http');
    return $base;
}

sub open_dir {
    my($r, $cfg, $base) = @_;

    my $dir = $r->filename;
    my $d = DirHandle->new($dir);
    unless ($d) {
	$r->log_reason("Can't open directory", $dir);
	return FORBIDDEN;
    }

    my $regexp = $cfg->{'RSSEnableRegexp'};
    my @items = ();
    while (my $file = $d->read) {
	next if $file =~ /^\./;
	next if $regexp && $file !~ m/$regexp/;
	my $subr = $r->lookup_uri($file);
	next unless -f $subr->filename;
	push @items, Apache::RSS::Item->new({
	    content_type => $subr->content_type,
	    title => $cfg->{'RSSScanHTMLTitle'} ? (find_title($subr, $cfg) || $file) : $file,
	    name => $file,
	    link => URI->new_abs($file, $base),
	    filename => $subr->filename,
	    mtime => (stat $subr->finfo)[9]
	});
    }
    $d->close;
    return @items;
}

sub create_rss {
    my($r, $cfg, $items, $base) = @_;
    my $req_time = Time::Piece->new($r->request_time);
    my $channel_title = 
	$cfg->{'RSSChannelTitle'} || sprintf("Index Of %s", $r->uri);
    my $channel_description = 
	$cfg->{'RSSChannelDescription'} || sprintf("Index Of %s", $r->uri);
    my $copyright =
	$cfg->{'RSSCopyRight'} || sprintf("Copyright %d %s", $req_time->year, $r->hostname);
    my $language = $cfg->{'RSSLanguage'} || "en-us";
    my $encoding = $cfg->{'RSSEncoding'} || "UTF-8";

    my $rss = XML::RSS->new(version => '0.91', encoding => $encoding);
    $rss->channel(
	title => escape_html($channel_title),
	link => $base,
	description => escape_html($channel_description),
	webMaster => $r->server->server_admin,
	pubDate => $req_time->datetime,
	lastBuildDate => $req_time->datetime,
	copyright => escape_html($copyright),
	language => $language,
    );
    foreach my $item (@$items) {
	$rss->add_item(
	    link => $item->link,
	    title => escape_html($item->title),
	);
    }
    return $rss;
}

sub find_title {
    my($subr, $cfg) = @_;
    my $encoder = $cfg->{'RSSEncodeHandler'};
    if ($subr->content_type =~ m#^text/html#) {
	local $/ = undef;
	my $f = IO::File->new($subr->filename, "r") or return undef;
	my $html = <$f>;
	$html =~ m#<title>([^>]+)</title>#i;
	return undef unless $1;
	if ($encoder) {
	    my $enc = $encoder->new;
	    return $enc->encode($1);
	}
	else {
	    return $1;
	}
    }
    return undef;
}

my %SortBy = (
    'N' => 'title' ,
    'M' => 'mtime',
);

sub build_sorter {
    my $args = shift;

    # N=A by default
    my $sortby = (grep exists $args->{$_}, keys %SortBy)[0] || 'N';
    my $order  = $args->{$sortby} || 'A';
    my @target = $order eq 'A' ? qw($_[0] $_[1]) : qw($_[1] $_[0]);
    my $cmp    = $sortby eq 'N' ? 'cmp' : '<=>';

    return eval sprintf "sub { %s->%s %s %s->%s }",
	$target[0], $SortBy{$sortby}, $cmp, $target[1], $SortBy{$sortby};
}

##----------------------------------------------------------------
## Directives
##----------------------------------------------------------------
sub RSSEnableRegexp($$$){
    my($cfg, $params, $arg) = @_;
    $cfg->{RSSEnableRegexp} = eval "qr/$arg/";
    die $@ if $@;
}

sub RSSChannelTitle($$$) {
    my($cfg, $params, $arg) = @_;
    $cfg->{RSSChannelTitle} = $arg;
}

sub RSSChannelDescription($$$) {
    my($cfg, $params, $arg) = @_;
    $cfg->{RSSChannelDescription} = $arg;



( run in 0.799 second using v1.01-cache-2.11-cpan-e1769b4cff6 )