#! /usr/bin/perl
# Copyleft meh. [http://meh.doesntexist.org | meh.ffff@gmail.com]
# Released under the GNU General Public License v3

use strict;
use warnings;
use LWP::UserAgent;
use Getopt::Std;

my $version = "0.6.2";

my $agent = new LWP::UserAgent((user_agent => "pastebin/$version"));

my %languages = (
    text          => "None",
    abap          => "ABAP",
    actionscript  => "ActionScript",
    actionscript3 => "ActionScript 3",
    ada           => "ADA",
    apache        => "Apache Log",
    applescript   => "AppleScript",
    apt_sources   => "APT Sources",
    asm           => "ASM (NASM)",
    asp           => "ASP",
    autoit        => "AutoIt",
    avisynth      => "Avisynth",
    bash          => "Bash",
    basic4gl      => "Basic4GL",
    bibtex        => "BibTeX",
    blitzbasic    => "Blitz Basic",
    bnf           => "BNF",
    boo           => "BOO",
    bf            => "BrainFuck",
    c             => "C",
    c_mac         => "C for Macs",
    cill          => "C Intermediate Language",
    csharp        => "C#",
    cpp           => "C++",
    caddcl        => "CAD DCL",
    cadlisp       => "CAD LISP",
    cfdg          => "CFDG",
    klonec        => "Clone C",
    klonecpp      => "Clone C++",
    cmake         => "CMake",
    cobol         => "COBOL",
    cfm           => "ColdFusion",
    css           => "CSS",
    d             => "D",
    dcs           => "DCS",
    delphi        => "Delphi",
    dff           => "Diff",
    div           => "DIV",
    dos           => "DOS",
    dot           => "DOT",
    eiffel        => "Eiffel",
    email         => "Email",
    erlang        => "Erlang",
    fo            => "FO Language",
    fortran       => "Fortran",
    freebasic     => "FreeBasic",
    gml           => "Game Maker",
    genero        => "Genero",
    gettext       => "GetText",
    groovy        => "Groovy",
    haskell       => "Haskell",
    hq9plus       => "HQ9 Plus",
    html4strict   => "HTML",
    idl           => "IDL",
    ini           => "INI file",
    inno          => "Inno Script",
    intercal      => "INTERCAL",
    io            => "IO",
    java          => "Java",
    java5         => "Java 5",
    javascript    => "JavaScript",
    kixtart       => "KiXtart",
    latex         => "LaTeX",
    lsl2          => "Linden Scripting",
    lisp          => "LISP",
    locobasic     => "Loco Basic",
    lolcode       => "LOL Code",
    lotusformulas => "Lotus Formulas",
    lotusscript   => "Lotus Script",
    lscript       => "LScript",
    lua           => "Lua",
    m68k          => "M68000 Assembler",
    make          => "Make",
    matlab        => "MatLab",
    mirc          => "mIRC",
    modula3       => "Modula 3",
    mpasm         => "MPASM",
    mxml          => "MXML",
    mysql         => "MySQL",
    nsis          => "NullSoft Installer",
    oberon2       => "Oberon 2",
    objc          => "Objective C",
    'ocaml-brief' => "OCalm Brief",
    ocaml         => "OCaml",
    glsl          => "OpenGL Shading",
    oobas         => "Openoffice.org BASIC",
    oracle11      => "Oracle 11",
    oracle8       => "Oracle 8",
    pascal        => "Pascal",
    pawn          => "PAWN",
    perl          => "Perl",
    'php-brief'   => "PHP Brief",
    php           => "PHP",
    pic16         => "Pic 16",
    pixelbender   => "Pixel Bender",
    plsql         => "PL/SQL",
    povray        => "POV-Ray",
    powershell    => "Power Shell",
    progress      => "Progress",
    prolog        => "Prolog",
    properties    => "Properties",
    providex      => "ProvideX",
    python        => "Python",
    qbasic        => "QBasic",
    rails         => "Rails",
    rebol         => "REBOL",
    reg           => "REG",
    robots        => "Robots",
    ruby          => "Ruby",
    gnuplot       => "Ruby Gnuplot",
    sas           => "SAS",
    scala         => "Scala",
    scheme        => "Scheme",
    scilab        => "Scilab",
    sdlbasic      => "SdlBasic",
    smalltalk     => "Smalltalk",
    smarty        => "Smarty",
    sql           => "SQL",
    tsql          => "T-SQL",
    tcl           => "TCL",
    teraterm      => "Tera Term",
    thinbasic     => "thinBasic",
    typoscript    => "TypoScript",
    unreal        => "unrealScript",
    vbnet         => "VB.NET",
    verilog       => "VeriLog",
    vhdl          => "VHDL",
    vim           => "VIM",
    visualprolog  => "Visual Pro Log",
    vb            => "VisualBasic",
    visualfoxpro  => "VisualFoxPro",
    whitespace    => "WhiteSpace",
    whois         => "WHOIS",
    winbatch      => "Win Batch",
    xml           => "XML",
    xorg_conf     => "Xorg Config",
    xpp           => "XPP",
    z80           => "Z80 Assembler",
);

my $options = {};
getopts('hvLl:pn:e:d:Ac:', $options);

my $file = shift;

if ($options->{v}) {
    print Other::version(), "\n";
    exit;
}

if ($options->{h}) {
    print Other::usage();
    exit;
}

if ($options->{L} and not $options->{c} and not defined $file) {
    print Other::listLanguages();
    exit;
}

if (defined $file) {
    if ($file =~ m{^http://}) {
        if ($file =~ m{((\w+)\.)?pastebin\.com/(\w+)}) {
            my $domain = $1 || '';
            my $code   = $3;
    
            Other::output($domain, $code);
        }
        else {
            print "The url has to be a pastebin.com url.", "\n";
            exit;
        }
    }
    else {
        if (not -e $file) {
            print "The file doesn't exist.", "\n";
            exit;
        }

        open my $FILE, '<', $file;
        print Paste::send(
            Options::name(),
            Options::language(),
            Options::expire(),
            Options::domain(),
            Options::public(),
            Other::fetch($FILE)
        ), "\n";
        close $FILE;
    }
}
elsif ($options->{c}) {
    Other::output(Options::domain(), $options->{c});
}
else {
    print Paste::send(
        Options::name(),
        Options::language(),
        Options::expire(),
        Options::domain(),
        Options::public(),
        Other::fetch('STDIN')
    ), "\n";
}

package Options;

sub name {
    return $options->{n} || `whoami`;
}

sub language {
    my $lang = lc $options->{l} || return 'text';

    for my $language (keys %languages) {
        my $check = Other::escape($languages{$language});
        if ($lang =~ /^$language$/i or $lang =~ /^$check$/i) {
            return $language;
        }
    }

    print Other::listLanguages();
    print "\n", "These are the languages available.", "\n";
    exit;
}

sub expire {
    if (not defined $options->{e}) {
        return '1D';
    }

    if ($options->{e} eq '10') {
        return '10M';
    }
    elsif ($options->{e} eq 'hour' or $options->{e} eq 'h') {
        return '1H';
    }
    elsif ($options->{e} eq 'day' or $options->{e} eq 'd') {
        return '1D';
    }
    elsif ($options->{e} eq 'month' or $options->{e} eq 'm') {
        return '1M';
    }
    elsif ($options->{e} eq 'never' or $options->{e} eq 'f') {
        return 'N';
    }
    else {
        return '1D';
    }
}

sub domain {
    if ($options->{d}) {
        return $options->{d};
    }
    else {
        return '';
    }
}

sub public {
    if ($options->{p}) {
        return 1;
    }
    else {
        return 0;
    }
}

package Other;

sub usage {
    return <<USAGE
Usage: pastebin [options] [file | url]

Give to pastebin the file to upload or the url to download or instead use a pipe.

Options:
  Paste:
    -l LANG         Set the language (defaults to "None")
    -n NAME         Set the nick (defaults to your username)
    -e DATE         Sets the expire time (day, month, never) (defaults to day)
    -d DOMAIN       Sets the private domain (ie lol.pastebin.com)
    -p              Make the paste public (defaults to false)

  Get:
    -A              Shows the language of the viewed pastebin as header of the output
    -L              Shows the language of the pastebin
    -c CODE         Pass the pastebin code instead of the url
    -d DOMAIN       Domain where the code is pasted on

  Other:
    -h              Shows this help
    -v              Shows the version
    -L              Shows the supported languages
USAGE
}

sub version {
    return "pastebin $version";
}

sub escape {
    my @string = split //, shift;

    my $newString = "";
    for my $char (@string) {
        if ($char =~ /^\+|\[|\]|\-|\(|\)|\\$/) {
            $newString .= "\\";
        }

        $newString .= $char;
    }
    return $newString;
}

sub listLanguages {
    my $output = "Languages:\n";

    my $longest = 0;
    for my $language (keys %languages) {
        if (length $language > $longest) {
            $longest = length $language;
        }
    }

    for my $language (sort keys %languages) {
        $output .= "    $language"." "x($longest - length $language). " => $languages{$language}\n";
    }

    return $output;
}

sub fetch {
    my $pipe = shift;

    my $text;
    while (my $line = <$pipe>) {
        $text .= $line;
    }
    chomp($text);

    return $text;
}

sub output {
    my ($domain, $code) = @_;

    if ($options->{L} or $options->{A}) {
        print "Language: ", Get::language($domain, $code), "\n";

        if ($options->{L}) {
            exit;
        }
        
        if ($options->{A}) {
            print "----", "\n";
        }
    }

    print Get::text($domain, $code);
}

package Paste;

sub send {
    my ($name, $language, $expire, $domain, $public, $code) = @_;

    my $response = $agent->post(
        'http://pastebin.com/api_public.php',
        {
            paste_subdomain   => $domain,
            paste_private     => ($public) ? '0' : '1',
            paste_code        => $code,
            paste_name        => $name,
            paste_format      => $language,
            paste_expire_date => $expire
        }
    );

    return $response->content;
}

package Get;

sub language {
    my ($domain, $code) = @_;

    my $url = ($domain)
        ? "http://$domain.pastebin.com/$code"
        : "http://pastebin.com/$code";

    my $response = $agent->get($url);

    if ($response->is_success) {
        my $content = $response->content;
        $content =~ m{<title>(.*?) pastebin};
        my $lang = $1;
        
        if (not defined $lang) {
            return "Text";
        }
        else {
            return $lang;
        }
    }
    else {
        print "It has to be an existing pastebin.com url :(", "\n";
        exit;
    }
}

sub text {
    my ($domain, $code) = @_;

    my $url = ($domain)
        ? "http://$domain.pastebin.com/pastebin.php?dl=$code"
        : "http://pastebin.com/pastebin.php?dl=$code";
    
    my $response = $agent->get($url);

    if ($response->is_success) {
        return $response->content;
    }
    else {
        print "It has to be an existing pastebin.com url :(", "\n";
        exit;
    }
}

