You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
		
		
		
		
		
			
		
			
				
					
					
						
							636 lines
						
					
					
						
							18 KiB
						
					
					
				
			
		
		
	
	
							636 lines
						
					
					
						
							18 KiB
						
					
					
				/* | 
						|
uSynergy client -- Implementation for the embedded Synergy client library | 
						|
  version 1.0.0, July 7th, 2012 | 
						|
 | 
						|
Copyright (c) 2012 Alex Evans | 
						|
 | 
						|
This software is provided 'as-is', without any express or implied | 
						|
warranty. In no event will the authors be held liable for any damages | 
						|
arising from the use of this software. | 
						|
 | 
						|
Permission is granted to anyone to use this software for any purpose, | 
						|
including commercial applications, and to alter it and redistribute it | 
						|
freely, subject to the following restrictions: | 
						|
 | 
						|
   1. The origin of this software must not be misrepresented; you must not | 
						|
   claim that you wrote the original software. If you use this software | 
						|
   in a product, an acknowledgment in the product documentation would be | 
						|
   appreciated but is not required. | 
						|
 | 
						|
   2. Altered source versions must be plainly marked as such, and must not be | 
						|
   misrepresented as being the original software. | 
						|
 | 
						|
   3. This notice may not be removed or altered from any source | 
						|
   distribution. | 
						|
*/ | 
						|
#include "uSynergy.h" | 
						|
#include <stdio.h> | 
						|
#include <string.h> | 
						|
 | 
						|
 | 
						|
 | 
						|
//--------------------------------------------------------------------------------------------------------------------- | 
						|
//	Internal helpers | 
						|
//--------------------------------------------------------------------------------------------------------------------- | 
						|
 | 
						|
 | 
						|
 | 
						|
/** | 
						|
@brief Read 16 bit integer in network byte order and convert to native byte order | 
						|
**/ | 
						|
static int16_t sNetToNative16(const unsigned char *value) | 
						|
{ | 
						|
#ifdef USYNERGY_LITTLE_ENDIAN | 
						|
	return value[1] | (value[0] << 8); | 
						|
#else | 
						|
	return value[0] | (value[1] << 8); | 
						|
#endif | 
						|
} | 
						|
 | 
						|
 | 
						|
 | 
						|
/** | 
						|
@brief Read 32 bit integer in network byte order and convert to native byte order | 
						|
**/ | 
						|
static int32_t sNetToNative32(const unsigned char *value) | 
						|
{ | 
						|
#ifdef USYNERGY_LITTLE_ENDIAN | 
						|
	return value[3] | (value[2] << 8) | (value[1] << 16) | (value[0] << 24); | 
						|
#else | 
						|
	return value[0] | (value[1] << 8) | (value[2] << 16) | (value[3] << 24); | 
						|
#endif | 
						|
} | 
						|
 | 
						|
 | 
						|
 | 
						|
/** | 
						|
@brief Trace text to client | 
						|
**/ | 
						|
static void sTrace(uSynergyContext *context, const char* text) | 
						|
{ | 
						|
	// Don't trace if we don't have a trace function | 
						|
	if (context->m_traceFunc != 0L) | 
						|
		context->m_traceFunc(context->m_cookie, text); | 
						|
} | 
						|
 | 
						|
 | 
						|
 | 
						|
/** | 
						|
@brief Add string to reply packet | 
						|
**/ | 
						|
static void sAddString(uSynergyContext *context, const char *string) | 
						|
{ | 
						|
	size_t len = strlen(string); | 
						|
	memcpy(context->m_replyCur, string, len); | 
						|
	context->m_replyCur += len; | 
						|
} | 
						|
 | 
						|
 | 
						|
 | 
						|
/** | 
						|
@brief Add uint8 to reply packet | 
						|
**/ | 
						|
static void sAddUInt8(uSynergyContext *context, uint8_t value) | 
						|
{ | 
						|
	*context->m_replyCur++ = value; | 
						|
} | 
						|
 | 
						|
 | 
						|
 | 
						|
/** | 
						|
@brief Add uint16 to reply packet | 
						|
**/ | 
						|
static void sAddUInt16(uSynergyContext *context, uint16_t value) | 
						|
{ | 
						|
	uint8_t *reply = context->m_replyCur; | 
						|
	*reply++ = (uint8_t)(value >> 8); | 
						|
	*reply++ = (uint8_t)value; | 
						|
	context->m_replyCur = reply; | 
						|
} | 
						|
 | 
						|
 | 
						|
 | 
						|
/** | 
						|
@brief Add uint32 to reply packet | 
						|
**/ | 
						|
static void sAddUInt32(uSynergyContext *context, uint32_t value) | 
						|
{ | 
						|
	uint8_t *reply = context->m_replyCur; | 
						|
	*reply++ = (uint8_t)(value >> 24); | 
						|
	*reply++ = (uint8_t)(value >> 16); | 
						|
	*reply++ = (uint8_t)(value >> 8); | 
						|
	*reply++ = (uint8_t)value; | 
						|
	context->m_replyCur = reply; | 
						|
} | 
						|
 | 
						|
 | 
						|
 | 
						|
/** | 
						|
@brief Send reply packet | 
						|
**/ | 
						|
static uSynergyBool sSendReply(uSynergyContext *context) | 
						|
{ | 
						|
	// Set header size | 
						|
	uint8_t		*reply_buf	= context->m_replyBuffer; | 
						|
	uint32_t	reply_len	= (uint32_t)(context->m_replyCur - reply_buf);				/* Total size of reply */ | 
						|
	uint32_t	body_len	= reply_len - 4;											/* Size of body */ | 
						|
	uSynergyBool ret; | 
						|
	reply_buf[0] = (uint8_t)(body_len >> 24); | 
						|
	reply_buf[1] = (uint8_t)(body_len >> 16); | 
						|
	reply_buf[2] = (uint8_t)(body_len >> 8); | 
						|
	reply_buf[3] = (uint8_t)body_len; | 
						|
 | 
						|
	// Send reply | 
						|
	ret = context->m_sendFunc(context->m_cookie, context->m_replyBuffer, reply_len); | 
						|
 | 
						|
	// Reset reply buffer write pointer | 
						|
	context->m_replyCur = context->m_replyBuffer+4; | 
						|
	return ret; | 
						|
} | 
						|
 | 
						|
 | 
						|
 | 
						|
/** | 
						|
@brief Call mouse callback after a mouse event | 
						|
**/ | 
						|
static void sSendMouseCallback(uSynergyContext *context) | 
						|
{ | 
						|
	// Skip if no callback is installed | 
						|
	if (context->m_mouseCallback == 0L) | 
						|
		return; | 
						|
 | 
						|
	// Send callback | 
						|
	context->m_mouseCallback(context->m_cookie, context->m_mouseX, context->m_mouseY, context->m_mouseWheelX, | 
						|
		context->m_mouseWheelY, context->m_mouseButtonLeft, context->m_mouseButtonRight, context->m_mouseButtonMiddle); | 
						|
} | 
						|
 | 
						|
 | 
						|
 | 
						|
/** | 
						|
@brief Send keyboard callback when a key has been pressed or released | 
						|
**/ | 
						|
static void sSendKeyboardCallback(uSynergyContext *context, uint16_t key, uint16_t modifiers, uSynergyBool down, uSynergyBool repeat) | 
						|
{ | 
						|
	// Skip if no callback is installed | 
						|
	if (context->m_keyboardCallback == 0L) | 
						|
		return; | 
						|
 | 
						|
	// Send callback | 
						|
	context->m_keyboardCallback(context->m_cookie, key, modifiers, down, repeat); | 
						|
} | 
						|
 | 
						|
 | 
						|
 | 
						|
/** | 
						|
@brief Send joystick callback | 
						|
**/ | 
						|
static void sSendJoystickCallback(uSynergyContext *context, uint8_t joyNum) | 
						|
{ | 
						|
	int8_t *sticks; | 
						|
 | 
						|
	// Skip if no callback is installed | 
						|
	if (context->m_joystickCallback == 0L) | 
						|
		return; | 
						|
 | 
						|
	// Send callback | 
						|
	sticks = context->m_joystickSticks[joyNum]; | 
						|
	context->m_joystickCallback(context->m_cookie, joyNum, context->m_joystickButtons[joyNum], sticks[0], sticks[1], sticks[2], sticks[3]); | 
						|
} | 
						|
 | 
						|
 | 
						|
 | 
						|
/** | 
						|
@brief Parse a single client message, update state, send callbacks and send replies | 
						|
**/ | 
						|
#define USYNERGY_IS_PACKET(pkt_id)	memcmp(message+4, pkt_id, 4)==0 | 
						|
static void sProcessMessage(uSynergyContext *context, const uint8_t *message) | 
						|
{ | 
						|
	// We have a packet! | 
						|
	if (memcmp(message+4, "Synergy", 7)==0) | 
						|
	{ | 
						|
		// Welcome message | 
						|
		//		kMsgHello			= "Synergy%2i%2i" | 
						|
		//		kMsgHelloBack		= "Synergy%2i%2i%s" | 
						|
		sAddString(context, "Synergy"); | 
						|
		sAddUInt16(context, USYNERGY_PROTOCOL_MAJOR); | 
						|
		sAddUInt16(context, USYNERGY_PROTOCOL_MINOR); | 
						|
		sAddUInt32(context, (uint32_t)strlen(context->m_clientName)); | 
						|
		sAddString(context, context->m_clientName); | 
						|
		if (!sSendReply(context)) | 
						|
		{ | 
						|
			// Send reply failed, let's try to reconnect | 
						|
			sTrace(context, "SendReply failed, trying to reconnect in a second"); | 
						|
			context->m_connected = USYNERGY_FALSE; | 
						|
			context->m_sleepFunc(context->m_cookie, 1000); | 
						|
		} | 
						|
		else | 
						|
		{ | 
						|
			// Let's assume we're connected | 
						|
			char buffer[256+1]; | 
						|
			sprintf(buffer, "Connected as client \"%s\"", context->m_clientName); | 
						|
			sTrace(context, buffer); | 
						|
			context->m_hasReceivedHello = USYNERGY_TRUE; | 
						|
		} | 
						|
		return; | 
						|
	} | 
						|
	else if (USYNERGY_IS_PACKET("QINF")) | 
						|
	{ | 
						|
		// Screen info. Reply with DINF | 
						|
		//		kMsgQInfo			= "QINF" | 
						|
		//		kMsgDInfo			= "DINF%2i%2i%2i%2i%2i%2i%2i" | 
						|
		uint16_t x = 0, y = 0, warp = 0; | 
						|
		sAddString(context, "DINF"); | 
						|
		sAddUInt16(context, x); | 
						|
		sAddUInt16(context, y); | 
						|
		sAddUInt16(context, context->m_clientWidth); | 
						|
		sAddUInt16(context, context->m_clientHeight); | 
						|
		sAddUInt16(context, warp); | 
						|
		sAddUInt16(context, 0);		// mx? | 
						|
		sAddUInt16(context, 0);		// my? | 
						|
		sSendReply(context); | 
						|
		return; | 
						|
	} | 
						|
	else if (USYNERGY_IS_PACKET("CIAK")) | 
						|
	{ | 
						|
		// Do nothing? | 
						|
		//		kMsgCInfoAck		= "CIAK" | 
						|
		return; | 
						|
	} | 
						|
	else if (USYNERGY_IS_PACKET("CROP")) | 
						|
	{ | 
						|
		// Do nothing? | 
						|
		//		kMsgCResetOptions	= "CROP" | 
						|
		return; | 
						|
	} | 
						|
	else if (USYNERGY_IS_PACKET("CINN")) | 
						|
	{ | 
						|
		// Screen enter. Reply with CNOP | 
						|
		//		kMsgCEnter 			= "CINN%2i%2i%4i%2i" | 
						|
 | 
						|
		// Obtain the Synergy sequence number | 
						|
		context->m_sequenceNumber = sNetToNative32(message + 12); | 
						|
		context->m_isCaptured = USYNERGY_TRUE; | 
						|
 | 
						|
		// Call callback | 
						|
		if (context->m_screenActiveCallback != 0L) | 
						|
			context->m_screenActiveCallback(context->m_cookie, USYNERGY_TRUE); | 
						|
	} | 
						|
	else if (USYNERGY_IS_PACKET("COUT")) | 
						|
	{ | 
						|
		// Screen leave | 
						|
		//		kMsgCLeave 			= "COUT" | 
						|
		context->m_isCaptured = USYNERGY_FALSE; | 
						|
 | 
						|
		// Call callback | 
						|
		if (context->m_screenActiveCallback != 0L) | 
						|
			context->m_screenActiveCallback(context->m_cookie, USYNERGY_FALSE); | 
						|
	} | 
						|
	else if (USYNERGY_IS_PACKET("DMDN")) | 
						|
	{ | 
						|
		// Mouse down | 
						|
		//		kMsgDMouseDown		= "DMDN%1i" | 
						|
		char btn = message[8]-1; | 
						|
		if (btn==2) | 
						|
			context->m_mouseButtonRight		= USYNERGY_TRUE; | 
						|
		else if (btn==1) | 
						|
			context->m_mouseButtonMiddle	= USYNERGY_TRUE; | 
						|
		else | 
						|
			context->m_mouseButtonLeft		= USYNERGY_TRUE; | 
						|
		sSendMouseCallback(context); | 
						|
	} | 
						|
	else if (USYNERGY_IS_PACKET("DMUP")) | 
						|
	{ | 
						|
		// Mouse up | 
						|
		//		kMsgDMouseUp		= "DMUP%1i" | 
						|
		char btn = message[8]-1; | 
						|
		if (btn==2) | 
						|
			context->m_mouseButtonRight		= USYNERGY_FALSE; | 
						|
		else if (btn==1) | 
						|
			context->m_mouseButtonMiddle	= USYNERGY_FALSE; | 
						|
		else | 
						|
			context->m_mouseButtonLeft		= USYNERGY_FALSE; | 
						|
		sSendMouseCallback(context); | 
						|
	} | 
						|
	else if (USYNERGY_IS_PACKET("DMMV")) | 
						|
	{ | 
						|
		// Mouse move. Reply with CNOP | 
						|
		//		kMsgDMouseMove		= "DMMV%2i%2i" | 
						|
		context->m_mouseX = sNetToNative16(message+8); | 
						|
		context->m_mouseY = sNetToNative16(message+10); | 
						|
		sSendMouseCallback(context); | 
						|
	} | 
						|
	else if (USYNERGY_IS_PACKET("DMWM")) | 
						|
	{ | 
						|
		// Mouse wheel | 
						|
		//		kMsgDMouseWheel		= "DMWM%2i%2i" | 
						|
		//		kMsgDMouseWheel1_0	= "DMWM%2i" | 
						|
		context->m_mouseWheelX += sNetToNative16(message+8); | 
						|
		context->m_mouseWheelY += sNetToNative16(message+10); | 
						|
		sSendMouseCallback(context); | 
						|
	} | 
						|
	else if (USYNERGY_IS_PACKET("DKDN")) | 
						|
	{ | 
						|
		// Key down | 
						|
		//		kMsgDKeyDown		= "DKDN%2i%2i%2i" | 
						|
		//		kMsgDKeyDown1_0		= "DKDN%2i%2i" | 
						|
		//uint16_t id = sNetToNative16(message+8); | 
						|
		uint16_t mod = sNetToNative16(message+10); | 
						|
		uint16_t key = sNetToNative16(message+12); | 
						|
		sSendKeyboardCallback(context, key, mod, USYNERGY_TRUE, USYNERGY_FALSE); | 
						|
	} | 
						|
	else if (USYNERGY_IS_PACKET("DKRP")) | 
						|
	{ | 
						|
		// Key repeat | 
						|
		//		kMsgDKeyRepeat		= "DKRP%2i%2i%2i%2i" | 
						|
		//		kMsgDKeyRepeat1_0	= "DKRP%2i%2i%2i" | 
						|
		uint16_t mod = sNetToNative16(message+10); | 
						|
//		uint16_t count = sNetToNative16(message+12); | 
						|
		uint16_t key = sNetToNative16(message+14); | 
						|
		sSendKeyboardCallback(context, key, mod, USYNERGY_TRUE, USYNERGY_TRUE); | 
						|
	} | 
						|
	else if (USYNERGY_IS_PACKET("DKUP")) | 
						|
	{ | 
						|
		// Key up | 
						|
		//		kMsgDKeyUp			= "DKUP%2i%2i%2i" | 
						|
		//		kMsgDKeyUp1_0		= "DKUP%2i%2i" | 
						|
		//uint16 id=Endian::sNetToNative(sbuf[4]); | 
						|
		uint16_t mod = sNetToNative16(message+10); | 
						|
		uint16_t key = sNetToNative16(message+12); | 
						|
		sSendKeyboardCallback(context, key, mod, USYNERGY_FALSE, USYNERGY_FALSE); | 
						|
	} | 
						|
	else if (USYNERGY_IS_PACKET("DGBT")) | 
						|
	{ | 
						|
		// Joystick buttons | 
						|
		//		kMsgDGameButtons	= "DGBT%1i%2i"; | 
						|
		uint8_t	joy_num = message[8]; | 
						|
		if (joy_num<USYNERGY_NUM_JOYSTICKS) | 
						|
		{ | 
						|
			// Copy button state, then send callback | 
						|
			context->m_joystickButtons[joy_num] = (message[9] << 8) | message[10]; | 
						|
			sSendJoystickCallback(context, joy_num); | 
						|
		} | 
						|
	} | 
						|
	else if (USYNERGY_IS_PACKET("DGST")) | 
						|
	{ | 
						|
		// Joystick sticks | 
						|
		//		kMsgDGameSticks		= "DGST%1i%1i%1i%1i%1i"; | 
						|
		uint8_t	joy_num = message[8]; | 
						|
		if (joy_num<USYNERGY_NUM_JOYSTICKS) | 
						|
		{ | 
						|
			// Copy stick state, then send callback | 
						|
			memcpy(context->m_joystickSticks[joy_num], message+9, 4); | 
						|
			sSendJoystickCallback(context, joy_num); | 
						|
		} | 
						|
	} | 
						|
	else if (USYNERGY_IS_PACKET("DSOP")) | 
						|
	{ | 
						|
		// Set options | 
						|
		//		kMsgDSetOptions		= "DSOP%4I" | 
						|
	} | 
						|
	else if (USYNERGY_IS_PACKET("CALV")) | 
						|
	{ | 
						|
		// Keepalive, reply with CALV and then CNOP | 
						|
		//		kMsgCKeepAlive		= "CALV" | 
						|
		sAddString(context, "CALV"); | 
						|
		sSendReply(context); | 
						|
		// now reply with CNOP | 
						|
	} | 
						|
	else if (USYNERGY_IS_PACKET("DCLP")) | 
						|
	{ | 
						|
		// Clipboard message | 
						|
		//		kMsgDClipboard		= "DCLP%1i%4i%s" | 
						|
		// | 
						|
		// The clipboard message contains: | 
						|
		//		1 uint32:	The size of the message | 
						|
		//		4 chars: 	The identifier ("DCLP") | 
						|
		//		1 uint8: 	The clipboard index | 
						|
		//		1 uint32:	The sequence number. It's zero, because this message is always coming from the server? | 
						|
		//		1 uint32:	The total size of the remaining 'string' (as per the Synergy %s string format (which is 1 uint32 for size followed by a char buffer (not necessarily null terminated)). | 
						|
		//		1 uint32:	The number of formats present in the message | 
						|
		// And then 'number of formats' times the following: | 
						|
		//		1 uint32:	The format of the clipboard data | 
						|
		//		1 uint32:	The size n of the clipboard data | 
						|
		//		n uint8:	The clipboard data | 
						|
		const uint8_t *	parse_msg	= message+17; | 
						|
		uint32_t		num_formats = sNetToNative32(parse_msg); | 
						|
		parse_msg += 4; | 
						|
		for (; num_formats; num_formats--) | 
						|
		{ | 
						|
			// Parse clipboard format header | 
						|
			uint32_t format	= sNetToNative32(parse_msg); | 
						|
			uint32_t size	= sNetToNative32(parse_msg+4); | 
						|
			parse_msg += 8; | 
						|
			 | 
						|
			// Call callback | 
						|
			if (context->m_clipboardCallback) | 
						|
				context->m_clipboardCallback(context->m_cookie, format, parse_msg, size); | 
						|
 | 
						|
			parse_msg += size; | 
						|
		} | 
						|
	} | 
						|
	else | 
						|
	{ | 
						|
		// Unknown packet, could be any of these | 
						|
		//		kMsgCNoop 			= "CNOP" | 
						|
		//		kMsgCClose 			= "CBYE" | 
						|
		//		kMsgCClipboard 		= "CCLP%1i%4i" | 
						|
		//		kMsgCScreenSaver 	= "CSEC%1i" | 
						|
		//		kMsgDKeyRepeat		= "DKRP%2i%2i%2i%2i" | 
						|
		//		kMsgDKeyRepeat1_0	= "DKRP%2i%2i%2i" | 
						|
		//		kMsgDMouseRelMove	= "DMRM%2i%2i" | 
						|
		//		kMsgEIncompatible	= "EICV%2i%2i" | 
						|
		//		kMsgEBusy 			= "EBSY" | 
						|
		//		kMsgEUnknown		= "EUNK" | 
						|
		//		kMsgEBad			= "EBAD" | 
						|
		char buffer[64]; | 
						|
		sprintf(buffer, "Unknown packet '%c%c%c%c'", message[4], message[5], message[6], message[7]); | 
						|
		sTrace(context, buffer); | 
						|
		return; | 
						|
	} | 
						|
 | 
						|
	// Reply with CNOP maybe? | 
						|
	sAddString(context, "CNOP"); | 
						|
	sSendReply(context); | 
						|
} | 
						|
#undef USYNERGY_IS_PACKET | 
						|
 | 
						|
 | 
						|
 | 
						|
/** | 
						|
@brief Mark context as being disconnected | 
						|
**/ | 
						|
static void sSetDisconnected(uSynergyContext *context) | 
						|
{ | 
						|
	context->m_connected		= USYNERGY_FALSE; | 
						|
	context->m_hasReceivedHello = USYNERGY_FALSE; | 
						|
	context->m_isCaptured		= USYNERGY_FALSE; | 
						|
	context->m_replyCur			= context->m_replyBuffer + 4; | 
						|
	context->m_sequenceNumber	= 0; | 
						|
} | 
						|
 | 
						|
 | 
						|
 | 
						|
/** | 
						|
@brief Update a connected context | 
						|
**/ | 
						|
static void sUpdateContext(uSynergyContext *context) | 
						|
{ | 
						|
	/* Receive data (blocking) */ | 
						|
	int receive_size = USYNERGY_RECEIVE_BUFFER_SIZE - context->m_receiveOfs; | 
						|
	int num_received = 0; | 
						|
	int packlen = 0; | 
						|
	if (context->m_receiveFunc(context->m_cookie, context->m_receiveBuffer + context->m_receiveOfs, receive_size, &num_received) == USYNERGY_FALSE) | 
						|
	{ | 
						|
		/* Receive failed, let's try to reconnect */ | 
						|
		char buffer[128]; | 
						|
		sprintf(buffer, "Receive failed (%d bytes asked, %d bytes received), trying to reconnect in a second", receive_size, num_received); | 
						|
		sTrace(context, buffer); | 
						|
		sSetDisconnected(context); | 
						|
		context->m_sleepFunc(context->m_cookie, 1000); | 
						|
		return; | 
						|
	} | 
						|
	context->m_receiveOfs += num_received; | 
						|
 | 
						|
	/*	If we didn't receive any data then we're probably still polling to get connected and | 
						|
		therefore not getting any data back. To avoid overloading the system with a Synergy | 
						|
		thread that would hammer on polling, we let it rest for a bit if there's no data. */ | 
						|
	if (num_received == 0) | 
						|
		context->m_sleepFunc(context->m_cookie, 500); | 
						|
 | 
						|
	/* Check for timeouts */ | 
						|
	if (context->m_hasReceivedHello) | 
						|
	{ | 
						|
		uint32_t cur_time = context->m_getTimeFunc(); | 
						|
		if (num_received == 0) | 
						|
		{ | 
						|
			/* Timeout after 2 secs of inactivity (we received no CALV) */ | 
						|
			if ((cur_time - context->m_lastMessageTime) > USYNERGY_IDLE_TIMEOUT) | 
						|
				sSetDisconnected(context); | 
						|
		} | 
						|
		else | 
						|
			context->m_lastMessageTime = cur_time; | 
						|
	} | 
						|
 | 
						|
	/* Eat packets */ | 
						|
	for (;;) | 
						|
	{ | 
						|
		/* Grab packet length and bail out if the packet goes beyond the end of the buffer */ | 
						|
		packlen = sNetToNative32(context->m_receiveBuffer); | 
						|
		if (packlen+4 > context->m_receiveOfs) | 
						|
			break; | 
						|
 | 
						|
		/* Process message */ | 
						|
		sProcessMessage(context, context->m_receiveBuffer); | 
						|
 | 
						|
		/* Move packet to front of buffer */ | 
						|
		memmove(context->m_receiveBuffer, context->m_receiveBuffer+packlen+4, context->m_receiveOfs-packlen-4); | 
						|
		context->m_receiveOfs -= packlen+4; | 
						|
	} | 
						|
 | 
						|
	/* Throw away over-sized packets */ | 
						|
	if (packlen > USYNERGY_RECEIVE_BUFFER_SIZE) | 
						|
	{ | 
						|
		/* Oversized packet, ditch tail end */ | 
						|
		char buffer[128]; | 
						|
		sprintf(buffer, "Oversized packet: '%c%c%c%c' (length %d)", context->m_receiveBuffer[4], context->m_receiveBuffer[5], context->m_receiveBuffer[6], context->m_receiveBuffer[7], packlen); | 
						|
		sTrace(context, buffer); | 
						|
		num_received = context->m_receiveOfs-4; // 4 bytes for the size field | 
						|
		while (num_received != packlen) | 
						|
		{ | 
						|
			int buffer_left = packlen - num_received; | 
						|
			int to_receive = buffer_left < USYNERGY_RECEIVE_BUFFER_SIZE ? buffer_left : USYNERGY_RECEIVE_BUFFER_SIZE; | 
						|
			int ditch_received = 0; | 
						|
			if (context->m_receiveFunc(context->m_cookie, context->m_receiveBuffer, to_receive, &ditch_received) == USYNERGY_FALSE) | 
						|
			{ | 
						|
				/* Receive failed, let's try to reconnect */ | 
						|
				sTrace(context, "Receive failed, trying to reconnect in a second"); | 
						|
				sSetDisconnected(context); | 
						|
				context->m_sleepFunc(context->m_cookie, 1000); | 
						|
				break; | 
						|
			} | 
						|
			else | 
						|
			{ | 
						|
				num_received += ditch_received; | 
						|
			} | 
						|
		} | 
						|
		context->m_receiveOfs = 0; | 
						|
	} | 
						|
} | 
						|
 | 
						|
 | 
						|
//--------------------------------------------------------------------------------------------------------------------- | 
						|
//	Public interface | 
						|
//--------------------------------------------------------------------------------------------------------------------- | 
						|
 | 
						|
 | 
						|
 | 
						|
/** | 
						|
@brief Initialize uSynergy context | 
						|
**/ | 
						|
void uSynergyInit(uSynergyContext *context) | 
						|
{ | 
						|
	/* Zero memory */ | 
						|
	memset(context, 0, sizeof(uSynergyContext)); | 
						|
 | 
						|
	/* Initialize to default state */ | 
						|
	sSetDisconnected(context); | 
						|
} | 
						|
 | 
						|
 | 
						|
/** | 
						|
@brief Update uSynergy | 
						|
**/ | 
						|
void uSynergyUpdate(uSynergyContext *context) | 
						|
{ | 
						|
	if (context->m_connected) | 
						|
	{ | 
						|
		/* Update context, receive data, call callbacks */ | 
						|
		sUpdateContext(context); | 
						|
	} | 
						|
	else | 
						|
	{ | 
						|
		/* Try to connect */ | 
						|
		if (context->m_connectFunc(context->m_cookie)) | 
						|
			context->m_connected = USYNERGY_TRUE; | 
						|
	} | 
						|
} | 
						|
 | 
						|
 | 
						|
 | 
						|
/** | 
						|
@brief Send clipboard data | 
						|
**/ | 
						|
void uSynergySendClipboard(uSynergyContext *context, const char *text) | 
						|
{ | 
						|
	// Calculate maximum size that will fit in a reply packet | 
						|
	uint32_t overhead_size =	4 +					/* Message size */ | 
						|
								4 +					/* Message ID */ | 
						|
								1 +					/* Clipboard index */ | 
						|
								4 +					/* Sequence number */ | 
						|
								4 +					/* Rest of message size (because it's a Synergy string from here on) */ | 
						|
								4 +					/* Number of clipboard formats */ | 
						|
								4 +					/* Clipboard format */ | 
						|
								4;					/* Clipboard data length */ | 
						|
	uint32_t max_length = USYNERGY_REPLY_BUFFER_SIZE - overhead_size; | 
						|
	 | 
						|
	// Clip text to max length | 
						|
	uint32_t text_length = (uint32_t)strlen(text); | 
						|
	if (text_length > max_length) | 
						|
	{ | 
						|
		char buffer[128]; | 
						|
		sprintf(buffer, "Clipboard buffer too small, clipboard truncated at %d characters", max_length); | 
						|
		sTrace(context, buffer); | 
						|
		text_length = max_length; | 
						|
	} | 
						|
 | 
						|
	// Assemble packet | 
						|
	sAddString(context, "DCLP"); | 
						|
	sAddUInt8(context, 0);							/* Clipboard index */ | 
						|
	sAddUInt32(context, context->m_sequenceNumber); | 
						|
	sAddUInt32(context, 4+4+4+text_length);			/* Rest of message size: numFormats, format, length, data */ | 
						|
	sAddUInt32(context, 1);							/* Number of formats (only text for now) */ | 
						|
	sAddUInt32(context, USYNERGY_CLIPBOARD_FORMAT_TEXT); | 
						|
	sAddUInt32(context, text_length); | 
						|
	sAddString(context, text); | 
						|
	sSendReply(context); | 
						|
}
 | 
						|
 |