1 /* -*- c-basic-offset: 8 -*-
2    rdesktop: A Remote Desktop Protocol client.
3    User interface services - SVGA lib
4    Copyright (C) Jay Sorg 2004-2005
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License along
17    with this program; if not, write to the Free Software Foundation, Inc.,
18    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20 
21 #include "../rdesktop.h"
22 
23 #include <vga.h>
24 #include <vgakeyboard.h>
25 #include <vgamouse.h>
26 #include <vgagl.h>
27 
28 #include <unistd.h> // gethostname
29 #include <pwd.h> // getpwuid
30 #include <stdarg.h> // va_list va_start va_end
31 
32 #include <sys/ioctl.h>
33 #include <linux/keyboard.h>
34 #include <linux/kd.h>
35 #include <fcntl.h>
36 
37 extern int g_tcp_port_rdp;
38 int g_use_rdp5 = 0;
39 char g_hostname[16] = "";
40 char g_username[64] = "";
41 int g_height = 600;
42 int g_width = 800;
43 int g_server_bpp = 8;
44 int g_encryption = 1;
45 int g_desktop_save = 1;
46 int g_polygon_ellipse_orders = 0;
47 int g_bitmap_cache = 1;
48 int g_bitmap_cache_persist_enable = False;
49 int g_bitmap_cache_precache = True;
50 int g_bitmap_compression = 1;
51 int g_rdp5_performanceflags = 0;
52 int g_console_session = 0;
53 int g_keylayout = 0x409; /* Defaults to US keyboard layout */
54 int g_keyboard_type = 0x4; /* Defaults to US keyboard layout */
55 int g_keyboard_subtype = 0x0; /* Defaults to US keyboard layout */
56 int g_keyboard_functionkeys = 0xc; /* Defaults to US keyboard layout */
57 
58 /* hack globals */
59 int g_argc = 0;
60 char** g_argv = 0;
61 int UpAndRunning = 0;
62 int g_sock = 0;
63 int deactivated = 0;
64 uint32 ext_disc_reason = 0;
65 char g_servername[128] = "";
66 static uint32* colmap = 0;
67 static uint8* desk_save = 0;
68 static int g_server_Bpp = 1;
69 
70 /* Keyboard LEDS */
71 static int numlock;
72 static int capslock;
73 static int scrolllock;
74 
75 // this is non null if vgalib has non accel functions available
76 // reading from video memory is sooo slow
77 static uint8* sdata = 0;
78 static int g_save_mem = 0; // for video memory use eg sdata == 0
79 
80 // video acceleration
81 static int use_accel = 1;
82 static int has_fill_box = 0;
83 static int has_screen_copy = 0;
84 static int has_put_image = 0;
85 
86 // clip
87 int clip_startx;
88 int clip_starty;
89 int clip_endx;
90 int clip_endy;
91 
92 // mouse
93 uint8 mouse_under[32 * 32 * 4]; // save area under mouse
94 int mousex = 0;
95 int mousey = 0;
96 int mouseb = 0;
97 
98 // mouse info
99 typedef struct
100 {
101   uint8 andmask[32 * 32];
102   uint8 xormask[32 * 32];
103   int x;
104   int y;
105   int w;
106   int h;
107 } tcursor;
108 
109 // mouse global
110 static tcursor mcursor;
111 
112 static int g_draw_mouse = 1;
113 
114 /* Session Directory redirection */
115 BOOL g_redirect = False;
116 char g_redirect_server[64];
117 char g_redirect_domain[16];
118 char g_redirect_password[64];
119 char g_redirect_username[64];
120 char g_redirect_cookie[128];
121 uint32 g_redirect_flags = 0;
122 
123 // bitmap
124 typedef struct
125 {
126   int width;
127   int height;
128   uint8* data;
129   uint8 Bpp;
130 } bitmap;
131 
132 typedef struct
133 {
134   int x;
135   int y;
136   int cx;
137   int cy;
138   void* prev;
139   void* next;
140 } myrect;
141 
142 myrect* head_rect = 0;
143 
144 //*****************************************************************************
145 // Keyboard stuff - PeterS
146 static void setled(int mask, int state)
147 {
148   int fd;
149   long int leds;
150 
151   if (( fd=open("/dev/console", O_NOCTTY)) != -1 )
152   {
153     if (ioctl (fd, KDGETLED, &leds) != -1)
154     {
155       leds &= 7;
156       if (state)
157         leds |= mask;
158       else
159         leds &= ~mask;
160       ioctl (fd, KDSETLED, leds);
161     }
162     close(fd);
163   }
164 }
165 
166 
167 //*****************************************************************************
168 // do a raster op
169 int rop(int rop, int src, int dst)
170 {
171   switch (rop)
172   {
173     case 0x0: return 0;
174     case 0x1: return ~(src | dst);
175     case 0x2: return (~src) & dst;
176     case 0x3: return ~src;
177     case 0x4: return src & (~dst);
178     case 0x5: return ~(dst);
179     case 0x6: return src ^ dst;
180     case 0x7: return ~(src & dst);
181     case 0x8: return src & dst;
182     case 0x9: return ~(src) ^ dst;
183     case 0xa: return dst;
184     case 0xb: return (~src) | dst;
185     case 0xc: return src;
186     case 0xd: return src | (~dst);
187     case 0xe: return src | dst;
188     case 0xf: return ~0;
189   }
190   return dst;
191 }
192 
193 //*****************************************************************************
194 // get a screen pixel
195 int get_pixel(int x, int y)
196 {
197   if (x >= 0 && x < g_width && y >= 0 && y < g_height)
198   {
199     if (sdata != 0)
200     {
201       if (g_server_Bpp == 1)
202         return sdata[y * g_width + x];
203       else if (g_server_Bpp == 2)
204         return ((uint16*)sdata)[y * g_width + x];
205       else
206         return 0;
207     }
208     else
209       return vga_getpixel(x, y);
210   }
211   else
212     return 0;
213 }
214 
215 //*****************************************************************************
216 // set a screen pixel
217 void set_pixel(int x, int y, int pixel, int op)
218 {
219   if (x >= clip_startx && x < clip_endx && y >= clip_starty && y < clip_endy)
220   {
221     if (x >= 0 && x < g_width && y >= 0 && y < g_height)
222     {
223       if (op == 0x0)
224         pixel = 0;
225       else if (op == 0xf)
226         pixel = -1;
227       else if (op != 0xc)
228         pixel = rop(op, pixel, get_pixel(x, y));
229       if (sdata != 0)
230       {
231         if (g_server_Bpp == 1)
232           sdata[y * g_width + x] = pixel;
233         else if (g_server_Bpp == 2)
234           ((uint16*)sdata)[y * g_width + x] = pixel;
235       }
236       else
237       {
238         vga_setcolor(pixel);
239         vga_drawpixel(x, y);
240       }
241     }
242   }
243 }
244 
245 //*****************************************************************************
246 // get a pixel from a bitmap
247 int get_pixel2(int x, int y, uint8* data, int width, int bpp)
248 {
249   if (bpp == 8)
250     return data[y * width + x];
251   else if (bpp == 16)
252     return ((uint16*)data)[y * width + x];
253   else
254     return 0;
255 }
256 
257 //*****************************************************************************
258 // set a pixel in a bitmap
259 void set_pixel2(int x, int y, int pixel, uint8* data, int width, int bpp)
260 {
261   if (bpp == 8)
262     data[y * width + x] = pixel;
263   else if (bpp == 16)
264     ((uint16*)data)[y * width + x] = pixel;
265 }
266 
267 //*****************************************************************************
268 // get a pointer into a bitmap
269 uint8* get_ptr(int x, int y, uint8* data, int width, int bpp)
270 {
271   if (bpp == 8)
272     return data + (y * width + x);
273   else if (bpp == 16)
274     return data + (y * width + x) * 2;
275   else
276     return 0;
277 }
278 
279 //*****************************************************************************
280 // check if a certain pixel is set in a bitmap
281 BOOL is_pixel_on(uint8* data, int x, int y, int width, int bpp)
282 {
283   int start;
284   int shift;
285 
286   if (bpp == 1)
287   {
288     width = (width + 7) / 8;
289     start = (y * width) + x / 8;
290     shift = x % 8;
291     return (data[start] & (0x80 >> shift)) != 0;
292   }
293   else if (bpp == 8)
294   {
295     return data[y * width + x] != 0;
296   }
297   else if (bpp == 24)
298   {
299     return data[(y * 3) * width + (x * 3)] != 0 &&
300            data[(y * 3) * width + (x * 3) + 1] != 0 &&
301            data[(y * 3) * width + (x * 3) + 2] != 0;
302   }
303   else
304     return False;
305 }
306 
307 //*****************************************************************************
308 void set_pixel_on(uint8* data, int x, int y, int width, int bpp, int pixel)
309 {
310   if (bpp == 8)
311   {
312     data[y * width + x] = pixel;
313   }
314 }
315 
316 /*****************************************************************************/
317 int warp_coords(int* x, int* y, int* cx, int* cy, int* srcx, int* srcy)
318 {
319   int dx;
320   int dy;
321 //  int lx = *x, ly = *y, lcx = *cx, lcy = *cy;
322 
323   if (clip_startx > *x)
324     dx = clip_startx - *x;
325   else
326     dx = 0;
327   if (clip_starty > *y)
328     dy = clip_starty - *y;
329   else
330     dy = 0;
331   if (*x + *cx > clip_endx)
332     *cx = (*cx - ((*x + *cx) - clip_endx)) /*+ 1*/;
333   if (*y + *cy > clip_endy)
334     *cy = (*cy - ((*y + *cy) - clip_endy)) /*+ 1*/;
335   *cx = *cx - dx;
336   *cy = *cy - dy;
337   if (*cx <= 0)
338     return False;
339   if (*cy <= 0)
340     return False;
341   *x = *x + dx;
342   *y = *y + dy;
343   if (srcx != NULL)
344     *srcx = *srcx + dx;
345   if (srcy != NULL)
346     *srcy = *srcy + dy;
347 
348 //  if (*x != lx || *y != ly || *cx != lcx || *cy != lcy)
349 //    printf("%d %d %d %d to %d %d %d %d\n", lx, ly, lcx, lcy, *x, *y, *cx, *cy);
350 
351   return True;
352 }
353 
354 //*****************************************************************************
355 void copy_mem(uint8* d, uint8* s, int n)
356 {
357   while (n & (~7))
358   {
359     *(d++) = *(s++);
360     *(d++) = *(s++);
361     *(d++) = *(s++);
362     *(d++) = *(s++);
363     *(d++) = *(s++);
364     *(d++) = *(s++);
365     *(d++) = *(s++);
366     *(d++) = *(s++);
367     n = n - 8;
368   }
369   while (n > 0)
370   {
371     *(d++) = *(s++);
372     n--;
373   }
374 }
375 
376 //*****************************************************************************
377 void copy_memb(uint8* d, uint8* s, int n)
378 {
379   d = (d + n) - 1;
380   s = (s + n) - 1;
381   while (n & (~7))
382   {
383     *(d--) = *(s--);
384     *(d--) = *(s--);
385     *(d--) = *(s--);
386     *(d--) = *(s--);
387     *(d--) = *(s--);
388     *(d--) = *(s--);
389     *(d--) = *(s--);
390     *(d--) = *(s--);
391     n = n - 8;
392   }
393   while (n > 0)
394   {
395     *(d--) = *(s--);
396     n--;
397   }
398 }
399 
400 //*****************************************************************************
401 // all in pixel except line_size is in bytes
402 void accel_draw_box(int x, int y, int cx, int cy, uint8* data, int line_size)
403 {
404   int i;
405   uint8* s;
406   uint8* d;
407 
408   if (sdata != 0)
409   {
410     s = data;
411     d = get_ptr(x, y, sdata, g_width, g_server_bpp);
412     for (i = 0; i < cy; i++)
413     {
414       copy_mem(d, s, cx * g_server_Bpp);
415       s = s + line_size;
416       d = d + g_width * g_server_Bpp;
417     }
418   }
419   else if (has_put_image && line_size == cx * g_server_Bpp)
420   {
421     vga_accel(ACCEL_PUTIMAGE, x, y, cx, cy, data);
422   }
423   else
424   {
425     s = data;
426     for (i = 0; i < cy; i++)
427     {
428       vga_drawscansegment(s, x, y + i, cx * g_server_Bpp);
429       s = s + line_size;
430     }
431   }
432 }
433 
434 //*****************************************************************************
435 void accel_fill_rect(int x, int y, int cx, int cy, int color)
436 {
437   int i;
438   uint8* temp;
439   uint8* d;
440 
441   if (sdata != 0)
442   {
443     temp = xmalloc(cx * g_server_Bpp);
444     if (g_server_Bpp == 1)
445       for (i = 0; i < cx; i++)
446         temp[i] = color;
447     else if (g_server_Bpp == 2)
448       for (i = 0; i < cx; i++)
449         ((uint16*)temp)[i] = color;
450     d = get_ptr(x, y, sdata, g_width, g_server_bpp);
451     for (i = 0; i < cy; i++)
452     {
453       copy_mem(d, temp, cx * g_server_Bpp);
454       d = d + g_width * g_server_Bpp;
455     }
456     xfree(temp);
457   }
458   else if (has_fill_box)
459   {
460     vga_accel(ACCEL_SETFGCOLOR, color);
461     vga_accel(ACCEL_FILLBOX, x, y, cx, cy);
462   }
463   else
464   {
465     temp = xmalloc(cx * g_server_Bpp);
466     if (g_server_Bpp == 1)
467       for (i = 0; i < cx; i++)
468         temp[i] = color;
469     else if (g_server_Bpp == 2)
470       for (i = 0; i < cx; i++)
471         ((uint16*)temp)[i] = color;
472     for (i = 0; i < cy; i++)
473       vga_drawscansegment(temp, x, y + i, cx * g_server_Bpp);
474     xfree(temp);
475   }
476 }
477 
478 //*****************************************************************************
479 void accel_screen_copy(int x, int y, int cx, int cy, int srcx, int srcy)
480 {
481   uint8* temp;
482   uint8* s;
483   uint8* d;
484   int i;
485 
486   if (sdata != 0)
487   {
488     if (srcy < y)
489     { // bottom to top
490       s = get_ptr(srcx, (srcy + cy) - 1, sdata, g_width, g_server_bpp);
491       d = get_ptr(x, (y + cy) - 1, sdata, g_width, g_server_bpp);
492       for (i = 0; i < cy; i++)  // copy down
493       {
494         copy_mem(d, s, cx * g_server_Bpp);
495         s = s - g_width * g_server_Bpp;
496         d = d - g_width * g_server_Bpp;
497       }
498     }
499     else if (srcy > y || srcx > x) // copy up or left
500     { // top to bottom
501       s = get_ptr(srcx, srcy, sdata, g_width, g_server_bpp);
502       d = get_ptr(x, y, sdata, g_width, g_server_bpp);
503       for (i = 0; i < cy; i++)
504       {
505         copy_mem(d, s, cx * g_server_Bpp);
506         s = s + g_width * g_server_Bpp;
507         d = d + g_width * g_server_Bpp;
508       }
509     }
510     else // copy straight right
511     {
512       s = get_ptr(srcx, srcy, sdata, g_width, g_server_bpp);
513       d = get_ptr(x, y, sdata, g_width, g_server_bpp);
514       for (i = 0; i < cy; i++)
515       {
516         copy_memb(d, s, cx * g_server_Bpp);
517         s = s + g_width * g_server_Bpp;
518         d = d + g_width * g_server_Bpp;
519       }
520     }
521   }
522   else if (has_screen_copy)
523   {
524     vga_accel(ACCEL_SCREENCOPY, srcx, srcy, x, y, cx, cy);
525   }
526   else
527   {
528     // slow
529     temp = (uint8*)xmalloc(cx * cy * g_server_Bpp);
530     for (i = 0; i < cy; i++)
531       vga_getscansegment(get_ptr(0, i, temp, cx, g_server_bpp), srcx, srcy + i, cx * g_server_Bpp);
532     for (i = 0; i < cy; i++)
533       vga_drawscansegment(get_ptr(0, i, temp, cx, g_server_bpp), x, y + i, cx * g_server_Bpp);
534     xfree(temp);
535   }
536 }
537 
538 //*****************************************************************************
539 // return bool
540 int contains_mouse(int x, int y, int cx, int cy)
541 {
542   if (mousex + 32 >= x &&
543       mousey + 32 >= y &&
544       mousex <= x + cx &&
545       mousey <= y + cy)
546     return 1;
547   else
548     return 0;
549 }
550 
551 //*****************************************************************************
552 void fill_rect(int x, int y, int cx, int cy, int colour, int opcode)
553 {
554   int i;
555   int j;
556 
557   if (warp_coords(&x, &y, &cx, &cy, NULL, NULL))
558   {
559     if (opcode == 0xc)
560       accel_fill_rect(x, y, cx, cy, colour);
561     else if (opcode == 0xf)
562       accel_fill_rect(x, y, cx, cy, -1);
563     else if (opcode == 0x0)
564       accel_fill_rect(x, y, cx, cy, 0);
565     else
566     {
567       for (i = 0; i < cy; i++)
568         for (j = 0; j < cx; j++)
569           set_pixel(x + j, y + i, colour, opcode);
570     }
571   }
572 }
573 
574 //*****************************************************************************
575 void get_rect(int x, int y, int cx, int cy, uint8* p)
576 {
577   int i;
578 
579   if (x < 0)
580   {
581     cx = cx + x;
582     x = 0;
583   }
584   if (y < 0)
585   {
586     cy = cy + y;
587     y = 0;
588   }
589   if (sdata != 0)
590   {
591     for (i = 0; i < cy; i++)
592     {
593       copy_mem(p, get_ptr(x, y + i, sdata, g_width, g_server_bpp), cx * g_server_Bpp);
594       p = p + cx * g_server_Bpp;
595     }
596   }
597   else
598   {
599     for (i = 0; i < cy; i++)
600     {
601       vga_getscansegment(p, x, y + i, cx * g_server_Bpp);
602       p = p + cx * g_server_Bpp;
603     }
604   }
605 }
606 
607 /*****************************************************************************/
608 // return true if r1 is contained by r2
609 int is_contained_by(myrect* r1, myrect* r2)
610 {
611   if (r1->x >= r2->x &&
612       r1->y >= r2->y &&
613       r1->x + r1->cx <= r2->x + r2->cx &&
614       r1->y + r1->cy <= r2->y + r2->cy)
615     return 1;
616   else
617     return 0;
618 }
619 
620 /*****************************************************************************/
621 void draw_cursor_under(int ox, int oy)
622 {
623   int i;
624   int j;
625   int k;
626   uint8* ptr;
627   int len;
628 
629   if (ox < 0)
630     k = -ox;
631   else
632     k = 0;
633   j = g_width - ox;
634   if (j > 32)
635     j = 32;
636   if (j > 0)
637   {
638     for (i = 0; i < 32; i++)
639     {
640       ptr = get_ptr(k, i, mouse_under, 32, g_server_bpp);
641       len = (j - k) * g_server_Bpp;
642       if (ox + k >= 0 && oy + i >= 0 && ox + k < g_width && oy + i < g_height)
643         vga_drawscansegment(ptr, ox + k, oy + i, len);
644     }
645   }
646   g_draw_mouse = 1;
647 }
648 
649 /*****************************************************************************/
650 void draw_cursor(void)
651 {
652   int i;
653   int j;
654   int k;
655   int pixel;
656   uint8 mouse_a[32 * 32 * 4];
657   uint8* ptr;
658   int len;
659 
660   if (!g_draw_mouse)
661     return;
662   memset(mouse_under, 0, sizeof(mouse_under));
663   for (i = 0; i < 32; i++)
664   {
665     for (j = 0; j < 32; j++)
666     {
667       pixel = get_pixel(mousex + j, mousey + i);
668       set_pixel2(j, i, pixel, mouse_under, 32, g_server_bpp);
669       if (mcursor.andmask[i * 32 + j] == 0)
670         k = 0;
671       else
672         k = ~0;
673       pixel = rop(0x8, k, pixel);
674       if (mcursor.xormask[i * 32 + j] == 0)
675         k = 0;
676       else
677         k = ~0;
678       pixel = rop(0x6, k, pixel);
679       set_pixel2(j, i, pixel, mouse_a, 32, g_server_bpp);
680     }
681   }
682   if (mousex < 0)
683     k = -mousex;
684   else
685     k = 0;
686   j = g_width - mousex;
687   if (j > 32)
688     j = 32;
689   if (j > 0)
690   {
691     for (i = mousey; i < mousey + 32; i++)
692       if (i < g_height && i >= 0)
693       {
694         ptr = get_ptr(k, i - mousey, mouse_a, 32, g_server_bpp);
695         len = (j - k) * g_server_Bpp;
696         vga_drawscansegment(ptr, mousex + k, i, len);
697       }
698   }
699   g_draw_mouse = 0;
700 }
701 
702 /*****************************************************************************/
703 // add a rect to cache
704 void cache_rect(int x, int y, int cx, int cy, int do_warp)
705 {
706   myrect* rect;
707   myrect* walk_rect;
708 
709   if (sdata == 0)
710   {
711     draw_cursor();
712     return;
713   }
714   if (do_warp)
715     if (!warp_coords(&x, &y, &cx, &cy, NULL, NULL))
716       return;
717   rect = (myrect*)xmalloc(sizeof(myrect));
718   rect->x = x;
719   rect->y = y;
720   rect->cx = cx;
721   rect->cy = cy;
722   rect->next = 0;
723   rect->prev = 0;
724   if (head_rect == 0)
725     head_rect = rect;
726   else
727   {
728     walk_rect = 0;
729     do
730     {
731       if (walk_rect == 0)
732         walk_rect = head_rect;
733       else
734         walk_rect = walk_rect->next;
735       if (is_contained_by(rect, walk_rect))
736       {
737         xfree(rect);
738         return;
739       }
740     }
741     while (walk_rect->next != 0);
742     walk_rect->next = rect;
743     rect->prev = walk_rect;
744   }
745 }
746 
747 //*****************************************************************************
748 void draw_cache_rects(void)
749 {
750   int i;
751   myrect* rect;
752   myrect* rect1;
753   uint8* p;
754 
755   // draw all the rects
756   rect = head_rect;
757   while (rect != 0)
758   {
759     p = get_ptr(rect->x, rect->y, sdata, g_width, g_server_bpp);
760     for (i = 0; i < rect->cy; i++)
761     {
762       vga_drawscansegment(p, rect->x, rect->y + i, rect->cx * g_server_Bpp);
763       p = p + g_width * g_server_Bpp;
764     }
765     rect1 = rect;
766     rect = rect->next;
767     xfree(rect1);
768   }
769   head_rect = 0;
770 }
771 
772 /*****************************************************************************/
773 void key_event(int scancode, int pressed)
774 {
775   int rdpkey;
776   int ext;
777 
778   if (!UpAndRunning)
779     return;
780   rdpkey = scancode;
781   ext = 0;
782 
783   // Keyboard LEDS
784   if ((scancode == SCANCODE_CAPSLOCK) && pressed)
785   {
786      capslock = !capslock;
787      setled(LED_CAP, capslock);
788   }
789   if ((scancode == SCANCODE_SCROLLLOCK) && pressed)
790   {
791      scrolllock = !scrolllock;
792      setled(LED_SCR, scrolllock);
793   }
794 
795   if ((scancode == SCANCODE_NUMLOCK) && pressed)
796   {
797      numlock = !numlock;
798      setled(LED_NUM, numlock);
799   }
800 
801   switch (scancode)
802   {
803     case SCANCODE_CURSORBLOCKUP:    rdpkey = 0xc8; ext = KBD_FLAG_EXT; break; // up arrow
804     case SCANCODE_CURSORBLOCKDOWN:  rdpkey = 0xd0; ext = KBD_FLAG_EXT; break; // down arrow
805     case SCANCODE_CURSORBLOCKRIGHT: rdpkey = 0xcd; ext = KBD_FLAG_EXT; break; // right arrow
806     case SCANCODE_CURSORBLOCKLEFT:  rdpkey = 0xcb; ext = KBD_FLAG_EXT; break; // left arrow
807     case SCANCODE_PAGEDOWN:         rdpkey = 0xd1; ext = KBD_FLAG_EXT; break; // page down
808     case SCANCODE_PAGEUP:           rdpkey = 0xc9; ext = KBD_FLAG_EXT; break; // page up
809     case SCANCODE_HOME:             rdpkey = 0xc7; ext = KBD_FLAG_EXT; break; // home
810     case SCANCODE_END:              rdpkey = 0xcf; ext = KBD_FLAG_EXT; break; // end
811     case SCANCODE_INSERT:           rdpkey = 0xd2; ext = KBD_FLAG_EXT; break; // insert
812     case SCANCODE_REMOVE:           rdpkey = 0xd3; ext = KBD_FLAG_EXT; break; // delete
813     case SCANCODE_KEYPADDIVIDE:     rdpkey = 0x35; break; // /
814     case SCANCODE_KEYPADENTER:      rdpkey = 0x1c; break; // enter
815     case SCANCODE_RIGHTCONTROL:     rdpkey = 0x1d; break; // right ctrl
816     case SCANCODE_RIGHTALT:         rdpkey = 0x38; break; // right alt
817     case SCANCODE_LEFTWIN:          rdpkey = 0x5b; ext = KBD_FLAG_EXT; break; // left win
818     case SCANCODE_RIGHTWIN:         rdpkey = 0x5c; ext = KBD_FLAG_EXT; break; // right win
819     case 127:                       rdpkey = 0x5d; ext = KBD_FLAG_EXT; break; // menu key
820     case SCANCODE_PRINTSCREEN:      rdpkey = 0x37; ext = KBD_FLAG_EXT; break; // print screen
821     case SCANCODE_BREAK:            //rdpkey = 0; break; // break
822     {
823       if (pressed)
824       {
825         ext = KBD_FLAG_EXT;
826         rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYPRESS | ext, 0x46, 0);
827         rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYPRESS | ext, 0xc6, 0);
828       }
829       rdpkey = 0;
830     }
831     case SCANCODE_SCROLLLOCK:       rdpkey = 0x46; break; // scroll lock
832     case 112: // mouse down
833     {
834       rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON4,
835                      mouse_getx(), mouse_gety());
836       return;
837     }
838     case 113: // mouse up
839     {
840       rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON5,
841                      mouse_getx(), mouse_gety());
842       return;
843     }
844   }
845 //  printf("%d %d\n", scancode, pressed);
846   if (pressed)
847     rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYPRESS | ext, rdpkey, 0);
848   else
849     rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYRELEASE | ext, rdpkey, 0);
850 
851 
852 }
853 
854 /*****************************************************************************/
855 int ui_init(void)
856 {
857   vga_init();
858   memset(&mcursor, 0, sizeof(tcursor));
859   desk_save = (uint8*)xmalloc(0x38400 * g_server_Bpp);
860   return 1;
861 }
862 
863 /*****************************************************************************/
864 void ui_deinit(void)
865 {
866   xfree(desk_save);
867 }
868 
869 /*****************************************************************************/
870 int ui_create_window(void)
871 {
872   int vgamode;
873   int i;
874 
875   vgamode = G800x600x256;
876   if (g_width == 640 && g_height == 480)
877   {
878     if (g_server_Bpp == 1)
879       vgamode = G640x480x256;
880     else if (g_server_Bpp == 2)
881       vgamode = G640x480x64K;
882   }
883   else if (g_width == 800 && g_height == 600)
884   {
885     if (g_server_Bpp == 1)
886       vgamode = G800x600x256;
887     else if (g_server_Bpp == 2)
888       vgamode = G800x600x64K;
889   }
890   else if (g_width == 1024 && g_height == 768)
891   {
892     if (g_server_Bpp == 1)
893       vgamode = G1024x768x256;
894     else if (g_server_Bpp == 2)
895       vgamode = G1024x768x64K;
896   }
897   else
898   {
899     error("Invalid width / height");
900     return 0;
901   }
902   ui_reset_clip();
903   if (!vga_hasmode(vgamode))
904   {
905     error("Graphics unavailable");
906     return 0;
907   }
908   vga_setmousesupport(1);
909   mouse_setposition(g_width / 2, g_height / 2);
910   vga_setmode(vgamode);
911   if (keyboard_init())
912   {
913     error("Keyboard unavailable");
914     return 0;
915   }
916   keyboard_seteventhandler(key_event);
917   if (use_accel)
918   {
919     i = vga_ext_set(VGA_EXT_AVAILABLE, VGA_AVAIL_ACCEL);
920     if (i & ACCELFLAG_PUTIMAGE)
921       has_put_image = 1;
922     if (i & ACCELFLAG_SCREENCOPY)
923       has_screen_copy = 1;
924     if (i & ACCELFLAG_FILLBOX)
925       has_fill_box = 1;
926     printf("accel %d\n", i);
927   }
928   if (!has_screen_copy && !g_save_mem)
929     sdata = xmalloc(g_width * g_height * g_server_Bpp);
930   return 1;
931 }
932 
933 /*****************************************************************************/
934 void ui_destroy_window(void)
935 {
936   keyboard_close(); /* Don't forget this! */
937   vga_setmode(TEXT);
938   if (sdata != 0)
939     xfree(sdata);
940 }
941 
942 /*****************************************************************************/
943 void process_mouse(void)
944 {
945   int ox = mousex;
946   int oy = mousey;
947   int ob = mouseb;
948 
949   if (!UpAndRunning)
950     return;
951   mousex = mouse_getx() - mcursor.x;
952   mousey = mouse_gety() - mcursor.y;
953   mouseb = mouse_getbutton();
954 
955   if (mouseb != ob) // button
956   {
957     // right button
958     if (mouseb & 1)
959       if (!(ob & 1))
960         rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON2,
961                        mousex + mcursor.x, mousey + mcursor.y);
962     if (ob & 1)
963       if (!(mouseb & 1))
964         rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON2,
965                        mousex + mcursor.x, mousey + mcursor.y);
966     // middle button
967     if (mouseb & 2)
968       if (!(ob & 2))
969         rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON3,
970                        mousex + mcursor.x, mousey + mcursor.y);
971     if (ob & 2)
972       if (!(mouseb & 2))
973         rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON3,
974                        mousex + mcursor.x, mousey + mcursor.y);
975     // left button
976     if (mouseb & 4)
977       if (!(ob & 4))
978         rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON1,
979                        mousex + mcursor.x, mousey + mcursor.y);
980     if (ob & 4)
981       if (!(mouseb & 4))
982         rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON1,
983                        mousex + mcursor.x, mousey + mcursor.y);
984   }
985   if (mousex != ox || mousey != oy) // movement
986   {
987     rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
988                    mousex + mcursor.x, mousey + mcursor.y);
989     draw_cursor_under(ox, oy);
990     draw_cursor();
991   }
992 }
993 
994 /*****************************************************************************/
995 void process_keyboard(void)
996 {
997   if (!UpAndRunning)
998     return;
999 }
1000 
1001 /*****************************************************************************/
1002 BOOL ui_main_loop(void)
1003 {
1004   int sel;
1005   fd_set rfds;
1006 
1007   if (!rdp_connect(g_servername, RDP_LOGON_NORMAL, "", "", "", ""))
1008     return False;
1009   UpAndRunning = 1;
1010   FD_ZERO(&rfds);
1011   FD_SET(g_sock, &rfds);
1012   sel = vga_waitevent(3, &rfds, NULL, NULL, NULL);
1013   while (sel >= 0)
1014   {
1015     if (sel & 1) /* mouse */
1016     {
1017       process_mouse();
1018     }
1019     else if (sel & 2) /* keyboard */
1020     {
1021       process_keyboard();
1022     }
1023     else
1024     {
1025       if (!rdp_loop(&deactivated, &ext_disc_reason))
1026         return True; /* ok */
1027     }
1028     FD_ZERO(&rfds);
1029     FD_SET(g_sock, &rfds);
1030     sel = vga_waitevent(3, &rfds, NULL, NULL, NULL);
1031   }
1032   return True;
1033 }
1034 
1035 /*****************************************************************************/
1036 void ui_bell(void)
1037 {
1038 }
1039 
1040 /*****************************************************************************/
1041 int ui_select(int in)
1042 {
1043   g_sock = in;
1044   return 1;
1045 }
1046 
1047 /*****************************************************************************/
1048 void* ui_create_glyph(int width, int height, uint8* data)
1049 {
1050   int i, j;
1051   uint8* glyph_data;
1052   bitmap* the_glyph;
1053 
1054   glyph_data = (uint8*)xmalloc(width * height);
1055   the_glyph = (bitmap*)xmalloc(sizeof(bitmap));
1056   the_glyph->width = width;
1057   the_glyph->height = height;
1058   the_glyph->data = glyph_data;
1059   memset(glyph_data, 0, width * height);
1060   for (i = 0; i < height; i++)
1061     for (j = 0; j < width; j++)
1062       if (is_pixel_on(data, j, i, width, 1))
1063         set_pixel_on(glyph_data, j, i, width, 8, 255);
1064   return the_glyph;
1065 }
1066 
1067 /*****************************************************************************/
1068 void ui_destroy_glyph(void* glyph)
1069 {
1070   bitmap* the_glyph;
1071 
1072   the_glyph = (bitmap*)glyph;
1073   if (the_glyph != NULL)
1074   {
1075     if (the_glyph->data != NULL)
1076       xfree(the_glyph->data);
1077     xfree(the_glyph);
1078   }
1079 }
1080 
1081 /*****************************************************************************/
1082 void ui_destroy_bitmap(void* bmp)
1083 {
1084   bitmap* b;
1085 
1086   b = (bitmap*)bmp;
1087   xfree(b->data);
1088   xfree(b);
1089 }
1090 
1091 /*****************************************************************************/
1092 void ui_reset_clip(void)
1093 {
1094   clip_startx = 0;
1095   clip_starty = 0;
1096   clip_endx = g_width;
1097   clip_endy = g_height;
1098 }
1099 
1100 /*****************************************************************************/
1101 void ui_set_clip(int x, int y, int cx, int cy)
1102 {
1103   clip_startx = x;
1104   clip_starty = y;
1105   clip_endx = x + cx;
1106   clip_endy = y + cy;
1107 }
1108 
1109 /*****************************************************************************/
1110 void* ui_create_colourmap(COLOURMAP * colours)
1111 {
1112   int i = 0;
1113   int n = colours->ncolours;
1114   COLOURENTRY* c = colours->colours;
1115   int* cmap = (int*)xmalloc(3 * 256 * sizeof (int));
1116   if (n > 256)
1117     n = 256;
1118   bzero(cmap, 256 * 3 * sizeof (int));
1119   for (i = 0; i < (3 * n); c++)
1120   {
1121     cmap[i++] = (c->red) >> 2;
1122     cmap[i++] = (c->green) >> 2;
1123     cmap[i++] = (c->blue) >> 2;
1124   }
1125   return cmap;
1126 }
1127 
1128 /*****************************************************************************/
1129 void ui_destroy_colourmap(HCOLOURMAP map)
1130 {
1131   if (colmap == map)
1132     colmap = 0;
1133   xfree(map);
1134 }
1135 
1136 /*****************************************************************************/
1137 void ui_set_colourmap(void* map)
1138 {
1139   if (colmap != 0)
1140     xfree(colmap);
1141   vga_setpalvec(0, 256, (int*)map);
1142   colmap = map;
1143 }
1144 
1145 /*****************************************************************************/
1146 HBITMAP ui_create_bitmap(int width, int height, uint8* data)
1147 {
1148   bitmap* b;
1149 
1150   b = (bitmap*)xmalloc(sizeof(bitmap));
1151   b->data = (uint8*)xmalloc(width * height * g_server_Bpp);
1152   b->width = width;
1153   b->height = height;
1154   b->Bpp = g_server_Bpp;
1155   copy_mem(b->data, data, width * height * g_server_Bpp);
1156   return (void*)b;
1157 }
1158 
1159 //*****************************************************************************
1160 void draw_glyph (int x, int y, HGLYPH glyph, int fgcolour)
1161 {
1162   bitmap* the_glyph;
1163   int i, j;
1164 
1165   the_glyph = (bitmap*)glyph;
1166   if (the_glyph == NULL)
1167     return;
1168   for (i = 0; i < the_glyph->height; i++)
1169     for (j = 0; j < the_glyph->width; j++)
1170       if (is_pixel_on(the_glyph->data, j, i, the_glyph->width, 8))
1171         set_pixel(x + j, y + i, fgcolour, 0xc);
1172 }
1173 
1174 #define DO_GLYPH(ttext,idx) \
1175 {\
1176   glyph = cache_get_font (font, ttext[idx]);\
1177   if (!(flags & TEXT2_IMPLICIT_X))\
1178     {\
1179       xyoffset = ttext[++idx];\
1180       if ((xyoffset & 0x80))\
1181 	{\
1182 	  if (flags & TEXT2_VERTICAL) \
1183 	    y += ttext[idx+1] | (ttext[idx+2] << 8);\
1184 	  else\
1185 	    x += ttext[idx+1] | (ttext[idx+2] << 8);\
1186 	  idx += 2;\
1187 	}\
1188       else\
1189 	{\
1190 	  if (flags & TEXT2_VERTICAL) \
1191 	    y += xyoffset;\
1192 	  else\
1193 	    x += xyoffset;\
1194 	}\
1195     }\
1196   if (glyph != NULL)\
1197     {\
1198       draw_glyph (x + glyph->offset, y + glyph->baseline, glyph->pixmap, fgcolour);\
1199       if (flags & TEXT2_IMPLICIT_X)\
1200 	x += glyph->width;\
1201     }\
1202 }
1203 
1204 /*****************************************************************************/
1205 void ui_draw_text(uint8 font, uint8 flags, uint8 opcode, int mixmode,
1206                   int x, int y,
1207                   int clipx, int clipy, int clipcx, int clipcy,
1208                   int boxx, int boxy, int boxcx, int boxcy, BRUSH * brush,
1209                   int bgcolour, int fgcolour, uint8* text, uint8 length)
1210 {
1211   int i;
1212   int j;
1213   int xyoffset;
1214   DATABLOB* entry;
1215   FONTGLYPH* glyph;
1216 
1217   if (boxcx > 1)
1218   {
1219     if (contains_mouse(boxx, boxy, boxcx, boxcy))
1220       draw_cursor_under(mousex, mousey);
1221     fill_rect(boxx, boxy, boxcx, boxcy, bgcolour, 0xc);
1222   }
1223   else
1224   {
1225     if (contains_mouse(clipx, clipy, clipcx, clipcy))
1226       draw_cursor_under(mousex, mousey);
1227     if (mixmode == MIX_OPAQUE)
1228       fill_rect(clipx, clipy, clipcx, clipcy, bgcolour, 0xc);
1229   }
1230 
1231   /* Paint text, character by character */
1232   for (i = 0; i < length;)
1233   {
1234     switch (text[i])
1235     {
1236       case 0xff:
1237         if (i + 2 < length)
1238           cache_put_text(text[i + 1], text, text[i + 2]);
1239         else
1240         {
1241           error("this shouldn't be happening\n");
1242           exit(1);
1243         }
1244         /* this will move pointer from start to first character after FF command */
1245         length -= i + 3;
1246         text = &(text[i + 3]);
1247         i = 0;
1248         break;
1249 
1250       case 0xfe:
1251         entry = cache_get_text(text[i + 1]);
1252         if (entry != NULL)
1253         {
1254           if ((((uint8 *) (entry->data))[1] == 0) && (!(flags & TEXT2_IMPLICIT_X)))
1255           {
1256             if (flags & TEXT2_VERTICAL)
1257               y += text[i + 2];
1258             else
1259               x += text[i + 2];
1260           }
1261           for (j = 0; j < entry->size; j++)
1262             DO_GLYPH(((uint8 *) (entry->data)), j);
1263         }
1264         if (i + 2 < length)
1265           i += 3;
1266         else
1267           i += 2;
1268         length -= i;
1269         /* this will move pointer from start to first character after FE command */
1270         text = &(text[i]);
1271         i = 0;
1272         break;
1273 
1274       default:
1275         DO_GLYPH(text, i);
1276         i++;
1277         break;
1278     }
1279   }
1280   if (boxcx > 1)
1281     cache_rect(boxx, boxy, boxcx, boxcy, True);
1282   else
1283     cache_rect(clipx, clipy, clipcx, clipcy, True);
1284 }
1285 
1286 //*****************************************************************************
1287 // Bresenham's line drawing algorithm
1288 void ui_line(uint8 opcode, int startx, int starty, int endx,
1289              int endy, PEN* pen)
1290 {
1291   int dx;
1292   int dy;
1293   int incx;
1294   int incy;
1295   int dpr;
1296   int dpru;
1297   int p;
1298   int left;
1299   int top;
1300   int right;
1301   int bottom;
1302 
1303   if (startx > endx)
1304   {
1305     dx = startx - endx;
1306     incx = -1;
1307     left = endx;
1308     right = startx;
1309   }
1310   else
1311   {
1312     dx = endx - startx;
1313     incx = 1;
1314     left = startx;
1315     right = endx;
1316   }
1317   if (starty > endy)
1318   {
1319     dy = starty - endy;
1320     incy = -1;
1321     top = endy;
1322     bottom = starty;
1323   }
1324   else
1325   {
1326     dy = endy - starty;
1327     incy = 1;
1328     top = starty;
1329     bottom = endy;
1330   }
1331   if (contains_mouse(left, top, (right - left) + 1, (bottom - top) + 1))
1332     draw_cursor_under(mousex, mousey);
1333   if (dx >= dy)
1334   {
1335     dpr = dy << 1;
1336     dpru = dpr - (dx << 1);
1337     p = dpr - dx;
1338     for (; dx >= 0; dx--)
1339     {
1340       set_pixel(startx, starty, pen->colour, opcode);
1341       if (p > 0)
1342       {
1343         startx += incx;
1344         starty += incy;
1345         p += dpru;
1346       }
1347       else
1348       {
1349         startx += incx;
1350         p += dpr;
1351       }
1352     }
1353   }
1354   else
1355   {
1356     dpr = dx << 1;
1357     dpru = dpr - (dy << 1);
1358     p = dpr - dy;
1359     for (; dy >= 0; dy--)
1360     {
1361       set_pixel(startx, starty, pen->colour, opcode);
1362       if (p > 0)
1363       {
1364         startx += incx;
1365         starty += incy;
1366         p += dpru;
1367       }
1368       else
1369       {
1370         starty += incy;
1371         p += dpr;
1372       }
1373     }
1374   }
1375   cache_rect(left, top, (right - left) + 1, (bottom - top) + 1, True);
1376 }
1377 
1378 /*****************************************************************************/
1379 void ui_triblt(uint8 opcode, int x, int y, int cx, int cy,
1380                HBITMAP src, int srcx, int srcy,
1381                BRUSH* brush, int bgcolour, int fgcolour)
1382 {
1383   // non used
1384 }
1385 
1386 /*****************************************************************************/
1387 void ui_memblt(uint8 opcode, int x, int y, int cx, int cy,
1388                HBITMAP src, int srcx, int srcy)
1389 {
1390   bitmap* b;
1391   int i;
1392   int j;
1393   int pixel;
1394 
1395   if (warp_coords(&x, &y, &cx, &cy, &srcx, &srcy))
1396   {
1397     if (contains_mouse(x, y, cx, cy))
1398       draw_cursor_under(mousex, mousey);
1399     b = (bitmap*)src;
1400     if (opcode == 0xc)
1401       accel_draw_box(x, y, cx, cy, get_ptr(srcx, srcy, b->data, b->width, g_server_bpp),
1402                      b->width * g_server_Bpp);
1403     else
1404     {
1405       for (i = 0; i < cy; i++)
1406       {
1407         for (j = 0; j < cx; j++)
1408         {
1409           pixel = get_pixel2(srcx + j, srcy + i, b->data, b->width, g_server_bpp);
1410           set_pixel(x + j, y + i, pixel, opcode);
1411         }
1412       }
1413     }
1414     cache_rect(x, y, cx, cy, False);
1415   }
1416 }
1417 
1418 /*****************************************************************************/
1419 void ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy)
1420 {
1421   uint8* p;
1422 
1423   if (offset > 0x38400)
1424     offset = 0;
1425   if (offset + cx * cy > 0x38400)
1426     return;
1427   p = desk_save + offset * g_server_Bpp;
1428   ui_paint_bitmap(x, y, cx, cy, cx, cy, p);
1429 }
1430 
1431 /*****************************************************************************/
1432 void ui_desktop_save(uint32 offset, int x, int y, int cx, int cy)
1433 {
1434   uint8* p;
1435 
1436   if (offset > 0x38400)
1437     offset = 0;
1438   if (offset + cx * cy > 0x38400)
1439     return;
1440   if (contains_mouse(x, y, cx, cy))
1441     draw_cursor_under(mousex, mousey);
1442   p = desk_save + offset * g_server_Bpp;
1443   get_rect(x, y, cx, cy, p);
1444 }
1445 
1446 /*****************************************************************************/
1447 void ui_rect(int x, int y, int cx, int cy, int colour)
1448 {
1449   if (warp_coords(&x, &y, &cx, &cy, NULL, NULL))
1450   {
1451     if (contains_mouse(x, y, cx, cy))
1452       draw_cursor_under(mousex, mousey);
1453     accel_fill_rect(x, y, cx, cy, colour);
1454     cache_rect(x, y, cx, cy, False);
1455   }
1456 }
1457 
1458 /*****************************************************************************/
1459 void ui_screenblt(uint8 opcode, int x, int y, int cx, int cy,
1460                   int srcx, int srcy)
1461 {
1462   int i;
1463   int j;
1464   uint8* temp;
1465 
1466   if (x == srcx && y == srcy)
1467     return;
1468   if (warp_coords(&x, &y, &cx, &cy, &srcx, &srcy))
1469   {
1470     if (contains_mouse(x, y, cx, cy) || contains_mouse(srcx, srcy, cx, cy))
1471       draw_cursor_under(mousex, mousey);
1472     if (opcode == 0xc) /* copy */
1473       accel_screen_copy(x, y, cx, cy, srcx, srcy);
1474     else
1475     {
1476       temp = (uint8*)xmalloc(cx * cy * g_server_Bpp);
1477       for (i = 0; i < cy; i++)
1478         for (j = 0; j < cx; j++)
1479           set_pixel2(j, i, get_pixel(srcx + j, srcy + i), temp, cx, g_server_bpp);
1480       for (i = 0; i < cy; i++)
1481         for (j = 0; j < cx; j++)
1482           set_pixel(x + j, y + i, get_pixel2(j, i, temp, cx, g_server_bpp), opcode);
1483       xfree(temp);
1484     }
1485     cache_rect(x, y, cx, cy, False);
1486     draw_cache_rects(); // draw them all so screen is not jumpy
1487   }
1488 }
1489 
1490 /*****************************************************************************/
1491 void ui_patblt(uint8 opcode, int x, int y, int cx, int cy,
1492                BRUSH * brush, int bgcolour, int fgcolour)
1493 {
1494   int i;
1495   int j;
1496   uint8 ipattern[8];
1497 
1498   if (warp_coords(&x, &y, &cx, &cy, NULL, NULL))
1499   {
1500     if (contains_mouse(x, y, cx, cy))
1501       draw_cursor_under(mousex, mousey);
1502     switch (brush->style)
1503     {
1504       case 0:
1505         fill_rect(x, y, cx, cy, fgcolour, opcode);
1506         break;
1507       case 3:
1508         for (i = 0; i < 8; i++)
1509           ipattern[i] = ~brush->pattern[7 - i];
1510         for (i = 0; i < cy; i++)
1511           for (j = 0; j < cx; j++)
1512             if (is_pixel_on(ipattern, (x + j + brush->xorigin) % 8,
1513                               (y + i + brush->yorigin) % 8, 8, 1))
1514               set_pixel(x + j, y + i, fgcolour, opcode);
1515             else
1516               set_pixel(x + j, y + i, bgcolour, opcode);
1517         break;
1518     }
1519     cache_rect(x, y, cx, cy, False);
1520   }
1521 }
1522 
1523 /*****************************************************************************/
1524 void ui_destblt(uint8 opcode, int x, int y, int cx, int cy)
1525 {
1526   if (warp_coords(&x, &y, &cx, &cy, NULL, NULL))
1527   {
1528     if (contains_mouse(x, y, cx, cy))
1529       draw_cursor_under(mousex, mousey);
1530     fill_rect(x, y, cx, cy, -1, opcode);
1531     cache_rect(x, y, cx, cy, False);
1532   }
1533 }
1534 
1535 /*****************************************************************************/
1536 void ui_move_pointer(int x, int y)
1537 {
1538 }
1539 
1540 /*****************************************************************************/
1541 void ui_set_null_cursor(void)
1542 {
1543   draw_cursor_under(mousex, mousey);
1544   mousex = mousex - mcursor.x;
1545   mousey = mousey - mcursor.y;
1546   memset(&mcursor, 0, sizeof(mcursor));
1547   memset(mcursor.andmask, 255, sizeof(mcursor.andmask));
1548   memset(mcursor.xormask, 0, sizeof(mcursor.xormask));
1549   draw_cursor();
1550 }
1551 
1552 /*****************************************************************************/
1553 void ui_paint_bitmap(int x, int y, int cx, int cy,
1554                      int width, int height, uint8* data)
1555 {
1556   if (warp_coords(&x, &y, &cx, &cy, NULL, NULL))
1557   {
1558     if (contains_mouse(x, y, cx, cy))
1559       draw_cursor_under(mousex, mousey);
1560     accel_draw_box(x, y, cx, cy, data, width * g_server_Bpp);
1561     cache_rect(x, y, cx, cy, False);
1562   }
1563 }
1564 
1565 /*****************************************************************************/
1566 void* ui_create_cursor(unsigned int x, unsigned int y,
1567                        int width, int height,
1568                        uint8* andmask, uint8* xormask)
1569 {
1570   tcursor* c;
1571   int i;
1572   int j;
1573 
1574   c = (tcursor*)xmalloc(sizeof(tcursor));
1575   memset(c, 0, sizeof(tcursor));
1576   c->w = width;
1577   c->h = height;
1578   c->x = x;
1579   c->y = y;
1580   for (i = 0; i < 32; i++)
1581   {
1582     for (j = 0; j < 32; j++)
1583     {
1584       if (is_pixel_on(andmask, j, i, 32, 1))
1585         set_pixel_on(c->andmask, j, 31 - i, 32, 8, 255);
1586       if (is_pixel_on(xormask, j, i, 32, 24))
1587         set_pixel_on(c->xormask, j, 31 - i, 32, 8, 255);
1588     }
1589   }
1590   return (void*)c;
1591 }
1592 
1593 /*****************************************************************************/
1594 void ui_destroy_cursor(void* cursor)
1595 {
1596   if (cursor != NULL)
1597     xfree(cursor);
1598 }
1599 
1600 /*****************************************************************************/
1601 void ui_set_cursor(void* cursor)
1602 {
1603   int x;
1604   int y;
1605   int ox;
1606   int oy;
1607 
1608   ox = mousex;
1609   oy = mousey;
1610   x = mousex + mcursor.x;
1611   y = mousey + mcursor.y;
1612   memcpy(&mcursor, cursor, sizeof(tcursor));
1613   mousex = x - mcursor.x;
1614   mousey = y - mcursor.y;
1615   draw_cursor_under(ox, oy);
1616   draw_cursor();
1617 }
1618 
1619 /*****************************************************************************/
1620 uint16 ui_get_numlock_state(unsigned int state)
1621 {
1622   return 0;
1623 }
1624 
1625 /*****************************************************************************/
1626 unsigned int read_keyboard_state(void)
1627 {
1628   return 0;
1629 }
1630 
1631 /*****************************************************************************/
1632 void ui_resize_window(void)
1633 {
1634 }
1635 
1636 /*****************************************************************************/
1637 void ui_begin_update(void)
1638 {
1639 }
1640 
1641 /*****************************************************************************/
1642 void ui_end_update(void)
1643 {
1644   draw_cache_rects();
1645   draw_cursor();
1646 }
1647 
1648 /*****************************************************************************/
1649 void ui_polygon(uint8 opcode, uint8 fillmode, POINT * point, int npoints,
1650                 BRUSH * brush, int bgcolour, int fgcolour)
1651 {
1652 }
1653 
1654 /*****************************************************************************/
1655 void ui_polyline(uint8 opcode, POINT * points, int npoints, PEN * pen)
1656 {
1657 }
1658 
1659 /*****************************************************************************/
1660 void ui_ellipse(uint8 opcode, uint8 fillmode,
1661                 int x, int y, int cx, int cy,
1662                 BRUSH * brush, int bgcolour, int fgcolour)
1663 {
1664 }
1665 
1666 /*****************************************************************************/
1667 void generate_random(uint8* random)
1668 {
1669   memcpy(random, "12345678901234567890123456789012", 32);
1670 }
1671 
1672 /*****************************************************************************/
1673 void save_licence(uint8* data, int length)
1674 {
1675 }
1676 
1677 /*****************************************************************************/
1678 int load_licence(uint8** data)
1679 {
1680   return 0;
1681 }
1682 
1683 /*****************************************************************************/
1684 void* xrealloc(void* in_val, int size)
1685 {
1686   return realloc(in_val, size);
1687 }
1688 
1689 /*****************************************************************************/
1690 void* xmalloc(int size)
1691 {
1692   return malloc(size);
1693 }
1694 
1695 /*****************************************************************************/
1696 void xfree(void* in_val)
1697 {
1698   free(in_val);
1699 }
1700 
1701 /*****************************************************************************/
1702 char * xstrdup(const char * s)
1703 {
1704   char * mem = strdup(s);
1705   if (mem == NULL)
1706   {
1707     perror("strdup");
1708     exit(1);
1709   }
1710   return mem;
1711 }
1712 
1713 /*****************************************************************************/
1714 void warning(char* format, ...)
1715 {
1716   va_list ap;
1717 
1718   fprintf(stderr, "WARNING: ");
1719   va_start(ap, format);
1720   vfprintf(stderr, format, ap);
1721   va_end(ap);
1722 }
1723 
1724 /*****************************************************************************/
1725 void unimpl(char* format, ...)
1726 {
1727   va_list ap;
1728 
1729   fprintf(stderr, "NOT IMPLEMENTED: ");
1730   va_start(ap, format);
1731   vfprintf(stderr, format, ap);
1732   va_end(ap);
1733 }
1734 
1735 /*****************************************************************************/
1736 void error(char* format, ...)
1737 {
1738   va_list ap;
1739 
1740   fprintf(stderr, "ERROR: ");
1741   va_start(ap, format);
1742   vfprintf(stderr, format, ap);
1743   va_end(ap);
1744 }
1745 
1746 BOOL rd_pstcache_mkdir(void)
1747 {
1748   return 0;
1749 }
1750 
1751 /*****************************************************************************/
1752 int rd_open_file(char *filename)
1753 {
1754   return 0;
1755 }
1756 
1757 /*****************************************************************************/
1758 void rd_close_file(int fd)
1759 {
1760   return;
1761 }
1762 
1763 /*****************************************************************************/
1764 int rd_read_file(int fd, void *ptr, int len)
1765 {
1766   return 0;
1767 }
1768 
1769 /*****************************************************************************/
1770 int rd_write_file(int fd, void* ptr, int len)
1771 {
1772   return 0;
1773 }
1774 
1775 /*****************************************************************************/
1776 int rd_lseek_file(int fd, int offset)
1777 {
1778   return 0;
1779 }
1780 
1781 /*****************************************************************************/
1782 BOOL rd_lock_file(int fd, int start, int len)
1783 {
1784   return False;
1785 }
1786 
1787 /*****************************************************************************/
1788 void get_username_and_hostname(void)
1789 {
1790   char fullhostname[64];
1791   char* p;
1792   struct passwd* pw;
1793 
1794   STRNCPY(g_username, "unknown", sizeof(g_username));
1795   STRNCPY(g_hostname, "unknown", sizeof(g_hostname));
1796   pw = getpwuid(getuid());
1797   if (pw != NULL && pw->pw_name != NULL)
1798   {
1799     STRNCPY(g_username, pw->pw_name, sizeof(g_username));
1800   }
1801   if (gethostname(fullhostname, sizeof(fullhostname)) != -1)
1802   {
1803     p = strchr(fullhostname, '.');
1804     if (p != NULL)
1805       *p = 0;
1806     STRNCPY(g_hostname, fullhostname, sizeof(g_hostname));
1807   }
1808 }
1809 
1810 /*****************************************************************************/
1811 void out_params(void)
1812 {
1813   fprintf(stderr, "rdesktop: A Remote Desktop Protocol client.\n");
1814   fprintf(stderr, "Version " VERSION ". Copyright (C) 1999-2003 Matt Chapman.\n");
1815   fprintf(stderr, "See http://www.rdesktop.org/ for more information.\n\n");
1816   fprintf(stderr, "Usage: svgardesktop [options] server\n");
1817   fprintf(stderr, "   -g: desktop geometry (WxH)\n");
1818   fprintf(stderr, "   -4: use RDP version 4\n");
1819   fprintf(stderr, "   -5: use RDP version 5 (default)\n");
1820   fprintf(stderr, "   -t: tcp port\n");
1821   fprintf(stderr, "   -u: user name\n");
1822   fprintf(stderr, "   -n: client hostname\n");
1823   fprintf(stderr, "   -d: disable accel funcs\n");
1824   fprintf(stderr, "   -a: connection colour depth\n");
1825   fprintf(stderr, "   -l: low memory\n");
1826   fprintf(stderr, "\n");
1827 }
1828 
1829 /* produce a hex dump */
1830 void hexdump(uint8* p, uint32 len)
1831 {
1832   uint8* line;
1833   int i;
1834   int thisline;
1835   int offset;
1836 
1837   line = p;
1838   offset = 0;
1839   while (offset < len)
1840   {
1841     printf("%04x ", offset);
1842     thisline = len - offset;
1843     if (thisline > 16)
1844       thisline = 16;
1845 
1846     for (i = 0; i < thisline; i++)
1847       printf("%02x ", line[i]);
1848 
1849     for (; i < 16; i++)
1850       printf("   ");
1851 
1852     for (i = 0; i < thisline; i++)
1853       printf("%c", (line[i] >= 0x20 && line[i] < 0x7f) ? line[i] : '.');
1854 
1855     printf("\n");
1856     offset += thisline;
1857     line += thisline;
1858   }
1859 }
1860 
1861 /*****************************************************************************/
1862 int parse_parameters(int in_argc, char** in_argv)
1863 {
1864   int i;
1865   char* p;
1866 
1867   if (in_argc <= 1)
1868   {
1869     out_params();
1870     return 0;
1871   }
1872   g_argc = in_argc;
1873   g_argv = in_argv;
1874   for (i = 1; i < in_argc; i++)
1875   {
1876     strcpy(g_servername, in_argv[i]);
1877     if (strcmp(in_argv[i], "-g") == 0)
1878     {
1879       g_width = strtol(in_argv[i + 1], &p, 10);
1880       if (g_width <= 0)
1881       {
1882         error("invalid geometry\n");
1883         return 0;
1884       }
1885       if (*p == 'x')
1886         g_height = strtol(p + 1, NULL, 10);
1887       if (g_height <= 0)
1888       {
1889         error("invalid geometry\n");
1890         return 0;
1891       }
1892       g_width = (g_width + 3) & ~3;
1893     }
1894     else if (strcmp(in_argv[i], "-4") == 0)
1895       g_use_rdp5 = 0;
1896     else if (strcmp(in_argv[i], "-5") == 0)
1897       g_use_rdp5 = 1;
1898     else if (strcmp(in_argv[i], "-t") == 0)
1899       g_tcp_port_rdp = strtol(in_argv[i + 1], &p, 10);
1900     else if (strcmp(in_argv[i], "-h") == 0)
1901     {
1902       out_params();
1903       return 0;
1904     }
1905     else if (strcmp(in_argv[i], "-n") == 0)
1906     {
1907       STRNCPY(g_hostname, in_argv[i + 1], sizeof(g_hostname));
1908     }
1909     else if (strcmp(in_argv[i], "-u") == 0)
1910     {
1911       STRNCPY(g_username, in_argv[i + 1], sizeof(g_username));
1912     }
1913     else if (strcmp(in_argv[i], "-d") == 0)
1914     {
1915       use_accel = 0;
1916     }
1917     else if (strcmp(in_argv[i], "-a") == 0)
1918     {
1919       g_server_bpp = strtol(in_argv[i + 1], NULL, 10);
1920       if (g_server_bpp != 8 && g_server_bpp != 16)
1921       {
1922         error("invalid server bpp\n");
1923         return 0;
1924       }
1925       g_server_Bpp = (g_server_bpp + 7) / 8;
1926     }
1927     else if (strcmp(in_argv[i], "-l") == 0)
1928       g_save_mem = 1;
1929   }
1930   return 1;
1931 }
1932 
1933 /*****************************************************************************/
1934 int main(int in_argc, char** in_argv)
1935 {
1936   get_username_and_hostname();
1937   if (!parse_parameters(in_argc, in_argv))
1938     return 0;
1939   if (!ui_init())
1940     return 1;
1941   if (!ui_create_window())
1942     return 1;
1943   ui_main_loop();
1944   ui_destroy_window();
1945   ui_deinit();
1946   return 0;
1947 }
1948