#!/bin/sh
#-*-Perl-*-

exec perl -x $0 "$@"

#!perl

#
# It may be feature-rich, but it's a big, chunky monster when it comes to taking up room on your screen.
# Maximum Linux
#

##############################################################################
#
# Jarl - A Jabber Client written in Perl/Tk for both GUI and CLI
#
##############################################################################

##############################################################################
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
#  Jabber
#  Copyright (C) 1998-1999 The Jabber Team http://jabber.org/
#
##############################################################################

use strict;
use Net::Jabber qw(Client);
use XML::Stream qw(Tree);
use Getopt::Long;
use FindBin qw($Bin);
use Carp;

use vars qw(
	    %options
	    %connectiontypes
	    %loaded
	    @globalArgs
	    $semaphore
	    $AUTOLOAD
	    $LASTAUTOLOAD
	    %CLI
	    %GUI
	    %jabber
	    $Debug
	    $Bitmaps
	    $Libs
	    %profiles
	    $activeProfile
	    %config
	    %agents
	    %agentsList
	    %debug
	    %groupchat
	    %groupchatJIDs
	    %groupchatRosters
	    %timeoffsets
	    %searchJIDs
	    %transportJIDs
	    %chat
	    %sxpm
	    %normal
	    $threadcount
	    %messages
	    @headlines
	    %results
	    $resultsWidget
	    $VERSION
	    %optctl
	    $Roster
	    $TabBar
	    $maxX
	    $maxY
	   );

$VERSION = "0.5000";

$Bitmaps = "$Bin/../share/jarl/bitmaps";
$Bitmaps = "$Bin/bitmaps" if !(-d $Bitmaps);
$Libs = "$Bin/../share/jarl/lib";
$Libs = "$Bin/lib" if !(-d $Libs);

use lib ((-d "$Bin/../share/jarl/lib") ?
	 "$Bin/../share/jarl/lib" :
	 "$Bin/lib");

use Jarl;

$options{gpg} = 1;
eval("use GnuPG::Interface;");
if ($@) {
  $options{gpg} = 0;
}

$options{ssl} = 1;
eval("use IO::Socket::SSL;");
if ($@) {
  $options{ssl} = 0;
}


@globalArgs = @ARGV;

%optctl = ();
$optctl{debug} = -1;
$optctl{debugfile} = "stdout";
$optctl{mode} = "tk";
$optctl{help} = 0;

if (-e "$Bin/../share/jarl/mode") {
  open(MODE,"$Bin/../share/jarl/mode");
  $optctl{mode} = <MODE>;
  close(MODE);
  $optctl{mode} =~ s/\n//g;
}

&GetOptions(\%optctl,"debug=i","debugfile=s","mode=s","help");

&usage if ($optctl{help} == 1);

$Debug = new Net::Jabber::Debug(level=>$optctl{debug},
				file=>$optctl{debugfile},
				header=>"Jarl",
			        time=>1);

$jabber{olddebug} = "";
$jabber{oldstatus} = "";
$jabber{error} = 0;

$jabber{replyCount} = 0;
$jabber{threadCount} = 0;
($jabber{readhandle},$jabber{writehandle}) = FileHandle::pipe;
$jabber{writehandle}->autoflush(1);

$jabber{presence} = new Jarl::Presence(type=>"unavailable",
				       status=>"Offline");

$profiles{"Connect w/o Profile"} = new Jarl::Profile();
$profiles{"Connect w/o Profile"}->Server("");
$profiles{"Connect w/o Profile"}->Port(5222);
$profiles{"Connect w/o Profile"}->Type("TCP/IP");

%connectiontypes = ( "TCP/IP"=>["tcpip","5222","0"],
		     "TCP/IP w/ SSL"=>["tcpip","5223","1"],
		     "HTTP"=>["http","5222","0"],
		     "HTTPS"=>["http","5223","1"],
		   );

delete($connectiontypes{"TCP/IP w/ SSL"}) if ($options{ssl} == 0);
delete($connectiontypes{"HTTPS"}) if ($options{ssl} == 0);

&jarlSettings_ReadProfiles();

$config{presence}->{dnd}->{name} = "Do Not Disturb";
$config{presence}->{dnd}->{status}->[0] = "Busy coding";
$config{presence}->{dnd}->{status}->[1] = "Doing real work";
$config{presence}->{away}->{name} = "Away";
$config{presence}->{away}->{status}->[0] = "At lunch";
$config{presence}->{away}->{status}->[1] = "On the phone";
$config{presence}->{xa}->{name} = "Extended Away";
$config{presence}->{xa}->{status}->[0] = "ZzzZzz";
$config{presence}->{xa}->{status}->[1] = "Gone Home";

$jabber{reconnect} = 0;

#-----------------------------------------------------------------------------
# Start the interface.  This function will not quit until the interface sees
# a quit initiated by the user.
#-----------------------------------------------------------------------------
&jarlMainIF_Init();

#-----------------------------------------------------------------------------
# Since the user quit, save the settings of the current profile.
#-----------------------------------------------------------------------------
&jarlSettings_Save();




##############################################################################
#
# messageCB - handle incoming <message/> tags.
#
##############################################################################
sub messageCB {
  my $sid = shift;
  my $message = shift;

  $Debug->Log1("messageCB: start");
  $Debug->Log1("messageCB: (",$message->GetXML(),")");

  my $fromJID = $message->GetFrom("jid");

  if (($message->GetType() eq "normal") || ($message->GetType() eq "")) {

    my @updateXTags = $message->GetX("jabber:x:autoupdate");
    if ($#updateXTags == -1) {
      &jarlNormal_AddMessage($message);
    } else {
      my $updateXTag = $updateXTags[0];
      my $iq = new Net::Jabber::IQ();
      $iq->SetIQ(to=>$updateXTag->GetJID(),
		 type=>"get");
      my $iqQuery = $iq->NewQuery("jabber:iq:autoupdate");
      $jabber{client}->Send($iq);
    }
  }
  if ($message->GetType() eq "chat") {
    my $jid = new Net::Jabber::JID();
    $jid->SetJID($fromJID->GetJID("full"));
    $jid->SetResource() if !exists($groupchat{jids}->{$jid->GetJID()});
    &jarlChat_AddMessage($jid,$message);
  }
  if ($message->GetType() eq "groupchat") {
    &jarlGroupChat_AddMessage($message->GetFrom("jid"),$message);
  }
  if ($message->GetType() eq "headline") {
    &jarlHeadlineIF_AddMessage($message);
  }
  if ($message->GetType() eq "error") {
    if (exists($groupchat{jids}->{$fromJID->GetJID()})) {
      $groupchat{tags}->{&jarlGroupChat_Tag($fromJID->GetJID())}->{reconnect} = 1;
      $groupchat{tags}->{&jarlGroupChat_Tag($fromJID->GetJID())}->{transportdown} = 1;
    } else {

      my @xTags = $message->GetX("jabber:x:delay");
      if ($#xTags == -1) {
	my $body = ("*"x30)."\n";
	$body .= "ERROR: ".$message->GetErrorCode().": ".$message->GetError()."\n";
	$body .= ("*"x30)."\n";
	$body .= "\n";
	$body .= "Subject: ".$message->GetSubject()
	  if ($message->GetSubject() ne "");
	$body .= "\n";
	$body .= $message->GetBody();
	$message->SetBody($body);
	$message->SetSubject("ERROR: ".$message->GetErrorCode().": ".$message->GetError());

	&jarlNormal_AddMessage($message,"error");
      }
    }
  }

  $Debug->Log1("messageCB: end");
}


##############################################################################
#
# presenceCB - handle incoming <presence/> tags.
#
##############################################################################
sub presenceCB {
  my $sid = shift;
  my $presence = shift;

  $Debug->Log1("presenceCB: start");
  $Debug->Log1("presenceCB: (",$presence->GetXML(),")");

  my $fromJID = $presence->GetFrom("jid");

  my @replyPresXTags = $presence->GetX("jabber:x:replypres");
  return if (($#replyPresXTags > -1) &&
	     exists($chat{jids}->{$fromJID->GetJID()}));

  &jarlMainIF_StatusAdd($presence);

  my $type = $presence->GetType();

  my $oldPresence = $jabber{client}->PresenceDBQuery($fromJID);

  if (($type eq "") || ($type eq "available") || ($type eq "unavailable")) {
    $jabber{client}->PresenceDBParse($presence);

    $Roster->UpdatePresence($presence);

    my $newPresence = $jabber{client}->PresenceDBQuery($fromJID);
    $presence = $newPresence if (defined($newPresence) &&
				 !exists($groupchat{jids}->{$fromJID->GetJID()}));
  }

  $type = $presence->GetType();
  my $show = $presence->GetShow();
  my $reply = "";

  $Debug->Log2("presenceCB: type($type)");

  if (($type eq "") || ($type eq "available") || ($type eq "unavailable")) {
    $Debug->Log0("presenceCB: Got a type($type) from jid(",$fromJID->GetJID("full"),")");

    if (exists($groupchat{jids}->{$fromJID->GetJID()})) {

      $Debug->Log1("presenceCB: we have a groupchat presence");

      $groupchatRosters{"groupchat-$$-".$fromJID->GetJID()}->UpdatePresence($presence);

      if (($type eq "available") || ($type eq "")) {
	if (exists($chat{jids}->{$fromJID->GetJID("full")})) {

	  $Debug->Log1("presenceCB: it's an available and we are chatting with them");

	  my $body = $fromJID->GetResource()." logged in to channel ".$fromJID->GetUserID();
	  $body .= ": ".$presence->GetStatus() if ($presence->GetStatus() ne "");
	  my $serverMsg = new Net::Jabber::Message();
	  $serverMsg->SetMessage(body=>$body);
	  &jarlChat_AddMessage($fromJID,$serverMsg,1);
	  &jarlChat_SecureChat($fromJID);
	}
      } else {
	if (exists($chat{jids}->{$fromJID->GetJID("full")})) {

	  $Debug->Log1("presenceCB: it's an unavailable and we are chatting with them");

	  my $serverMsg = new Net::Jabber::Message();
	  $serverMsg->SetMessage(body=>$fromJID->GetResource()." logged out from channel ".$fromJID->GetUserID());
	  &jarlChat_AddMessage($fromJID,$serverMsg,1);
	  if (&jarlChat_IsSecure($fromJID) == 1) {
	    &jarlChat_UnsecureChat($fromJID);
	  }
	}
      }
    } else {

      $Debug->Log1("presenceCB: we have a regular presence");

      if (($type eq "available") || ($type eq "")) {

# You should always be able to send an encrypted message... and the other
# person should just grok it later.
#	if (scalar(keys(%{$normal{$fromJID->GetJID()}})) > 0) {
#	  $Debug->Log1("presenceCB: it's an available and we are composing a message to them");
#	  &jarlNormal_SecureMessage($fromJID);
#	}

	my $body;
	$body = $Roster->GetValue($fromJID->GetJID(),"name")." logged in to Jabber"
	  if (!defined($oldPresence) || ($oldPresence->GetType() eq "unavailable"));
	$body = $Roster->GetValue($fromJID->GetJID(),"name")." changed availability"
	  if (defined($oldPresence) && ($oldPresence->GetType() ne "unavailable"));
	$body .= ": ".$presence->GetShow() if ($presence->GetShow() ne "");
	$body .= ": ".$presence->GetStatus() if ($presence->GetStatus() ne "");
	&jarlMainIF_StatusBarChangeStatus($body);
	if (exists($chat{jids}->{$fromJID->GetJID()})) {

	  $Debug->Log1("presenceCB: it's an available and we are chatting with them");

	  my $serverMsg = new Net::Jabber::Message();
	  $serverMsg->SetMessage(body=>$body);
	  &jarlChat_AddMessage($fromJID,$serverMsg,1);
	  &jarlChat_SecureChat($fromJID);
	}
      } else {

#	if (scalar(keys(%{$normal{$fromJID->GetJID()}})) > 0) {
#	  $Debug->Log1("presenceCB: it's an unavailable and we are composing a message to them");
#	  &jarlNormal_UnsecureMessage($fromJID);
#	}

	my $body = $Roster->GetValue($fromJID->GetJID(),"name")." logged out from Jabber";
	&jarlMainIF_StatusBarChangeStatus($body);
	if (exists($chat{jids}->{$fromJID->GetJID()})) {

	  $Debug->Log1("presenceCB: it's an unavailable and we are chatting with them");

	  my $serverMsg = new Net::Jabber::Message();
	  $serverMsg->SetMessage(body=>$body);
	  &jarlChat_AddMessage($fromJID,$serverMsg,1);
	  if (&jarlChat_IsSecure($fromJID) == 1) {
	    &jarlChat_UnsecureChat($fromJID);
	  }
	}
      }
    }
  }

  if ($type eq "unsubscribe") {
    &jarlMainIF_StatusBarChangeStatus("Unsubscribe request from ".$fromJID->GetJID());
    $reply = $presence->Reply(template=>"client",
			      type=>"unsubscribed");
  }

  if ($type eq "unsubscribed") {
    &jarlMainIF_StatusBarChangeStatus("We are unsubscribed from ".$fromJID->GetJID());
    $jabber{client}->PresenceDBDelete($fromJID);
  }

  if ($type eq "subscribed") {
    &jarlMainIF_StatusBarChangeStatus("We are subscribed to ".$fromJID->GetJID());
  }

  #---------------------------------------------------------------------------
  # User wants to subscribe to us
  #---------------------------------------------------------------------------
  if ($type eq "subscribe") {
    &jarlMainIF_StatusBarChangeStatus("Subscribe request from ".$fromJID->GetJID());
    $Debug->Log2("presenceCB: Handle a subscribe...");

    if ($config{subscriptions} eq "all") {
      $Debug->Log2("presenceCB: User says \"Come on in!\"");
      $reply = $presence->Reply(template=>"client",
				type=>"subscribed");

      if ($Roster->GetValue($fromJID->GetJID()) == 0) {
	$Debug->Log2("presenceCB: we aren't subscribed to them");
	if ($config{subscribe} == 0) {
	  $Debug->Log2("presenceCB: Should we commit to them?");
	  &jarlPresenceIF_SubscriptionAsk($presence);
	} else {
	  $Debug->Log2("presenceCB: I want to be thier friend");
	  my $subscribe = $presence->Reply(template=>"client",
					   type=>"subscribe");
	  $jabber{client}->Send($subscribe);
	}
      }
    }
    if ($config{subscriptions} eq "roster") {
      $Debug->Log2("presenceCB: Roster test");
      if ($Roster->GetValue($fromJID->GetJID()) == 1) {
	$Debug->Log2("presenceCB: They are in our roster... let 'em in");
	$reply = $presence->Reply(template=>"client",
				  type=>"subscribed");
	if ($Roster->GetValue($fromJID->GetJID()) == 0) {
	  $Debug->Log2("presenceCB: we aren't subscribed to them");
	  if ($config{subscribe} == 0) {
	    $Debug->Log2("presenceCB: Should we commit to them?");
	    &jarlPresenceIF_SubscriptionAsk($presence);
	  } else {
	    $Debug->Log2("presenceCB: I want to be thier friend");
	    my $subscribe = $presence->Reply(template=>"client",
					     type=>"subscribe");
	    $jabber{client}->Send($subscribe);
	  }
	}
      } else {
	$Debug->Log2("presenceCB: They are not in our roster");
	if ($config{subscriptiondeny} == 1) {
	  $Debug->Log2("presenceCB: They didn't make the A-list either... Kick 'em out");
	  $reply = $presence->Reply(template=>"client",
				    status=>$config{subscriptiondenymessage},
				    type=>"unsubscribed");
	} else {
	  $Debug->Log2("presenceCB: Ask the master");
	  &jarlPresenceIF_SubscriptionAsk($presence);
	}
      }
    }
    if ($config{subscriptions} eq "prompt") {
      $Debug->Log2("presenceCB: User is screening his calls");
      &jarlPresenceIF_SubscriptionAsk($presence);
    }
  }

  $Debug->Log2("presenceCB: reply(",$reply->GetXML(),")") if ($reply ne "");
  $jabber{client}->Send($reply) if ($reply ne "");
  $Debug->Log1("presenceCB: end");
}


##############################################################################
#
# iqCB - handle incoming <iq/> tags.
#
##############################################################################
sub iqCB {
  my $sid = shift;
  my $iq = shift;

  $Debug->Log1("iqCB: start");
  $Debug->Log1("iqCB: (",$iq->GetXML(),")");

  my $fromJID = $iq->GetFrom("jid");

  my $query;
  my $reply = "";
  my $type = $iq->GetType();
  $type = "set" if ($type eq "");

  if (defined($query = $iq->GetQuery())) {

    $Debug->Log2("iqCB: query($query)");
    $Debug->Log2("iqCB: queryXML(",$query->GetXML(),")");

    if ($query->GetXMLNS() eq "jabber:iq:roster") {
      $Roster->ExtractRoster($jabber{client}->RosterParse($iq));
    }

    if ($query->GetXMLNS() eq "jabber:x:gc") {
      my $changeJID = $iq->GetFrom("jid");
      my $presence = new Net::Jabber::Presence();
      $changeJID->SetResource($groupchat{tags}->{&jarlGroupChat_Tag($fromJID->GetJID())}->{nick});
      $presence->SetPresence(from=>$changeJID,
			     type=>"unavailable");

      $groupchatRosters{&jarlGroupChat_Tag($fromJID->GetJID())}->UpdatePresence($presence);
      &jarlGroupChatIF_ChangeNick($iq->GetFrom("jid"),$query->GetNick());

      $changeJID->SetResource($groupchat{tags}->{&jarlGroupChat_Tag($fromJID->GetJID())}->{nick});
      $presence->SetPresence(from=>$changeJID,
			     type=>"available");
    }

    if ($query->GetXMLNS() eq "jabber:iq:search") {
      my %searchResults = $query->GetResults();

      my $jid;
      foreach $jid (keys(%searchResults)) {
	$results{$jid} = $searchResults{$jid};
      }

      &jarlSearchIF_ListResults($resultsWidget);
    }

    if ($query->GetXMLNS() eq "jabber:iq:version") {
      if ($type eq "get") {
	$reply = $iq->Reply(template=>"client",
			    type=>"result");
	my $replyQuery = $reply->GetQuery();
	$replyQuery->SetVersion(name=>"Jarl - Perl/".ucfirst($optctl{mode})." Client",
				ver=>$VERSION,
				os=>"");
      }
      if ($type eq "result") {
	my $body = "Program: ".$query->GetName()."\n";
	$body .=   "Version: ".$query->GetVer()."\n";
	$body .=   "OS: ".$query->GetOS()."\n";
	
	my $sender = $fromJID->GetJID();
	($sender = $Roster->GetValue($sender,"name"))
	  if ($Roster->GetValue($sender,"name") ne "");
	
	my $message = new Net::Jabber::Message();
	$message->SetMessage(from=>$iq->GetFrom(),
			     subject=>"CTCP: Version",
			     body=>$body);
	
	&jarlNormal_AddMessage($message,"system");
      }
    }

    if ($query->GetXMLNS() eq "jabber:iq:time") {
      if ($type eq "get") {
	$reply = $iq->Reply(template=>"client",
			    type=>"result");
	my $replyQuery = $reply->GetQuery();
	$replyQuery->SetTime();
      }
      if ($type eq "result") {
	
	my $body = "UTC: ".$query->GetUTC()."\n";
	$body .=   "Time: ".$query->GetDisplay()."\n";
	$body .=   "Timezone: ".$query->GetTZ()."\n";
	
	my $sender = $fromJID->GetJID();
	($sender = $Roster->GetValue($sender,"name"))
	  if ($Roster->GetValue($sender,"name") ne "");
	
	my $message = new Net::Jabber::Message();
	$message->SetMessage(from=>$iq->GetFrom(),
			     subject=>"CTCP: Time",
			     body=>$body);

	&jarlNormal_AddMessage($message,"system");
      }
    }

    if ($query->GetXMLNS() eq "jabber:iq:autoupdate") {
      &jarlAutoUpdateIF_GUI($query);
    }
  }
  $jabber{client}->Send($reply) if ($reply ne "");
  $Debug->Log1("iqCB: end");
}


##############################################################################
#
# jarlFetchURL - fetch the URL using the default data from the preferences.
#
##############################################################################
sub jarlFetchURL {
  my ($url) = @_;

  if (ref($url) eq "Net::Jabber::Message") {
    my @xTags = $url->GetX("jabber:x:oob");
    my $xTag = $xTags[0];
    $url = $xTag->GetURL();
  }

  my $command = $config{webbrowser}->{command};
  return if ($command eq "");
  $command =~ s/\"?\'?\%URL\%\'?\"?/\'$url\'/;
  $command =~ s/\s*\&\s*$//;

  system($command." &");
}


##############################################################################
#
# jarlConnect - function to handle connecting and logging into the server,
#               sending the initial presence, auto-update, and roster fetch.
#
##############################################################################
sub jarlConnect {
  my (%args) = @_;

  if (exists($args{server}) && exists($args{port}) &&
      exists($args{username}) && exists($args{password}) &&
      exists($args{resource}) && exists($args{priority}) &&
      exists($args{ssl}) && exists($args{connectiontype})) {
    $jabber{server} = $args{server};
    $jabber{port} = $args{port};
    $jabber{connectiontype} = $args{connectiontype};
    $jabber{username} = $args{username};
    $jabber{password} = $args{password};
    $jabber{resource} = $args{resource};
    $jabber{ssl} = $args{ssl};
    $jabber{presence}->Priority($args{priority});
  }

  return if (
	     ($jabber{server} =~ /^\s*$/) ||
	     ($jabber{port} =~ /^\s*$/) ||
	     ($jabber{connectiontype} =~ /^\s*$/) ||
	     ($jabber{username} =~ /^\s*$/) ||
	     ($jabber{password} =~ /^\s*$/) ||
	     ($jabber{resource} =~ /^\s*$/) ||
	     ($jabber{ssl} =~ /^\s*$/) ||
	     ($jabber{presence}->Priority() =~ /^\s*$/)
	    );

  $jabber{ssl} = 0 if ($options{ssl} == 0);

  $jabber{client} = new Net::Jabber::Client(debuglevel=>$optctl{debug},
					    debugfile=>$optctl{debugfile},
					    debugtime=>1);
  $jabber{client}->SetCallBacks(message=>\&messageCB,
				presence=>\&presenceCB,
				iq=>\&iqCB,
			        send=>\&jarlDebug_AddSendXML,
			        receive=>\&jarlDebug_AddReceiveXML);
  $jabber{client}->SetCallBacks(update=>\&jarlMainIF_Update);

  &jarlMainIF_StatusAdd("Attempting to connect...");

  my $status =
    $jabber{client}->Connect(connectiontype=>$jabber{connectiontype},
			     hostname=>$jabber{server},
			     port=>$jabber{port},
			     ssl=>$jabber{ssl});
  if (!defined($status)) {
    &jarlErrorIF_Popup("","Cannot connect to server $jabber{server}:$jabber{port}.");
    $Debug->Log0("Cannot connect to server $jabber{server}:$jabber{port}.  (".$jabber{client}->GetErrorCode().")");
    delete($jabber{client});
    return;
  }

  &jarlMainIF_StatusAdd("Connected successfully...");
  &jarlMainIF_StatusAdd("Attempting to login...");

  my @result =
    $jabber{client}->
      AuthSend(username=>$jabber{username},
	       password=>$jabber{password},
	       resource=>$jabber{resource});

  if ($result[0] ne "ok") {
    &jarlErrorIF_Popup(@result);
    $Debug->Log0("ERROR: Could not login to server:",@result);

    $jabber{client}->Disconnect();
    delete($jabber{client});
    return;
  }

  $jabber{connected} = 1;
  &jarlMainIF_StatusAdd("Logged in...");

  $jabber{myJID} = new Net::Jabber::JID($jabber{username}."\@".$jabber{server}."/".$jabber{resource});

  &jarlMainIF_StatusAdd("Fetching agents...");
  &jarlMainIF_PopulateAgentsMenu();

  &jarlMainIF_StatusAdd("Fetching roster...");
  $Roster->ExtractRoster($jabber{client}->RosterGet());

  &jarlMainIF_StatusAdd("Sending presence...");
  if ($jabber{reconnect} == 0) {
    $jabber{presence}->Set(status=>"Online");
  } else {
    &jarlMainIF_StatusAdd("Reconnect...");
    $jabber{presence}->ReconnectPresenceSend();
  }
  $jabber{reconnect} = 0;

  &jarlMainIF_StatusAdd("Check for updates...");
  $jabber{client}->PresenceSend(to=>"962065957\@update.jabber.org/$VERSION");

  if ($#headlines > -1) {
    &jarlMainIF_StatusAdd("Display headlines...");
    &jarlHeadlineIF_List();
  }

  &jarlMainIF_LoggedIn();

  return 1;
}


##############################################################################
#
# jarlDisconnect - function to handle disconnecting from the server and
#                  cleaning everything up.
#
##############################################################################
sub jarlDisconnect {
  return unless exists($jabber{client});
  &jarlMainIF_StatusAdd("Disconnecting...");
  if ($jabber{reconnect} == 0) {
    $jabber{presence}->Set(type=>"unavailable",
			   status=>"Logging out");
  }
  $jabber{client}->Disconnect();
  $Roster->Clear();
  $TabBar->HideTab("status");
  $TabBar->HideTab("debug");
  &jarlMainIF_PopulateAgentsMenu();
  &jarlMainIF_PopulateFavGroupsMenu();

  foreach my $tag (keys(%{$groupchat{tags}})) {
    &jarlGroupChat_Disconnect($tag);
    $groupchat{tags}->{$tag}->{reconnect} = 0;
  }

  $jabber{connected} = 0;
  &jarlMainIF_LoggedOut();
}



##############################################################################
#
# AUTOLOAD - if a function is called that is not defined then this function
#            will examine the function name and load the required library.
#
##############################################################################
sub AUTOLOAD {
  my ($function) = ($AUTOLOAD =~ /^main\:\:(.*)$/);
  croak("$function not defined") if (defined($LASTAUTOLOAD) &&
				     ($AUTOLOAD eq $LASTAUTOLOAD));
  $LASTAUTOLOAD = $AUTOLOAD;

  my ($base,$func) = split("_",$function);
  $Debug->Log1("AUTOLOAD: base($base) function($function)");

  my ($file) = ($base =~ /^jarl(\S+)$/);
  my $interface = ($file =~ /IF$/);
  $file =~ s/IF$//;
  $file = lc($file);
  $Debug->Log1("AUTOLOAD: file($file) interface($interface)");

  my $loadFile = $Libs."/".$file.".pl";
  $loadFile = $Libs."/".$file."_".$optctl{mode}.".pl" if ($interface == 1);

  $Debug->Log1("AUTOLOAD: loadFile($loadFile)");

  croak("Cannot find library file ($loadFile)") if !(-e $loadFile);

  if (!exists($loaded{$loadFile})) {
    $Debug->Log1("AUTOLOAD: loading($loadFile)");
    $loaded{$loadFile} = 1;
    require $loadFile;
  }

  goto &$AUTOLOAD;
}


sub usage {
  print "jarl v$VERSION\n";
  print "\n";
  print "jarl [ --mode <mode> ] [ --debug <level> --debugfile <filename> ]\n";
  print "\n";
  print "    --mode         selects the mode to run with.  Possible modes\n";
  print "                   are:\n";
  open(MODE,"$Bin/../share/jarl/mode");
  while(<MODE>) {
    print "                       $_";
  }
  print "    --debug        selects the debug level for output (0..N)\n";
  print "    --debugfile    specify the file to put the debug into\n";
  print "    --help         this screen\n";
  exit(0);
}
