package NetHirc::Terminal;
use strict;
use warnings;
use POE qw(Kernel Session Wheel::ReadWrite);
use POSIX ();
use String::Format;
use NetHirc::Shell;
use NetHirc::Util;
use constant AWAY => "(Away)";
use constant DEFAULT_STATUS => "[%d] NetHirc: %v%o%O%n(%p) on %c(%m) {%s} %a %q";
use constant NO_NICK => "Amnesiac";
use constant NO_CHANNEL => "no channel";
use constant NO_QUERIES => "";
use constant NO_SERVER => "no server";
use constant NOT_AWAY => "";
use constant SSFE_STATUSLINE_FORMAT => "`#ssfe#s%s";
my @events = qw(
_start
_stop
spit
format
error
confirm
ssfe
);
my @ssfe_events = qw(
again
update
);
sub new
{
shift;
POE::Session->create(
'package_states' => [
'NetHirc::Terminal' => [
@events,
$ENV{'SSFE'} ? @ssfe_events : (),
]
],
'args' => [ @_ ],
);
}
sub _start
{
my ($kernel, $heap, $session) = @_[KERNEL, HEAP, SESSION];
my ($db, $rc, $shellargs) = @_[ARG0..ARG2];
$kernel->alias_set('nethirc_terminal');
my $wheel = POE::Wheel::ReadWrite->new(
InputHandle => \*STDIN,
OutputHandle => \*STDOUT,
InputEvent => 'spit',
ErrorEvent => 'error',
InputFilter => POE::Filter::Line->new(),
OutputFilter => POE::Filter::Stream->new(),
);
$heap->{'wheel'} = $wheel;
$heap->{'db'} = $db;
$heap->{'rc'} = $rc;
my $shell = NetHirc::Shell->new($shellargs);
$heap->{'shell'} = $shell;
if ($ENV{'SSFE'})
{
$kernel->post($session, 'ssfe', 1);
}
}
sub _stop
{
my ($kernel, $heap) = @_[KERNEL, HEAP];
delete $heap->{'wheel'};
$kernel->alarm_remove_all();
}
sub confirm
{
debug('t', "confirm");
my ($kernel, $heap, $sender) = @_[KERNEL, HEAP, SENDER];
my ($confirm, $refuse) = @_[ARG0, ARG1];
$heap->{'confirm'} = $sender->postback($confirm);
$heap->{'refuse'} = $sender->postback($refuse);
}
sub spit
{
debug('t', 'spit');
my ($heap, $input) = @_[HEAP, ARG0];
my $shell = $heap->{'shell'};
unless (exists $heap->{'confirm'})
{
$shell->run_once($input);
return;
}
if (lc(substr($input, 0, 1)) eq 'y')
{
$heap->{'confirm'}->();
}
else
{
$heap->{'refuse'}->();
}
delete $heap->{'confirm'};
delete $heap->{'refuse'}
}
sub ssfe
{
debug('t', "ssfe");
my ($kernel, $heap, $session, $arg) = @_[KERNEL, HEAP, SESSION, ARG0];
return unless $arg;
my $inventory = $heap->{'rc'};
$heap->{'formatter'} = String::Format->stringfactory(
'a' => sub { isaway($inventory) },
'c' => sub { channel($inventory) },
'd' => \&datestamp,
'm' => sub { chanmode($inventory) },
'n' => sub { nick($inventory) },
'o' => sub { chops($inventory) },
'O' => sub { serverops($inventory) },
'p' => sub { yourmode($inventory) },
'q' => sub { query($inventory) },
's' => sub { server($inventory) },
'v' => sub { voice($inventory) },
);
$kernel->post($session, 'update');
my ($sec) = localtime(time());
$kernel->delay_set('again', 60 - $sec);
}
sub update
{
debug('t', "update");
my $heap = $_[HEAP];
my $formatter = $heap->{'formatter'};
my $wheel = $heap->{'wheel'};
my $format = $heap->{'db'}->{'formats'}->{'status'} || DEFAULT_STATUS;
my $cooked = $formatter->($format);
my $status = sprintf(SSFE_STATUSLINE_FORMAT, $cooked);
$wheel->put($status);
$wheel->put("\n");
}
sub again
{
debug('t', "again");
my ($kernel, $session) = @_[KERNEL, SESSION];
$kernel->post($session, 'update');
$kernel->delay_set('again', 60);
}
sub format
{
no warnings; # Yes, @args can be empty.
debug('t', 'format');
my ($kernel, $heap, $type, @args) = @_[KERNEL, HEAP, ARG0, ARG1..$#_];
my $wheel = $heap->{'wheel'};
my $db = $heap->{'db'};
my $format = $db->{'formats'}->{$type};
return unless $format;
my $message = sprintf($format, @args);
$wheel->put($message, "\n");
$kernel->post('nethirc_log', 'log', $message);
}
sub error
{
debug('t', 'error');
my ($heap, @args) = @_[HEAP, ARG0..ARG3];
my $wheel = $heap->{'wheel'};
$wheel->shutdown_input();
$wheel->shutdown_output();
delete $heap->{'wheel'};
}
sub datestamp
{
debug('t', "datestamp");
my $format = $_[0] || "%H:%M";
return POSIX::strftime($format, localtime(time));
}
sub nick
{
debug('t', "nick");
my $inventory = shift;
my $server = $inventory->current_server();
return NO_NICK unless $server;
return $server->nick();
}
sub chops
{
debug('t', "chops");
my $inventory = shift;
my $server = $inventory->current_server();
return "" unless $server;
my $channel = $server->current_channel();
return "" unless $channel;
if ($server->has_chops($channel))
{
return "@";
}
return "";
}
sub serverops
{
debug('t', "serverops");
my $inventory = shift;
my $server = $inventory->current_server();
return "" unless $server;
if ($server->oper())
{
return "*";
}
return "";
}
sub voice
{
debug('t', "voice");
my $inventory = shift;
my $server = $inventory->current_server();
return "" unless $server;
my $channel = $server->current_channel();
return "" unless $channel;
if ($server->has_chops($channel))
{
return ""; # +@ is redundant
}
if ($server->has_voice($channel))
{
return "+";
}
return "";
}
sub chanmode
{
debug('t', "chanmode");
my $inventory = shift;
my $server = $inventory->current_server();
return "" unless $server;
my $channel = $server->current_channel();
return "" unless $channel;
return $server->channel_mode($channel);
}
sub yourmode
{
debug('t', "yourmode");
my $inventory = shift;
my $server = $inventory->current_server();
return "" unless $server;
return $server->mymode();
}
sub channel
{
debug('t', "channel");
my $inventory = shift;
my $server = $inventory->current_server();
return NO_CHANNEL unless $server;
my $channel = $server->current_channel();
return NO_CHANNEL unless $channel;
if ($server->is_query($channel))
{
return "querying $channel";
}
return "on $channel";
}
sub server
{
debug('t', "server");
my $inventory = shift;
my $server = $inventory->current_server();
return NO_SERVER unless $server;
return $server->name();
}
sub isaway
{
debug('t', "away"),
my $inventory = shift;
my $server = $inventory->current_server();
return NOT_AWAY unless $server;
my $away = $server->away();
return NOT_AWAY unless $away;
return AWAY;
}
1;
__END__
SSFE quick reference:
`#ssfe#i set irc mode, confirmed with @ssfe@i
`#ssfe#c set cooked mode, confirmed with @ssfe@c
`#ssfe#s<text> set status line to <text>
`#ssfe#T<text> set text sent with ^T (newline added)
`#ssfe#t<text> add alternative to tab list
`#ssfe#l clear screen
`#ssfe#P prompt something, noecho
`#ssfe#p prompt something, echo
`#ssfe#n<text> insert text on input line
`#ssfe#o<text> store text to be recalled to input line via ^O
syntax highlighted by Code2HTML, v. 0.9.1