#!/usr/bin/perl

# moblog.pl - a mail to movabletype gateway for use with moblogging, mostly.
# GPL v2 license -- see http://www.gnu.org/licenses/gpl.html
# Portions (heavily) inspired by Ben Compton.  Thanks Ben.
# The rest by Jason Costomiris <jcostom {at} jasons {dot} org>

# If you're going to use this for real, please, add some error checking.
# I was lazy the day I wrote this..

# There is no warranty here.  It works for me.  If it doesn't work for you,
# or does bad things, I take no responsibility, nor does Ben.

# This works with Wordpress, or at least with my WP 1.5.x installation.
# As always, YMMV.

use strict;
use MIME::Parser;
use MIME::Entity;
use Data::Dumper;
use XMLRPC::Lite;
use Image::Magick;

# create configuration array
my %config = (
	"tmpdir"	=> "/var/tmp", # or other tmp dir
	"urldir"	=> "/your-image-upload-dir", # dir writeable by server
	"attachdir"	=> "/",   # this is relative to urldir
	"blogid"	=> 1,
	"user"		=> "your-username",
	"pass"		=> "your-password",
	"proxyurl"	=> "http://www.yoursite.org/xmlrpc.php",
	"catid"		=> 17 # replace with your numeric cat id value!
);

# initialize some vars we'll use
my ($subject, @uploaded_img_names, @post_img_names);

# Make with the parsing, etc..
my $parser = new MIME::Parser;
$parser->output_dir($config{tmpdir});
my $entity = $parser->parse(\*STDIN);
$subject = getSubject($entity);
my %data = parseEntity($entity);

# upload the files
foreach my $attachment (@{ $data{attachments} }){
	uploadFile($attachment);
}

# post to the moblog
submitPost(@post_img_names, $data{'bodyText'});

# clean up the mess we made..
$entity->purge;



sub getSubject{
	my $mimeEntity = shift;
	my $head = $mimeEntity->head;
	chomp($subject = $head->get('subject',0));
	return $subject;
}

sub parseEntity { 
    my $mimeEntity = shift;

    my @attachments;
    my $body;

    # Handle the non-multipart messages
    if($mimeEntity->parts == 0) {
        $body = $mimeEntity->bodyhandle->as_string;
    }

    foreach my $part ($mimeEntity->parts) {
	my $bodyHandle = $part->bodyhandle;

	if (!defined($bodyHandle)) {
	    # could be a multipart/mixed message, which is what I get
	    # when I email with a pgp sig attachment. Now, you know,
	    # there are way too many variations on how the messages
	    # can be structured for me to handle any large number of
	    # cases. So I'm just going to handle the simple cases and
	    # this special case for myself.
	    if ($part->mime_type eq 'multipart/mixed') {
		# recursive call! 
		return parseEntity($part);
	    } else { 
		next;
	    }
	}

	# We only care about text/plain parts and image/* parts.
	# We'll assume we can deal with any image/* mime type.  Maybe
	# this should be changed to do something more interesting like
	# decide to choose the text/html portion over the text/plain
	# portion if available. I'm planning on just putting html in
	# my text/plain emails if I want the post to be HTMLified.
	if ($part->mime_type eq 'text/plain') {
	    $body .= $bodyHandle->as_string;
#	} elsif ($part->mime_type eq 'text/html') {
#	    print "HTML! " . $bodyHandle->as_string;
	} elsif ($part->mime_type =~ /^image/ || 
		 $part->mime_type eq 'application/octet-stream') {
	    # push the whole MIME::Body object into the array.. this is a
	    # useful structure to pass the file around in
	    push @attachments, $bodyHandle;
	} 
    }

    # get rid of the stupid cingular message
    my @bodySplit = split /^=+$/m, $body, 2;

    return (bodyText => $bodySplit[0], 
	    attachments => \@attachments);
}

sub uploadFile {
	my $attachment = shift;
	my $bits;
	{
		my $handle = $attachment->open('r');
		local($/) = undef;
		$bits = $handle->getline;
		$handle->close();
	}
	my ($ext) = ($attachment->path =~ /\.(\w+)$/);
	my $rand = int(rand(2**24));
	my $randfile = "$$.$rand.$ext";
	my $ulimgname = "$config{attachdir}/$randfile";
	push @uploaded_img_names, $ulimgname;

	my $urlimgname = "$config{urldir}/$randfile";
	push @post_img_names, $urlimgname;

	my $rpCaller = new XMLRPC::Lite;
	my $result = $rpCaller
		->proxy($config{proxyurl})
		->call('metaWeblog.newMediaObject',
				$config{blogid},
				$config{user},
				$config{pass},
				{
					'bits' => $bits,
					'name' => "$ulimgname",
					'type' => 'ignored'
				},
		  );
}

sub submitPost {
	my @images = shift;
	my $bodyText = shift;
	my $desc;
	$subject ||= "this just in...";

	# If you want to format the post differently, or make use of
	# $bodyText, this would be the place to do it.
	# That is, $desc is the body of your post, format it as you 
	# like it.  My formatting uses Textile, so YMMV.

	foreach my $img (@images){
		$desc .= "!$img($subject)!";
	}
	my $rpCaller = new XMLRPC::Lite;
	my $result = $rpCaller
		->proxy($config{proxyurl})
		->call('metaWeblog.newPost', 
				$config{blogid}, 
				$config{user}, 
				$config{pass},
				{
					'title' => "$subject",
					'description'	=> "$desc",
					'mt_allow_comments'     => 1,
					'mt_allow_pings'        => 1
				},
		1)
		->result;

	# Set Category to cat id defined above
	my @categories;
	$categories[0] = [{ 'categoryId' => $config{catid} }];
	my $catResult = $rpCaller
		->proxy($config{proxyurl})
		->call('mt.setPostCategories',
			$result,
			$config{user},
			$config{pass},
			@categories);
}
