F:\WEBSITES\testbed\zipped\yabb_svn_new\branches\2.5.2\cgi-bin\yabb2\Sources\RSS.pl F:\WEBSITES\testbed\zipped\yabb_svn_new\trunk\cgi-bin\yabb2\Sources\RSS.pm
#!/usr/bin/perl --  
# Change the shebang only if you plan to use RSS in a program of your own.  
############################################################################### ###############################################################################
# RSS.pl                                                                      # # RSS.pm                                                                      #
  # $Date: 01.05.16 $                                                           #
############################################################################### ###############################################################################
# YaBB: Yet another Bulletin Board                                            # # YaBB: Yet another Bulletin Board                                            #
# Open-Source Community Software for Webmasters                               # # Open-Source Community Software for Webmasters                               #
# Version:        YaBB 2.5.2                                                  # # Version:        YaBB 2.6.12                                                 #
# Packaged:       October 21, 2012                                            # # Packaged:       January 5, 2016                                             #
# Distributed by: http://www.yabbforum.com                                    # # Distributed by: http://www.yabbforum.com                                    #
# =========================================================================== # # =========================================================================== #
# Copyright (c) 2000-2012 YaBB (www.yabbforum.com) - All Rights Reserved.     # # Copyright (c) 2000-2016 YaBB (www.yabbforum.com) - All Rights Reserved.     #
# Software by:  The YaBB Development Team                                     # # Software by:  The YaBB Development Team                                     #
#               with assistance from the YaBB community.                      # #               with assistance from the YaBB community.                      #
############################################################################### ###############################################################################
  use CGI::Carp qw(fatalsToBrowser);
  our $VERSION = '2.6.12';
   
$rssplver = 'YaBB 2.5.2 $Revision: 1.0 $'; $rsspmver = 'YaBB 2.6.12 $Revision: 1710 $';
if ($action eq 'detailedversion') { return 1; } if ( $action eq 'detailedversion' ) { return 1; }
   
# Change the error routine for here. # Change the error routine for here.
$SIG{__WARN__} = sub { &RSS_error(@_) }; local $SIG{__WARN__} = sub { RSS_error(@_) };
   
# Allow us to be called by a system()-like call # Allow us to be called by a system()-like call
# This lets us send data to any language that supports capturing STDOUT. # This lets us send data to any language that supports capturing STDOUT.
# Usage is detailed in POD at the bottom. # Usage is detailed in POD at the bottom.
if (scalar @ARGV) {&shellaccess();}  if ( scalar @ARGV ) { shellaccess(); } 
   
# Is RSS disabled? # Is RSS disabled?
&RSS_error('not_allowed') if $rss_disabled;  if ($rss_disabled) { RSS_error('not_allowed'); } 
   
&LoadCensorList;  LoadCensorList(); 
   
# Load YaBBC if it is enabled # Load YaBBC if it is enabled
require "$sourcedir/YaBBC.pl" if $enable_ubbc;  if ($enable_ubbc) { require Sources::YaBBC; } 
   
# Read from a single board # Read from a single board
sub RSS_board { sub RSS_board {
   ### Arguments:    ### Arguments:
   # board: the board to load from. Defaults to all boards.    # board: the board to load from. Defaults to all boards.
   # showauthor: show the author or not? Defaults to false.    # showauthor: show the author or not? Defaults to false.
   # topics: Number of topics to show. Defaults to 5.     # topics: Number of topics to show. Defaults to 10. 
   ###    ###
   
   # Local variables     # Settings 
   my ($board, $topics); # Variables for settings     my $board = $INFO{'board'}; 
     my $topics = $INFO{'topics'} || $rss_limit || 10;
   # Settings     if ( $rss_limit && $topics > $rss_limit ) { $topics = $rss_limit; } 
   $board = $INFO{'board'};  
   $topics = $INFO{'topics'} || $rss_limit || 10;     ### Security check ### 
   if ($rss_limit && $topics > $rss_limit) { $topics = $rss_limit; }     if ( AccessCheck( $currentboard, q{}, $boardperms ) ne 'granted' ) { 
         RSS_error('no_access');
   ### Security check ###     } 
   if (&AccessCheck($currentboard, '', $boardperms) ne 'granted') { &RSS_error('no_access'); }     if ( $annboard eq $board && !$iamadmin && !$iamgmod ) { 
   if ($annboard eq $board && !$iamadmin && !$iamgmod) { &RSS_error('no_access'); }         RSS_error('no_access'); 
     }
   # Now, go into the board and look for the last X topics     if ( ${ $uid . $currentboard }{'brdpasswr'} ) { 
   fopen(BRDTXT, "$boardsdir/$board.txt") || &RSS_error('cannot_open', "$boardsdir/$board.txt", 1);         my $cookiename = "$cookiepassword$currentboard$username"; 
   my @threadlist = <BRDTXT>;         my $crypass    = ${ $uid . $currentboard }{'brdpassw'}; 
   fclose(BRDTXT);         if ( !$staff && $yyCookies{$cookiename} ne $crypass ) { 
   my $threadcount = @threadlist;             RSS_error('no_access'); 
   if ($threadcount < $topics) { $topics = $threadcount; }        }
     }
   @threadlist = splice(@threadlist, 0, $topics);  
   # Sorting mode     # Now, go into the board and look for the last X topics 
   if ($rss_message == 2) {     fopen( BRDTXT, "$boardsdir/$board.txt" ) 
       # Sort by original post       || RSS_error( 'cannot_open', "$boardsdir/$board.txt", 1 ); 
       @threadlist = sort @threadlist;     my @threadlist = <BRDTXT>; 
   }     fclose(BRDTXT); 
   # Otherwise, it's good enough as-is     my $threadcount = @threadlist; 
   chomp @threadlist;     if ( $threadcount < $topics ) { $topics = $threadcount; } 
   
   my $i = 0;     @threadlist = splice @threadlist, 0, $topics; 
   foreach (@threadlist) {  
       ($mnum, $msub, $mname, $memail, $mdate, $mreplies, $musername, $micon, $mstate, $ns) = split(/\|/, $_);     # Sorting mode 
       $curnum = $mnum;     if ( $rss_message == 2 ) { 
       # See if this is a topic that we don't want displayed.  
       if ($mstate =~ /h/ && !$iamadmin && !$iamgmod) { next; }         # Sort by original post 
         @threadlist = sort @threadlist;
       # Does it need to be returned as a 304?     } 
       if ($i == 0) { # Do this for the first request only  
           $cachedate = &RFC822Date($mdate);     # Otherwise, it's good enough as-is 
           if ($ENV{'HTTP_IF_NONE_MATCH'} eq qq~"$cachedate"~ || $ENV{'HTTP_IF_MODIFIED_SINCE'} eq $cachedate) {     chomp @threadlist; 
               &Send304NotModified(); # Comment this out to test with caching disabled  
           }     my $i = 0; 
       }     for (@threadlist) { 
         (
       ($msub, undef) = &Split_Splice_Move($msub,0);             $mnum,     $msub,      $mname, $memail, $mdate, 
       &FromHTML($msub);             $mreplies, $musername, $micon, $mstate, $ns 
       &ToChars($msub);         ) = split /\|/xsm, $_; 
       # Censor the subject of the thread.         $curnum = $mnum; 
       $msub = &Censor($msub);  
         # See if this is a topic that we don't want displayed.
       my $postid = "$mreplies#$mreplies";         if ( $mstate =~ /h/sm && !$iamadmin && !$iamgmod ) { next; } 
       $postid = '0#0' if $rss_message == 2;  
         # Does it need to be returned as a 304?
       my $category = "$mbname/$boardname";         if ( $i == 0 ) {    # Do this for the first request only 
       &FromHTML($category);             $cachedate = RFC822Date($mdate); 
       # Show the minimum stuff (topic title, link to it)             if (   $ENV{'HTTP_IF_NONE_MATCH'} eq $cachedate 
       if ($accept_permalink){                 || $ENV{'HTTP_IF_MODIFIED_SINCE'} eq $cachedate ) 
           $permdate = &permtimer($curnum);             { 
           $yymain .= qq~        <item>                 Send304NotModified(); 
               <title>~ . &RSSDescriptionTrim($msub) . qq~</title>  
               <link>~ . &RSSDescriptionTrim("http://$perm_domain/$symlink$permdate/$currentboard/$curnum") . qq~</link>                 # Comment this out to test with caching disabled 
               <category>~ . &RSSDescriptionTrim($category) . qq~</category>             } 
               <guid isPermaLink="true">~ . &RSSDescriptionTrim("http://$perm_domain/$symlink$permdate/$currentboard/$curnum") . qq~</guid>         } 
   
         ( $msub, undef ) = Split_Splice_Move( $msub, 0 );
         FromHTML($msub);
         ToChars($msub);
   
         # Censor the subject of the thread.
         $msub = Censor($msub);
   
         my $postid = "$mreplies#$mreplies";
         if ( $rss_message == 2 ) { $postid = '0#0'; }
   
         my $category = "$mbname/$boardname";
         FromHTML($category);
   
         # Show the minimum stuff (topic title, link to it)
         if ($accept_permalink) {
             $permdate = permtimer($curnum);
             $yymain .= q~       <item>
                 <title>~ . RSSDescriptionTrim($msub) . q~</title>
                 <link>~
               . RSSDescriptionTrim(
                 "http://$perm_domain/$symlink$permdate/$currentboard/$curnum")
               . q~</link>
                 <category>~ . RSSDescriptionTrim($category) . q~</category>
                 <guid isPermaLink="true">~
               . RSSDescriptionTrim(
                 "http://$perm_domain/$symlink$permdate/$currentboard/$curnum")
               . q~</guid>
~; ~;
       } else {         } 
           $yymain .= qq~        <item>         else { 
               <title>~ . &RSSDescriptionTrim($msub) . qq~</title>             $yymain .= q~       <item> 
               <link>~ . &RSSDescriptionTrim("$scripturl?num=$curnum") . qq~</link>                 <title>~ . RSSDescriptionTrim($msub) . q~</title> 
               <category>~ . &RSSDescriptionTrim($category) . qq~</category>                 <link>~ 
               <guid>~ . &RSSDescriptionTrim("$scripturl?num=$curnum") . qq~</guid>               . RSSDescriptionTrim("$scripturl?num=$curnum") . q~</link> 
                 <category>~ . RSSDescriptionTrim($category) . q~</category>
                 <guid>~
               . RSSDescriptionTrim("$scripturl?num=$curnum") . q~</guid>
~; ~;
       }        }
   
       my $post;        my $post;
       fopen(TOPIC, "$datadir/$curnum.txt") || &RSS_error('cannot_open', "$datadir/$curnum.txt", 1);         fopen( TOPIC, "$datadir/$curnum.txt" ) 
       if ($rss_message == 1) {           || RSS_error( 'cannot_open', "$datadir/$curnum.txt", 1 ); 
           # Open up the thread and read the last post.         if ( $rss_message == 1 ) { 
           while (<TOPIC>) {  
               chomp $_;             # Open up the thread and read the last post. 
               $post = $_ if $_;             while (<TOPIC>) { 
           }                 chomp $_; 
       } elsif ($rss_message == 2) {                 if ($_) { $post = $_; } 
           # Open up the thread and read the first post.             } 
           $post = <TOPIC>;         } 
       }         elsif ( $rss_message == 2 ) { 
       fclose(TOPIC);  
       if ($post ne '') {             # Open up the thread and read the first post. 
           (undef, undef, undef, undef, $musername, undef, undef, undef, $message, $ns) = split(/\|/, $post);             $post = <TOPIC>; 
       }        }
       if ($showauthor) {         fclose(TOPIC); 
           if (-e "$memberdir/$musername.vars") {        if ( $post ne q{} ) {
               &LoadUser($musername);             ( 
               if (!${$uid.$musername}{'hidemail'}){                 undef, undef, undef, undef,    $musername, 
                   $yymain .= qq~<author>~ . &RSSDescriptionTrim("${$uid.$musername}{'email'} (${$uid.$musername}{'realname'})") . qq~</author>~;                 undef, undef, undef, $message, $ns 
               }             ) = split /\|/xsm, $post; 
               else {         } 
                   $yymain .= qq~            <author><name>~ . &RSSDescriptionTrim("(${$uid.$musername}{'realname'})") . qq~</name></author>\n~;         if ($showauthor) { 
               }             if ( -e "$memberdir/$musername.vars" ) { 
           }                 LoadUser($musername); 
       }                 if ( !${ $uid . $musername }{'hidemail'} ) { 
       if ($showdate) {                     $yymain .= 
               $mdate = $curnum if $rss_message == 2; # Sort by topic creation if requested.                       q~<author>~ 
               # Get the date how the user wants it.                       . RSSDescriptionTrim( 
               my $realdate = &RFC822Date($mdate);  "${$uid.$musername}{'email'} (${$uid.$musername}{'realname'})" 
               $yymain .= qq~        <pubDate>$realdate</pubDate>                       ) . q~</author>~; 
                 }
                 else {
                     $yymain .=
                       q~           <author>~
                       . RSSDescriptionTrim(
                         "$rssemail (${$uid.$musername}{'realname'})")
                       . qq~</author>\n~;
                 }
             }
         }
         if ($showdate) {
             if ( $rss_message == 2 ) {
                 $mdate = $curnum;
             }    # Sort by topic creation if requested.
                  # Get the date how the user wants it.
             my $realdate = RFC822Date($mdate);
             $yymain .= qq~      <pubDate>$realdate</pubDate>
~; ~;
       }        }
       if ($message ne '') {        if ( $message ne q{} ) {
           ($message, undef) = &Split_Splice_Move($message,$curnum);             ( $message, undef ) = Split_Splice_Move( $message, $curnum ); 
           if ($enable_ubbc) {            if ($enable_ubbc) {
                   &LoadUser($musername);                 LoadUser($musername); 
                   $displayname = ${$uid.$musername}{'realname'};                 $displayname = ${ $uid . $musername }{'realname'}; 
                   &DoUBBC;                 DoUBBC(); 
           }            }
           &FromHTML($message);             FromHTML($message); 
           &ToChars($message);             ToChars($message); 
           $message = &Censor($message);             $message = Censor($message); 
           $yymain .= qq~        <description>~ . &RSSDescriptionTrim($message) . qq~</description>             $yymain .= 
                 q~       <description>~
               . RSSDescriptionTrim($message)
               . q~</description>
~; ~;
       }        }
       # Finish up the item  
       $yymain .= qq~        </item>  
~;  
       $i++; # Increment  
   }  
   
   &ToChars($boardname);         # Finish up the item 
   $yytitle = $boardname;         $yymain .= q~       </item> 
   $yydesc = ${$uid.$curboard}{'description'};  ~; 
         $yymain =~ s/data-rel/rel/gsm;
         $i++;    # Increment
     }
   
     ToChars($boardname);
     $yytitle = $boardname;
     $yydesc  = ${ $uid . $curboard }{'description'};
   
   &RSS_template();     RSS_template(); 
     return;
} }
   
# Similar to Recent.pl&RecentList but uses original code # Similar to Recent.pl&RecentList but uses original code
# RSS feed from multiple boards (a category or the whole forum) # RSS feed from multiple boards (a category or the whole forum)
sub RSS_recent { sub RSS_recent {
   ### Arguments:    ### Arguments:
   # catselect: use a specific category instead of the whole forum (optional)    # catselect: use a specific category instead of the whole forum (optional)
   # topics: Number of topics to show. Defaults to 5.     # topics: Number of topics to show. Defaults to 10. 
   ###    ###
   
     # Local variables
   # Local variables     my @threadlist = (); 
   my ($topics); # Variables for settings  
   my (@threadlist, $i, $cutofftime); # Variables for the messages     # Settings 
     my $topics = $INFO{'topics'} || $rss_limit || 10;
   # Settings     if ( $rss_limit && $topics > $rss_limit ) { $topics = $rss_limit; } 
   $topics = $INFO{'topics'} || $rss_limit;  
   if ($rss_limit && $topics > $rss_limit) { $topics = $rss_limit; }     $yytitle = "$topics $maintxt{'214b'}"; 
   
   # If this is just a single category, handle it.    # If this is just a single category, handle it.
   if ($catinfo{$INFO{'catselect'}}) { @categoryorder = ($INFO{'catselect'}); }     if ( $INFO{'catselect'} ) { 
         @categoryorder = ( $INFO{'catselect'} );
   # Find the latest $topics post times in all boards that we have access to     } 
   # and add them to a giant array  
   foreach $catid (@categoryorder) {     # Find the latest $topics post times in all boards that we have access to 
       my $boardlist = $cat{$catid};     # and add them to a giant array 
     for my $catid (@categoryorder) {
       my @bdlist = split(/\,/, $boardlist);  
       my ($catname, $catperms) = split(/\|/, $catinfo{$catid});         my @bdlist = split /\,/xsm, $cat{$catid}; 
       my $cataccess = &CatAccess($catperms);         my ( $catname, $catperms ) = split /\|/xsm, $catinfo{$catid}; 
       if (!$cataccess) { next; }         my $cataccess = CatAccess($catperms); 
         if ( !$cataccess ) { next; }
       foreach $curboard (@bdlist) {  
           ($boardname{$curboard}, $boardperms, $boardview) = split(/\|/, $board{$curboard});         if ( $INFO{'catselect'} ) { 
             $yytitle = $catname;
           my $access = &AccessCheck($curboard, '', $boardperms);             $mydesc  = $catname; 
           if (!$iamadmin && $access ne 'granted') { next; }        }
   
           fopen(BOARD, "$boardsdir/$curboard.txt") || &RSS_error('cannot_open', "$boardsdir/$curboard.txt", 1);         *get_subboards = sub { 
           for($i = 0; $i < $topics; $i++) {             my @brd = @_; 
               my($buffer, $mnum, $mdate, $mstate);             for my $brd (@brd) { 
                 ( $boardname{$brd}, $boardperms, $boardview ) = split /\|/xsm,
               $buffer = <BOARD>;                   $board{$brd}; 
               last unless $buffer;  
               chomp $buffer;                 my $access = AccessCheck( $brd, q{}, $boardperms ); 
                 if ( !$iamadmin && $access ne 'granted' ) { next; }
               ($mnum, undef, undef, undef, $mdate, undef, undef, undef, $mstate) = split(/\|/, $buffer);                 if ( ${ $uid . $brd }{'brdpasswr'} ) { 
               $mdate = sprintf("%010d", $mdate);                     my $cookiename = "$cookiepassword$brd$username"; 
               $mdate = $mnum if $rss_message == 2; # Sort by topic creation if requested.                     my $crypass    = ${ $uid . $brd }{'brdpassw'}; 
                     if ( !$staff && $yyCookies{$cookiename} ne $crypass ) {
               # Check if it's hidden. If so, don't show it                         next; 
               if ($mstate =~ /h/ && !$iamadmin && !$iamgmod) { next; }                    }
                 }
               # Add it to an array, using $mdate as the first value so we can easily sort  
               push(@threadlist, "$mdate|$curboard|$buffer");                 fopen( BOARD, "$boardsdir/$brd.txt" ) 
           }                   || RSS_error( 'cannot_open', "$boardsdir/$brd.txt", 1 ); 
           fclose(BOARD);                 for my $i ( 0 .. ( $topics - 1 ) ) { 
                     my $buffer = <BOARD>;
           # Clean out the extra entries in the threadlist                     if ( !$buffer ) { last; } 
           @threadlist = reverse sort @threadlist;                     chomp $buffer; 
           @threadlist = @threadlist[0 .. $topics - 1];  
       }                     my ( 
   }                         $mnum, undef, undef, undef, $mdate, 
                         undef, undef, undef, $mstate
   for($i = 0; $threadlist[$i]; $i++) {                     ) = split /\|/xsm, $buffer; 
       # Opening item stuff                     if ( $rss_message == 2 ) { 
       ($mdate, $board, $mnum, $msub, $mname, $memail, $modate, $mreplies, $musername, $micon, $mstate) = split(/\|/, $threadlist[$i]);                         $mdate = $mnum; 
       $curnum = $mnum;                     }    # Sort by topic creation if requested. 
                     $mdate = sprintf '%010d', $mdate;
       ($msub, undef) = &Split_Splice_Move($msub,0);  
       &FromHTML($msub);                     # Check if it's hidden. If so, don't show it 
       &ToChars($msub);                     if ( $mstate =~ /h/sm && !$iamadmin && !$iamgmod ) { next; } 
       # Censor the subject of the thread.  
       $msub = &Censor($msub);      # Add it to an array, using $mdate as the first value so we can easily sort 
                     push @threadlist, "$mdate|$brd|$buffer";
       # Does it need to be returned as a 304?                 } 
       if($i == 0) { # Do this for the first request only                 fclose(BOARD); 
           $cachedate = &RFC822Date($mdate);  
           if($ENV{'HTTP_IF_NONE_MATCH'} eq qq~"$cachedate"~ || $ENV{'HTTP_IF_MODIFIED_SINCE'} eq $cachedate) {                if ( $subboard{$brd} ) {
               &Send304NotModified(); # Comment this out to test with caching disabled                     get_subboards( split /\|/xsm, $subboard{$brd} ); 
           }               }
       }            }
         };
       my $postid = "$mreplies#$mreplies";         for my $curbrd (@bdlist) { 
       $postid = '0#0' if $rss_message == 2;             get_subboards($curbrd); 
         }
       my $category = "$mbname/$boardname{$board}";     } 
       &FromHTML($category);     @threadlist = reverse sort @threadlist; 
       my $bn = $boardname{$board};  
       &FromHTML($bn);     for my $i ( 0 .. $#threadlist ) { 
       if ($accept_permalink){         if ( $i == ( $topics - 1 ) ) { last; } 
           my $permsub = $msub;  
           $permdate = &permtimer($curnum);         # Opening item stuff 
           $permsub =~ s~ ~$perm_spacer~g;         ( 
           $yymain .= qq~            <item>             $mdate,     $board,  $mnum,   $msub, 
           <title>~ . &RSSDescriptionTrim("$bn - $msub") . qq~</title>             $mname,     $memail, $modate, $mreplies, 
           <link>~ . &RSSDescriptionTrim("http://$perm_domain/$symlink$permdate/$board/$curnum") . qq~</link>             $musername, $micon,  $mstate 
           <category>~ . &RSSDescriptionTrim($category) . qq~</category>         ) = split /\|/xsm, $threadlist[$i]; 
           <guid isPermaLink="true">~ . &RSSDescriptionTrim("http://$perm_domain/$symlink$permdate/$board/$curnum") . qq~</guid>\n~;         $curnum = $mnum; 
       } else {  
           $yymain .= qq~        <item>         ( $msub, undef ) = Split_Splice_Move( $msub, 0 ); 
           <title>~ . &RSSDescriptionTrim("$bn - $msub") . qq~</title>         FromHTML($msub); 
           <link>~ . &RSSDescriptionTrim("$scripturl?num=$curnum/$postid") . qq~</link>         ToChars($msub); 
           <category>~ . &RSSDescriptionTrim($category) . qq~</category>  
           <guid>~ . &RSSDescriptionTrim("$scripturl?num=$curnum/$postid") . qq~</guid>\n~;         # Censor the subject of the thread. 
       }         $msub = Censor($msub); 
   
       my $post;         # Does it need to be returned as a 304? 
       fopen(TOPIC, "$datadir/$curnum.txt") || &RSS_error('cannot_open', "$datadir/$curnum.txt", 1);         if ( $i == 0 ) {    # Do this for the first request only 
       if ($rss_message == 1) {             $cachedate = RFC822Date($mdate); 
           # Open up the thread and read the last post.             if (   $ENV{'HTTP_IF_NONE_MATCH'} eq $cachedate 
           while(<TOPIC>) {                 || $ENV{'HTTP_IF_MODIFIED_SINCE'} eq $cachedate ) 
               chomp $_;             { 
               $post = $_ if $_;                 Send304NotModified(); 
           }                 # Comment this out to test with caching disabled 
       } elsif ($rss_message == 2) {             } 
           # Open up the thread and read the first post.         } 
           $post = <TOPIC>;  
       }         my $postid = "$mreplies#$mreplies"; 
       fclose(TOPIC);         if ( $rss_message == 2 ) { $postid = '0#0'; } 
   
       if ($post ne ''){         my $category = "$mbname/$boardname{$board}"; 
           (undef, undef, undef, undef, $musername, undef, undef, undef, $message, $ns) = split(/\|/, $post);         FromHTML($category); 
       }         my $bn = $boardname{$board}; 
         FromHTML($bn);
       if ($showauthor) {        if ($accept_permalink) {
           # The spec really wants us to include their email.             my $permsub = $msub; 
           # That's not adviseable for us (spambots anyone?). So we skip author if the email hidden flag is on for that user.             $permdate = permtimer($curnum); 
           if (-e "$memberdir/$musername.vars") {             $permsub =~ s/ /$perm_spacer/gsm; 
               &LoadUser($musername);             $yymain .= q~           <item> 
               if (!${$uid.$musername}{'hidemail'}){             <title>~ . RSSDescriptionTrim("$bn - $msub") . q~</title> 
                   $yymain .= qq~            <author>~ . &RSSDescriptionTrim("${$uid.$musername}{'email'} (${$uid.$musername}{'realname'})") . qq~</author>\n~;             <link>~ 
               }               . RSSDescriptionTrim( 
               else {                 "http://$perm_domain/$symlink$permdate/$board/$curnum") 
                   $yymain .= qq~            <author><name>~ . &RSSDescriptionTrim("${$uid.$musername}{'realname'}") . qq~</name></author>\n~;               . q~</link> 
               }             <category>~ . RSSDescriptionTrim($category) . q~</category> 
           }             <guid isPermaLink="true">~ 
       }               . RSSDescriptionTrim( 
                 "http://$perm_domain/$symlink$permdate/$board/$curnum")
       if ($showdate) {               . qq~</guid>\n~; 
           $mdate = $curnum if $rss_message == 2; # Sort by topic creation if requested.         } 
           # Get the date how the user wants it.         else { 
           my $realdate = &RFC822Date($mdate);             $yymain .= q~       <item> 
           $yymain .= qq~            <pubDate>$realdate</pubDate>\n~;             <title>~ . RSSDescriptionTrim("$bn - $msub") . q~</title> 
       }             <link>~ 
               . RSSDescriptionTrim("$scripturl?num=$curnum/$postid") . q~</link>
       if ($message ne '') {             <category>~ . RSSDescriptionTrim($category) . q~</category> 
           ($message, undef) = &Split_Splice_Move($message,$curnum);             <guid>~ 
           if ($enable_ubbc) {               . RSSDescriptionTrim("$scripturl?num=$curnum/$postid") 
                   &LoadUser($musername);               . qq~</guid>\n~; 
                   $displayname = ${$uid.$musername}{'realname'};         } 
                   &DoUBBC;  
           }         my $post; 
           &FromHTML($message);         fopen( TOPIC, "$datadir/$curnum.txt" ) 
           &ToChars($message);           || RSS_error( 'cannot_open', "$datadir/$curnum.txt", 1 ); 
           $message = &Censor($message);         if ( $rss_message == 1 ) { 
           $yymain .= qq~            <description>~ . &RSSDescriptionTrim($message) . qq~</description>\n~;  
       }             # Open up the thread and read the last post. 
             while (<TOPIC>) {
       $yymain .= qq~        </item>\n~;                 chomp $_; 
   }                if ($_) { $post = $_; }
             }
   &ToChars($boardname);         } 
   $yytitle = "$topics $maintxt{'214b'}";         elsif ( $rss_message == 2 ) { 
   $yydesc = ${$uid.$curboard}{'description'};  
             # Open up the thread and read the first post.
             $post = <TOPIC>;
         }
         fclose(TOPIC);
   
         if ( $post ne q{} ) {
             (
                 undef, undef, undef, undef,    $musername,
                 undef, undef, undef, $message, $ns
             ) = split /\|/xsm, $post;
         }
   
         if ($showauthor) {
             # The spec really wants us to include their email.
             if ( -e "$memberdir/$musername.vars" ) {
                 LoadUser($musername);
                 if ( !${ $uid . $musername }{'hidemail'} ) {
                     $yymain .=
                       q~           <author>~
                       . RSSDescriptionTrim(
  "${$uid.$musername}{'email'} (${$uid.$musername}{'realname'})" 
                       ) . qq~</author>\n~;
                 }
                 else {
                     $yymain .=
                       q~           <author>~
                       . RSSDescriptionTrim(
                         "$rssemail (${$uid.$musername}{'realname'})")
                       . qq~</author>\n~;
                 }
             }
         }
   
         if ($showdate) {
             if ( $rss_message == 2 ) {
                 $mdate = $curnum;
             }    # Sort by topic creation if requested.
                  # Get the date how the user wants it.
             my $realdate = RFC822Date($mdate);
             $yymain .= qq~          <pubDate>$realdate</pubDate>\n~;
         }
   
         if ( $message ne q{} ) {
             ( $message, undef ) = Split_Splice_Move( $message, $curnum );
             if ($enable_ubbc) {
                 LoadUser($musername);
                 $displayname = ${ $uid . $musername }{'realname'};
                 DoUBBC();
             }
             FromHTML($message);
             ToChars($message);
             $message = Censor($message);
             $yymain .=
                 q~           <description>~
               . RSSDescriptionTrim($message)
               . qq~</description>\n~;
         }
   
         $yymain .= qq~      </item>\n
  ~;
         $yymain =~ s/data-rel/rel/gsm;
     }
   
   &RSS_template();     ToChars($boardname); 
     $yydesc = ${ $uid . $curboard }{'description'};
   
     RSS_template();
     return;
} }
   
sub RSS_template { # print RSS output sub RSS_template {    # print RSS output
   # Generate the lastBuildDate                      # Generate the lastBuildDate
   my $rssdate = &RFC822Date($date);     my $rssdate = RFC822Date($date); 
   
   # Send out the "Last-Modified" and "ETag" headers so nice readers will ask before downloading. # Send out the "Last-Modified" and "ETag" headers so nice readers will ask before downloading.
   $LastModified = $ETag = $cachedate || $rssdate;    $LastModified = $ETag = $cachedate || $rssdate;
   $contenttype = 'text/xml';    $contenttype = 'text/xml';
   &print_output_header;     print_output_header(); 
   
   # Make the generator look better    # Make the generator look better
   my $RSSplver = $rssplver;    my $RSSplver = $rssplver;
   $RSSplver =~ s/\$//g;     $RSSplver =~ s/\$//gxsm; 
   
   # Removed per Corey's suggestion: http://www.yabbforum.com/community/YaBB.pl?num=1142571424/20#20 # Removed per Corey's suggestion: http://www.yabbforum.com/community/YaBB.pl?num=1142571424/20#20
   #my $docs = "        <docs>http://$perm_domain</docs>\n" if $perm_domain; #my $docs = "       <docs>http://$perm_domain</docs>\n" if $perm_domain;
   
   my $mainlink = $scripturl;    my $mainlink = $scripturl;
   $mainlink .= "?board=$INFO{'board'}" if $INFO{'board'};     my $tit      = "$yytitle - $mbname"; 
   $mainlink .= "?catselect=$INFO{'catselect'}" if $INFO{'catselect'};     if ( $INFO{'board'} ) { 
         $mainlink .= "?board=$INFO{'board'}";
   my $tit = "$yytitle - $mbname";         $descr = ( $boardname ? "$boardname - " : q{} ) . $mbname; 
   &FromHTML($tit);     } 
   my $descr = ($boardname ? "$boardname - " : "") . $mbname;     elsif ( $INFO{'catselect'} ) { 
   &FromHTML($descr);         $mainlink .= "?catselect=$INFO{'catselect'}"; 
   my $mn = $mbname;         $descr = qq{$mydesc - $mbname}; 
   &FromHTML($mn);     } 
   $output = qq~<?xml version="1.0" encoding="$yycharset" ?>  
     FromHTML($tit);
     FromHTML($descr);
     my $mn = $mbname;
     FromHTML($mn);
     $output = qq~<?xml version="1.0" encoding="$yymycharset" ?>
  <!-- IF YOU'RE SEEING THIS AND ARE USING CHROME GO TO https://chrome.google.com/webstore/detail/rss-subscription-extensio/nlbjncdgjeocebhnmkbbbdekmmmcbfjd AND GET THE ADD-IN -->
  <!-- IF YOU'RE SEEING THIS AND ARE USING OPERA GO TO https://addons.opera.com/en/extensions/ and search for 'RSS' to get an add-in -->
<!-- Generated by YaBB on $rssdate --> <!-- Generated by YaBB on $rssdate -->
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
   <channel>    <channel>
       <atom:link href="$scripturl?action=$INFO{'action'}~ . ($INFO{'board'} ? ";board=$INFO{'board'}" : "") . qq~" rel="self" type="application/rss+xml" />         <atom:link href="$scripturl?action=$INFO{'action'}~ 
       <title>~ . &RSSDescriptionTrim($tit) . qq~</title>       . ( $INFO{'board'}     ? ";board=$INFO{'board'}"         : q{} ) 
       <link>~ . &RSSDescriptionTrim($mainlink) . qq~</link>       . ( $INFO{'catselect'} ? ";catselect=$INFO{'catselect'}" : q{} ) 
       <description>~ . &RSSDescriptionTrim($descr) . qq~</description>       . q~" rel="self" type="application/rss+xml" /> 
       <language>~ . &RSSDescriptionTrim("$maintxt{'w3c_lngcode'}") . qq~</language>         <title>~ . RSSDescriptionTrim($tit) . q~</title> 
         <link>~ . RSSDescriptionTrim($mainlink) . q~</link>
       <copyright>~ . &RSSDescriptionTrim($mn) . qq~</copyright>         <description>~ . RSSDescriptionTrim($descr) . q~</description> 
       <lastBuildDate>$rssdate</lastBuildDate>         <language>~ 
       <docs>http://blogs.law.harvard.edu/tech/rss</docs>       . RSSDescriptionTrim("$maintxt{'w3c_lngcode'}") . q~</language> 
       <generator>$RSSplver</generator>  
       <ttl>30</ttl>         <copyright>~ . RSSDescriptionTrim($mn) . qq~</copyright> 
         <lastBuildDate>$rssdate</lastBuildDate>
         <docs>http://blogs.law.harvard.edu/tech/rss</docs>
         <generator>$RSSplver</generator>
         <ttl>30</ttl>
$yymain $yymain
   </channel>    </channel>
</rss>~; </rss>~;
   
   &print_HTML_output_and_finish;     print_HTML_output_and_finish(); 
     return;
} }
   
sub RSS_error { sub RSS_error {
   # This routine is mostly a copy of fatal_error except it uses RSS templating  
   &LoadLanguage('Error');  
   my($e_filename, $e_line, $e_subroutine, $l, $ot);  
   # Gets filename and line where fatal_error was called.  
   # Need to go further back to get correct subroutine name,  
   # otherwise will print fatal_error as current subroutine!  
   (undef, $e_filename, $e_line) = caller(0);  
   (undef, undef, undef, $e_subroutine) = caller(1);  
   (undef, $e_subroutine) = split(/::/, $e_subroutine);  
   my($e,$t,$v) = @_;  
   if ($t || $e) { $ot = "<b>$maintxt{'error_description'}</b>: $error_txt{$e} $t"; }  
   if (($debug == 1 or ($debug == 2 && $iamadmin)) && ($e_filename || $e_line || $e_subroutine)) { $l = "<br />$maintxt{'error_location'}: $e_filename<br />$maintxt{'error_line'}: $e_line<br />$maintxt{'error_subroutine'}: $e_subroutine"; }  
   if ($v) { $v = "<br />$maintxt{'error_verbose'}: $!"; }  
   
   if ($elenable) {  
       &fatal_error_logging("$ot$l$v");  
   }  
   
   my $tit = $error_txt{'error_occurred'};  
   &FromHTML($tit);  
   my $ed = "$ot$l$v";  
   &FromHTML($ed);  
   my $mn = $mbname;  
   &FromHTML($mn);  
   $yymain = qq~  
   <item>  
       <title>~ . &RSSDescriptionTrim($tit) . qq~</title>  
       <description>~ . &RSSDescriptionTrim($ed) . qq~</description>  
       <category>~ . &RSSDescriptionTrim($mn) . qq~</category>  
   </item>~;  
   
   &RSS_template();     # This routine is mostly a copy of fatal_error except it uses RSS templating 
     my ( $e, $t, $v ) = @_;
     LoadLanguage('Error');
     my ( $e_filename, $e_line, $e_subroutine, $l, $ot );
   
     # Gets filename and line where fatal_error was called.
     # Need to go further back to get correct subroutine name,
     # otherwise will print fatal_error as current subroutine!
     ( undef, $e_filename, $e_line ) = caller 0;
     ( undef, undef, undef, $e_subroutine ) = caller 1;
     ( undef, $e_subroutine ) = split /::/xsm, $e_subroutine;
     if ( $t || $e ) {
         $ot = "<b>$maintxt{'error_description'}</b>: $error_txt{$e} $t";
     }
     if (   ( $debug == 1 or ( $debug == 2 && $iamadmin ) )
         && ( $e_filename || $e_line || $e_subroutine ) )
     {
         $l =
  "<br />$maintxt{'error_location'}: $e_filename<br />$maintxt{'error_line'}: $e_line<br />$maintxt{'error_subroutine'}: $e_subroutine";
     }
     if ($v) { $v = "<br />$maintxt{'error_verbose'}: $!"; }
   
     if ($elenable) {
         fatal_error_logging("$ot$l$v");
     }
   
     my $tit = $error_txt{'error_occurred'};
     FromHTML($tit);
     my $ed = "$ot$l$v";
     FromHTML($ed);
     my $mn = $mbname;
     FromHTML($mn);
     $yymain = q~
     <item>
         <title>~ . RSSDescriptionTrim($tit) . q~</title>
         <description>~ . RSSDescriptionTrim($ed) . q~</description>
         <category>~ . RSSDescriptionTrim($mn) . q~</category>
     </item>~;
   
     RSS_template();
     return;
} }
   
sub Send304NotModified { sub Send304NotModified {
   print "Status: 304 Not Modified\n\n";     print "Status: 304 Not Modified\n\n" or croak "$croak{'print'} 304"; 
   exit;    exit;
} }
   
sub RFC822Date { sub RFC822Date {
   # Takes a Unix timestamp and returns the RFC-822 date format  
   # of it: Sat, 07 Sep 2002 9:42:31 GMT     # Takes a Unix timestamp and returns the RFC-822 date format 
   my @GMTime = split(/ +/, gmtime(shift));     # of it: Sat, 07 Sep 2002 9:42:31 GMT 
   "$GMTime[0], $GMTime[2] $GMTime[1] $GMTime[4] $GMTime[3] GMT";     my @GMTime = split / +/sm, gmtime shift; 
     return "$GMTime[0], $GMTime[2] $GMTime[1] $GMTime[4] $GMTime[3] GMT";
} }
   
sub RSSDescriptionTrim { # This formats the RSS sub RSSDescriptionTrim {    # This formats the RSS
   my $x = $_[0];     my @x = @_; 
   
   $x =~ s/ (class|style)\s*=\s*["'].+?['"]//g;     $x[0] =~ s/ (class|style)\s*=\s*[\x22\x27].+?[\x27\x22]//gsm; 
   
   $x =~ s/&/&#38;/g;     $x[0] =~ s/&/&\x2338;/gsm; 
   $x =~ s/"/&#34;/g;     $x[0] =~ s/\x22/&\x2334;/gsm; 
   $x =~ s~'~&#39;~g;     $x[0] =~ s/\x27/&\x2339;/gsm; 
   $x =~ s/  / &#160;/g;     $x[0] =~ s/  / &\x23160;/gsm; 
   $x =~ s/</&#60;/g;     $x[0] =~ s/</&\x2360;/gsm; 
   $x =~ s/>/&#62;/g;     $x[0] =~ s/>/&\x2362;/gsm; 
   $x =~ s/\|/&#124;/g;     $x[0] =~ s/\|/&\x23124;/gsm; 
   $x =~ s/\{/&#123;/g;     $x[0] =~ s/\{/&\x23123;/gsm; 
   $x =~ s/\}/&#125;/g;     $x[0] =~ s/\}/&\x23125;/gsm; 
   
   $x;     return $x[0]; 
} }
   
sub shellaccess { sub shellaccess {
   # Parse the arguments  
   my($data, $i, %arguments);  
   
   for($i = 0; $i < @ARGV; $i++) {     # Parse the arguments 
       if($ARGV[$i] =~ /\A\-/) {     my ( $i, %arguments ); 
           my($option, $value);  
           $option = $ARGV[$i];  
           $option =~ s/\A\-\-?//;  
           ($option, $value) = split(/\=/, $option);  
           $arguments{$option} = $value || '';  
           unless(defined $arguments{$option}) {$arguments{$option} = 1;}  
       }  
   }  
   
   ### Requirements and Errors ###  
   $script_root = $arguments{'script-root'};  
   
   if (-e "Paths.pl") { require "Paths.pl"; }  
   elsif (-e "$script_root/Paths.pl") { require "$script_root/Paths.pl"; }  
   
   require "$vardir/Settings.pl";  
   require "$sourcedir/Subs.pl";  
   require "$sourcedir/DateTime.pl";  
   require "$sourcedir/Load.pl";  
   
   &LoadCookie;          # Load the user's cookie (or set to guest)  
   &LoadUserSettings;    # Load user settings  
   &WhatLanguage;        # Figure out which language file we should be using! :D  
   
   require "$boardsdir/forum.master";  
   require "$sourcedir/Security.pl";  
   
   # Is RSS disabled?  
   &RSS_error('rss_disabled') if $rss_disabled;  
   
   $gzcomp = 0; # Disable gzip so we can talk clearly  
   
   # Map %arguments to %INFO  
   foreach my $var (qw(action board catselect topics)) {  
       $INFO{$var} = $arguments{$var};  
   }  
   
   # Run the subroutine  
   require "$sourcedir/SubList.pl";  
   my $action = $INFO{'action'};  
   my ($file,$sub) = split(/&/, $director{$action});  
   if ($file eq 'RSS.pl') { &{$sub}(); }  
   exit;  
}  
   
1;  
   
__END__     for my $i ( 0 .. $#ARGV ) { 
         if ( $ARGV[$i] =~ /\A\-/sm ) {
# Sample subroutine to show how to use URL encoding             my ( $option, $value ); 
# If $_[1] is true, it fully encodes the text. If not, it just encodes non-word characters (\W).             $option = $ARGV[$i]; 
sub urlencode {             $option =~ s/\A\-\-?//xsm; 
   my($text, $mode) = ($_[0], $_[1]);             ( $option, $value ) = split /\=/xsm, $option; 
   #$text =~ s/(\W)/sprintf("%%%lx", ord($1));/eg; # Not good enough; doesn't make it 2 digits all the time             $arguments{$option} = $value || q{}; 
             if ( !$arguments{$option} ) { $arguments{$option} = 1; }
   ### "Real Perl Hackers Use 'pack'" (tm) - jbert on Perlmonks         } 
   if(!$mode) {$text =~ s/(\W)/'%' . unpack("H*", pack("C", ord($1)))/eg;}     } 
   elsif($mode) {$text =~ s/(.)/'%' . unpack("H*", pack("C", ord($1)))/eg;}  
   return $text;     ### Requirements and Errors ### 
     $script_root = $arguments{'script-root'};
   
     if ( -e 'Paths.pm' ) { require Paths; }
     elsif ( -e "$script_root/Paths.pm" ) { require "$script_root/Paths.pm"; }
   
     require Variables::Settings;
     require Sources::Subs;
     require Sources::DateTime;
     require Sources::Load;
   
     LoadCookie();        # Load the user's cookie (or set to guest)
     LoadUserSettings();  # Load user settings
     WhatLanguage();      # Figure out which language file we should be using! :D
   
     get_forum_master();
     require Sources::Security;
   
     # Is RSS disabled?
     if ($rss_disabled) { RSS_error('rss_disabled'); }
   
     $gzcomp = 0;         # Disable gzip so we can talk clearly
   
     # Map %arguments to %INFO
     for my $var (qw(action board catselect topics)) {
         $INFO{$var} = $arguments{$var};
     }
   
     # Run the subroutine
     require Sources::SubList;
     my $action = $INFO{'action'};
     my ( $file, $sub ) = split /&/xsm, $director{$action};
     if ( $file eq 'RSS.pm' ) { &{$sub}(); }
     exit;
} }
   
=pod  1; 
   
=head1 Command line usage  
   
To make it possible for most programming languages to easily get output from this script, we have a command line mode.  
To do this, simply run "$sourcedir/RSS.pl (ARGUMENTS)". The RSS feed will be sent to STDOUT.  
   
=head1 Command line arguments  
   
You must give at least one argument so we know we're running as a commandline script.  
   
All options are given delimited by equal signs, for instance:  
   
Sources/RSS.pl --action=RSS_board  
   
If you need to insert a character with a special meaning such as a space, equals sign, or percent sign: use the URL encoding format. The subroutine &urlencode found in this file should show how to encode properly.  
   
For true/false values, 0 is false and anything else is true (even without an option).  
   
=head2 Required argument  
   
=over 12  
   
=item C<--action>  
   
Action to run. This is the exact same as the actions found in SubList.pl that belong to this file.  
   
=back  
   
=head3 Optional argument  
   
=over 12  
   
=item C<--script-root>  
   
Changes the script root used to load Paths.pl from.  
   
=back  
   
=head2 Optional arguments for action=RSSrecent  
   
=over 12  
   
=item C<--catselect>  
   
Category to use for recent posts.  
   
=item C<--showauthor>  
   
Show the author's email address and name? Defaults to false. Working only if allowed by forum Admin  
   
=item C<--topics>  
   
Number of topics to show. Can be anywhere from 1 to 10, and it defaults to 5.  
   
=back  
   
=head2 Required arguments for action=RSSboard  
   
=over 12  
   
=item C<--board>  
   
Board ID to use.  
   
=back  
   
=head3 Optional arguments for action=RSSboard  
   
=over 12  
   
=item C<--showauthor>  
   
Show the author's name? Defaults to false.  
   
=item C<--topics>  
   
Number of topics to show. Can be anywhere from 1 to 10, and it defaults to 5.  
   
=back  
   
=cut