[telepathy-ashes/master] added ability to connect using a .account file. Streamed media still doesn't work.
David Laban (none)
dl325 at eee
Thu Sep 17 15:34:04 PDT 2009
---
ashes/tools/account.py | 57 ++++++++++++++++++
ashes/tools/echo_bot.py | 152 ++++++++++++++++++++++++++++++++---------------
2 files changed, 160 insertions(+), 49 deletions(-)
create mode 100644 ashes/tools/account.py
diff --git a/ashes/tools/account.py b/ashes/tools/account.py
new file mode 100644
index 0000000..bb9172c
--- /dev/null
+++ b/ashes/tools/account.py
@@ -0,0 +1,57 @@
+import telepathy
+from telepathy.interfaces import CONN_MGR_INTERFACE
+import dbus
+
+def parse_account(s):
+ lines = s.splitlines()
+ pairs = []
+ manager = None
+ protocol = None
+
+ for line in lines:
+ if not line.strip():
+ continue
+
+ k, v = line.split(':', 1)
+ k = k.strip()
+ v = v.strip()
+
+ if k == 'manager':
+ manager = v
+ elif k == 'protocol':
+ protocol = v
+ else:
+ if k not in ("account", "password"):
+ if v.lower() == "false":
+ v = False
+ elif v.lower() == "true":
+ v = True
+ else:
+ try:
+ v = dbus.UInt32(int(v))
+ except:
+ pass
+ pairs.append((k, v))
+
+ assert manager
+ assert protocol
+ return manager, protocol, dict(pairs)
+
+def read_account(path):
+ return parse_account(file(path).read())
+
+def connect(manager, protocol, account, ready_handler=None):
+ reg = telepathy.client.ManagerRegistry()
+ reg.LoadManagers()
+
+ mgr = reg.GetManager(manager)
+ conn_bus_name, conn_object_path = \
+ mgr[CONN_MGR_INTERFACE].RequestConnection(protocol, account)
+ return telepathy.client.Connection(conn_bus_name, conn_object_path,
+ ready_handler=ready_handler)
+
+def connection_from_file(path, ready_handler=None):
+ manager, protocol, account = read_account(path)
+ return connect(manager, protocol, account, ready_handler=ready_handler)
+
+
diff --git a/ashes/tools/echo_bot.py b/ashes/tools/echo_bot.py
index c78738c..608ef7d 100644
--- a/ashes/tools/echo_bot.py
+++ b/ashes/tools/echo_bot.py
@@ -1,7 +1,7 @@
import re
import time
import pdb
-import shiny
+import sys
import gobject
import gst
@@ -9,10 +9,14 @@ import dbus
import dbus.mainloop.glib
import telepathy
from telepathy.constants import HANDLE_TYPE_CONTACT
+sys.path.append('/usr/lib/python2.6/site-packages')
import tpfarsight
import farsight
+
+import shiny
from helper_functions import get_connections, green, red
+from account import connection_from_file
#TODO: wrap everything to 80 chars so that I can hack on my eeepc.
@@ -37,6 +41,10 @@ class ObjectListener(object):
return True
else:
return False
+
+ def __getitem__(self, iface):
+ """Enables InterfaceFactory gumph."""
+ return self.dbus_object[iface]
def connect_to_signal(self, iface_name, signal_name):
@@ -74,21 +82,34 @@ class ConnectionListener(ObjectListener):
can be done reliably using the __ prefix for members, and only writing one
signal handler per signal. If common functionality is needed in sister
classes, push it up to the parent class.
+
+ WARNING: connections are not guaranteed to be ready when this is initialised.
"""
CONNECTION = telepathy.interfaces.CONNECTION
def __init__(self, connection, contact_regexp='.*'):
"""
- contact_regexp is used in base classes to selectively echo only specific users.
+ contact_regexp is used in derived classes to selectively echo only specific users.
"""
+ self.init(connection, contact_regexp)
+
+ def init(self, connection, contact_regexp='.*'):
+ print "Listening to connection"
ObjectListener.__init__(self, connection)
- # I could use self.dbus_object, but connection everywhere, but
+ # I could use self.dbus_object everywhere, but
# self.connection is clearer.
self.connection = connection
self.contact_regexp = contact_regexp
self.channel_extra_args = [contact_regexp]
- connection.call_when_ready(self._register_callbacks)
-
+ self.connection.Connect()
+ connection.call_when_ready(self.finish_setup)
+ def finish_setup(self, *args):
+ """
+ Calls register_callbacks and ensures that the connection is connected.
+ """
+ print 'finishing setup'
+ self._register_callbacks(self.connection)
+ self.connection.Connect()
def _register_callbacks(self, conn):
"""
Registers callbacks for all signals provided by the connection.
@@ -135,7 +156,16 @@ class ConnectionListener(ObjectListener):
'org.freedesktop.DBus.Properties':
[],
}
-
+class Onlineifier(ConnectionListener):
+ """
+ Sets presence to online on setup
+ """
+ def finish_setup(self, *_args):
+ print "Setting status to online"
+ super(Onlineifier, self).finish_setup(*_args)
+ self.connection.Connect()
+ self.connection[self.SIMPLE_PRESENCE].SetPresence('available', '')
+
class ChannelDispatcher(ConnectionListener):
"""
Listens for Requests.NewChannels and Connection.NewChannel, creates a
@@ -170,11 +200,13 @@ class ChannelDispatcher(ConnectionListener):
return class_
return decorate
- def __init__(self, connection, contact_regexp='.*'):
- # FIXME: This should really be done only if there is a handler for this type.
- # It should also probably be done in some kind of setup function rather than
- # __init__ because I don't know what state the connection is in here.
- super(ChannelDispatcher, self).__init__(connection, contact_regexp)
+ def finish_setup(self, *conn):
+ """
+ Sets up super-classes recursively, then sets capabilities
+ FIXME: do this based on _handler_classes rather than hardcoded.
+ """
+ print "advertising streamed media caps"
+ super(ChannelDispatcher, self).finish_setup()
self.connection[telepathy.CONN_INTERFACE_CAPABILITIES].AdvertiseCapabilities(
[(telepathy.CHANNEL_TYPE_STREAMED_MEDIA, 0xff)], [])
@@ -218,10 +250,12 @@ class ChannelDispatcher(ConnectionListener):
if (channel_type, handle_type) in self._handler_classes:
handler_class = self._handler_classes[channel_type, handle_type]
- handler = handler_class(self, channel, properties, *self.channel_extra_args)
+ handler = handler_class(self, channel, properties)
channels.append(handler)
else:
- print "Don't know how to handle channel with handle type:", handle_type
+ print "Don't know how to handle channel with handle type:", handle_type,
+ print "and channel type", channel_type
+
class PresenceEchoer(ConnectionListener):
@@ -247,14 +281,14 @@ class PresenceEchoer(ConnectionListener):
"""Handles SimplePresence.PresencesChanged, and echoes it."""
#FIXME: This may cause a flood on connect. Should probably put a limit here.
for handle, presence in presences.items():
-
- (contact_string,) = self.connection.InspectHandles(HANDLE_TYPE_CONTACT, [handle])
+ type, status, message = presence
self_handle = self._get_self_handle()
- if (handle != self_handle and
- re.match(self.contact_regexp, contact_string)):
- type, status, message = presence
- new_message = self.identify(contact_string, message)
- self.connection[self.SIMPLE_PRESENCE].SetPresence(status, new_message)
+ if (type > 1 and handle != self_handle):
+ (contact_string,) = self.connection.InspectHandles(HANDLE_TYPE_CONTACT, [handle])
+
+ if re.match(self.contact_regexp, contact_string):
+ new_message = self.identify(contact_string, message)
+ self.connection[self.SIMPLE_PRESENCE].SetPresence(status, new_message)
def PresenceUpdate(self, presences):
"""
@@ -266,18 +300,22 @@ class PresenceEchoer(ConnectionListener):
#FIXME: This may cause a flood on connect. Should probably put a limit here.
for handle, presence in presences.items():
+ last_activity, statuses = presence
+ ((status, parameters),) = statuses.items()
- (contact_string,) = self.connection.InspectHandles(HANDLE_TYPE_CONTACT, [handle])
self_handle = self._get_self_handle()
- if (handle != self_handle and
- re.match(self.contact_regexp, contact_string)):
- last_activity, statuses = presence
- ((status, parameters),) = statuses.items()
- message = parameters.get('message', '')
- new_message = self.identify(contact_string, message)
- self.connection[self.PRESENCE].SetStatus({status: {'message': new_message}})
-
-class EchoBot(PresenceEchoer, ChannelDispatcher):
+ if (handle != self_handle and status != 'offline'):
+ (contact_string,) = self.connection.InspectHandles(HANDLE_TYPE_CONTACT, [handle])
+ if re.match(self.contact_regexp, contact_string):
+ message = parameters.get('message', '')
+ new_message = self.identify(contact_string, message)
+ self.connection[self.PRESENCE].SetStatus({status: {'message': new_message}})
+
+ at shiny.debug_class
+class EchoBot( PresenceEchoer,
+ ChannelDispatcher,
+ Onlineifier,
+ ):
"""
This class just mixes together functionality from PresenceEchoer and friends
into a nice tasty echo bot.
@@ -305,6 +343,8 @@ class ChannelListener(ObjectListener):
'StreamRemoved', 'StreamStateChanged',],
'org.freedesktop.Telepathy.Channel.Interface.Destroyable':
[],
+ 'org.freedesktop.Telepathy.Channel.Type.ContactList':
+ [],
'org.freedesktop.Telepathy.Channel.Interface.Messages':
['MessageSent', 'PendingMessagesRemoved', 'MessageReceived'],
'org.freedesktop.Telepathy.Channel':
@@ -349,6 +389,10 @@ class ChannelListener(ObjectListener):
+ at ChannelDispatcher.handler_for('org.freedesktop.Telepathy.Channel.Type.ContactList',
+ telepathy.HANDLE_TYPE_LIST)
+class ContactAcceptor(ChannelListener):
+ pass
@ChannelDispatcher.handler_for('org.freedesktop.Telepathy.Channel.Type.Text',
telepathy.HANDLE_TYPE_CONTACT)
@@ -356,7 +400,7 @@ class TextChannelEchoer(ChannelListener):
"""
Listens to a text channel and echoes everything with id and timestamp etc.
"""
- def __init__(self, connection, channel, properties, contact_regexp):
+ def __init__(self, connection, channel, properties):
ChannelListener.__init__(self, connection, channel, properties)
self.contact_string = properties['org.freedesktop.Telepathy.Channel.TargetID']
print green('Text Channel Handled.')
@@ -383,7 +427,7 @@ class MediaChannelEchoer(ChannelListener):
"""
Listens to a media channel and echoes everything it hears/sees.
"""
- def __init__(self, connection, channel, properties, contact_regexp):
+ def __init__(self, connection, channel, properties):
ChannelListener.__init__(self, connection, channel, properties)
print green('Media Channel Handled.')
self.tfchannel = tpfarsight.Channel(self.connection.service_name,
@@ -515,6 +559,7 @@ channels = []
def run_echo_service(conn, contact_regexp):
"""
Runs the echo service unless it's already running.
+ Also helpfully appends it to connections and returns that.
"""
if conn in connections:
#note: requires patch to dbus-python which implements __eq__
@@ -524,22 +569,14 @@ def run_echo_service(conn, contact_regexp):
bot = EchoBot(conn, contact_regexp)
assert bot == conn # so that 'if conn in connections:' works.
connections.append(bot)
-
-def connection_callback_factory(connection_regexp, contact_regexp):
- """
- Creates callbacks for passing into telepathy.client.Connection as
- ready_handler. Generated callbacks only handle connections matching
- connection_regexp. The resulting echo service only echoes events caused by
- contacts with InspectHandles() matching contact_regexp.
- """
- def connection_callback(conn):
- if re.match(connection_regexp, conn.service_name):
- run_echo_service(conn, contact_regexp)
- else:
- print conn.service_name, "does not match", connection_regexp
- return connection_callback
+ return connections
+
+
+
-def main(connection_regexp='.*echo123.*', contact_regexp='.*'):
+def main(connection_regexp='.*echo123.*',
+ contact_regexp='.*',
+ account_file=''):
"""
This program will look on the bus for a connection object which matches
connection_regexp.
@@ -549,8 +586,19 @@ def main(connection_regexp='.*echo123.*', contact_regexp='.*'):
dmainloop = dbus.mainloop.glib.DBusGMainLoop()
dbus.set_default_main_loop(dmainloop)
regexp = re.compile(connection_regexp)
- cb = connection_callback_factory(connection_regexp, contact_regexp)
- get_connections(ready_handler=cb)
+
+ if account_file:
+ print 'Creating connection'
+ connection = connection_from_file(account_file)
+ run_echo_service(connection, contact_regexp)
+ else:
+ connections_ = get_connections()
+
+ for connection in connections_:
+ if re.match(connection_regexp, connection.service_name):
+ run_echo_service(connection, contact_regexp)
+ else:
+ print conn.service_name, "does not match", connection_regexp
while mainloop.is_running():
print 'running'
@@ -558,6 +606,12 @@ def main(connection_regexp='.*echo123.*', contact_regexp='.*'):
mainloop.run()
except KeyboardInterrupt:
gobject.idle_add(quit)
+ if account_file:
+ # If we set it up we should probably take it down.
+ assert connections
+ assert len(connections) == 1
+ connections[0][telepathy.CONN_INTERFACE].Disconnect()
+ account_file = None
print 'done\n\n'
--
1.5.6.5
More information about the telepathy-commits
mailing list