Making phone numbers as consistent as possible so user started conversations don...
[theonering] / src / handle.py
1 import logging
2 import weakref
3
4 import telepathy
5
6 import tp
7 import util.misc as util_misc
8
9
10 _moduleLogger = logging.getLogger("handle")
11
12
13 class TheOneRingHandle(tp.Handle):
14         """
15         Instances are memoized
16         """
17
18         def __init__(self, connection, id, handleType, name):
19                 tp.Handle.__init__(self, id, handleType, name)
20                 self._conn = weakref.proxy(connection)
21
22         def __repr__(self):
23                 return "<%s id=%u name='%s'>" % (
24                         type(self).__name__, self.id, self.name
25                 )
26
27         id = property(tp.Handle.get_id)
28         type = property(tp.Handle.get_type)
29         name = property(tp.Handle.get_name)
30
31
32 class ConnectionHandle(TheOneRingHandle):
33
34         def __init__(self, connection, id):
35                 handleType = telepathy.HANDLE_TYPE_CONTACT
36                 handleName = connection.username
37                 TheOneRingHandle.__init__(self, connection, id, handleType, handleName)
38
39                 self.profile = connection.username
40
41
42 class ContactHandle(TheOneRingHandle):
43
44         _DELIMETER = "|"
45
46         def __init__(self, connection, id, contactId, phoneNumber):
47                 handleType = telepathy.HANDLE_TYPE_CONTACT
48                 handleName = self.to_handle_name(contactId, phoneNumber)
49                 TheOneRingHandle.__init__(self, connection, id, handleType, handleName)
50
51                 self._contactId = contactId
52                 self._phoneNumber = util_misc.normalize_number(phoneNumber)
53
54         @classmethod
55         def from_handle_name(cls, handleName):
56                 """
57                 >>> ContactHandle.from_handle_name("+1 555 123-1234")
58                 ('', '+15551231234')
59                 >>> ContactHandle.from_handle_name("+15551231234")
60                 ('', '+15551231234')
61                 >>> ContactHandle.from_handle_name("123456|+15551231234")
62                 ('123456', '+15551231234')
63                 """
64                 parts = handleName.split(cls._DELIMETER, 1)
65                 if len(parts) == 2:
66                         contactId, contactNumber = parts[0:2]
67                 elif len(parts) == 1:
68                         contactId, contactNumber = "", handleName
69                 else:
70                         raise RuntimeError("Invalid handle: %s" % handleName)
71
72                 contactNumber = util_misc.normalize_number(contactNumber)
73                 return contactId, contactNumber
74
75         @classmethod
76         def to_handle_name(cls, contactId, contactNumber):
77                 """
78                 >>> ContactHandle.to_handle_name('', "+1 555 123-1234")
79                 '+15551231234'
80                 >>> ContactHandle.to_handle_name('', "+15551231234")
81                 '+15551231234'
82                 >>> ContactHandle.to_handle_name('123456', "+15551231234")
83                 '123456|+15551231234'
84                 """
85                 contactNumber = util_misc.normalize_number(contactNumber)
86                 if contactId:
87                         handleName = cls._DELIMETER.join((contactId, contactNumber))
88                 else:
89                         handleName = contactNumber
90                 return handleName
91
92         @property
93         def contactID(self):
94                 return self._contactId
95
96         @property
97         def phoneNumber(self):
98                 return self._phoneNumber
99
100         @property
101         def contactDetails(self):
102                 return self._conn.addressbook.get_contact_details(self._id)
103
104
105 class ListHandle(TheOneRingHandle):
106
107         def __init__(self, connection, id, listName):
108                 handleType = telepathy.HANDLE_TYPE_LIST
109                 handleName = listName
110                 TheOneRingHandle.__init__(self, connection, id, handleType, handleName)
111
112
113 _HANDLE_TYPE_MAPPING = {
114         'connection': ConnectionHandle,
115         'contact': ContactHandle,
116         'list': ListHandle,
117 }
118
119
120 def create_handle_factory():
121
122         cache = weakref.WeakValueDictionary()
123
124         def create_handle(connection, type, *args):
125                 Handle = _HANDLE_TYPE_MAPPING[type]
126                 key = Handle, connection.username, args
127                 try:
128                         handle = cache[key]
129                         isNewHandle = False
130                 except KeyError:
131                         # The misnamed get_handle_id requests a new handle id
132                         handle = Handle(connection, connection.get_handle_id(), *args)
133                         cache[key] = handle
134                         isNewHandle = True
135                 connection._handles[handle.get_type(), handle.get_id()] = handle
136                 handleStatus = "Is New!" if isNewHandle else "From Cache"
137                 _moduleLogger.debug("Created Handle: %r (%s)" % (handle, handleStatus))
138                 return handle
139
140         return create_handle
141
142
143 create_handle = create_handle_factory()