From febced55362321b1015fe23ca7d7b831c28acfcc Mon Sep 17 00:00:00 2001 From: dscho Date: Fri, 21 Sep 2001 23:33:47 +0000 Subject: [PATCH] http added, prepare for cursor --- Makefile | 4 +- classes/index.vnc | 16 ++ classes/vncviewer.jar | Bin 0 -> 31235 bytes cursor.c | 350 ++++++++++++++++++++++++++++++++++++++ example.c | 1 + httpd.c | 383 ++++++++++++++++++++++++++++++++++++++++++ main.c | 8 +- rfb.h | 5 + 8 files changed, 764 insertions(+), 3 deletions(-) create mode 100644 classes/index.vnc create mode 100644 classes/vncviewer.jar create mode 100644 cursor.c create mode 100644 httpd.c diff --git a/Makefile b/Makefile index 91e6a6c..0154b72 100644 --- a/Makefile +++ b/Makefile @@ -20,10 +20,10 @@ OSX_LIBS = -framework ApplicationServices -framework Carbon SOURCES=main.c rfbserver.c miregion.c auth.c sockets.c xalloc.c \ stats.c corre.c hextile.c rre.c translate.c cutpaste.c \ - zlib.c tight.c + zlib.c tight.c httpd.c OBJS=main.o rfbserver.o miregion.o auth.o sockets.o xalloc.o \ stats.o corre.o hextile.o rre.o translate.o cutpaste.o \ - zlib.o tight.o + zlib.o tight.o httpd.o all: example pnmshow storepasswd diff --git a/classes/index.vnc b/classes/index.vnc new file mode 100644 index 0000000..5b78cf6 --- /dev/null +++ b/classes/index.vnc @@ -0,0 +1,16 @@ + + + + +$USER's $DESKTOP desktop ($DISPLAY) + + + + +www.TightVNC.com + diff --git a/classes/vncviewer.jar b/classes/vncviewer.jar new file mode 100644 index 0000000000000000000000000000000000000000..6ae627d32dc867ebfda96384ca812885084e4595 GIT binary patch literal 31235 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 +#include "rfb.h" +#include "mipointer.h" +#include "sprite.h" +#include "cursorstr.h" +#include "servermd.h" + + +/* Copied from Xvnc/lib/font/util/utilbitmap.c */ +static unsigned char _reverse_byte[0x100] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff +}; + + +static int EncodeRichCursorData8 (char *buf, rfbPixelFormat *fmt, + CursorPtr pCursor); +static int EncodeRichCursorData16 (char *buf, rfbPixelFormat *fmt, + CursorPtr pCursor); +static int EncodeRichCursorData32 (char *buf, rfbPixelFormat *fmt, + CursorPtr pCursor); + + +/* + * Send cursor shape either in X-style format or in client pixel format. + */ + +Bool +rfbSendCursorShape(cl, pScreen) + rfbClientPtr cl; + ScreenPtr pScreen; +{ + CursorPtr pCursor; + rfbFramebufferUpdateRectHeader rect; + rfbXCursorColors colors; + int saved_ublen; + int bitmapRowBytes, paddedRowBytes, maskBytes, dataBytes; + int i, j; + CARD8 *bitmapData; + CARD8 bitmapByte; + + if (cl->useRichCursorEncoding) { + rect.encoding = Swap32IfLE(rfbEncodingRichCursor); + } else { + rect.encoding = Swap32IfLE(rfbEncodingXCursor); + } + + pCursor = rfbSpriteGetCursorPtr(pScreen); + + /* If there is no cursor, send update with empty cursor data. */ + + if ( pCursor->bits->width == 1 && + pCursor->bits->height == 1 && + pCursor->bits->mask[0] == 0 ) { + pCursor = NULL; + } + + if (pCursor == NULL) { + if (ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE ) { + if (!rfbSendUpdateBuf(cl)) + return FALSE; + } + rect.r.x = rect.r.y = 0; + rect.r.w = rect.r.h = 0; + memcpy(&updateBuf[ublen], (char *)&rect, + sz_rfbFramebufferUpdateRectHeader); + ublen += sz_rfbFramebufferUpdateRectHeader; + + cl->rfbCursorBytesSent += sz_rfbFramebufferUpdateRectHeader; + cl->rfbCursorUpdatesSent++; + + if (!rfbSendUpdateBuf(cl)) + return FALSE; + + return TRUE; + } + + /* Calculate data sizes. */ + + bitmapRowBytes = (pCursor->bits->width + 7) / 8; + paddedRowBytes = PixmapBytePad(pCursor->bits->width, 1); + maskBytes = bitmapRowBytes * pCursor->bits->height; + dataBytes = (cl->useRichCursorEncoding) ? + (pCursor->bits->width * pCursor->bits->height * + (cl->format.bitsPerPixel / 8)) : maskBytes; + + /* Send buffer contents if needed. */ + + if ( ublen + sz_rfbFramebufferUpdateRectHeader + + sz_rfbXCursorColors + maskBytes + dataBytes > UPDATE_BUF_SIZE ) { + if (!rfbSendUpdateBuf(cl)) + return FALSE; + } + + if ( ublen + sz_rfbFramebufferUpdateRectHeader + + sz_rfbXCursorColors + maskBytes + dataBytes > UPDATE_BUF_SIZE ) { + return FALSE; /* FIXME. */ + } + + saved_ublen = ublen; + + /* Prepare rectangle header. */ + + rect.r.x = Swap16IfLE(pCursor->bits->xhot); + rect.r.y = Swap16IfLE(pCursor->bits->yhot); + rect.r.w = Swap16IfLE(pCursor->bits->width); + rect.r.h = Swap16IfLE(pCursor->bits->height); + + memcpy(&updateBuf[ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader); + ublen += sz_rfbFramebufferUpdateRectHeader; + + /* Prepare actual cursor data (depends on encoding used). */ + + if (!cl->useRichCursorEncoding) { + /* XCursor encoding. */ + colors.foreRed = (char)(pCursor->foreRed >> 8); + colors.foreGreen = (char)(pCursor->foreGreen >> 8); + colors.foreBlue = (char)(pCursor->foreBlue >> 8); + colors.backRed = (char)(pCursor->backRed >> 8); + colors.backGreen = (char)(pCursor->backGreen >> 8); + colors.backBlue = (char)(pCursor->backBlue >> 8); + + memcpy(&updateBuf[ublen], (char *)&colors, sz_rfbXCursorColors); + ublen += sz_rfbXCursorColors; + + bitmapData = (CARD8 *)pCursor->bits->source; + + for (i = 0; i < pCursor->bits->height; i++) { + for (j = 0; j < bitmapRowBytes; j++) { + bitmapByte = bitmapData[i * paddedRowBytes + j]; + if (screenInfo.bitmapBitOrder == LSBFirst) { + bitmapByte = _reverse_byte[bitmapByte]; + } + updateBuf[ublen++] = (char)bitmapByte; + } + } + } else { + /* RichCursor encoding. */ + switch (cl->format.bitsPerPixel) { + case 8: + ublen += EncodeRichCursorData8(&updateBuf[ublen], + &cl->format, pCursor); + break; + case 16: + ublen += EncodeRichCursorData16(&updateBuf[ublen], + &cl->format, pCursor); + break; + case 32: + ublen += EncodeRichCursorData32(&updateBuf[ublen], + &cl->format, pCursor); + break; + default: + return FALSE; + } + } + + /* Prepare transparency mask. */ + + bitmapData = (CARD8 *)pCursor->bits->mask; + + for (i = 0; i < pCursor->bits->height; i++) { + for (j = 0; j < bitmapRowBytes; j++) { + bitmapByte = bitmapData[i * paddedRowBytes + j]; + if (screenInfo.bitmapBitOrder == LSBFirst) { + bitmapByte = _reverse_byte[bitmapByte]; + } + updateBuf[ublen++] = (char)bitmapByte; + } + } + + /* Send everything we have prepared in the updateBuf[]. */ + + cl->rfbCursorBytesSent += (ublen - saved_ublen); + cl->rfbCursorUpdatesSent++; + + if (!rfbSendUpdateBuf(cl)) + return FALSE; + + return TRUE; +} + + +/* + * Code to convert cursor source bitmap to the desired pixel format. + */ + +#define RGB48_TO_PIXEL(fmt,r,g,b) \ + (((CARD32)(r) * ((fmt)->redMax + 1) >> 16) << (fmt)->redShift | \ + ((CARD32)(g) * ((fmt)->greenMax + 1) >> 16) << (fmt)->greenShift | \ + ((CARD32)(b) * ((fmt)->blueMax + 1) >> 16) << (fmt)->blueShift) + +static int +EncodeRichCursorData8(buf, fmt, pCursor) + char *buf; + rfbPixelFormat *fmt; + CursorPtr pCursor; +{ + int widthPixels, widthBytes; + int x, y, b; + CARD8 *src; + char pix[2]; + CARD8 bitmapByte; + + pix[0] = (char)RGB48_TO_PIXEL(fmt, pCursor->backRed, pCursor->backGreen, + pCursor->backBlue); + pix[1] = (char)RGB48_TO_PIXEL(fmt, pCursor->foreRed, pCursor->foreGreen, + pCursor->foreBlue); + + src = (CARD8 *)pCursor->bits->source; + widthPixels = pCursor->bits->width; + widthBytes = PixmapBytePad(widthPixels, 1); + + for (y = 0; y < pCursor->bits->height; y++) { + for (x = 0; x < widthPixels / 8; x++) { + bitmapByte = src[y * widthBytes + x]; + if (screenInfo.bitmapBitOrder == LSBFirst) { + bitmapByte = _reverse_byte[bitmapByte]; + } + for (b = 7; b >= 0; b--) { + *buf++ = pix[bitmapByte >> b & 1]; + } + } + if (widthPixels % 8) { + bitmapByte = src[y * widthBytes + x]; + if (screenInfo.bitmapBitOrder == LSBFirst) { + bitmapByte = _reverse_byte[bitmapByte]; + } + for (b = 7; b > 7 - widthPixels % 8; b--) { + *buf++ = pix[bitmapByte >> b & 1]; + } + } + } + + return (widthPixels * pCursor->bits->height); +} + +#define DEFINE_RICH_ENCODE(bpp) \ + \ +static int \ +EncodeRichCursorData##bpp(buf, fmt, pCursor) \ + char *buf; \ + rfbPixelFormat *fmt; \ + CursorPtr pCursor; \ +{ \ + int widthPixels, widthBytes; \ + int x, y, b; \ + CARD8 *src; \ + CARD##bpp pix[2]; \ + CARD8 bitmapByte; \ + \ + pix[0] = (CARD##bpp)RGB48_TO_PIXEL(fmt, pCursor->backRed, \ + pCursor->backGreen, \ + pCursor->backBlue); \ + pix[1] = (CARD##bpp)RGB48_TO_PIXEL(fmt, pCursor->foreRed, \ + pCursor->foreGreen, \ + pCursor->foreBlue); \ + if (!rfbServerFormat.bigEndian != !fmt->bigEndian) { \ + pix[0] = Swap##bpp(pix[0]); \ + pix[1] = Swap##bpp(pix[1]); \ + } \ + \ + src = (CARD8 *)pCursor->bits->source; \ + widthPixels = pCursor->bits->width; \ + widthBytes = PixmapBytePad(widthPixels, 1); \ + \ + for (y = 0; y < pCursor->bits->height; y++) { \ + for (x = 0; x < widthPixels / 8; x++) { \ + bitmapByte = src[y * widthBytes + x]; \ + if (screenInfo.bitmapBitOrder == LSBFirst) { \ + bitmapByte = _reverse_byte[bitmapByte]; \ + } \ + for (b = 7; b >= 0; b--) { \ + memcpy (buf, (char *)&pix[bitmapByte >> b & 1], \ + sizeof(CARD##bpp)); \ + buf += sizeof(CARD##bpp); \ + } \ + } \ + if (widthPixels % 8) { \ + bitmapByte = src[y * widthBytes + x]; \ + if (screenInfo.bitmapBitOrder == LSBFirst) { \ + bitmapByte = _reverse_byte[bitmapByte]; \ + } \ + for (b = 7; b > 7 - widthPixels % 8; b--) { \ + memcpy (buf, (char *)&pix[bitmapByte >> b & 1], \ + sizeof(CARD##bpp)); \ + buf += sizeof(CARD##bpp); \ + } \ + } \ + } \ + \ + return (widthPixels * pCursor->bits->height * (bpp / 8)); \ +} + +DEFINE_RICH_ENCODE(16) +DEFINE_RICH_ENCODE(32) + diff --git a/example.c b/example.c index 1f1a4e3..cdbbc2e 100644 --- a/example.c +++ b/example.c @@ -208,6 +208,7 @@ int main(int argc,char** argv) rfbScreen->ptrAddEvent = doptr; rfbScreen->kbdAddEvent = dokey; rfbScreen->newClientHook = newclient; + rfbScreen->httpDir = "./classes"; initBuffer(rfbScreen->frameBuffer); diff --git a/httpd.c b/httpd.c new file mode 100644 index 0000000..37ae18a --- /dev/null +++ b/httpd.c @@ -0,0 +1,383 @@ +/* + * httpd.c - a simple HTTP server + */ + +/* + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rfb.h" + +#define NOT_FOUND_STR "HTTP/1.0 404 Not found\n\n" \ + "File Not Found\n" \ + "

File Not Found

\n" + +#define OK_STR "HTTP/1.0 200 OK\n\n" + +static void httpProcessInput(); +static Bool compareAndSkip(char **ptr, const char *str); + +/* +int httpPort = 0; +char *httpDir = NULL; + +int httpListenSock = -1; +int httpSock = -1; +FILE* httpFP = NULL; +*/ + +#define BUF_SIZE 32768 + +static char buf[BUF_SIZE]; + + +/* + * httpInitSockets sets up the TCP socket to listen for HTTP connections. + */ + +void +httpInitSockets(rfbScreenInfoPtr rfbScreen) +{ + static Bool done = FALSE; + + if (done) + return; + + done = TRUE; + + if (!rfbScreen->httpDir) + return; + + if (rfbScreen->httpPort == 0) { + rfbScreen->httpPort = rfbScreen->rfbPort-100; + } + + rfbLog("Listening for HTTP connections on TCP port %d\n", rfbScreen->httpPort); + + rfbLog(" URL http://%s:%d\n",rfbScreen->rfbThisHost,rfbScreen->httpPort); + + if ((rfbScreen->httpListenSock = ListenOnTCPPort(rfbScreen->httpPort)) < 0) { + rfbLogPerror("ListenOnTCPPort"); + exit(1); + } + + //AddEnabledDevice(httpListenSock); +} + + +/* + * httpCheckFds is called from ProcessInputEvents to check for input on the + * HTTP socket(s). If there is input to process, httpProcessInput is called. + */ + +void +httpCheckFds(rfbScreenInfoPtr rfbScreen) +{ + int nfds, n; + fd_set fds; + struct timeval tv; + struct sockaddr_in addr; + int addrlen = sizeof(addr); + + if (!rfbScreen->httpDir) + return; + + FD_ZERO(&fds); + FD_SET(rfbScreen->httpListenSock, &fds); + if (rfbScreen->httpSock >= 0) { + FD_SET(rfbScreen->httpSock, &fds); + } + tv.tv_sec = 0; + tv.tv_usec = 0; + nfds = select(max(rfbScreen->httpSock,rfbScreen->httpListenSock) + 1, &fds, NULL, NULL, &tv); + if (nfds == 0) { + return; + } + if (nfds < 0) { + rfbLogPerror("httpCheckFds: select"); + return; + } + + if ((rfbScreen->httpSock >= 0) && FD_ISSET(rfbScreen->httpSock, &fds)) { + httpProcessInput(rfbScreen); + } + + if (FD_ISSET(rfbScreen->httpListenSock, &fds)) { + if (rfbScreen->httpSock >= 0) close(rfbScreen->httpSock); + + if ((rfbScreen->httpSock = accept(rfbScreen->httpListenSock, + (struct sockaddr *)&addr, &addrlen)) < 0) { + rfbLogPerror("httpCheckFds: accept"); + return; + } + if ((rfbScreen->httpFP = fdopen(rfbScreen->httpSock, "r+")) == NULL) { + rfbLogPerror("httpCheckFds: fdopen"); + close(rfbScreen->httpSock); + rfbScreen->httpSock = -1; + return; + } + + //AddEnabledDevice(httpSock); + } +} + + +static void +httpCloseSock(rfbScreenInfoPtr rfbScreen) +{ + fclose(rfbScreen->httpFP); + rfbScreen->httpFP = NULL; + //RemoveEnabledDevice(httpSock); + rfbScreen->httpSock = -1; +} + +static rfbClientRec cl; + +/* + * httpProcessInput is called when input is received on the HTTP socket. + */ + +static void +httpProcessInput(rfbScreenInfoPtr rfbScreen) +{ + struct sockaddr_in addr; + int addrlen = sizeof(addr); + char fullFname[256]; + char *fname; + int maxFnameLen; + int fd; + Bool gotGet = FALSE; + Bool performSubstitutions = FALSE; + char str[256]; + struct passwd *user = getpwuid(getuid());; + + cl.sock=rfbScreen->httpSock; + + if (strlen(rfbScreen->httpDir) > 200) { + rfbLog("-httpd directory too long\n"); + httpCloseSock(rfbScreen); + return; + } + strcpy(fullFname, rfbScreen->httpDir); + fname = &fullFname[strlen(fullFname)]; + maxFnameLen = 255 - strlen(fullFname); + + buf[0] = '\0'; + + while (1) { + + /* Read lines from the HTTP client until a blank line. The only + line we need to parse is the line "GET ..." */ + + if (!fgets(buf, BUF_SIZE, rfbScreen->httpFP)) { + rfbLogPerror("httpProcessInput: fgets"); + httpCloseSock(rfbScreen); + return; + } + + if ((strcmp(buf,"\n") == 0) || (strcmp(buf,"\r\n") == 0) + || (strcmp(buf,"\r") == 0) || (strcmp(buf,"\n\r") == 0)) + /* end of client request */ + break; + + if (strncmp(buf, "GET ", 4) == 0) { + gotGet = TRUE; + + if (strlen(buf) > maxFnameLen) { + rfbLog("GET line too long\n"); + httpCloseSock(rfbScreen); + return; + } + + if (sscanf(buf, "GET %s HTTP/1.0", fname) != 1) { + rfbLog("couldn't parse GET line\n"); + httpCloseSock(rfbScreen); + return; + } + + if (fname[0] != '/') { + rfbLog("filename didn't begin with '/'\n"); + WriteExact(&cl, NOT_FOUND_STR, strlen(NOT_FOUND_STR)); + httpCloseSock(rfbScreen); + return; + } + + if (strchr(fname+1, '/') != NULL) { + rfbLog("asking for file in other directory\n"); + WriteExact(&cl, NOT_FOUND_STR, strlen(NOT_FOUND_STR)); + httpCloseSock(rfbScreen); + return; + } + + getpeername(rfbScreen->httpSock, (struct sockaddr *)&addr, &addrlen); + rfbLog("httpd: get '%s' for %s\n", fname+1, + inet_ntoa(addr.sin_addr)); + continue; + } + } + + if (!gotGet) { + rfbLog("no GET line\n"); + httpCloseSock(rfbScreen); + return; + } + + /* If we were asked for '/', actually read the file index.vnc */ + + if (strcmp(fname, "/") == 0) { + strcpy(fname, "/index.vnc"); + rfbLog("httpd: defaulting to '%s'\n", fname+1); + } + + /* Substitutions are performed on files ending .vnc */ + + if (strlen(fname) >= 4 && strcmp(&fname[strlen(fname)-4], ".vnc") == 0) { + performSubstitutions = TRUE; + } + + /* Open the file */ + + if ((fd = open(fullFname, O_RDONLY)) < 0) { + rfbLogPerror("httpProcessInput: open"); + WriteExact(&cl, NOT_FOUND_STR, strlen(NOT_FOUND_STR)); + httpCloseSock(rfbScreen); + return; + } + + WriteExact(&cl, OK_STR, strlen(OK_STR)); + + while (1) { + int n = read(fd, buf, BUF_SIZE-1); + if (n < 0) { + rfbLogPerror("httpProcessInput: read"); + close(fd); + httpCloseSock(rfbScreen); + return; + } + + if (n == 0) + break; + + if (performSubstitutions) { + + /* Substitute $WIDTH, $HEIGHT, etc with the appropriate values. + This won't quite work properly if the .vnc file is longer than + BUF_SIZE, but it's reasonable to assume that .vnc files will + always be short. */ + + char *ptr = buf; + char *dollar; + buf[n] = 0; /* make sure it's null-terminated */ + + while ((dollar = strchr(ptr, '$'))!=NULL) { + WriteExact(&cl, ptr, (dollar - ptr)); + + ptr = dollar; + + if (compareAndSkip(&ptr, "$WIDTH")) { + + sprintf(str, "%d", rfbScreen->width); + WriteExact(&cl, str, strlen(str)); + + } else if (compareAndSkip(&ptr, "$HEIGHT")) { + + sprintf(str, "%d", rfbScreen->height); + WriteExact(&cl, str, strlen(str)); + + } else if (compareAndSkip(&ptr, "$APPLETWIDTH")) { + + sprintf(str, "%d", rfbScreen->width); + WriteExact(&cl, str, strlen(str)); + + } else if (compareAndSkip(&ptr, "$APPLETHEIGHT")) { + + sprintf(str, "%d", rfbScreen->height + 32); + WriteExact(&cl, str, strlen(str)); + + } else if (compareAndSkip(&ptr, "$PORT")) { + + sprintf(str, "%d", rfbScreen->rfbPort); + WriteExact(&cl, str, strlen(str)); + + } else if (compareAndSkip(&ptr, "$DESKTOP")) { + + WriteExact(&cl, rfbScreen->desktopName, strlen(rfbScreen->desktopName)); + + } else if (compareAndSkip(&ptr, "$DISPLAY")) { + + sprintf(str, "%s:%d", rfbScreen->rfbThisHost, rfbScreen->rfbPort-5900); + WriteExact(&cl, str, strlen(str)); + + } else if (compareAndSkip(&ptr, "$USER")) { + + if (user) { + WriteExact(&cl, user->pw_name, + strlen(user->pw_name)); + } else { + WriteExact(&cl, "?", 1); + } + + } else { + if (!compareAndSkip(&ptr, "$$")) + ptr++; + + if (WriteExact(&cl, "$", 1) < 0) { + close(fd); + httpCloseSock(rfbScreen); + return; + } + } + } + if (WriteExact(&cl, ptr, (&buf[n] - ptr)) < 0) + break; + + } else { + + /* For files not ending .vnc, just write out the buffer */ + + if (WriteExact(&cl, buf, n) < 0) + break; + } + } + + close(fd); + httpCloseSock(rfbScreen); +} + + +static Bool +compareAndSkip(char **ptr, const char *str) +{ + if (strncmp(*ptr, str, strlen(str)) == 0) { + *ptr += strlen(str); + return TRUE; + } + + return FALSE; +} diff --git a/main.c b/main.c index 43cb0e0..6d9abe2 100644 --- a/main.c +++ b/main.c @@ -310,6 +310,11 @@ rfbScreenInfoPtr rfbDefaultScreenInit(int argc,char** argv,int width,int height, rfbScreen->maxFd=0; rfbScreen->rfbListenSock=-1; rfbScreen->udpPort=0; + rfbScreen->httpPort=0; + rfbScreen->httpDir=NULL; + rfbScreen->httpListenSock=-1; + rfbScreen->httpSock=-1; + rfbScreen->httpFP=NULL; rfbScreen->inetdInitDone = FALSE; rfbScreen->desktopName = "LibVNCServer"; rfbScreen->rfbAlwaysShared = FALSE; @@ -388,7 +393,7 @@ void processEvents(rfbScreenInfoPtr rfbScreen,long usec) { rfbCheckFds(rfbScreen,usec); - //httpCheckFds(rfbScreen); + httpCheckFds(rfbScreen); #ifdef CORBA corbaCheckFds(rfbScreen); #endif @@ -421,6 +426,7 @@ void runEventLoop(rfbScreenInfoPtr rfbScreen, long usec, Bool runInBackground) } rfbInitSockets(rfbScreen); + httpInitSockets(rfbScreen); while(1) processEvents(rfbScreen,usec); } diff --git a/rfb.h b/rfb.h index 6836c20..4a1257f 100644 --- a/rfb.h +++ b/rfb.h @@ -155,6 +155,11 @@ typedef struct Bool inetdInitDone; fd_set allFds; int rfbMaxClientWait; + int httpPort; + char* httpDir; + int httpListenSock; + int httpSock; + FILE* httpFP; char* rfbAuthPasswdFile; int rfbDeferUpdateTime; char* rfbScreen;