1/*
2 *  This file is called main.c, because it contains most of the new functions
3 *  for use with LibVNCServer.
4 *
5 *  LibVNCServer (C) 2001 Johannes E. Schindelin <Johannes.Schindelin@gmx.de>
6 *  Original OSXvnc (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
7 *  Original Xvnc (C) 1999 AT&T Laboratories Cambridge.
8 *  All Rights Reserved.
9 *
10 *  see GPL (latest version) for full details
11 */
12
13#ifdef __STRICT_ANSI__
14#define _BSD_SOURCE
15#endif
16#include <rfb/rfb.h>
17#include <rfb/rfbregion.h>
18#include "private.h"
19
20#include <stdarg.h>
21#include <errno.h>
22
23#ifndef false
24#define false 0
25#define true -1
26#endif
27
28#ifdef LIBVNCSERVER_HAVE_SYS_TYPES_H
29#include <sys/types.h>
30#endif
31
32#ifndef WIN32
33#include <sys/socket.h>
34#include <netinet/in.h>
35#include <unistd.h>
36#endif
37
38#include <signal.h>
39#include <time.h>
40
41static int extMutex_initialized = 0;
42static int logMutex_initialized = 0;
43#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
44static MUTEX(logMutex);
45static MUTEX(extMutex);
46#endif
47
48static int rfbEnableLogging=1;
49
50#ifdef LIBVNCSERVER_WORDS_BIGENDIAN
51char rfbEndianTest = (1==0);
52#else
53char rfbEndianTest = (1==1);
54#endif
55
56/*
57 * Protocol extensions
58 */
59
60static rfbProtocolExtension* rfbExtensionHead = NULL;
61
62/*
63 * This method registers a list of new extensions.
64 * It avoids same extension getting registered multiple times.
65 * The order is not preserved if multiple extensions are
66 * registered at one-go.
67 */
68void
69rfbRegisterProtocolExtension(rfbProtocolExtension* extension)
70{
71	rfbProtocolExtension *head = rfbExtensionHead, *next = NULL;
72
73	if(extension == NULL)
74		return;
75
76	next = extension->next;
77
78	if (! extMutex_initialized) {
79		INIT_MUTEX(extMutex);
80		extMutex_initialized = 1;
81	}
82
83	LOCK(extMutex);
84
85	while(head != NULL) {
86		if(head == extension) {
87			UNLOCK(extMutex);
88			rfbRegisterProtocolExtension(next);
89			return;
90		}
91
92		head = head->next;
93	}
94
95	extension->next = rfbExtensionHead;
96	rfbExtensionHead = extension;
97
98	UNLOCK(extMutex);
99	rfbRegisterProtocolExtension(next);
100}
101
102/*
103 * This method unregisters a list of extensions.
104 * These extensions won't be available for any new
105 * client connection.
106 */
107void
108rfbUnregisterProtocolExtension(rfbProtocolExtension* extension)
109{
110
111	rfbProtocolExtension *cur = NULL, *pre = NULL;
112
113	if(extension == NULL)
114		return;
115
116	if (! extMutex_initialized) {
117		INIT_MUTEX(extMutex);
118		extMutex_initialized = 1;
119	}
120
121	LOCK(extMutex);
122
123	if(rfbExtensionHead == extension) {
124		rfbExtensionHead = rfbExtensionHead->next;
125		UNLOCK(extMutex);
126		rfbUnregisterProtocolExtension(extension->next);
127		return;
128	}
129
130	cur = pre = rfbExtensionHead;
131
132	while(cur) {
133		if(cur == extension) {
134			pre->next = cur->next;
135			break;
136		}
137		pre = cur;
138		cur = cur->next;
139	}
140
141	UNLOCK(extMutex);
142
143	rfbUnregisterProtocolExtension(extension->next);
144}
145
146rfbProtocolExtension* rfbGetExtensionIterator()
147{
148	if (! extMutex_initialized) {
149		INIT_MUTEX(extMutex);
150		extMutex_initialized = 1;
151	}
152
153	LOCK(extMutex);
154	return rfbExtensionHead;
155}
156
157void rfbReleaseExtensionIterator()
158{
159	UNLOCK(extMutex);
160}
161
162rfbBool rfbEnableExtension(rfbClientPtr cl, rfbProtocolExtension* extension,
163	void* data)
164{
165	rfbExtensionData* extData;
166
167	/* make sure extension is not yet enabled. */
168	for(extData = cl->extensions; extData; extData = extData->next)
169		if(extData->extension == extension)
170			return FALSE;
171
172	extData = calloc(sizeof(rfbExtensionData),1);
173	extData->extension = extension;
174	extData->data = data;
175	extData->next = cl->extensions;
176	cl->extensions = extData;
177
178	return TRUE;
179}
180
181rfbBool rfbDisableExtension(rfbClientPtr cl, rfbProtocolExtension* extension)
182{
183	rfbExtensionData* extData;
184	rfbExtensionData* prevData = NULL;
185
186	for(extData = cl->extensions; extData; extData = extData->next) {
187		if(extData->extension == extension) {
188			if(extData->data)
189				free(extData->data);
190			if(prevData == NULL)
191				cl->extensions = extData->next;
192			else
193				prevData->next = extData->next;
194			return TRUE;
195		}
196		prevData = extData;
197	}
198
199	return FALSE;
200}
201
202void* rfbGetExtensionClientData(rfbClientPtr cl, rfbProtocolExtension* extension)
203{
204    rfbExtensionData* data = cl->extensions;
205
206    while(data && data->extension != extension)
207	data = data->next;
208
209    if(data == NULL) {
210	rfbLog("Extension is not enabled !\n");
211	/* rfbCloseClient(cl); */
212	return NULL;
213    }
214
215    return data->data;
216}
217
218/*
219 * Logging
220 */
221
222void rfbLogEnable(int enabled) {
223  rfbEnableLogging=enabled;
224}
225
226/*
227 * rfbLog prints a time-stamped message to the log file (stderr).
228 */
229
230static void
231rfbDefaultLog(const char *format, ...)
232{
233    va_list args;
234    char buf[256];
235    time_t log_clock;
236
237    if(!rfbEnableLogging)
238      return;
239
240    if (! logMutex_initialized) {
241      INIT_MUTEX(logMutex);
242      logMutex_initialized = 1;
243    }
244
245    LOCK(logMutex);
246    va_start(args, format);
247
248    time(&log_clock);
249    strftime(buf, 255, "%d/%m/%Y %X ", localtime(&log_clock));
250    fprintf(stderr, "%s", buf);
251
252    vfprintf(stderr, format, args);
253    fflush(stderr);
254
255    va_end(args);
256    UNLOCK(logMutex);
257}
258
259rfbLogProc rfbLog=rfbDefaultLog;
260rfbLogProc rfbErr=rfbDefaultLog;
261
262void rfbLogPerror(const char *str)
263{
264    rfbErr("%s: %s\n", str, strerror(errno));
265}
266
267void rfbScheduleCopyRegion(rfbScreenInfoPtr rfbScreen,sraRegionPtr copyRegion,int dx,int dy)
268{
269   rfbClientIteratorPtr iterator;
270   rfbClientPtr cl;
271
272   iterator=rfbGetClientIterator(rfbScreen);
273   while((cl=rfbClientIteratorNext(iterator))) {
274     LOCK(cl->updateMutex);
275     if(cl->useCopyRect) {
276       sraRegionPtr modifiedRegionBackup;
277       if(!sraRgnEmpty(cl->copyRegion)) {
278	  if(cl->copyDX!=dx || cl->copyDY!=dy) {
279	     /* if a copyRegion was not yet executed, treat it as a
280	      * modifiedRegion. The idea: in this case it could be
281	      * source of the new copyRect or modified anyway. */
282	     sraRgnOr(cl->modifiedRegion,cl->copyRegion);
283	     sraRgnMakeEmpty(cl->copyRegion);
284	  } else {
285	     /* we have to set the intersection of the source of the copy
286	      * and the old copy to modified. */
287	     modifiedRegionBackup=sraRgnCreateRgn(copyRegion);
288	     sraRgnOffset(modifiedRegionBackup,-dx,-dy);
289	     sraRgnAnd(modifiedRegionBackup,cl->copyRegion);
290	     sraRgnOr(cl->modifiedRegion,modifiedRegionBackup);
291	     sraRgnDestroy(modifiedRegionBackup);
292	  }
293       }
294
295       sraRgnOr(cl->copyRegion,copyRegion);
296       cl->copyDX = dx;
297       cl->copyDY = dy;
298
299       /* if there were modified regions, which are now copied,
300	* mark them as modified, because the source of these can be overlapped
301	* either by new modified or now copied regions. */
302       modifiedRegionBackup=sraRgnCreateRgn(cl->modifiedRegion);
303       sraRgnOffset(modifiedRegionBackup,dx,dy);
304       sraRgnAnd(modifiedRegionBackup,cl->copyRegion);
305       sraRgnOr(cl->modifiedRegion,modifiedRegionBackup);
306       sraRgnDestroy(modifiedRegionBackup);
307
308       if(!cl->enableCursorShapeUpdates) {
309          /*
310           * n.b. (dx, dy) is the vector pointing in the direction the
311           * copyrect displacement will take place.  copyRegion is the
312           * destination rectangle (say), not the source rectangle.
313           */
314          sraRegionPtr cursorRegion;
315          int x = cl->cursorX - cl->screen->cursor->xhot;
316          int y = cl->cursorY - cl->screen->cursor->yhot;
317          int w = cl->screen->cursor->width;
318          int h = cl->screen->cursor->height;
319
320          cursorRegion = sraRgnCreateRect(x, y, x + w, y + h);
321          sraRgnAnd(cursorRegion, cl->copyRegion);
322          if(!sraRgnEmpty(cursorRegion)) {
323             /*
324              * current cursor rect overlaps with the copy region *dest*,
325              * mark it as modified since we won't copy-rect stuff to it.
326              */
327             sraRgnOr(cl->modifiedRegion, cursorRegion);
328          }
329          sraRgnDestroy(cursorRegion);
330
331          cursorRegion = sraRgnCreateRect(x, y, x + w, y + h);
332          /* displace it to check for overlap with copy region source: */
333          sraRgnOffset(cursorRegion, dx, dy);
334          sraRgnAnd(cursorRegion, cl->copyRegion);
335          if(!sraRgnEmpty(cursorRegion)) {
336             /*
337              * current cursor rect overlaps with the copy region *source*,
338              * mark the *displaced* cursorRegion as modified since we
339              * won't copyrect stuff to it.
340              */
341             sraRgnOr(cl->modifiedRegion, cursorRegion);
342          }
343          sraRgnDestroy(cursorRegion);
344       }
345
346     } else {
347       sraRgnOr(cl->modifiedRegion,copyRegion);
348     }
349     TSIGNAL(cl->updateCond);
350     UNLOCK(cl->updateMutex);
351   }
352
353   rfbReleaseClientIterator(iterator);
354}
355
356void rfbDoCopyRegion(rfbScreenInfoPtr screen,sraRegionPtr copyRegion,int dx,int dy)
357{
358   sraRectangleIterator* i;
359   sraRect rect;
360   int j,widthInBytes,bpp=screen->serverFormat.bitsPerPixel/8,
361    rowstride=screen->paddedWidthInBytes;
362   char *in,*out;
363
364   /* copy it, really */
365   i = sraRgnGetReverseIterator(copyRegion,dx<0,dy<0);
366   while(sraRgnIteratorNext(i,&rect)) {
367     widthInBytes = (rect.x2-rect.x1)*bpp;
368     out = screen->frameBuffer+rect.x1*bpp+rect.y1*rowstride;
369     in = screen->frameBuffer+(rect.x1-dx)*bpp+(rect.y1-dy)*rowstride;
370     if(dy<0)
371       for(j=rect.y1;j<rect.y2;j++,out+=rowstride,in+=rowstride)
372	 memmove(out,in,widthInBytes);
373     else {
374       out += rowstride*(rect.y2-rect.y1-1);
375       in += rowstride*(rect.y2-rect.y1-1);
376       for(j=rect.y2-1;j>=rect.y1;j--,out-=rowstride,in-=rowstride)
377	 memmove(out,in,widthInBytes);
378     }
379   }
380   sraRgnReleaseIterator(i);
381
382   rfbScheduleCopyRegion(screen,copyRegion,dx,dy);
383}
384
385void rfbDoCopyRect(rfbScreenInfoPtr screen,int x1,int y1,int x2,int y2,int dx,int dy)
386{
387  sraRegionPtr region = sraRgnCreateRect(x1,y1,x2,y2);
388  rfbDoCopyRegion(screen,region,dx,dy);
389  sraRgnDestroy(region);
390}
391
392void rfbScheduleCopyRect(rfbScreenInfoPtr screen,int x1,int y1,int x2,int y2,int dx,int dy)
393{
394  sraRegionPtr region = sraRgnCreateRect(x1,y1,x2,y2);
395  rfbScheduleCopyRegion(screen,region,dx,dy);
396  sraRgnDestroy(region);
397}
398
399void rfbMarkRegionAsModified(rfbScreenInfoPtr screen,sraRegionPtr modRegion)
400{
401   rfbClientIteratorPtr iterator;
402   rfbClientPtr cl;
403
404   iterator=rfbGetClientIterator(screen);
405   while((cl=rfbClientIteratorNext(iterator))) {
406     LOCK(cl->updateMutex);
407     sraRgnOr(cl->modifiedRegion,modRegion);
408     TSIGNAL(cl->updateCond);
409     UNLOCK(cl->updateMutex);
410   }
411
412   rfbReleaseClientIterator(iterator);
413}
414
415void rfbScaledScreenUpdate(rfbScreenInfoPtr screen, int x1, int y1, int x2, int y2);
416void rfbMarkRectAsModified(rfbScreenInfoPtr screen,int x1,int y1,int x2,int y2)
417{
418   sraRegionPtr region;
419   int i;
420
421   if(x1>x2) { i=x1; x1=x2; x2=i; }
422   if(x1<0) x1=0;
423   if(x2>screen->width) x2=screen->width;
424   if(x1==x2) return;
425
426   if(y1>y2) { i=y1; y1=y2; y2=i; }
427   if(y1<0) y1=0;
428   if(y2>screen->height) y2=screen->height;
429   if(y1==y2) return;
430
431   /* update scaled copies for this rectangle */
432   rfbScaledScreenUpdate(screen,x1,y1,x2,y2);
433
434   region = sraRgnCreateRect(x1,y1,x2,y2);
435   rfbMarkRegionAsModified(screen,region);
436   sraRgnDestroy(region);
437}
438
439#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
440#include <unistd.h>
441
442static void *
443clientOutput(void *data)
444{
445    rfbClientPtr cl = (rfbClientPtr)data;
446    rfbBool haveUpdate;
447    sraRegion* updateRegion;
448
449    while (1) {
450        haveUpdate = false;
451        while (!haveUpdate) {
452		if (cl->sock == -1) {
453			/* Client has disconnected. */
454			return NULL;
455		}
456		if (cl->state != RFB_NORMAL || cl->onHold) {
457			/* just sleep until things get normal */
458			usleep(cl->screen->deferUpdateTime * 1000);
459			continue;
460		}
461
462		LOCK(cl->updateMutex);
463
464		if (sraRgnEmpty(cl->requestedRegion)) {
465			; /* always require a FB Update Request (otherwise can crash.) */
466		} else {
467			haveUpdate = FB_UPDATE_PENDING(cl);
468			if(!haveUpdate) {
469				updateRegion = sraRgnCreateRgn(cl->modifiedRegion);
470				haveUpdate   = sraRgnAnd(updateRegion,cl->requestedRegion);
471				sraRgnDestroy(updateRegion);
472			}
473		}
474
475		if (!haveUpdate) {
476			WAIT(cl->updateCond, cl->updateMutex);
477		}
478
479		UNLOCK(cl->updateMutex);
480        }
481
482        /* OK, now, to save bandwidth, wait a little while for more
483           updates to come along. */
484        usleep(cl->screen->deferUpdateTime * 1000);
485
486        /* Now, get the region we're going to update, and remove
487           it from cl->modifiedRegion _before_ we send the update.
488           That way, if anything that overlaps the region we're sending
489           is updated, we'll be sure to do another update later. */
490        LOCK(cl->updateMutex);
491	updateRegion = sraRgnCreateRgn(cl->modifiedRegion);
492        UNLOCK(cl->updateMutex);
493
494        /* Now actually send the update. */
495	rfbIncrClientRef(cl);
496        LOCK(cl->sendMutex);
497        rfbSendFramebufferUpdate(cl, updateRegion);
498        UNLOCK(cl->sendMutex);
499	rfbDecrClientRef(cl);
500
501	sraRgnDestroy(updateRegion);
502    }
503
504    /* Not reached. */
505    return NULL;
506}
507
508static void *
509clientInput(void *data)
510{
511    rfbClientPtr cl = (rfbClientPtr)data;
512    pthread_t output_thread;
513    pthread_create(&output_thread, NULL, clientOutput, (void *)cl);
514
515    while (1) {
516	fd_set rfds, wfds, efds;
517	struct timeval tv;
518	int n;
519
520	if (cl->sock == -1) {
521	  /* Client has disconnected. */
522            break;
523        }
524
525	FD_ZERO(&rfds);
526	FD_SET(cl->sock, &rfds);
527	FD_ZERO(&efds);
528	FD_SET(cl->sock, &efds);
529
530	/* Are we transferring a file in the background? */
531	FD_ZERO(&wfds);
532	if ((cl->fileTransfer.fd!=-1) && (cl->fileTransfer.sending==1))
533	    FD_SET(cl->sock, &wfds);
534
535	tv.tv_sec = 60; /* 1 minute */
536	tv.tv_usec = 0;
537	n = select(cl->sock + 1, &rfds, &wfds, &efds, &tv);
538	if (n < 0) {
539	    rfbLogPerror("ReadExact: select");
540	    break;
541	}
542	if (n == 0) /* timeout */
543	{
544            rfbSendFileTransferChunk(cl);
545	    continue;
546        }
547
548        /* We have some space on the transmit queue, send some data */
549        if (FD_ISSET(cl->sock, &wfds))
550            rfbSendFileTransferChunk(cl);
551
552        if (FD_ISSET(cl->sock, &rfds) || FD_ISSET(cl->sock, &efds))
553            rfbProcessClientMessage(cl);
554    }
555
556    /* Get rid of the output thread. */
557    LOCK(cl->updateMutex);
558    TSIGNAL(cl->updateCond);
559    UNLOCK(cl->updateMutex);
560    IF_PTHREADS(pthread_join(output_thread, NULL));
561
562    rfbClientConnectionGone(cl);
563
564    return NULL;
565}
566
567static void*
568listenerRun(void *data)
569{
570    rfbScreenInfoPtr screen=(rfbScreenInfoPtr)data;
571    int client_fd;
572    struct sockaddr_storage peer;
573    rfbClientPtr cl = NULL;
574    socklen_t len;
575    fd_set listen_fds;  /* temp file descriptor list for select() */
576
577    /* TODO: this thread wont die by restarting the server */
578    /* TODO: HTTP is not handled */
579    while (1) {
580        client_fd = -1;
581        FD_ZERO(&listen_fds);
582	if(screen->listenSock >= 0)
583	  FD_SET(screen->listenSock, &listen_fds);
584	if(screen->listen6Sock >= 0)
585	  FD_SET(screen->listen6Sock, &listen_fds);
586
587        if (select(screen->maxFd+1, &listen_fds, NULL, NULL, NULL) == -1) {
588            rfbLogPerror("listenerRun: error in select");
589            return NULL;
590        }
591
592	/* there is something on the listening sockets, handle new connections */
593	len = sizeof (peer);
594	if (FD_ISSET(screen->listenSock, &listen_fds))
595	    client_fd = accept(screen->listenSock, (struct sockaddr*)&peer, &len);
596	else if (FD_ISSET(screen->listen6Sock, &listen_fds))
597	    client_fd = accept(screen->listen6Sock, (struct sockaddr*)&peer, &len);
598
599	if(client_fd >= 0)
600	  cl = rfbNewClient(screen,client_fd);
601	if (cl && !cl->onHold )
602	  rfbStartOnHoldClient(cl);
603    }
604    return(NULL);
605}
606
607void
608rfbStartOnHoldClient(rfbClientPtr cl)
609{
610    pthread_create(&cl->client_thread, NULL, clientInput, (void *)cl);
611}
612
613#else
614
615void
616rfbStartOnHoldClient(rfbClientPtr cl)
617{
618	cl->onHold = FALSE;
619}
620
621#endif
622
623void
624rfbRefuseOnHoldClient(rfbClientPtr cl)
625{
626    rfbCloseClient(cl);
627    rfbClientConnectionGone(cl);
628}
629
630static void
631rfbDefaultKbdAddEvent(rfbBool down, rfbKeySym keySym, rfbClientPtr cl)
632{
633}
634
635void
636rfbDefaultPtrAddEvent(int buttonMask, int x, int y, rfbClientPtr cl)
637{
638  rfbClientIteratorPtr iterator;
639  rfbClientPtr other_client;
640  rfbScreenInfoPtr s = cl->screen;
641
642  if (x != s->cursorX || y != s->cursorY) {
643    LOCK(s->cursorMutex);
644    s->cursorX = x;
645    s->cursorY = y;
646    UNLOCK(s->cursorMutex);
647
648    /* The cursor was moved by this client, so don't send CursorPos. */
649    if (cl->enableCursorPosUpdates)
650      cl->cursorWasMoved = FALSE;
651
652    /* But inform all remaining clients about this cursor movement. */
653    iterator = rfbGetClientIterator(s);
654    while ((other_client = rfbClientIteratorNext(iterator)) != NULL) {
655      if (other_client != cl && other_client->enableCursorPosUpdates) {
656	other_client->cursorWasMoved = TRUE;
657      }
658    }
659    rfbReleaseClientIterator(iterator);
660  }
661}
662
663static void rfbDefaultSetXCutText(char* text, int len, rfbClientPtr cl)
664{
665}
666
667/* TODO: add a nice VNC or RFB cursor */
668
669#if defined(WIN32) || defined(sparc) || !defined(NO_STRICT_ANSI)
670static rfbCursor myCursor =
671{
672   FALSE, FALSE, FALSE, FALSE,
673   (unsigned char*)"\000\102\044\030\044\102\000",
674   (unsigned char*)"\347\347\176\074\176\347\347",
675   8, 7, 3, 3,
676   0, 0, 0,
677   0xffff, 0xffff, 0xffff,
678   NULL
679};
680#else
681static rfbCursor myCursor =
682{
683   cleanup: FALSE,
684   cleanupSource: FALSE,
685   cleanupMask: FALSE,
686   cleanupRichSource: FALSE,
687   source: "\000\102\044\030\044\102\000",
688   mask:   "\347\347\176\074\176\347\347",
689   width: 8, height: 7, xhot: 3, yhot: 3,
690   foreRed: 0, foreGreen: 0, foreBlue: 0,
691   backRed: 0xffff, backGreen: 0xffff, backBlue: 0xffff,
692   richSource: NULL
693};
694#endif
695
696static rfbCursorPtr rfbDefaultGetCursorPtr(rfbClientPtr cl)
697{
698   return(cl->screen->cursor);
699}
700
701/* response is cl->authChallenge vncEncrypted with passwd */
702static rfbBool rfbDefaultPasswordCheck(rfbClientPtr cl,const char* response,int len)
703{
704  int i;
705  char *passwd=rfbDecryptPasswdFromFile(cl->screen->authPasswdData);
706
707  if(!passwd) {
708    rfbErr("Couldn't read password file: %s\n",cl->screen->authPasswdData);
709    return(FALSE);
710  }
711
712  rfbEncryptBytes(cl->authChallenge, passwd);
713
714  /* Lose the password from memory */
715  for (i = strlen(passwd); i >= 0; i--) {
716    passwd[i] = '\0';
717  }
718
719  free(passwd);
720
721  if (memcmp(cl->authChallenge, response, len) != 0) {
722    rfbErr("authProcessClientMessage: authentication failed from %s\n",
723	   cl->host);
724    return(FALSE);
725  }
726
727  return(TRUE);
728}
729
730/* for this method, authPasswdData is really a pointer to an array
731   of char*'s, where the last pointer is 0. */
732rfbBool rfbCheckPasswordByList(rfbClientPtr cl,const char* response,int len)
733{
734  char **passwds;
735  int i=0;
736
737  for(passwds=(char**)cl->screen->authPasswdData;*passwds;passwds++,i++) {
738    uint8_t auth_tmp[CHALLENGESIZE];
739    memcpy((char *)auth_tmp, (char *)cl->authChallenge, CHALLENGESIZE);
740    rfbEncryptBytes(auth_tmp, *passwds);
741
742    if (memcmp(auth_tmp, response, len) == 0) {
743      if(i>=cl->screen->authPasswdFirstViewOnly)
744	cl->viewOnly=TRUE;
745      return(TRUE);
746    }
747  }
748
749  rfbErr("authProcessClientMessage: authentication failed from %s\n",
750	 cl->host);
751  return(FALSE);
752}
753
754void rfbDoNothingWithClient(rfbClientPtr cl)
755{
756}
757
758static enum rfbNewClientAction rfbDefaultNewClientHook(rfbClientPtr cl)
759{
760	return RFB_CLIENT_ACCEPT;
761}
762
763/*
764 * Update server's pixel format in screenInfo structure. This
765 * function is called from rfbGetScreen() and rfbNewFramebuffer().
766 */
767
768static void rfbInitServerFormat(rfbScreenInfoPtr screen, int bitsPerSample)
769{
770   rfbPixelFormat* format=&screen->serverFormat;
771
772   format->bitsPerPixel = screen->bitsPerPixel;
773   format->depth = screen->depth;
774   format->bigEndian = rfbEndianTest?FALSE:TRUE;
775   format->trueColour = TRUE;
776   screen->colourMap.count = 0;
777   screen->colourMap.is16 = 0;
778   screen->colourMap.data.bytes = NULL;
779
780   if (format->bitsPerPixel == 8) {
781     format->redMax = 7;
782     format->greenMax = 7;
783     format->blueMax = 3;
784     format->redShift = 0;
785     format->greenShift = 3;
786     format->blueShift = 6;
787   } else {
788     format->redMax = (1 << bitsPerSample) - 1;
789     format->greenMax = (1 << bitsPerSample) - 1;
790     format->blueMax = (1 << bitsPerSample) - 1;
791     if(rfbEndianTest) {
792       format->redShift = 0;
793       format->greenShift = bitsPerSample;
794       format->blueShift = bitsPerSample * 2;
795     } else {
796       if(format->bitsPerPixel==8*3) {
797	 format->redShift = bitsPerSample*2;
798	 format->greenShift = bitsPerSample*1;
799	 format->blueShift = 0;
800       } else {
801	 format->redShift = bitsPerSample*3;
802	 format->greenShift = bitsPerSample*2;
803	 format->blueShift = bitsPerSample;
804       }
805     }
806   }
807}
808
809rfbScreenInfoPtr rfbGetScreen(int* argc,char** argv,
810 int width,int height,int bitsPerSample,int samplesPerPixel,
811 int bytesPerPixel)
812{
813   rfbScreenInfoPtr screen=calloc(sizeof(rfbScreenInfo),1);
814
815   if (! logMutex_initialized) {
816     INIT_MUTEX(logMutex);
817     logMutex_initialized = 1;
818   }
819
820
821   if(width&3)
822     rfbErr("WARNING: Width (%d) is not a multiple of 4. VncViewer has problems with that.\n",width);
823
824   screen->autoPort=FALSE;
825   screen->clientHead=NULL;
826   screen->pointerClient=NULL;
827   screen->port=5900;
828   screen->ipv6port=5900;
829   screen->socketState=RFB_SOCKET_INIT;
830
831   screen->inetdInitDone = FALSE;
832   screen->inetdSock=-1;
833
834   screen->udpSock=-1;
835   screen->udpSockConnected=FALSE;
836   screen->udpPort=0;
837   screen->udpClient=NULL;
838
839   screen->maxFd=0;
840   screen->listenSock=-1;
841   screen->listen6Sock=-1;
842
843   screen->httpInitDone=FALSE;
844   screen->httpEnableProxyConnect=FALSE;
845   screen->httpPort=0;
846   screen->http6Port=0;
847   screen->httpDir=NULL;
848   screen->httpListenSock=-1;
849   screen->httpListen6Sock=-1;
850   screen->httpSock=-1;
851
852   screen->desktopName = "LibVNCServer";
853   screen->alwaysShared = FALSE;
854   screen->neverShared = FALSE;
855   screen->dontDisconnect = FALSE;
856   screen->authPasswdData = NULL;
857   screen->authPasswdFirstViewOnly = 1;
858
859   screen->width = width;
860   screen->height = height;
861   screen->bitsPerPixel = screen->depth = 8*bytesPerPixel;
862
863   screen->passwordCheck = rfbDefaultPasswordCheck;
864
865   screen->ignoreSIGPIPE = TRUE;
866
867   /* disable progressive updating per default */
868   screen->progressiveSliceHeight = 0;
869
870   screen->listenInterface = htonl(INADDR_ANY);
871
872   screen->deferUpdateTime=5;
873   screen->maxRectsPerUpdate=50;
874
875   screen->handleEventsEagerly = FALSE;
876
877   screen->protocolMajorVersion = rfbProtocolMajorVersion;
878   screen->protocolMinorVersion = rfbProtocolMinorVersion;
879
880   screen->permitFileTransfer = FALSE;
881
882   if(!rfbProcessArguments(screen,argc,argv)) {
883     free(screen);
884     return NULL;
885   }
886
887#ifdef WIN32
888   {
889	   DWORD dummy=255;
890	   GetComputerName(screen->thisHost,&dummy);
891   }
892#else
893   gethostname(screen->thisHost, 255);
894#endif
895
896   screen->paddedWidthInBytes = width*bytesPerPixel;
897
898   /* format */
899
900   rfbInitServerFormat(screen, bitsPerSample);
901
902   /* cursor */
903
904   screen->cursorX=screen->cursorY=screen->underCursorBufferLen=0;
905   screen->underCursorBuffer=NULL;
906   screen->dontConvertRichCursorToXCursor = FALSE;
907   screen->cursor = &myCursor;
908   INIT_MUTEX(screen->cursorMutex);
909
910   IF_PTHREADS(screen->backgroundLoop = FALSE);
911
912   /* proc's and hook's */
913
914   screen->kbdAddEvent = rfbDefaultKbdAddEvent;
915   screen->kbdReleaseAllKeys = rfbDoNothingWithClient;
916   screen->ptrAddEvent = rfbDefaultPtrAddEvent;
917   screen->setXCutText = rfbDefaultSetXCutText;
918   screen->getCursorPtr = rfbDefaultGetCursorPtr;
919   screen->setTranslateFunction = rfbSetTranslateFunction;
920   screen->newClientHook = rfbDefaultNewClientHook;
921   screen->displayHook = NULL;
922   screen->displayFinishedHook = NULL;
923   screen->getKeyboardLedStateHook = NULL;
924   screen->xvpHook = NULL;
925
926   /* initialize client list and iterator mutex */
927   rfbClientListInit(screen);
928
929   return(screen);
930}
931
932/*
933 * Switch to another framebuffer (maybe of different size and color
934 * format). Clients supporting NewFBSize pseudo-encoding will change
935 * their local framebuffer dimensions if necessary.
936 * NOTE: Rich cursor data should be converted to new pixel format by
937 * the caller.
938 */
939
940void rfbNewFramebuffer(rfbScreenInfoPtr screen, char *framebuffer,
941                       int width, int height,
942                       int bitsPerSample, int samplesPerPixel,
943                       int bytesPerPixel)
944{
945  rfbPixelFormat old_format;
946  rfbBool format_changed = FALSE;
947  rfbClientIteratorPtr iterator;
948  rfbClientPtr cl;
949
950  /* Update information in the screenInfo structure */
951
952  old_format = screen->serverFormat;
953
954  if (width & 3)
955    rfbErr("WARNING: New width (%d) is not a multiple of 4.\n", width);
956
957  screen->width = width;
958  screen->height = height;
959  screen->bitsPerPixel = screen->depth = 8*bytesPerPixel;
960  screen->paddedWidthInBytes = width*bytesPerPixel;
961
962  rfbInitServerFormat(screen, bitsPerSample);
963
964  if (memcmp(&screen->serverFormat, &old_format,
965             sizeof(rfbPixelFormat)) != 0) {
966    format_changed = TRUE;
967  }
968
969  screen->frameBuffer = framebuffer;
970
971  /* Adjust pointer position if necessary */
972
973  if (screen->cursorX >= width)
974    screen->cursorX = width - 1;
975  if (screen->cursorY >= height)
976    screen->cursorY = height - 1;
977
978  /* For each client: */
979  iterator = rfbGetClientIterator(screen);
980  while ((cl = rfbClientIteratorNext(iterator)) != NULL) {
981
982    /* Re-install color translation tables if necessary */
983
984    if (format_changed)
985      screen->setTranslateFunction(cl);
986
987    /* Mark the screen contents as changed, and schedule sending
988       NewFBSize message if supported by this client. */
989
990    LOCK(cl->updateMutex);
991    sraRgnDestroy(cl->modifiedRegion);
992    cl->modifiedRegion = sraRgnCreateRect(0, 0, width, height);
993    sraRgnMakeEmpty(cl->copyRegion);
994    cl->copyDX = 0;
995    cl->copyDY = 0;
996
997    if (cl->useNewFBSize)
998      cl->newFBSizePending = TRUE;
999
1000    TSIGNAL(cl->updateCond);
1001    UNLOCK(cl->updateMutex);
1002  }
1003  rfbReleaseClientIterator(iterator);
1004}
1005
1006/* hang up on all clients and free all reserved memory */
1007
1008void rfbScreenCleanup(rfbScreenInfoPtr screen)
1009{
1010  rfbClientIteratorPtr i=rfbGetClientIterator(screen);
1011  rfbClientPtr cl,cl1=rfbClientIteratorNext(i);
1012  while(cl1) {
1013    cl=rfbClientIteratorNext(i);
1014    rfbClientConnectionGone(cl1);
1015    cl1=cl;
1016  }
1017  rfbReleaseClientIterator(i);
1018
1019#define FREE_IF(x) if(screen->x) free(screen->x)
1020  FREE_IF(colourMap.data.bytes);
1021  FREE_IF(underCursorBuffer);
1022  TINI_MUTEX(screen->cursorMutex);
1023  if(screen->cursor && screen->cursor->cleanup)
1024    rfbFreeCursor(screen->cursor);
1025
1026#ifdef LIBVNCSERVER_HAVE_LIBZ
1027  rfbZlibCleanup(screen);
1028#ifdef LIBVNCSERVER_HAVE_LIBJPEG
1029  rfbTightCleanup(screen);
1030#endif
1031
1032  /* free all 'scaled' versions of this screen */
1033  while (screen->scaledScreenNext!=NULL)
1034  {
1035      rfbScreenInfoPtr ptr;
1036      ptr = screen->scaledScreenNext;
1037      screen->scaledScreenNext = ptr->scaledScreenNext;
1038      free(ptr->frameBuffer);
1039      free(ptr);
1040  }
1041
1042#endif
1043  free(screen);
1044}
1045
1046void rfbInitServer(rfbScreenInfoPtr screen)
1047{
1048#ifdef WIN32
1049  WSADATA trash;
1050  WSAStartup(MAKEWORD(2,2),&trash);
1051#endif
1052  rfbInitSockets(screen);
1053  rfbHttpInitSockets(screen);
1054#ifndef __MINGW32__
1055  if(screen->ignoreSIGPIPE)
1056    signal(SIGPIPE,SIG_IGN);
1057#endif
1058}
1059
1060void rfbShutdownServer(rfbScreenInfoPtr screen,rfbBool disconnectClients) {
1061  if(disconnectClients) {
1062    rfbClientPtr cl;
1063    rfbClientIteratorPtr iter = rfbGetClientIterator(screen);
1064    while( (cl = rfbClientIteratorNext(iter)) )
1065      if (cl->sock > -1)
1066	/* we don't care about maxfd here, because the server goes away */
1067	rfbCloseClient(cl);
1068    rfbReleaseClientIterator(iter);
1069  }
1070
1071  rfbShutdownSockets(screen);
1072  rfbHttpShutdownSockets(screen);
1073}
1074
1075#ifndef LIBVNCSERVER_HAVE_GETTIMEOFDAY
1076#include <fcntl.h>
1077#include <conio.h>
1078#include <sys/timeb.h>
1079
1080void gettimeofday(struct timeval* tv,char* dummy)
1081{
1082   SYSTEMTIME t;
1083   GetSystemTime(&t);
1084   tv->tv_sec=t.wHour*3600+t.wMinute*60+t.wSecond;
1085   tv->tv_usec=t.wMilliseconds*1000;
1086}
1087#endif
1088
1089rfbBool
1090rfbProcessEvents(rfbScreenInfoPtr screen,long usec)
1091{
1092  rfbClientIteratorPtr i;
1093  rfbClientPtr cl,clPrev;
1094  rfbBool result=FALSE;
1095  extern rfbClientIteratorPtr
1096    rfbGetClientIteratorWithClosed(rfbScreenInfoPtr rfbScreen);
1097
1098  if(usec<0)
1099    usec=screen->deferUpdateTime*1000;
1100
1101  rfbCheckFds(screen,usec);
1102  rfbHttpCheckFds(screen);
1103
1104  i = rfbGetClientIteratorWithClosed(screen);
1105  cl=rfbClientIteratorHead(i);
1106  while(cl) {
1107    result = rfbUpdateClient(cl);
1108    clPrev=cl;
1109    cl=rfbClientIteratorNext(i);
1110    if(clPrev->sock==-1) {
1111      rfbClientConnectionGone(clPrev);
1112      result=TRUE;
1113    }
1114  }
1115  rfbReleaseClientIterator(i);
1116
1117  return result;
1118}
1119
1120rfbBool
1121rfbUpdateClient(rfbClientPtr cl)
1122{
1123  struct timeval tv;
1124  rfbBool result=FALSE;
1125  rfbScreenInfoPtr screen = cl->screen;
1126
1127  if (cl->sock >= 0 && !cl->onHold && FB_UPDATE_PENDING(cl) &&
1128        !sraRgnEmpty(cl->requestedRegion)) {
1129      result=TRUE;
1130      if(screen->deferUpdateTime == 0) {
1131          rfbSendFramebufferUpdate(cl,cl->modifiedRegion);
1132      } else if(cl->startDeferring.tv_usec == 0) {
1133        gettimeofday(&cl->startDeferring,NULL);
1134        if(cl->startDeferring.tv_usec == 0)
1135          cl->startDeferring.tv_usec++;
1136      } else {
1137        gettimeofday(&tv,NULL);
1138        if(tv.tv_sec < cl->startDeferring.tv_sec /* at midnight */
1139           || ((tv.tv_sec-cl->startDeferring.tv_sec)*1000
1140               +(tv.tv_usec-cl->startDeferring.tv_usec)/1000)
1141             > screen->deferUpdateTime) {
1142          cl->startDeferring.tv_usec = 0;
1143          rfbSendFramebufferUpdate(cl,cl->modifiedRegion);
1144        }
1145      }
1146    }
1147
1148    if (!cl->viewOnly && cl->lastPtrX >= 0) {
1149      if(cl->startPtrDeferring.tv_usec == 0) {
1150        gettimeofday(&cl->startPtrDeferring,NULL);
1151        if(cl->startPtrDeferring.tv_usec == 0)
1152          cl->startPtrDeferring.tv_usec++;
1153      } else {
1154        struct timeval tv;
1155        gettimeofday(&tv,NULL);
1156        if(tv.tv_sec < cl->startPtrDeferring.tv_sec /* at midnight */
1157           || ((tv.tv_sec-cl->startPtrDeferring.tv_sec)*1000
1158           +(tv.tv_usec-cl->startPtrDeferring.tv_usec)/1000)
1159           > cl->screen->deferPtrUpdateTime) {
1160          cl->startPtrDeferring.tv_usec = 0;
1161          cl->screen->ptrAddEvent(cl->lastPtrButtons,
1162                                  cl->lastPtrX,
1163                                  cl->lastPtrY, cl);
1164          cl->lastPtrX = -1;
1165        }
1166      }
1167    }
1168
1169    return result;
1170}
1171
1172rfbBool rfbIsActive(rfbScreenInfoPtr screenInfo) {
1173  return screenInfo->socketState!=RFB_SOCKET_SHUTDOWN || screenInfo->clientHead!=NULL;
1174}
1175
1176void rfbRunEventLoop(rfbScreenInfoPtr screen, long usec, rfbBool runInBackground)
1177{
1178  if(runInBackground) {
1179#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
1180       pthread_t listener_thread;
1181
1182       screen->backgroundLoop = TRUE;
1183
1184       pthread_create(&listener_thread, NULL, listenerRun, screen);
1185    return;
1186#else
1187    rfbErr("Can't run in background, because I don't have PThreads!\n");
1188    return;
1189#endif
1190  }
1191
1192  if(usec<0)
1193    usec=screen->deferUpdateTime*1000;
1194
1195  while(rfbIsActive(screen))
1196    rfbProcessEvents(screen,usec);
1197}
1198