PageRenderTime 141ms CodeModel.GetById 9ms app.highlight 113ms RepoModel.GetById 1ms app.codeStats 1ms

/apps/desktop/libvncserver/rfbserver.c

http://ftk.googlecode.com/
C | 2091 lines | 1533 code | 301 blank | 257 comment | 247 complexity | b001978ce777d800da530f617c17cbc0 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/*
   2 * rfbserver.c - deal with server-side of the RFB protocol.
   3 */
   4
   5/*
   6 *  Copyright (C) 2005 Rohit Kumar, Johannes E. Schindelin
   7 *  Copyright (C) 2002 RealVNC Ltd.
   8 *  OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
   9 *  Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.  
  10 *  All Rights Reserved.
  11 *
  12 *  This is free software; you can redistribute it and/or modify
  13 *  it under the terms of the GNU General Public License as published by
  14 *  the Free Software Foundation; either version 2 of the License, or
  15 *  (at your option) any later version.
  16 *
  17 *  This software is distributed in the hope that it will be useful,
  18 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  19 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20 *  GNU General Public License for more details.
  21 *
  22 *  You should have received a copy of the GNU General Public License
  23 *  along with this software; if not, write to the Free Software
  24 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
  25 *  USA.
  26 */
  27
  28#ifdef __STRICT_ANSI__
  29#define _BSD_SOURCE
  30#endif
  31#include <string.h>
  32#include <rfb/rfb.h>
  33#include <rfb/rfbregion.h>
  34#include "private.h"
  35
  36#ifdef LIBVNCSERVER_HAVE_FCNTL_H
  37#include <fcntl.h>
  38#endif
  39
  40#ifdef WIN32
  41#define write(sock,buf,len) send(sock,buf,len,0)
  42#else
  43#ifdef LIBVNCSERVER_HAVE_UNISTD_H
  44#include <unistd.h>
  45#endif
  46#include <pwd.h>
  47#ifdef LIBVNCSERVER_HAVE_SYS_SOCKET_H
  48#include <sys/socket.h>
  49#endif
  50#ifdef LIBVNCSERVER_HAVE_NETINET_IN_H
  51#include <netinet/in.h>
  52#include <netinet/tcp.h>
  53#include <arpa/inet.h>
  54#endif
  55#endif
  56
  57#ifdef CORBA
  58#include <vncserverctrl.h>
  59#endif
  60
  61#ifdef DEBUGPROTO
  62#undef DEBUGPROTO
  63#define DEBUGPROTO(x) x
  64#else
  65#define DEBUGPROTO(x)
  66#endif
  67#include <stdarg.h>
  68#include <scale.h>
  69/* stst() */
  70#include <sys/types.h>
  71#include <sys/stat.h>
  72#include <unistd.h>
  73/* readdir() */
  74#include <dirent.h>
  75/* errno */
  76#include <errno.h>
  77
  78#ifdef __MINGW32__
  79static int compat_mkdir(const char *path, int mode)
  80{
  81	return mkdir(path);
  82}
  83#define mkdir compat_mkdir
  84#endif
  85
  86static void rfbProcessClientProtocolVersion(rfbClientPtr cl);
  87static void rfbProcessClientNormalMessage(rfbClientPtr cl);
  88static void rfbProcessClientInitMessage(rfbClientPtr cl);
  89
  90#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
  91void rfbIncrClientRef(rfbClientPtr cl)
  92{
  93  LOCK(cl->refCountMutex);
  94  cl->refCount++;
  95  UNLOCK(cl->refCountMutex);
  96}
  97
  98void rfbDecrClientRef(rfbClientPtr cl)
  99{
 100  LOCK(cl->refCountMutex);
 101  cl->refCount--;
 102  if(cl->refCount<=0) /* just to be sure also < 0 */
 103    TSIGNAL(cl->deleteCond);
 104  UNLOCK(cl->refCountMutex);
 105}
 106#else
 107void rfbIncrClientRef(rfbClientPtr cl) {}
 108void rfbDecrClientRef(rfbClientPtr cl) {}
 109#endif
 110
 111#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
 112static MUTEX(rfbClientListMutex);
 113#endif
 114
 115struct rfbClientIterator {
 116  rfbClientPtr next;
 117  rfbScreenInfoPtr screen;
 118  rfbBool closedToo;
 119};
 120
 121void
 122rfbClientListInit(rfbScreenInfoPtr rfbScreen)
 123{
 124    if(sizeof(rfbBool)!=1) {
 125        /* a sanity check */
 126        fprintf(stderr,"rfbBool's size is not 1 (%d)!\n",(int)sizeof(rfbBool));
 127	/* we cannot continue, because rfbBool is supposed to be char everywhere */
 128	exit(1);
 129    }
 130    rfbScreen->clientHead = NULL;
 131    INIT_MUTEX(rfbClientListMutex);
 132}
 133
 134rfbClientIteratorPtr
 135rfbGetClientIterator(rfbScreenInfoPtr rfbScreen)
 136{
 137  rfbClientIteratorPtr i =
 138    (rfbClientIteratorPtr)malloc(sizeof(struct rfbClientIterator));
 139  i->next = NULL;
 140  i->screen = rfbScreen;
 141  i->closedToo = FALSE;
 142  return i;
 143}
 144
 145rfbClientIteratorPtr
 146rfbGetClientIteratorWithClosed(rfbScreenInfoPtr rfbScreen)
 147{
 148  rfbClientIteratorPtr i =
 149    (rfbClientIteratorPtr)malloc(sizeof(struct rfbClientIterator));
 150  i->next = NULL;
 151  i->screen = rfbScreen;
 152  i->closedToo = TRUE;
 153  return i;
 154}
 155
 156rfbClientPtr
 157rfbClientIteratorHead(rfbClientIteratorPtr i)
 158{
 159#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
 160  if(i->next != 0) {
 161    rfbDecrClientRef(i->next);
 162    rfbIncrClientRef(i->screen->clientHead);
 163  }
 164#endif
 165  LOCK(rfbClientListMutex);
 166  i->next = i->screen->clientHead;
 167  UNLOCK(rfbClientListMutex);
 168  return i->next;
 169}
 170
 171rfbClientPtr
 172rfbClientIteratorNext(rfbClientIteratorPtr i)
 173{
 174  if(i->next == 0) {
 175    LOCK(rfbClientListMutex);
 176    i->next = i->screen->clientHead;
 177    UNLOCK(rfbClientListMutex);
 178  } else {
 179    IF_PTHREADS(rfbClientPtr cl = i->next);
 180    i->next = i->next->next;
 181    IF_PTHREADS(rfbDecrClientRef(cl));
 182  }
 183
 184#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
 185    if(!i->closedToo)
 186      while(i->next && i->next->sock<0)
 187        i->next = i->next->next;
 188    if(i->next)
 189      rfbIncrClientRef(i->next);
 190#endif
 191
 192    return i->next;
 193}
 194
 195void
 196rfbReleaseClientIterator(rfbClientIteratorPtr iterator)
 197{
 198  IF_PTHREADS(if(iterator->next) rfbDecrClientRef(iterator->next));
 199  free(iterator);
 200}
 201
 202
 203/*
 204 * rfbNewClientConnection is called from sockets.c when a new connection
 205 * comes in.
 206 */
 207
 208void
 209rfbNewClientConnection(rfbScreenInfoPtr rfbScreen,
 210                       int sock)
 211{
 212    rfbClientPtr cl;
 213
 214    cl = rfbNewClient(rfbScreen,sock);
 215#ifdef CORBA
 216    if(cl!=NULL)
 217      newConnection(cl, (KEYBOARD_DEVICE|POINTER_DEVICE),1,1,1);
 218#endif
 219}
 220
 221
 222/*
 223 * rfbReverseConnection is called by the CORBA stuff to make an outward
 224 * connection to a "listening" RFB client.
 225 */
 226
 227rfbClientPtr
 228rfbReverseConnection(rfbScreenInfoPtr rfbScreen,
 229                     char *host,
 230                     int port)
 231{
 232    int sock;
 233    rfbClientPtr cl;
 234
 235    if ((sock = rfbConnect(rfbScreen, host, port)) < 0)
 236        return (rfbClientPtr)NULL;
 237
 238    cl = rfbNewClient(rfbScreen, sock);
 239
 240    if (cl) {
 241        cl->reverseConnection = TRUE;
 242    }
 243
 244    return cl;
 245}
 246
 247
 248void
 249rfbSetProtocolVersion(rfbScreenInfoPtr rfbScreen, int major_, int minor_)
 250{
 251    /* Permit the server to set the version to report */
 252    /* TODO: sanity checking */
 253    if ((major_==3) && (minor_ > 2 && minor_ < 9))
 254    {
 255      rfbScreen->protocolMajorVersion = major_;
 256      rfbScreen->protocolMinorVersion = minor_;
 257    }
 258    else
 259        rfbLog("rfbSetProtocolVersion(%d,%d) set to invalid values\n", major_, minor_);
 260}
 261
 262/*
 263 * rfbNewClient is called when a new connection has been made by whatever
 264 * means.
 265 */
 266
 267static rfbClientPtr
 268rfbNewTCPOrUDPClient(rfbScreenInfoPtr rfbScreen,
 269                     int sock,
 270                     rfbBool isUDP)
 271{
 272    rfbProtocolVersionMsg pv;
 273    rfbClientIteratorPtr iterator;
 274    rfbClientPtr cl,cl_;
 275    struct sockaddr_in addr;
 276    socklen_t addrlen = sizeof(struct sockaddr_in);
 277    rfbProtocolExtension* extension;
 278
 279    cl = (rfbClientPtr)calloc(sizeof(rfbClientRec),1);
 280
 281    cl->screen = rfbScreen;
 282    cl->sock = sock;
 283    cl->viewOnly = FALSE;
 284    /* setup pseudo scaling */
 285    cl->scaledScreen = rfbScreen;
 286    cl->scaledScreen->scaledScreenRefCount++;
 287
 288    rfbResetStats(cl);
 289
 290    cl->clientData = NULL;
 291    cl->clientGoneHook = rfbDoNothingWithClient;
 292
 293    if(isUDP) {
 294      rfbLog(" accepted UDP client\n");
 295    } else {
 296      int one=1;
 297
 298      getpeername(sock, (struct sockaddr *)&addr, &addrlen);
 299      cl->host = strdup(inet_ntoa(addr.sin_addr));
 300
 301      rfbLog("  other clients:\n");
 302      iterator = rfbGetClientIterator(rfbScreen);
 303      while ((cl_ = rfbClientIteratorNext(iterator)) != NULL) {
 304        rfbLog("     %s\n",cl_->host);
 305      }
 306      rfbReleaseClientIterator(iterator);
 307
 308#ifndef WIN32
 309      if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
 310	rfbLogPerror("fcntl failed");
 311	close(sock);
 312	return NULL;
 313      }
 314#endif
 315
 316      if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
 317		     (char *)&one, sizeof(one)) < 0) {
 318	rfbLogPerror("setsockopt failed");
 319	close(sock);
 320	return NULL;
 321      }
 322
 323      FD_SET(sock,&(rfbScreen->allFds));
 324		rfbScreen->maxFd = max(sock,rfbScreen->maxFd);
 325
 326      INIT_MUTEX(cl->outputMutex);
 327      INIT_MUTEX(cl->refCountMutex);
 328      INIT_COND(cl->deleteCond);
 329
 330      cl->state = RFB_PROTOCOL_VERSION;
 331
 332      cl->reverseConnection = FALSE;
 333      cl->readyForSetColourMapEntries = FALSE;
 334      cl->useCopyRect = FALSE;
 335      cl->preferredEncoding = -1;
 336      cl->correMaxWidth = 48;
 337      cl->correMaxHeight = 48;
 338#ifdef LIBVNCSERVER_HAVE_LIBZ
 339      cl->zrleData = NULL;
 340#endif
 341
 342      cl->copyRegion = sraRgnCreate();
 343      cl->copyDX = 0;
 344      cl->copyDY = 0;
 345   
 346      cl->modifiedRegion =
 347	sraRgnCreateRect(0,0,rfbScreen->width,rfbScreen->height);
 348
 349      INIT_MUTEX(cl->updateMutex);
 350      INIT_COND(cl->updateCond);
 351
 352      cl->requestedRegion = sraRgnCreate();
 353
 354      cl->format = cl->screen->serverFormat;
 355      cl->translateFn = rfbTranslateNone;
 356      cl->translateLookupTable = NULL;
 357
 358      LOCK(rfbClientListMutex);
 359
 360      IF_PTHREADS(cl->refCount = 0);
 361      cl->next = rfbScreen->clientHead;
 362      cl->prev = NULL;
 363      if (rfbScreen->clientHead)
 364        rfbScreen->clientHead->prev = cl;
 365
 366      rfbScreen->clientHead = cl;
 367      UNLOCK(rfbClientListMutex);
 368
 369#ifdef LIBVNCSERVER_HAVE_LIBZ
 370#ifdef LIBVNCSERVER_HAVE_LIBJPEG
 371      cl->tightCompressLevel = TIGHT_DEFAULT_COMPRESSION;
 372      cl->tightQualityLevel = -1;
 373      {
 374	int i;
 375	for (i = 0; i < 4; i++)
 376          cl->zsActive[i] = FALSE;
 377      }
 378#endif
 379#endif
 380
 381      cl->fileTransfer.fd = -1;
 382
 383      cl->enableCursorShapeUpdates = FALSE;
 384      cl->enableCursorPosUpdates = FALSE;
 385      cl->useRichCursorEncoding = FALSE;
 386      cl->enableLastRectEncoding = FALSE;
 387      cl->enableKeyboardLedState = FALSE;
 388      cl->enableSupportedMessages = FALSE;
 389      cl->enableSupportedEncodings = FALSE;
 390      cl->enableServerIdentity = FALSE;
 391      cl->lastKeyboardLedState = -1;
 392      cl->cursorX = rfbScreen->cursorX;
 393      cl->cursorY = rfbScreen->cursorY;
 394      cl->useNewFBSize = FALSE;
 395
 396#ifdef LIBVNCSERVER_HAVE_LIBZ
 397      cl->compStreamInited = FALSE;
 398      cl->compStream.total_in = 0;
 399      cl->compStream.total_out = 0;
 400      cl->compStream.zalloc = Z_NULL;
 401      cl->compStream.zfree = Z_NULL;
 402      cl->compStream.opaque = Z_NULL;
 403
 404      cl->zlibCompressLevel = 5;
 405#endif
 406
 407      cl->progressiveSliceY = 0;
 408
 409      cl->extensions = NULL;
 410
 411      cl->lastPtrX = -1;
 412
 413      sprintf(pv,rfbProtocolVersionFormat,rfbScreen->protocolMajorVersion, 
 414              rfbScreen->protocolMinorVersion);
 415
 416      if (rfbWriteExact(cl, pv, sz_rfbProtocolVersionMsg) < 0) {
 417        rfbLogPerror("rfbNewClient: write");
 418        rfbCloseClient(cl);
 419	rfbClientConnectionGone(cl);
 420        return NULL;
 421      }
 422    }
 423
 424    for(extension = rfbGetExtensionIterator(); extension;
 425	    extension=extension->next) {
 426	void* data = NULL;
 427	/* if the extension does not have a newClient method, it wants
 428	 * to be initialized later. */
 429	if(extension->newClient && extension->newClient(cl, &data))
 430		rfbEnableExtension(cl, extension, data);
 431    }
 432    rfbReleaseExtensionIterator();
 433
 434    switch (cl->screen->newClientHook(cl)) {
 435    case RFB_CLIENT_ON_HOLD:
 436	    cl->onHold = TRUE;
 437	    break;
 438    case RFB_CLIENT_ACCEPT:
 439	    cl->onHold = FALSE;
 440	    break;
 441    case RFB_CLIENT_REFUSE:
 442	    rfbCloseClient(cl);
 443	    rfbClientConnectionGone(cl);
 444	    cl = NULL;
 445	    break;
 446    }
 447    return cl;
 448}
 449
 450rfbClientPtr
 451rfbNewClient(rfbScreenInfoPtr rfbScreen,
 452             int sock)
 453{
 454  return(rfbNewTCPOrUDPClient(rfbScreen,sock,FALSE));
 455}
 456
 457rfbClientPtr
 458rfbNewUDPClient(rfbScreenInfoPtr rfbScreen)
 459{
 460  return((rfbScreen->udpClient=
 461	  rfbNewTCPOrUDPClient(rfbScreen,rfbScreen->udpSock,TRUE)));
 462}
 463
 464/*
 465 * rfbClientConnectionGone is called from sockets.c just after a connection
 466 * has gone away.
 467 */
 468
 469void
 470rfbClientConnectionGone(rfbClientPtr cl)
 471{
 472#ifdef LIBVNCSERVER_HAVE_LIBJPEG
 473    int i;
 474#endif
 475
 476    LOCK(rfbClientListMutex);
 477
 478    if (cl->prev)
 479        cl->prev->next = cl->next;
 480    else
 481        cl->screen->clientHead = cl->next;
 482    if (cl->next)
 483        cl->next->prev = cl->prev;
 484
 485    if(cl->sock>0)
 486	close(cl->sock);
 487
 488    if (cl->scaledScreen!=NULL)
 489        cl->scaledScreen->scaledScreenRefCount--;
 490
 491#ifdef LIBVNCSERVER_HAVE_LIBZ
 492    rfbFreeZrleData(cl);
 493#endif
 494
 495    rfbFreeUltraData(cl);
 496
 497#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
 498    if(cl->screen->backgroundLoop != FALSE) {
 499      int i;
 500      do {
 501	LOCK(cl->refCountMutex);
 502	i=cl->refCount;
 503	if(i>0)
 504	  WAIT(cl->deleteCond,cl->refCountMutex);
 505	UNLOCK(cl->refCountMutex);
 506      } while(i>0);
 507    }
 508#endif
 509
 510    UNLOCK(rfbClientListMutex);
 511
 512    if(cl->sock>=0)
 513       FD_CLR(cl->sock,&(cl->screen->allFds));
 514
 515    cl->clientGoneHook(cl);
 516
 517    rfbLog("Client %s gone\n",cl->host);
 518    free(cl->host);
 519
 520#ifdef LIBVNCSERVER_HAVE_LIBZ
 521    /* Release the compression state structures if any. */
 522    if ( cl->compStreamInited ) {
 523	deflateEnd( &(cl->compStream) );
 524    }
 525
 526#ifdef LIBVNCSERVER_HAVE_LIBJPEG
 527    for (i = 0; i < 4; i++) {
 528	if (cl->zsActive[i])
 529	    deflateEnd(&cl->zsStruct[i]);
 530    }
 531#endif
 532#endif
 533
 534    if (cl->screen->pointerClient == cl)
 535        cl->screen->pointerClient = NULL;
 536
 537    sraRgnDestroy(cl->modifiedRegion);
 538    sraRgnDestroy(cl->requestedRegion);
 539    sraRgnDestroy(cl->copyRegion);
 540
 541    if (cl->translateLookupTable) free(cl->translateLookupTable);
 542
 543    TINI_COND(cl->updateCond);
 544    TINI_MUTEX(cl->updateMutex);
 545
 546    /* make sure outputMutex is unlocked before destroying */
 547    LOCK(cl->outputMutex);
 548    UNLOCK(cl->outputMutex);
 549    TINI_MUTEX(cl->outputMutex);
 550
 551#ifdef CORBA
 552    destroyConnection(cl);
 553#endif
 554
 555    rfbPrintStats(cl);
 556
 557    free(cl);
 558}
 559
 560
 561/*
 562 * rfbProcessClientMessage is called when there is data to read from a client.
 563 */
 564
 565void
 566rfbProcessClientMessage(rfbClientPtr cl)
 567{
 568    switch (cl->state) {
 569    case RFB_PROTOCOL_VERSION:
 570        rfbProcessClientProtocolVersion(cl);
 571        return;
 572    case RFB_SECURITY_TYPE:
 573        rfbProcessClientSecurityType(cl);
 574        return;
 575    case RFB_AUTHENTICATION:
 576        rfbAuthProcessClientMessage(cl);
 577        return;
 578    case RFB_INITIALISATION:
 579        rfbProcessClientInitMessage(cl);
 580        return;
 581    default:
 582        rfbProcessClientNormalMessage(cl);
 583        return;
 584    }
 585}
 586
 587
 588/*
 589 * rfbProcessClientProtocolVersion is called when the client sends its
 590 * protocol version.
 591 */
 592
 593static void
 594rfbProcessClientProtocolVersion(rfbClientPtr cl)
 595{
 596    rfbProtocolVersionMsg pv;
 597    int n, major_, minor_;
 598
 599    if ((n = rfbReadExact(cl, pv, sz_rfbProtocolVersionMsg)) <= 0) {
 600        if (n == 0)
 601            rfbLog("rfbProcessClientProtocolVersion: client gone\n");
 602        else
 603            rfbLogPerror("rfbProcessClientProtocolVersion: read");
 604        rfbCloseClient(cl);
 605        return;
 606    }
 607
 608    pv[sz_rfbProtocolVersionMsg] = 0;
 609    if (sscanf(pv,rfbProtocolVersionFormat,&major_,&minor_) != 2) {
 610        char name[1024]; 
 611	if(sscanf(pv,"RFB %03d.%03d %1023s\n",&major_,&minor_,name) != 3) {
 612	    rfbErr("rfbProcessClientProtocolVersion: not a valid RFB client: %s\n", pv);
 613	    rfbCloseClient(cl);
 614	    return;
 615	}
 616	free(cl->host);
 617	cl->host=strdup(name);
 618    }
 619    rfbLog("Client Protocol Version %d.%d\n", major_, minor_);
 620
 621    if (major_ != rfbProtocolMajorVersion) {
 622        rfbErr("RFB protocol version mismatch - server %d.%d, client %d.%d",
 623                cl->screen->protocolMajorVersion, cl->screen->protocolMinorVersion,
 624                major_,minor_);
 625        rfbCloseClient(cl);
 626        return;
 627    }
 628
 629    /* Check for the minor version use either of the two standard version of RFB */
 630    /*
 631     * UltraVNC Viewer detects FileTransfer compatible servers via rfb versions
 632     * 3.4, 3.6, 3.14, 3.16
 633     * It's a bad method, but it is what they use to enable features...
 634     * maintaining RFB version compatibility across multiple servers is a pain
 635     * Should use something like ServerIdentity encoding
 636     */
 637    cl->protocolMajorVersion = major_;
 638    cl->protocolMinorVersion = minor_;
 639    
 640    rfbLog("Protocol version sent %d.%d, using %d.%d\n",
 641              major_, minor_, rfbProtocolMajorVersion, cl->protocolMinorVersion);
 642
 643    rfbAuthNewClient(cl);
 644}
 645
 646
 647void
 648rfbClientSendString(rfbClientPtr cl, char *reason)
 649{
 650    char *buf;
 651    int len = strlen(reason);
 652
 653    rfbLog("rfbClientSendString(\"%s\")\n", reason);
 654
 655    buf = (char *)malloc(4 + len);
 656    ((uint32_t *)buf)[0] = Swap32IfLE(len);
 657    memcpy(buf + 4, reason, len);
 658
 659    if (rfbWriteExact(cl, buf, 4 + len) < 0)
 660        rfbLogPerror("rfbClientSendString: write");
 661    free(buf);
 662
 663    rfbCloseClient(cl);
 664}
 665
 666/*
 667 * rfbClientConnFailed is called when a client connection has failed either
 668 * because it talks the wrong protocol or it has failed authentication.
 669 */
 670
 671void
 672rfbClientConnFailed(rfbClientPtr cl,
 673                    char *reason)
 674{
 675    char *buf;
 676    int len = strlen(reason);
 677
 678    rfbLog("rfbClientConnFailed(\"%s\")\n", reason);
 679
 680    buf = (char *)malloc(8 + len);
 681    ((uint32_t *)buf)[0] = Swap32IfLE(rfbConnFailed);
 682    ((uint32_t *)buf)[1] = Swap32IfLE(len);
 683    memcpy(buf + 8, reason, len);
 684
 685    if (rfbWriteExact(cl, buf, 8 + len) < 0)
 686        rfbLogPerror("rfbClientConnFailed: write");
 687    free(buf);
 688
 689    rfbCloseClient(cl);
 690}
 691
 692
 693/*
 694 * rfbProcessClientInitMessage is called when the client sends its
 695 * initialisation message.
 696 */
 697
 698static void
 699rfbProcessClientInitMessage(rfbClientPtr cl)
 700{
 701    rfbClientInitMsg ci;
 702    char buf[256];
 703    rfbServerInitMsg *si = (rfbServerInitMsg *)buf;
 704    int len, n;
 705    rfbClientIteratorPtr iterator;
 706    rfbClientPtr otherCl;
 707    rfbExtensionData* extension;
 708
 709    if ((n = rfbReadExact(cl, (char *)&ci,sz_rfbClientInitMsg)) <= 0) {
 710        if (n == 0)
 711            rfbLog("rfbProcessClientInitMessage: client gone\n");
 712        else
 713            rfbLogPerror("rfbProcessClientInitMessage: read");
 714        rfbCloseClient(cl);
 715        return;
 716    }
 717
 718    memset(buf,0,sizeof(buf));
 719
 720    si->framebufferWidth = Swap16IfLE(cl->screen->width);
 721    si->framebufferHeight = Swap16IfLE(cl->screen->height);
 722    si->format = cl->screen->serverFormat;
 723    si->format.redMax = Swap16IfLE(si->format.redMax);
 724    si->format.greenMax = Swap16IfLE(si->format.greenMax);
 725    si->format.blueMax = Swap16IfLE(si->format.blueMax);
 726
 727    strncpy(buf + sz_rfbServerInitMsg, cl->screen->desktopName, 127);
 728    len = strlen(buf + sz_rfbServerInitMsg);
 729    si->nameLength = Swap32IfLE(len);
 730
 731    if (rfbWriteExact(cl, buf, sz_rfbServerInitMsg + len) < 0) {
 732        rfbLogPerror("rfbProcessClientInitMessage: write");
 733        rfbCloseClient(cl);
 734        return;
 735    }
 736
 737    for(extension = cl->extensions; extension;) {
 738	rfbExtensionData* next = extension->next;
 739	if(extension->extension->init &&
 740		!extension->extension->init(cl, extension->data))
 741	    /* extension requested that it be removed */
 742	    rfbDisableExtension(cl, extension->extension);
 743	extension = next;
 744    }
 745
 746    cl->state = RFB_NORMAL;
 747
 748    if (!cl->reverseConnection &&
 749                        (cl->screen->neverShared || (!cl->screen->alwaysShared && !ci.shared))) {
 750
 751        if (cl->screen->dontDisconnect) {
 752            iterator = rfbGetClientIterator(cl->screen);
 753            while ((otherCl = rfbClientIteratorNext(iterator)) != NULL) {
 754                if ((otherCl != cl) && (otherCl->state == RFB_NORMAL)) {
 755                    rfbLog("-dontdisconnect: Not shared & existing client\n");
 756                    rfbLog("  refusing new client %s\n", cl->host);
 757                    rfbCloseClient(cl);
 758                    rfbReleaseClientIterator(iterator);
 759                    return;
 760                }
 761            }
 762            rfbReleaseClientIterator(iterator);
 763        } else {
 764            iterator = rfbGetClientIterator(cl->screen);
 765            while ((otherCl = rfbClientIteratorNext(iterator)) != NULL) {
 766                if ((otherCl != cl) && (otherCl->state == RFB_NORMAL)) {
 767                    rfbLog("Not shared - closing connection to client %s\n",
 768                           otherCl->host);
 769                    rfbCloseClient(otherCl);
 770                }
 771            }
 772            rfbReleaseClientIterator(iterator);
 773        }
 774    }
 775}
 776
 777/* The values come in based on the scaled screen, we need to convert them to
 778 * values based on the man screen's coordinate system
 779 */
 780static rfbBool rectSwapIfLEAndClip(uint16_t* x,uint16_t* y,uint16_t* w,uint16_t* h,
 781		rfbClientPtr cl)
 782{
 783	int x1=Swap16IfLE(*x);
 784	int y1=Swap16IfLE(*y);
 785	int w1=Swap16IfLE(*w);
 786	int h1=Swap16IfLE(*h);
 787
 788	rfbScaledCorrection(cl->scaledScreen, cl->screen, &x1, &y1, &w1, &h1, "rectSwapIfLEAndClip");
 789	*x = x1;
 790	*y = y1;
 791	*w = w1;
 792	*h = h1;
 793
 794	if(*w>cl->screen->width-*x)
 795		*w=cl->screen->width-*x;
 796	/* possible underflow */
 797	if(*w>cl->screen->width-*x)
 798		return FALSE;
 799	if(*h>cl->screen->height-*y)
 800		*h=cl->screen->height-*y;
 801	if(*h>cl->screen->height-*y)
 802		return FALSE;
 803
 804	return TRUE;
 805}
 806
 807/*
 808 * Send keyboard state (PointerPos pseudo-encoding).
 809 */
 810
 811rfbBool
 812rfbSendKeyboardLedState(rfbClientPtr cl)
 813{
 814    rfbFramebufferUpdateRectHeader rect;
 815
 816    if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
 817        if (!rfbSendUpdateBuf(cl))
 818            return FALSE;
 819    }
 820
 821    rect.encoding = Swap32IfLE(rfbEncodingKeyboardLedState);
 822    rect.r.x = Swap16IfLE(cl->lastKeyboardLedState);
 823    rect.r.y = 0;
 824    rect.r.w = 0;
 825    rect.r.h = 0;
 826
 827    memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
 828        sz_rfbFramebufferUpdateRectHeader);
 829    cl->ublen += sz_rfbFramebufferUpdateRectHeader;
 830
 831    rfbStatRecordEncodingSent(cl, rfbEncodingKeyboardLedState, sz_rfbFramebufferUpdateRectHeader, sz_rfbFramebufferUpdateRectHeader);
 832
 833    if (!rfbSendUpdateBuf(cl))
 834        return FALSE;
 835
 836    return TRUE;
 837}
 838
 839
 840#define rfbSetBit(buffer, position)  (buffer[(position & 255) / 8] |= (1 << (position % 8)))
 841
 842/*
 843 * Send rfbEncodingSupportedMessages.
 844 */
 845
 846rfbBool
 847rfbSendSupportedMessages(rfbClientPtr cl)
 848{
 849    rfbFramebufferUpdateRectHeader rect;
 850    rfbSupportedMessages msgs;
 851
 852    if (cl->ublen + sz_rfbFramebufferUpdateRectHeader
 853                  + sz_rfbSupportedMessages > UPDATE_BUF_SIZE) {
 854        if (!rfbSendUpdateBuf(cl))
 855            return FALSE;
 856    }
 857
 858    rect.encoding = Swap32IfLE(rfbEncodingSupportedMessages);
 859    rect.r.x = 0;
 860    rect.r.y = 0;
 861    rect.r.w = Swap16IfLE(sz_rfbSupportedMessages);
 862    rect.r.h = 0;
 863
 864    memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
 865        sz_rfbFramebufferUpdateRectHeader);
 866    cl->ublen += sz_rfbFramebufferUpdateRectHeader;
 867
 868    memset((char *)&msgs, 0, sz_rfbSupportedMessages);
 869    rfbSetBit(msgs.client2server, rfbSetPixelFormat);
 870    rfbSetBit(msgs.client2server, rfbFixColourMapEntries);
 871    rfbSetBit(msgs.client2server, rfbSetEncodings);
 872    rfbSetBit(msgs.client2server, rfbFramebufferUpdateRequest);
 873    rfbSetBit(msgs.client2server, rfbKeyEvent);
 874    rfbSetBit(msgs.client2server, rfbPointerEvent);
 875    rfbSetBit(msgs.client2server, rfbClientCutText);
 876    rfbSetBit(msgs.client2server, rfbFileTransfer);
 877    rfbSetBit(msgs.client2server, rfbSetScale);
 878    /*rfbSetBit(msgs.client2server, rfbSetServerInput);  */
 879    /*rfbSetBit(msgs.client2server, rfbSetSW);           */
 880    /*rfbSetBit(msgs.client2server, rfbTextChat);        */
 881    /*rfbSetBit(msgs.client2server, rfbKeyFrameRequest); */
 882    rfbSetBit(msgs.client2server, rfbPalmVNCSetScaleFactor);
 883
 884    rfbSetBit(msgs.server2client, rfbFramebufferUpdate);
 885    rfbSetBit(msgs.server2client, rfbSetColourMapEntries);
 886    rfbSetBit(msgs.server2client, rfbBell);
 887    rfbSetBit(msgs.server2client, rfbServerCutText);
 888    rfbSetBit(msgs.server2client, rfbResizeFrameBuffer);
 889    /*rfbSetBit(msgs.server2client, rfbKeyFrameUpdate);  */
 890    rfbSetBit(msgs.server2client, rfbPalmVNCReSizeFrameBuffer);
 891
 892    memcpy(&cl->updateBuf[cl->ublen], (char *)&msgs, sz_rfbSupportedMessages);
 893    cl->ublen += sz_rfbSupportedMessages;
 894
 895    rfbStatRecordEncodingSent(cl, rfbEncodingSupportedMessages,
 896        sz_rfbFramebufferUpdateRectHeader+sz_rfbSupportedMessages,
 897        sz_rfbFramebufferUpdateRectHeader+sz_rfbSupportedMessages);
 898    if (!rfbSendUpdateBuf(cl))
 899        return FALSE;
 900
 901    return TRUE;
 902}
 903
 904
 905
 906static void rfbSendSupporteddEncodings_SendEncoding(rfbClientPtr cl, uint32_t enc)
 907{
 908    uint32_t nSwapped=0;
 909    nSwapped = Swap32IfLE(enc);
 910    memcpy(&cl->updateBuf[cl->ublen], (char *)&nSwapped, sizeof(nSwapped));
 911    cl->ublen+=sizeof(nSwapped);
 912}
 913
 914
 915/*
 916 * Send rfbEncodingSupportedEncodings.
 917 */
 918
 919rfbBool
 920rfbSendSupportedEncodings(rfbClientPtr cl)
 921{
 922    rfbFramebufferUpdateRectHeader rect;
 923    uint16_t nEncodings=0;
 924    
 925    /* think rfbSetEncodingsMsg */
 926
 927    /* TODO: dynamic way of doing this */
 928    nEncodings=16;
 929#ifdef LIBVNCSERVER_HAVE_LIBZ
 930    nEncodings += 2;
 931#endif
 932#ifdef LIBVNCSERVER_HAVE_LIBZ
 933    nEncodings++;
 934#endif
 935
 936    if (cl->ublen + sz_rfbFramebufferUpdateRectHeader
 937                  + (nEncodings*sizeof(uint32_t)) > UPDATE_BUF_SIZE) {
 938        if (!rfbSendUpdateBuf(cl))
 939            return FALSE;
 940    }
 941
 942    rect.encoding = Swap32IfLE(rfbEncodingSupportedEncodings);
 943    rect.r.x = 0;
 944    rect.r.y = 0;
 945    rect.r.w = Swap16IfLE(nEncodings * sizeof(uint32_t));
 946    rect.r.h = Swap16IfLE(nEncodings);
 947
 948    memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
 949        sz_rfbFramebufferUpdateRectHeader);
 950    cl->ublen += sz_rfbFramebufferUpdateRectHeader;
 951
 952    rfbSendSupporteddEncodings_SendEncoding(cl, rfbEncodingRaw);
 953    rfbSendSupporteddEncodings_SendEncoding(cl, rfbEncodingCopyRect);
 954    rfbSendSupporteddEncodings_SendEncoding(cl, rfbEncodingRRE);
 955    rfbSendSupporteddEncodings_SendEncoding(cl, rfbEncodingCoRRE);
 956    rfbSendSupporteddEncodings_SendEncoding(cl, rfbEncodingHextile);
 957#ifdef LIBVNCSERVER_HAVE_LIBZ
 958    rfbSendSupporteddEncodings_SendEncoding(cl, rfbEncodingZlib);
 959    rfbSendSupporteddEncodings_SendEncoding(cl, rfbEncodingTight);
 960#endif
 961#ifdef LIBVNCSERVER_HAVE_LIBZ
 962    rfbSendSupporteddEncodings_SendEncoding(cl, rfbEncodingZRLE);
 963#endif
 964    rfbSendSupporteddEncodings_SendEncoding(cl, rfbEncodingUltra);
 965    rfbSendSupporteddEncodings_SendEncoding(cl, rfbEncodingUltraZip);
 966    rfbSendSupporteddEncodings_SendEncoding(cl, rfbEncodingXCursor);
 967    rfbSendSupporteddEncodings_SendEncoding(cl, rfbEncodingRichCursor);
 968    rfbSendSupporteddEncodings_SendEncoding(cl, rfbEncodingPointerPos);
 969    rfbSendSupporteddEncodings_SendEncoding(cl, rfbEncodingLastRect);
 970    rfbSendSupporteddEncodings_SendEncoding(cl, rfbEncodingNewFBSize);
 971    rfbSendSupporteddEncodings_SendEncoding(cl, rfbEncodingKeyboardLedState);
 972    rfbSendSupporteddEncodings_SendEncoding(cl, rfbEncodingSupportedMessages);
 973    rfbSendSupporteddEncodings_SendEncoding(cl, rfbEncodingSupportedEncodings);
 974    rfbSendSupporteddEncodings_SendEncoding(cl, rfbEncodingServerIdentity);
 975
 976    rfbStatRecordEncodingSent(cl, rfbEncodingSupportedEncodings,
 977        sz_rfbFramebufferUpdateRectHeader+(nEncodings * sizeof(uint32_t)),
 978        sz_rfbFramebufferUpdateRectHeader+(nEncodings * sizeof(uint32_t)));
 979
 980    if (!rfbSendUpdateBuf(cl))
 981        return FALSE;
 982
 983    return TRUE;
 984}
 985
 986
 987void
 988rfbSetServerVersionIdentity(rfbScreenInfoPtr screen, char *fmt, ...)
 989{
 990    char buffer[256];
 991    va_list ap;
 992    
 993    va_start(ap, fmt);
 994    vsnprintf(buffer, sizeof(buffer)-1, fmt, ap);
 995    va_end(ap);
 996    
 997    if (screen->versionString!=NULL) free(screen->versionString);
 998    screen->versionString = strdup(buffer);
 999}
1000
1001/*
1002 * Send rfbEncodingServerIdentity.
1003 */
1004
1005rfbBool
1006rfbSendServerIdentity(rfbClientPtr cl)
1007{
1008    rfbFramebufferUpdateRectHeader rect;
1009    char buffer[512];
1010
1011    /* tack on our library version */
1012    snprintf(buffer,sizeof(buffer)-1, "%s (%s)", 
1013        (cl->screen->versionString==NULL ? "unknown" : cl->screen->versionString),
1014        LIBVNCSERVER_PACKAGE_STRING);
1015
1016    if (cl->ublen + sz_rfbFramebufferUpdateRectHeader
1017                  + (strlen(buffer)+1) > UPDATE_BUF_SIZE) {
1018        if (!rfbSendUpdateBuf(cl))
1019            return FALSE;
1020    }
1021
1022    rect.encoding = Swap32IfLE(rfbEncodingServerIdentity);
1023    rect.r.x = 0;
1024    rect.r.y = 0;
1025    rect.r.w = Swap16IfLE(strlen(buffer)+1);
1026    rect.r.h = 0;
1027
1028    memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
1029        sz_rfbFramebufferUpdateRectHeader);
1030    cl->ublen += sz_rfbFramebufferUpdateRectHeader;
1031
1032    memcpy(&cl->updateBuf[cl->ublen], buffer, strlen(buffer)+1);
1033    cl->ublen += strlen(buffer)+1;
1034
1035    rfbStatRecordEncodingSent(cl, rfbEncodingServerIdentity,
1036        sz_rfbFramebufferUpdateRectHeader+strlen(buffer)+1,
1037        sz_rfbFramebufferUpdateRectHeader+strlen(buffer)+1);
1038    
1039
1040    if (!rfbSendUpdateBuf(cl))
1041        return FALSE;
1042
1043    return TRUE;
1044}
1045
1046rfbBool rfbSendTextChatMessage(rfbClientPtr cl, uint32_t length, char *buffer)
1047{
1048    rfbTextChatMsg tc;
1049    int bytesToSend=0;
1050
1051    memset((char *)&tc, 0, sizeof(tc)); 
1052    tc.type = rfbTextChat;
1053    tc.length = Swap32IfLE(length);
1054    
1055    switch(length) {
1056    case rfbTextChatOpen:
1057    case rfbTextChatClose:
1058    case rfbTextChatFinished:
1059        bytesToSend=0;
1060        break;
1061    default:
1062        bytesToSend=length;
1063        if (bytesToSend>rfbTextMaxSize)
1064            bytesToSend=rfbTextMaxSize;
1065    }
1066
1067    if (cl->ublen + sz_rfbTextChatMsg + bytesToSend > UPDATE_BUF_SIZE) {
1068        if (!rfbSendUpdateBuf(cl))
1069            return FALSE;
1070    }
1071    
1072    memcpy(&cl->updateBuf[cl->ublen], (char *)&tc, sz_rfbTextChatMsg);
1073    cl->ublen += sz_rfbTextChatMsg;
1074    if (bytesToSend>0) {
1075        memcpy(&cl->updateBuf[cl->ublen], buffer, bytesToSend);
1076        cl->ublen += bytesToSend;    
1077    }
1078    rfbStatRecordMessageSent(cl, rfbTextChat, sz_rfbTextChatMsg+bytesToSend, sz_rfbTextChatMsg+bytesToSend);
1079
1080    if (!rfbSendUpdateBuf(cl))
1081        return FALSE;
1082        
1083    return TRUE;
1084}
1085
1086#define FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN(msg, cl, ret) \
1087	if ((cl->screen->getFileTransferPermission != NULL \
1088	    && cl->screen->getFileTransferPermission(cl) != TRUE) \
1089	    || cl->screen->permitFileTransfer != TRUE) { \
1090		rfbLog("%sUltra File Transfer is disabled, dropping client: %s\n", msg, cl->host); \
1091		rfbCloseClient(cl); \
1092		return ret; \
1093	}
1094
1095int DB = 1;
1096
1097rfbBool rfbSendFileTransferMessage(rfbClientPtr cl, uint8_t contentType, uint8_t contentParam, uint32_t size, uint32_t length, char *buffer)
1098{
1099    rfbFileTransferMsg ft;
1100    ft.type = rfbFileTransfer;
1101    ft.contentType = contentType;
1102    ft.contentParam = contentParam;
1103    ft.pad          = 0; /* UltraVNC did not Swap16LE(ft.contentParam) (Looks like it might be BigEndian) */
1104    ft.size         = Swap32IfLE(size);
1105    ft.length       = Swap32IfLE(length);
1106    
1107    FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN("", cl, FALSE);
1108    /*
1109    rfbLog("rfbSendFileTransferMessage( %dtype, %dparam, %dsize, %dlen, %p)\n", contentType, contentParam, size, length, buffer);
1110    */
1111    if (rfbWriteExact(cl, (char *)&ft, sz_rfbFileTransferMsg) < 0) {
1112        rfbLogPerror("rfbSendFileTransferMessage: write");
1113        rfbCloseClient(cl);
1114        return FALSE;
1115    }
1116
1117    if (length>0)
1118    {
1119        if (rfbWriteExact(cl, buffer, length) < 0) {
1120            rfbLogPerror("rfbSendFileTransferMessage: write");
1121            rfbCloseClient(cl);
1122            return FALSE;
1123        }
1124    }
1125
1126    rfbStatRecordMessageSent(cl, rfbFileTransfer, sz_rfbFileTransferMsg+length, sz_rfbFileTransferMsg+length);
1127
1128    return TRUE;
1129}
1130
1131
1132/*
1133 * UltraVNC uses Windows Structures
1134 */
1135#define MAX_PATH 260
1136
1137typedef struct {
1138    uint32_t dwLowDateTime;
1139    uint32_t dwHighDateTime;
1140} RFB_FILETIME; 
1141
1142typedef struct {
1143    uint32_t dwFileAttributes;
1144    RFB_FILETIME ftCreationTime;
1145    RFB_FILETIME ftLastAccessTime;
1146    RFB_FILETIME ftLastWriteTime;
1147    uint32_t nFileSizeHigh;
1148    uint32_t nFileSizeLow;
1149    uint32_t dwReserved0;
1150    uint32_t dwReserved1;
1151    uint8_t  cFileName[ MAX_PATH ];
1152    uint8_t  cAlternateFileName[ 14 ];
1153} RFB_FIND_DATA;
1154
1155#define RFB_FILE_ATTRIBUTE_READONLY   0x1
1156#define RFB_FILE_ATTRIBUTE_HIDDEN     0x2
1157#define RFB_FILE_ATTRIBUTE_SYSTEM     0x4
1158#define RFB_FILE_ATTRIBUTE_DIRECTORY  0x10
1159#define RFB_FILE_ATTRIBUTE_ARCHIVE    0x20
1160#define RFB_FILE_ATTRIBUTE_NORMAL     0x80
1161#define RFB_FILE_ATTRIBUTE_TEMPORARY  0x100
1162#define RFB_FILE_ATTRIBUTE_COMPRESSED 0x800
1163
1164rfbBool rfbFilenameTranslate2UNIX(rfbClientPtr cl, char *path, char *unixPath)
1165{
1166    int x;
1167    char *home=NULL;
1168
1169    FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN("", cl, FALSE);
1170
1171    /* C: */
1172    if (path[0]=='C' && path[1]==':')
1173      strcpy(unixPath, &path[2]);
1174    else
1175    {
1176      home = getenv("HOME");
1177      if (home!=NULL)
1178      {
1179        strcpy(unixPath, home);
1180        strcat(unixPath,"/");
1181        strcat(unixPath, path);
1182      }
1183      else
1184        strcpy(unixPath, path);
1185    }
1186    for (x=0;x<strlen(unixPath);x++)
1187      if (unixPath[x]=='\\') unixPath[x]='/';
1188    return TRUE;
1189}
1190
1191rfbBool rfbFilenameTranslate2DOS(rfbClientPtr cl, char *unixPath, char *path)
1192{
1193    int x;
1194
1195    FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN("", cl, FALSE);
1196
1197    sprintf(path,"C:%s", unixPath);
1198    for (x=2;x<strlen(path);x++)
1199        if (path[x]=='/') path[x]='\\';
1200    return TRUE;
1201}
1202
1203rfbBool rfbSendDirContent(rfbClientPtr cl, int length, char *buffer)
1204{
1205    char retfilename[MAX_PATH];
1206    char path[MAX_PATH];
1207    struct stat statbuf;
1208    RFB_FIND_DATA win32filename;
1209    int nOptLen = 0, retval=0;
1210    DIR *dirp=NULL;
1211    struct dirent *direntp=NULL;
1212
1213    FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN("", cl, FALSE);
1214
1215    /* Client thinks we are Winblows */
1216    rfbFilenameTranslate2UNIX(cl, buffer, path);
1217
1218    if (DB) rfbLog("rfbProcessFileTransfer() rfbDirContentRequest: rfbRDirContent: \"%s\"->\"%s\"\n",buffer, path);
1219
1220    dirp=opendir(path);
1221    if (dirp==NULL)
1222        return rfbSendFileTransferMessage(cl, rfbDirPacket, rfbADirectory, 0, 0, NULL);
1223    /* send back the path name (necessary for links) */
1224    if (rfbSendFileTransferMessage(cl, rfbDirPacket, rfbADirectory, 0, length, buffer)==FALSE) return FALSE;
1225    for (direntp=readdir(dirp); direntp!=NULL; direntp=readdir(dirp))
1226    {
1227        /* get stats */
1228        snprintf(retfilename,sizeof(retfilename),"%s/%s", path, direntp->d_name);
1229        retval = stat(retfilename, &statbuf);
1230
1231        if (retval==0)
1232        {
1233            memset((char *)&win32filename, 0, sizeof(win32filename));
1234            win32filename.dwFileAttributes = Swap32IfBE(RFB_FILE_ATTRIBUTE_NORMAL);
1235            if (S_ISDIR(statbuf.st_mode))
1236              win32filename.dwFileAttributes = Swap32IfBE(RFB_FILE_ATTRIBUTE_DIRECTORY);
1237            win32filename.ftCreationTime.dwLowDateTime = Swap32IfBE(statbuf.st_ctime);   /* Intel Order */
1238            win32filename.ftCreationTime.dwHighDateTime = 0;
1239            win32filename.ftLastAccessTime.dwLowDateTime = Swap32IfBE(statbuf.st_atime); /* Intel Order */
1240            win32filename.ftLastAccessTime.dwHighDateTime = 0;
1241            win32filename.ftLastWriteTime.dwLowDateTime = Swap32IfBE(statbuf.st_mtime);  /* Intel Order */
1242            win32filename.ftLastWriteTime.dwHighDateTime = 0;
1243            win32filename.nFileSizeLow = Swap32IfBE(statbuf.st_size); /* Intel Order */
1244            win32filename.nFileSizeHigh = 0;
1245            win32filename.dwReserved0 = 0;
1246            win32filename.dwReserved1 = 0;
1247
1248            /* If this had the full path, we would need to translate to DOS format ("C:\") */
1249            /* rfbFilenameTranslate2DOS(cl, retfilename, win32filename.cFileName); */
1250            strcpy((char *)win32filename.cFileName, direntp->d_name);
1251            
1252            /* Do not show hidden files (but show how to move up the tree) */
1253            if ((strcmp(direntp->d_name, "..")==0) || (direntp->d_name[0]!='.'))
1254            {
1255                nOptLen = sizeof(RFB_FIND_DATA) - MAX_PATH - 14 + strlen((char *)win32filename.cFileName);
1256                /*
1257                rfbLog("rfbProcessFileTransfer() rfbDirContentRequest: rfbRDirContent: Sending \"%s\"\n", (char *)win32filename.cFileName);
1258                */
1259                if (rfbSendFileTransferMessage(cl, rfbDirPacket, rfbADirectory, 0, nOptLen, (char *)&win32filename)==FALSE) return FALSE;
1260            }
1261        }
1262    }
1263    closedir(dirp);
1264    /* End of the transfer */
1265    return rfbSendFileTransferMessage(cl, rfbDirPacket, 0, 0, 0, NULL);
1266}
1267
1268
1269char *rfbProcessFileTransferReadBuffer(rfbClientPtr cl, uint32_t length)
1270{
1271    char *buffer=NULL;
1272    int   n=0;
1273
1274    FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN("", cl, NULL);
1275    /*
1276    rfbLog("rfbProcessFileTransferReadBuffer(%dlen)\n", length);
1277    */
1278    if (length>0) {
1279        buffer=malloc(length+1);
1280        if (buffer!=NULL) {
1281            if ((n = rfbReadExact(cl, (char *)buffer, length)) <= 0) {
1282                if (n != 0)
1283                    rfbLogPerror("rfbProcessFileTransferReadBuffer: read");
1284                rfbCloseClient(cl);
1285                /* NOTE: don't forget to free(buffer) if you return early! */
1286                if (buffer!=NULL) free(buffer);
1287                return NULL;
1288            }
1289            /* Null Terminate */
1290            buffer[length]=0;
1291        }
1292    }
1293    return buffer;
1294}
1295
1296
1297rfbBool rfbSendFileTransferChunk(rfbClientPtr cl)
1298{
1299    /* Allocate buffer for compression */
1300    unsigned char readBuf[sz_rfbBlockSize];
1301    int bytesRead=0;
1302    int retval=0;
1303    fd_set wfds;
1304    struct timeval tv;
1305    int n;
1306#ifdef LIBVNCSERVER_HAVE_LIBZ
1307    unsigned char compBuf[sz_rfbBlockSize + 1024];
1308    unsigned long nMaxCompSize = sizeof(compBuf);
1309    int nRetC = 0;
1310#endif
1311
1312    /*
1313     * Don't close the client if we get into this one because 
1314     * it is called from many places to service file transfers.
1315     * Note that permitFileTransfer is checked first.
1316     */
1317    if (cl->screen->permitFileTransfer != TRUE ||
1318       (cl->screen->getFileTransferPermission != NULL
1319        && cl->screen->getFileTransferPermission(cl) != TRUE)) { 
1320		return TRUE;
1321    }
1322
1323    /* If not sending, or no file open...   Return as if we sent something! */
1324    if ((cl->fileTransfer.fd!=-1) && (cl->fileTransfer.sending==1))
1325    {
1326	FD_ZERO(&wfds);
1327        FD_SET(cl->sock, &wfds);
1328
1329        /* return immediately */
1330	tv.tv_sec = 0; 
1331	tv.tv_usec = 0;
1332	n = select(cl->sock + 1, NULL, &wfds, NULL, &tv);
1333
1334	if (n<0) {
1335            rfbLog("rfbSendFileTransferChunk() select failed: %s\n", strerror(errno));
1336	}
1337        /* We have space on the transmit queue */
1338	if (n > 0)
1339	{
1340            bytesRead = read(cl->fileTransfer.fd, readBuf, sz_rfbBlockSize);
1341            switch (bytesRead) {
1342            case 0:
1343                /*
1344                rfbLog("rfbSendFileTransferChunk(): End-Of-File Encountered\n");
1345                */
1346                retval = rfbSendFileTransferMessage(cl, rfbEndOfFile, 0, 0, 0, NULL);
1347                close(cl->fileTransfer.fd);
1348                cl->fileTransfer.fd = -1;
1349                cl->fileTransfer.sending   = 0;
1350                cl->fileTransfer.receiving = 0;
1351                return retval;
1352            case -1:
1353                /* TODO : send an error msg to the client... */
1354                rfbLog("rfbSendFileTransferChunk(): %s\n",strerror(errno));
1355                retval = rfbSendFileTransferMessage(cl, rfbAbortFileTransfer, 0, 0, 0, NULL);
1356                close(cl->fileTransfer.fd);
1357                cl->fileTransfer.fd = -1;
1358                cl->fileTransfer.sending   = 0;
1359                cl->fileTransfer.receiving = 0;
1360                return retval;
1361            default:
1362                /*
1363                rfbLog("rfbSendFileTransferChunk(): Read %d bytes\n", bytesRead);
1364                */
1365                if (!cl->fileTransfer.compressionEnabled)
1366                    return  rfbSendFileTransferMessage(cl, rfbFilePacket, 0, 0, bytesRead, (char *)readBuf);
1367                else
1368                {
1369#ifdef LIBVNCSERVER_HAVE_LIBZ
1370                    nRetC = compress(compBuf, &nMaxCompSize, readBuf, bytesRead);
1371                    /*
1372                    rfbLog("Compressed the packet from %d -> %d bytes\n", nMaxCompSize, bytesRead);
1373                    */
1374                    
1375                    if ((nRetC==0) && (nMaxCompSize<bytesRead))
1376                        return  rfbSendFileTransferMessage(cl, rfbFilePacket, 0, 1, nMaxCompSize, (char *)compBuf);
1377                    else
1378                        return  rfbSendFileTransferMessage(cl, rfbFilePacket, 0, 0, bytesRead, (char *)readBuf);
1379#else
1380                    /* We do not support compression of the data stream */
1381                    return  rfbSendFileTransferMessage(cl, rfbFilePacket, 0, 0, bytesRead, (char *)readBuf);
1382#endif
1383                }
1384            }
1385        }
1386    }
1387    return TRUE;
1388}
1389
1390rfbBool rfbProcessFileTransfer(rfbClientPtr cl, uint8_t contentType, uint8_t contentParam, uint32_t size, uint32_t length)
1391{
1392    char *buffer=NULL, *p=NULL;
1393    int retval=0;
1394    char filename1[MAX_PATH];
1395    char filename2[MAX_PATH];
1396    char szFileTime[MAX_PATH];
1397    struct stat statbuf;
1398    uint32_t sizeHtmp=0;
1399    int n=0;
1400    char timespec[64];
1401#ifdef LIBVNCSERVER_HAVE_LIBZ
1402    unsigned char compBuff[sz_rfbBlockSize];
1403    unsigned long nRawBytes = sz_rfbBlockSize;
1404    int nRet = 0;
1405#endif
1406
1407    FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN("", cl, FALSE);
1408        
1409    /*
1410    rfbLog("rfbProcessFileTransfer(%dtype, %dparam, %dsize, %dlen)\n", contentType, contentParam, size, length);
1411    */
1412
1413    switch (contentType) {
1414    case rfbDirContentRequest:
1415        switch (contentParam) {
1416        case rfbRDrivesList: /* Client requests the List of Local Drives */
1417            /*
1418            rfbLog("rfbProcessFileTransfer() rfbDirContentRequest: rfbRDrivesList:\n");
1419            */
1420            /* Format when filled : "C:\<NULL>D:\<NULL>....Z:\<NULL><NULL>
1421             *
1422             * We replace the "\" char following the drive letter and ":"
1423             * with a char corresponding to the type of drive
1424             * We obtain something like "C:l<NULL>D:c<NULL>....Z:n\<NULL><NULL>"
1425             *  Isn't it ugly ?
1426             * DRIVE_FIXED = 'l'     (local?)
1427             * DRIVE_REMOVABLE = 'f' (floppy?)
1428             * DRIVE_CDROM = 'c'
1429             * DRIVE_REMOTE = 'n'
1430             */
1431            
1432            /* in unix, there are no 'drives'  (We could list mount points though)
1433             * We fake the root as a "C:" for the Winblows users
1434             */
1435            filename2[0]='C';
1436            filename2[1]=':';
1437            filename2[2]='l';
1438            filename2[3]=0;
1439            filename2[4]=0;
1440            retval = rfbSendFileTransferMessage(cl, rfbDirPacket, rfbADrivesList, 0, 5, filename2);
1441            if (buffer!=NULL) free(buffer);
1442            return retval;
1443            break;
1444        case rfbRDirContent: /* Client requests the content of a directory */
1445            /*
1446            rfbLog("rfbProcessFileTransfer() rfbDirContentRequest: rfbRDirContent\n");
1447            */
1448            if ((buffer = rfbProcessFileTransferReadBuffer(cl, length))==NULL) return FALSE;
1449            retval = rfbSendDirContent(cl, length, buffer);
1450            if (buffer!=NULL) free(buffer);
1451            return retval;
1452        }
1453        break;
1454
1455    case rfbDirPacket:
1456        rfbLog("rfbProcessFileTransfer() rfbDirPacket\n");
1457        break;
1458    case rfbFileAcceptHeader:
1459        rfbLog("rfbProcessFileTransfer() rfbFileAcceptHeader\n");
1460        break;
1461    case rfbCommandReturn:
1462        rfbLog("rfbProcessFileTransfer() rfbCommandReturn\n");
1463        break;
1464    case rfbFileChecksums:
1465        /* Destination file already exists - the viewer sends the checksums */
1466        rfbLog("rfbProcessFileTransfer() rfbFileChecksums\n");
1467        break;
1468    case rfbFileTransferAccess:
1469        rfbLog("rfbProcessFileTransfer() rfbFileTransferAccess\n");
1470        break;
1471
1472    /*
1473     * sending from the server to the viewer
1474     */
1475
1476    case rfbFileTransferRequest:
1477        /*
1478        rfbLog("rfbProcessFileTransfer() rfbFileTransferRequest:\n");
1479        */
1480        /* add some space to the end of the buffer as we will be adding a timespec to it */
1481        if ((buffer = rfbProcessFileTransferReadBuffer(cl, length))==NULL) return FALSE;
1482        /* The client requests a File */
1483        rfbFilenameTranslate2UNIX(cl, buffer, filename1);
1484        cl->fileTransfer.fd=open(filename1, O_RDONLY, 0744);
1485
1486        /*
1487        */
1488        if (DB) rfbLog("rfbProcessFileTransfer() rfbFileTransferRequest(\"%s\"->\"%s\") Open: %s fd=%d\n", buffer, filename1, (cl->fileTransfer.fd==-1?"Failed":"Success"), cl->fileTransfer.fd);
1489        
1490        if (cl->fileTransfer.fd!=-1) {
1491            if (fstat(cl->fileTransfer.fd, &statbuf)!=0) {
1492                close(cl->fileTransfer.fd);
1493                cl->fileTransfer.fd=-1;
1494            }
1495            else
1496            {
1497              /* Add the File Time Stamp to the filename */
1498              strftime(timespec, sizeof(timespec), "%m/%d/%Y %H:%M",gmtime(&statbuf.st_ctime));
1499              buffer=realloc(buffer, length + strlen(timespec) + 2); /* comma, and Null term */
1500              if (buffer==NULL) {
1501                  rfbLog("rfbProcessFileTransfer() rfbFileTransferRequest: Failed to malloc %d bytes\n", length + strlen(timespec) + 2);
1502                  return FALSE;
1503              }
1504              strcat(buffer,",");
1505              strcat(buffer, timespec);
1506              length = strlen(buffer);
1507              if (DB) rfbLog("rfbProcessFileTransfer() buffer is now: \"%s\"\n", buffer);
1508            }
1509        }
1510
1511        /* The viewer supports compression if size==1 */
1512        cl->fileTransfer.compressionEnabled = (size==1);
1513
1514        /*
1515        rfbLog("rfbProcessFileTransfer() rfbFileTransferRequest(\"%s\"->\"%s\")%s\n", buffer, filename1, (size==1?" <Compression Enabled>":""));
1516        */
1517
1518        /* File Size in bytes, 0xFFFFFFFF (-1) means error */
1519        retval = rfbSendFileTransferMessage(cl, rfbFileHeader, 0, (cl->fileTransfer.fd==-1 ? -1 : statbuf.st_size), length, buffer);
1520
1521        if (cl->fileTransfer.fd==-1)
1522        {
1523            if (buffer!=NULL) free(buffer);
1524            return retval;
1525        }
1526        /* setup filetransfer stuff */
1527        cl->fileTransfer.fileSize = statbuf.st_size;
1528        cl->fileTransfer.numPackets = statbuf.st_size / sz_rfbBlockSize;
1529        cl->fileTransfer.receiving = 0;
1530        cl->fileTransfer.sending = 0; /* set when we receive a rfbFileHeader: */
1531
1532        /* TODO: finish 64-bit file size support */
1533        sizeHtmp = 0;        
1534        if (rfbWriteExact(cl, (char *)&sizeHtmp, 4) < 0) {
1535          rfbLogPerror("rfbProcessFileTransfer: write");
1536          rfbCloseClient(cl);
1537          if (buffer!=NULL) free(buffer);
1538          return FALSE;
1539        }
1540        break;
1541
1542    case rfbFileHeader:
1543        /* Destination file (viewer side) is ready for reception (size > 0) or not (size = -1) */
1544        if (size==-1) {
1545            rfbLog("rfbProcessFileTransfer() rfbFileHeader (error, aborting)\n");
1546            close(cl->fileTransfer.fd);
1547            cl->fileTransfer.fd=-1;
1548            return TRUE;
1549        }
1550
1551        /*
1552        rfbLog("rfbProcessFileTransfer() rfbFileHeader (%d bytes of a file)\n", size);
1553        */
1554
1555        /* Starts the transfer! */
1556        cl->fileTransfer.sending=1;
1557        return rfbSendFileTransferChunk(cl);
1558        break;
1559
1560
1561    /*
1562     * sending from the viewer to the server
1563     */
1564
1565    case rfbFileTransferOffer:
1566        /* client is sending a file to us */
1567        /* buffer contains full path name (plus FileTime) */
1568        /* size contains size of the file */
1569        /*
1570        rfbLog("rfbProcessFileTransfer() rfbFileTransferOffer:\n");
1571        */
1572        if ((buffer = rfbProcessFileTransferReadBuffer(cl, length))==NULL) return FALSE;
1573
1574        /* Parse the FileTime */
1575        p = strrchr(buffer, ',');
1576        if (p!=NULL) {
1577            *p = '\0';
1578            strcpy(szFileTime, p+1);
1579        } else
1580            szFileTime[0]=0;
1581
1582
1583
1584        /* Need to read in sizeHtmp */
1585        if ((n = rfbReadExact(cl, (char *)&sizeHtmp, 4)) <= 0) {
1586            if (n != 0)
1587                rfbLogPerror("rfbProcessFileTransfer: read sizeHtmp");
1588            rfbCloseClient(cl);
1589            /* NOTE: don't forget to free(buffer) if you return early! */
1590            if (buffer!=NULL) free(buffer);
1591            return FALSE;
1592        }
1593        sizeHtmp = Swap32IfLE(sizeHtmp);
1594        
1595        rfbFilenameTranslate2UNIX(cl, buffer, filename1);
1596
1597        /* If the file exists... We can send a rfbFileChecksums back to the client before we send an rfbFileAcceptHeader */
1598        /* TODO: Delta Transfer */
1599
1600        cl->fileTransfer.fd=open(filename1, O_CREAT|O_WRONLY|O_TRUNC, 0744);
1601        if (DB) rfbLog("rfbProcessFileTransfer() rfbFileTransferOffer(\"%s\"->\"%s\") %s %s fd=%d\n", buffer, filename1, (cl->fileTransfer.fd==-1?"Failed":"Success"), (cl->fileTransfer.fd==-1?strerror(errno):""), cl->fileTransfer.fd);
1602        /*
1603        */
1604        
1605        /* File Size in bytes, 0xFFFFFFFF (-1) means error */
1606        retval = rfbSendFileTransferMessage(cl, rfbFileAcceptHeader, 0, (cl->fileTransfer.fd==-1 ? -1 : 0), length, buffer);
1607        if (cl->fileTransfer.fd==-1) {
1608            free(buffer);
1609            return retval;
1610        }
1611        
1612        /* setup filetransfer stuff */
1613        cl->fileTransfer.fileSize = size;
1614        cl->fileTransfer.numPackets = size / sz_rfbBlockSize;
1615        cl->fileTransfer.receiving = 1;
1616        cl->fileTransfer.sending = 0;
1617        break;
1618
1619    case rfbFilePacket:
1620        /*
1621        rfbLog("rfbProcessFileTransfer() rfbFilePacket:\n");
1622        */
1623        if ((buffer = rfbProcessFileTransferReadBuffer(cl, length))==NULL) return FALSE;
1624        if (cl->fileTransfer.fd!=-1) {
1625            /* buffer contains the contents of the file */
1626            if (size==0)
1627                retval=write(cl->fileTransfer.fd, buffer, length);
1628            else
1629            {
1630#ifdef LIBVNCSERVER_HAVE_LIBZ
1631                /* compressed packet */
1632                nRet = uncompress(compBuff,&nRawBytes,(const unsigned char*)buffer, length);
1633                retval=write(cl->fileTransfer.fd, compBuff, nRawBytes);
1634#else
1635                /* Write the file out as received... */
1636                retval=write(cl->fileTransfer.fd, buffer, length);
1637#endif
1638            }
1639            if (retval==-1)
1640            {
1641                close(cl->fileTransfer.fd);
1642                cl->fileTransfer.fd=-1;
1643                cl->fileTransfer.sending   = 0;
1644                cl->fileTransfer.receiving = 0;
1645            }
1646        }
1647        break;
1648
1649    case rfbEndOfFile:
1650        if (DB) rfbLog("rfbProcessFileTransfer() rfbEndOfFile\n");
1651        /*
1652        */
1653        if (cl->fileTransfer.fd!=-1)
1654            close(cl->fileTransfer.fd);
1655        cl->fileTransfer.fd=-1;
1656        cl->fileTransfer.sending   = 0;
1657        cl->fileTransfer.receiving = 0;
1658        break;
1659
1660    case rfbAbortFileTransfer:
1661        if (DB) rfbLog("rfbProcessFileTransfer() rfbAbortFileTransfer\n");
1662        /*
1663        */
1664        if (cl->fileTransfer.fd!=-1)
1665        

Large files files are truncated, but you can click here to view the full file