1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
import logging
from telepathy.client import Connection
from telepathy.interfaces import (
CHANNEL_INTERFACE, CHANNEL_INTERFACE_GROUP,
CHANNEL_TYPE_TEXT)
from telepathy.constants import (
CHANNEL_GROUP_FLAG_CHANNEL_SPECIFIC_HANDLES,
CHANNEL_TEXT_MESSAGE_TYPE_NORMAL)
class TextChannelWrapper(object):
"""Wrap a telepathy Text Channel to make
usage simpler."""
def __init__(self, text_chan, conn, pservice):
"""Connect to the text channel"""
self._activity_cb = None
self._activity_close_cb = None
self._text_chan = text_chan
self._conn = conn
self._pservice = pservice
self._logger = logging.getLogger(
'minichat-activity.TextChannelWrapper')
self._signal_matches = []
m = self._text_chan[CHANNEL_INTERFACE].\
connect_to_signal(
'Closed', self._closed_cb)
self._signal_matches.append(m)
def send(self, text):
"""Send text over the Telepathy text channel."""
# XXX Implement CHANNEL_TEXT_MESSAGE_TYPE_ACTION
if self._text_chan is not None:
self._text_chan[CHANNEL_TYPE_TEXT].Send(
CHANNEL_TEXT_MESSAGE_TYPE_NORMAL, text)
def close(self):
"""Close the text channel."""
self._logger.debug('Closing text channel')
try:
self._text_chan[CHANNEL_INTERFACE].Close()
except:
self._logger.debug('Channel disappeared!')
self._closed_cb()
def _closed_cb(self):
"""Clean up text channel."""
self._logger.debug('Text channel closed.')
for match in self._signal_matches:
match.remove()
self._signal_matches = []
self._text_chan = None
if self._activity_close_cb is not None:
self._activity_close_cb()
def set_received_callback(self, callback):
"""Connect the function callback to the signal.
callback -- callback function taking buddy
and text args
"""
if self._text_chan is None:
return
self._activity_cb = callback
m = self._text_chan[CHANNEL_TYPE_TEXT].\
connect_to_signal(
'Received', self._received_cb)
self._signal_matches.append(m)
def handle_pending_messages(self):
"""Get pending messages and show them as
received."""
for id, timestamp, sender, type, flags, text \
in self._text_chan[CHANNEL_TYPE_TEXT].ListPendingMessages(
False):
self._received_cb(id, timestamp, sender, type, flags, text)
def _received_cb(self, id, timestamp, sender, type, flags, text):
"""Handle received text from the text channel.
Converts sender to a Buddy.
Calls self._activity_cb which is a callback
to the activity.
"""
if self._activity_cb:
buddy = self._get_buddy(sender)
self._activity_cb(buddy, text)
self._text_chan[
CHANNEL_TYPE_TEXT].AcknowledgePendingMessages([id])
else:
self._logger.debug(
'Throwing received message on the floor'
' since there is no callback connected. See '
'set_received_callback')
def set_closed_callback(self, callback):
"""Connect a callback for when the text channel
is closed.
callback -- callback function taking no args
"""
self._activity_close_cb = callback
def _get_buddy(self, cs_handle):
"""Get a Buddy from a (possibly channel-specific)
handle."""
# XXX This will be made redundant once Presence
# Service provides buddy resolution
# Get the Telepathy Connection
tp_name, tp_path = \
self._pservice.get_preferred_connection()
conn = Connection(tp_name, tp_path)
group = self._text_chan[CHANNEL_INTERFACE_GROUP]
my_csh = group.GetSelfHandle()
if my_csh == cs_handle:
handle = conn.GetSelfHandle()
elif group.GetGroupFlags() & \
CHANNEL_GROUP_FLAG_CHANNEL_SPECIFIC_HANDLES:
handle = group.GetHandleOwners([cs_handle])[0]
else:
handle = cs_handle
# XXX: deal with failure to get the handle owner
assert handle != 0
return self._pservice.get_buddy_by_telepathy_handle(
tp_name, tp_path, handle)
|