/*
**  GXSNMP -- An snmp management application
**
**  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.
**
**  keepalive.c -- A basic keepalive monitor for GXSNMP
**
*/

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

#include <glib.h>
#include "plugins.h"
#include "main.h"
#include "tables.h"
#include "keepalive_dialog.h"

#include "rfc1213.h"

extern gxsnmp * app_info;

/******************************************************************************
**
**  Local data structures
**
******************************************************************************/

typedef struct _ka_data
{
  guint		rowid;		/* Rowid of interface to monitor */
  host_snmp	host;		/* Host snmp structure for keepalive request */
  GSList      * pdu;		/* GSList of PDUs */
  gpointer	request;	/* Return value from g_async_get () */
}
ka_data;

/******************************************************************************
**
**  Forward references
**
******************************************************************************/

static void 	menu_callback  (GtkWidget 	* widget, 
			 	gpointer 	  data);

static void 	initialize     (void);

static gboolean start_request  (ka_data 	* ka);

static gboolean completed_cb   (host_snmp 	* host,
				gpointer    	  data,
              			SNMP_PDU  	* pdu,
              			GSList    	* objs);

static void 	timeout_cb     (host_snmp 	* host,
            			gpointer    	  data);

/******************************************************************************
**
**  Static data
**
******************************************************************************/

static gchar * menu_location;
static GList * kagl;			/* GList of hosts to monitor */

static gulong  sysdescr[] = { SYSDESCR, 0 };
static gulong  sysname[]  = { SYSNAME, 0 };

#define oidlen(val) (sizeof(val)/sizeof(gulong))

/******************************************************************************
**
**  The plugin load routine
**
******************************************************************************/

gint
load_plugin (PluginData * pd)
{
  pd->type = PLUGIN_APPLICATION;
  return 0;
}

/******************************************************************************
**
**  The plugin unload routine
**
******************************************************************************/

void
unload_plugin (PluginData * pd)
{
#ifdef DEBUG
  g_print ("keepalive plugin unloaded\n");
#endif
}

/******************************************************************************
**
**  The plugin start routine 
**
******************************************************************************/

gint 
start_plugin (PluginData * pd)
{
  GnomeUIInfo   * menu;
#ifdef DEBUG
  g_print ("Starting keepalive plugin.\n");
#endif 
  menu_location         = g_strdup_printf ("%s/", gettext("_Plugins"));

  menu 			= g_malloc0 (2 * sizeof(GnomeUIInfo));
  menu->type		= GNOME_APP_UI_ITEM;
  menu->label           = g_strdup ("Keepalive");
  menu->hint            = NULL;
  menu->moreinfo        = menu_callback;       /* Menu activation cb routine */
  menu->user_data       = NULL;		       /* User data for the callback */
  menu->unused_data     = NULL;                /* Reserved for future use */
  menu->pixmap_type     = 0;
  menu->pixmap_info     = NULL;
  menu->accelerator_key = 0;
  (menu + 1)->type      = GNOME_APP_UI_ENDOFINFO;

  gnome_app_insert_menus (GNOME_APP (app_info->window), menu_location, menu);

  initialize ();

  return 0;
}

/******************************************************************************
**
**  Callback handler for when 'keepalive' is selected from the 'plugins' menu
**
**  Create the dialog widget and hand it over to the dialog manager.
**
******************************************************************************/

static void
menu_callback (GtkWidget * widget, gpointer data)
{
  GtkWidget       * dialog_widget;

  if (!gxsnmp_dialog_check ("keepalive_plugin", NULL))
    {
      dialog_widget = gxsnmp_keepalive_dialog_new ();
      if (dialog_widget)
        gxsnmp_dialog_add (dialog_widget, "Keepalive Plugin", NULL,
                           g_strdup ("Keepalive Plugin"));
    }
}

/******************************************************************************
**
**  Initialize function for the keepalive queue 
**
******************************************************************************/

static void
initialize (void)
{
  GList * gl;
  gint		interfaces = 0;
#ifdef DEBUG
  g_print ("Constructing initial keepalive list\n");
#endif
  gl = g_sqldb_table_list (interface_sqldb);  

  while (gl)
    {
      DB_interface 	* dbi;
      ka_data		* ka;

      dbi 	  = (DB_interface *)gl->data;
      ka 	  = g_new0 (ka_data, 1);
      ka->rowid   = dbi->rowid;
      ka->request = NULL;
      kagl = g_list_append (kagl, ka);
      if (start_request (ka))
        interfaces++;
      gl = gl->next;
    }
#ifdef DEBUG
  g_print ("keepalive checking %d interfaces\n", interfaces);
#endif
}

/******************************************************************************
**
**  Subroutine to send a keepalive request to a host
**
******************************************************************************/

static gboolean
start_request (ka_data * ka)
{
  DB_interface      * dbi;	/* Interface structure */
  DB_snmp	    * dbs;	/* SNMP parameter structure */

  if (!(dbi = g_sqldb_row_find (interface_sqldb, "_rowid", &ka->rowid)))
    return FALSE;

  if (!(dbs = (DB_snmp *) dbi->DB_snmp))
      return FALSE;

  ka->pdu = NULL;

  g_pdu_add_oid (&ka->pdu, sysdescr, oidlen(sysdescr), SNMP_NULL, NULL);
  g_pdu_add_oid (&ka->pdu, sysname, oidlen(sysname), SNMP_NULL, NULL);

  ka->host.domain		= dbi->transport;
  ka->host.rcomm		= dbs->read_c  ? g_strdup (dbs->read_c)
					       : NULL;
  ka->host.wcomm		= dbs->write_c ? g_strdup (dbs->write_c)
					       : NULL;
  ka->host.retries		= dbs->retries;
  ka->host.name			= g_strdup (dbi->address ? dbi->address : "");
  ka->host.status      		= 0;
  ka->host.port			= dbs->port;
  ka->host.timeout		= dbs->timeout;
  ka->host.version     		= dbs->version;
  ka->host.done_callback 	= completed_cb;
  ka->host.time_callback 	= timeout_cb;
  ka->host.magic		= ka;		/* Address of control block */

  ka->request = g_async_get (&ka->host, ka->pdu);
#ifdef DEBUG
  g_print ("Request sent to %s, request ID %x\n", dbi->address, 
						  (guint)ka->request);
#endif
  return TRUE;
}

/******************************************************************************
**
**  Callback for when a request completes
**
******************************************************************************/

static gboolean
completed_cb (host_snmp * host,		/* Pointer to host_snmp structure */
	      gpointer	  data,		/* User data pointer */
	      SNMP_PDU	* spdu,		/* We don't use this yet */
	      GSList    * objs)		/* Returned list of objects */
{
  ka_data * ka;
  int       i;

  ka = (ka_data *) data;		/* Recover pointer to ka_data block */ 
#ifdef DEBUG
  g_print ("Completed request %x\n", (guint )ka->request);
#endif
  if (host->status)
    {
#ifdef DEBUG
      g_print ("SNMP engine reported error: ");
      switch(host->status)
        {
          case SNMP_TOOBIG:
            g_print ("PDU too big\n");
            break;
          case SNMP_NOSUCHNAME:
            g_print ("No such name\n");
            break;
          case SNMP_BADVALUE:
            g_print ("Bad value\n");
            break;
          case SNMP_READONLY:
            g_print ("Read only\n");
            break;
          case SNMP_GENERROR:
            g_print ("Generic error\n");
            break;
          default:
            g_print ("unknown: %d\n", host->status);
            break;
        }
#endif
      return TRUE;
    }

  while (objs)
    {
      SNMP_OBJECT * obj;

      obj = (SNMP_OBJECT *) objs->data;
#ifdef DEBUG
      g_print ("Object MIB = ");
      for (i = 0; i < obj->id_len; i++)
        {
	  g_print ("%d", obj->id[i]);
	  if (i < obj->id_len)
	    g_print (".");
	}
      g_print (" data:\n%s\n", obj->syntax.c);
#endif
      objs = objs->next;
    }

  return TRUE;
}

/******************************************************************************
**
**  Callback for when a request times out
**
******************************************************************************/

static void
timeout_cb (host_snmp * host, 
	    gpointer    data)
{
  ka_data * ka;

  ka = (ka_data *)data;                 /* Recover pointer to ka_data block */
#ifdef DEBUG
  g_print ("Request timed out %x\n", (guint )ka->request);
#endif
}

/* EOF */
