1 /* -*- c-basic-offset: 8 -*-
2    rdesktop: A Remote Desktop Protocol client.
3    User interface services - NanoX(microwindows)
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   problems with nanox lib
22     opcodes don't work, can only rely on copy
23     stipple orgins don't work
24     clip seems to affect source too, it should only affect dest
25       in copyarea functions
26 */
27 
28 #include "../rdesktop.h"
29 
30 #include <stdarg.h>  /* va_list va_start va_end */
31 #include <unistd.h> /* gethostname */
32 #include <pwd.h> /* getpwuid */
33 
34 #include <nano-X.h>
35 
36 extern int g_tcp_port_rdp;
37 int g_use_rdp5 = 1;
38 char g_hostname[16];
39 char g_username[64];
40 int g_width = 800;
41 int g_height = 600;
42 int g_server_bpp = 16;
43 int g_encryption = 1;
44 int g_desktop_save = 0; /* todo */
45 int g_polygon_ellipse_orders = 0;
46 int g_bitmap_cache = 1;
47 int g_bitmap_cache_persist_enable = 0;
48 int g_bitmap_cache_precache = 1;
49 int g_bitmap_compression = 1;
50 uint32 g_rdp5_performanceflags =
51   RDP5_NO_WALLPAPER | RDP5_NO_FULLWINDOWDRAG | RDP5_NO_MENUANIMATIONS;
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 static int g_sck = 0;
59 static char g_servername[256] = "";
60 static char g_password[64] = "";
61 static char g_domain[64] = "";
62 static char g_shell[64] = "";
63 static char g_directory[64] = "";
64 static GR_WINDOW_ID g_wnd = 0;
65 static GR_GC_ID g_gc = 0;
66 static GR_GC_ID g_gc_clean = 0;
67 static int g_deactivated = 0;
68 static int g_ext_disc_reason = 0;
69 static GR_SCREEN_INFO g_screen_info;
70 static int g_bpp = 0;
71 static int g_Bpp = 0;
72 static GR_RECT g_clip; /* set in main */
73 static GR_CURSOR_ID g_null_cursor; /* set in main */
74 static int g_flags = RDP_LOGON_NORMAL;
75 
76 struct key
77 {
78   int ch1;
79   int ch2;
80   int ch3;
81   int chs; /* shift char */
82 };
83 
84 static struct key g_keys[256];
85 
86 /* Session Directory redirection */
87 BOOL g_redirect = False;
88 char g_redirect_server[64];
89 char g_redirect_domain[16];
90 char g_redirect_password[64];
91 char g_redirect_username[64];
92 char g_redirect_cookie[128];
93 uint32 g_redirect_flags = 0;
94 
95 #define COLOR16TO32(color) \
96 ( \
97   ((((color >> 8) & 0xf8) | ((color >> 13) & 0x7)) <<  0) | \
98   ((((color >> 3) & 0xfc) | ((color >>  9) & 0x3)) <<  8) | \
99   ((((color << 3) & 0xf8) | ((color >>  2) & 0x7)) << 16) \
100 )
101 
102 static uint32 g_ops[16] =
103 {
104   GR_MODE_CLEAR,         /* 0 */
105   GR_MODE_NOR,           /* ~(src | dst) */
106   GR_MODE_ANDINVERTED,   /* (~src) & dst */
107   GR_MODE_COPYINVERTED,  /* ~src */
108   GR_MODE_ANDREVERSE,    /* src & (~dst) */
109   GR_MODE_INVERT,        /* ~(dst) */
110   GR_MODE_XOR,           /* src ^ dst */
111   GR_MODE_NAND,          /* ~(src & dst) */
112   GR_MODE_AND,           /* src & dst */
113   GR_MODE_EQUIV,         /* ~(src) ^ dst or is it ~(src ^ dst) */
114   GR_MODE_NOOP,          /* dst */
115   GR_MODE_ORINVERTED,    /* (~src) | dst */
116   GR_MODE_COPY,          /* src */
117   GR_MODE_ORREVERSE,     /* src | (~dst) */
118   GR_MODE_OR,            /* src | dst */
119   GR_MODE_SETTO1         /* ~0 */
120 };
121 
122 /*****************************************************************************/
123 /* do a raster op */
124 static int rop(int rop, int src, int dst)
125 {
126   switch (rop)
127   {
128     case 0x0: return 0;
129     case 0x1: return ~(src | dst);
130     case 0x2: return (~src) & dst;
131     case 0x3: return ~src;
132     case 0x4: return src & (~dst);
133     case 0x5: return ~(dst);
134     case 0x6: return src ^ dst;
135     case 0x7: return ~(src & dst);
136     case 0x8: return src & dst;
137     case 0x9: return ~(src) ^ dst;
138     case 0xa: return dst;
139     case 0xb: return (~src) | dst;
140     case 0xc: return src;
141     case 0xd: return src | (~dst);
142     case 0xe: return src | dst;
143     case 0xf: return ~0;
144   }
145   return dst;
146 }
147 
148 /*****************************************************************************/
149 static int get_pixel32(uint8 * data, int x, int y,
150                        int width, int height)
151 {
152   if (x >= 0 && y >= 0 && x < width && y < height)
153   {
154     return *(((int*)data) + (y * width + x));
155   }
156   else
157   {
158     return 0;
159   }
160 }
161 
162 /*****************************************************************************/
163 static void set_pixel32(uint8 * data, int x, int y,
164                         int width, int height, int pixel)
165 {
166   if (x >= 0 && y >= 0 && x < width && y < height)
167   {
168     *(((int*)data) + (y * width + x)) = pixel;
169   }
170 }
171 
172 /*****************************************************************************/
173 static int warp_coords(int * x, int * y, int * cx, int * cy,
174                        int * srcx, int * srcy)
175 {
176   int dx;
177   int dy;
178 
179   if (g_clip.x > *x)
180   {
181     dx = g_clip.x - *x;
182   }
183   else
184   {
185     dx = 0;
186   }
187   if (g_clip.y > *y)
188   {
189     dy = g_clip.y - *y;
190   }
191   else
192   {
193     dy = 0;
194   }
195   if (*x + *cx > g_clip.x + g_clip.width)
196   {
197     *cx = (*cx - ((*x + *cx) - (g_clip.x + g_clip.width)));
198   }
199   if (*y + *cy > g_clip.y + g_clip.height)
200   {
201     *cy = (*cy - ((*y + *cy) - (g_clip.y + g_clip.height)));
202   }
203   *cx = *cx - dx;
204   *cy = *cy - dy;
205   if (*cx <= 0)
206   {
207     return 0;
208   }
209   if (*cy <= 0)
210   {
211     return 0;
212   }
213   *x = *x + dx;
214   *y = *y + dy;
215   if (srcx != 0)
216   {
217     *srcx = *srcx + dx;
218   }
219   if (srcy != 0)
220   {
221     *srcy = *srcy + dy;
222   }
223   return 1;
224 }
225 
226 /******************************************************************************/
227 /* check if a certain pixel is set in a bitmap */
228 static int is_pixel_on(uint8 * data, int x, int y, int width, int bpp)
229 {
230   int start;
231   int shift;
232 
233   if (bpp == 1)
234   {
235     width = (width + 7) / 8;
236     start = (y * width) + x / 8;
237     shift = x % 8;
238     return (data[start] & (0x80 >> shift)) != 0;
239   }
240   else
241     return 0;
242 }
243 
244 /*****************************************************************************/
245 int ui_select(int in)
246 {
247   if (g_sck == 0)
248   {
249     g_sck = in;
250   }
251   return 1;
252 }
253 
254 /*****************************************************************************/
255 void ui_set_clip(int x, int y, int cx, int cy)
256 {
257   GR_REGION_ID region;
258 
259   g_clip.x = x;
260   g_clip.y = y;
261   g_clip.width = cx;
262   g_clip.height = cy;
263   region = GrNewRegion();
264   GrUnionRectWithRegion(region, &g_clip);
265   GrSetGCRegion(g_gc, region); /* can't destroy region here, i guess gc */
266                                /* takes owership, if you destroy it */
267                                /* clip is reset, hum */
268 }
269 
270 /*****************************************************************************/
271 void ui_reset_clip(void)
272 {
273   GrSetGCRegion(g_gc, 0);
274   g_clip.x = 0;
275   g_clip.y = 0;
276   g_clip.width = g_width;
277   g_clip.height = g_height;
278 }
279 
280 /*****************************************************************************/
281 void ui_bell(void)
282 {
283   GrBell();
284 }
285 
286 /*****************************************************************************/
287 /* gota convert the rdp glyph to nanox glyph */
288 void * ui_create_glyph(int width, int height, uint8 * data)
289 {
290   char * p, * q, * r;
291   int datasize, i, j;
292 
293   datasize = GR_BITMAP_SIZE(width, height) * sizeof(GR_BITMAP);
294   p = xmalloc(datasize);
295   q = p;
296   r = data;
297   memset(p, 0, datasize);
298   for (i = 0; i < height; i++)
299   {
300     j = 0;
301     while (j + 8 < width)
302     {
303       *q = *(r + 1);
304       q++;
305       r++;
306       *q = *(r - 1);
307       q++;
308       r++;
309       j += 16;
310     }
311     if ((width % 16) <= 8 && (width % 16) > 0)
312     {
313       q++;
314       *q = *r;
315       q++;
316       r++;
317       j += 8;
318     }
319   }
320   return p;
321 }
322 
323 /*****************************************************************************/
324 void ui_destroy_glyph(void * glyph)
325 {
326   xfree(glyph);
327 }
328 
329 /*****************************************************************************/
330 void * ui_create_colourmap(COLOURMAP * colors)
331 {
332   return 0;
333 }
334 
335 /*****************************************************************************/
336 void ui_set_colourmap(void * map)
337 {
338 }
339 
340 /*****************************************************************************/
341 void * ui_create_bitmap(int width, int height, uint8 * data)
342 {
343   GR_WINDOW_ID pixmap;
344   uint8 * p;
345   uint32 i, j, pixel;
346 
347   p = data;
348   pixmap = GrNewPixmap(width, height, 0);
349   if (g_server_bpp == 16 && g_bpp == 32)
350   {
351     p = xmalloc(width * height * g_Bpp);
352     for (i = 0; i < height; i++)
353     {
354       for (j = 0; j < width; j++)
355       {
356         pixel = *(((uint16 *) data) + (i * width + j));
357         pixel = COLOR16TO32(pixel);
358         *(((uint32 *) p) + (i * width + j)) = pixel;
359       }
360     }
361   }
362   GrArea(pixmap, g_gc_clean, 0, 0, width, height, p, MWPF_RGB);
363   if (p != data)
364   {
365     xfree(p);
366   }
367   return (void *) pixmap;
368 }
369 
370 /*****************************************************************************/
371 void ui_destroy_bitmap(void * bmp)
372 {
373   GrDestroyWindow((GR_WINDOW_ID)bmp);
374 }
375 
376 /*****************************************************************************/
377 #define DO_GLYPH(ttext,idx) \
378 { \
379   glyph = cache_get_font (font, ttext[idx]); \
380   if (!(flags & TEXT2_IMPLICIT_X)) \
381   { \
382     xyoffset = ttext[++idx]; \
383     if ((xyoffset & 0x80)) \
384     { \
385       if (flags & TEXT2_VERTICAL) \
386       { \
387         y += ttext[idx+1] | (ttext[idx+2] << 8); \
388       } \
389       else \
390       { \
391         x += ttext[idx+1] | (ttext[idx+2] << 8); \
392       } \
393       idx += 2; \
394     } \
395     else \
396     { \
397       if (flags & TEXT2_VERTICAL) \
398       { \
399         y += xyoffset; \
400       } \
401       else \
402       { \
403         x += xyoffset; \
404       } \
405     } \
406   } \
407   if (glyph != NULL) \
408   { \
409     x1 = x + glyph->offset; \
410     y1 = y + glyph->baseline; \
411     GrBitmap(g_wnd, g_gc, x1, y1, glyph->width, glyph->height, glyph->pixmap); \
412     if (flags & TEXT2_IMPLICIT_X) \
413     { \
414       x += glyph->width; \
415     } \
416   } \
417 }
418 
419 /*****************************************************************************/
420 void ui_draw_text(uint8 font, uint8 flags, uint8 opcode, int mixmode,
421                   int x, int y,
422                   int clipx, int clipy, int clipcx, int clipcy,
423                   int boxx, int boxy, int boxcx, int boxcy, BRUSH * brush,
424                   int bgcolor, int fgcolor, uint8 * text, uint8 length)
425 {
426   FONTGLYPH * glyph;
427   int i, j, xyoffset, x1, y1;
428   DATABLOB * entry;
429 
430   GrSetGCMode(g_gc, GR_MODE_COPY);
431   GrSetGCUseBackground(g_gc, 0); /* this can be set when gc is created */
432   if (g_server_bpp == 16 && g_bpp == 32)
433   {
434     fgcolor = COLOR16TO32(fgcolor);
435     bgcolor = COLOR16TO32(bgcolor);
436   }
437   GrSetGCForeground(g_gc, bgcolor);
438   if (boxx + boxcx > g_width)
439   {
440     boxcx = g_width - boxx;
441   }
442   if (boxcx > 1)
443   {
444     GrFillRect(g_wnd, g_gc, boxx, boxy, boxcx, boxcy);
445   }
446   else if (mixmode == MIX_OPAQUE)
447   {
448     GrFillRect(g_wnd, g_gc, clipx, clipy, clipcx, clipcy);
449   }
450   GrSetGCForeground(g_gc, fgcolor);
451   /* Paint text, character by character */
452   for (i = 0; i < length;)
453   {
454     switch (text[i])
455     {
456       case 0xff:
457         if (i + 2 < length)
458         {
459           cache_put_text(text[i + 1], text, text[i + 2]);
460         }
461         else
462         {
463           error("this shouldn't be happening\n");
464           exit(1);
465         }
466         /* this will move pointer from start to first character after */
467         /* FF command */
468         length -= i + 3;
469         text = &(text[i + 3]);
470         i = 0;
471         break;
472       case 0xfe:
473         entry = cache_get_text(text[i + 1]);
474         if (entry != NULL)
475         {
476           if ((((uint8 *) (entry->data))[1] == 0) &&
477                                 (!(flags & TEXT2_IMPLICIT_X)))
478           {
479             if (flags & TEXT2_VERTICAL)
480             {
481               y += text[i + 2];
482             }
483             else
484             {
485               x += text[i + 2];
486             }
487           }
488           for (j = 0; j < entry->size; j++)
489           {
490             DO_GLYPH(((uint8 *) (entry->data)), j);
491           }
492         }
493         if (i + 2 < length)
494         {
495           i += 3;
496         }
497         else
498         {
499           i += 2;
500         }
501         length -= i;
502         /* this will move pointer from start to first character after */
503         /* FE command */
504         text = &(text[i]);
505         i = 0;
506         break;
507       default:
508         DO_GLYPH(text, i);
509         i++;
510         break;
511     }
512   }
513 }
514 
515 /*****************************************************************************/
516 void ui_line(uint8 opcode, int startx, int starty, int endx, int endy,
517              PEN * pen)
518 {
519   uint32 op;
520   uint32 color;
521 
522   color = pen->colour;
523   if (opcode == 5) /* GR_MODE_INVERT, not supported so convert it */
524   {                /* i think x ^ -1 = ~x */
525     color = 0xffffffff;
526     opcode = 6; /* GR_MODE_XOR */
527   }
528   if (opcode == 12 || opcode == 6) /* nanox only supports these 2 opcode */
529   {
530     op = g_ops[opcode];
531     GrSetGCMode(g_gc, op);
532     if (g_server_bpp == 16 && g_bpp == 32)
533     {
534       color = COLOR16TO32(color);
535     }
536     GrSetGCForeground(g_gc, color);
537     GrLine(g_wnd, g_gc, startx, starty, endx, endy);
538     GrSetGCMode(g_gc, GR_MODE_COPY);
539   }
540   else
541   {
542     unimpl("opcode %d in ui_line\n", opcode);
543   }
544 }
545 
546 /*****************************************************************************/
547 void ui_triblt(uint8 opcode, int x, int y, int cx, int cy,
548                void * src, int srcx, int srcy,
549                BRUSH * brush, int bgcolor, int fgcolor)
550 {
551 /* not used, turned off */
552 }
553 
554 /*****************************************************************************/
555 void ui_memblt(uint8 opcode, int x, int y, int cx, int cy,
556                void * src, int srcx, int srcy)
557 {
558   uint8 * dest;
559   uint8 * source;
560   uint8 * final;
561   GR_WINDOW_INFO wi;
562   int i, j, s, d;
563   GR_WINDOW_ID pixmap;
564 
565   if (opcode == 12)
566   {
567     GrCopyArea(g_wnd, g_gc, x, y, cx, cy, (GR_DRAW_ID)src, srcx, srcy,
568                GR_MODE_COPY);
569   }
570   else /* do opcodes ourself */
571   {    /* slow but its correct, ok to be slow here, these are rare */
572     GrGetWindowInfo((GR_DRAW_ID)src, &wi);
573     dest = xmalloc(cx * cy * g_Bpp);
574     source = xmalloc(wi.width * wi.height * g_Bpp);
575     final = xmalloc(cx * cy * g_Bpp);
576     memset(final, 0, cx * cy * g_Bpp);
577     /* dest */
578     GrReadArea(g_wnd, x, y, cx, cy, (GR_PIXELVAL*)dest);
579     /* source */
580     GrReadArea((GR_DRAW_ID)src, 0, 0,
581                wi.width, wi.height, (GR_PIXELVAL*)source);
582     for (i = 0; i < cy; i++)
583     {
584       for (j = 0; j < cx; j++)
585       {
586         s = get_pixel32(source, j + srcx, i + srcy, wi.width, wi.height);
587         d = get_pixel32(dest, j, i, cx ,cy);
588         set_pixel32(final, j, i, cx, cy, rop(opcode, s, d));
589       }
590     }
591     pixmap = GrNewPixmap(cx, cy, 0);
592     GrArea(pixmap, g_gc_clean, 0, 0, cx, cy, final, MWPF_TRUECOLOR0888);
593     GrCopyArea(g_wnd, g_gc, x, y, cx, cy, pixmap, 0, 0, GR_MODE_COPY);
594     GrDestroyWindow(pixmap);
595     xfree(dest);
596     xfree(source);
597     xfree(final);
598   }
599 }
600 
601 /*****************************************************************************/
602 void ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy)
603 {
604 /* not used, turned off */
605 }
606 
607 /*****************************************************************************/
608 void ui_desktop_save(uint32 offset, int x, int y, int cx, int cy)
609 {
610 /* not used, turned off */
611 }
612 
613 /*****************************************************************************/
614 void ui_rect(int x, int y, int cx, int cy, int color)
615 {
616   if (g_server_bpp == 16 && g_bpp == 32)
617   {
618     color = COLOR16TO32(color);
619   }
620   GrSetGCForeground(g_gc, color);
621   GrFillRect(g_wnd, g_gc, x, y, cx, cy);
622 }
623 
624 /*****************************************************************************/
625 /* using warp_coords cause clip seems to affect source in GrCopyArea */
626 void ui_screenblt(uint8 opcode, int x, int y, int cx, int cy,
627                   int srcx, int srcy)
628 {
629   if (opcode == 12)
630   {
631     if (warp_coords(&x, &y, &cx, &cy, &srcx, &srcy))
632     {
633       GrCopyArea(g_wnd, g_gc_clean, x, y, cx, cy, g_wnd, srcx, srcy,
634                  GR_MODE_COPY);
635     }
636   }
637   else
638   {
639     unimpl("opcode %d in ui_screenblt\n", opcode);
640   }
641 }
642 
643 /******************************************************************************/
644 /* can't use stipple cause tsorigin don't work, GrPoint too slow,
645    GrPoints too slow but better, using a copy from the screen,
646    do the pattern and copy it back */
647 void ui_patblt(uint8 opcode, int x, int y, int cx, int cy,
648                BRUSH * brush, int bgcolor, int fgcolor)
649 {
650   uint8 ipattern[8], * dest, * final;
651   uint32 op;
652   int i, j, s, d;
653   GR_WINDOW_ID pixmap;
654 
655   if (g_server_bpp == 16 && g_bpp == 32)
656   {
657     fgcolor = COLOR16TO32(fgcolor);
658     bgcolor = COLOR16TO32(bgcolor);
659   }
660   switch (brush->style)
661   {
662     case 0: /* Solid */
663       if (opcode == 12 || opcode == 6)
664       {
665         op = g_ops[opcode];
666         GrSetGCMode(g_gc, op);
667         GrSetGCForeground(g_gc, fgcolor);
668         GrFillRect(g_wnd, g_gc, x, y, cx, cy);
669         GrSetGCMode(g_gc, GR_MODE_COPY);
670       }
671       else
672       {
673         unimpl("opcode %d in ui_patblt solid brush\n", opcode);
674       }
675       break;
676     case 3: /* Pattern - all opcodes ok */
677       for (i = 0; i != 8; i++)
678       {
679         ipattern[7 - i] = brush->pattern[i];
680       }
681       dest = xmalloc(cx * cy * g_Bpp);
682       final = xmalloc(cx * cy * g_Bpp);
683       memset(final, 0, cx * cy * g_Bpp);
684       /* dest */
685       if (opcode != 12)
686       {
687         GrReadArea(g_wnd, x, y, cx, cy, (GR_PIXELVAL*)dest);
688       }
689       for (i = 0; i < cy; i++)
690       {
691         for (j = 0; j < cx; j++)
692         {
693           if (is_pixel_on(ipattern, (x + j + brush->xorigin) % 8,
694                           (y + i + brush->yorigin) % 8, 8, 1))
695           {
696             s = fgcolor;
697           }
698           else
699           {
700             s = bgcolor;
701           }
702           d = get_pixel32(dest, j, i, cx ,cy);
703           set_pixel32(final, j, i, cx, cy, rop(opcode, s, d));
704         }
705       }
706       pixmap = GrNewPixmap(cx, cy, 0);
707       GrArea(pixmap, g_gc_clean, 0, 0, cx, cy, final, MWPF_TRUECOLOR0888);
708       GrCopyArea(g_wnd, g_gc, x, y, cx, cy, pixmap, 0, 0, GR_MODE_COPY);
709       GrDestroyWindow(pixmap);
710       xfree(dest);
711       xfree(final);
712       break;
713   }
714 }
715 
716 /*****************************************************************************/
717 void ui_destblt(uint8 opcode, int x, int y, int cx, int cy)
718 {
719   uint32 op;
720 
721   if (opcode == 0) /* black */
722   {
723     GrSetGCForeground(g_gc, 0);
724     opcode = 12;
725   }
726   else if (opcode == 5) /* invert */
727   {
728     GrSetGCForeground(g_gc, 0xffffffff);
729     opcode = 6;
730   }
731   else if (opcode == 15) /* white */
732   {
733     GrSetGCForeground(g_gc, 0xffffffff);
734     opcode = 12;
735   }
736   if (opcode == 12 || opcode == 6)
737   {
738     op = g_ops[opcode];
739     GrSetGCMode(g_gc, op);
740     GrFillRect(g_wnd, g_gc, x, y, cx, cy);
741     GrSetGCMode(g_gc, GR_MODE_COPY);
742   }
743   else
744   {
745     unimpl("opcode %d in ui_destblt\n", opcode);
746   }
747 }
748 
749 /*****************************************************************************/
750 void ui_paint_bitmap(int x, int y, int cx, int cy,
751                      int width, int height, uint8 * data)
752 {
753   void * b;
754 
755   b = ui_create_bitmap(width, height, data);
756   ui_memblt(12, x, y, cx, cy, b, 0, 0);
757   ui_destroy_bitmap(b);
758 }
759 
760 /*****************************************************************************/
761 void ui_move_pointer(int x, int y)
762 {
763   GrMoveCursor(x, y);
764 }
765 
766 /*****************************************************************************/
767 void ui_set_null_cursor(void)
768 {
769   GrSetWindowCursor(g_wnd, g_null_cursor);
770 }
771 
772 /*****************************************************************************/
773 void ui_set_cursor(void * cursor)
774 {
775   GrSetWindowCursor(g_wnd, (GR_CURSOR_ID)cursor);
776 }
777 
778 //******************************************************************************
779 static int is24on(uint8 * data, int x, int y)
780 {
781   uint8 r, g, b;
782   int start;
783 
784   if (data == 0)
785   {
786     return 0;
787   }
788   start = y * 32 * 3 + x * 3;
789   r = data[start];
790   g = data[start + 1];
791   b = data[start + 2];
792   return !((r == 0) && (g == 0) && (b == 0));
793 }
794 
795 //******************************************************************************
796 static int is1on(uint8 * data, int x, int y)
797 {
798   int start;
799   int shift;
800 
801   if (data == 0)
802   {
803     return 0;
804   }
805   start = (y * 32) / 8 + x / 8;
806   shift = x % 8;
807   return (data[start] & (0x80 >> shift)) == 0;
808 }
809 
810 //******************************************************************************
811 static void set1(uint8 * data, int x, int y)
812 {
813   int start;
814   int shift;
815 
816   if (data == 0)
817   {
818     return;
819   }
820   start = (y * 32) / 8 + x / 8;
821   shift = x % 8;
822   data[start] = data[start] | (0x80 >> shift);
823 }
824 
825 //******************************************************************************
826 static void flipover(uint8 * data)
827 {
828   uint8 adata[128];
829   int index;
830 
831   if (data == 0)
832   {
833     return;
834   }
835   memcpy(adata, data, 128);
836   for (index = 0; index <= 31; index++)
837   {
838     data[127 - (index * 4 + 3)] = adata[index * 4];
839     data[127 - (index * 4 + 2)] = adata[index * 4 + 1];
840     data[127 - (index * 4 + 1)] = adata[index * 4 + 2];
841     data[127 - index * 4] = adata[index * 4 + 3];
842   }
843 }
844 
845 /*****************************************************************************/
846 void * ui_create_cursor(uint32 x, uint32 y,
847                         int width, int height,
848                         uint8 * andmask, uint8 * xormask)
849 {
850   uint8 adata[128];
851   uint8 amask[128];
852   GR_BITMAP * databitmap;
853   GR_BITMAP * maskbitmap;
854   GR_CURSOR_ID cursor;
855   int i1, i2, bon, mon;
856 
857   if (width != 32 || height != 32)
858   {
859     return 0;
860   }
861   memset(adata, 0, 128);
862   memset(amask, 0, 128);
863   for (i1 = 0; i1 <= 31; i1++)
864   {
865     for (i2 = 0; i2 <= 31; i2++)
866     {
867       mon = is24on(xormask, i1, i2);
868       bon = is1on(andmask, i1, i2);
869       if (bon ^ mon) // xor
870       {
871         set1(adata, i1, i2);
872         if (!mon)
873         {
874           set1(amask, i1, i2);
875         }
876       }
877       if (mon)
878       {
879         set1(amask, i1, i2);
880       }
881     }
882   }
883   flipover(adata);
884   flipover(amask);
885   databitmap = ui_create_glyph(32, 32, adata);
886   maskbitmap = ui_create_glyph(32, 32, amask);
887   cursor = GrNewCursor(32, 32, x, y, 0xffffff, 0, databitmap, maskbitmap);
888   ui_destroy_glyph(databitmap);
889   ui_destroy_glyph(maskbitmap);
890   return (void*)cursor;
891 }
892 
893 /*****************************************************************************/
894 void ui_destroy_cursor(void * cursor)
895 {
896   GrDestroyCursor((GR_CURSOR_ID)cursor);
897 }
898 
899 /*****************************************************************************/
900 uint16 ui_get_numlock_state(uint32 state)
901 {
902   return 0;
903 }
904 
905 /*****************************************************************************/
906 uint32 read_keyboard_state(void)
907 {
908   return 0;
909 }
910 
911 /*****************************************************************************/
912 void ui_resize_window(void)
913 {
914 }
915 
916 /*****************************************************************************/
917 void ui_begin_update(void)
918 {
919 }
920 
921 /*****************************************************************************/
922 void ui_end_update(void)
923 {
924 }
925 
926 /*****************************************************************************/
927 void ui_polygon(uint8 opcode, uint8 fillmode, POINT * point, int npoints,
928                 BRUSH * brush, int bgcolor, int fgcolor)
929 {
930 /* not used, turned off */
931 }
932 
933 /*****************************************************************************/
934 void ui_polyline(uint8 opcode, POINT * points, int npoints, PEN * pen)
935 {
936   int i, x, y, dx, dy;
937 
938   if (npoints > 0)
939   {
940     x = points[0].x;
941     y = points[0].y;
942     for (i = 1; i < npoints; i++)
943     {
944       dx = points[i].x;
945       dy = points[i].y;
946       ui_line(opcode, x, y, x + dx, y + dy, pen);
947       x = x + dx;
948       y = y + dy;
949     }
950   }
951 }
952 
953 /*****************************************************************************/
954 void ui_ellipse(uint8 opcode, uint8 fillmode,
955                 int x, int y, int cx, int cy,
956                 BRUSH * brush, int bgcolor, int fgcolor)
957 {
958 /* not used, turned off */
959 }
960 
961 /*****************************************************************************/
962 void generate_random(uint8 * random)
963 {
964   memcpy(random, "12345678901234567890123456789012", 32);
965 }
966 
967 /*****************************************************************************/
968 void save_licence(uint8 * data, int length)
969 {
970 }
971 
972 /*****************************************************************************/
973 int load_licence(uint8 ** data)
974 {
975   return 0;
976 }
977 
978 /*****************************************************************************/
979 void * xrealloc(void * in, int size)
980 {
981   if (size < 1)
982   {
983     size = 1;
984   }
985   return realloc(in, size);
986 }
987 
988 /*****************************************************************************/
989 void * xmalloc(int size)
990 {
991   return malloc(size);
992 }
993 
994 /*****************************************************************************/
995 void xfree(void * in)
996 {
997   if (in != 0)
998   {
999     free(in);
1000   }
1001 }
1002 
1003 /*****************************************************************************/
1004 char * xstrdup(const char * s)
1005 {
1006   char * mem = strdup(s);
1007   if (mem == NULL)
1008   {
1009     perror("strdup");
1010     exit(1);
1011   }
1012   return mem;
1013 }
1014 
1015 /*****************************************************************************/
1016 void warning(char * format, ...)
1017 {
1018   va_list ap;
1019 
1020   fprintf(stderr, "WARNING: ");
1021   va_start(ap, format);
1022   vfprintf(stderr, format, ap);
1023   va_end(ap);
1024 }
1025 
1026 /*****************************************************************************/
1027 void unimpl(char * format, ...)
1028 {
1029   va_list ap;
1030 
1031   fprintf(stderr, "NOT IMPLEMENTED: ");
1032   va_start(ap, format);
1033   vfprintf(stderr, format, ap);
1034   va_end(ap);
1035 }
1036 
1037 /*****************************************************************************/
1038 void error(char * format, ...)
1039 {
1040   va_list ap;
1041 
1042   fprintf(stderr, "ERROR: ");
1043   va_start(ap, format);
1044   vfprintf(stderr, format, ap);
1045   va_end(ap);
1046 }
1047 
1048 /*****************************************************************************/
1049 int rd_pstcache_mkdir(void)
1050 {
1051   return 0;
1052 }
1053 
1054 /*****************************************************************************/
1055 int rd_open_file(char * filename)
1056 {
1057   return 0;
1058 }
1059 
1060 /*****************************************************************************/
1061 void rd_close_file(int fd)
1062 {
1063   return;
1064 }
1065 
1066 /*****************************************************************************/
1067 int rd_read_file(int fd, void * ptr, int len)
1068 {
1069   return 0;
1070 }
1071 
1072 /*****************************************************************************/
1073 int rd_write_file(int fd, void * ptr, int len)
1074 {
1075   return 0;
1076 }
1077 
1078 /*****************************************************************************/
1079 int rd_lseek_file(int fd, int offset)
1080 {
1081   return 0;
1082 }
1083 
1084 /*****************************************************************************/
1085 int rd_lock_file(int fd, int start, int len)
1086 {
1087   return False;
1088 }
1089 
1090 /*****************************************************************************/
1091 /*static int key(int ch, int flags)
1092 {
1093   return (ch & 0xffff) | ((flags & 0xffff) << 16);
1094 }*/
1095 
1096 /*****************************************************************************/
1097 static void init_keys(void)
1098 {
1099   memset(&g_keys, 0, sizeof(g_keys));
1100   g_keys[0x01].ch1 = 27; /* esc */
1101   g_keys[0x02].ch1 = '1';
1102   g_keys[0x02].chs = '!';
1103   g_keys[0x03].ch1 = '2';
1104   g_keys[0x03].chs = '@';
1105   g_keys[0x04].ch1 = '3';
1106   g_keys[0x04].chs = '#';
1107   g_keys[0x05].ch1 = '4';
1108   g_keys[0x05].chs = '$';
1109   g_keys[0x06].ch1 = '5';
1110   g_keys[0x06].chs = '%';
1111   g_keys[0x07].ch1 = '6';
1112   g_keys[0x07].chs = '^';
1113   g_keys[0x08].ch1 = '7';
1114   g_keys[0x08].chs = '&';
1115   g_keys[0x09].ch1 = '8';
1116   g_keys[0x09].chs = '*';
1117   g_keys[0x0a].ch1 = '9';
1118   g_keys[0x0a].chs = '(';
1119   g_keys[0x0b].ch1 = '0';
1120   g_keys[0x0b].chs = ')';
1121   g_keys[0x0c].ch1 = '-';
1122   g_keys[0x0c].chs = '_';
1123   g_keys[0x0d].ch1 = '=';
1124   g_keys[0x0d].chs = '+';
1125   g_keys[0x0e].ch1 = 8; /* backspace */
1126   g_keys[0x0f].ch1 = 9; /* tab */
1127   g_keys[0x10].ch1 = 'q';
1128   g_keys[0x10].chs = 'Q';
1129   g_keys[0x11].ch1 = 'w';
1130   g_keys[0x11].chs = 'W';
1131   g_keys[0x12].ch1 = 'e';
1132   g_keys[0x12].chs = 'E';
1133   g_keys[0x13].ch1 = 'r';
1134   g_keys[0x13].chs = 'R';
1135   g_keys[0x14].ch1 = 't';
1136   g_keys[0x14].chs = 'T';
1137   g_keys[0x15].ch1 = 'y';
1138   g_keys[0x15].chs = 'Y';
1139   g_keys[0x16].ch1 = 'u';
1140   g_keys[0x16].chs = 'U';
1141   g_keys[0x17].ch1 = 'i';
1142   g_keys[0x17].chs = 'I';
1143   g_keys[0x18].ch1 = 'o';
1144   g_keys[0x18].chs = 'O';
1145   g_keys[0x19].ch1 = 'p';
1146   g_keys[0x19].chs = 'P';
1147   g_keys[0x1a].ch1 = '[';
1148   g_keys[0x1a].chs = '{';
1149   g_keys[0x1b].ch1 = ']';
1150   g_keys[0x1b].chs = '}';
1151   g_keys[0x1c].ch2 = 13; /* enter */
1152   g_keys[0x1d].ch1 = 63533; /* left control */
1153   g_keys[0x1d].ch2 = 63534; /* right control */
1154   g_keys[0x1e].ch1 = 'a';
1155   g_keys[0x1e].chs = 'A';
1156   g_keys[0x1f].ch1 = 's';
1157   g_keys[0x1f].chs = 'S';
1158   g_keys[0x20].ch1 = 'd';
1159   g_keys[0x20].chs = 'D';
1160   g_keys[0x21].ch1 = 'f';
1161   g_keys[0x21].chs = 'F';
1162   g_keys[0x22].ch1 = 'g';
1163   g_keys[0x22].chs = 'G';
1164   g_keys[0x23].ch1 = 'h';
1165   g_keys[0x23].chs = 'H';
1166   g_keys[0x24].ch1 = 'j';
1167   g_keys[0x24].chs = 'J';
1168   g_keys[0x25].ch1 = 'k';
1169   g_keys[0x25].chs = 'K';
1170   g_keys[0x26].ch1 = 'l';
1171   g_keys[0x26].chs = 'L';
1172   g_keys[0x27].ch1 = ';';
1173   g_keys[0x27].chs = ':';
1174   g_keys[0x28].ch1 = '\'';
1175   g_keys[0x28].chs = '"';
1176   g_keys[0x29].ch1 = '`';
1177   g_keys[0x29].chs = '~';
1178   g_keys[0x2a].ch1 = 63531; /* left shift */
1179   g_keys[0x2b].ch1 = '\\';
1180   g_keys[0x2c].ch1 = 'z';
1181   g_keys[0x2c].chs = 'Z';
1182   g_keys[0x2d].ch1 = 'x';
1183   g_keys[0x2d].chs = 'X';
1184   g_keys[0x2e].ch1 = 'c';
1185   g_keys[0x2e].chs = 'C';
1186   g_keys[0x2f].ch1 = 'v';
1187   g_keys[0x2f].chs = 'V';
1188   g_keys[0x30].ch1 = 'b';
1189   g_keys[0x30].chs = 'B';
1190   g_keys[0x31].ch1 = 'n';
1191   g_keys[0x31].chs = 'N';
1192   g_keys[0x32].ch1 = 'm';
1193   g_keys[0x32].chs = 'M';
1194   g_keys[0x33].ch1 = ',';
1195   g_keys[0x33].chs = '<';
1196   g_keys[0x34].ch1 = '.';
1197   g_keys[0x34].chs = '>';
1198   g_keys[0x35].ch1 = '/';
1199   g_keys[0x35].ch2 = 63509;
1200   g_keys[0x35].chs = '?';
1201   g_keys[0x36].ch1 = 63532; /* right shift */
1202   g_keys[0x37].ch1 = '*'; /* star on keypad */
1203   g_keys[0x37].ch2 = 63510; /* star on keypad */
1204   g_keys[0x38].ch1 = 63535; /* alt */
1205   g_keys[0x38].ch2 = 63536; /* alt */
1206   g_keys[0x39].ch1 = ' ';
1207   g_keys[0x3a].ch1 = 0; /* caps lock */
1208   g_keys[0x3b].ch1 = 63515; /* f1 */
1209   g_keys[0x3c].ch1 = 63516; /* f2 */
1210   g_keys[0x3d].ch1 = 63517; /* f3 */
1211   g_keys[0x3e].ch1 = 63518; /* f4 */
1212   g_keys[0x3f].ch1 = 63519; /* f5 */
1213   g_keys[0x40].ch1 = 63520; /* f6 */
1214   g_keys[0x41].ch1 = 63521; /* f7 */
1215   g_keys[0x42].ch1 = 63522; /* f8 */
1216   g_keys[0x43].ch1 = 63523; /* f9 */
1217   g_keys[0x44].ch1 = 63524; /* f10 */
1218   g_keys[0x45].ch1 = 0; /* num lock */
1219   g_keys[0x46].ch1 = 0; /* scroll lock */
1220   g_keys[0x47].ch1 = 63505; /* home */
1221   g_keys[0x47].ch2 = 63494; /* home */
1222   g_keys[0x48].ch1 = 63490; /* arrow up */
1223   g_keys[0x48].ch2 = 63506; /* arrow up */
1224   g_keys[0x49].ch1 = 63507; /* page up */
1225   g_keys[0x49].ch2 = 63496; /* page up */
1226   g_keys[0x4a].ch1 = '-'; /* -(minus) on keypad */
1227   g_keys[0x4a].ch2 = 63511; /* -(minus) on keypad */
1228   g_keys[0x4b].ch1 = 63502; /* arrow left */
1229   g_keys[0x4b].ch2 = 63488; /* arrow left */
1230   g_keys[0x4c].ch1 = 63503; /* middle(5 key) on keypad */
1231   g_keys[0x4d].ch1 = 63504; /* arrow right */
1232   g_keys[0x4d].ch2 = 63489; /* arrow right */
1233   g_keys[0x4e].ch1 = '+'; /* +(plus) on keypad */
1234   g_keys[0x4e].ch2 = 63512; /* +(plus) on keypad */
1235   g_keys[0x4f].ch1 = 63499; /* end */
1236   g_keys[0x4f].ch2 = 63495; /* end */
1237   g_keys[0x50].ch1 = 63500; /* arrow down */
1238   g_keys[0x50].ch2 = 63491; /* arrow down */
1239   g_keys[0x51].ch1 = 63501; /* page down */
1240   g_keys[0x51].ch2 = 63497; /* page down */
1241   g_keys[0x52].ch1 = 63498; /* insert */
1242   g_keys[0x52].ch2 = 63492; /* insert */
1243   g_keys[0x53].ch1 = 63508; /* delete */
1244   g_keys[0x53].ch2 = 63493; /* delete */
1245   g_keys[0x54].ch1 = 63525; /* f11 */
1246   g_keys[0x54].ch1 = 63527; /* f12 */
1247 }
1248 
1249 /*****************************************************************************/
1250 /* returns 0 if found key */
1251 static int get_sc(GR_EVENT_KEYSTROKE * event_keystroke, int * sc, int * ec)
1252 {
1253   int i;
1254 
1255   //printf("%d %d\n", event_keystroke->ch, event_keystroke->modifiers);
1256   *sc = 0;
1257   *ec = 0;
1258   for (i = 0; i < 256; i++)
1259   {
1260     if (event_keystroke->modifiers & 1) /* shift is down */
1261     {
1262       if (event_keystroke->ch == g_keys[i].chs)
1263       {
1264         *sc = i;
1265         break;
1266       }
1267     }
1268     if (event_keystroke->ch == g_keys[i].ch1 ||
1269         event_keystroke->ch == g_keys[i].ch2 ||
1270         event_keystroke->ch == g_keys[i].ch3)
1271     {
1272       *sc = i;
1273       break;
1274     }
1275   }
1276   if (*sc == 0)
1277   {
1278     return 1;
1279   }
1280   else
1281   {
1282     return 0;
1283   }
1284 }
1285 
1286 /*****************************************************************************/
1287 void static process_keystroke(GR_EVENT_KEYSTROKE * event_keystroke, int down)
1288 {
1289   int sc, ec;
1290 
1291   if (get_sc(event_keystroke, &sc, &ec) == 0)
1292   {
1293     if (down)
1294     {
1295       rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYPRESS, sc, ec);
1296     }
1297     else
1298     {
1299       rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYRELEASE, sc, ec);
1300     }
1301   }
1302 }
1303 
1304 /*****************************************************************************/
1305 void nanox_event(GR_EVENT * ev)
1306 {
1307   GR_EVENT_MOUSE * event_mouse;
1308   GR_EVENT_BUTTON * event_button;
1309   GR_EVENT_FDINPUT * event_fdinput;
1310   GR_EVENT_KEYSTROKE * event_keystroke;
1311 
1312   do
1313   {
1314     if (ev->type == GR_EVENT_TYPE_FDINPUT) /* 12 */
1315     {
1316       event_fdinput = (GR_EVENT_FDINPUT *) ev;
1317       if (event_fdinput->fd == g_sck)
1318       {
1319         if (!rdp_loop(&g_deactivated, &g_ext_disc_reason))
1320         {
1321           fprintf(stderr, "rdp_loop in nanox_event exit codes %d %d\n",
1322                   g_deactivated, g_ext_disc_reason);
1323           exit(1);
1324         }
1325       }
1326     }
1327     else if (ev->type == GR_EVENT_TYPE_BUTTON_DOWN) /* 2 */
1328     {
1329       event_button = (GR_EVENT_BUTTON *) ev;
1330       if (event_button->changebuttons & 4) /* left */
1331       {
1332         rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON1,
1333                        event_button->x, event_button->y);
1334       }
1335       else if (event_button->changebuttons & 1) /* right */
1336       {
1337         rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON2,
1338                        event_button->x, event_button->y);
1339       }
1340     }
1341     else if (ev->type == GR_EVENT_TYPE_BUTTON_UP) /* 3 */
1342     {
1343       event_button = (GR_EVENT_BUTTON *) ev;
1344       if (event_button->changebuttons & 4) /* left */
1345       {
1346         rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON1,
1347                        event_button->x, event_button->y);
1348       }
1349       else if (event_button->changebuttons & 1) /* right */
1350       {
1351         rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON2,
1352                        event_button->x, event_button->y);
1353       }
1354     }
1355     else if (ev->type == GR_EVENT_TYPE_MOUSE_MOTION) /* 6 */
1356     {
1357       event_mouse = (GR_EVENT_MOUSE *) ev;
1358       rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
1359                      event_mouse->x, event_mouse->y);
1360     }
1361     else if (ev->type == GR_EVENT_TYPE_MOUSE_POSITION) /* 7 */
1362     {
1363       /* use GR_EVENT_TYPE_MOUSE_MOTION */
1364     }
1365     else if (ev->type == GR_EVENT_TYPE_KEY_DOWN) /* 8 */
1366     {
1367       event_keystroke = (GR_EVENT_KEYSTROKE *) ev;
1368       process_keystroke(event_keystroke, 1);
1369     }
1370     else if (ev->type == GR_EVENT_TYPE_KEY_UP) /* 9 */
1371     {
1372       event_keystroke = (GR_EVENT_KEYSTROKE *) ev;
1373       process_keystroke(event_keystroke, 0);
1374     }
1375     else if (ev->type == GR_EVENT_TYPE_FOCUS_IN) /* 10 */
1376     {
1377     }
1378     else if (ev->type == GR_EVENT_TYPE_FOCUS_OUT) /* 11 */
1379     {
1380     }
1381     else if (ev->type == GR_EVENT_TYPE_UPDATE) /* 13 */
1382     {
1383     }
1384     GrCheckNextEvent(ev);
1385   } while (ev->type != GR_EVENT_TYPE_NONE);
1386 }
1387 
1388 /*****************************************************************************/
1389 static void get_username_and_hostname(void)
1390 {
1391   char fullhostname[64];
1392   char * p;
1393   struct passwd * pw;
1394 
1395   STRNCPY(g_username, "unknown", sizeof(g_username));
1396   STRNCPY(g_hostname, "unknown", sizeof(g_hostname));
1397   pw = getpwuid(getuid());
1398   if (pw != NULL && pw->pw_name != NULL)
1399   {
1400     STRNCPY(g_username, pw->pw_name, sizeof(g_username));
1401   }
1402   if (gethostname(fullhostname, sizeof(fullhostname)) != -1)
1403   {
1404     p = strchr(fullhostname, '.');
1405     if (p != NULL)
1406     {
1407       *p = 0;
1408     }
1409     STRNCPY(g_hostname, fullhostname, sizeof(g_hostname));
1410   }
1411 }
1412 /*****************************************************************************/
1413 static void out_params(void)
1414 {
1415   fprintf(stderr, "rdesktop: A Remote Desktop Protocol client.\n");
1416   fprintf(stderr, "Version " VERSION ". Copyright (C) 1999-2005 Matt Chapman.\n");
1417   fprintf(stderr, "nanox uiport by Jay Sorg\n");
1418   fprintf(stderr, "See http://www.rdesktop.org/ for more information.\n\n");
1419   fprintf(stderr, "Usage: nanoxrdesktop [options] server\n");
1420   fprintf(stderr, "   -u: user name\n");
1421   fprintf(stderr, "   -n: client hostname\n");
1422   fprintf(stderr, "   -p: password\n");
1423   fprintf(stderr, "   -d: domain\n");
1424   fprintf(stderr, "   -s: shell\n");
1425   fprintf(stderr, "   -c: working directory\n");
1426   fprintf(stderr, "\n");
1427 }
1428 
1429 /*****************************************************************************/
1430 static int parse_parameters(int in_argc, char ** in_argv)
1431 {
1432   int i;
1433 
1434   if (in_argc <= 1)
1435   {
1436     out_params();
1437     return 0;
1438   }
1439   for (i = 1; i < in_argc; i++)
1440   {
1441     strcpy(g_servername, in_argv[i]);
1442     if (strcmp(in_argv[i], "-h") == 0)
1443     {
1444       out_params();
1445       return 0;
1446     }
1447     else if (strcmp(in_argv[i], "-n") == 0)
1448     {
1449       STRNCPY(g_hostname, in_argv[i + 1], sizeof(g_hostname));
1450     }
1451     else if (strcmp(in_argv[i], "-u") == 0)
1452     {
1453       STRNCPY(g_username, in_argv[i + 1], sizeof(g_username));
1454     }
1455     else if (strcmp(in_argv[i], "-p") == 0)
1456     {
1457       STRNCPY(g_password, in_argv[i + 1], sizeof(g_password));
1458       g_flags |= RDP_LOGON_AUTO;
1459       i++;
1460     }
1461     else if (strcmp(in_argv[i], "-d") == 0)
1462     {
1463       STRNCPY(g_domain, in_argv[i + 1], sizeof(g_domain));
1464       i++;
1465     }
1466     else if (strcmp(in_argv[i], "-s") == 0)
1467     {
1468       STRNCPY(g_shell, in_argv[i + 1], sizeof(g_shell));
1469       i++;
1470     }
1471     else if (strcmp(in_argv[i], "-c") == 0)
1472     {
1473       STRNCPY(g_directory, in_argv[i + 1], sizeof(g_directory));
1474       i++;
1475     }
1476   }
1477   return 1;
1478 }
1479 
1480 /*****************************************************************************/
1481 int main(int in_argc, char ** in_argv)
1482 {
1483   get_username_and_hostname();
1484   /* read command line options */
1485   if (!parse_parameters(in_argc, in_argv))
1486   {
1487     exit(0);
1488   }
1489   /* connect to server */
1490   if (GrOpen() < 0)
1491   {
1492     fprintf(stderr, "Couldn't connect to Nano-X server\n");
1493     exit(1);
1494   }
1495   GrGetScreenInfo(&g_screen_info);
1496   g_bpp = g_screen_info.bpp;
1497   g_Bpp = (g_screen_info.bpp + 7) / 8;
1498   g_width = g_screen_info.vs_width;
1499   g_height = g_screen_info.vs_height;
1500   g_clip.x = 0;
1501   g_clip.y = 0;
1502   g_clip.width = g_width;
1503   g_clip.height = g_height;
1504   if (!((g_bpp == 32 && g_server_bpp == 16) ||
1505         (g_bpp == 16 && g_server_bpp == 16)))
1506   {
1507     fprintf(stderr, "unsupported bpp, server = %d, client = %d\n",
1508             g_server_bpp, g_bpp);
1509     GrClose();
1510     exit(0);
1511   }
1512   init_keys();
1513   /* connect to server */
1514   if (!rdp_connect(g_servername, g_flags, g_domain, g_password, g_shell,
1515                    g_directory))
1516   {
1517     fprintf(stderr, "Error connecting\n");
1518     GrClose();
1519     exit(1);
1520   }
1521   /* create window */
1522   g_wnd = GrNewWindow(GR_ROOT_WINDOW_ID, 0, 0, g_width, g_height, 0, 0, 0);
1523   /* show window */
1524   GrMapWindow(g_wnd);
1525   /* create graphic context */
1526   g_gc = GrNewGC();
1527   g_gc_clean = GrNewGC();
1528   /* clear screen */
1529   GrSetGCForeground(g_gc, 0);
1530   GrFillRect(g_wnd, g_gc, 0, 0, g_width, g_height);
1531   /* create null cursor */
1532   g_null_cursor = (GR_CURSOR_ID)ui_create_cursor(0, 0, 32, 32, 0, 0);
1533   /* register callbacks, set mask, and run main loop */
1534   GrSelectEvents(g_wnd, -1); /* all events */
1535   GrRegisterInput(g_sck);
1536   GrMainLoop(nanox_event);
1537   /* free null cursor */
1538   ui_destroy_cursor((void*)g_null_cursor);
1539   /* free graphic context */
1540   GrDestroyGC(g_gc);
1541   GrDestroyGC(g_gc_clean);
1542   /* free window */
1543   GrDestroyWindow(g_wnd);
1544   /* close connection */
1545   GrClose();
1546   return 0;
1547 }
1548