aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitmodules3
-rw-r--r--README.md4
-rw-r--r--Trolltech.conf189
-rw-r--r--X11/XCompose69
-rw-r--r--X11/Xresources67
-rw-r--r--X11/Xresources-theme39
-rw-r--r--X11/xinitrc14
-rw-r--r--cower/config39
-rw-r--r--dunst/dunstrc102
-rw-r--r--git/config27
-rw-r--r--gtk-2.0/gtkrc-2.017
-rw-r--r--gtk-3.0/settings.ini15
-rw-r--r--i3/bar.py55
-rw-r--r--i3/config166
-rw-r--r--mpv/config4
-rw-r--r--mutt/gpg.rc85
-rw-r--r--mutt/mailcap2
-rw-r--r--mutt/muttrc139
-rw-r--r--mutt/sig3
-rw-r--r--mutt/themes/comidia52
-rw-r--r--mutt/themes/current88
-rwxr-xr-xmutt/tiny.pl49
-rw-r--r--ncmpcpp/bindings515
-rw-r--r--ncmpcpp/config277
-rw-r--r--termite/config66
-rw-r--r--vim/after/syntax/c.vim13
m---------vim/bundle/neobundle.vim0
-rw-r--r--vim/colors/Darkcustomside.vim103
-rw-r--r--vim/filetype.vim4
-rw-r--r--vim/ftplugin/mail.vim2
-rw-r--r--vim/vimrc70
-rw-r--r--weechat/alias.conf45
-rw-r--r--weechat/aspell.conf21
-rw-r--r--weechat/buffers.conf60
-rw-r--r--weechat/charset.conf11
-rw-r--r--weechat/irc.conf242
-rw-r--r--weechat/iset.conf27
-rw-r--r--weechat/logger.conf26
l---------weechat/perl/autoload/buffers.pl1
l---------weechat/perl/autoload/highmon.pl1
l---------weechat/perl/autoload/iset.pl1
l---------weechat/perl/autoload/stalker.pl1
l---------weechat/perl/autoload/yaurls.pl1
-rw-r--r--weechat/perl/buffers.pl1200
-rw-r--r--weechat/perl/highmon.pl1064
-rw-r--r--weechat/perl/iset.pl1394
-rw-r--r--weechat/perl/stalker.pl1408
-rw-r--r--weechat/perl/yaurls.pl301
-rw-r--r--weechat/python/announce_url_title.py318
-rw-r--r--weechat/python/anotify.py470
l---------weechat/python/autoload/announce_url_title.py1
l---------weechat/python/autoload/anotify.py1
l---------weechat/python/autoload/colorize_nicks.py1
l---------weechat/python/autoload/listbuffer.py1
-rw-r--r--weechat/python/colorize_nicks.py316
-rw-r--r--weechat/python/listbuffer.py467
-rw-r--r--weechat/relay.conf37
-rw-r--r--weechat/rmodifier.conf14
-rw-r--r--weechat/script.conf48
-rw-r--r--weechat/sec.conf11
-rw-r--r--weechat/theos.crt23
-rw-r--r--weechat/xfer.conf38
-rw-r--r--weechat/yaurls.conf28
-rw-r--r--zsh/.zkbd/linux-unknown-linux-gnu26
-rw-r--r--zsh/.zkbd/screen-256color-:026
-rw-r--r--zsh/.zkbd/screen-:026
-rw-r--r--zsh/.zkbd/xterm-termite-:026
-rw-r--r--zsh/.zprofile42
-rw-r--r--zsh/.zshenv8
-rw-r--r--zsh/.zshrc118
70 files changed, 10128 insertions, 0 deletions
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..244a7b0
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "vim/bundle/neobundle.vim"]
+ path = vim/bundle/neobundle.vim
+ url = https://github.com/Shougo/neobundle.vim
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..47af4d0
--- /dev/null
+++ b/README.md
@@ -0,0 +1,4 @@
+dotfiles
+========
+
+Just a little repo of a few dotfiles...
diff --git a/Trolltech.conf b/Trolltech.conf
new file mode 100644
index 0000000..05b5e75
--- /dev/null
+++ b/Trolltech.conf
@@ -0,0 +1,189 @@
+[Qt%20Plugin%20Cache%204.8.false]
+usr\lib32\qt\plugins\inputmethods\libqimsw-multi.so=40805, 0, i386 linux g++-4 full-config, 2013-11-11T15:40:26
+usr\lib32\qt\plugins\iconengines\libqsvgicon.so=40805, 0, i386 linux g++-4 full-config, 2013-11-11T15:40:26
+usr\lib32\qt\plugins\imageformats\libqgif.so=40805, 0, i386 linux g++-4 full-config, 2013-11-11T15:40:26
+usr\lib32\qt\plugins\imageformats\libqico.so=40805, 0, i386 linux g++-4 full-config, 2013-11-11T15:40:26
+usr\lib32\qt\plugins\imageformats\libqjpeg.so=40805, 0, i386 linux g++-4 full-config, 2013-11-11T15:40:26
+usr\lib32\qt\plugins\imageformats\libqmng.so=40805, 0, i386 linux g++-4 full-config, 2013-11-11T15:40:26
+usr\lib32\qt\plugins\imageformats\libqsvg.so=40805, 0, i386 linux g++-4 full-config, 2013-11-11T15:40:26
+usr\lib32\qt\plugins\imageformats\libqtga.so=40805, 0, i386 linux g++-4 full-config, 2013-11-11T15:40:26
+usr\lib32\qt\plugins\imageformats\libqtiff.so=40805, 0, i386 linux g++-4 full-config, 2013-11-11T15:40:26
+usr\lib32\qt\plugins\bearer\libqconnmanbearer.so=40805, 0, i386 linux g++-4 full-config, 2013-11-11T15:40:26
+usr\lib32\qt\plugins\bearer\libqgenericbearer.so=40805, 0, i386 linux g++-4 full-config, 2013-11-11T15:40:26
+usr\lib32\qt\plugins\bearer\libqnmbearer.so=40805, 0, i386 linux g++-4 full-config, 2013-11-11T15:40:26
+usr\lib\qt4\plugins\inputmethods\libqimsw-multi.so=40805, 0, x86_64 linux g++-4 full-config, 2013-12-11T16:03:36
+usr\lib\qt4\plugins\imageformats\libqgif.so=40805, 0, x86_64 linux g++-4 full-config, 2013-12-11T16:03:36
+usr\lib\qt4\plugins\imageformats\libqico.so=40805, 0, x86_64 linux g++-4 full-config, 2013-12-11T16:03:36
+usr\lib\qt4\plugins\imageformats\libqjpeg.so=40805, 0, x86_64 linux g++-4 full-config, 2013-12-11T16:03:36
+usr\lib\qt4\plugins\imageformats\libqmng.so=40805, 0, x86_64 linux g++-4 full-config, 2013-12-11T16:03:36
+usr\lib\qt4\plugins\imageformats\libqsvg.so=40805, 0, x86_64 linux g++-4 full-config, 2013-12-11T16:03:36
+usr\lib\qt4\plugins\imageformats\libqtiff.so=40805, 0, x86_64 linux g++-4 full-config, 2013-12-11T16:03:36
+usr\lib\kde4\plugins\imageformats\kimg_dds.so=40805, 0, x86_64 linux g++-4 full-config, 2013-12-15T17:50:40
+usr\lib\kde4\plugins\imageformats\kimg_eps.so=40805, 0, x86_64 linux g++-4 full-config, 2013-12-15T17:50:40
+usr\lib\kde4\plugins\imageformats\kimg_exr.so=40805, 0, x86_64 linux g++-4 full-config, 2013-12-15T17:50:40
+usr\lib\kde4\plugins\imageformats\kimg_jp2.so=40805, 0, x86_64 linux g++-4 full-config, 2013-12-15T17:50:40
+usr\lib\kde4\plugins\imageformats\kimg_pcx.so=40805, 0, x86_64 linux g++-4 full-config, 2013-12-15T17:50:40
+usr\lib\kde4\plugins\imageformats\kimg_pic.so=40805, 0, x86_64 linux g++-4 full-config, 2013-12-15T17:50:40
+usr\lib\kde4\plugins\imageformats\kimg_psd.so=40805, 0, x86_64 linux g++-4 full-config, 2013-12-15T17:50:40
+usr\lib\kde4\plugins\imageformats\kimg_ras.so=40805, 0, x86_64 linux g++-4 full-config, 2013-12-15T17:50:40
+usr\lib\kde4\plugins\imageformats\kimg_rgb.so=40805, 0, x86_64 linux g++-4 full-config, 2013-12-15T17:50:40
+usr\lib\kde4\plugins\imageformats\kimg_tga.so=40805, 0, x86_64 linux g++-4 full-config, 2013-12-15T17:50:40
+usr\lib\kde4\plugins\imageformats\kimg_webp.so=40805, 0, x86_64 linux g++-4 full-config, 2013-12-15T18:04:51
+usr\lib\kde4\plugins\imageformats\kimg_xcf.so=40805, 0, x86_64 linux g++-4 full-config, 2013-12-15T17:50:40
+usr\lib\kde4\plugins\imageformats\kimg_xview.so=40805, 0, x86_64 linux g++-4 full-config, 2013-12-15T17:50:40
+usr\lib\kde4\kcm_apper.so=40802, 0, x86_64 linux g++-4 full-config, 2012-09-03T22:25:12
+usr\lib\qt4\plugins\sqldrivers\libqsqlibase.so=40805, 0, x86_64 linux g++-4 full-config, 2013-12-11T16:03:36
+usr\lib\qt4\plugins\sqldrivers\libqsqlite.so=40805, 0, x86_64 linux g++-4 full-config, 2013-12-11T16:03:36
+usr\lib\qt4\plugins\sqldrivers\libqsqlite3.so=40805, 0, x86_64 linux g++-4 full-config, 2013-10-07T14:16:40
+usr\lib\qt4\plugins\sqldrivers\libqsqlmysql.so=40805, 0, x86_64 linux g++-4 full-config, 2013-12-11T16:03:36
+usr\lib\qt4\plugins\sqldrivers\libqsqlodbc.so=40805, 0, x86_64 linux g++-4 full-config, 2013-12-11T16:03:36
+usr\lib\qt4\plugins\sqldrivers\libqsqlpsql.so=40805, 0, x86_64 linux g++-4 full-config, 2013-12-11T16:03:36
+usr\lib\qt4\plugins\iconengines\libqsvgicon.so=40805, 0, x86_64 linux g++-4 full-config, 2013-12-11T16:03:36
+usr\lib\qt4\plugins\bearer\libqconnmanbearer.so=40805, 0, x86_64 linux g++-4 full-config, 2013-12-11T16:03:36
+usr\lib\qt4\plugins\bearer\libqgenericbearer.so=40805, 0, x86_64 linux g++-4 full-config, 2013-12-11T16:03:36
+usr\lib\qt4\plugins\bearer\libqnmbearer.so=40805, 0, x86_64 linux g++-4 full-config, 2013-12-11T16:03:36
+usr\lib\kadu\plugins\libgadu_protocol.so=40804, 0, x86_64 linux g++-4 full-config, 2013-05-05T11:04:19
+usr\lib\kadu\plugins\libjabber_protocol.so=40804, 0, x86_64 linux g++-4 full-config, 2013-05-05T11:04:20
+usr\lib\kadu\plugins\libidle.so=40804, 0, x86_64 linux g++-4 full-config, 2013-05-05T11:04:19
+usr\lib\kadu\plugins\libautoaway.so=40804, 0, x86_64 linux g++-4 full-config, 2013-05-05T11:04:20
+usr\lib\kadu\plugins\libchat_notify.so=40804, 0, x86_64 linux g++-4 full-config, 2013-05-05T11:04:19
+usr\lib\kadu\plugins\libconfig_wizard.so=40804, 0, x86_64 linux g++-4 full-config, 2013-05-05T11:04:19
+usr\lib\kadu\plugins\libencryption_ng.so=40804, 0, x86_64 linux g++-4 full-config, 2013-05-05T11:04:19
+usr\lib\qt4\plugins\crypto\libqca-ossl.so=40805, 0, x86_64 linux g++-4 full-config, 2013-11-15T21:57:29
+usr\lib\kadu\plugins\libencryption_ng_simlite.so=40804, 0, x86_64 linux g++-4 full-config, 2013-05-05T11:04:20
+usr\lib\kadu\plugins\libfreedesktop_notify.so=40804, 0, x86_64 linux g++-4 full-config, 2013-05-05T11:04:19
+usr\lib\kadu\plugins\libhints.so=40804, 0, x86_64 linux g++-4 full-config, 2013-05-05T11:04:20
+usr\lib\kadu\plugins\libhistory.so=40804, 0, x86_64 linux g++-4 full-config, 2013-05-05T11:04:20
+usr\lib\kadu\plugins\libsql_history.so=40804, 0, x86_64 linux g++-4 full-config, 2013-05-05T11:04:20
+usr\lib\kadu\plugins\libhistory_migration.so=40804, 0, x86_64 linux g++-4 full-config, 2013-05-05T11:04:20
+usr\lib\kadu\plugins\libsound.so=40804, 0, x86_64 linux g++-4 full-config, 2013-05-05T11:04:19
+usr\lib\kadu\plugins\libphonon_sound.so=40804, 0, x86_64 linux g++-4 full-config, 2013-05-05T11:04:20
+usr\lib\kadu\plugins\libprofiles_import.so=40804, 0, x86_64 linux g++-4 full-config, 2013-05-05T11:04:20
+usr\lib\kadu\plugins\libdocking.so=40804, 0, x86_64 linux g++-4 full-config, 2013-05-05T11:04:19
+usr\lib\kadu\plugins\libqt4_docking.so=40804, 0, x86_64 linux g++-4 full-config, 2013-05-05T11:04:20
+usr\lib\kadu\plugins\libsms.so=40804, 0, x86_64 linux g++-4 full-config, 2013-05-05T11:04:20
+usr\lib\kadu\plugins\libtabs.so=40804, 0, x86_64 linux g++-4 full-config, 2013-05-05T11:04:20
+usr\lib\kde4\plugins\phonon_backend\phonon_gstreamer.so=40805, 0, x86_64 linux g++-4 full-config, 2013-11-10T11:00:06
+usr\lib\qt4\plugins\codecs\libqcncodecs.so=40805, 0, x86_64 linux g++-4 full-config, 2013-12-11T16:03:36
+usr\lib\qt4\plugins\codecs\libqjpcodecs.so=40805, 0, x86_64 linux g++-4 full-config, 2013-12-11T16:03:36
+usr\lib\qt4\plugins\codecs\libqkrcodecs.so=40805, 0, x86_64 linux g++-4 full-config, 2013-12-11T16:03:36
+usr\lib\qt4\plugins\codecs\libqtwcodecs.so=40805, 0, x86_64 linux g++-4 full-config, 2013-12-11T16:03:36
+opt\teamspeak3\sqldrivers\libqsqlite.so=40803, 0, x86_64 linux g++-4 full-config, 2013-10-25T11:58:46
+opt\teamspeak3\imageformats\libqgif.so=40803, 0, x86_64 linux g++-4 full-config, 2013-10-25T11:58:47
+opt\teamspeak3\imageformats\libqjpeg.so=40803, 0, x86_64 linux g++-4 full-config, 2013-10-25T11:58:47
+
+[Qt%20Factory%20Cache%204.8]
+com.trolltech.Qt.QInputContextFactoryInterface%3A\usr\lib32\qt\plugins\inputmethods\libqimsw-multi.so=2013-11-11T15:40:26, imsw-multi
+com.trolltech.Qt.QIconEngineFactoryInterfaceV2%3A\usr\lib32\qt\plugins\iconengines\libqsvgicon.so=2013-11-11T15:40:26, svg, svgz, svg.gz
+com.trolltech.Qt.QIconEngineFactoryInterface%3A\usr\lib32\qt\plugins\iconengines\libqsvgicon.so=2013-11-11T15:40:26
+com.trolltech.Qt.QImageIOHandlerFactoryInterface%3A\usr\lib32\qt\plugins\imageformats\libqgif.so=2013-11-11T15:40:26, gif
+com.trolltech.Qt.QImageIOHandlerFactoryInterface%3A\usr\lib32\qt\plugins\imageformats\libqico.so=2013-11-11T15:40:26, ico
+com.trolltech.Qt.QImageIOHandlerFactoryInterface%3A\usr\lib32\qt\plugins\imageformats\libqjpeg.so=2013-11-11T15:40:26, jpeg, jpg
+com.trolltech.Qt.QImageIOHandlerFactoryInterface%3A\usr\lib32\qt\plugins\imageformats\libqmng.so=2013-11-11T15:40:26, mng
+com.trolltech.Qt.QImageIOHandlerFactoryInterface%3A\usr\lib32\qt\plugins\imageformats\libqsvg.so=2013-11-11T15:40:26, svg, svgz
+com.trolltech.Qt.QImageIOHandlerFactoryInterface%3A\usr\lib32\qt\plugins\imageformats\libqtga.so=2013-11-11T15:40:26, tga
+com.trolltech.Qt.QImageIOHandlerFactoryInterface%3A\usr\lib32\qt\plugins\imageformats\libqtiff.so=2013-11-11T15:40:26, tiff, tif
+com.trolltech.Qt.QBearerEngineFactoryInterface%3A\usr\lib32\qt\plugins\bearer\libqconnmanbearer.so=2013-11-11T15:40:26, connman
+com.trolltech.Qt.QBearerEngineFactoryInterface%3A\usr\lib32\qt\plugins\bearer\libqgenericbearer.so=2013-11-11T15:40:26, generic
+com.trolltech.Qt.QBearerEngineFactoryInterface%3A\usr\lib32\qt\plugins\bearer\libqnmbearer.so=2013-11-11T15:40:26, networkmanager
+com.trolltech.Qt.QInputContextFactoryInterface%3A\usr\lib\qt4\plugins\inputmethods\libqimsw-multi.so=2013-12-11T16:03:36, imsw-multi
+com.trolltech.Qt.QImageIOHandlerFactoryInterface%3A\usr\lib\qt4\plugins\imageformats\libqgif.so=2013-12-11T16:03:36, gif
+com.trolltech.Qt.QImageIOHandlerFactoryInterface%3A\usr\lib\qt4\plugins\imageformats\libqico.so=2013-12-11T16:03:36, ico
+com.trolltech.Qt.QImageIOHandlerFactoryInterface%3A\usr\lib\qt4\plugins\imageformats\libqjpeg.so=2013-12-11T16:03:36, jpeg, jpg
+com.trolltech.Qt.QImageIOHandlerFactoryInterface%3A\usr\lib\qt4\plugins\imageformats\libqmng.so=2013-12-11T16:03:36, mng
+com.trolltech.Qt.QImageIOHandlerFactoryInterface%3A\usr\lib\qt4\plugins\imageformats\libqsvg.so=2013-12-11T16:03:36, svg, svgz
+com.trolltech.Qt.QImageIOHandlerFactoryInterface%3A\usr\lib\qt4\plugins\imageformats\libqtiff.so=2013-12-11T16:03:36, tiff, tif
+com.trolltech.Qt.QImageIOHandlerFactoryInterface%3A\usr\lib\kde4\plugins\imageformats\kimg_dds.so=2013-12-15T17:50:40, dds
+com.trolltech.Qt.QImageIOHandlerFactoryInterface%3A\usr\lib\kde4\plugins\imageformats\kimg_eps.so=2013-12-15T17:50:40, eps, EPS, epsi, EPSI, epsf, EPSF
+com.trolltech.Qt.QImageIOHandlerFactoryInterface%3A\usr\lib\kde4\plugins\imageformats\kimg_exr.so=2013-12-15T17:50:40, exr, EXR
+com.trolltech.Qt.QImageIOHandlerFactoryInterface%3A\usr\lib\kde4\plugins\imageformats\kimg_jp2.so=2013-12-15T17:50:40, jp2
+com.trolltech.Qt.QImageIOHandlerFactoryInterface%3A\usr\lib\kde4\plugins\imageformats\kimg_pcx.so=2013-12-15T17:50:40, pcx, PCX
+com.trolltech.Qt.QImageIOHandlerFactoryInterface%3A\usr\lib\kde4\plugins\imageformats\kimg_pic.so=2013-12-15T17:50:40, pic
+com.trolltech.Qt.QImageIOHandlerFactoryInterface%3A\usr\lib\kde4\plugins\imageformats\kimg_psd.so=2013-12-15T17:50:40, psd, PSD
+com.trolltech.Qt.QImageIOHandlerFactoryInterface%3A\usr\lib\kde4\plugins\imageformats\kimg_ras.so=2013-12-15T17:50:40, ras, RAS
+com.trolltech.Qt.QImageIOHandlerFactoryInterface%3A\usr\lib\kde4\plugins\imageformats\kimg_rgb.so=2013-12-15T17:50:40, rgb, RGB, rgba, RGBA, bw, BW, sgi, SGI
+com.trolltech.Qt.QImageIOHandlerFactoryInterface%3A\usr\lib\kde4\plugins\imageformats\kimg_tga.so=2013-12-15T17:50:40, tga, TGA
+com.trolltech.Qt.QImageIOHandlerFactoryInterface%3A\usr\lib\kde4\plugins\imageformats\kimg_webp.so=2013-12-15T18:04:51, webp
+com.trolltech.Qt.QImageIOHandlerFactoryInterface%3A\usr\lib\kde4\plugins\imageformats\kimg_xcf.so=2013-12-15T17:50:40, xcf, XCF
+com.trolltech.Qt.QImageIOHandlerFactoryInterface%3A\usr\lib\kde4\plugins\imageformats\kimg_xview.so=2013-12-15T17:50:40, xv
+com.trolltech.Qt.QSqlDriverFactoryInterface%3A\usr\lib\qt4\plugins\sqldrivers\libqsqlite.so=2013-12-11T16:03:36, QSQLITE
+com.trolltech.Qt.QSqlDriverFactoryInterface%3A\usr\lib\qt4\plugins\sqldrivers\libqsqlite3.so=2013-10-07T14:16:40, QSQLITE3
+com.trolltech.Qt.QSqlDriverFactoryInterface%3A\usr\lib\qt4\plugins\sqldrivers\libqsqlmysql.so=2013-10-24T12:03:08, QMYSQL3, QMYSQL
+com.trolltech.Qt.QIconEngineFactoryInterfaceV2%3A\usr\lib\qt4\plugins\iconengines\libqsvgicon.so=2013-12-11T16:03:36, svg, svgz, svg.gz
+com.trolltech.Qt.QIconEngineFactoryInterface%3A\usr\lib\qt4\plugins\iconengines\libqsvgicon.so=2013-12-11T16:03:36
+com.trolltech.Qt.QBearerEngineFactoryInterface%3A\usr\lib\qt4\plugins\bearer\libqconnmanbearer.so=2013-12-11T16:03:36, connman
+com.trolltech.Qt.QBearerEngineFactoryInterface%3A\usr\lib\qt4\plugins\bearer\libqgenericbearer.so=2013-12-11T16:03:36, generic
+com.trolltech.Qt.QBearerEngineFactoryInterface%3A\usr\lib\qt4\plugins\bearer\libqnmbearer.so=2013-12-11T16:03:36, networkmanager
+com.trolltech.Qt.QTextCodecFactoryInterface%3A\usr\lib\qt4\plugins\codecs\libqcncodecs.so=2013-12-11T16:03:36, GB18030, GBK, GB2312, gb2312.1980-0, gbk-0, CP936, MS936, windows-936, MIB: 114, MIB: 113, MIB: 2025, MIB: 57, MIB: -113
+com.trolltech.Qt.QTextCodecFactoryInterface%3A\usr\lib\qt4\plugins\codecs\libqjpcodecs.so=2013-12-11T16:03:36, EUC-JP, ISO-2022-JP, Shift_JIS, jisx0201*-0, jisx0208*-0, JIS7, SJIS, MS_Kanji, MIB: 18, MIB: 39, MIB: 17, MIB: 15, MIB: 63
+com.trolltech.Qt.QTextCodecFactoryInterface%3A\usr\lib\qt4\plugins\codecs\libqkrcodecs.so=2013-12-11T16:03:36, EUC-KR, ksc5601.1987-0, cp949, MIB: 38, MIB: 36, MIB: -949
+com.trolltech.Qt.QTextCodecFactoryInterface%3A\usr\lib\qt4\plugins\codecs\libqtwcodecs.so=2013-12-11T16:03:36, Big5, Big5-HKSCS, big5-0, big5hkscs-0, Big5-ETen, CP950, MIB: 2026, MIB: 2101, MIB: -2026, MIB: -2101
+com.trolltech.Qt.QSqlDriverFactoryInterface%3A\usr\lib\qt4\plugins\sqldrivers\libqsqlodbc.so=2013-12-11T16:03:36, QODBC3, QODBC
+com.trolltech.Qt.QSqlDriverFactoryInterface%3A\usr\lib\qt4\plugins\sqldrivers\libqsqlpsql.so=2013-12-11T16:03:36, QPSQL7, QPSQL
+com.trolltech.Qt.QSqlDriverFactoryInterface%3A\opt\teamspeak3\sqldrivers\libqsqlite.so=2013-10-25T11:58:46, QSQLITE
+com.trolltech.Qt.QImageIOHandlerFactoryInterface%3A\opt\teamspeak3\imageformats\libqgif.so=2013-10-25T11:58:47, gif
+com.trolltech.Qt.QImageIOHandlerFactoryInterface%3A\opt\teamspeak3\imageformats\libqjpeg.so=2013-10-25T11:58:47, jpeg, jpg
+
+[Qt]
+font="Ubuntu,9,-1,5,50,0,0,0,0,0"
+Palette\active=#333333, #ededed, #ffffff, #cbc7c4, #c6c6c6, #b8b5b2, #444444, #ffffff, #333333, #ffffff, #ededed, #b7b7b7, #a9b7c4, #333333, #0000ff, #ff00ff, #ececed, #000000, #ffffdc, #222222
+Palette\inactive=#333333, #ededed, #ffffff, #cbc7c4, #c6c6c6, #b8b5b2, #444444, #ffffff, #333333, #ffffff, #ededed, #b7b7b7, #bec7d1, #333333, #0000ff, #ff00ff, #ececed, #000000, #ffffdc, #222222
+Palette\disabled=#909090, #ededed, #ffffff, #cbc7c4, #c6c6c6, #b8b5b2, #909090, #ffffff, #909090, #ffffff, #ededed, #b7b7b7, #c4c4c4, #333333, #0000ff, #ff00ff, #ececed, #000000, #ffffdc, #222222
+fontPath=@Invalid()
+embedFonts=false
+style=GTK+
+doubleClickInterval=400
+cursorFlashTime=1000
+wheelScrollLines=3
+resolveSymlinks=false
+globalStrut\width=0
+globalStrut\height=0
+useRtlExtensions=false
+XIMInputStyle=On The Spot
+DefaultInputMethod=xim
+audiosink=Auto
+videomode=Auto
+GUIEffects=none
+customColors\0=4294967295
+customColors\1=4294967295
+customColors\2=4294967295
+customColors\3=4294967295
+customColors\4=4294967295
+customColors\5=4294967295
+customColors\6=4294967295
+customColors\7=4294967295
+customColors\8=4294967295
+customColors\9=4294967295
+customColors\10=4294967295
+customColors\11=4294967295
+customColors\12=4294967295
+customColors\13=4294967295
+customColors\14=4294967295
+customColors\15=4294967295
+4.8\libraryPath=
+filedialog=@ByteArray(\0\0\0\xbe\0\0\0\x3\0\0\0\x1e\0\0\0\xff\0\0\0\0\0\0\0\x2\0\0\0W\0\0\xe\0\x1\0\0\0\x6\x1\0\0\0\x1\0\0\0\x2\0\0\0\x5\x66ile:\0\0\0\x13\x66ile:///home/kyrias\0\0\0\x1\0\0\0\x1e\0/\0m\0\x65\0\x64\0i\0\x61\0/\0p\0i\0\x63\0t\0u\0r\0\x65\0s\0\0\0\x1e\0/\0m\0\x65\0\x64\0i\0\x61\0/\0p\0i\0\x63\0t\0u\0r\0\x65\0s\0\0\0~\0\0\0\xff\0\0\0\0\0\0\0\x1\0\0\0\0\0\0\0\0\x1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x1\xc6\0\0\0\x4\x1\x1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x64\xff\xff\xff\xff\0\0\0\x81\0\0\0\0\0\0\0\x4\0\0\0\xea\0\0\0\x1\0\0\0\0\0\0\0\x39\0\0\0\x1\0\0\0\0\0\0\0<\0\0\0\x1\0\0\0\0\0\0\0g\0\0\0\x1\0\0\0\0\0\0\0\x1)
+
+[Qt%20Plugin%20Cache%204.5.false]
+tmp\QtJambi_kyrias_amd64_4.5.2_01_gcc-20090628-2055\plugins\imageformats\libqgif.so=40502, 0, x86_64 linux g++-4 full-config, 2013-11-04T22:15:36
+tmp\QtJambi_kyrias_amd64_4.5.2_01_gcc-20090628-2055\plugins\imageformats\libqjpeg.so=40502, 0, x86_64 linux g++-4 full-config, 2013-11-04T22:15:36
+tmp\QtJambi_kyrias_amd64_4.5.2_01_gcc-20090628-2055\plugins\imageformats\libqmng.so=40502, 0, x86_64 linux g++-4 full-config, 2013-11-04T22:15:36
+tmp\QtJambi_kyrias_amd64_4.5.2_01_gcc-20090628-2055\plugins\imageformats\libqsvg.so=40502, 0, x86_64 linux g++-4 full-config, 2013-11-04T22:15:36
+tmp\QtJambi_kyrias_amd64_4.5.2_01_gcc-20090628-2055\plugins\imageformats\libqtiff.so=40502, 0, x86_64 linux g++-4 full-config, 2013-11-04T22:15:36
+tmp\QtJambi_kyrias_amd64_4.5.2_01_gcc-20090628-2055\plugins\iconengines\libqsvgicon.so=40502, 0, x86_64 linux g++-4 full-config, 2013-11-04T22:15:36
+tmp\QtJambi_kyrias_amd64_4.5.2_01_gcc-20090628-2055\plugins\codecs\libqcncodecs.so=40502, 0, x86_64 linux g++-4 full-config, 2013-11-04T22:15:36
+tmp\QtJambi_kyrias_amd64_4.5.2_01_gcc-20090628-2055\plugins\codecs\libqjpcodecs.so=40502, 0, x86_64 linux g++-4 full-config, 2013-11-04T22:15:36
+tmp\QtJambi_kyrias_amd64_4.5.2_01_gcc-20090628-2055\plugins\codecs\libqkrcodecs.so=40502, 0, x86_64 linux g++-4 full-config, 2013-11-04T22:15:36
+tmp\QtJambi_kyrias_amd64_4.5.2_01_gcc-20090628-2055\plugins\codecs\libqtwcodecs.so=40502, 0, x86_64 linux g++-4 full-config, 2013-11-04T22:15:36
+
+[Qt%20Factory%20Cache%204.5]
+com.trolltech.Qt.QImageIOHandlerFactoryInterface%3A\tmp\QtJambi_kyrias_amd64_4.5.2_01_gcc-20090628-2055\plugins\imageformats\libqgif.so=2013-11-04T22:15:36, gif
+com.trolltech.Qt.QImageIOHandlerFactoryInterface%3A\tmp\QtJambi_kyrias_amd64_4.5.2_01_gcc-20090628-2055\plugins\imageformats\libqjpeg.so=2013-11-04T22:15:36, jpeg, jpg
+com.trolltech.Qt.QImageIOHandlerFactoryInterface%3A\tmp\QtJambi_kyrias_amd64_4.5.2_01_gcc-20090628-2055\plugins\imageformats\libqmng.so=2013-11-04T22:15:36, mng
+com.trolltech.Qt.QImageIOHandlerFactoryInterface%3A\tmp\QtJambi_kyrias_amd64_4.5.2_01_gcc-20090628-2055\plugins\imageformats\libqsvg.so=2013-11-04T22:15:36, svg
+com.trolltech.Qt.QImageIOHandlerFactoryInterface%3A\tmp\QtJambi_kyrias_amd64_4.5.2_01_gcc-20090628-2055\plugins\imageformats\libqtiff.so=2013-11-04T22:15:36, tiff, tif
+com.trolltech.Qt.QIconEngineFactoryInterfaceV2%3A\tmp\QtJambi_kyrias_amd64_4.5.2_01_gcc-20090628-2055\plugins\iconengines\libqsvgicon.so=2013-11-04T22:15:36, svg, svgz, svg.gz
+com.trolltech.Qt.QIconEngineFactoryInterface%3A\tmp\QtJambi_kyrias_amd64_4.5.2_01_gcc-20090628-2055\plugins\iconengines\libqsvgicon.so=2013-11-04T22:15:36
+com.trolltech.Qt.QTextCodecFactoryInterface%3A\tmp\QtJambi_kyrias_amd64_4.5.2_01_gcc-20090628-2055\plugins\codecs\libqcncodecs.so=2013-11-04T22:15:36, GB18030, GBK, GB2312, gb2312.1980-0, gbk-0, CP936, MS936, windows-936, MIB: 114, MIB: 113, MIB: 2025, MIB: 57, MIB: -113
+com.trolltech.Qt.QTextCodecFactoryInterface%3A\tmp\QtJambi_kyrias_amd64_4.5.2_01_gcc-20090628-2055\plugins\codecs\libqjpcodecs.so=2013-11-04T22:15:36, EUC-JP, ISO-2022-JP, Shift_JIS, jisx0201*-0, jisx0208*-0, JIS7, SJIS, MS_Kanji, MIB: 18, MIB: 39, MIB: 17, MIB: 15, MIB: 63
+com.trolltech.Qt.QTextCodecFactoryInterface%3A\tmp\QtJambi_kyrias_amd64_4.5.2_01_gcc-20090628-2055\plugins\codecs\libqkrcodecs.so=2013-11-04T22:15:36, EUC-KR, ksc5601.1987-0, cp949, MIB: 38, MIB: 36, MIB: -949
+com.trolltech.Qt.QTextCodecFactoryInterface%3A\tmp\QtJambi_kyrias_amd64_4.5.2_01_gcc-20090628-2055\plugins\codecs\libqtwcodecs.so=2013-11-04T22:15:36, Big5, Big5-HKSCS, big5-0, big5hkscs-0, Big5-ETen, CP950, MIB: 2026, MIB: 2101, MIB: -2026, MIB: -2101
diff --git a/X11/XCompose b/X11/XCompose
new file mode 100644
index 0000000..2a526c2
--- /dev/null
+++ b/X11/XCompose
@@ -0,0 +1,69 @@
+# Various extra characters
+<Multi_key> <a> <o> : "å" aring
+<Multi_key> <A> <o> : "Å" Aring
+<Multi_key> <a> <e> : "ä" adiaeresis
+<Multi_key> <A> <e> : "Ä" Adiaeresis
+<Multi_key> <o> <e> : "ö" odiaeresis
+<Multi_key> <O> <e> : "Ö" Odiaeresis
+<Multi_key> <quotedbl> <u> : "ü" udiaeresis
+<Multi_key> <quotedbl> <U> : "Ü" Udiaeresis
+<Multi_key> <apostrophe> <e> : "é" eacute
+<Multi_key> <apostrophe> <E> : "É" Eacute
+<Multi_key> <grave> <e> : "è" egrave
+<Multi_key> <grave> <E> : "È" Egrave
+<Multi_key> <quotedbl> <i> : "ï" idiaeresis
+<Multi_key> <quotedbl> <I> : "Ï" Idiaeresis
+
+# Quotes
+<Multi_key> <quotedbl> <bracketleft> : "“" U201C
+<Multi_key> <quotedbl> <bracketright> : "”" U201D
+<Multi_key> <apostrophe> <bracketleft> : "‘" U2018
+<Multi_key> <apostrophe> <bracketright> : "’" U2019
+<Multi_key> <less> <bracketleft> : "「" UFF62
+<Multi_key> <more> <bracketright> : "」" UFF63
+
+<Multi_key> <e> <m> <minus> : "—" U2014
+
+# Dots/ellipsises
+<Multi_key> <period> <colon> : "·" periodcentered # MIDDLE DOT
+<Multi_key> <period> <period> <period> : "…" U2026 # HORIZONTAL ELLIPSIS
+
+<Multi_key> <minus> <less> : "←" leftarrow # LEFTWARDS ARROW
+<Multi_key> <minus> <v> : "↓" downarrow # DOWNWARDS ARROW
+<Multi_key> <minus> <asciicircum> : "↑" uparrow # UPWARDS ARROW
+<Multi_key> <minus> <greater> : "→" rightarrow # RIGHTWARDS ARROW
+
+# Mathstuffs
+<Multi_key> <x> <x> : "×" U00D7 # MULTIPLICATION SIGN
+<Multi_key> <slash> <slash> : "÷" U00F7 # DIVISION SIGN
+<Multi_key> <plus> <minus> : "±" U00B1 # PLUS-MINUS SIGN
+<Multi_key> <8> <8> : "∞" U221E # INFINITY
+
+<Multi_key> <slash> <equal> : "≠" U2260 # NOT EQUAL TO
+
+# Smileys
+<Multi_key> <colon> <parenright> : "☺" U263A # WHITE SMILING FACE
+<Multi_key> <colon> <parenleft> : "☹" U2639 # WHITE FROWNING FACE
+
+# Hearts
+<Multi_key> <less> <3> : "❤" U2764 # HEAVY BLACK HEART
+<Multi_key> <less> <e> : "❥" U2765 # ROTATED HEAVY BLACK HEART BULLET
+
+# Stars and misc symbols
+<Multi_key> <asterisk> <asterisk> : "★" U2605 # BLACK STAR
+<Multi_key> <asterisk> <0> : "☆" U2606 # WHITE STAR
+<Multi_key> <asterisk> <minus> : "✪" U272A # CIRCLED WHITE STAR
+<Multi_key> <y> <y> : "☯" U262F # YIN YANG
+
+# Degree symbols
+<Multi_key> <asciicircum> <o> : "°" U00B0 # DEGREE SIGN
+<Multi_key> <o> <C> : "℃" U2103 # DEGREE CELSIUS
+<Multi_key> <o> <F> : "℉" U2109 # DEGREE CELSIUS
+
+# Intellectual property symbols
+<Multi_key> <c> <s> : "©" U00A9 # COPYRIGHT SIGN
+<Multi_key> <r> <s> : "®" U00AE # REGISTERED SIGN
+<Multi_key> <t> <m> : "™" U2122 # TRADE MARK SIGN
+
+<Multi_key> <b> <h> <s> : "☣" U2623 # BIOHAZARD SIGN
+<Multi_key> <r> <a> <s> : "☢" U2622 # RADIOACTIVE SIGN
diff --git a/X11/Xresources b/X11/Xresources
new file mode 100644
index 0000000..5ef5d6a
--- /dev/null
+++ b/X11/Xresources
@@ -0,0 +1,67 @@
+Xcursor.theme: Vanilla-DMZ-AA
+
+!URxvt*termName: rxvt-unicode-256color
+
+!URxvt*loginShell: true
+
+URxvt.iconFile: /usr/share/icons/elementary-xfce/apps/32/terminal.svg
+
+!transparency
+URxvt.depth: 32
+URxvt.background: [80]#000000
+URxvt.fading: 0
+
+!urxvt fonts:
+
+URxvt*font: xft:Ubuntu Mono:pixelsize=15
+URxvt*boldFont: xft:Ubuntu Mono:bold:pixelsize=15
+
+URxvt*geometry: 90x25
+
+!urxvt extensions:
+URxvt.perl-ext-common: default,fullscreen,tabbedex,vtwheel,clipboard,url-select,keyboard-select
+URxvt.url-select.launcher: /usr/bin/firefox
+URxvt.url-select.underline: true
+URxvt.keysym.M-u: perl:url-select:select_next
+URxvt.keysym.M-Escape: perl:keyboard-select:activate
+URxvt.keysym.M-s: perl:keyboard-select:search
+
+
+URxvt.keysym.F11: perl:fullscreen:switch
+
+!enabling clickable links:
+!URxvt.url-launcher: /usr/bin/firefox
+!URxvt.matcher.button: 1
+
+!urxvt scrolling options and cursor style:
+URxvt*saveLines: 12000
+URxvt*scrollstyle:plain
+URxvt*scrollBar: true
+URxvt*scrollBar_right: true
+URxvt*cursorBlink: true
+URxvt*cursorUnderline: true
+
+! urxvt tabs settings:
+URxvt.tabbed.tabbar-fg: 2
+URxvt.tabbed.tabbar-bg: 0
+URxvt.tabbed.tab-fg: 2
+URxvt.tabbed.tab-bg: 8
+URxvt.tabbed.autohide: yes
+URxvt.tabbed.new-button: no
+URxvt.tabbed.title: no
+
+URxvt*.keysym.Control-Up: \033[1;5A
+URxvt*.keysym.Control-Down: \033[1;5B
+URxvt*.keysym.Control-Left: \033[1;5D
+URxvt*.keysym.Control-Right: \033[1;5C
+
+URxvt.colorIT: #87af5f
+URxvt.colorBD: #d7d7d7
+URxvt.colorUL: #87afd7
+
+*VT100.colorBDMode: true
+*VT100.colorBD: red
+*VT100.colorULMode: true
+*VT100.colorUL: cyan
+XTerm*bellIsUrgent: true
+URxvt.urgentOnBell: true
diff --git a/X11/Xresources-theme b/X11/Xresources-theme
new file mode 100644
index 0000000..1b636be
--- /dev/null
+++ b/X11/Xresources-theme
@@ -0,0 +1,39 @@
+! ----------------------------------------------------------------------------
+! file: Xresources-colors
+! author: Miblo - http://miblodelcarpio.blog.co.uk/
+! modified: 2012-06-15
+! vim:fenc=utf-8:nu:ai:si:et:ts=4:sw=4:ft=xdefaults:
+! ----------------------------------------------------------------------------
+
+*background: #000000
+*foreground: #FFFFFF
+*fading: 40
+*fadeColor: #000000
+*cursorColor: #33FF33
+*pointerColorBackground:#99FF33
+*pointerColorForeground:#000000
+
+!! blacks: Black / Dark grey
+*color0: #000000
+*color8: #3D3D3D
+!! reds: Strong red / Light brilliant red
+*color1: #B80000
+*color9: #FF3333
+!! greens: Light brilliant green / Light brilliant chartreuse green
+*color2: #33FF33
+*color10: #99FF33
+!! yellows: Light brilliant orange / Light brilliant yellow
+*color3: #FF9933
+*color11: #FFFF33
+!! blues: Light brilliant blue / Light brilliant azure
+*color4: #3333FF
+*color12: #3399FF
+!! magentas: Light brilliant magenta / Light brilliant violet
+*color5: #FF33FF
+*color13: #9933FF
+!! cyans: Light brilliant cyan / Very light cyan
+*color6: #33FFFF
+*color14: #99FFFF
+!! whites: Cosmic latte / White
+*color7: #FFF8E7
+*color15: #FFFFFF
diff --git a/X11/xinitrc b/X11/xinitrc
new file mode 100644
index 0000000..dd2b874
--- /dev/null
+++ b/X11/xinitrc
@@ -0,0 +1,14 @@
+#!/bin/sh
+#
+# ~/.xinitrc
+#
+# Executed by startx (run your window manager from here)
+
+if [ -d /etc/X11/xinit/xinitrc.d ]; then
+ for f in /etc/X11/xinit/xinitrc.d/*; do
+ [ -x "$f" ] && . "$f"
+ done
+ unset f
+fi
+
+exec i3 -c /home/kyrias/.config/i3/config
diff --git a/cower/config b/cower/config
new file mode 100644
index 0000000..0dec69d
--- /dev/null
+++ b/cower/config
@@ -0,0 +1,39 @@
+#
+# example cower config file
+#
+# All options here can be overriden with flags on the command line. All options
+# are case sensitive. This file will be read per user, and should be located at
+# $XDG_CONFIG_HOME/cower/config or $HOME/.config/cower/config.
+#
+
+# Use color in the output. This takes an optional arg of auto/never/always,
+# identical to the command line arg --color. If no arg is specified, this is
+# assumed to mean auto.
+Color = auto
+
+# Connection timeout to be passed to curl. Setting this to 0 will disable
+# timeouts.
+#ConnectTimeout =
+
+# Always ignore out of date packages. This can be overridden on the command line
+# with --no-ignore-ood.
+#IgnoreOOD
+
+# Ignore the specified packages when checking for updates. Multiple arguments
+# to this option should be space delimited. Similar to the --ignore option,
+# this is in addition to any packages found in pacman's config.
+IgnorePkg = weechat-git beets-git
+
+# Ignore the specified binary repos when checking for updates. Multiple arguments
+# to this option should be space delimited.
+#IgnoreRepo =
+
+# Absolute path to download and extract to. Parameter and tilde expansions are
+# honored here.
+TargetDir = /home/kyrias/build/
+
+# Max number of threads cower will use. This is synonymous with the max number
+# of concurrent connections that will be opened to the AUR.
+MaxThreads = 4
+
+# vim: set noet syn=conf
diff --git a/dunst/dunstrc b/dunst/dunstrc
new file mode 100644
index 0000000..07c5114
--- /dev/null
+++ b/dunst/dunstrc
@@ -0,0 +1,102 @@
+[global]
+ font = Terminus 10
+ allow_markup = yes
+ format = "%a\n%s %p\n%b"
+ sort = no
+ indicate_hidden = yes
+ alignment = left
+ show_age_threshold = 60
+ word_wrap = yes
+ ignore_newline = no
+ geometry = "550x0-1+18"
+ transparency = 15
+ idle_threshold = 120
+ monitor = 0
+ follow = mouse
+ sticky_history = yes
+ line_height = 0
+ separator_height = 2
+ padding = 8
+ horizontal_padding = 8
+ separator_color = frame
+ startup_notification = true
+ dmenu = /usr/bin/dmenu -p dunst:
+ browser = /usr/bin/firefox -new-tab
+
+[frame]
+ width = 3
+ color = "#000000"
+
+[shortcuts]
+ close = ctrl+mod4+space
+ close_all = ctrl+shift+mod4+space
+ history = mod4+grave
+ context = ctrl+mod4+period
+
+[urgency_low]
+ background = "#0f0f0f"
+ foreground = "#3EA290"
+ timeout = 10
+
+[urgency_normal]
+ background = "#0f0f0f"
+ foreground = "#899AFF"
+ timeout = 15
+
+[urgency_critical]
+ background = "#0f0f0f"
+ foreground = "#95A7CC"
+ timeout = 25
+
+
+# Every section that isn't one of the above is interpreted as a rules
+# to override settings for certain messages.
+# Messages can be matched by 'appname', 'summary', 'body' or 'icon'
+# and you can override the 'timeout', 'urgency', 'foreground', 'background'
+# and 'format'.
+# Shell-like globbing will get expanded.
+#
+# SCRIPTING
+# you can specify a script that gets run when the rule matches by setting
+# the 'script' option.
+# The script will be called as follows:
+# script appname summary body icon urgency
+# where urgency can be "LOW", "NORMAL" or "CRITICAL".
+#
+# NOTE: if you don't want a notification to be displayed, set the format to ""
+# NOTE: It might be helpful to run dunst -print in a terminal in order to find
+# fitting options for rules.
+
+#[espeak]
+# summary = "*"
+# script = dunst_espeak.sh
+
+#[script-test]
+# summary = "*script*"
+# script = dunst_test.sh
+
+#[ignore]
+## This notification will not be displayed
+# summary = "foobar"
+# format = ""
+
+#[signed_on]
+# appname = Pidgin
+# summary = "*signed on*"
+# urgency = low
+#
+#[signed_off]
+# appname = Pidgin
+# summary = *signed off*
+# urgency = low
+#
+#[says]
+# appname = Pidgin
+# summary = *says*
+# urgency = critical
+#
+#[twitter]
+# appname = Pidgin
+# summary = *twitter.com*
+# urgency = normal
+#
diff --git a/git/config b/git/config
new file mode 100644
index 0000000..d35dec6
--- /dev/null
+++ b/git/config
@@ -0,0 +1,27 @@
+[user]
+ name = Johannes Löthberg
+ email = johannes@kyriasis.com
+ signingkey = 3A9D0BB5
+[credential]
+ helper = cache --timeout=7200
+[color]
+ ui = true
+[push]
+ default = simple
+[alias]
+ co = checkout
+ br = branch
+ ci = commit
+ st = status
+ unstage = reset HEAD --
+ last = log -1 HEAD
+[branch]
+ autosetuprebase = always
+[github]
+ user = kyrias
+[core]
+ editor = vim
+[merge]
+ tool = vimdiff
+[sendemail]
+ smtpserver = /usr/bin/msmtp
diff --git a/gtk-2.0/gtkrc-2.0 b/gtk-2.0/gtkrc-2.0
new file mode 100644
index 0000000..091744f
--- /dev/null
+++ b/gtk-2.0/gtkrc-2.0
@@ -0,0 +1,17 @@
+# DO NOT EDIT! This file will be overwritten by LXAppearance.
+# Any customization should be done in ~/.gtkrc-2.0.mine instead.
+
+gtk-theme-name="Albatross"
+gtk-icon-theme-name="elementary-xfce-darkest"
+gtk-font-name="Ubuntu 9"
+gtk-cursor-theme-size=0
+gtk-toolbar-style=GTK_TOOLBAR_BOTH
+gtk-toolbar-icon-size=GTK_ICON_SIZE_LARGE_TOOLBAR
+gtk-button-images=1
+gtk-menu-images=1
+gtk-enable-event-sounds=1
+gtk-enable-input-feedback-sounds=1
+gtk-xft-antialias=1
+gtk-xft-hinting=1
+gtk-xft-hintstyle="hintmedium"
+gtk-xft-rgba="rgb"
diff --git a/gtk-3.0/settings.ini b/gtk-3.0/settings.ini
new file mode 100644
index 0000000..e1447d6
--- /dev/null
+++ b/gtk-3.0/settings.ini
@@ -0,0 +1,15 @@
+[Settings]
+gtk-theme-name=Albatross
+gtk-icon-theme-name=elementary-xfce-darkest
+gtk-font-name=Ubuntu 9
+gtk-cursor-theme-size=0
+gtk-toolbar-style=GTK_TOOLBAR_BOTH
+gtk-toolbar-icon-size=GTK_ICON_SIZE_LARGE_TOOLBAR
+gtk-button-images=1
+gtk-menu-images=1
+gtk-enable-event-sounds=1
+gtk-enable-input-feedback-sounds=1
+gtk-xft-antialias=1
+gtk-xft-hinting=1
+gtk-xft-hintstyle=hintmedium
+gtk-xft-rgba=rgb
diff --git a/i3/bar.py b/i3/bar.py
new file mode 100644
index 0000000..0ce9469
--- /dev/null
+++ b/i3/bar.py
@@ -0,0 +1,55 @@
+# -*- coding: utf-8 -*-
+
+import subprocess
+
+from i3pystatus import Status
+
+status = Status(standalone=True)
+
+status.register("clock",
+ format="%y-%m-%d %H:%M:%S",)
+
+status.register("battery",
+ format="{status} {percentage:.2f}% {remaining:%E%hh:%Mm}",
+ alert=True,
+ alert_percentage=20,
+ status={
+ "DIS": "↓",
+ "CHR": "↑",
+ "FULL": "=",
+ },
+ battery_ident="BAT1",)
+
+
+status.register("temp",
+ format="{temp:.0f}°C",)
+
+status.register("pulseaudio",
+ format="♪:{volume}%",)
+
+status.register("mpd",
+ format="{status} {artist} > {title}",
+ status={
+ "pause": "✧",
+ "play": "▶",
+ "stop": "◾",
+ },)
+
+status.register("wireless",
+ interface="wlp3s0",
+ format_up="{v4cidr}{quality:3.0f}%",)
+
+# Shows disk usage of /
+# Format:
+# 42/128G [86G]
+status.register("disk",
+ path="/home/kyrias/media",
+ format="{avail}G",)
+
+status.register("disk",
+ path="/",
+ format="{avail}G",)
+
+
+
+status.run()
diff --git a/i3/config b/i3/config
new file mode 100644
index 0000000..3e5403e
--- /dev/null
+++ b/i3/config
@@ -0,0 +1,166 @@
+set $mod Mod4
+
+#font pango:visitor tt2 brk 10
+font pango:Source Code Pro 8
+
+floating_modifier $mod
+bindsym $mod+Return exec termite
+bindsym $mod+Shift+q kill
+bindsym $mod+d exec --no-startup-id j4-dmenu-desktop
+bindsym $mod+Shift+d exec --no-startup-id dmenu_run
+
+# change focus
+bindsym $mod+h focus left
+bindsym $mod+j focus down
+bindsym $mod+k focus up
+bindsym $mod+l focus right
+
+# move focused window
+bindsym $mod+Shift+h move left
+bindsym $mod+Shift+j move down
+bindsym $mod+Shift+k move up
+bindsym $mod+Shift+l move right
+
+bindsym $mod+b split h
+bindsym $mod+v split v
+
+bindsym $mod+f fullscreen
+bindsym $mod+s layout stacking
+bindsym $mod+w layout tabbed
+bindsym $mod+e layout toggle split
+bindsym $mod+Shift+space floating toggle
+# change focus between tiling / floating windows
+bindsym $mod+space focus mode_toggle
+
+bindsym $mod+a focus parent
+bindsym $mod+c focus child
+
+set $workspace1 1
+set $workspace2 2
+set $workspace3 3
+set $workspace4 4
+set $workspace5 5
+set $workspace6 6
+set $workspace7 7
+set $workspace8 8
+set $workspace9 9
+set $workspace0 10
+
+# switch to workspace
+bindsym $mod+1 workspace $workspace1
+bindsym $mod+2 workspace $workspace2
+bindsym $mod+3 workspace $workspace3
+bindsym $mod+4 workspace $workspace4
+bindsym $mod+5 workspace $workspace5
+bindsym $mod+6 workspace $workspace6
+bindsym $mod+7 workspace $workspace7
+bindsym $mod+8 workspace $workspace8
+bindsym $mod+9 workspace $workspace9
+bindsym $mod+0 workspace $workspace0
+
+# move focused container to workspace
+bindsym $mod+Shift+1 move container to workspace $workspace1
+bindsym $mod+Shift+2 move container to workspace $workspace2
+bindsym $mod+Shift+3 move container to workspace $workspace3
+bindsym $mod+Shift+4 move container to workspace $workspace4
+bindsym $mod+Shift+5 move container to workspace $workspace5
+bindsym $mod+Shift+6 move container to workspace $workspace6
+bindsym $mod+Shift+7 move container to workspace $workspace7
+bindsym $mod+Shift+8 move container to workspace $workspace8
+bindsym $mod+Shift+9 move container to workspace $workspace9
+bindsym $mod+Shift+0 move container to workspace $workspace0
+
+# reload the configuration file
+bindsym $mod+Shift+c reload
+# restart i3 inplace (preserves your layout/session, can be used to upgrade i3)
+bindsym $mod+Shift+r restart
+# exit i3 (logs you out of your X session)
+bindsym $mod+Shift+e exec "i3-nagbar -t warning -m 'You pressed the exit shortcut. Do you really want to exit i3? This will end your X session.' -b 'Yes, exit i3' 'i3-msg exit'"
+
+# resize window (you can also use the mouse for that)
+mode "resize" {
+# These bindings trigger as soon as you enter the resize mode
+
+# Pressing left will shrink the window’s width.
+# Pressing right will grow the window’s width.
+# Pressing up will shrink the window’s height.
+# Pressing down will grow the window’s height.
+ bindsym h resize shrink width 10 px or 10 ppt
+ bindsym j resize grow height 10 px or 10 ppt
+ bindsym k resize shrink height 10 px or 10 ppt
+ bindsym l resize grow width 10 px or 10 ppt
+
+# same bindings, but for the arrow keys
+ bindsym Left resize shrink width 10 px or 10 ppt
+ bindsym Down resize grow height 10 px or 10 ppt
+ bindsym Up resize shrink height 10 px or 10 ppt
+ bindsym Right resize grow width 10 px or 10 ppt
+
+# back to normal: Enter or Escape
+ bindsym Return mode "default"
+ bindsym Escape mode "default"
+}
+
+bindsym $mod+r mode "resize"
+
+# Start i3bar to display a workspace bar (plus the system information i3status
+# finds out, if available)
+#bar {
+# status_command i3status
+#}
+
+# i3bar
+bar {
+ status_command python ~/.config/i3/bar.py
+ position bottom
+ workspace_buttons yes
+ colors {
+ #class border backgr. text
+ background #101010
+ statusline #ffffff
+ urgent_workspace #303030 #202020 #bd3267
+ active_workspace #5f5f5f #101010 #101010
+ inactive_workspace #101010 #101010 #5f5f5f
+ focused_workspace #2e3436 #2a2a2a #FFFFFF
+ }
+}
+
+bindsym $mod+Shift+g exec --no-startup-id setxkbmap us
+#bindsym $mod+Shift+u exec --no-startup-id setxkbmap dvp
+bindsym $mod+Shift+u exec --no-startup-id setxkbmap dvorak
+
+# TrackPoint scrolling
+exec --no-startup-id xinput set-prop "TPPS/2 IBM TrackPoint" "Evdev Wheel Emulation" 1
+exec --no-startup-id xinput set-prop "TPPS/2 IBM TrackPoint" "Evdev Wheel Emulation Button" 2
+exec --no-startup-id xinput set-prop "TPPS/2 IBM TrackPoint" "Evdev Wheel Emulation Timeout" 150
+exec --no-startup-id xinput set-prop "TPPS/2 IBM TrackPoint" "Evdev Wheel Emulation Axes" 6 7 4 5
+exec --no-startup-id xinput set-prop "TPPS/2 IBM TrackPoint" "Evdev Middle Button Emulation" 1
+exec --no-startup-id xinput set-prop "TPPS/2 IBM TrackPoint" "Evdev Wheel Emulation Inertia" 25
+exec --no-startup-id xinput set-prop "SynPS/2 Synaptics TouchPad" "Synaptics Off" 1
+
+# control ncmpcpp / mpd from media keys
+bindsym XF86AudioPlay exec --no-startup-id mpc toggle
+bindsym XF86AudioStop exec --no-startup-id mpc stop
+bindsym XF86AudioNext exec --no-startup-id mpc next
+bindsym XF86AudioPrev exec --no-startup-id mpc prev
+
+# control PulseAudio from media keys
+bindsym XF86AudioMute exec volumecontrol.sh mute
+bindsym XF86Back exec volumecontrol.sh lower
+bindsym XF86AudioLowerVolume exec volumecontrol.sh lower
+bindsym XF86Forward exec volumecontrol.sh raise
+bindsym XF86AudioRaiseVolume exec volumecontrol.sh raise
+bindsym XF86ScreenSaver exec screenlock.sh
+
+new_window 1pixel
+bindsym $mod+t border normal
+bindsym $mod+y border 1pixel
+bindsym $mod+u border none
+
+for_window [class="Gifview"] floating enable
+#for_window [title="MPD:"] border 1pixel
+
+exec --no-startup-id /usr/bin/clipit &
+#exec --no-startup-id /usr/bin/dropbox start
+exec --no-startup-id feh --bg-tile /media/pictures/wallpapers/1366x768/wallpaper.png
+exec --no-startup-id /usr/lib/lxpolkit/lxpolkit &
diff --git a/mpv/config b/mpv/config
new file mode 100644
index 0000000..4598425
--- /dev/null
+++ b/mpv/config
@@ -0,0 +1,4 @@
+hwdec=vdpau
+vo=vdpau
+
+no-osc
diff --git a/mutt/gpg.rc b/mutt/gpg.rc
new file mode 100644
index 0000000..d6c9def
--- /dev/null
+++ b/mutt/gpg.rc
@@ -0,0 +1,85 @@
+# -*-muttrc-*-
+#
+# Command formats for gpg.
+#
+# This version uses gpg-2comp from
+# http://70t.de/download/gpg-2comp.tar.gz
+#
+# $Id$
+#
+# %p The empty string when no passphrase is needed,
+# the string "PGPPASSFD=0" if one is needed.
+#
+# This is mostly used in conditional % sequences.
+#
+# %f Most PGP commands operate on a single file or a file
+# containing a message. %f expands to this file's name.
+#
+# %s When verifying signatures, there is another temporary file
+# containing the detached signature. %s expands to this
+# file's name.
+#
+# %a In "signing" contexts, this expands to the value of the
+# configuration variable $pgp_sign_as. You probably need to
+# use this within a conditional % sequence.
+#
+# %r In many contexts, mutt passes key IDs to pgp. %r expands to
+# a list of key IDs.
+
+# Note that we explicitly set the comment armor header since GnuPG, when used
+# in some localiaztion environments, generates 8bit data in that header, thereby
+# breaking PGP/MIME.
+
+# decode application/pgp
+set pgp_decode_command="gpg --status-fd=2 %?p?--passphrase-fd 0? --no-verbose --quiet --batch --output - %f"
+
+# verify a pgp/mime signature
+set pgp_verify_command="gpg --status-fd=2 --no-verbose --quiet --batch --output - --verify %s %f"
+
+# decrypt a pgp/mime attachment
+set pgp_decrypt_command="gpg --status-fd=2 %?p?--passphrase-fd 0? --no-verbose --quiet --batch --output - %f"
+
+# create a pgp/mime signed attachment
+# set pgp_sign_command="gpg-2comp --comment '' --no-verbose --batch --output - %?p?--passphrase-fd 0? --armor --detach-sign --textmode %?a?-u %a? %f"
+set pgp_sign_command="gpg --no-verbose --batch --quiet --output - %?p?--passphrase-fd 0? --armor --detach-sign --textmode %?a?-u %a? %f"
+
+# create a application/pgp signed (old-style) message
+# set pgp_clearsign_command="gpg-2comp --comment '' --no-verbose --batch --output - %?p?--passphrase-fd 0? --armor --textmode --clearsign %?a?-u %a? %f"
+set pgp_clearsign_command="gpg --no-verbose --batch --quiet --output - %?p?--passphrase-fd 0? --armor --textmode --clearsign %?a?-u %a? %f"
+
+# create a pgp/mime encrypted attachment
+# set pgp_encrypt_only_command="pgpewrap gpg-2comp -v --batch --output - --encrypt --textmode --armor --always-trust -- -r %r -- %f"
+set pgp_encrypt_only_command="pgpewrap gpg --batch --quiet --no-verbose --output - --encrypt --textmode --armor --always-trust -- -r %r -- %f"
+
+# create a pgp/mime encrypted and signed attachment
+# set pgp_encrypt_sign_command="pgpewrap gpg-2comp %?p?--passphrase-fd 0? -v --batch --output - --encrypt --sign %?a?-u %a? --armor --always-trust -- -r %r -- %f"
+set pgp_encrypt_sign_command="pgpewrap gpg %?p?--passphrase-fd 0? --batch --quiet --no-verbose --textmode --output - --encrypt --sign %?a?-u %a? --armor --always-trust -- -r %r -- %f"
+
+# import a key into the public key ring
+set pgp_import_command="gpg --no-verbose --import %f"
+
+# export a key from the public key ring
+set pgp_export_command="gpg --no-verbose --export --armor %r"
+
+# verify a key
+set pgp_verify_key_command="gpg --verbose --batch --fingerprint --check-sigs %r"
+
+# read in the public key ring
+set pgp_list_pubring_command="gpg --no-verbose --batch --quiet --with-colons --list-keys %r"
+
+# read in the secret key ring
+set pgp_list_secring_command="gpg --no-verbose --batch --quiet --with-colons --list-secret-keys %r"
+
+# fetch keys
+# set pgp_getkeys_command="pkspxycwrap %r"
+
+# pattern for good signature - may need to be adapted to locale!
+
+# set pgp_good_sign="^gpgv?: Good signature from "
+
+# OK, here's a version which uses gnupg's message catalog:
+# set pgp_good_sign="`gettext -d gnupg -s 'Good signature from "' | tr -d '"'`"
+
+# This version uses --status-fd messages
+set pgp_good_sign="^\\[GNUPG:\\] GOODSIG"
+
diff --git a/mutt/mailcap b/mutt/mailcap
new file mode 100644
index 0000000..e0ed500
--- /dev/null
+++ b/mutt/mailcap
@@ -0,0 +1,2 @@
+text/html; ~/.config/mutt/tiny.pl %s %{charset} ; copiousoutput ; nametemplate=%s.html
+text/plain; ~/.config/mutt/tiny.pl %s %{charset} 't' ; copiousoutput ; nametemplate=%s.html
diff --git a/mutt/muttrc b/mutt/muttrc
new file mode 100644
index 0000000..8044f21
--- /dev/null
+++ b/mutt/muttrc
@@ -0,0 +1,139 @@
+# Compose View Options -------------------------------
+set realname = "Johannes Löthberg"
+set from = "johannes@kyriasis.com"
+set envelope_from # which from?
+set sig_dashes # dashes before sig
+set edit_headers # show headers when composing
+set fast_reply # skip to compose when replying
+set fcc_attach # save attachments with the body
+unset mime_forward # forward attachments as part of body
+set forward_format = "Fwd: %s" # format of subject when forwarding
+set forward_decode # decode when forwarding
+set attribution = "On %d, %n wrote:" # format of quoting header
+set reply_to # reply to Reply to: field
+set reverse_name # reply as whomever it was to
+set include # include message in replies
+set forward_quote # include message in forwards
+set charset = "utf-8"
+set send_charset = "utf-8"
+
+set editor = "vim"
+set text_flowed = yes
+set mark_old = no
+set sleep_time = 0 # no delay when opening a maildir!
+
+set mbox_type = Maildir
+set folder = "~/.mail/kyriasis"
+set trash = "~/.mail/kyriasis/Trash"
+set header_cache = ~/.config/mutt/cache/headers # where to store headers
+set message_cachedir = ~/.config/mutt/cache/ # where to store bodies
+set certificate_file = ~/.config/mutt/certificates # where to store certs
+set mailcap_path = ~/.config/mutt/mailcap # entries for filetypes
+set tmpdir = ~/.config/mutt/temp # where to keep temp files
+set signature = ~/.config/mutt/sig # my signature file
+set spoolfile = "+INBOX"
+set mbox = "+Archives"
+set postponed = "+Drafts"
+mailboxes +INBOX +Sent +Drafts +Trash +Archives +arch-dev-public +arch-bugs +Spam +Ham
+
+## Abook
+set query_command= "abook --datafile ~/.config/abook/addressbook --mutt-query '%s'"
+macro index,pager A "<pipe-message>abook --datafile ~/.config/abook/addressbook --add-email-quiet<return>" "Add this sender to Abook"
+bind editor <Tab> complete-query
+
+# Sync email
+macro index O "<shell-escape>offlineimap<enter>" "run offlineimap to sync all mail"
+macro index o "<shell-escape>offlineimap -qf INBOX<enter>" "run offlineimap to sync inbox"
+
+set sendmail = "/usr/bin/msmtp -a kyriasis"
+set sendmail_wait = 0
+set record = +Sent
+set copy = yes
+
+# Basic Options --------------------------------------
+#set wait_key = no # shut up, mutt
+#set timeout = 3 # idle time before scanning
+#set mail_check = 0 # minimum time between scans
+#unset move # gmail does that
+#set delete # don't ask, just do
+#unset confirmappend # don't ask, just do!
+#set quit # don't ask, just do!!
+#unset mark_old # read/new is good enough for me
+set beep_new # bell on new mails
+unset pipe_decode # strip headers and eval mimes when piping
+set thorough_search # strip headers and eval mimes before searching
+
+
+# Status Bar -----------------------------------------
+set status_chars = " *%A"
+set status_format = "───[ Folder: %f ]───[%r%m messages%?n? (%n new)?%?d? (%d to delete)?%?t? (%t tagged)? ]───%>─%?p?( %p postponed )?───"
+
+# Header Options -------------------------------------
+#ignore * # ignore all headers
+#unignore from: to: cc: date: subject: # show only these
+unignore X-Spambayes-Classification: X-Spambayes-Trained:
+#unhdr_order * # some distros order things by default
+#hdr_order from: to: cc: date: subject: # and in this order
+
+# Index View Options ---------------------------------
+set date_format = "%d/%m"
+set index_format = "[%Z] %D %-20.20F %s"
+set sort = threads # like gmail
+#set sort_aux = reverse-last-date-received # like gmail
+#set sort = reverse-last-date-received # like gmail
+#set sort_aux = threads # like gmail
+set uncollapse_jump # don't collapse on an unread message
+set sort_re # thread based on regex
+set reply_regexp = "^(([Rr][Ee]?(\[[0-9]+\])?: *)?(\[[^]]+\] *)?)*"
+# Pager View Options ---------------------------------
+set pager_index_lines = 10 # number of index lines to show
+set pager_context = 3 # number of context lines to show
+set pager_stop # don't go to next message automatically
+set menu_scroll # scroll in menus
+set tilde # show tildes like in vim
+unset markers # no ugly plus signs
+
+set quote_regexp = "^( {0,4}[>|:#%]| {0,4}[a-z0-9]+[>|]+)+"
+alternative_order text/plain text/enriched text/html
+
+
+macro index C "<copy-message>?<toggle-mailboxes>" "copy a message to a mailbox"
+macro index M "<save-message>?<toggle-mailboxes>" "move a message to a mailbox"
+
+# Index Key Bindings
+bind index gg first-entry
+bind index G last-entry
+
+bind index R group-reply
+bind index S sync-mailbox
+bind index <space> collapse-thread
+bind index B bounce-message
+
+# Pager Key Bindings ---------------------------------
+bind pager k previous-line
+bind pager j next-line
+bind pager gg top
+bind pager G bottom
+bind pager R group-reply
+
+# Move message to Archives
+macro index,pager a "s=Archives<enter>"
+
+# View attachments properly.
+bind attach <return> view-mailcap
+
+# Save and recall drafts
+bind compose P postpone-message
+bind index P recall-message
+
+source ~/.config/mutt/gpg.rc
+set pgp_timeout = 3600 # how long to cache the pass-phrase
+set crypt_autosign = yes
+set crypt_replyencrypt = yes
+set pgp_sign_as = 3A9D0BB5
+set pgp_use_gpg_agent = yes
+set crypt_use_pka = yes
+
+source ~/.config/mutt/themes/comidia
+
+subscribe arch-dev-public@archlinux.org
diff --git a/mutt/sig b/mutt/sig
new file mode 100644
index 0000000..5d39d0e
--- /dev/null
+++ b/mutt/sig
@@ -0,0 +1,3 @@
+Sincerely,
+ Johannes Löthberg
+ PGP Key ID: 3A9D0BB5
diff --git a/mutt/themes/comidia b/mutt/themes/comidia
new file mode 100644
index 0000000..40f70c6
--- /dev/null
+++ b/mutt/themes/comidia
@@ -0,0 +1,52 @@
+#
+# This theme is from H. D. Lee
+#
+# This colors file was originally taken from Rosenfeld's
+# Modified slightly.
+# Running aterm with:
+# aterm +sb -geometry 80x60 -bg papayawhip -fg darkgreen -e mutt
+#
+# color terminals:
+# (default, white, black, green, magenta, blue, cyan, yellow, red)
+# (bright...)
+# (color1,color2,...,colorN-1)
+#
+# object foreground background
+#
+color normal default default # normal text
+color indicator brightcyan black # actual message
+color tree brightmagenta default # thread arrows
+color status cyan black # status line
+color error brightcyan default # errors
+color message cyan default # info messages
+color signature red default # signature
+color attachment green default # MIME attachments
+color search brightyellow red # search matches
+color tilde brightmagenta default # ~ at bottom of msg
+color markers red default # + at beginning of wrapped lines
+color hdrdefault blue default # default header lines
+color bold red default # hiliting bold patterns in body
+color underline green default # hiliting underlined patterns in body
+color quoted cyan default # quoted text
+color quoted1 green default
+color quoted2 red default
+color quoted3 magenta default
+color quoted4 blue default
+color quoted5 blue default
+#
+# object foreground backg. RegExp
+#
+color header red default "^(from|subject):"
+color body yellow default "((ftp|http|https)://|(file|news):|www\\.)[-a-z0-9_.:]*[a-z0-9](/[^][{} \t\n\r\"<>()]*[^][{} \t\n\r\"<>().,:!])?/?"
+color body cyan default "[-a-z_0-9.+]+@[-a-z_0-9.]+"
+color body red default "(^| )\\*[-a-z0-9*]+\\*[,.?]?[ \n]"
+color body green default "(^| )_[-a-z0-9_]+_[,.?]?[ \n]"
+
+uncolor index * # unset all color index entries
+color index green default ~F # Flagged
+color index red default ~N # New
+color index magenta default ~T # Tagged
+color index yellow default ~D # Deleted
+color index blue default '\[(CHRPM|Contrib-Rpm)\]'
+color index color240 default "~h ^X.Mailer..Microsoft.Outlook"
+#color index brightblack default "~n 10-20"
diff --git a/mutt/themes/current b/mutt/themes/current
new file mode 100644
index 0000000..028ab5b
--- /dev/null
+++ b/mutt/themes/current
@@ -0,0 +1,88 @@
+
+## Theme kindly inspired from
+## http://nongeekshandbook.blogspot.ie/2009/03/mutt-color-configuration.html
+
+## Colours for items in the index
+color index brightcyan black ~N
+color index brightred black ~O
+color index brightyellow black ~F
+color index black green ~T
+color index brightred black ~D
+mono index bold ~N
+mono index bold ~F
+mono index bold ~T
+mono index bold ~D
+
+## Highlights inside the body of a message.
+
+## URLs
+color body brightgreen black "(http|ftp|news|telnet|finger)://[^ \"\t\r\n]*"
+color body brightgreen black "mailto:[-a-z_0-9.]+@[-a-z_0-9.]+"
+mono body bold "(http|ftp|news|telnet|finger)://[^ \"\t\r\n]*"
+mono body bold "mailto:[-a-z_0-9.]+@[-a-z_0-9.]+"
+
+## Email addresses.
+color body brightgreen black "[-a-z_0-9.%$]+@[-a-z_0-9.]+\\.[-a-z][-a-z]+"
+
+## Header
+color header green black "^from:"
+color header green black "^to:"
+color header green black "^cc:"
+color header green black "^date:"
+color header yellow black "^newsgroups:"
+color header yellow black "^reply-to:"
+color header brightcyan black "^subject:"
+color header red black "^x-spam-rule:"
+color header green black "^x-mailer:"
+color header yellow black "^message-id:"
+color header yellow black "^Organization:"
+color header yellow black "^Organisation:"
+color header yellow black "^User-Agent:"
+color header yellow black "^message-id: .*pine"
+color header yellow black "^X-Fnord:"
+color header yellow black "^X-WebTV-Stationery:"
+
+color header red black "^x-spam-rule:"
+color header green black "^x-mailer:"
+color header yellow black "^message-id:"
+color header yellow black "^Organization:"
+color header yellow black "^Organisation:"
+color header yellow black "^User-Agent:"
+color header yellow black "^message-id: .*pine"
+color header yellow black "^X-Fnord:"
+color header yellow black "^X-WebTV-Stationery:"
+color header yellow black "^X-Message-Flag:"
+color header yellow black "^X-Spam-Status:"
+color header yellow black "^X-SpamProbe:"
+color header red black "^X-SpamProbe: SPAM"
+
+## Coloring quoted text - coloring the first 7 levels:
+color quoted cyan black
+color quoted1 yellow black
+color quoted2 red black
+color quoted3 green black
+color quoted4 cyan black
+color quoted5 yellow black
+color quoted6 red black
+color quoted7 green black
+
+## Default color definitions
+color hdrdefault white green
+color signature brightmagenta black
+color indicator black cyan
+color attachment green black
+color error red black
+color message white black
+color search brightwhite magenta
+color status brightyellow blue
+color tree brightblue black
+color normal white black
+color tilde green black
+color bold brightyellow black
+color underline magenta black
+color markers brightcyan black
+
+## Colour definitions when on a mono screen
+mono bold bold
+mono underline underline
+mono indicator reverse
diff --git a/mutt/tiny.pl b/mutt/tiny.pl
new file mode 100755
index 0000000..06b51b7
--- /dev/null
+++ b/mutt/tiny.pl
@@ -0,0 +1,49 @@
+#!/usr/bin/perl
+###################################
+# By: Ventz Petkov #
+# Date: 01-05-11 #
+# Last: 01-02-13 #
+# Parses HTML + Long URLs in MUTT #
+###################################
+
+use URI::Escape;
+$file = $ARGV[0];
+@text = ();
+
+# Only shorten URLs at least this length or more
+$tinyurltrigger = 40;
+
+# If we pass a 2nd argument, it means we want to force HTML check a 'text/plain' file
+if(defined($ARGV[2])) { open(FP, $file); for(<FP>) { push(@text, $_); } close(FP); }
+# Otherwise, treat as HTML first
+else { @text = `elinks -dump -dump-charset $ARGV[1] -default-mime-type text/html $file`; }
+
+
+# Note: using while (instead of for) b/c for supposedly loads
+# everything into memory - no reason to load large emails into memory
+
+while (my $line = shift @text) {
+ next if($line =~ /mailto:/);
+ if($line =~ /(\w+:\/\/\S+)/) {
+ my $link = $1;
+ chomp($link);
+ $size = length($link);
+ if($size >= $tinyurltrigger) {
+ eval {
+ my $alarm = 5;
+ alarm $alarm;
+ my $link = uri_escape($link);
+ $tinyurl=`wget -q -O - http://tinyurl.com/api-create.php?url=$link`;
+ alarm 0;
+ };
+
+ if ($@) {
+ $line =~ s/(\w+:\/\/\S+)/$link (wget TimeOut)/; }
+ else { $line =~ s/(\w+:\/\/\S+)/$tinyurl\n\t[>> $link <<]/; }
+ }
+ }
+ print "$line";
+}
+
+
+exit 0;
diff --git a/ncmpcpp/bindings b/ncmpcpp/bindings
new file mode 100644
index 0000000..046ec25
--- /dev/null
+++ b/ncmpcpp/bindings
@@ -0,0 +1,515 @@
+##########################################################
+## this is example bindings configuration file, copy it ##
+## to ~/.ncmpcpp/bindings and set up your preferences ##
+##########################################################
+##
+##### General rules #####
+##
+## 1) Because each action has runtime checks whether it's
+## ok to run it, a few actions can be bound to one key.
+## Actions will be bound in order given in configuration
+## file. When a key is pressed, first action in order
+## will test itself whether it's possible to run it. If
+## test succeeds, action is executed and other actions
+## bound to this key are ignored. If it doesn't, next
+## action in order tests itself etc.
+##
+## 2) It's possible to bind more that one action at once
+## to a key. It can be done using the following syntax:
+##
+## def_key "key"
+## action1
+## action2
+## ...
+##
+## This creates chain of actions. When such chain is
+## executed, each action in chain is run until the end of
+## chain is reached or one of actions failed to execute
+## due to its requirements not being met. Note that
+## execution of chain of actions ALWAYS succeeds, no
+## matter if one of actions from the chain failed (even
+## if it was the first one in order and thus nothing
+## was really executed). Because of that, if you decide
+## to bind both actions and chains to a single key, make
+## sure that chain is defined in the end. Otherwise, all
+## actions bound to the key after chain will never be run.
+##
+## 3) When ncmpcpp starts, bindings configuration file is
+## parsed and then ncmpcpp provides "missing pieces"
+## of default keybindings. If you want to disable some
+## bindings, there is a special action called 'dummy'
+## for that purpose. Eg. if you want to disable ability
+## to crop playlists, you need to put the following
+## into configuration file:
+##
+## def_key "C"
+## dummy
+##
+## After that ncmpcpp will not bind any default action
+## to this key.
+##
+## 4) To let you write simple macros, the following special
+## actions are provided:
+##
+## - push_character "character" - pushes given special
+## character into input queue, so it will be immediately
+## picked by ncmpcpp upon next call to readKey function.
+## Accepted values: mouse, up, down, page_up, page_down,
+## home, end, space, enter, insert, delete, left, right,
+## tab, shift_tab, ctrl_a, ctrl_b, ..., ctrl_z, f1, f2,
+## ..., f12, backspace, backspace_2.
+##
+## - push_characters "string" - pushes given string into
+## input queue.
+##
+## - require_runnable "action" - checks whether given action
+## is runnable and fails if it isn't. This is especially
+## useful when mixed with previous two functions. Consider
+## the following macro definition:
+##
+## def_key "key"
+## push_characters "custom_filter"
+## apply_filter
+##
+## If apply_filter can't be currently run, we end up with
+## sequence of characters in input queue which will be
+## treated just as we typed them. This may lead to unexpected
+## results (in this case 'c' will most likely clear current
+## playlist, 'u' will trigger database update, 's' will stop
+## playback etc.). To prevent such thing from happening, we
+## need to change above definition to this one:
+##
+## def_key "key"
+## require_runnable "apply_filter"
+## push_characters "custom_filter"
+## apply_filter
+##
+## Here, first we test whether apply_filter can be actually run
+## before we stuff characters into input queue, so if condition
+## is not met, whole chain is aborted and we're fine.
+##
+## - require_screen "screen" - checks whether given screen is
+## currently active. accepted values: browser, clock, help,
+## media_library, outputs, playlist, playlist_editor,
+## search_engine, tag_editor, visualizer, last_fm, lyrics,
+## selected_items_adder, server_info, song_info,
+## sort_playlist_dialog, tiny_tag_editor.
+##
+## - run_external_command "command" - runs given command using
+## system() function.
+##
+## 5) In addition to binding to a key, you can also bind actions
+## or chains of actions to a command. If it comes to commands,
+## syntax is very similar to defining keys. Here goes example
+## definition of a command:
+##
+## def_command "quit" [deferred]
+## stop
+## quit
+##
+## If you execute the above command (which can be done by
+## invoking action execute_command, typing 'quit' and pressing
+## enter), ncmpcpp will stop the player and then quit. Note the
+## presence of word 'deferred' enclosed in square brackets. It
+## tells ncmpcpp to wait for confirmation (ie. pressing enter)
+## after you typed quit. Instead of 'deferred', 'immediate'
+## could be used. Then ncmpcpp will not wait for confirmation
+## (enter) and will execute the command the moment it sees it.
+##
+## Note: Both 'backspace' and 'backspace_2' are used because some
+## terminals interpret backspace using keycode of 'backspace'
+## and some the one of 'backspace_2'. You can get away with
+## binding once if all your terminal emulators use the same
+## value.
+##
+## Note: There is a difference between:
+##
+## def_key "key"
+## action1
+##
+## def_key "key"
+## action2
+##
+## and
+##
+## def_key "key"
+## action1
+## action2
+##
+## First one binds two single actions to the same key whilst
+## second one defines a chain of actions. The behavior of
+## these two is different and is described in (1) and (2).
+##
+## Note: Function def_key accepts non-ascii characters.
+##
+##### List of unbound actions #####
+##
+## The following actions are not bound to any key/command:
+##
+## - set_volume
+## - filter_playlist_on_priorities
+##
+#
+#def_key "mouse"
+# mouse_event
+#
+def_key "k"
+ scroll_up
+
+def_key "j"
+ scroll_down
+
+#def_key "["
+# scroll_up_album
+#
+#def_key "]"
+# scroll_down_album
+#
+#def_key "{"
+# scroll_up_artist
+#
+#def_key "}"
+# scroll_down_artist
+#
+#def_key "page_up"
+# page_up
+#
+#def_key "page_down"
+# page_down
+#
+#def_key "home"
+# move_home
+#
+#def_key "end"
+# move_end
+#
+#def_key "space"
+# press_space
+#
+#def_key "enter"
+# press_enter
+#
+#def_key "delete"
+# delete_playlist_items
+#
+#def_key "delete"
+# delete_stored_playlist
+#
+#def_key "right"
+# next_column
+#
+#def_key "right"
+# slave_screen
+#
+#def_key "right"
+# volume_up
+#
+#def_key "+"
+# volume_up
+#
+#def_key "left"
+# previous_column
+#
+#def_key "left"
+# master_screen
+#
+#def_key "left"
+# volume_down
+#
+#def_key "-"
+# volume_down
+#
+#def_key ":"
+# execute_command
+#
+#def_key "tab"
+# next_screen
+#
+#def_key "shift_tab"
+# previous_screen
+#
+#def_key "f1"
+# show_help
+#
+#def_key "1"
+# show_playlist
+#
+#def_key "2"
+# show_browser
+#
+#def_key "2"
+# change_browse_mode
+#
+#def_key "3"
+# show_search_engine
+#
+#def_key "3"
+# reset_search_engine
+#
+#def_key "4"
+# show_media_library
+#
+#def_key "4"
+# toggle_media_library_columns_mode
+#
+#def_key "5"
+# show_playlist_editor
+#
+#def_key "6"
+# show_tag_editor
+#
+#def_key "7"
+# show_outputs
+#
+#def_key "8"
+# show_visualizer
+#
+#def_key "="
+# show_clock
+#
+#def_key "@"
+# show_server_info
+#
+#def_key "s"
+# stop
+#
+#def_key "p"
+# pause
+#
+#def_key ">"
+# next
+#
+#def_key "<"
+# previous
+#
+#def_key "ctrl_h"
+# jump_to_parent_directory
+#
+#def_key "ctrl_h"
+# replay_song
+#
+#def_key "backspace"
+# jump_to_parent_directory
+#
+#def_key "backspace"
+# replay_song
+#
+#def_key "backspace_2"
+# jump_to_parent_directory
+#
+#def_key "backspace_2"
+# replay_song
+#
+#def_key "f"
+# seek_forward
+#
+#def_key "b"
+# seek_backward
+#
+#def_key "r"
+# toggle_repeat
+#
+#def_key "z"
+# toggle_random
+#
+#def_key "y"
+# save_tag_changes
+#
+#def_key "y"
+# start_searching
+#
+#def_key "y"
+# toggle_single
+#
+#def_key "R"
+# toggle_consume
+#
+#def_key "Y"
+# toggle_replay_gain_mode
+#
+#def_key "t"
+# toggle_space_mode
+#
+#def_key "T"
+# toggle_add_mode
+#
+#def_key "|"
+# toggle_mouse
+#
+#def_key "#"
+# toggle_bitrate_visibility
+#
+#def_key "Z"
+# shuffle
+#
+#def_key "x"
+# toggle_crossfade
+#
+#def_key "X"
+# set_crossfade
+#
+#def_key "u"
+# update_database
+#
+#def_key "ctrl_v"
+# sort_playlist
+#
+#def_key "ctrl_r"
+# reverse_playlist
+#
+#def_key "ctrl_f"
+# apply_filter
+#
+#def_key "/"
+# find
+#
+#def_key "/"
+# find_item_forward
+#
+#def_key "?"
+# find
+#
+#def_key "?"
+# find_item_backward
+#
+#def_key "."
+# next_found_item
+#
+#def_key ","
+# previous_found_item
+#
+#def_key "w"
+# toggle_find_mode
+#
+#def_key "e"
+# edit_song
+#
+#def_key "e"
+# edit_library_tag
+#
+#def_key "e"
+# edit_library_album
+#
+#def_key "e"
+# edit_directory_name
+#
+#def_key "e"
+# edit_playlist_name
+#
+#def_key "e"
+# edit_lyrics
+#
+#def_key "i"
+# show_song_info
+#
+#def_key "I"
+# show_artist_info
+#
+#def_key "g"
+# jump_to_position_in_song
+#
+#def_key "l"
+# show_lyrics
+#
+#def_key "v"
+# reverse_selection
+#
+#def_key "V"
+# remove_selection
+#
+#def_key "B"
+# select_album
+#
+#def_key "a"
+# add_selected_items
+#
+#def_key "c"
+# clear_playlist
+#
+#def_key "c"
+# clear_main_playlist
+#
+#def_key "C"
+# crop_playlist
+#
+#def_key "C"
+# crop_main_playlist
+#
+#def_key "m"
+# move_sort_order_up
+#
+#def_key "m"
+# move_selected_items_up
+#
+#def_key "m"
+# toggle_media_library_sort_mode
+#
+#def_key "n"
+# move_sort_order_down
+#
+#def_key "n"
+# move_selected_items_down
+#
+#def_key "M"
+# move_selected_items_to
+#
+#def_key "A"
+# add
+#
+#def_key "S"
+# save_playlist
+#
+#def_key "o"
+# jump_to_playing_song
+#
+#def_key "G"
+# jump_to_browser
+#
+#def_key "G"
+# jump_to_playlist_editor
+#
+#def_key "~"
+# jump_to_media_library
+#
+#def_key "E"
+# jump_to_tag_editor
+#
+#def_key "U"
+# toggle_playing_song_centering
+#
+#def_key "P"
+# toggle_display_mode
+#
+#def_key "\\"
+# toggle_interface
+#
+#def_key "!"
+# toggle_separators_between_albums
+#
+#def_key "L"
+# toggle_lyrics_fetcher
+#
+#def_key "F"
+# toggle_fetching_lyrics_in_background
+#
+#def_key "ctrl_l"
+# toggle_screen_lock
+#
+#def_key "`"
+# toggle_browser_sort_mode
+#
+#def_key "`"
+# toggle_library_tag_type
+#
+#def_key "`"
+# refetch_lyrics
+#
+#def_key "`"
+# add_random_items
+#
+#def_key "ctrl_p"
+# set_selected_items_priority
+#
+#def_key "q"
+# quit
+#
diff --git a/ncmpcpp/config b/ncmpcpp/config
new file mode 100644
index 0000000..1e91f3c
--- /dev/null
+++ b/ncmpcpp/config
@@ -0,0 +1,277 @@
+ncmpcpp_directory = "~/.config/ncmpcpp"
+lyrics_directory = "~/.config/mpd/lyrics"
+mpd_host = "127.0.0.1"
+mpd_port = "6600"
+mpd_music_dir = "/media/music"
+#mpd_connection_timeout = "5"
+#mpd_crossfade_time = "5"
+
+# Vis
+visualizer_in_stereo = "yes"
+visualizer_fifo_path = "/run/user/1000/mpd.fifo"
+visualizer_output_name = "mpd_vis_fifo"
+visualizer_sync_interval = "30"
+visualizer_type = "spectrum" # (spectrum/wave)
+visualizer_look = "◆│"
+
+message_delay_time = "5"
+
+##### song format #####
+## %l - length
+## %f - filename
+## %D - directory
+## %a - artist
+## %A - album artist
+## %t - title
+## %b - album
+## %y - year
+## %n - track number (01/12 -> 01)
+## %N - full track info (01/12 -> 01/12)
+## %g - genre
+## %c - composer
+## %p - performer
+## %d - disc
+## %C - comment
+## $R - begin right alignment
+## you can also put them in { } and then it will be displayed
+## only if all requested values are available and/or define alternate
+## value with { }|{ } eg. {%a - %t}|{%f}
+## eg. if you want length to be green, write $3%l$9
+## - 0 - default window color (discards all other colors)
+## - 1 - black
+## - 2 - red
+## - 3 - green
+## - 4 - yellow
+## - 5 - blue
+## - 6 - magenta
+## - 7 - cyan
+## - 8 - white
+## - 9 - end of current color
+
+#song_list_format = "{%a - }{%t}|{$8%f$9}$R{$3(%l)$9}"
+#
+#song_status_format = "{{%a{ \"%b\"{ (%y)}} - }{%t}}|{%f}"
+#
+#song_library_format = "{%n - }{%t}|{%f}"
+
+## Note: Below variables are for alternative version of user's interface.
+## Their syntax supports all tags and colors listed above plus some extra
+## markers used for text attributes. They are followed by character '$'.
+## After that you can put:
+##
+## - b - bold text
+## - u - underline text
+## - r - reverse colors
+## - a - use alternative character set
+##
+## If you don't want to use an attribute anymore, just put it again, but
+## this time insert character '/' between '$' and attribute character,
+## e.g. {$b%t$/b}|{$r%f$/r} will display bolded title tag or filename
+## with reversed colors.
+##
+#alternative_header_first_line_format = "$b$1$aqqu$/a$9 {%t}|{%f} $1$atqq$/a$9$/b"
+alternative_header_second_line_format = "{{$4$b%a$/b$9}{ - $7%b$9}}"
+now_playing_prefix = "$b"
+now_playing_suffix = "$/b"
+#browser_playlist_prefix = "$2playlist$9 "
+#selected_item_prefix = "$6"
+#selected_item_suffix = "$9"
+
+song_window_title_format = "MPD: {%a > }{%t}{ [%b]}|{%f}"
+#
+##### columns settings #####
+##
+## syntax of song columns list format is "column column etc."
+##
+## - syntax for each column is:
+##
+## (width of column)[column's color]{displayed tag}
+##
+## Note: Width is by default in %, if you want a column to
+## have fixed size, add 'f' after the value, e.g. (10)[white]{a}
+## will be the column that take 10% of screen (so the real column's
+## width will depend on actual screen size), whereas (10f)[white]{a}
+## will take 10 terminal cells, no matter how wide the screen is.
+##
+## - color is optional (if you want the default one, type [])
+##
+## Note: You can give a column additional attributes by putting appropriate
+## character after displayed tag character. Available attributes are:
+##
+## - r - column will be right aligned
+## - E - if tag is empty, empty tag marker won't be displayed
+##
+## You can also:
+##
+## - give a column custom name by putting it after attributes,
+## separated with character ':', e.g. {lr:Length} gives you
+## right aligned column of lengths named "Length".
+##
+## - define sequence of tags, that have to be displayed in case
+## predecessor is empty in a way similar to the one in classic
+## song format, i.e. using '|' character, e.g. {a|c|p:Owner}
+## creates column named "Owner" that tries to display artist
+## tag and then composer and performer if previous ones are
+## not available.
+##
+#
+#song_columns_list_format = "(7f)[green]{l} (25)[cyan]{a} (40)[]{t|f} (30)[red]{b}"
+song_columns_list_format = "(7f)[blue]{l} (20)[cyan]{a} (30)[blue]{b} (50)[cyan]{t}"
+#
+##### various settings #####
+#
+##
+## Note: Custom command that will be executed each
+## time song changes. Useful for notifications etc.
+##
+## Attention: It doesn't support song format anymore.
+## Use `ncmpcpp --now-playing SONG_FORMAT` instead.
+##
+#execute_on_song_change = ""
+#
+#playlist_show_remaining_time = "no"
+#
+#playlist_shorten_total_times = "no"
+#
+#playlist_separate_albums = "no"
+#
+#playlist_display_mode = "classic" (classic/columns)
+playlist_display_mode = "columns"
+#
+#browser_display_mode = "classic" (classic/columns)
+browser_display_mode = "columns"
+#
+#search_engine_display_mode = "classic" (classic/columns)
+#
+#playlist_editor_display_mode = "classic" (classic/columns)
+#
+#discard_colors_if_item_is_selected = "yes"
+#
+#incremental_seeking = "yes"
+#
+#seek_time = "1"
+#
+#autocenter_mode = "no"
+#
+#centered_cursor = "no"
+#
+##
+## Note: You can specify third character which will
+## be used to build 'empty' part of progressbar.
+##
+progressbar_look = "─╼╶"
+#progressbar_look = "━━╸"
+#progressbar_look = "=>"
+#
+#default_place_to_search_in = "database" (database/playlist)
+#
+user_interface = "alternative" # (classic/alternative)
+#
+media_library_left_column = "A" # (possible values: a,y,g,c,p, legend above)
+#
+#default_find_mode = "wrapped" (wrapped/normal)
+#
+#default_space_mode = "add" (add/select)
+#
+#default_tag_editor_left_col = "albums" (albums/dirs)
+#
+#default_tag_editor_pattern = "%n - %t"
+#
+#header_visibility = "yes"
+#
+#statusbar_visibility = "yes"
+#
+#titles_visibility = "yes"
+#
+#header_text_scrolling = "yes"
+#
+#fancy_scrolling = "yes"
+#
+#cyclic_scrolling = "no"
+#
+#lines_scrolled = "2"
+#
+#follow_now_playing_lyrics = "no"
+#
+#fetch_lyrics_for_current_song_in_background = "no"
+#
+#store_lyrics_in_song_dir = "no"
+#
+##
+## Note: If you set this variable, ncmpcpp will try to
+## get info from last.fm in language you set and if it
+## fails, it will fall back to english. Otherwise it will
+## use english the first time.
+##
+## Note: Language has to be expressed as an ISO 639 alpha-2 code.
+##
+#lastfm_preferred_language = ""
+#
+#ncmpc_like_songs_adding = "no" (enabled - add/remove, disabled - always add)
+#
+#show_hidden_files_in_local_browser = "no"
+#
+#display_screens_numbers_on_start = "yes"
+#
+##
+## How shall key_screen_switcher work?
+##
+## - "previous" - switch between current and last used screen
+## - "sequence: 2 -> 9 -> 5" - switch between given sequence of screens.
+##
+## Screen numbers you can use after 'sequence' keyword are:
+##
+## - 1 - help
+## - 2 - playlist
+## - 3 - browser
+## - 4 - search engine
+## - 5 - media library
+## - 6 - playlist editor
+## - 7 - tag editor
+## - 8 - outputs
+## - 9 - visualizer
+## - 10 - clock
+##
+## As you can see, above example will switch between
+## playlist, visualizer and media library screens.
+##
+#screen_switcher_mode = "sequence: 2 -> 3"
+#
+##
+## Default width of locked screen (in %).
+## Acceptable values are from 20 to 80.
+##
+#
+locked_screen_width_part = "50"
+ask_for_locked_screen_width_part = "yes"
+startup_screen = "2"
+jump_to_now_playing_song_at_start = "yes"
+ask_before_clearing_main_playlist = "yes"
+clock_display_seconds = "yes"
+# display_volume_level = "yes"
+display_bitrate = "yes"
+display_remaining_time = "no"
+regular_expressions = "extended" # (basic/extended)
+
+#block_search_constraints_change_if_items_found = "yes"
+mouse_support = "yes"
+mouse_list_scroll_whole_page = "yes"
+empty_tag_marker = "<empty>"
+enable_window_title = "yes"
+search_engine_default_search_mode = "2"
+
+##### colors definitions #####
+colors_enabled = "yes"
+header_window_color = "blue"
+volume_color = "cyan"
+state_line_color = "white"
+state_flags_color = "white"
+main_window_color = "blue"
+color1 = "blue"
+color2 = "cyan"
+main_window_highlight_color = "green"
+progressbar_color = "cyan"
+statusbar_color = "cyan"
+alternative_ui_separator_color = "blue"
+active_column_color = "cyan"
+visualizer_color = "cyan"
diff --git a/termite/config b/termite/config
new file mode 100644
index 0000000..c3cd354
--- /dev/null
+++ b/termite/config
@@ -0,0 +1,66 @@
+[options]
+resize_grip = false
+scroll_on_output = false
+scroll_on_keystroke = true
+audible_bell = false
+visible_bell = true
+mouse_autohide = false
+allow_bold = true
+dynamic_title = true
+urgent_on_bell = true
+clickable_url = false
+font = Source Code Pro Earnest 9
+scrollback_lines = 1000
+search_wrap = true
+icon_name = terminal
+geometry = 618x306
+
+# "system", "on" or "off"
+cursor_blink = off
+
+# "block", "underline" or "ibeam"
+cursor_shape = block
+
+# word characters used for word selection
+# (default if unset: all graphic non-punctuation/space characters)
+#word_chars = -A-Za-z0-9,./?%&#:_=+@~
+
+[colors]
+foreground = #dcdccc
+foreground_bold = #ffffff
+#foreground_dim = #888888
+#background = #3f3f3f
+background = #303030
+#cursor = #dcdccc
+
+# if unset, will reverse foreground and background
+highlight = #252525
+
+# colors from color0 to color254 can be set
+color0 = #3f3f3f
+color1 = #906060
+color2 = #60b48a
+color3 = #dfaf8f
+color4 = #607080
+color5 = #dc8cc3
+color6 = #8cd0d3
+color7 = #dcdccc
+color8 = #709080
+color9 = #dca3a3
+color10 = #c3bf9f
+color11 = #f0dfaf
+color12 = #94bff3
+color13 = #ec93d3
+color14 = #93e0e3
+color15 = #ffffff
+
+[hints]
+#font = Monospace 9
+#foreground = #dcdccc
+#background = #3f3f3f
+#padding = 2
+#border = #3f3f3f
+#border_width = 0.5
+#roundness = 2.0
+
+# vim: ft=dosini
diff --git a/vim/after/syntax/c.vim b/vim/after/syntax/c.vim
new file mode 100644
index 0000000..0f796e3
--- /dev/null
+++ b/vim/after/syntax/c.vim
@@ -0,0 +1,13 @@
+" Highlight Class and Function names
+syn match cCustomParen "(" contains=cParen
+syn match cCustomFunc "\w\+\s*(" contains=cCustomParen
+
+hi def link cCustomFunc Function
+hi def cCustomFunc gui=bold guifg=yellowgreen
+
+highlight ExtraWhitespace ctermbg=red guibg=red
+match ExtraWhitespace /\s\+$/
+autocmd BufWinEnter * match ExtraWhitespace /\s\+$/
+autocmd InsertEnter * match ExtraWhitespace /\s\+\%#\@<!$/
+autocmd InsertLeave * match ExtraWhitespace /\s\+$/
+autocmd BufWinLeave * call clearmatches()
diff --git a/vim/bundle/neobundle.vim b/vim/bundle/neobundle.vim
new file mode 160000
+Subproject e967ed9522c52d4708e3d9d3d81902ee0aa59b7
diff --git a/vim/colors/Darkcustomside.vim b/vim/colors/Darkcustomside.vim
new file mode 100644
index 0000000..e62c6e6
--- /dev/null
+++ b/vim/colors/Darkcustomside.vim
@@ -0,0 +1,103 @@
+" Vim color file
+" Converted from Textmate theme Darkside using Coloration v0.3.2 (http://github.com/sickill/coloration)
+
+set background=dark
+highlight clear
+
+if exists("syntax_on")
+ syntax reset
+endif
+
+let g:colors_name = "Darkcustomside"
+
+hi Cursor ctermfg=NONE ctermbg=231 cterm=NONE guifg=NONE guibg=#f8f8f0 gui=NONE
+hi Visual ctermfg=NONE ctermbg=16 cterm=NONE guifg=NONE guibg=#161a1f gui=NONE
+hi CursorLine ctermfg=NONE ctermbg=236 cterm=NONE guifg=NONE guibg=#313233 gui=NONE
+hi CursorColumn ctermfg=NONE ctermbg=236 cterm=NONE guifg=NONE guibg=#313233 gui=NONE
+hi ColorColumn ctermfg=NONE ctermbg=236 cterm=NONE guifg=NONE guibg=#313233 gui=NONE
+hi LineNr ctermfg=242 ctermbg=236 cterm=NONE guifg=#6e6f6f guibg=#313233 gui=NONE
+hi VertSplit ctermfg=239 ctermbg=239 cterm=NONE guifg=#4e4f50 guibg=#4e4f50 gui=NONE
+hi MatchParen ctermfg=208 ctermbg=NONE cterm=NONE guifg=#f08d24 guibg=NONE gui=NONE
+hi StatusLine ctermfg=250 ctermbg=239 cterm=bold guifg=#bababa guibg=#4e4f50 gui=bold
+hi StatusLineNC ctermfg=250 ctermbg=239 cterm=NONE guifg=#bababa guibg=#4e4f50 gui=NONE
+hi Pmenu ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE
+hi PmenuSel ctermfg=NONE ctermbg=16 cterm=NONE guifg=NONE guibg=#161a1f gui=NONE
+hi IncSearch ctermfg=NONE ctermbg=58 cterm=NONE guifg=NONE guibg=#664624 gui=NONE
+hi Search ctermfg=NONE ctermbg=58 cterm=NONE guifg=NONE guibg=#664624 gui=NONE
+hi Directory ctermfg=98 ctermbg=NONE cterm=NONE guifg=#8e69c9 guibg=NONE gui=NONE
+hi Folded ctermfg=59 ctermbg=235 cterm=NONE guifg=#494b4d guibg=#222324 gui=NONE
+
+hi Normal ctermfg=250 ctermbg=236cterm=NONE guifg=#bababa guibg=#303030 gui=NONE
+hi Boolean ctermfg=98 ctermbg=NONE cterm=NONE guifg=#8e69c9 guibg=NONE gui=NONE
+hi Character ctermfg=98 ctermbg=NONE cterm=NONE guifg=#8e69c9 guibg=NONE gui=NONE
+hi Comment ctermfg=59 ctermbg=NONE cterm=NONE guifg=#494b4d guibg=NONE gui=NONE
+hi Conditional ctermfg=208 ctermbg=NONE cterm=NONE guifg=#f08d24 guibg=NONE gui=NONE
+hi Constant ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE
+hi Define ctermfg=208 ctermbg=NONE cterm=NONE guifg=#f08d24 guibg=NONE gui=NONE
+hi ErrorMsg ctermfg=231 ctermbg=38 cterm=NONE guifg=#f8f8f0 guibg=#00a8c6 gui=NONE
+hi WarningMsg ctermfg=231 ctermbg=38 cterm=NONE guifg=#f8f8f0 guibg=#00a8c6 gui=NONE
+hi Float ctermfg=98 ctermbg=NONE cterm=NONE guifg=#8e69c9 guibg=NONE gui=NONE
+hi Function ctermfg=71 ctermbg=NONE cterm=NONE guifg=#68c244 guibg=NONE gui=NONE
+hi Identifier ctermfg=38 ctermbg=NONE cterm=NONE guifg=#1cc3e8 guibg=NONE gui=italic
+hi Keyword ctermfg=208 ctermbg=NONE cterm=NONE guifg=#f08d24 guibg=NONE gui=NONE
+hi Label ctermfg=220 ctermbg=NONE cterm=NONE guifg=#f2d42c guibg=NONE gui=NONE
+hi NonText ctermfg=59 ctermbg=235 cterm=NONE guifg=#3b3a32 guibg=#2a2b2c gui=NONE
+hi Number ctermfg=98 ctermbg=NONE cterm=NONE guifg=#8e69c9 guibg=NONE gui=NONE
+hi Operator ctermfg=208 ctermbg=NONE cterm=NONE guifg=#f08d24 guibg=NONE gui=NONE
+hi PreProc ctermfg=208 ctermbg=NONE cterm=NONE guifg=#f08d24 guibg=NONE gui=NONE
+hi Special ctermfg=250 ctermbg=NONE cterm=NONE guifg=#bababa guibg=NONE gui=NONE
+hi SpecialKey ctermfg=59 ctermbg=236 cterm=NONE guifg=#3b3a32 guibg=#313233 gui=NONE
+hi Statement ctermfg=208 ctermbg=NONE cterm=NONE guifg=#f08d24 guibg=NONE gui=NONE
+hi StorageClass ctermfg=38 ctermbg=NONE cterm=NONE guifg=#1cc3e8 guibg=NONE gui=italic
+hi String ctermfg=220 ctermbg=NONE cterm=NONE guifg=#f2d42c guibg=NONE gui=NONE
+hi Tag ctermfg=166 ctermbg=NONE cterm=NONE guifg=#e8341c guibg=NONE gui=NONE
+hi Title ctermfg=250 ctermbg=NONE cterm=bold guifg=#bababa guibg=NONE gui=bold
+hi Todo ctermfg=59 ctermbg=NONE cterm=inverse,bold guifg=#494b4d guibg=NONE gui=inverse,bold
+hi Type ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE
+hi Underlined ctermfg=NONE ctermbg=NONE cterm=underline guifg=NONE guibg=NONE gui=underline
+hi rubyClass ctermfg=208 ctermbg=NONE cterm=NONE guifg=#f08d24 guibg=NONE gui=NONE
+hi rubyFunction ctermfg=71 ctermbg=NONE cterm=NONE guifg=#68c244 guibg=NONE gui=NONE
+hi rubyInterpolationDelimiter ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE
+hi rubySymbol ctermfg=98 ctermbg=NONE cterm=NONE guifg=#8e69c9 guibg=NONE gui=NONE
+hi rubyConstant ctermfg=98 ctermbg=NONE cterm=NONE guifg=#8e69c9 guibg=NONE gui=italic
+hi rubyStringDelimiter ctermfg=220 ctermbg=NONE cterm=NONE guifg=#f2d42c guibg=NONE gui=NONE
+hi rubyBlockParameter ctermfg=98 ctermbg=NONE cterm=NONE guifg=#8e69c9 guibg=NONE gui=italic
+hi rubyInstanceVariable ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE
+hi rubyInclude ctermfg=208 ctermbg=NONE cterm=NONE guifg=#f08d24 guibg=NONE gui=NONE
+hi rubyGlobalVariable ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE
+hi rubyRegexp ctermfg=220 ctermbg=NONE cterm=NONE guifg=#f2d42c guibg=NONE gui=NONE
+hi rubyRegexpDelimiter ctermfg=220 ctermbg=NONE cterm=NONE guifg=#f2d42c guibg=NONE gui=NONE
+hi rubyEscape ctermfg=98 ctermbg=NONE cterm=NONE guifg=#8e69c9 guibg=NONE gui=NONE
+hi rubyControl ctermfg=208 ctermbg=NONE cterm=NONE guifg=#f08d24 guibg=NONE gui=NONE
+hi rubyClassVariable ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE
+hi rubyOperator ctermfg=208 ctermbg=NONE cterm=NONE guifg=#f08d24 guibg=NONE gui=NONE
+hi rubyException ctermfg=208 ctermbg=NONE cterm=NONE guifg=#f08d24 guibg=NONE gui=NONE
+hi rubyPseudoVariable ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE
+hi rubyRailsUserClass ctermfg=98 ctermbg=NONE cterm=NONE guifg=#8e69c9 guibg=NONE gui=italic
+hi rubyRailsARAssociationMethod ctermfg=98 ctermbg=NONE cterm=NONE guifg=#8e69c9 guibg=NONE gui=NONE
+hi rubyRailsARMethod ctermfg=98 ctermbg=NONE cterm=NONE guifg=#8e69c9 guibg=NONE gui=NONE
+hi rubyRailsRenderMethod ctermfg=98 ctermbg=NONE cterm=NONE guifg=#8e69c9 guibg=NONE gui=NONE
+hi rubyRailsMethod ctermfg=98 ctermbg=NONE cterm=NONE guifg=#8e69c9 guibg=NONE gui=NONE
+hi erubyDelimiter ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE
+hi erubyComment ctermfg=59 ctermbg=NONE cterm=NONE guifg=#494b4d guibg=NONE gui=NONE
+hi erubyRailsMethod ctermfg=98 ctermbg=NONE cterm=NONE guifg=#8e69c9 guibg=NONE gui=NONE
+hi htmlTag ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE
+hi htmlEndTag ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE
+hi htmlTagName ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE
+hi htmlArg ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE
+hi htmlSpecialChar ctermfg=98 ctermbg=NONE cterm=NONE guifg=#8e69c9 guibg=NONE gui=NONE
+hi javaScriptFunction ctermfg=38 ctermbg=NONE cterm=NONE guifg=#1cc3e8 guibg=NONE gui=italic
+hi javaScriptRailsFunction ctermfg=98 ctermbg=NONE cterm=NONE guifg=#8e69c9 guibg=NONE gui=NONE
+hi javaScriptBraces ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE
+hi yamlKey ctermfg=166 ctermbg=NONE cterm=NONE guifg=#e8341c guibg=NONE gui=NONE
+hi yamlAnchor ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE
+hi yamlAlias ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE
+hi yamlDocumentHeader ctermfg=220 ctermbg=NONE cterm=NONE guifg=#f2d42c guibg=NONE gui=NONE
+hi cssURL ctermfg=98 ctermbg=NONE cterm=NONE guifg=#8e69c9 guibg=NONE gui=italic
+hi cssFunctionName ctermfg=98 ctermbg=NONE cterm=NONE guifg=#8e69c9 guibg=NONE gui=NONE
+hi cssColor ctermfg=98 ctermbg=NONE cterm=NONE guifg=#8e69c9 guibg=NONE gui=NONE
+hi cssPseudoClassId ctermfg=71 ctermbg=NONE cterm=NONE guifg=#68c244 guibg=NONE gui=NONE
+hi cssClassName ctermfg=71 ctermbg=NONE cterm=NONE guifg=#68c244 guibg=NONE gui=NONE
+hi cssValueLength ctermfg=98 ctermbg=NONE cterm=NONE guifg=#8e69c9 guibg=NONE gui=NONE
+hi cssCommonAttr ctermfg=98 ctermbg=NONE cterm=NONE guifg=#8e69c9 guibg=NONE gui=NONE
+hi cssBraces ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE
diff --git a/vim/filetype.vim b/vim/filetype.vim
new file mode 100644
index 0000000..357aa24
--- /dev/null
+++ b/vim/filetype.vim
@@ -0,0 +1,4 @@
+augroup filetypedetect
+ " Mail
+ autocmd BufRead,BufNewFile *mutt-* setfiletype mail
+augroup END
diff --git a/vim/ftplugin/mail.vim b/vim/ftplugin/mail.vim
new file mode 100644
index 0000000..7b38173
--- /dev/null
+++ b/vim/ftplugin/mail.vim
@@ -0,0 +1,2 @@
+set tw=78
+set fo+=aw
diff --git a/vim/vimrc b/vim/vimrc
new file mode 100644
index 0000000..b6c4397
--- /dev/null
+++ b/vim/vimrc
@@ -0,0 +1,70 @@
+set nocompatible " be iMproved
+
+" Respect XDG
+set directory=$XDG_CACHE_HOME/vim,~/,/tmp
+set backupdir=$XDG_CACHE_HOME/vim,~/,/tmp
+set viminfo+=n$XDG_CACHE_HOME/vim/viminfo
+set runtimepath=$XDG_CONFIG_HOME/vim,$XDG_CONFIG_HOME/vim/after,$VIM,$VIMRUNTIME,/usr/share/vim/vimfiles
+let $MYVIMRC="$XDG_CONFIG_HOME/vim/vimrc"
+
+" Make backspace behave in a sane manner.
+set backspace=indent,eol,start
+
+" NeoBndle stuff
+set runtimepath+=~/.config/vim/bundle/neobundle.vim/
+call neobundle#rc('/home/kyrias/.config/vim/bundle')
+NeoBundleFetch 'Shougo/neobundle.vim'
+
+NeoBundle 'Shougo/vimproc', {
+ \ 'build' : {
+ \ 'unix' : 'make -f make_unix.mak',
+ \ },
+ \ }
+NeoBundle 'Shougo/unite.vim'
+
+" Colorscheme❤
+NeoBundle "daylerees/colour-schemes", { "rtp": "vim-themes/" }
+colorscheme Darkcustomside
+
+" Smart Tabs (http://www.emacswiki.org/emacs/SmartTabs)
+NeoBundle 'gustavo-hms/vim-smart-tabs'
+
+" Switch syntax highlighting on
+syntax on
+" Enable file type detection and do language-dependent indenting.
+filetype plugin indent on
+
+" Tabs are 4 spaces wide
+set tabstop=8
+set softtabstop=8
+set shiftwidth=9
+set noexpandtab
+
+" Make the cursor be on the left side in normal mode if line starts with tab
+set list lcs=tab:\ \
+" Note the extra space after the second \
+
+" Append modeline after last line in buffer.
+function! AppendModeline()
+ let l:modeline = printf(" vim: set ts=%d sw=%d %set:",
+ \ &tabstop, &shiftwidth, &expandtab ? '' : 'no')
+ let l:modeline = substitute(&commentstring, "%s", l:modeline, "")
+ call append(line("$"), l:modeline)
+endfunction
+nnoremap <silent> <Leader>ml Go<ESC>``:call AppendModeline()<CR>
+
+" Paste mode when pressing Insert, disables autoformating
+set pastetoggle=<Insert>
+
+" Installation check.
+NeoBundleCheck
+
+set listchars=tab:»·,trail:·
+set list
+
+highlight ExtraWhitespace ctermbg=red guibg=red
+match ExtraWhitespace /\s\+$/
+autocmd BufWinEnter * match ExtraWhitespace /\s\+$/
+autocmd InsertEnter * match ExtraWhitespace /\s\+\%#\@<!$/
+autocmd InsertLeave * match ExtraWhitespace /\s\+$/
+autocmd BufWinLeave * call clearmatches()
diff --git a/weechat/alias.conf b/weechat/alias.conf
new file mode 100644
index 0000000..f0673be
--- /dev/null
+++ b/weechat/alias.conf
@@ -0,0 +1,45 @@
+#
+# alias.conf -- weechat v0.4.3-dev
+#
+
+[cmd]
+AAWAY = "allserv /away"
+alot = "/input insert http://hyperboleandahalf.blogspot.com/2010/04/alot-is-better-than-you-at-everything.html"
+AME = "allchan /me"
+AMSG = "allchan /msg *"
+ANICK = "allserv /nick"
+bro = "/input insert ლ(°◡°ლ)"
+BYE = "quit"
+C = "buffer clear"
+CHAT = "dcc chat"
+CL = "buffer clear"
+CLOSE = "buffer close"
+EXIT = "quit"
+ig = "filter add ignore_$1 *.$server.* nick_$1 *"
+irc-analogy = "/input insert an IRC server is like a shopping mall. It provides space for various shops. While the mall owner (read: the server's staff) might control some of the shops (read: channels), most of them are 'owned' (registered) by individual parties (channel founders). Each of the shops (channels) usually have their own subject/topic of conversation and their own rules and guidelines. All of the shops (channels) can be reached via the main entrance (any IRC client connected to the server's address), but some of them might have their own entrance (an IRC applet/client on their own website). So, the fact that you have connected through website X about subject Y, doesn't mean all other channels belong to the same website / share the same topic of conversation."
+J = "join"
+K = "kick"
+KB = "kickban"
+konamicode = "/input insert ↑ ↑ ↓ ↓ ← → ← → B A"
+LEAVE = "part"
+lookaround = "/input insert /me looks around ('-' ) (._. ) (o_o) ( ._.) ( '-')"
+M = "msg"
+MUB = "unban *"
+N = "names"
+Q = "query"
+qt = "disconnect -all ;quit"
+REDRAW = "window refresh"
+SAY = "msg *"
+SIGNOFF = "quit"
+T = "topic"
+UB = "unban"
+UMODE = "mode $nick"
+unig = "filter del ignore_$1"
+V = "command core version"
+W = "who"
+WC = "window merge"
+WI = "whois"
+WII = "whois $1 $1"
+WW = "whowas"
+
+[completion]
diff --git a/weechat/aspell.conf b/weechat/aspell.conf
new file mode 100644
index 0000000..a07a4bc
--- /dev/null
+++ b/weechat/aspell.conf
@@ -0,0 +1,21 @@
+#
+# aspell.conf -- weechat v0.4.3-dev
+#
+
+[color]
+misspelled = lightred
+suggestions = default
+
+[check]
+commands = "ame,amsg,away,command,cycle,kick,kickban,me,msg,notice,part,query,quit,topic"
+default_dict = "en"
+during_search = off
+enabled = on
+real_time = on
+suggestions = 0
+word_min_length = 2
+
+[dict]
+core.weechat = "en"
+
+[option]
diff --git a/weechat/buffers.conf b/weechat/buffers.conf
new file mode 100644
index 0000000..0aa864d
--- /dev/null
+++ b/weechat/buffers.conf
@@ -0,0 +1,60 @@
+#
+# buffers.conf -- weechat v0.4.3-dev
+#
+
+[color]
+current_bg = blue
+current_fg = yellow
+default_bg = default
+default_fg = default
+hotlist_highlight_bg = red
+hotlist_highlight_fg = magenta
+hotlist_low_bg = default
+hotlist_low_fg = blue
+hotlist_message_bg = default
+hotlist_message_fg = lightblue
+hotlist_private_bg = red
+hotlist_private_fg = magenta
+none_channel_bg = default
+none_channel_fg = default
+number = lightgreen
+number_char = lightgreen
+queries_default_bg = default
+queries_default_fg = default
+queries_highlight_bg = red
+queries_highlight_fg = magenta
+queries_message_bg = red
+queries_message_fg = magenta
+whitelist_default_bg = default
+whitelist_default_fg = default
+whitelist_highlight_bg = red
+whitelist_highlight_fg = magenta
+whitelist_low_bg = default
+whitelist_low_fg = blue
+whitelist_message_bg = red
+whitelist_message_fg = magenta
+whitelist_private_bg = red
+whitelist_private_fg = magenta
+
+[look]
+core_to_front = on
+detach = 0
+detach_free_content = off
+detach_query = off
+hide_merged_buffers = server
+hotlist_counter = off
+immune_detach_buffers = ""
+indenting = on
+indenting_number = on
+jump_prev_next_visited_buffer = off
+mark_inactive = on
+name_crop_suffix = "×"
+name_size_max = 0
+number_char = "."
+prefix = off
+prefix_empty = on
+short_names = on
+show_lag = off
+show_number = on
+sort = number
+whitelist_buffers = ""
diff --git a/weechat/charset.conf b/weechat/charset.conf
new file mode 100644
index 0000000..bf46f99
--- /dev/null
+++ b/weechat/charset.conf
@@ -0,0 +1,11 @@
+#
+# charset.conf -- weechat v0.4.3-dev
+#
+
+[default]
+decode = "iso-8859-1"
+encode = "UTF-8"
+
+[decode]
+
+[encode]
diff --git a/weechat/irc.conf b/weechat/irc.conf
new file mode 100644
index 0000000..25f2807
--- /dev/null
+++ b/weechat/irc.conf
@@ -0,0 +1,242 @@
+#
+# irc.conf -- weechat v0.4.3-dev
+#
+
+[look]
+buffer_switch_autojoin = off
+buffer_switch_join = on
+color_nicks_in_names = on
+color_nicks_in_nicklist = on
+color_nicks_in_server_messages = on
+color_pv_nick_like_channel = on
+ctcp_time_format = "%a, %d %b %Y %T %z"
+display_away = local
+display_ctcp_blocked = on
+display_ctcp_reply = on
+display_ctcp_unknown = on
+display_host_join = on
+display_host_join_local = on
+display_host_quit = on
+display_join_message = "329,332,333"
+display_old_topic = on
+display_pv_away_once = on
+display_pv_back = on
+highlight_channel = "$nick"
+highlight_pv = "$nick"
+highlight_server = "$nick"
+highlight_tags_restrict = "irc_privmsg,irc_notice"
+item_away_message = on
+item_channel_modes_hide_key = off
+item_display_server = buffer_plugin
+item_nick_modes = on
+item_nick_prefix = on
+msgbuffer_fallback = current
+new_channel_position = none
+new_pv_position = none
+nick_color_force = ""
+nick_color_hash = djb2
+nick_color_stop_chars = "_|["
+nick_completion_smart = speakers
+nick_mode = prefix
+nick_mode_empty = off
+nicks_hide_password = "nickserv"
+notice_as_pv = auto
+notice_welcome_redirect = on
+notice_welcome_tags = ""
+notify_tags_ison = "notify_message"
+notify_tags_whois = "notify_message"
+part_closes_buffer = off
+pv_buffer = independent
+pv_tags = "notify_private"
+raw_messages = 256
+server_buffer = merge_with_core
+smart_filter = on
+smart_filter_delay = 5
+smart_filter_join = on
+smart_filter_join_unmask = 30
+smart_filter_mode = "ovh"
+smart_filter_nick = on
+smart_filter_quit = on
+topic_strip_colors = off
+
+[color]
+input_nick = lightcyan
+item_away = yellow
+item_channel_modes = default
+item_lag_counting = default
+item_lag_finished = yellow
+message_join = green
+message_quit = lightred
+mirc_remap = "1,-1:darkgray"
+nick_prefixes = "q:lightred;a:lightcyan;o:lightgreen;h:lightmagenta;v:yellow;*:lightblue"
+notice = blue
+reason_quit = default
+topic_new = white
+topic_old = darkgray
+
+[network]
+alternate_nick = on
+autoreconnect_delay_growing = 2
+autoreconnect_delay_max = 1800
+ban_mask_default = "*!$user@$host"
+colors_receive = on
+colors_send = on
+lag_check = 15
+lag_max = 1800
+lag_min_show = 0
+lag_reconnect = 0
+lag_refresh_interval = 1
+notify_check_ison = 1
+notify_check_whois = 5
+send_unknown_commands = off
+whois_double_nick = on
+
+[msgbuffer]
+
+[ctcp]
+
+[ignore]
+
+[server_default]
+addresses = "theos.kyriasis.com/6697"
+anti_flood_prio_high = 2
+anti_flood_prio_low = 2
+autoconnect = off
+autojoin = ""
+autoreconnect = on
+autoreconnect_delay = 10
+autorejoin = off
+autorejoin_delay = 30
+away_check = 0
+away_check_max_nicks = 25
+capabilities = "znc.in/server-time-iso"
+command = ""
+command_delay = 0
+connection_timeout = 60
+default_msg_kick = ""
+default_msg_part = ""
+default_msg_quit = ""
+ipv6 = on
+local_hostname = ""
+nicks = "demize,remize,dem,kyrias"
+notify = ""
+password = ""
+proxy = ""
+realname = "Johannes Löthberg"
+sasl_mechanism = plain
+sasl_password = ""
+sasl_timeout = 15
+sasl_username = ""
+ssl = on
+ssl_cert = "%h/keys/demize.pem"
+ssl_dhkey_size = 2048
+ssl_priorities = "NORMAL"
+ssl_verify = on
+username = "dem"
+
+[server]
+Freenode.addresses
+Freenode.proxy
+Freenode.ipv6
+Freenode.ssl
+Freenode.ssl_cert
+Freenode.ssl_priorities
+Freenode.ssl_dhkey_size
+Freenode.ssl_verify
+Freenode.password = "kyrias/freenode:"
+Freenode.capabilities
+Freenode.sasl_mechanism
+Freenode.sasl_username
+Freenode.sasl_password
+Freenode.sasl_timeout
+Freenode.autoconnect = on
+Freenode.autoreconnect
+Freenode.autoreconnect_delay
+Freenode.nicks
+Freenode.username
+Freenode.realname
+Freenode.local_hostname
+Freenode.command
+Freenode.command_delay
+Freenode.autojoin
+Freenode.autorejoin
+Freenode.autorejoin_delay
+Freenode.connection_timeout
+Freenode.anti_flood_prio_high
+Freenode.anti_flood_prio_low
+Freenode.away_check
+Freenode.away_check_max_nicks
+Freenode.default_msg_kick
+Freenode.default_msg_part
+Freenode.default_msg_quit
+Freenode.notify
+Furnet.addresses
+Furnet.proxy
+Furnet.ipv6
+Furnet.ssl
+Furnet.ssl_cert
+Furnet.ssl_priorities
+Furnet.ssl_dhkey_size
+Furnet.ssl_verify
+Furnet.password = "kyrias/furnet:"
+Furnet.capabilities
+Furnet.sasl_mechanism
+Furnet.sasl_username
+Furnet.sasl_password
+Furnet.sasl_timeout
+Furnet.autoconnect = on
+Furnet.autoreconnect
+Furnet.autoreconnect_delay
+Furnet.nicks
+Furnet.username
+Furnet.realname
+Furnet.local_hostname
+Furnet.command
+Furnet.command_delay
+Furnet.autojoin
+Furnet.autorejoin
+Furnet.autorejoin_delay
+Furnet.connection_timeout
+Furnet.anti_flood_prio_high
+Furnet.anti_flood_prio_low
+Furnet.away_check
+Furnet.away_check_max_nicks
+Furnet.default_msg_kick
+Furnet.default_msg_part
+Furnet.default_msg_quit
+Furnet.notify
+Foonetic.addresses
+Foonetic.proxy
+Foonetic.ipv6
+Foonetic.ssl
+Foonetic.ssl_cert
+Foonetic.ssl_priorities
+Foonetic.ssl_dhkey_size
+Foonetic.ssl_verify
+Foonetic.password = "kyrias/foonetic:"
+Foonetic.capabilities
+Foonetic.sasl_mechanism
+Foonetic.sasl_username
+Foonetic.sasl_password
+Foonetic.sasl_timeout
+Foonetic.autoconnect = on
+Foonetic.autoreconnect
+Foonetic.autoreconnect_delay
+Foonetic.nicks
+Foonetic.username
+Foonetic.realname
+Foonetic.local_hostname
+Foonetic.command
+Foonetic.command_delay
+Foonetic.autojoin
+Foonetic.autorejoin
+Foonetic.autorejoin_delay
+Foonetic.connection_timeout
+Foonetic.anti_flood_prio_high
+Foonetic.anti_flood_prio_low
+Foonetic.away_check
+Foonetic.away_check_max_nicks
+Foonetic.default_msg_kick
+Foonetic.default_msg_part
+Foonetic.default_msg_quit
+Foonetic.notify
diff --git a/weechat/iset.conf b/weechat/iset.conf
new file mode 100644
index 0000000..cf43d55
--- /dev/null
+++ b/weechat/iset.conf
@@ -0,0 +1,27 @@
+#
+# iset.conf -- weechat v0.4.3-dev
+#
+
+[color]
+bg_selected = red
+help_default_value = green
+help_option_name = white
+help_text = default
+option = default
+option_selected = white
+type = brown
+type_selected = yellow
+value = cyan
+value_selected = lightcyan
+value_undef = green
+value_undef_selected = lightgreen
+
+[help]
+show_help_bar = on
+show_help_extra_info = on
+show_plugin_description = on
+
+[look]
+scroll_horiz = 10
+show_current_line = on
+value_search_char = "="
diff --git a/weechat/logger.conf b/weechat/logger.conf
new file mode 100644
index 0000000..02a4a92
--- /dev/null
+++ b/weechat/logger.conf
@@ -0,0 +1,26 @@
+#
+# logger.conf -- weechat v0.4.3-dev
+#
+
+[look]
+backlog = 20
+
+[color]
+backlog_end = darkgray
+backlog_line = green
+
+[file]
+auto_log = on
+flush_delay = 120
+info_lines = off
+mask = "$server/$channel/%F"
+name_lower_case = on
+nick_prefix = ""
+nick_suffix = ""
+path = "%h/logs/"
+replacement_char = "_"
+time_format = "%Y-%m-%d %H:%M:%S"
+
+[level]
+
+[mask]
diff --git a/weechat/perl/autoload/buffers.pl b/weechat/perl/autoload/buffers.pl
new file mode 120000
index 0000000..445dc3c
--- /dev/null
+++ b/weechat/perl/autoload/buffers.pl
@@ -0,0 +1 @@
+../buffers.pl \ No newline at end of file
diff --git a/weechat/perl/autoload/highmon.pl b/weechat/perl/autoload/highmon.pl
new file mode 120000
index 0000000..2eb5e1e
--- /dev/null
+++ b/weechat/perl/autoload/highmon.pl
@@ -0,0 +1 @@
+../highmon.pl \ No newline at end of file
diff --git a/weechat/perl/autoload/iset.pl b/weechat/perl/autoload/iset.pl
new file mode 120000
index 0000000..2746e0d
--- /dev/null
+++ b/weechat/perl/autoload/iset.pl
@@ -0,0 +1 @@
+../iset.pl \ No newline at end of file
diff --git a/weechat/perl/autoload/stalker.pl b/weechat/perl/autoload/stalker.pl
new file mode 120000
index 0000000..28bb788
--- /dev/null
+++ b/weechat/perl/autoload/stalker.pl
@@ -0,0 +1 @@
+../stalker.pl \ No newline at end of file
diff --git a/weechat/perl/autoload/yaurls.pl b/weechat/perl/autoload/yaurls.pl
new file mode 120000
index 0000000..c7dbf0c
--- /dev/null
+++ b/weechat/perl/autoload/yaurls.pl
@@ -0,0 +1 @@
+../yaurls.pl \ No newline at end of file
diff --git a/weechat/perl/buffers.pl b/weechat/perl/buffers.pl
new file mode 100644
index 0000000..e315f80
--- /dev/null
+++ b/weechat/perl/buffers.pl
@@ -0,0 +1,1200 @@
+#
+# Copyright (C) 2008-2012 Sebastien Helleu <flashcode@flashtux.org>
+# Copyright (C) 2011-2012 Nils G <weechatter@arcor.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 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/>.
+#
+#
+# Display sidebar with list of buffers.
+#
+# History:
+#
+# 2012-10-18, nils_2@freenode.#weechat:
+# v3.8: add option "mark_inactive", to mark buffers you are not in (idea by xrdodrx)
+# : add wildcard "*" for immune_detach_buffers (idea by StarWeaver)
+# : add new options "detach_query" and "detach_free_content" (idea by StarWeaver)
+# 2012-10-06, Nei <anti.teamidiot.de>:
+# v3.7: call menu on right mouse if menu script is loaded.
+# 2012-10-06, nils_2 <weechatter@arcor.de>:
+# v3.6: add new option "hotlist_counter" (idea by torque).
+# 2012-06-02, nils_2 <weechatter@arcor.de>:
+# v3.5: add values "server|channel|private|all|keepserver|none" to option "hide_merged_buffers" (suggested by dominikh).
+# 2012-05-25, nils_2 <weechatter@arcor.de>:
+# v3.4: add new option "show_lag".
+# 2012-04-07, Sebastien Helleu <flashcode@flashtux.org>:
+# v3.3: fix truncation of wide chars in buffer name (option name_size_max) (bug #36034)
+# 2012-03-15, nils_2 <weechatter@arcor.de>:
+# v3.2: add new option "detach"(weechat >= 0.3.8)
+# add new option "immune_detach_buffers" (requested by Mkaysi)
+# add new function buffers_whitelist add|del|reset (suggested by FiXato)
+# add new function buffers_detach add|del|reset
+# 2012-03-09, Sebastien Helleu <flashcode@flashtux.org>:
+# v3.1: fix reload of config file
+# 2012-01-29, nils_2 <weechatter@arcor.de>:
+# v3.0: fix: buffers did not update directly during window_switch (reported by FiXato)
+# 2012-01-29, nils_2 <weechatter@arcor.de>:
+# v2.9: add options "name_size_max" and "name_crop_suffix"
+# 2012-01-08, nils_2 <weechatter@arcor.de>:
+# v2.8: fix indenting for option "show_number off"
+# fix unset of buffer activity in hotlist when buffer was moved with mouse
+# add buffer with free content and core buffer sorted first (suggested by nyuszika7h)
+# add options queries_default_fg/bg and queries_message_fg/bg (suggested by FiXato)
+# add clicking with left button on current buffer will do a jump_previously_visited_buffer (suggested by FiXato)
+# add clicking with right button on current buffer will do a jump_next_visited_buffer
+# add additional informations in help texts
+# add default_fg and default_bg for whitelist channels
+# internal changes (script is now 3Kb smaller)
+# 2012-01-04, Sebastien Helleu <flashcode@flashtux.org>:
+# v2.7: fix regex lookup in whitelist buffers list
+# 2011-12-04, nils_2 <weechatter@arcor.de>:
+# v2.6: add own config file (buffers.conf)
+# add new behavior for indenting (under_name)
+# add new option to set different color for server buffers and buffers with free content
+# 2011-10-30, nils_2 <weechatter@arcor.de>:
+# v2.5: add new options "show_number_char" and "color_number_char",
+# add help-description for options
+# 2011-08-24, Sebastien Helleu <flashcode@flashtux.org>:
+# v2.4: add mouse support
+# 2011-06-06, nils_2 <weechatter@arcor.de>:
+# v2.3: added: missed option "color_whitelist_default"
+# 2011-03-23, Sebastien Helleu <flashcode@flashtux.org>:
+# v2.2: fix color of nick prefix with WeeChat >= 0.3.5
+# 2011-02-13, nils_2 <weechatter@arcor.de>:
+# v2.1: add options "color_whitelist_*"
+# 2010-10-05, Sebastien Helleu <flashcode@flashtux.org>:
+# v2.0: add options "sort" and "show_number"
+# 2010-04-12, Sebastien Helleu <flashcode@flashtux.org>:
+# v1.9: replace call to log() by length() to align buffer numbers
+# 2010-04-02, Sebastien Helleu <flashcode@flashtux.org>:
+# v1.8: fix bug with background color and option indenting_number
+# 2010-04-02, Helios <helios@efemes.de>:
+# v1.7: add indenting_number option
+# 2010-02-25, m4v <lambdae2@gmail.com>:
+# v1.6: add option to hide empty prefixes
+# 2010-02-12, Sebastien Helleu <flashcode@flashtux.org>:
+# v1.5: add optional nick prefix for buffers like IRC channels
+# 2009-09-30, Sebastien Helleu <flashcode@flashtux.org>:
+# v1.4: remove spaces for indenting when bar position is top/bottom
+# 2009-06-14, Sebastien Helleu <flashcode@flashtux.org>:
+# v1.3: add option "hide_merged_buffers"
+# 2009-06-14, Sebastien Helleu <flashcode@flashtux.org>:
+# v1.2: improve display with merged buffers
+# 2009-05-02, Sebastien Helleu <flashcode@flashtux.org>:
+# v1.1: sync with last API changes
+# 2009-02-21, Sebastien Helleu <flashcode@flashtux.org>:
+# v1.0: remove timer used to update bar item first time (not needed any more)
+# 2009-02-17, Sebastien Helleu <flashcode@flashtux.org>:
+# v0.9: fix bug with indenting of private buffers
+# 2009-01-04, Sebastien Helleu <flashcode@flashtux.org>:
+# v0.8: update syntax for command /set (comments)
+# 2008-10-20, Jiri Golembiovsky <golemj@gmail.com>:
+# v0.7: add indenting option
+# 2008-10-01, Sebastien Helleu <flashcode@flashtux.org>:
+# v0.6: add default color for buffers, and color for current active buffer
+# 2008-09-18, Sebastien Helleu <flashcode@flashtux.org>:
+# v0.5: fix color for "low" level entry in hotlist
+# 2008-09-18, Sebastien Helleu <flashcode@flashtux.org>:
+# v0.4: rename option "show_category" to "short_names",
+# remove option "color_slash"
+# 2008-09-15, Sebastien Helleu <flashcode@flashtux.org>:
+# v0.3: fix bug with priority in hotlist (var not defined)
+# 2008-09-02, Sebastien Helleu <flashcode@flashtux.org>:
+# v0.2: add color for buffers with activity and config options for
+# colors, add config option to display/hide categories
+# 2008-03-15, Sebastien Helleu <flashcode@flashtux.org>:
+# v0.1: script creation
+#
+# Help about settings:
+# display all settings for script (or use iset.pl script to change settings):
+# /set buffers*
+# show help text for option buffers.look.whitelist_buffers:
+# /help buffers.look.whitelist_buffers
+#
+# Mouse-support (standard key bindings):
+# left mouse-button:
+# - click on a buffer to switch to selected buffer
+# - click on current buffer will do action jump_previously_visited_buffer
+# - drag a buffer and drop it on another position will move the buffer to position
+# right mouse-button:
+# - click on current buffer will do action jump_next_visited_buffer
+# - moving buffer to the left/right will close buffer.
+#
+
+use strict;
+use Encode qw( decode encode );
+# -------------------------------[ internal ]-------------------------------------
+my $version = "3.8";
+
+my $BUFFERS_CONFIG_FILE_NAME = "buffers";
+my $buffers_config_file;
+my $cmd_buffers_whitelist= "buffers_whitelist";
+my $cmd_buffers_detach = "buffers_detach";
+
+my %mouse_keys = ("\@item(buffers):button1*" => "hsignal:buffers_mouse", # catch all left mouse button gestures
+ "\@item(buffers):button2*" => "hsignal:buffers_mouse"); # catch all right mouse button gestures
+my %options;
+my %hotlist_level = (0 => "low", 1 => "message", 2 => "private", 3 => "highlight");
+my @whitelist_buffers = ();
+my @immune_detach_buffers= ();
+my @buffers_focus = ();
+my %buffers_timer = ();
+my %Hooks = ();
+
+# --------------------------------[ init ]--------------------------------------
+weechat::register("buffers", "Sebastien Helleu <flashcode\@flashtux.org>", $version,
+ "GPL3", "Sidebar with list of buffers", "", "");
+my $weechat_version = weechat::info_get("version_number", "") || 0;
+
+buffers_config_init();
+buffers_config_read();
+
+weechat::bar_item_new("buffers", "build_buffers", "");
+weechat::bar_new("buffers", "0", "0", "root", "", "left", "horizontal",
+ "vertical", "0", "0", "default", "default", "default", "1",
+ "buffers");
+weechat::hook_signal("buffer_*", "buffers_signal_buffer", "");
+weechat::hook_signal("window_switch", "buffers_signal_buffer", "");
+weechat::hook_signal("hotlist_*", "buffers_signal_hotlist", "");
+weechat::hook_signal("window_switch", "buffers_signal_buffer", "");
+#weechat::hook_command_run("/input switch_active_*", "buffers_signal_buffer", "");
+weechat::bar_item_update("buffers");
+if ($weechat_version >= 0x00030600)
+{
+ weechat::hook_focus("buffers", "buffers_focus_buffers", "");
+ weechat::hook_hsignal("buffers_mouse", "buffers_hsignal_mouse", "");
+ weechat::key_bind("mouse", \%mouse_keys);
+}
+
+weechat::hook_command( $cmd_buffers_whitelist,
+ "add/del current buffer to/from buffers whitelist",
+ "[add] || [del] || [reset]",
+
+ " add: add current buffer in configuration file\n".
+ " del: delete current buffer from configuration file\n".
+ "reset: reset all buffers from configuration file (no confirmation!)\n\n".
+ "Examples:\n".
+ "/$cmd_buffers_whitelist add\n",
+ "add %-||".
+ "del %-||".
+ "reset %-",
+ "buffers_cmd_whitelist", "");
+weechat::hook_command( $cmd_buffers_detach,
+ "add/del current buffer to/from buffers detach",
+ "[add] || [del] || [reset]",
+
+ " add: add current buffer in configuration file\n".
+ " del: delete current buffer from configuration file\n".
+ "reset: reset all buffers from configuration file (no confirmation!)\n\n".
+ "Examples:\n".
+ "/$cmd_buffers_detach add\n",
+ "add %-||".
+ "del %-||".
+ "reset %-",
+ "buffers_cmd_detach", "");
+
+if ($weechat_version >= 0x00030800)
+{
+ weechat::hook_config("buffers.look.detach", "hook_timer_detach", "");
+}
+
+ weechat::hook_config("buffers.look.show_lag", "hook_timer_lag", "");
+
+# -------------------------------- [ command ] --------------------------------
+sub buffers_cmd_whitelist
+{
+my ( $data, $buffer, $args ) = @_;
+ $args = lc($args);
+ my $buffers_whitelist = weechat::config_string( weechat::config_get("buffers.look.whitelist_buffers") );
+ return weechat::WEECHAT_RC_OK if ( $buffers_whitelist eq "" and $args eq "del" or $buffers_whitelist eq "" and $args eq "reset" );
+ my @buffers_list = split( /,/, $buffers_whitelist );
+ # get buffers name
+ my $infolist = weechat::infolist_get("buffer", weechat::current_buffer(), "");
+ weechat::infolist_next($infolist);
+ my $buffers_name = weechat::infolist_string($infolist, "name");
+ weechat::infolist_free($infolist);
+ return weechat::WEECHAT_RC_OK if ( $buffers_name eq "" ); # should never happen
+
+ if ( $args eq "add" )
+ {
+ return weechat::WEECHAT_RC_OK if ( grep /^$buffers_name$/, @buffers_list ); # check if buffer already in list
+ push @buffers_list,( $buffers_name );
+ my $buffers_list = &create_whitelist(\@buffers_list);
+ weechat::config_option_set( weechat::config_get("buffers.look.whitelist_buffers"), $buffers_list,1 );
+ weechat::print(weechat::current_buffer(), "buffer \"$buffers_name\" added to buffers whitelist");
+ }
+ elsif ( $args eq "del" )
+ {
+ return weechat::WEECHAT_RC_OK unless ( grep /^$buffers_name$/, @buffers_list ); # check if buffer is in list
+ @buffers_list = grep {$_ ne $buffers_name} @buffers_list; # delete entry
+ my $buffers_list = &create_whitelist(\@buffers_list);
+ weechat::config_option_set( weechat::config_get("buffers.look.whitelist_buffers"), $buffers_list,1 );
+ weechat::print(weechat::current_buffer(), "buffer \"$buffers_name\" deleted from buffers whitelist");
+ }
+ elsif ( $args eq "reset" )
+ {
+ return weechat::WEECHAT_RC_OK if ( $buffers_whitelist eq "" );
+ weechat::config_option_set( weechat::config_get("buffers.look.whitelist_buffers"), "",1 );
+ weechat::print(weechat::current_buffer(), "buffers whitelist is empty, now...");
+ }
+ return weechat::WEECHAT_RC_OK;
+}
+sub buffers_cmd_detach
+{
+my ( $data, $buffer, $args ) = @_;
+ $args = lc($args);
+ my $immune_detach_buffers = weechat::config_string( weechat::config_get("buffers.look.immune_detach_buffers") );
+ return weechat::WEECHAT_RC_OK if ( $immune_detach_buffers eq "" and $args eq "del" or $immune_detach_buffers eq "" and $args eq "reset" );
+ my @buffers_list = split( /,/, $immune_detach_buffers );
+ # get buffers name
+ my $infolist = weechat::infolist_get("buffer", weechat::current_buffer(), "");
+ weechat::infolist_next($infolist);
+ my $buffers_name = weechat::infolist_string($infolist, "name");
+ weechat::infolist_free($infolist);
+ return weechat::WEECHAT_RC_OK if ( $buffers_name eq "" ); # should never happen
+
+ if ( $args eq "add" )
+ {
+ return weechat::WEECHAT_RC_OK if ( grep /^$buffers_name$/, @buffers_list ); # check if buffer already in list
+ push @buffers_list,( $buffers_name );
+ my $buffers_list = &create_whitelist(\@buffers_list);
+ weechat::config_option_set( weechat::config_get("buffers.look.immune_detach_buffers"), $buffers_list,1 );
+ weechat::print(weechat::current_buffer(), "buffer \"$buffers_name\" added to immune detach buffers");
+ }
+ elsif ( $args eq "del" )
+ {
+ return weechat::WEECHAT_RC_OK unless ( grep /^$buffers_name$/, @buffers_list ); # check if buffer is in list
+ @buffers_list = grep {$_ ne $buffers_name} @buffers_list; # delete entry
+ my $buffers_list = &create_whitelist(\@buffers_list);
+ weechat::config_option_set( weechat::config_get("buffers.look.immune_detach_buffers"), $buffers_list,1 );
+ weechat::print(weechat::current_buffer(), "buffer \"$buffers_name\" deleted from immune detach buffers");
+ }
+ elsif ( $args eq "reset" )
+ {
+ return weechat::WEECHAT_RC_OK if ( $immune_detach_buffers eq "" );
+ weechat::config_option_set( weechat::config_get("buffers.look.immune_detach_buffers"), "",1 );
+ weechat::print(weechat::current_buffer(), "immune detach buffers is empty, now...");
+ }
+ return weechat::WEECHAT_RC_OK;
+}
+sub create_whitelist
+{
+ my @buffers_list = @{$_[0]};
+ my $buffers_list = "";
+ foreach (@buffers_list)
+ {
+ $buffers_list .= $_ .",";
+ }
+ chop $buffers_list; # remove last ","
+ return $buffers_list;
+}
+
+# -------------------------------- [ config ] --------------------------------
+sub hook_timer_detach
+{
+ my $detach = $_[2];
+ if ( $detach eq 0 )
+ {
+ weechat::unhook($Hooks{timer_detach}) if $Hooks{timer_detach};
+ $Hooks{timer_detach} = "";
+ }
+ else
+ {
+ weechat::unhook($Hooks{timer_detach}) if $Hooks{timer_detach};
+ $Hooks{timer_detach} = weechat::hook_timer( weechat::config_integer( $options{"detach"}) * 1000, 60, 0, "buffers_signal_buffer", "");
+ }
+ weechat::bar_item_update("buffers");
+ return weechat::WEECHAT_RC_OK;
+}
+
+sub hook_timer_lag
+{
+ my $lag = $_[2];
+ if ( $lag eq 0 )
+ {
+ weechat::unhook($Hooks{timer_lag}) if $Hooks{timer_lag};
+ $Hooks{timer_lag} = "";
+ }
+ else
+ {
+ weechat::unhook($Hooks{timer_lag}) if $Hooks{timer_lag};
+ $Hooks{timer_lag} = weechat::hook_timer( weechat::config_integer(weechat::config_get("irc.network.lag_refresh_interval")) * 1000, 0, 0, "buffers_signal_hotlist", "");
+ }
+ weechat::bar_item_update("buffers");
+ return weechat::WEECHAT_RC_OK;
+}
+
+sub buffers_config_read
+{
+ return weechat::config_read($buffers_config_file) if ($buffers_config_file ne "");
+}
+sub buffers_config_write
+{
+ return weechat::config_write($buffers_config_file) if ($buffers_config_file ne "");
+}
+sub buffers_config_reload_cb
+{
+ my ($data,$config_file) = ($_[0], $_[1]);
+ return weechat::config_reload($config_file)
+}
+sub buffers_config_init
+{
+ $buffers_config_file = weechat::config_new($BUFFERS_CONFIG_FILE_NAME,"buffers_config_reload_cb","");
+ return if ($buffers_config_file eq "");
+
+my %default_options_color =
+("color_current_fg" => ["current_fg", "color", "foreground color for current buffer", "", 0, 0,"lightcyan", "lightcyan", 0, "", "","buffers_signal_config", "", "", ""],
+ "color_current_bg" => ["current_bg", "color", "background color for current buffer", "", 0, 0,"red", "red", 0, "", "","buffers_signal_config", "", "", ""],
+ "color_default_fg" => ["default_fg", "color", "default foreground color for buffer name", "", 0, 0,"default", "default", 0, "", "","buffers_signal_config", "", "", ""],
+ "color_default_bg" => ["default_bg", "color", "default background color for buffer name", "", 0, 0,"default", "default", 0, "", "","buffers_signal_config", "", "", ""],
+ "color_hotlist_highlight_fg" => ["hotlist_highlight_fg", "color", "change foreground color of buffer name if a highlight messaged received","", 0, 0,"magenta", "magenta", 0, "", "","buffers_signal_config", "", "", ""],
+ "color_hotlist_highlight_bg" => ["hotlist_highlight_bg", "color", "change background color of buffer name if a highlight messaged received", "", 0, 0,"default", "default", 0, "", "","buffers_signal_config", "", "", ""],
+ "color_hotlist_low_fg" => ["hotlist_low_fg", "color", "change foreground color of buffer name if a low message received", "", 0, 0,"white", "white", 0, "", "","buffers_signal_config", "", "", ""],
+ "color_hotlist_low_bg" => ["hotlist_low_bg", "color", "change background color of buffer name if a low message received", "", 0, 0,
+ "default", "default", 0, "", "","buffers_signal_config", "", "", ""],
+ "color_hotlist_message_fg" => ["hotlist_message_fg", "color", "change foreground color of buffer name if a normal message received", "", 0, 0,"yellow", "yellow", 0, "", "","buffers_signal_config", "", "", ""],
+ "color_hotlist_message_bg" => ["hotlist_message_bg", "color", "change background color of buffer name if a normal message received", "", 0, 0,"default", "default", 0, "", "","buffers_signal_config", "", "", ""],
+ "color_hotlist_private_fg" => ["hotlist_private_fg", "color", "change foreground color of buffer name if a private message received", "", 0, 0,"lightgreen", "lightgreen", 0, "", "","buffers_signal_config", "", "", ""],
+ "color_hotlist_private_bg" => ["hotlist_private_bg", "color", "change background color of buffer name if a private message received", "", 0, 0,"default", "default", 0, "", "","buffers_signal_config", "", "", ""],
+ "color_number" => ["number", "color", "color for buffer number", "", 0, 0,"lightgreen", "lightgreen", 0, "", "","buffers_signal_config", "", "", ""],
+ "color_number_char" => ["number_char", "color", "color for buffer number char", "", 0, 0,"lightgreen", "lightgreen", 0, "", "","buffers_signal_config", "", "", ""],
+ "color_whitelist_default_fg" => ["whitelist_default_fg", "color", "default foreground color for whitelist buffer name", "", 0, 0,"", "", 0, "", "","buffers_signal_config", "", "", ""],
+ "color_whitelist_default_bg" => ["whitelist_default_bg", "color", "default background color for whitelist buffer name", "", 0, 0,"", "", 0, "", "","buffers_signal_config", "", "", ""],
+ "color_whitelist_low_fg" => ["whitelist_low_fg", "color", "low color of whitelist buffer name", "", 0, 0,"", "", 0, "", "","buffers_signal_config", "", "", ""],
+ "color_whitelist_low_bg" => ["whitelist_low_bg", "color", "low color of whitelist buffer name", "", 0, 0,"", "", 0, "", "","buffers_signal_config", "", "", ""],
+ "color_whitelist_message_fg" => ["whitelist_message_fg", "color", "message color of whitelist buffer name", "", 0, 0,"", "", 0, "", "","buffers_signal_config", "", "", ""],
+ "color_whitelist_message_bg" => ["whitelist_message_bg", "color", "message color of whitelist buffer name", "", 0, 0,"", "", 0, "", "","buffers_signal_config", "", "", ""],
+ "color_whitelist_private_fg" => ["whitelist_private_fg", "color", "private color of whitelist buffer name", "", 0, 0,"", "", 0, "", "","buffers_signal_config", "", "", ""],
+ "color_whitelist_private_bg" => ["whitelist_private_bg", "color", "private color of whitelist buffer name", "", 0, 0,"", "", 0, "", "","buffers_signal_config", "", "", ""],
+ "color_whitelist_highlight_fg" => ["whitelist_highlight_fg", "color", "highlight color of whitelist buffer name", "", 0, 0,"", "", 0, "", "","buffers_signal_config", "", "", ""],
+ "color_whitelist_highlight_bg" => ["whitelist_highlight_bg", "color", "highlight color of whitelist buffer name", "", 0, 0,"", "", 0, "", "","buffers_signal_config", "", "", ""],
+ "color_none_channel_fg" => ["none_channel_fg", "color", "foreground color for none channel buffer (e.g.: core/server/plugin buffer)", "", 0, 0,"default", "default", 0, "", "","buffers_signal_config", "", "", ""],
+ "color_none_channel_bg" => ["none_channel_bg", "color", "background color for none channel buffer (e.g.: core/server/plugin buffer)", "", 0, 0,"default", "default", 0, "", "","buffers_signal_config", "", "", ""],
+ "queries_default_fg" => ["queries_default_fg", "color", "foreground color for query buffer without message", "", 0, 0,"default", "default", 0, "", "","buffers_signal_config", "", "", ""],
+ "queries_default_bg" => ["queries_default_bg", "color", "background color for query buffer without message", "", 0, 0,"default", "default", 0, "", "","buffers_signal_config", "", "", ""],
+ "queries_message_fg" => ["queries_message_fg", "color", "foreground color for query buffer with unread message", "", 0, 0,"default", "default", 0, "", "","buffers_signal_config", "", "", ""],
+ "queries_message_bg" => ["queries_message_bg", "color", "background color for query buffer with unread message", "", 0, 0,"default", "default", 0, "", "","buffers_signal_config", "", "", ""],
+ "queries_highlight_fg" => ["queries_highlight_fg", "color", "foreground color for query buffer with unread highlight", "", 0, 0,"default", "default", 0, "", "","buffers_signal_config", "", "", ""],
+ "queries_highlight_bg" => ["queries_highlight_bg", "color", "background color for query buffer with unread highlight", "", 0, 0,"default", "default", 0, "", "","buffers_signal_config", "", "", ""],
+);
+
+my %default_options_look =
+(
+ "hotlist_counter" => ["hotlist_counter","boolean","show number of message for the buffer (this option needs WeeChat >= 0.3.5). The relevant option for notification is \"weechat.look.buffer_notify_default\"","",0,0,"off","off",0,"","","buffers_signal_config","","",""],
+ "show_lag" => ["show_lag","boolean","show lag behind servername. This option is using \"irc.color.item_lag_finished\", \"irc.network.lag_min_show\" and \"irc.network.lag_refresh_interval\"","",0,0,"off","off",0,"","","buffers_signal_config","","",""],
+ "look_whitelist_buffers" => ["whitelist_buffers", "string", "comma separated list of buffers for using a differnt color scheme (for example: freenode.#weechat,freenode.#weechat-fr)", "", 0, 0,"", "", 0, "", "", "buffers_signal_config_whitelist", "", "", ""],
+ "hide_merged_buffers" => ["hide_merged_buffers", "integer", "hide merged buffers. The value determines which merged buffers should be hidden, keepserver meaning 'all except server buffers'. Other values correspondent to the buffer type.", "server|channel|private|keepserver|all|none", 0, 0,"none", "none", 0, "", "", "buffers_signal_config", "", "", ""],
+ "indenting" => ["indenting", "integer", "use indenting for channel and query buffers. This option only takes effect if bar is left/right positioned", "off|on|under_name", 0, 0,"off", "off", 0, "", "", "buffers_signal_config", "", "", ""],
+ "indenting_number" => ["indenting_number", "boolean", "use indenting for numbers. This option only takes effect if bar is left/right positioned", "", 0, 0,"on", "on", 0, "", "", "buffers_signal_config", "", "", ""],
+ "short_names" => ["short_names", "boolean", "display short names (remove text before first \".\" in buffer name)", "", 0, 0,"on", "on", 0, "", "", "buffers_signal_config", "", "", ""],
+ "show_number" => ["show_number", "boolean", "display channel number in front of buffername", "", 0, 0,"on", "on", 0, "", "", "buffers_signal_config", "", "", ""],
+ "show_number_char" => ["number_char", "string", "display a char after channel number", "", 0, 0,".", ".", 0, "", "", "buffers_signal_config", "", "", ""],
+ "show_prefix" => ["prefix", "boolean", "show your prefix for channel", "", 0, 0,"off", "off", 0, "", "", "buffers_signal_config", "", "", ""],
+ "show_prefix_empty" => ["prefix_empty", "boolean", "use a placeholder for channels without prefix", "", 0, 0,"on", "on", 0, "", "", "buffers_signal_config", "", "", ""],
+ "sort" => ["sort", "integer", "sort buffer-list by \"number\" or \"name\"", "number|name", 0, 0,"number", "number", 0, "", "", "buffers_signal_config", "", "", ""],
+ "core_to_front" => ["core_to_front", "boolean", "core buffer and buffers with free content will be listed first. Take only effect if buffer sort is by name", "", 0, 0,"off", "off", 0, "", "", "buffers_signal_config", "", "", ""],
+ "jump_prev_next_visited_buffer" => ["jump_prev_next_visited_buffer", "boolean", "jump to previously or next visited buffer if you click with left/right mouse button on currently visiting buffer", "", 0, 0,"off", "off", 0, "", "", "buffers_signal_config", "", "", ""],
+ "name_size_max" => ["name_size_max","integer","maximum size of buffer name. 0 means no limitation","",0,256,0,0,0, "", "", "buffers_signal_config", "", "", ""],
+ "name_crop_suffix" => ["name_crop_suffix","string","contains an optional char(s) that is appended when buffer name is shortened","",0,0,"+","+",0,"","","buffers_signal_config", "", "", ""],
+ "detach" => ["detach", "integer","detach channel from buffers list after a specific period of time (in seconds) without action (weechat ≥ 0.3.8 required)", "", 0, 31536000,0, "number", 0, "", "", "buffers_signal_config", "", "", ""],
+ "immune_detach_buffers"=> ["immune_detach_buffers", "string", "Comma seperated list of buffers to NOT automatically detatch. Allows \"*\" wildcard. Ex: \"BitlBee,freenode.*\"", "", 0, 0,"", "", 0, "", "", "buffers_signal_config_immune_detach_buffers", "", "", ""],
+ "detach_query" => ["detach_query", "boolean", "query buffer will be detachted", "", 0, 0,"off", "off", 0, "", "", "buffers_signal_config", "", "", ""],
+ "detach_free_content" => ["detach_free_content", "boolean", "buffers with free content will be detached (Ex: iset, chanmon)", "", 0, 0,"off", "off", 0, "", "", "buffers_signal_config", "", "", ""],
+ "mark_inactive" => ["mark_inactive", "boolean", "if option is \"on\", inactive buffers (those you are not in) will have parentesis around them. An inactive buffer will not be detached.", "", 0, 0,"off", "off", 0, "", "", "buffers_signal_config", "", "", ""],
+);
+ # section "color"
+ my $section_color = weechat::config_new_section($buffers_config_file,"color", 0, 0, "", "", "", "", "", "", "", "", "", "");
+ if ($section_color eq "")
+ {
+ weechat::config_free($buffers_config_file);
+ return;
+ }
+ foreach my $option (keys %default_options_color)
+ {
+ $options{$option} = weechat::config_new_option($buffers_config_file, $section_color,
+ $default_options_color{$option}[0],$default_options_color{$option}[1],$default_options_color{$option}[2],
+ $default_options_color{$option}[3],$default_options_color{$option}[4],$default_options_color{$option}[5],
+ $default_options_color{$option}[6],$default_options_color{$option}[7],$default_options_color{$option}[8],
+ $default_options_color{$option}[9],$default_options_color{$option}[10],$default_options_color{$option}[11],
+ $default_options_color{$option}[12],$default_options_color{$option}[13],$default_options_color{$option}[14]);
+ }
+
+ # section "look"
+ my $section_look = weechat::config_new_section($buffers_config_file,"look", 0, 0, "", "", "", "", "", "", "", "", "", "");
+ if ($section_look eq "")
+ {
+ weechat::config_free($buffers_config_file);
+ return;
+ }
+ foreach my $option (keys %default_options_look)
+ {
+ $options{$option} = weechat::config_new_option($buffers_config_file, $section_look,
+ $default_options_look{$option}[0],$default_options_look{$option}[1],$default_options_look{$option}[2],
+ $default_options_look{$option}[3],$default_options_look{$option}[4],$default_options_look{$option}[5],
+ $default_options_look{$option}[6],$default_options_look{$option}[7],$default_options_look{$option}[8],
+ $default_options_look{$option}[9],$default_options_look{$option}[10],$default_options_look{$option}[11],
+ $default_options_look{$option}[12],$default_options_look{$option}[13],$default_options_look{$option}[14]);
+ }
+}
+
+sub build_buffers
+{
+ my $str = "";
+
+ # get bar position (left/right/top/bottom)
+ my $position = "left";
+ my $option_position = weechat::config_get("weechat.bar.buffers.position");
+ if ($option_position ne "")
+ {
+ $position = weechat::config_string($option_position);
+ }
+
+ # read hotlist
+ my %hotlist;
+ my $infolist = weechat::infolist_get("hotlist", "", "");
+ while (weechat::infolist_next($infolist))
+ {
+ $hotlist{weechat::infolist_pointer($infolist, "buffer_pointer")} =
+ weechat::infolist_integer($infolist, "priority");
+ if ( weechat::config_boolean( $options{"hotlist_counter"} ) eq 1 and $weechat_version >= 0x00030500)
+ {
+ $hotlist{weechat::infolist_pointer($infolist, "buffer_pointer")."_count_00"} =
+ weechat::infolist_integer($infolist, "count_00"); # low message
+ $hotlist{weechat::infolist_pointer($infolist, "buffer_pointer")."_count_01"} =
+ weechat::infolist_integer($infolist, "count_01"); # channel message
+ $hotlist{weechat::infolist_pointer($infolist, "buffer_pointer")."_count_02"} =
+ weechat::infolist_integer($infolist, "count_02"); # private message
+ $hotlist{weechat::infolist_pointer($infolist, "buffer_pointer")."_count_03"} =
+ weechat::infolist_integer($infolist, "count_03"); # highlight message
+ }
+ }
+ weechat::infolist_free($infolist);
+
+ # read buffers list
+ @buffers_focus = ();
+ my @buffers;
+ my @current1 = ();
+ my @current2 = ();
+ my $old_number = -1;
+ my $max_number = 0;
+ my $max_number_digits = 0;
+ my $active_seen = 0;
+ $infolist = weechat::infolist_get("buffer", "", "");
+ while (weechat::infolist_next($infolist))
+ {
+ my $buffer;
+ my $number = weechat::infolist_integer($infolist, "number");
+ if ($number ne $old_number)
+ {
+ @buffers = (@buffers, @current2, @current1);
+ @current1 = ();
+ @current2 = ();
+ $active_seen = 0;
+ }
+ if ($number > $max_number)
+ {
+ $max_number = $number;
+ }
+ $old_number = $number;
+ my $active = weechat::infolist_integer($infolist, "active");
+ if ($active)
+ {
+ $active_seen = 1;
+ }
+ $buffer->{"pointer"} = weechat::infolist_pointer($infolist, "pointer");
+ $buffer->{"number"} = $number;
+ $buffer->{"active"} = $active;
+ $buffer->{"current_buffer"} = weechat::infolist_integer($infolist, "current_buffer");
+ $buffer->{"plugin_name"} = weechat::infolist_string($infolist, "plugin_name");
+ $buffer->{"name"} = weechat::infolist_string($infolist, "name");
+ $buffer->{"short_name"} = weechat::infolist_string($infolist, "short_name");
+ $buffer->{"full_name"} = $buffer->{"plugin_name"}.".".$buffer->{"name"};
+ $buffer->{"type"} = weechat::buffer_get_string($buffer->{"pointer"},"localvar_type");
+# weechat::print("",$buffer->{"type"});
+
+ # check if buffer is active (or maybe a /part, /kick channel)
+ if ($buffer->{"type"} eq "channel" and weechat::config_boolean( $options{"mark_inactive"} ) eq 1)
+ {
+ my $server = weechat::buffer_get_string($buffer->{"pointer"},"localvar_server");
+ my $channel = weechat::buffer_get_string($buffer->{"pointer"},"localvar_channel");
+ my $infolist_channel = weechat::infolist_get("irc_channel","",$server.",".$channel);
+ if ($infolist_channel)
+ {
+ weechat::infolist_next($infolist_channel);
+ $buffer->{"nicks_count"} = weechat::infolist_integer($infolist_channel,"nicks_count");
+ }else
+ {
+ $buffer->{"nicks_count"} = 0;
+ }
+ weechat::infolist_free($infolist_channel);
+ }
+
+ my $result = check_immune_detached_buffers($buffer->{"name"}); # checking for wildcard
+ unless ($result)
+ {
+ my $detach_time = weechat::config_integer( $options{"detach"});
+ my $current_time = time();
+ # set timer for buffers with no hotlist action
+ $buffers_timer{$buffer->{"pointer"}} = $current_time
+ if ( not exists $hotlist{$buffer->{"pointer"}}
+ and $buffer->{"type"} eq "channel"
+ and not exists $buffers_timer{$buffer->{"pointer"}}
+ and $detach_time > 0);
+
+ $buffers_timer{$buffer->{"pointer"}} = $current_time
+ if (weechat::config_boolean($options{"detach_query"}) eq 1
+ and not exists $hotlist{$buffer->{"pointer"}}
+ and $buffer->{"type"} eq "private"
+ and not exists $buffers_timer{$buffer->{"pointer"}}
+ and $detach_time > 0);
+
+ $detach_time = 0
+ if (weechat::config_boolean($options{"detach_query"}) eq 0
+ and $buffer->{"type"} eq "private");
+
+ # free content buffer
+ $buffers_timer{$buffer->{"pointer"}} = $current_time
+ if (weechat::config_boolean($options{"detach_free_content"}) eq 1
+ and not exists $hotlist{$buffer->{"pointer"}}
+ and $buffer->{"type"} eq ""
+ and not exists $buffers_timer{$buffer->{"pointer"}}
+ and $detach_time > 0);
+ $detach_time = 0
+ if (weechat::config_boolean($options{"detach_free_content"}) eq 0
+ and $buffer->{"type"} eq "");
+
+ $detach_time = 0 if (weechat::config_boolean($options{"mark_inactive"}) eq 1 and defined $buffer->{"nicks_count"} and $buffer->{"nicks_count"} == 0);
+
+ # check for detach
+ unless ( $buffer->{"current_buffer"} eq 0
+ and not exists $hotlist{$buffer->{"pointer"}}
+# and $buffer->{"type"} eq "channel"
+ and exists $buffers_timer{$buffer->{"pointer"}}
+ and $detach_time > 0
+ and $weechat_version >= 0x00030800
+ and $current_time - $buffers_timer{$buffer->{"pointer"}} >= $detach_time)
+ {
+ if ($active_seen)
+ {
+ push(@current2, $buffer);
+ }
+ else
+ {
+ push(@current1, $buffer);
+ }
+ }
+ }
+ else # buffer in "immune_detach_buffers"
+ {
+ if ($active_seen)
+ {
+ push(@current2, $buffer);
+ }
+ else
+ {
+ push(@current1, $buffer);
+ }
+ }
+ } # while end
+
+
+ if ($max_number >= 1)
+ {
+ $max_number_digits = length(int($max_number));
+ }
+ @buffers = (@buffers, @current2, @current1);
+ weechat::infolist_free($infolist);
+
+ # sort buffers by number, name or shortname
+ my %sorted_buffers;
+ if (1)
+ {
+ my $number = 0;
+ for my $buffer (@buffers)
+ {
+ my $key;
+ if (weechat::config_integer( $options{"sort"} ) eq 1) # number = 0; name = 1
+ {
+ my $name = $buffer->{"name"};
+ $name = $buffer->{"short_name"} if (weechat::config_boolean( $options{"short_names"} ) eq 1);
+ if (weechat::config_integer($options{"name_size_max"}) >= 1){
+ $name = encode("UTF-8", substr(decode("UTF-8", $name), 0, weechat::config_integer($options{"name_size_max"})));
+ }
+ if ( weechat::config_boolean($options{"core_to_front"}) eq 1)
+ {
+ if ( (weechat::buffer_get_string($buffer->{"pointer"}, "localvar_type") ne "channel" ) and ( weechat::buffer_get_string($buffer->{"pointer"}, "localvar_type") ne "private") )
+ {
+ my $type = weechat::buffer_get_string($buffer->{"pointer"}, "localvar_type");
+ if ( $type eq "" and $name ne "weechat")
+ {
+ $name = " " . $name
+ }else
+ {
+ $name = " " . $name;
+ }
+ }
+ }
+ $key = sprintf("%s%08d", lc($name), $buffer->{"number"});
+ }
+ else
+ {
+ $key = sprintf("%08d", $number);
+ }
+ $sorted_buffers{$key} = $buffer;
+ $number++;
+ }
+ }
+
+ # build string with buffers
+ $old_number = -1;
+ foreach my $key (sort keys %sorted_buffers)
+ {
+ my $buffer = $sorted_buffers{$key};
+
+ if ( weechat::config_string($options{"hide_merged_buffers"}) eq "server" )
+ {
+ # buffer type "server" or merged with core?
+ if ( ($buffer->{"type"} eq "server" or $buffer->{"plugin_name"} eq "core") && (! $buffer->{"active"}) )
+ {
+ next;
+ }
+ }
+ if ( weechat::config_string($options{"hide_merged_buffers"}) eq "channel" )
+ {
+ # buffer type "channel" or merged with core?
+ if ( ($buffer->{"type"} eq "channel" or $buffer->{"plugin_name"} eq "core") && (! $buffer->{"active"}) )
+ {
+ next;
+ }
+ }
+ if ( weechat::config_string($options{"hide_merged_buffers"}) eq "private" )
+ {
+ # buffer type "private" or merged with core?
+ if ( ($buffer->{"type"} eq "private" or $buffer->{"plugin_name"} eq "core") && (! $buffer->{"active"}) )
+ {
+ next;
+ }
+ }
+ if ( weechat::config_string($options{"hide_merged_buffers"}) eq "keepserver" )
+ {
+ if ( ($buffer->{"type"} ne "server" or $buffer->{"plugin_name"} eq "core") && (! $buffer->{"active"}) )
+ {
+ next;
+ }
+ }
+ if ( weechat::config_string($options{"hide_merged_buffers"}) eq "all" )
+ {
+ if ( ! $buffer->{"active"} )
+ {
+ next;
+ }
+ }
+
+ push(@buffers_focus, $buffer); # buffer > buffers_focus, for mouse support
+ my $color = "";
+ my $bg = "";
+
+ $color = weechat::config_color( $options{"color_default_fg"} );
+ $bg = weechat::config_color( $options{"color_default_bg"} );
+
+ if ( weechat::buffer_get_string($buffer->{"pointer"}, "localvar_type") eq "private" )
+ {
+ if ( (weechat::config_color($options{"queries_default_bg"})) ne "default" || (weechat::config_color($options{"queries_default_fg"})) ne "default" )
+ {
+ $bg = weechat::config_color( $options{"queries_default_bg"} );
+ $color = weechat::config_color( $options{"queries_default_fg"} );
+ }
+ }
+ # check for core and buffer with free content
+ if ( (weechat::buffer_get_string($buffer->{"pointer"}, "localvar_type") ne "channel" ) and ( weechat::buffer_get_string($buffer->{"pointer"}, "localvar_type") ne "private") )
+ {
+ $color = weechat::config_color( $options{"color_none_channel_fg"} );
+ $bg = weechat::config_color( $options{"color_none_channel_bg"} );
+ }
+ # default whitelist buffer?
+ if (grep {$_ eq $buffer->{"name"}} @whitelist_buffers)
+ {
+ $color = weechat::config_color( $options{"color_whitelist_default_fg"} );
+ $bg = weechat::config_color( $options{"color_whitelist_default_bg"} );
+ }
+
+ $color = "default" if ($color eq "");
+
+ # color for channel and query buffer
+ if (exists $hotlist{$buffer->{"pointer"}})
+ {
+ delete $buffers_timer{$buffer->{"pointer"}};
+ # check if buffer is in whitelist buffer
+ if (grep {$_ eq $buffer->{"name"}} @whitelist_buffers)
+ {
+ $bg = weechat::config_color( $options{"color_whitelist_".$hotlist_level{$hotlist{$buffer->{"pointer"}}}."_bg"} );
+ $color = weechat::config_color( $options{"color_whitelist_".$hotlist_level{$hotlist{$buffer->{"pointer"}}}."_fg"} );
+ }
+ elsif ( weechat::buffer_get_string($buffer->{"pointer"}, "localvar_type") eq "private" )
+ {
+ # queries_default_fg/bg and buffers.color.queries_message_fg/bg
+ if ( (weechat::config_color($options{"queries_highlight_fg"})) ne "default" ||
+ (weechat::config_color($options{"queries_highlight_bg"})) ne "default" ||
+ (weechat::config_color($options{"queries_message_fg"})) ne "default" ||
+ (weechat::config_color($options{"queries_message_bg"})) ne "default" )
+ {
+ if ( ($hotlist{$buffer->{"pointer"}}) == 2 )
+ {
+ $bg = weechat::config_color( $options{"queries_message_bg"} );
+ $color = weechat::config_color( $options{"queries_message_fg"} );
+ }
+
+ elsif ( ($hotlist{$buffer->{"pointer"}}) == 3 )
+ {
+ $bg = weechat::config_color( $options{"queries_highlight_bg"} );
+ $color = weechat::config_color( $options{"queries_highlight_fg"} );
+ }
+ }else
+ {
+ $bg = weechat::config_color( $options{"color_hotlist_".$hotlist_level{$hotlist{$buffer->{"pointer"}}}."_bg"} );
+ $color = weechat::config_color( $options{"color_hotlist_".$hotlist_level{$hotlist{$buffer->{"pointer"}}}."_fg"} );
+ }
+ }else
+ {
+ $bg = weechat::config_color( $options{"color_hotlist_".$hotlist_level{$hotlist{$buffer->{"pointer"}}}."_bg"} );
+ $color = weechat::config_color( $options{"color_hotlist_".$hotlist_level{$hotlist{$buffer->{"pointer"}}}."_fg"} );
+ }
+ }
+
+ if ($buffer->{"current_buffer"})
+ {
+ $color = weechat::config_color( $options{"color_current_fg"} );
+ $bg = weechat::config_color( $options{"color_current_bg"} );
+ }
+ my $color_bg = "";
+ $color_bg = weechat::color(",".$bg) if ($bg ne "");
+
+ # create channel number for output
+ if ( weechat::config_boolean( $options{"show_number"} ) eq 1 ) # on
+ {
+ if (( weechat::config_boolean( $options{"indenting_number"} ) eq 1)
+ && (($position eq "left") || ($position eq "right")))
+ {
+ $str .= weechat::color("default").$color_bg
+ .(" " x ($max_number_digits - length(int($buffer->{"number"}))));
+ }
+ if ($old_number ne $buffer->{"number"})
+ {
+ $str .= weechat::color( weechat::config_color( $options{"color_number"} ) )
+ .$color_bg
+ .$buffer->{"number"}
+ .weechat::color("default")
+ .$color_bg
+ .weechat::color( weechat::config_color( $options{"color_number_char"} ) )
+ .weechat::config_string( $options{"show_number_char"} )
+ .$color_bg;
+ }
+ else
+ {
+ my $indent = "";
+ $indent = ((" " x length($buffer->{"number"}))." ") if (($position eq "left") || ($position eq "right"));
+ $str .= weechat::color("default")
+ .$color_bg
+ .$indent;
+ }
+ }
+
+ if (( weechat::config_integer( $options{"indenting"} ) ne 0 ) # indenting NOT off
+ && (($position eq "left") || ($position eq "right")))
+ {
+ my $type = weechat::buffer_get_string($buffer->{"pointer"}, "localvar_type");
+ if (($type eq "channel") || ($type eq "private"))
+ {
+ if ( weechat::config_integer( $options{"indenting"} ) eq 1 )
+ {
+ $str .= " ";
+ }
+ elsif ( (weechat::config_integer($options{"indenting"}) eq 2) and (weechat::config_integer($options{"indenting_number"}) eq 0) ) #under_name
+ {
+ if ( weechat::config_boolean( $options{"show_number"} ) eq 0 )
+ {
+ $str .= " ";
+ }else
+ {
+ $str .= ( (" " x ( $max_number_digits - length($buffer->{"number"}) ))." " );
+ }
+ }
+ }
+ }
+ if (weechat::config_boolean( $options{"show_prefix"} ) eq 1)
+ {
+ my $nickname = weechat::buffer_get_string($buffer->{"pointer"}, "localvar_nick");
+ if ($nickname ne "")
+ {
+ # with version >= 0.3.2, this infolist will return only nick
+ # with older versions, whole nicklist is returned for buffer, and this can be very slow
+ my $infolist_nick = weechat::infolist_get("nicklist", $buffer->{"pointer"}, "nick_".$nickname);
+ if ($infolist_nick ne "")
+ {
+ my $version = weechat::info_get("version_number", "");
+ $version = 0 if ($version eq "");
+ while (weechat::infolist_next($infolist_nick))
+ {
+ if ((weechat::infolist_string($infolist_nick, "type") eq "nick")
+ && (weechat::infolist_string($infolist_nick, "name") eq $nickname))
+ {
+ my $prefix = weechat::infolist_string($infolist_nick, "prefix");
+ if (($prefix ne " ") or (weechat::config_boolean( $options{"show_prefix_empty"} ) eq 1))
+ {
+ # with version >= 0.3.5, it is now a color name (for older versions: option name with color)
+ if (int($version) >= 0x00030500)
+ {
+ $str .= weechat::color(weechat::infolist_string($infolist_nick, "prefix_color"));
+ }
+ else
+ {
+ $str .= weechat::color(weechat::config_color(
+ weechat::config_get(
+ weechat::infolist_string($infolist_nick, "prefix_color"))));
+ }
+ $str .= $prefix;
+ }
+ last;
+ }
+ }
+ weechat::infolist_free($infolist_nick);
+ }
+ }
+ }
+ if ($buffer->{"type"} eq "channel" and weechat::config_boolean( $options{"mark_inactive"} ) eq 1 and $buffer->{"nicks_count"} == 0)
+ {
+ $str .= "(";
+ }
+
+ $str .= weechat::color($color) . weechat::color(",".$bg);
+
+ if (weechat::config_boolean( $options{"short_names"} ) eq 1)
+ {
+ if (weechat::config_integer($options{"name_size_max"}) >= 1) # check max_size of buffer name
+ {
+ $str .= encode("UTF-8", substr(decode("UTF-8", $buffer->{"short_name"}), 0, weechat::config_integer($options{"name_size_max"})));
+ $str .= weechat::color(weechat::config_color( $options{"color_number_char"})).weechat::config_string($options{"name_crop_suffix"}) if (length($buffer->{"short_name"}) > weechat::config_integer($options{"name_size_max"}));
+ $str .= add_inactive_parentless($buffer->{"type"},$buffer->{"nicks_count"});
+ $str .= add_hotlist_count($buffer->{"pointer"},%hotlist);
+ }
+ else
+ {
+ #$str .= weechat::buffer_get_string($buffer->{"pointer"},"localvar_server");
+ #$str .= "/";
+ $str .= $buffer->{"short_name"};
+ $str .= add_inactive_parentless($buffer->{"type"},$buffer->{"nicks_count"});
+ $str .= add_hotlist_count($buffer->{"pointer"},%hotlist);
+ }
+ }
+ else
+ {
+ if (weechat::config_integer($options{"name_size_max"}) >= 1) # check max_size of buffer name
+ {
+ $str .= encode("UTF-8", substr(decode("UTF-8", $buffer->{"name"},), 0, weechat::config_integer($options{"name_size_max"})));
+ $str .= weechat::color(weechat::config_color( $options{"color_number_char"})).weechat::config_string($options{"name_crop_suffix"}) if (length($buffer->{"name"}) > weechat::config_integer($options{"name_size_max"}));
+ $str .= add_inactive_parentless($buffer->{"type"},$buffer->{"nicks_count"});
+ $str .= add_hotlist_count($buffer->{"pointer"},%hotlist);
+ }
+ else
+ {
+ $str .= $buffer->{"name"};
+ $str .= add_inactive_parentless($buffer->{"type"},$buffer->{"nicks_count"});
+ $str .= add_hotlist_count($buffer->{"pointer"},%hotlist);
+ }
+ }
+ if ( weechat::buffer_get_string($buffer->{"pointer"}, "localvar_type") eq "server" and weechat::config_boolean($options{"show_lag"}) eq 1)
+ {
+ my $color_lag = weechat::config_color(weechat::config_get("irc.color.item_lag_finished"));
+ my $min_lag = weechat::config_integer(weechat::config_get("irc.network.lag_min_show"));
+ my $infolist_server = weechat::infolist_get("irc_server","",$buffer->{"short_name"});
+ weechat::infolist_next($infolist_server);
+ my $lag = (weechat::infolist_integer($infolist_server, "lag"));
+ weechat::infolist_free($infolist_server);
+ if ( int($lag) > int($min_lag) )
+ {
+ $lag = $lag / 1000;
+ $str .= weechat::color("default") . " (" . weechat::color($color_lag) . $lag . weechat::color("default") . ")";
+ }
+ }
+ $str .= "\n";
+ $old_number = $buffer->{"number"};
+ }
+
+ return $str;
+}
+
+sub add_inactive_parentless
+{
+my ($buf_type, $buf_nicks_count) = @_;
+my $str = "";
+ if ($buf_type eq "channel" and weechat::config_boolean( $options{"mark_inactive"} ) eq 1 and $buf_nicks_count == 0)
+ {
+ $str .= weechat::color(weechat::config_color( $options{"color_number_char"}));
+ $str .= ")";
+ }
+return $str;
+}
+
+sub add_hotlist_count
+{
+my ($bufpointer,%hotlist) = @_;
+
+return "" if ( weechat::config_boolean( $options{"hotlist_counter"} ) eq 0 or ($weechat_version < 0x00030500)); # off
+my $col_number_char = weechat::color(weechat::config_color( $options{"color_number_char"}) );
+my $str = " ".$col_number_char."(";
+
+# 0 = low level
+if (defined $hotlist{$bufpointer."_count_00"})
+{
+ my $bg = weechat::config_color( $options{"color_hotlist_low_bg"} );
+ my $color = weechat::config_color( $options{"color_hotlist_low_fg"} );
+ $str .= weechat::color($bg).
+ weechat::color($color).
+ $hotlist{$bufpointer."_count_00"} if ($hotlist{$bufpointer."_count_00"} ne "0");
+}
+
+# 1 = message
+if (defined $hotlist{$bufpointer."_count_01"})
+{
+ my $bg = weechat::config_color( $options{"color_hotlist_message_bg"} );
+ my $color = weechat::config_color( $options{"color_hotlist_message_fg"} );
+ if ($str =~ /[0-9]$/)
+ {
+ $str .= ",".
+ weechat::color($bg).
+ weechat::color($color).
+ $hotlist{$bufpointer."_count_01"} if ($hotlist{$bufpointer."_count_01"} ne "0");
+ }else
+ {
+ $str .= weechat::color($bg).
+ weechat::color($color).
+ $hotlist{$bufpointer."_count_01"} if ($hotlist{$bufpointer."_count_01"} ne "0");
+ }
+}
+# 2 = private
+if (defined $hotlist{$bufpointer."_count_02"})
+{
+ my $bg = weechat::config_color( $options{"color_hotlist_private_bg"} );
+ my $color = weechat::config_color( $options{"color_hotlist_private_fg"} );
+ if ($str =~ /[0-9]$/)
+ {
+ $str .= ",".
+ weechat::color($bg).
+ weechat::color($color).
+ $hotlist{$bufpointer."_count_02"} if ($hotlist{$bufpointer."_count_02"} ne "0");
+ }else
+ {
+ $str .= weechat::color($bg).
+ weechat::color($color).
+ $hotlist{$bufpointer."_count_02"} if ($hotlist{$bufpointer."_count_02"} ne "0");
+ }
+}
+# 3 = highlight
+if (defined $hotlist{$bufpointer."_count_03"})
+{
+ my $bg = weechat::config_color( $options{"color_hotlist_highlight_bg"} );
+ my $color = weechat::config_color( $options{"color_hotlist_highlight_fg"} );
+ if ($str =~ /[0-9]$/)
+ {
+ $str .= ",".
+ weechat::color($bg).
+ weechat::color($color).
+ $hotlist{$bufpointer."_count_03"} if ($hotlist{$bufpointer."_count_03"} ne "0");
+ }else
+ {
+ $str .= weechat::color($bg).
+ weechat::color($color).
+ $hotlist{$bufpointer."_count_03"} if ($hotlist{$bufpointer."_count_03"} ne "0");
+ }
+}
+$str .= $col_number_char. ")";
+
+$str = "" if (weechat::string_remove_color($str, "") eq " ()"); # remove color and check for buffer with no messages
+return $str;
+}
+
+sub buffers_signal_buffer
+{
+my ($data, $signal, $signal_data) = @_;
+ # check for buffer_switch and set or remove detach time
+ if ($weechat_version >= 0x00030800)
+ {
+ if ($signal eq "buffer_switch")
+ {
+ my $pointer = weechat::hdata_get_list (weechat::hdata_get("buffer"), "gui_buffer_last_displayed"); # get switched buffer
+ my $current_time = time();
+ if ( weechat::buffer_get_string($pointer, "localvar_type") eq "channel")
+ {
+ $buffers_timer{$pointer} = $current_time;
+ }
+ else
+ {
+ delete $buffers_timer{$pointer};
+ }
+ }
+ if ($signal eq "buffer_opened")
+ {
+ my $current_time = time();
+ $buffers_timer{$signal_data} = $current_time;
+ }
+ if ($signal eq "buffer_closing")
+ {
+ delete $buffers_timer{$signal_data};
+ }
+ }
+
+ weechat::bar_item_update("buffers");
+ return weechat::WEECHAT_RC_OK;
+}
+
+sub buffers_signal_hotlist
+{
+ weechat::bar_item_update("buffers");
+ return weechat::WEECHAT_RC_OK;
+}
+
+
+sub buffers_signal_config_whitelist
+{
+ @whitelist_buffers = ();
+ @whitelist_buffers = split( /,/, weechat::config_string( $options{"look_whitelist_buffers"} ) );
+ weechat::bar_item_update("buffers");
+ return weechat::WEECHAT_RC_OK;
+}
+sub buffers_signal_config_immune_detach_buffers
+{
+ @immune_detach_buffers = ();
+ @immune_detach_buffers = split( /,/, weechat::config_string( $options{"immune_detach_buffers"} ) );
+ weechat::bar_item_update("buffers");
+ return weechat::WEECHAT_RC_OK;
+}
+
+sub buffers_signal_config
+{
+ weechat::bar_item_update("buffers");
+ return weechat::WEECHAT_RC_OK;
+}
+
+# called when mouse click occured in buffers item: this callback returns buffer
+# hash according to line of item where click occured
+sub buffers_focus_buffers
+{
+ my %info = %{$_[1]};
+ my $item_line = int($info{"_bar_item_line"});
+ undef my $hash;
+ if (($info{"_bar_item_name"} eq "buffers") && ($item_line >= 0) && ($item_line <= $#buffers_focus))
+ {
+ $hash = $buffers_focus[$item_line];
+ }
+ else
+ {
+ $hash = {};
+ my $hash_focus = $buffers_focus[0];
+ foreach my $key (keys %$hash_focus)
+ {
+ $hash->{$key} = "?";
+ }
+ }
+ return $hash;
+}
+
+# called when a mouse action is done on buffers item, to execute action
+# possible actions: jump to a buffer or move buffer in list (drag & drop of buffer)
+sub buffers_hsignal_mouse
+{
+ my ($data, $signal, %hash) = ($_[0], $_[1], %{$_[2]});
+ my $current_buffer = weechat::buffer_get_integer(weechat::current_buffer(), "number"); # get current buffer number
+
+ if ( $hash{"_key"} eq "button1" ) # left mouse button
+ {
+ if ($hash{"number"} eq $hash{"number2"})
+ {
+ if ( weechat::config_integer($options{"jump_prev_next_visited_buffer"}) eq 1 )
+ {
+ if ( $current_buffer eq $hash{"number"} )
+ {
+ weechat::command("","/input jump_previously_visited_buffer");
+ }
+ else
+ {
+ weechat::command("", "/buffer ".$hash{"full_name"});
+ }
+ }
+ else
+ {
+ weechat::command("", "/buffer ".$hash{"full_name"});
+ }
+ }
+ else
+ {
+ move_buffer(%hash);
+ }
+ }
+ elsif ( ($hash{"_key"} eq "button2") && (weechat::config_integer($options{"jump_prev_next_visited_buffer"}) eq 1) )# right mouse button
+ {
+ if ( $current_buffer eq $hash{"number2"} )
+ {
+ weechat::command("","/input jump_next_visited_buffer");
+ }
+ }
+ else
+ {
+ my $infolist = weechat::infolist_get("hook", "", "command,menu");
+ my $has_menu_command = weechat::infolist_next($infolist);
+ weechat::infolist_free($infolist);
+
+ if ( $has_menu_command && $hash{"_key"} =~ /button2/ )
+ {
+ if ($hash{"number"} eq $hash{"number2"})
+ {
+ weechat::command($hash{"pointer"}, "/menu buffer1 $hash{short_name} $hash{number}");
+ }
+ else
+ {
+ weechat::command($hash{"pointer"}, "/menu buffer2 $hash{short_name}/$hash{short_name2} $hash{number} $hash{number2}")
+ }
+ }
+ else
+ {
+ move_buffer(%hash);
+ }
+ }
+}
+
+sub move_buffer
+{
+ my %hash = @_;
+ my $number2 = $hash{"number2"};
+ if ($number2 eq "?")
+ {
+ # if number 2 is not known (end of gesture outside buffers list), then set it
+ # according to mouse gesture
+ $number2 = "999999";
+ $number2 = "1" if (($hash{"_key"} =~ /gesture-left/) || ($hash{"_key"} =~ /gesture-up/));
+ }
+ my $ptrbuf = weechat::current_buffer();
+ weechat::command($hash{"pointer"}, "/buffer move ".$number2);
+}
+
+sub check_immune_detached_buffers
+{
+ my ($buffername) = @_;
+ foreach ( @immune_detach_buffers ){
+ my $immune_buffer = weechat::string_mask_to_regex($_);
+ if ($buffername =~ /^$immune_buffer$/i)
+ {
+ return 1;
+ }
+ }
+ return 0;
+}
diff --git a/weechat/perl/highmon.pl b/weechat/perl/highmon.pl
new file mode 100644
index 0000000..b7e0aae
--- /dev/null
+++ b/weechat/perl/highmon.pl
@@ -0,0 +1,1064 @@
+#
+# highmon.pl - Highlight Monitoring for weechat 0.3.0
+# Version 2.3.2
+#
+# Add 'Highlight Monitor' buffer/bar to log all highlights in one spot
+#
+# Usage:
+# /highmon [help] | [monitor [channel [server]]] | [clean default|orphan|all]
+# Command wrapper for highmon commands
+#
+# /highmon clean default|orphan|all will clean the config section of default 'on' entries,
+# channels you are no longer joined, or both
+#
+# /highmon monitor [channel] [server] is used to toggle a highlight monitoring on and off, this
+# can be used in the channel buffer for the channel you wish to toggle, or be given
+# with arguments e.g. /highmon monitor #weechat freenode
+#
+# /set plugins.var.perl.highmon.alignment
+# The config setting "alignment" can be changed to;
+# "channel", "schannel", "nchannel", "channel,nick", "schannel,nick", "nchannel,nick"
+# to change how the monitor appears
+# The 'channel' value will show: "#weechat"
+# The 'schannel' value will show: "6"
+# The 'nchannel' value will show: "6:#weechat"
+#
+# /set plugins.var.perl.highmon.short_names
+# Setting this to 'on' will trim the network name from highmon, ala buffers.pl
+#
+# /set plugins.var.perl.highmon.merge_private
+# Setting this to 'on' will merge private messages to highmon's display
+#
+# /set plugins.var.perl.highmon.color_buf
+# This turns colored buffer names on or off, you can also set a single fixed color by using a weechat color name.
+# This *must* be a valid color name, or weechat will likely do unexpected things :)
+#
+# /set plugins.var.perl.highmon.hotlist_show
+# Setting this to 'on' will let the highmon buffer appear in hotlists
+# (status bar/buffer.pl)
+#
+# /set plugins.var.perl.highmon.away_only
+# Setting this to 'on' will only put messages in the highmon buffer when
+# you set your status to away
+#
+# /set plugins.var.perl.highmon.logging
+# Toggles logging status for highmon buffer (default: off)
+#
+# /set plugins.var.perl.highmon.output
+# Changes where output method of highmon; takes either "bar" or "buffer" (default; buffer)
+# /set plugins.var.perl.highmon.bar_lines
+# Changes the amount of lines the output bar will hold.
+# (Only appears once output has been set to bar, defaults to 10)
+# /set plugins.var.perl.highmon.bar_scrolldown
+# Toggles the bar scrolling at the bottom when new highlights are received
+# (Only appears once output has been set to bar, defaults to off)
+#
+# /set plugins.var.perl.highmon.nick_prefix
+# /set plugins.var.perl.highmon.nick_suffix
+# Sets the prefix and suffix chars in the highmon buffer
+# (Defaults to <> if nothing set, and blank if there is)
+#
+# servername.#channel
+# servername is the internal name for the server (set when you use /server add)
+# #channel is the channel name, (where # is whatever channel type that channel happens to be)
+#
+
+# Bugs and feature requests at: https://github.com/KenjiE20/highmon
+
+# History:
+# 2013-01-15, KenjiE20 <longbow@longbowslair.co.uk>:
+# v2.3.2: -fix: Let bar output use the string set in weechat's config option
+# -add: github info
+# 2012-04-15, KenjiE20 <longbow@longbowslair.co.uk>:
+# v2.3.1: -fix: Colour tags in bar timestamp string
+# 2012-02-28, KenjiE20 <longbow@longbowslair.co.uk>:
+# v2.3: -feature: Added merge_private option to display private messages (default: off)
+# -fix: Channel name colours now show correctly when set to on
+# 2011-08-07, Sitaktif <romainchossart_at_gmail.com>:
+# v2.2.1: -feature: Add "bar_scrolldown" option to have the bar display the latest hl at anytime
+# -fix: Set up bar-specific config at startup if 'output' is already configured as 'bar'
+# 2010-12-22, KenjiE20 <longbow@longbowslair.co.uk>:
+# v2.2: -change: Use API instead of config to find channel colours, ready for 0.3.4 and 256 colours
+# 2010-12-13, idl0r & KenjiE20 <longbow@longbowslair.co.uk>:
+# v2.1.3: -fix: perl errors caused by bar line counter
+# -fix: Add command list to inbuilt help
+# 2010-09-30, KenjiE20 <longbow@longbowslair.co.uk>:
+# v2.1.2: -fix: logging config was not correctly toggling back on (thanks to sleo for noticing)
+# -version sync w/ chanmon
+# 2010-08-27, KenjiE20 <longbow@longbowslair.co.uk>:
+# v2.1: -feature: Add 'nchannel' option to alignment to display buffer and name
+# 2010-04-25, KenjiE20 <longbow@longbowslair.co.uk>:
+# v2.0: Release as version 2.0
+# 2010-04-24, KenjiE20 <longbow@longbowslair.co.uk>:
+# v1.9: Rewrite for v2.0
+# Bring feature set in line with chanmon 2.0
+# -code change: Made more subs to shrink the code down in places
+# -fix: Stop highmon attempting to double load/hook
+# -fix: Add version dependant check for away status
+# 2010-01-25, KenjiE20 <longbow@longbowslair.co.uk>:
+# v1.7: -fixture: Let highmon be aware of nick_prefix/suffix
+# and allow custom prefix/suffix for chanmon buffer
+# (Defaults to <> if nothing set, and blank if there is)
+# (Thanks to m4v for these)
+# 2009-09-07, KenjiE20 <longbow@longbowslair.co.uk>:
+# v1.6: -feature: colored buffer names
+# -change: version sync with chanmon
+# 2009-09-05, KenjiE20 <longbow@longbowslair.co.uk>:
+# v1.2: -fix: disable buffer highlight
+# 2009-09-02, KenjiE20 <longbow@longbowslair.co.uk>:
+# v.1.1.1 -change: Stop unsightly text block on '/help'
+# 2009-08-10, KenjiE20 <longbow@longbowslair.co.uk>:
+# v1.1: In-client help added
+# 2009-08-02, KenjiE20 <longbow@longbowslair.co.uk>:
+# v1.0: Initial Public Release
+
+# Copyright (c) 2009 by KenjiE20 <longbow@longbowslair.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 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/>.
+#
+
+@bar_lines = ();
+@bar_lines_time = ();
+# Replicate info earlier for in-client help
+
+$highmonhelp = weechat::color("bold")."/highmon [help] | [monitor [channel [server]]] | [clean default|orphan|all]".weechat::color("-bold")."
+ Command wrapper for highmon commands
+
+".weechat::color("bold")."/highmon clean default|orphan|all".weechat::color("-bold")." will clean the config section of default 'on' entries, channels you are no longer joined, or both
+
+".weechat::color("bold")."/highmon monitor [channel] [server]".weechat::color("-bold")." is used to toggle a highlight monitoring on and off, this can be used in the channel buffer for the channel you wish to toggle, or be given with arguments e.g. /highmon monitor #weechat freenode
+
+".weechat::color("bold")."/set plugins.var.perl.highmon.alignment".weechat::color("-bold")."
+ The config setting \"alignment\" can be changed to;
+ \"channel\", \"schannel\", \"nchannel\", \"channel,nick\", \"schannel,nick\", \"nchannel,nick\"
+ to change how the monitor appears
+ The 'channel' value will show: \"#weechat\"
+ The 'schannel' value will show: \"6\"
+ The 'nchannel' value will show: \"6:#weechat\"
+
+".weechat::color("bold")."/set plugins.var.perl.highmon.short_names".weechat::color("-bold")."
+ Setting this to 'on' will trim the network name from highmon, ala buffers.pl
+
+".weechat::color("bold")."/set plugins.var.perl.highmon.merge_private".weechat::color("-bold")."
+ Setting this to 'on' will merge private messages to highmon's display
+
+".weechat::color("bold")."/set plugins.var.perl.highmon.color_buf".weechat::color("-bold")."
+ This turns colored buffer names on or off, you can also set a single fixed color by using a weechat color name.
+ This ".weechat::color("bold")."must".weechat::color("-bold")." be a valid color name, or weechat will likely do unexpected things :)
+
+".weechat::color("bold")."/set plugins.var.perl.highmon.hotlist_show".weechat::color("-bold")."
+Setting this to 'on' will let the highmon buffer appear in hotlists (status bar/buffer.pl)
+
+".weechat::color("bold")."/set plugins.var.perl.highmon.away_only".weechat::color("-bold")."
+Setting this to 'on' will only put messages in the highmon buffer when you set your status to away
+
+".weechat::color("bold")."/set plugins.var.perl.highmon.logging".weechat::color("-bold")."
+ Toggles logging status for highmon buffer (default: off)
+
+".weechat::color("bold")."/set plugins.var.perl.highmon.output".weechat::color("-bold")."
+ Changes where output method of highmon; takes either \"bar\" or \"buffer\" (default; buffer)
+".weechat::color("bold")."/set plugins.var.perl.highmon.bar_lines".weechat::color("-bold")."
+ Changes the amount of lines the output bar will hold.
+ (Only appears once output has been set to bar, defaults to 10)
+".weechat::color("bold")."/set plugins.var.perl.highmon.bar_scrolldown".weechat::color("-bold")."
+ Toggles the bar scrolling at the bottom when new highlights are received
+ (Only appears once output has been set to bar, defaults to off)
+
+".weechat::color("bold")."/set plugins.var.perl.highmon.nick_prefix".weechat::color("-bold")."
+".weechat::color("bold")."/set plugins.var.perl.highmon.nick_suffix".weechat::color("-bold")."
+ Sets the prefix and suffix chars in the highmon buffer
+ (Defaults to <> if nothing set, and blank if there is)
+
+".weechat::color("bold")."servername.#channel".weechat::color("-bold")."
+ servername is the internal name for the server (set when you use /server add)
+ #channel is the channel name, (where # is whatever channel type that channel happens to be)";
+# Print verbose help
+sub print_help
+{
+ weechat::print("", "\t".weechat::color("bold")."Highmon Help".weechat::color("-bold")."\n\n");
+ weechat::print("", "\t".$highmonhelp);
+ return weechat::WEECHAT_RC_OK;
+}
+
+# Bar item build
+sub highmon_bar_build
+{
+ # Get max lines
+ $max_lines = weechat::config_get_plugin("bar_lines");
+ $max_lines = $max_lines ? $max_lines : 10;
+ $str = '';
+ $align_num = 0;
+ $count = 0;
+ # Keep lines within max
+ while ($#bar_lines > $max_lines)
+ {
+ shift(@bar_lines);
+ shift(@bar_lines_time);
+ }
+ # So long as we have some lines, build a string
+ if (@bar_lines)
+ {
+ # Build loop
+ $sep = " ".weechat::config_string(weechat::config_get("weechat.look.prefix_suffix"))." ";
+ foreach(@bar_lines)
+ {
+ # Find max align needed
+ $prefix_num = (index(weechat::string_remove_color($_, ""), $sep));
+ $align_num = $prefix_num if ($prefix_num > $align_num);
+ }
+ foreach(@bar_lines)
+ {
+ # Get align for this line
+ $prefix_num = (index(weechat::string_remove_color($_, ""), $sep));
+
+ # Make string
+ $str = $str.$bar_lines_time[$count]." ".(" " x ($align_num - $prefix_num)).$_."\n";
+ # Increment count for sync with time list
+ $count++;
+ }
+ }
+ return $str;
+}
+
+# Make a new bar
+sub highmon_bar_open
+{
+ # Make the bar item
+ weechat::bar_item_new("highmon", "highmon_bar_build", "");
+
+ $highmon_bar = weechat::bar_new ("highmon", "off", 100, "root", "", "bottom", "vertical", "vertical", 0, 0, "default", "cyan", "default", "on", "highmon");
+
+ return weechat::WEECHAT_RC_OK;
+}
+# Close bar
+sub highmon_bar_close
+{
+ # Find if bar exists
+ $highmon_bar = weechat::bar_search("highmon");
+ # If is does, close it
+ if ($highmon_bar ne "")
+ {
+ weechat::bar_remove($highmon_bar);
+ }
+
+ # Find if bar item exists
+ $highmon_bar_item = weechat::bar_item_search("highmon_bar");
+ # If is does, close it
+ if ($highmon_bar_item ne "")
+ {
+ weechat::bar_remove($highmon_bar_item);
+ }
+
+ @bar_lines = ();
+ return weechat::WEECHAT_RC_OK;
+}
+
+# Make a new buffer
+sub highmon_buffer_open
+{
+ # Search for pre-existing buffer
+ $highmon_buffer = weechat::buffer_search("perl", "highmon");
+
+ # Make a new buffer
+ if ($highmon_buffer eq "")
+ {
+ $highmon_buffer = weechat::buffer_new("highmon", "highmon_buffer_input", "", "highmon_buffer_close", "");
+ }
+
+ # Turn off notify, highlights
+ if ($highmon_buffer ne "")
+ {
+ if (weechat::config_get_plugin("hotlist_show" eq "off"))
+ {
+ weechat::buffer_set($highmon_buffer, "notify", "0");
+ }
+ weechat::buffer_set($highmon_buffer, "highlight_words", "-");
+ weechat::buffer_set($highmon_buffer, "title", "Highlight Monitor");
+ # Set no_log
+ if (weechat::config_get_plugin("logging") eq "off")
+ {
+ weechat::buffer_set($highmon_buffer, "localvar_set_no_log", "1");
+ }
+ }
+ return weechat::WEECHAT_RC_OK;
+}
+# Buffer input has no action
+sub highmon_buffer_input
+{
+ return weechat::WEECHAT_RC_OK;
+}
+# Close up
+sub highmon_buffer_close
+{
+ $highmon_buffer = "";
+ return weechat::WEECHAT_RC_OK;
+}
+
+# Highmon command wrapper
+sub highmon_command_cb
+{
+ $data = $_[0];
+ $buffer = $_[1];
+ $args = $_[2];
+ my $cmd = '';
+ my $arg = '';
+
+ if ($args ne "")
+ {
+ # Split argument up
+ @arg_array = split(/ /,$args);
+ # Take first as command
+ $cmd = shift(@arg_array);
+ # Rebuild string to pass to subs
+ if (@arg_array)
+ {
+ $arg = join(" ", @arg_array);
+ }
+ }
+
+ # Help command
+ if ($cmd eq "" || $cmd eq "help")
+ {
+ print_help();
+ }
+ # /monitor command
+ elsif ($cmd eq "monitor")
+ {
+ highmon_toggle($data, $buffer, $arg);
+ }
+ # /highclean command
+ elsif ($cmd eq "clean")
+ {
+ highmon_config_clean($data, $buffer, $arg);
+ }
+ return weechat::WEECHAT_RC_OK;
+}
+
+# Clean up config entries
+sub highmon_config_clean
+{
+ $data = $_[0];
+ $buffer = $_[1];
+ $args = $_[2];
+
+ # Don't do anything if bad option given
+ if ($args ne "default" && $args ne "orphan" && $args ne "all")
+ {
+ weechat::print("", "\thighmon.pl: Unknown option");
+ return weechat::WEECHAT_RC_OK;
+ }
+
+ @chans = ();
+ # Load an infolist of highmon options
+ $infolist = weechat::infolist_get("option", "", "*highmon*");
+ while (weechat::infolist_next($infolist))
+ {
+ $name = weechat::infolist_string($infolist, "option_name");
+ $name =~ s/perl\.highmon\.(\w*)\.([#&\+!])(.*)/$1.$2$3/;
+ if ($name =~ /^(.*)\.([#&\+!])(.*)$/)
+ {
+ $action = 0;
+ # Clean up all 'on's
+ if ($args eq "default" || $args eq "all")
+ {
+ # If value in config is "on"
+ if (weechat::config_get_plugin($name) eq "on")
+ {
+ # Unset and if successful flag as changed
+ $rc = weechat::config_unset_plugin($name);
+ if ($rc eq weechat::WEECHAT_CONFIG_OPTION_UNSET_OK_REMOVED)
+ {
+ $action = 1;
+ }
+ }
+ }
+ # Clean non joined
+ if ($args eq "orphan" || $args eq "all")
+ {
+ # If we can't find the buffer for this entry
+ if (weechat::buffer_search("irc", $name) eq "")
+ {
+ # Unset and if successful flag as changed
+ $rc = weechat::config_unset_plugin($name);
+ if ($rc eq weechat::WEECHAT_CONFIG_OPTION_UNSET_OK_REMOVED)
+ {
+ $action = 1;
+ }
+ }
+ }
+ # Add changed entry names to list
+ push (@chans, $name) if ($action);
+ }
+ }
+ weechat::infolist_free($infolist);
+ # If channels were cleaned from config
+ if (@chans)
+ {
+ # If only one entry
+ if (@chans == 1)
+ {
+ $str = "\thighmon.pl: Cleaned ".@chans." entry from the config:";
+ }
+ else
+ {
+ $str = "\thighmon.pl: Cleaned ".@chans." entries from the config:";
+ }
+ # Build a list of channels
+ foreach(@chans)
+ {
+ $str = $str." ".$_;
+ }
+ # Print what happened
+ weechat::print("",$str);
+ }
+ # Config seemed to be clean
+ else
+ {
+ weechat::print("", "\thighmon.pl: No entries removed");
+ }
+ return weechat::WEECHAT_RC_OK;
+}
+
+# Check config elements
+sub highmon_config_init
+{
+ # Alignment default
+ if (!(weechat::config_is_set_plugin ("alignment")))
+ {
+ weechat::config_set_plugin("alignment", "channel");
+ }
+ if (weechat::config_get_plugin("alignment") eq "")
+ {
+ weechat::config_set_plugin("alignment", "none");
+ }
+
+ # Short name default
+ if (!(weechat::config_is_set_plugin ("short_names")))
+ {
+ weechat::config_set_plugin("short_names", "off");
+ }
+
+ # Coloured names default
+ if (!(weechat::config_is_set_plugin ("color_buf")))
+ {
+ weechat::config_set_plugin("color_buf", "on");
+ }
+
+ # Hotlist show default
+ if (!(weechat::config_is_set_plugin ("hotlist_show")))
+ {
+ weechat::config_set_plugin("hotlist_show", "off");
+ }
+
+ # Away only default
+ if (!(weechat::config_is_set_plugin ("away_only")))
+ {
+ weechat::config_set_plugin("away_only", "off");
+ }
+
+ # highmon log default
+ if (!(weechat::config_is_set_plugin ("logging")))
+ {
+ weechat::config_set_plugin("logging", "off");
+ }
+
+ # Output default
+ if (!(weechat::config_is_set_plugin ("output")))
+ {
+ weechat::config_set_plugin("output", "buffer");
+ }
+
+ # Private message merging
+ if (!(weechat::config_is_set_plugin ("merge_private")))
+ {
+ weechat::config_set_plugin("merge_private", "off");
+ }
+
+ # Set bar config in case output was set to "bar" before even changing the setting
+ if (weechat::config_get_plugin("output") eq "bar")
+ {
+ # Output bar lines default
+ if (!(weechat::config_is_set_plugin ("bar_lines")))
+ {
+ weechat::config_set_plugin("bar_lines", "10");
+ }
+ if (!(weechat::config_is_set_plugin ("bar_scrolldown")))
+ {
+ weechat::config_set_plugin("bar_scrolldown", "off");
+ }
+ }
+
+ # Check for exisiting prefix/suffix chars, and setup accordingly
+ $prefix = weechat::config_get("irc.look.nick_prefix");
+ $prefix = weechat::config_string($prefix);
+ $suffix = weechat::config_get("irc.look.nick_suffix");
+ $suffix = weechat::config_string($suffix);
+
+ if (!(weechat::config_is_set_plugin("nick_prefix")))
+ {
+ if ($prefix eq "" && $suffix eq "")
+ {
+ weechat::config_set_plugin("nick_prefix", "<");
+ }
+ else
+ {
+ weechat::config_set_plugin("nick_prefix", "");
+ }
+ }
+
+ if (!(weechat::config_is_set_plugin("nick_suffix")))
+ {
+ if ($prefix eq "" && $suffix eq "")
+ {
+ weechat::config_set_plugin("nick_suffix", ">");
+ }
+ else
+ {
+ weechat::config_set_plugin("nick_suffix", "");
+ }
+ }
+}
+
+# Get config updates
+sub highmon_config_cb
+{
+ $point = $_[0];
+ $name = $_[1];
+ $value = $_[2];
+
+ $name =~ s/^plugins\.var\.perl\.highmon\.//;
+
+ # Set logging on buffer
+ if ($name eq "logging")
+ {
+ # Search for pre-existing buffer
+ $highmon_buffer = weechat::buffer_search("perl", "highmon");
+ if ($value eq "off")
+ {
+ weechat::buffer_set($highmon_buffer, "localvar_set_no_log", "1");
+ }
+ else
+ {
+ weechat::buffer_set($highmon_buffer, "localvar_del_no_log", "");
+ }
+ }
+ # Output changer
+ elsif ($name eq "output")
+ {
+ if ($value eq "bar")
+ {
+ # Search for pre-existing buffer
+ $highmon_buffer = weechat::buffer_search("perl", "highmon");
+ # Close if it exists
+ if ($highmon_buffer ne "")
+ {
+ weechat::buffer_close($highmon_buffer)
+ }
+
+ # Output bar lines default
+ if (!(weechat::config_is_set_plugin ("bar_lines")))
+ {
+ weechat::config_set_plugin("bar_lines", "10");
+ }
+ if (!(weechat::config_is_set_plugin ("bar_scrolldown")))
+ {
+ weechat::config_set_plugin("bar_scrolldown", "off");
+ }
+ # Make a bar if doesn't exist
+ highmon_bar_open();
+ }
+ elsif ($value eq "buffer")
+ {
+ # If a bar exists, close it
+ highmon_bar_close();
+ # Open buffer
+ highmon_buffer_open();
+ }
+
+ }
+ # Change if hotlist config changes
+ elsif ($name eq "hotlist_show")
+ {
+ # Search for pre-existing buffer
+ $highmon_buffer = weechat::buffer_search("perl", "highmon");
+ if ($value eq "off" && $highmon_buffer)
+ {
+ weechat::buffer_set($highmon_buffer, "notify", "0");
+ }
+ elsif ($value ne "off" && $highmon_buffer)
+ {
+ weechat::buffer_set($highmon_buffer, "notify", "3");
+ }
+ }
+ elsif ($name eq "weechat.look.prefix_suffix")
+ {
+ if (weechat::config_get_plugin("output") eq "bar")
+ {
+ @bar_lines = ();
+ weechat::print("", "\thighmon: weechat.look.prefix_suffix changed, clearing highmon bar");
+ weechat::bar_item_update("highmon");
+ }
+ }
+ return weechat::WEECHAT_RC_OK;
+}
+
+# Set up weechat hooks / commands
+sub highmon_hook
+{
+ weechat::hook_print("", "", "", 0, "highmon_new_message", "");
+ weechat::hook_command("highclean", "Highmon config clean up", "default|orphan|all", " default: Cleans all config entries with the default \"on\" value\n orphan: Cleans all config entries for channels you aren't currently joined\n all: Does both defaults and orphan", "default|orphan|all", "highmon_config_clean", "");
+
+ weechat::hook_command("highmon", "Highmon help", "[help] | [monitor [channel [server]]] | [clean default|orphan|all]", " help: Print help on config options for highmon\n monitor: Toggles monitoring for a channel\n clean: Highmon config clean up (/highclean)", "help || monitor %(irc_channels) %(irc_servers) || clean default|orphan|all", "highmon_command_cb", "");
+
+ weechat::hook_config("plugins.var.perl.highmon.*", "highmon_config_cb", "");
+ weechat::hook_config("weechat.look.prefix_suffix", "highmon_config_cb", "");
+}
+
+# Main body, Callback for hook_print
+sub highmon_new_message
+{
+ my $net = "";
+ my $chan = "";
+ my $nick = "";
+ my $outstr = "";
+ my $window_displayed = "";
+ my $dyncheck = "0";
+
+# DEBUG point
+# $string = "\t"."0: ".$_[0]." 1: ".$_[1]." 2: ".$_[2]." 3: ".$_[3]." 4: ".$_[4]." 5: ".$_[5]." 6: ".$_[6]." 7: ".$_[7];
+# weechat::print("", "\t".$string);
+
+ $cb_datap = $_[0];
+ $cb_bufferp = $_[1];
+ $cb_date = $_[2];
+ $cb_tags = $_[3];
+ $cb_disp = $_[4];
+ $cb_high = $_[5];
+ $cb_prefix = $_[6];
+ $cb_msg = $_[7];
+
+ # Only work on highlighted messages or private message when enabled
+ if ($cb_high == "1" || (weechat::config_get_plugin("merge_private") eq "on" && $cb_tags =~ /notify_private/))
+ {
+ # Pre bug #29618 (0.3.3) away detect
+ if (weechat::info_get("version_number", "") <= 197120)
+ {
+ $away = '';
+ # Get infolist for this server
+ $infolist = weechat::infolist_get("irc_server", "", weechat::buffer_get_string($cb_bufferp, "localvar_server"));
+ while (weechat::infolist_next($infolist))
+ {
+ # Get away message is is_away is on
+ $away = weechat::infolist_string($infolist, "away_message") if (weechat::infolist_integer($infolist, "is_away"));
+ }
+ weechat::infolist_free($infolist);
+ }
+ # Post bug #29618 fix
+ else
+ {
+ $away = weechat::buffer_get_string($cb_bufferp, "localvar_away");
+ }
+ if (weechat::config_get_plugin("away_only") ne "on" || ($away ne ""))
+ {
+ # Check buffer name is an IRC channel
+ $bufname = weechat::buffer_get_string($cb_bufferp, 'name');
+ if ($bufname =~ /(.*)\.([#&\+!])(.*)/)
+ {
+ # Are we running on this channel
+ if (weechat::config_get_plugin($bufname) ne "off" && $cb_disp eq "1")
+ {
+ # Format nick
+ # Line isn't action or topic notify
+ if (!($cb_tags =~ /irc_action/) && !($cb_tags =~ /irc_topic/))
+ {
+ # Strip nick colour
+ $uncolnick = weechat::string_remove_color($cb_prefix, "");
+ # Format nick
+ $nick = " ".weechat::config_get_plugin("nick_prefix").weechat::color("chat_highlight").$uncolnick.weechat::color("reset").weechat::config_get_plugin("nick_suffix");
+ }
+ # Topic line
+ elsif ($cb_tags =~ /irc_topic/)
+ {
+ $nick = " ".$cb_prefix.weechat::color("reset");
+ }
+ # Action line
+ else
+ {
+ $uncolnick = weechat::string_remove_color($cb_prefix, "");
+ $nick = weechat::color("chat_highlight").$uncolnick.weechat::color("reset");
+ }
+ # Send to output
+ highmon_print ($cb_msg, $cb_bufferp, $nick);
+ }
+ }
+ # Or is private message
+ elsif (weechat::config_get_plugin("merge_private") eq "on" && $cb_tags =~ /notify_private/)
+ {
+ # Strip nick colour
+ $uncolnick = weechat::buffer_get_string($cb_bufferp, 'short_name');
+ # Format nick
+ $nick = " ".weechat::config_get_plugin("nick_prefix").weechat::color("chat_highlight").$uncolnick.weechat::color("reset").weechat::config_get_plugin("nick_suffix");
+ #Send to output
+ highmon_print ($cb_msg, $cb_bufferp, $nick);
+ }
+ }
+ }
+ return weechat::WEECHAT_RC_OK;
+}
+
+# Output formatter and printer takes (msg bufpointer nick)
+sub highmon_print
+{
+ $cb_msg = $_[0];
+ my $cb_bufferp = $_[1] if ($_[1]);
+ my $nick = $_[2] if ($_[2]);
+
+ #Normal channel message
+ if ($cb_bufferp && $nick)
+ {
+ # Format buffer name
+ $bufname = format_buffer_name($cb_bufferp);
+
+ # If alignment is #channel | nick msg
+ if (weechat::config_get_plugin("alignment") eq "channel")
+ {
+ $nick =~ s/\s(.*)/$1/;
+ # Build string
+ $outstr = $bufname."\t".$nick." ".$cb_msg;
+ }
+ # or if it is channel number | nick msg
+ elsif (weechat::config_get_plugin("alignment") eq "schannel")
+ {
+ $nick =~ s/\s(.*)/$1/;
+ # Use channel number instead
+ $bufname = weechat::color("chat_prefix_buffer").weechat::buffer_get_integer($cb_bufferp, 'number').weechat::color("reset");
+ # Build string
+ $outstr = $bufname."\t".$nick." ".$cb_msg;
+ }
+ # or if it is number:#channel | nick msg
+ elsif (weechat::config_get_plugin("alignment") eq "nchannel")
+ {
+ $nick =~ s/\s(.*)/$1/;
+ # Place channel number in front of formatted name
+ $bufname = weechat::color("chat_prefix_buffer").weechat::buffer_get_integer($cb_bufferp, 'number').":".weechat::color("reset").$bufname;
+ # Build string
+ $outstr = $bufname."\t".$nick." ".$cb_msg;
+ }
+ # or if it is #channel nick | msg
+ elsif (weechat::config_get_plugin("alignment") eq "channel,nick")
+ {
+ # Build string
+ $outstr = $bufname.":".$nick."\t".$cb_msg;
+ }
+ # or if it is channel number nick | msg
+ elsif (weechat::config_get_plugin("alignment") eq "schannel,nick")
+ {
+ # Use channel number instead
+ $bufname = weechat::color("chat_prefix_buffer").weechat::buffer_get_integer($cb_bufferp, 'number').weechat::color("reset");
+ # Build string
+ $outstr = $bufname.":".$nick."\t".$cb_msg;
+ }
+ # or if it is number:#channel nick | msg
+ elsif (weechat::config_get_plugin("alignment") eq "nchannel,nick")
+ {
+ # Place channel number in front of formatted name
+ $bufname = weechat::color("chat_prefix_buffer").weechat::buffer_get_integer($cb_bufferp, 'number').":".weechat::color("reset").$bufname;
+ # Build string
+ $outstr = $bufname.":".$nick."\t".$cb_msg;
+ }
+ # or finally | #channel nick msg
+ else
+ {
+ # Build string
+ $outstr = "\t".$bufname.":".$nick." ".$cb_msg;
+ }
+ }
+ # highmon channel toggle message
+ elsif ($cb_bufferp && !$nick)
+ {
+ # Format buffer name
+ $bufname = format_buffer_name($cb_bufferp);
+
+ # If alignment is #channel * | *
+ if (weechat::config_get_plugin("alignment") =~ /channel/)
+ {
+ # If it's actually channel number * | *
+ if (weechat::config_get_plugin("alignment") =~ /schannel/)
+ {
+ # Use channel number instead
+ $bufname = weechat::color("chat_prefix_buffer").weechat::buffer_get_integer($cb_bufferp, 'number').weechat::color("reset");
+ }
+ # Or if it's actually number:#channel * | *
+ if (weechat::config_get_plugin("alignment") =~ /nchannel/)
+ {
+ # Place channel number in front of formatted name
+ $bufname = weechat::color("chat_prefix_buffer").weechat::buffer_get_integer($cb_bufferp, 'number').":".weechat::color("reset").$bufname;
+ }
+ $outstr = $bufname."\t".$cb_msg;
+ }
+ # or if alignment is | *
+ else
+ {
+ $outstr = $bufname.": ".$cb_msg;
+ }
+ }
+ # highmon dynmon
+ elsif (!$cb_bufferp && !$nick)
+ {
+ $outstr = "\t".$cb_msg;
+ }
+
+ # Send string to buffer
+ if (weechat::config_get_plugin("output") eq "buffer")
+ {
+ # Search for and confirm buffer
+ $highmon_buffer = weechat::buffer_search("perl", "highmon");
+ # Print
+ weechat::print($highmon_buffer, $outstr);
+ }
+ elsif (weechat::config_get_plugin("output") eq "bar")
+ {
+ # Add time string
+ use POSIX qw(strftime);
+ $time = strftime(weechat::config_string(weechat::config_get("weechat.look.buffer_time_format")), localtime);
+ # Colourise
+ if ($time =~ /\$\{\w+\}/) # Coloured string
+ {
+ while ($time =~ /\$\{(\w+)\}/)
+ {
+ $color = weechat::color($1);
+ $time =~ s/\$\{\w+\}/$color/;
+ }
+ }
+ else # Default string
+ {
+ $colour = weechat::color(weechat::config_string(weechat::config_get("weechat.color.chat_time_delimiters")));
+ $reset = weechat::color("reset");
+ $time =~ s/(\d*)(.)(\d*)/$1$colour$2$reset$3/g;
+ }
+ # Push updates to bar lists
+ push (@bar_lines_time, $time);
+
+ # Change tab char
+ $delim = " ".weechat::color(weechat::config_string(weechat::config_get("weechat.color.chat_delimiters"))).weechat::config_string(weechat::config_get("weechat.look.prefix_suffix")).weechat::color("reset")." ";
+ $outstr =~ s/\t/$delim/;
+
+ push (@bar_lines, $outstr);
+ # Trigger update
+ weechat::bar_item_update("highmon");
+
+ if (weechat::config_get_plugin("bar_scrolldown") eq "on")
+ {
+ weechat::command("", "/bar scroll highmon * ye")
+ }
+ }
+}
+
+# Start the output display
+sub highmon_start
+{
+ if (weechat::config_get_plugin("output") eq "buffer")
+ {
+ highmon_buffer_open();
+ }
+ elsif (weechat::config_get_plugin("output") eq "bar")
+ {
+ highmon_bar_open();
+ }
+}
+
+# Takes two optional args (channel server), toggles monitoring on/off
+sub highmon_toggle
+{
+ $data = $_[0];
+ $buffer = $_[1];
+ $args = $_[2];
+
+ # Check if we've been told what channel to act on
+ if ($args ne "")
+ {
+ # Split argument up
+ @arg_array = split(/ /,$args);
+ # Check if a server was given
+ if ($arg_array[1])
+ {
+ # Find matching
+ $bufp = weechat::buffer_search("irc", $arg_array[1].".".$arg_array[0]);
+ }
+ else
+ {
+ $found_chans = 0;
+ # Loop through defined servers
+ $infolist = weechat::infolist_get("buffer", "", "");
+ while (weechat::infolist_next($infolist))
+ {
+ # Only interesting in IRC buffers
+ if (weechat::infolist_string($infolist, "plugin_name") eq "irc")
+ {
+ # Find buffers that maych
+ $sname = weechat::infolist_string($infolist, "short_name");
+ if ($sname eq $arg_array[0])
+ {
+ $found_chans++;
+ $bufp = weechat::infolist_pointer($infolist, "pointer");
+ }
+ }
+ }
+ weechat::infolist_free($infolist);
+ # If the infolist found more than one channel, halt as we need to know which one
+ if ($found_chans > 1)
+ {
+ weechat::print("", "Channel name is not unique, please define server");
+ return weechat::WEECHAT_RC_OK;
+ }
+ }
+ # Something didn't return right
+ if ($bufp eq "")
+ {
+ weechat::print("", "Could not find buffer");
+ return weechat::WEECHAT_RC_OK;
+ }
+ }
+ else
+ {
+ # Get pointer from where we are
+ $bufp = weechat::current_buffer();
+ }
+ # Get buffer name
+ $bufname = weechat::buffer_get_string($bufp, 'name');
+ # Test if buffer is an IRC channel
+ if ($bufname =~ /(.*)\.([#&\+!])(.*)/)
+ {
+ if (weechat::config_get_plugin($bufname) eq "off")
+ {
+ # If currently off, set on
+ weechat::config_set_plugin($bufname, "on");
+
+ # Send to output formatter
+ highmon_print("Highlight Monitoring Enabled", $bufp);
+ return weechat::WEECHAT_RC_OK;
+ }
+ elsif (weechat::config_get_plugin($bufname) eq "on" || weechat::config_get_plugin($bufname) eq "")
+ {
+ # If currently on, set off
+ weechat::config_set_plugin($bufname, "off");
+
+ # Send to output formatter
+ highmon_print("Highlight Monitoring Disabled", $bufp);
+ return weechat::WEECHAT_RC_OK;
+ }
+ }
+}
+
+# Takes a buffer pointer and returns a formatted name
+sub format_buffer_name
+{
+ $cb_bufferp = $_[0];
+ $bufname = weechat::buffer_get_string($cb_bufferp, 'name');
+
+ # Set colour from buffer name
+ if (weechat::config_get_plugin("color_buf") eq "on")
+ {
+ # Determine what colour to use
+ $color = weechat::info_get("irc_nick_color", $bufname);
+ if (!$color)
+ {
+ $color = 0;
+ @char_array = split(//,$bufname);
+ foreach $char (@char_array)
+ {
+ $color += ord($char);
+ }
+ $color %= 10;
+ $color = sprintf "weechat.color.chat_nick_color%02d", $color+1;
+ $color = weechat::config_get($color);
+ $color = weechat::config_string($color);
+ $color = weechat::color($color);
+ }
+
+ # Private message just show network
+ if (weechat::config_get_plugin("merge_private") eq "on" && weechat::buffer_get_string($cb_bufferp, "localvar_type") eq "private")
+ {
+ $bufname = weechat::buffer_get_string($cb_bufferp, "localvar_server");
+ }
+ # Format name to short or 'nicename'
+ elsif (weechat::config_get_plugin("short_names") eq "on")
+ {
+ $bufname = weechat::buffer_get_string($cb_bufferp, 'short_name');
+ }
+ else
+ {
+ $bufname =~ s/(.*)\.([#&\+!])(.*)/$1$2$3/;
+ }
+
+ # Build a coloured string
+ $bufname = $color.$bufname.weechat::color("reset");
+ }
+ # User set colour name
+ elsif (weechat::config_get_plugin("color_buf") ne "off")
+ {
+ # Private message just show network
+ if (weechat::config_get_plugin("merge_private") eq "on" && weechat::buffer_get_string($cb_bufferp, "localvar_type") eq "private")
+ {
+ $bufname = weechat::buffer_get_string($cb_bufferp, "localvar_server");
+ }
+ # Format name to short or 'nicename'
+ elsif (weechat::config_get_plugin("short_names") eq "on")
+ {
+ $bufname = weechat::buffer_get_string($cb_bufferp, 'short_name');
+ }
+ else
+ {
+ $bufname =~ s/(.*)\.([#&\+!])(.*)/$1$2$3/;
+ }
+
+ $color = weechat::config_get_plugin("color_buf");
+ $bufname = weechat::color($color).$bufname.weechat::color("reset");
+ }
+ # Stick with default colour
+ else
+ {
+ # Private message just show network
+ if (weechat::config_get_plugin("merge_private") eq "on" && weechat::buffer_get_string($cb_bufferp, "localvar_type") eq "private")
+ {
+ $bufname = weechat::buffer_get_string($cb_bufferp, "localvar_server");
+ }
+ # Format name to short or 'nicename'
+ elsif (weechat::config_get_plugin("short_names") eq "on")
+ {
+ $bufname = weechat::buffer_get_string($cb_bufferp, 'short_name');
+ }
+ else
+ {
+ $bufname =~ s/(.*)\.([#&\+!])(.*)/$1$2$3/;
+ }
+ }
+
+ return $bufname;
+}
+
+# Check result of register, and attempt to behave in a sane manner
+if (!weechat::register("highmon", "KenjiE20", "2.3.2", "GPL3", "Highlight Monitor", "", ""))
+{
+ # Double load
+ weechat::print ("", "\tHighmon is already loaded");
+ return weechat::WEECHAT_RC_OK;
+}
+else
+{
+ # Start everything
+ highmon_hook();
+ highmon_config_init();
+ highmon_start();
+}
diff --git a/weechat/perl/iset.pl b/weechat/perl/iset.pl
new file mode 100644
index 0000000..d27ec92
--- /dev/null
+++ b/weechat/perl/iset.pl
@@ -0,0 +1,1394 @@
+#
+# Copyright (C) 2008-2012 Sebastien Helleu <flashcode@flashtux.org>
+# Copyright (C) 2010-2012 Nils Görs <weechatter@arcor.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 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/>.
+#
+# Set WeeChat and plugins options interactively.
+#
+# History:
+#
+# 2013-04-30, arza <arza@arza.us>:
+# version 3.0: simpler title, fix refresh on unset
+# 2012-12-16, nils_2 <weechatter@arcor.de>:
+# version 2.9: fix focus window with iset buffer on mouse click
+# 2012-08-25, nils_2 <weechatter@arcor.de>:
+# version 2.8: most important key and mouse bindings for iset buffer added to title-bar (idea The-Compiler)
+# 2012-07-31, nils_2 <weechatter@arcor.de>:
+# version 2.7: add combined option and value search (see /help iset)
+# : add exact value search (see /help iset)
+# : fix problem with metacharacter in value search
+# : fix use of uninitialized value for unset option and reset value of option
+# 2012-07-25, nils_2 <weechatter@arcor.de>:
+# version 2.6: switch to iset buffer (if existing) when command /iset is called with arguments
+# 2012-03-17, Sebastien Helleu <flashcode@flashtux.org>:
+# version 2.5: fix check of sections when creating config file
+# 2012-03-09, Sebastien Helleu <flashcode@flashtux.org>:
+# version 2.4: fix reload of config file
+# 2012-02-02, nils_2 <weechatter@arcor.de>:
+# version 2.3: fixed: refresh problem with new search results and cursor was outside window.
+# : add: new option "current_line" in title bar
+# version 2.2: fixed: refresh error when toggling plugins description
+# 2011-11-05, nils_2 <weechatter@arcor.de>:
+# version 2.1: use own config file (iset.conf), fix own help color (used immediately)
+# 2011-10-16, nils_2 <weechatter@arcor.de>:
+# version 2.0: add support for left-mouse-button and more sensitive mouse gesture (for integer/color options)
+# add help text for mouse support
+# 2011-09-20, Sebastien Helleu <flashcode@flashtux.org>:
+# version 1.9: add mouse support, fix iset buffer, fix errors on first load under FreeBSD
+# 2011-07-21, nils_2 <weechatter@arcor.de>:
+# version 1.8: added: option "show_plugin_description" (alt+p)
+# fixed: typos in /help iset (lower case for alt+'x' keys)
+# 2011-05-29, nils_2 <weechatter@arcor.de>:
+# version 1.7: added: version check for future needs
+# added: new option (scroll_horiz) and usage of scroll_horiz function (weechat >= 0.3.6 required)
+# fixed: help_bar did not pop up immediately using key-shortcut
+# 2011-02-19, nils_2 <weechatter@arcor.de>:
+# version 1.6: added: display of all possible values in help bar (show_help_extra_info)
+# fixed: external user options never loaded when starting iset first time
+# 2011-02-13, Sebastien Helleu <flashcode@flashtux.org>:
+# version 1.5: use new help format for command arguments
+# 2011-02-03, nils_2 <weechatter@arcor.de>:
+# version 1.4: fixed: restore value filter after /upgrade using buffer local variable.
+# 2011-01-14, nils_2 <weechatter@arcor.de>:
+# version 1.3: added function to search for values (option value_search_char).
+# code optimization.
+# 2010-12-26, Sebastien Helleu <flashcode@flashtux.org>:
+# version 1.2: improve speed of /upgrade when iset buffer is open,
+# restore filter used after /upgrade using buffer local variable,
+# use /iset filter argument if buffer is open.
+# 2010-11-21, drubin <drubin+weechat@smartcube.co.za>:
+# version 1.1.1: fix bugs with cursor position
+# 2010-11-20, nils_2 <weechatter@arcor.de>:
+# version 1.1: cursor position set to value
+# 2010-08-03, Sebastien Helleu <flashcode@flashtux.org>:
+# version 1.0: move misplaced call to infolist_free()
+# 2010-02-02, rettub <rettub@gmx.net>:
+# version 0.9: turn all the help stuff off if option 'show_help_bar' is 'off',
+# new key binding <alt>-<v> to toggle help_bar and help stuff on/off
+# 2010-01-30, nils_2 <weechatter@arcor.de>:
+# version 0.8: fix error when option does not exist
+# 2010-01-24, Sebastien Helleu <flashcode@flashtux.org>:
+# version 0.7: display iset bar only on iset buffer
+# 2010-01-22, nils_2 <weechatter@arcor.de> and drubin:
+# version 0.6: add description in a bar, fix singular/plural bug in title bar,
+# fix selected line when switching buffer
+# 2009-06-21, Sebastien Helleu <flashcode@flashtux.org>:
+# version 0.5: fix bug with iset buffer after /upgrade
+# 2009-05-02, Sebastien Helleu <flashcode@flashtux.org>:
+# version 0.4: sync with last API changes
+# 2009-01-04, Sebastien Helleu <flashcode@flashtux.org>:
+# version 0.3: open iset buffer when /iset command is executed
+# 2009-01-04, Sebastien Helleu <flashcode@flashtux.org>:
+# version 0.2: use null values for options, add colors, fix refresh bugs,
+# use new keys to reset/unset options, sort options by name,
+# display number of options in buffer's title
+# 2008-11-05, Sebastien Helleu <flashcode@flashtux.org>:
+# version 0.1: first official version
+# 2008-04-19, Sebastien Helleu <flashcode@flashtux.org>:
+# script creation
+
+use strict;
+
+my $PRGNAME = "iset";
+my $VERSION = "3.0";
+my $DESCR = "Interactive Set for configuration options";
+my $AUTHOR = "Sebastien Helleu <flashcode\@flashtux.org>";
+my $LICENSE = "GPL3";
+my $LANG = "perl";
+my $ISET_CONFIG_FILE_NAME = "iset";
+
+my $iset_config_file;
+my $iset_buffer = "";
+my $wee_version_number = 0;
+my @iset_focus = ();
+my @options_names = ();
+my @options_types = ();
+my @options_values = ();
+my @options_is_null = ();
+my $option_max_length = 0;
+my $current_line = 0;
+my $filter = "*";
+my $description = "";
+my $options_name_copy = "";
+my $iset_filter_title = "";
+# search modes: 0 = index() on value, 1 = grep() on value, 2 = grep() on option, 3 = grep on option & value
+my $search_mode = 2;
+my $search_value = "";
+my $help_text_keys = "alt + space: toggle, +/-: increase/decrease, enter: change, ir: reset, iu: unset, v: toggle help bar";
+my $help_text_mouse = "Mouse: left: select, right: toggle/set, right + drag left/right: increase/decrease";
+my %options_iset;
+
+my %mouse_keys = ("\@chat(perl.$PRGNAME):button1" => "hsignal:iset_mouse",
+ "\@chat(perl.$PRGNAME):button2*" => "hsignal:iset_mouse",
+ "\@chat(perl.$PRGNAME):wheelup" => "/repeat 5 /iset **up",
+ "\@chat(perl.$PRGNAME):wheeldown" => "/repeat 5 /iset **down");
+
+
+sub iset_title
+{
+ if ($iset_buffer ne "")
+ {
+ my $current_line_counter = "";
+ $current_line_counter = ($current_line + 1) . "/" if (weechat::config_boolean($options_iset{"show_current_line"}) == 1);
+ my $show_filter = "";
+ if ($search_mode eq 0)
+ {
+ $iset_filter_title = "(value) ";
+ $show_filter = $search_value;
+ if ( substr($show_filter,0,1) eq weechat::config_string($options_iset{"value_search_char"}) )
+ {
+ $show_filter = substr($show_filter,1,length($show_filter));
+ }
+ }
+ elsif ($search_mode eq 1)
+ {
+ $iset_filter_title = "(value) ";
+ $show_filter = "*".$search_value."*";
+ }
+ elsif ($search_mode eq 2)
+ {
+ $iset_filter_title = "";
+ $filter = "*" if ($filter eq "");
+ $show_filter = $filter;
+ }
+ elsif ($search_mode eq 3)
+ {
+ $iset_filter_title = "(option) ";
+ $show_filter = $filter
+ .weechat::color("default")
+ ." / (value) "
+ .weechat::color("yellow")
+ ."*".$search_value."*";
+ }
+ weechat::buffer_set($iset_buffer, "title",
+ $iset_filter_title
+ .weechat::color("yellow")
+ .$show_filter
+ .weechat::color("default")." | "
+ .$current_line_counter
+ .@options_names
+ ." | "
+ .$help_text_keys
+ ." | "
+ .$help_text_mouse);
+ }
+}
+
+sub iset_create_filter
+{
+ $filter = $_[0];
+ if ( $search_mode == 3 )
+ {
+ my @cmd_array = split(/ /,$filter);
+ my $array_count = @cmd_array;
+ $filter = $cmd_array[0];
+ $filter = $cmd_array[0] . " " . $cmd_array[1] if ( $array_count >2 );
+ }
+ $filter = "$1.*" if ($filter =~ /f (.*)/); # search file
+ $filter = "*.$1.*" if ($filter =~ /s (.*)/); # search section
+ if ((substr($filter, 0, 1) ne "*") && (substr($filter, -1, 1) ne "*"))
+ {
+ $filter = "*".$filter."*";
+ }
+ if ($iset_buffer ne "")
+ {
+ weechat::buffer_set($iset_buffer, "localvar_set_iset_filter", $filter);
+ }
+}
+
+sub iset_buffer_input
+{
+ my ($data, $buffer, $string) = ($_[0], $_[1], $_[2]);
+ $search_value = "";
+ my @cmd_array = split(/ /,$string);
+ my $array_count = @cmd_array;
+ my $string2 = substr($string, 0, 1);
+ if ($string2 eq weechat::config_string($options_iset{"value_search_char"})
+ or (defined $cmd_array[0] and $cmd_array[0] eq weechat::config_string($options_iset{"value_search_char"}).weechat::config_string($options_iset{"value_search_char"})) )
+ {
+ $search_mode = 1;
+ $search_value = substr($string, 1);
+ iset_get_values($search_value);
+ if ($iset_buffer ne "")
+ {
+ weechat::buffer_set($iset_buffer, "localvar_set_iset_search_value", $search_value);
+ }
+ }
+ else
+ {
+ $search_mode = 2;
+ if ( $array_count >= 2 and $cmd_array[0] ne "f" or $cmd_array[0] ne "s")
+ {
+ if ( defined $cmd_array[1] and substr($cmd_array[1], 0, 1) eq weechat::config_string($options_iset{"value_search_char"})
+ or defined $cmd_array[2] and substr($cmd_array[2], 0, 1) eq weechat::config_string($options_iset{"value_search_char"}) )
+ {
+ $search_mode = 3;
+ $search_value = substr($cmd_array[1], 1); # cut value_search_char
+ $search_value = substr($cmd_array[2], 1) if ( $array_count > 2); # cut value_search_char
+ }
+ }
+ if ( $search_mode == 3)
+ {
+ iset_create_filter($string);
+ iset_get_options($search_value);
+ }else
+ {
+ iset_create_filter($string);
+ iset_get_options("");
+ }
+ }
+ weechat::buffer_set($iset_buffer, "localvar_set_iset_search_mode", $search_mode);
+ weechat::buffer_clear($buffer);
+ $current_line = 0;
+ iset_refresh();
+ return weechat::WEECHAT_RC_OK;
+}
+
+sub iset_buffer_close
+{
+ $iset_buffer = "";
+
+ return weechat::WEECHAT_RC_OK;
+}
+
+sub iset_init
+{
+ $current_line = 0;
+ $iset_buffer = weechat::buffer_search($LANG, $PRGNAME);
+ if ($iset_buffer eq "")
+ {
+ $iset_buffer = weechat::buffer_new($PRGNAME, "iset_buffer_input", "", "iset_buffer_close", "");
+ }
+ else
+ {
+ my $new_filter = weechat::buffer_get_string($iset_buffer, "localvar_iset_filter");
+ $search_mode = weechat::buffer_get_string($iset_buffer, "localvar_iset_search_mode");
+ $search_value = weechat::buffer_get_string($iset_buffer, "localvar_iset_search_value");
+ $filter = $new_filter if ($new_filter ne "");
+ }
+ if ($iset_buffer ne "")
+ {
+ weechat::buffer_set($iset_buffer, "type", "free");
+ iset_title();
+ weechat::buffer_set($iset_buffer, "key_bind_ctrl-L", "/iset **refresh");
+ weechat::buffer_set($iset_buffer, "key_bind_meta2-A", "/iset **up");
+ weechat::buffer_set($iset_buffer, "key_bind_meta2-B", "/iset **down");
+ weechat::buffer_set($iset_buffer, "key_bind_meta2-23~", "/iset **left");
+ weechat::buffer_set($iset_buffer, "key_bind_meta2-24~" , "/iset **right");
+ weechat::buffer_set($iset_buffer, "key_bind_meta- ", "/iset **toggle");
+ weechat::buffer_set($iset_buffer, "key_bind_meta-+", "/iset **incr");
+ weechat::buffer_set($iset_buffer, "key_bind_meta--", "/iset **decr");
+ weechat::buffer_set($iset_buffer, "key_bind_meta-imeta-r", "/iset **reset");
+ weechat::buffer_set($iset_buffer, "key_bind_meta-imeta-u", "/iset **unset");
+ weechat::buffer_set($iset_buffer, "key_bind_meta-ctrl-J", "/iset **set");
+ weechat::buffer_set($iset_buffer, "key_bind_meta-ctrl-M", "/iset **set");
+ weechat::buffer_set($iset_buffer, "key_bind_meta-meta2-1~", "/iset **scroll_top");
+ weechat::buffer_set($iset_buffer, "key_bind_meta-meta2-4~", "/iset **scroll_bottom");
+ weechat::buffer_set($iset_buffer, "key_bind_meta-v", "/iset **toggle_help");
+ weechat::buffer_set($iset_buffer, "key_bind_meta-p", "/iset **toggle_show_plugin_desc");
+ weechat::buffer_set($iset_buffer, "localvar_set_iset_filter", $filter);
+ weechat::buffer_set($iset_buffer, "localvar_set_iset_search_mode", $search_mode);
+ weechat::buffer_set($iset_buffer, "localvar_set_iset_search_value", $search_value);
+ }
+}
+
+sub iset_get_options
+{
+ my $var_value = $_[0];
+ $var_value = "" if (not defined $var_value);
+ $var_value = lc($var_value);
+ $search_value = $var_value;
+ @iset_focus = ();
+ @options_names = ();
+ @options_types = ();
+ @options_values = ();
+ @options_is_null = ();
+ $option_max_length = 0;
+ my %options_internal = ();
+ my $i = 0;
+ my $key;
+ my $iset_struct;
+ my %iset_struct;
+
+ weechat::buffer_set($iset_buffer, "localvar_set_iset_search_value", $var_value) if ($search_mode == 3);
+
+ my $infolist = weechat::infolist_get("option", "", $filter);
+ while (weechat::infolist_next($infolist))
+ {
+ $key = sprintf("%08d", $i);
+ my $name = weechat::infolist_string($infolist, "full_name");
+ next if (weechat::config_boolean($options_iset{"show_plugin_description"}) == 0 and index ($name, "plugins.desc.") != -1);
+ my $type = weechat::infolist_string($infolist, "type");
+ my $value = weechat::infolist_string($infolist, "value");
+ my $is_null = weechat::infolist_integer($infolist, "value_is_null");
+ if ($search_mode == 3)
+ {
+ my $value = weechat::infolist_string($infolist, "value");
+ if ( grep /\Q$var_value/,lc($value) )
+ {
+ $options_internal{$name}{"type"} = $type;
+ $options_internal{$name}{"value"} = $value;
+ $options_internal{$name}{"is_null"} = $is_null;
+ $option_max_length = length($name) if (length($name) > $option_max_length);
+ $iset_struct{$key} = $options_internal{$name};
+ push(@iset_focus, $iset_struct{$key});
+ }
+ }
+ else
+ {
+ $options_internal{$name}{"type"} = $type;
+ $options_internal{$name}{"value"} = $value;
+ $options_internal{$name}{"is_null"} = $is_null;
+ $option_max_length = length($name) if (length($name) > $option_max_length);
+ $iset_struct{$key} = $options_internal{$name};
+ push(@iset_focus, $iset_struct{$key});
+ }
+ $i++;
+ }
+ weechat::infolist_free($infolist);
+
+ foreach my $name (sort keys %options_internal)
+ {
+ push(@options_names, $name);
+ push(@options_types, $options_internal{$name}{"type"});
+ push(@options_values, $options_internal{$name}{"value"});
+ push(@options_is_null, $options_internal{$name}{"is_null"});
+ }
+}
+
+sub iset_get_values
+{
+ my $var_value = $_[0];
+ $var_value = lc($var_value);
+ if (substr($var_value,0,1) eq weechat::config_string($options_iset{"value_search_char"}) and $var_value ne weechat::config_string($options_iset{"value_search_char"}))
+ {
+ $var_value = substr($var_value,1,length($var_value));
+ $search_mode = 0;
+ }
+ iset_search_values($var_value,$search_mode);
+ weechat::buffer_set($iset_buffer, "localvar_set_iset_search_mode", $search_mode);
+ weechat::buffer_set($iset_buffer, "localvar_set_iset_search_value", $var_value);
+ $search_value = $var_value;
+}
+sub iset_search_values
+{
+ my ($var_value,$search_mode) = ($_[0],$_[1]);
+ @options_names = ();
+ @options_types = ();
+ @options_values = ();
+ @options_is_null = ();
+ $option_max_length = 0;
+ my %options_internal = ();
+ my $i = 0;
+ my $infolist = weechat::infolist_get("option", "", "*");
+ while (weechat::infolist_next($infolist))
+ {
+ my $name = weechat::infolist_string($infolist, "full_name");
+ next if (weechat::config_boolean($options_iset{"show_plugin_description"}) == 0 and index ($name, "plugins.desc.") != -1);
+ my $type = weechat::infolist_string($infolist, "type");
+ my $is_null = weechat::infolist_integer($infolist, "value_is_null");
+ my $value = weechat::infolist_string($infolist, "value");
+ if ($search_mode)
+ {
+ if ( grep /\Q$var_value/,lc($value) )
+ {
+ $options_internal{$name}{"type"} = $type;
+ $options_internal{$name}{"value"} = $value;
+ $options_internal{$name}{"is_null"} = $is_null;
+ $option_max_length = length($name) if (length($name) > $option_max_length);
+ }
+ }
+ else
+ {
+# if ($value =~ /\Q$var_value/si)
+ if (lc($value) eq $var_value)
+ {
+ $options_internal{$name}{"type"} = $type;
+ $options_internal{$name}{"value"} = $value;
+ $options_internal{$name}{"is_null"} = $is_null;
+ $option_max_length = length($name) if (length($name) > $option_max_length);
+ }
+ }
+ $i++;
+ }
+ weechat::infolist_free($infolist);
+ foreach my $name (sort keys %options_internal)
+ {
+ push(@options_names, $name);
+ push(@options_types, $options_internal{$name}{"type"});
+ push(@options_values, $options_internal{$name}{"value"});
+ push(@options_is_null, $options_internal{$name}{"is_null"});
+ }
+}
+
+sub iset_refresh_line
+{
+ if ($iset_buffer ne "")
+ {
+ my $y = $_[0];
+ if ($y <= $#options_names)
+ {
+ return if (! defined($options_types[$y]));
+ my $format = sprintf("%%s%%-%ds %%s %%-7s %%s %%s%%s%%s", $option_max_length);
+ my $around = "";
+ $around = "\"" if ((!$options_is_null[$y]) && ($options_types[$y] eq "string"));
+
+ my $color1 = weechat::color(weechat::config_color($options_iset{"color_option"}));
+ my $color2 = weechat::color(weechat::config_color($options_iset{"color_type"}));
+ my $color3 = "";
+ if ($options_is_null[$y])
+ {
+ $color3 = weechat::color(weechat::config_color($options_iset{"color_value_undef"}));
+ }
+ else
+ {
+ $color3 = weechat::color(weechat::config_color($options_iset{"color_value"}));
+ }
+ if ($y == $current_line)
+ {
+ $color1 = weechat::color(weechat::config_color($options_iset{"color_option_selected"}).",".weechat::config_color($options_iset{"color_bg_selected"}));
+ $color2 = weechat::color(weechat::config_color($options_iset{"color_type_selected"}).",".weechat::config_color($options_iset{"color_bg_selected"}));
+ if ($options_is_null[$y])
+ {
+ $color3 = weechat::color(weechat::config_color($options_iset{"color_value_undef_selected"}).",".weechat::config_color($options_iset{"color_bg_selected"}));
+ }
+ else
+ {
+ $color3 = weechat::color(weechat::config_color($options_iset{"color_value_selected"}).",".weechat::config_color($options_iset{"color_bg_selected"}));
+ }
+ }
+ my $value = $options_values[$y];
+ $value = "(undef)" if ($options_is_null[$y]);
+ my $strline = sprintf($format,
+ $color1, $options_names[$y],
+ $color2, $options_types[$y],
+ $color3, $around, $value, $around);
+ weechat::print_y($iset_buffer, $y, $strline);
+ }
+ }
+}
+
+sub iset_refresh
+{
+ iset_title();
+ if (($iset_buffer ne "") && ($#options_names >= 0))
+ {
+ foreach my $y (0 .. $#options_names)
+ {
+ iset_refresh_line($y);
+ }
+ }
+
+ weechat::bar_item_update("isetbar_help") if (weechat::config_boolean($options_iset{"show_help_bar"}) == 1);
+}
+
+sub iset_full_refresh
+{
+ $iset_buffer = weechat::buffer_search($LANG, $PRGNAME);
+ if ($iset_buffer ne "")
+ {
+ weechat::buffer_clear($iset_buffer) unless defined $_[0]; # iset_full_refresh(1) does a full refresh without clearing buffer
+ # search for "*" in $filter.
+ if ($filter =~ m/\*/ and $search_mode == 2)
+ {
+ iset_get_options("");
+ }
+ else
+ {
+ if ($search_mode == 0)
+ {
+ $search_value = "=" . $search_value;
+ iset_get_values($search_value);
+ }
+ elsif ($search_mode == 1)
+ {
+ iset_get_values($search_value);
+ }
+ elsif ($search_mode == 3)
+ {
+ iset_create_filter($filter);
+ iset_get_options($search_value);
+ }
+ }
+ if (weechat::config_boolean($options_iset{"show_plugin_description"}) == 1)
+ {
+ iset_set_current_line($current_line);
+ }else
+ {
+ $current_line = $#options_names if ($current_line > $#options_names);
+ }
+ iset_refresh();
+ weechat::command($iset_buffer, "/window refresh");
+ }
+}
+
+sub iset_set_current_line
+{
+ my $new_current_line = $_[0];
+ my $old_current_line = $current_line;
+ $current_line = $new_current_line;
+ $current_line = $#options_names if ($current_line > $#options_names);
+ if ($old_current_line != $current_line)
+ {
+ iset_refresh_line($old_current_line);
+ iset_refresh_line($current_line);
+ weechat::bar_item_update("isetbar_help") if (weechat::config_boolean($options_iset{"show_help_bar"}) == 1);
+ }
+}
+
+sub iset_signal_window_scrolled_cb
+{
+ my ($data, $signal, $signal_data) = ($_[0], $_[1], $_[2]);
+ if ($iset_buffer ne "")
+ {
+ my $infolist = weechat::infolist_get("window", $signal_data, "");
+ if (weechat::infolist_next($infolist))
+ {
+ if (weechat::infolist_pointer($infolist, "buffer") eq $iset_buffer)
+ {
+ my $old_current_line = $current_line;
+ my $new_current_line = $current_line;
+ my $start_line_y = weechat::infolist_integer($infolist, "start_line_y");
+ my $chat_height = weechat::infolist_integer($infolist, "chat_height");
+ $new_current_line += $chat_height if ($new_current_line < $start_line_y);
+ $new_current_line -= $chat_height if ($new_current_line >= $start_line_y + $chat_height);
+ $new_current_line = $start_line_y if ($new_current_line < $start_line_y);
+ $new_current_line = $start_line_y + $chat_height - 1 if ($new_current_line >= $start_line_y + $chat_height);
+ iset_set_current_line($new_current_line);
+ }
+ }
+ weechat::infolist_free($infolist);
+ }
+
+ return weechat::WEECHAT_RC_OK;
+}
+
+sub iset_get_window_number
+{
+ if ($iset_buffer ne "")
+ {
+ my $window = weechat::window_search_with_buffer($iset_buffer);
+ return "-window ".weechat::window_get_integer ($window, "number")." " if ($window ne "");
+ }
+ return "";
+}
+
+sub iset_check_line_outside_window
+{
+ if ($iset_buffer ne "")
+ {
+ undef my $infolist;
+ if ($wee_version_number >= 0x00030500)
+ {
+ my $window = weechat::window_search_with_buffer($iset_buffer);
+ $infolist = weechat::infolist_get("window", $window, "") if $window;
+ }
+ else
+ {
+ $infolist = weechat::infolist_get("window", "", "current");
+ }
+ if ($infolist)
+ {
+ if (weechat::infolist_next($infolist))
+ {
+ my $start_line_y = weechat::infolist_integer($infolist, "start_line_y");
+ my $chat_height = weechat::infolist_integer($infolist, "chat_height");
+ my $window_number = "";
+ if ($wee_version_number >= 0x00030500)
+ {
+ $window_number = "-window ".weechat::infolist_integer($infolist, "number")." ";
+ }
+ if ($start_line_y > $current_line)
+ {
+ weechat::command($iset_buffer, "/window scroll ".$window_number."-".($start_line_y - $current_line));
+ }
+ else
+ {
+ if ($start_line_y <= $current_line - $chat_height)
+ {
+ weechat::command($iset_buffer, "/window scroll ".$window_number."+".($current_line - $start_line_y - $chat_height + 1));
+
+ }
+ }
+ }
+ weechat::infolist_free($infolist);
+ }
+ }
+}
+
+sub iset_get_option_name_index
+{
+ my $option_name = $_[0];
+ my $index = 0;
+ while ($index <= $#options_names)
+ {
+ return -1 if ($options_names[$index] gt $option_name);
+ return $index if ($options_names[$index] eq $option_name);
+ $index++;
+ }
+ return -1;
+}
+
+sub iset_config_cb
+{
+ my ($data, $option_name, $value) = ($_[0], $_[1], $_[2]);
+
+ if ($iset_buffer ne "")
+ {
+ return weechat::WEECHAT_RC_OK if (weechat::info_get("weechat_upgrading", "") eq "1");
+
+ my $index = iset_get_option_name_index($option_name);
+ if ($index >= 0)
+ {
+ # refresh info about changed option
+ my $infolist = weechat::infolist_get("option", "", $option_name);
+ if ($infolist)
+ {
+ weechat::infolist_next($infolist);
+ if (weechat::infolist_fields($infolist))
+ {
+ $options_types[$index] = weechat::infolist_string($infolist, "type");
+ $options_values[$index] = weechat::infolist_string($infolist, "value");
+ $options_is_null[$index] = weechat::infolist_integer($infolist, "value_is_null");
+ iset_refresh_line($index);
+ iset_title() if ($option_name eq "iset.look.show_current_line");
+ }
+ else
+ {
+ iset_full_refresh(1); # if not found, refresh fully without clearing buffer
+ weechat::print_y($iset_buffer, $#options_names + 1, "");
+ }
+ weechat::infolist_free($infolist);
+ }
+ }
+ else
+ {
+ iset_full_refresh() if ($option_name ne "weechat.bar.isetbar.hidden");
+ }
+ }
+
+ return weechat::WEECHAT_RC_OK;
+}
+
+sub iset_set_option
+{
+ my ($option, $value) = ($_[0],$_[1]);
+ if (defined $option and defined $value)
+ {
+ $option = weechat::config_get($option);
+ weechat::config_option_set($option, $value, 1) if ($option ne "");
+ }
+}
+
+sub iset_reset_option
+{
+ my $option = $_[0];
+ if (defined $option)
+ {
+ $option = weechat::config_get($option);
+ weechat::config_option_reset($option, 1) if ($option ne "");
+ }
+}
+
+sub iset_unset_option
+{
+ my $option = $_[0];
+ if (defined $option)
+ {
+ $option = weechat::config_get($option);
+ weechat::config_option_unset($option) if ($option ne "");
+ }
+}
+
+
+sub iset_cmd_cb
+{
+ my ($data, $buffer, $args) = ($_[0], $_[1], $_[2]);
+ my $filter_set = 0;
+# $search_value = "";
+ if (($args ne "") && (substr($args, 0, 2) ne "**"))
+ {
+ my @cmd_array = split(/ /,$args);
+ my $array_count = @cmd_array;
+ if (substr($args, 0, 1) eq weechat::config_string($options_iset{"value_search_char"})
+ or (defined $cmd_array[0] and $cmd_array[0] eq weechat::config_string($options_iset{"value_search_char"}).weechat::config_string($options_iset{"value_search_char"})) )
+ {
+ $search_mode = 1;
+ my $search_value = substr($args, 1); # cut value_search_char
+ if ($iset_buffer ne "")
+ {
+ weechat::buffer_clear($iset_buffer);
+ weechat::command($iset_buffer, "/window refresh");
+ }
+ weechat::buffer_set($iset_buffer, "localvar_set_iset_search_mode", $search_mode);
+ weechat::buffer_set($iset_buffer, "localvar_set_iset_search_value", $search_value);
+ iset_init();
+ iset_get_values($search_value);
+ iset_refresh();
+ weechat::buffer_set($iset_buffer, "display", "1");
+# $filter = $var_value;
+ return weechat::WEECHAT_RC_OK;
+ }
+ else
+ {
+ # f/s option =value
+ # option =value
+ $search_mode = 2;
+ if ( $array_count >= 2 and $cmd_array[0] ne "f" or $cmd_array[0] ne "s")
+ {
+ if ( defined $cmd_array[1] and substr($cmd_array[1], 0, 1) eq weechat::config_string($options_iset{"value_search_char"})
+ or defined $cmd_array[2] and substr($cmd_array[2], 0, 1) eq weechat::config_string($options_iset{"value_search_char"}) )
+ {
+ $search_mode = 3;
+ $search_value = substr($cmd_array[1], 1); # cut value_search_char
+ $search_value = substr($cmd_array[2], 1) if ( $array_count > 2); # cut value_search_char
+ }
+ }
+ iset_create_filter($args);
+ $filter_set = 1;
+ my $ptrbuf = weechat::buffer_search($LANG, $PRGNAME);
+ if ($ptrbuf eq "")
+ {
+ iset_init();
+ iset_get_options($search_value);
+ iset_full_refresh();
+ weechat::buffer_set(weechat::buffer_search($LANG, $PRGNAME), "display", "1");
+ weechat::buffer_set($iset_buffer, "localvar_set_iset_search_value", $search_value);
+ weechat::buffer_set($iset_buffer, "localvar_set_iset_search_mode", $search_mode);
+ return weechat::WEECHAT_RC_OK;
+ }
+ else
+ {
+ iset_get_options($search_value);
+ iset_full_refresh();
+ weechat::buffer_set($ptrbuf, "display", "1");
+ }
+ }
+ weechat::buffer_set($iset_buffer, "localvar_set_iset_search_mode", $search_mode);
+ weechat::buffer_set($iset_buffer, "localvar_set_iset_search_value", $search_value);
+ }
+ if ($iset_buffer eq "")
+ {
+ iset_init();
+ iset_get_options("");
+ iset_refresh();
+ }
+ else
+ {
+# iset_get_options($search_value);
+ iset_full_refresh() if ($filter_set);
+ }
+
+ if ($args eq "")
+ {
+ weechat::buffer_set($iset_buffer, "display", "1");
+ }
+ else
+ {
+ if ($args eq "**refresh")
+ {
+ iset_full_refresh();
+ }
+ if ($args eq "**up")
+ {
+ if ($current_line > 0)
+ {
+ $current_line--;
+ iset_refresh_line($current_line + 1);
+ iset_refresh_line($current_line);
+ iset_check_line_outside_window();
+ }
+ }
+ if ($args eq "**down")
+ {
+ if ($current_line < $#options_names)
+ {
+ $current_line++;
+ iset_refresh_line($current_line - 1);
+ iset_refresh_line($current_line);
+ iset_check_line_outside_window();
+ }
+ }
+ if ($args eq "**left" && $wee_version_number >= 0x00030600)
+ {
+ weechat::command($iset_buffer, "/window scroll_horiz ".iset_get_window_number()."-".weechat::config_integer($options_iset{"scroll_horiz"})."%");
+ }
+ if ($args eq "**right" && $wee_version_number >= 0x00030600)
+ {
+ weechat::command($iset_buffer, "/window scroll_horiz ".iset_get_window_number().weechat::config_integer($options_iset{"scroll_horiz"})."%");
+ }
+ if ($args eq "**scroll_top")
+ {
+ my $old_current_line = $current_line;
+ $current_line = 0;
+ iset_refresh_line ($old_current_line);
+ iset_refresh_line ($current_line);
+ iset_title();
+ weechat::command($iset_buffer, "/window scroll_top ".iset_get_window_number());
+ }
+ if ($args eq "**scroll_bottom")
+ {
+ my $old_current_line = $current_line;
+ $current_line = $#options_names;
+ iset_refresh_line ($old_current_line);
+ iset_refresh_line ($current_line);
+ iset_title();
+ weechat::command($iset_buffer, "/window scroll_bottom ".iset_get_window_number());
+ }
+ if ($args eq "**toggle")
+ {
+ if ($options_types[$current_line] eq "boolean")
+ {
+ iset_set_option($options_names[$current_line], "toggle");
+ }
+ }
+ if ($args eq "**incr")
+ {
+ if (($options_types[$current_line] eq "integer")
+ || ($options_types[$current_line] eq "color"))
+ {
+ iset_set_option($options_names[$current_line], "++1");
+ }
+ }
+ if ($args eq "**decr")
+ {
+ if (($options_types[$current_line] eq "integer")
+ || ($options_types[$current_line] eq "color"))
+ {
+ iset_set_option($options_names[$current_line], "--1");
+ }
+ }
+ if ($args eq "**reset")
+ {
+ iset_reset_option($options_names[$current_line]);
+ }
+ if ($args eq "**unset")
+ {
+ iset_unset_option($options_names[$current_line]);
+ }
+ if ($args eq "**toggle_help")
+ {
+ if (weechat::config_boolean($options_iset{"show_help_bar"}) == 1)
+ {
+ weechat::config_option_set($options_iset{"show_help_bar"},0,1);
+ iset_show_bar(0);
+ }
+ else
+ {
+ weechat::config_option_set($options_iset{"show_help_bar"},1,1);
+ iset_show_bar(1);
+ }
+ }
+ if ($args eq "**toggle_show_plugin_desc")
+ {
+ if (weechat::config_boolean($options_iset{"show_plugin_description"}) == 1)
+ {
+ weechat::config_option_set($options_iset{"show_plugin_description"},0,1);
+ iset_full_refresh();
+ iset_check_line_outside_window();
+ iset_title();
+ }
+ else
+ {
+ weechat::config_option_set($options_iset{"show_plugin_description"},1,1);
+ iset_full_refresh();
+ iset_check_line_outside_window();
+ iset_title();
+ }
+ }
+ if ($args eq "**set")
+ {
+ my $quote = "";
+ my $value = $options_values[$current_line];
+ if ($options_is_null[$current_line])
+ {
+ $value = "null";
+ }
+ else
+ {
+ $quote = "\"" if ($options_types[$current_line] eq "string");
+ }
+ weechat::buffer_set($iset_buffer, "input", "/set ".$options_names[$current_line]." ".$quote.$value.$quote);
+ weechat::command($iset_buffer, "/input move_beginning_of_line");
+ weechat::command($iset_buffer, "/input move_next_word");
+ weechat::command($iset_buffer, "/input move_next_word");
+ weechat::command($iset_buffer, "/input move_next_char");
+ weechat::command($iset_buffer, "/input move_next_char") if ($quote ne "");
+ }
+ }
+ weechat::bar_item_update("isetbar_help") if (weechat::config_boolean($options_iset{"show_help_bar"}) == 1);
+ return weechat::WEECHAT_RC_OK;
+}
+
+sub iset_get_help
+{
+ my ($redraw) = ($_[0]);
+
+ return '' if (weechat::config_boolean($options_iset{"show_help_bar"}) == 0);
+
+ if (not defined $options_names[$current_line])
+ {
+ return "No option selected. Set a new filter using command line (use '*' to see all options)";
+ }
+ if ($options_name_copy eq $options_names[$current_line] and not defined $redraw)
+ {
+ return $description;
+ }
+ $options_name_copy = $options_names[$current_line];
+ my $optionlist ="";
+ $optionlist = weechat::infolist_get("option", "", $options_names[$current_line]);
+ weechat::infolist_next($optionlist);
+ my $full_name = weechat::infolist_string($optionlist,"full_name");
+ my $option_desc = "";
+ my $option_default_value = "";
+ my $option_range = "";
+ my $possible_values = "";
+ my $re = qq(\Q$full_name);
+ if (grep (/^$re$/,$options_names[$current_line]))
+ {
+ $option_desc = weechat::infolist_string($optionlist, "description_nls");
+ $option_desc = weechat::infolist_string($optionlist, "description") if ($option_desc eq "");
+ $option_desc = "No help found" if ($option_desc eq "");
+ $option_default_value = weechat::infolist_string($optionlist, "default_value");
+ $possible_values = weechat::infolist_string($optionlist, "string_values") if (weechat::infolist_string($optionlist, "string_values") ne "");
+ if ((weechat::infolist_string($optionlist, "type") eq "integer") && ($possible_values eq ""))
+ {
+ $option_range = weechat::infolist_integer($optionlist, "min")
+ ." .. ".weechat::infolist_integer($optionlist, "max");
+ }
+ }
+ weechat::infolist_free($optionlist);
+ iset_title();
+
+ $description = weechat::color(weechat::config_color($options_iset{"color_help_option_name"})).$options_names[$current_line]
+ .weechat::color("bar_fg").": "
+ .weechat::color(weechat::config_color($options_iset{"color_help_text"})).$option_desc;
+
+ # show additional infos like default value and possible values
+
+ if (weechat::config_boolean($options_iset{"show_help_extra_info"}) == 1)
+ {
+ $description .=
+ weechat::color("bar_delim")." ["
+ .weechat::color("bar_fg")."default: "
+ .weechat::color("bar_delim")."\""
+ .weechat::color(weechat::config_color($options_iset{"color_help_default_value"})).$option_default_value
+ .weechat::color("bar_delim")."\"";
+ if ($option_range ne "")
+ {
+ $description .= weechat::color("bar_fg").", values: ".$option_range;
+ }
+ if ($possible_values ne "")
+ {
+ $possible_values =~ s/\|/", "/g; # replace '|' to '", "'
+ $description .= weechat::color("bar_fg").", values: ". "\"" . $possible_values . "\"";
+
+ }
+ $description .= weechat::color("bar_delim")."]";
+ }
+ return $description;
+}
+
+sub iset_check_condition_isetbar_cb
+{
+ my ($data, $modifier, $modifier_data, $string) = ($_[0], $_[1], $_[2], $_[3]);
+ my $buffer = weechat::window_get_pointer($modifier_data, "buffer");
+ if ($buffer ne "")
+ {
+ if ((weechat::buffer_get_string($buffer, "plugin") eq $LANG)
+ && (weechat::buffer_get_string($buffer, "name") eq $PRGNAME))
+ {
+ return "1";
+ }
+ }
+ return "0";
+}
+
+sub iset_show_bar
+{
+ my $show = $_[0];
+ my $barhidden = weechat::config_get("weechat.bar.isetbar.hidden");
+ if ($barhidden)
+ {
+ if ($show)
+ {
+ if (weechat::config_boolean($options_iset{"show_help_bar"}) == 1)
+ {
+ if (weechat::config_boolean($barhidden))
+ {
+ weechat::config_option_set($barhidden, 0, 1);
+ }
+ }
+ }
+ else
+ {
+ if (!weechat::config_boolean($barhidden))
+ {
+ weechat::config_option_set($barhidden, 1, 1);
+ }
+ }
+ }
+}
+
+sub iset_signal_buffer_switch_cb
+{
+ my $buffer_pointer = $_[2];
+ my $show_bar = 0;
+ $show_bar = 1 if (weechat::buffer_get_integer($iset_buffer, "num_displayed") > 0);
+ iset_show_bar($show_bar);
+ iset_check_line_outside_window() if ($buffer_pointer eq $iset_buffer);
+ return weechat::WEECHAT_RC_OK;
+}
+
+sub iset_item_cb
+{
+ return iset_get_help();
+}
+
+sub iset_upgrade_ended
+{
+ iset_full_refresh();
+}
+
+sub iset_end
+{
+ # when script is unloaded, we hide bar
+ iset_show_bar(0);
+}
+
+# -------------------------------[ mouse support ]-------------------------------------
+
+sub hook_focus_iset_cb
+{
+ my %info = %{$_[1]};
+ my $bar_item_line = int($info{"_bar_item_line"});
+ undef my $hash;
+ if (($info{"_buffer_name"} eq $PRGNAME) && $info{"_buffer_plugin"} eq $LANG && ($bar_item_line >= 0) && ($bar_item_line <= $#iset_focus))
+ {
+ $hash = $iset_focus[$bar_item_line];
+ }
+ else
+ {
+ $hash = {};
+ my $hash_focus = $iset_focus[0];
+ foreach my $key (keys %$hash_focus)
+ {
+ $hash->{$key} = "?";
+ }
+ }
+ return $hash;
+}
+
+# _chat_line_y contains selected line
+sub iset_hsignal_mouse_cb
+{
+ my ($data, $signal, %hash) = ($_[0], $_[1], %{$_[2]});
+
+ if ($hash{"_buffer_name"} eq $PRGNAME && ($hash{"_buffer_plugin"} eq $LANG))
+ {
+ if ($hash{"_key"} eq "button1")
+ {
+ $current_line = $hash{"_chat_line_y"};
+ iset_refresh_line($current_line);
+ iset_refresh();
+ }
+ elsif ($hash{"_key"} eq "button2")
+ {
+ if ($options_types[$hash{"_chat_line_y"}] eq "boolean")
+ {
+ iset_set_option($options_names[$hash{"_chat_line_y"}], "toggle");
+ $current_line = $hash{"_chat_line_y"};
+ iset_refresh_line($current_line);
+ iset_refresh();
+ }
+ elsif ($options_types[$hash{"_chat_line_y"}] eq "string")
+ {
+ $current_line = $hash{"_chat_line_y"};
+ iset_refresh_line($current_line);
+ iset_refresh();
+ weechat::command("", "/$PRGNAME **set");
+ }
+ }
+ elsif ($hash{"_key"} eq "button2-gesture-left" or $hash{"_key"} eq "button2-gesture-left-long")
+ {
+ if ($options_types[$hash{"_chat_line_y"}] eq "integer" or ($options_types[$hash{"_chat_line_y"}] eq "color"))
+ {
+ $current_line = $hash{"_chat_line_y"};
+ iset_refresh_line($current_line);
+ iset_refresh();
+ my $distance = distance($hash{"_chat_line_x"},$hash{"_chat_line_x2"});
+ weechat::command("", "/repeat $distance /$PRGNAME **decr");
+ }
+ }
+ elsif ($hash{"_key"} eq "button2-gesture-right" or $hash{"_key"} eq "button2-gesture-right-long")
+ {
+ if ($options_types[$hash{"_chat_line_y"}] eq "integer" or ($options_types[$hash{"_chat_line_y"}] eq "color"))
+ {
+ $current_line = $hash{"_chat_line_y"};
+ iset_refresh_line($current_line);
+ iset_refresh();
+ my $distance = distance($hash{"_chat_line_x"},$hash{"_chat_line_x2"});
+ weechat::command("", "/repeat $distance /$PRGNAME **incr");
+ }
+ }
+ }
+ window_switch();
+}
+
+sub window_switch
+{
+ my $current_window = weechat::current_window();
+ my $dest_window = weechat::window_search_with_buffer(weechat::buffer_search("perl","iset"));
+ return 0 if ($dest_window eq "" or $current_window eq $dest_window);
+
+ my $infolist = weechat::infolist_get("window", $dest_window, "");
+ weechat::infolist_next($infolist);
+ my $number = weechat::infolist_integer($infolist, "number");
+ weechat::infolist_free($infolist);
+ weechat::command("","/window " . $number);
+}
+
+sub distance
+{
+ my ($x1,$x2) = ($_[0], $_[1]);
+ my $distance;
+ $distance = $x1 - $x2;
+ $distance = abs($distance);
+ if ($distance > 0)
+ {
+ use integer;
+ $distance = $distance / 3;
+ $distance = 1 if ($distance == 0);
+ }
+ elsif ($distance == 0)
+ {
+ $distance = 1;
+ }
+ return $distance;
+}
+
+# -----------------------------------[ config ]---------------------------------------
+
+sub iset_config_init
+{
+ $iset_config_file = weechat::config_new($ISET_CONFIG_FILE_NAME,"iset_config_reload_cb","");
+ return if ($iset_config_file eq "");
+
+ # section "color"
+ my $section_color = weechat::config_new_section($iset_config_file,"color", 0, 0, "", "", "", "", "", "", "", "", "", "");
+ if ($section_color eq "")
+ {
+ weechat::config_free($iset_config_file);
+ return;
+ }
+ $options_iset{"color_option"} = weechat::config_new_option(
+ $iset_config_file, $section_color,
+ "option", "color", "Color for option name in iset buffer", "", 0, 0,
+ "default", "default", 0, "", "", "full_refresh_cb", "", "", "");
+ $options_iset{"color_option_selected"} = weechat::config_new_option(
+ $iset_config_file, $section_color,
+ "option_selected", "color", "Color for selected option name in iset buffer", "", 0, 0,
+ "white", "white", 0, "", "", "full_refresh_cb", "", "", "");
+ $options_iset{"color_type"} = weechat::config_new_option(
+ $iset_config_file, $section_color,
+ "type", "color", "Color for option type (integer, boolean, string)", "", 0, 0,
+ "brown", "brown", 0, "", "", "full_refresh_cb", "", "", "");
+ $options_iset{"color_type_selected"} = weechat::config_new_option(
+ $iset_config_file, $section_color,
+ "type_selected", "color", "Color for selected option type (integer, boolean, string)", "", 0, 0,
+ "yellow", "yellow", 0, "", "", "full_refresh_cb", "", "", "");
+ $options_iset{"color_value"} = weechat::config_new_option(
+ $iset_config_file, $section_color,
+ "value", "color", "Color for option value", "", 0, 0,
+ "cyan", "cyan", 0, "", "", "full_refresh_cb", "", "", "");
+ $options_iset{"color_value_selected"} = weechat::config_new_option(
+ $iset_config_file, $section_color,
+ "value_selected", "color", "Color for selected option value", "", 0, 0,
+ "lightcyan", "lightcyan", 0, "", "", "full_refresh_cb", "", "", "");
+ $options_iset{"color_value_undef"} = weechat::config_new_option(
+ $iset_config_file, $section_color,
+ "value_undef", "color", "Color for option value undef", "", 0, 0,
+ "green", "green", 0, "", "", "full_refresh_cb", "", "", "");
+ $options_iset{"color_value_undef_selected"} = weechat::config_new_option(
+ $iset_config_file, $section_color,
+ "value_undef_selected", "color", "Color for selected option value undef", "", 0, 0,
+ "lightgreen", "lightgreen", 0, "", "", "full_refresh_cb", "", "", "");
+ $options_iset{"color_bg_selected"} = weechat::config_new_option(
+ $iset_config_file, $section_color,
+ "bg_selected", "color", "Background color for current selected option", "", 0, 0,
+ "red", "red", 0, "", "", "full_refresh_cb", "", "", "");
+ $options_iset{"color_help_option_name"} = weechat::config_new_option(
+ $iset_config_file, $section_color,
+ "help_option_name", "color", "Color for option name in help-bar", "", 0, 0,
+ "white", "white", 0, "", "", "bar_refresh", "", "", "");
+ $options_iset{"color_help_text"} = weechat::config_new_option(
+ $iset_config_file, $section_color,
+ "help_text", "color", "Color for option description in help-bar", "", 0, 0,
+ "default", "default", 0, "", "", "bar_refresh", "", "", "");
+ $options_iset{"color_help_default_value"} = weechat::config_new_option(
+ $iset_config_file, $section_color,
+ "help_default_value", "color", "Color for default option value in help-bar", "", 0, 0,
+ "green", "green", 0, "", "", "bar_refresh", "", "", "");
+
+ # section "help"
+ my $section_help = weechat::config_new_section($iset_config_file,"help", 0, 0, "", "", "", "", "", "", "", "", "", "");
+ if ($section_help eq "")
+ {
+ weechat::config_free($iset_config_file);
+ return;
+ }
+ $options_iset{"show_help_bar"} = weechat::config_new_option(
+ $iset_config_file, $section_help,
+ "show_help_bar", "boolean", "Show help bar", "", 0, 0,
+ "on", "on", 0, "", "", "toggle_help_cb", "", "", "");
+ $options_iset{"show_help_extra_info"} = weechat::config_new_option(
+ $iset_config_file, $section_help,
+ "show_help_extra_info", "boolean", "Show additional information in help bar (default value, max./min. value) ", "", 0, 0,
+ "on", "on", 0, "", "", "", "", "", "");
+ $options_iset{"show_plugin_description"} = weechat::config_new_option(
+ $iset_config_file, $section_help,
+ "show_plugin_description", "boolean", "Show plugin description in iset buffer", "", 0, 0,
+ "off", "off", 0, "", "", "full_refresh_cb", "", "", "");
+
+ # section "look"
+ my $section_look = weechat::config_new_section($iset_config_file, "look", 0, 0, "", "", "", "", "", "", "", "", "", "");
+ if ($section_look eq "")
+ {
+ weechat::config_free($iset_config_file);
+ return;
+ }
+ $options_iset{"value_search_char"} = weechat::config_new_option(
+ $iset_config_file, $section_look,
+ "value_search_char", "string", "Trigger char to tell iset to search for value instead of option (for example: =red)", "", 0, 0,
+ "=", "=", 0, "", "", "", "", "", "");
+ $options_iset{"scroll_horiz"} = weechat::config_new_option(
+ $iset_config_file, $section_look,
+ "scroll_horiz", "integer", "scroll content of iset buffer n%", "", 1, 100,
+ "10", "10", 0, "", "", "", "", "", "");
+ $options_iset{"show_current_line"} = weechat::config_new_option(
+ $iset_config_file, $section_look,
+ "show_current_line", "boolean", "show current line in title bar.", "", 0, 0,
+ "on", "on", 0, "", "", "", "", "", "");
+}
+
+sub iset_config_reload_cb
+{
+ my ($data,$config_file) = ($_[0], $_[1]);
+ return weechat::config_reload($config_file)
+}
+
+sub iset_config_read
+{
+ return weechat::config_read($iset_config_file) if ($iset_config_file ne "");
+}
+
+sub iset_config_write
+{
+ return weechat::config_write($iset_config_file) if ($iset_config_file ne "");
+}
+
+sub full_refresh_cb
+{
+ iset_full_refresh();
+ return weechat::WEECHAT_RC_OK;
+}
+
+sub bar_refresh
+{
+ iset_get_help(1);
+ weechat::bar_item_update("isetbar_help") if (weechat::config_boolean($options_iset{"show_help_bar"}) == 1);
+ return weechat::WEECHAT_RC_OK;
+}
+
+sub toggle_help_cb
+{
+ my $value = weechat::config_boolean($options_iset{"show_help_bar"});
+ iset_show_bar($value);
+ return weechat::WEECHAT_RC_OK;
+}
+
+# -----------------------------------[ main ]-----------------------------------------
+
+weechat::register($PRGNAME, $AUTHOR, $VERSION, $LICENSE,
+ $DESCR, "iset_end", "");
+
+$wee_version_number = weechat::info_get("version_number", "") || 0;
+
+iset_config_init();
+iset_config_read();
+
+weechat::hook_command($PRGNAME, "Interactive set", "f <file> || s <section> || [=][=]<text>",
+ "f file : show options for a file\n".
+ "s section: show options for a section\n".
+ "text : show options with 'text' in name\n".
+ weechat::config_string($options_iset{"value_search_char"})."text : show options with 'text' in value\n".
+ weechat::config_string($options_iset{"value_search_char"}).weechat::config_string($options_iset{"value_search_char"})."text : show options with exact 'text' in value\n\n".
+ "Keys for iset buffer:\n".
+ "f11,f12 : move iset content left/right\n".
+ "up,down : move one option up/down\n".
+ "pgup,pdwn : move one page up/down\n".
+ "home,end : move to first/last option\n".
+ "ctrl+'L' : refresh options and screen\n".
+ "alt+space : toggle boolean on/off\n".
+ "alt+'+' : increase value (for integer or color)\n".
+ "alt+'-' : decrease value (for integer or color)\n".
+ "alt+'i',alt+'r': reset value of option\n".
+ "alt+'i',alt+'u': unset option\n".
+ "alt+enter : set new value for option (edit it with command line)\n".
+ "text,enter : set a new filter using command line (use '*' to see all options)\n".
+ "alt+'v' : toggle help bar on/off\n".
+ "alt+'p' : toggle option \"show_plugin_description\" on/off\n".
+ "\n".
+ "Mouse actions:\n".
+ "wheel up/down : move cursor up/down\n".
+ "left button : select an option from list\n".
+ "right button : toggle boolean (on/off) or set a new value for option (edit it with command line)\n".
+ "right button + drag left/right: increase/decrease value (for integer or color)\n".
+ "\n".
+ "Examples:\n".
+ " show options for file 'weechat'\n".
+ " /iset f weechat\n".
+ " show options for file 'irc'\n".
+ " /iset f irc\n".
+ " show options for section 'look'\n".
+ " /iset s look\n".
+ " show all options with text 'nicklist' in name\n".
+ " /iset nicklist\n".
+ " show all values which contain 'red'. ('" . weechat::config_string($options_iset{"value_search_char"}) . "' is a trigger char).\n".
+ " /iset ". weechat::config_string($options_iset{"value_search_char"}) ."red\n".
+ " show all values which hit 'off'. ('" . weechat::config_string($options_iset{"value_search_char"}) . weechat::config_string($options_iset{"value_search_char"}) . "' is a trigger char).\n".
+ " /iset ". weechat::config_string($options_iset{"value_search_char"}) . weechat::config_string($options_iset{"value_search_char"}) ."off\n".
+ " show options for file 'weechat' which contains value 'off'\n".
+ " /iset f weechat ".weechat::config_string($options_iset{"value_search_char"})."off\n".
+ "",
+ "", "iset_cmd_cb", "");
+weechat::hook_signal("upgrade_ended", "iset_upgrade_ended", "");
+weechat::hook_signal("window_scrolled", "iset_signal_window_scrolled_cb", "");
+weechat::hook_signal("buffer_switch", "iset_signal_buffer_switch_cb","");
+weechat::bar_item_new("isetbar_help", "iset_item_cb", "");
+weechat::bar_new("isetbar", "on", "0", "window", "", "top", "horizontal",
+ "vertical", "3", "3", "default", "cyan", "default", "1",
+ "isetbar_help");
+weechat::hook_modifier("bar_condition_isetbar", "iset_check_condition_isetbar_cb", "");
+weechat::hook_config("*", "iset_config_cb", "");
+$iset_buffer = weechat::buffer_search($LANG, $PRGNAME);
+iset_init() if ($iset_buffer ne "");
+
+if ($wee_version_number >= 0x00030600)
+{
+ weechat::hook_focus("chat", "hook_focus_iset_cb", "");
+ weechat::hook_hsignal($PRGNAME."_mouse", "iset_hsignal_mouse_cb", "");
+ weechat::key_bind("mouse", \%mouse_keys);
+}
diff --git a/weechat/perl/stalker.pl b/weechat/perl/stalker.pl
new file mode 100644
index 0000000..813ef42
--- /dev/null
+++ b/weechat/perl/stalker.pl
@@ -0,0 +1,1408 @@
+#
+# Copyright (c) 2013 by Nils Görs <weechatter@arcor.de>
+# Copyright (c) 2013 by Stefan Wold <ratler@stderr.eu>
+# based on irssi script stalker.pl from Kaitlyn Parkhurst (SymKat) <symkat@symkat.com>
+# https://github.com/symkat/Stalker
+#
+# Records and correlates nick!user@host information
+#
+# 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/>.
+#
+# History:
+#
+# version 1.1:nils_2@freenode.#weechat
+# 2013-10-31: add: flood-protection on JOINs
+#
+# version 1.0:nils_2@freenode.#weechat
+# 2013-10-28: add: option 'additional_join_info' (idea by: arch_bcn)
+# add: option 'timeout' time to wait for result of hook_process()
+# add: localvar 'drop_additional_join_info'
+# add: hook_process() to prevent blocking weechat on slower machines (like rpi)
+# add: more DEBUG informations
+#
+# version 0.9: Ratler@freenode.#weechat
+# 2013-08-11: fix: removed trailing whitespaces
+# fix: only add index if it doesn't exist
+# fix: dynamically create or upgrade database based on missing tables or columns
+# fix: allow dynamically creating indices for future tables
+#
+# version 0.8: Ratler@freenode.#weechat
+# 2013-08-09: add: case insensitive nick search
+# add: show "server.nickname" in search results when search_this_network_only is set to off
+# fix: type no longer needed for _ignore_guests()
+#
+# version 0.7: nils_2@freenode.#weechat
+# 2013-08-04: add: support of colors with format "${color:xxx}" (>= WeeChat 0.4.2)
+# add: function "remove_nick_from_host" (patch by FiXato)
+#
+# version 0.6: nils_2@freenode.#weechat
+# 2013-05-27: cleanup code
+#
+# version 0.5: nils_2@freenode.#weechat
+# 2013-05-26: add: function 'count'
+#
+# version 0.4: nils_2@freenode.#weechat
+# 2013-05-18: add: option 'tags'
+#
+# version 0.3: nils_2@freenode.#weechat
+# 2013-05-05: fix: typos in help and description option (thanks FiXato)
+# add: 'ChanServ' to option 'guest_nick_regex'
+#
+# version 0.2: nils_2@freenode.#weechat
+# 2013-05-01: fix: bug with regular expressions using /whois
+# removed: option 'allow_regex_for_search'
+# add: command option '-regex'
+#
+# version 0.1: nils_2@freenode.#weechat
+# 2013-04-23: - initial release -
+#
+# thanks to firebird and mave_ for testing...
+#
+# Development is currently hosted at
+# https://github.com/weechatter/weechat-scripts
+#
+# Requires:
+# DBI
+# DBD::SQLite
+#
+# How to install DBI:
+# with cpan : install DBI
+# with deb-package: sudo apt-get install libdbi-perl
+#
+# How to install DBD::SQLite:
+# with cpan : install DBD::SQLite
+# with deb-package: sudo apt-get install libdbd-sqlite3-perl libdbd-sqlite3 sqlite3-pcre
+
+#use strict;
+use warnings;
+use File::Spec;
+use DBI;
+
+my $SCRIPT_NAME = "stalker";
+my $SCRIPT_VERSION = "1.1";
+my $SCRIPT_AUTHOR = "Nils Görs <weechatter\@arcor.de>";
+my $SCRIPT_LICENCE = "GPL3";
+my $SCRIPT_DESC = "Records and correlates nick!user\@host information";
+
+
+# internal values
+my $weechat_version = "";
+my $ptr_hook_timer = "";
+my $flood_counter = 0; # counter to take care of JOINs, e.g. after netsplit
+
+# default values
+my %options = ('db_name' => '%h/nicks.db',
+ 'debug' => 'off',
+ 'max_recursion' => '20',
+ 'recursive_search' => 'on',
+ 'ignore_guest_hosts' => 'off',
+ 'ignore_guest_nicks' => 'on',
+ 'guest_nick_regex' => '^(guest|weebot|Floodbot|ChanServ).*',
+ 'guest_host_regex' => '^webchat',
+ 'normalize_nicks' => 'on',
+ 'search_this_network_only' => 'on',
+ 'use_localvar' => 'off',
+ 'ignore_nickchange' => 'off',
+ 'ignore_whois' => 'off',
+ 'tags' => '',
+ 'additional_join_info' => 'off',
+ 'timeout' => '1',
+ 'flood_timer' => '10',
+ 'flood_max_nicks' => '20',
+# '' => '',
+);
+my %desc_options = ('db_name' => 'file containing the SQLite database where information is recorded. This database is created on loading of ' . $SCRIPT_NAME . ' if it does not exist. ("%h" will be replaced by WeeChat home, "~/.weechat" by default) (default: %h/nicks.db)',
+ 'debug' => 'Prints debug output to core buffer so you know exactly what is going on. This is far too verbose to be enabled when not actively debugging something. (default: off)',
+ 'max_recursion' => 'For each correlation between nick <-> host that happens, one point of recursion happens. A corrupt database, general evilness, or misfortune can cause the recursion to skyrocket. This is a ceiling number that says if after this many correlation attempts we have not found all nickname and hostname correlations, stop the process and return the list to this point. Use this option with care on slower machines like raspberry pi.',
+ 'recursive_search' => 'When enabled, recursive search causes stalker to function better than a simple hostname to nickname map. Disabling the recursive search in effect turns stalker into a more standard hostname -> nickname map.',
+ 'ignore_guest_hosts'=> 'See option guest_host_regex',
+ 'guest_host_regex' => 'regex mask to ignore host masks',
+ 'ignore_guest_nicks'=> 'See option guest_nick_regex',
+ 'guest_nick_regex' => 'Some networks set default nicknames when a user fails to identify to nickserv, other networks using relay-bots, some irc clients set default nicknames when someone connects and often these change from network to network depending on who is configuring the java irc clients. This allows a regular expression to be entered. When a nickname matches the regular expression and "ignore_guest_nicks" is enabled the nickname is dropped from the search as if it had never been seen. (default: ^(guest|weebot|Floodbot).*)',
+ 'normalize_nicks' => 'this option will truncate special chars from username (like: ~) (default: on)',
+ 'search_this_network_only' => 'When enabled searches are limited to within the network the window is currently set on. Turning this off is really only useful if multiple networks don\'t encode the hostmask. (default: on)',
+ 'use_localvar' => 'When enabled, only channels with a localvar \'stalker\' will be monitored. This option will not affect /NICK and /WHOIS monitoring. It\'s only for /JOIN messages. (default: off)',
+ 'ignore_nickchange' => 'When enabled, /NICK changes won\'t be monitored. (default: off)',
+ 'ignore_whois' => 'When enabled, /WHOIS won\'t be monitored. (default: off)',
+ 'tags' => 'comma separated list of tags used for messages printed by stalker. See documentation for possible tags (e.g. \'no_log\', \'no_highlight\'). This option does not effect DEBUG messages.',
+ 'additional_join_info' => 'add a line below the JOIN message that will display alternative nicks (tags: "irc_join", "irc_smart_filter" will be add to additional_join_info). You can use a localvar to drop additional join info for specific buffer(s) "stalker_drop_additional_join_info" (default: off)',
+ 'timeout' => 'timeout in seconds for hook_process(), used with option "additional_join_info". On slower machines, like raspberry pi, increase time. (default: 1)',
+ 'flood_timer' => 'Time in seconds for which flood protection is active. Once max_nicks is reached, joins will be ignored for the remaining duration of the timer. (default:10)',
+ 'flood_max_nicks' => 'Maximum number of joins to allow in flood_timer length of time. Once maximum number of joins is reached, joins will be ignored until the timer ends (default:20)',
+);
+
+my $count;
+my %data;
+my $str;
+my $DBH;
+my $DBH_child;
+my $DBH_fork;
+my $last_nick = "";
+my $last_host = "";
+
+# SQLite table definition
+my %tables = (
+ 'records' => [
+ { 'column' => 'nick', 'type' => 'TEXT NOT NULL' },
+ { 'column' => 'user', 'type' => 'TEXT NOT NULL' },
+ { 'column' => 'host', 'type' => 'TEXT NOT NULL' },
+ { 'column' => 'serv', 'type' => 'TEXT NOT NULL' },
+ { 'column' => 'added', 'type' => 'DATE NOT NULL DEFAULT CURRENT_TIMESTAMP' },
+ ],
+ );
+
+# SQLite index definitions
+my %indices = (
+ 'records' => [
+ { 'name' => 'index1', 'column' => 'nick' },
+ { 'name' => 'index2', 'column' => 'host' },
+ ],
+ );
+
+# ---------------[ external routines for hook_process() ]---------------------
+if ($#ARGV == 8 ) # (0-8) nine arguments given?
+{
+ my $db_filename = $ARGV[0];
+ my ($db_user, $db_pass);
+ $DBH_fork = DBI->connect(
+ 'dbi:SQLite:dbname='.$db_filename, $db_user, $db_pass,
+ {
+ RaiseError => 1,
+# AutoCommit => 1,
+ sqlite_use_immediate_transaction => 1,
+ }
+ );
+
+ exit if (not defined $DBH_fork);
+
+ if ($ARGV[1] eq 'additional_join_info')
+ {
+ my $nick = $ARGV[2];
+ my $user = $ARGV[3];
+ my $host = $ARGV[4];
+ my $serv = $ARGV[5];
+ my $max_recursion = $ARGV[6];
+ my $ignore_guest_nicks = $ARGV[7];
+ my $guest_nick_regex = $ARGV[8];
+
+ my $nicks_found = join( ", ", (get_nick_records_fork($nick, $serv, $max_recursion, $ignore_guest_nicks, $guest_nick_regex)));
+
+ print "$nicks_found";
+ $DBH_fork->disconnect();
+ exit;
+ }
+ elsif ($ARGV[1] eq 'db_add_record')
+ {
+ my $nick = $ARGV[2];
+ my $user = $ARGV[3];
+ my $host = $ARGV[4];
+ my $serv = $ARGV[5];
+
+# DEBUG("info", "Adding to DB: nick = $nick, user = $user, host = $host, serv = $serv" );
+
+ # We don't have the record, add it. Test for record is done in add_record()
+ $sth = $DBH_fork->prepare("INSERT INTO records (nick,user,host,serv) VALUES( ?, ?, ?, ? )" );
+ eval { $sth->execute( $nick, $user, $host, $serv ) };
+ $DBH_fork->disconnect();
+ if ($@)
+ {
+ print "error Failed to process record, database said: $@";
+ exit;
+ }
+ print "info Added record for $nick!$user\@$host to $serv";
+ }
+exit;
+}
+
+my $count2;
+my %data_fork;
+sub get_nick_records_fork
+{
+ my ( $nick, $serv, $max_recursion, $ignore_guest_nicks, $guest_nick_regex ) = @_;
+ my $type = 'nick';
+ my @return;
+ $count2 = 0; %data_fork = ( );
+ @return = _r_search_fork( $serv, $type, $max_recursion, $ignore_guest_nicks, $guest_nick_regex, ({ $type => $nick }) );
+
+ # remove original nick
+ @return = grep {$_ ne $nick} @return;
+ # case-insensitive sort
+ return sort {uc($a) cmp uc($b)} @return;
+}
+
+my @nicks_found;
+sub _r_search_fork
+{
+ my ( $serv, $type, $max_recursion, $ignore_guest_nicks, $guest_nick_regex, @input ) = @_;
+ return @nicks_found = &del_double(@nicks_found) if $count2 > $max_recursion;
+
+ if ( $type eq 'nick' )
+ {
+ $count2++;
+ for my $row ( @input )
+ {
+ my $nick = $row->{nick};
+ next if exists $data_fork{$nick};
+
+ $data_fork{$nick} = 'nick';
+ my @hosts = _get_hosts_from_nick_fork( $nick, $serv, $ignore_guest_nicks, $guest_nick_regex );
+ _r_search_fork ( $serv, 'host', $max_recursion, $ignore_guest_nicks, $guest_nick_regex, @hosts );
+ }
+ }
+ elsif ( $type eq 'host' )
+ {
+ $count2++;
+ for my $row ( @input )
+ {
+ my $host = $row->{host};
+ next if exists $data_fork{$host};
+ $data_fork{$host} = 'host';
+
+ my @nicks = _get_nicks_from_host_fork ( $host, $serv, $ignore_guest_nicks, $guest_nick_regex );
+ next if (scalar(@nicks) <= 0);
+ push @nicks_found, map { $_->{nick} } @nicks;
+ # search only current network
+# $output_nicks = join( ", ", map { $_->{nick} } @nicks );
+
+ # use regex only for host search!
+ _r_search_fork( $serv, 'nick', $max_recursion, $ignore_guest_nicks, $guest_nick_regex, @nicks );
+ }
+ }
+ return @nicks_found = &del_double(@nicks_found);
+# return %data_fork;
+}
+
+sub _get_hosts_from_nick_fork
+{
+ my ( $nick, $serv, $ignore_guest_nicks, $guest_nick_regex, @return ) = @_;
+
+ my $sth = $DBH_fork->prepare( "SELECT nick, host FROM records WHERE nick = ? COLLATE NOCASE AND serv = ?" );
+ $sth->execute( $nick, $serv );
+
+ return _ignore_guests_fork( $sth, $ignore_guest_nicks, $guest_nick_regex );
+}
+
+sub _get_nicks_from_host_fork
+{
+ my ( $host, $serv, $ignore_guest_nicks, $guest_nick_regex, @return ) = @_;
+ my $sth = $DBH_fork->prepare( "SELECT nick, host FROM records WHERE host = ? AND serv = ?" );
+ $sth->execute( $host, $serv );
+
+ return _ignore_guests_fork( $sth,$ignore_guest_nicks, $guest_nick_regex );
+}
+
+sub del_double
+{
+ my %all=();
+ @all{@_}=1;
+ return (keys %all);
+}
+
+sub _ignore_guests_fork
+{
+ my ( $sth, $ignore_guest_nicks, $guest_nick_regex ) = @_;
+ my @return;
+
+ while ( my $row = $sth->fetchrow_hashref )
+ {
+ if ( lc($ignore_guest_nicks) eq "on" )
+ {
+ my $regex = $guest_nick_regex;
+ next if( $row->{nick} =~ m/$regex/i );
+ }
+ push @return, $row;
+ }
+ return @return;
+}
+
+# -----------------------------[ Database ]-----------------------------------
+sub open_database
+{
+ my $db = weechat_dir();
+
+ stat_database( $db );
+ my ($db_user, $db_pass);
+ # my $db_host = '127.0.0.1';
+ # my $db_port = 3306;
+
+ $DBH = DBI->connect(
+ 'dbi:SQLite:dbname='.$db, $db_user, $db_pass,
+ {
+ RaiseError => 1,
+# AutoCommit => 1,
+ sqlite_use_immediate_transaction => 1,
+ }
+ );
+
+ # DBI::SQLite and fork() don't mix. Do it anyhow but keep the parent and child DBH separate?
+ # Ideally the child should open its own connection.
+ $DBH_child = DBI->connect(
+ 'dbi:SQLite:dbname='.$db, $db_user, $db_pass,
+ {
+ RaiseError => 1,
+# AutoCommit => 1,
+ sqlite_use_immediate_transaction => 1,
+ }
+ );
+
+ # async data
+ my @records_to_add; # Queue of records to add
+}
+
+# Automatic Database Creation And Checking
+sub stat_database {
+ my ( $db_file ) = @_;
+
+ DEBUG('info', 'Stat database');
+ if ( ! -e $db_file ) {
+ open my $fh, '>', $db_file
+ or die 'Cannot create database file. Abort.';
+ close $fh;
+ }
+ my $DBH = DBI->connect(
+ 'dbi:SQLite:dbname='.$db_file, "", "",
+ {
+ RaiseError => 1,
+# AutoCommit => 1,
+ sqlite_use_immediate_transaction => 1,
+ }
+ );
+
+ create_or_upgrade_database( $DBH );
+
+ index_db( $DBH );
+}
+
+sub create_or_upgrade_database {
+ my ( $DBH ) = @_;
+
+ # This part will always add missing tables or columns defined in @tables (ie create or upgrade the database)
+ DEBUG("info", "Checking database table structure");
+ my %col_exists;
+ for my $table (keys %tables) {
+ for my $col ( @{ $DBH->selectall_arrayref ( "PRAGMA TABLE_INFO($table)" ) } ) {
+ $col_exists{$table}{$col->[1]} = 1;
+ }
+ }
+ for my $table (keys %tables) {
+ my $upgrade = 0;
+
+ # Create missing tables
+ unless ( exists( $col_exists{$table} ) ) {
+ create_table( $DBH, $table );
+ next;
+ }
+
+ # Check for missing columns
+ my @cols_not_null;
+ for my $col ( @{$tables{$table}} ) {
+ unless ( $col_exists{$table}{$col->{column}} ) {
+ if ( ($col->{type} =~ /NOT NULL/) and ($col->{type} !~ /DEFAULT/) ) {
+ push @cols_not_null, $col->{column};
+ }
+ $upgrade = 1;
+ }
+ }
+
+ # Due to limitations in ALTER TABLE in sqlite this cumbersome method is necessary to alter a table
+ if ( $upgrade ) {
+ DEBUG("info", "Upgrade required for table '$table', please wait...");
+ # Save the old records
+ $DBH->do( "ALTER TABLE $table RENAME TO old_$table" );
+
+ # Preserve old column names for copying of data later
+ my $old_columns = join( ", ", map { $_->[1] } @{ $DBH->selectall_arrayref( "PRAGMA TABLE_INFO(old_$table)" ) } );
+
+ # Create the new table
+ create_table( $DBH, $table );
+
+ # Special care for NOT NULL columns, we set value 1 for all missing columns defined with NOT NULL or the copy will fail
+ my $old_select;
+ if ( scalar(@cols_not_null) > 0 ) {
+ $old_select = $old_columns . ", " . join(", ", map { 1 } @cols_not_null );
+ $old_columns .= ", " . join(", ", @cols_not_null);
+ } else {
+ $old_select = $old_columns;
+ }
+
+ # Copy the old records over and drop them
+ my @queries = (
+ "INSERT INTO $table ($old_columns) SELECT $old_select FROM old_$table",
+ "DROP TABLE old_$table",
+ );
+ for my $query (@queries) {
+ my $sth = $DBH->prepare($query) or die "Failed to prepare '$query'. " . $sth->err;
+ $sth->execute() or die "Failed to execute '$query'. " . $sth->err;
+ }
+ DEBUG( "info", "Table '$table' has been successfully upgraded" ) unless ( $DBH->err );
+ }
+ }
+}
+
+# Create table
+sub create_table {
+ my ( $DBH, $table_name ) = @_;
+
+ my @queries;
+
+ DEBUG("info", "Creating table '$table_name'");
+ push @queries, "DROP TABLE IF EXISTS $table_name";
+ push @queries, "CREATE TABLE $table_name (" . join(", ", map { "$_->{column} $_->{type}" } @{ $tables{$table_name} }) . ")";
+
+ for my $query (@queries) {
+ my $sth = $DBH->prepare($query) or die "Failed to prepare '$query'. " . $sth->err;
+ $sth->execute() or die "Failed to execute '$query'. " . $sth->err;
+ }
+}
+
+# Add indices to the DB.
+sub index_db {
+ my ( $DBH ) = @_;
+
+ for my $table (keys %indices) {
+ my %idx_exists;
+ for my $index ( @{ $DBH->selectall_arrayref( "PRAGMA INDEX_LIST($table)" ) } ) {
+ $idx_exists{$index->[1]} = 1;
+ }
+
+ $DBH->{RaiseError} = 0;
+ $DBH->{PrintError} = 0;
+ for my $index ( @{$indices{$table}} ) {
+ $DBH->do( "CREATE INDEX $index->{name} ON $table ($index->{column})" ) unless ( $idx_exists{$index->{name}} );
+ }
+ $DBH->{RaiseError} = 1;
+ $DBH->{PrintError} = 1;
+ }
+}
+
+sub normalize
+{
+ my ( @nicks ) = @_;
+ my ( %nicks, %ret ) = map { $_, 1 } @nicks;
+
+ for my $nick ( @nicks )
+ {
+ (my $base = $nick ) =~ s/[\Q-_~^`\E]//g;
+ $ret{ exists $nicks{$base} ? $base : $nick }++;
+ }
+ return keys %ret;
+}
+
+sub add_record
+{
+ my ( $nick, $user, $host, $serv ) = @_;
+ return unless ($nick and $user and $host and $serv);
+
+ # Check if we already have this record, before using a hook_process()
+ my $sth = $DBH_child->prepare( "SELECT nick FROM records WHERE nick = ? AND user = ? AND host = ? AND serv = ?" );
+ $sth->execute( $nick, $user, $host, $serv );
+ my $result = $sth->fetchrow_hashref;
+
+ if ( defined $result->{nick} )
+ {
+ if ( $result->{nick} eq $nick ) {
+ DEBUG( "info", "Record for $nick skipped - already exists." );
+ return weechat::WEECHAT_RC_OK;
+ }
+ }
+
+ my $filename = get_script_filename();
+ return weechat::WEECHAT_RC_OK if ($filename eq "");
+
+ my $db_filename = weechat_dir();
+ DEBUG("info", "Start hook_process(), to add $nick $user\@$host on $serv to database");
+ weechat::hook_process("perl $filename $db_filename 'db_add_record' '$nick' '$user' '$host' '$serv' 'dummy' 'dummy' 'dummy'", 1000 * $options{'timeout'},"db_add_record_cb","");
+}
+
+# function called when data from child is available, or when child has ended, arguments and return value
+sub db_add_record_cb
+{
+ my ( $data, $command, $return_code, $out, $err ) = @_;
+ return weechat::WEECHAT_RC_OK if ( $return_code > 0 or $out eq ""); # something wrong!
+
+ my ($DEBUG_prefix,$message) = split(/ /,$out,2);
+ DEBUG($DEBUG_prefix, $message);
+ return weechat::WEECHAT_RC_OK;
+}
+
+sub get_host_records {
+ # suppress output? yes|no
+ # type = host|nick, $query = name, $serv = server, @return = "."
+ my ( $suppress, $type, $query, $serv, @return ) = @_;
+
+ $count = 0; %data = ( );
+ my %data = _r_search( $suppress, $serv, $type, $query );
+ for my $k ( keys %data ) {
+ DEBUG( "info", "$type query for records on $query from server $serv returned: $k" );
+ push @return, $k if $data{$k} eq 'host';
+ }
+
+ # case-insensitive sort
+ return sort {uc($a) cmp uc($b)} @return;
+}
+
+sub get_nick_records
+{
+ # type = host|nick, $query = nick, $serv = server, use_regex = 0|1, @return = "."
+ my ( $suppress, $type, $query, $serv, $use_regex, @return ) = @_;
+
+ $count = 0; %data = ( );
+ my %data = _r_search( $suppress, $serv, $type, $use_regex, ({ $type => $query }) );
+ for my $k ( keys %data ) {
+ DEBUG( "info", "$type query for database records on $query from server $serv. returned: $k" );
+ push @return, $k if $data{$k} eq 'nick';
+ }
+
+ if (lc($options{'normalize_nicks'}) eq "on" ) {
+ @return = normalize(@return);
+ }
+
+ # remove original nick
+ @return = grep {$_ ne $query} @return;
+
+ # case-insensitive sort
+ return sort {uc($a) cmp uc($b)} @return;
+}
+
+sub _r_search
+{
+ my ( $suppress, $serv, $type, $use_regex, @input ) = @_;
+
+ return %data if $count > 1000;
+ return %data if $count > $options{'max_recursion'};
+ return %data if $count == 2 and ! $options{'recursive_search'};
+
+ DEBUG( "info", "Recursion Level: $count" );
+
+ if ( $type eq 'nick' )
+ {
+ $count++;
+ for my $row ( @input )
+ {
+ my $nick = $row->{nick};
+ next if exists $data{$nick};
+
+ $data{$nick} = 'nick';
+ my @hosts = _get_hosts_from_nick( $nick, $serv, $use_regex );
+ # use regex only for nick search!
+ $use_regex = 0 if ( $use_regex );
+ _r_search( $suppress, $serv, 'host', $use_regex, @hosts );
+ }
+ } elsif ( $type eq 'host' )
+ {
+ $count++;
+ for my $row ( @input )
+ {
+ my $host = $row->{host};
+ next if exists $data{$host};
+ $data{$host} = 'host';
+ my @nicks = _get_nicks_from_host( $host, $serv, $use_regex );
+ next if (scalar(@nicks) <= 0);
+
+ my $output_nicks;
+ if ( lc($options{'search_this_network_only'}) eq "on" )
+ {
+ $output_nicks = join( ", ", map { $_->{nick} } @nicks );
+ }
+ else {
+ $output_nicks = join( ", ", map { $_->{serv} . "." . $_->{nick} } @nicks );
+ }
+
+ if ($suppress eq 'no')
+ {
+ my $ptr_buffer = weechat::current_buffer();
+
+ my $output = weechat::color('chat_prefix_network').
+ weechat::prefix('network').
+ weechat::color('chat_delimiters').
+ "[".
+ weechat::color('chat_nick').
+ $SCRIPT_NAME.
+ weechat::color('chat_delimiters').
+ "] ".
+ weechat::color('reset').
+ "Found nicks: $output_nicks".
+ " from host $host";
+
+ OUTPUT($ptr_buffer,$output);
+ }
+
+ # use regex only for host search!
+ $use_regex = 0 if ( $use_regex );
+ _r_search( $suppress, $serv, 'nick', $use_regex, @nicks );
+ }
+ }
+ return %data;
+}
+
+sub _get_hosts_from_nick {
+ my ( $nick, $serv, $use_regex, @return ) = @_;
+
+ my $sth;
+
+ if ( lc($options{'search_this_network_only'}) eq "on" )
+ {
+ if ( $use_regex )
+ {
+ $sth = $DBH->prepare( "SELECT nick, host FROM records WHERE nick REGEXP ? AND serv = ?" );
+ $sth->execute( $nick, $serv );
+ }
+ else
+ {
+ $sth = $DBH->prepare( "SELECT nick, host FROM records WHERE nick = ? COLLATE NOCASE AND serv = ?" );
+ $sth->execute( $nick, $serv );
+ }
+ }
+ else
+ {
+ if ( $use_regex )
+ {
+ $sth = $DBH->prepare( "SELECT nick, host, serv FROM records WHERE nick REGEXP ?");
+ }
+ else
+ {
+ $sth = $DBH->prepare( "SELECT nick, host, serv FROM records WHERE nick = ? COLLATE NOCASE" );
+ }
+ $sth->execute( $nick );
+ }
+ # nothing found in database
+# return '' if (not defined $sth->fetchrow_hashref);
+ return _ignore_guests( $sth );
+}
+
+sub _get_nicks_from_host {
+ my ( $host, $serv, $use_regex, @return ) = @_;
+
+ my $sth;
+ if ( lc($options{'search_this_network_only'}) eq "on" )
+ {
+ if ( $use_regex )
+ {
+ $sth = $DBH->prepare( "SELECT nick, host FROM records WHERE host REGEXP ? AND serv = ?" );
+# $sth->execute( $host, $serv );
+ }
+ else
+ {
+ $sth = $DBH->prepare( "SELECT nick, host FROM records WHERE host = ? AND serv = ?" );
+ }
+ $sth->execute( $host, $serv );
+ }
+ else
+ {
+ if ( $use_regex )
+ {
+ $sth = $DBH->prepare( "SELECT nick, host, serv FROM records WHERE host REGEXP ?" );
+ }
+ else
+ {
+ $sth = $DBH->prepare( "SELECT nick, host, serv FROM records WHERE host = ?" );
+ }
+ $sth->execute( $host );
+ }
+ # nothing found in database
+# return '' if (not defined $sth->fetchrow_hashref);
+ return _ignore_guests( $sth );
+}
+
+sub _ignore_guests
+{
+ my ( $sth ) = @_;
+ my @return;
+
+ while ( my $row = $sth->fetchrow_hashref )
+ {
+ if ( lc($options{'ignore_guest_nicks'}) eq "on" )
+ {
+ my $regex = $options{'guest_nick_regex'};
+ next if( $row->{nick} =~ m/$regex/i );
+ }
+ if ( lc($options{'ignore_guest_hosts'}) eq "on" )
+ {
+ my $regex = $options{'guest_host_regex'};
+ next if( $row->{host} =~ m/$regex/i );
+ }
+ push @return, $row;
+ }
+ return @return;
+}
+
+sub _deassociate_nick_from_host
+{
+ my ( $nick, $host, $serv, $use_regex, @return ) = @_;
+
+ my $sth;
+ if ( lc($options{'search_this_network_only'}) eq "on" )
+ {
+ if ( $use_regex )
+ {
+ $sth = $DBH->prepare( "DELETE FROM records WHERE host REGEXP ? AND nick REGEXP ? AND serv = ?" );
+ }
+ else
+ {
+ $sth = $DBH->prepare( "DELETE FROM records WHERE host = ? AND nick = ? AND serv = ?" );
+ }
+ $sth->execute( $host, $nick, $serv );
+ }
+ else
+ {
+ if ( $use_regex )
+ {
+ $sth = $DBH->prepare( "DELETE FROM records WHERE host REGEXP ? AND nick REGEXP ?" );
+ }
+ else
+ {
+ $sth = $DBH->prepare( "DELETE FROM records WHERE host = ? AND nick = ?" );
+ }
+ $sth->execute( $host, $nick );
+ }
+ return $sth->rows;
+}
+
+# ------------------------[ OUTPUT with tags ]------------------------------
+sub OUTPUT
+{
+ my ($ptr_buffer,$output) = @_;
+
+ if ( $options{'tags'} ne '' )
+ {
+ weechat::print_date_tags($ptr_buffer,0,$options{'tags'},$output);
+ }
+ else
+ {
+ weechat::print($ptr_buffer,$output);
+ }
+}
+# -----------------------------[ debug ]-----------------------------------
+sub DEBUG
+{
+ my $DEBUG_prefix;
+ my $color;
+
+ return if (lc($options{debug}) eq 'off');
+
+ if ( $_[0] eq 'info')
+ {
+ $DEBUG_prefix = 'info';
+ $color = "default";
+ }
+ elsif ( $_[0] eq 'error')
+ {
+ $DEBUG_prefix = weechat::config_string(weechat::config_get("weechat.look.prefix_error"));
+ $color = weechat::color(weechat::config_color(weechat::config_get("weechat.color.chat_prefix_error")));
+ }
+ else
+ {
+ $DEBUG_prefix = '***';
+ $color = 'default';
+ }
+ weechat::print('', _color_str($color, $DEBUG_prefix) . "\t$SCRIPT_NAME: $_[1]");
+}
+
+sub _color_str
+{
+ my ($color_name, $string) = @_;
+ # use eval for colors-codes (${color:red} eg in weechat.look.prefix_error)
+ $string = weechat::string_eval_expression($string, {}, {},{}) if ($weechat_version >= 0x00040200);
+ weechat::color($color_name) . $string . weechat::color('reset');
+}
+# -------------------------------[ subroutines ]-------------------------------------
+sub weechat_dir
+{
+ my $dir = $options{'db_name'};
+ if ( $dir =~ /%h/ )
+ {
+ my $weechat_dir = weechat::info_get( 'weechat_dir', '');
+ $dir =~ s/%h/$weechat_dir/;
+ }
+ return $dir;
+}
+# -------------------------------[ main ]-------------------------------------
+sub stalker_command_cb
+{
+ my ($data, $buffer, $args) = ($_[0], $_[1], $_[2]);
+ my @args_array=split(/ /,$args);
+ my $number = @args_array;
+
+ return weechat::WEECHAT_RC_OK if ($number <= 0);
+
+ if (lc($args_array[0]) eq 'count')
+ {
+# my $ptr_buffer = weechat::current_buffer();
+ my ($count) = $DBH->selectrow_array("SELECT count(*) FROM records");
+ my $output = weechat::color('chat_prefix_network').
+ weechat::prefix('network').
+ weechat::color('chat_delimiters').
+ "[".
+ weechat::color('chat_nick').
+ $SCRIPT_NAME.
+ weechat::color('chat_delimiters').
+ "] ".
+ weechat::color('reset').
+ "number of rows: ".
+ $count;
+
+ OUTPUT($buffer,$output);
+ return weechat::WEECHAT_RC_OK;
+ }
+ # get localvar from current buffer
+ my $name = weechat::buffer_get_string($buffer,'localvar_name');
+ my $server = weechat::buffer_get_string($buffer,'localvar_server');
+ my $type = weechat::buffer_get_string($buffer,'localvar_type');
+
+ if ( weechat::buffer_get_string($buffer,'plugin') ne 'irc' and lc($args_array[0]) eq 'scan' )
+ {
+ command_must_be_executed_on_irc_buffer();
+ return weechat::WEECHAT_RC_OK;
+ }
+
+ if (lc($args_array[0]) eq 'scan' && $type eq 'channel' && $number == 1)
+ {
+ channel_scan($buffer);
+# channel_scan_41(weechat::current_buffer());
+ return weechat::WEECHAT_RC_OK;
+ }
+
+ # at least, we have two arguments
+ return weechat::WEECHAT_RC_OK if ($number <= 1);
+
+ my $use_regex = 0;
+
+ if (lc($args_array[0]) eq 'scan' && $args_array[1] ne "")
+ {
+ $args_array[1] =~ s/\./,/; # info_get() needs an "," instead of "."
+ my $ptr_buffer = weechat::info_get('irc_buffer',$args_array[1]);
+# channel_scan_41($ptr_buffer) if ( $ptr_buffer ne "");
+ channel_scan($ptr_buffer) if ( $ptr_buffer ne "");
+ }
+ elsif (lc($args_array[0]) eq 'nick' or lc($args_array[0]) eq 'host')
+ {
+ if ( defined $args_array[2] and $args_array[2] eq "-regex" )
+ {
+ $use_regex = 1;
+ }
+ else
+ {
+ $server = $args_array[2] if ( defined $args_array[2] and $args_array[2] ne "" );
+ }
+
+ if ( defined $args_array[3] and $args_array[3] eq "-regex" )
+ {
+ $use_regex = 1;
+ }
+
+ if ( $server eq "" )
+ {
+ command_must_be_executed_on_irc_buffer();
+ return weechat::WEECHAT_RC_OK;
+ }
+ # $args_array[0]: 'nick' or 'host', $args_array[1]: nick or host name
+ # list will be print in subroutine!
+ my $nicks_found = join( ", ", (get_nick_records('no', $args_array[0], $args_array[1], $server, $use_regex)));
+ }
+ elsif (lc($args_array[0]) eq 'remove_nick_from_host')
+ {
+ $use_regex = 1 if ( grep{ $args_array[$_] eq '-regex' }0..$#args_array );
+
+ my $server = weechat::buffer_get_string($buffer,'localvar_server');
+
+ if ( $server eq "" )
+ {
+ command_must_be_executed_on_irc_buffer();
+ return weechat::WEECHAT_RC_OK;
+ }
+ my $affected_rows = _deassociate_nick_from_host( $args_array[1], $args_array[2], $server, $use_regex );
+ my $color = weechat::color(weechat::config_color(weechat::config_get('weechat.color.chat_prefix_error')));
+ my $DEBUG_prefix = weechat::config_string(weechat::config_get('weechat.look.prefix_error'));
+ weechat::print($buffer, _color_str($color, $DEBUG_prefix) . "\t$SCRIPT_NAME: $affected_rows deleted");
+ }
+ return weechat::WEECHAT_RC_OK;
+}
+
+sub command_must_be_executed_on_irc_buffer
+{
+ my $text = 'command must be executed on irc buffer (server or channel) or a server must be given';
+ my $color = weechat::color(weechat::config_color(weechat::config_get('weechat.color.chat_prefix_error')));
+ my $DEBUG_prefix = weechat::config_string(weechat::config_get('weechat.look.prefix_error'));
+ weechat::print('', _color_str($color, $DEBUG_prefix) . "\t$SCRIPT_NAME: $text");
+}
+# hdata_search()
+# hdata: hdata pointer
+# pointer: pointer to a WeeChat/plugin object
+# search: expression to evaluate, default pointer in expression is the name of hdata (and this pointer changes for each element in list); for help on expression, see command /eval in WeeChat User’s guide
+# move: number of jump(s) to execute after unsuccessful search (negative or positive integer, different from 0)
+
+sub channel_scan_41
+{
+ my $ptr_buffer = $_[0];
+
+ my $server_name = weechat::buffer_get_string($ptr_buffer, "localvar_server");
+ my $channel_name = weechat::buffer_get_string($ptr_buffer, "localvar_channel");
+ return if ($server_name eq "" or $channel_name eq "");
+
+#my %hdata = { map { $_ => weechat::hdata_get( "irc_" . $_ ) } qw( server channel nick ) };
+ my $hdata_server = weechat::hdata_get("irc_server");
+ my $hdata_channel = weechat::hdata_get("irc_channel");
+ my $hdata_nick = weechat::hdata_get("irc_nick");
+
+ my $ptr_server = weechat::hdata_search($hdata_server, weechat::hdata_get_list($hdata_server, 'irc_servers'), '${irc_server.name} == ' . $server_name, 1);
+ if ($ptr_server)
+ {
+ my $ptr_channel = weechat::hdata_search($hdata_channel, weechat::hdata_pointer($hdata_server, $ptr_server, 'channels'), '${irc_channel.name} == ' . $channel_name, 1);
+
+ if ($ptr_channel)
+ {
+ my $nick = weechat::hdata_pointer($hdata_channel, $ptr_channel, 'nicks');
+ while ( $nick )
+ {
+ my $nick_name = weechat::hdata_string($hdata_nick, $nick, 'name');
+ my $host_name = weechat::hdata_string($hdata_nick, $nick, 'host');
+ $host_name =~ /(.*)\@/;
+ my $user_name = $1;
+
+ add_record( $nick_name, $user_name, $host_name, $server_name);
+
+ $nick = weechat::hdata_move($hdata_nick, $nick, 1);
+ }
+ }
+
+ }
+# weechat::print("",$ptr_buffer);
+# weechat::print("",$server_name);
+
+# if ($ptr_servers)
+# {
+# my $channel = weechat::hdata_search(hdata['channel'], weechat.hdata_pointer(hdata['server'], server, 'channels'), '${irc_channel.name} == #test', 1)
+# }
+}
+sub channel_scan
+{
+ my $ptr_buffer = $_[0];
+ my $infolist = weechat::infolist_get('nicklist', $ptr_buffer, '');
+ # don't stalk yourself
+ my $my_nick = weechat::buffer_get_string($ptr_buffer,'localvar_nick');
+
+ my $nick_counter;
+
+ while (weechat::infolist_next($infolist))
+ {
+ my $nick = weechat::infolist_string($infolist, 'name');
+ if ((weechat::infolist_string($infolist, 'type') eq 'nick')
+ && ($nick ne $my_nick))
+ {
+ my $ptr_nick = weechat::nicklist_search_nick($ptr_buffer, '', $nick);
+ my $localvar_server = weechat::buffer_get_string($ptr_buffer,'localvar_server');
+ my $localvar_channel = weechat::buffer_get_string($ptr_buffer,'localvar_channel');
+
+ my $infolist_nick = weechat::infolist_get('irc_nick','',$localvar_server.','.$localvar_channel.','.$nick);
+ weechat::infolist_next($infolist_nick);
+ my $host = weechat::infolist_string($infolist_nick,'host');
+ weechat::infolist_free($infolist_nick);
+
+ next unless ($nick or $host or $localvar_server);
+ $host =~ /(.*)\@/;
+ $user = $1;
+
+ add_record( $nick, $user, $host, $localvar_server);
+
+# $user=~ s/[\Q-_~^`\E]//g;
+# my $hdata = weechat::hdata_get("irc_nick");
+# my $hdata_host = weechat::hdata_string($hdata, $ptr_nick, "host");
+# next if ($host eq $name);
+
+ }
+ }
+ weechat::infolist_free($infolist);
+}
+
+# simple check for last nick/host
+# to prevent multiple requests (e.g. "/nick|join nick" for several channels!)
+# 0 = failed
+# 1 = found
+sub check_last_nick_host
+{
+ my ($nick,$host) = @_;
+ my $rc = 0;
+
+ $rc = 1 if ($nick eq $last_nick && $host eq $last_host);
+
+ $last_nick = $nick;
+ $last_host = $host;
+ return $rc;
+}
+# -------------------------------[ hooks ]-------------------------------------
+# :old_nick!~user@host NICK :new_nick
+# /NICK command called
+# this is a server command
+sub irc_in2_nick_cb
+{
+ my ($signal, $callback, $callback_data) = @_;
+ my ($server,undef) = split(',',$callback);
+
+ return weechat::WEECHAT_RC_OK if ( lc($options{'ignore_nickchange'}) eq "on" );
+
+ DEBUG('info', 'weechat_hook_signal(): NICK change');
+
+ my $hashtable = weechat::info_get_hashtable("irc_message_parse" => + { "message" => $callback_data });
+
+ # $old_nick = $hashtable->{nick}
+ my ($old_nick, $host) = split('!', $hashtable->{host});
+ my $nick = $hashtable->{arguments};
+ $nick =~ s/^.//; # remove leading ":"
+ my ($user,undef) = split("@",$host);
+
+ return weechat::WEECHAT_RC_OK if check_last_nick_host($nick,$host);
+
+ add_record( $nick, $user, $host, $server);
+
+ return weechat::WEECHAT_RC_OK;
+}
+
+sub irc_in2_whois_cb
+{
+ my ($signal, $callback, $callback_data) = @_;
+ my ($server,undef) = split(',',$callback);
+
+ my $ptr_buffer = '';
+
+ my (undef, undef, undef, $nick, $user, $host, undef) = split(' ', $callback_data);
+ my $msgbuffer_whois = weechat::config_string(weechat::config_get('irc.msgbuffer.whois'));
+
+
+ DEBUG('info', 'weechat_hook_signal(): WHOIS');
+
+ # check for nick_regex
+ if ( lc($options{'ignore_guest_nicks'}) eq "on" )
+ {
+ my $regex = $options{'guest_nick_regex'};
+ return weechat::WEECHAT_RC_OK if( $nick =~ m/$regex/i );
+ }
+
+ my $complete_host = $user."@".$host;
+
+ unless ( check_last_nick_host($nick,$complete_host) or lc($options{'ignore_whois'}) eq "on" )
+ {
+ add_record( $nick, $user, $complete_host, $server);
+ }
+
+ # output for /whois
+ if ($msgbuffer_whois eq 'server')
+ {
+ $ptr_buffer = weechat::info_get('irc_buffer',$server);
+# $ptr_buffer = weechat::buffer_search('irc', 'server.' . $server);
+ }
+ elsif ($msgbuffer_whois eq 'weechat')
+ {
+ $ptr_buffer = weechat::buffer_search_main();
+ }
+ elsif ($msgbuffer_whois eq 'current')
+ {
+ $ptr_buffer = weechat::current_buffer();
+ }
+ elsif ($msgbuffer_whois eq 'private')
+ {
+ $ptr_buffer = weechat::info_get('irc_buffer',$server.','.$nick);
+ if ($ptr_buffer eq '')
+ {
+ $msgbuffer_whois = weechat::config_string(weechat::config_get('irc.look.msgbuffer_fallback'));
+ $ptr_buffer = weechat::info_get('irc_buffer', $server) if ($msgbuffer_whois eq 'server');
+ }
+ }
+
+ my $use_regex = 0;
+ my $nicks_found = join( ", ", (get_nick_records('yes', 'nick', $nick, $server, $use_regex)));
+# my $nicks_found = join( ", ", (get_nick_records('no', 'nick', $nick, $server, $use_regex)));
+
+ # only the given nick is returned?
+ return weechat::WEECHAT_RC_OK if ($nicks_found eq $nick or $nicks_found eq "");
+
+ # more than one nick was returned from sqlite
+ my $prefix_network = weechat::prefix('network');
+ my $color_chat_delimiter = weechat::color('chat_delimiters');
+ my $color_chat_nick = weechat::color('chat_nick');
+
+ my $output = weechat::color('chat_prefix_network').
+ weechat::prefix('network').
+ weechat::color('chat_delimiters').
+ "[".
+ weechat::color('chat_nick').
+ $SCRIPT_NAME.
+ weechat::color('chat_delimiters').
+ "] ".
+ $nicks_found;
+
+ # fallback buffer..
+ $ptr_buffer = weechat::buffer_search_main() unless ($ptr_buffer);
+
+ # print /WHOIS with [stalker] line
+ OUTPUT($ptr_buffer,$output);
+
+ return weechat::WEECHAT_RC_OK;
+}
+
+# callback_data: :nick!~user_2@host JOIN #channel
+sub irc_in2_join_cb
+{
+ my ($data, $buffer, $date, $tags, $displayed, $highlight, $prefix, $message) = @_;
+
+
+ # get nick, user and host. format: nick (user@host) translated join message
+ my ($nick,$user,$host) = ($message =~ /(.*) \((.*)\@(.*)\)/);
+ return weechat::WEECHAT_RC_OK if (not defined $nick or $nick eq ""
+ or not defined $user or $user eq ""
+ or not defined $host or $host eq "");
+
+ my $my_nick = weechat::buffer_get_string($buffer,'localvar_nick');
+ my $server = weechat::buffer_get_string($buffer,'localvar_server');
+ my $name = weechat::buffer_get_string($buffer,'localvar_name');
+
+ # don't stalk yourself
+ return weechat::WEECHAT_RC_OK if ($nick eq $my_nick);
+
+ return weechat::WEECHAT_RC_OK if check_last_nick_host($nick,$host);
+
+ DEBUG('info', 'weechat_hook_signal(): JOIN');
+
+ # check for localvar "stalker"
+ if ( lc($options{'use_localvar'}) eq "on" )
+ {
+ return weechat::WEECHAT_RC_OK if (not weechat::config_string_to_boolean(weechat::buffer_get_string($buffer, 'localvar_stalker')) );
+ }
+
+ # check if "flood_timer" is activated
+ if ( $options{'flood_timer'} > 0 )
+ {
+ # reset ptr_hook_timer and flood_counter if hook_timer() does not exists anymore
+ if ( $ptr_hook_timer ne "" and search_hook('hook',$ptr_hook_timer) eq 0 )
+ {
+ $ptr_hook_timer = "";
+ $flood_counter = 0;
+ }
+ # timer still running, add counter
+ else
+ {
+ $flood_counter++;
+ }
+
+ if ($ptr_hook_timer eq "")
+ {
+ # call timer only once
+ $ptr_hook_timer = weechat::hook_timer($options{'flood_timer'} * 1000, 0, 1, 'my_hook_timer_cb', '');
+ }
+
+ if ( $ptr_hook_timer ne "" and $flood_counter > $options{'flood_max_nicks'} )
+ {
+ DEBUG("info", "flood protection activated for: $nick with $user\@$host on $server");
+ return weechat::WEECHAT_RC_OK;
+ }
+ }
+ # end of flood protection
+
+ add_record( $nick, $user, $host, $server);
+
+ return weechat::WEECHAT_RC_OK if (weechat::config_string_to_boolean(weechat::buffer_get_string($buffer, 'localvar_stalker_drop_additional_join_info')) );
+
+ if ( lc($options{'additional_join_info'}) eq "on" )
+ {
+ my $filename = get_script_filename();
+ return weechat::WEECHAT_RC_OK if ($filename eq "");
+
+ # get tags for stalker output
+ my $my_tags = $options{'tags'};
+ # add tag 'irc_smart_filter' or 'irc_join' to list of tags, if tag(s) exists in original JOIN message
+ $my_tags = $my_tags . ',irc_smart_filter' if (index($tags,'irc_smart_filter') >= 0);
+ $my_tags = $my_tags . ',irc_join' if (index($tags,'irc_join') >= 0);
+
+ my $db_filename = weechat_dir();
+ DEBUG("info", "Start hook_process(), get additional info from $nick with $user\@$host on $name");
+ weechat::hook_process("perl $filename $db_filename 'additional_join_info' '$nick' '$user' '$host' '$server' $options{'max_recursion'} $options{'ignore_guest_nicks'} '$options{'guest_nick_regex'}'", 1000 * $options{'timeout'},"hook_process_get_nicks_records_cb","$nick $buffer $my_tags");
+ }
+ return weechat::WEECHAT_RC_OK;
+}
+
+# get absolute path of script
+sub get_script_filename
+{
+ my $infolist_ptr = weechat::infolist_get("perl_script","",$SCRIPT_NAME);
+ weechat::infolist_next($infolist_ptr);
+ my $filename = weechat::infolist_string($infolist_ptr,"filename");
+ weechat::infolist_free($infolist_ptr);
+ return $filename;
+}
+
+sub hook_process_get_nicks_records_cb
+{
+ my ($data, $command, $return_code, $out, $err) = @_;
+ DEBUG("info", "hook_process_get_nicks_records_cb: data=$data command=$command, rc=$return_code out=$out err=$err");
+
+ return weechat::WEECHAT_RC_OK if ( $return_code > 0 or $out eq ""); # something wrong!
+
+ my ($nick,$buffer_ptr,$tags) = split(/ /,$data);
+ my $nicks_found = $out;
+ # don't print output if there is no other nick used
+ return weechat::WEECHAT_RC_OK if ($nick eq $nicks_found or $nicks_found eq '');
+
+ my $string = weechat::color('chat_prefix_network').
+ weechat::prefix('network').
+ weechat::color('chat_delimiters').
+ "[".
+ weechat::color('chat_nick').
+ $SCRIPT_NAME.
+ weechat::color('chat_delimiters').
+ "] ".
+ weechat::color('reset').
+ $nick.
+ " is also known as: ".
+ $nicks_found;
+
+ weechat::print_date_tags($buffer_ptr,0,$tags,$string);
+ return weechat::WEECHAT_RC_OK;
+}
+
+sub search_hook
+{
+ my ($hook, $ptr_hook) = @_;
+ my $hook_found = 0;
+ my $infolist = weechat::infolist_get($hook, $ptr_hook, '');
+ while ( weechat::infolist_next($infolist) )
+ {
+ $hook_found = 1 if ( weechat::infolist_pointer($infolist,'pointer') eq $ptr_hook );
+ }
+ weechat::infolist_free($infolist);
+
+ return $hook_found;
+}
+
+sub my_hook_timer_cb
+{
+ # simply add the flood_counter
+ $flood_counter++;
+ return weechat::WEECHAT_RC_OK;
+}
+
+# -----------------------------[ config ]-----------------------------------
+sub init_config
+{
+
+ foreach my $option (keys %options){
+ if (!weechat::config_is_set_plugin($option)){
+ weechat::config_set_plugin($option, $options{$option});
+ }
+ else{
+ $options{$option} = weechat::config_get_plugin($option);
+ }
+ }
+ # set help text for options
+ if ( ($weechat_version ne '') && (weechat::info_get('version_number', '') >= 0x00030500) ) { # v0.3.5
+ foreach my $desc_options (keys %desc_options)
+ {
+ weechat::config_set_desc_plugin($desc_options,$desc_options{$desc_options});
+ }
+ }
+
+}
+
+sub toggle_config_by_set
+{
+ my ($pointer, $name, $value) = @_;
+ $name = substr($name, length("plugins.var.perl.$SCRIPT_NAME."), length($name));
+ $options{$name} = $value;
+# insert a refresh here
+ return weechat::WEECHAT_RC_OK;
+}
+# -----------------------------[ shutdown ]-----------------------------------
+sub shutdown_cb
+{
+ # close database
+ $DBH->disconnect();
+ $DBH_child->disconnect();
+ return weechat::WEECHAT_RC_OK;
+}
+
+# -------------------------------[ init ]-------------------------------------
+# first function called by a WeeChat-script.
+weechat::register($SCRIPT_NAME, $SCRIPT_AUTHOR, $SCRIPT_VERSION,
+ $SCRIPT_LICENCE, $SCRIPT_DESC, 'shutdown_cb', '');
+
+ $weechat_version = weechat::info_get('version_number', '');
+
+ if ( ($weechat_version ne '') && (weechat::info_get('version_number', '') <= 0x00030400) )
+ {
+ OUTPUT('',weechat::prefix('error') . 'You need WeeChat >= 0.3.4. Visit: www.weechat.org');
+ weechat::command('',"/wait 1ms /perl unload $SCRIPT_NAME");
+ }
+ else
+ {
+ init_config();
+ open_database();
+
+ weechat::hook_command($SCRIPT_NAME, $SCRIPT_DESC, "host <host> [server] [-regex] || nick <nick> [server] [-regex] || scan [<server.channel>] || count",
+ " host : look for hostname\n".
+ " nick : look for nick\n".
+ " scan : scan a channel (be careful; scanning large channels takes a while!)\n".
+ " you should manually /WHO #channel first or use /quote PROTOCTL UHNAMES\n".
+ " count: display the number of rows in database\n".
+ "remove_nick_from_host: remove a nick from a given host\n".
+ "\n\n".
+ "Stalker will add nick!user\@host to database monitoring JOIN/WHOIS/NICK messages.\n\n".
+ "\n".
+ "Monitor specific channels:\n".
+ "==========================\n".
+ "Set following option:\n".
+ " /set plugins.var.perl.".$SCRIPT_NAME.".use_localvar \"on\" (default: off)\n".
+ "Now you'll have to set a localvar for those channels to monitor:\n".
+ " /buffer set localvar_set_stalker [value]\n".
+ " values: \"on\", \"true\", \"t\", \"yes\", \"y\", \"1\")\n".
+ "\n".
+ "Display additional information below join message:\n".
+ "=================================================\n".
+ "Example: [stalker] nils_2 is also known as: nils_2_\n".
+ " /set plugins.var.perl.".$SCRIPT_NAME.".additional_join_info \"on\" (default: off)\n".
+ "If you want to drop informations for specific channels (especially channels with lot of nicks):\n".
+ " /buffer set localvar_set_stalker_drop_additional_join_info [value]\n".
+ " values: \"on\", \"true\", \"t\", \"yes\", \"y\", \"1\")\n".
+ "\n".
+ "Regex:\n".
+ "======\n".
+ "$SCRIPT_NAME performs standard perl regular expression matching with option '-regex'.\n".
+ "Note that regex matching will not use SQLite indices, but will iterate over all rows, so it could be quite costly in terms of performance.\n".
+ "\n".
+ "Tags:\n".
+ "======\n".
+ $SCRIPT_NAME." can use tags to display messages. See documentation for most commonly used tags and add them in following option:\n".
+ " /set plugins.var.perl.".$SCRIPT_NAME.".tags \"no_log\"\n".
+ "\n".
+ "Examples:\n".
+ " search for nick 'nils_2'\n".
+ " /".$SCRIPT_NAME." nick nils_2\n".
+ " search for nick 'nils_2' on a different server named 'unknown'\n".
+ " /".$SCRIPT_NAME." nick nils_2 unknown\n".
+ " search for nicks starting with 'ni'\n".
+ " /".$SCRIPT_NAME." nick \\bni.* -regex\n".
+ " search all hosts located in '.de'\n".
+ " /".$SCRIPT_NAME." host .*\\.de -regex\n".
+ " remove nick from an association host'\n".
+ " /".$SCRIPT_NAME." remove_nick_from_host TheNick ~the\@bad.users.host\n".
+ "",
+ "count %-||".
+ "host %% %(irc_servers)|-regex %-||".
+ "nick %(nick) %(irc_servers)|-regex -regex %-||".
+ "remove_nick_from_host %(nick) |-regex -regex %-||".
+ "scan %(buffers_names) %-", "stalker_command_cb", "");
+
+ weechat::hook_config("plugins.var.perl.$SCRIPT_NAME.*", "toggle_config_by_set", "");
+# weechat::hook_signal('*,irc_in2_join', 'irc_in2_join_cb', '');
+ weechat::hook_print('','irc_join','',1,'irc_in2_join_cb','');
+ weechat::hook_signal('*,irc_in2_311', 'irc_in2_whois_cb', '');
+ weechat::hook_signal('*,irc_in2_NICK', 'irc_in2_nick_cb', '');
+ }
diff --git a/weechat/perl/yaurls.pl b/weechat/perl/yaurls.pl
new file mode 100644
index 0000000..caae3e2
--- /dev/null
+++ b/weechat/perl/yaurls.pl
@@ -0,0 +1,301 @@
+# Copyright (c) 2012 by R1cochet R1cochet@hushmail.com
+# All rights reserved
+#
+# 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/>.
+#
+#
+# yaURLs, version 1.9, for weechat version 0.3.7 or later
+# will shorten URL's in channels
+#
+# Shorten URL's using any of the following services:
+# durl.me, is.gd, ln-s.net, lytn.it, metamark.net, sapo.pt, safe.mn, tinyURL.com
+#
+# Default color theme in 256color terminal
+# header: 46
+# prefix/suffix: *200
+# url: *190
+# domain: 196
+#
+#
+# Changelog:
+# 2012-09-21, R1cochet
+# version 1.9: Added more shortening services
+# 2012-03-09, Sebastien Helleu <flashcode@flashtux.org>
+# version 1.8: Fix reload of config file
+# 2012-03-08, R1cochet
+# version 1.7: Removed need for Regexp::Common and URI::Escape modules. Cleaned up some code
+# 2012-03-04, R1cochet
+# version 1.6: Fixed error with twitter links not being recognized. Added module URI::Escape to properly format URL's before shortening
+# 2012-02-28, R1cochet
+# version 1.5: Initial release
+
+use strict;
+use warnings;
+
+my $SCRIPT_NAME = "yaurls";
+my $SCRIPT_AUTHOR = "R1cochet";
+my $VERSION = "1.9";
+my $SCRIPT_LICENSE = "GPL3";
+my $SCRIPT_DESC = "yes, another URL shortener";
+
+# initialize global variables
+my $config_file; # config pointer
+my %config_section; # config section pointer
+my %config_options; # init config options
+my $incoming_nick = "";
+
+my %Unsafe = (RFC3986 => qr/[^A-Za-z0-9\-\._~]/,);
+my %escapes;
+for (0..255) {
+ $escapes{chr($_)} = sprintf("%%%02X", $_);
+}
+
+weechat::register($SCRIPT_NAME, $SCRIPT_AUTHOR, $VERSION, $SCRIPT_LICENSE, $SCRIPT_DESC, "", "");
+
+### initial config
+sub init_config {
+ $config_file = weechat::config_new("yaurls", "config_reload_cb", "");
+ return if (!$config_file);
+
+ # create new section in config file
+ $config_section{'blacklists'} = weechat::config_new_section($config_file, "blacklists", 0, 0, "", "", "", "", "", "", "", "", "", "");
+ if (!$config_section{'blacklists'}) {
+ weechat::config_free($config_file);
+ return;
+ }
+ # add the options to the section
+ $config_options{'channel_blacklist'} = weechat::config_new_option($config_file, $config_section{'blacklists'}, "channel_blacklist", "string",
+ "Comma seperated list of Channels to ignore", "", 0, 0, "", "", 1, "", "", "", "", "", "",);
+ $config_options{'nick_blacklist'} = weechat::config_new_option($config_file, $config_section{'blacklists'}, "nick_blacklist", "string",
+ "Comma seperated list of Nicks to ignore", "", 0, 0, "", "", 1, "", "", "", "", "", "",);
+ $config_options{'server_blacklist'} = weechat::config_new_option($config_file, $config_section{'blacklists'}, "server_blacklist", "string",
+ "Comma seperated list of Servers to ignore", "", 0, 0, "", "", 1, "", "", "", "", "", "",);
+ $config_options{'string_blacklist'} = weechat::config_new_option($config_file, $config_section{'blacklists'}, "string_blacklist", "string",
+ "Comma seperated list of Strings to ignore", "", 0, 0, "", "", 1, "", "", "", "", "", "",);
+ $config_options{'url_blacklist'} = weechat::config_new_option($config_file, $config_section{'blacklists'}, "url_blacklist", "string",
+ "Comma seperated list of URL's to ignore", "", 0, 0, "youtube.com", "youtube.com", 1, "", "", "", "", "", "",);
+
+ $config_section{'colors'} = weechat::config_new_section($config_file, "colors", 0, 0, "", "", "", "", "", "", "", "", "", "");
+ if (!$config_section{'colors'}) {
+ weechat::config_free($config_file);
+ return;
+ }
+ $config_options{'header_color'} = weechat::config_new_option($config_file, $config_section{'colors'}, "header_color", "color",
+ "Set the color of the header", "", 0, 0, "green", "green", 0, "", "", "", "", "", "",);
+ $config_options{'prefix_color'} = weechat::config_new_option($config_file, $config_section{'colors'}, "prefix_suffix_color", "color",
+ "Set the color of the prefix and suffix", "", 0, 0, "magenta", "magenta", 0, "", "", "", "", "", "",);
+ $config_options{'url_color'} = weechat::config_new_option($config_file, $config_section{'colors'}, "url_color", "color",
+ "Set the color of the tinyURL link", "", 0, 0, "yellow", "yellow", 0, "", "", "", "", "", "",);
+ $config_options{'domain_color'} = weechat::config_new_option($config_file, $config_section{'colors'}, "domain_color", "color",
+ "Set the color of the domain name", "", 0, 0, "blue", "blue", 0, "", "", "", "", "", "",);
+
+ $config_section{'engine'} = weechat::config_new_section($config_file, "engine", 0, 0, "", "", "", "", "", "", "", "", "", "");
+ if (!$config_section{'engine'}) {
+ weechat::config_free($config_file);
+ return;
+ }
+ $config_options{'service'} = weechat::config_new_option($config_file, $config_section{'engine'}, "service", "integer",
+ "Set which shortener service to use (durl = durl.me, is.gd = is.gd, ln-s = ln-s.net, lytn = lytn.it, ".
+ "metamark = metamark.net, punyURL = sapo.pt, safe = safe.mn, tinyURL = tinyURL.com)",
+ "durl|is.gd|ln-s|lytn|metamark|punyURL|safe|tinyURL", 0, 0, "tinyURL", "tinyURL", 0, "", "", "", "", "", "");
+ $config_options{'convert_own'} = weechat::config_new_option($config_file, $config_section{'engine'}, "convert_own", "boolean",
+ "Convert own links sent to buffer", "", 0, 0, "off", "off", 0, "", "", "", "", "", "",);
+ $config_options{'maximum_length'} = weechat::config_new_option($config_file, $config_section{'engine'}, "maximum_length", "integer",
+ "Set the maximum length of URL's to be converted (anything equal to or larger will be converted)", "", 20, 500, "35", "35", 0, "", "", "", "", "", "");
+ $config_options{'timeout'} = weechat::config_new_option($config_file, $config_section{'engine'}, "timeout", "integer",
+ "Set the maximum time limit for fetching the short URL (time in seconds)", "", 10, 120, "20", "20", 0, "", "", "", "", "", "");
+
+ $config_section{'look'} = weechat::config_new_section($config_file, "look", 0, 0, "", "", "", "", "", "", "", "", "", "");
+ if (!$config_section{'look'}) {
+ weechat::config_free($config_file);
+ return;
+ }
+ $config_options{'header'} = weechat::config_new_option($config_file, $config_section{'look'}, "header", "string",
+ "Set the header string", "", 0, 0, "yaURLs", "yaURLs", 1, "", "", "", "", "", "",);
+ $config_options{'header_prefix'} = weechat::config_new_option($config_file, $config_section{'look'}, "header_prefix", "string",
+ "Set the header prefix", "", 0, 0, "{", "{", 1, "", "", "", "", "", "",);
+ $config_options{'header_suffix'} = weechat::config_new_option($config_file, $config_section{'look'}, "header_suffix", "string",
+ "Set the header suffix", "", 0, 0, "}~>", "}~>", 1, "", "", "", "", "", "",);
+ $config_options{'format'} = weechat::config_new_option($config_file, $config_section{'look'}, "format", "string",
+ "Set the print format (%H = Header, %U = tinyURL, %D = Domain)", "", 0, 0, "%H %U %D", "%H %U %D", 0, "", "", "", "", "", "",);
+}
+# intit callbacks
+sub config_reload_cb { # reload config file
+ return weechat::config_reload($config_file);
+}
+
+sub config_read { # read my config file
+ return weechat::config_read($config_file);
+}
+
+sub config_write { # write to my config file
+ return weechat::config_write($config_file);
+}
+
+init_config(); # load config
+config_read(); # get options if already in config file
+
+weechat::hook_print( "", "irc_privmsg", "://", 1, "print_hook_cb", ""); # Hook into print
+
+sub build_header {
+ my $header = weechat::color(weechat::config_color($config_options{'header_color'})) . weechat::config_string($config_options{'header'}) . weechat::color("reset");
+ $header = weechat::color(weechat::config_color($config_options{'prefix_color'})) . weechat::config_string($config_options{'header_prefix'}) . weechat::color("reset") . $header;
+ $header = $header . weechat::color(weechat::config_color($config_options{'prefix_color'})) . weechat::config_string($config_options{'header_suffix'}) . weechat::color("reset");
+ return $header;
+}
+
+sub black_list1 { # match url, string
+ my ($string, $black_list) = @_;
+ my @black_list = split ",", $black_list;
+ foreach(@black_list) {
+ return 1 if $string =~ /\Q$_\E/i;
+ }
+ return 0;
+}
+
+sub black_list2 { # match nick, server, channel; front to end
+ my ($string, $black_list) = @_;
+ my @black_list = split ",", $black_list;
+ foreach(@black_list) {
+ return 1 if $string =~ /^\Q$_\E\z/;
+ }
+ return 0;
+}
+
+sub uri_escape {
+ my $url = shift;
+ utf8::encode($url);
+ $url =~ s/($Unsafe{RFC3986})/$escapes{$1}/ge;
+ return $url;
+}
+
+sub service_url {
+ my $url = shift;
+ $url = uri_escape($url);
+
+ if (weechat::config_string($config_options{'service'}) eq "durl") {
+ $url = "http://durl.me/api/Create.do?longurl=$url";
+ }
+ elsif (weechat::config_string($config_options{'service'}) eq "is.gd") {
+ $url = "http://is.gd/create.php?format=simple&url=$url";
+ }
+ elsif (weechat::config_string($config_options{'service'}) eq "ln-s") {
+ $url = "http://ln-s.net/home/api.jsp?url=$url";
+ }
+ elsif (weechat::config_string($config_options{'service'}) eq "lytn") {
+ $url = "http://lytn.it/api.php?rel=2&link=$url";
+ }
+ elsif (weechat::config_string($config_options{'service'}) eq "metamark") {
+ $url = "http://metamark.net/api/rest/simple?long_url=$url";
+ }
+ elsif (weechat::config_string($config_options{'service'}) eq "punyURL") {
+ $url = "http://services.sapo.pt/PunyURL/GetCompressedURLByURL?url=$url";
+ }
+ elsif (weechat::config_string($config_options{'service'}) eq "safe") {
+ $url = "http://safe.mn/api/?format=text&url=$url";
+ }
+ else {
+ $url = "http://tinyurl.com/api-create.php?url=$url";
+ }
+
+ return $url;
+}
+
+sub process_cb {
+ my ($buffer_domain, $command, $return_code, $out, $err) = @_;
+
+ if ($return_code != 0) { # weechat::WEECHAT_HOOK_PROCESS_ERROR
+ weechat::print("", "Error with command: $command");
+ weechat::print("", "An error occured: $err") if ($err ne "");
+ weechat::print("", "ret code: $return_code");
+ }
+ elsif ($out) {
+ my ($buffer, $domain) = split "_:_", $buffer_domain, 2;
+ my $header = build_header();
+ $domain = weechat::color(weechat::config_color($config_options{'domain_color'})) . "($domain)" . weechat::color("reset");
+
+ if (weechat::config_string($config_options{'service'}) eq "durl") {
+ ($out) = $out =~ m/(http:\/\/durl\.me\/\w+)/;
+ }
+ elsif (weechat::config_string($config_options{'service'}) eq "ln-s") {
+ $out =~ s/^(\d{3}\s)|\n*$//g;
+ }
+ elsif (weechat::config_string($config_options{'service'}) eq "punyURL") {
+ weechat::print("", "punyURL called");
+ ($out) = $out =~ m/.+\<ascii\>(.+)\<\/ascii\>/;
+ }
+ elsif (weechat::config_string($config_options{'service'}) eq "safe") {
+ $out =~ s/\n*//g;
+ }
+
+ my $short_url = weechat::color(weechat::config_color($config_options{'url_color'})) . $out . weechat::color("reset");
+ my $tiny_url = weechat::config_string($config_options{'format'});
+
+ $tiny_url =~ s/%H/$header/;
+ $tiny_url =~ s/%U/$short_url/;
+ $tiny_url =~ s/%D/$domain/;
+ weechat::print($buffer, "$tiny_url");
+ }
+ return weechat::WEECHAT_RC_OK;
+}
+
+sub print_hook_cb {
+ my ($data, $buffer, $date, $tags, $displayed, $highlight, $prefix, $msg) = @_;
+ return weechat::WEECHAT_RC_OK if ($displayed != 1); # return if initial message wont be shown
+
+ if ((weechat::config_string($config_options{'string_blacklist'})) ne "") { # check message against "string blacklist"
+ return weechat::WEECHAT_RC_OK if (black_list1($msg, weechat::config_string($config_options{'string_blacklist'}))); # return if string is blacklisted
+ }
+
+ my $hdata = weechat::hdata_get("buffer");
+ my $buffer_name = weechat::hdata_string($hdata, $buffer, "name");
+ my ($server, $channel) = split /\./, $buffer_name; # can be done with a match
+ $channel =~ s/#//;
+
+ if ((weechat::config_string($config_options{'server_blacklist'})) ne "") { # check message against "server blacklist"
+ return weechat::WEECHAT_RC_OK if (black_list2($server, weechat::config_string($config_options{'server_blacklist'}))); # return if server is blacklisted
+ }
+
+ if ((weechat::config_string($config_options{'channel_blacklist'})) ne "") { # check message against "channel blacklist"
+ return weechat::WEECHAT_RC_OK if (black_list2($channel, weechat::config_string($config_options{'channel_blacklist'}))); # return if nick is blacklisted
+ }
+
+ ($incoming_nick = $tags) =~ s/.*nick_//i;
+ $incoming_nick =~ s/,.*//i;
+ my $own_nick = weechat::info_get("irc_nick", $server);
+
+ if (!weechat::config_boolean($config_options{'convert_own'})) { # check if converting own
+ return weechat::WEECHAT_RC_OK if $incoming_nick =~ /^\Q$own_nick\E\z/;
+ }
+
+ if ((weechat::config_string($config_options{'nick_blacklist'})) ne "") { # check message against "nick blacklist"
+ return weechat::WEECHAT_RC_OK if (black_list2($incoming_nick, weechat::config_string($config_options{'nick_blacklist'}))); # return if nick is blacklisted
+ }
+
+ my @msg = split " ", $msg;
+ foreach(@msg) {
+ if ($_ =~ /^(ht|f)tp/ && $_ =~ m|(?:([^:/?#]+):)?(?://([^/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?|) {
+ next if (length($_) <= weechat::config_integer($config_options{'maximum_length'})); # skip if url shorter than max
+
+ if (weechat::config_string($config_options{'url_blacklist'}) ne "") {
+ next if (black_list1($_, weechat::config_string($config_options{'url_blacklist'}))); # skip if url is blacklisted
+ }
+ my $buffer_domain = $buffer."_:_$2";
+ my $url = service_url($_);
+
+ weechat::hook_process("url:$url", weechat::config_integer($config_options{'timeout'}) * 1000, "process_cb", $buffer_domain);
+ }
+ }
+ return weechat::WEECHAT_RC_OK;
+}
diff --git a/weechat/python/announce_url_title.py b/weechat/python/announce_url_title.py
new file mode 100644
index 0000000..95bd796
--- /dev/null
+++ b/weechat/python/announce_url_title.py
@@ -0,0 +1,318 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2009 by xt <xt@bash.no>
+# Borrowed parts from pagetitle.py by xororand
+#
+# 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/>.
+#
+
+#
+#
+# If someone posts an URL in a configured channel
+# this script will post back title
+
+# Explanation about ignores:
+# * plugins.var.python.announce_url_title.ignore_buffers:
+# Comma separated list of patterns for define ignores.
+# URLs from channels where its name matches any of these patterns will be ignored.
+# Wildcards '*', '?' and char groups [..] can be used.
+# An ignore exception can be added by prefixing '!' in the pattern.
+#
+# Example:
+# *ubuntu*,!#ubuntu-offtopic
+# any urls from a 'ubuntu' channel will be ignored,
+# except from #ubuntu-offtopic
+#
+# * plugins.var.python.announce_url_title.url_ignore
+# simply does partial match, so specifying 'google' will ignore every url with the word google in it
+#
+#
+# History:
+# 2012-11-15, xt
+# version 16: improve escaping
+# 2011-09-04, Deltafire
+# version 15: fix remote execution exploit due to unescaped ' character in urls;
+# small bug fix for version 14 changes
+# 2011-08-23, Deltafire
+# version 14: ignore filtered lines
+# 2011-03-11, Sebastien Helleu <flashcode@flashtux.org>
+# version 13: get python 2.x binary for hook_process (fix problem when python 3.x is default python version)
+# 2010-12-10, xt
+# version 12: add better ignores (code based on m4v inotify.py)
+# 2010-11-02, xt
+# version 11: add prefix
+# 2010-11-01, xt
+# version 10: add ignored buffers feature
+# 2010-10-29, add ignore buffers feature
+# version 0.9: WeeChat user-agent option
+# 2010-10-11, xt
+# version 0.8: support multiple concurrent url lookups
+# 2010-10-11, xt
+# version 0.7: do not trigger on notices
+# 2010-08-25, xt
+# version 0.6: notice some buffers instead of msg
+# 2009-12-08, Chaz6
+# version 0.5: only announce for specified channels
+# 2009-12-08, Chaz6 <chaz@chaz6.com>
+# version 0.4: add global option
+# 2009-12-08, xt
+# version 0.3: option for public announcing or not
+# 2009-12-07, xt <xt@bash.no>
+# version 0.2: don't renannounce same urls for a time
+# add optional prefix and suffix
+# 2009-12-02, xt
+# version 0.1: initial
+
+import weechat
+w = weechat
+import re
+import htmllib
+from time import time as now
+from fnmatch import fnmatch
+from urllib import quote
+
+SCRIPT_NAME = "announce_url_title"
+SCRIPT_AUTHOR = "xt <xt@bash.no>"
+SCRIPT_VERSION = "16"
+SCRIPT_LICENSE = "GPL3"
+SCRIPT_DESC = "Announce URL titles to channel or locally"
+
+settings = {
+ "buffers" : 'freenode.#testing,', # comma separated list of buffers
+ "buffers_notice" : 'freenode.#testing,', # comma separated list of buffers
+ 'ignore_buffers' : 'grep,', # comma separated list of buffers to be ignored by this module
+ 'title_max_length': '80',
+ 'url_ignore' : '', # comma separated list of strings in url to ignore
+ 'reannounce_wait': '5', # 5 minutes delay
+ 'prefix': '',
+ 'suffix': '',
+ 'announce_public': 'off', # print it or msg the buffer
+ 'global': 'off', # whether to enable for all buffers
+ 'user_agent': 'WeeChat/%(version)s (http://www.weechat.org)', # user-agent format string
+ 'global_prefix':'url', # Prefix for when not public announcement
+}
+
+
+octet = r'(?:2(?:[0-4]\d|5[0-5])|1\d\d|\d{1,2})'
+ipAddr = r'%s(?:\,.%s){3}' % (octet, octet)
+# Base domain regex off RFC 1034 and 1738
+label = r'[0-9a-z][-0-9a-z]*[0-9a-z]?'
+domain = r'%s(?:\.%s)*\.[a-z][-0-9a-z]*[a-z]?' % (label, label)
+urlRe = re.compile(r'(\w+://(?:%s|%s)(?::\d+)?(?:/[^\])>\s]*)?)' % (domain, ipAddr), re.I)
+
+buffer_name = ''
+
+urls = {}
+script_nick = 'url'
+def say(s, buffer=''):
+ """normal msg"""
+ weechat.prnt(buffer, '%s\t%s' %(script_nick, s))
+
+def unescape(s):
+ """Unescape HTML entities"""
+ p = htmllib.HTMLParser(None)
+ p.save_bgn()
+ p.feed(s)
+ return p.save_end()
+
+def url_print_cb(data, buffer, time, tags, displayed, highlight, prefix, message):
+ global buffer_name, urls, ignore_buffers
+
+ # Do not trigger on filtered lines and notices
+ if displayed == '0' or prefix == '--':
+ return w.WEECHAT_RC_OK
+
+ msg_buffer_name = w.buffer_get_string(buffer, "name")
+ # Skip ignored buffers
+
+ #if msg_buffer_name in w.config_get_plugin('ignore_buffers').split(','):
+ # return w.WEECHAT_RC_OK
+ if msg_buffer_name in ignore_buffers:
+ return w.WEECHAT_RC_OK
+
+ found = False
+ notice = False
+ if w.config_get_plugin('global') == 'on':
+ found = True
+ buffer_name = msg_buffer_name
+ else:
+ for active_buffer in w.config_get_plugin('buffers').split(','):
+ if active_buffer.lower() == msg_buffer_name.lower():
+ found = True
+ buffer_name = msg_buffer_name
+ break
+ for active_buffer in w.config_get_plugin('buffers_notice').split(','):
+ if active_buffer.lower() == msg_buffer_name.lower():
+ found = True
+ buffer_name = msg_buffer_name
+ break
+
+ if not found:
+ return w.WEECHAT_RC_OK
+
+ ignorelist = w.config_get_plugin('url_ignore').split(',')
+ for url in urlRe.findall(message):
+
+ url = quote(url, ":/") # Escape URL
+ ignore = False
+ for ignore_part in ignorelist:
+ if ignore_part.strip():
+ if ignore_part in url:
+ ignore = True
+ w.prnt('', '%s: Found %s in URL: %s, ignoring.' %(SCRIPT_NAME, ignore_part, url))
+ break
+
+ if ignore:
+ continue
+
+ if url in urls:
+ continue
+ else:
+ urls[url] = {}
+ url_process_launcher()
+
+ return w.WEECHAT_RC_OK
+
+def url_process_launcher():
+ ''' Iterate found urls, fetch title if hasn't been launched '''
+ global urls
+
+ user_agent = w.config_get_plugin('user_agent') % {'version': w.info_get("version", "")}
+ for url, url_d in urls.items():
+ if not url_d: # empty dict means not launched
+ url_d['launched'] = now()
+
+ # Read 8192
+ python2_bin = w.info_get("python2_bin", "") or "python"
+ cmd = python2_bin + " -c \"import urllib2; opener = urllib2.build_opener();"
+ cmd += "opener.addheaders = [('User-agent','%s')];" % user_agent
+ cmd += "print opener.open('%s').read(8192)\"" % url
+
+ url_d['stdout'] = ''
+ url_d['url_hook_process'] = w.hook_process(cmd, 30 * 1000, "url_process_cb", "")
+
+ return w.WEECHAT_RC_OK
+
+def url_process_cb(data, command, rc, stdout, stderr):
+ """ Callback parsing html for title """
+
+ global buffer_name, urls
+
+ url = command.split("'")[-2]
+ if stdout != "":
+ urls[url]['stdout'] += stdout
+ if int(rc) >= 0:
+
+ head = re.sub("[\r\n\t ]"," ", urls[url]['stdout'])
+ title = re.search('(?i)\<title\>(.*?)\</title\>', head)
+ if title:
+ title = unescape(title.group(1))
+
+ max_len = int(w.config_get_plugin('title_max_length'))
+ if len(title) > max_len:
+ title = "%s [...]" % title[0:max_len]
+
+ splits = buffer_name.split('.') #FIXME bad code
+ server = splits[0]
+ buffer = '.'.join(splits[1:])
+ output = w.config_get_plugin('prefix') + title + w.config_get_plugin('suffix')
+ announce_public = w.config_get_plugin('announce_public')
+ if announce_public == 'on':
+ found = False
+ for active_buffer in w.config_get_plugin('buffers').split(','):
+ if active_buffer.lower() == buffer_name.lower():
+ w.command('', '/msg -server %s %s %s' %(server, buffer, output))
+ found = True
+ for active_buffer in w.config_get_plugin('buffers_notice').split(','):
+ if active_buffer.lower() == buffer_name.lower():
+ w.command('', '/notice -server %s %s %s' %(server, buffer, output))
+ found = True
+ if found == False:
+ say(output,w.buffer_search('', buffer_name))
+ else:
+ say(output,w.buffer_search('', buffer_name))
+ urls[url]['stdout'] = ''
+
+ return w.WEECHAT_RC_OK
+
+def purge_cb(*args):
+ ''' Purge the url list on configured intervals '''
+
+ global urls
+
+ t_now = now()
+ for url, url_d in urls.items():
+ if (t_now - url_d['launched']) > \
+ int(w.config_get_plugin('reannounce_wait'))*60:
+ del urls[url]
+
+ return w.WEECHAT_RC_OK
+
+class Ignores(object):
+ def __init__(self, ignore_type):
+ self.ignore_type = ignore_type
+ self.ignores = []
+ self.exceptions = []
+ self._get_ignores()
+
+ def _get_ignores(self):
+ assert self.ignore_type is not None
+ ignores = weechat.config_get_plugin(self.ignore_type).split(',')
+ ignores = [ s.lower() for s in ignores if s ]
+ self.ignores = [ s for s in ignores if s[0] != '!' ]
+ self.exceptions = [ s[1:] for s in ignores if s[0] == '!' ]
+
+ def __contains__(self, s):
+ s = s.lower()
+ for p in self.ignores:
+ if fnmatch(s, p):
+ for e in self.exceptions:
+ if fnmatch(s, e):
+ return False
+ return True
+ return False
+
+def ignore_update(*args):
+ ignore_buffers._get_ignores()
+ return w.WEECHAT_RC_OK
+
+
+if __name__ == "__main__":
+ if w.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE,
+ SCRIPT_DESC, "", ""):
+
+ # Set default settings
+ for option, default_value in settings.iteritems():
+ if not w.config_is_set_plugin(option):
+ w.config_set_plugin(option, default_value)
+ ignore_buffers = Ignores('ignore_buffers')
+
+ w.hook_print("", "", "://", 1, "url_print_cb", "")
+ w.hook_timer(\
+ int(w.config_get_plugin('reannounce_wait')) * 1000 * 60,
+ 0,
+ 0,
+ "purge_cb",
+ '')
+ weechat.hook_config('plugins.var.python.%s.ignore_buffers' %SCRIPT_NAME, 'ignore_update', '')
+ color_chat_delimiters = weechat.color('chat_delimiters')
+ color_chat_nick = weechat.color('chat_nick')
+ color_reset = weechat.color('reset')
+ color_chat_buffer = weechat.color('chat_buffer')
+ # pretty printing
+ script_nick = '%s[%s%s%s]%s' %(color_chat_delimiters,
+ color_chat_nick,
+ w.config_get_plugin('global_prefix'),
+ color_chat_delimiters,
+ color_reset)
diff --git a/weechat/python/anotify.py b/weechat/python/anotify.py
new file mode 100644
index 0000000..19e2445
--- /dev/null
+++ b/weechat/python/anotify.py
@@ -0,0 +1,470 @@
+# -*- coding: utf-8 -*-
+#
+# anotify.py
+# Copyright (c) 2012 magnific0 <jacco.geul@gmail.com>
+#
+# based on:
+# growl.py
+# Copyright (c) 2011 Sorin Ionescu <sorin.ionescu@gmail.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+
+SCRIPT_NAME = 'anotify'
+SCRIPT_AUTHOR = 'magnific0'
+SCRIPT_VERSION = '1.0.0'
+SCRIPT_LICENSE = 'MIT'
+SCRIPT_DESC = 'Sends libnotify notifications upon events.'
+
+
+# Changelog
+# 2012-09-20: v1.0.0 Forked from original and adapted for libnotify.
+
+# -----------------------------------------------------------------------------
+# Settings
+# -----------------------------------------------------------------------------
+SETTINGS = {
+ 'show_public_message': 'off',
+ 'show_private_message': 'on',
+ 'show_public_action_message': 'off',
+ 'show_private_action_message': 'on',
+ 'show_notice_message': 'off',
+ 'show_invite_message': 'on',
+ 'show_highlighted_message': 'on',
+ 'show_server': 'on',
+ 'show_channel_topic': 'on',
+ 'show_dcc': 'on',
+ 'show_upgrade_ended': 'on',
+ 'sticky': 'off',
+ 'sticky_away': 'on',
+ 'icon': '/usr/share/pixmaps/weechat.xpm',
+}
+
+
+# -----------------------------------------------------------------------------
+# Imports
+# -----------------------------------------------------------------------------
+try:
+ import re
+ import os
+ import weechat
+ import pynotify
+ IMPORT_OK = True
+except ImportError as error:
+ IMPORT_OK = False
+ if str(error).find('weechat') != -1:
+ print('This script must be run under WeeChat.')
+ print('Get WeeChat at http://www.weechat.org.')
+ else:
+ weechat.prnt('', 'anotify: {0}'.format(error))
+
+# -----------------------------------------------------------------------------
+# Globals
+# -----------------------------------------------------------------------------
+TAGGED_MESSAGES = {
+ 'public message or action': set(['irc_privmsg', 'notify_message']),
+ 'private message or action': set(['irc_privmsg', 'notify_private']),
+ 'notice message': set(['irc_notice', 'notify_private']),
+ 'invite message': set(['irc_invite', 'notify_highlight']),
+ 'channel topic': set(['irc_topic', ]),
+ #'away status': set(['away_info', ]),
+}
+
+
+UNTAGGED_MESSAGES = {
+ 'away status':
+ re.compile(r'^You ((\w+).){2,3}marked as being away', re.UNICODE),
+ 'dcc chat request':
+ re.compile(r'^xfer: incoming chat request from (\w+)', re.UNICODE),
+ 'dcc chat closed':
+ re.compile(r'^xfer: chat closed with (\w+)', re.UNICODE),
+ 'dcc get request':
+ re.compile(
+ r'^xfer: incoming file from (\w+) [^:]+: ((?:,\w|[^,])+),',
+ re.UNICODE),
+ 'dcc get completed':
+ re.compile(r'^xfer: file ([^\s]+) received from \w+: OK', re.UNICODE),
+ 'dcc get failed':
+ re.compile(
+ r'^xfer: file ([^\s]+) received from \w+: FAILED',
+ re.UNICODE),
+ 'dcc send completed':
+ re.compile(r'^xfer: file ([^\s]+) sent to \w+: OK', re.UNICODE),
+ 'dcc send failed':
+ re.compile(r'^xfer: file ([^\s]+) sent to \w+: FAILED', re.UNICODE),
+}
+
+
+DISPATCH_TABLE = {
+ 'away status': 'set_away_status',
+ 'public message or action': 'notify_public_message_or_action',
+ 'private message or action': 'notify_private_message_or_action',
+ 'notice message': 'notify_notice_message',
+ 'invite message': 'notify_invite_message',
+ 'channel topic': 'notify_channel_topic',
+ 'dcc chat request': 'notify_dcc_chat_request',
+ 'dcc chat closed': 'notify_dcc_chat_closed',
+ 'dcc get request': 'notify_dcc_get_request',
+ 'dcc get completed': 'notify_dcc_get_completed',
+ 'dcc get failed': 'notify_dcc_get_failed',
+ 'dcc send completed': 'notify_dcc_send_completed',
+ 'dcc send failed': 'notify_dcc_send_failed',
+}
+
+
+STATE = {
+ 'icon': None,
+ 'is_away': False
+}
+
+
+# -----------------------------------------------------------------------------
+# Notifiers
+# -----------------------------------------------------------------------------
+def cb_irc_server_connected(data, signal, signal_data):
+ '''Notify when connected to IRC server.'''
+ if weechat.config_get_plugin('show_server') == 'on':
+ a_notify(
+ 'Server',
+ 'Server Connected',
+ 'Connected to network {0}.'.format(signal_data))
+ return weechat.WEECHAT_RC_OK
+
+
+def cb_irc_server_disconnected(data, signal, signal_data):
+ '''Notify when disconnected to IRC server.'''
+ if weechat.config_get_plugin('show_server') == 'on':
+ a_notify(
+ 'Server',
+ 'Server Disconnected',
+ 'Disconnected from network {0}.'.format(signal_data))
+ return weechat.WEECHAT_RC_OK
+
+
+def cb_notify_upgrade_ended(data, signal, signal_data):
+ '''Notify on end of WeeChat upgrade.'''
+ if weechat.config_get_plugin('show_upgrade_ended') == 'on':
+ a_notify(
+ 'WeeChat',
+ 'WeeChat Upgraded',
+ 'WeeChat has been upgraded.')
+ return weechat.WEECHAT_RC_OK
+
+
+def notify_highlighted_message(prefix, message):
+ '''Notify on highlighted message.'''
+ if weechat.config_get_plugin("show_highlighted_message") == "on":
+ a_notify(
+ 'Highlight',
+ 'Highlighted Message',
+ "{0}: {1}".format(prefix, message),
+ priority=pynotify.URGENCY_CRITICAL)
+
+
+def notify_public_message_or_action(prefix, message, highlighted):
+ '''Notify on public message or action.'''
+ if prefix == ' *':
+ regex = re.compile(r'^(\w+) (.+)$', re.UNICODE)
+ match = regex.match(message)
+ if match:
+ prefix = match.group(1)
+ message = match.group(2)
+ notify_public_action_message(prefix, message, highlighted)
+ else:
+ if highlighted:
+ notify_highlighted_message(prefix, message)
+ elif weechat.config_get_plugin("show_public_message") == "on":
+ a_notify(
+ 'Public',
+ 'Public Message',
+ '{0}: {1}'.format(prefix, message))
+
+
+def notify_private_message_or_action(prefix, message, highlighted):
+ '''Notify on private message or action.'''
+ regex = re.compile(r'^CTCP_MESSAGE.+?ACTION (.+)$', re.UNICODE)
+ match = regex.match(message)
+ if match:
+ notify_private_action_message(prefix, match.group(1), highlighted)
+ else:
+ if prefix == ' *':
+ regex = re.compile(r'^(\w+) (.+)$', re.UNICODE)
+ match = regex.match(message)
+ if match:
+ prefix = match.group(1)
+ message = match.group(2)
+ notify_private_action_message(prefix, message, highlighted)
+ else:
+ if highlighted:
+ notify_highlighted_message(prefix, message)
+ elif weechat.config_get_plugin("show_private_message") == "on":
+ a_notify(
+ 'Private',
+ 'Private Message',
+ '{0}: {1}'.format(prefix, message))
+
+
+def notify_public_action_message(prefix, message, highlighted):
+ '''Notify on public action message.'''
+ if highlighted:
+ notify_highlighted_message(prefix, message)
+ elif weechat.config_get_plugin("show_public_action_message") == "on":
+ a_notify(
+ 'Action',
+ 'Public Action Message',
+ '{0}: {1}'.format(prefix, message),
+ priority=pynotify.URGENCY_NORMAL)
+
+
+def notify_private_action_message(prefix, message, highlighted):
+ '''Notify on private action message.'''
+ if highlighted:
+ notify_highlighted_message(prefix, message)
+ elif weechat.config_get_plugin("show_private_action_message") == "on":
+ a_notify(
+ 'Action',
+ 'Private Action Message',
+ '{0}: {1}'.format(prefix, message),
+ priority=pynotify.URGENCY_NORMAL)
+
+
+def notify_notice_message(prefix, message, highlighted):
+ '''Notify on notice message.'''
+ regex = re.compile(r'^([^\s]*) [^:]*: (.+)$', re.UNICODE)
+ match = regex.match(message)
+ if match:
+ prefix = match.group(1)
+ message = match.group(2)
+ if highlighted:
+ notify_highlighted_message(prefix, message)
+ elif weechat.config_get_plugin("show_notice_message") == "on":
+ a_notify(
+ 'Notice',
+ 'Notice Message',
+ '{0}: {1}'.format(prefix, message))
+
+
+def notify_invite_message(prefix, message, highlighted):
+ '''Notify on channel invitation message.'''
+ if weechat.config_get_plugin("show_invite_message") == "on":
+ regex = re.compile(
+ r'^You have been invited to ([^\s]+) by ([^\s]+)$', re.UNICODE)
+ match = regex.match(message)
+ if match:
+ channel = match.group(1)
+ nick = match.group(2)
+ a_notify(
+ 'Invite',
+ 'Channel Invitation',
+ '{0} has invited you to join {1}.'.format(nick, channel))
+
+
+def notify_channel_topic(prefix, message, highlighted):
+ '''Notify on channel topic change.'''
+ if weechat.config_get_plugin("show_channel_topic") == "on":
+ regex = re.compile(
+ r'^\w+ has (?:changed|unset) topic for ([^\s]+)' +
+ '(?:(?: from "(?:(?:"\w|[^"])+)")? to "((?:"\w|[^"])+)")?',
+ re.UNICODE)
+ match = regex.match(message)
+ if match:
+ channel = match.group(1)
+ topic = match.group(2) or ''
+ a_notify(
+ 'Channel',
+ 'Channel Topic',
+ "{0}: {1}".format(channel, topic))
+
+
+def notify_dcc_chat_request(match):
+ '''Notify on DCC chat request.'''
+ if weechat.config_get_plugin("show_dcc") == "on":
+ nick = match.group(1)
+ a_notify(
+ 'DCC',
+ 'Direct Chat Request',
+ '{0} wants to chat directly.'.format(nick))
+
+
+def notify_dcc_chat_closed(match):
+ '''Notify on DCC chat termination.'''
+ if weechat.config_get_plugin("show_dcc") == "on":
+ nick = match.group(1)
+ a_notify(
+ 'DCC',
+ 'Direct Chat Ended',
+ 'Direct chat with {0} has ended.'.format(nick))
+
+
+def notify_dcc_get_request(match):
+ 'Notify on DCC get request.'
+ if weechat.config_get_plugin("show_dcc") == "on":
+ nick = match.group(1)
+ file_name = match.group(2)
+ a_notify(
+ 'DCC',
+ 'File Transfer Request',
+ '{0} wants to send you {1}.'.format(nick, file_name))
+
+
+def notify_dcc_get_completed(match):
+ 'Notify on DCC get completion.'
+ if weechat.config_get_plugin("show_dcc") == "on":
+ file_name = match.group(1)
+ a_notify('DCC', 'Download Complete', file_name)
+
+
+def notify_dcc_get_failed(match):
+ 'Notify on DCC get failure.'
+ if weechat.config_get_plugin("show_dcc") == "on":
+ file_name = match.group(1)
+ a_notify('DCC', 'Download Failed', file_name)
+
+
+def notify_dcc_send_completed(match):
+ 'Notify on DCC send completion.'
+ if weechat.config_get_plugin("show_dcc") == "on":
+ file_name = match.group(1)
+ a_notify('DCC', 'Upload Complete', file_name)
+
+
+def notify_dcc_send_failed(match):
+ 'Notify on DCC send failure.'
+ if weechat.config_get_plugin("show_dcc") == "on":
+ file_name = match.group(1)
+ a_notify('DCC', 'Upload Failed', file_name)
+
+
+# -----------------------------------------------------------------------------
+# Utility
+# -----------------------------------------------------------------------------
+def set_away_status(match):
+ status = match.group(1)
+ if status == 'been ':
+ STATE['is_away'] = True
+ if status == 'longer ':
+ STATE['is_away'] = False
+
+
+def cb_process_message(
+ data,
+ wbuffer,
+ date,
+ tags,
+ displayed,
+ highlight,
+ prefix,
+ message
+):
+ '''Delegates incoming messages to appropriate handlers.'''
+ tags = set(tags.split(','))
+ functions = globals()
+ is_public_message = tags.issuperset(
+ TAGGED_MESSAGES['public message or action'])
+ buffer_name = weechat.buffer_get_string(wbuffer, 'name')
+ dcc_buffer_regex = re.compile(r'^irc_dcc\.', re.UNICODE)
+ dcc_buffer_match = dcc_buffer_regex.match(buffer_name)
+ highlighted = False
+ if highlight == "1":
+ highlighted = True
+ # Private DCC message identifies itself as public.
+ if is_public_message and dcc_buffer_match:
+ notify_private_message_or_action(prefix, message, highlighted)
+ return weechat.WEECHAT_RC_OK
+ # Pass identified, untagged message to its designated function.
+ for key, value in UNTAGGED_MESSAGES.items():
+ match = value.match(message)
+ if match:
+ functions[DISPATCH_TABLE[key]](match)
+ return weechat.WEECHAT_RC_OK
+ # Pass identified, tagged message to its designated function.
+ for key, value in TAGGED_MESSAGES.items():
+ if tags.issuperset(value):
+ functions[DISPATCH_TABLE[key]](prefix, message, highlighted)
+ return weechat.WEECHAT_RC_OK
+ return weechat.WEECHAT_RC_OK
+
+
+def a_notify(notification, title, description, priority=pynotify.URGENCY_LOW):
+ '''Returns whether notifications should be sticky.'''
+ is_away = STATE['is_away']
+ icon = STATE['icon']
+ time_out = 5000
+ if weechat.config_get_plugin('sticky') == 'on':
+ time_out = 0
+ if weechat.config_get_plugin('sticky_away') == 'on' and is_away:
+ time_out = 0
+ try:
+ pynotify.init("wee-notifier")
+ wn = pynotify.Notification(title, description, icon)
+ wn.set_urgency(priority)
+ wn.set_timeout(time_out)
+ wn.show()
+ except Exception as error:
+ weechat.prnt('', 'anotify: {0}'.format(error))
+
+
+# -----------------------------------------------------------------------------
+# Main
+# -----------------------------------------------------------------------------
+def main():
+ '''Sets up WeeChat notifications.'''
+ # Initialize options.
+ for option, value in SETTINGS.items():
+ if not weechat.config_is_set_plugin(option):
+ weechat.config_set_plugin(option, value)
+ # Initialize.
+ name = "WeeChat"
+ icon = "/usr/share/pixmaps/weechat.xpm"
+ notifications = [
+ 'Public',
+ 'Private',
+ 'Action',
+ 'Notice',
+ 'Invite',
+ 'Highlight',
+ 'Server',
+ 'Channel',
+ 'DCC',
+ 'WeeChat'
+ ]
+ STATE['icon'] = icon
+ # Register hooks.
+ weechat.hook_signal(
+ 'irc_server_connected',
+ 'cb_irc_server_connected',
+ '')
+ weechat.hook_signal(
+ 'irc_server_disconnected',
+ 'cb_irc_server_disconnected',
+ '')
+ weechat.hook_signal('upgrade_ended', 'cb_upgrade_ended', '')
+ weechat.hook_print('', '', '', 1, 'cb_process_message', '')
+
+
+if __name__ == '__main__' and IMPORT_OK and weechat.register(
+ SCRIPT_NAME,
+ SCRIPT_AUTHOR,
+ SCRIPT_VERSION,
+ SCRIPT_LICENSE,
+ SCRIPT_DESC,
+ '',
+ ''
+):
+ main()
diff --git a/weechat/python/autoload/announce_url_title.py b/weechat/python/autoload/announce_url_title.py
new file mode 120000
index 0000000..5417bfe
--- /dev/null
+++ b/weechat/python/autoload/announce_url_title.py
@@ -0,0 +1 @@
+../announce_url_title.py \ No newline at end of file
diff --git a/weechat/python/autoload/anotify.py b/weechat/python/autoload/anotify.py
new file mode 120000
index 0000000..1517fef
--- /dev/null
+++ b/weechat/python/autoload/anotify.py
@@ -0,0 +1 @@
+../anotify.py \ No newline at end of file
diff --git a/weechat/python/autoload/colorize_nicks.py b/weechat/python/autoload/colorize_nicks.py
new file mode 120000
index 0000000..3ee34e9
--- /dev/null
+++ b/weechat/python/autoload/colorize_nicks.py
@@ -0,0 +1 @@
+../colorize_nicks.py \ No newline at end of file
diff --git a/weechat/python/autoload/listbuffer.py b/weechat/python/autoload/listbuffer.py
new file mode 120000
index 0000000..e7089b2
--- /dev/null
+++ b/weechat/python/autoload/listbuffer.py
@@ -0,0 +1 @@
+../listbuffer.py \ No newline at end of file
diff --git a/weechat/python/colorize_nicks.py b/weechat/python/colorize_nicks.py
new file mode 100644
index 0000000..d3730da
--- /dev/null
+++ b/weechat/python/colorize_nicks.py
@@ -0,0 +1,316 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2010 by xt <xt@bash.no>
+#
+# 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/>.
+#
+
+# This script colors nicks in IRC channels in the actual message
+# not just in the prefix section.
+#
+#
+# History:
+# 2013-01-29, nils_2
+# version 14: make script compatible with Python 3.x
+# 2012-10-19, ldvx
+# version 13: Iterate over every word to prevent incorrect colorization of
+# nicks. Added option greedy_matching.
+# 2012-04-28, ldvx
+# version 12: added ignore_tags to avoid colorizing nicks if tags are present
+# 2012-01-14, nesthib
+# version 11: input_text_display hook and modifier to colorize nicks in input bar
+# 2010-12-22, xt
+# version 10: hook config option for updating blacklist
+# 2010-12-20, xt
+# version 0.9: hook new config option for weechat 0.3.4
+# 2010-11-01, nils_2
+# version 0.8: hook_modifier() added to communicate with rainbow_text
+# 2010-10-01, xt
+# version 0.7: changes to support non-irc-plugins
+# 2010-07-29, xt
+# version 0.6: compile regexp as per patch from Chris quigybo@hotmail.com
+# 2010-07-19, xt
+# version 0.5: fix bug with incorrect coloring of own nick
+# 2010-06-02, xt
+# version 0.4: update to reflect API changes
+# 2010-03-26, xt
+# version 0.3: fix error with exception
+# 2010-03-24, xt
+# version 0.2: use ignore_channels when populating to increase performance.
+# 2010-02-03, xt
+# version 0.1: initial (based on ruby script by dominikh)
+#
+# Known issues: nicks will not get colorized if they begin with a character
+# such as ~ (which some irc networks do happen to accept)
+
+import weechat
+import re
+w = weechat
+
+SCRIPT_NAME = "colorize_nicks"
+SCRIPT_AUTHOR = "xt <xt@bash.no>"
+SCRIPT_VERSION = "14"
+SCRIPT_LICENSE = "GPL"
+SCRIPT_DESC = "Use the weechat nick colors in the chat area"
+
+settings = {
+ "blacklist_channels" : '', # comma separated list of channels (use short_name)
+ "blacklist_nicks" : 'so,root', # comma separated list of nicks
+ "min_nick_length" : '2', # length
+ "colorize_input" : 'off', # boolean
+ "ignore_tags" : '', # comma separated list of tags to ignore. I.e. irc_join,irc_part,irc_quit
+ "greedy_matching" : 'on', # if off, then let's use lazy matching instead
+}
+
+
+VALID_NICK = r'([@~&!%+])?([-a-zA-Z0-9\[\]\\`_^\{|\}]+)'
+valid_nick_re = re.compile(VALID_NICK)
+PREFIX_COLORS = {
+ '@' : 'nicklist_prefix1',
+ '~' : 'nicklist_prefix1',
+ '&' : 'nicklist_prefix1',
+ '!' : 'nicklist_prefix1',
+ '%' : 'nicklist_prefix2',
+ '+' : 'nicklist_prefix3',
+}
+ignore_channels = []
+ignore_nicks = []
+
+# Dict with every nick on every channel with its color as lookup value
+colored_nicks = {}
+
+def colorize_cb(data, modifier, modifier_data, line):
+ ''' Callback that does the colorizing, and returns new line if changed '''
+
+ global ignore_nicks, ignore_channels, colored_nicks
+
+ full_name = modifier_data.split(';')[1]
+ server = full_name.split('.')[0]
+ channel = '.'.join(full_name.split('.')[1:])
+
+ buffer = w.buffer_search('', full_name)
+ # Check if buffer has colorized nicks
+ if not buffer in colored_nicks:
+ return line
+
+ if channel in ignore_channels:
+ return line
+
+ try:
+ min_length = int(w.config_get_plugin('min_nick_length'))
+ except ValueError:
+ w.prnt('', '%sError with option min_nick_length, should be a integer' % weechat.prefix('error'))
+ w.config_set_plugin('min_nick_length', settings['min_nick_length'])
+
+ reset = w.color('reset')
+
+ # Don't colorize if the ignored tag is present in message
+ tags_line = modifier_data.rsplit(';')
+ if len(tags_line) >= 3:
+ tags_line = tags_line[2].split(',')
+ for i in w.config_get_plugin('ignore_tags').split(','):
+ if i in tags_line:
+ return line
+
+ for words in valid_nick_re.findall(line):
+ prefix, nick = words[0], words[1]
+ # Check that nick is not ignored and longer than minimum length
+ if len(nick) < min_length or nick in ignore_nicks:
+ continue
+ # Check that nick is in the dictionary colored_nicks
+ if nick in colored_nicks[buffer]:
+ nick_color = colored_nicks[buffer][nick]
+
+ # Let's use greedy matching. Will check against every word in a line.
+ if w.config_get_plugin('greedy_matching') == "on":
+ for word in line.split():
+ if nick in word:
+ # Is there a nick that contains nick and has a greater lenght?
+ # If so let's save that nick into var biggest_nick
+ biggest_nick = ""
+ for i in colored_nicks[buffer]:
+ if nick in i and nick != i and len(i) > len(nick):
+ if i in word:
+ # If a nick with greater len is found, and that word
+ # also happens to be in word, then let's save this nick
+ biggest_nick = i
+ # If there's a nick with greater len, then let's skip this
+ # As we will have the chance to colorize when biggest_nick
+ # iterates being nick.
+ if len(biggest_nick) > 0 and biggest_nick in word:
+ pass
+ elif len(word) < len(biggest_nick) or len(biggest_nick) == 0:
+ new_word = word.replace(nick, '%s%s%s' %(nick_color, nick, reset))
+ line = line.replace(word, new_word)
+ # Let's use lazy matching for nick
+ elif w.config_get_plugin('greedy_matching') == "off":
+ if nick in colored_nicks[buffer]:
+ nick_color = colored_nicks[buffer][nick]
+ # The two .? are in case somebody writes "nick:", "nick,", etc
+ # to address somebody
+ regex = r"(\A|\s).?(%s).?(\Z|\s)" % re.escape(nick)
+ match = re.search(regex, line)
+ if str(type(match)) == "<type '_sre.SRE_Match'>":
+ new_line = line[:match.start(2)] + nick_color+nick+reset + line[match.end(2):]
+ line = new_line
+ return line
+
+def colorize_input_cb(data, modifier, modifier_data, line):
+ ''' Callback that does the colorizing in input '''
+
+ global ignore_nicks, ignore_channels, colored_nicks
+
+ try:
+ min_length = int(w.config_get_plugin('min_nick_length'))
+ except ValueError:
+ w.prnt('', '%sError with option min_nick_length, should be a integer' % weechat.prefix('error'))
+ w.config_set_plugin('min_nick_length', settings['min_nick_length'])
+
+ if w.config_get_plugin('colorize_input') == 'on':
+ pass
+ elif w.config_get_plugin('colorize_input') == 'off':
+ return line
+ else:
+ w.prnt('', '%sError with option colorize_input, should be on or off' % weechat.prefix('error'))
+ w.config_set_plugin('colorize_input', settings['colorize_input'])
+ return line
+
+ buffer = w.current_buffer()
+ # Check if buffer has colorized nicks
+ if not buffer in colored_nicks:
+ return line
+
+ channel = w.buffer_get_string(buffer,'name')
+ if channel in ignore_channels:
+ return line
+
+ reset = w.color('reset')
+
+ for words in valid_nick_re.findall(line):
+ prefix, nick = words[0], words[1]
+ # Check that nick is not ignored and longer than minimum length
+ if len(nick) < min_length or nick in ignore_nicks:
+ continue
+ if nick in colored_nicks[buffer]:
+ nick_color = colored_nicks[buffer][nick]
+ line = line.replace(nick, '%s%s%s' %(nick_color, nick, reset))
+
+ return line
+
+def populate_nicks(*args):
+ ''' Fills entire dict with all nicks weechat can see and what color it has
+ assigned to it. '''
+ global colored_nicks
+
+ colored_nicks = {}
+
+ servers = w.infolist_get('irc_server', '', '')
+ while w.infolist_next(servers):
+ servername = w.infolist_string(servers, 'name')
+ colored_nicks[servername] = {}
+ my_nick = w.info_get('irc_nick', servername)
+ channels = w.infolist_get('irc_channel', '', servername)
+ while w.infolist_next(channels):
+ pointer = w.infolist_pointer(channels, 'buffer')
+ nicklist = w.infolist_get('nicklist', pointer, '')
+ channelname = w.infolist_string(channels, 'name')
+
+ if not pointer in colored_nicks:
+ colored_nicks[pointer] = {}
+
+ while w.infolist_next(nicklist):
+ nick = w.infolist_string(nicklist, 'name')
+ if nick == my_nick:
+ nick_color = w.color(\
+ w.config_string(\
+ w.config_get('weechat.color.chat_nick_self')))
+ else:
+ nick_color = w.info_get('irc_nick_color', nick)
+
+ colored_nicks[pointer][nick] = nick_color
+
+ w.infolist_free(nicklist)
+
+ w.infolist_free(channels)
+
+ w.infolist_free(servers)
+
+ return w.WEECHAT_RC_OK
+
+def add_nick(data, signal, type_data):
+ ''' Add nick to dict of colored nicks '''
+ global colored_nicks
+
+ pointer, nick = type_data.split(',')
+ if not pointer in colored_nicks:
+ colored_nicks[pointer] = {}
+
+ servername = w.buffer_get_string(pointer, 'localvar_server')
+ my_nick = w.buffer_get_string(pointer, 'localvar_nick')
+
+ if nick == my_nick:
+ nick_color = w.color(\
+ w.config_string(\
+ w.config_get('weechat.color.chat_nick_self')))
+ else:
+ nick_color = w.info_get('irc_nick_color', nick)
+
+ colored_nicks[pointer][nick] = nick_color
+
+ return w.WEECHAT_RC_OK
+
+def remove_nick(data, signal, type_data):
+ ''' Remove nick from dict with colored nicks '''
+ global colored_nicks
+
+ pointer, nick = type_data.split(',')
+
+ if pointer in colored_nicks and nick in colored_nicks[pointer]:
+ del colored_nicks[pointer][nick]
+
+ return w.WEECHAT_RC_OK
+
+def update_blacklist(*args):
+ global ignore_channels, ignore_nicks
+ if w.config_get_plugin('blacklist_channels'):
+ ignore_channels = w.config_get_plugin('blacklist_channels').split(',')
+ ignore_nicks = w.config_get_plugin('blacklist_nicks').split(',')
+ return w.WEECHAT_RC_OK
+
+if __name__ == "__main__":
+ if w.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE,
+ SCRIPT_DESC, "", ""):
+ # Set default settings
+# for option, default_value in settings.iteritems():
+ for option, default_value in list(settings.items()):
+ if not w.config_is_set_plugin(option):
+ w.config_set_plugin(option, default_value)
+
+ for key, value in list(PREFIX_COLORS.items()):
+# for key, value in PREFIX_COLORS.iteritems():
+ PREFIX_COLORS[key] = w.color(w.config_string(w.config_get('weechat.look.%s'%value)))
+
+ update_blacklist() # Set blacklist
+ populate_nicks() # Run it once to get data ready
+ w.hook_signal('nicklist_nick_added', 'add_nick', '')
+ w.hook_signal('nicklist_nick_removed', 'remove_nick', '')
+ w.hook_modifier('weechat_print', 'colorize_cb', '')
+ # Hook config for changing colors
+ w.hook_config('weechat.color.chat_nick_colors', 'populate_nicks', '')
+ # Hook for working togheter with other scripts (like colorize_lines)
+ w.hook_modifier('colorize_nicks', 'colorize_cb', '')
+ # Hook for modifying input
+ w.hook_modifier('250|input_text_display', 'colorize_input_cb', '')
+ # Hook for updating blacklist (this could be improved to use fnmatch)
+ weechat.hook_config('plugins.var.python.%s.blacklist*' %SCRIPT_NAME, 'update_blacklist', '')
diff --git a/weechat/python/listbuffer.py b/weechat/python/listbuffer.py
new file mode 100644
index 0000000..227a3ba
--- /dev/null
+++ b/weechat/python/listbuffer.py
@@ -0,0 +1,467 @@
+# -*- coding: utf-8 -*-
+#
+# ListBuffer, version 0.8.1 for WeeChat version 0.3
+# Latest development version: https://github.com/FiXato/listbuffer
+#
+# Show /list results in a common buffer and interact with them.
+#
+# This script allows you to easily join channels from the /list output.
+# It will open a common buffer for the /list result, through which you
+# browse with your cursor keys, and join with the meta-enter keys.
+# Adjust sorting with meta->, meta-< and meta-/ keybindings.
+#
+## History:
+### 2011-09-08: FiXato:
+#
+# * version 0.1: initial release.
+# * added a common buffer for /list results
+# * added highlighting for currently selected line
+# * added /join support via enter key
+# * added scroll_top and scroll_bottom support
+#
+# * version 0.2: /list format bugfix
+# * added support for /list results without modes
+# * some servers don't send 321 (/list start). Taken into account.
+#
+# * version 0.3: Sorting support
+# * Added some basic sorting support. Scroll through sort options
+# with meta-> and meta-< (users, channel, topic, modes)
+#
+### 2011-09-19: FiXato
+#
+# * version 0.4:
+# * Case-insensitive buffer lookup fix.
+# * Removed default enter keybind
+#
+### 2011-12-28: troydm:
+#
+# * version 0.5: It's an upside-down-world
+# * Added inverted sorting support provided by Dmitry "troydm" Geurkov
+# Use meta-/ to switch between inverted and regular sorting.
+#
+### 2012-02-10: FiXato:
+#
+# * version 0.6: Stop shoving that buffer in my face!
+# * The listbuffer should no longer pop up by itself when you load the script.
+# It should only pop up now when you actually do a /list query.
+#
+# * version 0.7: .. but please pop it up in my current window when I ask for it
+# * Added setting plugins.var.python.listbuffer.autofocus
+# This will autofocus the listbuffer in the current window if another window isn't
+# already showing it, and of course only when the user issues /list
+#
+### 2012-07-10: FiXato:
+#
+# * version 0.7.1: Forgetful bugfix
+# * Made sure lb_curline global variable is defined
+#
+### 2013-03-19: FiXato:
+#
+# * version 0.8: Sorted out the sorting
+# * Added automatically updating options for sorting:
+# * plugins.var.python.listbuffer.sort_inverted
+# * plugins.var.python.listbuffer.sort_order
+# * version 0.8.1: Pad it baby!
+# * Channel modes are equally padded even when there are no channel modes.
+# * Added padding options:
+# * plugins.var.python.listbuffer.modes_min_width
+# * plugins.var.python.listbuffer.channel_min_width
+# * plugins.var.python.listbuffer.users_min_width
+#
+## Acknowledgements:
+# * Dmitry "troydm" Geurkov, for providing the inverse-sorting patch to the project.
+# * Sebastien "Flashcode" Helleu, for developing the kick-ass IRC client WeeChat
+# and the iset.pl script which inspired me to this script.
+# * Nils "nils_2" Görs, for his contributions to iset.pl which served as
+# example code.
+# * David "drubin" Rubin, for his urlgrab.py script, which also served
+# as example code.
+# * ArZa, whose listsort.pl script helped me getting started with
+# grabbing the /list results. Parts of his code have been shamelessly
+# copied and ported to Python.
+# * Khaled Mardam-Bey, for making me yearn for similar /list support in
+# WeeChat as mIRC already offered. :P
+# * mave_, for pointing out that sort orders weren't remembered.
+#
+## TODO:
+# - Auto-scroll selected line upon window scroll.
+# - Add option to hide already joined channels.
+# - Improve sorting methods
+# - Add auto-join support
+# - Detect if channel is already in auto-join
+# - Allow automatically switching to the listbuffer
+# - Add support for ALIS (/squery alis LIST * -mix 100 (IRCNet)
+# - Make colours configurable
+# - Limit number of channels to parse
+# - Add filter support a la iset
+# - Allow selecting multiple channels
+# - Add optional command redirection.
+#
+## Copyright (c) 2011,2012,2013 Filip H.F. "FiXato" Slagter,
+# <FiXato [at] Gmail [dot] com>
+# http://profile.fixato.org
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+SCRIPT_NAME = "listbuffer"
+SCRIPT_AUTHOR = "Filip H.F. 'FiXato' Slagter <fixato [at] gmail [dot] com>"
+SCRIPT_VERSION = "0.8.1"
+SCRIPT_LICENSE = "MIT"
+SCRIPT_DESC = "A common buffer for /list output."
+SCRIPT_COMMAND = "listbuffer"
+
+import_ok = True
+
+try:
+ import weechat
+except ImportError:
+ print "This script must be run under WeeChat."
+ import_ok = False
+
+import re
+
+lb_settings = (
+ ("autofocus", "on", "Focus the listbuffer in the current window if it isn't already displayed by a window."),
+ ("sort_order", "users", "Last used sort order for the channel list."),
+ ("sort_inverted", "on", "Invert the sort order for the channel list."),
+ ("modes_min_width", "8", "The minimum width used for modes in the channel list. If a channel has less modes than this amount, the column will be padded with spaces."),
+ ("channel_min_width", "25", "The minimum width used for the channel name in the channel list. If a channelname is shorter than this amount, the column will be padded with spaces."),
+ ("users_min_width", "8", "The minimum width used for the usercount in the channel list. If the usercount has less digits than this amount, the column will be padded with spaces."),
+)
+lb_buffer = None
+lb_curline = 0
+lb_channels = []
+lb_network = None
+lb_list_started = False
+lb_current_sort = None
+lb_sort_inverted = False
+lb_sort_options = (
+ 'channel',
+ 'users',
+ 'modes',
+ 'topic',
+)
+
+# server numeric Nick Chan Users Modes Topic
+lb_channel_list_expression = '(:\S+) (\d{3}) (\S+) (\S+) (\d+) :(\[(.*?)\] )?(.*)'
+
+# Create listbuffer.
+def lb_create_buffer():
+ global lb_buffer, lb_curline
+
+ if not lb_buffer:
+ lb_buffer = weechat.buffer_new("listbuffer", "lb_input_cb", \
+ "", "lb_close_cb", "")
+ lb_set_buffer_title()
+ # Sets notify to 0 as this buffer does not need to be in hotlist.
+ weechat.buffer_set(lb_buffer, "notify", "0")
+ weechat.buffer_set(lb_buffer, "nicklist", "0")
+ weechat.buffer_set(lb_buffer, "type", "free")
+ weechat.buffer_set(lb_buffer, "key_bind_ctrl-L", "/listbuffer **refresh")
+ weechat.buffer_set(lb_buffer, "key_bind_meta2-A", "/listbuffer **up")
+ weechat.buffer_set(lb_buffer, "key_bind_meta2-B", "/listbuffer **down")
+ weechat.buffer_set(lb_buffer, "key_bind_meta2-1~", "/listbuffer **scroll_top")
+ weechat.buffer_set(lb_buffer, "key_bind_meta2-4~", "/listbuffer **scroll_bottom")
+ weechat.buffer_set(lb_buffer, "key_bind_meta-ctrl-J", "/listbuffer **enter")
+ weechat.buffer_set(lb_buffer, "key_bind_meta-ctrl-M", "/listbuffer **enter")
+ weechat.buffer_set(lb_buffer, "key_bind_meta->", "/listbuffer **sort_next")
+ weechat.buffer_set(lb_buffer, "key_bind_meta-<", "/listbuffer **sort_previous")
+ weechat.buffer_set(lb_buffer, "key_bind_meta-/", "/listbuffer **sort_invert")
+ lb_curline = 0
+ if weechat.config_get_plugin("autofocus") == "on":
+ if not weechat.window_search_with_buffer(lb_buffer):
+ weechat.command("", "/buffer " + weechat.buffer_get_string(lb_buffer,"name"))
+
+def lb_set_buffer_title():
+ global lb_buffer, lb_current_sort
+ ascdesc = '(v)' if lb_sort_inverted else '(^)'
+ weechat.buffer_set(lb_buffer, "title", lb_line_format({
+ 'channel': 'Channel name%s' % (ascdesc if lb_current_sort == 'channel' else ''),
+ 'users': 'Users%s' % (ascdesc if lb_current_sort == 'users' else ''),
+ 'modes': 'Modes%s' % (ascdesc if lb_current_sort == 'modes' else ''),
+ 'topic': 'Topic%s' % (ascdesc if lb_current_sort == 'topic' else ''),
+ 'nomodes': None,
+ }))
+
+def lb_list_start(data, signal, message):
+ lb_initialise_list
+
+ return weechat.WEECHAT_RC_OK
+
+def lb_initialise_list(signal):
+ global lb_channels, lb_network, lb_list_started
+
+ lb_create_buffer()
+ lb_channels = []
+ lb_network = signal.split(',')[0]
+ lb_list_started = True
+ return
+
+
+def lb_list_chan(data, signal, message):
+ global lb_channels, lb_buffer, lb_list_started
+
+ # Work-around for IRCds which don't send 321 Numeric (/List start)
+ if not lb_list_started:
+ lb_initialise_list(signal)
+
+ for chan_data in re.findall(lb_channel_list_expression,message):
+ lb_channels.append({
+ 'server': chan_data[0][1:-1],
+ 'numeric': chan_data[1],
+ 'nick': chan_data[2],
+ 'channel': chan_data[3],
+ 'users': chan_data[4],
+ 'nomodes': chan_data[5] == '',
+ 'modes': chan_data[6],
+ 'topic': weechat.hook_modifier_exec("irc_color_decode", "1", chan_data[7])
+ })
+ return weechat.WEECHAT_RC_OK
+
+def lb_list_end(data, signal, message):
+ global lb_list_started
+
+ # Work-around for IRCds which don't send 321 Numeric (/List start)
+ if not lb_list_started:
+ lb_initialise_list(signal)
+
+ lb_list_started = False
+ if lb_current_sort:
+ lb_sort()
+ lb_refresh()
+ return weechat.WEECHAT_RC_OK
+
+def keyEvent (data, buffer, args):
+ global lb_options
+ lb_options[args]()
+
+def lb_input_cb(data, buffer, input_data):
+ global lb_options, lb_curline
+ lb_options[input_data]()
+ return weechat.WEECHAT_RC_OK
+
+def lb_refresh():
+ global lb_channels, lb_buffer
+ weechat.buffer_clear(lb_buffer)
+
+ y = 0
+ for list_data in lb_channels:
+ lb_refresh_line(y)
+ y += 1
+ return
+
+def lb_refresh_line(y):
+ global lb_buffer, lb_curline, lb_channels
+ if y >= 0 and y < len(lb_channels):
+ formatted_line = lb_line_format(lb_channels[y], y == lb_curline)
+ weechat.prnt_y(lb_buffer, y, formatted_line)
+
+def lb_refresh_curline():
+ global lb_curline
+ lb_refresh_line(lb_curline-1)
+ lb_refresh_line(lb_curline)
+ lb_refresh_line(lb_curline+1)
+ return
+
+def lb_line_format(list_data,curr=False):
+ str = ""
+ if (curr):
+ str += weechat.color("yellow,red")
+ channel_text = list_data['channel'].ljust(int(weechat.config_get_plugin('channel_min_width')))
+ users_text = "(%s)" % list_data['users']
+ padded_users_text = users_text.rjust(int(weechat.config_get_plugin('users_min_width')) + 2)
+ str += "%s%s %s " % (weechat.color("bold"), channel_text, padded_users_text)
+ if not list_data['nomodes']:
+ modes = "[%s]" % list_data['modes']
+ else:
+ modes = "[]"
+ str += "%s: " % modes.rjust(int(weechat.config_get_plugin('modes_min_width')) + 2)
+ str += "%s" % list_data['topic']
+ return str
+
+def lb_line_up():
+ global lb_curline
+ if lb_curline <= 0:
+ return
+ lb_curline -= 1
+ lb_refresh_curline()
+ lb_check_outside_window()
+ return
+
+def lb_line_down():
+ global lb_curline, lb_channels
+ if lb_curline+1 >= len(lb_channels):
+ return
+ lb_curline += 1
+ lb_refresh_curline()
+ lb_check_outside_window()
+ return
+
+def lb_line_run():
+ global lb_channels, lb_curline, lb_network
+ buff = weechat.info_get("irc_buffer", lb_network)
+ channel = lb_channels[lb_curline]['channel']
+ command = "/join %s" % channel
+ weechat.command(buff, command)
+ return
+
+def lb_line_select():
+ return
+
+def lb_scroll_top():
+ global lb_curline
+ old_y = lb_curline
+ lb_curline = 0
+ lb_refresh_curline()
+ lb_refresh_line(old_y)
+ weechat.command(lb_buffer, "/window scroll_top")
+ return
+
+def lb_scroll_bottom():
+ global lb_curline, lb_channels
+ old_y = lb_curline
+ lb_curline = len(lb_channels)-1
+ lb_refresh_curline()
+ lb_refresh_line(old_y)
+ weechat.command(lb_buffer, "/window scroll_bottom")
+ return
+
+def lb_check_outside_window():
+ global lb_buffer, lb_curline
+ if (lb_buffer):
+ infolist = weechat.infolist_get("window", "", "current")
+ if (weechat.infolist_next(infolist)):
+ start_line_y = weechat.infolist_integer(infolist, "start_line_y")
+ chat_height = weechat.infolist_integer(infolist, "chat_height")
+ if(start_line_y > lb_curline):
+ weechat.command(lb_buffer, "/window scroll -%i" %(start_line_y - lb_curline))
+ elif(start_line_y <= lb_curline - chat_height):
+ weechat.command(lb_buffer, "/window scroll +%i"%(lb_curline - start_line_y - chat_height + 1))
+ weechat.infolist_free(infolist)
+
+def lb_sort_next():
+ global lb_current_sort, lb_sort_options
+ if lb_current_sort:
+ new_index = lb_sort_options.index(lb_current_sort) + 1
+ else:
+ new_index = 0
+
+ if len(lb_sort_options) <= new_index:
+ new_index = 0
+
+ lb_set_current_sort_order(lb_sort_options[new_index])
+ lb_sort()
+
+def lb_set_current_sort_order(value):
+ global lb_current_sort
+ lb_current_sort = value
+ weechat.config_set_plugin('sort_order', lb_current_sort)
+
+def lb_set_invert_sort_order(value):
+ global lb_sort_inverted
+ lb_sort_inverted = value
+ weechat.config_set_plugin('sort_inverted', ('on' if lb_sort_inverted else 'off'))
+
+def lb_sort_previous():
+ global lb_current_sort, lb_sort_options
+ if lb_current_sort:
+ new_index = lb_sort_options.index(lb_current_sort) - 1
+ else:
+ new_index = 0
+
+ if new_index < 0:
+ new_index = len(lb_sort_options) - 1
+
+ lb_set_current_sort_order(lb_sort_options[new_index])
+ lb_sort()
+
+def lb_sort(sort_key=None):
+ global lb_channels, lb_current_sort, lb_sort_inverted
+ if sort_key:
+ lb_set_current_sort_order(sort_key)
+ if lb_current_sort == 'users':
+ lb_channels = sorted(lb_channels, key=lambda chan_data: int(chan_data[lb_current_sort]))
+ else:
+ lb_channels = sorted(lb_channels, key=lambda chan_data: chan_data[lb_current_sort])
+ if lb_sort_inverted:
+ lb_channels.reverse()
+ lb_set_buffer_title()
+ lb_refresh()
+
+def lb_sort_invert():
+ global lb_current_sort, lb_sort_inverted
+ if lb_current_sort:
+ lb_set_invert_sort_order(not lb_sort_inverted)
+ lb_sort()
+
+def lb_close_cb(*kwargs):
+ """ A callback for buffer closing. """
+ global lb_buffer
+
+ lb_buffer = None
+ return weechat.WEECHAT_RC_OK
+
+lb_options = {
+ 'refresh' : lb_refresh,
+ 'up' : lb_line_up,
+ 'down' : lb_line_down,
+ 'enter' : lb_line_run,
+ 'space' : lb_line_select,
+ 'scroll_top' : lb_scroll_top,
+ 'scroll_bottom': lb_scroll_bottom,
+ 'sort_next' : lb_sort_next,
+ 'sort_previous': lb_sort_previous,
+ 'sort_invert': lb_sort_invert
+}
+
+def lb_command_main(data, buffer, args):
+ if args[0:2] == "**":
+ keyEvent(data, buffer, args[2:])
+ return weechat.WEECHAT_RC_OK
+
+def lb_set_default_settings():
+ global lb_settings
+ # Set default settings
+ for option, default_value, description in lb_settings:
+ if not weechat.config_is_set_plugin(option):
+ weechat.config_set_plugin(option, default_value)
+ version = weechat.info_get("version_number", "") or 0
+ if int(version) >= 0x00030500:
+ weechat.config_set_desc_plugin(option, description)
+
+def lb_reset_stored_sort_order():
+ global lb_current_sort, lb_sort_inverted
+ lb_current_sort = weechat.config_get_plugin('sort_order')
+ lb_sort_inverted = (True if weechat.config_get_plugin('sort_inverted') == 'on' else False)
+
+if __name__ == "__main__" and import_ok:
+ if weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION,
+ SCRIPT_LICENSE, SCRIPT_DESC, "lb_close_cb", ""):
+ lb_set_default_settings()
+ lb_reset_stored_sort_order()
+ lb_buffer = weechat.buffer_search("python", "listbuffer")
+
+ weechat.hook_signal("*,irc_in_321", "lb_list_start", "")
+ weechat.hook_signal("*,irc_in_322", "lb_list_chan", "")
+ weechat.hook_signal("*,irc_in_323", "lb_list_end", "")
+ weechat.hook_command(SCRIPT_COMMAND,
+ "List Buffer",
+ "", "", "",
+ "lb_command_main", "")
diff --git a/weechat/relay.conf b/weechat/relay.conf
new file mode 100644
index 0000000..7c45ba4
--- /dev/null
+++ b/weechat/relay.conf
@@ -0,0 +1,37 @@
+#
+# relay.conf -- weechat v0.4.3-dev
+#
+
+[look]
+auto_open_buffer = on
+raw_messages = 256
+
+[color]
+client = cyan
+status_active = lightblue
+status_auth_failed = lightred
+status_connecting = yellow
+status_disconnected = lightred
+status_waiting_auth = brown
+text = default
+text_bg = default
+text_selected = white
+
+[network]
+allowed_ips = ""
+bind_address = ""
+compression_level = 6
+ipv6 = on
+max_clients = 5
+password = ""
+ssl_cert_key = "%h/ssl/relay.pem"
+websocket_allowed_origins = ""
+
+[irc]
+backlog_max_minutes = 1440
+backlog_max_number = 256
+backlog_since_last_disconnect = on
+backlog_tags = "irc_privmsg"
+backlog_time_format = "[%H:%M] "
+
+[port]
diff --git a/weechat/rmodifier.conf b/weechat/rmodifier.conf
new file mode 100644
index 0000000..c21d8ef
--- /dev/null
+++ b/weechat/rmodifier.conf
@@ -0,0 +1,14 @@
+#
+# rmodifier.conf -- weechat v0.4.3-dev
+#
+
+[look]
+hide_char = "*"
+
+[modifier]
+command_auth = "history_add,input_text_display,irc_command_auth;^(/(msg|quote) +nickserv +(id|identify|register|ghost \S+|release \S+) +)(.*);1,4*"
+message_auth = "irc_message_auth;^(.*(id|identify|register|ghost \S+|release \S+) +)(.*);1,3*"
+oper = "history_add,input_text_display;^(/oper +\S+ +)(.*);1,2*"
+quote_pass = "history_add,input_text_display;^(/quote pass +)(.*);1,2*"
+server = "history_add,input_text_display;^(/(server|connect) .*-(sasl_)?password=)(\S+)(.*);1,4*,5"
+set_pass = "history_add;^(/set +\S*password\S* +)(.*);1,2*"
diff --git a/weechat/script.conf b/weechat/script.conf
new file mode 100644
index 0000000..570e651
--- /dev/null
+++ b/weechat/script.conf
@@ -0,0 +1,48 @@
+#
+# script.conf -- weechat v0.4.3-dev
+#
+
+[look]
+columns = "%s %n %V %v %u | %d | %t"
+diff_color = on
+diff_command = "auto"
+display_source = on
+quiet_actions = on
+sort = "p,n"
+translate_description = on
+use_keys = on
+
+[color]
+status_autoloaded = cyan
+status_held = white
+status_installed = lightcyan
+status_obsolete = lightmagenta
+status_popular = yellow
+status_running = lightgreen
+status_unknown = lightred
+text = default
+text_bg = default
+text_bg_selected = red
+text_date = default
+text_date_selected = white
+text_delimiters = darkgray
+text_description = default
+text_description_selected = white
+text_extension = default
+text_extension_selected = white
+text_name = cyan
+text_name_selected = lightcyan
+text_selected = white
+text_tags = brown
+text_tags_selected = yellow
+text_version = magenta
+text_version_loaded = default
+text_version_loaded_selected = white
+text_version_selected = lightmagenta
+
+[scripts]
+autoload = on
+cache_expire = 60
+dir = "%h/script"
+hold = ""
+url = "http://www.weechat.org/files/plugins.xml.gz"
diff --git a/weechat/sec.conf b/weechat/sec.conf
new file mode 100644
index 0000000..a6d419a
--- /dev/null
+++ b/weechat/sec.conf
@@ -0,0 +1,11 @@
+#
+# sec.conf -- weechat v0.4.3-dev
+#
+
+[crypt]
+cipher = aes256
+hash_algo = sha256
+passphrase_file = ""
+salt = on
+
+[data]
diff --git a/weechat/theos.crt b/weechat/theos.crt
new file mode 100644
index 0000000..db9e868
--- /dev/null
+++ b/weechat/theos.crt
@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIID4TCCAsmgAwIBAgIJAIdcg5Fz/kmfMA0GCSqGSIb3DQEBBQUAMIGGMQswCQYD
+VQQGEwJOTDETMBEGA1UECAwKU29tZS1TdGF0ZTERMA8GA1UECgwIa3lyaWFzaXMx
+DDAKBgNVBAsMA3puYzEbMBkGA1UEAwwSdGhlb3Mua3lyaWFzaXMuY29tMSQwIgYJ
+KoZIhvcNAQkBFhVqb2hhbm5lc0BreXJpYXNpcy5jb20wHhcNMTQwMTA4MTYyNjIw
+WhcNMjQwMTA2MTYyNjIwWjCBhjELMAkGA1UEBhMCTkwxEzARBgNVBAgMClNvbWUt
+U3RhdGUxETAPBgNVBAoMCGt5cmlhc2lzMQwwCgYDVQQLDAN6bmMxGzAZBgNVBAMM
+EnRoZW9zLmt5cmlhc2lzLmNvbTEkMCIGCSqGSIb3DQEJARYVam9oYW5uZXNAa3ly
+aWFzaXMuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzX3w6HdZ
+3D9PmyVaoSKQXN1cNshL7pu0yVQekUIoG1NbUo95Dtgt4LD3U2BtjI2PG/mmmnIk
+fZEv7frNGNXc93SBE4x9SM3E8YRxFidFeJNdcnlJrTFMczqZkcullEWWT5Sby/lt
+UEZBl1WtxnmLx8ILpUOAyDUWqUykx0KSW6Z5/rh+zdN3WiHx0RKoIoUGUrF47fbS
+PjdrUKVy14qSoDEjZ1ZMV6DBd5yvbrSsPe0DiQ2HcfXbYtR/XOTVBDDRgPUdwW+b
+IiZ4UWmnMZ2VLElqAhlmL9lwcIXiG6zopqcexzq+O01/02t5jE03BVnZQOaLiPV8
+LjVNAFezEjvdHQIDAQABo1AwTjAdBgNVHQ4EFgQUzWZqmo/ZRmxsLAQpQ8TbzQJk
+J28wHwYDVR0jBBgwFoAUzWZqmo/ZRmxsLAQpQ8TbzQJkJ28wDAYDVR0TBAUwAwEB
+/zANBgkqhkiG9w0BAQUFAAOCAQEAm7HK5ytpjKVVCDNrxKdRmm/IIA7GJwuanYNK
+NVarnj4GdsLSr3x6vci+EsTfGkRiLu7wr/u+Lk2v6gDtFJnkX3AdR5vk6LTrYIGD
+mF3/uliY+tdAJ1D5lCmrgcM/qDo+tyGGB/XpHgy7Ag4uKjYg/VOsopLTqr2ZLtY4
+/TIs894eHbBLUHucG8Qjnqe0BG4Q9CGq+r6NmjX+84COclWlDt25UFU1WCmR49er
+kCCfl40h+Gwsj+JfuqzA8IlXazAFpsnFBfK61/sQ1KH8f4PYzBrFwagHslJMeMgZ
+Mn65qDposEMkYX2g3zTDC9orPpl2pK/XvRV+UGinUwbYuxjfLw==
+-----END CERTIFICATE-----
diff --git a/weechat/xfer.conf b/weechat/xfer.conf
new file mode 100644
index 0000000..c102e9d
--- /dev/null
+++ b/weechat/xfer.conf
@@ -0,0 +1,38 @@
+#
+# xfer.conf -- weechat v0.4.3-dev
+#
+
+[look]
+auto_open_buffer = on
+progress_bar_size = 20
+pv_tags = "notify_private"
+
+[color]
+status_aborted = lightred
+status_active = lightblue
+status_connecting = yellow
+status_done = lightgreen
+status_failed = lightred
+status_waiting = lightcyan
+text = default
+text_bg = default
+text_selected = white
+
+[network]
+blocksize = 65536
+fast_send = on
+own_ip = ""
+port_range = ""
+speed_limit = 0
+timeout = 300
+
+[file]
+auto_accept_chats = off
+auto_accept_files = off
+auto_accept_nicks = ""
+auto_rename = on
+auto_resume = on
+convert_spaces = on
+download_path = "%h/xfer"
+upload_path = "~"
+use_nick_in_filename = on
diff --git a/weechat/yaurls.conf b/weechat/yaurls.conf
new file mode 100644
index 0000000..ed55160
--- /dev/null
+++ b/weechat/yaurls.conf
@@ -0,0 +1,28 @@
+#
+# yaurls.conf -- weechat v0.4.3-dev
+#
+
+[blacklists]
+channel_blacklist = ""
+nick_blacklist = ""
+server_blacklist = ""
+string_blacklist = ""
+url_blacklist = "youtube.com"
+
+[colors]
+domain_color = lightblue
+header_color = green
+prefix_suffix_color = lightmagenta
+url_color = lightgreen
+
+[engine]
+convert_own = on
+maximum_length = 35
+service = durl
+timeout = 20
+
+[look]
+format = "%H %U %D"
+header = "durl"
+header_prefix = "["
+header_suffix = "]→"
diff --git a/zsh/.zkbd/linux-unknown-linux-gnu b/zsh/.zkbd/linux-unknown-linux-gnu
new file mode 100644
index 0000000..d121321
--- /dev/null
+++ b/zsh/.zkbd/linux-unknown-linux-gnu
@@ -0,0 +1,26 @@
+typeset -g -A key
+
+key[F1]='^[[[A'
+key[F2]='^[[[B'
+key[F3]='^[[[C'
+key[F4]='^[[[D'
+key[F5]='^[[[E'
+key[F6]='^[[17~'
+key[F7]='^[[18~'
+key[F8]='^[[19~'
+key[F9]='^[[20~'
+key[F10]='^[[21~'
+key[F11]='^[[23~'
+key[F12]='^[[24~'
+key[Backspace]='^?'
+key[Insert]='^[[2~'
+key[Home]='^[[1~'
+key[PageUp]='^[[5~'
+key[Delete]='^[[3~'
+key[End]='^[[4~'
+key[PageDown]='^[[6~'
+key[Up]='^[[A'
+key[Left]='^[[D'
+key[Down]='^[[B'
+key[Right]='^[[C'
+key[Menu]=''''
diff --git a/zsh/.zkbd/screen-256color-:0 b/zsh/.zkbd/screen-256color-:0
new file mode 100644
index 0000000..65cc3a9
--- /dev/null
+++ b/zsh/.zkbd/screen-256color-:0
@@ -0,0 +1,26 @@
+typeset -g -A key
+
+key[F1]='^[OP'
+key[F2]='^[OQ'
+key[F3]='^[OR'
+key[F4]='^[OS'
+key[F5]='^[[15~'
+key[F6]='^[[17~'
+key[F7]='^[[18~'
+key[F8]='^[[19~'
+key[F9]='^[[20~'
+key[F10]='^[[21~'
+key[F11]='^[[23~'
+key[F12]='^[[24~'
+key[Backspace]='^?'
+key[Insert]='^[[2~'
+key[Home]='^[[1~'
+key[PageUp]='^[[5~'
+key[Delete]='^[[3~'
+key[End]='^[[4~'
+key[PageDown]='^[[6~'
+key[Up]='^[[A'
+key[Left]='^[[D'
+key[Down]='^[[B'
+key[Right]='^[[C'
+key[Menu]=''''
diff --git a/zsh/.zkbd/screen-:0 b/zsh/.zkbd/screen-:0
new file mode 100644
index 0000000..65cc3a9
--- /dev/null
+++ b/zsh/.zkbd/screen-:0
@@ -0,0 +1,26 @@
+typeset -g -A key
+
+key[F1]='^[OP'
+key[F2]='^[OQ'
+key[F3]='^[OR'
+key[F4]='^[OS'
+key[F5]='^[[15~'
+key[F6]='^[[17~'
+key[F7]='^[[18~'
+key[F8]='^[[19~'
+key[F9]='^[[20~'
+key[F10]='^[[21~'
+key[F11]='^[[23~'
+key[F12]='^[[24~'
+key[Backspace]='^?'
+key[Insert]='^[[2~'
+key[Home]='^[[1~'
+key[PageUp]='^[[5~'
+key[Delete]='^[[3~'
+key[End]='^[[4~'
+key[PageDown]='^[[6~'
+key[Up]='^[[A'
+key[Left]='^[[D'
+key[Down]='^[[B'
+key[Right]='^[[C'
+key[Menu]=''''
diff --git a/zsh/.zkbd/xterm-termite-:0 b/zsh/.zkbd/xterm-termite-:0
new file mode 100644
index 0000000..01f4e31
--- /dev/null
+++ b/zsh/.zkbd/xterm-termite-:0
@@ -0,0 +1,26 @@
+typeset -g -A key
+
+key[F1]='^[OP'
+key[F2]='^[OQ'
+key[F3]='^[OR'
+key[F4]='^[OS'
+key[F5]='^[[15~'
+key[F6]='^[[17~'
+key[F7]='^[[18~'
+key[F8]='^[[19~'
+key[F9]='^[[20~'
+key[F10]='^[[21~'
+key[F11]='^[[23~'
+key[F12]='^[[24~'
+key[Backspace]='^?'
+key[Insert]='^[[2~'
+key[Home]='^[OH'
+key[PageUp]='^[[5~'
+key[Delete]='^[[3~'
+key[End]='^[OF'
+key[PageDown]='^[[6~'
+key[Up]='^[[A'
+key[Left]='^[[D'
+key[Down]='^[[B'
+key[Right]='^[[C'
+key[Menu]=''''
diff --git a/zsh/.zprofile b/zsh/.zprofile
new file mode 100644
index 0000000..a8fd7d2
--- /dev/null
+++ b/zsh/.zprofile
@@ -0,0 +1,42 @@
+export PATH="$HOME"/.local/bin:"$PATH":"$HOME"/.gem/ruby/2.0.0/bin:$PLAN9/bin
+export PLAN9=/usr/local/plan9
+
+export XDG_CACHE_HOME="$HOME"/.cache
+export XDG_CONFIG_HOME="$HOME"/.config
+export XDG_DATA_HOME="$HOME"/.local/share
+
+export MPV_HOME="$XDG_CONFIG_HOME"/mpv
+export GNUPGHOME="$XDG_CONFIG_HOME"/gnupg
+export GTK2_RC_FILES="$XDG_CONFIG_HOME"/gtk-2.0/gtkrc-2.0
+export XCOMPOSEFILE="$XDG_CONFIG_HOME"/X11/XCompose
+
+export ABSROOT="$HOME/build/abs"
+
+export EDITOR=vim
+# Set vimrc's location and source it on vim startup
+export VIMINIT='let $MYVIMRC="$XDG_CONFIG_HOME/vim/vimrc" | source $MYVIMRC'
+
+export PAGER=less
+export LESSHISTFILE=-
+
+export LESSOPEN="|lesspipe.sh %s"
+export LESSCOLORIZER=pygmentize
+
+export GREP_OPTIONS=--color=auto
+export LESS=-R
+
+export BROWSER=firefox
+export TERMINAL=termite
+
+export SDL_AUDIODRIVER=pulse
+
+export GTK_IM_MODULE=xim
+
+export SUDO_PROMPT=$'\e[31mSUDO\e[m password for \e[34m%p\e[m: '
+
+export GOPATH=$HOME/code/go
+export PATH=$PATH:$GOPATH/bin
+
+[[ -z $DISPLAY && $XDG_VTNR -eq 1 ]] && exec startx "$HOME"/.config/X11/xinitrc
+envoy -t gpg-agent
+source <(envoy -p)
diff --git a/zsh/.zshenv b/zsh/.zshenv
new file mode 100644
index 0000000..2bfb3d1
--- /dev/null
+++ b/zsh/.zshenv
@@ -0,0 +1,8 @@
+
+export XDG_CACHE_HOME=$HOME/.cache
+export XDG_DATA_HOME=$HOME/.local/share
+
+export BROWSER=firefox
+
+export LESSHISTFILE="-" # ugh, stupid less. Disable ridiculous history file
+
diff --git a/zsh/.zshrc b/zsh/.zshrc
new file mode 100644
index 0000000..01d6100
--- /dev/null
+++ b/zsh/.zshrc
@@ -0,0 +1,118 @@
+HISTFILE=~/.config/zsh/.zsh_history
+HISTSIZE=500
+SAVEHIST=500
+setopt notify
+
+zstyle :compinstall filename "$HOME/.config/zsh/.zshrc"
+
+al=(colors
+ compinit
+ promptinit
+ vcs_info
+)
+autoload -Uz $al
+compinit
+promptinit
+colors
+
+shellopts=(PROMPT_SUBST
+ completealiases
+ auto_cd
+)
+setopt $shellopts
+
+zmodload zsh/mapfile
+
+# Menu completion
+zstyle ':completion:*' menu select
+
+if [[ $TERM == xterm-termite && $DISPLAY == ":0" ]]; then
+ . /etc/profile.d/vte.sh
+ __vte_osc7
+fi
+
+# Load all configs
+#for f in ~/.config/zsh/zsh.d/*.zsh
+# source $f
+
+source /usr/share/doc/pkgfile/command-not-found.zsh
+
+#zstyle ':vcs_info:*' check-for-changes true
+
+zstyle ':vcs_info:git*' stagedstr "✚ "
+zstyle ':vcs_info:git*' unstagedstr "● "
+
+zstyle ':vcs_info:git*' formats "「%b %u%c%m」"
+
+zstyle ':vcs_info:*' enable git
+precmd() {
+ vcs_info
+}
+
+PS1=$'%{${fg[blue]}%}%B%~%b%{${fg[blue]}%} %B%#%b %{${fg[default]}%}'
+#PS1=$'┌─[${fg[cyan]}%B%n%b ${fg[blue]}%B%~%b$fg[default]]\n└─╼ '
+RPS1='%{${fg[blue]}%}${vcs_info_msg_0_}%{${fg[default]}%}'
+
+# Vi keybindings
+bindkey -v
+
+# Bind "<command mode> H" to run-help (man pages)
+bindkey -M vicmd 'H' run-help
+bindkey "^R" history-incremental-search-backward
+
+autoload -U edit-command-line
+zle -N edit-command-line
+bindkey -M vicmd 'e' edit-command-line
+
+###########################
+## Aliasing and keybinding
+##
+alias wefree='weechat -a -r "/connect Freenode"'
+ls_options='-F --color=auto --group-directories-first'
+alias ls="ls $ls_options"
+alias lsa="ls $ls_options -hAX"
+alias lla="ls $ls_options -lhA"
+alias df='df -h'
+alias nano='nano -w' # No linewrap
+alias ncmpcpp='ncmpcpp -c ~/.config/ncmpcpp/config'
+alias 'cd..'='cd ..'
+alias ',,'='..'
+alias '...'='../..'
+alias mkdir='mkdir -vp'
+alias 'please?'='sudo $(history | tail -n1 | cut -c 8-)'
+alias acp='acp -g'
+alias amv='amv -g'
+
+# Use 'git's completions with 'hub'
+if type compdef >/dev/null; then
+ compdef hub=git
+fi
+
+# Colored man
+man() {
+ env LESS_TERMCAP_mb=$(printf "\e[1;31m") \
+ LESS_TERMCAP_md=$(printf "\e[1;31m") \
+ LESS_TERMCAP_me=$(printf "\e[0m") \
+ LESS_TERMCAP_se=$(printf "\e[0m") \
+ LESS_TERMCAP_so=$(printf "\e[1;44;33m") \
+ LESS_TERMCAP_ue=$(printf "\e[0m") \
+ LESS_TERMCAP_us=$(printf "\e[1;32m") \
+ man "$@"
+}
+
+source ~/.config/zsh/.zkbd/$TERM-${${DISPLAY:t}:-$VENDOR-$OSTYPE}
+[[ -n "${key[Home]}" ]] && bindkey "${key[Home]}" beginning-of-line
+[[ -n "${key[End]}" ]] && bindkey "${key[End]}" end-of-line
+[[ -n "${key[Insert]}" ]] && bindkey "${key[Insert]}" overwrite-mode
+[[ -n "${key[Delete]}" ]] && bindkey "${key[Delete]}" delete-char
+[[ -n "${key[Up]}" ]] && bindkey "${key[Up]}" up-line-or-history
+[[ -n "${key[Down]}" ]] && bindkey "${key[Down]}" down-line-or-history
+[[ -n "${key[Left]}" ]] && bindkey "${key[Left]}" backward-char
+[[ -n "${key[Right]}" ]] && bindkey "${key[Right]}" forward-char
+[[ -n "${key[PageUp]}" ]] && bindkey "${key[PageUp]}" beginning-of-buffer-or-history
+[[ -n "${key[PageDown]}" ]] && bindkey "${key[PageDown]}" end-of-buffer-or-history
+
+alias sprin='curl -F "sprunge=<-" http://sprunge.us'
+sprfile() {
+ curl -F "sprunge=<$1" http://sprunge.us
+}