Move the weechat command setup and some commands.
This commit is contained in:
parent
be48b73395
commit
27c0836eb5
7 changed files with 707 additions and 633 deletions
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
# pylint: disable=redefined-builtin
|
||||||
|
from builtins import str
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
|
||||||
import webcolors
|
import webcolors
|
||||||
|
|
445
matrix/commands.py
Normal file
445
matrix/commands.py
Normal file
|
@ -0,0 +1,445 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
import matrix.globals
|
||||||
|
|
||||||
|
from matrix.utf import utf8_decode
|
||||||
|
from matrix.api import MatrixMessage, MessageType
|
||||||
|
from matrix.utils import key_from_value, tags_from_line_data
|
||||||
|
from matrix.socket import send_or_queue
|
||||||
|
|
||||||
|
|
||||||
|
W = matrix.globals.W
|
||||||
|
GLOBAL_OPTIONS = matrix.globals.OPTIONS
|
||||||
|
SERVERS = matrix.globals.SERVERS
|
||||||
|
|
||||||
|
|
||||||
|
def hook_commands():
|
||||||
|
W.hook_completion(
|
||||||
|
"matrix_server_commands",
|
||||||
|
"Matrix server completion",
|
||||||
|
"server_command_completion_cb",
|
||||||
|
""
|
||||||
|
)
|
||||||
|
|
||||||
|
W.hook_completion(
|
||||||
|
"matrix_servers",
|
||||||
|
"Matrix server completion",
|
||||||
|
"matrix_server_completion_cb",
|
||||||
|
""
|
||||||
|
)
|
||||||
|
|
||||||
|
W.hook_completion(
|
||||||
|
"matrix_commands",
|
||||||
|
"Matrix command completion",
|
||||||
|
"matrix_command_completion_cb",
|
||||||
|
""
|
||||||
|
)
|
||||||
|
|
||||||
|
W.hook_completion(
|
||||||
|
"matrix_messages",
|
||||||
|
"Matrix message completion",
|
||||||
|
"matrix_message_completion_cb",
|
||||||
|
""
|
||||||
|
)
|
||||||
|
|
||||||
|
W.hook_completion(
|
||||||
|
"matrix_debug_types",
|
||||||
|
"Matrix debugging type completion",
|
||||||
|
"matrix_debug_completion_cb",
|
||||||
|
""
|
||||||
|
)
|
||||||
|
|
||||||
|
W.hook_command(
|
||||||
|
# Command name and short description
|
||||||
|
'matrix', 'Matrix chat protocol command',
|
||||||
|
# Synopsis
|
||||||
|
(
|
||||||
|
'server add <server-name> <hostname>[:<port>] ||'
|
||||||
|
'server delete|list|listfull <server-name> ||'
|
||||||
|
'connect <server-name> ||'
|
||||||
|
'disconnect <server-name> ||'
|
||||||
|
'reconnect <server-name> ||'
|
||||||
|
'debug <debug-type> ||'
|
||||||
|
'help <matrix-command>'
|
||||||
|
),
|
||||||
|
# Description
|
||||||
|
(
|
||||||
|
' server: list, add, or remove Matrix servers\n'
|
||||||
|
' connect: connect to Matrix servers\n'
|
||||||
|
'disconnect: disconnect from one or all Matrix servers\n'
|
||||||
|
' reconnect: reconnect to server(s)\n\n'
|
||||||
|
' help: show detailed command help\n\n'
|
||||||
|
' debug: enable or disable debugging\n\n'
|
||||||
|
'Use /matrix help [command] to find out more\n'
|
||||||
|
),
|
||||||
|
# Completions
|
||||||
|
(
|
||||||
|
'server %(matrix_server_commands)|%* ||'
|
||||||
|
'connect %(matrix_servers) ||'
|
||||||
|
'disconnect %(matrix_servers) ||'
|
||||||
|
'reconnect %(matrix_servers) ||'
|
||||||
|
'debug %(matrix_debug_types) ||'
|
||||||
|
'help %(matrix_commands)'
|
||||||
|
),
|
||||||
|
# Function name
|
||||||
|
'matrix_command_cb', '')
|
||||||
|
|
||||||
|
W.hook_command(
|
||||||
|
# Command name and short description
|
||||||
|
'redact', 'redact messages',
|
||||||
|
# Synopsis
|
||||||
|
(
|
||||||
|
'<message-number>[:<"message-part">] [<reason>]'
|
||||||
|
),
|
||||||
|
# Description
|
||||||
|
(
|
||||||
|
"message-number: number of the message to redact (message numbers"
|
||||||
|
"\n start from the last recieved as "
|
||||||
|
"1 and count up)\n"
|
||||||
|
" message-part: a shortened part of the message\n"
|
||||||
|
" reason: the redaction reason\n"
|
||||||
|
),
|
||||||
|
# Completions
|
||||||
|
(
|
||||||
|
'%(matrix_messages)'
|
||||||
|
),
|
||||||
|
# Function name
|
||||||
|
'matrix_redact_command_cb', '')
|
||||||
|
|
||||||
|
W.hook_command_run('/topic', 'matrix_command_topic_cb', '')
|
||||||
|
W.hook_command_run('/buffer clear', 'matrix_command_buf_clear_cb', '')
|
||||||
|
W.hook_command_run('/join', 'matrix_command_join_cb', '')
|
||||||
|
W.hook_command_run('/part', 'matrix_command_part_cb', '')
|
||||||
|
W.hook_command_run('/invite', 'matrix_command_invite_cb', '')
|
||||||
|
|
||||||
|
if GLOBAL_OPTIONS.enable_backlog:
|
||||||
|
hook_page_up()
|
||||||
|
|
||||||
|
|
||||||
|
def matrix_fetch_old_messages(server, room_id):
|
||||||
|
room = server.rooms[room_id]
|
||||||
|
prev_batch = room.prev_batch
|
||||||
|
|
||||||
|
if not prev_batch:
|
||||||
|
return
|
||||||
|
|
||||||
|
message = MatrixMessage(server, GLOBAL_OPTIONS, MessageType.ROOM_MSG,
|
||||||
|
room_id=room_id, extra_id=prev_batch)
|
||||||
|
|
||||||
|
send_or_queue(server, message)
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def hook_page_up():
|
||||||
|
GLOBAL_OPTIONS.page_up_hook = W.hook_command_run(
|
||||||
|
'/window page_up',
|
||||||
|
'matrix_command_pgup_cb',
|
||||||
|
''
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@utf8_decode
|
||||||
|
def matrix_debug_completion_cb(data, completion_item, buffer, completion):
|
||||||
|
for debug_type in ["messaging", "network", "timing"]:
|
||||||
|
W.hook_completion_list_add(
|
||||||
|
completion,
|
||||||
|
debug_type,
|
||||||
|
0,
|
||||||
|
W.WEECHAT_LIST_POS_SORT)
|
||||||
|
return W.WEECHAT_RC_OK
|
||||||
|
|
||||||
|
|
||||||
|
@utf8_decode
|
||||||
|
def matrix_command_buf_clear_cb(data, buffer, command):
|
||||||
|
for server in SERVERS.values():
|
||||||
|
if buffer in server.buffers.values():
|
||||||
|
room_id = key_from_value(server.buffers, buffer)
|
||||||
|
server.rooms[room_id].prev_batch = server.next_batch
|
||||||
|
|
||||||
|
return W.WEECHAT_RC_OK
|
||||||
|
|
||||||
|
return W.WEECHAT_RC_OK
|
||||||
|
|
||||||
|
|
||||||
|
@utf8_decode
|
||||||
|
def matrix_command_pgup_cb(data, buffer, command):
|
||||||
|
# TODO the highlight status of a line isn't allowed to be updated/changed
|
||||||
|
# via hdata, therefore the highlight status of a messages can't be
|
||||||
|
# reoredered this would need to be fixed in weechat
|
||||||
|
# TODO we shouldn't fetch and print out more messages than
|
||||||
|
# max_buffer_lines_number or older messages than max_buffer_lines_minutes
|
||||||
|
for server in SERVERS.values():
|
||||||
|
if buffer in server.buffers.values():
|
||||||
|
window = W.window_search_with_buffer(buffer)
|
||||||
|
|
||||||
|
first_line_displayed = bool(
|
||||||
|
W.window_get_integer(window, "first_line_displayed")
|
||||||
|
)
|
||||||
|
|
||||||
|
if first_line_displayed:
|
||||||
|
room_id = key_from_value(server.buffers, buffer)
|
||||||
|
matrix_fetch_old_messages(server, room_id)
|
||||||
|
|
||||||
|
return W.WEECHAT_RC_OK
|
||||||
|
|
||||||
|
return W.WEECHAT_RC_OK
|
||||||
|
|
||||||
|
|
||||||
|
@utf8_decode
|
||||||
|
def matrix_command_join_cb(data, buffer, command):
|
||||||
|
def join(server, args):
|
||||||
|
split_args = args.split(" ", 1)
|
||||||
|
|
||||||
|
# TODO handle join for non public rooms
|
||||||
|
if len(split_args) != 2:
|
||||||
|
message = ("{prefix}Error with command \"/join\" (help on "
|
||||||
|
"command: /help join)").format(
|
||||||
|
prefix=W.prefix("error"))
|
||||||
|
W.prnt("", message)
|
||||||
|
return
|
||||||
|
|
||||||
|
_, room_id = split_args
|
||||||
|
message = MatrixMessage(
|
||||||
|
server,
|
||||||
|
GLOBAL_OPTIONS,
|
||||||
|
MessageType.JOIN,
|
||||||
|
room_id=room_id
|
||||||
|
)
|
||||||
|
send_or_queue(server, message)
|
||||||
|
|
||||||
|
for server in SERVERS.values():
|
||||||
|
if buffer in server.buffers.values():
|
||||||
|
join(server, command)
|
||||||
|
return W.WEECHAT_RC_OK_EAT
|
||||||
|
elif buffer == server.server_buffer:
|
||||||
|
join(server, command)
|
||||||
|
return W.WEECHAT_RC_OK_EAT
|
||||||
|
|
||||||
|
return W.WEECHAT_RC_OK
|
||||||
|
|
||||||
|
|
||||||
|
@utf8_decode
|
||||||
|
def matrix_command_part_cb(data, buffer, command):
|
||||||
|
def part(server, buffer, args):
|
||||||
|
rooms = []
|
||||||
|
|
||||||
|
split_args = args.split(" ", 1)
|
||||||
|
|
||||||
|
if len(split_args) == 1:
|
||||||
|
if buffer == server.server_buffer:
|
||||||
|
message = ("{prefix}Error with command \"/part\" (help on "
|
||||||
|
"command: /help part)").format(
|
||||||
|
prefix=W.prefix("error"))
|
||||||
|
W.prnt("", message)
|
||||||
|
return
|
||||||
|
|
||||||
|
rooms = [key_from_value(server.buffers, buffer)]
|
||||||
|
|
||||||
|
else:
|
||||||
|
_, rooms = split_args
|
||||||
|
rooms = rooms.split(" ")
|
||||||
|
|
||||||
|
for room_id in rooms:
|
||||||
|
message = MatrixMessage(
|
||||||
|
server,
|
||||||
|
GLOBAL_OPTIONS,
|
||||||
|
MessageType.PART,
|
||||||
|
room_id=room_id
|
||||||
|
)
|
||||||
|
send_or_queue(server, message)
|
||||||
|
|
||||||
|
for server in SERVERS.values():
|
||||||
|
if buffer in server.buffers.values():
|
||||||
|
part(server, buffer, command)
|
||||||
|
return W.WEECHAT_RC_OK_EAT
|
||||||
|
elif buffer == server.server_buffer:
|
||||||
|
part(server, buffer, command)
|
||||||
|
return W.WEECHAT_RC_OK_EAT
|
||||||
|
|
||||||
|
return W.WEECHAT_RC_OK
|
||||||
|
|
||||||
|
|
||||||
|
@utf8_decode
|
||||||
|
def matrix_command_invite_cb(data, buffer, command):
|
||||||
|
def invite(server, buf, args):
|
||||||
|
split_args = args.split(" ", 1)
|
||||||
|
|
||||||
|
# TODO handle join for non public rooms
|
||||||
|
if len(split_args) != 2:
|
||||||
|
message = ("{prefix}Error with command \"/invite\" (help on "
|
||||||
|
"command: /help invite)").format(
|
||||||
|
prefix=W.prefix("error"))
|
||||||
|
W.prnt("", message)
|
||||||
|
return
|
||||||
|
|
||||||
|
_, invitee = split_args
|
||||||
|
room_id = key_from_value(server.buffers, buf)
|
||||||
|
|
||||||
|
body = {"user_id": invitee}
|
||||||
|
|
||||||
|
message = MatrixMessage(
|
||||||
|
server,
|
||||||
|
GLOBAL_OPTIONS,
|
||||||
|
MessageType.INVITE,
|
||||||
|
room_id=room_id,
|
||||||
|
data=body
|
||||||
|
)
|
||||||
|
send_or_queue(server, message)
|
||||||
|
|
||||||
|
for server in SERVERS.values():
|
||||||
|
if buffer in server.buffers.values():
|
||||||
|
invite(server, buffer, command)
|
||||||
|
return W.WEECHAT_RC_OK_EAT
|
||||||
|
|
||||||
|
return W.WEECHAT_RC_OK
|
||||||
|
|
||||||
|
|
||||||
|
def event_id_from_line(buf, target_number):
|
||||||
|
# type: (weechat.buffer, int) -> str
|
||||||
|
own_lines = W.hdata_pointer(W.hdata_get('buffer'), buf, 'own_lines')
|
||||||
|
if own_lines:
|
||||||
|
line = W.hdata_pointer(
|
||||||
|
W.hdata_get('lines'),
|
||||||
|
own_lines,
|
||||||
|
'last_line'
|
||||||
|
)
|
||||||
|
|
||||||
|
line_number = 1
|
||||||
|
|
||||||
|
while line:
|
||||||
|
line_data = W.hdata_pointer(
|
||||||
|
W.hdata_get('line'),
|
||||||
|
line,
|
||||||
|
'data'
|
||||||
|
)
|
||||||
|
|
||||||
|
if line_data:
|
||||||
|
tags = tags_from_line_data(line_data)
|
||||||
|
|
||||||
|
# Only count non redacted user messages
|
||||||
|
if ("matrix_message" in tags
|
||||||
|
and 'matrix_redacted' not in tags
|
||||||
|
and "matrix_new_redacted" not in tags):
|
||||||
|
|
||||||
|
if line_number == target_number:
|
||||||
|
for tag in tags:
|
||||||
|
if tag.startswith("matrix_id"):
|
||||||
|
event_id = tag[10:]
|
||||||
|
return event_id
|
||||||
|
|
||||||
|
line_number += 1
|
||||||
|
|
||||||
|
line = W.hdata_move(W.hdata_get('line'), line, -1)
|
||||||
|
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
@utf8_decode
|
||||||
|
def matrix_redact_command_cb(data, buffer, args):
|
||||||
|
for server in SERVERS.values():
|
||||||
|
if buffer in server.buffers.values():
|
||||||
|
body = {}
|
||||||
|
|
||||||
|
room_id = key_from_value(server.buffers, buffer)
|
||||||
|
|
||||||
|
matches = re.match(r"(\d+)(:\".*\")? ?(.*)?", args)
|
||||||
|
|
||||||
|
if not matches:
|
||||||
|
message = ("{prefix}matrix: Invalid command arguments (see "
|
||||||
|
"the help for the command /help redact)").format(
|
||||||
|
prefix=W.prefix("error"))
|
||||||
|
W.prnt("", message)
|
||||||
|
return W.WEECHAT_RC_ERROR
|
||||||
|
|
||||||
|
line_string, _, reason = matches.groups()
|
||||||
|
line = int(line_string)
|
||||||
|
|
||||||
|
if reason:
|
||||||
|
body = {"reason": reason}
|
||||||
|
|
||||||
|
event_id = event_id_from_line(buffer, line)
|
||||||
|
|
||||||
|
if not event_id:
|
||||||
|
message = ("{prefix}matrix: No such message with number "
|
||||||
|
"{number} found").format(
|
||||||
|
prefix=W.prefix("error"),
|
||||||
|
number=line)
|
||||||
|
W.prnt("", message)
|
||||||
|
return W.WEECHAT_RC_OK
|
||||||
|
|
||||||
|
message = MatrixMessage(
|
||||||
|
server,
|
||||||
|
GLOBAL_OPTIONS,
|
||||||
|
MessageType.REDACT,
|
||||||
|
data=body,
|
||||||
|
room_id=room_id,
|
||||||
|
extra_id=event_id
|
||||||
|
)
|
||||||
|
send_or_queue(server, message)
|
||||||
|
|
||||||
|
return W.WEECHAT_RC_OK
|
||||||
|
|
||||||
|
elif buffer == server.server_buffer:
|
||||||
|
message = ("{prefix}matrix: command \"redact\" must be "
|
||||||
|
"executed on a Matrix channel buffer").format(
|
||||||
|
prefix=W.prefix("error"))
|
||||||
|
W.prnt("", message)
|
||||||
|
return W.WEECHAT_RC_OK
|
||||||
|
|
||||||
|
return W.WEECHAT_RC_OK
|
||||||
|
|
||||||
|
|
||||||
|
@utf8_decode
|
||||||
|
def matrix_message_completion_cb(data, completion_item, buffer, completion):
|
||||||
|
own_lines = W.hdata_pointer(W.hdata_get('buffer'), buffer, 'own_lines')
|
||||||
|
if own_lines:
|
||||||
|
line = W.hdata_pointer(
|
||||||
|
W.hdata_get('lines'),
|
||||||
|
own_lines,
|
||||||
|
'last_line'
|
||||||
|
)
|
||||||
|
|
||||||
|
line_number = 1
|
||||||
|
|
||||||
|
while line:
|
||||||
|
line_data = W.hdata_pointer(
|
||||||
|
W.hdata_get('line'),
|
||||||
|
line,
|
||||||
|
'data'
|
||||||
|
)
|
||||||
|
|
||||||
|
if line_data:
|
||||||
|
message = W.hdata_string(W.hdata_get('line_data'), line_data,
|
||||||
|
'message')
|
||||||
|
|
||||||
|
tags = tags_from_line_data(line_data)
|
||||||
|
|
||||||
|
# Only add non redacted user messages to the completion
|
||||||
|
if (message
|
||||||
|
and 'matrix_message' in tags
|
||||||
|
and 'matrix_redacted' not in tags):
|
||||||
|
|
||||||
|
if len(message) > GLOBAL_OPTIONS.redaction_comp_len + 2:
|
||||||
|
message = (
|
||||||
|
message[:GLOBAL_OPTIONS.redaction_comp_len]
|
||||||
|
+ '..')
|
||||||
|
|
||||||
|
item = ("{number}:\"{message}\"").format(
|
||||||
|
number=line_number,
|
||||||
|
message=message)
|
||||||
|
|
||||||
|
W.hook_completion_list_add(
|
||||||
|
completion,
|
||||||
|
item,
|
||||||
|
0,
|
||||||
|
W.WEECHAT_LIST_POS_END)
|
||||||
|
line_number += 1
|
||||||
|
|
||||||
|
line = W.hdata_move(W.hdata_get('line'), line, -1)
|
||||||
|
|
||||||
|
return W.WEECHAT_RC_OK
|
96
matrix/globals.py
Normal file
96
matrix/globals.py
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
# pylint: disable=import-error
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from matrix.utf import WeechatWrapper
|
||||||
|
from matrix.config import PluginOptions, Option
|
||||||
|
|
||||||
|
import weechat
|
||||||
|
|
||||||
|
|
||||||
|
def init_matrix_config():
|
||||||
|
config_file = W.config_new("matrix", "matrix_config_reload_cb", "")
|
||||||
|
|
||||||
|
look_options = [
|
||||||
|
Option(
|
||||||
|
"redactions", "integer",
|
||||||
|
"strikethrough|notice|delete", 0, 0,
|
||||||
|
"strikethrough",
|
||||||
|
(
|
||||||
|
"Only notice redactions, strike through or delete "
|
||||||
|
"redacted messages"
|
||||||
|
)
|
||||||
|
),
|
||||||
|
Option(
|
||||||
|
"server_buffer", "integer",
|
||||||
|
"merge_with_core|merge_without_core|independent",
|
||||||
|
0, 0, "merge_with_core", "Merge server buffers"
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
network_options = [
|
||||||
|
Option(
|
||||||
|
"max_initial_sync_events", "integer",
|
||||||
|
"", 1, 10000,
|
||||||
|
"30",
|
||||||
|
(
|
||||||
|
"How many events to fetch during the initial sync"
|
||||||
|
)
|
||||||
|
),
|
||||||
|
Option(
|
||||||
|
"max_backlog_sync_events", "integer",
|
||||||
|
"", 1, 100,
|
||||||
|
"10",
|
||||||
|
(
|
||||||
|
"How many events to fetch during backlog fetching"
|
||||||
|
)
|
||||||
|
),
|
||||||
|
Option(
|
||||||
|
"fetch_backlog_on_pgup", "boolean",
|
||||||
|
"", 0, 0,
|
||||||
|
"on",
|
||||||
|
(
|
||||||
|
"Fetch messages in the backlog on a window page up event"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
def add_global_options(section, options):
|
||||||
|
for option in options:
|
||||||
|
OPTIONS.options[option.name] = W.config_new_option(
|
||||||
|
config_file, section, option.name,
|
||||||
|
option.type, option.description, option.string_values,
|
||||||
|
option.min, option.max, option.value, option.value, 0, "",
|
||||||
|
"", "matrix_config_change_cb", "", "", "")
|
||||||
|
|
||||||
|
section = W.config_new_section(config_file, "color", 0, 0, "", "", "", "",
|
||||||
|
"", "", "", "", "", "")
|
||||||
|
|
||||||
|
# TODO color options
|
||||||
|
|
||||||
|
section = W.config_new_section(config_file, "look", 0, 0, "", "", "", "",
|
||||||
|
"", "", "", "", "", "")
|
||||||
|
|
||||||
|
add_global_options(section, look_options)
|
||||||
|
|
||||||
|
section = W.config_new_section(config_file, "network", 0, 0, "", "", "",
|
||||||
|
"", "", "", "", "", "", "")
|
||||||
|
|
||||||
|
add_global_options(section, network_options)
|
||||||
|
|
||||||
|
W.config_new_section(
|
||||||
|
config_file, "server",
|
||||||
|
0, 0,
|
||||||
|
"matrix_config_server_read_cb",
|
||||||
|
"",
|
||||||
|
"matrix_config_server_write_cb",
|
||||||
|
"", "", "", "", "", "", ""
|
||||||
|
)
|
||||||
|
|
||||||
|
return config_file
|
||||||
|
|
||||||
|
|
||||||
|
W = weechat if sys.hexversion >= 0x3000000 else WeechatWrapper(weechat)
|
||||||
|
|
||||||
|
OPTIONS = PluginOptions() # type: PluginOptions
|
||||||
|
SERVERS = dict() # type: Dict[str, MatrixServer]
|
||||||
|
CONFIG = None # type: weechat.config
|
|
@ -5,10 +5,8 @@ from __future__ import unicode_literals
|
||||||
import ssl
|
import ssl
|
||||||
|
|
||||||
from collections import deque
|
from collections import deque
|
||||||
|
|
||||||
from http_parser.pyparser import HttpParser
|
from http_parser.pyparser import HttpParser
|
||||||
|
|
||||||
|
|
||||||
from matrix.config import Option
|
from matrix.config import Option
|
||||||
|
|
||||||
|
|
||||||
|
|
72
matrix/socket.py
Normal file
72
matrix/socket.py
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import time
|
||||||
|
|
||||||
|
from builtins import bytes, str
|
||||||
|
|
||||||
|
import matrix.globals
|
||||||
|
from matrix.config import DebugType
|
||||||
|
from matrix.utils import prnt_debug, server_buffer_prnt
|
||||||
|
|
||||||
|
|
||||||
|
W = matrix.globals.W
|
||||||
|
|
||||||
|
|
||||||
|
def disconnect(server):
|
||||||
|
# type: (MatrixServer) -> None
|
||||||
|
if server.fd_hook:
|
||||||
|
W.unhook(server.fd_hook)
|
||||||
|
|
||||||
|
server.fd_hook = None
|
||||||
|
server.socket = None
|
||||||
|
server.connected = False
|
||||||
|
|
||||||
|
server_buffer_prnt(server, "Disconnected")
|
||||||
|
|
||||||
|
|
||||||
|
def send_or_queue(server, message):
|
||||||
|
# type: (MatrixServer, MatrixMessage) -> None
|
||||||
|
if not send(server, message):
|
||||||
|
prnt_debug(DebugType.MESSAGING, server,
|
||||||
|
("{prefix} Failed sending message of type {t}. "
|
||||||
|
"Adding to queue").format(
|
||||||
|
prefix=W.prefix("error"),
|
||||||
|
t=message.type))
|
||||||
|
server.send_queue.append(message)
|
||||||
|
|
||||||
|
|
||||||
|
def send(server, message):
|
||||||
|
# type: (MatrixServer, MatrixMessage) -> bool
|
||||||
|
|
||||||
|
request = message.request.request
|
||||||
|
payload = message.request.payload
|
||||||
|
|
||||||
|
prnt_debug(DebugType.MESSAGING, server,
|
||||||
|
"{prefix} Sending message of type {t}.".format(
|
||||||
|
prefix=W.prefix("error"),
|
||||||
|
t=message.type))
|
||||||
|
|
||||||
|
try:
|
||||||
|
start = time.time()
|
||||||
|
|
||||||
|
# TODO we probably shouldn't use sendall here.
|
||||||
|
server.socket.sendall(bytes(request, 'utf-8'))
|
||||||
|
if payload:
|
||||||
|
server.socket.sendall(bytes(payload, 'utf-8'))
|
||||||
|
|
||||||
|
end = time.time()
|
||||||
|
message.send_time = end
|
||||||
|
send_time = (end - start) * 1000
|
||||||
|
prnt_debug(DebugType.NETWORK, server,
|
||||||
|
("Message done sending ({t}ms), putting message in the "
|
||||||
|
"receive queue.").format(t=send_time))
|
||||||
|
|
||||||
|
server.receive_queue.append(message)
|
||||||
|
return True
|
||||||
|
|
||||||
|
except OSError as error:
|
||||||
|
disconnect(server)
|
||||||
|
server_buffer_prnt(server, str(error))
|
||||||
|
return False
|
46
matrix/utils.py
Normal file
46
matrix/utils.py
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import time
|
||||||
|
|
||||||
|
import matrix.globals
|
||||||
|
|
||||||
|
|
||||||
|
W = matrix.globals.W
|
||||||
|
GLOBAL_OPTIONS = matrix.globals.OPTIONS
|
||||||
|
|
||||||
|
|
||||||
|
def key_from_value(dictionary, value):
|
||||||
|
# type: (Dict[str, Any], Any) -> str
|
||||||
|
return list(dictionary.keys())[list(dictionary.values()).index(value)]
|
||||||
|
|
||||||
|
|
||||||
|
def prnt_debug(debug_type, server, message):
|
||||||
|
if debug_type in GLOBAL_OPTIONS.debug:
|
||||||
|
W.prnt(server.server_buffer, message)
|
||||||
|
|
||||||
|
|
||||||
|
def server_buffer_prnt(server, string):
|
||||||
|
# type: (MatrixServer, str) -> None
|
||||||
|
assert server.server_buffer
|
||||||
|
buffer = server.server_buffer
|
||||||
|
now = int(time.time())
|
||||||
|
W.prnt_date_tags(buffer, now, "", string)
|
||||||
|
|
||||||
|
|
||||||
|
def tags_from_line_data(line_data):
|
||||||
|
# type: (weechat.hdata) -> List[str]
|
||||||
|
tags_count = W.hdata_get_var_array_size(
|
||||||
|
W.hdata_get('line_data'),
|
||||||
|
line_data,
|
||||||
|
'tags_array')
|
||||||
|
|
||||||
|
tags = [
|
||||||
|
W.hdata_string(
|
||||||
|
W.hdata_get('line_data'),
|
||||||
|
line_data,
|
||||||
|
'%d|tags_array' % i
|
||||||
|
) for i in range(tags_count)]
|
||||||
|
|
||||||
|
return tags
|
|
@ -8,11 +8,9 @@ import ssl
|
||||||
import time
|
import time
|
||||||
import datetime
|
import datetime
|
||||||
import pprint
|
import pprint
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
|
|
||||||
# pylint: disable=redefined-builtin
|
# pylint: disable=redefined-builtin
|
||||||
from builtins import bytes, str
|
from builtins import str
|
||||||
|
|
||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
|
|
||||||
|
@ -20,20 +18,48 @@ from operator import itemgetter
|
||||||
from typing import (List, Set, Dict, Tuple, Text, Optional, AnyStr, Deque, Any)
|
from typing import (List, Set, Dict, Tuple, Text, Optional, AnyStr, Deque, Any)
|
||||||
|
|
||||||
from matrix import colors
|
from matrix import colors
|
||||||
from matrix.utf import WeechatWrapper, utf8_decode
|
from matrix.utf import utf8_decode
|
||||||
from matrix.http import HttpResponse
|
from matrix.http import HttpResponse
|
||||||
from matrix.api import MatrixMessage, MessageType
|
from matrix.api import MatrixMessage, MessageType
|
||||||
from matrix.server import MatrixServer
|
from matrix.server import MatrixServer
|
||||||
|
from matrix.socket import disconnect, send_or_queue, send
|
||||||
|
|
||||||
|
|
||||||
|
# Weechat searches for the registered callbacks in the global scope, import the
|
||||||
|
# callbacks here so weechat can find them.
|
||||||
|
from matrix.commands import (
|
||||||
|
hook_commands,
|
||||||
|
hook_page_up,
|
||||||
|
matrix_command_join_cb,
|
||||||
|
matrix_command_part_cb,
|
||||||
|
matrix_command_invite_cb,
|
||||||
|
matrix_command_pgup_cb,
|
||||||
|
matrix_redact_command_cb,
|
||||||
|
matrix_command_buf_clear_cb,
|
||||||
|
matrix_debug_completion_cb,
|
||||||
|
matrix_message_completion_cb
|
||||||
|
)
|
||||||
|
|
||||||
|
from matrix.utils import (
|
||||||
|
key_from_value,
|
||||||
|
server_buffer_prnt,
|
||||||
|
prnt_debug,
|
||||||
|
tags_from_line_data
|
||||||
|
)
|
||||||
|
|
||||||
from matrix.config import (
|
from matrix.config import (
|
||||||
PluginOptions,
|
|
||||||
Option,
|
|
||||||
DebugType,
|
DebugType,
|
||||||
RedactType,
|
RedactType,
|
||||||
ServerBufferType
|
ServerBufferType
|
||||||
)
|
)
|
||||||
|
|
||||||
# pylint: disable=import-error
|
import matrix.globals
|
||||||
import weechat
|
|
||||||
|
W = matrix.globals.W
|
||||||
|
GLOBAL_OPTIONS = matrix.globals.OPTIONS
|
||||||
|
CONFIG = matrix.globals.CONFIG
|
||||||
|
SERVERS = matrix.globals.SERVERS
|
||||||
|
|
||||||
|
|
||||||
WEECHAT_SCRIPT_NAME = "matrix" # type: str
|
WEECHAT_SCRIPT_NAME = "matrix" # type: str
|
||||||
WEECHAT_SCRIPT_DESCRIPTION = "matrix chat plugin" # type: str
|
WEECHAT_SCRIPT_DESCRIPTION = "matrix chat plugin" # type: str
|
||||||
|
@ -41,15 +67,6 @@ WEECHAT_SCRIPT_AUTHOR = "Damir Jelić <poljar@termina.org.uk>" # type: str
|
||||||
WEECHAT_SCRIPT_VERSION = "0.1" # type: str
|
WEECHAT_SCRIPT_VERSION = "0.1" # type: str
|
||||||
WEECHAT_SCRIPT_LICENSE = "MIT" # type: str
|
WEECHAT_SCRIPT_LICENSE = "MIT" # type: str
|
||||||
|
|
||||||
SERVERS = dict() # type: Dict[str, MatrixServer]
|
|
||||||
CONFIG = None # type: weechat.config
|
|
||||||
GLOBAL_OPTIONS = None # type: PluginOptions
|
|
||||||
|
|
||||||
|
|
||||||
def prnt_debug(debug_type, server, message):
|
|
||||||
if debug_type in GLOBAL_OPTIONS.debug:
|
|
||||||
W.prnt(server.server_buffer, message)
|
|
||||||
|
|
||||||
|
|
||||||
class MatrixUser:
|
class MatrixUser:
|
||||||
def __init__(self, name, display_name):
|
def __init__(self, name, display_name):
|
||||||
|
@ -73,11 +90,6 @@ class MatrixRoom:
|
||||||
self.encrypted = False # type: bool
|
self.encrypted = False # type: bool
|
||||||
|
|
||||||
|
|
||||||
def key_from_value(dictionary, value):
|
|
||||||
# type: (Dict[str, Any], Any) -> str
|
|
||||||
return list(dictionary.keys())[list(dictionary.values()).index(value)]
|
|
||||||
|
|
||||||
|
|
||||||
@utf8_decode
|
@utf8_decode
|
||||||
def server_config_change_cb(server_name, option):
|
def server_config_change_cb(server_name, option):
|
||||||
# type: (str, weechat.config_option) -> int
|
# type: (str, weechat.config_option) -> int
|
||||||
|
@ -363,8 +375,8 @@ def date_from_age(age):
|
||||||
|
|
||||||
def color_for_tags(color):
|
def color_for_tags(color):
|
||||||
if color == "weechat.color.chat_nick_self":
|
if color == "weechat.color.chat_nick_self":
|
||||||
option = weechat.config_get(color)
|
option = W.config_get(color)
|
||||||
return weechat.config_string(option)
|
return W.config_string(option)
|
||||||
return color
|
return color
|
||||||
|
|
||||||
|
|
||||||
|
@ -964,52 +976,6 @@ def matrix_login(server):
|
||||||
send_or_queue(server, message)
|
send_or_queue(server, message)
|
||||||
|
|
||||||
|
|
||||||
def send_or_queue(server, message):
|
|
||||||
# type: (MatrixServer, MatrixMessage) -> None
|
|
||||||
if not send(server, message):
|
|
||||||
prnt_debug(DebugType.MESSAGING, server,
|
|
||||||
("{prefix} Failed sending message of type {t}. "
|
|
||||||
"Adding to queue").format(
|
|
||||||
prefix=W.prefix("error"),
|
|
||||||
t=message.type))
|
|
||||||
server.send_queue.append(message)
|
|
||||||
|
|
||||||
|
|
||||||
def send(server, message):
|
|
||||||
# type: (MatrixServer, MatrixMessage) -> bool
|
|
||||||
|
|
||||||
request = message.request.request
|
|
||||||
payload = message.request.payload
|
|
||||||
|
|
||||||
prnt_debug(DebugType.MESSAGING, server,
|
|
||||||
"{prefix} Sending message of type {t}.".format(
|
|
||||||
prefix=W.prefix("error"),
|
|
||||||
t=message.type))
|
|
||||||
|
|
||||||
try:
|
|
||||||
start = time.time()
|
|
||||||
|
|
||||||
# TODO we probably shouldn't use sendall here.
|
|
||||||
server.socket.sendall(bytes(request, 'utf-8'))
|
|
||||||
if payload:
|
|
||||||
server.socket.sendall(bytes(payload, 'utf-8'))
|
|
||||||
|
|
||||||
end = time.time()
|
|
||||||
message.send_time = end
|
|
||||||
send_time = (end - start) * 1000
|
|
||||||
prnt_debug(DebugType.NETWORK, server,
|
|
||||||
("Message done sending ({t}ms), putting message in the "
|
|
||||||
"receive queue.").format(t=send_time))
|
|
||||||
|
|
||||||
server.receive_queue.append(message)
|
|
||||||
return True
|
|
||||||
|
|
||||||
except socket.error as error:
|
|
||||||
disconnect(server)
|
|
||||||
server_buffer_prnt(server, str(error))
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
@utf8_decode
|
@utf8_decode
|
||||||
def receive_cb(server_name, file_descriptor):
|
def receive_cb(server_name, file_descriptor):
|
||||||
server = SERVERS[server_name]
|
server = SERVERS[server_name]
|
||||||
|
@ -1081,26 +1047,6 @@ def close_socket(server):
|
||||||
server.socket.close()
|
server.socket.close()
|
||||||
|
|
||||||
|
|
||||||
def disconnect(server):
|
|
||||||
# type: (MatrixServer) -> None
|
|
||||||
if server.fd_hook:
|
|
||||||
W.unhook(server.fd_hook)
|
|
||||||
|
|
||||||
server.fd_hook = None
|
|
||||||
server.socket = None
|
|
||||||
server.connected = False
|
|
||||||
|
|
||||||
server_buffer_prnt(server, "Disconnected")
|
|
||||||
|
|
||||||
|
|
||||||
def server_buffer_prnt(server, string):
|
|
||||||
# type: (MatrixServer, str) -> None
|
|
||||||
assert server.server_buffer
|
|
||||||
buffer = server.server_buffer
|
|
||||||
now = int(time.time())
|
|
||||||
W.prnt_date_tags(buffer, now, "", string)
|
|
||||||
|
|
||||||
|
|
||||||
def server_buffer_set_title(server):
|
def server_buffer_set_title(server):
|
||||||
# type: (MatrixServer) -> None
|
# type: (MatrixServer) -> None
|
||||||
if server.numeric_address:
|
if server.numeric_address:
|
||||||
|
@ -1421,7 +1367,7 @@ def matrix_config_change_cb(data, option):
|
||||||
|
|
||||||
if GLOBAL_OPTIONS.enable_backlog:
|
if GLOBAL_OPTIONS.enable_backlog:
|
||||||
if not GLOBAL_OPTIONS.page_up_hook:
|
if not GLOBAL_OPTIONS.page_up_hook:
|
||||||
hook_page_up()
|
hook_page_up(CONFIG)
|
||||||
else:
|
else:
|
||||||
if GLOBAL_OPTIONS.page_up_hook:
|
if GLOBAL_OPTIONS.page_up_hook:
|
||||||
W.unhook(GLOBAL_OPTIONS.page_up_hook)
|
W.unhook(GLOBAL_OPTIONS.page_up_hook)
|
||||||
|
@ -1430,96 +1376,14 @@ def matrix_config_change_cb(data, option):
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|
||||||
def init_matrix_config():
|
|
||||||
config_file = W.config_new("matrix", "matrix_config_reload_cb", "")
|
|
||||||
|
|
||||||
look_options = [
|
|
||||||
Option(
|
|
||||||
"redactions", "integer",
|
|
||||||
"strikethrough|notice|delete", 0, 0,
|
|
||||||
"strikethrough",
|
|
||||||
(
|
|
||||||
"Only notice redactions, strike through or delete "
|
|
||||||
"redacted messages"
|
|
||||||
)
|
|
||||||
),
|
|
||||||
Option(
|
|
||||||
"server_buffer", "integer",
|
|
||||||
"merge_with_core|merge_without_core|independent",
|
|
||||||
0, 0, "merge_with_core", "Merge server buffers"
|
|
||||||
)
|
|
||||||
]
|
|
||||||
|
|
||||||
network_options = [
|
|
||||||
Option(
|
|
||||||
"max_initial_sync_events", "integer",
|
|
||||||
"", 1, 10000,
|
|
||||||
"30",
|
|
||||||
(
|
|
||||||
"How many events to fetch during the initial sync"
|
|
||||||
)
|
|
||||||
),
|
|
||||||
Option(
|
|
||||||
"max_backlog_sync_events", "integer",
|
|
||||||
"", 1, 100,
|
|
||||||
"10",
|
|
||||||
(
|
|
||||||
"How many events to fetch during backlog fetching"
|
|
||||||
)
|
|
||||||
),
|
|
||||||
Option(
|
|
||||||
"fetch_backlog_on_pgup", "boolean",
|
|
||||||
"", 0, 0,
|
|
||||||
"on",
|
|
||||||
(
|
|
||||||
"Fetch messages in the backlog on a window page up event"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
|
|
||||||
def add_global_options(section, options):
|
|
||||||
for option in options:
|
|
||||||
GLOBAL_OPTIONS.options[option.name] = W.config_new_option(
|
|
||||||
config_file, section, option.name,
|
|
||||||
option.type, option.description, option.string_values,
|
|
||||||
option.min, option.max, option.value, option.value, 0, "",
|
|
||||||
"", "matrix_config_change_cb", "", "", "")
|
|
||||||
|
|
||||||
section = W.config_new_section(config_file, "color", 0, 0, "", "", "", "",
|
|
||||||
"", "", "", "", "", "")
|
|
||||||
|
|
||||||
# TODO color options
|
|
||||||
|
|
||||||
section = W.config_new_section(config_file, "look", 0, 0, "", "", "", "",
|
|
||||||
"", "", "", "", "", "")
|
|
||||||
|
|
||||||
add_global_options(section, look_options)
|
|
||||||
|
|
||||||
section = W.config_new_section(config_file, "network", 0, 0, "", "", "",
|
|
||||||
"", "", "", "", "", "", "")
|
|
||||||
|
|
||||||
add_global_options(section, network_options)
|
|
||||||
|
|
||||||
W.config_new_section(
|
|
||||||
config_file, "server",
|
|
||||||
0, 0,
|
|
||||||
"matrix_config_server_read_cb",
|
|
||||||
"",
|
|
||||||
"matrix_config_server_write_cb",
|
|
||||||
"", "", "", "", "", "", ""
|
|
||||||
)
|
|
||||||
|
|
||||||
return config_file
|
|
||||||
|
|
||||||
|
|
||||||
def read_matrix_config():
|
def read_matrix_config():
|
||||||
# type: () -> bool
|
# type: () -> bool
|
||||||
return_code = W.config_read(CONFIG)
|
return_code = W.config_read(CONFIG)
|
||||||
if return_code == weechat.WEECHAT_CONFIG_READ_OK:
|
if return_code == W.WEECHAT_CONFIG_READ_OK:
|
||||||
return True
|
return True
|
||||||
elif return_code == weechat.WEECHAT_CONFIG_READ_MEMORY_ERROR:
|
elif return_code == W.WEECHAT_CONFIG_READ_MEMORY_ERROR:
|
||||||
return False
|
return False
|
||||||
elif return_code == weechat.WEECHAT_CONFIG_READ_FILE_NOT_FOUND:
|
elif return_code == W.WEECHAT_CONFIG_READ_FILE_NOT_FOUND:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -2051,13 +1915,13 @@ def add_servers_to_completion(completion):
|
||||||
completion,
|
completion,
|
||||||
server_name,
|
server_name,
|
||||||
0,
|
0,
|
||||||
weechat.WEECHAT_LIST_POS_SORT
|
W.WEECHAT_LIST_POS_SORT
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@utf8_decode
|
@utf8_decode
|
||||||
def server_command_completion_cb(data, completion_item, buffer, completion):
|
def server_command_completion_cb(data, completion_item, buffer, completion):
|
||||||
buffer_input = weechat.buffer_get_string(buffer, "input").split()
|
buffer_input = W.buffer_get_string(buffer, "input").split()
|
||||||
|
|
||||||
args = buffer_input[1:]
|
args = buffer_input[1:]
|
||||||
commands = ['add', 'delete', 'list', 'listfull']
|
commands = ['add', 'delete', 'list', 'listfull']
|
||||||
|
@ -2068,7 +1932,7 @@ def server_command_completion_cb(data, completion_item, buffer, completion):
|
||||||
completion,
|
completion,
|
||||||
command,
|
command,
|
||||||
0,
|
0,
|
||||||
weechat.WEECHAT_LIST_POS_SORT
|
W.WEECHAT_LIST_POS_SORT
|
||||||
)
|
)
|
||||||
|
|
||||||
if len(args) == 1:
|
if len(args) == 1:
|
||||||
|
@ -2109,7 +1973,7 @@ def matrix_command_completion_cb(data, completion_item, buffer, completion):
|
||||||
completion,
|
completion,
|
||||||
command,
|
command,
|
||||||
0,
|
0,
|
||||||
weechat.WEECHAT_LIST_POS_SORT)
|
W.WEECHAT_LIST_POS_SORT)
|
||||||
return W.WEECHAT_RC_OK
|
return W.WEECHAT_RC_OK
|
||||||
|
|
||||||
|
|
||||||
|
@ -2190,348 +2054,6 @@ def matrix_command_topic_cb(data, buffer, command):
|
||||||
return W.WEECHAT_RC_OK
|
return W.WEECHAT_RC_OK
|
||||||
|
|
||||||
|
|
||||||
def matrix_fetch_old_messages(server, room_id):
|
|
||||||
room = server.rooms[room_id]
|
|
||||||
prev_batch = room.prev_batch
|
|
||||||
|
|
||||||
if not prev_batch:
|
|
||||||
return
|
|
||||||
|
|
||||||
message = MatrixMessage(server, GLOBAL_OPTIONS, MessageType.ROOM_MSG,
|
|
||||||
room_id=room_id, extra_id=prev_batch)
|
|
||||||
|
|
||||||
send_or_queue(server, message)
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
@utf8_decode
|
|
||||||
def matrix_command_buf_clear_cb(data, buffer, command):
|
|
||||||
for server in SERVERS.values():
|
|
||||||
if buffer in server.buffers.values():
|
|
||||||
room_id = key_from_value(server.buffers, buffer)
|
|
||||||
server.rooms[room_id].prev_batch = server.next_batch
|
|
||||||
|
|
||||||
return W.WEECHAT_RC_OK
|
|
||||||
|
|
||||||
return W.WEECHAT_RC_OK
|
|
||||||
|
|
||||||
|
|
||||||
@utf8_decode
|
|
||||||
def matrix_command_pgup_cb(data, buffer, command):
|
|
||||||
# TODO the highlight status of a line isn't allowed to be updated/changed
|
|
||||||
# via hdata, therefore the highlight status of a messages can't be
|
|
||||||
# reoredered this would need to be fixed in weechat
|
|
||||||
# TODO we shouldn't fetch and print out more messages than
|
|
||||||
# max_buffer_lines_number or older messages than max_buffer_lines_minutes
|
|
||||||
for server in SERVERS.values():
|
|
||||||
if buffer in server.buffers.values():
|
|
||||||
window = W.window_search_with_buffer(buffer)
|
|
||||||
|
|
||||||
first_line_displayed = bool(
|
|
||||||
W.window_get_integer(window, "first_line_displayed")
|
|
||||||
)
|
|
||||||
|
|
||||||
if first_line_displayed:
|
|
||||||
room_id = key_from_value(server.buffers, buffer)
|
|
||||||
matrix_fetch_old_messages(server, room_id)
|
|
||||||
|
|
||||||
return W.WEECHAT_RC_OK
|
|
||||||
|
|
||||||
return W.WEECHAT_RC_OK
|
|
||||||
|
|
||||||
|
|
||||||
@utf8_decode
|
|
||||||
def matrix_command_join_cb(data, buffer, command):
|
|
||||||
def join(server, args):
|
|
||||||
split_args = args.split(" ", 1)
|
|
||||||
|
|
||||||
# TODO handle join for non public rooms
|
|
||||||
if len(split_args) != 2:
|
|
||||||
message = ("{prefix}Error with command \"/join\" (help on "
|
|
||||||
"command: /help join)").format(
|
|
||||||
prefix=W.prefix("error"))
|
|
||||||
W.prnt("", message)
|
|
||||||
return
|
|
||||||
|
|
||||||
_, room_id = split_args
|
|
||||||
message = MatrixMessage(
|
|
||||||
server,
|
|
||||||
GLOBAL_OPTIONS,
|
|
||||||
MessageType.JOIN,
|
|
||||||
room_id=room_id
|
|
||||||
)
|
|
||||||
send_or_queue(server, message)
|
|
||||||
|
|
||||||
for server in SERVERS.values():
|
|
||||||
if buffer in server.buffers.values():
|
|
||||||
join(server, command)
|
|
||||||
return W.WEECHAT_RC_OK_EAT
|
|
||||||
elif buffer == server.server_buffer:
|
|
||||||
join(server, command)
|
|
||||||
return W.WEECHAT_RC_OK_EAT
|
|
||||||
|
|
||||||
return W.WEECHAT_RC_OK
|
|
||||||
|
|
||||||
|
|
||||||
@utf8_decode
|
|
||||||
def matrix_command_part_cb(data, buffer, command):
|
|
||||||
def part(server, buffer, args):
|
|
||||||
rooms = []
|
|
||||||
|
|
||||||
split_args = args.split(" ", 1)
|
|
||||||
|
|
||||||
if len(split_args) == 1:
|
|
||||||
if buffer == server.server_buffer:
|
|
||||||
message = ("{prefix}Error with command \"/part\" (help on "
|
|
||||||
"command: /help part)").format(
|
|
||||||
prefix=W.prefix("error"))
|
|
||||||
W.prnt("", message)
|
|
||||||
return
|
|
||||||
|
|
||||||
rooms = [key_from_value(server.buffers, buffer)]
|
|
||||||
|
|
||||||
else:
|
|
||||||
_, rooms = split_args
|
|
||||||
rooms = rooms.split(" ")
|
|
||||||
|
|
||||||
for room_id in rooms:
|
|
||||||
message = MatrixMessage(
|
|
||||||
server,
|
|
||||||
GLOBAL_OPTIONS,
|
|
||||||
MessageType.PART,
|
|
||||||
room_id=room_id
|
|
||||||
)
|
|
||||||
send_or_queue(server, message)
|
|
||||||
|
|
||||||
for server in SERVERS.values():
|
|
||||||
if buffer in server.buffers.values():
|
|
||||||
part(server, buffer, command)
|
|
||||||
return W.WEECHAT_RC_OK_EAT
|
|
||||||
elif buffer == server.server_buffer:
|
|
||||||
part(server, buffer, command)
|
|
||||||
return W.WEECHAT_RC_OK_EAT
|
|
||||||
|
|
||||||
return W.WEECHAT_RC_OK
|
|
||||||
|
|
||||||
|
|
||||||
@utf8_decode
|
|
||||||
def matrix_command_invite_cb(data, buffer, command):
|
|
||||||
def invite(server, buf, args):
|
|
||||||
split_args = args.split(" ", 1)
|
|
||||||
|
|
||||||
# TODO handle join for non public rooms
|
|
||||||
if len(split_args) != 2:
|
|
||||||
message = ("{prefix}Error with command \"/invite\" (help on "
|
|
||||||
"command: /help invite)").format(
|
|
||||||
prefix=W.prefix("error"))
|
|
||||||
W.prnt("", message)
|
|
||||||
return
|
|
||||||
|
|
||||||
_, invitee = split_args
|
|
||||||
room_id = key_from_value(server.buffers, buf)
|
|
||||||
|
|
||||||
body = {"user_id": invitee}
|
|
||||||
|
|
||||||
message = MatrixMessage(
|
|
||||||
server,
|
|
||||||
GLOBAL_OPTIONS,
|
|
||||||
MessageType.INVITE,
|
|
||||||
room_id=room_id,
|
|
||||||
data=body
|
|
||||||
)
|
|
||||||
send_or_queue(server, message)
|
|
||||||
|
|
||||||
for server in SERVERS.values():
|
|
||||||
if buffer in server.buffers.values():
|
|
||||||
invite(server, buffer, command)
|
|
||||||
return W.WEECHAT_RC_OK_EAT
|
|
||||||
|
|
||||||
return W.WEECHAT_RC_OK
|
|
||||||
|
|
||||||
|
|
||||||
def tags_from_line_data(line_data):
|
|
||||||
# type: (weechat.hdata) -> List[str]
|
|
||||||
tags_count = W.hdata_get_var_array_size(
|
|
||||||
W.hdata_get('line_data'),
|
|
||||||
line_data,
|
|
||||||
'tags_array')
|
|
||||||
|
|
||||||
tags = [
|
|
||||||
W.hdata_string(
|
|
||||||
W.hdata_get('line_data'),
|
|
||||||
line_data,
|
|
||||||
'%d|tags_array' % i
|
|
||||||
) for i in range(tags_count)]
|
|
||||||
|
|
||||||
return tags
|
|
||||||
|
|
||||||
|
|
||||||
def event_id_from_line(buf, target_number):
|
|
||||||
# type: (weechat.buffer, int) -> str
|
|
||||||
own_lines = W.hdata_pointer(W.hdata_get('buffer'), buf, 'own_lines')
|
|
||||||
if own_lines:
|
|
||||||
line = W.hdata_pointer(
|
|
||||||
W.hdata_get('lines'),
|
|
||||||
own_lines,
|
|
||||||
'last_line'
|
|
||||||
)
|
|
||||||
|
|
||||||
line_number = 1
|
|
||||||
|
|
||||||
while line:
|
|
||||||
line_data = W.hdata_pointer(
|
|
||||||
W.hdata_get('line'),
|
|
||||||
line,
|
|
||||||
'data'
|
|
||||||
)
|
|
||||||
|
|
||||||
if line_data:
|
|
||||||
tags = tags_from_line_data(line_data)
|
|
||||||
|
|
||||||
# Only count non redacted user messages
|
|
||||||
if ("matrix_message" in tags
|
|
||||||
and 'matrix_redacted' not in tags
|
|
||||||
and "matrix_new_redacted" not in tags):
|
|
||||||
|
|
||||||
if line_number == target_number:
|
|
||||||
for tag in tags:
|
|
||||||
if tag.startswith("matrix_id"):
|
|
||||||
event_id = tag[10:]
|
|
||||||
return event_id
|
|
||||||
|
|
||||||
line_number += 1
|
|
||||||
|
|
||||||
line = W.hdata_move(W.hdata_get('line'), line, -1)
|
|
||||||
|
|
||||||
return ""
|
|
||||||
|
|
||||||
|
|
||||||
@utf8_decode
|
|
||||||
def matrix_redact_command_cb(data, buffer, args):
|
|
||||||
for server in SERVERS.values():
|
|
||||||
if buffer in server.buffers.values():
|
|
||||||
body = {}
|
|
||||||
|
|
||||||
room_id = key_from_value(server.buffers, buffer)
|
|
||||||
|
|
||||||
matches = re.match(r"(\d+)(:\".*\")? ?(.*)?", args)
|
|
||||||
|
|
||||||
if not matches:
|
|
||||||
message = ("{prefix}matrix: Invalid command arguments (see "
|
|
||||||
"the help for the command /help redact)").format(
|
|
||||||
prefix=W.prefix("error"))
|
|
||||||
W.prnt("", message)
|
|
||||||
return W.WEECHAT_RC_ERROR
|
|
||||||
|
|
||||||
line_string, _, reason = matches.groups()
|
|
||||||
line = int(line_string)
|
|
||||||
|
|
||||||
if reason:
|
|
||||||
body = {"reason": reason}
|
|
||||||
|
|
||||||
event_id = event_id_from_line(buffer, line)
|
|
||||||
|
|
||||||
if not event_id:
|
|
||||||
message = ("{prefix}matrix: No such message with number "
|
|
||||||
"{number} found").format(
|
|
||||||
prefix=W.prefix("error"),
|
|
||||||
number=line)
|
|
||||||
W.prnt("", message)
|
|
||||||
return W.WEECHAT_RC_OK
|
|
||||||
|
|
||||||
message = MatrixMessage(
|
|
||||||
server,
|
|
||||||
GLOBAL_OPTIONS,
|
|
||||||
MessageType.REDACT,
|
|
||||||
data=body,
|
|
||||||
room_id=room_id,
|
|
||||||
extra_id=event_id
|
|
||||||
)
|
|
||||||
send_or_queue(server, message)
|
|
||||||
|
|
||||||
return W.WEECHAT_RC_OK
|
|
||||||
|
|
||||||
elif buffer == server.server_buffer:
|
|
||||||
message = ("{prefix}matrix: command \"redact\" must be "
|
|
||||||
"executed on a Matrix channel buffer").format(
|
|
||||||
prefix=W.prefix("error"))
|
|
||||||
W.prnt("", message)
|
|
||||||
return W.WEECHAT_RC_OK
|
|
||||||
|
|
||||||
return W.WEECHAT_RC_OK
|
|
||||||
|
|
||||||
|
|
||||||
@utf8_decode
|
|
||||||
def matrix_debug_completion_cb(data, completion_item, buffer, completion):
|
|
||||||
for debug_type in ["messaging", "network", "timing"]:
|
|
||||||
W.hook_completion_list_add(
|
|
||||||
completion,
|
|
||||||
debug_type,
|
|
||||||
0,
|
|
||||||
weechat.WEECHAT_LIST_POS_SORT)
|
|
||||||
return W.WEECHAT_RC_OK
|
|
||||||
|
|
||||||
|
|
||||||
@utf8_decode
|
|
||||||
def matrix_message_completion_cb(data, completion_item, buffer, completion):
|
|
||||||
own_lines = W.hdata_pointer(W.hdata_get('buffer'), buffer, 'own_lines')
|
|
||||||
if own_lines:
|
|
||||||
line = W.hdata_pointer(
|
|
||||||
W.hdata_get('lines'),
|
|
||||||
own_lines,
|
|
||||||
'last_line'
|
|
||||||
)
|
|
||||||
|
|
||||||
line_number = 1
|
|
||||||
|
|
||||||
while line:
|
|
||||||
line_data = W.hdata_pointer(
|
|
||||||
W.hdata_get('line'),
|
|
||||||
line,
|
|
||||||
'data'
|
|
||||||
)
|
|
||||||
|
|
||||||
if line_data:
|
|
||||||
message = W.hdata_string(W.hdata_get('line_data'), line_data,
|
|
||||||
'message')
|
|
||||||
|
|
||||||
tags = tags_from_line_data(line_data)
|
|
||||||
|
|
||||||
# Only add non redacted user messages to the completion
|
|
||||||
if (message
|
|
||||||
and 'matrix_message' in tags
|
|
||||||
and 'matrix_redacted' not in tags):
|
|
||||||
|
|
||||||
if len(message) > GLOBAL_OPTIONS.redaction_comp_len + 2:
|
|
||||||
message = (
|
|
||||||
message[:GLOBAL_OPTIONS.redaction_comp_len]
|
|
||||||
+ '..')
|
|
||||||
|
|
||||||
item = ("{number}:\"{message}\"").format(
|
|
||||||
number=line_number,
|
|
||||||
message=message)
|
|
||||||
|
|
||||||
W.hook_completion_list_add(
|
|
||||||
completion,
|
|
||||||
item,
|
|
||||||
0,
|
|
||||||
weechat.WEECHAT_LIST_POS_END)
|
|
||||||
line_number += 1
|
|
||||||
|
|
||||||
line = W.hdata_move(W.hdata_get('line'), line, -1)
|
|
||||||
|
|
||||||
return W.WEECHAT_RC_OK
|
|
||||||
|
|
||||||
|
|
||||||
def hook_page_up():
|
|
||||||
GLOBAL_OPTIONS.page_up_hook = W.hook_command_run(
|
|
||||||
'/window page_up',
|
|
||||||
'matrix_command_pgup_cb',
|
|
||||||
''
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@utf8_decode
|
@utf8_decode
|
||||||
def matrix_bar_item_plugin(data, item, window, buffer, extra_info):
|
def matrix_bar_item_plugin(data, item, window, buffer, extra_info):
|
||||||
# pylint: disable=unused-argument
|
# pylint: disable=unused-argument
|
||||||
|
@ -2576,109 +2098,6 @@ def matrix_bar_item_name(data, item, window, buffer, extra_info):
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
def init_hooks():
|
|
||||||
W.hook_completion(
|
|
||||||
"matrix_server_commands",
|
|
||||||
"Matrix server completion",
|
|
||||||
"server_command_completion_cb",
|
|
||||||
""
|
|
||||||
)
|
|
||||||
|
|
||||||
W.hook_completion(
|
|
||||||
"matrix_servers",
|
|
||||||
"Matrix server completion",
|
|
||||||
"matrix_server_completion_cb",
|
|
||||||
""
|
|
||||||
)
|
|
||||||
|
|
||||||
W.hook_completion(
|
|
||||||
"matrix_commands",
|
|
||||||
"Matrix command completion",
|
|
||||||
"matrix_command_completion_cb",
|
|
||||||
""
|
|
||||||
)
|
|
||||||
|
|
||||||
W.hook_completion(
|
|
||||||
"matrix_messages",
|
|
||||||
"Matrix message completion",
|
|
||||||
"matrix_message_completion_cb",
|
|
||||||
""
|
|
||||||
)
|
|
||||||
|
|
||||||
W.hook_completion(
|
|
||||||
"matrix_debug_types",
|
|
||||||
"Matrix debugging type completion",
|
|
||||||
"matrix_debug_completion_cb",
|
|
||||||
""
|
|
||||||
)
|
|
||||||
|
|
||||||
W.hook_command(
|
|
||||||
# Command name and short description
|
|
||||||
'matrix', 'Matrix chat protocol command',
|
|
||||||
# Synopsis
|
|
||||||
(
|
|
||||||
'server add <server-name> <hostname>[:<port>] ||'
|
|
||||||
'server delete|list|listfull <server-name> ||'
|
|
||||||
'connect <server-name> ||'
|
|
||||||
'disconnect <server-name> ||'
|
|
||||||
'reconnect <server-name> ||'
|
|
||||||
'debug <debug-type> ||'
|
|
||||||
'help <matrix-command>'
|
|
||||||
),
|
|
||||||
# Description
|
|
||||||
(
|
|
||||||
' server: list, add, or remove Matrix servers\n'
|
|
||||||
' connect: connect to Matrix servers\n'
|
|
||||||
'disconnect: disconnect from one or all Matrix servers\n'
|
|
||||||
' reconnect: reconnect to server(s)\n\n'
|
|
||||||
' help: show detailed command help\n\n'
|
|
||||||
' debug: enable or disable debugging\n\n'
|
|
||||||
'Use /matrix help [command] to find out more\n'
|
|
||||||
),
|
|
||||||
# Completions
|
|
||||||
(
|
|
||||||
'server %(matrix_server_commands)|%* ||'
|
|
||||||
'connect %(matrix_servers) ||'
|
|
||||||
'disconnect %(matrix_servers) ||'
|
|
||||||
'reconnect %(matrix_servers) ||'
|
|
||||||
'debug %(matrix_debug_types) ||'
|
|
||||||
'help %(matrix_commands)'
|
|
||||||
),
|
|
||||||
# Function name
|
|
||||||
'matrix_command_cb', '')
|
|
||||||
|
|
||||||
W.hook_command(
|
|
||||||
# Command name and short description
|
|
||||||
'redact', 'redact messages',
|
|
||||||
# Synopsis
|
|
||||||
(
|
|
||||||
'<message-number>[:<"message-part">] [<reason>]'
|
|
||||||
),
|
|
||||||
# Description
|
|
||||||
(
|
|
||||||
"message-number: number of the message to redact (message numbers"
|
|
||||||
"\n start from the last recieved as "
|
|
||||||
"1 and count up)\n"
|
|
||||||
" message-part: a shortened part of the message\n"
|
|
||||||
" reason: the redaction reason\n"
|
|
||||||
),
|
|
||||||
# Completions
|
|
||||||
(
|
|
||||||
'%(matrix_messages)'
|
|
||||||
),
|
|
||||||
# Function name
|
|
||||||
'matrix_redact_command_cb', '')
|
|
||||||
|
|
||||||
W.hook_command_run('/topic', 'matrix_command_topic_cb', '')
|
|
||||||
W.hook_command_run('/buffer clear', 'matrix_command_buf_clear_cb', '')
|
|
||||||
W.hook_command_run('/join', 'matrix_command_join_cb', '')
|
|
||||||
W.hook_command_run('/part', 'matrix_command_part_cb', '')
|
|
||||||
W.hook_command_run('/invite', 'matrix_command_invite_cb', '')
|
|
||||||
|
|
||||||
if GLOBAL_OPTIONS.enable_backlog:
|
|
||||||
hook_page_up()
|
|
||||||
|
|
||||||
|
|
||||||
def autoconnect(servers):
|
def autoconnect(servers):
|
||||||
for server in servers.values():
|
for server in servers.values():
|
||||||
if server.autoconnect:
|
if server.autoconnect:
|
||||||
|
@ -2686,8 +2105,6 @@ def autoconnect(servers):
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
W = weechat if sys.hexversion >= 0x3000000 else WeechatWrapper(weechat)
|
|
||||||
|
|
||||||
if W.register(WEECHAT_SCRIPT_NAME,
|
if W.register(WEECHAT_SCRIPT_NAME,
|
||||||
WEECHAT_SCRIPT_AUTHOR,
|
WEECHAT_SCRIPT_AUTHOR,
|
||||||
WEECHAT_SCRIPT_VERSION,
|
WEECHAT_SCRIPT_VERSION,
|
||||||
|
@ -2696,13 +2113,11 @@ if __name__ == "__main__":
|
||||||
'matrix_unload_cb',
|
'matrix_unload_cb',
|
||||||
''):
|
''):
|
||||||
|
|
||||||
GLOBAL_OPTIONS = PluginOptions()
|
|
||||||
|
|
||||||
# TODO if this fails we should abort and unload the script.
|
# TODO if this fails we should abort and unload the script.
|
||||||
CONFIG = init_matrix_config()
|
CONFIG = matrix.globals.init_matrix_config()
|
||||||
read_matrix_config()
|
read_matrix_config()
|
||||||
|
|
||||||
init_hooks()
|
hook_commands()
|
||||||
|
|
||||||
W.bar_item_new("(extra)buffer_plugin", "matrix_bar_item_plugin", "")
|
W.bar_item_new("(extra)buffer_plugin", "matrix_bar_item_plugin", "")
|
||||||
W.bar_item_new("(extra)buffer_name", "matrix_bar_item_name", "")
|
W.bar_item_new("(extra)buffer_name", "matrix_bar_item_name", "")
|
||||||
|
|
Loading…
Add table
Reference in a new issue