/*  $Id: queue.c,v 1.4 2001/02/23 11:52:58 remlali Exp $
 *
 * Copyright 2000 Larry Liimatainen
 * queue.c -- request processing
 *
 *  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.
 *
 *  queue.c
 *
 */

/*

 I added these "queue" function to have the structure somewhat ready
 if real queing is implemented.

*/

#include <stdio.h>
#include <glib.h>

#include "dbapi.h"
#include "ddserver.h"
#include "table-common.h"

extern GList *tranq;
extern GList *profiles;
extern G_sql_connection *dbhandler;

/* tranq_check()
 *
 * check queue for transaction requests.
 *
 *
 */

extern gchar buffer[2000];

void tranrec_free(tranrec *req)
{
  if(req->table)
    g_free(req->table);
  if(req->members)
    g_free(req->members);
  g_free(req);
}

gint tranq_check()
{
static gint num_write;
static GList *gl;
static tranrec *req;
static gchar sqlstr[2000];
static gchar buffer[2000];

static G_sql_query *sql;
gchar *outbuf1 = 0;
gchar *outbuf2 = 0;
gint outi, n=0;
db_table_descriptor *table;

  if(!(gl = g_list_first(tranq))) return;			/* get oldest request from list, return if queue is empty */
  sqlstr[0] = 0;
  req = gl->data;
  switch(req->action)
    {
      case AUTH:
      break;
      case ROW_ADD: /* TAR */
            if(!((req->prf->value & DBCTL_AUTH) && (req->prf->value & DBCTL_RW))) break;
            table = db_lookup_table(req->table);
            if(!encode_sql(table, req->members, sqlstr, SQL_INSERT, &n, req->mlen)){  /* build a SQL INSERT string */
              debug_decode_output(&n, req->members, 20, 80);
              break;
            }
            if(sql = g_sql_query(dbhandler, sqlstr, strlen(sqlstr))){
              g_sql_free_query(sql);
            }
                /*IF g_sql_query fails, we must build a failure 
                  request and send to source */
            notification_build_and_add(table, req->prf, req->members);
      break;
      case ROW_UPDATE: /* TUR */
            if(!((req->prf->value & DBCTL_AUTH) && (req->prf->value & DBCTL_RW))) break;
            table = db_lookup_table(req->table);
            if(!encode_sql(table, req->members, sqlstr, SQL_UPDATE, &n, req->mlen)){  /* build a SQL UPDATE string */
              debug_decode_output(&n, req->members, 20, 80);
              break;
            }
            if(sql = g_sql_query(dbhandler, sqlstr, strlen(sqlstr))){
              g_sql_free_query(sql);
            }
            notification_build_and_add(table, req->prf, req->members);
      break;
      case ROW_DELETE: /* TDR */
            if(!((req->prf->value & DBCTL_AUTH) && (req->prf->value & DBCTL_RW))) break;
            table = db_lookup_table(req->table);
            encode_sql(table, req->members, sqlstr, SQL_DELETE, &n, req->mlen);  /* build a SQL DELETE string */
            if(sql = g_sql_query(dbhandler, sqlstr, strlen(sqlstr))){
              g_sql_free_query(sql);
            }
            notification_build_and_add(table, req->prf, req->members);

      break;
      case TABLE_LOAD:
            /* lookup table to use
               make a SQL string and send to database
               go through each row of results and compile memberrecords
               send packet back to requesting client ( req->source ) */
            table = db_lookup_table(req->table);
            outi = 2000;
            if(!(outbuf1 = g_malloc(outi))) break;				/* alloc initial buffer */
            encode_sql(table, 0, sqlstr, SQL_SELECT_ALL,0, 0); /* WHY? */
            n = RESULT;
            memcpy(outbuf1, &n, sizeof(gint));					/* set GxSNMP_APICMD type */           
            n=0;
            sql = g_sql_query(dbhandler, sqlstr, strlen(sqlstr));
            if(!(sql = g_sql_query(dbhandler, sqlstr, strlen(sqlstr)))){
              /*FIX: Notify user, else he must timeout */
              break;
            }

            while(g_sql_next_row(sql)){						/*walk through each database row*/
              decode_sql(table, outbuf1+(sizeof(gint)*2), sql, 0, &n);	/* That zero means fetch ALL fields */
              if(n > outi - 1000){						/* we are almost out of buffer */
                outi += 2000;
                if(!(outbuf2 = g_malloc(outi))){					/* alloc new buffer */
                  /*FIX: Notify user, else he must timeout */
                  g_free(outbuf1);
                  g_sql_free_query(sql);
                  break;
                }
                memcpy(outbuf2, outbuf1, n + (sizeof(gint) * 2));		/* move over old buffer to new */
                g_free(outbuf1);						/* release old buffer */
                outbuf1 = outbuf2;						/* set new buffer pointer */
              }
            }
            /* ALL data in table has been fetched, send result back to user */
            g_sql_free_query(sql);
            n += sizeof(gint) * 2;						/* Total packet length */
            memcpy(outbuf1+sizeof(gint), &n, sizeof(gint));			/*write packet total length*/
            g_io_channel_write(req->source, outbuf1, n, &num_write);
            g_free(outbuf1);
      break;
      case ROW_READ:
/* this code isn't so nice to*/

            table = db_lookup_table(req->table);
            n = RESULT;
            memcpy(buffer, &n, sizeof(gint));    				/* build action_cmd in header */
            n=0;
            encode_sql(table, req->members, sqlstr, SQL_SELECT_PRI, &n, req->mlen);  /* build a SQL SELECT string */
            if(!(sql = g_sql_query(dbhandler, sqlstr, strlen(sqlstr)))){
              fprintf(stderr,"SQL query failed.\n");
              /*FIX: Notify user, else he must timeout */
              break;
            }
            g_sql_next_row(sql);
            n=0;
            decode_sql(table, buffer+(sizeof(gint)*2), sql, 0, &n);	/* That zero means fetch ALL fields */
            g_sql_free_query(sql);					/* all SQL result data fetched */

            n += sizeof(gint) * 2;					/* total packet length*/
            memcpy(buffer+sizeof(gint), &n, sizeof(gint));                        /* write total packet length*/
            g_io_channel_write(req->source, buffer, n, &num_write);
      break;
      case NOTIFY: /*just copy req->table to the connection profile */
            req->prf->value = req->table;
      break;

      case TABLE_LOAD_FILTERED: /* translate the IP address to a hostname */
            table = db_lookup_table(req->table);
              /* build a SQL-SELECT string */
            encode_sql(table, req->members, sqlstr, SQL_SELECT, &n, req->mlen);
            if(!(sql = g_sql_query(dbhandler, sqlstr, strlen(sqlstr)))){
              break;
            }
               /* we have now sent the SQL string that is originally built out of a
                  object filter converted into member-records, now we convert all
                  answers from SQL-DB into member-records */

            outi = 2000;
            if(!(outbuf1 = g_malloc(outi))) break;	/* alloc initial buffer */
            n = RESULT;
            memcpy(outbuf1, &n, sizeof(gint));		/* set GxSNMP_APICMD type */           
            n=0;

            while(g_sql_next_row(sql)){			/*walk through each database row*/
              decode_sql(table, outbuf1+(sizeof(gint)*2), sql, 0, &n);
							/* That zero means fetch ALL fields */
              if(n > outi - 1000){			/* we are almost out of buffer */
                outi += 2000;
                if(!(outbuf2 = g_malloc(outi))){	/* alloc new buffer */
                  g_free(outbuf1);
                  break;
                }
                memcpy(outbuf2, outbuf1, n + (sizeof(gint) * 2));		/* move over old buffer to new */
                g_free(outbuf1);			/* release old buffer */
                outbuf1 = outbuf2;			/* set new buffer pointer */
              }
            }

            /* all data in table has been fetched, send result back to user */
            g_sql_free_query(sql);
            n += sizeof(gint) * 2;			/* Total packet length */
            memcpy(outbuf1+sizeof(gint), &n, sizeof(gint)); /*write packet total length*/
            g_io_channel_write(req->source, outbuf1, n, &num_write);
            g_free(outbuf1);
      break;

      default:
        fprintf(stderr,"Unknown request action\n");
            /*maybe we should notify the client about this, 
              he could be running a old version or something*/
   }
  tranq = g_list_remove(tranq, req);
  tranrec_free(req);
  return 0;
}
