/*  $Id: tcp_service.c,v 1.4 2001/03/02 10:01:01 remlali Exp $
 *
 * Copyright 2000
 * tcp_service.c -- create requests from socket
 *
 *  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.
 *
 *  tcp_service.c
 *
 */

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

#include <glib.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

#include "dbapi.h" /*think its obsolete*/
#include "ddserver.h"

extern GList *tranq;
extern GList *profiles;
extern GMainLoop *loop;

G_sql_connection *dbhandler;

/**
 * io_callback
 * Handles input from the clients and passes it off to the parser/dispatcher.
 * This will get the raw data from the socket, make sure there is a NULL 
 * terminator, and call the command dispatcher.
 **/
gboolean 
io_callback (gint type, GIOChannel *source, gint len, gpointer data)
{
  guint num_read = 0;
  guint h, tpl;  /* header len h, total_packet_len tpl */
  tranrec *rec;
  guint tablen;
  struct sockaddr_in client_addr;
  profile *prf;

  switch(type){
    case 0:
      if(!(prf = g_malloc(sizeof(profile)))){
        fprintf(stderr,"Couldn't connect to client, due to malloc() failure\n");
        return FALSE;
      }
      prf->value = DBCTL_NOTIFY_FULL | DBCTL_AUTH | DBCTL_RW;	
        /* a connection has full notification, read_write and
           is authenticated by default */
      prf->source = source;
      profiles = g_list_append(profiles, prf);
      g_print ("Connect GIOChannel: %u.\n", source);
      return TRUE;
    case 2:
      tcp_client_disconnect(source);
      return FALSE;
    case 1:
      /* Process packet header only
         assing request to transaction list */
      rec = g_malloc0 ((unsigned int)sizeof(tranrec));
      memcpy(&rec->action, data, sizeof(gint));			/* get action */
      if(rec->action == DISCONNECT){
        g_free(rec);
        tcp_client_disconnect(source);
        return FALSE;
      }
//          fprintf(stderr,"  action: %d\n", rec->action);
      memcpy(&tablen, data+sizeof(gint), sizeof(gint));		/* get table name length*/
//          fprintf(stderr,"  Length of table name: %d\n", tablen);
      rec->table = g_strndup(data+(sizeof(gint)*2), tablen);	/* get table name */
      memcpy(&tpl, data+(sizeof(gint)*2)+tablen, sizeof(gint));		/* get Total packet length*/

//          fprintf(stderr,"  table_name: %s\n", rec->table);
	  
      h = (sizeof(gint) * 3)+tablen;	/* h is header length */

/* pointer into memberrecords */
      rec->mlen = tpl - h;			/* set length of member records */
//	  fprintf(stderr,"  MemRecLen(%d) TPL(%d) HdrLen(%d)\n", rec->mlen, tpl, h);
      if(rec->mlen){	/* Copy memberRecords if there are any.
			  Alloc buffer to hold all members.
		   	  Copy all members at once to buffer */
        rec->members = g_malloc0 ((unsigned int)rec->mlen);
        memcpy(rec->members, data+h, rec->mlen);	
      } else rec->members = 0;	/* No members, Null pointer */
        rec->source = source;
        rec->prf = prf;
      /* OK, rec is setup, assign it to queue 'tranq' */
      tranq = g_list_append(tranq, rec);
  }
  return TRUE;
}

/**
 * tcp_client_disconnect()
 * Called when A client disappears, should remove it from the list and
 * go on with life.
 *
 * go through transaction request list, and remove read-only actions,
 * from this source
 *
 * remove this user from profile list
 *
 **/
gboolean
tcp_client_disconnect (GIOChannel *source)
{
  profile *prf;
  GList *gl;

  gl = profiles;
  while(gl){
    prf = gl->data;
    if(prf->source == source){
      g_print ("Disconnect GIOChannel: %u.\n", source);
      profiles = g_list_remove(profiles, prf);
      g_free(prf);
      g_io_channel_close(source);
      break;
    }
    gl = gl->next;
  }

  return TRUE;
}

