Contact Lists

The ContactList channel type provides a list of people on the server, such as the contacts in a chat room, or the contacts to whose presence information you are subscribed.

Like individual remote contacts themselves, lists of remote contacts is referred to by numeric handle of type Handle_Type_List (for server defined lists) or Handle_Type_Group (for a user defined list of contacts). The handle can be retrieved using the RequestHandles method on the Connection.

To request a contact list, three properties must be provided to EnsureChannel (see Section 6.1 ― Requesting Channels): the channel type (org.freedesktop.Telepathy.Channel.Type.ContactList), the target handle type (either Handle_Type_List or Handle_Type_Group) and either a target handle retrieved by RequestHandles or the ID. Example 6-8 shows a code example.

Example 6-7Example Maps For Requesting a Contact List
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"
org.freedesktop.Telepathy.Channel.ChannelType org.freedesktop.Telepathy.Channel.Type.ContactList
org.freedesktop.Telepathy.Channel.TargetHandleType Handle_Type_List
org.freedesktop.Telepathy.Channel.TargetHandle <handle>
org.freedesktop.Telepathy.Channel.ChannelType org.freedesktop.Telepathy.Channel.Type.ContactList
org.freedesktop.Telepathy.Channel.TargetHandleType Handle_Type_Group
org.freedesktop.Telepathy.Channel.TargetHandle <handle>
Example 6-8Setting Up a Channel for a ContactList
print "Ensuring channel to %s..." % group
conn[CONNECTION_INTERFACE_REQUESTS].EnsureChannel({
    CHANNEL + '.ChannelType'     : CHANNEL_TYPE_CONTACT_LIST,
    CHANNEL + '.TargetHandleType': HANDLE_TYPE_LIST,
    CHANNEL + '.TargetID'        : group,
    },
    reply_handler = ensure_channel_cb(self, group),
    error_handler = no_channel_available)

Complete Source Code

Gaining access to the contacts listed in a contact list is actually achieved using the Channel's Group interface, which all ContactList objects implement. See Section 6.4 ― Contact Groups.

6.3.1. Server Defined Lists

A particular messaging protocol will likely provide a number of contact lists to a client, e.g. the list of subscribed contacts. These are the server defined lists (Handle_Type_List).

Telepathy provides for several server-defined lists, but not all of them may be implemented by a given protocol, or even a given version of a protocol server. If you attempt to open a channel for a list that doesn't exists, an error will be returned. This error is not fatal, it simply means that list doesn't exist.

Telepathy knows about the following server-defined lists:

subscribe

the group of contacts for whom you receive presence

publish

the group of contacts who may receive your presence

hide

a group of contacts who are on the publish list but are temporarily disallowed from receiving your presence

allow

a group of contacts who may send you messages

deny

a group of contacts who may not send you messages

stored

on protocols where the user's contacts are stored, this contact list contains all stored contacts regardless of subscription status

6.3.2. Subscription

Subscription to and from another user's presence is handled via the the subscribe and publish contact lists.

The subscribe list is the list of contacts for whom you receive, or would like to receive, presence information. This list is split into two sub-lists: members, contacts who's presence you receive; and remote pending, contacts who's presence you've requested but is pending approval.

The publish list is the list of contacts for whom you make available, or are requesting, presence information. This list is also split into two sub-lists: members, contacts to whom you show your presence; and local pending, contacts who are requesting your presence, pending your approval.

Table 6-3 summarises these lists.

Table 6-3Summary of Subscription Lists
Contact List Sub List Description
subscribe members Contacts who provide you their presence. You will receive valid presence information for these contacts.
remote pending Contacts who's presence you've requested, but subscription is pending their approval.
publish members Contacts to whom you provide your presence. These contacts will receive your presence information.
local pending Contacts who have requested your presence, but are pending your approval.

6.3.2.1. Subscribing a Contact

To subscribe a contact, you call AddMembers on the subscribe contact list, giving the Handles of the contacts you wish to subscribe. MembersChanged will then by signalled with these Handles appearing in remote-pending-added.

When the remote user accepts or declines your request MembersChanged will be emitted again. If your request is accepted, their handle will appear in added; if your request is declined, their handle will appear in removed.

If the remove user accepts your request, their client will likely make a subscription request back to you, see below.

6.3.2.2. Handling a Subscription Request

Incoming subscription requests are notified by the MembersChanged signal on the publish contact list, with Handles appearing in local-pending-added.

The client can then present this subscription request to the user to accept or decline (alternatively, many clients will auto-accept who is already a member of the subscribe list).

If the user accepts the request, call AddMembers with the remote contact's Handle. If the user declines the request, call RemoveMembers.

When you, or another Telepathy client, accepts or declines the subscription request MembersChanged will be emitted. If the request has been accepted, the contact will appear in added; if the request has been declined, the contact will appear in removed. It is important to watch for another client handling the request before yours does and to cancel your question to the user.

If your client accepts the subscription, and the remote contact isn't a member of subscribe, you probably want to add them, see above.

6.3.3. User Defined Groups

User-defined groups are the groups that a user places their contacts into. Not all protocols may support the concept of user-defined groups. In some protocols (e.g. XMPP) a contact may possibly be in more than one group.

Channels will be set up for user-defined groups as they are discovered by the connection. Thus the currently configured groups can be discovered at any time by checking the Channels property or connecting to the NewChannels signal on the Requests interface (see Section 6.2.2 ― The NewChannels Signal).

This returns a list of Channel_Details, which gives the channel object and a map of properties for the channel. This map always contains the properties Channel.ChannelType, Channel.TargetHandleType, Channel.TargetHandle, Channel.TargetID, and Channel.Requested. Filtering on Channel.ChannelType equals Channel.Type.ContactList and Channel.TargetHandleType equals Handle_Type_Group will yield the user-defined contact groups (demonstrated in Example 6-9).

Example 6-9Filtering NewChannels
static void
new_channels_cb (TpConnection *conn,
    const GPtrArray *channels,
    gpointer user_data,
    GObject *weak_obj)
{
  int i;
  GError *error = NULL;

  /* @channels has the D-Bus type a(oa{sv}), which decomposes to:
   *  - a GPtrArray containing a GValueArray for each channel
   *  - each GValueArray contains
   *     - an object path
   *     - an a{sv} map
   */
  for (i = 0; i < channels->len; i++)
    {
      GValueArray *channel = g_ptr_array_index (channels, i);
      char *object_path;
      GHashTable *map;

      const char *channel_type, *target_id;
      int handle_type;

      tp_value_array_unpack (channel, 2,
          &object_path,
          &map);

      channel_type = tp_asv_get_string (map, TP_PROP_CHANNEL_CHANNEL_TYPE);
      handle_type = tp_asv_get_uint32 (map, TP_PROP_CHANNEL_TARGET_HANDLE_TYPE,
          NULL);
      target_id = tp_asv_get_string (map, TP_PROP_CHANNEL_TARGET_ID);

      /* ensure this channel is a contact group */
      if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_CONTACT_LIST) &&
          handle_type == TP_HANDLE_TYPE_GROUP)
        {
          g_print ("Got user-defined contact group: %s\n", target_id);
        }
    }
}

Complete Source Code