#include "vncviewer.h"
#include <sys/socket.h>
#include <resolv.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <errno.h>
#include <mysql.h>

#include <unistd.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <signal.h>

typedef struct _GdkIOClosure GdkIOClosure;
struct _GdkIOClosure
{
  GdkInputFunction function;
  GdkInputCondition condition;
  GdkDestroyNotify notify;
  gpointer data;
};

static void controlSocketCallback(gpointer clientData, gint fd, GdkInputCondition condition);
static void vncSocketCallback(gpointer clientData, gint fd, GdkInputCondition condition);
static Bool CheckDrawingarea(int);
static Bool DiscoverDrawingarea(int);
void CheckLockClient(void);
extern char *swf_file;

int getClientFromCtldsp (int fd);
int getClientFromVncdsp (int fd);
void SendCastMsg (char flag, int clientNum, char fullscreen);
int ConnectMyself ();
Bool AuthDB (char *client_ID);


extern int multi_ttl;
extern GtkWidget *main_window;
GtkWidget *dialog_IDinput;

//extern GtkWidget *dialog_record;


/* shared memory */
long *shm_sec;
long *shm_usec;
struct timeval timenow;
struct Shm_asym *shm_asym[MAXCLIENT];

/* semaphore */
int semaphore;
struct sembuf semb;
union semun {
  int val;
  struct semid_ds *buf;
  unsigned short *array;
  struct seminfo *__buf;
};

int
SendAdv ()
{
  int sockadv;
  int pchild;
  int shm_id_s;
  int shm_id_u;
  
  shm_id_s = shmget ((key_t)1111, sizeof(long), 0666 | IPC_CREAT);
  if (shm_id_s == -1) {
    fprintf(stderr, "error : shm_id_s\n");
    exit (1);
  }
  shm_id_u = shmget ((key_t)2222, sizeof(long), 0666 | IPC_CREAT);
  if (shm_id_u == -1) {
    fprintf(stderr, "error : shm_id_u\n");
    exit (1);
  }
  shm_sec = (long *)shmat(shm_id_s, 0, 0);
  if ((int)shm_sec == -1) {
    fprintf(stderr, "error : shm_sec\n");
    exit (1);
  }
  shm_usec = (long *)shmat(shm_id_u, 0, 0);
  if ((int)shm_usec == -1) {
    fprintf(stderr, "error : shm_usec\n");
    exit (1);
  }
  
  sockadv = CreateMultiSockToSend (server_CB.advertise_ip, server_CB.advertise_port); 

  if ((pchild = fork()) == 0) {
    /* child */
    struct sockaddr_in adv;
    ServerAdv serveradv;

    /* Make Advertise Packet */
    serveradv.type = rfbServerAdv;
    serveradv.length = sizeof(ServerAdv);
    serveradv.server_port = server_CB.server_port;
    memcpy(serveradv.server_ID, server_CB.server_ID, IDLENGTH);

    /* Initialize address/port structure */
    bzero(&adv, sizeof(struct sockaddr_in));
    adv.sin_family = AF_INET;
    adv.sin_port = server_CB.advertise_port;
    adv.sin_addr.s_addr = server_CB.advertise_ip;

    while (1) {
      sleep(INTERVAL);	/*interval*/
      if (getppid() == 1) exit(-1);
      gettimeofday (&server_CB.basetime, 0);
      (*shm_sec) = server_CB.basetime.tv_sec;
      (*shm_usec) = server_CB.basetime.tv_usec;
      sendto(sockadv, &serveradv, serveradv.length, 0, (struct sockaddr *)&adv, sizeof(adv));
    }
  }

  return sockadv;
}


int
ConnectAdv ()
{
  int sockfd;
  struct sockaddr_in self;
  int optval = 1;

  /* Create listen socket */
  if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
    fprintf(stderr, programName);
    perror(":sockfd : socket");
    return False;
  }

  if (setsockopt (sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof (optval)) < 0) {
    fprintf(stderr, programName);
    perror(":sendfd : so_reuseaddr");
    close(sockfd);
    return False;
  }

  /* Initialize address/port structure */
  bzero(&self, sizeof(struct sockaddr_in));
  self.sin_family = AF_INET;
  self.sin_port = server_CB.server_port;
  self.sin_addr.s_addr = INADDR_ANY;

  /* Assign a port number to the socket */
  if (bind(sockfd, (struct sockaddr*)&self, sizeof(self)) != 0) {
    fprintf(stderr, programName);
    perror(":sockfd : bind");
    close(sockfd);
    return False;
  }

  /* Make it a "listening socket" */
  if (listen(sockfd, MAXCON) != 0) {
    fprintf(stderr, programName);
    perror(":sockfd : listen");
    close(sockfd);
    return False;
  }

  /* Connect Myself */
  if (ConnectMyself() < 0) {
    fprintf(stderr, programName);
    perror(":sendAdv: ");
    close(sockfd);
    return False;
  }

  /* Send Advertise */
  if (SendAdv() < 0) {
    fprintf(stderr, programName);
    perror(":sendAdv: ");
    close(sockfd);
    return False;
  }

  return sockfd;
}

void
AdvInit ()
{
  int i;
  char low_ip[4];

  bzero(&server_CB, sizeof(struct server_cb));
  /* Input Server_ID */
  dialog_IDinput = (GtkWidget *)create_dialog_IDinput();
  gtk_widget_show(dialog_IDinput);
  gtk_grab_add(dialog_IDinput);
  gtk_main();
  server_CB.server_port = htons(SERVER_PORT);
  server_CB.advertise_ip = inet_addr(ADVERTISE_IP);
  server_CB.advertise_port = htons(ADVERTISE_PORT);

  /* Casting_ip/port Initialize */
  for (i=0; i < MAXCLIENT-2; i++) {
    char tmp_ip[32];
    CARD32 int_ip;
    bzero (tmp_ip, 32);
    strcat (tmp_ip, DEFAULT_IP);
    sprintf (low_ip, "%d\0", i+1);
    strcat (tmp_ip, low_ip);
    int_ip = inet_addr(tmp_ip);
    memcpy ((int *)&server_CB.casting_ip[i], (int *)&int_ip, sizeof(int));
  }
  server_CB.casting_port = htons(SERVER_PORT);

  //sem_init ();
}

int
ConnectMyself ()
{
  char tmp[256] = "multivnc_client -d 1 --nonotice -u ";
  strcat (tmp, (char *)server_CB.server_ID);
  strcat (tmp, " -s ");
  strcat (tmp, (char *)server_CB.server_ID);
  strcat (tmp, " &");
  printf("tmp=%s\n",tmp);

  return system(tmp);
}
  
void
ConnectCTL (struct sockaddr_in client_addr, int ctldsp, int cnum)
{
  printf("************ ConnectCTL ******************\n");
  printf("cnum=%d\n",cnum);
  server_CB.client_grp[cnum] = malloc(sizeof(struct client_grp));
  bzero(server_CB.client_grp[cnum], sizeof(struct client_grp));
  server_CB.client_grp[cnum]->ctldsp = ctldsp;
  server_CB.client_grp[cnum]->client_ip = client_addr.sin_addr.s_addr;
  server_CB.client_grp[cnum]->client_port = client_addr.sin_port;

  printf("%s:%d connected\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
  printf("ctldsp=%d\n",(int)server_CB.client_grp[cnum]->ctldsp);
  printf("clientip=%s\n",inet_ntoa(client_addr.sin_addr));
  printf("clientport=%d\n",ntohs(client_addr.sin_port));

  server_CB.client_grp[cnum]->g_ctldsp = gdk_input_add_priority (server_CB.client_grp[cnum]->ctldsp, 
      GDK_INPUT_READ, (GdkInputFunction)controlSocketCallback, NULL, INPUT_PRIORITY);

  printf("ConnectCTL=%d\n",(int)server_CB.client_grp[cnum]);
  printf("ctl=%d, g_ctl=%d\nvnc=%d, g_vnc=%d\n",(int)server_CB.client_grp[cnum]->ctldsp,
      (int)server_CB.client_grp[cnum]->g_ctldsp,(int)server_CB.client_grp[cnum]->vncdsp,
      (int)server_CB.client_grp[cnum]->g_vncdsp);
  printf("************ END ******************\n");
}


void
ConnectVNC (struct sockaddr_in client_addr, int vncdsp, int cnum)
{
  sem_lock ();
  printf("************ ConnectVNC ******************\n");
  printf("cnum=%d\n",cnum);
  server_CB.client_grp[cnum]->vncdsp = vncdsp;
  
  printf("%s:%d connected\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
  printf("vncdsp=%d\n",(int)server_CB.client_grp[cnum]->vncdsp);
  printf("vncclientip=%s\n",inet_ntoa(client_addr.sin_addr));
  printf("vncclientport=%d\n",ntohs(client_addr.sin_port));

  printf("connectVNC rfbsock from:%d to:%d\n",rfbsock,vncdsp);
  rfbsock = vncdsp;
  server_CB.processingNum = cnum;
  if (InitialiseRFBConnection() == False) {
    printf("InitialiseRFBConnection_error\n");
    return;
  }

  SetVisualAndCmap();
  ToplevelInitBeforeRealization();

  if (gdkimage[cnum] == NULL) {
    gdkimage[cnum] = gdk_image_new (GDK_IMAGE_FASTEST, gdkvis,
				    server_CB.client_grp[cnum]->serverInitMsg.framebufferWidth,
				    server_CB.client_grp[cnum]->serverInitMsg.framebufferHeight);
  }
  if (smallimage[cnum] == NULL) {
    smallimage[cnum] = gdk_image_new (GDK_IMAGE_FASTEST, gdkvis,
				      server_CB.client_grp[cnum]->serverInitMsg.framebufferWidth,
				      server_CB.client_grp[cnum]->serverInitMsg.framebufferHeight);
  }

  DesktopInitAfterRealization();
  SetFormatAndEncodings();

  if (!CheckDrawingarea(cnum)) {
    server_CB.client_grp[cnum]->cast_grp = EMPTY;
    server_CB.client_grp[cnum]->recv_grp = EMPTY;
    if (!DiscoverDrawingarea(cnum)) {
      if (tab_num == TAB_MAX) return;
      else {
	strcpy(draw_info[tab_num].group_name, "new group");
	server_CB.client_grp[cnum]->draw_page = page = tab_num;
	server_CB.client_grp[cnum]->draw_area = da_num = 0;
	makeTable(page, 2, 2);
	ChangeLabel(page, 0, (char *)server_CB.client_grp[cnum]->client_ID);
	tab_num++;
      }
    }
  } else {
    page = server_CB.client_grp[cnum]->draw_page;
    da_num = server_CB.client_grp[cnum]->draw_area;
  }

  clientNum = draw_info[page].client_num[da_num] = cnum;
  CreateImageInfo(FALSE);
  if ((gdkpixmap[page][da_num]) && (page == current_page) && (da_num < draw_info[page].row * draw_info[page].column) \
      || (GETSEND(cnum)))
    SendAllFramebufferUpdateRequest();

  server_CB.client_grp[cnum]->g_vncdsp = gdk_input_add_priority (server_CB.client_grp[cnum]->vncdsp, GDK_INPUT_READ, \
							  (GdkInputFunction)vncSocketCallback, NULL, INPUT_PRIORITY);

  add_to_dialog_viewset(cnum);

  printf("ConnectVNC=%d\n",(int)server_CB.client_grp[cnum]);
  printf("ctl=%d, g_ctl=%d\nvnc=%d, g_vnc=%d\n",(int)server_CB.client_grp[cnum]->ctldsp,
      (int)server_CB.client_grp[cnum]->g_ctldsp,(int)server_CB.client_grp[cnum]->vncdsp,
      (int)server_CB.client_grp[cnum]->g_vncdsp);
  printf("************ END ******************\n");
  sem_unlock ();
}

void
gdk_input_remove_all ()
{
  int i;
  for (i = 0; i < server_CB.user_num; i++) {
    if (server_CB.client_grp[i] == NULL) continue;
    gdk_input_remove(server_CB.client_grp[i]->g_vncdsp);
    gdk_input_remove(server_CB.client_grp[i]->g_ctldsp);
  }
}

void
gdk_input_add_all ()
{
  int i;
  for (i = 0; i < server_CB.user_num; i++) {
    if (server_CB.client_grp[i] == NULL) continue;
    if (server_CB.client_grp[i]->g_vncdsp != 0)
    server_CB.client_grp[i]->g_vncdsp = gdk_input_add_priority (server_CB.client_grp[i]->vncdsp,
                                              GDK_INPUT_READ, (GdkInputFunction)vncSocketCallback, NULL, INPUT_PRIORITY);
    if (server_CB.client_grp[i]->g_ctldsp != 0)
    server_CB.client_grp[i]->g_ctldsp = gdk_input_add_priority (server_CB.client_grp[i]->ctldsp,
		                              GDK_INPUT_READ, (GdkInputFunction)controlSocketCallback, NULL, INPUT_PRIORITY);
      
  }
}

static void
gdk_io_destroy (gpointer data)
{
  GdkIOClosure *closure = data;

  if (closure->notify)
    closure->notify(closure->data);

  g_free(closure);
}

#define READ_CONDITION (G_IO_IN | G_IO_HUP | G_IO_ERR)
#define WRITE_CONDITION (G_IO_OUT | G_IO_ERR)
#define EXCEPTION_CONDITION (G_IO_PRI)

static gboolean
gdk_io_invoke (GIOChannel   *source,
	       GIOCondition condition,
	       gpointer     data)
{
  GdkIOClosure *closure = data;
  GdkInputCondition gdk_cond = 0;

  if (condition & READ_CONDITION)
    gdk_cond |= GDK_INPUT_READ;
  if (condition & WRITE_CONDITION)
    gdk_cond |= GDK_INPUT_WRITE;
  if (condition & EXCEPTION_CONDITION)
    gdk_cond |= GDK_INPUT_EXCEPTION;

  if (closure->condition & gdk_cond)
    closure->function(closure->data, g_io_channel_unix_get_fd(source), gdk_cond);

  return TRUE;
}

gint
gdk_input_add_priority (gint              source,
			GdkInputCondition condition,
			GdkInputFunction  function,
			gpointer          data,
			gint              priority)
{
  guint result;
  GdkIOClosure *closure = g_new(GdkIOClosure, 1);
  GIOChannel *channel;
  GIOCondition cond = 0;

  closure->function = function;
  closure->condition = condition;
  closure->notify = NULL;
  closure->data = data;

  if (condition & GDK_INPUT_READ)
    cond |= READ_CONDITION;
  if (condition & GDK_INPUT_WRITE)
    cond |= WRITE_CONDITION;
  if (condition & GDK_INPUT_EXCEPTION)
    cond |= EXCEPTION_CONDITION;

  channel = g_io_channel_unix_new(source);
  result = g_io_add_watch_full(channel, priority, cond, gdk_io_invoke,
			       closure, gdk_io_destroy);
  g_io_channel_unref(channel);

  return result;
}

void
controlSocketCallback (gpointer clientData, gint fd, GdkInputCondition condition)
{
  clientNum = getClientFromCtldsp (fd);
  if (clientNum == EMPTY) return;
  gdk_input_remove(server_CB.client_grp[clientNum]->g_ctldsp);
  int socket = server_CB.client_grp[clientNum]->ctldsp;
  char buf[64];

  bzero (buf, 64);
  if (recv (socket, buf, 2, 0) <= 0) {
    printf("session closed\n");

    /* クライアント消去 */
    if ((exDB_flag) && (!chStateDB(clientNum, 0))) {
      fprintf(stderr, "Can't Connect DB Server.\n");
    }

    if (server_CB.client_grp[clientNum]->g_vncdsp != 0) {
      int p,d;
      GdkRectangle gdkrect;

      DestroyImageInfo(clientNum);
      p = server_CB.client_grp[clientNum]->draw_page;
      d = server_CB.client_grp[clientNum]->draw_area;
      draw_info[p].client_num[d] = EMPTY;
      if (draw_info[p].row * draw_info[p].column > d) {
	ChangeLabel(p, d, "no client");
	gdk_draw_rectangle(gdkpixmap[p][d], drawingarea[p][d]->style->white_gc, TRUE,
			   0, 0, drawingarea[p][d]->allocation.width,
			   drawingarea[p][d]->allocation.height);
	gdkrect.x = 0;
	gdkrect.y = 0;
	gdkrect.width = drawingarea[p][d]->allocation.width;
	gdkrect.height = drawingarea[p][d]->allocation.height;
	gtk_widget_draw(drawingarea[p][d], &gdkrect);
      }
      if (gdkimage[clientNum]) {
	gdk_image_destroy(gdkimage[clientNum]);
	gdkimage[clientNum] = NULL;
      }
      if (smallimage[clientNum]) {
	gdk_image_destroy(smallimage[clientNum]);
	smallimage[clientNum] = NULL;
      }
      printf("Init cnum=%d\n",clientNum);
      bzero(&zlibStream[clientNum][0], sizeof(z_stream)*4);
      bzero(&zlibStreamActive[clientNum][0], sizeof(Bool)*4);
      gdk_input_remove(server_CB.client_grp[clientNum]->g_vncdsp);
      close(server_CB.client_grp[clientNum]->vncdsp);
    }

    if ((clientNum == clientNum_ex) && (window_ex != NULL)) {
      gtk_widget_destroy(window_ex);
      window_ex = NULL;
    }
    gdk_input_remove(server_CB.client_grp[clientNum]->g_ctldsp);
    close(server_CB.client_grp[clientNum]->ctldsp);
    bzero (server_CB.client_grp[clientNum], sizeof(struct client_grp));
    free(server_CB.client_grp[clientNum]);
    server_CB.client_grp[clientNum] = NULL;
    server_CB.user_num--;
    return;
  }
 
  switch (buf[0]) {

    case rfbClientAdv:
      printf("rfbClientAdv\n");
      if (recv (socket, buf, IDLENGTH, 0) <= 0) {
        printf("error rfbClientAdv \n");
      }
      memcpy (server_CB.client_grp[clientNum]->client_ID, buf, IDLENGTH);
      printf("Client : %s\n",server_CB.client_grp[clientNum]->client_ID);
      fprintf(stderr, "Control packet receive\n");
      
      /* Database Authentication */
      SendAllowMsg (clientNum, buf);
      break;

    case rfbClientExist:
      server_CB.client_grp[clientNum]->state &= ~LOCKSTATE | (buf[1] & LOCKSTATE);

      struct timeval tmptime;
      gettimeofday(&timenow, 0);
      tmptime.tv_usec = timenow.tv_usec - (*shm_usec);
      if (tmptime.tv_usec < 0) tmptime.tv_usec += ((timenow.tv_sec - (*shm_sec)) * 1000000);
      server_CB.client_grp[clientNum]->r_time = tmptime.tv_usec;

      if (buf[1] & RESENDSTATE) SETRESEND (clientNum, 1);
      if (!(buf[1] & RECSTATE)) SETREC (clientNum, 0);
      break;

#if 0
    case  rfbFileAdv:
      {
	size_t fsize, received = 0;
	char fname[STRLENGTH +1];
	char data[SWF_DATA +1];
	FILE *fp;

	if (read (socket, &fsize, sizeof(fsize)) <= 0) {
	  fprintf(stderr, "client:%d fsize", clientNum);
	  perror("read");
	  return;
	}
	if ((received = recv (socket, fname, STRLENGTH, 0)) < STRLENGTH) {
	  fprintf(stderr, "client:%dB file name", clientNum);
	  perror("recv");
	  return;
	}
	if ((received = recv (socket, data, SWF_DATA, 0)) < SWF_DATA) {
	  fprintf(stderr, "client:%dB file data %dB get", clientNum, received);
	  perror("recv");
	  return;
	}

//	fprintf(stderr, "recv(cnum:%d flag:%d fsize:%d(%d) name:%s(%d) data:%d\n", clientNum, buf[1], fsize, sizeof(fsize), fname, sizeof(fname), sizeof(data));
	switch (buf[1]) {
	// START or CONTINUE
	  case START:
	      fprintf(stderr, "client:%d %s revcieve start.\n", clientNum, fname);
	  case CONTINUE:
	    if ((server_CB.client_grp[clientNum]->fp = fopen(fname, "a+")) == NULL) {
	      fprintf(stderr, "client:%d ", clientNum);
	      perror("fopen");
	    }
	    if(fwrite(data, fsize, 1, server_CB.client_grp[clientNum]->fp) <= 0) {
//	    if(fwrite(data, received, 1, server_CB.client_grp[clientNum]->fp) <= 0) {
	      fprintf(stderr, "client:%d ", clientNum);
	      perror("fwrite");
	    }
	    fclose(server_CB.client_grp[clientNum]->fp);
	    break;

          case STOP:
	    {
	      fprintf(stderr, "client:%d %s(%d) revcieve done.\n", clientNum, fname, fsize);
	      SETREC(clientNum, STOP);
	      // bottun clear
	      if (dialog_record != NULL)
	        on_dialog_rec_stop_button_clicked(NULL, NULL);
	      /*
	      int pCnt = server_CB.client_grp[clientNum]->draw_page;
	      int dCnt = server_CB.client_grp[clientNum]->draw_area;
              gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog_send_checkbutton2[pCnt][dCnt]), GETREC(clientNum));
	      */
	      size_t size;
	      size = get_file_size(fname);
	      if (size != fsize) {
	        fprintf(stderr, "%s transfer error.(%d/%d)\n", fname, size, fsize);
	      }
	      else {
	        fprintf(stderr, "%s transfer success.(%d/%d)\n", fname, size, fsize);
	      }
	    }
	    break;
	}
      }
      break;

#endif

    default:
      perror("Unknown Message Type");
      printf("client:%d, type %d\n", clientNum, buf[0]);
      break;
  } 
  server_CB.client_grp[clientNum]->g_ctldsp = gdk_input_add_priority (server_CB.client_grp[clientNum]->ctldsp,
		        GDK_INPUT_READ, (GdkInputFunction)controlSocketCallback, NULL, INPUT_PRIORITY);
  return;
}

void
vncSocketCallback (gpointer clientData, gint fd, GdkInputCondition condition)
{
  sem_lock ();
  clientNum = getClientFromVncdsp (fd);
  if (clientNum == EMPTY) return;
  gdk_input_remove(server_CB.client_grp[clientNum]->g_vncdsp);
  page = server_CB.client_grp[clientNum]->draw_page;
  da_num = server_CB.client_grp[clientNum]->draw_area;
  /* 非表示クライアントの画像データは破棄 */
  if ((!GETSEND(clientNum)) && (!GETVIEW(clientNum))) {
    if ((page != current_page) || (draw_info[page].row * draw_info[page].column <= da_num) || 
	(gdkpixmap[page][da_num] == NULL)) {
      char dummybuf[MAXBUF];
      while (read(server_CB.client_grp[clientNum]->vncdsp, dummybuf, MAXBUF) == MAXBUF);
      server_CB.client_grp[clientNum]->g_vncdsp = gdk_input_add_priority (server_CB.client_grp[clientNum]->vncdsp, \
						   GDK_INPUT_READ, (GdkInputFunction)vncSocketCallback, NULL, INPUT_PRIORITY);
      return;
    }
  }
  rfbsock = server_CB.client_grp[clientNum]->vncdsp;
  reducedWindowWidth = drawingarea[page][da_num]->allocation.width;
  reducedWindowHeight = drawingarea[page][da_num]->allocation.height;
  CreateImageInfo(FALSE);
  memcpy(&si, &(server_CB.client_grp[clientNum]->serverInitMsg), sizeof(si));
  if (HandleRFBServerMessage() < 0) {
    printf("#########error#########\n");
  }
  sem_unlock ();

  server_CB.client_grp[clientNum]->g_vncdsp = gdk_input_add_priority (server_CB.client_grp[clientNum]->vncdsp, \
						GDK_INPUT_READ, (GdkInputFunction)vncSocketCallback, NULL, INPUT_PRIORITY);
  return;
}

int
getClientFromCtldsp (int fd)
{
  int cnt;
  int max = server_CB.user_num;

  for (cnt = 0; cnt < MAXCLIENT; cnt++) {
    if (server_CB.client_grp[cnt] == NULL) continue;
    if (server_CB.client_grp[cnt]->ctldsp == fd)
      return cnt;
  }
  fprintf (stderr, "getClientFromCtldsp search error, user_num : %d, fd : %d\n", max, fd);
  return EMPTY;
}

int
getClientFromVncdsp (int fd)
{
  int cnt;
  int max = server_CB.user_num;

  for (cnt = 0; cnt < MAXCLIENT; cnt++) {
    if (server_CB.client_grp[cnt] == NULL) continue;
    if (server_CB.client_grp[cnt]->vncdsp == fd)
      return cnt;
  }
  fprintf (stderr, "getClientFromVncdsp search error, user_num : %d, fd : %d\n", max, fd);
  return EMPTY;
}

Bool 
AuthDB (char *client_ID)
{

  /* client authentication */
  printf("AuthDB=%s\n",client_ID);    

  MYSQL *myData;
  MYSQL_RES *res;
  int num;
  
  char Tmpquery[64] = "select * from student where id = '";
  strcat(Tmpquery, client_ID);
  strcat(Tmpquery, "'");
  printf("%s\n", Tmpquery);
  
  printf("host=%s, port=%d, name=%s, pass=%s, database=%s\n", \
      server_CB.DB_Host,server_CB.DB_Port,server_CB.DB_Name,server_CB.DB_Pass,server_CB.DB_Database);
  if ((myData = mysql_init((MYSQL *)0)) && \
      mysql_real_connect (myData, (char *)server_CB.DB_Host, (char *)server_CB.DB_Name, \
      (char *)server_CB.DB_Pass, (char *)server_CB.DB_Database, server_CB.DB_Port, NULL, 0)) {
    num = mysql_query (myData, Tmpquery);
    if (num != 0) printf("Can't connect SQL-server\n");
    res = mysql_store_result(myData);
    if (mysql_num_rows(res) > 0) {
      /* success */
      mysql_close(myData);
      return True;
    }
    mysql_close(myData);
  }
  
  /* failure */
  printf("Failure\n");
  return False;
}

Bool 
chStateDB(int clientNum, int flag)
{
  MYSQL *myData;
  char Tmpquery[64];
  int num;

  if (flag) strcpy(Tmpquery, "update student set joinnow = 't' where joinnow = 'f' and id = '");
  else strcpy(Tmpquery, "update student set joinnow = 'f' where joinnow = 't' and id = '");
  strcat(Tmpquery, (char *)server_CB.client_grp[clientNum]->client_ID);
  strcat(Tmpquery, "'");

  printf("%s\n",Tmpquery);
  
  if ((myData = mysql_init((MYSQL *)0)) && \
      mysql_real_connect (myData, (char *)server_CB.DB_Host, (char *)server_CB.DB_Name, \
      (char *)server_CB.DB_Pass, (char *)server_CB.DB_Database, server_CB.DB_Port, NULL, 0)) {
    num = mysql_query (myData, Tmpquery);
    if (num == 0) {
      /* success */
      mysql_close(myData);
      return True;
    }
    mysql_close(myData);
  }
  
  /* failure */
  printf("Failure\n");
  return False;
}


static Bool
CheckDrawingarea(int client)
{
  int pCnt, dCnt;

  for (pCnt = 0; pCnt < tab_num; pCnt++) {
    for (dCnt = 0; dCnt < TABGROUP_MAX; dCnt++) {
      if (draw_info[pCnt].client_num[dCnt] == client) return True;
    }
  }

  return False;
}


static Bool
DiscoverDrawingarea(int client)
{
  int pCnt, dCnt, area;

  for (pCnt = 0; pCnt < tab_num; pCnt++) {
    area = draw_info[pCnt].row * draw_info[pCnt].column;
    for (dCnt = 0; dCnt < area; dCnt++) {
      if (draw_info[pCnt].client_num[dCnt] == EMPTY) {
	ChangeLabel(pCnt, dCnt, (char *)server_CB.client_grp[client]->client_ID);
	server_CB.client_grp[client]->draw_page = page = pCnt;
	server_CB.client_grp[client]->draw_area = da_num = dCnt;
	return True;
      }
    }
  }

  return False;
}

int
CreateMultiSockToSend (unsigned int ip, int port)
{
  int sockadv;
  struct sockaddr_in adv;
  struct ip_mreq stMreq;
  u_long TTLadv = multi_ttl;
  int optval = 1;

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

  if (setsockopt (sockadv, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof (optval)) < 0) {
    fprintf(stderr, "%s : CreateMultiSockToSend : so_reuseaddr\n", programName);
    close(sockadv);
    exit (1);
  }

  /* Initialize address/port structure */
  bzero(&adv, sizeof(struct sockaddr_in));
  adv.sin_family = AF_INET;
  adv.sin_port = port;
  adv.sin_addr.s_addr = ip;

  stMreq.imr_multiaddr.s_addr = adv.sin_addr.s_addr;
  stMreq.imr_interface.s_addr = INADDR_ANY;

  if (setsockopt(sockadv, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &stMreq, sizeof(stMreq)) < 0) {
    fprintf(stderr, "%s : CreateMultiSockToSend : ip_add_membership\n", programName);
    close(sockadv);
    exit (1);
  }

  if (setsockopt(sockadv, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &TTLadv, sizeof(TTLadv)) < 0) {
    fprintf(stderr, "%s : CreateMultiSockToSend : ip_multicast_ttl\n", programName);
    close(sockadv);
    exit (1);
  }

  return sockadv;
}

void
CutVNC (int clientNum)
{
  if (server_CB.client_grp[clientNum]->vncdsp) {
    printf("CutVNC cnum=%d\n",clientNum);
    bzero(&zlibStream[clientNum][0], sizeof(z_stream)*4);
    bzero(&zlibStreamActive[clientNum][0], sizeof(Bool)*4);
    gdk_input_remove(server_CB.client_grp[clientNum]->g_vncdsp);
    close(server_CB.client_grp[clientNum]->vncdsp);
    server_CB.client_grp[clientNum]->vncdsp = 0;
  }
}

void 
SendCastMsg (char flag, int clientNum, char fullscreen)
{
  CastAdv castadv;
  int len;
  int i;

  bzero(&castadv, sizeof(CastAdv));
  castadv.type = rfbCastAdv;
  castadv.flag = flag;
  castadv.casting_ip = server_CB.casting_ip[server_CB.client_grp[clientNum]->recv_grp];
  castadv.casting_port = server_CB.casting_port;
  castadv.fullscreen = fullscreen;
  memcpy(&castadv.pixelFormat, &myFormat, sizeof(rfbPixelFormat));

  for (i = 0; i < MAXCLIENT; i++) {
    if (server_CB.client_grp[i]->cast_grp == server_CB.client_grp[clientNum]->recv_grp) {
      memcpy (castadv.src_ID, server_CB.client_grp[i]->client_ID, IDLENGTH);
      memcpy (&castadv.serverInitMsg, &server_CB.client_grp[i]->serverInitMsg, sizeof(rfbServerInitMsg));
      break;
    }
  }

  len = write (server_CB.client_grp[clientNum]->ctldsp, &castadv, sizeof(CastAdv));
}

void 
SendLockMsg (char flag, int clientNum)
{
  LockAdv lockadv;

  bzero(&lockadv, sizeof(LockAdv));
  lockadv.type = rfbLockAdv;
  lockadv.flag = flag;
  lockadv.locktime = LOCKTIME;

  write (server_CB.client_grp[clientNum]->ctldsp, &lockadv, sizeof(LockAdv));
}

void
SendAllowMsg (int clientNum, char *buf)
{
  AllowAdv allowadv;

  allowadv.type = rfbAllowAdv; 
  allowadv.flag = (exDB_flag) ? AuthDB (buf) : 1;

  send (server_CB.client_grp[clientNum]->ctldsp, &allowadv, sizeof(AllowAdv), 0);
}
  
void
SendVncMsg (int clientNum)
{
  VncConnAdv vncconnadv;

  vncconnadv.type = rfbVncConnAdv; 
  vncconnadv.flag = STAT_CUT;

  send (server_CB.client_grp[clientNum]->ctldsp, &vncconnadv, sizeof(VncConnAdv), 0);
}

void
CheckLockClient(void)
{
  int c_num, user_cnt = 0;

  for (c_num = 0; c_num < MAXCLIENT; c_num++) {
    if (server_CB.client_grp[c_num] == NULL) continue;
    if (GETLOCK(c_num))
      SendLockMsg(1, c_num);
    if (server_CB.user_num == ++user_cnt) return;
  }
}

void
sem_init ()
{
  /* セマフォの作成と初期化 */
  semaphore = semget ((key_t)9999, 1, 0666|IPC_CREAT);
  if (semaphore == -1) {
    fprintf(stderr, "semget error\n");
    exit (1);
  }
  {
    union semun semunion;

    semunion.val = 1;
    if (semctl(semaphore, 0, SETVAL, semunion) == -1) {
      fprintf(stderr, "semctl_init error\n");
      exit (1);
    }
  }

  semb.sem_num = 0;
  semb.sem_op = -1;
  semb.sem_flg = SEM_UNDO;
}

void
sem_lock ()
{
  return;
  /* セマフォの取得 */
  errno = 0;
  if (semop (semaphore, &semb, 1) == -1) {
    fprintf(stderr, "semop_wait error %d\n",errno);
    sem_init ();
  }
#if 0
  printf("nise_semaphore\n");
  /* 疑似的セマフォ */
  while (!semaphore);
  semaphore = 0;
#endif
}

void
sem_unlock ()
{
  return;
  /* セマフォの解放 */
  semb.sem_op = 1;
  if (semop (semaphore, &semb, 1) == -1) {
    fprintf(stderr, "semop_signal error\n");
  }
#if 0
  printf("nise_semaphore\n");
  /* 疑似的セマフォ */
  semaphore = 1;
#endif
}


