# -*- coding: utf-8 -*- # # Copyright (c) 2010 by Alexander Schremmer # Copyright (c) 2013,2020 by Corey Halpin # # 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 . # # # (this script requires WeeChat 0.3.6 or newer) # # History: # 2020-05-10, Sébastien Helleu # version 0.7: remove useless list() around .items() # 2020-04-15, Corey Halpin # version 0.6: # * Update for python3, fixing issues pointed out by 2to3. # * Fix complaints from pycodestyle. # 2014-02-15, Corey Halpin # version 0.5: # * Improve documentation for the 'server' setting # * Change the default for 'server' to bitlbee, as this is probably # what most people use. # 2013-06-24, Priska Herger # version 0.4: bug fix: if TYPING 0, don't show typing. # 2013-04-27, Corey Halpin # version 0.3: # * Use irc_message_parse to extract nicks # * Send typing = 0 at message completion in private buffers # * Make server, channel, and timeout configurable w/o editing plugin code. # 2010-05-20, Alexander Schremmer # version 0.2: also handle users that do not send a TYPING 0 msg before # quitting removed InfoList code # 2010-05-16, Alexander Schremmer # version 0.1: initial release # Configuration options via /set: # # 'channel' # description: Name of your bitlbee channel # command: /set plugins.var.python.bitlbee_typing_notice.channel &bitlbee # # 'server' # description: Name of the server running your bitlbee instance. This will # be whatever you type after /connect to get to your bitlbee server # (e.g., localhost, bitlbee). # command: /set plugins.var.python.bitlbee_typing_notice.server bitlbee # # 'timeout' # description: Send "not typing" after this many seconds w/o typing. # command: /set plugins.var.python.bitlbee_typing_notice.timeout 4 # # Note, the plugin must be reloaded after either of these settings are changed. # /python reload works for this. import weechat as w import re SCRIPT_NAME = "bitlbee_typing_notice" SCRIPT_AUTHOR = "Alexander Schremmer " SCRIPT_VERSION = "0.7" SCRIPT_LICENSE = "GPL3" SCRIPT_DESC = "Sends and displays bitlbee typing notices." # Record nicks who sent typing notices. # key = subject nick, val = typing level. typing = {} # Nicks to whom we're sending typing notices. # key = target nick, val = sequence number used to determine when the typing # notice should be removed. sending_typing = {} def channel_has_nick(server, channel, nick): buffer = w.buffer_search("", "%s.%s" % (server, channel)) return bool(w.nicklist_search_nick(buffer, "", nick)) # Callback which checks for ctcp typing notices sent to us. # Updates typing data, hides the ctcp notices. def ctcp_cb(data, modifier, modifier_data, string): if modifier_data != w.config_get_plugin("server"): return string msg_hash = w.info_get_hashtable( "irc_message_parse", {"message": string}) if msg_hash["command"] != "PRIVMSG": return string match = re.search('\001TYPING ([0-9])\001', msg_hash["arguments"]) if match: nick = msg_hash["nick"] typing_level = int(match.groups()[0]) if typing_level == 0 and nick in typing: del typing[nick] elif typing_level > 0: typing[nick] = typing_level w.bar_item_update("bitlbee_typing_notice") return "" else: return string def stop_typing(data, signal, signal_data): msg_hash = w.info_get_hashtable( "irc_message_parse", {"message": signal_data}) if msg_hash["nick"] in typing: del typing[msg_hash["nick"]] w.bar_item_update("bitlbee_typing_notice") return w.WEECHAT_RC_OK def typed_char(data, signal, signal_data): buffer = w.current_buffer() input_s = w.buffer_get_string(buffer, 'input') server = w.buffer_get_string(buffer, 'localvar_server') channel = w.buffer_get_string(buffer, 'localvar_channel') buffer_type = w.buffer_get_string(buffer, 'localvar_type') if server != w.config_get_plugin("server") or input_s.startswith("/"): return w.WEECHAT_RC_OK if buffer_type == "private": if len(input_s) == 0: send_typing(channel, 0) # Line sent or deleted -- no longer typing else: send_typing(channel, 1) elif channel == w.config_get_plugin("channel"): nick_completer = w.config_string("weechat.completion.nick_completer") parts = input_s.split(":", 1) if len(parts) > 1: nick = parts[0] send_typing(nick, 1) return w.WEECHAT_RC_OK def typing_disable_timer(data, remaining_calls): nick, cookie = data.rsplit(":", 1) cookie = int(cookie) if nick in sending_typing and sending_typing[nick] == cookie: send_typing_ctcp(nick, 0) del sending_typing[nick] return w.WEECHAT_RC_OK def send_typing_ctcp(nick, level): if not channel_has_nick(w.config_get_plugin("server"), w.config_get_plugin("channel"), nick): return server = w.config_get_plugin("server") channel = w.config_get_plugin("channel") buffer = w.buffer_search( "irc", "%s.%s" % (server, channel)) w.command(buffer, "/mute -all /ctcp %s TYPING %i" % (nick, level)) def send_typing(nick, level): if level == 0 and nick in sending_typing: send_typing_ctcp(nick, 0) del sending_typing[nick] elif level > 0: if nick not in sending_typing: send_typing_ctcp(nick, level) cookie = sending_typing.get(nick, 0) + 1 sending_typing[nick] = cookie timeout = int(1000 * float(w.config_get_plugin('timeout'))) w.hook_timer( timeout, 0, 1, "typing_disable_timer", "%s:%i" % (nick, cookie)) def typing_notice_item_cb(data, buffer, args): if typing: msgs = [] for key, value in typing.items(): msg = key if value == 2: msg += " (stale)" msgs.append(msg) return "typing: " + ", ".join(sorted(msgs)) return "" # Main if __name__ == "__main__": if w.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE, SCRIPT_DESC, "", ""): if not w.config_get_plugin('channel'): w.config_set_plugin('channel', "&bitlbee") if not w.config_get_plugin('server'): w.config_set_plugin('server', "bitlbee") if not w.config_get_plugin('timeout'): w.config_set_plugin('timeout', "4") server = w.config_get_plugin("server") w.hook_signal("input_text_changed", "typed_char", "") w.hook_signal(server+",irc_in_quit", "stop_typing", "") w.hook_signal(server+",irc_in_privmsg", "stop_typing", "") w.bar_item_new('bitlbee_typing_notice', 'typing_notice_item_cb', '') w.hook_modifier("irc_in_privmsg", "ctcp_cb", "")