diff options
| author | Ben Beltran <ben@nsovocal.com> | 2012-10-20 13:14:07 -0500 |
|---|---|---|
| committer | Ben Beltran <ben@nsovocal.com> | 2012-10-20 13:14:07 -0500 |
| commit | f853d479d6e699499bee610ea8584b7e09f89cb3 (patch) | |
| tree | 333b35315d7094477262214041d51f258e10a1ce /weechat/python | |
| parent | ee6d2b11353c28d428b287752c0079f5ec407061 (diff) | |
Add weechat, ack, git and nethack
Diffstat (limited to 'weechat/python')
| l--------- | weechat/python/autoload/screen_away.py | 1 | ||||
| l--------- | weechat/python/autoload/upside_down.py | 1 | ||||
| -rw-r--r-- | weechat/python/autoload/weeget.py | 980 | ||||
| -rw-r--r-- | weechat/python/screen_away.py | 151 | ||||
| -rw-r--r-- | weechat/python/upside_down.py | 130 |
5 files changed, 1263 insertions, 0 deletions
diff --git a/weechat/python/autoload/screen_away.py b/weechat/python/autoload/screen_away.py new file mode 120000 index 0000000..e485b70 --- /dev/null +++ b/weechat/python/autoload/screen_away.py @@ -0,0 +1 @@ +../screen_away.py
\ No newline at end of file diff --git a/weechat/python/autoload/upside_down.py b/weechat/python/autoload/upside_down.py new file mode 120000 index 0000000..fb007ad --- /dev/null +++ b/weechat/python/autoload/upside_down.py @@ -0,0 +1 @@ +../upside_down.py
\ No newline at end of file diff --git a/weechat/python/autoload/weeget.py b/weechat/python/autoload/weeget.py new file mode 100644 index 0000000..8622ef6 --- /dev/null +++ b/weechat/python/autoload/weeget.py @@ -0,0 +1,980 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2009-2012 Sebastien Helleu <flashcode@flashtux.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 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/>. +# + +# +# WeeChat scripts manager. +# (this script requires WeeChat >= 0.3.0 and python >= 2.6) +# +# History: +# +# 2012-03-09, Sebastien Helleu <flashcode@flashtux.org>: +# version 1.8: fix reload of config file +# 2012-02-27, Sebastien Helleu <flashcode@flashtux.org>: +# version 1.7: add support of scheme scripts +# 2012-02-05, Sebastien Helleu <flashcode@flashtux.org>: +# version 1.6: use URL transfer from API (for WeeChat >= 0.3.7) +# 2012-01-03, Sebastien Helleu <flashcode@flashtux.org>: +# version 1.5: make script compatible with Python 3.x +# 2011-03-25, Sebastien Helleu <flashcode@flashtux.org>: +# version 1.4: add completion with installed scripts for action "remove" +# 2011-03-10, Sebastien Helleu <flashcode@flashtux.org>: +# version 1.3: add script extension in script name completion and a new +# completion with tags for actions "list" and "listinstalled" +# 2011-02-13, Sebastien Helleu <flashcode@flashtux.org>: +# version 1.2: use new help format for command arguments +# 2010-11-08, Sebastien Helleu <flashcode@flashtux.org>: +# version 1.1: get python 2.x binary for hook_process (fix problem +# when python 3.x is default python version, requires +# WeeChat >= 0.3.4) +# 2010-02-22, Blake Winton <bwinton@latte.ca>: +# version 1.0: add action "listinstalled" for command /weeget +# 2010-01-25, Sebastien Helleu <flashcode@flashtux.org>: +# version 0.9: fix "running" status of scripts with /weeget check +# 2009-09-30, Sebastien Helleu <flashcode@flashtux.org>: +# version 0.8: fix bugs and add missing info in "/weeget show", +# display warning if url for plugins.xml.gz is old site +# 2009-09-07, Sebastien Helleu <flashcode@flashtux.org>: +# version 0.7: update weechat site with new URL +# 2009-05-02, Sebastien Helleu <flashcode@flashtux.org>: +# version 0.6: sync with last API changes +# 2009-04-15, Sebastien Helleu <flashcode@flashtux.org>: +# version 0.5: display missing module(s) when import failed +# 2009-04-11, Sebastien Helleu <flashcode@flashtux.org>: +# version 0.4: use new completion for command arguments +# 2009-04-07, Sebastien Helleu <flashcode@flashtux.org>: +# version 0.3: fix bug with install/upgrade when weeget is updated with +# other scripts: ensure that weeget is always the last +# installed script +# 2009-04-07, Sebastien Helleu <flashcode@flashtux.org>: +# version 0.2: add author's mail in script description +# 2009-04-05, Sebastien Helleu <flashcode@flashtux.org>: +# version 0.1: initial release +# + +SCRIPT_NAME = "weeget" +SCRIPT_AUTHOR = "Sebastien Helleu <flashcode@flashtux.org>" +SCRIPT_VERSION = "1.8" +SCRIPT_LICENSE = "GPL3" +SCRIPT_DESC = "WeeChat scripts manager" + +SCRIPT_COMMAND = "weeget" + +import_ok = True + +try: + import weechat +except ImportError: + print("This script must be run under WeeChat.") + print("Get WeeChat now at: http://www.weechat.org/") + import_ok = False + +try: + import sys, os, stat, time, gzip, hashlib, xml.dom.minidom +except ImportError as message: + print("Missing package(s) for %s: %s" % (SCRIPT_NAME, message)) + import_ok = False + +CONFIG_FILE_NAME = "wg" + +SCRIPT_EXTENSION = { + "perl" : "pl", + "python": "py", + "ruby" : "rb", + "lua" : "lua", + "tcl" : "tcl", + "guile" : "scm", +} + +# timeout for download of plugins.xml.gz +TIMEOUT_UPDATE = 60 * 1000 + +# timeout for download of a script +TIMEOUT_SCRIPT = 60 * 1000 + +# config file and options +wg_config_file = "" +wg_config_option = {} + +# action (install, remove, ..) and arguments +wg_action = "" +wg_action_args = "" + +# loaded scripts +wg_loaded_scripts = {} + +# hook process and stdout +wg_hook_process = { "update": "", "script": "" } +wg_stdout = { "update": "", "script": "" } + +# scripts read from plugins.xml.gz +wg_scripts = {} + +# list of script to install, and script currently installing +wg_scripts_to_install = [] +wg_current_script_install = {} + +# =================================[ config ]================================= + +def wg_config_init(): + """ + Initialization of configuration file. + Sections: color, scripts. + """ + global wg_config_file, wg_config_option + wg_config_file = weechat.config_new(CONFIG_FILE_NAME, + "wg_config_reload_cb", "") + if wg_config_file == "": + return + + # section "color" + section_color = weechat.config_new_section( + wg_config_file, "color", 0, 0, "", "", "", "", "", "", "", "", "", "") + if section_color == "": + weechat.config_free(wg_config_file) + return + wg_config_option["color_script"] = weechat.config_new_option( + wg_config_file, section_color, + "script", "color", "Color for script names", "", 0, 0, + "cyan", "cyan", 0, "", "", "", "", "", "") + wg_config_option["color_installed"] = weechat.config_new_option( + wg_config_file, section_color, + "installed", "color", "Color for \"installed\" indicator", "", 0, 0, + "yellow", "yellow", 0, "", "", "", "", "", "") + wg_config_option["color_running"] = weechat.config_new_option( + wg_config_file, section_color, + "running", "color", "Color for \"running\" indicator", "", 0, 0, + "lightgreen", "lightgreen", 0, "", "", "", "", "", "") + wg_config_option["color_obsolete"] = weechat.config_new_option( + wg_config_file, section_color, + "obsolete", "color", "Color for \"obsolete\" indicator", "", 0, 0, + "lightmagenta", "lightmagenta", 0, "", "", "", "", "", "") + wg_config_option["color_unknown"] = weechat.config_new_option( + wg_config_file, section_color, + "unknown", "color", "Color for \"unknown status\" indicator", "", 0, 0, + "lightred", "lightred", 0, "", "", "", "", "", "") + wg_config_option["color_language"] = weechat.config_new_option( + wg_config_file, section_color, + "language", "color", "Color for language names", "", 0, 0, + "lightblue", "lightblue", 0, "", "", "", "", "", "") + + # section "scripts" + section_scripts = weechat.config_new_section( + wg_config_file, "scripts", 0, 0, "", "", "", "", "", "", "", "", "", "") + if section_scripts == "": + weechat.config_free(wg_config_file) + return + wg_config_option["scripts_url"] = weechat.config_new_option( + wg_config_file, section_scripts, + "url", "string", "URL for file with list of plugins", "", 0, 0, + "http://www.weechat.org/files/plugins.xml.gz", + "http://www.weechat.org/files/plugins.xml.gz", 0, "", "", "", "", "", "") + wg_config_option["scripts_dir"] = weechat.config_new_option( + wg_config_file, section_scripts, + "dir", "string", "Local cache directory for" + SCRIPT_NAME, "", 0, 0, + "%h/" + SCRIPT_NAME, "%h/" + SCRIPT_NAME, 0, "", "", "", "", "", "") + wg_config_option["scripts_cache_expire"] = weechat.config_new_option( + wg_config_file, section_scripts, + "cache_expire", "integer", "Local cache expiration time, in minutes " + "(-1 = never expires, 0 = always expires)", "", + -1, 60*24*365, "60", "60", 0, "", "", "", "", "", "") + +def wg_config_reload_cb(data, config_file): + """ Reload configuration file. """ + return weechat.config_reload(config_file) + +def wg_config_read(): + """ Read configuration file. """ + global wg_config_file + return weechat.config_read(wg_config_file) + +def wg_config_write(): + """ Write configuration file. """ + global wg_config_file + return weechat.config_write(wg_config_file) + +def wg_config_color(color): + """ Get a color from configuration. """ + global wg_config_option + option = wg_config_option.get("color_" + color, "") + if option == "": + return "" + return weechat.color(weechat.config_string(option)) + +def wg_config_get_dir(): + """ Return weeget directory, with expanded WeeChat home dir. """ + global wg_config_option + return weechat.config_string( + wg_config_option["scripts_dir"]).replace("%h", + weechat.info_get("weechat_dir", "")) + +def wg_config_create_dir(): + """ Create weeget directory. """ + dir = wg_config_get_dir() + if not os.path.isdir(dir): + os.makedirs(dir, mode=0o700) + +def wg_config_get_cache_filename(): + """ Get local cache filename, based on URL. """ + global wg_config_option + return wg_config_get_dir() + os.sep + \ + os.path.basename(weechat.config_string(wg_config_option["scripts_url"])) + +# =============================[ download file ]============================== + +def wg_download_file(url, filename, timeout, callback, callback_data): + """Download a file with an URL. Return hook_process created.""" + version = weechat.info_get("version_number", "") or 0 + if int(version) >= 0x00030700: + return weechat.hook_process_hashtable("url:%s" % url, + { "file_out": filename }, + timeout, + callback, callback_data) + else: + script = [ "import sys", + "try:", + " if sys.version_info >= (3,):", + " import urllib.request", + " response = urllib.request.urlopen('%s')" % url, + " else:", + " import urllib2", + " response = urllib2.urlopen(urllib2.Request('%s'))" % url, + " f = open('%s', 'wb')" % filename, + " f.write(response.read())", + " response.close()", + " f.close()", + "except Exception as e:", + " print('error:' + str(e))" ] + return weechat.hook_process("python -c \"%s\"" % "\n".join(script), + timeout, + callback, callback_data) + +# ================================[ scripts ]================================= + +def wg_search_script_by_name(name): + """ + Search a script in list by name. + Name can be short name ('weeget') or full name ('weeget.py'). + """ + global wg_scripts + for id, script in wg_scripts.items(): + if script["name"] == name or script["full_name"] == name: + return script + return None + +def wg_get_loaded_scripts(): + """ + Get python dictionary with loaded scripts. + Keys are filenames and values are path to script, for example: + 'weeget.py': '/home/xxx/.weechat/python/weeget.py' + """ + global wg_loaded_scripts + wg_loaded_scripts = {} + for language in SCRIPT_EXTENSION.keys(): + infolist = weechat.infolist_get(language + "_script", "", "") + while weechat.infolist_next(infolist): + filename = weechat.infolist_string(infolist, "filename") + if filename != "": + wg_loaded_scripts[os.path.basename(filename)] = filename + weechat.infolist_free(infolist) + +def wg_is_local_script_loaded(filename): + """ Check if a script filename (like 'python/weeget.py') is loaded. """ + global wg_loaded_scripts + filename2 = filename + if filename2.startswith("autoload/"): + filename2 = filename2[9:] + for name, path in wg_loaded_scripts.items(): + if path.endswith(filename) or path.endswith(filename2): + return True + return False + +def wg_get_local_script_status(script): + """ + Check if a script is installed. + 'script' is a dictionary retrieved from scripts xml list. + """ + global wg_loaded_scripts + status = { "installed": "", "obsolete": "", "running": "" } + local_dir = weechat.info_get("weechat_dir", "") + os.sep + script["language"] + local_name = local_dir + os.sep + "autoload" + os.sep + script["full_name"] + if not os.path.isfile(local_name): + local_name = local_dir + os.sep + script["full_name"] + if os.path.isfile(local_name): + status["installed"] = "1" + f = open(local_name, "rb") + md5 = hashlib.md5() + md5.update(f.read()) + f.close() + local_md5 = md5.hexdigest() + if local_md5 != script["md5sum"]: + status["obsolete"] = "1" + if script["full_name"] in wg_loaded_scripts.keys(): + status["running"] = "1" + return status + +def wg_get_local_scripts(): + """ + Get list of all local scripts (in languages and autoload dirs). + Return a dictionary with language as key and list of paths as value, + with autoloaded scripts at beginning of list, for example: + { 'perl': [ 'autoload/buffers.pl', + 'autoload/weetris.pl', + 'beep.pl', + 'launcher.pl' ], + 'python': [ 'autoload/weeget.py', + 'go.py', + 'vdm.py' ] + } + """ + files = {} + for language in SCRIPT_EXTENSION.keys(): + files[language] = [] + autoloaded_files = [] + rootdir = weechat.info_get("weechat_dir", "") + os.sep + language + for root, dirs, listfiles in os.walk(rootdir): + if root == rootdir: + files[language] = listfiles + elif root == rootdir + os.sep + "autoload": + autoloaded_files = listfiles + for file in autoloaded_files: + if file in files[language]: + files[language].remove(file) + files[language].insert(0, "autoload" + os.sep + file) + return files + +def wg_get_local_scripts_status(): + """ + Return list of all local scripts with status (unknown/obsolete/running). + For example: + [ 'perl/weetris.pl': { 'unknown': '', 'obsolete': '1', 'running': '' }, + 'python/weeget.py': { 'unknown': '', 'obsolete': '', 'running': '1' } + ] + """ + local_scripts_status = [] + local_scripts = wg_get_local_scripts() + if len(local_scripts) > 0: + for language, files in local_scripts.items(): + for file in files: + script_status = { "unknown": "", "obsolete": "", "running": "" } + name_with_ext = os.path.basename(file) + script = wg_search_script_by_name(os.path.basename(file)) + if script == None: + script_status["unknown"] = "1" + else: + status = wg_get_local_script_status(script) + if status["obsolete"]: + script_status["obsolete"] = "1" + if wg_is_local_script_loaded(file): + script_status["running"] = "1" + local_scripts_status.append((language + os.sep + file, + script_status)) + return local_scripts_status + +def wg_search_scripts(search): + """ Search word in scripts, return list of matching scripts. """ + global wg_scripts + if search == "": + return wg_scripts + scripts_matching = {} + for id, script in wg_scripts.items(): + if script["name"].lower().find(search) >= 0 \ + or script["language"].lower().find(search) >= 0 \ + or script["desc_en"].lower().find(search) >= 0 \ + or script["desc_fr"].lower().find(search) >= 0 \ + or script["tags"].lower().find(search) >= 0: + scripts_matching[id] = script + return scripts_matching + +def wg_list_scripts(search, installed=False): + """ + List all scripts (with optional search string). + If installed == True, then list only installed scripts. + For each script, display status (installed/running/new version available), + name of script, language and description. + For example: + ir buffers pl Sidebar with list of buffers. + i N go py Quick jump to buffers. + i weetris pl Tetris-like game. + """ + global wg_scripts + search = search.strip().lower() + scripts_matching = wg_search_scripts(search) + if len(scripts_matching) == 0: + weechat.prnt("", "%s: no script found" % SCRIPT_NAME) + else: + weechat.prnt("", "") + if search != "": + if installed: + weechat.prnt("", "Scripts installed matching \"%s\":" % search) + else: + weechat.prnt("", "Scripts for WeeChat %s matching \"%s\":" + % (weechat.info_get("version", ""), + search)) + else: + if installed: + weechat.prnt("", "Scripts installed:") + else: + weechat.prnt("", "Scripts for WeeChat %s:" + % weechat.info_get("version", "")) + sorted_scripts = sorted(scripts_matching.items(), + key=lambda s: s[1]["name"]) + length_max_name = 0 + for item in sorted_scripts: + length = len(item[1]["name"]) + if length > length_max_name: + length_max_name = length + str_format = "%%s%%s%%s%%s%%s%%s%%s %%s%%-%ds %%s%%-3s %%s%%s" \ + % length_max_name + for item in sorted_scripts: + script = item[1] + str_installed = " " + str_running = " " + str_obsolete = " " + status = wg_get_local_script_status(script) + if installed and not status["installed"]: + continue + if status["installed"]: + str_installed = "i" + if status["running"]: + str_running = "r" + if status["obsolete"]: + str_obsolete = "N" + weechat.prnt("", str_format + % (wg_config_color("installed"), + str_installed, + wg_config_color("running"), + str_running, + wg_config_color("obsolete"), + str_obsolete, + weechat.color("chat"), + wg_config_color("script"), + script["name"], + wg_config_color("language"), + SCRIPT_EXTENSION[script["language"]], + weechat.color("chat"), + script["desc_en"])) + +def wg_show_script(name): + """ + Show detailed info about a script (in repository). + For example: + Script: weeget.py, version 0.7, license: GPL3 + Author: Sebastien Helleu <flashcode [at] flashtux [dot] org> + Status: installed, running + Date: added: 2009-04-05, updated: 2009-09-07 + URL: http://www.weechat.org/files/scripts/weeget.py + MD5: 4b0458dd5cc5c9a09ba8078f89830869 + Desc: Scripts manager. + Tags: scripts + Requires: python 2.5 + Min: 0.3.0 + """ + if len(wg_scripts) == 0: + return + script = wg_search_script_by_name(name) + if script == None: + weechat.prnt("", "%s: script \"%s%s%s\" not found" + % (SCRIPT_NAME, + wg_config_color("script"), + name, + weechat.color("chat"))) + else: + weechat.prnt("", "") + weechat.prnt("", " Script: %s%s%s, version %s, license: %s" + % (wg_config_color("script"), + script["full_name"], + weechat.color("chat"), + script["version"], + script["license"])) + weechat.prnt("", " Author: %s <%s>" % (script["author"], script["mail"])) + status = wg_get_local_script_status(script) + str_status = "not installed" + if status["installed"]: + str_status = "installed" + if status["running"]: + str_status += ", running" + else: + str_status += ", not running" + if status["obsolete"]: + str_status += " (new version available)" + weechat.prnt("", " Status: %s" % str_status) + date_added = script.get("added", "")[:10] + str_updated = script.get("updated", "") + if str_updated != "": + date_updated = script["updated"][:10] + if date_updated == "0000-00-00" or date_updated == date_added: + str_updated = "" + if str_updated != "": + weechat.prnt("", " Date: added: %s, updated: %s" + % (date_added, date_updated)) + else: + weechat.prnt("", " Date: added: %s" % date_added) + weechat.prnt("", " URL: %s" % script.get("url", "")) + weechat.prnt("", " MD5: %s" % script.get("md5sum", "")) + weechat.prnt("", " Desc: %s" % script.get("desc_en", "")) + weechat.prnt("", " Tags: %s" % script.get("tags", "")) + str_requires = script.get("requirements", "") + if str_requires == "": + str_requires = "(nothing)" + weechat.prnt("", "Requires: %s" % str_requires) + vmin = script.get("min_weechat", "") + vmax = script.get("max_weechat", "") + if vmin != "": + weechat.prnt("", " Min: %s" % vmin) + if vmax != "": + weechat.prnt("", " Max: %s" % vmax) + +def wg_install_next_script(): + """ + Install first script in list wg_scripts_to_install and remove it from + list. + """ + global wg_scripts, wg_scripts_to_install, wg_current_script_install + global wg_hook_process + if len(wg_scripts) == 0: + return + # be sure weeget is ALWAYS last script to install/update + # otherwise we'll lose end of list when weeget is unloaded by WeeChat + if SCRIPT_NAME in wg_scripts_to_install: + wg_scripts_to_install.remove(SCRIPT_NAME) + wg_scripts_to_install.append(SCRIPT_NAME) + # loop until a script is installed, or end if list is empty + while len(wg_scripts_to_install) > 0: + name = wg_scripts_to_install.pop(0) + script = wg_search_script_by_name(name) + if script == None: + weechat.prnt("", "%s: script \"%s%s%s\" not found" + % (SCRIPT_NAME, + wg_config_color("script"), + name, + weechat.color("chat"))) + else: + status = wg_get_local_script_status(script) + if status["installed"] and not status["obsolete"]: + weechat.prnt("", + "%s: script \"%s%s%s\" is already " + "installed and up to date" + % (SCRIPT_NAME, + wg_config_color("script"), + script["full_name"], + weechat.color("chat"))) + else: + weechat.prnt("", "%s: downloading \"%s%s%s\"..." + % (SCRIPT_NAME, + wg_config_color("script"), + script["full_name"], + weechat.color("chat"))) + if wg_hook_process["script"] != "": + weechat.unhook(wg_hook_process["script"]) + wg_hook_process["script"] = "" + wg_current_script_install = script + filename = wg_config_get_dir() + os.sep + script["full_name"] + wg_hook_process["script"] = wg_download_file(script["url"], filename, TIMEOUT_SCRIPT, + "wg_process_script_cb", "") + # this function will be called again when script will be + # downloaded + return + +def wg_install_scripts(names): + """ Install scripts. """ + global wg_scripts_to_install + for name in names.split(" "): + wg_scripts_to_install.append(name) + wg_install_next_script() + +def wg_process_script_cb(data, command, rc, stdout, stderr): + """ Callback when reading a script from website. """ + global wg_hook_process, wg_stdout, wg_current_script_install, wg_loaded_scripts + if stdout != "": + wg_stdout["script"] += stdout + if stderr != "": + wg_stdout["script"] += stderr + if int(rc) >= 0: + if wg_stdout["script"].startswith("error:"): + weechat.prnt("", "%s%s: error downloading script (%s)" + % (weechat.prefix("error"), SCRIPT_NAME, + wg_stdout["update"][6:].strip())) + else: + # ask C plugin to install/load script + weechat.hook_signal_send(wg_current_script_install["language"] + "_script_install", + weechat.WEECHAT_HOOK_SIGNAL_STRING, + wg_config_get_dir() + os.sep + wg_current_script_install["full_name"]) + wg_hook_process["script"] = "" + wg_install_next_script() + return weechat.WEECHAT_RC_OK + +def wg_check_scripts(): + """ + Check status of local script(s). + For each script found, display status (unknown/running/new version available). + For example: + r python/autoload/vdm.py + ?r python/autoload/dummy.py + rN python/shell.py + perl/buffers.pl + """ + local_scripts_status = wg_get_local_scripts_status() + if len(local_scripts_status) == 0: + return + weechat.prnt("", "") + weechat.prnt("", "Local scripts:") + for file, status in local_scripts_status: + str_unknown = " " + str_running = " " + str_obsolete = " " + if status["unknown"]: + str_unknown = "?" + if status["running"]: + str_running = "r" + if status["obsolete"]: + str_obsolete = "N" + weechat.prnt("", "%s%s%s%s%s%s%s %s%s%s%s" + % (wg_config_color("unknown"), str_unknown, + wg_config_color("running"), str_running, + wg_config_color("obsolete"), str_obsolete, + weechat.color("chat"), + os.path.dirname(file), + os.sep, + wg_config_color("script"), + os.path.basename(file))) + +def wg_upgrade_scripts(): + """ Upgrade scripts. """ + global wg_scripts, wg_scripts_to_install + if len(wg_scripts) == 0: + return + scripts_to_upgrade = [] + for id, script in wg_scripts.items(): + status = wg_get_local_script_status(script) + if status["installed"] and status["obsolete"]: + scripts_to_upgrade.append(script["name"]) + if len(scripts_to_upgrade) == 0: + weechat.prnt("", "%s: all scripts are up to date" % SCRIPT_NAME) + else: + wg_scripts_to_install.extend(scripts_to_upgrade) + wg_install_next_script() + +def wg_remove_scripts(names): + """ Remove scripts. """ + if len(wg_scripts) == 0: + return + list_names = names.split(" ") + scripts_to_remove = {} + for language in SCRIPT_EXTENSION.keys(): + scripts_to_remove[language] = [] + for name in list_names: + script = wg_search_script_by_name(name) + if script == None: + weechat.prnt("", "%s: script \"%s%s%s\" not found" + % (SCRIPT_NAME, + wg_config_color("script"), + name, + weechat.color("chat"))) + else: + if script["full_name"] not in scripts_to_remove[script["language"]]: + scripts_to_remove[script["language"]].append(script["full_name"]) + for language in SCRIPT_EXTENSION.keys(): + if len(scripts_to_remove[language]) > 0: + # ask C plugin to remove script file(s) + weechat.hook_signal_send(language + "_script_remove", + weechat.WEECHAT_HOOK_SIGNAL_STRING, + ",".join(scripts_to_remove[language])) + +# ==================================[ xml ]=================================== + +def wg_execute_action(): + """ Execute action. """ + global wg_action, wg_action_args, wg_loaded_scripts + if wg_action != "": + wg_get_loaded_scripts() + if wg_action == "list": + wg_list_scripts(wg_action_args) + elif wg_action == "listinstalled": + wg_list_scripts(wg_action_args, installed=True) + elif wg_action == "show": + wg_show_script(wg_action_args) + elif wg_action == "install": + wg_install_scripts(wg_action_args) + elif wg_action == "check": + wg_check_scripts() + elif wg_action == "upgrade": + wg_upgrade_scripts() + elif wg_action == "remove": + wg_remove_scripts(wg_action_args) + else: + weechat.prnt("", "%s%s: unknown action \"%s\"" + % (weechat.prefix("error"), SCRIPT_NAME, wg_action)) + + # reset action + wg_action = "" + wg_action_args = "" + wg_loaded_scripts = {} + +def wg_check_version(script): + """ Check if a script is designed for current running WeeChat version.""" + version = weechat.info_get("version", "") + version = version.split("-", 1)[0] + vmin = script.get("min_weechat", "") + vmax = script.get("max_weechat", "") + if vmin != "" and version < vmin: + return False + if vmax != "" and version > vmax: + return False + return True + +def wg_parse_xml(): + """ + Parse XML scripts list and return dictionary with list, with key 'id'. + Example of item return in dictionary : + '119': { 'name' : 'weeget', + 'version' : '0.1', + 'url' : 'http://www.weechat.org/files/scripts/weeget.py', + 'language' : 'python', + 'license' : 'GPL3', + 'md5sum' : 'd500714fc19b0e10cc4e339e70739e4ad500714fc19b0e10cc4e339e70739e4a', + 'tags' : 'scripts', + 'desc_en' : 'Scripts manager.', + 'desc_fr' : 'Gestionnaire de scripts.', + 'requirements': 'python 2.5', + 'min_weechat' : '0.3.0', + 'max_weechat' : '', + 'author' : 'FlashCode', + 'mail' : 'flashcode [at] flashtux [dot] org', + 'added' : '2009-04-05 22:39:18', + 'updated' : '0000-00-00 00:00:00' } + """ + global wg_scripts, wg_action, wg_action_args + wg_scripts = {} + try: + f = gzip.open(wg_config_get_cache_filename(), "rb") + string = f.read() + f.close() + except: + weechat.prnt("", "%s%s: unable to read xml file" + % (weechat.prefix("error"), SCRIPT_NAME)) + else: + try: + dom = xml.dom.minidom.parseString(string) + except: + weechat.prnt("", + "%s%s: unable to parse xml list of scripts" + % (weechat.prefix("error"), SCRIPT_NAME)) + # discard action + wg_action = "" + wg_action_args = "" + else: + for scriptNode in dom.getElementsByTagName("plugin"): + id = scriptNode.getAttribute("id") + script = {} + for node in scriptNode.childNodes: + if node.nodeType == node.ELEMENT_NODE: + if node.firstChild != None: + nodename = node.nodeName + value = node.firstChild.data + if sys.version_info < (3,): + # python 2.x: convert unicode to str (in python 3.x, id and text are already strings) + nodename = nodename.encode("utf-8") + value = value.encode("utf-8") + script[nodename] = value + if script["language"] in SCRIPT_EXTENSION: + script["full_name"] = script["name"] + "." + SCRIPT_EXTENSION[script["language"]] + if wg_check_version(script): + wg_scripts[id] = script + wg_execute_action() + +def wg_process_update_cb(data, command, rc, stdout, stderr): + """ Callback when reading XML cache file from website. """ + global wg_hook_process, wg_stdout, wg_scripts + if stdout != "": + wg_stdout["update"] += stdout + if stderr != "": + wg_stdout["update"] += stderr + if int(rc) >= 0: + if wg_stdout["update"].startswith("error:"): + weechat.prnt("", "%s%s: error downloading scripts (%s)" + % (weechat.prefix("error"), SCRIPT_NAME, + wg_stdout["update"][6:].strip())) + else: + weechat.prnt("", "%s: scripts downloaded" % SCRIPT_NAME) + wg_parse_xml() + wg_hook_process["update"] = "" + return weechat.WEECHAT_RC_OK + +def wg_update_cache(): + """ Download list of scripts and update local cache. """ + global wg_config_option, wg_hook_process, wg_stdout + # get data from website, via hook_process + if wg_hook_process["update"] != "": + weechat.unhook(wg_hook_process["update"]) + wg_hook_process["update"] = "" + weechat.prnt("", "%s: downloading list of scripts..." % SCRIPT_NAME) + wg_stdout["update"] = "" + wg_config_create_dir() + url = weechat.config_string(wg_config_option["scripts_url"]) + filename = wg_config_get_cache_filename() + wg_hook_process["update"] = wg_download_file(url, filename, TIMEOUT_UPDATE, + "wg_process_update_cb", "") + +def wg_read_scripts(download_list=True): + """ Read scripts list (download list if needed and asked). """ + global wg_scripts + cache_file = wg_config_get_cache_filename() + if os.path.isfile(cache_file): + # check if local cache file is too old + cache_expire = weechat.config_integer(wg_config_option["scripts_cache_expire"]) * 60 + if cache_expire >= 0: + diff_time = time.time() - os.stat(cache_file)[stat.ST_MTIME] + if download_list and diff_time >= cache_expire: + os.unlink(cache_file) + wg_scripts.clear() + if len(wg_scripts) > 0: + wg_execute_action() + else: + if os.path.isfile(cache_file): + wg_parse_xml() + elif download_list: + wg_update_cache() + +# ================================[ command ]================================= + +def wg_cmd(data, buffer, args): + """ Callback for /weeget command. """ + global wg_action, wg_action_args + if args == "": + weechat.command("", "/help %s" % SCRIPT_COMMAND) + return weechat.WEECHAT_RC_OK + argv = args.strip().split(" ", 1) + if len(argv) == 0: + return weechat.WEECHAT_RC_OK + + wg_action = "" + wg_action_args = "" + + # check arguments + if len(argv) < 2: + if argv[0] == "show" or \ + argv[0] == "install" or \ + argv[0] == "remove": + weechat.prnt("", "%s: too few arguments for action \"%s\"" + % (SCRIPT_NAME, argv[0])) + return weechat.WEECHAT_RC_OK + + # execute asked action + if argv[0] == "update": + wg_update_cache() + else: + wg_action = argv[0] + wg_action_args = "" + if len(argv) > 1: + wg_action_args = argv[1] + wg_read_scripts() + + return weechat.WEECHAT_RC_OK + +def wg_completion_scripts_cb(data, completion_item, buffer, completion): + """ Complete with known script names, for command '/weeget'. """ + global wg_scripts + wg_read_scripts(download_list=False) + if len(wg_scripts) > 0: + for id, script in wg_scripts.items(): + weechat.hook_completion_list_add(completion, script["full_name"], + 0, weechat.WEECHAT_LIST_POS_SORT) + return weechat.WEECHAT_RC_OK + +def wg_completion_scripts_installed_cb(data, completion_item, buffer, completion): + """ Complete with names of scripts installed, for command '/weeget'. """ + global wg_scripts + wg_read_scripts(download_list=False) + if len(wg_scripts) > 0: + for id, script in wg_scripts.items(): + status = wg_get_local_script_status(script) + if status["installed"]: + weechat.hook_completion_list_add(completion, script["full_name"], + 0, weechat.WEECHAT_LIST_POS_SORT) + return weechat.WEECHAT_RC_OK + +def wg_completion_scripts_tags_cb(data, completion_item, buffer, completion): + """ Complete with known tags, for command '/weeget'. """ + global wg_scripts + wg_read_scripts(download_list=False) + if len(wg_scripts) > 0: + for id, script in wg_scripts.items(): + if script["tags"]: + for tag in script["tags"].split(","): + weechat.hook_completion_list_add(completion, tag, + 0, weechat.WEECHAT_LIST_POS_SORT) + return weechat.WEECHAT_RC_OK + +# ==================================[ main ]================================== + +if __name__ == "__main__" and import_ok: + if weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE, + SCRIPT_DESC, "wg_unload_script", ""): + wg_config_init() + wg_config_read() + if weechat.config_string(wg_config_option["scripts_url"]).find("weechat.flashtux.org") >= 0: + weechat.prnt("", "%sWarning: old site still used in URL for plugins.xml.gz, you should do: /unset wg.scripts.url" + % weechat.prefix("error")) + str_installed = wg_config_color("installed") + "i" + weechat.color("chat") + str_unknown = wg_config_color("unknown") + "?" + weechat.color("chat") + str_running = wg_config_color("running") + "r" + weechat.color("chat") + str_obsolete = wg_config_color("obsolete") + "N" + weechat.color("chat") + weechat.hook_command(SCRIPT_COMMAND, + "WeeChat scripts manager", + "list|listinstalled [<text>|<tag>] || show <script>" + " || install|remove <script> [<script>...] || check|update|upgrade", + " list: list scripts (search text if given)\n" + "listinstalled: list installed scripts (search text if given)\n" + " show: show detailed information about a script (in repository)\n" + " install: install/upgrade script(s)\n" + " check: check if local scripts needs upgrade\n" + " update: update local scripts cache\n" + " upgrade: upgrade all local scripts if they are obsolete\n" + " remove: remove script(s)\n\n" + "Indicators in lists (first column):\n" + " " + str_installed + " script is installed\n" + " " + str_unknown + " unknown script\n" + " " + str_running + " script is running (loaded)\n" + " " + str_obsolete + " script is obsolete (new version available)\n\n" + "Examples:\n" + " /" + SCRIPT_COMMAND + " list => list all scripts\n" + " /" + SCRIPT_COMMAND + " list game => list all scripts with text/tag \"game\"\n" + " /" + SCRIPT_COMMAND + " install beep.pl => install script beep.pl\n" + " /" + SCRIPT_COMMAND + " remove beep.pl => remove script beep.pl", + "list %(weeget_scripts_tags)" + " || listinstalled %(weeget_scripts_tags)" + " || show %(weeget_scripts)" + " || install %(weeget_scripts)|%*" + " || remove %(weeget_scripts_installed)|%*" + " || check" + " || update" + " || upgrade", + "wg_cmd", "") + weechat.hook_completion("weeget_scripts", "list of scripts in repository", + "wg_completion_scripts_cb", "") + weechat.hook_completion("weeget_scripts_installed", "list of scripts installed", + "wg_completion_scripts_installed_cb", "") + weechat.hook_completion("weeget_scripts_tags", "tags of scripts in repository", + "wg_completion_scripts_tags_cb", "") + +# ==================================[ end ]=================================== + +def wg_unload_script(): + """ Function called when script is unloaded. """ + wg_config_write() + return weechat.WEECHAT_RC_OK diff --git a/weechat/python/screen_away.py b/weechat/python/screen_away.py new file mode 100644 index 0000000..744638a --- /dev/null +++ b/weechat/python/screen_away.py @@ -0,0 +1,151 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2009 by xt <xt@bash.no> +# Copyright (c) 2009 by penryu <penryu@gmail.com> +# Copyright (c) 2010 by Blake Winton <bwinton@latte.ca> +# Copyright (c) 2010 by Aron Griffis <agriffis@n01se.net> +# Copyright (c) 2010 by Jani Kesänen <jani.kesanen@gmail.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +# +# (this script requires WeeChat 0.3.0 or newer) +# +# History: +# 2010-08-07, Filip H.F. "FiXato" Slagter <fixato@gmail.com> +# version 0.8: add command on attach feature +# 2010-05-07, Jani Kesänen <jani.kesanen@gmail.com> +# version 0.7: add command on detach feature +# 2010-03-07, Aron Griffis <agriffis@n01se.net> +# version 0.6: move socket check to register, +# add hook_config for interval, +# reduce default interval from 60 to 5 +# 2010-02-19, Blake Winton <bwinton@latte.ca> +# version 0.5: add option to change nick when away +# 2010-01-18, xt +# version 0.4: only update servers that are connected +# 2009-11-30, xt <xt@bash.no> +# version 0.3: do not touch servers that are manually set away +# 2009-11-27, xt <xt@bash.no> +# version 0.2: code for TMUX from penryu +# 2009-11-27, xt <xt@bash.no> +# version 0.1: initial release + +import weechat as w +import re +import os + +SCRIPT_NAME = "screen_away" +SCRIPT_AUTHOR = "xt <xt@bash.no>" +SCRIPT_VERSION = "0.8" +SCRIPT_LICENSE = "GPL3" +SCRIPT_DESC = "Set away status on screen detach" + +settings = { + 'message': 'Detached from screen', + 'interval': '5', # How often in seconds to check screen status + 'away_suffix': '', # What to append to your nick when you're away. + 'command_on_attach': '', # Command to execute on attach + 'command_on_detach': '' # Command to execute on detach +} + +TIMER = None +SOCK = None +AWAY = False + +def set_timer(): + '''Update timer hook with new interval''' + + global TIMER + if TIMER: + w.unhook(TIMER); + TIMER = w.hook_timer(int(w.config_get_plugin('interval')) * 1000, + 0, 0, "screen_away_timer_cb", '') + +def screen_away_config_cb(data, option, value): + if option.endswith(".interval"): + set_timer() + return w.WEECHAT_RC_OK + +def get_servers(): + '''Get the servers that are not away, or were set away by this script''' + + infolist = w.infolist_get('irc_server','','') + buffers = [] + while w.infolist_next(infolist): + if not w.infolist_integer(infolist, 'is_connected') == 1: + continue + if not w.infolist_integer(infolist, 'is_away') or \ + w.infolist_string(infolist, 'away_message') == \ + w.config_get_plugin('message'): + buffers.append((w.infolist_pointer(infolist, 'buffer'), + w.infolist_string(infolist, 'nick'))) + w.infolist_free(infolist) + return buffers + +def screen_away_timer_cb(buffer, args): + '''Check if screen is attached, update awayness''' + + global AWAY, SOCK + + suffix = w.config_get_plugin('away_suffix') + attached = os.access(SOCK, os.X_OK) # X bit indicates attached + + if attached and AWAY: + w.prnt('', '%s: Screen attached. Clearing away status' % SCRIPT_NAME) + for server, nick in get_servers(): + w.command(server, "/away") + if suffix and nick.endswith(suffix): + nick = nick[:-len(suffix)] + w.command(server, "/nick %s" % nick) + AWAY = False + if w.config_get_plugin("command_on_attach"): + w.command("", w.config_get_plugin("command_on_attach")) + + elif not attached and not AWAY: + w.prnt('', '%s: Screen detached. Setting away status' % SCRIPT_NAME) + for server, nick in get_servers(): + if suffix: + w.command(server, "/nick %s%s" % (nick, suffix)); + w.command(server, "/away %s" % w.config_get_plugin('message')); + AWAY = True + if w.config_get_plugin("command_on_detach"): + w.command("", w.config_get_plugin("command_on_detach")) + + return w.WEECHAT_RC_OK + + +if w.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE, + SCRIPT_DESC, "", ""): + for option, default_value in settings.iteritems(): + if not w.config_is_set_plugin(option): + w.config_set_plugin(option, default_value) + + if 'STY' in os.environ.keys(): + # We are running under screen + cmd_output = os.popen('env LC_ALL=C screen -ls').read() + match = re.search(r'Sockets? in (/.+)\.', cmd_output) + if match: + SOCK = os.path.join(match.group(1), os.environ['STY']) + + if not SOCK and 'TMUX' in os.environ.keys(): + # We are running under tmux + socket_data = os.environ['TMUX'] + SOCK = socket_data.rsplit(',',2)[0] + + if SOCK: + set_timer() + w.hook_config("plugins.var.python." + SCRIPT_NAME + ".*", + "screen_away_config_cb", "") diff --git a/weechat/python/upside_down.py b/weechat/python/upside_down.py new file mode 100644 index 0000000..e07a7bf --- /dev/null +++ b/weechat/python/upside_down.py @@ -0,0 +1,130 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2009 by xt <xt@bash.no> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# +# +# USAGE: Bind a key to command /flip . Then write some text at input line +# press your key to transform it to upside down. + +# +# (this script requires WeeChat 0.3.0 or newer) +# +# History: +# 2010-01-14, xt +# version 0.3: steal more chars from m4v +# 2010-01-06, xt <xt@bash.no> +# version 0.2: fix idiotic programming +# 2009-11-12, xt <xt@bash.no> +# version 0.1: initial release + +import weechat as w +import re + +SCRIPT_NAME = "upside_down" +SCRIPT_AUTHOR = "xt <xt@bash.no>" +SCRIPT_VERSION = "0.3" +SCRIPT_LICENSE = "GPL3" +SCRIPT_DESC = "Replaces text you write with upside down text" + +settings = {} + +replacements = { +# Upper case + u'A' : u'\N{FOR ALL}', + u'B' : u'\N{GREEK SMALL LETTER XI}', + u'C' : u'\N{ROMAN NUMERAL REVERSED ONE HUNDRED}', + u'D' : u'\N{LEFT HALF BLACK CIRCLE}', + u'E' : u'\N{LATIN CAPITAL LETTER REVERSED E}', + u'F' : u'\N{TURNED CAPITAL F}', + u'G' : u'\N{TURNED SANS-SERIF CAPITAL G}', + u'J' : u'\N{LATIN SMALL LETTER LONG S}', + u'K' : u'\N{RIGHT NORMAL FACTOR SEMIDIRECT PRODUCT}', + u'L' : u'\ua780', + u'M' : u'W', + u'N' : u'\N{LATIN LETTER SMALL CAPITAL REVERSED N}', + u'P' : u'\N{CYRILLIC CAPITAL LETTER KOMI DE}', + u'Q' : u'\N{GREEK CAPITAL LETTER OMICRON WITH TONOS}', + u'R' : u'\N{LATIN LETTER SMALL CAPITAL TURNED R}', + u'T' : u'\N{UP TACK}', + u'U' : u'\N{INTERSECTION}', + u'V' : u'\u0245', + u'Y' : u'\N{TURNED SANS-SERIF CAPITAL Y}', + 'a' : u"\u0250", + 'b' : u'q', + 'c' : u"\u0254", + 'd' : u'p', + 'e' : u"\u01DD", + 'f' : u"\u025F", + 'g' : u"\u0183", + 'h' : u'\u0265', + 'i' : u'\u0131', + 'j' : u'\u027E', + 'k' : u'\u029E', + 'm' : u'\u026F', + 'n' : u'u', + 'r' : u'\u0279', + 't' : u'\u0287', + 'p' : u'd', + 'u' : u'n', + 'q' : u'b', + 'v' : u'\u028C', + 'w' : u'\u028D', + 'y' : u'\u028E', + '.' : u'\u02D9', + '[' : u']', + '(' : u')', + '{' : u'}', + '?' : u'\u00BF', + '!' : u'\u00A1', + "\'" :u',', + '>' : u'<', + '<' : u'>', + '_' : u'\u203E', + ';' : u'\u061B', + '\u203F' : u'\u2040', + '\u2045' : u'\u2046', + '\u2234' : u'\u2235', +} + + + +if w.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE, + SCRIPT_DESC, "", ""): + for option, default_value in settings.iteritems(): + if not w.config_is_set_plugin(option): + w.config_set_plugin(option, default_value) + w.hook_command("flip", + SCRIPT_DESC, + "[text]", + "text: text to be flipped\n" + "", + "", "flip_cmd_cb", "") + + +def flip_cmd_cb(data, buffer, args): + ''' Command /flip ''' + translate_input = args + if not translate_input: + translate_input = w.buffer_get_string(w.current_buffer(), "input") + outstring = '' + for char in translate_input: + if char in replacements: + char = replacements[char] + outstring += char + outstring = outstring.encode('UTF-8') + w.buffer_set(w.current_buffer(), 'input', outstring) + return w.WEECHAT_RC_OK |