#!/usr/bin/perl -w
#
# irssi to jabber notifier
# (c) 2008 Jakub Kolasa
#
# $Revision: 1.4 $
# $Author: jezik $
#
# ChangeLog:
#
# 0.1 - initial, beta testing
# 0.2 - fixed MSGLEVEL to prevent sending own messages to jabber
# 0.3 - connections based on timer (thx to PaSzCzUs for hint)
# 0.4
#	  - connection timeout for locking up slow connections
#	  - reconnect based on jabber_autostart variable
#	  - bugfix in timer connection method (can occure too short delay)
#	  - fixed jabber stop and disconnect methods (thx to shadzik for pointing that)
#	  - added variable jabber_reconnect
#	  - added unload signal handling
#	  - added jabber_help command
#	  - added jabber_status command
# 0.4.1
#	  - fixed problem with resource priority
#     - added status of jabber
#
#
# KNOWN BUGS:
#	irssi can freez when connection, timeout is set to 5sec. Problem is in
#	Net::Jabber, which does not support ASYNC/NONBLOCKING connections.
#	Also, in some tests Net::Jabber do not show disconnect status, when
#	packets are droped (strange), but reconnects itself when connection
#	is back (more strange for me).
#


use strict;
use Irssi;
use Irssi::Irc;
use vars qw($VERSION %IRSSI);
use Net::Jabber qw(Client);
use Data::Dumper;

$VERSION = "0.4.1";
%IRSSI = (
    authors     => 'Jakub Kolasa',
    contact     => 'jezik@arker.pl',
    name        => 'irssijabbernotify',
    description => 'Jabber Hilight Forwarder',
    license     => 'GNU GPLv2 (not v3+)',
    url         => 'http://www.arker.pl/j/irssi/',
    changed     => '$Revision: 1.4 $'
);

my $jid=undef;
my $jid_connect=1;
my $jid_status=0;

my $flood_time=time();
my $flood_counter=0;

#retry to connect every 30sek
my $jid_timer_interval=10;

#last connect try
my $jid_connect_time=0;

#prio testing
my $jabber_prio=100;

sub cmd_help() {

Irssi::print($IRSSI{name}." ".$VERSION."
VARIABLES:
    jabber_login
    jabber_server
    jabber_password
        - your jabber account settings
    jabber_roster
        - your destination jabber roster
    jabber_reconnect
        - reconnecting delay (0 == disabled)
    jabber_flood_max
    jabber_flood_time_max
        - flood protection settings
COMMANDS:
    /start_jabber
        - start jabber connection (allow connection)
    /stop_jabber
        - stop jabber");
};

sub cmd_status()
{
	Irssi::print("Jabber Client ON: ".($jid_connect>0 ? 'YES' : 'NO'));
	if ($jid)
	{
		Irssi::print("Jabber Client Instance: YES");
		Irssi::print("Jabber Client ON-LINE: ".($jid && $jid->Connected() ? 'YES' : 'NO'));
	}
	Irssi::print("Jabber Client STATUS: ".($jid_status>0 ? 'BUSY' : 'IDLE')); #for future purpose
	Irssi::print("Jabber Client Last Connection time: ".($jid_connect_time>0 ? (time()-$jid_connect_time)." sec ago" : "NEVER")); #for future purpose
};

sub event_msg
{
	my ($dest, $text, $stripped) = @_;
    my $server = $dest->{server};
	my $away=defined $server->{usermode_away};
	my $target=$dest->{target};
	my $type=undef;
	my $ok;
	my $msg;
	my $ct;

	unless ($away) {return;};

	$ok=($away &&
		(
		(($dest->{level} & MSGLEVEL_MSGS) && (!($dest->{level} & MSGLEVEL_NOHILIGHT)))
		||
		($dest->{level} & MSGLEVEL_HILIGHT)
		));

	unless ($ok) { return;};

	$flood_counter++;

	$ct=time();

	#reset flood counter, if needed
	if (($ct-$flood_time)>Irssi::settings_get_int('jabber_flood_time_max'))
	{
		$flood_counter=1;
		$flood_time=$ct;
	};

	if ($flood_counter>Irssi::settings_get_int('jabber_flood_max'))
	{
		return 0;
	};

	$type="PRIVMSG" if ($dest->{level} & MSGLEVEL_MSGS);
	$type="PUBLIC" if ($dest->{level} & MSGLEVEL_PUBLIC);
	$type="GENERAL" unless defined $type;



	$msg=$target."/".$type.'::'.$stripped;

	#send chat to roster, if avail
	if (checkconnect())
	{
		_jidSend(Irssi::settings_get_str('jabber_roster'),'chat', $msg);

	};
};

sub event_unload
{
	Irssi::print("You killed Kenny! You bastards!");
	$jid_connect=0;
	$jid_status=0;
	if ($jid) { $jid->Disconnect();};
	undef($jid);
	$jid=undef;
};

sub _jidMessage
{

};

sub _jidSend
{
	my ($to,$type,$body)=@_;

	unless ($jid) { return 0;};

	if ($to eq '')
	{
		Irssi::print("Jabber: Empty jabber_roster");
		return 0;
	};

	if ($to=~/[a-z\-_]+@([a-z\-_]+\.)+[a-z]+/i)
	{
		$jid->MessageSend(to=>$to, type=>$type, body=>$body);
		return 1;
	};
	Irssi::print("Jabber: Illegal roster");
	return 0;
};

sub jid_timer
{
	my @ret;

	#already connecting or sth?
	if ($jid_status>0) { return;};

	$jid_status=1;
	if (($jid_connect<=0) && ($jid))
	{
		Irssi::print("Jabber disconnection...");
		$jid->Disconnect();
		undef($jid);
		$jid=undef;
		$jid_status=0;
		return;
	};

	unless ($jid_connect>0)
	{
		$jid_status=0;
		return;
	};

	if ($jid)
	{
		if ($jid->Connected())
		{
			$jid_status=0;
			return;
		};
	};

	#reconnects allowed or reconnect once?
	if ($jid_connect==1)
	{
		if (Irssi::settings_get_int('jabber_reconnect')<=0)
		{
			$jid_status=0;
			return;
		};
	}else
	{
		$jid_connect=1;
	};


	#is it a reconnect time?
	if ((time()-$jid_connect_time) < Irssi::settings_get_int('jabber_reconnect'))
	{
		$jid_status=0;
		return ;
	};

	undef($jid);
	$jid=undef;

	$jid_connect_time=time();

	$jid=new Net::Jabber::Client(
		debuglevel=>2,
		debugfile=>'/tmp/irssi.log',
		debugtime=>1,
	);
	$jid->SetCallBacks("message" => \&_jidMessage);

	Irssi::print("Jabber: Connecting...");
	$jid->Connect(hostname=>Irssi::settings_get_str('jabber_server'),timeout=>5);
	unless ($jid->Connected())
	{
		my $err = $jid->GetErrorCode();
		Irssi::print("Jabber: Could not connect: ". $err->{text});
		$jid_status=0;

		return;
	};

	$jid_status=2;
	Irssi::print("Jabber: Connected. Authorizing...");
	@ret=$jid->AuthSend(username=>Irssi::settings_get_str('jabber_login'),
						password=>Irssi::settings_get_str('jabber_password'),
						resource=>'irc',
						priority=>$jabber_prio
						);

	if ($ret[0] eq 'ok')
	{
		$jid->PresenceSend(priority => -1,
							show => 'dnd',
                           	status => 'IRC Notify.');
		Irssi::print("Jabber: Connected and authorized.");
		$jid_status=0;
		return ;
	}else
	{
		Irssi::print("Jabber: Could authorize, sorry.");
		$jid->Disconnect();
		undef($jid);
		$jid=undef;
		$jid_status=0;
		return ;
	};
};

sub jid_timer_start
{
	Irssi::timeout_add( $jid_timer_interval * 1000, \&jid_timer, "");
};

sub checkconnect
{
	unless ($jid_connect)
	{
		return 0;
	};

	if (!Irssi::settings_get_bool('jabber_autostart'))
	{
		return 0;
	};

	if ($jid)
	{
		if ($jid->Connected())
		{
			return 1;
		};
	};
	return 0;
};

sub cmd_start
{
	Irssi::print("Jabber start");
	$jid_connect=2;
};

sub cmd_stop
{
	Irssi::print("Jabber stop");
	$jid_connect=0;
	$jid_status=0;

	if ($jid) { $jid->Disconnect();};
	undef($jid);
	$jid=undef;
};

Irssi::signal_add_first('command script unload', \&event_unload);
Irssi::signal_add("print text",\&event_msg);

Irssi::command_bind('start_jabber',"cmd_start");
Irssi::command_bind('stop_jabber',"cmd_stop");
Irssi::command_bind('jabber_help',"cmd_help");
Irssi::command_bind('jabber_status',"cmd_status");

Irssi::settings_add_bool('misc', 'jabber_autostart', 'OFF');
Irssi::settings_add_str('misc', 'jabber_server', 'jid.arker.pl');
Irssi::settings_add_str('misc', 'jabber_login', 'irc');

Irssi::settings_add_str('misc', 'jabber_password', 'irc');
Irssi::settings_add_str('misc', 'jabber_roster', 'jezik@jid.arker.pl');

Irssi::settings_add_int('misc', 'jabber_reconnect', 0);

Irssi::settings_add_int('misc', 'jabber_flood_max', 10);
Irssi::settings_add_int('misc', 'jabber_flood_time_max', 20);

Irssi::print('Jabber Hilight Forwarder (irssijabbernotify) v'.$VERSION);
Irssi::print(' - please, send any bugs/requests to jezik@arker.pl');

if (Irssi::settings_get_bool('jabber_autostart'))
{
	cmd_start();
};

jid_timer_start();

0;
