
Channels may be requested from the Channel Dispatcher or directly from a Connection object using the Requests interface.
Requesting a channel from the dispatcher will cause it to be handled like any other dispatched channel. This is the preferred way of requesting new channels.
Requesting a channel directly from the Connection will cause it to be ignored by the Channel Dispatcher, meaning that the requesting application must handle the channel itself.
Channels requested from the Channel Dispatcher will be dispatched via the same mechanism as an unrequested, incoming channel. This means that the best available application to handle the channel will be used.
Requesting channels through the Channel Dispatcher also allows the Dispatcher to try a different client if the first client fails to handle the channel.
If you wish to handle the request yourself, you can pass the D-Bus well-known name of your client as the preferred handler.
These interfaces provides two methods: CreateChannel and EnsureChannel. Both methods take the same parameter, a dictionary containing the desired properties for the channel.
CreateChannel will attempt to create a new channel with the requested properties. Depending on the protocol, some types of channels are exclusive, and only one such channel can exist at a time (e.g. a XMPP chatroom). If a second channel is requested, the error NotAvailable is returned.
Conversely, EnsureChannel will attempt to reuse an existing channel with the same properties wherever possible, else it will create a new channel. It's possible that another client is also utilising this channel.
Choosing when to always create a new channel, or when to use an existing channel can usually be deduced based on the function of the channel. If it would make sense to reuse an existing channel then use EnsureChannel, otherwise use CreateChannel.
EnsureChannel is usually used for Text, StreamedMedia and ContactList channels.
CreateChannel is usually used for FileTransfer, Tubes, RoomList and ContactSearch channels.
The properties argument for CreateChannel and EnsureChannel is a map of property names on the desired channel, and their values. In general every channel requires at least three channel properties: the type of channel we wish to create (ChannelType), the handle/id of the contact/room/list we wish to create a channel for (TargetHandle or TargetID) and the type of that handle (TargetHandleType). Specific channel types may require additional properties in order to be created, this is noted in the specification.
For example, to create a ContactList channel (this is the type of channel that is used to get a list of subscribed contacts from a service), we might provide a map like so:
| org.freedesktop.Telepathy.Channel.ChannelType | org.freedesktop.Telepathy.Channel.Type.ContactList |
| org.freedesktop.Telepathy.Channel.TargetHandleType | Handle_Type_List |
| org.freedesktop.Telepathy.Channel.TargetID | "subscribe" |
Anonymous channels are channels that do not connect to a remote (single) contact, room, list or group. For example, RoomList channels, or anonymous MUC chats (e.g. in MSN).
They are requested by giving a TargetHandleType of Handle_Type_None (you should not specify a TargetHandle for an anonymous channel).
When using the Requests interface to request a channel directly from a Connection, both EnsureChannel and CreateChannel return the object path of a channel that can be access on that Connection.
Using the Channel Dispatcher, requests might take some time (e.g. if the account has to be brought online), so you are instead returned a Channel Request Object, which is discussed further in Section 6.1.1 ― Channel Request Objects.
Channels requested via the Channel Dispatcher don't immediately return the newly created channel from calls to CreateChannel and EnsureChannel. This is because the specified Account may not be immediately ready to request a channel, and the D-Bus method call may time out before the channel is requested.
In the worst case, the specified Account for a request may be offline and have to be brought online by the Account Manager. The network connection may only connect on demand (common on mobile devices) and may have to be brought up before the account can be connected.
To solve this problem, the Channel Dispatcher returns Channel Request Objects, which implement the ChannelRequest interface. These objects are accessible via the Channel Dispatcher well-known bus name (org.freedesktop.Telepathy.ChannelDispatcher).
Channel Requests provide two signals: Succeeded and Failed. You should connect these two signals and then call the Proceed method to begin the request. If you do not call Proceed, the request will not begin.
There is also a Cancel method that will allow you to cancel a method up until the time it has been dispatched to a Channel Handler. The precise semantics of this method are provided in the Telepathy specification.
telepathy-python provides the telepathy.client.Channel class as a D-Bus proxy object. To construct this proxy you need to pass the connection's D-Bus service name and the path to the channel object.
telepathy.client.Channel can be inherited like any other Python class, so that you can pass around all of the methods and state relating to that channel as one object. This is shown in Example 6-1.
Table 6-1 shows the respective functions for calling CreateChannel and EnsureChannel using telepathy-glib.
| From the... | Method | telepathy-glib Function |
|---|---|---|
| Channel Dispatcher | CreateChannel | tp_cli_channel_dispatcher_call_create_channel |
| EnsureChannel | tp_cli_channel_dispatcher_call_ensure_channel | |
| Connection | CreateChannel | tp_cli_connection_interface_requests_call_create_channel |
| EnsureChannel | tp_cli_connection_interface_requests_call_ensure_channel |
Example 6-2 shows ensuring a channel directly from a Connection.
/* explicitly ask for the publish and subscribe contact lists * these will be announced by NewChannels, so we don't need * to handle their callbacks (this does mean we also can't * handle their errors) */ GHashTable *request = tp_asv_new ( TP_IFACE_CHANNEL ".ChannelType", G_TYPE_STRING, TP_IFACE_CHANNEL_TYPE_CONTACT_LIST, TP_IFACE_CHANNEL ".TargetHandleType", TP_TYPE_HANDLE, TP_HANDLE_TYPE_LIST, NULL); /* the 'publish' list */ tp_asv_set_string (request, TP_IFACE_CHANNEL ".TargetID", "publish"); tp_cli_connection_interface_requests_call_ensure_channel ( conn, -1, request, NULL, NULL, NULL, NULL); /* the 'subscribe' list */ tp_asv_set_string (request, TP_IFACE_CHANNEL ".TargetID", "subscribe"); tp_cli_connection_interface_requests_call_ensure_channel ( conn, -1, request, NULL, NULL, NULL, NULL); g_hash_table_destroy (request);
The TpChannel is used to work with channels in telepathy-glib. It also provides API to help use the Groups interface, that is present on many channels.
A TpChannel can either be created using tp_channel_new or tp_channel_new_from_properties. The latter is generally preferred as you can just pass in the returned property map, as shown in Example 6-3.
const char *type = tp_asv_get_string (map, TP_IFACE_CHANNEL ".ChannelType"); /* if this channel is a contact list, we want to know * about it */ if (!strcmp (type, TP_IFACE_CHANNEL_TYPE_CONTACT_LIST)) { TpChannel *channel = tp_channel_new_from_properties ( conn, object_path, map, &error); handle_error (error); tp_channel_call_when_ready (channel, channel_ready, NULL); }
The RequestChannel method has been deprecated and should only be used if compatibility is required with older Connection Managers that do not implement the Requests interface.
Some Connection Managers might not yet implement the Requests interface on their Connections. In these cases you can use the RequestChannel method on the Connection interface, but you do so at your own risk.
CreateChannel and EnsureChannel fix several flaws that were present in RequestChannel:
If you must call RequestChannel, you call it with the same three arguments required for all channels (channel type, handle type and handle). The Suppress_Handler argument should always be True. Example 6-4 shows how to do this.
self.conn[CONNECTION].RequestChannel(CHANNEL_TYPE_ROOM_LIST, HANDLE_TYPE_NONE, 0, True, reply_handler = self.got_roomlist, error_handler = self.error) # begin example.channel.roomlist.listrooms def got_roomlist(self, channel_path): print 'Got Roomlist Channel' channel = telepathy.client.Channel(self.conn.service_name, channel_path)
When requesting an anonymous channel with RequestChannel, a channel with handle type Handle_Type_None (as is the case in Example 6-4), pass the handle id 0.