69ed50ce7c7f4df796bca7d89e34ace024f0fa15
[theonering] / src / connection.py
1 import weakref
2 import logging
3
4 import telepathy
5
6 import constants
7 import util.go_utils as gobject_utils
8 import util.coroutines as coroutines
9 import gtk_toolbox
10 import gvoice
11 import handle
12 import aliasing
13 import simple_presence
14 import channel_manager
15
16
17 _moduleLogger = logging.getLogger("connection")
18
19
20 class TheOneRingConnection(
21         telepathy.server.Connection,
22         aliasing.AliasingMixin,
23         simple_presence.SimplePresenceMixin,
24 ):
25
26         # Overriding a base class variable
27         # Should the forwarding number be handled by the alias or by an option?
28         _mandatory_parameters = {
29                 'username' : 's',
30                 'password' : 's',
31                 'forward' : 's',
32         }
33         # Overriding a base class variable
34         _optional_parameters = {
35         }
36         _parameter_defaults = {
37         }
38
39         def __init__(self, manager, parameters):
40                 self.check_parameters(parameters)
41                 try:
42                         account = unicode(parameters['username'])
43
44                         # Connection init must come first
45                         telepathy.server.Connection.__init__(
46                                 self,
47                                 constants._telepathy_protocol_name_,
48                                 account,
49                                 constants._telepathy_implementation_name_
50                         )
51                         aliasing.AliasingMixin.__init__(self)
52                         simple_presence.SimplePresenceMixin.__init__(self)
53
54                         self._manager = weakref.proxy(manager)
55                         self._credentials = (
56                                 parameters['username'].encode('utf-8'),
57                                 parameters['password'].encode('utf-8'),
58                         )
59                         self._callbackNumber = parameters['forward'].encode('utf-8')
60                         self._channelManager = channel_manager.ChannelManager(self)
61
62                         cookieFilePath = None
63                         self._session = gvoice.session.Session(cookieFilePath)
64
65                         self.set_self_handle(handle.create_handle(self, 'connection'))
66
67                         self._callback = coroutines.func_sink(
68                                 coroutines.expand_positional(
69                                         self._on_conversations_updated
70                                 )
71                         )
72                         _moduleLogger.info("Connection to the account %s created" % account)
73                 except Exception, e:
74                         _moduleLogger.exception("Failed to create Connection")
75                         raise
76
77         @property
78         def manager(self):
79                 return self._manager
80
81         @property
82         def session(self):
83                 return self._session
84
85         @property
86         def username(self):
87                 return self._credentials[0]
88
89         def handle(self, handleType, handleId):
90                 self.check_handle(handleType, handleId)
91                 return self._handles[handleType, handleId]
92
93         @gtk_toolbox.log_exception(_moduleLogger)
94         def Connect(self):
95                 """
96                 For org.freedesktop.telepathy.Connection
97                 """
98                 _moduleLogger.info("Connecting...")
99                 self.StatusChanged(
100                         telepathy.CONNECTION_STATUS_CONNECTING,
101                         telepathy.CONNECTION_STATUS_REASON_REQUESTED
102                 )
103                 try:
104                         self.session.conversations.updateSignalHandler.register_sink(
105                                 self._callback
106                         )
107                         self.session.login(*self._credentials)
108                         self.session.backend.set_callback_number(self._callbackNumber)
109                 except gvoice.backend.NetworkError, e:
110                         _moduleLogger.exception("Connection Failed")
111                         self.StatusChanged(
112                                 telepathy.CONNECTION_STATUS_DISCONNECTED,
113                                 telepathy.CONNECTION_STATUS_REASON_NETWORK_ERROR
114                         )
115                 except Exception, e:
116                         _moduleLogger.exception("Connection Failed")
117                         self.StatusChanged(
118                                 telepathy.CONNECTION_STATUS_DISCONNECTED,
119                                 telepathy.CONNECTION_STATUS_REASON_AUTHENTICATION_FAILED
120                         )
121                 else:
122                         _moduleLogger.info("Connected")
123                         self.StatusChanged(
124                                 telepathy.CONNECTION_STATUS_CONNECTED,
125                                 telepathy.CONNECTION_STATUS_REASON_REQUESTED
126                         )
127
128         @gtk_toolbox.log_exception(_moduleLogger)
129         def Disconnect(self):
130                 """
131                 For org.freedesktop.telepathy.Connection
132                 @bug Not properly logging out.  Cookie files need to be per connection and removed
133                 """
134                 _moduleLogger.info("Disconnecting")
135                 try:
136                         self.session.conversations.updateSignalHandler.unregister_sink(
137                                 self._callback
138                         )
139                         self._channelManager.close()
140                         self.session.logout()
141                         _moduleLogger.info("Disconnected")
142                 except Exception:
143                         _moduleLogger.exception("Disconnecting Failed")
144                 self.StatusChanged(
145                         telepathy.CONNECTION_STATUS_DISCONNECTED,
146                         telepathy.CONNECTION_STATUS_REASON_REQUESTED
147                 )
148
149         @gtk_toolbox.log_exception(_moduleLogger)
150         def RequestChannel(self, type, handleType, handleId, suppressHandler):
151                 """
152                 For org.freedesktop.telepathy.Connection
153
154                 @param type DBus interface name for base channel type
155                 @param handleId represents a contact, list, etc according to handleType
156
157                 @returns DBus object path for the channel created or retrieved
158                 """
159                 self.check_connected()
160                 self.check_handle(handleType, handleId)
161
162                 channel = None
163                 channelManager = self._channelManager
164                 handle = self.handle(handleType, handleId)
165
166                 if type == telepathy.CHANNEL_TYPE_CONTACT_LIST:
167                         _moduleLogger.info("RequestChannel ContactList")
168                         channel = channelManager.channel_for_list(handle, suppressHandler)
169                 elif type == telepathy.CHANNEL_TYPE_TEXT:
170                         _moduleLogger.info("RequestChannel Text")
171                         channel = channelManager.channel_for_text(handle, suppressHandler)
172                 elif type == telepathy.CHANNEL_TYPE_STREAMED_MEDIA:
173                         _moduleLogger.info("RequestChannel Media")
174                         channel = channelManager.channel_for_call(handle, suppressHandler)
175                 else:
176                         raise telepathy.errors.NotImplemented("unknown channel type %s" % type)
177
178                 _moduleLogger.info("RequestChannel Object Path: %s" % channel._object_path)
179                 return channel._object_path
180
181         @gtk_toolbox.log_exception(_moduleLogger)
182         def RequestHandles(self, handleType, names, sender):
183                 """
184                 For org.freedesktop.telepathy.Connection
185                 Overiding telepathy.server.Connecton to allow custom handles
186                 """
187                 self.check_connected()
188                 self.check_handle_type(handleType)
189
190                 handles = []
191                 for name in names:
192                         name = name.encode('utf-8')
193                         if handleType == telepathy.HANDLE_TYPE_CONTACT:
194                                 _moduleLogger.info("RequestHandles Contact: %s" % name)
195                                 h = self._create_contact_handle(name)
196                         elif handleType == telepathy.HANDLE_TYPE_LIST:
197                                 # Support only server side (immutable) lists
198                                 _moduleLogger.info("RequestHandles List: %s" % name)
199                                 h = handle.create_handle(self, 'list', name)
200                         else:
201                                 raise telepathy.errors.NotAvailable('Handle type unsupported %d' % handleType)
202                         handles.append(h.id)
203                         self.add_client_handle(h, sender)
204                 return handles
205
206         def _create_contact_handle(self, requestedHandleName):
207                 requestedContactId, requestedContactNumber = handle.ContactHandle.from_handle_name(
208                         requestedHandleName
209                 )
210                 h = handle.create_handle(self, 'contact', requestedContactId, requestedContactNumber)
211                 return h
212
213         @gobject_utils.async
214         @gtk_toolbox.log_exception(_moduleLogger)
215         def _on_conversations_updated(self, conv, conversationIds):
216                 # @todo get conversations update running
217                 # @todo test conversatiuons
218                 _moduleLogger.info("Incoming messages from: %r" % (conversationIds, ))
219                 channelManager = self._channelManager
220                 for contactId, phoneNumber in conversationIds:
221                         h = handle.create_handle(self, 'contact', contactId, phoneNumber)
222                         # if its new, __init__ will take care of things
223                         # if its old, its own update will take care of it
224                         channel = channelManager.channel_for_text(h)