/* 
 * osdworker.c: osd worker thread
 *
 * See the README file for copyright information and how to reach the author.
 *
 */

#include <vdr/tools.h>

#include "tools/socket.h"
#include "tools/select.h"

#include "osdworker.h"

//////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////

cOSDWorker *cOSDWorker::m_Instance = NULL;

cOSDWorker::cOSDWorker(void)
		: cThread("[ffnetdev] OSD via VNC")
{
	m_Active 		= false;
	m_OSDClient 		= NULL;
	
	state 			= NO_CLIENT;
	close_OSDclient_request = false;
	
	UseAlpha 		= false;

	memset(&osdbuffer, 0, 720*576);
}

cOSDWorker::~cOSDWorker() {
	if (m_Active) Stop();
}

void cOSDWorker::Init(cMyRemote *Remote, int osdport) {
	if (m_Instance == NULL) {
		m_Instance = new cOSDWorker;
		
		m_Instance->m_Remote = Remote;
		m_Instance->OSDPort = osdport;
		m_Instance->Start();
	}
	
}

void cOSDWorker::Exit(void) {
	if (m_Instance != NULL) {
		m_Instance->Stop();
		DELETENULL(m_Instance);
	}
}

void cOSDWorker::Stop(void) {
	m_Active = false;
	Cancel(3);
}

void cOSDWorker::CloseOSDClient(void) {
	m_Instance->close_OSDclient_request = true;
#ifdef DEBUG
	fprintf(stderr, "[ffnetdev] VNC: Closing of OSD client socket requested.\r\n");
#endif
}

bool cOSDWorker::SendPlayMode(ePlayMode PlayMode) {

	// not yet implemented
	return true;
}

bool cOSDWorker::ClearScreen(void)
{
	// this should be improved;
	// 1) maybe we should send a our very "special" pseudo encoding[CLEAR_SCREEN] to our "special" VNC client to get an empty screen really fast
	
	memset(&(m_Instance->osdbuffer), 0, 720*576); 
	return( SendScreen(720,0,0,720,576,&(m_Instance->osdbuffer)) );
}

bool cOSDWorker::SendScreen(unsigned int stride, unsigned int x1, unsigned int y1, unsigned int w, unsigned int h, const void *data)
{
   rfbFramebufferUpdateMsg fu;
   rfbFramebufferUpdateRectHeader furh;
   unsigned int y;
   unsigned int x;
    
   if (m_Instance->state==HANDSHAKE_OK) {
   
   	fu.type=rfbFramebufferUpdate;
   	fu.nRects=Swap16IfLE(1);
   	OSDWrite((unsigned char*)&fu, sz_rfbFramebufferUpdateMsg);
   
	furh.encoding=Swap32IfLE(rfbEncodingRaw);
   	furh.r.x=Swap16IfLE((CARD16)x1);
   	furh.r.y=Swap16IfLE((CARD16)y1);
   	furh.r.w=Swap16IfLE((CARD16)w);
   	furh.r.h=Swap16IfLE((CARD16)h);
   	OSDWrite((unsigned char*)&furh, sz_rfbFramebufferUpdateRectHeader);
   
	if (m_Instance->ClientFormat.trueColour) {
		
		
		// truecolor mode: 8bpp
		if (m_Instance->ClientFormat.bitsPerPixel==8) {
   		
	   		// Reserve buffer for this window update
	   		CARD8 tempbuf[h*w];
   		  	
	   		// now convert from colour map format to truecolor format
	   		for(y=0; y<h; y++) {
		   		for (x=0; x<w;x++) {
					CARD8 index;
					CARD8 red;
					CARD8 green;
					CARD8 blue;
					//CARD8 alpha;   // not currently used by any client
					index = *((unsigned char*)data+(y*stride)+x);
					red   = ((m_Instance->OSDColors[index]&0x00FF0000) >> 16);
           				green = ((m_Instance->OSDColors[index]&0x0000FF00) >>  8);
           				blue  = ((m_Instance->OSDColors[index]&0x000000FF) );
           				//alpha = ((m_Instance->OSDColors[index]&0xFF000000) >> 24); // not currently used by any client
			
					CARD8 packed;
			
					packed  = ((red	  / (256/(1+Swap16IfLE(m_Instance->ClientFormat.redMax  ))))& Swap16IfLE(m_Instance->ClientFormat.redMax  )  ) << (m_Instance->ClientFormat.redShift  );
					packed |= ((green / (256/(1+Swap16IfLE(m_Instance->ClientFormat.greenMax))))& Swap16IfLE(m_Instance->ClientFormat.greenMax)  ) << (m_Instance->ClientFormat.greenShift);
					packed |= ((blue  / (256/(1+Swap16IfLE(m_Instance->ClientFormat.blueMax ))))& Swap16IfLE(m_Instance->ClientFormat.blueMax )  ) << (m_Instance->ClientFormat.blueShift );
						
					tempbuf[y*w+x] = packed;
	   	        	}
		  	}
			// Send screen in truecolor format
			OSDWrite( (unsigned char*) &tempbuf, h*w*sizeof(CARD8));
			fprintf(stderr, "[ffnetdev] VNC: sent screen with %d bytes.\n",h*w*sizeof(CARD8));
		}
		// truecolor mode: 16bpp   		
   		else if (m_Instance->ClientFormat.bitsPerPixel==16) {
   		
	   		// Reserve buffer for this window update
	   		CARD16 tempbuf[h*w];
   		  	
	   		// now convert from colour map format to truecolor format
	   		for(y=0; y<h; y++) {
		   		for (x=0; x<w;x++) {
					CARD8 index;
					CARD8 red;
					CARD8 green;
					CARD8 blue;
					//CARD8 alpha;   // not currently used by any client
					index = *((unsigned char*)data+(y*stride)+x);
					red   = ((m_Instance->OSDColors[index]&0x00FF0000) >> 16);
           				green = ((m_Instance->OSDColors[index]&0x0000FF00) >>  8);
           				blue  = ((m_Instance->OSDColors[index]&0x000000FF) );
           				//alpha = ((m_Instance->OSDColors[index]&0xFF000000) >> 24); // not currently used by any client
			
					CARD16 packed;
			
					packed  = ((red	  / (256/(1+Swap16IfLE(m_Instance->ClientFormat.redMax  ))))& Swap16IfLE(m_Instance->ClientFormat.redMax  )  ) << (m_Instance->ClientFormat.redShift  );
					packed |= ((green / (256/(1+Swap16IfLE(m_Instance->ClientFormat.greenMax))))& Swap16IfLE(m_Instance->ClientFormat.greenMax)  ) << (m_Instance->ClientFormat.greenShift);
					packed |= ((blue  / (256/(1+Swap16IfLE(m_Instance->ClientFormat.blueMax ))))& Swap16IfLE(m_Instance->ClientFormat.blueMax )  ) << (m_Instance->ClientFormat.blueShift );
					
					if (m_Instance->ClientFormat.bigEndian)	
										tempbuf[y*w+x] = Swap16( packed );
					else
										tempbuf[y*w+x] = packed;
	   	        	}
		  	}
    			// Send screen in truecolor format
			OSDWrite( (unsigned char*) &tempbuf, h*w*sizeof(CARD16));
#ifdef DEBUG
			fprintf(stderr, "[ffnetdev] VNC: sent screen with %d bytes.\n",h*w*sizeof(CARD16));
#endif

		 } 	
		 // truecolor mode: 32bpp
		 else if (m_Instance->ClientFormat.bitsPerPixel==32) {
   		
	   		// Reserve buffer for this window update
	   		CARD32 tempbuf[h*w];
   		  	
	   		// now convert from colour map format to truecolor format
	   		for(y=0; y<h; y++) {
		   		for (x=0; x<w;x++) {
					CARD8 index;
					CARD8 red;
					CARD8 green;
					CARD8 blue;
					//CARD8 alpha;   // not currently used by any client
					index = *((unsigned char*)data+(y*stride)+x);
					red   = ((m_Instance->OSDColors[index]&0x00FF0000) >> 16);
           				green = ((m_Instance->OSDColors[index]&0x0000FF00) >>  8);
           				blue  = ((m_Instance->OSDColors[index]&0x000000FF) );
           				//alpha = ((m_Instance->OSDColors[index]&0xFF000000) >> 24); // not currently used by any client
			
					CARD32 packed;
			
					packed  = ((red	  / (256/(1+Swap16IfLE(m_Instance->ClientFormat.redMax  ))))& Swap16IfLE(m_Instance->ClientFormat.redMax  )  ) << (m_Instance->ClientFormat.redShift  );
					packed |= ((green / (256/(1+Swap16IfLE(m_Instance->ClientFormat.greenMax))))& Swap16IfLE(m_Instance->ClientFormat.greenMax)  ) << (m_Instance->ClientFormat.greenShift);
					packed |= ((blue  / (256/(1+Swap16IfLE(m_Instance->ClientFormat.blueMax ))))& Swap16IfLE(m_Instance->ClientFormat.blueMax )  ) << (m_Instance->ClientFormat.blueShift );
					
					if (m_Instance->ClientFormat.bigEndian)	
										tempbuf[y*w+x] = Swap32( packed );
					else
										tempbuf[y*w+x] = packed;
	   	        	}
		  	}
			// Send screen in truecolor format
			OSDWrite( (unsigned char*) &tempbuf, h*w*sizeof(CARD32));
#ifdef DEBUG
			fprintf(stderr, "[ffnetdev] VNC: sent screen with %d bytes.\n",h*w*sizeof(CARD32));
#endif
		}
		else
			return false;
	}
	else {
		// Send screen in coulor map format
		for(y=0; y<h; y++)
			OSDWrite((unsigned char*)data+(y*stride), w);
#ifdef DEBUG   
		fprintf(stderr, "[ffnetdev] VNC: sent screen with %d bytes\n",h*w);
   		//unsigned char *test=(unsigned char*)data;
   		//for(x=0; x<200; x++)
   		//   printf("%02X ",  test[x]   );
   		//printf("\n");
#endif   
	}
       	

   	return true;
   }
   
   // make sure we have a copy all screen updates in colour map format if there is no OSD client connected 
   // write all updates to a buffer(osdbuffer) which is sent to the client immediately after connection was established
   else {
   	unsigned int x;
   	unsigned int y;
   	for (y=0; y<h; y++)
   	   for (x=0; x<w; x++)
   		m_Instance->osdbuffer[(720*(y+y1))+x+x1] = *((unsigned char *)data+(y*stride)+x);
   	return false;
   }
}

bool cOSDWorker::SendCMAP(int NumColors, const tColor *Colors)
{
	rfbSetColourMapEntriesMsg scme;
	CARD16 red;
	CARD16 green;
	CARD16 blue;
	CARD16 alpha;

       	int i;
	
	if ((m_Instance->state==HANDSHAKE_OK) && !(m_Instance->ClientFormat.trueColour)) { 
		scme.type=rfbSetColourMapEntries;
		scme.firstColour = Swap16IfLE(0);
		scme.nColours = Swap16IfLE((CARD16)NumColors);

		OSDWrite((unsigned char*)&scme, sz_rfbSetColourMapEntriesMsg);

        	for(i=0; i<NumColors; i++)
        	{
           	red   = ((Colors[i]&0x00FF0000) >> 16);
           	green = ((Colors[i]&0x0000FF00) >>  8);
           	blue  = ((Colors[i]&0x000000FF) );
           	
           	if (m_Instance->UseAlpha) {
           		alpha = ((Colors[i]&0xFF000000) >> 24);
               		OSDWrite( (unsigned char*) &alpha, 2);
           	}
           	
	        OSDWrite( (unsigned char*) &red, 2);
      	   	OSDWrite( (unsigned char*) &green, 2);
	  	OSDWrite( (unsigned char*) &blue, 2);
	   	
	   	m_Instance->OSDColors[i] = Colors[i];
		}
		m_Instance->numOSDColors = NumColors;
		return true;
	} 
	else {
		for (i=0; i<NumColors; i++)
			m_Instance->OSDColors[i] = Colors[i];
		m_Instance->numOSDColors = NumColors;
		return false;
	}
}

bool cOSDWorker::OSDWrite(unsigned char *data, unsigned int data_length)
{
  if (m_Instance->m_OSDClient!=NULL) {
   if (m_Instance->m_OSDClient->IsOpen()) 
   {
	//fprintf(stderr, "[ffnetdev] VNC: Trying to send...\n");
	if (!m_Instance->m_OSDClient->SafeWrite(data, data_length))
	{   
	    CloseOSDClient();
	    return false;
	}
   }  //else fprintf(stderr, "[ffnetdev] VNC: Cannot send...\n"); 
    //for (unsigned int i=0; i<data_length; i++) fprintf(stderr,"%02X ",*(data+i));
    //fprintf(stderr,"\n");
    
    return true;
  }
  return false;
}

bool cOSDWorker::RFBRead(char *buffer, int len)
{
	if ( m_OSDClient->Read(buffer, len)==0 ) {
#ifdef DEBUG
			fprintf(stderr, "[ffnetdev] VNC: Client closed connection.\n");
#endif
			isyslog("[ffnetdev] VNC: Connection closed: client %s:%d",
			m_OSDClient->RemoteIp().c_str(), m_OSDClient->RemotePort());
			state = NO_CLIENT;
			m_Instance->m_OSDClient->Close();
			return false;
	} 
	else
		return true;
}

void cOSDWorker::HandleClientRequests(cTBSelect *select) 
{
	if ( select->CanRead(*m_OSDClient) ) {
		rfbClientToServerMsg msg;
		
		if (!RFBRead((char*)&msg, 1))
			return;
		
		switch (msg.type) {
			
		case rfbSetPixelFormat:		if (!RFBRead( ((char*)&msg.spf)+1, sz_rfbSetPixelFormatMsg-1))
							return;
						fprintf(stderr, "[ffnetdev] VNC: SetPixelFormat\n");
						fprintf(stderr, "[ffnetdev] VNC: ->bitsPerPixel: %d\n",msg.spf.format.bitsPerPixel);
						fprintf(stderr, "[ffnetdev] VNC: ->depth: %d\n",msg.spf.format.depth);
						fprintf(stderr, "[ffnetdev] VNC: ->bigEndian: %d\n",msg.spf.format.bigEndian);
						fprintf(stderr, "[ffnetdev] VNC: ->trueColour: %d\n",msg.spf.format.trueColour);
						fprintf(stderr, "[ffnetdev] VNC: ->redMax: %d\n",Swap16IfLE(msg.spf.format.redMax));
						fprintf(stderr, "[ffnetdev] VNC: ->greenMax: %d\n",Swap16IfLE(msg.spf.format.greenMax));
						fprintf(stderr, "[ffnetdev] VNC: ->blueMax: %d\n",Swap16IfLE(msg.spf.format.blueMax));
						fprintf(stderr, "[ffnetdev] VNC: ->redShift: %d\n",msg.spf.format.redShift);
						fprintf(stderr, "[ffnetdev] VNC: ->greenShift: %d\n",msg.spf.format.greenShift);
						fprintf(stderr, "[ffnetdev] VNC: ->blueShift: %d\n",msg.spf.format.blueShift);
						
						if ( (msg.spf.format.bitsPerPixel!=8 ) 
						   &&(msg.spf.format.bitsPerPixel!=16)
						   &&(msg.spf.format.bitsPerPixel!=32)) {
							fprintf(stderr, "[ffnetdev] SORRY!!! VNC client requested unsupported pixel format! Closing connection...\n");
							close_OSDclient_request = true;
							return;
						}
						else
							ClientFormat = msg.spf.format;
						
						break;
		case rfbFixColourMapEntries:	if (!RFBRead( ((char*)&msg.fcme)+1, sz_rfbFixColourMapEntriesMsg-1))
							return;
						fprintf(stderr, "[ffnetdev] VNC: FixColourMapEntries (ignored).\n");
						break;
		case rfbSetEncodings:		if (!RFBRead( ((char*)&msg.se)+1, sz_rfbSetEncodingsMsg-1))
							return;
					
						fprintf(stderr, "[ffnetdev] VNC: SetEncodings: Client offers %d encodings:\n", Swap16IfLE(msg.se.nEncodings));

						CARD32 encodings[16];
						if (!RFBRead( ((char*)&encodings), Swap16IfLE(msg.se.nEncodings)*sizeof(CARD32) ))
							return;

						for (int i=0;i<Swap16IfLE(msg.se.nEncodings);i++) {
							switch (Swap32IfLE(encodings[i])) {
								case rfbEncodingRaw: 		fprintf(stderr, "[ffnetdev] VNC: ->RAW encoding.\n");
										     		break;
								case rfbEncodingCopyRect:	fprintf(stderr, "[ffnetdev] VNC: ->CopyRect encoding(not supported).\n");
										    	 	break;
								case rfbEncodingRRE: 		fprintf(stderr, "[ffnetdev] VNC: ->RRE encoding(not supported).\n");
										    	 	break;
								case rfbEncodingCoRRE: 		fprintf(stderr, "[ffnetdev] VNC: ->CoRRE encoding(not supported).\n");
										     		break;
								case rfbEncodingHextile:	fprintf(stderr, "[ffnetdev] VNC: ->Hextile encoding(not supported).\n");
										     		break;
								case rfbEncodingZlib: 		fprintf(stderr, "[ffnetdev] VNC: ->Zlib encoding(not supported).\n");
										    		 break;
								case rfbEncodingTight: 		fprintf(stderr, "[ffnetdev] VNC: ->Tight encoding(not supported).\n");
										    		 break;
								case rfbEncodingZlibHex:	fprintf(stderr, "[ffnetdev] VNC: ->ZlibHex encoding(not supported).\n");
										    	 	break;
								case rfbEncodingZRLE:		fprintf(stderr, "[ffnetdev] VNC: ->ZRLE encoding(not supported).\n");
										    	 	break;
								case rfbEncSpecialUseAlpha:	fprintf(stderr, "[ffnetdev] VNC: ->Special FFnetDev Encoding: client wants alpha channel.\n");
												UseAlpha = true;
												break;
								default:			fprintf(stderr, "[ffnetdev] VNC: ->Unknown encoding or unknown pseudo encoding.\n");
							}
						}
						break;
		case rfbFramebufferUpdateRequest:
						if (!RFBRead( ((char*)&msg.fur)+1, sz_rfbFramebufferUpdateRequestMsg-1))
							return;
#ifdef DEBUG
						fprintf(stderr, "[ffnetdev] VNC: FramebufferUpdateRequest: Client wants %s:\n",
										msg.fur.incremental? "incremental update":"complete update");
						fprintf(stderr, "[ffnetdev] VNC: x: %d, y: %d, w: %d, h: %d\n", 
								Swap16IfLE(msg.fur.x),
								Swap16IfLE(msg.fur.y),
								Swap16IfLE(msg.fur.w),
								Swap16IfLE(msg.fur.h)
							);
#endif
						if (FirstUpdateRequest) {
							SendScreen(720, //stride
								Swap16IfLE(msg.fur.x), Swap16IfLE(msg.fur.y),
								Swap16IfLE(msg.fur.w), Swap16IfLE(msg.fur.h),
							  	&osdbuffer);
							SendCMAP(numOSDColors, OSDColors);
							FirstUpdateRequest = false;
						}
						break;
		case rfbKeyEvent:		if (!RFBRead( ((char*)&msg.ke)+1, sz_rfbKeyEventMsg-1))
							return;
						fprintf(stderr, "[ffnetdev] VNC: KeyEvent\n");
						if (m_Remote!=NULL) {	
							if (msg.ke.down) 
								m_Remote->Put(Swap32IfLE(msg.ke.key), false, false);
							else 
								m_Remote->Put(Swap32IfLE(msg.ke.key), false, true);
						}
#ifdef DEBUG
						fprintf(stderr, "[ffnetdev] VNC: Remote: %04X\n", msg.ke.key);
#endif									
						break;
		case rfbPointerEvent:		if (!RFBRead( ((char*)&msg.pe)+1, sz_rfbPointerEventMsg-1))
							return;
						//fprintf(stderr, "[ffnetdev] VNC: PointerEvent\n");
						break;
 		case rfbClientCutText:		if (!RFBRead( ((char*)&msg.cct)+1, sz_rfbClientCutTextMsg-1))
							return;
						fprintf(stderr, "[ffnetdev] VNC: ClientCutText\n");
						break;
		default:
						fprintf(stderr, "[ffnetdev] VNC: Unknown RFB message.\n");
		}
	}
}

void cOSDWorker::Action(void) {
	cTBSelect select;
	cTBSocket m_OSDListen;
	        
	const char* m_ListenIp = "0.0.0.0";
	uint m_OSDListenPort = OSDPort;
	
	m_OSDClient	= new cTBSocket;
	
	m_Active = true;

        if (!m_OSDListen.Listen(m_ListenIp, m_OSDListenPort, 1)) {
		esyslog("[ffnetdev] VNC: Couldn't listen %s:%d: %s", m_ListenIp, m_OSDListenPort, strerror(errno));
		m_Active = false;
	} 
	else
	        isyslog("[ffnetdev] VNC: Listening on port %d", m_OSDListenPort);
	        
            
	while (m_Active) {
		select.Clear();
		
		if (state==NO_CLIENT)
			select.Add(m_OSDListen, false);
		else
			select.Add(*m_OSDClient, false);
		
		int numfd;
		/* React on status change of any of the above file descriptor */
		if ((numfd=select.Select(1000)) < 0) {
			if (!m_Active) // Exit was requested while polling
				continue;
			esyslog("FFNetDev: Fatal error, FFNetDev exiting: %s", strerror(errno));
			m_Active = false;
			continue;
		}
		
		//DEBUG
		/*
		fprintf(stderr, "Num_FD OSD: %d\n", numfd);
		
		if (select.CanRead(m_OSDListen) || select.CanWrite(m_OSDListen)) 
			fprintf (stderr, "m_OSDListen can act.\n");
		if (select.CanRead(*m_OSDClient) || select.CanWrite(*m_OSDClient)) 
			fprintf (stderr, "m_OSDClient can act.\n");
		*/
		//fprintf(stderr, "State: %d\n",state);	
		
		int res;
		switch (state) {
		
			case NO_CLIENT: /* Accept connecting OSD clients  */		
					if (select.CanRead(m_OSDListen) ) {
		    				if (m_OSDClient->Accept(m_OSDListen)) {
							isyslog("[ffnetdev] VNC: Accepted client %s:%d",
								m_OSDClient->RemoteIp().c_str(), m_OSDClient->RemotePort());
							state = CLIENT_CONNECTED;
							/* Sending RFB protocol version */
							rfbProtocolVersionMsg msg;
							sprintf(msg, rfbProtocolVersionFormat, rfbProtocolMajorVersion, rfbProtocolMinorVersion);
							m_OSDClient->SafeWrite(&msg, sz_rfbProtocolVersionMsg);
							break;					
							
		    				} 
		    				else {
							esyslog("[ffnetdev] VNC: Couldn't accept : %s", strerror(errno));
							state = NO_CLIENT;
							m_Active = false;
							continue;
		    				}
					}
					break;

			case CLIENT_CONNECTED: 	
						rfbProtocolVersionMsg pvmsg;
						res = m_OSDClient->Read(&pvmsg, sz_rfbProtocolVersionMsg);
		 			        fprintf(stderr, "[ffnetdev] VNC: Client wants RFB protocol version %s", pvmsg);
		 			        if (1) {//FIXME:protocol ok
		 			        	state = PROTOCOL_OK;
		 			        	/* Sending security type */
		 			        	CARD32 secmsg;
		 			        	secmsg = Swap32IfLE(rfbNoAuth);
		 			        	m_OSDClient->SafeWrite(&secmsg, sizeof(secmsg));
		 			        }
		 			        else {
							state = NO_CLIENT;
							fprintf(stderr, "[ffnetdev] VNC: Client wants unsupported protocol version.\n");
							if ( m_OSDClient->Close() ) {
#ifdef DEBUG
								fprintf(stderr, "[ffnetdev] VNC: Client socket closed successfully.\n");
#endif				
								isyslog("[ffnetdev] VNC: Connection closed.");
							}
							else {
#ifdef DEBUG
					   			fprintf(stderr, "[ffnetdev] VNC: Error closing client socket.\n");
#endif
					   			esyslog("[ffnetdev] VNC: Error closing connection.");
					   			m_Active=false;
					   			continue;
							} 		 			    
		 			        }	
						break;
			case PROTOCOL_OK:	/* Since we do not need authentication challenge(rfbNoAuth), proceed to next state */
						state = AUTHENTICATED;
						break;
			case AUTHENTICATED:	
						rfbClientInitMsg cimsg;
						res = m_OSDClient->Read(&cimsg, sz_rfbClientInitMsg);
						fprintf(stderr, "[ffnetdev] VNC: Client wants %s desktop(ignored).\n", 
									cimsg.shared ? "shared":"non-shared");
											
						rfbPixelFormat pxfmt;
						pxfmt.bitsPerPixel = 8;
						pxfmt.depth = 8;
						pxfmt.bigEndian = 0;
						pxfmt.trueColour = 0;
						pxfmt.redMax = 0;
						pxfmt.greenMax = 0;
						pxfmt.blueMax = 0;
						pxfmt.redShift = 0;
						pxfmt.greenShift = 0;
						pxfmt.blueShift = 0;
						pxfmt.pad1 = 0;
						pxfmt.pad2 = 0;
						
						rfbServerInitMsg simsg;
						simsg.framebufferWidth = Swap16IfLE(720);
						simsg.framebufferHeight = Swap16IfLE(576);
						simsg.format = pxfmt;
						simsg.nameLength = Swap32IfLE(7);
						m_OSDClient->SafeWrite(&simsg, sizeof(simsg));
						
					 	CARD8 name[7];
					 	strcpy((char*)&name, "VDR-OSD");
					 	m_OSDClient->SafeWrite(&name, 7);
					 	
						state = HANDSHAKE_OK;
						FirstUpdateRequest = true;
						break;

			case HANDSHAKE_OK:	
						
						/* Check for closed OSD connection */
						if (close_OSDclient_request==true) {
							close_OSDclient_request = false;
							state = NO_CLIENT;
							UseAlpha = false;
							
							if ( m_OSDClient->Close() ) {
#ifdef DEBUG
								fprintf(stderr, "[ffnetdev] VNC: Client socket closed successfully.\n");
#endif				
								isyslog("[ffnetdev] VNC: Connection closed.");
							}
							else {
#ifdef DEBUG
					   			fprintf(stderr, "[ffnetdev] VNC: Error closing client socket.\n");
#endif
					   			esyslog("[ffnetdev] VNC: Error closing connection.");
					   			m_Active=false;
					   			continue;
							} 
						}
						HandleClientRequests(&select);

						break;		
			default: fprintf(stderr, "[ffnetdev] VNC: Undefined state! This is a bug! Please report.\n");
				 esyslog("[ffnetdev] VNC: Fatal error, FFNetDev exiting: undefined state");
				 m_Active = false;
				 continue;
		}
		
		

		
	} // while(m_Active)

}
