## TpBaseChannel

TpBaseChannel — base class for TpExportableChannel implementations

## Synopsis

    #include <telepathy-glib/telepathy-glib.h>

                        TpBaseChannel;
    struct              TpBaseChannelClass;
    void                (*TpBaseChannelFillPropertiesFunc)  (TpBaseChannel *chan,
                                                             GHashTable *properties);
    void                (*TpBaseChannelCloseFunc)           (TpBaseChannel *chan);
    gchar *             (*TpBaseChannelGetPathFunc)         (TpBaseChannel *chan);
    GPtrArray *         (*TpBaseChannelGetInterfacesFunc)   (TpBaseChannel *chan);
    void                tp_base_channel_register            (TpBaseChannel *chan);
    void                tp_base_channel_close               (TpBaseChannel *chan);
    void                tp_base_channel_destroyed           (TpBaseChannel *chan);
    void                tp_base_channel_reopened            (TpBaseChannel *chan,
                                                             TpHandle initiator);
    void                tp_base_channel_disappear           (TpBaseChannel *chan);
    void                tp_base_channel_reopened_with_requested
                                                            (TpBaseChannel *chan,
                                                             gboolean requested,
                                                             TpHandle initiator);
    const gchar *       tp_base_channel_get_object_path     (TpBaseChannel *chan);
    TpBaseConnection *  tp_base_channel_get_connection      (TpBaseChannel *chan);
    TpHandle            tp_base_channel_get_self_handle     (TpBaseChannel *chan);
    TpHandle            tp_base_channel_get_target_handle   (TpBaseChannel *chan);
    TpHandle            tp_base_channel_get_initiator       (TpBaseChannel *chan);
    gboolean            tp_base_channel_is_requested        (TpBaseChannel *chan);
    gboolean            tp_base_channel_is_registered       (TpBaseChannel *chan);
    gboolean            tp_base_channel_is_destroyed        (TpBaseChannel *chan);
    gboolean            tp_base_channel_is_respawning       (TpBaseChannel *chan);

## Object Hierarchy

      GObject
       +----TpBaseChannel
             +----TpBaseCallChannel
             +----TpBasePasswordChannel

## Implemented Interfaces

TpBaseChannel implements TpSvcDBusProperties, TpSvcChannel, TpChannelIface and TpExportableChannel.

## Properties

      "connection"               TpBaseConnection*     : Read / Write / Construct Only
      "initiator-handle"         guint                 : Read / Write / Construct Only
      "initiator-id"             gchar*                : Read
      "interfaces"               GStrv                 : Read
      "requested"                gboolean              : Read / Write / Construct Only
      "target-id"                gchar*                : Read

## Description

This base class makes it easier to write TpExportableChannel implementations by implementing some of its properties, and defining other relevant properties.

Subclasses should fill in TpBaseChannelClass.channel_type and TpBaseChannelClass.target_handle_type; and implement the TpBaseChannelClass.get_interfaces and TpBaseChannelClass.close virtual functions.

If the channel type and/or interfaces being implemented define immutable D-Bus properties besides those on the Channel interface, the subclass should implement the TpBaseChannelClass.fill_immutable_properties virtual function.

If the "object-path" property is not set at construct time, the TpBaseChannelClass.get_object_path_suffix virtual function will be called to determine the channel's path, whose default implementation simply generates a unique path based on the object's address in memory.

TpBaseChannel also has the ability to remove the channel from the bus, but keep the object around. To close the channel and remove it from the bus, subclasses should call `tp_base_channel_disappear()`. To bring the channel back, subclasses use `tp_base_channel_reopened_with_requested()` and the channel should be re-announced with `tp_channel_manager_emit_new_channel()`. Note that channels which can disappear but can also reopen due to pending messages need special casing by the channel manager:

    static void
    channel_closed_cb (TpBaseChannel *chan,
        TpChannelManager *manager)
    {
      MyChannelManager *self = MY_CHANNEL_MANAGER (manager);
      TpHandle handle = tp_base_channel_get_target_handle (chan);

      // first, emit ChannelClosed if the channel is registered (it
      // won't be registered if it is appearing from being hidden, so
      // let's not emit the signal in this case)
      if (tp_base_channel_is_registered (chan))
        {
          tp_channel_manager_emit_channel_closed (manager,
              TP_EXPORTABLE_CHANNEL (chan));
        }

      if (tp_base_channel_is_destroyed (chan))
        {
          // destroyed() must have been called; forget this channel
          g_hash_table_remove (self->priv->channels, handle);
        }
      else if (tp_base_channel_is_respawning (chan))
        {
          // reopened_with_requested() must have been called; re-announce the channel
          tp_channel_manager_emit_new_channel (manager, TP_EXPORTABLE_CHANNEL (chan));
        }
      else
        {
          // disappear() must have been called, do nothing special
        }
    }

and the TpChannelManagerIface.foreach_channel virtual function should be updated to only include registered channels:

    static void
    foreach_channel (TpChannelManager *manager,
        TpChannelManagerChannelClassFunc func,
        gpointer user_data)
    {
      MyChannelManager *self = MY_CHANNEL_MANAGER (manager);
      GHashTableIter iter;
      gpointer chan;

      g_hash_table_iter_init (&iter, self->priv->channels);
      while (g_hash_table_iter_next (&iter, NULL, &chan))
        {
          if (tp_base_channel_is_registered (TP_BASE_CHANNEL (chan)))
            func (TP_EXPORTABLE_CHANNEL (chan), user_data);
        }
    }

## Details

### TpBaseChannel

    typedef struct _TpBaseChannel TpBaseChannel;

A base class for channel implementations

Since 0.11.14

### struct TpBaseChannelClass

    struct TpBaseChannelClass {
      TpDBusPropertiesMixinClass dbus_props_class;

      const gchar *channel_type;
      TpHandleType target_handle_type;

      TpBaseChannelCloseFunc close;
      TpBaseChannelFillPropertiesFunc fill_immutable_properties;
      TpBaseChannelGetPathFunc get_object_path_suffix;
      TpBaseChannelGetInterfacesFunc get_interfaces;
    };

The class structure for TpBaseChannel

TpDBusPropertiesMixinClass `dbus_props_class`; | The class structure for the DBus properties mixin
const gchar *`channel_type`; | The type of channel that instances of this class represent (e.g. TP_IFACE_CHANNEL_TYPE_TEXT)
TpHandleType `target_handle_type`; | The type of handle that is the target of channels of this type
TpBaseChannelCloseFunc `close`; | A virtual function called to close the channel, which will be called by `tp_base_channel_close()` and by the implementation of the Closed D-Bus method.
TpBaseChannelFillPropertiesFunc `fill_immutable_properties`; | A virtual function called to add custom properties to the DBus properties hash. Implementations must chain up to the parent class implementation and call `tp_dbus_properties_mixin_fill_properties_hash()` on the supplied hash table

TpBaseChannelGetPathFunc `get_object_path_suffix`;

Returns a string that will be appended to the Connection objects's object path to get the Channel's object path. This function will only be called as a fallback if the "object-path" property is not set. The default implementation simply generates a unique path based on the object's address in memory. The returned string will be freed automatically.

TpBaseChannelGetInterfacesFunc `get_interfaces`; | Extra interfaces provided by this channel (this SHOULD NOT include the channel type and interface itself). Implementation must first chainup on parent class implementation and then add extra interfaces into the GPtrArray. Replaces `interfaces`.

Since 0.11.14

### TpBaseChannelFillPropertiesFunc ()

    void                (*TpBaseChannelFillPropertiesFunc)  (TpBaseChannel *chan,
                                                             GHashTable *properties);

Signature of an implementation of the TpBaseChannelClass.fill_immutable_properties virtual function. A typical implementation, for a channel implementing TpSvcChannelTypeContactSearch, would be:

    static void
    my_search_channel_fill_properties (
        TpBaseChannel *chan,
        GHashTable *properties)
    {
      TpBaseChannelClass *klass = TP_BASE_CHANNEL_CLASS (my_search_channel_parent_class);

      klass->fill_immutable_properties (chan, properties);

      tp_dbus_properties_mixin_fill_properties_hash (
          G_OBJECT (chan), properties,
          TP_IFACE_CHANNEL_TYPE_CONTACT_SEARCH, "Limit",
          TP_IFACE_CHANNEL_TYPE_CONTACT_SEARCH, "AvailableSearchKeys",
          TP_IFACE_CHANNEL_TYPE_CONTACT_SEARCH, "Server",
          NULL);
    }

Note that the SearchState property is not added to `properties`, since only immutable properties (whose value cannot change over the lifetime of `chan`) should be included.

`chan` : | a channel
`properties` : | a dictionary of `chan`'s immutable properties, which the implementation may add to using `tp_dbus_properties_mixin_fill_properties_hash()`

Since 0.11.14

### TpBaseChannelCloseFunc ()

    void                (*TpBaseChannelCloseFunc)           (TpBaseChannel *chan);

Signature of an implementation of the TpBaseChannelClass.close virtual function. Implementations should eventually call either `tp_base_channel_destroyed()` if the channel is really closed as a result, or `tp_base_channel_reopened()` if the channel will be re-spawned (for instance, due to unacknowledged messages on a text channel), but need not do so before returning. Note that channels that support re-spawning must also implement TpSvcChannelInterfaceDestroyable.

Implementations may assume that `tp_base_channel_is_destroyed()` is FALSE for `chan` when called. Note that if this function is implemented asynchronously, it may be called more than once. A subclass which needs to perform some asynchronous clean-up in order to close might implement this function as follows:

    static void
    my_channel_close (TpBaseChannel *chan)
    {
      MyChannel *self = MY_CHANNEL (chan);

      if (self->priv->closing)
        return;

      self->priv->closing = TRUE;

      // some hypothetical channel-specific clean-up function:
      clean_up (self, cleaned_up_cb);
    }

    static void
    cleaned_up_cb (MyChannel *self)
    {
      // all done, we can finish closing now
      tp_base_channel_destroyed (TP_BASE_CHANNEL (self));
    }
    static void
    my_channel_class_init (MyChannelClass *klass)
    {
      TpBaseChannelClass *base_channel_class = TP_BASE_CHANNEL_CLASS (klass);

      klass->close = my_channel_close;
      // ...
    }

If a subclass does not need to do anything to clean itself up, it may implement TpBaseChannelClass.close using `tp_base_channel_destroyed()` directly:

    static void
    my_channel_class_init (MyChannelClass *klass)
    {
      TpBaseChannelClass *base_channel_class = TP_BASE_CHANNEL_CLASS (klass);

      klass->close = tp_base_channel_destroyed;
      // ...
    }

`chan` : | a channel

Since 0.11.14

### TpBaseChannelGetPathFunc ()

    gchar *             (*TpBaseChannelGetPathFunc)         (TpBaseChannel *chan);

Signature of an implementation of the TpBaseChannelClass.get_object_path_suffix virtual function.

`chan` : | a channel
Returns : | a string that will be appended to the Connection objects's object path to get the Channel's object path. [transfer full]

Since 0.11.14

### TpBaseChannelGetInterfacesFunc ()

    GPtrArray *         (*TpBaseChannelGetInterfacesFunc)   (TpBaseChannel *chan);

Signature of an implementation of TpBaseChannelClass.get_interfaces virtual function.

Implementation must first chainup on parent class implementation and then add extra interfaces into the GPtrArray.

    static GPtrArray *
    my_channel_get_interfaces (TpBaseChannel *self)
    {
      GPtrArray *interfaces;

      interfaces = TP_BASE_CHANNEL_CLASS (my_channel_parent_class)->get_interfaces (self);

      g_ptr_array_add (interfaces, TP_IFACE_BADGERS);

      return interfaces;
    }

`chan` : | a channel
Returns : | a GPtrArray of static strings for D-Bus interfaces implemented by this client. [transfer container]

Since 0.17.5

### tp_base_channel_register ()

    void                tp_base_channel_register            (TpBaseChannel *chan);

Make the channel appear on the bus. "object-path" must have been set to a valid path, which must not already be in use as another object's path.

`chan` : | a channel

Since 0.11.14

### tp_base_channel_close ()

    void                tp_base_channel_close               (TpBaseChannel *chan);

Asks `chan` to close, just as if the Close D-Bus method had been called. If "channel-destroyed" is TRUE, this is a no-op.

Note that, depending on the subclass's implementation of TpBaseChannelClass.close and internal behaviour, this may or may not be a suitable method to use during connection teardown. For instance, if the channel may respawn when Close is called, an equivalent of the Destroy D-Bus method would be more appropriate during teardown, since the intention is to forcibly terminate all channels.

`chan` : | a channel

Since 0.11.14

### tp_base_channel_destroyed ()

    void                tp_base_channel_destroyed           (TpBaseChannel *chan);

Called by subclasses to indicate that this channel was destroyed and can be removed from the bus. The "Closed" signal will be emitted and the "channel-destroyed" property will be set.

`chan` : | a channel

Since 0.11.14

### tp_base_channel_reopened ()

    void                tp_base_channel_reopened            (TpBaseChannel *chan,
                                                             TpHandle initiator);

Called by subclasses to indicate that this channel was closed but was re-opened due to pending messages.

Calling this method is the same as calling `tp_base_channel_reopened_with_requested()` with a requested value of `FALSE`.

`chan` : | a channel
`initiator` : | the handle of the contact that re-opened the channel

Since 0.11.14

### tp_base_channel_disappear ()

    void                tp_base_channel_disappear           (TpBaseChannel *chan);

Called by subclasses to indicate that this channel is closing and should be unregistered from the bus, but the actual object shouldn't be destroyed. The "Closed" signal will be emitted, the "channel-destroyed" property will not be set, and the channel will be unregistered from the bus.

`chan` : | a channel

Since 0.19.7

### tp_base_channel_reopened_with_requested ()

    void                tp_base_channel_reopened_with_requested
                                                            (TpBaseChannel *chan,
                                                             gboolean requested,
                                                             TpHandle initiator);

Called by subclasses to indicate that this channel was closed but was re-opened, either due to pending messages or from having disappeared (with `tp_base_channel_disappear()`). The "Closed" signal will be emitted, but the "channel-destroyed" property will not be set. The channel's "initiator-handle" property will be set to `initiator`, and the "requested" property will be set to `requested`.

`chan` : | a channel
`requested` : | `TRUE` if the channel is requested, otherwise `FALSE`
`initiator` : | the handle of the contact that re-opened the channel

Since 0.19.7

### tp_base_channel_get_object_path ()

    const gchar *       tp_base_channel_get_object_path     (TpBaseChannel *chan);

Returns `chan`'s object path, as a shortcut for retrieving the "object-path" property.

`chan` : | a channel
Returns : | `chan`'s object path. [transfer none]

Since 0.11.14

### tp_base_channel_get_connection ()

    TpBaseConnection *  tp_base_channel_get_connection      (TpBaseChannel *chan);

Returns the connection to which `chan` is attached, as a shortcut for retrieving the "connection" property.

`chan` : | a channel
Returns : | the connection to which `chan` is attached. [transfer none]

Since 0.11.14

### tp_base_channel_get_self_handle ()

    TpHandle            tp_base_channel_get_self_handle     (TpBaseChannel *chan);

If `chan` has a TpGroupMixin, returns the value of group's self handle. Otherwise return the value of "self-handle".

`chan` : | a channel
Returns : | the self handle of `chan`

Since 0.17.5

### tp_base_channel_get_target_handle ()

    TpHandle            tp_base_channel_get_target_handle   (TpBaseChannel *chan);

Returns the target handle of `chan` (without a reference), which will be 0 if TpBaseChannelClass.target_handle_type is TP_HANDLE_TYPE_NONE for this class, and non-zero otherwise. This is a shortcut for retrieving the "handle" property.

`chan` : | a channel
Returns : | the target handle of `chan`

Since 0.11.14

### tp_base_channel_get_initiator ()

    TpHandle            tp_base_channel_get_initiator       (TpBaseChannel *chan);

Returns the initiator handle of `chan`, as a shortcut for retrieving the "initiator-handle" property.

`chan` : | a channel
Returns : | the initiator handle of `chan`

Since 0.11.14

### tp_base_channel_is_requested ()

    gboolean            tp_base_channel_is_requested        (TpBaseChannel *chan);

Returns whether or not `chan` was requested, as a shortcut for retrieving the "requested" property.

`chan` : | a channel
Returns : | whether or not `chan` was requested.

Since 0.11.14

### tp_base_channel_is_registered ()

    gboolean            tp_base_channel_is_registered       (TpBaseChannel *chan);

Returns whether or not `chan` is visible on the bus; that is, whether `tp_base_channel_register()` has been called and `tp_base_channel_destroyed()` has not been called.

`chan` : | a channel
Returns : | TRUE if `chan` is visible on the bus

Since 0.11.14

### tp_base_channel_is_destroyed ()

    gboolean            tp_base_channel_is_destroyed        (TpBaseChannel *chan);

Returns the value of the "channel-destroyed" property, which is TRUE if `tp_base_channel_destroyed()` has been called (and thus the channel has been removed from the bus).

`chan` : | a channel
Returns : | TRUE if `tp_base_channel_destroyed()` has been called.

Since 0.11.14

### tp_base_channel_is_respawning ()

    gboolean            tp_base_channel_is_respawning       (TpBaseChannel *chan);

Returns `TRUE` if the channel has been reopened, either by a subclass calling `tp_base_channel_reopened()` or `tp_base_channel_reopened_with_requested()`. This is useful for "closed" handlers to distinguish between channels really closing and channels that have been reopened due to pending messages.

`chan` : | a channel
Returns : | `TRUE` if `tp_base_channel_reopened()` or `tp_base_channel_reopened_with_requested()` have been called.

Since 0.19.7

## Property Details

### The `"connection"` property

      "connection"               TpBaseConnection*     : Read / Write / Construct Only

Connection object that owns this channel.

### The `"initiator-handle"` property

      "initiator-handle"         guint                 : Read / Write / Construct Only

The contact who initiated the channel.

Default value: 0

### The `"initiator-id"` property

      "initiator-id"             gchar*                : Read

The string obtained by inspecting the initiator-handle.

Default value: NULL

### The `"interfaces"` property

      "interfaces"               GStrv                 : Read

Additional Channel.Interface.* interfaces.

### The `"requested"` property

      "requested"                gboolean              : Read / Write / Construct Only

True if this channel was requested by the local user.

Default value: FALSE

### The `"target-id"` property

      "target-id"                gchar*                : Read

The string obtained by inspecting the target handle.

Default value: NULL

## See Also

TpSvcChannel