6 import util.coroutines as coroutines
11 _moduleLogger = logging.getLogger("gvoice.conversations")
14 class Conversations(object):
16 def __init__(self, backend):
17 self._backend = backend
18 self._conversations = {}
20 self.updateSignalHandler = coroutines.CoTee()
23 def update(self, force=False):
24 if not force and self._conversations:
27 oldConversationIds = set(self._conversations.iterkeys())
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"]
35 conversation = self._conversations[key]
36 isNewConversation = False
38 conversation = Conversation(self._backend, messageData)
39 self._conversations[key] = conversation
40 isNewConversation = True
43 # @todo see if this has issues with a user marking a item as unread/unarchive?
44 isConversationUpdated = True
46 isConversationUpdated = conversation.merge_conversation(messageData)
48 if isConversationUpdated:
49 updateConversationIds.add(key)
51 if updateConversationIds:
52 message = (self, updateConversationIds, )
53 self.updateSignalHandler.stage.send(message)
55 def get_conversations(self):
56 return self._conversations.iterkeys()
58 def get_conversation(self, key):
59 return self._conversations[key]
61 def clear_conversation(self, key):
62 del self._conversations[key]
65 self._conversations.clear()
68 class Conversation(object):
70 def __init__(self, backend, data):
71 self._backend = backend
72 self._data = dict((key, value) for (key, value) in data.iteritems())
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"]
80 def __getitem__(self, key):
81 return self._data[key]
83 def merge_conversation(self, moreData):
85 @returns True if there was content to merge (new messages arrived
86 rather than being a duplicate)
88 @warning This assumes merges are done in chronological order
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)
93 if moreData["time"] < self._data["time"]:
94 # If its older, assuming it has nothing new to report
97 for preferredMoreField in ("id", "name", "time", "relTime", "prettyNumber", "location"):
98 preferredFieldValue = moreData[preferredMoreField]
99 if preferredFieldValue:
100 self._data[preferredMoreField] = preferredFieldValue
102 messageAppended = False
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
113 return messageAppended
116 def _append_time(message, exactWhen):
117 whoFrom, message, when = message
118 return exactWhen, whoFrom, message, when