#!/usr/bin/perl # viewnews.cgi # NewsPro User CGI # Version: 3.8 build 33 # See newspro.cgi for license information. # SCRIPT SETTINGS # If you are using Microsoft IIS, set the following to 1. If you are # using Unix/Apache, set it to 2. Setting it 0 tries to determine # automatically, and usually works just fine. If you use IIS yet have # 500 error problems, try setting the variable to 2, then try 3. $IIS = 0; # ** FILE LOCKING ** # File locking is a feature, provided by the operating system, which # prevents possible serious problems when NewsPro is being used by # multiple users. Almost every operating system supports this, except # for Windows 9x. Possible settings: # 2 Enable file locking. If you know your server supports it, set # UseFlock to this. # 1 Auto-detect file locking support (default). # 0 Disable file locking. This may result in file corruption. $UseFlock = 0; # If you want to use a subroutine other than DoNewsHTML for viewnews.cgi functions, # other than search, enter the name here. e.g. 'DoHeadlineHTML' $VNSub = 'DoNewsHTML'; # If you want to a template other than viewnews.tmpl for viewnews.cgi functions, # enter the name here. The template file must be in your NewsPro directory # (the same directory that viewnews.cgi is in). $VNTmpl = 'viewnews.tmpl'; # Set this to 1 to automatically look for and load ViewNews addons. # Generally, enable this only if you have addons installed. # This does slow down viewnews.cgi, as it has to scan for addons # whenever it is run. $EnableAddons = 0; # If you will be including viewnews.cgi into an HTML page via SSI, # set the following to 1. Don't do this if you can use news.txt # instead. $VNSSI = 0; # END OF SETTINGS (unless you encounter problems - then fill out the next section) # SERVER PROBLEMS WORKAROUNDS # If the script either gets its URL wrong or produces a fatal error # about not being able to include npconfig.pl, set the following variables. # While it won't hurt, most users don't have to. $abspath = ''; # Set the above to the absolute path to NewsPro's directory, without # a trailing slash. Example: # $abspath = '/absolute/path/to/newspro'; $scripturl = ''; # Set the above to the URL to vienews.cgi. Example: # $scripturl = 'http://www.myserver.com/newspro/viewnews.cgi'; # Once again, you only need to set the above two variables if you're # having server problems. # END SERVER PROBLEMS WORKAROUNDS # The script begins... eval { &main; }; if ($@) { &NPdie("Untrapped Error: $@"); } exit; sub main { # Microsoft servers. Try and be compatible... if ($IIS != 2) { if ($IIS == 0) { if ($ENV{'SERVER_SOFTWARE'} =~ m!IIS!) { $IIS = 1 } } if (($IIS) && ($0 =~ m!(.*)(\\|\/)!)) { chdir($1); } if ($IIS == 1) { print "HTTP/1.0 200 OK\n"; } } # That's over! if ($UseFlock == 1) { if ($^O ne 'MSWin32') { $UseFlock = 1; } else { if ($ENV{'PATH'} =~ /WINNT/i) { # Yes, this won't work if you didn't use the default name # for your Windows directory. But the alternative is loading # the Win32 module, which is time-consuming. $UseFlock = 1; } else { # We appear to be on Windows 9x. $UseFlock = 0; } } } elsif ($UseFlock == 2) { $UseFlock = 1; } # Server problem workaround #1 if ($abspath) { push(@INC, $abspath); } require "npconfig.pl"; require "ndisplay.pl"; require "nplib.pl"; ReadForm(); SubmitFormFields(); push(@formfields, 'newstext'); # Put the script's URL into $scripturl. # Don't if it was already set as a server problem workaround. unless ($scripturl) { $scripturl = &GetScriptURL; } ReadConfigInfo(); if ($EnableAddons) {&LoadAddons;} if (@Addons_ViewNews_Handler) { &RunAddons(@Addons_ViewNews_Handler); } if (query_string() eq "dispsearchform") { print header(); print qq~ News Search
Search Field:
~; } elsif (query_string() =~ /^search/) { DoSearch(); } elsif (query_string() eq "emaillist") { &EmailList; } elsif (query_string() eq "emaillistform") { print header(); print qq~
~; } elsif (query_string() =~ /^news/) { &ShowNews; } elsif (query_string() =~ /^archive/) { &ShowArchivedNews; } elsif (query_string() eq "disparchiveform") { print header(); print qq~ Below are three forms that can be used to view your archives. Cut and paste these forms from the page source.
View news from:

View news from to

View news from the past days.
~; } else { if ($VNSSI) { $OnlyNewNews = 1; print header(); MiniGenHTML(1); } else { NPdie($Messages{'Viewnews_Error_2'}); # Not a perfect error message, but it's all that's available in nplang } } } sub MiniGenHTML { my $printmode = shift; &GetCookies; &loadND; $currenttime = time; local ($content) = ""; $oldtime = $currenttime - $NPConfig{'mainpagelimit'}; $newsnum = @NewsData; if ($NPConfig{'NumberLimit'}) { $oldnum = $newsnum - $NPConfig{'NumberLimit'}; if ($oldnum > 0) { $oldtime = $NewsData[$oldnum]->{'newstime'}; } else { $oldtime = $NewsData[0]->{'newstime'}; } } $newsnum--; NVLOOP: while ($newsnum >= 0) { getNDvar($newsnum); if ($NPConfig{'NewsArcDel'} eq "0" || $newstime >= $oldtime) { $BeingArchived = 0; $DynamicPage = 1; if (@Addons_ViewNews_Build) { &RunAddons(@Addons_ViewNews_Build); } &$VNSub; if ($NPConfig{'CreateAnchors'}) {$newshtml = qq~$newshtml~;} unless ($printmode) { $content .= $newshtml; } else { print $newshtml; } } $newsnum--; } if ($NPConfig{'DisplayLink'}) { # You can modify this link if you'd like. $content .= qq~ $Messages{'DisplayLink'} $Messages{'NewsPro'}.
~; } unless ($printmode) { return $content; } } sub ShowArchivedNews { print header(); my $content = ''; my $startdate; my $enddate; if (query_string() =~ /^archive(\d{4})-(\d{1,2})-(\d{1,2})to(\d{4})-(\d{1,2})-(\d{1,2})/) { my ($year1, $month1, $day1, $year2, $month2, $day2) = ($1, $2, $3, $4, $5, $6); $startdate = &YMDtoUNIX($year1, $month1, $day1); $enddate = &YMDtoUNIX($year2, $month2, $day2); $enddate = $enddate + 86399; } elsif (query_string() =~ /^archivepast(\d+)days/) { ($startdate, $enddate) = &PastDaysTime($1); } elsif ($in{'pastdays'}) { ($startdate, $enddate) = &PastDaysTime($in{'pastdays'}); } elsif ($in{'year'} && $in{'day'} && $in{'month'}) { $startdate = &YMDtoUNIX($in{'year'}, $in{'month'}, $in{'day'}); $enddate = $startdate + 86399; } elsif ($in{'year1'} && $in{'year2'} && $in{'day1'} && $in{'day2'} && $in{'month1'} && $in{'month2'}) { $startdate = &YMDtoUNIX($in{'year1'}, $in{'month1'}, $in{'day1'}); $enddate = &YMDtoUNIX($in{'year2'}, $in{'month2'}, $in{'day2'}); $enddate = $enddate + 86399; } else { &NPdie($Messages{'Viewnews_Error_1'}); } my @NewNewsData; &loadND; foreach $i (@NewsData) { if ($i->{'newstime'} >= $startdate && $i->{'newstime'} <= $enddate) { push(@NewNewsData, $i); } } @NewsData = @NewNewsData; $newsnum = @NewsData; if ($newsnum == 0) { &NPdie($Messages{'Viewnews_Error_1'}); } $newsnum--; NVLOOP: while ($newsnum >= 0) { &getNDvar($newsnum); if (@Addons_ViewNews_Archive) { &RunAddons(@Addons_ViewNews_Archive); } &{$VNSub}; if ($NPConfig{'CreateAnchors'}) {$newshtml = qq~$newshtml~;} $content .= $newshtml; $newsnum--; } my $date1 = GetTheDate($startdate); my $date2 = GetTheDate($enddate); &GenPage("$Messages{'Viewnews_From'} $date1 $Messages{'Viewnews_To'} $date2", $content); } sub ShowNews { print header(); local ($content) = ""; $OnlyNewNews = 0; query_string() =~ /^news(\S+)/; $newsparam = $1; if ($newsparam ne "") { &loadND; $newsnum = @NewsData; if (@Addons_ViewNews_Show3) { &RunAddons(@Addons_ViewNews_Show3); } if ($newsparam eq "all") { $newsstart = 0; $newsend = $newsnum - 1; } elsif ($newsparam =~ /item(\d+)/) { $newsstart = $1; $newsend = $newsstart; } elsif ($newsparam =~ /id(\S+)/) { $nid = $1; $nid =~ s/\_/\,/g; $nid =~ s/[^\d,]//g; $newsstart = $NewsID{$nid}; $newsend = $newsstart; } else { $newsparam =~ /start(\d+)end(\d+)/; $newsstart = $1; $newsend = $2; } if (($newsstart < 0) || ($newsstart >= $newsnum) || ($newsend < $newsstart) || ($newsend >= $newsnum) || !defined $newsstart) { &NPdie($Messages{'Viewnews_Error_3'}); } $newscount = $newsend; while ($newscount >= $newsstart) { &getNDvar($newscount); $newsnum = $newscount; $DynamicPage = 1; if (@Addons_ViewNews_Show) { &RunAddons(@Addons_ViewNews_Show); } &{$VNSub}; if ($NPConfig{'CreateAnchors'}) {$newshtml = qq~$newshtml~;} $content .= $newshtml; $newscount--; } if ($newsstart == $newsend) { $gptitle = $newssubject; } else { $gptitle = "$Messages{'Viewnews_Items'} $newsstart-$newsend"; } if (@Addons_ViewNews_Show2) { &RunAddons(@Addons_ViewNews_Show2); } &GenPage($gptitle, $content); } else { $content = MiniGenHTML(); &GenPage($Messages{'Viewnews_Latest'}, $content); } } sub EmailList { @emaillist = split(/~/, $NPConfig{'emaillist'}); if ($in{'npsubscribe'}) { $in{'npemail'} = lc $in{'npemail'}; $in{'npemail'} =~ s/\n//g; $in{'npemail'} =~ s/\r//g; $in{'npemail'} =~ s/~//g; $in{'npemail'} =~ s/``x//g; $in{'npemail'} =~ s/,//g; my $IsDuplicate = 0; if ($in{'npemail'} =~ m/^(\S+)\@(\S+).(\S+)/) { foreach $i (@emaillist) { if ($in{'npemail'} eq $i) { $IsDuplicate = 1; last; } } unless ($IsDuplicate) { $NPConfig{'emaillist'} .= "~$in{'npemail'}"; &WriteConfigInfo; } &ELPage(1, $Messages{'Viewnews_EmailAdd'}); } else { &ELPage(0, "$in{'npemail'} $Messages{'Viewnews_EmailFail'}"); } } elsif ($in{'npunsubscribe'}) { foreach $i (@emaillist) { if ($i =~ /^\Q$in{'npemail'}\E$/i) { $UnsubscribeSuccess = 1; } else { push(@newemaillist, $i); } } if ($UnsubscribeSuccess) { $NPConfig{'emaillist'} = join('~', @newemaillist); &WriteConfigInfo; &ELPage(1, "$in{'npemail'} $Messages{'Viewnews_EmailUnsubSuccess'}"); } else { &ELPage(0, "$in{'npemail'} $Messages{'Viewnews_EmailUnsubFail'}"); } } else { &ELPage(0, $Messages{'Viewnews_EmailIncomplete'}); } } sub ELPage { local ($statuscode, $statusmsg) = @_; if ($in{'successredirect'} && $statuscode == 1) { print "Location: $in{'successredirect'}\n\n"; exit; } if ($in{'failureredirect'} && $statuscode == 0) { print "Location: $in{'failureredirect'}\n\n"; exit; } print header(); if ($statuscode) { &GenPage("$Messages{'Viewnews_Mailing'}: $Messages{'Viewnews_Success'}", $statusmsg); } else { &GenPage("$Messages{'Viewnews_Mailing'}: $Messages{'Viewnews_Failure'}", $statusmsg); } } sub NPdie { unless ($HeaderPrinted) { print header(); } my $error = shift; my $content = "

Error: $error

"; if ($NPdied == 1) { print $content; } else { $NPdied = 1; &GenPage("$NPConfig{'SiteTitle'} $Messages{'Error'}", $content); } exit; } sub DoSearch { print header(); $content = ''; my %SearchScore; &loadND; unless ($in{'searchstring'}) { query_string() =~ /^search(.*)/; $in{'searchstring'} = $1; $in{'searchstring'} =~ tr/+/ /; $in{'searchstring'} =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; } if ($in{'searchfield'}) { foreach $field (@formfields) { if ($field eq $in{'searchfield'}) { $FieldMatched = 1; last; } } unless ($FieldMatched) { $in{'searchfield'} = ""; } } require Text::ParseWords; @searchstring = &Text::ParseWords::quotewords('\s+', 0, $in{'searchstring'}); if (@Addons_ViewNews_DoSearch) { &RunAddons(@Addons_ViewNews_DoSearch); } $newsnum = 0; VNLOOP: while ($newsnum < @NewsData) { if (@Addons_ViewNews_DoSearch2) { &RunAddons(@Addons_ViewNews_DoSearch2) } if ($in{'searchfield'}) { &getNDvar($newsnum); $searchData = ${$in{'searchfield'}}; } else { $searchData = join(' ', $NewsData[$newsnum]->{'newstext'}, $NewsData[$newsnum]->{'newssubject'}, $NewsData[$newsnum]->{'newsname'}); } foreach $j (@searchstring) { if ($searchData =~ /\Q$j/i) { if ($SearchScore{$newsnum}) { $SearchScore{$newsnum}++; } else { push(@searchresults, $newsnum); push(@searchdates, $NewsData[$newsnum]->{'newstime'}); $SearchScore{$newsnum} = 1; } } } $newsnum++; } if (@searchresults > 0) { # We have results. Start sorting! # Build an array of search scores. foreach $key (sort {$a <=> $b} keys %SearchScore) { push(@searchscores, $SearchScore{$key}); } # Array built. Now, sort by score, then date. @resultssorted = @searchresults [ sort { $searchdates[$a] <=> $searchdates[$b] } 0 .. $#searchdates]; @resultssorted = @resultssorted [ sort { $searchscores[$a] <=> $searchscores[$b] } 0 .. $#searchscores]; @resultssorted = reverse(@resultssorted); # Sorting is finished. Cut off number of results... my $maxsearch = $NPConfig{'MaxSearchResults'} - 1; if ($maxsearch < 0) { $maxsearch = 0; } my $rstotal = @resultssorted - 1; if ($maxsearch > $rstotal) { $maxsearch = $rstotal; } @resultssorted = @resultssorted[0 .. $maxsearch]; # ... and display. foreach $newsnum (@resultssorted) { &getNDvar($newsnum); $SearchResult = 1; &DoSearchHTML; $content .= $newshtml; } } else { $content .= "$Messages{'Viewnews_NoResults'}"; } &GenPage($Messages{'Viewnews_Results'}, $content); } sub GenPage { my $title = shift; my $content = shift; $HTTP_REFERER = $ENV{'HTTP_REFERER'}; if ($abspath) { NPopen(TMPL, "$abspath/$VNTmpl"); } else { NPopen(TMPL, $VNTmpl); } @tmpl = ; close(TMPL); $tmpl = join('', @tmpl); $tmpl =~ s///g; $tmpl =~ s/\{\[]+)>/${\(HTMLtoText(${$1}))}/g; $tmpl =~ s/\{]+)\{[\'\"]([^\s\>\}\'\"]+)[\'\"]\}>/${\(HTMLtoText(${$1}{$2}))}/g; $tmpl =~ s/\[]+)\[(\d+)\]>/${\(HTMLtoText(${$1}[$2]))}/g; $tmpl =~ s/\{\[]+)>/${$1}/gi; $tmpl =~ s/\{]+)\{[\'\"]([^\s\>\}\'\"]+)[\'\"]\}>/${$1}{$2}/g; $tmpl =~ s/\[]+)\[(\d+)\]>/${$1}[$2]/g; $tmpl =~ s/<\!--#include file\s*?=\s*?"(\S+?)"\s*?-->/${\(VNFileLoad($1))}/gi; $tmpl =~ s//$title/g; $tmpl =~ s//$content/; $tmpl =~ s//${\(HTMLtoText($content))}/g; if (@Addons_ViewNews_GenPage) { &RunAddons(@Addons_ViewNews_GenPage); } print $tmpl; } sub VNFileLoad { my $fname = shift; my $file; $fname =~ s/([\&;\`'\|\"*\?\~\^\(\)\[\]\{\}\$\n\r])//g; open(FILE, $fname) || return '[an error occured while processing this directive]'; my @file = ; close(FILE); $file = join('', @file); return $file; } sub LoadAddons { opendir(ADMINDIR,$NPConfig{'admin_path'}); my @admindir = readdir(ADMINDIR); closedir(ADMINDIR); my $direntry; foreach $direntry (@admindir) { if ($direntry =~ /vna_\S+\.pl/) { eval { require "$NPConfig{'admin_path'}/$direntry"; }; } } $AddonsLoaded = 1; } sub RunAddons { my @addonslist = @_; my $AddonSub; foreach $AddonSub (@addonslist) { eval { &$AddonSub; }; } } sub NPopen { my $handle = shift; my $path = shift; $path =~ s/([\&;\`'\|\"*\?\~\^\(\)\[\]\{\}\$\n\r\0])//g; open($handle, $path) || &NPdie("$Messages{'Viewnews_NoOpen'} $path"); if ($UseFlock) { flock($handle, 2); } return 1; }