From 8a9fa626c7ee9183a6d275e8cb1134ee35c73eef Mon Sep 17 00:00:00 2001 From: Louis-Francis Ratté-Boulianne Date: Thu, 28 Oct 2010 16:38:38 -0400 Subject: Add Protocol default implementation Connection Managers have to populate Protocol properties (_english_name, _icon, etc.) in a child class. create_connection must be overridden. The method _implement_protocol must be called on the connection manager to add all known Protocol classes. --- src/server/Makefile.am | 3 +- src/server/__init__.py | 1 + src/server/conn.py | 5 +- src/server/connmgr.py | 7 ++- src/server/protocol.py | 161 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 173 insertions(+), 4 deletions(-) create mode 100644 src/server/protocol.py diff --git a/src/server/Makefile.am b/src/server/Makefile.am index e6739ab..5d92dc2 100644 --- a/src/server/Makefile.am +++ b/src/server/Makefile.am @@ -9,7 +9,8 @@ server_PYTHON = \ handle.py \ __init__.py \ media.py \ - properties.py + properties.py \ + protocol.py clean-local: rm -rf *.pyc *.pyo diff --git a/src/server/__init__.py b/src/server/__init__.py index 16167aa..94fb3dd 100644 --- a/src/server/__init__.py +++ b/src/server/__init__.py @@ -28,6 +28,7 @@ from telepathy.server.debug import * from telepathy.server.handle import * from telepathy.server.media import * from telepathy.server.properties import * +from telepathy.server.protocol import * from telepathy._generated.Client_Observer import ClientObserver as Observer from telepathy._generated.Client_Approver import ClientApprover as Approver diff --git a/src/server/conn.py b/src/server/conn.py index 9192829..dff738c 100644 --- a/src/server/conn.py +++ b/src/server/conn.py @@ -60,7 +60,7 @@ class Connection(_Connection, DBusProperties): _secret_parameters = {} _parameter_defaults = {} - def __init__(self, proto, account, manager=None): + def __init__(self, proto, account, manager=None, protocol=None): """ Parameters: proto - the name of the protcol this conection should be handling. @@ -99,7 +99,8 @@ class Connection(_Connection, DBusProperties): 'Status': lambda: dbus.UInt32(self.GetStatus()) }) - self._proto = proto + self._proto = proto # Protocol name + self._protocol = protocol # Protocol object self._status = CONNECTION_STATUS_DISCONNECTED diff --git a/src/server/connmgr.py b/src/server/connmgr.py index f087aae..bdf1dc6 100644 --- a/src/server/connmgr.py +++ b/src/server/connmgr.py @@ -41,7 +41,7 @@ class ConnectionManager(_ConnectionManager, DBusProperties): self._interfaces = set() self._connections = set() - self._protos = {} # proto name => Connection class + self._protos = {} # proto name => Connection constructor self._protocols = {} # proto name => Protocol object DBusProperties.__init__(self) @@ -86,6 +86,11 @@ class ConnectionManager(_ConnectionManager, DBusProperties): self.connected(conn) return (conn._name.get_name(), conn._object_path) + def _implement_protocol(self, name, protocol_class): + protocol = protocol_class(self) + self._protocols[name] = protocol + self._protos[name] = protocol.create_connection + @property def _protocol_properties(self): properties = {} diff --git a/src/server/protocol.py b/src/server/protocol.py new file mode 100644 index 0000000..fa20de4 --- /dev/null +++ b/src/server/protocol.py @@ -0,0 +1,161 @@ +# telepathy-python - Base classes defining the interfaces of the Telepathy framework +# +# Copyright (C) 2010 Collabora Limited +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +import dbus +import dbus.service + +from telepathy.constants import (CONN_MGR_PARAM_FLAG_REQUIRED, + CONN_MGR_PARAM_FLAG_SECRET, + CONN_MGR_PARAM_FLAG_HAS_DEFAULT) +from telepathy.errors import InvalidArgument, NotImplemented +from telepathy.interfaces import PROTOCOL +from telepathy.server.properties import DBusProperties + +from telepathy._generated.Protocol import Protocol as _Protocol + +class Protocol(_Protocol, DBusProperties): + + """ Class members to override in CM implementations : """ + + _english_name = "" + _icon = "" + _vcard_field = "" + + # List of Requestable_Channel_Class struct + _requestable_channel_classe = [] + + _optional_parameters = {} + _mandatory_parameters = {} + _secret_parameters = {} + _parameter_defaults = {} + + + def __init__(self, connection_manager, proto): + escaped_name = proto.replace("-", "_") + bus_name = connection_manager._name + object_path = connection_manager._object_path + "/" + escaped_name + + _Protocol.__init__(self, bus_name, object_path) + + self._proto = proto + self._interfaces = set() + + DBusProperties.__init__(self) + self._implement_property_get(PROTOCOL, { + 'EnglishName': lambda: self.english_name, + 'Icon': lambda: self.icon, + 'VCardField': lambda: self.vcard_field, + 'Interfaces': lambda: self.interfaces, + 'ConnectionInterfaces': lambda: self.connection_interfaces, + 'RequestableChannelClasses': lambda: self.requestable_channels, + 'Parameters': lambda: self.parameters + }) + + @property + def english_name(self): + return dbus.String(self._english_name) + + @property + def icon(self): + return dbus.String(self._icon) + + @property + def vcard_field(self): + return dbus.String(self._vcard_field) + + @property + def interfaces(self): + return dbus.Array(self._interfaces, signature='s') + + @property + def connection_interfaces(self): + return dbus.Array(self._supported_interfaces, signature='s') + + @property + def requestable_channels(self): + return dbus.Array(self._requestable_channel_classes, + signature='(a{sv}as)') + + @property + def parameters(self): + parameters = [] + + secret_parameters = self._secret_parameters + mandatory_parameters = self._mandatory_parameters + optional_parameters = self._optional_parameters + default_parameters = self._parameter_defaults + + for parameter_name, parameter_type in mandatory_parameters.iteritems(): + flags = CONN_MGR_PARAM_FLAG_REQUIRED + if parameter_name in secret_parameters: + flags |= CONN_MGR_PARAM_FLAG_SECRET + param = (parameter_name, flags, parameter_type, '') + parameters.append(param) + + for parameter_name, parameter_type in optional_parameters.iteritems(): + flags = 0 + default = '' + if parameter_name in secret_parameters: + flags |= CONN_MGR_PARAM_FLAG_SECRET + if parameter_name in default_parameters: + flags |= CONN_MGR_PARAM_FLAG_HAS_DEFAULT + default = default_parameters[parameter_name] + param = (parameter_name, flags, parameter_type, default) + parameters.append(param) + + return dbus.Array(parameters, signature='(susv)') + + def check_parameters(self, parameters): + """ + Validate and type check all of the provided parameters, and + check all mandatory parameters are present before creating a + new connection. + Sets defaults according to the defaults if the client has not + provided any. + """ + for (parm, value) in parameters.iteritems(): + if parm in self._mandatory_parameters.keys(): + sig = self._mandatory_parameters[parm] + elif parm in self._optional_parameters.keys(): + sig = self._optional_parameters[parm] + else: + raise InvalidArgument('unknown parameter name %s' % parm) + + # we currently support strings, (u)int16/32 and booleans + if sig == 's': + if not isinstance(value, unicode): + raise InvalidArgument('incorrect type to %s parameter, got %s, expected a string' % (parm, type(value))) + elif sig in 'iunq': + if not isinstance(value, (int, long)): + raise InvalidArgument('incorrect type to %s parameter, got %s, expected an int' % (parm, type(value))) + elif sig == 'b': + if not isinstance(value, (bool, dbus.Boolean)): + raise InvalidArgument('incorrect type to %s parameter, got %s, expected an boolean' % (parm, type(value))) + else: + raise TypeError('unknown type signature %s in protocol parameters' % type) + + for (parm, value) in self._parameter_defaults.iteritems(): + if parm not in parameters: + parameters[parm] = value + + missing = set(self._mandatory_parameters.keys()).difference(parameters.keys()) + if missing: + raise InvalidArgument('required parameters %s not given' % missing) + + def create_connection(self, connection_manager, parameters): + raise NotImplemented('no create_connection for %s' % self._proto) -- cgit v1.2.3