aboutsummaryrefslogtreecommitdiffstats
path: root/wee_slack.py
diff options
context:
space:
mode:
Diffstat (limited to 'wee_slack.py')
-rw-r--r--wee_slack.py599
1 files changed, 485 insertions, 114 deletions
diff --git a/wee_slack.py b/wee_slack.py
index a9cd888..2c7adfd 100644
--- a/wee_slack.py
+++ b/wee_slack.py
@@ -59,9 +59,9 @@ except ImportError:
Reversible = object
try:
- from urllib.parse import quote, urlencode
+ from urllib.parse import quote, unquote, urlencode
except ImportError:
- from urllib import quote, urlencode
+ from urllib import quote, unquote, urlencode
try:
JSONDecodeError = json.JSONDecodeError
@@ -393,6 +393,15 @@ def format_exc_only():
return "".join(decode_from_utf8(traceback.format_exception_only(etype, value)))
+def url_encode_if_not_encoded(value):
+ decoded = unquote(value)
+ is_encoded = value != decoded
+ if is_encoded:
+ return value
+ else:
+ return quote(value)
+
+
def get_localvar_type(slack_type):
if slack_type in ("im", "mpim"):
return "private"
@@ -623,7 +632,7 @@ class EventRouter(object):
)
team.set_disconnected()
if not team.connected:
- team.connect(reconnect=True)
+ team.connect()
dbg("reconnecting {}".format(team))
@utf8_decode
@@ -659,6 +668,59 @@ class EventRouter(object):
message_json["wee_slack_metadata_team"] = team
self.receive(message_json)
+ def http_check_ratelimited(self, request_metadata, response):
+ headers_end_index = response.index("\r\n\r\n")
+ headers = response[:headers_end_index].split("\r\n")
+ http_status = headers[0].split(" ")[1]
+
+ if http_status == "429":
+ for header in headers[1:]:
+ name, value = header.split(":", 1)
+ if name.lower() == "retry-after":
+ retry_after = int(value.strip())
+ request_metadata.retry_time = time.time() + retry_after
+ return "", "ratelimited"
+
+ body = response[headers_end_index + 4 :]
+ return body, ""
+
+ def retry_request(self, request_metadata, data, return_code, err):
+ self.reply_buffer.pop(request_metadata.response_id, None)
+ self.delete_context(data)
+ retry_text = (
+ "retrying"
+ if request_metadata.should_try()
+ else "will not retry after too many failed attempts"
+ )
+ team = (
+ "for team {}".format(request_metadata.team)
+ if request_metadata.team
+ else "with token {}".format(token_for_print(request_metadata.token))
+ )
+ w.prnt(
+ "",
+ (
+ "Failed requesting {} {}, {}. "
+ + "If this persists, try increasing slack_timeout. Error (code {}): {}"
+ ).format(
+ request_metadata.request,
+ team,
+ retry_text,
+ return_code,
+ err,
+ ),
+ )
+ dbg(
+ "{} failed with return_code {} and error {}. stack:\n{}".format(
+ request_metadata.request,
+ return_code,
+ err,
+ "".join(traceback.format_stack()),
+ ),
+ level=5,
+ )
+ self.receive(request_metadata)
+
@utf8_decode
def receive_httprequest_callback(self, data, command, return_code, out, err):
"""
@@ -683,25 +745,31 @@ class EventRouter(object):
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)
- try:
- j = json.loads(
- self.reply_buffer[request_metadata.response_id].getvalue()
- )
- except:
- pass
- # dbg("Incomplete json, awaiting more", True)
- try:
- j["wee_slack_process_method"] = request_metadata.request_normalized
- if self.recording:
- self.record_event(
- j, request_metadata.team, "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:
- dbg("HTTP REQUEST CALLBACK FAILED", True)
+
+ response = self.reply_buffer[request_metadata.response_id].getvalue()
+ body, error = self.http_check_ratelimited(request_metadata, response)
+ if error:
+ self.retry_request(request_metadata, data, return_code, error)
+ else:
+ j = json.loads(body)
+
+ try:
+ j[
+ "wee_slack_process_method"
+ ] = request_metadata.request_normalized
+ if self.recording:
+ self.record_event(
+ j,
+ request_metadata.team,
+ "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:
+ dbg("HTTP REQUEST CALLBACK FAILED", True)
# We got an empty reply and this is weird so just ditch it and retry
else:
dbg("length was zero, probably a bug..")
@@ -712,33 +780,7 @@ class EventRouter(object):
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 {}, {}. "
- + "If this persists, try increasing slack_timeout. Error (code {}): {}"
- ).format(
- token_for_print(request_metadata.token),
- retry_text,
- return_code,
- err,
- ),
- )
- dbg(
- "rtm.start failed with return_code {}. stack:\n{}".format(
- return_code, "".join(traceback.format_stack())
- ),
- level=5,
- )
- self.receive(request_metadata)
+ self.retry_request(request_metadata, data, return_code, err)
return w.WEECHAT_RC_OK
def receive(self, dataobj, slow=False):
@@ -810,10 +852,12 @@ class EventRouter(object):
team = request.team
channel = request.channel
metadata = request.metadata
+ callback = request.callback
else:
team = j.get("wee_slack_metadata_team")
channel = None
metadata = {}
+ callback = None
if team:
if "channel" in j:
@@ -830,7 +874,9 @@ class EventRouter(object):
metadata["user"] = team.users.get(user_id)
dbg("running {}".format(function_name))
- if (
+ if callable(callback):
+ callback(j, self, team, channel, metadata)
+ elif (
function_name.startswith("local_")
and function_name in self.local_proc
):
@@ -919,14 +965,13 @@ def local_process_async_slack_api_request(request, event_router):
random.choice(string.ascii_uppercase + string.digits) for _ in range(4)
)
)
- params = {"useragent": "wee_slack {}".format(SCRIPT_VERSION)}
request.tried()
+ options = request.options()
+ options["header"] = "1"
context = event_router.store_context(request)
- # 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,
+ options,
config.slack_timeout,
"receive_httprequest_callback",
context,
@@ -1427,6 +1472,8 @@ class SlackRequest(object):
metadata=None,
retries=3,
token=None,
+ cookies=None,
+ callback=None,
):
if team is None and token is None:
raise ValueError("Both team and token can't be None")
@@ -1436,28 +1483,41 @@ class SlackRequest(object):
self.channel = channel
self.metadata = metadata if metadata else {}
self.retries = retries
+ self.retry_time = 0
self.token = token if token else team.token
+ self.cookies = cookies or {}
+ if ":" in self.token:
+ token, cookie = self.token.split(":", 1)
+ self.token = token
+ if cookie.startswith("d="):
+ for name, value in [c.split("=") for c in cookie.split(";")]:
+ self.cookies[name] = value
+ else:
+ self.cookies["d"] = cookie
+ self.callback = callback
+ self.domain = "api.slack.com"
+ self.reset()
+
+ def reset(self):
self.tries = 0
self.start_time = time.time()
- self.request_normalized = re.sub(r"\W+", "", request)
- self.domain = "api.slack.com"
- self.post_data["token"] = self.token
+ self.request_normalized = re.sub(r"\W+", "", self.request)
self.url = "https://{}/api/{}?{}".format(
self.domain, self.request, urlencode(encode_to_utf8(self.post_data))
)
- self.params = {"useragent": "wee_slack {}".format(SCRIPT_VERSION)}
self.response_id = sha1_hex("{}{}".format(self.url, self.start_time))
def __repr__(self):
return (
"SlackRequest(team={}, request='{}', post_data={}, retries={}, token='{}', "
- "tries={}, start_time={})"
+ "cookies={}, tries={}, start_time={})"
).format(
self.team,
self.request,
self.post_data,
self.retries,
token_for_print(self.token),
+ self.cookies,
self.tries,
self.start_time,
)
@@ -1465,6 +1525,26 @@ class SlackRequest(object):
def request_string(self):
return "{}".format(self.url)
+ def options(self):
+ cookies = "; ".join(
+ [
+ "{}={}".format(key, url_encode_if_not_encoded(value))
+ for key, value in self.cookies.items()
+ ]
+ )
+ return {
+ "useragent": "wee_slack {}".format(SCRIPT_VERSION),
+ "httpheader": "Authorization: Bearer {}".format(self.token),
+ "cookie": cookies,
+ }
+
+ def options_as_cli_args(self):
+ options = self.options()
+ options["user-agent"] = options.pop("useragent")
+ httpheader = options.pop("httpheader")
+ headers = [": ".join(x) for x in options.items()] + httpheader.split("\n")
+ return ["-H{}".format(header) for header in headers]
+
def tried(self):
self.tries += 1
self.response_id = sha1_hex("{}{}".format(self.url, time.time()))
@@ -1473,7 +1553,10 @@ class SlackRequest(object):
return self.tries < self.retries
def retry_ready(self):
- return (self.start_time + (self.tries**2)) < time.time()
+ if self.retry_time:
+ return time.time() > self.retry_time
+ else:
+ return (self.start_time + (self.tries**2)) < time.time()
class SlackSubteam(object):
@@ -1516,7 +1599,7 @@ class SlackTeam(object):
users,
bots,
channels,
- **kwargs
+ **kwargs,
):
self.slack_api_translator = copy.deepcopy(SLACK_API_TRANSLATOR)
self.identifier = team_info["id"]
@@ -1685,7 +1768,7 @@ class SlackTeam(object):
def mark_read(self, ts=None, update_remote=True, force=False):
pass
- def connect(self, reconnect=False):
+ def connect(self):
if not self.connected and not self.connecting_ws:
if self.ws_url:
self.connecting_ws = True
@@ -1737,9 +1820,7 @@ class SlackTeam(object):
# The fast reconnect failed, so start over-ish
for chan in self.channels:
self.channels[chan].history_needs_update = True
- s = initiate_connection(
- self.token, retries=999, team=self, reconnect=reconnect
- )
+ s = get_rtm_connect_request(self.token, retries=999, team=self)
self.eventrouter.receive(s)
self.connecting_rtm = True
@@ -2262,13 +2343,15 @@ class SlackChannel(SlackChannelCommon):
self.create_buffer()
return
- # Only check is_member if is_open is not set, because in some cases
- # (e.g. group DMs), is_member should be ignored in favor of is_open.
- is_open = self.is_open if hasattr(self, "is_open") else self.is_member
- if is_open or self.unread_count_display:
+ if (
+ getattr(self, "is_open", False)
+ or self.unread_count_display
+ or self.type not in ["im", "mpim"]
+ and getattr(self, "is_member", False)
+ ):
self.create_buffer()
- elif self.type == "im":
- # If it is an IM, we still might want to open it if there are unread messages.
+ elif self.type in ["im", "mpim"]:
+ # If it is an IM or MPIM, we still might want to open it if there are unread messages.
info_method = self.team.slack_api_translator[self.type].get("info")
if info_method:
s = SlackRequest(
@@ -2501,7 +2584,7 @@ class SlackChannel(SlackChannelCommon):
self.pending_history_requests.add(self.identifier)
self.get_members()
- post_data = {"channel": self.identifier, "count": config.history_fetch_count}
+ post_data = {"channel": self.identifier, "limit": config.history_fetch_count}
if self.got_history and self.messages and not full:
post_data["oldest"] = next(reversed(self.messages))
@@ -2870,7 +2953,7 @@ class SlackMPDMChannel(SlackChannel):
"""
def __init__(self, eventrouter, team_users, myidentifier, **kwargs):
- if "members" in kwargs:
+ if kwargs.get("members"):
kwargs["name"] = self.name_from_members(
team_users, kwargs["members"], myidentifier
)
@@ -3243,7 +3326,7 @@ class SlackBot(SlackUser):
"""
def __init__(self, originating_team_id, **kwargs):
- super(SlackBot, self).__init__(originating_team_id, is_bot=True, **kwargs)
+ super(SlackBot, self).__init__(originating_team_id, **kwargs)
class SlackMessage(object):
@@ -3689,7 +3772,7 @@ def handle_rtmstart(login_data, eventrouter, team, channel, metadata):
t.set_reconnect_url(login_data["url"])
t.connecting_rtm = False
- t.connect(metadata.metadata["reconnect"])
+ t.connect()
def handle_rtmconnect(login_data, eventrouter, team, channel, metadata):
@@ -3707,7 +3790,7 @@ def handle_rtmconnect(login_data, eventrouter, team, channel, metadata):
return
team.set_reconnect_url(login_data["url"])
- team.connect(metadata.metadata["reconnect"])
+ team.connect()
def handle_emojilist(emoji_json, eventrouter, team, channel, metadata):
@@ -3715,28 +3798,50 @@ def handle_emojilist(emoji_json, eventrouter, team, channel, metadata):
team.emoji_completions.extend(emoji_json["emoji"].keys())
-def handle_channelsinfo(channel_json, eventrouter, team, channel, metadata):
- channel.set_unread_count_display(
- channel_json["channel"].get("unread_count_display", 0)
- )
- channel.set_members(channel_json["channel"]["members"])
-
-
-def handle_groupsinfo(group_json, eventrouter, team, channel, metadatas):
- channel.set_unread_count_display(group_json["group"].get("unread_count_display", 0))
- channel.set_members(group_json["group"]["members"])
+def handle_conversationsinfo(channel_json, eventrouter, team, channel, metadata):
+ channel_info = channel_json["channel"]
+ if "unread_count_display" in channel_info:
+ unread_count = channel_info["unread_count_display"]
+ if unread_count and channel.channel_buffer is None:
+ channel.create_buffer()
+ channel.set_unread_count_display(unread_count)
+ if "last_read" in channel_info:
+ channel.last_read = SlackTS(channel_info["last_read"])
+ if "members" in channel_info:
+ channel.set_members(channel_info["members"])
+
+ # MPIMs don't have unread_count_display so we have to request the history to check if there are unread messages
+ if channel.type == "mpim" and not channel.channel_buffer:
+ s = SlackRequest(
+ team,
+ "conversations.history",
+ {"channel": channel.identifier, "limit": 1},
+ channel=channel,
+ metadata={"only_set_unread": True},
+ )
+ eventrouter.receive(s)
def handle_conversationsopen(
conversation_json, eventrouter, team, channel, metadata, object_name="channel"
):
- # Set unread count if the channel isn't new
- if channel:
- unread_count_display = conversation_json[object_name].get(
- "unread_count_display", 0
+ channel_info = conversation_json[object_name]
+ if not channel:
+ channel = create_channel_from_info(
+ eventrouter, channel_info, team, team.myidentifier, team.users
)
+ team.channels[channel_info["id"]] = channel
+
+ if channel.channel_buffer is None:
+ channel.create_buffer()
+
+ unread_count_display = channel_info.get("unread_count_display")
+ if unread_count_display is not None:
channel.set_unread_count_display(unread_count_display)
+ if metadata.get("switch") and config.switch_buffer_on_join:
+ w.buffer_set(channel.channel_buffer, "display", "1")
+
def handle_mpimopen(
mpim_json, eventrouter, team, channel, metadata, object_name="group"
@@ -3749,6 +3854,16 @@ def handle_mpimopen(
def handle_history(
message_json, eventrouter, team, channel, metadata, includes_threads=True
):
+ if metadata.get("only_set_unread"):
+ if message_json["messages"]:
+ latest = message_json["messages"][0]
+ latest_ts = SlackTS(latest["ts"])
+ if latest_ts > channel.last_read:
+ if not channel.channel_buffer:
+ channel.create_buffer()
+ channel.set_unread_count_display(1)
+ return
+
channel.got_history = True
channel.history_needs_update = False
for message in reversed(message_json["messages"]):
@@ -3830,14 +3945,6 @@ def handle_conversationsmembers(members_json, eventrouter, team, channel, metada
)
-def handle_conversationsinfo(message_json, eventrouter, team, channel, metadata):
- if message_json["channel"]["is_im"]:
- unread = message_json["channel"]["unread_count_display"]
- if unread:
- channel.check_should_open(True)
- channel.set_unread_count_display(unread)
-
-
def handle_usersinfo(user_json, eventrouter, team, channel, metadata):
user_info = user_json["user"]
if not metadata.get("user"):
@@ -4090,11 +4197,12 @@ def download_files(message_json, channel):
for fileout in fileout_iter(os.path.join(download_location, filename)):
if os.path.isfile(fileout):
continue
+ curl_options = SlackRequest(channel.team, "").options()
w.hook_process_hashtable(
"url:" + f["url_private"],
{
+ **curl_options,
"file_out": fileout,
- "httpheader": "Authorization: Bearer " + channel.team.token,
},
config.slack_timeout,
"",
@@ -5173,7 +5281,6 @@ def command_register(data, current_buffer, args):
"client_id={}&client_secret={}&redirect_uri={}&code={}"
).format(CLIENT_ID, CLIENT_SECRET, redirect_uri, code)
params = {"useragent": "wee_slack {}".format(SCRIPT_VERSION)}
- w.hook_process_hashtable("url:", params, config.slack_timeout, "", "")
w.hook_process_hashtable(
"url:{}".format(uri), params, config.slack_timeout, "register_callback", ""
)
@@ -5429,6 +5536,7 @@ def join_query_command_cb(data, current_buffer, args):
team,
team.slack_api_translator[channel_type]["join"],
{"users": ",".join(users)},
+ metadata={"switch": True},
)
EVENTROUTER.receive(s)
@@ -5862,10 +5970,12 @@ def command_upload(data, current_buffer, args):
if isinstance(channel, SlackThreadChannel):
post_data["thread_ts"] = channel.thread_ts
- url = SlackRequest(
- channel.team, "files.upload", post_data, channel=channel
- ).request_string()
- options = ["-s", "-Ffile=@{}".format(file_path), url]
+ request = SlackRequest(channel.team, "files.upload", post_data, channel=channel)
+ options = request.options_as_cli_args() + [
+ "-s",
+ "-Ffile=@{}".format(file_path),
+ request.request_string(),
+ ]
proxy_string = ProxyWrapper().curl()
if proxy_string:
@@ -6687,21 +6797,275 @@ def trace_calls(frame, event, arg):
return
-def initiate_connection(token, retries=3, team=None, reconnect=False):
- request_type = "connect" if team else "start"
- post_data = {"batch_presence_aware": 1}
- if request_type == "start":
- post_data["mpim_aware"] = "true"
+def get_rtm_connect_request(token, retries=3, team=None, callback=None):
return SlackRequest(
team,
- "rtm.{}".format(request_type),
- post_data,
+ "rtm.connect",
+ {"batch_presence_aware": 1},
retries=retries,
token=token,
- metadata={"reconnect": reconnect},
+ callback=callback,
)
+def get_next_page(response_json):
+ next_cursor = response_json.get("response_metadata", {}).get("next_cursor")
+ if next_cursor:
+ request = response_json["wee_slack_request_metadata"]
+ request.post_data["cursor"] = next_cursor
+ request.reset()
+ EVENTROUTER.receive(request)
+ return True
+ else:
+ return False
+
+
+def initiate_connection(token):
+ initial_data = {
+ "channels": [],
+ "members": [],
+ "usergroups": [],
+ "remaining": {
+ "channels": 2,
+ "members": 1,
+ "usergroups": 1,
+ "prefs": 1,
+ "presence": 1,
+ },
+ "errors": [],
+ }
+
+ def handle_initial(data_type):
+ def handle(response_json, eventrouter, team, channel, metadata):
+ if not response_json["ok"]:
+ if response_json["error"] == "user_is_restricted":
+ w.prnt(
+ "",
+ "You are a restricted user in this team, "
+ f"{data_type} not loaded",
+ )
+ else:
+ initial_data["errors"].append(
+ f'{data_type}: {response_json["error"]}'
+ )
+ initial_data["remaining"][data_type] -= 1
+ create_team(token, initial_data)
+ return
+
+ initial_data[data_type].extend(response_json[data_type])
+
+ if not get_next_page(response_json):
+ initial_data["remaining"][data_type] -= 1
+ create_team(token, initial_data)
+
+ return handle
+
+ def handle_prefs(response_json, eventrouter, team, channel, metadata):
+ if not response_json["ok"]:
+ initial_data["errors"].append(f'prefs: {response_json["error"]}')
+ initial_data["remaining"]["prefs"] -= 1
+ create_team(token, initial_data)
+ return
+
+ initial_data["prefs"] = response_json["prefs"]
+ initial_data["remaining"]["prefs"] -= 1
+ create_team(token, initial_data)
+
+ def handle_getPresence(response_json, eventrouter, team, channel, metadata):
+ if not response_json["ok"]:
+ initial_data["errors"].append(f'presence: {response_json["error"]}')
+ initial_data["remaining"]["presence"] -= 1
+ create_team(token, initial_data)
+ return
+
+ initial_data["presence"] = response_json
+ initial_data["remaining"]["presence"] -= 1
+ create_team(token, initial_data)
+
+ s = SlackRequest(
+ None,
+ "conversations.list",
+ {
+ "exclude_archived": True,
+ "types": "public_channel,private_channel,im",
+ "limit": 1000,
+ },
+ token=token,
+ callback=handle_initial("channels"),
+ )
+ EVENTROUTER.receive(s)
+ s = SlackRequest(
+ None,
+ "conversations.list",
+ {
+ "exclude_archived": True,
+ "types": "mpim",
+ "limit": 1000,
+ },
+ token=token,
+ callback=handle_initial("channels"),
+ )
+ EVENTROUTER.receive(s)
+ s = SlackRequest(
+ None,
+ "users.list",
+ {"limit": 1000},
+ token=token,
+ callback=handle_initial("members"),
+ )
+ EVENTROUTER.receive(s)
+ s = SlackRequest(
+ None,
+ "usergroups.list",
+ {"include_users": True},
+ token=token,
+ callback=handle_initial("usergroups"),
+ )
+ EVENTROUTER.receive(s)
+ s = SlackRequest(
+ None,
+ "users.prefs.get",
+ token=token,
+ callback=handle_prefs,
+ )
+ EVENTROUTER.receive(s)
+ s = SlackRequest(
+ None,
+ "users.getPresence",
+ token=token,
+ callback=handle_getPresence,
+ )
+ EVENTROUTER.receive(s)
+
+
+def create_channel_from_info(eventrouter, channel_info, team, myidentifier, users):
+ if channel_info.get("is_im"):
+ return SlackDMChannel(eventrouter, users, team=team, **channel_info)
+ elif channel_info.get("is_mpim"):
+ return SlackMPDMChannel(
+ eventrouter, users, myidentifier, team=team, **channel_info
+ )
+ elif channel_info.get("is_shared"):
+ return SlackSharedChannel(eventrouter, team=team, **channel_info)
+ elif channel_info.get("is_private"):
+ return SlackPrivateChannel(eventrouter, team=team, **channel_info)
+ else:
+ return SlackChannel(eventrouter, team=team, **channel_info)
+
+
+def create_team(token, initial_data):
+ if not any(initial_data["remaining"].values()):
+ if initial_data["errors"]:
+ w.prnt(
+ "",
+ "ERROR: Failed connecting to Slack with token {}: {}".format(
+ token_for_print(token), ", ".join(initial_data["errors"])
+ ),
+ )
+ if not re.match(r"^xo\w\w(-\d+){3}-[0-9a-f]+(:.*)?$", token):
+ w.prnt(
+ "",
+ "ERROR: Token does not look like a valid Slack token. "
+ "Ensure it is a valid token and not just a OAuth code.",
+ )
+
+ return
+
+ def handle_rtmconnect(response_json, eventrouter, team, channel, metadata):
+ if not response_json["ok"]:
+ print(response_json["error"])
+ return
+
+ team_id = response_json["team"]["id"]
+ myidentifier = response_json["self"]["id"]
+
+ users = {}
+ bots = {}
+ for member in initial_data["members"]:
+ if member.get("is_bot"):
+ bots[member["id"]] = SlackBot(team_id, **member)
+ else:
+ users[member["id"]] = SlackUser(team_id, **member)
+
+ self_nick = nick_from_profile(
+ users[myidentifier].profile, response_json["self"]["name"]
+ )
+
+ channels = {}
+ for channel_info in initial_data["channels"]:
+ channels[channel_info["id"]] = create_channel_from_info(
+ eventrouter, channel_info, None, myidentifier, users
+ )
+
+ subteams = {}
+ for usergroup in initial_data["usergroups"]:
+ is_member = myidentifier in usergroup["users"]
+ subteams[usergroup["id"]] = SlackSubteam(
+ team_id, is_member=is_member, **usergroup
+ )
+
+ manual_presence = (
+ "away" if initial_data["presence"]["manual_away"] else "active"
+ )
+
+ team_info = {
+ "id": team_id,
+ "name": response_json["team"]["id"],
+ "domain": response_json["team"]["domain"],
+ }
+
+ team_hash = SlackTeam.generate_team_hash(
+ team_id, response_json["team"]["domain"]
+ )
+ if not eventrouter.teams.get(team_hash):
+ team = SlackTeam(
+ eventrouter,
+ token,
+ team_hash,
+ response_json["url"],
+ team_info,
+ subteams,
+ self_nick,
+ myidentifier,
+ manual_presence,
+ users,
+ bots,
+ channels,
+ muted_channels=initial_data["prefs"]["muted_channels"],
+ highlight_words=initial_data["prefs"]["highlight_words"],
+ )
+ eventrouter.register_team(team)
+ team.connect()
+ else:
+ team = eventrouter.teams.get(team_hash)
+ if team.myidentifier != myidentifier:
+ print_error(
+ "The Slack team {} has tokens for two different users, this is not supported. The "
+ "token {} is for user {}, and the token {} is for user {}. Please remove one of "
+ "them.".format(
+ team.team_info["name"],
+ token_for_print(team.token),
+ team.nick,
+ token_for_print(token),
+ self_nick,
+ )
+ )
+ else:
+ print_error(
+ "Ignoring duplicate Slack tokens for the same team ({}) and user ({}). The two "
+ "tokens are {} and {}.".format(
+ team.team_info["name"],
+ team.nick,
+ token_for_print(team.token),
+ token_for_print(token),
+ ),
+ warning=True,
+ )
+
+ s = get_rtm_connect_request(token, callback=handle_rtmconnect)
+ EVENTROUTER.receive(s)
+
+
if __name__ == "__main__":
w = WeechatWrapper(weechat)
@@ -6777,6 +7141,13 @@ if __name__ == "__main__":
),
)
for t in tokens:
- s = initiate_connection(t)
- EVENTROUTER.receive(s)
+ if t.startswith("xoxc-") and ":" not in t:
+ w.prnt(
+ "",
+ "{}When using an xoxc token, you need to also provide the d cookie in the format token:cookie".format(
+ w.prefix("error")
+ ),
+ )
+ else:
+ initiate_connection(t)
EVENTROUTER.handle_next()