#!/usr/bin/perl #-----------------------------------------------------------------# # my_portal # pudge # See POD after __END__ # # Created: Chris Nandor (pudge@pobox.com) 09 Nov 1999 # Last Modified: Chris Nandor (pudge@pobox.com) 02 Jan 2000 # # $Log: my_portal.plx,v $ # Revision 1.1 2000/06/20 14:30:20 hoffman # Initial revision # #-----------------------------------------------------------------# use strict; use AnyDBM_File; use CGI ':all'; use CGI::Carp 'fatalsToBrowser'; use Data::Dumper; use Date::Parse; use Date::Format; use Fcntl; use File::Basename; use Getopt::Std; use LWP::Simple qw[mirror is_error]; use Symbol; use Time::Local; # require '/export/home/pudge/site_perl/XML/RSS.pm'; use XML::RSS; $ENV{PATH} = ''; #================== # set defaults #================== my %conf = ( prog => '/my_portal/', # $ENV{SCRIPT_NAME} admin => 'hoffman@dlhoffman.com', src => 'http://www.dlhoffman.com/my_portal/my_portal.plx', dir => '/data/httpd/html/my_portal', cookieDom => '.dlhoffman.com', cookieNam => 'myPortalName', cookieExp => '+1y', cookiePath => '/my_portal', defaults => { 31 => '1,1', 38 => '2,1', 1 => '3,1', 30 => '1,2', 29 => '2,2', 28 => '3,2', 35 => '1,3', 4 => '2,3', 37 => '3,3', 21 => '1,4', 36 => '2,4', 19 => '3,4', 16 => '1,5', 32 => '2,5', 11 => '3,5', 3 => '1,6', 6 => '2,6', 20 => '3,6', 14 => '1,7', 2 => '2,7', 33 => '3,7', 10 => '1,8', back => '#ffffff', fore => '#dddddd', btext => '#000000', ftext => '#000000', 'link' => '#000088', vlink => '#880000', showdesc => '', save_cookie => 'CHECKED', }, ); $conf{imgurl} = "img"; $conf{imgdir} = "$conf{dir}/img"; $conf{rdfdir} = "$conf{dir}/rdf"; $conf{rdff} = "$conf{dir}/rdfs"; $conf{userf} = "$conf{dir}/users"; unless ($ENV{SERVER_SOFTWARE}) { do_cl(); exit; } tie my %rdfs, 'AnyDBM_File', $conf{rdff}, O_RDONLY, 0444 or die $!; $conf{rdfs} = \%rdfs; #================== # do main #================== while (my $cgi = new CGI) { if ($cgi->param('dumpusers')) { tie my %users, 'AnyDBM_File', $conf{userf}, O_RDWR|O_CREAT, 0644 or die $!; print header('text/plain'); print Dumper \%users; untie %users; exit; } my($user) = $cgi->cookie(-name => $conf{cookieNam}); $user ||= ''; my $prefs = get_prefs($user); my($un, $pw) = ($cgi->param('un'), $cgi->param('pw')); if ($cgi->param('dologin') && $un && $pw) { my $nuser = join '|', crypt($pw, $un), $un; my $ok = userOK($un, $pw); $user = $ok ? $nuser : ''; $prefs = get_prefs($user, ($ok ? $prefs : undef)); print myhead($cgi, $user, $prefs, 1), ($ok ? '' : <

Incorrect password for user $un

EOT display_channels($prefs); } else { ($user, $prefs) = set_config($cgi, $user, $prefs) if $cgi->param('set'); if ($cgi->param('login')) { print myhead($cgi, $user, $prefs); print show_login($user, $prefs); } elsif ($cgi->param('config')) { print myhead($cgi, $user, $prefs); print show_config($user, $prefs); } else { print myhead($cgi, $user, $prefs, 1); print display_channels($prefs); } } print myfoot(); exit; } #================== # main displays #================== sub show_login { my($user, $prefs) = @_; return <

Enter username and password to log in or create new login.

Username: Password:

EOT } sub show_config { my($user, $prefs) = @_; my $return = <
EOT foreach my $i (sort {$conf{rdfs}->{$a} cmp $conf{rdfs}->{$b}} keys %{$conf{rdfs}}) { my($c, $l) = split m/\|/, $conf{rdfs}->{$i}; my($m, $r) = split m/,/, $prefs->{$i} if exists $prefs->{$i}; my $k = 'CHECKED' if exists $prefs->{$i}; $m ||= ''; $r ||= ''; $return .= < EOT } $return .= <
Channel Column Row
$c
 
{showdesc}> Show item descriptions
{save_cookie}> Save cookie
Background color
Foreground color
Text color
Link color
Visited link color
EOT return $return; } sub display_channels { my $prefs = shift; my(%channels, $channels); for my $rdf (sort { $a->[1] <=> $b->[1] || $a->[2] <=> $b->[2] || $a->[0] <=> $b->[0] } map { [$_, split /,/, $prefs->{$_}] } grep { /^\d+$/ } keys %$prefs) { my $rss = new XML::RSS; eval { $rss->parsefile("$conf{rdfdir}/$rdf->[0].rdf") }; next if $@; push @{$channels{$rdf->[1]}}, format_channel($rss, $prefs, $rdf->[0]); } $channels = qq[ \n]; for (grep { exists $channels{$_} } 1..3) { $channels .= join '', qq[ \n], join("\n
\n", @{$channels{$_}}), qq[ \n]; } $channels .= qq[ \n]; return $channels; } sub format_channel { my($rss, $prefs, $rdf) = @_; my($desc, $img, @items, $items, $input, $date); $img = $rss->{image}{url} && -e "$conf{imgurl}/$rdf.gif" ? qq'{image}{description}) { $img .= qq' ALT="$rss->{image}{description}"'; } elsif ($rss->{image}{title}) { $img .= qq' ALT="$rss->{image}{title}"'; } if ($rss->{image}{width} && $rss->{image}{height}) { $img .= qq' HEIGHT="$rss->{image}{height}" WIDTH="$rss->{image}{width}"'; } $img .= '>'; if ($rss->{image}{'link'}) { $img = qq[$img]; } $img = "

$img

"; } else { $img = qq[

$rss->{channel}{title}

]; } for my $item (@{$rss->{items}}) { my $i = qq[ * ] . qq[$item->{title}]; $i .= " - $item->{description}" if $prefs->{showdesc} && $item->{description}; $i .= "
"; push @items, $i; } $items = join "\n", @items; $date = $rss->{channel}{lastBuildDate} || $rss->{channel}{pubDate} || ''; my @date = $date ? gmtime timegm localtime str2time($date) : localtime(time - ((-M "$conf{rdfdir}/$rdf.rdf") * 86400)); $date = sprintf '

%s

', strftime('%B %d, %Y, %H:%M EST', @date); # $desc = $rss->{channel}{description} || ''; # $desc = "

$desc

" if $desc; $input = $rss->{textinput}{'link'} ? <

${\($rss->{textinput}{title} || '')}

EOT return < $img $items $input $date EOT } sub myhead { my($cgi, $user, $prefs, $refresh) = @_; my( $pw, $uname) = split( '\|', $user); my $funame = "for $uname" if $uname; my $huname = "
for user $uname" if $uname; $refresh = $refresh ? < EOT return header(get_cookie($cgi, $user, $prefs)), < My Portal \@ DLHoffman.com $funame $refresh
rising

 Welcome 
 My Portal 
 Public Library 
 Literature 
 Reference 
 Science 
 Software 
 LDP 
 Linux Focus 
 Linux Gazette 
 RPMs 
 RFCs 
 Mail Us 

  Search: 
 
 

EOT } sub myfoot { return <

© Copyright 2000, Doug L. Hoffman. All Rights Reserved.
Copyright of content of each channel maintained by respective owners.

[ Home | Login | Configure | Source | Feedback ]$huname


Top 

Hosting provided by Dr. Doug L. Hoffman

EOT } #================== # data stuff #================== sub save_prefs { my($user, $prefs) = @_; tie my %users, 'AnyDBM_File', $conf{userf}, O_RDWR|O_CREAT, 0644 or die $!; $users{$user} = join '|', %$prefs, modtime => time; untie %users; } sub get_cookie { my($cgi, $user, $prefs) = @_; my %params; if ($user) { $params{-cookie} = $cgi->cookie( -name => $conf{cookieNam}, -value => $user, -domain => $conf{cookieDom}, -path => $conf{cookiePath}, $prefs->{save_cookie} ? (-expires => $conf{cookieExp}) : () ); } return %params; } sub set_config { my($cgi, $user, $prefs) = @_; $user ||= join '.', $ENV{REMOTE_ADDR}, $$, time; $user = join '', map { $_ ? chr : '' } split m/\%/, $user if $user =~ m/^\%/; for my $i (keys %$prefs) { delete $prefs->{$i} if $i =~ /^\d+$/; } # channels for ($cgi->param('channels')) { my($m, $r) = ($cgi->param("col-$_"), $cgi->param("row-$_")); $m = $m =~ /^\d+$/ ? $m : 3; $r = $r =~ /^\d+$/ ? $r : 9; $prefs->{$_} = "$m,$r"; } # color for my $c (qw(back fore btext ftext link vlink)) { my $color = $cgi->param($c); $color =~ s/^\s*(.*)\s*$/$1/; if ($color =~ /^(?:#?[0-9a-fA-F]{6}|[a-zA-Z]+)$/) { $prefs->{$c} = $color; } } # other for my $c (qw(showdesc save_cookie)) { $prefs->{$c} = $cgi->param($c); } save_prefs($user, $prefs); return($user, $prefs); } sub get_prefs { my($user, $prefs) = @_; # ----- NOTE: the suffix .db might change! # return $conf{defaults} unless -e $conf{userf} . '.db'; $user = join '', map { $_ ? chr : '' } split m/\%/, $user if $user =~ m/^\%/; tie my %users, 'AnyDBM_File', $conf{userf}, O_RDONLY, 0444 or die $!; return $prefs || $conf{defaults} unless $users{$user}; my %prefs = split m/\|/, $users{$user}; untie %users; for (grep !/^\d+$/, keys %{$conf{defaults}}) { $prefs{$_} = $conf{defaults}->{$_} unless exists $prefs{$_}; } return \%prefs; } sub userOK { my($un, $pw) = @_; return $conf{defaults} unless -e $conf{userf} . '.pag'; tie my %users, 'AnyDBM_File', $conf{userf}, O_RDONLY, 0444 or die $!; for my $u (keys %users) { next unless $u =~ /^(.+?)\|$un$/; if (crypt($pw, $1) ne $1) { return; } } 1; } #================== # command line stuff #================== sub fetch_rdf { my($rdf, $l) = @_; my $rc = mirror($l, "$conf{rdfdir}/$rdf.rdf"); return($rc, $l) if is_error($rc); { my $file = "$conf{rdfdir}/$rdf.rdf"; my @time = (stat $file)[8, 9]; local $^I = '.bak'; local @ARGV = $file; while (<>) { s/\015\012?/\012/g; s/\227/--/g; s/&(?!(?:[a-zA-Z0-9]+|#\d+);)/&/g; print; } unlink "$file.bak"; utime @time, $file; } my $rss = new XML::RSS; eval { $rss->parsefile("$conf{rdfdir}/$rdf.rdf") }; warn "RDF $l not well-formed - $@" and return if $@; return($rc, $l) unless $rss->{image}{url}; $rc = mirror($rss->{image}{url}, "$conf{imgdir}/$rdf.gif"); return($rc, $rss->{image}{url}); } sub do_cl { my %o; getopts('r:c:l:upf:v', \%o); # no locking ... oh well if ($o{r}) { tie my %rdfs, 'AnyDBM_File', $conf{rdff}, O_RDWR, 0444 or die $!; if ($rdfs{$o{r}}) { $o{r} =~ /^(\d+)$/; # untaint $o{r} = $1; for ("$conf{rdfdir}/$o{r}.rdf", "$conf{imgdir}/$o{r}.gif") { if (-e) { unlink or warn "Can't unlink $_: $!"; } } delete $rdfs{$o{r}}; print "Channel $o{r} deleted\n"; } else { print "No key $o{r} found\n"; } untie %rdfs; } elsif ($o{c} && $o{l}) { tie my %rdfs, 'AnyDBM_File', $conf{rdff}, O_CREAT|O_RDWR, 0644 or die $!; my($n) = sort { $b <=> $a } keys %rdfs; $rdfs{++$n} = join '|', $o{c}, $o{l}; untie %rdfs; print "Channel $n. $o{c} ($o{l}) added.\n"; my($rc, $u) = fetch_rdf($n, $o{l}); if ($rc && is_error($rc)) { print "Error downloading $o{c} file $u: $rc\n"; } elsif ($rc) { print "Fetched $o{c} RDF file and (maybe?) img\n"; } } elsif ($o{p}) { tie my %rdfs, 'AnyDBM_File', $conf{rdff}, O_RDWR, 0444 or die $!; for (sort { $a <=> $b } keys %rdfs) { printf "%3d. %-20s => %-50s\n", $_, split m/\|/, $rdfs{$_}; } untie %rdfs; } elsif ($o{f}) { my @f; tie my %rdfs, 'AnyDBM_File', $conf{rdff}, O_RDWR, 0444 or die $!; if ($o{f} eq 'all') { @f = sort keys %rdfs; } else { @f = split m/\s+/, $o{f}; } for my $rdf (@f) { $rdf =~ /^(\d+)$/; $rdf = $1; warn "$rdf not found" and next unless $rdfs{$rdf}; my($c, $l) = split m/\|/, $rdfs{$rdf}; my($rc, $u) = fetch_rdf($rdf, $l); if (is_error($rc)) { print "Error downloading $c file $u: $rc\n"; } } untie %rdfs; } else { warn < exists on disk. =item v0.56 (16 Nov 1999) Delete image and RDF files on channel delete (B<-r>). =item v0.55 (15 Nov 1999) Small bug in B<-f> option fixed. Added printing of date back in (uses date of RSS file on disk if appropriate field in RSS file not filled in). Added C parameter to cookie config. =item v0.54 (13 Nov 1999) Even more fixes! Wooooo! Most of these fixes are not even worth mentioning, really. Cosmetic stuff, stuff to make it cleaner and pass HTML validation, etc. =item v0.53 (11 Nov 1999) Some more fixes! =item v0.52 (10 Nov 1999) Some fixes. =item v0.51 (10 Nov 1999) Cosmetic changes. =item v0.50 (09 Nov 1999) A nice project for a day ... =back =head1 AUTHOR AND COPYRIGHT Chris Nandor Epudge@pobox.comE, http://pudge.net/ Copyright (c) 2000 Chris Nandor. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the Artistic License, distributed with Perl. =head1 VERSION 0.61, 02 Jan 2000