/*****************************************************************************/
/*** multivnc_client.c                                                       ***/
/*****************************************************************************/

#include "vncviewer.h"

#include <sys/socket.h>
#include <resolv.h>
#include <errno.h>
#include <time.h>
#include <getopt.h>
#include <sys/types.h>
#include <signal.h>
#include <jpeglib.h>
#include <zlib.h>
#include <fcntl.h>


Bool JoinCTL ();
void JoinVNC ();
int CreateMultiSockToRecv (char *, short);
Bool MultiRecieve1 ();
Bool MultiRecieve2 ();
void ClientInit ();
Bool ReadFromMultiVNCServer(char *out, unsigned int n);
Bool HandleMultiVNCServerMessage (void);
void GetMultiVNCServerMsg (void *);
void help (char *);
void DrawingInit();

struct client_cb client_CB;
int connectstate = STAT_FIRST;
char *programName;
char *vncdisplay = "1";
AppData appData;
int rfbsock;
Display* dpy;
char answer;
int lock_time = 0;
gint lock_tag;
//gint record_tag;
int auto_flag = 0;
int notice_flag = 1;
char connect_server[IDLENGTH] = "\0";
int server_flag = 0;	// init:0, -s opt set:1, sever ID match:2
int passwd_flag = 0;    // default(init): 0, -p opt set:1
GtkWidget *drawing_window;
GtkWidget *dialog_IDinput;
GtkWidget *dialog_wait;
GtkWidget *dialog_recvAdv;
GtkWidget *dialog_inputmiss;
GtkWidget *lock_window;
GtkWidget *mini_window;

/****/
#define BGR233_SIZE 256
#define BUF_SIZE 5000000
static char buf[BUF_SIZE];
static char *bufoutptr = buf;
//static int buffered = 0;

static int changePixelFormat8To16(char *src_buf, int src_size, char *new_buf);
static int changePixelFormat8To32(char *src_buf, int src_size, char *new_buf);
static int changePixelFormat16To8(char *src_buf, int src_size, char *new_buf);
static int changePixelFormat16To32(char *src_buf, int src_size, char *new_buf);
static int changePixelFormat32To8(char *src_buf, int src_size, char *new_buf);
static int changePixelFormat32To16(char *src_buf, int src_size, char *new_buf);

/* from rfbproto.c */
static Bool HandleRRE8(int rx, int ry, int rw, int rh);
static Bool HandleRRE16(int rx, int ry, int rw, int rh);
static Bool HandleRRE32(int rx, int ry, int rw, int rh);
static Bool HandleCoRRE8(int rx, int ry, int rw, int rh);
static Bool HandleCoRRE16(int rx, int ry, int rw, int rh);
static Bool HandleCoRRE32(int rx, int ry, int rw, int rh);
static Bool HandleHextile8To8(int rx, int ry, int rw, int rh);
static Bool HandleHextile8To16(int rx, int ry, int rw, int rh);
static Bool HandleHextile8To32(int rx, int ry, int rw, int rh);
static Bool HandleHextile16To8(int rx, int ry, int rw, int rh);
static Bool HandleHextile16To16(int rx, int ry, int rw, int rh);
static Bool HandleHextile16To32(int rx, int ry, int rw, int rh);
static Bool HandleHextile32To8(int rx, int ry, int rw, int rh);
static Bool HandleHextile32To16(int rx, int ry, int rw, int rh);
static Bool HandleHextile32To32(int rx, int ry, int rw, int rh);
static Bool HandleZlib8(int rx, int ry, int rw, int rh);
static Bool HandleZlib16(int rx, int ry, int rw, int rh);
static Bool HandleZlib32(int rx, int ry, int rw, int rh);
static Bool HandleTight8(int rx, int ry, int rw, int rh);
static Bool HandleTight16(int rx, int ry, int rw, int rh);
static Bool HandleTight32(int rx, int ry, int rw, int rh);

static long c_ReadCompactLen (void);

static void JpegInitSource(j_decompress_ptr cinfo);
static boolean JpegFillInputBuffer(j_decompress_ptr cinfo);
static void JpegSkipInputData(j_decompress_ptr cinfo, long num_bytes);
static void JpegTermSource(j_decompress_ptr cinfo);
static void JpegSetSrcManager(j_decompress_ptr cinfo, CARD8 *compressedData,
                              int compressedLen);

rfbPixelFormat myFormat;
rfbServerInitMsg si;

int endianTest = 1;

#define BUFFER_SIZE (640*480)
static char buffer[BUFFER_SIZE];

static int raw_buffer_size = -1;
static char *raw_buffer;

static z_stream decompStream;
static Bool decompStreamInited = False;

/*
 * Variables for the ``tight'' encoding implementation.
 */

/* Separate buffer for compressed data. */
#define ZLIB_BUFFER_SIZE 512
static char zlib_buffer[ZLIB_BUFFER_SIZE];

/* Four independent compression streams for zlib library. */
static z_stream c_zlibStream[4];
static Bool c_zlibStreamActive[4] = {
  False, False, False, False
};

/* Filter stuff. Should be initialized by filter initialization code. */
static Bool cutZeros;
static int rectWidth, rectColors;
static char tightPalette[256*4];
static CARD8 tightPrevRow[2048*3*sizeof(CARD16)];

/* JPEG decoder state. */
static Bool jpegError;

static struct jpeg_source_mgr jpegSrcManager;
static JOCTET *jpegBufferPtr;
static size_t jpegBufferLen;


static void
JpegInitSource(j_decompress_ptr cinfo)
{
  jpegError = False;
}


static boolean
JpegFillInputBuffer(j_decompress_ptr cinfo)
{
  jpegError = True;
  jpegSrcManager.bytes_in_buffer = jpegBufferLen;
  jpegSrcManager.next_input_byte = (JOCTET *)jpegBufferPtr;

  return True;
}


static void
JpegSkipInputData(j_decompress_ptr cinfo, long num_bytes)
{
  if (num_bytes < 0 || num_bytes > jpegSrcManager.bytes_in_buffer) {
    jpegError = True;
    jpegSrcManager.bytes_in_buffer = jpegBufferLen;
    jpegSrcManager.next_input_byte = (JOCTET *)jpegBufferPtr;
  } else {
    jpegSrcManager.next_input_byte += (size_t) num_bytes;
    jpegSrcManager.bytes_in_buffer -= (size_t) num_bytes;
  }
}


static void
JpegTermSource(j_decompress_ptr cinfo)
{
  /* No work necessary here. */
}


static long
c_ReadCompactLen (void)
{
  long len;
  CARD8 b;

  if (!ReadFromMultiVNCServer((char *)&b, 1))
    return -1;
  len = (int)b & 0x7F;
  if (b & 0x80) {
    if (!ReadFromMultiVNCServer((char *)&b, 1))
      return -1;
    len |= ((int)b & 0x7F) << 7;
    if (b & 0x80) {
      if (!ReadFromMultiVNCServer((char *)&b, 1))
	return -1;
      len |= ((int)b & 0xFF) << 14;
    }
  }
  return len;
}

static void
JpegSetSrcManager(j_decompress_ptr cinfo, CARD8 *compressedData,
		  int compressedLen)
{
  jpegBufferPtr = (JOCTET *)compressedData;
  jpegBufferLen = (size_t)compressedLen;

  jpegSrcManager.init_source = JpegInitSource;
  jpegSrcManager.fill_input_buffer = JpegFillInputBuffer;
  jpegSrcManager.skip_input_data = JpegSkipInputData;
  jpegSrcManager.resync_to_restart = jpeg_resync_to_restart;
  jpegSrcManager.term_source = JpegTermSource;
  jpegSrcManager.next_input_byte = jpegBufferPtr;
  jpegSrcManager.bytes_in_buffer = jpegBufferLen;

  cinfo->src = &jpegSrcManager;
}



#define GET_PIXEL8(pix, ptr) ((pix) = *(ptr)++)

#define GET_PIXEL16(pix, ptr) (((CARD8*)&(pix))[0] = *(ptr)++, \
                               ((CARD8*)&(pix))[1] = *(ptr)++)

#define GET_PIXEL32(pix, ptr) (((CARD8*)&(pix))[0] = *(ptr)++, \
                               ((CARD8*)&(pix))[1] = *(ptr)++, \
                               ((CARD8*)&(pix))[2] = *(ptr)++, \
                               ((CARD8*)&(pix))[3] = *(ptr)++)

#define CONCAT2(a,b) a##b
#define CONCAT2E(a,b) CONCAT2(a,b)

#define BPP 8
#include "mrre.c"
#include "mcorre.c"
#include "mzlib.c"
#include "mtight.c"
#define BPPC 8
#include "mhextile.c"
#undef BPPC
#define BPPC 16
#include "mhextile.c"
#include "pixel.c"
#undef BPPC
#define BPPC 32
#include "mhextile.c"
#include "pixel.c"
#undef BPPC
#undef BPP

#define BPP 16
#include "mrre.c"
#include "mcorre.c"
#include "mzlib.c"
#include "mtight.c"
#define BPPC 8
#include "mhextile.c"
#include "pixel.c"
#undef BPPC
#define BPPC 16
#include "mhextile.c"
#undef BPPC
#define BPPC 32
#include "mhextile.c"
#include "pixel.c"
#undef BPPC
#undef BPP

#define BPP 32
#include "mrre.c"
#include "mcorre.c"
#include "mzlib.c"
#include "mtight.c"
#define BPPC 8
#include "mhextile.c"
#include "pixel.c"
#undef BPPC
#define BPPC 16
#include "mhextile.c"
#include "pixel.c"
#undef BPPC
#define BPPC 32
#include "mhextile.c"
#undef BPPC
#undef BPP

#define OPTNUM 2


int client_main(int argc, char **argv)
{   
  int errno;
  int c, option_index;
  struct option *options;
  
  options = malloc(sizeof(struct option) * OPTNUM);
  options[0].name = "nonotice";
  options[0].has_arg = no_argument;
  options[0].flag = NULL;
  options[0].val = 1;
  options[1].name = 0;
  options[1].has_arg = 0;
  options[1].flag = 0;
  options[1].val = 0;

  /* command line check */
  programName = argv[0];
  while ((c = getopt_long(argc, argv, "d:s:u:fh", options, &option_index)) != EOF) {
//  while ((c = getopt(argc, argv, "d:u:fnh")) != EOF) {
    switch (c) {
      case 1:
	notice_flag = 0;
	break;
      case 'd':
	vncdisplay = optarg;
	break;
      case 's':
	memcpy(connect_server, optarg, IDLENGTH);
	server_flag = 1;
        break;
      case 'u':
	memcpy((char *)client_CB.client_ID, optarg, IDLENGTH);
	auto_flag = 1;
	break;
      case 'p':
	passwd_flag = 1;
//	memcpy((char *)client_CB.passwd, optarg, IDLENGTH);
	break;
      case 'h':
      case '?':
      default:
	help(argv[0]);
	exit(EXIT_FAILURE);
	break;
    }
  }

  /* start vncserver */
  StartVNCServer();

  if (notice_flag == 1) {
    mini_window = (GtkWidget *)create_mini_window();
    gtk_widget_show(mini_window);
  }

  /* client_CB Initialize */
  ClientInit ();

  /* Create Multicast socket for Advertise */
  client_CB.mltdsp = CreateMultiSockToRecv (ADVERTISE_IP, ADVERTISE_PORT);
  client_CB.g_mltdsp = gdk_input_add (client_CB.mltdsp, GDK_INPUT_READ, \
 				      (GdkInputFunction)GetMultiVNCServerMsg, \
				      (gpointer)client_CB.mltdsp);
  
  while (1) {
    gtk_main_iteration();
    usleep(1);
  }

  /* Clean up */
  close(client_CB.ctldsp);
  return 0;
}

void
ClientInit ()
{
  if (auto_flag == 0) {
    /* Input Client_ID */
    dialog_IDinput = (GtkWidget *)create_dialog_IDinput();
    gtk_widget_show(dialog_IDinput);
    gtk_grab_add(dialog_IDinput);
    draw_string_to_mini_window(_("Input ID"));
    gtk_main();
  }
  fprintf(stderr, "vncdisplay=%s\n",vncdisplay);
}


void
DrawingInit()
{
  dpy = XOpenDisplay(gdk_get_display());
  SetVisualAndCmap();
  ToplevelInitBeforeRealization();
  DesktopInitForClient();
}


Bool
JoinCTL ()
{
  struct sockaddr_in dest;
  ClientAdv clientadv;

  /* Open socket for client control */
  if ( (client_CB.ctldsp = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
    fprintf(stderr, "%s : Socket\n", programName);
    return False;
  }

  /* Initialize server address/port struct */
  bzero(&dest, sizeof(dest));
  dest.sin_family = AF_INET;
  dest.sin_addr.s_addr = client_CB.server_ip;
  dest.sin_port = client_CB.server_port;

  /* Join to server */
  if ( connect(client_CB.ctldsp, (struct sockaddr *)&dest, sizeof(dest)) != 0 ) {
    fprintf(stderr, "%s : Connect\n", programName);
    return False;
  }

  /* Send Client_ID */
  clientadv.type = rfbClientAdv;
  clientadv.length = sizeof(ClientAdv);
  memcpy(clientadv.client_ID, client_CB.client_ID, IDLENGTH);
  send (client_CB.ctldsp, &clientadv, sizeof(ClientAdv), 0);
  printf("clientadv.client_ID: %s\n", client_CB.client_ID);

  return True;
}

void 
JoinVNC () {
  char commandvnc1[256] = "vncconfig -display :";
  char commandvnc2[256] = "vncconnect -display :";
  char commandvnc3[256] = "vnc4config -display :";
  char serverport[10];
  int errno;
  
  /* make sh command */
  fprintf(stderr, "vncdisplay=%s\n",vncdisplay);
  strcat (commandvnc1, vncdisplay);
  strcat (commandvnc2, vncdisplay);
  strcat (commandvnc3, vncdisplay);
  strcat (commandvnc1, " -connect ");
  strcat (commandvnc2, " ");
  strcat (commandvnc3, " -connect ");
  strcat (commandvnc1, (char *)inet_ntoa(client_CB.server_ip));
  strcat (commandvnc2, (char *)inet_ntoa(client_CB.server_ip));
  strcat (commandvnc3, (char *)inet_ntoa(client_CB.server_ip));
  strcat (commandvnc1, ":");
  strcat (commandvnc2, ":");
  strcat (commandvnc3, ":");
  sprintf (serverport, "%d\0", ntohs(client_CB.server_port));
  strcat (commandvnc1, serverport);
  strcat (commandvnc2, serverport);
  strcat (commandvnc3, serverport);
  fflush (stdout);
  fprintf (stdout, "%s\n", commandvnc1);
  fprintf (stdout, "%s\n", commandvnc2);
  fprintf (stdout, "%s\n", commandvnc3);

  /* execute vncconnect */
  client_CB.vncdsp = (FILE*)system(commandvnc1);
  client_CB.vncdsp = (FILE*)system(commandvnc2);
  client_CB.vncdsp = (FILE*)system(commandvnc3);

  client_CB.connectstate = STAT_VNC;
}


int
CreateMultiSockToRecv (char *addr, short port) {
  struct sockaddr_in adv;
  int sock, errno;
  struct ip_mreq stMreq;
  int optval = 1;

  /* Create advertise socket */
  if ( (sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
    fprintf(stderr, "%s : SocketAdv\n", programName);
    exit(errno);
  }

  setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof (optval));

  /* Initialize address/port structure */
  bzero(&adv, sizeof(adv));
  adv.sin_family = AF_INET;
  adv.sin_port = htons(port);
  adv.sin_addr.s_addr = inet_addr(addr);

  stMreq.imr_multiaddr.s_addr = inet_addr(addr);
  stMreq.imr_interface.s_addr = INADDR_ANY;
  setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*) &stMreq, sizeof(stMreq));

  bind(sock, (struct sockaddr *) &adv, sizeof(adv));
  
  return sock;
}

void
ClearServerInfo ()
{
  if (client_CB.mltdsp != 0) close(client_CB.mltdsp);
  if (client_CB.vncdsp != NULL) pclose(client_CB.vncdsp);
  if (client_CB.ctldsp != 0) {
    gdk_input_remove(client_CB.g_ctldsp);
    close(client_CB.ctldsp);
  }
  if (client_CB.cstdsp != 0) {
    gdk_input_remove(client_CB.g_cstdsp);
    close(client_CB.cstdsp);
  }
  
  bzero (&client_CB, sizeof(client_CB));
  client_CB.connectstate = STAT_FIRST;

  draw_string_to_mini_window(_("ID input ERROR"));
  dialog_inputmiss = (GtkWidget *)create_dialog_inputmiss();
  gtk_widget_show(dialog_inputmiss);
  gtk_grab_add(dialog_inputmiss);
  gtk_main();

  ClientInit ();
  client_CB.mltdsp = CreateMultiSockToRecv (ADVERTISE_IP, ADVERTISE_PORT);
  client_CB.g_mltdsp = gdk_input_add (client_CB.mltdsp, GDK_INPUT_READ, \
                                      (GdkInputFunction)GetMultiVNCServerMsg, \
				      (gpointer)client_CB.mltdsp);
  
}

Bool
MultiRecieve1 ()
{
  struct sockaddr_in recvadd;
  int addr_len = sizeof(recvadd);
  int numrcv;
  ServerAdv serveradv;

  bzero(&serveradv, sizeof(ServerAdv));
  numrcv = recvfrom(client_CB.mltdsp, &serveradv, sizeof(ServerAdv), 0, \
      		    (struct sockaddr *)&recvadd, (socklen_t *)&addr_len);
  strncpy(client_CB.server_ID, serveradv.server_ID, IDLENGTH);

  if (strcmp((char *)client_CB.server_ID, (char *)client_CB.client_ID) == 0) {
//  if (memcmp((char *)client_CB.server_ID, (char *)client_CB.client_ID, IDLENGTH) == 0) {
    client_CB.server_ip = inet_addr(SERVER_IP);
    client_CB.server_port = htons(SERVER_PORT);
  } else {
    client_CB.server_ip = recvadd.sin_addr.s_addr;
    client_CB.server_port = serveradv.server_port;
  }
  
  fprintf(stderr, "\nrecv-adv %d\n",numrcv);
  fprintf(stderr, "type=%d\n",serveradv.type);
  fprintf(stderr, "length=%d\n",serveradv.length);
  fprintf(stderr, "serverID=%s\n",serveradv.server_ID);
  fprintf(stderr, "serverID=%x\n",serveradv.server_ID);
  fprintf(stderr, "serverip=%s\n",(char *)inet_ntoa(recvadd.sin_addr));
  fprintf(stderr, "serverport=%d\n\n",ntohs(serveradv.server_port));

  if (!strcmp((char *)connect_server, (char *)serveradv.server_ID)) {
    server_flag = 2;
  }

  if (server_flag != 1) {
    if (dialog_wait != NULL) {
      gtk_grab_remove(dialog_wait);
      gtk_widget_destroy(dialog_wait);
      dialog_wait = NULL;
    }
  }


  /* no option (-u and -s unset) */
  if ((auto_flag == 0) && (server_flag == 0)) {
    draw_string_to_mini_window(_("Connect?"));
    open_dialog_recvAdv((char *)serveradv.server_ID);
  }
  /* -u set and -s unset. -s set and match server_ID */
  else if (((auto_flag == 1) && (server_flag == 0)) || (server_flag == 2)) {
    draw_string_to_mini_window(_("Connect"));
  }

  if (((answer == 'y') || ((auto_flag == 1) && (server_flag == 0)) || (server_flag == 2)) && JoinCTL ()) {
    client_CB.connectstate = STAT_ADV;  
    return True;
  } 
  
  /* -s set and no match server_ID -> infinity loop */
  bzero(client_CB.server_ID, sizeof(client_CB.server_ID));
  client_CB.server_ip = 0;
  client_CB.server_port = 0;
  
  return False;
}

Bool
MultiRecieve2 ()
{
  struct sockaddr_in recvadd;
  ServerAdv serveradv;
  int numrcv;
  int addr_len = sizeof(recvadd);
  ExistAdv existadv;
  existadv.type = rfbClientExist;
  existadv.flag = client_CB.state;

  numrcv = recvfrom(client_CB.mltdsp, &serveradv, sizeof(ServerAdv), 0, \
      		    (struct sockaddr *)&recvadd, (socklen_t *)&addr_len);
  if (memcmp(&client_CB.server_ip, &recvadd.sin_addr, sizeof(CARD32)) != 0)
    return False; 

  send (client_CB.ctldsp, &existadv, sizeof(ExistAdv), 0);

  client_CB.del_pk_num = 0;
  SETRESEND_C (0);
  return True;
}

void
GetMultiVNCServerMsg (void *g_dsp)
{
  int dsp = (int)g_dsp;
  
  /* Recieve mltdsp Socket */
  if (dsp == client_CB.mltdsp) {
    gdk_input_remove(client_CB.g_mltdsp);

    if (client_CB.connectstate == STAT_FIRST) {
      if (!MultiRecieve1 ()) {
	client_CB.g_mltdsp = gdk_input_add (client_CB.mltdsp, GDK_INPUT_READ, \
	                                    (GdkInputFunction)GetMultiVNCServerMsg, \
					    (void *)client_CB.mltdsp);
	return;
      }
      client_CB.g_ctldsp = gdk_input_add (client_CB.ctldsp, GDK_INPUT_READ, \
	                                  (GdkInputFunction)GetMultiVNCServerMsg, \
					  (gpointer)client_CB.ctldsp);
    } else if ((client_CB.connectstate == STAT_VNC) || (client_CB.connectstate == STAT_CUT)) {
      MultiRecieve2 ();
    }
    client_CB.g_mltdsp = gdk_input_add (client_CB.mltdsp, GDK_INPUT_READ, \
                                	(GdkInputFunction)GetMultiVNCServerMsg, \
					(void *)client_CB.mltdsp);
  }

  /* Recieve ctldsp Socket */
  else if (dsp == client_CB.ctldsp) {

    char buf[2];
    //gdk_input_remove(client_CB.g_ctldsp);
    bzero (buf, 2);
    if (read (client_CB.ctldsp, buf, 2) <= 0) {
      CloseVNCServer();
      fprintf(stderr, "%s : session closed\n", programName);
      exit (EXIT_FAILURE);
    }
    printf("type=%d, flag=%d\n",buf[0],buf[1]);

    /* Screen Lock, Receive Teacher's Screen etc... */
    switch (buf[0]) {

      case rfbAllowAdv:
        printf("switch : rfbAllowAdv\n");
	if ((client_CB.connectstate == STAT_ADV) || (client_CB.connectstate == STAT_CUT)) {
	  if (buf[1] == 1) {
	      sleep(rand() %6);
	      usleep((rand() %2) * 500000);
              JoinVNC ();
	  }
	  else if (buf[1] == 0) {
              ClearServerInfo (); 
	  }
	}
	break;

      case rfbCastAdv: 
      {
        CastAdv castadv;

	printf("switch : rfbCastAdv=%d\n",GETRECV_C);
	if (read (client_CB.ctldsp, (char *)&castadv + 2, sizeof(CastAdv)-2) <= 0) {
	  CloseVNCServer();
	  fprintf(stderr, "%s : session closed\n", programName);
	  exit (EXIT_FAILURE);
	}

	if ((client_CB.connectstate == STAT_VNC) || (client_CB.connectstate == STAT_CUT)) {
	  if ((buf[1] == 1) && (!GETRECV_C)) {
	    SETRECV_C(1);

	    /* Stock data from MultiVNC server */
	    client_CB.casting_ip = castadv.casting_ip;
	    client_CB.casting_port = castadv.casting_port;
	    memcpy (&client_CB.serverInitMsg, &castadv.serverInitMsg, sizeof(rfbServerInitMsg));
	    memcpy(&si, &client_CB.serverInitMsg, sizeof(rfbServerInitMsg));
	    draw_string_to_mini_window(_("Receive Data"));

	    /* Create Multicast packet */
	    printf("ip=%s, port=%d\n",(char *)inet_ntoa(client_CB.casting_ip), \
							ntohs(client_CB.casting_port));
            client_CB.cstdsp = CreateMultiSockToRecv ((char *)inet_ntoa(client_CB.casting_ip), \
							ntohs(client_CB.casting_port));
	    const int size = 340000;
	    setsockopt (client_CB.cstdsp, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
	    client_CB.g_cstdsp = gdk_input_add (client_CB.cstdsp, GDK_INPUT_READ, \
		                                (GdkInputFunction)GetMultiVNCServerMsg, \
						(gpointer)client_CB.cstdsp);
	    /* Create window for drawing */
	    drawing_window = (GtkWidget *)create_drawing_window();
	    gtk_window_set_default_size(GTK_WINDOW(drawing_window), 600, 400);

	    GtkWidget *screen_label = (GtkWidget *)lookup_widget(GTK_WIDGET(drawing_window), "screen_label");
	    GtkWidget *client_drawingarea = (GtkWidget *)lookup_widget(GTK_WIDGET(drawing_window), "client_drawingarea");
	    gtk_label_set_text(GTK_LABEL(screen_label), (char *)castadv.src_ID);

	    drawingarea[0][0] = client_drawingarea;
	    gtk_widget_show(drawing_window);
	    if (castadv.fullscreen)
	      gdk_window_fullscreen(gdk_window_get_toplevel(drawing_window->window));
	    /* Initialize for drawing */
	    memcpy(&client_CB.serverFormat, &castadv.pixelFormat, sizeof(rfbPixelFormat));
	    DrawingInit();

	  } else if ((buf[1] == 0) && (GETRECV_C)) {
            SETRESEND_C(0);
	    SETRECV_C(0);
	    gdk_input_remove(client_CB.g_cstdsp);
	    close(client_CB.cstdsp);
	    gdk_image_destroy(gdkimage[0]);
	    gdk_image_destroy(smallimage[0]);
	    gtk_widget_destroy(drawing_window);
	    gdkimage[0] = NULL;
	    smallimage[0] = NULL;
	    drawing_window = NULL;
	    draw_string_to_mini_window(_("Connect"));
	  } 
	}
	break;
      }

      case rfbLockAdv:
      {
	LockAdv lockadv;
	
	printf("switch : rfbLockAdv\n");
	if (read (client_CB.ctldsp, (char *)&lockadv + 2, sizeof(LockAdv)-2) <= 0) {
	  CloseVNCServer();
	  fprintf(stderr, "%s : session closed\n", programName);
	  exit (EXIT_FAILURE);
	}

	if ((client_CB.connectstate == STAT_VNC) || (client_CB.connectstate == STAT_CUT)) {
	  if (buf[1]) {
	    if (lock_window == NULL)
	      create_lock_window();
	    else {
	      start_lock();
	      gtk_timeout_remove (lock_tag);
	    }
	    lock_tag = gtk_timeout_add((int)(lockadv.locktime + 10) * 1000, (GtkFunction)stop_lock, NULL);
	  } else {
	    gtk_timeout_remove (lock_tag);
	    stop_lock();
	  }
	}	
	break;
      } 

#if 0
      case rfbRecAdv:
      {
	RecAdv recadv;

	printf("switch : rfbRecAdv\n");
	if (recv (client_CB.ctldsp, (char *)&recadv + 2, sizeof(recadv)-2, 0) <= 0) {
	  CloseVNCServer();
	  fprintf(stderr, "%s : session closed\n", programName);
	  exit (EXIT_FAILURE);
	}

	if ((client_CB.connectstate == STAT_VNC) || (client_CB.connectstate == STAT_CUT)) {
	  switch (buf[1]) {
	    case START:
	      fprintf(stderr, "recording time:%d fps:%d\n", recadv.rectime, recadv.fps);  
	      start_record(recadv.fps,recadv.geometry, REC_PATH);
	      record_tag = gtk_timeout_add(recadv.rectime * 1000, stop_record, NULL);
	    break;

	    case STOP:
	      stop_record();
	    break;

	    default:
	  }
	}
	break;
      }

#endif
      case rfbVncConnAdv:
        client_CB.connectstate = buf[1];
	break;

      default:
	fprintf(stderr, "%s : Undefind Message\n", programName);
    } 
    //client_CB.g_ctldsp = gdk_input_add (client_CB.ctldsp, GDK_INPUT_READ, \
                                	  (GdkInputFunction)GetMultiVNCServerMsg, \
					  (void *)client_CB.ctldsp);
  } 

  /* Recieve cstdsp Socket */
  else if ((GETRECV_C) && (dsp == client_CB.cstdsp)) {

    gdk_input_remove(client_CB.g_cstdsp);
    if ((client_CB.connectstate == STAT_VNC) || (client_CB.connectstate == STAT_CUT)) {

      if (GETRECV_C) {
	if (!HandleMultiVNCServerMessage()) {
	  char dummy[BUFFER_SIZE];
	  int size;
	  fcntl(client_CB.cstdsp, F_SETFL, O_NONBLOCK);
	  size = recvfrom (client_CB.cstdsp, dummy, BUFFER_SIZE, 0, NULL, NULL);
	  buffered = 0;
	  fcntl(client_CB.cstdsp, F_SETFL, 0);
	  
          if (!GETRESEND_C) {
            client_CB.del_pk_num += size;
            if (client_CB.del_pk_num != CAST_PK_SIZE) {
	      /* request resend to server */
              SETRESEND_C(1);
	    }
	  }
	}
      }
    }
    client_CB.g_cstdsp = gdk_input_add (client_CB.cstdsp, GDK_INPUT_READ, \
	                                (GdkInputFunction)GetMultiVNCServerMsg, \
					(void *)client_CB.cstdsp);
  }

  else {
    fprintf(stderr, "%s : Can't find correct dsp\n", programName);
    return;
  }
  return;
}
  
Bool
ReadFromMultiVNCServer(char *out, unsigned int n)
{
  int rfbsock;
  struct sockaddr_in dest; 
  int len = sizeof(dest);
  bzero(&dest, sizeof(dest));
  dest.sin_family = AF_INET;
  dest.sin_addr.s_addr = client_CB.casting_ip;
  dest.sin_port = client_CB.casting_port;
  
  if (n <= buffered) {
    memcpy(out, bufoutptr, n);
    bufoutptr += n;
    buffered -= n;
    return True;
  }
  memcpy(out, bufoutptr, buffered);

  out += buffered;
  n -= buffered;

  bufoutptr = buf;
  buffered = 0;

  rfbsock = client_CB.cstdsp;

  if (n <= BUF_SIZE) {

    while (buffered < n) {

      int i = recvfrom (rfbsock, buf + buffered, BUF_SIZE - buffered, 0, \
	  		(struct sockaddr *)&dest, (socklen_t *)&len);
      if (dest.sin_addr.s_addr != client_CB.server_ip) continue;

      if (i <= 0) {
	if (i < 0) {
	  if (errno == EWOULDBLOCK || errno == EAGAIN) {
	    i = 0;
	  } else {
	    fprintf(stderr, "%s : recvfrom", programName);
	    continue;
	  }
	} else {
	  return False;
	}
      }
      buffered += i;
    }

    memcpy(out, bufoutptr, n);
    bufoutptr += n;
    buffered -= n;
    return True;

  } else {
    
    while (n > 0) {
      int i = recvfrom (rfbsock, out, n, 0, (struct sockaddr *)&dest, (socklen_t *)&len);
      if (i <= 0) {
	if (i < 0) {
	  if (errno == EWOULDBLOCK || errno == EAGAIN) {
	    i = 0;
	  } else {
	    fprintf(stderr, "%s : read\n", programName);
	    return False;
	  }
	} else {
	  return False;
	}
      }
      out += i;
      n -= i;
    }

    return True;
  }
}

int page=0;
Bool
HandleMultiVNCServerMessage()
{
  rfbServerToClientMsg msg;

  CreateImageInfoForClient();
  if (!ReadFromMultiVNCServer((char *)&msg, 1))
    return False;

  if (msg.type != rfbFramebufferUpdate) return False;

  if (msg.type == rfbFramebufferUpdate) {

    rfbFramebufferUpdateRectHeader rect;
    int linesToRead;
    int bytesPerLine;
    int i;
    GdkRectangle gdkrect;

    if (!ReadFromMultiVNCServer(((char *)&msg.fu) + 1,
			   sz_rfbFramebufferUpdateMsg - 1))
      return False;

    msg.fu.nRects = Swap16IfLE(msg.fu.nRects);
    for (i = 0; i < msg.fu.nRects; i++) {
      if (!ReadFromMultiVNCServer((char *)&rect, sz_rfbFramebufferUpdateRectHeader))
	return False;

      rect.encoding = Swap32IfLE(rect.encoding);
      if (rect.encoding == rfbEncodingLastRect)
	break;

      rect.r.x = Swap16IfLE(rect.r.x);
      rect.r.y = Swap16IfLE(rect.r.y);
      rect.r.w = Swap16IfLE(rect.r.w);
      rect.r.h = Swap16IfLE(rect.r.h);

      if (rect.encoding == rfbEncodingXCursor ||
	  rect.encoding == rfbEncodingRichCursor) {
	/*if (!HandleCursorShape(rect.r.x, rect.r.y, rect.r.w, rect.r.h,
			      rect.encoding)) {
	  return False;
	}*/
	continue;
      }

      if (rect.encoding == rfbEncodingPointerPos) {
	/*if (!HandleCursorPos(rect.r.x, rect.r.y)) {
	  return False;
	}*/
	continue;
      }

      if ((rect.r.x + rect.r.w > client_CB.serverInitMsg.framebufferWidth) ||
	  (rect.r.y + rect.r.h > client_CB.serverInitMsg.framebufferHeight)) {
	//fprintf(stderr,"Rect too large: %dx%d at (%d, %d)\n", \
		  rect.r.w, rect.r.h, rect.r.x, rect.r.y);
	return False;
      }

      if (rect.r.h * rect.r.w == 0) {
	//fprintf(stderr,"Zero size rect - ignoring\n");
	continue;
      }

      switch (rect.encoding) {

      case rfbEncodingRaw:
	bytesPerLine = rect.r.w * myFormat.bitsPerPixel / 8;
	linesToRead = BUFFER_SIZE / bytesPerLine;

	while (rect.r.h > 0) {
	  if (linesToRead > rect.r.h)
	    linesToRead = rect.r.h;

	  if (!ReadFromMultiVNCServer(buffer,bytesPerLine * linesToRead)) {
	    printf("read false?\n");
	    return False;
	  }
	  CopyDataToScreenForClient(buffer, rect.r.x, rect.r.y, rect.r.w,
			   linesToRead);

	  rect.r.h -= linesToRead;
	  rect.r.y += linesToRead;
	}
	break;

      case rfbEncodingCopyRect:
      {
	rfbCopyRect cr;

	if (!ReadFromMultiVNCServer((char *)&cr, sz_rfbCopyRect))
	  return False;

	cr.srcX = Swap16IfLE(cr.srcX);
	cr.srcY = Swap16IfLE(cr.srcY);

	if (appData.copyRectDelay != 0) {
          draw_rectangle(gdkpixmap[page][da_num], gdksrcGC, TRUE, cr.srcX, cr.srcY,
                       rect.r.w, rect.r.h, 0x0f0f0f0f);
          draw_rectangle(gdkpixmap[page][da_num], gdksrcGC, TRUE, rect.r.x, rect.r.y,
                       rect.r.w, rect.r.h, 0x0f0f0f0f);
	  XSync(dpy,False);
	  usleep(appData.copyRectDelay * 1000);
          draw_rectangle(gdkpixmap[page][da_num], gdksrcGC, TRUE, rect.r.x, rect.r.y,
                       rect.r.w, rect.r.h, 0x0f0f0f0f);
          draw_rectangle(gdkpixmap[page][da_num], gdksrcGC, TRUE, cr.srcX, cr.srcY,
                       rect.r.w, rect.r.h, 0x0f0f0f0f);
	}

        window_copy_area_for_client(gdkpixmap[0][0], gdkGC, rect.r.x, rect.r.y,
                       gdkpixmap[0][0], cr.srcX, cr.srcY, rect.r.w, rect.r.h);

	break;
      }

      case rfbEncodingRRE:
      {
	switch (myFormat.bitsPerPixel) {
	case 8:
	  if (!HandleRRE8(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
	    return False;
	  break;
	case 16:
	  if (!HandleRRE16(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
	    return False;
	  break;
	case 32:
	  if (!HandleRRE32(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
	    return False;
	  break;
	}
	break;
      }

      case rfbEncodingCoRRE:
      {
	switch (myFormat.bitsPerPixel) {
	case 8:
	  if (!HandleCoRRE8(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
	    return False;
	  break;
	case 16:
	  if (!HandleCoRRE16(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
	    return False;
	  break;
	case 32:
	  if (!HandleCoRRE32(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
	    return False;
	  break;
	}
	break;
      }

      case rfbEncodingHextile:
      {
	switch (client_CB.serverFormat.bitsPerPixel) {
	case 8:
	  switch (myFormat.bitsPerPixel) {
	  case 8:
	    if (!HandleHextile8To8(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
	      return False;
	    break;
	  case 16:
	    if (!HandleHextile8To16(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
	      return False;
	    break;
	  case 32:
	    if (!HandleHextile8To32(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
	      return False;
	    break;
	  }
	  break;
	case 16:
	  switch (myFormat.bitsPerPixel) {
	  case 8:
	    if (!HandleHextile16To8(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
	      return False;
	    break;
	  case 16:
	    if (!HandleHextile16To16(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
	      return False;
	    break;
	  case 32:
	    if (!HandleHextile16To32(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
	      return False;
	    break;
	  }
	  break;
	case 32:
	  switch (myFormat.bitsPerPixel) {
	  case 8:
	    if (!HandleHextile32To8(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
	      return False;
	    break;
	  case 16:
	    if (!HandleHextile32To16(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
	      return False;
	    break;
	  case 32:
	    if (!HandleHextile32To32(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
	      return False;
	    break;
	  }
	  break;
	}
	break;
      }

      case rfbEncodingZlib:
      {
	switch (myFormat.bitsPerPixel) {
	case 8:
	  if (!HandleZlib8(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
	    return False;
	  break;
	case 16:
	  if (!HandleZlib16(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
	    return False;
	  break;
	case 32:
	  if (!HandleZlib32(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
	    return False;
	  break;
	}
	break;
      }

      case rfbEncodingTight:
      {
	switch (myFormat.bitsPerPixel) {
	case 8:
	  if (!HandleTight8(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
	    return False;
	  break;
	case 16:
	  if (!HandleTight16(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
	    return False;
	  break;
	case 32:
	  if (!HandleTight32(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
	    return False;
	  break;
	}
	break;
      }

      default:
	//fprintf(stderr,"Unknown rect encoding %d\n", (int)rect.encoding);
	return False;
      } 
    }

    gdkrect.x = 0;
    gdkrect.y = 0;
    gdkrect.width = drawingarea[0][0]->allocation.width;
    gdkrect.height = drawingarea[0][0]->allocation.height;
    gtk_widget_draw(drawingarea[0][0], &gdkrect);

    XSync(dpy, False);
  }
  return True;
}

void
help (char *cmd)
{
  fprintf(stderr, "\nmultivnc_client\n");
  fprintf(stderr, "  -d [num]\t\tDisplay number of vncserver\n\n");
  fprintf(stderr, "  -s [server_name]\tInput server ID\n\n");
  fprintf(stderr, "  -u [user_name]\tInput client ID and auto connect.\n\n");
  fprintf(stderr, "  --nonotice\t\tState window is not displayed.\n\n");
}

void
StartVNCServer()
{
  char vncserver_cmd[16] = "vncserver :";
  if (atoi(vncdisplay) != 0) {
    printf("---start vncserver---\n");
    strcat(vncserver_cmd, vncdisplay);
    printf("%s", vncserver_cmd);
    system(vncserver_cmd);
    printf("\n-----\n\n");
  }
}

void
CloseVNCServer()
{
  char vncserver_cmd[32] = "vncserver -kill :";
  if (atoi(vncdisplay) != 0) {
    printf("---close vncserver---\n");
    strcat(vncserver_cmd, vncdisplay);
    printf("%s", vncserver_cmd);
    system(vncserver_cmd);
    printf("\n-----\n\n");
  }
}

int
adjustColorBitShift(short server_bits, short client_bits)
{
  int i, count = 0;
  short bits;

  bits = server_bits ^ client_bits;
  for (i = 0; i < 8; i++) {
    count = count + (bits & 0x01);
    bits = bits >> 1;
  }

  return count;
}

