/*
 * $Id: tcp_service.c,v 1.4 1999/10/20 11:24:44 remlali Exp $
 * 
 * TCP Service  -- Handles all socket level issues.
 */
#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 "g_sql.h"
#include "gxdd.h"

extern gchar bufme[1024];
extern G_sql_connection *dbhandler;

/****************************************************************************
 * Forward references
 ***************************************************************************/
gboolean             tcp_new_connection           (GIOChannel     *source,
						   GIOCondition   condition,
						   gpointer       data);
gboolean             tcp_client_activity          (GIOChannel     *source,
						   GIOCondition   condition,
						   gpointer       data);
gboolean             tcp_client_disconnect        (GIOChannel     *source,
						   GIOCondition   condition,
						   gpointer       data);
/****************************************************************************
 * Implementation.
 ***************************************************************************/
void
tcp_enable_reuseaddr (gint sock)
{
  gint tmp = 1;
  if (sock < 0)
    return;
  if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (gchar *)&tmp, 
		  sizeof (tmp)) == -1)
    perror ("Bah! Bad setsockopt ()\n");
}

void 
tcp_enable_nbio (gint fd)
{
  if (fcntl (fd, F_SETOWN, getpid()) == -1)
    perror ("fcntl (F_SETOWN) error\n");
  if (fcntl (fd, F_SETFL, FNDELAY) == -1)
    perror ("fcntl (F_SETFL, FNDELAY\n");
}

void 
tcp_socket_init (gint port)
{
  gint                s;
  struct sockaddr_in  addr;
  GIOChannel          *channel;

  if (port <= 0)
    return ;

  s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if (s == -1)
    return;
  tcp_enable_reuseaddr (s);
  memset (&addr, 0, sizeof (addr));
  addr.sin_family       = AF_INET;
  addr.sin_port         = htons ((u_short)port);
  addr.sin_addr.s_addr  = INADDR_ANY;
  if (bind (s, (struct sockaddr *)&addr, sizeof (addr)) == -1)
    {
      close (s);
      return ;
    }
  if (listen (s, 5) == -1)
    {
      close (s);
      return ;
    }
  channel = g_io_channel_unix_new (s);
  g_io_add_watch (channel, G_IO_IN, tcp_new_connection, NULL);
}

/****************************************************************************
 * Callback functions
 ***************************************************************************/
/**
 * tcp_new_connection 
 * Will accept a new connection and add the client to the list of clients.
 * actual client communication is handled elsewhere.
 **/
gboolean 
tcp_new_connection (GIOChannel *source, GIOCondition cond, gpointer data)
{
  gint               new;              /* new socket descriptor */
  gint               client;
  GIOChannel         *new_channel;
  struct sockaddr_in client_addr;

  if (cond == G_IO_IN)
    {
      if ( (new = accept (g_io_channel_unix_get_fd (source),
			  (struct sockaddr *)&client_addr, &client)) < 0)
	{
	  g_warning ("Unable to accept new connection.");
	  return FALSE;
	}
      new_channel = g_io_channel_unix_new (new);
      g_io_add_watch (new_channel, G_IO_IN, tcp_client_activity, NULL);
      g_io_add_watch (new_channel, G_IO_HUP, tcp_client_disconnect, NULL);
    }
  return TRUE;
}

/**
 * tcp_client_activity
 * 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 
tcp_client_activity (GIOChannel *source, GIOCondition cond, gpointer data)
{
/*  gchar bufme[1024];*/
  gchar w1[1024];
  gchar w2[1024];
  guint num_read = 0;
  guint num_write;
  guint test;
  gchar sqlstr[2000];
  guint n;

  if (cond == G_IO_IN)
    {
      g_print ("Read channel...\n");
      if (g_io_channel_read (source, bufme, sizeof (bufme), &num_read) == G_IO_ERROR_NONE)
        {
	  bufme[num_read] = '\0';           /* Make sure its null terminated */
          g_print ("Read (%d) from the socket\n", num_read);
          if(!strncmp(bufme, "TAR",3)){                            /* Table Add Row */
            wordcpyt(w1, bufme, " ", 2);				 /* get table to add to */
            decode_to_sql(bufme+5+strlen(w1), sqlstr, SQL_INSERT);
            /*g_sql_query(dbhandler, sqlstr, strlen(sqlstr));*/
          }
          else if(!strncmp(bufme, "TUR",3)){                            /* Table Add Row */
            wordcpyt(w1, bufme, " ", 2);				 /* get table to add to */
          }
          else if(!strncmp(bufme, "TDR",3)){                            /* Table Add Row */
            wordcpyt(w1, bufme, " ", 2);				 /* get table to add to */
          }


        }
    }
  return TRUE;
}
/**
 * tcp_client_disconnect
 * Called when A client disappears, should remove it from the list and
 * go on with life.
 **/
gboolean
tcp_client_disconnect (GIOChannel *source, GIOCondition cond, gpointer data)
{
  return TRUE;
}
