7 import util.coroutines as coroutines
8 import util.misc as misc_utils
9 import util.go_utils as gobject_utils
13 _moduleLogger = logging.getLogger(__name__)
16 class TextChannel(tp.ChannelTypeText):
18 def __init__(self, connection, manager, props, contactHandle):
19 self.__manager = manager
22 tp.ChannelTypeText.__init__(self, connection, manager, props)
23 self.__nextRecievedId = 0
25 self.__otherHandle = contactHandle
27 self.__callback = coroutines.func_sink(
28 coroutines.expand_positional(
29 self._on_conversations_updated
32 self._conn.session.voicemails.updateSignalHandler.register_sink(
35 self._conn.session.texts.updateSignalHandler.register_sink(
39 self._filter_out_reported = gvoice.conversations.FilterOutReported()
41 # The only reason there should be anything in the conversation is if
42 # its new, so report it all
44 mergedConversations = self._conn.session.voicemails.get_conversation(self._contactKey)
46 _moduleLogger.debug("No voicemails in the conversation yet for %r" % (self._contactKey, ))
48 self._report_conversation(mergedConversations)
50 mergedConversations = self._conn.session.texts.get_conversation(self._contactKey)
52 _moduleLogger.debug("No texts conversation yet for %r" % (self._contactKey, ))
54 self._report_conversation(mergedConversations)
56 @misc_utils.log_exception(_moduleLogger)
57 def Send(self, messageType, text):
58 le = gobject_utils.AsyncLinearExecution(self._conn.session.pool, self._send)
59 le.start(messageType, text)
61 @misc_utils.log_exception(_moduleLogger)
62 def _send(self, messageType, text):
63 if messageType != telepathy.CHANNEL_TEXT_MESSAGE_TYPE_NORMAL:
64 raise telepathy.errors.NotImplemented("Unhandled message type: %r" % messageType)
66 _moduleLogger.info("Sending message to %r" % (self.__otherHandle, ))
69 self._conn.session.backend.send_sms,
70 ([self.__otherHandle.phoneNumber], text),
74 _moduleLogger.exception(result)
77 self._conn.session.textsStateMachine.reset_timers()
79 self.Sent(int(time.time()), messageType, text)
81 @misc_utils.log_exception(_moduleLogger)
82 def _on_send_sms_failed(self, error):
83 _moduleLogger.error(error)
85 @misc_utils.log_exception(_moduleLogger)
90 _moduleLogger.debug("Closing text")
91 self._conn.session.voicemails.updateSignalHandler.unregister_sink(
94 self._conn.session.texts.updateSignalHandler.unregister_sink(
97 self.__callback = None
99 tp.ChannelTypeText.Close(self)
100 self.remove_from_connection()
103 def _contactKey(self):
104 contactKey = self.__otherHandle.phoneNumber
107 @misc_utils.log_exception(_moduleLogger)
108 def _on_conversations_updated(self, conv, conversationIds):
109 if self._contactKey not in conversationIds:
111 _moduleLogger.debug("Incoming messages from %r for existing conversation" % (self._contactKey, ))
112 mergedConversations = conv.get_conversation(self._contactKey)
113 self._report_conversation(mergedConversations)
115 def _report_conversation(self, mergedConversations):
116 newConversations = mergedConversations.conversations
117 if not newConversations:
119 "No messages ended up existing for %r" % (self._contactKey, )
123 # Can't filter out messages in a texting conversation that came in
124 # before the last one sent because that creates a race condition of two
125 # people sending at about the same time, which happens quite a bit
126 newConversations = gvoice.conversations.filter_out_self(newConversations)
127 newConversations = self._filter_out_reported(newConversations)
128 newConversations = gvoice.conversations.filter_out_read(newConversations)
129 newConversations = list(newConversations)
130 if not newConversations:
132 "New messages for %r have already been read externally" % (self._contactKey, )
138 for newConversation in newConversations
139 for newMessage in newConversation.messages
140 if not gvoice.conversations.is_message_from_self(newMessage)
144 "How did this happen for %r?" % (self._contactKey, )
147 for newMessage in messages:
148 formattedMessage = self._format_message(newMessage)
149 self._report_new_message(formattedMessage)
151 for conv in newConversations:
154 def _format_message(self, message):
155 return " ".join(part.text.strip() for part in message.body)
157 def _report_new_message(self, message):
158 currentReceivedId = self.__nextRecievedId
159 timestamp = int(time.time())
160 type = telepathy.CHANNEL_TEXT_MESSAGE_TYPE_NORMAL
162 _moduleLogger.info("Received message from User %r" % self.__otherHandle)
163 self.Received(currentReceivedId, timestamp, self.__otherHandle, type, 0, message)
165 self.__nextRecievedId += 1