"Fossies" - the Fresh Open Source Software Archive

Member "gkrellm_snmp-1.1/gkrellm_snmp.c" (3 Jan 2009, 48337 Bytes) of package /linux/privat/old/gkrellm_snmp-1.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /* SNMP reader plugin for GKrellM 
    2 |  Copyright (C) 2000-2009  Christian W. Zuckschwerdt <zany@triq.net>
    3 |
    4 |  Author:  Christian W. Zuckschwerdt  <zany@triq.net>  http://triq.net/
    5 |  Latest versions might be found at:  http://gkrellm.net/
    6 |
    7 | GKrellM_SNMP is free software; you can redistribute it and/or
    8 | modify it under the terms of the GNU General Public License as
    9 | published by the Free Software Foundation; either version 2 of
   10 | the License, or (at your option) any later version.
   11 |
   12 | In addition, as a special exception, the copyright holders give
   13 | permission to link the code of this program with the OpenSSL library,
   14 | and distribute linked combinations including the two.
   15 | You must obey the GNU General Public License in all respects
   16 | for all of the code used other than OpenSSL.  If you modify
   17 | file(s) with this exception, you may extend this exception to your
   18 | version of the file(s), but you are not obligated to do so.  If you
   19 | do not wish to do so, delete this exception statement from your
   20 | version.  If you delete this exception statement from all source
   21 | files in the program, then also delete it here.
   22 
   23 | This program is distributed in the hope that it will be useful,
   24 | but WITHOUT ANY WARRANTY; without even the implied warranty of
   25 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   26 | GNU General Public License for more details.
   27 
   28 | You should have received a copy of the GNU General Public License
   29 | along with GKrellM_SNMP. If not, see <http://www.gnu.org/>.
   30 */
   31 
   32 /* Installation:
   33 |
   34 |     make
   35 |     make install
   36 |      or without using superuser privileges
   37 |     make install-user
   38 |
   39 */
   40 
   41 /* In case of SNMP trouble: #define DEBUG_SNMP */
   42 
   43 #include <stdio.h>
   44 #include <sys/types.h>
   45 
   46 #ifdef UCDSNMP
   47 #include <ucd-snmp/asn1.h>
   48 #include <ucd-snmp/mib.h>
   49 #include <ucd-snmp/parse.h>
   50 #include <ucd-snmp/snmp.h>
   51 #include <ucd-snmp/snmp_api.h>
   52 #include <ucd-snmp/snmp_client.h>
   53 #include <ucd-snmp/snmp_impl.h> /* special ASN types */
   54 #ifdef DEBUG_SNMP
   55 #include <ucd-snmp/snmp_debug.h>
   56 #endif /* DEBUG_SNMP */
   57 #else /* UCDSNMP */
   58 #include <net-snmp/net-snmp-config.h>
   59 #include <net-snmp/net-snmp-includes.h>
   60 #define RECEIVED_MESSAGE NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE
   61 #define TIMED_OUT NETSNMP_CALLBACK_OP_TIMED_OUT
   62 #ifdef DEBUG_SNMP
   63 #include <net-snmp/snmp_debug.h>
   64 #endif /* DEBUG_SNMP */
   65 #endif /* UCDSNMP */
   66 
   67 #include <sys/time.h>
   68 
   69 
   70 #include <gkrellm2/gkrellm.h>
   71 
   72 /* #define STREAM /* test for Lou Cephyr */
   73 
   74 
   75 #define SNMP_PLUGIN_MAJOR_VERSION 0
   76 #define SNMP_PLUGIN_MINOR_VERSION 21
   77 
   78 #define PLUGIN_CONFIG_NAME   "SNMP"
   79 #define PLUGIN_CONFIG_KEYWORD   "snmp_monitor"
   80 
   81 
   82 typedef struct Reader Reader;
   83 
   84 struct Reader {
   85     Reader          *next;
   86     gchar           *label;
   87     gchar           *peer;
   88     gint            port;
   89     gchar           *community;
   90     gchar           *oid_str;
   91     oid         objid[MAX_OID_LEN];
   92     size_t          objid_length;
   93     gchar           *unit;
   94     gint            divisor;
   95     gboolean        scale;
   96     gint            delay;
   97     gboolean        active;
   98     gboolean        delta;
   99     gint            asn1_type;
  100     gchar           *sample;
  101     u_long          sample_n;
  102     u_long          sample_time;
  103     gchar           *old_sample;
  104     u_long          old_sample_n;
  105     u_long          old_sample_time;
  106     gchar           *error;
  107     gchar           *old_error;
  108     struct snmp_session *session;
  109 
  110     GkrellmPanel            *panel;
  111     GtkTooltips             *tooltip;
  112 
  113     GkrellmChart            *chart;
  114     GkrellmChartdata        *chart_data;
  115     GkrellmChartconfig      *chart_config;
  116 };
  117 
  118 
  119 /*
  120  * caller needs to free the returned gchar*
  121  */
  122 
  123 gchar *
  124 scale(u_long num)
  125 {
  126     if (num > 2000000000)
  127     return g_strdup_printf("%ldG", num/1024/1024/1024);
  128     if (num > 6000000)
  129     return g_strdup_printf("%ldM", num/1024/1024);
  130     if (num > 6000)
  131     return g_strdup_printf("%ldK", num/1024);
  132     return g_strdup_printf("%ld", num);
  133 }
  134 
  135 gchar *
  136 strdup_uptime (u_long time)
  137 {
  138     gint up_d, up_h, up_m;
  139 
  140     up_d = time/100/60/60/24;
  141     up_h = (time/100/60/60) % 24;
  142     up_m = (time/100/60) % 60;
  143 
  144     return g_strdup_printf ("%dd %d:%d", up_d, up_h, up_m );
  145 }
  146 
  147 gchar *
  148 render_error(Reader *reader)
  149 {
  150     return g_strdup_printf ("%s %s (snmp://%s@%s:%d/%s)",
  151                 reader->label,
  152                 reader->session ? reader->error : "Unknown host",
  153                 reader->community,
  154                 reader->peer, reader->port,
  155                 reader->oid_str );
  156 }
  157 
  158 gchar *
  159 render_label(Reader *reader)
  160 {
  161     u_long since_last = 0;
  162     u_long val;
  163 
  164     /* 100: turn TimeTicks into seconds */
  165     since_last = (reader->sample_time - reader->old_sample_time) / 100;
  166 
  167     /* short-cut if only binary data present */
  168     if (reader->asn1_type == ASN_OCTET_STR) {
  169     return g_strdup_printf ("%s %s%s",
  170                 reader->label,
  171                 reader->sample,
  172                 reader->unit);
  173     }
  174 
  175     /* pretty print Uptime */
  176     if (reader->asn1_type == ASN_TIMETICKS) {
  177     return strdup_uptime (reader->sample_n);
  178     }
  179 
  180     if (reader->delta)
  181     val = (reader->sample_n - reader->old_sample_n) /
  182         ( (since_last < 1) ? 1 : since_last ) /
  183         ( (reader->divisor == 0) ? 1 : reader->divisor );
  184     else
  185     val = reader->sample_n / 
  186         ( (reader->divisor == 0) ? 1 : reader->divisor );
  187 
  188     if (reader->scale)
  189     return g_strdup_printf ("%s %s%s",
  190                 reader->label,
  191                 scale(val),
  192                 reader->unit);
  193     else
  194     return g_strdup_printf ("%s %ld%s",
  195                 reader->label,
  196                 val,
  197                 reader->unit);
  198 }
  199 
  200 gchar *
  201 render_info(Reader *reader)
  202 {
  203     u_long since_last = 0;
  204     u_long delta;
  205     gint up_d, up_h, up_m;
  206     
  207     /* 100: turn TimeTicks into seconds */
  208     since_last = (reader->sample_time - reader->old_sample_time) / 100;
  209 
  210     up_d = reader->sample_time/100/60/60/24;
  211     up_h = (reader->sample_time/100/60/60) % 24;
  212     up_m = (reader->sample_time/100/60) % 60;
  213 
  214     delta = (reader->sample_n - reader->old_sample_n) /
  215         ( (since_last < 1) ? 1 : since_last );
  216 
  217     return g_strdup_printf ("%s '%s' %ld (%ld s: %ld /%d =%ld) %s  (snmp://%s@%s:%d/%s) Uptime: %dd %d:%d",
  218                 reader->label,
  219                 reader->sample,
  220                 reader->sample_n,
  221                 since_last,
  222                 delta,
  223                 reader->divisor, 
  224                 delta / ( (reader->divisor == 0) ? 1 : reader->divisor ), 
  225                 reader->unit, 
  226                 reader->community,
  227                 reader->peer, reader->port,
  228                 reader->oid_str,
  229                 up_d, up_h, up_m );
  230 }
  231 
  232 #ifdef UCDSNMP_PRE_4_2
  233 
  234 /*
  235  * snmp_parse_args.c
  236  */
  237 
  238 oid
  239 *snmp_parse_oid(const char *argv,
  240         oid *root,
  241         size_t *rootlen)
  242 {
  243   size_t savlen = *rootlen;
  244   /* printf("parse_oid: read_objid\n"); */
  245   if (read_objid(argv,root,rootlen)) {
  246     return root;
  247   }
  248   *rootlen = savlen;
  249   /* printf("parse_oid: get_node\n"); */
  250   if (get_node(argv,root,rootlen)) {
  251     return root;
  252   }
  253   *rootlen = savlen;
  254   /* printf("parse_oid: wildly parsing\n"); */
  255   if (get_wild_node(argv,root,rootlen)) {
  256     return root;
  257   }
  258   return NULL;
  259 }
  260 
  261 #endif
  262 
  263 gchar *
  264 snmp_probe(gchar *peer, gint port, gchar *community)
  265 {
  266     oid sysDescr[MAX_OID_LEN];
  267     size_t sysDescr_length;
  268     oid sysObjectID[MAX_OID_LEN];
  269     size_t sysObjectID_length;
  270     oid sysUpTime[MAX_OID_LEN];
  271     size_t sysUpTime_length;
  272     oid sysContact[MAX_OID_LEN];
  273     size_t sysContact_length;
  274     oid sysName[MAX_OID_LEN];
  275     size_t sysName_length;
  276     oid sysLocation[MAX_OID_LEN];
  277     size_t sysLocation_length;
  278 
  279     struct snmp_session session, *ss;
  280     struct snmp_pdu *pdu, *response;
  281     struct variable_list *vars;
  282 
  283     int count;
  284     int status;
  285 
  286     char textbuf[1024]; 
  287     char *result = NULL;
  288     char *tmp = NULL;
  289 
  290     /* transform interesting OIDs */
  291     sysDescr_length = MAX_OID_LEN;
  292     if (!snmp_parse_oid("system.sysDescr.0", sysDescr, &sysDescr_length))
  293         printf("error parsing oid: system.sysDescr.0\n");
  294 
  295     sysObjectID_length = MAX_OID_LEN;
  296     if (!snmp_parse_oid("system.sysObjectID.0", sysObjectID, &sysObjectID_length))
  297         printf("error parsing oid: system.sysObjectID.0\n");
  298 
  299     sysUpTime_length = MAX_OID_LEN;
  300     if (!snmp_parse_oid("system.sysUpTime.0", sysUpTime, &sysUpTime_length))
  301         printf("error parsing oid: system.sysUpTime.0\n");
  302 
  303     sysContact_length = MAX_OID_LEN;
  304     if (!snmp_parse_oid("system.sysContact.0", sysContact, &sysContact_length))
  305         printf("error parsing oid: system.sysContact.0\n");
  306 
  307     sysName_length = MAX_OID_LEN;
  308     if (!snmp_parse_oid("system.sysName.0", sysName, &sysName_length))
  309         printf("error parsing oid: system.sysName.0\n");
  310 
  311     sysLocation_length = MAX_OID_LEN;
  312     if (!snmp_parse_oid("system.sysLocation.0", sysLocation, &sysLocation_length))
  313         printf("error parsing oid: system.sysLocation.0\n");
  314 
  315     /* initialize session to default values */
  316     snmp_sess_init( &session );
  317 
  318     session.version = SNMP_VERSION_1;
  319     session.community = community;
  320     session.community_len = strlen(community);
  321     session.peername = peer;
  322 
  323 #ifdef STREAM
  324     session.flags |= SNMP_FLAGS_STREAM_SOCKET;
  325     fprintf (stderr, "local port set to: %d\n", session.local_port);
  326 #endif
  327 
  328     /* 
  329      * Open an SNMP session.
  330      */
  331     ss = snmp_open(&session);
  332     if (ss == NULL){
  333       fprintf (stderr, "local port set to: %d\n", session.local_port);
  334       snmp_sess_perror("snmp_open", &session);
  335       exit(1);
  336     }
  337 
  338     /* 
  339      * Create PDU for GET request and add object names to request.
  340      */
  341     pdu = snmp_pdu_create(SNMP_MSG_GET);
  342 
  343     snmp_add_null_var(pdu, sysDescr, sysDescr_length);
  344     snmp_add_null_var(pdu, sysObjectID, sysObjectID_length);
  345     snmp_add_null_var(pdu, sysUpTime, sysUpTime_length);
  346     snmp_add_null_var(pdu, sysContact, sysContact_length);
  347     snmp_add_null_var(pdu, sysName, sysName_length);
  348     snmp_add_null_var(pdu, sysLocation, sysLocation_length);
  349 
  350     /* 
  351      * Perform the request.
  352      *
  353      * If the Get Request fails, note the OID that caused the error,
  354      * "fix" the PDU (removing the error-prone OID) and retry.
  355      */
  356 retry:
  357     status = snmp_synch_response(ss, pdu, &response);
  358     if (status == STAT_SUCCESS){
  359       if (response->errstat == SNMP_ERR_NOERROR){
  360         /* just render all vars */
  361         for(vars = response->variables; vars; vars = vars->next_variable) {
  362         snprint_variable(textbuf, 1023, vars->name, vars->name_length, vars);
  363         textbuf[1023] = '\0';
  364         if (result) {
  365             tmp = result;
  366         result = g_strdup_printf("%s\n%s\n", tmp, textbuf);
  367         g_free(tmp);
  368         } else {
  369         result = g_strdup_printf("%s\n", textbuf);
  370         }
  371     }
  372                               
  373       } else {
  374         fprintf(stderr, "Error in packet\nReason: %s\n",
  375                 snmp_errstring(response->errstat));
  376 
  377         if (response->errstat == SNMP_ERR_NOSUCHNAME){
  378           fprintf(stderr, "This name doesn't exist: ");
  379           for(count = 1, vars = response->variables; 
  380                 vars && count != response->errindex;
  381                 vars = vars->next_variable, count++)
  382             /*EMPTY*/ ;
  383           if (vars)
  384             fprint_objid(stderr, vars->name, vars->name_length);
  385           fprintf(stderr, "\n");
  386         }
  387 
  388         /* retry if the errored variable was successfully removed */
  389         pdu = snmp_fix_pdu(response, SNMP_MSG_GET);
  390         snmp_free_pdu(response);
  391         response = NULL;
  392         if (pdu != NULL)
  393           goto retry;
  394 
  395       }  /* endif -- SNMP_ERR_NOERROR */
  396 
  397     } else if (status == STAT_TIMEOUT){
  398         snmp_close(ss);
  399         return g_strdup_printf("Timeout: No Response from %s.\n", session.peername);
  400 
  401     } else {    /* status == STAT_ERROR */
  402       fprintf (stderr, "local port set to: %d\n", session.local_port);
  403       snmp_sess_perror("STAT_ERROR", ss);
  404       snmp_close(ss);
  405       return NULL;
  406 
  407     }  /* endif -- STAT_SUCCESS */
  408 
  409     if (response)
  410       snmp_free_pdu(response);
  411     snmp_close(ss);
  412 
  413     return result;
  414 }
  415          
  416 int
  417 snmp_input(int op,
  418        struct snmp_session *session,
  419        int reqid,
  420        struct snmp_pdu *pdu,
  421        void *magic)
  422 {
  423     struct variable_list *vars;
  424     gint asn1_type = 0;
  425     gchar *result = NULL;
  426     u_long result_n = 0;
  427 
  428     gchar *error = NULL;
  429     u_long time = 0;
  430     Reader *reader = NULL;
  431 
  432     if (op == RECEIVED_MESSAGE) {
  433 
  434         if (pdu->errstat == SNMP_ERR_NOERROR) {
  435 
  436         /*
  437         fprintf(stderr, "recv from (@ %ld): %s type: %d\n",
  438                 pdu->time, session->peername, pdu->variables->type);
  439         */
  440 
  441             for(vars = pdu->variables; vars; vars = vars->next_variable) {
  442                 switch (vars->type) {
  443         case ASN_TIMETICKS:
  444             time = *vars->val.integer;
  445             break;
  446         case ASN_OCTET_STR: /* value is a string */
  447             asn1_type = ASN_OCTET_STR;
  448             result = g_strndup(vars->val.string, vars->val_len);
  449             break;
  450         case ASN_INTEGER: /* value is a integer */
  451         case ASN_COUNTER: /* use as if it were integer */
  452         case ASN_UNSIGNED: /* use as if it were integer */
  453             asn1_type = ASN_INTEGER;
  454             result_n = *vars->val.integer;
  455             result = g_strdup_printf("%ld", *vars->val.integer);
  456             break;
  457         default:
  458             fprintf(stderr, "recv unknown ASN type: %d - please report to zany@triq.net\n", vars->type);
  459         }
  460         }
  461                               
  462         } else {
  463             error = g_strdup_printf("Error in packet\nReason: %s",
  464                      snmp_errstring(pdu->errstat));
  465 
  466         if (pdu->errstat == SNMP_ERR_NOSUCHNAME) {
  467         error = g_strdup_printf("Error! This name doesn't exist!");
  468             }
  469         }
  470 
  471 
  472     } else if (op == TIMED_OUT){
  473         error = g_strdup_printf("Error! SNMP Timeout.");
  474     }
  475     /* we use session's callback magic to pass back data */
  476     if (session->callback_magic) {
  477     reader = session->callback_magic;
  478     if (error) {
  479         if (reader->error)
  480         g_free(reader->error);
  481         reader->error = error;
  482     } else {
  483         if (reader->error)
  484         {
  485         g_free (reader->error);
  486         reader->error = NULL;
  487         }
  488         if (reader->sample)
  489         g_free(reader->sample);
  490         /* should we save data ? */
  491         /*
  492         if (reader->old_sample)
  493         g_free(reader->old_sample);
  494         reader->old_sample = reader->sample;
  495         reader->old_sample-time = reader->sample_time;
  496         */
  497         reader->asn1_type = asn1_type;
  498         reader->sample = result;
  499         reader->sample_n = result_n;
  500         reader->sample_time = time;
  501 
  502         if (strcmp(reader->oid_str, "sysUpTime.0") == 0) {
  503             reader->asn1_type = ASN_TIMETICKS;
  504             reader->sample_n = time;
  505         reader->sample=  strdup_uptime (time);
  506         }
  507     }
  508     }
  509     return 1;
  510 }
  511 
  512 void
  513 simpleSNMPupdate()
  514 {
  515     int count;
  516     int numfds, block;
  517     fd_set fdset;
  518     struct timeval timeout, *tvp;
  519 
  520     numfds = 0;
  521     FD_ZERO(&fdset);
  522     block = 0;
  523     tvp = &timeout;
  524     timerclear(tvp);
  525     tvp->tv_sec = 0;
  526     snmp_select_info(&numfds, &fdset, tvp, &block);
  527     /*        if (block == 1)
  528           tvp = NULL; */ /* block without timeout */
  529     count = select(numfds, &fdset, 0, 0, tvp);
  530     if (count > 0){
  531         snmp_read(&fdset);
  532     } else switch(count){
  533         case 0:
  534             snmp_timeout();
  535         break;
  536         case -1:
  537         fprintf(stderr, "snmp error on select\n");
  538         break;
  539         default:
  540             fprintf(stderr, "select returned %d\n", count);
  541     }
  542 }
  543 
  544 struct snmp_session *
  545 simpleSNMPopen(gchar *peername,
  546            gint port,
  547            gchar *community,
  548            void *data)
  549 {
  550     struct snmp_session session, *ss;
  551 
  552     /*
  553      * initialize session to default values
  554      */
  555     snmp_sess_init( &session );
  556 
  557     session.version = SNMP_VERSION_1;
  558     session.community = community;
  559     session.community_len = strlen(community);
  560     session.peername = peername;
  561     session.remote_port = port;
  562 
  563     session.retries = SNMP_DEFAULT_RETRIES;
  564     session.timeout = SNMP_DEFAULT_TIMEOUT;
  565 
  566     session.callback = snmp_input;
  567     session.callback_magic = data; /* most likely a Reader */
  568     session.authenticator = NULL;
  569 
  570 #ifdef STREAM
  571     session.flags |= SNMP_FLAGS_STREAM_SOCKET;
  572 #endif
  573 
  574     /* 
  575      * Open an SNMP session.
  576      */
  577     ss = snmp_open(&session);
  578     if (ss == NULL){
  579         snmp_sess_perror("snmp_open", &session);
  580         // exit(1);
  581     }
  582 
  583     return ss;
  584 }
  585 
  586 void
  587 simpleSNMPsend(struct snmp_session *session,
  588            oid *name,
  589            size_t name_length)
  590 {
  591     struct snmp_pdu *pdu;
  592     oid uptime[MAX_OID_LEN];
  593     size_t uptime_length;
  594 
  595     /* 
  596      * Create PDU for GET request and add object names to request.
  597      */
  598     pdu = snmp_pdu_create(SNMP_MSG_GET);
  599 
  600     /* 
  601      * First insert uptime request into PDU.
  602      */
  603     uptime_length = MAX_OID_LEN;
  604     if (!snmp_parse_oid("system.sysUpTime.0",
  605             uptime, &uptime_length)) {
  606         printf("error parsing oid: system.sysUpTime.0\n");
  607     }
  608     snmp_add_null_var(pdu, uptime, uptime_length);
  609 
  610     snmp_add_null_var(pdu, name, name_length);
  611 
  612     /* 
  613      * Perform the request.
  614      */
  615 
  616     snmp_send(session, pdu);
  617 }
  618 
  619 
  620 /* GKrellM Callbacks */
  621 
  622 static void
  623 cb_draw_chart(gpointer data)
  624 {
  625     Reader *reader = (Reader *)data;
  626 
  627     gchar *text = render_label(reader);
  628     gkrellm_draw_chartdata(reader->chart);
  629     gkrellm_draw_chart_text(reader->chart,
  630                 DEFAULT_STYLE_ID,
  631                 text);
  632     gkrellm_draw_chart_to_screen(reader->chart);
  633     g_free(text);
  634 }
  635 
  636 static void
  637 cb_chart_click(GtkWidget *widget, GdkEventButton *event, gpointer data)
  638     {
  639         if (event->button == 3)
  640             gkrellm_chartconfig_window_create(data);
  641     }
  642 
  643 /* GKrellM interface */
  644  
  645 static GkrellmMonitor *mon;
  646 static Reader *readers;
  647 static GtkWidget *main_vbox;
  648 
  649 static void
  650 update_plugin()
  651 {
  652     Reader *reader;
  653     gchar  *text;
  654     u_long val, since_last;
  655     gint clock_style_id;
  656     //  GkrellmKrell       *k;
  657     //  gint i;
  658 
  659     /* See if we recieved SNMP responses */
  660     simpleSNMPupdate();
  661 
  662     /* Send new SNMP requests */
  663     for (reader = readers; reader ; reader = reader->next)
  664     {
  665         //      k = KRELL(panel);
  666     //      k->previous = 0;
  667 
  668     if ( (! reader->session) && (! reader->old_error) ) {
  669         reader->session = simpleSNMPopen(reader->peer,
  670                          reader->port,
  671                          reader->community,
  672                          reader);
  673         if (! reader->session) {
  674         text = reader->old_error;
  675         reader->old_error = render_error(reader);
  676         g_free(text);
  677         }
  678     }
  679 
  680     /* Send new SNMP requests */
  681     if ( (reader->session) && ((GK.timer_ticks % reader->delay) == 0))
  682         simpleSNMPsend(reader->session,
  683                reader->objid,
  684                reader->objid_length);
  685 
  686 
  687     if ( (reader->session) && (reader->sample) ) {
  688         if ((reader->error) && (reader->panel != NULL)) {
  689             if (!reader->old_error ||
  690             strcmp(reader->error,
  691                reader->old_error) ) {
  692             text = reader->old_error;
  693             reader->old_error = g_strdup(reader->error);
  694             g_free(text);
  695             reader->panel->textstyle = gkrellm_panel_alt_textstyle(DEFAULT_STYLE_ID);
  696             text = render_error(reader);
  697             gtk_tooltips_set_tip(reader->tooltip, reader->panel->drawing_area, text, "");
  698             gtk_tooltips_enable(reader->tooltip);
  699             g_free(text);
  700         }
  701         } else {
  702             if ((GK.timer_ticks % reader->delay) == 0)
  703                 if (reader->chart != NULL)
  704                 {
  705     /* 100: turn TimeTicks into seconds */
  706     since_last = (reader->sample_time - reader->old_sample_time) / 100;
  707     
  708     if (reader->delta)
  709     val = (reader->sample_n - reader->old_sample_n) /
  710         ( (since_last < 1) ? 1 : since_last ) /
  711         ( (reader->divisor == 0) ? 1 : reader->divisor );
  712     else
  713     val = reader->sample_n / 
  714         ( (reader->divisor == 0) ? 1 : reader->divisor );
  715         
  716                     gkrellm_store_chartdata(reader->chart, 0, val);
  717                     cb_draw_chart(reader);
  718 
  719                     text = render_info(reader);
  720                     gtk_tooltips_set_tip(reader->tooltip, reader->chart->drawing_area, text, "");
  721                     gtk_tooltips_enable(reader->tooltip);
  722                     g_free(text);
  723 
  724                         reader->old_sample_n = reader->sample_n;
  725                     reader->old_sample_time = reader->sample_time;
  726                 }
  727 
  728             /* if there are changes update label */
  729         if (reader->panel != NULL)
  730         {
  731             reader->panel->textstyle = gkrellm_panel_textstyle(DEFAULT_STYLE_ID);
  732         if ( !reader->old_sample || strcmp(reader->sample,
  733                            reader->old_sample) ||
  734              (reader->sample_n != reader->old_sample_n) ) {
  735 
  736             g_free(reader->old_sample);
  737             reader->old_sample = g_strdup(reader->sample);
  738 
  739             text = render_label(reader);
  740             gkrellm_dup_string(&reader->panel->label->string, text);
  741             g_free(text);
  742             //  i = atoi(text);
  743 
  744             text = render_info(reader);
  745             gtk_tooltips_set_tip(reader->tooltip, reader->panel->drawing_area, text, "");
  746             gtk_tooltips_enable(reader->tooltip);
  747 
  748             g_free(text);
  749             reader->old_sample_n = reader->sample_n;
  750             reader->old_sample_time = reader->sample_time;
  751         }
  752         }
  753         }
  754 
  755     } else {
  756         if (reader->panel != NULL)
  757         reader->panel->textstyle = gkrellm_panel_alt_textstyle(DEFAULT_STYLE_ID);
  758         if (reader->panel != NULL)
  759         gtk_tooltips_disable(reader->tooltip);
  760         //  i = -1;
  761     }
  762       
  763     //      gkrellm_update_krell(panel, k, i);
  764 
  765     clock_style_id = gkrellm_lookup_meter_style_id(CLOCK_STYLE_NAME);
  766 
  767         if (reader->panel != NULL)
  768     gkrellm_draw_panel_label( reader->panel );
  769                 //GTK2 gkrellm_bg_panel_piximage(clock_style_id) );
  770         if (reader->panel != NULL)
  771     gkrellm_draw_panel_layers(reader->panel);
  772     }
  773 
  774 }
  775 
  776 static gint
  777 panel_expose_event(GtkWidget *widget, GdkEventExpose *ev)
  778 {
  779     Reader *reader;
  780 
  781     for (reader = readers; reader ; reader = reader->next)
  782         if ((reader->panel) && (widget == reader->panel->drawing_area)) {
  783 
  784         gdk_draw_pixmap(widget->window,
  785                 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
  786                 reader->panel->pixmap,
  787                 ev->area.x, ev->area.y, ev->area.x, ev->area.y,
  788                 ev->area.width, ev->area.height);
  789     }
  790     return FALSE;
  791 }
  792 
  793 static gint
  794 chart_expose_event(GtkWidget *widget, GdkEventExpose *ev)
  795 {
  796     Reader *reader;
  797 
  798     for (reader = readers; reader ; reader = reader->next)
  799         if ((reader->chart) && (widget == reader->chart->drawing_area)) {
  800 
  801         gdk_draw_pixmap(widget->window,
  802                 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
  803                 reader->chart->pixmap,
  804                 ev->area.x, ev->area.y, ev->area.x, ev->area.y,
  805                 ev->area.width, ev->area.height);
  806     }
  807     return FALSE;
  808 }
  809 
  810 static void
  811 create_chart(GtkWidget *vbox, Reader *reader, gint first_create)
  812 {
  813     if (first_create)
  814         reader->chart = gkrellm_chart_new0();
  815 
  816 //    gkrellm_set_chart_height_default(reader->chart, 20);
  817 
  818     gkrellm_chart_create(vbox, mon, reader->chart, &reader->chart_config);
  819 
  820     gkrellm_chartconfig_grid_resolution_adjustment(reader->chart_config,
  821                 /*map*/TRUE, /*spin_factor*/1.0, /*low*/1, /*high*/100000000,
  822             /*step0*/0, /*step1*/0, /*digits*/0, /*width*/50);
  823 
  824     reader->chart_data = gkrellm_add_default_chartdata(reader->chart, "Plugin Data");
  825     
  826     gkrellm_monotonic_chartdata(reader->chart_data, FALSE);
  827 
  828     gkrellm_set_chartdata_draw_style_default(reader->chart_data, CHARTDATA_LINE);
  829     gkrellm_set_chartdata_flags(reader->chart_data, CHARTDATA_ALLOW_HIDE);
  830 
  831     gkrellm_alloc_chartdata(reader->chart);
  832 
  833     if (first_create)
  834     {
  835             gkrellm_set_draw_chart_function(reader->chart, cb_draw_chart, reader);
  836         gtk_signal_connect(GTK_OBJECT(reader->chart->drawing_area),
  837                    "expose_event", (GtkSignalFunc) chart_expose_event, NULL);
  838         gtk_signal_connect(GTK_OBJECT(reader->chart->drawing_area),
  839                    "button_press_event", (GtkSignalFunc) cb_chart_click, reader->chart);
  840         reader->tooltip=gtk_tooltips_new();
  841     }
  842     else
  843     {
  844         gkrellm_draw_chartdata(reader->chart);
  845         gkrellm_draw_chart_to_screen(reader->chart);
  846     }
  847 
  848 }
  849 
  850 static void
  851 create_panel(GtkWidget *vbox, Reader *reader, gint first_create)
  852 {
  853       //    GkrellmKrell           *k;
  854     GkrellmStyle           *style;
  855     //    GkrellmPiximage   *krell_piximage;
  856     gchar *text;
  857 
  858     if (first_create)
  859         reader->panel = gkrellm_panel_new0();
  860     else
  861         gkrellm_destroy_krell_list(reader->panel);
  862 
  863     /* Create a krell.  A Krell structure is allocated and linked into
  864     |  the list of krells pointed to by panel->krell.
  865     */
  866     style = gkrellm_meter_style(DEFAULT_STYLE_ID);
  867     //GTK2 style->label_position = LABEL_CENTER;
  868     //    krell_piximage = gkrellm_krell_meter_piximage(DEFAULT_STYLE_ID);
  869     //    k = gkrellm_create_krell(panel, krell_piximage, style);
  870     //    k->full_scale = 30;
  871 
  872     /* Configure panel calculates the panel height needed for the "Plugin" label.
  873     |  and the krell.
  874     */
  875     reader->panel->textstyle = gkrellm_meter_textstyle(DEFAULT_STYLE_ID);
  876     gkrellm_panel_configure(reader->panel, "SNMP", style);
  877 
  878     //    reader->panel->textstyle = gkrellm_panel_alt_textstyle(DEFAULT_STYLE_ID);
  879 
  880 
  881     /* Build the configured panel with a background image and pack it into
  882     |  the vbox assigned to this monitor.
  883     */
  884 //dep:    gkrellm_create_panel(vbox, reader->panel, gkrellm_bg_meter_piximage(DEFAULT_STYLE_ID));
  885     gkrellm_panel_create(vbox, mon, reader->panel);
  886     gkrellm_monitor_height_adjust(reader->panel->h);
  887 
  888     if (first_create) {
  889         gtk_signal_connect(GTK_OBJECT (reader->panel->drawing_area),
  890                "expose_event",
  891                (GtkSignalFunc) panel_expose_event, NULL);
  892     reader->tooltip=gtk_tooltips_new();
  893     }
  894 
  895     /* refresh the display */
  896     text = render_label(reader);
  897     gkrellm_dup_string(&reader->panel->label->string, text);
  898     g_free(text);
  899 }
  900 
  901 static void
  902 create_reader(GtkWidget *vbox, Reader *reader, gint first_create)
  903 {
  904     if (1) /* FIXME */
  905         create_chart(vbox, reader, first_create);
  906     else
  907         create_panel(vbox, reader, first_create);
  908 }
  909 
  910 static void
  911 destroy_reader(Reader *reader)
  912 {
  913     if (!reader)
  914         return;
  915 
  916     reader->session->callback_magic = 0; /* detach the callback */
  917     g_free(reader->label);
  918     g_free(reader->peer);
  919     g_free(reader->community);
  920     g_free(reader->oid_str);
  921     g_free(reader->unit);
  922 
  923     g_free(reader->sample);
  924     g_free(reader->old_sample);
  925 
  926     /* can't free snmp session. may be there are pending snmp_reads! */
  927     /*
  928     if (reader->session)
  929         snmp_close(reader->session);
  930     g_free(reader->session);
  931     */
  932   
  933     if (reader->panel)
  934     {
  935         gkrellm_monitor_height_adjust( - reader->panel->h);
  936         gkrellm_panel_destroy(reader->panel);
  937     }
  938 
  939     if (reader->chart)
  940     {
  941         gkrellm_monitor_height_adjust( - reader->chart->h);
  942         gkrellm_chartconfig_destroy(&reader->chart_config);
  943         gkrellm_chart_destroy(reader->chart);
  944     }
  945 
  946     //  gtk_widget_destroy(reader->vbox);
  947     g_free(reader);
  948 }
  949 
  950 static void
  951 create_plugin(GtkWidget *vbox, gint first_create)
  952 {
  953   Reader *reader;
  954 
  955   main_vbox = vbox;
  956 
  957   for (reader = readers; reader ; reader = reader->next) {
  958       create_reader(vbox, reader, first_create);
  959   }
  960 }
  961 
  962 /* Config section */
  963 
  964 static GtkWidget        *label_entry;
  965 static GtkWidget        *peer_entry;
  966 static GtkObject        *port_spin_adj;
  967 static GtkWidget        *port_spin;
  968 static GtkWidget        *community_entry;
  969 static GtkWidget        *oid_entry;
  970 static GtkWidget        *unit_entry;
  971 static GtkObject        *freq_spin_adj;
  972 static GtkWidget        *freq_spin;
  973 static GtkObject        *div_spin_adj;
  974 static GtkWidget        *div_spin;
  975 static GtkWidget        *delta_button;
  976 static GtkWidget        *scale_button;
  977 static GtkWidget        *reader_clist;
  978 static gint             selected_row = -1;
  979 static gint             list_modified;
  980 #define CLIST_WIDTH 11
  981 
  982 #define  STR_DELIMITERS " \t"
  983 
  984 static void
  985 save_plugin_config(FILE *f)
  986 {
  987   Reader *reader;
  988   gchar *label, *unit;
  989 
  990   for (reader = readers; reader ; reader = reader->next) {
  991       label = g_strdelimit(g_strdup(reader->label), STR_DELIMITERS, '_');
  992       unit = g_strdelimit(g_strdup(reader->unit), STR_DELIMITERS, '_');
  993       if (label[0] == '\0') label = strdup("_");
  994       if (unit[0] == '\0') unit = strdup("_");
  995       fprintf(f, "%s %s snmp://%s@%s:%d/%s %s %d %d %d %d\n",
  996           PLUGIN_CONFIG_KEYWORD,
  997           label, reader->community,
  998           reader->peer, reader->port,
  999           reader->oid_str, unit,
 1000           reader->delay, reader->delta,
 1001           reader->divisor, reader->scale);
 1002       gkrellm_save_chartconfig(f, reader->chart_config, PLUGIN_CONFIG_KEYWORD, label);
 1003       g_free(label);
 1004       g_free(unit);
 1005   }
 1006 }
 1007 
 1008 static void
 1009 load_plugin_config(gchar *config_line)
 1010 {
 1011   Reader *reader, *nreader = NULL;
 1012 
 1013   gchar   proto[CFG_BUFSIZE], bufl[CFG_BUFSIZE];
 1014   gchar   bufc[CFG_BUFSIZE], bufp[CFG_BUFSIZE];
 1015   gchar   bufo[CFG_BUFSIZE], bufu[CFG_BUFSIZE];
 1016   gchar   buft[CFG_BUFSIZE], peer[CFG_BUFSIZE];
 1017   gint    n;
 1018 
 1019   if (sscanf(config_line, GKRELLM_CHARTCONFIG_KEYWORD " %s %[^\n]", bufl, bufc) == 2) {
 1020     g_strdelimit(bufl, "_", ' ');
 1021     /* look for any such reader */
 1022     for (reader = readers; reader ; reader = reader->next) {
 1023         if (!strcmp(reader->label, bufl)) {
 1024             nreader = reader;
 1025             break;
 1026         }
 1027     }
 1028     /* look for unconf'd reader */
 1029     for (reader = readers; reader ; reader = reader->next) {
 1030         if (!strcmp(reader->label, bufl) && !reader->chart_config) {
 1031             nreader = reader;
 1032             break;
 1033         }
 1034     }
 1035     if (!nreader) {/* well... */
 1036         fprintf(stderr, "chart_config appeared before chart, this isn't handled\n%s\n", config_line);
 1037         return;
 1038     }
 1039     //"chart_config in "
 1040     gkrellm_load_chartconfig(&nreader->chart_config, bufc, /*max_cd*/1);
 1041     return;
 1042   }
 1043   
 1044   reader = g_new0(Reader, 1); 
 1045 
 1046   n = sscanf(config_line, "%s %[^:]://%[^@]@%[^:]:%[^:]:%d/%s %s %d %d %d %d",
 1047          bufl, proto, bufc, buft, bufp, &reader->port, bufo, bufu,
 1048          &reader->delay, &reader->delta,
 1049          &reader->divisor, &reader->scale);
 1050   if (n >= 6) {
 1051     g_snprintf(peer, CFG_BUFSIZE, "%s:%s", buft, bufp);
 1052     peer[CFG_BUFSIZE-1] = '\0';
 1053   } else
 1054       n = sscanf(config_line, "%s %[^:]://%[^@]@%[^:]:%d/%s %s %d %d %d %d",
 1055          bufl, proto, bufc, peer, &reader->port, bufo, bufu,
 1056          &reader->delay, &reader->delta,
 1057          &reader->divisor, &reader->scale);
 1058   if (n >= 7)
 1059     {
 1060       if (g_strcasecmp(proto, "snmp") == 0) {
 1061     gkrellm_dup_string(&reader->label, bufl);
 1062     gkrellm_dup_string(&reader->community, bufc);
 1063     gkrellm_dup_string(&reader->peer, peer);
 1064     if (reader->delay < 10)
 1065         reader->delay = 100;
 1066     if (reader->divisor == 0)
 1067         reader->divisor = 1;
 1068 
 1069     gkrellm_dup_string(&reader->oid_str, bufo);
 1070 
 1071     reader->objid_length = MAX_OID_LEN;
 1072     if (!snmp_parse_oid(reader->oid_str,
 1073                 reader->objid, &reader->objid_length)) {
 1074 //FIXME:
 1075         printf("error parsing oid: %s\n", reader->oid_str);
 1076     }
 1077 
 1078     if (n > 7) {
 1079         gkrellm_dup_string(&reader->unit, bufu);
 1080     } else {
 1081         gkrellm_dup_string(&reader->unit, "");
 1082     }
 1083 
 1084     g_strdelimit(reader->label, "_", ' ');
 1085     g_strdelimit(reader->unit, "_", ' ');
 1086 
 1087     // reader->old_sample = "SNMP"; // be nice.
 1088       }
 1089 
 1090       if (!readers)
 1091       readers = reader;
 1092       else { 
 1093       for (nreader = readers; nreader->next ; nreader = nreader->next);
 1094       nreader->next = reader;
 1095       }
 1096 
 1097     }
 1098 }
 1099 
 1100 static void
 1101 apply_plugin_config()
 1102 {
 1103   Reader *reader, *nreader;
 1104   gchar  *name;
 1105   gint   row;
 1106 
 1107   if (!list_modified)
 1108     return;
 1109 
 1110   for (reader = readers; reader; reader = readers) {
 1111     readers = reader->next;
 1112     destroy_reader(reader);
 1113   }
 1114 
 1115   for (row = 0; row < GTK_CLIST(reader_clist)->rows; ++row)
 1116     {
 1117       gint i;
 1118       i = 0;
 1119       reader = g_new0(Reader, 1);
 1120 
 1121       gtk_clist_get_text(GTK_CLIST(reader_clist), row, i++, &name);
 1122       gkrellm_dup_string(&reader->label, name);
 1123 
 1124       gtk_clist_get_text(GTK_CLIST(reader_clist), row, i++, &name);
 1125       gkrellm_dup_string(&reader->peer, name);
 1126 
 1127       gtk_clist_get_text(GTK_CLIST(reader_clist), row, i++, &name);
 1128       reader->port = atoi(name);
 1129 
 1130       gtk_clist_get_text(GTK_CLIST(reader_clist), row, i++, &name);
 1131       gkrellm_dup_string(&reader->community, name);
 1132 
 1133       gtk_clist_get_text(GTK_CLIST(reader_clist), row, i++, &name);
 1134       gkrellm_dup_string(&reader->oid_str, name);
 1135       reader->objid_length = MAX_OID_LEN;
 1136       if (!snmp_parse_oid(reader->oid_str,
 1137               reader->objid, &reader->objid_length)) {
 1138 //FIXME:
 1139       printf("error parsing oid: %s\n", reader->oid_str);
 1140       }
 1141 
 1142       gtk_clist_get_text(GTK_CLIST(reader_clist), row, i++, &name);
 1143       gkrellm_dup_string(&reader->unit, name);
 1144 
 1145       gtk_clist_get_text(GTK_CLIST(reader_clist), row, i++, &name);
 1146       reader->delay = atoi(name);
 1147 
 1148       gtk_clist_get_text(GTK_CLIST(reader_clist), row, i++, &name);
 1149       reader->divisor = atoi(name);
 1150 
 1151       gtk_clist_get_text(GTK_CLIST(reader_clist), row, i++, &name);
 1152       reader->delta = (strcmp(name, "yes") == 0) ? TRUE : FALSE;
 1153 
 1154       gtk_clist_get_text(GTK_CLIST(reader_clist), row, i++, &name);
 1155       reader->scale = (strcmp(name, "yes") == 0) ? TRUE : FALSE;
 1156 
 1157       gtk_clist_get_text(GTK_CLIST(reader_clist), row, i++, &name);
 1158       reader->active = (strcmp(name, "yes") == 0) ? TRUE : FALSE;
 1159 
 1160       if (!readers)
 1161           readers = reader;
 1162       else { 
 1163       for (nreader = readers; nreader->next ; nreader = nreader->next);
 1164       nreader->next = reader;
 1165       }
 1166       create_reader(main_vbox, reader, 1);
 1167     }
 1168   list_modified = 0;
 1169 }
 1170 
 1171 
 1172 static void
 1173 reset_entries()
 1174 {
 1175   gtk_entry_set_text(GTK_ENTRY(label_entry), "");
 1176   gtk_entry_set_text(GTK_ENTRY(peer_entry), "");
 1177   // gtk_entry_set_text(GTK_ENTRY(port_entry), "");
 1178   gtk_entry_set_text(GTK_ENTRY(community_entry), "");
 1179   gtk_entry_set_text(GTK_ENTRY(oid_entry), "");
 1180   gtk_entry_set_text(GTK_ENTRY(unit_entry), "");
 1181   // gtk_entry_set_text(GTK_ENTRY(freq_entry), "");
 1182   // gtk_entry_set_text(GTK_ENTRY(div_entry), "");
 1183   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(delta_button), FALSE);
 1184   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(scale_button), TRUE);
 1185   // gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(active_button), FALSE);
 1186 }
 1187 
 1188 
 1189 static void
 1190 cb_clist_selected(GtkWidget *clist, gint row, gint column,
 1191           GdkEventButton *bevent)
 1192 {
 1193   gchar           *s;
 1194   gint            state, i;
 1195 
 1196   i = 0;
 1197   gtk_clist_get_text(GTK_CLIST(clist), row, i++, &s);
 1198   gtk_entry_set_text(GTK_ENTRY(label_entry), s);
 1199 
 1200   gtk_clist_get_text(GTK_CLIST(clist), row, i++, &s);
 1201   gtk_entry_set_text(GTK_ENTRY(peer_entry), s);
 1202 
 1203   gtk_clist_get_text(GTK_CLIST(clist), row, i++, &s);
 1204   gtk_entry_set_text(GTK_ENTRY(port_spin), s);
 1205   //  gtk_spin_button_get_value_as_int(GTK_SPINBUTTON(port_spin), 161);
 1206 
 1207   gtk_clist_get_text(GTK_CLIST(clist), row, i++, &s);
 1208   gtk_entry_set_text(GTK_ENTRY(community_entry), s);
 1209 
 1210   gtk_clist_get_text(GTK_CLIST(clist), row, i++, &s);
 1211   gtk_entry_set_text(GTK_ENTRY(oid_entry), s);
 1212 
 1213   gtk_clist_get_text(GTK_CLIST(clist), row, i++, &s);
 1214   gtk_entry_set_text(GTK_ENTRY(unit_entry), s);
 1215 
 1216   gtk_clist_get_text(GTK_CLIST(clist), row, i++, &s);
 1217   gtk_entry_set_text(GTK_ENTRY(freq_spin), s);
 1218 
 1219   gtk_clist_get_text(GTK_CLIST(clist), row, i++, &s);
 1220   gtk_entry_set_text(GTK_ENTRY(div_spin), s);
 1221 
 1222   gtk_clist_get_text(GTK_CLIST(clist), row, i++, &s);
 1223   state = (strcmp(s, "yes") == 0) ? TRUE : FALSE;
 1224   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(delta_button), state);
 1225 
 1226   gtk_clist_get_text(GTK_CLIST(clist), row, i++, &s);
 1227   state = (strcmp(s, "yes") == 0) ? TRUE : FALSE;
 1228   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(scale_button), state);
 1229 
 1230   gtk_clist_get_text(GTK_CLIST(clist), row, i++, &s);
 1231   state = (strcmp(s, "yes") == 0) ? TRUE : FALSE;
 1232   //  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(active_button), state);
 1233 
 1234   selected_row = row;
 1235 }
 1236 
 1237 static void
 1238 cb_clist_unselected(GtkWidget *clist, gint row, gint column,
 1239             GdkEventButton *bevent)
 1240 {
 1241   reset_entries();
 1242   selected_row = -1;
 1243 }
 1244 
 1245 static void
 1246 cb_clist_up(GtkWidget *widget)
 1247 {
 1248   gint            row;
 1249 
 1250   row = selected_row;
 1251   if (row > 0)
 1252     {
 1253       gtk_clist_row_move(GTK_CLIST(reader_clist), row, row - 1);
 1254       gtk_clist_select_row(GTK_CLIST(reader_clist), row - 1, -1);
 1255       if (gtk_clist_row_is_visible(GTK_CLIST(reader_clist), row - 1)
 1256       != GTK_VISIBILITY_FULL)
 1257     gtk_clist_moveto(GTK_CLIST(reader_clist), row - 1, -1, 0.0, 0.0);
 1258       selected_row = row - 1;
 1259       list_modified = TRUE;
 1260     }
 1261 }
 1262 
 1263 static void
 1264 cb_clist_down(GtkWidget *widget)
 1265 {
 1266   gint            row;
 1267 
 1268   row = selected_row;
 1269   if (row >= 0 && row < GTK_CLIST(reader_clist)->rows - 1)
 1270     {
 1271       gtk_clist_row_move(GTK_CLIST(reader_clist), row, row + 1);
 1272       gtk_clist_select_row(GTK_CLIST(reader_clist), row + 1, -1);
 1273       if (gtk_clist_row_is_visible(GTK_CLIST(reader_clist), row + 1)
 1274       != GTK_VISIBILITY_FULL)
 1275     gtk_clist_moveto(GTK_CLIST(reader_clist), row + 1, -1, 1.0, 0.0);
 1276       selected_row = row + 1;
 1277       list_modified = TRUE;
 1278     }
 1279 }
 1280 
 1281 static void
 1282 cb_enter(GtkWidget *widget)
 1283 {
 1284   gchar           *buf[CLIST_WIDTH];
 1285   gint            i;
 1286 
 1287   i = 0;
 1288   buf[i++] = gkrellm_gtk_entry_get_text(&label_entry);
 1289   buf[i++] = gkrellm_gtk_entry_get_text(&peer_entry);
 1290   buf[i++] = gkrellm_gtk_entry_get_text(&port_spin);
 1291   buf[i++] = gkrellm_gtk_entry_get_text(&community_entry);
 1292   buf[i++] = gkrellm_gtk_entry_get_text(&oid_entry);
 1293   buf[i++] = gkrellm_gtk_entry_get_text(&unit_entry);
 1294   buf[i++] = gkrellm_gtk_entry_get_text(&freq_spin);
 1295   buf[i++] = gkrellm_gtk_entry_get_text(&div_spin);
 1296   buf[i++] = GTK_TOGGLE_BUTTON(delta_button)->active ? "yes" : "no";
 1297   buf[i++] = GTK_TOGGLE_BUTTON(scale_button)->active ? "yes" : "no";
 1298   buf[i++] = "yes"; // GTK_TOGGLE_BUTTON(active_button)->active ? "yes" : "no";
 1299 
 1300   /* validate we have input */
 1301   if (!*(buf[1]) || !*(buf[2]) || !*(buf[3]) || !*(buf[4]))
 1302     {
 1303       gkrellm_config_message_dialog("Entry Error",
 1304                     "Peer, Port, Community and OID must be entered.");
 1305       return;
 1306     }
 1307   if (selected_row >= 0)
 1308     {
 1309       for (i = 0; i < CLIST_WIDTH; ++i)
 1310     gtk_clist_set_text(GTK_CLIST(reader_clist), selected_row, i, buf[i]);
 1311       gtk_clist_unselect_row(GTK_CLIST(reader_clist), selected_row, 0);
 1312       selected_row = -1;
 1313     }
 1314   else
 1315     gtk_clist_append(GTK_CLIST(reader_clist), buf);
 1316   reset_entries();
 1317   list_modified = TRUE;
 1318 }
 1319 
 1320 static void
 1321 cb_delete(GtkWidget *widget)
 1322 {
 1323   reset_entries();
 1324   if (selected_row >= 0)
 1325     {
 1326       gtk_clist_remove(GTK_CLIST(reader_clist), selected_row);
 1327       list_modified = TRUE;
 1328       selected_row = -1;
 1329     }
 1330 }
 1331 
 1332 static void
 1333 cb_probe(GtkWidget *widget)
 1334 {
 1335     gchar *peer;
 1336     gint port;
 1337     gchar *community;
 1338     gchar *probe;
 1339 
 1340     peer = gkrellm_gtk_entry_get_text(&peer_entry);
 1341     port = atoi(gkrellm_gtk_entry_get_text(&port_spin));
 1342     community = gkrellm_gtk_entry_get_text(&community_entry);
 1343 
 1344     /* validate we have input */
 1345     if (!*(peer) || !*(community))
 1346     {
 1347         gkrellm_config_message_dialog("Entry Error",
 1348             "Peer, Port and Community must be entered.");
 1349         return;
 1350     }
 1351     probe = snmp_probe(peer, port, community);
 1352     gkrellm_config_message_dialog("SNMP Probe", probe);
 1353     g_free(probe);
 1354 }
 1355 
 1356 
 1357 static gchar    *plugin_info_text =
 1358 "This configuration tab is for the SNMP monitor plugin.\n"
 1359 "\n"
 1360 "Adding new SNMP readers should be fairly easy.\n"
 1361 "Peer, Port, Community and OID are the respective SNMP parameters.\n"
 1362 "Whereas Port ist preselected with the default value 161.\n"
 1363 "Freq sets the delay between updates of the reader value.\n"
 1364 "It's measured in GKrellM ticks -- that's 1/10 seconds.\n"
 1365 "Label is a unique name that gets prepended to your reader.\n"
 1366 "Unit is just a string thats appended to your reader.\n"
 1367 "You can prepend a specific transport to the peer name.\n"
 1368 "(i.e. tcp:192.168.0.1)\n"
 1369 "\n"
 1370 "Some examples:\n"
 1371 "\n"
 1372 "(1)\n"
 1373 "The ambiente temperature sensor for some net-snmp server\n"
 1374 "public / 192.168.1.2 port 161 oid .1.3.6.1.4.1.2021.8.1.101.1\n"
 1375 "\n"
 1376 "That is:\n"
 1377 " SNMP peer '192.168.1.2' (some.server.name)\n"
 1378 " SNMP port '161' (that's the default)\n"
 1379 " SNMP community name 'public'\n"
 1380 " SNMP oid '.1.3.6.1.4.1.2021.8.1.101.1'\n"
 1381 "\n"
 1382 "Resonable Label/Unit would be 'Temp.' / '°C'\n"
 1383 "\n"
 1384 "(2)\n"
 1385 "\n"
 1386 "Server CPU load using a string ranging from 0.00 to 1.00\n"
 1387 "\n"
 1388 "public / 192.168.1.3 pot 161 oid .1.3.6.1.4.1.2021.10.1.3.1\n"
 1389 "(Thats the load factor for some server)\n"
 1390 "\n"
 1391 "(3)\n"
 1392 "\n"
 1393 "Server CPU load using integer variable ranging from 0 to 100\n"
 1394 "\n"
 1395 "public / 192.168.1.4 port 161 oid .1.3.6.1.4.1.2021.10.1.5.1\n"
 1396 "(Thats the percentile load for some server)\n"
 1397 "\n"
 1398 "please mail any problems/questions to me...\n"
 1399 ;
 1400 
 1401 static gchar    *plugin_about_text =
 1402    "SNMP plugin 1.0\n"
 1403    "GKrellM SNMP monitor Plugin\n\n"
 1404    "Copyright (C) 2000-2006 Christian W. Zuckschwerdt <zany@triq.net>\n"
 1405    "\n"
 1406    "http://triq.net/gkrellm.html\n\n"
 1407    "Released under the GNU Public Licence with OpenSSL exemption"
 1408 ;
 1409 
 1410 static gchar *reader_title[CLIST_WIDTH] =
 1411 { "Label", "Peer", "Port",
 1412   "Community", "OID", "Unit",
 1413   "Freq", "Divisor", "Delta", "Scale", "Active" };
 1414 
 1415 static void
 1416 create_plugin_tab(GtkWidget *tab_vbox)
 1417 {
 1418   Reader *reader;
 1419 
 1420   GtkWidget               *tabs;
 1421   GtkWidget               *vbox;
 1422   GtkWidget               *hbox;
 1423   GtkWidget               *button;
 1424   GtkWidget               *arrow;
 1425   GtkWidget               *scrolled;
 1426   GtkWidget               *text;
 1427   GtkWidget               *label;
 1428 
 1429   gchar                   *buf[CLIST_WIDTH];
 1430   gint                    row, i;
 1431 
 1432         /* Make a couple of tabs.  One for setup and one for info
 1433         */
 1434         tabs = gtk_notebook_new();
 1435         gtk_notebook_set_tab_pos(GTK_NOTEBOOK(tabs), GTK_POS_TOP);
 1436         gtk_box_pack_start(GTK_BOX(tab_vbox), tabs, TRUE, TRUE, 0);
 1437 
 1438 /* --- Setup tab */
 1439     vbox = gkrellm_gtk_framed_notebook_page(tabs, "Setup");
 1440 
 1441     hbox = gtk_hbox_new(FALSE,0);
 1442 
 1443     label = gtk_label_new("Label : ");
 1444     gtk_box_pack_start(GTK_BOX(hbox),label,FALSE,FALSE,0);
 1445     label_entry = gtk_entry_new();
 1446     gtk_entry_set_text(GTK_ENTRY(label_entry), "");
 1447     gtk_box_pack_start(GTK_BOX(hbox),label_entry,FALSE,FALSE,0);
 1448 
 1449     label = gtk_label_new("Peer : ");
 1450     gtk_box_pack_start(GTK_BOX(hbox),label,FALSE,FALSE,0);
 1451     peer_entry = gtk_entry_new();
 1452     gtk_entry_set_text(GTK_ENTRY(peer_entry), "");
 1453     gtk_box_pack_start(GTK_BOX(hbox),peer_entry,FALSE,FALSE,0);
 1454 
 1455     label = gtk_label_new("Port : ");
 1456     gtk_box_pack_start(GTK_BOX(hbox),label,FALSE,FALSE,0);
 1457     port_spin_adj = gtk_adjustment_new (161, 1, 65535, 1, 10, 10);
 1458     port_spin = gtk_spin_button_new (GTK_ADJUSTMENT (port_spin_adj), 1, 0);
 1459     gtk_box_pack_start(GTK_BOX(hbox),port_spin,FALSE,FALSE,0);
 1460 
 1461     label = gtk_label_new("Freq : ");
 1462     gtk_box_pack_start(GTK_BOX(hbox),label,FALSE,FALSE,0);
 1463     freq_spin_adj = gtk_adjustment_new (100, 10, 6000, 10, 100, 100);
 1464     freq_spin = gtk_spin_button_new (GTK_ADJUSTMENT (freq_spin_adj), 1, 0);
 1465     gtk_box_pack_start(GTK_BOX(hbox),freq_spin,FALSE,FALSE,0);
 1466 
 1467     gtk_container_add(GTK_CONTAINER(vbox),hbox);
 1468     hbox = gtk_hbox_new(FALSE,0);
 1469 
 1470     label = gtk_label_new("Community : ");
 1471     gtk_box_pack_start(GTK_BOX(hbox),label,FALSE,FALSE,0);
 1472     community_entry = gtk_entry_new();
 1473     gtk_entry_set_text(GTK_ENTRY(community_entry), "");
 1474         gtk_box_pack_start(GTK_BOX(hbox), community_entry, FALSE, FALSE, 0);
 1475 
 1476     label = gtk_label_new("OID : ");
 1477     gtk_box_pack_start(GTK_BOX(hbox),label,FALSE,FALSE,0);
 1478     oid_entry = gtk_entry_new();
 1479     gtk_entry_set_text(GTK_ENTRY(oid_entry), "");
 1480         gtk_box_pack_start(GTK_BOX(hbox), oid_entry, FALSE, FALSE, 0);
 1481 
 1482     label = gtk_label_new("Unit : ");
 1483     gtk_box_pack_start(GTK_BOX(hbox),label,FALSE,FALSE,0);
 1484     unit_entry = gtk_entry_new();
 1485     gtk_entry_set_text(GTK_ENTRY(unit_entry), "");
 1486     gtk_box_pack_start(GTK_BOX(hbox),unit_entry,FALSE,FALSE,0);
 1487 
 1488     gtk_container_add(GTK_CONTAINER(vbox),hbox);
 1489     hbox = gtk_hbox_new(FALSE,0);
 1490 
 1491     label = gtk_label_new("Divisor : ");
 1492     gtk_box_pack_start(GTK_BOX(hbox),label,FALSE,FALSE,0);
 1493     div_spin_adj = gtk_adjustment_new (1, 1, 1024, 1, 1, 1);
 1494     div_spin = gtk_spin_button_new (GTK_ADJUSTMENT (div_spin_adj), 1, 0);
 1495     gtk_box_pack_start(GTK_BOX(hbox),div_spin,FALSE,FALSE,0);
 1496 
 1497         delta_button = gtk_check_button_new_with_label("Compute delta");
 1498         gtk_box_pack_start(GTK_BOX(hbox),delta_button,FALSE,FALSE,0);
 1499 
 1500         scale_button = gtk_check_button_new_with_label("Auto scale");
 1501         gtk_box_pack_start(GTK_BOX(hbox),scale_button,FALSE,FALSE,0);
 1502 
 1503         button = gtk_button_new_with_label("Probe");
 1504         gtk_signal_connect(GTK_OBJECT(button), "clicked",
 1505                (GtkSignalFunc) cb_probe, NULL);
 1506         gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 4);
 1507 
 1508     gtk_container_add(GTK_CONTAINER(vbox),hbox);
 1509 
 1510         hbox = gtk_hbox_new(FALSE, 3);
 1511         gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2);
 1512     /*
 1513         *mount_button = gtk_check_button_new_with_label(
 1514                                         "Enable /etc/fstab mounting");
 1515         gtk_box_pack_start(GTK_BOX(hbox), *mount_button, TRUE, TRUE, 0);
 1516         gtk_signal_connect(GTK_OBJECT(GTK_BUTTON(*mount_button)), "clicked",
 1517                                 GTK_SIGNAL_FUNC (cb_mount_button_clicked), NULL);
 1518     */
 1519 
 1520         button = gtk_button_new();
 1521         arrow = gtk_arrow_new(GTK_ARROW_UP, GTK_SHADOW_ETCHED_OUT);
 1522         gtk_container_add(GTK_CONTAINER(button), arrow);
 1523         gtk_signal_connect(GTK_OBJECT(button), "clicked",
 1524                (GtkSignalFunc) cb_clist_up, NULL);
 1525         gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 4);
 1526 
 1527         button = gtk_button_new();
 1528         arrow = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_ETCHED_OUT);
 1529         gtk_container_add(GTK_CONTAINER(button), arrow);
 1530         gtk_signal_connect(GTK_OBJECT(button), "clicked",
 1531                (GtkSignalFunc) cb_clist_down, NULL);
 1532         gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 4);
 1533 
 1534         button = gtk_button_new_with_label("Enter");
 1535         gtk_signal_connect(GTK_OBJECT(button), "clicked",
 1536                (GtkSignalFunc) cb_enter, NULL);
 1537         gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 4);
 1538 
 1539         button = gtk_button_new_with_label("Delete");
 1540         gtk_signal_connect(GTK_OBJECT(button), "clicked",
 1541                (GtkSignalFunc) cb_delete, NULL);
 1542         gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 4);
 1543 
 1544 
 1545         scrolled = gtk_scrolled_window_new(NULL, NULL);
 1546         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
 1547                         GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
 1548         gtk_box_pack_start(GTK_BOX(vbox), scrolled, TRUE, TRUE, 0);
 1549 
 1550     reader_clist = gtk_clist_new_with_titles(CLIST_WIDTH, reader_title);    
 1551         gtk_clist_set_shadow_type (GTK_CLIST(reader_clist), GTK_SHADOW_OUT);
 1552     gtk_clist_set_column_width (GTK_CLIST(reader_clist), 1, 100);
 1553     gtk_clist_set_column_width (GTK_CLIST(reader_clist), 4, 100);
 1554 
 1555         gtk_signal_connect(GTK_OBJECT(reader_clist), "select_row",
 1556                         (GtkSignalFunc) cb_clist_selected, NULL);
 1557         gtk_signal_connect(GTK_OBJECT(reader_clist), "unselect_row",
 1558                         (GtkSignalFunc) cb_clist_unselected, NULL);
 1559 
 1560         gtk_container_add(GTK_CONTAINER(scrolled), reader_clist);
 1561 
 1562         for (reader = readers; reader; reader = reader->next)
 1563       {
 1564         i = 0;
 1565         buf[i++] = reader->label;
 1566         buf[i++] = reader->peer;
 1567         buf[i++] = g_strdup_printf("%d", reader->port);
 1568         buf[i++] = reader->community;
 1569         buf[i++] = reader->oid_str;
 1570         buf[i++] = reader->unit;
 1571         buf[i++] = g_strdup_printf("%d", reader->delay);
 1572         buf[i++] = g_strdup_printf("%d", reader->divisor);
 1573         buf[i++] = reader->delta ? "yes" : "no";
 1574         buf[i++] = reader->scale ? "yes" : "no";
 1575         buf[i++] = reader->active ? "yes" : "no";
 1576         row = gtk_clist_append(GTK_CLIST(reader_clist), buf);
 1577       }
 1578 
 1579 
 1580 /* --- Info tab */
 1581     vbox = gkrellm_gtk_framed_notebook_page(tabs, "Info");
 1582 //        scrolled = gtk_scrolled_window_new(NULL, NULL);
 1583 //        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
 1584 //                        GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
 1585 //        gtk_box_pack_start(GTK_BOX(vbox), scrolled, TRUE, TRUE, 0);
 1586 //        text = gtk_text_new(NULL, NULL);
 1587     text = gkrellm_gtk_scrolled_text_view(vbox, NULL, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
 1588 //        gtk_text_insert(GTK_TEXT(text), NULL, NULL, NULL, plugin_info_text, -1);
 1589     gkrellm_gtk_text_view_append(text, plugin_info_text);
 1590 //        gtk_text_set_editable(GTK_TEXT(text), FALSE);
 1591 //        gtk_container_add(GTK_CONTAINER(scrolled), text);
 1592 
 1593 /* --- about text */
 1594 
 1595     text = gtk_label_new(plugin_about_text); 
 1596 
 1597     gtk_notebook_append_page(GTK_NOTEBOOK(tabs), text,
 1598                  gtk_label_new("About"));
 1599 
 1600 }
 1601 
 1602 
 1603 
 1604 
 1605 static GkrellmMonitor  plugin_mon  =
 1606         {
 1607         PLUGIN_CONFIG_NAME,    /* Name, for config tab.        */
 1608         0,                     /* Id,  0 if a plugin           */
 1609         create_plugin,         /* The create_plugin() function */
 1610         update_plugin,         /* The update_plugin() function */
 1611         create_plugin_tab,     /* The create_plugin_tab() config function */
 1612         apply_plugin_config,   /* The apply_plugin_config() function      */
 1613 
 1614         save_plugin_config,    /* The save_plugin_config() function  */
 1615         load_plugin_config,    /* The load_plugin_config() function  */
 1616         PLUGIN_CONFIG_KEYWORD, /* config keyword                     */
 1617 
 1618         NULL,                  /* Undefined 2  */
 1619         NULL,                  /* Undefined 1  */
 1620         NULL,                  /* Undefined 0  */
 1621 
 1622         MON_MAIL,              /* Insert plugin before this monitor.       */
 1623         NULL,                  /* Handle if a plugin, filled in by GKrellM */
 1624         NULL                   /* path if a plugin, filled in by GKrellM   */
 1625         };
 1626 
 1627 GkrellmMonitor *
 1628 gkrellm_init_plugin(void)
 1629 {
 1630     readers = NULL;
 1631 
 1632 #ifdef DEBUG_SNMP
 1633     debug_register_tokens("all");
 1634     snmp_set_do_debugging(1);
 1635 #endif /* DEBUG_SNMP */
 1636 
 1637     init_mib();
 1638     
 1639     mon = &plugin_mon;
 1640     return &plugin_mon;
 1641 }