summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2022-07-04 17:38:57 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2022-07-04 17:38:57 +0000
commitc5cf332efe2282f9b1c0449f6e7f93d927cea434 (patch)
tree5186cdd9a9109dbe6b1251e0f095ec8eae46f1bb
parentInitial commit. (diff)
downloadirssi-scripts-c5cf332efe2282f9b1c0449f6e7f93d927cea434.tar.xz
irssi-scripts-c5cf332efe2282f9b1c0449f6e7f93d927cea434.zip
Adding upstream version 20220704.upstream/20220704upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
-rw-r--r--INDEX1480
-rw-r--r--scripts/0x0st.pl215
-rw-r--r--scripts/8-ball.pl131
-rw-r--r--scripts/Cirssi.pl802
-rw-r--r--scripts/UNIBG-autoident.pl242
-rw-r--r--scripts/XMMSInfo.pm308
-rw-r--r--scripts/accent.pl153
-rw-r--r--scripts/act.pl54
-rw-r--r--scripts/active_notice.pl207
-rw-r--r--scripts/active_notify.pl157
-rw-r--r--scripts/adv_windowlist.pl2988
-rw-r--r--scripts/ai.pl265
-rw-r--r--scripts/aidle.pl80
-rw-r--r--scripts/akftp.pl96
-rw-r--r--scripts/akilluser.pl92
-rw-r--r--scripts/alame.pl36
-rw-r--r--scripts/anotherway.pl54
-rw-r--r--scripts/antiplenk.pl47
-rw-r--r--scripts/apm.pl122
-rw-r--r--scripts/armeija.pl267
-rw-r--r--scripts/ascii.pl405
-rw-r--r--scripts/auto_away.pl90
-rw-r--r--scripts/auto_whois.pl80
-rw-r--r--scripts/autoaway.pl130
-rw-r--r--scripts/autochannel.pl69
-rw-r--r--scripts/autocycle.pl47
-rw-r--r--scripts/autolimit.pl53
-rw-r--r--scripts/autoopper.pl412
-rw-r--r--scripts/autorealname.pl304
-rw-r--r--scripts/autorejoinpunish.pl124
-rw-r--r--scripts/autoreminder.pl147
-rw-r--r--scripts/autoversion.pl25
-rw-r--r--scripts/autovoice.pl684
-rw-r--r--scripts/autowhois.pl39
-rw-r--r--scripts/autowrap.pl38
-rw-r--r--scripts/away.pl199
-rw-r--r--scripts/away2web.pl58
-rw-r--r--scripts/away_hilight_notice.pl215
-rw-r--r--scripts/away_verbose.pl234
-rw-r--r--scripts/awaybar.pl44
-rw-r--r--scripts/awaylogcnt.pl59
-rw-r--r--scripts/awayproxy.pl279
-rw-r--r--scripts/badword.pl163
-rw-r--r--scripts/ban.pl394
-rw-r--r--scripts/bandwidth.pl115
-rw-r--r--scripts/bansearch.pl421
-rw-r--r--scripts/bantime.pl110
-rw-r--r--scripts/beep.pl50
-rw-r--r--scripts/beep_beep.pl54
-rw-r--r--scripts/beepaway.pl41
-rw-r--r--scripts/bestoiber.pl61
-rw-r--r--scripts/bgta.pl284
-rw-r--r--scripts/binary.pl114
-rw-r--r--scripts/bitlbee_blist.pl77
-rw-r--r--scripts/bitlbee_join_notice.pl109
-rw-r--r--scripts/bitlbee_nick_change.pl72
-rw-r--r--scripts/bitlbee_tab_completion.pl88
-rw-r--r--scripts/bitlbee_typing_notice.pl349
-rw-r--r--scripts/blowjob.pl555
-rw-r--r--scripts/bmi.pl45
-rw-r--r--scripts/calc.pl30
-rw-r--r--scripts/callerid.pl135
-rw-r--r--scripts/cap_sasl.pl437
-rw-r--r--scripts/centericq.pl342
-rw-r--r--scripts/cgrep.pl192
-rw-r--r--scripts/challenge.pl106
-rw-r--r--scripts/chanact.pl756
-rw-r--r--scripts/chanfull.pl48
-rw-r--r--scripts/chanfull_duden.pl47
-rw-r--r--scripts/chankeys.pl569
-rw-r--r--scripts/chanpeak.pl182
-rw-r--r--scripts/chansearch.pl300
-rw-r--r--scripts/chanshare.pl122
-rw-r--r--scripts/chansort.pl79
-rw-r--r--scripts/chansync.pl75
-rw-r--r--scripts/chops.pl144
-rw-r--r--scripts/cleanpublic.pl41
-rw-r--r--scripts/clipboard.pl90
-rw-r--r--scripts/cloneprot.pl89
-rw-r--r--scripts/clones.pl55
-rw-r--r--scripts/colorize_nicks.pl217
-rw-r--r--scripts/colorkick.pl69
-rw-r--r--scripts/colorswap.pl47
-rw-r--r--scripts/connectcmd.pl165
-rw-r--r--scripts/copy.pl290
-rw-r--r--scripts/countdown.pl59
-rw-r--r--scripts/country.pl325
-rw-r--r--scripts/cp1250_kick.pl65
-rw-r--r--scripts/crapbuster.pl43
-rw-r--r--scripts/cron.pl306
-rw-r--r--scripts/ctrlact.pl1087
-rw-r--r--scripts/cwho.pl79
-rw-r--r--scripts/dancer_forwardfix.pl58
-rw-r--r--scripts/dancer_hide_477.pl54
-rw-r--r--scripts/dau.pl5750
-rw-r--r--scripts/dcc_ip.pl117
-rw-r--r--scripts/dccmove.pl43
-rw-r--r--scripts/dccself.pl38
-rw-r--r--scripts/dccstat.pl501
-rw-r--r--scripts/defaultchanmode.pl98
-rw-r--r--scripts/desktop-notify.pl120
-rw-r--r--scripts/df.pl157
-rw-r--r--scripts/dice.pl191
-rw-r--r--scripts/dictcomplete.pl78
-rw-r--r--scripts/dim_nicks.pl431
-rw-r--r--scripts/discord_unbridge.pl45
-rw-r--r--scripts/dispatch.pl26
-rw-r--r--scripts/doc.pl276
-rw-r--r--scripts/doublefilter.pl113
-rw-r--r--scripts/dtach_away.pl209
-rw-r--r--scripts/duckduckgo.pl256
-rw-r--r--scripts/elist.pl137
-rw-r--r--scripts/eliza.pl107
-rw-r--r--scripts/email_msgs.pl305
-rw-r--r--scripts/emaildb.pl131
-rw-r--r--scripts/emaildb1.0.pl0
-rw-r--r--scripts/eng_no_translate_dpryo.pl57
-rw-r--r--scripts/events.pl54
-rw-r--r--scripts/exec_clean.pl52
-rw-r--r--scripts/fakectcp.pl277
-rw-r--r--scripts/figlet.pl58
-rw-r--r--scripts/file.pl102
-rw-r--r--scripts/find.pl45
-rw-r--r--scripts/findbot.pl984
-rw-r--r--scripts/fleech.pl948
-rw-r--r--scripts/fnotify.pl140
-rw-r--r--scripts/follow.pl72
-rw-r--r--scripts/foo.pl75
-rw-r--r--scripts/foreach_user.pl59
-rw-r--r--scripts/fortune.pl124
-rw-r--r--scripts/forward.pl128
-rw-r--r--scripts/fpaste.pl264
-rw-r--r--scripts/freenode_filter.pl122
-rw-r--r--scripts/friends_peder.pl639
-rw-r--r--scripts/friends_shasta.pl2719
-rw-r--r--scripts/fserve.pl3578
-rw-r--r--scripts/fuckem.pl86
-rw-r--r--scripts/getop.pl387
-rw-r--r--scripts/gimmie.pl39
-rw-r--r--scripts/gitscriptassist.pl631
-rw-r--r--scripts/go.pl115
-rw-r--r--scripts/go2.pl495
-rw-r--r--scripts/google.pl224
-rw-r--r--scripts/gpgvalidator.pl224
-rw-r--r--scripts/grep.pl82
-rw-r--r--scripts/guts.pl21
-rw-r--r--scripts/hddtemp.pl183
-rw-r--r--scripts/hello.pl55
-rw-r--r--scripts/hide.pl177
-rw-r--r--scripts/hideauth.pl63
-rw-r--r--scripts/hideshow.pl319
-rw-r--r--scripts/highlite.pl113
-rw-r--r--scripts/hignore.pl78
-rw-r--r--scripts/hilightwin.pl85
-rw-r--r--scripts/history_search.pl146
-rw-r--r--scripts/hl.pl53
-rw-r--r--scripts/hlbot.pl217
-rw-r--r--scripts/hostname.pl157
-rw-r--r--scripts/iMPD.pl1179
-rw-r--r--scripts/identify-md5.pl168
-rw-r--r--scripts/idlesince.pl32
-rw-r--r--scripts/idletime.pl70
-rw-r--r--scripts/idonkey.pl1408
-rw-r--r--scripts/ignore_log.pl78
-rw-r--r--scripts/ignoreoc.pl65
-rw-r--r--scripts/il.pl133
-rw-r--r--scripts/imdb.pl115
-rw-r--r--scripts/intercept.pl217
-rw-r--r--scripts/invitejoin.pl298
-rw-r--r--scripts/ipupdate.pl39
-rw-r--r--scripts/irccomplete.pl213
-rw-r--r--scripts/ircgallery.pl257
-rw-r--r--scripts/ircgmessagenotify.pl218
-rw-r--r--scripts/ircops.pl44
-rw-r--r--scripts/ircsec.pl205
-rw-r--r--scripts/irssiBlaster.pl446
-rw-r--r--scripts/isdn.pl58
-rw-r--r--scripts/itime.pl47
-rw-r--r--scripts/ixmmsa.pl63
-rw-r--r--scripts/joininfo.pl1097
-rw-r--r--scripts/kban-referrals.pl372
-rw-r--r--scripts/kblamehost.pl65
-rw-r--r--scripts/keepnick.pl387
-rw-r--r--scripts/kenny.pl92
-rw-r--r--scripts/kernel.pl37
-rw-r--r--scripts/kicks.pl253
-rw-r--r--scripts/kill_fake_gets.pl131
-rw-r--r--scripts/kline_warning.pl147
-rw-r--r--scripts/l33tmusic.pl283
-rw-r--r--scripts/lastspoke.pl210
-rw-r--r--scripts/len.pl374
-rw-r--r--scripts/leodict.pl435
-rw-r--r--scripts/licq.pl66
-rw-r--r--scripts/linkchan.pl488
-rw-r--r--scripts/listen.pl163
-rw-r--r--scripts/loadavg.pl47
-rw-r--r--scripts/localize.pl1642
-rw-r--r--scripts/log2ansi.pl419
-rw-r--r--scripts/logcompress.pl24
-rw-r--r--scripts/logresume.pl253
-rw-r--r--scripts/ls.pl40
-rw-r--r--scripts/mailcheck_imap.pl566
-rw-r--r--scripts/mailcheck_mbox_flux.pl126
-rw-r--r--scripts/mailcheck_pop3_kimmo.pl120
-rw-r--r--scripts/mangle.pl721
-rw-r--r--scripts/map.pl129
-rw-r--r--scripts/mass_hilight_blocker.pl62
-rw-r--r--scripts/miodek.pl368
-rw-r--r--scripts/mkick.pl114
-rw-r--r--scripts/mkshorterlink.pl219
-rw-r--r--scripts/mldonkey_bandwidth.pl51
-rw-r--r--scripts/modelist-r.pl468
-rw-r--r--scripts/modelist.pl153
-rw-r--r--scripts/mood.pl202
-rw-r--r--scripts/morse.pl347
-rw-r--r--scripts/mouse.pl168
-rw-r--r--scripts/mpg123.pl86
-rw-r--r--scripts/multipaste.pl151
-rw-r--r--scripts/my_beep.pl61
-rw-r--r--scripts/mygoogle.pl114
-rw-r--r--scripts/myimdb.pl114
-rw-r--r--scripts/mysqlurllogger.pl82
-rw-r--r--scripts/nact.pl335
-rw-r--r--scripts/news.pl282
-rw-r--r--scripts/newsline.pl453
-rw-r--r--scripts/nickban.pl66
-rw-r--r--scripts/nickcolor.pl253
-rw-r--r--scripts/nickident.pl230
-rw-r--r--scripts/nickignore.pl49
-rw-r--r--scripts/nicklist.pl828
-rw-r--r--scripts/nickmix-c0ffee.pl89
-rw-r--r--scripts/nickmix_pasky.pl74
-rw-r--r--scripts/nickserv.pl684
-rw-r--r--scripts/niq.pl296
-rw-r--r--scripts/nm.pl693
-rw-r--r--scripts/nocaps.pl96
-rw-r--r--scripts/nocollide.pl118
-rw-r--r--scripts/noisyquery.pl33
-rw-r--r--scripts/nopl.pl66
-rw-r--r--scripts/norepeat.pl76
-rw-r--r--scripts/noteserve.pl89
-rw-r--r--scripts/noticemove.pl49
-rw-r--r--scripts/notonline.pl76
-rw-r--r--scripts/ogg123.pl95
-rw-r--r--scripts/oidenty.pl75
-rw-r--r--scripts/on.pl287
-rw-r--r--scripts/ontv.pl339
-rw-r--r--scripts/oops.pl90
-rw-r--r--scripts/oopsie.pl50
-rw-r--r--scripts/openurl.pl269
-rw-r--r--scripts/operit.pl320
-rw-r--r--scripts/operview.pl422
-rw-r--r--scripts/opnotice.pl56
-rw-r--r--scripts/opnotify.pl47
-rw-r--r--scripts/osd.pl313
-rw-r--r--scripts/page-c0ffee.pl116
-rw-r--r--scripts/page_reeler.pl47
-rw-r--r--scripts/pager.pl127
-rw-r--r--scripts/pangotext.pl253
-rw-r--r--scripts/paste-derwan.pl184
-rw-r--r--scripts/paste_derwan.pl381
-rw-r--r--scripts/paste_huggie.pl187
-rw-r--r--scripts/paste_kimmoke.pl110
-rw-r--r--scripts/pelix.pl235
-rw-r--r--scripts/people.pl2493
-rw-r--r--scripts/perlalias.pl1026
-rw-r--r--scripts/pggb_sound.pl251
-rw-r--r--scripts/phpdoc.pl134
-rw-r--r--scripts/poison.pl341
-rw-r--r--scripts/postpone.pl119
-rw-r--r--scripts/ppl.pl210
-rw-r--r--scripts/print_signals.pl319
-rw-r--r--scripts/q_username.pl26
-rw-r--r--scripts/query-connection-notifier.pl67
-rw-r--r--scripts/query.pl593
-rw-r--r--scripts/queryresume.pl64
-rw-r--r--scripts/quiet.pl90
-rw-r--r--scripts/quitrand.pl52
-rw-r--r--scripts/quiz.pl451
-rw-r--r--scripts/quizgr.pl655
-rw-r--r--scripts/quizmaster.pl354
-rw-r--r--scripts/rainbow.pl173
-rw-r--r--scripts/randaway.pl119
-rw-r--r--scripts/randname.pl46
-rw-r--r--scripts/relm.pl93
-rw-r--r--scripts/remote.pl91
-rw-r--r--scripts/repeat.pl144
-rw-r--r--scripts/resize_split.pl62
-rw-r--r--scripts/revolve.pl388
-rw-r--r--scripts/rk.pl53
-rw-r--r--scripts/romaji.pl273
-rw-r--r--scripts/romajibind.pl301
-rw-r--r--scripts/rot13.pl77
-rw-r--r--scripts/rotator.pl138
-rw-r--r--scripts/sana.pl66
-rw-r--r--scripts/sana_cmd.pl57
-rw-r--r--scripts/schwaebisch.pl191
-rw-r--r--scripts/screen_away.pl248
-rw-r--r--scripts/scripthelp.pl39
-rw-r--r--scripts/scriptinfo.pl118
-rw-r--r--scripts/scroller.pl97
-rw-r--r--scripts/seen.pl1198
-rw-r--r--scripts/servercomplete.pl85
-rw-r--r--scripts/seti.pl50
-rw-r--r--scripts/shortenurl.pl170
-rw-r--r--scripts/showhilight.pl32
-rw-r--r--scripts/showhost.pl68
-rw-r--r--scripts/showmode.pl83
-rw-r--r--scripts/smiley.pl43
-rw-r--r--scripts/sms.pl439
-rw-r--r--scripts/snmpup.pl101
-rw-r--r--scripts/spambot.pl80
-rw-r--r--scripts/special_complete.pl30
-rw-r--r--scripts/spellcheck.pl301
-rw-r--r--scripts/sping.pl41
-rw-r--r--scripts/stocks.pl431
-rw-r--r--scripts/synccheck.pl346
-rw-r--r--scripts/sysinfo277-irssi.pl546
-rw-r--r--scripts/sysinfo_dg.pl330
-rw-r--r--scripts/sysinfoplus.pl107
-rw-r--r--scripts/tab_stop.pl61
-rw-r--r--scripts/talk.pl274
-rw-r--r--scripts/target.pl163
-rw-r--r--scripts/thankop.pl134
-rw-r--r--scripts/theme.pl451
-rw-r--r--scripts/thistory.pl162
-rw-r--r--scripts/tictactoe.pl665
-rw-r--r--scripts/timer.pl177
-rw-r--r--scripts/tinyurl.pl47
-rw-r--r--scripts/title.pl150
-rw-r--r--scripts/tlock.pl81
-rw-r--r--scripts/tmux-nicklist-portable.pl432
-rw-r--r--scripts/topic-diff.pl86
-rw-r--r--scripts/topics.pl126
-rw-r--r--scripts/topicsed.pl61
-rw-r--r--scripts/track.pl310
-rw-r--r--scripts/trackbar.pl606
-rw-r--r--scripts/tracknick.pl201
-rw-r--r--scripts/trigger.pl1258
-rw-r--r--scripts/trustweb.pl374
-rw-r--r--scripts/tvmusor.pl143
-rw-r--r--scripts/twirssi.pl4217
-rw-r--r--scripts/twprompt.pl100
-rw-r--r--scripts/twsocials.pl1154
-rw-r--r--scripts/twtopic.pl120
-rw-r--r--scripts/u.pl69
-rw-r--r--scripts/upgradeinfo.pl87
-rw-r--r--scripts/uptime.pl138
-rw-r--r--scripts/url.pl329
-rw-r--r--scripts/url_log.pl399
-rw-r--r--scripts/urlfeed.pl262
-rw-r--r--scripts/urlgrab.pl71
-rw-r--r--scripts/urlplot.pl841
-rw-r--r--scripts/urlwindow.pl49
-rw-r--r--scripts/userhost.pl103
-rw-r--r--scripts/users.pl270
-rw-r--r--scripts/version-stat.pl88
-rw-r--r--scripts/verstats.pl81
-rw-r--r--scripts/vowels.pl93
-rw-r--r--scripts/warnkick.pl71
-rw-r--r--scripts/washnicks.pl79
-rw-r--r--scripts/watch.pl179
-rw-r--r--scripts/whitelist.pl445
-rw-r--r--scripts/whois.pl38
-rw-r--r--scripts/whos.pl109
-rw-r--r--scripts/wilm.pl54
-rw-r--r--scripts/wkb.pl68
-rw-r--r--scripts/wlstat.pl669
-rw-r--r--scripts/wordcompletition.pl144
-rw-r--r--scripts/wordscramble.pl160
-rw-r--r--scripts/xauth.pl546
-rw-r--r--scripts/xcmd.pl65
-rw-r--r--scripts/xdccget.pl650
-rw-r--r--scripts/xetra.pl209
-rw-r--r--scripts/xlist.pl65
-rw-r--r--scripts/xmms.pl161
-rw-r--r--scripts/xmms2.pl86
-rw-r--r--scripts/xmmsinfo.pl116
-rw-r--r--scripts/xqf.pl238
-rwxr-xr-xupdate-scripts227
380 files changed, 103962 insertions, 0 deletions
diff --git a/INDEX b/INDEX
new file mode 100644
index 0000000..0032228
--- /dev/null
+++ b/INDEX
@@ -0,0 +1,1480 @@
+script 0x0st.pl
+url https://github.com/irssi/scripts/raw/master/scripts/0x0st.pl
+description upload file to https://0x0.st/
+
+script 8-ball.pl
+url https://github.com/irssi/scripts/raw/master/scripts/8-ball.pl
+description Dont like to take decisions? Have the 8-ball do it for you instead.
+
+script Cirssi.pl
+url https://github.com/irssi/scripts/raw/master/scripts/Cirssi.pl
+description Controls Audacious2 and MOCP from Irssi
+
+script UNIBG-autoident.pl
+url https://github.com/irssi/scripts/raw/master/scripts/UNIBG-autoident.pl
+description Automaticaly /msg ident NS yourpassword when you connect or services come back from death
+
+script accent.pl
+url https://github.com/irssi/scripts/raw/master/scripts/accent.pl
+description This script strips the hungarian accents.
+
+script act.pl
+url https://github.com/irssi/scripts/raw/master/scripts/act.pl
+description Reset window activity status. defines command /act
+
+script active_notice.pl
+url https://github.com/irssi/scripts/raw/master/scripts/active_notice.pl
+description This script shows incoming notices into the active channel.
+
+script active_notify.pl
+url https://github.com/irssi/scripts/raw/master/scripts/active_notify.pl
+description This script will display notify messages into the active window or broadcast it so all the windows.
+
+script adv_windowlist.pl
+url https://github.com/irssi/scripts/raw/master/scripts/adv_windowlist.pl
+description Adds a permanent advanced window list on the right or in a status bar.
+
+script ai.pl
+url https://github.com/irssi/scripts/raw/master/scripts/ai.pl
+description Puts people on ignore if they do a public away. See source for options.
+
+script aidle.pl
+url https://github.com/irssi/scripts/raw/master/scripts/aidle.pl
+description Antyidler with random time
+
+script akftp.pl
+url https://github.com/irssi/scripts/raw/master/scripts/akftp.pl
+description Full configurable FTP advertiser for Irssi
+
+script alame.pl
+url https://github.com/irssi/scripts/raw/master/scripts/alame.pl
+description Converts towards lame speech
+
+script anotherway.pl
+url https://github.com/irssi/scripts/raw/master/scripts/anotherway.pl
+description Another auto away script
+
+script antiplenk.pl
+url https://github.com/irssi/scripts/raw/master/scripts/antiplenk.pl
+description notices users who "plenk"
+
+script apm.pl
+url https://github.com/irssi/scripts/raw/master/scripts/apm.pl
+description Shows your battery status in your Statusbar
+
+script armeija.pl
+url https://github.com/irssi/scripts/raw/master/scripts/armeija.pl
+description Ignores people bringin up boring/repeated subjects, plus replies.
+
+script ascii.pl
+url https://github.com/irssi/scripts/raw/master/scripts/ascii.pl
+description Ascii-art bassed on figlet. Available commands: /ASCII, /COLSAY, /COLME, /COLTOPIC, /COLKICK, /COLQUIT.
+
+script auto_whois.pl
+url https://github.com/irssi/scripts/raw/master/scripts/auto_whois.pl
+description /WHOIS all the users who send you a private message.
+
+script autoaway.pl
+url https://github.com/irssi/scripts/raw/master/scripts/autoaway.pl
+description Automatically goes away after defined inactivity
+
+script autochannel.pl
+url https://github.com/irssi/scripts/raw/master/scripts/autochannel.pl
+description Auto add channels to channel list on join
+
+script autocycle.pl
+url https://github.com/irssi/scripts/raw/master/scripts/autocycle.pl
+description Auto regain ops in empty opless channels
+
+script autolimit.pl
+url https://github.com/irssi/scripts/raw/master/scripts/autolimit.pl
+description does an autolimit for a channel
+
+script autoopper.pl
+url https://github.com/irssi/scripts/raw/master/scripts/autoopper.pl
+description Auto-op script with dynamic address support and random delay
+
+script autorealname.pl
+url https://github.com/irssi/scripts/raw/master/scripts/autorealname.pl
+description Print realname of everyone who join to channels
+
+script autorejoinpunish.pl
+url https://github.com/irssi/scripts/raw/master/scripts/autorejoinpunish.pl
+description Kickbans or knockouts people who use autorejoin on kick.
+
+script autoreminder.pl
+url https://github.com/irssi/scripts/raw/master/scripts/autoreminder.pl
+description This script Reminds people to do stuff! :)
+
+script autoversion.pl
+url https://github.com/irssi/scripts/raw/master/scripts/autoversion.pl
+description Auto-CTCP Verison on every joining nick
+
+script autovoice.pl
+url https://github.com/irssi/scripts/raw/master/scripts/autovoice.pl
+description autovoice
+
+script autowhois.pl
+url https://github.com/irssi/scripts/raw/master/scripts/autowhois.pl
+description /WHOIS all the users who send you a private message.
+
+script autowrap.pl
+url https://github.com/irssi/scripts/raw/master/scripts/autowrap.pl
+description Automatically wraps long sent messages into multiple shorter sent messages
+
+script away.pl
+url https://github.com/irssi/scripts/raw/master/scripts/away.pl
+description Away with reason, unaway, and autoaway
+
+script away2web.pl
+url https://github.com/irssi/scripts/raw/master/scripts/away2web.pl
+description Write /away information to a file to be used on web pages
+
+script away_hilight_notice.pl
+url https://github.com/irssi/scripts/raw/master/scripts/away_hilight_notice.pl
+description This script will notice your away message in response to a hilight.
+
+script away_verbose.pl
+url https://github.com/irssi/scripts/raw/master/scripts/away_verbose.pl
+description A verbose away script, displays a verbose away/back message in the channels you are in. BUT it can limit the channels (not spamming every channel!)
+
+script awaybar.pl
+url https://github.com/irssi/scripts/raw/master/scripts/awaybar.pl
+description Provides a menubar item with away message
+
+script awaylogcnt.pl
+url https://github.com/irssi/scripts/raw/master/scripts/awaylogcnt.pl
+description Displays in statusbar number of messages in awaylog
+
+script awayproxy.pl
+url https://github.com/irssi/scripts/raw/master/scripts/awayproxy.pl
+description Sets nick away when client discconects from the irssi-proxy. If away gathers messages targeted to nick and forwards them to an email address.
+
+script badword.pl
+url https://github.com/irssi/scripts/raw/master/scripts/badword.pl
+description Configurable badword kickbanning script
+
+script ban.pl
+url https://github.com/irssi/scripts/raw/master/scripts/ban.pl
+description /BAN [channel] [-normal|-host|-user|-domain|-crap|-ip|-class -before|-after "cmd" nick|mask] ... - bans several nicks/masks on channel, removes any conflicting bans before banning
+
+script bandwidth.pl
+url https://github.com/irssi/scripts/raw/master/scripts/bandwidth.pl
+description shows bandwidth usage in statusbar
+
+script bansearch.pl
+url https://github.com/irssi/scripts/raw/master/scripts/bansearch.pl
+description Searches for bans, quiets, and channel modes affecting a user
+
+script bantime.pl
+url https://github.com/irssi/scripts/raw/master/scripts/bantime.pl
+description Print time when ban was set in a nicer way. eg. 23m, 40s ago.
+
+script beep.pl
+url https://github.com/irssi/scripts/raw/master/scripts/beep.pl
+description Replaces your terminal bell by a command specified via /set; adds a beep_when_not_away setting
+
+script beep_beep.pl
+url https://github.com/irssi/scripts/raw/master/scripts/beep_beep.pl
+description runs arbitrary command instead of system beep, includes flood protection
+
+script beepaway.pl
+url https://github.com/irssi/scripts/raw/master/scripts/beepaway.pl
+description Only beep when you are away
+
+script bestoiber.pl
+url https://github.com/irssi/scripts/raw/master/scripts/bestoiber.pl
+description stoibers your messages
+
+script binary.pl
+url https://github.com/irssi/scripts/raw/master/scripts/binary.pl
+description adds /binary command that converts what you type into 2-base string representation, also decodes other peoples binary automatically
+
+script bitlbee_blist.pl
+url https://github.com/irssi/scripts/raw/master/scripts/bitlbee_blist.pl
+description /blist <all|online|offline|away|word> <word>, greps <word> from blist for bitlbee
+
+script bitlbee_join_notice.pl
+url https://github.com/irssi/scripts/raw/master/scripts/bitlbee_join_notice.pl
+description 1. Adds an item to the status bar wich shows [joined: <nicks>] when someone is joining &bitlbee. 2. Shows join messages in the query. (For bitlbee v3.0+)
+
+script bitlbee_nick_change.pl
+url https://github.com/irssi/scripts/raw/master/scripts/bitlbee_nick_change.pl
+description Shows an IM nickchange in an Irssi way. (in a query and in the bitlbee channel). (For bitlbee 3.0+)
+
+script bitlbee_tab_completion.pl
+url https://github.com/irssi/scripts/raw/master/scripts/bitlbee_tab_completion.pl
+description Intelligent Tab-completion for BitlBee commands.
+
+script bitlbee_typing_notice.pl
+url https://github.com/irssi/scripts/raw/master/scripts/bitlbee_typing_notice.pl
+description 1. Adds an item to the status bar wich shows [typing] when someone is typing a message on the supported IM-networks 2. Sends typing notices to the supported IM networks (the other way arround). (For bitlbee 3.0+)
+
+script blowjob.pl
+url https://github.com/irssi/scripts/raw/master/scripts/blowjob.pl
+description Crypt IRC communication with blowfish encryption. Supports public #channels, !channels, +channel, querys and dcc chat. Roadmap for Version 1.0.0 is to get some feedback and cleanup. Join #blowtest on freenode (irc.debian.org) to get latest stuff available. Note to users upgrading from versions prior to 0.8.5: The blowjob.keys format has changed.
+
+script bmi.pl
+url https://github.com/irssi/scripts/raw/master/scripts/bmi.pl
+description a simple body mass index calculator for depression ;)
+
+script calc.pl
+url https://github.com/irssi/scripts/raw/master/scripts/calc.pl
+description Simple /calc mechanism
+
+script callerid.pl
+url https://github.com/irssi/scripts/raw/master/scripts/callerid.pl
+description Reformats CallerID (+g) Messages (Also known as Server-Side Ignore) on Hybrid & Ratbox IRCDs (EFnet) to be Easier on the Eyes
+
+script cap_sasl.pl
+url https://github.com/irssi/scripts/raw/master/scripts/cap_sasl.pl
+description Implements SASL authentication and enables CAP "multi-prefix"
+
+script centericq.pl
+url https://github.com/irssi/scripts/raw/master/scripts/centericq.pl
+description Staturbar item which indicates how many new messages you have in your centericq
+
+script cgrep.pl
+url https://github.com/irssi/scripts/raw/master/scripts/cgrep.pl
+description Lists users on the channel matching the specified regexp
+
+script chanact.pl
+url https://github.com/irssi/scripts/raw/master/scripts/chanact.pl
+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>
+
+script chanfull.pl
+url https://github.com/irssi/scripts/raw/master/scripts/chanfull.pl
+description Notifies the user when some channel limit is reached
+
+script chanfull_duden.pl
+url https://github.com/irssi/scripts/raw/master/scripts/chanfull_duden.pl
+description Notify if Channellimit is reached
+
+script chankeys.pl
+url https://github.com/irssi/scripts/raw/master/scripts/chankeys.pl
+description manage channel keyboard shortcuts
+
+script chanpeak.pl
+url https://github.com/irssi/scripts/raw/master/scripts/chanpeak.pl
+description Log maximum number of people ever been in a channel
+
+script chansearch.pl
+url https://github.com/irssi/scripts/raw/master/scripts/chansearch.pl
+description searches for specific channels
+
+script chanshare.pl
+url https://github.com/irssi/scripts/raw/master/scripts/chanshare.pl
+description /CHANSHARE - display people who are in more than one channel with you
+
+script chansort.pl
+url https://github.com/irssi/scripts/raw/master/scripts/chansort.pl
+description Sort all channel and query windows
+
+script chansync.pl
+url https://github.com/irssi/scripts/raw/master/scripts/chansync.pl
+description /who a channel and optionaly executes a command
+
+script chops.pl
+url https://github.com/irssi/scripts/raw/master/scripts/chops.pl
+description Simulates BitchX's /CHOPS and /NOPS commands.
+
+script cleanpublic.pl
+url https://github.com/irssi/scripts/raw/master/scripts/cleanpublic.pl
+description Simple script that removes colors and other formatting (bold, etc) from public channels
+
+script clipboard.pl
+url https://github.com/irssi/scripts/raw/master/scripts/clipboard.pl
+description Better quoting of content from clipboard (without leading spaces) -- requires Perl/Tk
+
+script clones.pl
+url https://github.com/irssi/scripts/raw/master/scripts/clones.pl
+description /CLONES - Display clones in the active channel (with added options)
+
+script colorize_nicks.pl
+url https://github.com/irssi/scripts/raw/master/scripts/colorize_nicks.pl
+description Colourise mention of nicks in the message body.
+
+script colorkick.pl
+url https://github.com/irssi/scripts/raw/master/scripts/colorkick.pl
+description kicking users for using colors or blinks
+
+script colorswap.pl
+url https://github.com/irssi/scripts/raw/master/scripts/colorswap.pl
+description Swap between green and white format for public messages. I think this helps readability. Assumes you haven't changed message formats.
+
+script connectcmd.pl
+url https://github.com/irssi/scripts/raw/master/scripts/connectcmd.pl
+description run arbitrary shell commands while [dis]connecting to a server
+
+script copy.pl
+url https://github.com/irssi/scripts/raw/master/scripts/copy.pl
+description copy a line in a paste buffer
+
+script countdown.pl
+url https://github.com/irssi/scripts/raw/master/scripts/countdown.pl
+description adds public channel command for counting down something
+
+script country.pl
+url https://github.com/irssi/scripts/raw/master/scripts/country.pl
+description Print the country name in /WHOIS replies
+
+script cp1250_kick.pl
+url https://github.com/irssi/scripts/raw/master/scripts/cp1250_kick.pl
+description Kicks people using cp1250 charset
+
+script crapbuster.pl
+url https://github.com/irssi/scripts/raw/master/scripts/crapbuster.pl
+description Removes CRAP or CLIENTCRAP messages from your buffer
+
+script cron.pl
+url https://github.com/irssi/scripts/raw/master/scripts/cron.pl
+description cron implementation, allows to execute commands at given interval/time
+
+script ctrlact.pl
+url https://github.com/irssi/scripts/raw/master/scripts/ctrlact.pl
+description allows per-channel control over activity indication
+
+script cwho.pl
+url https://github.com/irssi/scripts/raw/master/scripts/cwho.pl
+description Usage: /CWHO [-a | -l | -o | -v ] [ mask ]
+
+script dancer_forwardfix.pl
+url https://github.com/irssi/scripts/raw/master/scripts/dancer_forwardfix.pl
+description This script will fix the Irssi problem with channel forwarding on the Dancer ircd.
+
+script dau.pl
+url https://github.com/irssi/scripts/raw/master/scripts/dau.pl
+description write like an idiot
+
+script dcc_ip.pl
+url https://github.com/irssi/scripts/raw/master/scripts/dcc_ip.pl
+description This script sets dcc_own_ip when starting a DCC send or chat.set dcc_ip_interface to your external interface, f.e. ppp0.If you are connecting though a router, set it to "router"
+
+script dccmove.pl
+url https://github.com/irssi/scripts/raw/master/scripts/dccmove.pl
+description Move completed dcc gets to the subfolder done
+
+script dccself.pl
+url https://github.com/irssi/scripts/raw/master/scripts/dccself.pl
+description /dccself ip port, starts a dcc chat with yourself on that host/port, best used with /set dcc_autochat_masks.
+
+script dccstat.pl
+url https://github.com/irssi/scripts/raw/master/scripts/dccstat.pl
+description Shows verbose or short information of dcc send/gets on statusbar (speed, size, eta etc.)
+
+script defaultchanmode.pl
+url https://github.com/irssi/scripts/raw/master/scripts/defaultchanmode.pl
+description Allows your client to automatically set desired chanmode upon a join to an empty channel.
+
+script desktop-notify.pl
+url https://github.com/irssi/scripts/raw/master/scripts/desktop-notify.pl
+description Sends notification using the Desktop Notifications Specification.
+
+script df.pl
+url https://github.com/irssi/scripts/raw/master/scripts/df.pl
+description Adds an item which displays the current disk usage.
+
+script dice.pl
+url https://github.com/irssi/scripts/raw/master/scripts/dice.pl
+description A Dice Simulator for Roleplaying in Channels or just for fun.
+
+script dictcomplete.pl
+url https://github.com/irssi/scripts/raw/master/scripts/dictcomplete.pl
+description Caching dictionary based tab completion
+
+script dim_nicks.pl
+url https://github.com/irssi/scripts/raw/master/scripts/dim_nicks.pl
+description Dims nicks that are not in channel anymore.
+
+script discord_unbridge.pl
+url https://github.com/irssi/scripts/raw/master/scripts/discord_unbridge.pl
+description In channels with a discord bridge, turns "<bridge> <Sender> Message" into "<Sender> Message", and hides spoilers.
+
+script dispatch.pl
+url https://github.com/irssi/scripts/raw/master/scripts/dispatch.pl
+description This scripts sends unknown commands to the server
+
+script doc.pl
+url https://github.com/irssi/scripts/raw/master/scripts/doc.pl
+description manage tips ; url ; help in a doc file in the keyword=definition form
+
+script doublefilter.pl
+url https://github.com/irssi/scripts/raw/master/scripts/doublefilter.pl
+description Filters msgs which appear the same on different channels.
+
+script dtach_away.pl
+url https://github.com/irssi/scripts/raw/master/scripts/dtach_away.pl
+description set (un)away, if dtach is attached/detached
+
+script duckduckgo.pl
+url https://github.com/irssi/scripts/raw/master/scripts/duckduckgo.pl
+description search by https://duckduckgo.com/html/
+
+script elist.pl
+url https://github.com/irssi/scripts/raw/master/scripts/elist.pl
+description This script allow advanced parametrization of the /list command. Accepted parameters are -minusers <#users> and -maxusers <#users>.
+
+script eliza.pl
+url https://github.com/irssi/scripts/raw/master/scripts/eliza.pl
+description Answers to /msg's using Chatbot::Eliza when you're away.
+
+script email_msgs.pl
+url https://github.com/irssi/scripts/raw/master/scripts/email_msgs.pl
+description Emails you messages sent/received while you're away or not. Works for both public mentions and private messages.When away, it is very useful in combination with screen_away. Based on email_privmsgs, with advanced features and options. Requires Email::Sender.
+
+script emaildb.pl
+url https://github.com/irssi/scripts/raw/master/scripts/emaildb.pl
+description a script for accessing an email mysql database through irc
+
+script events.pl
+url https://github.com/irssi/scripts/raw/master/scripts/events.pl
+description Expand "event mode" and emit "event mode {channel,user,server} *"
+
+script exec_clean.pl
+url https://github.com/irssi/scripts/raw/master/scripts/exec_clean.pl
+description Adds a setting to automatically terminate a process whose parent window has been closed
+
+script fakectcp.pl
+url https://github.com/irssi/scripts/raw/master/scripts/fakectcp.pl
+description This script sends fake ctcp replies to a client using a fake ctcp list.
+
+script figlet.pl
+url https://github.com/irssi/scripts/raw/master/scripts/figlet.pl
+description Safe figlet implementation (with color support!)
+
+script file.pl
+url https://github.com/irssi/scripts/raw/master/scripts/file.pl
+description A command to output content of files in various ways
+
+script find.pl
+url https://github.com/irssi/scripts/raw/master/scripts/find.pl
+description Finds a nick by real name, if he's on a channel with you.
+
+script findbot.pl
+url https://github.com/irssi/scripts/raw/master/scripts/findbot.pl
+description Public command @find script
+
+script fleech.pl
+url https://github.com/irssi/scripts/raw/master/scripts/fleech.pl
+description fserve leecher - helps you download files from file servers
+
+script fnotify.pl
+url https://github.com/irssi/scripts/raw/master/scripts/fnotify.pl
+description Write notifications to a file in a consistent format.
+
+script follow.pl
+url https://github.com/irssi/scripts/raw/master/scripts/follow.pl
+description Automatically switch to active windows
+
+script foo.pl
+url https://github.com/irssi/scripts/raw/master/scripts/foo.pl
+description Rot n+i encryption and decryption
+
+script foreach_user.pl
+url https://github.com/irssi/scripts/raw/master/scripts/foreach_user.pl
+description Extends the /foreach command to have /foreach user (users in a channel). Syntax: /foreach user [hostmask] command.
+
+script fortune.pl
+url https://github.com/irssi/scripts/raw/master/scripts/fortune.pl
+description Send a random fortune cookie to an user in channel.
+
+script forward.pl
+url https://github.com/irssi/scripts/raw/master/scripts/forward.pl
+description forward incoming messages to another nick
+
+script fpaste.pl
+url https://github.com/irssi/scripts/raw/master/scripts/fpaste.pl
+description copy infos to fpaste
+
+script friends_peder.pl
+url https://github.com/irssi/scripts/raw/master/scripts/friends_peder.pl
+description Basically an autoop script with a nice interface and nick coloring ;)
+
+script friends_shasta.pl
+url https://github.com/irssi/scripts/raw/master/scripts/friends_shasta.pl
+description Maintains list of people you know.
+
+script fserve.pl
+url https://github.com/irssi/scripts/raw/master/scripts/fserve.pl
+description File server for irssi
+
+script fuckem.pl
+url https://github.com/irssi/scripts/raw/master/scripts/fuckem.pl
+description Simulates the BitchX /FUCKEM command. Deop/Dehalfop everyone on the channel including you.
+
+script getop.pl
+url https://github.com/irssi/scripts/raw/master/scripts/getop.pl
+description Automatically request op from random opped person with specifed command from list after joining channel
+
+script gimmie.pl
+url https://github.com/irssi/scripts/raw/master/scripts/gimmie.pl
+description a bot script, using ! followed by anything the script will say (as an action): gets nickname anything
+
+script gitscriptassist.pl
+url https://github.com/irssi/scripts/raw/master/scripts/gitscriptassist.pl
+description script management with git
+
+script go.pl
+url https://github.com/irssi/scripts/raw/master/scripts/go.pl
+description Implements /go command that activates a window given a name/partial name. It features a nice completion.
+
+script go2.pl
+url https://github.com/irssi/scripts/raw/master/scripts/go2.pl
+description Switch to the window with the given name or item
+
+script google.pl
+url https://github.com/irssi/scripts/raw/master/scripts/google.pl
+description This script queries google.com with googler and returns the results.
+
+script gpgvalidator.pl
+url https://github.com/irssi/scripts/raw/master/scripts/gpgvalidator.pl
+description Have gpg-based trusting features in your irssi client!
+
+script grep.pl
+url https://github.com/irssi/scripts/raw/master/scripts/grep.pl
+description /GREP [-i] [-w] [-v] [-F] <perl-regexp> <command to run>
+
+script guts.pl
+url https://github.com/irssi/scripts/raw/master/scripts/guts.pl
+description Adds the uppercased version of the tab completes
+
+script hddtemp.pl
+url https://github.com/irssi/scripts/raw/master/scripts/hddtemp.pl
+description adds a statusbar item which shows temperatures of harddisks (with multiple hddtemp-hosts support)
+
+script hello.pl
+url https://github.com/irssi/scripts/raw/master/scripts/hello.pl
+description This script allows you to greet the channel You're joining with the command /hello. The text it shows depends on the time you're living.
+
+script hide.pl
+url https://github.com/irssi/scripts/raw/master/scripts/hide.pl
+description a little interface to irssi's activity_hide_* settings
+
+script hideauth.pl
+url https://github.com/irssi/scripts/raw/master/scripts/hideauth.pl
+description Stops eggdrop passwords showing up
+
+script hideshow.pl
+url https://github.com/irssi/scripts/raw/master/scripts/hideshow.pl
+description Removes and re-adds lines to the Irssi buffer view.
+
+script highlite.pl
+url https://github.com/irssi/scripts/raw/master/scripts/highlite.pl
+description shows events happening in all channels you are in that may concern you
+
+script hignore.pl
+url https://github.com/irssi/scripts/raw/master/scripts/hignore.pl
+description This script will add the HIGNORE command, if you use this command in a query it will ignore the host.
+
+script hilightwin.pl
+url https://github.com/irssi/scripts/raw/master/scripts/hilightwin.pl
+description Print hilighted messages to window named "hilight"
+
+script history_search.pl
+url https://github.com/irssi/scripts/raw/master/scripts/history_search.pl
+description Search within your typed history as you type (like ctrl-R in bash)
+
+script hl.pl
+url https://github.com/irssi/scripts/raw/master/scripts/hl.pl
+description responds to "!hl counterstrike.server " command on channels/msg's to query counter-strike servers
+
+script hlbot.pl
+url https://github.com/irssi/scripts/raw/master/scripts/hlbot.pl
+description Floods the channel about things that are hapening in your hl -server. Also enables you to send rcon commands to the server from channel.
+
+script hostname.pl
+url https://github.com/irssi/scripts/raw/master/scripts/hostname.pl
+description Adds a /HOSTNAME command; it will list all IP addresses on all interfaces found on your machine, resolve them, and allow you to choose one easily
+
+script iMPD.pl
+url https://github.com/irssi/scripts/raw/master/scripts/iMPD.pl
+description This controls Music Player Daemon from the familiar irssi interface
+
+script idletime.pl
+url https://github.com/irssi/scripts/raw/master/scripts/idletime.pl
+description Retrieves the idletime of any nick
+
+script idonkey.pl
+url https://github.com/irssi/scripts/raw/master/scripts/idonkey.pl
+description equips Irssi with an interface to mldonkey
+
+script ignore_log.pl
+url https://github.com/irssi/scripts/raw/master/scripts/ignore_log.pl
+description script to log ignored messages
+
+script ignoreoc.pl
+url https://github.com/irssi/scripts/raw/master/scripts/ignoreoc.pl
+description Ignore messages from people not on your channels.Now people you msg are added to bypass-list.
+
+script il.pl
+url https://github.com/irssi/scripts/raw/master/scripts/il.pl
+description adds a statusbar item which show length of the inputline
+
+script imdb.pl
+url https://github.com/irssi/scripts/raw/master/scripts/imdb.pl
+description Automatically lookup IMDB-numbers in nicknames
+
+script intercept.pl
+url https://github.com/irssi/scripts/raw/master/scripts/intercept.pl
+description Intercept misprinted commands and offer to remove the first character before sending it on
+
+script invitejoin.pl
+url https://github.com/irssi/scripts/raw/master/scripts/invitejoin.pl
+description This script will join a channel if somebody invites you to it.
+
+script ipupdate.pl
+url https://github.com/irssi/scripts/raw/master/scripts/ipupdate.pl
+description Auto "/set dcc_own_ip IP" on connect.
+
+script irccomplete.pl
+url https://github.com/irssi/scripts/raw/master/scripts/irccomplete.pl
+description Adds words from IRC to your tab-completion list, plus fixes typos
+
+script ircgallery.pl
+url https://github.com/irssi/scripts/raw/master/scripts/ircgallery.pl
+description Show IRC gallery (http://irc-galleria.net, finnish only) information on /WHOIS or /GALLERY
+
+script ircgmessagenotify.pl
+url https://github.com/irssi/scripts/raw/master/scripts/ircgmessagenotify.pl
+description Tarkistelee irc-galleria.net:iä ja sanoo kun sinulle on uusia viestejä.
+
+script ircops.pl
+url https://github.com/irssi/scripts/raw/master/scripts/ircops.pl
+description /IRCOPS - Display IrcOps in current channel
+
+script ircsec.pl
+url https://github.com/irssi/scripts/raw/master/scripts/ircsec.pl
+description secures your conversation
+
+script irssiBlaster.pl
+url https://github.com/irssi/scripts/raw/master/scripts/irssiBlaster.pl
+description Display the song played by mp3blaster in channels and statusbar. See the top of the file for usage.
+
+script isdn.pl
+url https://github.com/irssi/scripts/raw/master/scripts/isdn.pl
+description Displays incoming ISDN calls
+
+script itime.pl
+url https://github.com/irssi/scripts/raw/master/scripts/itime.pl
+description Internet Time statusbar item. See http://www.timeanddate.com/time/internettime.html
+
+script ixmmsa.pl
+url https://github.com/irssi/scripts/raw/master/scripts/ixmmsa.pl
+description /xmms announces which _file_ is currently playing. E.g. Currently playing: "Kieran Halpin & Band - Mirror Town.mp3"
+
+script joininfo.pl
+url https://github.com/irssi/scripts/raw/master/scripts/joininfo.pl
+description Reports WHOIS information and channel list for those who join a channel
+
+script kban-referrals.pl
+url https://github.com/irssi/scripts/raw/master/scripts/kban-referrals.pl
+description Script for kickbanning those who post referral links in a channel
+
+script kblamehost.pl
+url https://github.com/irssi/scripts/raw/master/scripts/kblamehost.pl
+description Kicks (and bans) people with >= 4 dots in theirs hostname
+
+script keepnick.pl
+url https://github.com/irssi/scripts/raw/master/scripts/keepnick.pl
+description Try to get your nick back when it becomes available.
+
+script kenny.pl
+url https://github.com/irssi/scripts/raw/master/scripts/kenny.pl
+description autodekennyfies /kenny, adds /kenny, /dekenny. Based on Jan-Pieter Cornets signature version
+
+script kernel.pl
+url https://github.com/irssi/scripts/raw/master/scripts/kernel.pl
+description Fetches the version(s) of the latest Linux kernel(s).
+
+script kicks.pl
+url https://github.com/irssi/scripts/raw/master/scripts/kicks.pl
+description Enhances /k /kb and /kn with some nice options.
+
+script kill_fake_gets.pl
+url https://github.com/irssi/scripts/raw/master/scripts/kill_fake_gets.pl
+description When new send arrives checks if there are old identical sends (ie from the same nick on the same server and with the same filename) and closes them
+
+script kline_warning.pl
+url https://github.com/irssi/scripts/raw/master/scripts/kline_warning.pl
+description This script shows a warning in the statuswindow if somebody preforms a /KlINE or /UNKLINE.
+
+script l33tmusic.pl
+url https://github.com/irssi/scripts/raw/master/scripts/l33tmusic.pl
+description A script to show playing xmms song in channel or in a statusbar, and also control xmms. Be sure to read through the script to see all features.
+
+script lastspoke.pl
+url https://github.com/irssi/scripts/raw/master/scripts/lastspoke.pl
+description Remembers what people said last on what channels
+
+script len.pl
+url https://github.com/irssi/scripts/raw/master/scripts/len.pl
+description If you try to get a nick with 11 characters but only 9 are allowed, this script will prevent the nickchange. The same for too long topics, kickmsgs, partmsgs and quitmsgs.
+
+script leodict.pl
+url https://github.com/irssi/scripts/raw/master/scripts/leodict.pl
+description translates via dict.leo.org
+
+script licq.pl
+url https://github.com/irssi/scripts/raw/master/scripts/licq.pl
+description Licq statusbar thingy
+
+script linkchan.pl
+url https://github.com/irssi/scripts/raw/master/scripts/linkchan.pl
+description Link several channels on serveral networks
+
+script listen.pl
+url https://github.com/irssi/scripts/raw/master/scripts/listen.pl
+description A simple mp3 display script that will display what mp3 you are playing in which software (mpg123, xmms, mp3blaster, etc) to your active channel or to a query window.
+
+script loadavg.pl
+url https://github.com/irssi/scripts/raw/master/scripts/loadavg.pl
+description display a loadavg statusbar item using vm.loadavg mib or /proc/loadavg
+
+script localize.pl
+url https://github.com/irssi/scripts/raw/master/scripts/localize.pl
+description Localizes users using traceroute, the localizer database or IP-Atlas
+
+script log2ansi.pl
+url https://github.com/irssi/scripts/raw/master/scripts/log2ansi.pl
+description Convert various color codes to ANSI colors, useful for log filtering and viewing.
+
+script logcompress.pl
+url https://github.com/irssi/scripts/raw/master/scripts/logcompress.pl
+description compress logfiles then they're rotated
+
+script logresume.pl
+url https://github.com/irssi/scripts/raw/master/scripts/logresume.pl
+description print last n lines of logs when opening queries/channels
+
+script mailcheck_imap.pl
+url https://github.com/irssi/scripts/raw/master/scripts/mailcheck_imap.pl
+description Staturbar item which indicates how many new emails you have in the specified IMAP[S] mailbox
+
+script mailcheck_mbox_flux.pl
+url https://github.com/irssi/scripts/raw/master/scripts/mailcheck_mbox_flux.pl
+description Polls your unix mailbox for new mail
+
+script mailcheck_pop3_kimmo.pl
+url https://github.com/irssi/scripts/raw/master/scripts/mailcheck_pop3_kimmo.pl
+description POP3 new mail notification and listing of mailbox contents. Use "/mail help" for instructions. Requires Net::POP3.
+
+script mangle.pl
+url https://github.com/irssi/scripts/raw/master/scripts/mangle.pl
+description translates your messages into Morse code, rot13 and other sillinesses.
+
+script map.pl
+url https://github.com/irssi/scripts/raw/master/scripts/map.pl
+description Generates simple tree of IRC network based on the output of the LINKS command.
+
+script mass_hilight_blocker.pl
+url https://github.com/irssi/scripts/raw/master/scripts/mass_hilight_blocker.pl
+description Disables hilighting for messages containing a lot of nicknames
+
+script miodek.pl
+url https://github.com/irssi/scripts/raw/master/scripts/miodek.pl
+description Simple wordkick system, with extended polish dictionary for channels enforcing correct polish.
+
+script mkick.pl
+url https://github.com/irssi/scripts/raw/master/scripts/mkick.pl
+description Masskick, usage: /mkick [-aovdln6 (hostmask)] <[:]reason>
+
+script mldonkey_bandwidth.pl
+url https://github.com/irssi/scripts/raw/master/scripts/mldonkey_bandwidth.pl
+description Shows your mldonkey's current down- and upload rate
+
+script modelist-r.pl
+url https://github.com/irssi/scripts/raw/master/scripts/modelist-r.pl
+description Cache of invites, ban exceptions and reops in channel. Script commands: /si, /se, /sr, /unexcept, /uninvite, /unreop (version only for ircd >= 2.11.0).
+
+script modelist.pl
+url https://github.com/irssi/scripts/raw/master/scripts/modelist.pl
+description Cache of invites and ban exceptions in channel. Usage: /si, /se, /unexcept [indexes], /uninvite [indexes]
+
+script mood.pl
+url https://github.com/irssi/scripts/raw/master/scripts/mood.pl
+description Keeps track of the channel mood
+
+script morse.pl
+url https://github.com/irssi/scripts/raw/master/scripts/morse.pl
+description turns your messages into morse or spelling code
+
+script mouse.pl
+url https://github.com/irssi/scripts/raw/master/scripts/mouse.pl
+description control irssi using mouse clicks and gestures
+
+script mpg123.pl
+url https://github.com/irssi/scripts/raw/master/scripts/mpg123.pl
+description Display current mpg123 track
+
+script multipaste.pl
+url https://github.com/irssi/scripts/raw/master/scripts/multipaste.pl
+description Helps pasting multiple lines to a channel
+
+script my_beep.pl
+url https://github.com/irssi/scripts/raw/master/scripts/my_beep.pl
+description runs arbitrary command instead of system beep, includes flood protection
+
+script mysqlurllogger.pl
+url https://github.com/irssi/scripts/raw/master/scripts/mysqlurllogger.pl
+description logs url's to mysql database
+
+script nact.pl
+url https://github.com/irssi/scripts/raw/master/scripts/nact.pl
+description Adds an item which displays the current network activity. Needs /proc/net/dev.
+
+script news.pl
+url https://github.com/irssi/scripts/raw/master/scripts/news.pl
+description News reader, usage: /article [-s <server>] [-p <port>] [-P <password> -U <login>] [-l <group> <count>] [-a] [-L <index>] <message-id>
+
+script newsline.pl
+url https://github.com/irssi/scripts/raw/master/scripts/newsline.pl
+description brings various newstickers to Irssi (Slashdot, Freshmeat, Heise etc.)
+
+script nickban.pl
+url https://github.com/irssi/scripts/raw/master/scripts/nickban.pl
+description A simple nick banner. If it encounters a nick it bans its host
+
+script nickcolor.pl
+url https://github.com/irssi/scripts/raw/master/scripts/nickcolor.pl
+description assign a different color for each nick
+
+script nickignore.pl
+url https://github.com/irssi/scripts/raw/master/scripts/nickignore.pl
+description Ignores any nick changes when only the case or special characters are modified, like 'rpr -> Rpr' or 'rpr_ -> rpr', with optional pattern for more complicated ignores
+
+script nicklist.pl
+url https://github.com/irssi/scripts/raw/master/scripts/nicklist.pl
+description draws a nicklist to another terminal, or at the right of your irssi in the same terminal
+
+script nickmix-c0ffee.pl
+url https://github.com/irssi/scripts/raw/master/scripts/nickmix-c0ffee.pl
+description Perturbates your nick, use /nickmix nick/len where len is the number of chars you want to keep from your orig nick. use /stopmix to stop. Always issue the commands in a window of the server you want to mix in.
+
+script nickmix_pasky.pl
+url https://github.com/irssi/scripts/raw/master/scripts/nickmix_pasky.pl
+description Perturbates given nick (or just a word) in certain way.
+
+script nickserv.pl
+url https://github.com/irssi/scripts/raw/master/scripts/nickserv.pl
+description This script will authorize you into NickServ.
+
+script niq.pl
+url https://github.com/irssi/scripts/raw/master/scripts/niq.pl
+description BitchX like Nickcompletion at line start plus statusbar
+
+script nm.pl
+url https://github.com/irssi/scripts/raw/master/scripts/nm.pl
+description right aligned nicks depending on longest nick
+
+script nocaps.pl
+url https://github.com/irssi/scripts/raw/master/scripts/nocaps.pl
+description Replaces lines in ALL CAPS with something easier on the eyes
+
+script nocollide.pl
+url https://github.com/irssi/scripts/raw/master/scripts/nocollide.pl
+description Automatically changes nick (to randnick or uid on ircd 2.11) when certain amount of nick colissionstakes place on channel
+
+script noisyquery.pl
+url https://github.com/irssi/scripts/raw/master/scripts/noisyquery.pl
+description Prints an info about a newly started Query in your current window and runs a /whois on the nick.
+
+script nopl.pl
+url https://github.com/irssi/scripts/raw/master/scripts/nopl.pl
+description Replaces polish national characters with their corresponding letters
+
+script norepeat.pl
+url https://github.com/irssi/scripts/raw/master/scripts/norepeat.pl
+description stops public repeating
+
+script noticemove.pl
+url https://github.com/irssi/scripts/raw/master/scripts/noticemove.pl
+description Prints private notices from people in the channel where they are joined with you. Useful when you get lots of private notices from some bots.
+
+script notonline.pl
+url https://github.com/irssi/scripts/raw/master/scripts/notonline.pl
+description Answers "$nick: No." if you're away and someone asks are you online on a channel
+
+script ogg123.pl
+url https://github.com/irssi/scripts/raw/master/scripts/ogg123.pl
+description Display current ogg123 track
+
+script oidenty.pl
+url https://github.com/irssi/scripts/raw/master/scripts/oidenty.pl
+description oidentd support for irssi
+
+script on.pl
+url https://github.com/irssi/scripts/raw/master/scripts/on.pl
+description /on command - this is very simple and not really designed to be the same as ircII - it tries to fit into Irssi's usage style more than emulating ircII.
+
+script oops.pl
+url https://github.com/irssi/scripts/raw/master/scripts/oops.pl
+description turns 'll' and 'ls' in the beginning of a sent line into the names or whois commands
+
+script oopsie.pl
+url https://github.com/irssi/scripts/raw/master/scripts/oopsie.pl
+description Stops those silly mistakes being sent (spaces at start of line, /1/1 for window changes, etc).
+
+script openurl.pl
+url https://github.com/irssi/scripts/raw/master/scripts/openurl.pl
+description Stores URLs in a list and launches mail, web or ftp software
+
+script operit.pl
+url https://github.com/irssi/scripts/raw/master/scripts/operit.pl
+description Perform certain action (invite/op/...) on request authenticated by the IRC operator status.
+
+script operview.pl
+url https://github.com/irssi/scripts/raw/master/scripts/operview.pl
+description Reformats some server notices, which may come i.e. from &clients or &servers at IRCnet. You can turn the script on/off bytoggling variable mangle_server_notices.
+
+script opnotice.pl
+url https://github.com/irssi/scripts/raw/master/scripts/opnotice.pl
+description No description.
+
+script opnotify.pl
+url https://github.com/irssi/scripts/raw/master/scripts/opnotify.pl
+description Hilights window refnumber in statusbar if someone ops/deops you on channel
+
+script osd.pl
+url https://github.com/irssi/scripts/raw/master/scripts/osd.pl
+description An OnScreenDisplay (osd) it show's who is talking to you, on what IRC Network.
+
+script page-c0ffee.pl
+url https://github.com/irssi/scripts/raw/master/scripts/page-c0ffee.pl
+description Adds the /PAGE command to page a nick (use /page nick <text>)... to ignore pages /set pager_mode off
+
+script page_reeler.pl
+url https://github.com/irssi/scripts/raw/master/scripts/page_reeler.pl
+description display and send CTCP PAGE
+
+script pager.pl
+url https://github.com/irssi/scripts/raw/master/scripts/pager.pl
+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
+
+script pangotext.pl
+url https://github.com/irssi/scripts/raw/master/scripts/pangotext.pl
+description Render text with various color modifications using HTML tag syntax.
+
+script paste-derwan.pl
+url https://github.com/irssi/scripts/raw/master/scripts/paste-derwan.pl
+description Usage: /paste [-all|-msgs|-public] [-c|-b] [-s|-l| where] [lines]
+
+script paste_derwan.pl
+url https://github.com/irssi/scripts/raw/master/scripts/paste_derwan.pl
+description Pasting lines to specified targets, type "/paste -help" for help
+
+script paste_huggie.pl
+url https://github.com/irssi/scripts/raw/master/scripts/paste_huggie.pl
+description Paste reformats long pieces of text typically pasted into your client from webpages so that they fit nicely into your channel. Width of client may be specified
+
+script paste_kimmoke.pl
+url https://github.com/irssi/scripts/raw/master/scripts/paste_kimmoke.pl
+description Provides /start, /stop, /play <-nopack> <-nospace> paste mechanism - start and stop recording and then replay without linebreaks. Also /see to view what was recorded.
+
+script pelix.pl
+url https://github.com/irssi/scripts/raw/master/scripts/pelix.pl
+description This script allows you flood shit.
+
+script people.pl
+url https://github.com/irssi/scripts/raw/master/scripts/people.pl
+description Userlist with autoopping, autokicking etc.
+
+script perlalias.pl
+url https://github.com/irssi/scripts/raw/master/scripts/perlalias.pl
+description Quickly create commands from short perl blocks
+
+script pggb_sound.pl
+url https://github.com/irssi/scripts/raw/master/scripts/pggb_sound.pl
+description does CTCP SOUNDs and other similar things.
+
+script poison.pl
+url https://github.com/irssi/scripts/raw/master/scripts/poison.pl
+description equips Irssi with an interface to giFT
+
+script postpone.pl
+url https://github.com/irssi/scripts/raw/master/scripts/postpone.pl
+description Postpones messages sent to a splitted user and resends them when the nick rejoins
+
+script ppl.pl
+url https://github.com/irssi/scripts/raw/master/scripts/ppl.pl
+description port of asmodean's /ppl command from skuld3
+
+script print_signals.pl
+url https://github.com/irssi/scripts/raw/master/scripts/print_signals.pl
+description hooks into almost every signal and writes the information provided to a file
+
+script query.pl
+url https://github.com/irssi/scripts/raw/master/scripts/query.pl
+description Give you more control over when to jump to query windows and when to just tell you one has been created. Enhanced autoclose.
+
+script queryresume.pl
+url https://github.com/irssi/scripts/raw/master/scripts/queryresume.pl
+description restores the last lines of a query on re-creation
+
+script quitrand.pl
+url https://github.com/irssi/scripts/raw/master/scripts/quitrand.pl
+description Random quit messages - based on quitmsg (Timo Sirainen)
+
+script quiz.pl
+url https://github.com/irssi/scripts/raw/master/scripts/quiz.pl
+description Turns irssi into a quiz bot
+
+script quizgr.pl
+url https://github.com/irssi/scripts/raw/master/scripts/quizgr.pl
+description Turns irssi into a quiz bot. Has greek language and many answers support
+
+script quizmaster.pl
+url https://github.com/irssi/scripts/raw/master/scripts/quizmaster.pl
+description a trivia script for Irssi
+
+script rainbow.pl
+url https://github.com/irssi/scripts/raw/master/scripts/rainbow.pl
+description Prints colored text. Rather simple than sophisticated.
+
+script randaway.pl
+url https://github.com/irssi/scripts/raw/master/scripts/randaway.pl
+description Random away-messages
+
+script randname.pl
+url https://github.com/irssi/scripts/raw/master/scripts/randname.pl
+description Random "/set real_name" taken from a file.
+
+script relm.pl
+url https://github.com/irssi/scripts/raw/master/scripts/relm.pl
+description Keeps last 15 messages in cache
+
+script remote.pl
+url https://github.com/irssi/scripts/raw/master/scripts/remote.pl
+description Lets you run commands remotely via /msg and a password
+
+script repeat.pl
+url https://github.com/irssi/scripts/raw/master/scripts/repeat.pl
+description Hide duplicate lines
+
+script resize_split.pl
+url https://github.com/irssi/scripts/raw/master/scripts/resize_split.pl
+description Resizes a split window when it is made active (see comments in script for details)
+
+script revolve.pl
+url https://github.com/irssi/scripts/raw/master/scripts/revolve.pl
+description Summarizes multiple sequential joins/parts/quits.
+
+script rk.pl
+url https://github.com/irssi/scripts/raw/master/scripts/rk.pl
+description /RK [-o | -l | -a] - kicks random nick from ops | lusers | all on channel
+
+script romaji.pl
+url https://github.com/irssi/scripts/raw/master/scripts/romaji.pl
+description translates romaji to hiragana or katakana in text enclosed in ^R
+
+script romajibind.pl
+url https://github.com/irssi/scripts/raw/master/scripts/romajibind.pl
+description Dynamic romaji binds
+
+script rot13.pl
+url https://github.com/irssi/scripts/raw/master/scripts/rot13.pl
+description ROT13 encoding and reverse :)
+
+script rotator.pl
+url https://github.com/irssi/scripts/raw/master/scripts/rotator.pl
+description Displaye a small, changeing statusbar item to show irssi is still running
+
+script schwaebisch.pl
+url https://github.com/irssi/scripts/raw/master/scripts/schwaebisch.pl
+description /schwäbisch - translates your messages from german to swabian
+
+script screen_away.pl
+url https://github.com/irssi/scripts/raw/master/scripts/screen_away.pl
+description set (un)away, if screen is attached/detached
+
+script scripthelp.pl
+url https://github.com/irssi/scripts/raw/master/scripts/scripthelp.pl
+description Provides access to script's help
+
+script scriptinfo.pl
+url https://github.com/irssi/scripts/raw/master/scripts/scriptinfo.pl
+description Access script information
+
+script scroller.pl
+url https://github.com/irssi/scripts/raw/master/scripts/scroller.pl
+description Scrolls specified text on the status bar
+
+script seen.pl
+url https://github.com/irssi/scripts/raw/master/scripts/seen.pl
+description Tell people when other people were online
+
+script shortenurl.pl
+url https://github.com/irssi/scripts/raw/master/scripts/shortenurl.pl
+description shortenurl
+
+script showhilight.pl
+url https://github.com/irssi/scripts/raw/master/scripts/showhilight.pl
+description Show hilight messages in active window
+
+script showhost.pl
+url https://github.com/irssi/scripts/raw/master/scripts/showhost.pl
+description show host kicks
+
+script showmode.pl
+url https://github.com/irssi/scripts/raw/master/scripts/showmode.pl
+description show modes in parts, quits, kicks, topic changes or actions, like show_nickmode does for public messages
+
+script smiley.pl
+url https://github.com/irssi/scripts/raw/master/scripts/smiley.pl
+description Very useful smiley-flooder
+
+script sms.pl
+url https://github.com/irssi/scripts/raw/master/scripts/sms.pl
+description /ADDSMS, /DELSMS, /LISTSMS and /SMS - phone address-book with smssender, for now supports only Polish operators
+
+script snmpup.pl
+url https://github.com/irssi/scripts/raw/master/scripts/snmpup.pl
+description This script queries remote hosts (/snmpup <host1> <host2> <hostN>) running snmpd for it's uptime and cpu usage
+
+script spambot.pl
+url https://github.com/irssi/scripts/raw/master/scripts/spambot.pl
+description Oper script to kill Spam Bots.
+
+script special_complete.pl
+url https://github.com/irssi/scripts/raw/master/scripts/special_complete.pl
+description (tab)complete irssi special variables (words that start with $) by evaluating them
+
+script spellcheck.pl
+url https://github.com/irssi/scripts/raw/master/scripts/spellcheck.pl
+description checks for spelling errors using Aspell
+
+script sping.pl
+url https://github.com/irssi/scripts/raw/master/scripts/sping.pl
+description /SPING [server] - checks latency between current server and [server]
+
+script synccheck.pl
+url https://github.com/irssi/scripts/raw/master/scripts/synccheck.pl
+description Script checking channel synchronization. Usage: /sync-check [channel (servers)|-stop]
+
+script sysinfo277-irssi.pl
+url https://github.com/irssi/scripts/raw/master/scripts/sysinfo277-irssi.pl
+description Cross-platform/architecture system information script.
+
+script sysinfo_dg.pl
+url https://github.com/irssi/scripts/raw/master/scripts/sysinfo_dg.pl
+description Adds a /sysinfo command which prints system information (linux only).
+
+script sysinfoplus.pl
+url https://github.com/irssi/scripts/raw/master/scripts/sysinfoplus.pl
+description Linux system information (with vPenis and other stuff)
+
+script tab_stop.pl
+url https://github.com/irssi/scripts/raw/master/scripts/tab_stop.pl
+description Replaces \t TAB characters to line up with tab stops (default 8) or to contents of /set tabstop_replacement if tabstop_interval is set to 0
+
+script talk.pl
+url https://github.com/irssi/scripts/raw/master/scripts/talk.pl
+description This script talks to you *g*. It reads the chat-msgs for you.
+
+script target.pl
+url https://github.com/irssi/scripts/raw/master/scripts/target.pl
+description advances IRC warfare to the next level ;)
+
+script thankop.pl
+url https://github.com/irssi/scripts/raw/master/scripts/thankop.pl
+description Remembers the last person oping you on a channel
+
+script theme.pl
+url https://github.com/irssi/scripts/raw/master/scripts/theme.pl
+description activate, show or get theme
+
+script thistory.pl
+url https://github.com/irssi/scripts/raw/master/scripts/thistory.pl
+description Keeps information about the most recent topics of the channels you are on.
+
+script tictactoe.pl
+url https://github.com/irssi/scripts/raw/master/scripts/tictactoe.pl
+description tic-tac-toe game
+
+script timer.pl
+url https://github.com/irssi/scripts/raw/master/scripts/timer.pl
+description Provides /timer command for mIRC/BitchX type timer functionality.
+
+script tinyurl.pl
+url https://github.com/irssi/scripts/raw/master/scripts/tinyurl.pl
+description create a tinyurl from a long one
+
+script title.pl
+url https://github.com/irssi/scripts/raw/master/scripts/title.pl
+description Display configurable title as XTerm title
+
+script tlock.pl
+url https://github.com/irssi/scripts/raw/master/scripts/tlock.pl
+description /TLOCK [-d] [channel] [topic] - locks current or specified topic on [channel]
+
+script tmux-nicklist-portable.pl
+url https://github.com/irssi/scripts/raw/master/scripts/tmux-nicklist-portable.pl
+description displays a list of nicks in a separate tmux pane
+
+script topics.pl
+url https://github.com/irssi/scripts/raw/master/scripts/topics.pl
+description records a topic history and locks the channel topic
+
+script topicsed.pl
+url https://github.com/irssi/scripts/raw/master/scripts/topicsed.pl
+description editing channel topics by regexps
+
+script track.pl
+url https://github.com/irssi/scripts/raw/master/scripts/track.pl
+description Keeps track of users by building a databaseof online, joining and nickchanges. Regex-cabablefor the most part, AKA import available. Search byident, nick or host
+
+script trackbar.pl
+url https://github.com/irssi/scripts/raw/master/scripts/trackbar.pl
+description Shows a bar where you have last read a window.
+
+script tracknick.pl
+url https://github.com/irssi/scripts/raw/master/scripts/tracknick.pl
+description Are you ever tired of those people who keep changing their nicks? Or maybe you just don't like someone's nick? This script lets you see them with the real nick all the time no matter what nick they're currently using.
+
+script trigger.pl
+url https://github.com/irssi/scripts/raw/master/scripts/trigger.pl
+description execute a command or replace text, triggered by an event in irssi
+
+script trustweb.pl
+url https://github.com/irssi/scripts/raw/master/scripts/trustweb.pl
+description Illustrates the trust between ops
+
+script twprompt.pl
+url https://github.com/irssi/scripts/raw/master/scripts/twprompt.pl
+description BitchX's CrackRock3 animated prompt bar.
+
+script twsocials.pl
+url https://github.com/irssi/scripts/raw/master/scripts/twsocials.pl
+description IRC version of Social Commands
+
+script twtopic.pl
+url https://github.com/irssi/scripts/raw/master/scripts/twtopic.pl
+description Animated Topic bar.
+
+script upgradeinfo.pl
+url https://github.com/irssi/scripts/raw/master/scripts/upgradeinfo.pl
+description Statusbar item notifying you about updated binary
+
+script uptime.pl
+url https://github.com/irssi/scripts/raw/master/scripts/uptime.pl
+description Try a little harder to figure out client uptime
+
+script url_log.pl
+url https://github.com/irssi/scripts/raw/master/scripts/url_log.pl
+description logs urls to textfile or/and database, able to list, quote, open or `http head` saved urls.
+
+script urlfeed.pl
+url https://github.com/irssi/scripts/raw/master/scripts/urlfeed.pl
+description Provides RSS feeds with URLs pasted on your channels.
+
+script urlgrab.pl
+url https://github.com/irssi/scripts/raw/master/scripts/urlgrab.pl
+description Captures urls said in channel and private messages and saves them to a file, also adds a /url command which loads the last said url into a browser.
+
+script urlplot.pl
+url https://github.com/irssi/scripts/raw/master/scripts/urlplot.pl
+description URL grabber with HTML generation and cmd execution
+
+script urlwindow.pl
+url https://github.com/irssi/scripts/raw/master/scripts/urlwindow.pl
+description Log all urls from #channels and /msgs in a separate window
+
+script userhost.pl
+url https://github.com/irssi/scripts/raw/master/scripts/userhost.pl
+description Adds a -cmd option to the /USERHOST builtin command
+
+script users.pl
+url https://github.com/irssi/scripts/raw/master/scripts/users.pl
+description Implements /USERS
+
+script version-stat.pl
+url https://github.com/irssi/scripts/raw/master/scripts/version-stat.pl
+description shows top[0-9]+ irc client versions in a channel
+
+script verstats.pl
+url https://github.com/irssi/scripts/raw/master/scripts/verstats.pl
+description Draws a diagram of the used clients in a channel
+
+script vowels.pl
+url https://github.com/irssi/scripts/raw/master/scripts/vowels.pl
+description Silly script, removes vowels, idea taken from #linuxnews ;-)
+
+script warnkick.pl
+url https://github.com/irssi/scripts/raw/master/scripts/warnkick.pl
+description warns you if someone kicks you out of a channel
+
+script washnicks.pl
+url https://github.com/irssi/scripts/raw/master/scripts/washnicks.pl
+description Removes annoying characters from nicks
+
+script watch.pl
+url https://github.com/irssi/scripts/raw/master/scripts/watch.pl
+description Uso del comando watch para irssi.
+
+script whitelist.pl
+url https://github.com/irssi/scripts/raw/master/scripts/whitelist.pl
+description Whitelist specific nicks or hosts and ignore messages from anyone else.
+
+script whois.pl
+url https://github.com/irssi/scripts/raw/master/scripts/whois.pl
+description Hilights '@' in whois channel reply
+
+script whos.pl
+url https://github.com/irssi/scripts/raw/master/scripts/whos.pl
+description This script allows you to view all users on a specific server.
+
+script wilm.pl
+url https://github.com/irssi/scripts/raw/master/scripts/wilm.pl
+description Provides /wilm and /wiilm commands, which do a whois on a person who sent you last private message
+
+script wkb.pl
+url https://github.com/irssi/scripts/raw/master/scripts/wkb.pl
+description A simple word kickbanner
+
+script wordcompletition.pl
+url https://github.com/irssi/scripts/raw/master/scripts/wordcompletition.pl
+description Adds words from IRC to your tab-completion list
+
+script wordscramble.pl
+url https://github.com/irssi/scripts/raw/master/scripts/wordscramble.pl
+description A script that scrambles all the letters in a word except the first and last.
+
+script xauth.pl
+url https://github.com/irssi/scripts/raw/master/scripts/xauth.pl
+description Undernet X Service Authentication Program
+
+script xcmd.pl
+url https://github.com/irssi/scripts/raw/master/scripts/xcmd.pl
+description makes Undernet's X commands easier and faster to use
+
+script xdccget.pl
+url https://github.com/irssi/scripts/raw/master/scripts/xdccget.pl
+description enhanced downloading, queing, searching from XDCC bots
+
+script xlist.pl
+url https://github.com/irssi/scripts/raw/master/scripts/xlist.pl
+description Better readable listing of channel names
+
+script xmms.pl
+url https://github.com/irssi/scripts/raw/master/scripts/xmms.pl
+description XMMS-InfoPipe front-end - allow /np [-help] [dest]
+
+script xmms2.pl
+url https://github.com/irssi/scripts/raw/master/scripts/xmms2.pl
+description Returns XMMS-InfoPipe data
+
+script xmmsinfo.pl
+url https://github.com/irssi/scripts/raw/master/scripts/xmmsinfo.pl
+description /xmmsinfo to tell what you're currently playing
+
+script xqf.pl
+url https://github.com/irssi/scripts/raw/master/scripts/xqf.pl
+description automatically sends xqf data to irssi and optionally licq
+
+script ontv.pl
+url https://github.com/irssi/scripts/raw/master/scripts/ontv.pl
+description turns irssi into a tv program guide
+
+script tvmusor.pl
+url https://github.com/irssi/scripts/raw/master/scripts/tvmusor.pl
+description asks for the current tv-lineup from http://www.port.hu/
+
+script emaildb1.0.pl
+url https://github.com/irssi/scripts/raw/master/scripts/emaildb1.0.pl
+description a script for accessing an email mysql database through irc
+
+script freenode_filter.pl
+url https://github.com/irssi/scripts/raw/master/scripts/freenode_filter.pl
+description This script will filter some Freenode IRCD (Dancer) servernotices.
+
+script noteserve.pl
+url https://github.com/irssi/scripts/raw/master/scripts/noteserve.pl
+description Utilizes NoteServ to implement a buddylist
+
+script sana_cmd.pl
+url https://github.com/irssi/scripts/raw/master/scripts/sana_cmd.pl
+description /sana command, translates english-finnish-english.
+
+script seti.pl
+url No upstream source.
+description Tell ppl how far you've gotten with you SETI\@home workunit.
+
+script bgta.pl
+url https://github.com/irssi/scripts/raw/master/scripts/bgta.pl
+description Byte's Gallery of the TAilor Script
+
+script cloneprot.pl
+url https://github.com/irssi/scripts/raw/master/scripts/cloneprot.pl
+description Parses OperServ notices to make autokill aliases from clonewarnings
+
+script dancer_hide_477.pl
+url https://github.com/irssi/scripts/raw/master/scripts/dancer_hide_477.pl
+description This script hides the 477 numerics from the dancer IRCd.
+
+script identify-md5.pl
+url https://github.com/irssi/scripts/raw/master/scripts/identify-md5.pl
+description MD5 NickServ identification script for SorceryNet
+
+script mygoogle.pl
+url https://github.com/irssi/scripts/raw/master/scripts/mygoogle.pl
+description Query Google
+
+script myimdb.pl
+url https://github.com/irssi/scripts/raw/master/scripts/myimdb.pl
+description Query imdb
+
+script stocks.pl
+url https://github.com/irssi/scripts/raw/master/scripts/stocks.pl
+description prints the stats for german stocks
+
+script xetra.pl
+url https://github.com/irssi/scripts/raw/master/scripts/xetra.pl
+description brings the stock exchanges of the world to your irssi
+
+script mkshorterlink.pl
+url https://github.com/irssi/scripts/raw/gh-pages/scripts/mkshorterlink.pl
+description Automatically filters all http:// links through makeashorterlink.com
+
+script twirssi.pl
+url http://raw.github.com/zigdon/twirssi/master/twirssi.pl
+description Send twitter updates using /tweet.
+
+script akilluser.pl
+url http://raw.github.com/oftc/oftc-tools/master/oper/akilluser.pl
+description AKILL a specified nick
+
+script challenge.pl
+url http://raw.github.com/oftc/oftc-tools/master/oper/challenge.pl
+description Run a challenge response oper thingie
+
+script nickident.pl
+url http://raw.github.com/oftc/oftc-tools/master/user/irssi/nickident.pl
+description identify to nickserv
+
+script quiet.pl
+url http://raw.github.com/oftc/oftc-tools/master/user/irssi/quiet.pl
+description This script adds support for +q (quiet user) channel modes to irssi.
+
+script auto_away.pl
+url http://raw.github.com/timing/irssi-scripts/master/auto_away.pl
+description sets an away message automatically when you're idle
+
+script idlesince.pl
+url http://tris.net/irssi/scripts/idlesince.pl
+description Adds 'idle since' line to whois replies.
+
+script topic-diff.pl
+url http://svn.df7cb.de/dotfiles/cb/.irssi/scripts/topic-diff.pl
+description This script shows you changes in the topic.
+
+script phpdoc.pl
+url No upstream source.
+description Display all functions of the famous language PHP which is used in the funcsummary.txt file in the CVS of http://php.net
+
+script sana.pl
+url No upstream source.
+description responds to "!sana test" command on channels/publics with a finnish/english translation given as parameter
+
+script url.pl
+url No upstream source.
+description url.pl grabs URLs in messages and allows you to open them on the fly, or to write them in a HTML file and open that file.
+
diff --git a/scripts/0x0st.pl b/scripts/0x0st.pl
new file mode 100644
index 0000000..95c7d96
--- /dev/null
+++ b/scripts/0x0st.pl
@@ -0,0 +1,215 @@
+use strict;
+use vars qw($VERSION %IRSSI);
+
+use POSIX;
+use Irssi;
+use HTTP::Request::Common;
+use LWP::UserAgent;
+use Storable qw/store_fd fd_retrieve/;
+use File::Glob qw/:bsd_glob/;
+
+$VERSION = '0.04';
+%IRSSI = (
+ authors => 'bw1',
+ contact => 'bw1@aol.at',
+ name => '0x0st',
+ description => 'upload file to https://0x0.st/',
+ license => 'ISC',
+ url => 'https://scripts.irssi.org/',
+ changed => '2021-01-13',
+ modules => 'POSIX HTTP::Request::Common LWP::UserAgent Storable File::Glob',
+ commands=> '0x0st',
+ selfcheckcmd=> '0x0st -c',
+);
+
+my $help = << "END";
+%9Name%9
+ $IRSSI{name}
+%9Version%9
+ $VERSION
+%9Syntax%9
+ /0x0st [-p] [-s <URL> | -u <URL> | file ]
+ /0x0st -c
+%9Description%9
+ $IRSSI{description}
+ -p past url to channel
+ -s shorten url
+ -u file from url
+ -c self check
+%9See also%9
+ https://0x0.st/
+ https://github.com/lachs0r/0x0
+END
+
+my $test_str;
+
+my $base_uri;
+
+my %bg_process= ();
+my $self_check_timer;
+
+sub background {
+ my ($cmd) =@_;
+ my ($fh_r, $fh_w);
+ pipe $fh_r, $fh_w;
+ my $pid = fork();
+ if ($pid ==0 ) {
+ my @res;
+ @res= &{$cmd->{cmd}}(@{$cmd->{args}});
+ store_fd \@res, $fh_w;
+ close $fh_w;
+ POSIX::_exit(1);
+ } else {
+ $cmd->{fh_r}=$fh_r;
+ Irssi::pidwait_add($pid);
+ $bg_process{$pid}=$cmd;
+ }
+}
+
+sub sig_pidwait {
+ my ($pid, $status) = @_;
+ if (exists $bg_process{$pid}) {
+ my @res= @{ fd_retrieve($bg_process{$pid}->{fh_r})};
+ $bg_process{$pid}->{res}=[@res];
+ if (exists $bg_process{$pid}->{last}) {
+ foreach my $p (@{$bg_process{$pid}->{last}}) {
+ &$p($bg_process{$pid});
+ }
+ } else {
+ Irssi::print(join(" ",@res), MSGLEVEL_CLIENTCRAP);
+ }
+ delete $bg_process{$pid};
+ }
+}
+
+sub upload {
+ my ($filename) = @_;
+ my $ua = LWP::UserAgent->new(agent=>'wget');
+ my $filename = bsd_glob $filename;
+ if (-e $filename) {
+ my $re = $ua->request(POST $base_uri,
+ Content_Type => 'form-data',
+ Content =>
+ {file=>[$filename]}
+ );
+ my $res= $re->content;
+ my $code= $re->code();
+ chomp $res;
+ return $res, $code;
+ }
+}
+
+sub url {
+ my ($url) = @_;
+ my $ua = LWP::UserAgent->new(agent=>'wget');
+ my $re = $ua->request(POST $base_uri,
+ {url=> $url}
+ );
+ my $res= $re->content;
+ my $code= $re->code();
+ chomp $res;
+ return $res, $code;
+}
+
+sub shorten {
+ my ($url) = @_;
+ my $ua = LWP::UserAgent->new(agent=>'wget');
+ my $re = $ua->request(POST $base_uri,
+ {shorten=> $url}
+ );
+ my $res= $re->content;
+ my $code= $re->code();
+ chomp $res;
+ return $res, $code;
+}
+
+sub past2channel {
+ my ($cmd) = @_;
+ my $witem = $cmd->{witem};
+ if (defined $witem && (int($cmd->{res}[1] / 100) == 2)) {
+ $witem->command("msg * $cmd->{res}[0]");
+ } else {
+ Irssi::print($cmd->{res}[0],MSGLEVEL_CLIENTCRAP);
+ }
+}
+
+sub cmd {
+ my ($args, $server, $witem)=@_;
+ my ($opt, $arg) = Irssi::command_parse_options($IRSSI{'name'}, $args);
+
+ if (length($args) >0 ) {
+ my $cmd;
+ if (exists $opt->{p}) {
+ $cmd->{last}=[\&past2channel];
+ $cmd->{witem}=$witem;
+ }
+ if (exists $opt->{u}) {
+ $cmd->{cmd}=\&url;
+ $cmd->{args}=[$arg];
+ background( $cmd );
+ } elsif (exists $opt->{s}) {
+ $cmd->{cmd}=\&shorten;
+ $cmd->{args}=[$arg];
+ background( $cmd );
+ } elsif (exists $opt->{c}) {
+ $cmd->{cmd}=\&shorten;
+ $cmd->{args}=['https://scripts.irssi.org/'];
+ $cmd->{last}=[\&self_check];
+ $self_check_timer= Irssi::timeout_add_once(2000, \&self_check, '');
+ background( $cmd );
+ } else {
+ $cmd->{cmd}=\&upload;
+ $cmd->{args}=[$arg];
+ background( $cmd );
+ }
+ } else {
+ cmd_help($IRSSI{'name'});
+ }
+}
+
+sub self_check {
+ my ( $arg )=@_;
+ my $s='ok';
+ my @res;
+ if ( ref($arg) ne 'HASH' ) {
+ $s = 'Error: timeout';
+ } else {
+ @res= @{$arg->{res}};
+ Irssi::timeout_remove($self_check_timer);
+ Irssi::print("0x0st: surl: $res[0] stat: $res[1]", MSGLEVEL_CLIENTCRAP);
+ if ( 2 != scalar (@res ) ) {
+ $s = 'Error: arg count';
+ } elsif ( $res[1] != 200 ) {
+ $s = "Error: HTTP status code ($res[1])";
+ } elsif ( $res[0] !~ m/^http/ ) {
+ $s = "Error: result ($res[0])";
+ }
+ }
+ Irssi::print("0x0st: selfckeck $s", MSGLEVEL_CLIENTCRAP);
+ my $schs_version = $Irssi::Script::selfcheckhelperscript::VERSION;
+ Irssi::command("selfcheckhelperscript $s") if (defined $schs_version);
+}
+
+sub cmd_help {
+ my ($args, $server, $witem)=@_;
+ $args=~ s/\s+//g;
+ if ($IRSSI{name} eq $args) {
+ Irssi::print($help, MSGLEVEL_CLIENTCRAP);
+ Irssi::signal_stop();
+ }
+}
+
+sub sig_setup_changed {
+ $base_uri= Irssi::settings_get_str($IRSSI{name}.'_base_uri');
+}
+
+Irssi::signal_add('setup changed', \&sig_setup_changed);
+Irssi::signal_add('pidwait', \&sig_pidwait);
+
+Irssi::settings_add_str($IRSSI{name} ,$IRSSI{name}.'_base_uri', 'https://0x0.st/');
+
+Irssi::command_bind($IRSSI{name}, \&cmd);
+Irssi::command_bind('help', \&cmd_help);
+Irssi::command_set_options($IRSSI{name},"p u s c");
+
+sig_setup_changed();
diff --git a/scripts/8-ball.pl b/scripts/8-ball.pl
new file mode 100644
index 0000000..cb8a0df
--- /dev/null
+++ b/scripts/8-ball.pl
@@ -0,0 +1,131 @@
+#8-ball / decision ball
+#
+#What is this?
+#
+#The 8-ball (Eight-ball) is a decision ball which i bought
+#in a gadget shop when i was in London. I then came up with
+#the idea to make an irc-version of this one :)
+#There are 16 possible answers that the ball may give you.
+#
+#
+#usage
+#
+#Anyone in the same channel as the one who runs this script may
+#write "8-ball: question ?" without quotes and where question is
+#a question to ask the 8-ball.
+#An answer is given randomly. The possible answers are the exact
+#same answers that the real 8-ball gives.
+#
+#Write "8-ball" without quotes to have the the ball tell you
+#how money questions it've got totally.
+#
+#Write "8-ball version" without quotes to have him tell what
+#his version is.
+#
+#
+use strict;
+use warnings;
+use vars qw($VERSION %IRSSI);
+
+use Irssi qw(command_bind signal_add);
+use IO::File;
+$VERSION = '0.23';
+%IRSSI = (
+ authors => 'Patrik Akerfeldt',
+ contact => 'patrik.akerfeldt@gmail.com',
+ name => '8-ball',
+ description => 'Dont like to take decisions? Have the 8-ball do it for you instead.',
+ license => 'GPL',
+);
+
+my $filename= Irssi::get_irssi_dir().'/8-ball';
+
+sub own_question {
+ my ($server, $msg, $target) = @_;
+ question($server, $msg, "", $target);
+}
+
+sub public_question {
+ my ($server, $msg, $nick, $address, $target) = @_;
+ question($server, $msg, $nick.": ", $target);
+}
+sub question {
+ my ($server, $msg, $nick, $target) = @_;
+ $_ = $msg;
+ if (!/^8-ball/i) { return 0; }
+
+ if (/^8-ball:.+\?$/i) {
+ # From: "The 8-Ball Answers", http://8ball.ofb.net/answers.html
+ my @answers = (
+ 'Signs point to yes.',
+ 'Yes.',
+ 'Reply hazy, try again.',
+ 'Without a doubt.',
+ 'My sources say no.',
+ 'As I see it, yes.',
+ 'You may rely on it.',
+ 'Concentrate and ask again.',
+ 'Outlook not so good.',
+ 'It is decidedly so.',
+ 'Better not tell you now.',
+ 'Very doubtful.',
+ 'Yes - definitely.',
+ 'It is certain.',
+ 'Cannot predict now.',
+ 'Most likely.',
+ 'Ask again later.',
+ 'My reply is no.',
+ 'Outlook good.',
+ 'Don\'t count on it.'
+ );
+
+ $server->command('msg '.$target.' '.$nick.'8-ball says: '.$answers[rand @answers]);
+
+ my ($fh, $count);
+ $fh = new IO::File;
+ $count = 0;
+ if ($fh->open($filename, 'r')){
+ $count = <$fh>;
+ $fh->close;
+ }
+ $count++;
+ $fh = new IO::File;
+ if ($fh->open($filename, 'w')){
+ print $fh $count;
+ $fh->close;
+ }else{
+ print "Couldn't open file for output. The value $count couldn't be written.";
+ return 1;
+ }
+ return 0;
+ } elsif (/^8-ball$/i) {
+
+ my ($fh, $count);
+ $fh = new IO::File;
+ $count = 0;
+ if ($fh->open($filename, 'r')){
+ $count = <$fh>;
+ $server->command('msg '.$target.' 8-ball says: I\'ve got '.$count.' questions so far.');
+ $fh->close;
+ }else{
+ print "Couldn't open file for input";
+ return 1;
+ }
+ return 0;
+
+ } elsif (/^8-ball version$/i){
+ $server->command('msg '.$target.' My version is: '.$VERSION);
+ return 0;
+ } else {
+ if(!/^8-ball says/i){
+ $server->command('msg '.$target.' '.$nick.'A question please.');
+ return 0;
+ }
+ }
+
+}
+
+signal_add("message public", "public_question");
+signal_add("message own_public", "own_question");
+
+# vim:set ts=8 sw=8:
diff --git a/scripts/Cirssi.pl b/scripts/Cirssi.pl
new file mode 100644
index 0000000..92e0b9f
--- /dev/null
+++ b/scripts/Cirssi.pl
@@ -0,0 +1,802 @@
+use strict;
+use vars qw($VERSION %IRSSI);
+# Consolidate Irssi Player
+#
+# Copyright (C) 2009 Dani Soufi
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# Change Log:
+# v2.2:
+# - change the audacious and audtool command name
+# v2.0.1b:
+# - Cleaning some unusefull code.
+# - Show an error when a command is executed in a wrong window, instead of exiting silently.
+# v2.0.0:
+# - Start/Play(Toggle)/Stop/Pause/Unpause/Next/Previous/Volume MOC Player control functions are added.
+# - MOC Player support is implemented.
+# v1.1.2:
+# - The script is now meant to be a bit more intelligent in dealing with song tags and different user song display settings.
+# - Display album name in --details if it exists.
+# v1.1.0:
+# - Script's name is renamed to Consolidate Irssi Player on global basis to expand it's use in the future.
+# - Removed cmd_shuffle{} and cmd_repeat{} functions since they aren't supported anymore by Audacious2.
+# - Added use --details flag for bitrate and frequency details in current playing song.
+# - Added Jump to specific song in the playing list according to track number.
+# - Added Volume control support from Irssi.
+# - Updated the script to work with the newest Audacious v2 and audtool2 available.
+# v1.0.4:
+# - Added Repeat on/off capability
+# - Added Shuffle on/off capability
+# - Fixed script output handling for audacious version in case audacious isn't running
+# - If encountered a problem with audacious version, try changing `audacious --version` to `audtool -v`
+# v1.0.3:
+# - Added Playlist functionality
+# - Added Song details (Bitrate/Frequency/Length/Volume)
+# - Current song notice with song details (Optional)
+# v1.0.2:
+# - The script now handles warning support if you got audacious not running
+# - Added track number, current time elapse and total track time
+# - Added Stop functionality
+# v1.0.1:
+# - Added ability to autonotify the channel after skipping a song (optional)
+# - Added Skip/Play/Pause/Resume calls
+#
+# How To Use?
+# Copy your script into ~/.irssi/scripts/ directory
+# Load your script with /script load audacious in your Irssi Client
+# Type '/audacious help' in any channel for script commands
+# For autoload insert your script into ~/.irssi/scripts/autorun/ directory
+# Even better would be if you placed them in ~/.irssi/scripts/ and created symlinks in autorun directory
+#
+use Irssi;
+use IPC::Open3;
+
+$VERSION = '2.2';
+%IRSSI = (
+ authors => "Dani Soufi (compengi)",
+ contact => "IRC: Freenode network, #ubuntu-lb",
+ name => "Consolidate Irssi Player",
+ description => "Controls Audacious2 and MOCP from Irssi",
+ license => "GNU General Public License",
+ url => "http://git.peersnode.net/",
+ changed => "2019-01-20",
+);
+
+#################################################################################
+# Please do not change anything below this, unless you know what you are doing. #
+#################################################################################
+
+# command names of audacious and audtool
+my $c_audtool="audtool";
+my $c_audacious="audacious";
+
+# Give an error when a command is used where it was not supposed to, instead
+# of exiting silently. Much better this way.
+sub cmd_err {
+ print "Error: This command can't be executed in this window.";
+}
+
+sub cmd_aud_song {
+ my ($data, $server, $witem) = @_;
+ # Get current song information.
+ if ($witem && ($witem->{type} eq "CHANNEL")) {
+ my ($position, $song, $current, $total, $artist, $album, $title,
+ $total, $bitrate, $frequency, $album);
+
+ chomp($position = `$c_audtool --playlist-position`);
+ chomp($song = `$c_audtool --current-song`);
+ chomp($current = `$c_audtool --current-song-output-length`);
+ chomp($total = `$c_audtool --current-song-length`);
+ chomp($artist = `$c_audtool --current-song-tuple-data artist`);
+ chomp($album = `$c_audtool current-song-tuple-data album`);
+ chomp($title = `$c_audtool --current-song-tuple-data title`);
+ chomp($total = `$c_audtool --current-song-length`);
+ chomp($bitrate = `$c_audtool --current-song-bitrate-kbps`);
+ chomp($frequency = `$c_audtool --current-song-frequency-khz`);
+ chomp($album = `$c_audtool current-song-tuple-data album`);
+
+
+ # Read output.
+ my ( $wtr, $rdr, $err );
+ my $pid = open3( $wtr, $rdr, $err,
+ $c_audtool, '--current-song-tuple-data', 'file-name') or die $!;
+
+ # Make it global.
+ my $file;
+ {
+ local $/;
+ $file = <$rdr>;
+ $file =~ s/\.(?i:mp3|cda|aa3|ac3|aif|ape|med|mpu|wave|mpc|oga|wma|ogg|wav|aac|flac)\n//;
+ }
+
+ if (`ps -C $c_audacious` =~ /audacious/) {
+ if ($data ne "--details") {
+
+ # If we notice that the user sorted his playlist
+ # by song title, we will try to be nice and parse
+ # the existing artist for him.
+ if ($song !~ /$artist/) {
+ # If $song is different from $album,
+ # we add the artist to output line.
+ # Else strip the album from $song.
+ if ($song !~ /$album/) {
+ # If we have no song tags, $song will be set to the file's name.
+ # In this case, we drop the file's extension know to us and print it.
+ if ($song =~ /$file/) {
+ $witem->command("/me is listening to: $file ($current/$total)");
+ }
+ else {
+ $witem->command("/me is listening to: $artist - $song ($current/$total)");
+ }
+ }
+ else {
+ $song =~ s/$album - //im;
+ $witem->command("/me is listening to: $artist - $song ($current/$total)");
+ }
+ }
+ else {
+ $witem->command("/me is listening to: $artist - $title ($current/$total)");
+ }
+ }
+ # Show more details in our output.
+ if ($data eq "--details") {
+
+ # Check against an empty string.
+ # If it's empty, we don't print it.
+ if ($album ne "") {
+ # Make sure $song doesn't match $artist.
+ # Else we print the $song as it is.
+ if ($song !~ /$artist/) {
+ # If $song is different from $album,
+ # we add the artist to output line.
+ # Else strip the album from $song.
+ if ($song !~ /$album/) {
+ if ($song =~ /$file/) {
+ $witem->command("/me is listening to: $artist - $song from $album ($current/$total) [$bitrate Kbps/$frequency KHz]");
+ }
+ }
+ else {
+ $witem->command("/me is listening to: $artist - $title from $album ($current/$total) [$bitrate Kbps/$frequency KHz]");
+ }
+ }
+ elsif ($song =~ /\[ $album \]/) {
+ $witem->command("/me is listening to: $artist - $title from $album ($current/$total) [$bitrate Kbps/$frequency KHz]");
+ }
+ else {
+ $song =~ s/$album - //im;
+ $witem->command("/me is listening to: $song from $album ($current/$total) [$bitrate Kbps/$frequency KHz]");
+ }
+ }
+ elsif ($song =~ /$file/) {
+ $witem->command("/me is listening to: $file ($current/$total) [$bitrate Kbps/$frequency KHz]");
+ }
+ else {
+ $witem->command("/me is listening to: $artist - $title ($current/$total) [$bitrate Kbps/$frequency KHz]");
+ }
+ }
+ }
+ else {
+ $witem->print("Audacious is not currently running.");
+ }
+ return 1;
+ }
+ else {
+ cmd_err();
+ }
+}
+
+sub cmd_aud_next {
+ my ($data, $server, $witem) = @_;
+ # Skip to the next track.
+ if ($witem && ($witem->{type} eq "CHANNEL")) {
+ if (`ps -C audacious` =~ /audacious/) {
+ my $next = `$c_audtool --playlist-advance`;
+
+ $witem->print("Skipped to next track.");
+ }
+ else {
+ $witem->print("Can't skip to next track. Check your Audacious.");
+ }
+ return 1;
+ }
+ else {
+ cmd_err();
+ }
+}
+
+sub cmd_aud_previous {
+ my ($data, $server, $witem) = @_;
+ # Skip to the previous track.
+ if ($witem && ($witem->{type} eq "CHANNEL")) {
+ if (`ps -C $c_audacious` =~ /audacious/) {
+ my $reverse = `$c_audtool --playlist-reverse`;
+
+ $witem->print("Skipped to previous track.");
+ }
+ else {
+ $witem->print("Can't skip to next track. Check your Audacious.");
+ }
+ return 1;
+ }
+ else {
+ cmd_err();
+ }
+}
+
+sub cmd_aud_play {
+ my ($data, $server, $witem) = @_;
+ # Start playback.
+ if ($witem && ($witem->{type} eq "CHANNEL")) {
+ if (`ps -C $c_audacious` =~ /audacious/) {
+ my $play = `$c_audtool --playback-play`;
+
+ $witem->print("Started playback.");
+ }
+ else {
+ $witem->print("Playback can't be performed now.");
+ }
+ return 1;
+ }
+ else {
+ cmd_err();
+ }
+}
+
+sub cmd_aud_pause {
+ my ($data, $server, $witem) = @_;
+ # Pause playback.
+ if ($witem && ($witem->{type} eq "CHANNEL")) {
+ if (`ps -C $c_audacious` =~ /audacious/) {
+ my $pause = `$c_audtool --playback-pause`;
+
+ $witem->print("Paused playback.");
+ }
+ else {
+ $witem->print("Pause can be only performed when Audacious is running.");
+ }
+ return 1;
+ }
+ else {
+ cmd_err();
+ }
+}
+
+sub cmd_aud_stop {
+ my ($data, $server, $witem) = @_;
+ # Pause playback.
+ if ($witem && ($witem->{type} eq "CHANNEL")) {
+ if (`ps -C $c_audacious` =~ /audacious/) {
+ my $stop = `$c_audtool --playback-stop`;
+
+ $witem->print("Stopped playback.");
+ }
+ else {
+ $witem->print("This way you can't start Audacious.");
+ }
+ return 1;
+ }
+ else {
+ cmd_err();
+ }
+}
+
+sub cmd_aud_volume {
+ my ($data, $server, $witem) = @_;
+ # Set volume and make sure the value is an integer
+ # that lays between 0 and 100.
+ if ($witem && ($witem->{type} eq "CHANNEL")) {
+ if (`ps -C $c_audacious` =~ /audacious/) {
+
+ if ($data eq "") {
+ $witem->print("Use /audacious volume <value> to set a specific volume value");
+ }
+ elsif ($data < 0 or $data > 100) {
+ $witem->print("Given value is out of range [0-100].");
+ return 0;
+ }
+ elsif ($data =~ /^[\d]+$/) {
+ system $c_audtool,'--set-volume', $data;
+ my $volume = `$c_audtool --get-volume`;
+ chomp($volume);
+ $witem->print("Volume is changed to $volume%%");
+ }
+ else {
+ $witem->print("Please use a value [0-100] instead.");
+ }
+ }
+ else {
+ $witem->print("Volume can't be set in the current state.");
+ }
+ return 1;
+ }
+ else {
+ cmd_err();
+ }
+}
+
+sub cmd_aud_jump {
+ my ($data, $server, $witem) = @_;
+ # Jump to a specific track, making sure that
+ # the selected track number exists.
+ if ($witem && ($witem->{type} eq "CHANNEL")) {
+ if (`ps -C $c_audacious` =~ /audacious/) {
+
+ if ($data eq "") {
+ $witem->print("Use /audacious jump <track> number to jump to it in your playlist.");
+ }
+ elsif ($data =~ /^[\d]+$/) {
+ # Many thanks to Khisanth for this awesome fix!
+ my ( $wtr, $rdr, $err );
+ my $pid = open3( $wtr, $rdr, $err,
+ $c_audtool, '--playlist-jump', $data) or die $!;
+ my $output;
+ {
+ local $/;
+ $output = <$rdr>;
+ }
+ if ($output =~ /invalid/) {
+ $witem->print("Track #$data isn't found in your playlist.");
+ }
+ else {
+ $witem->print("Jumped to track #$data.");
+ }
+ }
+ else {
+ $witem->print("Please use a valid integer.");
+ }
+ }
+ else {
+ $witem->print("Start your audacious first.");
+ }
+ return 1;
+ }
+ else {
+ cmd_err();
+ }
+}
+
+sub cmd_aud_playlist {
+ my ($data, $server, $witem) = @_;
+ # Displays entire playlist loaded.
+ if (`ps -C $c_audacious` =~ /audacious/) {
+ my $display = `$c_audtool --playlist-display`;
+ chomp($display);
+
+ Irssi::print("$display");
+ }
+ else {
+ $witem->print("Start your player first.");
+ }
+ return 1;
+}
+
+sub cmd_aud_search {
+ my ($data, $server, $witem) = @_;
+
+ if ($witem && ($witem->{type} eq "CHANNEL")) {
+ if (`ps -C $c_audacious` =~ /audacious/) {
+ my $playlist = `$c_audtool --playlist-display`;
+ my @matches;
+
+ for (split /\n/, $playlist) {
+ push @matches, $_ if /$data/i;
+ }
+ if (@matches) {
+ $witem->print("Search Results:");
+ for (@matches) {
+ $_ =~ s/^\s+|\s+$//g;
+ $witem->print("$_");
+ }
+ }
+ else {
+ $witem->print("Couldn't find any match(s) for your keyword '$data'.");
+ }
+ }
+ else {
+ $witem->print("Audacious is not running.");
+ }
+ }
+ else {
+ cmd_err();
+ }
+}
+
+
+sub cmd_aud_details {
+ my ($data, $server, $witem) = @_;
+
+ # Displays current song's details.
+ if ($witem && ($witem->{type} eq "CHANNEL")) {
+ if (`ps -C $c_audacious` =~ /audacious/) {
+ my ($bitrate, $frequency, $length, $volume);
+
+ chomp($bitrate = `$c_audtool --current-song-bitrate-kbps`);
+ chomp($frequency = `$c_audtool --current-song-frequency-khz`);
+ chomp($length = `$c_audtool --current-song-length`);
+ chomp($volume = `$c_audtool --get-volume`);
+
+ $witem->print("Current song details: rate: $bitrate kbps - freq: $frequency KHz - l: $length min - vol: $volume%%");
+ }
+ else {
+ $witem->print("Your player doesn't seem to be running");
+ }
+ return 1;
+ }
+ else {
+ cmd_err();
+ }
+}
+
+sub cmd_aud_version {
+ my ($data, $server, $witem) = @_;
+
+ my ($audtool, $audacious);
+ chop($audtool = `$c_audtool --version`);
+ chop($audacious = `$c_audacious --version`);
+
+ # Displays version information to the channel.
+ if ($witem && ($witem->{type} eq "CHANNEL")) {
+
+ if ($data eq "--audtool") {
+ $witem->command("/me is running: Consolidate Irssi Player v$VERSION with $audtool");
+ }
+ elsif ($data eq "--audacious") {
+ $witem->command("/me is running: Consolidate Irssi Player v$VERSION with $audacious");
+ }
+ return 1;
+ }
+ else {
+ Irssi::print("Consolidate Irssi Player v$VERSION on $audacious with $audtool");
+ }
+}
+
+sub cmd_audacious {
+ my ($data, $server, $witem) = @_;
+ if ($data =~ m/^[(song)|(next)|(previous)|(play)|(pause)|(stop)|(help)|(volume)|(jump)|(playlist)|(details)|(about)|(search)]/i) {
+ Irssi::command_runsub('audacious', $data, $server, $witem);
+ }
+ else {
+ Irssi::print("Use /audacious <option> or check /help audacious for the complete list");
+ }
+}
+
+sub cmd_aud_help {
+ my ($data, $server) = @_;
+ # Displays usage screen.
+ Irssi::print("* /audacious song - Displays the current playing song in a channel.");
+ Irssi::print("* /audacious song --details - Displays bitrate and frequency with the current playing song.");
+ Irssi::print("* /audacious next - Skips to the next song.");
+ Irssi::print("* /audacious previous - Skips to the previous song.");
+ Irssi::print("* /audacious play - Starts playback.");
+ Irssi::print("* /audacious pause - Pauses playback.");
+ Irssi::print("* /audacious stop - Stops playback.");
+ Irssi::print("* /audacious volume <value> - Sets volume [0-100].");
+ Irssi::print("* /audacious jump <track> - Jumps to specified track.");
+ Irssi::print("* /audacious playlist - Displays entire playlist.");
+ Irssi::print("* /audacious search <keyword> - Searches for the keyword in your playlist and displays the results.");
+ Irssi::print("* /audacious details - Displays current song's details.");
+ Irssi::print("* /audacious version --audtool - Displays version of the script and audtool in the channel.");
+ Irssi::print("* /audacious version --audacious - Displays version of the script and audacious in the channel.");
+}
+
+sub cmd_moc_song {
+ my ($data, $server, $witem) = @_;
+ if ($witem && ($witem->{type} eq "CHANNEL")) {
+
+ if (`ps -C mocp` =~ /mocp/) {
+
+ my $mocp = `mocp -i`;
+ $mocp =~ /^State: (.*)$/m;
+ my $state = $1;
+ $mocp =~ /.*Title: (.*).*/;
+ my $title = $1;
+ $mocp =~ /.*TotalTime: (.*).*/;
+ my $totaltime = $1;
+ $mocp =~ /.*CurrentTime: (.*).*/;
+ my $currenttime = $1;
+
+ if ($data ne "--details") {
+ if ($state eq '' || $state eq 'STOP') {
+ $witem->print("MOC is not playing.");
+ }
+ else {
+ $witem->command("/me is listening to: $title ($currenttime/$totaltime)");
+ }
+ }
+
+ if ($data eq "--details") {
+ if ($state eq '' || $state eq 'STOP') {
+ $witem->print("MOC is not playing.");
+ }
+ else {
+ $mocp =~ /.*Bitrate: (.*).*/;
+ my $bitrate = $1;
+ $mocp =~ /.*Rate: (.*).*/;
+ my $rate = $1;
+ $witem->command("/me is listening to: $title ($currenttime/$totaltime) [$bitrate/$rate]");
+ }
+ }
+ }
+ else {
+ $witem->print("MOC is not started.");
+ }
+ return 1;
+ }
+ else {
+ cmd_err();
+ }
+}
+
+sub cmd_moc_next {
+ my ($data, $server, $witem) = @_;
+ # Advance to next track in playlist.
+ if ($witem && ($witem->{type} eq "CHANNEL")) {
+
+ if (`ps -C mocp` =~ /mocp/) {
+ my $mocp = `mocp -i`;
+ $mocp =~ /^State: (.*)$/m;
+ my $state = $1;
+
+ if ($state eq '' || $state eq 'STOP') {
+ $witem->print("MOC is not playing.");
+ }
+ else {
+ my $next = `mocp -f`;
+ $witem->print("Skipped to next track.");
+ }
+ }
+ else {
+ $witem->print("Can't skip to next track. Check your MOC Player.");
+ }
+ return 1;
+ }
+ else {
+ cmd_err();
+ }
+}
+
+sub cmd_moc_previous {
+ my ($data, $server, $witem) = @_;
+ # Skip to previous track in playlist.
+ if ($witem && ($witem->{type} eq "CHANNEL")) {
+
+ if (`ps -C mocp` =~ /mocp/) {
+ my $mocp = `mocp -i`;
+ $mocp =~ /^State: (.*)$/m;
+ my $state = $1;
+
+ if ($state eq '' || $state eq 'STOP') {
+ $witem->print("MOC is not playing.");
+ }
+ else {
+ my $next = `mocp -r`;
+ $witem->print("Skipped to previous track.");
+ }
+ }
+ else {
+ $witem->print("Can't skip to previous track. Check your MOC Player.");
+ }
+ return 1;
+ }
+ else {
+ cmd_err();
+ }
+}
+
+sub cmd_moc_play_toggle {
+ my ($data, $server, $witem) = @_;
+ # Start playback.
+ if ($witem && ($witem->{type} eq "CHANNEL")) {
+
+ if (`ps -C mocp` =~ /mocp/) {
+ my $mocp = `mocp -i`;
+ $mocp =~ /^State: (.*)$/m;
+ my $state = $1;
+
+ if ($state eq '' || $state eq 'STOP') {
+ $witem->print("MOC is not playing.");
+ }
+ elsif ($state eq 'PLAY') {
+ my $play_toggle = `mocp -G`;
+ $witem->print("Paused playing song.");
+ }
+ else {
+ my $play = `mocp -G`;
+ $witem->print("Started playback.");
+ }
+ }
+ else {
+ $witem->print("Playback can't be performed now.");
+ }
+ return 1;
+ }
+ else {
+ cmd_err();
+ }
+}
+
+sub cmd_moc_pause {
+ my ($data, $server, $witem) = @_;
+ # Pause playback.
+ if ($witem && ($witem->{type} eq "CHANNEL")) {
+
+ if (`ps -C mocp` =~ /mocp/) {
+ my $mocp = `mocp -i`;
+ $mocp =~ /^State: (.*)$/m;
+ my $state = $1;
+
+ if ($state eq '' || $state eq 'STOP') {
+ $witem->print("MOC is not playing.");
+ }
+ elsif ($state eq 'PAUSE') {
+ $witem->print("The song is already paused.");
+ }
+ else {
+ my $pause = `mocp -P`;
+ $witem->print("Paused playback.");
+ }
+ }
+ else {
+ $witem->print("Pause can be only performed when your MOC Player is running.");
+ }
+ return 1;
+ }
+ else {
+ cmd_err();
+ }
+}
+
+sub cmd_moc_unpause {
+ my ($data, $server, $witem) = @_;
+ # Unpause playback, if and only if the previous song was paused.
+ if ($witem && ($witem->{type} eq "CHANNEL")) {
+
+ if (`ps -C mocp` =~ /mocp/) {
+ my $mocp = `mocp -i`;
+ $mocp =~ /^State: (.*)$/m;
+ my $state = $1;
+
+ if ($state eq '' || $state eq 'STOP') {
+ $witem->print("MOC is not playing.");
+ }
+ elsif ($state eq 'PAUSE') {
+ my $pause = `mocp -U`;
+ $witem->print("Unpaused playback.");
+ }
+ else {
+ $witem->print("Can't unpause your playing song.");
+ }
+ }
+ else {
+ $witem->print("Unpause can be only performed when your MOC Player is running.");
+ }
+ return 1;
+ }
+ else {
+ cmd_err();
+ }
+}
+
+sub cmd_moc_stop {
+ my ($data, $server, $witem) = @_;
+ # Stop the current playing song.
+ if ($witem && ($witem->{type} eq "CHANNEL")) {
+
+ if (`ps -C mocp` =~ /mocp/) {
+ my $mocp = `mocp -i`;
+ $mocp =~ /^State: (.*)$/m;
+ my $state = $1;
+
+ if ($state eq '' || $state eq 'STOP') {
+ $witem->print("MOC is not playing.");
+ }
+ else {
+ my $stop = `mocp -s`;
+ $witem->print("Stopped playback.");
+ }
+ }
+ else {
+ $witem->print("This way you can't stop a song. Double check your player.");
+ }
+ return 1;
+ }
+ else {
+ cmd_err();
+ }
+}
+
+sub cmd_moc_volume {
+ my ($data, $server, $witem) = @_;
+ # Set volume and make sure the value is an integer
+ # that lays between 0 and 100.
+ if ($witem && ($witem->{type} eq "CHANNEL")) {
+ if (`ps -C mocp` =~ /mocp/) {
+
+ if ($data eq "") {
+ $witem->print("Use /mocp volume <value> to set a specific volume value");
+ }
+ elsif ($data < 0 or $data > 100) {
+ $witem->print("Given value is out of range [0-100].");
+ return 0;
+ }
+ elsif ($data =~ /^[\d]+$/) {
+ system 'mocp','-v', $data;
+ $witem->print("Volume is changed to $data%%");
+ }
+ else {
+ $witem->print("Please use a value [0-100] instead.");
+ }
+ }
+ else {
+ $witem->print("Volume can't be set when MOC Player is not functioning.");
+ }
+ return 1;
+ }
+ else {
+ cmd_err();
+ }
+}
+
+sub cmd_moc {
+ my ($data, $server, $witem) = @_;
+ if ($data =~ m/^[(song)|(next)|(previous)|(play)|(pause)|(unpause)|(stop)|(help)|(volume)]/i) {
+ Irssi::command_runsub('mocp', $data, $server, $witem);
+ }
+ else {
+ Irssi::print("Use /mocp <option> or check /help mocp for the complete list");
+ }
+}
+
+sub cmd_moc_help {
+ my ($data, $server) = @_;
+ # Displays usage screen.
+ Irssi::print("* /mocp song - Displays the current playing song in a channel.");
+ Irssi::print("* /mocp song --details - Displays bitrate and frequency with the current playing song.");
+ Irssi::print("* /mocp next - Skips to the next song.");
+ Irssi::print("* /mocp previous - Skips to the previous song.");
+ Irssi::print("* /mocp play - Starts playback.");
+ Irssi::print("* /mocp pause - Pauses playback.");
+ Irssi::print("* /mocp stop - Stops playback.");
+ Irssi::print("* /mocp volume <value> - Sets volume [0-100].");
+}
+
+Irssi::command_bind ('audacious song', 'cmd_aud_song');
+Irssi::command_bind ('audacious next', 'cmd_aud_next');
+Irssi::command_bind ('audacious previous', 'cmd_aud_previous');
+Irssi::command_bind ('audacious play', 'cmd_aud_play');
+Irssi::command_bind ('audacious pause', 'cmd_aud_pause');
+Irssi::command_bind ('audacious stop', 'cmd_aud_stop');
+Irssi::command_bind ('audacious help', 'cmd_aud_help');
+Irssi::command_bind ('audacious volume', 'cmd_aud_volume');
+Irssi::command_bind ('audacious jump', 'cmd_aud_jump');
+Irssi::command_bind ('audacious playlist', 'cmd_aud_playlist');
+Irssi::command_bind ('audacious details', 'cmd_aud_details');
+Irssi::command_bind ('audacious version', 'cmd_aud_version');
+Irssi::command_bind ('audacious', 'cmd_audacious');
+Irssi::command_bind ('mocp song', 'cmd_moc_song');
+Irssi::command_bind ('mocp next', 'cmd_moc_next');
+Irssi::command_bind ('mocp previous', 'cmd_moc_previous');
+Irssi::command_bind ('mocp play', 'cmd_moc_play_toggle');
+Irssi::command_bind ('mocp pause', 'cmd_moc_pause');
+Irssi::command_bind ('mocp unpause', 'cmd_moc_unpause');
+Irssi::command_bind ('mocp stop', 'cmd_moc_stop');
+Irssi::command_bind ('mocp help', 'cmd_moc_help');
+Irssi::command_bind ('mocp volume', 'cmd_moc_volume');
+Irssi::command_bind ('mocp', 'cmd_moc');
+Irssi::command_bind ('audacious search', 'cmd_aud_search');
+
+Irssi::print("Consolidate Irssi Player v$VERSION is loaded successfully.");
+
+# vim:set expandtab sw=2 ts=2:
diff --git a/scripts/UNIBG-autoident.pl b/scripts/UNIBG-autoident.pl
new file mode 100644
index 0000000..c8bee32
--- /dev/null
+++ b/scripts/UNIBG-autoident.pl
@@ -0,0 +1,242 @@
+use strict;
+use vars qw($VERSION %IRSSI);
+use Irssi::TextUI;
+
+$VERSION = "0.2";
+%IRSSI = (
+ authors => 'Doncho N. Gunchev',
+ contact => 'mr_700@yahoo.com',
+ name => 'UNIBG-autoident',
+ description => 'Automaticaly /msg ident NS yourpassword when you connect or services come back from death',
+ license => 'Public Domain',
+ url => 'http://not.available.yet/',
+ changed => '2018-09-10'
+);
+
+# UNIBG NS auto identifyer
+# for irssi 0.8.1 by Doncho N. Gunchev
+#
+# Check /id help for help.
+
+
+my $msghead='autoident:';
+# list of nicks/passwords
+my %passwords = ();
+my $numpasswords = 0;
+my $passwordspassword = '';
+my $nsnick='NS';
+my $nshost='NickServ@UniBG.services';
+my $nsreq='This nickname is registered and protected';
+my $nsok ='Password accepted - you are now recognized';
+my $nscmd ='identify';
+# 2DO
+# 0. Do it!
+# 1. Make it take nick, passwor and network as parameters
+# 2. Make NS, CS, MS and maybe OS support
+# 3. Add eggdrop support
+# 4. Add encrypted passwords in config file...
+# 5. Add Global support or maybe /notify NS or bouth?
+# 6. Don't autoident 2 times in less than xxx seconds
+# 7. Change nick if we don't have the password / ask user for it
+# in xxx seconds before changing nicks
+# 8. Add /id newpass,setpass,permpas,ghost,kill....
+# 9. Add /id chanadd chandel chan....
+#
+
+sub cmd_print_help {
+ Irssi::print(<<EOF, MSGLEVEL_CRAP);
+$msghead
+ WELL... as I'm starting to write this - no help!
+ /id add nick password - add new nick with password to autoident
+ /id del nick - delete nick from autoident list
+ /id list - show nicks in autoident list
+ /id show - same as /id list
+ /id help - this one
+EOF
+# /id check - see if current nick is in autoident list
+}
+
+
+sub msg {
+ my ($msg, $lvl) = @_;
+ Irssi::print("$msghead $msg", $lvl);
+}
+
+
+sub event_notice {
+ # $server = server record where the message came
+ # $data = the raw data received from server, with NOTICEs it is:
+ # "target :text" where target is either your nick or #channel
+ # $nick = the nick who sent the message
+ # $host = host of the nick who sent the message
+ my ($server, $data, $nick, $host) = @_;
+ #04:06 -!- autoident(debug): server= Irssi::Irc::Server=HASH(0x86786cc)
+ #04:06 -!- autoident(debug): data = Mr_700 :This nickname is owned by someone else
+ #04:06 -!- autoident(debug): nick = NS
+ #04:06 -!- autoident(debug): host = NickServ@UniBG.services
+ #04:06 -!- autoident(debug): target = Mr_700
+ #04:06 -!- autoident(debug): text = This nickname is owned by someone else
+
+ # split data to target/text
+ my ($target, $text) = $data =~ /^(\S*)\s:(.*)/;
+
+ # check the sent text
+ return if ($text !~ /$nsreq/) && ($text !~ /$nsok/);
+
+ # check the sender's nick
+ return if ($nick !~ /$nsnick/);
+
+ # check the sender's host
+ if ($host !~ /$nshost/) {
+ msg("!!! '$nsnick' host is bad, hack attempt? !!!", MSGLEVEL_CRAP);
+ msg("!!!", MSGLEVEL_CRAP);
+ msg("!!! sender: '$nick!$host'", MSGLEVEL_CRAP);
+ msg("!!! target: '$target'", MSGLEVEL_CRAP);
+ msg("!!! text : '$text'", MSGLEVEL_CRAP);
+ msg("!!!", MSGLEVEL_CRAP);
+ msg("!!! '$nsnick' host is bad, hack attempt? !!!", MSGLEVEL_CRAP);
+ return;
+ }
+
+ # check if sent to us directly
+ return if ($target !~ /$server->{nick}/);
+
+ if ($text =~ /$nsreq/) {
+ if (exists($passwords{$server->{nick}})) {
+ msg("'$nsnick!$nshost' requested identity, sending...", MSGLEVEL_CRAP);
+ $server->command("MSG $nsnick $nscmd " . $passwords{$server->{nick}});
+ } else {
+ msg("'$nsnick!$nshost' says '$nsreq' and we have no password set for it!", MSGLEVEL_CRAP);
+ msg(" use /id add " . $server->{nick} . " <password> to set it!", MSGLEVEL_CRAP);
+ msg(" ... autoident has left you in /dev/random", MSGLEVEL_CRAP);
+ }
+ } else {
+ msg("'$nsnick!$nshost' accepted identity", MSGLEVEL_CRAP);
+ }
+}
+
+
+sub addpassword {
+ my ($name, $password) = @_;
+
+ if (exists($passwords{$name})) {
+ if ($password eq $passwords{$name}) {
+ msg("Nick $name already has this password for autoident", MSGLEVEL_CRAP);
+ } else {
+ msg("Nick $name's autoident password changed", MSGLEVEL_CRAP);
+ $passwords{$name} = $password;
+ }
+ } else {
+ $passwords{$name} = $password;
+ $numpasswords++;
+ msg("Nick $name added to autoident list ($numpasswords total)", MSGLEVEL_CRAP);
+ }
+}
+
+sub delpassword {
+ my $name = $_[0];
+
+ if (exists($passwords{$name})) {
+ delete($passwords{$name});
+ $numpasswords--;
+ msg("Nick $name removed from autoidentify list ($numpasswords left)", MSGLEVEL_CRAP);
+ } else {
+ msg("Nick $name is not in autoident list", MSGLEVEL_CRAP);
+ }
+}
+
+sub init_passwords {
+ # Add the passwords at startup of the script
+ my $passwordsstring = Irssi::settings_get_str('autoident');
+ if (length($passwordsstring) > 0) {
+ my @passwords = split(/,/, $passwordsstring);
+
+ foreach my $i (@passwords) {
+ my $name = substr($i, 0, index($i, '='));
+ my $password = substr($i, index($i, '=') + 1, length($i));
+ addpassword($name, $password);
+ }
+ }
+}
+
+
+sub read_settings {
+# my $passwords = Irssi::settings_get_str('passwords');
+}
+
+
+sub update_settings_string {
+ my $setting;
+
+ foreach my $name (keys(%passwords)) {
+ $setting .= $name . "=" . $passwords{$name} . ",";
+ }
+
+ Irssi::settings_set_str("autoident", $setting);
+}
+
+
+sub cmd_addpassword {
+ my ($name, $password) = split(/ +/, $_[0]);
+
+ if ($name eq "" || $password eq "") {
+ msg("Use /id add <name> <password> to add new nick to autoident list", MSGLEVEL_CRAP);
+ return;
+ }
+ addpassword($name, $password);
+ update_settings_string();
+}
+
+sub cmd_delpassword {
+ my $name = $_[0];
+
+ if ($name eq "") {
+ msg("Use /id del <name> to delete a nick from autoident list", MSGLEVEL_CRAP);
+ return;
+ }
+
+ delpassword($name);
+ update_settings_string();
+}
+
+sub cmd_showpasswords {
+ if ($numpasswords == 0) {
+ msg("No nicks defined for autoident", MSGLEVEL_CRAP);
+ return;
+ }
+ msg("Nicks for autoident:", MSGLEVEL_CRAP);
+ my $n = 1;
+ foreach my $nick (keys(%passwords)) {
+# msg("$nick: " . $mailboxes{$password}, MSGLEVEL_CRAP);
+ msg("$n. $nick: ***", MSGLEVEL_CRAP);
+ $n++;
+ }
+}
+
+sub cmd_id {
+ my ($data, $server, $item) = @_;
+ if ($data =~ m/^[(show)|(add)|(del)|(help)]/i ) {
+ Irssi::command_runsub('id', $data, $server, $item);
+ } else {
+ msg("Use /id (show|add|del|help)", MSGLEVEL_CRAP);
+ }
+}
+
+Irssi::command_bind('id show', 'cmd_showpasswords');
+Irssi::command_bind('id list', 'cmd_showpasswords');
+Irssi::command_bind('id add', 'cmd_addpassword');
+Irssi::command_bind('id del', 'cmd_delpassword');
+Irssi::command_bind('id help', 'cmd_print_help');
+Irssi::command_bind('id', 'cmd_id');
+Irssi::settings_add_str('misc', 'autoident', '');
+
+read_settings();
+init_passwords();
+Irssi::signal_add('setup changed', 'read_settings');
+
+#Irssi::signal_add('event privmsg', 'event_privmsg');
+Irssi::signal_add('event notice', 'event_notice');
+
+msg("loaded ok", MSGLEVEL_CRAP);
+
+# EOF
diff --git a/scripts/XMMSInfo.pm b/scripts/XMMSInfo.pm
new file mode 100644
index 0000000..39d51ad
--- /dev/null
+++ b/scripts/XMMSInfo.pm
@@ -0,0 +1,308 @@
+# XMMSInfo.pm
+# this should be in a separate file...
+package XMMSInfo;
+
+# should write docs...
+
+use strict;
+use POSIX;
+use IO::File;
+use MP3::Info;
+use vars qw($PIPE $STATUS @ISA @EXPORT);
+
+@ISA = qw(Exporter);
+@EXPORT = qw($STATUS);
+
+$PIPE = '/tmp/xmms-info';
+$STATUS = {
+ -1 => 'Fatal error',
+ 0 => 'Not running',
+ 1 => 'Stopped',
+ 2 => 'Playing',
+ 3 => 'Paused',
+};
+
+sub new {
+ my($class) = shift;
+
+ my($self) = {};
+ bless($self, $class);
+
+ $self->die("Try calling some methods first. \$obj->getInfo() is currently the only one available...");
+
+ $self;
+}
+
+sub parseArgs {
+ my($self) = shift;
+
+ $#_ % 2 || return $self->die("Invalid number of arguments");
+ for(my $i = 0; $i < $#_; $i += 2) {
+ my($k, $v) = ($_[$i], $_[$i + 1]);
+ $self->{Args}->{'.'.uc($k)} = $v;
+ }
+
+ 1;
+}
+
+sub die {
+ my($self) = shift;
+ $self->setError(shift);
+ $self->setStatus(-1);
+ undef;
+}
+
+sub round {
+ my($d) = shift;
+ return $d unless $d =~ /^(\d+)\.(\d)/;
+ $d = $1;
+ $d++ if $2 >= 5;
+ $d;
+}
+
+sub getInfo {
+ my($self) = shift;
+
+ $self->parseArgs(@_) || return;
+
+ my($f) = $self->argPipe || $PIPE;
+ -r $f || return $self->setStatus(0);
+ my($fh) = IO::File->new($f) ||
+ return $self->die("Can't open $f for reading: $!");
+
+ while(<$fh>) {
+ chomp;
+ next unless /^(.+?): (.+)$/;
+ if($1 eq 'Status') {
+ $self->setStatus($2);
+ } else {
+ $self->{Info}->{'.'.uc($1)} = $2;
+ }
+ }
+ $fh->close;
+
+ return $self->die("Invalid input") unless $self->{Info}->{'.INFOPIPE PLUGIN VERSION'};
+
+ my($t) = get_mp3tag($self->infoFile) || return $self->die("Can't read ID3 tag: ". $self->infoFile);
+ my($i) = get_mp3info($self->infoFile) || return $self->die("Can't read MP3 info: ". $self->infoFile);
+
+ my($k, $v);
+ while(($k, $v) = (each(%$t), each(%$i))) {
+ $self->{Info}->{'.'.$k} = $v;
+ }
+
+ $self->getStatus;
+}
+
+sub setStatus {
+ my($self, $s) = @_;
+ if($s =~ /^*\d+$/) {
+ $self->{Status}->{'.STATUS'} = $s;
+ $self->{Status}->{'.STATUSSTRING'} = $STATUS->{$s};
+ } else {
+ foreach my $k (keys %$STATUS) {
+ my($v) = $STATUS->{$k};
+ if($s eq $v) {
+ $self->{Status}->{'.STATUS'} = $k;
+ $self->{Status}->{'.STATUSSTRING'} = $s;
+ return $self->getStatus;
+ }
+ }
+ die "HELP";
+ }
+
+ $self->getStatus;
+}
+
+sub setError {
+ shift->{Status}->{'.ERROR'} = pop;
+}
+
+sub getStatus {
+ shift->{Status}->{'.STATUS'};
+}
+
+sub getStatusString {
+ shift->{Status}->{'.STATUSSTRING'};
+}
+
+sub getError {
+ shift->{Status}->{'.ERROR'};
+}
+
+sub isFatalError {
+ shift->getStatus == -1;
+}
+
+sub isXmmsRunning {
+ shift->getStatus > 0;
+}
+
+sub isPlaying {
+ shift->getStatus == 2;
+}
+
+sub isPaused {
+ shift->getStatus == 3;
+}
+
+sub isStopped {
+ shift->getStatus == 1;
+}
+
+sub argPipe {
+ shift->{Args}->{'.PIPE'};
+}
+
+sub infoPlayListItems {
+ shift->{Info}->{'.TUNES IN PLAYLIST'};
+}
+
+sub infoCurrentItemInPlaylist {
+ shift->{Info}->{'.CURRENTLY PLAYING'};
+}
+
+sub infoTimeNow {
+ shift->{Info}->{'.POSITION'};
+}
+
+sub infoTimeTotal {
+ shift->{Info}->{'.TIME'};
+}
+
+sub infoSecondsTotal {
+ POSIX::ceil (shift->{Info}->{'.SECS'});
+}
+
+sub infoSecondsNow {
+ my($self) = shift;
+ my($s) = $self->infoTimeNow;
+ die "HELP" unless $s =~ /^(\d+):(\d+)$/;
+ $1 * 60 + $2;
+}
+
+sub infoMinutesTotal {
+ shift->{Info}->{'.MM'};
+}
+
+sub infoMinutesNow {
+ my($self) = shift;
+ my($s) = $self->infoTimeNow;
+ die "HELP" unless $s =~ /^(\d+):\d+$/;
+ $1;
+}
+
+sub infoSecondsTotalLeftover {
+ shift->{Info}->{'.SS'};
+}
+
+sub infoSecondsNowLeftover {
+ my($self) = shift;
+ $self->infoSecondsNow - ($self->infoMinutesNow * 60);
+}
+
+sub infouSecTotal {
+ shift->{Info}->{'.USECTIME'};
+}
+
+sub infouSecNow {
+ shift->{Info}->{'.USECPOSITION'};
+}
+
+sub infoPercentage {
+ my($self) = shift;
+ my($p) = ($self->infouSecNow / $self->infouSecTotal) * 100;
+ round($p);
+}
+
+sub infoTitle {
+ shift->{Info}->{'.TITLE'};
+}
+
+sub infoFile {
+ shift->{Info}->{'.FILE'};
+}
+
+sub infoArtist {
+ shift->{Info}->{'.ARTIST'};
+}
+
+sub infoAlbum {
+ shift->{Info}->{'.ALBUM'};
+}
+
+sub infoYear {
+ shift->{Info}->{'.YEAR'};
+}
+
+sub infoComment {
+ shift->{Info}->{'.COMMENT'};
+}
+
+sub infoGenre {
+ shift->{Info}->{'.GENRE'};
+}
+
+sub infoVersion {
+ shift->{Info}->{'.VERSION'};
+}
+
+sub infoLayer {
+ shift->{Info}->{'.LAYER'};
+}
+
+sub infoIsStereo {
+ shift->{Info}->{'.STEREO'};
+}
+
+sub infoIsVbr {
+ shift->{Info}->{'.VBR'};
+}
+
+sub infoBitrate {
+ shift->{Info}->{'.BITRATE'};
+}
+
+sub infoFrequency {
+ shift->{Info}->{'.FREQUENCY'};
+}
+
+sub infoSizeBytes {
+ shift->{Info}->{'.SIZE'};
+}
+
+sub infoSize {
+ shift->infoSizeBytes;
+}
+
+sub infoSizeKiloBytes {
+ round(shift->infoSizeBytes / 1024);
+}
+
+sub infoSizeMegaBytes {
+ round(shift->infoSizeKiloBytes / 1024);
+}
+
+sub infoIsCopyright {
+ shift->{Info}->{'.COPYRIGHT'};
+}
+
+sub infoIsPadded {
+ shift->{Info}->{'.PADDING'};
+}
+
+sub infoFrames {
+ shift->{Info}->{'.FRAMES'};
+}
+
+sub infoFramesLength {
+ shift->{Info}->{'.FRAMESLENGTH'};
+}
+
+sub infoVbrScale {
+ shift->{Info}->{'.VBR_SCALE'};
+}
+
+1;
+
+# EOF
diff --git a/scripts/accent.pl b/scripts/accent.pl
new file mode 100644
index 0000000..3fe0ffa
--- /dev/null
+++ b/scripts/accent.pl
@@ -0,0 +1,153 @@
+#to run it if it is here (but in this case it will run automagically when
+#irssi will start):
+#
+#/script load ~/.irssi/scripts/autorun/accent.pl
+#
+#you can simply remove the script:
+#
+#/script unload accent
+#
+#and it will strips your incoming and outgoing hungarian accents
+#but you can:
+#
+#/set accent_strip_in <on|off> -- strips the incoming accents (on) or not (off)
+#/set accent_strip_out <on|off> -- strips the outgoing accents (on) or not (off)
+#
+#/set accent_tag_in <string, default: [A]> indicates the incoming msg filtered
+#/set accent_tag_out <string, default: [A]> indicates the outgoing msg filtered
+#
+#/set accent_latin <string, default: iso 8859-2: A',a',E',e',I',i',O',o',O:,o:,O",o",U',u',U:,u:,U",u"> which to strip
+#/set accent_ascii <string, default: AaEeIiOoOoOoUuUuUu> will be the stripped
+#
+#be careful, accent_latin and accent_latin must be charlist and must have
+#the same length to be matched as a pair.
+#
+#/set accent_debug <on|off> -- if you have a problem try to turn this on
+
+use strict;
+use vars qw($VERSION %IRSSI);
+
+use Irssi;
+($VERSION) = '$Id: accent.pl,v 1.34 2003/03/27 15:54:25 toma Exp $' =~ / (\d+\.\d+) /;
+%IRSSI = (
+ authors => 'Tamas SZERB',
+ contact => 'toma@rulez.org',
+ name => 'accent',
+ description => 'This script strips the hungarian accents.',
+ license => 'GPL',
+);
+
+my $stripped_out = 0;
+my $stripped_in = 0;
+
+sub accent_out {
+ if(Irssi::settings_get_bool('accent_strip_out') && !$stripped_out) {
+ my $accent_tag = Irssi::settings_get_str('accent_tag_out');
+
+ my $debug=Irssi::settings_get_bool('accent_debug');
+
+ my $accent_latin = Irssi::settings_get_str('accent_latin');
+ my $accent_ascii = Irssi::settings_get_str('accent_ascii');
+ if (length($accent_latin) != length($accent_ascii)) {
+ if ($debug) {
+ Irssi::print("`$accent_latin' and `$accent_ascii' hasn't same length");
+ }
+ }
+ else {
+ my $emitted_signal = Irssi::signal_get_emitted();
+ my ($msg, $dummy1, $dummy2) = @_;
+
+ if ($debug) {
+ Irssi::print("signal emitted: $emitted_signal");
+ }
+
+ if ( $msg =~ /[$accent_latin]/ ) {
+ if ($debug) {
+ Irssi::print("outgoing contains accent: $msg");
+ }
+ eval "\$msg =~ tr/$accent_latin/$accent_ascii/;";
+ $msg = $msg . ' ' . $accent_tag;
+ $stripped_out=1;
+
+ Irssi::signal_emit("$emitted_signal", $msg, $dummy1, $dummy2 );
+ Irssi::signal_stop();
+ $stripped_out=0;
+ }
+ }
+ }
+}
+
+sub accent_in {
+ if(Irssi::settings_get_bool('accent_strip_in') && !$stripped_in) {
+ my $accent_tag = Irssi::settings_get_str('accent_tag_in');
+
+ my $debug=Irssi::settings_get_bool('accent_debug');
+
+ my $accent_latin = Irssi::settings_get_str('accent_latin');
+ my $accent_ascii = Irssi::settings_get_str('accent_ascii');
+ if (length($accent_latin) != length($accent_ascii)) {
+ if ($debug) {
+ Irssi::print("`$accent_latin' and `$accent_ascii' hasn't same length");
+ }
+ }
+ else {
+ my $emitted_signal = Irssi::signal_get_emitted();
+
+ my ($dummy0, $text, $dummy3, $dummy4, $dummy5) = @_;
+ if ($debug) {
+ Irssi::print("signal emitted: $emitted_signal");
+ }
+ if ( $text =~ /[$accent_latin]/ ) {
+ if ($debug) {
+ Irssi::print("incoming contains accent: $text");
+ }
+ if ($debug) {
+ Irssi::print("text=$text");
+ }
+ #no idea why w/o eval doesn't work:
+ eval "\$text =~ tr/$accent_latin/$accent_ascii/;";
+ $text = $text . ' ' . $accent_tag;
+ $stripped_in=1;
+
+ if ($debug) {
+ Irssi::print("text=$text");
+ }
+ Irssi::signal_emit("$emitted_signal", $dummy0, $text, $dummy3, $dummy4, $dummy5 );
+ Irssi::signal_stop();
+ $stripped_in=0;
+ }
+ }
+ }
+}
+
+#main():
+
+#default settings /set accent_in && accent_out ON:
+Irssi::settings_add_bool('lookandfeel', 'accent_strip_in', 1);
+Irssi::settings_add_bool('lookandfeel', 'accent_strip_out', 1);
+
+#define the default tags for the filtered text:
+Irssi::settings_add_str('lookandfeel', 'accent_tag_in', '[Ai]');
+Irssi::settings_add_str('lookandfeel', 'accent_tag_out', '[Ao]');
+
+#define which chars will be changed:
+#iso 8859-2: A',a',E',e',I',i',O',o',O:,o:,O",o",U',u',U:,u:,U",u"
+Irssi::settings_add_str('lookandfeel', 'accent_latin', "\301\341\311\351\315\355\323\363\326\366\325\365\332\372\334\374\333\373");
+Irssi::settings_add_str('lookandfeel', 'accent_ascii', "AaEeIiOoOoOoUuUuUu");
+
+#define wheather debug or not (default OFF):
+Irssi::settings_add_bool('lookandfeel', 'accent_debug', 0);
+
+#filters:
+#incoming filters:
+Irssi::signal_add_first('server event', 'accent_in');
+
+#output filters:
+Irssi::signal_add_first('send command', 'accent_out');
+#Irssi::signal_add_first('message own_public', 'accent_out');
+#Irssi::signal_add_first('message own_private', 'accent_out');
+
+#startup info:
+Irssi::print("Hungarian accent stripper by toma * http://scripts.irssi.org/scripts/accent.pl");
+Irssi::print("Version: $VERSION");
+
diff --git a/scripts/act.pl b/scripts/act.pl
new file mode 100644
index 0000000..21cbbbb
--- /dev/null
+++ b/scripts/act.pl
@@ -0,0 +1,54 @@
+#!/usr/bin/perl
+# resets window activity status
+# by c0ffee
+# - http://www.penguin-breeder.org/irssi/
+
+#<scriptinfo>
+use strict;
+use vars qw($VERSION %IRSSI);
+
+use Irssi 20020120;
+$VERSION = "0.15";
+%IRSSI = (
+ authors => "c0ffee",
+ contact => "c0ffee\@penguin-breeder.org",
+ name => "Reset window activity status",
+ description => "Reset window activity status. defines command /act",
+ license => "Public Domain",
+ url => "http://www.penguin-breeder.org/irssi/",
+ changed => "Thu Apr 16 15:55:05 BST 2015",
+);
+#</scriptinfo>
+
+#
+# /ACT [PUBLIC|ALL]
+#
+# /ACT without parameters marks windows as non-active where no
+# public talk occured.
+#
+# /ACT PUBLIC also removes those where no nick hilight was triggered
+#
+# /ACT ALL sets all windows as non-active
+
+Irssi::command_bind 'act' => sub {
+ my ( $data, $server, $item ) = @_;
+ $data =~ s/\s+$//g;
+ if ($data) {
+ Irssi::command_runsub('act', $data, $server, $item);
+ }
+ else {
+ _act(1);
+ }
+};
+
+Irssi::command_bind('act public', sub { _act(2); });
+Irssi::command_bind('act all', sub { _act(3); });
+
+sub _act {
+ my($level) = @_;
+ for (Irssi::windows()) {
+ if ($_->{data_level} <= $level) {
+ Irssi::signal_emit("window dehilight", $_);
+ }
+ }
+}
diff --git a/scripts/active_notice.pl b/scripts/active_notice.pl
new file mode 100644
index 0000000..7a851a6
--- /dev/null
+++ b/scripts/active_notice.pl
@@ -0,0 +1,207 @@
+#!/usr/bin/perl -w
+
+## Bugreports and Licence disclaimer.
+#
+# For bugreports and other improvements contact Geert Hauwaerts <geert@hauwaerts.be>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; either version 2 of the License, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this script; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA.
+##
+
+
+## Documentation.
+#
+# Versioning:
+#
+# This script uses the YEAR.FEATURE.REVISION versioning scheme and must abide
+# by the follwing rules:
+#
+# 1) when adding a new feature, you must increase the FEATURE
+# numeric by one;
+#
+# 2) when fixing a bug, you must increase the REVISION numeric
+# by one; and
+#
+# 3) the first feature or bug change in any given year must set the YEAR
+# numeric to the two digit representation of the current year, and
+# reset the FEATURE and REVISION numerics to 01.
+#
+# Settings:
+#
+# active_notice_show_in_status_window
+#
+# When enabled, notices will also be sent to the status window.
+##
+
+
+##
+# Load the required libraries.
+##
+
+use strict;
+use Irssi;
+use vars qw($VERSION %IRSSI);
+
+
+##
+# Declare the administrative information.
+##
+
+$VERSION = '18.01.01';
+
+%IRSSI = (
+ authors => 'Geert Hauwaerts',
+ contact => 'geert@hauwaerts.be',
+ name => 'active_notice.pl',
+ description => 'This script shows incoming notices into the active channel.',
+ license => 'GNU General Public License',
+ url => 'https://github.com/GeertHauwaerts/irssi-scripts/blob/master/src/active_notice.pl',
+ changed => '2018-07-27',
+);
+
+
+##
+# Register the custom theme formats.
+##
+
+Irssi::theme_register([
+ 'active_notice_loaded', '%R>>%n %_Scriptinfo:%_ Loaded $0 version $1 by $2.'
+]);
+
+
+## Function.
+#
+# Irssi::active_notice::notice_move() function.
+#
+# Function: notice_move()
+# Arguments: The destination.
+# The text.
+# The stripped text.
+#
+# Description: Print received notices into the active window.
+##
+
+sub notice_move {
+
+
+ ##
+ # Parse the parameters.
+ ##
+
+ my ($dest, $text, $stripped) = @_;
+ my $server = $dest->{'server'};
+
+
+ ##
+ # Check whether the message is irrelevant.
+ ##
+
+ if (!$server || !($dest->{level} & MSGLEVEL_NOTICES) || $server->ischannel($dest->{'target'})) {
+ return;
+ }
+
+
+ ##
+ # Fetch the source, destination and status windows.
+ ##
+
+ my $witem = $server->window_item_find($dest->{'target'});
+ my $status = Irssi::window_find_name("(status)");
+ my $awin = Irssi::active_win();
+
+
+ ##
+ # Check whether we have a window for the source of the notice.
+ ##
+
+ if (!$witem) {
+
+
+ ##
+ # Check whether the notice originated from the status window.
+ ##
+
+ if ($awin->{'name'} eq "(status)") {
+ return;
+ }
+
+ ##
+ # replace a single % with %%. (by Dwarf <dwarf@rizon.net>)
+ ##
+
+ $text =~ s/%/%%/g;
+
+ ##
+ # Print the notice in the active window.
+ ###
+
+ $awin->print($text, MSGLEVEL_NOTICES);
+
+
+ ##
+ # Check whether the notice needs to be printed in the status window.
+ ##
+
+ if (!Irssi::settings_get_bool('active_notice_show_in_status_window')) {
+ Irssi::signal_stop();
+ }
+ } else {
+
+
+ ##
+ # Check whether we need to print the notice in the status window.
+ ##
+
+ if (($awin->{'name'} ne "(status)") && (Irssi::settings_get_bool('active_notice_show_in_status_window'))) {
+ $status->print($text, MSGLEVEL_NOTICES);
+ }
+
+
+ ##
+ # Check whether the notice originated from the active window.
+ ##
+
+ if ($witem->{'_irssi'} == $awin->{'active'}->{'_irssi'}) {
+ return;
+ }
+
+
+ ##
+ # Print the notice in the active window.
+ ##
+
+ $awin->print($text, MSGLEVEL_NOTICES);
+ }
+}
+
+
+##
+# Register the signals to hook on.
+##
+
+Irssi::signal_add('print text', 'notice_move');
+
+
+##
+# Register the custom settings.
+##
+
+Irssi::settings_add_bool('active_notice', 'active_notice_show_in_status_window', 1);
+
+
+##
+# Display the script banner.
+##
+
+Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'active_notice_loaded', $IRSSI{name}, $VERSION, $IRSSI{authors});
diff --git a/scripts/active_notify.pl b/scripts/active_notify.pl
new file mode 100644
index 0000000..dce841a
--- /dev/null
+++ b/scripts/active_notify.pl
@@ -0,0 +1,157 @@
+#!/usr/bin/perl -w
+
+## Bugreports and Licence disclaimer.
+#
+# For bugreports and other improvements contact Geert Hauwaerts <geert@irssi.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this script; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+##
+
+## Comments and remarks.
+#
+# This script uses settings, by default the broadcast will be set off.
+# If you want the notify message to be shown in all the windows use
+# /SET or /TOGGLE to switch it on or off.
+#
+# Setting: notify_broadcast
+#
+##
+
+use strict;
+use Irssi;
+use vars qw($VERSION %IRSSI);
+
+$VERSION = "0.07";
+
+%IRSSI = (
+ authors => 'Geert Hauwaerts',
+ contact => 'geert@irssi.org',
+ name => 'active_notify.pl',
+ description => 'This script will display notify messages into the active window or broadcast it so all the windows.',
+ license => 'GNU General Public License',
+ url => 'http://irssi.hauwaerts.be/active_notify.pl',
+ changed => 'Wed Sep 17 23:00:11 CEST 2003',
+);
+
+Irssi::theme_register([
+ 'notify_joined', '%_Notify%_: %R>>%n %_$0%_ [$1@$2] [$3] has joined /$4/.',
+ 'notify_left', '%_Notify%_: %R>>%n %_$0%_ [$1@$2] [$3] has parted /$4/.',
+ 'notify_new', '%_Notify%_: %R>>%n Added %_$0%_ to the notify list.',
+ 'notify_del', '%_Notify%_: %R>>%n Removed %_$0%_ from the notify list.',
+ 'active_notify_loaded', '%R>>%n %_Scriptinfo:%_ Loaded $0 version $1 by $2.'
+]);
+
+sub notify_joined {
+
+ my ($server, $nick, $user, $host, $realname, $awaymsg) = @_;
+ my $broadcast = Irssi::settings_get_bool('notify_broadcast');
+ my $window = Irssi::active_win();
+
+ if ($broadcast) {
+ foreach my $bwin (Irssi::windows) {
+ $bwin->printformat(MSGLEVEL_CLIENTCRAP, 'notify_joined', $nick, $user, $host, $realname, $server->{tag});
+ }
+ } else {
+ $window->printformat(MSGLEVEL_CLIENTCRAP, 'notify_joined', $nick, $user, $host, $realname, $server->{tag});
+ }
+
+ Irssi::signal_stop();
+}
+
+sub notify_left {
+
+ my ($server, $nick, $user, $host, $realname, $awaymsg) = @_;
+ my $broadcast = Irssi::settings_get_bool('notify_broadcast');
+ my $window = Irssi::active_win();
+
+ if ($broadcast) {
+ foreach my $bwin (Irssi::windows) {
+ $bwin->printformat(MSGLEVEL_CLIENTCRAP, 'notify_left', $nick, $user, $host, $realname, $server->{tag});
+ }
+ } else {
+ $window->printformat(MSGLEVEL_CLIENTCRAP, 'notify_left', $nick, $user, $host, $realname, $server->{tag});
+ }
+
+ Irssi::signal_stop();
+}
+
+sub notify_new {
+
+ my ($nick) = @_;
+ my $broadcast = Irssi::settings_get_bool('notify_broadcast');
+ my $window = Irssi::active_win();
+ my ($aw_ch, $ircnet, $mask, $ict);
+
+ if ($broadcast) {
+ foreach my $bwin (Irssi::windows) {
+ $bwin->printformat(MSGLEVEL_CLIENTCRAP, 'notify_new', $nick->{mask});
+ }
+ } else {
+ $window->printformat(MSGLEVEL_CLIENTCRAP, 'notify_new', $nick->{mask});
+ }
+
+ Irssi::signal_stop();
+}
+
+sub notify_del {
+
+ my ($nick) = @_;
+ my $broadcast = Irssi::settings_get_bool('notify_broadcast');
+ my $window = Irssi::active_win();
+
+ if ($broadcast) {
+ foreach my $bwin (Irssi::windows) {
+ $bwin->printformat(MSGLEVEL_CLIENTCRAP, 'notify_del', $nick->{mask});
+ }
+ } else {
+ $window->printformat(MSGLEVEL_CLIENTCRAP, 'notify_del', $nick->{mask});
+ }
+
+ Irssi::signal_stop();
+}
+
+Irssi::signal_add_first('notifylist joined', 'notify_joined');
+Irssi::signal_add_first('notifylist left', 'notify_left');
+
+## BUG, BUG, BUG! Warning!
+#
+# [16:02] [-] Irssi: Starting query in Freenode with cras
+# [16:04] :cras: it crashes every time it gets into 'notifylist remove' signal?
+# [16:04] :Geert: yes
+# [16:05] :Geert: the notifylist new too
+# [16:06] :cras: even if they didn't do anything?
+# [16:06] :Geert: indeed
+# [16:06] :Geert: Try for yourself :)
+# [16:06] :Geert: joined & remove signals are working great
+# [16:07] :cras: i guess it doesn't like the notifylist_rec ..
+# [16:08] :Geert: So, what should I do now? :)
+# [16:10] :cras: try cvs update?
+# [16:10] :cras: i fixed one possible cause for it
+# [16:10] :cras: and can't see another one :)
+# [16:11] :Geert: Well, It's a scriptrequest from someone. So I'll just comment that feature
+# [16:11] :Geert: Are you sure it works in the cvs?
+# [16:11] :cras: well, 70% sure :)
+# [16:12] :Geert: Let's hope so :P
+#
+# Uncomment the next two lines. ONLY if you have the CVS version.
+#
+#Irssi::signal_add_first('notifylist new', 'notify_new');
+#Irssi::signal_add_first('notifylist remove', 'notify_del');
+#
+##
+
+Irssi::settings_add_bool('notify', 'notify_broadcast' => 0);
+Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'active_notify_loaded', $IRSSI{name}, $VERSION, $IRSSI{authors});
diff --git a/scripts/adv_windowlist.pl b/scripts/adv_windowlist.pl
new file mode 100644
index 0000000..839814e
--- /dev/null
+++ b/scripts/adv_windowlist.pl
@@ -0,0 +1,2988 @@
+use strict;
+use warnings;
+
+our $VERSION = '1.11'; # 28b8dcf69e0355e
+our %IRSSI = (
+ authors => 'Nei',
+ contact => 'Nei @ anti@conference.jabber.teamidiot.de',
+ url => "http://anti.teamidiot.de/",
+ name => 'adv_windowlist',
+ description => 'Adds a permanent advanced window list on the right or in a status bar.',
+ sbitems => 'awl_shared',
+ license => 'GNU GPLv2 or later',
+ );
+
+# UPGRADE NOTE
+# ============
+# for users of 0.7 or earlier series, please note that appearance
+# settings have moved to /format, i.e. inside your theme!
+# the fifo (screen) has been replaced by an external viewer script
+
+# Usage
+# =====
+# copy the script to ~/.irssi/scripts/
+#
+# In irssi:
+#
+# /run adv_windowlist
+#
+# In your shell (for example a tmux split):
+#
+# perl ~/.irssi/scripts/adv_windowlist.pl
+#
+# To use sbar mode instead:
+#
+# /toggle awl_viewer
+#
+# Hint: to get rid of the old [Act:] display
+# /statusbar window remove act
+#
+# to get it back:
+# /statusbar window add -after lag -priority 10 act
+
+# Options
+# =======
+# formats can be cleared with /format -delete
+#
+# /format awl_display_(no)key(_active|_visible) <string>
+# * string : Format String for one window. The following $'s are expanded:
+# $C : Name
+# $N : Number of the Window
+# $Q : meta-Keymap
+# $H : Start hilighting
+# $S : Stop hilighting
+# /+++++++++++++++++++++++++++++++++,
+# | **** I M P O R T A N T : **** |
+# | |
+# | don't forget to use $S if you |
+# | used $H before! |
+# | |
+# '+++++++++++++++++++++++++++++++++/
+# key : a key binding that goes to this window could be detected in /bind
+# nokey : no such key binding was detected
+# active : window would receive the input you are currently typing
+# visible : window is also visible on screen but not active (a split window)
+#
+# /format awl_name_display <string>
+# * string : Format String for window names
+# $0 : name as formatted by the settings
+#
+# /format awl_display_header <string>
+# * string : Format String for this header line. The following $'s are expanded:
+# $C : network tag
+#
+# /format awl_separator(2) <string>
+# * string : Character to use between the channel entries
+# variant 2 can be used for alternating separators (only in status bar
+# without block display)
+#
+# /format awl_abbrev_chars <string>
+# * string : Character to use when shortening long names. The second character
+# will be used if two blocks need to be filled.
+#
+# /format awl_title <string>
+# * string : Text to display in the title string or title bar
+#
+# /format awl_viewer_item_bg <string>
+# * string : Format String specifying the viewer's item background colour
+#
+# /set awl_prefer_name <ON|OFF>
+# * this setting decides whether awl will use the active_name (OFF) or the
+# window name as the name/caption in awl_display_*.
+# That way you can rename windows using /window name myownname.
+#
+# /set awl_hide_empty <num>
+# * if visible windows without items should be hidden from the window list
+# set it to 0 to show all windows
+# 1 to hide visible windows without items (negative exempt
+# active window)
+#
+# /set awl_custom_key_re <regex>
+# * regex : which symbolic key names to show in $Q (for example F-keys)
+#
+# /set awl_detach <list>
+# * list of windows that should be hidden from the window list. you
+# can also use /awl detach and /awl attach to manage this
+# setting. an optional data_level can be specified with ",num"
+#
+# /set awl_detach_data <num>
+# * num : hide the detached window if its data_level is below num
+#
+# /set awl_detach_aht <ON|OFF>
+# * if enabled, also detach all windows listed in the
+# activity_hide_targets setting
+#
+# /set awl_hide_data <num>
+# * num : hide the window if its data_level is below num
+# set it to 0 to basically disable this feature,
+# 1 if you don't want windows without activity to be shown
+# 2 to show only those windows with channel text or hilight
+# 3 to show only windows with hilight (negative exempt active window)
+#
+# /set awl_hide_name_data <num>
+# * num : hide the name of the window if its data_level is below num
+# (only works in status bar without block display)
+# you will want to change your formats to add $H...$S around $Q or $N
+# if you plan to use this
+#
+# /set awl_maxlines <num>
+# * num : number of lines to use for the window list (0 to disable, negative
+# lock)
+#
+# /set awl_maxcolumns <num>
+# * num : number of columns to use for the window list when using the
+# tmux integration (0 to disable)
+#
+# /set awl_block <num>
+# * num : width of a column in viewer mode (negative values = block
+# display in status bar mode)
+# /+++++++++++++++++++++++++++++++++,
+# | ****** W A R N I N G ! ****** |
+# | |
+# | If your block display looks |
+# | DISTORTED, you need to add the |
+# | following line to your .theme |
+# | file under |
+# | abstracts = { : |
+# | |
+# | sb_act_none = "%K$*"; |
+# | |
+# '+++++++++++++++++++++++++++++++++/
+#
+# /set awl_sbar_maxlength <ON|OFF>
+# * if you enable the maxlength setting, the block width will be used as a
+# maximum length for the non-block status bar mode too.
+#
+# /set awl_height_adjust <num>
+# * num : how many lines to leave empty in viewer mode
+#
+# /set awl_sort <-data_level|-last_line|refnum>
+# * you can change the window sort order with this variable
+# -data_level : sort windows with hilight first
+# -last_line : sort windows in order of activity
+# refnum : sort windows by window number
+# active/server/tag : sort by server name
+# lru : sort windows with the last recently used last
+# "-" reverses the sort order
+# typechecks are supported via ::, e.g. active::Query or active::Irc::Query
+# undefinedness can be checked with ~, e.g. ~active
+# string comparison can be done with =, e.g. name=(status)
+# to make sort case insensitive, use #i, e.g. name#i
+# any key in the window hash can be tested, e.g. active/chat_type=XMPP
+# multiple criteria can be separated with , or +, e.g. -data_level+-last_line
+#
+# /set awl_placement <top|bottom>
+# /set awl_position <num>
+# * these settings correspond to /statusbar because awl will create
+# status bars for you
+# (see /help statusbar to learn more)
+#
+# /set awl_all_disable <ON|OFF>
+# * if you set awl_all_disable to ON, awl will also remove the
+# last status bar it created if it is empty.
+# As you might guess, this only makes sense with awl_hide_data > 0 ;)
+#
+# /set awl_viewer <ON|OFF>
+# * enable the external viewer script
+#
+# /set awl_viewer_launch <ON|OFF>
+# * try to auto-launch the viewer under tmux or with a shell command
+# /awl restart is required all auto-launch related settings to take
+# effect
+#
+# /set awl_viewer_tmux_position <left|top|right|bottom|custom>
+# * try to split in this direction when using tmux for the viewer
+# custom : use custom_command setting
+#
+# /set awl_viewer_xwin_command <shell command>
+# * custom command to run in order to start the viewer when irssi is
+# running under X
+# %A - gets replaced by the command to run the viewer
+# %qA - additionally quote the command
+#
+# /set awl_viewer_custom_command <shell command>
+# * custom command to run in order to start the viewer
+#
+# /set awl_viewer_launch_env <string>
+# * specific environment settings for use on viewer auto-launch,
+# without the AWL_ prefix
+#
+# /set awl_shared_sbar <left<right|OFF>
+# * share a status bar for the first awl item, you will need to manually
+# /statusbar window add -after lag -priority 10 awl_shared
+# left : space in cells occupied on the left of status bar
+# right : space occupied on the right
+# Note: you need to replace "left" AND "right" with the appropriate numbers!
+#
+# /set awl_path <path>
+# * path to the file which the viewer script reads
+#
+# /set fancy_abbrev <no|head|strict|fancy>
+# * how to shorten too long names
+# no : shorten in the middle
+# head : always cut off the ends
+# strict : shorten repeating substrings
+# fancy : combination of no+strict
+#
+# /set awl_custom_xform <perl code>
+# * specify a custom routine to transform window names
+# example: s/^#// remove the #-mark of IRC channels
+# the special flags $CHANNEL / $TAG / $QUERY / $NAME can be
+# tested in conditionals
+#
+# /set awl_last_line_shade <timeout>
+# * set timeout to shade activity base colours, to enable
+# you also need to add +-last_line to awl_sort
+# (requires 256 colour support)
+#
+# /set awl_no_mode_hint <ON|OFF>
+# * whether to show the hint of running the viewer script in the
+# status bar
+#
+# /set awl_mouse <ON|OFF>
+# * enable the terminal mouse in irssi
+# (use the awl-patched mouse.pl for gestures and commands if you need
+# them and disable mouse_escape)
+#
+# /set awl_mouse_offset <num>
+# * specifies where on the screen is the awl status bar
+# (0 = on top/bottom, 1 = one additional line in between,
+# e.g. prompt)
+# you MUST set this correctly otherwise the mouse coordinates will
+# be off
+#
+# /set mouse_scroll <num>
+# * how many lines the mouse wheel scrolls
+#
+# /set mouse_escape <num>
+# * seconds to disable the mouse, when not clicked on the windowlist
+#
+
+# Commands
+# ========
+# /awl detach <num>
+# * hide the current window from the window list. num specifies the
+# data_level (optional)
+#
+# /awl attach
+# * unhide the current window from the window list
+#
+# /awl ack
+# * change to the next window with activity, ignoring detached windows
+#
+# /awl redraw
+# * redraws the windowlist. There may be occasions where the
+# windowlist can get destroyed so you can use this command to
+# force a redraw.
+#
+# /awl restart
+# * restart the connection to the viewer script.
+
+# Viewer script
+# =============
+# When run from the command line, adv_windowlist acts as the viewer
+# script to be used together with the irssi script to display the
+# window list in a sidebar/terminal of its own.
+#
+# One optional parameter is accepted, the awl_path
+#
+# The viewer can be configured by three environment variables:
+#
+# AWL_HI9=1
+# * interpret %9 as high-intensity toggle instead of bold. This had
+# been the default prior to version 0.9b8
+#
+# AWL_AUTOFOCUS=0
+# * disable auto-focus behaviour when activating a window
+#
+# AWL_NOTITLE=1
+# * disable the title bar
+
+# Nei =^.^= ( anti@conference.jabber.teamidiot.de )
+
+no warnings 'redefine';
+use constant IN_IRSSI => __PACKAGE__ ne 'main' || $ENV{IRSSI_MOCK};
+use constant SCRIPT_FILE => __FILE__;
+no if !IN_IRSSI, strict => (qw(subs refs));
+use if IN_IRSSI, Irssi => ();
+use if IN_IRSSI, 'Irssi::TextUI' => ();
+use v5.10;
+use Encode;
+use Storable ();
+use IO::Socket::UNIX;
+use List::Util qw(min max reduce);
+use Hash::Util qw(lock_keys);
+use Text::ParseWords qw(shellwords);
+
+BEGIN {
+ if ($] < 5.012) {
+ *CORE::GLOBAL::length = *CORE::GLOBAL::length = sub (_) {
+ defined $_[0] ? CORE::length($_[0]) : undef
+ };
+ }
+ *Irssi::active_win = {}; # hide incorrect warning
+}
+
+unless (IN_IRSSI) {
+ local *_ = \@ARGV;
+ &AwlViewer::main;
+ exit;
+}
+
+
+use constant GLOB_QUEUE_TIMER => 100;
+
+our $BLOCK_ALL; # localized blocker
+my @actString; # status bar texts
+my @win_items;
+my $currentLines = 0;
+my %awins;
+my $globTime; # timer to limit remake calls
+
+my %CHANGED;
+my $VIEWER_MODE;
+my $MOUSE_ON;
+my %mouse_coords;
+my %statusbars;
+my %S; # settings
+my $settings_str = '1';
+my $window_sort_func;
+my $custom_xform;
+my $custom_key_re = qr/(?!)/;
+my ($sb_base_width, $sb_base_width_pre, $sb_base_width_post);
+my $print_text_activity;
+my $shade_line_timer;
+my ($screenHeight, $screenWidth);
+my %viewer;
+
+my (%keymap, %nummap, %wnmap, %specialmap, %wnmap_exp, %custom_key_map);
+my %banned_channels;
+my %detach_map;
+my %abbrev_cache;
+
+use constant setc => 'awl';
+
+sub set ($) {
+ setc . '_' . $_[0]
+}
+
+sub add_statusbar {
+ for (@_) {
+ # add subs
+ my $l = set $_;
+ {
+ my $close = $_;
+ no strict 'refs';
+ *{$l} = sub { awl($close, @_) };
+ }
+ Irssi::command("^statusbar $l reset");
+ Irssi::command("statusbar $l enable");
+ if (lc $S{placement} eq 'top') {
+ Irssi::command("statusbar $l placement top");
+ }
+ if (my $x = $S{position}) {
+ Irssi::command("statusbar $l position $x");
+ }
+ Irssi::command("statusbar $l add -priority 100 -alignment left barstart");
+ Irssi::command("statusbar $l add $l");
+ Irssi::command("statusbar $l add -priority 100 -alignment right barend");
+ Irssi::command("statusbar $l disable");
+ Irssi::statusbar_item_register($l, '$0', $l);
+ $statusbars{$_} = 1;
+ Irssi::command("statusbar $l enable");
+ }
+}
+
+sub remove_statusbar {
+ for (@_) {
+ my $l = set $_;
+ Irssi::command("statusbar $l disable");
+ Irssi::command("statusbar $l reset");
+ Irssi::statusbar_item_unregister($l);
+ {
+ no strict 'refs';
+ undef &{$l};
+ }
+ delete $statusbars{$_};
+ }
+}
+
+my $awl_shared_empty = sub {
+ return if $BLOCK_ALL;
+ my ($item, $get_size_only) = @_;
+ $item->default_handler($get_size_only, '', '', 0);
+};
+
+sub syncLines {
+ my $maxLines = $S{maxlines};
+ my $newLines = ($maxLines > 0 and @actString > $maxLines) ?
+ $maxLines :
+ ($maxLines < 0) ?
+ -$maxLines :
+ @actString;
+ $currentLines = 1 if !$currentLines && $S{shared_sbar};
+ if ($S{shared_sbar} && !$statusbars{shared}) {
+ my $l = set 'shared';
+ {
+ no strict 'refs';
+ *{$l} = sub {
+ return if $BLOCK_ALL;
+ my ($item, $get_size_only) = @_;
+
+ my $text = $actString[0];
+ my $title = _get_format(set 'title');
+ if (length $title) {
+ $title =~ s{\\(.)|(.)}{
+ defined $2 ? quotemeta $2
+ : $1 eq 'V' ? '\u'
+ : $1 eq ':' ? quotemeta ':%n'
+ : $1 =~ /^[uUFQE]$/ ? "\\$1"
+ : quotemeta "\\$1"
+ }sge;
+ $title = eval qq{"$title"};
+ $title .= ' ';
+ }
+ my $pat = defined $text ? "{sb $title\$*}" : '{sb }';
+ $text //= '';
+ $item->default_handler($get_size_only, $pat, $text, 0);
+ };
+ }
+ $statusbars{shared} = 1;
+ remove_statusbar (0) if $statusbars{0};
+ }
+ elsif ($statusbars{shared} && !$S{shared_sbar}) {
+ add_statusbar (0) if $currentLines && $newLines;
+ delete $statusbars{shared};
+ my $l = set 'shared';
+ {
+ no strict 'refs';
+ *{$l} = $awl_shared_empty;
+ }
+ }
+ if ($currentLines == $newLines) { return; }
+ elsif ($newLines > $currentLines) {
+ add_statusbar ($currentLines .. ($newLines - 1));
+ }
+ else {
+ remove_statusbar (reverse ($newLines .. ($currentLines - 1)));
+ }
+ $currentLines = $newLines;
+}
+
+sub awl {
+ return if $BLOCK_ALL;
+ my ($line, $item, $get_size_only) = @_;
+
+ my $text = $actString[$line];
+ my $pat = defined $text ? '{sb $*}' : '{sb }';
+ $text //= '';
+ $item->default_handler($get_size_only, $pat, $text, 0);
+}
+
+# remove old statusbars
+{ my %killBar;
+ sub get_old_status {
+ my ($textDest, $cont, $cont_stripped) = @_;
+ if ($textDest->{level} == MSGLEVEL_CLIENTCRAP and $textDest->{target} eq '' and !defined $textDest->{server}) {
+ my $name = quotemeta(set '');
+ if ($cont_stripped =~ m/^$name(\d+)\s/) { $killBar{$1} = 1; }
+ Irssi::signal_stop;
+ }
+ }
+ sub killOldStatus {
+ %killBar = ();
+ Irssi::signal_add_first('print text' => 'get_old_status');
+ Irssi::command('statusbar');
+ Irssi::signal_remove('print text' => 'get_old_status');
+ remove_statusbar(keys %killBar);
+ }
+}
+
+sub _add_map {
+ my ($type, $target, $map) = @_;
+ ($type->{$target}) = sort { length $a <=> length $b || $a cmp $b }
+ $map, exists $type->{$target} ? $type->{$target} : ();
+}
+
+sub get_keymap {
+ my ($textDest, undef, $cont_stripped) = @_;
+ if ($textDest->{level} == MSGLEVEL_CLIENTCRAP and $textDest->{target} eq '' and !defined $textDest->{server}) {
+ my $one_meta_or_ctrl_key = qr/((?:meta-)*?)(?:(meta-|\^)(\S)|(\w+))/;
+ $cont_stripped = as_uni($cont_stripped);
+ if ($cont_stripped =~ m/((?:$one_meta_or_ctrl_key-)*$one_meta_or_ctrl_key)\s+(.*)$/) {
+ my ($combo, $command) = ($1, $10);
+ my $map = '';
+ while ($combo =~ s/(?:-|^)$one_meta_or_ctrl_key$//) {
+ my ($level, $ctl, $key, $nkey) = ($1, $2, $3, $4);
+ my $numlevel = ($level =~ y/-//);
+ if (not defined $key and $nkey =~ /^($custom_key_re)$/) {
+ $key = $nkey;
+ }
+ $ctl = '' if !$ctl || $ctl ne '^';
+ $map = ('-' x ($numlevel%2)) . ('+' x ($numlevel/2)) .
+ $ctl . (defined $key ? $key : "\01$nkey\01") . $map;
+ }
+ for ($command) {
+ last unless length $map;
+ if (/^change_window (\d+)/i) {
+ _add_map(\%nummap, $1, $map);
+ }
+ elsif (/^(?:command window goto|change_window) (\S+)/i) {
+ my $window = $1;
+ if ($window !~ /\D/) {
+ _add_map(\%nummap, $window, $map);
+ }
+ elsif (lc $window eq 'active') {
+ _add_map(\%specialmap, '_active', $map);
+ }
+ else {
+ _add_map(\%wnmap, $window, $map);
+ }
+ }
+ elsif (/^(?:active_window|command ((awl )?ack))/i) {
+ _add_map(\%specialmap, '_active', $map);
+ $viewer{use_ack} = $1;
+ }
+ elsif (/^command window last/i) {
+ _add_map(\%specialmap, '_last', $map);
+ }
+ elsif (/^(?:upper_window|command window up)/i) {
+ _add_map(\%specialmap, '_up', $map);
+ }
+ elsif (/^(?:lower_window|command window down)/i) {
+ _add_map(\%specialmap, '_down', $map);
+ }
+ elsif (/^key\s+(\w+)/i) {
+ $custom_key_map{$1} = $map;
+ }
+ }
+ }
+ Irssi::signal_stop;
+ }
+}
+
+sub update_keymap {
+ %nummap = %wnmap = %specialmap = %custom_key_map = ();
+ Irssi::signal_remove('command bind' => 'watch_keymap');
+ Irssi::signal_add_first('print text' => 'get_keymap');
+ Irssi::command('bind');
+ Irssi::signal_remove('print text' => 'get_keymap');
+ for (keys %custom_key_map) {
+ if (exists $custom_key_map{$_} &&
+ $custom_key_map{$_} =~ s/\01(\w+)\01/exists $custom_key_map{$1} ? $custom_key_map{$1} : "\02"/ge) {
+ if ($custom_key_map{$_} =~ /\02/) {
+ delete $custom_key_map{$_};
+ }
+ else {
+ redo;
+ }
+ }
+ }
+ for my $keymap (\(%specialmap, %wnmap, %nummap)) {
+ for (keys %$keymap) {
+ if ($keymap->{$_} =~ s/\01(\w+)\01/exists $custom_key_map{$1} ? $custom_key_map{$1} : "\02"/ge) {
+ if ($keymap->{$_} =~ /\02/) {
+ delete $keymap->{$_};
+ }
+ }
+ }
+ }
+ Irssi::signal_add('command bind' => 'watch_keymap');
+ delete $viewer{client_keymap};
+ &wl_changed;
+}
+
+# watch keymap changes
+sub watch_keymap {
+ Irssi::timeout_add_once(1000, 'update_keymap', undef);
+}
+
+{ my %strip_table = (
+ # fe-common::core::formats.c:format_expand_styles
+ # delete format_backs format_fores bold_fores other stuff
+ (map { $_ => '' } (split //, '04261537' . 'kbgcrmyw' . 'KBGCRMYW' . 'U9_8I:|FnN>#[' . 'pP')),
+ # escape
+ (map { $_ => $_ } (split //, '{}%')),
+ );
+ sub ir_strip_codes { # strip %codes
+ my $o = shift;
+ $o =~ s/(%(%|Z.{6}|z.{6}|X..|x..|.))/exists $strip_table{$2} ? $strip_table{$2} :
+ $2 =~ m{x(?:0[a-f]|[1-6][0-9a-z]|7[a-x])|z[0-9a-f]{6}}i ? '' : $1/gex;
+ $o
+ }
+}
+## ir_parse_special -- wrapper around parse_special
+## $i - input format
+## $args - array ref of arguments to format
+## $win - different target window (default current window)
+## $flags - different kind of escape flags (default 4|8)
+## returns formatted str
+sub ir_parse_special {
+ my $o;
+ my $i = shift;
+ my $args = shift // [];
+ y/ /\177/ for @$args; # hack to escape spaces
+ my $win = shift || Irssi::active_win;
+ my $flags = shift // 0x4|0x8;
+ my @cmd_args = ($i, (join ' ', @$args), $flags);
+ my $server = Irssi::active_server();
+ if (ref $win and ref $win->{active}) {
+ $o = $win->{active}->parse_special(@cmd_args);
+ }
+ elsif (ref $win and ref $win->{active_server}) {
+ $o = $win->{active_server}->parse_special(@cmd_args);
+ }
+ elsif (ref $server) {
+ $o = $server->parse_special(@cmd_args);
+ }
+ else {
+ $o = &Irssi::parse_special(@cmd_args);
+ }
+ $o =~ y/\177/ /;
+ $o
+}
+
+sub sb_format_expand { # Irssi::current_theme->format_expand wrapper
+ Irssi::current_theme->format_expand(
+ $_[0],
+ (
+ Irssi::EXPAND_FLAG_IGNORE_REPLACES
+ |
+ ($_[1] ? 0 : Irssi::EXPAND_FLAG_IGNORE_EMPTY)
+ )
+ )
+}
+
+{ my $term_type = Irssi::version > 20040819 ? 'term_charset' : 'term_type';
+ if (Irssi->can('string_width')) {
+ *screen_length = sub { Irssi::string_width($_[0]) };
+ }
+ else {
+ local $@;
+ eval { require Text::CharWidth; };
+ unless ($@) {
+ *screen_length = sub { Text::CharWidth::mbswidth($_[0]) };
+ }
+ else {
+ my $err = $@; chomp $err; $err =~ s/\sat .* line \d+\.$//;
+ #Irssi::print("%_$IRSSI{name}: warning:%_ Text::CharWidth module failed to load. Length calculation may be off! Error was:");
+ print "%_$IRSSI{name}:%_ $err";
+ *screen_length = sub {
+ my $temp = shift;
+ if (lc Irssi::settings_get_str($term_type) eq 'utf-8') {
+ Encode::_utf8_on($temp);
+ }
+ length($temp)
+ };
+ }
+ }
+ sub as_uni {
+ no warnings 'utf8';
+ Encode::decode(Irssi::settings_get_str($term_type), $_[0], 0)
+ }
+ sub as_tc {
+ Encode::encode(Irssi::settings_get_str($term_type), $_[0], 0)
+ }
+}
+
+sub sb_length {
+ screen_length(ir_strip_codes($_[0]))
+}
+
+sub run_custom_xform {
+ local $@;
+ eval {
+ $custom_xform->()
+ };
+ if ($@) {
+ $@ =~ /^(.*)/;
+ print '%_'.(set 'custom_xform').'%_ died (disabling): '.$1;
+ $custom_xform = undef;
+ }
+}
+
+sub remove_uniform {
+ my $o = shift;
+ $o =~ s/^xmpp:(.*?[%@]).+\.[^.]+$/$1/ or
+ $o =~ s#^psyc://.+\.[^.]+/([@~].*)$#$1#;
+ if ($custom_xform) {
+ run_custom_xform() for $o;
+ }
+ $o
+}
+
+sub remove_uniform_vars {
+ my $win = shift;
+ my $name = __PACKAGE__ . '::custom_xform::' . $win->{active}{type}
+ if ref $win->{active} && $win->{active}{type};
+ no strict 'refs';
+ local ${$name} = 1 if $name;
+ remove_uniform(+shift);
+}
+
+sub lc1459 {
+ my $x = shift;
+ $x =~ y/][\\^/}{|~/;
+ lc $x
+}
+
+sub window_list {
+ my $i = 0;
+ map { $_->[1] } sort $window_sort_func map { [ $i++, $_ ] } Irssi::windows;
+}
+
+sub _calculate_abbrev {
+ my ($wins, $abbrevList) = @_;
+ if ($S{fancy_abbrev} !~ /^(no|off|head)/i) {
+ my @nameList = map { ref $_ ? remove_uniform_vars($_, as_uni($_->get_active_name) // '') : '' } @$wins;
+ for (my $i = 0; $i < @nameList - 1; ++$i) {
+ my ($x, $y) = ($nameList[$i], $nameList[$i + 1]);
+ s/^[+#!=]// for $x, $y;
+ my $res = exists $abbrev_cache{$x}{$y} ? $abbrev_cache{$x}{$y}
+ : $abbrev_cache{$x}{$y} = string_LCSS($x, $y);
+ if (defined $res) {
+ for ($nameList[$i], $nameList[$i + 1]) {
+ $abbrevList->{$_} //= int((index $_, $res) + (length $res) / 2);
+ }
+ }
+ }
+ }
+}
+
+my %act_last_line_shades = (
+ r => [qw[ 50 40 30 20 ]],
+ g => [qw[ 1O 1I 1C 16 ]],
+ y => [qw[ 5O 4I 3C 26 ]],
+ b => [qw[ 15 14 13 12 ]],
+ m => [qw[ 54 43 32 21 ]],
+ c => [qw[ 1S 1L 1E 17 ]],
+ w => [qw[ 7W 7T 7Q 3E ]],
+ K => [qw[ 7M 7K 27 7H ]],
+ R => [qw[ 60 50 40 30 ]],
+ G => [qw[ 1U 1O 1I 1C ]],
+ Y => [qw[ 6U 5O 4I 3C ]],
+ B => [qw[ 2B 2A 29 28 ]],
+ M => [qw[ 65 54 43 32 ]],
+ C => [qw[ 1Z 1S 1L 1E ]],
+ W => [qw[ 6Z 5S 7R 7O ]],
+ );
+
+sub _format_display {
+ my (undef, $format, $cformat, $hilight, $name, $number, $key, $win) = @_;
+ if ($print_text_activity && $S{line_shade}) {
+ my @hilight_code = split /\177/, sb_format_expand("{$hilight \177}"), 2;
+ my $max_time = max(1, log($S{line_shade}) - log(1000));
+ my $time_delta = min(3, min($max_time, log(max(1, time - $win->{last_line}))) / $max_time * 3);
+ if ($hilight_code[0] =~ /%(.)/ && exists $act_last_line_shades{$1}) {
+ $hilight = 'sb_act_hilight_color %X'.$act_last_line_shades{$1}[$time_delta];
+ }
+ }
+ $cformat = '$0' unless length $cformat;
+ my %map = ('$C' => $cformat, '$N' => '$1', '$Q' => '$2');
+ $format =~ s<(\$.)><$map{$1}//$1>ge;
+ $format =~ s<\$H((?:\$.|[^\$])*?)\$S><{$hilight $1%n}>g;
+ my @ret = ir_parse_special(sb_format_expand($format), [$name, $number, $key], $win);
+ @ret
+}
+
+sub _get_format {
+ Irssi::current_theme->get_format(__PACKAGE__, @_)
+}
+
+sub _is_detached {
+ my ($win, $active_number) = @_;
+ my $level = $win->{data_level} // 0;
+ my $number = $win->{refnum};
+ my $name = lc1459( as_uni($win->{name}) );
+ my $active = lc1459( as_uni($win->get_active_name) // '' );
+ my $tag = $win->{active} && $win->{active}{server} ? lc1459( as_uni($win->{active}{server}{tag}) // '' ) : '';
+ my @cond = ($number);
+ push @cond, "$name" if length $name;
+ push @cond, "$tag/$active" if length $tag && length $active;
+ push @cond, "$active" if length $active;
+ push @cond, "$tag/*", "$tag/::all" if length $tag;
+ push @cond, "*", "::all";
+ for my $cond (@cond) {
+ if (exists $detach_map{ $cond }) {
+ my $dd = $detach_map{ $cond } // $S{detach_data};
+ return $win->{data_level} < abs $dd
+ && ($number != $active_number || 0 <= $dd);
+ }
+ }
+ return;
+}
+
+sub _calculate_items {
+ my ($wins, $abbrevList) = @_;
+
+ my $display_header = _get_format(set 'display_header');
+ my $name_format = _get_format(set 'name_display');
+ my $abbrev_chars = as_uni(_get_format(set 'abbrev_chars'));
+
+ my %displays;
+
+ my $active = Irssi::active_win;
+ @win_items = ();
+ %keymap = (%nummap, %wnmap_exp);
+
+ my ($numPad, $keyPad) = (0, 0);
+ if ($VIEWER_MODE or $S{block} < 0) {
+ $numPad = length((sort { length $b <=> length $a } keys %keymap)[0]) // 0;
+ $keyPad = length((sort { length $b <=> length $a } values %keymap)[0]) // 0;
+ }
+ my $last_net;
+ my ($abbrev1, $abbrev2) = $abbrev_chars =~ /(\X)(.*)/;
+ my @abbrev_chars = ('~', "\x{301c}");
+ unless (defined $abbrev1 && screen_length(as_tc($abbrev1)) == 1) { $abbrev1 = $abbrev_chars[0] }
+ unless (length $abbrev2) {
+ $abbrev2 = $abbrev1;
+ if ($abbrev1 eq $abbrev_chars[0]) {
+ $abbrev2 = $abbrev_chars[1];
+ }
+ else {
+ $abbrev2 = $abbrev1;
+ }
+ }
+ if (screen_length(as_tc($abbrev2)) == 1) {
+ $abbrev2 x= 2;
+ }
+ while (screen_length(as_tc($abbrev2)) > 2) {
+ chop $abbrev2;
+ }
+ unless (screen_length(as_tc($abbrev2)) == 2) {
+ $abbrev2 = $abbrev_chars[1];
+ }
+ for my $win (@$wins) {
+ my $global_tag_header_mode;
+
+ next unless ref $win;
+
+ my $backup_win = Storable::dclone($win);
+ delete $backup_win->{active} unless ref $backup_win->{active};
+
+ $global_tag_header_mode =
+ $display_header && ($last_net // '') ne ($backup_win->{active}{server}{tag} // '');
+
+ if ($win->{data_level} < abs $S{hide_data}
+ && ($win->{refnum} != $active->{refnum} || 0 <= $S{hide_data})) {
+ next; }
+ elsif (exists $awins{$win->{refnum}} && $S{hide_empty} && !$win->items
+ && ($win->{refnum} != $active->{refnum} || 0 <= $S{hide_empty})) {
+ next; }
+ elsif (_is_detached($win, $active->{refnum})) {
+ next; }
+
+ my $colour = $win->{hilight_color} // '';
+ my $hilight = do {
+ if ($win->{data_level} == 0) { 'sb_act_none'; }
+ elsif ($win->{data_level} == 1) { 'sb_act_text'; }
+ elsif ($win->{data_level} == 2) { 'sb_act_msg'; }
+ elsif ($colour ne '') { "sb_act_hilight_color $colour"; }
+ elsif ($win->{data_level} == 3) { 'sb_act_hilight'; }
+ else { 'sb_act_special'; }
+ };
+ my $number = $win->{refnum};
+
+ my ($name, $display, $cdisplay);
+ if ($global_tag_header_mode) {
+ $display = $display_header;
+ $name = as_uni($backup_win->{active}{server}{tag}) // '';
+ if ($custom_xform) {
+ no strict 'refs';
+ local ${ __PACKAGE__ . '::custom_xform::TAG' } = 1;
+ run_custom_xform() for $name;
+ }
+ }
+ else {
+ my @display = ('display_nokey');
+ if (defined $keymap{$number} and $keymap{$number} ne '') {
+ unshift @display, map { (my $cpy = $_) =~ s/_no/_/; $cpy } @display;
+ }
+ if (exists $awins{$number}) {
+ unshift @display, map { my $cpy = $_; $cpy .= '_visible'; $cpy } @display;
+ }
+ if ($active->{refnum} == $number) {
+ unshift @display, map { my $cpy = $_; $cpy .= '_active'; $cpy }
+ grep { !/_visible$/ } @display;
+ }
+ $display = (grep { length $_ }
+ map { $displays{$_} //= _get_format(set $_) }
+ @display)[0];
+ $cdisplay = $name_format;
+ $name = as_uni($win->get_active_name) // '';
+ $name = '*' if $S{banned_on} and exists $banned_channels{lc1459($name)};
+ $name = remove_uniform_vars($win, $name) if $name ne '*';
+ if ($name ne '*' and $win->{name} ne '' and $S{prefer_name}) {
+ $name = as_uni($win->{name});
+ if ($custom_xform) {
+ no strict 'refs';
+ local ${ __PACKAGE__ . '::custom_xform::NAME' } = 1;
+ run_custom_xform() for $name;
+ }
+ }
+
+ if (!$VIEWER_MODE && $S{block} >= 0 && $S{hide_name}
+ && $win->{data_level} < abs $S{hide_name}
+ && ($win->{refnum} != $active->{refnum} || 0 <= $S{hide_name})) {
+ $name = '';
+ $cdisplay = '';
+ }
+ }
+
+ $display = "$display%n";
+ my $num_ent = (' 'x max(0,$numPad - length $number)) . $number;
+ my $key_ent = exists $keymap{$number} ? ((' 'x max(0,$keyPad - length $keymap{$number})) . $keymap{$number}) : ' 'x$keyPad;
+ if ($VIEWER_MODE or $S{sbar_maxlen} or $S{block} < 0) {
+ my $baseLength = sb_length(_format_display(
+ '', $display, $cdisplay, $hilight,
+ 'x', # placeholder
+ $num_ent,
+ $key_ent,
+ $win)) - 1;
+ my $diff = (abs $S{block}) - (screen_length(as_tc($name)) + $baseLength);
+ if ($diff < 0) { # too long
+ my $screen_length = screen_length(as_tc($name));
+ if ((abs $diff) >= $screen_length) { $name = '' } # forget it
+ elsif ((abs $diff) + screen_length(as_tc(substr($name, 0, 1))) >= $screen_length) { $name = substr($name, 0, 1); }
+ else {
+ my $ulen = length $name;
+ my $middle2 = exists $abbrevList->{$name} ?
+ ($S{fancy_strict}) ?
+ 2* $abbrevList->{$name} :
+ (2*($abbrevList->{$name} + $ulen) / 3) :
+ ($S{fancy_head}) ?
+ 2*$ulen :
+ $ulen;
+ my $first = 1;
+ while (length $name > 1) {
+ my $cp = $middle2 >= 0 ? $middle2/2 : -1; # clearing position
+ my $rm = 2;
+ # if character at end is wider than 1 cell -> replace it with ~
+ if (screen_length(as_tc(substr $name, $cp, 1)) > 1) {
+ if ($first || $cp < 0) {
+ $rm = 1;
+ $first = undef;
+ }
+ }
+ elsif ($cp < 0) { # elsif at end -> replace last 2 characters
+ --$cp;
+ }
+ (substr $name, $cp, $rm) = $abbrev1;
+ if ($cp > -1 && $rm > 1) {
+ --$middle2;
+ }
+ my $sl = screen_length(as_tc($name));
+ if ($sl + $baseLength < abs $S{block}) {
+ (substr $name, ($middle2+1)/2, 1) = $abbrev2;
+ last;
+ }
+ elsif ($sl + $baseLength == abs $S{block}) {
+ last;
+ }
+ }
+ }
+ }
+ elsif ($VIEWER_MODE or $S{block} < 0) {
+ $name .= (' ' x $diff);
+ }
+ }
+
+ push @win_items, _format_display(
+ '', $display, $cdisplay, $hilight,
+ as_tc($name),
+ $num_ent,
+ as_tc($key_ent),
+ $win);
+
+ if ($global_tag_header_mode) {
+ $last_net = $backup_win->{active}{server}{tag};
+ redo;
+ }
+
+ $mouse_coords{refnum}{$#win_items} = $number;
+ }
+}
+
+sub _spread_items {
+ my $width = $screenWidth - $sb_base_width - 1;
+ my @separator = _get_format(set 'separator');
+ if ($S{block} >= 0) {
+ my $sep2 = _get_format(set 'separator2');
+ push @separator, $sep2 if length $sep2 && $sep2 ne $separator[0];
+ }
+ $separator[0] .= '%n';
+ my @sepLen = map { sb_length($_) } @separator;
+
+ @actString = ();
+ my $curLine;
+ my $curLen = 0;
+ if ($S{shared_sbar}) {
+ $curLen += $S{shared_sbar}[0] + 2;
+ $width -= $S{shared_sbar}[2];
+ }
+ my $mouse_header_check = 0;
+ for my $it (@win_items) {
+ my $itemLen = sb_length($it);
+ if ($curLen) {
+ if ($curLen + $itemLen + $sepLen[$mouse_header_check % @sepLen] > $width) {
+ $width += $S{shared_sbar}[2]
+ if !@actString && $S{shared_sbar};
+ push @actString, $curLine;
+ $curLine = undef;
+ $curLen = 0;
+ }
+ elsif (defined $curLine) {
+ $curLine .= $separator[$mouse_header_check % @separator];
+ $curLen += $sepLen[$mouse_header_check % @sepLen];
+ }
+ }
+ $curLine .= $it;
+ if (exists $mouse_coords{refnum}{$mouse_header_check}) {
+ $mouse_coords{scalar @actString}{ $_ } = $mouse_coords{refnum}{$mouse_header_check}
+ for $curLen .. $curLen + $itemLen - 1;
+ }
+ $curLen += $itemLen;
+ }
+ continue {
+ ++$mouse_header_check;
+ }
+ $curLen -= $S{shared_sbar}[0]
+ if !@actString && $S{shared_sbar};
+ push @actString, $curLine if $curLen;
+}
+
+sub remake {
+ my %abbrevList;
+ my @wins = window_list();
+ if ($VIEWER_MODE or $S{sbar_maxlen} or $S{block} < 0) {
+ _calculate_abbrev(\@wins, \%abbrevList);
+ }
+
+ %mouse_coords = ( refnum => +{} );
+ _calculate_items(\@wins, \%abbrevList);
+
+ unless ($VIEWER_MODE) {
+ _spread_items();
+
+ push @actString, undef unless @actString || $S{all_disable};
+ }
+}
+
+sub update_wl {
+ return if $BLOCK_ALL;
+ remake();
+
+ Irssi::statusbar_items_redraw(set $_) for keys %statusbars;
+
+ unless ($VIEWER_MODE) {
+ Irssi::timeout_add_once(100, 'syncLines', undef);
+ }
+ else {
+ syncViewer();
+ }
+}
+
+sub screenFullRedraw {
+ my ($window) = @_;
+ if (!ref $window or $window->{refnum} == Irssi::active_win->{refnum}) {
+ $viewer{fullRedraw} = 1 if $viewer{client};
+ $settings_str = '';
+ &setup_changed;
+ }
+}
+
+sub restartViewerServer {
+ if ($VIEWER_MODE) {
+ stop_viewer();
+ start_viewer();
+ }
+}
+
+sub _simple_quote {
+ my @r = map {
+ my $x = $_;
+ $x =~ s/'/'"'"'/g;
+ $x = "'$x'";
+ } @_;
+ wantarray ? @r : shift @r
+}
+
+sub _viewer_command_replace_format {
+ my ($ecmd, @args) = @_;
+ my $file = _simple_quote(SCRIPT_FILE());
+ my $path = _simple_quote($viewer{path});
+ my @env;
+ for my $env (shellwords($S{viewer_launch_env})) {
+ if ($env =~ /^(\w+)(?:=(.*))$/) {
+ push @env, "AWL_$1=$2"
+ }
+ }
+ my $cmd = join ' ',
+ (@env ? ('env', _simple_quote(@env)) : ()),
+ 'perl', $file, '-1', _simple_quote(@args), $path;
+ $ecmd =~ s{%(%|\w+)}{
+ my $sub = $1;
+ if ($sub eq '%') {
+ '%'
+ }
+ elsif ($sub =~ /^(q*)A(.*)/) {
+ my $ret = $cmd;
+ for (1..length $1) {
+ $ret = _simple_quote($ret);
+ }
+ "$ret$2"
+ }
+ else {
+ "%$sub"
+ }
+ }gex;
+ $ecmd
+}
+
+sub start_viewer {
+ unlink $viewer{path} if -S $viewer{path} || -p _;
+
+ $viewer{server} = IO::Socket::UNIX->new(
+ Type => SOCK_STREAM,
+ Local => $viewer{path},
+ Listen => 1
+ );
+ unless ($viewer{server}) {
+ $viewer{msg} = "Viewer: $!";
+ $viewer{retry} = Irssi::timeout_add_once(5000, 'retry_viewer', 1);
+ return;
+ }
+ $viewer{server}->blocking(0);
+ set_viewer_mode_hint();
+ $viewer{server_tag} = Irssi::input_add($viewer{server}->fileno, INPUT_READ, 'vi_connected', undef);
+
+ if ($S{viewer_launch}) {
+ if (length $ENV{TMUX_PANE} && length $ENV{TMUX} && lc $S{viewer_tmux_position} ne 'custom') {
+ my $cmd = _viewer_command_replace_format('%qA', '-p', lc $S{viewer_tmux_position});
+ Irssi::command("exec - tmux neww -d $cmd 2>&1 &");
+ }
+ elsif (length $ENV{WINDOWID} && length $ENV{DISPLAY} && length $S{viewer_xwin_command} && $S{viewer_xwin_command} =~ /\S/) {
+ my $cmd = _viewer_command_replace_format($S{viewer_xwin_command});
+ Irssi::command("exec - $cmd 2>&1 &");
+ }
+ elsif (length $S{viewer_custom_command} && $S{viewer_custom_command} =~ /\S/) {
+ my $cmd = _viewer_command_replace_format($S{viewer_custom_command});
+ Irssi::command("exec - $cmd 2>&1 &");
+ }
+ }
+}
+
+sub set_viewer_mode_hint {
+ return unless $viewer{server};
+ if ($S{no_mode_hint}) {
+ $viewer{msg} = undef;
+ }
+ else {
+ my ($name) = __PACKAGE__ =~ /::([^:]+)$/;
+ $viewer{msg} = "Run $name from the shell or switch to sbar mode";
+ }
+}
+
+sub retry_viewer {
+ start_viewer();
+}
+
+sub vi_close_client {
+ Irssi::input_remove(delete $viewer{client_tag}) if exists $viewer{client_tag};
+ $viewer{client}->close if $viewer{client};
+ delete $viewer{client};
+ delete $viewer{client_keymap};
+ delete $viewer{client_settings};
+ delete $viewer{client_env};
+ delete $viewer{fullRedraw};
+}
+
+sub vi_connected {
+ vi_close_client();
+ $viewer{client} = $viewer{server}->accept or return;
+ $viewer{client}->blocking(0);
+ $viewer{client_tag} = Irssi::input_add($viewer{client}->fileno, INPUT_READ, 'vi_clientinput', undef);
+ syncViewer();
+}
+
+use constant VIEWER_BLOCK_SIZE => 1024;
+sub vi_clientinput {
+ if ($viewer{client}->read(my $buf, VIEWER_BLOCK_SIZE)) {
+ $viewer{rcvbuf} .= $buf;
+ if ($viewer{rcvbuf} =~ s/^(?:(active|\d+)|(last|up|down))\n//igm) {
+ if (defined $2) {
+ Irssi::command("window $2");
+ }
+ elsif (lc $1 eq 'active' && $viewer{use_ack}) {
+ Irssi::command($viewer{use_ack});
+ }
+ else {
+ Irssi::command("window goto $1");
+ }
+ }
+ }
+ else {
+ vi_close_client();
+ Irssi::timeout_add_once(100, 'syncViewer', undef);
+ }
+}
+
+sub stop_viewer {
+ Irssi::timeout_remove(delete $viewer{retry}) if exists $viewer{retry};
+ vi_close_client();
+ Irssi::input_remove(delete $viewer{server_tag}) if exists $viewer{server_tag};
+ return unless $viewer{server};
+ $viewer{server}->close;
+ delete $viewer{server};
+}
+sub _encode_var {
+ my $str;
+ while (@_) {
+ my ($name, $var) = splice @_, 0, 2;
+ my $type = ref $var ? $var =~ /HASH/ ? 'map' : $var =~ /ARRAY/ ? 'list' : '' : '';
+ $str .= "\n\U$name$type\_begin\n";
+ if ($type eq 'map') {
+ no warnings 'numeric';
+ $str .= " $_\n ${$var}{$_}\n" for sort { $a <=> $b || $a cmp $b } keys %$var;
+ }
+ elsif ($type eq 'list') {
+ $str .= " $_\n" for @$var;
+ }
+ else {
+ $str .= " $var\n";
+ }
+ $str .= "\U$name$type\_end\n";
+ }
+ $str
+}
+sub syncViewer {
+ if ($viewer{client}) {
+ @actString = ();
+ if ($currentLines) {
+ killOldStatus();
+ $currentLines = 0;
+ }
+ my $str;
+ unless ($viewer{client_keymap}) {
+ $str .= _encode_var('key', +{ %nummap, %specialmap });
+ $viewer{client_keymap} = 1;
+ }
+ unless ($viewer{client_settings}) {
+ $str .= _encode_var(
+ block => $S{block},
+ ha => $S{height_adjust},
+ mc => $S{maxcolumns},
+ ml => $S{maxlines},
+ tc => $S{true_colour},
+ );
+ $viewer{client_settings} = 1;
+ }
+ unless ($viewer{client_env}) {
+ $str .= _encode_var(irssienv => +{
+ length $ENV{TMUX_PANE} && length $ENV{TMUX} ?
+ (tmux_pane => $ENV{TMUX_PANE},
+ tmux_srv => $ENV{TMUX}) : (),
+ length $ENV{WINDOWID} ?
+ (xwinid => $ENV{WINDOWID}) : (),
+ });
+ $viewer{client_env} = 1;
+ }
+ my $separator = _get_format(set 'separator');
+ my $sepLen = sb_length($separator);
+ my $item_bg = _get_format(set 'viewer_item_bg');
+ my $title = _get_format(set 'title');
+ if (length $title) {
+ $title =~ s{\\(.)|(.)}{
+ defined $2 ? quotemeta $2
+ : $1 eq 'V' ? '\U'
+ : $1 eq ':' ? quotemeta '%N'
+ : $1 =~ /^[uUFQE]$/ ? "\\$1"
+ : quotemeta "\\$1"
+ }sge;
+ $title = eval qq{"$title"};
+ }
+ $str .= _encode_var(redraw => 1) if delete $viewer{fullRedraw};
+ $str .= _encode_var(separator => $separator,
+ seplen => $sepLen,
+ itembg => $item_bg,
+ title => $title,
+ mouse => $mouse_coords{refnum},
+ key2 => \%wnmap_exp,
+ win => \@win_items);
+
+ my $was = $viewer{client}->blocking(1);
+ $viewer{client}->print($str);
+ $viewer{client}->blocking($was);
+ }
+ elsif ($viewer{server}) {
+ if (defined $viewer{msg}) {
+ @actString = ((uc setc()).": $viewer{msg}");
+ }
+ else {
+ @actString = ();
+ }
+ }
+ elsif (defined $viewer{msg}) {
+ @actString = ((uc setc()).": $viewer{msg}");
+ }
+ if (@actString) {
+ Irssi::timeout_add_once(100, 'syncLines', undef);
+ }
+ elsif ($currentLines) {
+ killOldStatus();
+ $currentLines = 0;
+ }
+}
+
+sub reset_awl {
+ Irssi::timeout_remove($shade_line_timer) if $shade_line_timer; $shade_line_timer = undef;
+ my $was_sort = $S{sort} // '';
+ my $was_xform = $S{xform} // '';
+ my $was_shared = $S{shared_sbar};
+ my $was_no_hint = $S{no_mode_hint};
+ my $was_custom_key = $S{custom_key_re} // '';
+ %S = (
+ sort => Irssi::settings_get_str( set 'sort'),
+ fancy_abbrev => Irssi::settings_get_str('fancy_abbrev'),
+ xform => Irssi::settings_get_str( set 'custom_xform'),
+ block => Irssi::settings_get_int( set 'block'),
+ banned_on => Irssi::settings_get_bool('banned_channels_on'),
+ prefer_name => Irssi::settings_get_bool(set 'prefer_name'),
+ hide_data => Irssi::settings_get_int( set 'hide_data'),
+ hide_name => Irssi::settings_get_int( set 'hide_name_data'),
+ hide_empty => Irssi::settings_get_int( set 'hide_empty'),
+ custom_key_re => Irssi::settings_get_str( set 'custom_key_re'),
+ detach => Irssi::settings_get_str( set 'detach'),
+ detach_data => Irssi::settings_get_int( set 'detach_data'),
+ detach_aht => Irssi::settings_get_bool(set 'detach_aht'),
+ sbar_maxlen => Irssi::settings_get_bool(set 'sbar_maxlength'),
+ placement => Irssi::settings_get_str( set 'placement'),
+ position => Irssi::settings_get_int( set 'position'),
+ maxlines => Irssi::settings_get_int( set 'maxlines'),
+ maxcolumns => Irssi::settings_get_int( set 'maxcolumns'),
+ all_disable => Irssi::settings_get_bool(set 'all_disable'),
+ height_adjust => Irssi::settings_get_int( set 'height_adjust'),
+ mouse_offset => Irssi::settings_get_int( set 'mouse_offset'),
+ mouse_scroll => Irssi::settings_get_int( 'mouse_scroll'),
+ mouse_escape => Irssi::settings_get_int( 'mouse_escape'),
+ line_shade => Irssi::settings_get_time(set 'last_line_shade'),
+ no_mode_hint => Irssi::settings_get_bool(set 'no_mode_hint'),
+ true_colour => Irssi::parse_special('$colors_ansi_24bit'),
+ viewer_launch => Irssi::settings_get_bool(set 'viewer_launch'),
+ viewer_launch_env => Irssi::settings_get_str(set 'viewer_launch_env'),
+ viewer_xwin_command => Irssi::settings_get_str(set 'viewer_xwin_command'),
+ viewer_custom_command => Irssi::settings_get_str(set 'viewer_custom_command'),
+ viewer_tmux_position => Irssi::settings_get_str(set 'viewer_tmux_position'),
+ );
+ $S{fancy_strict} = $S{fancy_abbrev} =~ /^strict/i;
+ $S{fancy_head} = $S{fancy_abbrev} =~ /^head/i;
+ my $shared = Irssi::settings_get_str(set 'shared_sbar');
+ if ($shared =~ /^(\d+)([<])(\d+)$/) {
+ $S{shared_sbar} = [$1, $2, $3];
+ }
+ else {
+ Irssi::settings_set_str(set 'shared_sbar', 'OFF');
+ $S{shared_sbar} = undef;
+ }
+ lock_keys(%S);
+ if ($was_sort ne $S{sort}) {
+ $print_text_activity = undef;
+ my @sort_order = grep { @$_ > 4 } map {
+ s/^\s*//;
+ my $reverse = s/^\W*\K[-!]//;
+ my $undef_check = s/^\W*\K~// ? 1 : undef;
+ my $equal_check = s/=(.*)\s?$// ? $1 : undef;
+ s/\s*$//;
+ my $ignore_case = s/#i$// ? 1 : undef;
+
+ $print_text_activity = 1 if $_ eq 'last_line';
+
+ my @path = split '/';
+ my $class_check = @path && $path[-1] =~ s/(::.*)$// ? $1 : undef;
+ my $lru = "@path" eq 'lru';
+
+ [ $reverse ? -1 : 1, $undef_check, $equal_check, $class_check, $ignore_case, $lru, @path ]
+ } "$S{sort}," =~ /([^+,]*|[^+,]*=[^,]*?\s(?=\+)|[^+,]*=[^,]*)[+,]/g;
+ $window_sort_func = sub {
+ no warnings qw(numeric uninitialized);
+ for my $so (@sort_order) {
+ my @x = map {
+ my $ret = 0;
+ $_ = lc1459($_) if defined $_ && !ref $_ && $so->[4];
+ $ret = $_ eq ($so->[4] ? lc1459($so->[2]) : $so->[2]) ? 1 : -1 if defined $so->[2];
+ $ret = defined $_ ? ($ret || -3) : 3 if $so->[1];
+ $ret = ref $_ && $_->isa('Irssi'.$so->[3]) ? 2 : ($ret || -2) if $so->[3];
+ -$ret || $_
+ }
+ map {
+ $so->[5] ? $_->[0] : reduce { return unless ref $a; $a->{$b} } $_->[1], @{$so}[6..$#$so]
+ } $a, $b;
+ return ((($x[0] <=> $x[1] || $x[0] cmp $x[1]) * $so->[0]) || next);
+ }
+ return ($a->[1]{refnum} <=> $b->[1]{refnum});
+ };
+ }
+ if ($was_xform ne $S{xform}) {
+ if ($S{xform} !~ /\S/) {
+ $custom_xform = undef;
+ }
+ else {
+ my $script_pkg = __PACKAGE__ . '::custom_xform';
+ local $@;
+ $custom_xform = eval qq{
+package $script_pkg;
+use strict;
+no warnings;
+our (\$QUERY, \$CHANNEL, \$TAG, \$NAME);
+return sub {
+# line 1 @{[ set 'custom_xform' ]}\n$S{xform}\n}};
+ if ($@) {
+ $@ =~ /^(.*)/;
+ print '%_'.(set 'custom_xform').'%_ did not compile: '.$1;
+ }
+ }
+ }
+ if ($was_custom_key ne $S{custom_key_re}) {
+ my $custom_key = $S{custom_key_re};
+ my $was_custom_key_re = $custom_key_re;
+ local $@;
+ eval { $custom_key_re = qr/(?i)$custom_key/; 1 }
+ or do {
+ print '%_'.(set 'custom_key_re').'%_ did not compile: '
+ . do { $@ =~ /(.*) at / && $1 };
+ $custom_key_re = qr/(?!)/;
+ };
+ if ($was_custom_key_re ne $custom_key_re) {
+ update_keymap();
+ }
+ }
+
+ my $new_settings = join "\n", $VIEWER_MODE
+ ? ("\\", $S{block}, $S{height_adjust}, $S{maxlines}, $S{maxcolumns}, $S{true_colour})
+ : ("!", $S{placement}, $S{position});
+
+ my $first_viewer = $settings_str eq '1';
+ if ($settings_str ne $new_settings) {
+ @actString = ();
+ %abbrev_cache = ();
+ $currentLines = 0;
+ killOldStatus();
+ delete $viewer{client_settings};
+ $settings_str = $new_settings;
+ }
+
+ my $was_mouse_mode = $MOUSE_ON;
+ if ($MOUSE_ON = Irssi::settings_get_bool(set 'mouse') and !$was_mouse_mode) {
+ install_mouse();
+ }
+ elsif ($was_mouse_mode and !$MOUSE_ON) {
+ uninstall_mouse();
+ }
+
+ unless ($first_viewer) {
+ my $path = Irssi::settings_get_str(set 'path');
+ my $was_viewer_mode = $VIEWER_MODE;
+ if ($was_viewer_mode &&
+ defined $viewer{path} && $viewer{path} ne $path) {
+ stop_viewer();
+ $was_viewer_mode = 0;
+ }
+ elsif ($was_viewer_mode && $S{no_mode_hint} != $was_no_hint + 0) {
+ set_viewer_mode_hint();
+ }
+ $viewer{path} = $path;
+ if ($VIEWER_MODE = Irssi::settings_get_bool(set 'viewer') and !$was_viewer_mode) {
+ start_viewer();
+ }
+ elsif ($was_viewer_mode and !$VIEWER_MODE) {
+ stop_viewer();
+ }
+ }
+
+ %banned_channels = map { lc1459(as_uni($_)) => undef }
+ split ' ', Irssi::settings_get_str('banned_channels');
+
+ %detach_map = ($S{detach_aht}
+ ? (map { ( lc1459(as_uni($_)) => undef ) }
+ split ' ', Irssi::settings_get_str('activity_hide_targets')) : (),
+ (map { my ($k, $v) = (split /(?:,(-?\d+))$/, $_)[0, 1];
+ ( lc1459(as_uni($k)) => $v ) }
+ split ' ', $S{detach}));
+
+ my @sb_base = split /\177/, sb_format_expand("{sbstart}{sb \177}{sbend}"), 2;
+ $sb_base_width_pre = sb_length($sb_base[0]);
+ $sb_base_width_post = max 0, sb_length($sb_base[1])-1;
+ $sb_base_width = $sb_base_width_pre + $sb_base_width_post;
+
+ if ($print_text_activity && $S{line_shade}) {
+ $shade_line_timer = Irssi::timeout_add(max(10 * GLOB_QUEUE_TIMER, 100*$S{line_shade}**(1/3)), 'wl_changed', undef);
+ }
+
+ $CHANGED{AWINS} = 1;
+}
+
+sub hide_window {
+ my ($data) = @_;
+ my $ent;
+
+ $data =~ s/\s*$//;
+ my $win = Irssi::active_win;
+ my $number = $win->{refnum};
+ my $name = as_uni($win->{name});
+ my $active = as_uni($win->get_active_name) // '';
+ my $tag = $win->{active} && $win->{active}{server} ? as_uni($win->{active}{server}{tag}) // '' : '';
+ if (length $name) {
+ $ent = "$name";
+ }
+ elsif (length $tag && length $active) {
+ $ent = "$tag/$active";
+ }
+ else {
+ $ent = "$number";
+ }
+
+ my $found = 0;
+ my @setting;
+ for my $s (split ' ', $S{detach}) {
+ my ($k, $v) = (split /(?:,(-?\d+))$/, $s)[0, 1];
+ if (lc1459(as_uni($k)) eq lc1459($ent)) {
+ unless ($found) {
+ if ($data =~ /^(-?\d+)$/) {
+ $ent .= ",$1";
+ }
+ if (defined $v && 0 == abs $v) {
+ $win->print("Hiding window $ent");
+ }
+ push @setting, as_tc($ent);
+ $found = 1;
+ }
+ }
+ else {
+ push @setting, defined $v ? "$k,$v" : $k;
+ }
+ }
+ unless ($found) {
+ $win->print("Hiding window $ent");
+ if ($data =~ /^(-?\d+)$/) {
+ $ent .= ",$1";
+ }
+ push @setting, as_tc($ent);
+ }
+
+ if (@setting) {
+ Irssi::command("^set ".(set 'detach')." @setting");
+ } else {
+ Irssi::command("^set -clear ".(set 'detach'));
+ }
+}
+
+sub unhide_window {
+ my ($data, $server, $witem) = @_;
+ my $win = Irssi::active_win;
+ my $number = $win->{refnum};
+ my $name = as_uni($win->{name});
+ my $active = as_uni($win->get_active_name) // '';
+ my $tag = $win->{active} && $win->{active}{server} ? as_uni($win->{active}{server}{tag}) // '' : '';
+
+ my %detach_aht;
+ if ($S{detach_aht}) {
+ %detach_aht = (map { ( lc1459(as_uni($_)) => undef ) }
+ split ' ', Irssi::settings_get_str('activity_hide_targets'));
+ }
+ my @setting;
+ my @kills = (length $name ? $name : undef,
+ length $tag && length $active ? "$tag/$active" : undef,
+ length $active ? $active : undef,
+ $number);
+ my @was_unhidden = (0) x @kills;
+ for my $s (split ' ', $S{detach}) {
+ my ($k, $v) = (split /(?:,(-?\d+))$/, $s)[0, 1];
+ my $k2 = lc1459(as_uni($k));
+ my $kill;
+ for my $ki (0..$#kills) {
+ if (defined $kills[$ki] && $k2 eq lc1459($kills[$ki])) {
+ $kill = $ki;
+ }
+ }
+
+ if (defined $kill) {
+ if (defined $v && 0 == abs $v) {
+ $was_unhidden[$kill] = 1;
+ push @setting, defined $v ? "$k,$v" : $k;
+ } else {
+ $win->print("Unhiding window $kills[$kill]");
+ }
+ }
+ else {
+ push @setting, defined $v ? "$k,$v" : $k;
+ }
+ }
+ my @is_hidden = (defined $kills[0] && (exists $detach_map{"*"} || exists $detach_map{"::all"}),
+ defined $kills[1] && (exists $detach_map{lc1459("$tag/*")} || exists $detach_map{lc1459("$tag/::all")}
+ || exists $detach_map{"*"} || exists $detach_map{"::all"}),
+ defined $kills[2] && (exists $detach_map{"*"} || exists $detach_map{"::all"}),
+ (exists $detach_map{"*"} || exists $detach_map{"::all"})
+ );
+ for my $ki (1, 2, 0, 3) {
+ if ($is_hidden[$ki]) {
+ unless ($was_unhidden[$ki]) {
+ $win->print("Unhiding window $kills[$ki]");
+ push @setting, "$kills[$ki],0";
+ $was_unhidden[$ki] = 1;
+ }
+ last;
+ }
+ }
+ my @is_hidden_aht = (defined $kills[0] && (exists $detach_aht{lc1459($name)}
+ || exists $detach_aht{"*"} || exists $detach_aht{"::all"}),
+ defined $kills[1] && (exists $detach_aht{lc1459("$tag/$active")}
+ || exists $detach_aht{lc1459($active)}
+ || exists $detach_aht{lc1459("$tag/*")} || exists $detach_aht{lc1459("$tag/::all")}
+ || exists $detach_aht{"*"} || exists $detach_aht{"::all"}),
+ defined $kills[2] && (exists $detach_aht{lc1459($active)}
+ || exists $detach_aht{"*"} || exists $detach_aht{"::all"}),
+ (exists $detach_aht{$number} || exists $detach_aht{"*"} || exists $detach_aht{"::all"})
+ );
+ for my $ki (1, 2, 0, 3) {
+ if ($is_hidden_aht[$ki]) {
+ unless ($was_unhidden[$ki]) {
+ $win->print("Unhiding window $kills[$ki], it is hidden because ".(set 'detach_aht')." is ON");
+ push @setting, "$kills[$ki],0";
+ $was_unhidden[$ki] = 1;
+ }
+ last;
+ }
+ }
+
+ if (@setting) {
+ Irssi::command("^set ".(set 'detach')." @setting");
+ } else {
+ Irssi::command("^set -clear ".(set 'detach'));
+ }
+}
+
+sub ack_window {
+ my ($data, $server, $witem) = @_;
+ my $win = Irssi::active_win;
+ my $number = $win->{refnum};
+ if (grep { $_->{cmd} eq 'ack' } Irssi::commands) {
+ my $Orig_Irssi_windows = \&Irssi::windows;
+ local *Irssi::windows = sub () { grep { !_is_detached($_, $number) } $Orig_Irssi_windows->() };
+ Irssi::command("ack" . (length $data ? " $data" : ""));
+ } else {
+ my $ignore_refnum = Irssi::settings_get_bool('active_window_ignore_refnum');
+ my $max_win;
+ my $max_act = 0;
+ my $max_ref = 0;
+ for my $rec (Irssi::windows) {
+ next if _is_detached($rec, $number);
+
+ # ignore refnum
+ if ($ignore_refnum &&
+ $rec->{data_level} > 0 && $max_act < $rec->{data_level}) {
+ $max_act = $rec->{data_level};
+ $max_win = $rec;
+ }
+
+ # windows with lower refnums break ties
+ elsif (!$ignore_refnum &&
+ $rec->{data_level} > 0 &&
+ ($rec->{data_level} > $max_act ||
+ ($rec->{data_level} == $max_act && $rec->{refnum} < $max_ref))) {
+ $max_act = $rec->{data_level};
+ $max_win = $rec;
+ $max_ref = $rec->{refnum};
+ }
+ }
+ $max_win->set_active if defined $max_win;
+ }
+}
+
+sub refnum_changed {
+ my ($win, $old_refnum) = @_;
+ my @old_setting = split ' ', $S{detach};
+ my @setting = map {
+ my ($k, $v) = (split /(?:,(-?\d+))$/, $_)[0, 1];
+ if ($k eq $old_refnum) {
+ $win->{refnum} . (defined $v ? ",$v" : "")
+ }
+ else {
+ $_
+ }
+ } @old_setting;
+ if ("@old_setting" ne "@setting") {
+ $S{detach} = "@setting";
+ Irssi::settings_set_str(set 'detach', "@setting");
+ &setup_changed;
+ }
+ else {
+ &wl_changed;
+ }
+}
+
+sub window_destroyed {
+ my ($win) = @_;
+ my @old_setting = split ' ', $S{detach};
+ my @setting = grep {
+ my ($k, $v) = (split /(?:,(-?\d+))$/, $_)[0, 1];
+ if ($k eq $win->{refnum}) {
+ 0;
+ }
+ else {
+ 1;
+ }
+ } @old_setting;
+ if ("@old_setting" ne "@setting") {
+ $S{detach} = "@setting";
+ Irssi::settings_set_str(set 'detach', "@setting");
+ &setup_changed;
+ }
+ else {
+ &awins_changed;
+ }
+}
+
+sub stop_mouse_tracking {
+ print STDERR "\e[?1005l\e[?1000l";
+}
+sub start_mouse_tracking {
+ print STDERR "\e[?1000h\e[?1005h";
+}
+sub install_mouse {
+ Irssi::command_bind('mouse_xterm' => 'mouse_xterm');
+ Irssi::command('^bind meta-[M command mouse_xterm');
+ Irssi::signal_add_first('gui key pressed' => 'mouse_key_hook');
+ start_mouse_tracking();
+}
+sub uninstall_mouse {
+ stop_mouse_tracking();
+ Irssi::signal_remove('gui key pressed' => 'mouse_key_hook');
+ Irssi::command('^bind -delete meta-[M');
+ Irssi::command_unbind('mouse_xterm' => 'mouse_xterm');
+}
+
+sub awl_mouse_event {
+ return if $VIEWER_MODE;
+ if ((($_[0] == 3 and $_[3] == 0)
+ || $_[0] == 64 || $_[0] == 65) and
+ $_[1] == $_[4] and $_[2] == $_[5]) {
+ my $top = lc $S{placement} eq 'top';
+ my ($pos, $line) = @_[1 .. 2];
+ unless ($top) {
+ $line -= $screenHeight;
+ $line += $currentLines;
+ $line += $S{mouse_offset};
+ }
+ else {
+ $line -= $S{mouse_offset};
+ }
+ $pos -= $sb_base_width_pre;
+ return if $line < 0 || $line >= $currentLines;
+ if ($_[0] == 64) {
+ Irssi::command('window up');
+ }
+ elsif ($_[0] == 65) {
+ Irssi::command('window down');
+ }
+ elsif (exists $mouse_coords{$line}{$pos}) {
+ my $win = $mouse_coords{$line}{$pos};
+ Irssi::command('window ' . $win);
+ }
+ Irssi::signal_stop;
+ }
+}
+
+sub mouse_scroll_event {
+ return unless $S{mouse_scroll};
+ if (($_[3] == 64 or $_[3] == 65) and
+ $_[0] == $_[3] and $_[1] == $_[4] and $_[2] == $_[5]) {
+ my $cmd = 'scrollback goto ' . ($_[3] == 64 ? '-' : '+') . $S{mouse_scroll};
+ Irssi::active_win->command($cmd);
+ Irssi::signal_stop;
+ }
+ elsif ($_[0] == 64 or $_[0] == 65) {
+ Irssi::signal_stop;
+ }
+}
+
+sub mouse_escape {
+ return unless $S{mouse_escape} > 0;
+ if ($_[0] == 3) {
+ my $tm = $S{mouse_escape};
+ $tm *= 1000 if $tm < 1000;
+ stop_mouse_tracking();
+ Irssi::timeout_add_once($tm, 'start_mouse_tracking', undef);
+ Irssi::signal_stop;
+ }
+}
+
+sub UNLOAD {
+ @actString = ();
+ killOldStatus();
+ stop_viewer() if $VIEWER_MODE;
+ uninstall_mouse() if $MOUSE_ON;
+}
+
+sub addPrintTextHook { # update on print text
+ return unless defined $^S;
+ return if $BLOCK_ALL;
+ return unless $print_text_activity;
+ return if $_[0]->{level} == MSGLEVEL_CLIENTNOTICE and $_[0]->{target} eq ''
+ and !defined($_[0]->{server});
+ &wl_changed;
+}
+
+sub block_event_window_change {
+ Irssi::signal_stop;
+}
+
+sub update_awins {
+ my @wins = Irssi::windows;
+ local $BLOCK_ALL = 1;
+ Irssi::signal_add_first('window changed' => 'block_event_window_change');
+ my $bwin =
+ my $awin = Irssi::active_win;
+ my $lwin;
+ my $defer_irssi_broken_last;
+ unless ($wins[0]{refnum} == $awin->{refnum}) {
+ # special case: more than 1 last win, so /win last;
+ # /win last doesn't come back to the current window. eg. after
+ # connect & autojoin; we can't handle this situation, bail out
+ $defer_irssi_broken_last = 1;
+ }
+ else {
+ $awin->command('window last');
+ $lwin = Irssi::active_win;
+ $lwin->command('window last');
+ $defer_irssi_broken_last = $lwin->{refnum} == $bwin->{refnum};
+ }
+ my $awin_counter = 0;
+ Irssi::signal_remove('window changed' => 'block_event_window_change');
+ unless ($defer_irssi_broken_last) {
+ # we need to keep the fe-windows code running here
+ Irssi::signal_add_priority('window changed' => 'block_event_window_change', -99);
+ %awins = %wnmap_exp = ();
+ do {
+ Irssi::active_win->command('window up');
+ $awin = Irssi::active_win;
+ $awins{$awin->{refnum}} = undef;
+ ++$awin_counter;
+ } until ($awin->{refnum} == $bwin->{refnum} || $awin_counter >= @wins);
+ Irssi::signal_remove('window changed' => 'block_event_window_change');
+
+ Irssi::signal_add_first('window changed' => 'block_event_window_change');
+ for my $key (keys %wnmap) {
+ next unless Irssi::window_find_name($key) || Irssi::window_find_item($key);
+ $awin->command("window goto $key");
+ my $cwin = Irssi::active_win;
+ $wnmap_exp{ $cwin->{refnum} } = $wnmap{$key};
+ $cwin->command('window last')
+ if $cwin->{refnum} != $awin->{refnum};
+ }
+ for my $win (reverse @wins) { # restore original window order
+ Irssi::active_win->command('window '.$win->{refnum});
+ }
+ $awin->command('window '.$lwin->{refnum}); # restore last win
+ Irssi::active_win->command('window last');
+ Irssi::signal_remove('window changed' => 'block_event_window_change');
+ }
+ $CHANGED{WL} = 1;
+}
+
+sub resizeTerm {
+ if (defined (my $r = `stty size 2>/dev/null`)) {
+ ($screenHeight, $screenWidth) = split ' ', $r;
+ $CHANGED{SETUP} = 1;
+ }
+ else {
+ $CHANGED{SIZE} = 1;
+ }
+}
+
+sub awl_refresh {
+ $globTime = undef;
+ resizeTerm() if delete $CHANGED{SIZE};
+ reset_awl() if delete $CHANGED{SETUP};
+ update_awins() if delete $CHANGED{AWINS};
+ update_wl() if delete $CHANGED{WL};
+}
+
+sub termsize_changed { $CHANGED{SIZE} = 1; &queue_refresh; }
+sub setup_changed { $CHANGED{SETUP} = 1; &queue_refresh; }
+sub awins_changed { $CHANGED{AWINS} = 1; &queue_refresh; }
+sub wl_changed { $CHANGED{WL} = 1; &queue_refresh; }
+
+sub window_changed {
+ &awins_changed if $_[1];
+}
+
+sub queue_refresh {
+ return if $BLOCK_ALL;
+ Irssi::timeout_remove($globTime)
+ if defined $globTime; # delay the update further
+ $globTime = Irssi::timeout_add_once(GLOB_QUEUE_TIMER, 'awl_refresh', undef);
+}
+
+sub awl_init {
+ termsize_changed();
+ setup_changed();
+ update_keymap();
+ Irssi::timeout_remove($globTime)
+ if defined $globTime;
+ awl_refresh();
+ termsize_changed();
+}
+
+sub runsub {
+ my $cmd = shift;
+ sub {
+ my ($data, $server, $item) = @_;
+ Irssi::command_runsub($cmd, $data, $server, $item);
+ };
+}
+
+Irssi::signal_register({
+ 'gui mouse' => [qw/int int int int int int/],
+ });
+{ my $broken_expandos = (Irssi::version >= 20081128 && Irssi::version < 20110210)
+ ? sub { my $x = shift; $x =~ s/\$\{cumode_space\}/ /; $x } : undef;
+ Irssi::theme_register([
+ map { $broken_expandos ? $broken_expandos->($_) : $_ }
+ set 'display_nokey' => '$N${cumode_space}$H$C$S',
+ set 'display_key' => '$Q${cumode_space}$H$C$S',
+ set 'display_nokey_visible' => '%2$N${cumode_space}$H$C$S',
+ set 'display_key_visible' => '%2$Q${cumode_space}$H$C$S',
+ set 'display_nokey_active' => '%1$N${cumode_space}$H$C$S',
+ set 'display_key_active' => '%1$Q${cumode_space}$H$C$S',
+ set 'display_header' => '%8$C|${N}',
+ set 'name_display' => '$0',
+ set 'separator' => ' ',
+ set 'separator2' => '',
+ set 'abbrev_chars' => "~\x{301c}",
+ set 'viewer_item_bg' => sb_format_expand('{sb_background}'),
+ set 'title' => '\V'.setc().'\:',
+ ]);
+}
+Irssi::settings_add_bool(setc, set 'prefer_name', 0); #
+Irssi::settings_add_int( setc, set 'hide_empty', 0); #
+Irssi::settings_add_int( setc, set 'hide_data', 0); #
+Irssi::settings_add_str( setc, set 'detach', ''); #
+Irssi::settings_add_int( setc, set 'detach_data', -3); #
+Irssi::settings_add_bool(setc, set 'detach_aht', 0); #
+Irssi::settings_add_int( setc, set 'hide_name_data', 0); #
+Irssi::settings_add_int( setc, set 'maxlines', 9); #
+Irssi::settings_add_int( setc, set 'maxcolumns', 4); #
+Irssi::settings_add_int( setc, set 'block', 15); #
+Irssi::settings_add_bool(setc, set 'sbar_maxlength', 1); #
+Irssi::settings_add_int( setc, set 'height_adjust', 2); #
+Irssi::settings_add_str( setc, set 'sort', 'refnum'); #
+Irssi::settings_add_str( setc, set 'placement', 'bottom'); #
+Irssi::settings_add_int( setc, set 'position', 0); #
+Irssi::settings_add_bool(setc, set 'all_disable', 1); #
+Irssi::settings_add_bool(setc, set 'viewer', 1); #
+Irssi::settings_add_str( setc, set 'shared_sbar', 'OFF'); #
+Irssi::settings_add_bool(setc, set 'mouse', 0); #
+Irssi::settings_add_str( setc, set 'path', Irssi::get_irssi_dir . '/_windowlist'); #
+Irssi::settings_add_str( setc, set 'custom_xform', ''); #
+Irssi::settings_add_str( setc, set 'custom_key_re', 'f\d+'); #
+Irssi::settings_add_time(setc, set 'last_line_shade', '0'); #
+Irssi::settings_add_int( setc, set 'mouse_offset', 1); #
+Irssi::settings_add_int( setc, 'mouse_scroll', 3); #
+Irssi::settings_add_int( setc, 'mouse_escape', 1); #
+Irssi::settings_add_str( setc, 'banned_channels', '');
+Irssi::settings_add_bool(setc, 'banned_channels_on', 1);
+Irssi::settings_add_str( setc, 'fancy_abbrev', 'fancy'); #
+Irssi::settings_add_bool(setc, set 'no_mode_hint', 0); #
+Irssi::settings_add_bool(setc, set 'viewer_launch', 1); #
+Irssi::settings_add_str( setc, set 'viewer_launch_env', ''); #
+Irssi::settings_add_str( setc, set 'viewer_tmux_position', 'left'); #
+Irssi::settings_add_str( setc, set 'viewer_xwin_command', 'xterm +sb -e %A'); #
+Irssi::settings_add_str( setc, set 'viewer_custom_command', ''); #
+
+Irssi::signal_add_last({
+ 'setup changed' => 'setup_changed',
+ 'print text' => 'addPrintTextHook',
+ 'terminal resized' => 'termsize_changed',
+ 'setup reread' => 'screenFullRedraw',
+ 'window hilight' => 'wl_changed',
+ 'command format' => 'wl_changed',
+});
+Irssi::signal_add({
+ 'window changed' => 'window_changed',
+ 'window item changed' => 'wl_changed',
+ 'window changed automatic' => 'window_changed',
+ 'window created' => 'awins_changed',
+ 'window destroyed' => 'window_destroyed',
+ 'window name changed' => 'wl_changed',
+ 'window refnum changed' => 'refnum_changed',
+});
+Irssi::signal_add_last('gui mouse' => 'mouse_escape');
+Irssi::signal_add_last('gui mouse' => 'mouse_scroll_event');
+Irssi::signal_add_last('gui mouse' => 'awl_mouse_event');
+Irssi::command_bind( setc() => runsub(setc()) );
+Irssi::command_bind( setc() . ' redraw' => 'screenFullRedraw' );
+Irssi::command_bind( setc() . ' restart' => 'restartViewerServer' );
+Irssi::command_bind( setc() . ' attach' => 'unhide_window' );
+Irssi::command_bind( setc() . ' detach' => 'hide_window' );
+Irssi::command_bind( setc() . ' ack' => 'ack_window' );
+
+{
+ my $l = set 'shared';
+ {
+ no strict 'refs';
+ *{$l} = $awl_shared_empty;
+ }
+ Irssi::statusbar_item_register($l, '$0', $l);
+}
+
+awl_init();
+
+# Mouse script based on irssi mouse patch by mirage
+{ my $mouse_status = -1; # -1:off 0,1,2:filling mouse_combo
+ my @mouse_combo = (-1, -1, -1); # 0:button 1:x 2:y
+ my @mouse_previous = (-1, -1, -1); # previous contents of mouse_combo
+
+ sub mouse_xterm_off {
+ $mouse_status = -1;
+ }
+ sub mouse_xterm {
+ $mouse_status = 0;
+ Irssi::timeout_add_once(10, 'mouse_xterm_off', undef);
+ }
+
+ sub mouse_key_hook {
+ my ($key) = @_;
+ if ($mouse_status != -1) {
+ if ($mouse_status == 0) {
+ @mouse_previous = @mouse_combo;
+ #if @mouse_combo && $mouse_combo[0] < 64;
+ }
+ $mouse_combo[$mouse_status] = $key - 32;
+ $mouse_status++;
+ if ($mouse_status == 3) {
+ $mouse_status = -1;
+ # match screen coordinates
+ $mouse_combo[1]--;
+ $mouse_combo[2]--;
+ Irssi::signal_emit('gui mouse', @mouse_combo[0 .. 2], @mouse_previous[0 .. 2]);
+ }
+ Irssi::signal_stop;
+ }
+ }
+}
+
+sub string_LCSS {
+ my $str = join "\0", @_;
+ (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;
+ use warnings;
+ no warnings 'redefine';
+ use Encode;
+ use IO::Socket::UNIX;
+ use IO::Select;
+ use List::Util qw(max);
+ use constant BLOCK_SIZE => 1024;
+ use constant RECONNECT_TIME => 5;
+
+ my $sockpath;
+
+ our $VERSION = '0.8';
+
+ our ($got_int, $resized, $timeout);
+
+ my %vars;
+ my (%c2w, @seqlist);
+ my %mouse_coords;
+ my (@mouse, @last_mouse);
+ my ($err, $sock, $loop);
+ my ($keybuf, $rcvbuf);
+ my @screen;
+ my ($screenHeight, $screenWidth);
+ my ($disp_update, $fs_open, $one_shot_integration, $one_shot_resize);
+ my $integration_position;
+ my $show_title_bar;
+
+ sub connect_it {
+ $sock = IO::Socket::UNIX->new(
+ Type => SOCK_STREAM,
+ Peer => $sockpath,
+ );
+ unless ($sock) {
+ $err = $!;
+ return;
+ }
+ $sock->blocking(0);
+ $loop->add($sock);
+ }
+
+ sub remove_conn {
+ my $fh = shift;
+ $loop->remove($fh);
+ $fh->close;
+ $sock = undef;
+ %vars = ();
+ @screen = ();
+ }
+
+ { package Terminfo; # xterm
+ sub civis { "\e[?25l" }
+ sub sc { "\e7" }
+ sub cup { "\e[" . ($_[0] + 1) . ';' . ($_[1] + 1) . 'H' }
+ sub el { "\e[K" }
+ sub rc { "\e8" }
+ sub cnorm { "\e[?25h" }
+ sub setab { "\e[4" . $_[0] . 'm' }
+ sub setaf { "\e[3" . $_[0] . 'm' }
+ sub setaf16 { "\e[9" . $_[0] . 'm' }
+ sub setab16 { "\e[10" . $_[0] . 'm' }
+ sub setaf256 { "\e[38;5;" . $_[0] . 'm' }
+ sub setab256 { "\e[48;5;" . $_[0] . 'm' }
+ sub setafrgb { "\e[38;2;" . $_[0] . ';' . $_[1] . ';' . $_[2] . 'm' }
+ sub setabrgb { "\e[48;2;" . $_[0] . ';' . $_[1] . ';' . $_[2] . 'm' }
+ sub sgr0 { "\e[0m" }
+ sub bold { "\e[1m" }
+ sub it { "\e[3m" }
+ sub ul { "\e[4m" }
+ sub blink { "\e[5m" }
+ sub rev { "\e[7m" }
+ sub op { "\e[39;49m" }
+ sub exit_bold { "\e[22m" }
+ sub exit_it { "\e[23m" }
+ sub exit_ul { "\e[24m" }
+ sub exit_blink { "\e[25m" }
+ sub exit_rev { "\e[27m" }
+ sub smcup { "\e[?1049h" }
+ sub rmcup { "\e[?1049l" }
+ sub smmouse { "\e[?1000h\e[?1005h" }
+ sub rmmouse { "\e[?1005l\e[?1000l" }
+ }
+
+ sub init {
+ $sockpath = shift // "$ENV{HOME}/.irssi/_windowlist";
+ STDOUT->autoflush(1);
+ printf "\r%swaiting for %s...", Terminfo::sc, $::IRSSI{name};
+
+ `stty -icanon -echo`;
+
+ $loop = IO::Select->new;
+ STDIN->blocking(0);
+ $loop->add(\*STDIN);
+
+ $SIG{INT} = sub {
+ $got_int = 1
+ };
+ $SIG{WINCH} = sub {
+ $resized = 1
+ };
+
+ $resized = 3;
+
+ $disp_update = 2;
+
+ $show_title_bar = 1;
+ }
+
+ sub enter_fs {
+ return if $fs_open;
+ safe_print(Terminfo::rc, Terminfo::smcup, Terminfo::civis, Terminfo::smmouse);
+ $fs_open = 1;
+ }
+
+ sub leave_fs {
+ return unless $fs_open;
+ safe_print(Terminfo::rmmouse, Terminfo::cnorm, Terminfo::rmcup);
+ safe_print(sprintf "\r%swaiting for %s...", Terminfo::sc, $::IRSSI{name}) if $_[0];
+
+ $fs_open = 0;
+ }
+
+ sub end_prog {
+ leave_fs();
+ STDIN->blocking(1);
+ `stty sane`;
+ printf "\r%s%sthanks for using %s\n", Terminfo::rc, Terminfo::el, $::IRSSI{name};
+ }
+
+ sub safe_print {
+ my $st = STDIN->blocking(1);
+ print @_;
+ STDIN->blocking($st);
+ }
+
+ sub safe_qx {
+ my $st = STDIN->blocking(1);
+ my $ret = `$_[0]`;
+ STDIN->blocking($st);
+ $ret
+ }
+
+ sub safe_print_sock {
+ return unless $sock;
+ my $was = $sock->blocking(1);
+ $sock->print(@_);
+ $sock->blocking($was);
+ }
+
+ sub process_recv {
+ my $need = 0;
+ while ($rcvbuf =~ s/\n(.+)_BEGIN\n((?: .*\n)*)\1_END\n//) {
+ my $var = lc $1;
+ my $data = $2;
+ my @data = split "\n ", "\n$data ", -1;
+ shift @data; pop @data;
+ my $itembg = $vars{itembg};
+ if ($var =~ s/list$//) {
+ $vars{$var} = \@data;
+ }
+ elsif ($var =~ s/map$//) {
+ $vars{$var} = +{ @data };
+ }
+ else {
+ $vars{$var} = join "\n", @data;
+ }
+ $need = 1 if $var eq 'win';
+ $need = 1 if $var eq 'redraw' && $vars{$var};
+ if (($itembg//'') ne ($vars{itembg}//'')) {
+ $need = $vars{redraw} = 1;
+ }
+ _build_keymap() if $var eq 'key2';
+ }
+ $need
+ }
+
+ { my %ansi_table;
+ my ($i, $j, $k) = (0, 0, 0);
+ my %term_state;
+ sub reset_term_state { my %old_term = %term_state; %term_state = (); %old_term }
+ sub set_term_state { my %old_term = %term_state; %term_state = @_; %old_term }
+ %ansi_table = (
+ # fe-common::core::formats.c:format_expand_styles
+ (map { my $t = $i++; ($_ => sub { my $n = $term_state{hicolor} ? \&Terminfo::setab16 : \&Terminfo::setab;
+ $n->($t) }) } (split //, '01234567' )),
+ (map { my $t = $j++; ($_ => sub { my $n = $term_state{hicolor} ? \&Terminfo::setaf16 : \&Terminfo::setaf;
+ $n->($t) }) } (split //, 'krgybmcw' )),
+ (map { my $t = $k++; ($_ => sub { my $n = $term_state{hicolor} ? \&Terminfo::setaf : \&Terminfo::setaf16;
+ $n->($t) }) } (split //, 'KRGYBMCW')),
+ # reset
+ n => sub { $term_state{hicolor} = 0; my $r = Terminfo::op;
+ for (qw(blink rev bold)) {
+ $r .= Terminfo->can("exit_$_")->() if delete $term_state{$_};
+ }
+ {
+ local $ansi_table{n} = $ansi_table{N};
+ $r .= formats_to_ansi_basic($vars{itembg});
+ }
+ $r
+ },
+ N => sub { reset_term_state(); Terminfo::sgr0 },
+ # flash/bright
+ F => sub { my $n = 'blink'; my $e = ($term_state{$n} ^= 1) ? $n : "exit_$n"; Terminfo->can($e)->() },
+ # reverse
+ 8 => sub { my $n = 'rev'; my $e = ($term_state{$n} ^= 1) ? $n : "exit_$n"; Terminfo->can($e)->() },
+ # bold
+ "_" => sub { my $n = 'bold'; my $e = ($term_state{$n} ^= 1) ? $n : "exit_$n"; Terminfo->can($e)->() },
+ # underline
+ U => sub { my $n = 'ul'; my $e = ($term_state{$n} ^= 1) ? $n : "exit_$n"; Terminfo->can($e)->() },
+ # italic
+ I => sub { my $n = 'it'; my $e = ($term_state{$n} ^= 1) ? $n : "exit_$n"; Terminfo->can($e)->() },
+ # bold, used as colour modifier if AWL_HI9 is set
+ 9 => $ENV{AWL_HI9} ? sub { $term_state{hicolor} ^= 1; '' }
+ : sub { my $n = 'bold'; my $e = ($term_state{$n} ^= 1) ? $n : "exit_$n"; Terminfo->can($e)->() },
+ # delete other stuff
+ (map { $_ => sub { '' } } (split //, ':|>#[')),
+ # escape
+ (map { my $close = $_; $_ => sub { $close } } (split //, '{}%')),
+ );
+ for my $base (0 .. 15) {
+ my $close = $base;
+ my $idx = ($close&8) | ($close&4)>>2 | ($close&2) | ($close&1)<<2;
+ $ansi_table{ (sprintf "x0%x", $close) } =
+ $ansi_table{ (sprintf "x0%X", $close) } =
+ sub { Terminfo::setab256($idx) };
+ $ansi_table{ (sprintf "X0%x", $close) } =
+ $ansi_table{ (sprintf "X0%X", $close) } =
+ sub { Terminfo::setaf256($idx) };
+ }
+ for my $plane (1 .. 6) {
+ for my $coord (0 .. 35) {
+ my $close = 16 + ($plane-1) * 36 + $coord;
+ my $ch = $coord < 10 ? $coord : chr( $coord - 10 + ord 'a' );
+ $ansi_table{ "x$plane$ch" } =
+ $ansi_table{ "x$plane\U$ch" } =
+ sub { Terminfo::setab256($close) };
+ $ansi_table{ "X$plane$ch" } =
+ $ansi_table{ "X$plane\U$ch" } =
+ sub { Terminfo::setaf256($close) };
+ }
+ }
+ for my $gray (0 .. 23) {
+ my $close = 232 + $gray;
+ my $ch = chr( $gray + ord 'a' );
+ $ansi_table{ "x7$ch" } =
+ $ansi_table{ "x7\U$ch" } =
+ sub { Terminfo::setab256($close) };
+ $ansi_table{ "X7$ch" } =
+ $ansi_table{ "X7\U$ch" } =
+ sub { Terminfo::setaf256($close) };
+ }
+ # fe-windows.c:color_24bit_256
+ my $cc = sub {
+ use integer;
+
+ my $cstep_size = 40;
+ my $cstep_start = 0x5f;
+
+ my $gstep_size = 10;
+ my $gstep_start = 0x08;
+
+ my @dist = (0) x 3;
+ my @r; my @gr;
+
+ for (my $i = 0; $i < 3; ++$i) {
+ my $n = $_[$i];
+ $gr[$i] = -1;
+ if ($n < $cstep_start /2) {
+ $r[$i] = 0;
+ $dist[$i] = -$cstep_size/2;
+ }
+ else {
+ $r[$i] = 1+(($n-$cstep_start + $cstep_size /2)/$cstep_size);
+ $dist[$i] = (($n-$cstep_start + $cstep_size /2)% $cstep_size - $cstep_size/2);
+ }
+ if ($n < $gstep_start /2) {
+ $gr[$i] = -1;
+ }
+ else {
+ $gr[$i] = (($n-$gstep_start + $gstep_size /2)/$gstep_size);
+ }
+ }
+ if ($r[0] == $r[1] && $r[1] == $r[2] &&
+ 4*abs($dist[0]) < $gstep_size && 4*abs($dist[1]) < $gstep_size && 4*abs($dist[2]) < $gstep_size) {
+ # skip gray detection
+ }
+ else {
+ my $j = $r[1] == $r[2] ? 0 : 1;
+ if (($r[0] == $r[1] || $r[$j] == $r[2]) && abs($r[$j]-$r[($j+1)% 3]) <= 1) {
+ my $k = $gr[1] == $gr[2] ? 0 : 1;
+ if (($gr[0] == $gr[1] || $gr[$k] == $gr[2]) && abs($gr[$k]-$gr[($k+1)% 3]) <= 2) {
+ if ($gr[$k] < 0) {
+ $r[0] = $r[1] = $r[2] = 0;
+ }
+ elsif ($gr[$k] > 23) {
+ $r[0] = $r[1] = $r[2] = 5;
+ }
+ else {
+ $r[0] = 6;
+ $r[1] = ($gr[$k] / 6);
+ $r[2] = $gr[$k]% 6;
+ }
+ }
+ }
+ }
+ return 16 + $r[0]*36 + $r[1] * 6 + $r[2];
+ };
+ $ansi_table{z} = sub {
+ my ($r, $g, $b) = map { hex } unpack '(A2)*', $_[0];
+ $vars{tc} eq 'ON' ? Terminfo::setabrgb($r, $g, $b) : Terminfo::setab256($cc->($r, $g, $b));
+ };
+ $ansi_table{Z} = sub {
+ my ($r, $g, $b) = map { hex } unpack '(A2)*', $_[0];
+ $vars{tc} eq 'ON' ? Terminfo::setafrgb($r, $g, $b) : Terminfo::setaf256($cc->($r, $g, $b));
+ };
+ sub formats_to_ansi_basic {
+ my $o = shift;
+ $o =~ s{(%((Z|z)(......)|X..|x..|.))}{
+ if ($ansi_table{$2}) { $ansi_table{$2}->() }
+ elsif ($ansi_table{$3}) { $ansi_table{$3}->($4) }
+ else { $1 }
+ }gex;
+ $o
+ }
+ }
+
+ sub _header {
+ my $str = $vars{title} // uc ::setc();
+ my $ccs = qr/%(?:Z(?:[0-9A-F]{6})|X(?:[1-6][0-9A-Z]|7[A-X])|[0-9BCFGIKMNRUWY_])/i;
+ (my $stripstr = $str) =~ s/($ccs)//g;
+ my $space = int( ((abs $vars{block}) - length $stripstr) / (1 + length $stripstr));
+ if ($space > 0) {
+ my $ss = ' ' x $space;
+ my @x = $str =~ /((?:$ccs)*\X(?:(?:$ccs)*$)?)/g;
+ $str = join $ss, '', @x, '';
+ }
+ ($stripstr = $str) =~ s/($ccs)//g;
+ my $pad = max 0, (abs $vars{block}) - length $stripstr;
+ $str = ' ' x ($pad/2) . $str . ' ' x ($pad/2 + $pad%2);
+ $str
+ }
+
+ sub _add_item {
+ my ($i, $j, $c, $wi, $screen, $mouse) = @_;
+ $screen->[$i][$j] = "%N%n$wi";
+ if (exists $vars{mouse}{$c - 1}) {
+ $mouse->[$i][$j] = $vars{mouse}{$c - 1};
+ }
+ }
+ sub update_screen {
+ $disp_update = 0;
+ unless ($sock && exists $vars{seplen} && exists $vars{block}) {
+ leave_fs(1);
+ return;
+ }
+ enter_fs();
+ @screen = () if delete $vars{redraw};
+ %mouse_coords = ();
+ my $ncols = ($vars{seplen} + abs $vars{block}) ?
+ int( ($screenWidth + $vars{seplen}) / ($vars{seplen} + abs $vars{block}) ) : 0;
+ my $xenl = ($vars{seplen} + abs $vars{block})
+ && $ncols > int( ($screenWidth + $vars{seplen} - 1) / ($vars{seplen} + abs $vars{block}) );
+ my $nrows = $screenHeight - $vars{ha};
+ my @wi = @{$vars{win}//[]};
+ my $max_items = $ncols * $nrows;
+ my $c = $show_title_bar ? 1 : 0;
+ my $items = @wi + $c;
+ my $titems = $items > $max_items ? $max_items : $items;
+ my $i = 0;
+ my $j = 0;
+ my @new_screen;
+ my @new_mouse;
+ $new_screen[0][0] = _header() #. ' ' x $vars{seplen}
+ if $show_title_bar;
+ unless ($nrows > $ncols) { # line layout
+ ++$j if $show_title_bar;
+ for my $wi (@wi) {
+ if ($j >= $ncols) {
+ $j = 0;
+ ++$i;
+ }
+ last if $i >= $nrows;
+ _add_item($i, $j, $show_title_bar ? $c : $c + 1,
+ $wi, \@new_screen, \@new_mouse);
+ if ($c + 1 < $titems && $j + 1 < $ncols) {
+ $new_screen[$i][$j] .= $vars{separator};
+ }
+ ++$j;
+ ++$c;
+ }
+ }
+ else { # column layout
+ ++$i if $show_title_bar;
+ for my $wi (@wi) {
+ if ($i >= $nrows) {
+ $i = 0;
+ ++$j;
+ }
+ last if $j >= $ncols;
+ _add_item($i, $j, $show_title_bar ? $c : $c + 1,
+ $wi, \@new_screen, \@new_mouse);
+ if ($c + $nrows < $titems) {
+ $new_screen[$i][$j] .= $vars{separator};
+ }
+ ++$i;
+ ++$c;
+ }
+ }
+ my $step = $vars{seplen} + abs $vars{block};
+ $i = 0;
+ my $str = Terminfo::sc . Terminfo::sgr0;
+ for (my $i = 0; $i < @new_screen; ++$i) {
+ for (my $j = 0; $j < @{$new_screen[$i]}; ++$j) {
+ if (defined $new_mouse[$i] && defined $new_mouse[$i][$j]) {
+ my $from = $j * $step;
+ $mouse_coords{$i}{$_} = $new_mouse[$i][$j]
+ for $from .. $from + abs $vars{block};
+ }
+ next if defined $screen[$i] && defined $screen[$i][$j]
+ && $screen[$i][$j] eq $new_screen[$i][$j];
+ $str .= Terminfo::cup($i, $j * $step)
+ . formats_to_ansi_basic($new_screen[$i][$j])
+ . Terminfo::sgr0;
+ $str .= Terminfo::el if $j == $#{$new_screen[$i]} && (!$xenl || $j + 1 != $ncols);
+ }
+ }
+ for (@new_screen .. $screenHeight - 1) {
+ if (!@screen || defined $screen[$_]) {
+ $str .= Terminfo::cup($_, 0) . Terminfo::sgr0 . Terminfo::el;
+ }
+ }
+ $str .= Terminfo::rc;
+ safe_print $str;
+ @screen = @new_screen;
+ }
+
+ sub handle_resize {
+ if (defined (my $r = safe_qx('stty size'))) {
+ ($screenHeight, $screenWidth) = split ' ', $r;
+ $resized = 0;
+ @screen = ();
+ $disp_update = 1;
+ if ($one_shot_integration == 2) {
+ $one_shot_resize--;
+ }
+ }
+ else {
+ }
+ }
+
+ sub _build_keymap {
+ %c2w = reverse( %{$vars{key}}, %{$vars{key2}} );
+ if (!grep { /^[+-]./ } keys %c2w) {
+ %c2w = (%c2w, map { ("-$_" => $c2w{$_}) } grep { !/^\^./ } keys %c2w);
+ }
+ %c2w = map {
+ my $key = $_;
+ s{^(-)?(\+)?(\^)?(.)}{
+ join '', (
+ ($1 ? "\e" : ''),
+ ($2 ? "\e\e" : ''),
+ ($3 ? "$4"^"@" : $4)
+ )
+ }e;
+ $_ => $c2w{$key}
+ } keys %c2w;
+ @seqlist = sort { length $b <=> length $a } keys %c2w;
+ }
+
+ sub _match_tmux {
+ length $ENV{TMUX} && exists $vars{irssienv}{tmux_srv} && length $vars{irssienv}{tmux_pane}
+ && $ENV{TMUX} eq $vars{irssienv}{tmux_srv}
+ }
+
+ sub process_keys {
+ Encode::_utf8_on($keybuf);
+ my $win;
+ my $use_mouse;
+ my $maybe;
+ KEY: while (length $keybuf && !$maybe) {
+ $maybe = 0;
+ if ($keybuf =~ s/^\e\[M(.)(.)(.)//) {
+ @last_mouse = @mouse;# if @mouse && $mouse[0] < 64;
+ @mouse = map { -32 + ord } ($1, $2, $3);
+ $use_mouse = 1;
+ next KEY;
+ }
+ for my $s (@seqlist) {
+ if ($keybuf =~ s/^\Q$s//) {
+ $win = $c2w{$s};
+ $use_mouse = 0;
+ next KEY;
+ }
+ elsif (length $keybuf < length $s && $s =~ /^\Q$keybuf/) {
+ $maybe = 1;
+ }
+ }
+ unless ($maybe) {
+ substr $keybuf, 0, 1, '';
+ }
+ }
+ if ($use_mouse && @mouse && @last_mouse &&
+ $mouse[2] == $last_mouse[2] &&
+ $mouse[1] == $last_mouse[1] &&
+ ($mouse[0] == 3 || $mouse[0] == 64 || $mouse[0] == 65)) {
+ if ($mouse[0] == 64) {
+ $win = 'up';
+ }
+ elsif ($mouse[0] == 65) {
+ $win = 'down';
+ }
+ elsif (exists $mouse_coords{$mouse[2] - 1}{$mouse[1] - 1}) {
+ $win = $mouse_coords{$mouse[2] - 1}{$mouse[1] - 1};
+ }
+ elsif ($mouse[2] == 1 && $mouse[1] <= abs $vars{block}) {
+ $win = $last_mouse[0] != 0 ? 'last' : 'active';
+ }
+ else {
+ }
+ }
+ if (defined $win) {
+ $win =~ s/^_//;
+ safe_print_sock("$win\n");
+ if (!exists $ENV{AWL_AUTOFOCUS} || $ENV{AWL_AUTOFOCUS}) {
+ if (_match_tmux()) {
+ safe_qx("tmux selectp -t $vars{irssienv}{tmux_pane} 2>&1");
+ }
+ elsif (exists $vars{irssienv}{xwinid}) {
+ safe_qx("wmctrl -ia $vars{irssienv}{xwinid} 2>/dev/null");
+ }
+ }
+ }
+ Encode::_utf8_off($keybuf);
+ }
+
+ sub check_integration {
+ return unless $vars{irssienv};
+ return unless $sock && exists $vars{seplen} && exists $vars{block};
+ if ($one_shot_integration == 1) {
+ my $nrows = $screenHeight - $vars{ha};
+ my $ncols = ($vars{seplen} + abs $vars{block}) ? int( ($screenWidth + $vars{seplen}) / ($vars{seplen} + abs $vars{block}) ) : 0;
+ my $items = ($show_title_bar ? 1 : 0) + @{$vars{win}//[]};
+ my $dcols_required = $nrows ? int($items/$nrows) + !!($items%$nrows) : 0;
+ my $rows_required = $ncols ? int($items/$ncols) + !!($items%$ncols) : 0;
+ $rows_required = abs $vars{ml}
+ if ($vars{ml} < 0 || ($vars{ml} > 0 && $rows_required > $vars{ml}));
+ $dcols_required = abs $vars{mc}
+ if ($vars{mc} < 0 || ($vars{mc} > 0 && $dcols_required > $vars{mc}));
+ my $rows = $rows_required + $vars{ha};
+ my $cols = ($dcols_required * ($vars{seplen} + abs $vars{block})) - $vars{seplen};
+ if (_match_tmux()) {
+ # int( ($screenWidth + $vars{seplen}) / ($vars{seplen} + abs $vars{block}) );
+ my ($pos_flag, $before);
+ if ($integration_position eq 'left') {
+ $pos_flag = 'h';
+ $before = 1;
+ }
+ elsif ($integration_position eq 'top') {
+ $pos_flag = 'v';
+ $before = 1;
+ }
+ elsif ($integration_position eq 'right') {
+ $pos_flag = 'h';
+ }
+ else {
+ $pos_flag = 'v';
+ }
+ my @cmd = "joinp -d$pos_flag -s $ENV{TMUX_PANE} -t $vars{irssienv}{tmux_pane}";
+ push @cmd, "swapp -d -t $ENV{TMUX_PANE} -s $vars{irssienv}{tmux_pane}"
+ if $before;
+ $cols = max($cols, 2);
+ $rows = max($rows, 2);
+
+ safe_qx("tmux " . (join " \\\; ", @cmd) . " 2>&1");
+ }
+ else {
+ $resized = 1;
+ #safe_qx("resize -s $screenHeight $cols 2>&1")
+ # if $cols > 0;
+ }
+ $one_shot_integration++;
+ if ($resized == 1) {
+ handle_resize();
+ resize_integration();
+ }
+ }
+ elsif ($one_shot_integration == 2) {
+ resize_integration(1);
+ }
+ }
+
+ sub resize_integration {
+ return unless $one_shot_integration;
+ return unless ($one_shot_resize//0) < 0 || shift;
+ return if ($one_shot_resize//0) > 0;
+
+ my $nrows = $screenHeight - $vars{ha};
+ my $ncols = ($vars{seplen} + abs $vars{block}) ? int( ($screenWidth + $vars{seplen}) / ($vars{seplen} + abs $vars{block}) ) : 0;
+ my $items = ($show_title_bar ? 1 : 0) + @{$vars{win}//[]};
+ my $dcols_required = $nrows ? (int($items/$nrows) + !!($items%$nrows)) : 0;
+ my $rows_required = $ncols ? int($items/$ncols) + !!($items%$ncols) : 0;
+ $rows_required = abs $vars{ml}
+ if ($vars{ml} < 0 || ($vars{ml} > 0 && $rows_required > $vars{ml}));
+ $dcols_required = abs $vars{mc}
+ if ($vars{mc} < 0 || ($vars{mc} > 0 && $dcols_required > $vars{mc}));
+ my $rows = $rows_required + $vars{ha};
+ my $cols = ($dcols_required * ($vars{seplen} + abs $vars{block})) - $vars{seplen};
+ if (_match_tmux()) {
+ my $pos_flag;
+ my $before = 0;
+ if ($integration_position eq 'left') {
+ $pos_flag = 'h';
+ $before = 1;
+ }
+ elsif ($integration_position eq 'top') {
+ $pos_flag = 'v';
+ $before = 1;
+ }
+ elsif ($integration_position eq 'right') {
+ $pos_flag = 'h';
+ }
+ else {
+ $pos_flag = 'v';
+ }
+ my @cmd;
+ # hard tmux limits
+ $cols = max($cols, 2);
+ $rows = max($rows, 2);
+ if ($pos_flag eq 'h' && $cols != $screenWidth) {
+ my $change = $screenWidth - $cols;
+ my $dir = ($before ^ ($change<0)) ? 'L' : 'R';
+ push @cmd, "resizep -$dir -t $ENV{TMUX_PANE} @{[abs $change]}";
+ #push @cmd, "resizep -x $cols -t $ENV{TMUX_PANE}";
+ $one_shot_resize = 1;
+ }
+ if ($pos_flag eq 'v' && $rows != $screenHeight) {
+ #push @cmd, "resizep -y $rows -t $ENV{TMUX_PANE}";
+ my $change = $screenHeight - $rows;
+ my $dir = ($before ^ ($change<0)) ? 'U' : 'D';
+ push @cmd, "resizep -$dir -t $ENV{TMUX_PANE} @{[abs $change]}";
+ $one_shot_resize = 1;
+ }
+
+ safe_qx("tmux " . (join " \\\; ", @cmd) . " 2>&1")
+ if @cmd;
+ }
+ else {
+ $cols = max($cols, 1);
+ $rows = max($rows, 1);
+ unless ($nrows > $ncols) { # line layout
+ if ($rows != $screenHeight) {
+ safe_qx("resize -s $rows $screenWidth 2>&1");
+ $one_shot_resize = 1;
+ }
+ }
+ else {
+ if ($cols != $screenWidth) {
+ safe_qx("resize -s $screenHeight $cols 2>&1");
+ $one_shot_resize = 1;
+ }
+ }
+ }
+ if ($resized == 1) {
+ handle_resize();
+ }
+ }
+
+ sub init_integration {
+ return unless $one_shot_integration;
+ if (_match_tmux()) {
+ }
+ else {
+ }
+ safe_print("\e]2;".(uc ::setc())."\e\\");
+ }
+
+ sub main {
+ require Getopt::Std;
+ my %opts;
+ Getopt::Std::getopts('1p:', \%opts);
+ my $one_shot = $opts{1};
+ $integration_position = $opts{p};
+ $one_shot_integration = 0+!!$one_shot;
+ #shift if @_ && $_[0] eq '--';
+ &init;
+ $show_title_bar = 0 if $ENV{AWL_NOTITLE};
+ init_integration();
+ until ($got_int) {
+ $timeout = undef;
+ if ($resized) {
+ if ($resized == 1) {
+ $timeout = 1;
+ $resized++;
+ }
+ else {
+ handle_resize();
+ resize_integration();
+ }
+ }
+ unless ($sock || $timeout) {
+ connect_it();
+ }
+ $timeout ||= RECONNECT_TIME unless $sock;
+ update_screen() if $disp_update;
+ SELECT: while (my @read = $loop->can_read($timeout)) {
+ for my $fh (@read) {
+ if ($fh == \*STDIN) {
+ if (read STDIN, my $buf, BLOCK_SIZE) {
+ do {
+ $keybuf .= $buf;
+ } while read STDIN, $buf, BLOCK_SIZE;
+ }
+ else {
+ $got_int = 1;
+ last SELECT;
+ }
+ }
+ else {
+ if ($fh->read(my $buf, BLOCK_SIZE)) {
+ do {
+ $rcvbuf .= $buf;
+ } while $fh->read($buf, BLOCK_SIZE);
+ }
+ else {
+ $disp_update = 1;
+ remove_conn($fh);
+ if ($one_shot) {
+ $got_int = 1;
+ last SELECT;
+ }
+ $timeout ||= RECONNECT_TIME;
+ }
+ }
+ }
+ $disp_update |= process_recv() if length $rcvbuf;
+ process_keys() if length $keybuf;
+ check_integration() if $one_shot;
+ update_screen() if $disp_update;
+ }
+ continue {
+ }
+ }
+ end_prog();
+ }
+}
+
+1;
+
+# Changelog
+# =========
+# 1.11
+# - fix compat with Irssi 1.4
+#
+# 1.10
+# - add /set awl_custom_key_re, to display custom keys in the $Q
+# expando. requested by madduck
+#
+# 1.9.1
+# - fix crash on mouse click
+#
+# 1.9
+# - add %Z support to viewer
+#
+# 1.8
+# - use string_width in Irssi 1.2.0
+#
+# 1.7
+# - fix crash on invalid /set awl_sort, introduced in 1.6, reported by
+# tpetazzoni
+# - delay viewer initialisation
+# - improve race condition on tmux resize integration
+#
+# 1.6
+# - add detach setting to hide windows
+# - fix race condition when loading the script, reported by madduck
+# - improve compatibility with irssi 1.2
+# - add special value lru to awl_sort to sort windows by usage
+#
+# 1.5
+# - improve compat. with sideways splits
+#
+# 1.4
+# - fix line wrapping in some themes, reported by justanotherbody
+# - fix named window key detection, reported by madduck
+# - make title (in viewer and shared_sbar) configurable
+#
+# 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
+#
+# 1.0
+# - new awl_viewer_launch setting and an array of related settings
+# - fixed regression bug /exec -interactive
+# - fixed some warnings in perl 5.10 reported by kl3
+# - workaround for crash due to infinite recursion in irssi's Perl
+# error handling
+#
+# 0.9
+# - fix endless loop in awin detection code!
+# - correct colour swap in awl_viewer
+# - fix passing of alternate socket path to the viewer
+# - potential undefinedness in mouse refnum hinted at by Canopus
+# - fixed regression bug /exec -interactive
+# - add case-insensitive modifier to awl_sort
+# - run custom_xform on awl_prefer_name also
+# - avoid inconsistent active window state after awin detection
+# reported by ss
+# - revert %9-hack in the viewer prompted by discussion with pierrot
+# - fix new warning in perl 5.22
+#
+# 0.8
+# - replace fifo mode with external viewer script
+# - remove bundled cpan modules
+# - work around bogus irssi warning
+# - improve mouse support
+# - workaround for broken cumode in irssi 0.8.15
+# - fix handling of non-meta windows (uninitialized warning)
+# - add 256 colour support, strip true colour codes
+# - fix totally bogus $N padding reported by Ed S.
+# - make /window goto #name mappings work but ignore non-existant ones
+# - improve incomplete reads reported by bcode
+# - fix single % in awl_viewer reported by bcode
+# - add support for key bindings by nike and ferret
+# - coerce utf8 key binds
+# - add settings: custom_xform, last_line_shade, hide_name_data
+# - abbreviations were broken in some cases
+# - fix some misuse of / as cmdchar in mouse script reported by bcode
+# - add shared status bar mode
+# - ${type} variables for custom_xform setting
+# - crash if custom_xform had runtime error
+# - update sorting documentation
+# - fix odd case in size calculation noted by lasers
+# - add missing font styles to the viewer reported by ishanyx
+# - add italic
+#
+# 0.7g
+# - remove screen support and replace it with fifo support
+# - add double-width support to the shortener
+# - correct documentation regarding $T vs. display_header
+# - add missing refresh for window item changed (thanks vague)
+# - add visible windows
+# - add exemptions for active window
+# - workaround for hiding the window changes from trackbar
+# - hack to force 16colours in screen mode
+# - remember last window (reported by earthnative)
+# - wrong window focus on new queries (reported by emsid)
+# - dataloss bug on trying to remember last window
+#
+# 0.6d+
+# - add support for network headers
+# - fixed regression bug /exec -interactive
+#
+# 0.6ca+
+# - add screen support (from nicklist.pl)
+# - names can now have a max length and window names can be used
+# - fixed a bug with block display in screen mode and status bar mode
+# - added space handling to ir_fe and removed it again
+# - now handling formats on my own
+# - started to work on $tag display
+# - added warning about missing sb_act_none abstract leading to
+# - display*active settings
+# - added warning about the bug in awl_display_(no)key_active settings
+# - mouse hack
+#
+# 0.5d
+# - add setting to also hide the last status bar if empty (awl_all_disable)
+# - reverted to old utf8 code to also calculate broken utf8 length correctly
+# - simplified dealing with status bars in wlreset
+# - added a little tweak for the renamed term_type somewhere after Irssi 0.8.9
+# - fixed bug in handling channel #$$
+# - reset background colour at the beginning of an entry
+#
+# 0.4d
+# - fixed order of disabling status bars
+# - several attempts at special chars, without any real success
+# and much more weird new bugs caused by this
+# - setting to specify sort order
+# - reduced timeout values
+# - added awl_hide_data
+# - make it so the dynamic sub is actually deleted
+# - fix a bug with removing of the last separator
+# - take into consideration parse_special
+#
+# 0.3b
+# - automatically kill old status bars
+# - reset on /reload
+# - position/placement settings
+#
+# 0.2
+# - automated retrieval of key bindings (thanks grep.pl authors)
+# - improved removing of status bars
+# - got rid of status chop
+#
+# 0.1
+# - Based on chanact.pl which was apparently based on lightbar.c and
+# nicklist.pl with various other ideas from random scripts.
diff --git a/scripts/ai.pl b/scripts/ai.pl
new file mode 100644
index 0000000..af3e5c1
--- /dev/null
+++ b/scripts/ai.pl
@@ -0,0 +1,265 @@
+use strict;
+use Irssi;
+use Irssi::Irc;
+
+use vars qw($VERSION %IRSSI);
+
+$VERSION="0.3";
+%IRSSI = (
+ authors=> 'BC-bd',
+ contact=> 'bd@bc-bd.org',
+ name=> 'ai',
+ description=> 'Puts people on ignore if they do a public away. See source for options.',
+ license=> 'GPL v2',
+ url=> 'https://bc-bd.org/svn/repos/irssi/trunk/',
+);
+
+# $Id: ai.pl,v 1.4 2002/06/02 15:20:03 bd Exp $
+# for irssi 0.8.4 by bd@bc-bd.org
+#
+#########
+# USAGE
+###
+#
+# Examples:
+#
+# Ignore people saying "away"
+# /set ai_words away
+#
+# Ignore people saying "gone for good" or "back"
+# /set ai_words gone for good,back
+#
+# Ignore people for 500 seconds
+# /set ai_time 500
+#
+# Ignore people forever
+# /set ai_time 0
+#
+# Ignore people only on channels #foo,#bar
+# /set ai_ignore_only_in ON
+# /set ai_channels #foo,#bar
+#
+# Ignore people on all channels BUT #foo,#bar
+# /set ai_ignore_only_in OFF
+# /set ai_channels #foo,#bar
+#
+# Ignore people on all channels
+# /set ai_ignore_only_in OFF
+# /set -clear ai_channels
+#
+# Perform a command on ignore (e.g send them a message)
+# /set ai_command ^msg -$C $N no "$W" in $T please
+#
+# would become on #foo on chatnet bar from nick dude with "dude is away"
+# /msg -cbar dude no "away" in #foo please
+#
+# look further down for details
+#
+# Per channel command on #irssi:
+# /ai #irssi ^say foobar
+#
+# delete channel command in #irssi:
+# /ai #irssi
+#
+#########
+# OPTIONS
+#########
+#
+# /set ai_words [expr[,]+]+
+# * expr : comma seperated list of expressions that should trigger an ignore
+# e.g. : away,foo,bar baz bat,bam
+#
+# /set ai_command [command]
+# * command : to be executed on a triggered ignore.
+# /set -clear ai_command to disable. The following $'s are expanded
+# ( see the default command for an example ):
+# $C : Chatnet (e.g. IRCnet, DALNet, ...)
+# $N : Nick (some dude)
+# $W : Word (the word(s) that triggered the ignore
+# $T : Target (e.g. the channel)
+#
+# /set ai_channels [#channel[ ]]+
+# * #channel : space seperated list of channels, see ai_ignore_only_in
+#
+# /set ai_time <seconds>
+# * seconds : number of seconds to wait before removing the ignore
+#
+# /set ai_ignore_only_in <ON|OFF>
+# * ON : only trigger ignores in ai_channels
+# * OFF : trigger ignores in all channels EXCEPT ai_channels
+#
+# /set ai_display <ON|OFF>
+# * ON : log whole sentence
+# * OFF : only log word that matched regex
+#
+###
+################
+###
+#
+# Changelog
+#
+# Version 0.4
+# - added optional sentence output
+#
+# Version 0.3
+# - added per channel command support
+# - the command is now executed in the channel the event occured
+# - changed the expand char from % to $
+#
+# Version 0.2
+# - changed MSGLVL_ALL to MSGLVL_ACTIONS to avoid problems
+# with channels with ignored Levels
+#
+# Version 0.1
+# - initial release
+#
+###
+################
+
+sub expand {
+ my ($string, %format) = @_;
+ my ($exp, $repl);
+ $string =~ s/\$$exp/$repl/g while (($exp, $repl) = each(%format));
+ return $string;
+}
+
+sub combineSettings {
+ my ($setting,$string,$match) = @_;
+
+ $match = quotemeta($match);
+
+ if ($setting) {
+ if ($string !~ /$match\b/i) {
+ return 1;
+ }
+ } else {
+ if ($string =~ /$match\b/i) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+sub sig_action {
+ my ($server,$msg,$nick,$address,$target) = @_;
+
+ my $command;
+
+ if ($server->ignore_check($nick, $address, $target, $msg, MSGLEVEL_ACTIONS)) {
+ return;
+ }
+
+ if (combineSettings(Irssi::settings_get_bool('ai_ignore_only_in'),
+ Irssi::settings_get_str('ai_channels'),$target)) {
+ return ;
+ }
+
+ my @words = split(',',Irssi::settings_get_str('ai_words'));
+
+ foreach (@words) {
+ if ($msg =~ /$_/i) {
+ my $word = $_;
+
+ my $sentence = $word;
+
+ my $channel = $server->channel_find($target);
+ my $n = $channel->nick_find($nick);
+
+ my $type = Irssi::Irc::MASK_USER | Irssi::Irc::MASK_DOMAIN;
+ my $mask = Irssi::Irc::get_mask($n->{nick}, $n->{host}, $type);
+
+ my $time = Irssi::settings_get_int('ai_time');
+ if ($time == 0) {
+ $time = "";
+ } else {
+ $time = "-time ".$time;
+ }
+ Irssi::command("^ignore ".$time." $mask");
+
+ if (Irssi::settings_get_bool('ai_display')) {
+ $sentence = $msg
+ }
+ Irssi::print("Ignoring $nick$target\@$server->{chatnet} because of '$sentence'");
+
+ my %commands = stringToHash('`',Irssi::settings_get_str('ai_commands'));
+ if (defined $commands{$target}) {
+ $command = $commands{$target};
+ } else {
+ $command = Irssi::settings_get_str('ai_command');
+ }
+
+ if ($command ne "") {
+ $command = expand($command,"C",$server->{tag},"N",$nick,"T",$target,"W",$word);
+ $server->window_item_find($target)->command($command);
+ $server->window_item_find($target)->print($command);
+ }
+
+ return;
+ }
+ }
+}
+
+sub stringToHash {
+ my ($delim,$str) = @_;
+
+ return split($delim,$str);
+}
+
+sub hashToString {
+ my ($delim,%hash) = @_;
+
+ return join($delim,%hash);
+}
+
+sub colorCommand {
+ my ($com) = @_;
+
+ $com =~ s/\$(.)/%_\$$1%_/g;
+
+ return $com;
+}
+
+sub cmd_ai {
+ my ($data, $server, $channel) = @_;
+
+ my $chan = $data;
+ $chan =~ s/ .*//;
+ $data =~ s/^\Q$chan\E *//;
+
+ my %command = stringToHash('`',Irssi::settings_get_str('ai_commands'));
+
+ if ($chan eq "") {
+ foreach my $key (keys(%command)) {
+ Irssi::print("AI: %_$key%_ = ".colorCommand($command{$key}));
+ }
+
+ Irssi::print("AI: placeholders: %_\$C%_)hatnet %_\$N%_)ick %_\$W%_)ord %_\$T%_)arget");
+ Irssi::print("AI: not enough parameters: ai <channel> [command]");
+
+ return;
+ }
+
+ if ($data eq "") {
+ delete($command{$chan});
+ } else {
+ $command{$chan} = $data;
+ }
+
+ Irssi::settings_set_str('ai_commands',hashToString('`',%command));
+
+ Irssi::print("AI: command on %_$chan%_ now: '".colorCommand($data)."'");
+}
+
+Irssi::command_bind('ai', 'cmd_ai');
+
+# "message irc action", SERVER_REC, char *msg, char *nick, char *address, char *target
+Irssi::signal_add_first('message irc action', 'sig_action');
+
+Irssi::settings_add_str('misc', 'ai_commands', '');
+Irssi::settings_add_str('misc', 'ai_words', 'away,gone,ist auf');
+Irssi::settings_add_str('misc', 'ai_command', '^msg -$C $N no "$W" in $T please');
+Irssi::settings_add_str('misc', 'ai_channels', '');
+Irssi::settings_add_int('misc', 'ai_time', 500);
+Irssi::settings_add_bool('misc', 'ai_ignore_only_in', 0);
+Irssi::settings_add_bool('misc', 'ai_display', 0);
diff --git a/scripts/aidle.pl b/scripts/aidle.pl
new file mode 100644
index 0000000..93c30ee
--- /dev/null
+++ b/scripts/aidle.pl
@@ -0,0 +1,80 @@
+use strict;
+use Irssi 20020300;
+use Irssi::Irc;
+
+# /SET aidle_max_idle_time <seconds>
+# - specifies max possible idle time
+# /SET aidle_ircnets IRCNet EFnet
+# - specifies IRCNets where anty idler will be on
+# SET -clear aidle_ircnets makes aidle work on every network;
+# /SET aidle_only_when_away - makes aidler work only when you're away
+
+use vars qw($VERSION %IRSSI);
+$VERSION = "1.1b";
+%IRSSI = (
+ authors => "Maciek \'fahren\' Freudenheim",
+ contact => "fahren\@bochnia.pl",
+ name => "Antyidler",
+ description => "Antyidler with random time",
+ license => "GNU GPLv2 or later",
+ changed => "Thu Jan 2 02:58:34 CET 2003"
+);
+
+# Changelog:
+# 1.1b
+# - removed "hoho, <chatnet>" message :)
+# 1.1
+# - added /set'tings
+# 1.0
+# - fixed that annoying "your_nick: is away blah blah" message
+
+my %aidle;
+
+Irssi::settings_add_int 'aidle', 'aidle_max_idle_time', '180';
+$aidle{'max'} = Irssi::settings_get_int 'aidle_max_idle_time';
+
+Irssi::settings_add_str 'aidle', 'aidle_ircnets', '';
+@{$aidle{'ircnets'}} = (split(/ +/, Irssi::settings_get_str('aidle_ircnets')));
+
+Irssi::settings_add_bool 'aidle', 'aidle_only_when_away', 0;
+$aidle{'away'} = Irssi::settings_get_bool 'aidle_only_when_away';
+
+$aidle{'timer'} = Irssi::timeout_add $aidle{'max'} * 1000, 'antyidlesend', '';
+
+sub antyidlesend {
+ for my $server (Irssi::servers()) {
+ next if (not $server->{'connected'} or ($aidle{'away'} and not $server->{'usermode_away'})
+ or (@{$aidle{'ircnets'}} and not grep {lc $server->{'chatnet'} eq lc $_} @{$aidle{'ircnets'}}));
+ $server->send_raw("PRIVMSG " . $server->{nick} . " IDLE");
+ Irssi::timeout_remove $aidle{'timer'};
+ $aidle{'timer'} = Irssi::timeout_add int(rand($aidle{'max'})+1) * 1000, 'antyidlesend', '';
+ }
+}
+
+Irssi::signal_add 'setup changed' => sub {
+ $aidle{'away'} = Irssi::settings_get_bool 'aidle_only_when_away';
+ my $max_idle_time = Irssi::settings_get_int 'aidle_max_idle_time';
+ if ($max_idle_time < $aidle{'max'}) {
+ Irssi::timeout_remove $aidle{'timer'};
+ $aidle{'timer'} = Irssi::timeout_add int(rand($max_idle_time)+1) * 1000, 'antyidlesend', '';
+ }
+ $aidle{'max'} = $max_idle_time;
+ @{$aidle{'ircnets'}} = (split(/[\s,|-]+/, Irssi::settings_get_str('aidle_ircnets')));
+ foreach my $ircnet (@{$aidle{'ircnets'}}) {
+ Irssi::print("%RWarning%n - no such chatnet \'$ircnet\' !", MSGLEVEL_CLIENTERROR) unless (Irssi::chatnet_find($ircnet));
+ }
+};
+
+Irssi::signal_add "event 301" => sub {
+ my ($server, $data) = @_;
+
+ my ($fnick, $snick, undef) = split(' ', $data);
+
+ Irssi::signal_stop() if $fnick eq $snick;
+};
+
+Irssi::signal_add "default ctcp msg" => sub {
+ my ($server, $data, $sender, $addr, $target) = @_;
+
+ Irssi::signal_stop() if ($sender eq $target && $data eq "IDLE");
+};
diff --git a/scripts/akftp.pl b/scripts/akftp.pl
new file mode 100644
index 0000000..0c93230
--- /dev/null
+++ b/scripts/akftp.pl
@@ -0,0 +1,96 @@
+###########################################################################
+# ak FTP-Ad v1.4
+# Copyright (C) 2003 ak
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+# Or check out here, eh ;) -> http://www.gnu.org/licenses/gpl.html //ak
+###########################################################################
+
+# code follows .. nothing to do here for you,
+# just load the script into irssi with /script load akftp.pl
+# and enter /akftp for more information
+#############################################################
+
+use strict;
+use Irssi 20021117.1611 ();
+use vars qw($VERSION %IRSSI);
+ $VERSION = "1.4";
+ %IRSSI = (
+ authors => "ak",
+ contact => "ocb23\@freenet.removethis.de",
+ name => "ak FTP-Ad",
+ description => "Full configurable FTP advertiser for Irssi",
+ license => "GPLv2",
+ url => "http://members.tripod.com.br/archiv/",
+ );
+
+
+use Irssi qw(
+ settings_get_bool settings_add_bool
+ settings_get_str settings_add_str
+ settings_get_int settings_add_int
+ print
+);
+
+sub cmd_list {
+ my ($server, $msg, $nick, $mask, $target) = @_;
+ my ($c1, $c2, $trigger, $targets);
+ $trigger=settings_get_str('akftp_trigger');
+ $targets=settings_get_str('akftp_channels');
+
+ if (!settings_get_bool('akftp_enable_add')) { return 0 }
+ if(!($target =~ $targets)) { return 0 }
+ elsif ($msg=~/^$trigger/){
+ $c1=settings_get_str('akftp_color1');
+ $c2=settings_get_str('akftp_color2');
+ $server->command("^NOTICE ".$nick." ".$c1."=(".$c2."FTP Online".$c1.")= \@(".
+ $c2.settings_get_str('akftp_host').$c1.") Port:(".$c2.settings_get_str('akftp_port').
+ $c1.") Login:(".$c2.settings_get_str('akftp_login').$c1.") Pass:(".
+ $c2.settings_get_str('akftp_pass').$c1.") Quicklink: ".$c2.
+ "ftp://".settings_get_str('akftp_login').":".settings_get_str('akftp_pass')."\@".
+ settings_get_str('akftp_host').":".settings_get_str('akftp_port')."/".
+ $c1." Notes:(".$c2.settings_get_str('akftp_notes').$c1.")");
+ # Irssi::signal_stop();
+ }
+}
+
+sub cmd_akftp {
+ print("%r.--------------------<%n%_ak FTP-Ad for Irssi%_%r>--------------------<");
+ print("%r|%n Configure the script with %_/set%_ commands, to see all values,");
+ print("%r|%n you can type \"%_/set akftp%_\".");
+ print("%r|%n You can configure multiple chans by separating them with %_|%_");
+ print("%r|%n You have to specify the colors with \"%_CTRL+C##%_\". where %_##%_");
+ print("%r|%n must be numbers between %_00%_ and %_15%_! Prefix 0-9 with a zero!");
+ print("%r|%n Note that \"%_/set akftp%_\" will show empty variables for colors,");
+ print("%r|%n even if they are already set.");
+ print("%r`------------------------------------------------------------->");
+}
+
+settings_add_bool('akftp', 'akftp_enable_add', 0);
+settings_add_str('akftp', 'akftp_login', "username");
+settings_add_str('akftp', 'akftp_pass', "password");
+settings_add_str('akftp', 'akftp_host', "your.dyndns-or-static.ip");
+settings_add_str('akftp', 'akftp_notes', "Don't hammer!");
+settings_add_str('akftp', 'akftp_channels', "#chan1|#chan2");
+settings_add_int('akftp', 'akftp_port', "21");
+settings_add_str('akftp', 'akftp_color1', "\00303");
+settings_add_str('akftp', 'akftp_color2', "\00315");
+settings_add_str('akftp', 'akftp_trigger', "!list");
+
+Irssi::signal_add_last('message public', 'cmd_list');
+Irssi::command_bind('akftp', 'cmd_akftp');
+
+#EOF
diff --git a/scripts/akilluser.pl b/scripts/akilluser.pl
new file mode 100644
index 0000000..e786943
--- /dev/null
+++ b/scripts/akilluser.pl
@@ -0,0 +1,92 @@
+# AKILL a specified nick, either with the defined reason or with something given
+# in the command
+#
+# (C) 2006 by Joerg Jaspert <joerg@debian.org>
+# (C) 2007 by Christoph Berg <cb@df7cb.de>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this script; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+use strict;
+use Irssi;
+
+use vars qw($VERSION %IRSSI);
+
+$VERSION = '0.2';
+%IRSSI = (
+ authors => 'Joerg Jaspert',
+ contact => 'joerg@debian.org',
+ name => 'akilluser',
+ description => 'AKILLS a nick',
+ license => 'GPL v2 (and no later)',
+);
+
+########################################################################
+# Kill it
+
+sub akill_nick {
+ my ($arg, $server, $channel) = @_;
+
+ $arg =~ /(\S+)\s?(.*)?/;
+ my ($target, $reason) = ($1, $2);
+ my ($user, $host);
+
+ if ($target =~ /(.+)@(.+)/) {
+ ($user, $host) = ($1, $2);
+ } else {
+ if (!$channel) {
+ Irssi::print("Not joined to a channel");
+ return;
+ }
+ my $nickh = $channel->nick_find($target);
+ if (!$nickh->{host}) {
+ Irssi::print("User $target not found on $channel->{name}");
+ return;
+ }
+ if ($server->masks_match(Irssi::settings_get_str('akill_exempt'), $target, $nickh->{host})) {
+ Irssi::print("Not AKILLing an akill-exempt user");
+ return;
+ }
+ $nickh->{host} =~ /(\S+)@(\S+)/;
+ ($user, $host) = ("*", $2);
+ }
+
+ if ("$user$host" !~ /[\w\d]/) {
+ Irssi::print("AKILLing $user\@$host looks insane");
+ return;
+ }
+
+ if (length($reason) < 2) {
+ $reason = Irssi::settings_get_str('akill_reason');
+ }
+ if ($reason !~ /\@oftc\.net/) {
+ $reason .= " " . Irssi::settings_get_str('akill_trailer');
+ }
+
+ my $window = Irssi::active_win();
+ $window->print("AKILLed $target ($user\@$host) with \"$reason\"");
+ $server->command("quote os akill add $user\@$host $reason");
+}
+
+
+########################################################################
+# ---------- Do the startup tasks ----------
+
+# Add the settings
+Irssi::settings_add_str("akilluser.pl", "akill_reason", 'This host violated network policy.');
+Irssi::settings_add_str("akilluser.pl", "akill_trailer", 'Mail support@oftc.net if you think this is in error.');
+Irssi::settings_add_str("akilluser.pl", "akill_exempt", '*!*@*.sponsor.oftc.net *!*@*.advisor.oftc.net *!*@*.netrep.oftc.net *!*@*.netop.oftc.net *!*@*.noc.oftc.net *!*@*.ombudsman.oftc.net *!*@*.chair.oftc.net');
+
+Irssi::command_bind('akill', 'akill_nick');
diff --git a/scripts/alame.pl b/scripts/alame.pl
new file mode 100644
index 0000000..3c590cc
--- /dev/null
+++ b/scripts/alame.pl
@@ -0,0 +1,36 @@
+use Irssi;
+use Irssi::Irc;
+use strict;
+use warnings;
+use vars qw($VERSION %IRSSI);
+$VERSION="0.0.1";
+%IRSSI = (
+ authors => 'Christian \'mordeth\' Weber',
+ contact => 'mordeth\@mac.com',
+ name => 'alame',
+ description => 'Converts towards lame speech',
+ license => 'GPL v2',
+ url => 'http://',
+);
+
+
+# USAGE:
+# /alame <text>
+# writes "text" in lamespeech to the current channel
+
+sub cmd_lamer {
+ my ($data, $server, $witem) = @_;
+ if (!$server || !$server->{connected}) {
+ Irssi::print("Not connected to server");
+ return;
+ }
+ if ($data) {
+ my $x; $_=$data; s/./$x=rand(6); $x>3?lc($&):uc($&)/eg; s/a/4/gi; s/c/(/gi;
+ s/d/|)/gi; s/e/3/gi; s/f/|=/gi; s/h/|-|/gi; s/i/1/gi; s/k/|</gi;
+ s/l/|_/gi; s!m!/\\/\\!gi; s!n!/\\/!gi; s/o/0/gi; s/s/Z/gi; s/t/7/gi;
+ s/u/|_|/gi; s!v!\\/!gi; s!w!\\/\\/!gi; #s/w/\/\//gi;
+ $witem->command("/SAY $_");
+ }
+}
+
+Irssi::command_bind('alamer', 'cmd_lamer');
diff --git a/scripts/anotherway.pl b/scripts/anotherway.pl
new file mode 100644
index 0000000..f7a0ca8
--- /dev/null
+++ b/scripts/anotherway.pl
@@ -0,0 +1,54 @@
+#!/usr/bin/perl
+#
+# by Stefan Tomanek <stefan@pico.ruhr.de>
+
+use strict;
+use vars qw($VERSION %IRSSI);
+$VERSION = "2003010201";
+%IRSSI = (
+ authors => "Stefan 'tommie' Tomanek",
+ contact => "stefan\@pico.ruhr.de",
+ name => "anotherway",
+ description => "Another auto away script",
+ license => "GPLv2",
+ changed => "$VERSION",
+);
+use Irssi 20020324;
+use vars qw($timer @signals);
+
+@signals = ('message own_public', 'message own_private');
+
+sub go_away {
+ #Irssi::print "%R>>%n Going away...$timer";
+ Irssi::timeout_remove($timer);
+ my $reason = Irssi::settings_get_str("anotherway_reason");
+ my @servers = Irssi::servers();
+ return unless @servers;
+ Irssi::signal_remove($_ , "reset_timer") foreach (@signals);
+ $servers[0]->command('AWAY '.$reason);
+ Irssi::signal_add($_ , "reset_timer") foreach (@signals);
+}
+
+sub reset_timer {
+ #Irssi::print "%R>>%n RESET";
+ Irssi::signal_remove($_ , "reset_timer") foreach (@signals);
+ foreach (Irssi::servers()) {
+ $_->command('AWAY') if $_->{usermode_away};
+ last;
+ }
+ #Irssi::signal_add('nd', "reset_timer");
+ Irssi::timeout_remove($timer);
+ my $timeout = Irssi::settings_get_int("anotherway_timeout");
+ $timer = Irssi::timeout_add($timeout*1000, "go_away", undef);
+ Irssi::signal_add($_, "reset_timer") foreach (@signals);
+}
+
+Irssi::settings_add_str($IRSSI{name}, 'anotherway_reason', 'a-nother-way');
+Irssi::settings_add_int($IRSSI{name}, 'anotherway_timeout', 300);
+
+{
+ Irssi::signal_add($_, "reset_timer") foreach (@signals);
+ reset_timer();
+}
+
+print CLIENTCRAP '%B>>%n '.$IRSSI{name}.' '.$VERSION.' loaded';
diff --git a/scripts/antiplenk.pl b/scripts/antiplenk.pl
new file mode 100644
index 0000000..40c0d50
--- /dev/null
+++ b/scripts/antiplenk.pl
@@ -0,0 +1,47 @@
+use Irssi;
+use 5.6.0;
+use strict;
+use vars qw($VERSION %IRSSI);
+
+$VERSION = "0.2.1";
+%IRSSI = (
+ authors => 'Grigori Goronzy',
+ contact => 'greg@chown.ath.cx',
+ name => 'antiplenk',
+ description => 'notices users who "plenk"',
+ license => 'BSD',
+ url => 'http://chown.ath.cx/~greg/antiplenk/',
+ changed => 'Mi 12 Feb 2003 07:00:05 CET',
+);
+
+Irssi::settings_add_str($IRSSI{'name'}, "plenk_channels", "#foobar|#barfoo");
+Irssi::settings_add_bool($IRSSI{'name'}, "plenk_spam", "1");
+Irssi::settings_add_int($IRSSI{'name'}, "plenk_allowed", "10");
+Irssi::signal_add_last('message public', 'plenk');
+my %times;
+
+Irssi::print "antiplenk $VERSION loaded";
+
+sub plenk {
+my ($server, $msg, $nick, $address, $channel) = @_;
+my $spam = Irssi::settings_get_bool("plenk_spam");
+my $allowed = Irssi::settings_get_int("plenk_allowed");
+
+# channel in list?
+if(!($channel =~ Irssi::settings_get_str("plenk_channels"))) { return 0 }
+
+# check..
+while($msg =~ /[[:alnum:]]+ (\.|\,|\?|\!|\: |\; )(\!|\1|\?|\ß|\.|\ |$)/g) {
+ # increment
+ $times{$nick}++;
+ # "debug"
+ if($spam) { Irssi::print "antiplenk: $nick plenked on $channel for the $times{$nick}" .
+ ($times{$nick} == 1 ? "st" : $times{$nick} == 2 ? "nd" : $times{$nick} == 3 ? "rd" : "th") .
+ " time" }
+ # too often?
+ if($times{$nick} > $allowed ) {
+ $server->command("msg $nick antiplenk: you 'plenked' more than $allowed times! please stop this at once!");
+ Irssi::print "antiplenk: $nick got a notice";
+ $times{$nick} = 0; }
+ }
+}
diff --git a/scripts/apm.pl b/scripts/apm.pl
new file mode 100644
index 0000000..5ab1b62
--- /dev/null
+++ b/scripts/apm.pl
@@ -0,0 +1,122 @@
+use strict;
+use vars qw($VERSION %IRSSI);
+
+use Irssi::TextUI;
+
+$VERSION = "0.4";
+%IRSSI = (
+ authors => "Alexander Wirt",
+ contact => "formorer\@formorer.de",
+ name => "apm",
+ description => "Shows your battery status in your Statusbar",
+ sbitems => "power",
+ license => "GNU Public License",
+ url => "http://www.formorer.de/code",
+);
+
+
+#
+#apm.pl
+# apm.pl is a small script for displaying your Battery Level in irssi.
+# Just load the script and do a /statusbar window add apm
+# and a small box [BAT: +/-XX%] should be displayed this is only possible
+# on Computers where /proc/apm or /proc/acpi is existing.
+# The + or - indicates if battery is charging or discharging.
+#
+# /set power_refresh <sec> changes the refreshing time of the display
+#
+#
+# Changelog:
+#
+# 0.3 - Added support for ACPI and enhanced APM support
+# 0.2 - Added apm_refresh and some documentation
+# 0.1 - Initial Release
+
+
+
+
+
+my ($refresh, $last_refresh, $refresh_tag) = (10);
+
+my ($acpi,$apm) = 0;
+
+
+if (-r "/proc/acpi") { $acpi = "yes" }
+if (-r "/proc/apm") { $apm = "yes" }
+
+exit unless ($apm or $acpi);
+
+
+sub get_apm {
+ open(RC, q{<}, "/proc/apm");
+ my $line = <RC>;
+ close RC;
+ my ($ver1, $ver2, $sysstatus, $acstat, $chargstat, $batstatus, $prozent, $remain) = split(/\s/,$line);
+
+ if ($acstat eq "0x01") { return "+$prozent" } else { return "-$prozent" }
+}
+
+sub get_acpi {
+ open(RC, q{<}, "/proc/acpi/ac_adapter/ACAD/state");
+ my $line = <RC>;
+ close RC;
+ my ($text,$state) = split (/:/,$line);
+ $state =~ s/\s//g;
+
+ open (RC, q{<}, "/proc/acpi/battery/BAT0/info");
+ my ($text,$capa,$ein);
+ while (my $line = <RC>) {
+ if ($line =~ /last full capacity/) {
+ ($text, $capa,$ein) = split (/:/,$line);
+ $capa =~ s/\s//g;
+ }
+ }
+ open (RC, q{<}, "/proc/acpi/battery/BAT0/state");
+ my ($text,$remain,$ein);
+ while (my $line = <RC>) {
+ if ($line =~ /remaining capacity/) {
+ ($text, $remain,$ein) = split (/:/,$line);
+ $remain =~ s/\s//g;
+ }
+ }
+ my $pstate = $remain / $capa * 100;
+ $pstate = sprintf("%2i", $pstate);
+
+ if ($state eq "off-line") { $pstate = "-$pstate%"; } else { $pstate = "+$pstate%"; }
+ return $pstate;
+}
+
+
+sub power {
+ my ($item, $get_size_only) = @_;
+ my $pstate;
+ if ($apm) {
+ $pstate = get_apm();
+ } else {
+ $pstate = get_acpi();
+ }
+ $item->default_handler($get_size_only, undef, "BAT:$pstate", 1 );
+}
+
+
+sub set_power {
+ $refresh = Irssi::settings_get_int('power_refresh');
+ $refresh = 1 if $refresh < 1;
+ return if $refresh == $last_refresh;
+ $last_refresh = $refresh;
+ Irssi::timeout_remove($refresh_tag) if $refresh_tag;
+ $refresh_tag = Irssi::timeout_add($refresh*1000, 'refresh_power', undef);
+
+}
+
+
+sub refresh_power {
+ Irssi::statusbar_items_redraw('power');
+}
+
+Irssi::statusbar_item_register('power', '{sb $0-}', 'power');
+Irssi::statusbars_recreate_items();
+
+Irssi::settings_add_int('misc', 'power_refresh', $refresh);
+set_power();
+Irssi::signal_add('setup changed', 'set_power');
diff --git a/scripts/armeija.pl b/scripts/armeija.pl
new file mode 100644
index 0000000..fc854c6
--- /dev/null
+++ b/scripts/armeija.pl
@@ -0,0 +1,267 @@
+#!/usr/bin/perl -w
+# script to ignore boring messages in irc
+# it has a list of keywords which on a public message will cause someone
+# to be ignored for 60 seconds (changeable). also it ignores (tries to)
+# every message back to ignored people.
+# - flux@inside.org
+
+# check out my other irssi-stuff at http://xulfad.inside.org/~flux/software/irssi/
+
+use strict;
+use Irssi;
+
+use vars qw($VERSION %IRSSI);
+$VERSION = "0.4";
+%IRSSI = (
+ authors => "Erkki Seppälä",
+ contact => "flux\@inside.org",
+ name => "Armeija Ignore",
+ description => "Ignores people bringin up boring/repeated subjects, plus replies.",
+ license => "Public Domain",
+ url => "http://xulfad.inside.org/~flux/software/irssi/",
+ changed => "Tue Mar 5 00:06:35 EET 2002"
+);
+
+
+use Irssi::Irc;
+
+my $log = 0;
+my $logFile = "$ENV{HOME}/.irssi/armeija.log";
+
+my $retrigger = 0;
+my $wordFile = "$ENV{HOME}/.irssi/armeija.words";
+my $channelFile = "$ENV{HOME}/.irssi/armeija.channels";
+my $overflowLimit = 3;
+
+my @channels = ("#linux.fi");
+
+my @keywords = (
+
+# armeija
+ "\\barmeija", "\\brynkky", "\\bintti", "\\bintissä", "\\bgines", "\\btj\\b"
+, "\\bsaapumiserä", "\\bvarus(mies|nainen|täti)", "\\bvemppa", "\\bvempula"
+, "\\bvempa", "\\bveksi", "\\bsulkeiset", "\\bsulkeisi"
+, "\\bvlv\\b", "\\bhl\\b"
+
+# offtopic
+, "\\bsalkkari", "\\bsalatut eläm". "\\bsalattuja eläm"
+
+# urheilu
+,"\\bhiiht", "\\bhiihd", "\\bformula", "\\bolympia"
+
+);
+
+my %infected;
+my $timeout = 60;
+
+my $who = "";
+my $why = "";
+
+sub p0 {
+ my $a = $_[0];
+ while (length($a) < 2) {
+ $a = "0$a";
+ }
+ return $a;
+}
+
+sub why {
+ if ($who ne "") {
+ Irssi::print "$who was ignored: $why";
+ }
+}
+
+sub public {
+ my ($server, $msg, $nick, $address, $target) = @_;
+
+ local *F;
+
+ my $now = time;
+
+ my $skip = 1;
+ foreach my $channel (@channels) {
+ if (lc($target) eq lc($channel)) {
+ $skip = 0;
+ last;
+ }
+ }
+
+ if ($skip) {
+ return 0;
+ }
+
+ # check for keywords
+
+ my $count = 0;
+ foreach my $word (@keywords) {
+ if ($msg =~ /$word/i) {
+ ++$count;
+ }
+ }
+
+ if (($count >= 1) && ($count < $overflowLimit)) {
+ Irssi::print "Ignoring $nick";
+ $why = $msg;
+ $who = $nick;
+ if ($log) {
+ open(F, q{>>}, $logFile);
+ my @t = localtime($now);
+ $t[5] += 1900;
+ print F "$t[5]-", p0($t[4] + 1), "-", p0($t[3]), " ",
+ p0($t[2]), ":", p0($t[1]), ":", p0($t[0]), " $who/$target: $why\n";
+ close(F);
+ }
+ if ($retrigger || !exists $infected{$nick}) {
+ $infected{$nick} = $now + $timeout;
+ }
+ Irssi::signal_stop();
+ return 1;
+ }
+
+ # check and expire old ignores
+ if (exists $infected{$nick}) {
+ if ($infected{$nick} < $now) {
+ Irssi::print "Timed out: $nick";
+ delete $infected{$nick};
+ } else {
+ Irssi::signal_stop();
+ return 1;
+ }
+ }
+
+ # check for messages targetted to ignored people
+ foreach my $nick (keys %infected) {
+ if ($msg =~ /^$nick/i) {
+ # ignore messages to these people
+ Irssi::signal_stop();
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+sub logging {
+ my (@args) = @_;
+ if (@args) {
+ if ($args[0] eq "on") {
+ $log = 1;
+ Irssi::print("Armeija-logging on to file $logFile");
+ } elsif ($args[0] eq "off") {
+ $log = 0;
+ Irssi::print("Armeija-logging stopped");
+ } else {
+ $logFile = $args[0];
+ Irssi::print("Armeija-logfile set to $logFile");
+ }
+ } else {
+ Irssi::print("usage: armeija log [on|off|new log file name]");
+ Irssi::print("Log is " . ($log ? "on" : "off") . ", logfile is $logFile");
+ }
+}
+
+sub load {
+ local $/ = "\n";
+ local *F;
+ if (open(F, q{<}, $wordFile)) {
+ @keywords = ();
+ while (<F>) {
+ chomp;
+ push @keywords, $_;
+ }
+ close(F);
+ } else {
+ Irssi::print("Failed to open wordfile $wordFile\n");
+ }
+ if (open(F, q{<}, $channelFile)) {
+ @channels = ();
+ while (<F>) {
+ chomp;
+ push @channels, $_;
+ }
+ close(F);
+ }
+}
+
+sub save {
+ local *F;
+ if (open(F, q{>}, $wordFile)) {
+ for (my $c = 0; $c < @keywords; ++$c) {
+ print F $keywords[$c], "\n";
+ }
+ close(F);
+ }
+ if (open(F, q{>}, $channelFile)) {
+ for (my $c = 0; $c < @channels; ++$c) {
+ print F $channels[$c], "\n";
+ }
+ close(F);
+ }
+}
+
+sub retrigger {
+ if (@_ == 1) {
+ if ($_[0] eq "on") {
+ Irssi::print "Armeija retrigger on";
+ $retrigger = 1;
+ } elsif ($_[0] eq "off") {
+ Irssi::print "Armeija retrigger off";
+ $retrigger = 0;
+ } else {
+ Irssi::print("Invalid armeija trigger state");
+ }
+ } else {
+ Irssi::print("usage: /armeija retrigger [on|off]");
+ }
+}
+
+sub armeija {
+ my (@args) = split(" ", $_[0]);
+ if (@args) {
+ if ($args[0] eq "why") {
+ why();
+ } elsif ($args[0] eq "log") {
+ my @a = @args;
+ shift @a;
+ logging(@a);
+ } elsif ($args[0] eq "load") {
+ load();
+ } elsif ($args[0] eq "save") {
+ save();
+ } elsif ($args[0] eq "+word") {
+ my @a = @args;
+ shift @a;
+ push @keywords, join(" ", @a);
+ save();
+ } elsif ($args[0] eq "-word") {
+ my @a = @args;
+ shift @a;
+ for (my $c = 0; $c < @keywords; ++$c) {
+ for (my $d = 0; $d < @a;) {
+ if ($a[$d] eq $keywords[$c]) {
+ splice @keywords, $c, 1;
+ } else {
+ ++$d;
+ }
+ }
+ }
+ save();
+ } elsif ($args[0] eq "words") {
+ Irssi::print(join(", ", @keywords));
+ } elsif ($args[0] eq "retrigger") {
+ my @a = @args;
+ shift @a;
+ retrigger(@a);
+ } else {
+ Irssi::print("Invalid armeija command");
+ }
+ } else {
+ Irssi::print("Armeija usage: armeija [log [off|on|filename]|load|save|+word word|-word word|words]");
+ }
+}
+
+Irssi::signal_add("message public", "public");
+Irssi::command_bind("armeija", "armeija");
+
+Irssi::print "Armeija-ignore v$VERSION by $IRSSI{contact}";
+load();
diff --git a/scripts/ascii.pl b/scripts/ascii.pl
new file mode 100644
index 0000000..557ebb0
--- /dev/null
+++ b/scripts/ascii.pl
@@ -0,0 +1,405 @@
+#
+# Commands: /ASCII, /COLSAY, /COLME, /COLTOPIC, /COLKICK, /COLQUIT
+# Usage:
+# /ASCII [-c1234] [-f <fontname>] [-p <prefix>] [-l|-s|-m <where>] <text>
+# /COLSAY [-1234] [-m <where>] <text>
+# /COLME [-1234] <text>
+# /COLTOPIC [-1234] <text>
+# /COLKICK [-1234] [nick(,nick_1,...,nick_n)] <reason>
+# /COLQUIT [-1234] <reason>
+# Settings:
+# /SET ascii_figlet_path [path]
+# /SET ascii_default_font [fontname]
+# /SET ascii_default_colormode [1-4]
+# /SET ascii_default_prefix [prefix]
+# /SET ascii_default_kickreason [reason]
+# /SET ascii_default_quitreason [reason]
+#
+# Script is bassed on figlet.
+#
+
+use strict;
+use Irssi;
+use Irssi::Irc;
+
+use vars qw($VERSION %IRSSI);
+
+$VERSION = "1.6.3";
+%IRSSI = (
+ "authors" => "Marcin Rozycki",
+ "contact" => "derwan\@irssi.pl",
+ "name" => "ascii-art",
+ "description" => "Ascii-art bassed on figlet. Available commands: /ASCII, /COLSAY, /COLME, /COLTOPIC, /COLKICK, /COLQUIT.",
+ "url" => "http://derwan.irssi.pl",
+ "license" => "GNU GPL v2",
+ "changed" => "Fri Jun 21 17:17:53 CEST 2002"
+);
+
+use IPC::Open3;
+
+# defaults
+my $ascii_default_font = "small.flf";
+my $ascii_default_kickreason = "Irssi BaBy!";
+my $ascii_default_quitreason = "I Quit!";
+my $ascii_last_color = undef;
+my @ascii_colors = (12, 12, 12, 9, 5, 4, 13, 8, 7, 3, 11, 10, 2, 6, 6, 6, 6, 10, 8, 7, 4, 3, 9, 11, 2, 12, 13, 5);
+
+# registering themes
+Irssi::theme_register([
+ 'ascii_not_connected', '%_$0:%_ You\'re not connected to server',
+ 'ascii_not_window', '%_$0:%_ Not joined to any channel or query window',
+ 'ascii_not_chanwindow', '%_$0:%_ Not joined to any channel',
+ 'ascii_not_chanop', '%_$0:%_ You\'re not channel operator in {hilight $1}',
+ 'ascii_figlet_notfound', '%_Ascii:%_ Cannot execute {hilight $0} - file not found or bad permissions',
+ 'ascii_figlet_notset', '%_Ascii:%_ Cannot find external program %_figlet%_, usign /SET ascii_figlet_path [path], to set it',
+ 'ascii_cmd_syntax', '%_$0:%_ $1, usage: $2',
+ 'ascii_figlet_error', '%_Ascii: Figlet returns error:%_ $0-',
+ 'ascii_fontlist', '%_Ascii:%_ Available fonts [in $0]: $1 ($2)',
+ 'ascii_empty_fontlist', '%_Ascii:%_ Cannot find figlet fonts in $0',
+ 'ascii_unknown_fontdir', '%_Ascii:%_ Cannot find figlet fontdir',
+ 'ascii_show_line', '$0-'
+
+]);
+
+# str find_figlet_path()
+sub find_figlet_path {
+ foreach my $dir (split(/\:/, $ENV{'PATH'}))
+ {
+ return "$dir/figlet" if ($dir and -x "$dir/figlet");
+ }
+}
+
+# int randcolor()
+sub randcolor {
+ return $ascii_colors[int(rand(12)+2)];
+}
+
+# str colorline($colormode, $text)
+sub colorline {
+ my ($colormode, $text) = @_;
+ my $colortext = undef;
+ my $last = ($ascii_last_color) ? $ascii_last_color : randcolor();
+ my $indx = $last;
+
+ if ($colormode =~ /3/) {
+ $ascii_last_color = randcolor();
+ }elsif ($colormode =~ /4/) {
+ $ascii_last_color = $ascii_colors[$last];
+ }elsif ($colormode !~ /2/) {
+ $ascii_last_color = $ascii_colors[14+$last];
+ }
+
+ while ($text =~ /./g)
+ {
+ my $char = "$&";
+
+ if ($colormode =~ /3/) {
+ while ($indx == $last) { $indx = randcolor(); };
+ $last = $indx;
+ }elsif ($colormode =~ /4/) {
+ $indx = $ascii_colors[$indx];
+ }elsif ($last) {
+ $indx = $ascii_colors[$last];
+ undef $last;
+ } else {
+ $indx = $ascii_colors[$indx];
+ $last = $indx + 14;
+ };
+
+ $colortext .= $char, next if ($char eq " ");
+ $colortext .= "\003" . sprintf("%02d", $indx) . $char;
+ $colortext .= $char if ($char eq ",");
+ };
+
+ return $colortext;
+};
+
+# int colormode()
+sub colormode {
+ my $mode = Irssi::settings_get_int("ascii_default_colormode");
+ $mode =~ s/-//g;
+ return (!$mode or $mode > 4) ? 1 : $mode;
+};
+
+# bool ascii_test($command, $flags, $server, $window)
+sub ascii_test {
+ my ($cmd, $test, $server, $window) = @_;
+
+ if ($test =~ /s/ and !$server || !$server->{connected}) {
+ Irssi::printformat(MSGLEVEL_CRAP, "ascii_not_connected", $cmd);
+ return 0;
+ };
+ if ($test =~ /W/ and !$window || $window->{type} !~ /(channel|query)/i) {
+ Irssi::printformat(MSGLEVEL_CRAP, "ascii_not_window", $cmd);
+ return 0;
+ };
+ if ($test =~ /(w|o)/ and !$window || $window->{type} !~ /channel/i) {
+ Irssi::printformat(MSGLEVEL_CRAP, "ascii_not_chanwindow", $cmd);
+ return 0;
+ };
+ if ($test =~ /o/ and !$window->{chanop}) {
+ Irssi::printformat(MSGLEVEL_CRAP, "ascii_not_chanop", $cmd, Irssi::active_win()->get_active_name());
+ return 0;
+ };
+
+ return 1;
+}
+
+# void cmd_ascii()
+# handles /ascii
+sub cmd_ascii
+{
+ my $usage = "/ASCII [-c1234] [-f <fontname>] [-p <prefix>] [-l|-s|-m <where>] <text>";
+ my $font = Irssi::settings_get_str("ascii_default_font");
+ my $prefix = Irssi::settings_get_str("ascii_default_prefix");
+ my ($arguments, $server, $witem) = @_;
+ my ($text, $cmd, $mode);
+
+ $font = $ascii_default_font unless ($font);
+ $ascii_last_color = randcolor();
+
+ my $figlet = Irssi::settings_get_str("ascii_figlet_path");
+ if (!$figlet or !(-x $figlet)) {
+ my $theme = ($figlet) ? "ascii_figlet_notfound" : "ascii_figlet_notset";
+ Irssi::printformat(MSGLEVEL_CRAP, $theme, $figlet);
+ return;
+ };
+
+ my @foo = split(/ +/, $arguments);
+ while ($_ = shift(@foo))
+ {
+ /^-l$/ and show_figlet_fonts($figlet), return;
+ /^-c$/ and $mode = colormode(), next;
+ /^-(1|2|3|4)$/ and s/-//g, $mode = $_, next;
+ /^-f$/ and $font = shift(@foo), next;
+ /^-p$/ and $prefix = shift(@foo), next;
+ /^-m$/ and $cmd = shift(@foo), next;
+ /^-s$/ and $cmd = 0, next;
+ /^-/ and Irssi::printformat(MSGLEVEL_CRAP, "ascii_cmd_syntax", "Ascii", "Unknown argument: $_", $usage), return;
+ $text = ($#foo < 0) ? $_ : $_ . " " . join(" ", @foo);
+ last;
+ }
+
+ unless (length($text)) {
+ Irssi::printformat(MSGLEVEL_CRAP, "ascii_cmd_syntax", "Ascii", "Missing arguments", $usage);
+ return;
+ };
+
+ if ($cmd eq "") {
+ return unless (ascii_test("Ascii", "sW", $server, $witem));
+ $cmd = Irssi::active_win()->get_active_name();
+ } elsif ($cmd ne "0" and !ascii_test("Ascii", "s", $server, $witem)) {
+ return;
+ }
+
+ my $pid = open3(*FIGIN, *FIGOUT, *FIGERR, $figlet, qw(-k -f), $font, $text);
+
+ while (<FIGOUT>)
+ {
+ chomp;
+ next unless (/[^ ]/);
+ $_ = colorline($mode, $_) if ($mode);
+ Irssi::printformat(MSGLEVEL_CLIENTCRAP, "ascii_show_line", $prefix.$_), next if ($cmd eq "0");
+ $server->command("msg $cmd $prefix$_");
+ }
+
+ while (<FIGERR>)
+ {
+ chomp;
+ Irssi::printformat(MSGLEVEL_CRAP, "ascii_figlet_error", $_);
+ };
+
+ close FIGIN;
+ close FIGOUT;
+ close FIGERR;
+
+ waitpid $pid, 0;
+}
+
+# void show_figlet_fonts(figlet path)
+sub show_figlet_fonts {
+ my @fontlist;
+ if (my $fontdir = `"$_[0]" -I 2 2>/dev/null`) {
+ chomp $fontdir;
+ foreach my $font (glob $fontdir."/*.flf")
+ {
+ $font =~ s/^$fontdir\///;
+ $font =~ s/\.flf$//;
+ push @fontlist, $font;
+ }
+ if ($#fontlist < 0) {
+ Irssi::printformat(MSGLEVEL_CRAP, "ascii_fontlist_empty", $fontdir);
+ } else {
+ Irssi::printformat(MSGLEVEL_CRAP, "ascii_fontlist", $fontdir, join(", ", @fontlist), scalar(@fontlist));
+ }
+ } else {
+ Irssi::printformat(MSGLEVEL_CRAP, "ascii_unknown_fontdir");
+ }
+}
+
+# void cmd_colsay()
+# handles /colsay
+sub cmd_colsay {
+ my $usage = "/COLSAY [-1234] [-m <where>] <text>";
+ my ($arguments, $server, $witem) = @_;
+ my ($cmd, $text);
+ my $mode = colormode();
+
+ $ascii_last_color = randcolor();
+
+ my @foo = split(/ /, $arguments);
+ while ($_ = shift(@foo))
+ {
+ /^-(1|2|3|4)$/ and $mode = $_, next;
+ /^-m$/i and $cmd = shift(@foo), next;
+ /^-/ and Irssi::printformat(MSGLEVEL_CRAP, "ascii_cmd_syntax", "Colsay", "Unknown argument: $_", $usage), return;
+ $text = ($#foo < 0) ? $_ : $_ . " " . join(" ", @foo);
+ last;
+ };
+
+ unless (length($text)) {
+ Irssi::printformat(MSGLEVEL_CRAP, "ascii_cmd_syntax", "Colsay", "Missing arguments", $usage);
+ return;
+ };
+
+ if ($cmd) {
+ return unless (ascii_test("Colsay", "s", $server, $witem));
+ } else {
+ return unless (ascii_test("Colsay", "sW", $server, $witem));
+ $cmd = Irssi::active_win()->get_active_name();
+ };
+
+ $server->command("msg $cmd ".colorline($mode, $text));
+}
+
+
+sub cmd_colme {
+ my $usage = "/COLME [-1234] <text>";
+ my ($arguments, $server, $witem) = @_;
+ my $mode = colormode();
+ my $text;
+
+ $ascii_last_color = randcolor();
+
+ my @foo = split(/ /, $arguments);
+ while ($_ = shift(@foo))
+ {
+ /^-(1|2|3|4)$/ and $mode = $_, next;
+ /^-/ and Irssi::printformat(MSGLEVEL_CRAP, "ascii_cmd_syntax", "Colme", "Unknown argument: $_", $usage), return;
+ $text = ($#foo < 0) ? $_ : $_ . " " . join(" ", @foo);
+ last;
+ };
+
+ unless (length($text)) {
+ Irssi::printformat(MSGLEVEL_CRAP, "ascii_cmd_syntax", "Colme", "Missing arguments", $usage);
+ return;
+ };
+
+ return unless (ascii_test("Colme", "sW", $server, $witem));
+ $witem->command("me ".colorline($mode, $text));
+}
+
+# void cmd_coltopic()
+# handles /coltopic
+sub cmd_coltopic {
+ my $usage = "/COLTOPIC [-1234] <text>";
+ my ($arguments, $server, $witem) = @_;
+ my $mode = colormode();
+ my $text;
+
+ $ascii_last_color = randcolor();
+
+ my @foo = split(/ /, $arguments);
+ while ($_ = shift(@foo))
+ {
+ /^-(1|2|3|4)$/ and $mode = $_, next;
+ /^-/ and Irssi::printformat(MSGLEVEL_CRAP, "ascii_cmd_syntax", "Coltopic", "Unknown argument: $_", $usage), return;
+ $text = ($#foo < 0) ? $_ : $_ . " " . join(" ", @foo);
+ last;
+ };
+
+ unless (length($text)) {
+ Irssi::printformat(MSGLEVEL_CRAP, "ascii_cmd_syntax", "Coltopic", "Missing arguments", $usage);
+ return;
+ };
+
+ return unless (ascii_test("Coltopic", "sw", $server, $witem));
+
+ $server->command("topic " . Irssi::active_win()->get_active_name() . " " . colorline($mode, $text));
+};
+
+# void cmd_colkick()
+# handles /colkick
+sub cmd_colkick {
+ my $usage = "/COLKICK [-1234] [nick(,nick_1,...,nick_n)] <reason>";
+ my ($arguments, $server, $witem) = @_;
+ my $kickreason = Irssi::settings_get_str("ascii_default_kickreason");
+ my $mode = colormode();
+ my $who = undef;
+
+ $ascii_last_color = randcolor();
+ $kickreason = $ascii_default_kickreason unless ($kickreason);
+
+ my @foo = split(/ /, $arguments);
+ while ($_ = shift(@foo))
+ {
+ /^-(1|2|3|4)$/ and $mode = $_, next;
+ /^-/ and Irssi::printformat(MSGLEVEL_CRAP, "ascii_cmd_syntax", "Colkick", "Unknown argument: $_", $usage), return;
+ $kickreason = join(" ", @foo) if ($#foo >= 0);
+ $who = $_;
+ last;
+ };
+
+ if (!$who or !length($kickreason)) {
+ Irssi::printformat(MSGLEVEL_CRAP, "ascii_cmd_syntax", "Colkick", "Missing arguments", $usage);
+ return;
+ };
+
+ return unless (ascii_test("Colkick", "swo", $server, $witem));
+ $witem->command("kick $who ".colorline($mode, $kickreason));
+};
+
+# void cmd_colquit()
+# handles /colquit
+sub cmd_colquit {
+ my $usage = "/COLQUIT [-1234] <reason>";
+ my ($arguments, $server, $witem) = @_;
+ my $quitreason = Irssi::settings_get_str("ascii_default_quitreason");
+ my $mode = colormode();
+
+ $ascii_last_color = randcolor();
+ $quitreason = $ascii_default_quitreason unless ($quitreason);
+
+ my @foo = split(/ /, $arguments);
+ while ($_ = shift(@foo))
+ {
+ /^-(1|2|3|4)$/ and $mode = $_, next;
+ /^-/ and Irssi::printformat(MSGLEVEL_CRAP, "ascii_cmd_syntax", "Colquit", "Unknown argument: $_", $usage), return;
+ $quitreason = ($#foo < 0) ? $_ : $_ . " " . join(" ", @foo);
+ last;
+ };
+
+ unless (length($quitreason)) {
+ Irssi::printformat(MSGLEVEL_CRAP, "ascii_cmd_syntax", "Colquit", "Missing arguments", $usage);
+ return;
+ };
+
+ return unless (ascii_test("Colquit", "s", $server, $witem));
+ $server->command("quit " . colorline($mode, $quitreason));
+}
+
+# registering settings
+Irssi::settings_add_str("misc", "ascii_default_font", $ascii_default_font);
+Irssi::settings_add_str("misc", "ascii_default_kickreason", $ascii_default_kickreason);
+Irssi::settings_add_str("misc", "ascii_default_quitreason", $ascii_default_quitreason);
+Irssi::settings_add_str("misc", "ascii_default_prefix", "");
+Irssi::settings_add_int("misc", "ascii_default_colormode", 1);
+Irssi::settings_add_str("misc", "ascii_figlet_path", find_figlet_path);
+
+# binding commands
+Irssi::command_bind("ascii", "cmd_ascii");
+Irssi::command_bind("colsay", "cmd_colsay");
+Irssi::command_bind("colme", "cmd_colme");
+Irssi::command_bind("coltopic", "cmd_coltopic");
+Irssi::command_bind("colkick", "cmd_colkick");
+Irssi::command_bind("colquit", "cmd_colquit");
diff --git a/scripts/auto_away.pl b/scripts/auto_away.pl
new file mode 100644
index 0000000..1c2980f
--- /dev/null
+++ b/scripts/auto_away.pl
@@ -0,0 +1,90 @@
+use Irssi;
+use Irssi::TextUI;
+use strict;
+use vars qw($VERSION %IRSSI);
+
+#Setting variables:
+
+#first_away_message - The first /away messsage
+#second_away_message - The second /away message
+#first_away_timeout - Number of seconds to activate the first away state
+#second_away_timeout - Number of seconds to activate the second away state
+#away_servers - list of servertags seperated by spaces where auto_away will work.
+# If empty (/set -clear away_servers, it will work on every network
+#
+# CHANGELOG:
+# 21 DEC 2004:
+# the timer is only being reset when pressing enter. and the away timer starts counting after the last time you pressed enter.
+# this is less CPU consuming :-D
+
+$VERSION = '0.2';
+%IRSSI = (
+ authors => 'Tijmen Ruizendaal',
+ contact => 'tijmen@fokdat.nl',
+ name => 'auto_away.pl',
+ description => 'server specific autoaway with two different away states at different intervals',
+ license => 'GPLv2',
+ url => 'http://the-timing.nl/stuff/irssi-bitlbee',
+ changed => '2004-12-21',
+);
+
+
+my $timer;
+
+Irssi::settings_add_str('misc', 'first_away_message', undef);
+Irssi::settings_add_str('misc', 'second_away_message', undef);
+Irssi::settings_add_int('misc', 'first_away_timeout', undef);
+Irssi::settings_add_int('misc', 'second_away_timeout', undef);
+Irssi::settings_add_str('misc', 'away_servers', undef);
+
+sub reset_timer{
+ my $key=shift;
+ if($key == 10){
+ my (@servers) = Irssi::servers();
+ foreach my $server (@servers) {
+ if($server->{usermode_away} == 1){
+ $server->command("AWAY -one");
+ }
+ }
+ Irssi::timeout_remove($timer);
+ my $timeout = Irssi::settings_get_int('first_away_timeout');
+ if ($timeout){
+ $timer = Irssi::timeout_add_once($timeout*1000, 'first_away', undef); ## activate first away state
+ }
+ }
+}
+sub first_away{
+ away(1);
+ my $timeout = Irssi::settings_get_int('second_away_timeout');
+ if ($timeout){
+ Irssi::timeout_remove($timer);
+ $timer = Irssi::timeout_add_once($timeout*1000, 'away', 2); ## activate second away state
+ }
+}
+sub away{
+ my $state = shift;
+ my $server_string = Irssi::settings_get_str('away_servers');
+ my (@away_servers) = split (/ +/, $server_string);
+ my (@servers) = Irssi::servers();
+ my $message;
+
+ if($state == 1){
+ $message = Irssi::settings_get_str('first_away_message');
+ }elsif($state == 2){
+ $message = Irssi::settings_get_str('second_away_message');
+ }
+ if($server_string){
+ foreach my $away_server (@away_servers) {
+ #print "|$away_server|";
+ foreach my $server (@servers) {
+ if ($away_server eq $server->{tag} && ($server->{usermode_away} == 0 || $state == 2) ){
+ $server->command("AWAY -one $message");
+ }
+ }
+ }
+ }else{
+ my $server=$servers[0];
+ $server->command("AWAY -all $message");
+ }
+}
+Irssi::signal_add_last('gui key pressed', 'reset_timer');
diff --git a/scripts/auto_whois.pl b/scripts/auto_whois.pl
new file mode 100644
index 0000000..59fc1ef
--- /dev/null
+++ b/scripts/auto_whois.pl
@@ -0,0 +1,80 @@
+# /WHOIS all the users who send you a private message.
+# v0.9 for irssi by Andreas 'ads' Scherbaum
+# idea and some code taken from autowhois.pl from Timo Sirainen
+use strict;
+use Irssi;
+use vars qw($VERSION %IRSSI);
+
+$VERSION = "0.9";
+%IRSSI = (
+ authors => "Andreas \'ads\' Scherbaum",
+ contact => "ads\@ufp.de",
+ name => "auto_whois",
+ description => "/WHOIS all the users who send you a private message.",
+ license => "GPL",
+ url => "http://irssi.org/",
+ changed => "2004-02-10",
+ changes => "v0.9: don't /WHOIS if query exists for the nick already"
+);
+
+# History:
+# v0.9: don't /WHOIS if query exists for the nick already
+# now we store all nicks we have seen in the last 10 minutes
+
+my @seen = ();
+
+sub msg_private_first {
+ my ($server, $msg, $nick, $address) = @_;
+
+ # go through every stored connection and remove, if timed out
+ my $time = time();
+ my ($connection);
+ my @new = ();
+ foreach $connection (@seen) {
+ if ($connection->{lasttime} >= $time - 600) {
+ # is ok, use it
+ push(@new, $connection);
+ # all timed out connections will be dropped
+ }
+ }
+ @seen = @new;
+}
+
+sub msg_private {
+ my ($server, $msg, $nick, $address) = @_;
+
+ # look, if we already know this connection
+ my ($connection, $a);
+ my $known_to_us = 0;
+ for ($a = 0; $a <= $#seen; $a++) {
+ $connection = $seen[$a];
+ # the lc() works not exact, because irc uses another charset
+ if ($connection->{server} eq $server->{address} and $connection->{port} eq $server->{port} and lc($connection->{nick}) eq lc($nick)) {
+ $known_to_us = 1;
+ # mark as refreshed
+ $seen[$a]->{lasttime} = time();
+ last;
+ }
+ }
+
+ if ($known_to_us == 1) {
+ # all ok, return
+ return;
+ }
+
+ # now store the new connection
+ $connection = {};
+ # store our own server data here
+ $connection->{server} = $server->{address};
+ $connection->{port} = $server->{port};
+ # and the nick who queried us
+ $connection->{nick} = $nick;
+ $connection->{lasttime} = time();
+ $connection->{starttime} = time();
+ push(@seen, $connection);
+
+ $server->command("whois $nick");
+}
+
+Irssi::signal_add_first('message private', 'msg_private_first');
+Irssi::signal_add('message private', 'msg_private');
diff --git a/scripts/autoaway.pl b/scripts/autoaway.pl
new file mode 100644
index 0000000..5850360
--- /dev/null
+++ b/scripts/autoaway.pl
@@ -0,0 +1,130 @@
+# /AUTOAWAY <n> - Mark user away after <n> seconds of inactivity
+# /AWAY - play nice with autoaway
+# New, brighter, whiter version of my autoaway script. Actually works :)
+# (c) 2000 Larry Daffner (vizzie@airmail.net)
+# You may freely use, modify and distribute this script, as long as
+# 1) you leave this notice intact
+# 2) you don't pretend my code is yours
+# 3) you don't pretend your code is mine
+#
+# share and enjoy!
+
+# A simple script. /autoaway <n> will mark you as away automatically if
+# you have not typed any commands in <n> seconds. (<n>=0 disables the feature)
+# It will also automatically unmark you away the next time you type a command.
+# Note that using the /away command will disable the autoaway mechanism, as
+# well as the autoreturn. (when you unmark yourself, the autoaway wil
+# restart again)
+
+# Thanks to Adam Monsen for multiserver and config file fix
+
+use strict;
+use Irssi;
+use Irssi::Irc;
+
+use vars qw($VERSION %IRSSI);
+$VERSION = "0.5";
+%IRSSI = (
+ authors => 'Larry "Vizzie" Daffner',
+ contact => 'vizzie@airmail.net',
+ name => 'Automagic away setting',
+ description => 'Automatically goes away after defined inactivity',
+ license => 'BSD',
+ url => 'http://www.flamingpackets.net/~vizzie/irssi/',
+ changed => '2018-12-02',
+);
+
+my ($autoaway_sec, $autoaway_to_tag, $autoaway_state);
+$autoaway_state = 0;
+
+#
+# /AUTOAWAY - set the autoaway timeout
+#
+sub cmd_autoaway {
+ my ($data, $server, $channel) = @_;
+
+ if (!($data =~ /^[0-9]+$/)) {
+ Irssi::print("autoaway: usage: /autoaway <seconds>");
+ return 1;
+ }
+
+ $autoaway_sec = $data;
+
+ if ($autoaway_sec) {
+ Irssi::settings_set_int("autoaway_timeout", $autoaway_sec);
+ Irssi::print("autoaway timeout set to $autoaway_sec seconds");
+ } else {
+ Irssi::print("autoway disabled");
+ }
+
+ if (defined($autoaway_to_tag)) {
+ Irssi::timeout_remove($autoaway_to_tag);
+ $autoaway_to_tag = undef;
+ }
+
+ if ($autoaway_sec) {
+ $autoaway_to_tag =
+ Irssi::timeout_add($autoaway_sec*1000, "auto_timeout", "");
+ }
+}
+
+#
+# away = Set us away or back, within the autoaway system
+sub cmd_away {
+ my ($data, $server, $channel) = @_;
+
+ if ($data eq "") {
+ $autoaway_state = 0;
+ } else {
+ if ($autoaway_state eq 0) {
+ Irssi::timeout_remove($autoaway_to_tag);
+ $autoaway_to_tag = undef;
+ $autoaway_state = 2;
+ }
+ }
+}
+
+sub auto_timeout {
+ my ($data, $server) = @_;
+
+ # we're in the process.. don't touch anything.
+ $autoaway_state = 3;
+ foreach my $server (Irssi::servers()) {
+ $server->command("/AWAY autoaway after $autoaway_sec seconds");
+ }
+
+ Irssi::timeout_remove($autoaway_to_tag);
+ $autoaway_state = 1;
+}
+
+sub reset_timer {
+ if ($autoaway_state eq 1) {
+ $autoaway_state = 3;
+ foreach my $server (Irssi::servers()) {
+ $server->command("/AWAY");
+ }
+
+ $autoaway_state = 0;
+ }
+ if ($autoaway_state eq 0) {
+ if (defined($autoaway_to_tag)) {
+ Irssi::timeout_remove($autoaway_to_tag);
+ $autoaway_to_tag = undef();
+ }
+ if ($autoaway_sec) {
+ $autoaway_to_tag = Irssi::timeout_add($autoaway_sec*1000
+ , "auto_timeout", "");
+ }
+ }
+}
+
+Irssi::settings_add_int("misc", "autoaway_timeout", 0);
+
+$autoaway_sec = Irssi::settings_get_int("autoaway_timeout");
+reset_timer();
+
+Irssi::command_bind('autoaway', 'cmd_autoaway');
+Irssi::command_bind('away', 'cmd_away');
+Irssi::signal_add('send command', 'reset_timer');
+
+# vim:set expandtab ts=2 sw=2:
diff --git a/scripts/autochannel.pl b/scripts/autochannel.pl
new file mode 100644
index 0000000..43a15cf
--- /dev/null
+++ b/scripts/autochannel.pl
@@ -0,0 +1,69 @@
+#
+# Copyright (C) 2007-2021 by Peder Stray <peder.stray@gmail.com>
+#
+
+use strict;
+use Irssi;
+use Irssi::Irc;
+
+use vars qw{$VERSION %IRSSI};
+($VERSION) = ' $Revision: 1.3.1 $ ' =~ / (\d+(\.\d+)+) /;
+%IRSSI = (
+ name => 'autochannel',
+ authors => 'Peder Stray',
+ contact => 'peder.stray@gmail.com',
+ url => 'https://github.com/pstray/irssi-autochannel',
+ license => 'GPL',
+ description => 'Auto add channels to channel list on join',
+ );
+
+# "channel joined", channel
+sub sig_channel_joined {
+ my($c) = @_;
+
+ my $server = $c->{server};
+ my $channel = $c->{name};
+
+ return unless $server->{chatnet};
+ return unless Irssi::settings_get_bool('channel_add_on_join');
+
+ Irssi::command(sprintf "channel add %s %s %s",
+ Irssi::settings_get_bool('channel_add_with_auto')
+ ? '-auto' : '',
+ $channel,
+ $server->{chatnet},
+ );
+}
+
+# "message part", SERVER_REC, char *channel, char *nick, char *address, char *reason
+sub sig_message_part {
+ my($server,$channel,$nick,$addr,$reason) = @_;
+
+ return unless $nick eq $server->{nick};
+ return unless $server->{chatnet};
+ return unless
+ Irssi::settings_get_bool('channel_remove_on_part') ||
+ Irssi::settings_get_bool('channel_remove_auto_on_part');
+
+ if (Irssi::settings_get_bool('channel_remove_on_part')) {
+ Irssi::command(sprintf "channel remove %s %s",
+ $channel,
+ $server->{chatnet},
+ );
+ }
+ elsif (Irssi::settings_get_bool('channel_remove_auto_on_part')) {
+ Irssi::command(sprintf "channel add %s %s %s",
+ '-noauto',
+ $channel,
+ $server->{chatnet},
+ );
+ }
+}
+
+Irssi::settings_add_bool('autochannel', 'channel_add_on_join', 1);
+Irssi::settings_add_bool('autochannel', 'channel_add_with_auto', 1);
+Irssi::settings_add_bool('autochannel', 'channel_remove_auto_on_part', 1);
+Irssi::settings_add_bool('autochannel', 'channel_remove_on_part', 0);
+
+Irssi::signal_add_last('channel joined', 'sig_channel_joined');
+Irssi::signal_add_last('message part', 'sig_message_part');
diff --git a/scripts/autocycle.pl b/scripts/autocycle.pl
new file mode 100644
index 0000000..3095470
--- /dev/null
+++ b/scripts/autocycle.pl
@@ -0,0 +1,47 @@
+# Usage: /SET auto_regain_ops [On/Off]
+# /autocycle
+
+use strict;
+use vars qw($VERSION %IRSSI);
+
+use Irssi 20020313 qw( settings_add_bool settings_get_bool servers command_bind timeout_add );
+$VERSION = "0.4";
+%IRSSI = (
+ authors => "Marcin Rozycki",
+ contact => "derwan\@irssi.pl",
+ name => "autocycle",
+ description => "Auto regain ops in empty opless channels",
+ url => "http://derwan.irssi.pl",
+ license => "GNU GPL v2",
+ changed => "Fri Jan 3 23:20:06 CET 2003"
+);
+
+sub check_channels {
+ foreach my $server (servers) {
+ if ($server->{usermode} !~ m/r/ and my @channels = $server->channels) {
+ CHANNEL: while (my $channel = shift @channels) {
+ my $modes = $channel->{mode};
+ my $test = ($modes and $modes =~ m/a/) ? 1 : 0;
+ if (!$test && $channel->{synced} && $channel->{name} !~ m/^[\+\!]/ && !$channel->{ownnick}->{op}) {
+ foreach my $nick ($channel->nicks) {
+ ($nick->{nick} eq $server->{nick}) or goto CHANNEL;
+ }
+ $channel->print("Auto regain op in empty channel " . $channel->{name});
+ $channel->command("cycle");
+ }
+ }
+ }
+ }
+}
+
+sub autocycle {
+ if (settings_get_bool("auto_regain_ops")) {
+ check_channels();
+ }
+}
+
+settings_add_bool "misc", "auto_regain_ops", 1;
+command_bind "autocycle", "check_channels";
+timeout_add 60000, \&autocycle, undef;
+autocycle;
+
diff --git a/scripts/autolimit.pl b/scripts/autolimit.pl
new file mode 100644
index 0000000..d77666c
--- /dev/null
+++ b/scripts/autolimit.pl
@@ -0,0 +1,53 @@
+use strict;
+use Irssi 20010920.0000 ();
+use vars qw($VERSION %IRSSI);
+$VERSION = "1.01";
+%IRSSI = (
+ authors => 'David Leadbeater',
+ contact => 'dgl@dgl.cx',
+ name => 'autolimit',
+ description => 'does an autolimit for a channel',
+ license => 'GNU GPLv2 or later',
+ url => 'http://irssi.dgl.cx/',
+);
+
+my $sname=$IRSSI{name};
+my $channel;
+my $offset;
+my $tolerence;
+my $time;
+my $timeouttag;
+
+sub sig_setup_changed {
+ $channel=Irssi::settings_get_str($sname.'_channel');
+ $offset=Irssi::settings_get_int($sname.'_offset');
+ $tolerence=Irssi::settings_get_int($sname.'_tolerence');
+ $time=Irssi::settings_get_int($sname.'_time');
+ if (defined $timeouttag) {
+ Irssi::timeout_remove($timeouttag);
+ }
+ $timeouttag = Irssi::timeout_add($time * 1000, 'checklimit','');
+}
+
+sub checklimit {
+ my $c = Irssi::channel_find($channel);
+ return unless ref $c;
+ return unless $c->{chanop};
+ my $users = scalar @{[$c->nicks]};
+
+ if(($c->{limit} <= ($users+$offset-$tolerence)) ||
+ ($c->{limit} > ($users+$offset+$tolerence))) {
+ $c->{server}->send_raw("MODE $channel +l " . ($users+$offset));
+ }
+}
+
+Irssi::signal_add('setup changed', \&sig_setup_changed);
+
+Irssi::settings_add_str($sname, $sname.'_channel', "#channel");
+Irssi::settings_add_int($sname, $sname.'_offset', 5);
+Irssi::settings_add_int($sname, $sname.'_tolerence', 2);
+Irssi::settings_add_int($sname, $sname.'_time', 60);
+
+sig_setup_changed();
+
+# vim:set ts=3 sw=3 expandtab:
diff --git a/scripts/autoopper.pl b/scripts/autoopper.pl
new file mode 100644
index 0000000..61882f3
--- /dev/null
+++ b/scripts/autoopper.pl
@@ -0,0 +1,412 @@
+use strict;
+use Irssi;
+use POSIX;
+use Socket;
+use vars qw($VERSION %IRSSI);
+
+$VERSION = "3.7";
+%IRSSI = (
+ authors => 'Toni Salomäki',
+ name => 'autoopper',
+ contact => 'Toni@IRCNet',
+ description => 'Auto-op script with dynamic address support and random delay',
+ license => 'GNU GPLv2 or later',
+ url => 'http://vinku.dyndns.org/irssi_scripts/'
+);
+
+# This is a script to auto-op people on a certain channel (all or, represented with *).
+# Users are auto-opped on join with random delay.
+# There is a possibility to use dns aliases (for example dyndns.org) for getting the correct address.
+# The auto-op list is stored into ~/.irssi/autoop
+#
+# To get the dynamic addresses to be refreshed automatically, set value to autoop_dynamic_refresh (in hours)
+# The value will be used next time the script is loaded (at startup or manual load)
+#
+# NOTICE: the datafile is in completely different format than in 1.0 and this version cannot read it. Sorry.
+#
+
+# COMMANDS:
+#
+# autoop_show - Displays list of auto-opped hostmasks & channels
+# The current address of dynamic host is displayed in parenthesis
+#
+# autoop_add - Add new auto-op. Parameters hostmask, channel (or *) and dynamic flag
+#
+# Dynamic flag has 3 different values:
+# 0: treat host as a static ip
+# 1: treat host as an alias for dynamic ip
+# 2: treat host as an alias for dynamic ip, but do not resolve the ip (not normally needed)
+#
+# autoop_del - Remove auto-op
+#
+# autoop_save - Save auto-ops to file (done normally automatically)
+#
+# autoop_load - Load auto-ops from file (use this if you have edited the autoop -file manually)
+#
+# autoop_check - Check all channels and op people needed
+#
+# autoop_dynamic - Refresh dynamic addresses (automatically if parameter set)
+#
+# Data is stored in ~/.irssi/autoop
+# format: host channels flag
+# channels separated with comma
+# one host per line
+
+my (%oplist);
+my (@opitems);
+srand();
+
+#resolve dynamic host
+sub resolve_host {
+ my ($host, $dyntype) = @_;
+
+ if (my $iaddr = inet_aton($host)) {
+ if ($dyntype ne "2") {
+ if (my $newhost = gethostbyaddr($iaddr, AF_INET)) {
+ return $newhost;
+ } else {
+ return inet_ntoa($iaddr);
+ }
+ } else {
+ return inet_ntoa($iaddr);
+ }
+ }
+ return "error";
+}
+
+# return list of dynamic hosts with real addresses
+sub fetch_dynamic_hosts {
+ my %hostcache;
+ my $resultext;
+ foreach my $item (@opitems) {
+ next if ($item->{dynamic} ne "1" && $item->{dynamic} ne "2");
+
+ my (undef, $host) = split(/\@/, $item->{mask}, 2);
+
+ # fetch the host's real address (if not cached)
+ unless ($hostcache{$host}) {
+ $hostcache{$host} = resolve_host($host, $item->{dynamic});
+ $resultext .= $host . "\t" . $hostcache{$host} . "\n";
+ }
+ }
+ chomp $resultext;
+ return $resultext;
+}
+
+# fetch real addresses for dynamic hosts
+sub cmd_change_dynamic_hosts {
+ pipe READ, WRITE;
+ my $pid = fork();
+
+ unless (defined($pid)) {
+ Irssi::print("Can't fork - aborting");
+ return;
+ }
+
+ if ($pid > 0) {
+ # the original process, just add a listener for pipe
+ close (WRITE);
+ Irssi::pidwait_add($pid);
+ my $target = {fh => \*READ, tag => undef};
+ $target->{tag} = Irssi::input_add(fileno(READ), INPUT_READ, \&read_dynamic_hosts, $target);
+ } else {
+ # the new process, fetch addresses and write to the pipe
+ print WRITE fetch_dynamic_hosts;
+ close (READ);
+ close (WRITE);
+ POSIX::_exit(1);
+ }
+}
+
+# get dynamic hosts from pipe and change them to users
+sub read_dynamic_hosts {
+ my $target = shift;
+ my $rh = $target->{fh};
+ my %hostcache;
+
+ while (<$rh>) {
+ chomp;
+ my ($dynhost, $realhost, undef) = split (/\t/, $_, 3);
+ $hostcache{$dynhost} = $realhost;
+ }
+
+ close($target->{fh});
+ Irssi::input_remove($target->{tag});
+
+ my $mask;
+ my $count = 0;
+ undef %oplist if (%oplist);
+
+ foreach my $item (@opitems) {
+ if ($item->{dynamic} eq "1" || $item->{dynamic} eq "2") {
+ my ($user, $host) = split(/\@/, $item->{mask}, 2);
+
+ $count++ if ($item->{dynmask} ne $hostcache{$host});
+ $item->{dynmask} = $hostcache{$host};
+ $mask = $user . "\@" . $hostcache{$host};
+ } else {
+ $mask = $item->{mask};
+ }
+
+ foreach my $channel (split (/,/,$item->{chan})) {
+ $oplist{$channel} .= "$mask ";
+ }
+ }
+ chop %oplist;
+ Irssi::print("$count dynamic hosts changed") if ($count > 0);
+}
+
+# Save data to file
+sub cmd_save_autoop {
+ my $file = Irssi::get_irssi_dir."/autoop";
+ open FILE, ">", "$file" or return;
+
+ foreach my $item (@opitems) {
+ printf FILE ("%s\t%s\t%s\n", $item->{mask}, $item->{chan}, $item->{dynamic});
+ }
+
+ close FILE;
+ Irssi::print("Auto-op list saved to $file");
+}
+
+# Load data from file
+sub cmd_load_autoop {
+ my $file = Irssi::get_irssi_dir."/autoop";
+ open FILE, "<","$file" or return;
+ undef @opitems if (@opitems);
+
+ while (<FILE>) {
+ chomp;
+ my ($mask, $chan, $dynamic, undef) = split (/\t/, $_, 4);
+ my $item = {mask=>$mask, chan=>$chan, dynamic=>$dynamic, dynmask=>undef};
+ push (@opitems, $item);
+ }
+
+ close FILE;
+ Irssi::print("Auto-op list reloaded from $file");
+ cmd_change_dynamic_hosts;
+}
+
+# Show who's being auto-opped
+sub cmd_show_autoop {
+ my %list;
+ foreach my $item (@opitems) {
+ foreach my $channel (split (/,/,$item->{chan})) {
+ $list{$channel} .= "\n" . $item->{mask};
+ $list{$channel} .= " (" . $item->{dynmask} . ")" if ($item->{dynmask});
+ }
+ }
+
+ Irssi::print("All channels:" . $list{"*"}) if (exists $list{"*"});
+ delete $list{"*"}; #this is already printed, so remove it
+ foreach my $channel (sort (keys %list)) {
+ Irssi::print("$channel:" . $list{$channel});
+ }
+}
+
+# Add new auto-op
+sub cmd_add_autoop {
+ my ($data) = @_;
+ my ($mask, $chan, $dynamic, undef) = split(" ", $data, 4);
+ my $found = 0;
+
+ if ($chan eq "" || $mask eq "" || !($mask =~ /.+!.+@.+/)) {
+ Irssi::print("Invalid hostmask. It must contain both ! and @.") if (!($mask =~ /.+!.+@.+/));
+ Irssi::print("Usage: /autoop_add <hostmask> <*|#channel> [dynflag]");
+ Irssi::print("Dynflag: 0 normal, 1 dynamic, 2 dynamic without resolving");
+ return;
+ }
+
+ foreach my $item (@opitems) {
+ next unless ($item->{mask} eq $mask);
+ $found = 1;
+ $item->{chan} .= ",$chan";
+ last;
+ }
+
+ if ($found == 0) {
+ $dynamic = "0" unless ($dynamic eq "1" || $dynamic eq "2");
+ my $item = {mask=>$mask, chan=>$chan, dynamic=>$dynamic, dynmask=>undef};
+ push (@opitems, $item);
+ }
+
+ $oplist{$chan} .= " $mask";
+
+ Irssi::print("Added auto-op: $chan: $mask");
+}
+
+# Remove autoop
+sub cmd_del_autoop {
+ my ($data) = @_;
+ my ($mask, $channel, undef) = split(" ", $data, 3);
+
+ if ($channel eq "" || $mask eq "") {
+ Irssi::print("Usage: /autoop_del <hostmask> <*|#channel>");
+ return;
+ }
+
+ my $i=0;
+ foreach my $item (@opitems) {
+ if ($item->{mask} eq $mask) {
+ if ($channel eq "*" || $item->{chan} eq $channel) {
+ splice @opitems, $i, 1;
+ Irssi::print("Removed: $mask");
+ } else {
+ my $newchan;
+ foreach my $currchan (split (/,/,$item->{chan})) {
+ if ($channel eq $currchan) {
+ Irssi::print("Removed: $channel from $mask");
+ } else {
+ $newchan .= $currchan . ",";
+ }
+ }
+ chop $newchan;
+ Irssi::print("Couldn't remove $channel from $mask") if ($item->{chan} eq $newchan);
+ $item->{chan} = $newchan;
+ }
+ last;
+ }
+ $i++;
+ }
+}
+
+# Do the actual opping
+sub do_autoop {
+ my $target = shift;
+
+ Irssi::timeout_remove($target->{tag});
+
+ # nick has to be fetched again, because $target->{nick}->{op} is not updated
+ my $nick = $target->{chan}->nick_find($target->{nick}->{nick});
+
+ # if nick is changed during delay, it will probably be lost here...
+ if ($nick->{nick} ne "") {
+ if ($nick->{host} eq $target->{nick}->{host}) {
+ $target->{chan}->command("op " . $nick->{nick}) unless ($nick->{op});
+ } else {
+ Irssi::print("Host changed for nick during delay: " . $nick->{nick});
+ }
+ }
+ undef $target;
+}
+
+# Someone joined, might be multiple person. Check if opping is needed
+sub event_massjoin {
+ my ($channel, $nicklist) = @_;
+ my @nicks = @{$nicklist};
+
+ return if (!$channel->{chanop});
+
+ my $masks = $oplist{"*"} . " " . $oplist{$channel->{name}};
+
+ foreach my $nick (@nicks) {
+ my $host = $nick->{host};
+ $host=~ s/^~//g; # remove this if you don't want to strip ~ from username (no ident)
+ next unless ($channel->{server}->masks_match($masks, $nick->{nick}, $host));
+
+ my $min_delay = Irssi::settings_get_int("autoop_min_delay");
+ my $max_delay = Irssi::settings_get_int("autoop_max_delay") - $min_delay;
+ my $delay = int(rand($max_delay)) + $min_delay;
+
+ my $target = {nick => $nick, chan => $channel, tag => undef};
+
+ $target->{tag} = Irssi::timeout_add($delay, 'do_autoop', $target);
+ }
+
+}
+
+# Check channel op status
+sub do_channel_check {
+ my $target = shift;
+
+ Irssi::timeout_remove($target->{tag});
+
+ my $channel = $target->{chan};
+ my $server = $channel->{server};
+ my $masks = $oplist{"*"} . " " . $oplist{$channel->{name}};
+ my $nicks = "";
+
+ foreach my $nick ($channel->nicks()) {
+ next if ($nick->{op});
+
+ my $host = $nick->{host};
+ $host=~ s/^~//g; # remove this if you don't want to strip ~ from username (no ident)
+
+ if ($server->masks_match($masks, $nick->{nick}, $host)) {
+ $nicks = $nicks . " " . $nick->{nick};
+ }
+ }
+ $channel->command("op" . $nicks) unless ($nicks eq "");
+
+ undef $target;
+}
+
+#check people needing opping after getting ops
+sub event_nickmodechange {
+ my ($channel, $nick, $setby, $mode, $type) = @_;
+
+ return unless (($mode eq '@') && ($type eq '+'));
+
+ my $server = $channel->{server};
+
+ return unless ($server->{nick} eq $nick->{nick});
+
+ my $min_delay = Irssi::settings_get_int("autoop_min_delay");
+ my $max_delay = Irssi::settings_get_int("autoop_max_delay") - $min_delay;
+ my $delay = int(rand($max_delay)) + $min_delay;
+
+ my $target = {chan => $channel, tag => undef};
+
+ $target->{tag} = Irssi::timeout_add($delay, 'do_channel_check', $target);
+}
+
+#Check all channels / all users if someone needs to be opped
+sub cmd_autoop_check {
+ my ($data, $server, $witem) = @_;
+
+ foreach my $channel ($server->channels()) {
+ Irssi::print("Checking: " . $channel->{name});
+ next if (!$channel->{chanop});
+
+ my $masks = $oplist{"*"} . " " . $oplist{$channel->{name}};
+
+ foreach my $nick ($channel->nicks()) {
+ next if ($nick->{op});
+
+ my $host = $nick->{host};
+ $host=~ s/^~//g; # remove this if you don't want to strip ~ from username (no ident)
+
+ if ($server->masks_match($masks, $nick->{nick}, $host)) {
+ $channel->command("op " . $nick->{nick}) if (!$nick->{op});
+ }
+ }
+ }
+}
+
+#Set dynamic refresh period.
+sub set_dynamic_refresh {
+ my $refresh = Irssi::settings_get_int("autoop_dynamic_refresh");
+ return if ($refresh == 0);
+
+ Irssi::print("Dynamic host refresh set for $refresh hours");
+ Irssi::timeout_add($refresh*3600000, 'cmd_change_dynamic_hosts', undef);
+}
+
+Irssi::command_bind('autoop_show', 'cmd_show_autoop');
+Irssi::command_bind('autoop_add', 'cmd_add_autoop');
+Irssi::command_bind('autoop_del', 'cmd_del_autoop');
+Irssi::command_bind('autoop_save', 'cmd_save_autoop');
+Irssi::command_bind('autoop_load', 'cmd_load_autoop');
+Irssi::command_bind('autoop_check', 'cmd_autoop_check');
+Irssi::command_bind('autoop_dynamic', 'cmd_change_dynamic_hosts');
+Irssi::signal_add_last('massjoin', 'event_massjoin');
+Irssi::signal_add_last('setup saved', 'cmd_save_autoop');
+Irssi::signal_add_last('setup reread', 'cmd_load_autoop');
+Irssi::signal_add_last("nick mode changed", "event_nickmodechange");
+Irssi::settings_add_int('autoop', 'autoop_max_delay', 15000);
+Irssi::settings_add_int('autoop', 'autoop_min_delay', 1000);
+Irssi::settings_add_int('autoop', 'autoop_dynamic_refresh', 0);
+
+
+cmd_load_autoop;
+set_dynamic_refresh;
diff --git a/scripts/autorealname.pl b/scripts/autorealname.pl
new file mode 100644
index 0000000..33103e6
--- /dev/null
+++ b/scripts/autorealname.pl
@@ -0,0 +1,304 @@
+# Print realname of everyone who join to channels
+# for irssi 0.7.99 by Timo Sirainen
+
+use Irssi 20011207;
+use strict;
+use vars qw($VERSION %IRSSI);
+$VERSION = "0.8.7";
+%IRSSI = (
+ authors => "Timo \'cras\' Sirainen, Bastian Blank",
+ contact => "tss\@iki.fi, waldi\@debian.org",
+ name => "auto realname",
+ description => "Print realname of everyone who join to channels",
+ license => "GPLv2 or later",
+ url => "http://irssi.org/",
+ changed => "2021-01-16"
+);
+
+# v0.8.7 changes - bw1
+# - fix Can't call method "nick_find" ... line 282.
+# v0.8.6 changes - Juhamatti Niemelä
+# - fix join msg printing when there are multiple common channels
+# v0.8.5 changes - Bastian Blank
+# - really use the introduced state variable
+# v0.8.4 changes - Bastian Blank
+# - fix queue abort
+# v0.8.3 changes - Bastian Blank
+# - on queue abort print any join messages
+# v0.8.2 changes - Bastian Blank
+# - use channelname instead of Irssi::Irc::Channel for channelname within message on join
+# v0.8.1 changes - Bastian Blank
+# - print any join messages on abort
+# - also remove any timeouts
+# v0.8 changes - Bastian Blank
+# - join message includes realname
+# - add timeout
+# - don't print realname for our self
+# - change license because german law doesn't allow to give away the copyright
+# v0.71 changes
+# - a bit safer now with using "redirect last"
+# v0.7 changes
+# - pretty much a rewrite - shouldn't break anymore
+# v0.62 changes
+# - upgraded redirection to work with latest CVS irssi - lot easier
+# to handle it this time :)
+# v0.61 changes
+# - forgot to reset %chan_list..
+# v0.6 changes
+# - works now properly when a nick joins to multiple channels
+# v0.5 changes
+# - Use "message join" so we won't ask realname for ignored people
+
+Irssi::theme_register([
+ 'join', '{channick_hilight $0} {chanhost_hilight $1} has joined {channel $2}',
+ 'join_realname', '{channick_hilight $0} ({hilight $1}) {chanhost_hilight $2} has joined {channel $3}',
+ 'join_realname_only', '{channick_hilight $0} is {hilight $1}',
+]);
+
+my $whois_queue_length_before_abort = 10; # max. whois queue length before we should abort the whois queries for next few seconds (people are probably joining behind a netsplit)
+my $whois_abort_seconds = 10; # wait for 10 secs when there's been too many joins
+my $debug = 0;
+
+my %servers;
+
+my %whois_waiting;
+my %whois_queue;
+my %aborted;
+my %chan_list;
+
+sub sig_connected {
+ my $server = shift;
+ $servers{$server->{tag}} = {
+ abort_time => 0, # if join event is received before this, abort
+ waiting => 0, # waiting reply for WHOIS request
+ queue => [], # whois queue
+ nicks => {} # nick => [ #chan1, #chan2, .. ]
+ };
+}
+
+sub sig_disconnected {
+ my $server = shift;
+ delete $servers{$server->{tag}};
+}
+
+sub msg_join {
+ my ($server, $channame, $nick, $host) = @_;
+ $channame =~ s/^://;
+ my $rec = $servers{$server->{tag}};
+
+ # don't display realname for our self
+ return if ($nick eq $server->{nick});
+
+ # don't whois people who netjoin back
+ return if ($server->netsplit_find($nick, $host));
+
+ return if (time < $rec->{abort_time});
+ $rec->{abort_time} = 0;
+
+ Irssi::signal_stop();
+
+ # check if the nick is already found from another channel
+ {
+ my $ret = 0;
+ foreach my $channel ($server->channels()) {
+ my $nickrec = $channel->nick_find($nick);
+ if ($nickrec && $nickrec->{realname}) {
+ # this user already has a known realname - use it.
+ $channel = $server->channel_find($channame);
+ $channel->printformat(MSGLEVEL_JOINS, 'join_realname', $nick, $nickrec->{realname}, $nickrec->{host}, $channel->{name});
+ $channel->print("autorealname: already found: $nick", MSGLEVEL_CLIENTCRAP) if $debug;
+ $ret = 1;
+ last;
+ }
+ }
+
+ return if ($ret);
+ }
+
+ # save channel to nick specific hash so we can later check which channels
+ # it needs to print the realname
+
+ if ($rec->{nicks}->{$nick}) {
+ # don't send the WHOIS again if nick is already in queue
+ push @{$rec->{nicks}->{$nick}->{chans_join}}, $channame;
+ push @{$rec->{nicks}->{$nick}->{chans_realname}}, $channame;
+ $rec->{nicks}->{$nick}->{state} = 0;
+ my $channel = $server->channel_find($channame);
+ $channel->print("autorealname: already in queue: $nick", MSGLEVEL_CLIENTCRAP) if $debug;
+ }
+ else {
+ $rec->{nicks}->{$nick} = {};
+ $rec->{nicks}->{$nick}->{chans_join} = [$channame];
+ $rec->{nicks}->{$nick}->{chans_realname} = [$channame];
+ $rec->{nicks}->{$nick}->{state} = 0;
+
+ # add the nick to queue
+ push @{$rec->{queue}}, $nick;
+
+ # timeout
+ $rec->{nicks}->{$nick}->{timeout} = Irssi::timeout_add(1000, \&timeout_whois, [$server, $nick]);
+ my $channel = $server->channel_find($channame);
+ $channel->print("autorealname: add to queue: $nick", MSGLEVEL_CLIENTCRAP) if $debug;
+ }
+
+ if (scalar @{$rec->{queue}} >= $whois_queue_length_before_abort) {
+ # too many whois requests in queue, abort
+ foreach $nick (@{$rec->{queue}}) {
+ foreach my $channel (@{$rec->{nicks}->{$nick}->{chans_join}}) {
+ my $chanrec = $server->channel_find($channel);
+ my $nickrec = $chanrec->nick_find($nick);
+ if ($chanrec && $nickrec) {
+ $chanrec->printformat(MSGLEVEL_JOINS, 'join', $nick, $nickrec->{host}, $channel);
+ $chanrec->print("autorealname: queue abort: $nick", MSGLEVEL_CLIENTCRAP) if $debug;
+ }
+ }
+ Irssi::timeout_remove($rec->{nicks}->{$nick}->{timeout}) if (!($rec->{nicks}->{$nick}->{state} & 2));
+ delete $rec->{nicks}->{$nick};
+ }
+ $rec->{queue} = [];
+ $rec->{abort_time} = time+$whois_abort_seconds;
+ return;
+ }
+
+ # waiting for WHOIS reply..
+ return if $rec->{waiting};
+
+ request_whois($server, $rec);
+}
+
+sub request_whois {
+ my ($server, $rec) = @_;
+ return if (scalar @{$rec->{queue}} == 0);
+
+ my @whois_nicks = splice(@{$rec->{queue}}, 0, $server->{max_whois_in_cmd});
+ my $whois_query = join(',', @whois_nicks);
+
+ # ignore all whois replies except the first line of the WHOIS reply
+ my $redir_arg = $whois_query.' '.join(' ', @whois_nicks);
+ $server->redirect_event("whois", 1, $redir_arg, 0,
+ "redir autorealname_whois_last", {
+ "event 311" => "redir autorealname_whois",
+ "event 401" => "redir autorealname_whois_unknown",
+ "redirect last" => "redir autorealname_whois_last",
+ "" => "event empty" });
+
+ $server->send_raw("WHOIS :$whois_query");
+ $rec->{waiting} = 1;
+}
+
+sub event_whois {
+ my ($server, $data) = @_;
+ my ($num, $nick, $user, $host, $empty, $realname) = split(/ +/, $data, 6);
+ $realname =~ s/^://;
+ my $rec = $servers{$server->{tag}};
+
+ return if not $rec->{nicks}->{$nick};
+
+ $rec->{nicks}->{$nick}->{state} |= 1;
+
+ if (!($rec->{nicks}->{$nick}->{state} & 2)) {
+ Irssi::timeout_remove($rec->{nicks}->{$nick}->{timeout});
+ foreach my $channel (@{$rec->{nicks}->{$nick}->{chans_join}}) {
+ my $chanrec = $server->channel_find($channel);
+ my $nickrec = $chanrec->nick_find($nick);
+ if ($chanrec && $nickrec) {
+ $chanrec->printformat(MSGLEVEL_JOINS, 'join_realname', $nick, $realname, $nickrec->{host}, $channel);
+ $chanrec->print("autorealname: got whois: $nick, state: ".$rec->{nicks}->{$nick}->{state}, MSGLEVEL_CLIENTCRAP) if $debug;
+ }
+ }
+ $rec->{nicks}->{$nick}->{chans_join} = [];
+ $rec->{nicks}->{$nick}->{chans_realname} = [];
+ $rec->{nicks}->{$nick}->{state} |= 2;
+ }
+ else {
+ foreach my $channel (@{$rec->{nicks}->{$nick}->{chans_realname}}) {
+ my $chanrec = $server->channel_find($channel);
+ next unless (defined $chanrec);
+ my $nickrec = $chanrec->nick_find($nick);
+ if ($chanrec && $nickrec) {
+ $chanrec->printformat(MSGLEVEL_JOINS, 'join_realname_only', $nick, $realname);
+ $chanrec->print("autorealname: got whois: $nick, state: ".$rec->{nicks}->{$nick}->{state}, MSGLEVEL_CLIENTCRAP) if $debug;
+ }
+ }
+ $rec->{nicks}->{$nick}->{chans_realname} = [];
+ }
+
+ delete $rec->{nicks}->{$nick} if ($rec->{nicks}->{$nick}->{state} == 3);
+}
+
+sub event_whois_unknown {
+ my ($server, $data) = @_;
+ my ($temp, $nick) = split(" ", $data);
+ my $rec = $servers{$server->{tag}};
+
+ return if not $rec->{nicks}->{$nick};
+
+ $rec->{nicks}->{$nick}->{state} |= 1;
+
+ if (!($rec->{nicks}->{$nick}->{state} & 2)) {
+ Irssi::timeout_remove($rec->{nicks}->{$nick}->{timeout});
+ foreach my $channel (@{$rec->{nicks}->{$nick}->{chans_join}}) {
+ my $chanrec = $server->channel_find($channel);
+ my $nickrec = $chanrec->nick_find($nick);
+ if ($chanrec && $nickrec) {
+ $chanrec->printformat(MSGLEVEL_JOINS, 'join', $nick, $nickrec->{host}, $channel);
+ $chanrec->print("autorealname: got unknown whois: $nick", MSGLEVEL_CLIENTCRAP) if $debug;
+ }
+ }
+ $rec->{nicks}->{$nick}->{chans_join} = [];
+ } else {
+ foreach my $channel (@{$rec->{nicks}->{$nick}->{chans_join}}) {
+ my $chanrec = $server->channel_find($channel);
+ $chanrec->print("autorealname: got unknown whois (already considered): $nick", MSGLEVEL_CLIENTCRAP) if $debug;
+ }
+ }
+
+ delete $rec->{nicks}->{$nick} if ($rec->{nicks}->{$nick}->{state} == 3);
+}
+
+sub event_whois_last {
+ my $server = shift;
+ my $rec = $servers{$server->{tag}};
+
+ $rec->{waiting} = 0;
+ request_whois($server, $rec);
+}
+
+foreach my $server (Irssi::servers()) {
+ sig_connected($server);
+}
+
+sub timeout_whois {
+ my $server = shift @{$_[0]};
+ my $nick = shift @{$_[0]};
+
+ my $rec = $servers{$server->{tag}};
+
+ return if not $rec->{nicks}->{$nick};
+
+ Irssi::timeout_remove($rec->{nicks}->{$nick}->{timeout});
+ $rec->{nicks}->{$nick}->{state} |= 2;
+
+ my @channels = @{$rec->{nicks}->{$nick}->{chans_join}};
+ foreach my $channel (@channels) {
+ my $chanrec = $server->channel_find($channel);
+ next unless (defined $chanrec);
+ my $nickrec = $chanrec->nick_find($nick);
+ if ($nickrec && $chanrec) {
+ $chanrec->printformat(MSGLEVEL_JOINS, 'join', $nick, $nickrec->{host}, $channel);
+ $chanrec->print("autorealname: timeout: $nick, state: ".$rec->{nicks}->{$nick}->{state}, MSGLEVEL_CLIENTCRAP) if $debug;
+ }
+ }
+
+ $rec->{nicks}->{$nick}->{chans_join} = [];
+}
+
+Irssi::signal_add( {
+ 'server connected' => \&sig_connected,
+ 'server disconnected' => \&sig_disconnected,
+ 'message join' => \&msg_join,
+ 'redir autorealname_whois' => \&event_whois,
+ 'redir autorealname_whois_unknown' => \&event_whois_unknown,
+ 'redir autorealname_whois_last' => \&event_whois_last });
+
+# vim:set sw=2 ts=8 et:
diff --git a/scripts/autorejoinpunish.pl b/scripts/autorejoinpunish.pl
new file mode 100644
index 0000000..31f6e68
--- /dev/null
+++ b/scripts/autorejoinpunish.pl
@@ -0,0 +1,124 @@
+##
+# autorejoinpunish - your solution for banning people who don't
+# know what kicks are for.
+# This script is for irssi 0.8.4, and was written by Paul Raade,
+# laaama in IRCNet.
+##
+# Explanations for the settings, with defaults shown:
+#
+# /set autorejoinpunish_time_limit 3
+# - The time limit in seconds for measuring what is an
+# autorejoin, and what is not.
+# /set autorejoinpunish_kickban_message Kickban for autorejoining.
+# - Kick reason, if kickban was selected.
+# /set autorejoinpunish_knockout ON
+# - Whether kick or knockout. As default, knockout is
+# selected, so that the bans will be removed automatically.
+# /set autorejoinpunish_knockout_time 60
+# - Time in seconds how long a ban will be kept if
+# knockout is selected.
+# /set autorejoinpunish_knockout_message Temporary ban for autorejoining.
+# - Kick reason, if knockout was selected.
+# /set autorejoinpunish_channels
+# - Space separated list of channels on which autorejoin punishment
+# be used will
+# /set autorejoinpunish_only_own_kicks ON
+# - If set ON, only people kicked by you will be banned.
+##
+# Changelog:
+# - 0.2: Better way of checking channels, /set autorejoinpunish_only_own_kicks added.
+# - 0.1: Initial release.
+##
+# Happy banning! ;)
+##
+
+use strict;
+use Irssi qw(settings_get_str settings_get_int settings_get_bool
+timeout_add settings_add_int settings_add_str settings_add_bool
+signal_add_first command server_find_tag);
+
+use vars qw(%IRSSI $VERSION);
+$VERSION = '0.3';
+%IRSSI = (
+ authors => 'Paul \'laaama\' Raade',
+ contact => 'paul\@raade.org',
+ name => 'Autorejoin punisher',
+ description => 'Kickbans or knockouts people who use autorejoin on kick.',
+ license => 'BSD',
+ url => 'http://www.raade.org/~paul/irssi/scripts/',
+ changes => 'Changed signals to be added to the top of the list to make the script work with scripts that stop the signals (autorealname, for example).',
+ changed => 'Thu 02 May 2002, 22:04:48 EEST'
+);
+
+my %victims;
+my %bans;
+
+sub message_kick { # Set a time stamp for people who are kicked.
+ # "message kick", SERVER_REC, char *channel, char *nick, char *kicker, char *address, char *reason
+ my ($server, $channel, $nick, $kicker, $address, undef) = @_;
+ if ((settings_get_bool('autorejoinpunish_only_own_kicks') == 0) || (settings_get_bool('autorejoinpunish_only_own_kicks') == 1 && ($kicker eq $server->{nick}) )) {
+ foreach my $item (split(' ', lc(settings_get_str('autorejoinpunish_channels')))) {
+ if ((lc $channel) eq $item) { $victims{$channel}{$nick} = time(); }
+ }
+ }
+}
+
+sub message_join { # Check for recent kicks,
+ # "message join", SERVER_REC, char *channel, char *nick, char *address
+ my ($server, $channel, $nick, $address) = @_;
+ if ($victims{$channel}{$nick} && ((time()-$victims{$channel}{$nick}) <= settings_get_int('autorejoinpunish_time_limit'))) {
+ if (settings_get_bool('autorejoinpunish_knockout') == 1) {
+ $server->command('mode' . ' ' . $channel . ' +b *!' . $address);
+ $server->command('kick' . ' ' . $channel . ' ' . $nick . ' ' . settings_get_str('autorejoinpunish_knockout_message'));
+ $bans{$server->{tag}}{time()} = $channel . '/' . $address;
+ } else {
+ $server->command('mode' . ' ' . $channel . ' +b *!' . $address);
+ $server->command('kick' . ' ' . $channel . ' ' . $nick . ' ' . settings_get_str('autorejoinpunish_kickban_message'));
+ }
+ }
+ delete $victims{$channel}{$nick};
+}
+
+sub clean_list {
+ my ($channelkey, $nickkey);
+ if (%victims) {
+ foreach $channelkey (keys %victims) {
+ foreach $nickkey (keys %{$victims{$channelkey}}) {
+ if ((time()-$victims{$channelkey}{$nickkey}) > settings_get_int('autorejoinpunish_time_limit')) {
+ delete $victims{$channelkey}{$nickkey};
+ }
+ }
+ }
+ }
+}
+
+sub check_bans {
+ my ($server, $timestamp);
+ if (%bans) {
+ foreach $server (keys %bans) {
+ foreach $timestamp (keys %{$bans{$server}}) {
+ if ((time()-$timestamp) > settings_get_int('autorejoinpunish_knockout_time')) {
+ my ($channel, $address) = split(/\//, $bans{$server}{$timestamp});
+ server_find_tag($server)->command('mode' . ' ' . $channel . ' -b *!' . $address);
+ delete $bans{$server}{$timestamp};
+ }
+ }
+ }
+ }
+}
+
+
+settings_add_int ('misc', 'autorejoinpunish_time_limit', '3');
+settings_add_str ('misc', 'autorejoinpunish_kickban_message', 'Kickban for autorejoining.');
+settings_add_bool ('misc', 'autorejoinpunish_knockout', '1');
+settings_add_int ('misc', 'autorejoinpunish_knockout_time', '60');
+settings_add_str ('misc', 'autorejoinpunish_knockout_message', 'Temporary ban for autorejoining.');
+settings_add_str ('misc', 'autorejoinpunish_channels', '');
+settings_add_bool ('misc', 'autorejoinpunish_only_own_kicks', '1');
+
+signal_add_first 'message join' => 'message_join';
+signal_add_first 'message kick' => 'message_kick';
+
+timeout_add ('5000', 'check_bans', '');
+timeout_add ('3600000', 'clean_list', '');
+# 1h = 60min * 60s * 1000ms = 3600000ms
diff --git a/scripts/autoreminder.pl b/scripts/autoreminder.pl
new file mode 100644
index 0000000..3548b28
--- /dev/null
+++ b/scripts/autoreminder.pl
@@ -0,0 +1,147 @@
+#####################
+#
+# irssi autoreminder script.
+# Copyright (C) Terry Lewis
+# Terry Lewis <mrkennie@kryogenic.co.uk>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#####################
+#
+# Auto reminder script for irssi
+# This is really a first attempt at an irssi script,
+# really more of a hack I suppose, to auto remind
+# someone at certain intervals.
+# It will not remind at every interval defined, so its
+# kinda less annoying, but hopefully effective.
+#
+# To start:
+# /start <nick> <"reminder message"> [interval]
+# (<> = required, [] = optional)
+# reminder Message must use "" parenthasis.
+#
+# to stop reminding use /stop
+#
+# I know the code is not fantastic but I will appreciate
+# any patches for improvements, just mail them to me if
+# you do improve it :)
+#
+# I use a rather nice script called cron.pl by Piotr
+# Krukowiecki which I found at http://www.irssi.org/scripts/
+# so I can start and stop the script at certain times.
+# I hope someone finds this useful, Enjoy =)
+#
+#####################
+
+use strict;
+use vars qw($VERSION %IRSSI);
+
+use Irssi;
+$VERSION = '0.01';
+%IRSSI = (
+ authors => 'Terry Lewis',
+ contact => 'terry@kryogenic.co.uk',
+ name => 'Auto Reminder',
+ description => 'This script ' .
+ 'Reminds people ' .
+ 'to do stuff! :)',
+ license => 'GPLv2',
+);
+
+my($timeout_tag, $timeout, $state, @opts, $date, @time, @hour, $start_hour, $end_hour);
+
+
+#default state 0 meaning we are not started yet
+$state = 0;
+
+
+# /start <nick> <"message"> [interval]
+sub cmd_start {
+ if($state != 1){
+ my($data,$server,$channel) = @_;
+ @opts = split(/\s\B\"(.*)\b\"/, $data);
+
+ if($opts[0] ne ''){
+ if($opts[1] ne ''){
+ if($opts[0] =~ /\s/g){
+ Irssi::print("Invalid username");
+ }elsif($opts[1] eq ''){
+ Irssi::print("You must type a message to send");
+ }else{
+
+ $state = 1;
+
+ if($opts[2] =~ /[0-9]/g){
+ $opts[2] =~ s/\s//g;
+ $timeout = $opts[2];
+ timeout_init($timeout);
+ }else{
+ Irssi::print("Invalid interval value, using defaults (15mins)") unless $opts[2] eq '';
+ $timeout = "900000";
+ timeout_init($timeout);
+ }
+ Irssi::print "Bugging $opts[0] with message \"$opts[1]\" every \"$timeout ms\"";
+ }
+ }else{
+ Irssi::print ("Usage: /start nick \"bug_msg\" [interval] (interval is optional)");
+ }
+ }else{
+ Irssi::print ("Usage: /start nick \"bug_msg\" [interval] (interval is optional)");
+ }
+
+ }else{
+ Irssi::print "Already started";
+ }
+}
+
+# /stop
+sub cmd_stop {
+ if($state == 1){
+ $state = 0;
+ Irssi::print "No longer bugging $opts[0]";
+ Irssi::timeout_remove($timeout_tag);
+ $timeout_tag = undef;
+ }else{
+ Irssi::print "Not started";
+ }
+}
+
+sub timeout_init {
+ if($state == 1){
+
+ Irssi::timeout_remove($timeout_tag);
+ $timeout_tag = undef;
+ $timeout_tag = Irssi::timeout_add($timeout, "remind_them", "");
+ }
+}
+
+sub remind_them {
+ if($state == 1){
+ my (@servers) = Irssi::servers();
+
+ # make it random, so we dont remind at every defined interval
+ my $time = rand()*3;
+
+ if($time < 1){
+ $servers[0]->command("MSG $opts[0] Hi, this is an automated reminder, $opts[1]");
+ }
+ timeout_init($timeout);
+ }
+}
+
+
+Irssi::command_bind('start', \&cmd_start);
+Irssi::command_bind('stop', \&cmd_stop);
+
diff --git a/scripts/autoversion.pl b/scripts/autoversion.pl
new file mode 100644
index 0000000..47d4475
--- /dev/null
+++ b/scripts/autoversion.pl
@@ -0,0 +1,25 @@
+#!/usr/bin/perl
+use strict;
+use vars qw($VERSION %IRSSI);
+
+$VERSION = "0.0.1";
+%IRSSI = (
+ authors => "Christian 'mordeth' Weber",
+ contact => "chris\@mac.ruhr.de",
+ name => "autoversion",
+ description => "Auto-CTCP Verison on every joining nick",
+ license => "GPLv2",
+ url => "",
+ changed => "20020821",
+ modules => ""
+);
+
+sub event_message_join ($$$$) {
+ my ($server, $channel, $nick, $address) = @_;
+ if (lc($channel) eq lc(Irssi::active_win()->{active}->{name})) {
+ $server->command("ctcp $nick VERSION");
+ };
+}
+
+Irssi::signal_add('message join', 'event_message_join');
+
diff --git a/scripts/autovoice.pl b/scripts/autovoice.pl
new file mode 100644
index 0000000..168371c
--- /dev/null
+++ b/scripts/autovoice.pl
@@ -0,0 +1,684 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+BEGIN {
+ unless (exists $::{"Irssi::"}) {
+ require Pod::Usage;
+ Pod::Usage::pod2usage(-verbose => 2);
+ }
+}
+
+use Irssi;
+our $VERSION = '0.06';
+our %IRSSI = (
+ authors => 'aluser',
+ name => 'autovoice',
+ description => 'autovoice',
+ license => 'GPL',
+ );
+
+our %bad;
+
+=head1 SYNOPSIS
+
+ /script load autovoice
+ /autovoice add #somechannel
+Idle on #somechannel as [half]op, and you will voice people :)
+
+=head1 MOTIVATION
+
+This is certainly not a new concept, but I dislike many implementations of autovoicing because they are not as intelligent as they could be. Blindly voicing everyone who joins your channel is dumb, because it removes the protection that +m is supposed to give you. A troublemake need merely to rejoin the channel to get his voice back. You probably want to voice newcomers to your channel, so a password or hostmask system is no good. Besides, it's intuitive that anybody leaving the channel without voice and quickly rejoining is trying to leverage your autovoicer! So, the main purpose of this script is to automatically detect these people and not voice them.
+
+The other important feature is fine-grained control over where you voice people. You might want to autovoice in efnet #foo but not in dalnet #foo. The C</autovoice add> command gives you C<-server> and C<-ircnet> options to control on which channels you will autovoice, even if the channels have identical names.
+
+I still consider this script to be lightly tested, but I do hope that it is well documented enough that it can be debugged well.
+
+=head1 INSTALL
+
+Just place this script in F<~/.irssi/scripts>. To have it load automatically when you start Irssi, do this:
+
+ mkdir -p ~/.irssi/scripts/autorun
+ ln -s ../autovoice.pl ~/.irssi/scripts/autorun/
+
+If you haven't figured it out yet, you can run the script outside of Irssi to get a man page type document, like this:
+
+ chmod +x autovoice.pl
+ ./autovoice.pl
+
+=head1 COMMANDS
+
+=over
+
+=item I</autovoice add>
+
+This is a helper to add channels to L<autovoice_channels> for you.
+I'm going to explain this by example:
+
+ /autovoice add #channelfoo
+ /autovoice add -server irc.foo.com #barbarfoo
+ /autovoice add -ircnet EFNet #perlhelp
+ /autovoice add -server irc.efnet.org -ircnet Undernet #irssi
+
+Note that the last example actually adds two "channels" to the setting, both named #irssi. The channel will be valid on Undernet or the server irc.efnet.org.
+
+=item I</autovoice remove>
+
+This is a helper to remove channels from L<autovoice_channels> for you.
+Example:
+
+ /autovoice remove #somechannel
+ /autovoice remove #channel1 #channel2
+
+=item I</autovoice dump>
+
+Mostly for debugging, this dumps the perl hash containing blacklisted nicks to your screen.
+
+=item I</autovoice flush>
+
+Flush the blacklists.
+
+=back
+
+=head1 SETTINGS
+
+=over
+
+=item bool I<autovoice> = ON
+
+Set autovoicing on or off.
+
+=item string I<autovoice_channels> =
+
+Control which channels we will autovoice. The simplest form is
+
+ #channel1 , #channel2 , #channel3
+
+Space before the commas is mandatory; after is optional. For any channel in the list, you may specify a chatnet or a server like this:
+
+ #channel1 , #channel2 =>SOMECHATNET , #channel3 @some.server.com
+
+Space after the channels and before the C<< => >> or C<@> is required. Space after the C<< => >> or C<@> is optional. (not shown)
+
+See L</autovoice add> and L</autovoice remove> for wrappers to this.
+
+=item int I<autovoice_cycletime> = 600
+
+Control the amount of time, in seconds, for which we remember that a nick left a channel without voice.
+
+=item bool I<autovoice_voice_ops> = OFF
+
+Whether or not to give voice to people who already have op or halfop
+
+=item bool I<autovoice_use_ident> = OFF
+
+Whether to distinguish between nicks which have the same host but different user names. (nick![ident@host] vs nick!ident@[host])
+
+=back
+
+=cut
+
+
+=head1 BUGS
+
+Plenty.
+
+=over
+
+=item
+
+&add will add duplicate channels
+
+=item
+
+Error checking in &add is weak.
+
+=item
+
+Setting L<autovoice_use_ident> causes the existing blacklists to be ineffective.
+
+=item
+
+C<parse_channels> and C<deparse_channels> mix up the ordering of the channels in the autovoice_channels setting. This is a property of the hash used to represent the setting.
+
+=item
+
+remove doesn't let you remove only one channel when several use the same name.
+
+=item
+
+Setting L<autovoice_cycletime> does not change the timing for entries already in the badlist, only for entries made after the setting is changed. As far as I can tell, the alternatives are to A) Have a potentially ever-growing %bad, or B) to run a cleanup on a timer which must traverse all of %bad.
+
+=back
+
+=cut
+
+
+=head1 HACKING
+
+This section is for people interested in tweaking/fixing/improving/developing/hacking this script. It describes every subroutine and data structure in the script. If you do not know Perl you should stop reading here.
+
+Variables ending in C<_rec> are Irssi objects of some sort. I also use C<_text> to indicate normal strings.
+
+=head2 DATA STRUCTURES
+
+=over
+
+=item %bad
+
+This hash holds the badlists for all channels. Each key is a tag as supplied by C<$server_rec->{tag}>. Each value is a hash reference as follows:
+
+Each key is a lowercased channel name as given by C<< lc $channel_rec->{name} >> . Each value is a hash referenc described as follows:
+
+Each key is a lowercased host. If the host was marked bad while autovoice_use_ident was set, it is in the form "username@host.com". If not, it is just "host.com". Each value is a tag as returned by C<Irssi::timeout_add>. This is used to remove the callback which is planning to remove the entry from the badlist after autovoice_cycletime expires.
+
+=item %commands
+
+This hash holds the commands invoked as C<< /autovoice <command> [ arg1 arg2 ... ] >>. Each key is the lowercased name of a command, and each value is a reference to a subroutine. The subroutine should expect an Irssi Server object, a WindowItem object, and a list of user supplied arguments. The case of the arguments is left as supplied by the user.
+
+=back
+
+=cut
+
+=head2 SUBROUTINES
+
+=over
+
+=item I<massjoin($channel_rec, $nicks_ray)>
+
+The nicks in the array referenced by $nicks_ray are joining $channel_rec. This is an irssi signal handler.
+
+=cut
+
+sub massjoin {
+ my ($channel_rec, $nicks_ray) = @_;
+ voicem($channel_rec, @$nicks_ray);
+}
+
+=item I<message_part($server_rec, $channel_text, $nick_text, $addr, $reason)>
+
+A nick is parting a channel. $addr and $reason are not used. This is an irssi signal handler.
+
+=cut
+
+sub message_part {
+ my ($server_rec, $channel_text, $nick_text) = @_;
+ #Irssi::print("chan: $channel_text, nick: $nick_text");
+ #return unless defined $nick_text; # happens if the part was us
+ no warnings;
+ my $channel_rec = $server_rec->channel_find($channel_text);
+ use warnings;
+ return unless defined $channel_rec;
+ my $nick_rec = $channel_rec->nick_find($nick_text);
+ partem($channel_rec, $nick_rec);
+}
+
+=item I<message_quit($server_rec, $nick_text, $addr, $reason)>
+
+A nick is quiting the server. $addr and $reason are not used. This is an irssi signal handler.
+
+=cut
+
+sub message_quit {
+ my ($server_rec, $nick_text, $addr, $reason) = @_;
+ my $chanstring = $server_rec->get_channels();
+ $chanstring =~ s/ .*//; #strip channel keys
+ my @channels_text = split /,/, $chanstring;
+ no warnings;
+ my @channels_rec =
+ map { $server_rec->channel_find($_) } @channels_text;
+ use warnings;
+ for (@channels_rec) {
+ my $nick_rec = $_->nick_find($nick_text);
+ if (defined $nick_rec) {
+ partem($_, $nick_rec);
+ }
+ }
+}
+
+=item I<message_kick($server_rec, $channel_text, $nick_text, $addr, $reason)>
+
+Called when a nick is kicked from a channel. This is an Irssi signal handler.
+
+=cut
+
+sub message_kick {
+ my ($server_rec, $channel_text, $nick_text) = @_;
+ my $channel_rec = $server_rec->channel_find($channel_text);
+ return unless defined $channel_rec;
+ my $nick_rec = $channel_rec->nick_find($nick_text);
+ partem($channel_rec, $nick_rec);
+}
+
+=item I<voicem($channel_rec, @nicks)>
+
+This voices all of @nicks on $channel_rec, provided they aren't in the blacklist.
+
+=cut
+
+sub voicem {
+ my ($channel_rec, @nicks) = @_;
+ if (is_auto($channel_rec)) {
+ for my $nick_rec (@nicks) {
+ unless (is_bad($channel_rec, $nick_rec)
+ or $nick_rec->{voice}) {
+ if (get_voiceops() or
+ !($nick_rec->{op} or $nick_rec->{halfop})) {
+ my $nick_text = $nick_rec->{nick};
+ $channel_rec->command("voice $nick_text");
+ }
+ }
+ }
+ }
+}
+
+=item I<partem($channel_rec, $nick_rec)>
+
+Called when a nick is leaving a channel, by any means. This is what decides whether the nick does or does not have voice.
+
+=cut
+
+sub partem {
+ my ($channel_rec, $nick_rec) = @_;
+ #$channel_rec->print("partem called");
+ if (is_auto($channel_rec)) {
+ #$channel_rec->print("this channel is autovoiced.");
+ if (not $nick_rec->{voice} and
+ not $nick_rec->{op} and
+ not $nick_rec->{halfop}) {
+ #$channel_rec->print("nick leaving with no voice");
+ make_bad($channel_rec, $nick_rec);
+ } else {
+ make_unbad($channel_rec, $nick_rec);
+ }
+ }
+}
+
+=item I<is_bad($channel_rec, $nick_rec)>
+
+Returns 1 if $nick_rec is blacklisted on $channel_rec, 0 otherwise.
+
+=cut
+
+sub is_bad {
+ my ($channel_rec, $nick_rec) = @_;
+ my $server_tag = $channel_rec->{server}->{tag};
+ my $channel_text = lc $channel_rec->{name};
+ my $host_text = lc $nick_rec->{host};
+ if (not get_useident()) {
+ $host_text =~ s/.*?\@//;
+ }
+ #$channel_rec->print("calling is_bad {$server_tag}{$channel_text}{$host_text}");
+ return
+ exists $bad{$server_tag} &&
+ exists $bad{$server_tag}{$channel_text} &&
+ exists $bad{$server_tag}{$channel_text}{$host_text};
+}
+
+=item I<make_bad($channel_rec, $nick_rec)>
+
+Blacklist $nick_rec on $channel_rec for autovoice_cycletime seconds.
+
+=cut
+
+sub make_bad {
+ my ($channel_rec, $nick_rec) = @_;
+ my $tag = $channel_rec->{server}->{tag};
+ my $channel_text = lc $channel_rec->{name};
+ my $host_text = lc $nick_rec->{host};
+ if (not get_useident()) {
+ $host_text =~ s/.*?\@//;
+ }
+ #$channel_rec->print("channel_rec: ".ref($channel_rec)."nick_rec: ".ref($nick_rec).". make bad $tag, $channel_text, $host_text");
+ Irssi::timeout_remove($bad{$tag}{$channel_text}{$host_text})
+ if exists $bad{$tag}{$channel_text}{$host_text};
+ $bad{$tag}{$channel_text}{$host_text} =
+ Irssi::timeout_add(get_cycletime(),
+ 'timeout',
+ [ $channel_rec, $nick_rec ]);
+}
+
+=item I<timeout([$channel_rec, $nick_rec])>
+
+This is the irssi timeout callback which removes $nick_rec from the blacklist for $channel_rec when autovoice_cycletime seconds have elapsed. make_unbad finds the tag in the badlist in order to keep this from being called again. Note that it only takes one argument, an array ref
+
+=cut
+
+sub timeout {
+ my ($channel_rec, $nick_rec) = @{$_[0]};
+ #$channel_rec->print("timing out");
+ make_unbad($channel_rec, $nick_rec);
+}
+
+=item I<make_unbad($channel_rec, $nick_rec)>
+
+Remove $nick_rec from the blacklist for $channel_rec
+
+=cut
+
+sub make_unbad {
+ my ($channel_rec, $nick_rec) = @_;
+ my $tag = $channel_rec->{server}->{tag};
+ my $channel_text = lc $channel_rec->{name};
+ my $host_text = lc $nick_rec->{host};
+ if (not get_useident()) {
+ $host_text =~ s/.*\@//;
+ }
+ if (exists $bad{$tag}{$channel_text}{$host_text}) {
+ Irssi::timeout_remove($bad{$tag}{$channel_text}{$host_text});
+ delete $bad{$tag}{$channel_text}{$host_text};
+ if (not keys %{$bad{$tag}{$channel_text}}) {
+ delete $bad{$tag}{$channel_text};
+ }
+ if (not keys %{$bad{$tag}}) {
+ delete $bad{$tag};
+ }
+ }
+}
+
+=item I<parse_channels()>
+
+Examine autovoice_channels and return a hash reference. Each key is a channel name, lowercased. Each value is a hash with one to three keys, 'server', 'chatnet', and/or 'plain'. If server, it holds an array ref with all servers on which the channel is autovoice. If chatnet, it holds an array ref with all the chatnets on which the channel is autovoice. If plain, it just has the value 1.
+
+=cut
+
+sub parse_channels {
+ my $chanstring = lc Irssi::settings_get_str('autovoice_channels');
+ $chanstring =~ s/^\s+//;
+ $chanstring =~ s/\s+$//;
+ my @fields = split /\s+,\s*/, $chanstring;
+ my %hash;
+ keys %hash = scalar @fields;
+ for (@fields) {
+ if (/\s=>/) {
+ my ($channel, $chatnet) = split /\s+=>\s*/, $_, 2;
+ add_channel_to_parsed(\%hash, $channel, $chatnet, undef);
+ } elsif (/\s\@/) {
+ my ($channel, $server) = split /\s+\@\s*/, $_, 2;
+ add_channel_to_parsed(\%hash, $channel, undef, $server);
+ } else {
+ my ($channel) = /(\S+)/;
+ add_channel_to_parsed(\%hash, $channel, undef, undef);
+ }
+ }
+ return \%hash;
+}
+
+=item I<deparse_channels($hashr)>
+
+Take a hash ref like that produced by parse_channels and convert it into a string suitable for autovoice_channels
+
+=cut
+
+sub deparse_channels {
+ my $hashr = shift;
+ my @fields;
+ for my $channel (keys %$hashr) {
+ my $s = $channel;
+ push(@fields, $s) if exists $hashr->{$channel}->{plain};
+ if (exists $hashr->{$channel}->{server}) {
+ for (@{$hashr->{$channel}->{server}}) {
+ push(@fields, $s.' @ '.$_);
+ }
+ }
+ if (exists $hashr->{$channel}->{chatnet}) {
+ for (@{$hashr->{$channel}->{chatnet}}) {
+ push(@fields, $s.' => '.$_);
+ }
+ }
+ }
+ return join ' , ', @fields;
+}
+
+=item I<is_auto($channel_rec)>
+
+Returns 1 if $channel_rec is an autovoiced channel as defined by autovoice_channels, 0 otherwise.
+
+=cut
+
+sub is_auto {
+ unless (Irssi::settings_get_bool('autovoice')) {
+ return 0;
+ }
+ my $channel_rec = shift;
+ my $channel_text = lc $channel_rec->{name};
+ my $parsedchannels = parse_channels();
+ return 0 unless exists $parsedchannels->{$channel_text};
+ if (exists $parsedchannels->{$channel_text}->{plain}) {
+ return 1;
+ } elsif (exists $parsedchannels->{$channel_text}->{chatnet}) {
+ #Irssi::print("looking at chatnet @{$parsedchannels->{$channel_text}->{chatnet}}");
+ for (@{$parsedchannels->{$channel_text}->{chatnet}}) {
+ return 1 if $_ eq lc $channel_rec->{server}->{chatnet};
+ }
+ return 0;
+ } else {
+ for (@{$parsedchannels->{$channel_text}->{server}}) {
+ return 1 if $_ eq lc $channel_rec->{server}->{address};
+ }
+ return 0;
+ }
+}
+
+our %commands = (
+ dump => \&dump,
+ add => \&add,
+ remove => \&remove,
+ flush => \&flush,
+ );
+
+=item I<autovoice_cmd($data, $server, $witem)>
+
+Irssi command handler which dispatches all the /autovoice * commands. Autovoice commands are given ($server_rec, $witem, @args), where @args is the result of split ' ', $data minus the first element ("autovoice"). Note that the case of @args is not changed.
+
+=cut
+
+sub autovoice_cmd {
+ my ($data, $server, $witem) = @_;
+ my ($cmd, @args) = (split ' ', $data);
+ $cmd='' if (!defined $cmd);
+ $cmd = lc $cmd;
+ if (exists $commands{$cmd}) {
+ $commands{$cmd}->($server, $witem, @args)
+ } else {
+ Irssi::print("No such subcommand: autovoice '$cmd'");
+ }
+}
+
+=item I<dump($server_rec, $witem, @args)>
+
+Invoked as C</autovoice dump>, this C<require>s Data::Dumper and dumps the blacklist hash to the current window. @args and $server_rec are ignored.
+
+=cut
+
+sub dump {
+ require Data::Dumper;
+ my $witem = $_[1];
+ my $string = Data::Dumper->Dump([\%bad], ['bad']);
+ chomp $string;
+ if ($witem) {
+ $witem->print($string);
+ } else {
+ Irssi::print($string);
+ }
+}
+
+=item I<add($server_rec, $witem, @args)>
+
+Invoked as C</autovoice add (args)>. This adds channels to autovoice_channels. See L</autovoice add> in COMMANDS for usage.
+
+=cut
+
+sub add {
+ my ($server_rec, $witem, @args) = @_;
+ @args = map {lc} @args;
+ my $parsedchannels = parse_channels();
+ my ($server, $chatnet, $channel);
+ for (my $i = 0; $i < @args; ++$i) {
+ if ($args[$i] eq '-ircnet') {
+ if (defined $chatnet) {
+ Irssi::print("autovoice add: warning: -ircnet given twice, using the second value.");
+ }
+ $chatnet = $args[$i+1];
+ splice(@args, $i, 1)
+ } elsif ($args[$i] eq '-server') {
+ if (defined $server) {
+ Irssi::print("autovoice add: warning: -server given twice, using the second value.");
+ }
+ $server = $args[$i+1];
+ splice(@args, $i, 1);
+ } else {
+ if (defined $channel) {
+ Irssi::print("autovoice add: warning: more than one channel specified, using the last one.");
+ }
+ $channel = $args[$i];
+ $channel = '#'.$channel
+ unless $server_rec->ischannel($channel);
+ }
+ }
+ unless (defined $channel) {
+ Irssi::print("autovoice add: no channel specified");
+ return;
+ }
+ add_channel_to_parsed($parsedchannels, $channel, $chatnet, $server);
+ Irssi::settings_set_str('autovoice_channels' =>
+ deparse_channels($parsedchannels));
+ if ($witem) {
+ $witem->command("set autovoice_channels");
+ } else {
+ Irssi::command("set autovoice_channels");
+ }
+}
+
+=item I<add_channel_to_parsed($parsedchannels, $channel, $chatnet, $server)>
+
+Adds a channel to a hash ref like that returned by &parse_channels. If $chatnet is defined but $server is not, restrict it to the chatnet. If $server is defined but $chatnet is not, restrict it to the server. If both are defined, add to channels, one restricted to the server and the other to the chatnet. (Both with the same name) If neither is defined, do not restrict the channel to a chatnet or server.
+
+=cut
+
+sub add_channel_to_parsed {
+ my ($parsedchannels, $channel, $chatnet, $server) = @_;
+ if (defined $chatnet) {
+ push @{$parsedchannels->{$channel}->{chatnet}}, $chatnet;
+ }
+ if (defined $server) {
+ push @{$parsedchannels->{$channel}->{server}}, $server;
+ }
+ if (not defined($chatnet) and not defined($server)) {
+ $parsedchannels->{$channel}->{plain} = 1;
+ }
+}
+
+=item I<remove($server_rec, $witem, @args)>
+
+Invoked as
+
+ /autovoice remove [-ircnet IRCNET] [-server SERVER] #chan1 [-ircnet IRCNET] [-server SERVER] #chan2
+
+Removes all channels matching those specified. An -ircnet or -server option only applies to the channel following it, and must be specified before its channel name. A channel without -ircnet or -server options removes all channels with that name.
+
+=cut
+
+sub remove {
+ my ($server_rec, $witem, @args) = @_;
+ my %parsedchannels = %{parse_channels()};
+ my ($wantserver, $wantchatnet, $server, $chatnet);
+ for (@args) {
+ $_ = lc;
+ if ($wantserver) {
+ $wantserver = 0;
+ $server = $_;
+ } elsif ($wantchatnet) {
+ $wantchatnet = 0;
+ $chatnet = $_;
+ } elsif ($_ eq '-server') {
+ $wantserver = 1;
+ } elsif ($_ eq '-ircnet') {
+ $wantchatnet = 1;
+ } elsif (exists $parsedchannels{$_}) {
+ my $chan = $_;
+ if (defined $server and exists $parsedchannels{$chan}{server}) {
+ @{$parsedchannels{$chan}{server}} = grep {$_ ne $server} @{$parsedchannels{$chan}{server}};
+ }
+ if (defined $chatnet and exists $parsedchannels{$chan}{chatnet}) {
+ @{$parsedchannels{$chan}{chatnet}} = grep {$_ ne $chatnet} @{$parsedchannels{$chan}{chatnet}};
+ }
+ if (not defined $server and not defined $chatnet) {
+ delete $parsedchannels{$chan};
+ } else {
+ if (exists $parsedchannels{$chan}{server} and not @{$parsedchannels{$chan}{server}}) {
+ delete $parsedchannels{$chan}{server};
+ }
+ if (exists $parsedchannels{$chan}{chatnet} and not @{$parsedchannels{$chan}{chatnet}}) {
+ delete $parsedchannels{$chan}{chatnet};
+ }
+ }
+ }
+ }
+ Irssi::settings_set_str('autovoice_channels' =>
+ deparse_channels(\%parsedchannels));
+ if ($witem) {
+ $witem->command("set autovoice_channels");
+ } else {
+ Irssi::command("set autovoice_channels");
+ }
+}
+
+=item I<flush($server_rec, $witem, @args)>
+
+Flush the badlist.
+
+=cut
+
+sub flush {
+ %bad = ();
+}
+
+=item I<get_cycletime()>
+
+Checks autovoice_cycletime and returns the cycle time in milliseconds.
+
+=cut
+
+sub get_cycletime {
+ 1000 * Irssi::settings_get_int("autovoice_cycletime");
+}
+
+=item I<get_voiceops()>
+
+Return the value of autovoice_voice_ops
+
+=cut
+
+sub get_voiceops {
+ Irssi::settings_get_bool("autovoice_voice_ops");
+}
+
+=item I<get_useident()>
+
+Return the value of autovoice_use_ident
+
+=cut
+
+sub get_useident {
+ Irssi::settings_get_bool("autovoice_use_ident");
+}
+
+=back
+
+=cut
+
+Irssi::signal_add_first('message part', 'message_part');
+Irssi::signal_add_first('message quit', 'message_quit');
+Irssi::signal_add_first('message kick', 'message_kick');
+Irssi::signal_add_last('massjoin', 'massjoin');
+Irssi::settings_add_str('autovoice', 'autovoice_channels' => "");
+Irssi::settings_add_int('autovoice', 'autovoice_cycletime' => 600);
+Irssi::settings_add_bool('autovoice', 'autovoice_voice_ops' => 0);
+Irssi::settings_add_bool('autovoice', 'autovoice_use_ident' => 0);
+Irssi::settings_add_bool('autovoice', 'autovoice' => 1);
+
+Irssi::command_bind($IRSSI{name},'autovoice_cmd');
+foreach (keys %commands) {
+ Irssi::command_bind($IRSSI{name}.' '.$_,'autovoice_cmd');
+}
diff --git a/scripts/autowhois.pl b/scripts/autowhois.pl
new file mode 100644
index 0000000..5ec6c19
--- /dev/null
+++ b/scripts/autowhois.pl
@@ -0,0 +1,39 @@
+# /WHOIS all the users who send you a private message.
+# v1.1 for irssi 0.7.98 by Timo Sirainen
+use strict;
+use Irssi;
+use vars qw($VERSION %IRSSI);
+$VERSION = "1.1";
+%IRSSI = (
+ authors => "Timo \'cras\' Sirainen",
+ contact => "tss\@iki.fi",
+ name => "autowhois",
+ description => "/WHOIS all the users who send you a private message.",
+ license => "Public Domain",
+ url => "http://irssi.org/",
+ changed => "2002-03-04T22:47+0100",
+ changes => "v1.1: don't /WHOIS if query exists for the nick already"
+);
+
+# History:
+# v1.1: don't /WHOIS if query exists for the nick already
+
+my ($lastfrom, $lastquery);
+
+sub msg_private_first {
+ my ($server, $msg, $nick, $address) = @_;
+
+ $lastquery = $server->query_find($nick);
+}
+
+sub msg_private {
+ my ($server, $msg, $nick, $address) = @_;
+
+ return if $lastquery || $lastfrom eq $nick;
+
+ $lastfrom = $nick;
+ $server->command("whois $nick");
+}
+
+Irssi::signal_add_first('message private', 'msg_private_first');
+Irssi::signal_add('message private', 'msg_private');
diff --git a/scripts/autowrap.pl b/scripts/autowrap.pl
new file mode 100644
index 0000000..c110c91
--- /dev/null
+++ b/scripts/autowrap.pl
@@ -0,0 +1,38 @@
+use strict;
+use Text::Wrap;
+
+use vars qw($VERSION %IRSSI);
+$VERSION = '2007031900';
+%IRSSI = (
+ authors => 'Bitt Faulk',
+ contact => 'lxsfx3h02@sneakemail.com',
+ name => 'autowrap',
+ description => 'Automatically wraps long sent messages into multiple shorter sent messages',
+ license => 'BSD',
+ url => 'none',
+ modules => 'Text::Wrap',
+);
+
+sub event_send_text () {
+ my ($line, $server_rec, $wi_item_rec) = @_;
+ my @shortlines;
+ if (length($line) <= 400) {
+ return;
+ } else {
+ # split line, recreate multiple "send text" events
+ local($Text::Wrap::columns) = 400;
+ @shortlines = split(/\n/,wrap('','',$line));
+ foreach (@shortlines) {
+ if ($_ >= 400) {
+ Irssi::print("autowrap: unable to split long line. sent as-is");
+ return;
+ }
+ }
+ foreach (@shortlines) {
+ Irssi::signal_emit('send text', $_, $server_rec, $wi_item_rec);
+ }
+ Irssi::signal_stop();
+ }
+}
+
+Irssi::signal_add_first('send text', "event_send_text");
diff --git a/scripts/away.pl b/scripts/away.pl
new file mode 100644
index 0000000..9018903
--- /dev/null
+++ b/scripts/away.pl
@@ -0,0 +1,199 @@
+# $Id: away.pl,v 1.6 2003/02/25 08:48:56 nemesis Exp $
+
+use strict;
+use Irssi 20020121.2020 ();
+use vars qw($VERSION %IRSSI);
+$VERSION = "0.23";
+%IRSSI = (
+ authors => 'Jean-Yves Lefort, Larry "Vizzie" Daffner, Kees Cook',
+ contact => 'jylefort@brutele.be, vizzie@airmail.net, kc@outflux.net',
+ name => 'away',
+ description => 'Away with reason, unaway, and autoaway',
+ license => 'BSD',
+ changed => '$Date: 2003/02/25 08:48:56 $ ',
+);
+
+# /SET
+#
+# away_reason if you are not away and type /AWAY without
+# arguments, this string will be used as
+# your away reason
+#
+# autoaway number of seconds before marking away,
+# only actions listed in "autounaway_level"
+# will reset the timeout.
+#
+# autounaway_level if you are away and you type a message
+# belonging to one of these levels, you'll be
+# automatically unmarked away
+#
+# levels considered:
+#
+# DCC a dcc chat connection has
+# been established
+# PUBLICS a public message from you
+# MSGS a private message from you
+# ACTIONS an action from you
+# NOTICES a notice from you
+#
+# changes:
+# 2003-02-24
+# 0.23?
+# merged with autoaway script
+#
+# 2003-01-09 release 0.22
+# * command char independed
+#
+# 2002-07-04 release 0.21
+# * signal_add's uses a reference instead of a string
+#
+# todo:
+#
+# * rewrite the away command to support -one and -all switches
+# * make auto-away stuff sane for multiple servers
+# * make auto-away reason configurable
+#
+# (c) 2003 Jean-Yves Lefort (jylefort@brutele.be)
+#
+# (c) 2000 Larry Daffner (vizzie@airmail.net)
+# You may freely use, modify and distribute this script, as long as
+# 1) you leave this notice intact
+# 2) you don't pretend my code is yours
+# 3) you don't pretend your code is mine
+#
+# (c) 2003 Kees Cook (kc@outflux.net)
+# merged 'autoaway.pl' and 'away.pl'
+#
+# BUGS:
+# - This only works for the first server
+
+use Irssi;
+use Irssi::Irc; # for DCC object
+
+my ($autoaway_sec, $autoaway_to_tag, $am_away);
+
+sub away {
+ my ($args, $server, $item) = @_;
+
+ if ($server)
+ {
+ if (!$server->{usermode_away})
+ {
+ # go away
+ $am_away=1;
+
+ # stop autoaway
+ if (defined($autoaway_to_tag)) {
+ Irssi::timeout_remove($autoaway_to_tag);
+ $autoaway_to_tag = undef();
+ }
+
+ if (!defined($args))
+ {
+ $server->command("AWAY " . Irssi::settings_get_str("away_reason"));
+ Irssi::signal_stop();
+ }
+ }
+ else
+ {
+ # come back
+ $am_away=0;
+ reset_timer();
+ }
+
+ }
+}
+
+sub cond_unaway {
+ my ($server, $level) = @_;
+ if (Irssi::level2bits(Irssi::settings_get_str("autounaway_level")) & $level)
+ {
+ #if ($server->{usermode_away})
+ if ($am_away)
+ {
+ # come back from away
+ $server->command("AWAY");
+ }
+ else
+ {
+ # bump the autoaway timeout
+ reset_timer();
+ }
+ }
+}
+
+sub dcc_connected {
+ my ($dcc) = @_;
+ cond_unaway($dcc->{server}, MSGLEVEL_DCC) if ($dcc->{type} eq "CHAT");
+}
+
+sub message_own_public {
+ my ($server, $msg, $target) = @_;
+ cond_unaway($server, MSGLEVEL_PUBLIC);
+}
+
+sub message_own_private {
+ my ($server, $msg, $target, $orig_target) = @_;
+ cond_unaway($server, MSGLEVEL_MSGS);
+}
+
+sub message_irc_own_action {
+ my ($server, $msg, $target) = @_;
+ cond_unaway($server, MSGLEVEL_ACTIONS);
+}
+
+sub message_irc_own_notice {
+ my ($server, $msg, $target) = @_;
+ cond_unaway($server, MSGLEVEL_NOTICES);
+}
+
+#
+# /AUTOAWAY - set the autoaway timeout
+#
+sub away_setupcheck {
+ $autoaway_sec = Irssi::settings_get_int("autoaway");
+ reset_timer();
+}
+
+
+sub auto_timeout {
+ my ($data, $server) = @_;
+ my $msg = "autoaway after $autoaway_sec seconds";
+
+ Irssi::timeout_remove($autoaway_to_tag);
+ $autoaway_to_tag=undef;
+
+ Irssi::print($msg);
+
+ $am_away=1;
+
+ my (@servers) = Irssi::servers();
+ $servers[0]->command("AWAY $msg");
+}
+
+sub reset_timer {
+ if (defined($autoaway_to_tag)) {
+ Irssi::timeout_remove($autoaway_to_tag);
+ $autoaway_to_tag = undef;
+ }
+ if ($autoaway_sec) {
+ $autoaway_to_tag = Irssi::timeout_add($autoaway_sec*1000,
+ "auto_timeout", "");
+ }
+}
+
+Irssi::settings_add_str("misc", "away_reason", "not here");
+Irssi::settings_add_str("misc", "autounaway_level", "PUBLIC MSGS ACTIONS DCC");
+Irssi::settings_add_int("misc", "autoaway", 0);
+
+Irssi::signal_add("dcc connected", \&dcc_connected);
+Irssi::signal_add("message own_public", \&message_own_public);
+Irssi::signal_add("message own_private", \&message_own_private);
+Irssi::signal_add("message irc own_action", \&message_irc_own_action);
+Irssi::signal_add("message irc own_notice", \&message_irc_own_notice);
+Irssi::signal_add("setup changed" => \&away_setupcheck);
+
+Irssi::command_bind("away", "away");
+
+away_setupcheck();
+
diff --git a/scripts/away2web.pl b/scripts/away2web.pl
new file mode 100644
index 0000000..7414c23
--- /dev/null
+++ b/scripts/away2web.pl
@@ -0,0 +1,58 @@
+#!/usr/bin/perl
+
+use strict;
+use vars qw($VERSION %IRSSI);
+$VERSION = "2003100201";
+%IRSSI = (
+ authors => "Oskari 'Okko' Ojala",
+ contact => "sorter.irssi-scripts\@okko.net",
+ name => "away2web",
+ description => "Write /away information to a file to be used on web pages",
+ license => "BSD",
+ changed => "$VERSION",
+);
+use Irssi 20020324;
+
+#
+# Writes /away information to a file. A web page script (cgi / php / pl..) can
+# then read the file and display online/offline information.
+#
+# The web page script is left as an excersise for the user because the platforms
+# vary. :-)
+#
+# Tip: You can also modify this script to directly write HTML and then just include
+# the file on your web page.
+#
+#
+# Format of the file:
+# First line: Either "1" or "0". 0=Offline (away), 1=Online (not away).
+# Second line: The away reason (message). If the user is Online, second line is
+# empty but exists.
+#
+# File is written to ~/.irssi/away2web-status.
+#
+
+sub catch_away {
+ my $server = shift;
+
+ open(STATUSFILE, q{>}, $ENV{'HOME'}.'/.irssi/away2web-status') || die ("away2web.pl: Could not open file for writing:".$!);
+
+ if ($server->{usermode_away}) {
+ # User is offline.
+ print STATUSFILE "0\n";
+ } else {
+ # User is online.
+ print STATUSFILE "1\n";
+ }
+
+ print STATUSFILE $server->{'away_reason'}."\n";
+
+ close(STATUSFILE);
+
+}
+
+Irssi::signal_add("away mode changed", "catch_away");
+
+print CLIENTCRAP '%B>>%n '.$IRSSI{name}.' '.$VERSION.' (c) '.$IRSSI{authors}.' loaded';
+
+# end of script.
diff --git a/scripts/away_hilight_notice.pl b/scripts/away_hilight_notice.pl
new file mode 100644
index 0000000..2ee719b
--- /dev/null
+++ b/scripts/away_hilight_notice.pl
@@ -0,0 +1,215 @@
+#!/usr/bin/perl -w
+
+## Bugreports and Licence disclaimer.
+#
+# For bugreports and other improvements contact Geert Hauwaerts <geert@hauwaerts.be>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; either version 2 of the License, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this script; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA.
+##
+
+
+## Documentation.
+#
+# Versioning:
+#
+# This script uses the YEAR.FEATURE.REVISION versioning scheme and must abide
+# by the follwing rules:
+#
+# 1) when adding a new feature, you must increase the FEATURE
+# numeric by one;
+#
+# 2) when fixing a bug, you must increase the REVISION numeric
+# by one; and
+#
+# 3) the first feature or bug change in any given year must set the YEAR
+# numeric to the two digit representation of the current year, and
+# reset the FEATURE and REVISION numerics to 01.
+#
+# Settings:
+#
+# away_hilight_notice_timeout
+#
+# The default time between notices sent to the same person are 3600
+# seconds or once an hour.
+#
+# away_hilight_notice_filter
+#
+# A list of channels, separated by space, on which the script will be
+# disabled.
+##
+
+
+##
+# Load the required libraries.
+##
+
+use strict;
+use Irssi;
+use vars qw($VERSION %IRSSI);
+
+
+##
+# Declare the administrative information.
+##
+
+$VERSION = '15.01.01';
+
+%IRSSI = (
+ authors => 'Geert Hauwaerts',
+ contact => 'geert@hauwaerts.be',
+ name => 'away_hilight_notice.pl',
+ description => 'This script will notice your away message in response to a hilight.',
+ license => 'GNU General Public License',
+ url => 'https://github.com/GeertHauwaerts/irssi-scripts/blob/master/src/away_hilight_notice.pl',
+ changed => 'Thu Jun 25 20:46:51 UTC 2015',
+);
+
+
+##
+# Register the custom theme formats.
+##
+
+Irssi::theme_register([
+ 'away_hilight_notice_loaded', '%R>>%n %_Scriptinfo:%_ Loaded $0 version $1 by $2.',
+]);
+
+
+##
+# Declare the script variables.
+##
+
+my %lasthilight;
+
+
+## Function.
+#
+# Irssi::away_hilight_notice::away_hilight_notice() function.
+#
+# Function: away_hilight_notice()
+# Arguments: The destination.
+# The text.
+# The stripped text.
+#
+# Description: Sends a notice with your away message.
+##
+
+sub away_hilight_notice {
+
+
+ ##
+ # Parse the parameters.
+ ##
+
+ my ($dest, $text, $stripped) = @_;
+ my $server = $dest->{'server'};
+ my $hilight = Irssi::parse_special('$;');
+
+
+ ##
+ # Check whether the message is irrelevant.
+ ##
+
+ if (!$server || !($dest->{'level'} & MSGLEVEL_HILIGHT) || ($dest->{'level'} & (MSGLEVEL_MSGS|MSGLEVEL_NOTICES|MSGLEVEL_SNOTES|MSGLEVEL_CTCPS|MSGLEVEL_ACTIONS|MSGLEVEL_JOINS|MSGLEVEL_PARTS|MSGLEVEL_QUITS|MSGLEVEL_KICKS|MSGLEVEL_MODES|MSGLEVEL_TOPICS|MSGLEVEL_WALLOPS|MSGLEVEL_INVITES|MSGLEVEL_NICKS|MSGLEVEL_DCC|MSGLEVEL_DCCMSGS|MSGLEVEL_CLIENTNOTICE|MSGLEVEL_CLIENTERROR))) {
+ return;
+ }
+
+
+ ##
+ # Check whether we are marked as away.
+ ##
+
+ if ($server->{'usermode_away'}) {
+
+
+ ##
+ # Loop through each entry in the filter.
+ ##
+
+ foreach (split /\s+/, Irssi::settings_get_str('away_hilight_notice_filter')) {
+
+
+ ##
+ # Check if the target is filtered.
+ ##
+
+ if (lc($dest->{'target'}) eq lc($_)) {
+ return;
+ }
+ }
+
+
+ ##
+ # Check whether we need to send a notice.
+ ##
+
+ if (!$lasthilight{lc($hilight)}{'last'} || ($lasthilight{lc($hilight)}{'last'} && ((time() - $lasthilight{lc($hilight)}{'last'}) > Irssi::settings_get_int('away_hilight_notice_timeout')))) {
+ $lasthilight{lc($hilight)}{'last'} = time();
+ $server->command('^NOTICE ' . $hilight . ' I\'m away (' . $server->{'away_reason'} . ')');
+ }
+ }
+}
+
+
+## Function.
+#
+# Irssi::away_hilight_notice::clear_associative_array() function.
+#
+# Function: clear_associative_array()
+# Arguments: The server.
+#
+# Description: Remove the timers from the memory.
+##
+
+sub clear_associative_array {
+
+
+ ##
+ # Parse the parameters.
+ ##
+
+ my ($server) = @_;
+
+
+ ##
+ # Check whether we are marked as active.
+ ##
+
+ if (!$server->{'usermode_away'}) {
+ %lasthilight = ();
+ }
+}
+
+
+##
+# Register the signals to hook on.
+##
+
+Irssi::signal_add('print text', 'away_hilight_notice');
+Irssi::signal_add('away mode changed', 'clear_associative_array');
+
+
+##
+# Register the custom settings.
+##
+
+Irssi::settings_add_int('away', 'away_hilight_notice_timeout', 3600);
+Irssi::settings_add_str('away', 'away_hilight_notice_filter', '#bitlbee #twitter');
+
+
+##
+# Display the script banner.
+##
+
+Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'away_hilight_notice_loaded', $IRSSI{name}, $VERSION, $IRSSI{authors}); \ No newline at end of file
diff --git a/scripts/away_verbose.pl b/scripts/away_verbose.pl
new file mode 100644
index 0000000..29aefd1
--- /dev/null
+++ b/scripts/away_verbose.pl
@@ -0,0 +1,234 @@
+use Irssi;
+use strict;
+use vars qw($VERSION %IRSSI);
+
+$VERSION = '0.0.7';
+%IRSSI = (
+ authors => 'Wouter Coekaerts, Koenraad Heijlen',
+ contact => 'vipie@ulyssis.org, wouter@coekaerts.be',
+ name => 'away_verbose',
+ description => 'A verbose away script, displays a verbose away/back message in the channels you are in. BUT it can limit the channels (not spamming every channel!)',
+ license => 'GNU GPL version 2',
+ url => 'http://vipie.studentenweb.org/dev/irssi/',
+ changed => '2004-01-01'
+);
+
+#--------------------------------------------------------------------
+# Changelog
+#--------------------------------------------------------------------
+#
+# away_verbose.pl 0.7 (2004-01-01)
+# * Wouter Coekaerts
+# - don't hard code the command char
+#
+# away_verbose.pl 0.5 (2002-11-17)
+# * James Seward
+# - make regex case insensitive
+#
+#--------------------------------------------------------------------
+
+#--------------------------------------------------------------------
+# Public Variables
+#--------------------------------------------------------------------
+my $away_time_texts = "wk,wks,day,days,hr,hrs,min,mins,sec,secs";
+my ($away_set, $away_time, $away_reason, $away_silent)=(0,0,"",0);
+my %myHELP = ();
+
+
+#--------------------------------------------------------------------
+# Help function
+#--------------------------------------------------------------------
+sub cmd_help {
+ my ($about) = @_;
+
+ %myHELP = (
+ back => "
+BACK
+
+Away is unset, the time you were away is displayed in the channel with the reason.
+
+like this: /me away_back_text_part1 <reason> away_back_text_part2 TIME
+
+Currently it will display:
+/me " . Irssi::settings_get_str('away_back_text_part1') . " Some Reason " . Irssi::settings_get_str('away_back_text_part2') . " " . &secs2text(10000) . "
+
+You can change this by changing the settings (with /set setting_name):
+
+* away_back_text_part1 (default: is back from)
+* away_back_text_part2 (default: after)
+* away_time_texts (default: wk,wks,day,days,hr,hrs,min,mins,sec,secs)
+
+",
+
+ gone => "
+GONE <your away reason>
+
+Sets you away with the given reason, and displays it publically on the allowed channels.
+
+like this: /me away_gone_text <reason>
+
+Currently it will display:
+/me " . Irssi::settings_get_str('away_gone_text') . " Some Reason
+
+You can change this by changing the settings (with /set setting_name):
+
+* away_gone_text (default: is gone:)
+
+
+How do I decide on which channels they away message is displayed?
+-----------------------------------------------------------------
+
+You set 2 settings: away_order_channels, away_allow_channels.
+
+away_order_channels = [allow|exclude]
+ Should the channels be allowed or excluded using a regular expression. (exclude = all but the matching channels).
+
+away_allow_channels = <regular expression>
+ The regular expression limiting the channels (eg 'linux|home' without the '').
+",
+
+ awe => "
+AWE [<your away reason>]
+
+When a reason is given, it acts as GONE
+When no reason is supplied it acts as BACK.
+
+SEE ALSO: HELP BACK, HELP GONE
+",
+
+);
+
+ if ( $about =~ /(back|gone|awe)/i ) {
+ Irssi::print($myHELP{$1});
+ }
+}
+
+
+#--------------------------------------------------------------------
+# Translate the number of seconds to a human readable format.
+#--------------------------------------------------------------------
+sub secs2text {
+ $away_time_texts = Irssi::settings_get_str('away_time_texts');
+ my ($secs) = @_;
+ my ($wk_,$wks_,$day_,$days_,$hr_,$hrs_,$min_,$mins_,$sec_,$secs_) = (0,1,2,3,4,5,6,7,8,9,10);
+ my @texts = split(/,/,$away_time_texts);
+ my $mins=int($secs/60); $secs -= ($mins*60);
+ my $hrs=int($mins/60); $mins -= ($hrs*60);
+ my $days=int($hrs/24); $hrs -= ($days*24);
+ my $wks=int($days/7); $days -= ($wks*7);
+ my $text = (($wks>0) ? (($wks>1) ? "$wks $texts[$wks_] " : "$wks $texts[$wk_] ") : "" );
+ $text .= (($days>0) ? (($days>1) ? "$days $texts[$days_] " : "$days $texts[$day_] ") : "" );
+ $text .= (($hrs>0) ? (($hrs>1) ? "$hrs $texts[$hrs_] " : "$hrs $texts[$hr_] ") : "" );
+ $text .= (($mins>0) ? (($mins>1) ? "$mins $texts[$mins_] " : "$mins $texts[$min_] ") : "" );
+ $text .= (($secs>0) ? (($secs>1) ? "$secs $texts[$secs_] " : "$secs $texts[$sec_] ") : "" );
+ $text =~ s/ $//;
+ return $text;
+}
+
+#--------------------------------------------------------------------
+# Output the public away on all permitted channels.
+#--------------------------------------------------------------------
+sub away_describe_pub_channels {
+ my $away_allow_channels=Irssi::settings_get_str('away_allow_channels');
+ my $away_order_channels=Irssi::settings_get_str('away_order_channels');
+ my ($server,$text) = @_;
+ foreach my $server (Irssi::servers) {
+ foreach my $chan ($server->channels) {
+
+ if ((($server->{chatnet} .":". $chan->{name}) =~ /$away_allow_channels/i) != ($away_order_channels eq "exclude")) {
+ $server->command("DESCRIBE $chan->{name} $text");
+ }
+ }
+ }
+}
+
+#--------------------------------------------------------------------
+# Set the away reason, and call the function to do the announce.
+#--------------------------------------------------------------------
+sub away_setaway {
+ my ($server, $reason)=@_;
+
+ my $away_gone_text=Irssi::settings_get_str('away_gone_text');
+
+ $server->command("AWAY " . $reason);
+ away_describe_pub_channels($server,"$away_gone_text $reason");
+ $away_time=time;
+ $away_reason=$reason;
+ $away_set=1;
+}
+
+#--------------------------------------------------------------------
+# Remove the away reason, and call the function to do the announce.
+#--------------------------------------------------------------------
+sub away_back {
+ my($server)=@_;
+
+ my $away_back_text_part1=Irssi::settings_get_str('away_back_text_part1');
+ my $away_back_text_part2=Irssi::settings_get_str('away_back_text_part2');
+
+ if ( $away_set ) {
+ $server->command("AWAY");
+ away_describe_pub_channels($server,"$away_back_text_part1 $away_reason $away_back_text_part2 " . secs2text(time - $away_time));
+ $away_time=0;
+ $away_reason="";
+ $away_set=0;
+
+ } else {
+ Irssi::print("Don't use back if you are not away! OXYMORON");
+ Irssi::print("(ed. note) OXYMORON: a combination of contradictory or incongruous words (as cruel kindness)");
+ return;
+ }
+}
+
+#--------------------------------------------------------------------
+# Defintion of /gone, /back and /awe
+#--------------------------------------------------------------------
+sub gone {
+ my ($args, $server, $item) = @_;
+ away_setaway($server,$args);
+}
+
+sub back {
+ my ($args, $server, $item) = @_;
+ away_back($server);
+}
+
+sub cmd_away {
+ my ($args, $server, $item) = @_;
+
+ if ( $args ) {
+ away_setaway($server,$args);
+ } else {
+ away_back($server);
+ }
+}
+
+
+#--------------------------------------------------------------------
+# Irssi::Settings / Irssi::command_bind
+#--------------------------------------------------------------------
+
+Irssi::settings_add_str('away', 'away_allow_channels', "^\$");
+Irssi::settings_add_str('away', 'away_order_channels', "exclude");
+Irssi::settings_add_str('away', 'away_time_texts', $away_time_texts);
+
+Irssi::settings_add_str('away', 'away_gone_text', "is gone:");
+Irssi::settings_add_str('away', 'away_back_text_part1', "is back from");
+Irssi::settings_add_str('away', 'away_back_text_part2', "after");
+
+Irssi::command_bind("gone", "gone", "Advanced Away");
+Irssi::command_bind("back", "back", "Advanced Away");
+Irssi::command_bind("awe","cmd_away", "Advanced Away");
+
+Irssi::command_bind("help","cmd_help", "Irssi commands");
+
+#--------------------------------------------------------------------
+# This text is printed at Load time.
+#--------------------------------------------------------------------
+
+Irssi::print("Use /back, /gone <reason>, or the toggle /awe [<reason>]");
+Irssi::print("Use /away [<reason>] for silent away");
+Irssi::print("Use /help back or gone or awe for more information.");
+
+
+#- end
diff --git a/scripts/awaybar.pl b/scripts/awaybar.pl
new file mode 100644
index 0000000..7d11ae5
--- /dev/null
+++ b/scripts/awaybar.pl
@@ -0,0 +1,44 @@
+# awaybar.pl -- initially built for Irssi 0.8.9
+# thanks to mood.pl for practically allowing me
+# to copy the approach..
+use strict;
+use Irssi;
+use Irssi::TextUI;
+use vars qw($VERSION %IRSSI);
+
+$VERSION = "0.1.1";
+%IRSSI = (
+ authors => 'Simon Shine',
+ contact => 'http://shine.eu.org/',
+ name => 'awaybar',
+ description => 'Provides a menubar item with away message',
+ sbitems => 'awaybar',
+ license => 'Public domain',
+);
+
+Irssi::statusbar_item_register('awaybar', 0, 'awaybar');
+Irssi::signal_add('away mode changed', 'awaybar_redraw');
+
+sub awaybar {
+ my ($item, $get_size_only) = @_;
+ my $away_reason = !Irssi::active_server() ? undef : Irssi::active_server()->{away_reason};
+
+ if (defined $away_reason && length $away_reason) {
+ my %r = ('\{' => '(',
+ '\}' => ')',
+ '%' => '%%',);
+ $away_reason =~ s/$_/$r{$_}/g for (keys %r);
+
+ #my $format = $theme->format_expand("{sb_awaybar $away_reason}");
+ my $format = "{sb Away: $away_reason}";
+
+ $item->{min_size} = $item->{max_size} = length($away_reason);
+ $item->default_handler($get_size_only, $format, 0, 1);
+ } else {
+ $item->{min_size} = $item->{max_size} = 0;
+ }
+}
+
+sub awaybar_redraw {
+ Irssi::statusbar_items_redraw('awaybar');
+}
diff --git a/scripts/awaylogcnt.pl b/scripts/awaylogcnt.pl
new file mode 100644
index 0000000..5c9ec82
--- /dev/null
+++ b/scripts/awaylogcnt.pl
@@ -0,0 +1,59 @@
+# $Id: awaylogcnt.pl,v 0.2 2004/10/27 19:46 derwan Exp $
+#
+# Run command '/statusbar window add -after user -priority 1 awaylogcnt' after loading awaylogcnt.pl.
+#
+
+use strict;
+use vars qw($VERSION %IRSSI);
+
+use Irssi;
+$VERSION = '0.2';
+%IRSSI = (
+ authors => 'Marcin Rozycki',
+ contact => 'derwan@irssi.pl',
+ name => 'awalogcnt',
+ description => 'Displays in statusbar number of messages in awaylog',
+ modules => '',
+ sbitems => 'awaylogcnt',
+ license => 'GNU GPL v2',
+ url => 'http://derwan.irssi.pl',
+ changed => 'Wed Oct 27 19:46:28 CEST 2004'
+);
+
+use Irssi::TextUI;
+
+our $cnt = 0;
+our $fname = undef();
+
+
+Irssi::signal_add( 'log started' => sub {
+ my $logfile = Irssi::settings_get_str( 'awaylog_file' );
+ return unless ( $_[0]->{fname} eq $logfile );
+ ($fname, $cnt) = ($logfile, 0);
+ Irssi::statusbar_items_redraw('awaylogcnt');
+});
+
+Irssi::signal_add( 'log stopped' => sub {
+ return unless ( $_[0]->{fname} eq $fname );
+ ($cnt, $fname) = (0, undef);
+ Irssi::statusbar_items_redraw('awaylogcnt');
+});
+
+Irssi::signal_add( 'log written' => sub {
+ return unless ( $_[0]->{fname} eq $fname );
+ $cnt++;
+ Irssi::statusbar_items_redraw('awaylogcnt');
+});
+
+sub awaylogcnt ($$) {
+ my ($sbitem, $get_size_only) = @_;
+ unless ( $cnt )
+ {
+ $sbitem->{min_size} = $sbitem->{max_size} = 0 if ( ref $sbitem );
+ return;
+ }
+ my $format = sprintf('{sb \%%yawaylog\%%n %d}', $cnt);
+ $sbitem->default_handler($get_size_only, $format, undef, 1);
+}
+
+Irssi::statusbar_item_register('awaylogcnt', undef, 'awaylogcnt');
diff --git a/scripts/awayproxy.pl b/scripts/awayproxy.pl
new file mode 100644
index 0000000..8e84833
--- /dev/null
+++ b/scripts/awayproxy.pl
@@ -0,0 +1,279 @@
+# vim:syntax=perl
+# vim:tabstop=4
+# vim:shiftwidth=4
+# vim:foldmethod=marker
+# vim:foldenable
+# vim:enc=utf-8
+########################################################################################################
+## WARNING!! BAD ENGLISH BELOW :P
+##
+## This script is designed for those who have been using muh irc bouncer.
+## Basicly this script just monitors the proxy module and if new client
+## connects it sets you automatically back from away state and when client
+## disconnects it sets you automatically away if you arent allready away.
+##
+## Other hand if you dont use irssi-proxy you still have a good reason to
+## use this if you want to forward messages that come to you while
+## you are away to email box.
+## This is usefull for forwarding messages to an SMS-gateway ;)
+##
+## btw.. if you find any bugs or have any ideas for development of this
+## script dont hesitate to send msg to BCOW@IrcNET
+## or send email to anttip@n0-life.com
+##
+#### Version history:
+# 0.1
+# * basic functionality
+# 0.2b
+# * a patch from Wulf that gives a user ability to change the autoaway reason.
+# * Added away_level parameter that gives you ability to control how many
+# clients there can be connected to the irssi_proxy module before you are
+# set away.
+# * You arent set away when disconnecting from the irssi_proxy if you already
+# are away. This means that your current away reason isn't changed.
+# * Sends cumulated away messages back to the client when it connects to the
+# irssi_proxy module.
+# 0.2c
+# * Fixes bug where cummulated messages weren't sent.
+# * Code cleanup.
+# * Text wrapping to standart 80x24 text console.
+# * Added debug mode.
+# * Added script modes.
+# * Got rid of crappy irssi setings system.
+# * New logging expansion capability, either time or line based.
+# 0.2d
+# * Micro fix to get back only when needed
+# 0.2e
+# * Changed default values for $config{script_mode} and $config{emailto} for IRC-only and a non-existing placeholder respectively.
+#### To come / planned / wanted:
+# * Make expansion system log several channels at once.
+# * Make this script server based.
+########################################################################################################
+
+use strict;
+use warnings;
+
+# irssi imports
+use Irssi;
+use Irssi::Irc;
+use vars qw($VERSION %IRSSI %config);
+
+$VERSION = "0.2e";
+%IRSSI = (
+ authors => "BCOW",
+ contact => "anttip\@n0-life.com",
+ name => "awayproxy",
+ description => "Sets nick away when client discconects from the "
+ . "irssi-proxy. If away gathers messages targeted to nick and forwards "
+ . "them to an email address.",
+ license => "GPLv2",
+ url => "http://www.n0-life.com",
+);
+
+# After how much seconds we can check if there are any messages to send?
+$config{check_interval} = 45;
+# this setting controls that when this amout of clients are connected to the
+# proxy module script sets you away. If you set this to 0 you are set away when
+# no clients are connected to the proxy module. If you set this to lets say 5
+# then you will be set away allways when the amount of clients connected to the
+# proxy module is 5 or under.
+$config{away_level} = 0;
+# Controls expansion mode. This mode records pub msgs that come after one with
+# your nick in it. you can use line counting or time counting.
+# 0 - off
+# line - line counting
+# time - time counting
+$config{expansion_mode} = 'time';
+# How many lines include after start line?
+$config{expansion_lines} = 12;
+# After how many seconds stop gathering msgs?
+$config{expansion_timeout} = 90;
+# script operation mode:
+# 0 - to send messages both to email and when you get back to proxy
+# 1 - only email
+# 2 - only irc
+# 3 - off
+$config{script_mode} = 2;
+# email address where to send the email
+$config{emailto} = 'recipient@domain.tld';
+# sendmail location
+$config{sendmail} = '/usr/sbin/sendmail';
+# who is the sender of the email
+$config{emailfrom} = 'sender@domain.tld';
+# Subject of email
+$config{emailsubject} = '[irssi-proxy]';
+# and the awayreason setting (Thanx Wulf)
+$config{awayreason} = 'Auto-away because client has disconnected from proxy.';
+# Debugging mode
+$config{debug} = 0;
+
+# -- Don't change anything below this line if you don't know Perl. --
+# number of clients connected
+$config{clientcount} = 0;
+# number of lines recorded
+$config{expansion_lines_count} = 0;
+
+$config{expansion_started} = 0;
+# the small list and archive list
+$config{awaymsglist} = [];
+$config{awaymsglist2} = [];
+
+if ( $config{script_mode} == 0 || $config{script_mode} == 1 ) { # {{{
+ # timeouts for check loop
+ debug('Timer on, timeout: ' . $config{check_interval});
+ Irssi::timeout_add($config{check_interval} * 1000, 'msgsend_check', '');
+} # }}}
+
+sub debug { # {{{
+ if ($config{debug}) {
+ my $text = shift;
+ my $caller = caller;
+ Irssi::print('From ' . $caller . ":\n" . $text);
+ }
+} # }}}
+sub msgsend_check { # {{{
+ # If there are any messages to send
+ my $count = @{$config{awaymsglist}};
+ debug("Checking for messages: $count");
+ # Check if we didn't grep msgs right now
+ if ($count > 0 && !$config{expansion_started}) {
+ # Concentate messages into one text.
+ my $text = join "\n", @{$config{awaymsglist}};
+ # Then empty list.
+ $config{awaymsglist} = [];
+ # Finally send email
+ debug("Concentated msgs: $text");
+ send_mail($text);
+ }
+} # }}}
+sub send_mail { # {{{
+ my $text = shift;
+ debug("Sending mail");
+ open MAIL, q{|-}, $config{sendmail} . " -t";
+ print MAIL "To: $config{emailto}\n";
+ print MAIL "From: $config{emailfrom}\n";
+ print MAIL "Subject: $config{emailsubject}\n";
+ print MAIL "$text";
+ close MAIL;
+} # }}}
+sub client_connect { # {{{
+ my (@servers) = Irssi::servers;
+
+ $config{clientcount}++;
+ debug("Client connected, current script mode: $config{script_mode}");
+
+ # setback
+ foreach my $server (@servers) {
+ # if you're away on that server send yourself back
+ if ($server->{usermode_away} == 1) {
+ $server->send_raw('AWAY :');
+ # and then send the current contents of archive list as notify's to
+ # your self ;)
+ # .. weird huh? :)
+ # This sends all the away messages to ALL the servers where you are
+ # connected... this is somewhat weird i know
+ # but if someone wants to make a patch to this i would really
+ # appreciate it.
+ if ($config{script_mode} == 0 || $config{script_mode} == 2) {
+ debug('Sending notices');
+ $server->send_raw('NOTICE ' . $server->{nick} . " :$_")
+ for @{$config{awaymsglist2}};
+ }
+ }
+ }
+ # and "clear" the awaymessage list
+ $config{awaymsglist2} = []
+ if $config{script_mode} == 0 || $config{script_mode} == 2;
+} # }}}
+sub client_disconnect { # {{{
+ my (@servers) = Irssi::servers;
+ debug('Client Disconnectted');
+
+ $config{clientcount}-- unless $config{clientcount} == 0;
+
+ # setaway
+ if ($config{clientcount} <= $config{away_level}) {
+ # ok.. we have the away_level of clients connected or less.
+ foreach my $server (@servers) {
+ if ($server->{usermode_away} == "0") {
+ # we are not away on this server allready.. set the autoaway
+ # reason
+ $server->send_raw(
+ 'AWAY :' . $config{awayreason}
+ );
+ }
+ }
+ }
+} # }}}
+sub msg_pub { # {{{
+ my ($server, $data, $nick, $mask, $target) = @_;
+
+ sub push_into_archive { # {{{
+ my ($nick, $mask, $target, $data) = @_;
+ # simple list that is emptied on the email run
+ push @{$config{awaymsglist}}, "<$nick!$mask\@$target> $data"
+ if $config{script_mode} == 0 || $config{script_mode} == 1;
+ # archive list that is emptied only on the client connect run
+ push @{$config{awaymsglist2}}, "<$nick!$mask\@$target> $data"
+ if $config{script_mode} == 0 || $config{script_mode} == 2;
+ } # }}}
+
+ if ($config{expansion_started}) {
+ if ($config{expansion_mode} eq 'line') {
+ if ($config{expansion_lines_count} <= $config{expansion_lines} -1) {
+ if ($config{expansion_chan} eq $target) {
+ debug("In effect from line expansion, pushing on. Cnt: "
+ . $config{expansion_lines_count});
+ push_into_archive($nick, $mask, $target, $data);
+ $config{expansion_lines_count}++;
+ }
+ }
+ else {
+ debug("Line counter reached max, stopping expansion");
+ $config{expansion_lines_count} = 0;
+ $config{expansion_started} = 0;
+ $config{expansion_chan} = '';
+ }
+ }
+ elsif ($config{expansion_mode} eq 'time') {
+ if ($config{expansion_chan} eq $target) {
+ debug("Time expansion in effect, pushing on.");
+ push_into_archive($nick, $mask, $target, $data);
+ }
+ }
+ }
+ elsif ($server->{usermode_away} == "1" && $data =~ /$server->{nick}/i) {
+ debug("Got pub msg with my name");
+ push_into_archive($nick, $mask, $target, $data);
+ if ($config{expansion_mode}) {
+ debug("Starting expansion in mode: " . $config{expansion_mode});
+ $config{expansion_started} = 1;
+ $config{expansion_chan} = $target;
+ $config{expansion_time_out} = Irssi::timeout_add(
+ $config{expansion_timeout} * 1000, 'expansion_stop', ''
+ ) if $config{expansion_mode} eq 'time';
+ }
+ }
+} # }}}
+sub expansion_stop { # {{{
+ debug("Stopping expansion from timer");
+ $config{expansion_started} = 0;
+ $config{expansion_chan} = '';
+} # }}}
+sub msg_pri { # {{{
+ my ($server, $data, $nick, $address) = @_;
+ if ($server->{usermode_away} == "1") {
+ debug("Got priv msg");
+ # simple list that is emptied on the email run
+ push @{$config{awaymsglist}}, "<$nick!$address> $data"
+ if $config{script_mode} == 0 || $config{script_mode} == 1;
+ # archive list that is emptied only on the client connect run
+ push @{$config{awaymsglist2}}, "<$nick!$address> $data"
+ if $config{script_mode} == 0 || $config{script_mode} == 2;
+ }
+} # }}}
+
+Irssi::signal_add_last('proxy client connected', 'client_connect');
+Irssi::signal_add_last('proxy client disconnected', 'client_disconnect');
+Irssi::signal_add_last('message public', 'msg_pub');
+Irssi::signal_add_last('message private', 'msg_pri');
diff --git a/scripts/badword.pl b/scripts/badword.pl
new file mode 100644
index 0000000..20a0b57
--- /dev/null
+++ b/scripts/badword.pl
@@ -0,0 +1,163 @@
+###############################################################################
+# badword.pl
+# Copyright (C) 2002 Jan 'fissie' Sembera <fis@ji.cz>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+###############################################################################
+# This is configurable badword script. It may be configured to ban immediately
+# when first badword is detected, or it may count badwords and if number of
+# badwords of given nick exceeds limit, ban him. Badword count may also be
+# expired if no badword is seen for specified period of time. Optional
+# verbosity (let's call it logging) may be enabled as well
+#
+# Runtime variables:
+#
+# badword_channels = list of channels where script is active, separated by space
+# badword_words = list of 'bad words' that trigger this, separated by space
+# badword_reason = reason used in kick when count exceeds permitted limit
+# badword_limit = if number of detected badwords reaches this number, ban'em.
+# Set 1 to immediately kickban.
+# badword_clear_delay = if no badword is detected from user for time specified
+# here (in seconds), clear his counter. Set 0 to disable.
+# badword_verbose = turns on/off logging features
+# badword_ban_delay = ban after number of kicks specified here. 0 - disables
+# banning, 1 - ban immediately, ...
+###############################################################################
+#
+# Changelog:
+#
+# Jun 4 2002
+# - added ban delaying feature
+#
+###############################################################################
+use Irssi;
+use Irssi::Irc;
+use strict;
+use vars qw($VERSION %IRSSI);
+
+$VERSION = "0.0.3";
+
+%IRSSI = (
+ authors => "Jan 'fissie' Sembera",
+ contact => "fis\@ji.cz",
+ name => "badword",
+ description => "Configurable badword kickbanning script",
+ license => "GPL v2 and any later",
+ url => "http://fis.bofh.cz/devel/irssi/",
+);
+
+my %nick_dbase;
+
+sub sig_public {
+ my ($server, $msg, $nick, $address, $target) = @_;
+ my $watch_channels = Irssi::settings_get_str('badword_channels');
+ my $watch_words = Irssi::settings_get_str('badword_words');
+
+ my @chanz = split (/ /, $watch_channels);
+ my @wordz = split (/ /, $watch_words);
+
+ my $nickrec = $server->channel_find($target)->nick_find($nick);
+ my $nickmode = $nickrec->{op} ? "@" : $nickrec->{voice} ? "+" : "";
+
+ my $aux = 0;
+
+ if (! ($nickmode eq "")) {
+ return;
+ }
+
+ foreach my $ch (@chanz) {
+ if ($ch eq $target) {
+ $aux = 1;
+ }
+ }
+
+ if ($aux == 0) {
+ return;
+ }
+
+ $aux = 0;
+ foreach my $bw (@wordz) {
+# if (($msg =~ /\ $bw/) || ($msg =~ /^$bw/)) {
+ if ($msg =~ /$bw/) {
+ $aux = 1;
+ }
+ }
+
+ if ($aux == 0) {
+ return;
+ }
+
+ # Ok, here comes badword, check record
+
+ my $luser = $nick_dbase{$nick}{$target};
+
+ if (!$luser) {
+ $nick_dbase{$nick}{$target}{'count'} = 1;
+ $nick_dbase{$nick}{$target}{'kcount'} = 0;
+ $nick_dbase{$nick}{$target}{'stamp'} = time();
+ } else {
+ if ((Irssi::settings_get_int('badword_clear_delay') != 0) && (($nick_dbase{$nick}{$target}{'stamp'})+(Irssi::settings_get_int('badword_clear_delay'))) < time()) {
+ $nick_dbase{$nick}{$target}{'count'} = 1;
+ if (Irssi::settings_get_bool('badword_verbose') == 1) { Irssi::print('BW: Expired for '.$nick.' with hostmask '.$address.' on channel '.$target); }
+ } else {
+ $nick_dbase{$nick}{$target}{'count'} = ($nick_dbase{$nick}{$target}{'count'})+1;
+ }
+ $nick_dbase{$nick}{$target}{'stamp'} = time();
+ }
+
+ $luser = $nick_dbase{$nick}{$target}{'count'};
+
+ if (Irssi::settings_get_bool('badword_verbose') == 1) { Irssi::print('BW: Detected badword from nick '.$nick.' with hostmask '.$address.' on channel '.$target.' - '.$nick_dbase{$nick}{$target}{'count'}.' times'); }
+
+ if ($luser == Irssi::settings_get_int('badword_limit')) {
+ $nick_dbase{$nick}{$target}{'count'} = 0;
+ # Ban'em!
+ my @host = split(/\@/, $address);
+ if (($host[0] =~ /\~/) || ($host[0] =~ /\-/) || ($host[0] =~ /\=/) || ($host[0] =~ /\^/)) { $host[0] = "*"; }
+ my $mask = '*!'.$host[0].'@'.$host[1];
+ $nick_dbase{$nick}{$target}{'kcount'} = ($nick_dbase{$nick}{$target}{'kcount'})+1;
+ if ((Irssi::settings_get_int('badword_ban_delay') > 0) && (Irssi::settings_get_int('badword_ban_delay') == $nick_dbase{$nick}{$target}{'kcount'})) {
+ $server->command('mode '.$target.' +b '.$mask);
+ $nick_dbase{$nick}{$target}{'kcount'} = 0;
+ if (Irssi::settings_get_bool('badword_verbose') == 1) { Irssi::print('BW: Nick '.$nick.' with mask '.$mask.' punished for badwording on channel '.$target.' - banned'); }
+ } else {
+ if (Irssi::settings_get_bool('badword_verbose') == 1) { Irssi::print('BW: Nick '.$nick.' with mask '.$mask.' punished for badwording on channel '.$target.' - kicked'); }
+ }
+ $server->command('quote kick '.$target.' '.$nick.' :'.Irssi::settings_get_str('badword_reason'));
+ }
+}
+
+sub sig_nick {
+ my ($server, $newnick, $nick, $address) = @_;
+
+ $newnick = substr ($newnick, 1) if ($newnick =~ /^:/);
+ my $count = $nick_dbase{$nick};
+ if ($count) {
+ $nick_dbase{$nick} = undef;
+ $nick_dbase{$newnick} = $count;
+ if (Irssi::settings_get_bool('badword_verbose') == 1) { Irssi::print('BW: Tranferred badwords from '.$nick.' to '.$newnick); }
+ }
+}
+
+Irssi::settings_add_str("misc", "badword_channels", "");
+Irssi::settings_add_str("misc", "badword_words", "");
+Irssi::settings_add_str("misc", "badword_reason", "BW: badword limit exceeded");
+Irssi::settings_add_int("misc", "badword_limit", 3);
+Irssi::settings_add_int("misc", "badword_clear_delay", 3600);
+Irssi::settings_add_int("misc", "badword_ban_delay", 1);
+Irssi::settings_add_bool("misc", "badword_verbose", 0);
+
+Irssi::signal_add_last('message public', 'sig_public');
+Irssi::signal_add_last('event nick', 'sig_nick');
diff --git a/scripts/ban.pl b/scripts/ban.pl
new file mode 100644
index 0000000..8915dbc
--- /dev/null
+++ b/scripts/ban.pl
@@ -0,0 +1,394 @@
+use Irssi 20020300;
+use 5.6.0;
+use strict;
+use Socket;
+use POSIX;
+
+use vars qw($VERSION %IRSSI %HELP);
+$HELP{ban} = "
+BAN [channel] [-normal|-host|-user|-domain|-crap|-ip|-class -before \"command\"|-after \"command\" nicks|masks] ...
+
+Bans the specified nicks or userhost masks.
+
+If nick is given as parameter, the ban type is used to generate the ban mask.
+/SET banpl_type specified the default ban type. Ban type is one of the following:
+
+ normal - *!fahren\@*.ds14.agh.edu.pl
+ host - *!*\@plus.ds14.agh.edu.pl
+ user - *!fahren@*
+ domain - *!*\@*.agh.edu.pl
+ crap - *?fah???\@?l??.?s??.??h.???.?l
+ ip - *!fahren\@149.156.124.*
+ class - *!*\@149.156.124.*
+
+Only one flag can be specified for a given nick.
+Script removes any conflicting bans before banning.
+
+You can specify command that will be executed before or after
+banning nick/mask using -before or -after.
+
+Examples:
+ /BAN fahren - Bans the nick 'fahren'
+ /BAN -ip fahren - Bans the ip of nick 'fahren'
+ /BAN fahren -ip fantazja -crap nerhaf -normal ff
+ - Bans 'fahren' (using banpl_type set), ip of 'fantazja',
+ host with crap mask of 'nerhaf' and 'ff' with normal bantype.
+ /BAN *!*fahren@* - Bans '*!*fahren@*'
+ /BAN #chan -after \"KICK #chan fahren :reason\" fahren
+ - Bans and kicks 'fahren' from channel '#chan' with reason 'reason'.
+
+ /ALIAS ipkb ban \$C -after \"KICK \$C \$0 \$1-\" -ip \$0
+ - Adds command /ipkb <nick> [reason] which kicks 'nick' and bans it's ip address.
+";
+$VERSION = "1.4d";
+%IRSSI = (
+ authors => "Maciek \'fahren\' Freudenheim",
+ contact => "fahren\@bochnia.pl",
+ name => "ban",
+ description => "/BAN [channel] [-normal|-host|-user|-domain|-crap|-ip|-class -before|-after \"cmd\" nick|mask] ... - bans several nicks/masks on channel, removes any conflicting bans before banning",
+ license => "GNU GPLv2 or later",
+ changed => "Tue Nov 19 18:11:09 CET 2002"
+);
+
+# Changelog:
+# 1.4d
+# - getting user@host of someone who isn't on channel was broken
+# 1.4c
+# - fixed banning of unresolved hosts
+# - fixed problem with /ban unexisting_nick other_nick
+# 1.4b
+# - doesn't require op to see banlist :)
+# 1.4
+# - few fixes
+# - using banpl_type instead of irssi's builtin ban_type
+# - changed -normal behaviour
+# 1.3
+# - :( fixed crap banning (yes, i'm to stupid to code it)
+# 1.2
+# - queuing MODES for nicks that aren't on channel
+# 1.11
+# - fixed .. surprise! crap banning
+# - added use 5.6.0
+# 1.1
+# - fixed banning 10-char long idents
+# - fixed crap banning (once more)
+# - added -before and -after [command] for executing command before/after setting ban
+# 1.0
+# - -o+b if banning opped nick
+# - fixed -crap banning
+# - always banning with *!*ident@ (instead of *!ident@)
+# - can take channel as first argument now
+# - displays error if it couldn't resolve host for -ip / -class ban
+# - groups all modes and sends them at once, ie. -bbo\n+b-o+b
+# - gets user@host via USERHOST if requested ban of someone who is not on channel
+# - added help
+
+my (%ftag, $parent, %modes, %modes_args, %b, @userhosts);
+
+sub cmd_ban {
+ my ($args, $server, $winit) = @_;
+
+ my $chan;
+ my ($channel) = $args =~ /^([^\s]+)/;
+
+ if (($server->ischannel($channel))) {
+ $args =~ s/^[^\s]+\s?//;
+ return unless ($args);
+ unless (($chan = $server->channel_find($channel)) && $chan->{chanop}) {
+ Irssi::print("%R>>%n You are not on $channel or you are not opped.");
+ Irssi::signal_stop();
+ return;
+ }
+ } else {
+ return unless ($args);
+ unless ($winit && $winit->{type} eq "CHANNEL" && $winit->{chanop}) {
+ Irssi::print("%R>>%n You don't have active channel in that window or you are not opped.");
+ Irssi::signal_stop();
+ return;
+ }
+ $chan = $winit;
+ $channel = $chan->{name};
+ }
+
+ Irssi::signal_stop();
+
+ my $bantype = Irssi::settings_get_str("banpl_type");
+ my $max = $server->{max_modes_in_cmd};
+ my ($cmdwhat, $cmdwhen) = (0, 0);
+ $b{$channel} = 0;
+
+ # counts nicks/masks to ban, lame :|
+ for my $cmd (split("\"", $args)) {
+ ($cmdwhen) and $cmdwhen = 0, next;
+ for (split(/ +/, $cmd)) {
+ next unless $_;
+ /^-(normal|host|user|domain|crap|ip|class)$/ and next;
+ /^-(before|after)$/ and $cmdwhen = 1, next;
+ $b{$channel}++;
+ }
+ }
+
+ for my $cmd (split("\"", $args)) {
+ ($cmdwhen && !$cmdwhat) and $cmdwhat = $cmd, next;
+ for my $arg (split(/ +/, $cmd)) {
+ next unless $arg;
+ $arg =~ /^-(normal|host|user|domain|crap|ip|class)$/ and $bantype = $1, next;
+ $arg eq "-before" and $cmdwhen = 1, next;
+ $arg eq "-after" and $cmdwhen = 2, next;
+
+ if (index($arg, "@") == -1) {
+ my $n;
+ if ($n = $chan->nick_find($arg)) {
+ # nick is on channel
+
+ my ($user, $host) = split("@", $n->{host});
+
+ if ($bantype eq "ip" || $bantype eq "class") {
+ # requested ip ban, forking
+ my $pid = &ban_fork;
+ unless (defined $pid) { # error
+ $cmdwhen = $cmdwhat = 0;
+ $b{$channel}--;
+ next;
+ } elsif ($pid) { # parent
+ $cmdwhen = $cmdwhat = 0;
+ next;
+ }
+ my $ia = gethostbyname($host);
+ unless ($ia) {
+ print($parent "error $channel %R>>%n Couldn't resolve $host.\n");
+ } else {
+ print($parent "execute $server->{tag} $channel " . (($n->{op})? $arg : 0) . " " . make_ban($user, inet_ntoa($ia), $bantype) . " $cmdwhen $cmdwhat\n");
+ }
+ close $parent; POSIX::_exit(1);
+ }
+ ban_execute($chan, (($n->{op})? $arg : 0), make_ban($user, $host, $bantype), $max, $cmdwhen, $cmdwhat);
+ } else {
+ # nick is not on channel, trying to get addres via /userhost
+ $server->redirect_event('userhost', 1, $arg, 0, undef, {
+ 'event 302' => 'redir ban userhost',
+ '' => 'event empty' } );
+ $server->send_raw("USERHOST :$arg");
+ my $uh = {
+ tag => $server->{tag},
+ nick => lc($arg),
+ channel => $channel,
+ chanhash => $chan,
+ bantype => $bantype,
+ cmdwhen => $cmdwhen,
+ cmdwhat => $cmdwhat
+ };
+ push @userhosts, $uh;
+ }
+ } else {
+ # specified mask
+ my $ban;
+ $ban = "*!" if (index($arg, "!") == -1);
+ $ban .= $arg;
+ ban_execute($chan, 0, $ban, $max, $cmdwhen, $cmdwhat);
+ }
+
+ $cmdwhen = $cmdwhat = 0;
+ }
+ }
+}
+
+sub push_mode ($$$$) {
+ my ($chan, $mode, $arg, $max) = @_;
+
+ my $channel = $chan->{name};
+ $modes{$channel} .= $mode;
+ $modes_args{$channel} .= "$arg ";
+
+ flush_mode($chan) if (length($modes{$channel}) >= ($max * 2));
+}
+
+sub flush_mode ($) {
+ my $chan = shift;
+
+ my $channel = $chan->{name};
+ return unless (defined $modes{$channel});
+# Irssi::print("MODE $channel $modes{$channel} $modes_args{$channel}");
+ $chan->command("MODE $channel $modes{$channel} $modes_args{$channel}");
+ undef $modes{$channel}; undef $modes_args{$channel};
+}
+
+sub userhost_red {
+ my ($server, $data) = @_;
+ $data =~ s/^[^ ]* :?//;
+
+ my $uh = shift @userhosts;
+
+ unless ($data && $data =~ /^([^=\*]*)\*?=.(.*)@(.*)/ && lc($1) eq $uh->{nick}) {
+ Irssi::print("%R>>%n No such nickname: $uh->{nick}");
+ $b{$uh->{channel}}--;
+ flush_mode($uh->{chanhash}) unless ($b{$uh->{channel}});
+ return;
+ }
+
+ my ($user, $host) = (lc($2), lc($3));
+
+ if ($uh->{bantype} eq "ip" || $uh->{bantype} eq "class") {
+ # requested ip ;/
+ my $pid = &ban_fork;
+ unless (defined $pid) { # error
+ $b{$uh->{channel}}--;
+ return;
+ } elsif ($pid) { # parent
+ return;
+ }
+ my $ia = gethostbyname($host);
+ unless ($ia) {
+ print($parent "error " . $uh->{channel} . " %R>>%n Couldn't resolve $host.\n");
+ } else {
+ print($parent "execute " . $uh->{tag} . " " . $uh->{channel} . " 0 " . make_ban($user, inet_ntoa($ia), $uh->{bantype}) . " " . $uh->{cmdwhen} . " " . $uh->{cmdwhat} . "\n");
+ }
+ close $parent; POSIX::_exit(1);
+ }
+
+ my $serv = Irssi::server_find_tag($uh->{tag});
+ ban_execute($uh->{chanhash}, 0, make_ban($user, $host, $uh->{bantype}), $serv->{max_modes_in_cmd}, $uh->{cmdwhen}, $uh->{cmdwhat});
+}
+
+sub ban_execute ($$$$$$) {
+ my ($chan, $nick, $ban, $max, $cmdwhen, $cmdwhat) = @_;
+
+ my $no = 0;
+ my $channel = $chan->{name};
+
+ for my $hash ($chan->bans()) {
+ if (mask_match($ban, $hash->{ban})) {
+ # should display also who set the ban (if available)
+ Irssi::print("%Y>>%n $channel: ban $hash->{ban}");
+ $no = 1;
+ last;
+ } elsif (mask_match($hash->{ban}, $ban)) {
+ push_mode($chan, "-b", $hash->{ban}, $max);
+ }
+ }
+
+ unless ($no) {
+ my ($cmdmode, $cmdarg);
+ # is requested command a MODE so we can put it to queue?
+ ($cmdmode, $cmdarg) = $cmdwhat =~ /^MODE\s+[^\s]+\s+([^\s]+)\s+([^\s]+)/i if $cmdwhen;
+ if ($cmdwhen == 1) { # command requested *before* banning
+ unless ($cmdmode) { # command isn't mode, ie: KICK
+ flush_mode($chan); # flush all -b conflicting bans
+ $chan->command($cmdwhat); # execute
+ } else { # command is MODE, we can add it to queue
+ push_mode($chan, $cmdmode, $cmdarg, $max);
+ }
+ }
+ push_mode($chan, "-o", $nick, $max) if ($nick);
+ push_mode($chan, "+b", $ban, $max);
+ if ($cmdwhen == 2) { # command requested *after* banning
+ unless ($cmdmode) {
+ flush_mode($chan); # flush all modes
+ $chan->command($cmdwhat);
+ } else {
+ push_mode($chan, $cmdmode, $cmdarg, $max);
+ }
+ }
+ }
+
+ $b{$channel}--;
+ flush_mode($chan) unless ($b{$channel});
+}
+
+sub ban_fork {
+ my ($rh, $wh);
+ pipe($rh, $wh);
+ my $pid = fork();
+ unless (defined $pid) {
+ Irssi::print("%R>>%n Failed to fork() :/ - $!");
+ close $rh; close $wh;
+ return undef;
+ } elsif ($pid) { # parent
+ close $wh;
+ $ftag{$rh} = Irssi::input_add(fileno($rh), INPUT_READ, \&ifork, $rh);
+ Irssi::pidwait_add($pid);
+ } else { # child
+ close $rh;
+ $parent = $wh;
+ }
+ return $pid;
+}
+
+sub ifork {
+ my $rh = shift;
+ while (<$rh>) {
+ /^error\s([^\s]+)\s(.+)/ and $b{$1}--, Irssi::print("$2"), last;
+ if (/^execute\s([^\s]+)\s([^\s]+)\s([^\s]+)\s([^\s]+)\s([^\s]+)\s(.+)/) {
+ my $serv = Irssi::server_find_tag($1);
+ ban_execute($serv->channel_find($2), $3, $4, $serv->{max_modes_in_cmd}, $5, $6);
+ last;
+ }
+ }
+ Irssi::input_remove($ftag{$rh});
+ delete $ftag{$rh};
+ close $rh;
+}
+
+sub make_ban ($$$) {
+ my ($user, $host, $bantype) = @_;
+
+ $user =~ s/^[~+\-=^]/*/;
+ if ($bantype eq "ip") {
+ $host =~ s/\.[0-9]+$/.*/;
+ } elsif ($bantype eq "class") {
+ $user = "*";
+ $host =~ s/\.[0-9]+$/.*/;
+ } elsif ($bantype eq "user") {
+ $host = "*";
+ } elsif ($bantype eq "domain") {
+ # i know -- lame
+ if ($host =~ /^.*\..*\..*\..*$/) {
+ $host =~ s/.*(\..+\..+\..+)$/*\1/;
+ } elsif ($host =~ /^.*\..*\..*$/) {
+ $host =~ s/.*(\..+\..+)$/*\1/;
+ }
+ $user = "*";
+ } elsif ($bantype eq "host") {
+ $user = "*";
+ } elsif ($bantype eq "normal") {
+# $host =~ s/^[A-Za-z\-]*[0-9]+\./*./;
+ if ($host =~ /\d$/) {
+ $host =~ s/\.[0-9]+$/.*/;
+ } else {
+ $host =~ s/^[^.]+\./*./ if $host =~ /^.*\..*\..*$/;
+ }
+ } elsif ($bantype eq "crap") {
+ my $crap;
+ for my $c (split(//, $user)) {
+ $crap .= ((int(rand(2)))? "?" : $c);
+ }
+ $user = $crap;
+ $crap = "";
+ for my $c (split(//, $host)) {
+ $crap .= ((int(rand(2)))? "?" : $c);
+ }
+ $host = $crap;
+ }
+
+ return ("*!" . $user . "@" . $host);
+}
+
+sub mask_match ($$) {
+ my ($what, $match) = @_;
+
+ # stolen from shasta's friend.pl
+ $match =~ s/\\/\\\\/g;
+ $match =~ s/\./\\\./g;
+ $match =~ s/\*/\.\*/g;
+ $match =~ s/\!/\\\!/g;
+ $match =~ s/\?/\./g;
+ $match =~ s/\+/\\\+/g;
+ $match =~ s/\^/\\\^/g;
+ $match =~ s/\[/\\\[/g;
+
+ return ($what =~ /^$match$/i);
+}
+
+Irssi::command_bind 'ban' => \&cmd_ban;
+Irssi::settings_add_str 'misc', 'banpl_type', 'normal';
+Irssi::signal_add 'redir ban userhost' => \&userhost_red;
diff --git a/scripts/bandwidth.pl b/scripts/bandwidth.pl
new file mode 100644
index 0000000..8c0d0fb
--- /dev/null
+++ b/scripts/bandwidth.pl
@@ -0,0 +1,115 @@
+# Mrtg-compatible any statistic loader
+# /SET status_min_in - The minimum load to show
+# /SET status_min_in - The minimum load to show
+# /SET status_refresh - How often the loadavg is refreshed
+#
+# takes output from mrtg compatible scripts,
+# see the mrtg-contrib and mrtgutils package for scripts to load
+#
+# this one requires /usr/bin/mrtg-ip-acct from mrtgutils package
+#
+# TODO ; add support for more than one stat at the same time
+# TODO : negative amounts?
+
+use Irssi 20011113;
+use Irssi::TextUI;
+
+use strict;
+use 5.6.0;
+
+use vars qw($VERSION %IRSSI);
+
+# header begins here
+
+$VERSION = "1.0";
+%IRSSI = (
+ authors => "Riku Voipio",
+ contact => "riku.voipio\@iki.fi",
+ name => "bandwidth",
+ description => "shows bandwidth usage in statusbar",
+ sbitems => "stats",
+ license => "GPLv2",
+ url => "http://nchip.ukkosenjyly.mine.nu/irssiscripts/",
+ );
+
+my ($refresh, $last_refresh, $refresh_tag) = (10);
+my ($last_in, $last_out) = (0.0,0.0);
+my ($min_in, $min_out) = (1.0,1.0);
+my ($cur_in, $cur_out, $first_run) = (0.0,0.0,1);
+my $command = '/usr/bin/mrtg-ip-acct';
+
+
+sub get_stats
+{
+ my ($old_in, $old_out) = ($last_in, $last_out);
+
+ my @localstats;
+ if (open my $fh, q{-|}, $command)
+ {
+ @localstats = <$fh>;
+ close $fh;
+ } else {
+ Irssi::print("Failed to execute $command: $!", MSGLEVEL_CLIENTERROR);
+ }
+
+ for(@localstats[0..1]) {
+ return unless defined;
+ return unless /^\d+$/;
+ }
+ $last_in=$localstats[0];
+ $last_out=$localstats[1];
+
+ if ($old_out==0){return;}
+
+ $cur_out=($last_out-$old_out) / ($refresh*1024);
+ $cur_in=($last_in-$old_in) / ($refresh*1024);
+}
+
+sub stats {
+ my ($item, $get_size_only) = @_;
+ #get_stats();
+
+ $min_out = Irssi::settings_get_int('stats_min_out');
+ $min_in = Irssi::settings_get_int('stats_min_in');
+ $min_in = 0 if $min_in < 0;
+ $min_out = 0 if $min_out < 0;
+
+
+ if ($cur_in < $min_in and $cur_out <$min_out){
+ #dont print
+ if ($get_size_only) {
+ $item->{min_size} = $item->{max_size} = 0;
+ }
+ } else {
+ $item->default_handler($get_size_only, undef, sprintf("i:%.2f o:%.2f",$cur_in, $cur_out ), 1 );
+ }
+}
+
+sub refresh_stats {
+ get_stats();
+ Irssi::statusbar_items_redraw('stats');
+}
+
+sub read_settings {
+ $refresh = Irssi::settings_get_int('stats_refresh');
+ $command = Irssi::settings_get_str('stats_commandline');
+ $refresh = 1 if $refresh < 1;
+ return if $refresh == $last_refresh;
+ $last_refresh = $refresh;
+
+ Irssi::timeout_remove($refresh_tag) if $refresh_tag;
+ $refresh_tag = Irssi::timeout_add($refresh*1000, 'refresh_stats', undef);
+}
+
+Irssi::settings_add_int('misc', 'stats_min_in', $min_in);
+Irssi::settings_add_int('misc', 'stats_min_out', $min_out);
+Irssi::settings_add_int('misc', 'stats_refresh', $refresh);
+Irssi::settings_add_str('misc', 'stats_commandline', $command);
+
+Irssi::statusbar_item_register('stats', '{sb S: $0-}', 'stats');
+Irssi::statusbars_recreate_items();
+
+read_settings();
+Irssi::signal_add('setup changed', 'read_settings');
+
+
diff --git a/scripts/bansearch.pl b/scripts/bansearch.pl
new file mode 100644
index 0000000..cc961ad
--- /dev/null
+++ b/scripts/bansearch.pl
@@ -0,0 +1,421 @@
+#!/usr/bin/perl
+
+use strict;
+use Irssi;
+use Irssi::Irc;
+use vars qw($VERSION %IRSSI);
+
+$VERSION = "1.3";
+%IRSSI = (
+ authors => 'Nathan Handler, Joseph Price',
+ contact => 'nathan.handler@gmail.com, pricechild@ubuntu.com',
+ name => 'bansearch',
+ description => 'Searches for bans, quiets, and channel modes affecting a user',
+ license => 'GPLv3+',
+);
+
+my($channel,$person,$nick,$user,$host,$real,$account,$string,$issues,$running,@jchannels,@jchannelstocheck,$debug);
+
+$running=0;
+
+sub bansearch {
+ my($data,$server,$witem) = @_;
+
+ if($running) {
+ Irssi::print("bansearch is already running.");
+ }
+
+ $running=1;
+ @jchannels=();
+ @jchannelstocheck=();
+
+ #Clear variables and register redirects
+ &reset();
+ $debug = Irssi::settings_get_bool('bansearch_debug');
+
+ #Split command arguments into a nick and a channel separated by a space
+ ($person,$channel)=split(/ /, $data, 2);
+
+ #If no channel is specified, use the current window if it is a channel
+ if($channel!~m/^#/ && $person!~m/^\s*$/ && $witem->{type} eq "CHANNEL") {
+ $channel=$witem->{name};
+ }
+
+ #Stop the script and display usage information if they did not specify a person or if we can't find a channel to use
+ if($channel!~m/^#/ || $person=~m/^\s*$/) {
+ Irssi::active_win()->print("\x02Usage\x02: /bansearch nick [#channel]");
+ $running=0;
+ return;
+ }
+
+ #Print the name of the channel we are running on
+ Irssi::active_win()->print("\x02Channel\x02: $channel");
+
+ #Perform a /who <user> %uhnar
+ $server->redirect_event('who',1, '', 0, undef,
+ {
+ 'event 352' => 'redir rpl_whoreply',
+ 'event 354' => 'redir rpl_whospcrpl',
+ 'event 315' => 'redir rpl_endofwho',
+ 'event 401' => 'redir err_nosuchnick',
+ '' => 'event empty',
+ }
+ );
+ $server->send_raw("WHO $person %uhnar");
+}
+#Irssi::signal_add('event empty', 'EMPTY');
+Irssi::signal_add('redir rpl_whoreply', 'RPL_WHOREPLY');
+Irssi::signal_add('redir rpl_whospcrpl', 'RPL_WHOSPCRPL');
+Irssi::signal_add('redir rpl_endofwho', 'RPL_ENDOFWHO');
+Irssi::signal_add('redir err_nosuchnick', 'ERR_NOSUCHNICK');
+Irssi::signal_add('redir err_nosuchchannel', 'ERR_NOSUCHCHANNEL');
+Irssi::signal_add('redir rpl_banlist', sub { my($server,$data) = @_; RPL_BANLIST($server, "Ban $data"); });
+Irssi::signal_add('redir rpl_endofbanlist', sub { my($server,$data) = @_; RPL_ENDOFBANLIST($server, "Ban $data"); });
+Irssi::signal_add('redir rpl_quietlist', sub { my($server,$data) = @_; RPL_BANLIST($server, "Quiet $data"); });
+Irssi::signal_add('redir rpl_endofquietlist', sub { my($server,$data) = @_; RPL_ENDOFBANLIST($server, "Quiet $data"); });
+Irssi::signal_add('redir rpl_channelmodeis', 'RPL_CHANNELMODEIS');
+
+sub EMPTY {
+ my($server, $data) = @_;
+
+ return if(!$running);
+
+ Irssi::print("\x02EMPTY\x02: $data");
+}
+
+sub RPL_BANLIST {
+ my($server, $data) = @_;
+
+ return if(!$running);
+
+ my($type, $mask, $setby, $banchannel, $jchannel);
+ if($data=~m/^Ban/) {
+ ($type, undef, $banchannel, $mask, $setby, undef) = split(/ /, $data, 6);
+ }
+ elsif($data=~m/^Quiet/) {
+ ($type, undef, $banchannel, undef, $mask, $setby, undef) = split(/ /, $data, 7);
+ }
+ my $maskreg = $mask;
+ $maskreg=~s/\$\#.*$//; #Support matching ban-forwards
+ $maskreg=~s/\./\\./g;
+ $maskreg=~s/\//\\\//g;
+ $maskreg=~s/\@/\\@/g;
+ $maskreg=~s/\[/\\[/g;
+ $maskreg=~s/\]/\\]/g;
+ $maskreg=~s/\|/\\|/g;
+ $maskreg=~s/\?/\./g;
+ $maskreg=~s/\*/\.\*\?/g;
+
+ #We only want to display who set the ban/quiet if it is listed as a person
+ if($setby!~m/!/) {
+ $setby='';
+ }
+ else {
+ $setby=" (Set by $setby)";
+ }
+
+ if($maskreg=~m/^\$/) { #extban
+ # account
+ if($maskreg=~m/^\$a:(.*?)$/i) {
+ if($account=~m/^$1$/i && $account!~m/^0$/) {
+ Irssi::active_win()->print("$type against \x02$mask\x02 in $banchannel matches $account" . $setby);
+ $issues++;
+ }
+ else {
+ Irssi::active_win()->print("$type against \x02$mask\x02 in $banchannel does NOT match $account" . $setby) if $debug;
+ }
+ }
+ # cannot join other channel
+ if($channel == $banchannel) {
+ if($maskreg=~m/^\$j:(.*?)$/i) {
+ $jchannel = $1;
+ if(!(grep {$jchannel eq $_} @jchannels)) {
+ push(@jchannels, $jchannel);
+ push(@jchannelstocheck, $jchannel);
+ Irssi::active_win()->print("Following bans in "
+ . $jchannel . " will " . $type . " " . $person . " in " . $channel . $setby);
+ }
+ }
+ }
+ # any logged-in user
+ if($maskreg=~m/^\$a$/i) {
+ if($account!~m/^0$/) {
+ Irssi::active_win()->print(
+ "$type against \x02$mask\x02 in $banchannel matches identified user" . $setby);
+ $issues++;
+ }
+ else {
+ Irssi::active_win()->print("$type against \x02$mask\x02 in $banchannel does NOT match unidentified user" . $setby) if $debug;
+ }
+ }
+ # any unidentified user
+ if($maskreg=~m/^\$\~a$/i) {
+ if($account=~m/^0$/) {
+ Irssi::active_win()->print(
+ "$type against \x02$mask\x02 in $banchannel matches unidentified user" . $setby);
+ $issues++;
+ }
+ else {
+ Irssi::active_win()->print("$type against \x02$mask\x02 in $banchannel does NOT match identified user" . $setby) if $debug;
+ }
+ }
+ # ircname
+ if($maskreg=~m/^\$r:(.*?)$/i) {
+ if($real=~m/^$1$/i) {
+ Irssi::active_win()->print(
+ "$type against \x02$mask\x02 in $banchannel matches real name of $real" . $setby);
+ $issues++;
+ }
+ else {
+ Irssi::active_win()->print("$type against \x02$mask\x02 in $banchannel does NOT match real name of $real" . $setby) if $debug;
+ }
+ }
+ # full match
+ if($maskreg=~m/^\$x:(.*?)$/i) {
+ my $full = "$nick!$user\@$host\#$real";
+ if($full=~m/^$1$/i) {
+ Irssi::active_win()->print(
+ "$type against \x02$mask\x02 in $banchannel matches $full" . $setby);
+ $issues++;
+ }
+ else {
+ Irssi::active_win()->print("$type against \x02$mask\x02 in $banchannel does NOT match $full" . $setby) if $debug;
+ }
+ }
+ }
+ else { #Normal Ban
+ if($string=~m/^$maskreg$/i) {
+ Irssi::active_win()->print("$type against \x02$mask\x02 in $banchannel matches $string" . $setby);
+ $issues++;
+ }
+ else {
+ Irssi::active_win()->print("$type against \x02$mask\x02 in $banchannel does NOT match $string" . $setby) if $debug;
+ }
+ }
+}
+
+sub RPL_ENDOFBANLIST {
+ my($server, $data) = @_;
+
+ return if(!$running);
+
+# Irssi::active_win()->print("End of Ban List");
+ if($data=~m/^Ban/) {
+ $server->redirect_event('mode q',1, $channel, 0, undef,
+ {
+ 'event 728' => 'redir rpl_quietlist',
+ 'event 729' => 'redir rpl_endofquietlist',
+ '' => 'event empty',
+ }
+ );
+ $server->send_raw("MODE $channel q");
+ }
+ elsif($data=~m/^Quiet/) {
+ if (@jchannelstocheck) {
+ my $nextchannel = pop(@jchannelstocheck);
+ $server->redirect_event('mode b',1, $nextchannel, 0, undef,
+ {
+ 'event 367' => 'redir rpl_banlist',
+ 'event 368' => 'redir rpl_endofbanlist',
+ 'event 403' => 'redir err_nosuchchannel',
+ '' => 'event empty',
+ }
+ );
+ $server->send_raw("MODE $nextchannel b");
+ } else {
+ $server->redirect_event('mode channel',1, $channel, 0, undef,
+ {
+ 'event 324' => 'redir rpl_channelmodeis',
+ '' => 'event empty',
+ }
+ );
+ $server->send_raw("MODE $channel");
+ }
+ }
+}
+
+sub RPL_WHOREPLY {
+ my($server, $data) = @_;
+
+ return if(!$running);
+
+ # 0 1 2 3 4 5 6 7 8
+ # bw2 * ~pi rpi1.my irc.example.net rpi1 H :0 real name
+ (undef, undef, $user, $host, undef, $nick, undef, undef, $real) = split(/ /, $data,9);
+ $account='';
+ $real=~s/^://;
+ Irssi::active_win()->print("\x02User\x02: $nick [$account] ($real) $user\@$host");
+}
+
+sub RPL_WHOSPCRPL {
+ my($server, $data) = @_;
+
+ return if(!$running);
+
+ # $server->send_raw("WHO $person %uhnar");
+ # 0 1 2 3 4 5
+ # bw2 ~bw1 irc.example.net bw1 bw2 :real name
+ (undef, $user, $host, $nick, $account, $real) = split(/ /, $data,6);
+ $real=~s/^://;
+ Irssi::active_win()->print("\x02User\x02: $nick [$account] ($real) $user\@$host");
+}
+
+sub RPL_ENDOFWHO {
+ my($server, $data) = @_;
+
+ return if(!$running);
+
+ if($nick=~m/^$/ && $user=~m/^$/ && $host=~m/^$/) {
+ Irssi::active_win()->print("$person is currently offline.");
+ return;
+ }
+ $string="$nick!$user\@$host";
+ $server->redirect_event('mode b',1, $channel, 0, undef,
+ {
+ 'event 367' => 'redir rpl_banlist',
+ 'event 368' => 'redir rpl_endofbanlist',
+ 'event 403' => 'redir err_nosuchchannel',
+ '' => 'event empty',
+ }
+ );
+ $server->send_raw("MODE $channel b");
+}
+
+sub ERR_NOSUCHNICK {
+ my($server, $data) = @_;
+
+ return if(!$running);
+
+ Irssi::active_win()->print("$person is currently offline.");
+ $running=0;
+}
+
+sub ERR_NOSUCHCHANNEL {
+ my($server, $data) = @_;
+
+ return if(!$running);
+
+ Irssi::active_win()->print("$channel does not exist.");
+ $running=0;
+}
+
+sub RPL_CHANNELMODEIS {
+ my($server, $data) = @_;
+
+ return if(!$running);
+
+ my(undef, undef, $modes, $args) = split(/ /, $data, 4);
+ Irssi::active_win()->print("\x02Channel Modes\x02: $modes");
+ if($modes=~m/i/) {
+ Irssi::active_win()->print("Channel is \x02invite-only\x02 (+i)");
+ $issues++;
+ }
+ if($modes=~m/k/) {
+ Irssi::active_win()->print("Channel has a \x02password\x02 (+k)");
+ $issues++;
+ }
+ if($modes=~m/r/) {
+ if($account=~m/^0$/) {
+ Irssi::active_win()->print("Channel is \x02blocking unidentified users\x02 (+r) and user is not identified");
+ $issues++;
+ }
+ }
+ if($modes=~m/m/) {
+ if($server->channel_find("$channel")) {
+ my $n = $server->channel_find("$channel")->nick_find("$nick");
+ if($n->{voice} == 0 && $n->{op} == 0) {
+ Irssi::active_win()->print("Channel is \x02moderated\x02 (+m) and user is not voiced or oped");
+ $issues++;
+ }
+ }
+ else {
+ Irssi::active_win()->print("Channel is \x02moderated\x02 (+m) and user might not be voiced or oped");
+ $issues++;
+ }
+ }
+
+ if($issues == 0) {
+ Irssi::active_win()->print("There does not appear to be anything preventing $person from joining/talking in $channel");
+ }
+ elsif ($issues == 1) {
+ Irssi::active_win()->print("There is \x02$issues issue\x02 that might be preventing $person from joining/talking in $channel");
+ }
+ else {
+ Irssi::active_win()->print("There are \x02$issues issues\x02 that might be preventing $person from joining/talking in $channel");
+ }
+ $running=0;
+}
+
+sub reset {
+
+ return if(!$running);
+
+ $channel='';
+ $person='';
+ $nick='';
+ $user='';
+ $host='';
+ $real='';
+ $account='';
+ $string='';
+ $issues=0;
+
+ &register_redirects();
+}
+
+sub register_redirects {
+
+ return if(!$running);
+
+ #who
+ Irssi::Irc::Server::redirect_register('who', 0, 0,
+ { "event 352" => 1, # start events
+ "event 354" => -1,
+ },
+ { # stop events
+ "event 315" => 1, # End of Who List
+ "event 401" => 1, # No Such Nick
+ },
+ undef, # optional events
+ );
+
+ #mode b
+ Irssi::Irc::Server::redirect_register('mode b', 0, 0,
+ { "event 367" => 1 }, # start events
+ { # stop events
+ "event 368" => 1, # End of channel ban list
+ "event 403" => 1, # no such channel
+ "event 442" => 1, # "you're not on that channel"
+ "event 479" => 1 # "Cannot join channel (illegal name)"
+ },
+ undef, # optional events
+ );
+
+ #mode q
+ Irssi::Irc::Server::redirect_register('mode q', 0, 0,
+ { "event 728" => 1 }, # start events
+ { # stop events
+ "event 729" => 1, # End of channel quiet list
+ "event 403" => 1, # no such channel
+ "event 442" => 1, # "you're not on that channel"
+ "event 479" => 1, # "Cannot join channel (illegal name)"
+ },
+ undef, # optional events
+ );
+
+ #mode channel
+ Irssi::Irc::Server::redirect_register('mode channel', 0, 0, undef,
+ { # stop events
+ "event 324" => 1, # MODE-reply
+ "event 403" => 1, # no such channel
+ "event 442" => 1, # "you're not on that channel"
+ "event 479" => 1 # "Cannot join channel (illegal name)"
+ },
+ { "event 329" => 1 } # Channel create time
+ );
+}
+
+Irssi::command_bind('bansearch', 'bansearch');
+Irssi::settings_add_bool('bansearch', 'bansearch_debug', 0);
+
+# vim:set ts=8 sw=4:
diff --git a/scripts/bantime.pl b/scripts/bantime.pl
new file mode 100644
index 0000000..bebb63a
--- /dev/null
+++ b/scripts/bantime.pl
@@ -0,0 +1,110 @@
+use strict;
+use Irssi; # developed using irssi 0.8.9.CVS
+
+# I recommend rebinding irssi's default 'BAN' to 'bantimes' (/alias BAN BANTIME)
+
+use vars qw($VERSION %IRSSI);
+$VERSION = '1.03';
+%IRSSI = (
+ authors => "David O\'Rourke",
+ contact => "phyber [at] #irssi",
+ name => "bantime",
+ description => "Print time when ban was set in a nicer way. eg. 23m, 40s ago.",
+ license => "GPLv2",
+ changed => "02/03/2009",
+);
+
+sub duration {
+ my ($when) = @_;
+
+ my $diff = (time - $when);
+ my $day = int($diff / 86400); $diff -= ($day * 86400);
+ my $hrs = int($diff / 3600); $diff -= ($hrs * 3600);
+ my $min = int($diff / 60); $diff -= ($min * 60);
+ my $sec = $diff;
+
+ my $str;
+ $str .= "${day}d " if $day;
+ $str .= "${hrs}h " if $day or $hrs;
+ $str .= "${min}m " if $day or $hrs or $min;
+ $str .= "${sec}s"; # seconds should always be shown
+
+ return $str;
+}
+
+sub cmd_bans {
+ my ($args, $server, $witem) = @_;
+ return if not ($witem && $witem->{type} eq "CHANNEL");
+ my $channel = $witem->{name};
+
+ if (!$witem->bans()) {
+ $witem->printformat(
+ MSGLEVEL_CLIENTCRAP,
+ 'bantime_nobans',
+ $channel);
+ return;
+ }
+
+ my $count = 1;
+ foreach my $ban ($witem->bans()) {
+ if (!$ban->{setby} || !$ban->{time}) {
+ $witem->printformat(
+ MSGLEVEL_CLIENTCRAP,
+ 'bantime',
+ $count,
+ $channel,
+ $ban->{ban});
+ }
+ else {
+ my $bantime;
+ if (Irssi::settings_get_bool('bantime_show_date')) {
+ $bantime = localtime($ban->{time}) . ": ";
+ $bantime =~ s/\s+/ /g;
+ }
+ $bantime .= duration($ban->{time});
+ $witem->printformat(
+ MSGLEVEL_CLIENTCRAP,
+ 'bantime_long',
+ $count,
+ $channel,
+ $ban->{ban},
+ $ban->{setby},
+ $bantime);
+ }
+ $count++;
+ }
+}
+
+Irssi::theme_register([
+ 'bantime', '{line_start}$0 - {channel $1}: ban {ban $2}',
+ 'bantime_long', '{line_start}$0 - {channel $1}: ban {ban $2} {comment by {nick $3}, $4 ago}',
+ 'bantime_nobans', '{line_start}{hilight Irssi:} No bans in channel {channel $0}'
+]);
+Irssi::command_bind('bantime', 'cmd_bans');
+Irssi::print("Loaded $IRSSI{name} $VERSION");
+Irssi::settings_add_bool('bantime', 'bantime_show_date' => 0);
+
+#############
+# ChangeLog #
+#############
+# 02.03.2009: 1.03
+# Minor cosmetic changes to the script.
+# 28.02.2007: 1.03
+# duration() now returns a nicer string. Fields arn't visible if they're zero.
+# Random bits cleaned up.
+# 28.04.2005: 1.01
+# Removed redundant '$bantime2' variable, left over from a setting that was removed earlier.
+# 19.03.2005: 1.0
+# Removed dependancy on Time::Duration by using duration().
+# Removed obsolete 'bantime_short_format' setting.
+# Increased version to 1.0
+# 11.01.2004: Jan 11 2004: 04:30
+# Added new bantime_show_date setting. Displays the date the ban was set along with the time info.
+# 11.01.2004: Jan 11 2004: 04:05
+# Added new bantime_short_format setting. Displays the time in a nice short format. (#irssi: ban *!*@test.testing [by phyber, 3d 5h 54m 59s ago])
+# 11.01.2004: Jan 11 2004: 03:49
+# Changed handling bans without setby/time information closer to how irssi does.
+# 08.01.2004: Jan 08 2004: 02:46
+# Fixed a bug which occured if the IRCd didn't tell us who set the bans at which time. eg. IRCNet if a user doesn't have +o.
+# 08.01.2004: Jan 08 2004: 01:52
+# Initial Release. Many thanks to coekie for helping me with my scripting.
diff --git a/scripts/beep.pl b/scripts/beep.pl
new file mode 100644
index 0000000..0bc5c53
--- /dev/null
+++ b/scripts/beep.pl
@@ -0,0 +1,50 @@
+# $Id: beep.pl,v 1.9 2002/07/04 13:18:02 jylefort Exp $
+
+use strict;
+use Irssi 20020121.2020 ();
+use vars qw($VERSION %IRSSI);
+$VERSION = "1.01";
+%IRSSI = (
+ authors => 'Jean-Yves Lefort',
+ contact => 'jylefort\@brutele.be, decadix on IRCNet',
+ name => 'beep',
+ description => 'Replaces your terminal bell by a command specified via /set; adds a beep_when_not_away setting',
+ license => 'BSD',
+ url => 'http://void.adminz.be/irssi.shtml',
+ changed => '$Date: 2002/07/04 13:18:02 $ ',
+);
+
+# /set's:
+#
+# beep_when_not_away opposite of builtin beep_when_away
+#
+# beep_command if not empty, the specified command will be
+# executed instead of the normal terminal bell
+# changes:
+#
+# 2002-07-04 release 1.01
+# * signal_add's uses a reference instead of a string
+#
+# 2002-04-25 release 1.00
+# * increased version number
+#
+# 2002-01-24 initial release
+
+sub beep {
+ my $server = Irssi::active_server;
+ if ($server && ! $server->{usermode_away}
+ && ! Irssi::settings_get_bool("beep_when_not_away")) {
+ Irssi::signal_stop();
+ } else {
+ if (my $command = Irssi::settings_get_str("beep_command")) {
+ system($command);
+ Irssi::signal_stop();
+ }
+ }
+}
+
+Irssi::settings_add_bool("lookandfeel", "beep_when_not_away", 0);
+Irssi::settings_add_str("misc", "beep_command",
+ "esdplay ~/sound/events/beep.wav &");
+
+Irssi::signal_add("beep", \&beep);
diff --git a/scripts/beep_beep.pl b/scripts/beep_beep.pl
new file mode 100644
index 0000000..2c139ab
--- /dev/null
+++ b/scripts/beep_beep.pl
@@ -0,0 +1,54 @@
+#!/usr/bin/irssi
+#
+# irssi beep replace script (tested with irssi v0.8.8.CVS (20030126-1726))
+# (C) 2002-2004 Ge0rG@IRCnet (Georg Lukas <georg@op-co.de>)
+# inspired and tested by Macrotron@IRCnet (macrotron@president.eu.org)
+
+# added beep_flood to irssi settings: beep_cmd will be run not more often
+# then every $beep_flood milliseconds
+
+# fixed memory leak with timeout_add (made irssi waste 80mb and more after a day of IRC)
+# added > /dev/null, thx to Luis Oliveira
+# fixed timeout handling bug, thx to frizop@charter.net
+
+use strict;
+use vars qw($VERSION %IRSSI);
+$VERSION = "0.10";
+%IRSSI = (
+ authors => "Georg Lukas",
+ contact => "georg\@op-co.de",
+ name => "beep_beep",
+ description => "runs arbitrary command instead of system beep, includes flood protection",
+ license => "Public Domain",
+ url => "http://op-co.de/irssi/",
+);
+
+use Irssi;
+
+my $might_beep = 1;
+my $to_tag;
+
+sub beep_overflow_timeout() {
+ $might_beep = 1;
+ Irssi::timeout_remove($to_tag);
+}
+
+sub beep_beep() {
+ my $beep_cmd = Irssi::settings_get_str("beep_cmd");
+ if ($beep_cmd) {
+ if ($might_beep) {
+ my $beep_flood = Irssi::settings_get_int('beep_flood');
+ $beep_flood = 1000 if $beep_flood < 0;
+ Irssi::timeout_remove($to_tag);
+ $to_tag = Irssi::timeout_add($beep_flood, 'beep_overflow_timeout', undef);
+ system($beep_cmd);
+ $might_beep = 0;
+ }
+ Irssi::signal_stop();
+ }
+}
+
+Irssi::settings_add_str("lookandfeel", "beep_cmd", "play ~/.irssi/scripts/beep_beep.wav > /dev/null &");
+Irssi::settings_add_int("lookandfeel", "beep_flood", 250);
+Irssi::signal_add("beep", "beep_beep");
+
diff --git a/scripts/beepaway.pl b/scripts/beepaway.pl
new file mode 100644
index 0000000..ade6e7b
--- /dev/null
+++ b/scripts/beepaway.pl
@@ -0,0 +1,41 @@
+#!/usr/bin/perl
+#
+# by Simon 'corecode' Schuberty <corecode@corecode.ath.cx>
+
+use strict;
+use vars qw($VERSION %IRSSI);
+$VERSION = "2018122301";
+%IRSSI = (
+ authors => "Simon 'corecode' Schubert",
+ contact => "corecode\@corecode.ath.cx",
+ name => "beepaway",
+ description => "Only beep when you are away",
+ license => "BSD",
+ changed => "$VERSION",
+);
+use Irssi 20020324;
+
+sub catch_away {
+ my $level;
+ my $server;
+ ($server) = @_;
+
+ if ($server->{usermode_away}) {
+ $level = Irssi::settings_get_str("beep_away_msg_level")
+ } else {
+ $level = Irssi::settings_get_str("beep_back_msg_level")
+ }
+# Irssi::print "%R>>%n setting levels ``$level''";
+ if ($level eq '' || $level =~ m/NONE/) {
+ $server->command("/^set -clear beep_msg_level ");
+ } else {
+ $server->command("/^set beep_msg_level ".$level);
+ }
+}
+
+Irssi::settings_add_str($IRSSI{name}, "beep_away_msg_level", "MSGS NOTICES DCC DCCMSGS HILIGHT");
+Irssi::settings_add_str($IRSSI{name}, "beep_back_msg_level", "NONE");
+
+Irssi::signal_add("away mode changed", "catch_away");
+
+print CLIENTCRAP '%B>>%n '.$IRSSI{name}.' '.$VERSION.' (c) '.$IRSSI{authors}.' loaded';
diff --git a/scripts/bestoiber.pl b/scripts/bestoiber.pl
new file mode 100644
index 0000000..7d9f68f
--- /dev/null
+++ b/scripts/bestoiber.pl
@@ -0,0 +1,61 @@
+#!/usr/bin/perl
+#
+# by Stefan 'tommie' Tomanek
+
+use strict;
+
+use vars qw($VERSION %IRSSI);
+$VERSION = "2003020801";
+%IRSSI = (
+ authors => "Stefan 'tommie' Tomanek",
+ contact => "stefan\@pico.ruhr.de",
+ name => "BeStoiber",
+ description => "stoibers your messages",
+ license => "GPLv2",
+ url => "",
+ modules => "",
+ changed => "$VERSION",
+ commands => "bestoiber"
+);
+
+
+use Irssi 20020324;
+
+sub stoibern ($) {
+ my ($text) = @_;
+ my $result;
+ my $buffer;
+ foreach (split / /, $text) {
+ if (int(rand(4)) == 1) {
+ $result .= ' eehh, ';
+ } else {
+ $result .= ' ';
+ }
+ if (substr($_, 0,1) =~ /[A-Z]+/ && int(rand(2)) == 1) {
+ my @buzzwords = split(/,/, Irssi::settings_get_str('bestoiber_buzzwords'));
+ $result .= $buzzwords[rand(scalar(@buzzwords))].", ";
+ }
+ if (int(rand(6)) == 1) {
+ $result =~ s/,?\ $//;
+ $result .= ", ".$buffer." " if $buffer;
+ }
+
+ $result .= $_;
+ $buffer = $_;
+ }
+ $result =~ s/^ //;
+ return $result;
+}
+
+sub cmd_bestoiber ($$$) {
+ my ($arg, $server, $witem) = @_;
+ if ($witem && ($witem->{type} eq 'CHANNEL' || $witem->{type} eq 'QUERY')) {
+ $witem->command('MSG '.$witem->{name}.' '.stoibern($arg));
+ } else {
+ print CLIENTCRAP "%B>>%n ".stoibern($arg);
+ }
+}
+
+Irssi::settings_add_str($IRSSI{name}, 'bestoiber_buzzwords', 'Arbeitslose,Fr. Merkel,Schröder');
+
+Irssi::command_bind('bestoiber', \&cmd_bestoiber);
diff --git a/scripts/bgta.pl b/scripts/bgta.pl
new file mode 100644
index 0000000..3b388e3
--- /dev/null
+++ b/scripts/bgta.pl
@@ -0,0 +1,284 @@
+#!/usr/local/bin/perl
+
+# BgTA SCRIPT
+
+use strict;
+use vars qw($VERSION %IRSSI %FEATURES);
+
+use Irssi;
+
+# Define Script Version
+$VERSION = '0.0.1';
+%IRSSI = (
+ authors => '[^BgTA^]',
+ contact => 'raul@bgta.net',
+ name => 'BgTA Script',
+ description => 'Byte\'s Gallery of the TAilor Script',
+ license => 'Public Domain',
+);
+
+# /bgversion command
+
+sub cmd_bgversion {
+ my ($data, $server, $witem) = @_;
+
+ print("\cC4BgTA Script v. ".$VERSION);
+ foreach my $key (sort keys %IRSSI) {
+ print("\cC4$key: \cC0".$IRSSI{$key}) unless $key =~ /name/i;
+ }
+ return 1;
+}
+
+Irssi::command_bind bgversion => \&cmd_bgversion;
+
+# /bghelp command
+$FEATURES{'help'} = "/bghelp \c0 List the BgTA Script FEATURES";
+
+sub cmd_bghelp {
+ my ($data, $server, $witem) = @_;
+
+ print("\cC4BgTA Script v. ".$VERSION);
+ foreach my $key (sort keys %FEATURES) {
+ print("\cC4$key: \cC0".$FEATURES{$key}) unless $key =~ /name/i;
+ }
+ return 1;
+}
+
+Irssi::command_bind bghelp => \&cmd_bghelp;
+# GOOGLE
+$FEATURES{'google'} = "/bggoogle \cC7search_string \t \cC5Search one result in Google.com";
+
+sub cmd_bggoogle {
+ my ($data, $server, $witem) = @_;
+
+ return unless $witem;
+
+
+ use Net::Google;
+
+ # Put here the Google Key. See Google->Tools & Services
+ use constant LOCAL_GOOGLE_KEY => "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
+
+ $witem->command("me Google Searching [$data]...");
+ my $google = Net::Google->new(key=>LOCAL_GOOGLE_KEY);
+
+ my $search = $google->search(max_results => 100);
+
+ $search->query($data);
+
+ my @tresults = @{$search->results()};
+
+ if(!defined($tresults[0])) {
+ $witem->command("me NO RESULTS");
+ return;
+ }
+ my $title = $tresults[0]->title();
+ $title =~ s/<[^<]*>//ig;
+ $witem->command("me ".$title."\cC2: ".$tresults[0]->URL());
+ return;
+}
+
+Irssi::command_bind bggoogle => \&cmd_bggoogle;
+
+# PHP Documentation
+$FEATURES{'php'} = "/bgphp \cC7function_name \t \cC5Search a PHP Function URL and Definition";
+$FEATURES{'phpwb'} = "/bgphpwb \cC7function_name \t \cC5Search a PHP Function URL and Definition AND Kick BAN With the URL";
+sub cmd_bgphp {
+
+ my ($data, $server, $witem) = @_;
+
+ return unless $witem;
+
+
+ use LWP;
+
+ my $Navigator = new LWP::UserAgent({
+ "agent" => "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)",
+ "timeout" => "180",
+ });
+
+ $data =~ s/\_/\-/ig;
+
+ my $Page = $Navigator->get('http://www.php.net/manual/es/function.'.$data.'.php');
+
+ my $content = $Page->content if $Page->is_success;
+ if($Page->is_success && $content =~ /([^<]*)<B\nCLASS=\"methodname\"\n>([^<]*)<\/B\n> ([^<]*)/i) {
+ $witem->command("me PHP Function $data:");
+ $witem->command("me Location: \cC5 http://www.php.net/manual/es/function.".$data.'.php');
+ if($content =~ /<td><a href=\"ref.([^\.]*).php\">/i) {
+ $witem->command("me Reference: \cC6 http://www.php.net/manual/es/ref.$1.php");
+ }
+ if($content =~ />([^<]*)<B\nCLASS=\"methodname\"\n>([^<]*)<\/B\n> ([^<]*)/i) {
+ $witem->command("me $1\cC0$2\cC $3");
+ }
+ if($content =~ /--\&nbsp;([A-Za-z0-9\ áéíóú\n]+)/i) {
+ my $sal = $1;
+ $sal =~ s/\ \ /\ /gi;
+ $sal =~ s/\n/\ /gi;
+ chomp($sal);
+ $witem->command("me Description: $sal");
+ }
+ } else {
+ $witem->command("me \cC5PHP Function $data: No Results.");
+ }
+
+ return;
+
+}
+
+sub cmd_bgphpwb {
+
+ my ($data, $server, $witem) = @_;
+
+ return unless $witem;
+
+
+ use LWP;
+
+ my $Navigator = new LWP::UserAgent({
+ "agent" => "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)",
+ "timeout" => "180",
+ });
+
+ $data =~ /^([^\ ]*) (.*)$/i;
+ my $nick = $1;
+ $data = $2;
+ $data =~ s/\_/\-/ig;
+
+ my $Page = $Navigator->get('http://www.php.net/manual/es/function.'.$data.'.php');
+
+ my $content = $Page->content if $Page->is_success;
+ if($Page->is_success && $content =~ /([^<]*)<B\nCLASS=\"methodname\"\n>([^<]*)<\/B\n> ([^<]*)/i) {
+ $witem->command("kickban $nick Mira el Jodido Manual: \cC5 http://www.php.net/manual/es/function.".$data.'.php');
+ }
+
+ return;
+
+}
+sub bgphpevent {
+ my ($server, $data, $nick, $address) = @_;
+ my ($target, $text) = $data =~ /^(\S*)\s:(.*)/;
+
+ #if($text =~ /bgphp:(.*)$/) {
+ #}
+
+}
+Irssi::signal_add("event notice", "bgphpevent");
+Irssi::command_bind bgphp => \&cmd_bgphp;
+Irssi::command_bind bgphpwb => \&cmd_bgphpwb;
+
+
+# WEB SEARCH TITLE
+$FEATURES{'wwwd'} = "/bgwwwd \cC7http://some.web.com/ \t \cC5Look for title and Description of Web";
+sub cmd_bgwwwd {
+
+ my ($data, $server, $witem) = @_;
+
+ return unless $witem;
+
+
+ use LWP;
+
+ my $Navigator = new LWP::UserAgent({
+ "agent" => "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)",
+ "timeout" => "180",
+ });
+
+ my $Page = $Navigator->get($data);
+
+ if($Page->is_success) {
+ my $content = $Page->content;
+ my $title = "No Title";
+ my $description = "No Description Page";
+
+ if($content =~ /TITLE>([^<]*)<\/TITLE>/i) {
+ $title = $1;
+ }
+
+ if($content =~ /META NAME=\"DESCRIPTION\" CONTENT=\"([^\"]*)\"/i) {
+ $description = $1;
+ }
+ $witem->command("me [ $data ]: ".$title);
+ $witem->command("me \cC5 $description");
+ } else {
+ $witem->command("me [ $data ] Page Not Found");
+ }
+}
+
+Irssi::command_bind bgwwwd => \&cmd_bgwwwd;
+
+
+# Perl Documentation
+$FEATURES{'perl'} = "/bgperl \cC7function_name \t \cC5Search a Perl Function URL and Definition";
+sub cmd_bgperl {
+
+ my ($data, $server, $witem) = @_;
+
+ return unless $witem;
+
+
+ use LWP;
+
+ my $Navigator = new LWP::UserAgent({
+ "agent" => "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)",
+ "timeout" => "180",
+ });
+
+ my $Page = $Navigator->get('http://www.perldoc.com/perl5.8.0/pod/func/'.$data.'.html');
+
+ my $content = $Page->content if $Page->is_success;
+ if($Page->is_success && $content =~ /<span class=\"docTitle\">([^<]*)<\/span>/i) {
+ $witem->command("me Perl Function $data:");
+ $witem->command("me Location: \cC5 http://www.perldoc.com/perl5.8.0/pod/func/".$data.'.html');
+ if($content =~ /<DL><DT><A NAME=\"[^\"]*\">(.*)\n/i) {
+ $witem->command("me \cC0$1");
+ }
+ if($content =~ /<DT><A NAME=\"$data\">$data\n\n<\/A><\/DT>\n<DD>\n([^\n]*)/i) {
+ $witem->command("me $1");
+ }
+ } else {
+ $witem->command("me \cC5Perl Function $data: No Results.");
+ }
+
+ return;
+
+}
+Irssi::command_bind bgperl => \&cmd_bgperl;
+
+# Debian Search Packages
+$FEATURES{'debian'} = "/bgdebian \cC7package name | \cC5Search a package in a Debian stable distribution";
+sub cmd_bgdebian {
+
+ my ($data, $server, $witem) = @_;
+
+ return unless $witem;
+
+
+ use LWP;
+
+ my $Navigator = new LWP::UserAgent({
+ "agent" => "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)",
+ "timeout" => "180",
+ });
+
+ $data =~ s/\ /\+/;
+ my $Page = $Navigator->get('http://packages.debian.org/cgi-bin/search_packages.pl?keywords='.$data.'&searchon=names&subword=1&version=stable&release=all');
+
+ my $content = $Page->content if $Page->is_success;
+ if($Page->is_success && $content =~ /<TD><B><A HREF=\"http:\/\/packages\.debian\.org\/stable\/misc\/([^\.]*).html\"> $data/i) {
+ $witem->command("me Debian \cC2$data\cC package:");
+ $witem->command("me Location: \cC5 http://packages.debian.org/stable/misc/$1.html");
+ if($content =~ /<TD COLSPAN=2>([^<]*)</i) {
+ $witem->command("me Description: $1");
+ }
+ } else {
+ $witem->command("me \cC5Debian $data package: No Results.");
+ }
+
+ return;
+
+}
+Irssi::command_bind bgdebian => \&cmd_bgdebian;
+1;
+
+
diff --git a/scripts/binary.pl b/scripts/binary.pl
new file mode 100644
index 0000000..1eb374a
--- /dev/null
+++ b/scripts/binary.pl
@@ -0,0 +1,114 @@
+# /binary huora
+# tuolostaa k.o. ikkunaan huora:n sijaan 01101001 ....
+#
+# and modified by carl 2004-03-09
+
+# Changelog
+# Version 1: original version by nchip
+# Version 1.1: added unbinary function
+# Verison 1.2: added server truncate detection (requested by André, thanks for spotting the problem) and choice to have spaces in the binary or not (reqested by Tapio)
+
+
+use strict;
+use Irssi;
+use Irssi qw(command_bind command signal_add_last signal_stop settings_get_bool settings_add_bool);
+
+use vars qw($VERSION %IRSSI);
+
+#%IRSSI = (
+# authors => "Riku Voipio",
+# contact => "riku.voipio\@iki.fi",
+# name => "binary",
+# description => "adds /binary command that converts what you type into 2-base string representation",
+# license => "GPLv2",
+# url => "http://nchip.ukkosenjyly.mine.nu/irssiscripts/",
+# );
+
+$VERSION = "1.2";
+%IRSSI = (
+ authors => "Carl Fischer",
+ contact => "carl.fischer\@netcourrier.com",
+ name => "binary",
+ description => "adds /binary command that converts what you type into 2-base string representation, also decodes other peoples binary automatically",
+ license => "GPLv2",
+ );
+
+
+sub cmd_binary {
+ $_=join(" ",$_[0]);
+ $_=reverse;
+ my (@r);
+ if (settings_get_bool('binary_spaces')) {
+ $r[0]="/say";
+ } else {
+ $r[0]="/say ";
+ }
+ while ($a = chop($_)) {
+ push (@r,unpack ("B*", $a));}
+
+ my $window = Irssi::active_win();
+ if (settings_get_bool('binary_spaces')) {
+ $window->command(join (" ",@r));
+ } else {
+ $window->command(join ("",@r));
+ }
+ }
+
+# here ends the original code
+# some of the following was strongly inspired by the kenny script
+
+sub cmd_unbinary {
+ pop @_;
+ pop @_;
+ my $window = Irssi::active_win();
+ $window->print(unbinary($_[0]));
+}
+
+sub unbinary {
+ my $r;
+ if (settings_get_bool('binary_spaces')) {
+ $r=pack("B*", join ("", split(" ", @_[0])));
+ } else {
+ $r=pack("B*", @_[0]);
+ }
+ return $r;
+}
+
+sub sig_binary {
+ my ($server, $msg, $nick, $address, $target) = @_;
+ if (($msg=~m/^([01]{8}( [01]{8})*)( [01]{1,7})*$/ and settings_get_bool('binary_spaces')) or ($msg=~m/^([01]{8}([01]{8})*)([01]{1,7})*$/ and not settings_get_bool('binary_spaces'))) {
+ my $leftover="";
+ $leftover="* (truncated by server)" if $3;
+ $target=$nick if $target eq "";
+ # the address may _never_ be emtpy, if it is its own_public
+ $nick=$server->{'nick'} if $address eq "";
+ $server->window_item_find($target)->print("[binary] <$nick> " .
+ unbinary($1) . $leftover, 'MSGLEVEL_CRAP');
+ signal_stop() if not settings_get_bool('show_binary_too');
+ }
+}
+
+signal_add_last('message own_public', 'sig_binary');
+signal_add_last('message public', 'sig_binary');
+signal_add_last('message own_private', 'sig_binary');
+signal_add_last('message private', 'sig_binary');
+
+settings_add_bool('lookandfeel', 'show_binary_too', 0);
+settings_add_bool('lookandfeel', 'binary_spaces', 1);
+
+Irssi::command_bind('binary', 'cmd_binary');
+Irssi::command_bind('unbinary', 'cmd_unbinary');
+
+Irssi::print("binary obfuscator vanity script loaded");
+Irssi::print("written by nchip and updated by carl");
+Irssi::print("--------------------------------------");
+Irssi::print("/binary message");
+Irssi::print("will send binary text to the current channel");
+Irssi::print("");
+Irssi::print("/unbinary obfuscated_text");
+Irssi::print("will print the unobfuscated equivalent to your window (and not to the channel)");
+Irssi::print("");
+Irssi::print("/set show_binary_too on");
+Irssi::print("will make this script print the binary equivalent as well as the translation to your screen whenever someone uses binary on the channel");
+Irssi::print("/set binary_spaces off");
+Irssi::print("will make the binary be printed as a single word with no spaces");
diff --git a/scripts/bitlbee_blist.pl b/scripts/bitlbee_blist.pl
new file mode 100644
index 0000000..864001f
--- /dev/null
+++ b/scripts/bitlbee_blist.pl
@@ -0,0 +1,77 @@
+# Changelog
+#
+# 2008-09-13 (v 0.5)
+# Thanks to Olof Johansson the first parm can just be a regexp.
+#
+
+use strict;
+use vars qw($VERSION %IRSSI);
+
+$VERSION = '0.5';
+%IRSSI = (
+ authors => 'Tijmen "timing" Ruizendaal',
+ contact => 'tijmen.ruizendaal@gmail.com',
+ name => 'bitlbee_blist',
+ description => '/blist <all|online|offline|away|word> <word>, greps <word> from blist for bitlbee',
+ license => 'GPLv2',
+ url => 'http://the-timing.nl/stuff/irssi-bitlbee',
+ changed => '2008-09-13',
+);
+
+my $bitlbee_server_tag = "localhost";
+my $bitlbee_channel = "&bitlbee";
+my ($list, $word);
+
+get_channel();
+
+Irssi::signal_add_last 'channel sync' => sub {
+ my( $channel ) = @_;
+ if( $channel->{topic} eq "Welcome to the control channel. Type \x02help\x02 for help information." ){
+ $bitlbee_server_tag = $channel->{server}->{tag};
+ $bitlbee_channel = $channel->{name};
+ }
+};
+
+sub get_channel {
+ my @channels = Irssi::channels();
+ foreach my $channel(@channels) {
+ if ($channel->{topic} eq "Welcome to the control channel. Type \x02help\x02 for help information.") {
+ $bitlbee_channel = $channel->{name};
+ $bitlbee_server_tag = $channel->{server}->{tag};
+ return 1;
+ }
+ }
+ return 0;
+}
+
+sub blist {
+ my ($args, $server, $winit) = @_;
+ ($list, $word) = split(/ /, $args, 2);
+ ($word, $list) = ($list, $word) unless $word;
+ $list=lc $list;
+ $word=lc $word;
+ if($list ne "all" && $list ne "online" && $list ne "offline" &&
+ $list ne "away" && $list ne "") {
+ $word=$list;
+ $list="";
+ }
+ if (Irssi::active_win->{'active'}->{'name'} eq $bitlbee_channel) {
+ print "blist $list";
+ Irssi::active_win()->command("msg $bitlbee_channel blist $list");
+ Irssi::signal_add('event privmsg', 'grep');
+ } else {
+ print "Only use in $bitlbee_channel.";
+ }
+}
+
+sub grep {
+ my ($server, $data, $nick, $address) = @_;
+ my ($target, $text) = split(/ :/, $data, 2);
+ $text=lc $text;
+ if ($text =~ /$word/ && $target =~ /$bitlbee_channel/){
+ ##do nothing
+ } else {Irssi::signal_stop();}
+ if ($text =~ /buddies/ && $target =~/$bitlbee_channel/){Irssi::signal_remove('event privmsg', 'grep');}
+}
+
+Irssi::command_bind('blist','blist');
diff --git a/scripts/bitlbee_join_notice.pl b/scripts/bitlbee_join_notice.pl
new file mode 100644
index 0000000..53bfdfc
--- /dev/null
+++ b/scripts/bitlbee_join_notice.pl
@@ -0,0 +1,109 @@
+# CHANGELOG:
+#
+# 2010-08-10 (version 1.3)
+# * new bitlbee server detection
+#
+# 2004-11-28:
+# * adds join message to query
+#
+# /statusbar window add join_notice
+# use Data::Dumper;
+
+use strict;
+use Irssi::TextUI;
+#use Irssi::Themes;
+use Data::Dumper;
+
+use vars qw($VERSION %IRSSI);
+
+$VERSION = '1.3';
+%IRSSI = (
+ authors => 'Tijmen "timing" Ruizendaal',
+ contact => 'tijmen.ruizendaal@gmail.com',
+ name => 'BitlBee_join_notice',
+ description => '1. Adds an item to the status bar wich shows [joined: <nicks>] when someone is joining &bitlbee. 2. Shows join messages in the query. (For bitlbee v3.0+)',
+ sbitems => 'join_notice',
+ license => 'GPLv2',
+ url => 'http://the-timing.nl/stuff/irssi-bitlbee',
+ changed => '2010-08-10'
+);
+my %timers;
+my $bitlbee_server; # server object
+my @control_channels; # mostly: &bitlbee, &facebook etc.
+init();
+
+sub init { # if script is loaded after connect
+ my @servers = Irssi::servers();
+ foreach my $server(@servers) {
+ if( $server->isupport('NETWORK') eq 'BitlBee' ){
+ $bitlbee_server = $server;
+ my @channels = $server->channels();
+ foreach my $channel(@channels) {
+ if( $channel->{mode} =~ /C/ ){
+ push @control_channels, $channel->{name} unless (grep $_ eq $channel->{name}, @control_channels);
+ }
+ }
+ }
+ }
+}
+# if connect after script is loaded
+Irssi::signal_add_last('event 005' => sub {
+ my( $server ) = @_;
+ if( $server->isupport('NETWORK') eq 'BitlBee' ){
+ $bitlbee_server = $server;
+ }
+});
+# if new control channel is synced after script is loaded
+Irssi::signal_add_last('channel sync' => sub {
+ my( $channel ) = @_;
+ if( $channel->{mode} =~ /C/ && $channel->{server}->{tag} eq $bitlbee_server->{tag} ){
+ push @control_channels, $channel->{name} unless (grep $_ eq $channel->{name}, @control_channels);
+ }
+});
+
+# BEGIN bitlbee_join_notice.pl
+
+my %online;
+
+sub event_join {
+ my ($server, $channel, $nick, $address) = @_;
+ $channel =~ s/^://g;
+ if ( (grep $_ eq $channel, @control_channels) && $server->{tag} eq $bitlbee_server->{tag}){
+ $online{$nick} = 1;
+ Irssi::timeout_remove($timers{$nick});
+ delete($timers{$nick});
+ $timers{$nick} = Irssi::timeout_add_once(7000, 'empty', $nick);
+ Irssi::statusbar_items_redraw('join_notice');
+ my $window = Irssi::window_find_item($nick);
+ if($window){
+ $window->printformat(Irssi::MSGLEVEL_JOINS, 'join', $nick, $address, $channel);
+ }
+ }
+}
+sub join_notice {
+ my ($item, $get_size_only) = @_;
+ my $line;
+ foreach my $key (keys(%online) ){
+ $line = $line." ".$key;
+ }
+ if ($line ne "" ){
+ $item->default_handler($get_size_only, "{sb joined:$line}", undef, 1);
+ $line = "";
+ } else {
+ $item->default_handler($get_size_only, "", undef, 1);
+ }
+}
+sub empty {
+ my $nick = shift;
+ delete($online{$nick});
+ Irssi::timeout_remove($timers{$nick});
+ delete($timers{$nick});
+ Irssi::statusbar_items_redraw('join_notice');
+}
+
+Irssi::signal_add('event join', 'event_join' );
+Irssi::statusbar_item_register('join_notice', undef, 'join_notice');
+Irssi::statusbars_recreate_items();
+Irssi::theme_register([ 'join', '{channick_hilight $0} {chanhost $1} has joined {channel $2}', ]);
+
+# END bitlbee_join_notice.pl
diff --git a/scripts/bitlbee_nick_change.pl b/scripts/bitlbee_nick_change.pl
new file mode 100644
index 0000000..93a01b9
--- /dev/null
+++ b/scripts/bitlbee_nick_change.pl
@@ -0,0 +1,72 @@
+use strict;
+use Data::Dumper;
+use vars qw($VERSION %IRSSI);
+
+$VERSION = '1.3';
+%IRSSI = (
+ authors => 'Tijmen "timing" Ruizendaal',
+ contact => 'tijmen.ruizendaal@gmail.com',
+ name => 'BitlBee_nick_change',
+ description => 'Shows an IM nickchange in an Irssi way. (in a query and in the bitlbee channel). (For bitlbee 3.0+)',
+ license => 'GPLv2',
+ url => 'http://the-timing.nl/stuff/irssi-bitlbee',
+ changed => '2010-07-28'
+);
+
+my $bitlbee_server; # server object
+my @control_channels; # mostly: &bitlbee, &facebook etc.
+init();
+
+sub init { # if script is loaded after connect
+ my @servers = Irssi::servers();
+ foreach my $server(@servers) {
+ if( $server->isupport('NETWORK') eq 'BitlBee' ){
+ $bitlbee_server = $server;
+ my @channels = $server->channels();
+ foreach my $channel(@channels) {
+ if( $channel->{mode} =~ /C/ ){
+ push @control_channels, $channel->{name} unless (grep $_ eq $channel->{name}, @control_channels);
+ }
+ }
+ }
+ }
+}
+# if connect after script is loaded
+Irssi::signal_add_last('event 005' => sub {
+ my( $server ) = @_;
+ if( $server->isupport('NETWORK') eq 'BitlBee' ){
+ $bitlbee_server = $server;
+ }
+});
+# if new control channel is synced after script is loaded
+Irssi::signal_add_last('channel sync' => sub {
+ my( $channel ) = @_;
+ if( $channel->{mode} =~ /C/ && $channel->{server}->{tag} eq $bitlbee_server->{tag} ){
+ push @control_channels, $channel->{name} unless (grep $_ eq $channel->{name}, @control_channels);
+ }
+});
+
+# BEGIN bitlbee_nick_change.pl
+
+sub event_notice {
+ my ($server, $msg, $nick, $address, $target) = @_;
+ if( $server->{tag} eq $bitlbee_server->{tag} && $msg =~ /.*Changed name to.*/ ){
+ my $friendly_name = $msg;
+ $friendly_name =~ s/.*Changed name to `(.*)'.*/$1/;
+ my $window = $server->window_find_item($nick);
+ if ($window) {
+ $window->printformat(MSGLEVEL_CRAP, 'nick_change', $nick, $address, 'changed name to `'.$friendly_name.'`');
+ Irssi::signal_stop();
+ } else {
+ # TODO find control channel where this user is located and display the notice there
+ #my $window = $server->window_find_item($bitlbee_channel);
+ #$window->printformat(MSGLEVEL_CRAP, 'nick_change', $nick, $address, 'changed name to `'.$friendly_name.'`');
+ #Irssi::signal_stop();
+ }
+ }
+};
+
+Irssi::signal_add_last('message irc notice', 'event_notice');
+Irssi::theme_register(['nick_change', '{channick_hilight $0} [$1] $2']);
+
+# END bitbee_nick_change.pl
diff --git a/scripts/bitlbee_tab_completion.pl b/scripts/bitlbee_tab_completion.pl
new file mode 100644
index 0000000..8d19128
--- /dev/null
+++ b/scripts/bitlbee_tab_completion.pl
@@ -0,0 +1,88 @@
+use strict;
+use vars qw($VERSION %IRSSI);
+
+$VERSION = '1.3';
+
+%IRSSI = (
+ authors => 'Tijmen "timing" Ruizendaal & Wilmer van der Gaast',
+ contact => 'tijmen.ruizendaal@gmail.com',
+ name => 'BitlBee_tab_completion',
+ description => 'Intelligent Tab-completion for BitlBee commands.',
+ license => 'GPLv2',
+ url => 'http://the-timing.nl/stuff/irssi-bitlbee',
+ changed => '2009-08-11',
+);
+
+my $root_nick = 'root';
+my $bitlbee_channel = '&bitlbee';
+my $bitlbee_server_tag = 'localhost';
+my $get_completions = 0;
+
+my @commands;
+
+Irssi::signal_add_last 'channel sync' => sub {
+ my( $channel ) = @_;
+ if( $channel->{topic} eq "Welcome to the control channel. Type \x02help\x02 for help information." ){
+ $bitlbee_server_tag = $channel->{server}->{tag};
+ $bitlbee_channel = $channel->{name};
+ request_completions();
+ }
+};
+
+if (get_channel()) {
+ request_completions();
+}
+
+sub request_completions {
+ $get_completions = 1;
+ Irssi::server_find_tag($bitlbee_server_tag)->send_raw( 'COMPLETIONS' );
+}
+
+sub get_channel {
+ my @channels = Irssi::channels();
+ foreach my $channel(@channels) {
+ if ($channel->{topic} eq "Welcome to the control channel. Type \x02help\x02 for help information.") {
+ $bitlbee_channel = $channel->{name};
+ $bitlbee_server_tag = $channel->{server}->{tag};
+ return 1;
+ }
+ }
+ return 0;
+}
+
+sub irc_notice {
+ return unless $get_completions;
+ my( $server, $msg, $from, $address, $target ) = @_;
+
+ if( $msg =~ s/^COMPLETIONS // ) {
+ $root_nick = $from;
+ if( $msg eq 'OK' ) {
+ @commands = ();
+ }
+ elsif( $msg eq 'END' ) {
+ $get_completions = 0;
+ }
+ @commands = ( @commands, $msg );
+
+ Irssi::signal_stop();
+ }
+}
+
+sub complete_word {
+ my ($complist, $window, $word, $linestart, $want_space) = @_;
+ my $channel = $window->get_active_name();
+ if ($channel eq $bitlbee_channel or $channel eq $root_nick or $linestart =~ /^\/(msg|query) \Q$root_nick\E */i){
+ $linestart =~ s/^\/(msg|query) \Q$root_nick\E *//i;
+ $linestart =~ s/^\Q$root_nick\E[:,] *//i;
+ foreach my $command(@commands) {
+ if ($command =~ /^$word/i) {
+ push @$complist, $command;
+ }
+ }
+ }
+}
+
+
+Irssi::signal_add_last('complete word', 'complete_word');
+Irssi::signal_add_first('message irc notice', 'irc_notice');
+
diff --git a/scripts/bitlbee_typing_notice.pl b/scripts/bitlbee_typing_notice.pl
new file mode 100644
index 0000000..10cd746
--- /dev/null
+++ b/scripts/bitlbee_typing_notice.pl
@@ -0,0 +1,349 @@
+# INSTALLATION
+# [&bitlbee] set typing_notice true
+# <@root> typing_notice = `true'
+# AND
+# /statusbar window add typing_notice
+#
+# SETTINGS
+# [bitlbee]
+# bitlbee_send_typing = ON
+# -> send typing messages to buddies
+# bitlbee_typing_allwin = OFF
+# -> show typing notifications in all windows
+#
+#
+# Changelog:
+#
+# 2016-01-01 (version 1.7.2)
+# * Fix crash in Irssi during disconnect
+#
+# 2010-08-09 (version 1.7.1)
+# * Multiple control channels supported by checking chanmodes
+#
+# 2010-07-27 (version 1.7)
+# * Using new server detection for latest BitlBee support
+#
+# 2010-07-26 (version 1.6.3)
+# * Removed checking if nicks exists in &bitlbee channel, this because BitlBee
+# can be used without control channel from this date
+#
+# 2007-03-03 (version 1.6.2)
+# * Fix: timers weren't deleted correctly. This resulted in huge mem usage.
+#
+# 2006-11-02 (version 1.6.1)
+# * Sending typing works again.
+#
+# 2006-10-27 (version 1.6)
+# * 'channel sync' re-implemented.
+# * bitlbee_send_typing was a string setting, It's a boolean now, like it should.
+#
+# 2006-10-24 (version 1.5)
+# * Sending notices to online users only. ( removed this again at 2010-07-26, see above )
+# * Using the new get_channel function;
+#
+# 2005-12-15 (version 1.42):
+# * Fixed small bug with typing notices disappearing under certain circumstances
+# in channels
+# * Fixed bug that caused outgoing notifications not to work
+# * root cares not about our typing status.
+#
+# 2005-12-04 (version 1.41):
+# * Implemented stale states in statusbar (shows "(stale)" for OSCAR connections)
+# * Introduced bitlbee_typing_allwin (default OFF). Set this to ON to make
+# typing notifications visible in all windows.
+#
+# 2005-12-03 (version 1.4):
+# * Major code cleanups and rewrites for bitlbee 1.0 with the updated typing
+# scheme. TYPING 0, TYPING 1, and TYPING 2 are now supported from the server.
+# * Stale states (where user has typed in text but has stopped typing) are now
+# recognized.
+# * Bug where user thinks you are still typing if you close the window after
+# typing something and then erasing it quickly.. fixed.
+# * If a user signs off while they are still typing, the notification is removed
+# This update by Matt "f0rked" Sparks
+#
+# 2005-08-26:
+# Some fixes for AIM, Thanks to Dracula.
+#
+# 2005-08-16:
+# AIM supported, for sending notices, using CTCP TYPING 0. (Use the AIM patch from Hanji http://get.bitlbee.org/patches/)
+#
+# 2004-10-31:
+# Sends typing notice to the bitlbee server when typing a message in irssi. bitlbee > 0.92
+#
+# 2004-06-11:
+# shows [typing: ] in &bitlbee with multiple users.
+#
+use strict;
+use Irssi::TextUI;
+use Data::Dumper;
+
+use vars qw($VERSION %IRSSI);
+
+$VERSION = '1.7.3';
+%IRSSI = (
+ authors => 'Tijmen "timing" Ruizendaal, Matt "f0rked" Sparks',
+ contact => 'tijmen.ruizendaal@gmail.com, root@f0rked.com',
+ name => 'BitlBee_typing_notice',
+ description => '1. Adds an item to the status bar wich shows [typing] when someone is typing a message on the supported IM-networks 2. Sends typing notices to the supported IM networks (the other way arround). (For bitlbee 3.0+)',
+ sbitems => 'typing_notice',
+ license => 'GPLv2',
+ url => 'http://the-timing.nl/stuff/irssi-bitlbee, http://f0rked.com',
+);
+
+my %bitlbee_tag; # server object
+my %control_channels; # mostly: &bitlbee, &facebook etc.
+init();
+
+sub init { # if script is loaded after connect
+ my @servers = Irssi::servers();
+ foreach my $server(@servers) {
+ if( $server->isupport('NETWORK') eq 'BitlBee' ){
+ my $T = $server->{tag};
+ $bitlbee_tag{$T} = 1;
+ my @channels = $server->channels();
+ foreach my $channel(@channels) {
+ if( $channel->{mode} =~ /C/ ){
+ push @{ $control_channels{$T} }, $channel->{name} unless (grep $_ eq $channel->{name}, @{ $control_channels{$T} // [] });
+ }
+ }
+ }
+ }
+}
+# if connect after script is loaded
+Irssi::signal_add_last('event 005' => sub {
+ my( $server ) = @_;
+ if( $server->isupport('NETWORK') eq 'BitlBee' ){
+ $bitlbee_tag{ $server->{tag} } = 1;
+ }
+});
+# if new control channel is synced after script is loaded
+Irssi::signal_add_last('channel sync' => sub {
+ my( $channel ) = @_;
+ my $T = $channel->{server}->{tag};
+ if( $channel->{mode} =~ /C/ && $bitlbee_tag{$T} ){
+ push @{ $control_channels{$T} }, $channel->{name} unless (grep $_ eq $channel->{name}, @{ $control_channels{$T} // [] });
+ }
+});
+
+# How often to check if we are typing, or on msn,
+# how long to keep the typing notice up, or check
+# if the other user is still typing...
+my $KEEP_TYPING_TIMEOUT = 1;
+my $STOP_TYPING_TIMEOUT = 7;
+
+my %timer_tag;
+
+my %typing;
+my %tag;
+my $line;
+my %out_typing;
+my $lastkey;
+my $keylog_active = 1;
+my $command_char = Irssi::settings_get_str('cmdchars'); # mostly: /
+my $to_char = Irssi::settings_get_str("completion_char"); # mostly: :
+
+sub event_ctcp_msg {
+ my ($server, $msg, $from, $address) = @_;
+ my $tag = $server->{tag};
+ return unless $bitlbee_tag{ $tag };
+ if ( my($type) = $msg =~ "TYPING ([0-9])" ){
+ Irssi::signal_stop();
+ if( $type == 0 ){
+ unset_typing($tag, $from);
+ } elsif( $type == 1 ){
+ my $k = "$tag/$from";
+ $typing{$k}=1;
+ if( $address !~ /\@login\.oscar\.aol\.com/ and $address !~ /\@YAHOO/ and $address !~ /\@login\.icq\.com/ ){
+ Irssi::timeout_remove($tag{$k});
+ delete($tag{$k});
+ $tag{$k}=Irssi::timeout_add_once($STOP_TYPING_TIMEOUT*1000,"unset_typing",[$tag,$from]);
+ }
+ redraw($tag, $from);
+ } elsif( $type == 2 ){
+ stale_typing($tag, $from);
+ }
+ }
+}
+
+sub unset_typing {
+ my($tag,$from,$no_redraw)=@_;
+ my $k = "$tag/$from";
+ delete $typing{$k} if $typing{$k};
+ Irssi::timeout_remove($tag{$k});
+ delete($tag{$k});
+ redraw($tag, $from) if !$no_redraw;
+}
+
+sub stale_typing {
+ my($tag,$from)=@_;
+ my $k = "$tag/$from";
+ $typing{$k}=2;
+ redraw($tag, $from);
+}
+
+sub redraw {
+ my($tag,$from)=@_;
+ my $window = Irssi::active_win();
+ my $name = $window->get_active_name();
+
+ # only redraw if current window equals to the typing person, is a control channel or if allwin is set
+ if( $from eq $name || (grep $_ eq $name, @{ $control_channels{$tag} // [] }) || Irssi::settings_get_bool("bitlbee_typing_allwin") ){
+ Irssi::statusbar_items_redraw('typing_notice');
+ }
+}
+
+sub event_msg {
+ my ($server,$data,$from,$address,$target) = @_;
+ my $tag = $server->{tag};
+ return unless $bitlbee_tag{ $tag };
+ my $channel=Irssi::active_win()->get_active_name();
+ unset_typing $tag, $from, "no redraw";
+ unset_typing $tag, $channel;
+}
+
+sub event_quit {
+ my $server = shift;
+ my $tag = $server->{tag};
+ return unless $bitlbee_tag{ $tag };
+ my $nick = shift;
+ unset_typing $tag, $nick;
+}
+
+sub typing_notice {
+ my ($item, $get_size_only) = @_;
+ my $window = Irssi::active_win();
+ my $tag = $window->{active}{server}{tag} // "";
+ my $channel = $window->get_active_name();
+ my $k = "$tag/$channel";
+
+ if (exists($typing{$k})) {
+ my $append=$typing{$k}==2 ? " (stale)" : "";
+ $item->default_handler($get_size_only, "{sb typing$append}", 0, 1);
+ } else {
+ $item->default_handler($get_size_only, "", 0, 1);
+ Irssi::timeout_remove($tag{$k});
+ delete($tag{$k});
+ }
+ # we check for correct windows again, because the statusbar item is redrawn after window change too.
+ if( (grep $_ eq $channel, @{ $control_channels{$tag} // [] }) || Irssi::settings_get_bool("bitlbee_typing_allwin")) {
+ foreach my $key (sort keys(%typing)) {
+ $line .= " ".$key;
+ if ($typing{$key}==2) { $line .= " (stale)"; }
+ }
+ if ($line ne "") {
+ $item->default_handler($get_size_only, "{sb typing:$line}", 0, 1);
+ $line = "";
+ }
+ }
+}
+
+sub window_change {
+ Irssi::statusbar_items_redraw('typing_notice');
+ my $win = !Irssi::active_win() ? undef : Irssi::active_win()->{active};
+ if (ref $win && defined $win->{server}->{tag} && $bitlbee_tag{ $win->{server}->{tag} }) {
+ if (!$keylog_active) {
+ $keylog_active = 1;
+ Irssi::signal_add_last('gui key pressed', 'key_pressed');
+ }
+ } else {
+ if ($keylog_active) {
+ $keylog_active = 0;
+ Irssi::signal_remove('gui key pressed', 'key_pressed');
+ }
+ }
+}
+
+sub key_pressed {
+ return if !Irssi::settings_get_bool("bitlbee_send_typing");
+ my $key = shift;
+ if ($key != 9 && $key != 10 && $key != 13 && $lastkey != 27 && $key != 27
+ && $lastkey != 91 && $key != 126 && $key != 127)
+ {
+ my $window = Irssi::active_win();
+ my $nick = $window->get_active_name();
+ my $tag = $window->{active}{server}{tag};
+ if (defined $tag && $bitlbee_tag{ $tag } && $nick ne "(status)" && $nick ne "root") {
+ if( grep $_ eq $nick, @{ $control_channels{$tag} // [] } ){ # send typing if in control channel
+ my $input = Irssi::parse_special("\$L");
+ my ($first_word) = split(/ /,$input);
+ if ($input !~ /^$command_char.*/ && $first_word =~ s/$to_char$//){
+ send_typing($tag, $first_word);
+ }
+ } else { # or any other channels / query
+ my $input = Irssi::parse_special("\$L");
+ if ($input !~ /^$command_char.*/ && length($input) > 0){
+ send_typing($tag, $nick);
+ }
+ }
+ }
+ }
+ $lastkey = $key;
+}
+
+sub delete_server {
+ my $tag = shift;
+ delete $bitlbee_tag{$tag};
+ delete $control_channels{$tag};
+ undef;
+}
+
+sub out_empty {
+ my ($a) = @_;
+ my($nick,$tag)=@{$a};
+ my $k = "$tag/$nick";
+ delete($out_typing{$k});
+ Irssi::timeout_remove($timer_tag{$k});
+ delete($timer_tag{$k});
+ if (my $bitlbee_server = Irssi::server_find_tag($tag)) {
+ $bitlbee_server->command("^CTCP $nick TYPING 0");
+ } else {
+ delete_server($tag);
+ }
+}
+
+sub send_typing {
+ my ($tag, $nick) = @_;
+ my $k = "$tag/$nick";
+ if (!exists($out_typing{$k}) || time - $out_typing{$k} > $KEEP_TYPING_TIMEOUT) {
+ if (my $bitlbee_server = Irssi::server_find_tag($tag)) {
+ $bitlbee_server->command("^CTCP $nick TYPING 1");
+ } else {
+ delete_server($tag);
+ }
+ $out_typing{$k} = time;
+ ### Reset 'stop-typing' timer
+ Irssi::timeout_remove($timer_tag{$k});
+ delete($timer_tag{$k});
+
+ ### create new timer
+ $timer_tag{$k} = Irssi::timeout_add_once($STOP_TYPING_TIMEOUT*1000, 'out_empty', ["$nick", $tag]);
+ }
+}
+
+#README: Delete the old bitlbee_send_typing string from ~/.irssi/config. A boolean is better.
+
+sub db_typing {
+ local $Data::Dumper::Sortkeys = 1;
+ print "Detected channels: ";
+ print Dumper(%control_channels);
+ print "Detected server tag: ".join ", ", sort keys %bitlbee_tag;
+ print "Tag: ".Dumper(%tag);
+ print "Timer Tag: ".Dumper(%timer_tag);
+ print "Typing: ".Dumper(%typing);
+ print "Out Typing: ".Dumper(%out_typing);
+}
+
+Irssi::command_bind('db_typing','db_typing');
+
+Irssi::settings_add_bool("bitlbee","bitlbee_send_typing",1);
+Irssi::settings_add_bool("bitlbee","bitlbee_typing_allwin",0);
+
+Irssi::signal_add("ctcp msg", "event_ctcp_msg");
+Irssi::signal_add("message private", "event_msg");
+Irssi::signal_add("message public", "event_msg");
+Irssi::signal_add("message quit", "event_quit");
+Irssi::signal_add_last('window changed', 'window_change');
+Irssi::signal_add_last('gui key pressed', 'key_pressed');
+Irssi::statusbar_item_register('typing_notice', undef, 'typing_notice');
+Irssi::statusbars_recreate_items();
diff --git a/scripts/blowjob.pl b/scripts/blowjob.pl
new file mode 100644
index 0000000..072703c
--- /dev/null
+++ b/scripts/blowjob.pl
@@ -0,0 +1,555 @@
+#!/usr/bin/perl -w
+use strict;
+
+# BlowJob 0.9.1, a crypto script - ported from xchat
+# was based on rodney mulraney's crypt
+# changed crypting method to Blowfish+Base64+randomness+Z-compression
+# needs :
+# Crypt::CBC,
+# Crypt::Blowfish,
+# MIME::Base64,
+# Compress::Zlib
+#
+# crypted format is :
+# HEX(Base64((paranoia-factor)*(blowfish(RANDOM+Zcomp(string))+RANDOM)))
+#
+# 04-22-2015 Updated for compatibility with current Crypt::CBC
+# 10-03-2004 Removed seecrypt, fixed two minor bugs
+# 09-03-2004 Supporting multiline messages now.
+# 08-03-2004 Lots of bugfixes on the irssi version by Thomas Reifferscheid
+# 08-03-2004 CONF FILE FORMAT CHANGED
+#
+# from server:channel:key:paranoia
+# to server:channel:paranoia:key
+#
+# /perm /bconf /setkey /showkey working now
+# keys may contain colons ":" now.
+#
+#
+# 06-12-2001 Added default umask for blowjob.keys
+# 05-12-2001 Added paranoia support for each key
+# 05-12-2001 Added conf file support
+# 05-12-2001 Added delkey and now can handle multi-server/channel keys
+# 05-12-2001 permanent crypting to a channel added
+# 05-12-2001 Can now handle multi-channel keys
+# just /setkey <key> on the channel you are to associate a channel with a key
+#
+# --- conf file format ---
+#
+# # the generic key ( when /setkey has not been used )
+# key: generic key value
+# # header that marks a crypted sentance
+# header: {header}
+# # enable wildcards for multiserver entries ( useful for OPN for example )
+# wildcardserver: yes
+#
+# --- end of conf file ---
+#
+# iMil <imil@gcu-squad.org>
+# skid <skid@gcu-squad.org>
+# Foxmask <odemah@gcu-squad.org>
+# Thomas Reifferscheid <blowjob@reifferscheid.org>
+
+use Crypt::CBC;
+use Crypt::Blowfish;
+use MIME::Base64;
+use Compress::Zlib;
+
+use Irssi::Irc;
+use Irssi;
+use vars qw($VERSION %IRSSI $cipher);
+
+$VERSION = "0.9.0";
+%IRSSI = (
+ authors => 'iMil,Skid,Foxmask,reiffert',
+ contact => 'imil@gcu-squad.org,blowjob@reifferscheid.org,#blowtest@freenode',
+ name => 'blowjob',
+ description => 'Crypt IRC communication with blowfish encryption. Supports public #channels, !channels, +channel, querys and dcc chat. Roadmap for Version 1.0.0 is to get some feedback and cleanup. Join #blowtest on freenode (irc.debian.org) to get latest stuff available. Note to users upgrading from versions prior to 0.8.5: The blowjob.keys format has changed.',
+ license => 'GNU GPL',
+ url => 'http://ftp.gcu-squad.org/misc/',
+);
+
+
+############# IRSSI README AREA #################################
+#To install this script just do
+#/script load ~/blowjob-irssi.pl
+# and
+#/blowhelp
+# to read all the complete feature of the script :)
+#To uninstall it do
+#/script unload blowjob-irssi
+################################################################
+
+
+my $key = 'very poor key' ; # the default key
+my $header = "{blow}";
+# Crypt loops, 1 should be enough for everyone imho ;)
+# please note with a value of 4, a single 4-letter word can generate
+# a 4 line crypted sentance
+my $paranoia = 1;
+# add a server mask by default ?
+my $enableWildcard="yes";
+
+my $alnum = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+
+my $gkey;
+sub loadconf
+{
+ my $fconf =Irssi::get_irssi_dir()."/blowjob.conf";
+ my @conf;
+ open (CONF, q{<}, $fconf);
+
+ if (!( -f CONF)) {
+ Irssi::print("\00305> $fconf not found, setting to defaults\n");
+ Irssi::print("\00305> creating $fconf with default values\n\n");
+ close(CONF);
+ open(CONF, q{>}, $fconf);
+ print CONF "key: $key\n";
+ print CONF "header: $header\n";
+ print CONF "wildcardserver: $enableWildcard\n";
+ close(CONF);
+ return 1;
+ }
+
+ @conf=<CONF>;
+ close(CONF);
+
+ my $current;
+ foreach(@conf) {
+ $current = $_;
+ $current =~ s/\n//g;
+ if ($current =~ m/key/) {
+ $current =~ s/.*\:[\ \t]*//;
+ $key = $current;
+ $gkey = $key;
+ }
+ if ($current =~ m/header/) {
+ $current =~ s/.*\:[\s\t]*\{(.*)\}.*/{$1}/;
+ $header = $current;
+ }
+ if ($current =~ m/wildcardserver/) {
+ $current =~ s/.*\:[\ \t]*//;
+ $enableWildcard = $current;
+ }
+ }
+ Irssi::print("\00314- configuration file loaded\n");
+ return 1;
+}
+loadconf;
+
+my $kfile ="$ENV{HOME}/.irssi/blowjob.keys";
+my @keys;
+$gkey=$key;
+my $gparanoia=$paranoia;
+
+sub loadkeys
+{
+ if ( -e "$kfile" ) {
+ open (KEYF, q{<}, $kfile);
+ @keys = <KEYF>;
+ close (KEYF);
+ }
+ Irssi::print("\00314- keys reloaded (Total:\00315 ".scalar @keys."\00314)\n");
+ return 1;
+}
+loadkeys;
+
+sub getkey
+{
+ my ($curserv, $curchan) = @_;
+
+ my $gotkey=0;
+ my $serv;
+ my $chan;
+ my $fkey;
+
+ foreach(@keys) {
+ chomp; # keys can contain ":" now. Note:
+ my ($serv,$chan,$fparanoia,$fkey)=split /:/,$_,4; # place of paranoia has changed!
+ if ( $curserv =~ /$serv/ and $curchan eq $chan ) {
+ $key= $fkey;
+ $paranoia=$fparanoia;
+ $gotkey=1;
+ }
+ }
+ if (!$gotkey) {
+ $key=$gkey;
+ $paranoia=$gparanoia;
+ }
+ $cipher=new Crypt::CBC(-key=> $key, -cipher=> 'Blowfish', -header => 'randomiv');
+}
+
+sub setkey
+{
+ my (undef,$server, $channel) = @_;
+ if (! $channel) { return 1; }
+ my $curchan = $channel->{name};
+ my $curserv = $server->{address};
+ # my $key = $data;
+
+ my $fparanoia;
+
+ my $newchan=1;
+ umask(0077);
+ unless ($_[0] =~ /( +\d$)/) {
+ $_[0].= " $gparanoia";
+ }
+ ($key, $fparanoia) = ($_[0] =~ /(.*) +(\d)/);
+
+ if($enableWildcard =~ /[Yy][Ee][Ss]/) {
+ $curserv =~ s/(.*?)\./(.*?)\./;
+ Irssi::print("\00314IRC server wildcards enabled\n");
+ }
+
+ # Note, place of paranoia has changed!
+ my $line="$curserv:$curchan:$fparanoia:$key";
+
+ open (KEYF, q{>}, $kfile);
+ foreach(@keys) {
+ s/\n//g;
+ if (/^$curserv\:$curchan\:/) {
+ print KEYF "$line\n";
+ $newchan=0;
+ } else {
+ print KEYF "$_\n";
+ }
+ }
+ if ($newchan) {
+ print KEYF "$line\n";
+ }
+ close (KEYF);
+ loadkeys;
+ Irssi::active_win()->print("\00314key set to \00315$key\00314 for channel \00315$curchan");
+ return 1 ;
+}
+
+sub delkey
+{
+ my ($data, $server, $channel) = @_;
+ my $curchan = $channel->{name};
+ my $curserv = $server->{address};
+
+ my $serv;
+ my $chan;
+
+ open (KEYF, q{>}, $kfile);
+ foreach(@keys) {
+ s/\n//g;
+ ($serv,$chan)=/^(.*?)\:(.*?)\:/;
+ unless ($curserv =~ /$serv/ and $curchan=~/^$chan$/) {
+ print KEYF "$_\n";
+ }
+ }
+ close (KEYF);
+ Irssi::active_win()->print("\00314key for channel \00315$curchan\00314 deleted");
+ loadkeys;
+ return 1 ;
+}
+
+sub showkey {
+ my (undef, $server, $channel) = @_;
+ if (! $channel) { return 1; }
+ my $curchan = $channel->{name};
+ my $curserv = $server->{address};
+
+ getkey($curserv,$curchan);
+
+ Irssi::active_win()->print("\00314current key is : \00315$key");
+ return 1 ;
+}
+
+sub enc
+{
+ my ($curserv,$curchan, $in) = @_;
+ my $prng1="";
+ my $prng2="";
+
+ # copy & paste from former sub blow()
+
+ for (my $i=0;$i<4;$i++) {
+ $prng1.=substr($alnum,int(rand(61)),1);
+ $prng2.=substr($alnum,int(rand(61)),1);
+ }
+
+
+ getkey($curserv,$curchan);
+
+ $cipher->start('encrypting');
+
+ my $tbout = compress($in);
+ my $i;
+ for ($i=0;$i<$paranoia;$i++) {
+ $tbout = $prng1.$tbout;
+ $tbout = $cipher->encrypt($tbout);
+ $tbout .= $prng2;
+ }
+
+ $tbout = encode_base64($tbout);
+ $tbout = unpack("H*",$tbout);
+ $tbout = $header." ".$tbout;
+ $tbout =~ s/=+$//;
+
+ $cipher->finish();
+
+ return (length($tbout),$tbout);
+
+}
+
+sub irclen
+{
+ my ($len,$curchan,$nick,$userhost) = @_;
+
+ # calculate length of "PRIVMSG #blowtest :{blow} 4b7257724a ..." does not exceed
+ # it may not exceed 511 bytes
+ # result gets handled by caller.
+
+ return ($len + length($curchan) + length("PRIVMSG : ") + length($userhost) + 1 + length($nick) );
+}
+sub recurs
+{
+ my ($server,$curchan,$in) = @_;
+
+ # 1. devide input line by 2. <--|
+ # into two halfes, called $first and $second. |
+ # 2. try to decrease $first to a delimiting " " |
+ # but only try on the last 8 bytes ^
+ # 3. encrypt $first |
+ # if result too long, call sub recurs($first)----
+ # 4. encrypt $second ^
+ # if result too long, call sub recurs($second)--|
+ # 5. pass back encrypted halfes as reference
+ # to an array.
+
+
+ my $half = length($in)/2-1;
+ my $first = substr($in,0,$half);
+ my $second = substr($in,$half,$half+3);
+ if ( (my $pos = rindex($first," ",length($first)-8) ) != -1)
+ {
+ $second = substr($first,$pos+1,length($first)-$pos) . $second;
+ $first = substr($first,0,$pos);
+ }
+
+ my @a;
+
+ my ($len,$probablyout);
+
+ ($len,$probablyout) = enc($server->{address},$curchan,$first);
+
+ if ( irclen($len,$curchan,$server->{nick},$server->{userhost}) > 510)
+ {
+ my @b=recurs($server,$curchan,$first);
+ push(@a,@{$b[0]});
+ } else {
+ push(@a,$probablyout);
+ }
+
+ ($len,$probablyout) = enc($server->{address},$curchan,$second);
+ if ( irclen($len,$curchan,$server->{nick},$server->{userhost}) > 510)
+ {
+ my @b = recurs($server,$curchan,$second);
+ push(@a,@{$b[0]});
+ } else {
+ push(@a,$probablyout);
+ }
+ return \@a;
+
+}
+
+
+sub printout
+{
+ my ($aref,$server,$curchan) = @_;
+
+ # encrypted lines get stored [ '{blow} yxcvasfd', '{blow} qewrdf', ... ];
+ # in an arrayref
+
+ foreach(@{$aref})
+ {
+ $server->command("/^msg -$server->{tag} $curchan ".$_);
+ }
+}
+
+sub enhanced_printing
+{
+ my ($server,$curchan,$in) = @_;
+
+ # calls the recursing sub recurs ... and
+ my $arref = recurs($server,$curchan,$in);
+ # print out.
+ printout($arref,$server,$curchan);
+
+}
+
+sub blow
+{
+ my ($data, $server, $channel) = @_;
+ if (! $channel) { return 1;}
+ my $in = $data ;
+ my $nick = $server->{nick};
+ my $curchan = $channel->{name};
+ my $curserv = $server->{address};
+
+ my ($len,$encrypted_message) = enc($curserv,$curchan,$in);
+
+ $server->print($channel->{name}, "<$nick|{crypted}> \00311$in",MSGLEVEL_CLIENTCRAP);
+
+ $len = length($encrypted_message); # kept for debugging
+
+ if ( irclen($len,$curchan,$server->{nick},$server->{userhost}) > 510)
+ {
+ # if complete message too long .. see sub irclen
+ enhanced_printing($server,$curchan,$data);
+ } else {
+ # everything is fine, just print out
+ $server->command("/^msg -$server->{tag} $curchan $encrypted_message");
+ }
+
+ return 1 ;
+}
+
+sub infoline
+{
+ my ($server, $data, $nick, $address) = @_;
+
+ my ($channel,$text,$msgline,$msgnick,$curchan,$curserv);
+
+ if ( ! defined($address) ) # dcc chat
+ {
+ $msgline = $data;
+ $curserv = $server->{server}->{address};
+ $channel = $curchan = "=".$nick;
+ $msgnick = $nick;
+ $server = $server->{server};
+ } else
+ {
+ ($channel, $text) = $data =~ /^(\S*)\s:(.*)/;
+ $msgline = $text;
+ $msgnick = $server->{nick};
+ $curchan = $channel;
+ $curserv = $server->{address};
+ }
+
+ if ($msgline =~ m/^$header/) {
+ my $out = $msgline;
+ $out =~ s/\0030[0-9]//g;
+ $out =~ s/^$header\s*(.*)/$1/;
+
+ if ($msgnick eq $channel)
+ {
+ $curchan = $channel = $nick;
+ }
+
+ getkey($curserv,$curchan);
+
+ $cipher->start('decrypting');
+ $out = pack("H*",$out);
+ $out = decode_base64($out);
+
+ my $i;
+ for ($i=0;$i<$paranoia;$i++) {
+ $out = substr($out,0,(length($out)-4));
+ $out = $cipher->decrypt($out);
+ $out = substr($out,4);
+ }
+ $out = uncompress($out);
+
+ $cipher->finish;
+
+ if(length($out))
+ {
+ $server->print($channel, "<$nick|{uncrypted}> \00311$out", MSGLEVEL_CLIENTCRAP);
+ Irssi::signal_stop();
+ }
+ return 1;
+
+ }
+ return 0 ;
+}
+
+sub dccinfoline
+{
+ my ($server, $data) = @_;
+ infoline($server,$data,$server->{nick},undef);
+}
+my %permchans={};
+sub perm
+{
+ my ($data, $server, $channel) = @_;
+ if (! $channel) { return 1; }
+ my $curchan = $channel->{name};
+ my $curserv = $server->{address};
+
+ if ( exists($permchans{$curserv}{$curchan}) && $permchans{$curserv}{$curchan} == 1) {
+ delete $permchans{$curserv}{$curchan};
+ Irssi::active_win()->print("\00314not crypting to \00315$curchan\00314 on \00315$curserv\00314 anymore");
+ } else {
+ $permchans{$curserv}{$curchan} = 1;
+ Irssi::active_win()->print("\00314crypting to \00315$curchan on \00315$curserv");
+ }
+ return 1;
+}
+sub myline
+{
+ my ($data, $server, $channel) = @_;
+ if (! $channel) { return 1; }
+ my $curchan = $channel->{name};
+ my $curserv = $server->{address};
+ my $line = shift;
+ chomp($line);
+ if (length($line) == 0)
+ {
+ return;
+ }
+ my $gotchan = 0;
+ foreach(@keys) {
+ s/\n//g;
+ my ($serv,$chan,undef,undef)=split /:/;
+ if ( ($curserv =~ /$serv/ && $curchan =~ /^$chan$/ && exists($permchans{$curserv}{$curchan}) && $permchans{$curserv}{$curchan} == 1) || (exists($permchans{$curserv}{$curchan}) && $permchans{$curserv}{$curchan} == 1))
+ {
+ $gotchan = 1;
+ }
+ }
+ if ($gotchan)
+ {
+
+ blow($line,$server,$channel);
+ Irssi::signal_stop();
+ return 1;
+ }
+}
+
+sub reloadconf
+{
+ loadconf;
+ loadkeys;
+}
+sub help
+{
+ Irssi::print("\00314[\00303bl\003090\00303wjob\00314]\00315 script :\n");
+ Irssi::print("\00315/setkey <newkey> [<paranoia>] :\00314 new key for current channel\n") ;
+ Irssi::print("\00315/delkey :\00314 delete key for current channel");
+ Irssi::print("\00315/showkey :\00314 show your current key\n") ;
+ Irssi::print("\00315/blow <line> :\00314 send crypted line\n") ;
+ Irssi::print("\00315/perm :\00314 flag current channel as permanently crypted\n") ;
+ Irssi::print("\00315/bconf :\00314 reload blowjob.conf\n") ;
+
+ return 1 ;
+}
+
+Irssi::print("blowjob script $VERSION") ;
+Irssi::print("\n\00314[\00303bl\003090\00303wjob\00314] v$VERSION\00315 script loaded\n\n");
+Irssi::print("\00314- type \00315/blowhelp\00314 for options\n") ;
+Irssi::print("\00314- paranoia level is : \00315$paranoia\n") ;
+Irssi::print("\00314- generic key is : \00315$key\n") ;
+Irssi::print("\n\00314* please read script itself for documentation\n");
+Irssi::signal_add("event privmsg","infoline") ;
+Irssi::signal_add("dcc chat message","dccinfoline");
+Irssi::command_bind("blowhelp","help") ;
+Irssi::command_bind("setkey","setkey") ;
+Irssi::command_bind("delkey","delkey");
+Irssi::command_bind("blow","blow") ;
+Irssi::command_bind("showkey","showkey") ;
+Irssi::command_bind("perm","perm") ;
+Irssi::command_bind("bconf","reloadconf") ;
+Irssi::signal_add("send text","myline") ;
diff --git a/scripts/bmi.pl b/scripts/bmi.pl
new file mode 100644
index 0000000..a8a729d
--- /dev/null
+++ b/scripts/bmi.pl
@@ -0,0 +1,45 @@
+use strict;
+use vars qw($VERSION %IRSSI);
+use Irssi qw(command_bind command_runsub);
+
+$VERSION = '2002121801';
+%IRSSI = (
+ authors => 'Daniel K. Gebhart, Marcus Rückert',
+ contact => 'dkg@con-fuse.org, darix@irssi.org',
+ name => 'BMI Calculator',
+ description => 'a simple body mass index calculator for depression ;)',
+ license => 'GPLv2',
+ url => 'http://dkg.con-fuse.org/irssi/scripts/',
+ changed => $VERSION,
+);
+
+sub bmi_help () {
+ print ( CLIENTCRAP "\nBMI <weigth_in_kg> <height_in_cm> [<precision>]\n" );
+ print ( CLIENTCRAP "please specify weight in kilograms (10-999kg) and height in cm (10-999cm). you can use decimal places. output precision (0-9).\n" );
+ print ( CLIENTCRAP "The optimal BMI is 19-24 for women and 20-25 for men.\n" );
+}
+
+command_bind 'bmi help' => sub { bmi_help(); };
+
+command_bind 'bmi' => sub {
+ my ($data, $server, $item) = @_;
+ $data =~ s/\s+$//g;
+ $data =~ s/,/./g;
+ if ($data eq '') {
+ bmi_help();
+ }
+ elsif ( $data =~ m/^help/i ) {
+ command_runsub ( 'bmi', $data, $server, $item );
+ }
+ else {
+ if ( $data =~ m/^(\d{2,3}(\.\d+)?)\s+(\d{2,3}(\.\d+)?)(\s+(\d))?$/ ) {
+ my ($kg, $cm) = ($1, $3);
+ my $precision = ( defined ($6) ) ? $6 : 2;
+ print ( CRAP "with $kg kg at $cm cm you have a bmi of " . sprintf("%." . $precision . "f", ( ( $kg/$cm**2 ) *10000 ) ) );
+ }
+ else {
+ print ( CRAP "please specify weight in kilograms (10-999kg) and height in cm (10-999cm). you can use decimal places. output precision (0-9)." );
+ print ( CRAP "params were: $data" );
+ }
+ }
+};
diff --git a/scripts/calc.pl b/scripts/calc.pl
new file mode 100644
index 0000000..21aa7de
--- /dev/null
+++ b/scripts/calc.pl
@@ -0,0 +1,30 @@
+use strict;
+use vars qw($VERSION %IRSSI);
+
+use Irssi qw(command_bind active_win);
+$VERSION = '1.10';
+%IRSSI = (
+ authors => 'Juerd',
+ contact => 'juerd@juerd.nl',
+ name => 'Calculator',
+ description => 'Simple /calc mechanism',
+ license => 'Public Domain',
+ url => 'http://juerd.nl/irssi/',
+ changed => 'Thu Mar 19 11:00 CET 2002',
+);
+
+command_bind(
+ calc => sub {
+ my ($msg) = @_;
+ for ($msg) {
+ s/,/./g;
+ s/[^*.+0-9&|)(x\/^-]//g;
+ s/\*\*/^/g;
+ s/([*+\\.\/x-])\1*/$1/g;
+ s/\^/**/g;
+ s/(?<!0)x//g;
+ }
+ my $answer = eval("($msg) || 0");
+ active_win->print($@ ? "$msg = ERROR (${\ (split / at/, $@, 2)[0]})" : "$msg = $answer");
+ }
+);
diff --git a/scripts/callerid.pl b/scripts/callerid.pl
new file mode 100644
index 0000000..8931f6c
--- /dev/null
+++ b/scripts/callerid.pl
@@ -0,0 +1,135 @@
+use strict;
+use Irssi;
+use vars qw($VERSION %IRSSI);
+
+$VERSION = "1.0";
+%IRSSI = (
+ authors => 'Daniel "dubkat" Reidy',
+ contact => 'dubkat@dubkat.org (www.dubkat.org)',
+ name => 'callerid',
+ description => 'Reformats CallerID (+g) Messages
+ (Also known as Server-Side Ignore)
+ on Hybrid & Ratbox IRCDs (EFnet)
+ to be Easier on the Eyes',
+ license => 'GPL',
+ url => 'http://scripts.irssi.org/',
+);
+
+#########################################################################################
+# Thanks to Geert and Senneth for helping me out with my first irssi script! #
+# Hopefully someone will find this useful. #
+# #
+# Callerid is used to block messages from users at the server. #
+# Callerid mode is activated by usermode +g on Hybrid and Ratbox servers (EFnet) #
+# The ircd maintains a list of users that may message you. #
+# To add users to the list, do /quote accept NICK #
+# The IRCD will *NOT* inform you that the user has been added. #
+# To remove a user from the list do /quote accept -NICK #
+# The IRCD will *NOT* inform you that the user has been removed. #
+# To see a list of users on your accept list do /quote accept * #
+# #
+# The following alias may make life easier: #
+# alias accept quote accept #
+#########################################################################################
+
+Irssi::signal_add('event 716', 'callerid_them');
+ sub callerid_them {
+ my ($server, $data) = @_;
+ my (undef, $nick, undef) = split(/ +/, $data, 3);
+ Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'callerid_them', $nick);
+ Irssi::signal_stop();
+ }
+
+Irssi::signal_add('event 717', 'callerid_them_notified');
+ sub callerid_them_notified {
+ my ($server, $data) = @_;
+ my (undef, $nick, undef) = split(/ +/, $data, 3);
+ $server->printformat($nick, MSGLEVEL_CLIENTCRAP, 'callerid_them_notified', $nick);
+ Irssi::signal_stop();
+ }
+
+Irssi::signal_add('event 282', 'callerid_accept_eof');
+ sub callerid_accept_eof { Irssi::signal_stop(); }
+
+Irssi::signal_add('event 718', 'callerid_you');
+ sub callerid_you {
+ my ($server, $data) = @_;
+ my (undef, $nick, $host, undef) = split(/ +/, $data, 4);
+ $server->printformat($nick, MSGLEVEL_CLIENTCRAP, 'callerid_you', $nick, $host);
+ Irssi::signal_stop();
+ }
+
+Irssi::signal_add('event 281', 'callerid_accept_list');
+ sub callerid_accept_list {
+ my ($server, $data) = @_;
+ my (undef, $list, undef) = split(/ +/, $data, 3);
+ $data =~ s/^\S+\s//;
+ $data =~ s/\s+:$//;
+ $server->printformat($data, MSGLEVEL_CLIENTCRAP, 'callerid_accept_list', $data);
+ Irssi::signal_stop();
+ }
+
+
+Irssi::signal_add('event 457', 'callerid_accept_exsists');
+ sub callerid_accept_exsists {
+ my ($server, $data) = @_;
+ my (undef, $nick, undef) = split(/ +/, $data, 3);
+ Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'callerid_accept_exsists', $nick);
+ Irssi::signal_stop();
+ }
+
+
+Irssi::signal_add('event 458', 'callerid_not_on_list');
+ sub callerid_not_on_list {
+ my ($server, $data) = @_;
+ my (undef, $info, undef) = split(/ +/, $data, 3);
+ Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'callerid_not_on_list', $info);
+ Irssi::signal_stop();
+ }
+
+Irssi::signal_add('event 456', 'callerid_full');
+ sub callerid_full {
+ my ($server, $data) = @_;
+ my (undef, $info) = split(/ +/, $data, 2);
+ Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'callerid_full', $info);
+ Irssi::signal_stop();
+ }
+
+Irssi::signal_add('event 401', 'callerid_invalid_nick');
+ sub callerid_invalid_nick{
+ my ($server, $data) = @_;
+ my (undef, $info, undef) = split(/ +/, $data, 3);
+ Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'callerid_invalid_nick', $info);
+ Irssi::signal_stop();
+ }
+
+
+Irssi::theme_register
+ (
+ [
+ 'callerid_them',
+ '%_[%_%RCALLERID%n%_]%_ %W$0%n is in server-side ignore.',
+
+ 'callerid_you',
+ '%_[%_%yCALLERID%n%_]%_ %W$0%n ($1) is attempting to message you.',
+
+ 'callerid_accept_list',
+ '%_[%_%gACCEPTED%n%_]%_ %W$0%n',
+
+ 'callerid_accept_exsists',
+ '%_[%_%BCALLERID%n%_]%_ %W$0%n Is Already On Your Accept List. Do %_/quote accept *%_ for a list :)',
+
+ 'callerid_full',
+ '%_[%_%pCALLERID%n%_]%_ List is full. Do %_/quote accept *%_ for a list',
+
+ 'callerid_not_on_list',
+ '%_[%_%pCALLERID%n%_]%_ $0 is not a user on your accept list.',
+
+ 'callerid_invalid_nick',
+ '%_[%_%pCALLERID%n%_]%_ Cannot add/remove $0. That nick does not exist.',
+
+ 'callerid_them_notified',
+ '%_[%_%rCALLERID%n%_]%_ %_$0%_ has been notified that you attempted to message them. (They will not notified of further messages for 60sec).',
+
+ ]
+ );
diff --git a/scripts/cap_sasl.pl b/scripts/cap_sasl.pl
new file mode 100644
index 0000000..7a0b742
--- /dev/null
+++ b/scripts/cap_sasl.pl
@@ -0,0 +1,437 @@
+use strict;
+use Irssi;
+use MIME::Base64;
+use vars qw($VERSION %IRSSI);
+use constant CHALLENGE_SIZE => 32;
+
+$VERSION = "1.11";
+%IRSSI = (
+ authors => 'Michael Tharp (gxti), Jilles Tjoelker (jilles), Mantas MikulÄ—nas (grawity)',
+ contact => 'grawity@gmail.com',
+ name => 'cap_sasl.pl',
+ description => 'Implements SASL authentication and enables CAP "multi-prefix"',
+ license => 'GPLv2',
+ url => 'http://ircv3.atheme.org/extensions/sasl-3.1',
+);
+
+my %sasl_auth = ();
+my %mech = ();
+
+sub irssi_abspath {
+ my $f = shift;
+ $f =~ s!^~/!$ENV{HOME}/!;
+ if ($f !~ m!^/!) {
+ $f = Irssi::get_irssi_dir()."/".$f;
+ }
+ return $f;
+}
+
+sub timeout;
+
+sub server_connected {
+ my $server = shift;
+ if (uc $server->{chat_type} eq 'IRC') {
+ $server->send_raw_now("CAP LS");
+ }
+}
+
+sub event_cap {
+ my ($server, $args, $nick, $address) = @_;
+ my ($subcmd, $caps, $tosend, $sasl);
+
+ $tosend = '';
+ $sasl = $sasl_auth{$server->{tag}};
+ if ($args =~ /^\S+ (\S+) :(.*)$/) {
+ $subcmd = uc $1;
+ $caps = ' '.$2.' ';
+ if ($subcmd eq 'LS') {
+ $tosend .= ' multi-prefix' if $caps =~ / multi-prefix /i;
+ $tosend .= ' sasl' if $caps =~ / sasl /i && defined($sasl);
+ $tosend =~ s/^ //;
+ $server->print('', "CLICAP: supported by server:$caps");
+ if (!$server->{connected}) {
+ if ($tosend eq '') {
+ $server->send_raw_now("CAP END");
+ } else {
+ $server->print('', "CLICAP: requesting: $tosend");
+ $server->send_raw_now("CAP REQ :$tosend");
+ }
+ }
+ Irssi::signal_stop();
+ } elsif ($subcmd eq 'ACK') {
+ $server->print('', "CLICAP: now enabled:$caps");
+ if ($caps =~ / sasl /i) {
+ $sasl->{buffer} = '';
+ $sasl->{step} = 0;
+ if ($mech{$sasl->{mech}}) {
+ $server->send_raw_now("AUTHENTICATE " . $sasl->{mech});
+ Irssi::timeout_add_once(7500, \&timeout, $server->{tag});
+ } else {
+ $server->print('', 'SASL: attempted to start unknown mechanism "' . $sasl->{mech} . '"');
+ }
+ }
+ elsif (!$server->{connected}) {
+ $server->send_raw_now("CAP END");
+ }
+ Irssi::signal_stop();
+ } elsif ($subcmd eq 'NAK') {
+ $server->print('', "CLICAP: refused:$caps");
+ if (!$server->{connected}) {
+ $server->send_raw_now("CAP END");
+ }
+ Irssi::signal_stop();
+ } elsif ($subcmd eq 'LIST') {
+ $server->print('', "CLICAP: currently enabled:$caps");
+ Irssi::signal_stop();
+ }
+ }
+}
+
+sub event_authenticate {
+ my ($server, $args, $nick, $address) = @_;
+ my $sasl = $sasl_auth{$server->{tag}};
+ return unless $sasl && $mech{$sasl->{mech}};
+
+ $sasl->{buffer} .= $args;
+ return if length($args) == 400;
+
+ my $data = ($sasl->{buffer} eq '+') ? '' : decode_base64($sasl->{buffer});
+ my $out = $mech{$sasl->{mech}}($sasl, $data);
+
+ if (defined $out) {
+ $out = ($out eq '') ? '+' : encode_base64($out, '');
+ while (length $out >= 400) {
+ my $subout = substr($out, 0, 400, '');
+ $server->send_raw_now("AUTHENTICATE $subout");
+ }
+ if (length $out) {
+ $server->send_raw_now("AUTHENTICATE $out");
+ } else {
+ # Last piece was exactly 400 bytes, we have to send
+ # some padding to indicate we're done.
+ $server->send_raw_now("AUTHENTICATE +");
+ }
+ } else {
+ $server->send_raw_now("AUTHENTICATE *");
+ }
+
+ $sasl->{buffer} = "";
+ Irssi::signal_stop();
+}
+
+sub event_saslend {
+ my ($server, $args, $nick, $address) = @_;
+
+ my $data = $args;
+ $data =~ s/^\S+ :?//;
+ # need this to see it, ?? -- jilles
+
+ $server->print('', $data);
+ if (!$server->{connected}) {
+ $server->send_raw_now("CAP END");
+ }
+}
+
+sub event_saslfail {
+ my ($server, $args, $nick, $address) = @_;
+
+ my $data = $args;
+ $data =~ s/^\S+ :?//;
+
+ if (Irssi::settings_get_bool('sasl_disconnect_on_fail')) {
+ $server->print('', "$data - disconnecting from server", MSGLEVEL_CLIENTERROR);
+ $server->disconnect();
+ } else {
+ $server->print('', "$data - continuing anyway");
+ if (!$server->{connected}) {
+ $server->send_raw_now("CAP END");
+ }
+ }
+}
+
+sub timeout {
+ my $tag = shift;
+ my $server = Irssi::server_find_tag($tag);
+ if ($server && !$server->{connected}) {
+ $server->print('', "SASL: authentication timed out", MSGLEVEL_CLIENTERROR);
+ $server->send_raw_now("CAP END");
+ }
+}
+
+sub cmd_sasl {
+ my ($data, $server, $item) = @_;
+
+ if ($data ne '') {
+ Irssi::command_runsub ('sasl', $data, $server, $item);
+ } else {
+ cmd_sasl_show(@_);
+ }
+}
+
+sub cmd_sasl_set {
+ my ($data, $server, $item) = @_;
+
+ if (my ($net, $u, $p, $m) = $data =~ /^(\S+) (\S+) (\S+) (\S+)$/) {
+ if ($mech{uc $m}) {
+ $sasl_auth{$net}{user} = $u;
+ $sasl_auth{$net}{password} = $p;
+ $sasl_auth{$net}{mech} = uc $m;
+ Irssi::print("SASL: added $net: [$m] $sasl_auth{$net}{user} *");
+ } else {
+ Irssi::print("SASL: unknown mechanism $m", MSGLEVEL_CLIENTERROR);
+ }
+ } elsif ($data =~ /^(\S+)$/) {
+ $net = $1;
+ if (defined($sasl_auth{$net})) {
+ delete $sasl_auth{$net};
+ Irssi::print("SASL: deleted $net");
+ } else {
+ Irssi::print("SASL: no entry for $net");
+ }
+ } else {
+ Irssi::print("SASL: usage: /sasl set <net> <user> <password or keyfile> <mechanism>");
+ }
+}
+
+sub cmd_sasl_show {
+ #my ($data, $server, $item) = @_;
+ my @nets = keys %sasl_auth;
+ for my $net (@nets) {
+ Irssi::print("SASL: $net: [$sasl_auth{$net}{mech}] $sasl_auth{$net}{user} *");
+ }
+ Irssi::print("SASL: no networks defined") if !@nets;
+}
+
+sub cmd_sasl_save {
+ #my ($data, $server, $item) = @_;
+ my $file = Irssi::get_irssi_dir()."/sasl.auth";
+ if (open(my $fh, ">", $file)) {
+ chmod(0600, $file);
+ for my $net (keys %sasl_auth) {
+ printf $fh ("%s\t%s\t%s\t%s\n",
+ $net,
+ $sasl_auth{$net}{user},
+ $sasl_auth{$net}{password},
+ $sasl_auth{$net}{mech});
+ }
+ close($fh);
+ Irssi::print("SASL: auth saved to '$file'");
+ } else {
+ Irssi::print("SASL: couldn't access '$file': $@");
+ }
+}
+
+sub cmd_sasl_load {
+ #my ($data, $server, $item) = @_;
+ my $file = Irssi::get_irssi_dir()."/sasl.auth";
+ if (open(my $fh, "<", $file)) {
+ %sasl_auth = ();
+ while (<$fh>) {
+ chomp;
+ my ($net, $u, $p, $m) = split(/\t/, $_, 4);
+ $m ||= "PLAIN";
+ if ($mech{uc $m}) {
+ $sasl_auth{$net}{user} = $u;
+ $sasl_auth{$net}{password} = $p;
+ $sasl_auth{$net}{mech} = uc $m;
+ } else {
+ Irssi::print("SASL: unknown mechanism $m", MSGLEVEL_CLIENTERROR);
+ }
+ }
+ close($fh);
+ Irssi::print("SASL: cap_sasl $VERSION, auth loaded from '$file'");
+ }
+}
+
+sub cmd_sasl_mechanisms {
+ Irssi::print("SASL: mechanisms supported: " . join(", ", sort keys %mech));
+}
+
+Irssi::settings_add_bool('server', 'sasl_disconnect_on_fail', 1);
+
+Irssi::signal_add_first('server connected', \&server_connected);
+Irssi::signal_add('event cap', \&event_cap);
+Irssi::signal_add('event authenticate', \&event_authenticate);
+Irssi::signal_add('event 903', \&event_saslend);
+Irssi::signal_add('event 904', \&event_saslfail);
+Irssi::signal_add('event 905', \&event_saslend);
+Irssi::signal_add('event 906', \&event_saslfail);
+Irssi::signal_add('event 907', \&event_saslend);
+
+Irssi::command_bind('sasl', \&cmd_sasl);
+Irssi::command_bind('sasl load', \&cmd_sasl_load);
+Irssi::command_bind('sasl save', \&cmd_sasl_save);
+Irssi::command_bind('sasl set', \&cmd_sasl_set);
+Irssi::command_bind('sasl show', \&cmd_sasl_show);
+Irssi::command_bind('sasl mechanisms', \&cmd_sasl_mechanisms);
+
+$mech{PLAIN} = sub {
+ my ($sasl, $data) = @_;
+ my $u = $sasl->{user};
+ my $p = $sasl->{password};
+ return join("\0", $u, $u, $p);
+};
+
+$mech{EXTERNAL} = sub {
+ my ($sasl, $data) = @_;
+ return $sasl->{user} // "";
+};
+
+if (eval {require Crypt::PK::ECC}) {
+ my $mech = "ECDSA-NIST256P-CHALLENGE";
+
+ $mech{'ECDSA-NIST256P-CHALLENGE'} = sub {
+ my ($sasl, $data) = @_;
+ my $u = $sasl->{user};
+ my $f = $sasl->{password};
+ $f = irssi_abspath($f);
+ if (!-f $f) {
+ Irssi::print("SASL: key file '$f' not found", MSGLEVEL_CLIENTERROR);
+ return;
+ }
+ my $pk = eval {Crypt::PK::ECC->new($f)};
+ if ($@ || !$pk || !$pk->is_private) {
+ Irssi::print("SASL: no private key in file '$f'", MSGLEVEL_CLIENTERROR);
+ return;
+ }
+ my $step = ++$sasl->{step};
+ if ($step == 1) {
+ if (length $data == CHALLENGE_SIZE) {
+ my $sig = $pk->sign_hash($data);
+ return $u."\0".$u."\0".$sig;
+ } elsif (length $data) {
+ return;
+ } else {
+ return $u."\0".$u;
+ }
+ }
+ elsif ($step == 2) {
+ if (length $data == CHALLENGE_SIZE) {
+ return $pk->sign_hash($data);
+ } else {
+ return;
+ }
+ }
+ };
+
+ Irssi::command_bind("sasl keygen" => sub {
+ my ($data, $server, $witem) = @_;
+
+ my $print = $server
+ ? sub { $server->print("", shift, shift // MSGLEVEL_CLIENTNOTICE) }
+ : sub { Irssi::print(shift, shift // MSGLEVEL_CLIENTNOTICE) };
+
+ my $net = $server ? $server->{tag} : $data;
+ if (!length $net) {
+ Irssi::print("SASL: please connect to a server first",
+ MSGLEVEL_CLIENTERROR);
+ return;
+ }
+
+ my $f_name = lc "sasl-ecdsa-$net";
+ $f_name =~ s![ /]+!_!g;
+ my $f_priv = Irssi::get_irssi_dir()."/$f_name.key";
+ my $f_pub = Irssi::get_irssi_dir()."/$f_name.pub";
+ if (-e $f_priv) {
+ $print->("SASL: refusing to overwrite '$f_priv'", MSGLEVEL_CLIENTERROR);
+ return;
+ }
+
+ $print->("SASL: generating keypair for '$net'...");
+ my $pk = Crypt::PK::ECC->new;
+ $pk->generate_key("prime256v1");
+
+ my $priv = $pk->export_key_pem("private");
+ my $pub = encode_base64($pk->export_key_raw("public_compressed"), "");
+
+ if (open(my $fh, ">", $f_priv)) {
+ chmod(0600, $f_priv);
+ print $fh $priv;
+ close($fh);
+ $print->("SASL: wrote private key to '$f_priv'");
+ } else {
+ $print->("SASL: could not write '$f_priv': $!", MSGLEVEL_CLIENTERROR);
+ return;
+ }
+
+ if (open(my $fh, ">", $f_pub)) {
+ print $fh $pub."\n";
+ close($fh);
+ } else {
+ $print->("SASL: could not write '$f_pub': $!", MSGLEVEL_CLIENTERROR);
+ }
+
+ my $cmdchar = substr(Irssi::settings_get_str("cmdchars"), 0, 1);
+ my $cmd = "msg NickServ SET PUBKEY $pub";
+
+ if ($server) {
+ $print->("SASL: updating your Irssi settings...");
+ $sasl_auth{$net}{user} //= $server->{nick};
+ $sasl_auth{$net}{password} = "$f_name.key";
+ $sasl_auth{$net}{mech} = $mech;
+ cmd_sasl_save(@_);
+ $print->("SASL: submitting pubkey to NickServ...");
+ $server->command($cmd);
+ } else {
+ $print->("SASL: update your Irssi settings:");
+ $print->("%P".$cmdchar."sasl set $net <nick> $f_name.key $mech");
+ $print->("SASL: submit your pubkey to $net:");
+ $print->("%P".$cmdchar.$cmd);
+ }
+ });
+
+ Irssi::command_bind("sasl pubkey" => sub {
+ my ($data, $server, $witem) = @_;
+
+ my $arg = $server ? $server->{tag} : $data;
+
+ my $f;
+ if (!length $arg) {
+ Irssi::print("SASL: please select a server or specify a keyfile path",
+ MSGLEVEL_CLIENTERROR);
+ return;
+ } elsif ($arg =~ m![/.]!) {
+ $f = $arg;
+ } else {
+ if ($sasl_auth{$arg}{mech} eq $mech) {
+ $f = $sasl_auth{$arg}{password};
+ } else {
+ $f = lc "sasl-ecdsa-$arg";
+ $f =~ s![ /]+!_!g;
+ $f = "$f.key";
+ }
+ }
+
+ $f = irssi_abspath($f);
+ if (!-e $f) {
+ Irssi::print("SASL: keyfile '$f' not found", MSGLEVEL_CLIENTERROR);
+ return;
+ }
+
+ my $pk = eval {Crypt::PK::ECC->new($f)};
+ if ($@ || !$pk || !$pk->is_private) {
+ Irssi::print("SASL: no private key in file '$f'", MSGLEVEL_CLIENTERROR);
+ Irssi::print("(keys using named parameters or PKCS#8 are not yet supported)",
+ MSGLEVEL_CLIENTERROR);
+ return;
+ }
+
+ my $pub = encode_base64($pk->export_key_raw("public_compressed"), "");
+ Irssi::print("SASL: loaded keyfile '$f'");
+ Irssi::print("SASL: your pubkey is $pub");
+ });
+} else {
+ Irssi::command_bind("sasl keygen" => sub {
+ Irssi::print("SASL: cannot '/sasl keygen' as the Perl 'CryptX' module is missing",
+ MSGLEVEL_CLIENTERROR);
+ });
+
+ Irssi::command_bind("sasl pubkey" => sub {
+ Irssi::print("SASL: cannot '/sasl pubkey' as the Perl 'CryptX' module is missing",
+ MSGLEVEL_CLIENTERROR);
+ });
+}
+
+cmd_sasl_load();
+
+# vim: ts=4:sw=4
diff --git a/scripts/centericq.pl b/scripts/centericq.pl
new file mode 100644
index 0000000..9b80170
--- /dev/null
+++ b/scripts/centericq.pl
@@ -0,0 +1,342 @@
+# $Id: centericq.pl,v 1.0.0 2002/10/19 13:15:49 Garion Exp $
+use strict;
+use vars qw($VERSION %IRSSI);
+$VERSION = "1.0.0";
+%IRSSI = (
+ authors => "Joost \"Garion\" Vunderink",
+ contact => "joost\@carnique.nl",
+ name => "centericq",
+ description => "Staturbar item which indicates how many new messages you have in your centericq",
+ sbitems => "centericq",
+ license => "Public Domain",
+ url => "http://irssi.org, http://scripts.irssi.org",
+);
+
+# centericq new messages statusbar item
+# for irssi 0.8.4 by Timo Sirainen
+#
+# This statusbar item checks whether you have unread messages in
+# ~/.centericq/, and if so, displays a status in your statusbar.
+# Example status: [ICQ: JamesOff-1,Linn-3,Paul-4]
+#
+# Use:
+# /script load centericq
+# /statusbar <name> add centericq
+#
+# Known bugs:
+# - It only works for ICQ and MSN in centericq.
+# - The refreshing is not optimal. You'll need to swap windows to make
+# the statusbar item disappear if you've read the messages.
+# - You have to reload the script if you add new people in centericq.
+# - Works only with centericq in ~/.centericq/
+#
+# TODO:
+# - Use only the first N letters of the nickname instead of the full
+# nickname.
+
+use Irssi;
+use Irssi::TextUI;
+
+my $icqdir = $ENV{'HOME'} . "/.centericq";
+my ($last_refresh_time, $refresh_tag);
+my $statusbar_item;
+
+# The following vars are all hashes with key the name of the dir in
+# ~/.centericq/ of that person
+
+my %lastreads; # Timestamp of the last read message, per nick
+my %numunreads; # Number of unread messages, per nick
+my %historyts; # Timestamp of the history file of each nick
+my %lastreadts; # Timestamp of the lastread file of each nick
+my %friendnicks; # The nicknames of the friends
+
+
+#######################################################################
+# This is the function that will be called each N seconds, where
+# N is given by the centericq_refresh_time setting.
+
+sub refresh_centericq {
+ check_new_friends();
+
+ my @friends = keys(%lastreads);
+ my ($friend, $changed) = ("", 0);
+ foreach $friend (@friends) {
+ if (history_changed($friend) || lastread_changed($friend)) {
+ $changed = 1;
+ update_status($friend);
+ }
+ }
+
+ if ($changed) {
+ update_statusbar_item();
+ }
+
+ # Adding new timeout to make sure that this function will be called
+ # again
+ if ($refresh_tag) {
+ Irssi::timeout_remove($refresh_tag)
+ }
+ my $time = Irssi::settings_get_int('centericq_refresh_time');
+ $refresh_tag = Irssi::timeout_add($time*1000, 'refresh_centericq', undef);
+}
+
+
+#######################################################################
+# Checks if any new friends have been added. Not yet functional.
+
+sub check_new_friends {
+ #Irssi::print("Checking if there are any new friends...");
+}
+
+#######################################################################
+# Checks if the last modified date/time of the lastread file has changed.
+# A -lot- more efficient than reading and processing the whole file :)
+
+sub lastread_changed {
+ my ($friend) = @_;
+
+ my $lr = get_lastread($friend);
+ if ($lr != $lastreads{$friend}) {
+ #Irssi::print("Lastread of $friendnick{$friend} changed from $lastreads{$friend} to $lr.");
+ $lastreads{$friend} = $lr;
+ return 1;
+ }
+
+ return 0;
+}
+
+#######################################################################
+# Checks if the last modified date/time of the history file has changed.
+# A -lot- more efficient than reading and processing the whole file :)
+
+sub history_changed {
+ my ($friend) = @_;
+ my $ts = get_historyts($friend);
+ if ($ts != $historyts{$friend}) {
+ #Irssi::print("History ts of $friendnick{$friend} changed from $historyts{$friend} to $ts.");
+ $historyts{$friend} = $ts;
+ return 1;
+ }
+
+ return 0;
+}
+
+#######################################################################
+# Reads the last read message and determines the number of unread
+# messages of $friend.
+
+sub update_status {
+ my ($friend) = @_;
+ $lastreads{$friend} = get_lastread($friend);
+ $numunreads{$friend} = get_numunreads($friend);
+}
+
+#######################################################################
+# Gets the number of unread messages of all nicks and puts them together
+# in a nice statusbar string.
+# It then requests a statusbar item redraw.
+
+sub update_statusbar_item {
+ #Irssi::print("Updating statusbaritem...");
+ $statusbar_item = "";
+
+ my @keys = keys(%lastreads);
+ my ($key, $status);
+
+ foreach $key(@keys) {
+ if ($numunreads{$key} > 0) {
+ #Irssi::print("$friendnick{$key} has $numunreads{$key} unreads.");
+ $status .= $friendnicks{$key} . "-" . $numunreads{$key} . ",";
+ }
+ }
+ $status =~ s/,$//;
+ if (length($status) > 0) {
+ $statusbar_item = "ICQ: " . $status;
+ Irssi::statusbar_items_redraw('centericq');
+ }
+}
+
+
+#######################################################################
+# This is the function called by irssi to obtain the statusbar item
+# for centericq.
+
+sub centericq {
+ my ($item, $get_size_only) = @_;
+
+ if (length($statusbar_item) == 0) {
+ # no icq - don't print the [ICQ] at all
+ if ($get_size_only) {
+ $item->{min_size} = $item->{max_size} = 0;
+ }
+ } else {
+ $item->default_handler($get_size_only, undef, $statusbar_item, 1);
+ }
+}
+
+#######################################################################
+# Initialization of the hashes with the useful data.
+
+sub init {
+ if (!opendir(ICQDIR, $icqdir)) {
+ Irssi::print("There is no directory $icqdir, which is needed for this script.");
+ return 0;
+ }
+
+ my ($icqfriends, $msnfriends) = (0, 0);
+ while (my $filename = readdir(ICQDIR)) {
+ # ICQ friends
+ if ($filename =~ /^[0-9]+$/ && $filename !~ /^0$/) {
+ $icqfriends++;
+ init_friend($filename);
+ }
+ # MSN friends
+ if ($filename =~ /^m.+/ && $filename !~ /^modelist$/ ) {
+ $msnfriends++;
+ init_friend($filename);
+ }
+ }
+ Irssi::print("Watching $icqfriends ICQ friends and $msnfriends MSN friends.");
+
+ closedir(ICQDIR);
+ return 1;
+}
+
+#######################################################################
+# Initialises all data of $friend
+
+sub init_friend {
+ my ($friend) = @_;
+
+ $lastreads{$friend} = get_lastread($friend);
+ $numunreads{$friend} = get_numunreads($friend);
+ #$filesizes{$friend} = get_filesize($friend);
+ $friendnicks{$friend} = get_nickname($friend);
+ $historyts{$friend} = get_historyts($friend);
+ #Irssi::print("Initilialized $friendnick{$friend}.");
+}
+
+#######################################################################
+# Returns the last read message of $friend
+
+sub get_lastread {
+ my ($friend) = @_;
+ my $lastreadfile = $icqdir . "/" . $friend . "/lastread";
+
+ open(F, "<", $lastreadfile) || return 0; #die("Could not open $lastreadfile.");;
+ my $lastrd = <F>;
+ close(F);
+ chop($lastrd);
+ #Irssi::print("Found lastread $lastrd of $friend from $lastreadfile.");
+
+ return $lastrd;
+}
+
+#######################################################################
+# Returns the number of unread messages for $friend
+
+sub get_numunreads {
+ my ($friend) = @_;
+ my $lr = $lastreads{$friend};
+ # Unknown last read message - return 0.
+ if ($lr == 0) {
+ return 0;
+ }
+
+ my $msgfile = $icqdir . "/" . $friend . "/history";
+ open(F, "<", $msgfile) || return 0; #die("Could not open $msgfile.");
+ my @lines = <F>;
+ chop(@lines);
+ close(F);
+
+ my $numlines = @lines;
+
+ # read all lines up to the lastread message
+ my $line;
+ my $bla = 0;
+ do {
+ $line = shift(@lines);
+ $bla++;
+ } while ($line ne $lr);
+
+ # now count the number of times that "MSG" is found on a line below
+ # a line with "IN"
+ my $count = 0;
+ my $incoming = 0;
+ my $verify = 0;
+ my $bli = 0;
+
+ for (@lines) {
+ $bli++;
+ # Sometimes 2 messages get in at the same time. Remove this so-called
+ # new message if it has the same time as the last read message.
+ if ($verify == 1) {
+ if ($_ =~ /$lr/) {
+ $count--;
+ }
+ $verify = 0;
+ }
+ # A line with "IN" has been found; check if the next line is "MSG".
+ if ($incoming == 1) {
+ if ($_ =~ /^MSG/) {
+ $count++;
+ $verify = 1;
+ }
+ $incoming = 0;
+ }
+ # Check for "IN".
+ if ($_ =~ /^IN/) {
+ $incoming = 1;
+ }
+ }
+
+ return $count;
+}
+
+#######################################################################
+# Returns the nickname of a friend. This is taken from the 46th line
+# of the info file. Let's hope that centericq does not change its
+# config file format.
+
+sub get_nickname {
+ my ($friend) = @_;
+
+ my $infofile = $icqdir . "/" . $friend . "/info";
+ open(F, "<", $infofile) || return $friend; #die("Could not open $msgfile.");
+ my @lines = <F>;
+ chop(@lines);
+ close(F);
+
+ return $lines[45];
+}
+
+#######################################################################
+# Returns the timestamp of the history file of $friend.
+
+sub get_historyts {
+ my ($friend) = @_;
+ my $histfile = $icqdir . "/" . $friend . "/history";
+ my @stat = stat($histfile);
+ return $stat[9];
+}
+
+#######################################################################
+# Adding stuff to irssi
+
+Irssi::settings_add_int('misc', 'centericq_refresh_time', 120);
+#Irssi::settings_add_bool('misc', 'centericq_debug', 0);
+Irssi::statusbar_item_register('centericq', '{sb $0-}', 'centericq');
+
+#######################################################################
+# Startup functions
+
+if (init() == 0) {
+ Irssi::print("You need centericq for this script.");
+ return 0;
+}
+update_statusbar_item();
+refresh_centericq();
+
+Irssi::print("Centericq statusbar item loaded.");
+
+#######################################################################
diff --git a/scripts/cgrep.pl b/scripts/cgrep.pl
new file mode 100644
index 0000000..e7afc7c
--- /dev/null
+++ b/scripts/cgrep.pl
@@ -0,0 +1,192 @@
+################################################################################
+#
+# Usage: /cgrep <regexp>
+#
+# Shows all WHO records matching that regexp in a friendly yet complete format
+# Works on the active channel only
+#
+# This is a bit like c0ffee's ls command, except it matches ALL returned data.
+# Since IRSSI doe snot cache realnames properly, this script calls WHO once
+# and awaits the results.
+#
+# Also check out 'joininfo.pl' which shows lots of WHOIS info when a person
+# joins the channel.
+#
+# FORMAT SETTINGS:
+# cgrep_match Matching record
+# cgrep_line Start and end line format
+#
+################################################################################
+
+use strict;
+use Irssi;
+use vars qw($VERSION %IRSSI);
+use integer;
+
+$VERSION = "1.0.0";
+%IRSSI = (
+ authors => "Pieter-Bas IJdens",
+ contact => "irssi-scripts\@nospam.mi4.org.uk",
+ name => "cgrep",
+ description => "Lists users on the channel matching the specified regexp",
+ license => "GPLv2 or later",
+ url => "http://pieter-bas.ijdens.com/irssi/",
+ changed => "2005-03-10"
+);
+
+################################################################################
+
+my($busy) = 0;
+my($regexp) = "";
+my($results) = 0;
+my($debug) = 0;
+
+################################################################################
+
+sub run_who
+{
+ my($server, $channel) = @_;
+
+ $server->redirect_event(
+ "who",
+ 1,
+ $channel,
+ 0,
+ "redir who_default",
+ {
+ "event 352" => "redir cgrep_evt_who_result",
+ "event 315" => "redir cgrep_evt_who_end",
+ "" => "event empty"
+ }
+ );
+
+ $server->send_raw("WHO $channel");
+}
+
+################################################################################
+
+sub event_who_result
+{
+ my ($server, $data) = @_;
+
+ if ($busy)
+ {
+ my($start,$realname);
+ if ($data =~ /^(.*):([^:]{1,})$/)
+ {
+ $start = $1;
+ $realname = $2;
+ }
+ else
+ {
+ Irssi::print("$data can't be parsed");
+ }
+
+ # my($start,$realname) = split(":", $data);
+
+ my($me, $channel, $ident, $host, $server, $nick, $mode) =
+ split(" ", $start);
+ my($hops) = -1;
+
+ if ($realname =~ /^([0-9]{1,} )(.*$)$/i)
+ {
+ $hops = $1;
+ $realname = $2;
+
+ $hops =~ s/[ ]{1,}$//g;
+ }
+
+ my($string) = "$nick ($ident\@$host) \"$realname\" $channel "
+ . "($server, $hops)";
+
+ if ($string =~ /$regexp/i)
+ {
+ Irssi::printformat(
+ MSGLEVEL_CLIENTCRAP,
+ 'cgrep_match',
+ $nick,
+ "$ident\@$host",
+ "$realname",
+ $channel,
+ $server,
+ $hops
+ );
+
+ $results++;
+ }
+ }
+}
+
+################################################################################
+
+sub event_who_end
+{
+ my ($server, $data) = @_;
+
+ Irssi::printformat(
+ MSGLEVEL_CLIENTCRAP,
+ 'cgrep_line',
+ "End of list. Found $results matches."
+ );
+
+ $busy = 0;
+ $regexp = "";
+ $results = 0;
+}
+
+################################################################################
+
+sub cmd_cgrep
+{
+ my ($data, $server, $window) = @_;
+
+ if (!$server)
+ {
+ Irssi::print("Not connected to a server in this window.");
+ return;
+ }
+ elsif ($window->{type} ne "CHANNEL")
+ {
+ Irssi::print("Not a channel window.");
+ return;
+ }
+ elsif ($busy)
+ {
+ Irssi::print("A request seems to be in progress.");
+ Irssi::print("Reload script if I'm wrong.");
+ }
+
+ $busy = 1;
+ $regexp = $data;
+ $results = 0;
+
+ Irssi::printformat(
+ MSGLEVEL_CLIENTCRAP,
+ 'cgrep_line',
+ "WHO on " . $window->{name} . " filtered on '$regexp'"
+ );
+
+ run_who($server, $window->{name});
+}
+
+################################################################################
+
+Irssi::theme_register([
+ 'cgrep_match',
+ '%GWHO:%n {channick_hilight $0} [{hilight $1}] is "{hilight $2}"%n on {channel $3} [server: {hilight $4}, hops: {hilight $5}]',
+ 'cgrep_line',
+ '%R------------%n {hilight $0} %R------------%n'
+]);
+
+Irssi::signal_add(
+ {
+ 'redir cgrep_evt_who_result' => \&event_who_result,
+ 'redir cgrep_evt_who_end' => \&event_who_end
+ }
+);
+
+################################################################################
+
+Irssi::command_bind("cgrep", \&cmd_cgrep);
+
+################################################################################
diff --git a/scripts/challenge.pl b/scripts/challenge.pl
new file mode 100644
index 0000000..69cba77
--- /dev/null
+++ b/scripts/challenge.pl
@@ -0,0 +1,106 @@
+# Run a challenge response oper thingie
+#
+# (C) 2006 by Joerg Jaspert <joerg@debian.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this script; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+# This script needs "rsa_respond" out of the hybrid ircd to actually work.
+# (https://github.com/oftc/oftc-hybrid/tree/develop/tools)
+# And you need to have an rsa keypair in your oper block. Create one with
+# openssl genrsa -des3 1024 > oper-whatever.key
+# openssl rsa -pubout < oper-whatever.key > oper-whatever.pub
+# and send the .pub to your noc :)