Scripts backup from msparks/irssiscripts

This commit is contained in:
q3aql 2021-04-02 13:04:11 +02:00
parent 6f16d64929
commit db98087730
11 changed files with 2123 additions and 0 deletions

233
scripts/anames.pl Normal file
View File

@ -0,0 +1,233 @@
# anames.pl
# Irssi script that adds an /anames command, a clone of /names, with away nicks
# grayed out.
#
# Thanks to Dirm and Chris62vw for the Perl help and coekie for writing the
# evil code to sort the nicklist by the alphabet and rank in nicklist.pl
#
# 1.5 - Fixed halfop display bug (patch by epinephrine), 20100712
#
# 1.4 - Merged changes from VMiklos and readded /who redirection to prevent
# spamming the status window. - ms, 20090122
#
# 1.3 - by VMiklos
# Doing /dowho is very annoying and /alias foo /dowho;/anames won't
# work either since anames will work from the old infos. So I've
# modified /anames to just do a /dowho and the nicklist will be printed
# when we'll get the answer from the server.
#
# 1.2 - It seems that redirected events will not pass through the internal
# mechanisms that update user information (like away states). So, it
# /dowho and the periodic execution of the command has been disabled.
# /anames will still work, but new away information will need to be
# obtained by executing a /who on a channel.
# If you can make redirection (execute a /who without the information
# spilling to the status window) work, let me know so I can fix the
# script.
#
# 1.0.1 - Fixed row-determining and max-nick-length code, changed command_add
# calls to refs instead of names.
#
# 1.0 - Added timer for periodic /who of all channels
#
# 0.9 - Initial test release
use strict;
use Irssi;
use POSIX;
#use Data::Dumper;
use vars qw($VERSION %IRSSI);
$VERSION = '1.5';
%IRSSI = (
authors => 'Matt "f0rked" Sparks, Miklos Vajna',
contact => 'ms+irssi@quadpoint.org',
name => 'anames',
description => 'a /names display with away nicks colored',
license => 'GPLv2',
url => 'http://quadpoint.org',
changed => '2010-07-12',
);
# How often to do a /who of all channels (in seconds)
#my $who_timer = 300;
my $tmp_server;
my $tmp_chan;
sub cmd_anames
{
my($args, $server, $item) = @_;
my $channel = Irssi::active_win->{active};
$tmp_server = $server;
$tmp_chan = $channel->{"name"};
if ($args ne "") {
$server = $args;
$server =~ s/-([^ ]*) .*/\1/;
$tmp_server = Irssi::server_find_tag($server);
$tmp_chan = $args;
$tmp_chan =~ s/-[^ ]* (.*)/\1/;
}
# set up redirection
$tmp_server->redirect_event("who", 1, $tmp_chan, 0, undef,
{
"event 352" => "redir who_reply",
"event 315" => "redir who_reply_end",
});
$tmp_server->command("who $tmp_chan");
}
sub print_anames
{
my $server = $tmp_server;
my $chan = $tmp_chan;
my $channel = Irssi::Server::channel_find($server, $chan);
my $nick;
if (!$channel) {
# no nicklist
Irssi::print("Not joined to any channel", MSGLEVEL_CLIENTERROR);
} else {
# Loop through each nick and display
my @nicks;
my($ops, $halfops, $voices, $normal, $away) = (0, 0, 0, 0, 0);
# sorting from nicklist.pl
foreach my $nick (sort {(($a->{'op'}?'1':$a->{'halfop'}?'2':$a->{'voice'}?'3':'4').lc($a->{'nick'}))
cmp (($b->{'op'}?'1':$b->{'halfop'}?'2':$b->{'voice'}?'3':'4').lc($b->{'nick'}))} $channel->nicks()) {
my $realnick = $nick->{'nick'};
my $gone = $nick->{'gone'};
my $prefix;
if ($nick->{'op'}) {
$prefix = "@";
$ops++;
} elsif ($nick->{'halfop'}) {
$prefix = "%%";
$halfops++;
} elsif ($nick->{'voice'}) {
$prefix = "+";
$voices++;
} else {
$prefix = " ";
$normal++;
}
$prefix = "%W$prefix%n";
if ($gone) {
$realnick = "%K$realnick%n";
$away++;
}
push @nicks, "$prefix" . $realnick;
}
my $total = @nicks;
$channel->print("%K[%n%gUsers%n %G" . $chan . "%n%K]%n",
MSGLEVEL_CLIENTCRAP);
columnize_nicks($channel,@nicks);
$channel->print("%W$chan%n: Total of %W$total%n nicks %K[%W$ops%n ops, " .
"%W$halfops%n halfops, %W$voices%n voices, %W$normal%n " .
"normal, %W$away%n away%K]%n",
MSGLEVEL_CLIENTNOTICE);
}
}
# create a /names style column, increasing alphabetically going down the
# columns.
sub columnize_nicks
{
my($channel, @nicks) = @_;
my $total = @nicks;
# determine max columns
# FIXME: this could be more intelligent (i.e., read window size)
my $cols = Irssi::settings_get_int("names_max_columns");
$cols = 6 if $cols == 0;
# determine number of rows
my $rows = round(ceil($total / $cols));
# array of rows
my @r;
for (my $i = 0; $i < $cols; $i++) {
# peek at next $rows items, determine max length
my $max_length = find_max_length(@nicks[0 .. $rows - 1]);
# fill rows
for (my $j = 0; $j < $rows; $j++) {
my $n = shift @nicks; # single nick
if ($n ne "") {
$r[$j] .= "%K[%n$n" . fill_spaces($n,$max_length) . "%K]%n ";
}
}
}
for (my $m = 0; $m < $rows; $m++) {
chomp $r[$m];
$channel->print($r[$m], MSGLEVEL_CLIENTCRAP);
}
}
sub fill_spaces
{
my($text, $max_length) = @_;
$text =~ s/%[a-zA-Z]//g;
return " " x ($max_length - length($text));
}
sub find_max_length
{
my $max_length = 0;
for (my $i = 0; $i < @_; $i++) {
my $nick = $_[$i];
$nick =~ s/%[a-zA-Z]//g;
if (length($nick) > $max_length) {
$max_length = length($nick);
}
}
return $max_length;
}
sub round
{
my($number) = @_;
return int($number + .5);
}
sub who_reply
{
my($server, $data) = @_;
my(undef, $c, $i, $h, $n, $s) = split / /, $data;
if ($tmp_chan ne $c) {
$tmp_chan = $c;
#print "Got who info for $c";
}
}
sub who_reply_end
{
print_anames();
$tmp_chan = "";
}
Irssi::Irc::Server::redirect_register("who", 0, 0,
{"event 352" => 1},
{"event 315" => 1},
undef);
Irssi::signal_add("redir who_reply", \&who_reply);
Irssi::signal_add("redir who_reply_end", \&who_reply_end);
Irssi::command_bind("anames", \&cmd_anames);

321
scripts/automode.pl Normal file
View File

@ -0,0 +1,321 @@
# automode.pl
#
# Passively learn and actively maintain the ops/voices/halfops in channels.
# This is a no-maintenance auto-op/auto-voice script for irssi.
#
# INSTALL:
# 1) /script load automode.pl
# 2) Be a channel operator
#
# HOW IT WORKS:
# When someone joins a channel and is given ops/voice/halfop, the script
# will record that user's mask, as a combination of their nickname and part
# of their hostname or IP address. When that person leaves and rejoins, the
# script will check against its database and regrant the user the modes
# he or she had before leaving.
#
# If a user is kicked from a channel, all modes for that person are removed.
# They must therefore be regiven by another operator manually. Note this.
#
# Also, this script relies on the "chatnet" attribute being set for a
# particular connection. Use /network (or /ircnet) to set up your networks
# and such. This script will spit out (lots of) warnings if the chatnet is
# not set.
#
# IGNORING CHANNELS:
# If you do not wish to maintain modes on a channel, add it to the setting
# "automode_ignore" in the form <tag>:<channel>, separated by spaces.
#
# For example: /set automode_ignore FreeNode:#perl EFnet:#irssi
# (should) not maintain modes in #perl on FreeNode or #irssi
# on EFnet, provided FreeNode and EFnet are the tags for those
# connections.
#
# NOTES:
# The Perl module Data::Serializer is needed for this script.
# The database file is not written instantaneously; it is on a timer and is
# written to every five minutes or so. If the script is reloaded before it has
# had a chance to save will result in forgotten modes.
#
use strict;
use Irssi;
use Data::Serializer;
use Data::Dumper;
use vars qw($VERSION %IRSSI);
$VERSION = '1.3';
%IRSSI = (
authors => 'Matt "f0rked" Sparks',
contact => 'ms+irssi@quadpoint.org',
name => 'automode',
description => 'Mode maintainer',
license => 'BSD',
url => 'http://quadpoint.org',
changed => '2008-06-14',
);
# show debug lines
my $debug = 0;
my $s = new Data::Serializer;
my $file = Irssi::get_irssi_dir."/automode_list";
if (!-e $file) {
print "[automode] creating $file";
system("touch $file");
}
my $listref = $s->retrieve($file);
my %list = $listref ? %{$listref} : ();
#print Dumper %list;
my $save_tag;
my %buffer_tags;
my %buffer;
sub save_list
{
$s->store(\%list,$file);
}
sub clear_list
{
%list = ();
}
sub make_mask
{
my($address) = @_;
return if !$address;
my($ident, $host) = split /@/, $address;
my @split = split /\./, $host;
if (@split <= 2) {
# host is something like "foo.com". We cannot make the mask *.com.
} else {
if ($split[$#split] =~ /^\d+$/) {
# Looks like an IP address.
pop @split;
$host = join(".", @split) . ".\d{1,3}";
} else {
# Mask the first segment.
shift @split;
$host = ".+?." . join(".", @split);
}
}
return ".+?!.*${ident}@" . "${host}";
}
sub show
{
my($net, $channel) = @_;
print Dumper %{$list{$net}->{$channel}};
}
sub show_all
{
my $list;
print Dumper %list;
}
sub clear_channel
{
my($net, $channel) = @_;
delete $list{$net}->{$channel};
}
sub set_modes
{
my($net, $channel) = @{$_[0]};
return if !$buffer{$net}->{$channel};
my($nicks, $modes) = values(%{$buffer{$net}->{$channel}});
print "[automode] modes: $modes, nicks: $nicks" if $debug;
my $c = Irssi::server_find_chatnet($net)->channel_find($channel);
# iterate through the modes and see which ones we don't have to set
my($final_modes, $final_nicks);
my $i = 0;
for (split //,$modes) {
my $m = $_;
my $n = (split / /, $nicks)[$i];
$i++;
next if (!$c->nick_find($n));
next if ($m eq "o" && $c->nick_find($n)->{"op"});
next if ($m eq "v" && $c->nick_find($n)->{"voice"});
next if ($m eq "h" && $c->nick_find($n)->{"halfop"});
# if we made it this far, add this to the final modes
$final_modes .= $m;
$final_nicks .= "$n ";
}
print "[automode] final modes: +$final_modes $final_nicks" if $debug;
$c->command("MODE $channel +$final_modes $final_nicks")
if ($final_modes && $final_nicks);
delete $buffer{$net}->{$channel};
}
sub mode2letter
{
my($mode) = @_;
if ($mode eq "@") {
return "o";
} elsif ($mode eq "+") {
return "v";
} elsif ($mode eq "%") {
return "h";
}
return -1;
}
sub remove_mode
{
my($net, $channel, $mask, $mode) = @_;
my $letter = mode2letter($mode);
$list{$net}->{$channel}->{$mask} =~ s/$letter//
if user_modes($net, $channel, $mask);
delete $list{$net}->{$channel}->{$mask}
if exists $list{$net}->{$channel}->{$mask}
and !$list{$net}->{$channel}->{$mask};
}
sub remove_all
{
my($net, $channel, $mask) = @_;
delete $list{$net}->{$channel}->{$mask}
if exists $list{$net}->{$channel}->{$mask};
}
sub user_modes
{
my($net, $channel, $mask) = @_;
return $list{$net}->{$channel}->{$mask};
}
sub add_mode
{
my($net, $channel, $mask, $mode) = @_;
return if !$mask or !$net or !$channel or !$mode;
my $letter = mode2letter($mode);
$list{$net}->{$channel}->{$mask} .= $letter
if $list{$net}->{$channel}->{$mask} !~ /$letter/;
Irssi::timeout_remove($save_tag);
$save_tag = Irssi::timeout_add_once(300, "save_list", []);
}
sub event_mode
{
my($channel, $nick, $setby, $mode, $type) = @_;
return if check_ignore($channel->{server}, $channel->{name});
my $w = Irssi::active_win;
return if $mode != '@' and $mode != '%' and $mode != '+';
my $chatnet = $channel->{server}->{chatnet};
my $tag = $channel->{server}->{tag};
print ("[automode] The 'chatnet' attribute is missing for the tag '$tag'. " .
"Use /network (or /ircnet) to properly manage this.") if !$chatnet;
return if !$chatnet;
my $mask = make_mask($nick->{host});
print "[automode] failed to make mask ($mask)" if (!$mask && $debug);
return if !$mask;
if ($type eq "+") {
print ("[automode] adding mode '$mode' for $mask in $channel->{name} on " .
$chatnet) if $debug;
add_mode($chatnet, $channel->{name}, $mask, $mode);
} else {
# don't remove op if they deop themselves.
return if $setby eq $nick->{nick};
print ("[automode] removing mode '$mode' for $mask in $channel->{name} " .
" on $chatnet") if $debug;
remove_mode($chatnet, $channel->{name}, $mask, $mode);
}
#show($chatnet, $channel->{name});
}
sub event_join
{
my($server, $channel, $nick, $address) = @_;
return if check_ignore($server, $channel);
my $mask = make_mask($address);
return if !user_modes($server->{chatnet}, $channel, $mask);
my $c = $server->channel_find($channel);
return if not $c->{chanop};
if (my $modes = user_modes($server->{chatnet}, $channel, $mask)) {
print "[automode] Matched mask ($mask) with modes: $modes" if $debug;
my $nick_list = "$nick " x length($modes);
my %buf = ($buffer{$server->{chatnet}}->{$channel} ?
%{$buffer{$server->{chatnet}}->{$channel}} : ());
$buf{modes} .= $modes;
$buf{nicks} .= $nick_list;
$buffer{$server->{chatnet}}->{$channel} = \%buf;
my $tag = $server->{chatnet} . "_$channel";
Irssi::timeout_remove($buffer_tags{$tag});
$buffer_tags{$tag} = Irssi::timeout_add_once(1000 + int(rand(250) * 3),
"set_modes",
[$server->{chatnet},
$channel]);
#print Dumper %buffer;
}
}
sub event_kick
{
my($server, $channel, $nick, $kicker, $address, $reason) = @_;
my $n = $server->channel_find($channel)->nick_find($nick);
#print Dumper $n;
my $mask = make_mask($n->{host});
remove_all($server->{chatnet}, $channel, $mask) if $mask;
}
sub check_ignore
{
my($server, $channel) = @_;
my $chatnet = $server->{chatnet};
my $ignore = Irssi::settings_get_str("automode_ignore") . " ";
return ($ignore =~ /$chatnet:$channel /i) ? 1 : 0;
}
# I don't think this does what I want it to do.
sub event_exit
{
save_list;
}
Irssi::signal_add("gui exit", "event_exit");
Irssi::signal_add("message kick", "event_kick");
Irssi::signal_add("message join", "event_join");
Irssi::signal_add("nick mode changed", "event_mode");
Irssi::settings_add_str("automode", "automode_ignore", "IM:&bitlbee");

View File

@ -0,0 +1,62 @@
# Sends autoreplies to IM users when they message while you are away.
#
# SETTINGS
# [bitlbee]
# bitlbee_autoreply_duration = OFF
# -> Send how long you have been away in your auto-reply. This requires
# Time::Duration.
# Example auto-reply: "gone (away: 3 minutes and 2 seconds)"
use strict;
use Irssi;
use Time::Duration qw/duration_exact/;
use vars qw($VERSION %IRSSI);
$VERSION = '0.12';
%IRSSI = (
authors => 'Matt "f0rked" Sparks',
contact => 'ms+irssi@quadpoint.org',
name => 'bitlbee status notice',
description => 'Sends autoreplies to IM users while you are away',
license => 'GPLv2',
url => 'http://quadpoint.org',
changed => '2005-12-04',
);
my $bitlbee_channel = "&bitlbee";
my $bitlbee_server_tag = "IM";
my(%times, $away, $away_time);
sub away
{
$away_time=time;
%times=();
}
sub event_msg
{
my($server, $msg, $nick, $address, $target) = @_;
return if $server->{tag} ne $bitlbee_server_tag;
return unless $server->{usermode_away};
#return unless $address =~ /\@login\.oscar\.aol\.com$/; # Only send for AIM.
return unless !$target or ($target eq $bitlbee_channel and $nick ne "root");
return unless time - $times{$nick} > 3600; # send an auto-reply once an hour.
$times{$nick} = time;
my $append;
if (Irssi::settings_get_bool("bitlbee_autoreply_duration") && $away_time) {
$append = " (away: " . duration_exact(time - $away_time) . ")";
}
$server->command("/notice $nick $server->{away_reason}$append");
}
Irssi::signal_add("message private", "event_msg");
Irssi::signal_add("message public", "event_msg");
Irssi::signal_add("away mode changed", "away");
Irssi::settings_add_bool("bitlbee", "bitlbee_autoreply_duration", 0);

460
scripts/bitlbee_html.pl Normal file
View File

@ -0,0 +1,460 @@
# This script is a drop-in HTML filter and parser for use with bitlbee and
# irssi. HTML that can be rendered will be, and the rest will be stripped.
# This should not interfere with other scripts for bitlbee; it is intended to be
# a transparent mangler.
#
# TO USE:
# 1) Adjust the channel and server tag settings below.
# 2) Load the script
# 3) In the bitlbee control channel (&bitlbee), type: set strip_html false
# 4) Enjoy.
#
# For use with bitlbee 1.0+. ChangeLog is available at the bottom of the file.
#
# SETTINGS
# [bitlbee]
# bitlbee_replace_html = ON
# -> replaces HTML in incoming AIM messages
# bitlbee_replace_control_codes = OFF
# -> replaces control codes (bold, underline, reverse) in outgoing private
# messages to AIM users with HTML equivalents. This is turned off by
# default due to the known bug below. If this wouldn't bother you, and you
# would like to have this feature, there's no real harm in turning it on.
# bitlbee_strip_trailing_whitespace = OFF
# -> removes whitespace at the end of messages
#
# KNOWN BUGS
# * This script is somewhat incompatible with splitlong.pl. When long messages
# get split up, and bitlbee_replace_control_codes is ON, the control codes
# will properly get replaced when they are sent to the remote user, but when
# the subsequent split parts are displayed, they may contain the html that
# is supposed to be hidden.
use strict;
use Irssi::TextUI;
use Data::Dumper;
use vars qw($VERSION %IRSSI);
$VERSION = '0.95';
%IRSSI = (
authors => 'Matt "f0rked" Sparks',
contact => 'ms+irssi@quadpoint.org',
name => 'bitlbee_html',
description => 'Adds some HTML parsing to bitlbee messages',
license => 'GPLv2',
url => 'http://quadpoint.org',
changed => '2005-12-18',
);
# TODO: Make these settings (?)
my $bitlbee_channel = "&bitlbee";
my $bitlbee_server_tag = "IM";
# Time to wait to collect all parts of a message from bitlbee server
my $buffer_timeout = 200; # milliseconds
# How long does a message have to be before we consider it a split?
my $split_length = 425;
my %buffer;
my %emitting;
my $debug = 0;
# Thanks to timing (http://the-timing.nl) for this
Irssi::signal_add_last 'channel sync' => sub
{
my($channel) = @_;
if ($channel->{topic} eq "Welcome to the control channel. Type \x02help\x02 for help information.") {
$bitlbee_server_tag = $channel->{server}->{tag};
$bitlbee_channel = $channel->{name};
}
};
# Debug to the active window
sub adebug
{
return if !$debug;
my($t) = @_;
my $w = Irssi::active_win();
$w->print($t, MSGLEVEL_CLIENTCRAP);
}
# Debug to the status window
sub sdebug
{
return if !$debug;
my($t) = @_;
print $t;
}
sub trim
{
($_) = @_;
s/^\s*(.+)\s*$/$1/;
return $_;
}
# return true if given address supports HTML, false if not.
sub does_html
{
my($address) = @_;
return ($address =~ /^[a-z].*\@login\.oscar\.aol\.com$/i ||
$address =~ /^[a-z].*\@login\.icq\.com$/i) ? 1 : 0;
}
# More advanced checking in the future?
sub bee_server
{
my($server) = @_;
return 0 if !$server;
return ($server->{tag} ne $bitlbee_server_tag) ? 0 : 1;
}
sub html2irc
{
($_) = @_;
#print "Before: $_";
s/<br ?\/?>/\n/isg;
s/<font .+?>//isg;
s/<\/font>//ig;
s/<\/?body.*?>//isg;
s/<\/?html>//ig;
s/<a .*?href="(.+?)".*?>(.*?)<\/a>/handle_link($1,$2)/iesg;
# note for <b>,<i>, and <u>, these are encapsulating tags, and they _may_
# contain newlines. This script will split by newlines and emit message
# signals for each part, and a part may end up looking like "<b>foo" with
# no end tag, because the end tag is on the next message. To fix this, we
# have to also check for <b>foo\n and ^foo</b> and put the control codes
# in the appropriate places to avoid formatting the wrong text.
s/<b>(.*?)<\/b>/\002$1\002/ig; # bold
s/<b>(.*?)\n/\002$1\n/isg;
s/^(.*?)<\/b>/\002$1\002/isg;
s/<u>(.*?)<\/u>/\037$1\037/ig; # underline
s/<u>(.*?)\n/\037$1\n/isg;
s/^(.*?)<\/u>/\037$1\037/isg;
s/<i>(.*?)<\/i>/\026$1\026/ig; # reverse (for italics)
s/<i>(.*?)\n/\026$1\n/isg;
s/^(.*?)<\/i>/\026$1\026/isg;
s/&quot;/"/ig;
s/&lt;/</ig;
s/&gt;/>/ig;
s/&amp;/&/ig;
#print "After: $_";
return $_;
}
sub irc2html
{
($_) = @_;
my $ret;
adebug "irc2html input: $_";
if (/^<html>/) {
# Already htmlized? This shouldn't happen. Assume that html tags were
# manually inserted, in which case we should just escape the html and
# return.
s/&/&amp;/g;
s/"/&quot;/g;
s/</&lt;/g;
s/>/&gt;/g;
$ret = "<html>$_</html>";
adebug "irc2html return: $ret";
return $ret;
}
my $orig = $_;
s/&/&amp;/g;
s/"/&quot;/g;
s/</&lt;/g;
s/>/&gt;/g;
s/\002(.*?)\002/<b>$1<\/b>/sg; # bold
s/\002(.*)/<b>$1<\/b>/sg; # unended bold
s/\037(.*?)\037/<u>$1<\/u>/sg; # underline
s/\037(.*)/<u>$1<\/u>/sg;
s/\026(.*?)\026/<i>$1<\/i>/sg; # reverse (italics)
s/\026(.*)/<i>$1<\/i>/sg;
s/\003/<br>/g; # newlines.. this is ctrl+c in irssi.
#print "After: $_, length: ".length($_);
my $ret = ($_ ne $orig) ? "<html>$_</html>" : $orig;
adebug "irc2html return: $ret";
return $ret;
}
sub handle_link
{
my($url, $title) = @_;
$title = html2irc($title);
#adebug $url;
#adebug $title;
if ($url eq $title) {
return $url;
} elsif ($url eq "mailto:$title") {
return $title;
} else {
my $str = "[$title]($url)";
$str =~ s/^\[(\n)*/$1\[/;
return $str;
}
}
sub event_privmsg
{
my($server, $msg, $nick, $address) = @_;
return if !Irssi::settings_get_bool("bitlbee_replace_html");
return if !does_html($address);
return if $emitting{"priv_$nick"}; # don't catch if we're sending signal
return if !bee_server($server);
#print "Received msg: $msg";
# Check the buffer. If it is empty, set a timeout. Fill it in either
# case. This step is necessary because long messages will naturally
# get split up, and to avoid the HTML cutting split up, we buffer
# and then parse everything at once.
if (!$buffer{"priv_$nick"}) {
# We have no buffer, this is a new message
my @data = ("priv", $server, $nick, $address);
Irssi::timeout_add_once($buffer_timeout, "check_buffer", \@data);
}
$msg .= " ";
sdebug "Adding part: '$msg'";
$buffer{"priv_$nick"} .= $msg;#."\002|\002";
# Length hack. Sometimes we get multiple messages quickly from bitlbee
# that aren't html formatted with <br>. Detect this and add newlines
# appropriately.
my $length = length("$nick $address $msg");
sdebug "Length: $length";
if ($length < $split_length) {
$buffer{"priv_$nick"} .= "\n";
}
Irssi::signal_stop;
}
sub event_pubmsg
{
my($server, $msg, $nick, $address, $target) = @_;
return if !Irssi::settings_get_bool("bitlbee_replace_html");
return if !bee_server($server);
return if !does_html($address) and $nick ne "root"; # only aim does html.
return if $emitting{"pub_$nick"};
if (!$buffer{"pub_$nick"}) {
my @data = ("pub", $server, $nick, $address, $target);
Irssi::timeout_add_once($buffer_timeout, "check_buffer", \@data);
}
$buffer{"pub_$nick"} .= $msg;
if (length("$nick $address $msg $target") < $split_length) {
$buffer{"pub_$nick"} .= "\n";
}
Irssi::signal_stop;
}
sub event_action
{
my($server, $msg, $nick, $address, $target) = @_;
#print $msg;
return if !Irssi::settings_get_bool("bitlbee_replace_html");
return if !does_html($address);
return if $emitting{"act_$nick"};
return if !bee_server($server);
if (!$buffer{"act_$nick"}) {
my @data = ("act", $server, $nick, $address, $target);
Irssi::timeout_add_once($buffer_timeout, "check_buffer", \@data);
}
$buffer{"act_$nick"} .= $msg;
if (length("$nick $address $msg $target") < $split_length) {
$buffer{"act_$nick"} .= "\n";
}
Irssi::signal_stop;
}
sub event_send_text
{
my($text, $server, $witem) = @_;
return if !bee_server($server);
return if !Irssi::settings_get_bool("bitlbee_replace_control_codes");
# This will make sure that the person we are talking to is on AIM.
my $address;
my $modified_text = $text;
if ($witem->{type} eq "CHANNEL") {
if (my($n, $s, $m) = $text =~ /^([^ ]+):([ ]*)(.*)$/) {
$address = $witem->nick_find($n)->{host};
$modified_text = "$n:$s" . irc2html($m);
}
} else {
$address = $witem->{address};
$modified_text = irc2html($text);
}
return if !does_html($address);
#print Dumper $witem;
#print "Sending: $modified_text";
Irssi::signal_stop;
Irssi::signal_continue($modified_text, $server, $witem);
}
sub event_send_command
{
my($args, $server, $witem) = @_;
return if !bee_server($server);
adebug "send command: $args";
}
sub event_message_own
{
my($server, $msg, $target, $orig_target) = @_;
return if !bee_server($server);
return if !Irssi::settings_get_bool("bitlbee_replace_control_codes");
return if !Irssi::settings_get_bool("bitlbee_replace_html");
if ($msg =~ /^<html>/ || $msg =~ /^([^ ]+):[ ]*<html>/) {
# If we're on the bitlbee server and the message looks like html,
# we're here.
#print "$server '$msg' $target $orig_target";
if ($orig_target && (my $qu = $server->query_find($target))) {
#print "orig target, found query.";
if ($qu->{address} && !does_html($qu->{address})) {
# The person we're talking to is not using an HTML-compatible
# protocol. Don't treat this as html.
return;
}
} elsif (!$orig_target &&
(my $ch = $server->channel_find($target)) &&
(my($t) = $msg =~ /^([^ ]+):/)) {
my $to_nick = $ch->nick_find($t);
if ($to_nick->{address} && !does_html($to_nick->{address})) {
# We're talking to someone in a particular channel on
# bitlbee, but they don't support HTML.
return;
}
}
# If we made it this far, treat the message as HTML.
Irssi::signal_stop;
Irssi::signal_continue($server, html2irc($msg), $target, $orig_target);
}
}
sub check_buffer
{
my($type, $server, $nick, $address, $target) = @{@_[0]};
# We should now have a full buffer for $nick, we can examine it, parse
# it, and re-emit the appropriate signals without any HTML splitting
# problems.
my $msg = $buffer{"${type}_${nick}"};
sdebug "Complete msg: $msg";
return if !$msg;
$msg = html2irc($msg);
$msg =~ s/[\s]*$//
if Irssi::settings_get_bool("bitlbee_strip_trailing_whitespace");
# $msg is now in the appropriate format, we can emit the signal.
$emitting{"${type}_${nick}"} = 1;
my $sig = "message ";
if ($type eq "priv") {
$sig.="private";
} elsif ($type eq "pub") {
$sig.="public";
} else {
$sig.="irc action";
}
#print "Emitting $sig";
for (split /\n/, $msg) {
Irssi::signal_emit($sig, $server, $_, $nick, $address, $target);
}
delete($buffer{"${type}_${nick}"});
delete($emitting{"${type}_${nick}"});
}
sub event_301
{
return if !Irssi::settings_get_bool("bitlbee_replace_html");
my($server, $data, $foo, $bar)=@_;
return if !bee_server($server);
my($me, $them, @msg) = split / /, $data;
my $msg = join " ", @msg;
$msg = html2irc($msg);
$msg = ~s/[\s]*$//
if Irssi::settings_get_bool("bitlbee_strip_trailing_whitespace");
Irssi::signal_stop;
Irssi::signal_continue($server, "$me $them $msg", $foo, $bar);
}
Irssi::signal_add_first("message private", "event_privmsg");
Irssi::signal_add_first("message public", "event_pubmsg");
Irssi::signal_add_first("event 301", "event_301");
Irssi::signal_add_first("message irc action", "event_action");
Irssi::signal_add_first("send text", "event_send_text");
Irssi::signal_add_first("send command", "event_send_command");
Irssi::signal_add_first("message own_private", "event_message_own");
Irssi::signal_add_first("message own_public", "event_message_own");
Irssi::signal_add_first("message irc own_action", "event_message_own");
# Settings
Irssi::settings_add_bool("bitlbee", "bitlbee_replace_html", 1);
Irssi::settings_add_bool("bitlbee", "bitlbee_replace_control_codes", 0);
Irssi::settings_add_bool("bitlbee", "bitlbee_strip_trailing_whitespace", 0);
### ChangeLog ###
# Version 0.95
# - fixed a small bug causing links to sometimes not be properly formatted
# Version 0.94
# - fixed bug causing a script error when typing in the status window and on
# startup of irssi
# Version 0.93
# - fixed a stupid case issue in address recognization.
# Version 0.92
# - code cleanups
# - control codes are allowed in control channel, but targets must be used
# (remoteuser: I'm talking to you) (this is the default)
# Version 0.91
# - more intelligent checking for HTML support
# - allowed html from AIM users over ICQ connections
# Version 0.9
# - removed html parsing for non-AIM connections
# - added support for replacing control codes (created by ctrl+b, ctrl+v, and
# cltr+-) with html equivalents. Disabled by default.
#
# Version 0.8 (2005-12-02)
# - Initial public release

View File

@ -0,0 +1,211 @@
# bitlbee_status_notice.pl
# Adds detailed information about status changed to bitlbee query windows
# Information about known offline, online, and away durations will be printed
# to open query windows of buddies. Away messages will also be asked for when
# using the Oscar network.
# To use:
# Set the correct values for $bitlbee_* below, and then:
# /script load bitlbee_status_notice.pl
# Settings:
# /set bitlbee_hide_joins ON|OFF
# Prevents joins from showing up in #bitlbee control channel when buddies
# sign on
# /set bitlbee_hide_quits ON|OFF
# Same for buddies signing off, except it also applies to query windows,
# because Irssi shows quit notices in query windows automatically.
#
# As of version 1.4, these settings default to OFF.
# If you wish also to ignore mode changes (voicing/devoicing):
# /ignore &bitlbee MODES
use strict;
use Irssi;
use Time::Duration;
use Data::Dumper;
use vars qw($VERSION %IRSSI);
$VERSION = '1.4';
%IRSSI = (
authors => 'Matt "f0rked" Sparks',
contact => 'ms+irssi@quadpoint.org',
name => 'bitlbee_status_notice',
description => 'Adds detailed information about status changes to bitlbee query windows',
license => 'GPLv2',
url => 'http://quadpoint.org',
changed => '2010-03-04',
);
my $bitlbee_channel = "&bitlbee";
my $bitlbee_server_tag = "IM";
my %away_watch;
my %away_times;
my %online_times;
my %offline_times;
my $hide_it;
my $requested_info;
Irssi::theme_register([
'state_away', '{channick $0} {chanhost $1} has gone away',
'state_back', '{channick_hilight $0} {chanhost_hilight $1} has come back$2',
'away_msg', '{chanhost msg} $0',
'join', '{channick_hilight $0} {chanhost_hilight $1} has signed on$2',
'quit', '{channick $0} {chanhost $1} has signed off$2',
]);
Irssi::signal_add_last 'channel sync' => sub
{
my($channel) = @_;
if ($channel->{topic} eq "Welcome to the control channel. Type \x02help\x02 for help information.") {
$bitlbee_server_tag = $channel->{server}->{tag};
$bitlbee_channel = $channel->{name};
}
};
sub get_channel
{
my @channels = Irssi::channels();
foreach my $channel (@channels) {
if ($channel->{topic} eq "Welcome to the control channel. Type \x02help\x02 for help information.") {
$bitlbee_channel = $channel->{name};
$bitlbee_server_tag = $channel->{server}->{tag};
return 1;
}
}
return 0;
}
sub event_join
{
my($server, $channel, $nick, $address) = @_;
if ($channel eq $bitlbee_channel && $server->{tag} eq $bitlbee_server_tag) {
my $off_time;
$off_time = time - $offline_times{$nick} if $offline_times{$nick};
delete $offline_times{$nick} if $offline_times{$nick};
my $str;
$str = " (last seen: " . ago_exact($off_time) . ")" if $off_time;
$online_times{$nick} = time;
my $window = $server->query_find($nick);
if ($window) {
$window->printformat(MSGLEVEL_JOINS, "join", $nick, $address, $str);
}
Irssi::signal_stop() # don't print the join announcement in &bitlbee
if Irssi::settings_get_bool("bitlbee_hide_joins");
}
}
sub event_quit
{
my($server, $nick, $address, $reason) = @_;
if ($server->{tag} eq $bitlbee_server_tag) {
my $on_time;
$on_time = time - $online_times{$nick} if $online_times{$nick};
delete $online_times{$nick} if $online_times{$nick};
my $str;
$str = " (duration: " . duration($on_time) . ")" if $on_time;
$offline_times{$nick} = time;
my $window = $server->query_find($nick);
if ($window) {
$window->printformat(MSGLEVEL_QUITS, "quit", $nick, $address, $str);
}
Irssi::signal_stop() # don't print the quit announcement anywhere
if Irssi::settings_get_bool("bitlbee_hide_quits");
}
}
sub event_mode
{
my($channel, $nick, $setby, $mode, $type) = @_;
#print Dumper $nick;
#print Dumper $channel;
if ($mode eq "+" && $channel->{name} eq $bitlbee_channel &&
$channel->{server}->{tag} eq $bitlbee_server_tag) {
my $window = $channel->{server}->query_find($nick->{nick});
my $gone_time;
if ($type eq "-") {
$away_times{$nick->{nick}} = time;
} elsif ($type eq "+") {
if (my $time = $away_times{$nick->{nick}}) {
$gone_time = time-$time;
delete $away_times{$nick->{nick}};
}
}
if ($window) {
if ($type eq "+") {
my $gone_str;
$gone_str = " (gone: ".duration($gone_time).")" if $gone_time;
$window->printformat(MSGLEVEL_MODES, "state_back", $nick->{nick},
$nick->{host}, $gone_str)
if (time-$online_times{$nick->{nick}} > 2);
} elsif ($type eq "-") {
$window->printformat(MSGLEVEL_MODES, "state_away", $nick->{nick},
$nick->{host});
if ($nick->{host} =~ /login\.oscar\.aol\.com$/) {
$away_watch{nick} = $nick->{nick};
$channel->{server}->send_message($channel->{name},
"info $nick->{nick}", 0);
$requested_info = 1;
}
}
}
}
}
sub pub_msg
{
my($server, $msg, $nick, $address, $target) = @_;
#print "$msg $nick $address $target";
if ($nick eq "root" && $server->{tag} eq $bitlbee_server_tag &&
$target eq $bitlbee_channel) {
my $window = $server->channel_find($target);
if ($window) {
my $qwin;
$qwin = $server->query_find($away_watch{nick}) if $away_watch{nick};
if ($msg =~ /^TOC\(?.*\)? \- Away Message/g ||
$msg =~ /^oscar \- Away Message/) {
$away_watch{watch} = 1;
$hide_it = 1 if $requested_info;
Irssi::timeout_add_once(400,
sub { $hide_it = 0; $requested_info = 0; },
"");
#$qwin->print("Away message:",MSGLEVEL_CRAP) if $qwin;
} elsif ($msg =~ /^TOC\(?.*\)? \- .+$/ || $msg =~ /^oscar \- .+$/) {
delete $away_watch{watch};
delete $away_watch{nick};
} elsif ($away_watch{watch} && $qwin) {
$qwin->printformat(MSGLEVEL_CRAP, "away_msg", $msg) if $qwin;
}
}
Irssi::signal_stop if $hide_it;
}
}
get_channel();
Irssi::settings_add_bool("bitlbee", "bitlbee_hide_joins", 0);
Irssi::settings_add_bool("bitlbee", "bitlbee_hide_quits", 0);
Irssi::signal_add("message public", "pub_msg");
Irssi::signal_add("nick mode changed", "event_mode");
Irssi::signal_add("message join", "event_join");
Irssi::signal_add("message quit", "event_quit");

View File

@ -0,0 +1,319 @@
# INSTALLATION
# [&bitlbee] set typing_notice true
# <@root> typing_notice = `true'
# AND
# /statusbar window add typing_notice
#
# SETTINGS
# [bitlbee]
# bitlbee_send_typing = ON
# -> send typing messages to buddies
# bitlbee_typing_allwin = OFF
# -> show typing notifications in all windows
#
#
# Changelog:
#
# 2006-11-02 (version 1.6.1_
# * Sending typing works again.
#
# 2006-10-27 (version 1.6)
# * 'channel sync' re-implemented.
# * bitlbee_send_typing was a string setting, It's a boolean now, like it should.
#
# 2006-10-24 (version 1.5)
# * Sending notices to online users only.
# * Using the new get_channel function;
#
# 2005-12-15 (version 1.42):
# * Fixed small bug with typing notices disappearing under certain circumstances
# in channels
# * Fixed bug that caused outgoing notifications not to work
# * root cares not about our typing status.
#
# 2005-12-04 (version 1.41):
# * Implemented stale states in statusbar (shows "(stale)" for OSCAR connections)
# * Introduced bitlbee_typing_allwin (default OFF). Set this to ON to make
# typing notifications visible in all windows.
#
# 2005-12-03 (version 1.4):
# * Major code cleanups and rewrites for bitlbee 1.0 with the updated typing
# scheme. TYPING 0, TYPING 1, and TYPING 2 are now supported from the server.
# * Stale states (where user has typed in text but has stopped typing) are now
# recognized.
# * Bug where user thinks you are still typing if you close the window after
# typing something and then erasing it quickly.. fixed.
# * If a user signs off while they are still typing, the notification is removed
# This update by Matt "f0rked" Sparks
#
# 2005-08-26:
# Some fixes for AIM, Thanks to Dracula.
#
# 2005-08-16:
# AIM supported, for sending notices, using CTCP TYPING 0. (Use the AIM patch from Hanji http://get.bitlbee.org/patches/)
#
# 2004-10-31:
# Sends typing notice to the bitlbee server when typing a message in irssi. bitlbee > 0.92
#
# 2004-06-11:
# shows [typing: ] in &bitlbee with multiple users.
#
use strict;
use Irssi;
use Irssi::TextUI;
use vars qw($VERSION %IRSSI);
$VERSION = '1.6.1';
%IRSSI = (
authors => 'Tijmen "timing" Ruizendaal, Matt "f0rked" Sparks',
contact => 'tijmen.ruizendaal@gmail.com, ms+irssi@quadpoint.org',
name => 'BitlBee_typing_notice',
description => '1. Adds an item to the status bar wich shows [typing] when someone is typing a message on the supported IM-networks
2. Sending typing notices to the supported IM networks (the other way around)',
license => 'GPLv2',
url => 'http://the-timing.nl/stuff/irssi-bitlbee, http://quadpoint.org',
changed => '2006-11-02',
);
my $bitlbee_channel = "&bitlbee";
my $bitlbee_server_tag = "localhost";
my $KEEP_TYPING_TIMEOUT = 1;
my $STOP_TYPING_TIMEOUT = 7; # How often to check if we are typing, or on msn,
# how long to keep the typing notice up, or check
# if the other user is still typing...
my %timer_tag;
my %typing;
my %tag;
my $line;
my %out_typing;
my $lastkey;
my $keylog_active = 1;
my $command_char = Irssi::settings_get_str('cmdchars');
my $to_char = Irssi::settings_get_str("completion_char");
get_channel();
Irssi::signal_add_last 'channel sync' => sub {
my($channel) = @_;
if ($channel->{topic} eq "Welcome to the control channel. Type \x02help\x02 for help information.") {
$bitlbee_server_tag = $channel->{server}->{tag};
$bitlbee_channel = $channel->{name};
}
};
sub get_channel {
my @channels = Irssi::channels();
foreach my $channel(@channels) {
if ($channel->{topic} eq "Welcome to the control channel. Type \x02help\x02 for help information.") {
$bitlbee_channel = $channel->{name};
$bitlbee_server_tag = $channel->{server}->{tag};
return 1;
}
}
return 0;
}
sub event_ctcp_msg {
my ($server, $msg, $from, $address) = @_;
#print "CTCP: $msg $from $address";
return if $server->{tag} ne $bitlbee_server_tag;
if (my($type) = $msg =~ "TYPING ([0-9])") {
Irssi::signal_stop();
if ($type == 0) {
unset_typing($from);
}
elsif ($type == 1) {
$typing{$from}=1;
if ($address !~ /\@login\.oscar\.aol\.com/
and $address !~ /\@YAHOO/
and $address !~ /\@login\.icq\.com/) {
#Irssi::timeout_remove($tag{$from});
#$tag{$from}=Irssi::timeout_add_once($STOP_TYPING_TIMEOUT*1000,"unset_typing",$from);
}
redraw($from);
}
elsif ($type == 2) {
stale_typing($from);
}
}
}
sub unset_typing {
my($from, $no_redraw)=@_;
delete $typing{$from} if $typing{$from};
Irssi::timeout_remove($tag{$from});
redraw($from) if !$no_redraw;
}
sub stale_typing {
my($from) = @_;
$typing{$from} = 2;
redraw($from);
}
sub redraw {
my($from)=@_;
my $window = Irssi::active_win();
my $channel = $window->get_active_name();
if ($from eq $channel || $channel eq $bitlbee_channel
|| $channel =~ /&chat_0/
|| Irssi::settings_get_bool("bitlbee_typing_allwin")) {
Irssi::statusbar_items_redraw('typing_notice');
}
}
sub event_msg {
my ($server,$data,$from,$address,$target) = @_;
return if $server->{tag} ne $bitlbee_server_tag;
my $channel=Irssi::active_win()->get_active_name();
unset_typing $from, "no redraw";
unset_typing $channel;
}
sub event_quit {
my($server,$nick,$address,$reason)=@_;
return if $server->{tag} ne $bitlbee_server_tag;
unset_typing $nick;
}
sub typing_notice {
my ($item, $get_size_only) = @_;
my $window = Irssi::active_win();
my $channel = $window->get_active_name();
if (exists($typing{$channel})) {
my $append=$typing{$channel}==2 ? " (stale)" : "";
$item->default_handler($get_size_only, "{sb typing$append}", 0, 1);
}
else {
$item->default_handler($get_size_only, "", 0, 1);
Irssi::timeout_remove($tag{$channel});
}
if ($channel eq $bitlbee_channel || $channel =~ /&chat_0/
|| Irssi::settings_get_bool("bitlbee_typing_allwin")) {
foreach my $key (keys(%typing)) {
$line .= " ".$key;
if ($typing{$key}==2) { $line .= " (stale)"; }
}
if ($line ne "") {
$item->default_handler($get_size_only, "{sb typing:$line}", 0, 1);
$line = "";
}
}
}
sub empty {
my $from = shift;
delete($typing{$from});
Irssi::statusbar_items_redraw('typing_notice');
}
sub window_change {
Irssi::statusbar_items_redraw('typing_notice');
my $win = !Irssi::active_win() ? undef : Irssi::active_win()->{active};
if (ref $win && ($win->{server}->{tag} eq $bitlbee_server_tag)) {
if (!$keylog_active) {
$keylog_active = 1;
Irssi::signal_add_last('gui key pressed', 'key_pressed');
#print "Keylog started";
}
}
else {
if ($keylog_active) {
$keylog_active = 0;
Irssi::signal_remove('gui key pressed', 'key_pressed');
#print "Keylog stopped";
}
}
}
sub key_pressed {
return if !Irssi::settings_get_bool("bitlbee_send_typing");
my $key = shift;
if ($key != 9 && $key != 10 && $lastkey != 27 && $key != 27
&& $lastkey != 91 && $key != 126 && $key != 127)
{
my $server = Irssi::active_server();
my $window = Irssi::active_win();
my $nick = $window->get_active_name();
if ($server->{tag} eq $bitlbee_server_tag &&
$nick ne "(status)" &&
$nick ne "root")
{
if ($nick eq $bitlbee_channel) {
my $input = Irssi::parse_special("\$L");
my ($first_word) = split(/ /,$input);
if ($input !~ /^$command_char.*/ && $first_word =~ s/$to_char$//){
send_typing($first_word);
}
}
else {
my $input = Irssi::parse_special("\$L");
if ($input !~ /^$command_char.*/ && length($input) > 0){
send_typing($nick);
}
}
}
}
$lastkey = $key;
}
sub out_empty {
my ($a) = @_;
my($nick,$tag)=@{$a};
delete($out_typing{$nick});
#print $winnum."|".$nick;
if (my $server=Irssi::server_find_tag($tag)) {
$server->command("^CTCP $nick TYPING 0");
}
}
sub send_typing {
my $nick = shift;
if (!exists($out_typing{$nick}) || time - $out_typing{$nick} > $KEEP_TYPING_TIMEOUT) {
my @nicks = Irssi::server_find_tag($bitlbee_server_tag)->channel_find($bitlbee_channel)->nicks();
my $exists=0;
foreach my $nick1(@nicks) { #check if the nickname is in the BitlBee channel
if($nick1->{'nick'} eq $nick) {
#print "Exists!";
$exists=1;
}
}
if (!$exists) {
#print "Does not exist";
return;
}
#print "Send typing";
my $server = Irssi::active_server();
$server->command("^CTCP $nick TYPING 1");
$out_typing{$nick} = time;
### Reset 'stop-typing' timer
if ($timer_tag{$nick}) {
Irssi::timeout_remove($timer_tag{$nick});
delete($timer_tag{$nick});
}
$timer_tag{$nick} = Irssi::timeout_add_once($STOP_TYPING_TIMEOUT*1000, 'out_empty', ["$nick", $server->{tag}]);
}
}
# README: Delete the old bitlbee_send_typing string from ~/.irssi/config.
# A boolean is better.
Irssi::settings_add_bool("bitlbee","bitlbee_send_typing",1);
Irssi::settings_add_bool("bitlbee","bitlbee_typing_allwin",0);
Irssi::signal_add("ctcp msg", "event_ctcp_msg");
Irssi::signal_add("message private", "event_msg");
Irssi::signal_add("message public", "event_msg");
Irssi::signal_add("message quit", "event_quit");
Irssi::signal_add_last('window changed', 'window_change');
Irssi::signal_add_last('gui key pressed', 'key_pressed');
Irssi::statusbar_item_register('typing_notice', undef, 'typing_notice');
Irssi::statusbars_recreate_items();

115
scripts/grumble.pl Normal file
View File

@ -0,0 +1,115 @@
# grumble.pl provides sane integration of Irssi with Growl [http://growl.info/]
# and Mumbles [http://www.mumbles-project.org/]. These programs both support the
# Growl network protocol that the Perl module Net::Growl uses to communicate.
#
# This script supports multiple targets, each with a potentially unique Growl
# password.
#
# SETTINGS
# Targets are specified in the "grumble_targets" setting:
# /set grumble_targets localhost:mypass
# sends messages to an instance running on localhost with password "mypass"
# /set grumble_targets localhost:mypass othermachine:otherpass
# sends messages to two separate machines with different passwords
#
# To turn on/off notifications while /away, toggle the setting
# 'grumble_notify_when_away'. Default: OFF.
#
# To enable/disable notifications for the active window, toggle the setting
# 'grumble_notify_for_active_window'. Default: ON.
use strict;
use Irssi;
use Net::Growl;
use IO::Socket::INET;
use vars qw($VERSION %IRSSI);
$VERSION = '1.3';
%IRSSI = (
authors => 'Matt "f0rked" Sparks',
contact => 'ms+irssi@quadpoint.org',
name => 'grumble',
description => 'Irssi integration with growl and mumbles',
license => 'BSD',
url => 'http://quadpoint.org',
changed => '2010-02-08'
);
sub send_growl
{
my($host, $password, $title, $text) = @_;
my %addr = (PeerAddr => $host,
PeerPort => Net::Growl::GROWL_UDP_PORT,
Proto => "udp");
my $s = IO::Socket::INET->new(%addr) || die "Could not create socket: $!\n";
my $r = Net::Growl::RegistrationPacket->new(application => "grumble.pl",
password => $password);
$r->addNotification();
print $s $r->payload();
# send a notification
my $p = Net::Growl::NotificationPacket->new(application => "grumble.pl",
title => $title,
description => $text,
priority => 2,
sticky => 'True',
password => $password);
print $s $p->payload();
close $s;
}
sub send_to_all
{
my($title, $text) = @_;
my @targets = split / /, Irssi::settings_get_str("grumble_targets");
for my $target (@targets) {
my($host, $pass) = split /:/, $target, 2;
send_growl($host, $pass, $title, $text);
}
}
sub event_privmsg
{
my($server, $msg, $nick, $address, $target) = @_;
my $active = Irssi::active_win();
return if ($active->get_active_name() eq $nick &&
!Irssi::settings_get_bool("grumble_notify_for_active_window"));
return if ($server->{usermode_away} &&
!Irssi::settings_get_bool("grumble_notify_when_away"));
send_to_all("irssi: $nick", "new private message from $nick");
}
sub event_printtext
{
my ($dest, $text, $stripped) = @_;
my $server = $dest->{server};
my $active = Irssi::active_win();
return if ($active->get_active_name() eq $dest->{window}->get_active_name() &&
!Irssi::settings_get_bool("grumble_notify_for_active_window"));
return if ($server->{usermode_away} &&
!Irssi::settings_get_bool("grumble_notify_when_away"));
# Run the command if we're hilighted
if (($dest->{level} & (MSGLEVEL_HILIGHT)) &&
($dest->{level} & MSGLEVEL_NOHILIGHT) == 0) {
send_to_all("irssi: hilight", $stripped);
}
}
Irssi::signal_add("message private", \&event_privmsg);
Irssi::signal_add("print text", \&event_printtext);
Irssi::settings_add_str("grumble", "grumble_targets", "localhost:grwlpass");
Irssi::settings_add_bool("grumble", "grumble_notify_when_away", 0);
Irssi::settings_add_bool("grumble", "grumble_notify_for_active_window", 1);

41
scripts/hilight_notice.pl Normal file
View File

@ -0,0 +1,41 @@
# hilight_notice.pl for irssi
#
# This script changes the message level for notices to the level used by private
# messages. Notices go to the status window by default, so when this script is
# loaded, the status window will be hilighted like a query window.
#
# Based off of active_notice.pl by Geert.
use strict;
use Irssi;
use vars qw($VERSION %IRSSI);
$VERSION = '1.1';
%IRSSI = (
authors => 'Matt "f0rked" Sparks',
contact => 'ms+irssi@quadpoint.org',
name => 'hilight_notice',
description => 'hilight status window on notices',
license => 'GPLv2',
url => 'http://quadpoint.org',
changed => '2006-12-15',
);
sub hilight_notice
{
my ($dest, $text, $stripped) = @_;
my $server = $dest->{server};
return if (!$server || !($dest->{level} & MSGLEVEL_NOTICES));
# Change the message level to level used by PRIVMSGs
my $witem = $server->window_item_find($dest->{target});
$witem->print($text, MSGLEVEL_MSGS) if $witem;
Irssi::print($text, MSGLEVEL_MSGS) if !$witem;
Irssi::signal_stop();
}
Irssi::signal_add("print text", "hilight_notice");

38
scripts/hilightcmd.pl Normal file
View File

@ -0,0 +1,38 @@
use strict;
use Irssi;
use vars qw($VERSION %IRSSI);
$VERSION = '1.0';
%IRSSI = (
authors => 'Matt "f0rked" Sparks',
contact => 'ms+irssi@quadpoint.org',
name => 'hilightcmd',
description => 'Executes command on hilight',
license => 'Public domain',
url => 'http://quadpoint.org',
changed => '2005-06-16',
);
# Run the command when away?
my $run_cmd_when_away = 0;
my $cmd_to_run = "~/bin/notify.sh";
sub sig_printtext
{
my($dest, $text, $stripped) = @_;
my $server = $dest->{server};
# Do not run the command if we're not supposed to when away
return if ($server->{usermode_away} && !$run_cmd_when_away);
# Run the command if we're hilighted
if (($dest->{level} & (MSGLEVEL_HILIGHT)) &&
($dest->{level} & MSGLEVEL_NOHILIGHT) == 0) {
system($cmd_to_run, $text);
}
}
Irssi::signal_add("print text", \&sig_printtext);

77
scripts/rtm.pl Normal file
View File

@ -0,0 +1,77 @@
# rtm.pl - add new tasks to rememberthemilk.com
#
# Install:
# 1) /script load rtm
# 2) /set rtm_email <your remember the milk email address>
# 3) /save
#
# Usage:
# /rtm <task>
#
# where:
# <task> task name, e.g. "do laundry"
# Uses RTM's 'Smart Add' for due dates, priority, etc.
#
# Examples:
# Do the dishes for an hour, priority 2.
# /rtm do dishes =1 hour !2
#
# Do homework, due tomorrow.
# /rtm homework ^tomorrow
#
# See also:
# http://www.rememberthemilk.com/services/email/
use strict;
use Irssi;
use vars qw($VERSION %IRSSI);
$VERSION = '1.0';
%IRSSI = (
authors => 'Matt "f0rked" Sparks',
contact => 'ms+irssi@quadpoint.org',
name => 'rtm',
description => 'Add new tasks to rememberthemilk.com',
license => 'BSD',
url => 'http://quadpoint.org',
changed => '2010-12-20',
);
sub rtm_print
{
my($text) = @_;
my $window = Irssi::active_win();
my $b = chr(2);
$window->print("[${b}rtm${b}] $text", MSGLEVEL_CRAP);
}
sub add_task
{
my($email, $text) = @_;
open SM, qq(| mail -s "$text" $email);
print SM "\n\n";
close SM;
}
sub cmd_rtm
{
my($data, $server, $witem) = @_;
my $email_addr = Irssi::settings_get_str("rtm_email");
if (!$email_addr) {
rtm_print("your rememberthemilk.com email address is not set. ".
"Use /set rtm_email <email address> to set it. Don't forget ".
"to /save.");
return;
}
add_task($email_addr, $data);
rtm_print($data);
}
Irssi::command_bind("rtm", "cmd_rtm");
Irssi::settings_add_str("rtm", "rtm_email", "");

246
scripts/socket-interface.pl Normal file
View File

@ -0,0 +1,246 @@
use strict;
use IO::Socket;
use Fcntl;
use Irssi;
use Time::Format qw(%strftime);
#use Data::Dumper;
use vars qw($VERSION %IRSSI);
$VERSION = '1.0.1';
%IRSSI = (
authors => 'Matt "f0rked" Sparks, Miklos Vajna',
contact => 'ms+irssi@quadpoint.org',
name => 'socket-interface',
description => 'provides an interface to irssi via unix sockets',
license => 'GPLv2',
url => 'http://quadpoint.org',
changed => '2009-01-22',
);
my $socket = $ENV{"HOME"} . "/.irssi/socket";
# create the socket
unlink $socket;
my $server = IO::Socket::UNIX->new(Local => $socket,
Type => SOCK_STREAM,
Listen => 5) or die $@;
# set this socket as nonblocking so we can check stuff without interrupting
# irssi.
nonblock($server);
# method to set a socket handle as nonblocking
sub nonblock
{
my($fd) = @_;
my $flags = fcntl($fd, F_GETFL, 0);
fcntl($fd, F_SETFL, $flags | O_NONBLOCK);
}
# check the socket for data and act upon it
sub check_sock
{
my $msg;
if (my $client = $server->accept()) {
$client->recv($msg, 1024);
#print "Got message: $msg" if $msg;
if ($msg =~ /^activelog ?(\d*)$/) {
my $lines = ($1) ? $1 : 5;
#print "found lines: $lines";
#print Dumper $win;
my $ref = get_active_refnum();
my $name = get_active_name();
my $tag = get_active_tag();
my $fname = get_log_fname(get_active_tag(), get_active_name());
my $log = tail_log($fname, $lines);
if (!$log) {
$log = "Could not open log";
}
chomp $log;
$client->send(">> $ref: $name ($tag)\n$log");
} elsif ($msg eq "windowlist") {
# send back a list of the windows
my $out;
for (2 .. last_refnum()) {
$out .= ("$_: " . name_of($_) . " (".tag_of($_).") " .
level_of($_) . "\n");
}
chomp $out;
$client->send($out);
} elsif ($msg =~ /^switch (\d+)$/) {
$client->send(switch_to($1));
} elsif ($msg =~ /^get_lines (\d+)$/) {
$client->send(get_lines($1));
} elsif ($msg =~ /^send (.+)$/) {
$client->send(msg_active($1));
} elsif ($msg =~ /^command (.+)$/) {
$client->send(command($1));
}
}
}
# returns the name of the active window item. If there is no active window
# item, return the name of the window itself.
sub get_active_name
{
my $win = Irssi::active_win();
return $win->get_active_name();
}
# returns the server tag of the active window item
sub get_active_tag
{
my $win = Irssi::active_win();
return ($win->{active}) ? $win->{active}->{server}->{tag} : "";
}
# returns refnum of active window
sub get_active_refnum
{
return (Irssi::active_win())->{refnum};
}
# switches windows to the given refnum
sub switch_to
{
my($refnum) = @_;
my $window = Irssi::window_find_refnum($refnum);
if ($window) {
$window->set_active();
return 1;
} else {
return 0;
}
}
# gets the lines from a buffer of a window
sub get_lines
{
my($refnum) = @_;
my $window = Irssi::window_find_refnum($refnum);
if ($window) {
my $view = $window->view;
my $line = $view->get_lines();
my $ret = "";
while (defined $line) {
$ret .= $line->get_text(0) . "\n";
$line = $line->next();
}
return $ret;
}
else {
return 0;
}
}
# return highest refnum
sub last_refnum
{
return Irssi::windows_refnum_last();
}
# name of given refnum's window
sub name_of
{
my($refnum) = @_;
my $win = Irssi::window_find_refnum($refnum);
return $win->get_active_name();
}
# tag of given refnum's window
sub tag_of
{
my($refnum) = @_;
my $win = Irssi::window_find_refnum($refnum);
return ($win->{active}) ? $win->{active}->{server}->{tag} : "";
}
# level of given refnum's window
sub level_of
{
my($refnum) = @_;
my $win = Irssi::window_find_refnum($refnum);
return $win->{data_level};
}
sub msg
{
my($refnum, $text) = @_;
my $win = Irssi::window_find_refnum($refnum);
return unless $win;
if ($text =~ /^\//) {
# this is a command, don't prepend /msg *
$win->command($text);
} else {
$win->command("msg * $text");
}
return 1;
}
sub command
{
my($command) = @_;
if (my $s = Irssi::active_server()) {
$s->command($command);
} else {
Irssi::command($command);
}
return 1;
}
sub msg_active
{
my($text) = @_;
return msg(get_active_refnum(), $text);
}
sub get_log_fname
{
my($servertag, $name) = @_;
$name = lc($name);
my $log_path = Irssi::settings_get_str("autolog_path");
# fill in variables
my $log_file = $strftime{$log_path};
$log_file =~ s/^~/$ENV{HOME}/;
$log_file =~ s/\$tag/$servertag/g;
$log_file =~ s/\$0/$name/g;
#print "log file: $log_file";
return $log_file; # hope this is filled in enough.
}
# return the last x lines of a given filename
sub tail_log
{
my($filename, $lines) = @_;
$lines ||= 5;
#print "found $filename";
return 0 if !-e $filename;
my $t = qx(tail -n $lines '$filename');
chomp $t;
return $t;
}
my $timer = Irssi::timeout_add(250, \&check_sock, []);