static void
infinoted_plugin_manager_add_connection(InfinotedPluginManager* manager,
                                        InfinotedPluginInstance* instance,
                                        InfXmlConnection* connection)
{
  gpointer plugin_info;
  gpointer hash;
  gpointer connection_info;

  plugin_info = instance+1;
  hash = infinoted_plugin_manager_hash(plugin_info, connection);
  g_assert(g_hash_table_lookup(manager->connections, hash) == NULL);

  if(instance->plugin->connection_info_size > 0)
  {
    connection_info = g_slice_alloc(instance->plugin->connection_info_size);
    g_hash_table_insert(manager->connections, hash, connection_info);
  }

  if(instance->plugin->on_connection_added != NULL)
  {
    instance->plugin->on_connection_added(
      connection,
      plugin_info,
      connection_info
    );
  }
}
static void
infinoted_plugin_manager_remove_connection(InfinotedPluginManager* manager,
                                           InfinotedPluginInstance* instance,
                                           InfXmlConnection* connection)
{
  gpointer plugin_info;
  gpointer hash;
  gpointer connection_info;

  plugin_info = instance+1;
  hash = infinoted_plugin_manager_hash(plugin_info, connection);
  
  connection_info = g_hash_table_lookup(manager->connections, hash);

  g_assert(
    instance->plugin->connection_info_size == 0 || connection_info != NULL
  );

  if(instance->plugin->on_connection_removed != NULL)
  {
    instance->plugin->on_connection_removed(
      connection,
      plugin_info,
      connection_info
    );
  }

  if(instance->plugin->connection_info_size > 0)
  {
    g_hash_table_remove(manager->connections, hash);
    g_slice_free1(instance->plugin->connection_info_size, connection_info);
  }
}
static void
infinoted_plugin_manager_add_session(InfinotedPluginManager* manager,
                                     InfinotedPluginInstance* instance,
                                     const InfBrowserIter* iter,
                                     InfSessionProxy* proxy)
{
  gpointer plugin_info;
  gpointer hash;
  gpointer session_info;

  if(infinoted_plugin_manager_check_session_type(instance, proxy))
  {
    plugin_info = instance+1;
    hash = infinoted_plugin_manager_hash(plugin_info, proxy);
    g_assert(g_hash_table_lookup(manager->sessions, hash) == NULL);

    if(instance->plugin->session_info_size > 0)
    {
      session_info = g_slice_alloc(instance->plugin->session_info_size);
      g_hash_table_insert(manager->sessions, hash, session_info);
    }

    if(instance->plugin->on_session_added != NULL)
    {
      instance->plugin->on_session_added(
        iter,
        proxy,
        plugin_info,
        session_info
      );
    }
  }
}
static void
infinoted_plugin_manager_add_connection(InfinotedPluginManager* manager,
                                        InfinotedPluginInstance* instance,
                                        InfXmlConnection* connection)
{
  InfinotedPluginManagerPrivate* priv;
  gpointer plugin_info;
  gpointer hash;
  gpointer connection_info;

  priv = INFINOTED_PLUGIN_MANAGER_PRIVATE(manager);

  plugin_info = instance+1;
  hash = infinoted_plugin_manager_hash(plugin_info, connection);
  g_assert(g_hash_table_lookup(priv->connections, hash) == NULL);

  if(instance->plugin->connection_info_size > 0)
  {
    connection_info = g_slice_alloc(instance->plugin->connection_info_size);
    g_hash_table_insert(priv->connections, hash, connection_info);
  }

  if(instance->plugin->on_connection_added != NULL)
  {
    instance->plugin->on_connection_added(
      connection,
      plugin_info,
      connection_info
    );
  }
}
/**
 * infinoted_plugin_manager_get_session_info:
 * @mgr: A #InfinotedPluginManager.
 * @plugin_info: The @plugin_info pointer of a plugin instance.
 * @proxy: The #InfSessionProxy for which to retrieve plugin data.
 *
 * Queries the session-specfic plugin data for the plugin instance
 * @plugin_info. Returns %NULL if no such object exists, i.e. when the
 * plugin's @session_info_size is set to 0.
 *
 * Returns: A pointer to the session-specific plugin data, or %NULL.
 */
gpointer
infinoted_plugin_manager_get_session_info(InfinotedPluginManager* mgr,
                                          gpointer plugin_info,
                                          InfSessionProxy* proxy)
{
  return g_hash_table_lookup(
    mgr->sessions,
    infinoted_plugin_manager_hash(plugin_info, proxy)
  );
}
/**
 * infinoted_plugin_manager_get_connection_info:
 * @mgr: A #InfinotedPluginManager.
 * @plugin_info: The @plugin_info pointer of a plugin instance.
 * @connection: The #InfXmlConnection for which to retrieve plugin data.
 *
 * Queries the connection-specfic plugin data for the plugin instance
 * @plugin_info. Returns %NULL if no such object exists, i.e. when the
 * plugin's @connection_info_size is set to 0.
 *
 * Returns: A pointer to the connection-specific plugin data, or %NULL.
 */
gpointer
infinoted_plugin_manager_get_connection_info(InfinotedPluginManager* mgr,
                                             gpointer plugin_info,
                                             InfXmlConnection* connection)
{
  return g_hash_table_lookup(
    mgr->connections,
    infinoted_plugin_manager_hash(plugin_info, connection)
  );
}
/**
 * infinoted_plugin_manager_get_session_info:
 * @mgr: A #InfinotedPluginManager.
 * @plugin_info: The @plugin_info pointer of a plugin instance.
 * @proxy: The #InfSessionProxy for which to retrieve plugin data.
 *
 * Queries the session-specfic plugin data for the plugin instance
 * @plugin_info. Returns %NULL if no such object exists, i.e. when the
 * plugin's @session_info_size is set to 0.
 *
 * Returns: A pointer to the session-specific plugin data, or %NULL.
 */
gpointer
infinoted_plugin_manager_get_session_info(InfinotedPluginManager* mgr,
                                          gpointer plugin_info,
                                          InfSessionProxy* proxy)
{
  InfinotedPluginManagerPrivate* priv;

  g_return_val_if_fail(INFINOTED_IS_PLUGIN_MANAGER(mgr), NULL);
  g_return_val_if_fail(INF_IS_SESSION_PROXY(proxy), NULL);

  priv = INFINOTED_PLUGIN_MANAGER_PRIVATE(mgr);

  return g_hash_table_lookup(
    priv->sessions,
    infinoted_plugin_manager_hash(plugin_info, proxy)
  );
}
/**
 * infinoted_plugin_manager_get_connection_info:
 * @mgr: A #InfinotedPluginManager.
 * @plugin_info: The @plugin_info pointer of a plugin instance.
 * @connection: The #InfXmlConnection for which to retrieve plugin data.
 *
 * Queries the connection-specfic plugin data for the plugin instance
 * @plugin_info. Returns %NULL if no such object exists, i.e. when the
 * plugin's @connection_info_size is set to 0.
 *
 * Returns: A pointer to the connection-specific plugin data, or %NULL.
 */
gpointer
infinoted_plugin_manager_get_connection_info(InfinotedPluginManager* mgr,
                                             gpointer plugin_info,
                                             InfXmlConnection* connection)
{
  InfinotedPluginManagerPrivate* priv;

  g_return_val_if_fail(INFINOTED_IS_PLUGIN_MANAGER(mgr), NULL);
  g_return_val_if_fail(INF_IS_XML_CONNECTION(connection), NULL);

  priv = INFINOTED_PLUGIN_MANAGER_PRIVATE(mgr);

  return g_hash_table_lookup(
    priv->connections,
    infinoted_plugin_manager_hash(plugin_info, connection)
  );
}
static void
infinoted_plugin_manager_remove_session(InfinotedPluginManager* manager,
                                        InfinotedPluginInstance* instance,
                                        const InfBrowserIter* iter,
                                        InfSessionProxy* proxy)
{
  InfinotedPluginManagerPrivate* priv;
  gpointer plugin_info;
  gpointer hash;
  gpointer session_info;

  priv = INFINOTED_PLUGIN_MANAGER_PRIVATE(manager);

  if(infinoted_plugin_manager_check_session_type(instance, proxy))
  {
    plugin_info = instance+1;
    hash = infinoted_plugin_manager_hash(plugin_info, proxy);
    
    session_info = g_hash_table_lookup(priv->sessions, hash);

    g_assert(
      instance->plugin->session_info_size == 0 || session_info != NULL
    );

    if(instance->plugin->on_session_removed != NULL)
    {
      instance->plugin->on_session_removed(
        iter,
        proxy,
        plugin_info,
        session_info
      );
    }

    if(instance->plugin->session_info_size > 0)
    {
      g_hash_table_remove(priv->sessions, hash);
      g_slice_free1(instance->plugin->session_info_size, session_info);
    }
  }
}