/*
 * $Id: browser.c,v 1.43 2000/12/26 19:30:20 remlali Exp $
 * GXSNMP - An snmp managment 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.
 *
 * The mib browser panel.
 */

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

#include "debug.h"

/****************************************************************************
 * Static data
 ***************************************************************************/
#define BROWSER_LABELS 6
static gchar *browser_labels[] = {
  N_("Object Type"), N_("Module"), N_("OID"), N_("Status"), N_("Label"), 
  N_("Value")
};

const gchar *gxsnmp_browser_name_key = "gxsnmp-browser-name-value";
const gchar *gxsnmp_browser_module_key = "gxsnmp-browser-module-value";

/****************************************************************************
 * Forward declarations and callback functions  
 ***************************************************************************/
static void      browser_class_init       (GXsnmp_browserClass       *klass);
static void      browser_init             (GXsnmp_browser            *dialog);
static gint      browser_close_cb         (GXsnmp_browser            *dialog,
					   gpointer                   data);
static void      browser_dialog_cb        (GnomeDialog               *dialog,
					   gint                       button,
                                           gpointer                   data);
static void      build_mib_tree           (GXsnmp_browser            *dialog);
static void      first_button_cb          (GtkWidget                 *widget,
					   gpointer                   data);
static void      next_button_cb           (GtkWidget                 *widget,
					   gpointer                   data);
static void      get_button_cb            (GtkWidget                 *widget,
					   gpointer                   data);
static void      put_button_cb            (GtkWidget                 *widget,
					   gpointer                   data);
static void      cb_tree_changed          (GtkTree                   *tree,
                                           gpointer                   data);
gboolean         update_mib_value         (host_snmp                 *host,
                                           void                      *magic,
                                           SNMP_PDU                  *spdu,
                                           GSList                    *objs);
void             update_mib_timeout       (host_snmp                 *host, 
                                           void                      *magic);
/****************************************************************************
 * gxsnmp_browser_get_type()
 ***************************************************************************/
GtkType
gxsnmp_browser_get_type ()
{
  static GtkType list_type = 0;
  if (!list_type)
    {
      GtkTypeInfo list_info = 
      {
	"GXsnmp_browser",
	sizeof (GXsnmp_browser),
	sizeof (GXsnmp_browserClass),
	(GtkClassInitFunc) browser_class_init,
	(GtkObjectInitFunc) browser_init,
	/* reserved 1 */ NULL,
	/* reserved 2 */ NULL,
	(GtkClassInitFunc) NULL,
      };
      list_type =gtk_type_unique(gnome_dialog_get_type(), &list_info);
    }
  return list_type;
}
/****************************************************************************
 * Class init
 ***************************************************************************/
static void
browser_class_init (GXsnmp_browserClass *klass)
{
}
/****************************************************************************
 * Widget init
 ***************************************************************************/
static void
browser_init (GXsnmp_browser *dialog)
{
  GtkWidget    *hbox;
  GtkWidget    *vbox;
  GtkWidget    *table;
  GtkWidget    *frame;
  GtkWidget    *label;
  GtkWidget    *hscroll;
  GtkWidget    *vscroll;
  GtkWidget    *bar;
  GtkWidget    *button_box;
  GtkWidget    *scrolled_window;
  int           i;

  D_FUNC_START;
  hbox = gtk_hbox_new (FALSE, 2);
  gtk_box_pack_start (GTK_BOX (GNOME_DIALOG(dialog)->vbox), 
                      hbox, TRUE, TRUE, 0);
/* Left side shows MIB tree */
  vbox = gtk_vbox_new (FALSE, 2);
  gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
  scrolled_window = gtk_scrolled_window_new (NULL, NULL);
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
				  GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
  gtk_box_pack_start (GTK_BOX (vbox), scrolled_window, TRUE, TRUE, 0);
  gtk_widget_set_usize (GTK_WIDGET (scrolled_window), 250, 250);
  dialog->root = gtk_tree_new ();
  gtk_tree_set_selection_mode (GTK_TREE (dialog->root), GTK_SELECTION_SINGLE);
  gtk_scrolled_window_add_with_viewport 
                        (GTK_SCROLLED_WINDOW (scrolled_window), dialog->root);
  gtk_widget_set_sensitive (GTK_WIDGET (dialog->root), FALSE);
/* Right side shows entry fields */
  vbox = gtk_vbox_new (FALSE, 2);
  gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 2);
  frame = gtk_frame_new (NULL);
  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
  table = gtk_table_new ( 2, 7, FALSE);
  gtk_container_add (GTK_CONTAINER (frame), table);
/* Create labels */
  for (i=0; i<BROWSER_LABELS; i++)
    { 
      label = gtk_label_new (gettext(browser_labels[i]));
      gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
      gtk_table_attach (GTK_TABLE (table), label, 0, 1, i, i+1,
		        GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
    }
/* Create SNMP updatable fields */
  dialog->mib_type = gtk_entry_new ();
  gtk_entry_set_editable (GTK_ENTRY (dialog->mib_type), FALSE);
  gtk_table_attach (GTK_TABLE (table), dialog->mib_type,
		    1, 2, 0, 1,
		    GTK_EXPAND | GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
  dialog->mib_module = gtk_entry_new ();
  gtk_entry_set_editable (GTK_ENTRY (dialog->mib_module), FALSE);
  gtk_table_attach (GTK_TABLE (table), dialog->mib_module,
		    1, 2, 1, 2,
		    GTK_EXPAND | GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
  dialog->mib_oid = gtk_entry_new ();
  gtk_entry_set_editable (GTK_ENTRY (dialog->mib_oid), FALSE);
  gtk_table_attach (GTK_TABLE (table), dialog->mib_oid, 
		    1, 2, 2, 3,
		    GTK_EXPAND | GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
  dialog->mib_status = gtk_entry_new ();
  gtk_entry_set_editable (GTK_ENTRY (dialog->mib_status), FALSE);
  gtk_table_attach (GTK_TABLE (table), dialog->mib_status, 
		    1, 2, 3, 4,
		    GTK_EXPAND | GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
  dialog->mib_label = gtk_entry_new ();
  gtk_entry_set_editable (GTK_ENTRY (dialog->mib_label), FALSE);
  gtk_table_attach (GTK_TABLE (table), dialog->mib_label,
		    1, 2, 4, 5, 
		    GTK_EXPAND | GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
  dialog->mib_value = gtk_entry_new ();
  gtk_table_attach (GTK_TABLE (table), dialog->mib_value,
		    1, 2, 5, 6,
		    GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
/* Text entry field for displaying description */
  label = gtk_label_new (_("Description"));
  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.1);
  gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
  table = gtk_table_new (2, 2, FALSE);
  gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2);
  gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2);
  gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0);
  dialog->mib_desc = gtk_text_new (NULL, NULL);
  gtk_text_set_editable (GTK_TEXT (dialog->mib_desc), FALSE);
  gtk_widget_set_usize (GTK_WIDGET (dialog->mib_desc), 350, 200);
  GTK_TEXT(dialog->mib_desc)->line_wrap = FALSE;
  gtk_table_attach_defaults (GTK_TABLE (table), dialog->mib_desc, 0, 1, 0, 1);
  hscroll = gtk_hscrollbar_new (GTK_TEXT (dialog->mib_desc)->hadj);
  gtk_table_attach (GTK_TABLE (table), hscroll, 0, 1, 1, 2,
		    GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
  vscroll = gtk_vscrollbar_new (GTK_TEXT (dialog->mib_desc)->vadj);
  gtk_table_attach (GTK_TABLE (table), vscroll, 1, 2, 0, 1,
		    GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
/* Buttons for FIRST, NEXT, GET, PUT */
  bar = gtk_hseparator_new ();
  gtk_box_pack_start (GTK_BOX (vbox), bar, FALSE, FALSE, 0);
  frame = gtk_frame_new (NULL);
  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
  button_box = gtk_hbutton_box_new ();
  gtk_container_border_width (GTK_CONTAINER (button_box), 2);
  gtk_button_box_set_layout (GTK_BUTTON_BOX (button_box), 
			     GTK_BUTTONBOX_SPREAD);
  gtk_button_box_set_spacing (GTK_BUTTON_BOX (button_box), 2);
  gtk_button_box_set_child_size (GTK_BUTTON_BOX (button_box), 85, 20);
  gtk_container_add (GTK_CONTAINER (frame), button_box);
  dialog->fbutton = gtk_button_new_with_label (_("First"));
  gtk_container_add (GTK_CONTAINER (button_box), dialog->fbutton);
  dialog->nbutton = gtk_button_new_with_label (_("Next"));
  gtk_container_add (GTK_CONTAINER (button_box), dialog->nbutton);
  gtk_widget_set_sensitive (dialog->nbutton, FALSE);
  dialog->gbutton = gtk_button_new_with_label (_("Get"));
  gtk_container_add (GTK_CONTAINER (button_box), dialog->gbutton);
  gtk_widget_set_sensitive (dialog->gbutton, FALSE);
  dialog->pbutton = gtk_button_new_with_label (_("Put"));
  gtk_container_add (GTK_CONTAINER (button_box), dialog->pbutton);
/****************************************************************************
 * Signals
 ***************************************************************************/
  gtk_signal_connect (GTK_OBJECT (dialog->fbutton), "clicked",
		      GTK_SIGNAL_FUNC (first_button_cb),
		      dialog);
  gtk_signal_connect (GTK_OBJECT (dialog->nbutton), "clicked",
		      GTK_SIGNAL_FUNC (next_button_cb),
		      dialog);
  gtk_signal_connect (GTK_OBJECT (dialog->gbutton), "clicked",
		      GTK_SIGNAL_FUNC (get_button_cb),
		      dialog);
  gtk_signal_connect (GTK_OBJECT (dialog->pbutton), "clicked",
		      GTK_SIGNAL_FUNC (put_button_cb),
		      dialog);
  gtk_signal_connect (GTK_OBJECT (dialog->root), "selection_changed",
                      GTK_SIGNAL_FUNC (cb_tree_changed),
                      dialog);
  gtk_widget_show_all (hbox);
  /* Append buttons for close and help */
  gnome_dialog_append_buttons (GNOME_DIALOG (dialog),
                               GNOME_STOCK_BUTTON_CLOSE,
                               GNOME_STOCK_BUTTON_HELP,
                               NULL);
  gtk_signal_connect (GTK_OBJECT(dialog), "clicked",
		      GTK_SIGNAL_FUNC(browser_dialog_cb), NULL);
  D_FUNC_END;
}
static gint
browser_close_cb (GXsnmp_browser *dialog, gpointer data)
{
  D_FUNC_START;
  if (dialog->request)
    g_remove_request(dialog->request);
  D_FUNC_END;
  return FALSE;
}
static void
browser_dialog_cb (GnomeDialog *dialog, gint button, gpointer data)
{
  gchar *tmp;
  D_FUNC_START;
  if (button == 0)
    {
      gnome_dialog_close (GNOME_DIALOG (dialog));
    }
  else if (button == 1)
    {
      tmp = gnome_help_file_find_file ("gxsnmp", "browser-help.html");
      if (tmp)
	{
	  gnome_help_goto (0, tmp);
	  g_free (tmp);
	}
    }
  D_FUNC_END;
}
static void
getoid (SmiNode *node, char *buffer, int buflen)
{
  int i;
  D_FUNC_START;
  snprintf(buffer, buflen, "%d", node->oid[0]);
  for (i=1; i < node->oidlen; i++)
    snprintf(buffer + strlen (buffer), buflen - strlen (buffer), ".%d", 
             node->oid[i]);
  D_FUNC_END;
}
/*
 * Get the list of the enumerated values for this object.
 *
 * This is the (up, down, testing... etc stuff)
 */
static void
get_enums (GXsnmp_browser *dialog, SmiNode *node)
{
  char               buf[80];
  SmiNamedNumber    *num;
  SmiType	    *type;
  D_FUNC_START;
  type = smiGetNodeType(node);
  if (type && type->basetype == SMI_BASETYPE_ENUM)
    {
      sprintf (buf, _("\n\nAvailable values:\n\n"));
      gtk_text_insert (GTK_TEXT (dialog->mib_desc), NULL,
		       &(dialog->mib_desc)->style->black,
		       NULL, buf, strlen(buf));
      num = smiGetFirstNamedNumber(type);
      while (num)
	{
	  sprintf (buf, "%s (%d)\n", num->name, 
                   num->value.value.integer32);
	  gtk_text_insert (GTK_TEXT (dialog->mib_desc), NULL,
			   &(dialog->mib_desc)->style->black,
			   NULL, buf, -1);
	  num = smiGetNextNamedNumber(num);
	}
    }
  D_FUNC_END;
}
static void 
cb_tree_changed(GtkTree* tree, gpointer data) 
{
  GList          *selected;
  GtkTreeItem    *selected_item;
  gint            nb_selected;
  guint           length;
  SmiNode        *node;
  SmiModule	 *module;
  SmiType	 *type;
  gchar          *name;
  gchar          *modname;
  gchar          *buffer;
  GXsnmp_browser *dialog;
  D_FUNC_START;
  g_return_if_fail (data != NULL);
  dialog = (GXsnmp_browser *) data;
  selected    = tree->selection;
  nb_selected = g_list_length(selected);
  if (nb_selected != 1) 
    return;
  selected_item = GTK_TREE_ITEM(selected->data);
  name    = gtk_object_get_data(GTK_OBJECT(selected_item), 
                                gxsnmp_browser_name_key);
  modname = gtk_object_get_data(GTK_OBJECT(selected_item), 
                                gxsnmp_browser_module_key);
  module = smiGetModule(modname);
  node = smiGetNode(module, name);
  gtk_text_set_point(GTK_TEXT (dialog->mib_desc),0);
  length = gtk_text_get_length(GTK_TEXT (dialog->mib_desc));
  gtk_text_forward_delete(GTK_TEXT (dialog->mib_desc),length);
  if (node)
    {
      type = smiGetNodeType(node);
      if (!type)
        {
          buffer = _("None");
	}
      else switch (type->basetype)
	{
	  case SMI_BASETYPE_INTEGER32:
	    buffer = _("Integer32");
	    break;
	  case SMI_BASETYPE_OCTETSTRING:
	    buffer = _("String");
	    break;
	  case SMI_BASETYPE_OBJECTIDENTIFIER:
	    buffer = _("Object ID");
	    break;
	  case SMI_BASETYPE_UNSIGNED32:
	    buffer = _("Unsigned32");
	    break;
	  case SMI_BASETYPE_INTEGER64:
	    buffer = _("Integer64");
	    break;
	  case SMI_BASETYPE_UNSIGNED64:
	    buffer = _("Unsigned64");
	    break;
	  case SMI_BASETYPE_FLOAT32:
	    buffer = _("Float32");
	    break;
	  case SMI_BASETYPE_FLOAT64:
	    buffer = _("Float64");
	    break;
	  case SMI_BASETYPE_FLOAT128:
	    buffer = _("Float128");
	    break;
	  case SMI_BASETYPE_ENUM:
	    buffer = _("Enum");
	    break;
	  case SMI_BASETYPE_BITS:
	    buffer = _("Bits");
	    break;
	  case SMI_BASETYPE_UNKNOWN:
	  default:
	    buffer = _("Unknown");
	}
      gtk_entry_set_text (GTK_ENTRY (dialog->mib_type), buffer);
      switch (node->status)
	{
	  case SMI_STATUS_CURRENT:
	    buffer = _("Current");
	    break;
	  case SMI_STATUS_DEPRECATED:
	    buffer = _("Deprecated");
	    break;
	  case SMI_STATUS_MANDATORY:
	    buffer = _("Mandatory");
	    break;
	  case SMI_STATUS_OPTIONAL:
	    buffer = _("Optional");
	    break;
	  case SMI_STATUS_OBSOLETE:
	    buffer = _("Obsolete");
	    break;
	  case SMI_STATUS_UNKNOWN:
	  default:
	    buffer = _("Unknown");
	}
      gtk_entry_set_text (GTK_ENTRY (dialog->mib_status), buffer);
      gtk_entry_set_text (GTK_ENTRY (dialog->mib_module), module->name);
      buffer = (gchar *) g_malloc(1024);
      getoid(node, buffer, 1024);
      gtk_entry_set_text (GTK_ENTRY (dialog->mib_oid), buffer);
      g_free(buffer);
      gtk_entry_set_text (GTK_ENTRY (dialog->mib_label), node->name);
      if (node->description) 
	{
	  gtk_text_insert (GTK_TEXT (dialog->mib_desc), NULL, 
			  &(dialog->mib_desc)->style->black, 
			  NULL, node->description, strlen
			  (node->description));
        }
      get_enums (dialog, node);
    }
  gtk_text_thaw (GTK_TEXT (dialog->mib_desc));
  gtk_widget_set_sensitive (GTK_WIDGET (dialog->nbutton), FALSE);
  D_FUNC_END;
}
static void 
create_tree_item(GtkWidget* parent, SmiNode *node) 
{
  char buffer[255];
  GtkWidget *item, *tree;
  SmiNode *child;
  SmiModule *module;
  D_FUNC_START;
  gtk_main_iteration_do(FALSE); /* keep the UI from locking up */
  if (node->name)
    sprintf(buffer,"%s (%d)", node->name, node->oid[node->oidlen-1]);
  else
    sprintf(buffer,"(%d)", node->oid[node->oidlen-1]);
  item = gtk_tree_item_new_with_label(buffer);
  gtk_tree_append(GTK_TREE(parent), item);
  module = smiGetNodeModule(node);
  gtk_object_set_data(GTK_OBJECT(item), gxsnmp_browser_name_key,
                     (gpointer)node->name);
  gtk_object_set_data(GTK_OBJECT(item), gxsnmp_browser_module_key,
                     (gpointer)module->name);
  gtk_widget_show(item);
  if ((child = smiGetFirstChildNode(node)))
    {
      tree = gtk_tree_new();
      gtk_tree_item_set_subtree(GTK_TREE_ITEM(item), tree);
      while(child)
        {  
          create_tree_item(tree, child);
          child = smiGetNextChildNode(child);
        }
    }
  D_FUNC_END;
}
/*
 * Moved this here cause with the cmu snmp lib at least it takes a few
 * seconds for the window to appear, so we'll build the window, show it,
 * stick a watch cursor up, build and insert the tree, and restore the
 * normal cursor.
 */
static void
build_mib_tree (GXsnmp_browser *dialog)
{
  GtkWidget           *root_item;
  GtkWidget           *root_subtree;
  SmiNode             *node;
  D_FUNC_START;
  gtk_widget_hide (dialog->root); /* Work around a bug in gtk*/
  root_item = gtk_tree_item_new_with_label (".");
  gtk_tree_append (GTK_TREE (dialog->root), root_item);
  gtk_widget_show (root_item);
  root_subtree = gtk_tree_new();
  gtk_tree_item_set_subtree (GTK_TREE_ITEM (root_item), root_subtree);
  if((node = smiGetNode(NULL, "ccitt")))
    {
      create_tree_item (root_subtree, node);
    }
  if((node = smiGetNode(NULL, "iso")))
    {
      create_tree_item (root_subtree, node);
    }
  if((node = smiGetNode(NULL, "joint-iso-ccitt")))
    {
      create_tree_item (root_subtree, node);
    }

  gtk_tree_item_expand (GTK_TREE_ITEM (root_item));
  gtk_widget_set_sensitive (GTK_WIDGET (dialog->root), TRUE);
  gtk_widget_show (dialog->root); /* Work around a bug in gtk*/
  D_FUNC_END;
}
static int
setup_snmp (host_snmp *host, DB_host *dbh)
{
  DB_interface   *dbi;
  DB_snmp        *dbs;
  GList          *gl;
  D_FUNC_START;
  g_return_val_if_fail (dbh != NULL, FALSE);
  g_return_val_if_fail (host != NULL, FALSE);
  if (!(gl = dbh->DB_interfaces))
    return FALSE;
  dbi = (DB_interface *)gl->data;
  if (!(dbs = (DB_snmp *)dbi->DB_snmp))
    return FALSE;
  if (!dbi->address)
    return FALSE;
  host->domain         = dbi->transport;
  host->rcomm          = dbs->read_c ? g_strdup (dbs->read_c) : "public";
  host->wcomm          = dbs->write_c ? g_strdup (dbs->write_c) : "private";
  host->retries        = dbs->retries;
  host->name           = g_strdup (dbi->address);
  host->status         = 0;
  host->port           = dbs->port;
  host->timeout        = dbs->timeout;
  host->version        = dbs->version;
  host->time_callback  = update_mib_timeout;
  host->done_callback  = update_mib_value;
  D_FUNC_END;
  return TRUE;
}
static void
first_button_cb (GtkWidget *widget, gpointer data)
{
  GList          *sel;
  GtkTreeItem    *sel_item;
  SmiNode        *node;
  SmiModule	 *module;
  GSList         *objs;
  SNMP_OBJECT    *obj;
  host_snmp       host;
  GXsnmp_browser *dialog;
  gchar          *name;
  gchar          *modname;
  D_FUNC_START;
  g_return_if_fail (data != NULL);
  dialog = (GXsnmp_browser *) data;
  objs = NULL;
  sel = GTK_TREE (dialog->root)->selection;
  if ( (g_list_length (sel)) != 1)
    {
      D_FUNC_END;
      return;
    }
  sel_item = GTK_TREE_ITEM (sel->data);
  name    = gtk_object_get_data(GTK_OBJECT(sel_item), 
                                gxsnmp_browser_name_key);
  modname = gtk_object_get_data(GTK_OBJECT(sel_item), 
                                gxsnmp_browser_module_key);
  host.magic = dialog;
  if (!setup_snmp(&host, dialog->dbh))
    {
      g_warning ("first_button_cb: unable to setup the snmp structure.");
      D_FUNC_END;
      return;
    }
  module = smiGetModule(modname);
  node = smiGetNode(module, name);
  g_pdu_add_oid(&objs, node->oid, node->oidlen, SNMP_NULL, NULL);
  obj = (SNMP_OBJECT *)objs->data;
  dialog->basemib_length = obj->id_len;
  memcpy(dialog->basemib, obj->id, dialog->basemib_length * sizeof(gulong));
  dialog->request = g_async_getnext(&host, objs);
  D_FUNC_END;
  return;
}
static void
get_button_cb (GtkWidget *widget, gpointer data)
{
  host_snmp       host;
  GSList         *objs;
  GXsnmp_browser *dialog;
  D_FUNC_START;
  g_return_if_fail (data != NULL);
  dialog = (GXsnmp_browser *) data;
  objs = NULL;
  host.magic = dialog;
  if (!setup_snmp(&host, dialog->dbh))
    {
      g_warning ("Unable to initilize the needed snmp setup.");
      D_FUNC_END;
      return;
    }
  g_pdu_add_oid(&objs, dialog->thismib, dialog->thismib_length, 
                SNMP_NULL, NULL);
  dialog->request = g_async_get(&host, objs);
  D_FUNC_END;
  return;
}
static void
next_button_cb (GtkWidget *widget, gpointer data)
{
  host_snmp       host;
  GSList         *objs;
  GXsnmp_browser *dialog;
  D_FUNC_START;
  g_return_if_fail (data != NULL);
  dialog = (GXsnmp_browser *) data;
  objs = NULL;
  host.magic = dialog;
  if (!setup_snmp(&host, dialog->dbh))
    {
      g_warning ("Unable to setup the needed snmp configuration.");
      D_FUNC_END;
      return;
    }
  g_pdu_add_oid(&objs, dialog->thismib, dialog->thismib_length, 
                SNMP_NULL, NULL);
  dialog->request = g_async_getnext(&host, objs);
  gtk_widget_set_sensitive (GTK_WIDGET (dialog->nbutton), FALSE);
}
static void
put_button_cb (GtkWidget *widget, gpointer data)
{
  host_snmp       host;
  GList          *sel;
  GtkTreeItem    *sel_item;
  SmiNode        *node;
  SmiModule      *module;
  SmiType        *type;
  char           *value;
  guint32         val;
  GSList         *objs;
  GXsnmp_browser *dialog;
  gchar          *name;
  gchar          *modname;
  D_FUNC_START;
  g_return_if_fail (data != NULL);
  dialog = (GXsnmp_browser *) data;
  objs = NULL;
  sel = GTK_TREE (dialog->root)->selection;
  if ( (g_list_length (sel)) != 1)
    {
      g_warning ("No mib selected.");
      D_FUNC_END;
      return;
    }
  sel_item = GTK_TREE_ITEM (sel->data);
  name    = gtk_object_get_data(GTK_OBJECT(sel_item), 
                                gxsnmp_browser_name_key);
  modname = gtk_object_get_data(GTK_OBJECT(sel_item), 
                                gxsnmp_browser_module_key);
  module = smiGetModule(modname);
  node = smiGetNode(module, name);
  host.magic = dialog;
  if (!setup_snmp(&host, dialog->dbh))
    {
      g_warning ("Unable to setup the needed snmp configuration.");
      D_FUNC_END;
      return;
    }
  type = smiGetNodeType(node);
  if (!type)
    {
      g_warning("Unable to get type information.");
      D_FUNC_END;
      return;
    }
  value = gtk_entry_get_text(GTK_ENTRY (dialog->mib_value));
  switch(type->basetype)
    {
      case SMI_BASETYPE_INTEGER32:
      case SMI_BASETYPE_UNSIGNED32:
        val = atoi(value);
        g_pdu_add_oid(&objs, dialog->thismib, dialog->thismib_length, 
                      SNMP_INTEGER, &val);
        dialog->request = g_async_set(&host, objs);
        break;
      case 0:
      case 2:
      case 12:
        g_pdu_add_oid(&objs, dialog->thismib, dialog->thismib_length, 
                      SNMP_OCTETSTR, value);
        dialog->request = g_async_set(&host, objs);
        break;
      case SMI_BASETYPE_OBJECTIDENTIFIER:
      case SMI_BASETYPE_INTEGER64:
      case SMI_BASETYPE_UNSIGNED64:
      case SMI_BASETYPE_FLOAT32:
      case SMI_BASETYPE_FLOAT64:
      case SMI_BASETYPE_FLOAT128:
      case SMI_BASETYPE_ENUM:
      case SMI_BASETYPE_BITS:
      break;
    }
  D_FUNC_END;
  return;
}
/*
 * snmp callback
 */
gboolean
update_mib_value (host_snmp *host, void *magic, SNMP_PDU *spdu, GSList *objs)
{
  char    buf[1024];
  int     i;
  struct _SNMP_OBJECT *obj;
  GXsnmp_browser *dialog;
  D_FUNC_START;
  g_return_val_if_fail (magic != NULL, FALSE);
  dialog = (GXsnmp_browser *) magic;
  dialog->request = NULL;
  obj = objs->data;
  if (memcmp(dialog->basemib, obj->id, dialog->basemib_length * sizeof(gulong)))
    {
      gtk_widget_set_sensitive (GTK_WIDGET (dialog->nbutton), FALSE);
    }
  else
    {
      dialog->thismib_length = obj->id_len;
      memcpy(dialog->thismib, obj->id, dialog->thismib_length * sizeof(gulong));
      g_snmp_printf (buf, sizeof(buf), obj);
      gtk_entry_set_text (GTK_ENTRY (dialog->mib_value), buf);
      buf[0] = 0;
      for (i = 0; i < dialog->thismib_length; i++)
	sprintf (buf + strlen (buf), ".%ld", dialog->thismib[i]);
      gtk_entry_set_text (GTK_ENTRY (dialog->mib_oid), buf);
      gtk_widget_set_sensitive (GTK_WIDGET (dialog->nbutton), TRUE);
      gtk_widget_set_sensitive (GTK_WIDGET (dialog->gbutton), TRUE);
    }
  D_FUNC_END;
  return TRUE;
}
/*
 * timeout callback
 */
void
update_mib_timeout (host_snmp *host, void *magic)
{
  GXsnmp_browser *dialog;
  D_FUNC_START;
  g_return_if_fail (magic != NULL);
  dialog = (GXsnmp_browser *) magic;
  dialog->request = NULL;
  D_FUNC_END;
}
/****************************************************************************
 * Public API
 ***************************************************************************/
GtkWidget *
gxsnmp_browser_new (gpointer data)
{
  GXsnmp_browser  *dialog;
  D_FUNC_START;
  g_return_val_if_fail (data != NULL, NULL);
  dialog = gtk_type_new (gxsnmp_browser_get_type ());
  if (dialog)
    {
      dialog->dbh = (DB_host *)data;
      dialog->request = NULL;
      build_mib_tree (dialog);
      gtk_signal_connect (GTK_OBJECT (dialog), "close",
			  GTK_SIGNAL_FUNC (browser_close_cb), NULL);
      D_FUNC_END;
      return GTK_WIDGET (dialog);
    }
  D_FUNC_END;
  return NULL;
}
/* EOF */
