#!/usr/bin/perl -w
use strict;
use Digest::MD5 qw/md5_hex/;
use File::Temp qw/tempfile/;
use Net::Ping;
use Getopt::Long;
use XMLRPC::Lite;
use Data::Dumper;
use IPC::Open2;

#customize these if needed
my $home = $ENV{'HOME'};
my $tempdir = "$home/jobs";
my $me = "$home/bin/ljpost.pl";

# post LJ entries
# reads either from the file as last argument or from stdin
# options: --canfail means it's OK to fail and not create a
# delayed job.

# first in text come options:
# to: where to post name (default: my journal)
# priv: private, public, friends (default: public)
# subj/subject: subject
# mood/music: currents.

# subject can also be the first line of the rest of the text
# if the second line is whitespace

# text is in utf-8.

my @input;
my $status;

my $canfail = 0;
my $hardfail = 0;

GetOptions('canfail'=>\$canfail);

sub out {
    my $code = shift;
    print "$status\n";
    # if we can't fail, we must delay
    exit $code if $canfail || $hardfail;
    exit $code if $code == 0;
    print "[delayed: " . delay() . "]\n";
    exit 0;
}

sub delay {
    my ($fh,$name) = tempfile("ljpostXXXXXX", DIR => $tempdir);
    print $fh <<END;
#!/bin/bash
$me --canfail <<'DELIM-$name'
END
    for (@input) { print $fh $_; }
    print $fh "DELIM-$name\n";
    print $fh <<END;
if [ "\$?" -eq "0" ]; then
  cp \$0 /tmp/
  echo "[removing \$0]"
  rm \$0
  exit 0
else
  exit 1
fi
END
    close $fh;
    chmod 0755, $name;
    return $name;
}

sub net {
    my $p = Net::Ping->new();
    return $p->ping("www.livejournal.com");
}
 
@input = <>;
my ($subject, $body, $to, $music, $mood, $priv);

my $inbody = 0;
my $options = {
    to => \$to,
    priv => \$priv,
    subject => \$subject,
    subj => \$subject,
    mood => \$mood,
    music => \$music
};

my @lines = @input;
while ($_ = shift @lines) {
  $body .= $_, next if $inbody;
  ${$options->{$1}} = $2, next 
      if m!^(\w+):\s*(\S.+)*$! && $options->{$1};
  # empty line(s) between options and subject/body
  next if m!^\s*$!;
  # an initial line with an empty lines following it is a subject
  $subject = $_, next
      if @lines and $lines[0]=~m!^\s*$! and not defined $subject;
  $inbody = 1;
  unshift @lines, $_;
  next;
}

$body ||= "";

# consider a $ sign alone on a line as a stop sign
$body =~ s/^\$\n.*//sm;

# lose initial and final newline(s) in the body
$body =~ s/^(\n)+//s;
$body =~ s/(\n)+$//s;

$status = "[empty body]", $hardfail = 1, out(1)
    unless $body;

$status = "[no net]", out(1)
    unless net();

# markdown!
my($min, $mout, $pid);
$pid = open2($min, $mout, "markdown");
{
    local $/;
    print $mout $body;
    close $mout;
    $body = <$min>;
    close $min;
    waitpid $pid, 0;
}

$status = "[markdown failed]", out(1)
    unless $body;

# post
my $uri = "http://www.livejournal.com/interface/xmlrpc/";
my ($user, $pwd) = ("avva", "yeah_right");

my $itemid;

eval {
    my ($rpc, $out, $chal, $resp);
    $rpc = XMLRPC::Lite->proxy($uri);

    # challenge
    my $challenge = sub {
    	$out = $rpc->call("LJ.XMLRPC.getchallenge")->result;
    	$chal = $out->{challenge};
    	die "no challenge\n" unless $chal;
    	$resp = md5_hex($chal . md5_hex($pwd));
    };

    # login
    $challenge->();
    # preved!
    $out = $rpc->call("LJ.XMLRPC.login", {
        ver => 1,
        auth_method => 'challenge',
        username => $user,
        auth_challenge => $chal,
        auth_response => $resp,
    })->result;
    die "login failed\n" unless $out->{userid};

    # postevent
    $challenge->();

    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
        localtime(time);

    my $props = { opt_preformatted => 1 };
    $props->{'current_mood'} = $mood if $mood;
    $props->{'current_music'} = $music if $music;

    my $request = {
        ver => 1,
        auth_method => 'challenge',
        username => $user,
        auth_challenge => $chal,
        auth_response => $resp,
        event => $body,
        lineendings => 'unix',
	year => $year+1900,
	mon => $mon+1,
	day => $mday,
	hour => $hour,
	min => $min,
	props => $props,
    };
    $request->{'usejournal'} = $to if $to;
    $request->{'subject'} = $subject if $subject;
    if ($priv) {
        $request->{'security'} = "public" 
            if $priv =~ m!^(pub|public)$!;
        $request->{'security'} = "private"
            if $priv =~ m!^(pr|priv|private)$!;
        $request->{'security'} = "usemask", $request->{allowmask} = 1
            if $priv =~ m!^(fr|friend|friends)$!;
    }

    my $r = $rpc->call("LJ.XMLRPC.postevent", $request);
    #print Dumper($r);
    $out = $r->result;
    #print Dumper($out); 
    die "postevent failed\n" unless $out->{itemid};
    $itemid = $out->{itemid}*256+$out->{anum};
};

if ($@) { 
    chomp $@;
    print "[failure: " . substr($@, 0, 80) . "]\n";
    $status = "[failed to post]";
    out(1);
}

$status = "[OK: $itemid]"; out(0);

