/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
/*
 *  bonobo-activation: A library for accessing bonobo-activation-server.
 *
 *  Copyright (C) 1999, 2000 Red Hat, Inc.
 *  Copyright (C) 2000 Eazel, Inc.
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 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
 *  Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public
 *  License along with this library; if not, write to the Free
 *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *  Author: Elliot Lee <sopwith@redhat.com>
 */
#include <config.h>
#include <string.h>
#include <stdlib.h>
#include <locale.h>

#include <bonobo-activation/bonobo-activation-activate.h>

#include <bonobo-activation/bonobo-activation-init.h>
#include <bonobo-activation/bonobo-activation-server-info.h>
#include <bonobo-activation/bonobo-activation-private.h>
#include <bonobo-activation/bonobo-activation-shlib.h>
#include <bonobo-activation/bonobo-activation-client.h>
#include <bonobo-activation/bonobo-activation-async.h>
#include <glib/gi18n-lib.h>
#include <bonobo-activation/Bonobo_ActivationContext.h>

static Bonobo_ActivationEnvironment *activation_environment = NULL;

/* FIXME: deprecated internal functions. Should we just remove?
 */
void
bonobo_activation_set_test_components_enabled (gboolean val)
{
}

gboolean
bonobo_activation_get_test_components_enabled (void)
{
	return FALSE;
}

static void 
copy_strv_to_sequence (char *const       *selection_order,
		       Bonobo_StringList *str_seq)
{
	int len;

	if (!selection_order) {
		memset (str_seq, 0, sizeof (Bonobo_StringList));
		return;
	}

	for (len = 0; selection_order [len]; len++);

	str_seq->_length  = str_seq->_maximum = len;
	str_seq->_buffer  = (char **) selection_order;
	str_seq->_release = FALSE;
}

/* Limit of the number of cached queries */
#define QUERY_CACHE_MAX 32
#undef QUERY_CACHE_DEBUG

static GHashTable *query_cache = NULL;

typedef struct {
	char  *query;
	char **sort_criteria;

	Bonobo_ServerInfoList *list;
} QueryCacheEntry;

static void
query_cache_entry_free (gpointer data)
{
        QueryCacheEntry *entry = data;

#ifdef QUERY_CACHE_DEBUG
        g_message ("Blowing item %p", entry);
#endif /* QUERY_CACHE_DEBUG */

        g_free (entry->query);
        g_strfreev (entry->sort_criteria);
        CORBA_free (entry->list);
        g_free (entry);
}

static gboolean
cache_clean_half (gpointer  key,
                  gpointer  value,
                  gpointer  user_data)
{
        int *a = user_data;
        /* Blow half the elements */
        return (*a)++ % 2;
}

static gboolean
query_cache_equal (gconstpointer a, gconstpointer b)
{
	int i;
	char **strsa, **strsb;
	const QueryCacheEntry *entrya = a;
	const QueryCacheEntry *entryb = b;

	if (strcmp (entrya->query, entryb->query))
		return FALSE;

	strsa = entrya->sort_criteria;
	strsb = entryb->sort_criteria;

	if (!strsa && !strsb)
		return TRUE;

	if (!strsa || !strsb)
		return FALSE;

	for (i = 0; strsa [i] && strsb [i]; i++)
		if (strcmp (strsa [i], strsb [i]))
			return FALSE;

	if (strsa [i] || strsb [i])
		return FALSE;

	return TRUE;
}

static guint
query_cache_hash (gconstpointer a)
{
	guint hash, i;
	char **strs;
	const QueryCacheEntry *entry = a;
	
	hash = g_str_hash (entry->query);
	strs = entry->sort_criteria;

	for (i = 0; strs && strs [i]; i++)
		hash ^= g_str_hash (strs [i]);

	return hash;
}

static void
query_cache_reset (void)
{
        if (query_cache) {
                g_hash_table_destroy (query_cache);
                query_cache = NULL;
        }
}

static void
create_query_cache (void)
{
        query_cache = g_hash_table_new_full (
                query_cache_hash,
                query_cache_equal,
                query_cache_entry_free,
                NULL);
        bonobo_activation_add_reset_notify (query_cache_reset);
}

static Bonobo_ServerInfoList *
query_cache_lookup (const char   *query,
		    char * const *sort_criteria,
                    gboolean *active)
{
	QueryCacheEntry  fake;
	QueryCacheEntry *entry;
        Bonobo_ServerInfoList *result;

        BONOBO_ACTIVATION_LOCK ();

        *active = FALSE;

	if (!query_cache) {
                create_query_cache ();
                BONOBO_ACTIVATION_UNLOCK ();
		return NULL;
	}

        if (strstr (query, "_active")) {
                *active = TRUE;
                return NULL;
        }

	fake.query = (char *) query;
	fake.sort_criteria = (char **) sort_criteria;
	if ((entry = g_hash_table_lookup (query_cache, &fake))) {
#ifdef QUERY_CACHE_DEBUG
		g_message ("\n\n ---  Hit (%p)  ---\n\n\n", entry->list);
#endif /* QUERY_CACHE_DEBUG */
		result = Bonobo_ServerInfoList_duplicate (entry->list);
	} else {
#ifdef QUERY_CACHE_DEBUG
		g_message ("Miss");
#endif /* QUERY_CACHE_DEBUG */
		result = NULL;
	}

        BONOBO_ACTIVATION_UNLOCK ();

        return result;
}

static void
query_cache_insert (const char   *query,
		    char * const *sort_criteria,
		    Bonobo_ServerInfoList *list)
{
        int idx = 0;
	QueryCacheEntry *entry = g_new (QueryCacheEntry, 1);

        if (!query_cache) {
                create_query_cache ();
        
        } else if (g_hash_table_size (query_cache) > QUERY_CACHE_MAX) {
                g_hash_table_foreach_remove (
                        query_cache, cache_clean_half, &idx);
        }

	entry->query = g_strdup (query);
	entry->sort_criteria = g_strdupv ((char **) sort_criteria);
	entry->list = Bonobo_ServerInfoList_duplicate (list);

	g_hash_table_replace (query_cache, entry, entry);

#ifdef QUERY_CACHE_DEBUG
	g_message ("Query cache size now %d",
                g_hash_table_size (query_cache));
#endif /* QUERY_CACHE_DEBUG */
}

/**
 * bonobo_activation_query: 
 * @requirements: query string.
 * @selection_order: sort criterion for returned list.
 * @ev: a %CORBA_Environment structure which will contain 
 *      the CORBA exception status of the operation, or NULL
 *
 * Executes the @requirements query on the bonobo-activation-server.
 * The result is sorted according to @selection_order. 
 * @selection_order can safely be NULL as well as @ev.
 * The returned list has to be freed with CORBA_free.
 *
 * Return value: the list of servers matching the requirements.
 */
Bonobo_ServerInfoList *
bonobo_activation_query (const char        *requirements,
                         char * const      *selection_order,
                         CORBA_Environment *opt_ev)
{
        gboolean                  active;
	Bonobo_StringList         selorder;
	Bonobo_ServerInfoList    *retval;
	Bonobo_ActivationContext  ac;
	CORBA_Environment         tempenv, *ev;

	g_return_val_if_fail (requirements != NULL, CORBA_OBJECT_NIL);

	ac = bonobo_activation_activation_context_get ();
	g_return_val_if_fail (ac != NULL, CORBA_OBJECT_NIL);

	retval = query_cache_lookup (requirements, selection_order, &active);
	if (retval)
		return retval;

	if (!opt_ev) {
		CORBA_exception_init (&tempenv);
		ev = &tempenv;
	} else
		ev = opt_ev;

	copy_strv_to_sequence (selection_order, &selorder);

	retval = Bonobo_ActivationContext_query (
                ac, requirements, &selorder,
                bonobo_activation_context_get (), ev);

        if (ev->_major == CORBA_NO_EXCEPTION) {
                if (!active)
                        query_cache_insert (requirements, selection_order, retval);
        } else
                retval = NULL;

	if (!opt_ev)
		CORBA_exception_free (&tempenv);

	return retval;
}

static CORBA_Object
handle_activation_result (Bonobo_ActivationResult *result,
			  Bonobo_ActivationID     *ret_aid,
			  CORBA_Environment       *ev)
{
	CORBA_Object retval = CORBA_OBJECT_NIL;

	switch (result->res._d) {
	case Bonobo_ACTIVATION_RESULT_SHLIB:
		retval = bonobo_activation_activate_shlib_server (result, ev);
		break;
	case Bonobo_ACTIVATION_RESULT_OBJECT:
		retval = CORBA_Object_duplicate (result->res._u.res_object, ev);
		break;
	case Bonobo_ACTIVATION_RESULT_NONE:
	default:
		break;
	}

	if (ret_aid) {
		if (result->aid && result->aid [0])
			*ret_aid = g_strdup (result->aid);
		else
			*ret_aid = NULL;
	}

	CORBA_free (result);

	return retval;
}

/**
 * bonobo_activation_activate:
 * @requirements: query string.
 * @selection_order: sort criterion for returned list.
 * @flags: how to activate the object.
 * @ret_aid: AID of the activated object.
 * @ev: %CORBA_Environment structure which will contain 
 *      the CORBA exception status of the operation. 
 *
 * Activates a given object. @ret_aid can be safely NULLed as well
 * as @ev and @selection_order. @flags can be set to zero if you do 
 * not what to use.
 *
 * Return value: the CORBA object reference of the activated object.
 *               This value can be CORBA_OBJECT_NIL: you are supposed 
 *               to check @ev for success.
 */
CORBA_Object
bonobo_activation_activate (const char             *requirements,
			    char *const            *selection_order,
			    Bonobo_ActivationFlags  flags,
			    Bonobo_ActivationID    *ret_aid,
			    CORBA_Environment      *opt_ev)
{
	Bonobo_ActivationContext  ac;
	Bonobo_ActivationResult  *result;
	CORBA_Environment         tempenv, *ev;
	Bonobo_StringList         selorder;
	CORBA_Object              retval = CORBA_OBJECT_NIL;

	g_return_val_if_fail (requirements != NULL, CORBA_OBJECT_NIL);

	ac = bonobo_activation_activation_context_get ();
	g_return_val_if_fail (ac != NULL, CORBA_OBJECT_NIL);

	if (!opt_ev) {
		CORBA_exception_init (&tempenv);
		ev = &tempenv;
	} else
		ev = opt_ev;

	copy_strv_to_sequence (selection_order, &selorder);
        
        result = Bonobo_ActivationContext_activateMatchingFull
                (ac, requirements, &selorder, activation_environment,
                 flags, bonobo_activation_client_get (),
                 bonobo_activation_context_get (), ev);
        
        if (ev->_major == CORBA_SYSTEM_EXCEPTION &&
            !strcmp (ev->_id, ex_CORBA_BAD_OPERATION)) /* fall-back */
        {
                g_message ("TESTME: Fall-back activate");
                result = Bonobo_ActivationContext_activateMatching
                        (ac, requirements, &selorder, activation_environment,
                         flags, bonobo_activation_context_get (), ev);
        }

	if (ev->_major == CORBA_NO_EXCEPTION)
		retval = handle_activation_result (result, ret_aid, ev);

	if (!opt_ev)
		CORBA_exception_free (&tempenv);

	return retval;
}

/**
 * bonobo_activation_activate_from_id
 * @aid: AID or IID of the object to activate.
 * @flags: activation flag.
 * @ret_aid: AID of the activated server.
 * @ev: %CORBA_Environment structure which will contain 
 *      the CORBA exception status of the operation. 
 *
 * Activates the server corresponding to @aid. @ret_aid can be safely 
 * NULLed as well as @ev. @flags can be zero if you do not know what 
 * to do.
 *
 * Return value: a CORBA object reference to the newly activated 
 *               server. Do not forget to check @ev for failure!!
 */
CORBA_Object
bonobo_activation_activate_from_id (const Bonobo_ActivationID aid, 
				    Bonobo_ActivationFlags    flags,
				    Bonobo_ActivationID      *ret_aid,
				    CORBA_Environment        *opt_ev)
{
	Bonobo_ActivationContext  ac;
	Bonobo_ActivationResult  *result;
	CORBA_Environment        *ev, tempenv;
	CORBA_Object              retval = CORBA_OBJECT_NIL;

	g_return_val_if_fail (aid != NULL, CORBA_OBJECT_NIL);

	if (!strncmp ("OAFIID:", aid, 7)) {
		char *requirements;

		requirements = g_alloca (strlen (aid) + sizeof ("iid == ''"));
		sprintf (requirements, "iid == '%s'", aid);

		return bonobo_activation_activate (
				requirements, NULL, flags, ret_aid, opt_ev);
	}
	
	if (!opt_ev) {
		CORBA_exception_init (&tempenv);
		ev = &tempenv;
	} else
		ev = opt_ev;

	ac = bonobo_activation_internal_activation_context_get_extended (
				(flags & Bonobo_ACTIVATION_FLAG_EXISTING_ONLY), ev);
	if (!ac) {
		if (!opt_ev)
			CORBA_exception_free (&tempenv);

		return CORBA_OBJECT_NIL;
	}

	result = Bonobo_ActivationContext_activateFromAidFull
                (ac, aid, flags, bonobo_activation_client_get (),
                 bonobo_activation_context_get (), ev);

        if (ev->_major == CORBA_SYSTEM_EXCEPTION &&
            !strcmp (ev->_id, ex_CORBA_BAD_OPERATION)) /* fall-back */
                result = Bonobo_ActivationContext_activateFromAid
                        (ac, aid, flags, bonobo_activation_context_get (), ev);

	if (ev->_major == CORBA_NO_EXCEPTION)
		retval = handle_activation_result (result, ret_aid, ev);
        
	if (!opt_ev)
		CORBA_exception_free (&tempenv);

	return retval;
}

/* Async activation
 */

#define ASYNC_ERROR_NO_AID            (_("No ActivationID supplied"))
#define ASYNC_ERROR_NO_REQUIREMENTS   (_("No requirements supplied"))
#define ASYNC_ERROR_NO_CONTEXT        (_("Failed to initialise the ActivationContext"))
#define ASYNC_ERROR_INV_FAILED        (_("Failed to invoke method on the ActivationContext"))
#define ASYNC_ERROR_GENERAL_EXCEPTION (_("System exception: %s : %s"))
#define ASYNC_ERROR_EXCEPTION         (_("System exception: %s"))

static ORBit_IMethod *activate_matching_full_method = NULL;
static ORBit_IMethod *activate_from_aid_full_method = NULL;

typedef struct {
	BonoboActivationCallback user_cb;
	gpointer                 user_data;
} AsyncActivationData;

static void
setup_methods (void)
{
	activate_matching_full_method = &Bonobo_ActivationContext__iinterface.methods._buffer [7];
	activate_from_aid_full_method = &Bonobo_ActivationContext__iinterface.methods._buffer [9];

	/* If these blow the IDL changed order, and the above
	   indexes need updating */
	g_assert (!strcmp (activate_matching_full_method->name, "activateMatchingFull"));
	g_assert (!strcmp (activate_from_aid_full_method->name, "activateFromAidFull"));
}

static void
activation_async_callback (CORBA_Object          object,
			   ORBit_IMethod        *m_data,
			   ORBitAsyncQueueEntry *aqe,
			   gpointer              user_data,
			   CORBA_Environment    *ev)
{
	Bonobo_ActivationResult *result = NULL;
	AsyncActivationData     *async_data = user_data;
	Bonobo_GeneralError     *err;
	CORBA_Object             retval;
	char                    *reason = NULL;

	g_return_if_fail (async_data != NULL);
	g_return_if_fail (async_data->user_cb != NULL);

	if (ev->_major != CORBA_NO_EXCEPTION)
		goto return_exception;

	ORBit_small_demarshal_async (aqe, &result, NULL, ev);

	if (ev->_major != CORBA_NO_EXCEPTION)
		goto return_exception;

	retval = handle_activation_result (result, NULL, ev);

	if (ev->_major != CORBA_NO_EXCEPTION)
		goto return_exception;

	async_data->user_cb (retval, NULL, async_data->user_data);

clean_out:
	g_free (async_data);
	return;

return_exception:
	if (!strcmp (ev->_id, "IDL:Bonobo/GeneralError:1.0")) {
		err = ev->_any._value;

		if (!err || !err->description)
			reason = g_strdup_printf (ASYNC_ERROR_GENERAL_EXCEPTION,
						  ev->_id, "(no description)");
		else
			reason = g_strdup_printf (ASYNC_ERROR_GENERAL_EXCEPTION,
						  ev->_id, err->description);
	} else
		reason = g_strdup_printf (ASYNC_ERROR_EXCEPTION, ev->_id);

	async_data->user_cb (CORBA_OBJECT_NIL, reason, async_data->user_data);
	g_free (reason);

	goto clean_out;
}

/**
 * bonobo_activation_activate_async:
 * @requirements: the bonobo-activation query string.
 * @selection_order: preference array.
 * @flags: activation flags.
 * @callback: callback function.
 * @user_data: data to be poassed to the callback function.
 * @ev: exception structure.
 *
 * This function will asynchronously try to activate a component
 * given the @requirements query string. When the component is
 * activated or when the activation fails, it will call @callback
 * with the given @user_data data as parameter.
 * callback will be called with a CORBA_OBJECT_NIL object if the
 * activation fails. If the activation fails, the callback will be
 * given a human-readable string containing a description of the
 * error. In case of sucess, the error string value is undefined.
 *
 * @selection_order can be safely NULLed as well as @ev and
 * @user_data. @flags can be set to 0 if you do not know what to
 * use.
 */
void
bonobo_activation_activate_async (const char               *requirements,
				  char *const              *selection_order,
				  Bonobo_ActivationFlags    flags,
				  BonoboActivationCallback  async_cb,
				  gpointer                  user_data,
				  CORBA_Environment        *opt_ev)
{
	Bonobo_ActivationContext  ac;
	AsyncActivationData      *async_data;
	CORBA_Environment        *ev, tempenv;
	Bonobo_StringList         selorder;
        Bonobo_ActivationClient   client;
	gpointer                  args [5];

	if (!requirements) {
		async_cb (CORBA_OBJECT_NIL, ASYNC_ERROR_NO_REQUIREMENTS, user_data);
		return;
	}

	ac = bonobo_activation_activation_context_get ();
	if (!ac) {
		async_cb (CORBA_OBJECT_NIL, ASYNC_ERROR_NO_CONTEXT, user_data);
		return;
	}

	if (!opt_ev) {
		CORBA_exception_init (&tempenv);
		ev = &tempenv;
	} else
		ev = opt_ev;

	async_data = g_new (AsyncActivationData, 1);
	async_data->user_cb   = async_cb;
	async_data->user_data = user_data;

	copy_strv_to_sequence (selection_order, &selorder);

        client = bonobo_activation_client_get ();

        args [0] = &requirements;
	args [1] = &selorder;
	args [2] = activation_environment;
	args [3] = &flags;
	args [4] = &client;

	if (!activate_matching_full_method)
		setup_methods ();

	ORBit_small_invoke_async (ac, activate_matching_full_method,
				  activation_async_callback, async_data,
				  args, bonobo_activation_context_get (), ev);

	if (ev->_major != CORBA_NO_EXCEPTION) {
		async_cb (CORBA_OBJECT_NIL, ASYNC_ERROR_INV_FAILED, user_data);
		g_free (async_data);
	}

	if (!opt_ev)
		CORBA_exception_free (&tempenv);

	return;
}

/**
 * bonobo_activation_activate_from_id_async:
 * @aid: the AID or IID of the component to activate.
 * @flags: activation flags.
 * @callback: callback function.
 * @user_data: data to be poassed to the callback function.
 * @ev: exception structure.
 *
 * This function will asynchronously try to activate a component
 * with the given @aid. When the component is
 * activated or when the activation fails, it will call @callback
 * with the given @user_data data as parameter.
 * callback will be called with a CORBA_OBJECT_NIL object if the
 * activation fails. If the activation fails, the callback will be
 * given a human-readable string containing a description of the
 * error. In case of sucess, the error string value is undefined.
 *
 * @flags can be 0 if you do not know what to set it to and
 * @ev can be safely set to NULL.
 */
void
bonobo_activation_activate_from_id_async (const Bonobo_ActivationID  aid,
					  Bonobo_ActivationFlags     flags,
					  BonoboActivationCallback   async_cb,
					  gpointer                   user_data,
					  CORBA_Environment         *opt_ev)
{
	Bonobo_ActivationContext  ac;
	AsyncActivationData      *async_data;
	CORBA_Environment        *ev, tempenv;
        Bonobo_ActivationClient   client;
	gpointer                  args [3];

	if (!aid) {
		async_cb (CORBA_OBJECT_NIL, ASYNC_ERROR_NO_AID, user_data);
		return;
	}

	if (!strncmp ("OAFIID:", aid, 7)) {
		char *requirements;

		requirements = g_alloca (strlen (aid) + sizeof ("iid == ''"));
		sprintf (requirements, "iid == '%s'", aid);

                bonobo_activation_activate_async (
                        requirements, NULL, flags, async_cb, user_data, opt_ev);
                return;
	}
	
	if (!opt_ev) {
		CORBA_exception_init (&tempenv);
		ev = &tempenv;
	} else
		ev = opt_ev;

	ac = bonobo_activation_internal_activation_context_get_extended (
				(flags & Bonobo_ACTIVATION_FLAG_EXISTING_ONLY), ev);
	if (!ac) {
		if (!opt_ev)
			CORBA_exception_free (&tempenv);

		async_cb (CORBA_OBJECT_NIL, ASYNC_ERROR_NO_CONTEXT, user_data);
		return;
	}

	async_data = g_new (AsyncActivationData, 1);
	async_data->user_cb   = async_cb;
	async_data->user_data = user_data;

	if (!activate_from_aid_full_method)
		setup_methods ();

        client = bonobo_activation_client_get ();

	args [0] = (gpointer) &aid;
	args [1] = &flags;
	args [2] = &client;

	ORBit_small_invoke_async (ac, activate_from_aid_full_method,
				  activation_async_callback, async_data,
				  args, bonobo_activation_context_get (), ev);

	if (ev->_major != CORBA_NO_EXCEPTION) {
		async_cb (CORBA_OBJECT_NIL, ASYNC_ERROR_INV_FAILED, user_data);
		g_free (async_data);
	}

	if (!opt_ev)
		CORBA_exception_free (&tempenv);

	return;

}

void
bonobo_activation_init_activation_env (void)
{
	int i;

	struct {
		const char *name;
		const char *value;
	} getenv_values[] = {
#ifndef G_OS_WIN32
		{ "DISPLAY",         NULL }, /* X display */
		{ "SESSION_MANAGER", NULL }, /* XSMP session manager */
		{ "AUDIODEV",        NULL }, /* Audio device on Sun systems */
                { "XAUTHORITY",      NULL },
		{ "LC_ALL",	     NULL }, /* locale information: see setlocale(3) */
		{ "LC_COLLATE",	     NULL }, 
		{ "LC_MESSAGES",     NULL },
		{ "LC_MONETARY",     NULL },
		{ "LC_NUMERIC",	     NULL },
		{ "LC_TIME",	     NULL },
#endif
		{ "LANG",            NULL }, /* Fallback locale name */
		{ NULL,		     NULL }
	};

        g_assert (activation_environment == NULL);
        activation_environment = Bonobo_ActivationEnvironment__alloc ();

	for (i = 0; getenv_values [i].name; i++) {
		getenv_values [i].value = getenv (getenv_values [i].name);

		if (!getenv_values [i].value)
			continue;

                Bonobo_ActivationEnvValue value = {
                        (CORBA_char *) getenv_values [i].name,
                        (CORBA_char *) getenv_values [i].value,
                        0 /* flags */ };

                ORBit_sequence_append (activation_environment, &value);
	}
}

void
bonobo_activation_set_activation_env_value (const char *name,
					    const char *value)
{
	int                        i;
        Bonobo_ActivationEnvValue env_value = { (CORBA_char *) name, (CORBA_char *) value, 0 };

	g_return_if_fail (name != NULL);

	for (i = 0; i < activation_environment->_length; i++) {
		if (!strcmp (activation_environment->_buffer [i].name, name)) {
                        ORBit_sequence_remove (activation_environment, i);
			break;
		}
        }
        ORBit_sequence_append (activation_environment, &env_value);
}

CORBA_char *
_bonobo_activation_get_activation_env_value (const char *name)
{
	int                        i;

	g_return_val_if_fail (name != NULL, NULL);

	for (i = 0; i < activation_environment->_length; i++) {
		if (strcmp (activation_environment->_buffer [i].name, name) == 0) {
                        return activation_environment->_buffer [i].value;
		}
        }
        return NULL;
}


/**
 * bonobo_activation_name_service_get:
 * @ev: %CORBA_Environment structure which will contain 
 *      the CORBA exception status of the operation. 
 *
 * Returns the name server of bonobo-activation. @ev can be NULL.
 *
 * Return value: the name server of bonobo-activation.
 */
CORBA_Object
bonobo_activation_name_service_get (CORBA_Environment * ev)
{
	return bonobo_activation_activate_from_id (
                "OAFIID:Bonobo_CosNaming_NamingContext", 0, NULL, ev);
}

/**
 * bonobo_activation_dynamic_add_path:
 * @add_path: The path would be loaded in runtime.  
 * @ev: %CORBA_Environment structure which will contain
 *      the CORBA exception status of the operation.
 * This function could make BAS server load the specific
 * search path in runtime.
 * 
 * Return value: a result of dynamic path load
 */
Bonobo_DynamicPathLoadResult
bonobo_activation_dynamic_add_path (const char *add_path,
				    CORBA_Environment * ev)
{
	Bonobo_ObjectDirectory        od;
	Bonobo_DynamicPathLoadResult  res;

	g_return_val_if_fail (add_path != NULL, Bonobo_DYNAMIC_LOAD_ERROR);
	od = bonobo_activation_object_directory_get (
					bonobo_activation_username_get (),
					bonobo_activation_hostname_get ());
	if (CORBA_Object_is_nil (od, ev))
		return Bonobo_DYNAMIC_LOAD_ERROR;

	res = Bonobo_ObjectDirectory_dynamic_add_path(od, add_path, ev);
	if (ev->_major != CORBA_NO_EXCEPTION) 
		return Bonobo_DYNAMIC_LOAD_ERROR;

	return res;
					
}

/**
 * bonobo_activation_dynamic_remove_path:
 * @remove_path: The path would be unloaded in runtime.
 * @ev: %CORBA_Environment structure which will contain
 * the CORBA exception status of the operation.
 * This function could make BAS server unload the specific
 * search path in runtime.
 * 
 * Return value: a result of dynamic path load
 */
Bonobo_DynamicPathLoadResult
bonobo_activation_dynamic_remove_path (const char *remove_path,
				       CORBA_Environment * ev)
{
	Bonobo_ObjectDirectory        od;
	Bonobo_DynamicPathLoadResult  res;

	g_return_val_if_fail (remove_path != NULL, Bonobo_DYNAMIC_LOAD_ERROR);
	od = bonobo_activation_object_directory_get (
						bonobo_activation_username_get (),
						bonobo_activation_hostname_get ());
	if (CORBA_Object_is_nil (od, ev))
		return Bonobo_DYNAMIC_LOAD_ERROR;

	res = Bonobo_ObjectDirectory_dynamic_remove_path(od, remove_path, ev);
	if (ev->_major != CORBA_NO_EXCEPTION)
		return Bonobo_DYNAMIC_LOAD_ERROR;

	return res;
}



syntax highlighted by Code2HTML, v. 0.9.1