<yoshiki@xemacs.org>
#include <unistd.h>
#include <errno.h>
#include <pwd.h>
#include <vncviewer.h>
#include <vncauth.h>
#include <zlib.h>
#include <jpeglib.h>
static void InitCapabilities(void);
static Bool SetupTunneling(void);
static int ReadSecurityType(void);
static int SelectSecurityType(void);
static Bool PerformAuthenticationTight(void);
static Bool AuthenticateVNC(void);
static Bool AuthenticateNone(void);
static Bool ReadAuthenticationResult(void);
static Bool ReadInteractionCaps(void);
static Bool ReadCapabilityList(CapsContainer *caps, int count);
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 void ReadConnFailedReason(void);
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);
int rfbsock;
char *desktopName;
rfbPixelFormat myFormat;
rfbServerInitMsg si;
char *serverCutText = NULL;
Bool newServerCutText = False;
int endianTest = 1;
static int protocolMinorVersion;
static Bool tightVncProtocol = False;
static CapsContainer *tunnelCaps;
static CapsContainer *authCaps;
static CapsContainer *serverMsgCaps;
static CapsContainer *clientMsgCaps;
static CapsContainer *encodingCaps;
#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;
#define ZLIB_BUFFER_SIZE 512
static char zlib_buffer[ZLIB_BUFFER_SIZE];
static z_stream zlibStream[4];
static Bool zlibStreamActive[4] = {
False, False, False, False
};
static Bool cutZeros;
static int rectWidth, rectColors;
static char tightPalette[256*4];
static CARD8 tightPrevRow[2048*3*sizeof(CARD16)];
static Bool jpegError;
static void
InitCapabilities(void)
{
tunnelCaps = CapsNewContainer();
authCaps = CapsNewContainer();
serverMsgCaps = CapsNewContainer();
clientMsgCaps = CapsNewContainer();
encodingCaps = CapsNewContainer();
CapsAdd(authCaps, rfbAuthNone, rfbStandardVendor, sig_rfbAuthNone,
"No authentication");
CapsAdd(authCaps, rfbAuthVNC, rfbStandardVendor, sig_rfbAuthVNC,
"Standard VNC password authentication");
CapsAdd(encodingCaps, rfbEncodingCopyRect, rfbStandardVendor,
sig_rfbEncodingCopyRect, "Standard CopyRect encoding");
CapsAdd(encodingCaps, rfbEncodingRRE, rfbStandardVendor,
sig_rfbEncodingRRE, "Standard RRE encoding");
CapsAdd(encodingCaps, rfbEncodingCoRRE, rfbStandardVendor,
sig_rfbEncodingCoRRE, "Standard CoRRE encoding");
CapsAdd(encodingCaps, rfbEncodingHextile, rfbStandardVendor,
sig_rfbEncodingHextile, "Standard Hextile encoding");
CapsAdd(encodingCaps, rfbEncodingZlib, rfbTridiaVncVendor,
sig_rfbEncodingZlib, "Zlib encoding from TridiaVNC");
CapsAdd(encodingCaps, rfbEncodingTight, rfbTightVncVendor,
sig_rfbEncodingTight, "Tight encoding by Constantin Kaplinsky");
CapsAdd(encodingCaps, rfbEncodingCompressLevel0, rfbTightVncVendor,
sig_rfbEncodingCompressLevel0, "Compression level");
CapsAdd(encodingCaps, rfbEncodingQualityLevel0, rfbTightVncVendor,
sig_rfbEncodingQualityLevel0, "JPEG quality level");
CapsAdd(encodingCaps, rfbEncodingXCursor, rfbTightVncVendor,
sig_rfbEncodingXCursor, "X-style cursor shape update");
CapsAdd(encodingCaps, rfbEncodingRichCursor, rfbTightVncVendor,
sig_rfbEncodingRichCursor, "Rich-color cursor shape update");
CapsAdd(encodingCaps, rfbEncodingPointerPos, rfbTightVncVendor,
sig_rfbEncodingPointerPos, "Pointer position update");
CapsAdd(encodingCaps, rfbEncodingLastRect, rfbTightVncVendor,
sig_rfbEncodingLastRect, "LastRect protocol extension");
}
Bool
ConnectToRFBServer(const char *hostname, int port)
{
unsigned int host;
if (appData.play || appData.movie)
return True;
if (!StringToIPAddr(hostname, &host)) {
fprintf(stderr,"Couldn't convert '%s' to host address\n", hostname);
return False;
}
rfbsock = ConnectToTcpAddr(host, port);
if (rfbsock < 0) {
fprintf(stderr,"Unable to connect to VNC server\n");
return False;
}
return SetNonBlocking(rfbsock);
}
Bool
InitialiseRFBConnection(void)
{
rfbProtocolVersionMsg pv;
int server_major, server_minor;
rfbClientInitMsg ci;
int secType;
if (listenSpecified)
errorMessageOnReadFailure = False;
if (!ReadFromRFBServer(pv, sz_rfbProtocolVersionMsg))
return False;
errorMessageOnReadFailure = True;
pv[sz_rfbProtocolVersionMsg] = 0;
if (sscanf(pv, rfbProtocolVersionFormat,
&server_major, &server_minor) != 2) {
fprintf(stderr,"Not a valid VNC server\n");
return False;
}
if (server_major == 3 && server_minor >= 8) {
protocolMinorVersion = 8;
} else if (server_major == 3 && server_minor == 7) {
protocolMinorVersion = 7;
} else {
protocolMinorVersion = 3;
}
if (!appData.ffInfo) {
fprintf(stderr, "Connected to RFB server, using protocol version 3.%d\n",
protocolMinorVersion);
}
sprintf(pv, rfbProtocolVersionFormat, 3, protocolMinorVersion);
if (!WriteExact(rfbsock, pv, sz_rfbProtocolVersionMsg))
return False;
if (protocolMinorVersion >= 7) {
secType = SelectSecurityType();
} else {
secType = ReadSecurityType();
}
if (secType == rfbSecTypeInvalid)
return False;
switch (secType) {
case rfbSecTypeNone:
if (!AuthenticateNone())
return False;
break;
case rfbSecTypeVncAuth:
if (!AuthenticateVNC())
return False;
break;
case rfbSecTypeTight:
tightVncProtocol = True;
InitCapabilities();
if (!SetupTunneling())
return False;
if (!PerformAuthenticationTight())
return False;
break;
default:
fprintf(stderr, "Internal error: Invalid security type\n");
return False;
}
ci.shared = (appData.shareDesktop ? 1 : 0);
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);
FIXME:
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;
if (!appData.ffInfo) {
fprintf(stderr,"Desktop name \"%s\"\n",desktopName);
}
if (!appData.ffInfo) {
fprintf(stderr,"VNC server default format:\n");
PrintPixelFormat(&si.format);
}
if (tightVncProtocol) {
if (!ReadInteractionCaps())
return False;
}
return True;
}
static int
ReadSecurityType(void)
{
CARD32 secType;
if (!ReadFromRFBServer((char *)&secType, sizeof(secType)))
return rfbSecTypeInvalid;
secType = Swap32IfLE(secType);
if (secType == rfbSecTypeInvalid) {
ReadConnFailedReason();
return rfbSecTypeInvalid;
}
if (secType != rfbSecTypeNone && secType != rfbSecTypeVncAuth) {
fprintf(stderr, "Unknown security type from RFB server: %d\n",
(int)secType);
return rfbSecTypeInvalid;
}
return (int)secType;
}
static int
SelectSecurityType(void)
{
CARD8 nSecTypes;
char *secTypeNames[] = {"None", "VncAuth"};
CARD8 knownSecTypes[] = {rfbSecTypeNone, rfbSecTypeVncAuth};
int nKnownSecTypes = sizeof(knownSecTypes);
CARD8 *secTypes;
CARD8 secType = rfbSecTypeInvalid;
int i, j;
if (!ReadFromRFBServer((char *)&nSecTypes, sizeof(nSecTypes)))
return rfbSecTypeInvalid;
if (nSecTypes == 0) {
ReadConnFailedReason();
return rfbSecTypeInvalid;
}
secTypes = malloc(nSecTypes);
if (!ReadFromRFBServer((char *)secTypes, nSecTypes))
return rfbSecTypeInvalid;
for (j = 0; j < (int)nSecTypes; j++) {
if (secTypes[j] == rfbSecTypeTight) {
free(secTypes);
secType = rfbSecTypeTight;
if (!WriteExact(rfbsock, (char *)&secType, sizeof(secType)))
return rfbSecTypeInvalid;
fprintf(stderr, "Enabling TightVNC protocol extensions\n");
return rfbSecTypeTight;
}
}
for (j = 0; j < (int)nSecTypes; j++) {
for (i = 0; i < nKnownSecTypes; i++) {
if (secTypes[j] == knownSecTypes[i]) {
secType = secTypes[j];
if (!WriteExact(rfbsock, (char *)&secType, sizeof(secType))) {
free(secTypes);
return rfbSecTypeInvalid;
}
break;
}
}
if (secType != rfbSecTypeInvalid) break;
}
free(secTypes);
if (secType == rfbSecTypeInvalid)
fprintf(stderr, "Server did not offer supported security type\n");
return (int)secType;
}
static Bool
SetupTunneling(void)
{
rfbTunnelingCapsMsg caps;
CARD32 tunnelType;
if (!ReadFromRFBServer((char *)&caps, sz_rfbTunnelingCapsMsg))
return False;
caps.nTunnelTypes = Swap32IfLE(caps.nTunnelTypes);
if (caps.nTunnelTypes) {
if (!ReadCapabilityList(tunnelCaps, caps.nTunnelTypes))
return False;
tunnelType = Swap32IfLE(rfbNoTunneling);
if (!WriteExact(rfbsock, (char *)&tunnelType, sizeof(tunnelType)))
return False;
}
return True;
}
static Bool
PerformAuthenticationTight(void)
{
rfbAuthenticationCapsMsg caps;
CARD32 authScheme;
int i;
if (!ReadFromRFBServer((char *)&caps, sz_rfbAuthenticationCapsMsg))
return False;
caps.nAuthTypes = Swap32IfLE(caps.nAuthTypes);
if (!caps.nAuthTypes)
return AuthenticateNone();
if (!ReadCapabilityList(authCaps, caps.nAuthTypes))
return False;
for (i = 0; i < CapsNumEnabled(authCaps); i++) {
authScheme = CapsGetByOrder(authCaps, i);
if (authScheme != rfbAuthVNC && authScheme != rfbAuthNone)
continue;
authScheme = Swap32IfLE(authScheme);
if (!WriteExact(rfbsock, (char *)&authScheme, sizeof(authScheme)))
return False;
authScheme = Swap32IfLE(authScheme);
switch (authScheme) {
case rfbAuthNone:
return AuthenticateNone();
case rfbAuthVNC:
return AuthenticateVNC();
default:
fprintf(stderr, "Internal error: Invalid authentication type\n");
return False;
}
}
fprintf(stderr, "No suitable authentication schemes offered by server\n");
return False;
}
static Bool
AuthenticateNone(void)
{
fprintf(stderr, "No authentication needed\n");
if (protocolMinorVersion >= 8) {
if (!ReadAuthenticationResult())
return False;
}
return True;
}
static Bool
AuthenticateVNC(void)
{
CARD32 authScheme;
CARD8 challenge[CHALLENGESIZE];
char *passwd;
char buffer[64];
char* cstatus;
int len;
if (!appData.ffInfo) {
fprintf(stderr, "Performing standard VNC authentication\n");
}
if (!ReadFromRFBServer((char *)challenge, CHALLENGESIZE))
return False;
if (appData.play || appData.movie) {
passwd = strdup ("dummy");
return ReadAuthenticationResult();
}
if (appData.passwordFile) {
passwd = vncDecryptPasswdFromFile(appData.passwordFile);
if (!passwd) {
fprintf(stderr, "Cannot read valid password from file \"%s\"\n",
appData.passwordFile);
return False;
}
} else if (appData.autoPass) {
passwd = buffer;
cstatus = fgets(buffer, sizeof buffer, stdin);
if (cstatus == NULL)
buffer[0] = '\0';
else
{
len = strlen(buffer);
if (len > 0 && buffer[len - 1] == '\n')
buffer[len - 1] = '\0';
}
} else if (appData.passwordDialog) {
passwd = DoPasswordDialog();
} else {
passwd = getpass("Password: ");
}
if (!passwd || strlen(passwd) == 0) {
fprintf(stderr, "Reading password failed\n");
return False;
}
if (strlen(passwd) > 8) {
passwd[8] = '\0';
}
vncEncryptBytes(challenge, passwd);
memset(passwd, '\0', strlen(passwd));
if (!WriteExact(rfbsock, (char *)challenge, CHALLENGESIZE))
return False;
return ReadAuthenticationResult();
}
static Bool
ReadAuthenticationResult(void)
{
CARD32 authResult;
if (!ReadFromRFBServer((char *)&authResult, 4))
return False;
authResult = Swap32IfLE(authResult);
switch (authResult) {
case rfbAuthOK:
if (!appData.ffInfo) {
fprintf(stderr, "Authentication successful\n");
}
break;
case rfbAuthFailed:
if (protocolMinorVersion >= 8) {
ReadConnFailedReason();
} else {
fprintf(stderr, "Authentication failure\n");
}
return False;
case rfbAuthTooMany:
fprintf(stderr, "Authentication failure, too many tries\n");
return False;
default:
fprintf(stderr, "Unknown result of authentication (%d)\n",
(int)authResult);
return False;
}
return True;
}
static Bool
ReadInteractionCaps(void)
{
rfbInteractionCapsMsg intr_caps;
if (!ReadFromRFBServer((char *)&intr_caps, sz_rfbInteractionCapsMsg))
return False;
intr_caps.nServerMessageTypes = Swap16IfLE(intr_caps.nServerMessageTypes);
intr_caps.nClientMessageTypes = Swap16IfLE(intr_caps.nClientMessageTypes);
intr_caps.nEncodingTypes = Swap16IfLE(intr_caps.nEncodingTypes);
return (ReadCapabilityList(serverMsgCaps, intr_caps.nServerMessageTypes) &&
ReadCapabilityList(clientMsgCaps, intr_caps.nClientMessageTypes) &&
ReadCapabilityList(encodingCaps, intr_caps.nEncodingTypes));
}
static Bool
ReadCapabilityList(CapsContainer *caps, int count)
{
rfbCapabilityInfo msginfo;
int i;
for (i = 0; i < count; i++) {
if (!ReadFromRFBServer((char *)&msginfo, sz_rfbCapabilityInfo))
return False;
msginfo.code = Swap32IfLE(msginfo.code);
CapsEnable(caps, &msginfo);
}
return True;
}
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 (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");
}
}
encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCopyRect);
encs[se->nEncodings++] = Swap32IfLE(rfbEncodingHextile);
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) {
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;
}
Bool
SendIncrementalFramebufferUpdateRequest()
{
return SendFramebufferUpdateRequest(0, 0, si.framebufferWidth,
si.framebufferHeight, True);
}
Bool
SendFramebufferUpdateRequest(int x, int y, int w, int h, Bool incremental)
{
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(rfbsock, (char *)&fur, sz_rfbFramebufferUpdateRequestMsg))
return False;
return True;
}
Bool
SendPointerEvent(int x, int y, int buttonMask)
{
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(rfbsock, (char *)&pe, sz_rfbPointerEventMsg);
}
Bool
SendKeyEvent(CARD32 key, Bool down)
{
rfbKeyEventMsg ke;
ke.type = rfbKeyEvent;
ke.down = down ? 1 : 0;
ke.key = Swap32IfLE(key);
return WriteExact(rfbsock, (char *)&ke, sz_rfbKeyEventMsg);
}
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));
}
Bool
HandleRFBServerMessage()
{
rfbServerToClientMsg msg;
vncLogTimeStamp = True;
if (!ReadFromRFBServer((char *)&msg, 1))
return False;
vncLogTimeStamp = False;
switch (msg.type) {
case rfbSetColourMapEntries:
{
int i;
CARD16 rgb[3];
XColor xc;
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;
xc.pixel = msg.scme.firstColour + i;
xc.red = Swap16IfLE(rgb[0]);
xc.green = Swap16IfLE(rgb[1]);
xc.blue = Swap16IfLE(rgb[2]);
xc.flags = DoRed|DoGreen|DoBlue;
XStoreColor(dpy, cmap, &xc);
}
break;
}
case rfbFramebufferUpdate:
{
rfbFramebufferUpdateRectHeader rect;
int linesToRead;
int bytesPerLine;
int i;
int usecs;
if (!ReadFromRFBServer(((char *)&msg.fu) + 1,
sz_rfbFramebufferUpdateMsg - 1))
return False;
msg.fu.nRects = Swap16IfLE(msg.fu.nRects);
for (i = 0; i < msg.fu.nRects; i++) {
vncLogTimeStamp = True;
if (!ReadFromRFBServer((char *)&rect, sz_rfbFramebufferUpdateRectHeader))
return False;
vncLogTimeStamp = 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 > si.framebufferWidth) ||
(rect.r.y + rect.r.h > si.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;
}
SoftCursorLockArea(rect.r.x, rect.r.y, rect.r.w, rect.r.h);
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 (!ReadFromRFBServer(buffer,bytesPerLine * linesToRead))
return False;
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;
cr.srcX = Swap16IfLE(cr.srcX);
cr.srcY = Swap16IfLE(cr.srcY);
SoftCursorLockArea(cr.srcX, cr.srcY, rect.r.w, rect.r.h);
if (appData.copyRectDelay != 0) {
XFillRectangle(dpy, desktopWin, srcGC, cr.srcX, cr.srcY,
rect.r.w, rect.r.h);
XFillRectangle(dpy, desktopWin, dstGC, rect.r.x, rect.r.y,
rect.r.w, rect.r.h);
XSync(dpy,False);
usleep(appData.copyRectDelay * 1000);
XFillRectangle(dpy, desktopWin, dstGC, rect.r.x, rect.r.y,
rect.r.w, rect.r.h);
XFillRectangle(dpy, desktopWin, srcGC, cr.srcX, cr.srcY,
rect.r.w, rect.r.h);
}
XCopyArea(dpy, desktopWin, desktopWin, gc, cr.srcX, cr.srcY,
rect.r.w, rect.r.h, rect.r.x, rect.r.y);
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 (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:
{
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;
}
SoftCursorUnlockScreen();
}
#ifdef MITSHM
if (appData.useShm)
XSync(dpy, False);
#endif
if (!SendIncrementalFramebufferUpdateRequest())
return False;
break;
}
case rfbBell:
{
Window toplevelWin;
XBell(dpy, 0);
if (appData.raiseOnBeep) {
toplevelWin = XtWindow(toplevel);
XMapRaised(dpy, toplevelWin);
}
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;
}
return True;
}
#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 "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
static void
ReadConnFailedReason(void)
{
CARD32 reasonLen;
char *reason = NULL;
if (ReadFromRFBServer((char *)&reasonLen, sizeof(reasonLen))) {
reasonLen = Swap32IfLE(reasonLen);
if ((reason = malloc(reasonLen)) != NULL &&
ReadFromRFBServer(reason, reasonLen)) {
fprintf(stderr,"%.*s\n", (int)reasonLen, reason);
free(reason);
return;
}
}
fprintf(stderr, "VNC connection failed\n");
if (reason != NULL)
free(reason);
}
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;
len = (int)b & 0x7F;
if (b & 0x80) {
if (!ReadFromRFBServer((char *)&b, 1))
return -1;
len |= ((int)b & 0x7F) << 7;
if (b & 0x80) {
if (!ReadFromRFBServer((char *)&b, 1))
return -1;
len |= ((int)b & 0xFF) << 14;
}
}
return len;
}
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)
{
}
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;
}