Copyright © 2008-2009 Collabora Ltd. Copyright © 2008-2009 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

(as a stable interface)

Observers monitor the creation of new channels. This functionality can be used for things like message logging. All observers are notified simultaneously.

Observers SHOULD NOT modify the state of a channel except via user interaction.

We want Observer UIs for file transfer channels (a progress bar for the transfer) to be able to have a Cancel button.

Observers MUST NOT carry out actions that exactly one process must take responsibility for (e.g. acknowledging Text messages, or carrying out the actual transfer in a file transfer channel).

Since arbitrarily many observers can be activated for each channel, it would not make sense for observers to do things that can only be done by one process (acknowledging Text messages, carrying out streaming for Call1 channels, doing the actual data transfer for file transfers, setting up the out-of-band connection for Tubes). The Handler is responsible for such tasks.

Handlers MAY, of course, delegate responsibility for these tasks to other processes (including those run as observers), but this MUST be done explicitly via a request from the Handler to the Observer.

Whenever a new channel is signalled, the channel dispatcher will notify all running or activatable observers whose ObserverChannelFilter property (possibly as cached in the .client file) indicates that they are interested in that channel.

Observers are activated for all channels in which they have registered an interest - incoming, outgoing or automatically created - although of course the ObserverChannelFilter property can be set to filter on the Requested property.

Because it might take time for an observer to become ready (for instance, a Text logger needs to wait until pending messages have been downloaded), the channel dispatcher must wait (up to some timeout) for all observers to return from ObserveChannel before letting anything destructive happen. Destructive things (e.g. acknowledging messages) are defined to be done by handlers, therefore HandleWith and Claim aren't allowed to succeed until all observers are ready.

Non-interactive approvers (for instance, to shoot down spam IM channels before the tray icon blinks at the user, or to grab a SASL channel before the user is prompted for a password) can be implemented as observers by following these steps:

  1. ObserveChannel() is called on the observer.
  2. The observer calls Claim() on the CDO.
  3. The observer then returns from ObserveChannel().
  4. Claim will return successfully if the channels were successfully claimed, or failure if someone else got there first.

Non-interactive approvers implemented as observers SHOULD also set DelayApprovers to TRUE so that other Approvers are not called on until all observers return from ObserveChannel. This gives non-interactive approvers a chance to claim the channels before Approvers are called.

A specification of the channels in which this observer is interested. The ObserveChannel method should be called by the channel dispatcher whenever the new channel in a NewChannel signal matches this description.

Only certain D-Bus types have useful semantics for matching like this, so only certain types are allowed:

Integers of all sizes, including byte (y, n, q, i, u, x, t)
Matched by numeric value, regardless of type (e.g. 42 as a 16-bit signed integer 'n' is considered equal to 42 as a 32-bit unsigned integer 'u')
Booleans (b)
Matched by equality in the obvious way; not considered equal to any other type
Strings (s)
Matched by equality in the obvious way; not considered equal to any other type
Object paths (o)
Matched by equality in the obvious way; not considered equal to any other type

This property never changes while the observer process owns its Client bus name. For activatable processes, the filter can change due to an upgrade - the channel dispatcher SHOULD observe changes to .client files using a mechanism like inotify.

Not allowing this property to change is a simplification, particularly for activatable processes (we reject the possibility that a process with a .client file, when activated, has a filter that differs from what its .client file said).

If an Observer wants to add extra channels to its list of interests at runtime, it can register an additional Client bus name (for instance, the im.telepathy.v1.Client.Empathy process with unique name :1.42 could additionally register im.telepathy.v1.Client.Empathy._1_42) with additional filters. To remove those filters, it can release the bus name; it could even re-claim the bus name immediately, with different filters.

The same principle is applied to Approvers and Handlers.

For observers that have a .client file, the channel dispatcher may discover this property from keys of the form "propertyname type", in groups in the .client file whose name is the name of this interface followed by .ObserverChannelFilter, a space and an ASCII decimal number starting from 0.

Values in the .client file are encoded in exactly the same way as the default-p keys in .manager files, as described in the ConnectionManager interface (but note that not all types supported in .manager files can appear in .client files).

For instance, a .client file for an observer that is only interested in Text channels, with CONTACT or ROOM handles, that were requested by a local client:

[im.telepathy.v1.Client]
Interfaces=im.telepathy.v1.Client.Observer;

[im.telepathy.v1.Client.Observer.ObserverChannelFilter 0]
im.telepathy.v1.Channel.ChannelType s=im.telepathy.v1.Channel.Type.Text
im.telepathy.v1.Channel.TargetEntityType u=1
im.telepathy.v1.Channel.Requested b=true

[im.telepathy.v1.Client.Observer.ObserverChannelFilter 1]
im.telepathy.v1.Channel.ChannelType s=im.telepathy.v1.Channel.Type.Text
im.telepathy.v1.Channel.TargetEntityType u=2
im.telepathy.v1.Channel.Requested b=true
When using telepathy-mission-control, version 5.4.0 or later is needed for this property to be useful.

If true, upon the startup of this observer, ObserveChannel will be called for every already existing channel matching its ObserverChannelFilter

When an activatable client having this property disappears from the bus and there are channels matching its ObserverChannelFilter, ObserveChannel will be called immediately to reactivate it again. Such clients should specify this property in their .client file as follows:

[im.telepathy.v1.Client.Observer]
Recover=true

This means that if an activatable Observer crashes, it will be restarted as soon as possible; while there is an unavoidable possibility that it will miss some events during this process (particularly Text messages), this window of event loss is kept to a minimum.

Non-activatable observers can't take advantage of this mechanism, but setting this property on a non-activatable observer does allow it to "catch up" on channels that are currently active at the time that it starts up.

When the ObserveChannel method is called due to observer recovery, the Observer_Info dictionary will contain one extra item mapping the key "recovering" to True.

Called by the channel dispatcher when a channel in which the observer has registered an interest are announced in a NewChannel signal.

The observer MUST NOT return from this method call until it is ready for a handler for the channel to run (which may change the channel's state).

The channel dispatcher must wait for observers to start up, to avoid the following race: text channel logger (observer) gets ObserveChannel, text channel handler gets HandleChannel channel handler starts up faster and acknowledges messages, logger never sees those messages.

The channel dispatcher SHOULD NOT change its behaviour based on whether this method succeeds or fails: there are no defined D-Bus errors for this method, and if it fails, this only indicates that an Observer is somehow broken.

The expected error response in the channel dispatcher is to log a warning, and otherwise continue as though this method had succeeded.

The Account with which the channel is associated. The well-known bus name to use is that of the AccountManager. The Connection with which the channel is associated. The well-known bus name to use can be derived from this object path by removing the leading '/' and replacing all subsequent '/' by '.'.

The Channel object. Its well-known bus name is the same as that of the Connection.

Properties of the channel, equivalent to the properties in Channel_Details.

The path to the ChannelDispatchOperation for this channel, or the special value '/' if there is no ChannelDispatchOperation (because the channel was requested, not incoming).

If the Observer calls Claim or HandleWith on the dispatch operation, it MUST be careful to avoid deadlock, since these methods cannot return until the Observer has returned from ObserveChannel.

This allows an Observer to Claim a channel without having to match up calls to this method with calls to AddDispatchOperation.

The ChannelRequests satisfied by this channel. If the same process is an Observer and a Handler, it can be useful to be given this information as soon as possible (it will also be passed to Handler.HandleChannel).

Additional information about this channel. Currently defined keys are:

recovering - b
True if ObserveChannel was called for an existing channel (due to the Recover property being True); False or omitted otherwise. This allows observers to distinguish between new channels (the normal case), and existing channels that were given to the observer in order to catch up on previous events (perhaps after a previous instance of the same observer crashed).

All defined keys for this dictionary are optional; observers MAY safely ignore any entry in this dictionary.

If true, the channel dispatcher will wait for ObserveChannel to return before calling Approver.AddDispatchOperation on appropriate Approvers.

This property SHOULD be false unless there is a reason why a channel should not be given to approvers. An example of this is if an Observer is also a Handler and wants to Claim a channel so that it becomes its handler and doesn't want any approver to be called, this property should be true.

Observers and Approvers should be called at the same time in normal operation (with this property set to false) to improve responsiveness. For example, if an incoming call appears, the approver should get the channel as fast as possible to show a dialog, but if an approver has to make round-trips to set itself up, then the approval of the channel is delayed. As a result, it is recommended for this property to remain false unless absolutely necessary.

For service-activatable clients, this property should be specified in the observer's .client file as follows:

[im.telepathy.v1.Client.Observer]
DelayApprovers=true