Commit 589eab1c authored by Trygve Aaberge's avatar Trygve Aaberge Committed by Sébastien Helleu

slack.py 2.4.0: Merge with mainline

This is version 2.4.0 of slack.py (currently the most recent), copied
over from the wee-slack repo.
parent 8722a68a
# Copyright (c) 2014-2016 Ryan Huber <[email protected]>
# Copyright (c) 2015-2018 Tollef Fog Heen <[email protected]>
# Copyright (c) 2015-2019 Trygve Aaberge <[email protected]>
# Copyright (c) 2015-2020 Trygve Aaberge <[email protected]>
# Released under the MIT license.
from __future__ import print_function, unicode_literals
......@@ -25,6 +25,11 @@ import random
import socket
import string
# Prevent websocket from using numpy (it's an optional dependency). We do this
# because numpy causes python (and thus weechat) to crash when it's reloaded.
# See https://github.com/numpy/numpy/issues/11925
sys.modules["numpy"] = None
from websocket import ABNF, create_connection, WebSocketConnectionClosedException
try:
......@@ -38,6 +43,11 @@ try:
except ImportError:
from urllib import urlencode
try:
from json import JSONDecodeError
except:
JSONDecodeError = ValueError
# hack to make tests possible.. better way?
try:
import weechat
......@@ -46,7 +56,7 @@ except ImportError:
SCRIPT_NAME = "slack"
SCRIPT_AUTHOR = "Ryan Huber <[email protected]>"
SCRIPT_VERSION = "2.3.0"
SCRIPT_VERSION = "2.4.0"
SCRIPT_LICENSE = "MIT"
SCRIPT_DESC = "Extends weechat for typing notification/search/etc on slack.com"
......@@ -83,6 +93,13 @@ SLACK_API_TRANSLATOR = {
"mark": "groups.mark",
"info": "groups.info"
},
"private": {
"history": "conversations.history",
"join": "conversations.join",
"leave": "conversations.leave",
"mark": "conversations.mark",
"info": "conversations.info",
},
"shared": {
"history": "conversations.history",
"join": "conversations.join",
......@@ -122,6 +139,8 @@ def slack_buffer_required(f):
@wraps(f)
def wrapper(data, current_buffer, *args, **kwargs):
if current_buffer not in EVENTROUTER.weechat_controller.buffers:
command_name = f.__name__.replace('command_', '', 1)
w.prnt('', 'slack: command "{}" must be executed on slack buffer'.format(command_name))
return w.WEECHAT_RC_ERROR
return f(data, current_buffer, *args, **kwargs)
return wrapper
......@@ -215,7 +234,7 @@ class WeechatWrapper(object):
class ProxyWrapper(object):
def __init__(self):
self.proxy_name = w.config_string(weechat.config_get('weechat.network.proxy_curl'))
self.proxy_name = w.config_string(w.config_get('weechat.network.proxy_curl'))
self.proxy_string = ""
self.proxy_type = ""
self.proxy_address = ""
......@@ -226,12 +245,12 @@ class ProxyWrapper(object):
if self.proxy_name:
self.proxy_string = "weechat.proxy.{}".format(self.proxy_name)
self.proxy_type = w.config_string(weechat.config_get("{}.type".format(self.proxy_string)))
self.proxy_type = w.config_string(w.config_get("{}.type".format(self.proxy_string)))
if self.proxy_type == "http":
self.proxy_address = w.config_string(weechat.config_get("{}.address".format(self.proxy_string)))
self.proxy_port = w.config_integer(weechat.config_get("{}.port".format(self.proxy_string)))
self.proxy_user = w.config_string(weechat.config_get("{}.username".format(self.proxy_string)))
self.proxy_password = w.config_string(weechat.config_get("{}.password".format(self.proxy_string)))
self.proxy_address = w.config_string(w.config_get("{}.address".format(self.proxy_string)))
self.proxy_port = w.config_integer(w.config_get("{}.port".format(self.proxy_string)))
self.proxy_user = w.config_string(w.config_get("{}.username".format(self.proxy_string)))
self.proxy_password = w.config_string(w.config_get("{}.password".format(self.proxy_string)))
self.has_proxy = True
else:
w.prnt("", "\nWarning: weechat.network.proxy_curl is set to {} type (name : {}, conf string : {}). Only HTTP proxy is supported.\n\n".format(self.proxy_type, self.proxy_name, self.proxy_string))
......@@ -250,7 +269,7 @@ class ProxyWrapper(object):
else:
port = ""
return "--proxy {}{}{}".format(user, self.proxy_address, port)
return "-x{}{}{}".format(user, self.proxy_address, port)
##### Helpers
......@@ -369,7 +388,7 @@ class EventRouter(object):
weechat's "callback_data" has a limited size and weechat will crash if you exceed
this size.
"""
data = self.context.get(identifier, None)
data = self.context.get(identifier)
if data:
# dbg("retrieved context {} ".format(identifier))
return data
......@@ -477,10 +496,10 @@ class EventRouter(object):
# dbg("Incomplete json, awaiting more", True)
try:
j["wee_slack_process_method"] = request_metadata.request_normalized
j["wee_slack_request_metadata"] = request_metadata
self.reply_buffer.pop(request_metadata.response_id)
if self.recording:
self.record_event(j, 'wee_slack_process_method', 'http')
j["wee_slack_request_metadata"] = request_metadata
self.reply_buffer.pop(request_metadata.response_id)
self.receive(j)
self.delete_context(data)
except:
......@@ -491,22 +510,22 @@ class EventRouter(object):
dbg("length was zero, probably a bug..")
self.delete_context(data)
self.receive(request_metadata)
elif return_code != -1:
elif return_code == -1:
if request_metadata.response_id not in self.reply_buffer:
self.reply_buffer[request_metadata.response_id] = StringIO()
self.reply_buffer[request_metadata.response_id].write(out)
else:
self.reply_buffer.pop(request_metadata.response_id, None)
self.delete_context(data)
if request_metadata.request.startswith('rtm.'):
retry_text = ('retrying' if request_metadata.should_try() else
'will not retry after too many failed attempts')
w.prnt('', ('Failed connecting to slack team with token starting with {}, {}. ' +
'If this persists, try increasing slack_timeout.')
.format(request_metadata.token[:15], retry_text))
'If this persists, try increasing slack_timeout. Error: {}')
.format(request_metadata.token[:15], retry_text, err))
dbg('rtm.start failed with return_code {}. stack:\n{}'
.format(return_code, ''.join(traceback.format_stack())), level=5)
self.receive(request_metadata)
else:
if request_metadata.response_id not in self.reply_buffer:
self.reply_buffer[request_metadata.response_id] = StringIO()
self.reply_buffer[request_metadata.response_id].write(out)
def receive(self, dataobj):
"""
......@@ -580,12 +599,12 @@ class EventRouter(object):
function_name = "unknown"
# Here we are passing the actual objects. No more lookups.
meta = j.get("wee_slack_metadata", None)
meta = j.get("wee_slack_metadata")
if meta:
try:
if isinstance(meta, basestring):
dbg("string of metadata")
team = meta.get("team", None)
team = meta.get("team")
if team:
kwargs["team"] = self.teams[team]
if "user" in j:
......@@ -662,7 +681,7 @@ class WeechatController(object):
w.buffer_close(buffer_ptr)
def get_channel_from_buffer_ptr(self, buffer_ptr):
return self.buffers.get(buffer_ptr, None)
return self.buffers.get(buffer_ptr)
def get_all(self, buffer_ptr):
return self.buffers
......@@ -812,6 +831,7 @@ def input_text_for_buffer_cb(data, modifier, current_buffer, string):
return ""
return string
@utf8_decode
def buffer_switch_callback(signal, sig_type, data):
"""
......@@ -869,11 +889,11 @@ def quit_notification_callback(signal, sig_type, data):
@utf8_decode
def typing_notification_cb(data, signal, current_buffer):
msg = w.buffer_get_string(current_buffer, "input")
if len(msg) > 8 and msg[:1] != "/":
if len(msg) > 8 and msg[0] != "/":
global typing_timer
now = time.time()
if typing_timer + 4 < now:
channel = EVENTROUTER.weechat_controller.buffers.get(current_buffer, None)
channel = EVENTROUTER.weechat_controller.buffers.get(current_buffer)
if channel and channel.type != "thread":
identifier = channel.identifier
request = {"type": "typing", "channel": identifier}
......@@ -891,9 +911,9 @@ def typing_update_cb(data, remaining_calls):
@utf8_decode
def slack_never_away_cb(data, remaining_calls):
if config.never_away:
for t in EVENTROUTER.teams.values():
slackbot = t.get_channel_map()['Slackbot']
channel = t.channels[slackbot]
for team in EVENTROUTER.teams.values():
slackbot = team.get_channel_map()['Slackbot']
channel = team.channels[slackbot]
request = {"type": "typing", "channel": channel.identifier}
channel.team.send_to_websocket(request, expect_reply=False)
return w.WEECHAT_RC_OK
......@@ -906,7 +926,7 @@ def typing_bar_item_cb(data, item, current_window, current_buffer, extra_info):
why is typing a DM to you globally.
"""
typers = []
current_channel = EVENTROUTER.weechat_controller.buffers.get(current_buffer, None)
current_channel = EVENTROUTER.weechat_controller.buffers.get(current_buffer)
# first look for people typing in this channel
if current_channel:
......@@ -919,8 +939,8 @@ def typing_bar_item_cb(data, item, current_window, current_buffer, extra_info):
# here is where we notify you that someone is typing in DM
# regardless of which buffer you are in currently
for t in EVENTROUTER.teams.values():
for channel in t.channels.values():
for team in EVENTROUTER.teams.values():
for channel in team.channels.values():
if channel.type == "im":
if channel.is_someone_typing():
typers.append("D/" + channel.slack_name)
......@@ -934,19 +954,61 @@ def typing_bar_item_cb(data, item, current_window, current_buffer, extra_info):
@utf8_decode
def nick_completion_cb(data, completion_item, current_buffer, completion):
def channel_completion_cb(data, completion_item, current_buffer, completion):
"""
Adds all @-prefixed nicks to completion list
Adds all channels on all teams to completion list
"""
current_channel = EVENTROUTER.weechat_controller.buffers.get(current_buffer)
should_include_channel = lambda channel: channel.active and channel.type in ['channel', 'group', 'private', 'shared']
other_teams = [team for team in EVENTROUTER.teams.values() if not current_channel or team != current_channel.team]
for team in other_teams:
for channel in team.channels.values():
if should_include_channel(channel):
w.hook_completion_list_add(completion, channel.name, 0, w.WEECHAT_LIST_POS_SORT)
if current_channel:
for channel in sorted(current_channel.team.channels.values(), key=lambda channel: channel.name, reverse=True):
if should_include_channel(channel):
w.hook_completion_list_add(completion, channel.name, 0, w.WEECHAT_LIST_POS_BEGINNING)
if should_include_channel(current_channel):
w.hook_completion_list_add(completion, current_channel.name, 0, w.WEECHAT_LIST_POS_BEGINNING)
return w.WEECHAT_RC_OK
current_channel = EVENTROUTER.weechat_controller.buffers.get(current_buffer, None)
@utf8_decode
def dm_completion_cb(data, completion_item, current_buffer, completion):
"""
Adds all dms/mpdms on all teams to completion list
"""
for team in EVENTROUTER.teams.values():
for channel in team.channels.values():
if channel.active and channel.type in ['im', 'mpim']:
w.hook_completion_list_add(completion, channel.name, 0, w.WEECHAT_LIST_POS_SORT)
return w.WEECHAT_RC_OK
@utf8_decode
def nick_completion_cb(data, completion_item, current_buffer, completion):
"""
Adds all @-prefixed nicks to completion list
"""
current_channel = EVENTROUTER.weechat_controller.buffers.get(current_buffer)
if current_channel is None or current_channel.members is None:
return w.WEECHAT_RC_OK
for m in current_channel.members:
u = current_channel.team.users.get(m, None)
if u:
w.hook_completion_list_add(completion, "@" + u.name, 1, w.WEECHAT_LIST_POS_SORT)
base_command = w.hook_completion_get_string(completion, "base_command")
if base_command in ['invite', 'msg', 'query', 'whois']:
members = current_channel.team.members
else:
members = current_channel.members
for member in members:
user = current_channel.team.users.get(member)
if user and not user.deleted:
w.hook_completion_list_add(completion, user.name, 1, w.WEECHAT_LIST_POS_SORT)
w.hook_completion_list_add(completion, "@" + user.name, 1, w.WEECHAT_LIST_POS_SORT)
return w.WEECHAT_RC_OK
......@@ -955,27 +1017,66 @@ def emoji_completion_cb(data, completion_item, current_buffer, completion):
"""
Adds all :-prefixed emoji to completion list
"""
current_channel = EVENTROUTER.weechat_controller.buffers.get(current_buffer)
if current_channel is None:
return w.WEECHAT_RC_OK
base_word = w.hook_completion_get_string(completion, "base_word")
if ":" not in base_word:
return w.WEECHAT_RC_OK
prefix = base_word.split(":")[0] + ":"
for emoji in current_channel.team.emoji_completions:
w.hook_completion_list_add(completion, prefix + emoji + ":", 0, w.WEECHAT_LIST_POS_SORT)
return w.WEECHAT_RC_OK
@utf8_decode
def thread_completion_cb(data, completion_item, current_buffer, completion):
"""
Adds all $-prefixed thread ids to completion list
"""
current_channel = EVENTROUTER.weechat_controller.buffers.get(current_buffer)
if current_channel is None or not hasattr(current_channel, 'hashed_messages'):
return w.WEECHAT_RC_OK
threads = current_channel.hashed_messages.items()
for thread_id, message in sorted(threads, key=lambda item: item[1].ts):
if message.number_of_replies():
w.hook_completion_list_add(completion, "$" + thread_id, 0, w.WEECHAT_LIST_POS_BEGINNING)
return w.WEECHAT_RC_OK
current_channel = EVENTROUTER.weechat_controller.buffers.get(current_buffer, None)
@utf8_decode
def topic_completion_cb(data, completion_item, current_buffer, completion):
"""
Adds topic for current channel to completion list
"""
current_channel = EVENTROUTER.weechat_controller.buffers.get(current_buffer)
if current_channel is None:
return w.WEECHAT_RC_OK
for e in current_channel.team.emoji_completions:
w.hook_completion_list_add(completion, ":" + e + ":", 0, w.WEECHAT_LIST_POS_SORT)
topic = current_channel.render_topic()
channel_names = [channel.name for channel in current_channel.team.channels.values()]
if topic.split(' ', 1)[0] in channel_names:
topic = '{} {}'.format(current_channel.name, topic)
w.hook_completion_list_add(completion, topic, 0, w.WEECHAT_LIST_POS_SORT)
return w.WEECHAT_RC_OK
@utf8_decode
def usergroups_completion_cb(data, completion_item, current_buffer, completion):
"""
Adds all @-prefixed usergroups to completion list
"""
current_channel = EVENTROUTER.weechat_controller.buffers.get(current_buffer, None)
current_channel = EVENTROUTER.weechat_controller.buffers.get(current_buffer)
if current_channel is None:
return w.WEECHAT_RC_OK
for subteam in current_channel.team.subteams.values():
w.hook_completion_list_add(completion, "@" + subteam.handle, 1, w.WEECHAT_LIST_POS_SORT)
subteam_handles = [subteam.handle for subteam in current_channel.team.subteams.values()]
for group in subteam_handles + ["@channel", "@everyone", "@here"]:
w.hook_completion_list_add(completion, group, 1, w.WEECHAT_LIST_POS_SORT)
return w.WEECHAT_RC_OK
......@@ -985,12 +1086,8 @@ def complete_next_cb(data, current_buffer, command):
rely on nick_completion_cb adding the @-prefixed versions to the
completion lists, then let Weechat's internal completion do its
thing
"""
current_channel = EVENTROUTER.weechat_controller.buffers.get(current_buffer, None)
# channel = channels.find(current_buffer)
current_channel = EVENTROUTER.weechat_controller.buffers.get(current_buffer)
if not hasattr(current_channel, 'members') or current_channel is None or current_channel.members is None:
return w.WEECHAT_RC_OK
......@@ -1015,9 +1112,9 @@ def complete_next_cb(data, current_buffer, command):
break
word = line_input[word_start:word_end]
for m in current_channel.members:
u = current_channel.team.users.get(m, None)
if u and u.name == word:
for member in current_channel.members:
user = current_channel.team.users.get(member)
if user and user.name == word:
# Here, we cheat. Insert a @ in front and rely in the @
# nicks being in the completion list
w.buffer_set(current_buffer, "input", line_input[:word_start] + "@" + line_input[word_start:])
......@@ -1053,7 +1150,9 @@ class SlackRequest(object):
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):
def __init__(self, token, request, post_data=None, **kwargs):
if post_data is None:
post_data = {}
for key, value in kwargs.items():
setattr(self, key, value)
self.tries = 0
......@@ -1084,23 +1183,25 @@ class SlackRequest(object):
def retry_ready(self):
return (self.start_time + (self.tries**2)) < time.time()
class SlackSubteam(object):
"""
Represents a slack group or subteam
Represents a slack group or subteam
"""
def __init__(self, originating_team_id, **kwargs):
self.handle = kwargs.get('handle', None)
def __init__(self, originating_team_id, is_member, **kwargs):
self.handle = '@{}'.format(kwargs['handle'])
self.identifier = kwargs['id']
self.name = kwargs.get('name', None)
self.description = kwargs.get('description', None)
self.name = kwargs['name']
self.description = kwargs.get('description')
self.team_id = originating_team_id
self.is_member = is_member
def __repr__(self):
return "Name:{} Identifier:{}".format(self.name, self.identifier)
def __eq__(self, compare_str):
return compare_str == self.subteam_id
return compare_str == self.subteam_id
class SlackTeam(object):
......@@ -1111,6 +1212,7 @@ class SlackTeam(object):
def __init__(self, eventrouter, token, websocket_url, team_info, subteams, nick, myidentifier, users, bots, channels, **kwargs):
self.identifier = team_info["id"]
self.active = True
self.ws_url = websocket_url
self.connected = False
self.connecting_rtm = False
......@@ -1148,7 +1250,6 @@ class SlackTeam(object):
for c in self.channels.keys():
channels[c].set_related_server(self)
channels[c].check_should_open()
# self.channel_set_related_server(c)
# Last step is to make sure my nickname is the set color
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
......@@ -1177,7 +1278,7 @@ class SlackTeam(object):
channel.set_related_server(self)
def generate_usergroup_map(self):
return { s.handle: s.identifier for s in self.subteams.values()}
return {s.handle: s.identifier for s in self.subteams.values()}
# def connect_request_generate(self):
# return SlackRequest(self.token, 'rtm.start', {})
......@@ -1235,7 +1336,7 @@ class SlackTeam(object):
return channel
def get_channel_map(self):
return {v.slack_name: k for k, v in self.channels.items()}
return {v.name: k for k, v in self.channels.items()}
def get_username_map(self):
return {v.name: k for k, v in self.users.items()}
......@@ -1378,10 +1479,12 @@ class SlackChannelCommon(object):
s = SlackRequest(self.team.token, "chat.delete", {"channel": self.identifier, "ts": message['ts']}, team_hash=self.team.team_hash, channel_identifier=self.identifier)
self.eventrouter.receive(s)
else:
num_replace = 1
if 'g' in flags:
num_replace = 0
new_message = re.sub(old, new, message["text"], num_replace)
num_replace = 0 if 'g' in flags else 1
f = re.UNICODE
f |= re.IGNORECASE if 'i' in flags else 0
f |= re.MULTILINE if 'm' in flags else 0
f |= re.DOTALL if 's' in flags else 0
new_message = re.sub(old, new, message["text"], num_replace, f)
if new_message != message["text"]:
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)
......@@ -1468,7 +1571,7 @@ class SlackChannel(SlackChannelCommon):
self.identifier = kwargs["id"]
self.last_read = SlackTS(kwargs.get("last_read", SlackTS()))
self.channel_buffer = None
self.team = kwargs.get('team', None)
self.team = kwargs.get('team')
self.got_history = False
self.messages = OrderedDict()
self.hashed_messages = {}
......@@ -1531,7 +1634,7 @@ class SlackChannel(SlackChannelCommon):
def formatted_name(self, style="default", typing=False, **kwargs):
if typing and config.channel_name_typing_indicator:
prepend = ">"
elif self.type == "group":
elif self.type == "group" or self.type == "private":
prepend = config.group_name_prefix
elif self.type == "shared":
prepend = config.shared_name_prefix
......@@ -1547,16 +1650,19 @@ class SlackChannel(SlackChannelCommon):
}
return select[style]
def render_topic(self):
def render_topic(self, fallback_to_purpose=False):
topic = self.topic['value']
if not topic and fallback_to_purpose:
topic = self.slack_purpose['value']
return unhtmlescape(unfurl_refs(topic, ignore_alt_text=False))
def set_topic(self, value=None):
if value is not None:
self.topic = {"value": value}
if self.channel_buffer:
topic = self.topic['value'] or self.slack_purpose['value']
topic = unhtmlescape(unfurl_refs(topic, ignore_alt_text=False))
topic = self.render_topic(fallback_to_purpose=True)
w.buffer_set(self.channel_buffer, "title", topic)
def set_topic(self, value):
self.topic = {"value": value}
self.render_topic()
def update_from_message_json(self, message_json):
for key, value in message_json.items():
setattr(self, key, value)
......@@ -1589,15 +1695,15 @@ class SlackChannel(SlackChannelCommon):
def set_related_server(self, team):
self.team = team
def mentions(self):
return {'@' + self.team.nick, self.team.myidentifier}
def highlights(self):
personal_highlights = self.team.highlight_words.union(self.mentions())
nick_highlights = {'@' + self.team.nick, self.team.myidentifier}
subteam_highlights = {subteam.handle for subteam in self.team.subteams.values()
if subteam.is_member}
highlights = nick_highlights | subteam_highlights | self.team.highlight_words
if self.muted and config.muted_channels_activity == "personal_highlights":
return personal_highlights
return highlights
else:
return personal_highlights.union({"!here", "!channel", "!everyone"})
return highlights | {"@channel", "@everyone", "@group", "@here"}
def set_highlights(self):
# highlight my own name and any set highlights
......@@ -1605,6 +1711,17 @@ class SlackChannel(SlackChannelCommon):
h_str = ",".join(self.highlights())
w.buffer_set(self.channel_buffer, "highlight_words", h_str)
if self.muted and config.muted_channels_activity != "all":
notify_level = "0" if config.muted_channels_activity == "none" else "1"
w.buffer_set(self.channel_buffer, "notify", notify_level)
else:
w.buffer_set(self.channel_buffer, "notify", "3")
if self.muted and config.muted_channels_activity == "none":
w.buffer_set(self.channel_buffer, "highlight_tags_restrict", "highlight_force")
else:
w.buffer_set(self.channel_buffer, "highlight_tags_restrict", "")
def create_buffer(self):
"""
Creates the weechat buffer where the channel magic happens.
......@@ -1620,7 +1737,7 @@ class SlackChannel(SlackChannelCommon):
w.buffer_set(self.channel_buffer, "localvar_set_channel", self.formatted_name())
w.buffer_set(self.channel_buffer, "localvar_set_nick", self.team.nick)
w.buffer_set(self.channel_buffer, "short_name", self.formatted_name(style="sidebar", enable_color=True))
self.render_topic()
self.set_topic()
self.eventrouter.weechat_controller.set_refresh_buffer_list(True)
if self.channel_buffer:
# if self.team.server_alias:
......@@ -1654,7 +1771,7 @@ class SlackChannel(SlackChannelCommon):
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):
def buffer_prnt(self, nick, text, timestamp=str(time.time()), tagset=None, tag_nick=None, history_message=False, extra_tags=None, **kwargs):
data = "{}\t{}".format(format_nick(nick, self.last_line_from), text)
self.last_line_from = nick
ts = SlackTS(timestamp)
......@@ -1664,24 +1781,19 @@ class SlackChannel(SlackChannelCommon):
self.open(update_remote=False)
if self.channel_buffer:
# backlog messages - we will update the read marker as we print these
backlog = True if ts <= last_read else False
if tagset:
backlog = ts <= last_read
if not backlog:
self.new_messages = True
# we have to infer the tagset because we weren't told
elif ts <= last_read:
tagset = "backlog"
elif self.type in ["im", "mpim"]:
if tag_nick != self.team.nick:
if not tagset:
if self.type in ["im", "mpim"]:
tagset = "dm"
self.new_messages = True
else:
tagset = "dmfromme"
else:
tagset = "default"
self.new_messages = True
tagset = "channel"
tags = tag(tagset, user=tag_nick, muted=self.muted)
no_log = history_message and backlog
self_msg = tag_nick == self.team.nick
tags = tag(tagset, user=tag_nick, self_msg=self_msg, backlog=backlog, no_log=no_log, extra_tags=extra_tags)
try:
if (config.unhide_buffers_with_activity
......@@ -1690,7 +1802,7 @@ class SlackChannel(SlackChannelCommon):
w.prnt_date_tags(self.channel_buffer, ts.major, tags, data)
modify_last_print_time(self.channel_buffer, ts.minor)
if backlog or tag_nick == self.team.nick:
if backlog or self_msg:
self.mark_read(ts, update_remote=False, force=True)
except:
dbg("Problem processing buffer_prnt")
......@@ -1733,7 +1845,8 @@ class SlackChannel(SlackChannelCommon):
# we have probably reconnected. flush the buffer
if self.team.connected:
self.clear_messages()
self.buffer_prnt('', 'getting channel history...', tagset='backlog')
w.prnt_date_tags(self.channel_buffer, SlackTS().major,
tag(backlog=True, no_log=True), '\tgetting channel history...')
s = SlackRequest(self.team.token, SLACK_API_TRANSLATOR[self.type]["history"], {"channel": self.identifier, "count": BACKLOG_SIZE}, team_hash=self.team.team_hash, channel_identifier=self.identifier, clear=True)
if not slow_queue:
self.eventrouter.receive(s)
......@@ -1753,7 +1866,7 @@ class SlackChannel(SlackChannelCommon):
def unset_typing(self, user):
if self.channel_buffer and self.is_visible():
u = self.typing.get(user, None)
u = self.typing.get(user)
if u:
self.eventrouter.weechat_controller.set_refresh_buffer_list(True)
......@@ -1810,7 +1923,7 @@ class SlackChannel(SlackChannelCommon):
def update_nicklist(self, user=None):
if not self.channel_buffer:
return
if self.type not in ["channel", "group", "mpim", "shared"]:
if self.type not in ["channel", "group", "mpim", "private", "shared"]:
return
w.buffer_set(self.channel_buffer, "nicklist", "1")
# create nicklists for the current channel if they don't exist
......@@ -1977,16 +2090,32 @@ class SlackGroupChannel(SlackChannel):
# return prepend + self.slack_name
class SlackPrivateChannel(SlackGroupChannel):
"""
A private channel is a private discussion group. At the time of writing, it
differs from group channels in that group channels are channels initially
created as private, while private channels are public channels which are
later converted to private.
"""
def __init__(self, eventrouter, **kwargs):
super(SlackPrivateChannel, self).__init__(eventrouter, **kwargs)