diff options
| author | wilk | 2017-03-11 21:37:51 +0100 |
|---|---|---|
| committer | GitHub | 2017-03-11 21:37:51 +0100 |
| commit | ddf111c5a04753981ffcddc9af1f16608b2518cc (patch) | |
| tree | 029c3f0a6c34eb008c0087eb5cda7b90b4c23d87 | |
| parent | ba002c7c1711c2ecd8228f09bc12928d53e82799 (diff) | |
| parent | 7d56ba19ec8048a9135aab37aac0d337224ed38b (diff) | |
| download | scripts.irssi.org-ddf111c5a04753981ffcddc9af1f16608b2518cc.tar.bz2 | |
Merge pull request #3 from wilkowy/master
Resync with master.
31 files changed, 2725 insertions, 651 deletions
diff --git a/_data/scripts.yaml b/_data/scripts.yaml index 4135141..512e454 100644 --- a/_data/scripts.yaml +++ b/_data/scripts.yaml @@ -99,11 +99,11 @@ description: 'Adds a permanent advanced window list on the right or in a status bar.' filename: adv_windowlist.pl license: 'GNU GPLv2 or later' - modified: '2016-02-15 11:38:04' + modified: '2016-11-01 17:15:32' modules: Text::CharWidth name: adv_windowlist url: http://anti.teamidiot.de/ - version: '1.2' + version: '1.3' - authors: BC-bd contact: bd@bc-bd.org @@ -230,10 +230,10 @@ description: 'ASpell spellchecking system for Irssi' filename: aspell.pl license: MIT - modified: '2015-11-16 19:36:52' + modified: '2016-10-06 17:55:58' modules: Text::Aspell name: aspell - version: 1.6.1 + version: 1.6.2 - authors: 'Philipp Haegi' commands: rotate_dict @@ -837,9 +837,9 @@ description: 'Disconnect from server if SASL authentication fails.' filename: cap_sasl_fail.pl license: 'GNU GPLv2 or later' - modified: '2016-03-24 11:01:05' + modified: '2017-01-16 16:43:50' name: cap_sasl_fail - version: '2.0' + version: '2.1' - authors: ZaMz0n commands: cddb @@ -873,15 +873,15 @@ url: http://pieter-bas.ijdens.com/irssi/ version: 1.0.0 - - authors: 'BC-bd, Veli' - contact: 'bd@bc-bd.org, veli@piipiip.net' + authors: BC-bd + contact: bd@bc-bd.org description: 'Adds new powerful and customizable [Act: ...] item (chanelnames,modes,alias). Lets you give alias characters to windows so that you can select those with meta-<char>' filename: chanact.pl license: 'GNU GPLv2 or later' - modified: '2016-04-25 18:46:30' + modified: '2017-02-13 17:21:07' name: chanact - url: https://bc-bd.org/svn/repos/irssi/chanact - version: 0.5.15 + url: http://bc-bd.org/blog/irssi/ + version: 0.6.0 - authors: "Joern 'Wulf' Heissler" contact: wulf@wulf.eu.org @@ -1068,8 +1068,9 @@ description: 'kicking users for using colors or blinks' filename: colorkick.pl license: 'public domain' - modified: '2014-10-17 20:34:00' + modified: '2017-03-07 22:28:22' name: colorkick + version: '0.1' - authors: "Timo 'cras' Sirainen" contact: tss@iki.fi @@ -1167,6 +1168,15 @@ url: http://www.krukowiecki.net/code/irssi/ version: '0.12' - + authors: 'martin f. krafft' + contact: madduck@madduck.net + description: 'allows per-channel control over activity indication' + filename: ctrlact.pl + license: MIT + modified: '2017-02-24 07:41:29' + name: ctrlact + version: '1.2' +- authors: "Maciek 'fahren' Freudenheim" contact: fahren@bochnia.pl description: 'Usage: /CWHO [-a | -l | -o | -v ] [ mask ]' @@ -1242,8 +1252,9 @@ description: "/dccself ip port, starts a dcc chat with yourself on that \n\t host/port, best used with /set dcc_autochat_masks." filename: dccself.pl license: GPL - modified: '2008-05-17 17:39:11' + modified: '2017-03-05 13:58:24' name: dccself + version: '0.1' - authors: "Matti 'qvr' Hiljanen" contact: matti\@hiljanen.com @@ -1291,10 +1302,10 @@ description: 'Sends notification using the Desktop Notifications Specification.' filename: desktop-notify.pl license: 'GPL v3+' - modified: '2016-08-04 19:09:35' + modified: '2017-01-23 21:52:29' modules: 'Glib::Object::Introspection HTML::Entities' name: desktop-notify - version: 1.0.0 + version: 1.0.1 - authors: 'Jochem Meyers' contact: jochem.meyers@gmail.com @@ -1759,9 +1770,9 @@ description: 'Implements /go command that activates a window given a name/partial name. It features a nice completion.' filename: go.pl license: 'GPLv2 or later' - modified: '2014-10-19 15:12:04' + modified: '2017-02-02 02:40:44' name: 'go to window' - version: '1.01' + version: '1.1' - authors: cxreg contact: cxreg@pobox.com @@ -1939,10 +1950,20 @@ description: 'Print hilighted messages to window named "hilight"' filename: hilightwin.pl license: 'Public Domain' - modified: '2015-11-07 14:09:15' + modified: '2017-02-10 17:59:58' name: hilightwin url: http://irssi.org/ - version: '0.04' + version: '0.05' +- + authors: 'Stefan Heinemann' + contact: stefan.heinemann@codedump.ch + description: 'Simple script that highlights URL' + filename: hilite_url.pl + license: GPL + modified: '2017-01-12 12:37:37' + name: 'hilite url' + url: http://senseless.codedump.ch + version: '0.1' - authors: 'John Morrissey' contact: jwm@horde.net @@ -2024,6 +2045,15 @@ url: http://www.musicpd.org version: 0.0.0n - + authors: 'Isaac Good' + contact: 'irssi@isaacgood.com; irc.freenode.net/yitz' + description: 'Automatically IDENTIFY when prompted' + filename: ident.pl + license: MIT + modified: '2016-12-06 18:45:34' + name: ident + version: '1.0' +- authors: 'Eric Jansen' contact: chaos@sorcery.net description: 'MD5 NickServ identification script for SorceryNet' @@ -2143,10 +2173,10 @@ description: 'This script will join a channel if somebody invites you to it.' filename: invitejoin.pl license: 'Public Domain' - modified: '2004-04-11 12:38:18' + modified: '2017-01-17 20:26:41' name: invitejoin.pl - url: http://irssi.hauwaerts.be/invitejoin.pl - version: '0.01' + url: https://github.com/irssi/scripts.irssi.org/blob/master/scripts/invitejoin.pl + version: '0.02' - authors: xlony contact: anderfdez@yahoo.es @@ -2158,6 +2188,26 @@ name: IPupdate version: '1.2' - + authors: wilk + contact: http://mail.quizpl.net + description: 'irssi quiz script' + filename: iquiz.pl + license: 'GNU GPL v3 or any later version' + modified: '2016-10-03 18:26:38' + name: iQuiz + url: http://iquiz.quizpl.net + version: '160919' +- + authors: wilk + contact: http://mail.quizpl.net + description: 'irssi quiz script' + filename: iquiz_en.pl + license: 'GNU GPL v3 or any later version' + modified: '2016-10-03 18:26:38' + name: iQuiz + url: http://iquiz.quizpl.net + version: 160919_en +- authors: DonRumata commands: none contact: rumata@dragons.ru @@ -2532,6 +2582,15 @@ name: listen version: '0.2' - + authors: 'Isaac Good' + contact: irssi@isaacgood.com + filename: listsort.pl + license: BSD + modified: '2016-12-07 11:32:54' + name: listsort + url: https://github.com/IsaacG/irssi-scripts + version: '0.1' +- authors: aki contact: aki@evilbsd.info description: 'display a loadavg statusbar item using vm.loadavg mib or /proc/loadavg' @@ -2578,10 +2637,10 @@ description: "compress logfiles then they're rotated, modified from original logcompress.pl to use perl modules instead" filename: logcompress_perl.pl license: 'Public Domain' - modified: '2016-01-31 01:51:39' + modified: '2017-01-07 11:52:46' name: logcompress_perl url: http://irssi.org/ - version: '0.01' + version: '0.02' - authors: ferret commands: 'logtail, logview' @@ -2747,10 +2806,10 @@ description: 'statusbar item that shows users and limit info in channels' filename: mh_sbuserinfo.pl license: BSD - modified: '2016-01-23 00:22:49' + modified: '2016-11-07 14:57:43' name: mh_sbuserinfo url: 'http://scripts.irssi.org / https://github.com/mh-source/irssi-scripts' - version: '1.04' + version: '1.05' - authors: 'Michael Hansen' contact: 'mh on IRCnet #help' @@ -3142,10 +3201,10 @@ description: 'This script will authorize you into NickServ.' filename: nickserv.pl license: 'GNU General Public License' - modified: '2016-04-06 16:03:28' + modified: '2017-01-17 00:18:42' name: nickserv.pl - url: http://irssi.hauwaerts.be/nickserv.pl - version: '1.10' + url: https://github.com/irssi/scripts.irssi.org/blob/master/scripts/nickserv.pl + version: '1.11' - authors: BC-bd contact: bd@bc-bd.org @@ -3461,9 +3520,9 @@ description: 'Notifies people if they send you a private message or a DCC chat offer while you are away; runs a shell command configurable via /set if they page you' filename: pager.pl license: BSD - modified: '2014-10-19 11:54:16' + modified: '2017-03-06 20:58:29' name: pager - version: '1.1' + version: '1.2' - authors: fprintf contact: fprintf@github.com @@ -3543,6 +3602,15 @@ url: http://wouter.coekaerts.be/irssi/ version: '1.1' - + authors: aquanight + contact: aquanight@gmail.com + description: 'Quickly create commands from short perl blocks' + filename: perlalias.pl + license: 'public domain' + modified: '2017-02-19 12:53:47' + name: perlalias + version: '1.2' +- authors: 'Adam Duck' contact: duck@cs.uni-frankfurt.de description: 'does CTCP SOUNDs and other similar things.' @@ -3570,9 +3638,9 @@ description: 'Postpones messages sent to a splitted user and resends them when the nick rejoins' filename: postpone.pl license: GPLv2 - modified: '2008-05-17 17:39:11' + modified: '2017-02-04 02:11:54' name: postpone - version: '20030208' + version: '20170204' - authors: "Maciek Freudenheim, Marco d'Itri" contact: 'fahren@bochnia.pl, md@linux.it' @@ -3584,6 +3652,15 @@ url: http://www.linux.it/~md/irssi/ version: '20020128' - + authors: 'martin f. krafft' + contact: madduck@madduck.net + description: 'hooks into every signal and writes the information provided to a file' + filename: print_signals.pl + license: MIT + modified: '2017-02-03 11:47:17' + name: 'print signals debugger' + version: '1.0' +- authors: 'Cyprien Debu' contact: frey@notk.org description: 'Gets new mails from procmail.log file' @@ -3751,13 +3828,14 @@ url: http://irssi.dgl.cx/ version: '1' - - authors: 'Isaac G' - contact: irssi@isaac.otherinbox.com + authors: 'Isaac Good' + contact: irssi@isaacgood.com description: 'Reordering windows based on a textfile.' filename: reorder.pl license: GPL - modified: '2010-02-12 22:42:13' + modified: '2016-12-06 18:47:28' name: reorder + version: '1.0' - authors: BC-bd contact: bd@bc-bd.org @@ -3853,9 +3931,9 @@ description: 'Replaces :emote_name: text in your sent messages into pre-defined emotes (unicode mostly).' filename: rud_emotes.pl license: GPLv3 - modified: '2016-09-17 10:03:31' + modified: '2016-11-07 15:43:52' name: 'emotes script' - version: '1.00' + version: '1.10' - authors: "Johan \"Ion\" Kiviniemi, idea taken from Riku Voipio's sana.pl" contact: 'ion at hassers.org' @@ -4459,11 +4537,11 @@ description: 'Shows a bar where you have last read a window.' filename: trackbar22.pl license: 'GNU General Public License' - modified: '2015-11-16 19:36:52' + modified: '2017-01-09 14:35:07' modules: Text::CharWidth name: trackbar url: http://www.pfoe.be/~peter/trackbar/ - version: '2.2' + version: '2.3' - authors: 'Timo Sirainen' contact: tss@iki.fi @@ -4480,8 +4558,9 @@ description: translitiratar filename: translit.pl license: GPL - modified: '2008-05-17 17:39:11' + modified: '2017-03-05 14:29:01' name: translit + version: '0.1' - authors: 'Wouter Coekaerts' contact: wouter@coekaerts.be @@ -4937,10 +5016,10 @@ description: 'XDCC Autoget, for automated searching and downloading of xdcc packs' filename: xdcc_autoget.pl license: 'BeerWare Version 42' - modified: '2016-02-09 01:27:46' + modified: '2016-10-26 19:23:08' modules: 'File::HomeDir Try::Tiny' name: autoget - version: '2.0' + version: '2.1' - authors: "Stefan 'tommie' Tomanek, Obfuscoder" commands: xdccget diff --git a/_testing/config.yml b/_testing/config.yml index 2b96a25..8764417 100644 --- a/_testing/config.yml +++ b/_testing/config.yml @@ -36,12 +36,10 @@ cpan: whitelist: - amaroknp - babelirc + - cap_sasl_fail - cap_sasl - - cgrep - - colorkick - connectcmd - dau - - dccself - dnsspam - hddtemp - hitcount @@ -63,19 +61,16 @@ whitelist: - 'on' - osd - page-c0ffee - - pager - query - quizgr - quizmaster-fr - quizmaster - quiz - randaway - - reorder - scroller - stocks - sysinfoplus - topicsed - - translit - tvmusor - wordcompletition - xetra diff --git a/assets/css/style.css b/assets/css/style.css index fe72819..302d311 100644 --- a/assets/css/style.css +++ b/assets/css/style.css @@ -23,3 +23,12 @@ table.sortable thead { table.sortable thead th:hover { opacity: 0.8; } + +div.instructions input { + opacity: 0; + position: fixed; +} +div.instructions label { display: inline; } +input#manual-instructions:checked ~ dl.automatic-instructions, +input#automatic-instructions:checked ~ dl.manual-instructions +{ display: none; } diff --git a/assets/js/votes.js b/assets/js/votes.js index 4fb585d..2fa9097 100644 --- a/assets/js/votes.js +++ b/assets/js/votes.js @@ -1,75 +1,153 @@ (function(document, $){ 'use strict'; var jsonpRe = /^\/\*[\s\S]*?\*\/jsonp\(([\s\S]*)\)$/m; + var ghLimits = {search: {}, core: {}}; + var stopId = 0; + var queue = {search: [], core: []}; + var todo = 1; - function requestAll(start) { - $.ajax({ + function requestLater(what, how, arg) { + var when = rateTimeout(what); + if (when >= 0) { + var empty = queue[what].length == 0; + queue[what].push([how, arg]); + if (empty) window.setTimeout(function(){reQueue(what);}, when); + } else { + ghLimits[what].remaining--; + how(arg); + } + } + + function reQueue(what) { + limitsThen(what, function(q) { + q.forEach(function(e) { + requestLater(what, e[0], e[1]); + }); + }, queue[what].splice(0, queue[what].length)); + } + + function signalDone() { + if (!todo) $("#th-votes").html("Votes"); + } + + function _jsonpToJson(dta, typ) { + if (typ == "json") { + return dta.replace(jsonpRe, "$1"); + } + return dta; + } + + function jj(url) { + return $.ajax({ accepts: { json: 'application/vnd.github.squirrel-girl-preview' }, dataType: 'json', - url: start, + url: url + (url.indexOf('callback=') === -1 + ? (url.indexOf('?') === -1 ? '?' : ';') + 'callback=jsonp' + : ''), jsonp: false, jsonpCallback: 'jsonp', - dataFilter: function(dta, typ) { - if (typ == "json") { - return dta.replace(jsonpRe, "$1"); - } - return dta; - } - }) - .done(function(r) { - var remaining = r.meta['X-RateLimit-Remaining']; - var rateReset = r.meta['X-RateLimit-Reset']; - var timeOut = 0; - var hasMore = false; - if (remaining < 10) { - timeOut = 1000 + rateReset * 1000 - (new Date() / 1); - } - if (timeOut < 0) timeOut = 0; - if (r.meta.Link) { - r.meta.Link.forEach(function(l) { - if (l[1].rel == "next") { - window.setTimeout(function(){requestAll(l[0]);}, timeOut); - hasMore = true; - return; - } - }); - } - if (timeOut > 0) { - timeOut += 1000; + dataFilter: _jsonpToJson + }); + } + + function searchVotes(url) { + var start = url.indexOf("//") !== -1 ? url + : 'https://api.github.com/search/issues?q=votes+in:title+state:closed+type:issue+' + + 'repo:' + url + ';sort=updated'; + jj(start).done(function(r) { + var hasMore = fetchNext('search', r.meta, searchVotes); + if (hasMore) todo++; + r.data.items.forEach(function(e) { + if (stopId && e.number > stopId) return; + if (e.title != "votes") return; + if (e.locked) { stopId = e.number; return; } + todo++; + requestLater('core', requestComments, e.comments_url); + todo++; + requestLater('core', requestComments, e.comments_url + '?page=2'); + todo++; + requestLater('core', requestComments, e.comments_url + '?page=3'); + //todo++; + //requestLater('core', requestComments, e.comments_url + '?page=4'); + }); + todo--; + signalDone(); + }); + } + + function rateTimeout(what) { + if ($.isEmptyObject(ghLimits[what])) return -1; + + var remaining = ghLimits[what].remaining; + var rateReset = ghLimits[what].reset; + var limit = ghLimits[what].limit; + + var timeOut = -1; + if (remaining < Math.log(limit) + Math.sqrt(limit)) { + timeOut = 1000 + rateReset * 1000 - (new Date() / 1); + if (timeOut < -1) timeOut = 0; + } + return timeOut; + } + + function updateLimits(what, meta) { + ghLimits[what].remaining = meta['X-RateLimit-Remaining']; + ghLimits[what].reset = meta['X-RateLimit-Reset']; + } + + function fetchNext(what, meta, how) { + var hasMore = false; + updateLimits(what, meta); + if (meta.Link) { + meta.Link.forEach(function(l) { + if (l[1].rel == "next") { + hasMore = true; + requestLater(what, how, l[0]); + return; } + }); + } + return hasMore; + } - r.data.forEach(function(e) { - e.body = e.body.replace(/\r/g, ""); - var redir = e.body.match(/^#(\d+)$/); - if (redir) { - var l = start.replace(/(\/issues\/)\d+(\/comments\?)/, "$1" + redir[1] + "$2").replace(/&.*/, ""); - window.setTimeout(function(){requestAll(l);}, timeOut); - hasMore = true; - return; - } - - var lines = e.body.split("\n"); - var script = lines[0].replace(/[^-a-zA-Z0-9_]/g, "_"); - if (script == "comment") { - script = "adv_windowlist_pl"; - } - var st = "#script-" + script + " .votes"; - var row = $(st); - if (row.length) { - var votes = 1+ e.reactions['+1'] - e.reactions['-1']; - var link = "๏ผ"; - if (e.reactions['heart'] >= votes) { - link = "๐"; - } - row.html( "" + votes ); - - row.append("<span><a data-toggle=\"tooltip\" title=\"vote on github\" href=\"" + e.html_url + "\">"+link+"</a></span>"); - } - }); - if (!hasMore) { - $("#th-votes").html("Votes"); + function requestComments(start) { + jj(start).done(function(r) { + updateLimits('core', r.meta); + if (r.meta.status == 403 && !r.meta['X-RateLimit-RateLimit']) { + requestLater('core', requestComments, start); + return; + } + //var hasMore = fetchNext('core', r.meta, requestComments); + //if (hasMore) todo++; + r.data.some(function(e) { + e.body = e.body.replace(/\r/g, ""); + var lines = e.body.split("\n"); + var redir = e.body.match(/^#(\d+)$/); + if (redir) return true; + var script = lines[0].replace(/^## /, "").replace(/[^-a-zA-Z0-9_]/g, "_"); + var row = $("#script-" + script + " .votes"); + if (row.length) { + var votes = 1+ e.reactions['+1'] - e.reactions['-1']; + var link = "๏ผ"; + if (e.reactions['heart'] >= votes) link = "๐"; + row.html( "" + votes ); + row.append("<span><a data-toggle=\"tooltip\" title=\"vote on github\" href=\"" + + e.html_url + "\">"+link+"</a></span>"); } + return false; }); + todo--; + signalDone(); + }); } - requestAll('https://api.github.com/repos/ailin-nemui/scripts.irssi.org/issues/2/comments?callback=jsonp'); + + function limitsThen(what, how, arg) { + jj('https://api.github.com/rate_limit').done(function(r) { + ghLimits = r.data.resources; + requestLater(what, how, arg); + }); + } + + limitsThen('search', searchVotes, 'ailin-nemui/scripts.irssi.org'); + })(document, $); @@ -10,7 +10,31 @@ layout: default </div> <div class="row"> - <dl> + <div class="instructions"> + <input id="automatic-instructions" type="radio" checked="checked" name="instructions" /> + <input id="manual-instructions" type="radio" name="instructions" /> + <dl class="automatic-instructions"> + <dt>How do I install scripts?</dt> + <dd>In Irssi, do <code>/run scriptassist</code> (only once per session), then + <code>/script install <i>scriptname</i></code> . + + <dt>How do I rerun scripts?</dt> + <dd>Just do <code>/script load <i>scriptname</i></code> .</dd> + + <dt>How do I unload scripts?</dt> + <dd>Just do <code>/script unload <i>scriptname</i></code> .</dd> + + <dt>How do I run scripts automatically at startup?</dt> + <dd>Just do <code>/script autorun <i>scriptname</i></code> .</dd> + + <dt>Scriptassist does not work for me / I want to do it myself?</dt> + <dd><label for="manual-instructions" class="btn-link"> + View manual instructions.</label></dd> + + <dt>How do I submit a script to this page?</dt> + <dd>See information on how to contribute <a href="https://github.com/irssi/scripts.irssi.org">here</a>.</dd> + </dl> + <dl class="manual-instructions"> <dt>How do I run scripts?</dt> <dd>Put them into <code>~/.irssi/scripts/</code> and in irssi do <code>/script load script.pl</code> . There is a default alias for @@ -32,15 +56,17 @@ layout: default <dt>Is there an easy way of managing scripts?</dt> <dd>Try <code>scriptassist.pl</code>, it can update and manage your scripts - as well as install new ones and search the database.</dd> + as well as install new ones and search the database. + <label for="automatic-instructions" class="btn-link"> + View instructions when using scriptassist.pl .</label></dd> <dt>How do I submit a script to this page?</dt> <dd>See information on how to contribute <a href="https://github.com/irssi/scripts.irssi.org">here</a>.</dd> </dl> - + </div> <hr> - <input type="search" class="light-table-filter form-control" data-table="sortable" data-name="q" placeholder="Filter" style="width: 100%"> + <input type="search" class="light-table-filter form-control" data-table="sortable" data-name="q" placeholder="Filter" style="width: 100%" autocorrect="off" spellcheck="false"> <table class="table table-striped table-condensed sortable"> <thead> <tr> @@ -50,7 +76,7 @@ layout: default <th class="sorttable_alpha">Description</th> <th class="sorttable_alpha">Authors</th> <th class="sorttable_alpha">Modified</th> - <th class="sorttable_numeric" id="th-votes">…</th> + <th class="sorttable_numeric" id="th-votes">……</th> </tr> </thead> <tbody> diff --git a/scripts/adv_windowlist.pl b/scripts/adv_windowlist.pl index ee0219b..6285786 100644 --- a/scripts/adv_windowlist.pl +++ b/scripts/adv_windowlist.pl @@ -1,7 +1,7 @@ use strict; use warnings; -our $VERSION = '1.2'; # 762850b0c2c1d5a +our $VERSION = '1.3'; # 463402cffae35e5 our %IRSSI = ( authors => 'Nei', contact => 'Nei @ anti@conference.jabber.teamidiot.de', @@ -1710,8 +1710,13 @@ sub string_LCSS { (sort { length $b <=> length $a } $str =~ /(?=(.+).*\0.*\1)/g)[0] } +# workaround for issue #271 { package Irssi::Nick } +# workaround for issue #572 +@Irssi::UI::Exec::ISA = 'Irssi::Windowitem' + if Irssi::version >= 20140822 && Irssi::version <= 20161101 && !@Irssi::UI::Exec::ISA; + UNITCHECK { package AwlViewer; use strict; @@ -2388,6 +2393,7 @@ UNITCHECK # Changelog # ========= +# 1.3 - workaround for irssi issue #572 # 1.2 - new format to choose abbreviation character # 1.1 - infinite loop on shortening certain window names reported by Kalan # diff --git a/scripts/aspell.pl b/scripts/aspell.pl index b6a254e..71369f3 100644 --- a/scripts/aspell.pl +++ b/scripts/aspell.pl @@ -85,6 +85,7 @@ See README file. use warnings; use strict; use Data::Dumper; +use Encode 'decode'; use Irssi; use Irssi::Irc; use Irssi::TextUI; @@ -107,7 +108,7 @@ if ($@ && $@ =~ m/Can't locate/) { } -our $VERSION = '1.6.1'; +our $VERSION = '1.6.2'; our %IRSSI = ( authors => 'Isaac Good (yitz_), Tom Feist (shabble)', contact => 'irssi@isaacgood.com, shabble+irssi@metavore.org', @@ -306,6 +307,7 @@ sub process_word { } else { print_suggestions(); + highlight_incorrect_word($word_obj); } } else { @@ -391,7 +393,8 @@ sub spellcheck_finish { # stick the cursor at the end of the input line? my $input = _input(); - my $end = length($input); + my $charset = lc Irssi::settings_get_str('term_charset'); + my $end = length(decode $charset=>$input); Irssi::gui_input_set_pos($end); } diff --git a/scripts/cap_sasl_fail.pl b/scripts/cap_sasl_fail.pl index 226bc2c..22d0b79 100644 --- a/scripts/cap_sasl_fail.pl +++ b/scripts/cap_sasl_fail.pl @@ -1,7 +1,7 @@ use strict; use warnings; -our $VERSION = '2.0'; # ed9e98e5d63cfb3 +our $VERSION = '2.1'; # bb62357c61d9e54 our %IRSSI = ( authors => 'Nei', name => 'cap_sasl_fail', @@ -15,8 +15,8 @@ use version; my %disconnect_next; my $irssi_version = qv(Irssi::parse_special('v$J') =~ s/-.*//r); -die sprintf "Support for Irssi v%vd has not been written yet.\n", $irssi_version - if $irssi_version > v0.8.20; +die sprintf "Please use /set sasl_disconnect_on_failure instead of this script.\n" + if $irssi_version >= v1.0.0; Irssi::signal_register({'server sasl fail' => [qw[iobject string]]}); Irssi::signal_add_first('server sasl fail' => 'sasl_fail_failed'); diff --git a/scripts/chanact.pl b/scripts/chanact.pl index ee6ef3c..4a42364 100644 --- a/scripts/chanact.pl +++ b/scripts/chanact.pl @@ -1,20 +1,25 @@ use Irssi 20020101.0001 (); + use strict; -# FIXME use warning; +use warnings; + use Irssi::TextUI; use vars qw($VERSION %IRSSI); -$VERSION = "0.5.15"; +$VERSION = "0.6.0"; %IRSSI = ( - authors => 'BC-bd, Veli', - contact => 'bd@bc-bd.org, veli@piipiip.net', + authors => 'BC-bd', + contact => 'bd@bc-bd.org', name => 'chanact', description => 'Adds new powerful and customizable [Act: ...] item (chanelnames,modes,alias). Lets you give alias characters to windows so that you can select those with meta-<char>', license => 'GNU GPLv2 or later', - url => 'https://bc-bd.org/svn/repos/irssi/chanact' + url => 'http://bc-bd.org/blog/irssi/' ); +# Please send patches / pull requests to the email listed unter contact above +# and not to the irssi/scripts.irssi.org repository on github. + # Adds new powerful and customizable [Act: ...] item (chanelnames,modes,alias). # Lets you give alias characters to windows so that you can select those with # meta-<char>. @@ -27,19 +32,22 @@ $VERSION = "0.5.15"; # Contributors ######### # -# veli@piipiip.net /window_alias code -# qrczak@knm.org.pl chanact_abbreviate_names -# qerub@home.se Extra chanact_show_mode and chanact_chop_status +# veli@piipiip.net original /window_alias code +# qrczak@knm.org.pl chanact_abbreviate_names +# qerub@home.se Extra chanact_show_mode and chanact_chop_status # madduck@madduck.net Better channel aliasing (case-sensitive, cross-network) # chanact_filter_windowlist basis -# Jan 'jast' Krueger <jast@heapsort.de>, 2004-06-22 -# Ivo Timmermans <ivo@o2w.nl> win->{hilight} patch -# Trevor 'tee' Slocum <tslocum@gmail.com> Case-insensitive aliases, bugfix -# +# jast@heapsort.de Updated documentation +# ivo@o2w.nl win->{hilight} patch +# Bazerka base patch for sorting by level change +# updated documentation +# mrtnpaolo@gmail.com rename commands +# tslocum@gmail.com Case-insensitive aliases +# ######### # USAGE ### -# +# # copy the script to ~/.irssi/scripts/ # # In irssi: @@ -61,11 +69,11 @@ $VERSION = "0.5.15"; # aliases to your windows. Go to the window you want to give the alias to # and say: # -# /window_alias <alias char> +# /chanact_window_alias <alias char> # # You can remove the aliases with from an aliased window: # -# /window_unalias +# /chanact_window_unalias # # To see a list of your windows use: # @@ -100,11 +108,11 @@ $VERSION = "0.5.15"; # $H : Start highlightning # $S : Stop highlightning # * example: -# +# # /set chanact_display $H$N:$M.$S$C -# +# # will give you on #irssi.de if you have voice -# +# # [3:+.#irssi.de] # # with '3:+.' highlighted and the channel name printed in regular color @@ -113,12 +121,26 @@ $VERSION = "0.5.15"; # * ON : Aliases are case-sensitive # * OFF : Aliases are case-insensitive # -# Existing aliases must be reapplied after switching to case-insensitive. +# Existing aliases must be reapplied after changing this option +# +# Switching from OFF to ON _after_ aliases have been defined, and +# then redefining or changing an existing alias will leave some +# bindings behind, e.g. +# +# /set chanact_case_sensitive OFF +# /chanact_window_alias x +# +# -> window reachable with meta-x/meta-X +# +# /set chanact_case_sensitive ON +# /chanact_window_alias y +# +# -> window reachable with meta-y/meta-X # # /set chanact_display_alias <string> # as 'chanact_display' but is used if the window has an alias and # 'chanact_show_alias' is set to on. -# +# # /set chanact_show_names <ON|OFF> # * ON : show the channelnames after the number/alias # * OFF : don't show the names @@ -141,7 +163,7 @@ $VERSION = "0.5.15"; # # /set chanact_autorenumber <ON|OFF> # * ON : Move the window automatically to first available slot -# starting from "chanact_renumber_start" when assigning +# starting from "chanact_renumber_start" when assigning # an alias to window. Also moves the window back to a # first available slot from refnum 1 when the window # loses it's alias. @@ -160,7 +182,7 @@ $VERSION = "0.5.15"; # beginning of the channel name. # * example : # To shorten a lot of debian channels: -# +# # /set chanact_remove_prefix deb(ian.(devel-)?)? # # /set chanact_filter <int> @@ -174,7 +196,7 @@ $VERSION = "0.5.15"; # * <string> : space-separated list of windows for which to use # chanact_filter_windowlist_level instead of # chanact_filter. -# +# # Alternatively, an entry can be postfixed with # a comma (',') and the level to use for that # window. @@ -232,15 +254,14 @@ sub expand { # but we dont need to recreate the item every time so we first # check if something has changed and only then we recreate the string # this might just save some cycles -# FIXME implement $get_size_only check, and user $item->{min|max-size} sub chanact { my ($item, $get_size_only) = @_; if ($needRemake) { remake(); } - - $item->default_handler($get_size_only, $actString, undef, 1); + + $item->default_handler($get_size_only, $actString, "", 1); } # build a hash to easily access special levels based on @@ -268,13 +289,13 @@ sub calculate_levels(@) { my %levels; foreach my $win (@windows) { - # FIXME we could use the next statements to weed out entries in - # @windows that we will not need later on !ref($win) && next; my $name = $win->get_active_name; + # skip nameless windows + next unless $name; - if (exists($matches{$name})) { + if ($name && exists($matches{$name})) { $levels{$name} = $matches{$name}; } else { $levels{$name} = $default; @@ -293,7 +314,7 @@ sub calculate_levels(@) { # this is the real creation method sub remake() { my ($afternumber,$finish,$hilight,$mode,$number,$display,@windows); - my $separator = Irssi::settings_get_str('chanact_separator'); + my $separator = Irssi::settings_get_str('chanact_separator'); my $abbrev = Irssi::settings_get_int('chanact_abbreviate_names'); my $remove_prefix = Irssi::settings_get_str('chanact_remove_prefix'); my $remove_hash = Irssi::settings_get_bool('chanact_remove_hash'); @@ -317,6 +338,8 @@ sub remake() { $type = $active->{type} if $active; my $name = $win->get_active_name; + # skip windows without a name + next unless $name; my $filter_level = $type eq 'QUERY' ? $levels{'@QUERIES'} : $levels{$name}; @@ -334,7 +357,7 @@ sub remake() { && $name eq "(status)") { $name = "S"; } - + # check if we should show the mode $mode = ""; if ($type eq "CHANNEL") { @@ -346,7 +369,7 @@ sub remake() { my $nick = $channel->nick_find($server->{nick}); !ref($nick) && next; - + if ($nick->{op}) { $mode = "@"; } elsif ($nick->{voice}) { @@ -377,13 +400,13 @@ sub remake() { $name =~ s/^[&#+!=]//; } - if (Irssi::settings_get_bool('chanact_show_alias') == 1 && + if (Irssi::settings_get_bool('chanact_show_alias') == 1 && $win->{name} =~ /^([a-zA-Z+]):(.+)$/) { $number = "$1"; - $display = Irssi::settings_get_str('chanact_display_alias'); + $display = Irssi::settings_get_str('chanact_display_alias'); } else { $number = $win->{refnum}; - $display = Irssi::settings_get_str('chanact_display'); + $display = Irssi::settings_get_str('chanact_display'); } # fixup { and } in nicks, those are used by irssi themes @@ -396,7 +419,7 @@ sub remake() { if ($actString ne "") { # Remove the last separator $actString =~ s/$separator$//; - + $actString = "{sb ".Irssi::settings_get_str('chanact_header').$actString."}"; } @@ -429,12 +452,33 @@ sub setup_changed { chanactHasChanged(); } +# Remove key binding for current window +sub unbind { + my ($name, $server) = @_; + + # chanact'ified windows have a name like this: X:servertag/name. if we + # can't find anything like this we return and do not unbind nor renumber + # anything + my ($key, $tag) = split(/:/, $name); + return unless $tag; + + ($tag, $name) = split('/', $tag); + return unless (length($key) == 1); + + if (Irssi::settings_get_bool('chanact_case_sensitive')) { + $server->command("/bind -delete meta-$key"); + } else { + $server->command("/bind -delete meta-" . lc($key)); + $server->command("/bind -delete meta-" . uc($key)); + } +} + # Remove alias sub cmd_window_unalias { - my ($data, $server, $witem, $internal) = @_; + my ($data, $server, $witem) = @_; - if ($data ne '' && !$internal) { - Irssi::print("chanact: /window_unalias does not take any ". + if ($data ne '') { + Irssi::print("chanact: /chanact_window_unalias does not take any ". "parameters, Run it in the window you want to unalias"); return; } @@ -442,24 +486,7 @@ sub cmd_window_unalias { my $win = Irssi::active_win(); my $name = Irssi::active_win()->{name}; - # chanact'ified windows have a name like this: X:servertag/name - my ($key, $tag) = split(/:/, $name); - ($tag, $name) = split('/', $tag); - - # remove alias only of we have a single character keybinding, if we - # haven't the name was not set by chanact, so we won't blindly unset - # stuff - if (length($key) == 1) { - if (Irssi::settings_get_bool('chanact_case_sensitive')) { - $server->command("/bind -delete meta-$data"); - } else { - $server->command("/bind -delete meta-" . lc($data)); - $server->command("/bind -delete meta-" . uc($data)); - } - } elsif (!$internal) { - Irssi::print("chanact: could not determine keybinding. ". - "Won't unbind anything"); - } + unbind($name, $server); # set the windowname back to it's old one. We don't bother checking # for a vaild name here, as we want to remove the current one and if @@ -472,7 +499,7 @@ sub cmd_window_unalias { # we are renumbering, so move the window to the lowest available # refnum. my $refnum = 1; - while (Irssi::window_find_refnum($refnum) ne "") { + while (Irssi::window_find_refnum($refnum)) { $refnum++; } @@ -480,14 +507,13 @@ sub cmd_window_unalias { Irssi::print("chanact: moved wintow to refnum $refnum"); } -# function by veli@piipiip.net # Make an alias sub cmd_window_alias { my ($data, $server, $witem) = @_; my $rn_start = Irssi::settings_get_int('chanact_renumber_start'); unless ($data =~ /^[a-zA-Z+]$/) { - Irssi::print("Usage: /window_alias <char>"); + Irssi::print("Usage: /chanact_window_alias <char>"); return; } @@ -508,23 +534,23 @@ sub cmd_window_alias { $winname = $window->{name}; } - cmd_window_unalias($data, $server, $witem, 1); + unbind($window->{name}, $server); my $winnum = $window->{refnum}; - + if (Irssi::settings_get_bool('chanact_autorenumber') == 1 && $window->{refnum} < $rn_start) { my $old_refnum = $window->{refnum}; $winnum = $rn_start; - + # Find the first available slot and move the window - while (Irssi::window_find_refnum($winnum) ne "") { $winnum++; } + while (Irssi::window_find_refnum($winnum)) { $winnum++; } $window->set_refnum($winnum); - + Irssi::print("Moved the window from $old_refnum to $winnum"); } - + my $winserver = $window->{active_server}->{tag}; my $winhandle = "$winserver/$winname"; # cmd_window_unalias relies on a certain format here @@ -543,8 +569,8 @@ sub cmd_window_alias { $needRemake = 1; # Window alias command -Irssi::command_bind('window_alias','cmd_window_alias'); -Irssi::command_bind('window_unalias','cmd_window_unalias'); +Irssi::command_bind('chanact_window_alias','cmd_window_alias'); +Irssi::command_bind('chanact_window_unalias','cmd_window_unalias'); # our config item Irssi::settings_add_str('chanact', 'chanact_display', '$H$N:$M$C$S'); @@ -587,8 +613,15 @@ Irssi::signal_add('nick mode changed', 'chanactHasChanged'); # # Changelog # -# 0.5.15 -# - fixed unbind error when aliasing a previously un-aliased window +# 0.6.0 +# - fixed URL +# - now with 'use warnings' +# - fix cmd_window_unalias call from cmd_window_alias +# - fix Use of uninitialized value $name in hash element warnings +# - return from cmd_window_unalias if the window has no valid +# chanact'ified name +# - rename /window_(un)alias to /chanact_window_(un)alias +# - fix refnum renumber race # - added setting to allow case-insensitive window aliases # # 0.5.14 @@ -645,10 +678,10 @@ Irssi::signal_add('nick mode changed', 'chanactHasChanged'); # # 0.5.6 # - fixed a bug (#1) reported by Wouter Coekaert -# +# # 0.5.5 # - some speedups from David Leadbeater <dgl@dgl.cx> -# +# # # 0.5.4 # - added help for chanact_display_alias @@ -662,7 +695,7 @@ Irssi::signal_add('nick mode changed', 'chanactHasChanged'); # - removed unused chanact_show_name settings (thx to Qerub) # - fixed $mode display # - guarded reference operations to (hopefully) fix errors on server disconnect -# +# # 0.5.1 # - small typo fixed # @@ -670,7 +703,7 @@ Irssi::signal_add('nick mode changed', 'chanactHasChanged'); # - changed chanact_show_mode to chanact_display. reversed changes from # Qerub through that, but kept funcionality. # - removed chanact_color_all since it is no longer needed -# +# # 0.4.3 # - changes by Qerub # + added chanact_show_mode to show the mode just before the channel name diff --git a/scripts/colorkick.pl b/scripts/colorkick.pl index 24b29fd..c28e420 100644 --- a/scripts/colorkick.pl +++ b/scripts/colorkick.pl @@ -13,7 +13,8 @@ use strict; use Irssi; use Irssi::Irc; -use vars %IRSSI; +use vars qw/%IRSSI $VERSION/; +$VERSION='0.1'; %IRSSI = ( authors => "Gabor Nyeki", @@ -22,7 +23,7 @@ use vars %IRSSI; description => "kicking users for using colors or blinks", license => "public domain", written => "Thu Dec 26 00:22:54 CET 2002", - changed => "Fri Jan 2 03:43:10 CET 2004" + changed => "2017-03-07" ); sub catch_junk @@ -31,15 +32,15 @@ sub catch_junk my ($target, $text) = split(/ :/, $data, 2); my $valid_channel = 0; - if ($target[0] != '#' && $target[0] != '!' && $target[0] != '&') - { - return; - } + #if ($target[0] != '#' && $target[0] != '!' && $target[0] != '&') + #{ + # return; + #} for my $channel (split(/ /, Irssi::settings_get_str('colorkick_channels'))) { - if ($target == $channel) + if ($target eq $channel) { $valid_channel = 1; last; diff --git a/scripts/ctrlact.pl b/scripts/ctrlact.pl new file mode 100644 index 0000000..da39804 --- /dev/null +++ b/scripts/ctrlact.pl @@ -0,0 +1,574 @@ +# ctrlact.pl โ Irssi script for fine-grained control of activity indication +# +# ยฉ 2017 martin f. krafft <madduck@madduck.net> +# Released under the MIT licence. +# +### Usage: +# +# /script load ctrlact +# +# If you like a busy activity statusbar, this script is not for you. +# +# If, on the other hand, you don't care about most activity, but you do want +# the ability to define per-item and per-window, what level of activity should +# trigger a change in the statusbar, then ctrlact might be for you. +# +# For instance, you might never want to be disturbed by activity in any +# channel, unless someone highlights you. However, you do want all activity +# in queries (except on efnet, as well as an indication about any chatter in +# your company channels. The following ctrlact map would do this for you: +# +# channel /^#myco-/ messages +# channel * hilights +# query efnet * messages +# query * all +# +# These three lines would be interpreted/read as: +# "only messages or higher in a channel matching /^#myco-/ should trigger act" +# "in all other channels, only hilights (or higher) should trigger act" +# "queries on efnet should only trigger act for messages and higher" +# "messages of all levels should trigger act in queries elsewhere" +# +# The activity level in the third column is thus to be interpreted as +# "the minimum level of activity that will trigger an indication" +# +# Loading this script per-se should not change anything, except it will create +# ~/.irssi/ctrlact with some informational content, including the defaults and +# some examples. +# +# The four activity levels are, and you can use either the words, or the +# integers in the map. +# +# all (data_level: 1) +# messages (data_level: 2) +# hilights (data_level: 3) +# none (data_level: 4) +# +# Note that the name is either matched in full and verbatim, or treated like +# a regular expression, if it starts and ends with the same punctuation +# character. The asterisk ('*') is special and simply gets translated to /.*/ +# internally. No other wildcards are supported. +# +# Once you defined your mappings, please don't forget to /ctrlact reload them. +# You can then use the following commands from Irssi to check out the result: +# +# # list all mappings +# /ctrlact list +# +# # query the applicable activity levels, possibly limited to +# # windows/channels/queries +# /ctrlact query name [name, โฆ] [-window|-channel|-query] +# +# # display the applicable level for each window/channel/query +# /ctrlact show [-window|-channel|-query] +# +# There's an interplay between window items and windows here, and you can +# specify mininum activity levels for each. Here are the rules: +# +# 1. if the minimum activity level of a window item (channel or query) is not +# reached, then the window is prevented from indicating activity. +# 2. if traffic in a window item does reach minimum activity level, then the +# minimum activity level of the window is considered, and activity is only +# indicated if the window's minimum activity level is lower. +# +# In general, this means you'd have windows defaulting to 'all', but it might +# come in handy to move window items to windows with min.levels of 'hilights' +# or even 'none' in certain cases, to further limit activity indication for +# them. +# +# You can use the Irssi settings activity_msg_level and activity_hilight_level +# to specify which IRC levels will be considered messages and hilights. Note +# that if an activity indication is inhibited, then there also won't be +# a beep (cf. beep_msg_level), unless you toggle ctrlmap_inhibit_beep. +# +### Settings: +# +# /set ctrlact_map_file [~/.irssi/ctrlact] +# Controls where the activity control map will be read from (and saved to) +# +# /set ctrlact_fallback_(channel|query|window)_threshold [1] +# Controls the lowest data level that will trigger activity for channels, +# queries, and windows respectively, if no applicable mapping could be +# found. +# +# /set ctrlact_inhibit_beep [on] +# If an activity wouldn't be indicated, also inhibit the beep/bell. Turn +# this off if you want the bell anyway. +# +# /set ctrlact_debug [off] +# Turns on debug output. Not that this may itself be buggy, so please don't +# use it unless you really need it. +# +### To-do: +# +# - figure out interplay with activity_hide_level +# - /ctrlact add/delete/move and /ctrlact save, maybe +# - completion for commands +# +use strict; +use warnings; +use Carp qw( croak ); +use Irssi; +use Text::ParseWords; + +our $VERSION = '1.2'; + +our %IRSSI = ( + authors => 'martin f. krafft', + contact => 'madduck@madduck.net', + name => 'ctrlact', + description => 'allows per-channel control over activity indication', + license => 'MIT', + changed => '2017-02-24' +); + +### DEFAULTS AND SETTINGS ###################################################### + +my $debug = 0; +my $map_file = Irssi::get_irssi_dir()."/ctrlact"; +my $fallback_channel_threshold = 1; +my $fallback_query_threshold = 1; +my $fallback_window_threshold = 1; +my $inhibit_beep = 1; + +Irssi::settings_add_str('ctrlact', 'ctrlact_map_file', $map_file); +Irssi::settings_add_bool('ctrlact', 'ctrlact_debug', $debug); +Irssi::settings_add_int('ctrlact', 'ctrlact_fallback_channel_threshold', $fallback_channel_threshold); +Irssi::settings_add_int('ctrlact', 'ctrlact_fallback_query_threshold', $fallback_query_threshold); +Irssi::settings_add_int('ctrlact', 'ctrlact_fallback_window_threshold', $fallback_window_threshold); +Irssi::settings_add_bool('ctrlact', 'ctrlact_inhibit_beep', $inhibit_beep); + +sub sig_setup_changed { + $debug = Irssi::settings_get_bool('ctrlact_debug'); + $map_file = Irssi::settings_get_str('ctrlact_map_file'); + $fallback_channel_threshold = Irssi::settings_get_int('ctrlact_fallback_channel_threshold'); + $fallback_query_threshold = Irssi::settings_get_int('ctrlact_fallback_query_threshold'); + $fallback_window_threshold = Irssi::settings_get_int('ctrlact_fallback_window_threshold'); + $inhibit_beep = Irssi::settings_get_bool('ctrlact_inhibit_beep'); +} +Irssi::signal_add('setup changed', \&sig_setup_changed); +Irssi::signal_add('setup reread', \&sig_setup_changed); +sig_setup_changed(); + +my $changed_since_last_save = 0; + +my @DATALEVEL_KEYWORDS = ('all', 'messages', 'hilights', 'none'); + +### HELPERS #################################################################### + +my $_inhibit_debug_activity = 0; +use constant DEBUGEVENTFORMAT => "%7s %7.7s %-22.22s %d %s %d โ %-7s (%-8s โ %s)"; +sub debugprint { + return unless $debug; + my ($msg, @rest) = @_; + $_inhibit_debug_activity = 1; + Irssi::print("ctrlact debug: ".$msg, MSGLEVEL_CRAP); + $_inhibit_debug_activity = 0; +} + +sub error { + my ($msg) = @_; + Irssi::print("ctrlact: ERROR: $msg", MSGLEVEL_CLIENTERROR); +} + +my @window_thresholds; +my @channel_thresholds; +my @query_thresholds; + +sub match { + my ($pat, $text) = @_; + my $npat = ($pat eq '*') ? '/.*/' : $pat; + if ($npat =~ m/^(\W)(.+)\1$/) { + my $re = qr/$2/; + $pat = $2 unless $pat eq '*'; + return $pat if $text =~ /$re/i; + } + else { + return $pat if lc($text) eq lc($npat); + } + return 0; +} + +sub to_data_level { + my ($kw) = @_; + return $1 if $kw =~ m/^(\d+)$/; + foreach my $i (2..4) { + my $matcher = qr/^$DATALEVEL_KEYWORDS[5-$i]$/; + return 6-$i if $kw =~ m/$matcher/i; + } + return 1; +} + +sub from_data_level { + my ($dl) = @_; + croak "Invalid numeric data level: $dl" unless $dl =~ m/^([1-4])$/; + return $DATALEVEL_KEYWORDS[$dl-1]; +} + +sub walk_match_array { + my ($name, $net, $type, @arr) = @_; + foreach my $quadruplet (@arr) { + my $netmatch = $net eq '*' ? '(ignored)' + : match($quadruplet->[0], $net); + my $match = match($quadruplet->[1], $name); + next unless $netmatch and $match; + + my $result = to_data_level($quadruplet->[2]); + my $tresult = from_data_level($result); + $name = '(unnamed)' unless length $name; + $match = sprintf('line %3d = net:%s name:%s', + $quadruplet->[3], $netmatch, $match); + return ($result, $tresult, $match) + } + return -1; +} + +sub get_mappings_table { + my (@arr) = @_; + my @ret = (); + for (my $i = 0; $i < @arr; $i++) { + push @ret, sprintf("%4d: %-10s %-40s %-10s (line: %3d)", + $i, $arr[$i]->[0], $arr[$i]->[1], $arr[$i]->[2], $arr[$i]->[3]); + } + return join("\n", @ret); +} + +sub get_specific_threshold { + my ($type, $name, $net) = @_; + $type = lc($type); + if ($type eq 'window') { + return walk_match_array($name, $net, $type, @window_thresholds); + } + elsif ($type eq 'channel') { + return walk_match_array($name, $net, $type, @channel_thresholds); + } + elsif ($type eq 'query') { + return walk_match_array($name, $net, $type, @query_thresholds); + } + else { + croak "ctrlact: can't look up threshold for type: $type"; + } +} + +sub get_item_threshold { + my ($chattype, $type, $name, $net) = @_; + my ($ret, $tret, $match) = get_specific_threshold($type, $name, $net); + return ($ret, $tret, $match) if $ret > 0; + if ($type eq 'CHANNEL') { + return ($fallback_channel_threshold, from_data_level($fallback_channel_threshold), '[default]'); + } + else { + return ($fallback_query_threshold, from_data_level($fallback_query_threshold), '[default]'); + } +} + +sub get_win_threshold { + my ($name, $net) = @_; + my ($ret, $tret, $match) = get_specific_threshold('window', $name, $net); + if ($ret > 0) { + return ($ret, $tret, $match); + } + else { + return ($fallback_window_threshold, from_data_level($fallback_window_threshold), '[default]'); + } +} + +sub print_levels_for_all { + my ($type, @arr) = @_; + Irssi::print("ctrlact: $type mappings:"); + for (my $i = 0; $i < @arr; $i++) { + my $name = $arr[$i]->{'name'}; + my $net = $arr[$i]->{'server'}->{'tag'} // ''; + my ($t, $tt, $match) = get_specific_threshold($type, $name, $net); + my $c = ($type eq 'window') ? $arr[$i]->{'refnum'} : $arr[$i]->window()->{'refnum'}; + Irssi::print(sprintf("%4d: %-40.40s โ %d (%-8s) match %s", $c, $name, $t, $tt, $match), MSGLEVEL_CRAP); + } +} + +### HILIGHT SIGNAL HANDLERS #################################################### + +my $_inhibit_beep = 0; +my $_inhibit_window = 0; + +sub maybe_inhibit_witem_hilight { + my ($witem, $oldlevel) = @_; + return unless $witem; + $oldlevel = 0 unless $oldlevel; + my $newlevel = $witem->{'data_level'}; + return if ($newlevel <= $oldlevel); + + $_inhibit_window = 0; + $_inhibit_beep = 0; + my $wichattype = $witem->{'chat_type'}; + my $witype = $witem->{'type'}; + my $winame = $witem->{'name'}; + my $witag = $witem->{'server'}->{'tag'} // ''; + my ($th, $tth, $match) = get_item_threshold($wichattype, $witype, $winame, $witag); + my $inhibit = $newlevel > 0 && $newlevel < $th; + debugprint(sprintf(DEBUGEVENTFORMAT, lc($witype), $witag, $winame, $newlevel, + $inhibit ? ('<',$th,'inhibit'):('โฅ',$th,'pass'), + $tth, $match)); + if ($inhibit) { + Irssi::signal_stop(); + # the rhval comes from config, so if the user doesn't want the + # bell inhibited, this is effectively a noop. + $_inhibit_beep = $inhibit_beep; + $_inhibit_window = $witem->window(); + } +} +Irssi::signal_add_first('window item hilight', \&maybe_inhibit_witem_hilight); + +sub inhibit_win_hilight { + my ($win) = @_; + Irssi::signal_stop(); + Irssi::signal_emit('window dehilight', $win); +} + +sub maybe_inhibit_win_hilight { + my ($win, $oldlevel) = @_; + return unless $win; + if ($_inhibit_debug_activity) { + inhibit_win_hilight($win); + } + elsif ($_inhibit_window && $win->{'refnum'} == $_inhibit_window->{'refnum'}) { + inhibit_win_hilight($win); + } + else { + $oldlevel = 0 unless $oldlevel; + my $newlevel = $win->{'data_level'}; + return if ($newlevel <= $oldlevel); + + my $wname = $win->{'name'}; + my $wtag = $win->{'server'}->{'tag'} // ''; + my ($th, $tth, $match) = get_win_threshold($wname, $wtag); + my $inhibit = $newlevel > 0 && $newlevel < $th; + debugprint(sprintf(DEBUGEVENTFORMAT, 'window', $wtag, + $wname?$wname:'(unnamed)', $newlevel, + $inhibit ? ('<',$th,'inhibit'):('โฅ',$th,'pass'), + $tth, $match)); + inhibit_win_hilight($win) if $inhibit; + } +} +Irssi::signal_add_first('window hilight', \&maybe_inhibit_win_hilight); + +sub maybe_inhibit_beep { + Irssi::signal_stop() if $_inhibit_beep; +} +Irssi::signal_add_first('beep', \&maybe_inhibit_beep); + +### SAVING AND LOADING ######################################################### + +sub get_mappings_fh { + my ($filename) = @_; + my $fh; + if (-e $filename) { + open($fh, '<', $filename) || croak "Cannot open mappings file: $!"; + } + else { + open($fh, '+>', $filename) || croak "Cannot create mappings file: $!"; + + my $ftw = from_data_level($fallback_window_threshold); + my $ftc = from_data_level($fallback_channel_threshold); + my $ftq = from_data_level($fallback_query_threshold); + print $fh <<"EOF"; +# ctrlact mappings file (version: $VERSION) +# +# type: window, channel, query +# server: the server tag (chatnet) +# name: full name to match, /regexp/, or * (for all) +# min.level: none, messages, hilights, all, or 1,2,3,4 +# +# type server name min.level + + +# EXAMPLES +# +### only indicate activity in the status window if messages were displayed: +# window * (status) messages +# +### never ever indicate activity for any item bound to this window: +# window * oubliette none +# +### indicate activity on all messages in debian-related channels on OFTC: +# channel oftc /^#debian/ messages +# +### display any text (incl. joins etc.) for the '#madduck' channel: +# channel * #madduck all +# +### otherwise ignore everything in channels, unless a hilight is triggered: +# channel * * hilights +# +### make somebot only get your attention if they hilight you: +# query efnet somebot hilights +# +### otherwise we want to see everything in queries: +# query * * all + +# DEFAULTS: +# window * * $ftw +# channel * * $ftc +# query * * $ftq + +# vim:noet:tw=0:ts=16 +EOF + Irssi::print("ctrlact: created new/empty mappings file: $filename"); + seek($fh, 0, 0) || croak "Cannot rewind $filename."; + } + return $fh; +} + +sub load_mappings { + my ($filename) = @_; + @window_thresholds = @channel_thresholds = @query_thresholds = (); + my $fh = get_mappings_fh($filename); + my $firstline = <$fh> || croak "Cannot read from $filename.";; + my $version; + if ($firstline =~ m/^#+\s+ctrlact mappings file \(version: *([\d.]+)\)/) { + $version = $1; + } + else { + croak "First line of $filename is not a ctrlact header."; + } + + my $nrcols = 4; + if ($version eq $VERSION) { + # current version, i.e. no special handling is required. If + # previous versions require special handling, then massage the + # data or do whatever is required in the following + # elsif-clauses: + } + elsif ($version eq "1.0") { + $nrcols = 3; + } + my $linesplitter = '^\s*'.join('\s+', ('(\S+)') x $nrcols).'\s*$'; + my $l = 1; + while (<$fh>) { + $l++; + next if m/^\s*(?:#|$)/; + my ($type, @matchers) = m/$linesplitter/; + @matchers = ['*', @matchers] if ($version eq "1.0"); + push @matchers, $l; + push @window_thresholds, [@matchers] if match($type, 'window'); + push @channel_thresholds, [@matchers] if match($type, 'channel'); + push @query_thresholds, [@matchers] if match($type, 'query'); + } + close($fh) || croak "Cannot close mappings file: $!"; +} + +sub cmd_load { + Irssi::print("ctrlact: loading mappings from $map_file"); + load_mappings($map_file); + $changed_since_last_save = 0; +} + +sub cmd_save { + error("saving not yet implemented"); + return 1; +} + +sub cmd_list { + Irssi::print("ctrlact: window mappings"); + Irssi::print(get_mappings_table(@window_thresholds), MSGLEVEL_CRAP); + Irssi::print("ctrlact: channel mappings"); + Irssi::print(get_mappings_table(@channel_thresholds), MSGLEVEL_CRAP); + Irssi::print("ctrlact: query mappings"); + Irssi::print(get_mappings_table(@query_thresholds), MSGLEVEL_CRAP); +} + +sub parse_args { + my (@args) = @_; + my @words = (); + my $typewasset = 0; + my $tag; + my $max = 0; + my $type = undef; + foreach my $arg (@args) { + if ($arg =~ m/^-(windows?|channels?|quer(?:ys?|ies))/) { + if ($typewasset) { + error("can't specify -$1 after -$type"); + return 1; + } + $type = 'window' if $1 =~ m/^w/; + $type = 'channel' if $1 =~ m/^c/; + $type = 'query' if $1 =~ m/^q/; + $typewasset = 1 + } + elsif ($arg =~ m/-(\S+)/) { + $tag = $1; + } + else { + push @words, $arg; + $max = length $arg if length $arg > $max; + } + } + return ($type, $tag, $max, @words); +} + +sub cmd_query { + my ($data, $server, $item) = @_; + my @args = shellwords($data); + my ($type, $tag, $max, @words) = parse_args(@args); + $type = $type // 'channel'; + $tag = $tag // '*'; + foreach my $word (@words) { + my ($t, $tt, $match) = get_specific_threshold($type, $word, $tag); + printf CLIENTCRAP "ctrlact $type map: %s %*s โ %d (%s, match:%s)", $tag, $max, $word, $t, $tt, $match; + } +} + +sub cmd_show { + my ($data, $server, $item) = @_; + my @args = shellwords($data); + my ($type, $max, @words) = parse_args(@args); + $type = $type // 'all'; + + if ($type eq 'channel' or $type eq 'all') { + print_levels_for_all('channel', Irssi::channels()); + } + if ($type eq 'query' or $type eq 'all') { + print_levels_for_all('query', Irssi::queries()); + } + if ($type eq 'window' or $type eq 'all') { + print_levels_for_all('window', Irssi::windows()); + } +} + +sub autosave { + cmd_save() if ($changed_since_last_save); +} + +sub UNLOAD { + autosave(); +} + +Irssi::signal_add('setup saved', \&autosave); +Irssi::signal_add('setup reread', \&cmd_load); + +Irssi::command_bind('ctrlact help',\&cmd_help); +Irssi::command_bind('ctrlact reload',\&cmd_load); +Irssi::command_bind('ctrlact load',\&cmd_load); +Irssi::command_bind('ctrlact save',\&cmd_save); +Irssi::command_bind('ctrlact list',\&cmd_list); +Irssi::command_bind('ctrlact query',\&cmd_query); +Irssi::command_bind('ctrlact show',\&cmd_show); + +Irssi::command_bind('ctrlact' => sub { + my ( $data, $server, $item ) = @_; + $data =~ s/\s+$//g; + if ($data) { + Irssi::command_runsub('ctrlact', $data, $server, $item); + } + else { + cmd_help(); + } + } +); +Irssi::command_bind('help', sub { + $_[0] =~ s/\s+$//g; + return unless $_[0] eq 'ctrlact'; + cmd_help(); + Irssi::signal_stop(); + } +); + +cmd_load(); diff --git a/scripts/dccself.pl b/scripts/dccself.pl index e944133..1a6ccea 100644 --- a/scripts/dccself.pl +++ b/scripts/dccself.pl @@ -1,7 +1,8 @@ use strict; -use vars qw/%IRSSI/; +use vars qw/%IRSSI $VERSION/; use Irssi qw(command_bind active_server); +$VERSION= "0.1"; %IRSSI = ( authors => "David Leadbeater", contact => "dgl\@dgl.cx", diff --git a/scripts/desktop-notify.pl b/scripts/desktop-notify.pl index da25b8c..c41a9f4 100644 --- a/scripts/desktop-notify.pl +++ b/scripts/desktop-notify.pl @@ -24,8 +24,9 @@ use strict; use Irssi; use HTML::Entities; use Glib::Object::Introspection; # Ignore 'late INIT' warning message if autoloading +use Encode; -our $VERSION = '1.0.0'; +our $VERSION = '1.0.1'; our %IRSSI = ( authors => 'Felipe F. Tonello', contact => 'eu@felipetonello.com', @@ -38,6 +39,7 @@ our %IRSSI = ( # List of standard icons can be found here: # http://standards.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html#names my $notify_icon; +my $term_charset; my $help = ' /set notify_icon <icon-name> @@ -60,6 +62,7 @@ sub UNLOAD { sub setup_changed { $notify_icon = Irssi::settings_get_str('notify_icon'); + $term_charset = Irssi::settings_get_str('term_charset'); } sub priv_msg { @@ -71,9 +74,9 @@ sub priv_msg { return; } - my $msg = HTML::Entities::encode_entities(Irssi::strip_codes($msg)); + my $msg = HTML::Entities::encode_entities(Irssi::strip_codes($msg), "\<>&'"); my $network = $server->{tag}; - my $noti = Notify::Notification->new($nick . '@' . $network, $msg, $notify_icon); + my $noti = Notify::Notification->new($nick . '@' . $network, decode($term_charset, $msg), $notify_icon); $noti->show(); } @@ -94,8 +97,8 @@ sub hilight { } my $network = $server->{tag}; - my $msg = HTML::Entities::encode_entities($stripped); - my $noti = Notify::Notification->new($dest->{target} . '@' . $network, $msg, $notify_icon); + my $msg = HTML::Entities::encode_entities($stripped, "\'<>&"); + my $noti = Notify::Notification->new($dest->{target} . '@' . $network, decode($term_charset, $msg), $notify_icon); $noti->show(); } diff --git a/scripts/go.pl b/scripts/go.pl index b656a0f..0b0a2a2 100644 --- a/scripts/go.pl +++ b/scripts/go.pl @@ -7,8 +7,29 @@ use Irssi::Irc; # /script load go.pl # 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) +# +# The following settings exist: +# +# /SET go_match_case_sensitive [ON|OFF] +# Match window/item names sensitively (the default). Turning this off +# means e.g. "/go foo" would jump to a window named "Foobar", too. +# +# /SET go_match_anchored [ON|OFF] +# Match window/names only at the start of the word (the default). Turning +# this off will mean that strings can match anywhere in the window/names. +# The leading '#' of channel names is optional either way. +# +# /SET go_complete_case_sensitive [ON|OFF] +# When using tab-completion, match case-insensitively (the default). +# Turning this on means that "/go foo<tab>" will *not* suggest "Foobar". +# +# /SET go_complete_anchored [ON|OFF] +# Match window/names only at the start of the word. The default is 'off', +# which causes completion to match anywhere in the window/names during +# completion. The leading '#' of channel names is optional either way. +# -$VERSION = '1.01'; +$VERSION = '1.1'; %IRSSI = ( authors => 'nohar', @@ -16,9 +37,17 @@ $VERSION = '1.01'; 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 => '2014-10-19' + changed => '2017-02-02' ); +sub _make_regexp { + my ($name, $ci, $aw) = @_; + my $re = "\Q${name}\E"; + $re = "(?i:$re)" unless $ci; + $re = "^#?$re" if $aw; + return $re; +} + sub signal_complete_go { my ($complist, $window, $word, $linestart, $want_space) = @_; my $channel = $window->get_active_name(); @@ -26,11 +55,14 @@ sub signal_complete_go { return unless ($linestart =~ /^\Q${k}\Ego\b/i); + my $re = _make_regexp($word, + Irssi::settings_get_bool('go_complete_case_sensitive'), + Irssi::settings_get_bool('go_complete_anchored')); @$complist = (); foreach my $w (Irssi::windows) { my $name = $w->get_active_name(); if ($word ne "") { - if ($name =~ /\Q${word}\E/i) { + if ($name =~ $re) { push(@$complist, $name) } } else { @@ -45,9 +77,13 @@ sub cmd_go my($chan,$server,$witem) = @_; $chan =~ s/ *//g; + my $re = _make_regexp($chan, + Irssi::settings_get_bool('go_match_case_sensitive'), + Irssi::settings_get_bool('go_match_anchored')); + foreach my $w (Irssi::windows) { my $name = $w->get_active_name(); - if ($name =~ /^#?\Q${chan}\E/) { + if ($name =~ $re) { $w->set_active(); return; } @@ -56,4 +92,14 @@ sub cmd_go Irssi::command_bind("go", "cmd_go"); Irssi::signal_add_first('complete word', 'signal_complete_go'); +Irssi::settings_add_bool('go', 'go_match_case_sensitive', 1); +Irssi::settings_add_bool('go', 'go_complete_case_sensitive', 0); +Irssi::settings_add_bool('go', 'go_match_anchored', 1); +Irssi::settings_add_bool('go', 'go_complete_anchored', 0); +# Changelog +# +# 2017-02-02 1.1 martin f. krafft <madduck@madduck.net> +# - made case-sensitivity of match configurable +# - made anchoring of search strings configurable +# diff --git a/scripts/hilightwin.pl b/scripts/hilightwin.pl index 7d70317..2e407fa 100644 --- a/scripts/hilightwin.pl +++ b/scripts/hilightwin.pl @@ -11,7 +11,7 @@ use Irssi; use POSIX; use vars qw($VERSION %IRSSI); -$VERSION = "0.04"; +$VERSION = "0.05"; %IRSSI = ( authors => "Timo \'cras\' Sirainen, Mark \'znx\' Sangster", contact => "tss\@iki.fi, znxster\@gmail.com", @@ -22,6 +22,26 @@ $VERSION = "0.04"; changed => "Sun May 25 18:59:57 BST 2008" ); +sub is_ignored { + my ($dest) = @_; + + my @ignore = split(' ', Irssi::settings_get_str('hilightwin_ignore_targets')); + return 0 if (!@ignore); + + my %targets = map { $_ => 1 } @ignore; + + return 1 if exists($targets{"*"}); + return 1 if exists($targets{$dest->{target}}); + + if ($dest->{server}) { + my $tag = $dest->{server}->{tag}; + return 1 if exists($targets{$tag . "/*"}); + return 1 if exists($targets{$tag . "/" . $dest->{target}}); + } + + return 0; +} + sub sig_printtext { my ($dest, $text, $stripped) = @_; @@ -33,7 +53,8 @@ sub sig_printtext { if( ($dest->{level} & ($opt)) && - ($dest->{level} & MSGLEVEL_NOHILIGHT) == 0 + ($dest->{level} & MSGLEVEL_NOHILIGHT) == 0 && + (!is_ignored($dest)) ) { my $window = Irssi::window_find_name('hilight'); @@ -49,6 +70,7 @@ my $window = Irssi::window_find_name('hilight'); Irssi::print("Create a window named 'hilight'") if (!$window); Irssi::settings_add_bool('hilightwin','hilightwin_showprivmsg',1); +Irssi::settings_add_str('hilightwin', 'hilightwin_ignore_targets', ''); Irssi::signal_add('print text', 'sig_printtext'); diff --git a/scripts/hilite_url.pl b/scripts/hilite_url.pl new file mode 100644 index 0000000..11c4b0d --- /dev/null +++ b/scripts/hilite_url.pl @@ -0,0 +1,28 @@ +# Simple script to highlight links in public messages + +use strict; +use vars qw($VERSION %IRSSI); + +# Dev. info ^_^ +$VERSION = "0.1"; +%IRSSI = ( + authors => "Stefan Heinemann", + contact => "stefan.heinemann\@codedump.ch", + name => "hilite url", + description => "Simple script that highlights URL", + license => "GPL", + url => "http://senseless.codedump.ch", +); + +sub hilite_url { + my ($server, $data, $nick, $mask, $target) = @_; + + # Add Colours + $data =~ s/(https?:\/\/[^\s]+)/\e[4;34m\1\e[00m/g; + + # Let it flow + Irssi::signal_continue($server, $data, $nick, $mask, $target); +} + +# Hook me up +Irssi::signal_add('message public', 'hilite_url'); diff --git a/scripts/ident.pl b/scripts/ident.pl new file mode 100644 index 0000000..a4854f2 --- /dev/null +++ b/scripts/ident.pl @@ -0,0 +1,68 @@ +#!/usr/bin/perl -w + +use strict; +use Irssi; +use POSIX; + +use vars qw($VERSION %IRSSI); + +$VERSION = "1.0"; +%IRSSI = ( + authors => 'Isaac Good', + contact => "irssi\@isaacgood.com; irc.freenode.net/yitz", + name => 'ident', + description => 'Ident to NickServs', + name => "ident", + description => "Automatically IDENTIFY when prompted", + license => 'MIT', +); + + +my %pw; + + +sub LoadPasswords { + # Load the passwords from file. + delete @pw{keys %pw}; + my $filename = Irssi::get_irssi_dir() . '/passwords'; + my $FH; + unless(open $FH, "<", $filename) + { + print "Can not open $filename"; + return 0; + } + while (my $line = <$FH>) + { + chomp $line; + next unless ($line); + my ($tag, $password) = split(/ */, $line, 2); + next unless ($tag and $password); + $pw{$tag} = $password; + } + return 1; +} + + +sub notice { + my ($server, $data, $nick, $host) = @_; + my ($channel, $msg) = split(/ :/, $data, 2); + my $l = 0; + + # Test the notice. Must be from nickserv and be asking you to identify. + return undef unless (lc($nick) eq 'nickserv'); + return undef unless (lc($msg) =~ /msg nickserv identify/); + # Check it's a direct message and we have a password for this network. + return undef unless (lc($channel) eq lc($server->{'nick'})); + return undef unless ($pw{$server->{'chatnet'}}); + + my $pw = $pw{$server->{'chatnet'}}; + # Use the /quote nickserv approach to reduce chance of leaking the password to a bad actor, ie someone pretending to be nickserv. + $server->command("^quote nickserv identify $pw"); + + return undef; +} + + +if (LoadPasswords()) { + Irssi::signal_add('event notice', \¬ice); +} diff --git a/scripts/invitejoin.pl b/scripts/invitejoin.pl index c69ed01..d3b5871 100644 --- a/scripts/invitejoin.pl +++ b/scripts/invitejoin.pl @@ -24,7 +24,7 @@ use strict; use Irssi; use vars qw($VERSION %IRSSI); -$VERSION = "0.01"; +$VERSION = '0.02'; %IRSSI = ( authors => 'Geert Hauwaerts', @@ -32,37 +32,254 @@ $VERSION = "0.01"; name => 'invitejoin.pl', description => 'This script will join a channel if somebody invites you to it.', license => 'Public Domain', - url => 'http://irssi.hauwaerts.be/invitejoin.pl', - changed => 'Sun Apr 11 12:38:18 2004', + url => 'https://github.com/irssi/scripts.irssi.org/blob/master/scripts/invitejoin.pl', + changed => 'Di 17. Jan 19:32:45 CET 2017', ); -## Comments and remarks. -# -# This script uses settings. -# Use /SET to change the value or /TOGGLE to switch it on or off. -# -# Setting: invitejoin -# Description: If this setting is turned on, you will join the channel -# when invite to. -# -## +my $help = <<EOF; + +/SET invitejoin 0|1 +/TOGGLE invitejoin + Description: If this setting is turned on, you will join the channel + when invited to. + +Default is to follow every invite, you can specify a list of allowed nicks. + +/INVITEJOIN [addnick <ircnet> <nick>] + [delnick <ircnet> <nick>] + [listnick] + [help] + +addnick: Add a new nickname on the given net as allowed autoinvite source. +delnick: Delete a nickname from the allowed list. +listnick: Display the contents of the allowed nickname list. +help: Display this useful little helptext. + +Examples: (all on one line) +/INVITEJOIN addnick Freenode ChanServ + +Note: This script doesn't allow wildcards +EOF +my @allowed_nicks = (); +my $allowed_nicks_file = "invitejoin.nicks"; + +my $irssidir = Irssi::get_irssi_dir(); Irssi::theme_register([ + 'invitejoin_usage', '%R>>%n %_Invitejoin:%_ Insufficient parameters: Use "%_/INVITEJOIN help%_" for further instructions.', + 'invitejoin_help', '$0', 'invitejoin_loaded', '%R>>%n %_Scriptinfo:%_ Loaded $0 version $1 by $2.', - 'invitejoin_invited', '%R>>%n %_Invitejoin:%_ Joined $1 (Invited by $0).' + 'invitejoin_invited', '%R>>%n %_Invitejoin:%_ Joined $1 (Invited by $0).', + 'invitejoin_usage_add_nick', '%R>>%n %_Invitejoin:%_ Insufficient parameters: Usage "%_/INVITEJOIN addnick ircnet ChanServ%_".', + 'invitejoin_no_net', '%R>>%n %_Invitejoin:%_ Unknown Irssi ircnet %_$0%_.', + 'saved_nick', '%R>>%n %_Invitejoin:%_ Added allowed nick "%_$1%_" on %_$0%_.', + 'nick_already_present', '%R>>%n %_Invitejoin:%_ Nick already present.', + 'invitejoin_delusage', '%R>>%n %_Invitejoin:%_ Insufficient parameters: Usage "%_/INVITEJOIN delnick ircnet nick%_".', + 'invitejoin_delled', '%R>>%n %_Invitejoin:%_ Deleted %_$1%_ on %_$0%_ from allowed list.', + 'invitejoin_nfound', '%R>>%n %_Invitejoin:%_ The nick %_$1%_ on %_$0%_ could not be found.', + 'allowed_nicks_info', '%_Ircnet Nick%_', + 'allowed_nicks_empty', '%R>>%n %_Invitejoin:%_ Your allowed nick list is empty. All invites will be followed.', + 'allowed_nicks_print', '$[18]0 $1', + 'invite_denied', '%R>>%n %_Invitejoin:%_ Invite from nick %_$1%_ on %_$0%_ to %_$2%_ not followed because it is not in the allowed list.', ]); +sub load_allowed_nicks { + my ($file) = @_; + + @allowed_nicks = load_file($file, sub { + my $new_allowed = new_allowed_nick(@_); + + return undef if ($new_allowed->{net} eq '' || $new_allowed->{nick} eq ''); + return $new_allowed; + }); +} + +sub save_allowed_nicks { + my ($file) = @_; + save_file($file, \@allowed_nicks, \&allowed_nick_to_list); +} + +sub allowed_nick_to_list { + my $allowed_nick = shift; + + return ( + $allowed_nick->{net}, + $allowed_nick->{nick} + ); +} + +sub new_allowed_nick { + return { + net => shift, + nick => shift + }; +} + +# file: filename to be read +# parse_line_fn: receives array of entries of a single line as input, should +# return parsed data object or undef in the data is incomplete +# returns: parsed data array +sub load_file { + my ($file, $parse_line_fn) = @_; + my @parsed_data = (); + + if (-e $file) { + open(my $fh, "<", $file); + local $/ = "\n"; + + while (<$fh>) { + chomp; + my $data = $parse_line_fn->(split("\t")); + push(@parsed_data, $data) if $data; + } + + close($fh); + } + + return @parsed_data; +} + +# file: filename to be written, is created accessable only by the user +# data_ref: array ref of data entries +# serialize_fn: receives a data reference and should return an array or tuples +# for that data that will be serialized into one line +sub save_file { + my ($file, $data_ref, $serialize_fn) = @_; + + create_private_file($file) unless -e $file; + + open(my $fh, ">", $file) or die "Can't create $file. Reason: $!"; + + for my $data (@$data_ref) { + print($fh join("\t", $serialize_fn->($data)), "\n"); + } + + close($fh); +} + +sub create_private_file { + my ($file) = @_; + my $umask = umask 0077; # save old umask + open(my $fh, ">", $file) or die "Can't create $file. Reason: $!"; + close($fh); + umask $umask; +} + +sub add_allowed_nick { + my ($network, $nick) = split(" ", $_[0], 2); + my ($correct_net); + + if ($network eq '' || $nick eq '') { + Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'invitejoin_usage_add_nick'); + return; + } + + if ($network) { + my ($ircnet) = Irssi::chatnet_find($network); + if (!$ircnet) { + Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'invitejoin_no_net', $network); + return; + } else { + $correct_net = 1; + } + } + + if ($correct_net && $nick) { + if (is_nick_in_list($network, $nick)) { + Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nick_already_present'); + return; + } + + push(@allowed_nicks, new_allowed_nick($network, $nick)); + save_allowed_nicks("$irssidir/$allowed_nicks_file"); + + Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'saved_nick', $network, $nick); + } +} + +sub del_allowed_nick { + my ($ircnet, $nick) = split(" ", $_[0], 2); + + if ($ircnet eq '' || $nick eq '') { + Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'invitejoin_delusage'); + return; + } + + my $size_before = scalar(@allowed_nicks); + @allowed_nicks = grep { ! ($_->{net} eq $ircnet && $_->{nick} eq $nick) } @allowed_nicks; + my $size_after = scalar(@allowed_nicks); + + if ($size_after != $size_before) { + Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'invitejoin_delled', $ircnet, $nick); + save_allowed_nicks("$irssidir/$allowed_nicks_file"); + } else { + Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'invitejoin_nfound', $ircnet, $nick); + } + + if ($size_after == 0) { + Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'allowed_nicks_empty'); + } +} + +sub list_allowed_nicks { + if (@allowed_nicks == 0) { + Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'allowed_nicks_empty'); + } else { + Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'allowed_nicks_info'); + + for my $allowed (@allowed_nicks) { + Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'allowed_nicks_print', $allowed->{net}, $allowed->{nick}); + } + } +} + +sub invitejoin_runsub { + my ($data, $server, $item) = @_; + $data =~ s/\s+$//g; + + if ($data) { + Irssi::command_runsub('invitejoin', $data, $server, $item); + } else { + Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'invitejoin_usage'); + } +} + +sub is_nick_in_list { + my ($net, $nick) = @_; + + return (grep { + $_->{net} eq $net && + $_->{nick} eq $nick + } @allowed_nicks) > 0; +} + +sub is_allowed_nick { + my ($net, $nick) = @_; + + # If no allowed nicks are specified (initial configuration) accept + # all invite requests. + # # (This mimics previous behavior of this script + # before there was an allowed list) + return 1 if @allowed_nicks == 0; + + return is_nick_in_list($net, $nick); +} + sub invitejoin { - my ($server, $channel, $nick, $address) = @_; my $invitejoin = Irssi::settings_get_bool('invitejoin'); if ($invitejoin) { - $server->command("join $channel"); - - Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'invitejoin_invited', $nick, $channel); - Irssi::signal_stop(); + if (is_allowed_nick($server->{tag}, $nick)) { + $server->command("join $channel"); + + Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'invitejoin_invited', $nick, $channel); + Irssi::signal_stop(); + } + else { + Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'invite_denied', $server->{tag}, $nick, $channel); + } } } @@ -70,4 +287,12 @@ Irssi::signal_add('message invite', 'invitejoin'); Irssi::settings_add_bool('invitejoin', 'invitejoin' => 1); +load_allowed_nicks("$irssidir/$allowed_nicks_file"); + +Irssi::command_bind('invitejoin', 'invitejoin_runsub'); +Irssi::command_bind('invitejoin addnick', 'add_allowed_nick'); +Irssi::command_bind('invitejoin delnick', 'del_allowed_nick'); +Irssi::command_bind('invitejoin listnick', 'list_allowed_nicks'); +Irssi::command_bind('invitejoin help' => sub { Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'invitejoin_help', $help) }); + Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'invitejoin_loaded', $IRSSI{name}, $VERSION, $IRSSI{authors}); diff --git a/scripts/listsort.pl b/scripts/listsort.pl new file mode 100644 index 0000000..81b9ab9 --- /dev/null +++ b/scripts/listsort.pl @@ -0,0 +1,60 @@ +use strict; +use warnings; +use Irssi; +use vars qw/$VERSION %IRSSI/; + +$VERSION = '0.1'; +%IRSSI = ( + authors => 'Isaac Good', + name => 'listsort', + contact => 'irssi@isaacgood.com', + decsription => 'Sort the /list output by channel size', + license => 'BSD', + url => 'https://github.com/IsaacG/irssi-scripts', + created => '2013/02/23', +); + +# Bindings. Start of channel list, end of list, list item. +Irssi::signal_add_last('event 322', \&list_event); +Irssi::signal_add_last('event 323', \&list_end); + +# Store the channel list between IRC messages +my %list; + +# Store list info in the hash. +sub list_event { + my ($server, $data, $server_name) = @_; + my ($meta, $more) = split (/ :/, $data, 2); + my ($nick, $name, $size) = split (/ /, $meta, 3); + $list{$name}{'size'} = $size; + + my $modes = ''; + $list{$name}{'desc'} = ''; + if ($more =~ /^[^[]*\[([^]]*)\][^ ]* *([^ ].*)$/) { + $modes = $1; + $list{$name}{'desc'} = $2; + } + + $modes =~ s/ +$//; + $list{$name}{'modes'} = $modes; +} + +# Print out the whole list in sorted order. +sub list_end { + for my $name (sort {$list{$a}{'size'} <=> $list{$b}{'size'}} keys %list) { + my $mode = $list{$name}{'modes'}; + $mode = " ($mode)" if ($mode); + my $msg = sprintf ( + "%d %s: %s%s", + $list{$name}{'size'}, + $name, + $list{$name}{'desc'}, + $mode + ); + + Irssi::print($msg, MSGLEVEL_CRAP); + } + # Drop the hash values; no point in holding them in memory. + %list = (); +} + diff --git a/scripts/logcompress_perl.pl b/scripts/logcompress_perl.pl index 062331e..d75755a 100644 --- a/scripts/logcompress_perl.pl +++ b/scripts/logcompress_perl.pl @@ -4,7 +4,7 @@ use Irssi; use IO::Compress::Gzip qw(gzip $GzipError); use vars qw($VERSION %IRSSI); -$VERSION = "0.01"; +$VERSION = "0.02"; %IRSSI = ( authors => 'vague', contact => 'vague!#irssi@fgreenode', @@ -12,12 +12,13 @@ $VERSION = "0.01"; description => "compress logfiles then they're rotated, modified from original logcompress.pl to use perl modules instead", license => "Public Domain", url => "http://irssi.org/", - changed => "2016-01-31T01:45+0100" + changed => "2017-01-07T12:00+0100" ); sub sig_rotate { my $input = $_[0]->{real_fname}; gzip $input => "$input.gz" or Irssi::print(MSGLEVEL_CLIENTERROR, "gzip failed: $GzipError\n"); + unlink $input if -e "$input.gz"; } Irssi::signal_add('log rotated', 'sig_rotate'); diff --git a/scripts/mh_sbuserinfo.pl b/scripts/mh_sbuserinfo.pl index fde7ebc..c9ee211 100644 --- a/scripts/mh_sbuserinfo.pl +++ b/scripts/mh_sbuserinfo.pl @@ -1,8 +1,8 @@ ############################################################################## # -# mh_sbuserinfo.pl v1.04 (20151225) +# mh_sbuserinfo.pl v1.05 (20161106) # -# Copyright (c) 2015 Michael Hansen +# Copyright (c) 2015, 2016 Michael Hansen # # Permission to use, copy, modify, and distribute this software # for any purpose with or without fee is hereby granted, provided @@ -25,23 +25,41 @@ # displays in the statusbar the number of users and the limit of the channel, # with several settings for finetuning: # -# default settings: [Users: <users>(@<users_op>:+<users_voice>:<users_rest>)/<limit>(<limitusers>)] +# default settings: [Users: <users>(*<users_oper>:@<users_op>:+<users_voice>:<users_rest>)/<limit>(<limitusers>)] # "/<limit>(<limitusers>)" will only show when there is a limit set. # "(<limitusers>)" shows the difference between the limit and current # users (this can be negative if the limit is lower than users) # +# setting mh_sbuserinfo_format_group_begin (default '(') and +# setting mh_sbuserinfo_format_group_end' (default ')'); change the characters grouping +# details +# +# setting mh_sbuserinfo_format_sep (default ':'): change the : seperator to another string +# +# setting mh_sbuserinfo_format_div (default '/'): change the / divider to another string +# # setting mh_sbuserinfo_show_prefix (default 'Users: '): set/unset the prefix # in the window item # # setting mh_sbuserinfo_show_details (default ON): enable/disable showing a -# detailed breakout of users into ops, halfops, voice and normal +# detailed breakout of users into opers, ops, halfops, voice and normal # # setting mh_sbuserinfo_show_details_mode (default ON): enable/disable -# prefixing ops, halfops and voice with @%+ when details are enabled +# prefixing opers, ops, halfops and voice with *@%+ when details are enabled +# +# setting mh_sbuserinfo_format_mode_oper (default '*'), +# setting mh_sbuserinfo_format_mode_op (default '@'), +# setting mh_sbuserinfo_format_mode_ho (default '%%'), +# setting mh_sbuserinfo_format_mode_vo (default '+') and +# setting mh_sbuserinfo_format_mode_other (default ''): change the mode prefix +# for each of oper, op, halfdop, voice and others # # setting mh_sbuserinfo_show_details_halfop (default OFF): enable/disable # showing halfops when details are enabled # +# setting mh_sbuserinfo_show_details_oper (default ON): enable/disable +# showing opers when details are enabled +# # setting mh_sbuserinfo_show_details_difference (default ON): enable/disable # showing the "(<limitusers>)" # @@ -51,9 +69,13 @@ # setting mh_sbuserinfo_show_warning_limit (default ON): change the colour # of "<limit>" if channel is above, at or close to the limited amount of users # -# setting mh_sbuserinfo_show_warning_limit_percent (default 95): number in +# setting mh_sbuserinfo_show_warning_limit_percent (default 0): number in # percent (0-100) of users relative to the limit before a limit warning is -# triggered +# triggered (if set to 0 see mh_sbuserinfo_show_warning_limit_difference) +# +# setting mh_sbuserinfo_show_warning_limit_difference (default 5): when +# mh_sbuserinfo_show_warning_limit_percent is 0, use this absolute value +# as the difference warning trigger instead of percentage # # setting mh_sbuserinfo_warning_format (default '%Y'): the colour used for # warnings. see http://www.irssi.org/documentation/formats @@ -63,6 +85,15 @@ # see '/help statusbar' for more details and do not forget to '/save' # # history: +# +# v1.05 (20161106) +# added setting _show_details_oper and supporting code +# added setting _format_sep and supportingf code +# added setting _format_div and supporting code +# added setting _group_begin and _format_group_end and supporting code +# added setting _format_mode_oper, _format_mode_op, _format_mode_ho, _format_mode_vo and _format_mode_other, and supporting code +# added settting _show_warning_limit_difference and supporting code (changing _show_warning_limit_percent behavior) +# changed default of _show_warning_limit_percent from 95 to 0 # v1.04 (20151225) # added setting _show_details_difference and supporting code # changed _show_warning_limit_percent default from 90 to 95 @@ -96,7 +127,7 @@ use strict; use Irssi 20100403; use Irssi::TextUI; -our $VERSION = '1.04'; +our $VERSION = '1.05'; our %IRSSI = ( 'name' => 'mh_sbuserinfo', @@ -105,7 +136,7 @@ our %IRSSI = 'authors' => 'Michael Hansen', 'contact' => 'mh on IRCnet #help', 'url' => 'http://scripts.irssi.org / https://github.com/mh-source/irssi-scripts', - 'changed' => 'Fri Dec 25 17:14:34 CET 2015', + 'changed' => 'Sun Nov 6 20:37:05 CET 2016', ); ############################################################################## @@ -183,6 +214,7 @@ sub statusbar_userinfo my $users_op = 0; my $users_ho = 0; my $users_vo = 0; + my $users_oper = 0; my $warning_format = Irssi::settings_get_str('mh_sbuserinfo_warning_format'); for my $nick ($channel->nicks()) @@ -201,56 +233,84 @@ sub statusbar_userinfo { $users_vo++; } + + if ($nick->{'serverop'}) + { + $users_oper++; + } } - $format = $format . $users; + $format .= $users; + + my $format_sep = Irssi::settings_get_str('mh_sbuserinfo_format_sep'); + my $format_div = Irssi::settings_get_str('mh_sbuserinfo_format_div'); + + my $format_group_begin = Irssi::settings_get_str('mh_sbuserinfo_format_group_begin'); + my $format_group_end = Irssi::settings_get_str('mh_sbuserinfo_format_group_end'); if (Irssi::settings_get_bool('mh_sbuserinfo_show_details')) { - $format = $format . '('; + $format .= $format_group_begin; my $showmode = Irssi::settings_get_bool('mh_sbuserinfo_show_details_mode'); + if (Irssi::settings_get_bool('mh_sbuserinfo_show_details_oper')) + { + if ($showmode) + { + $format .= Irssi::settings_get_str('mh_sbuserinfo_format_mode_oper'); + } + + $format .= $users_oper . $format_sep + } + if (Irssi::settings_get_bool('mh_sbuserinfo_show_warning_opless') and (not $users_op)) { - $format = $format . $warning_format; + $format .= $warning_format; } if ($showmode) { - $format = $format . '@'; + $format .= Irssi::settings_get_str('mh_sbuserinfo_format_mode_op'); } - $format = $format . $users_op . '%n:'; + $format .= $users_op . '%n' . $format_sep; if (Irssi::settings_get_bool('mh_sbuserinfo_show_details_halfop')) { # # add halfops to ops so users calculation below matches # - $users_op = $users_op + $users_ho; + $users_op += $users_ho; if ($showmode) { - $format = $format . '%%'; + $format .= Irssi::settings_get_str('mh_sbuserinfo_format_mode_ho'); } - $format = $format . $users_ho . ':'; + $format .= $users_ho . $format_sep; + } + + if ($showmode) + { + $format .= Irssi::settings_get_str('mh_sbuserinfo_format_mode_vo');; } + $format .= $users_vo . $format_sep; + if ($showmode) { - $format = $format . '+'; + $format .= Irssi::settings_get_str('mh_sbuserinfo_format_mode_other');; } - $format = $format . $users_vo . ':' . ($users - ($users_op + $users_vo)) . ')'; + $format .= ($users - ($users_op + $users_vo)) . $format_group_end; } my $limit = $channel->{'limit'}; if ($limit) { - $format = $format . '/'; + $format .= $format_div; if (Irssi::settings_get_bool('mh_sbuserinfo_show_warning_limit')) { @@ -265,20 +325,39 @@ sub statusbar_userinfo $setting_percent = 0; } - my $percent = int(($users / $limit) * 100); + if ($setting_percent) + { + + my $percent = int(($users / $limit) * 100); - if ($percent >= $setting_percent) + if ($percent >= $setting_percent) + { + $format .= $warning_format; + } + } else { - $format = $format . $warning_format; + my $setting_percent = Irssi::settings_get_int('mh_sbuserinfo_show_warning_limit_difference'); + + my $difference = ($limit - $users); + + if ($setting_percent < 0) + { + $setting_percent = 0; + } + + if ($difference < $setting_percent) + { + $format .= $warning_format; + } } } if (Irssi::settings_get_bool('mh_sbuserinfo_show_details_difference')) { - $limit = $limit . '(' . ($limit - $users) . ')'; + $limit .= $format_group_begin . ($limit - $users) . $format_group_end; } - $format = $format . $limit . '%n'; + $format .= $limit . '%n'; } } } @@ -292,17 +371,26 @@ sub statusbar_userinfo # ############################################################################## -Irssi::settings_add_bool('mh_sbuserinfo', 'mh_sbuserinfo_show_details', 1); -Irssi::settings_add_bool('mh_sbuserinfo', 'mh_sbuserinfo_show_details_mode', 1); -Irssi::settings_add_bool('mh_sbuserinfo', 'mh_sbuserinfo_show_details_halfop', 0); -Irssi::settings_add_bool('mh_sbuserinfo', 'mh_sbuserinfo_show_warning_opless', 1); -Irssi::settings_add_bool('mh_sbuserinfo', 'mh_sbuserinfo_show_warning_limit', 1); -Irssi::settings_add_int( 'mh_sbuserinfo', 'mh_sbuserinfo_show_warning_limit_percent', 95); -Irssi::settings_add_str( 'mh_sbuserinfo', 'mh_sbuserinfo_warning_format', '%Y'); -Irssi::settings_add_str( 'mh_sbuserinfo', 'mh_sbuserinfo_show_prefix', 'Users: '); -Irssi::settings_add_bool('mh_sbuserinfo', 'mh_sbuserinfo_show_details_difference', 1); - -Irssi::statusbar_item_register('mh_sbuserinfo', '', 'statusbar_userinfo'); +Irssi::settings_add_bool('mh_sbuserinfo', 'mh_sbuserinfo_show_details', 1); +Irssi::settings_add_bool('mh_sbuserinfo', 'mh_sbuserinfo_show_details_mode', 1); +Irssi::settings_add_bool('mh_sbuserinfo', 'mh_sbuserinfo_show_details_halfop', 0); +Irssi::settings_add_bool('mh_sbuserinfo', 'mh_sbuserinfo_show_warning_opless', 1); +Irssi::settings_add_bool('mh_sbuserinfo', 'mh_sbuserinfo_show_warning_limit', 1); +Irssi::settings_add_int( 'mh_sbuserinfo', 'mh_sbuserinfo_show_warning_limit_percent', 0); +Irssi::settings_add_int( 'mh_sbuserinfo', 'mh_sbuserinfo_show_warning_limit_difference', 5); +Irssi::settings_add_str( 'mh_sbuserinfo', 'mh_sbuserinfo_warning_format', '%Y'); +Irssi::settings_add_str( 'mh_sbuserinfo', 'mh_sbuserinfo_show_prefix', 'Users: '); +Irssi::settings_add_bool('mh_sbuserinfo', 'mh_sbuserinfo_show_details_difference', 1); +Irssi::settings_add_bool('mh_sbuserinfo', 'mh_sbuserinfo_show_details_oper', 1); +Irssi::settings_add_str( 'mh_sbuserinfo', 'mh_sbuserinfo_format_sep', ':'); +Irssi::settings_add_str( 'mh_sbuserinfo', 'mh_sbuserinfo_format_div', '/'); +Irssi::settings_add_str( 'mh_sbuserinfo', 'mh_sbuserinfo_format_group_begin', '('); +Irssi::settings_add_str( 'mh_sbuserinfo', 'mh_sbuserinfo_format_group_end', ')'); +Irssi::settings_add_str( 'mh_sbuserinfo', 'mh_sbuserinfo_format_mode_oper', '*'); +Irssi::settings_add_str( 'mh_sbuserinfo', 'mh_sbuserinfo_format_mode_op', '@'); +Irssi::settings_add_str( 'mh_sbuserinfo', 'mh_sbuserinfo_format_mode_ho', '%%'); +Irssi::settings_add_str( 'mh_sbuserinfo', 'mh_sbuserinfo_format_mode_vo', '+'); +Irssi::settings_add_str( 'mh_sbuserinfo', 'mh_sbuserinfo_format_mode_other', ''); Irssi::signal_add_last('channel sync', 'statusbar_redraw'); Irssi::signal_add_last('channel mode changed', 'statusbar_redraw'); @@ -312,6 +400,8 @@ Irssi::signal_add_last('nicklist remove', 'statusbar_redraw'); Irssi::signal_add_last('setup changed', 'signal_setup_changed_last'); Irssi::signal_add_last('window changed', 'signal_window_changed_last'); +Irssi::statusbar_item_register('mh_sbuserinfo', '', 'statusbar_userinfo'); + 1; ############################################################################## diff --git a/scripts/nickserv.pl b/scripts/nickserv.pl index c1d9ce8..ff2738d 100644 --- a/scripts/nickserv.pl +++ b/scripts/nickserv.pl @@ -24,7 +24,7 @@ use strict; use Irssi; use vars qw($VERSION %IRSSI); -$VERSION = "1.10"; +$VERSION = "1.11"; %IRSSI = ( authors => 'Geert Hauwaerts', @@ -32,37 +32,47 @@ $VERSION = "1.10"; name => 'nickserv.pl', description => 'This script will authorize you into NickServ.', license => 'GNU General Public License', - url => 'http://irssi.hauwaerts.be/nickserv.pl', + url => 'https://github.com/irssi/scripts.irssi.org/blob/master/scripts/nickserv.pl', + changed => 'Di 17. Jan 19:32:45 CET 2017', ); +my $irssidir = Irssi::get_irssi_dir(); + my @nickservnet = (); -my $nickservnet_file = "nickserv.networks"; +my $nickservnet_file = "$irssidir/nickserv.networks"; my @nickservauth = (); -my $nickservauth_file = "nickserv.auth"; +my $nickservauth_file = "$irssidir/nickserv.auth"; -my $irssidir = Irssi::get_irssi_dir(); +my @nickservpostcmd = (); +my $nickservpostcmd_file = "$irssidir/nickserv.postcmd"; my $help = <<EOF; Usage: (all on one line) /NICKSERV [addnet <ircnet> <services\@host>] [addnick <ircnet> <nickname> <password>] + [addpostcmd <ircnet> <nickname> <command>] [delnet <ircnet>] [delnick <ircnet> <nick>] - [help listnet listnick] - -addnet: Add a new network into the NickServ list. -addnick: Add a new nickname into the NickServ list. -delnet: Delete a network from the NickServ list. -delnick: Delete a nickname from the NickServ list. -listnet: Display the contents of the NickServ network list. -listnick: Display the contents of the NickServ nickname list. -help: Display this useful little helptext. + [delpostcmd <ircnet> <nick>] + [help listnet listnick listpostcmd] + +addnet: Add a new network into the NickServ list. +addnick: Add a new nickname into the NickServ list. +addpostcmd: Add a new post auth command for nickname into the NickServ list. +delnet: Delete a network from the NickServ list. +delnick: Delete a nickname from the NickServ list. +delpostcmd: Deletes all post auth commands for the given nickame. +listnet: Display the contents of the NickServ network list. +listnick: Display the contents of the NickServ nickname list. +listpostcmd: Display the contents of the NickServ postcmd list. +help: Display this useful little helptext. Examples: (all on one line) /NICKSERV addnet Freenode NickServ\@services. /NICKSERV addnick Freenode Geert mypass +/NICKSERV addpostcmd Freenode Geert ^MSG ChanServ invite #heaven /NICKSERV delnet Freenode /NICKSERV delnick Freenode Geert @@ -74,19 +84,25 @@ EOF Irssi::theme_register([ 'nickserv_usage_network', '%R>>%n %_NickServ:%_ Insufficient parameters: Usage "%_/NICKSERV addnet ircnet services@host%_".', 'nickserv_usage_nickname', '%R>>%n %_NickServ:%_ Insufficient parameters: Usage "%_/NICKSERV addnick ircnet nickname password%_".', + 'nickserv_usage_postcmd', '%R>>%n %_NickServ:%_ Insufficient parameters: Usage "%_/NICKSERV addpostcmd ircnet nickname command%_".', 'nickserv_delusage', '%R>>%n %_NickServ:%_ Insufficient parameters: Usage "%_/NICKSERV delnet ircnet%_".', 'nickserv_delnickusage', '%R>>%n %_NickServ:%_ Insufficient parameters: Usage "%_/NICKSERV delnick ircnet nickname%_".', - 'nickserv_delled', '%R>>%n %_NickServ:%_ Deleted %_$0%_ and his nicknames from the NickServ ircnet list.', - 'nickserv_delled_nick', '%R>>%n %_NickServ:%_ Deleted %_$1%_ from the NickServ list on $0.', + 'nickserv_delpostcmdusage', '%R>>%n %_NickServ:%_ Insufficient parameters: Usage "%_/NICKSERV delpostcmd ircnet nickname%_".', + 'nickserv_delled', '%R>>%n %_NickServ:%_ Deleted %_$0%_ and it\'s nicknames and post commands from the NickServ ircnet list.', + 'nickserv_delled_nick', '%R>>%n %_NickServ:%_ Deleted %_$1%_ and it\'s post commands from the NickServ list on $0.', + 'nickserv_delled_postcmd', '%R>>%n %_NickServ:%_ Deleted all entries for %_$1%_ from the NickServ postcmd list on $0.', 'nickserv_nfound', '%R>>%n %_NickServ:%_ The NickServ ircnet %_$0%_ could not be found.', 'nickserv_nfound_nick', '%R>>%n %_NickServ:%_ The NickServ nickname %_$0%_ could not be found on $1.', + 'nickserv_nfound_postcmd', '%R>>%n %_NickServ:%_ The NickServ post commands for nickname %_$1%_ could not be found on $0.', 'nickserv_usage', '%R>>%n %_NickServ:%_ Insufficient parameters: Use "%_/NICKSERV help%_" for further instructions.', 'nickserv_no_net', '%R>>%n %_NickServ:%_ Unknown Irssi ircnet %_$0%_.', 'nickserv_wrong_host', '%R>>%n %_NickServ:%_ Malformed services hostname %_$0%_.', 'already_loaded_network', '%R>>%n %_NickServ:%_ The ircnet %_$0%_ already exists in the NickServ ircnet list, please remove it first.', 'nickserv_loaded_nick', '%R>>%n %_NickServ:%_ The nickname %_$0%_ already exists in the NickServ authlist on %_$1%_, please remove it first.', 'nickserv_not_loaded_net', '%R>>%n %_NickServ:%_ The ircnet %_$0%_ doesn\'t exists in the NickServ ircnet list, please add it first.', + 'nickserv_not_loaded_nick', '%R>>%n %_NickServ:%_ The nickname %_$0%_ doesn\'t exists in the NickServ authlist on %_$1%_, please add it first.', 'saved_nickname', '%R>>%n %_NickServ:%_ Added nickname %_$1%_ on %_$0%_.', + 'saved_postcmd', '%R>>%n %_NickServ:%_ Added postcmd %_$1%_ on %_$0%_: %_%2%_.', 'network_print', '$[!-2]0 $[20]1 $2', 'password_request', '%R>>%n %_NickServ:%_ Auth Request from NickServ on %_$0%_.', 'password_accepted', '%R>>%n %_NickServ:%_ Password accepted on %_$0%_.', @@ -96,6 +112,9 @@ Irssi::theme_register([ 'nickname_print', '$[!-2]0 $[20]1 $[18]2 $3', 'nickname_info', '%_ # Ircnet Nickname Password%_', 'nickname_empty', '%R>>%n %_NickServ:%_ Your NickServ authlist is empty.', + 'postcmd_print', '$[!-2]0 $[20]1 $[18]2 $3', + 'postcmd_info', '%_ # Ircnet Nickname Postcmd%_', + 'postcmd_empty', '%R>>%n %_NickServ:%_ Your NickServ postcmd list is empty.', 'nickserv_help', '$0', 'saved_network', '%R>>%n %_NickServ:%_ Added services mask "%_$1%_" on %_$0%_.', 'nickserv_loaded', '%R>>%n %_Scriptinfo:%_ Loaded $0 version $1 by $2.' @@ -105,139 +124,171 @@ sub load_nickservnet { my ($file) = @_; - @nickservnet = (); + @nickservnet = load_file($file, sub { + my $new_nsnet = new_nickserv_network(@_); + return undef if ($new_nsnet->{name} eq "" || $new_nsnet->{host} eq ""); + return $new_nsnet; + }); +} - if (-e $file) { - local *F; - open(F, "<", $file); - local $/ = "\n"; +sub save_nickservnet { - while (<F>) { - chop; - my $new_nsnet = new_nickserv_network(split("\t")); - - if (($new_nsnet->{name} ne "") && ($new_nsnet->{host} ne "")) { - push(@nickservnet, $new_nsnet); - } - } - - close(F); - } + save_file($nickservnet_file, \@nickservnet, \&nickservnet_as_list); } -sub save_nickservnet { +sub new_nickserv_network { - my ($file) = @_; + return { + name => shift, + host => shift + }; +} - return unless scalar @nickservnet; # there's nothing to save +sub nickservnet_as_list { - if (-e $file) { - local *F; - open(F, ">", $file); + my $nickserv_net = shift; - for (my $n = 0; $n < @nickservnet; ++$n) { - print(F join("\t", $nickservnet[$n]->{name}, $nickservnet[$n]->{host}) . "\n"); - } - - close(F); - } else { - create_network_file($file); - save_nickservnet($file); - } + return ( + $nickserv_net->{name}, + $nickserv_net->{host} + ); } -sub create_network_file { - +sub load_nickservnick { + my ($file) = @_; - - open(F, ">", $file) or die "Can't create $file. Reason: $!"; + + @nickservauth = load_file($file, sub { + my $new_nsnick = new_nickserv_nick(@_); + + return undef if ($new_nsnick->{ircnet} eq "" || $new_nsnick->{nick} eq "" || $new_nsnick->{pass} eq ""); + return $new_nsnick; + }); } -sub new_nickserv_network { +sub save_nickservnick { - my $nsnet = {}; + save_file($nickservauth_file, \@nickservauth, \&nickserv_nick_as_list); +} - $nsnet->{name} = shift; - $nsnet->{host} = shift; +sub new_nickserv_nick { - return $nsnet; + return { + ircnet => shift, + nick => shift, + pass => shift + }; } -sub load_nickservnick { +sub nickserv_nick_as_list { + + my $nickserv_nick = shift; + return ( + $nickserv_nick->{ircnet}, + $nickserv_nick->{nick}, + $nickserv_nick->{pass} + ); +} + +sub load_nickservpostcmd { my ($file) = @_; - @nickservauth = (); + @nickservpostcmd = load_file($file, sub { + my $new_postcmd = new_postcmd(@_); - if (-e $file) { - local *F; - open(F, "<" ,$file); - local $/ = "\n"; + return undef if ($new_postcmd->{ircnet} eq "" || $new_postcmd->{nick} eq "" || $new_postcmd->{postcmd} eq ""); + return $new_postcmd; + }); +} - while (<F>) { - chop; - my $new_nsnick = new_nickserv_nick(split("\t")); - - if (($new_nsnick->{ircnet} ne "") && ($new_nsnick->{nick} ne "") && ($new_nsnick->{pass} ne "")) { - push(@nickservauth, $new_nsnick); - } - } - - close(F); - } +sub save_nickservpostcmd { + + save_file($nickservpostcmd_file, \@nickservpostcmd, \&postcmd_as_list); } -sub save_nickservnick { +sub new_postcmd { - my ($file) = @_; + return { + ircnet => shift, + nick => shift, + postcmd => shift + }; +} - return unless scalar @nickservauth; # there's nothing to save +sub postcmd_as_list { + my $postcmd = shift; - if (-e $file) { - local *F; - open(F, ">", $file); + return ( + $postcmd->{ircnet}, + $postcmd->{nick}, + $postcmd->{postcmd} + ); +} - for (my $n = 0; $n < @nickservauth; ++$n) { - print(F join("\t", $nickservauth[$n]->{ircnet}, $nickservauth[$n]->{nick}, $nickservauth[$n]->{pass}) . "\n"); - } - - close(F); - } else { - create_nick_file($file); - save_nickservnick($file); +# file: filename to be read +# parse_line_fn: receives array of entries of a single line as input, should +# return parsed data object or undef in the data is incomplete +# returns: parsed data array +sub load_file { + + my ($file, $parse_line_fn) = @_; + my @parsed_data = (); + + if (-e $file) { + open(my $fh, "<", $file); + local $/ = "\n"; + + while (<$fh>) { + chomp; + my $data = $parse_line_fn->(split("\t")); + push(@parsed_data, $data) if $data; } -} -sub create_nick_file { - - my ($file) = @_; - - my $umask = umask 0077; # save old umask - open(F, ">", $file) or die "Can't create $file. Reason: $!"; - umask $umask; + close($fh); + } + + return @parsed_data; } -sub new_nickserv_nick { +# file: filename to be written, is created accessable only by the user +# data_ref: array ref of data entries +# serialize_fn: receives a data reference and should return an array or tuples +# for that data that will be serialized into one line +sub save_file { + + my ($file, $data_ref, $serialize_fn) = @_; + + create_private_file($file) unless -e $file; - my $nsnick = {}; + open(my $fh, ">", $file) or die "Can't create $file. Reason: $!"; - $nsnick->{ircnet} = shift; - $nsnick->{nick} = shift; - $nsnick->{pass} = shift; + for my $data (@$data_ref) { + print($fh join("\t", $serialize_fn->($data)), "\n"); + } + + close($fh); +} - return $nsnick; +sub create_private_file { + + my ($file) = @_; + my $umask = umask 0077; # save old umask + open(my $fh, ">", $file) or die "Can't create $file. Reason: $!"; + close($fh); + umask $umask; } sub add_nickname { - + my ($network, $nickname, $password) = split(" ", $_[0], 3); - my ($correct_network, $correct_nickname, $correct_password); + my ($correct_network, $correct_nickname); if ($network eq "" || $nickname eq "" || $password eq "") { Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_usage_nickname'); return; } - + if ($network) { if (!already_loaded_net($network)) { Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_not_loaded_net', $network); @@ -246,7 +297,7 @@ sub add_nickname { $correct_network = 1; } } - + if ($nickname) { if (already_loaded_nick($nickname, $network)) { Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_loaded_nick', $nickname, $network); @@ -255,28 +306,64 @@ sub add_nickname { $correct_nickname = 1; } } - + if ($correct_network && $correct_nickname) { push(@nickservauth, new_nickserv_nick($network, $nickname, $password)); - save_nickservnick("$irssidir/$nickservauth_file"); - + save_nickservnick(); + Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'saved_nickname', $network, $nickname); } } +sub add_postcmd { + + my ($network, $nickname, $postcmd) = split(" ", $_[0], 3); + my ($correct_network, $correct_nickname); + + if ($network eq "" || $nickname eq "" || $postcmd eq "") { + Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_usage_postcmd'); + return; + } + + if ($network) { + if (!already_loaded_net($network)) { + Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_not_loaded_net', $network); + return; + } else { + $correct_network = 1; + } + } + + if ($nickname) { + if (!already_loaded_nick($nickname, $network)) { + Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_not_loaded_nick', $nickname, $network); + return; + } else { + $correct_nickname = 1; + } + } + + if ($correct_network && $correct_nickname) { + push(@nickservpostcmd, new_postcmd($network, $nickname, $postcmd)); + save_nickservpostcmd(); + + Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'saved_postcmd', $network, $nickname, $postcmd); + } +} + sub add_network { - + my ($network, $hostname) = split(" ", $_[0], 2); my ($correct_net, $correct_host); - + if ($network eq "" || $hostname eq "") { Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_usage_network'); return; } - + if ($network) { my ($ircnet) = Irssi::chatnet_find($network); - + if (!$ircnet) { Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_no_net', $network); return; @@ -287,7 +374,7 @@ sub add_network { $correct_net = 1; } } - + if ($hostname) { if ($hostname !~ /^[.+a-zA-Z0-9_-]{1,}@[.+a-zA-Z0-9_-]{1,}$/) { Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_wrong_host', $hostname); @@ -296,11 +383,11 @@ sub add_network { $correct_host = 1; } } - + if ($correct_net && $correct_host) { push(@nickservnet, new_nickserv_network($network, $hostname)); - save_nickservnet("$irssidir/$nickservnet_file"); - + save_nickservnet(); + Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'saved_network', $network, $hostname); } } @@ -308,56 +395,32 @@ sub add_network { sub already_loaded_net { my ($ircnet) = @_; - my $loaded = check_loaded_net($ircnet); - - if ($loaded > -1) { - return 1; - } - - return 0; -} - -sub check_loaded_net { - - my ($ircnet) = @_; $ircnet = lc($ircnet); - for (my $loaded = 0; $loaded < @nickservnet; ++$loaded) { - return $loaded if (lc($nickservnet[$loaded]->{name}) eq $ircnet); + for my $loaded (@nickservnet) { + return 1 if (lc($loaded->{name}) eq $ircnet); } - - return -1; + + return 0; } sub already_loaded_nick { - my ($nickname, $network) = @_; - my $loaded = check_loaded_nick($nickname, $network); - - if ($loaded > -1) { - return 1; - } - - return 0 -} -sub check_loaded_nick { - - my ($nickname, $network) = @_; - $nickname = lc($nickname); $network = lc($network); - - for (my $loaded = 0; $loaded < @nickservauth; ++$loaded) { - return $loaded if (lc($nickservauth[$loaded]->{nick}) eq $nickname && lc ($nickservauth[$loaded]->{ircnet}) eq $network); + + for my $loaded (@nickservauth) { + return 1 if (lc($loaded->{nick}) eq $nickname && + lc($loaded->{ircnet}) eq $network); } - - return -1; + + return 0; } sub list_net { - + if (@nickservnet == 0) { Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'network_empty'); } else { @@ -370,7 +433,7 @@ sub list_net { } sub list_nick { - + if (@nickservauth == 0) { Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickname_empty'); } else { @@ -382,8 +445,21 @@ sub list_nick { } } +sub list_postcmd { + + if (@nickservpostcmd == 0) { + Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'postcmd_empty'); + } else { + Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'postcmd_info'); + + for (my $n = 0; $n < @nickservpostcmd ; ++$n) { + Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'postcmd_print', $n, $nickservpostcmd[$n]->{ircnet}, $nickservpostcmd[$n]->{nick}, $nickservpostcmd[$n]->{postcmd}); + } + } +} + sub nickserv_notice { - + my ($server, $data, $nick, $address) = @_; my ($target, $text) = $data =~ /^(\S*)\s:(.*)/; @@ -392,14 +468,14 @@ sub nickserv_notice { if ($text =~ /^(?:If this is your nickname, type|Please identify via|Type) \/msg NickServ (?i:identify)/ || $text =~ /^This nickname is registered and protected. If it is your/ || $text =~ /This nickname is registered\. Please choose a different nickname/) { my $password = get_password($server->{tag}, $server->{nick}); - + if ($password == -1) { Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'password_request', $server->{tag}); Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_nfound_nick', $server->{nick}, $server->{tag}); Irssi::signal_stop(); return; } - + Irssi::signal_stop(); Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'password_request', $server->{tag}); $server->command("^MSG NickServ IDENTIFY $password"); @@ -442,6 +518,7 @@ sub nickserv_notice { } elsif ($text =~ /^Password accepted - you are now recognized/ || $text =~ /^You are now identified for/) { Irssi::signal_stop(); Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'password_accepted', $server->{tag}); + run_postcmds($server, $server->{tag}, $server->{nick}) } elsif ($text =~ /^Password Incorrect/ || $text =~ /^Password incorrect./) { Irssi::signal_stop(); Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'password_wrong', $server->{tag}); @@ -449,24 +526,39 @@ sub nickserv_notice { } } +sub run_postcmds { + my ($server, $ircnet, $nick) = @_; + return if @nickservpostcmd == 0; + + for my $cmd (@nickservpostcmd) { + if ($ircnet eq $cmd->{ircnet} && + $nick eq $cmd->{nick} && + $cmd->{postcmd}) { + $server->command($cmd->{postcmd}); + } + } +} + sub is_nickserv { - + my ($net, $host) = @_; for (my $loaded = 0; $loaded < @nickservnet; ++$loaded) { - return 1 if (lc($nickservnet[$loaded]->{name}) eq lc($net) && lc($nickservnet[$loaded]->{host}) eq lc($host)); + return 1 if (lc($nickservnet[$loaded]->{name}) eq lc($net) && + lc($nickservnet[$loaded]->{host}) eq lc($host)); } return 0; } sub get_password { - + my ($ircnet, $nick) = @_; - + for (my $loaded = 0; $loaded < @nickservauth; ++$loaded) { - return $nickservauth[$loaded]->{pass} if (lc($nickservauth[$loaded]->{ircnet}) eq lc($ircnet) && lc($nickservauth[$loaded]->{nick}) eq lc($nick)); + return $nickservauth[$loaded]->{pass} if (lc($nickservauth[$loaded]->{ircnet}) eq lc($ircnet) && + lc($nickservauth[$loaded]->{nick}) eq lc($nick)); } - + return -1; } @@ -485,47 +577,76 @@ sub del_network { $ircnetindex = 1; } } - + if ($ircnetindex) { @nickservnet = grep {lc($_->{name}) ne lc($ircnet)} @nickservnet; @nickservauth = grep {lc($_->{ircnet}) ne lc($ircnet)} @nickservauth; + @nickservpostcmd = grep {lc($_->{ircnet}) ne lc($ircnet)} @nickservpostcmd; Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_delled', $ircnet); - save_nickservnet("$irssidir/$nickservnet_file"); - save_nickservnick("$irssidir/$nickservauth_file"); + save_nickservnet(); + save_nickservnick(); + save_nickservpostcmd(); } else { Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_nfound', $ircnet); } } sub del_nickname { - + my ($ircnet, $nickname) = split(" ", $_[0], 2); my ($nickindex); - + if ($ircnet eq "" || $nickname eq "") { Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_delnickusage'); return; } for (my $index = 0; $index < @nickservauth; ++$index) { - if (lc($nickservauth[$index]->{ircnet}) eq lc($ircnet) && lc($nickservauth[$index]->{nick}) eq lc($nickname)) { + if (lc($nickservauth[$index]->{ircnet}) eq lc($ircnet) && + lc($nickservauth[$index]->{nick}) eq lc($nickname)) { $nickindex = splice(@nickservauth, $index, 1); - } + } } if ($nickindex) { + @nickservpostcmd = grep {lc($_->{ircnet}) ne lc($ircnet) || + lc($_->{nick}) ne lc($nickname)} + @nickservpostcmd; + Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_delled_nick', $ircnet, $nickname); - save_nickservnick("$irssidir/$nickservauth_file"); + save_nickservnick(); + save_nickservpostcmd(); } else { Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_nfound_nick', $ircnet, $nickname); } } +sub del_postcmd { + + my ($ircnet, $nickname) = split(" ", $_[0], 2); + + if ($ircnet eq "" || $nickname eq "") { + Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_delpostcmdusage'); + return; + } + + my $size_before = scalar(@nickservpostcmd); + @nickservpostcmd = grep { !( lc($_->{ircnet}) eq lc($ircnet) && lc($_->{nick}) eq lc($nickname) )} @nickservpostcmd; + my $size_after = scalar(@nickservpostcmd); + + if ($size_before != $size_after) { + Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_delled_postcmd', $ircnet, $nickname); + save_nickservpostcmd(); + } else { + Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_nfound_postcmd', $ircnet, $nickname); + } +} + sub nickserv_runsub { - + my ($data, $server, $item) = @_; $data =~ s/\s+$//g; - + if ($data) { Irssi::command_runsub('nickserv', $data, $server, $item); } else { @@ -533,32 +654,31 @@ sub nickserv_runsub { } } -load_nickservnet("$irssidir/$nickservnet_file"); -load_nickservnick("$irssidir/$nickservauth_file"); +load_nickservnet($nickservnet_file); +load_nickservnick($nickservauth_file); +load_nickservpostcmd($nickservpostcmd_file); Irssi::command_bind('nickserv', 'nickserv_runsub'); Irssi::command_bind('ns', 'nickserv_runsub'); -Irssi::command_bind('nickserv addnet', 'add_network'); -Irssi::command_bind('ns addnet', 'add_network'); - -Irssi::command_bind('nickserv addnick', 'add_nickname'); -Irssi::command_bind('ns addnick', 'add_nickname'); - -Irssi::command_bind('nickserv listnet', 'list_net'); -Irssi::command_bind('ns listnet', 'list_net'); - -Irssi::command_bind('nickserv listnick', 'list_nick'); -Irssi::command_bind('ns listnick', 'list_nick'); - -Irssi::command_bind('nickserv delnet', 'del_network'); -Irssi::command_bind('ns delnet', 'del_network'); - -Irssi::command_bind('nickserv delnick', 'del_nickname'); -Irssi::command_bind('ns delnick', 'del_nickname'); - Irssi::command_bind('nickserv help' => sub { Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_help', $help) }); Irssi::command_bind('ns help' => sub { Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_help', $help) }); +# "command binding" -> "function name" mapping +for my $cmd (( + ['addnet' => 'add_network'], + ['addnick' => 'add_nickname'], + ['addpostcmd' => 'add_postcmd'], + ['listnet' => 'list_net'], + ['listnick' => 'list_nick'], + ['listpostcmd' => 'list_postcmd'], + ['delnet' => 'del_network'], + ['delnick' => 'del_nickname'], + ['delpostcmd' => 'del_postcmd'], +)) { + Irssi::command_bind("nickserv $cmd->[0]", $cmd->[1]); + Irssi::command_bind("ns $cmd->[0]", $cmd->[1]); +} + Irssi::signal_add('event notice', 'nickserv_notice'); Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_loaded', $IRSSI{name}, $VERSION, $IRSSI{authors}); diff --git a/scripts/pager.pl b/scripts/pager.pl index 32f0902..50d7899 100644 --- a/scripts/pager.pl +++ b/scripts/pager.pl @@ -2,14 +2,16 @@ use strict; use Irssi 20020121.2020 (); -$VERSION = "1.1"; + +use vars qw/$VERSION %IRSSI/; +$VERSION = "1.2"; %IRSSI = ( authors => 'Jean-Yves Lefort', contact => 'jylefort\@brutele.be', name => 'pager', description => 'Notifies people if they send you a private message or a DCC chat offer while you are away; runs a shell command configurable via /set if they page you', license => 'BSD', - changed => '$Date: 2003/01/27 09:45:16 $ ', + changed => '$Date: 2017/03/06 $ ', ); # note: @@ -33,6 +35,9 @@ $VERSION = "1.1"; # # changes: # +# 2017-03-06 release 1.2 +# * declaration $VERSION %IRSSI +# # 2003-01-27 release 1.1 # * notices and commands are now optional # diff --git a/scripts/perlalias.pl b/scripts/perlalias.pl new file mode 100644 index 0000000..b546688 --- /dev/null +++ b/scripts/perlalias.pl @@ -0,0 +1,288 @@ +=head1 perlalias.pl - Perl-based command aliases for irssi + +This script provides an /alias-like function that uses small pieces of perl code to carry out the commands. + +=head2 Usage + +Install into irssi script directory and /run perlalias and/or put into autorun. + +=head2 Commands + +=over + +=item /perlalias + +Syntax: /perlalias [[[-]<alias>] [<code>]] + +Parameters: A name of the alias and the perl code to execute. + +If you prepend the alias with -, it will remove the alias. + +If you give no arguments, the list of defined aliases will be displayed. + +Description: + +Creates or updates an alias. Like any perl code, multiple statements must be separated using ; characters. +No replacement of parameter values is done: any $text is a perl variable. + +The arguments given to the /alias when typed are put into $_ and are also split on whitespace and put into @_. +In addition, the variables $server and $witem will refer to the active server and window item respectively. + +Examples: + +/PERLALIAS UNACT foreach my $w (Irssi::windows) { $w->activity(0); } + +=back + +=over + +=item /perlunalias + +Syntax: /perlunalias <alias> + +Parameters: The alias to remove. + +Description: + +Removes the given alias. + +=back + +Additionally, all aliases added are linked to perlalias.pl: if it is unloaded, the aliases will be removed. + +Aliases can be saved and reloaded with the usual /save and /reload (including autosave). Saved aliases are loaded at script load. + +=head2 ChangeLog + +=over + +=item 1.0 + +First version. + +=back + +=cut + +use strict; +use warnings FATAL => qw(all); +use Irssi; +use Irssi::Irc; +use Carp (); + +#use Cwd; +use POSIX qw(strftime); + +{ package Irssi::Nick; } # Keeps trying to look for this package but for some reason it doesn't get loaded. + +our $VERSION = '1.2'; +our %IRSSI = ( + authors => 'aquanight', + contact => 'aquanight@gmail.com', + name => 'perlalias', + description => 'Quickly create commands from short perl blocks', + license => 'public domain' + ); + +# Bound commands +my %cmds; # Contains command entries. The entry has three items: + # textcmd => Plaintext of the command to execute, which is used for loading/saving + # cmpcmd => Compiled command, for executing. + # tag => Our tag which we need to remove the command + +# Package we execute all the commands within, to keep them away from our bits. +package Irssi::Script::perlalias::aliaspkg { +} + +sub DESTROY { + Symbol::delete_package("Irssi::Script::perlalias::aliaspkg::"); +} + +# Alias executor +sub exec_perlalias { + my ($cmd, $data, $server, $witem) = @_; + exists $cmds{$cmd} or return; + defined $cmds{$cmd}->{cmpcmd} or return; + local $_ = $data; + $cmds{$cmd}->{cmpcmd}->($server, $witem, split / +/, $data); +} + +# Bind a command +sub setup_command { + my ($cmd, $data) = @_; + # Compile the script. + my $code = qq{package Irssi::Scripts::perlalias::aliaspkg;\nno warnings;\nsub {my \$server = shift; my \$witem = shift;\n#line 1 "perlalias $cmd"\n$data}\n}; + my $proc = eval $code; + if ($@) { + Irssi::printformat(MSGLEVEL_CLIENTERROR, perlalias_compile_error => $cmd); + Irssi::print(MSGLEVEL_CLIENTERROR, $@); + return ""; + } + if (exists($cmds{$cmd})) { + my $entry = $cmds{$cmd}; + $entry->{textcmd} = $data; + $entry->{cmpcmd} = $proc; + } + else { + my $entry = {}; + my $tag = sub { exec_perlalias $cmd, @_; }; + foreach my $existing_cmd (Irssi::commands()) { + if ($existing_cmd->{cmd} eq $cmd) { + Irssi::print_format(MSGLEVEL_CLIENTERROR, perlalias_cmd_in_use => $cmd); + return ""; + } + } + $entry->{textcmd} = $data; + $entry->{cmpcmd} = $proc; + $entry->{tag} = sub { exec_perlalias $cmd, @_; }; + Irssi::command_bind($cmd, $entry->{tag}); + $cmds{$cmd} = $entry; + } + return 1; +} + +sub remove_command { + my ($cmd) = @_; + if (exists($cmds{$cmd})) { + my $entry = $cmds{$cmd}; + $entry->{tag}//die "Missing the tag we need to remove the alias!!!"; + Irssi::command_unbind($cmd, $entry->{tag}); + delete $cmds{$cmd}; + return 1; + } + else { + Irssi::printformat(MSGLEVEL_CLIENTERROR, perlalias_not_found => $cmd); + return ""; + } +} + +sub list_commands { + my ($prefix) = @_; + my @whichones = sort grep /^\Q$prefix\E/, keys %cmds; + Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'perlaliaslist_header'); + for my $name (@whichones) { + my $entry = $cmds{$name}; + Irssi::printformat(MSGLEVEL_CLIENTCRAP, perlaliaslist_line => $name, $entry->{textcmd}); + } +} + +sub cmd_perlalias { + my ($data, $server, $witem) = @_; + my ($command, $script) = split /\s+/, $data, 2; + if (($command//"") eq "") { + list_commands ""; + } + elsif ($command =~ m/^-/) { + $command = substr($command, 1); + if (remove_command($command)) { Irssi::printformat(MSGLEVEL_CLIENTNOTICE, perlalias_removed => $command); } + } + elsif (($script//"") eq "") { + list_commands $command; + } + else { + if (setup_command($command, $script)) { Irssi::printformat(MSGLEVEL_CLIENTNOTICE, perlalias_added => $command); } + } + +} + +sub cmd_perlunalias { + my ($data, $server, $witem) = @_; + if (remove_command $data) { Irssi::printformat(MSGLEVEL_CLIENTNOTICE, perlalias_removed => $data); } +} + +sub sig_setup_saved { + my ($main, $auto) = @_; + my $file = Irssi::get_irssi_dir() . "/perlalias"; + open my $fd, '>', $file or return; + for my $cmd (keys %cmds) { + my $entry = $cmds{$cmd}; + printf $fd "%s\t%s\n", $cmd, $entry->{textcmd}; + } + close $fd; +} + +sub sig_setup_reread { + my $file = Irssi::get_irssi_dir() . "/perlalias"; + open my $fd, "<", $file or return; + my $ln; + my %newcmds; + while (defined($ln = <$fd>)) { + chomp $ln; + my ($cmd, $script) = split /\t/, $ln, 2; + if (exists $newcmds{$cmd}) { + Irssi::print(MSGLEVEL_CLIENTERROR, "There is a duplicate record in the PerlAlias save file."); + Irssi::print(MSGLEVEL_CLIENTERROR, "Offending alias: $cmd"); + Irssi::print(MSGLEVEL_CLIENTERROR, "Previous definition: " . $newcmds{$cmd}); + Irssi::print(MSGLEVEL_CLIENTERROR, "Duplicate definition: $script"); + } + $newcmds{$cmd} = $script; + } + # Scrub the existing list. Update existings, remove any that aren't in the config, then we'll add any that's new. + my @currentcmds = keys %cmds; + for my $cmd (@currentcmds) { + if (exists $newcmds{$cmd}) { + setup_command($cmd, $newcmds{$cmd}); + } + else { + remove_command($cmd); + } + delete $newcmds{$cmd}; + } + # By this point all that should be in newcmds is any ... new commands. + for my $cmd (keys %newcmds) { + setup_command($cmd, $newcmds{$cmd}); + } + close $fd; +} + +sub sig_complete_perlalias { + my ($lst, $win, $word, $line, $want_space) = @_; + $word//return; + $line//return; + $lst//return; + if ($line ne '') { + my $def = $cmds{$line}; + $def//return; + push @$lst, $def->{textcmd}; + Irssi::signal_stop(); + } + else { + push @$lst, (grep /^\Q$word\E/i, keys %cmds); + Irssi::signal_stop(); + } +} + +sub sig_complete_perlunalias { + my ($lst, $win, $word, $line, $want_space) = @_; + $lst//return; + $word//return; + push @$lst, (grep /^\Q$word\E/i, keys %cmds); +} + +Irssi::signal_register({"complete command " => [qw(glistptr_char* Irssi::UI::Window string string intptr)]}); +Irssi::signal_add("complete command perlalias" => \&sig_complete_perlalias); +Irssi::signal_add("complete command perlunalias" => \&sig_complete_perlunalias); + +Irssi::signal_add("setup saved" => \&sig_setup_saved); +Irssi::signal_add("setup reread" => \&sig_setup_reread); + +Irssi::command_bind(perlalias => \&cmd_perlalias); +Irssi::command_bind(perlunalias => \&cmd_perlunalias); + +my %formats = ( + # $0 Name of alias + 'perlalias_compile_error' => '{error Error compiling alias {hilight $0}:}', + # $0 Name of alias + 'perlalias_exec_error' => '{error Error executing alias {hilight $0}:}', + 'perlalias_cmd_in_use' => 'Command {hilight $0} is already in use', + 'perlalias_added' => 'PerlAlias {hilight $0} added', + 'perlalias_removed' => 'PerlAlias {hilight $0} removed', + 'perlalias_not_found' => 'PerlAlias {hilight $0} not found', + 'perlaliaslist_header' => '%#PerlAliases:', + # $0 Name of alias, $1 alias text + 'perlaliaslist_line' => '%#$[10]0 $1', +); + +Irssi::theme_register([%formats]); + +sig_setup_reread; diff --git a/scripts/postpone.pl b/scripts/postpone.pl index 72e0a90..11011f2 100644 --- a/scripts/postpone.pl +++ b/scripts/postpone.pl @@ -5,7 +5,7 @@ use strict; use vars qw($VERSION %IRSSI); -$VERSION = "20030208"; +$VERSION = "20170204"; %IRSSI = ( authors => "Stefan 'tommie' Tomanek", contact => "stefan\@pico.ruhr.de", @@ -37,6 +37,8 @@ sub show_help() { Display this help /postpone flush <nick> Flush postponed messages to <nick> +/postpone discard <nick> + Discard postponed messages to <nick> /postpone list List postponed messages "; @@ -85,11 +87,11 @@ sub cmd_postpone ($$$) { my @arg = split(/ /, $args); if (scalar(@arg) < 1) { #foo - } elsif ($arg[0] eq 'flush' && defined $arg[1]) { + } elsif (($arg[0] eq 'discard' || $arg[0] eq 'flush') && defined $arg[1]) { return unless ($witem && $witem->{type} eq "CHANNEL"); while (scalar(@{$messages{$server->{tag}}{$witem->{name}}{$arg[1]}}) > 0) { my $msg = pop @{$messages{$server->{tag}}{$witem->{name}}{$arg[1]}}; - $server->command('MSG '.$witem->{name}.' '.$msg); + $server->command('MSG '.$witem->{name}.' '.$msg) if $arg[0] eq 'flush'; } } elsif ($arg[0] eq 'list') { my $text; diff --git a/scripts/print_signals.pl b/scripts/print_signals.pl new file mode 100644 index 0000000..dadd9eb --- /dev/null +++ b/scripts/print_signals.pl @@ -0,0 +1,280 @@ +# print_signals.pl โ Irssi script to help with inspecting signals +# +# ยฉ 2017 martin f. krafft <madduck@madduck.net> +# Released under the MIT licence. +# +### Usage: +# +# /script load print_signals +# +# and then use e.g. tail -F /tmp/irssi_signals.log outside of irssi. +# +### Settings: +# +# /set print_signals_to_file ["/tmp/irssi_signals.log"] +# Set the file to which to log all signals and their data +# +# /set print_signals_limit_regexp [""] +# Specify a regexp to limit the signals being captured, e.g. "^window". +# Default is no limit. +# +# # Please note that exclude takes precedence over limit: +# +# /set print_signals_exclude_regexp ["print text|key press|textbuffer"] +# Specify a regexp to exclude signals from being captured. Default is not to +# fire on signals about printing text or key presses. +# + +use strict; +use warnings; +use vars qw($VERSION %IRSSI); +use Irssi; +use Data::Dumper; + +$VERSION = '1.0'; + +%IRSSI = ( + authors => 'martin f. krafft', + contact => 'madduck@madduck.net', + name => 'print signals debugger', + description => 'hooks into every signal and writes the information provided to a file', + license => 'MIT', + changed => '2017-02-03' +); + +Irssi::settings_add_str('print_signals', 'print_signals_to_file', '/tmp/irssi_signals.log'); +Irssi::settings_add_str('print_signals', 'print_signals_limit_regexp', ''); +Irssi::settings_add_str('print_signals', 'print_signals_exclude_regexp', + 'print text|key press|textbuffer|rawlog|log written'); + +$Data::Dumper::Sortkeys = 1; +$Data::Dumper::Pad = ' '; + +sub signal_handler { + my $signal = shift(@_); + my $limitre = Irssi::settings_get_str('print_signals_limit_regexp'); + return unless $signal =~ qr/$limitre/; + my $excludere = Irssi::settings_get_str('print_signals_exclude_regexp'); + return if $signal =~ qr/$excludere/; + my @names = shift(@_); + my @data = shift(@_); + my $outfile = Irssi::settings_get_str('print_signals_to_file'); + my $fh; + if (!open($fh, '>>', $outfile)) { + Irssi::print("cannot append to log file $outfile while handling signal '$signal'"); + return; + }; + print $fh "\n== $signal ==\n"; + print $fh Data::Dumper->Dump(@data, @names); + close($fh); +} + +# TODO: a programmatic way to extract the list of all signals from Irssi +# itself, along with descriptive names of the arguments. +my $signals = <<_END; +# curl -s https://raw.githubusercontent.com/irssi/irssi/master/docs/signals.txt | sed -rne 's,^ ",",p' +"gui exit" +"gui dialog", char *type, char *text +"send command", char *command, SERVER_REC, WI_ITEM_REC +"chat protocol created", CHAT_PROTOCOL_REC +"chat protocol updated", CHAT_PROTOCOL_REC +"chat protocol destroyed", CHAT_PROTOCOL_REC +"channel created", CHANNEL_REC, int automatic +"channel destroyed", CHANNEL_REC +"chatnet created", CHATNET_REC +"chatnet destroyed", CHATNET_REC +"commandlist new", COMMAND_REC +"commandlist remove", COMMAND_REC +"error command", int err, char *cmd +"send command", char *args, SERVER_REC, WI_ITEM_REC +"send text", char *line, SERVER_REC, WI_ITEM_REC +"command "<cmd>, char *args, SERVER_REC, WI_ITEM_REC +"default command", char *args, SERVER_REC, WI_ITEM_REC +"ignore created", IGNORE_REC +"ignore destroyed", IGNORE_REC +"ignore changed", IGNORE_REC +"log new", LOG_REC +"log remove", LOG_REC +"log create failed", LOG_REC +"log locked", LOG_REC +"log started", LOG_REC +"log stopped", LOG_REC +"log rotated", LOG_REC +"log written", LOG_REC, char *line +"module loaded", MODULE_REC, MODULE_FILE_REC +"module unloaded", MODULE_REC, MODULE_FILE_REC +"module error", int error, char *text, char *rootmodule, char *submodule +"tls handshake finished", SERVER_REC, TLS_REC +"nicklist new", CHANNEL_REC, NICK_REC +"nicklist remove", CHANNEL_REC, NICK_REC +"nicklist changed", CHANNEL_REC, NICK_REC, char *old_nick +"nicklist host changed", CHANNEL_REC, NICK_REC +"nicklist gone changed", CHANNEL_REC, NICK_REC +"nicklist serverop changed", CHANNEL_REC, NICK_REC +"pidwait", int pid, int status +"query created", QUERY_REC, int automatic +"query destroyed", QUERY_REC +"query nick changed", QUERY_REC, char *orignick +"window item name changed", WI_ITEM_REC +"query address changed", QUERY_REC +"query server changed", QUERY_REC, SERVER_REC +"rawlog", RAWLOG_REC, char *data +"server looking", SERVER_REC +"server connected", SERVER_REC +"server connecting", SERVER_REC, ulong *ip +"server connect failed", SERVER_REC +"server disconnected", SERVER_REC +"server quit", SERVER_REC, char *msg +"server sendmsg", SERVER_REC, char *target, char *msg, int target_type +"setup changed" +"setup reread", char *fname +"setup saved", char *fname, int autosaved +"ban type changed", char *bantype +"channel joined", CHANNEL_REC +"channel wholist", CHANNEL_REC +"channel sync", CHANNEL_REC +"channel topic changed", CHANNEL_REC +"ctcp msg", SERVER_REC, char *args, char *nick, char *addr, char *target +"ctcp msg "<cmd>, SERVER_REC, char *args, char *nick, char *addr, char *target +"default ctcp msg", SERVER_REC, char *args, char *nick, char *addr, char *target +"ctcp reply", SERVER_REC, char *args, char *nick, char *addr, char *target +"ctcp reply "<cmd>, SERVER_REC, char *args, char *nick, char *addr, char *target +"default ctcp reply", SERVER_REC, char *args, char *nick, char *addr, char *target +"ctcp action", SERVER_REC, char *args, char *nick, char *addr, char *target +"awaylog show", LOG_REC, int away_msgs, int filepos +"server nick changed", SERVER_REC +"event connected", SERVER_REC +"server cap ack "<cmd>, SERVER_REC +"server cap nak "<cmd>, SERVER_REC +"server cap end", SERVER_REC +"server sasl failure", SERVER_REC, char *reason +"server sasl success", SERVER_REC +"server event", SERVER_REC, char *data, char *sender_nick, char *sender_address +"event "<cmd>, SERVER_REC, char *args, char *sender_nick, char *sender_address +"default event", SERVER_REC, char *data, char *sender_nick, char *sender_address +"whois default event", SERVER_REC, char *args, char *sender_nick, char *sender_address +"server incoming", SERVER_REC, char *data +"redir "<cmd>, SERVER_REC, char *args, char *sender_nick, char *sender_address +"server lag", SERVER_REC +"server lag disconnect", SERVER_REC +"massjoin", CHANNEL_REC, GSList of NICK_RECs +"ban new", CHANNEL_REC, BAN_REC +"ban remove", CHANNEL_REC, BAN_REC, char *setby +"channel mode changed", CHANNEL_REC, char *setby +"nick mode changed", CHANNEL_REC, NICK_REC, char *setby, char *mode, char *type +"user mode changed", SERVER_REC, char *old +"away mode changed", SERVER_REC +"netsplit server new", SERVER_REC, NETSPLIT_SERVER_REC +"netsplit server remove", SERVER_REC, NETSPLIT_SERVER_REC +"netsplit new", NETSPLIT_REC +"netsplit remove", NETSPLIT_REC +"dcc ctcp "<cmd>, char *args, DCC_REC +"default dcc ctcp", char *args, DCC_REC +"dcc unknown ctcp", char *args, char *sender, char *sendaddr +"dcc reply "<cmd>, char *args, DCC_REC +"default dcc reply", char *args, DCC_REC +"dcc unknown reply", char *args, char *sender, char *sendaddr +"dcc chat message", DCC_REC, char *msg +"dcc created", DCC_REC +"dcc destroyed", DCC_REC +"dcc connected", DCC_REC +"dcc rejecting", DCC_REC +"dcc closed", DCC_REC +"dcc request", DCC_REC, char *sendaddr +"dcc request send", DCC_REC +"dcc chat message", DCC_REC, char *msg +"dcc transfer update", DCC_REC +"dcc get receive", DCC_REC +"dcc error connect", DCC_REC +"dcc error file create", DCC_REC, char *filename +"dcc error file open", char *nick, char *filename, int errno +"dcc error get not found", char *nick +"dcc error send exists", char *nick, char *filename +"dcc error unknown type", char *type +"dcc error close not found", char *type, char *nick, char *filename +"autoignore new", SERVER_REC, AUTOIGNORE_REC +"autoignore remove", SERVER_REC, AUTOIGNORE_REC +"flood", SERVER_REC, char *nick, char *host, int level, char *target +"notifylist new", NOTIFYLIST_REC +"notifylist remove", NOTIFYLIST_REC +"notifylist joined", SERVER_REC, char *nick, char *user, char *host, char *realname, char *awaymsg +"notifylist away changed", SERVER_REC, char *nick, char *user, char *host, char *realname, char *awaymsg +"notifylist left", SERVER_REC, char *nick, char *user, char *host, char *realname, char *awaymsg +"proxy client connecting", CLIENT_REC +"proxy client connected", CLIENT_REC +"proxy client disconnected", CLIENT_REC +"proxy client command", CLIENT_REC, char *args, char *data +"proxy client dump", CLIENT_REC, char *data +"gui print text", WINDOW_REC, int fg, int bg, int flags, char *text, TEXT_DEST_REC +"gui print text finished", WINDOW_REC +"complete word", GList * of char*, WINDOW_REC, char *word, char *linestart, int *want_space +"irssi init read settings" +"exec new", PROCESS_REC +"exec remove", PROCESS_REC, int status +"exec input", PROCESS_REC, char *text +"message public", SERVER_REC, char *msg, char *nick, char *address, char *target +"message private", SERVER_REC, char *msg, char *nick, char *address, char *target +"message own_public", SERVER_REC, char *msg, char *target +"message own_private", SERVER_REC, char *msg, char *target, char *orig_target +"message join", SERVER_REC, char *channel, char *nick, char *address +"message part", SERVER_REC, char *channel, char *nick, char *address, char *reason +"message quit", SERVER_REC, char *nick, char *address, char *reason +"message kick", SERVER_REC, char *channel, char *nick, char *kicker, char *address, char *reason +"message nick", SERVER_REC, char *newnick, char *oldnick, char *address +"message own_nick", SERVER_REC, char *newnick, char *oldnick, char *address +"message invite", SERVER_REC, char *channel, char *nick, char *address +"message topic", SERVER_REC, char *channel, char *topic, char *nick, char *address +"keyinfo created", KEYINFO_REC +"keyinfo destroyed", KEYINFO_REC +"print text", TEXT_DEST_REC *dest, char *text, char *stripped +"theme created", THEME_REC +"theme destroyed", THEME_REC +"window hilight", WINDOW_REC +"window dehilight", WINDOW_REC +"window activity", WINDOW_REC, int old_level +"window item hilight", WI_ITEM_REC +"window item activity", WI_ITEM_REC, int old_level +"window item new", WINDOW_REC, WI_ITEM_REC +"window item remove", WINDOW_REC, WI_ITEM_REC +"window item moved", WINDOW_REC, WI_ITEM_REC, WINDOW_REC +"window item changed", WINDOW_REC, WI_ITEM_REC +"window item server changed", WINDOW_REC, WI_ITEM_REC +"window created", WINDOW_REC +"window destroyed", WINDOW_REC +"window changed", WINDOW_REC, WINDOW_REC old +"window changed automatic", WINDOW_REC +"window server changed", WINDOW_REC, SERVER_REC +"window refnum changed", WINDOW_REC, int old +"window name changed", WINDOW_REC +"window history changed", WINDOW_REC, char *oldname +"window level changed", WINDOW_REC +"default event numeric", SERVER_REC, char *data, char *nick, char *address +"message irc op_public", SERVER_REC, char *msg, char *nick, char *address, char *target +"message irc own_wall", SERVER_REC, char *msg, char *target +"message irc own_action", SERVER_REC, char *msg, char *target +"message irc action", SERVER_REC, char *msg, char *nick, char *address, char *target +"message irc own_notice", SERVER_REC, char *msg, char *target +"message irc notice", SERVER_REC, char *msg, char *nick, char *address, char *target +"message irc own_ctcp", SERVER_REC, char *cmd, char *data, char *target +"message irc ctcp", SERVER_REC, char *cmd, char *data, char *nick, char *address, char *target +"message irc mode", SERVER_REC, char *channel, char *nick, char *addr, char *mode +"message dcc own", DCC_REC *dcc, char *msg +"message dcc own_action", DCC_REC *dcc, char *msg +"message dcc own_ctcp", DCC_REC *dcc, char *cmd, char *data +"message dcc", DCC_REC *dcc, char *msg +"message dcc action", DCC_REC *dcc, char *msg +"message dcc ctcp", DCC_REC *dcc, char *cmd, char *data +"gui key pressed", int key +"beep" +"gui print text after finished", WINDOW_REC, LINE_REC *line, LINE_REC *prev_line +"gui textbuffer line removed", TEXTBUFFER_VIEW_REC *view, LINE_REC *line, LINE_REC *prev_line +_END + +foreach my $sigline (split(/\n/, $signals)) { + my ($sig, @args) = split(/, /, $sigline); + $sig =~ y/"//d; + Irssi::signal_add_first($sig, sub { + signal_handler($sig, \@args, \@_); + } + ); +}; diff --git a/scripts/reorder.pl b/scripts/reorder.pl index 7bec6b8..ce82fa4 100644 --- a/scripts/reorder.pl +++ b/scripts/reorder.pl @@ -1,150 +1,161 @@ -# Save window layout to an arbitrary file and load layouts upon demand
-# Useful for being able to temporarily reorder your windows and then reverting to your "normal" layout
-# Also useful as an easy way to reorder your windows
-#
-# A special thanks to billnye, Zed` and Bazerka for their help
-#
-# Usage:
-# /layout_save filename
-# Saves the layout to the textfile "filename.layout"
-# /layout_load filename
-# Loads the layout from the textfile "filename.layout"
-# /set layout_savepath path
-# Use to set a default path for layouts
-#
-# TODO:
-# Check the layout file for a number used twice
-#
-
-use strict;
-use Irssi;
-use Data::Dumper;
-use vars qw($VERSION %IRSSI);
-
-%IRSSI = (
- authors => "Isaac G",
- contact => "irssi\@isaac.otherinbox.com",
- name => "reorder",
- description => "Reordering windows based on a textfile.",
- license => "GPL",
-);
-
-sub doFilenameFixing
-{
- my ($filename) = @_;
- unless ($filename)
- {
- print "No filename specified!";
- return;
- }
-
- $filename = glob($filename);
-
- if ($filename =~ /\//)
- {
- unless ($filename =~ /^\//)
- {
- print "I don't like /'s in filenames. Unless you want to specify an absolute path.";
- return;
- }
- # Let it go?
- }
-
- $filename .= '.layout' unless ($filename =~ /.layout$/);
-
- my $path = Irssi::settings_get_str('layout_savepath');
- $path .= '/' unless ($path =~ /\/$/);
- $filename = $path . $filename unless ($filename =~ /\//);
-
- return $filename;
-}
-
-sub canReadFile
-{
- my ($filename) = @_;
- unless (-f $filename)
- {
- print "No such file $filename";
- return;
- }
- unless (-r $filename)
- {
- print "Can not read file $filename";
- return;
- }
- return 1;
-}
-
-# Save a list of refnum and window info to file
-sub cmd_layout_save
-{
- my ($filename, $data, $more) = @_;
- my $FH;
-
- $filename = doFilenameFixing($filename);
- return unless ($filename);
-
- unless(open $FH, ">", $filename)
- {
- print "Can not open $filename";
- return;
- }
-
- # Order by ref. Print ref and an id tag
- for my $win (sort {$a->{'refnum'} <=> $b->{'refnum'}} Irssi::windows())
- {
- my $id = $win->{'name'} ? $win->{'name'} : $win->{'active'}->{'name'} . ":" . $win->{'active'}->{'server'}->{'tag'};
- printf $FH "%d\t%s\n", $win->{'refnum'}, $id;
- }
- close $FH;
- print "Layout saved to $filename";
-}
-
-# Load a list and use it to reorder
-sub cmd_layout_load
-{
- # Check filename supplied, exists and readable
- my ($filename, $data, $more) = @_;
- $filename = doFilenameFixing($filename);
- return unless ($filename);
-
- return unless canReadFile($filename);
-
- my @layout;
- my ($ref, $id, $FH);
-
- # Pull the refnum and id
- unless(open $FH, "<", $filename)
- {
- print "Can not open file $filename.";
- return;
- }
- while (my $line = <$FH>)
- {
- chomp $line;
- my ($ref, $id) = split(/\t/, $line, 2);
- next unless ($ref and $id);
-
- push @layout, {refnum => $ref, id => $id};
- }
- close $FH;
-
- # For each layout item from the file, find the window and set it's ref to that number
- for my $position (sort {$a->{'refnum'} <=> $b->{'refnum'}} @layout)
- {
- for my $win (Irssi::windows())
- {
- $id = $win->{'name'} ? $win->{'name'} : $win->{'active'}->{'name'} . ":" . $win->{'active'}->{'server'}->{'tag'};
- if ($id eq $position->{'id'})
- {
- $win->set_refnum($position->{'refnum'});
- last;
- }
- }
- }
-}
-
-Irssi::settings_add_str('misc', 'layout_savepath', Irssi::get_irssi_dir());
-
-Irssi::command_bind( 'layout_save', 'cmd_layout_save' );
-Irssi::command_bind( 'layout_load', 'cmd_layout_load' );
\ No newline at end of file +# Save window layout to an arbitrary file and load layouts upon demand +# Useful for being able to temporarily reorder your windows and then reverting to your "normal" layout +# Also useful as an easy way to reorder your windows +# +# A special thanks to billnye, Zed` and Bazerka for their help +# +# Usage: +# /layout_save filename +# Saves the layout to the textfile "filename.layout" +# /layout_load filename +# Loads the layout from the textfile "filename.layout" +# +# TODO: +# Check the layout file for a number used twice +# On script load, run a layout_load +# On channel join, run load: channel joined +# + +use strict; +use Irssi; +use Data::Dumper; +use vars qw($VERSION %IRSSI); +use POSIX 'strftime'; + +%IRSSI = ( + authors => "Isaac Good", + contact => "irssi\@isaacgood.com", + name => "reorder", + description => "Reordering windows based on a textfile.", + license => "GPL", +); +$VERSION = '1.0'; + +# Map user input to a valid filename +sub GetFilename +{ + my ($filename) = @_; + + # On no input, use a default filename. + unless (length($filename)) + { + my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); + $filename = POSIX::strftime("%y%m%d", $sec, $min, $hour, $mday, $mon, $year); + # If you prefer not having datestamped filenames, uncomment: + # $filename = "default"; + } + + # Use glob expansion to match things like ~/ + my $glob = glob($filename); + $filename = $glob if $glob; + + # Only handle directories when using an absolute path. + if ($filename =~ /\// and $filename !~ /^\//) + { + print "I don't like /'s in filenames. Unless you want to specify an absolute path."; + return; + } + + # Add a file extension + $filename .= '.layout' unless ($filename =~ /\.layout$/); + + # Use get_irssi_dir() unless using an absolute path + if ($filename !~ /\//) { + my $path = Irssi::get_irssi_dir(); + $path .= '/' unless ($path =~ /\/$/); + $filename = $path . $filename; + } + + return $filename; +} + +# Check a filename exists and can be read. +sub CanReadFile +{ + my ($filename) = @_; + unless (-f $filename) + { + print "No such file $filename"; + return 0; + } + unless (-r $filename) + { + print "Can not read file $filename"; + return 0; + } + return 1; +} + +# Save the current layout to file +sub CmdLayoutSave +{ + my ($filename, $data, $more) = @_; + my $FH; + + $filename = GetFilename($filename); + return unless ($filename); + + unless(open $FH, ">", $filename) + { + print "Can not open $filename"; + return; + } + + # Order by ref. Print ref and an id tag + for my $win (sort {$a->{'refnum'} <=> $b->{'refnum'}} Irssi::windows()) + { + my $id = $win->{'name'} ? $win->{'name'} : $win->{'active'}->{'name'}; + my $tag = $win->{'active'}->{'server'}->{'tag'}; + printf $FH "%d\t%s:%s\n", $win->{'refnum'}, $id, $tag; + } + close $FH; + print "Layout saved to $filename"; +} + +# Load a list and use it to reorder +sub CmdLayoutLoad +{ + my ($filename, $data, $more) = @_; + $filename = GetFilename($filename); + + return unless ($filename); + return unless CanReadFile($filename); + + my @layout; + my ($ref, $id, $tag, $FH); + + # Pull the refnum and id + unless(open $FH, "<", $filename) + { + print "Can not open file $filename."; + return; + } + while (my $line = <$FH>) + { + chomp $line; + my ($ref, $id) = split(/\t/, $line, 2); + next unless ($ref and $id); + + push @layout, {refnum => $ref, id => $id}; + } + close $FH; + + # For each layout item from the file, find the window and set it's ref to that number + for my $position (sort {$a->{'refnum'} <=> $b->{'refnum'}} @layout) + { + for my $win (Irssi::windows()) + { + $id = $win->{'name'} ? $win->{'name'} : $win->{'active'}->{'name'}; + $tag = $win->{'active'}->{'server'}->{'tag'}; + $id .= ":" . $tag; + if ($id eq $position->{'id'}) + { + $win->set_refnum($position->{'refnum'}); + last; + } + } + } +} + +Irssi::command_bind( 'layout_save', 'CmdLayoutSave' ); +Irssi::command_bind( 'layout_load', 'CmdLayoutLoad' ); diff --git a/scripts/rud_emotes.pl b/scripts/rud_emotes.pl index e783d75..de55cba 100644 --- a/scripts/rud_emotes.pl +++ b/scripts/rud_emotes.pl @@ -1,4 +1,4 @@ -# Copyright (C) 2015 Dawid Lekawski +# Copyright (C) 2016 Dawid Lekawski # contact: xxrud0lf@gmail.com # # --- INFORMATION --- @@ -33,7 +33,7 @@ # notes: # # - script doesn't work with /msg target text; must be typed in a channel -# or query window +# or query window (from version 1.10 it works with /me command too) # # - Ctrl+O (ascii 15) at the beggining of your text turns off emote replacing # for this text @@ -41,20 +41,31 @@ # - remeber to escape "\" characters in emotes (just type it twice -> "\\"), # take a look at 'shrug' emote for reference # +# +# +# -- CHANGES: -- +# +# - script now works with /me command (action) +# +# - moved text output messages into nice and clean theme_register +# +# use strict; use warnings; use utf8; -use Irssi qw(signal_add signal_continue command_bind); +use Irssi qw(signal_add signal_continue command_bind theme_register + printformat); -our $VERSION = "1.00"; +our $VERSION = "1.10"; our %IRSSI = ( authors => "Dawid 'rud0lf' Lekawski", contact => 'rud0lf/IRCnet; rud0lf/freenode; xxrud0lf@gmail.com', name => 'emotes script', description => 'Replaces :emote_name: text in your sent messages into pre-defined emotes (unicode mostly).', - license => 'GPLv3' + license => 'GPLv3', + changed => 'Mon Nov 07 14:54:38 2016' ); my $pattern = ''; @@ -94,10 +105,18 @@ my %emotes = ( 'wink', 'โโฟโผ', 'gift', '(ยดใปฯใป)ใฃ็ฑ', 'success', '(โขฬแดโขฬ)ู', - 'whatever', 'โ_โ' + 'whatever', 'โ_โ', + 'run', 'แ(โ สฬฏโ)แ', + 'rock', '(ใ)\m/' ); sub init { + theme_register([ + 'rud_emotes_list', 'List of emotes:', + 'rud_emotes_emote', '* $[!15]0 : $1', + 'rud_emotes_total', 'Total of $0 emotes.' +]); + $pattern = join('|', keys %emotes); if ($pattern eq '') { $pattern = '!?'; @@ -127,31 +146,28 @@ sub sig_send_text { signal_continue($newline, $server, $witem); } -sub pad { - my ($txt, $cnt) = @_; +sub sig_command_me { + my ($line, $server, $witem) = @_; - if (length($txt) >= $cnt) { - return $txt; - } - - $txt .= " " x ($cnt - length($txt)); - return $txt; + return unless ($witem); + return unless ($witem->{type} eq "CHANNEL" or $witem->{type} eq "QUERY"); + + my $newline = process_emotes($line); + signal_continue($newline, $server, $witem); } sub cmd_emotes { my ($data, $server, $witem) = @_; - - Irssi::print('List of emotes:', MSGLEVEL_CLIENTCRAP); + + printformat(MSGLEVEL_CLIENTCRAP, 'rud_emotes_list'); foreach my $key (sort(keys %emotes)) { - my $emote = $emotes{$key}; - Irssi::print('* '. pad($key, 15) . ' : ' . $emote, MSGLEVEL_CLIENTCRAP); + printformat(MSGLEVEL_CLIENTCRAP, 'rud_emotes_emote', $key, $emotes{$key}); } - Irssi::print('Total of '.scalar(keys %emotes).' emotes.', MSGLEVEL_CLIENTCRAP); + printformat(MSGLEVEL_CLIENTCRAP, 'rud_emotes_total', scalar(keys %emotes)); } init(); signal_add("send text", "sig_send_text"); +signal_add("command me", "sig_command_me"); command_bind("emotes", "cmd_emotes"); - - diff --git a/scripts/trackbar22.pl b/scripts/trackbar22.pl index 30015a2..6c899b6 100644 --- a/scripts/trackbar22.pl +++ b/scripts/trackbar22.pl @@ -96,7 +96,7 @@ use Encode; use POSIX qw(strftime); use vars qw($VERSION %IRSSI); -$VERSION = "2.2"; # cb3189a33c8e5f9 +$VERSION = "2.3"; # 45c0adad4366edd %IRSSI = ( authors => 'Peter Leurs and Geert Hauwaerts', @@ -106,7 +106,6 @@ $VERSION = "2.2"; # cb3189a33c8e5f9 description => 'Shows a bar where you have last read a window.', license => 'GNU General Public License', url => 'http://www.pfoe.be/~peter/trackbar/', - changed => 'Fri Jan 23 23:59:11 2004', commands => 'trackbar', ); @@ -234,6 +233,7 @@ sub add_one_trackbar { $win->print(line($win->{width}), MSGLEVEL_NEVER); $view->set_bookmark_bottom('trackbar'); $unseen_trackbar{ $win->{_irssi} } = 1; + Irssi::signal_emit("window trackbar added", $win); $view->redraw; } @@ -253,6 +253,7 @@ sub win_ignored { my $view = shift || $win->view; return 1 unless $view->{buffer}{lines_count}; return 1 if $win->{name} eq '(status)' && !$config{use_status_window}; + no warnings 'uninitialized'; return 1 if grep { $win->{name} eq $_ || $win->{refnum} eq $_ || $win->get_active_name eq $_ } @{ $config{ignore_windows} }; return 0; @@ -271,10 +272,13 @@ sub sig_window_changed { sub trackbar_update_seen { my $win = shift; return unless $win; + return unless $unseen_trackbar{ $win->{_irssi} }; + my $view = $win->view; my $line = $view->get_bookmark('trackbar'); unless ($line) { delete $unseen_trackbar{ $win->{_irssi} }; + Irssi::signal_emit("window trackbar seen", $win); return; } my $startline = $view->{startline}; @@ -283,6 +287,7 @@ sub trackbar_update_seen { if ($startline->{info}{time} < $line->{info}{time} || $startline->{_irssi} == $line->{_irssi}) { delete $unseen_trackbar{ $win->{_irssi} }; + Irssi::signal_emit("window trackbar seen", $win); } } @@ -477,6 +482,8 @@ update_config(); Irssi::signal_add_last( 'mainwindow resized' => 'redraw_trackbars') unless $old_irssi; +Irssi::signal_register({'window trackbar added' => [qw/Irssi::UI::Window/]}); +Irssi::signal_register({'window trackbar seen' => [qw/Irssi::UI::Window/]}); Irssi::signal_register({'gui page scrolled' => [qw/Irssi::UI::Window/]}); Irssi::signal_add_last('gui page scrolled' => 'trackbar_update_seen'); diff --git a/scripts/translit.pl b/scripts/translit.pl index 478dd50..0a01506 100644 --- a/scripts/translit.pl +++ b/scripts/translit.pl @@ -1,7 +1,8 @@ use strict; -use vars qw(%IRSSI); +use vars qw(%IRSSI $VERSION); use Irssi; +$VERSION = "0.1"; %IRSSI = ( authors => 'dreg', contact => 'dreg@fine.lv', diff --git a/scripts/xdcc_autoget.pl b/scripts/xdcc_autoget.pl index 16f4639..57bcf65 100644 --- a/scripts/xdcc_autoget.pl +++ b/scripts/xdcc_autoget.pl @@ -50,7 +50,7 @@ use File::Copy; use Try::Tiny; use vars qw($VERSION %IRSSI); -$VERSION = "2.0"; +$VERSION = "2.1"; %IRSSI = ( name => "autoget", description => "XDCC Autoget, for automated searching and downloading of xdcc packs", @@ -143,7 +143,7 @@ sub ag_list sub ag_initserver #init server { - Irssi::signal_remove("server connected", "ag_server"); + Irssi::signal_remove("server connected", "ag_initserver"); $statusbarmessage = "Connected"; $server = $_[0]; if (!$runningflag) {Irssi::timeout_add_once(5000, sub { &ag_run; }, []);} @@ -270,11 +270,11 @@ sub ag_search #searches bots for packs $msgflag[$botcounter] = 0; #unset message flag so that ag_skip knows no important message has arrived if($episodicflag) { - my $searchterm; + my $searchterm = $terms[$termcounter[$botcounter]]; my @words = split(/#/, $terms[$termcounter[$botcounter]]); my $ep = sprintf("%.2d", $episode[$botcounter]); if ($#words > 0){$searchterm = "$words[0]$ep$words[1]";} - else {$searchterm = "$words[0] $ep";} + elsif ($words[0] ne $searchterm) {$searchterm = "$words[0] $ep";} ag_message("msg $bots[$botcounter] $findprefix $searchterm" ); push(@{$totags[$botcounter]}, Irssi::timeout_add_once($botdelay * 1000, sub { ag_skip($botcounter); } , [])); @@ -323,9 +323,9 @@ sub ag_getpacks #if ($m =~ m{#(\d+):}) my @temp = split(/[#,]/, $message); #split up the message into 'words' my $timeoutscleared = 0; - my $newpackflag = 1; foreach my $m (@temp) #find packs (#[NUMBER]: format) { + my $newpackflag = 1; if ($m =~ m/(\d+):(.+)/) { if (!$timeoutscleared) #reset timeouts if any packs are found @@ -339,7 +339,7 @@ sub ag_getpacks #if ($m =~ m{#(\d+):}) my $filename = $2; $filename =~ tr/[ ']/[__]/; if ($n eq "$bots[$botcounter] $1" or $n eq $filename) {$newpackflag = 0;} - last if ($n eq "$bots[$botcounter] $1"); + last if ($n eq "$bots[$botcounter] $1" or $n eq $filename); } if($newpackflag){push(@{$packs[$botcounter]}, $1);} #push all new pack numbers to list of packs } @@ -650,7 +650,6 @@ sub ag_parserem #parses remove arguments for deletion from file sub ag_add #add search terms { - ag_server; my @args = quotewords('\s+', 0, $_[0]); #split arguments (words in brackets not seperated) if ($#args < 0) { @@ -664,7 +663,6 @@ sub ag_add #add search terms sub ag_rem #remove ssearch terms { - ag_server; my @args = quotewords('\s+', 0, $_[0]); if ($#args < 0) { @@ -678,7 +676,6 @@ sub ag_rem #remove ssearch terms sub ag_botadd #add bots { - ag_server; my @args = quotewords('\s+', 0, $_[0]); if ($#args < 0) { @@ -692,7 +689,6 @@ sub ag_botadd #add bots sub ag_botrem #remove bots { - ag_server; my @args = quotewords('\s+', 0, $_[0]); if ($#args < 0) { |
