/*
 *  Copyright (C) 2000-2002 Constantin Kaplinsky.  All Rights Reserved.
 *  Copyright (C) 2000 Tridia Corporation.  All Rights Reserved.
 *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
 *
 *  This is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This software is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this software; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
 *  USA.
 */

/*
 * rfbproto.c - functions to deal with client side of RFB protocol.
 */

#include <unistd.h>
#include <errno.h>
#include <pwd.h>
#include <vncviewer.h>
#include <vncauth.h>
#include <zlib.h>
#include <jpeglib.h>

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 HandleHextile8(int rx, int ry, int rw, int rh);
static Bool HandleHextile16(int rx, int ry, int rw, int rh);
static Bool HandleHextile32(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 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);
void SendCast (int cnum);
int rfbCastUpdateBuf (char *buf, int len, char push);
int calcRate (int cnum);
void wait_buf (int cnum, int len);
int rate_alg (int maxdelay, int cnum);

int rfbsock;
char *desktopName;
rfbPixelFormat myFormat;
rfbServerInitMsg si;
char *serverCutText = NULL;
Bool newServerCutText = False;

int endianTest = 1;


/* Note that the CoRRE encoding uses this buffer and assumes it is big enough
   to hold 255 * 255 * 32 bits -> 260100 bytes.  640*480 = 307200 bytes.
   Hextile also assumes it is big enough to hold 16 * 16 * 32 bits.
   Tight encoding assumes BUFFER_SIZE is at least 16384 bytes. */

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


/* The zlib encoding requires expansion/decompression/deflation of the
   compressed data in the "buffer" above into another, result buffer.
   However, the size of the result buffer can be determined precisely
   based on the bitsPerPixel, height and width of the rectangle.  We
   allocate this buffer one time to be the full size of the buffer. */

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. */
z_stream zlibStream[MAXCLIENT][4];
Bool zlibStreamActive[MAXCLIENT][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;


/*
 * ConnectToRFBServer.
 */

Bool
ConnectToRFBServer(const char *hostname, int port)
{
  unsigned int host;

  sem_lock ();
  if (!StringToIPAddr(hostname, &host)) {
    fprintf(stderr,"Couldn't convert '%s' to host address\n", hostname);
    return False;
  }

  printf("connecttoRFBserver rfbsock from:%d ",rfbsock);
  rfbsock = ConnectToTcpAddr(host, port);
  printf("to:%d\n",rfbsock);

  if (rfbsock < 0) {
    fprintf(stderr,"Unable to connect to VNC server\n");
    sem_unlock ();
    return False;
  }

  return SetNonBlocking(rfbsock);
}


/*
 * InitialiseRFBConnection.
 */

Bool
InitialiseRFBConnection()
{
  rfbProtocolVersionMsg pv;
  int major,minor;
  CARD32 authScheme, reasonLen;
  char *reason;
  rfbClientInitMsg ci;
  rfbServerInitMsg *si;

  si = &(server_CB.client_grp[server_CB.processingNum]->serverInitMsg);

  /* if the connection is immediately closed, don't report anything, so
       that pmw's monitor can make test connections */

  if (listenSpecified)
    errorMessageOnReadFailure = False;
  usleep(1);

  if (!ReadFromRFBServer(pv, sz_rfbProtocolVersionMsg)) return False;

  errorMessageOnReadFailure = True;

  pv[sz_rfbProtocolVersionMsg] = 0;

  if (sscanf(pv,rfbProtocolVersionFormat,&major,&minor) != 2) {
    fprintf(stderr,"Not a valid VNC server\n");
    return False;
  }

  fprintf(stderr,"VNC server supports protocol version %d.%d (viewer %d.%d)\n",
	  major, minor, rfbProtocolMajorVersion, rfbProtocolMinorVersion);

  major = rfbProtocolMajorVersion;
  minor = rfbProtocolMinorVersion;

  sprintf(pv,rfbProtocolVersionFormat,major,minor);

  if (!WriteExact(rfbsock, pv, sz_rfbProtocolVersionMsg)) return False;

  if (!ReadFromRFBServer((char *)&authScheme, 4)) return False;

  authScheme = Swap32IfLE(authScheme);

  switch (authScheme) {

  case rfbConnFailed:
    if (!ReadFromRFBServer((char *)&reasonLen, 4)) return False;
    reasonLen = Swap32IfLE(reasonLen);

    reason = malloc(reasonLen);

    if (!ReadFromRFBServer(reason, reasonLen)) return False;

    fprintf(stderr,"VNC connection failed: %.*s\n",(int)reasonLen, reason);
    return False;

  case rfbNoAuth:
    fprintf(stderr,"No authentication needed\n");
    break;

  default:
    fprintf(stderr,"Unknown authentication scheme from VNC server: %d\n",
	    (int)authScheme);
    return False;
  }

  /* force share */
  //  ci.shared = (appData.shareDesktop ? 1 : 0);
  ci.shared = 1;

  if (!WriteExact(rfbsock, (char *)&ci, sz_rfbClientInitMsg)) return False;

  if (!ReadFromRFBServer((char *)si, sz_rfbServerInitMsg)) return False;

  si->framebufferWidth = Swap16IfLE(si->framebufferWidth);
  si->framebufferHeight = Swap16IfLE(si->framebufferHeight);
  si->format.redMax = Swap16IfLE(si->format.redMax);
  si->format.greenMax = Swap16IfLE(si->format.greenMax);
  si->format.blueMax = Swap16IfLE(si->format.blueMax);
  si->nameLength = Swap32IfLE(si->nameLength);
  
  desktopName = malloc(si->nameLength + 1);
  if (!desktopName) {
    fprintf(stderr, "Error allocating memory for desktop name, %lu bytes\n",
            (unsigned long)si->nameLength);
    return False;
  }

  if (!ReadFromRFBServer(desktopName, si->nameLength)) return False;

  desktopName[si->nameLength] = 0;

  fprintf(stderr,"Desktop name \"%s\"\n",desktopName);

  fprintf(stderr,"Connected to VNC server, using protocol version %d.%d\n",
	  rfbProtocolMajorVersion, rfbProtocolMinorVersion);

  fprintf(stderr,"VNC server default format:\n");

  PrintPixelFormat(&si->format);

  return True;
}


/*
 * SetFormatAndEncodings.
 */

Bool
SetFormatAndEncodings()
{
  rfbSetPixelFormatMsg spf;
  char buf[sz_rfbSetEncodingsMsg + MAX_ENCODINGS * 4];
  rfbSetEncodingsMsg *se = (rfbSetEncodingsMsg *)buf;
  CARD32 *encs = (CARD32 *)(&buf[sz_rfbSetEncodingsMsg]);
  int len = 0;
  Bool requestCompressLevel = False;
  Bool requestQualityLevel = False;
  Bool requestLastRectEncoding = False;

  spf.type = rfbSetPixelFormat;
  spf.format = myFormat;
  spf.format.redMax = Swap16IfLE(spf.format.redMax);
  spf.format.greenMax = Swap16IfLE(spf.format.greenMax);
  spf.format.blueMax = Swap16IfLE(spf.format.blueMax);

  if (!WriteExact(rfbsock, (char *)&spf, sz_rfbSetPixelFormatMsg))
    return False;

  se->type = rfbSetEncodings;
  se->nEncodings = 0;

  if (appData.encodingsString) {
    char *encStr = appData.encodingsString;
    int encStrLen;
    do {
      char *nextEncStr = strchr(encStr, ' ');
      if (nextEncStr) {
	encStrLen = nextEncStr - encStr;
	nextEncStr++;
      } else {
	encStrLen = strlen(encStr);
      }

      if (strncasecmp(encStr,"raw",encStrLen) == 0) {
	encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRaw);
      } else if (strncasecmp(encStr,"copyrect",encStrLen) == 0) {
	encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCopyRect);
      } else if (strncasecmp(encStr,"tight",encStrLen) == 0) {
	encs[se->nEncodings++] = Swap32IfLE(rfbEncodingTight);
	requestLastRectEncoding = True;
	if (appData.compressLevel >= 0 && appData.compressLevel <= 9)
	  requestCompressLevel = True;
	if (appData.enableJPEG)
	  requestQualityLevel = True;
      } else if (strncasecmp(encStr,"hextile",encStrLen) == 0) {
	encs[se->nEncodings++] = Swap32IfLE(rfbEncodingHextile);
      } else if (strncasecmp(encStr,"zlib",encStrLen) == 0) {
	encs[se->nEncodings++] = Swap32IfLE(rfbEncodingZlib);
	if (appData.compressLevel >= 0 && appData.compressLevel <= 9)
	  requestCompressLevel = True;
      } else if (strncasecmp(encStr,"corre",encStrLen) == 0) {
	encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCoRRE);
      } else if (strncasecmp(encStr,"rre",encStrLen) == 0) {
	encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRRE);
      } else {
	fprintf(stderr,"Unknown encoding '%.*s'\n",encStrLen,encStr);
      }

      encStr = nextEncStr;
    } while (encStr && se->nEncodings < MAX_ENCODINGS);

    if (se->nEncodings < MAX_ENCODINGS && requestCompressLevel) {
      encs[se->nEncodings++] = Swap32IfLE(appData.compressLevel +
					  rfbEncodingCompressLevel0);
    }

    if (se->nEncodings < MAX_ENCODINGS && requestQualityLevel) {
      if (appData.qualityLevel < 0 || appData.qualityLevel > 9)
        appData.qualityLevel = 5;
      encs[se->nEncodings++] = Swap32IfLE(appData.qualityLevel +
					  rfbEncodingQualityLevel0);
    }

    if (appData.useRemoteCursor) {
      if (se->nEncodings < MAX_ENCODINGS)
	encs[se->nEncodings++] = Swap32IfLE(rfbEncodingXCursor);
      if (se->nEncodings < MAX_ENCODINGS)
	encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRichCursor);
      if (se->nEncodings < MAX_ENCODINGS)
	encs[se->nEncodings++] = Swap32IfLE(rfbEncodingPointerPos);
    }

    if (se->nEncodings < MAX_ENCODINGS && requestLastRectEncoding) {
      encs[se->nEncodings++] = Swap32IfLE(rfbEncodingLastRect);
    }
  }

  else {
#if 0
    if (SameMachine(rfbsock)) {
      if (!tunnelSpecified) {
	fprintf(stderr,"Same machine: preferring raw encoding\n");
	encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRaw);
      } else {
	fprintf(stderr,"Tunneling active: preferring tight encoding\n");
      }
    }
#endif
    encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCopyRect);
    //encs[se->nEncodings++] = Swap32IfLE(rfbEncodingTight);
    encs[se->nEncodings++] = Swap32IfLE(rfbEncodingHextile);
    //encs[se->nEncodings++] = Swap32IfLE(rfbEncodingZlib);
    encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCoRRE);
    encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRRE);
    if (appData.compressLevel >= 0 && appData.compressLevel <= 9) {
      encs[se->nEncodings++] = Swap32IfLE(appData.compressLevel +
					  rfbEncodingCompressLevel0);
    } else if (!tunnelSpecified) {


      /* If -tunnel option was provided, we assume that server machine is
	 not in the local network so we use default compression level for
	 tight encoding instead of fast compression. Thus we are
	 requesting level 1 compression only if tunneling is not used. */

      encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCompressLevel1);
    }
    if (appData.enableJPEG) {
      if (appData.qualityLevel < 0 || appData.qualityLevel > 9)
	appData.qualityLevel = 5;
      encs[se->nEncodings++] = Swap32IfLE(appData.qualityLevel +
					  rfbEncodingQualityLevel0);
    }

    if (appData.useRemoteCursor) {
      encs[se->nEncodings++] = Swap32IfLE(rfbEncodingXCursor);
      encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRichCursor);
      encs[se->nEncodings++] = Swap32IfLE(rfbEncodingPointerPos);
    }

    encs[se->nEncodings++] = Swap32IfLE(rfbEncodingLastRect);
  }

  len = sz_rfbSetEncodingsMsg + se->nEncodings * 4;

  se->nEncodings = Swap16IfLE(se->nEncodings);

  if (!WriteExact(rfbsock, buf, len)) return False;

  return True;
}


/*
 * SendIncrementalFramebufferUpdateRequest.
 */

Bool
SendIncrementalFramebufferUpdateRequest()
{
  return SendFramebufferUpdateRequest(0, 0, server_CB.client_grp[clientNum]->serverInitMsg.framebufferWidth, \
				      server_CB.client_grp[clientNum]->serverInitMsg.framebufferHeight, True);
  //return SendFramebufferUpdateRequest(0, 0, si.framebufferWidth,
//				      si.framebufferHeight, True);
}

Bool
SendAllFramebufferUpdateRequest()
{
  return SendFramebufferUpdateRequest(0, 0, server_CB.client_grp[clientNum]->serverInitMsg.framebufferWidth, \
				      server_CB.client_grp[clientNum]->serverInitMsg.framebufferHeight, False);
}

Bool
SendAllFramebufferUpdateRequestSpecified( int sock )
{
  return SendFramebufferUpdateRequestSpecified(0, 0, server_CB.client_grp[clientNum]->serverInitMsg.framebufferWidth, \
				      server_CB.client_grp[clientNum]->serverInitMsg.framebufferHeight, False, sock);
}

/*
 * SendFramebufferUpdateRequest.
 */

Bool
SendFramebufferUpdateRequest(int x, int y, int w, int h, Bool incremental)
{
  return SendFramebufferUpdateRequestSpecified( x, y, w, h, incremental, rfbsock);
}

Bool
SendFramebufferUpdateRequestSpecified(int x, int y, int w, int h, Bool incremental, int sock)
{
  rfbFramebufferUpdateRequestMsg fur;

  fur.type = rfbFramebufferUpdateRequest;
  fur.incremental = incremental ? 1 : 0;
  fur.x = Swap16IfLE(x);
  fur.y = Swap16IfLE(y);
  fur.w = Swap16IfLE(w);
  fur.h = Swap16IfLE(h);

  if (!WriteExact(sock, (char *)&fur, sz_rfbFramebufferUpdateRequestMsg))
    return False;
  return True;
}


/*
 * SendPointerEvent.
 */

Bool
SendPointerEvent(int x, int y, int buttonMask)
{
  return SendPointerEventSpecified( x, y, buttonMask, rfbsock);
}

Bool
SendPointerEventSpecified(int x, int y, int buttonMask, int sock)
{
  rfbPointerEventMsg pe;

  pe.type = rfbPointerEvent;
  pe.buttonMask = buttonMask;
  if (x < 0) x = 0;
  if (y < 0) y = 0;

  if (!appData.useX11Cursor)
    SoftCursorMove(x, y);

  pe.x = Swap16IfLE(x);
  pe.y = Swap16IfLE(y);
  return WriteExact(sock, (char *)&pe, sz_rfbPointerEventMsg);
}


/*
 * SendKeyEvent.
 */

Bool
SendKeyEvent(CARD32 key, Bool down)
{
  return SendKeyEventSpecified( key, down, rfbsock);
}

Bool
SendKeyEventSpecified(CARD32 key, Bool down, int sock)
{
  rfbKeyEventMsg ke;

  ke.type = rfbKeyEvent;
  ke.down = down ? 1 : 0;
  ke.key = Swap32IfLE(key);
  return WriteExact(sock, (char *)&ke, sz_rfbKeyEventMsg);
}


/*
 * SendClientCutText.
 */

Bool
SendClientCutText(char *str, int len)
{
  rfbClientCutTextMsg cct;

  if (serverCutText)
    free(serverCutText);
  serverCutText = NULL;

  cct.type = rfbClientCutText;
  cct.length = Swap32IfLE(len);
  return  (WriteExact(rfbsock, (char *)&cct, sz_rfbClientCutTextMsg) &&
	   WriteExact(rfbsock, str, len));
}



/*
 * HandleRFBServerMessage.
 */

Bool
HandleRFBServerMessage()
{
  rfbServerToClientMsg msg;
  if (!ReadFromRFBServer((char *)&msg, 1))
    return False;

  switch (msg.type) {

  case rfbSetColourMapEntries:
  {
    int i;
    CARD16 rgb[3];
    GdkColor gdkc;

    if (!ReadFromRFBServer(((char *)&msg) + 1,
			   sz_rfbSetColourMapEntriesMsg - 1))
      return False;

    msg.scme.firstColour = Swap16IfLE(msg.scme.firstColour);
    msg.scme.nColours = Swap16IfLE(msg.scme.nColours);

    for (i = 0; i < msg.scme.nColours; i++) {
      if (!ReadFromRFBServer((char *)rgb, 6))
	return False;
      gdkc.pixel = msg.scme.firstColour + i;
      gdkc.red = Swap16IfLE(rgb[0]);
      gdkc.green = Swap16IfLE(rgb[1]);
      gdkc.blue = Swap16IfLE(rgb[2]);
      gdk_color_change(gdkcmap, &gdkc);
    }

    break;
  }

  case rfbFramebufferUpdate:
  {
    rfbFramebufferUpdateRectHeader rect;
    int linesToRead;
    int bytesPerLine;
    int i;

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

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

      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 > si.framebufferWidth) ||
	  (rect.r.y + rect.r.h > si.framebufferHeight))
	{
	  fprintf(stderr,"Rect too large: %dx%d at (%d, %d) > width=%d, height=%d\n",
		  rect.r.w, rect.r.h, rect.r.x, rect.r.y, si.framebufferWidth, si.framebufferHeight);
	  return False;
	}

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

      /* If RichCursor encoding is used, we should prevent collisions
	 between framebuffer updates and cursor drawing operations. */
      SoftCursorLockArea(rect.r.x, rect.r.y, rect.r.w, rect.r.h);

      switch (rect.encoding) {

      case rfbEncodingRaw:
//  printf("---------------------rawdata--\n");
	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 (!ReadFromRFBServer(buffer,bytesPerLine * linesToRead))
	    return False;
	  rfbCastUpdateBuf (buffer, bytesPerLine * linesToRead, 0);
	  CopyDataToScreen(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 (!ReadFromRFBServer((char *)&cr, sz_rfbCopyRect))
	  return False;
// printf("---------------------CopyRectdata--\n");
	rfbCastUpdateBuf ((char *)&cr, sz_rfbCopyRect, 0);

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

	/* If RichCursor encoding is used, we should extend our
	   "cursor lock area" (previously set to destination
	   rectangle) to the source rectangle as well. */
	SoftCursorLockArea(cr.srcX, cr.srcY, rect.r.w, rect.r.h);
	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(gdkpixmap[page][da_num], gdkGC, rect.r.x, rect.r.y,
                       gdkpixmap[page][da_num], cr.srcX, cr.srcY, rect.r.w, rect.r.h);

	break;
      }

      case rfbEncodingRRE:
      {
//printf("---------------------RREdata--\n");
	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:
      {
//printf("-----------------------CoRREdata--\n");
	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:
      {
//printf("-------------------Hextiledata--\n");
	switch (myFormat.bitsPerPixel) {
	case 8:
	  if (!HandleHextile8(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
	    return False;
	  break;
	case 16:
	  if (!HandleHextile16(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
	    return False;
	  break;
	case 32:
	  if (!HandleHextile32(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
	    return False;
	  break;
	}
	break;
      }

      case rfbEncodingZlib:
      {
//printf("---------------------Zlibdata--\n");
	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:
      {
//printf("------------------Tightdata--\n");
	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;
      }

      /* Now we may discard "soft cursor locks". */
      SoftCursorUnlockScreen();
    }

    if (da_num < (draw_info[page].row * draw_info[page].column)) {
      GdkRectangle gdkrect;
      gdkrect.x = 0;
      gdkrect.y = 0;
      gdkrect.width = drawingarea[page][da_num]->allocation.width;
      gdkrect.height = drawingarea[page][da_num]->allocation.height;
      gtk_widget_draw(drawingarea[page][da_num], &gdkrect);
      if (GETVIEW(clientNum)) {
	gdkrect.width = drawingarea_ex->allocation.width;
	gdkrect.height = drawingarea_ex->allocation.height;
	gtk_widget_draw(drawingarea_ex, &gdkrect);
      }
    }

#ifdef MITSHM
    /* if using shared memory PutImage, make sure that the X server has
       updated its framebuffer before we reuse the shared memory.  This is
       mainly to avoid copyrect using invalid screen contents - not sure
       if we'd need it otherwise. */
      XSync(dpy, False);
#endif

    if (!SendIncrementalFramebufferUpdateRequest())
      return False;

    break;
  }

  case rfbBell:
  {
    XBell(dpy, 0);

    break;
  }

  case rfbServerCutText:
  {
    if (!ReadFromRFBServer(((char *)&msg) + 1,
			   sz_rfbServerCutTextMsg - 1))
      return False;

    msg.sct.length = Swap32IfLE(msg.sct.length);

    if (serverCutText)
      free(serverCutText);

    serverCutText = malloc(msg.sct.length+1);

    if (!ReadFromRFBServer(serverCutText, msg.sct.length))
      return False;

    serverCutText[msg.sct.length] = 0;

    newServerCutText = True;

    break;
  }

  default:
    fprintf(stderr,"Unknown message type %d from VNC server\n",msg.type);
    return False;
  }
				      
  //printf("****** push ****\n");
  rfbCastUpdateBuf (NULL, 0, 1);
  return True;
}

/* 画面送信に携わる関数 */
void
SendCast (int cnum)
{
  int sendcnt;
  struct sockaddr_in dest;
  int j;
  fd_set fds;
  int tmplen = 0;

  dest.sin_family = AF_INET;
  dest.sin_addr.s_addr = server_CB.casting_ip[server_CB.client_grp[cnum]->cast_grp];
  dest.sin_port = server_CB.casting_port;

  while ((*shm_asym[cnum]).flag != CAST_STOP) {
    if (getppid() == 1) exit(1);
    if (((*shm_asym[cnum]).flag != CAST_SEND) || ((*shm_asym[cnum]).end - (*shm_asym[cnum]).start == 0) ||
	((*shm_asym[cnum]).rec_s - (*shm_asym[cnum]).rec_e == 0)) {
      (*shm_asym[cnum]).ave_delay = 0;
      usleep(1);
      continue;
    }
    int tmpcp = (*shm_asym[cnum]).rec_size[(*shm_asym[cnum]).rec_s];
   
    while ((tmpcp) && ((*shm_asym[cnum]).flag != CAST_STOP)) {
      //if (tmpcp == 0) continue;
      if (sendcnt > (*shm_asym[cnum]).sendrate) {
        usleep(1);
        sendcnt = 0;
      } else sendcnt++;

      j = sendto ((int)server_CB.cstdsp[server_CB.client_grp[cnum]->cast_grp], \
                  &((*shm_asym[cnum]).castBuf[(*shm_asym[cnum]).start]), tmpcp, 0, \
                  (struct sockaddr *)&dest, sizeof(dest));
      if (j < 0) printf("   errno=%d\n",errno);
      if (j <= 0) {
        usleep (100 * 1000);
        if (errno == EWOULDBLOCK || errno == EAGAIN) continue;
        else {
	  fprintf(stderr, "%s:write\n", programName);
  	  if (errno == 90) return;
	  printf("write_error\n");
	  break;
        }
        continue;
      }
      (*shm_asym[cnum]).start += j;
      if ((*shm_asym[cnum]).start == CAST_BUF_SIZE ) (*shm_asym[cnum]).start = 0;
      tmpcp -= j;
    }
    (*shm_asym[cnum]).rec_size[(*shm_asym[cnum]).rec_s] = 0;
    if ((*shm_asym[cnum]).start >= CAST_BUF_SIZE ) (*shm_asym[cnum]).start = 0;
    if ((*shm_asym[cnum]).rec_s != (*shm_asym[cnum]).rec_e) (*shm_asym[cnum]).rec_s++;
    if ((*shm_asym[cnum]).rec_s >= CALC_SIZE) (*shm_asym[cnum]).rec_s = 0;
  }
  j = sendto ((int)server_CB.cstdsp[server_CB.client_grp[cnum]->cast_grp], NULL, 0, 0, \
                      (struct sockaddr *)&dest, sizeof(dest));
  printf("cast_end j=%d\n",j);
  return;
}

/* 要求がある場合、定期的に全画面要求を行なう */
void
resendCallback (gpointer cnum)
{
  int i;
  int request_flag = 1;
  for (i = 0; i < MAXCLIENT; i++) {
    if (server_CB.client_grp[i] == NULL) continue;
    if ((server_CB.client_grp[(int)cnum]->cast_grp == server_CB.client_grp[i]->recv_grp) \
	&& (GETRESEND (i))) {
      request_flag = 1;
      SETRESEND (i, 0);
    }
  }
  if (request_flag) {
    clientNum = GPOINTER_TO_INT(cnum);
    rfbsock = server_CB.client_grp[clientNum]->vncdsp;
    printf("FramebufferRequest*********************** dsp=%d\n",rfbsock);

    SendAllFramebufferUpdateRequest ();
  }
}

/* 定期的に画面送信レートを更新する */
void
calcRateCallback (gpointer cnum)
{
  (*shm_asym[(int)cnum]).sendrate = calcRate(GPOINTER_TO_INT(cnum));
}

/* 最遅クライアントを求める */
int
calcRate(int cnum)
{
  int i;
  int maxdelay = 0;	/* 送信グループ単位の最遅クライアントRTT */

  if (server_CB.client_grp[cnum] == NULL) return 0;
  for (i = 0; i < MAXCLIENT; i++) {
    /* 送信されるクライアントを確認 */
    if ((server_CB.client_grp[i] == NULL) || 
	(server_CB.client_grp[cnum]->cast_grp != server_CB.client_grp[i]->recv_grp))
      continue;
    /* 現段階の最遅クライアント番号とRTT */
    if (maxdelay < server_CB.client_grp[i]->r_time) {
      maxdelay = server_CB.client_grp[i]->r_time;
    }
    /* 一定基準以下であれば送信停止 */
    //printf("maxdelay=%d\n",maxdelay);
    //if (maxdelay > 4000) (*shm_asym[server_CB.client_grp[i]->cast_grp]).flag = CAST_WAIT;
  }

  return rate_alg(maxdelay, cnum);
}

/* 最遅クライアントに合わせた送信レートの算出 */
int
rate_alg (int maxdelay, int cnum)
{
  maxdelay = (((-1) * 10 * maxdelay)/1000000) + 10;
  
  if ((*shm_asym[cnum]).ave_delay < maxdelay) 
    (*shm_asym[cnum]).ave_delay += ((maxdelay - (*shm_asym[cnum]).ave_delay) / 3);
  else if ((*shm_asym[cnum]).ave_delay > maxdelay) {
    (*shm_asym[cnum]).ave_delay -= (((*shm_asym[cnum]).ave_delay - maxdelay) / 2);
  }
  if ((*shm_asym[cnum]).ave_delay > 10) (*shm_asym[cnum]).ave_delay = 10;
  if ((*shm_asym[cnum]).ave_delay < 1) (*shm_asym[cnum]).ave_delay = 1;
  //printf("avedelay=%d \n",(*shm_asym[cnum]).ave_delay);
  return (*shm_asym[cnum]).ave_delay;
}

void
pk_size_calc (int clientNum, int len, char push)
{
  /* ヘッダであればパケットの先頭にする */
  if (push == 1) {
    if ((*shm_asym[clientNum]).rec_size[(*shm_asym[clientNum]).rec_e]) (*shm_asym[clientNum]).rec_e++;
    if ((*shm_asym[clientNum]).rec_e >= CALC_SIZE) (*shm_asym[clientNum]).rec_e = 0;
    (*shm_asym[clientNum]).rec_size[(*shm_asym[clientNum]).rec_e] += len;
  } else {
    /* ヘッダでなければできるだけ詰める */
    while (len) {
      if (CAST_PK_SIZE >= (*shm_asym[clientNum]).rec_size[(*shm_asym[clientNum]).rec_e] + len) {
        (*shm_asym[clientNum]).rec_size[(*shm_asym[clientNum]).rec_e] += len;
        break;
      } else {
        len = ((*shm_asym[clientNum]).rec_size[(*shm_asym[clientNum]).rec_e] + len) - CAST_PK_SIZE;
        (*shm_asym[clientNum]).rec_size[(*shm_asym[clientNum]).rec_e] = CAST_PK_SIZE;
        (*shm_asym[clientNum]).rec_e++;
        if ((*shm_asym[clientNum]).rec_e >= CALC_SIZE) (*shm_asym[clientNum]).rec_e = 0;
      }
    }
  }
}

/* 共有バッファに描画情報を蓄える */
int
rfbCastUpdateBuf(char *buf, int len, char push)
{
  if (GETSEND (clientNum)) {
    //if (push == 1) (*shm_asym).flag = 1;
    (*shm_asym[clientNum]).flag = CAST_SEND;
    if (len) {
      if ((*shm_asym[clientNum]).end - (*shm_asym[clientNum]).start >= 0) {
	if (((*shm_asym[clientNum]).end + len) <= CAST_BUF_SIZE) {
	  memcpy(&((*shm_asym[clientNum]).castBuf[(*shm_asym[clientNum]).end]), (char *)buf, len);
	  pk_size_calc (clientNum, len, push);
	  (*shm_asym[clientNum]).end += len;
	  return 0;
	} else {
	  if ((*shm_asym[clientNum]).start > len) {
	    memcpy(&((*shm_asym[clientNum]).castBuf[(*shm_asym[clientNum]).end]), \
                   (char *)buf, CAST_BUF_SIZE - (*shm_asym[clientNum]).end);
            pk_size_calc (clientNum, CAST_BUF_SIZE - (*shm_asym[clientNum]).end, push);
            memcpy(&((*shm_asym[clientNum]).castBuf[0]), \
                   (char *)&buf[CAST_BUF_SIZE - (*shm_asym[clientNum]).end], \
                   len - (CAST_BUF_SIZE - (*shm_asym[clientNum]).end));
            pk_size_calc (clientNum, len - (CAST_BUF_SIZE - (*shm_asym[clientNum]).end), 1);
	    (*shm_asym[clientNum]).end = len - (CAST_BUF_SIZE - (*shm_asym[clientNum]).end);
	    return 0;
	  } else {
	    wait_buf(clientNum, len);
            rfbCastUpdateBuf(buf, len, push);
	    return 0;
	  }
	}
      } else if ((*shm_asym[clientNum]).end < (*shm_asym[clientNum]).start) {
	if (((*shm_asym[clientNum]).end + len) < (*shm_asym[clientNum]).start) {
	  memcpy(&((*shm_asym[clientNum]).castBuf[(*shm_asym[clientNum]).end]), (char *)buf, len);
	  pk_size_calc (clientNum, len, push);
	  (*shm_asym[clientNum]).end += len;
	  return 0;
	} else {
	  wait_buf(clientNum, len);
          rfbCastUpdateBuf(buf, len, push);
	  return 0;
	}
      }
      
    } else pk_size_calc (clientNum, len, push);
  }
  return 0;
}

/* 共有バッファが空くまで待つ */
void
wait_buf (int cnum, int len)
{
  (*shm_asym[cnum]).flag = CAST_SEND;
  while (1) {
    if (((*shm_asym[cnum]).end - (*shm_asym[cnum]).start >= 0) && 
        ((((*shm_asym[cnum]).end + len) <= CAST_BUF_SIZE) || ((*shm_asym[cnum]).start > len))) break;
    else if (((*shm_asym[cnum]).end < (*shm_asym[cnum]).start) \
	&& (((*shm_asym[cnum]).end + len) < (*shm_asym[cnum]).start)) break;
    sleep (1);
    printf("************************************************wait_buf\n");
  }
  printf("buf_released\n");
}		      

#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)++)

/* CONCAT2 concatenates its two arguments.  CONCAT2E does the same but also
   expands its arguments if they are macros */

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

#define BPP 8
#include "rre.c"
#include "corre.c"
#include "hextile.c"
#include "zlib.c"
#include "tight.c"
#undef BPP
#define BPP 16
#include "rre.c"
#include "corre.c"
#include "hextile.c"
#include "zlib.c"
#include "tight.c"
#undef BPP
#define BPP 32
#include "rre.c"
#include "corre.c"
#include "hextile.c"
#include "zlib.c"
#include "tight.c"
#undef BPP


/*
 * PrintPixelFormat.
 */

void
PrintPixelFormat(format)
    rfbPixelFormat *format;
{
  if (format->bitsPerPixel == 1) {
    fprintf(stderr,"  Single bit per pixel.\n");
    fprintf(stderr,
	    "  %s significant bit in each byte is leftmost on the screen.\n",
	    (format->bigEndian ? "Most" : "Least"));
  } else {
    fprintf(stderr,"  %d bits per pixel.\n",format->bitsPerPixel);
    if (format->bitsPerPixel != 8) {
      fprintf(stderr,"  %s significant byte first in each pixel.\n",
	      (format->bigEndian ? "Most" : "Least"));
    }
    if (format->trueColour) {
      fprintf(stderr,"  True colour: max red %d green %d blue %d",
	      format->redMax, format->greenMax, format->blueMax);
      fprintf(stderr,", shift red %d green %d blue %d\n",
	      format->redShift, format->greenShift, format->blueShift);
    } else {
      fprintf(stderr,"  Colour map (not true colour).\n");
    }
  }
}

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

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

/*
 * JPEG source manager functions for JPEG decompression in Tight decoder.
 */

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 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;
}

