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