##############################################################################
#
# Jarl - Main Command Line Interface Code
#   Perl code to handle setting up the command line interface with the user.
#
##############################################################################

##############################################################################
#
#  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 Curses;
use CLI::Roster;
use CLI::TabBar;
use vars qw ($TabBar %GUI %types);

##############################################################################
#
# jarlMainIF_Init - Main initialization for CLI
#
##############################################################################
sub jarlMainIF_Init {

#  use IO::Handle;
#  open(DEBUG,">debug.log");
#  DEBUG->autoflush(1);

  $GUI{window} = new Curses();

  &jarlMain_TabRotate(0);

  noecho();
  cbreak();
  $GUI{window}->nodelay(1);
  $GUI{window}->keypad(1);

  $GUI{maxY} = $GUI{window}->getmaxy();
  $GUI{maxX} = $GUI{window}->getmaxx();


  start_color;
  # Tab Colors
  init_pair(1,COLOR_RED,COLOR_WHITE);
  init_pair(2,COLOR_MAGENTA,COLOR_WHITE);
  init_pair(3,COLOR_GREEN,COLOR_WHITE);
  init_pair(4,COLOR_BLACK,COLOR_WHITE);
  init_pair(5,COLOR_WHITE,COLOR_BLACK);
  init_pair(6,COLOR_RED,COLOR_BLACK);
  init_pair(7,COLOR_BLUE,COLOR_BLACK);
  init_pair(8,COLOR_GREEN,COLOR_BLACK);
  init_pair(9,COLOR_MAGENTA,COLOR_BLACK);
  init_pair(10,COLOR_YELLOW,COLOR_BLACK);

  $types{"low"} = 1;
  $types{"medium"} = 2;
  $types{"high"} = 3;
  $types{"lowered"} = 4;
  $types{"raised"} = 5;
  $types{"normal"} = 5;
  $types{"highlight"} = 6;
  $types{"link"} = 7;
  $types{"me"} = 6;
  $types{"notme"} = 7;
  $types{"server"} = 8;
  $types{"action"} = 9;
  $types{"say"} = 5;
  $types{"timestamp"} = 5;
  $types{"secure"} = 10;
  $types{"history"} = 10;

  $types{"sent"} = 7;
  $types{"rcvd"} = 8;
  $types{"error"} = 6;

  $CLI{stdin} = new IO::Select(*STDIN);

  $TabBar = new CLI::TabBar();

  $GUI{window}->setscrreg($TabBar->Height(),$GUI{maxY}-3);
  $GUI{window}->scrollok(1);

  $Roster = new CLI::Roster();
  $Roster->DrawMode(0);
  $Roster->ShowOnlineOnly();

  &jarlMainIF_DrawScreen();

  $TabBar->AddTab(tag=>"login",
		  text=>"Login");
  $TabBar->AddTab(tag=>"status",
		  text=>"Status");
  $TabBar->AddTab(tag=>"roster",
		  text=>"Roster");
  $TabBar->AddTab(tag=>"normal",
		  text=>"Normal");
  $TabBar->AddTab(tag=>"debug",
		  text=>"Debug");

  $TabBar->HideTab("debug");

  $TabBar->RaiseTab("login");

  &jarlMainIF_DrawScreen();

  &jarlLoginIF_CLI();

  $TabBar->RaiseTab("roster");

  &jarlMainIF_Loop();

  endwin();
}


##############################################################################
#
# jarlMainIF_Loop - this is the Loop of code that allows Jarl to interact with
#                 Jabber and still be able to click on the GUI and have it
#                 work.
#
##############################################################################
sub jarlMainIF_Loop {
  $Debug->Log2("jarlMainIF_Loop: start");

  my $command = "";
  my $lastchecked = 0;
  while($command ne "/__jarl__:quit") {

    $jabber{checking} = 1;
    if (exists($jabber{client}) && ($jabber{client}->Connected())) {
      my $haveXML = 1;
      while($haveXML == 1) {
	$haveXML = $jabber{client}->Process(0);
	if (!defined($haveXML)) {
	  &jarlMainIF_StatusAdd("The connection to the server was lost...");
	  $Debug->Log0("ERROR: the connection was lost.  (",$jabber{client}->GetErrorCode(),")");
	  $jabber{reconnect} = 1;
	  &jarlDisconnect();
	  foreach (0..19) {
	    &jarlMainIF_StatusAdd("Waiting 5 seconds...");
	    sleep(5);
	    &jarlMainIF_StatusAdd("Attempting to reconnect...(".($_+1)."/20)");
	    last if defined(&jarlConnect());
	    &jarlMainIF_StatusAdd("Failed to reconnect...");
	  }	
	  if (exists($jabber{client}) && ($jabber{client}->Connected())) {
	    &jarlMainIF_StatusAdd("Reconnected to server...");
	  } else {
	    $haveXML = 0;
	    &jarlMainIF_StatusAdd("Could not reconnect to server...");
	  }
	}
      }
    }
    $jabber{checking} = 0;

    $jabber{time} = &Net::Jabber::GetTimeStamp("local","","normal");

    if (($jabber{time} ne $jabber{statustime}) ||
	(exists($jabber{statusID}) && ($jabber{statusID} == time))) {
      $jabber{statustime} = $jabber{time};
      if ($jabber{statusID} == time) {
	$jabber{presenceString} = $jabber{oldPresenceString};
	delete($jabber{statusID});
      }
      &jarlMainIF_DrawStatusBar();
    }

    $Debug->Log2("jarlMainIF_Loop: end");

    $command = &jarlMainIF_Prompt(timeout=>0,
				  passive=>1);

    if ($command =~ /^\/(\?|help)/) {
      $command = "/__jarl__:help";
      &jarlMainIF_Help();
    } elsif ($command =~ /^\/(q|quit)/) {
      $command = "/__jarl__:quit";
    } elsif ($command =~ /^\/(t|tab)\ ?\d*$/) {
      if ($command =~ /\d+/) {
	my ($tab) = ($command =~ /(\d+)/);
	$TabBar->RaiseTab($TabBar->GetOrder($tab));
      } else {
	$TabBar->DrawTabs();
      }
    } elsif ($command =~ /^\/(p|presence)/) {
      &jarlPresenceIF_CustomGUI();
    } elsif ($command =~ /^\/(d|debug)/) {
      $config{showdebug} ^= 1;
      if ($config{showdebug} == 1) {
	$TabBar->ShowTab("debug");
      } else {
	$TabBar->HideTab("debug");
      }
    } elsif ($command =~ /^\/(c|chat)/) {
      my ($to) = ($command =~ /\s(.*)$/);
      if ($TabBar->CurrentTab() =~ /^groupchat/) {
	$to = &jarlGroupChat_Channel($TabBar->CurrentTab())."/".$to;
      } else {
	$to = $Roster->NameToJID($to);
      }
      &jarlChat_AddMessage(new Net::Jabber::JID($to),"")
	if ($to ne "");
    } elsif ($command =~ /^\/(g|groupchat)/) {
      &jarlGroupChatIF_GUI();
    } else {

      my $target = $TabBar->CurrentTab();
      if (($target eq "roster") ||
	  ($target eq "normal") ||
	  ($target eq "status")) {
	&jarlMainIF_HandleCommand($command);
      } elsif ($target eq "debug") {
	&jarlDebugIF_HandleCommand($command);
      } else {
	my ($type) = ($target =~ /^([^\-]+)-/);
	&jarlChatIF_HandleCommand($target,$command) if ($type eq "chat");
	&jarlGroupChatIF_HandleCommand($target,$command) if ($type eq "groupchat");
      }
    }

    if ($lastchecked != time) {
      $lastchecked = time;
      &jarlMainIF_DrawScreen()
	if (($GUI{maxX} != $GUI{window}->getmaxx()) ||
	    ($GUI{maxY} != $GUI{window}->getmaxy()));
    }
  }

  &jarlDisconnect();
}


sub jarlMainIF_DrawStatusBar {

  $GUI{window}->move($GUI{maxY}-2,0);
  $GUI{window}->clrtoeol();
  $GUI{window}->attron(COLOR_PAIR(4));

  my $string = "[ jarl v$VERSION ] ";
  $string .= substr($jabber{presenceString}." "x600,0,($GUI{maxX} - length($string) - 2 - length($jabber{time})));
  $string .= " $jabber{time}";

  $GUI{window}->addstr($GUI{maxY}-2,0,$string);
  $GUI{window}->attrset(0);
  $GUI{window}->move($GUI{maxY}-1,$GUI{inputpos});

}


##############################################################################
#
# jarlMainIF_HandleCommand - take the command line for general tabs and
#                            parse it according to the general rules.
#
##############################################################################
sub jarlMainIF_HandleCommand {
  my $command = shift;

  return if ($command eq "");

  if ($command =~ /^\/(r|roster)/) {
    if ($command =~ /\sall/) {
      $Roster->DrawMode(1);
      $Roster->ShowAll();
      $Roster->DrawMode(0);
      $Roster->ShowOnlineOnly();
    } elsif ($command =~ /\s(t|toggle)/) {
      my ($group,$jid);
      my (undef,$toggle) = ($command =~ /\s(t|toggle)\s(.*)$/);

      my $ingroup = 1;
      foreach my $piece (split(/(\s+)/,$toggle)) {
	$ingroup = 0 unless $Roster->ExistsGroup($group.$piece);
	$group .= $piece if ($ingroup == 1);
	$jid .= $piece if ($ingroup == 0);
      }

      $jid =~ s/^\s+//;

      $Roster->DrawMode(1);
      $Roster->Toggle($group,$jid);
      $Roster->DrawMode(0);
    } else {
      $Roster->DrawMode(1);
      $Roster->Draw();
      $Roster->DrawMode(0);
    }
    return;
  }
  if ($command =~ /^\/(m|message)/) {
    my ($to) = ($command =~ /\s(.*)$/);
    &jarlNormal_Compose("new",$to);
    return;
  }
  if ($command =~ /^\/__jarl__\:tab$/) {
    &jarlMain_CompleteJID();
    return;
  }
  return if ($command =~ /^\/__jarl__\:/);
  $TabBar->Print("ERROR: Unknown command ($command)\n");
}


sub jarlMain_TabRotate {
  my $value = shift;
  $GUI{tabrotate} = $value if (defined($value));
  return $GUI{tabrotate};
}


sub jarlMain_PreviousJID {
  my $value = shift;
  $GUI{prevjid} = $value if (defined($value));
  return $GUI{prevjid};
}



##############################################################################
#
# jarlMain_CompleteJID - function to provide the interfaces with a consistent
#                        way to support JIDk completion from the Roster.
#
##############################################################################
sub jarlMain_CompleteJID {
  my $current;
  my $jid;
  my $prevJID;

  if (&jarlMain_TabRotate() eq "0") {
    $current = $GUI{input};
    ($prevJID) = ($current =~ /\s*(\S*)$/);
    &jarlMain_TabRotate($current);
    $jid = &jarlParser_NickComplete(type=>"roster",
				    string=>$current);
  } else {
    $current = &jarlMain_TabRotate();
    $prevJID = &jarlMain_PreviousJID();
    $jid = &jarlParser_NickComplete(type=>"roster",
				    string=>$current,
				    previous=>$prevJID);
  }
  &jarlMain_PreviousJID($jid);

  if ($jid ne "") {
    $prevJID =~ s/([\(\)\+\?\*\$])/\\$1/g;
    $GUI{input} =~ s/(\s?)${prevJID}$/$1$jid/;
    $GUI{inputpos} = length($GUI{input});
    $GUI{inputright} = ($GUI{inputpos} - $GUI{maxX} + 1);
    $GUI{inputright} = 0 if ($GUI{inputright} < 0);
  }

  &jarlMainIF_DrawPrompt();
}



##############################################################################
#
# jarlMainIF_BuildForm - in some GUIs we need to build fields based on results
#                        from the server.  This function is a generalized way
#                        to do that.
#
##############################################################################
sub jarlMainIF_BuildForm {
  my (%form) = @_;

  foreach my $index (0..$#{$form{form}}) {
    next if (!defined($form{form}->[$index]) || ($form{form}->[$index] eq ""));
    my @options = @{delete($form{form}->[$index]->{options})};
    my @newOptions = ();
    foreach my $option (@options) {
      push(@newOptions,
	   [
	    (exists($option->{label}) ? $option->{label} : $option->{value}),
	    $option->{value}
	   ]);
    }
    $form{form}->[$index]->{type} = "listbox"
      if (($#newOptions > 10) &&
	  ($form{form}->[$index]->{type} eq "pulldown"));
    &jarlMainIF_AddField(widget=>$form{widget},
			 %{$form{form}->[$index]},
			 options=>\@newOptions
			);
  }
}


##############################################################################
#
# jarlMainIF_AddField - in some GUIs we need to add fields based on the result
#                     from the server.  This function is a generalized way
#                     to do that.
#
##############################################################################
sub jarlMainIF_AddField {
  my (%field) = @_;

  $field{widget}->{vars}->{$field{var}} = $field{value}
    if exists($field{value});
  $field{label} = ucfirst($field{var}) unless exists($field{label});

  $field{widget}->{Fields}->{$field{var}}->{top} =
    $field{widget}->{top}->
      Frame(-background=>$GUI{color}->{window}->{bg}->{normal},
	    -foreground=>$GUI{color}->{window}->{fg}->{dark},
	   )->pack(-side=>'top',
		   -fill=>'x');
  $field{widget}->{Fields}->{$field{var}}->{Label} =
    $field{widget}->{Fields}->{$field{var}}->{top}->
      Label(-text=>"$field{label}:",
	    -width=>$GUI{width}->{jarl}->{profileeditor}->{label},
	    -background=>$GUI{color}->{jarl}->{profileeditor}->{bg}->{normal},
	    -foreground=>$GUI{color}->{jarl}->{profileeditor}->{fg}->{dark},
	    -font=>$GUI{fonts}->{normal},
	    -anchor=>'e'
	   )->pack(-side=>'left',
		   -anchor=>'e');
  if (($field{type} eq "entry") || ($field{type} eq "password")) {
    $field{widget}->{Fields}->{$field{var}}->{Entry} =
      $field{widget}->{Fields}->{$field{var}}->{top}->
	Entry(-textvariable=>\$field{widget}->{vars}->{$field{var}},
	      -width=>$GUI{width}->{jarl}->{profileeditor}->{entry},
	      -background=>$GUI{color}->{jarl}->{profileeditor}->{bg}->{light},
	      -foreground=>$GUI{color}->{jarl}->{profileeditor}->{fg}->{dark},
	      -font=>$GUI{fonts}->{normal},
	      -state=>"normal"
	     )->pack(-side=>'left',
		     -anchor=>'w');
    $field{widget}->{Fields}->{$field{var}}->{Entry}->configure(-show=>"*")
      if ($field{type} eq "password");
  }
  if ($field{type} eq "pulldown") {
    my $foo;
    $field{widget}->{Fields}->{$field{var}}->{Option} =
      $field{widget}->{Fields}->{$field{var}}->{top}->
	Optionmenu(-options=>[ @{$field{options}} ],
		   -textvariable=>\$foo,
		   -variable=>\$field{widget}->{vars}->{$field{var}},
		   -background=>$GUI{color}->{jarl}->{config}->{bg}->{normal},
		   -foreground=>$GUI{color}->{jarl}->{config}->{fg}->{dark},
		   -font=>$GUI{fonts}->{normal}
		  )->pack(-side=>'left',
			  -anchor=>'w');
  }
  if ($field{type} eq "listbox") {
    my $foo;
    $field{widget}->{Fields}->{$field{var}}->{Option} =
      $field{widget}->{Fields}->{$field{var}}->{top}->
	Listbox(-options=>[ @{$field{options}} ],
		   -textvariable=>\$foo,
		   -variable=>\$field{widget}->{vars}->{$field{var}},
		   -background=>$GUI{color}->{jarl}->{config}->{bg}->{normal},
		   -foreground=>$GUI{color}->{jarl}->{config}->{fg}->{dark},
		   -font=>$GUI{fonts}->{normal}
		  )->pack(-side=>'left',
			  -anchor=>'w');
  }
}


##############################################################################
#
# jarlMainIF_StatusBarChangeStatus - change the status bar status message for
#                                    a short time and then set it back to the
#                                    the previous state.
#
##############################################################################
sub jarlMainIF_StatusBarChangeStatus {
  my ($status) = @_;

  $Debug->Log3("jarlMainIF_StatusBarChangeStatus: start");
  $Debug->Log3("jarlMainIF_StatusBarChangeStatus: status($status)");

  if (exists($jabber{statusID})) {
    $Debug->Log3("jarlMainIF_StatusBarChangeStatus: there is a current status... cancel it");
  } else {
    $Debug->Log3("jarlMainIF_StatusBarChangeStatus: this is a new status... save current string as the default");
    $jabber{oldPresenceString} = $jabber{presenceString};
  }

  if ($status eq "") {
    $Debug->Log3("jarlMainIF_StatusBarChangeStatus: no status specified... save the current string as the default");
    $jabber{oldPresenceString} = $jabber{presenceString};
    return;
  }

  $jabber{presenceString} = $status;

  &jarlMainIF_DrawStatusBar();

  $jabber{statusID} = time + 5;

  $Debug->Log3("jarlMainIF_StatusBarChangeStatus: finish");
}


##############################################################################
#
# jarlMainIF_StatusBarChangePresence - change the status bar presence icon and
#                                      message for the users current status.
#
#       This function is called from Jarl::Presence and must exist in all
#     interface packages, even if just a stub.
#
##############################################################################
sub jarlMainIF_StatusBarChangePresence {
  my ($presence) = @_;
  my $string;

  if (ref($presence) eq "Net::Jabber::Presence") {
    $string = (($presence->GetType() eq "") ?
	       "available" :
	       $presence->GetType()
	      );
    $string = $presence->GetShow() if ($presence->GetShow() ne "");
    $string .= ": ".$presence->GetStatus() if ($presence->GetStatus() ne "");
  } else {
    $string = $presence;
  }
  my ($icon) = ($string =~ /^([^\:]+)\:?/);

  $jabber{presenceString} = "$jabber{username} is $string";
  &jarlMainIF_DrawStatusBar();
  &jarlMainIF_StatusBarChangeStatus();
}


##############################################################################
#
# jarlMainIF_UpdateOnlineOnly - function call that tells the main roster what
#                             mode to be in and what the icon should be for
#                             toolbar.
#
##############################################################################
sub jarlMainIF_UpdateOnlineOnly {
  $Roster->ShowOnlineOnly() if ($config{onlineonly} == 1);
  $Roster->ShowAll() if ($config{onlineonly} == 0);

#  &jarlMainIF_ChangeIcon($GUI{Jabber}->{Roster}->{ToolBar}->{RosterShow},
#		       ($config{onlineonly} == 1 ?
#			"ShowOnline" :
#			"ShowMixed"),
#		       ($config{onlineonly} == 1 ?
#			"ShowMixed" :
#			"ShowOnline"));
}


##############################################################################
#
# jarlMainIF_StatusAdd - add a message to the status window
#
##############################################################################
sub jarlMainIF_StatusAdd {
  my ($stuff) = @_;

  my %GUI;

  my $string = "";
  my $status = "";

  if (ref($stuff) eq "") {
    $status = $stuff;
    $string = $stuff."\n";
  }
  if (ref($stuff) eq "Net::Jabber::Presence") {
    $string .= "AVBL: " if (($stuff->GetType() eq "available") ||
			    ($stuff->GetType() eq ""));
    $string .= "UNAV: " if ($stuff->GetType() eq "unavailable");
    $string .= "S10N: ".$stuff->GetType()." "
      if (($stuff->GetType() eq "subscribe") ||
	  ($stuff->GetType() eq "unsubscribe") ||
	  ($stuff->GetType() eq "subscribed") ||
	  ($stuff->GetType() eq "unsubscribed"));
    my $fromJID = $stuff->GetFrom("jid");
    $string .= &jarlRoster_GetNick($fromJID);
    $string .= "/".$fromJID->GetResource()
      if (!exists($transportJIDs{$fromJID->GetServer()}) &&
	  ($fromJID->GetResource() ne ""));
    $string .= " - ".$stuff->GetStatus() if ($stuff->GetStatus() ne "");
    $string .= "\n";
  }

  $TabBar->Print("__jarl__:tabbar","status","normal",$string);

  &jarlMainIF_StatusBarChangeStatus($status) unless ($status eq "");
}



##############################################################################
#
# jarlMainIF_UpdateShowDebug - function call that sets whether or not the Debug
#                            Tab is visible or not
#
##############################################################################
sub jarlMainIF_UpdateShowDebug {
  my $currentTab = $TabBar->CurrentTab();
  if ($config{showdebug} == 1) {
    $TabBar->ShowTab("debug");
  } else {
    $TabBar->HideTab("debug");
  }
  $TabBar->RaiseTab($currentTab);
}


##############################################################################
#
# jarlMainIF_Update - update the GUI so that the user doesn't think that the GUI
#                   has gone on hiatus.
#
##############################################################################
sub jarlMainIF_Update {}
sub jarlMainIF_RotateBulb {}
sub jarlMainIF_StopBulb {}
sub jarlMainIF_PopulateFavGroupsMenu {}
sub jarlMainIF_InitFonts {}
sub jarlMainIF_UpdateFontChange {}
sub jarlMainIF_ChangeIcon {}
sub jarlMainIF_PopulateAgentsMenu {

  undef %agents;
  undef %transportJIDs;
  undef %groupchatJIDs;
  undef %searchJIDs;

  %agents = $jabber{client}->AgentsGet(to=>$jabber{server})
    if (exists($jabber{client}) && ($jabber{client}->Connected()));

  my $agentJID;
  foreach $agentJID (sort {$agents{$b}->{order} <=> $agents{$a}->{order}} keys(%agents)) {
    $transportJIDs{$agentJID} = 1;
    $searchJIDs{$agentJID} = 1 if ($agents{$agentJID}->{search} == 1);
    $groupchatJIDs{$agentJID} = 1 if ($agents{$agentJID}->{groupchat} == 1);
  }
}



##############################################################################
#
# jarlMainIF_LoggedIn - do any GUI code that needs to be done when we are logged
#                     in.
#
##############################################################################
sub jarlMainIF_LoggedIn {
}


##############################################################################
#
# jarlMainIF_LoggedOut - do any GUI code that needs to be done when we are
#                      logged out.
#
##############################################################################
sub jarlMainIF_LoggedOut {
}


##############################################################################
#
# jarlMainIF_AlertUser - do something to get the users attention.  Ring
#                        the bell or what not.
#
##############################################################################
sub jarlMainIF_AlertUser {
}


sub jarlMainIF_Prompt {
  my (%args) = @_;

  my @newOptions;

  $GUI{prompt} = "";
  $GUI{prompt} = "password" if exists($args{password});

  my $done = 0;
  while($done == 0) {
    my $prompt;
    if (defined($args{default}) && ($args{default} ne "")) {
      my $foundit = 0;
      foreach my $index (0..$#{$args{options}}) {
	$newOptions[$index] = $args{options}[$index];
	$foundit = 1 if ($args{default} eq $newOptions[$index]);
	if ($args{default} eq $newOptions[$index]) {
	  if ($newOptions[$index] eq uc($args{options}[$index])) {
	    $newOptions[$index] = "_$newOptions[$index]_";
	  } else {
	    $newOptions[$index] = uc($newOptions[$index]);
	  }
	}
      }
      if ($args{default} ne "__jarl__:prompt:nodefault") {
	$prompt .= " [".join(",",@newOptions)."]" if ($foundit == 1);
	$prompt .= " [$args{default}]" if ($foundit == 0);
      }
    }

    if (exists($args{prompt}) && !exists($args{passive})) {
      if (exists($args{transient})) {
	$TabBar->Print("__jarl__:tabbar:transient","$args{prompt}$prompt:");
      } else {
	$TabBar->Print("$args{prompt}$prompt:");
      }
    }
    if (!exists($args{passive})) {
      $GUI{window}->move($GUI{maxY}-1,0);
      $GUI{window}->clrtoeol();
      $GUI{input} = undef;
      $GUI{inputpos} = 0;
      $GUI{inputright} = 0;
    }
    $GUI{window}->refresh();
    my $timestart = time;
    my $ch;
    my $check = 0;
    while(1) {
      last if (($check == 1) &&
	       exists($args{timeout}) &&
	       (($timestart + $args{timeout}) <= time));
      $check = 1;
      select(undef,undef,undef,.01);

      $ch = $GUI{window}->getch();
      next if ($ch == -1);
      $ch = "\n" if ($ch == KEY_ENTER);
      $ch = "\b" if ($ch == KEY_BACKSPACE);
      $GUI{inputpos} = length($GUI{input}) if ($ch eq "\n");

      if ($ch ne "\t") {
	if ($TabBar->CurrentTab() =~ /^groupchat/) {
	  &jarlGroupChat_TabRotate($TabBar->CurrentTab(),0);
	} else {
	  &jarlMain_TabRotate(0);
	}
      }

      if ($ch eq "\b") {
	if ($GUI{inputpos} != 0) {
	  $GUI{inputright}-- if (length($GUI{input}) > ($GUI{maxX}-1));
	  substr($GUI{input},$GUI{inputpos}-1,1) = "";
	  $GUI{inputpos}--;
	}
      } elsif ($ch == KEY_RIGHT) {
	$GUI{inputpos}++;
	$GUI{inputpos} = length($GUI{input}) if ($GUI{inputpos} > length($GUI{input}));
	$GUI{inputright}++ if ($GUI{inputpos} > $GUI{inputright} + $GUI{maxX} - 1);
      } elsif ($ch == KEY_LEFT) {
	$GUI{inputpos}--;
	$GUI{inputpos} = 0 if ($GUI{inputpos} < 0);
	$GUI{inputright}-- if ($GUI{inputpos} < $GUI{inputright});
      } elsif ($ch == KEY_UP) {
	return "/__jarl__:up" if exists($args{passive});
      } elsif ($ch == KEY_DOWN) {
	return "/__jarl__:down" if exists($args{passive});
      } elsif ($ch eq "\t") {
	return "/__jarl__:tab" if exists($args{passive});
      } elsif (length($ch) == 1) {
	substr($GUI{input},$GUI{inputpos},0) = $ch;
	$GUI{inputpos}++;
	$GUI{inputright}++ if (length($GUI{input}) > ($GUI{maxX}-1));
      }
      last if ($ch eq "\n");
      &jarlMainIF_DrawPrompt();
    }

    if (!defined($GUI{input}) || !($GUI{input} =~ /\n$/)) {
      if (exists($args{prompt})) {
	if (exists($args{transient})) {
	  $TabBar->Print("__jarl__:tabbar:transient","\n");
	} else {
	  $TabBar->Print("\n");
	}
      }
      return;
    }
    $GUI{input} =~ s/\n//g;
    if (defined($args{default})) {
      $GUI{input} = $args{default} if ($GUI{input} eq "");
    }
    $done = 1;
    if ($#{$args{options}} > -1) {
      my $foundit = 0;
      foreach my $index (0..$#{$args{options}}) {
	$foundit = 1 if ($GUI{input} eq $args{options}[$index]);
      }
      $done = 0 if ($foundit == 0);
    } else {
      $done = 0 if (($GUI{input} eq "") && (exists($args{prompt})));
    }

    my $disp = $GUI{input};
    $disp =~ s/./\*/g if exists($args{password});
    if (exists($args{prompt})) {
      if (exists($args{transient})) {
	$TabBar->Print("__jarl__:tabbar:transient"," $disp\n");
      } else {
	$TabBar->Print(" $disp\n");
      }
    }

  }

  my $return = $GUI{input};
  $GUI{window}->move($GUI{maxY}-1,0);
  $GUI{window}->clrtoeol();
  $GUI{input} = undef;
  $GUI{inputpos} = 0;
  $GUI{inputright} = 0;
  return $return;
}


sub jarlMainIF_DrawScreen {
  $GUI{maxX} = $GUI{window}->getmaxx();
  $GUI{maxY} = $GUI{window}->getmaxy();

  $TabBar->Refresh();

  &jarlMainIF_DrawStatusBar();

  &jarlMainIF_DrawPrompt();
}

sub jarlMainIF_DrawPrompt {
  $GUI{window}->move($GUI{maxY}-1,0);
  $GUI{window}->clrtoeol();
  my $disp = $GUI{input};
  $disp =~ s/./\*/g if ($GUI{prompt} eq "password");
  $GUI{window}->addstr($GUI{maxY}-1,0,substr($disp,$GUI{inputright},($GUI{maxX}-1)));
  $GUI{window}->move($GUI{maxY}-1,$GUI{inputpos}-$GUI{inputright});
  $GUI{window}->refresh();
}


sub jarlMainIF_Help {
  foreach my $line (split("\n",<<"HELP")) {
/?  /help                   this screen
/t(ab) <tab number>         swtich tabs to the number specified
/d(ebug)                    toggle the debug window
/q(uit)                     quit Jarl

/r(oster)                   show the current online roster
/r(oster) all               show the entire roster
/r(oster) t(oggle) <group>  open a group in the roster
/p(resence)                 set your current presence

/m(essage)                  send a normal message
/c(hat) <jid>               opens a chat with a user.
/g(roupchat)                join a groupchat room
/l(eave)                    leave a chat/groupchat and close the tab

up-arrow                    scroll up through the history of this tab
down-arrow                  scroll down through the history of this tab
HELP
    $TabBar->Print("__jarl__:tabbar:transient","$line\n");
  }
}


1;
