From 6353236f1e13aa522325f742d64da5fa7067ec44 Mon Sep 17 00:00:00 2001 From: NeodarZ Date: Tue, 28 Feb 2017 14:12:19 +0100 Subject: Add my fucking weechat theme --- weechat/python/clone_scanner.py | 514 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 514 insertions(+) create mode 100644 weechat/python/clone_scanner.py (limited to 'weechat/python/clone_scanner.py') diff --git a/weechat/python/clone_scanner.py b/weechat/python/clone_scanner.py new file mode 100644 index 0000000..e8205c2 --- /dev/null +++ b/weechat/python/clone_scanner.py @@ -0,0 +1,514 @@ +# -*- coding: utf-8 -*- +# +# Clone Scanner, version 1.3 for WeeChat version 0.3 +# Latest development version: https://github.com/FiXato/weechat_scripts +# +# A Clone Scanner that can manually scan channels and +# automatically scans joins for users on the channel +# with multiple nicknames from the same host. +# +# Upon join by a user, the user's host is compared to the infolist of +# already connected users to see if they are already online from +# another nickname. If the user is a clone, it will report it. +# With the '/clone_scanner scan' command you can manually scan a chan. +# +# See /set plugins.var.python.clone_scanner.* for all possible options +# Use the brilliant iset.pl plugin (/weeget install iset) to see what they do +# Or check the sourcecode below. +# +# Example output for an on-join scan result: +# 21:32:46 ▬▬▶ FiXato_Odie (FiXato@FiXato.net) has joined #lounge +# 21:32:46 FiXato_Odie is already on the channel as FiXato!FiXato@FiXato.Net and FiX!FiXaphone@FiXato.net +# +# Example output for a manual scan: +# 21:34:44 fixato.net is online from 3 nicks: +# 21:34:44 - FiXato!FiXato@FiXato.Net +# 21:34:44 - FiX!FiXaphone@FiXato.net +# 21:34:44 - FiXato_Odie!FiXato@FiXato.net +# +## History: +### 2011-09-11: FiXato: +# +# * version 0.1: initial release. +# * Added an on-join clone scan. Any user that joins a channel will be +# matched against users already on the channel. +# +# * version 0.2: manual clone scan +# * Added a manual clone scan via /clone_scanner scan +# you can specify a target channel with: +# /clone_scanner scan #myChannelOnCurrentServer +# or: +# /clone_scanner scan Freenode.#myChanOnSpecifiedNetwork +# * Added completion +# +### 2011-09-12: FiXato: +# +# * version 0.3: Refactor galore +# * Refactored some code. Codebase should be DRYer and clearer now. +# * Manual scan report lists by host instead of nick now. +# * Case-insensitive host-matching +# * Bugfixed the infolist memleak. +# * on-join scanner works again +# * Output examples added to the comments +# +### 2011-09-19 +# * version 0.4: Option galore +# * Case-insensitive buffer lookup fix. +# * Made most messages optional through settings. +# * Made on-join alert and clone report key a bit more configurable. +# * Added formatting options for on-join alerts. +# * Added format_message helper method that accepts multiple whitespace-separated weechat.color() options. +# * Added formatting options for join messages +# * Added formatting options for clone reports +# * Added format_from_config helper method that reads the given formatting key from the config +# +# * version 0.5: cs_buffer refactoring +# * dropping the manual cs_create_buffer call in favor for a cs_get_buffer() method +# +### 2012-02-10: FiXato: +# +# * version 0.6: Stop shoving that buffer in my face! +# * The clone_scanner buffer should no longer pop up by itself when you load the script. +# It should only pop up now when you actually a line needs to show up in the buffer. +# +# * version 0.7: .. but please pop it up in my current window when I ask for it +# * Added setting plugins.var.python.clone_scanner.autofocus +# This will autofocus the clone_scanner buffer in the current window if another window isn't +# already showing it, and of course only when the clone_scanner buffer is triggered +# +### 2012-02-10: FiXato: +# +# * version 0.8: .. and only when it is first created.. +# * Prevents the buffer from being focused every time there is activity in it and not being shown in a window. +# +### 2012-04-01: FiXato: +# +# * version 0.9: Hurrah for bouncers... +# * Added the option plugins.var.python.clone_scanner.compare_idents +# Set it to 'on' if you don't want people with different idents to be marked as clones. +# Useful on channels with bouncers. +# +### 2012-04-02: FiXato: +# +# * version 1.0: Bugfix +# * Fixed the on-join scanner bug introduced by the 0.9 release. +# I was not properly comparing the new ident@host.name key in all places yet. +# Should really have tested this better >< +# +### 2012-04-03: FiXato: +# +# * version 1.1: Stop being so sensitive! +# * Continuing to fix the on-join scanner bugs introduced by the 0.9 release. +# The ident@host.name dict key wasn't being lowercased for comparison in the on-join scan. +# +# * version 1.2: So shameless! +# * Added shameless advertising for my script through /clone_scanner advertise +# +### 2013-04-09: FiXato: +# * version 1.3: Such a killer rabbit +# * Thanks to Curtis Sorensen aka killerrabbit clone_scanner.py now supports: +# * local channels (&-prefixed) +# * nameless channels (just # or &) +# +### 2014-12-07: FiXato: +# * version 1.4: Inefficiency Warning Patch +# WARNING! I recently noticed the clone_scanner script is currently rather inefficient, and requires a rewrite. +# It may cause nasty lag when there are a lot of concurrent joins on the channel, as it evaluates the nicklist on every join. +# For servers like twitch.tv and bitlbee, you might want to exclude the server with the new setting: +# /set plugins.var.python.clone_scanner.hooks.excluded_servers twitchtv,bitlbee +# This script update is an emergency update to add the above option, and warn the users of this script. +# You can disable this warning with: /set plugins.var.python.clone_scanner.lag_warning off +# +# * Other patches in this version include: +# * Re-did how settings are handled, using nils_2's skeleton code +# * Settings are now automatically memoized when changed +# * Added options hooks.excluded_servers, hooks.explicit_servers and lag_warning +# * Updated advertise option to include /script install clone_scanner.py +# * Updated min version to 0.3.6, though this will prob change in the next version +# +## Acknowledgements: +# * Sebastien "Flashcode" Helleu, for developing the kick-ass chat/IRC +# client WeeChat +# * ArZa, whose kickban.pl script helped me get started with using the +# infolist results. +# * LayBot, for requesting the ident comparison +# * Curtis "killerrabbit" Sorensen, for sending in two pull-requests, +# adding support for local and nameless channels. +# * nils_2 aka weechatter, for providing the excellent skeleton.py script +# +## TODO: +# - REWRITE TO IMPROVE EFFICIENCY: +# - Probably only do the infolist loop on self-join, +# and from then on manually keep track of join/parts/quit/nick-changes +# - Add option to enable/disable public clone reporting aka msg channels +# - Add option to enable/disable scanning on certain channels +# - Add cross-channel clone scan +# - Add cross-server clone scan +# +## Copyright (c) 2011-2014 Filip H.F. "FiXato" Slagter, +# +# 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 = "clone_scanner" +SCRIPT_AUTHOR = "Filip H.F. 'FiXato' Slagter " +SCRIPT_VERSION = "1.4" +SCRIPT_LICENSE = "MIT" +SCRIPT_DESC = "A Clone Scanner that can manually scan channels and automatically scans joins for users on the channel with multiple nicknames from the same host." +SCRIPT_COMMAND = "clone_scanner" +SCRIPT_CLOSE_CB = "cs_close_cb" + +import_ok = True + +try: + import weechat +except ImportError: + print "This script must be run under WeeChat." + import_ok = False + +import re +cs_buffer = None +OPTIONS = { + "autofocus": ("on", "Focus the clone_scanner buffer in the current window if it isn't already displayed by a window."), + "compare_idents": ("off", "Match against ident@host.name instead of just the hostname. Useful if you don't want different people from bouncers marked as clones"), + "display_join_messages": ("off", "Display all joins in the clone_scanner buffer"), + "display_onjoin_alert_clone_buffer": ("on", "Display an on-join clone alert in the clone_scanner buffer"), + "display_onjoin_alert_target_buffer": ("on", "Display an on-join clone alert in the buffer where the clone was detected"), + "display_onjoin_alert_current_buffer": ("off", "Display an on-join clone alert in the current buffer"), + "display_scan_report_clone_buffer": ("on", "Display manual scan reports in the clone buffer"), + "display_scan_report_target_buffer": ("off", "Display manual scan reports in the buffer of the scanned channel"), + "display_scan_report_current_buffer": ("on", "Display manual scan reports in the current buffer"), + + "clone_report_key": ("mask", "Which 'key' to display in the clone report: 'mask' for full hostmasks, or 'nick' for nicks"), + "clone_onjoin_alert_key": ("mask", "Which 'key' to display in the on-join alerts: 'mask' for full hostmasks, or 'nick' for nicks"), + + "colors.onjoin_alert.message": ("red", "The on-join clone alert's message colour. Formats are space separated."), + "colors.onjoin_alert.nick": ("bold red", "The on-join clone alert's nick colour. Formats are space separated. Note: if you have colorize_nicks, this option might not work as expected."), + "colors.onjoin_alert.channel": ("red", "The on-join clone alert's channel colour. Formats are space separated."), + "colors.onjoin_alert.matches": ("bold red", "The on-join clone alert's matches (masks or nicks) colour. Formats are space separated. Note: if you have colorize_nicks, this option might not work as expected."), + + "colors.join_messages.message": ("chat", "The base colour for the join messages."), + "colors.join_messages.nick": ("bold", "The colour for the 'nick'-part of the join messages. Note: if you have colorize_nicks, this option might not always work as expected."), + "colors.join_messages.identhost": ("chat", "The colour for the 'ident@host'-part of the join messages."), + "colors.join_messages.channel": ("bold", "The colour for the 'channel'-part of the join messages."), + + "colors.clone_report.header.message": ("chat", "The colour of the clone report header."), + "colors.clone_report.header.number_of_hosts": ("bold", "The colour of the number of hosts in the clone report header."), + "colors.clone_report.header.channel": ("bold", "The colour of the channel name in the clone report header."), + + "colors.clone_report.subheader.message": ("chat", "The colour of the clone report subheader."), + "colors.clone_report.subheader.host": ("bold", "The colour of the host in the clone report subheader."), + "colors.clone_report.subheader.number_of_clones": ("bold", "The colour of the number of clones in the clone report subheader."), + + "colors.clone_report.clone.message": ("chat", "The colour of the clone hit in the clone report message."), + "colors.clone_report.clone.match": ("chat", "The colour of the match details (masks or nicks) in the clone report."), + + "colors.mask.nick": ("bold", "The formatting of the nick in the match mask."), + "colors.mask.identhost": ("", "The formatting of the identhost in the match mask."), + "hooks.explicit_servers": ("*", "Comma-separated, wildcard-supporting list of servers for which we should add hook to for monitoring clones. E.g. 'freenode,chat4all,esper*' or '*' (default)"), + "hooks.excluded_servers": ("bitlbee,twitchtv", "Which servers should the hook *not* be valid for? There's no support for wildcards unfortunately. E.g.: 'bitlbee,twitchtv' to exclude servers named bitlbee and twitchtv (default)."), + "lag_warning": ('on', 'Show temporary warning upon script load regarding the inefficiency of the script. Set to "off" to disable.') +} +hooks = set([]) + +def get_validated_key_from_config(setting): + key = OPTIONS[setting] + if key != 'mask' and key != 'nick': + weechat.prnt("", "Key %s not found. Valid settings are 'nick' and 'mask'. Reverted the setting to 'mask'" % key) + weechat.config_set_plugin("clone_report_key", "mask") + key = "mask" + return key + +def format_message(msg, formats, reset_color='chat'): + if type(formats) == str: + formats = formats.split() + formatted_message = msg + needs_color_reset = False + for format in formats: + if format in ['bold', 'reverse', 'italic', 'underline']: + end_format = '-%s' % format + else: + needs_color_reset = True + end_format = "" + formatted_message = "%s%s%s" % (weechat.color(format), formatted_message, weechat.color(end_format)) + if needs_color_reset: + formatted_message += weechat.color(reset_color) + return formatted_message + +def format_from_config(msg, config_option): + return format_message(msg, OPTIONS[config_option]) + +def on_join_scan_cb(data, signal, signal_data): + network = signal.split(',')[0] + if network in OPTIONS['hooks.excluded_servers'].split(','): + return weechat.WEECHAT_RC_OK + + joined_nick = weechat.info_get("irc_nick_from_host", signal_data) + join_match_data = re.match(':[^!]+!([^@]+@(\S+)) JOIN :?([#&]\S*)', signal_data) + parsed_ident_host = join_match_data.group(1).lower() + parsed_host = join_match_data.group(2).lower() + if OPTIONS["compare_idents"] == "on": + hostkey = parsed_ident_host + else: + hostkey = parsed_host + + chan_name = join_match_data.group(3) + network_chan_name = "%s.%s" % (network, chan_name) + chan_buffer = weechat.info_get("irc_buffer", "%s,%s" % (network, chan_name)) + if not chan_buffer: + print "No IRC channel buffer found for %s" % network_chan_name + return weechat.WEECHAT_RC_OK + + if OPTIONS["display_join_messages"] == "on": + message = "%s%s%s%s%s" % ( + format_from_config(joined_nick, "colors.join_messages.nick"), + format_from_config("!", "colors.join_messages.message"), + format_from_config(parsed_ident_host, "colors.join_messages.identhost"), + format_from_config(" JOINed ", "colors.join_messages.message"), + format_from_config(network_chan_name, "colors.join_messages.channel"), + ) + #Make sure message format is also applied if no formatting is given for nick + message = format_from_config(message, "colors.join_messages.message") + weechat.prnt(cs_get_buffer(), message) + + clones = get_clones_for_buffer("%s,%s" % (network, chan_name), hostkey) + if clones: + key = get_validated_key_from_config("clone_onjoin_alert_key") + + filtered_clones = filter(lambda clone: clone['nick'] != joined_nick, clones[hostkey]) + match_strings = map(lambda m: format_from_config(m[key], "colors.onjoin_alert.matches"), filtered_clones) + + join_string = format_from_config(' and ',"colors.onjoin_alert.message") + masks = join_string.join(match_strings) + message = "%s %s %s %s %s" % ( + format_from_config(joined_nick, "colors.onjoin_alert.nick"), + format_from_config("is already on", "colors.onjoin_alert.message"), + format_from_config(network_chan_name, "colors.onjoin_alert.channel"), + format_from_config("as", "colors.onjoin_alert.message"), + masks + ) + message = format_from_config(message, 'colors.onjoin_alert.message') + + if OPTIONS["display_onjoin_alert_clone_buffer"] == "on": + weechat.prnt(cs_get_buffer(),message) + if OPTIONS["display_onjoin_alert_target_buffer"] == "on": + weechat.prnt(chan_buffer, message) + if OPTIONS["display_onjoin_alert_current_buffer"] == "on": + weechat.prnt(weechat.current_buffer(),message) + return weechat.WEECHAT_RC_OK + +def cs_get_buffer(): + global cs_buffer + + if not cs_buffer: + # Sets notify to 0 as this buffer does not need to be in hotlist. + cs_buffer = weechat.buffer_new("clone_scanner", "", \ + "", SCRIPT_CLOSE_CB, "") + weechat.buffer_set(cs_buffer, "title", "Clone Scanner") + weechat.buffer_set(cs_buffer, "notify", "0") + weechat.buffer_set(cs_buffer, "nicklist", "0") + if OPTIONS["autofocus"] == "on": + if not weechat.window_search_with_buffer(cs_buffer): + weechat.command("", "/buffer " + weechat.buffer_get_string(cs_buffer,"name")) + + return cs_buffer + +def cs_close_cb(*kwargs): + """ A callback for buffer closing. """ + global cs_buffer + + #TODO: Ensure the clone_scanner buffer gets closed if its option is set and the script unloads + + cs_buffer = None + return weechat.WEECHAT_RC_OK + + +def get_channel_from_buffer_args(buffer, args): + server_name = weechat.buffer_get_string(buffer, "localvar_server") + channel_name = args + if not channel_name: + channel_name = weechat.buffer_get_string(buffer, "localvar_channel") + + match_data = re.match('\A(irc.)?([^.]+)\.([#&]\S*)\Z', channel_name) + if match_data: + channel_name = match_data.group(3) + server_name = match_data.group(2) + + return server_name, channel_name + +#TODO: track the hosts + nicks ourselves instead of looking up the entire list every join... +def get_clones_for_buffer(infolist_buffer_name, hostname_to_match=None): + matches = {} + infolist = weechat.infolist_get("irc_nick", "", infolist_buffer_name) + while(weechat.infolist_next(infolist)): + ident_hostname = weechat.infolist_string(infolist, "host") + host_matchdata = re.match('([^@]+)@(\S+)', ident_hostname) + if not host_matchdata: + continue + + hostname = host_matchdata.group(2).lower() + ident = host_matchdata.group(1).lower() + if OPTIONS["compare_idents"] == "on": + hostkey = ident_hostname.lower() + else: + hostkey = hostname + + if hostname_to_match and hostname_to_match.lower() != hostkey: + continue + + nick = weechat.infolist_string(infolist, "name") + + matches.setdefault(hostkey,[]).append({ + 'nick': nick, + 'mask': "%s!%s" % ( + format_from_config(nick, "colors.mask.nick"), + format_from_config(ident_hostname, "colors.mask.identhost")), + 'ident': ident, + 'ident_hostname': ident_hostname, + 'hostname': hostname, + }) + weechat.infolist_free(infolist) + + #Select only the results that have more than 1 match for a host + return dict((k, v) for (k, v) in matches.iteritems() if len(v) > 1) + +def report_clones(clones, scanned_buffer_name, target_buffer=None): + # Default to clone_scanner buffer + if not target_buffer: + target_buffer = cs_get_buffer() + + if clones: + clone_report_header = "%s %s %s%s" % ( + format_from_config(len(clones), "colors.clone_report.header.number_of_hosts"), + format_from_config("hosts with clones were found on", "colors.clone_report.header.message"), + format_from_config(scanned_buffer_name, "colors.clone_report.header.channel"), + format_from_config(":", "colors.clone_report.header.message"), + ) + clone_report_header = format_from_config(clone_report_header, "colors.clone_report.header.message") + weechat.prnt(target_buffer, clone_report_header) + + for (host, clones) in clones.iteritems(): + host_message = "%s %s %s %s" % ( + format_from_config(host, "colors.clone_report.subheader.host"), + format_from_config("is online from", "colors.clone_report.subheader.message"), + format_from_config(len(clones), "colors.clone_report.subheader.number_of_clones"), + format_from_config("nicks:", "colors.clone_report.subheader.message"), + ) + host_message = format_from_config(host_message, "colors.clone_report.subheader.message") + weechat.prnt(target_buffer, host_message) + + for user in clones: + key = get_validated_key_from_config("clone_report_key") + clone_message = "%s%s" % (" - ", format_from_config(user[key], "colors.clone_report.clone.match")) + clone_message = format_from_config(clone_message,"colors.clone_report.clone.message") + weechat.prnt(target_buffer, clone_message) + else: + weechat.prnt(target_buffer, "No clones found on %s" % scanned_buffer_name) + +def cs_command_main(data, buffer, args): + if args[0:4] == 'scan': + server_name, channel_name = get_channel_from_buffer_args(buffer, args[5:]) + clones = get_clones_for_buffer('%s,%s' % (server_name, channel_name)) + if OPTIONS["display_scan_report_target_buffer"] == "on": + target_buffer = weechat.info_get("irc_buffer", "%s,%s" % (server_name, channel_name)) + report_clones(clones, '%s.%s' % (server_name, channel_name), target_buffer) + if OPTIONS["display_scan_report_clone_buffer"] == "on": + report_clones(clones, '%s.%s' % (server_name, channel_name)) + if OPTIONS["display_scan_report_current_buffer"] == "on": + report_clones(clones, '%s.%s' % (server_name, channel_name), weechat.current_buffer()) + elif args[0:9] == 'advertise': + weechat.command("", "/input insert /me is using FiXato's CloneScanner v%s for WeeChat. Get the latest version from: https://github.com/FiXato/weechat_scripts/blob/master/clone_scanner.py or /script install clone_scanner.py" % SCRIPT_VERSION) + return weechat.WEECHAT_RC_OK + +def cs_set_default_settings(): + global OPTIONS + + # Set default settings + for option,value in OPTIONS.items(): + if not weechat.config_is_set_plugin(option): + weechat.config_set_plugin(option, value[0]) + OPTIONS[option] = value[0] + else: + OPTIONS[option] = weechat.config_get_plugin(option) + weechat.config_set_desc_plugin(option, '%s (default: "%s")' % (value[1], value[0])) + +def toggle_refresh(pointer, name, value): + global OPTIONS + + config_option = name[len('plugins.var.python.' + SCRIPT_NAME + '.'):] # get optionname + OPTIONS[config_option] = value # save new value + if config_option in ('hooks.excluded_servers', 'hooks.explicit_servers'): + remove_hooks() + add_hooks() + weechat.config_set_plugin(config_option, value) + return weechat.WEECHAT_RC_OK + +def add_hooks(): + global hooks + hooked_servers = OPTIONS['hooks.explicit_servers'].split(',') + for server_name in hooked_servers: + signal = "%s,irc_in2_join" % server_name + # weechat.prnt('', "Adding hook on %s" % signal) + hook = weechat.hook_signal(signal, "on_join_scan_cb", "") + hooks.add(hook) + +def remove_hooks(): + global hooks + for hook in hooks: + weechat.unhook(hook) + hooks = set([]) + +if __name__ == "__main__" and import_ok: + if weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE, SCRIPT_DESC, SCRIPT_CLOSE_CB, ""): + version = weechat.info_get("version_number", "") or 0 + if int(version) >= 0x00030600: + if (not weechat.config_is_set_plugin('lag_warning') or weechat.config_get_plugin('lag_warning') == 'on'): + weechat.prnt('', '%s%sWARNING! This %s script is currently rather inefficient, and requires a rewrite.' % (weechat.prefix('error'), weechat.color('red'), SCRIPT_NAME)) + weechat.prnt('', '%s It may cause nasty lag when there are a lot of concurrent joins on the channel, as it evaluates the nicklist on every join.' % weechat.prefix('notice')) + weechat.prnt('', '%s For servers like twitch.tv and bitlbee, you might want to exclude the server with the new setting:' % weechat.prefix('notice')) + weechat.prnt('', '%s %s /set plugins.var.python.clone_scanner.hooks.excluded_servers twitchtv,bitlbee' % (weechat.prefix("notice"), weechat.color('*white'))) + weechat.prnt('', '%s This script update is an emergency update to add the above option, and warn the users of this script.' % weechat.prefix("notice")) + weechat.prnt('', '%s You can disable this warning with:%s /set plugins.var.python.clone_scanner.lag_warning off' % (weechat.prefix("notice"), weechat.color('*white'))) + + cs_set_default_settings() + cs_buffer = weechat.buffer_search("python", "clone_scanner") + + weechat.hook_config( 'plugins.var.python.%s.*' % SCRIPT_NAME, 'toggle_refresh', '' ) + add_hooks() + + weechat.hook_command(SCRIPT_COMMAND, + SCRIPT_DESC, + "[scan] [[plugin.][network.]channel] | [advertise] | [help]", + "the target_buffer can be: \n" + "- left out, so the current channel buffer will be scanned.\n" + "- a plain channel name, such as #weechat, in which case it will prefixed with the current network name\n" + "- a channel name prefixed with network name, such as Freenode.#weechat\n" + "- a channel name prefixed with plugin and network name, such as irc.freenode.#weechat\n" + "See /set plugins.var.python.clone_scanner.* for all possible configuration options", + + " || scan %(buffers_names)" + " || advertise" + " || help", + + "cs_command_main", "") + else: + weechat.prnt("","%s%s %s" % (weechat.prefix("error"),SCRIPT_NAME,": needs version 0.3.6 or higher")) + weechat.command("","/wait 1ms /python unload %s" % SCRIPT_NAME) -- cgit v1.2.1