/*
**  $Id: plugins-table.c,v 1.3 1999/10/31 20:35:29 remlali Exp $
**  GXSNMP -- An snmp management application
**  Copyright (C) 1998 Gregory McLean
**
**  This program is free software; you can redistribute it and/or modify
**  it under the terms of the GNU General Public License as published by
**  the Free Software Foundation; either version 2 of the License, or
**  (at your option) any later version.
**
**  This program 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 General Public License for more details.
**
**  You should have received a copy of the GNU General Public License
**  along with this program; if not, write to the Free Software
**  Foundation, Inc.,  59 Temple Place - Suite 330, Cambridge, MA 02139, USA.
**
**  plugin.c -- Support for dynamically-loaded plugin components.
**  Originally from gnumeric.
**  Orignal author Tom Dyas (tdyas@romulus.rutgers.edu)
**  Embraced and extended by Gregory McLean <gregm@comstar.net>
**  Yeah I'm a thief :)
**
** stolen again :)
** think table plugins could go into plugins.c as well.
** just thought it would be easier to startup.
*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <unistd.h>
#include <dirent.h>
#include <glib.h>
#include <gmodule.h>
#include <string.h>
#include <stdio.h>
#include "plugins.h"

#include "debug.h"

GList *plugintable_list = NULL;

/******************************************************************************
**
**  Local functions
**
******************************************************************************/

static PluginData * 	plugin_table_load 	(gchar	    * modfile);
static void 		plugin_table_unload 	(PluginData * pd);

/******************************************************************************
**
**  Private function to load a single plugin by filename
**
******************************************************************************/

static PluginData *
plugin_table_load (gchar * modfile)
{
  PluginData *data;
  D_FUNC_START;
  g_return_val_if_fail (modfile != NULL, NULL);
  d_print (DEBUG_DUMP, "load plugin %s\n", modfile);
/*  app_update_init_status ("Plugins loading...", g_basename (modfile));*/
  data = g_new0 (PluginData, 1);

/*
**  Call the dynamic loader to load the plugin into storage and link it
*/

  data->handle = g_module_open (modfile, 0);
  if (!data->handle)
    {
      g_warning ("Unable to load plugin module file: `%s`\n", 
		 g_module_error ());
      goto load_failed_could_not_load;
    }

/*
**  make sure that the module contains the required functions
*/

  if (!g_module_symbol (data->handle, "load_plugin",
			(gpointer *) &data->load_plugin))
    {
      g_warning ("Plugin error: '%s` must contain a load_plugin function\n",
		 modfile);
      goto load_failed_missing_symbol;
    }

  if (!g_module_symbol (data->handle, "unload_plugin",
			(gpointer *) &data->unload_plugin))
    {
      g_warning ("Plugin error: `%s` must contain a unload_plugin function\n", 
		 modfile);
      goto load_failed_missing_symbol;
    }

  if (!g_module_symbol (data->handle, "start_plugin",
                        (gpointer *) &data->start_plugin))
    {
      g_warning ("Plugin error: `%s` must contain a start_plugin function\n",
                 modfile);
      goto load_failed_missing_symbol;
    }

/*
**  Now invoke the load_plugin function.  If the plugin returns anything other
**  then zero, then the plugin is unusable, so discard it.
*/

  if (data->load_plugin (data) != 0)
    goto load_failed_bad_return_code;

/*
**  Everything checks out ok.  Continue ...
*/

  plugintable_list = g_list_append (plugintable_list, data);
  d_print (DEBUG_TRACE, "plugin loaded. returning valid handle.");
  D_FUNC_END;
  return data;

/*
**  An error occurred.  Close the module file if necessary and free the 
**  plugin control block
*/

load_failed_missing_symbol:
load_failed_bad_return_code:

  g_module_close (data->handle);

load_failed_could_not_load: 
  d_print(DEBUG_TRACE, "plugin failed to initilize, freeing structure and "
	"returning NULL pointer.");
  g_free (data);
  D_FUNC_END;
  return NULL;
}

/******************************************************************************
**
**  Unload a plugin
**
******************************************************************************/

static void
plugin_table_unload (PluginData * pd)
{
  D_FUNC_START;
  g_return_if_fail (pd != NULL);
  d_print (DEBUG_DUMP, "unloading plugin %s\n", g_module_name (pd->handle));
  if (pd->refcount > 0)
    {
      g_warning ("unload_plugin: Refcount is positive, cannot unload plugin "
		 "%s\n",g_module_name (pd->handle));
      return;
    }

  if (pd->unload_plugin)
    pd->unload_plugin (pd);

  if (pd->name)
    g_free (pd->name);
  plugintable_list = g_list_remove (plugintable_list, pd);

  g_module_close (pd->handle);
  g_free (pd);
  D_FUNC_END;
}

/******************************************************************************
**
**  Public function to unload all of the plugins
**
******************************************************************************/

void
plugins_table_unload (void)
{
  D_FUNC_START;
  while (plugintable_list)
    plugin_table_unload ((PluginData *)(plugintable_list->data));
  D_FUNC_END;
}

/******************************************************************************
**
**  Load all of the plugins in a directory
**
******************************************************************************/

void plugins_table_load(char *directory)
{
  gchar pathfile[512];
  DIR           * d;
  struct dirent * e;
  D_FUNC_START;
  d_print (DEBUG_DUMP, "scanning directory %s\n", directory);
  if ((d = opendir (directory)) == NULL)
    return;
  
  while ((e = readdir (d)) != NULL)
    {
      if (strncmp (e->d_name + strlen (e->d_name) - 3, ".so", 3) == 0)
	{
	  gchar *plugin_name;
	 
	  /*plugin_name = g_copy_strings (directory, e->d_name, NULL);*/
          sprintf(pathfile,"%s%s",directory, e->d_name); 
          plugin_name = pathfile;
          fprintf(stderr,"loading plugin: %s\n", plugin_name);
	  plugin_table_load (plugin_name);
	  
	  /*g_free (plugin_name);*/
	}
    }
  closedir (d);
  D_FUNC_END;
}

/******************************************************************************
**
**  Public function to start all the plugins of a certain type
**
******************************************************************************/

void
plugins_table_start ()
{
  GList * gl;
  D_FUNC_START;
  gl = plugintable_list;
  while (gl)
    {
      PluginData * pd;
      pd = (PluginData *)gl->data; 
      pd->start_plugin (pd);
      gl = gl->next;
    }
  D_FUNC_END;
}


/* EOF */

