# Blosxom Plugin: writebackplus
# Author(s): Rael Dornfest <rael@oreilly.com>
#		Fletcher T. Penney <http://fletcher.freeshell.org>
# Documentation: See the bottom of this file or type: perldoc writeback
# Based on original writeback plugin by Rael Dornfest <rael@oreilly.com>

package writeback;

# This plugin is created as a replacement for Rael Dornfest's original writeback 
# plugin. It adds several new features, improves ease of use, and in general,
# attempts address the comments and feedback from users of the original writeback
# plugin.

# This program would not be possible without Rael's original version, and as much of
# the code from the original that could be re-used was.  I simply attempted to make a
# few updates to his work.

# --- Configurable variables -----

# Where should I keep the writeback hierarchy?
# I suggest: $writeback_dir = "$blosxom::plugin_state_dir/writeback";
#
# NOTE: By setting this variable, you are telling the plug-in to go ahead
# and create a writeback directory for you.
my $writeback_dir = "$blosxom::plugin_state_dir/writeback";

# What flavour should I consider an incoming trackback ping?
# Otherwise trackback pings will be ignored!
my $trackback_flavour = "trackback";

# What file extension should I use for writebacks? 
# Make sure this is different from that used for your Blosxom weblog
# entries, usually txt.
my $file_extension = "wb";

# What fields are used in your comments form and by trackbacks?
my @fields = qw! name url date title comment excerpt blog_name ip !;

# --------------------------------

# Comments for a story; use as $writeback::writebacks in flavour templates
$writebacks;

# Count of writebacks for a story; use as $writeback::count in flavour templates
$count;

# The path and filename of the last story on the page (ideally, only 1 story
# in this view) for displaying the trackback URL;
# use as $writeback::trackback_path_and_filename in your foot flavour templates
$trackback_path_and_filename;

# Response to writeback; use as $writeback::writeback_response in 
# flavour templates
$writeback_response;

# Response to a trackback ping; use as $writeback::trackback_response in
# head.trackback flavour template
$trackback_response =<<'TRACKBACK_RESPONSE';
<?xml version="1.0" encoding="iso-8859-1"?>
<response>
<error></error>
<message></message>
</response>
TRACKBACK_RESPONSE
 
# --------------------------------

use CGI qw/:standard/;
use FileHandle;

my $fh = new FileHandle;

	# Added for spam protection
	my $email = '[\w\.\-]+@([\w\-]+\.)+[\w]+';

# Strip potentially confounding bits from user-configurable variables
$writeback_dir =~ s!/$!!; $file_extension =~ s!^\.!!;

# Save Name and URL/Email via cookie if the cookies plug-in is available
$cookie;

sub start {

  # $writeback_dir must be set to activate writebacks
  unless ( $writeback_dir ) { 
    warn "blosxom : writeback plugin > The \$writeback_dir configurable variable is not set; please set it to enable writebacks. Writebacks are disabled!\n";
    return 0;
  }

  # the $writeback_dir exists, but is not a directory
  if ( -e $writeback_dir and ( !-d $writeback_dir or !-w $writeback_dir ) ) { 
    warn "blosxom : writeback plugin > The \$writeback_dir, $writeback_dir, must be a writeable directory; please move or remove it and Blosxom will create it properly for you.  Writebacks are disabled!\n";
    return 0;
  }
  
  # the $writeback_dir does not yet exist, so Blosxom will create it
  if ( !-e  $writeback_dir )  {

    my $mkdir_r = mkdir("$writeback_dir", 0777);

    warn $mkdir_r 
      ? "blosxom : writeback plugin > \$writeback_dir, $writeback_dir, created.\n"
      : "blosxom : writeback plugin > There was a problem creating your \$writeback_dir, $writeback_dir. Writebacks are disabled!\n";

    $mkdir_r or return 0;

    my $chmod_r = chmod 0777, $writeback_dir;

    warn $chmod_r 
      ? "blosxom : writeback plugin > \$writeback_dir, $writeback_dir, set to 0755 permissions.\n"
      : "blosxom : writeback plugin > There was a problem setting permissions on \$writeback_dir, $writeback_dir. Writebacks are disabled!\n";

    $chmod_r or return 0;

    warn "blosxom : writeback plugin > writebacks are enabled!\n";
  }

  $path_info = CGI::path_info();
  my($path,$fn) = $path_info =~ m!^(?:(.*)/)?(.*)\.$blosxom::flavour!;
  $path =~ m!^/! or $path = "/$path";
  $path = "/$path";

  # Only spring into action if POSTing to the writeback plug-in
  if ( request_method() eq 'POST' and (param('plugin') eq 'writeback' or $blosxom::flavour eq $trackback_flavour) ) {

    foreach ( ('', split /\//, $path) ) {
      $p .= "/$_";
      $p =~ s!^/!!;
      -d "$writeback_dir/$p" or mkdir "$writeback_dir/$p", 0777;
	chmod (0777,"$writeback_dir/$p");
    }

    if ( $fh->open(">> $writeback_dir$path/$fn.$file_extension") ) {
      foreach ( @fields ) {
        my $p = param($_);
        if ( $_ == "url" ) {
        	$p =~ s/^($email)/mailto:$1/;
        }
        $p =~ s/\r?\n\r?/\r/mg;
        
        if ( $_ eq "ip" ) {
        	$p = $ENV{'REMOTE_ADDR'};
        }
        
        if ( $_ eq "date" ) {
        	my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time());
			$year += 1900;
			$mon += 1;
			$hour = sprintf("%02d",$hour);
			$min = sprintf("%02d",$min);
			$sec = sprintf("%02d",$sec);

        	$p = "$mon/$mday/$year $hour:$min:$sec";
        }
        
        if ( $_ eq "comment" ) {
        	# Convert all "$" to web-safe version to prevent accidentally ( or 
        	# purposefully) including variables in comments that crash blosxom
        	$p =~ s/\$/&#36;/g;
  
        	$p =~ s/<(?!(\/?(p|br)\/?))/&lt;/g;
        
        }
        
        print $fh "$_: $p\n";
      }
      print $fh "-----\n";
      $fh->close();
      chmod (0777,"$writeback_dir$path/$fn.$file_extension");

      $trackback_response =~ s!<error></error>!<error>0</error>!m;
      $trackback_response =~ s!<message></message>\n!!s;
      $writeback_response = "Thanks for the comment!<br>";

      # Make a note to save Name and URL/Email if save_preferences checked
      param('save_preferences') and $cookie++;
      # Pre-set Name and URL/Email based on submitted values
      $pref_name = param('name') || '';
      $pref_url = param('url') || '';

    } else {
      warn "couldn't >> $writeback_dir$path/$fn.$file_extension\n";

      $trackback_response =~ s!<error></error>!<error>1</error>!m;
      $trackback_response =~ s!<message>trackback error</message>!!m;
      $writeback_response = "There was a problem posting your comment.";
    }
  }
  1;
}

sub story {
  my($pkg, $path, $filename, $story_ref, $title_ref, $body_ref) = @_;
    
  $path =~ s!^/*!!; $path &&= "/$path";

  ($writebacks, $count)  = ('', 0);
  my %param = ();

  # Prepopulate Name and URL/Email with cookie-baked preferences, if any
  if ( $blosxom::plugins{cookies} > 0 and my $cookie = &cookies::get('writeback') ) {
    $pref_name ||= $cookie->{'name'};
    $pref_url ||= $cookie->{'url'};
  }

  if ( $fh->open("$writeback_dir$path/$filename.$file_extension") ) {
    foreach my $line (<$fh>) {
      $line =~ /^(.+?): (.*)$/ and $param{$1} = $2;
      if ( $line =~ /^-----$/ ) {

        my $writeback = &$blosxom::template($path,'writeback',$blosxom::flavour) || '<p><b>Name/Blog:</b> $writeback::name$writeback::blog_name<br /><b>URL:</b> $writeback::url<br /><b>Title:</b> $writeback::title<br /><b>Comment/Excerpt:</b> $writeback::comment$writeback::excerpt</p>';

        $writeback =~ s/\$writeback::(\w+)/$param{$1}/ge;
        $writebacks .= $writeback;
        $count++;
      }
    }

	# Added for spam protection
	
	while ($writebacks =~ /($email)/ig) {
		$original=$1;
		$masked="";
		@decimal = unpack('C*', $original);
		foreach $i (@decimal) {
			$masked.="&#".$i.";";
		}
		$writebacks =~ s/$original/$masked/ig;
	}
	
  }

  $trackback_path_and_filename = "$path/$filename";

  1;
}

sub head {
  $blosxom::plugins{cookies} > 0 and $cookie and &cookies::add(
    cookie(
          -name=>'writeback', 
          -value=>{ 'name' => param('name'), 'url' => param('url') }, 
          -path=>$cookies::path,
          -domain=>$cookies::domain,
          -expires=>$cookies::expires
    )
  );
}

1;

__END__

