Home | History | Annotate | Download | only in VisualNaCro
      1 #include <assert.h>
      2 #include <string.h>
      3 #include <rfb/rfb.h>
      4 #include <rfb/rfbclient.h>
      5 
      6 #include "nacro.h"
      7 
      8 /* for visual grepping */
      9 typedef struct image_t {
     10 	int width,height;
     11 	char* buffer;
     12 } image_t;
     13 
     14 /* this is a VNC connection */
     15 typedef struct private_resource_t {
     16 	int listen_port;
     17 	rfbScreenInfo* server;
     18 	rfbClient* client;
     19 
     20 	uint32_t keysym;
     21 	rfbBool keydown;
     22 
     23 	int x,y;
     24 	int buttons;
     25 
     26 	char* text_client;
     27 	char* text_server;
     28 
     29 	image_t* grep_image;
     30 	int x_origin,y_origin;
     31 
     32 	enum { SLEEP,VISUALGREP,WAITFORUPDATE } state;
     33 	result_t result;
     34 } private_resource_t;
     35 
     36 /* resource management */
     37 
     38 #define MAX_RESOURCE_COUNT 20
     39 
     40 static private_resource_t resource_pool[MAX_RESOURCE_COUNT];
     41 static int resource_count=0;
     42 
     43 static private_resource_t* get_resource(int resource)
     44 {
     45 	if(resource>=MAX_RESOURCE_COUNT || resource<0 || resource_pool[resource].client==0)
     46 		return NULL;
     47 	return resource_pool+resource;
     48 }
     49 
     50 static private_resource_t* get_next_resource(void)
     51 {
     52 	if(resource_count<MAX_RESOURCE_COUNT) {
     53 		memset(resource_pool+resource_count,0,sizeof(private_resource_t));
     54 		resource_count++;
     55 		return resource_pool+resource_count-1;
     56 	} else {
     57 		int i;
     58 
     59 		for(i=0;i<MAX_RESOURCE_COUNT && resource_pool[i].client;i++);
     60 		if(i<MAX_RESOURCE_COUNT)
     61 			return resource_pool+i;
     62 	}
     63 	return NULL;
     64 }
     65 
     66 static void free_resource(int resource)
     67 {
     68 	private_resource_t* res=get_resource(resource);
     69 	if(res)
     70 		res->client=NULL;
     71 }
     72 
     73 /* hooks */
     74 
     75 static void got_key(rfbBool down,rfbKeySym keysym,rfbClientRec* cl)
     76 {
     77 	private_resource_t* res=(private_resource_t*)cl->screen->screenData;
     78 
     79 	res->keydown=down;
     80 	res->keysym=keysym;
     81 	res->result|=RESULT_KEY;
     82 }
     83 
     84 static void got_mouse(int buttons,int x,int y,rfbClientRec* cl)
     85 {
     86 	private_resource_t* res=(private_resource_t*)cl->screen->screenData;
     87 
     88 	res->buttons=buttons;
     89 	res->x=x;
     90 	res->y=y;
     91 	res->result|=RESULT_MOUSE;
     92 }
     93 
     94 static void got_text(char* str,int len,rfbClientRec* cl)
     95 {
     96 	private_resource_t* res=(private_resource_t*)cl->screen->screenData;
     97 
     98 	if (res->text_client)
     99 		free(res->text_client);
    100 	res->text_client=strdup(str);
    101 	res->result|=RESULT_TEXT_CLIENT;
    102 }
    103 
    104 static void got_text_from_server(rfbClient* cl, const char *str, int textlen)
    105 {
    106 	private_resource_t* res=(private_resource_t*)cl->clientData;
    107 
    108 	if (res->text_server)
    109 		free(res->text_server);
    110 	res->text_server=strdup(str);
    111 	res->result|=RESULT_TEXT_SERVER;
    112 }
    113 
    114 static rfbBool malloc_frame_buffer(rfbClient* cl)
    115 {
    116 	private_resource_t* res=(private_resource_t*)cl->clientData;
    117 
    118 	if(!res->server) {
    119 		int w=cl->width,h=cl->height;
    120 
    121 		res->client->frameBuffer=malloc(w*4*h);
    122 
    123 		res->server=rfbGetScreen(NULL,NULL,w,h,8,3,4);
    124 		if(!res->server)
    125                   return FALSE;
    126 		res->server->screenData=res;
    127 		res->server->port=res->listen_port;
    128 		res->server->frameBuffer=res->client->frameBuffer;
    129 		res->server->kbdAddEvent=got_key;
    130 		res->server->ptrAddEvent=got_mouse;
    131 		res->server->setXCutText=got_text;
    132 		rfbInitServer(res->server);
    133 	} else {
    134 		/* TODO: realloc if necessary */
    135 		/* TODO: resolution change: send NewFBSize */
    136 		/* TODO: if the origin is out of bounds, reset to 0 */
    137 	}
    138 }
    139 
    140 static bool_t do_visual_grep(private_resource_t* res,int x,int y,int w,int h)
    141 {
    142 	rfbClient* cl;
    143 	image_t* image;
    144 	int x_start,y_start,x_end=x+w-1,y_end=y+h-1;
    145 	bool_t found=0;
    146 
    147 	if(res==0 || (cl=res->client)==0 || (image=res->grep_image)==0)
    148 		return 0;
    149 
    150 	x_start=x-image->width;
    151 	y_start=y-image->height;
    152 	if(x_start<0) x_start=0;
    153 	if(y_start<0) y_start=0;
    154 	if(x_end+image->width>cl->width) x_end=cl->width-image->width;
    155 	if(y_end+image->height>cl->height) y_end=cl->height-image->height;
    156 
    157 	/* find image and set x_origin,y_origin if found */
    158 	for(y=y_start;y<y_end;y++)
    159 		for(x=x_start;x<x_end;x++) {
    160 			bool_t matching=1;
    161 			int i,j;
    162 			for(j=0;matching && j<image->height;j++)
    163 				for(i=0;matching && i<image->width;i++)
    164 					if(memcmp(cl->frameBuffer+4*(x+i+cl->width*(y+j)),image->buffer+4*(i+image->width*j),3))
    165 						matching=0;
    166 			if(matching) {
    167 				private_resource_t* res=(private_resource_t*)cl->clientData;
    168 				res->x_origin=x;
    169 				res->y_origin=y;
    170 				return -1;
    171 			}
    172 		}
    173 	return 0;
    174 }
    175 
    176 static void got_frame_buffer(rfbClient* cl,int x,int y,int w,int h)
    177 {
    178 	private_resource_t* res=(private_resource_t*)cl->clientData;
    179 
    180 	assert(res->server);
    181 
    182 	if(res->grep_image && do_visual_grep(res,x,y,w,h)) {
    183 		res->result|=RESULT_FOUNDIMAGE;
    184 	}
    185 	if(res->server) {
    186 		rfbMarkRectAsModified(res->server,x,y,x+w,y+h);
    187 	}
    188 
    189 	res->result|=RESULT_SCREEN;
    190 }
    191 
    192 /* init/shutdown functions */
    193 
    194 resource_t initvnc(const char* server,int server_port,int listen_port)
    195 {
    196 	private_resource_t* res=get_next_resource();
    197 	int dummy=0;
    198 
    199 	if(res==0)
    200 		return -1;
    201 
    202 	/* remember for later */
    203 	res->listen_port=listen_port;
    204 
    205 	res->text_client = NULL;
    206 	res->text_server = NULL;
    207 
    208 	res->client=rfbGetClient(8,3,4);
    209 	res->client->clientData=(void*)res;
    210 	res->client->GotFrameBufferUpdate=got_frame_buffer;
    211 	res->client->MallocFrameBuffer=malloc_frame_buffer;
    212 	res->client->GotXCutText=got_text_from_server;
    213 	res->client->serverHost=strdup(server);
    214 	res->client->serverPort=server_port;
    215 	res->client->appData.encodingsString="raw";
    216 	if(!rfbInitClient(res->client,&dummy,NULL)) {
    217 		res->client=NULL;
    218 		return -1;
    219 	}
    220 	return res-resource_pool;
    221 }
    222 
    223 void closevnc(resource_t resource)
    224 {
    225 	private_resource_t* res=get_resource(resource);
    226 	if(res==0)
    227 		return;
    228 
    229 	if(res->server)
    230 		rfbScreenCleanup(res->server);
    231 
    232 	assert(res->client);
    233 
    234 	rfbClientCleanup(res->client);
    235 
    236 	res->client=NULL;
    237 }
    238 
    239 /* PNM (image) helpers */
    240 
    241 bool_t savepnm(resource_t resource,const char* filename,int x1,int y1,int x2,int y2)
    242 {
    243 	private_resource_t* res=get_resource(resource);
    244 	int i,j,w,h;
    245 	uint32_t* buffer;
    246 	FILE* f;
    247 
    248 	if(res==0 || res->client==0)
    249 		return 0;
    250 	assert(res->client->format.depth==24);
    251 
    252 	w=res->client->width;
    253 	h=res->client->height;
    254 	buffer=(uint32_t*)res->client->frameBuffer;
    255 
    256 	if(res==0 || x1>x2 || y1>y2 || x1<0 || x2>=w || y1<0 || y2>=h)
    257 		return FALSE;
    258 
    259 	f=fopen(filename,"wb");
    260 
    261 	if(f==0)
    262 		return FALSE;
    263 
    264 	fprintf(f,"P6\n%d %d\n255\n",1+x2-x1,1+y2-y1);
    265 	for(j=y1;j<=y2;j++)
    266 		for(i=x1;i<=x2;i++) {
    267 			fwrite(buffer+i+j*w,3,1,f);
    268 		}
    269 	if(fclose(f))
    270 		return FALSE;
    271 	return TRUE;
    272 }
    273 
    274 static image_t* loadpnm(const char* filename)
    275 {
    276 	FILE* f=fopen(filename,"rb");
    277 	char buffer[1024];
    278 	int i,j,w,h;
    279 	image_t* image;
    280 
    281 	if(f==0)
    282 		return NULL;
    283 
    284 	if(!fgets(buffer,1024,f) || strcmp("P6\n",buffer)) {
    285 		fclose(f);
    286 		return NULL;
    287 	}
    288 
    289 	do {
    290 		fgets(buffer,1024,f);
    291 		if(feof(f)) {
    292 			fclose(f);
    293 			return NULL;
    294 		}
    295 	} while(buffer[0]=='#');
    296 
    297 	if( sscanf(buffer,"%d %d",&w,&h)!=2
    298 			|| !fgets(buffer,1024,f) || strcmp("255\n",buffer)) {
    299 		fclose(f);
    300 		return NULL;
    301 	}
    302 
    303 	image=(image_t*)malloc(sizeof(image_t));
    304 	image->width=w;
    305 	image->height=h;
    306 	image->buffer=malloc(w*4*h);
    307 	if(!image->buffer) {
    308 		fclose(f);
    309 		free(image);
    310 		return NULL;
    311 	}
    312 
    313 	for(j=0;j<h;j++)
    314 		for(i=0;i<w;i++)
    315 			if(fread(image->buffer+4*(i+w*j),3,1,f)!=1) {
    316 				fprintf(stderr,"Could not read 3 bytes at %d,%d\n",i,j);
    317 				fclose(f);
    318 				free(image->buffer);
    319 				free(image);
    320 				return NULL;
    321 			}
    322 
    323 	fclose(f);
    324 
    325 	return image;
    326 }
    327 
    328 static void free_image(image_t* image)
    329 {
    330 	if(image->buffer)
    331 		free(image->buffer);
    332 	free(image);
    333 }
    334 
    335 static void copy_line(rfbScreenInfo *dest, char *backup,
    336 		int x0, int y0, int x1, int y1, int color_offset)
    337 {
    338 	uint8_t *d = (uint8_t *)dest->frameBuffer, *s = (uint8_t *)backup;
    339 	int i;
    340 	int steps0 = x1 > x0 ? x1 - x0 : x0 - x1;
    341 	int steps1 = y1 > y0 ? y1 - y0 : y0 - y1;
    342 
    343 	if (steps1 > steps0)
    344 		steps0 = steps1;
    345 	else if (steps0 == 0)
    346 		steps0 = 1;
    347 
    348 	for (i = 0; i <= steps0; i++) {
    349 		int j, index = 4 * (x0 + i * (x1 - x0) / steps0
    350 				+ dest->width * (y0 + i * (y1 - y0) / steps0));
    351 		for (j = 0; j < 4; j++)
    352 			d[index + j] = s[index + j] + color_offset;
    353 	}
    354 
    355 	rfbMarkRectAsModified(dest, x0 - 5, y0 - 5, x1 + 1, y1 + 2);
    356 }
    357 
    358 result_t displaypnm(resource_t resource, const char *filename,
    359 		coordinate_t x, coordinate_t y, bool_t border,
    360 		timeout_t timeout_in_seconds)
    361 {
    362 	private_resource_t* res = get_resource(resource);
    363 	image_t *image;
    364 	char* fake_frame_buffer;
    365 	char* backup;
    366 	int w, h, i, j, w2, h2;
    367 	result_t result;
    368 
    369 	if (res == NULL || res->server == NULL ||
    370 			(image = loadpnm(filename)) == NULL)
    371 		return 0;
    372 
    373 	w = res->server->width;
    374 	h = res->server->height;
    375 	fake_frame_buffer = malloc(w * 4 * h);
    376 	if(!fake_frame_buffer)
    377 		return 0;
    378 	memcpy(fake_frame_buffer, res->server->frameBuffer, w * 4 * h);
    379 
    380 	backup = res->server->frameBuffer;
    381 	res->server->frameBuffer = fake_frame_buffer;
    382 
    383 	w2 = image->width;
    384 	if (x + w2 > w)
    385 		w2 = w - x;
    386 	h2 = image->height;
    387 	if (y + h2 > h)
    388 		h2 = h - y;
    389 	for (j = 0; j < h2; j++)
    390 		memcpy(fake_frame_buffer + 4 * (x + (y + j) * w),
    391 			image->buffer + j * 4 * image->width, 4 * w2);
    392 	free(image);
    393 	if (border) {
    394 		copy_line(res->server, backup, x, y, x + w2, y, 0x80);
    395 		copy_line(res->server, backup, x, y, x, y + h2, 0x80);
    396 		copy_line(res->server, backup, x + w2, y, x + w2, y + h2, 0x80);
    397 		copy_line(res->server, backup, x, y + h2, x + w2, y + h2, 0x80);
    398 	}
    399 	rfbMarkRectAsModified(res->server,
    400 			x - 1, y - 1, x + w2 + 1, y + h2 + 1);
    401 
    402 	result = waitforinput(resource, timeout_in_seconds);
    403 
    404 	res->server->frameBuffer=backup;
    405 	free(fake_frame_buffer);
    406 	rfbMarkRectAsModified(res->server,
    407 			x - 1, y - 1, x + w2 + 1, y + h2 + 1);
    408 
    409 	return result;
    410 }
    411 
    412 /* process() and friends */
    413 
    414 /* this function returns only if res->result in return_mask */
    415 static result_t private_process(resource_t resource,timeout_t timeout_in_seconds,result_t return_mask)
    416 {
    417 	private_resource_t* res=get_resource(resource);
    418 	fd_set fds;
    419 	struct timeval tv,tv_start,tv_end;
    420 	unsigned long timeout=(unsigned long)(timeout_in_seconds*1000000UL);
    421 	int count,max_fd;
    422 
    423 	if(res==0)
    424 		return 0;
    425 
    426 	assert(res->client);
    427 
    428 	gettimeofday(&tv_start,NULL);
    429 	res->result=0;
    430 
    431 	do {
    432 		unsigned long timeout_done;
    433 
    434 		if(res->server) {
    435 			rfbBool loop;
    436 			do {
    437 				loop=rfbProcessEvents(res->server,res->server->deferUpdateTime);
    438 			} while(loop && (res->result&return_mask)==0
    439 				&& rfbIsActive(res->server));
    440 
    441 			if(!rfbIsActive(res->server))
    442 				return RESULT_SHUTDOWN;
    443 
    444 			if((res->result&return_mask)!=0)
    445 				return res->result;
    446 
    447 			memcpy((char*)&fds,(const char*)&(res->server->allFds),sizeof(fd_set));
    448 			max_fd=res->server->maxFd;
    449 		} else {
    450 			FD_ZERO(&fds);
    451 			max_fd=0;
    452 		}
    453 		FD_SET(res->client->sock,&fds);
    454 		if(res->client->sock>max_fd)
    455 			max_fd=res->client->sock;
    456 
    457 		gettimeofday(&tv_end,NULL);
    458 		timeout_done=tv_end.tv_usec-tv_start.tv_usec+
    459 			1000000L*(tv_end.tv_sec-tv_start.tv_sec);
    460 		if(timeout_done>=timeout)
    461 			return RESULT_TIMEOUT;
    462 
    463 		tv.tv_usec=((timeout-timeout_done)%1000000);
    464 		tv.tv_sec=(timeout-timeout_done)/1000000;
    465 
    466 		count=select(max_fd+1,&fds,NULL,NULL,&tv);
    467 		if(count<0)
    468 			return 0;
    469 
    470 		if(count>0) {
    471 			if(FD_ISSET(res->client->sock,&fds)) {
    472 				if(!HandleRFBServerMessage(res->client)) {
    473 					closevnc(resource);
    474 					return 0;
    475 				}
    476 				if((res->result&return_mask)!=0)
    477 					return res->result;
    478 			}
    479 		} else {
    480 			res->result|=RESULT_TIMEOUT;
    481 			return res->result;
    482 		}
    483 	} while(1);
    484 
    485 	return RESULT_TIMEOUT;
    486 }
    487 
    488 result_t process(resource_t res,timeout_t timeout)
    489 {
    490 	return private_process(res,timeout,RESULT_TIMEOUT);
    491 }
    492 
    493 result_t waitforanything(resource_t res,timeout_t timeout)
    494 {
    495 	return private_process(res,timeout,-1);
    496 }
    497 
    498 result_t waitforinput(resource_t res,timeout_t timeout)
    499 {
    500 	return private_process(res,timeout,RESULT_KEY|RESULT_MOUSE|RESULT_TIMEOUT);
    501 }
    502 
    503 result_t waitforupdate(resource_t res,timeout_t timeout)
    504 {
    505 	return private_process(res,timeout,RESULT_SCREEN|RESULT_TIMEOUT);
    506 }
    507 
    508 result_t visualgrep(resource_t resource,const char* filename,timeout_t timeout)
    509 {
    510 	private_resource_t* res=get_resource(resource);
    511 	image_t* image;
    512 	result_t result;
    513 
    514 	if(res==0 || res->client==0)
    515 		return 0;
    516 
    517 	/* load filename and set res->grep_image to this image */
    518 	image=loadpnm(filename);
    519 	if(image==0)
    520 		return 0;
    521 	if(res->grep_image)
    522 		free_image(res->grep_image);
    523 	res->grep_image=image;
    524 
    525 	if(do_visual_grep(res,0,0,res->client->width,res->client->height))
    526 		return RESULT_FOUNDIMAGE;
    527 
    528 	result=private_process(resource,timeout,RESULT_FOUNDIMAGE|RESULT_TIMEOUT);
    529 
    530 	/* free image */
    531 	if(res->grep_image) {
    532 		free_image(res->grep_image);
    533 		res->grep_image=NULL;
    534 	}
    535 
    536 	return result;
    537 }
    538 
    539 /* auxiliary function for alert */
    540 
    541 #include "default8x16.h"
    542 
    543 static void center_text(rfbScreenInfo* screen,const char* message,int* x,int* y,int* w,int* h)
    544 {
    545 	rfbFontData* font=&default8x16Font;
    546 	const char* pointer;
    547 	int j,x1,y1,x2,y2,line_count=0;
    548 	if(message==0 || screen==0)
    549 		return;
    550 	rfbWholeFontBBox(font,&x1,&y1,&x2,&y2);
    551 	for(line_count=1,pointer=message;*pointer;pointer++)
    552 		if(*pointer=='\n')
    553 			line_count++;
    554 
    555 	*h=(y2-y1)*line_count;
    556 	assert(*h>0);
    557 
    558 	if(*h>screen->height)
    559 		*h=screen->height;
    560 
    561 	*x=0; *w=screen->width; *y=(screen->height-*h)/2;
    562 
    563 	rfbFillRect(screen,*x,*y,*x+*w,*y+*h,0xff0000);
    564 
    565 	for(pointer=message,j=0;j<line_count;j++) {
    566 		const char* eol;
    567 		int x_cur,y_cur=*y-y1+j*(y2-y1),width;
    568 
    569 		for(width=0,eol=pointer;*eol && *eol!='\n';eol++)
    570 			width+=rfbWidthOfChar(font,*eol);
    571 		if(width>screen->width)
    572 			width=screen->width;
    573 
    574 		x_cur=(screen->width-width)/2;
    575 		for(;pointer!=eol;pointer++)
    576 			x_cur+=rfbDrawCharWithClip(screen,font,
    577 					x_cur,y_cur,*pointer,
    578 					0,0,screen->width,screen->height,
    579 					0xffffffff,0xffffffff);
    580 		pointer++;
    581 	}
    582 	rfbMarkRectAsModified(screen,*x,*y,*x+*w,*y+*h);
    583 }
    584 
    585 /* this is an overlay which is shown for a certain time */
    586 
    587 result_t alert(resource_t resource,const char* message,timeout_t timeout)
    588 {
    589 	private_resource_t* res=get_resource(resource);
    590 	char* fake_frame_buffer;
    591 	char* backup;
    592 	int x,y,w,h;
    593 	result_t result;
    594 
    595 	if(res == NULL || res->server==NULL)
    596 		return -1;
    597 
    598 	w=res->server->width;
    599 	h=res->server->height;
    600 
    601 	fake_frame_buffer=malloc(w*4*h);
    602 	if(!fake_frame_buffer)
    603 		return -1;
    604 	memcpy(fake_frame_buffer,res->server->frameBuffer,w*4*h);
    605 
    606 	backup=res->server->frameBuffer;
    607 	res->server->frameBuffer=fake_frame_buffer;
    608 	center_text(res->server,message,&x,&y,&w,&h);
    609 	fprintf(stderr,"%s\n",message);
    610 
    611 	result=waitforinput(resource,timeout);
    612 
    613 	res->server->frameBuffer=backup;
    614 	free(fake_frame_buffer);
    615 	rfbMarkRectAsModified(res->server,x,y,x+w,y+h);
    616 
    617 	return result;
    618 }
    619 /* inspect last events */
    620 
    621 keysym_t getkeysym(resource_t res)
    622 {
    623 	private_resource_t* r=get_resource(res);
    624 	return r->keysym;
    625 }
    626 
    627 bool_t getkeydown(resource_t res)
    628 {
    629 	private_resource_t* r=get_resource(res);
    630 	return r->keydown;
    631 }
    632 
    633 coordinate_t getx(resource_t res)
    634 {
    635 	private_resource_t* r=get_resource(res);
    636 	return r->x;
    637 }
    638 
    639 coordinate_t gety(resource_t res)
    640 {
    641 	private_resource_t* r=get_resource(res);
    642 	return r->y;
    643 }
    644 
    645 buttons_t getbuttons(resource_t res)
    646 {
    647 	private_resource_t* r=get_resource(res);
    648 	return r->buttons;
    649 }
    650 
    651 const char *gettext_client(resource_t res)
    652 {
    653 	private_resource_t* r=get_resource(res);
    654 	return r->text_client;
    655 }
    656 
    657 result_t rubberband(resource_t resource, coordinate_t x0, coordinate_t y0)
    658 {
    659 	private_resource_t* res=get_resource(resource);
    660 	char* fake_frame_buffer;
    661 	char* backup;
    662 	int w, h, x, y;
    663 
    664 	if(res == NULL || res->server==NULL)
    665 		return -1;
    666 
    667 	x = res->x;
    668 	y = res->y;
    669 	w = res->server->width;
    670 	h = res->server->height;
    671 	fake_frame_buffer = malloc(w * 4 * h);
    672 	if(!fake_frame_buffer)
    673 		return 0;
    674 	memcpy(fake_frame_buffer, res->server->frameBuffer, w * 4 * h);
    675 
    676 	backup = res->server->frameBuffer;
    677 	res->server->frameBuffer = fake_frame_buffer;
    678 
    679 	while (res->buttons) {
    680 		result_t r = waitforinput(resource, 1000000L);
    681 		if (x == res->x && y == res->y)
    682 				continue;
    683 		copy_line(res->server, backup, x0, y0, x, y0, 0);
    684 		copy_line(res->server, backup, x0, y0, x0, y, 0);
    685 		copy_line(res->server, backup, x, y0, x, y, 0);
    686 		copy_line(res->server, backup, x0, y, x, y, 0);
    687 		x = res->x;
    688 		y = res->y;
    689 		copy_line(res->server, backup, x0, y0, x, y0, 0x80);
    690 		copy_line(res->server, backup, x0, y0, x0, y, 0x80);
    691 		copy_line(res->server, backup, x, y0, x, y, 0x80);
    692 		copy_line(res->server, backup, x0, y, x, y, 0x80);
    693 	}
    694 
    695 	copy_line(res->server, backup, x0, y0, x, y0, 0);
    696 	copy_line(res->server, backup, x0, y0, x0, y, 0);
    697 	copy_line(res->server, backup, x, y0, x, y, 0);
    698 	copy_line(res->server, backup, x0, y, x, y, 0);
    699 
    700 	res->server->frameBuffer=backup;
    701 	free(fake_frame_buffer);
    702 
    703 	return RESULT_MOUSE;
    704 }
    705 
    706 const char *gettext_server(resource_t res)
    707 {
    708 	private_resource_t* r=get_resource(res);
    709 	return r->text_server;
    710 }
    711 
    712 /* send events to the server */
    713 
    714 bool_t sendkey(resource_t res,keysym_t keysym,bool_t keydown)
    715 {
    716 	private_resource_t* r=get_resource(res);
    717 	if(r==NULL)
    718 		return 0;
    719 	return SendKeyEvent(r->client,keysym,keydown);
    720 }
    721 
    722 bool_t sendascii(resource_t res,const char *string)
    723 {
    724 	timeout_t delay = 0.1;
    725 	private_resource_t* r=get_resource(res);
    726 	int i;
    727 	if(r==NULL)
    728 		return 0;
    729 	while (*string) {
    730 		int keysym = *string;
    731 		int need_shift = 0;
    732 
    733 		if (keysym >= 8 && keysym < ' ')
    734 			keysym += 0xff00;
    735 		else if (keysym >= 'A' && keysym <= 'Z')
    736 			need_shift = 1;
    737 		else if (keysym > '~') {
    738 			fprintf(stderr, "String contains non-ASCII "
    739 					"character 0x%02x\n", *string);
    740 			return FALSE;
    741 		}
    742 
    743 		if (need_shift) {
    744 			if (!SendKeyEvent(r->client,0xffe1,1))
    745 				return FALSE;
    746 			waitforinput(r,delay);
    747 		}
    748 		for (i = 1; i >= 0; i--) {
    749 			if (!SendKeyEvent(r->client,keysym,i))
    750 				return FALSE;
    751 			waitforinput(r,delay);
    752 		}
    753 		if (need_shift) {
    754 			if (!SendKeyEvent(r->client,0xffe1,0))
    755 				return FALSE;
    756 			waitforinput(r,delay);
    757 		}
    758 		string++;
    759 	}
    760 	return TRUE;
    761 }
    762 
    763 bool_t sendmouse(resource_t res,coordinate_t x,coordinate_t y,buttons_t buttons)
    764 {
    765 	private_resource_t* r=get_resource(res);
    766 	if(r==NULL)
    767 		return 0;
    768 	return SendPointerEvent(r->client,x,y,buttons);
    769 }
    770 
    771 bool_t sendtext(resource_t res, const char *string)
    772 {
    773 	private_resource_t* r=get_resource(res);
    774 	if(r==NULL)
    775 		return 0;
    776 	return SendClientCutText(r->client, (char *)string, (int)strlen(string));
    777 }
    778 
    779 bool_t sendtext_to_server(resource_t res, const char *string)
    780 {
    781 	private_resource_t* r=get_resource(res);
    782 	if(r==NULL)
    783 		return 0;
    784 	rfbSendServerCutText(r->server, (char *)string, (int)strlen(string));
    785 	return 1;
    786 }
    787 
    788 /* for visual grepping */
    789 
    790 coordinate_t getxorigin(resource_t res)
    791 {
    792 	private_resource_t* r=get_resource(res);
    793 	return r->x_origin;
    794 }
    795 
    796 coordinate_t getyorigin(resource_t res)
    797 {
    798 	private_resource_t* r=get_resource(res);
    799 	return r->y_origin;
    800 }
    801 
    802