def matrix_create_room_buffer(server, room_id): # type: (MatrixServer, str) -> None buf = W.buffer_new(room_id, "room_input_cb", server.name, "room_close_cb", server.name) W.buffer_set(buf, "localvar_set_type", 'channel') W.buffer_set(buf, "type", 'formatted') W.buffer_set(buf, "localvar_set_channel", room_id) W.buffer_set(buf, "localvar_set_nick", server.user) W.buffer_set(buf, "localvar_set_server", server.name) short_name = strip_matrix_server(room_id) W.buffer_set(buf, "short_name", short_name) W.nicklist_add_group(buf, '', "000|o", "weechat.color.nicklist_group", 1) W.nicklist_add_group(buf, '', "001|h", "weechat.color.nicklist_group", 1) W.nicklist_add_group(buf, '', "002|v", "weechat.color.nicklist_group", 1) W.nicklist_add_group(buf, '', "999|...", "weechat.color.nicklist_group", 1) W.buffer_set(buf, "nicklist", "1") W.buffer_set(buf, "nicklist_display_groups", "0") # TODO make this configurable W.buffer_set(buf, "highlight_tags_restrict", "matrix_message") server.buffers[room_id] = buf server.rooms[room_id] = MatrixRoom(room_id)
def room_close_cb(data, buffer): W.prnt("", "Buffer '%s' will be closed!" % W.buffer_get_string(buffer, "name")) return W.WEECHAT_RC_OK
def hook_page_up(): OPTIONS.page_up_hook = W.hook_command_run('/window page_up', 'matrix_command_pgup_cb', '')
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
def receive_cb(server_name, file_descriptor): server = SERVERS[server_name] while True: try: data = server.socket.recv(4096) except ssl.SSLWantReadError: break except socket.error as error: errno = "error" + str(error.errno) + " " if error.errno else "" str_error = error.strerror if error.strerror else "Unknown error" str_error = errno + str_error message = ("{prefix}Error while reading from " "socket: {error}").format(prefix=W.prefix("network"), error=str_error) server_buffer_prnt(server, message) server_buffer_prnt( server, ("{prefix}matrix: disconnecting from server...").format( prefix=W.prefix("network"))) server.disconnect() return W.WEECHAT_RC_OK if not data: server_buffer_prnt( server, "{prefix}matrix: Error while reading from socket".format( prefix=W.prefix("network"))) server_buffer_prnt( server, ("{prefix}matrix: disconnecting from server...").format( prefix=W.prefix("network"))) server.disconnect() break try: server.client.receive(data) except (RemoteTransportError, RemoteProtocolError) as e: server.error(str(e)) server.disconnect() break response = server.client.next_response() # Check if we need to send some data back data_to_send = server.client.data_to_send() if data_to_send: server.send(data_to_send) if response: server.handle_response(response) break return W.WEECHAT_RC_OK
def add_user(completion, user): W.hook_completion_list_add(completion, user, 0, W.WEECHAT_LIST_POS_SORT)
def init_completion(): W.hook_completion( "matrix_server_commands", "Matrix server completion", "matrix_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_completion( "olm_user_ids", "Matrix olm user id completion", "matrix_olm_user_completion_cb", "", ) W.hook_completion( "olm_devices", "Matrix olm device id completion", "matrix_olm_device_completion_cb", "", ) W.hook_completion( "matrix_users", "Matrix user id completion", "matrix_user_completion_cb", "", ) W.hook_completion( "matrix_own_devices", "Matrix own devices completion", "matrix_own_devices_completion_cb", "", ) W.hook_completion( "matrix_rooms", "Matrix room name completion", "matrix_room_completion_cb", "", )
def str_evaluate_getter(self): return W.string_eval_expression( W.config_string(self._option_ptrs[name]), {}, {}, {})
def int_getter(self): if cast_func: return cast_func(W.config_integer(self._option_ptrs[name])) return W.config_integer(self._option_ptrs[name])
def bool_getter(self): return bool(W.config_boolean(self._option_ptrs[name]))
def str_getter(self): if cast_func: return cast_func(W.config_string(self._option_ptrs[name])) return W.config_string(self._option_ptrs[name])
def free(self): W.config_section_free_options(self._ptr) W.config_section_free(self._ptr)
def buffer_sort_messages(buff): lines = [] own_lines = W.hdata_pointer(W.hdata_get('buffer'), buff, 'own_lines') if own_lines: hdata_line = W.hdata_get('line') hdata_line_data = W.hdata_get('line_data') line = W.hdata_pointer( W.hdata_get('lines'), own_lines, 'first_line') while line: data = W.hdata_pointer(hdata_line, line, 'data') line_data = {} if data: date = W.hdata_time(hdata_line_data, data, 'date') print_date = W.hdata_time(hdata_line_data, data, 'date_printed') tags = tags_from_line_data(data) prefix = W.hdata_string(hdata_line_data, data, 'prefix') message = W.hdata_string(hdata_line_data, data, 'message') highlight = W.hdata_char(hdata_line_data, data, "highlight") line_data = { 'date': date, 'date_printed': print_date, 'tags_array': ','.join(tags), 'prefix': prefix, 'message': message, 'highlight': highlight } lines.append(line_data) line = W.hdata_move(hdata_line, line, 1) sorted_lines = sorted(lines, key=itemgetter('date')) lines = [] # We need to convert the dates to a string for hdata_update(), this # will reverse the list at the same time while sorted_lines: line = sorted_lines.pop() new_line = {k: str(v) for k, v in line.items()} lines.append(new_line) MatrixBacklogEvent.update_buffer_lines(lines, own_lines)
def init_bar_items(): 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)lag", "matrix_bar_item_lag", "") W.bar_item_new("(extra)buffer_modes", "matrix_bar_item_buffer_modes", "")
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 __init__(self): self.debug_buffer = "" self.upload_buffer = "" self.debug_category = "all" self.page_up_hook = None look_options = [ Option( "redactions", "integer", "strikethrough|notice|delete", 0, 0, "strikethrough", ("Only notice redactions, strike through or delete " "redacted messages"), RedactType, ), Option( "server_buffer", "integer", "merge_with_core|merge_without_core|independent", 0, 0, "merge_with_core", "Merge server buffers", ServerBufferType, config_server_buffer_cb, ), Option( "max_typing_notice_item_length", "integer", "", 10, 1000, "50", ("Limit the length of the typing notice bar item."), ), Option( "bar_item_typing_notice_prefix", "string", "", 0, 0, "Typing: ", ("Prefix for the typing notice bar item."), ), Option( "encryption_warning_sign", "string", "", 0, 0, "⚠️ ", ("A sign that is used to signal trust issues in encrypted " "rooms (note: content is evaluated, see /help eval)"), eval_cast, ), Option( "busy_sign", "string", "", 0, 0, "⏳", ("A sign that is used to signal that the client is busy e.g. " "when the room backlog is fetching" " (note: content is evaluated, see /help eval)"), eval_cast, ), Option( "encrypted_room_sign", "string", "", 0, 0, "🔐", ("A sign that is used to show that the current room is " "encrypted " "(note: content is evaluated, see /help eval)"), eval_cast, ), Option( "disconnect_sign", "string", "", 0, 0, "❌", ("A sign that is used to show that the server is disconnected " "(note: content is evaluated, see /help eval)"), eval_cast, ), Option( "pygments_style", "string", "", 0, 0, "native", "Pygments style to use for highlighting source code blocks", ), Option( "code_blocks", "boolean", "", 0, 0, "on", ("Display preformatted code blocks as rectangular areas by " "padding them with whitespace up to the length of the longest" " line (with optional margin)"), ), Option( "code_block_margin", "integer", "", 0, 100, "2", ("Number of spaces to add as a margin around around a code " "block"), ), ] 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"), None, config_pgup_cb, ), Option( "debug_level", "integer", "error|warn|info|debug", 0, 0, "error", "Enable network protocol debugging.", level_to_logbook, config_log_level_cb, ), Option( "debug_category", "integer", "all|http|client|events|responses|encryption", 0, 0, "all", "Debugging category", logbook_category, config_log_category_cb, ), Option( "debug_buffer", "boolean", "", 0, 0, "off", ("Use a separate buffer for debug logs."), ), Option( "lazy_load_room_users", "boolean", "", 0, 0, "off", ("If on, room users won't be loaded in the background " "proactively, they will be loaded when the user switches to " "the room buffer. This only affects non-encrypted rooms."), ), Option( "max_nicklist_users", "integer", "", 100, 20000, "5000", ("Limit the number of users that are added to the nicklist. " "Active users and users with a higher power level are always." " Inactive users will be removed from the nicklist after a " "day of inactivity."), ), Option( "lag_reconnect", "integer", "", 5, 604800, "90", ("Reconnect to the server if the lag is greater than this " "value (in seconds)"), ), Option( "print_unconfirmed_messages", "boolean", "", 0, 0, "on", ("If off, messages are only printed after the server confirms " "their receival. If on, messages are immediately printed but " "colored differently until receival is confirmed."), ), Option( "lag_min_show", "integer", "", 1, 604800, "500", ("minimum lag to show (in milliseconds)"), ), Option( "typing_notice_conditions", "string", "", 0, 0, "${typing_enabled}", ("conditions to send typing notifications (note: content is " "evaluated, see /help eval); besides the buffer and window " "variables the typing_enabled variable is also expanded; " "the typing_enabled variable can be manipulated with the " "/room command, see /help room"), ), Option( "read_markers_conditions", "string", "", 0, 0, "${markers_enabled}", ("conditions to send read markers (note: content is " "evaluated, see /help eval); besides the buffer and window " "variables the markers_enabled variable is also expanded; " "the markers_enabled variable can be manipulated with the " "/room command, see /help room"), ), ] color_options = [ Option( "quote_fg", "color", "", 0, 0, "lightgreen", "Foreground color for matrix style blockquotes", ), Option( "quote_bg", "color", "", 0, 0, "default", "Background counterpart of quote_fg", ), Option( "error_message_fg", "color", "", 0, 0, "darkgray", ("Foreground color for error messages that appear inside a " "room buffer (e.g. when a message errors out when sending or " "when a message is redacted)"), ), Option( "error_message_bg", "color", "", 0, 0, "default", "Background counterpart of error_message_fg.", ), Option( "unconfirmed_message_fg", "color", "", 0, 0, "darkgray", ("Foreground color for messages that are printed out but the " "server hasn't confirmed the that he received them."), ), Option("unconfirmed_message_bg", "color", "", 0, 0, "default", "Background counterpart of unconfirmed_message_fg."), Option( "untagged_code_fg", "color", "", 0, 0, "blue", ("Foreground color for code without a language specifier. " "Also used for `inline code`."), ), Option( "untagged_code_bg", "color", "", 0, 0, "default", "Background counterpart of untagged_code_fg", ), ] sections = [ ("network", network_options), ("look", look_options), ("color", color_options), ] super().__init__(sections) # The server section is essentially a section with subsections and no # options, handle that case independently. W.config_new_section( self._ptr, "server", 0, 0, "matrix_config_server_read_cb", "", "matrix_config_server_write_cb", "", "", "", "", "", "", "", )
def server_buffer_merge(buffer): if OPTIONS.look_server_buf == ServerBufferType.MERGE_CORE: num = W.buffer_get_integer(W.buffer_search_main(), "number") W.buffer_unmerge(buffer, num + 1) W.buffer_merge(buffer, W.buffer_search_main()) elif OPTIONS.look_server_buf == ServerBufferType.MERGE: if SERVERS: first = None for server in SERVERS.values(): if server.server_buffer: first = server.server_buffer break if first: num = W.buffer_get_integer(W.buffer_search_main(), "number") W.buffer_unmerge(buffer, num + 1) if buffer is not first: W.buffer_merge(buffer, first) else: num = W.buffer_get_integer(W.buffer_search_main(), "number") W.buffer_unmerge(buffer, num + 1)
def free(self): section_ptr = W.config_search_section(self._ptr, "server") W.config_section_free(section_ptr) super().free()
def add_servers_to_completion(completion): for server_name in SERVERS: W.hook_completion_list_add(completion, server_name, 0, W.WEECHAT_LIST_POS_SORT)
def _get_session_path(self): home_dir = W.info_get('weechat_dir', '') return os.path.join(home_dir, "matrix", self.name)
def complete_commands(): for command in commands: W.hook_completion_list_add(completion, command, 0, W.WEECHAT_LIST_POS_SORT)
def connect(self): # type: (MatrixServer) -> int if not self.address or not self.port: message = "{prefix}Server address or port not set".format( prefix=W.prefix("error")) W.prnt("", message) return False if not self.user or not self.password: message = "{prefix}User or password not set".format( prefix=W.prefix("error")) W.prnt("", message) return False if self.connected: return True if not self.server_buffer: create_server_buffer(self) if not self.timer_hook: self.timer_hook = W.hook_timer(1 * 1000, 0, 0, "matrix_timer_cb", self.name) ssl_message = " (SSL)" if self.ssl_context.check_hostname else "" message = ("{prefix}matrix: Connecting to " "{server}:{port}{ssl}...").format( prefix=W.prefix("network"), server=self.address, port=self.port, ssl=ssl_message) W.prnt(self.server_buffer, message) W.hook_connect(self.proxy if self.proxy else "", self.address, self.port, 1, 0, "", "connect_cb", self.name) return True
if command in buffer.short_name: displayed = W.current_buffer() == buffer._ptr if displayed: continue W.buffer_set(buffer._ptr, 'display', '1') return W.WEECHAT_RC_OK_EAT return W.WEECHAT_RC_OK if __name__ == "__main__": if W.register(WEECHAT_SCRIPT_NAME, WEECHAT_SCRIPT_AUTHOR, WEECHAT_SCRIPT_VERSION, WEECHAT_SCRIPT_LICENSE, WEECHAT_SCRIPT_DESCRIPTION, 'matrix_unload_cb', ''): if not W.mkdir_home("matrix", 0o700): message = ("{prefix}matrix: Error creating session " "directory").format(prefix=W.prefix("error")) W.prnt("", message) handler = WeechatHandler() handler.format_string = "{record.channel}: {record.message}" handler.push_application() # TODO if this fails we should abort and unload the script. G.CONFIG = MatrixConfig() G.CONFIG.read()
def _create_session_dir(self): path = os.path.join("matrix", self.name) if not W.mkdir_home(path, 0o700): message = ("{prefix}matrix: Error creating server session " "directory").format(prefix=W.prefix("error")) W.prnt("", message)
def sso_login_cb(server_name, command, return_code, out, err): try: server = SERVERS[server_name] except KeyError: message = ( "{}{}: SSO callback ran, but no server for it was found.").format( W.prefix("error"), SCRIPT_NAME) W.prnt("", message) if return_code == W.WEECHAT_HOOK_PROCESS_ERROR: server.error("Error while running the matrix_sso_helper. Please " "make sure that the helper script is executable and can " "be found in your PATH.") server.sso_hook = None server.disconnect() return W.WEECHAT_RC_OK # The child process exited mark the hook as done. if return_code == 0: server.sso_hook = None if err != "": W.prnt("", "stderr: %s" % err) if out == "": return W.WEECHAT_RC_OK try: ret = json.loads(out) msgtype = ret.get("type") if msgtype == "redirectUrl": redirect_url = "http://{}:{}".format(ret["host"], ret["port"]) login_url = ( "{}/_matrix/client/r0/login/sso/redirect?redirectUrl={}" ).format(server.homeserver.geturl(), redirect_url) server.info_highlight( "The server requested a single sign-on, please open " "this URL in your browser. Note that the " "browser needs to run on the same host as Weechat.") server.info_highlight(login_url) message = {"server": server.name, "url": login_url} W.hook_hsignal_send("matrix_sso_login", message) elif msgtype == "token": token = ret["loginToken"] server.login(token=token) elif msgtype == "error": server.error("Error in the SSO helper {}".format(ret["message"])) else: server.error("Unknown SSO login message received from child " "process.") except JSONDecodeError: server.error( "Error decoding SSO login message from child process: {}".format( out)) return W.WEECHAT_RC_OK
def color_for_tags(color): if color == "weechat.color.chat_nick_self": option = W.config_get(color) return W.config_string(option) return color
def server_buffer_cb(server_name, buffer, input_data): message = ("{}{}: this buffer is not a room buffer!").format( W.prefix("error"), SCRIPT_NAME) W.prnt(buffer, message) return W.WEECHAT_RC_OK
def prnt_debug(debug_type, server, message): if debug_type in OPTIONS.debug: W.prnt(server.server_buffer, message)
def hook_commands(): 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 message to redact (starting from 1 for\n" " the last message received, counting up)\n" " message-part: an initial part of the message (ignored, only used\n" " as visual feedback when using completion)\n" " reason: the redaction reason\n"), # Completions ('%(matrix_messages)'), # Function name 'matrix_redact_command_cb', '') W.hook_command( # Command name and short description "me", "send an emote message to the current room", # Synopsis ("<message>"), # Description ("message: message to send"), # Completions "", # Function name "matrix_me_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', '') W.hook_command_run('/kick', 'matrix_command_kick_cb', '') if OPTIONS.enable_backlog: hook_page_up()
def __init__(self): self.debug_buffer = "" self.upload_buffer = "" self.debug_category = "all" self.page_up_hook = None self.human_buffer_names = None look_options = [ Option( "redactions", "integer", "strikethrough|notice|delete", 0, 0, "strikethrough", ("Only notice redactions, strike through or delete " "redacted messages"), RedactType, ), Option( "server_buffer", "integer", "merge_with_core|merge_without_core|independent", 0, 0, "merge_with_core", "Merge server buffers", ServerBufferType, config_server_buffer_cb, ), Option( "new_channel_position", "integer", "none|next|near_server", min(NewChannelPosition), max(NewChannelPosition), "none", "force position of new channel in list of buffers " "(none = default position (should be last buffer), " "next = current buffer + 1, near_server = after last " "channel/pv of server)", NewChannelPosition, ), Option( "max_typing_notice_item_length", "integer", "", 10, 1000, "50", ("Limit the length of the typing notice bar item."), ), Option( "bar_item_typing_notice_prefix", "string", "", 0, 0, "Typing: ", ("Prefix for the typing notice bar item."), ), Option( "encryption_warning_sign", "string", "", 0, 0, "⚠️ ", ("A sign that is used to signal trust issues in encrypted " "rooms (note: content is evaluated, see /help eval)"), eval_cast, ), Option( "busy_sign", "string", "", 0, 0, "⏳", ("A sign that is used to signal that the client is busy e.g. " "when the room backlog is fetching" " (note: content is evaluated, see /help eval)"), eval_cast, ), Option( "encrypted_room_sign", "string", "", 0, 0, "🔐", ("A sign that is used to show that the current room is " "encrypted " "(note: content is evaluated, see /help eval)"), eval_cast, ), Option( "disconnect_sign", "string", "", 0, 0, "❌", ("A sign that is used to show that the server is disconnected " "(note: content is evaluated, see /help eval)"), eval_cast, ), Option( "pygments_style", "string", "", 0, 0, "native", "Pygments style to use for highlighting source code blocks", ), Option( "code_blocks", "boolean", "", 0, 0, "on", ("Display preformatted code blocks as rectangular areas by " "padding them with whitespace up to the length of the longest" " line (with optional margin)"), ), Option( "code_block_margin", "integer", "", 0, 100, "2", ("Number of spaces to add as a margin around around a code " "block"), ), Option( "quote_wrap", "integer", "", -1, 1000, "67", ("After how many characters to soft-wrap lines in a quote " "block (reply message). Set to -1 to disable soft-wrapping."), ), Option( "human_buffer_names", "boolean", "", 0, 0, "off", ("If turned on the buffer name will consist of the server " "name and the room name instead of the Matrix room ID. Note, " "this requires a change to the logger.file.mask setting " "since conflicts can happen otherwise " "(requires a script reload)."), ), ] 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"), None, config_pgup_cb, ), Option( "debug_level", "integer", "error|warn|info|debug", 0, 0, "error", "Enable network protocol debugging.", level_to_logbook, config_log_level_cb, ), Option( "debug_category", "integer", "all|http|client|events|responses|encryption", 0, 0, "all", "Debugging category", logbook_category, config_log_category_cb, ), Option( "debug_buffer", "boolean", "", 0, 0, "off", ("Use a separate buffer for debug logs."), ), Option( "lazy_load_room_users", "boolean", "", 0, 0, "off", ("If on, room users won't be loaded in the background " "proactively, they will be loaded when the user switches to " "the room buffer. This only affects non-encrypted rooms."), ), Option( "max_nicklist_users", "integer", "", 100, 20000, "5000", ("Limit the number of users that are added to the nicklist. " "Active users and users with a higher power level are always." " Inactive users will be removed from the nicklist after a " "day of inactivity."), ), Option( "lag_reconnect", "integer", "", 5, 604800, "90", ("Reconnect to the server if the lag is greater than this " "value (in seconds)"), ), Option( "autoreconnect_delay_growing", "integer", "", 1, 100, "2", ("growing factor for autoreconnect delay to server " "(1 = always same delay, 2 = delay*2 for each retry, etc.)"), ), Option( "autoreconnect_delay_max", "integer", "", 0, 604800, "600", ("maximum autoreconnect delay to server " "(in seconds, 0 = no maximum)"), ), Option( "print_unconfirmed_messages", "boolean", "", 0, 0, "on", ("If off, messages are only printed after the server confirms " "their receival. If on, messages are immediately printed but " "colored differently until receival is confirmed."), ), Option( "lag_min_show", "integer", "", 1, 604800, "500", ("minimum lag to show (in milliseconds)"), ), Option( "typing_notice_conditions", "string", "", 0, 0, "${typing_enabled}", ("conditions to send typing notifications (note: content is " "evaluated, see /help eval); besides the buffer and window " "variables the typing_enabled variable is also expanded; " "the typing_enabled variable can be manipulated with the " "/room command, see /help room"), ), Option( "read_markers_conditions", "string", "", 0, 0, "${markers_enabled}", ("conditions to send read markers (note: content is " "evaluated, see /help eval); besides the buffer and window " "variables the markers_enabled variable is also expanded; " "the markers_enabled variable can be manipulated with the " "/room command, see /help room"), ), Option( "resending_ignores_devices", "boolean", "", 0, 0, "on", ("If on resending the same message to a room that contains " "unverified devices will mark the devices as ignored and " "continue sending the message. If off resending the message " "will again fail and devices need to be marked as verified " "one by one or the /send-anyways command needs to be used to " "ignore them."), ), ] color_options = [ Option( "quote_fg", "color", "", 0, 0, "lightgreen", "Foreground color for matrix style blockquotes", ), Option( "quote_bg", "color", "", 0, 0, "default", "Background counterpart of quote_fg", ), Option( "error_message_fg", "color", "", 0, 0, "darkgray", ("Foreground color for error messages that appear inside a " "room buffer (e.g. when a message errors out when sending or " "when a message is redacted)"), ), Option( "error_message_bg", "color", "", 0, 0, "default", "Background counterpart of error_message_fg.", ), Option( "unconfirmed_message_fg", "color", "", 0, 0, "darkgray", ("Foreground color for messages that are printed out but the " "server hasn't confirmed the that he received them."), ), Option("unconfirmed_message_bg", "color", "", 0, 0, "default", "Background counterpart of unconfirmed_message_fg."), Option( "untagged_code_fg", "color", "", 0, 0, "blue", ("Foreground color for code without a language specifier. " "Also used for `inline code`."), ), Option( "untagged_code_bg", "color", "", 0, 0, "default", "Background counterpart of untagged_code_fg", ), Option( "nick_prefixes", "string", "", 0, 0, "admin=lightgreen;mod=lightgreen;power=yellow", ('Colors for nick prefixes indicating power level. ' 'Format is "admin:color1;mod:color2;power:color3", ' 'where "admin" stands for admins (power level = 100), ' '"mod" stands for moderators (power level >= 50) and ' '"power" for any other power user (power level > 0). ' 'Requires restart to apply changes.'), parse_nick_prefix_colors, ), ] sections = [ ("network", network_options), ("look", look_options), ("color", color_options), ] super().__init__(sections) # The server section is essentially a section with subsections and no # options, handle that case independently. W.config_new_section( self._ptr, "server", 0, 0, "matrix_config_server_read_cb", "", "matrix_config_server_write_cb", "", "", "", "", "", "", "", )