Adding ConnectionInterfaceContactCapabilities, bringing ourselves inline with butterfly
[theonering] / src / simple_presence.py
1 import logging
2
3 import dbus
4 import telepathy
5
6 import util.misc as misc_utils
7 import tp
8 import handle
9 import gvoice.state_machine as state_machine
10
11
12 _moduleLogger = logging.getLogger(__name__)
13
14
15 class TheOneRingPresence(object):
16
17         # Note: these strings are also in the theonering.profile file
18         ONLINE = 'available'
19         AWAY = 'away'
20         HIDDEN = 'hidden'
21         OFFLINE = 'offline'
22
23         TO_PRESENCE_TYPE = {
24                 ONLINE: dbus.UInt32(telepathy.constants.CONNECTION_PRESENCE_TYPE_AVAILABLE),
25                 AWAY: dbus.UInt32(telepathy.constants.CONNECTION_PRESENCE_TYPE_AWAY),
26                 HIDDEN: dbus.UInt32(telepathy.constants.CONNECTION_PRESENCE_TYPE_HIDDEN),
27                 OFFLINE: dbus.UInt32(telepathy.constants.CONNECTION_PRESENCE_TYPE_OFFLINE),
28         }
29
30         @property
31         def session(self):
32                 """
33                 @abstract
34                 """
35                 raise NotImplementedError()
36
37         def Disconnect(self):
38                 """
39                 @abstract
40                 """
41                 raise NotImplementedError("Abstract function called")
42
43         def get_handle_by_id(self, handleType, handleId):
44                 """
45                 @abstract
46                 """
47                 raise NotImplementedError("Abstract function called")
48
49         def get_presences(self, contactIds):
50                 """
51                 @return {ContactHandle: (Status, Presence Type, Message)}
52                 """
53                 presences = {}
54                 for handleId in contactIds:
55                         h = self.get_handle_by_id(telepathy.HANDLE_TYPE_CONTACT, handleId)
56                         if isinstance(h, handle.ConnectionHandle):
57                                 isDnd = self.session.is_dnd()
58                                 if isDnd:
59                                         presence = TheOneRingPresence.HIDDEN
60                                 else:
61                                         state = self.session.stateMachine.state
62                                         if state == state_machine.StateMachine.STATE_ACTIVE:
63                                                 presence = TheOneRingPresence.ONLINE
64                                         elif state == state_machine.StateMachine.STATE_IDLE:
65                                                 presence = TheOneRingPresence.AWAY
66                                         else:
67                                                 raise telepathy.errors.InvalidArgument("Unsupported state on the state machine: %s" % state)
68                                 presenceType = TheOneRingPresence.TO_PRESENCE_TYPE[presence]
69                         else:
70                                 presence = TheOneRingPresence.AWAY
71                                 presenceType = TheOneRingPresence.TO_PRESENCE_TYPE[presence]
72
73                         presences[h] = (presenceType, presence)
74                 return presences
75
76         def set_presence(self, status):
77                 if status == self.ONLINE:
78                         self.session.set_dnd(False)
79                         self.session.stateMachine.set_state(state_machine.StateMachine.STATE_ACTIVE)
80                 elif status == self.AWAY:
81                         self.session.stateMachine.set_state(state_machine.StateMachine.STATE_IDLE)
82                 elif status == self.HIDDEN:
83                         self.session.set_dnd(True)
84                 elif status == self.OFFLINE:
85                         self.Disconnect()
86                 else:
87                         raise telepathy.errors.InvalidArgument("Unsupported status: %r" % status)
88                 _moduleLogger.info("Setting Presence to '%s'" % status)
89
90
91 class SimplePresenceMixin(tp.ConnectionInterfaceSimplePresence, TheOneRingPresence):
92
93         def __init__(self):
94                 tp.ConnectionInterfaceSimplePresence.__init__(self)
95                 TheOneRingPresence.__init__(self)
96
97                 self._implement_property_get(
98                         tp.CONNECTION_INTERFACE_SIMPLE_PRESENCE,
99                         {'Statuses' : self._get_statuses}
100                 )
101
102         @misc_utils.log_exception(_moduleLogger)
103         def GetPresences(self, contacts):
104                 """
105                 @return {ContactHandle: (Status, Presence Type, Message)}
106                 """
107                 personalMessage = u""
108                 return dbus.Dictionary(
109                         (
110                                 (h, dbus.Struct((presenceType, presence, personalMessage), signature="uss"))
111                                 for (h, (presenceType, presence)) in self.get_presences(contacts).iteritems()
112                         ),
113                         signature="u(uss)"
114                 )
115
116         @misc_utils.log_exception(_moduleLogger)
117         def SetPresence(self, status, message):
118                 if message:
119                         raise telepathy.errors.InvalidArgument("Messages aren't supported")
120
121                 self.set_presence(status)
122
123         def _get_statuses(self):
124                 """
125                 Property mapping presence statuses available to the corresponding presence types
126
127                 @returns {Name: (Telepathy Type, May Set On Self, Can Have Message)}
128                 """
129                 return dict(
130                         (localType, (telepathyType, True, False))
131                         for (localType, telepathyType) in self.TO_PRESENCE_TYPE.iteritems()
132                 )