-#-- vim:sw=2:et\r
-#++\r
-#\r
-# :title: Bans Plugin v3 for rbot 0.9.11 and later\r
-#\r
-# Author:: Marco Gulino <marco@kmobiletools.org>\r
-# Author:: kamu <mr.kamu@gmail.com>\r
-# Author:: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>\r
-#\r
-# Copyright:: (C) 2006 Marco Gulino\r
-# Copyright:: (C) 2007 kamu, Giuseppe Bilotta\r
-#\r
-# License:: GPL V2.\r
-#\r
-# Managing kick and bans, automatically removing bans after timeouts, quiet\r
-# bans, and kickban/quietban based on regexp\r
-#\r
-# v1 -> v2 (kamu's version, never released)\r
-# * reworked\r
-# * autoactions triggered on join\r
-# * action on join or badword can be anything: kick, ban, kickban, quiet\r
-#\r
-# v2 -> v3 (GB)\r
-# * remove the 'bans' prefix from most of the commands\r
-# * (un)quiet has been renamed to (un)silence because 'quiet' was used to\r
-# tell the bot to keep quiet\r
-# * both (un)quiet and (un)silence are accepted as actions\r
-# * use the more descriptive 'onjoin' term for autoactions\r
-# * convert v1's (0.9.10) :bans and :bansmasks to BadWordActions and\r
-# WhitelistEntries\r
-# * enhanced list manipulation facilities\r
-# * fixed regexp usage in requirements for plugin map\r
-# * add proper auth management\r
-\r
-OnJoinAction = Struct.new("OnJoinAction", :host, :action, :channel, :reason)\r
-BadWordAction = Struct.new("BadWordAction", :regexp, :action, :channel, :timer, :reason)\r
-WhitelistEntry = Struct.new("WhitelistEntry", :host, :channel)\r
-\r
-\r
-class BansPlugin < Plugin\r
-\r
- IdxRe = /^\d+$/\r
- TimerRe = /^\d+[smhd]$/\r
- ChannelRe = /^#+[^\s]+$/\r
- ChannelAllRe = /^(?:all|#+[^\s]+)$/\r
- ActionRe = /(?:ban|kick|kickban|silence|quiet)/\r
-\r
- def name\r
- "bans"\r
- end\r
-\r
- def make_badword_rx(txt)\r
- return /\b(?:#{txt})\b/i\r
- end\r
-\r
- def initialize\r
- super\r
-\r
- # Convert old BadWordActions, which were simpler and labelled :bans\r
- if @registry.has_key? :bans\r
- badwords = Array.new\r
- bans = @registry[:bans]\r
- @registry[:bans].each { |ar|\r
- case ar[0]\r
- when "quietban"\r
- action = :silence\r
- when "kickban"\r
- action = :kickban\r
- else\r
- # Shouldn't happen\r
- warn "Unknown action in old data #{ar.inspect} -- entry ignored"\r
- next\r
- end\r
- bans.delete(ar)\r
- chan = ar[1].downcase\r
- regexp = make_badword_rx(ar[2])\r
- badwords << BadWordAction.new(regexp, action, chan, "0s", "")\r
- }\r
- @registry[:badwords] = badwords\r
- if bans.length > 0\r
- # Store the ones we couldn't convert\r
- @registry[:bans] = bans\r
- else\r
- @registry.delete(:bans)\r
- end\r
- else\r
- @registry[:badwords] = Array.new unless @registry.has_key? :badwords\r
- end\r
-\r
- # Convert old WhitelistEntries, which were simpler and labelled :bansmasks\r
- if @registry.has_key? :bans\r
- wl = Array.new\r
- @registry[:bansmasks].each { |mask|\r
- badwords << WhitelistEntry.new(mask, "all")\r
- }\r
- @registry[:whitelist] = wl\r
- @registry.delete(:bansmasks)\r
- else\r
- @registry[:whitelist] = Array.new unless @registry.has_key? :whitelist\r
- end\r
-\r
- @registry[:onjoin] = Array.new unless @registry.has_key? :onjoin\r
- end\r
-\r
- def help(plugin, topic="")\r
- case plugin\r
- when "ban"\r
- return "ban <nick/hostmask> [Xs/m/h/d] [#channel]: ban a user from the given channel for the given amount of time. default is forever, on the current channel"\r
- when "unban"\r
- return "unban <nick/hostmask> [#channel]: unban a user from the given channel. defaults to the current channel"\r
- when "kick"\r
- return "kick <nick> [#channel] [reason ...]: kick a user from the given channel with the given reason. defaults to the current channel, no reason"\r
- when "kickban"\r
- return "kickban <nick> [Xs/m/h/d] [#channel] [reason ...]: kicks and bans a user from the given channel for the given amount of time, with the given reason. default is forever, on the current channel, with no reason"\r
- when "silence"\r
- return "silence <nick/hostmask> [Xs/m/h/d] [#channel]: silence a user on the given channel for the given time. default is forever, on the current channel. not all servers support silencing users"\r
- when "unsilence"\r
- return "unsilence <nick/hostmask> [#channel]: allow the given user to talk on the given channel. defaults to the current channel"\r
- when "bans"\r
- case topic\r
- when "add"\r
- return "bans add <onjoin|badword|whitelist>: add an automatic action for people that join or say some bad word, or a whitelist entry. further help available"\r
- when "add onjoin"\r
- return "bans add onjoin <hostmask> [action] [#channel] [reason ...]: will add an autoaction for any one who joins with hostmask. default action is silence, default channel is all"\r
- when "add badword"\r
- return "bans add badword <regexp> [action] [Xs/m/h/d] [#channel|all] [reason ...]: adds a badword regexp, if a user sends a message that matches regexp, the action will be invoked. default action is silence, default channel is all"\r
- when "add whitelist"\r
- return "bans add whitelist <hostmask> [#channel|all]: add the given hostmask to the whitelist. no autoaction will be triggered by users on the whitelist"\r
- when "rm"\r
- return "bans rm <onjoin|badword|whitelist> <hostmask/regexp> [#channel], or bans rm <onjoin|badword|whitelist> index <num>: removes the specified onjoin or badword rule or whitelist entry."\r
- when "list"\r
- return"bans list <onjoin|badword|whitelist>: lists all onjoin or badwords or whitelist entries"\r
- end\r
- end\r
- return "bans <command>: allows a user of the bot to do a range of bans and unbans. commands are: [un]ban, kick[ban], [un]silence, add, rm and list"\r
- end\r
-\r
- def listen(m)\r
- return unless m.respond_to?(:public?) and m.public?\r
- @registry[:whitelist].each { |white|\r
- next unless ['all', m.target.downcase].include?(white.channel)\r
- return if m.source.matches?(white.host)\r
- }\r
-\r
- @registry[:badwords].each { |badword|\r
- next unless ['all', m.target.downcase].include?(badword.channel)\r
- next unless badword.regexp.match(m.message)\r
-\r
- do_cmd(badword.action.to_sym, m.source.nick, m.target, badword.timer, badword.reason)\r
- m.reply "bad word detected! #{badword.action} for #{badword.timer} because: #{badword.reason}"\r
- return\r
- }\r
- end\r
-\r
- def join(m)\r
- @registry[:whitelist].each { |white|\r
- next unless ['all', m.target.downcase].include?(white.channel)\r
- return if m.source.matches?(white.host)\r
- }\r
-\r
- @registry[:onjoin].each { |auto|\r
- next unless ['all', m.target.downcase].include?(auto.channel)\r
- next unless m.source.matches? auto.host\r
-\r
- do_cmd(auto.action.to_sym, m.source.nick, m.target, "0s", auto.reason)\r
- return\r
- }\r
- end\r
-\r
- def ban_user(m, params=nil)\r
- nick, channel = params[:nick], check_channel(m, params[:channel])\r
- timer = params[:timer]\r
- do_cmd(:ban, nick, channel, timer)\r
- end\r
-\r
- def unban_user(m, params=nil)\r
- nick, channel = params[:nick], check_channel(m, params[:channel])\r
- do_cmd(:unban, nick, channel)\r
- end\r
-\r
- def kick_user(m, params=nil)\r
- nick, channel = params[:nick], check_channel(m, params[:channel])\r
- reason = params[:reason].to_s\r
- do_cmd(:kick, nick, channel, "0s", reason)\r
- end\r
-\r
- def kickban_user(m, params=nil)\r
- nick, channel, reason = params[:nick], check_channel(m, params[:channel])\r
- timer, reason = params[:timer], params[:reason].to_s\r
- do_cmd(:kickban, nick, channel, timer, reason)\r
- end\r
-\r
- def silence_user(m, params=nil)\r
- nick, channel = params[:nick], check_channel(m, params[:channel])\r
- timer = params[:timer]\r
- do_cmd(:silence, nick, channel, timer)\r
- end\r
-\r
- def unsilence_user(m, params=nil)\r
- nick, channel = params[:nick], check_channel(m, params[:channel])\r
- do_cmd(:unsilence, nick, channel)\r
- end\r
-\r
- def add_onjoin(m, params=nil)\r
- begin\r
- host, channel = m.server.new_netmask(params[:host]), params[:channel].downcase\r
- action, reason = params[:action], params[:reason].to_s\r
-\r
- autos = @registry[:onjoin]\r
- autos << OnJoinAction.new(host, action, channel, reason.dup)\r
- @registry[:onjoin] = autos\r
-\r
- m.okay\r
- rescue\r
- error $!\r
- m.reply $!\r
- end\r
- end\r
-\r
- def list_onjoin(m, params=nil)\r
- m.reply "onjoin rules: #{@registry[:onjoin].length}"\r
- @registry[:onjoin].each_with_index { |auto, idx|\r
- m.reply "\##{idx+1}: #{auto.host} | #{auto.action} | #{auto.channel} | '#{auto.reason}'"\r
- }\r
- end\r
-\r
- def rm_onjoin(m, params=nil)\r
- autos = @registry[:onjoin]\r
- count = autos.length\r
-\r
- idx = nil\r
- idx = params[:idx].to_i if params[:idx]\r
-\r
- if idx\r
- if idx > count\r
- m.reply "No such onjoin \##{idx}"\r
- return\r
- end\r
- autos.delete_at(idx-1)\r
- else\r
- begin\r
- host = m.server.new_netmask(params[:host])\r
- channel = params[:channel].downcase\r
-\r
- autos.each { |rule|\r
- next unless ['all', rule.channel].include?(channel)\r
- autos.delete rule if rule.host == host\r
- }\r
- rescue\r
- error $!\r
- m.reply $!\r
- end\r
- end\r
- @registry[:onjoin] = autos\r
- if count > autos.length\r
- m.okay\r
- else\r
- m.reply "No matching onjoin rule for #{host} found"\r
- end\r
- end\r
-\r
- def add_badword(m, params=nil)\r
- regexp, channel = make_badword_rx(params[:regexp]), params[:channel].downcase.dup\r
- action, timer, reason = params[:action], params[:timer].dup, params[:reason].to_s\r
-\r
- badwords = @registry[:badwords]\r
- badwords << BadWordAction.new(regexp, action, channel, timer, reason)\r
- @registry[:badwords] = badwords\r
-\r
- m.okay\r
- end\r
-\r
- def list_badword(m, params=nil)\r
- m.reply "badword rules: #{@registry[:badwords].length}"\r
-\r
- @registry[:badwords].each_with_index { |badword, idx|\r
- m.reply "\##{idx+1}: #{badword.regexp.source} | #{badword.action} | #{badword.channel} | #{badword.timer} | #{badword.reason}"\r
- }\r
- end\r
-\r
- def rm_badword(m, params=nil)\r
- badwords = @registry[:badwords]\r
- count = badwords.length\r
-\r
- idx = nil\r
- idx = params[:idx].to_i if params[:idx]\r
-\r
- if idx\r
- if idx > count\r
- m.reply "No such badword \##{idx}"\r
- return\r
- end\r
- badwords.delete_at(idx-1)\r
- else\r
- channel = params[:channel].downcase\r
-\r
- regexp = make_badword_rx(params[:regexp])\r
- debug "Trying to remove #{regexp.inspect} from #{badwords.inspect}"\r
-\r
- badwords.each { |badword|\r
- next unless ['all', badword.channel].include?(channel)\r
- debug "Removing #{badword.inspect}" if badword == regexp\r
- badwords.delete(badword) if badword == regexp\r
- }\r
- end\r
-\r
- @registry[:badwords] = badwords\r
- if count > badwords.length\r
- m.okay\r
- else\r
- m.reply "No matching badword #{regexp} found"\r
- end\r
- end\r
-\r
- def add_whitelist(m, params=nil)\r
- begin\r
- host, channel = m.server.new_netmask(params[:host]), params[:channel].downcase\r
-\r
- # TODO check if a whitelist entry for this host already exists\r
- whitelist = @registry[:whitelist]\r
- whitelist << WhitelistEntry.new(host, channel)\r
- @registry[:whitelist] = whitelist\r
-\r
- m.okay\r
- rescue\r
- error $!\r
- m.reply $!\r
- end\r
- end\r
-\r
- def list_whitelist(m, params=nil)\r
- m.reply "whitelist entries: #{@registry[:whitelist].length}"\r
- @registry[:whitelist].each_with_index { |auto, idx|\r
- m.reply "\##{idx+1}: #{auto.host} | #{auto.channel}"\r
- }\r
- end\r
-\r
- def rm_whitelist(m, params=nil)\r
- wl = @registry[:whitelist]\r
- count = wl.length\r
-\r
- idx = nil\r
- idx = params[:idx].to_i if params[:idx]\r
-\r
- if idx\r
- if idx > count\r
- m.reply "No such whitelist entry \##{idx}"\r
- return\r
- end\r
- wl.delete_at(idx-1)\r
- else\r
- begin\r
- host = m.server.new_netmask(params[:host])\r
- channel = params[:channel].downcase\r
-\r
- wl.each { |rule|\r
- next unless ['all', rule.channel].include?(channel)\r
- wl.delete rule if rule.host == host\r
- }\r
- rescue\r
- error $!\r
- m.reply $!\r
- end\r
- end\r
- @registry[:whitelist] = wl\r
- if count > whitelist.length\r
- m.okay\r
- else\r
- m.reply "No host matching #{host}"\r
- end\r
- end\r
-\r
- private\r
- def check_channel(m, strchannel)\r
- begin\r
- raise "must specify channel if using privmsg" if m.private? and not strchannel\r
- channel = m.server.channel(strchannel) || m.target\r
- raise "I am not in that channel" unless channel.has_user?(@bot.nick)\r
-\r
- return channel\r
- rescue\r
- error $!\r
- m.reply $!\r
- end\r
- end\r
-\r
- def do_cmd(action, nick, channel, timer_in=nil, reason=nil)\r
- case timer_in\r
- when nil\r
- timer = 0\r
- when /^(\d+)s$/\r
- timer = $1.to_i\r
- when /^(\d+)m$/\r
- timer = $1.to_i * 60\r
- when /^(\d+)h$/\r
- timer = $1.to_i * 60 * 60 \r
- when /^(\d+)d$/\r
- timer = $1.to_i * 60 * 60 * 24\r
- else\r
- raise "Wrong time specifications"\r
- end\r
-\r
- case action\r
- when :ban\r
- set_mode(channel, "+b", nick)\r
- @bot.timer.add_once(timer) { set_mode(channel, "-b", nick) } if timer > 0\r
- when :unban\r
- set_mode(channel, "-b", nick)\r
- when :kick\r
- do_kick(channel, nick, reason)\r
- when :kickban\r
- set_mode(channel, "+b", nick)\r
- @bot.timer.add_once(timer) { set_mode(channel, "-b", nick) } if timer > 0\r
- do_kick(channel, nick, reason)\r
- when :silence, :quiet\r
- set_mode(channel, "+q", nick)\r
- @bot.timer.add_once(timer) { set_mode(channel, "-q", nick) } if timer > 0\r
- when :unsilence, :unquiet\r
- set_mode(channel, "-q", nick)\r
- end\r
- end\r
-\r
- def set_mode(channel, mode, nick)\r
- host = channel.has_user?(nick) ? "*!*@" + channel.get_user(nick).host : nick\r
- @bot.mode(channel, mode, host)\r
- end\r
-\r
- def do_kick(channel, nick, reason="")\r
- @bot.kick(channel, nick, reason)\r
- end\r
-end\r
-\r
-plugin = BansPlugin.new\r
-\r
-plugin.default_auth( 'act', false )\r
-plugin.default_auth( 'edit', false )\r
-plugin.default_auth( 'list', true )\r
-\r
-plugin.map 'ban :nick :timer :channel', :action => 'ban_user',\r
- :requirements => {:timer => BansPlugin::TimerRe, :channel => BansPlugin::ChannelRe},\r
- :defaults => {:timer => nil, :channel => nil},\r
- :auth_path => 'act'\r
-plugin.map 'unban :nick :channel', :action => 'unban_user',\r
- :requirements => {:channel => BansPlugin::ChannelRe},\r
- :defaults => {:channel => nil},\r
- :auth_path => 'act'\r
-plugin.map 'kick :nick :channel *reason', :action => 'kick_user',\r
- :requirements => {:channel => BansPlugin::ChannelRe},\r
- :defaults => {:channel => nil, :reason => 'requested'},\r
- :auth_path => 'act'\r
-plugin.map 'kickban :nick :timer :channel *reason', :action => 'kickban_user',\r
- :requirements => {:timer => BansPlugin::TimerRe, :channel => BansPlugin::ChannelRe},\r
- :defaults => {:timer => nil, :channel => nil, :reason => 'requested'},\r
- :auth_path => 'act'\r
-plugin.map 'silence :nick :timer :channel', :action => 'silence_user',\r
- :requirements => {:timer => BansPlugin::TimerRe, :channel => BansPlugin::ChannelRe},\r
- :defaults => {:timer => nil, :channel => nil},\r
- :auth_path => 'act'\r
-plugin.map 'unsilence :nick :channel', :action => 'unsilence_user',\r
- :requirements => {:channel => BansPlugin::ChannelRe},\r
- :defaults => {:channel => nil},\r
- :auth_path => 'act'\r
-\r
-plugin.map 'bans add onjoin :host :action :channel *reason', :action => 'add_onjoin',\r
- :requirements => {:action => BansPlugin::ActionRe, :channel => BansPlugin::ChannelAllRe},\r
- :defaults => {:action => 'kickban', :channel => 'all', :reason => 'netmask not welcome'},\r
- :auth_path => 'edit::onjoin'\r
-plugin.map 'bans rm onjoin index :idx', :action => 'rm_onjoin',\r
- :requirements => {:num => BansPlugin::IdxRe},\r
- :auth_path => 'edit::onjoin'\r
-plugin.map 'bans rm onjoin :host :channel', :action => 'rm_onjoin',\r
- :requirements => {:channel => BansPlugin::ChannelAllRe},\r
- :defaults => {:channel => 'all'},\r
- :auth_path => 'edit::onjoin'\r
-plugin.map 'bans list onjoin[s]', :action => 'list_onjoin',\r
- :auth_path => 'list::onjoin'\r
-\r
-plugin.map 'bans add badword :regexp :action :timer :channel *reason', :action => 'add_badword',\r
- :requirements => {:action => BansPlugin::ActionRe, :timer => BansPlugin::TimerRe, :channel => BansPlugin::ChannelAllRe},\r
- :defaults => {:action => 'silence', :timer => "0s", :channel => 'all', :reason => 'bad word'},\r
- :auth_path => 'edit::badword'\r
-plugin.map 'bans rm badword index :idx', :action => 'rm_badword',\r
- :requirements => {:num => BansPlugin::IdxRe},\r
- :auth_path => 'edit::badword'\r
-plugin.map 'bans rm badword :regexp :channel', :action => 'rm_badword',\r
- :requirements => {:channel => BansPlugin::ChannelAllRe},\r
- :defaults => {:channel => 'all'},\r
- :auth_path => 'edit::badword'\r
-plugin.map 'bans list badword[s]', :action => 'list_badword',\r
- :auth_path => 'list::badword'\r
-\r
-plugin.map 'bans add whitelist :host :channel', :action => 'add_whitelist',\r
- :requirements => {:channel => BansPlugin::ChannelAllRe},\r
- :defaults => {:channel => 'all'},\r
- :auth_path => 'edit::whitelist'\r
-plugin.map 'bans rm whitelist index :idx', :action => 'rm_whitelist',\r
- :requirements => {:num => BansPlugin::IdxRe},\r
- :auth_path => 'edit::whitelist'\r
-plugin.map 'bans rm whitelist :host :channel', :action => 'rm_whitelist',\r
- :requirements => {:channel => BansPlugin::ChannelAllRe},\r
- :defaults => {:channel => 'all'},\r
- :auth_path => 'edit::whitelist'\r
-plugin.map 'bans list whitelist', :action => 'list_whitelist',\r
- :auth_path => 'list::whitelist'\r
-\r
+#-- vim:sw=2:et
+#++
+#
+# :title: Bans Plugin v3 for rbot 0.9.11 and later
+#
+# Author:: Marco Gulino <marco@kmobiletools.org>
+# Author:: kamu <mr.kamu@gmail.com>
+# Author:: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>
+#
+# Copyright:: (C) 2006 Marco Gulino
+# Copyright:: (C) 2007 kamu, Giuseppe Bilotta
+#
+# License:: GPL V2.
+#
+# Managing kick and bans, automatically removing bans after timeouts, quiet
+# bans, and kickban/quietban based on regexp
+#
+# v1 -> v2 (kamu's version, never released)
+# * reworked
+# * autoactions triggered on join
+# * action on join or badword can be anything: kick, ban, kickban, quiet
+#
+# v2 -> v3 (GB)
+# * remove the 'bans' prefix from most of the commands
+# * (un)quiet has been renamed to (un)silence because 'quiet' was used to
+# tell the bot to keep quiet
+# * both (un)quiet and (un)silence are accepted as actions
+# * use the more descriptive 'onjoin' term for autoactions
+# * convert v1's (0.9.10) :bans and :bansmasks to BadWordActions and
+# WhitelistEntries
+# * enhanced list manipulation facilities
+# * fixed regexp usage in requirements for plugin map
+# * add proper auth management
+
+define_structure :OnJoinAction, :host, :action, :channel, :reason
+define_structure :BadWordAction, :regexp, :action, :channel, :timer, :reason
+define_structure :WhitelistEntry, :host, :channel
+
+class BansPlugin < Plugin
+
+ IdxRe = /^\d+$/
+ TimerRe = /^\d+[smhd]$/
+ ChannelRe = /^#+[^\s]+$/
+ ChannelAllRe = /^(?:all|#+[^\s]+)$/
+ ActionRe = /(?:ban|kick|kickban|silence|quiet)/
+
+ def name
+ "bans"
+ end
+
+ def make_badword_rx(txt)
+ return /\b(?:#{txt})\b/i
+ end
+
+ def initialize
+ super
+
+ # Convert old BadWordActions, which were simpler and labelled :bans
+ if @registry.has_key? :bans
+ badwords = Array.new
+ bans = @registry[:bans]
+ @registry[:bans].each { |ar|
+ case ar[0]
+ when "quietban"
+ action = :silence
+ when "kickban"
+ action = :kickban
+ else
+ # Shouldn't happen
+ warning "Unknown action in old data #{ar.inspect} -- entry ignored"
+ next
+ end
+ bans.delete(ar)
+ chan = ar[1].downcase
+ regexp = make_badword_rx(ar[2])
+ badwords << BadWordAction.new(regexp, action, chan, "0s", "")
+ }
+ @registry[:badwords] = badwords
+ if bans.length > 0
+ # Store the ones we couldn't convert
+ @registry[:bans] = bans
+ else
+ @registry.delete(:bans)
+ end
+ else
+ @registry[:badwords] = Array.new unless @registry.has_key? :badwords
+ end
+
+ # Convert old WhitelistEntries, which were simpler and labelled :bansmasks
+ if @registry.has_key? :bans
+ wl = Array.new
+ @registry[:bansmasks].each { |mask|
+ badwords << WhitelistEntry.new(mask, "all")
+ }
+ @registry[:whitelist] = wl
+ @registry.delete(:bansmasks)
+ else
+ @registry[:whitelist] = Array.new unless @registry.has_key? :whitelist
+ end
+
+ @registry[:onjoin] = Array.new unless @registry.has_key? :onjoin
+ end
+
+ def help(plugin, topic="")
+ case plugin
+ when "ban"
+ return "ban <nick/hostmask> [Xs/m/h/d] [#channel]: ban a user from the given channel for the given amount of time. default is forever, on the current channel"
+ when "unban"
+ return "unban <nick/hostmask> [#channel]: unban a user from the given channel. defaults to the current channel"
+ when "kick"
+ return "kick <nick> [#channel] [reason ...]: kick a user from the given channel with the given reason. defaults to the current channel, no reason"
+ when "kickban"
+ return "kickban <nick> [Xs/m/h/d] [#channel] [reason ...]: kicks and bans a user from the given channel for the given amount of time, with the given reason. default is forever, on the current channel, with no reason"
+ when "silence"
+ return "silence <nick/hostmask> [Xs/m/h/d] [#channel]: silence a user on the given channel for the given time. default is forever, on the current channel. not all servers support silencing users"
+ when "unsilence"
+ return "unsilence <nick/hostmask> [#channel]: allow the given user to talk on the given channel. defaults to the current channel"
+ when "bans"
+ case topic
+ when "add"
+ return "bans add <onjoin|badword|whitelist>: add an automatic action for people that join or say some bad word, or a whitelist entry. further help available"
+ when "add onjoin"
+ return "bans add onjoin <hostmask> [action] [#channel] [reason ...]: will add an autoaction for any one who joins with hostmask. default action is silence, default channel is all"
+ when "add badword"
+ return "bans add badword <regexp> [action] [Xs/m/h/d] [#channel|all] [reason ...]: adds a badword regexp, if a user sends a message that matches regexp, the action will be invoked. default action is silence, default channel is all"
+ when "add whitelist"
+ return "bans add whitelist <hostmask> [#channel|all]: add the given hostmask to the whitelist. no autoaction will be triggered by users on the whitelist"
+ when "rm"
+ return "bans rm <onjoin|badword|whitelist> <hostmask/regexp> [#channel], or bans rm <onjoin|badword|whitelist> index <num>: removes the specified onjoin or badword rule or whitelist entry."
+ when "list"
+ return"bans list <onjoin|badword|whitelist>: lists all onjoin or badwords or whitelist entries"
+ end
+ end
+ return "bans <command>: allows a user of the bot to do a range of bans and unbans. commands are: [un]ban, kick[ban], [un]silence, add, rm and list"
+ end
+
+ def listen(m)
+ return unless m.respond_to?(:public?) and m.public?
+ @registry[:whitelist].each { |white|
+ next unless ['all', m.target.downcase].include?(white.channel)
+ return if m.source.matches?(white.host)
+ }
+
+ @registry[:badwords].each { |badword|
+ next unless ['all', m.target.downcase].include?(badword.channel)
+ next unless badword.regexp.match(m.message)
+
+ do_cmd(badword.action.to_sym, m.source.nick, m.target, badword.timer, badword.reason)
+ m.reply "bad word detected! #{badword.action} for #{badword.timer} because: #{badword.reason}"
+ return
+ }
+ end
+
+ def join(m)
+ @registry[:whitelist].each { |white|
+ next unless ['all', m.target.downcase].include?(white.channel)
+ return if m.source.matches?(white.host)
+ }
+
+ @registry[:onjoin].each { |auto|
+ next unless ['all', m.target.downcase].include?(auto.channel)
+ next unless m.source.matches? auto.host
+
+ do_cmd(auto.action.to_sym, m.source.nick, m.target, "0s", auto.reason)
+ return
+ }
+ end
+
+ def ban_user(m, params=nil)
+ nick, channel = params[:nick], check_channel(m, params[:channel])
+ timer = params[:timer]
+ do_cmd(:ban, nick, channel, timer)
+ end
+
+ def unban_user(m, params=nil)
+ nick, channel = params[:nick], check_channel(m, params[:channel])
+ do_cmd(:unban, nick, channel)
+ end
+
+ def kick_user(m, params=nil)
+ nick, channel = params[:nick], check_channel(m, params[:channel])
+ reason = params[:reason].to_s
+ do_cmd(:kick, nick, channel, "0s", reason)
+ end
+
+ def kickban_user(m, params=nil)
+ nick, channel, reason = params[:nick], check_channel(m, params[:channel])
+ timer, reason = params[:timer], params[:reason].to_s
+ do_cmd(:kickban, nick, channel, timer, reason)
+ end
+
+ def silence_user(m, params=nil)
+ nick, channel = params[:nick], check_channel(m, params[:channel])
+ timer = params[:timer]
+ do_cmd(:silence, nick, channel, timer)
+ end
+
+ def unsilence_user(m, params=nil)
+ nick, channel = params[:nick], check_channel(m, params[:channel])
+ do_cmd(:unsilence, nick, channel)
+ end
+
+ def add_onjoin(m, params=nil)
+ begin
+ host, channel = m.server.new_netmask(params[:host]), params[:channel].downcase
+ action, reason = params[:action], params[:reason].to_s
+
+ autos = @registry[:onjoin]
+ autos << OnJoinAction.new(host, action, channel, reason.dup)
+ @registry[:onjoin] = autos
+
+ m.okay
+ rescue
+ error $!
+ m.reply $!
+ end
+ end
+
+ def list_onjoin(m, params=nil)
+ m.reply "onjoin rules: #{@registry[:onjoin].length}"
+ @registry[:onjoin].each_with_index { |auto, idx|
+ m.reply "\##{idx+1}: #{auto.host} | #{auto.action} | #{auto.channel} | '#{auto.reason}'"
+ }
+ end
+
+ def rm_onjoin(m, params=nil)
+ autos = @registry[:onjoin]
+ count = autos.length
+
+ idx = nil
+ idx = params[:idx].to_i if params[:idx]
+
+ if idx
+ if idx > count
+ m.reply "No such onjoin \##{idx}"
+ return
+ end
+ autos.delete_at(idx-1)
+ else
+ begin
+ host = m.server.new_netmask(params[:host])
+ channel = params[:channel].downcase
+
+ autos.each { |rule|
+ next unless ['all', rule.channel].include?(channel)
+ autos.delete rule if rule.host == host
+ }
+ rescue
+ error $!
+ m.reply $!
+ end
+ end
+ @registry[:onjoin] = autos
+ if count > autos.length
+ m.okay
+ else
+ m.reply "No matching onjoin rule for #{host} found"
+ end
+ end
+
+ def add_badword(m, params=nil)
+ regexp, channel = make_badword_rx(params[:regexp]), params[:channel].downcase.dup
+ action, timer, reason = params[:action], params[:timer].dup, params[:reason].to_s
+
+ badwords = @registry[:badwords]
+ badwords << BadWordAction.new(regexp, action, channel, timer, reason)
+ @registry[:badwords] = badwords
+
+ m.okay
+ end
+
+ def list_badword(m, params=nil)
+ m.reply "badword rules: #{@registry[:badwords].length}"
+
+ @registry[:badwords].each_with_index { |badword, idx|
+ m.reply "\##{idx+1}: #{badword.regexp.source} | #{badword.action} | #{badword.channel} | #{badword.timer} | #{badword.reason}"
+ }
+ end
+
+ def rm_badword(m, params=nil)
+ badwords = @registry[:badwords]
+ count = badwords.length
+
+ idx = nil
+ idx = params[:idx].to_i if params[:idx]
+
+ if idx
+ if idx > count
+ m.reply "No such badword \##{idx}"
+ return
+ end
+ badwords.delete_at(idx-1)
+ else
+ channel = params[:channel].downcase
+
+ regexp = make_badword_rx(params[:regexp])
+ debug "Trying to remove #{regexp.inspect} from #{badwords.inspect}"
+
+ badwords.each { |badword|
+ next unless ['all', badword.channel].include?(channel)
+ debug "Removing #{badword.inspect}" if badword == regexp
+ badwords.delete(badword) if badword == regexp
+ }
+ end
+
+ @registry[:badwords] = badwords
+ if count > badwords.length
+ m.okay
+ else
+ m.reply "No matching badword #{regexp} found"
+ end
+ end
+
+ def add_whitelist(m, params=nil)
+ begin
+ host, channel = m.server.new_netmask(params[:host]), params[:channel].downcase
+
+ # TODO check if a whitelist entry for this host already exists
+ whitelist = @registry[:whitelist]
+ whitelist << WhitelistEntry.new(host, channel)
+ @registry[:whitelist] = whitelist
+
+ m.okay
+ rescue
+ error $!
+ m.reply $!
+ end
+ end
+
+ def list_whitelist(m, params=nil)
+ m.reply "whitelist entries: #{@registry[:whitelist].length}"
+ @registry[:whitelist].each_with_index { |auto, idx|
+ m.reply "\##{idx+1}: #{auto.host} | #{auto.channel}"
+ }
+ end
+
+ def rm_whitelist(m, params=nil)
+ wl = @registry[:whitelist]
+ count = wl.length
+
+ idx = nil
+ idx = params[:idx].to_i if params[:idx]
+
+ if idx
+ if idx > count
+ m.reply "No such whitelist entry \##{idx}"
+ return
+ end
+ wl.delete_at(idx-1)
+ else
+ begin
+ host = m.server.new_netmask(params[:host])
+ channel = params[:channel].downcase
+
+ wl.each { |rule|
+ next unless ['all', rule.channel].include?(channel)
+ wl.delete rule if rule.host == host
+ }
+ rescue
+ error $!
+ m.reply $!
+ end
+ end
+ @registry[:whitelist] = wl
+ if count > whitelist.length
+ m.okay
+ else
+ m.reply "No host matching #{host}"
+ end
+ end
+
+ private
+ def check_channel(m, strchannel)
+ begin
+ raise "must specify channel if using privmsg" if m.private? and not strchannel
+ channel = m.server.channel(strchannel) || m.target
+ raise "I am not in that channel" unless channel.has_user?(@bot.nick)
+
+ return channel
+ rescue
+ error $!
+ m.reply $!
+ end
+ end
+
+ def do_cmd(action, nick, channel, timer_in=nil, reason=nil)
+ case timer_in
+ when nil
+ timer = 0
+ when /^(\d+)s$/
+ timer = $1.to_i
+ when /^(\d+)m$/
+ timer = $1.to_i * 60
+ when /^(\d+)h$/
+ timer = $1.to_i * 60 * 60
+ when /^(\d+)d$/
+ timer = $1.to_i * 60 * 60 * 24
+ else
+ raise "Wrong time specifications"
+ end
+
+ case action
+ when :ban
+ set_mode(channel, "+b", nick)
+ @bot.timer.add_once(timer) { set_mode(channel, "-b", nick) } if timer > 0
+ when :unban
+ set_mode(channel, "-b", nick)
+ when :kick
+ do_kick(channel, nick, reason)
+ when :kickban
+ set_mode(channel, "+b", nick)
+ @bot.timer.add_once(timer) { set_mode(channel, "-b", nick) } if timer > 0
+ do_kick(channel, nick, reason)
+ when :silence, :quiet
+ set_mode(channel, "+q", nick)
+ @bot.timer.add_once(timer) { set_mode(channel, "-q", nick) } if timer > 0
+ when :unsilence, :unquiet
+ set_mode(channel, "-q", nick)
+ end
+ end
+
+ def set_mode(channel, mode, nick)
+ host = channel.has_user?(nick) ? "*!*@" + channel.get_user(nick).host : nick
+ @bot.mode(channel, mode, host)
+ end
+
+ def do_kick(channel, nick, reason="")
+ @bot.kick(channel, nick, reason)
+ end
+end
+
+plugin = BansPlugin.new
+
+plugin.default_auth( 'act', false )
+plugin.default_auth( 'edit', false )
+plugin.default_auth( 'list', true )
+
+plugin.map 'ban :nick :timer :channel', :action => 'ban_user',
+ :requirements => {:timer => BansPlugin::TimerRe, :channel => BansPlugin::ChannelRe},
+ :defaults => {:timer => nil, :channel => nil},
+ :auth_path => 'act'
+plugin.map 'unban :nick :channel', :action => 'unban_user',
+ :requirements => {:channel => BansPlugin::ChannelRe},
+ :defaults => {:channel => nil},
+ :auth_path => 'act'
+plugin.map 'kick :nick :channel *reason', :action => 'kick_user',
+ :requirements => {:channel => BansPlugin::ChannelRe},
+ :defaults => {:channel => nil, :reason => 'requested'},
+ :auth_path => 'act'
+plugin.map 'kickban :nick :timer :channel *reason', :action => 'kickban_user',
+ :requirements => {:timer => BansPlugin::TimerRe, :channel => BansPlugin::ChannelRe},
+ :defaults => {:timer => nil, :channel => nil, :reason => 'requested'},
+ :auth_path => 'act'
+plugin.map 'silence :nick :timer :channel', :action => 'silence_user',
+ :requirements => {:timer => BansPlugin::TimerRe, :channel => BansPlugin::ChannelRe},
+ :defaults => {:timer => nil, :channel => nil},
+ :auth_path => 'act'
+plugin.map 'unsilence :nick :channel', :action => 'unsilence_user',
+ :requirements => {:channel => BansPlugin::ChannelRe},
+ :defaults => {:channel => nil},
+ :auth_path => 'act'
+
+plugin.map 'bans add onjoin :host :action :channel *reason', :action => 'add_onjoin',
+ :requirements => {:action => BansPlugin::ActionRe, :channel => BansPlugin::ChannelAllRe},
+ :defaults => {:action => 'kickban', :channel => 'all', :reason => 'netmask not welcome'},
+ :auth_path => 'edit::onjoin'
+plugin.map 'bans rm onjoin index :idx', :action => 'rm_onjoin',
+ :requirements => {:num => BansPlugin::IdxRe},
+ :auth_path => 'edit::onjoin'
+plugin.map 'bans rm onjoin :host :channel', :action => 'rm_onjoin',
+ :requirements => {:channel => BansPlugin::ChannelAllRe},
+ :defaults => {:channel => 'all'},
+ :auth_path => 'edit::onjoin'
+plugin.map 'bans list onjoin[s]', :action => 'list_onjoin',
+ :auth_path => 'list::onjoin'
+
+plugin.map 'bans add badword :regexp :action :timer :channel *reason', :action => 'add_badword',
+ :requirements => {:action => BansPlugin::ActionRe, :timer => BansPlugin::TimerRe, :channel => BansPlugin::ChannelAllRe},
+ :defaults => {:action => 'silence', :timer => "0s", :channel => 'all', :reason => 'bad word'},
+ :auth_path => 'edit::badword'
+plugin.map 'bans rm badword index :idx', :action => 'rm_badword',
+ :requirements => {:num => BansPlugin::IdxRe},
+ :auth_path => 'edit::badword'
+plugin.map 'bans rm badword :regexp :channel', :action => 'rm_badword',
+ :requirements => {:channel => BansPlugin::ChannelAllRe},
+ :defaults => {:channel => 'all'},
+ :auth_path => 'edit::badword'
+plugin.map 'bans list badword[s]', :action => 'list_badword',
+ :auth_path => 'list::badword'
+
+plugin.map 'bans add whitelist :host :channel', :action => 'add_whitelist',
+ :requirements => {:channel => BansPlugin::ChannelAllRe},
+ :defaults => {:channel => 'all'},
+ :auth_path => 'edit::whitelist'
+plugin.map 'bans rm whitelist index :idx', :action => 'rm_whitelist',
+ :requirements => {:num => BansPlugin::IdxRe},
+ :auth_path => 'edit::whitelist'
+plugin.map 'bans rm whitelist :host :channel', :action => 'rm_whitelist',
+ :requirements => {:channel => BansPlugin::ChannelAllRe},
+ :defaults => {:channel => 'all'},
+ :auth_path => 'edit::whitelist'
+plugin.map 'bans list whitelist', :action => 'list_whitelist',
+ :auth_path => 'list::whitelist'
+