#!/usr/bin/perl

use Net::SMTP;
use Getopt::Long;
use XML::Simple;
use Jabber::Connection;
use Jabber::NodeFactory;
use Jabber::NS qw(:all);
use Data::Dumper;
use strict;

$SIG{CHLD} = 'IGNORE';

my ($configfile, $verbose, %jabberemail, $c);

my (%config, $con);
 
GetOptions("config=s" => \$configfile, "verbose" => \$verbose);
$con = &getConfig($configfile);
$verbose && print "Initializing Program Parameters...";

$config{JABBER_IP}        = $con->{'jabber'}->{'ip'};
$config{JABBER_PORT}      = $con->{'jabber'}->{'port'};
$config{JABBER_SECRET}    = $con->{'jabber'}->{'secret'};
$config{JABBER_SERVER}    = $con->{'jabber'}->{'server_name'};
$config{JABBER_NAME}      = $con->{'jabber'}->{'jname'};
$config{JABBER_DOMAIN}    = $con->{'jabber'}->{'server_name'};
$config{JUD}              = $con->{'jabber'}->{'jud'};
$config{MAIL_NAME}        = $con->{'smtp'}->{'mail_name'};
$config{FROM_DOMAIN}      = $con->{'smtp'}->{'from_domain'};

if ($verbose) {
	print "Using these configuration options:\n";
	foreach (qw(JABBER_IP JABBER_PORT JABBER_SECRET JABBER_SERVER JABBER_NAME MAIL_NAME FROM_DOMAIN JABBER_DOMAIN JUD)) {
		printf "%-20s %s\n", $_, $config{$_};
	}
}


$verbose && print "Done!\n";
$verbose && print "Trying to connect to $config{JABBER_IP}:$config{JABBER_PORT}\/$config{JABBER_NAME}\n";

$c = new Jabber::Connection(
	server         => "$config{JABBER_IP}:$config{JABBER_PORT}",
	ns             => 'jabber:component:accept',
	localname      => $config{FROM_DOMAIN},
	log            => 1,
	debug          => 1);

die "oops: ".$c->lastError unless $c->connect();

$c->auth($config{JABBER_SECRET});

$verbose && print "Registering Callbacks\n";

$c->register_handler(
	message  => \&message_handler,
	presence => \&presence_handler,
	iq       => \&iq_handler);
	
$verbose && print "Connected to Jabber Server\n";

$c->start();

sub message_handler() {
	my ($node, $msg) = @_;
	my (%info, $to, $from, $type, $username);
	$to = $node->attr('to');
	$from = $node->attr('from');

	foreach (qw(body subject)) {
		if (defined($node->getTag($_))) {
			$info{$_} = $node->getTag($_)->data;
		} else {
			$info{$_} = "null";
		}
	}
	
	# rewrite to and from to be in smtp or jabber form
	($username) = ($to =~ /^(.*)?\@/);
	if ($username =~ /%/) {
		# this is jabber->smtp
		# modify the $to and do a lookup on $from
		# to = 'username%stmpdomain.com@jsmtp.jabber.com'
		($to = $username) =~ s/%/\@/;
		$from = findjudemail($from);
		$verbose && print "Jabber from '$from'\n  to smtp '$to'\n";
		$type = "SMTP";
	} else {
		# this is smtp->jabber
		# $to gets jsmtp taken out , have to modify $from
		my ($domain) = ($to =~ /\@(.*)$/);
		$to =~ s/\@jsmtp\./\@/;
		my ($toprefix) = ($from =~ /\/(.*)$/);
		$from = "$toprefix\@$domain";
		$verbose && print "SMTP from '$from'\n  to jabber '$to'\n";
		$type = "JABBER";
	}

	if ($verbose) {
		print "$type\n";
		print "to:   '$to'\nfrom: '$from'\n";
		foreach (keys %info) {
			printf "%-10s %s\n", $_, $info{$_};
		}
	}

	if ($type eq "SMTP") {
		my $headers = {
		  'To' => $to, 'From' => $from, 'Subject' => $info{'subject'} };
		sendmail($headers, $info{'body'}, $config{MAIL_NAME});
	} else {
		jabbersend($to, $from, $info{'subject'}, $info{'body'});
	}

	return;
}

sub sendmail() {
	my ($headers, $body, $mailserver) = @_;
	my ($smtp, $date);
	$date = localtime();
	$smtp = Net::SMTP->new($mailserver);
	$headers->{'Date'} = $date;
	$headers->{'X-Mailer'} = "Sent from Jabber SMTP client by Net::SMTP";
	$smtp->mail($headers->{'From'});
	$smtp->to($headers->{'To'});
	$smtp->data();
	# should send in order
	my @headerorder = qw(From To Subject Date);
	foreach (@headerorder) {
		next unless ($headers->{$_});
		$smtp->datasend("$_: $headers->{$_}\n");
		delete $headers->{$_};
	}
	foreach (keys %$headers) {
		$smtp->datasend("$_: $headers->{$_}\n");
	}
	$smtp->datasend($body);
	$smtp->dataend();
	$smtp->quit();
}

sub iq_handler() {
	my ($node, $msg) = @_;
	print "In iq_handler\n";
	print Dumper($node);
	return;
}

sub getConfig() {
	my $configfile = shift;
	die "Can't find configfile '$configfile'\n" unless (-f $configfile);
	my $ref = XMLin($configfile); # should check for error
	return $ref;
}

sub findjudemail() {
	my $nick = shift; # from in form 'username@jabber.com/work'

	$verbose && print "Looking up email for '$nick'\n";
	$nick =~ s/\@.*$//;
	$verbose && print "  (modified to '$nick')\n";

	if (defined($jabberemail{$nick})) {
		my $email = $jabberemail{$nick};
		$verbose && print "Found '$email' in cache, returning...\n";
		return $email;
	}

	$verbose && print "Didn't find in caching, have to look for it in $config{JABBER_SERVER}\n";

	my ($jud, $nf, $c, $iq, $query, $result, $node, $email);
	$jud = $config{JUD};
   $nf = new Jabber::NodeFactory;
   $c = new Jabber::Connection( server  => $config{JABBER_SERVER});
   $c->connect or die "Cannot connect";
   $c->auth('smtp','smtp','Work');

   $iq = $nf->newNode('iq');
   $iq->attr('type', 'set');
   $iq->attr('to', $jud);

   $query = $iq->insertTag('query', NS_SEARCH);
   $query->insertTag('nick')->data($nick);
	if ($verbose) {
		print "QUERY #" x 30 . "\n";
	   print Dumper($query);
		print "IQ    #" x 30 . "\n";
	   print Dumper($iq);
	}
   $result = $c->ask($iq);
	$verbose && print Dumper($result);
   $node = $result->getTag('query','jabber:iq:search')->getTag('item');
   $c->disconnect;
   $email = $node->getTag('email')->data;
	$jabberemail{$nick} = $email;
   return $email;
}

sub jabbersend() {
	my ($to, $from, $subject, $body) = @_;
	my ($nf, $msg);
	$verbose && print "Sending jabber message to '$to' from '$from'\n";
   $nf = new Jabber::NodeFactory;

   $msg = $nf->newNode('message');
   $msg->attr('to', $to);
   $msg->attr('from', $from);
	$msg->insertTag('body')->data($body);
	$msg->insertTag('subject')->data($subject);
	$c->send($msg);
}
