#include <stdio.h>

#include <glib.h>

#include <winsock2.h>

static GTimeVal start;
static guint connect_watch, read_watch;
static GMainLoop *loop;

static long
get_time (void)
{
  GTimeVal tv;

  g_get_current_time (&tv);

  return (tv.tv_sec - start.tv_sec) * 1000000 + (tv.tv_usec - start.tv_usec);
}

static gboolean
read_cb (GIOChannel  *source,
	 GIOCondition condition,
	 gpointer     data)
{
  char buf[1000];
  int n;
  SOCKET fd;

  fd = g_io_channel_unix_get_fd (source);

  printf ("%s at %ld: condition=%#x\n", __FUNCTION__, get_time(), condition);

  if (condition & (G_IO_HUP | G_IO_ERR))
    {
      g_main_loop_quit (loop);
      return FALSE;
    }

  n = recv (fd, buf, sizeof (buf), 0);
  if (n == SOCKET_ERROR)
    g_error ("recv(%d) failed: %s\n", fd, g_win32_error_message (WSAGetLastError ()));

  printf ("\"%.*s\"\n", n, buf);

  return TRUE;
}

static gboolean
connect_cb (GIOChannel  *source,
	    GIOCondition condition,
	    gpointer     data)
{
  const char helo[] = "HELO foobar.zap\r\n";
  SOCKET fd;

  printf ("%s at %ld: condition=%#x\n", __FUNCTION__, get_time(), condition);

  if (condition & (G_IO_HUP | G_IO_ERR))
    {
      g_main_loop_quit (loop);
      return FALSE;
    }

  fd = g_io_channel_unix_get_fd (source);
  if (send (fd, helo, strlen (helo), 0) == SOCKET_ERROR)
    g_error ("send(%d) failed: %s\n",
	     fd,
	     g_win32_error_message (WSAGetLastError ()));

  read_watch = g_io_add_watch (source, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
			       read_cb, NULL);

  return FALSE;
}

int
main (int argc, char **argv)
{
  SOCKET s;
  struct sockaddr_in sin;
  WSADATA wsadata;
  GIOChannel *channel;

  g_get_current_time (&start);

  loop = g_main_loop_new (NULL, FALSE);

  if (WSAStartup (MAKEWORD (2, 0), &wsadata) != 0)
    g_error ("Windows Sockets could not be initialized");
  

  s = socket (AF_INET, SOCK_STREAM, 0);

  if (s == INVALID_SOCKET)
    g_error ("socket() failed: %s\n", g_win32_error_message (WSAGetLastError ()));

  channel = g_io_channel_win32_new_socket (s);
  connect_watch = g_io_add_watch (channel, G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
				  connect_cb, NULL);

  sin.sin_family = AF_INET;
  sin.sin_port = htons (25);
  sin.sin_addr.s_addr = inet_addr (argv[1]);

  Sleep (10);

  printf ("connect() at %ld\n", get_time ());

  if (connect (s, (struct sockaddr *) &sin, sizeof (sin)) == SOCKET_ERROR &&
      WSAGetLastError () != WSAEWOULDBLOCK)
    g_error ("connect() failed: %s\n", g_win32_error_message (WSAGetLastError ()));
  printf ("connect() returned at %ld\n", get_time ());

  g_main_loop_run (loop);

  exit (0);
}
