package PasteBot;
use strict;
use warnings;
no warnings qw(redefine);
use Digest::MD5 qw();
use File::Type;
use File::Slurp;
use Text::VimColor;
use FindBin;
use Apache2::RequestRec ();
use Apache2::RequestIO ();
use Apache2::Reload;
use Apache2::Const -compile => qw(OK FORBIDDEN NOT_FOUND);
use APR::Request::Apache2;
use APR::Table;
my $storage_path = $ENV{PASTEBOT_STORAGE_DIR};
unless ( defined $storage_path ) {
$storage_path = '/tmp/paste';
mkdir $storage_path unless -d $storage_path;
}
my $filetype_for = {
'text/html' => 'html',
};
sub get_params {
my $apr = shift;
my $params = {};
foreach my $key ( $apr->param ) {
my @values = $apr->param($key);
$params->{$key} = @values == 1 ? $values[0] : \@values;
}
return $params;
};
sub handler {
my $r = shift;
my $apr = APR::Request::Apache2->handle($r);
my $get = scalar($apr->args);
my $post = scalar($apr->body);
my $args = scalar($apr->param);
if ( $r->method eq 'POST' and exists $post->{text} ) {
my $digest = substr Digest::MD5::md5_hex($post->{text}), 26;
write_file($storage_path . '/' . $digest, $post->{text});
if (defined $post->{filetype} and $post->{filetype} =~ /\S/) {
write_file($storage_path . '/' . $digest . '.filetype', $post->{filetype});
}
$r->headers_out->add('Location' => 'http://' . $r->hostname . '/' . $digest);
$r->status(303);
}
elsif ( $r->uri eq '/' ) {
$r->content_type('text/html');
home_page($r);
}
elsif ( $r->uri =~ m{^/([a-z0-9]{6})(.txt)?$} and -f $storage_path . '/' . $1 ) {
my $contents = read_file($storage_path . '/' . $1);
if ( $2 ) {
$r->content_type('text/plain');
print $contents;
}
else {
my $mimetype = File::Type->new->checktype_contents($contents);
my $filetype = $get->{filetype};
$filetype ||= read_file($storage_path . '/' . $1 . '.filetype') if -f $storage_path . '/' . $1 . '.filetype';
$filetype ||= $filetype_for->{$mimetype};
my $syntax = Text::VimColor->new(
string => $contents,
html_full_page => 1,
filetype => $filetype,
);
$r->content_type('text/html');
print $syntax->html;
}
}
elsif ( $r->uri eq '/source' or $r->uri eq '/source.txt' ) {
my $contents = read_file($INC{__PACKAGE__ . '.pm'});
if ( $r->uri eq '/source' ) {
my $syntax = Text::VimColor->new(
string => $contents,
html_full_page => 1,
filetype => 'perl',
);
$r->content_type('text/html');
print $syntax->html;
}
else {
$r->content_type('text/plain');
print $contents;
}
}
else {
$r->status(404);
return Apache2::Const::NOT_FOUND;
}
return Apache2::Const::OK;
}
sub home_page {
my $r = shift;
print(q|<html>
<head>
<style type="text/css">
textarea {
width: 100%;
height: 50%;
}
</style>
<title>paste.dollyfish.net.nz</title>
</head>
<body onload="document.f.text.focus()">
<form method="post" name="f">
<input type="submit" value="Paste">
<textarea name="text"></textarea>
<input type="submit" value="Paste">
|);
if ( -f '/usr/share/vim/vimcurrent/synmenu.vim' ) {
print q{<select name="filetype">};
print q{<option value="">Automatic Detection</option>};
foreach my $line ( read_file('/usr/share/vim/vimcurrent/synmenu.vim') ) {
next unless ( my ( $syntax, $filetype ) = $line =~ /Syntax.[\w-]+\.(.*) :cal SetSyn\("(.*?)"/ );
$syntax =~ s/\\ / /g;
print '<option value="' . $filetype . '">' . $syntax . '</option>';
}
print q{</select>};
}
print(q|
</form>
<hr>
<p>
Checkout the <a href="http://dollyfish.net.nz/projects/pastebot">PasteBot homepage</a>
, or <a href="source">source code</a> powering this instance.
</p>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-1416732-4");
pageTracker._initData();
pageTracker._trackPageview();
</script>
</body>
</html>
|);
}
1;
=head1 Apache Configuration
ServerName paste.dollyfish.net.nz
<Perl>
use lib '/path/to/libdir';
</Perl>
PerlSetEnv PASTEBOT_STORAGE_DIR /path/to/storage
<Location />
SetHandler perl-script
PerlHandler PasteBot
</Location>
=cut