9 import util.misc as util_misc
18 import simple_presence
23 import channel_manager
26 _moduleLogger = logging.getLogger("connection")
29 class TheOneRingOptions(object):
33 assert gvoice.session.Session._DEFAULTS["contacts"][1] == "hours"
34 contactsPollPeriodInHours = gvoice.session.Session._DEFAULTS["contacts"][0]
36 assert gvoice.session.Session._DEFAULTS["voicemail"][1] == "minutes"
37 voicemailPollPeriodInMinutes = gvoice.session.Session._DEFAULTS["voicemail"][0]
39 assert gvoice.session.Session._DEFAULTS["texts"][1] == "minutes"
40 textsPollPeriodInMinutes = gvoice.session.Session._DEFAULTS["texts"][0]
42 def __init__(self, parameters = None):
43 if parameters is None:
45 self.useGVContacts = parameters["use-gv-contacts"]
46 self.contactsPollPeriodInHours = parameters['contacts-poll-period-in-hours']
47 self.voicemailPollPeriodInMinutes = parameters['voicemail-poll-period-in-minutes']
48 self.textsPollPeriodInMinutes = parameters['texts-poll-period-in-minutes']
51 class TheOneRingConnection(
53 requests.RequestsMixin,
54 contacts.ContactsMixin,
55 aliasing.AliasingMixin,
56 simple_presence.SimplePresenceMixin,
57 presence.PresenceMixin,
58 capabilities.CapabilitiesMixin,
61 # overiding base class variable
62 _mandatory_parameters = {
66 # overiding base class variable
67 _optional_parameters = {
69 'use-gv-contacts': 'b',
70 'contacts-poll-period-in-hours': 'i',
71 'voicemail-poll-period-in-minutes': 'i',
72 'texts-poll-period-in-minutes': 'i',
74 _parameter_defaults = {
76 'use-gv-contacts': TheOneRingOptions.useGVContacts,
77 'contacts-poll-period-in-hours': TheOneRingOptions.contactsPollPeriodInHours,
78 'voicemail-poll-period-in-minutes': TheOneRingOptions.voicemailPollPeriodInMinutes,
79 'texts-poll-period-in-minutes': TheOneRingOptions.textsPollPeriodInMinutes,
81 _secret_parameters = set((
85 @gtk_toolbox.log_exception(_moduleLogger)
86 def __init__(self, manager, parameters):
87 self.check_parameters(parameters)
88 account = unicode(parameters['account'])
89 encodedAccount = parameters['account'].encode('utf-8')
90 encodedPassword = parameters['password'].encode('utf-8')
91 encodedCallback = util_misc.normalize_number(parameters['forward'].encode('utf-8'))
92 if encodedCallback and not util_misc.is_valid_number(encodedCallback):
93 raise telepathy.errors.InvalidArgument("Invalid forwarding number")
95 # Connection init must come first
96 self.__options = TheOneRingOptions(parameters)
97 self.__session = gvoice.session.Session(
100 "contacts": (self.__options.contactsPollPeriodInHours, "hours"),
101 "voicemail": (self.__options.voicemailPollPeriodInMinutes, "minutes"),
102 "texts": (self.__options.textsPollPeriodInMinutes, "minutes"),
105 tp.Connection.__init__(
107 constants._telepathy_protocol_name_,
109 constants._telepathy_implementation_name_
111 requests.RequestsMixin.__init__(self)
112 contacts.ContactsMixin.__init__(self)
113 aliasing.AliasingMixin.__init__(self)
114 simple_presence.SimplePresenceMixin.__init__(self)
115 presence.PresenceMixin.__init__(self)
116 capabilities.CapabilitiesMixin.__init__(self)
118 self.__manager = weakref.proxy(manager)
119 self.__credentials = (
123 self.__callbackNumberParameter = encodedCallback
124 self.__channelManager = channel_manager.ChannelManager(self)
126 self.__cachePath = os.sep.join((constants._data_path_, "cache", self.username))
128 os.makedirs(self.__cachePath)
133 self.set_self_handle(handle.create_handle(self, 'connection'))
135 autogv.NewGVConversations(weakref.ref(self)),
136 autogv.RefreshVoicemail(weakref.ref(self)),
137 autogv.AutoDisconnect(weakref.ref(self)),
140 _moduleLogger.info("Connection to the account %s created" % account)
144 return self.__manager
148 return self.__session
152 return self.__options
156 return self.__credentials[0]
159 def callbackNumberParameter(self):
160 return self.__callbackNumberParameter
162 def get_handle_by_name(self, handleType, handleName):
163 requestedHandleName = handleName.encode('utf-8')
164 if handleType == telepathy.HANDLE_TYPE_CONTACT:
165 _moduleLogger.debug("get_handle_by_name Contact: %s" % requestedHandleName)
166 h = handle.create_handle(self, 'contact', requestedHandleName)
167 elif handleType == telepathy.HANDLE_TYPE_LIST:
168 # Support only server side (immutable) lists
169 _moduleLogger.debug("get_handle_by_name List: %s" % requestedHandleName)
170 h = handle.create_handle(self, 'list', requestedHandleName)
172 raise telepathy.errors.NotAvailable('Handle type unsupported %d' % handleType)
176 def _channel_manager(self):
177 return self.__channelManager
179 @gtk_toolbox.log_exception(_moduleLogger)
182 For org.freedesktop.telepathy.Connection
184 _moduleLogger.info("Connecting...")
186 telepathy.CONNECTION_STATUS_CONNECTING,
187 telepathy.CONNECTION_STATUS_REASON_REQUESTED
190 self.__session.load(self.__cachePath)
192 for plumber in self._plumbing:
194 self.session.login(*self.__credentials)
195 if not self.__callbackNumberParameter:
196 callback = gvoice.backend.get_sane_callback(
199 self.__callbackNumberParameter = util_misc.normalize_number(callback)
200 self.session.backend.set_callback_number(self.__callbackNumberParameter)
202 subscribeHandle = self.get_handle_by_name(telepathy.HANDLE_TYPE_LIST, "subscribe")
203 subscribeProps = self.generate_props(telepathy.CHANNEL_TYPE_CONTACT_LIST, subscribeHandle, False)
204 self.__channelManager.channel_for_props(subscribeProps, signal=True)
205 publishHandle = self.get_handle_by_name(telepathy.HANDLE_TYPE_LIST, "publish")
206 publishProps = self.generate_props(telepathy.CHANNEL_TYPE_CONTACT_LIST, publishHandle, False)
207 self.__channelManager.channel_for_props(publishProps, signal=True)
208 except gvoice.backend.NetworkError, e:
209 _moduleLogger.exception("Connection Failed")
211 telepathy.CONNECTION_STATUS_DISCONNECTED,
212 telepathy.CONNECTION_STATUS_REASON_NETWORK_ERROR
216 _moduleLogger.exception("Connection Failed")
218 telepathy.CONNECTION_STATUS_DISCONNECTED,
219 telepathy.CONNECTION_STATUS_REASON_AUTHENTICATION_FAILED
223 _moduleLogger.info("Connected")
225 telepathy.CONNECTION_STATUS_CONNECTED,
226 telepathy.CONNECTION_STATUS_REASON_REQUESTED
229 @gtk_toolbox.log_exception(_moduleLogger)
230 def Disconnect(self):
232 For org.freedesktop.telepathy.Connection
235 self.disconnect(telepathy.CONNECTION_STATUS_REASON_REQUESTED)
237 _moduleLogger.exception("Error durring disconnect")
239 @gtk_toolbox.log_exception(_moduleLogger)
240 def RequestChannel(self, type, handleType, handleId, suppressHandler):
242 For org.freedesktop.telepathy.Connection
244 @param type DBus interface name for base channel type
245 @param handleId represents a contact, list, etc according to handleType
247 @returns DBus object path for the channel created or retrieved
249 self.check_connected()
250 self.check_handle(handleType, handleId)
252 h = self.get_handle_by_id(handleType, handleId) if handleId != 0 else None
253 props = self.generate_props(type, h, suppressHandler)
254 self._validate_handle(props)
256 chan = self.__channelManager.channel_for_props(props, signal=True)
257 path = chan._object_path
258 _moduleLogger.info("RequestChannel Object Path (%s): %s" % (type.rsplit(".", 1)[-1], path))
261 def generate_props(self, channelType, handle, suppressHandler, initiatorHandle=None):
262 targetHandle = 0 if handle is None else handle.get_id()
263 targetHandleType = telepathy.HANDLE_TYPE_NONE if handle is None else handle.get_type()
265 telepathy.CHANNEL_INTERFACE + '.ChannelType': channelType,
266 telepathy.CHANNEL_INTERFACE + '.TargetHandle': targetHandle,
267 telepathy.CHANNEL_INTERFACE + '.TargetHandleType': targetHandleType,
268 telepathy.CHANNEL_INTERFACE + '.Requested': suppressHandler
271 if initiatorHandle is not None:
272 props[telepathy.CHANNEL_INTERFACE + '.InitiatorHandle'] = initiatorHandle.id
276 def disconnect(self, reason):
277 _moduleLogger.info("Disconnecting")
278 # Not having the disconnect first can cause weird behavior with clients
279 # including not being able to reconnect or even crashing
281 telepathy.CONNECTION_STATUS_DISCONNECTED,
285 for plumber in self._plumbing:
288 self.__channelManager.close()
289 self.session.save(self.__cachePath)
290 self.session.logout()
293 self.manager.disconnected(self)
294 _moduleLogger.info("Disconnected")