🢀︎ weechat :: 9263ac4


commit 9263ac46e847c12106bdf3771e20776ba67f2d20
Author: acidvegas <acid.vegas@acid.vegas>
Date:   Sat Jul 13 02:31:42 2019 -0400

    Initial commit

diff --git a/README.md b/README.md
new file mode 100644
index 0000000..1363826
--- /dev/null
+++ b/README.md
@@ -0,0 +1,151 @@
+###### Settings
+```
+/set weechat.plugin.autoload				"*,!aspell,!fifo,!guile,!logger,!lua,!ruby,!tcl,!xfer"
+/set weechat.startup.display_logo			off
+/set weechat.startup.display_version		off
+/set weechat.look.bar_more_down				"▼"
+/set weechat.look.bar_more_left				"◀"
+/set weechat.look.bar_more_right			"▶"
+/set weechat.look.bar_more_up				"▲"
+/set weechat.look.buffer_time_format		" %H:%M"
+/set weechat.look.confirm_quit				on
+/set weechat.look.day_change				off
+/set weechat.look.item_buffer_filter		"•"
+/set weechat.look.prefix_align_max			15
+/set weechat.look.prefix_join				"▬▬▶"
+/set weechat.look.prefix_quit				"◀▬▬"
+/set weechat.look.prefix_suffix				"│"
+/set weechat.look.quote_time_format			"%H:%M"
+/set weechat.look.read_marker_string		"─"
+/set weechat.look.separator_horizontal		"─"
+/set weechat.look.separator_vertical		"│"
+/set weechat.look.window_title				"hardchats"
+/set weechat.color.chat_delimiters			darkgray
+/set weechat.color.chat_highlight_bg		default
+/set weechat.color.chat_host				darkgray
+/set weechat.color.chat_nick				white
+/set weechat.color.chat_nick_colors			"cyan,magenta,green,brown,lightblue,default,lightcyan,lightmagenta,lightgreen,blue,31,35,38,40,49,63,70,80,92,99,112,126,130,138,142,148,160,162,167,169,174,176,178,184,186,210,212,215,247"
+/set weechat.color.chat_prefix_error		lightred
+/set weechat.color.chat_prefix_network		lightblue
+/set weechat.color.chat_prefix_suffix		darkgray
+/set weechat.color.chat_read_marker			darkgray
+/set weechat.color.chat_time				235
+/set weechat.color.chat_time_delimiters		235
+/set weechat.color.separator				darkgray
+/set weechat.color.status_name_ssl			white
+/set weechat.bar.buflist.size_max			20
+/set weechat.bar.fset.separator				off
+/set weechat.bar.input.color_delim			darkgray
+/set weechat.bar.input.conditions			"${window.buffer.full_name} != perl.highmon"
+/set weechat.bar.input.items				"buffer_name+(buffer_modes)+[buffer_nicklist_count],[input_prompt]+(away),[input_search],[input_paste],input_text"
+/set weechat.bar.input.separator			off
+/set weechat.bar.nicklist.size_max			15
+/set weechat.bar.status.color_bg			default
+/set weechat.bar.status.color_delim			darkgray
+/set weechat.bar.status.conditions			"${window.buffer.full_name} != perl.highmon"
+/set weechat.bar.status.items				"buffer_number+:+buffer_name+(buffer_modes)+[buffer_nicklist_count]"
+/set weechat.bar.status.separator			off
+/set weechat.bar.title.color_bg				black
+/set weechat.bar.title.separator			off
+/set weechat.bar.title.size_max				2
+/set buflist.format.buffer					"${if:${type}==server?${if:${window[gui_current_window].buffer.local_variables.server}==${buffer.local_variables.server}?${if:${irc_server.is_connected}?${color:green,235}:${color:lightred,235}}• ${color:default,235}${name}:${if:${irc_server.is_connected}?${color:green,235}:${color:lightred,235}}• ${color:default,235}${indent}${name}}:}${if:${type}=~(channel|private)?${color_hotlist}${indent}${name}:}${if:${type}!~(channel|private|server)?${color:gray}${name}:}"
+/set buflist.format.buffer_current			"${if:${type}==server?${if:${window[gui_current_window].buffer.local_variables.server}==${buffer.local_variables.server}?${color:lightred}${if:${irc_server.is_connected}?${color:green,235}:${color:lightred,235}}• ${name}${format_hotlist}:${color:237}${if:${irc_server.is_connected}?${color:green,235}:${color:lightred,235}}• ${name}}${format_lag}${format_hotlist}:${if:${type}=~(channel|private)?• ${name}:${if:${type}!~(channel|private|server)?${color:lightblue}${name}:}}}"
+/set buflist.format.hotlist_highlight		"${color:yellow}"
+/set buflist.format.hotlist_message			"${color:cyan}"
+/set buflist.format.hotlist_private			"${color:yellow}"
+/set irc.look.ctcp_time_format				""
+/set irc.look.display_ctcp_blocked			off
+/set irc.look.display_ctcp_reply			off
+/set irc.look.display_ctcp_unknown			off
+/set irc.look.display_old_topic				off
+/set irc.look.display_join_message			""
+/set irc.look.item_nick_modes				off
+/set irc.look.join_auto_add_chantype		on
+/set irc.look.server_buffer					independent
+/set irc.look.smart_filter					off
+/set irc.color.input_nick					default
+/set irc.color.nick_prefixes				"y:green;q:green;a:lightred;o:red;h:yellow;v:lightblue;*:lightmagenta"
+/set irc.color.reason_quit					darkgray
+/set irc.color.topic_new					lightblue
+/set irc.network.ban_mask_default			"*!*@$host"
+/set irc.ctcp.clientinfo					""
+/set irc.ctcp.finger						""
+/set irc.ctcp.ping							""
+/set irc.ctcp.source						""
+/set irc.ctcp.time							""
+/set irc.ctcp.userinfo						""
+/set irc.ctcp.version						""
+/set irc.server_default.autorejoin			on
+/set irc.server_default.autorejoin_delay	3
+/set irc.server_default.command_delay		3
+/set irc.server_default.msg_part			"G-line: User has been permanently banned from this network."
+/set irc.server_default.msg_quit			"G-line: User has been permanently banned from this network."
+/set irc.server_default.nicks				"acidvegas,acid_vegas,acidvegas_"
+/set irc.server_default.realname			"MOST DANGEROUS MOTHERFUCK"
+/set irc.server_default.sasl_mechanism		external
+/set irc.server_default.sasl_username		"acidvegas"
+/set irc.server_default.ssl_cert			"%h/cert.pem"
+/set irc.server_default.ssl_verify			off
+/set irc.server_default.username			"stillfree"
+/set plugins.var.perl.antifuck.autopart		1
+/set plugins.var.perl.antifuck.nobufs		1
+/set plugins.var.perl.fuckyou.forcejoin		sajoin
+/set plugins.var.perl.fuckyou.forcepart		sapart
+/set plugins.var.perl.highmon.first_run		false
+/set plugins.var.perl.highmon.short_names	on
+```
+
+###### Servers
+```
+/server add 420chan		irc.420chan.org
+/server add 711chan		irc.711chan.org/6697 -ssl
+/server add blackhat	breaking.technology/6697 -ssl
+/server add efnet		efnet.port80.se/6697,irc.choopa.net/6697 -ssl
+/server add freenode	irc.freenode.com/6697 -ssl
+/server add ircstorm	irc.ircstorm.net/6699 -ssl
+/server add malvager	irc.malvager.net/6697 -ssl
+/server add oftc		irc.oftc.net/6697 -ssl
+/server add rizon		irc.rizon.net/6697 -ssl
+/server add sandnet		irc.arabs.ps/6697 -ssl
+/server add silph		irc.silph.co/6697 -ssl
+/server add supernets	irc.supernets.org/6697 -ssl
+/server add unreal		irc.unrealircd.org/6697 -ssl
+/server add wtfux		irc.wtfux.org/6697 -ssl
+
+/set irc.server.420chan.autojoin	#420chan,#drugs
+/set irc.server.711chan.autojoin	#711chan
+/set irc.server.blackhat.autojoin	#blackhat
+/set irc.server.efnet.autojoin		#2600,#efnetnews,#exchange,#lrh,#mircart
+/set irc.server.silph.autojoin		#ramen
+
+/set irc.server.supernets.anti_flood_prio_high 0
+/set irc.server.supernets.anti_flood_prio_low  0
+/set irc.server.unreal.usermode                "-x"
+```
+
+###### Security
+```
+/secure passphrase CHANGEME
+/secure set networkname CHANGEME
+${sec.data.networkname}
+```
+
+###### Services
+```
+/msg NickServ register PASSWORD EMAIL
+/msg NickServ ACCESS DEL <mask>
+/msg NickServ ACCESS ADD <mask>
+/msg NickServ AJOIN ADD <channel>
+/msg NickServ CERT ADD
+/msg NickServ SET AUTOOP ON
+/msg NickServ SET HIDE EMAIL ON
+/msg NickServ SET HIDE STATUS ON
+/msg NickServ SET HIDE USERMASK ON
+/msg NickServ SET HIDE QUIT ON
+/msg NickServ SET KEEPMODES ON
+/msg NickServ SET KILL QUICK
+/msg NickServ SET PRIVATE ON
+/msg NickServ SET SECURE ON
+/msg HostServ REQUEST <mask>
+/msg HostServ ON
+```
\ No newline at end of file
diff --git a/alias.conf b/alias.conf
new file mode 100644
index 0000000..8e6b1d4
--- /dev/null
+++ b/alias.conf
@@ -0,0 +1,99 @@
+#  bold
+#  color
+#  underline
+#  reset
+
+[cmd]
+# Art
+agrep    = "play -find *$**"
+derp     = "say say 0,1    10,10  11,10 10,10  0,1  1,1 ; say 0,1   11,10______0,1  1,1 ; say 0,1  11,10|10,10 11,10|10,10 11,10|10,10 11,10|10,10 0,1 1,1 ; say 0,1 8,8 1,8__8,8   1,8__8,8 0,1 1,1 ; say 8,8   1,0o8,8   1,0.8,8   1,1 ; say 0,1 8,8   1,8<.8,8     1,1 ; say 0,1 8,8         0,1 1,1 ; say 0,1  8,8  0,1,'8,8   0,1  1,1 ; say 0,1   8,8    0,1    1,1.;"
+lovecock = "say 0,1                                                  ; say 0,1      5,7#######0,1                                     ; say 0,1   5,7#####0       0,1   hey guys im $1, let me tell  ; say 0,1  5,7#####0     5_1  5)0,1  you a little about myself...        ; say 0,1  5,7#####0     0100  1o0 0,1                                1 ; say 0,1  5,7###1@5# 0       1 0  0,1  i LOVE cock                   ; say 0,1  5,7#0   5# 0       1>0   0,1                               ; say 0,1  5,7#0        5\;\;\;\;\;\;\;\;0,1     i LOVE cock               ; say 0,1  0,7      0,1                                          ; say 0,1  0,7           0,1                              1 0      ; say 0,1  0,7          1 5...W.0,1    I ROMANTICIZE THE NOTION    ; say 0,1  0,7          1 5...0,1      OF HAVING COCKS AND BALLS   ; say 0,1 0,7           0,1          ON ME AT ALL TIMES OF MY    ; say 0,7     1 >0,1               LIFE.                       ; say 0,7      0,1;"
+umad     = "say 0,1<$1> umadyet?        0,7     0,1                                 ; say 0,1<$1> hemad         0,7  0,8   0,1 0,8 0,1  4hehe am ownin these fkn noobs; say 0,1<$1> umad          0,8        0,1                              ; say 0,1<$1> umad           0,8      0,1                               ; say 0,1<$1> umadyet?      0,5 0,8       0,1                    0,15   0,1       ; say 0,1<$1> nou           0,5 0,2         0,1                 0,11 0,15     0,1     ; say 0,1<$1> umad?         0,5 0,2     0,8       0,1              0,11 0,15      0,1    ; say 0,1<$1> umad          0,5 0,2      0,8              0,1      0,11 0,15       0,1   ; say 0,1<$1> cum @ me bra  0,5 0,2          0,8              0,1   0,15        0,1  ; say 0,1<$1> umad          0,5 0,2               0,1       0,8 0,1 0,8 0,1 0,5           ; say 0,1<$1> umadyet?      0,5 0,2               0,1       0,15    0,5 0,1         0,5 ; say 0,1<$1> umad          0,5 0,8                0,1      0,5     0,1         0,5 ; say 0,1<$1> somad         0,5 0,8                 0,1         0,5 0,1         0,5 ; say 0,1<$1> umadyet?      0,5 0,14                  0,1        0,5 0,1    0,15     0,5 ; say 0,1<$1> umad          0,5              0,1  0,14    0,1       0,5 0,1    0,15     0,5 ; say 0,1<$1> hes ragin     0,5 0,1            0,5 0,1  0,14    0,1      5 0,5 0,1    0,15     0,5 ; say 0,1<$1> umad          0,5 0,1            0,5 0,1  0,4  0,14  0,1      5 0,5 0,1    0,15     0,5 ; say 0,1<$1> umadyet?      0,5 0,1            0,5 0,1  0,4      0,1    5 0,5 0,1    0,15     0,5 ;"
+
+# Alerts
+chat_norm = "say 8,5▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄ NORMAL CHATS 8,5▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄"
+chat_srs  = "say 8,5▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄ SERIOUS CHATS 8,5▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄"
+emergency = "say 8!1,8!8!0,4 IRC EMERGENCY 8!1,8!8!0,4 IRC EMERGENCY 8!1,8!8!0,4 IRC EMERGENCY 8!1,8!8!0,4 IRC EMERGENCY 8!1,8!8!0,4 IRC EMERGENCY 8!1,8!8!0,4 IRC EMERGENCY 8!1,8!8!0,4 IRC EMERGENCY 8!1,8!8!0,4 IRC EMERGENCY 8!1,8!8!0,4 IRC EMERGENCY 8!1,8!8!"
+flashbang = "cflood -fg 0 -bg 8 FLASHBANG"
+prison    = "say 04----------------------------------------------------------------------[IMPENETRABLE IRC PRISON WALL]-----------------------------------------------------------------------"
+
+# Chatters
+dzl_credit  = "say im with a credit union"
+dzl_26      = "say i dont troll because im 26"
+dzl_job     = "say i need a better job im too good at entry level shit"
+dzl_reality = "say nice perception of reality"
+tp_boom     = "say just wait till i get a supernets then enough http requests then boom"
+tp_dumb     = "say your suck a dumb fucking idiot..."
+
+# EFNet
+en_gold = "say You must have an EFNet 8,7GOLD account to view this message."
+
+# Git
+github   = "say https://github.com/acidvegas/$*"
+gitsuper = "say https://git.supernets.org/acidvegas/$*"
+
+# Faces
+shrug  = "say ¯\_(ツ)_/¯"
+shades = "say (⌐■_■)"
+srs    = "say (ಠ_ಠ)"
+
+# Other
+terminate = "kick $1 08,04                    T E R M I N A T E D                    "
+warning   = "say 1,8/!\08,04 WARNING 1,8/!\ 04$*"
+
+# Random
+beer     = "me throws $1 an ice cold 0,0 0,2 BUD 1,0c =)"
+beer2    = "me throw $1 an ice cold 0,0 0,5 BUD 1,0c =)"
+blog     = "say Hi! It looks like you're blogging on IRC. Would you like to: 2[Add Comments] 2[e-Mail this to a Friend] 2[Digg This!] 6[Submit to Slashdot] 2[Add to del.icio.us] 5[Kill yourself because0⬉5 nobody cares]"
+chatrain = "say              ya                                                                                                                                                                                          nice; say                                             chillin                                                                                                                                                                                 u?; say                                                                                     nice                                                                            ty                                                              np; say                                              ok                                                                                                                nice                                                                 %%                                                                                                       true; say                                                                                      same"
+cig      = "say 8,7\;.`-,:.`\;15,0||||||||||||||||||||4,14&8,14@14-\;`,-\;`"
+coffee   = "me hands $1 a 5,2""] of coffee! =)"
+cooldown = "say 1,8/!\8,4 WARNING 1,8/!\ 4This keyboard is currently on 12COOL DOWN4 until $1 can handle it."
+cooled   = "say [9ALERT] This keyboard is no longer on fire. Chats may proceed accordingly."
+doritos  = "say ▼ ◄ ▲ ► ▼ ◄ ▲ ► ▼ ◄ ▲ ► ▼ ◄ ▲ ► ▼ ◄ ▲ ▼ ◄ ▲ ► ▼ ◄ ▲ ► ▼ ◄▼ ◄ ▲ ► ▼ ◄ ▲ ► ▼ ▼ ◄ ▲ ► ▼ ◄ ▲ ► ▼ ◄ ▲ ► ▼ ◄ ▲ ► ▼ ◄ ▲ ▼ ◄ ▲ ► ▼ ◄ ▲ ► ▼ ◄▼ ◄ ▲ ► ▼ ◄ ▲ ► ▼▼ ◄ ▲ ► ▼ ◄ ▲ ► ▼ ◄ ▲ ► ▼ ◄ ▲ ► ▼ ◄ ▲ ▼ ◄ ▲ ► ▼ ◄ ▲ ► ▼ ◄▼ ◄ ▲ ► ▼ ◄ ▲ ► ▼▼ ◄ ▲ ► ▼ ◄ ▲ ► ▼ ◄ ▲ ► ▼ ◄ ▲ ► ▼ ◄ ▲ ▼ ◄ ▲ ► ▼ ◄ ▲ ► ▼ ◄▼ ◄ ▲ ► ▼ ◄ ▲ ► ▼ ▼ ◄ ▲ ► ▼ ◄ ▲ ► ▼ ◄ ▲ ► ▼ ◄ ▲ ► ▼ ◄ ▲ ▼ ◄ ▲ ► ▼ ◄ ▲ ► ▼ ◄▼ ◄ ▲ ► ▼ ◄ ▲ ► ▼ Ah Mannn! I dropped my bag of Doritos!!!"
+fred     = "say 4()_ <- FRED DURST'S HAT LOL"
+gotem    = "say 1,0 GOT EM "
+hate     = "say 4  HATE     4  HATE     4  HATE  "
+knuckz   = "say my knuckz: (C)(H)(A)(T)b d(L)(I)(F)(E)"
+wave     = "cflood ▁▂▃▄▅▆▇█▇▆▅▄▃▂▁"
+weed     = "say 9DUUUUUUUUUUUUUUUUUUUUUUUUUUUUDE DUDE DUDE DUDE DUDE DUDE DUDE DUDE FUCKING WEEEEEEEEED AHAHAHAHAHAHAHA DUDE!!!!!!!!!! WEED!!!!!!!!!!!! *hits bong* FUCKING DUUUUUUDE that WEEED like just...................DUDE"
+
+# Text
+1stup     = "say YO BITCH IM THE 1ST UP IN THIS PIECE. RESPECT MY ABILITY TO BE UP EARLY AND CHAT BEFORE YOU COCK SUCKER!!!!!!!!!"
+dna       = "say i got your moms dna inserted into each of my sperms and everytime i fuck you your mom is somehow cumming inside you"
+heartbeat = "say $1: your heart will skip one (1) beat in -5 seconds; say do not read this message;"
+icmp      = "say how about i do a nice icmp ping 2 u, figure out where you are and what you are on, spawn your command.com to a port of my choice and log in with telnet and have a field day with you"
+limp      = "say OR YOULL BE LEAVIN WITH A FAT LIP; say ITS ALL ABOUT THE HE SAYS SHE SAYS BULL SHIT.; say I THINK YOU BETTER QUIT TALKIN THAT SHIT PUNK; say SO COME ON AND GET IT.; say ITS JUST ONE OF THOSE DAYS"
+linkin    = "say CRAWLING IN MY SKIN. THESE WOUNDS THEY WILL NOT HEAL. FEAR IS HOW I FALL. CONFUSING WHAT IS REAL."
+money     = "say u look like a fucking money irl"
+operscum  = "say I have like 50,000 shells/vhosts/bncs. Bans won't do a thing except fill your list. And 'get to where i am today' is a sad testament to your life apparently. On a side note, I used to op other chans that are far bigger than this chan. I didn't get ops by k/b'ing everyone in sight or anyone that carried a touch of annoyance to me. I reserved k/bs for spammers and flooders, that's it. Everyone else I /ignored"
+peep      = "say ight so boom, i told son chill ah ah ah, he like nah, this that and the 3rd, blazhee blah, so i ping ponged poofed ol boi shit then i peeped the boyz so"
+worms     = "say super models give me dome while i count stacks and play worms"
+your      = "say look its not hard, your isnt you're.. you're is YOU ARE. jesus. did you even make it out of 8th grade. can you even COUNT TO EIGHT, fuckin your an IDIOT.. and im sure right now your eaiting to CORRECT ME on using your in the wrong context now that i've TAUGHT YOU HOW TO USE IT OMG JESUS"
+
+# SuperNETs
+sn_ad1  = "masshl %n: 1,8/!\08,04 WARNING 1,8/!\ 04This channel has moved to 12IRC.SUPERNETS.ORG #SUPERBOWL"
+sn_ad2  = "masshl %n: 04CAN WE CONTINUE THIS CONVERSATION AT IRC.SUPERNETS.ORG #SUPERBOWL FOR FUCKS SAKE"
+sn_auto = "say yeah you can go ahead and add irc.supernets.org to your clients auto-connect config now."
+sn_dad  = "say this isnt your dads football channel"
+sn_gold = "say You must have a SuperNETs 8,7GOLD account to view this message."
+
+# Troll
+fadeop  = "me 14<02Mode14> [-o $114] by $nick"
+fakick  = "me 14<05Kick14> $1 was kicked by $nick 14[$2-14]"
+fbi     = "notice $channel The Federal Bureau of Investigation logged a record of your entry into this illegal chatroom along with your IP address due to potential violations of 18 U.S.C. º 1030. Your IP address is entered into our criminaldatabase as well as the Department of Homeland Security. If you are not associated with these claims we strongly advise you to type '/part'. Thank you."
+mail    = "notice $channel You have unread messages from another user! Type /server mail read to read them."
+
+# Useful
+clear     = "buffer clear"
+close     = "buffer close"
+deprotect = "msg ChanServ MODE $channel LOCK DEL +eI ~a:$1 ~a:$1; mode $channel -eI ~a:$1 ~a:$1"
+exempt    = "mode +eI *!$X *!$X"
+msgbuf    = "command -buffer $1 * /input send $2-"
+ns_ident  = "msg NickServ IDENTIFY ${sec.data.${server}}"
+protect   = "mode $channel +eI ~a:$1 ~a:$1; msg chanserv mode $channel lock add +eI ~a:$1 ~a:$1"
+redraw    = "color reset;window refresh"
+say       = "msg *"
+
+[completion]
+msgbuf = "%(buffers_plugins_names)"
diff --git a/scripts/antifuck.pl b/scripts/antifuck.pl
new file mode 100644
index 0000000..e95259b
--- /dev/null
+++ b/scripts/antifuck.pl
@@ -0,0 +1,369 @@
+# Released into the Public Domain
+
+use strict;
+use warnings;
+
+no strict 'subs';
+
+my $SCRIPT_NAME = 'antifuck';
+my $SCRIPT_AUTHOR = 'The Krusty Krab <wowaname@volatile.ch>';
+my $SCRIPT_VERSION = '1.1';
+my $SCRIPT_LICENCE = 'Public domain';
+my $SCRIPT_DESC = 'Defend against forcejoins (e.g. from fuckyou.pl) and '.
+	'forceparts (e.g. from /remove)';
+
+my %OPTIONS = (
+	autopart => ['Whether to automatically part forcejoined channels. '.
+		'You can always do this manually with /antifuck part', '0'],
+	delay => ['Delay in milliseconds to wait before autoparting', '5000'],
+	forward => ['Whether to allow channel forwards (+f on freenode)', '1'],
+	ignore => ['Servers to ignore (e.g. for bouncers), separated by comma', ''],
+	nobufs => ['If 1, do not create buffers for forcejoined channels', '0'],
+	timeout =>
+		['Delay in milliseconds to wait for server to send JOIN after join',
+		'60000'],
+	);
+
+# %channels: channels we joined and received JOIN / NAMES for
+# %zombie: channels we joined but aren't yet in
+# %part: channels we were forced into and will part soon
+# %partbuf: buffers belonging to parted channels, we'll close these on
+#           /antifuck part
+our (%channels, %zombie, %part, %partbuf, $fuckbuf, $timeout_cb, $gc_cb);
+
+if (weechat::register($SCRIPT_NAME, $SCRIPT_AUTHOR, $SCRIPT_VERSION,
+ $SCRIPT_LICENCE, $SCRIPT_DESC, '', '')) {
+	weechat::hook_command('antifuck', $SCRIPT_DESC, 'part', <<'HELP',
+This script defends against forced joins, such as from irssi's fuckyou.pl or
+from channel forwards, as well as forced parts, such as from the /remove
+command. You can configure certain behaviour using the options under
+"plugins.var.perl.antifuck.*". Configure rejoin-on-/remove with the
+irc.server_default.autorejoin and .autorejoin_delay commands.
+
+Running "/antifuck part" will close all forcejoined channels and part them where
+appropriate.
+HELP
+		'part', 'cmd_antifuck', '');
+	weechat::hook_signal('irc_server_connected', 'irc_connect', '');
+	weechat::hook_signal('irc_server_disconnected', 'irc_disconnect', '');
+	weechat::hook_signal('irc_channel_opened', 'buffer_opened', '');
+	weechat::hook_signal('buffer_closed', 'buffer_closed', '');
+	weechat::hook_signal('*,irc_out1_join', 'client_join', '');
+	weechat::hook_signal('*,irc_out1_part', 'client_part', '');
+	weechat::hook_signal('*,irc_raw_in_001', 'irc_001', '');
+	weechat::hook_signal('*,irc_raw_in_470', 'irc_470', '');
+	weechat::hook_modifier('irc_in_366', 'irc_366', '');
+	weechat::hook_modifier('irc_in_join', 'irc_join', '');
+	weechat::hook_modifier('irc_in_part', 'irc_part', '');
+
+	for my $option (keys %OPTIONS) {
+		weechat::config_set_plugin($option, $OPTIONS{$option}[1])
+		 unless weechat::config_is_set_plugin($option);
+		weechat::config_set_desc_plugin($option, $OPTIONS{$option}[0]);
+	}
+
+	my $iptr = weechat::infolist_get('buffer', '', '');
+
+	while (weechat::infolist_next($iptr)) {
+		next unless weechat::infolist_string($iptr, 'plugin_name') eq 'irc';
+		my $buf = weechat::infolist_pointer($iptr, 'pointer');
+		$channels{
+			lc weechat::buffer_get_string($buf, 'localvar_server')}{
+			lc weechat::buffer_get_string($buf, 'localvar_channel')} = 1;
+	}
+	weechat::infolist_free($iptr);
+}
+
+sub mynick
+{
+	my ($buf, $nick) = ($_[0], $_[1]);
+
+	return lc weechat::buffer_get_string($buf, 'localvar_nick') eq lc $nick;
+}
+
+sub ignored
+{
+	my $server = shift;
+	my $ignore_conf = lc weechat::config_get_plugin('ignore');
+
+	return $ignore_conf =~ /(^|,)$server($|,)/;
+}
+
+sub nobufs { weechat::config_get_plugin('nobufs') }
+
+sub ircbuf { weechat::buffer_search('irc', "(?i)".(join '.', @_)) }
+sub ircparse { weechat::info_get_hashtable(irc_message_parse =>
+	{ message => shift }) }
+
+sub servchan
+{
+	my $buf = shift;
+
+	return (lc weechat::buffer_get_string($buf, 'localvar_server'),
+		lc weechat::buffer_get_string($buf, 'localvar_channel'));
+}
+
+sub reset_gc
+{
+	weechat::unhook($gc_cb) if $gc_cb;
+	$gc_cb = weechat::hook_timer(weechat::config_get_plugin('timeout'), 0, 1,
+		'run_gc', '');
+}
+
+sub cmd_antifuck
+{
+	my (undef, $buffer, $args) = @_;
+
+	if ($args eq 'part') {
+		# TODO: we really need to spend more time here making sure we send the
+		# fewest PARTs possible, a la irc_join_delay
+		weechat::buffer_close($fuckbuf);
+	}
+
+	return weechat::WEECHAT_RC_OK;
+}
+
+sub fuckbuf_input { return weechat::WEECHAT_RC_OK; }
+
+sub fuckbuf_close
+{
+	weechat::buffer_close($_) for (keys %partbuf);
+	%partbuf = ();
+	$fuckbuf = '';
+
+	return weechat::WEECHAT_RC_OK;
+}
+
+sub irc_connect
+{
+	my $server = pop;
+	my ($autojoin) = (weechat::config_string(weechat::config_get(
+		"irc.server.$server.autojoin")) =~ /^([^ ]*)/);
+
+	$zombie{$server}{$_} = 1 for (split ',', lc($autojoin));
+
+	return weechat::WEECHAT_RC_OK;
+}
+
+sub irc_disconnect
+{
+	my $server = pop;
+
+	$server = lc $server;
+	delete $channels{$server};
+	delete $zombie{$server};
+	delete $part{$server};
+
+	return weechat::WEECHAT_RC_OK;
+}
+
+sub buffer_opened {
+	my $buffer = pop;
+	my ($server, $channel) = servchan($buffer);
+	return weechat::WEECHAT_RC_OK if exists $channels{$server}{$channel};
+	return weechat::WEECHAT_RC_OK if ignored($server);
+
+	$fuckbuf = weechat::buffer_new(
+		'antifuck',
+		'fuckbuf_input',
+		'',
+		'fuckbuf_close',
+		''
+		) unless $fuckbuf;
+
+	weechat::buffer_merge($buffer, $fuckbuf);
+	#return weechat::WEECHAT_RC_OK unless weechat::config_get_plugin('autopart');
+
+	$partbuf{$buffer} = 1;
+	return weechat::WEECHAT_RC_OK;
+}
+
+sub buffer_closed {
+	my $buffer = pop;
+
+	delete $partbuf{$buffer};
+	return weechat::WEECHAT_RC_OK;
+}
+
+sub client_join
+{
+	my (undef, $server, $channel) = (shift,
+		shift =~ /(.+),irc_out1_join/i,
+		shift =~ /^join :?([^ ]*)/i);
+	($server, $channel) = (lc $server, lc $channel);
+
+	reset_gc();
+
+	($_ eq '0' ? %{$channels{$server}} = () : $zombie{$server}{$_} = 1)
+		for (split ',', $channel);
+	return weechat::WEECHAT_RC_OK;
+}
+
+sub client_part
+{
+	my (undef, $server, $channel) = (shift,
+		shift =~ /(.+),irc_out1_part/i,
+		shift =~ /^part ([^ ]*)/i);
+	($server, $channel) = (lc $server, lc $channel);
+
+	delete $channels{$server}{$_} for (split ',', $channel);
+	return weechat::WEECHAT_RC_OK;
+}
+
+# RPL_WELCOME
+sub irc_001
+{
+	my (undef, $server, $message) = (shift,
+		shift =~ /(.+),irc_raw_in_001/, shift);
+
+	$server = lc $server;
+	return weechat::WEECHAT_RC_OK unless $message =~ / :- Welcome to ZNC -$/;
+
+	my $ignore_conf = lc weechat::config_get_plugin('ignore');
+	return weechat::WEECHAT_RC_OK if $ignore_conf =~ /(^|,)$server($|,)/;
+
+	weechat::config_set_plugin('ignore', "$ignore_conf,$server");
+
+	return weechat::WEECHAT_RC_OK;
+}
+
+sub irc_join
+{
+	my ($server, $message, $msghash) = (lc $_[2], $_[3], ircparse($_[3]));
+	my ($nick, $channel) = ($msghash->{nick}, lc $msghash->{channel});
+	my $buffer = ircbuf("$server.$channel");
+
+	return $message if exists $channels{$server}{$channel};
+	if (exists $zombie{$server}{$channel} || ignored($server)) {
+		delete $zombie{$server}{$channel};
+		$channels{$server}{$channel} = 1;
+		return $message;
+	}
+	# XXX return $message unless mynick($buffer, $nick);
+
+	$part{$server}{$channel} = 1;
+	$timeout_cb = weechat::hook_timer(
+		weechat::config_get_plugin('delay'), 0, 1, 'irc_join_delay', $buffer)
+		unless $timeout_cb || !weechat::config_get_plugin('autopart');
+
+	return $message unless nobufs();
+
+	$fuckbuf = weechat::buffer_new(
+		'antifuck',
+		'fuckbuf_input',
+		'',
+		'fuckbuf_close',
+		''
+		) unless $fuckbuf;
+	weechat::print($fuckbuf, weechat::prefix('join').
+		weechat::color('irc.color.message_join').
+		'You were forced to join '.weechat::color('chat_channel').$channel.
+		weechat::color('irc.color.message_join').', leaving');
+
+	return '';
+}
+
+# RPL_ENDOFNAMES
+sub irc_366
+{
+	my ($server, $message) = ($_[2], $_[3]);
+	my ($nick, $channel) = $message =~ /^:[^ ]* 366 ([^ ]*) ([^ ]*)/i;
+	my $buffer = ircbuf("$server.$channel");
+	($server, $channel) = (lc $server, lc $channel);
+
+	return $message if exists $channels{$server}{$channel};
+	return '' if nobufs();
+
+	weechat::print($buffer, weechat::prefix('network').
+		'Forcejoined, not syncing modes');
+
+	return '';
+}
+
+# ERR_LINKCHANNEL
+sub irc_470
+{
+	my (undef, $server, $oldchan, $newchan) = (shift,
+		shift =~ /(.+),irc_raw_in_470/,
+		shift =~ /^:[^ ]* 470 [^ ]+ ([^ ]+) ([^ ]+)/);
+	($server, $oldchan, $newchan) = (lc $server, lc $oldchan, lc $newchan);
+
+	delete $channels{$server}{$oldchan};
+	$channels{$server}{$newchan} = 1 if weechat::config_get_plugin('forward');
+	return weechat::WEECHAT_RC_OK;
+}
+
+sub irc_join_delay
+{
+	my $buffer = shift;
+
+	for my $server (keys %part) {
+		my $chans = '';
+
+		for my $chan (keys %{$part{$server}}) {
+			if (length($chans) + length($chan) > 500) {
+				weechat::hook_signal_send('irc_input_send',
+					weechat::WEECHAT_HOOK_SIGNAL_STRING,
+					"$server;;priority_low;;/part $chans");
+				$chans = '';
+			}
+
+			$chans .= "$chan,";
+		}
+
+		weechat::hook_signal_send('irc_input_send',
+			weechat::WEECHAT_HOOK_SIGNAL_STRING,
+			"$server;;priority_low;;/part $chans");
+	}
+	$timeout_cb = '';
+	%part = ();
+	return weechat::WEECHAT_RC_OK;
+}
+
+sub run_gc
+{
+	%zombie = ();
+	return weechat::WEECHAT_RC_OK;
+}
+
+sub irc_part
+{
+	my ($server, $message, $msghash) = ($_[2], $_[3], ircparse($_[3]));
+	my ($arj, $arj_delay, $arjd, $arjd_delay) = (
+		weechat::config_get("irc.server.$server.autorejoin"),
+		weechat::config_get("irc.server.$server.autorejoin_delay"),
+		weechat::config_get("irc.server_default.autorejoin"),
+		weechat::config_get("irc.server_default.autorejoin_delay")
+		);
+	return $message unless (
+		weechat::config_option_is_null($arj) ?
+		weechat::config_boolean($arjd) :
+		weechat::config_boolean($arj)
+		);
+
+	my ($nick, $channel, $reason) = ($msghash->{nick}, $msghash->{channel},
+		$msghash->{text});
+
+	my $buffer = ircbuf("$server.$channel");
+	my ($lserver, $lchannel) = (lc $server, lc $channel);
+
+	return $message unless mynick($buffer, $nick);
+	return $message unless exists $channels{$lserver}{$lchannel};
+	return $message if ignored($lserver);
+
+	weechat::print($buffer, weechat::prefix('quit').
+		weechat::color('irc.color.message_quit').
+		'You were forced to part '.weechat::color('chat_channel').$channel.
+		weechat::color('chat_delimiters').' ('.weechat::color('reset').
+		$reason.weechat::color('chat_delimiters').')'.
+		weechat::color('irc.color.message_quit').', rejoining');
+	my $delay = (
+		weechat::config_option_is_null($arj_delay) ?
+		weechat::config_integer($arjd_delay) :
+		weechat::config_integer($arj_delay)
+		);
+	weechat::command($buffer, ($delay ? "/wait $delay " : "").
+		"/join $channel");
+
+	return '';
+}
diff --git a/scripts/autosort.py b/scripts/autosort.py
new file mode 100644
index 0000000..8f7c263
--- /dev/null
+++ b/scripts/autosort.py
@@ -0,0 +1,1069 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2013-2017 Maarten de Vries <maarten@de-vri.es>
+#
+# 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/>.
+#
+
+#
+# Autosort automatically keeps your buffers sorted and grouped by server.
+# You can define your own sorting rules. See /help autosort for more details.
+#
+# https://github.com/de-vri-es/weechat-autosort
+#
+
+#
+# Changelog:
+# 3.6:
+#   * Add more documentation on provided info hooks.
+# 3.5:
+#   * Add ${info:autosort_escape,...} to escape arguments for other info hooks.
+# 3.4:
+#   * Fix rate-limit of sorting to prevent high CPU load and lock-ups.
+#   * Fix bug in parsing empty arguments for info hooks.
+#   * Add debug_log option to aid with debugging.
+#   * Correct a few typos.
+# 3.3:
+#   * Fix the /autosort debug command for unicode.
+#   * Update the default rules to work better with Slack.
+# 3.2:
+#   * Fix python3 compatiblity.
+# 3.1:
+#   * Use colors to format the help text.
+# 3.0:
+#   * Switch to evaluated expressions for sorting.
+#   * Add `/autosort debug` command.
+#   * Add ${info:autosort_replace,from,to,text} to replace substrings in sort rules.
+#   * Add ${info:autosort_order,value,first,second,third} to ease writing sort rules.
+#   * Make tab completion context aware.
+# 2.8:
+#   * Fix compatibility with python 3 regarding unicode handling.
+# 2.7:
+#   * Fix sorting of buffers with spaces in their name.
+# 2.6:
+#   * Ignore case in rules when doing case insensitive sorting.
+# 2.5:
+#   * Fix handling unicode buffer names.
+#   * Add hint to set irc.look.server_buffer to independent and buffers.look.indenting to on.
+# 2.4:
+#   * Make script python3 compatible.
+# 2.3:
+#   * Fix sorting items without score last (regressed in 2.2).
+# 2.2:
+#   * Add configuration option for signals that trigger a sort.
+#   * Add command to manually trigger a sort (/autosort sort).
+#   * Add replacement patterns to apply before sorting.
+# 2.1:
+#   * Fix some minor style issues.
+# 2.0:
+#   * Allow for custom sort rules.
+#
+
+
+import json
+import math
+import re
+import sys
+import time
+import weechat
+
+SCRIPT_NAME     = 'autosort'
+SCRIPT_AUTHOR   = 'Maarten de Vries <maarten@de-vri.es>'
+SCRIPT_VERSION  = '3.6'
+SCRIPT_LICENSE  = 'GPL3'
+SCRIPT_DESC     = 'Flexible automatic (or manual) buffer sorting based on eval expressions.'
+
+
+config             = None
+hooks              = []
+signal_delay_timer = None
+sort_limit_timer   = None
+sort_queued        = False
+
+
+# Make sure that unicode, bytes and str are always available in python2 and 3.
+# For python 2, str == bytes
+# For python 3, str == unicode
+if sys.version_info[0] >= 3:
+	unicode = str
+
+def ensure_str(input):
+	'''
+	Make sure the given type if the correct string type for the current python version.
+	That means bytes for python2 and unicode for python3.
+	'''
+	if not isinstance(input, str):
+		if isinstance(input, bytes):
+			return input.encode('utf-8')
+		if isinstance(input, unicode):
+			return input.decode('utf-8')
+	return input
+
+
+if hasattr(time, 'perf_counter'):
+	perf_counter = time.perf_counter
+else:
+	perf_counter = time.clock
+
+def casefold(string):
+	if hasattr(string, 'casefold'): return string.casefold()
+	# Fall back to lowercasing for python2.
+	return string.lower()
+
+def list_swap(values, a, b):
+	values[a], values[b] = values[b], values[a]
+
+def list_move(values, old_index, new_index):
+	values.insert(new_index, values.pop(old_index))
+
+def list_find(collection, value):
+	for i, elem in enumerate(collection):
+		if elem == value: return i
+	return None
+
+class HumanReadableError(Exception):
+	pass
+
+def parse_int(arg, arg_name = 'argument'):
+	''' Parse an integer and provide a more human readable error. '''
+	arg = arg.strip()
+	try:
+		return int(arg)
+	except ValueError:
+		raise HumanReadableError('Invalid {0}: expected integer, got "{1}".'.format(arg_name, arg))
+
+def decode_rules(blob):
+	parsed = json.loads(blob)
+	if not isinstance(parsed, list):
+		log('Malformed rules, expected a JSON encoded list of strings, but got a {0}. No rules have been loaded. Please fix the setting manually.'.format(type(parsed)))
+		return []
+
+	for i, entry in enumerate(parsed):
+		if not isinstance(entry, (str, unicode)):
+			log('Rule #{0} is not a string but a {1}. No rules have been loaded. Please fix the setting manually.'.format(i, type(entry)))
+			return []
+
+	return parsed
+
+def decode_helpers(blob):
+	parsed = json.loads(blob)
+	if not isinstance(parsed, dict):
+		log('Malformed helpers, expected a JSON encoded dictionary but got a {0}. No helpers have been loaded. Please fix the setting manually.'.format(type(parsed)))
+		return {}
+
+	for key, value in parsed.items():
+		if not isinstance(value, (str, unicode)):
+			log('Helper "{0}" is not a string but a {1}. No helpers have been loaded. Please fix setting manually.'.format(key, type(value)))
+			return {}
+	return parsed
+
+class Config:
+	''' The autosort configuration. '''
+
+	default_rules = json.dumps([
+		'${core_first}',
+		'${irc_last}',
+		'${buffer.plugin.name}',
+		'${irc_raw_first}',
+		'${if:${plugin}==irc?${server}}',
+		'${if:${plugin}==irc?${info:autosort_order,${type},server,*,channel,private}}',
+		'${if:${plugin}==irc?${hashless_name}}',
+		'${buffer.full_name}',
+	])
+
+	default_helpers = json.dumps({
+		'core_first':     '${if:${buffer.full_name}!=core.weechat}',
+		'irc_first':      '${if:${buffer.plugin.name}!=irc}',
+		'irc_last':       '${if:${buffer.plugin.name}==irc}',
+		'irc_raw_first':  '${if:${buffer.full_name}!=irc.irc_raw}',
+		'irc_raw_last':   '${if:${buffer.full_name}==irc.irc_raw}',
+		'hashless_name':  '${info:autosort_replace,#,,${info:autosort_escape,${buffer.name}}}',
+	})
+
+	default_signal_delay = 5
+	default_sort_limit   = 100
+
+	default_signals = 'buffer_opened buffer_merged buffer_unmerged buffer_renamed'
+
+	def __init__(self, filename):
+		''' Initialize the configuration. '''
+
+		self.filename         = filename
+		self.config_file      = weechat.config_new(self.filename, '', '')
+		self.sorting_section  = None
+		self.v3_section       = None
+
+		self.case_sensitive   = False
+		self.rules            = []
+		self.helpers          = {}
+		self.signals          = []
+		self.signal_delay     = Config.default_signal_delay,
+		self.sort_limit       = Config.default_sort_limit,
+		self.sort_on_config   = True
+		self.debug_log        = False
+
+		self.__case_sensitive = None
+		self.__rules          = None
+		self.__helpers        = None
+		self.__signals        = None
+		self.__signal_delay   = None
+		self.__sort_limit     = None
+		self.__sort_on_config = None
+		self.__debug_log      = None
+
+		if not self.config_file:
+			log('Failed to initialize configuration file "{0}".'.format(self.filename))
+			return
+
+		self.sorting_section = weechat.config_new_section(self.config_file, 'sorting', False, False, '', '', '', '', '', '', '', '', '', '')
+		self.v3_section      = weechat.config_new_section(self.config_file, 'v3',      False, False, '', '', '', '', '', '', '', '', '', '')
+
+		if not self.sorting_section:
+			log('Failed to initialize section "sorting" of configuration file.')
+			weechat.config_free(self.config_file)
+			return
+
+		self.__case_sensitive = weechat.config_new_option(
+			self.config_file, self.sorting_section,
+			'case_sensitive', 'boolean',
+			'If this option is on, sorting is case sensitive.',
+			'', 0, 0, 'off', 'off', 0,
+			'', '', '', '', '', ''
+		)
+
+		weechat.config_new_option(
+			self.config_file, self.sorting_section,
+			'rules', 'string',
+			'Sort rules used by autosort v2.x and below. Not used by autosort anymore.',
+			'', 0, 0, '', '', 0,
+			'', '', '', '', '', ''
+		)
+
+		weechat.config_new_option(
+			self.config_file, self.sorting_section,
+			'replacements', 'string',
+			'Replacement patterns used by autosort v2.x and below. Not used by autosort anymore.',
+			'', 0, 0, '', '', 0,
+			'', '', '', '', '', ''
+		)
+
+		self.__rules = weechat.config_new_option(
+			self.config_file, self.v3_section,
+			'rules', 'string',
+			'An ordered list of sorting rules encoded as JSON. See /help autosort for commands to manipulate these rules.',
+			'', 0, 0, Config.default_rules, Config.default_rules, 0,
+			'', '', '', '', '', ''
+		)
+
+		self.__helpers = weechat.config_new_option(
+			self.config_file, self.v3_section,
+			'helpers', 'string',
+			'A dictionary helper variables to use in the sorting rules, encoded as JSON. See /help autosort for commands to manipulate these helpers.',
+			'', 0, 0, Config.default_helpers, Config.default_helpers, 0,
+			'', '', '', '', '', ''
+		)
+
+		self.__signals = weechat.config_new_option(
+			self.config_file, self.sorting_section,
+			'signals', 'string',
+			'A space separated list of signals that will cause autosort to resort your buffer list.',
+			'', 0, 0, Config.default_signals, Config.default_signals, 0,
+			'', '', '', '', '', ''
+		)
+
+		self.__signal_delay = weechat.config_new_option(
+			self.config_file, self.sorting_section,
+			'signal_delay', 'integer',
+			'Delay in milliseconds to wait after a signal before sorting the buffer list. This prevents triggering many times if multiple signals arrive in a short time. It can also be needed to wait for buffer localvars to be available.',
+			'', 0, 1000, str(Config.default_signal_delay), str(Config.default_signal_delay), 0,
+			'', '', '', '', '', ''
+		)
+
+		self.__sort_limit = weechat.config_new_option(
+			self.config_file, self.sorting_section,
+			'sort_limit', 'integer',
+			'Minimum delay in milliseconds to wait after sorting before signals can trigger a sort again. This is effectively a rate limit on sorting. Keeping signal_delay low while setting this higher can reduce excessive sorting without a long initial delay.',
+			'', 0, 1000, str(Config.default_sort_limit), str(Config.default_sort_limit), 0,
+			'', '', '', '', '', ''
+		)
+
+		self.__sort_on_config = weechat.config_new_option(
+			self.config_file, self.sorting_section,
+			'sort_on_config_change', 'boolean',
+			'Decides if the buffer list should be sorted when autosort configuration changes.',
+			'', 0, 0, 'on', 'on', 0,
+			'', '', '', '', '', ''
+		)
+
+		self.__debug_log = weechat.config_new_option(
+			self.config_file, self.sorting_section,
+			'debug_log', 'boolean',
+			'If enabled, print more debug messages. Not recommended for normal usage.',
+			'', 0, 0, 'off', 'off', 0,
+			'', '', '', '', '', ''
+		)
+
+		if weechat.config_read(self.config_file) != weechat.WEECHAT_RC_OK:
+			log('Failed to load configuration file.')
+
+		if weechat.config_write(self.config_file) != weechat.WEECHAT_RC_OK:
+			log('Failed to write configuration file.')
+
+		self.reload()
+
+	def reload(self):
+		''' Load configuration variables. '''
+
+		self.case_sensitive = weechat.config_boolean(self.__case_sensitive)
+
+		rules_blob    = weechat.config_string(self.__rules)
+		helpers_blob  = weechat.config_string(self.__helpers)
+		signals_blob  = weechat.config_string(self.__signals)
+
+		self.rules          = decode_rules(rules_blob)
+		self.helpers        = decode_helpers(helpers_blob)
+		self.signals        = signals_blob.split()
+		self.signal_delay   = weechat.config_integer(self.__signal_delay)
+		self.sort_limit     = weechat.config_integer(self.__sort_limit)
+		self.sort_on_config = weechat.config_boolean(self.__sort_on_config)
+		self.debug_log      = weechat.config_boolean(self.__debug_log)
+
+	def save_rules(self, run_callback = True):
+		''' Save the current rules to the configuration. '''
+		weechat.config_option_set(self.__rules, json.dumps(self.rules), run_callback)
+
+	def save_helpers(self, run_callback = True):
+		''' Save the current helpers to the configuration. '''
+		weechat.config_option_set(self.__helpers, json.dumps(self.helpers), run_callback)
+