/*
 * Test case for bug #338943 from Owen Taylor in the bug report at 
 * http://bugzilla.gnome.org/show_bug.cgi?id=338943 , modifications:
 *
 * - Work on win32.
 *
 * - Test to see if one of the events was suppressed (will timeout in 5 
 *   seconds and return 1 if one was).
 *
 * - Keep the handlers active so the bug will continue to prevent the 
 *   other handler from being recognized.
 *
 * Steven Brown <swbrown@variadic.org>
 */
#include <glib.h>
#include <stdlib.h>

#ifdef __WIN32__
#include <winsock2.h>
#else
#include <netdb.h>
#endif

gboolean in_called = FALSE;
gboolean out_called = FALSE;

gboolean 
timeout_handler()
{
  g_printerr("Time ran out without both in and out being flagged, either the server was slow to respond, or the bug occured and glib failed to actually hook one of the events\n");
  exit(1);
}

gboolean 
in_handler(GIOChannel *channel, GIOCondition source, gpointer data)
{
  if (!in_called)
    {
      g_printerr("IN called, good\n");
      in_called = TRUE;
    }
  if (in_called && out_called)
    {
      g_printerr("Both handlers flagged, test passes\n");
      exit(0);
    }

  return TRUE;
}

gboolean 
out_handler(GIOChannel *channel, GIOCondition source, gpointer data)
{
  if (!out_called)
    {
      g_printerr("OUT called, good\n");
      out_called = TRUE;
    }
  if (in_called && out_called)
    {
      g_printerr("Both handlers flagged, test passes\n");
      exit(0);
    }

  return TRUE;
}

int main(int argc, char **argv)
{
  GMainLoop *loop;
  struct hostent *he;
  struct sockaddr_in sin;
  int fd;
  GIOChannel *ioc;
  
  // Init winsock.
#ifdef WIN32
    WSADATA wsaData;
    WORD wsaVersionRequested = MAKEWORD(2, 2);
    int result = WSAStartup(wsaVersionRequested, &wsaData);
    if (result != 0)
      {
        g_printerr ("WSAStartup failed, test is broken\n");
        exit(1);
      }
    if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
      {
        g_printerr ("Could not get a suitable version of winsock, test is broken\n");
        exit(1);
      }
#endif

  if (argc != 2)
    {
      g_printerr ("Usage: multiwatch MAIL_SERVER\n");
      exit (1);
    }

  he = gethostbyname(argv[1]);
  if (!he)
    {
      g_printerr ("Can't find host %s\n", argv[1]);
      exit (1);
    }

  fd = socket (PF_INET, SOCK_STREAM, 0);

  sin.sin_family = AF_INET;
  sin.sin_port = htons (25);
  sin.sin_addr = *(struct in_addr *)he->h_addr;

  if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0)
    {
      g_printerr ("Can't connect to  host %s\n", argv[1]);
      exit (1);
    }

#ifdef WIN32
  ioc = g_io_channel_win32_new_socket (fd);
#else
  ioc = g_io_channel_unix_new (fd);
#endif

  g_io_add_watch(ioc, G_IO_IN, in_handler, NULL);
  g_io_add_watch(ioc, G_IO_OUT, out_handler, NULL);

  g_io_channel_unref (ioc);

  // Give up after not seeing both events flagged for a while.
  if (!g_timeout_add((guint) (5 * 1000), timeout_handler, 0))
    {
      g_printerr ("Failed to create timer\n");
      exit (1);
    }

  loop = g_main_loop_new (NULL, FALSE);
  g_main_loop_run (loop);

  // Deinit winsock.
#ifdef WIN32
  WSACleanup();
#endif

  return 0;
}
