1378 lines
46 KiB
Python
1378 lines
46 KiB
Python
#!/usr/bin/env python3
|
|
|
|
# Libervia D-Bus communication bridge
|
|
# Copyright (C) 2009-2026 Jérôme Poisson (goffi@goffi.org)
|
|
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU Affero General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU Affero General Public License for more details.
|
|
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
import asyncio
|
|
from functools import partial
|
|
|
|
from twisted.internet import reactor
|
|
from txdbus import client
|
|
|
|
from .bridge_frontend import BridgeException
|
|
from libervia.backend.core.exceptions import BridgeExceptionNoService, BridgeInitError
|
|
from libervia.backend.core.i18n import _
|
|
from libervia.backend.core.log import getLogger
|
|
from libervia.backend.tools import config
|
|
|
|
log = getLogger(__name__)
|
|
|
|
|
|
# Interface prefix
|
|
conf = config.parse_main_conf()
|
|
bridge_conf = conf.get_bridge_conf(config.DBusBridgeSettings)
|
|
const_INT_PREFIX = bridge_conf.int_prefix
|
|
const_ERROR_PREFIX = const_INT_PREFIX + ".error"
|
|
const_OBJ_PATH = "/org/libervia/Libervia/bridge"
|
|
const_CORE_SUFFIX = ".core"
|
|
const_PLUGIN_SUFFIX = ".plugin"
|
|
const_TIMEOUT = 120
|
|
|
|
|
|
def dbus_to_bridge_exception(failure):
|
|
"""Convert a txdbus Failure to a BridgeException.
|
|
|
|
@param failure (Failure or RemoteError)
|
|
@return: BridgeException
|
|
"""
|
|
import ast
|
|
|
|
from twisted.python.failure import Failure
|
|
|
|
if isinstance(failure, Failure):
|
|
err = failure.value
|
|
message = failure.getErrorMessage()
|
|
else:
|
|
err = failure
|
|
message = str(failure)
|
|
|
|
full_name = getattr(err, "dbusErrorName", None) or getattr(err, "errName", None)
|
|
if full_name is None:
|
|
full_name = ".".join(
|
|
(const_ERROR_PREFIX, err.__class__.__module__, err.__class__.__name__)
|
|
)
|
|
|
|
if full_name and full_name.startswith(const_ERROR_PREFIX):
|
|
name = full_name[len(const_ERROR_PREFIX) + 1 :]
|
|
else:
|
|
name = full_name
|
|
|
|
# The backend GenericException serializes (message, condition) as a tuple string.
|
|
# Try to unpack it or fall back to using the raw message with no condition.
|
|
condition = ""
|
|
try:
|
|
data = ast.literal_eval(message)
|
|
if isinstance(data, tuple) and len(data) >= 2:
|
|
message = data[0]
|
|
condition = data[1]
|
|
except (ValueError, SyntaxError):
|
|
pass
|
|
|
|
return BridgeException(name, message, condition)
|
|
|
|
|
|
class SignalsHandler:
|
|
|
|
def __init__(self, db_object, iface_name):
|
|
self.db_object = db_object
|
|
self._iface_names = {
|
|
"core": const_INT_PREFIX + const_CORE_SUFFIX,
|
|
"plugin": iface_name,
|
|
}
|
|
|
|
def __getattr__(self, name):
|
|
if name.startswith("remote_"):
|
|
log.debug("calling an unregistered signal: {name}".format(name=name[7:]))
|
|
return lambda *args, **kwargs: None
|
|
else:
|
|
raise AttributeError(name)
|
|
|
|
def register_signal(self, name, handler, iface="core"):
|
|
log.debug("registering signal {name}".format(name=name))
|
|
method_name = "remote_" + name
|
|
try:
|
|
self.__getattribute__(method_name)
|
|
except AttributeError:
|
|
pass
|
|
else:
|
|
from libervia.backend.core import exceptions
|
|
|
|
raise exceptions.InternalError(
|
|
"{name} signal handler has been registered twice".format(name=method_name)
|
|
)
|
|
|
|
def on_signal(*args):
|
|
handler(*args)
|
|
|
|
d = self.db_object.notifyOnSignal(
|
|
name, on_signal, interface=self._iface_names[iface]
|
|
)
|
|
d.addErrback(
|
|
lambda failure_: log.error(
|
|
f"Failed to register signal {name}: {failure_.getErrorMessage()}"
|
|
)
|
|
)
|
|
|
|
setattr(self, method_name, on_signal)
|
|
|
|
|
|
class bridge:
|
|
|
|
def __init__(self):
|
|
self.conn = None
|
|
self.db_object = None
|
|
self.db_core_iface = None
|
|
self.db_plugin_iface = None
|
|
self.signals_handler = None
|
|
|
|
def __getattr__(self, name):
|
|
return partial(self.call, name)
|
|
|
|
@staticmethod
|
|
def _unwrap_txdbus_result(d, return_sig):
|
|
"""Unwrap txdbus result."""
|
|
# txdbus seems to wrongly wrap result in a list, this is a workaround.
|
|
# FIXME: check txdbus behaviour, and report upstream if it's confirmed to be a
|
|
# bug.
|
|
if return_sig and return_sig.startswith("("):
|
|
d.addCallback(
|
|
lambda result: (
|
|
result[0] if isinstance(result, list) and len(result) == 1 else result
|
|
)
|
|
)
|
|
return d
|
|
|
|
def _errback(self, failure_):
|
|
"""Convert Failure to BridgeException"""
|
|
raise dbus_to_bridge_exception(failure_)
|
|
|
|
def call(self, name: str, *args, **kwargs):
|
|
"""Call a remote method.
|
|
|
|
@param name: name of the bridge method
|
|
@param args: method arguments
|
|
@param kwargs: keyword arguments (callback, errback, and methods arguments)
|
|
"""
|
|
# Determine which interface to use by checking where the method is defined
|
|
for iface in self.db_object.interfaces:
|
|
if name in iface.methods:
|
|
interface_name = iface.name
|
|
return_sig = iface.methods[name].sigOut
|
|
break
|
|
else:
|
|
# Default to core interface if method not found (will raise AttributeError)
|
|
interface_name = const_INT_PREFIX + const_CORE_SUFFIX
|
|
return_sig = None
|
|
|
|
# Call the remote method
|
|
d = self.db_object.callRemote(
|
|
name,
|
|
*args,
|
|
interface=interface_name,
|
|
timeout=const_TIMEOUT,
|
|
)
|
|
|
|
self._unwrap_txdbus_result(d, return_sig)
|
|
|
|
return d
|
|
|
|
async def bridge_connect(self) -> None:
|
|
"""Connect to the D-Bus bridge."""
|
|
try:
|
|
self.conn = await client.connect(reactor)
|
|
self.db_object = await self.conn.getRemoteObject(
|
|
const_INT_PREFIX, const_OBJ_PATH
|
|
)
|
|
# Find the core and plugin interfaces
|
|
for iface in self.db_object.interfaces:
|
|
if iface.name == const_INT_PREFIX + const_CORE_SUFFIX:
|
|
self.db_core_iface = iface
|
|
elif iface.name == const_INT_PREFIX + const_PLUGIN_SUFFIX:
|
|
self.db_plugin_iface = iface
|
|
|
|
if self.db_core_iface is None:
|
|
raise BridgeInitError(
|
|
f"Core interface {const_INT_PREFIX + const_CORE_SUFFIX} not found"
|
|
)
|
|
if self.db_plugin_iface is None:
|
|
raise BridgeInitError(
|
|
f"Plugin interface {const_INT_PREFIX + const_PLUGIN_SUFFIX} not found"
|
|
)
|
|
|
|
# Initialize signals handler
|
|
self.signals_handler = SignalsHandler(
|
|
self.db_object, const_INT_PREFIX + const_PLUGIN_SUFFIX
|
|
)
|
|
except BridgeInitError as e:
|
|
raise e
|
|
except Exception as e:
|
|
msg = str(e)
|
|
if (
|
|
"org.freedesktop.DBus.Error.ServiceUnknown" in msg
|
|
or "org.freedesktop.DBus.Error.Spawn.ExecFailed" in msg
|
|
):
|
|
raise BridgeExceptionNoService from e
|
|
elif "org.freedesktop.DBus.Error.NotSupported" in msg:
|
|
log.error(
|
|
_(
|
|
"D-Bus is not launched, please see README to see instructions on"
|
|
" how to launch it"
|
|
)
|
|
)
|
|
raise BridgeInitError from e
|
|
|
|
def register_signal(self, functionName, handler, iface="core"):
|
|
if self.signals_handler is None:
|
|
log.error("Bridge not initialized")
|
|
return
|
|
self.signals_handler.register_signal(functionName, handler, iface)
|
|
|
|
def action_launch(self, callback_id, data, profile_key="@DEFAULT@"):
|
|
return self.call("action_launch", callback_id, data, profile_key)
|
|
|
|
def actions_get(self, profile_key="@DEFAULT@"):
|
|
return self.call("actions_get", profile_key)
|
|
|
|
def config_get(self, section, name):
|
|
return self.call("config_get", section, name)
|
|
|
|
def connect(self, profile_key="@DEFAULT@", password="", options={}):
|
|
return self.call("connect", profile_key, password, options)
|
|
|
|
def contact_add(self, entity_jid, profile_key="@DEFAULT@"):
|
|
return self.call("contact_add", entity_jid, profile_key)
|
|
|
|
def contact_del(self, entity_jid, profile_key="@DEFAULT@"):
|
|
return self.call("contact_del", entity_jid, profile_key)
|
|
|
|
def contact_get(self, arg_0, profile_key="@DEFAULT@"):
|
|
return self.call("contact_get", arg_0, profile_key)
|
|
|
|
def contact_update(self, entity_jid, name, groups, profile_key="@DEFAULT@"):
|
|
return self.call("contact_update", entity_jid, name, groups, profile_key)
|
|
|
|
def contacts_get(self, profile_key="@DEFAULT@"):
|
|
return self.call("contacts_get", profile_key)
|
|
|
|
def contacts_get_from_group(self, group, profile_key="@DEFAULT@"):
|
|
return self.call("contacts_get_from_group", group, profile_key)
|
|
|
|
def devices_infos_get(self, bare_jid, profile_key):
|
|
return self.call("devices_infos_get", bare_jid, profile_key)
|
|
|
|
def disco_find_by_features(
|
|
self,
|
|
namespaces,
|
|
identities,
|
|
bare_jid=False,
|
|
service=True,
|
|
roster=True,
|
|
own_jid=True,
|
|
local_device=False,
|
|
profile_key="@DEFAULT@",
|
|
):
|
|
return self.call(
|
|
"disco_find_by_features",
|
|
namespaces,
|
|
identities,
|
|
bare_jid,
|
|
service,
|
|
roster,
|
|
own_jid,
|
|
local_device,
|
|
profile_key,
|
|
)
|
|
|
|
def disco_infos(self, entity_jid, node="", use_cache=True, profile_key="@DEFAULT@"):
|
|
return self.call("disco_infos", entity_jid, node, use_cache, profile_key)
|
|
|
|
def disco_items(self, entity_jid, node="", use_cache=True, profile_key="@DEFAULT@"):
|
|
return self.call("disco_items", entity_jid, node, use_cache, profile_key)
|
|
|
|
def disconnect(self, profile_key="@DEFAULT@"):
|
|
return self.call("disconnect", profile_key)
|
|
|
|
def encryption_namespace_get(self, arg_0):
|
|
return self.call("encryption_namespace_get", arg_0)
|
|
|
|
def encryption_plugins_get(
|
|
self,
|
|
):
|
|
return self.call(
|
|
"encryption_plugins_get",
|
|
)
|
|
|
|
def encryption_trust_ui_get(self, to_jid, namespace, profile_key):
|
|
return self.call("encryption_trust_ui_get", to_jid, namespace, profile_key)
|
|
|
|
def entities_data_get(self, jids, keys, profile):
|
|
return self.call("entities_data_get", jids, keys, profile)
|
|
|
|
def entity_data_get(self, jid, keys, profile):
|
|
return self.call("entity_data_get", jid, keys, profile)
|
|
|
|
def features_get(self, profile_key):
|
|
return self.call("features_get", profile_key)
|
|
|
|
def history_get(
|
|
self, from_jid, to_jid, limit, between=True, filters="", profile="@NONE@"
|
|
):
|
|
return self.call(
|
|
"history_get", from_jid, to_jid, limit, between, filters, profile
|
|
)
|
|
|
|
def history_last_messages_metadata_get(self, options, profile_key="@NONE@"):
|
|
return self.call("history_last_messages_metadata_get", options, profile_key)
|
|
|
|
def image_check(self, arg_0):
|
|
return self.call("image_check", arg_0)
|
|
|
|
def image_convert(self, source, dest, arg_2, extra):
|
|
return self.call("image_convert", source, dest, arg_2, extra)
|
|
|
|
def image_generate_preview(self, image_path, profile_key):
|
|
return self.call("image_generate_preview", image_path, profile_key)
|
|
|
|
def image_resize(self, image_path, width, height):
|
|
return self.call("image_resize", image_path, width, height)
|
|
|
|
def init_pre_script(
|
|
self,
|
|
):
|
|
return self.call(
|
|
"init_pre_script",
|
|
)
|
|
|
|
def is_connected(self, profile_key="@DEFAULT@"):
|
|
return self.call("is_connected", profile_key)
|
|
|
|
def main_resource_get(self, contact_jid, profile_key="@DEFAULT@"):
|
|
return self.call("main_resource_get", contact_jid, profile_key)
|
|
|
|
def menu_help_get(self, menu_id, language):
|
|
return self.call("menu_help_get", menu_id, language)
|
|
|
|
def menu_launch(self, menu_type, path, data, security_limit, profile_key):
|
|
return self.call(
|
|
"menu_launch", menu_type, path, data, security_limit, profile_key
|
|
)
|
|
|
|
def menus_get(self, language, security_limit):
|
|
return self.call("menus_get", language, security_limit)
|
|
|
|
def message_encryption_get(self, to_jid, profile_key):
|
|
return self.call("message_encryption_get", to_jid, profile_key)
|
|
|
|
def message_encryption_start(
|
|
self, to_jid, namespace="", replace=False, profile_key="@NONE@"
|
|
):
|
|
return self.call(
|
|
"message_encryption_start", to_jid, namespace, replace, profile_key
|
|
)
|
|
|
|
def message_encryption_stop(self, to_jid, profile_key):
|
|
return self.call("message_encryption_stop", to_jid, profile_key)
|
|
|
|
def message_send(
|
|
self,
|
|
to_jid,
|
|
message,
|
|
subject={},
|
|
mess_type="auto",
|
|
extra={},
|
|
profile_key="@NONE@",
|
|
):
|
|
return self.call(
|
|
"message_send", to_jid, message, subject, mess_type, extra, profile_key
|
|
)
|
|
|
|
def messages_display_state_get(self, jids, profile_key):
|
|
return self.call("messages_display_state_get", jids, profile_key)
|
|
|
|
def messages_display_state_set(self, peer_jid, message_uid, profile_key):
|
|
return self.call("messages_display_state_set", peer_jid, message_uid, profile_key)
|
|
|
|
def namespaces_get(
|
|
self,
|
|
):
|
|
return self.call(
|
|
"namespaces_get",
|
|
)
|
|
|
|
def notification_add(
|
|
self,
|
|
type_,
|
|
body_plain,
|
|
body_rich,
|
|
title,
|
|
is_global,
|
|
requires_action,
|
|
arg_6,
|
|
priority,
|
|
expire_at,
|
|
extra,
|
|
):
|
|
return self.call(
|
|
"notification_add",
|
|
type_,
|
|
body_plain,
|
|
body_rich,
|
|
title,
|
|
is_global,
|
|
requires_action,
|
|
arg_6,
|
|
priority,
|
|
expire_at,
|
|
extra,
|
|
)
|
|
|
|
def notification_delete(self, id_, is_global, profile_key):
|
|
return self.call("notification_delete", id_, is_global, profile_key)
|
|
|
|
def notifications_expired_clean(self, limit_timestamp, profile_key):
|
|
return self.call("notifications_expired_clean", limit_timestamp, profile_key)
|
|
|
|
def notifications_get(self, filters, profile_key):
|
|
return self.call("notifications_get", filters, profile_key)
|
|
|
|
def param_get_a(self, name, category, attribute="value", profile_key="@DEFAULT@"):
|
|
return self.call("param_get_a", name, category, attribute, profile_key)
|
|
|
|
def param_get_a_async(
|
|
self,
|
|
name,
|
|
category,
|
|
attribute="value",
|
|
security_limit=-1,
|
|
profile_key="@DEFAULT@",
|
|
):
|
|
return self.call(
|
|
"param_get_a_async", name, category, attribute, security_limit, profile_key
|
|
)
|
|
|
|
def param_set(
|
|
self, name, value, category, security_limit=-1, profile_key="@DEFAULT@"
|
|
):
|
|
return self.call("param_set", name, value, category, security_limit, profile_key)
|
|
|
|
def param_ui_get(self, security_limit=-1, app="", extra="", profile_key="@DEFAULT@"):
|
|
return self.call("param_ui_get", security_limit, app, extra, profile_key)
|
|
|
|
def params_categories_get(
|
|
self,
|
|
):
|
|
return self.call(
|
|
"params_categories_get",
|
|
)
|
|
|
|
def params_register_app(self, xml, security_limit=-1, app=""):
|
|
return self.call("params_register_app", xml, security_limit, app)
|
|
|
|
def params_template_load(self, filename):
|
|
return self.call("params_template_load", filename)
|
|
|
|
def params_template_save(self, filename):
|
|
return self.call("params_template_save", filename)
|
|
|
|
def params_values_from_category_get_async(
|
|
self, category, security_limit=-1, app="", extra="", profile_key="@DEFAULT@"
|
|
):
|
|
return self.call(
|
|
"params_values_from_category_get_async",
|
|
category,
|
|
security_limit,
|
|
app,
|
|
extra,
|
|
profile_key,
|
|
)
|
|
|
|
def presence_set(self, to_jid="", show="", statuses={}, profile_key="@DEFAULT@"):
|
|
return self.call("presence_set", to_jid, show, statuses, profile_key)
|
|
|
|
def presence_statuses_get(self, profile_key="@DEFAULT@"):
|
|
return self.call("presence_statuses_get", profile_key)
|
|
|
|
def private_data_delete(self, namespace, key, arg_2):
|
|
return self.call("private_data_delete", namespace, key, arg_2)
|
|
|
|
def private_data_get(self, namespace, key, profile_key):
|
|
return self.call("private_data_get", namespace, key, profile_key)
|
|
|
|
def private_data_set(self, namespace, key, data, profile_key):
|
|
return self.call("private_data_set", namespace, key, data, profile_key)
|
|
|
|
def profile_create(self, profile, password="", component=""):
|
|
return self.call("profile_create", profile, password, component)
|
|
|
|
def profile_delete_async(self, profile):
|
|
return self.call("profile_delete_async", profile)
|
|
|
|
def profile_is_session_started(self, profile_key="@DEFAULT@"):
|
|
return self.call("profile_is_session_started", profile_key)
|
|
|
|
def profile_name_get(self, profile_key="@DEFAULT@"):
|
|
return self.call("profile_name_get", profile_key)
|
|
|
|
def profile_set_default(self, profile):
|
|
return self.call("profile_set_default", profile)
|
|
|
|
def profile_start_session(self, password="", profile_key="@DEFAULT@"):
|
|
return self.call("profile_start_session", password, profile_key)
|
|
|
|
def profiles_list_get(self, clients=True, components=False):
|
|
return self.call("profiles_list_get", clients, components)
|
|
|
|
def progress_get(self, id, profile):
|
|
return self.call("progress_get", id, profile)
|
|
|
|
def progress_get_all(self, profile):
|
|
return self.call("progress_get_all", profile)
|
|
|
|
def progress_get_all_metadata(self, profile):
|
|
return self.call("progress_get_all_metadata", profile)
|
|
|
|
def ready_get(
|
|
self,
|
|
):
|
|
return self.call(
|
|
"ready_get",
|
|
)
|
|
|
|
def roster_resync(self, profile_key="@DEFAULT@"):
|
|
return self.call("roster_resync", profile_key)
|
|
|
|
def session_infos_get(self, profile_key):
|
|
return self.call("session_infos_get", profile_key)
|
|
|
|
def sub_waiting_get(self, profile_key="@DEFAULT@"):
|
|
return self.call("sub_waiting_get", profile_key)
|
|
|
|
def subscription(self, sub_type, entity, profile_key="@DEFAULT@"):
|
|
return self.call("subscription", sub_type, entity, profile_key)
|
|
|
|
def tor_infos_get(self, extra, profile_key):
|
|
return self.call("tor_infos_get", extra, profile_key)
|
|
|
|
def tor_mode_get(self, profile_key):
|
|
return self.call("tor_mode_get", profile_key)
|
|
|
|
def version_get(
|
|
self,
|
|
):
|
|
return self.call(
|
|
"version_get",
|
|
)
|
|
|
|
|
|
class AIOSignalsHandler(SignalsHandler):
|
|
|
|
def register_signal(self, name, handler, iface="core"):
|
|
"""Register an async signal handler."""
|
|
async_handler = lambda *args: asyncio.ensure_future(handler(*args))
|
|
return super().register_signal(name, async_handler, iface)
|
|
|
|
async def action_launch(self, callback_id, data, profile_key="@DEFAULT@"):
|
|
return await self.call("action_launch", callback_id, data, profile_key)
|
|
|
|
async def actions_get(self, profile_key="@DEFAULT@"):
|
|
return await self.call("actions_get", profile_key)
|
|
|
|
async def config_get(self, section, name):
|
|
return await self.call("config_get", section, name)
|
|
|
|
async def connect(self, profile_key="@DEFAULT@", password="", options={}):
|
|
return await self.call("connect", profile_key, password, options)
|
|
|
|
async def contact_add(self, entity_jid, profile_key="@DEFAULT@"):
|
|
return await self.call("contact_add", entity_jid, profile_key)
|
|
|
|
async def contact_del(self, entity_jid, profile_key="@DEFAULT@"):
|
|
return await self.call("contact_del", entity_jid, profile_key)
|
|
|
|
async def contact_get(self, arg_0, profile_key="@DEFAULT@"):
|
|
return await self.call("contact_get", arg_0, profile_key)
|
|
|
|
async def contact_update(self, entity_jid, name, groups, profile_key="@DEFAULT@"):
|
|
return await self.call("contact_update", entity_jid, name, groups, profile_key)
|
|
|
|
async def contacts_get(self, profile_key="@DEFAULT@"):
|
|
return await self.call("contacts_get", profile_key)
|
|
|
|
async def contacts_get_from_group(self, group, profile_key="@DEFAULT@"):
|
|
return await self.call("contacts_get_from_group", group, profile_key)
|
|
|
|
async def devices_infos_get(self, bare_jid, profile_key):
|
|
return await self.call("devices_infos_get", bare_jid, profile_key)
|
|
|
|
async def disco_find_by_features(
|
|
self,
|
|
namespaces,
|
|
identities,
|
|
bare_jid=False,
|
|
service=True,
|
|
roster=True,
|
|
own_jid=True,
|
|
local_device=False,
|
|
profile_key="@DEFAULT@",
|
|
):
|
|
return await self.call(
|
|
"disco_find_by_features",
|
|
namespaces,
|
|
identities,
|
|
bare_jid,
|
|
service,
|
|
roster,
|
|
own_jid,
|
|
local_device,
|
|
profile_key,
|
|
)
|
|
|
|
async def disco_infos(
|
|
self, entity_jid, node="", use_cache=True, profile_key="@DEFAULT@"
|
|
):
|
|
return await self.call("disco_infos", entity_jid, node, use_cache, profile_key)
|
|
|
|
async def disco_items(
|
|
self, entity_jid, node="", use_cache=True, profile_key="@DEFAULT@"
|
|
):
|
|
return await self.call("disco_items", entity_jid, node, use_cache, profile_key)
|
|
|
|
async def disconnect(self, profile_key="@DEFAULT@"):
|
|
return await self.call("disconnect", profile_key)
|
|
|
|
async def encryption_namespace_get(self, arg_0):
|
|
return await self.call("encryption_namespace_get", arg_0)
|
|
|
|
async def encryption_plugins_get(
|
|
self,
|
|
):
|
|
return await self.call(
|
|
"encryption_plugins_get",
|
|
)
|
|
|
|
async def encryption_trust_ui_get(self, to_jid, namespace, profile_key):
|
|
return await self.call("encryption_trust_ui_get", to_jid, namespace, profile_key)
|
|
|
|
async def entities_data_get(self, jids, keys, profile):
|
|
return await self.call("entities_data_get", jids, keys, profile)
|
|
|
|
async def entity_data_get(self, jid, keys, profile):
|
|
return await self.call("entity_data_get", jid, keys, profile)
|
|
|
|
async def features_get(self, profile_key):
|
|
return await self.call("features_get", profile_key)
|
|
|
|
async def history_get(
|
|
self, from_jid, to_jid, limit, between=True, filters="", profile="@NONE@"
|
|
):
|
|
return await self.call(
|
|
"history_get", from_jid, to_jid, limit, between, filters, profile
|
|
)
|
|
|
|
async def history_last_messages_metadata_get(self, options, profile_key="@NONE@"):
|
|
return await self.call("history_last_messages_metadata_get", options, profile_key)
|
|
|
|
async def image_check(self, arg_0):
|
|
return await self.call("image_check", arg_0)
|
|
|
|
async def image_convert(self, source, dest, arg_2, extra):
|
|
return await self.call("image_convert", source, dest, arg_2, extra)
|
|
|
|
async def image_generate_preview(self, image_path, profile_key):
|
|
return await self.call("image_generate_preview", image_path, profile_key)
|
|
|
|
async def image_resize(self, image_path, width, height):
|
|
return await self.call("image_resize", image_path, width, height)
|
|
|
|
async def init_pre_script(
|
|
self,
|
|
):
|
|
return await self.call(
|
|
"init_pre_script",
|
|
)
|
|
|
|
async def is_connected(self, profile_key="@DEFAULT@"):
|
|
return await self.call("is_connected", profile_key)
|
|
|
|
async def main_resource_get(self, contact_jid, profile_key="@DEFAULT@"):
|
|
return await self.call("main_resource_get", contact_jid, profile_key)
|
|
|
|
async def menu_help_get(self, menu_id, language):
|
|
return await self.call("menu_help_get", menu_id, language)
|
|
|
|
async def menu_launch(self, menu_type, path, data, security_limit, profile_key):
|
|
return await self.call(
|
|
"menu_launch", menu_type, path, data, security_limit, profile_key
|
|
)
|
|
|
|
async def menus_get(self, language, security_limit):
|
|
return await self.call("menus_get", language, security_limit)
|
|
|
|
async def message_encryption_get(self, to_jid, profile_key):
|
|
return await self.call("message_encryption_get", to_jid, profile_key)
|
|
|
|
async def message_encryption_start(
|
|
self, to_jid, namespace="", replace=False, profile_key="@NONE@"
|
|
):
|
|
return await self.call(
|
|
"message_encryption_start", to_jid, namespace, replace, profile_key
|
|
)
|
|
|
|
async def message_encryption_stop(self, to_jid, profile_key):
|
|
return await self.call("message_encryption_stop", to_jid, profile_key)
|
|
|
|
async def message_send(
|
|
self,
|
|
to_jid,
|
|
message,
|
|
subject={},
|
|
mess_type="auto",
|
|
extra={},
|
|
profile_key="@NONE@",
|
|
):
|
|
return await self.call(
|
|
"message_send", to_jid, message, subject, mess_type, extra, profile_key
|
|
)
|
|
|
|
async def messages_display_state_get(self, jids, profile_key):
|
|
return await self.call("messages_display_state_get", jids, profile_key)
|
|
|
|
async def messages_display_state_set(self, peer_jid, message_uid, profile_key):
|
|
return await self.call(
|
|
"messages_display_state_set", peer_jid, message_uid, profile_key
|
|
)
|
|
|
|
async def namespaces_get(
|
|
self,
|
|
):
|
|
return await self.call(
|
|
"namespaces_get",
|
|
)
|
|
|
|
async def notification_add(
|
|
self,
|
|
type_,
|
|
body_plain,
|
|
body_rich,
|
|
title,
|
|
is_global,
|
|
requires_action,
|
|
arg_6,
|
|
priority,
|
|
expire_at,
|
|
extra,
|
|
):
|
|
return await self.call(
|
|
"notification_add",
|
|
type_,
|
|
body_plain,
|
|
body_rich,
|
|
title,
|
|
is_global,
|
|
requires_action,
|
|
arg_6,
|
|
priority,
|
|
expire_at,
|
|
extra,
|
|
)
|
|
|
|
async def notification_delete(self, id_, is_global, profile_key):
|
|
return await self.call("notification_delete", id_, is_global, profile_key)
|
|
|
|
async def notifications_expired_clean(self, limit_timestamp, profile_key):
|
|
return await self.call(
|
|
"notifications_expired_clean", limit_timestamp, profile_key
|
|
)
|
|
|
|
async def notifications_get(self, filters, profile_key):
|
|
return await self.call("notifications_get", filters, profile_key)
|
|
|
|
async def param_get_a(
|
|
self, name, category, attribute="value", profile_key="@DEFAULT@"
|
|
):
|
|
return await self.call("param_get_a", name, category, attribute, profile_key)
|
|
|
|
async def param_get_a_async(
|
|
self,
|
|
name,
|
|
category,
|
|
attribute="value",
|
|
security_limit=-1,
|
|
profile_key="@DEFAULT@",
|
|
):
|
|
return await self.call(
|
|
"param_get_a_async", name, category, attribute, security_limit, profile_key
|
|
)
|
|
|
|
async def param_set(
|
|
self, name, value, category, security_limit=-1, profile_key="@DEFAULT@"
|
|
):
|
|
return await self.call(
|
|
"param_set", name, value, category, security_limit, profile_key
|
|
)
|
|
|
|
async def param_ui_get(
|
|
self, security_limit=-1, app="", extra="", profile_key="@DEFAULT@"
|
|
):
|
|
return await self.call("param_ui_get", security_limit, app, extra, profile_key)
|
|
|
|
async def params_categories_get(
|
|
self,
|
|
):
|
|
return await self.call(
|
|
"params_categories_get",
|
|
)
|
|
|
|
async def params_register_app(self, xml, security_limit=-1, app=""):
|
|
return await self.call("params_register_app", xml, security_limit, app)
|
|
|
|
async def params_template_load(self, filename):
|
|
return await self.call("params_template_load", filename)
|
|
|
|
async def params_template_save(self, filename):
|
|
return await self.call("params_template_save", filename)
|
|
|
|
async def params_values_from_category_get_async(
|
|
self, category, security_limit=-1, app="", extra="", profile_key="@DEFAULT@"
|
|
):
|
|
return await self.call(
|
|
"params_values_from_category_get_async",
|
|
category,
|
|
security_limit,
|
|
app,
|
|
extra,
|
|
profile_key,
|
|
)
|
|
|
|
async def presence_set(
|
|
self, to_jid="", show="", statuses={}, profile_key="@DEFAULT@"
|
|
):
|
|
return await self.call("presence_set", to_jid, show, statuses, profile_key)
|
|
|
|
async def presence_statuses_get(self, profile_key="@DEFAULT@"):
|
|
return await self.call("presence_statuses_get", profile_key)
|
|
|
|
async def private_data_delete(self, namespace, key, arg_2):
|
|
return await self.call("private_data_delete", namespace, key, arg_2)
|
|
|
|
async def private_data_get(self, namespace, key, profile_key):
|
|
return await self.call("private_data_get", namespace, key, profile_key)
|
|
|
|
async def private_data_set(self, namespace, key, data, profile_key):
|
|
return await self.call("private_data_set", namespace, key, data, profile_key)
|
|
|
|
async def profile_create(self, profile, password="", component=""):
|
|
return await self.call("profile_create", profile, password, component)
|
|
|
|
async def profile_delete_async(self, profile):
|
|
return await self.call("profile_delete_async", profile)
|
|
|
|
async def profile_is_session_started(self, profile_key="@DEFAULT@"):
|
|
return await self.call("profile_is_session_started", profile_key)
|
|
|
|
async def profile_name_get(self, profile_key="@DEFAULT@"):
|
|
return await self.call("profile_name_get", profile_key)
|
|
|
|
async def profile_set_default(self, profile):
|
|
return await self.call("profile_set_default", profile)
|
|
|
|
async def profile_start_session(self, password="", profile_key="@DEFAULT@"):
|
|
return await self.call("profile_start_session", password, profile_key)
|
|
|
|
async def profiles_list_get(self, clients=True, components=False):
|
|
return await self.call("profiles_list_get", clients, components)
|
|
|
|
async def progress_get(self, id, profile):
|
|
return await self.call("progress_get", id, profile)
|
|
|
|
async def progress_get_all(self, profile):
|
|
return await self.call("progress_get_all", profile)
|
|
|
|
async def progress_get_all_metadata(self, profile):
|
|
return await self.call("progress_get_all_metadata", profile)
|
|
|
|
async def ready_get(
|
|
self,
|
|
):
|
|
return await self.call(
|
|
"ready_get",
|
|
)
|
|
|
|
async def roster_resync(self, profile_key="@DEFAULT@"):
|
|
return await self.call("roster_resync", profile_key)
|
|
|
|
async def session_infos_get(self, profile_key):
|
|
return await self.call("session_infos_get", profile_key)
|
|
|
|
async def sub_waiting_get(self, profile_key="@DEFAULT@"):
|
|
return await self.call("sub_waiting_get", profile_key)
|
|
|
|
async def subscription(self, sub_type, entity, profile_key="@DEFAULT@"):
|
|
return await self.call("subscription", sub_type, entity, profile_key)
|
|
|
|
async def tor_infos_get(self, extra, profile_key):
|
|
return await self.call("tor_infos_get", extra, profile_key)
|
|
|
|
async def tor_mode_get(self, profile_key):
|
|
return await self.call("tor_mode_get", profile_key)
|
|
|
|
async def version_get(
|
|
self,
|
|
):
|
|
return await self.call(
|
|
"version_get",
|
|
)
|
|
|
|
|
|
class AIOBridge(bridge):
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self.signals_handler = None
|
|
|
|
async def post_init(self):
|
|
"""Post-initialization hook.
|
|
|
|
Actually no post init is needed, but the "__getattr__" return "partial" for
|
|
unknown methods, and this causes "dynamic_import.load_and_init_bridge" to fail.
|
|
"""
|
|
pass
|
|
|
|
def call(self, name: str, *args, **kwargs):
|
|
"""Call a remote method and return an awaitable.
|
|
|
|
@param name: name of the bridge method
|
|
"""
|
|
d = super().call(name, *args, **kwargs)
|
|
d.addErrback(self._errback)
|
|
return d.asFuture(asyncio.get_event_loop())
|
|
|
|
async def bridge_connect(self):
|
|
"""Connect to the D-Bus bridge (async version)."""
|
|
try:
|
|
self.conn = await client.connect(reactor).asFuture(asyncio.get_event_loop())
|
|
self.db_object = await self.conn.getRemoteObject(
|
|
const_INT_PREFIX, const_OBJ_PATH
|
|
).asFuture(asyncio.get_event_loop())
|
|
|
|
# Find the core and plugin interfaces
|
|
for iface in self.db_object.interfaces:
|
|
if iface.name == const_INT_PREFIX + const_CORE_SUFFIX:
|
|
self.db_core_iface = iface
|
|
elif iface.name == const_INT_PREFIX + const_PLUGIN_SUFFIX:
|
|
self.db_plugin_iface = iface
|
|
|
|
if self.db_core_iface is None:
|
|
raise BridgeInitError(
|
|
f"Core interface {const_INT_PREFIX + const_CORE_SUFFIX} not found"
|
|
)
|
|
if self.db_plugin_iface is None:
|
|
raise BridgeInitError(
|
|
f"Plugin interface {const_INT_PREFIX + const_PLUGIN_SUFFIX} not found"
|
|
)
|
|
|
|
# Initialize signals handler
|
|
self.signals_handler = AIOSignalsHandler(
|
|
self.db_object, const_INT_PREFIX + const_PLUGIN_SUFFIX
|
|
)
|
|
except BridgeInitError as e:
|
|
raise e
|
|
except Exception as e:
|
|
msg = str(e)
|
|
if (
|
|
"org.freedesktop.DBus.Error.ServiceUnknown" in msg
|
|
or "org.freedesktop.DBus.Error.Spawn.ExecFailed" in msg
|
|
):
|
|
raise BridgeExceptionNoService from e
|
|
elif "org.freedesktop.DBus.Error.NotSupported" in msg:
|
|
log.error(
|
|
_(
|
|
"D-Bus is not launched, please see README to see instructions on"
|
|
" how to launch it"
|
|
)
|
|
)
|
|
raise BridgeInitError from e
|
|
|
|
def register_signal(self, functionName, handler, iface="core"):
|
|
if self.signals_handler is None:
|
|
log.error("Bridge not initialized")
|
|
return
|
|
self.signals_handler.register_signal(functionName, handler, iface)
|
|
|
|
|
|
class TwistedBridge(bridge):
|
|
|
|
async def post_init(self):
|
|
"""Post-initialization hook.
|
|
|
|
Actually no post init is needed, but the "__getattr__" return "partial" for
|
|
unknown methods, and this causes "dynamic_import.load_and_init_bridge" to fail.
|
|
"""
|
|
pass
|
|
|
|
def call(self, name, *args, **kwargs):
|
|
"""Call a remote method and return a Deferred.
|
|
|
|
@param name(str): name of the bridge method
|
|
@param args(list): arguments
|
|
@param kwargs(dict): keyword arguments (profile, etc.)
|
|
"""
|
|
d = super().call(name, *args, **kwargs)
|
|
d.addErrback(self._errback)
|
|
return d
|
|
|
|
async def bridge_connect(self) -> None:
|
|
"""Connect to the D-Bus bridge."""
|
|
return await super().bridge_connect()
|
|
|
|
def register_signal(self, functionName, handler, iface="core"):
|
|
super().register_signal(functionName, handler, iface)
|
|
|
|
def action_launch(self, callback_id, data, profile_key="@DEFAULT@"):
|
|
return self.call("action_launch", callback_id, data, profile_key)
|
|
|
|
def actions_get(self, profile_key="@DEFAULT@"):
|
|
return self.call("actions_get", profile_key)
|
|
|
|
def config_get(self, section, name):
|
|
return self.call("config_get", section, name)
|
|
|
|
def connect(self, profile_key="@DEFAULT@", password="", options={}):
|
|
return self.call("connect", profile_key, password, options)
|
|
|
|
def contact_add(self, entity_jid, profile_key="@DEFAULT@"):
|
|
return self.call("contact_add", entity_jid, profile_key)
|
|
|
|
def contact_del(self, entity_jid, profile_key="@DEFAULT@"):
|
|
return self.call("contact_del", entity_jid, profile_key)
|
|
|
|
def contact_get(self, arg_0, profile_key="@DEFAULT@"):
|
|
return self.call("contact_get", arg_0, profile_key)
|
|
|
|
def contact_update(self, entity_jid, name, groups, profile_key="@DEFAULT@"):
|
|
return self.call("contact_update", entity_jid, name, groups, profile_key)
|
|
|
|
def contacts_get(self, profile_key="@DEFAULT@"):
|
|
return self.call("contacts_get", profile_key)
|
|
|
|
def contacts_get_from_group(self, group, profile_key="@DEFAULT@"):
|
|
return self.call("contacts_get_from_group", group, profile_key)
|
|
|
|
def devices_infos_get(self, bare_jid, profile_key):
|
|
return self.call("devices_infos_get", bare_jid, profile_key)
|
|
|
|
def disco_find_by_features(
|
|
self,
|
|
namespaces,
|
|
identities,
|
|
bare_jid=False,
|
|
service=True,
|
|
roster=True,
|
|
own_jid=True,
|
|
local_device=False,
|
|
profile_key="@DEFAULT@",
|
|
):
|
|
return self.call(
|
|
"disco_find_by_features",
|
|
namespaces,
|
|
identities,
|
|
bare_jid,
|
|
service,
|
|
roster,
|
|
own_jid,
|
|
local_device,
|
|
profile_key,
|
|
)
|
|
|
|
def disco_infos(self, entity_jid, node="", use_cache=True, profile_key="@DEFAULT@"):
|
|
return self.call("disco_infos", entity_jid, node, use_cache, profile_key)
|
|
|
|
def disco_items(self, entity_jid, node="", use_cache=True, profile_key="@DEFAULT@"):
|
|
return self.call("disco_items", entity_jid, node, use_cache, profile_key)
|
|
|
|
def disconnect(self, profile_key="@DEFAULT@"):
|
|
return self.call("disconnect", profile_key)
|
|
|
|
def encryption_namespace_get(self, arg_0):
|
|
return self.call("encryption_namespace_get", arg_0)
|
|
|
|
def encryption_plugins_get(
|
|
self,
|
|
):
|
|
return self.call(
|
|
"encryption_plugins_get",
|
|
)
|
|
|
|
def encryption_trust_ui_get(self, to_jid, namespace, profile_key):
|
|
return self.call("encryption_trust_ui_get", to_jid, namespace, profile_key)
|
|
|
|
def entities_data_get(self, jids, keys, profile):
|
|
return self.call("entities_data_get", jids, keys, profile)
|
|
|
|
def entity_data_get(self, jid, keys, profile):
|
|
return self.call("entity_data_get", jid, keys, profile)
|
|
|
|
def features_get(self, profile_key):
|
|
return self.call("features_get", profile_key)
|
|
|
|
def history_get(
|
|
self, from_jid, to_jid, limit, between=True, filters="", profile="@NONE@"
|
|
):
|
|
return self.call(
|
|
"history_get", from_jid, to_jid, limit, between, filters, profile
|
|
)
|
|
|
|
def history_last_messages_metadata_get(self, options, profile_key="@NONE@"):
|
|
return self.call("history_last_messages_metadata_get", options, profile_key)
|
|
|
|
def image_check(self, arg_0):
|
|
return self.call("image_check", arg_0)
|
|
|
|
def image_convert(self, source, dest, arg_2, extra):
|
|
return self.call("image_convert", source, dest, arg_2, extra)
|
|
|
|
def image_generate_preview(self, image_path, profile_key):
|
|
return self.call("image_generate_preview", image_path, profile_key)
|
|
|
|
def image_resize(self, image_path, width, height):
|
|
return self.call("image_resize", image_path, width, height)
|
|
|
|
def init_pre_script(
|
|
self,
|
|
):
|
|
return self.call(
|
|
"init_pre_script",
|
|
)
|
|
|
|
def is_connected(self, profile_key="@DEFAULT@"):
|
|
return self.call("is_connected", profile_key)
|
|
|
|
def main_resource_get(self, contact_jid, profile_key="@DEFAULT@"):
|
|
return self.call("main_resource_get", contact_jid, profile_key)
|
|
|
|
def menu_help_get(self, menu_id, language):
|
|
return self.call("menu_help_get", menu_id, language)
|
|
|
|
def menu_launch(self, menu_type, path, data, security_limit, profile_key):
|
|
return self.call(
|
|
"menu_launch", menu_type, path, data, security_limit, profile_key
|
|
)
|
|
|
|
def menus_get(self, language, security_limit):
|
|
return self.call("menus_get", language, security_limit)
|
|
|
|
def message_encryption_get(self, to_jid, profile_key):
|
|
return self.call("message_encryption_get", to_jid, profile_key)
|
|
|
|
def message_encryption_start(
|
|
self, to_jid, namespace="", replace=False, profile_key="@NONE@"
|
|
):
|
|
return self.call(
|
|
"message_encryption_start", to_jid, namespace, replace, profile_key
|
|
)
|
|
|
|
def message_encryption_stop(self, to_jid, profile_key):
|
|
return self.call("message_encryption_stop", to_jid, profile_key)
|
|
|
|
def message_send(
|
|
self,
|
|
to_jid,
|
|
message,
|
|
subject={},
|
|
mess_type="auto",
|
|
extra={},
|
|
profile_key="@NONE@",
|
|
):
|
|
return self.call(
|
|
"message_send", to_jid, message, subject, mess_type, extra, profile_key
|
|
)
|
|
|
|
def messages_display_state_get(self, jids, profile_key):
|
|
return self.call("messages_display_state_get", jids, profile_key)
|
|
|
|
def messages_display_state_set(self, peer_jid, message_uid, profile_key):
|
|
return self.call("messages_display_state_set", peer_jid, message_uid, profile_key)
|
|
|
|
def namespaces_get(
|
|
self,
|
|
):
|
|
return self.call(
|
|
"namespaces_get",
|
|
)
|
|
|
|
def notification_add(
|
|
self,
|
|
type_,
|
|
body_plain,
|
|
body_rich,
|
|
title,
|
|
is_global,
|
|
requires_action,
|
|
arg_6,
|
|
priority,
|
|
expire_at,
|
|
extra,
|
|
):
|
|
return self.call(
|
|
"notification_add",
|
|
type_,
|
|
body_plain,
|
|
body_rich,
|
|
title,
|
|
is_global,
|
|
requires_action,
|
|
arg_6,
|
|
priority,
|
|
expire_at,
|
|
extra,
|
|
)
|
|
|
|
def notification_delete(self, id_, is_global, profile_key):
|
|
return self.call("notification_delete", id_, is_global, profile_key)
|
|
|
|
def notifications_expired_clean(self, limit_timestamp, profile_key):
|
|
return self.call("notifications_expired_clean", limit_timestamp, profile_key)
|
|
|
|
def notifications_get(self, filters, profile_key):
|
|
return self.call("notifications_get", filters, profile_key)
|
|
|
|
def param_get_a(self, name, category, attribute="value", profile_key="@DEFAULT@"):
|
|
return self.call("param_get_a", name, category, attribute, profile_key)
|
|
|
|
def param_get_a_async(
|
|
self,
|
|
name,
|
|
category,
|
|
attribute="value",
|
|
security_limit=-1,
|
|
profile_key="@DEFAULT@",
|
|
):
|
|
return self.call(
|
|
"param_get_a_async", name, category, attribute, security_limit, profile_key
|
|
)
|
|
|
|
def param_set(
|
|
self, name, value, category, security_limit=-1, profile_key="@DEFAULT@"
|
|
):
|
|
return self.call("param_set", name, value, category, security_limit, profile_key)
|
|
|
|
def param_ui_get(self, security_limit=-1, app="", extra="", profile_key="@DEFAULT@"):
|
|
return self.call("param_ui_get", security_limit, app, extra, profile_key)
|
|
|
|
def params_categories_get(
|
|
self,
|
|
):
|
|
return self.call(
|
|
"params_categories_get",
|
|
)
|
|
|
|
def params_register_app(self, xml, security_limit=-1, app=""):
|
|
return self.call("params_register_app", xml, security_limit, app)
|
|
|
|
def params_template_load(self, filename):
|
|
return self.call("params_template_load", filename)
|
|
|
|
def params_template_save(self, filename):
|
|
return self.call("params_template_save", filename)
|
|
|
|
def params_values_from_category_get_async(
|
|
self, category, security_limit=-1, app="", extra="", profile_key="@DEFAULT@"
|
|
):
|
|
return self.call(
|
|
"params_values_from_category_get_async",
|
|
category,
|
|
security_limit,
|
|
app,
|
|
extra,
|
|
profile_key,
|
|
)
|
|
|
|
def presence_set(self, to_jid="", show="", statuses={}, profile_key="@DEFAULT@"):
|
|
return self.call("presence_set", to_jid, show, statuses, profile_key)
|
|
|
|
def presence_statuses_get(self, profile_key="@DEFAULT@"):
|
|
return self.call("presence_statuses_get", profile_key)
|
|
|
|
def private_data_delete(self, namespace, key, arg_2):
|
|
return self.call("private_data_delete", namespace, key, arg_2)
|
|
|
|
def private_data_get(self, namespace, key, profile_key):
|
|
return self.call("private_data_get", namespace, key, profile_key)
|
|
|
|
def private_data_set(self, namespace, key, data, profile_key):
|
|
return self.call("private_data_set", namespace, key, data, profile_key)
|
|
|
|
def profile_create(self, profile, password="", component=""):
|
|
return self.call("profile_create", profile, password, component)
|
|
|
|
def profile_delete_async(self, profile):
|
|
return self.call("profile_delete_async", profile)
|
|
|
|
def profile_is_session_started(self, profile_key="@DEFAULT@"):
|
|
return self.call("profile_is_session_started", profile_key)
|
|
|
|
def profile_name_get(self, profile_key="@DEFAULT@"):
|
|
return self.call("profile_name_get", profile_key)
|
|
|
|
def profile_set_default(self, profile):
|
|
return self.call("profile_set_default", profile)
|
|
|
|
def profile_start_session(self, password="", profile_key="@DEFAULT@"):
|
|
return self.call("profile_start_session", password, profile_key)
|
|
|
|
def profiles_list_get(self, clients=True, components=False):
|
|
return self.call("profiles_list_get", clients, components)
|
|
|
|
def progress_get(self, id, profile):
|
|
return self.call("progress_get", id, profile)
|
|
|
|
def progress_get_all(self, profile):
|
|
return self.call("progress_get_all", profile)
|
|
|
|
def progress_get_all_metadata(self, profile):
|
|
return self.call("progress_get_all_metadata", profile)
|
|
|
|
def ready_get(
|
|
self,
|
|
):
|
|
return self.call(
|
|
"ready_get",
|
|
)
|
|
|
|
def roster_resync(self, profile_key="@DEFAULT@"):
|
|
return self.call("roster_resync", profile_key)
|
|
|
|
def session_infos_get(self, profile_key):
|
|
return self.call("session_infos_get", profile_key)
|
|
|
|
def sub_waiting_get(self, profile_key="@DEFAULT@"):
|
|
return self.call("sub_waiting_get", profile_key)
|
|
|
|
def subscription(self, sub_type, entity, profile_key="@DEFAULT@"):
|
|
return self.call("subscription", sub_type, entity, profile_key)
|
|
|
|
def tor_infos_get(self, extra, profile_key):
|
|
return self.call("tor_infos_get", extra, profile_key)
|
|
|
|
def tor_mode_get(self, profile_key):
|
|
return self.call("tor_mode_get", profile_key)
|
|
|
|
def version_get(
|
|
self,
|
|
):
|
|
return self.call(
|
|
"version_get",
|
|
)
|