Message Tutorial Example

This is example-text.py referred to by the DTube Tutorial; hopefully one day there will also be a Message Tutorial which may use a variant on this example...

import dbus, gobject, telepathy
import dbus.glib # sets up a main loop (!!!); somewhat deprecated


from telepathy.constants import (
    CONNECTION_HANDLE_TYPE_CONTACT, CONNECTION_HANDLE_TYPE_LIST,
    CHANNEL_TEXT_MESSAGE_TYPE_NORMAL)
from telepathy.interfaces import (
    CHANNEL_INTERFACE_GROUP, CHANNEL_TYPE_CONTACT_LIST, 
    CHANNEL_TYPE_TEXT,
    CONN_INTERFACE)

class Example:
    def __init__(self, conn):
        self.conn = conn
        self.buddies = []

    def get_roster(self):
        for name in ('subscribe', 'publish', 'hide', 'allow', 'deny', 'known'):
            try:
                handle = self.conn[CONN_INTERFACE].RequestHandles(
                    CONNECTION_HANDLE_TYPE_LIST, [name])[0]
                chan=self.conn.request_channel(
                    CHANNEL_TYPE_CONTACT_LIST, CONNECTION_HANDLE_TYPE_LIST,
                    handle, True)
            except dbus.DBusException:
                print "'%s' channel is not available" % name
                continue

            current, local_pending, remote_pending = (
                chan[CHANNEL_INTERFACE_GROUP].GetAllMembers())

            print '%s:'%name
            members = self.conn[CONN_INTERFACE].InspectHandles(
                        CONNECTION_HANDLE_TYPE_CONTACT, current)
            for member, member_h in zip(members, current):
                print ' - %s (%d)' % (member, member_h)
                self.buddies.append((member, member_h))

            if not current:
                print ' (none)'

            # Note: in a real application, connecting to this signal should
            # be done before calling GetAllMembers(), so that the race
            # condition is the right way around.
            def make_handler(chname):
                return lambda *args: self.members_changed_cb(chname, *args)
            chan[CHANNEL_INTERFACE_GROUP].connect_to_signal('MembersChanged',
                                                        make_handler(name))

    def members_changed_cb(self, name, message, added, removed, local_pending,
            remote_pending, actor, reason):
        if added:
            for handle in added:
                member = self.conn[CONN_INTERFACE].InspectHandles(
                    CONNECTION_HANDLE_TYPE_CONTACT, [handle])[0]
                print '%s: added: %s' % (name, member)

        if removed:
            for handle in removed:
                member = self.conn[CONN_INTERFACE].InspectHandles(
                    CONNECTION_HANDLE_TYPE_CONTACT, [handle])[0]
                print '%s: removed: %s' % (name, member)

    def contact(self, buddy_h):
        channel = self.conn.request_channel(
            CHANNEL_TYPE_TEXT, CONNECTION_HANDLE_TYPE_CONTACT, buddy_h, True)

        #print 'got text channel with handle (%d,%d)' % (handle_type, handle)
        #channel = telepathy.client.channel.Channel(self.conn.service_name, object_path)

        channel[CHANNEL_TYPE_TEXT].connect_to_signal('Sent', self.sent_cb)
        channel[CHANNEL_TYPE_TEXT].connect_to_signal('Received', self.recvd_cb)
        channel[CHANNEL_TYPE_TEXT].connect_to_signal('SendError',
            self.send_error_cb)

        channel[CHANNEL_TYPE_TEXT].Send(
            CHANNEL_TEXT_MESSAGE_TYPE_NORMAL, 'Hi there!')

        for message in channel[CHANNEL_TYPE_TEXT].ListPendingMessages(True):
            self.recvd_cb(*message)

    def recvd_cb(self, *args):
        print args
        id, timestamp, sender, type, flags, text = args
        print 'message #%d received from handle %d: """%s"""' \
                % (id, sender, text)

    def sent_cb(self, timestamp, type, text):
        print 'message sent: """%s"""' % text
        # if we Disconnect() immediately, the message might not actually
        # make it to the network before the socket is shut down (this can
        # be the case in Gabble) - as a workaround, delay before disconnecting

    def send_error_cb(self, error, timestamp, type, text):
        print 'error sending message: code %d' % error

    def request_channel_error_cb(self, exception):
        print 'error:', exception

def select_buddy(buddies):
    for buddy, buddy_h in buddies:
        if 'alice@' in buddy or 'bob@' in buddy:
            return buddy, buddy_h
    print "Didn't find alice or bob in buddy list! Aborting..."
    sys.exit(0)

if __name__ == '__main__':
    bus = dbus.SessionBus()

    mc = bus.get_object('org.freedesktop.Telepathy.MissionControl',
                        '/org/freedesktop/Telepathy/MissionControl')
    for conn in mc.GetOnlineConnections():
        print conn
        conn = telepathy.client.Connection(*mc.GetConnection(conn))
        #print c2.Introspect()
        #print dir(conn)

        client = Example(conn)

        # get list of buddies:
        client.get_roster()
        # select a buddy:
        buddy, buddy_h = select_buddy(client.buddies)
        print "Contacting %s"%buddy
        client.contact(buddy_h)

    try:
        gobject.MainLoop().run()
    except KeyboardInterrupt:
        print 'interrupted'