/*
**  $Id: plugins.c,v 1.4 1999/10/20 11:24:44 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 :)
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <unistd.h>
#include <dirent.h>
#include <glib.h>
#include <gmodule.h>
//#include <gnome.h>
#include <string.h>
#include <stdio.h>
#include "plugins.h"
//#include "main.h"

#include "debug.h"

GList *plugin_list = NULL;

//extern gxsnmp * app_info;

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

static PluginData * 	plugin_load 	(gchar	    * modfile);
static void 		plugin_unload 	(PluginData * pd);

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

static PluginData *
plugin_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 ...
*/

  plugin_list = g_list_append (plugin_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_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);
  plugin_list = g_list_remove (plugin_list, pd);

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

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

void plugins_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_load (plugin_name);
	  
	  /*g_free (plugin_name);*/
	}
    }
  closedir (d);
  D_FUNC_END;
}

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

void
plugins_unload (void)
{
  D_FUNC_START;
  while (plugin_list)
    plugin_unload ((PluginData *)(plugin_list->data));
  D_FUNC_END;
}

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

void
plugins_start ()
{
  gint type = PLUGIN_DATABASE;
  GList * gl;
  D_FUNC_START;
  gl = plugin_list;
  while (gl)
    {
      PluginData * pd;
      pd = (PluginData *)gl->data; 

      if (type & pd->type)
fprintf(stderr,"plugins.c plugins_start(): calling plugin code\n");
	pd->start_plugin (pd);
fprintf(stderr,"plugins.c plugins_start(): plugin started!\n");
      gl = gl->next;
    }
  D_FUNC_END;
}


/* EOF */

