summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Leadbeater2015-01-10 16:57:01 +0000
committerDavid Leadbeater2015-01-10 16:57:01 +0000
commitcbbdf2a1d93dbb64d3fb34346e9c57b14dfa2931 (patch)
tree019203a11e96a90be76a4538433e1d223a747d55
parent0a3941245c1cbb55dd3c67af0b5c33caddd04f8b (diff)
parent71dba3f266191eeeff577303232d700fefe2e6e1 (diff)
downloadscripts.irssi.org-cbbdf2a1d93dbb64d3fb34346e9c57b14dfa2931.tar.bz2
Merge branch 'gh-pages' of gh:irssi/scripts.irssi.org into gh-pages
Conflicts: _data/scripts.yaml
-rw-r--r--.travis.yml10
-rw-r--r--_data/scripts.yaml224
-rw-r--r--scripts/auth_quakenet.pl197
-rw-r--r--scripts/autoop.pl71
-rw-r--r--scripts/cap_sasl.pl431
-rw-r--r--scripts/clones_scanner.pl296
-rw-r--r--scripts/cron.pl7
-rw-r--r--scripts/dice_concise.pl247
-rw-r--r--scripts/eng_no_translate_dpryo.pl57
-rw-r--r--scripts/fnotify.pl92
-rw-r--r--scripts/frm_outgmsgs.pl4
-rw-r--r--scripts/go.pl6
-rw-r--r--scripts/localize.pl21
-rw-r--r--scripts/rainbow.pl28
-rw-r--r--scripts/screen_away.pl11
-rw-r--r--scripts/slack_emoji.pl50
-rw-r--r--scripts/trackbar.pl325
17 files changed, 1850 insertions, 227 deletions
diff --git a/.travis.yml b/.travis.yml
index 64d0fcb..1c69a58 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -20,21 +20,21 @@ before_install:
_testing/config.yml`
- |
if [ $TRAVIS_PULL_REQUEST = false ] && [ $USE_ARTEFACTS_CACHE = yes ] && [ $EXTRACT_TEST_ARTEFACTS = yes ]; then
- ./_testing/travis/load-old-artefacts.zsh
+ env -u REPO_LOGIN_TOKEN ./_testing/travis/load-old-artefacts.zsh
fi
-- ./_testing/travis/autoinstall-perl-prereqs.zsh
+- env -u REPO_LOGIN_TOKEN ./_testing/travis/autoinstall-perl-prereqs.zsh
install:
- true
before_script:
-- ./_testing/run-test.zsh
+- env -u REPO_LOGIN_TOKEN ./_testing/run-test.zsh
- |
if [ $TRAVIS_PULL_REQUEST != false ]; then
git diff --stat $TRAVIS_BRANCH
fi
script:
-- ./_testing/report-test.zsh
+- env -u REPO_LOGIN_TOKEN ./_testing/report-test.zsh
after_script:
-- ./_testing/travis/show-failures.zsh
+- env -u REPO_LOGIN_TOKEN ./_testing/travis/show-failures.zsh
- |
if [ $TRAVIS_PULL_REQUEST = false ] && $TRAVIS_SECURE_ENV_VARS; then
perl ./_testing/travis/update-scripts-yaml.pl
diff --git a/_data/scripts.yaml b/_data/scripts.yaml
index 9e91c59..06e9019 100644
--- a/_data/scripts.yaml
+++ b/_data/scripts.yaml
@@ -230,6 +230,17 @@
url: "http://www.mimir.ch/ph/"
version: "1.00"
+- authors: "Mantas Mikulėnas"
+ contact: "grawity@gmail.com"
+ description: "Implements QuakeNet's CHALLENGE authentication"
+ filename: "auth_quakenet.pl"
+ modified: "2014-12-18 06:38"
+ license: "WTFPL v2 <http://sam.zoy.org/wtfpl/>"
+ modules: "Digest::HMAC Digest::SHA Digest::SHA1 Digest::MD5"
+ name: "auth_quakenet"
+ url: "https://nullroute.eu.org/~grawity/irssi.html"
+ version: "1.0"
+
- authors: "Andreas ads Scherbaum"
contact: "ads@ufp.de"
description: "/WHOIS all the users who send you a private message."
@@ -291,13 +302,13 @@
url: "http://irssi.dgl.cx/"
version: "1.00"
-- authors: "Timo Sirainen"
+- authors: "Timo Sirainen & Jostein Kjønigsen"
description: "Simple auto-op script"
filename: "autoop.pl"
- modified: "2002-03-10 23:18:00"
+ modified: "2014-10-24 12:55:00"
license: "Public Domain"
name: "autoop"
- version: "1.00"
+ version: "1.10"
- authors: "Toni Salomäki"
contact: "Toni@IRCNet"
@@ -711,6 +722,18 @@
url: "http://scripts.irssi.org/"
version: "1.0"
+- authors: "Michael Tharp (gxti), Jilles Tjoelker (jilles), Mantas Mikulėnas (grawity)"
+ commands: "sasl"
+ contact: "grawity@gmail.com"
+ description: "Implements SASL authentication (and multi-prefix as free bonus)"
+ filename: "cap_sasl.pl"
+ modified: "2015-01-07 06:03"
+ modules: "Crypt::PK::ECC MIME::Base64"
+ license: "GPLv2"
+ name: "cap_sasl"
+ url: "https://nullroute.eu.org/~grawity/irssi.html"
+ version: "1.10"
+
- authors: "ZaMz0n"
commands: "cddb"
contact: "zamzon@freakpower.com"
@@ -874,6 +897,16 @@
url: "http://irssi.dgl.cx/"
version: "2.01"
+- authors: "Pablo Martín Báez Echevarría"
+ contact: "pab_24n@outlook.com"
+ description: "when a nick joins #channel, notifies you if there is (or there has been) someone in #channel with the same hostname"
+ filename: "clones_scanner.pl"
+ modified: "2014-12-20 22:30:25"
+ license: "Public domain"
+ name: "clones_scannner"
+ url: "http://reirssi.wordpress.com"
+ version: "1.6"
+
- authors: "Gabor Nyeki"
contact: "bigmac@vim.hu"
description: "kicking users for using colors or blinks"
@@ -1091,6 +1124,17 @@
url: "http://www.enumerator.org/component/option,com_docman/task,view_category/Itemid,34/subcat,7/"
version: "0.00.04"
+- authors: "Marcell Kossin, Makaze"
+ contact: "izaya.orihara@gmail.com"
+ description: "A concise dice simulator for channels."
+ filename: "dice_concise.pl"
+ modified: "2014-03-28 21:15:23"
+ license: "GNU GPL Version 2 or later"
+ modules: "Scalar::Util"
+ name: "dice_concise"
+ url: "https://github.com/Makaze/"
+ version: "0.1.5"
+
- authors: "Juerd (first version: Timo Sirainen)"
contact: "juerd@juerd.nl"
description: "Caching dictionary based tab completion"
@@ -1173,15 +1217,6 @@
url: "http://www.holmnilsen.com/"
version: "1.2"
-- authors: "Ilkka Pale"
- contact: "ilkka.pale@gmail.com"
- description: "Outputs various unicode emoticons."
- filename: "emo.pl"
- modified: "2014-06-12 19:06:00"
- license: "Public Domain"
- name: "emo"
- version: "0.0.1"
-
- authors: "Ilya Cassina"
contact: "icassina@gmail.com"
description: "This script allow advanced parametrization of the /list command. Accepted parameters are -minusers <#users> and -maxusers <#users>. "
@@ -1225,16 +1260,14 @@
url: "http://www.princessleia.com/"
version: "1.0"
-- authors: "Harald Nesland"
- contact: "hnesland@samsen.com"
- description: "Very simple script that sends incoming text to freetranslation.com for english->norwegian translation. May be modified to translate other languages."
- filename: "eng_no_translate_dpryo.pl"
- modified: "2002-04-11 14:15:25"
+- authors: "Ilkka Pale"
+ contact: "ilkka.pale@gmail.com"
+ description: "Outputs various unicode emoticons."
+ filename: "emo.pl"
+ modified: "2014-06-12 19:06:00"
license: "Public Domain"
- modules: "LWP::Simple"
- name: "EngNoTranslate"
- url: "http://www.satyra.net"
- version: "0.2"
+ name: "emo"
+ version: "0.0.1"
- authors: "Taneli Kaivola"
contact: "dist@sci.fi"
@@ -1337,6 +1370,16 @@
url: "http://www.krukowiecki.net/code/irssi/"
version: "0.0.2i"
+- authors: "Thorsten Leemhuis, James Shubin, Serge van Ginderachter"
+ contact: "fedora@leemhuis.info, serge@vanginderachter.be"
+ description: "Write notifications to a file in a consistent format."
+ filename: "fnotify.pl"
+ modified: "2014-11-25 21:02"
+ license: "GNU General Public License"
+ name: "fnotify"
+ url: "http://www.leemhuis.info/files/fnotify/fnotify https://ttboj.wordpress.com/"
+ version: "0.0.5"
+
- authors: "Juerd"
contact: "juerd@juerd.nl"
description: "Automatically switch to active windows"
@@ -1428,6 +1471,15 @@
url: "http://toxcorp.com/irc/irssi/friends/"
version: "2.4.9"
+- authors: "Pablo Martín Báez Echevarría"
+ contact: "pab_24n@outlook.com"
+ description: "define a permanent text formatting (bold, underline, etc.) for outgoing messages"
+ filename: "frm_outgmsgs.pl"
+ modified: "2014-10-16"
+ license: "Public Domain"
+ name: "frm_outgmsgs"
+ version: "1.1"
+
- authors: "Piotr Krukowiecki & others"
contact: "piotr at pingu.ii.uj.edu.pl"
description: "File server for irssi"
@@ -1471,10 +1523,10 @@
contact: "nohar@freenode"
description: "Implements /go command that activates a window given a name/partial name. It features a nice completion."
filename: "go.pl"
- modified: "2004-08-17 00:00:00"
+ modified: "2014-10-19 00:00:00"
license: "GPLv2 or later"
name: "go to window"
- version: "1.00"
+ version: "1.01"
- authors: "cxreg"
contact: "cxreg@pobox.com"
@@ -2147,12 +2199,12 @@
contact: "stefan@pico.ruhr.de"
description: "Localizes users using traceroute, the localizer database or IP-Atlas"
filename: "localize.pl"
- modified: "2008-05-17 17:39:09"
+ modified: "2014-11-25 14:20:00"
license: "GPLv2"
modules: "LWP::UserAgent HTML::Entities Data::Dumper Socket"
name: "localize"
url: ""
- version: "2003112301"
+ version: "2014112501"
- authors: "Peder Stray"
contact: "peder@ninja.no"
@@ -2775,6 +2827,15 @@
name: "oops"
version: "20071209"
+- authors: "David Leadbeater"
+ contact: "dgl@dgl.cx"
+ description: "Stops those silly mistakes being sent (spaces at start of line, /1/1 for window changes, etc)."
+ filename: "oopsie.pl"
+ modified: "2014-08-13"
+ license: "WTFPL"
+ name: "oopsie"
+ version: "1.0"
+
- authors: "Stefan tommie Tomanek"
commands: "openurl"
contact: "stefan@pico.ruhr.de"
@@ -3017,6 +3078,15 @@
name: "q_username"
version: "0.1"
+- authors: "Doug Freed"
+ contact: "dwfreed!#irssi@freenode"
+ description: "Authenticates with QuakeNet's Q service upon connection, using their CHALLENGEAUTH protocol"
+ filename: "qchallengeauth.pl"
+ modified: "2014-08-23"
+ license: "GPLv3+"
+ name: "qchallengeauth"
+ version: "1.0"
+
- authors: "Peder Stray"
contact: "peder@ninja.no"
description: "Give you more control over when to jump to query windows and when to just tell you one has been created. Enhanced autoclose."
@@ -3105,11 +3175,11 @@
contact: "shasta@atn.pl"
description: "Prints colored text. Rather simple than sophisticated."
filename: "rainbow.pl"
- modified: "2008-05-17 17:39:09"
+ modified: "2014-12-01 13:04:09"
license: "GNU GPLv2 or later"
name: "rainbow"
url: "http://irssi.atn.pl/"
- version: "1.4"
+ version: "1.6"
- authors: "Lasse Karstensen"
contact: "lkarsten@stud.ntnu.no"
@@ -3272,12 +3342,12 @@
- authors: "Andreas ads Scherbaum <ads@wars-nicht.de>"
description: "set (un)away, if screen is attached/detached"
filename: "screen_away.pl"
- modified: "2008-05-22 01:28:25"
+ modified: "2014-12-20 20:30:00"
license: "GPL v2"
modules: "FileHandle"
name: "screen_away"
url: "none"
- version: "0.9.7.1"
+ version: "0.9.8.1"
- authors: "Stefan tommie Tomanek"
commands: "scriptassist"
@@ -3418,6 +3488,25 @@
name: "showmode"
version: "0.3"
+- authors: "Lars Djerf"
+ contact: "lars.djerf@gmail.com"
+ description: "Converts Slack emoji to smileys."
+ filename: "slack_emoji.pl"
+ modified: "2015-01-03 19:55:28"
+ license: "GPLv3"
+ name: "slack_emoji"
+ version: "0.03"
+
+- authors: "crshd"
+ contact: "christian.brassat@gmail.com"
+ description: "Filters join/part messages if user hasn't been active in a while."
+ filename: "smartfilter.pl"
+ modified: "2012-10-02 21:05:40"
+ license: "BSD"
+ name: "smartfilter"
+ url: "none"
+ version: "0.1"
+
- authors: "Jonne Piittinen"
contact: "jip@loota.org"
description: "Very useful smiley-flooder"
@@ -3737,11 +3826,11 @@
contact: "peter@pfoe.be"
description: "Shows a bar where youve last read a window"
filename: "trackbar.pl"
- modified: "2003-02-20 16:18:08"
+ modified: "2013-11-19 13:44:07"
license: "GPLv2"
name: "trackbar"
url: "http://www.pfoe.be/~peter/trackbar/"
- version: "1.4"
+ version: "1.7"
- authors: "Timo Sirainen"
contact: "tss@iki.fi"
@@ -3843,6 +3932,15 @@
url: "http://otoria.freecode.nl/~michiel/u.pl"
version: "1.3"
+- authors: "David Leadbeater"
+ contact: "dgl@dgl.cx"
+ description: "Get infomation about unicode characters"
+ filename: "unicode.pl"
+ modified: "2014-07-06"
+ license: "WTFPL"
+ name: "unicode"
+ version: "2"
+
- authors: "Peder Stray"
contact: "peder@ninja.no"
description: "Statusbaritem notifying you about updated binary"
@@ -3906,6 +4004,15 @@
url: "http://irssi.dgl.cx/"
version: "0.2"
+- authors: "David Leadbeater"
+ contact: "dgl@dgl.cx"
+ description: "Print short summaries about URLs from known services that are mentioned on IRC. (Including YouTube, etc.)"
+ filename: "urlinfo.pl"
+ modified: "2014-08-22"
+ license: "WTFPL"
+ name: "urlinfo"
+ version: "1.3"
+
- authors: "bwolf"
contact: "bwolf@geekmind.org"
description: "URL grabber with HTML generation and cmd execution"
@@ -4240,58 +4347,3 @@
name: "XQF"
url: "none"
version: "0.14"
-
-- authors: "crshd"
- contact: "christian.brassat@gmail.com"
- description: "Filters join/part messages if user hasn't been active in a while."
- filename: "smartfilter.pl"
- modified: "2012-10-02 21:05:40"
- license: "BSD"
- name: "smartfilter"
- url: "none"
- version: "0.1"
-
-- authors: "David Leadbeater"
- contact: "dgl@dgl.cx"
- description: "Get infomation about unicode characters"
- filename: "unicode.pl"
- modified: "2014-07-06"
- license: "WTFPL"
- name: "unicode"
- version: "2"
-
-- authors: "David Leadbeater"
- contact: "dgl@dgl.cx"
- description: "Print short summaries about URLs from known services that are mentioned on IRC. (Including YouTube, etc.)"
- filename: "urlinfo.pl"
- modified: "2014-08-22"
- license: "WTFPL"
- name: "urlinfo"
- version: "1.3"
-
-- authors: "David Leadbeater"
- contact: "dgl@dgl.cx"
- description: "Stops those silly mistakes being sent (spaces at start of line, /1/1 for window changes, etc)."
- filename: "oopsie.pl"
- modified: "2014-08-13"
- license: "WTFPL"
- name: "oopsie"
- version: "1.0"
-
-- authors: "Doug Freed"
- contact: "dwfreed!#irssi@freenode"
- description: "Authenticates with QuakeNet's Q service upon connection, using their CHALLENGEAUTH protocol"
- filename: "qchallengeauth.pl"
- modified: "2014-08-23"
- license: "GPLv3+"
- name: "qchallengeauth"
- version: "1.0"
-
-- authors: "Pablo Martín Báez Echevarría"
- contact: "pab_24n@outlook.com"
- description: "define a permanent text formatting (bold, underline, etc.) for outgoing messages"
- filename: "frm_outgmsgs.pl"
- modified: "2014-10-16"
- license: "Public Domain"
- name: "frm_outgmsgs"
- version: "1.0" \ No newline at end of file
diff --git a/scripts/auth_quakenet.pl b/scripts/auth_quakenet.pl
new file mode 100644
index 0000000..53f8b96
--- /dev/null
+++ b/scripts/auth_quakenet.pl
@@ -0,0 +1,197 @@
+# vim: ft=perl
+use strict;
+use Irssi;
+use vars qw($VERSION %IRSSI);
+
+## Settings:
+#
+# quakenet_account (string) = ( [<servertag>:]<username>:<password> )*
+#
+# Your QuakeNet account details, in format <username>:<password>. Example:
+#
+# /set quakenet_account [fishking]:iLOVEfish12345
+#
+# Different accounts for different Irssi "networks" ("server tags") can be
+# set in format <servertag>:<username>:<password> (space-separated). The
+# account with empty (or missing) <servertag> will be used as the default
+# account for all other connections.)
+#
+# quakenet_auth_allowed_mechs (string) = any
+#
+# List of allowed mechanisms, separated by spaces.
+# Can be "any" to allow all supported mechanisms.
+#
+# Currently supported:
+# HMAC-SHA-256 (Digest::SHA)
+# HMAC-SHA-1 (Digest::SHA1)
+# HMAC-MD5 (Digest::MD5)
+# LEGACY-MD5 (Digest::MD5 without HMAC)
+#
+# Note: LEGACY-MD5 is excluded from "any"; if you want to use it, specify
+# it manually.
+#
+## To trigger the script manually, use:
+## /msg Q@cserve.quakenet.org challenge
+
+$VERSION = "1.0";
+%IRSSI = (
+ authors => 'Mantas Mikulėnas',
+ contact => 'grawity@gmail.com',
+ name => 'auth_quakenet_challenge.pl',
+ description => "Implements QuakeNet's CHALLENGE authentication",
+ license => 'WTFPL v2 <http://sam.zoy.org/wtfpl/>',
+ url => 'http://purl.net/net/grawity/irssi.html',
+);
+
+require Digest::HMAC;
+
+my @preferred_mechs = qw(HMAC-SHA-256 HMAC-SHA-1 HMAC-MD5);
+
+my %supported_mechs = ();
+
+eval {
+ require Digest::SHA;
+ $supported_mechs{"HMAC-SHA-256"} = sub {
+ hmac(\&Digest::SHA::sha256_hex, \&Digest::SHA::sha256, @_);
+ };
+};
+
+eval {
+ require Digest::SHA1;
+ $supported_mechs{"HMAC-SHA-1"} = sub {
+ hmac(\&Digest::SHA1::sha1_hex, \&Digest::SHA1::sha1, @_);
+ };
+};
+
+eval {
+ require Digest::MD5;
+ $supported_mechs{"HMAC-MD5"} = sub {
+ hmac(\&Digest::MD5::md5_hex, \&Digest::MD5::md5, @_);
+ };
+ $supported_mechs{"LEGACY-MD5"} = sub {
+ Irssi::print("WARNING: LEGACY-MD5 should not be used.");
+ my ($challenge, $username, $password) = @_;
+ Digest::MD5::md5_hex($password . " " . $challenge);
+ };
+};
+
+if (scalar keys %supported_mechs == 0) {
+ die "No mechanisms available. Please install these Perl modules:\n"
+ ." - Digest::HMAC\n"
+ ." - Digest::SHA, Digest::SHA1, Digest::MD5 (at least one)\n";
+}
+
+sub hmac {
+ my ($fnhex, $fnraw, $challenge, $username, $password) = @_;
+ my $key = &$fnhex($username . ":" . &$fnhex($password));
+ Digest::HMAC::hmac_hex($challenge, $key, $fnraw);
+}
+
+sub lcnick {
+ my $str = shift;
+ $str =~ tr/[\\]/{|}/;
+ lc $str;
+}
+
+sub get_account {
+ my ($servertag) = @_;
+ my $accounts = Irssi::settings_get_str("quakenet_account");
+ my ($defuser, $defpass) = (undef, undef);
+ for my $acct (split /\s+/, $accounts) {
+ my ($tag, $user, $pass);
+
+ my @acct = split(/:/, $acct);
+ if (@acct == 3) {
+ ($tag, $user, $pass) = @acct;
+ } elsif (@acct == 2) {
+ ($tag, $user, $pass) = ("*", @acct);
+ } else {
+ next;
+ }
+
+ if (lc $tag eq lc $servertag) {
+ return ($user, $pass);
+ }
+ elsif ($tag eq "*" or $tag eq "") {
+ ($defuser, $defpass) = ($user, $pass);
+ }
+ }
+ return ($defuser, $defpass);
+}
+
+Irssi::signal_add_last("event 001" => sub {
+ my ($server, $evargs, $srcnick, $srcaddr) = @_;
+ return unless $srcnick =~ /\.quakenet\.org$/;
+
+ my ($user, $pass) = get_account($server->{tag});
+ return if !length($pass);
+
+ $server->print("", "Authenticating to Q");
+ $server->send_message('Q@cserve.quakenet.org', "CHALLENGE", 1);
+});
+
+Irssi::signal_add_first("message irc notice" => sub {
+ my ($server, $msg, $nick, $address, $target) = @_;
+ return unless $server->mask_match_address('Q!*@cserve.quakenet.org', $nick, $address);
+
+ if ($msg =~ /^CHALLENGE ([0-9a-f]+) (.+)$/) {
+ Irssi::signal_stop();
+
+ my $challenge = $1;
+ my @server_mechs = split(" ", $2);
+
+ my ($user, $pass) = get_account($server->{tag});
+ return if !length($pass);
+
+ $user = lcnick($user);
+ $pass = substr($pass, 0, 10);
+
+ my $mech;
+ my @allowed_mechs = ();
+ my $allowed_mechs = uc Irssi::settings_get_str("quakenet_auth_allowed_mechs");
+ if ($allowed_mechs eq "ANY") {
+ # @preferred_mechs is sorted by strength
+ @allowed_mechs = @preferred_mechs;
+ } else {
+ @allowed_mechs = split(/\s+/, $allowed_mechs);
+ }
+
+ # choose first mech supported by both sides
+ for my $m (@allowed_mechs) {
+ if (grep {$_ eq $m} @server_mechs &&
+ grep {$_ eq $m} (keys %supported_mechs)) {
+ $mech = $m;
+ last;
+ }
+ }
+
+ if (!defined $mech) {
+ $server->print("", "Authentication failed (no mechanisms available)");
+ $server->print("", " Server offers: ".join(", ", @server_mechs));
+ $server->print("", " Client supports: ".join(", ", keys %supported_mechs));
+ $server->print("", " Restricted to: ".join(", ", @allowed_mechs));
+ return;
+ }
+
+ my $authfn = $supported_mechs{$mech};
+
+ my $response = &$authfn($challenge, $user, $pass);
+ $server->send_message('Q@cserve.quakenet.org', "CHALLENGEAUTH $user $response $mech", 1);
+ }
+
+ elsif ($msg =~ /^You are now logged in as (.+?)\.$/) {
+ Irssi::signal_stop();
+ $server->print("", "Authentication successful, logged in as $1");
+ }
+
+ elsif ($msg =~ /^Username or password incorrect\.$/) {
+ Irssi::signal_stop();
+ $server->print("", "Authentication failed (username or password incorrect)");
+ }
+});
+
+Irssi::settings_add_str("misc", "quakenet_auth_allowed_mechs", "any");
+Irssi::settings_add_str("misc", "quakenet_account", "");
+if (Irssi::settings_get_str("quakenet_account") eq "") {
+ Irssi::print("Set your QuakeNet account using /set quakenet_account username:password");
+}
diff --git a/scripts/autoop.pl b/scripts/autoop.pl
index d46d099..b72def1 100644
--- a/scripts/autoop.pl
+++ b/scripts/autoop.pl
@@ -5,13 +5,13 @@ use Irssi;
use strict;
use vars qw($VERSION %IRSSI);
-$VERSION = "1.00";
+$VERSION = "1.10";
%IRSSI = (
- authors => 'Timo Sirainen',
+ authors => 'Timo Sirainen & Jostein Kjønigsen',
name => 'autoop',
description => 'Simple auto-op script',
license => 'Public Domain',
- changed => 'Sun Mar 10 23:18 EET 2002'
+ changed => 'Fri Nov 24 12:55 GMT+1 2014'
);
my (%opnicks, %temp_opped);
@@ -89,3 +89,68 @@ sub event_massjoin {
Irssi::command_bind('autoop', 'cmd_autoop');
Irssi::signal_add_last('massjoin', 'event_massjoin');
+
+sub load_autoops {
+ my($file) = Irssi::get_irssi_dir."/autoop";
+ my($count) = 0;
+ local(*CONF);
+
+ %opnicks = ();
+ open(CONF, "<", "$file") or return;
+ while (my $line = <CONF>) {
+ if ($line !=~ /^\s*$/) {
+ cmd_autoop($line);
+ $count++;
+ }
+ }
+ close(CONF);
+
+ Irssi::print("Loaded $count channels from $file");
+}
+
+# --------[ save_autoops ]------------------------------------------------
+
+sub save_autoops {
+ my($auto) = @_;
+ my($file) = Irssi::get_irssi_dir."/autoop";
+ my($count) = 0;
+ my($channel) = "";
+ local(*CONF);
+
+ return if $auto;
+
+ open(CONF, ">", "$file");
+ foreach $channel (keys %opnicks) {
+ my $masks = $opnicks{$channel};
+ print CONF "$channel\t$masks\n";
+ $count++;
+ }
+ close(CONF);
+
+ Irssi::print("Saved $count channels to $file")
+ unless $auto;
+}
+
+
+# --------[ sig_setup_reread ]------------------------------------------
+
+# main setup is reread, so let us do it too
+sub sig_setup_reread {
+ load_autoops;
+}
+
+# --------[ sig_setup_save ]--------------------------------------------
+
+# main config is saved, and so we should save too
+sub sig_setup_save {
+ my($mainconf,$auto) = @_;
+ save_autoops($auto);
+}
+
+# persistance
+
+Irssi::signal_add('setup saved', 'sig_setup_save');
+Irssi::signal_add('setup reread', 'sig_setup_reread');
+
+# ensure we load persisted values on start
+load_autoops;
diff --git a/scripts/cap_sasl.pl b/scripts/cap_sasl.pl
new file mode 100644
index 0000000..7c1fba2
--- /dev/null
+++ b/scripts/cap_sasl.pl
@@ -0,0 +1,431 @@
+use strict;
+use Irssi;
+use MIME::Base64;
+use vars qw($VERSION %IRSSI);
+use constant CHALLENGE_SIZE => 32;
+
+$VERSION = "1.10";
+%IRSSI = (
+ authors => 'Michael Tharp (gxti), Jilles Tjoelker (jilles), Mantas Mikulėnas (grawity)',
+ contact => 'grawity@gmail.com',
+ name => 'cap_sasl.pl',
+ description => 'Implements SASL authentication and enables CAP "multi-prefix"',
+ license => 'GPLv2',
+ url => 'http://ircv3.atheme.org/extensions/sasl-3.1',
+);
+
+my %sasl_auth = ();
+my %mech = ();
+
+sub irssi_abspath {
+ my $f = shift;
+ $f =~ s!^~/!$ENV{HOME}/!;
+ if ($f !~ m!^/!) {
+ $f = Irssi::get_irssi_dir()."/".$f;
+ }
+ return $f;
+}
+
+sub timeout;
+
+sub server_connected {
+ my $server = shift;
+ if (uc $server->{chat_type} eq 'IRC') {
+ $server->send_raw_now("CAP LS");
+ }
+}
+
+sub event_cap {
+ my ($server, $args, $nick, $address) = @_;
+ my ($subcmd, $caps, $tosend, $sasl);
+
+ $tosend = '';
+ $sasl = $sasl_auth{$server->{tag}};
+ if ($args =~ /^\S+ (\S+) :(.*)$/) {
+ $subcmd = uc $1;
+ $caps = ' '.$2.' ';
+ if ($subcmd eq 'LS') {
+ $tosend .= ' multi-prefix' if $caps =~ / multi-prefix /i;
+ $tosend .= ' sasl' if $caps =~ / sasl /i && defined($sasl);
+ $tosend =~ s/^ //;
+ $server->print('', "CLICAP: supported by server:$caps");
+ if (!$server->{connected}) {
+ if ($tosend eq '') {
+ $server->send_raw_now("CAP END");
+ } else {
+ $server->print('', "CLICAP: requesting: $tosend");
+ $server->send_raw_now("CAP REQ :$tosend");
+ }
+ }
+ Irssi::signal_stop();
+ } elsif ($subcmd eq 'ACK') {
+ $server->print('', "CLICAP: now enabled:$caps");
+ if ($caps =~ / sasl /i) {
+ $sasl->{buffer} = '';
+ $sasl->{step} = 0;
+ if ($mech{$sasl->{mech}}) {
+ $server->send_raw_now("AUTHENTICATE " . $sasl->{mech});
+ Irssi::timeout_add_once(7500, \&timeout, $server->{tag});
+ } else {
+ $server->print('', 'SASL: attempted to start unknown mechanism "' . $sasl->{mech} . '"');
+ }
+ }
+ elsif (!$server->{connected}) {
+ $server->send_raw_now("CAP END");
+ }
+ Irssi::signal_stop();
+ } elsif ($subcmd eq 'NAK') {
+ $server->print('', "CLICAP: refused:$caps");
+ if (!$server->{connected}) {
+ $server->send_raw_now("CAP END");
+ }
+ Irssi::signal_stop();
+ } elsif ($subcmd eq 'LIST') {
+ $server->print('', "CLICAP: currently enabled:$caps");
+ Irssi::signal_stop();
+ }
+ }
+}
+
+sub event_authenticate {
+ my ($server, $args, $nick, $address) = @_;
+ my $sasl = $sasl_auth{$server->{tag}};
+ return unless $sasl && $mech{$sasl->{mech}};
+
+ $sasl->{buffer} .= $args;
+ return if length($args) == 400;
+
+ my $data = ($sasl->{buffer} eq '+') ? '' : decode_base64($sasl->{buffer});
+ my $out = $mech{$sasl->{mech}}($sasl, $data);
+
+ if (defined $out) {
+ $out = ($out eq '') ? '+' : encode_base64($out, '');
+ while (length $out >= 400) {
+ my $subout = substr($out, 0, 400, '');
+ $server->send_raw_now("AUTHENTICATE $subout");
+ }
+ if (length $out) {
+ $server->send_raw_now("AUTHENTICATE $out");
+ } else {
+ # Last piece was exactly 400 bytes, we have to send
+ # some padding to indicate we're done.
+ $server->send_raw_now("AUTHENTICATE +");
+ }
+ } else {
+ $server->send_raw_now("AUTHENTICATE *");
+ }
+
+ $sasl->{buffer} = "";
+ Irssi::signal_stop();
+}
+
+sub event_saslend {
+ my ($server, $args, $nick, $address) = @_;
+
+ my $data = $args;
+ $data =~ s/^\S+ :?//;
+ # need this to see it, ?? -- jilles
+
+ $server->print('', $data);
+ if (!$server->{connected}) {
+ $server->send_raw_now("CAP END");
+ }
+}
+
+sub event_saslfail {
+ my ($server, $args, $nick, $address) = @_;
+
+ my $data = $args;
+ $data =~ s/^\S+ :?//;
+
+ if (Irssi::settings_get_bool('sasl_disconnect_on_fail')) {
+ $server->print('', "$data - disconnecting from server", MSGLEVEL_CLIENTERROR);
+ $server->disconnect();
+ } else {
+ $server->print('', "$data - continuing anyway");
+ if (!$server->{connected}) {
+ $server->send_raw_now("CAP END");
+ }
+ }
+}
+
+sub timeout {
+ my $tag = shift;
+ my $server = Irssi::server_find_tag($tag);
+ if ($server && !$server->{connected}) {
+ $server->print('', "SASL: authentication timed out", MSGLEVEL_CLIENTERROR);
+ $server->send_raw_now("CAP END");
+ }
+}
+
+sub cmd_sasl {
+ my ($data, $server, $item) = @_;
+
+ if ($data ne '') {
+ Irssi::command_runsub ('sasl', $data, $server, $item);
+ } else {
+ cmd_sasl_show(@_);
+ }
+}
+
+sub cmd_sasl_set {
+ my ($data, $server, $item) = @_;
+
+ if (my ($net, $u, $p, $m) = $data =~ /^(\S+) (\S+) (\S+) (\S+)$/) {
+ if ($mech{uc $m}) {
+ $sasl_auth{$net}{user} = $u;
+ $sasl_auth{$net}{password} = $p;
+ $sasl_auth{$net}{mech} = uc $m;
+ Irssi::print("SASL: added $net: [$m] $sasl_auth{$net}{user} *");
+ } else {
+ Irssi::print("SASL: unknown mechanism $m", MSGLEVEL_CLIENTERROR);
+ }
+ } elsif ($data =~ /^(\S+)$/) {
+ $net = $1;
+ if (defined($sasl_auth{$net})) {
+ delete $sasl_auth{$net};
+ Irssi::print("SASL: deleted $net");
+ } else {
+ Irssi::print("SASL: no entry for $net");
+ }
+ } else {
+ Irssi::print("SASL: usage: /sasl set <net> <user> <password or keyfile> <mechanism>");
+ }
+}
+
+sub cmd_sasl_show {
+ #my ($data, $server, $item) = @_;
+ my @nets = keys %sasl_auth;
+ for my $net (@nets) {
+ Irssi::print("SASL: $net: [$sasl_auth{$net}{mech}] $sasl_auth{$net}{user} *");
+ }
+ Irssi::print("SASL: no networks defined") if !@nets;
+}
+
+sub cmd_sasl_save {
+ #my ($data, $server, $item) = @_;
+ my $file = Irssi::get_irssi_dir()."/sasl.auth";
+ if (open(my $fh, ">", $file)) {
+ chmod(0600, $file);
+ for my $net (keys %sasl_auth) {
+ printf $fh ("%s\t%s\t%s\t%s\n",
+ $net,
+ $sasl_auth{$net}{user},
+ $sasl_auth{$net}{password},
+ $sasl_auth{$net}{mech});
+ }
+ close($fh);
+ Irssi::print("SASL: auth saved to '$file'");
+ } else {
+ Irssi::print("SASL: couldn't access '$file': $@");
+ }
+}
+
+sub cmd_sasl_load {
+ #my ($data, $server, $item) = @_;
+ my $file = Irssi::get_irssi_dir()."/sasl.auth";
+ if (open(my $fh, "<", $file)) {
+ %sasl_auth = ();
+ while (<$fh>) {
+ chomp;
+ my ($net, $u, $p, $m) = split(/\t/, $_, 4);
+ $m ||= "PLAIN";
+ if ($mech{uc $m}) {
+ $sasl_auth{$net}{user} = $u;
+ $sasl_auth{$net}{password} = $p;
+ $sasl_auth{$net}{mech} = uc $m;
+ } else {
+ Irssi::print("SASL: unknown mechanism $m", MSGLEVEL_CLIENTERROR);
+ }
+ }
+ close($fh);
+ Irssi::print("SASL: cap_sasl $VERSION, auth loaded from '$file'");
+ }
+}
+
+sub cmd_sasl_mechanisms {
+ Irssi::print("SASL: mechanisms supported: " . join(", ", sort keys %mech));
+}
+
+Irssi::settings_add_bool('server', 'sasl_disconnect_on_fail', 1);
+
+Irssi::signal_add_first('server connected', \&server_connected);
+Irssi::signal_add('event cap', \&event_cap);
+Irssi::signal_add('event authenticate', \&event_authenticate);
+Irssi::signal_add('event 903', \&event_saslend);
+Irssi::signal_add('event 904', \&event_saslfail);
+Irssi::signal_add('event 905', \&event_saslend);
+Irssi::signal_add('event 906', \&event_saslfail);
+Irssi::signal_add('event 907', \&event_saslend);
+
+Irssi::command_bind('sasl', \&cmd_sasl);
+Irssi::command_bind('sasl load', \&cmd_sasl_load);
+Irssi::command_bind('sasl save', \&cmd_sasl_save);
+Irssi::command_bind('sasl set', \&cmd_sasl_set);
+Irssi::command_bind('sasl show', \&cmd_sasl_show);
+Irssi::command_bind('sasl mechanisms', \&cmd_sasl_mechanisms);
+
+$mech{PLAIN} = sub {
+ my ($sasl, $data) = @_;
+ my $u = $sasl->{user};
+ my $p = $sasl->{password};
+ return join("\0", $u, $u, $p);
+};
+
+$mech{EXTERNAL} = sub {
+ my ($sasl, $data) = @_;
+ return $sasl->{user} // "";
+};
+
+if (eval {require Crypt::PK::ECC}) {
+ my $mech = "ECDSA-NIST256P-CHALLENGE";
+
+ $mech{'ECDSA-NIST256P-CHALLENGE'} = sub {
+ my ($sasl, $data) = @_;
+ my $u = $sasl->{user};
+ my $f = $sasl->{password};
+ $f = irssi_abspath($f);
+ if (!-f $f) {
+ Irssi::print("SASL: key file '$f' not found", MSGLEVEL_CLIENTERROR);
+ return;
+ }
+ my $pk = eval {Crypt::PK::ECC->new($f)};
+ if ($@ || !$pk || !$pk->is_private) {
+ Irssi::print("SASL: no private key in file '$f'", MSGLEVEL_CLIENTERROR);
+ return;
+ }
+ my $step = ++$sasl->{step};
+ if ($step == 1) {
+ if (length $data == CHALLENGE_SIZE) {
+ my $sig = $pk->sign_hash($data);
+ return $u."\0".$u."\0".$sig;
+ } elsif (length $data) {
+ return;
+ } else {
+ return $u."\0".$u;
+ }
+ }
+ elsif ($step == 2) {
+ if (length $data == CHALLENGE_SIZE) {
+ return $pk->sign_hash($data);
+ } else {
+ return;
+ }
+ }
+ };
+
+ sub cmd_sasl_keygen {
+ my ($data, $server, $witem) = @_;
+
+ my $print = $server
+ ? sub { $server->print("", shift, shift // MSGLEVEL_CLIENTNOTICE) }
+ : sub { Irssi::print(shift, shift // MSGLEVEL_CLIENTNOTICE) };
+
+ my $net = $server ? $server->{tag} : $data;
+ if (!length $net) {
+ Irssi::print("SASL: please connect to a server first",
+ MSGLEVEL_CLIENTERROR);
+ return;
+ }
+
+ my $f_name = lc "sasl-ecdsa-$net";
+ $f_name =~ s![ /]+!_!g;
+ my $f_priv = Irssi::get_irssi_dir()."/$f_name.key";
+ my $f_pub = Irssi::get_irssi_dir()."/$f_name.pub";
+ if (-e $f_priv) {
+ $print->("SASL: refusing to overwrite '$f_priv'", MSGLEVEL_CLIENTERROR);
+ return;
+ }
+
+ $print->("SASL: generating keypair for '$net'...");
+ my $pk = Crypt::PK::ECC->new;
+ $pk->generate_key("prime256v1");
+
+ my $priv = $pk->export_key_pem("private");
+ my $pub = encode_base64($pk->export_key_raw("public_compressed"), "");
+
+ if (open(my $fh, ">", $f_priv)) {
+ chmod(0600, $f_priv);
+ print $fh $priv;
+ close($fh);
+ $print->("SASL: wrote private key to '$f_priv'");
+ } else {
+ $print->("SASL: could not write '$f_priv': $!", MSGLEVEL_CLIENTERROR);
+ return;
+ }
+
+ if (open(my $fh, ">", $f_pub)) {
+ print $fh $pub."\n";
+ close($fh);
+ } else {
+ $print->("SASL: could not write '$f_pub': $!", MSGLEVEL_CLIENTERROR);
+ }
+
+ my $cmdchar = substr(Irssi::settings_get_str("cmdchars"), 0, 1);
+ my $cmd = "msg NickServ SET PROPERTY pubkey $pub";
+ # TODO: change to 'SET PUBKEY' when freenode gets support for that
+
+ if ($server) {
+ $print->("SASL: updating your Irssi settings...");
+ $sasl_auth{$net}{user} //= $server->{nick};
+ $sasl_auth{$net}{password} = "$f_name.key";
+ $sasl_auth{$net}{mech} = $mech;
+ cmd_sasl_save(@_);
+ $print->("SASL: submitting pubkey to NickServ...");
+ $server->command($cmd);
+ } else {
+ $print->("SASL: update your Irssi settings:");
+ $print->("%P".$cmdchar."sasl set $net <nick> $f_name.key $mech");
+ $print->("SASL: submit your pubkey to $net:");
+ $print->("%P".$cmdchar.$cmd);
+ }
+ }
+
+ sub cmd_sasl_pubkey {
+ my ($data, $server, $witem) = @_;
+
+ my $arg = $server ? $server->{tag} : $data;
+
+ my $f;
+ if (!length $arg) {
+ Irssi::print("SASL: please select a server or specify a keyfile path",
+ MSGLEVEL_CLIENTERROR);
+ return;
+ } elsif ($arg =~ m![/.]!) {
+ $f = $arg;
+ } else {
+ if ($sasl_auth{$arg}{mech} eq $mech) {
+ $f = $sasl_auth{$arg}{password};
+ } else {
+ $f = lc "sasl-ecdsa-$arg";
+ $f =~ s![ /]+!_!g;
+ $f = "$f.key";
+ }
+ }
+
+ $f = irssi_abspath($f);
+ if (!-e $f) {
+ Irssi::print("SASL: keyfile '$f' not found", MSGLEVEL_CLIENTERROR);
+ return;
+ }
+
+ my $pk = eval {Crypt::PK::ECC->new($f)};
+ if ($@ || !$pk || !$pk->is_private) {
+ Irssi::print("SASL: no private key in file '$f'", MSGLEVEL_CLIENTERROR);
+ Irssi::print("(keys using named parameters or PKCS#8 are not yet supported)",
+ MSGLEVEL_CLIENTERROR);
+ return;
+ }
+
+ my $pub = encode_base64($pk->export_key_raw("public_compressed"), "");
+ Irssi::print("SASL: loaded keyfile '$f'");
+ Irssi::print("SASL: your pubkey is $pub");
+ }
+
+ Irssi::command_bind('sasl keygen', \&cmd_sasl_keygen);
+ Irssi::command_bind('sasl pubkey', \&cmd_sasl_pubkey);
+};
+
+cmd_sasl_load();
+
+# vim: ts=4:sw=4
diff --git a/scripts/clones_scanner.pl b/scripts/clones_scanner.pl
new file mode 100644
index 0000000..bf308a0
--- /dev/null
+++ b/scripts/clones_scanner.pl
@@ -0,0 +1,296 @@
+use strict;
+use warnings;
+
+{ package Irssi::Nick }
+# just in case, to avoid Irssi::Nick warnings ( see http://bugs.irssi.org/index.php?do=details&task_id=242 )
+
+use Irssi;
+use vars qw($VERSION %IRSSI);
+
+# Thanks to:
+# -noi_esportista!#Girona@chathispano for his suggestions about how this script should work.
+# -dg!#irssi@freenode (David Leadbeater) for the several code style issues that he pointed out and that helped me to improve my Perl.
+
+$VERSION = '1.6';
+%IRSSI = (
+ authors => 'Pablo Martín Báez Echevarría',
+ contact => 'pab_24n@outlook.com',
+ name => 'clones_scanner',
+ description => 'when a nick joins #channel, notifies you if there is (or there has been) someone in #channel with the same hostname',
+ license => 'Public Domain',
+ url => 'http://reirssi.wordpress.com',
+ changed => '22:30:25, Dec 20th, 2014 UYT',
+);
+
+#
+# USAGE
+# =====
+# Copy the script to ~/.irssi/scripts/
+#
+# In irssi:
+# /run clones_scanner
+#
+#
+# OPTIONS
+# =======
+# Settings can be resetted to defaults with /set -default
+#
+# /set clones_scanner_maxtime <time>
+# * This is the maximum time in which the script remembers that a specific hostname
+# left a channel because of a PART, QUIT or KICK event (default is 900secs = 15mins).
+# For example, suppose it is 1 hour. If someone with mask type nick1!*@host left #channel
+# at 11:00 and then comes back at 12:01 with mask type nick2!*@host, you will not be
+# notified that 'nick2' was seen earlier in #channel as 'nick1'.
+# It must be a time type, that is a series of integers with optional unit specifiers.
+# Valid specifiers are:
+#
+# d[ays]
+# h[ours]
+# m[inutes]
+# s[econds]
+# mil[liseconds] | ms[econds]
+#
+# Any unambiguous part of a specifier can be used, as shown by the strings in braces in
+# the above list. Multiple specifiers can be combined, with or without spaces between them.
+#
+# Examples:
+#
+# /set clones_scanner_maxtime 1hour30mins
+# /set clones_scanner_maxtime 2h
+# /set clones_scanner_maxtime 3h 10secs
+#
+# There must not be a space between the number and the unit specifier.
+#
+#
+# COMMANDS
+# ========
+# /clones_scanner_size
+# * Displays how many entries the data structure where the hosts are stored has, and how much
+# memory is used for that purpose.
+#
+# WARNING: This feature requires Devel::Size module. It seems that when installing Devel::Size
+# some tests started to fail since Perl 5.19.3 so if you're using the latest Perl release
+# (Perl 5.20.1) you'll have to wait for someone to fix Devel::Size for recent Perl versions.
+# See more about this issue at: https://rt.cpan.org/Public/Bug/Display.html?id=95493
+# Remeber that you can find out Perl version with
+# $ perl -v
+# in a terminal or alternatively executing /script exec print $^V in irssi.
+#
+
+
+Irssi::settings_add_time('clones_scanner', 'clones_scanner_maxtime', 900);
+
+# global variables
+my $have_devel_size = eval { require Devel::Size };
+my %hosts_hash = ();
+my $old_maxtime_msecs;
+my $old_maxtime_str;
+my $total_entries = 0;
+
+##########
+
+sub add_entry {
+ my ( $network, $channel, $address, $nick ) = @_;
+
+ (my $host = $address) =~ s/^[^@]+@//;
+
+ if (defined $hosts_hash{$network}{$channel}{$host}) {
+ my $old_tag = $hosts_hash{$network}{$channel}{$host}[2];
+ Irssi::timeout_remove( $old_tag );
+ $total_entries--;
+ }
+
+ my $time = Irssi::settings_get_time("clones_scanner_maxtime");
+ my @data = ( $network, $channel, $host );
+ my $tag = Irssi::timeout_add_once($time, "remove_entry", \@data);
+
+ my $entry = [$nick, time(), $tag];
+ $hosts_hash{$network}{$channel}{$host} = $entry;
+ $total_entries++;
+
+}
+
+sub str_time {
+ my ( $secs ) = @_;
+
+ my $d = int($secs/3600/24);
+ my $h = int($secs/3600%24);
+ my $m = int($secs/60%60);
+ my $s = int($secs%60);
+
+ my $d_str = ($d == 1) ? "day": "days";
+ my $h_str = ($h == 1) ? "hour": "hours";
+ my $m_str = ($m == 1) ? "minute": "minutes";
+ my $s_str = ($s == 1) ? "second": "seconds";
+
+ my $raw_str = $d.$d_str.", ".$h.$h_str.", ".$m.$m_str.", ".$s.$s_str;
+
+ (my $str_res = $raw_str) =~ s/\b0\w+(?:,\s)?//g;
+ ($str_res = $str_res) =~ s/,\s$//;
+ ($str_res = $str_res) =~ s/(\d)([dhms])/$1 $2/g;
+
+ return $str_res eq "" ? "less than 1 second" : $str_res;
+}
+
+sub remove_entry {
+ my ( $ref_data ) = @_;
+
+ my $network = @{$ref_data}[0];
+ my $chan = @{$ref_data}[1];
+ my $host = @{$ref_data}[2];
+
+ delete $hosts_hash{$network}{$chan}{$host};
+ $total_entries--;
+ delete $hosts_hash{$network}{$chan} if (!keys %{$hosts_hash{$network}{$chan}});
+ delete $hosts_hash{$network} if (!keys %{$hosts_hash{$network}});
+}
+
+sub update_hash {
+ my ( $nw_maxtime ) = @_;
+ my $remainder;
+ my $ni;
+ my $se;
+ my $tg;
+ my $nw_tg;
+
+ foreach my $network (keys %hosts_hash) {
+ foreach my $channel (keys %{$hosts_hash{$network}}) {
+ foreach my $host (keys %{$hosts_hash{$network}{$channel}}) {
+ $ni = @{$hosts_hash{$network}{$channel}{$host}}[0];
+ $se = @{$hosts_hash{$network}{$channel}{$host}}[1];
+ $tg = @{$hosts_hash{$network}{$channel}{$host}}[2];
+ Irssi::timeout_remove( $tg );
+ $remainder = $nw_maxtime - (time() - $se);
+ if( $remainder > 0 ) {
+ my @data = ( $network, $channel, $host );
+ $nw_tg = Irssi::timeout_add_once( $remainder*1000, "remove_entry", \@data);
+ $hosts_hash{$network}{$channel}{$host} = [$ni, $se, $nw_tg];
+ } else {
+ delete $hosts_hash{$network}{$channel}{$host};
+ $total_entries--;
+ }
+ }
+ delete $hosts_hash{$network}{$channel} if (!keys %{$hosts_hash{$network}{$channel}});
+ }
+ delete $hosts_hash{$network} if (!keys %{$hosts_hash{$network}});
+ }
+
+}
+
+sub setup_changed {
+ my $new_maxtime_msecs = Irssi::settings_get_time("clones_scanner_maxtime");
+ if($new_maxtime_msecs < 10) {
+ Irssi::print("Invalid timestamp (must be >= 10 msecs)", MSGLEVEL_CLIENTERROR);
+ Irssi::settings_set_time("clones_scanner_maxtime", $old_maxtime_str);
+ $new_maxtime_msecs = Irssi::settings_get_time("clones_scanner_maxtime");
+ }
+ update_hash(int($new_maxtime_msecs/1000)) if ($new_maxtime_msecs != $old_maxtime_msecs);
+}
+
+##########
+
+sub part_method {
+ my ($server, $channel, $nick, $address, $reason) = @_;
+
+ add_entry($server->{tag}, $channel, $address, $nick);
+}
+
+sub quit_method {
+ my ($server, $nick, $address, $reason) = @_;
+
+ foreach($server->channels()) {
+ if ($_->nick_find($nick)) {
+ add_entry($server->{tag}, $_->{name}, $address, $nick);
+ }
+ }
+}
+
+sub kick_method {
+ my ($server, $channel, $nick, $kicker, $address, $reason) = @_;
+
+ Irssi::signal_stop();
+ my $kicked_address = $server->channel_find($channel)->nick_find($nick)->{host};
+ Irssi::signal_continue(@_);
+ add_entry($server->{tag}, $channel, $kicked_address, $nick);
+}
+
+##########
+
+sub join_method {
+ my ($server, $channel, $nick, $address) = @_;
+
+ Irssi::signal_continue(@_);
+
+ my $servtag = $server->{tag};
+ (my $host = $address) =~ s/^[^@]+@//;
+ my $chan_rec = $server->channel_find($channel);
+
+ # ==== find clones ====
+ my $ni_host;
+ my $str_clones = "";
+ my @clones;
+ foreach my $ni ($chan_rec->nicks()) {
+ ($ni_host = "$ni->{host}") =~ s/^[^@]+@//;
+ if ( ($ni->{nick} ne $nick)&&($ni_host eq $host) ) {
+ $str_clones .= "$ni->{nick}".", ";
+ push @clones, $ni->{nick};
+ }
+ }
+ if( $str_clones ne "") {
+ ($str_clones = $str_clones) =~ s/,\s$//;
+ $chan_rec->printformat(Irssi::MSGLEVEL_JOINS, "clones_scanner_clones", $nick, $str_clones);
+ }
+
+ # ==== search in %hosts_hash ====
+ my $exists_nick_in_hash = (defined $hosts_hash{$servtag})&&(defined $hosts_hash{$servtag}{$channel})
+ &&(defined $hosts_hash{$servtag}{$channel}{$host});
+
+ if ($exists_nick_in_hash) {
+ my @alias = @{ $hosts_hash{$servtag}{$channel}{$host} };
+ if ( ($nick ne $alias[0]) && (!(grep {$_ eq $alias[0]} @clones)) ) {
+ my $time = Irssi::settings_get_time("clones_scanner_maxtime");
+ $chan_rec->printformat( Irssi::MSGLEVEL_JOINS, "clones_scanner_track_nick", $nick, str_time(int($time/1000)),
+ $alias[0], str_time(time()-$alias[1]));
+ }
+ }
+
+}
+
+##########
+
+Irssi::theme_register([
+ "clones_scanner_clones", 'Clones of {nick $0}: $1',
+ "clones_scanner_track_nick", '=> {nick $0} was seen during the last $1 as {nick $2} ($3 ago)',
+]);
+
+##########
+
+
+if ($have_devel_size) {
+
+ Irssi::command_bind('clones_scanner_size' , sub {
+ my $bytes = Devel::Size::total_size(\%hosts_hash);
+ print "Number of entries in \%hosts_hash: ", $total_entries;
+ print "Size in bytes: ", $bytes;
+ print int($bytes/1024/1024)."MB ".int($bytes/1024%1024)."kB ".int($bytes%1024)."B of data";
+ });
+
+} else {
+
+ print "Missing Devel::Size module. The command `/clones_scanner_size` will not be available.";
+
+}
+
+Irssi::signal_add_first('message part', \&part_method);
+Irssi::signal_add_first('message quit', \&quit_method);
+Irssi::signal_add_first('message kick', \&kick_method);
+
+Irssi::signal_add_last('message join', \&join_method);
+
+Irssi::signal_add_last('setup changed', \&setup_changed);
+
+Irssi::signal_add_first('send command',
+sub {
+ $old_maxtime_msecs = Irssi::settings_get_time("clones_scanner_maxtime");
+ $old_maxtime_str = Irssi::settings_get_str("clones_scanner_maxtime");
+});
diff --git a/scripts/cron.pl b/scripts/cron.pl
index 9e1d125..0d1ac1e 100644
--- a/scripts/cron.pl
+++ b/scripts/cron.pl
@@ -40,6 +40,9 @@
# ? should we remember if the server was given with -server
#
# Changelog:
+# 0.12 (2014.11.12)
+# Automatically load jobs when loaded
+#
# 0.11 (2004.12.12)
# Job are executed exactly at the time (+- 1s), not up to 59s late
#
@@ -69,7 +72,7 @@ use Irssi;
use strict;
use vars qw($VERSION %IRSSI);
-$VERSION = "0.11";
+$VERSION = "0.12";
%IRSSI = (
authors => 'Piotr Krukowiecki',
contact => 'piotr \at/ krukowiecki /dot\ net',
@@ -290,6 +293,8 @@ sub cmd_jobsload {
Irssi::print("Jobs loaded");
}
+cmd_jobsload();
+
Irssi::command_bind('jobs', 'cmd_jobs', 'Cron');
Irssi::command_bind('jobadd', 'cmd_jobadd', 'Cron');
Irssi::command_bind('jobdel', 'cmd_jobdel', 'Cron');
diff --git a/scripts/dice_concise.pl b/scripts/dice_concise.pl
new file mode 100644
index 0000000..8d5fbe3
--- /dev/null
+++ b/scripts/dice_concise.pl
@@ -0,0 +1,247 @@
+# dice_concise / Based on Marcel Kossin's 'dice' RP Dice Simulator
+#
+# What is this?
+#
+# -- Marcel Kossin's notes: --
+#
+# I (mkossin) often Dungeon Master on our Neverwinternights Servers called 'Bund der
+# alten Reiche' (eng. 'Alliance of the old realms') at bundderaltenreiche.de
+# (German Site) Often idling in our Channel I thought it might be Fun to have
+# a script to dice. Since I found nothing for irssi I wrote this little piece
+# of script. The script assumes, that if a 'd' for english dice is given it
+# should print the output in English. On the other hand if a 'w' for German
+# 'Würfel' is given it prints the output in German.
+#
+# Usage.
+#
+# Anyone on the Channel kann ask '!roll' to toss the dice for him. He just has
+# to say what dice he want to use. The notation should be well known from
+# RP :-) Thus
+#
+# Write: !roll <quantity of dice>d[or w for german users]<sides on dice>
+#
+# Here are some examples
+#
+# !roll 2d20
+# !roll 3d6
+#
+# OK, I think you got it already :-)
+#
+# Write: !roll version
+# For Version Information
+#
+# Write: !roll help
+# For Information about how to use it
+#
+# -- Makaze's notes: --
+#
+# [Changes in dice_concise:]
+#
+# Features added:
+#
+# [ ] Can add bonuses to the roll. e.g. "!roll 3d6+10"
+# [ ] Output changed to one line only. e.g. "Makaze rolls the 3d6 and gets: 9 [4,
+# 4, 1]"
+# [ ] Corrected English grammar.
+# [ ] Removed insults.
+# [ ] Cleaner code with fewer nested if statements and true case switches.
+# [ ] Errors call before the loop, saving clock cycles.
+#
+# Bugs fixed:
+#
+# [ ] Rolls within the correct range.*
+#
+# Edge cases added:
+#
+# [ ] Catch if rolling less than 1 dice.
+# [ ] Catch if dice or sides are above 100 instead of 99.
+#
+# -----------------------------------------
+#
+# * [The original dice.pl rolled a number between 1 and (<number of sides> - 1)]
+# [instead of using the full range. e.g. "!roll 1d6" would output 1 through ]
+# [5, but never 6. ]
+#
+# -----------------------------------------
+#
+# Original script 'dice.pl' by mkossin.
+#
+# Updated script 'dice_concise.pl' by Makaze.
+
+use strict;
+use vars qw($VERSION %IRSSI);
+use feature qw(switch);
+use Scalar::Util qw(looks_like_number);
+
+use Irssi qw(command_bind signal_add);
+
+$VERSION = '0.1.5';
+%IRSSI = (
+ authors => 'Marcel Kossin, Makaze',
+ contact => 'izaya.orihara@gmail',
+ name => 'dice_concise',
+ description => 'A concise dice simulator for channels.',
+ license => 'GNU GPL v2 or later'
+);
+
+sub own_question {
+ my ($server, $msg, $nick, $address, $target) = @_;
+ question($server, $msg, $nick, $target);
+}
+
+sub public_question {
+ my ($server, $msg, $nick, $address, $target) = @_;
+ question($server, $msg, $nick, $target);
+}
+
+sub question($server, $msg, $nick, $target) {
+ my ($server, $msg, $nick, $target) = @_;
+ $_ = $msg;
+
+ my $msgCompare = lc;
+
+ if (substr($msgCompare, 0, 5) ne '!roll') {
+ return 0;
+ }
+
+ unless (length $target) {
+ $target = $nick;
+ $nick = $server->{nick};
+ }
+
+ if (/\d[dw]\d/i) {
+ my $rnd;
+ my $forloop;
+ my $lang;
+ my @roll = split(/\s/, $_, 2);
+ my ($dice, $sides) = (@roll[1] =~ /(\d+)[dw](\d+)/i);
+ my @modifiers = ($roll[1] =~ /([\+\-\*\/]\d+)/gi);
+ my $modifyType;
+ my $modifyVal;
+ my @modifyErrors = ($roll[1] =~ /([\+\-\*\/][^\d\+\-\*\/]+)/);
+ my $value;
+ # Plus support added
+ my @rolls;
+
+ if (/\d[w]\d/i) {
+ $lang = 'DE';
+ } else {
+ $lang = 'EN';
+ }
+
+ if ($dice < 1) {
+ given ($lang) {
+ when ('DE') {
+ $server->command('msg ' . $target . ' ' . $nick . ' macht nichts... Würfeln funktioniert am besten mit Würfeln.');
+ }
+ when ('EN') {
+ $server->command('msg ' . $target . ' ' . $nick . ' does nothing... Rolling dice works best with dice.');
+ }
+ }
+ return 0;
+ } elsif ($dice > 100) {
+ given ($lang) {
+ when ('DE') {
+ $server->command('msg ' . $target . ' ' . $nick . ' scheitert den ' . $roll[1] . ' zu werfen... Versuch es mit weniger Würfeln.');
+ }
+ when ('EN') {
+ $server->command('msg ' . $target . ' ' . $nick . ' fails to roll the ' . $roll[1] . '... Try fewer dice.');
+ }
+ }
+ return 0;
+ } elsif ($sides <= 1) {
+ if ($sides == 0) {
+ given ($lang) {
+ when ('DE') {
+ $server->command('msg ' . $target . ' ' . $nick . ' verursacht ein Paradox... Oder hat jemand schon mal einen Würfel ohne Seiten gesehen?');
+ }
+ when ('EN') {
+ $server->command('msg ' . $target . ' ' . $nick . ' causes a paradox... Or has anybody ever seen a die without sides?');
+ }
+ }
+ return 0;
+ } elsif ($sides == 1) {
+ given ($lang) {
+ when ('DE') {
+ $server->command('msg ' . $target . ' ' . $nick . ' verursacht ein Paradox... Oder hat jemand schon mal einen Würfel mit nur einer Seite gesehen?');
+ }
+ when ('EN') {
+ $server->command('msg ' . $target . ' ' . $nick . ' causes a paradox... Or has anybody ever seen a die with only one side?');
+ }
+ }
+ return 0;
+ }
+ } elsif ($sides > 100) {
+ given ($lang) {
+ when ('DE') {
+ $server->command('msg ' . $target . ' ' . $nick . ' scheitert den ' . $roll[1] . ' zu werfen... Versuch es mit weniger Augen.');
+ }
+ when ('EN') {
+ $server->command('msg ' . $target . ' ' . $nick . ' fails to roll the ' . $roll[1] . '... Try fewer sides.');
+ }
+ }
+ return 0;
+ }
+ for ($forloop = 0; $forloop < $dice; $forloop++) {
+ $rnd = int(rand($sides));
+ if ($rnd == 0) {
+ $rnd = $sides;
+ }
+ $value += $rnd;
+ $rolls[$forloop] = $rnd;
+ }
+ foreach (@modifiers) {
+ ($modifyType) = ($_ =~ /([\+\-\*\/])/);
+ ($modifyVal) = ($_ =~ /(\d+)/);
+ given ($modifyType) {
+ when ('*') {
+ $value = $value * $modifyVal;
+ }
+ when ('/') {
+ $value = $value / $modifyVal;
+ }
+ when ('+') {
+ $value = $value + $modifyVal;
+ }
+ when ('-') {
+ $value = $value - $modifyVal;
+ }
+ }
+ }
+ given ($lang) {
+ when ('DE') {
+ $server->command('msg ' . $target . ' '. $nick . ' würfelt mit dem ' . $roll[1] . ' und erhält: ' . $value . ' [' . join(', ', @rolls) . ']');
+ }
+ when ('EN') {
+ $server->command('msg ' . $target . ' '. $nick . ' rolls the ' . $roll[1] . ' and gets: ' . $value . ' [' . join(', ', @rolls) . ']');
+ }
+ }
+ if (@modifyErrors) {
+ given ($lang) {
+ when ('DE') {
+ $server->command('msg ' . $target . ' ' . $nick . ' scheitert ihr Ergebnis zu ändern. Versuch es mit Zahlen. [' . join(', ', @modifyErrors) . ']');
+ }
+ when ('EN') {
+ $server->command('msg ' . $target . ' ' . $nick . ' fails to modify their result. Try using numbers. [' . join(', ', @modifyErrors) . ']');
+ }
+ }
+ }
+ return 1;
+ } elsif (substr($msgCompare, 0, 13) eq '!roll version') {
+ $server->command('msg ' . $target . " \x039" . $IRSSI{'name'} . ": Version " . $VERSION . " by Makaze & mkossin");
+ return 0;
+ } elsif (substr($msgCompare, 0, 10) eq '!roll help') {
+ $server->command('msg ' . $target . ' Syntax: "!roll <quantity of dice>d<sides on dice>[<+-*/>modifier]" - e.g. "!roll 2d20", "!roll 2d20*2+10"');
+ return 0;
+ } elsif (substr($msgCompare, 0, 11) eq '!roll hilfe') {
+ $server->command('msg ' . $target . ' Syntax: "!roll <Anzahl der Würfel>w<Augen des Würfels>[<+-*/>Modifikator]" - z.B. "!roll 2w20", "!roll 2w20*2+10"');
+ return 0;
+ } else {
+ $server->command('msg ' . $target .' "!roll help" - gives the English help');
+ $server->command('msg ' . $target . ' "!roll hilfe" - zeigt die deutsche Hilfe an');
+ return 0;
+ }
+}
+
+signal_add('message public', 'public_question');
+signal_add('message own_public', 'own_question'); \ No newline at end of file
diff --git a/scripts/eng_no_translate_dpryo.pl b/scripts/eng_no_translate_dpryo.pl
deleted file mode 100644
index f00f40c..0000000
--- a/scripts/eng_no_translate_dpryo.pl
+++ /dev/null
@@ -1,57 +0,0 @@
-# A simple script for all Norwegians who like to get
-# all incoming english text translated to Norwegian :D
-# Written by dpryo <hnesland@samsen.com>
-#
-# WARNING:
-# Dunno what freetranslation.com thinks about it ;D
-# ..so remember, this scripts sends ALL incoming public messages
-# as a webrequest to their server. That is, one request pr.
-# message you get. In other words, if somebody pubfloods 100 lines, you will
-# visit freetranslation.com 100 times ;)
-######
-#
-# There is at least one bug in it .. It doesn't check wether the
-# incoming text is english or not before it sends the request.
-#
-# Somebody could perhaps fix that?, since i'm a lazy asshole.
-#
-# Another thing, it doesn't handles channels or anything, so
-# I could call this a "Technology Preview" as all the big
-# guys are calling their software when it's in a buggy and
-# not-so-very-usefull stage of development :P
-#
-use Irssi;
-use LWP::Simple;
-use vars qw($VERSION %IRSSI);
-$translate =0;
-
-$VERSION = "0.2";
-%IRSSI = (
- authors => "Harald Nesland",
- contact => "hnesland\@samsen.com",
- name => "EngNoTranslate",
- description => "Very simple script that sends incoming text to freetranslation.com for english->norwegian translation. May be modified to translate other languages.",
- license => "Public Domain",
- url => "http://www.satyra.net",
- changed => "Thu Apr 11 14:15:25 CEST 2002"
-);
-
-sub income {
-my ($server, $data, $nick, $mask, $target) = @_;
- $eng = $data;
- if($translate=1) {
- $eng =~ s/ /+/ig;
- chop($eng);
- Irssi::command("/echo [$nick] $eng");
- $result = get("http://ets.freetranslation.com:5081/?Sequence=core&Mode=txt&template=TextResults2.htm&Language=English/Norwegian&SrcText=$eng");
- Irssi::command("/echo [$nick] $result");
- }
-}
-
-sub trans {
-
- if($translate =0) { $translate=1; } else { $translate =0; }
-}
-
-Irssi::signal_add("message public", "income");
-Irssi::command_bind("translate","trans");
diff --git a/scripts/fnotify.pl b/scripts/fnotify.pl
new file mode 100644
index 0000000..76e46b4
--- /dev/null
+++ b/scripts/fnotify.pl
@@ -0,0 +1,92 @@
+use strict;
+use warnings;
+use vars qw($VERSION %IRSSI);
+use Irssi;
+
+$VERSION = '0.0.5';
+%IRSSI = (
+ name => 'fnotify',
+ authors => 'Thorsten Leemhuis, James Shubin, Serge van Ginderachter',
+ description => 'Write notifications to a file in a consistent format.',
+ license => 'GNU General Public License',
+);
+
+#
+# README
+#
+# To use:
+# $ cp fnotify.pl ~/.irssi/scripts/fnotify.pl
+# irssi> /load perl
+# irssi> /script load fnotify
+#
+
+#
+# AUTHORS
+#
+# Strip non-parsed left over codes (Bitlbee otr messages)
+# version: 0.0.5
+# Serge van Ginderachter <serge@vanginderachter.be>
+#
+# Consistent output formatting by James Shubin:
+# version: 0.0.4
+# https://ttboj.wordpress.com/
+# note: changed license back to original GPL from Thorsten Leemhuis (svg)
+#
+# Modified from the Thorsten Leemhuis <fedora@leemhuis.info>
+# version: 0.0.3
+# http://www.leemhuis.info/files/fnotify/fnotify
+#
+# In parts based on knotify.pl 0.1.1 by Hugo Haas:
+# http://larve.net/people/hugo/2005/01/knotify.pl
+#
+# Which is based on osd.pl 0.3.3 by Jeroen Coekaerts, Koenraad Heijlen:
+# http://www.irssi.org/scripts/scripts/osd.pl
+#
+# Other parts based on notify.pl from Luke Macken:
+# http://fedora.feedjack.org/user/918/
+#
+
+#
+# catch private messages
+#
+sub priv_msg {
+ my ($server, $msg, $nick, $address, $target) = @_;
+ my $msg_stripped = Irssi::strip_codes($msg);
+ my $network = $server->{tag};
+ filewrite('' . $network . ' ' . $nick . ' ' . $msg_stripped);
+}
+
+#
+# catch 'hilight's
+#
+sub hilight {
+ my ($dest, $text, $stripped) = @_;
+ if ($dest->{level} & MSGLEVEL_HILIGHT) {
+ my $server = $dest->{server};
+ my $network = $server->{tag};
+ filewrite($network . ' ' . $dest->{target} . ' ' . $stripped);
+ }
+}
+
+#
+# write to file
+#
+sub filewrite {
+ my ($text) = @_;
+ my $fnfile = Irssi::get_irssi_dir() . "/fnotify";
+ if (!open(FILE, ">>", $fnfile)) {
+ print CLIENTCRAP "Error: cannot open $fnfile: $!";
+ } else {
+ print FILE $text . "\n";
+ if (!close(FILE)) {
+ print CLIENTCRAP "Error: cannot close $fnfile: $!";
+ }
+ }
+}
+
+#
+# irssi signals
+#
+Irssi::signal_add_last("message private", "priv_msg");
+Irssi::signal_add_last("print text", "hilight");
+
diff --git a/scripts/frm_outgmsgs.pl b/scripts/frm_outgmsgs.pl
index 7e51566..71c9b02 100644
--- a/scripts/frm_outgmsgs.pl
+++ b/scripts/frm_outgmsgs.pl
@@ -5,7 +5,7 @@ use Scalar::Util qw(looks_like_number);
use Irssi;
use vars qw($VERSION %IRSSI);
-$VERSION = '1.0';
+$VERSION = '1.1';
%IRSSI = (
authors => 'Pablo Martín Báez Echevarría',
contact => 'pab_24n@outlook.com',
@@ -95,7 +95,7 @@ sub cmd_colors {
}
sub is_mIRC_color {
- my $num = @_;
+ my ( $num ) = @_;
return (looks_like_number($num)) ? ((0 <= $num) && ($num <= 15)) : 0;
}
diff --git a/scripts/go.pl b/scripts/go.pl
index 3ca6744..b656a0f 100644
--- a/scripts/go.pl
+++ b/scripts/go.pl
@@ -8,7 +8,7 @@ use Irssi::Irc;
# If you are in #irssi you can type /go #irssi or /go irssi or even /go ir ...
# also try /go ir<tab> and /go <tab> (that's two spaces)
-$VERSION = '1.00';
+$VERSION = '1.01';
%IRSSI = (
authors => 'nohar',
@@ -16,7 +16,7 @@ $VERSION = '1.00';
name => 'go to window',
description => 'Implements /go command that activates a window given a name/partial name. It features a nice completion.',
license => 'GPLv2 or later',
- changed => '08-17-04'
+ changed => '2014-10-19'
);
sub signal_complete_go {
@@ -24,7 +24,7 @@ sub signal_complete_go {
my $channel = $window->get_active_name();
my $k = Irssi::parse_special('$k');
- return unless ($linestart =~ /^\Q${k}\Ego/i);
+ return unless ($linestart =~ /^\Q${k}\Ego\b/i);
@$complist = ();
foreach my $w (Irssi::windows) {
diff --git a/scripts/localize.pl b/scripts/localize.pl
index 8d00985..7aabe9f 100644
--- a/scripts/localize.pl
+++ b/scripts/localize.pl
@@ -52,11 +52,15 @@
#
# 03.07.2002
# *switched to Data::Dumper
+#
+# 25.11.2014
+# Added utrace.de as a localizer
+# http://www.utrace.de/
use strict;
use vars qw($VERSION %IRSSI);
-$VERSION = "2003112301";
+$VERSION = "2014112501";
%IRSSI = (
authors => "Stefan 'tommie' Tomanek",
contact => "stefan\@pico.ruhr.de",
@@ -186,16 +190,17 @@ $procs = 0;
);
%ipdb = (
- d1localizer=>{ name=>'localizer',
+ # For utrace.de API documentation, see http://en.utrace.de/api.php
+ d1utrace=>{ name=>'utrace',
active=>1,
- url=>'http://jan.kneschke.de/projects/localizer/index.php?query=',
- city=>'<tr><td><b>City<\/b><\/td><td>(.*?)<\/td>',
- province=>'<tr><td><b>Province<\/b><\/td><td>(.*?)<\/td><td>',
- country=>'<tr><td><b>Country<\/b><\/td><td>(.*?)<\/td>',
- provider=>'<tr><td><b>\(Backbone-\)Provider<\/b><\/td><td>(.*?)<\/td>',
+ url=>'http://xml.utrace.de/?query=',
+ city=>'<region>(.*?)<\/region>',
+ province=>'<org>(.*?)<\/org>',
+ country=>'<countrycode>(.*?)<\/countrycode>',
+ provider=>'<isp>(.*?)<\/isp>',
failure=>'request-limit-exceeded|Host not found'},
d2ipatlas=> { name=>'IP-Atlas',
- active=>1,
+ active=>0,
url=>'http://www.xpenguin.com/plot.php?address=',
city=>'is located in (.*?),',
province=>'is located in.*, (.*?) \(state\),',
diff --git a/scripts/rainbow.pl b/scripts/rainbow.pl
index 3fc2375..0dd292d 100644
--- a/scripts/rainbow.pl
+++ b/scripts/rainbow.pl
@@ -13,6 +13,9 @@
#
# /RKICK <nick> [reason]
# - kicks nick from the current channel with coloured reason
+#
+# /RKNOCKOUT [time] <nicks> [reason]
+# - knockouts nicks from the current channel with coloured reason for time
# Written by Jakub Jankowski <shasta@atn.pl>
# for Irssi 0.7.98.4 and newer
@@ -20,7 +23,7 @@
use strict;
use vars qw($VERSION %IRSSI);
-$VERSION = "1.4";
+$VERSION = "1.6";
%IRSSI = (
authors => 'Jakub Jankowski',
contact => 'shasta@atn.pl',
@@ -47,6 +50,7 @@ my @colors = ('0', '4', '8', '9', '11', '12', '13');
# returns random-coloured string
sub make_colors {
my ($string) = @_;
+ Encode::_utf8_on($string);
my $newstr = "";
my $last = 255;
my $color = 0;
@@ -132,10 +136,30 @@ sub rkick {
}
}
+# void rknockout($text, $server, $destination)
+# handles /rknockout
+sub rknockout {
+ my ($text, $server, $dest) = @_;
+
+ if (!$server || !$server->{connected}) {
+ Irssi::print("Not connected to server");
+ return;
+ }
+
+ if ($dest && $dest->{type} eq "CHANNEL") {
+ my ($time, $nick, $reason) = split(/ +/, $text, 3);
+ ($time, $nick, $reason) = (300, $time, $nick . " " . $reason) if ($time !~ m/^\d+$/);
+ return unless $nick;
+ $reason = "See you in " . $time . " seconds!" if ($reason =~ /^[\ ]*$/);
+ $dest->command("/knockout " . $time . " " . $nick . " " . make_colors($reason));
+ }
+}
+
Irssi::command_bind("rsay", "rsay");
Irssi::command_bind("rtopic", "rtopic");
Irssi::command_bind("rme", "rme");
Irssi::command_bind("rkick", "rkick");
+Irssi::command_bind("rknockout", "rknockout");
# changes:
#
@@ -144,3 +168,5 @@ Irssi::command_bind("rkick", "rkick");
# 29.01.2002: /rsay works with dcc chats now (v1.2)
# 02.02.2002: make_colors() doesn't assign any color to spaces (v1.3)
# 23.02.2002: /rkick added
+# 26.11.2014: utf-8 support
+# 01.12.2014: /rknockout added (v1.6)
diff --git a/scripts/screen_away.pl b/scripts/screen_away.pl
index 86e3087..722ceed 100644
--- a/scripts/screen_away.pl
+++ b/scripts/screen_away.pl
@@ -4,7 +4,7 @@ use FileHandle;
use vars qw($VERSION %IRSSI);
-$VERSION = "0.9.7.1";
+$VERSION = "0.9.8.1";
%IRSSI = (
authors => 'Andreas \'ads\' Scherbaum <ads@wars-nicht.de>',
name => 'screen_away',
@@ -18,6 +18,7 @@ $VERSION = "0.9.7.1";
# written by Andreas 'ads' Scherbaum <ads@ufp.de>
#
# changes:
+# 20.12.2014 fix the bug when screenname is changed during the session
# 07.02.2004 fix error with away mode
# thanks to Michael Schiansky for reporting and fixing this one
# 07.08.2004 new function for changing nick on away
@@ -83,7 +84,7 @@ if (!defined($ENV{STY})) {
return;
}
-my ($socket_name, $socket_path);
+my ($socket_pid, $socket_name, $socket_path);
# search for socket
# normal we could search the socket file, ... if we know the path
@@ -99,9 +100,13 @@ my $running_in_screen = 0;
# locale doesnt seems to be an problem (yet)
if ($socket !~ /^No Sockets found/s) {
# ok, should have only one socket
- $socket_name = $ENV{'STY'};
+ # $STY won't change if sessionname is changed during session
+ # therefore first find the pid and use that to find the actual sessionname
+ $socket_pid = substr($ENV{'STY'}, 0, index($ENV{'STY'}, '.'));
$socket_path = $socket;
$socket_path =~ s/^.+\d+ Sockets? in ([^\n]+)\.\n.+$/$1/s;
+ $socket_name = $socket;
+ $socket_name =~ s/^.+?($socket_pid\.\S+).+$/$1/s;
if (length($socket_path) != length($socket)) {
# only activate, if string length is different
# (to make sure, we really got a dir name)
diff --git a/scripts/slack_emoji.pl b/scripts/slack_emoji.pl
new file mode 100644
index 0000000..e94cec5
--- /dev/null
+++ b/scripts/slack_emoji.pl
@@ -0,0 +1,50 @@
+# slack_emoji.pl
+# This script converts slack emoji to smileys.
+
+use strict;
+use warnings;
+use vars qw($VERSION %IRSSI);
+
+use Irssi;
+$VERSION = '0.03';
+%IRSSI = (
+ authors=> 'Lars Djerf',
+ contact=> 'lars.djerf@gmail.com',
+ name=> 'slack_emoji',
+ description=> 'This script converts Slack emoji to smileys.',
+ license=> 'GPLv3',
+ );
+
+my %emoji = ('smile' => ':)',
+ 'simple_smile' => ':)',
+ 'smiley' => ':-)',
+ 'grin' => ':D',
+ 'wink' => ';)',
+ 'smirk' => ';)',
+ 'blush' => ':$',
+ 'stuck_out_tongue' => ':P',
+ 'stuck_out_tongue_winking_eye' => ';P',
+ 'stuck_out_tongue_closed_eyes' => '',
+ 'disappointed' => ':(',
+ 'astonished' => ':O',
+ 'open_mouth' => ':O',
+ 'heart' => '<3',
+ 'broken_heart' => '</3',
+ 'thumb' => '*thumbs-up*',
+ 'thumbsup' => '*thumbs-up*',
+ 'confused' => ':S');
+
+sub event_message ($$$) {
+ my ($server, $msg, @rest) = @_;
+ my @matches = ($msg =~ /\:(\w+)\:/g);
+ foreach (@matches) {
+ if ($emoji{$_}) {
+ my $smiley = $emoji{$_};
+ $msg =~ s/\:$_\:/$smiley/;
+ }
+ }
+ Irssi::signal_continue($server, $msg, @rest);
+}
+
+Irssi::signal_add_first('message public', 'event_message');
+Irssi::signal_add_first('message private', 'event_message');
diff --git a/scripts/trackbar.pl b/scripts/trackbar.pl
index 7123330..8f38a52 100644
--- a/scripts/trackbar.pl
+++ b/scripts/trackbar.pl
@@ -1,4 +1,22 @@
# trackbar.pl
+#
+# Track what you read last when switching to a window.
+#
+# Copyright (C) 2003 Peter Leurs
+#
+# 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.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# This little script will do just one thing: it will draw a line each time you
# switch away from a window. This way, you always know just upto where you've
@@ -10,27 +28,46 @@
# The script works right out of the box, but if you want you can change
# the working by /set'ing the following variables:
#
-# trackbar_string The characters to repeat to draw the bar
-# trackbar_style The style for the bar, %r is red for example
-# See formats.txt that came with irssi
+# trackbar_string The characters to repeat to draw the bar
+# "---" => U+2500 => a line
+# "===" => U+2550 => a double line
+# "___" => U+2501 => a wide line
+# "# #" => U+25ad.U+0020 => a white rectangle and a space
+# trackbar_style The style for the bar, %r is red for example
+# See formats.txt that came with irssi
+# trackbar_hide_windows Comma seperated list of window names where the
+# trackbar should not be drawn.
+# trackbar_timestamp Prints a timestamp at the start of the bar
+# trackbar_timestamp_styled When enabled, the timestamp respects
+# trackbar_style
#
-# /mark is a command that will redraw the line at the bottom. However! This
-# requires irssi version after 20021228. otherwise you'll get the error
-# redraw: unknown command, and your screen is all goofed up :)
+# /tb or /tb scroll is a command that will scroll to trackbar.
#
-# /upgrade & buf.pl notice: This version tries to remove the trackbars before
-# the upgrade is done, so buf.pl does not restore them, as they are not removeable
-# afterwards by trackbar. Unfortiounatly, to make this work, trackbar and buf.pl
-# need to be loaded in a specific order. Please experiment to see which order works
-# for you (strangely, it differs from configuration to configuration, something I will
-# try to fix in a next version)
+# /tb mark is a command that will redraw the line at the bottom. However!
+# This requires irssi version after 20021228. otherwise you'll get the
+# error redraw: unknown command, and your screen is all goofed up :)
+#
+# /upgrade & buf.pl notice: This version tries to remove the trackbars
+# before the upgrade is done, so buf.pl does not restore them, as they are
+# not removeable afterwards by trackbar. Unfortunately, to make this work,
+# trackbar and buf.pl need to be loaded in a specific order. Please
+# experiment to see which order works for you (strangely, it differs from
+# configuration to configuration, something I will try to fix in a next
+# version)
#
# Authors:
# - Main maintainer & author: Peter 'kinlo' Leurs
# - Many thanks to Timo 'cras' Sirainen for placing me on my way
# - on-upgrade-remove-line patch by Uwe Dudenhoeffer
+# - trackbar resizing by Michiel Holtkamp (02 Jul 2012)
+# - scroll to trackbar, window excludes, and timestamp options by Nico R.
+# Wohlgemuth (22 Sep 2012)
#
# Version history:
+# 1.7: - Added /tb scroll, trackbar_hide_windows, trackbar_timestamp_timestamp
+# and trackbar_timestamp_styled
+# 1.6: - Work around Irssi resize bug, please do /upgrade! (see below)
+# 1.5: - Resize trackbars in all windows when terminal is resized
# 1.4: - Changed our's by my's so the irssi script header is valid
# - Removed utf-8 support. In theory, the script should work w/o any
# problems for utf-8, just set trackbar_string to a valid utf-8 character
@@ -47,65 +84,93 @@
# 1.1: - Fixed bug when closing window
# 1.0: - Initial release
#
-#
-# Call for help!
-#
-# There is a trackbar version 2.0 that properly handles resizes and immediate config change
-# activation. However, there is/are some bug(s) in irssi's main buffer/window code that causes
-# irssi to 'forget' lines, which is ofcourse completly unaccepteable. I haven't found the time
-# nor do I know the irssi's internals enough to find and fix this bug, if you want to help, please
-# contact me, I'll give you a copy of the 2.0 version that will immediatly show you the problems.
+# Contacts
+# https://github.com/mjholtkamp/irssi-trackbar
#
# Known bugs:
# - if you /clear a window, it will be uncleared when returning to the window
-# - UTF-8 characters in the trackbar_string doesnt work. This is an irssi bug.
-# - if you resize your irssi (in xterm or so) the bar is not resized
# - changing the trackbar style is only visible after returning to a window
-# however, changing style/resize takes in effect after you left the window.
+# however, changing style/resize takes in effect after you left the window.
#
# Whishlist/todo:
# - instead of drawing a line, just invert timestamp or something,
# to save a line (but I don't think this is possible with current irssi)
-# - some pageup keybinding possibility, to scroll up upto the trackbar
# - <@coekie> kinlo: if i switch to another window, in another split window, i
# want the trackbar to go down in the previouswindow in that splitwindow :)
# - < bob_2> anyway to clear the line once the window is read?
# - < elho> kinlo: wishlist item: a string that gets prepended to the repeating pattern
-# - < elho> an option to still have the timestamp in front of the bar
-# - < elho> oh and an option to not draw it in the status window :P
#
# BTW: when you have feature requests, mailing a patch that works is the fastest way
# to get it added :p
+# IRSSI RESIZE BUG:
+# when resizing from a larger window to a smaller one, the width of the
+# trackbar causes some lines at the bottom not to be shown. This only happens
+# if the trackbar was not the last line. This glitch can be 'fixed' by
+# resetting the trackbar to the last line (e.g. by switching to another window
+# and back) and then resize twice (e.g. to a bigger size and back). Of course,
+# this is not convenient for the user.
+# This script works around this problem by printing not one, but two lines and
+# then removing the second line. My guess is that irssi does something to the
+# previous line (or the line cache) whenever a line is 'completed' (i.e. the
+# EOL is sent). When only one line is printed, it is not 'completed', but when
+# printing the second line, the first line is 'completed'. The second line is
+# still not completed, but since we delete it straight away, it doesn't matter.
+#
+# Some effects from older versions (<1.6) of trackbar.pl can still screw up your
+# buffer so we recommend to restart your irssi, or do an "/upgrade". After
+# installing this version of trackbar.pl
+
use strict;
use 5.6.1;
use Irssi;
use Irssi::TextUI;
+use POSIX qw(strftime);
+use utf8;
-my $VERSION = "1.4";
+my $VERSION = "1.7";
my %IRSSI = (
- authors => "Peter 'kinlo' Leurs",
- contact => "peter\@pfoe.be",
+ authors => "Peter 'kinlo' Leurs, Uwe Dudenhoeffer, " .
+ "Michiel Holtkamp, Nico R. Wohlgemuth",
+ contact => "irssi-trackbar\@supermind.nl",
name => "trackbar",
description => "Shows a bar where you've last read a window",
license => "GPLv2",
- url => "http://www.pfoe.be/~peter/trackbar/",
- changed => "Thu Feb 20 16:18:08 2003",
+ url => "http://github.com/mjholtkamp/irssi-trackbar/",
+ changed => "Tue, 22 Sep 2012 14:33:31 +0000",
);
my %config;
+my $screen_resizing = 0; # terminal is being resized
+
+# This could be '(status)' if you want to hide the status window
+Irssi::settings_add_str('trackbar', 'trackbar_hide_windows' => '');
+$config{'trackbar_hide_windows'} = Irssi::settings_get_str('trackbar_hide_windows');
+
Irssi::settings_add_str('trackbar', 'trackbar_string' => '-');
$config{'trackbar_string'} = Irssi::settings_get_str('trackbar_string');
Irssi::settings_add_str('trackbar', 'trackbar_style' => '%K');
$config{'trackbar_style'} = Irssi::settings_get_str('trackbar_style');
+Irssi::settings_add_bool('trackbar', 'trackbar_timestamp' => 0);
+$config{'trackbar_timestamp'} = Irssi::settings_get_bool('trackbar_timestamp');
+
+Irssi::settings_add_bool('trackbar', 'trackbar_timestamp_styled' => 1);
+$config{'trackbar_timestamp_styled'} = Irssi::settings_get_bool('trackbar_timestamp_styled');
+
+$config{'timestamp_format'} = Irssi::settings_get_str('timestamp_format');
+
Irssi::signal_add(
'setup changed' => sub {
$config{'trackbar_string'} = Irssi::settings_get_str('trackbar_string');
$config{'trackbar_style'} = Irssi::settings_get_str('trackbar_style');
+ $config{'trackbar_hide_windows'} = Irssi::settings_get_str('trackbar_hide_windows');
+ $config{'trackbar_timestamp'} = Irssi::settings_get_bool('trackbar_timestamp');
+ $config{'trackbar_timestamp_styled'} = Irssi::settings_get_bool('trackbar_timestamp_styled');
+ $config{'timestamp_format'} = Irssi::settings_get_str('timestamp_format');
if ($config{'trackbar_style'} =~ /(?<!%)[^%]|%%|%$/) {
Irssi::print(
"trackbar: %RWarning!%n 'trackbar_style' seems to contain "
@@ -119,7 +184,12 @@ Irssi::signal_add(
'window changed' => sub {
my (undef, $oldwindow) = @_;
- if ($oldwindow) {
+ my @hidden = split(',', $config{'trackbar_hide_windows'});
+
+ # remove whitespace around window names
+ s{^\s+|\s+$}{}g foreach @hidden;
+
+ if ($oldwindow && !($oldwindow->{'name'} ~~ @hidden)) {
my $line = $oldwindow->view()->get_bookmark('trackbar');
$oldwindow->view()->remove_line($line) if defined $line;
$oldwindow->print(line($oldwindow->{'width'}), MSGLEVEL_NEVER);
@@ -128,62 +198,201 @@ Irssi::signal_add(
}
);
+# terminal resize code inspired on nicklist.pl
+sub sig_terminal_resized {
+ if ($screen_resizing) {
+ # prevent multiple resize_trackbars from running
+ return;
+ }
+ $screen_resizing = 1;
+ Irssi::timeout_add_once(10,\&resize_trackbars,[]);
+}
+
+sub resize_trackbars {
+ my $active_win = Irssi::active_win();
+ for my $window (Irssi::windows) {
+ next unless defined $window;
+ my $line = $window->view()->get_bookmark('trackbar');
+ next unless defined $line;
+
+ # first add new trackbar line, then remove the old one. For some reason
+ # this works better than removing the old one, then adding a new one
+ $window->print_after($line, MSGLEVEL_NEVER, line($window->{'width'}));
+ my $next = $line->next();
+ $window->view()->set_bookmark('trackbar', $next);
+ $window->view()->remove_line($line);
+
+ # This hack exists to work around a bug: see IRSSI RESIZE BUG above.
+ # Add a line after the trackbar and delete it immediately
+ $window->print_after($next, MSGLEVEL_NEVER, line(1));
+ $window->view()->remove_line($next->next);
+ }
+ $active_win->view()->redraw();
+ $screen_resizing = 0;
+}
+
+Irssi::signal_add('terminal resized' => \&sig_terminal_resized);
+
sub line {
my $width = shift;
my $string = $config{'trackbar_string'};
- $string = '-' unless defined $string;
- # There is a bug in irssi's utf-8 handling on config file settings, as you
+ my $tslen = 0;
+
+ if ($config{'trackbar_timestamp'}) {
+ $tslen = int(1 + length $config{'timestamp_format'});
+ }
+
+ if (!defined($string) || $string eq '') {
+ $string = '-';
+ }
+
+ # There is a bug in (irssi's) utf-8 handling on config file settings, as you
# can reproduce/see yourself by the following code sniplet:
#
# my $quake = pack 'U*', 8364; # EUR symbol
# Irssi::settings_add_str 'temp', 'temp_foo' => $quake;
- # Irssi::print length $quake;
- # # prints 1
- # Irssi::print length Irssi::settings_get_str 'temp_foo';
- # # prints 3
- #
- #
- # Trackbar used to have a workaround, but on recent versions of perl/irssi
- # it does no longer work. Therefore, if you want your trackbar to contain
- # unicode characters, uncomment the line below for a nice full line, or set
- # the string to whatever char you want.
+ # $a= length($quake);
+ # # $a => 1
+ # $a= length(Irssi::settings_get_str 'temp_foo');
+ # # $a => 3
+ # $a= utf8::is_utf8(Irssi::settings_get_str 'temp_foo');
+ # # $a => false
- # $string = pack('U*', 0x2500);
+ utf8::decode($string);
+ if ($string =~ m/---/) {
+ $string = pack('U*', 0x2500);
+ }
- my $length = length $string;
+ if ($string =~ m/===/) {
+ $string = pack('U*', 0x2550);
+ }
- if ($length == 0) {
- $string = '-';
- $length = 1;
- }
+ if ($string =~ m/___/) {
+ $string = pack('U*', 0x2501);
+ }
- my $times = $width / $length;
+ if ($string =~ m/# #/) {
+ $string = pack('U*', 0x25ad)." ";
+ }
+
+ my $length = length $string;
+
+ my $times = $width / $length - $tslen;
$times = int(1 + $times) if $times != int($times);
$string =~ s/%/%%/g;
- return $config{'trackbar_style'} . substr($string x $times, 0, $width);
+
+ if ($tslen) {
+ # why $config{'timestamp_format'} won't work here?
+ my $ts = strftime(Irssi::settings_get_str('timestamp_format')." ", localtime);
+
+ if ($config{'trackbar_timestamp_styled'}) {
+ return $config{'trackbar_style'} . $ts . substr($string x $times, 0, $width);
+ } else {
+ return $ts . $config{'trackbar_style'} . substr($string x $times, 0, $width);
+ }
+ } else {
+ return $config{'trackbar_style'} . substr($string x $times, 0, $width);
+ }
}
# Remove trackbars on upgrade - but this doesn't really work if the scripts are not loaded in the correct order... watch out!
-Irssi::signal_add_first( 'session save' => sub {
- for my $window (Irssi::windows) {
+Irssi::signal_add_first('session save' => sub {
+ for my $window (Irssi::windows) {
next unless defined $window;
my $line = $window->view()->get_bookmark('trackbar');
$window->view()->remove_line($line) if defined $line;
- }
}
+}
);
sub cmd_mark {
my $window = Irssi::active_win();
-# return unless defined $window;
my $line = $window->view()->get_bookmark('trackbar');
$window->view()->remove_line($line) if defined $line;
$window->print(line($window->{'width'}), MSGLEVEL_NEVER);
$window->view()->set_bookmark_bottom('trackbar');
- Irssi::command("redraw");
+ Irssi::active_win()->view()->redraw();
+}
+
+# mark all visible windows with a line
+sub cmd_mark_visual {
+ my $w= Irssi::active_win();
+ my $refs =$w->{refnum};
+ my $refa;
+
+ cmd_mark();
+
+ do {
+ Irssi::command('window down');
+ $w= Irssi::active_win();
+ $refa =$w->{refnum};
+
+ if ($refs != $refa) {
+ cmd_mark();
+ }
+
+ } while ($refs != $refa)
+}
+
+# /tb or /trackbar
+sub cmd_tb {
+ if ($#_ >=0 ) {
+ my $sc = shift @_;
+ $sc =~ s/\s+$//;
+
+ if ($sc eq "mark") {
+ cmd_mark();
+ } elsif ($sc eq "help") {
+ cmd_help("trackbar");
+ } elsif ($sc eq "vmark") {
+ cmd_mark_visual();
+ } else {
+ cmd_scroll();
+ }
+ }
+}
+
+sub cmd_scroll {
+ my $window = Irssi::active_win();
+ my $line = $window->view()->get_bookmark('trackbar');
+ $window->view()->scroll_line($line) if defined $line;
}
-Irssi::command_bind('mark', 'cmd_mark');
+sub cmd_help {
+ my $help = <<HELP;
+/trackbar or /tb
+ /tb mark
+ - Set the trackbar of the current window at the bottom
+ /tb vmark
+ - Set the trackbar on all visible windows
+ /tb scroll
+ - Scroll to where the trackbar is right now
+ /tb help
+ - this help
+ /tb
+ - Same as /tb scroll
+HELP
+ if ($_[0] =~ m/^tb/ or $_[0] =~ m/^trackbar/ ) {
+ Irssi::print($help, MSGLEVEL_CLIENTCRAP);
+ Irssi::signal_stop;
+ }
+}
+
+Irssi::command_bind('tb', 'cmd_tb');
+Irssi::command_bind('tb help', 'cmd_tb');
+Irssi::command_bind('tb mark', 'cmd_tb');
+Irssi::command_bind('tb scroll', 'cmd_tb');
+Irssi::command_bind('tb vmark', 'cmd_tb');
+
+Irssi::command_bind('trackbar', 'cmd_tb');
+Irssi::command_bind('trackbar help', 'cmd_tb');
+Irssi::command_bind('trackbar mark', 'cmd_tb');
+Irssi::command_bind('trackbar scroll', 'cmd_tb');
+Irssi::command_bind('trackbar vmark', 'cmd_tb');
+
+Irssi::command_bind('mark', 'cmd_mark');
+#Irssi::command_bind('scroll', 'cmd_scroll');
+Irssi::command_bind('help', 'cmd_help');