Handles in Telepathy are used to represent various protocol resources, for example contacts, chatrooms, contact lists and user-defined groups. A Handle is simply a numeric id allocated by the connection. Each handle has a type (Handle_Type) that defines the sort of handle it is. The same numeric handle id can be given for different handle types and different connections. The tuple of (connection, handle type, handle) is guarenteed unique.
Every handle is associated with a string identifier, e.g. the contact email@example.com. The strings are normalised per the rules of the protocol. For example, if a protocol considers contact identifiers to be case insensitive the strings "firstname.lastname@example.org" and "Bob@Example.com" would resolve to the same handle. These handles can be tested for integer equality to determine this is in fact the same identifier.
Identifier normalisation rules can be complex and subtle. A Telepathy client should never attempt to do any normalisation of string identifiers. Nor should it compare string identifiers for equality.
Instead handles should be requested for the identifiers (via RequestHandles) and the handles compared for integer equality. If the normalised string is desired (e.g. for display), this can be accessed via the InspectHandles method call.
The handle id 0 is never a valid handle for an identifier, but may be used some places in the API to indicate a special condition. (Handle_Type_None, 0) is referred to as the anonymous handle, and also has special meaning.
The lifetime of handles is managed by each connection based on the currently open channels. For example, each contact in a channel has an associated handle. If no client has a hold on a handle, and that contact leaves all channels, the handle will cease to be valid.
Telepathy clients can keep handles around longer using the HoldHandles method. Unlike with reference counting, the HoldHandles method is idempotent, meaning that calling it multiple times is equivalent to calling it once. Instead of calling HoldHandles, clients can instead pass True to the Hold parameter of Contacts.GetContactAttributes.
A handle can be requested directly by its identifier using the RequestHandles method. This method is most commonly used when the user directly provides the identifier of a resource (e.g. the name of a chatroom) to access. The handle returned by RequestHandles is already held.
When a client is finished with a handle, it can be released with ReleaseHandles. This doesn't neccesarily mean the handle will instantly become invalid, it could still be referenced internally by the connection, but it could become invalid at any time.
The HoldHandles D-Bus method is idempotent. A single call to ReleaseHandles indicates that a client is no longer interested in a handle, no matter how many times HoldHandles or equivalent were called. If required, it is up to the client to implement some form of reference counting for handles.
Some language bindings however, may provide reference counting.
Method calls like Group.GetAllMembers return a list of handles, but do not hold any of the handles for the client. Thus, if a contact leaves the channel (e.g. goes offline), it is possible for the handle to become invalid in between the reply, and the next request using those handles. It is important that clients be aware of this possible race condition and handle it appropriately. For this reason, method calls like GetContactAttributes do not return the InvalidHandle error if one of the handles has already ceased to exist. Clients should listen to the appropriate signals (e.g. Group.MembersChangedDetailed) to determine if that handle has been made invalid in the intervening time.
The use of HoldHandles and ReleaseHandles is less necessary when using telepathy-glib, because it automatically holds handles for the lifetime of its objects, e.g. TpContact. When the object is destroyed its handle will be dropped.
Additionally, telepathy-glib wraps the HoldHandles and ReleaseHandles D-Bus methods with the tp_connection_hold_handles and tp_connection_unref_handles functions which reference-count the client-side handle "hold". This requires you to match each call of tp_connection_hold_handles with a matching call to tp_connection_unref_handles, similar to other reference counted resources.