357a8445521acdc644f20d987f4840d3ebfec1b3
[theonering] / src / gvoice / conversations.py
1 #!/usr/bin/python
2
3
4 import logging
5
6 import util.coroutines as coroutines
7
8 import backend
9
10
11 _moduleLogger = logging.getLogger("gvoice.conversations")
12
13
14 class Conversations(object):
15
16         def __init__(self, backend):
17                 self._backend = backend
18                 self._conversations = {}
19
20                 self.updateSignalHandler = coroutines.CoTee()
21                 self.update()
22
23         def update(self, force=False):
24                 if not force and self._conversations:
25                         return
26
27                 oldConversationIds = set(self._conversations.iterkeys())
28
29                 updateConversationIds = set()
30                 messages = self._backend.get_messages()
31                 sortedMessages = backend.sort_messages(messages)
32                 for messageData in sortedMessages:
33                         key = messageData["contactId"], messageData["number"]
34                         try:
35                                 conversation = self._conversations[key]
36                                 isNewConversation = False
37                         except KeyError:
38                                 conversation = Conversation(self._backend, messageData)
39                                 self._conversations[key] = conversation
40                                 isNewConversation = True
41
42                         if isNewConversation:
43                                 # @todo see if this has issues with a user marking a item as unread/unarchive?
44                                 isConversationUpdated = True
45                         else:
46                                 isConversationUpdated = conversation.merge_conversation(messageData)
47
48                         if isConversationUpdated:
49                                 updateConversationIds.add(key)
50
51                 if updateConversationIds:
52                         message = (self, updateConversationIds, )
53                         self.updateSignalHandler.stage.send(message)
54
55         def get_conversations(self):
56                 return self._conversations.iterkeys()
57
58         def get_conversation(self, key):
59                 return self._conversations[key]
60
61         def clear_conversation(self, key):
62                 try:
63                         del self._conversations[key]
64                 except KeyError:
65                         _moduleLogger.info("Conversation never existed for %r" % (key,))
66
67         def clear_all(self):
68                 self._conversations.clear()
69
70
71 class Conversation(object):
72
73         def __init__(self, backend, data):
74                 self._backend = backend
75                 self._data = dict((key, value) for (key, value) in data.iteritems())
76
77                 # confirm we have a list
78                 self._data["messageParts"] = list(
79                         self._append_time(message, self._data["time"])
80                         for message in self._data["messageParts"]
81                 )
82
83         def __getitem__(self, key):
84                 return self._data[key]
85
86         def merge_conversation(self, moreData):
87                 """
88                 @returns True if there was content to merge (new messages arrived
89                 rather than being a duplicate)
90
91                 @warning This assumes merges are done in chronological order
92                 """
93                 for constantField in ("contactId", "number"):
94                         assert self._data[constantField] == moreData[constantField], "Constant field changed, soemthing is seriously messed up: %r v %r" % (self._data, moreData)
95
96                 if moreData["time"] < self._data["time"]:
97                         # If its older, assuming it has nothing new to report
98                         return False
99
100                 for preferredMoreField in ("id", "name", "time", "relTime", "prettyNumber", "location"):
101                         preferredFieldValue = moreData[preferredMoreField]
102                         if preferredFieldValue:
103                                 self._data[preferredMoreField] = preferredFieldValue
104
105                 messageAppended = False
106
107                 # @todo Handle No Transcription voicemails
108                 messageParts = self._data["messageParts"]
109                 for message in moreData["messageParts"]:
110                         messageWithTimestamp = self._append_time(message, moreData["time"])
111                         if messageWithTimestamp not in messageParts:
112                                 messageParts.append(messageWithTimestamp)
113                                 messageAppended = True
114                 messageParts.sort()
115
116                 return messageAppended
117
118         @staticmethod
119         def _append_time(message, exactWhen):
120                 whoFrom, message, when = message
121                 return exactWhen, whoFrom, message, when