aboutsummaryrefslogtreecommitdiffstats
path: root/wee_slack.py
diff options
context:
space:
mode:
Diffstat (limited to 'wee_slack.py')
-rw-r--r--wee_slack.py734
1 files changed, 507 insertions, 227 deletions
diff --git a/wee_slack.py b/wee_slack.py
index ef41c6f..a3d43ce 100644
--- a/wee_slack.py
+++ b/wee_slack.py
@@ -1,5 +1,6 @@
-#-*- coding: utf-8 -*-
-#
+# -*- coding: utf-8 -*-
+
+from __future__ import unicode_literals
from functools import wraps
@@ -12,7 +13,7 @@ import re
import urllib
import sys
import traceback
-#import collections
+import collections
import ssl
import random
import string
@@ -21,7 +22,7 @@ from websocket import create_connection, WebSocketConnectionClosedException
# hack to make tests possible.. better way?
try:
- import weechat as w
+ import weechat
except:
pass
@@ -70,6 +71,7 @@ SLACK_API_TRANSLATOR = {
###### Decorators have to be up here
+
def slack_buffer_or_ignore(f):
"""
Only run this function if we're in a slack buffer, else ignore
@@ -81,6 +83,7 @@ def slack_buffer_or_ignore(f):
return f(data, current_buffer, *args, **kwargs)
return wrapper
+
def slack_buffer_required(f):
"""
Only run this function if we're in a slack buffer, else print error
@@ -102,16 +105,64 @@ if hasattr(ssl, "get_default_verify_paths") and callable(ssl.get_default_verify_
if ssl_defaults.cafile is not None:
sslopt_ca_certs = {'ca_certs': ssl_defaults.cafile}
+###### Unicode handling
+
+
+def encode_to_utf8(data):
+ if isinstance(data, unicode):
+ return data.encode('utf-8')
+ if isinstance(data, bytes):
+ return data
+ elif isinstance(data, collections.Mapping):
+ return dict(map(encode_to_utf8, data.iteritems()))
+ elif isinstance(data, collections.Iterable):
+ return type(data)(map(encode_to_utf8, data))
+ else:
+ return data
+
+
+def decode_from_utf8(data):
+ if isinstance(data, bytes):
+ return data.decode('utf-8')
+ if isinstance(data, unicode):
+ return data
+ elif isinstance(data, collections.Mapping):
+ return dict(map(decode_from_utf8, data.iteritems()))
+ elif isinstance(data, collections.Iterable):
+ return type(data)(map(decode_from_utf8, data))
+ else:
+ return data
+
+
+class WeechatWrapper(object):
+ def __init__(self, wrapped_class):
+ self.wrapped_class = wrapped_class
+
+ def __getattr__(self, attr):
+ orig_attr = self.wrapped_class.__getattribute__(attr)
+ if callable(orig_attr):
+ def hooked(*args, **kwargs):
+ result = orig_attr(*encode_to_utf8(args), **encode_to_utf8(kwargs))
+ # Prevent wrapped_class from becoming unwrapped
+ if result == self.wrapped_class:
+ return self
+ return decode_from_utf8(result)
+ return hooked
+ else:
+ return decode_from_utf8(orig_attr)
+
+
##### BEGIN NEW
IGNORED_EVENTS = [
"hello",
- #"pref_change",
- #"reconnect_url",
+ # "pref_change",
+ # "reconnect_url",
]
###### New central Event router
+
class EventRouter(object):
def __init__(self):
@@ -188,7 +239,7 @@ class EventRouter(object):
"""
data = self.context.get(identifier, None)
if data:
- #dbg("retrieved eontext {} ".format(identifier))
+ # dbg("retrieved context {} ".format(identifier))
return data
def delete_context(self, identifier):
@@ -196,7 +247,7 @@ class EventRouter(object):
Requests can span multiple requests, so we may need to delete this as a last step
"""
if identifier in self.context:
- #dbg("deleted eontext {} ".format(identifier))
+ # dbg("deleted eontext {} ".format(identifier))
del self.context[identifier]
def shutdown(self):
@@ -236,7 +287,7 @@ class EventRouter(object):
"""
try:
# Read the data from the websocket associated with this team.
- data = self.teams[team_hash].ws.recv()
+ data = decode_from_utf8(self.teams[team_hash].ws.recv())
message_json = json.loads(data)
metadata = WeeSlackMetadata({
"team": team_hash,
@@ -246,7 +297,7 @@ class EventRouter(object):
self.record_event(message_json, 'type', 'websocket')
self.receive_json(json.dumps(message_json))
except WebSocketConnectionClosedException:
- #TODO: handle reconnect here
+ # TODO: handle reconnect here
self.teams[team_hash].set_disconnected()
return w.WEECHAT_RC_OK
except Exception:
@@ -271,17 +322,17 @@ class EventRouter(object):
if return_code == 0:
if len(out) > 0:
if request_metadata.response_id in self.reply_buffer:
- #dbg("found response id in reply_buffer", True)
+ # dbg("found response id in reply_buffer", True)
self.reply_buffer[request_metadata.response_id] += out
else:
- #dbg("didn't find response id in reply_buffer", True)
+ # dbg("didn't find response id in reply_buffer", True)
self.reply_buffer[request_metadata.response_id] = ""
self.reply_buffer[request_metadata.response_id] += out
try:
j = json.loads(self.reply_buffer[request_metadata.response_id])
except:
pass
- #dbg("Incomplete json, awaiting more", True)
+ # dbg("Incomplete json, awaiting more", True)
try:
j["wee_slack_process_method"] = request_metadata.request_normalized
j["wee_slack_request_metadata"] = pickle.dumps(request_metadata)
@@ -315,6 +366,7 @@ class EventRouter(object):
dbg("RECEIVED JSON of len {}".format(len(data)))
message_json = json.loads(data)
self.queue.append(message_json)
+
def receive(self, dataobj):
"""
complete
@@ -324,6 +376,7 @@ class EventRouter(object):
"""
dbg("RECEIVED FROM QUEUE")
self.queue.append(dataobj)
+
def receive_slow(self, dataobj):
"""
complete
@@ -333,6 +386,7 @@ class EventRouter(object):
"""
dbg("RECEIVED FROM QUEUE")
self.slow_queue.append(dataobj)
+
def handle_next(self):
"""
complete
@@ -341,10 +395,10 @@ class EventRouter(object):
useful metadata and context to events as they are processed.
"""
if len(self.slow_queue) > 0 and ((self.slow_queue_timer + 1) < time.time()):
- #for q in self.slow_queue[0]:
+ # for q in self.slow_queue[0]:
dbg("from slow queue", 0)
self.queue.append(self.slow_queue.pop())
- #self.slow_queue = []
+ # self.slow_queue = []
self.slow_queue_timer = time.time()
if len(self.queue) > 0:
j = self.queue.pop(0)
@@ -378,7 +432,7 @@ class EventRouter(object):
meta = j.get("wee_slack_metadata", None)
if meta:
try:
- if isinstance(meta, str):
+ if isinstance(meta, basestring):
dbg("string of metadata")
team = meta.get("team", None)
if team:
@@ -401,6 +455,7 @@ class EventRouter(object):
else:
raise ProcessNotImplemented(function_name)
+
def handle_next(*args):
"""
complete
@@ -416,33 +471,38 @@ def handle_next(*args):
pass
return w.WEECHAT_RC_OK
+
class WeechatController(object):
"""
Encapsulates our interaction with weechat
"""
+
def __init__(self, eventrouter):
self.eventrouter = eventrouter
self.buffers = {}
self.previous_buffer = None
self.buffer_list_stale = False
+
def iter_buffers(self):
for b in self.buffers:
yield (b, self.buffers[b])
+
def register_buffer(self, buffer_ptr, channel):
"""
complete
Adds a weechat buffer to the list of handled buffers for this EventRouter
"""
- if isinstance(buffer_ptr, str):
+ if isinstance(buffer_ptr, basestring):
self.buffers[buffer_ptr] = channel
else:
raise InvalidType(type(buffer_ptr))
+
def unregister_buffer(self, buffer_ptr, update_remote=False, close_buffer=False):
"""
complete
Adds a weechat buffer to the list of handled buffers for this EventRouter
"""
- if isinstance(buffer_ptr, str):
+ if isinstance(buffer_ptr, basestring):
try:
self.buffers[buffer_ptr].destroy_buffer(update_remote)
if close_buffer:
@@ -452,22 +512,28 @@ class WeechatController(object):
dbg("Tried to close unknown buffer")
else:
raise InvalidType(type(buffer_ptr))
+
def get_channel_from_buffer_ptr(self, buffer_ptr):
return self.buffers.get(buffer_ptr, None)
+
def get_all(self, buffer_ptr):
return self.buffers
+
def get_previous_buffer_ptr(self):
return self.previous_buffer
+
def set_previous_buffer(self, data):
self.previous_buffer = data
+
def check_refresh_buffer_list(self):
return self.buffer_list_stale and self.last_buffer_list_update + 1 < time.time()
+
def set_refresh_buffer_list(self, setting):
self.buffer_list_stale = setting
-
###### New Local Processors
+
def local_process_async_slack_api_request(request, event_router):
"""
complete
@@ -480,21 +546,24 @@ def local_process_async_slack_api_request(request, event_router):
params = {'useragent': 'wee_slack {}'.format(SCRIPT_VERSION)}
request.tried()
context = event_router.store_context(request)
- #TODO: let flashcode know about this bug - i have to 'clear' the hashtable or retry requests fail
+ # TODO: let flashcode know about this bug - i have to 'clear' the hashtable or retry requests fail
w.hook_process_hashtable('url:', params, config.slack_timeout, "", context)
w.hook_process_hashtable(weechat_request, params, config.slack_timeout, "receive_httprequest_callback", context)
###### New Callbacks
+
def receive_httprequest_callback(data, command, return_code, out, err):
"""
complete
This is a dirty hack. There must be a better way.
"""
- #def url_processor_cb(data, command, return_code, out, err):
+ # def url_processor_cb(data, command, return_code, out, err):
+ data = decode_from_utf8(data)
EVENTROUTER.receive_httprequest_callback(data, command, return_code, out, err)
return w.WEECHAT_RC_OK
+
def receive_ws_callback(*args):
"""
complete
@@ -505,10 +574,12 @@ def receive_ws_callback(*args):
EVENTROUTER.receive_ws_callback(args[0])
return w.WEECHAT_RC_OK
+
def reconnect_callback(*args):
EVENTROUTER.reconnect_if_disconnected()
return w.WEECHAT_RC_OK
+
def buffer_closing_callback(signal, sig_type, data):
"""
complete
@@ -517,9 +588,11 @@ def buffer_closing_callback(signal, sig_type, data):
that is the only way we can do dependency injection via weechat
callback, hence the eval.
"""
+ data = decode_from_utf8(data)
eval(signal).weechat_controller.unregister_buffer(data, True, False)
return w.WEECHAT_RC_OK
+
def buffer_input_callback(signal, buffer_ptr, data):
"""
incomplete
@@ -527,6 +600,7 @@ def buffer_input_callback(signal, buffer_ptr, data):
this includes add/remove reactions, modifying messages, and
sending messages.
"""
+ data = decode_from_utf8(data)
eventrouter = eval(signal)
channel = eventrouter.weechat_controller.get_channel_from_buffer_ptr(buffer_ptr)
if not channel:
@@ -548,12 +622,13 @@ def buffer_input_callback(signal, buffer_ptr, data):
# rid of escapes.
new = new.replace(r'\/', '/')
old = old.replace(r'\/', '/')
- channel.edit_previous_message(old.decode("utf-8"), new.decode("utf-8"), flags)
+ channel.edit_previous_message(old, new, flags)
else:
channel.send_message(data)
- #this is probably wrong channel.mark_read(update_remote=True, force=True)
+ # this is probably wrong channel.mark_read(update_remote=True, force=True)
return w.WEECHAT_RC_ERROR
+
def buffer_switch_callback(signal, sig_type, data):
"""
incomplete
@@ -561,6 +636,7 @@ def buffer_switch_callback(signal, sig_type, data):
1) set read marker 2) determine if we have already populated
channel history data
"""
+ data = decode_from_utf8(data)
eventrouter = eval(signal)
prev_buffer_ptr = eventrouter.weechat_controller.get_previous_buffer_ptr()
@@ -577,6 +653,7 @@ def buffer_switch_callback(signal, sig_type, data):
eventrouter.weechat_controller.set_previous_buffer(data)
return w.WEECHAT_RC_OK
+
def buffer_list_update_callback(data, somecount):
"""
incomplete
@@ -586,8 +663,9 @@ def buffer_list_update_callback(data, somecount):
to indicate typing via "#channel" <-> ">channel" and
user presence via " name" <-> "+name".
"""
+ data = decode_from_utf8(data)
eventrouter = eval(data)
- #global buffer_list_update
+ # global buffer_list_update
for b in eventrouter.weechat_controller.iter_buffers():
b[1].refresh()
@@ -599,10 +677,13 @@ def buffer_list_update_callback(data, somecount):
# eventrouter.weechat_controller.set_refresh_buffer_list(False)
return w.WEECHAT_RC_OK
+
def quit_notification_callback(signal, sig_type, data):
stop_talking_to_slack()
+
def typing_notification_cb(signal, sig_type, data):
+ data = decode_from_utf8(data)
msg = w.buffer_get_string(data, "input")
if len(msg) > 8 and msg[:1] != "/":
global typing_timer
@@ -617,11 +698,15 @@ def typing_notification_cb(signal, sig_type, data):
typing_timer = now
return w.WEECHAT_RC_OK
+
def typing_update_cb(data, remaining_calls):
+ data = decode_from_utf8(data)
w.bar_item_update("slack_typing_notice")
return w.WEECHAT_RC_OK
+
def slack_never_away_cb(data, remaining_calls):
+ data = decode_from_utf8(data)
if config.never_away:
for t in EVENTROUTER.teams.values():
slackbot = t.get_channel_map()['slackbot']
@@ -630,6 +715,7 @@ def slack_never_away_cb(data, remaining_calls):
channel.team.send_to_websocket(request, expect_reply=False)
return w.WEECHAT_RC_OK
+
def typing_bar_item_cb(data, current_buffer, args):
"""
Privides a bar item indicating who is typing in the current channel AND
@@ -663,11 +749,14 @@ def typing_bar_item_cb(data, current_buffer, args):
return typing
+
def nick_completion_cb(data, completion_item, current_buffer, completion):
"""
Adds all @-prefixed nicks to completion list
"""
+ data = decode_from_utf8(data)
+ completion = decode_from_utf8(completion)
current_buffer = w.current_buffer()
current_channel = EVENTROUTER.weechat_controller.buffers.get(current_buffer, None)
@@ -679,11 +768,14 @@ def nick_completion_cb(data, completion_item, current_buffer, completion):
w.hook_completion_list_add(completion, "@" + u.slack_name, 1, w.WEECHAT_LIST_POS_SORT)
return w.WEECHAT_RC_OK
+
def emoji_completion_cb(data, completion_item, current_buffer, completion):
"""
Adds all :-prefixed emoji to completion list
"""
+ data = decode_from_utf8(data)
+ completion = decode_from_utf8(completion)
current_buffer = w.current_buffer()
current_channel = EVENTROUTER.weechat_controller.buffers.get(current_buffer, None)
@@ -693,6 +785,7 @@ def emoji_completion_cb(data, completion_item, current_buffer, completion):
w.hook_completion_list_add(completion, ":" + e + ":", 0, w.WEECHAT_LIST_POS_SORT)
return w.WEECHAT_RC_OK
+
def complete_next_cb(data, current_buffer, command):
"""Extract current word, if it is equal to a nick, prefix it with @ and
rely on nick_completion_cb adding the @-prefixed versions to the
@@ -701,10 +794,12 @@ def complete_next_cb(data, current_buffer, command):
"""
+ data = decode_from_utf8(data)
+ command = decode_from_utf8(data)
current_buffer = w.current_buffer()
current_channel = EVENTROUTER.weechat_controller.buffers.get(current_buffer, None)
- #channel = channels.find(current_buffer)
+ # channel = channels.find(current_buffer)
if not hasattr(current_channel, 'members') or current_channel is None or current_channel.members is None:
return w.WEECHAT_RC_OK
@@ -739,10 +834,12 @@ def complete_next_cb(data, current_buffer, command):
return w.WEECHAT_RC_OK_EAT
return w.WEECHAT_RC_OK
+
def script_unloaded():
stop_talking_to_slack()
return w.WEECHAT_RC_OK
+
def stop_talking_to_slack():
"""
complete
@@ -753,15 +850,16 @@ def stop_talking_to_slack():
EVENTROUTER.shutdown()
return w.WEECHAT_RC_OK
-
##### New Classes
+
class SlackRequest(object):
"""
complete
Encapsulates a Slack api request. Valuable as an object that we can add to the queue and/or retry.
makes a SHA of the requst url and current time so we can re-tag this on the way back through.
"""
+
def __init__(self, token, request, post_data={}, **kwargs):
for key, value in kwargs.items():
setattr(self, key, value)
@@ -774,31 +872,37 @@ class SlackRequest(object):
post_data["token"] = token
self.post_data = post_data
self.params = {'useragent': 'wee_slack {}'.format(SCRIPT_VERSION)}
- self.url = 'https://{}/api/{}?{}'.format(self.domain, request, urllib.urlencode(post_data))
+ self.url = 'https://{}/api/{}?{}'.format(self.domain, request, urllib.urlencode(encode_to_utf8(post_data)))
self.response_id = sha.sha("{}{}".format(self.url, self.start_time)).hexdigest()
self.retries = kwargs.get('retries', 3)
# def __repr__(self):
# return "URL: {} Tries: {} ID: {}".format(self.url, self.tries, self.response_id)
+
def request_string(self):
return "{}".format(self.url)
+
def tried(self):
self.tries += 1
self.response_id = sha.sha("{}{}".format(self.url, time.time())).hexdigest()
+
def should_try(self):
return self.tries < self.retries
+
def retry_ready(self):
return (self.start_time + (self.tries**2)) < time.time()
+
class SlackTeam(object):
"""
incomplete
Team object under which users and channels live.. Does lots.
"""
+
def __init__(self, eventrouter, token, websocket_url, subdomain, nick, myidentifier, users, bots, channels, **kwargs):
self.ws_url = websocket_url
self.connected = False
self.connecting = False
- #self.ws = None
+ # self.ws = None
self.ws_counter = 0
self.ws_replies = {}
self.eventrouter = eventrouter
@@ -819,7 +923,6 @@ class SlackTeam(object):
self.users = users
self.bots = bots
self.team_hash = SlackTeam.generate_team_hash(self.nick, self.subdomain)
- #self.team_hash = str(sha.sha("{}{}".format(self.nick, self.subdomain)).hexdigest())
self.name = self.domain
self.channel_buffer = None
self.got_history = True
@@ -833,21 +936,26 @@ class SlackTeam(object):
self.users[self.myidentifier].force_color(w.config_string(w.config_get('weechat.color.chat_nick_self')))
# This highlight step must happen after we have set related server
self.set_highlight_words(kwargs.get('highlight_words', ""))
+
def __eq__(self, compare_str):
if compare_str == self.token or compare_str == self.domain or compare_str == self.subdomain:
return True
else:
return False
+
def add_channel(self, channel):
self.channels[channel["id"]] = channel
channel.set_related_server(self)
-# def connect_request_generate(self):
-# return SlackRequest(self.token, 'rtm.start', {})
- #def close_all_buffers(self):
+
+ # def connect_request_generate(self):
+ # return SlackRequest(self.token, 'rtm.start', {})
+
+ # def close_all_buffers(self):
# for channel in self.channels:
# self.eventrouter.weechat_controller.unregister_buffer(channel.channel_buffer, update_remote=False, close_buffer=True)
# #also close this server buffer
# self.eventrouter.weechat_controller.unregister_buffer(self.channel_buffer, update_remote=False, close_buffer=True)
+
def create_buffer(self):
if not self.channel_buffer:
if config.short_buffer_names:
@@ -864,40 +972,54 @@ class SlackTeam(object):
if w.config_string(w.config_get('irc.look.server_buffer')) == 'merge_with_core':
w.buffer_merge(self.channel_buffer, w.buffer_search_main())
w.buffer_set(self.channel_buffer, "nicklist", "1")
+
def set_muted_channels(self, muted_str):
self.muted_channels = {x for x in muted_str.split(',')}
+
def set_highlight_words(self, highlight_str):
self.highlight_words = {x for x in highlight_str.split(',')}
if len(self.highlight_words) > 0:
for v in self.channels.itervalues():
v.set_highlights()
+
def formatted_name(self, **kwargs):
return self.domain
+
def buffer_prnt(self, data):
w.prnt_date_tags(self.channel_buffer, SlackTS().major, tag("backlog"), data)
+
def get_channel_map(self):
return {v.slack_name: k for k, v in self.channels.iteritems()}
+
def get_username_map(self):
return {v.slack_name: k for k, v in self.users.iteritems()}
+
def get_team_hash(self):
return self.team_hash
+
@staticmethod
def generate_team_hash(nick, subdomain):
return str(sha.sha("{}{}".format(nick, subdomain)).hexdigest())
+
def refresh(self):
self.rename()
+
def rename(self):
pass
- #def attach_websocket(self, ws):
+
+ # def attach_websocket(self, ws):
# self.ws = ws
+
def is_user_present(self, user_id):
user = self.users.get(user_id)
if user.presence == 'active':
return True
else:
return False
+
def mark_read(self):
pass
+
def connect(self):
if not self.connected and not self.connecting:
self.connecting = True
@@ -907,7 +1029,7 @@ class SlackTeam(object):
w.hook_fd(ws.sock._sock.fileno(), 1, 0, 0, "receive_ws_callback", self.get_team_hash())
ws.sock.setblocking(0)
self.ws = ws
- #self.attach_websocket(ws)
+ # self.attach_websocket(ws)
self.set_connected()
self.connecting = False
except Exception as e:
@@ -915,42 +1037,49 @@ class SlackTeam(object):
self.connecting = False
return False
else:
- #The fast reconnect failed, so start over-ish
+ # The fast reconnect failed, so start over-ish
for chan in self.channels:
self.channels[chan].got_history = False
s = SlackRequest(self.token, 'rtm.start', {}, retries=999)
self.eventrouter.receive(s)
self.connecting = False
- #del self.eventrouter.teams[self.get_team_hash()]
+ # del self.eventrouter.teams[self.get_team_hash()]
self.set_reconnect_url(None)
+
def set_connected(self):
self.connected = True
+
def set_disconnected(self):
self.connected = False
+
def set_reconnect_url(self, url):
self.ws_url = url
+
def next_ws_transaction_id(self):
if self.ws_counter > 999:
self.ws_counter = 0
self.ws_counter += 1
return self.ws_counter
+
def send_to_websocket(self, data, expect_reply=True):
data["id"] = self.next_ws_transaction_id()
message = json.dumps(data)
try:
if expect_reply:
self.ws_replies[data["id"]] = data
- self.ws.send(message)
+ self.ws.send(encode_to_utf8(message))
dbg("Sent {}...".format(message[:100]))
except:
print "WS ERROR"
dbg("Unexpected error: {}\nSent: {}".format(sys.exc_info()[0], data))
self.set_connected()
+
class SlackChannel(object):
"""
Represents an individual slack channel.
"""
+
def __init__(self, eventrouter, **kwargs):
# We require these two things for a vaid object,
# the rest we can just learn from slack
@@ -964,7 +1093,6 @@ class SlackChannel(object):
self.slack_purpose = kwargs.get("purpose", {"value": ""})
self.identifier = kwargs["id"]
self.last_read = SlackTS(kwargs.get("last_read", SlackTS()))
- #print self.last_read
self.channel_buffer = None
self.team = kwargs.get('team', None)
self.got_history = False
@@ -974,20 +1102,25 @@ class SlackChannel(object):
self.typing = {}
self.type = 'channel'
self.set_name(self.slack_name)
- #short name relates to the localvar we change for typing indication
+ # short name relates to the localvar we change for typing indication
self.current_short_name = self.name
self.update_nicklist()
+
def __eq__(self, compare_str):
if compare_str == self.slack_name or compare_str == self.formatted_name() or compare_str == self.formatted_name(style="long_default"):
return True
else:
return False
+
def __repr__(self):
return "Name:{} Identifier:{}".format(self.name, self.identifier)
+
def set_name(self, slack_name):
self.name = "#" + slack_name
+
def refresh(self):
return self.rename()
+
def rename(self):
if self.channel_buffer:
new_name = self.formatted_name(typing=self.is_someone_typing(), style="sidebar")
@@ -996,6 +1129,7 @@ class SlackChannel(object):
w.buffer_set(self.channel_buffer, "short_name", new_name)
return True
return False
+
def formatted_name(self, style="default", typing=False, **kwargs):
if config.channel_name_typing_indicator:
if not typing:
@@ -1012,20 +1146,20 @@ class SlackChannel(object):
"long_base": "{}.{}".format(self.team.preferred_name, self.slack_name),
}
return select[style]
+
def render_topic(self, topic=None):
if self.channel_buffer:
if not topic:
if self.slack_topic['value'] != "":
- encoded_topic = self.slack_topic['value'].encode('utf-8')
+ topic = self.slack_topic['value']
else:
- encoded_topic = self.slack_purpose['value'].encode('utf-8')
- else:
- encoded_topic = topic.encode('utf-8')
- self.encoded_topic = topic.encode('utf-8')
- w.buffer_set(self.channel_buffer, "title", encoded_topic)
+ topic = self.slack_purpose['value']
+ w.buffer_set(self.channel_buffer, "title", topic)
+
def update_from_message_json(self, message_json):
for key, value in message_json.items():
setattr(self, key, value)
+
def open(self, update_remote=True):
if update_remote:
if "join" in SLACK_API_TRANSLATOR[self.type]:
@@ -1037,7 +1171,8 @@ class SlackChannel(object):
if "info" in SLACK_API_TRANSLATOR[self.type]:
s = SlackRequest(self.team.token, SLACK_API_TRANSLATOR[self.type]["info"], {"name": self.identifier}, team_hash=self.team.team_hash, channel_identifier=self.identifier)
self.eventrouter.receive(s)
- #self.create_buffer()
+ # self.create_buffer()
+
def check_should_open(self, force=False):
try:
if self.is_archived:
@@ -1055,14 +1190,17 @@ class SlackChannel(object):
self.get_history(slow_queue=True)
except:
pass
+
def set_related_server(self, team):
self.team = team
+
def set_highlights(self):
- #highlight my own name and any set highlights
+ # highlight my own name and any set highlights
if self.channel_buffer:
highlights = self.team.highlight_words.union({'@' + self.team.nick, "!here", "!channel", "!everyone"})
h_str = ",".join(highlights)
w.buffer_set(self.channel_buffer, "highlight_words", h_str)
+
def create_buffer(self):
"""
incomplete (muted doesn't work)
@@ -1081,11 +1219,11 @@ class SlackChannel(object):
self.render_topic()
self.eventrouter.weechat_controller.set_refresh_buffer_list(True)
if self.channel_buffer:
- #if self.team.server_alias:
- #w.buffer_set(self.channel_buffer, "localvar_set_server", self.team.server_alias)
- #else:
+ # if self.team.server_alias:
+ # w.buffer_set(self.channel_buffer, "localvar_set_server", self.team.server_alias)
+ # else:
w.buffer_set(self.channel_buffer, "localvar_set_server", self.team.preferred_name)
- #else:
+ # else:
# self.eventrouter.weechat_controller.register_buffer(self.channel_buffer, self)
try:
for c in range(self.unread_count_display):
@@ -1095,40 +1233,42 @@ class SlackChannel(object):
w.buffer_set(self.channel_buffer, "hotlist", "1")
else:
pass
- #dbg("no unread in {}".format(self.name))
+ # dbg("no unread in {}".format(self.name))
except:
pass
self.update_nicklist()
- #dbg("exception no unread count")
- #if self.unread_count != 0 and not self.muted:
+ # dbg("exception no unread count")
+ # if self.unread_count != 0 and not self.muted:
# w.buffer_set(self.channel_buffer, "hotlist", "1")
+
def destroy_buffer(self, update_remote):
if self.channel_buffer is not None:
self.channel_buffer = None
self.messages = {}
self.hashed_messages = {}
self.got_history = False
- #if update_remote and not eventrouter.shutting_down:
+ # if update_remote and not eventrouter.shutting_down:
self.active = False
if update_remote and not self.eventrouter.shutting_down:
s = SlackRequest(self.team.token, SLACK_API_TRANSLATOR[self.type]["leave"], {"channel": self.identifier}, team_hash=self.team.team_hash, channel_identifier=self.identifier)
self.eventrouter.receive(s)
+
def buffer_prnt(self, nick, text, timestamp=str(time.time()), tagset=None, tag_nick=None, **kwargs):
data = "{}\t{}".format(nick, text)
ts = SlackTS(timestamp)
last_read = SlackTS(self.last_read)
- #without this, DMs won't open automatically
+ # without this, DMs won't open automatically
if not self.channel_buffer and ts > last_read:
self.open(update_remote=False)
if self.channel_buffer:
- #backlog messages - we will update the read marker as we print these
+ # backlog messages - we will update the read marker as we print these
backlog = True if ts <= last_read else False
if tagset:
tags = tag(tagset, user=tag_nick)
self.new_messages = True
- #we have to infer the tagset because we weren't told
+ # we have to infer the tagset because we weren't told
elif ts <= last_read:
tags = tag("backlog", user=tag_nick)
elif self.type in ["im", "mpdm"]:
@@ -1151,14 +1291,16 @@ class SlackChannel(object):
self.mark_read(ts, update_remote=False, force=True)
except:
dbg("Problem processing buffer_prnt")
+
def send_message(self, message, request_dict_ext={}):
- #team = self.eventrouter.teams[self.team]
+ # team = self.eventrouter.teams[self.team]
message = linkify_text(message, self.team, self)
dbg(message)
request = {"type": "message", "channel": self.identifier, "text": message, "_team": self.team.team_hash, "user": self.team.myidentifier}
request.update(request_dict_ext)
self.team.send_to_websocket(request)
self.mark_read(update_remote=False, force=True)
+
def store_message(self, message, team, from_me=False):
if not self.active:
return
@@ -1173,6 +1315,7 @@ class SlackChannel(object):
if msg_to_delete.hash:
del self.hashed_messages[msg_to_delete.hash]
del self.messages[k]
+
def change_message(self, ts, text=None, suffix=None):
ts = SlackTS(ts)
if ts in self.messages:
@@ -1184,6 +1327,7 @@ class SlackChannel(object):
text = m.render(force=True)
modify_buffer_line(self.channel_buffer, text, ts.major, ts.minor)
return True
+
def edit_previous_message(self, old, new, flags):
message = self.my_last_message()
if new == "" and old == "":
@@ -1195,18 +1339,21 @@ class SlackChannel(object):
num_replace = 0
new_message = re.sub(old, new, message["text"], num_replace)
if new_message != message["text"]:
- s = SlackRequest(self.team.token, "chat.update", {"channel": self.identifier, "ts": message['ts'], "text": new_message.encode("utf-8")}, team_hash=self.team.team_hash, channel_identifier=self.identifier)
+ s = SlackRequest(self.team.token, "chat.update", {"channel": self.identifier, "ts": message['ts'], "text": new_message}, team_hash=self.team.team_hash, channel_identifier=self.identifier)
self.eventrouter.receive(s)
+
def my_last_message(self):
for message in reversed(self.sorted_message_keys()):
m = self.messages[message]
if "user" in m.message_json and "text" in m.message_json and m.message_json["user"] == self.team.myidentifier:
return m.message_json
+
def is_visible(self):
return w.buffer_get_integer(self.channel_buffer, "hidden") == 0
+
def get_history(self, slow_queue=False):
if not self.got_history:
- #we have probably reconnected. flush the buffer
+ # we have probably reconnected. flush the buffer
if self.team.connected:
w.buffer_clear(self.channel_buffer)
self.buffer_prnt('', 'getting channel history...', tagset='backlog')
@@ -1216,32 +1363,39 @@ class SlackChannel(object):
else:
self.eventrouter.receive_slow(s)
self.got_history = True
+
def send_add_reaction(self, msg_number, reaction):
self.send_change_reaction("reactions.add", msg_number, reaction)
+
def send_remove_reaction(self, msg_number, reaction):
self.send_change_reaction("reactions.remove", msg_number, reaction)
+
def send_change_reaction(self, method, msg_number, reaction):
if 0 < msg_number < len(self.messages):
timestamp = self.sorted_message_keys()[-msg_number]
data = {"channel": self.identifier, "timestamp": timestamp, "name": reaction}
s = SlackRequest(self.team.token, method, data)
self.eventrouter.receive(s)
+
def sorted_message_keys(self):
keys = []
for k in self.messages:
if type(self.messages[k]) == SlackMessage:
keys.append(k)
return sorted(keys)
+
# Typing related
def set_typing(self, user):
if self.channel_buffer and self.is_visible():
self.typing[user] = time.time()
self.eventrouter.weechat_controller.set_refresh_buffer_list(True)
+
def unset_typing(self, user):
if self.channel_buffer and self.is_visible():
u = self.typing.get(user, None)
if u:
self.eventrouter.weechat_controller.set_refresh_buffer_list(True)
+
def is_someone_typing(self):
"""
Walks through dict of typing folks in a channel and fast
@@ -1255,6 +1409,7 @@ class SlackChannel(object):
self.typing = {}
self.eventrouter.weechat_controller.set_refresh_buffer_list(True)
return False
+
def get_typing_list(self):
"""
Returns the names of everyone in the channel who is currently typing.
@@ -1266,6 +1421,7 @@ class SlackChannel(object):
else:
del self.typing[user]
return typing
+
def mark_read(self, ts=None, update_remote=True, force=False):
if not ts:
ts = SlackTS()
@@ -1277,16 +1433,17 @@ class SlackChannel(object):
s = SlackRequest(self.team.token, SLACK_API_TRANSLATOR[self.type]["mark"], {"channel": self.identifier, "ts": ts}, team_hash=self.team.team_hash, channel_identifier=self.identifier)
self.eventrouter.receive(s)
self.new_messages = False
+
def user_joined(self, user_id):
- #ugly hack - for some reason this gets turned into a list
+ # ugly hack - for some reason this gets turned into a list
self.members = set(self.members)
self.members.add(user_id)
self.update_nicklist(user_id)
+
def user_left(self, user_id):
- #pass
- #filter(lambda u: u != user_id, self.members)
self.members.discard(user_id)
self.update_nicklist(user_id)
+
def update_nicklist(self, user=None):
if not self.channel_buffer:
return
@@ -1295,12 +1452,12 @@ class SlackChannel(object):
w.buffer_set(self.channel_buffer, "nicklist", "1")
# create nicklists for the current channel if they don't exist
# if they do, use the existing pointer
- #TODO: put this back for mithrandir
- #here = w.nicklist_search_group(self.channel_buffer, '', NICK_GROUP_HERE)
- #if not here:
+ # TODO: put this back for mithrandir
+ # here = w.nicklist_search_group(self.channel_buffer, '', NICK_GROUP_HERE)
+ # if not here:
# here = w.nicklist_add_group(self.channel_buffer, '', NICK_GROUP_HERE, "weechat.color.nicklist_group", 1)
- #afk = w.nicklist_search_group(self.channel_buffer, '', NICK_GROUP_AWAY)
- #if not afk:
+ # afk = w.nicklist_search_group(self.channel_buffer, '', NICK_GROUP_AWAY)
+ # if not afk:
# afk = w.nicklist_add_group(self.channel_buffer, '', NICK_GROUP_AWAY, "weechat.color.nicklist_group", 1)
if user and len(self.members) < 1000:
@@ -1311,7 +1468,7 @@ class SlackChannel(object):
# now add it back in to whichever..
if user.identifier in self.members:
w.nicklist_add_nick(self.channel_buffer, "", user.name, user.color_name, "", "", 1)
- #w.nicklist_add_nick(self.channel_buffer, here, user.name, user.color_name, "", "", 1)
+ # w.nicklist_add_nick(self.channel_buffer, here, user.name, user.color_name, "", "", 1)
# if we didn't get a user, build a complete list. this is expensive.
else:
@@ -1322,12 +1479,13 @@ class SlackChannel(object):
if user.deleted:
continue
w.nicklist_add_nick(self.channel_buffer, "", user.name, user.color_name, "", "", 1)
- #w.nicklist_add_nick(self.channel_buffer, here, user.name, user.color_name, "", "", 1)
+ # w.nicklist_add_nick(self.channel_buffer, here, user.name, user.color_name, "", "", 1)
except Exception as e:
dbg("DEBUG: {} {} {}".format(self.identifier, self.name, e))
else:
for fn in ["1| too", "2| many", "3| users", "4| to", "5| show"]:
w.nicklist_add_group(self.channel_buffer, '', fn, w.color('white'), 1)
+
def hash_message(self, ts):
ts = SlackTS(ts)
@@ -1337,15 +1495,15 @@ class SlackChannel(object):
if ts in self.messages and not self.messages[ts].hash:
message = self.messages[ts]
tshash = calc_hash(message)
- l = 3
- shorthash = tshash[:l]
+ hl = 3
+ shorthash = tshash[:hl]
while any(x.startswith(shorthash) for x in self.hashed_messages):
- l += 1
- shorthash = tshash[:l]
+ hl += 1
+ shorthash = tshash[:hl]
if shorthash[:-1] in self.hashed_messages:
col_msg = self.hashed_messages.pop(shorthash[:-1])
- col_new_hash = calc_hash(col_msg)[:l]
+ col_new_hash = calc_hash(col_msg)[:hl]
col_msg.hash = col_new_hash
self.hashed_messages[col_new_hash] = col_msg
self.change_message(str(col_msg.ts))
@@ -1361,6 +1519,7 @@ class SlackDMChannel(SlackChannel):
Subclass of a normal channel for person-to-person communication, which
has some important differences.
"""
+
def __init__(self, eventrouter, users, **kwargs):
dmuser = kwargs["user"]
kwargs["name"] = users[dmuser].name
@@ -1368,19 +1527,23 @@ class SlackDMChannel(SlackChannel):
self.type = 'im'
self.update_color()
self.set_name(self.slack_name)
+
def set_name(self, slack_name):
self.name = slack_name
+
def create_buffer(self):
if not self.channel_buffer:
super(SlackDMChannel, self).create_buffer()
w.buffer_set(self.channel_buffer, "localvar_set_type", 'private')
+
def update_color(self):
if config.colorize_private_chats:
- self.color_name = w.info_get('irc_nick_color_name', self.name.encode('utf-8'))
+ self.color_name = w.info_get('irc_nick_color_name', self.name)
self.color = w.color(self.color_name)
else:
self.color = ""
self.color_name = ""
+
def formatted_name(self, style="default", typing=False, present=True, enable_color=False, **kwargs):
if config.colorize_private_chats and enable_color:
print_color = self.color
@@ -1398,9 +1561,10 @@ class SlackDMChannel(SlackChannel):
"long_base": "{}.{}".format(self.team.preferred_name, self.slack_name),
}
return print_color + select[style]
+
def open(self, update_remote=True):
self.create_buffer()
- #self.active = True
+ # self.active = True
self.get_history()
if "info" in SLACK_API_TRANSLATOR[self.type]:
s = SlackRequest(self.team.token, SLACK_API_TRANSLATOR[self.type]["info"], {"name": self.identifier}, team_hash=self.team.team_hash, channel_identifier=self.identifier)
@@ -1410,6 +1574,7 @@ class SlackDMChannel(SlackChannel):
s = SlackRequest(self.team.token, SLACK_API_TRANSLATOR[self.type]["join"], {"user": self.user}, team_hash=self.team.team_hash, channel_identifier=self.identifier)
self.eventrouter.receive(s)
self.create_buffer()
+
def rename(self):
if self.channel_buffer:
new_name = self.formatted_name(style="sidebar", present=self.team.is_user_present(self.user), enable_color=config.colorize_private_chats)
@@ -1418,6 +1583,7 @@ class SlackDMChannel(SlackChannel):
w.buffer_set(self.channel_buffer, "short_name", new_name)
return True
return False
+
def refresh(self):
return self.rename()
@@ -1426,26 +1592,32 @@ class SlackGroupChannel(SlackChannel):
"""
A group channel is a private discussion group.
"""
+
def __init__(self, eventrouter, **kwargs):
super(SlackGroupChannel, self).__init__(eventrouter, **kwargs)
self.name = "#" + kwargs['name']
self.type = "group"
self.set_name(self.slack_name)
+
def set_name(self, slack_name):
self.name = "#" + slack_name
- #def formatted_name(self, prepend="#", enable_color=True, basic=False):
+
+ # def formatted_name(self, prepend="#", enable_color=True, basic=False):
# return prepend + self.slack_name
+
class SlackMPDMChannel(SlackChannel):
"""
An MPDM channel is a special instance of a 'group' channel.
We change the name to look less terrible in weechat.
"""
+
def __init__(self, eventrouter, **kwargs):
super(SlackMPDMChannel, self).__init__(eventrouter, **kwargs)
n = kwargs.get('name')
self.set_name(n)
self.type = "group"
+
def open(self, update_remote=False):
self.create_buffer()
self.active = True
@@ -1453,9 +1625,11 @@ class SlackMPDMChannel(SlackChannel):
if "info" in SLACK_API_TRANSLATOR[self.type]:
s = SlackRequest(self.team.token, SLACK_API_TRANSLATOR[self.type]["info"], {"name": self.identifier}, team_hash=self.team.team_hash, channel_identifier=self.identifier)
self.eventrouter.receive(s)
- #self.create_buffer()
+ # self.create_buffer()
+
def set_name(self, n):
self.name = "|".join("-".join(n.split("-")[1:-1]).split("--"))
+
def formatted_name(self, style="default", typing=False, **kwargs):
adjusted_name = "|".join("-".join(self.slack_name.split("-")[1:-1]).split("--"))
if config.channel_name_typing_indicator:
@@ -1474,28 +1648,29 @@ class SlackMPDMChannel(SlackChannel):
}
return select[style]
-# def formatted_name(self, **kwargs):
-# return self.name
def rename(self):
pass
+
class SlackThreadChannel(object):
"""
A thread channel is a virtual channel. We don't inherit from
SlackChannel, because most of how it operates will be different.
"""
+
def __init__(self, eventrouter, parent_message):
self.eventrouter = eventrouter
self.parent_message = parent_message
self.channel_buffer = None
- #self.identifier = ""
- #self.name = "#" + kwargs['name']
+ # self.identifier = ""
+ # self.name = "#" + kwargs['name']
self.type = "thread"
self.got_history = False
self.label = None
- #self.set_name(self.slack_name)
- #def set_name(self, slack_name):
+ # self.set_name(self.slack_name)
+ # def set_name(self, slack_name):
# self.name = "#" + slack_name
+
def formatted_name(self, style="default", **kwargs):
hash_or_ts = self.parent_message.hash or self.parent_message.ts
styles = {
@@ -1504,8 +1679,10 @@ class SlackThreadChannel(object):
"sidebar": " +{}".format(hash_or_ts),
}
return styles[style]
+
def refresh(self):
self.rename()
+
def mark_read(self, ts=None, update_remote=True, force=False):
if self.channel_buffer:
w.buffer_set(self.channel_buffer, "unread", "")
@@ -1515,40 +1692,41 @@ class SlackThreadChannel(object):
data = "{}\t{}".format(nick, text)
ts = SlackTS(timestamp)
if self.channel_buffer:
- #backlog messages - we will update the read marker as we print these
- #backlog = False
- #if ts <= SlackTS(self.last_read):
+ # backlog messages - we will update the read marker as we print these
+ # backlog = False
+ # if ts <= SlackTS(self.last_read):
# tags = tag("backlog")
# backlog = True
- #elif self.type in ["im", "mpdm"]:
+ # elif self.type in ["im", "mpdm"]:
# tags = tag("dm")
# self.new_messages = True
- #else:
+ # else:
tags = tag("default")
- #self.new_messages = True
+ # self.new_messages = True
w.prnt_date_tags(self.channel_buffer, ts.major, tags, data)
modify_print_time(self.channel_buffer, ts.minorstr(), ts.major)
- #if backlog:
+ # if backlog:
# self.mark_read(ts, update_remote=False, force=True)
+
def get_history(self):
self.got_history = True
for message in self.parent_message.submessages:
- #message = SlackMessage(message_json, team, channel)
+ # message = SlackMessage(message_json, team, channel)
text = message.render()
- #print text
+ # print text
suffix = ''
if 'edited' in message.message_json:
suffix = ' (edited)'
- #try:
+ # try:
# channel.unread_count += 1
- #except:
+ # except:
# channel.unread_count = 1
self.buffer_prnt(message.sender, text + suffix, message.ts)
def send_message(self, message):
- #team = self.eventrouter.teams[self.team]
+ # team = self.eventrouter.teams[self.team]
message = linkify_text(message, self.parent_message.team, self)
dbg(message)
request = {"type": "message", "channel": self.parent_message.channel.identifier, "text": message, "_team": self.parent_message.team.team_hash, "user": self.parent_message.team.myidentifier, "thread_ts": str(self.parent_message.ts)}
@@ -1559,10 +1737,10 @@ class SlackThreadChannel(object):
self.create_buffer()
self.active = True
self.get_history()
- #if "info" in SLACK_API_TRANSLATOR[self.type]:
+ # if "info" in SLACK_API_TRANSLATOR[self.type]:
# s = SlackRequest(self.team.token, SLACK_API_TRANSLATOR[self.type]["info"], {"name": self.identifier}, team_hash=self.team.team_hash, channel_identifier=self.identifier)
# self.eventrouter.receive(s)
- #if update_remote:
+ # if update_remote:
# if "join" in SLACK_API_TRANSLATOR[self.type]:
# s = SlackRequest(self.team.token, SLACK_API_TRANSLATOR[self.type]["join"], {"name": self.name}, team_hash=self.team.team_hash, channel_identifier=self.identifier)
# self.eventrouter.receive(s)
@@ -1586,11 +1764,11 @@ class SlackThreadChannel(object):
time_format = w.config_string(w.config_get("weechat.look.buffer_time_format"))
parent_time = time.localtime(SlackTS(self.parent_message.ts).major)
topic = '{} {} | {}'.format(time.strftime(time_format, parent_time), self.parent_message.sender, self.parent_message.render() )
- w.buffer_set(self.channel_buffer, "title", topic.encode('utf-8'))
+ w.buffer_set(self.channel_buffer, "title", topic)
- #self.eventrouter.weechat_controller.set_refresh_buffer_list(True)
+ # self.eventrouter.weechat_controller.set_refresh_buffer_list(True)
- #try:
+ # try:
# if self.unread_count != 0:
# for c in range(1, self.unread_count):
# if self.type == "im":
@@ -1600,22 +1778,25 @@ class SlackThreadChannel(object):
# else:
# pass
# #dbg("no unread in {}".format(self.name))
- #except:
+ # except:
# pass
- #dbg("exception no unread count")
- #if self.unread_count != 0 and not self.muted:
+ # dbg("exception no unread count")
+ # if self.unread_count != 0 and not self.muted:
# w.buffer_set(self.channel_buffer, "hotlist", "1")
+
def destroy_buffer(self, update_remote):
if self.channel_buffer is not None:
self.channel_buffer = None
self.got_history = False
- #if update_remote and not eventrouter.shutting_down:
+ # if update_remote and not eventrouter.shutting_down:
self.active = False
+
class SlackUser(object):
"""
Represends an individual slack user. Also where you set their name formatting.
"""
+
def __init__(self, **kwargs):
# We require these two things for a vaid object,
# the rest we can just learn from slack
@@ -1625,22 +1806,27 @@ class SlackUser(object):
for key, value in kwargs.items():
setattr(self, key, value)
self.update_color()
+
def __repr__(self):
return "Name:{} Identifier:{}".format(self.name, self.identifier)
+
def force_color(self, color_name):
self.color_name = color_name
self.color = w.color(self.color_name)
+
def update_color(self):
# This will automatically be none/"" if the user has disabled nick
# colourization.
- self.color_name = w.info_get('nick_color_name', self.name.encode('utf-8'))
+ self.color_name = w.info_get('nick_color_name', self.name)
self.color = w.color(self.color_name)
+
def formatted_name(self, prepend="", enable_color=True):
if enable_color:
return self.color + prepend + self.name
else:
return prepend + self.name
+
class SlackBot(SlackUser):
"""
Basically the same as a user, but split out to identify and for future
@@ -1649,6 +1835,7 @@ class SlackBot(SlackUser):
def __init__(self, **kwargs):
super(SlackBot, self).__init__(**kwargs)
+
class SlackMessage(object):
"""
Represents a single slack message and associated context/metadata.
@@ -1673,7 +1860,7 @@ class SlackMessage(object):
self.suffix = ''
self.ts = SlackTS(message_json['ts'])
text = self.message_json.get('text', '')
- if text.startswith('_') and text.endswith('_') and not 'subtype' in message_json:
+ if text.startswith('_') and text.endswith('_') and 'subtype' not in message_json:
message_json['text'] = text[1:-1]
message_json['subtype'] = 'me_message'
if message_json.get('subtype') == 'me_message' and not message_json['text'].startswith(self.sender):
@@ -1681,22 +1868,26 @@ class SlackMessage(object):
def __hash__(self):
return hash(self.ts)
+
def render(self, force=False):
if len(self.submessages) > 0:
return "{} {} {}".format(render(self.message_json, self.team, self.channel, force), self.suffix, "{}[ Thread: {} Replies: {} ]".format(w.color(config.thread_suffix_color), self.hash or self.ts, len(self.submessages)))
return "{} {}".format(render(self.message_json, self.team, self.channel, force), self.suffix)
+
def change_text(self, new_text):
self.message_json["text"] = new_text
dbg(self.message_json)
+
def change_suffix(self, new_suffix):
self.suffix = new_suffix
dbg(self.message_json)
- def get_sender(self, utf8=True):
- name = u""
- name_plain = u""
+
+ def get_sender(self):
+ name = ""
+ name_plain = ""
if 'bot_id' in self.message_json and self.message_json['bot_id'] is not None:
- name = u"{} :]".format(self.team.bots[self.message_json["bot_id"]].formatted_name())
- name_plain = u"{}".format(self.team.bots[self.message_json["bot_id"]].formatted_name(enable_color=False))
+ name = "{} :]".format(self.team.bots[self.message_json["bot_id"]].formatted_name())
+ name_plain = "{}".format(self.team.bots[self.message_json["bot_id"]].formatted_name(enable_color=False))
elif 'user' in self.message_json:
if self.message_json['user'] == self.team.myidentifier:
name = self.team.users[self.team.myidentifier].name
@@ -1704,23 +1895,21 @@ class SlackMessage(object):
elif self.message_json['user'] in self.team.users:
u = self.team.users[self.message_json['user']]
if u.is_bot:
- name = u"{} :]".format(u.formatted_name())
+ name = "{} :]".format(u.formatted_name())
else:
- name = u"{}".format(u.formatted_name())
- name_plain = u"{}".format(u.formatted_name(enable_color=False))
+ name = "{}".format(u.formatted_name())
+ name_plain = "{}".format(u.formatted_name(enable_color=False))
elif 'username' in self.message_json:
- name = u"-{}-".format(self.message_json["username"])
- name_plain = u"{}".format(self.message_json["username"])
+ name = "-{}-".format(self.message_json["username"])
+ name_plain = "{}".format(self.message_json["username"])
elif 'service_name' in self.message_json:
- name = u"-{}-".format(self.message_json["service_name"])
- name_plain = u"{}".format(self.message_json["service_name"])
- else:
- name = u""
- name_plain = u""
- if utf8:
- return (name.encode('utf-8'), name_plain.encode('utf-8'))
+ name = "-{}-".format(self.message_json["service_name"])
+ name_plain = "{}".format(self.message_json["service_name"])
else:
- return (name, name_plain)
+ name = ""
+ name_plain = ""
+ return (name, name_plain)
+
def add_reaction(self, reaction, user):
m = self.message_json.get('reactions', None)
if m:
@@ -1730,9 +1919,10 @@ class SlackMessage(object):
r["users"].append(user)
found = True
if not found:
- self.message_json["reactions"].append({u"name": reaction, u"users": [user]})
+ self.message_json["reactions"].append({"name": reaction, "users": [user]})
else:
- self.message_json["reactions"] = [{u"name": reaction, u"users": [user]}]
+ self.message_json["reactions"] = [{"name": reaction, "users": [user]}]
+
def remove_reaction(self, reaction, user):
m = self.message_json.get('reactions', None)
if m:
@@ -1742,10 +1932,11 @@ class SlackMessage(object):
else:
pass
+
class SlackThreadMessage(SlackMessage):
+
def __init__(self, parent_id, *args):
super(SlackThreadMessage, self).__init__(*args)
- #super(SlackBot, self).__init__(**kwargs)
self.parent_id = parent_id
@@ -1753,18 +1944,23 @@ class WeeSlackMetadata(object):
"""
A simple container that we pickle/unpickle to hold data.
"""
+
def __init__(self, meta):
self.meta = meta
+
def jsonify(self):
return self.meta
+
class SlackTS(object):
+
def __init__(self, ts=None):
if ts:
self.major, self.minor = [int(x) for x in ts.split('.', 1)]
else:
self.major = int(time.time())
self.minor = 0
+
def __cmp__(self, other):
if isinstance(other, SlackTS):
if self.major < other.major:
@@ -1786,19 +1982,25 @@ class SlackTS(object):
return 1
elif s == other:
return 0
+
def __hash__(self):
return hash("{}.{}".format(self.major, self.minor))
+
def __repr__(self):
return str("{0}.{1:06d}".format(self.major, self.minor))
+
def split(self, *args, **kwargs):
return [self.major, self.minor]
+
def majorstr(self):
return str(self.major)
+
def minorstr(self):
return str(self.minor)
###### New handlers
+
def handle_rtmstart(login_data, eventrouter):
"""
This handles the main entry call to slack, rtm.start
@@ -1807,14 +2009,14 @@ def handle_rtmstart(login_data, eventrouter):
metadata = pickle.loads(login_data["wee_slack_request_metadata"])
- #Let's reuse a team if we have it already.
+ # Let's reuse a team if we have it already.
th = SlackTeam.generate_team_hash(login_data['self']['name'], login_data['team']['domain'])
if not eventrouter.teams.get(th):
users = {}
for item in login_data["users"]:
users[item["id"]] = SlackUser(**item)
- #users.append(SlackUser(**item))
+ # users.append(SlackUser(**item))
bots = {}
for item in login_data["bots"]:
@@ -1853,39 +2055,43 @@ def handle_rtmstart(login_data, eventrouter):
t.set_reconnect_url(login_data['url'])
t.connect()
- #web_socket_url = login_data['url']
- #try:
+ # web_socket_url = login_data['url']
+ # try:
# ws = create_connection(web_socket_url, sslopt=sslopt_ca_certs)
# w.hook_fd(ws.sock._sock.fileno(), 1, 0, 0, "receive_ws_callback", t.get_team_hash())
# #ws_hook = w.hook_fd(ws.sock._sock.fileno(), 1, 0, 0, "receive_ws_callback", pickle.dumps(t))
# ws.sock.setblocking(0)
# t.attach_websocket(ws)
# t.set_connected()
- #except Exception as e:
+ # except Exception as e:
# dbg("websocket connection error: {}".format(e))
# return False
t.buffer_prnt('Connected to Slack')
- t.buffer_prnt('{:<20} {}'.format(u"Websocket URL", login_data["url"]))
- t.buffer_prnt('{:<20} {}'.format(u"User name", login_data["self"]["name"]))
- t.buffer_prnt('{:<20} {}'.format(u"User ID", login_data["self"]["id"]))
- t.buffer_prnt('{:<20} {}'.format(u"Team name", login_data["team"]["name"]))
- t.buffer_prnt('{:<20} {}'.format(u"Team domain", login_data["team"]["domain"]))
- t.buffer_prnt('{:<20} {}'.format(u"Team id", login_data["team"]["id"]))
+ t.buffer_prnt('{:<20} {}'.format("Websocket URL", login_data["url"]))
+ t.buffer_prnt('{:<20} {}'.format("User name", login_data["self"]["name"]))
+ t.buffer_prnt('{:<20} {}'.format("User ID", login_data["self"]["id"]))
+ t.buffer_prnt('{:<20} {}'.format("Team name", login_data["team"]["name"]))
+ t.buffer_prnt('{:<20} {}'.format("Team domain", login_data["team"]["domain"]))
+ t.buffer_prnt('{:<20} {}'.format("Team id", login_data["team"]["id"]))
dbg("connected to {}".format(t.domain))
- #self.identifier = self.domain
+ # self.identifier = self.domain
+
def handle_groupshistory(message_json, eventrouter, **kwargs):
handle_history(message_json, eventrouter, **kwargs)
+
def handle_channelshistory(message_json, eventrouter, **kwargs):
handle_history(message_json, eventrouter, **kwargs)
+
def handle_imhistory(message_json, eventrouter, **kwargs):
handle_history(message_json, eventrouter, **kwargs)
+
def handle_history(message_json, eventrouter, **kwargs):
request_metadata = pickle.loads(message_json["wee_slack_request_metadata"])
kwargs['team'] = eventrouter.teams[request_metadata.team_hash]
@@ -1903,9 +2109,11 @@ def handle_history(message_json, eventrouter, **kwargs):
###### New/converted process_ and subprocess_ methods
+
def process_reconnect_url(message_json, eventrouter, **kwargs):
kwargs['team'].set_reconnect_url(message_json['url'])
+
def process_manual_presence_change(message_json, eventrouter, **kwargs):
process_presence_change(message_json, eventrouter, **kwargs)
@@ -1913,15 +2121,17 @@ def process_manual_presence_change(message_json, eventrouter, **kwargs):
def process_presence_change(message_json, eventrouter, **kwargs):
kwargs["user"].presence = message_json["presence"]
+
def process_pref_change(message_json, eventrouter, **kwargs):
team = kwargs["team"]
- if message_json['name'] == u'muted_channels':
+ if message_json['name'] == 'muted_channels':
team.set_muted_channels(message_json['value'])
- elif message_json['name'] == u'highlight_words':
+ elif message_json['name'] == 'highlight_words':
team.set_highlight_words(message_json['value'])
else:
dbg("Preference change not implemented: {}\n".format(message_json['name']))
+
def process_user_typing(message_json, eventrouter, **kwargs):
channel = kwargs["channel"]
team = kwargs["team"]
@@ -1929,19 +2139,22 @@ def process_user_typing(message_json, eventrouter, **kwargs):
channel.set_typing(team.users.get(message_json["user"]).name)
w.bar_item_update("slack_typing_notice")
+
def process_team_join(message_json, eventrouter, **kwargs):
user = message_json['user']
team = kwargs["team"]
team.users[user["id"]] = SlackUser(**user)
+
def process_pong(message_json, eventrouter, **kwargs):
pass
+
def process_message(message_json, eventrouter, store=True, **kwargs):
channel = kwargs["channel"]
team = kwargs["team"]
- #try:
- # send these subtype messages elsewhere
+ # try:
+ # send these subtype messages elsewhere
known_subtypes = [
'thread_message',
'message_replied',
@@ -1950,8 +2163,8 @@ def process_message(message_json, eventrouter, store=True, **kwargs):
'channel_join',
'channel_leave',
'channel_topic',
- #'group_join',
- #'group_leave',
+ # 'group_join',
+ # 'group_leave',
]
if "thread_ts" in message_json and "reply_count" not in message_json:
message_json["subtype"] = "thread_message"
@@ -1990,16 +2203,15 @@ def process_message(message_json, eventrouter, store=True, **kwargs):
if store:
channel.store_message(message, team)
dbg("NORMAL REPLY {}".format(message_json))
- #except:
- # channel.buffer_prnt("WEE-SLACK-ERROR", json.dumps(message_json).encode('utf-8'), message_json["ts"], **kwargs)
+ # except:
+ # channel.buffer_prnt("WEE-SLACK-ERROR", json.dumps(message_json), message_json["ts"], **kwargs)
# traceback.print_exc()
+
def subprocess_thread_message(message_json, eventrouter, channel, team):
- #print ("THREADED: " + str(message_json))
+ # print ("THREADED: " + str(message_json))
parent_ts = message_json.get('thread_ts', None)
if parent_ts:
- #parent_ts = SlackTS(parent_ts)
- parent_ts = parent_ts
parent_message = channel.messages.get(SlackTS(parent_ts), None)
if parent_message:
message = SlackThreadMessage(parent_ts, message_json, team, channel)
@@ -2009,7 +2221,7 @@ def subprocess_thread_message(message_json, eventrouter, channel, team):
channel.change_message(parent_ts)
text = message.render()
- #channel.buffer_prnt(message.sender, text, message.ts, **kwargs)
+ # channel.buffer_prnt(message.sender, text, message.ts, **kwargs)
if parent_message.thread_channel:
parent_message.thread_channel.buffer_prnt(message.sender, text, message.ts)
@@ -2025,11 +2237,12 @@ def subprocess_thread_message(message_json, eventrouter, channel, team):
# else:
# dbg("COULDN'T find orig message {}".format(message_json['thread_ts']), main_buffer=True)
- #if threadinfo[0]:
+ # if threadinfo[0]:
# channel.messages[threadinfo[1]].become_thread()
# message_json["item"]["ts"], message_json)
- #channel.change_message(message_json["thread_ts"], None, message_json["text"])
- #channel.become_thread(message_json["item"]["ts"], message_json)
+ # channel.change_message(message_json["thread_ts"], None, message_json["text"])
+ # channel.become_thread(message_json["item"]["ts"], message_json)
+
def subprocess_channel_join(message_json, eventrouter, channel, team):
joinprefix = w.prefix("join")
@@ -2037,23 +2250,25 @@ def subprocess_channel_join(message_json, eventrouter, channel, team):
channel.buffer_prnt(joinprefix, message.render(), message_json["ts"], tagset='joinleave')
channel.user_joined(message_json['user'])
+
def subprocess_channel_leave(message_json, eventrouter, channel, team):
leaveprefix = w.prefix("quit")
message = SlackMessage(message_json, team, channel, override_sender=leaveprefix)
channel.buffer_prnt(leaveprefix, message.render(), message_json["ts"], tagset='joinleave')
channel.user_left(message_json['user'])
- #channel.update_nicklist(message_json['user'])
- #channel.update_nicklist()
+ # channel.update_nicklist(message_json['user'])
+ # channel.update_nicklist()
+
def subprocess_message_replied(message_json, eventrouter, channel, team):
pass
- #print ("REPLIED: " + str(message_json))
+
def subprocess_message_changed(message_json, eventrouter, channel, team):
m = message_json.get("message", None)
if m:
new_message = m
- #message = SlackMessage(new_message, team, channel)
+ # message = SlackMessage(new_message, team, channel)
if "attachments" in m:
message_json["attachments"] = m["attachments"]
if "text" in m:
@@ -2075,17 +2290,17 @@ def subprocess_message_changed(message_json, eventrouter, channel, team):
else:
channel.change_message(new_message["ts"], new_message["text"])
+
def subprocess_message_deleted(message_json, eventrouter, channel, team):
channel.change_message(message_json["deleted_ts"], "(deleted)", '')
+
def subprocess_channel_topic(message_json, eventrouter, channel, team):
text = unfurl_refs(message_json["text"], ignore_alt_text=False)
- if type(text) != unicode:
- text = text.decode('utf-8', 'ignore')
- text = text.encode('utf-8')
channel.buffer_prnt(w.prefix("network").rstrip(), text, message_json["ts"], tagset="muted")
channel.render_topic(message_json["topic"])
+
def process_reply(message_json, eventrouter, **kwargs):
dbg('processing reply')
team = kwargs["team"]
@@ -2101,10 +2316,8 @@ def process_reply(message_json, eventrouter, **kwargs):
c = original_message_json.get('channel', None)
channel = team.channels[c]
m = SlackMessage(original_message_json, team, channel)
- # m = Message(message_json, server=server)
- #dbg(m, True)
- #if "type" in message_json:
+ # if "type" in message_json:
# if message_json["type"] == "message" and "channel" in message_json.keys():
# message_json["ts"] = message_json["ts"]
# channels.find(message_json["channel"]).store_message(m, from_me=True)
@@ -2117,6 +2330,7 @@ def process_reply(message_json, eventrouter, **kwargs):
except KeyError:
dbg("Unexpected reply {}".format(message_json))
+
def process_channel_marked(message_json, eventrouter, **kwargs):
"""
complete
@@ -2127,29 +2341,39 @@ def process_channel_marked(message_json, eventrouter, **kwargs):
channel.mark_read(ts=ts, force=True, update_remote=False)
else:
dbg("tried to mark something weird {}".format(message_json))
+
+
def process_group_marked(message_json, eventrouter, **kwargs):
process_channel_marked(message_json, eventrouter, **kwargs)
+
+
def process_im_marked(message_json, eventrouter, **kwargs):
process_channel_marked(message_json, eventrouter, **kwargs)
+
+
def process_mpim_marked(message_json, eventrouter, **kwargs):
process_channel_marked(message_json, eventrouter, **kwargs)
+
def process_channel_joined(message_json, eventrouter, **kwargs):
item = message_json["channel"]
kwargs['team'].channels[item["id"]].update_from_message_json(item)
kwargs['team'].channels[item["id"]].open()
+
def process_channel_created(message_json, eventrouter, **kwargs):
item = message_json["channel"]
c = SlackChannel(eventrouter, team=kwargs["team"], **item)
kwargs['team'].channels[item["id"]] = c
kwargs['team'].buffer_prnt('Channel created: {}'.format(c.slack_name))
+
def process_channel_rename(message_json, eventrouter, **kwargs):
item = message_json["channel"]
channel = kwargs['team'].channels[item["id"]]
channel.slack_name = message_json['channel']['name']
+
def process_im_created(message_json, eventrouter, **kwargs):
team = kwargs['team']
item = message_json["channel"]
@@ -2157,17 +2381,20 @@ def process_im_created(message_json, eventrouter, **kwargs):
team.channels[item["id"]] = c
kwargs['team'].buffer_prnt('IM channel created: {}'.format(c.name))
+
def process_im_open(message_json, eventrouter, **kwargs):
channel = kwargs['channel']
item = message_json
kwargs['team'].channels[item["channel"]].check_should_open(True)
w.buffer_set(channel.channel_buffer, "hotlist", "2")
+
def process_im_close(message_json, eventrouter, **kwargs):
item = message_json
cbuf = kwargs['team'].channels[item["channel"]].channel_buffer
eventrouter.weechat_controller.unregister_buffer(cbuf, False, True)
+
def process_group_joined(message_json, eventrouter, **kwargs):
item = message_json["channel"]
if item["name"].startswith("mpdm-"):
@@ -2177,6 +2404,7 @@ def process_group_joined(message_json, eventrouter, **kwargs):
kwargs['team'].channels[item["id"]] = c
kwargs['team'].channels[item["id"]].open()
+
def process_reaction_added(message_json, eventrouter, **kwargs):
channel = kwargs['team'].channels[message_json["item"]["channel"]]
if message_json["item"].get("type") == "message":
@@ -2189,6 +2417,7 @@ def process_reaction_added(message_json, eventrouter, **kwargs):
else:
dbg("reaction to item type not supported: " + str(message_json))
+
def process_reaction_removed(message_json, eventrouter, **kwargs):
channel = kwargs['team'].channels[message_json["item"]["channel"]]
if message_json["item"].get("type") == "message":
@@ -2203,6 +2432,7 @@ def process_reaction_removed(message_json, eventrouter, **kwargs):
###### New module/global methods
+
def render(message_json, team, channel, force=False):
# If we already have a rendered version in the object, just return that.
if not force and message_json.get("_rendered_text", ""):
@@ -2216,9 +2446,9 @@ def render(message_json, team, channel, force=False):
if message_json['text'] is not None:
text = message_json["text"]
else:
- text = u""
+ text = ""
else:
- text = u""
+ text = ""
text = unfurl_refs(text, ignore_alt_text=config.unfurl_ignore_alt_text)
@@ -2235,20 +2465,15 @@ def render(message_json, team, channel, force=False):
text = re.sub(r'(^| )_([^_]+)_([^a-zA-Z0-9_]|$)',
r'\1{}\2{}\3'.format(w.color('underline'), w.color('-underline')), text)
- if type(text) is not unicode:
- text = text.decode('UTF-8', 'replace')
- text = text.encode('utf-8')
-
# if self.threads:
# text += " [Replies: {} Thread ID: {} ] ".format(len(self.threads), self.thread_id)
# #for thread in self.threads:
text += create_reaction_string(message_json.get("reactions", ""))
-
message_json["_rendered_text"] = text
-
return text
+
def linkify_text(message, team, channel):
# The get_username_map function is a bit heavy, but this whole
# function is only called on message send..
@@ -2257,9 +2482,7 @@ def linkify_text(message, team, channel):
message = message.replace('\x02', '*').replace('\x1F', '_').split(' ')
for item in enumerate(message):
targets = re.match('^\s*([@#])([\w.-]+[\w. -])(\W*)', item[1])
- #print targets
if targets and targets.groups()[0] == '@':
- #print targets.groups()
named = targets.groups()
if named[1] in ["group", "channel", "here"]:
message[item[0]] = "<!{}>".format(named[1])
@@ -2277,9 +2500,10 @@ def linkify_text(message, team, channel):
except:
message[item[0]] = "#{}{}".format(named[1], named[2])
- #dbg(message)
+ # dbg(message)
return " ".join(message)
+
def unfurl_refs(text, ignore_alt_text=False):
"""
input : <@U096Q7CQM|someuser> has joined the channel
@@ -2296,6 +2520,7 @@ def unfurl_refs(text, ignore_alt_text=False):
text = text.replace(m, unfurl_ref(m[1:-1], ignore_alt_text))
return text
+
def unfurl_ref(ref, ignore_alt_text=False):
id = ref.split('|')[0]
display_text = ref
@@ -2309,17 +2534,18 @@ def unfurl_ref(ref, ignore_alt_text=False):
display_text = ref.split('|')[1]
else:
url, desc = ref.split('|', 1)
- display_text = u"{} ({})".format(url, desc)
+ display_text = "{} ({})".format(url, desc)
else:
display_text = resolve_ref(ref)
return display_text
+
def unwrap_attachments(message_json, text_before):
attachment_text = ''
a = message_json.get("attachments", None)
if a:
if text_before:
- attachment_text = u'\n'
+ attachment_text = '\n'
for attachment in a:
# Attachments should be rendered roughly like:
#
@@ -2363,29 +2589,30 @@ def unwrap_attachments(message_json, text_before):
def resolve_ref(ref):
- #TODO: This hack to use eventrouter needs to go
- #this resolver should probably move to the slackteam or eventrouter itself
- #global EVENTROUTER
+ # TODO: This hack to use eventrouter needs to go
+ # this resolver should probably move to the slackteam or eventrouter itself
+ # global EVENTROUTER
if 'EVENTROUTER' in globals():
e = EVENTROUTER
if ref.startswith('@U') or ref.startswith('@W'):
for t in e.teams.keys():
if ref[1:] in e.teams[t].users:
- #try:
+ # try:
return "@{}".format(e.teams[t].users[ref[1:]].name)
- #except:
+ # except:
# dbg("NAME: {}".format(ref))
elif ref.startswith('#C'):
for t in e.teams.keys():
if ref[1:] in e.teams[t].channels:
- #try:
+ # try:
return "{}".format(e.teams[t].channels[ref[1:]].name)
- #except:
+ # except:
# dbg("CHANNEL: {}".format(ref))
# Something else, just return as-is
return ref
+
def create_reaction_string(reactions):
count = 0
if not isinstance(reactions, list):
@@ -2406,6 +2633,7 @@ def create_reaction_string(reactions):
reaction_string = ''
return reaction_string
+
def modify_buffer_line(buffer, new_line, timestamp, time_id):
# get a pointer to this buffer's lines
own_lines = w.hdata_pointer(w.hdata_get('buffer'), buffer, 'own_lines')
@@ -2440,6 +2668,7 @@ def modify_print_time(buffer, new_id, time):
This overloads the time printed field to let us store the slack
per message unique id that comes after the "." in a slack ts
"""
+
# get a pointer to this buffer's lines
own_lines = w.hdata_pointer(w.hdata_get('buffer'), buffer, 'own_lines')
if own_lines:
@@ -2456,6 +2685,7 @@ def modify_print_time(buffer, new_id, time):
return w.WEECHAT_RC_OK
+
def tag(tagset, user=None):
if user:
user.replace(" ", "_")
@@ -2463,28 +2693,30 @@ def tag(tagset, user=None):
else:
default_tag = 'nick_unknown'
tagsets = {
- #when replaying something old
+ # when replaying something old
"backlog": "no_highlight,notify_none,logger_backlog_end",
- #when posting messages to a muted channel
+ # when posting messages to a muted channel
"muted": "no_highlight,notify_none,logger_backlog_end",
- #when my nick is in the message
+ # when my nick is in the message
"highlightme": "notify_highlight,log1",
- #when receiving a direct message
+ # when receiving a direct message
"dm": "notify_private,notify_message,log1,irc_privmsg",
"dmfromme": "notify_none,log1,irc_privmsg",
- #when this is a join/leave, attach for smart filter ala:
- #if user in [x.strip() for x in w.prefix("join"), w.prefix("quit")]
+ # when this is a join/leave, attach for smart filter ala:
+ # if user in [x.strip() for x in w.prefix("join"), w.prefix("quit")]
"joinleave": "irc_smart_filter,no_highlight",
- #catchall ?
+ # catchall ?
"default": "notify_message,log1",
}
return default_tag + "," + tagsets[tagset]
-
###### New/converted command_ commands
+
@slack_buffer_or_ignore
def part_command_cb(data, current_buffer, args):
+ data = decode_from_utf8(data)
+ args = decode_from_utf8(args)
e = EVENTROUTER
args = args.split()
if len(args) > 1:
@@ -2498,6 +2730,7 @@ def part_command_cb(data, current_buffer, args):
e.weechat_controller.unregister_buffer(current_buffer, update_remote=True, close_buffer=True)
return w.WEECHAT_RC_OK_EAT
+
@slack_buffer_or_ignore
def topic_command_cb(data, current_buffer, args):
n = len(args.split())
@@ -2511,15 +2744,18 @@ def topic_command_cb(data, current_buffer, args):
else:
return w.WEECHAT_RC_ERROR
+
@slack_buffer_required
def command_topic(data, current_buffer, args):
"""
Change the topic of a channel
/slack topic [<channel>] [<topic>|-delete]
"""
+ data = decode_from_utf8(data)
+ args = decode_from_utf8(args)
e = EVENTROUTER
team = e.weechat_controller.buffers[current_buffer].team
- #server = servers.find(current_domain_name())
+ # server = servers.find(current_domain_name())
args = args.split(' ')
if len(args) > 2 and args[1].startswith('#'):
cmap = team.get_channel_map()
@@ -2539,14 +2775,20 @@ def command_topic(data, current_buffer, args):
else:
return w.WEECHAT_RC_ERROR_EAT
+
@slack_buffer_or_ignore
def me_command_cb(data, current_buffer, args):
+ data = decode_from_utf8(data)
+ args = decode_from_utf8(args)
message = "_{}_".format(args.split(' ', 1)[1])
buffer_input_callback("EVENTROUTER", current_buffer, message)
return w.WEECHAT_RC_OK_EAT
+
@slack_buffer_or_ignore
def msg_command_cb(data, current_buffer, args):
+ data = decode_from_utf8(data)
+ args = decode_from_utf8(args)
dbg("msg_command_cb")
aargs = args.split(None, 2)
who = aargs[1]
@@ -2561,12 +2803,16 @@ def msg_command_cb(data, current_buffer, args):
channel.send_message(message)
return w.WEECHAT_RC_OK_EAT
+
@slack_buffer_or_ignore
def command_talk(data, current_buffer, args):
"""
Open a chat with the specified user
/slack talk [user]
"""
+
+ data = decode_from_utf8(data)
+ args = decode_from_utf8(args)
e = EVENTROUTER
team = e.weechat_controller.buffers[current_buffer].team
channel_name = args.split(' ')[1]
@@ -2577,7 +2823,7 @@ def command_talk(data, current_buffer, args):
s = SlackRequest(team.token, "im.open", {"user": u[channel_name]}, team_hash=team.team_hash)
EVENTROUTER.receive(s)
dbg("found user")
- #refresh channel map here
+ # refresh channel map here
c = team.get_channel_map()
if channel_name.startswith('#'):
@@ -2590,11 +2836,15 @@ def command_talk(data, current_buffer, args):
return w.WEECHAT_RC_OK_EAT
return w.WEECHAT_RC_OK_EAT
+
def command_showmuted(data, current_buffer, args):
current = w.current_buffer()
w.prnt(EVENTROUTER.weechat_controller.buffers[current].team.channel_buffer, str(EVENTROUTER.weechat_controller.buffers[current].team.muted_channels))
+
def thread_command_callback(data, current_buffer, args):
+ data = decode_from_utf8(data)
+ args = decode_from_utf8(args)
current = w.current_buffer()
channel = EVENTROUTER.weechat_controller.buffers.get(current)
if channel:
@@ -2608,7 +2858,7 @@ def thread_command_callback(data, current_buffer, args):
tc = SlackThreadChannel(EVENTROUTER, pm)
pm.thread_channel = tc
tc.open()
- #tc.create_buffer()
+ # tc.create_buffer()
return w.WEECHAT_RC_OK_EAT
elif args[0] == '/reply':
count = int(args[1])
@@ -2621,7 +2871,10 @@ def thread_command_callback(data, current_buffer, args):
w.prnt(current, "Invalid thread command.")
return w.WEECHAT_RC_OK_EAT
+
def rehistory_command_callback(data, current_buffer, args):
+ data = decode_from_utf8(data)
+ args = decode_from_utf8(args)
current = w.current_buffer()
channel = EVENTROUTER.weechat_controller.buffers.get(current)
channel.got_history = False
@@ -2629,8 +2882,11 @@ def rehistory_command_callback(data, current_buffer, args):
channel.get_history()
return w.WEECHAT_RC_OK_EAT
+
@slack_buffer_required
def hide_command_callback(data, current_buffer, args):
+ data = decode_from_utf8(data)
+ args = decode_from_utf8(args)
c = EVENTROUTER.weechat_controller.buffers.get(current_buffer, None)
if c:
name = c.formatted_name(style='long_default')
@@ -2638,7 +2894,10 @@ def hide_command_callback(data, current_buffer, args):
w.buffer_set(c.channel_buffer, "hidden", "1")
return w.WEECHAT_RC_OK_EAT
+
def slack_command_cb(data, current_buffer, args):
+ data = decode_from_utf8(data)
+ args = decode_from_utf8(args)
a = args.split(' ', 1)
if len(a) > 1:
function_name, args = a[0], args
@@ -2651,6 +2910,7 @@ def slack_command_cb(data, current_buffer, args):
w.prnt("", "Command not found: " + function_name)
return w.WEECHAT_RC_OK
+
@slack_buffer_required
def command_distracting(data, current_buffer, args):
channel = EVENTROUTER.weechat_controller.buffers.get(current_buffer, None)
@@ -2662,9 +2922,11 @@ def command_distracting(data, current_buffer, args):
config.distracting_channels.pop(config.distracting_channels.index(fullname))
save_distracting_channels()
+
def save_distracting_channels():
w.config_set_plugin('distracting_channels', ','.join(config.distracting_channels))
+
@slack_buffer_required
def command_slash(data, current_buffer, args):
"""
@@ -2687,6 +2949,7 @@ def command_slash(data, current_buffer, args):
s = SlackRequest(team.token, "chat.command", {"command": command, "text": text, 'channel': channel.identifier}, team_hash=team.team_hash, channel_identifier=channel.identifier)
EVENTROUTER.receive(s)
+
@slack_buffer_required
def command_mute(data, current_buffer, args):
current = w.current_buffer()
@@ -2699,9 +2962,10 @@ def command_mute(data, current_buffer, args):
s = SlackRequest(team.token, "users.prefs.set", {"name": "muted_channels", "value": ",".join(team.muted_channels)}, team_hash=team.team_hash, channel_identifier=channel_id)
EVENTROUTER.receive(s)
+
@slack_buffer_required
def command_openweb(data, current_buffer, args):
- #if done from server buffer, open slack for reals
+ # if done from server buffer, open slack for reals
channel = EVENTROUTER.weechat_controller.buffers[current_buffer]
if isinstance(channel, SlackTeam):
url = "https://{}".format(channel.team.domain)
@@ -2710,22 +2974,24 @@ def command_openweb(data, current_buffer, args):
url = "https://{}/archives/{}/p{}000000".format(channel.team.domain, channel.slack_name, now.majorstr())
w.prnt_date_tags(channel.team.channel_buffer, SlackTS().major, "openweb,logger_backlog_end,notify_none", url)
+
def command_nodistractions(data, current_buffer, args):
global hide_distractions
hide_distractions = not hide_distractions
if config.distracting_channels != ['']:
for channel in config.distracting_channels:
dbg('hiding channel {}'.format(channel))
- #try:
+ # try:
for c in EVENTROUTER.weechat_controller.buffers.itervalues():
if c == channel:
dbg('found channel {} to hide'.format(channel))
w.buffer_set(c.channel_buffer, "hidden", str(int(hide_distractions)))
- #except:
+ # except:
# dbg("Can't hide channel {} .. removing..".format(channel), main_buffer=True)
# config.distracting_channels.pop(config.distracting_channels.index(channel))
# save_distracting_channels()
+
@slack_buffer_required
def command_upload(data, current_buffer, args):
channel = EVENTROUTER.weechat_controller.buffers.get(current_buffer)
@@ -2739,8 +3005,11 @@ def command_upload(data, current_buffer, args):
command = 'curl -F file=@{} -F channels={} -F token={} {}'.format(file_path, channel.identifier, team.token, url)
w.hook_process(command, config.slack_timeout, '', '')
+
def away_command_cb(data, current_buffer, args):
- #TODO: reimplement all.. maybe
+ data = decode_from_utf8(data)
+ args = decode_from_utf8(args)
+ # TODO: reimplement all.. maybe
(all, message) = re.match("^/away(?:\s+(-all))?(?:\s+(.+))?", args).groups()
if message is None:
command_back(data, current_buffer, args)
@@ -2748,6 +3017,7 @@ def away_command_cb(data, current_buffer, args):
command_away(data, current_buffer, args)
return w.WEECHAT_RC_OK
+
@slack_buffer_required
def command_away(data, current_buffer, args):
"""
@@ -2794,8 +3064,11 @@ def command_back(data, current_buffer, args):
s = SlackRequest(team.token, "presence.set", {"presence": "active"}, team_hash=team.team_hash)
EVENTROUTER.receive(s)
+
@slack_buffer_required
def label_command_cb(data, current_buffer, args):
+ data = decode_from_utf8(data)
+ args = decode_from_utf8(args)
channel = EVENTROUTER.weechat_controller.buffers.get(current_buffer)
if channel and channel.type == 'thread':
aargs = args.split(None, 2)
@@ -2803,12 +3076,14 @@ def label_command_cb(data, current_buffer, args):
channel.label = new_name
w.buffer_set(channel.channel_buffer, "short_name", new_name)
+
def command_p(data, current_buffer, args):
args = args.split(' ', 1)[1]
w.prnt("", "{}".format(eval(args)))
###### NEW EXCEPTIONS
+
class ProcessNotImplemented(Exception):
"""
Raised when we try to call process_(something), but
@@ -2817,6 +3092,7 @@ class ProcessNotImplemented(Exception):
def __init__(self, function_name):
super(ProcessNotImplemented, self).__init__(function_name)
+
class InvalidType(Exception):
"""
Raised when we do type checking to ensure objects of the wrong
@@ -2827,6 +3103,7 @@ class InvalidType(Exception):
###### New but probably old and need to migrate
+
def closed_slack_debug_buffer_cb(data, buffer):
global slack_debug
slack_debug = None
@@ -2842,11 +3119,12 @@ def create_slack_debug_buffer():
slack_debug = w.buffer_new("slack-debug", "", "", "closed_slack_debug_buffer_cb", "")
w.buffer_set(slack_debug, "notify", "0")
+
def load_emoji():
try:
global EMOJI
DIR = w.info_get("weechat_dir", "")
- #no idea why this does't work w/o checking the type?!
+ # no idea why this does't work w/o checking the type?!
dbg(type(DIR), 0)
ef = open('{}/weemoji.json'.format(DIR), 'r')
EMOJI = json.loads(ef.read())
@@ -2855,6 +3133,7 @@ def load_emoji():
dbg("Unexpected error: {}".format(sys.exc_info()), 5)
return w.WEECHAT_RC_OK
+
def setup_hooks():
cmds = {k[8:]: v for k, v in globals().items() if k.startswith("command_")}
@@ -2884,7 +3163,7 @@ def setup_hooks():
'|'.join(cmds.keys()),
# Function name
'slack_command_cb', '')
- #w.hook_command('me', '', 'stuff', 'stuff2', '', 'me_command_cb', '')
+ # w.hook_command('me', '', 'stuff', 'stuff2', '', 'me_command_cb', '')
w.hook_command_run('/me', 'me_command_cb', '')
w.hook_command_run('/query', 'command_talk', '')
@@ -2905,11 +3184,10 @@ def setup_hooks():
w.hook_completion("emoji", "complete :emoji: for slack", "emoji_completion_cb", "")
# Hooks to fix/implement
- #w.hook_timer(1000 * 60 * 5, 0, 0, "cache_write_cb", "")
- #w.hook_signal('buffer_opened', "buffer_opened_cb", "")
- #w.hook_signal('window_scrolled', "scrolled_cb", "")
- #w.hook_timer(3000, 0, 0, "slack_connection_persistence_cb", "")
-
+ # w.hook_timer(1000 * 60 * 5, 0, 0, "cache_write_cb", "")
+ # w.hook_signal('buffer_opened', "buffer_opened_cb", "")
+ # w.hook_signal('window_scrolled', "scrolled_cb", "")
+ # w.hook_timer(3000, 0, 0, "slack_connection_persistence_cb", "")
##### END NEW
@@ -2918,25 +3196,24 @@ def dbg(message, level=0, main_buffer=False, fout=False):
"""
send debug output to the slack-debug buffer and optionally write to a file.
"""
- #TODO: do this smarter
- #return
+ # TODO: do this smarter
+ # return
if level >= config.debug_level:
global debug_string
message = "DEBUG: {}".format(message)
- # message = message.encode('utf-8', 'replace')
if fout:
file('/tmp/debug.log', 'a+').writelines(message + '\n')
if main_buffer:
- #w.prnt("", "---------")
+ # w.prnt("", "---------")
w.prnt("", "slack: " + message)
else:
if slack_debug and (not debug_string or debug_string in message):
- #w.prnt(slack_debug, "---------")
+ # w.prnt(slack_debug, "---------")
w.prnt(slack_debug, message)
-
###### Config code
+
class PluginConfig(object):
# Default settings.
# These are in the (string) format that weechat expects; at __init__ time
@@ -3047,6 +3324,7 @@ def setup_trace():
now = time.time()
f = open('{}/{}-trace.json'.format(RECORD_DIR, now), 'w')
+
def trace_calls(frame, event, arg):
global f
if event != 'call':
@@ -3071,6 +3349,8 @@ def trace_calls(frame, event, arg):
# Main
if __name__ == "__main__":
+ w = WeechatWrapper(weechat)
+
if w.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE,
SCRIPT_DESC, "script_unloaded", ""):
@@ -3081,11 +3361,11 @@ if __name__ == "__main__":
global EVENTROUTER
EVENTROUTER = EventRouter()
- #setup_trace()
+ # setup_trace()
- #WEECHAT_HOME = w.info_get("weechat_dir", "")
- #CACHE_NAME = "slack.cache"
- #STOP_TALKING_TO_SLACK = False
+ # WEECHAT_HOME = w.info_get("weechat_dir", "")
+ # CACHE_NAME = "slack.cache"
+ # STOP_TALKING_TO_SLACK = False
# Global var section
slack_debug = None
@@ -3093,17 +3373,17 @@ if __name__ == "__main__":
config_changed_cb = config.config_changed
typing_timer = time.time()
- #domain = None
- #previous_buffer = None
- #slack_buffer = None
+ # domain = None
+ # previous_buffer = None
+ # slack_buffer = None
- #never_away = False
+ # never_away = False
hide_distractions = False
- #hotlist = w.infolist_get("hotlist", "", "")
- #main_weechat_buffer = w.info_get("irc_buffer", "{}.{}".format(domain, "DOESNOTEXIST!@#$"))
+ # hotlist = w.infolist_get("hotlist", "", "")
+ # main_weechat_buffer = w.info_get("irc_buffer", "{}.{}".format(domain, "DOESNOTEXIST!@#$"))
- #message_cache = collections.defaultdict(list)
- #if config.cache_messages:
+ # message_cache = collections.defaultdict(list)
+ # if config.cache_messages:
# cache_load()
w.hook_config("plugins.var.python." + SCRIPT_NAME + ".*", "config_changed_cb", "")