1 /* -*- c-basic-offset: 8 -*-
2    rdesktop: A Remote Desktop Protocol client.
3    User interface services - QT Window System
4    Copyright (C) Jay Sorg 2004-2006
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 <qapplication.h>
24 #include <qmainwindow.h>
25 #include <qwidget.h>
26 #include <qpainter.h>
27 #include <qpixmap.h>
28 #include <qbrush.h>
29 #include <qimage.h>
30 #include <qbitmap.h>
31 #include <qcursor.h>
32 #include <qsocketnotifier.h>
33 #include <qscrollview.h>
34 #include <qfile.h>
35 
36 #include "qtwin.h"
37 
38 #include <unistd.h> // gethostname
39 #include <pwd.h> // getpwuid
40 #include <stdarg.h> // va_list va_start va_end
41 
42 #include <errno.h>
43 #include <fcntl.h>
44 
45 /* rdesktop globals */
46 extern int g_tcp_port_rdp;
47 int g_use_rdp5 = 1;
48 char g_hostname[16];
49 char g_username[64];
50 int g_height = 600;
51 int g_width = 800;
52 int g_server_depth = 8;
53 int g_encryption = 1;
54 int g_desktop_save = 1;
55 int g_polygon_ellipse_orders = 0;
56 int g_bitmap_cache = 1;
57 int g_bitmap_cache_persist_enable = False;
58 int g_bitmap_cache_precache = True;
59 int g_bitmap_compression = 1;
60 int g_rdp5_performanceflags = 0;
61 int g_console_session = 0;
62 int g_keylayout = 0x409; /* Defaults to US keyboard layout */
63 int g_keyboard_type = 0x4; /* Defaults to US keyboard layout */
64 int g_keyboard_subtype = 0x0; /* Defaults to US keyboard layout */
65 int g_keyboard_functionkeys = 0xc; /* Defaults to US keyboard layout */
66 
67 /* hack globals */
68 static int g_argc = 0;
69 static char ** g_argv = 0;
70 static int g_UpAndRunning = 0;
71 static int g_sock = 0;
72 static int g_deactivated = 0;
73 static uint32 g_ext_disc_reason = 0;
74 static char g_servername[128];
75 static char g_title[128] = "";
76 static int g_flags = RDP_LOGON_NORMAL;
77 
78 #ifdef WITH_RDPSND
79 extern int g_dsp_busy;
80 extern int g_dsp_fd;
81 static int g_rdpsnd = 0;
82 static QSocketNotifier * g_SoundNotifier = 0;
83 #endif
84 
85 /* qt globals */
86 static QSocketNotifier * g_SocketNotifier = 0;
87 static QApplication * g_App = 0;
88 static QMyMainWindow * g_MW = 0;
89 static QMyScrollView * g_SV = 0;
90 static QPixmap * g_BS = 0;
91 static QPixmap * g_DS = 0;
92 static QPainter * g_P1 = 0;
93 static QPainter * g_P2 = 0;
94 static QColor g_Color1;
95 static QColor g_Color2;
96 
97 struct QColorMap
98 {
99   uint32 RGBColors[256];
100   int NumColors;
101 };
102 static struct QColorMap * g_CM = 0;
103 static QRegion * g_ClipRect;
104 
105 static Qt::RasterOp g_OpCodes[16] = {
106     Qt::ClearROP,        // BLACKNESS     0
107     Qt::NorROP,          // NOTSRCERASE   DSon
108     Qt::NotAndROP,       //               DSna
109     Qt::NotCopyROP,      // NOTSRCCOPY    Sn
110     Qt::AndNotROP,       // SRCERASE      SDna
111     Qt::NotROP,          // DSTINVERT     Dn
112     Qt::XorROP,          // SRCINVERT     DSx
113     Qt::NandROP,         //               DSan
114     Qt::AndROP,          // SRCAND        DSa
115     Qt::NotXorROP,       //               DSxn
116     Qt::NopROP,          //               D
117     Qt::NotOrROP,        // MERGEPAINT    DSno
118     Qt::CopyROP,         // SRCCOPY       S
119     Qt::OrNotROP,        //               SDno
120     Qt::OrROP,           // SRCPAINT      DSo
121     Qt::SetROP};         // WHITENESS     1
122 
123 /* Session Directory redirection */
124 BOOL g_redirect = False;
125 char g_redirect_server[64];
126 char g_redirect_domain[16];
127 char g_redirect_password[64];
128 char g_redirect_username[64];
129 char g_redirect_cookie[128];
130 uint32 g_redirect_flags = 0;
131 
132 //*****************************************************************************
133 uint32 Color15to32(uint32 InColor)
134 {
135   uint32 r, g, b;
136 
137   r = (InColor & 0x7c00) >> 10;
138   r = (r * 0xff) / 0x1f;
139   g = (InColor & 0x03e0) >> 5;
140   g = (g * 0xff) / 0x1f;
141   b = (InColor & 0x001f);
142   b = (b * 0xff) / 0x1f;
143   return (r << 16) | (g << 8) | b;
144 }
145 
146 //*****************************************************************************
147 uint32 Color16to32(uint32 InColor)
148 {
149   uint32 r, g, b;
150 
151   r = (InColor & 0xf800) >> 11;
152   r = (r * 0xff) / 0x1f;
153   g = (InColor & 0x07e0) >> 5;
154   g = (g * 0xff) / 0x3f;
155   b = (InColor & 0x001f);
156   b = (b * 0xff) / 0x1f;
157   return (r << 16) | (g << 8) | b;
158 }
159 
160 //*****************************************************************************
161 uint32 Color24to32(uint32 InColor)
162 {
163   return ((InColor & 0x00ff0000) >> 16) |
164          ((InColor & 0x000000ff) << 16) |
165           (InColor & 0x0000ff00);
166 }
167 
168 //*****************************************************************************
169 void SetColorx(QColor * Color, uint32 InColor)
170 {
171   switch (g_server_depth)
172   {
173     case 8:
174       if (g_CM == NULL || InColor > 255)
175       {
176         Color->setRgb(0);
177         return;
178       }
179       Color->setRgb(g_CM->RGBColors[InColor]);
180       break;
181     case 15:
182       Color->setRgb(Color15to32(InColor));
183       break;
184     case 16:
185       Color->setRgb(Color16to32(InColor));
186       break;
187     case 24:
188       Color->setRgb(Color24to32(InColor));
189       break;
190     default:
191       Color->setRgb(0);
192   }
193 }
194 
195 //*****************************************************************************
196 void SetOpCode(int opcode)
197 {
198   if (opcode >= 0 && opcode < 16)
199   {
200     Qt::RasterOp op = g_OpCodes[opcode];
201     if (op != Qt::CopyROP)
202     {
203       g_P1->setRasterOp(op);
204       g_P2->setRasterOp(op);
205     }
206   }
207 }
208 
209 //*****************************************************************************
210 void ResetOpCode(int opcode)
211 {
212   if (opcode >= 0 && opcode < 16)
213   {
214     Qt::RasterOp op = g_OpCodes[opcode];
215     if (op != Qt::CopyROP)
216     {
217       g_P1->setRasterOp(Qt::CopyROP);
218       g_P2->setRasterOp(Qt::CopyROP);
219     }
220   }
221 }
222 
223 /*****************************************************************************/
224 QMyMainWindow::QMyMainWindow(): QWidget()
225 {
226 }
227 
228 /*****************************************************************************/
229 QMyMainWindow::~QMyMainWindow()
230 {
231 }
232 
233 //*****************************************************************************
234 void QMyMainWindow::mouseMoveEvent(QMouseEvent * e)
235 {
236   if (!g_UpAndRunning)
237   {
238     return;
239   }
240   rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE, e->x(), e->y());
241 }
242 
243 //*****************************************************************************
244 void QMyMainWindow::mousePressEvent(QMouseEvent * e)
245 {
246   if (!g_UpAndRunning)
247   {
248     return;
249   }
250   if (e->button() == LeftButton)
251   {
252     rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON1,
253                    e->x(), e->y());
254   }
255   else if (e->button() == RightButton)
256   {
257     rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON2,
258                    e->x(), e->y());
259   }
260   else if (e->button() == MidButton)
261   {
262     rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON3,
263                    e->x(), e->y());
264   }
265 }
266 
267 //*****************************************************************************
268 void QMyMainWindow::mouseReleaseEvent(QMouseEvent * e)
269 {
270   if (!g_UpAndRunning)
271   {
272     return;
273   }
274   if (e->button() == LeftButton)
275   {
276     rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON1, e->x(), e->y());
277   }
278   else if (e->button() == RightButton)
279   {
280     rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON2, e->x(), e->y());
281   }
282   else if (e->button() == MidButton)
283   {
284     rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON3, e->x(), e->y());
285   }
286 }
287 
288 //*****************************************************************************
289 void QMyMainWindow::wheelEvent(QWheelEvent * e)
290 {
291   if (!g_UpAndRunning)
292   {
293     return;
294   }
295   if (e->delta() > 0)
296   {
297     rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON4, e->x(), e->y());
298   }
299   else if (e->delta() < 0)
300   {
301     rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON5, e->x(), e->y());
302   }
303 }
304 
305 //*****************************************************************************
306 int GetScanCode(QKeyEvent* e)
307 {
308   int Key = e->key();
309   int ScanCode = 0;
310   Qt::ButtonState bs = e->state();
311   if (!(bs & Qt::ShiftButton)) // shift is not down
312   {
313     if (Key == 42) // *
314       return 0x37;
315     if (Key == 43) // +
316       return 0x4e;
317   }
318   switch (Key)
319   {
320     case 4100: ScanCode = 0x1c; break; // enter
321     case 4101: ScanCode = 0x1c; break;
322     case 4117: ScanCode = 0xd0; break; // down arrow
323     case 4115: ScanCode = 0xc8; break; // up arrow
324     case 4114: ScanCode = 0xcb; break; // left arrow
325     case 4116: ScanCode = 0xcd; break; // right arrow
326     case 4112: ScanCode = 0xc7; break; // home
327     case 4113: ScanCode = 0xcf; break; // end
328     case 4102: ScanCode = 0xd2; break; // insert
329     case 4103: ScanCode = 0xd3; break; // delete
330     case 4118: ScanCode = 0xc9; break; // page up
331     case 4119: ScanCode = 0xd1; break; // page down
332     case 4143: ScanCode = 0x00; break; // num lock
333     case 47:   ScanCode = 0x35; break; // /
334     case 42:   ScanCode = 0x37; break; // *
335     case 45:   ScanCode = 0x0c; break; // -
336     case 95:   ScanCode = 0x0c; break; // _
337     case 43:   ScanCode = 0x0d; break; // +
338     case 46:   ScanCode = 0x34; break; // .
339     case 48:   ScanCode = 0x0b; break; // 0
340     case 41:   ScanCode = 0x0b; break; // )
341     case 49:   ScanCode = 0x02; break; // 1
342     case 33:   ScanCode = 0x02; break; // !
343     case 50:   ScanCode = 0x03; break; // 2
344     case 64:   ScanCode = 0x03; break; // @
345     case 51:   ScanCode = 0x04; break; // 3
346     case 35:   ScanCode = 0x04; break; // #
347     case 52:   ScanCode = 0x05; break; // 4
348     case 36:   ScanCode = 0x05; break; // $
349     case 53:   ScanCode = 0x06; break; // 5
350     case 37:   ScanCode = 0x06; break; // %
351     case 54:   ScanCode = 0x07; break; // 6
352     case 94:   ScanCode = 0x07; break; // ^
353     case 55:   ScanCode = 0x08; break; // 7
354     case 38:   ScanCode = 0x08; break; // &
355     case 56:   ScanCode = 0x09; break; // 8
356     case 57:   ScanCode = 0x0a; break; // 9
357     case 40:   ScanCode = 0x0a; break; // (
358     case 61:   ScanCode = 0x0d; break; // =
359     case 65:   ScanCode = 0x1e; break; // a
360     case 66:   ScanCode = 0x30; break; // b
361     case 67:   ScanCode = 0x2e; break; // c
362     case 68:   ScanCode = 0x20; break; // d
363     case 69:   ScanCode = 0x12; break; // e
364     case 70:   ScanCode = 0x21; break; // f
365     case 71:   ScanCode = 0x22; break; // g
366     case 72:   ScanCode = 0x23; break; // h
367     case 73:   ScanCode = 0x17; break; // i
368     case 74:   ScanCode = 0x24; break; // j
369     case 75:   ScanCode = 0x25; break; // k
370     case 76:   ScanCode = 0x26; break; // l
371     case 77:   ScanCode = 0x32; break; // m
372     case 78:   ScanCode = 0x31; break; // n
373     case 79:   ScanCode = 0x18; break; // o
374     case 80:   ScanCode = 0x19; break; // p
375     case 81:   ScanCode = 0x10; break; // q
376     case 82:   ScanCode = 0x13; break; // r
377     case 83:   ScanCode = 0x1f; break; // s
378     case 84:   ScanCode = 0x14; break; // t
379     case 85:   ScanCode = 0x16; break; // u
380     case 86:   ScanCode = 0x2f; break; // v
381     case 87:   ScanCode = 0x11; break; // w
382     case 88:   ScanCode = 0x2d; break; // x
383     case 89:   ScanCode = 0x15; break; // y
384     case 90:   ScanCode = 0x2c; break; // z
385     case 32:   ScanCode = 0x39; break; // space
386     case 44:   ScanCode = 0x33; break; // ,
387     case 60:   ScanCode = 0x33; break; // <
388     case 62:   ScanCode = 0x34; break; // >
389     case 63:   ScanCode = 0x35; break; // ?
390     case 92:   ScanCode = 0x2b; break; // backslash
391     case 124:  ScanCode = 0x2b; break; // bar
392     case 4097: ScanCode = 0x0f; break; // tab
393     case 4132: ScanCode = 0x3a; break; // caps lock
394     case 4096: ScanCode = 0x01; break; // esc
395     case 59:   ScanCode = 0x27; break; // ;
396     case 58:   ScanCode = 0x27; break; // :
397     case 39:   ScanCode = 0x28; break; // '
398     case 34:   ScanCode = 0x28; break; // "
399     case 91:   ScanCode = 0x1a; break; // [
400     case 123:  ScanCode = 0x1a; break; // {
401     case 93:   ScanCode = 0x1b; break; // ]
402     case 125:  ScanCode = 0x1b; break; // }
403     case 4144: ScanCode = 0x3b; break; // f1
404     case 4145: ScanCode = 0x3c; break; // f2
405     case 4146: ScanCode = 0x3d; break; // f3
406     case 4147: ScanCode = 0x3e; break; // f4
407     case 4148: ScanCode = 0x3f; break; // f5
408     case 4149: ScanCode = 0x40; break; // f6
409     case 4150: ScanCode = 0x41; break; // f7
410     case 4151: ScanCode = 0x42; break; // f8
411     case 4152: ScanCode = 0x43; break; // f9
412     case 4153: ScanCode = 0x44; break; // f10
413     case 4154: ScanCode = 0x57; break; // f11
414     case 4155: ScanCode = 0x58; break; // f12
415     case 4128: ScanCode = 0x2a; break; // shift
416     case 4131: ScanCode = 0x38; break; // alt
417     case 4129: ScanCode = 0x1d; break; // ctrl
418     case 96:   ScanCode = 0x29; break; // `
419     case 126:  ScanCode = 0x29; break; // ~
420     case 4099: ScanCode = 0x0e; break; // backspace
421   }
422 //  if (ScanCode == 0)
423 //    printf("key %d scancode %d\n", Key, ScanCode);
424   return ScanCode;
425 }
426 
427 //*****************************************************************************
428 void QMyMainWindow::keyPressEvent(QKeyEvent* e)
429 {
430   if (!g_UpAndRunning)
431     return;
432   int ScanCode = GetScanCode(e);
433   if (ScanCode != 0)
434   {
435     rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYPRESS, ScanCode, 0);
436     e->accept();
437   }
438 }
439 
440 //*****************************************************************************
441 void QMyMainWindow::keyReleaseEvent(QKeyEvent* e)
442 {
443   if (!g_UpAndRunning)
444   {
445     return;
446   }
447   int ScanCode = GetScanCode(e);
448   if (ScanCode != 0)
449   {
450     rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYRELEASE, ScanCode, 0);
451     e->accept();
452   }
453 }
454 
455 //*****************************************************************************
456 void QMyMainWindow::paintEvent(QPaintEvent * pe)
457 {
458   QRect Rect;
459 
460   Rect = pe->rect();
461   bitBlt(this, Rect.left(), Rect.top(), g_BS, Rect.left(), Rect.top(),
462          Rect.width(), Rect.height());
463 }
464 
465 //*****************************************************************************
466 void QMyMainWindow::closeEvent(QCloseEvent * e)
467 {
468   e->accept();
469 }
470 
471 //*****************************************************************************
472 bool QMyMainWindow::event(QEvent * e)
473 {
474   return QWidget::event(e);
475 }
476 
477 //*****************************************************************************
478 void QMyMainWindow::dataReceived()
479 {
480   if (!rdp_loop(&g_deactivated, &g_ext_disc_reason))
481   {
482     g_SV->close();
483   }
484 #ifdef WITH_RDPSND
485   if (g_dsp_busy)
486   {
487     if (g_SoundNotifier == 0)
488     {
489       g_SoundNotifier = new QSocketNotifier(g_dsp_fd, QSocketNotifier::Write,
490                                             g_MW);
491       g_MW->connect(g_SoundNotifier, SIGNAL(activated(int)), g_MW,
492                     SLOT(soundSend()));
493     }
494     else
495     {
496       if (!g_SoundNotifier->isEnabled())
497       {
498         g_SoundNotifier->setEnabled(true);
499       }
500     }
501   }
502 #endif
503 }
504 
505 /******************************************************************************/
506 void QMyMainWindow::soundSend()
507 {
508 #ifdef WITH_RDPSND
509   g_SoundNotifier->setEnabled(false);
510   wave_out_play();
511   if (g_dsp_busy)
512   {
513     g_SoundNotifier->setEnabled(true);
514   }
515 #endif
516 }
517 
518 //*****************************************************************************
519 void QMyScrollView::keyPressEvent(QKeyEvent * e)
520 {
521   g_MW->keyPressEvent(e);
522 }
523 
524 //*****************************************************************************
525 void QMyScrollView::keyReleaseEvent(QKeyEvent * e)
526 {
527   g_MW->keyReleaseEvent(e);
528 }
529 
530 
531 //*****************************************************************************
532 void ui_begin_update(void)
533 {
534   g_P1->begin(g_MW);
535   g_P2->begin(g_BS);
536 }
537 
538 //*****************************************************************************
539 void ui_end_update(void)
540 {
541   g_P1->end();
542   g_P2->end();
543 }
544 
545 /*****************************************************************************/
546 int ui_init(void)
547 {
548   g_App = new QApplication(g_argc, g_argv);
549   return 1;
550 }
551 
552 /*****************************************************************************/
553 void ui_deinit(void)
554 {
555   delete g_App;
556 }
557 
558 /*****************************************************************************/
559 int ui_create_window(void)
560 {
561   int w, h;
562   QPainter * painter;
563   QWidget * desktop;
564 
565   g_MW = new QMyMainWindow();
566   g_SV = new QMyScrollView();
567   g_SV->addChild(g_MW);
568   g_BS = new QPixmap(g_width, g_height);
569   painter = new QPainter(g_BS);
570   painter->fillRect(0, 0, g_width, g_height, QBrush(QColor("white")));
571   painter->fillRect(0, 0, g_width, g_height, QBrush(QBrush::CrossPattern));
572   delete painter;
573   g_DS = new QPixmap(480, 480);
574   g_P1 = new QPainter();
575   g_P2 = new QPainter();
576   g_ClipRect = new QRegion(0, 0, g_width, g_height);
577   desktop = QApplication::desktop();
578   w = desktop->width();              // returns screen width
579   h = desktop->height();             // returns screen height
580   g_MW->resize(g_width, g_height);
581   if (w < g_width || h < g_height)
582   {
583     g_SV->resize(w, h);
584   }
585   else
586   {
587     g_SV->resize(g_width + 4, g_height + 4);
588   }
589   g_SV->setMaximumWidth(g_width + 4);
590   g_SV->setMaximumHeight(g_height + 4);
591   g_App->setMainWidget(g_SV);
592   g_SV->show();
593   g_MW->setMouseTracking(true);
594   if (g_title[0] != 0)
595   {
596     g_SV->setCaption(g_title);
597   }
598 
599 /*  XGrayKey(0, 64, AnyModifie, SV->winId(), 0, GrabModeAsync, GrabModeAsync);
600   XGrayKey(0, 113, AnyModifie, SV->winId(), 0, GrabModeAsync, GrabModeAsync);
601   XGrayKey(0, 37, AnyModifie, SV-winId(), 0, GrabModeAsync, GrabModeAsync);
602   XGrayKey(0, 109, AnyModifie, SV->winId(), 0, GrabModeAsync, GrabModeAsync);
603   XGrayKey(0, 115, AnyModifie, SV->winId(), 0, GrabModeAsync, GrabModeAsync);
604   XGrayKey(0, 116, AnyModifie, SV->winId(), 0, GrabModeAsync, GrabModeAsync);
605   XGrayKey(0, 117, AnyModifie, SV->winId(), 0, GrabModeAsync, GrabModeAsync);
606   XGrayKey(0, 62, AnyModifie, SV->winId(), 0, GrabModeAsync, GrabModeAsync);
607   XGrayKey(0, 50, AnyModifie, SV->winId(), 0, GrabModeAsync, GrabModeAsync);*/
608 
609   return 1;
610 }
611 
612 //*****************************************************************************
613 void ui_main_loop(void)
614 {
615 #ifdef WITH_RDPSND
616   // init sound
617   if (g_rdpsnd)
618   {
619     rdpsnd_init();
620   }
621 #endif
622   // connect
623   if (!rdp_connect(g_servername, g_flags, "", "", "", ""))
624   {
625     return;
626   }
627   // start notifier
628   g_SocketNotifier = new QSocketNotifier(g_sock, QSocketNotifier::Read, g_MW);
629   g_MW->connect(g_SocketNotifier, SIGNAL(activated(int)),
630                 g_MW, SLOT(dataReceived()));
631   g_UpAndRunning = 1;
632   // app main loop
633   g_App->exec();
634 }
635 
636 //*****************************************************************************
637 void ui_destroy_window(void)
638 {
639   delete g_MW;
640   delete g_SV;
641   delete g_BS;
642   delete g_DS;
643   delete g_P1;
644   delete g_P2;
645   delete g_ClipRect;
646 }
647 
648 /*****************************************************************************/
649 void ui_bell(void)
650 {
651 }
652 
653 /*****************************************************************************/
654 int ui_select(int in_val)
655 {
656   if (g_sock == 0)
657   {
658     g_sock = in_val;
659   }
660   return 1;
661 }
662 
663 /*****************************************************************************/
664 void ui_destroy_cursor(void * cursor)
665 {
666   QCursor * Cursor;
667   Cursor = (QCursor*)cursor;
668   if (Cursor != NULL)
669   {
670     delete Cursor;
671   }
672 }
673 
674 /*****************************************************************************/
675 void* ui_create_glyph(int width, int height, uint8 * data)
676 {
677   QBitmap * Bitmap;
678   Bitmap = new QBitmap(width, height, data);
679   Bitmap->setMask(*Bitmap);
680   return (HGLYPH)Bitmap;
681 }
682 
683 /*****************************************************************************/
684 void ui_destroy_glyph(void * glyph)
685 {
686   QBitmap* Bitmap;
687   Bitmap = (QBitmap*)glyph;
688   delete Bitmap;
689 }
690 
691 /*****************************************************************************/
692 void ui_destroy_bitmap(void * bmp)
693 {
694   QPixmap * Pixmap;
695   Pixmap = (QPixmap*)bmp;
696   delete Pixmap;
697 }
698 
699 /*****************************************************************************/
700 void ui_reset_clip(void)
701 {
702   g_P1->setClipRect(0, 0, g_width, g_height);
703   g_P2->setClipRect(0, 0, g_width, g_height);
704   delete g_ClipRect;
705   g_ClipRect = new QRegion(0, 0, g_width, g_height);
706 }
707 
708 /*****************************************************************************/
709 void ui_set_clip(int x, int y, int cx, int cy)
710 {
711   g_P1->setClipRect(x, y, cx, cy);
712   g_P2->setClipRect(x, y, cx, cy);
713   delete g_ClipRect;
714   g_ClipRect = new QRegion(x, y, cx, cy);
715 }
716 
717 /*****************************************************************************/
718 void * ui_create_colourmap(COLOURMAP * colours)
719 {
720   QColorMap* LCM;
721   int i, r, g, b;
722   LCM = (QColorMap*)malloc(sizeof(QColorMap));
723   memset(LCM, 0, sizeof(QColorMap));
724   i = 0;
725   while (i < colours->ncolours && i < 256)
726   {
727     r = colours->colours[i].red;
728     g = colours->colours[i].green;
729     b = colours->colours[i].blue;
730     LCM->RGBColors[i] = (r << 16) | (g << 8) | b;
731     i++;
732   }
733   LCM->NumColors = colours->ncolours;
734   return LCM;
735 }
736 
737 //*****************************************************************************
738 // todo, does this leak at end of program
739 void ui_destroy_colourmap(HCOLOURMAP map)
740 {
741   QColorMap * LCM;
742   LCM = (QColorMap*)map;
743   if (LCM == NULL)
744     return;
745   free(LCM);
746 }
747 
748 /*****************************************************************************/
749 void ui_set_colourmap(void * map)
750 {
751   // destoy old colormap
752   ui_destroy_colourmap(g_CM);
753   g_CM = (QColorMap*)map;
754 }
755 
756 /*****************************************************************************/
757 HBITMAP ui_create_bitmap(int width, int height, uint8 * data)
758 {
759   QImage * Image = NULL;
760   QPixmap * Pixmap;
761   uint32 * d = NULL;
762   uint16 * s;
763   int i;
764 
765   switch (g_server_depth)
766   {
767     case 8:
768       Image = new QImage(data, width, height, 8, (QRgb*)&g_CM->RGBColors,
769                          g_CM->NumColors, QImage::IgnoreEndian);
770       break;
771     case 15:
772       d = (uint32*)malloc(width * height * 4);
773       s = (uint16*)data;
774       for (i = 0; i < width * height; i++)
775       {
776         d[i] = Color15to32(s[i]);
777       }
778       Image = new QImage((uint8*)d, width, height, 32, NULL,
779                          0, QImage::IgnoreEndian);
780       break;
781     case 16:
782       d = (uint32*)malloc(width * height * 4);
783       s = (uint16*)data;
784       for (i = 0; i < width * height; i++)
785       {
786         d[i] = Color16to32(s[i]);
787       }
788       Image = new QImage((uint8*)d, width, height, 32, NULL,
789                          0, QImage::IgnoreEndian);
790       break;
791     case 24:
792       d = (uint32*)malloc(width * height * 4);
793       memset(d, 0, width * height * 4);
794       for (i = 0; i < width * height; i++)
795       {
796         memcpy(d + i, data + i * 3, 3);
797       }
798       Image = new QImage((uint8*)d, width, height, 32, NULL,
799                          0, QImage::IgnoreEndian);
800       break;
801   }
802   if (Image == NULL)
803   {
804     return NULL;
805   }
806   Pixmap = new QPixmap();
807   Pixmap->convertFromImage(*Image);
808   delete Image;
809   if (d != NULL)
810   {
811     free(d);
812   }
813   return (HBITMAP)Pixmap;
814 }
815 
816 //******************************************************************************
817 // adjust coordinates for cliping rect
818 int WarpCoords(int * x, int * y, int * cx, int * cy, int * srcx, int * srcy)
819 {
820   int dx, dy;
821   QRect InRect(*x, *y, *cx, *cy);
822   QRect OutRect;
823   QRect CRect = g_ClipRect->boundingRect();
824   OutRect = InRect.intersect(CRect);
825   if (OutRect.isEmpty())
826   {
827     return False;
828   }
829   dx = OutRect.x() - InRect.x();
830   dy = OutRect.y() - InRect.y();
831   *x = OutRect.x();
832   *y = OutRect.y();
833   *cx = OutRect.width();
834   *cy = OutRect.height();
835   *srcx = *srcx + dx;
836   *srcy = *srcy + dy;
837   return True;
838 }
839 
840 //******************************************************************************
841 // needed because bitBlt don't seem to care about clipping rects
842 // also has 2 dsts and src can be null
843 void bitBltClip(QPaintDevice * dst1, QPaintDevice * dst2, int dx, int dy,
844                 QPaintDevice * src, int sx, int sy, int sw, int sh,
845                 Qt::RasterOp rop, bool im)
846 {
847   if (WarpCoords(&dx, &dy, &sw, &sh, &sx, &sy))
848   {
849     if (dst1 != NULL)
850     {
851       if (src == NULL)
852       {
853         bitBlt(dst1, dx, dy, dst1, sx, sy, sw, sh, rop, im);
854       }
855       else
856       {
857         bitBlt(dst1, dx, dy, src, sx, sy, sw, sh, rop, im);
858       }
859     }
860     if (dst2 != NULL)
861     {
862       if (src == NULL)
863       {
864         bitBlt(dst2, dx, dy, dst2, sx, sy, sw, sh, rop, im);
865       }
866       else
867       {
868         bitBlt(dst2, dx, dy, src, sx, sy, sw, sh, rop, im);
869       }
870     }
871   }
872 }
873 
874 #define DO_GLYPH(ttext,idx) \
875 { \
876   glyph = cache_get_font (font, ttext[idx]); \
877   if (!(flags & TEXT2_IMPLICIT_X)) \
878   { \
879     xyoffset = ttext[++idx]; \
880     if ((xyoffset & 0x80)) \
881     { \
882       if (flags & TEXT2_VERTICAL) \
883         y += ttext[idx+1] | (ttext[idx+2] << 8); \
884       else \
885         x += ttext[idx+1] | (ttext[idx+2] << 8); \
886       idx += 2; \
887     } \
888     else \
889     { \
890       if (flags & TEXT2_VERTICAL) \
891         y += xyoffset; \
892       else \
893         x += xyoffset; \
894     } \
895   } \
896   if (glyph != NULL) \
897   { \
898     g_P2->drawPixmap(x + glyph->offset, y + glyph->baseline, \
899                      *((QBitmap*)glyph->pixmap)); \
900     if (flags & TEXT2_IMPLICIT_X) \
901       x += glyph->width; \
902   } \
903 }
904 
905 //*****************************************************************************
906 void ui_draw_text(uint8 font, uint8 flags, uint8 opcode, int mixmode,
907                   int x, int y, int clipx, int clipy,
908                   int clipcx, int clipcy, int boxx,
909                   int boxy, int boxcx, int boxcy, BRUSH * brush,
910                   int bgcolour, int fgcolour, uint8 * text, uint8 length)
911 {
912   FONTGLYPH * glyph;
913   int i, j, xyoffset;
914   DATABLOB * entry;
915 
916   SetColorx(&g_Color1, fgcolour);
917   SetColorx(&g_Color2, bgcolour);
918   g_P2->setBackgroundColor(g_Color2);
919   g_P2->setPen(g_Color1);
920   if (boxcx > 1)
921   {
922     g_P2->fillRect(boxx, boxy, boxcx, boxcy, QBrush(g_Color2));
923   }
924   else if (mixmode == MIX_OPAQUE)
925   {
926     g_P2->fillRect(clipx, clipy, clipcx, clipcy, QBrush(g_Color2));
927   }
928 
929   /* Paint text, character by character */
930   for (i = 0; i < length;)
931   {
932     switch (text[i])
933     {
934       case 0xff:
935         if (i + 2 < length)
936         {
937           cache_put_text(text[i + 1], text, text[i + 2]);
938         }
939         else
940         {
941           error("this shouldn't be happening\n");
942           exit(1);
943         }
944         /* this will move pointer from start to first character after FF
945            command */
946         length -= i + 3;
947         text = &(text[i + 3]);
948         i = 0;
949         break;
950 
951       case 0xfe:
952         entry = cache_get_text(text[i + 1]);
953         if (entry != NULL)
954         {
955           if ((((uint8 *) (entry->data))[1] == 0) &&
956                              (!(flags & TEXT2_IMPLICIT_X)))
957           {
958             if (flags & TEXT2_VERTICAL)
959             {
960               y += text[i + 2];
961             }
962             else
963             {
964               x += text[i + 2];
965             }
966           }
967           for (j = 0; j < entry->size; j++)
968           {
969             DO_GLYPH(((uint8 *) (entry->data)), j);
970           }
971         }
972         if (i + 2 < length)
973         {
974           i += 3;
975         }
976         else
977         {
978           i += 2;
979         }
980         length -= i;
981         /* this will move pointer from start to first character after FE
982            command */
983         text = &(text[i]);
984         i = 0;
985         break;
986 
987       default:
988         DO_GLYPH(text, i);
989         i++;
990         break;
991     }
992   }
993   if (boxcx > 1)
994   {
995     bitBltClip(g_MW, NULL, boxx, boxy, g_BS, boxx, boxy, boxcx, boxcy,
996                Qt::CopyROP, true);
997   }
998   else
999   {
1000     bitBltClip(g_MW, NULL, clipx, clipy, g_BS, clipx, clipy, clipcx,
1001                clipcy, Qt::CopyROP, true);
1002   }
1003 }
1004 
1005 /*****************************************************************************/
1006 void ui_line(uint8 opcode, int startx, int starty, int endx, int endy,
1007              PEN * pen)
1008 {
1009   SetColorx(&g_Color1, pen->colour);
1010   SetOpCode(opcode);
1011   g_P1->setPen(g_Color1);
1012   g_P1->moveTo(startx, starty);
1013   g_P1->lineTo(endx, endy);
1014   g_P2->setPen(g_Color1);
1015   g_P2->moveTo(startx, starty);
1016   g_P2->lineTo(endx, endy);
1017   ResetOpCode(opcode);
1018 }
1019 
1020 /*****************************************************************************/
1021 // not used
1022 void ui_triblt(uint8 opcode, int x, int y, int cx, int cy,
1023                HBITMAP src, int srcx, int srcy,
1024                BRUSH* brush, int bgcolour, int fgcolour)
1025 {
1026 }
1027 
1028 /*****************************************************************************/
1029 void ui_memblt(uint8 opcode, int x, int y, int cx, int cy,
1030                HBITMAP src, int srcx, int srcy)
1031 {
1032   QPixmap* Pixmap;
1033   Pixmap = (QPixmap*)src;
1034   if (Pixmap != NULL)
1035   {
1036     SetOpCode(opcode);
1037     g_P1->drawPixmap(x, y, *Pixmap, srcx, srcy, cx, cy);
1038     g_P2->drawPixmap(x, y, *Pixmap, srcx, srcy, cx, cy);
1039     ResetOpCode(opcode);
1040   }
1041 }
1042 
1043 //******************************************************************************
1044 void CommonDeskSave(QPixmap* Pixmap1, QPixmap* Pixmap2, int Offset, int x,
1045                     int y, int cx, int cy, int dir)
1046 {
1047   int lx;
1048   int ly;
1049   int x1;
1050   int y1;
1051   int width;
1052   int lcx;
1053   int right;
1054   int bottom;
1055   lx = Offset % 480;
1056   ly = Offset / 480;
1057   y1 = y;
1058   right = x + cx;
1059   bottom = y + cy;
1060   while (y1 < bottom)
1061   {
1062     x1 = x;
1063     lcx = cx;
1064     while (x1 < right)
1065     {
1066       width = 480 - lx;
1067       if (width > lcx)
1068         width = lcx;
1069       if (dir == 0)
1070         bitBlt(Pixmap1, lx, ly, Pixmap2, x1, y1, width, 1, Qt::CopyROP, true);
1071       else
1072         bitBlt(Pixmap2, x1, y1, Pixmap1, lx, ly, width, 1, Qt::CopyROP, true);
1073       lx = lx + width;
1074       if (lx >= 480)
1075       {
1076         lx = 0;
1077         ly++;
1078         if (ly >= 480)
1079           ly = 0;
1080       }
1081       lcx = lcx - width;
1082       x1 = x1 + width;
1083     }
1084     y1++;
1085   }
1086 }
1087 
1088 /*****************************************************************************/
1089 void ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy)
1090 {
1091   QPixmap * Pixmap;
1092 
1093   Pixmap = new QPixmap(cx, cy);
1094   CommonDeskSave(g_DS, Pixmap, offset, 0, 0, cx, cy, 1);
1095   bitBltClip(g_MW, g_BS, x, y, Pixmap, 0, 0, cx, cy, Qt::CopyROP, true);
1096   delete Pixmap;
1097 }
1098 
1099 /*****************************************************************************/
1100 void ui_desktop_save(uint32 offset, int x, int y, int cx, int cy)
1101 {
1102   CommonDeskSave(g_DS, g_BS, offset, x, y, cx, cy, 0);
1103 }
1104 
1105 /*****************************************************************************/
1106 void ui_rect(int x, int y, int cx, int cy, int colour)
1107 {
1108   SetColorx(&g_Color1, colour);
1109   g_P1->fillRect(x, y, cx, cy, QBrush(g_Color1));
1110   g_P2->fillRect(x, y, cx, cy, QBrush(g_Color1));
1111 }
1112 
1113 /*****************************************************************************/
1114 void ui_screenblt(uint8 opcode, int x, int y, int cx, int cy,
1115                   int srcx, int srcy)
1116 {
1117   SetOpCode(opcode);
1118   bitBltClip(g_MW, g_BS, x, y, NULL, srcx, srcy, cx, cy, Qt::CopyROP, true);
1119   ResetOpCode(opcode);
1120 }
1121 
1122 /*****************************************************************************/
1123 void ui_patblt(uint8 opcode, int x, int y, int cx, int cy,
1124                BRUSH* brush, int bgcolour, int fgcolour)
1125 {
1126   QBitmap* Bitmap;
1127   QBrush* Brush;
1128   uint8 ipattern[8], i;
1129   SetOpCode(opcode);
1130   switch (brush->style)
1131   {
1132     case 0:
1133       SetColorx(&g_Color1, fgcolour);
1134       g_P2->fillRect(x, y, cx, cy, QBrush(g_Color1));
1135       break;
1136     case 3:
1137       SetColorx(&g_Color1, fgcolour);
1138       SetColorx(&g_Color2, bgcolour);
1139       for (i = 0; i != 8; i++)
1140       {
1141         ipattern[7 - i] = ~brush->pattern[i];
1142       }
1143       Bitmap = new QBitmap(8, 8, ipattern);
1144       Brush = new QBrush(g_Color1, *Bitmap);
1145       g_P2->setBackgroundMode(Qt::OpaqueMode);
1146       g_P2->setBrushOrigin(brush->xorigin, brush->yorigin);
1147       g_P2->setBackgroundColor(g_Color2);
1148       g_P2->fillRect(x, y, cx, cy, *Brush);
1149       delete Brush;
1150       delete Bitmap;
1151       g_P2->setBackgroundMode(Qt::TransparentMode);
1152       g_P2->setBrushOrigin(0, 0);
1153       break;
1154   }
1155   ResetOpCode(opcode);
1156   bitBltClip(g_MW, NULL, x, y, g_BS, x, y, cx, cy, Qt::CopyROP, true);
1157 }
1158 
1159 /*****************************************************************************/
1160 void ui_destblt(uint8 opcode, int x, int y, int cx, int cy)
1161 {
1162   SetOpCode(opcode);
1163   g_P1->fillRect(x, y, cx, cy, QBrush(QColor("black")));
1164   g_P2->fillRect(x, y, cx, cy, QBrush(QColor("black")));
1165   ResetOpCode(opcode);
1166 }
1167 
1168 /*****************************************************************************/
1169 void ui_move_pointer(int x, int y)
1170 {
1171 }
1172 
1173 /*****************************************************************************/
1174 void ui_set_null_cursor(void)
1175 {
1176   g_MW->setCursor(10); // Qt::BlankCursor
1177 }
1178 
1179 /*****************************************************************************/
1180 void ui_paint_bitmap(int x, int y, int cx, int cy,
1181                      int width, int height, uint8* data)
1182 {
1183   QImage * Image = NULL;
1184   QPixmap * Pixmap;
1185   uint32 * d = NULL;
1186   uint16 * s;
1187   int i;
1188 
1189   switch (g_server_depth)
1190   {
1191     case 8:
1192       Image = new QImage(data, width, height, 8, (QRgb*)&g_CM->RGBColors,
1193                          g_CM->NumColors, QImage::IgnoreEndian);
1194       break;
1195     case 15:
1196       d = (uint32*)malloc(width * height * 4);
1197       s = (uint16*)data;
1198       for (i = 0; i < width * height; i++)
1199       {
1200         d[i] = Color15to32(s[i]);
1201       }
1202       Image = new QImage((uint8*)d, width, height, 32, NULL,
1203                          0, QImage::IgnoreEndian);
1204       break;
1205     case 16:
1206       d = (uint32*)malloc(width * height * 4);
1207       s = (uint16*)data;
1208       for (i = 0; i < width * height; i++)
1209       {
1210         d[i] = Color16to32(s[i]);
1211       }
1212       Image = new QImage((uint8*)d, width, height, 32, NULL,
1213                          0, QImage::IgnoreEndian);
1214       break;
1215     case 24:
1216       d = (uint32*)malloc(width * height * 4);
1217       memset(d, 0, width * height * 4);
1218       for (i = 0; i < width * height; i++)
1219       {
1220         memcpy(d + i, data + i * 3, 3);
1221       }
1222       Image = new QImage((uint8*)d, width, height, 32, NULL,
1223                          0, QImage::IgnoreEndian);
1224       break;
1225   }
1226   if (Image == NULL)
1227   {
1228     return;
1229   }
1230   Pixmap = new QPixmap();
1231   Pixmap->convertFromImage(*Image);
1232   g_P1->drawPixmap(x, y, *Pixmap, 0, 0, cx, cy);
1233   g_P2->drawPixmap(x, y, *Pixmap, 0, 0, cx, cy);
1234   delete Image;
1235   delete Pixmap;
1236   if (d != NULL)
1237   {
1238     free(d);
1239   }
1240 }
1241 
1242 //******************************************************************************
1243 int Is24On(uint8* Data, int X, int Y)
1244 {
1245   uint8 R, G, B;
1246   int Start;
1247   Start = Y * 32 * 3 + X * 3;
1248   R = Data[Start];
1249   G = Data[Start + 1];
1250   B = Data[Start + 2];
1251   return !((R == 0) && (G == 0) && (B == 0));
1252 }
1253 
1254 //******************************************************************************
1255 int Is1On(uint8* Data, int X, int Y)
1256 {
1257   int Start;
1258   int Shift;
1259   Start = (Y * 32) / 8 + X / 8;
1260   Shift = X % 8;
1261   return (Data[Start] & (0x80 >> Shift)) == 0;
1262 }
1263 
1264 //******************************************************************************
1265 void Set1(uint8* Data, int X, int Y)
1266 {
1267   int Start;
1268   int Shift;
1269   Start = (Y * 32) / 8 + X / 8;
1270   Shift = X % 8;
1271   Data[Start] = Data[Start] | (0x80 >> Shift);
1272 }
1273 
1274 //******************************************************************************
1275 void FlipOver(uint8* Data)
1276 {
1277   uint8 AData[128];
1278   int Index;
1279   memcpy(AData, Data, 128);
1280   for (Index = 0; Index <= 31; Index++)
1281   {
1282     Data[127 - (Index * 4 + 3)] = AData[Index * 4];
1283     Data[127 - (Index * 4 + 2)] = AData[Index * 4 + 1];
1284     Data[127 - (Index * 4 + 1)] = AData[Index * 4 + 2];
1285     Data[127 - Index * 4] = AData[Index * 4 + 3];
1286   }
1287 }
1288 
1289 /*****************************************************************************/
1290 void ui_set_cursor(HCURSOR cursor)
1291 {
1292   QCursor* Cursor;
1293   Cursor = (QCursor*)cursor;
1294   if (Cursor != NULL)
1295     g_MW->setCursor(*Cursor);
1296 }
1297 
1298 /*****************************************************************************/
1299 HCURSOR ui_create_cursor(unsigned int x, unsigned int y,
1300                          int width, int height,
1301                          uint8* andmask, uint8* xormask)
1302 {
1303   uint8 AData[128];
1304   uint8 AMask[128];
1305   QBitmap* DataBitmap;
1306   QBitmap* MaskBitmap;
1307   QCursor* Cursor;
1308   int I1, I2, BOn, MOn;
1309 
1310   if (width != 32 || height != 32)
1311   {
1312     return 0;
1313   }
1314   memset(AData, 0, 128);
1315   memset(AMask, 0, 128);
1316   for (I1 = 0; I1 <= 31; I1++)
1317   {
1318     for (I2 = 0; I2 <= 31; I2++)
1319     {
1320       MOn = Is24On(xormask, I1, I2);
1321       BOn = Is1On(andmask, I1, I2);
1322       if (BOn ^ MOn) // xor
1323       {
1324         Set1(AData, I1, I2);
1325         if (!MOn)
1326         {
1327           Set1(AMask, I1, I2);
1328         }
1329       }
1330       if (MOn)
1331       {
1332         Set1(AMask, I1, I2);
1333       }
1334     }
1335   }
1336   FlipOver(AData);
1337   FlipOver(AMask);
1338   DataBitmap = new QBitmap(32, 32, AData);
1339   MaskBitmap = new QBitmap(32, 32, AMask);
1340   Cursor = new QCursor(*DataBitmap, *MaskBitmap, x, y);
1341   delete DataBitmap;
1342   delete MaskBitmap;
1343   return Cursor;
1344 }
1345 
1346 /*****************************************************************************/
1347 uint16 ui_get_numlock_state(uint32 state)
1348 {
1349   return 0;
1350 }
1351 
1352 /*****************************************************************************/
1353 uint32 read_keyboard_state(void)
1354 {
1355   return 0;
1356 }
1357 
1358 /*****************************************************************************/
1359 void ui_resize_window(void)
1360 {
1361 }
1362 
1363 /*****************************************************************************/
1364 void ui_polygon(uint8 opcode, uint8 fillmode, POINT * point, int npoints,
1365                 BRUSH * brush, int bgcolour, int fgcolour)
1366 {
1367 }
1368 
1369 /*****************************************************************************/
1370 /* todo, use qt function for this (QPainter::drawPolyline) */
1371 void ui_polyline(uint8 opcode, POINT * points, int npoints, PEN * pen)
1372 {
1373   int i, x, y, dx, dy;
1374 
1375   if (npoints > 0)
1376   {
1377     x = points[0].x;
1378     y = points[0].y;
1379     for (i = 1; i < npoints; i++)
1380     {
1381       dx = points[i].x;
1382       dy = points[i].y;
1383       ui_line(opcode, x, y, x + dx, y + dy, pen);
1384       x = x + dx;
1385       y = y + dy;
1386     }
1387   }
1388 }
1389 
1390 /*****************************************************************************/
1391 void ui_ellipse(uint8 opcode, uint8 fillmode,
1392                 int x, int y, int cx, int cy,
1393                 BRUSH * brush, int bgcolour, int fgcolour)
1394 {
1395 }
1396 
1397 /*****************************************************************************/
1398 void generate_random(uint8 * random)
1399 {
1400   QFile File("/dev/random");
1401   File.open(IO_ReadOnly);
1402   if (File.readBlock((char*)random, 32) == 32)
1403   {
1404     return;
1405   }
1406   warning("no /dev/random\n");
1407   memcpy(random, "12345678901234567890123456789012", 32);
1408 }
1409 
1410 /*****************************************************************************/
1411 void save_licence(uint8 * data, int length)
1412 {
1413   char * home, * path, * tmppath;
1414   int fd;
1415 
1416   home = getenv("HOME");
1417   if (home == NULL)
1418   {
1419     return;
1420   }
1421   path = (char *) xmalloc(strlen(home) + strlen(g_hostname) +
1422                           sizeof("/.rdesktop/licence."));
1423   sprintf(path, "%s/.rdesktop", home);
1424   if ((mkdir(path, 0700) == -1) && errno != EEXIST)
1425   {
1426     perror(path);
1427     return;
1428   }
1429   /* write licence to licence.hostname.new, then atomically rename to
1430      licence.hostname */
1431   sprintf(path, "%s/.rdesktop/licence.%s", home, g_hostname);
1432   tmppath = (char *) xmalloc(strlen(path) + sizeof(".new"));
1433   strcpy(tmppath, path);
1434   strcat(tmppath, ".new");
1435   fd = open(tmppath, O_WRONLY | O_CREAT | O_TRUNC, 0600);
1436   if (fd == -1)
1437   {
1438     perror(tmppath);
1439     return;
1440   }
1441   if (write(fd, data, length) != length)
1442   {
1443     perror(tmppath);
1444     unlink(tmppath);
1445   }
1446   else if (rename(tmppath, path) == -1)
1447   {
1448     perror(path);
1449     unlink(tmppath);
1450   }
1451   close(fd);
1452   xfree(tmppath);
1453   xfree(path);
1454 }
1455 
1456 /*****************************************************************************/
1457 int load_licence(uint8 ** data)
1458 {
1459   char * home, * path;
1460   struct stat st;
1461   int fd, length;
1462 
1463   home = getenv("HOME");
1464   if (home == NULL)
1465   {
1466     return -1;
1467   }
1468   path = (char *) xmalloc(strlen(home) + strlen(g_hostname) +
1469                           sizeof("/.rdesktop/licence."));
1470   sprintf(path, "%s/.rdesktop/licence.%s", home, g_hostname);
1471   fd = open(path, O_RDONLY);
1472   if (fd == -1)
1473   {
1474     return -1;
1475   }
1476   if (fstat(fd, &st))
1477   {
1478     close(fd);
1479     xfree(path);
1480     return -1;
1481   }
1482   *data = (uint8 *) xmalloc(st.st_size);
1483   length = read(fd, *data, st.st_size);
1484   close(fd);
1485   xfree(path);
1486   return length;
1487 }
1488 
1489 /*****************************************************************************/
1490 void* xrealloc(void * in_val, int size)
1491 {
1492   return realloc(in_val, size);
1493 }
1494 
1495 /*****************************************************************************/
1496 void* xmalloc(int size)
1497 {
1498   return malloc(size);
1499 }
1500 
1501 /*****************************************************************************/
1502 void xfree(void * in_val)
1503 {
1504   if (in_val != NULL)
1505   {
1506     free(in_val);
1507   }
1508 }
1509 
1510 /*****************************************************************************/
1511 char * xstrdup(const char * s)
1512 {
1513   char * mem = strdup(s);
1514   if (mem == NULL)
1515   {
1516     perror("strdup");
1517     exit(1);
1518   }
1519   return mem;
1520 }
1521 
1522 /*****************************************************************************/
1523 void warning(char * format, ...)
1524 {
1525   va_list ap;
1526 
1527   fprintf(stderr, "WARNING: ");
1528   va_start(ap, format);
1529   vfprintf(stderr, format, ap);
1530   va_end(ap);
1531 }
1532 
1533 /*****************************************************************************/
1534 void unimpl(char * format, ...)
1535 {
1536   va_list ap;
1537 
1538   fprintf(stderr, "NOT IMPLEMENTED: ");
1539   va_start(ap, format);
1540   vfprintf(stderr, format, ap);
1541   va_end(ap);
1542 }
1543 
1544 /*****************************************************************************/
1545 void error(char * format, ...)
1546 {
1547   va_list ap;
1548 
1549   fprintf(stderr, "ERROR: ");
1550   va_start(ap, format);
1551   vfprintf(stderr, format, ap);
1552   va_end(ap);
1553 }
1554 
1555 /*****************************************************************************/
1556 void out_params(void)
1557 {
1558   fprintf(stderr, "rdesktop: A Remote Desktop Protocol client.\n");
1559   fprintf(stderr, "Version " VERSION ". Copyright (C) 1999-2005 Matt Chapman.\n");
1560   fprintf(stderr, "QT uiport by Jay Sorg\n");
1561   fprintf(stderr, "See http://www.rdesktop.org/ for more information.\n\n");
1562   fprintf(stderr, "Usage: qtrdesktop [options] server\n");
1563   fprintf(stderr, "   -g WxH: desktop geometry\n");
1564   fprintf(stderr, "   -4: use RDP version 4\n");
1565   fprintf(stderr, "   -5: use RDP version 5 (default)\n");
1566   fprintf(stderr, "   -t 3389: tcp port)\n");
1567   fprintf(stderr, "   -a 8|16|24: connection colour depth\n");
1568   fprintf(stderr, "   -T title: window title\n");
1569   fprintf(stderr, "   -P: use persistent bitmap caching\n");
1570   fprintf(stderr, "   -0: attach to console\n");
1571   fprintf(stderr, "   -z: enable rdp compression\n");
1572   fprintf(stderr, "   -r sound: enable sound\n");
1573   fprintf(stderr, "\n");
1574 }
1575 
1576 /*****************************************************************************/
1577 /* produce a hex dump */
1578 void hexdump(uint8 * p, uint32 len)
1579 {
1580   uint8 * line = p;
1581   int i, thisline;
1582   uint32 offset = 0;
1583 
1584   while (offset < len)
1585   {
1586     printf("%04x ", offset);
1587     thisline = len - offset;
1588     if (thisline > 16)
1589     {
1590       thisline = 16;
1591     }
1592     for (i = 0; i < thisline; i++)
1593     {
1594       printf("%02x ", line[i]);
1595     }
1596     for (; i < 16; i++)
1597     {
1598       printf("   ");
1599     }
1600     for (i = 0; i < thisline; i++)
1601     {
1602       printf("%c", (line[i] >= 0x20 && line[i] < 0x7f) ? line[i] : '.');
1603     }
1604     printf("\n");
1605     offset += thisline;
1606     line += thisline;
1607   }
1608 }
1609 
1610 /*****************************************************************************/
1611 int rd_pstcache_mkdir(void)
1612 {
1613   char * home;
1614   char bmpcache_dir[256];
1615 
1616   home = getenv("HOME");
1617   if (home == NULL)
1618   {
1619     return False;
1620   }
1621   sprintf(bmpcache_dir, "%s/%s", home, ".rdesktop");
1622   if ((mkdir(bmpcache_dir, S_IRWXU) == -1) && errno != EEXIST)
1623   {
1624     perror(bmpcache_dir);
1625     return False;
1626   }
1627   sprintf(bmpcache_dir, "%s/%s", home, ".rdesktop/cache");
1628   if ((mkdir(bmpcache_dir, S_IRWXU) == -1) && errno != EEXIST)
1629   {
1630     perror(bmpcache_dir);
1631     return False;
1632   }
1633   return True;
1634 }
1635 
1636 /*****************************************************************************/
1637 int rd_open_file(char * filename)
1638 {
1639   char * home;
1640   char fn[256];
1641   int fd;
1642 
1643   home = getenv("HOME");
1644   if (home == NULL)
1645   {
1646     return -1;
1647   }
1648   sprintf(fn, "%s/.rdesktop/%s", home, filename);
1649   fd = open(fn, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
1650   if (fd == -1)
1651   {
1652     perror(fn);
1653   }
1654   return fd;
1655 }
1656 
1657 /*****************************************************************************/
1658 void rd_close_file(int fd)
1659 {
1660   close(fd);
1661 }
1662 
1663 /*****************************************************************************/
1664 int rd_read_file(int fd, void * ptr, int len)
1665 {
1666   return read(fd, ptr, len);
1667 }
1668 
1669 /*****************************************************************************/
1670 int rd_write_file(int fd, void * ptr, int len)
1671 {
1672   return write(fd, ptr, len);
1673 }
1674 
1675 /*****************************************************************************/
1676 int rd_lseek_file(int fd, int offset)
1677 {
1678   return lseek(fd, offset, SEEK_SET);
1679 }
1680 
1681 /*****************************************************************************/
1682 int rd_lock_file(int fd, int start, int len)
1683 {
1684   struct flock lock;
1685 
1686   lock.l_type = F_WRLCK;
1687   lock.l_whence = SEEK_SET;
1688   lock.l_start = start;
1689   lock.l_len = len;
1690   if (fcntl(fd, F_SETLK, &lock) == -1)
1691   {
1692     return False;
1693   }
1694   return True;
1695 }
1696 
1697 /*****************************************************************************/
1698 void get_username_and_hostname(void)
1699 {
1700   char fullhostname[64];
1701   char * p;
1702   struct passwd * pw;
1703 
1704   STRNCPY(g_username, "unknown", sizeof(g_username));
1705   STRNCPY(g_hostname, "unknown", sizeof(g_hostname));
1706   pw = getpwuid(getuid());
1707   if (pw != NULL && pw->pw_name != NULL)
1708   {
1709     STRNCPY(g_username, pw->pw_name, sizeof(g_username));
1710   }
1711   if (gethostname(fullhostname, sizeof(fullhostname)) != -1)
1712   {
1713     p = strchr(fullhostname, '.');
1714     if (p != NULL)
1715     {
1716       *p = 0;
1717     }
1718     STRNCPY(g_hostname, fullhostname, sizeof(g_hostname));
1719   }
1720 }
1721 
1722 /*****************************************************************************/
1723 int parse_parameters(int in_argc, char ** in_argv)
1724 {
1725   int i;
1726   char * p;
1727 
1728   if (in_argc <= 1)
1729   {
1730     out_params();
1731     return 0;
1732   }
1733   g_argc = in_argc;
1734   g_argv = in_argv;
1735   for (i = 1; i < in_argc; i++)
1736   {
1737     strcpy(g_servername, in_argv[i]);
1738     if (strcmp(in_argv[i], "-g") == 0)
1739     {
1740       g_width = strtol(in_argv[i + 1], &p, 10);
1741       if (g_width <= 0)
1742       {
1743         error("invalid geometry\n");
1744         return 0;
1745       }
1746       if (*p == 'x')
1747       {
1748         g_height = strtol(p + 1, NULL, 10);
1749       }
1750       if (g_height <= 0)
1751       {
1752         error("invalid geometry\n");
1753         return 0;
1754       }
1755       g_width = (g_width + 3) & ~3;
1756     }
1757     else if (strcmp(in_argv[i], "-T") == 0)
1758     {
1759       strcpy(g_title, in_argv[i + 1]);
1760     }
1761     else if (strcmp(in_argv[i], "-4") == 0)
1762     {
1763       g_use_rdp5 = 0;
1764     }
1765     else if (strcmp(in_argv[i], "-5") == 0)
1766     {
1767       g_use_rdp5 = 1;
1768     }
1769     else if (strcmp(in_argv[i], "-a") == 0)
1770     {
1771       g_server_depth = strtol(in_argv[i + 1], &p, 10);
1772       if (g_server_depth != 8 && g_server_depth != 15 &&
1773           g_server_depth != 16 && g_server_depth != 24)
1774       {
1775         error("invalid bpp\n");
1776         return 0;
1777       }
1778     }
1779     else if (strcmp(in_argv[i], "-t") == 0)
1780     {
1781       g_tcp_port_rdp = strtol(in_argv[i + 1], &p, 10);
1782     }
1783     else if (strcmp(in_argv[i], "-P") == 0)
1784     {
1785       g_bitmap_cache_persist_enable = 1;
1786     }
1787     else if (strcmp(in_argv[i], "-0") == 0)
1788     {
1789       g_console_session = 1;
1790     }
1791     else if (strcmp(in_argv[i], "-z") == 0)
1792     {
1793       g_flags |= (RDP_LOGON_COMPRESSION | RDP_LOGON_COMPRESSION2);
1794     }
1795     else if (strcmp(in_argv[i], "-r") == 0)
1796     {
1797       if (strcmp(in_argv[i + 1], "sound") == 0)
1798       {
1799 #ifdef WITH_RDPSND
1800         g_rdpsnd = 1;
1801 #endif
1802       }
1803     }
1804   }
1805   return 1;
1806 }
1807 
1808 /*****************************************************************************/
1809 int main(int in_argc, char** in_argv)
1810 {
1811   get_username_and_hostname();
1812   if (!parse_parameters(in_argc, in_argv))
1813   {
1814     return 0;
1815   }
1816   if (!ui_init())
1817   {
1818     return 1;
1819   }
1820   if (!ui_create_window())
1821   {
1822     return 1;
1823   }
1824   ui_main_loop();
1825   ui_destroy_window();
1826   ui_deinit();
1827   return 0;
1828 }
1829