3e0040c83661477bb28ed138d6a13a8bec386901
[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                 del self._conversations[key]
63
64         def clear_all(self):
65                 self._conversations.clear()
66
67
68 class Conversation(object):
69
70         def __init__(self, backend, data):
71                 self._backend = backend
72                 self._data = dict((key, value) for (key, value) in data.iteritems())
73
74                 # confirm we have a list
75                 self._data["messageParts"] = list(
76                         self._append_time(message, self._data["time"])
77                         for message in self._data["messageParts"]
78                 )
79
80         def __getitem__(self, key):
81                 return self._data[key]
82
83         def merge_conversation(self, moreData):
84                 """
85                 @returns True if there was content to merge (new messages arrived
86                 rather than being a duplicate)
87
88                 @warning This assumes merges are done in chronological order
89                 """
90                 for constantField in ("contactId", "number"):
91                         assert self._data[constantField] == moreData[constantField], "Constant field changed, soemthing is seriously messed up: %r v %r" % (self._data, moreData)
92
93                 if moreData["time"] < self._data["time"]:
94                         # If its older, assuming it has nothing new to report
95                         return False
96
97                 for preferredMoreField in ("id", "name", "time", "relTime", "prettyNumber", "location"):
98                         preferredFieldValue = moreData[preferredMoreField]
99                         if preferredFieldValue:
100                                 self._data[preferredMoreField] = preferredFieldValue
101
102                 messageAppended = False
103
104                 # @todo Handle No Transcription voicemails
105                 messageParts = self._data["messageParts"]
106                 for message in moreData["messageParts"]:
107                         messageWithTimestamp = self._append_time(message, moreData["time"])
108                         if messageWithTimestamp not in messageParts:
109                                 messageParts.append(messageWithTimestamp)
110                                 messageAppended = True
111                 messageParts.sort()
112
113                 return messageAppended
114
115         @staticmethod
116         def _append_time(message, exactWhen):
117                 whoFrom, message, when = message
118                 return exactWhen, whoFrom, message, when