summaryrefslogtreecommitdiff
path: root/noncore/net/opierdesktop
authormickeyl <mickeyl>2003-08-10 15:17:24 (UTC)
committer mickeyl <mickeyl>2003-08-10 15:17:24 (UTC)
commit1fb2f4ef9788b51c67b9c0f89ac3c3ce85e45e8f (patch) (side-by-side diff)
tree73b54db5d3aa3e40f4159079c14c8fca90a76c1e /noncore/net/opierdesktop
parentdf6337abb65463b466435a526bf62108e72a60f7 (diff)
downloadopie-1fb2f4ef9788b51c67b9c0f89ac3c3ce85e45e8f.zip
opie-1fb2f4ef9788b51c67b9c0f89ac3c3ce85e45e8f.tar.gz
opie-1fb2f4ef9788b51c67b9c0f89ac3c3ce85e45e8f.tar.bz2
initial import of qtrdesktop - not yet opiefied but working
Diffstat (limited to 'noncore/net/opierdesktop') (more/less context) (ignore whitespace changes)
-rw-r--r--noncore/net/opierdesktop/.cvsignore4
-rw-r--r--noncore/net/opierdesktop/bitmap.cpp282
-rw-r--r--noncore/net/opierdesktop/cache.cpp235
-rw-r--r--noncore/net/opierdesktop/constants.h259
-rw-r--r--noncore/net/opierdesktop/iso.cpp170
-rw-r--r--noncore/net/opierdesktop/licence.cpp314
-rw-r--r--noncore/net/opierdesktop/mcs.cpp394
-rw-r--r--noncore/net/opierdesktop/opie-rdesktop.control9
-rw-r--r--noncore/net/opierdesktop/opierdesktop.pro26
-rw-r--r--noncore/net/opierdesktop/orders.cpp940
-rw-r--r--noncore/net/opierdesktop/orders.h286
-rw-r--r--noncore/net/opierdesktop/parse.h108
-rw-r--r--noncore/net/opierdesktop/proto.h121
-rw-r--r--noncore/net/opierdesktop/qtwin.cpp1725
-rw-r--r--noncore/net/opierdesktop/qtwin.h105
-rw-r--r--noncore/net/opierdesktop/rdesktop.cpp313
-rw-r--r--noncore/net/opierdesktop/rdesktop.h66
-rw-r--r--noncore/net/opierdesktop/rdp.cpp748
-rw-r--r--noncore/net/opierdesktop/secure.cpp658
-rw-r--r--noncore/net/opierdesktop/tcp.cpp181
-rw-r--r--noncore/net/opierdesktop/types.h110
21 files changed, 7054 insertions, 0 deletions
diff --git a/noncore/net/opierdesktop/.cvsignore b/noncore/net/opierdesktop/.cvsignore
new file mode 100644
index 0000000..df6ec24
--- a/dev/null
+++ b/noncore/net/opierdesktop/.cvsignore
@@ -0,0 +1,4 @@
+*.o
+*~
+Makefile*
+moc_*
diff --git a/noncore/net/opierdesktop/bitmap.cpp b/noncore/net/opierdesktop/bitmap.cpp
new file mode 100644
index 0000000..378623f
--- a/dev/null
+++ b/noncore/net/opierdesktop/bitmap.cpp
@@ -0,0 +1,282 @@
+/*
+ rdesktop: A Remote Desktop Protocol client.
+ Bitmap decompression routines
+ Copyright (C) Matthew Chapman 1999-2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "rdesktop.h"
+
+#define CVAL(p) (*(p++))
+
+static uint32
+cvalx(unsigned char **input, int Bpp)
+{
+ uint32 rv = 0;
+ memcpy(&rv, *input, Bpp);
+ *input += Bpp;
+ return rv;
+}
+
+static void
+setli(unsigned char *input, int offset, uint32 value, int Bpp)
+{
+ input += offset * Bpp;
+ memcpy(input, &value, Bpp);
+}
+
+static uint32
+getli(unsigned char *input, int offset, int Bpp)
+{
+ uint32 rv = 0;
+ input += offset * Bpp;
+ memcpy(&rv, input, Bpp);
+ return rv;
+}
+
+#define UNROLL8(exp) { exp exp exp exp exp exp exp exp }
+
+#define REPEAT(statement) \
+{ \
+ while((count & ~0x7) && ((x+8) < width)) \
+ UNROLL8( statement; count--; x++; ); \
+ \
+ while((count > 0) && (x < width)) { statement; count--; x++; } \
+}
+
+#define MASK_UPDATE() \
+{ \
+ mixmask <<= 1; \
+ if (mixmask == 0) \
+ { \
+ mask = fom_mask ? fom_mask : CVAL(input); \
+ mixmask = 1; \
+ } \
+}
+
+BOOL
+bitmap_decompress(unsigned char *output, int width, int height, unsigned char *input, int size,
+ int Bpp)
+{
+ unsigned char *end = input + size;
+ unsigned char *prevline = NULL, *line = NULL;
+ int opcode, count, offset, isfillormix, x = width;
+ int lastopcode = -1, insertmix = False, bicolour = False;
+ uint8 code;
+ uint32 colour1 = 0, colour2 = 0;
+ uint8 mixmask, mask = 0;
+ uint32 mix = 0xffffffff;
+ int fom_mask = 0;
+
+ while (input < end)
+ {
+ fom_mask = 0;
+ code = CVAL(input);
+ opcode = code >> 4;
+
+ /* Handle different opcode forms */
+ switch (opcode)
+ {
+ case 0xc:
+ case 0xd:
+ case 0xe:
+ opcode -= 6;
+ count = code & 0xf;
+ offset = 16;
+ break;
+
+ case 0xf:
+ opcode = code & 0xf;
+ if (opcode < 9)
+ {
+ count = CVAL(input);
+ count |= CVAL(input) << 8;
+ }
+ else
+ {
+ count = (opcode < 0xb) ? 8 : 1;
+ }
+ offset = 0;
+ break;
+
+ default:
+ opcode >>= 1;
+ count = code & 0x1f;
+ offset = 32;
+ break;
+ }
+
+ /* Handle strange cases for counts */
+ if (offset != 0)
+ {
+ isfillormix = ((opcode == 2) || (opcode == 7));
+
+ if (count == 0)
+ {
+ if (isfillormix)
+ count = CVAL(input) + 1;
+ else
+ count = CVAL(input) + offset;
+ }
+ else if (isfillormix)
+ {
+ count <<= 3;
+ }
+ }
+
+ /* Read preliminary data */
+ switch (opcode)
+ {
+ case 0: /* Fill */
+ if ((lastopcode == opcode) && !((x == width) && (prevline == NULL)))
+ insertmix = True;
+ break;
+ case 8: /* Bicolour */
+ colour1 = cvalx(&input, Bpp);
+ case 3: /* Colour */
+ colour2 = cvalx(&input, Bpp);
+ break;
+ case 6: /* SetMix/Mix */
+ case 7: /* SetMix/FillOrMix */
+ mix = cvalx(&input, Bpp);
+ opcode -= 5;
+ break;
+ case 9: /* FillOrMix_1 */
+ mask = 0x03;
+ opcode = 0x02;
+ fom_mask = 3;
+ break;
+ case 0x0a: /* FillOrMix_2 */
+ mask = 0x05;
+ opcode = 0x02;
+ fom_mask = 5;
+ break;
+
+ }
+
+ lastopcode = opcode;
+ mixmask = 0;
+
+ /* Output body */
+ while (count > 0)
+ {
+ if (x >= width)
+ {
+ if (height <= 0)
+ return False;
+
+ x = 0;
+ height--;
+
+ prevline = line;
+ line = output + height * width * Bpp;
+ }
+
+ switch (opcode)
+ {
+ case 0: /* Fill */
+ if (insertmix)
+ {
+ if (prevline == NULL)
+ setli(line, x, mix, Bpp);
+ else
+ setli(line, x,
+ getli(prevline, x, Bpp) ^ mix, Bpp);
+
+ insertmix = False;
+ count--;
+ x++;
+ }
+
+ if (prevline == NULL)
+ {
+ REPEAT(setli(line, x, 0, Bpp))}
+ else
+ {
+ REPEAT(setli
+ (line, x, getli(prevline, x, Bpp), Bpp));
+ }
+ break;
+
+ case 1: /* Mix */
+ if (prevline == NULL)
+ {
+ REPEAT(setli(line, x, mix, Bpp));
+ }
+ else
+ {
+ REPEAT(setli
+ (line, x, getli(prevline, x, Bpp) ^ mix,
+ Bpp));
+ }
+ break;
+
+ case 2: /* Fill or Mix */
+ if (prevline == NULL)
+ {
+ REPEAT(MASK_UPDATE();
+ if (mask & mixmask) setli(line, x, mix, Bpp);
+ else
+ setli(line, x, 0, Bpp););
+ }
+ else
+ {
+ REPEAT(MASK_UPDATE();
+ if (mask & mixmask)
+ setli(line, x, getli(prevline, x, Bpp) ^ mix,
+ Bpp);
+ else
+ setli(line, x, getli(prevline, x, Bpp),
+ Bpp););
+ }
+ break;
+
+ case 3: /* Colour */
+ REPEAT(setli(line, x, colour2, Bpp));
+ break;
+
+ case 4: /* Copy */
+ REPEAT(setli(line, x, cvalx(&input, Bpp), Bpp));
+ break;
+
+ case 8: /* Bicolour */
+ REPEAT(if (bicolour)
+ {
+ setli(line, x, colour2, Bpp); bicolour = False;}
+ else
+ {
+ setli(line, x, colour1, Bpp); bicolour = True;
+ count++;}
+ );
+ break;
+
+ case 0xd: /* White */
+ REPEAT(setli(line, x, 0xffffffff, Bpp));
+ break;
+
+ case 0xe: /* Black */
+ REPEAT(setli(line, x, 0, Bpp));
+ break;
+
+ default:
+ unimpl("bitmap opcode 0x%x\n", opcode);
+ return False;
+ }
+ }
+ }
+
+ return True;
+}
diff --git a/noncore/net/opierdesktop/cache.cpp b/noncore/net/opierdesktop/cache.cpp
new file mode 100644
index 0000000..42ab135
--- a/dev/null
+++ b/noncore/net/opierdesktop/cache.cpp
@@ -0,0 +1,235 @@
+/*
+ rdesktop: A Remote Desktop Protocol client.
+ Cache routines
+ Copyright (C) Matthew Chapman 1999-2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "rdesktop.h"
+
+#define NUM_ELEMENTS(array) (sizeof(array) / sizeof(array[0]))
+
+
+/* BITMAP CACHE */
+static HBITMAP bmpcache[3][600];
+
+/* Retrieve a bitmap from the cache */
+HBITMAP
+cache_get_bitmap(uint8 cache_id, uint16 cache_idx)
+{
+ HBITMAP bitmap;
+
+ if ((cache_id < NUM_ELEMENTS(bmpcache)) && (cache_idx < NUM_ELEMENTS(bmpcache[0])))
+ {
+ bitmap = bmpcache[cache_id][cache_idx];
+ if (bitmap != NULL)
+ return bitmap;
+ }
+
+ error("get bitmap %d:%d\n", cache_id, cache_idx);
+ return NULL;
+}
+
+/* Store a bitmap in the cache */
+void
+cache_put_bitmap(uint8 cache_id, uint16 cache_idx, HBITMAP bitmap)
+{
+ HBITMAP old;
+
+ if ((cache_id < NUM_ELEMENTS(bmpcache)) && (cache_idx < NUM_ELEMENTS(bmpcache[0])))
+ {
+ old = bmpcache[cache_id][cache_idx];
+ if (old != NULL)
+ ui_destroy_bitmap(old);
+
+ bmpcache[cache_id][cache_idx] = bitmap;
+ }
+ else
+ {
+ error("put bitmap %d:%d\n", cache_id, cache_idx);
+ }
+}
+
+
+/* FONT CACHE */
+static FONTGLYPH fontcache[12][256];
+
+/* Retrieve a glyph from the font cache */
+FONTGLYPH *
+cache_get_font(uint8 font, uint16 character)
+{
+ FONTGLYPH *glyph;
+
+ if ((font < NUM_ELEMENTS(fontcache)) && (character < NUM_ELEMENTS(fontcache[0])))
+ {
+ glyph = &fontcache[font][character];
+ if (glyph->pixmap != NULL)
+ return glyph;
+ }
+
+ error("get font %d:%d\n", font, character);
+ return NULL;
+}
+
+/* Store a glyph in the font cache */
+void
+cache_put_font(uint8 font, uint16 character, uint16 offset,
+ uint16 baseline, uint16 width, uint16 height, HGLYPH pixmap)
+{
+ FONTGLYPH *glyph;
+
+ if ((font < NUM_ELEMENTS(fontcache)) && (character < NUM_ELEMENTS(fontcache[0])))
+ {
+ glyph = &fontcache[font][character];
+ if (glyph->pixmap != NULL)
+ ui_destroy_glyph(glyph->pixmap);
+
+ glyph->offset = offset;
+ glyph->baseline = baseline;
+ glyph->width = width;
+ glyph->height = height;
+ glyph->pixmap = pixmap;
+ }
+ else
+ {
+ error("put font %d:%d\n", font, character);
+ }
+}
+
+
+/* TEXT CACHE */
+static DATABLOB textcache[256];
+
+/* Retrieve a text item from the cache */
+DATABLOB *
+cache_get_text(uint8 cache_id)
+{
+ DATABLOB *text;
+
+ if (cache_id < NUM_ELEMENTS(textcache))
+ {
+ text = &textcache[cache_id];
+ if (text->data != NULL)
+ return text;
+ }
+
+ error("get text %d\n", cache_id);
+ return NULL;
+}
+
+/* Store a text item in the cache */
+void
+cache_put_text(uint8 cache_id, void *data, int length)
+{
+ DATABLOB *text;
+
+ if (cache_id < NUM_ELEMENTS(textcache))
+ {
+ text = &textcache[cache_id];
+ if (text->data != NULL)
+ xfree(text->data);
+
+ text->data = xmalloc(length);
+ text->size = length;
+ memcpy(text->data, data, length);
+ }
+ else
+ {
+ error("put text %d\n", cache_id);
+ }
+}
+
+
+/* DESKTOP CACHE */
+static uint8 deskcache[0x38400];
+
+/* Retrieve desktop data from the cache */
+uint8 *
+cache_get_desktop(uint32 offset, int cx, int cy, int bytes_per_pixel)
+{
+ int length = cx * cy * bytes_per_pixel;
+
+ if ((offset + length) <= sizeof(deskcache))
+ {
+ return &deskcache[offset];
+ }
+
+ error("get desktop %d:%d\n", offset, length);
+ return NULL;
+}
+
+/* Store desktop data in the cache */
+void
+cache_put_desktop(uint32 offset, int cx, int cy, int scanline, int bytes_per_pixel, uint8 * data)
+{
+ int length = cx * cy * bytes_per_pixel;
+
+ if ((offset + length) <= sizeof(deskcache))
+ {
+ cx *= bytes_per_pixel;
+ while (cy--)
+ {
+ memcpy(&deskcache[offset], data, cx);
+ data += scanline;
+ offset += cx;
+ }
+ }
+ else
+ {
+ error("put desktop %d:%d\n", offset, length);
+ }
+}
+
+
+/* CURSOR CACHE */
+static HCURSOR cursorcache[0x20];
+
+/* Retrieve cursor from cache */
+HCURSOR
+cache_get_cursor(uint16 cache_idx)
+{
+ HCURSOR cursor;
+
+ if (cache_idx < NUM_ELEMENTS(cursorcache))
+ {
+ cursor = cursorcache[cache_idx];
+ if (cursor != NULL)
+ return cursor;
+ }
+
+ error("get cursor %d\n", cache_idx);
+ return NULL;
+}
+
+/* Store cursor in cache */
+void
+cache_put_cursor(uint16 cache_idx, HCURSOR cursor)
+{
+ HCURSOR old;
+
+ if (cache_idx < NUM_ELEMENTS(cursorcache))
+ {
+ old = cursorcache[cache_idx];
+ if (old != NULL)
+ ui_destroy_cursor(old);
+
+ cursorcache[cache_idx] = cursor;
+ }
+ else
+ {
+ error("put cursor %d\n", cache_idx);
+ }
+}
diff --git a/noncore/net/opierdesktop/constants.h b/noncore/net/opierdesktop/constants.h
new file mode 100644
index 0000000..6dfbf93
--- a/dev/null
+++ b/noncore/net/opierdesktop/constants.h
@@ -0,0 +1,259 @@
+/*
+ rdesktop: A Remote Desktop Protocol client.
+ Miscellaneous protocol constants
+ Copyright (C) Matthew Chapman 1999-2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* TCP port for Remote Desktop Protocol */
+#define TCP_PORT_RDP 3389
+
+/* ISO PDU codes */
+enum ISO_PDU_CODE
+{
+ ISO_PDU_CR = 0xE0, /* Connection Request */
+ ISO_PDU_CC = 0xD0, /* Connection Confirm */
+ ISO_PDU_DR = 0x80, /* Disconnect Request */
+ ISO_PDU_DT = 0xF0, /* Data */
+ ISO_PDU_ER = 0x70 /* Error */
+};
+
+/* MCS PDU codes */
+enum MCS_PDU_TYPE
+{
+ MCS_EDRQ = 1, /* Erect Domain Request */
+ MCS_DPUM = 8, /* Disconnect Provider Ultimatum */
+ MCS_AURQ = 10, /* Attach User Request */
+ MCS_AUCF = 11, /* Attach User Confirm */
+ MCS_CJRQ = 14, /* Channel Join Request */
+ MCS_CJCF = 15, /* Channel Join Confirm */
+ MCS_SDRQ = 25, /* Send Data Request */
+ MCS_SDIN = 26 /* Send Data Indication */
+};
+
+#define MCS_CONNECT_INITIAL 0x7f65
+#define MCS_CONNECT_RESPONSE 0x7f66
+
+#define BER_TAG_BOOLEAN 1
+#define BER_TAG_INTEGER 2
+#define BER_TAG_OCTET_STRING 4
+#define BER_TAG_RESULT 10
+#define MCS_TAG_DOMAIN_PARAMS 0x30
+
+#define MCS_GLOBAL_CHANNEL 1003
+
+/* RDP secure transport constants */
+#define SEC_RANDOM_SIZE 32
+#define SEC_MODULUS_SIZE 64
+#define SEC_PADDING_SIZE 8
+#define SEC_EXPONENT_SIZE 4
+
+#define SEC_CLIENT_RANDOM 0x0001
+#define SEC_ENCRYPT 0x0008
+#define SEC_LOGON_INFO 0x0040
+#define SEC_LICENCE_NEG 0x0080
+
+#define SEC_TAG_SRV_INFO 0x0c01
+#define SEC_TAG_SRV_CRYPT 0x0c02
+#define SEC_TAG_SRV_3 0x0c03
+
+#define SEC_TAG_CLI_INFO 0xc001
+#define SEC_TAG_CLI_CRYPT 0xc002
+
+#define SEC_TAG_PUBKEY 0x0006
+#define SEC_TAG_KEYSIG 0x0008
+
+#define SEC_RSA_MAGIC 0x31415352 /* RSA1 */
+
+/* RDP licensing constants */
+#define LICENCE_TOKEN_SIZE 10
+#define LICENCE_HWID_SIZE 20
+#define LICENCE_SIGNATURE_SIZE 16
+
+#define LICENCE_TAG_DEMAND 0x0201
+#define LICENCE_TAG_AUTHREQ 0x0202
+#define LICENCE_TAG_ISSUE 0x0203
+#define LICENCE_TAG_REISSUE 0x0204
+#define LICENCE_TAG_PRESENT 0x0212
+#define LICENCE_TAG_REQUEST 0x0213
+#define LICENCE_TAG_AUTHRESP 0x0215
+#define LICENCE_TAG_RESULT 0x02ff
+
+#define LICENCE_TAG_USER 0x000f
+#define LICENCE_TAG_HOST 0x0010
+
+/* RDP PDU codes */
+enum RDP_PDU_TYPE
+{
+ RDP_PDU_DEMAND_ACTIVE = 1,
+ RDP_PDU_CONFIRM_ACTIVE = 3,
+ RDP_PDU_DEACTIVATE = 6,
+ RDP_PDU_DATA = 7
+};
+
+enum RDP_DATA_PDU_TYPE
+{
+ RDP_DATA_PDU_UPDATE = 2,
+ RDP_DATA_PDU_CONTROL = 20,
+ RDP_DATA_PDU_POINTER = 27,
+ RDP_DATA_PDU_INPUT = 28,
+ RDP_DATA_PDU_SYNCHRONISE = 31,
+ RDP_DATA_PDU_BELL = 34,
+ RDP_DATA_PDU_LOGON = 38,
+ RDP_DATA_PDU_FONT2 = 39
+};
+
+enum RDP_CONTROL_PDU_TYPE
+{
+ RDP_CTL_REQUEST_CONTROL = 1,
+ RDP_CTL_GRANT_CONTROL = 2,
+ RDP_CTL_DETACH = 3,
+ RDP_CTL_COOPERATE = 4
+};
+
+enum RDP_UPDATE_PDU_TYPE
+{
+ RDP_UPDATE_ORDERS = 0,
+ RDP_UPDATE_BITMAP = 1,
+ RDP_UPDATE_PALETTE = 2,
+ RDP_UPDATE_SYNCHRONIZE = 3
+};
+
+enum RDP_POINTER_PDU_TYPE
+{
+ RDP_POINTER_MOVE = 3,
+ RDP_POINTER_COLOR = 6,
+ RDP_POINTER_CACHED = 7
+};
+
+enum RDP_INPUT_DEVICE
+{
+ RDP_INPUT_SYNCHRONIZE = 0,
+ RDP_INPUT_CODEPOINT = 1,
+ RDP_INPUT_VIRTKEY = 2,
+ RDP_INPUT_SCANCODE = 4,
+ RDP_INPUT_MOUSE = 0x8001
+};
+
+/* Device flags */
+#define KBD_FLAG_RIGHT 0x0001
+#define KBD_FLAG_EXT 0x0100
+#define KBD_FLAG_QUIET 0x1000
+#define KBD_FLAG_DOWN 0x4000
+#define KBD_FLAG_UP 0x8000
+
+/* These are for synchronization; not for keystrokes */
+#define KBD_FLAG_SCROLL 0x0001
+#define KBD_FLAG_NUMLOCK 0x0002
+#define KBD_FLAG_CAPITAL 0x0004
+
+/* See T.128 */
+#define RDP_KEYPRESS 0
+#define RDP_KEYRELEASE (KBD_FLAG_DOWN | KBD_FLAG_UP)
+
+#define MOUSE_FLAG_MOVE 0x0800
+#define MOUSE_FLAG_BUTTON1 0x1000
+#define MOUSE_FLAG_BUTTON2 0x2000
+#define MOUSE_FLAG_BUTTON3 0x4000
+#define MOUSE_FLAG_BUTTON4 0x0280
+#define MOUSE_FLAG_BUTTON5 0x0380
+#define MOUSE_FLAG_DOWN 0x8000
+
+/* Raster operation masks */
+#define ROP2_S(rop3) (rop3 & 0xf)
+#define ROP2_P(rop3) ((rop3 & 0x3) | ((rop3 & 0x30) >> 2))
+
+#define ROP2_COPY 0xc
+#define ROP2_XOR 0x6
+#define ROP2_AND 0x8
+#define ROP2_NXOR 0x9
+#define ROP2_OR 0xe
+
+#define MIX_TRANSPARENT 0
+#define MIX_OPAQUE 1
+
+#define TEXT2_VERTICAL 0x04
+#define TEXT2_IMPLICIT_X 0x20
+
+/* RDP capabilities */
+#define RDP_CAPSET_GENERAL 1
+#define RDP_CAPLEN_GENERAL 0x18
+#define OS_MAJOR_TYPE_UNIX 4
+#define OS_MINOR_TYPE_XSERVER 7
+
+#define RDP_CAPSET_BITMAP 2
+#define RDP_CAPLEN_BITMAP 0x1C
+
+#define RDP_CAPSET_ORDER 3
+#define RDP_CAPLEN_ORDER 0x58
+#define ORDER_CAP_NEGOTIATE 2
+#define ORDER_CAP_NOSUPPORT 4
+
+#define RDP_CAPSET_BMPCACHE 4
+#define RDP_CAPLEN_BMPCACHE 0x28
+
+#define RDP_CAPSET_CONTROL 5
+#define RDP_CAPLEN_CONTROL 0x0C
+
+#define RDP_CAPSET_ACTIVATE 7
+#define RDP_CAPLEN_ACTIVATE 0x0C
+
+#define RDP_CAPSET_POINTER 8
+#define RDP_CAPLEN_POINTER 0x08
+
+#define RDP_CAPSET_SHARE 9
+#define RDP_CAPLEN_SHARE 0x08
+
+#define RDP_CAPSET_COLCACHE 10
+#define RDP_CAPLEN_COLCACHE 0x08
+
+#define RDP_CAPSET_UNKNOWN 13
+#define RDP_CAPLEN_UNKNOWN 0x9C
+
+#define RDP_SOURCE "MSTSC"
+
+/* Logon flags */
+#define RDP_LOGON_NORMAL 0x33
+#define RDP_LOGON_AUTO 0x8
+
+/* Keymap flags */
+#define MapRightShiftMask (1<<0)
+#define MapLeftShiftMask (1<<1)
+#define MapShiftMask (MapRightShiftMask | MapLeftShiftMask)
+
+#define MapRightAltMask (1<<2)
+#define MapLeftAltMask (1<<3)
+#define MapAltGrMask MapRightAltMask
+
+#define MapRightCtrlMask (1<<4)
+#define MapLeftCtrlMask (1<<5)
+#define MapCtrlMask (MapRightCtrlMask | MapLeftCtrlMask)
+
+#define MapRightWinMask (1<<6)
+#define MapLeftWinMask (1<<7)
+#define MapWinMask (MapRightWinMask | MapLeftWinMask)
+
+#define MapNumLockMask (1<<8)
+#define MapCapsLockMask (1<<9)
+
+#define MapLocalStateMask (1<<10)
+
+#define MapInhibitMask (1<<11)
+
+#define MASK_ADD_BITS(var, mask) (var |= mask)
+#define MASK_REMOVE_BITS(var, mask) (var &= ~mask)
+#define MASK_HAS_BITS(var, mask) ((var & mask)>0)
+#define MASK_CHANGE_BIT(var, mask, active) (var = ((var & ~mask) | (active ? mask : 0)))
diff --git a/noncore/net/opierdesktop/iso.cpp b/noncore/net/opierdesktop/iso.cpp
new file mode 100644
index 0000000..0fa1a17
--- a/dev/null
+++ b/noncore/net/opierdesktop/iso.cpp
@@ -0,0 +1,170 @@
+/*
+ rdesktop: A Remote Desktop Protocol client.
+ Protocol services - ISO layer
+ Copyright (C) Matthew Chapman 1999-2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "rdesktop.h"
+
+/* Send a self-contained ISO PDU */
+static void
+iso_send_msg(uint8 code)
+{
+ STREAM s;
+
+ s = tcp_init(11);
+
+ out_uint8(s, 3); /* version */
+ out_uint8(s, 0); /* reserved */
+ out_uint16_be(s, 11); /* length */
+
+ out_uint8(s, 6); /* hdrlen */
+ out_uint8(s, code);
+ out_uint16(s, 0); /* dst_ref */
+ out_uint16(s, 0); /* src_ref */
+ out_uint8(s, 0); /* class */
+
+ s_mark_end(s);
+ tcp_send(s);
+}
+
+/* Receive a message on the ISO layer, return code */
+static STREAM
+iso_recv_msg(uint8 * code)
+{
+ STREAM s;
+ uint16 length;
+ uint8 version;
+
+ s = tcp_recv(4);
+ if (s == NULL)
+ {
+ return NULL;
+ }
+
+ in_uint8(s, version);
+ if (version != 3)
+ {
+ error("TPKT v%d\n", version);
+ return NULL;
+ }
+
+ in_uint8s(s, 1); /* pad */
+ in_uint16_be(s, length);
+
+ s = tcp_recv(length - 4);
+ if (s == NULL)
+ return NULL;
+
+ in_uint8s(s, 1); /* hdrlen */
+ in_uint8(s, *code);
+
+ if (*code == ISO_PDU_DT)
+ {
+ in_uint8s(s, 1); /* eot */
+ return s;
+ }
+
+ in_uint8s(s, 5); /* dst_ref, src_ref, class */
+ return s;
+}
+
+/* Initialise ISO transport data packet */
+STREAM
+iso_init(int length)
+{
+ STREAM s;
+
+ s = tcp_init(length + 7);
+ s_push_layer(s, iso_hdr, 7);
+
+ return s;
+}
+
+/* Send an ISO data PDU */
+void
+iso_send(STREAM s)
+{
+ uint16 length;
+
+ s_pop_layer(s, iso_hdr);
+ length = s->end - s->p;
+
+ out_uint8(s, 3); /* version */
+ out_uint8(s, 0); /* reserved */
+ out_uint16_be(s, length);
+
+ out_uint8(s, 2); /* hdrlen */
+ out_uint8(s, ISO_PDU_DT); /* code */
+ out_uint8(s, 0x80); /* eot */
+
+ tcp_send(s);
+}
+
+/* Receive ISO transport data packet */
+STREAM
+iso_recv(void)
+{
+ STREAM s;
+ uint8 code;
+
+ s = iso_recv_msg(&code);
+ if (s == NULL)
+ return NULL;
+
+ if (code != ISO_PDU_DT)
+ {
+ error("expected DT, got 0x%x\n", code);
+ return NULL;
+ }
+
+ return s;
+}
+
+/* Establish a connection up to the ISO layer */
+BOOL
+iso_connect(char *server)
+{
+ uint8 code;
+
+ if (!tcp_connect(server))
+ return False;
+
+ iso_send_msg(ISO_PDU_CR);
+
+ if (iso_recv_msg(&code) == NULL)
+ {
+ return False;
+ }
+
+ if (code != ISO_PDU_CC)
+ {
+ error("expected CC, got 0x%x\n", code);
+ tcp_disconnect();
+ return False;
+ }
+
+ return True;
+}
+
+/* Disconnect from the ISO layer */
+void
+iso_disconnect(void)
+{
+ iso_send_msg(ISO_PDU_DR);
+ tcp_disconnect();
+}
diff --git a/noncore/net/opierdesktop/licence.cpp b/noncore/net/opierdesktop/licence.cpp
new file mode 100644
index 0000000..4e5bc38
--- a/dev/null
+++ b/noncore/net/opierdesktop/licence.cpp
@@ -0,0 +1,314 @@
+/*
+ rdesktop: A Remote Desktop Protocol client.
+ RDP licensing negotiation
+ Copyright (C) Matthew Chapman 1999-2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "rdesktop.h"
+
+#ifdef WITH_OPENSSL
+#include <openssl/rc4.h>
+#else
+#include "crypto/rc4.h"
+#endif
+
+extern char username[16];
+extern char hostname[16];
+
+static uint8 licence_key[16];
+static uint8 licence_sign_key[16];
+
+BOOL licence_issued = False;
+
+/* Generate a session key and RC4 keys, given client and server randoms */
+static void
+licence_generate_keys(uint8 * client_key, uint8 * server_key, uint8 * client_rsa)
+{
+ uint8 session_key[48];
+ uint8 temp_hash[48];
+
+ /* Generate session key - two rounds of sec_hash_48 */
+ sec_hash_48(temp_hash, client_rsa, client_key, server_key, 65);
+ sec_hash_48(session_key, temp_hash, server_key, client_key, 65);
+
+ /* Store first 16 bytes of session key, for generating signatures */
+ memcpy(licence_sign_key, session_key, 16);
+
+ /* Generate RC4 key */
+ sec_hash_16(licence_key, &session_key[16], client_key, server_key);
+}
+
+static void
+licence_generate_hwid(uint8 * hwid)
+{
+ buf_out_uint32(hwid, 2);
+ strncpy((char *) (hwid + 4), hostname, LICENCE_HWID_SIZE - 4);
+}
+
+/* Present an existing licence to the server */
+static void
+licence_present(uint8 * client_random, uint8 * rsa_data,
+ uint8 * licence_data, int licence_size, uint8 * hwid, uint8 * signature)
+{
+ uint32 sec_flags = SEC_LICENCE_NEG;
+ uint16 length =
+ 16 + SEC_RANDOM_SIZE + SEC_MODULUS_SIZE + SEC_PADDING_SIZE +
+ licence_size + LICENCE_HWID_SIZE + LICENCE_SIGNATURE_SIZE;
+ STREAM s;
+
+ s = sec_init(sec_flags, length + 4);
+
+ out_uint16_le(s, LICENCE_TAG_PRESENT);
+ out_uint16_le(s, length);
+
+ out_uint32_le(s, 1);
+ out_uint16(s, 0);
+ out_uint16_le(s, 0x0201);
+
+ out_uint8p(s, client_random, SEC_RANDOM_SIZE);
+ out_uint16(s, 0);
+ out_uint16_le(s, (SEC_MODULUS_SIZE + SEC_PADDING_SIZE));
+ out_uint8p(s, rsa_data, SEC_MODULUS_SIZE);
+ out_uint8s(s, SEC_PADDING_SIZE);
+
+ out_uint16_le(s, 1);
+ out_uint16_le(s, licence_size);
+ out_uint8p(s, licence_data, licence_size);
+
+ out_uint16_le(s, 1);
+ out_uint16_le(s, LICENCE_HWID_SIZE);
+ out_uint8p(s, hwid, LICENCE_HWID_SIZE);
+
+ out_uint8p(s, signature, LICENCE_SIGNATURE_SIZE);
+
+ s_mark_end(s);
+ sec_send(s, sec_flags);
+}
+
+/* Send a licence request packet */
+static void
+licence_send_request(uint8 * client_random, uint8 * rsa_data, char *user, char *host)
+{
+ uint32 sec_flags = SEC_LICENCE_NEG;
+ uint16 userlen = strlen(user) + 1;
+ uint16 hostlen = strlen(host) + 1;
+ uint16 length = 128 + userlen + hostlen;
+ STREAM s;
+
+ s = sec_init(sec_flags, length + 2);
+
+ out_uint16_le(s, LICENCE_TAG_REQUEST);
+ out_uint16_le(s, length);
+
+ out_uint32_le(s, 1);
+ out_uint16(s, 0);
+ out_uint16_le(s, 0xff01);
+
+ out_uint8p(s, client_random, SEC_RANDOM_SIZE);
+ out_uint16(s, 0);
+ out_uint16_le(s, (SEC_MODULUS_SIZE + SEC_PADDING_SIZE));
+ out_uint8p(s, rsa_data, SEC_MODULUS_SIZE);
+ out_uint8s(s, SEC_PADDING_SIZE);
+
+ out_uint16(s, LICENCE_TAG_USER);
+ out_uint16(s, userlen);
+ out_uint8p(s, user, userlen);
+
+ out_uint16(s, LICENCE_TAG_HOST);
+ out_uint16(s, hostlen);
+ out_uint8p(s, host, hostlen);
+
+ s_mark_end(s);
+ sec_send(s, sec_flags);
+}
+
+/* Process a licence demand packet */
+static void
+licence_process_demand(STREAM s)
+{
+ uint8 null_data[SEC_MODULUS_SIZE];
+ uint8 *server_random;
+ uint8 signature[LICENCE_SIGNATURE_SIZE];
+ uint8 hwid[LICENCE_HWID_SIZE];
+ uint8 *licence_data;
+ int licence_size;
+ RC4_KEY crypt_key;
+
+ /* Retrieve the server random from the incoming packet */
+ in_uint8p(s, server_random, SEC_RANDOM_SIZE);
+
+ /* We currently use null client keys. This is a bit naughty but, hey,
+ the security of licence negotiation isn't exactly paramount. */
+ memset(null_data, 0, sizeof(null_data));
+ licence_generate_keys(null_data, server_random, null_data);
+
+ licence_size = load_licence(&licence_data);
+ if (licence_size != -1)
+ {
+ /* Generate a signature for the HWID buffer */
+ licence_generate_hwid(hwid);
+ sec_sign(signature, 16, licence_sign_key, 16, hwid, sizeof(hwid));
+
+ /* Now encrypt the HWID */
+ RC4_set_key(&crypt_key, 16, licence_key);
+ RC4(&crypt_key, sizeof(hwid), hwid, hwid);
+
+ licence_present(null_data, null_data, licence_data, licence_size, hwid, signature);
+ xfree(licence_data);
+ return;
+ }
+
+ licence_send_request(null_data, null_data, username, hostname);
+}
+
+/* Send an authentication response packet */
+static void
+licence_send_authresp(uint8 * token, uint8 * crypt_hwid, uint8 * signature)
+{
+ uint32 sec_flags = SEC_LICENCE_NEG;
+ uint16 length = 58;
+ STREAM s;
+
+ s = sec_init(sec_flags, length + 2);
+
+ out_uint16_le(s, LICENCE_TAG_AUTHRESP);
+ out_uint16_le(s, length);
+
+ out_uint16_le(s, 1);
+ out_uint16_le(s, LICENCE_TOKEN_SIZE);
+ out_uint8p(s, token, LICENCE_TOKEN_SIZE);
+
+ out_uint16_le(s, 1);
+ out_uint16_le(s, LICENCE_HWID_SIZE);
+ out_uint8p(s, crypt_hwid, LICENCE_HWID_SIZE);
+
+ out_uint8p(s, signature, LICENCE_SIGNATURE_SIZE);
+
+ s_mark_end(s);
+ sec_send(s, sec_flags);
+}
+
+/* Parse an authentication request packet */
+static BOOL
+licence_parse_authreq(STREAM s, uint8 ** token, uint8 ** signature)
+{
+ uint16 tokenlen;
+
+ in_uint8s(s, 6); /* unknown: f8 3d 15 00 04 f6 */
+
+ in_uint16_le(s, tokenlen);
+ if (tokenlen != LICENCE_TOKEN_SIZE)
+ {
+ error("token len %d\n", tokenlen);
+ return False;
+ }
+
+ in_uint8p(s, *token, tokenlen);
+ in_uint8p(s, *signature, LICENCE_SIGNATURE_SIZE);
+
+ return s_check_end(s);
+}
+
+/* Process an authentication request packet */
+static void
+licence_process_authreq(STREAM s)
+{
+ uint8 *in_token, *in_sig;
+ uint8 out_token[LICENCE_TOKEN_SIZE], decrypt_token[LICENCE_TOKEN_SIZE];
+ uint8 hwid[LICENCE_HWID_SIZE], crypt_hwid[LICENCE_HWID_SIZE];
+ uint8 sealed_buffer[LICENCE_TOKEN_SIZE + LICENCE_HWID_SIZE];
+ uint8 out_sig[LICENCE_SIGNATURE_SIZE];
+ RC4_KEY crypt_key;
+
+ /* Parse incoming packet and save the encrypted token */
+ licence_parse_authreq(s, &in_token, &in_sig);
+ memcpy(out_token, in_token, LICENCE_TOKEN_SIZE);
+
+ /* Decrypt the token. It should read TEST in Unicode. */
+ RC4_set_key(&crypt_key, 16, licence_key);
+ RC4(&crypt_key, LICENCE_TOKEN_SIZE, in_token, decrypt_token);
+
+ /* Generate a signature for a buffer of token and HWID */
+ licence_generate_hwid(hwid);
+ memcpy(sealed_buffer, decrypt_token, LICENCE_TOKEN_SIZE);
+ memcpy(sealed_buffer + LICENCE_TOKEN_SIZE, hwid, LICENCE_HWID_SIZE);
+ sec_sign(out_sig, 16, licence_sign_key, 16, sealed_buffer, sizeof(sealed_buffer));
+
+ /* Now encrypt the HWID */
+ RC4_set_key(&crypt_key, 16, licence_key);
+ RC4(&crypt_key, LICENCE_HWID_SIZE, hwid, crypt_hwid);
+
+ licence_send_authresp(out_token, crypt_hwid, out_sig);
+}
+
+/* Process an licence issue packet */
+static void
+licence_process_issue(STREAM s)
+{
+ RC4_KEY crypt_key;
+ uint32 length;
+ uint16 check;
+
+ in_uint8s(s, 2); /* 3d 45 - unknown */
+ in_uint16_le(s, length);
+ if (!s_check_rem(s, length))
+ return;
+
+ RC4_set_key(&crypt_key, 16, licence_key);
+ RC4(&crypt_key, length, s->p, s->p);
+
+ in_uint16(s, check);
+ if (check != 0)
+ return;
+
+ licence_issued = True;
+ save_licence(s->p, length - 2);
+}
+
+/* Process a licence packet */
+void
+licence_process(STREAM s)
+{
+ uint16 tag;
+
+ in_uint16_le(s, tag);
+ in_uint8s(s, 2); /* length */
+
+ switch (tag)
+ {
+ case LICENCE_TAG_DEMAND:
+ licence_process_demand(s);
+ break;
+
+ case LICENCE_TAG_AUTHREQ:
+ licence_process_authreq(s);
+ break;
+
+ case LICENCE_TAG_ISSUE:
+ licence_process_issue(s);
+ break;
+
+ case LICENCE_TAG_REISSUE:
+ break;
+
+ case LICENCE_TAG_RESULT:
+ break;
+
+ default:
+ unimpl("licence tag 0x%x\n", tag);
+ }
+}
diff --git a/noncore/net/opierdesktop/mcs.cpp b/noncore/net/opierdesktop/mcs.cpp
new file mode 100644
index 0000000..8877d62
--- a/dev/null
+++ b/noncore/net/opierdesktop/mcs.cpp
@@ -0,0 +1,394 @@
+/*
+ rdesktop: A Remote Desktop Protocol client.
+ Protocol services - Multipoint Communications Service
+ Copyright (C) Matthew Chapman 1999-2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "rdesktop.h"
+
+uint16 mcs_userid;
+
+/* Parse an ASN.1 BER header */
+static BOOL
+ber_parse_header(STREAM s, int tagval, unsigned int *length)
+{
+ int tag, len;
+
+ if (tagval > 0xff)
+ {
+ in_uint16_be(s, tag);
+ }
+ else
+ {
+ in_uint8(s, tag)}
+
+ if (tag != tagval)
+ {
+ error("expected tag %d, got %d\n", tagval, tag);
+ return False;
+ }
+
+ in_uint8(s, len);
+
+ if (len & 0x80)
+ {
+ len &= ~0x80;
+ *length = 0;
+ while (len--)
+ next_be(s, *length);
+ }
+ else
+ *length = len;
+
+ return s_check(s);
+}
+
+/* Output an ASN.1 BER header */
+static void
+ber_out_header(STREAM s, int tagval, int length)
+{
+ if (tagval > 0xff)
+ {
+ out_uint16_be(s, tagval);
+ }
+ else
+ {
+ out_uint8(s, tagval);
+ }
+
+ if (length >= 0x80)
+ {
+ out_uint8(s, 0x82);
+ out_uint16_be(s, length);
+ }
+ else
+ out_uint8(s, length);
+}
+
+/* Output an ASN.1 BER integer */
+static void
+ber_out_integer(STREAM s, int value)
+{
+ ber_out_header(s, BER_TAG_INTEGER, 2);
+ out_uint16_be(s, value);
+}
+
+/* Output a DOMAIN_PARAMS structure (ASN.1 BER) */
+static void
+mcs_out_domain_params(STREAM s, int max_channels, int max_users, int max_tokens, int max_pdusize)
+{
+ ber_out_header(s, MCS_TAG_DOMAIN_PARAMS, 32);
+ ber_out_integer(s, max_channels);
+ ber_out_integer(s, max_users);
+ ber_out_integer(s, max_tokens);
+ ber_out_integer(s, 1); /* num_priorities */
+ ber_out_integer(s, 0); /* min_throughput */
+ ber_out_integer(s, 1); /* max_height */
+ ber_out_integer(s, max_pdusize);
+ ber_out_integer(s, 2); /* ver_protocol */
+}
+
+/* Parse a DOMAIN_PARAMS structure (ASN.1 BER) */
+static BOOL
+mcs_parse_domain_params(STREAM s)
+{
+ unsigned int length;
+
+ ber_parse_header(s, MCS_TAG_DOMAIN_PARAMS, &length);
+ in_uint8s(s, length);
+
+ return s_check(s);
+}
+
+/* Send an MCS_CONNECT_INITIAL message (ASN.1 BER) */
+static void
+mcs_send_connect_initial(STREAM mcs_data)
+{
+ int datalen = mcs_data->end - mcs_data->data;
+ int length = 7 + 3 * 34 + 4 + datalen;
+ STREAM s;
+
+ s = iso_init(length + 5);
+
+ ber_out_header(s, MCS_CONNECT_INITIAL, length);
+ ber_out_header(s, BER_TAG_OCTET_STRING, 0); /* calling domain */
+ ber_out_header(s, BER_TAG_OCTET_STRING, 0); /* called domain */
+
+ ber_out_header(s, BER_TAG_BOOLEAN, 1);
+ out_uint8(s, 0xff); /* upward flag */
+
+ mcs_out_domain_params(s, 2, 2, 0, 0xffff); /* target params */
+ mcs_out_domain_params(s, 1, 1, 1, 0x420); /* min params */
+ mcs_out_domain_params(s, 0xffff, 0xfc17, 0xffff, 0xffff); /* max params */
+
+ ber_out_header(s, BER_TAG_OCTET_STRING, datalen);
+ out_uint8p(s, mcs_data->data, datalen);
+
+ s_mark_end(s);
+ iso_send(s);
+}
+
+/* Expect a MCS_CONNECT_RESPONSE message (ASN.1 BER) */
+static BOOL
+mcs_recv_connect_response(STREAM mcs_data)
+{
+ uint8 result;
+ unsigned int length;
+ STREAM s;
+
+ s = iso_recv();
+ if (s == NULL)
+ return False;
+
+ ber_parse_header(s, MCS_CONNECT_RESPONSE, &length);
+
+ ber_parse_header(s, BER_TAG_RESULT, &length);
+ in_uint8(s, result);
+ if (result != 0)
+ {
+ error("MCS connect: %d\n", result);
+ return False;
+ }
+
+ ber_parse_header(s, BER_TAG_INTEGER, &length);
+ in_uint8s(s, length); /* connect id */
+ mcs_parse_domain_params(s);
+
+ ber_parse_header(s, BER_TAG_OCTET_STRING, &length);
+ if (length > mcs_data->size)
+ {
+ error("MCS data length %d\n", length);
+ length = mcs_data->size;
+ }
+
+ in_uint8a(s, mcs_data->data, length);
+ mcs_data->p = mcs_data->data;
+ mcs_data->end = mcs_data->data + length;
+
+ return s_check_end(s);
+}
+
+/* Send an EDrq message (ASN.1 PER) */
+static void
+mcs_send_edrq(void)
+{
+ STREAM s;
+
+ s = iso_init(5);
+
+ out_uint8(s, (MCS_EDRQ << 2));
+ out_uint16_be(s, 1); /* height */
+ out_uint16_be(s, 1); /* interval */
+
+ s_mark_end(s);
+ iso_send(s);
+}
+
+/* Send an AUrq message (ASN.1 PER) */
+static void
+mcs_send_aurq(void)
+{
+ STREAM s;
+
+ s = iso_init(1);
+
+ out_uint8(s, (MCS_AURQ << 2));
+
+ s_mark_end(s);
+ iso_send(s);
+}
+
+/* Expect a AUcf message (ASN.1 PER) */
+static BOOL
+mcs_recv_aucf(uint16 * mcs_userid)
+{
+ uint8 opcode, result;
+ STREAM s;
+
+ s = iso_recv();
+ if (s == NULL)
+ return False;
+
+ in_uint8(s, opcode);
+ if ((opcode >> 2) != MCS_AUCF)
+ {
+ error("expected AUcf, got %d\n", opcode);
+ return False;
+ }
+
+ in_uint8(s, result);
+ if (result != 0)
+ {
+ error("AUrq: %d\n", result);
+ return False;
+ }
+
+ if (opcode & 2)
+ in_uint16_be(s, *mcs_userid);
+
+ return s_check_end(s);
+}
+
+/* Send a CJrq message (ASN.1 PER) */
+static void
+mcs_send_cjrq(uint16 chanid)
+{
+ STREAM s;
+
+ s = iso_init(5);
+
+ out_uint8(s, (MCS_CJRQ << 2));
+ out_uint16_be(s, mcs_userid);
+ out_uint16_be(s, chanid);
+
+ s_mark_end(s);
+ iso_send(s);
+}
+
+/* Expect a CJcf message (ASN.1 PER) */
+static BOOL
+mcs_recv_cjcf(void)
+{
+ uint8 opcode, result;
+ STREAM s;
+
+ s = iso_recv();
+ if (s == NULL)
+ return False;
+
+ in_uint8(s, opcode);
+ if ((opcode >> 2) != MCS_CJCF)
+ {
+ error("expected CJcf, got %d\n", opcode);
+ return False;
+ }
+
+ in_uint8(s, result);
+ if (result != 0)
+ {
+ error("CJrq: %d\n", result);
+ return False;
+ }
+
+ in_uint8s(s, 4); /* mcs_userid, req_chanid */
+ if (opcode & 2)
+ in_uint8s(s, 2); /* join_chanid */
+
+ return s_check_end(s);
+}
+
+/* Initialise an MCS transport data packet */
+STREAM
+mcs_init(int length)
+{
+ STREAM s;
+
+ s = iso_init(length + 8);
+ s_push_layer(s, mcs_hdr, 8);
+
+ return s;
+}
+
+/* Send an MCS transport data packet */
+void
+mcs_send(STREAM s)
+{
+ uint16 length;
+
+ s_pop_layer(s, mcs_hdr);
+ length = s->end - s->p - 8;
+ length |= 0x8000;
+
+ out_uint8(s, (MCS_SDRQ << 2));
+ out_uint16_be(s, mcs_userid);
+ out_uint16_be(s, MCS_GLOBAL_CHANNEL);
+ out_uint8(s, 0x70); /* flags */
+ out_uint16_be(s, length);
+
+ iso_send(s);
+}
+
+/* Receive an MCS transport data packet */
+STREAM
+mcs_recv(void)
+{
+ uint8 opcode, appid, length;
+ STREAM s;
+
+ s = iso_recv();
+ if (s == NULL)
+ return NULL;
+
+ in_uint8(s, opcode);
+ appid = opcode >> 2;
+ if (appid != MCS_SDIN)
+ {
+ if (appid != MCS_DPUM)
+ {
+ error("expected data, got %d\n", opcode);
+ }
+ return NULL;
+ }
+
+ in_uint8s(s, 5); /* userid, chanid, flags */
+ in_uint8(s, length);
+ if (length & 0x80)
+ in_uint8s(s, 1); /* second byte of length */
+
+ return s;
+}
+
+/* Establish a connection up to the MCS layer */
+BOOL
+mcs_connect(char *server, STREAM mcs_data)
+{
+ if (!iso_connect(server))
+ {
+ return False;
+ }
+
+ mcs_send_connect_initial(mcs_data);
+ if (!mcs_recv_connect_response(mcs_data))
+ goto error;
+
+ mcs_send_edrq();
+
+ mcs_send_aurq();
+ if (!mcs_recv_aucf(&mcs_userid))
+ goto error;
+
+ mcs_send_cjrq(mcs_userid + 1001);
+ if (!mcs_recv_cjcf())
+ goto error;
+
+ mcs_send_cjrq(MCS_GLOBAL_CHANNEL);
+ if (!mcs_recv_cjcf())
+ goto error;
+
+ return True;
+
+ error:
+ iso_disconnect();
+ return False;
+}
+
+/* Disconnect from the MCS layer */
+void
+mcs_disconnect(void)
+{
+ iso_disconnect();
+}
diff --git a/noncore/net/opierdesktop/opie-rdesktop.control b/noncore/net/opierdesktop/opie-rdesktop.control
new file mode 100644
index 0000000..3fe3705
--- a/dev/null
+++ b/noncore/net/opierdesktop/opie-rdesktop.control
@@ -0,0 +1,9 @@
+Package: opie-rdesktop
+Files: bin/ordesktop pics/opierdesktop apps/Applications/opierdesktop.desktop
+Priority: optional
+Section: opie/applications
+Maintainer: Michael 'Mickey' Lauer <mickeyl@handhelds.org>
+Architecture: arm
+Version: 1.2.0-$SUB_VERSION
+Depends: task-opie-minimal
+Description: Remote Desktop Protocol (RDP) Client
diff --git a/noncore/net/opierdesktop/opierdesktop.pro b/noncore/net/opierdesktop/opierdesktop.pro
new file mode 100644
index 0000000..7704855
--- a/dev/null
+++ b/noncore/net/opierdesktop/opierdesktop.pro
@@ -0,0 +1,26 @@
+TEMPLATE = app
+DESTDIR = $(OPIEDIR)/bin
+CONFIG = qt warn_on debug
+
+HEADERS += constants.h orders.h parse.h proto.h qtwin.h rdesktop.h types.h
+SOURCES += bitmap.cpp \
+ cache.cpp \
+ iso.cpp \
+ licence.cpp \
+ mcs.cpp \
+ orders.cpp \
+ qtwin.cpp \
+ rdesktop.cpp \
+ rdp.cpp \
+ secure.cpp \
+ tcp.cpp
+
+INCLUDEPATH += $(OPIEDIR)/include
+DEPENDPATH += $(OPIEDIR)/include
+LIBS += -lqpe -lm -lcrypto
+INTERFACES =
+TARGET = ordesktop
+QMAKE_CXXFLAGS += -DSHARP=1 -DWITH_OPENSSL=1
+
+include ( $(OPIEDIR)/include.pro )
+
diff --git a/noncore/net/opierdesktop/orders.cpp b/noncore/net/opierdesktop/orders.cpp
new file mode 100644
index 0000000..194b043
--- a/dev/null
+++ b/noncore/net/opierdesktop/orders.cpp
@@ -0,0 +1,940 @@
+/*
+ rdesktop: A Remote Desktop Protocol client.
+ RDP order processing
+ Copyright (C) Matthew Chapman 1999-2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "rdesktop.h"
+#include "orders.h"
+
+extern uint8 *next_packet;
+static RDP_ORDER_STATE order_state;
+
+/* Read field indicating which parameters are present */
+static void
+rdp_in_present(STREAM s, uint32 * present, uint8 flags, int size)
+{
+ uint8 bits;
+ int i;
+
+ if (flags & RDP_ORDER_SMALL)
+ {
+ size--;
+ }
+
+ if (flags & RDP_ORDER_TINY)
+ {
+ if (size < 2)
+ size = 0;
+ else
+ size -= 2;
+ }
+
+ *present = 0;
+ for (i = 0; i < size; i++)
+ {
+ in_uint8(s, bits);
+ *present |= bits << (i * 8);
+ }
+}
+
+/* Read a co-ordinate (16-bit, or 8-bit delta) */
+static void
+rdp_in_coord(STREAM s, sint16 * coord, BOOL delta)
+{
+ sint8 change;
+
+ if (delta)
+ {
+ in_uint8(s, change);
+ *coord += change;
+ }
+ else
+ {
+ in_uint16_le(s, *coord);
+ }
+}
+
+/* Read a colour entry */
+static void
+rdp_in_colour(STREAM s, uint32 * colour)
+{
+ uint32 i;
+ in_uint8(s, i);
+ *colour = i;
+ in_uint8(s, i);
+ *colour |= i << 8;
+ in_uint8(s, i);
+ *colour |= i << 16;
+}
+
+/* Parse bounds information */
+static BOOL
+rdp_parse_bounds(STREAM s, BOUNDS * bounds)
+{
+ uint8 present;
+
+ in_uint8(s, present);
+
+ if (present & 1)
+ rdp_in_coord(s, &bounds->left, False);
+ else if (present & 16)
+ rdp_in_coord(s, &bounds->left, True);
+
+ if (present & 2)
+ rdp_in_coord(s, &bounds->top, False);
+ else if (present & 32)
+ rdp_in_coord(s, &bounds->top, True);
+
+ if (present & 4)
+ rdp_in_coord(s, &bounds->right, False);
+ else if (present & 64)
+ rdp_in_coord(s, &bounds->right, True);
+
+ if (present & 8)
+ rdp_in_coord(s, &bounds->bottom, False);
+ else if (present & 128)
+ rdp_in_coord(s, &bounds->bottom, True);
+
+ return s_check(s);
+}
+
+/* Parse a pen */
+static BOOL
+rdp_parse_pen(STREAM s, PEN * pen, uint32 present)
+{
+ if (present & 1)
+ in_uint8(s, pen->style);
+
+ if (present & 2)
+ in_uint8(s, pen->width);
+
+ if (present & 4)
+ rdp_in_colour(s, &pen->colour);
+
+ return s_check(s);
+}
+
+/* Parse a brush */
+static BOOL
+rdp_parse_brush(STREAM s, BRUSH * brush, uint32 present)
+{
+ if (present & 1)
+ in_uint8(s, brush->xorigin);
+
+ if (present & 2)
+ in_uint8(s, brush->yorigin);
+
+ if (present & 4)
+ in_uint8(s, brush->style);
+
+ if (present & 8)
+ in_uint8(s, brush->pattern[0]);
+
+ if (present & 16)
+ in_uint8a(s, &brush->pattern[1], 7);
+
+ return s_check(s);
+}
+
+/* Process a destination blt order */
+static void
+process_destblt(STREAM s, DESTBLT_ORDER * os, uint32 present, BOOL delta)
+{
+ if (present & 0x01)
+ rdp_in_coord(s, &os->x, delta);
+
+ if (present & 0x02)
+ rdp_in_coord(s, &os->y, delta);
+
+ if (present & 0x04)
+ rdp_in_coord(s, &os->cx, delta);
+
+ if (present & 0x08)
+ rdp_in_coord(s, &os->cy, delta);
+
+ if (present & 0x10)
+ in_uint8(s, os->opcode);
+
+ DEBUG(("DESTBLT(op=0x%x,x=%d,y=%d,cx=%d,cy=%d)\n",
+ os->opcode, os->x, os->y, os->cx, os->cy));
+
+ ui_destblt(ROP2_S(os->opcode), os->x, os->y, os->cx, os->cy);
+}
+
+/* Process a pattern blt order */
+static void
+process_patblt(STREAM s, PATBLT_ORDER * os, uint32 present, BOOL delta)
+{
+ if (present & 0x0001)
+ rdp_in_coord(s, &os->x, delta);
+
+ if (present & 0x0002)
+ rdp_in_coord(s, &os->y, delta);
+
+ if (present & 0x0004)
+ rdp_in_coord(s, &os->cx, delta);
+
+ if (present & 0x0008)
+ rdp_in_coord(s, &os->cy, delta);
+
+ if (present & 0x0010)
+ in_uint8(s, os->opcode);
+
+ if (present & 0x0020)
+ rdp_in_colour(s, &os->bgcolour);
+
+ if (present & 0x0040)
+ rdp_in_colour(s, &os->fgcolour);
+
+ rdp_parse_brush(s, &os->brush, present >> 7);
+
+ DEBUG(("PATBLT(op=0x%x,x=%d,y=%d,cx=%d,cy=%d,bs=%d,bg=0x%x,fg=0x%x)\n", os->opcode, os->x,
+ os->y, os->cx, os->cy, os->brush.style, os->bgcolour, os->fgcolour));
+
+ ui_patblt(ROP2_P(os->opcode), os->x, os->y, os->cx, os->cy,
+ &os->brush, os->bgcolour, os->fgcolour);
+}
+
+/* Process a screen blt order */
+static void
+process_screenblt(STREAM s, SCREENBLT_ORDER * os, uint32 present, BOOL delta)
+{
+ if (present & 0x0001)
+ rdp_in_coord(s, &os->x, delta);
+
+ if (present & 0x0002)
+ rdp_in_coord(s, &os->y, delta);
+
+ if (present & 0x0004)
+ rdp_in_coord(s, &os->cx, delta);
+
+ if (present & 0x0008)
+ rdp_in_coord(s, &os->cy, delta);
+
+ if (present & 0x0010)
+ in_uint8(s, os->opcode);
+
+ if (present & 0x0020)
+ rdp_in_coord(s, &os->srcx, delta);
+
+ if (present & 0x0040)
+ rdp_in_coord(s, &os->srcy, delta);
+
+ DEBUG(("SCREENBLT(op=0x%x,x=%d,y=%d,cx=%d,cy=%d,srcx=%d,srcy=%d)\n",
+ os->opcode, os->x, os->y, os->cx, os->cy, os->srcx, os->srcy));
+
+ ui_screenblt(ROP2_S(os->opcode), os->x, os->y, os->cx, os->cy, os->srcx, os->srcy);
+}
+
+/* Process a line order */
+static void
+process_line(STREAM s, LINE_ORDER * os, uint32 present, BOOL delta)
+{
+ if (present & 0x0001)
+ in_uint16_le(s, os->mixmode);
+
+ if (present & 0x0002)
+ rdp_in_coord(s, &os->startx, delta);
+
+ if (present & 0x0004)
+ rdp_in_coord(s, &os->starty, delta);
+
+ if (present & 0x0008)
+ rdp_in_coord(s, &os->endx, delta);
+
+ if (present & 0x0010)
+ rdp_in_coord(s, &os->endy, delta);
+
+ if (present & 0x0020)
+ rdp_in_colour(s, &os->bgcolour);
+
+ if (present & 0x0040)
+ in_uint8(s, os->opcode);
+
+ rdp_parse_pen(s, &os->pen, present >> 7);
+
+ DEBUG(("LINE(op=0x%x,sx=%d,sy=%d,dx=%d,dx=%d,fg=0x%x)\n",
+ os->opcode, os->startx, os->starty, os->endx, os->endy, os->pen.colour));
+
+ if (os->opcode < 0x01 || os->opcode > 0x10)
+ {
+ error("bad ROP2 0x%x\n", os->opcode);
+ return;
+ }
+
+ ui_line(os->opcode - 1, os->startx, os->starty, os->endx, os->endy, &os->pen);
+}
+
+/* Process an opaque rectangle order */
+static void
+process_rect(STREAM s, RECT_ORDER * os, uint32 present, BOOL delta)
+{
+ uint32 i;
+ if (present & 0x01)
+ rdp_in_coord(s, &os->x, delta);
+
+ if (present & 0x02)
+ rdp_in_coord(s, &os->y, delta);
+
+ if (present & 0x04)
+ rdp_in_coord(s, &os->cx, delta);
+
+ if (present & 0x08)
+ rdp_in_coord(s, &os->cy, delta);
+
+ if (present & 0x10)
+ {
+ in_uint8(s, i);
+ os->colour = (os->colour & 0xffffff00) | i;
+ }
+
+ if (present & 0x20)
+ {
+ in_uint8(s, i);
+ os->colour = (os->colour & 0xffff00ff) | (i << 8);
+ }
+
+ if (present & 0x40)
+ {
+ in_uint8(s, i);
+ os->colour = (os->colour & 0xff00ffff) | (i << 16);
+ }
+
+ DEBUG(("RECT(x=%d,y=%d,cx=%d,cy=%d,fg=0x%x)\n", os->x, os->y, os->cx, os->cy, os->colour));
+
+ ui_rect(os->x, os->y, os->cx, os->cy, os->colour);
+}
+
+/* Process a desktop save order */
+static void
+process_desksave(STREAM s, DESKSAVE_ORDER * os, uint32 present, BOOL delta)
+{
+ int width, height;
+
+ if (present & 0x01)
+ in_uint32_le(s, os->offset);
+
+ if (present & 0x02)
+ rdp_in_coord(s, &os->left, delta);
+
+ if (present & 0x04)
+ rdp_in_coord(s, &os->top, delta);
+
+ if (present & 0x08)
+ rdp_in_coord(s, &os->right, delta);
+
+ if (present & 0x10)
+ rdp_in_coord(s, &os->bottom, delta);
+
+ if (present & 0x20)
+ in_uint8(s, os->action);
+
+ DEBUG(("DESKSAVE(l=%d,t=%d,r=%d,b=%d,off=%d,op=%d)\n",
+ os->left, os->top, os->right, os->bottom, os->offset, os->action));
+
+ width = os->right - os->left + 1;
+ height = os->bottom - os->top + 1;
+
+ if (os->action == 0)
+ ui_desktop_save(os->offset, os->left, os->top, width, height);
+ else
+ ui_desktop_restore(os->offset, os->left, os->top, width, height);
+}
+
+/* Process a memory blt order */
+static void
+process_memblt(STREAM s, MEMBLT_ORDER * os, uint32 present, BOOL delta)
+{
+ HBITMAP bitmap;
+
+ if (present & 0x0001)
+ {
+ in_uint8(s, os->cache_id);
+ in_uint8(s, os->colour_table);
+ }
+
+ if (present & 0x0002)
+ rdp_in_coord(s, &os->x, delta);
+
+ if (present & 0x0004)
+ rdp_in_coord(s, &os->y, delta);
+
+ if (present & 0x0008)
+ rdp_in_coord(s, &os->cx, delta);
+
+ if (present & 0x0010)
+ rdp_in_coord(s, &os->cy, delta);
+
+ if (present & 0x0020)
+ in_uint8(s, os->opcode);
+
+ if (present & 0x0040)
+ rdp_in_coord(s, &os->srcx, delta);
+
+ if (present & 0x0080)
+ rdp_in_coord(s, &os->srcy, delta);
+
+ if (present & 0x0100)
+ in_uint16_le(s, os->cache_idx);
+
+ DEBUG(("MEMBLT(op=0x%x,x=%d,y=%d,cx=%d,cy=%d,id=%d,idx=%d)\n",
+ os->opcode, os->x, os->y, os->cx, os->cy, os->cache_id, os->cache_idx));
+
+ bitmap = cache_get_bitmap(os->cache_id, os->cache_idx);
+ if (bitmap == NULL)
+ return;
+
+ ui_memblt(ROP2_S(os->opcode), os->x, os->y, os->cx, os->cy, bitmap, os->srcx, os->srcy);
+}
+
+/* Process a 3-way blt order */
+static void
+process_triblt(STREAM s, TRIBLT_ORDER * os, uint32 present, BOOL delta)
+{
+ HBITMAP bitmap;
+
+ if (present & 0x000001)
+ {
+ in_uint8(s, os->cache_id);
+ in_uint8(s, os->colour_table);
+ }
+
+ if (present & 0x000002)
+ rdp_in_coord(s, &os->x, delta);
+
+ if (present & 0x000004)
+ rdp_in_coord(s, &os->y, delta);
+
+ if (present & 0x000008)
+ rdp_in_coord(s, &os->cx, delta);
+
+ if (present & 0x000010)
+ rdp_in_coord(s, &os->cy, delta);
+
+ if (present & 0x000020)
+ in_uint8(s, os->opcode);
+
+ if (present & 0x000040)
+ rdp_in_coord(s, &os->srcx, delta);
+
+ if (present & 0x000080)
+ rdp_in_coord(s, &os->srcy, delta);
+
+ if (present & 0x000100)
+ rdp_in_colour(s, &os->bgcolour);
+
+ if (present & 0x000200)
+ rdp_in_colour(s, &os->fgcolour);
+
+ rdp_parse_brush(s, &os->brush, present >> 10);
+
+ if (present & 0x008000)
+ in_uint16_le(s, os->cache_idx);
+
+ if (present & 0x010000)
+ in_uint16_le(s, os->unknown);
+
+ DEBUG(("TRIBLT(op=0x%x,x=%d,y=%d,cx=%d,cy=%d,id=%d,idx=%d,bs=%d,bg=0x%x,fg=0x%x)\n",
+ os->opcode, os->x, os->y, os->cx, os->cy, os->cache_id, os->cache_idx,
+ os->brush.style, os->bgcolour, os->fgcolour));
+
+ bitmap = cache_get_bitmap(os->cache_id, os->cache_idx);
+ if (bitmap == NULL)
+ return;
+
+ ui_triblt(os->opcode, os->x, os->y, os->cx, os->cy,
+ bitmap, os->srcx, os->srcy, &os->brush, os->bgcolour, os->fgcolour);
+}
+
+/* Parse a delta co-ordinate in polyline order form */
+static int
+parse_delta(uint8 * buffer, int *offset)
+{
+ int value = buffer[(*offset)++];
+ int two_byte = value & 0x80;
+
+ if (value & 0x40) /* sign bit */
+ value |= ~0x3f;
+ else
+ value &= 0x3f;
+
+ if (two_byte)
+ value = (value << 8) | buffer[(*offset)++];
+
+ return value;
+}
+
+/* Process a polyline order */
+static void
+process_polyline(STREAM s, POLYLINE_ORDER * os, uint32 present, BOOL delta)
+{
+ int index, line, data;
+ int x, y, xfrom, yfrom;
+ uint8 flags = 0;
+ PEN pen;
+ uint8 opcode;
+
+ if (present & 0x01)
+ rdp_in_coord(s, &os->x, delta);
+
+ if (present & 0x02)
+ rdp_in_coord(s, &os->y, delta);
+
+ if (present & 0x04)
+ in_uint8(s, os->opcode);
+
+ if (present & 0x10)
+ rdp_in_colour(s, &os->fgcolour);
+
+ if (present & 0x20)
+ in_uint8(s, os->lines);
+
+ if (present & 0x40)
+ {
+ in_uint8(s, os->datasize);
+ in_uint8a(s, os->data, os->datasize);
+ }
+
+ DEBUG(("POLYLINE(x=%d,y=%d,op=0x%x,fg=0x%x,n=%d,sz=%d)\n",
+ os->x, os->y, os->opcode, os->fgcolour, os->lines, os->datasize));
+
+ DEBUG(("Data: "));
+
+ for (index = 0; index < os->datasize; index++)
+ DEBUG(("%02x ", os->data[index]));
+
+ DEBUG(("\n"));
+
+ if (os->opcode < 0x01 || os->opcode > 0x10)
+ {
+ error("bad ROP2 0x%x\n", os->opcode);
+ return;
+ }
+
+ opcode = os->opcode - 1;
+ x = os->x;
+ y = os->y;
+ pen.style = pen.width = 0;
+ pen.colour = os->fgcolour;
+
+ index = 0;
+ data = ((os->lines - 1) / 4) + 1;
+ for (line = 0; (line < os->lines) && (data < os->datasize); line++)
+ {
+ xfrom = x;
+ yfrom = y;
+
+ if (line % 4 == 0)
+ flags = os->data[index++];
+
+ if ((flags & 0xc0) == 0)
+ flags |= 0xc0; /* none = both */
+
+ if (flags & 0x40)
+ x += parse_delta(os->data, &data);
+
+ if (flags & 0x80)
+ y += parse_delta(os->data, &data);
+
+ ui_line(opcode, xfrom, yfrom, x, y, &pen);
+
+ flags <<= 2;
+ }
+}
+
+/* Process a text order */
+static void
+process_text2(STREAM s, TEXT2_ORDER * os, uint32 present, BOOL delta)
+{
+ int i;
+
+ if (present & 0x000001)
+ in_uint8(s, os->font);
+
+ if (present & 0x000002)
+ in_uint8(s, os->flags);
+
+ if (present & 0x000004)
+ in_uint8(s, os->unknown);
+
+ if (present & 0x000008)
+ in_uint8(s, os->mixmode);
+
+ if (present & 0x000010)
+ rdp_in_colour(s, &os->fgcolour);
+
+ if (present & 0x000020)
+ rdp_in_colour(s, &os->bgcolour);
+
+ if (present & 0x000040)
+ in_uint16_le(s, os->clipleft);
+
+ if (present & 0x000080)
+ in_uint16_le(s, os->cliptop);
+
+ if (present & 0x000100)
+ in_uint16_le(s, os->clipright);
+
+ if (present & 0x000200)
+ in_uint16_le(s, os->clipbottom);
+
+ if (present & 0x000400)
+ in_uint16_le(s, os->boxleft);
+
+ if (present & 0x000800)
+ in_uint16_le(s, os->boxtop);
+
+ if (present & 0x001000)
+ in_uint16_le(s, os->boxright);
+
+ if (present & 0x002000)
+ in_uint16_le(s, os->boxbottom);
+
+ if (present & 0x004000) /* fix for connecting to a server that */
+ in_uint8s(s, 10); /* was disconnected with mstsc.exe */
+ /* 0x008000, 0x020000, and 0x040000 are present too ??? */
+
+ if (present & 0x080000)
+ in_uint16_le(s, os->x);
+
+ if (present & 0x100000)
+ in_uint16_le(s, os->y);
+
+ if (present & 0x200000)
+ {
+ in_uint8(s, os->length);
+ in_uint8a(s, os->text, os->length);
+ }
+
+ DEBUG(("TEXT2(x=%d,y=%d,cl=%d,ct=%d,cr=%d,cb=%d,bl=%d,bt=%d,bb=%d,br=%d,fg=0x%x,bg=0x%x,font=%d,fl=0x%x,mix=%d,unk=0x%x,n=%d)\n", os->x, os->y, os->clipleft, os->cliptop, os->clipright, os->clipbottom, os->boxleft, os->boxtop, os->boxright, os->boxbottom, os->fgcolour, os->bgcolour, os->font, os->flags, os->mixmode, os->unknown, os->length));
+
+ DEBUG(("Text: "));
+
+ for (i = 0; i < os->length; i++)
+ DEBUG(("%02x ", os->text[i]));
+
+ DEBUG(("\n"));
+
+ ui_draw_text(os->font, os->flags, os->mixmode, os->x, os->y,
+ os->clipleft, os->cliptop,
+ os->clipright - os->clipleft,
+ os->clipbottom - os->cliptop,
+ os->boxleft, os->boxtop,
+ os->boxright - os->boxleft,
+ os->boxbottom - os->boxtop, os->bgcolour, os->fgcolour, os->text, os->length);
+}
+
+/* Process a raw bitmap cache order */
+static void
+process_raw_bmpcache(STREAM s)
+{
+ HBITMAP bitmap;
+ uint16 cache_idx, bufsize;
+ uint8 cache_id, width, height, bpp, Bpp;
+ uint8 *data, *inverted;
+ int y;
+
+ in_uint8(s, cache_id);
+ in_uint8s(s, 1); /* pad */
+ in_uint8(s, width);
+ in_uint8(s, height);
+ in_uint8(s, bpp);
+ Bpp = (bpp + 7) / 8;
+ in_uint16_le(s, bufsize);
+ in_uint16_le(s, cache_idx);
+ in_uint8p(s, data, bufsize);
+
+ DEBUG(("RAW_BMPCACHE(cx=%d,cy=%d,id=%d,idx=%d)\n", width, height, cache_id, cache_idx));
+ inverted = (uint8*)xmalloc(width * height * Bpp);
+ for (y = 0; y < height; y++)
+ {
+ memcpy(&inverted[(height - y - 1) * (width * Bpp)], &data[y * (width * Bpp)],
+ width * Bpp);
+ }
+
+ bitmap = ui_create_bitmap(width, height, inverted);
+ xfree(inverted);
+ cache_put_bitmap(cache_id, cache_idx, bitmap);
+}
+
+/* Process a bitmap cache order */
+static void
+process_bmpcache(STREAM s)
+{
+ HBITMAP bitmap;
+ uint16 cache_idx, size;
+ uint8 cache_id, width, height, bpp, Bpp;
+ uint8 *data, *bmpdata;
+
+ in_uint8(s, cache_id);
+ in_uint8s(s, 1); /* pad */
+ in_uint8(s, width);
+ in_uint8(s, height);
+ in_uint8(s, bpp);
+ Bpp = (bpp + 7) / 8;
+ in_uint8s(s, 2); /* bufsize */
+ in_uint16_le(s, cache_idx);
+ in_uint8s(s, 2); /* pad */
+ in_uint16_le(s, size);
+ in_uint8s(s, 4); /* row_size, final_size */
+ in_uint8p(s, data, size);
+ DEBUG(("BMPCACHE(cx=%d,cy=%d,id=%d,idx=%d)\n", width, height, cache_id, cache_idx));
+ bmpdata = (uint8*)xmalloc(width * height * Bpp);
+ if (bitmap_decompress(bmpdata, width, height, data, size, Bpp))
+ {
+ bitmap = ui_create_bitmap(width, height, bmpdata);
+ cache_put_bitmap(cache_id, cache_idx, bitmap);
+ }
+ xfree(bmpdata);
+}
+
+/* Process a colourmap cache order */
+static void
+process_colcache(STREAM s)
+{
+ COLOURENTRY *entry;
+ COLOURMAP map;
+ HCOLOURMAP hmap;
+ uint8 cache_id;
+ int i;
+ in_uint8(s, cache_id);
+ in_uint16_le(s, map.ncolours);
+
+ map.colours = (COLOURENTRY*)xmalloc(3 * map.ncolours);
+
+ for (i = 0; i < map.ncolours; i++)
+ {
+ entry = &map.colours[i];
+ in_uint8(s, entry->blue);
+ in_uint8(s, entry->green);
+ in_uint8(s, entry->red);
+ in_uint8s(s, 1); /* pad */
+ }
+
+ DEBUG(("COLCACHE(id=%d,n=%d)\n", cache_id, map.ncolours));
+
+ hmap = ui_create_colourmap(&map);
+ ui_set_colourmap(hmap);
+
+ xfree(map.colours);
+}
+
+/* Process a font cache order */
+static void
+process_fontcache(STREAM s)
+{
+ HGLYPH bitmap;
+ uint8 font, nglyphs;
+ uint16 character, offset, baseline, width, height;
+ int i, datasize;
+ uint8 *data;
+
+ in_uint8(s, font);
+ in_uint8(s, nglyphs);
+
+ DEBUG(("FONTCACHE(font=%d,n=%d)\n", font, nglyphs));
+
+ for (i = 0; i < nglyphs; i++)
+ {
+ in_uint16_le(s, character);
+ in_uint16_le(s, offset);
+ in_uint16_le(s, baseline);
+ in_uint16_le(s, width);
+ in_uint16_le(s, height);
+
+ datasize = (height * ((width + 7) / 8) + 3) & ~3;
+ in_uint8p(s, data, datasize);
+
+ bitmap = ui_create_glyph(width, height, data);
+ cache_put_font(font, character, offset, baseline, width, height, bitmap);
+ }
+}
+
+/* Process a secondary order */
+static void
+process_secondary_order(STREAM s)
+{
+ uint16 length;
+ uint8 type;
+ uint8 *next_order;
+
+ in_uint16_le(s, length);
+ in_uint8s(s, 2); /* flags */
+ in_uint8(s, type);
+
+ next_order = s->p + length + 7;
+
+ switch (type)
+ {
+ case RDP_ORDER_RAW_BMPCACHE:
+ process_raw_bmpcache(s);
+ break;
+
+ case RDP_ORDER_COLCACHE:
+ process_colcache(s);
+ break;
+
+ case RDP_ORDER_BMPCACHE:
+ process_bmpcache(s);
+ break;
+
+ case RDP_ORDER_FONTCACHE:
+ process_fontcache(s);
+ break;
+
+ default:
+ unimpl("secondary order %d\n", type);
+ }
+
+ s->p = next_order;
+}
+
+/* Process an order PDU */
+void
+process_orders(STREAM s)
+{
+ RDP_ORDER_STATE *os = &order_state;
+ uint32 present;
+ uint16 num_orders;
+ uint8 order_flags;
+ int size, processed = 0;
+ BOOL delta;
+
+ in_uint8s(s, 2); /* pad */
+ in_uint16_le(s, num_orders);
+ in_uint8s(s, 2); /* pad */
+
+ while (processed < num_orders)
+ {
+ in_uint8(s, order_flags);
+
+ if (!(order_flags & RDP_ORDER_STANDARD))
+ {
+ error("order parsing failed\n");
+ break;
+ }
+
+ if (order_flags & RDP_ORDER_SECONDARY)
+ {
+ process_secondary_order(s);
+ }
+ else
+ {
+ if (order_flags & RDP_ORDER_CHANGE)
+ {
+ in_uint8(s, os->order_type);
+ }
+
+ switch (os->order_type)
+ {
+ case RDP_ORDER_TRIBLT:
+ case RDP_ORDER_TEXT2:
+ size = 3;
+ break;
+
+ case RDP_ORDER_PATBLT:
+ case RDP_ORDER_MEMBLT:
+ case RDP_ORDER_LINE:
+ size = 2;
+ break;
+
+ default:
+ size = 1;
+ }
+
+ rdp_in_present(s, &present, order_flags, size);
+
+ if (order_flags & RDP_ORDER_BOUNDS)
+ {
+ if (!(order_flags & RDP_ORDER_LASTBOUNDS))
+ rdp_parse_bounds(s, &os->bounds);
+
+ ui_set_clip(os->bounds.left,
+ os->bounds.top,
+ os->bounds.right -
+ os->bounds.left + 1,
+ os->bounds.bottom - os->bounds.top + 1);
+ }
+
+ delta = order_flags & RDP_ORDER_DELTA;
+
+ switch (os->order_type)
+ {
+ case RDP_ORDER_DESTBLT:
+ process_destblt(s, &os->destblt, present, delta);
+ break;
+
+ case RDP_ORDER_PATBLT:
+ process_patblt(s, &os->patblt, present, delta);
+ break;
+
+ case RDP_ORDER_SCREENBLT:
+ process_screenblt(s, &os->screenblt, present, delta);
+ break;
+
+ case RDP_ORDER_LINE:
+ process_line(s, &os->line, present, delta);
+ break;
+
+ case RDP_ORDER_RECT:
+ process_rect(s, &os->rect, present, delta);
+ break;
+
+ case RDP_ORDER_DESKSAVE:
+ process_desksave(s, &os->desksave, present, delta);
+ break;
+
+ case RDP_ORDER_MEMBLT:
+ process_memblt(s, &os->memblt, present, delta);
+ break;
+
+ case RDP_ORDER_TRIBLT:
+ process_triblt(s, &os->triblt, present, delta);
+ break;
+
+ case RDP_ORDER_POLYLINE:
+ process_polyline(s, &os->polyline, present, delta);
+ break;
+
+ case RDP_ORDER_TEXT2:
+ process_text2(s, &os->text2, present, delta);
+ break;
+
+ default:
+ unimpl("order %d\n", os->order_type);
+ return;
+ }
+
+ if (order_flags & RDP_ORDER_BOUNDS)
+ ui_reset_clip();
+ }
+
+ processed++;
+ }
+
+ if (s->p != next_packet)
+ error("%d bytes remaining\n", (int) (next_packet - s->p));
+}
+
+/* Reset order state */
+void
+reset_order_state(void)
+{
+ memset(&order_state, 0, sizeof(order_state));
+ order_state.order_type = RDP_ORDER_PATBLT;
+}
diff --git a/noncore/net/opierdesktop/orders.h b/noncore/net/opierdesktop/orders.h
new file mode 100644
index 0000000..be862c6
--- a/dev/null
+++ b/noncore/net/opierdesktop/orders.h
@@ -0,0 +1,286 @@
+/*
+ rdesktop: A Remote Desktop Protocol client.
+ RDP order processing
+ Copyright (C) Matthew Chapman 1999-2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#define RDP_ORDER_STANDARD 0x01
+#define RDP_ORDER_SECONDARY 0x02
+#define RDP_ORDER_BOUNDS 0x04
+#define RDP_ORDER_CHANGE 0x08
+#define RDP_ORDER_DELTA 0x10
+#define RDP_ORDER_LASTBOUNDS 0x20
+#define RDP_ORDER_SMALL 0x40
+#define RDP_ORDER_TINY 0x80
+
+enum RDP_ORDER_TYPE
+{
+ RDP_ORDER_DESTBLT = 0,
+ RDP_ORDER_PATBLT = 1,
+ RDP_ORDER_SCREENBLT = 2,
+ RDP_ORDER_LINE = 9,
+ RDP_ORDER_RECT = 10,
+ RDP_ORDER_DESKSAVE = 11,
+ RDP_ORDER_MEMBLT = 13,
+ RDP_ORDER_TRIBLT = 14,
+ RDP_ORDER_POLYLINE = 22,
+ RDP_ORDER_TEXT2 = 27
+};
+
+enum RDP_SECONDARY_ORDER_TYPE
+{
+ RDP_ORDER_RAW_BMPCACHE = 0,
+ RDP_ORDER_COLCACHE = 1,
+ RDP_ORDER_BMPCACHE = 2,
+ RDP_ORDER_FONTCACHE = 3
+};
+
+typedef struct _DESTBLT_ORDER
+{
+ sint16 x;
+ sint16 y;
+ sint16 cx;
+ sint16 cy;
+ uint8 opcode;
+
+}
+DESTBLT_ORDER;
+
+typedef struct _PATBLT_ORDER
+{
+ sint16 x;
+ sint16 y;
+ sint16 cx;
+ sint16 cy;
+ uint8 opcode;
+ uint32 bgcolour;
+ uint32 fgcolour;
+ BRUSH brush;
+
+}
+PATBLT_ORDER;
+
+typedef struct _SCREENBLT_ORDER
+{
+ sint16 x;
+ sint16 y;
+ sint16 cx;
+ sint16 cy;
+ uint8 opcode;
+ sint16 srcx;
+ sint16 srcy;
+
+}
+SCREENBLT_ORDER;
+
+typedef struct _LINE_ORDER
+{
+ uint16 mixmode;
+ sint16 startx;
+ sint16 starty;
+ sint16 endx;
+ sint16 endy;
+ uint32 bgcolour;
+ uint8 opcode;
+ PEN pen;
+
+}
+LINE_ORDER;
+
+typedef struct _RECT_ORDER
+{
+ sint16 x;
+ sint16 y;
+ sint16 cx;
+ sint16 cy;
+ uint32 colour;
+
+}
+RECT_ORDER;
+
+typedef struct _DESKSAVE_ORDER
+{
+ uint32 offset;
+ sint16 left;
+ sint16 top;
+ sint16 right;
+ sint16 bottom;
+ uint8 action;
+
+}
+DESKSAVE_ORDER;
+
+typedef struct _TRIBLT_ORDER
+{
+ uint8 colour_table;
+ uint8 cache_id;
+ sint16 x;
+ sint16 y;
+ sint16 cx;
+ sint16 cy;
+ uint8 opcode;
+ sint16 srcx;
+ sint16 srcy;
+ uint32 bgcolour;
+ uint32 fgcolour;
+ BRUSH brush;
+ uint16 cache_idx;
+ uint16 unknown;
+
+}
+TRIBLT_ORDER;
+
+typedef struct _MEMBLT_ORDER
+{
+ uint8 colour_table;
+ uint8 cache_id;
+ sint16 x;
+ sint16 y;
+ sint16 cx;
+ sint16 cy;
+ uint8 opcode;
+ sint16 srcx;
+ sint16 srcy;
+ uint16 cache_idx;
+
+}
+MEMBLT_ORDER;
+
+#define MAX_DATA 256
+
+typedef struct _POLYLINE_ORDER
+{
+ sint16 x;
+ sint16 y;
+ uint8 opcode;
+ uint32 fgcolour;
+ uint8 lines;
+ uint8 datasize;
+ uint8 data[MAX_DATA];
+
+}
+POLYLINE_ORDER;
+
+#define MAX_TEXT 256
+
+typedef struct _TEXT2_ORDER
+{
+ uint8 font;
+ uint8 flags;
+ uint8 mixmode;
+ uint8 unknown;
+ uint32 fgcolour;
+ uint32 bgcolour;
+ sint16 clipleft;
+ sint16 cliptop;
+ sint16 clipright;
+ sint16 clipbottom;
+ sint16 boxleft;
+ sint16 boxtop;
+ sint16 boxright;
+ sint16 boxbottom;
+ sint16 x;
+ sint16 y;
+ uint8 length;
+ uint8 text[MAX_TEXT];
+
+}
+TEXT2_ORDER;
+
+typedef struct _RDP_ORDER_STATE
+{
+ uint8 order_type;
+ BOUNDS bounds;
+
+ DESTBLT_ORDER destblt;
+ PATBLT_ORDER patblt;
+ SCREENBLT_ORDER screenblt;
+ LINE_ORDER line;
+ RECT_ORDER rect;
+ DESKSAVE_ORDER desksave;
+ MEMBLT_ORDER memblt;
+ TRIBLT_ORDER triblt;
+ POLYLINE_ORDER polyline;
+ TEXT2_ORDER text2;
+
+}
+RDP_ORDER_STATE;
+
+typedef struct _RDP_RAW_BMPCACHE_ORDER
+{
+ uint8 cache_id;
+ uint8 pad1;
+ uint8 width;
+ uint8 height;
+ uint8 bpp;
+ uint16 bufsize;
+ uint16 cache_idx;
+ uint8 *data;
+
+}
+RDP_RAW_BMPCACHE_ORDER;
+
+typedef struct _RDP_BMPCACHE_ORDER
+{
+ uint8 cache_id;
+ uint8 pad1;
+ uint8 width;
+ uint8 height;
+ uint8 bpp;
+ uint16 bufsize;
+ uint16 cache_idx;
+ uint16 pad2;
+ uint16 size;
+ uint16 row_size;
+ uint16 final_size;
+ uint8 *data;
+
+}
+RDP_BMPCACHE_ORDER;
+
+#define MAX_GLYPH 32
+
+typedef struct _RDP_FONT_GLYPH
+{
+ uint16 character;
+ uint16 unknown;
+ uint16 baseline;
+ uint16 width;
+ uint16 height;
+ uint8 data[MAX_GLYPH];
+
+}
+RDP_FONT_GLYPH;
+
+#define MAX_GLYPHS 256
+
+typedef struct _RDP_FONTCACHE_ORDER
+{
+ uint8 font;
+ uint8 nglyphs;
+ RDP_FONT_GLYPH glyphs[MAX_GLYPHS];
+
+}
+RDP_FONTCACHE_ORDER;
+
+typedef struct _RDP_COLCACHE_ORDER
+{
+ uint8 cache_id;
+ COLOURMAP map;
+
+}
+RDP_COLCACHE_ORDER;
diff --git a/noncore/net/opierdesktop/parse.h b/noncore/net/opierdesktop/parse.h
new file mode 100644
index 0000000..f54c05f
--- a/dev/null
+++ b/noncore/net/opierdesktop/parse.h
@@ -0,0 +1,108 @@
+/*
+ rdesktop: A Remote Desktop Protocol client.
+ Parsing primitives
+ Copyright (C) Matthew Chapman 1999-2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* Parser state */
+typedef struct stream
+{
+ unsigned char *p;
+ unsigned char *end;
+ unsigned char *data;
+ unsigned int size;
+// unsigned char *next_packet;
+
+
+ /* Offsets of various headers */
+ unsigned char *iso_hdr;
+ unsigned char *mcs_hdr;
+ unsigned char *sec_hdr;
+ unsigned char *rdp_hdr;
+
+}
+ *STREAM;
+
+#define s_push_layer(s,h,n) { (s)->h = (s)->p; (s)->p += n; }
+#define s_pop_layer(s,h) (s)->p = (s)->h;
+#define s_mark_end(s) (s)->end = (s)->p;
+#define s_check(s) ((s)->p <= (s)->end)
+#define s_check_rem(s,n) ((s)->p + n <= (s)->end)
+#define s_check_end(s) ((s)->p == (s)->end)
+
+#if defined(L_ENDIAN) && !defined(NEED_ALIGN)
+#define in_uint16_le(s,v) { v = *(uint16 *)((s)->p); (s)->p += 2; }
+#define in_uint32_le(s,v) { v = *(uint32 *)((s)->p); (s)->p += 4; }
+#define out_uint16_le(s,v) { *(uint16 *)((s)->p) = v; (s)->p += 2; }
+#define out_uint32_le(s,v) { *(uint32 *)((s)->p) = v; (s)->p += 4; }
+
+#else
+#define in_uint16_le(s,v) { v = *((s)->p++); v += *((s)->p++) << 8; }
+#define in_uint32_le(s,v) { in_uint16_le(s,v) \
+ v += *((s)->p++) << 16; v += *((s)->p++) << 24; }
+#define out_uint16_le(s,v) { *((s)->p++) = (v) & 0xff; *((s)->p++) = ((v) >> 8) & 0xff; }
+#define out_uint32_le(s,v) { out_uint16_le(s, (v) & 0xffff); out_uint16_le(s, ((v) >> 16) & 0xffff); }
+#endif
+
+#if defined(B_ENDIAN) && !defined(NEED_ALIGN)
+#define in_uint16_be(s,v) { v = *(uint16 *)((s)->p); (s)->p += 2; }
+#define in_uint32_be(s,v) { v = *(uint32 *)((s)->p); (s)->p += 4; }
+#define out_uint16_be(s,v) { *(uint16 *)((s)->p) = v; (s)->p += 2; }
+#define out_uint32_be(s,v) { *(uint32 *)((s)->p) = v; (s)->p += 4; }
+
+#define B_ENDIAN_PREFERRED
+#define in_uint16(s,v) in_uint16_be(s,v)
+#define in_uint32(s,v) in_uint32_be(s,v)
+#define out_uint16(s,v) out_uint16_be(s,v)
+#define out_uint32(s,v) out_uint32_be(s,v)
+
+#else
+#define next_be(s,v) v = ((v) << 8) + *((s)->p++);
+#define in_uint16_be(s,v) { v = *((s)->p++); next_be(s,v); }
+#define in_uint32_be(s,v) { in_uint16_be(s,v); next_be(s,v); next_be(s,v); }
+#define out_uint16_be(s,v) { *((s)->p++) = ((v) >> 8) & 0xff; *((s)->p++) = (v) & 0xff; }
+#define out_uint32_be(s,v) { out_uint16_be(s, ((v) >> 16) & 0xffff); out_uint16_be(s, (v) & 0xffff); }
+#endif
+
+#ifndef B_ENDIAN_PREFERRED
+#define in_uint16(s,v) in_uint16_le(s,v)
+#define in_uint32(s,v) in_uint32_le(s,v)
+#define out_uint16(s,v) out_uint16_le(s,v)
+#define out_uint32(s,v) out_uint32_le(s,v)
+#endif
+
+#define in_uint8(s,v) v = *((s)->p++);
+#define in_uint8p(s,v,n) { v = (s)->p; (s)->p += n; }
+#define in_uint8a(s,v,n) { memcpy(v,(s)->p,n); (s)->p += n; }
+#define in_uint8s(s,n) (s)->p += n;
+#define out_uint8(s,v) *((s)->p++) = v;
+#define out_uint8p(s,v,n) { memcpy((s)->p,v,n); (s)->p += n; }
+#define out_uint8a(s,v,n) out_uint8p(s,v,n);
+#define out_uint8s(s,n) { memset((s)->p,0,n); (s)->p += n; }
+
+#if defined(B_ENDIAN)
+
+#endif
+#if defined(B_ENDIAN_PREFERRED)
+
+#endif
+#if defined(NEED_ALIGN)
+
+#endif
+#if defined(L_ENDIAN)
+
+#endif
diff --git a/noncore/net/opierdesktop/proto.h b/noncore/net/opierdesktop/proto.h
new file mode 100644
index 0000000..6bc5b13
--- a/dev/null
+++ b/noncore/net/opierdesktop/proto.h
@@ -0,0 +1,121 @@
+/* bitmap.c */
+BOOL bitmap_decompress(unsigned char *output, int width, int height, unsigned char *input, int size,
+ int Bpp);
+/* cache.c */
+HBITMAP cache_get_bitmap(uint8 cache_id, uint16 cache_idx);
+void cache_put_bitmap(uint8 cache_id, uint16 cache_idx, HBITMAP bitmap);
+FONTGLYPH *cache_get_font(uint8 font, uint16 character);
+void cache_put_font(uint8 font, uint16 character, uint16 offset, uint16 baseline, uint16 width,
+ uint16 height, HGLYPH pixmap);
+DATABLOB *cache_get_text(uint8 cache_id);
+void cache_put_text(uint8 cache_id, void *data, int length);
+uint8 *cache_get_desktop(uint32 offset, int cx, int cy, int bytes_per_pixel);
+void cache_put_desktop(uint32 offset, int cx, int cy, int scanline, int bytes_per_pixel,
+ uint8 * data);
+HCURSOR cache_get_cursor(uint16 cache_idx);
+void cache_put_cursor(uint16 cache_idx, HCURSOR cursor);
+/* ewmhints.c */
+int get_current_workarea(uint32 * x, uint32 * y, uint32 * width, uint32 * height);
+/* iso.c */
+STREAM iso_init(int length);
+void iso_send(STREAM s);
+STREAM iso_recv(void);
+BOOL iso_connect(char *server);
+void iso_disconnect(void);
+/* licence.c */
+void licence_process(STREAM s);
+/* mcs.c */
+STREAM mcs_init(int length);
+void mcs_send(STREAM s);
+STREAM mcs_recv(void);
+BOOL mcs_connect(char *server, STREAM mcs_data);
+void mcs_disconnect(void);
+/* orders.c */
+void process_orders(STREAM s);
+void reset_order_state(void);
+/* rdesktop.c */
+int main(int argc, char *argv[]);
+void generate_random(uint8 * random);
+void *xmalloc(int size);
+void *xrealloc(void *oldmem, int size);
+void xfree(void *mem);
+void error(char *format, ...);
+void warning(char *format, ...);
+void unimpl(char *format, ...);
+void hexdump(unsigned char *p, unsigned int len);
+int load_licence(unsigned char **data);
+void save_licence(unsigned char *data, int length);
+/* rdp.c */
+void rdp_out_unistr(STREAM s, char *string, int len);
+void rdp_send_input(uint32 time, uint16 message_type, uint16 device_flags, uint16 param1,
+ uint16 param2);
+BOOL rdp_main_loop(void);
+BOOL rdp_connect(char *server, uint32 flags, char *domain, char *password, char *command,
+ char *directory);
+void rdp_disconnect(void);
+/* secure.c */
+void sec_hash_48(uint8 * out, uint8 * in, uint8 * salt1, uint8 * salt2, uint8 salt);
+void sec_hash_16(uint8 * out, uint8 * in, uint8 * salt1, uint8 * salt2);
+void buf_out_uint32(uint8 * buffer, uint32 value);
+void sec_sign(uint8 * signature, int siglen, uint8 * session_key, int keylen, uint8 * data,
+ int datalen);
+STREAM sec_init(uint32 flags, int maxlen);
+void sec_send(STREAM s, uint32 flags);
+STREAM sec_recv(void);
+BOOL sec_connect(char *server);
+void sec_disconnect(void);
+/* tcp.c */
+STREAM tcp_init(unsigned int maxlen);
+void tcp_send(STREAM s);
+STREAM tcp_recv(unsigned int length);
+BOOL tcp_connect(char *server);
+void tcp_disconnect(void);
+/* xkeymap.c */
+void xkeymap_init(void);
+BOOL handle_special_keys(uint32 keysym, unsigned int state, uint32 ev_time, BOOL pressed);
+key_translation xkeymap_translate_key(uint32 keysym, unsigned int keycode, unsigned int state);
+uint16 xkeymap_translate_button(unsigned int button);
+char *get_ksname(uint32 keysym);
+void ensure_remote_modifiers(uint32 ev_time, key_translation tr);
+void reset_modifier_keys(unsigned int state);
+void rdp_send_scancode(uint32 time, uint16 flags, uint8 scancode);
+/* xwin.c */
+BOOL get_key_state(unsigned int state, uint32 keysym);
+BOOL ui_init(void);
+void ui_deinit(void);
+BOOL ui_create_window(void);
+void ui_destroy_window(void);
+void xwin_toggle_fullscreen(void);
+int ui_select(int rdp_socket);
+void ui_move_pointer(int x, int y);
+HBITMAP ui_create_bitmap(int width, int height, uint8 * data);
+void ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * data);
+void ui_destroy_bitmap(HBITMAP bmp);
+HGLYPH ui_create_glyph(int width, int height, uint8 * data);
+void ui_destroy_glyph(HGLYPH glyph);
+HCURSOR ui_create_cursor(unsigned int x, unsigned int y, int width, int height, uint8 * andmask,
+ uint8 * xormask);
+void ui_set_cursor(HCURSOR cursor);
+void ui_destroy_cursor(HCURSOR cursor);
+HCOLOURMAP ui_create_colourmap(COLOURMAP * colours);
+void ui_destroy_colourmap(HCOLOURMAP map);
+void ui_set_colourmap(HCOLOURMAP map);
+void ui_begin_update(void);
+void ui_end_update(void);
+void ui_set_clip(int x, int y, int cx, int cy);
+void ui_reset_clip(void);
+void ui_bell(void);
+void ui_destblt(uint8 opcode, int x, int y, int cx, int cy);
+void ui_patblt(uint8 opcode, int x, int y, int cx, int cy, BRUSH * brush, int bgcolour,
+ int fgcolour);
+void ui_screenblt(uint8 opcode, int x, int y, int cx, int cy, int srcx, int srcy);
+void ui_memblt(uint8 opcode, int x, int y, int cx, int cy, HBITMAP src, int srcx, int srcy);
+void ui_triblt(uint8 opcode, int x, int y, int cx, int cy, HBITMAP src, int srcx, int srcy,
+ BRUSH * brush, int bgcolour, int fgcolour);
+void ui_line(uint8 opcode, int startx, int starty, int endx, int endy, PEN * pen);
+void ui_rect(int x, int y, int cx, int cy, int colour);
+void ui_draw_text(uint8 font, uint8 flags, int mixmode, int x, int y, int clipx, int clipy,
+ int clipcx, int clipcy, int boxx, int boxy, int boxcx, int boxcy, int bgcolour,
+ int fgcolour, uint8 * text, uint8 length);
+void ui_desktop_save(uint32 offset, int x, int y, int cx, int cy);
+void ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy);
diff --git a/noncore/net/opierdesktop/qtwin.cpp b/noncore/net/opierdesktop/qtwin.cpp
new file mode 100644
index 0000000..d2a5ef1
--- a/dev/null
+++ b/noncore/net/opierdesktop/qtwin.cpp
@@ -0,0 +1,1725 @@
+/*
+ rdesktop: A Remote Desktop Protocol client.
+ User interface services - X Window System
+ Copyright (C) Matthew Chapman 1999-2002
+ qt.cpp by Jay Sorg
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "rdesktop.h"
+#ifdef SHARP
+#include <qpe/qpeapplication.h>
+#else
+#include <qapplication.h>
+#endif
+#include <qmainwindow.h>
+#include <qwidget.h>
+#include <qpainter.h>
+#include <qimage.h>
+#include <qsocketnotifier.h>
+#include <qscrollview.h>
+#include <qmessagebox.h>
+#include <qpushbutton.h>
+#include <qlineedit.h>
+#include <qcombobox.h>
+#include <qlabel.h>
+#include <qfile.h>
+#include <qcheckbox.h>
+#include <qpopupmenu.h>
+#include "qtwin.h"
+#include <stdlib.h>
+
+uint32 flags;
+char server[64] = "";
+char domain[16] = "";
+char password[16] = "";
+char shell[128] = "";
+char directory[32] = "";
+
+extern int g_width;
+extern int g_height;
+extern int server_bpp;
+extern BOOL fullscreen;
+extern char username[];
+int global_sock;
+
+QSocketNotifier* SocketNotifier;
+#ifdef SHARP
+QPEApplication* App;
+#else
+QApplication* App;
+#endif
+QMyMainWindow* MW;
+QMyScrollView* SV;
+struct QColorMap
+{
+ uint32 RGBColors[256];
+ int NumColors;
+};
+QColorMap* CM;
+uint8* BS;
+int clipx;
+int clipy;
+int clipcx;
+int clipcy;
+
+struct bitmap
+{
+ int w;
+ int h;
+ uint8* data;
+};
+
+BOOL owncolmap = False;
+
+//*****************************************************************************
+void CleanString(QString* Item)
+{
+ int i;
+
+ i = Item->length() - 1;
+ while (i >= 0)
+ {
+ if (Item->at(i) == 10 || Item->at(i) == 13)
+ Item->remove(i, 1);
+ i--;
+ }
+}
+
+//*****************************************************************************
+QMyDialog::QMyDialog(QWidget* parent) : QDialog(parent, "Settings", true)
+{
+ int i, j;
+ char* home;
+ char Text[256];
+ QString Line;
+ QString ItemName;
+ QString ItemValue;
+
+ // resize dialog
+ resize(230, 270);
+ // main list box
+ ListBox = new QListBox(this);
+ ListBox->move(10, 10);
+ ListBox->resize(200, 100);
+ connect(ListBox, SIGNAL(selectionChanged()), this, SLOT(ListBoxChanged()));
+ connect(ListBox, SIGNAL(selected(int)), this, SLOT(ListBoxSelected(int)));
+ // server
+ Label1 = new QLabel(this);
+ Label1->setText("Server Desc");
+ Label1->move(10, 120);
+ Label1->resize(100, 20);
+ ServerNameEdit = new QLineEdit(this);
+ ServerNameEdit->move(75, 120);
+ ServerNameEdit->resize(100, 20);
+ // username
+ Label2 = new QLabel(this);
+ Label2->setText("User Name");
+ Label2->move(10, 150);
+ Label2->resize(100, 20);
+ UserNameEdit = new QLineEdit(this);
+ UserNameEdit->move(75, 150);
+ UserNameEdit->resize(100, 20);
+ // ip
+ Label3 = new QLabel(this);
+ Label3->setText("Server IP");
+ Label3->move(10, 180);
+ Label3->resize(100, 20);
+ IPEdit = new QLineEdit(this);
+ IPEdit->move(75, 180);
+ IPEdit->resize(100, 20);
+ // width and height
+ WidthHeightBox = new QComboBox(this);
+ WidthHeightBox->move(10, 210);
+ WidthHeightBox->resize(100, 20);
+ WidthHeightBox->insertItem("240x320");
+ WidthHeightBox->insertItem("640x480");
+ WidthHeightBox->insertItem("800x600");
+ connect(WidthHeightBox, SIGNAL(activated(int)), this, SLOT(ComboChanged(int)));
+ WidthHeightBox->setCurrentItem(1);
+ WidthEdit = new QLineEdit(this);
+ WidthEdit->move(110, 210);
+ WidthEdit->resize(30, 20);
+ WidthEdit->setText("800");
+ HeightEdit = new QLineEdit(this);
+ HeightEdit->move(140, 210);
+ HeightEdit->resize(30, 20);
+ HeightEdit->setText("600");
+ // add to list button
+ AddButton = new QPushButton(this);
+ AddButton->move(180, 120);
+ AddButton->resize(50, 20);
+ AddButton->setText("Add");
+ connect(AddButton, SIGNAL(clicked()), this, SLOT(AddClicked()));
+ // change list item button
+ EditButton = new QPushButton(this);
+ EditButton->move(180, 140);
+ EditButton->resize(50, 20);
+ EditButton->setText("Edit");
+ connect(EditButton, SIGNAL(clicked()), this, SLOT(EditClicked()));
+ // save to file button
+ SaveButton = new QPushButton(this);
+ SaveButton->move(180, 160);
+ SaveButton->resize(50, 20);
+ SaveButton->setText("Save");
+ connect(SaveButton, SIGNAL(clicked()), this, SLOT(SaveClicked()));
+ // remove an item button
+ RemoveButton = new QPushButton(this);
+ RemoveButton->move(180, 180);
+ RemoveButton->resize(50, 20);
+ RemoveButton->setText("Remove");
+ connect(RemoveButton, SIGNAL(clicked()), this, SLOT(RemoveClicked()));
+ // full screen check box
+ FullScreenCheckBox = new QCheckBox(this, "Full Screen");
+ FullScreenCheckBox->setText("Full Screen");
+ FullScreenCheckBox->move(10, 230);
+ // ok button
+ OKButton = new QPushButton(this);
+ OKButton->setText("OK");
+ OKButton->move(100, 240);
+ OKButton->resize(50, 20);
+ connect(OKButton, SIGNAL(clicked()), this, SLOT(OKClicked()));
+ // cancel button
+ CancelButton = new QPushButton(this);
+ CancelButton->setText("Cancel");
+ CancelButton->move(160, 240);
+ CancelButton->resize(50, 20);
+ connect(CancelButton, SIGNAL(clicked()), this, SLOT(CancelClicked()));
+
+ for (i = 0; i < 10; i++)
+ {
+ ConnectionList[i] = new QMyConnectionItem;
+ ConnectionList[i]->ServerName = "";
+ ConnectionList[i]->UserName = "";
+ ConnectionList[i]->ServerIP = "";
+ ConnectionList[i]->Width = 0;
+ ConnectionList[i]->Height = 0;
+ ConnectionList[i]->FullScreen = 0;
+ }
+ home = getenv("HOME");
+ if (home != NULL)
+ {
+ sprintf(Text, "%s/rdesktop.ini", home);
+ QFile* File = new QFile(Text);
+ if (File->open(IO_ReadOnly))
+ {
+ i = -1;
+ while (!File->atEnd())
+ {
+ File->readLine(Line, 255);
+ j = Line.find("=");
+ if (j > 0)
+ {
+ ItemName = Line.mid(0, j);
+ CleanString(&ItemName);
+ ItemValue = Line.mid(j + 1);
+ CleanString(&ItemValue);
+ if (ItemName == "Server")
+ {
+ i++;
+ ConnectionList[i]->ServerName = ItemValue;
+ ListBox->insertItem(ItemValue);
+ }
+ else if (ItemName == "UserName")
+ ConnectionList[i]->UserName = ItemValue;
+ else if (ItemName == "Width")
+ ConnectionList[i]->Width = ItemValue.toInt();
+ else if (ItemName == "Height")
+ ConnectionList[i]->Height = ItemValue.toInt();
+ else if (ItemName == "IP")
+ ConnectionList[i]->ServerIP = ItemValue;
+ else if (ItemName == "FullScreen")
+ ConnectionList[i]->FullScreen = (ItemValue != "0");
+ }
+ }
+ }
+ delete File;
+ }
+}
+
+//*****************************************************************************
+QMyDialog::~QMyDialog()
+{
+ QMyConnectionItem* Item;
+ int i;
+
+ for (i = 0; i < 10; i++)
+ {
+ Item = ConnectionList[i];
+ delete Item;
+ }
+}
+
+//*****************************************************************************
+void QMyDialog::ComboChanged(int index)
+{
+ if (index == 0)
+ {
+ WidthEdit->setText("240");
+ HeightEdit->setText("320");
+ }
+ if (index == 1)
+ {
+ WidthEdit->setText("640");
+ HeightEdit->setText("480");
+ }
+ else if (index == 2)
+ {
+ WidthEdit->setText("800");
+ HeightEdit->setText("600");
+ }
+}
+
+//*****************************************************************************
+void QMyDialog::OKClicked()
+{
+ ServerName = ServerNameEdit->text();
+ UserName = UserNameEdit->text();
+ Width = WidthEdit->text().toInt();
+ Height = HeightEdit->text().toInt();
+ ServerIP = IPEdit->text();
+ FullScreen = FullScreenCheckBox->isChecked();
+ done(1);
+}
+
+//*****************************************************************************
+void QMyDialog::CancelClicked()
+{
+ done(0);
+}
+
+//*****************************************************************************
+void QMyDialog::AddClicked()
+{
+ int i;
+ QMyConnectionItem* Item;
+
+ i = ListBox->count();
+ if (i < 10)
+ {
+ ListBox->insertItem(ServerNameEdit->text());
+ Item = ConnectionList[i];
+ Item->ServerName = ServerNameEdit->text();
+ Item->UserName = UserNameEdit->text();
+ Item->Width = WidthEdit->text().toInt();
+ Item->Height = HeightEdit->text().toInt();
+ Item->ServerIP = IPEdit->text();
+ Item->FullScreen = FullScreenCheckBox->isChecked();
+ }
+}
+
+//*****************************************************************************
+void QMyDialog::EditClicked()
+{
+ int i;
+ QMyConnectionItem* Item;
+
+ i = ListBox->currentItem();
+ if (i >= 0)
+ {
+ Item = ConnectionList[i];
+ Item->ServerName = ServerNameEdit->text();
+ Item->UserName = UserNameEdit->text();
+ Item->Width = WidthEdit->text().toInt();
+ Item->Height = HeightEdit->text().toInt();
+ Item->ServerIP = IPEdit->text();
+ Item->FullScreen = FullScreenCheckBox->isChecked();
+ ListBox->changeItem(ServerNameEdit->text(), i);
+ }
+}
+
+//*****************************************************************************
+void WriteString(QFile* File, QString* Line)
+{
+ File->writeBlock((const char*)(*Line), Line->length());
+}
+
+//*****************************************************************************
+void QMyDialog::SaveClicked()
+{
+ int i, j;
+ QMyConnectionItem* Item;
+ QString Line;
+ char* home;
+ char Text[256];
+ QFile* File;
+
+ home = getenv("HOME");
+ if (home != NULL)
+ {
+ sprintf(Text, "%s/rdesktop.ini", home);
+ File = new QFile(Text);
+ if (File->open(IO_Truncate | IO_ReadWrite))
+ {
+ i = ListBox->count();
+ for (j = 0; j < i; j++)
+ {
+ Item = ConnectionList[j];
+ Line = "Server=";
+ Line += Item->ServerName;
+ Line += (char)10;
+ WriteString(File, &Line);
+ Line = "UserName=";
+ Line += Item->UserName;
+ Line += (char)10;
+ WriteString(File, &Line);
+ Line = "Width=";
+ sprintf(Text, "%d", Item->Width);
+ Line += Text;
+ Line += (char)10;
+ WriteString(File, &Line);
+ Line = "Height=";
+ sprintf(Text, "%d", Item->Height);
+ Line += Text;
+ Line += (char)10;
+ WriteString(File, &Line);
+ Line = "IP=";
+ Line += Item->ServerIP;
+ Line += (char)10;
+ WriteString(File, &Line);
+ Line = "FullScreen=";
+ if (Item->FullScreen)
+ Line += "1";
+ else
+ Line += "0";
+ Line += (char)10;
+ WriteString(File, &Line);
+ }
+ }
+ File->flush();
+ File->close();
+ delete File;
+ }
+}
+
+//*****************************************************************************
+void QMyDialog::RemoveClicked()
+{
+ int i, j, c;
+ QMyConnectionItem* Item1;
+ QMyConnectionItem* Item2;
+
+ i = ListBox->currentItem();
+ if (i >= 0)
+ {
+ c = ListBox->count();
+ for (j = i; j < c - 1; j++)
+ {
+ Item1 = ConnectionList[i];
+ Item2 = ConnectionList[i + 1];
+ Item1->ServerName = Item2->ServerName;
+ Item1->UserName = Item2->UserName;
+ Item1->Width = Item2->Width;
+ Item1->Height = Item2->Height;
+ Item1->ServerIP = Item2->ServerIP;
+ Item1->FullScreen = Item2->FullScreen;
+ }
+ ListBox->removeItem(i);
+ }
+}
+
+//*****************************************************************************
+void QMyDialog::ListBoxChanged()
+{
+ int i;
+ QMyConnectionItem* Item;
+ char Text[100];
+
+ i = ListBox->currentItem();
+ if (i >= 0 && i < 10)
+ {
+ Item = ConnectionList[i];
+ ServerNameEdit->setText(Item->ServerName);
+ UserNameEdit->setText(Item->UserName);
+ sprintf(Text, "%d", Item->Width);
+ WidthEdit->setText(Text);
+ sprintf(Text, "%d", Item->Height);
+ HeightEdit->setText(Text);
+ IPEdit->setText(Item->ServerIP);
+ FullScreenCheckBox->setChecked(Item->FullScreen != 0);
+ }
+}
+
+//*****************************************************************************
+void QMyDialog::ListBoxSelected(int /*index*/)
+{
+}
+
+//*****************************************************************************
+void GetScanCode(QKeyEvent* e, int* ScanCode, int* code)
+{
+ int key;
+ int mod;
+ int ascii;
+
+ key = e->key();
+ mod = e->state();
+ ascii = e->ascii();
+
+ *ScanCode = 0;
+ *code = mod; // 8 shift, 16 control, 32 alt
+
+ switch (key)
+ {
+ case 4096: // esc
+ case 4097: // tab
+ case 4099: // backspace
+ case 4100: // enter
+ case 4101: // enter
+ case 4103: // delete
+ ascii = 0;
+ }
+
+ if (ascii == 0)
+ {
+ switch (key)
+ {
+ case 4096: *ScanCode = 0x01; break; // esc
+ case 4097: *ScanCode = 0x0f; break; // tab
+ case 4099: *ScanCode = 0x0e; break; // backspace
+ case 4100: *ScanCode = 0x1c; break; // enter
+ case 4101: *ScanCode = 0x1c; break; // enter
+ case 4112: *ScanCode = 0xc7; break; // home
+ case 4113: *ScanCode = 0xcf; break; // end
+ case 4102: *ScanCode = 0xd2; break; // insert
+ case 4103: *ScanCode = 0xd3; break; // delete
+ case 4118: *ScanCode = 0xc9; break; // page up
+ case 4119: *ScanCode = 0xd1; break; // page down
+ case 4117: *ScanCode = 0xd0; break; // down arrow
+ case 4115: *ScanCode = 0xc8; break; // up arrow
+ case 4114: *ScanCode = 0xcb; break; // left arrow
+ case 4116: *ScanCode = 0xcd; break; // right arrow
+ case 4128: *ScanCode = 0x2a; break; // shift
+ case 4131: *ScanCode = 0x38; break; // alt
+ case 4129: *ScanCode = 0x1d; break; // ctrl
+ }
+ if (*ScanCode != 0)
+ return;
+ }
+
+ switch (ascii)
+ {
+ // first row
+ case 'q': *ScanCode = 0x10; break;
+ case 'Q': *ScanCode = 0x10; *code |= 8; break;
+ case '1': *ScanCode = 0x02; break;
+ case 'w': *ScanCode = 0x11; break;
+ case 'W': *ScanCode = 0x11; *code |= 8; break;
+ case '2': *ScanCode = 0x03; break;
+ case 'e': *ScanCode = 0x12; break;
+ case 'E': *ScanCode = 0x12; *code |= 8; break;
+ case '3': *ScanCode = 0x04; break;
+ case 'r': *ScanCode = 0x13; break;
+ case 'R': *ScanCode = 0x13; *code |= 8; break;
+ case '4': *ScanCode = 0x05; break;
+ case 't': *ScanCode = 0x14; break;
+ case 'T': *ScanCode = 0x14; *code |= 8; break;
+ case '5': *ScanCode = 0x06; break;
+ case 'y': *ScanCode = 0x15; break;
+ case 'Y': *ScanCode = 0x15; *code |= 8; break;
+ case '6': *ScanCode = 0x07; break;
+ case 'u': *ScanCode = 0x16; break;
+ case 'U': *ScanCode = 0x16; *code |= 8; break;
+ case '7': *ScanCode = 0x08; break;
+ case 'i': *ScanCode = 0x17; break;
+ case 'I': *ScanCode = 0x17; *code |= 8; break;
+ case '8': *ScanCode = 0x09; break;
+ case 'o': *ScanCode = 0x18; break;
+ case 'O': *ScanCode = 0x18; *code |= 8; break;
+ case '9': *ScanCode = 0x0a; break;
+ case 'p': *ScanCode = 0x19; break;
+ case 'P': *ScanCode = 0x19; *code |= 8; break;
+ case '0': *ScanCode = 0x0b; break;
+ // second row
+ case 'a': *ScanCode = 0x1e; break;
+ case 'A': *ScanCode = 0x1e; *code |= 8; break;
+ case '!': *ScanCode = 0x02; *code |= 8; break;
+ case 's': *ScanCode = 0x1f; break;
+ case 'S': *ScanCode = 0x1f; *code |= 8; break;
+ case '@': *ScanCode = 0x03; *code |= 8; break;
+ case 'd': *ScanCode = 0x20; break;
+ case 'D': *ScanCode = 0x20; *code |= 8; break;
+ case '#': *ScanCode = 0x04; *code |= 8; break;
+ case 'f': *ScanCode = 0x21; break;
+ case 'F': *ScanCode = 0x21; *code |= 8; break;
+ case '$': *ScanCode = 0x05; *code |= 8; break;
+ case 'g': *ScanCode = 0x22; break;
+ case 'G': *ScanCode = 0x22; *code |= 8; break;
+ case '%': *ScanCode = 0x06; *code |= 8; break;
+ case 'h': *ScanCode = 0x23; break;
+ case 'H': *ScanCode = 0x23; *code |= 8; break;
+ case '_': *ScanCode = 0x0c; *code |= 8; break;
+ case 'j': *ScanCode = 0x24; break;
+ case 'J': *ScanCode = 0x24; *code |= 8; break;
+ case '&': *ScanCode = 0x08; *code |= 8; break;
+ case 'k': *ScanCode = 0x25; break;
+ case 'K': *ScanCode = 0x25; *code |= 8; break;
+ case '*': *ScanCode = 0x09; *code |= 8; break;
+ case 'l': *ScanCode = 0x26; break;
+ case 'L': *ScanCode = 0x26; *code |= 8; break;
+ case '(': *ScanCode = 0x0a; *code |= 8; break;
+// case 8: *ScanCode = 0x0e; break; // backspace
+ // third row
+ case 'z': *ScanCode = 0x2c; break;
+ case 'Z': *ScanCode = 0x2c; *code |= 8; break;
+ case 'x': *ScanCode = 0x2d; break;
+ case 'X': *ScanCode = 0x2d; *code |= 8; break;
+ case 'c': *ScanCode = 0x2e; break;
+ case 'C': *ScanCode = 0x2e; *code |= 8; break;
+ case 'v': *ScanCode = 0x2f; break;
+ case 'V': *ScanCode = 0x2f; *code |= 8; break;
+ case 'b': *ScanCode = 0x30; break;
+ case 'B': *ScanCode = 0x30; *code |= 8; break;
+ case '-': *ScanCode = 0x0c; break;
+ case 'n': *ScanCode = 0x31; break;
+ case 'N': *ScanCode = 0x31; *code |= 8; break;
+ case '+': *ScanCode = 0x0d; *code |= 8; break;
+ case 'm': *ScanCode = 0x32; break;
+ case 'M': *ScanCode = 0x32; *code |= 8; break;
+ case '=': *ScanCode = 0x0d; break;
+ case ',': *ScanCode = 0x33; break;
+ case ';': *ScanCode = 0x27; break;
+ case ')': *ScanCode = 0x0b; *code |= 8; break;
+ // fourth row
+// case 9: *ScanCode = 0x0f; break; // tab
+ case '/': *ScanCode = 0x35; break;
+ case '?': *ScanCode = 0x35; *code |= 8; break;
+ case ' ': *ScanCode = 0x39; break;
+ case '\'': *ScanCode = 0x28; break;
+ case '"': *ScanCode = 0x28; *code |= 8; break;
+ case '~': *ScanCode = 0x29; *code |= 8; break;
+ case '.': *ScanCode = 0x34; break;
+ case ':': *ScanCode = 0x27; *code |= 8; break;
+ case '<': *ScanCode = 0x33; *code |= 8; break;
+// case 13: *ScanCode = 0x1c; break; // enter
+ case '>': *ScanCode = 0x34; *code |= 8; break;
+ // others
+// case 27: *ScanCode = 0x01; break; // esc
+ case '`': *ScanCode = 0x29; break;
+ case '^': *ScanCode = 0x07; *code |= 8; break;
+ case '[': *ScanCode = 0x1a; break;
+ case '{': *ScanCode = 0x1a; *code |= 8; break;
+ case ']': *ScanCode = 0x1b; break;
+ case '}': *ScanCode = 0x1b; *code |= 8; break;
+ case '\\': *ScanCode = 0x2b; break;
+ case '|': *ScanCode = 0x2b; *code |= 8; break;
+ // ctrl keys
+ case 1: *ScanCode = 0x1e; *code |= 16; break; // a
+ case 2: *ScanCode = 0x30; *code |= 16; break; // b
+ }
+
+ if (*ScanCode == 0 && key < 3000)
+ printf("unknown key %d mod %d ascii %d\n", key, mod, ascii);
+
+}
+
+//*****************************************************************************
+QMyScrollView::QMyScrollView() : QScrollView()
+{
+}
+
+//*****************************************************************************
+QMyScrollView::~QMyScrollView()
+{
+}
+
+//*****************************************************************************
+void QMyScrollView::keyPressEvent(QKeyEvent* e)
+{
+ int ScanCode, code;
+ GetScanCode(e, &ScanCode, &code);
+ if (ScanCode != 0)
+ {
+ if (code & 8) // send shift
+ rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x2a, 0);
+ if (code & 16) // send control
+ rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x1d, 0);
+ if (code & 32) // send alt
+ rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x38, 0);
+ rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYPRESS, ScanCode, 0);
+ e->accept();
+ }
+}
+
+//*****************************************************************************
+void QMyScrollView::keyReleaseEvent(QKeyEvent* e)
+{
+ int ScanCode, code;
+ GetScanCode(e, &ScanCode, &code);
+ if (ScanCode != 0)
+ {
+ rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYRELEASE, ScanCode, 0);
+ if (code & 8) // send shift
+ rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYRELEASE, 0x2a, 0);
+ if (code & 16) // send control
+ rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYRELEASE, 0x1d, 0);
+ if (code & 32) // send alt
+ rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYRELEASE, 0x38, 0);
+ e->accept();
+ }
+}
+
+//*****************************************************************************
+void QMyScrollView::showEvent(QShowEvent* e)
+{
+ QScrollView::showEvent(e);
+}
+
+//*****************************************************************************
+void QMyScrollView::show()
+{
+ QScrollView::show();
+}
+
+//*****************************************************************************
+void QMyScrollView::polish()
+{
+ QScrollView::polish();
+}
+
+//*****************************************************************************
+void QMyScrollView::timerEvent(QTimerEvent* e)
+{
+ QScrollView::timerEvent(e);
+ killTimer(timer_id);
+ QMyDialog* d;
+ QWidget* Desktop;
+ int dw;
+ int dh;
+
+ d = new QMyDialog(this);
+ if (d->exec() == 1) // ok clicked
+ {
+ flags = RDP_LOGON_NORMAL;
+ g_width = d->Width;
+ g_height = d->Height;
+ fullscreen = d->FullScreen;
+ sprintf(server, "%s", (const char*)d->ServerIP);
+ sprintf(username, "%s", (const char*)d->UserName);
+ if (!rdp_connect(server, flags, domain, password, shell, directory))
+ {
+ delete d;
+ SV->close();
+ return;
+ }
+ BS = (uint8*)xmalloc(g_width * g_height);
+ memset(BS, 0, g_width * g_height);
+ clipx = 0;
+ clipy = 0;
+ clipcx = g_width;
+ clipcy = g_height;
+ CM = (QColorMap*)xmalloc(sizeof(struct QColorMap));
+ memset(CM, 0, sizeof(struct QColorMap));
+ CM->NumColors = 256;
+ MW = new QMyMainWindow();
+ MW->resize(g_width, g_height);
+ MW->show();
+ SV->addChild(MW);
+ MW->setMouseTracking(true);
+ SocketNotifier = new QSocketNotifier(global_sock, QSocketNotifier::Read, MW);
+ MW->connect(SocketNotifier, SIGNAL(activated(int)), MW, SLOT(dataReceived()));
+ if (fullscreen)
+ {
+ Desktop = App->desktop();
+ dw = Desktop->width();
+ dh = Desktop->height();
+ if (dw == g_width && dh == g_height)
+ MW->resize(g_width - 4, g_height - 4);
+ SV->showFullScreen();
+ }
+ delete d;
+ }
+ else // cancel clicked
+ {
+ delete d;
+ SV->close();
+ }
+}
+
+//*****************************************************************************
+QMyMainWindow::QMyMainWindow() : QWidget(SV->viewport())
+{
+ PopupMenu = new QPopupMenu(this);
+ PopupMenu->insertItem("Right click", 1, 0);
+ PopupMenu->insertItem("Toggle fullscreen", 2, 1);
+ PopupMenu->insertItem("Reset keyboard", 3, 2);
+ PopupMenu->insertItem("Double click", 4, 3);
+ connect(PopupMenu, SIGNAL(activated(int)), this, SLOT(MemuClicked(int)));
+}
+
+//*****************************************************************************
+QMyMainWindow::~QMyMainWindow()
+{
+ delete PopupMenu;
+}
+
+//*****************************************************************************
+void QMyMainWindow::timerEvent(QTimerEvent* e)
+{
+ QWidget::timerEvent(e);
+ if (e->timerId() == timer_id)
+ {
+ // send mouse up
+ rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON1, mx, my);
+ // if in fullscreen, take it out or the menu won't work
+ if (fullscreen)
+ {
+ fullscreen = 0;
+ SV->showNormal();
+ SV->showMaximized();
+ }
+ else
+ PopupMenu->popup(mapToGlobal(QPoint(mx, my)));
+ }
+ killTimer(timer_id);
+}
+
+//*****************************************************************************
+void QMyMainWindow::MemuClicked(int MenuID)
+{
+ QWidget* Desktop;
+ int dw;
+ int dh;
+
+ if (MenuID == 1) // right click
+ {
+ rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON2, mx, my);
+ rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON2, mx, my);
+ }
+ else if (MenuID == 2) // toggle full screen
+ {
+ fullscreen = ~fullscreen;
+ if (fullscreen)
+ {
+ Desktop = App->desktop();
+ dw = Desktop->width();
+ dh = Desktop->height();
+ if (dw == g_width && dh == g_height)
+ MW->resize(g_width - 4, g_height - 4);
+ SV->showFullScreen();
+ }
+ else
+ {
+ SV->showNormal();
+ SV->showMaximized();
+ MW->resize(g_width, g_height);
+ }
+ }
+ else if (MenuID == 3) // reset keyboard
+ {
+ rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYRELEASE, 0x2a, 0); // shift
+ rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYRELEASE, 0x1d, 0); // control
+ rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYRELEASE, 0x38, 0); // alt
+ }
+ else if (MenuID == 4) // double click
+ {
+ rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON1, mx, my);
+ rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON1, mx, my);
+ rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON1, mx, my);
+ rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON1, mx, my);
+ }
+}
+
+//*****************************************************************************
+void QMyMainWindow::mouseMoveEvent(QMouseEvent* e)
+{
+ int x;
+ int y;
+
+ x = e->x();
+ y = e->y();
+
+ if (timer_id)
+ {
+ x = x - mx;
+ y = y - my;
+ if (x < -10 || x > 10 || y < -10 || y > 10)
+ {
+ killTimer(timer_id);
+ timer_id = 0;
+ }
+ }
+ rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE, e->x(), e->y());
+}
+
+//*****************************************************************************
+void QMyMainWindow::mousePressEvent(QMouseEvent* e)
+{
+ timer_id = startTimer(1000);
+ mx = e->x();
+ my = e->y();
+ if (e->button() == LeftButton)
+ rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON1, e->x(), e->y());
+ else if (e->button() == RightButton)
+ rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON2, e->x(), e->y());
+ else if (e->button() == MidButton)
+ rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON3, e->x(), e->y());
+}
+
+//*****************************************************************************
+void QMyMainWindow::mouseReleaseEvent(QMouseEvent* e)
+{
+ killTimer(timer_id);
+ timer_id = 0;
+ if (e->button() == LeftButton)
+ rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON1, e->x(), e->y());
+ else if (e->button() == RightButton)
+ rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON2, e->x(), e->y());
+ else if (e->button() == MidButton)
+ rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON3, e->x(), e->y());
+}
+
+//*****************************************************************************
+void QMyMainWindow::wheelEvent(QWheelEvent* e)
+{
+ if (e->delta() > 0)
+ rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON4, e->x(), e->y());
+ else if (e->delta() < 0)
+ rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON5, e->x(), e->y());
+}
+
+#define NOT(x) (255-(x))
+
+//*****************************************************************************
+uint8 rop(int rop, uint8 src, uint8 dst)
+{
+ switch (rop)
+ {
+ case 0x0: return 0;
+ case 0x1: return NOT (src | dst);
+ case 0x2: return NOT (src) & dst;
+ case 0x3: return NOT (src);
+ case 0x4: return src & NOT (dst);
+ case 0x5: return NOT (dst);
+ case 0x6: return src ^ dst;
+ case 0x7: return NOT (src & dst);
+ case 0x8: return src & dst;
+ case 0x9: return NOT (src) ^ dst;
+ case 0xa: return dst;
+ case 0xb: return NOT (src) | dst;
+ case 0xc: return src;
+ case 0xd: return src | NOT (dst);
+ case 0xe: return src | dst;
+ case 0xf: return NOT (0);
+ }
+ return dst;
+}
+
+//*****************************************************************************
+uint8 get_pixel(int x, int y)
+{
+ if (x >= 0 && x < g_width && y >= 0 && y < g_height)
+ return BS[y * g_width + x];
+ else
+ return 0;
+}
+
+//*****************************************************************************
+void set_pixel(int x, int y, uint8 pixel, int op = 0xc)
+{
+ if (x >= clipx && x < (clipx + clipcx) && y >= clipy && y < (clipy + clipcy))
+ if (x >= 0 && x < g_width && y >= 0 && y < g_height)
+ if (op == 0xc)
+ BS[y * g_width + x] = pixel;
+ else
+ BS[y * g_width + x] = rop(op, pixel, BS[y * g_width + x]);
+}
+
+//******************************************************************************
+// adjust coordinates for cliping rect
+bool WarpCoords(int* x, int* y, int* cx, int* cy, int* srcx, int* srcy)
+{
+ int dx, dy;
+ QRect InRect(*x, *y, *cx, *cy);
+ QRect OutRect;
+ QRect CRect(clipx, clipy, clipcx, clipcy);
+ OutRect = InRect.intersect(CRect);
+ if (OutRect.isEmpty())
+ return false;
+ dx = OutRect.x() - InRect.x();
+ dy = OutRect.y() - InRect.y();
+ *x = OutRect.x();
+ *y = OutRect.y();
+ *cx = OutRect.width();
+ *cy = OutRect.height();
+ if (srcx != NULL)
+ *srcx = *srcx + dx;
+ if (srcy != NULL)
+ *srcy = *srcy + dy;
+ return true;
+}
+
+//*****************************************************************************
+void QMyMainWindow::paintEvent(QPaintEvent* pe)
+{
+ QImage* Image;
+ QPainter* Painter;
+ QRect Rect;
+ int i, j, w, h, l, t;
+ uint8* data;
+
+ if (!testWFlags(WRepaintNoErase))
+ setWFlags(WRepaintNoErase);
+ if (CM != NULL)
+ {
+ Rect = pe->rect();
+ l = Rect.left();
+ t = Rect.top();
+ w = Rect.width();
+ h = Rect.height();
+ if (w > 0 && h > 0 && CM->NumColors > 0)
+ {
+ data = (uint8*)xmalloc(w * h);
+ for (i = 0; i < h; i++)
+ for (j = 0; j < w; j++)
+ data[i * w + j] = get_pixel(l + j, t + i);
+ Image = new QImage(data, w, h, 8,(QRgb*)CM->RGBColors, CM->NumColors, QImage::IgnoreEndian);
+ Painter = new QPainter(this);
+ Painter->drawImage(l, t, *Image, 0, 0, w, h);
+ xfree(data);
+ delete Painter;
+ delete Image;
+ }
+ }
+}
+
+//*****************************************************************************
+void QMyMainWindow::closeEvent(QCloseEvent* e)
+{
+ e->accept();
+}
+
+//*****************************************************************************
+void QMyMainWindow::dataReceived()
+{
+ if (rdp_main_loop())
+ return;
+ else
+ SV->close();
+}
+
+//*****************************************************************************
+void redraw(int x, int y, int cx, int cy)
+{
+ if (WarpCoords(&x, &y, &cx, &cy, NULL, NULL))
+ {
+ MW->update(x, y, cx, cy);
+ }
+}
+
+/*
+BOOL ui_init(void)
+{
+ QWidget* d;
+
+ CM = NULL;
+ BS = NULL;
+#ifdef SHARP
+ App = new QPEApplication(g_argc, g_argv);
+#else
+ App = new QApplication(g_argc, g_argv, QApplication::GuiServer);
+#endif
+ if (fullscreen)
+ {
+ d = QApplication::desktop();
+ width = d->width(); // returns screen width
+ height = d->height(); // returns screen height
+ }
+ return True;
+}
+*/
+
+/*
+void ui_deinit(void)
+{
+ delete App;
+}
+*/
+
+/*
+BOOL ui_create_window(void)
+{
+ MW = new QMyMainWindow();
+ MW->resize(width, height);
+ SV = new QMyScrollView();
+ SV->resize(width + 4, height + 4);
+ App->setMainWidget(SV);
+ SV->addChild(MW);
+ MW->setMouseTracking(true);
+ SocketNotifier = new QSocketNotifier(global_sock, QSocketNotifier::Read, MW);
+ MW->connect(SocketNotifier, SIGNAL(activated(int)), MW, SLOT(dataReceived()));
+ if (fullscreen)
+ SV->showFullScreen();
+ else
+ SV->showMaximized();
+ BS = (uint8*)xmalloc(width * height);
+ memset(BS, 0, width * height);
+ clipx = 0;
+ clipy = 0;
+ clipcx = width;
+ clipcy = height;
+ CM = (QColorMap*)xmalloc(sizeof(struct QColorMap));
+ memset(CM, 0, sizeof(struct QColorMap));
+ SV->timer_id = SV->startTimer(1000);
+ return True;
+}
+*/
+
+/*
+void ui_destroy_window(void)
+{
+ delete MW;
+ delete SV;
+ xfree(BS);
+ xfree(CM);
+}
+*/
+
+//*****************************************************************************
+/* Returns 0 after user quit, 1 otherwise */
+int ui_select(int rdp_socket)
+{
+ global_sock = rdp_socket;
+ return 1;
+}
+
+//*****************************************************************************
+void ui_move_pointer(int /*x*/, int /*y*/)
+{
+}
+
+//*****************************************************************************
+HBITMAP ui_create_bitmap(int width, int height, uint8 * data)
+{
+ struct bitmap* the_bitmap;
+ uint8* bitmap_data;
+ int i, j;
+
+// printf("width %d height %d times %d\n", width, height, width * height);
+ bitmap_data = (uint8*)xmalloc(width * height);
+ the_bitmap = (struct bitmap*)xmalloc(sizeof(struct bitmap));
+ the_bitmap->w = width;
+ the_bitmap->h = height;
+ the_bitmap->data = bitmap_data;
+ for (i = 0; i < height; i++)
+ for (j = 0; j < width; j++)
+ bitmap_data[i * width + j] = data[i * width + j];
+ return the_bitmap;
+}
+
+//*****************************************************************************
+void ui_paint_bitmap(int x, int y, int cx, int cy, int width,
+ int height, uint8 * data)
+{
+ int i, j;
+
+ for (i = 0; i < cy; i++)
+ for (j = 0; j < cx; j++)
+ if (i < height)
+ if (j < width)
+ set_pixel(x + j, y + i, data[i * width + j]);
+ redraw(x, y, cx, cy);
+}
+
+//*****************************************************************************
+void ui_destroy_bitmap(HBITMAP bmp)
+{
+ struct bitmap* the_bitmap;
+
+ the_bitmap = (struct bitmap*)bmp;
+ if (the_bitmap != NULL)
+ {
+ if (the_bitmap->data != NULL)
+ xfree(the_bitmap->data);
+ xfree(the_bitmap);
+ }
+}
+
+//*****************************************************************************
+bool is_pixel_on(uint8* data, int x, int y, int width, int bpp)
+{
+ int start, shift;
+
+ if (bpp == 1)
+ {
+ width = (width + 7) / 8;
+ start = (y * width) + x / 8;
+ shift = x % 8;
+ return (data[start] & (0x80 >> shift)) != 0;
+ }
+ else if (bpp == 8)
+ return data[y * width + x] != 0;
+ else
+ return false;
+}
+
+//*****************************************************************************
+void set_pixel_on(uint8* data, int x, int y, int width, int bpp, uint8 pixel)
+{
+ if (bpp == 8)
+ data[y * width + x] = pixel;
+}
+
+//*****************************************************************************
+HGLYPH ui_create_glyph(int width, int height, uint8 * data)
+{
+ int i, j;
+ uint8* glyph_data;
+ struct bitmap* the_glyph;
+
+ glyph_data = (uint8*)xmalloc(width * height);
+ the_glyph = (struct bitmap*)xmalloc(sizeof(struct bitmap));
+ the_glyph->w = width;
+ the_glyph->h = height;
+ the_glyph->data = glyph_data;
+ memset(glyph_data, 0, width * height);
+ for (i = 0; i < height; i++)
+ for (j = 0; j < width; j++)
+ if (is_pixel_on(data, j, i, width, 1))
+ set_pixel_on(glyph_data, j, i, width, 8, 255);
+ return the_glyph;
+}
+
+//*****************************************************************************
+void ui_destroy_glyph(HGLYPH glyph)
+{
+ struct bitmap* the_glyph;
+
+ the_glyph = (struct bitmap*)glyph;
+ if (the_glyph != NULL)
+ {
+ if (the_glyph->data != NULL)
+ xfree(the_glyph->data);
+ xfree(the_glyph);
+ }
+}
+
+//*****************************************************************************
+HCURSOR ui_create_cursor(unsigned int /*x*/, unsigned int /*y*/,
+ int /*width*/, int /*height*/, uint8 * /*andmask*/,
+ uint8 * /*xormask*/)
+{
+ return (void*)1;
+}
+
+//*****************************************************************************
+void ui_set_cursor(HCURSOR /*cursor*/)
+{
+}
+
+//*****************************************************************************
+void ui_destroy_cursor(HCURSOR /*cursor*/)
+{
+}
+
+//*****************************************************************************
+HCOLOURMAP ui_create_colourmap(COLOURMAP * colours)
+{
+ int i;
+ int x;
+ uint8 r, g, b;
+ i = 0;
+ while (i < colours->ncolours && i < 256)
+ {
+ r = colours->colours[i].red;
+ g = colours->colours[i].green;
+ b = colours->colours[i].blue;
+ x = (r << 16) | (g << 8) | b;
+ CM->RGBColors[i] = x;
+ i++;
+ }
+ CM->NumColors = colours->ncolours;
+ return CM;
+}
+
+//*****************************************************************************
+void ui_destroy_colourmap(HCOLOURMAP /*map*/)
+{
+}
+
+//*****************************************************************************
+void ui_set_colourmap(HCOLOURMAP /*map*/)
+{
+}
+
+//*****************************************************************************
+void ui_begin_update(void)
+{
+}
+
+//*****************************************************************************
+void ui_end_update(void)
+{
+}
+
+//*****************************************************************************
+void ui_set_clip(int x, int y, int cx, int cy)
+{
+ clipx = x;
+ clipy = y;
+ clipcx = cx;
+ clipcy = cy;
+}
+
+//*****************************************************************************
+void ui_reset_clip(void)
+{
+ clipx = 0;
+ clipy = 0;
+ clipcx = g_width;
+ clipcy = g_height;
+}
+
+//*****************************************************************************
+void ui_bell(void)
+{
+ App->beep();
+}
+
+//*****************************************************************************
+void ui_destblt(uint8 opcode, int x, int y, int cx, int cy)
+{
+ int i, j;
+
+ for (i = 0; i < cy; i++)
+ for (j = 0; j < cx; j++)
+ set_pixel(x + j, y + i, get_pixel(x + j, y + i), opcode);
+ redraw(x, y, cx, cy);
+}
+
+//*****************************************************************************
+// does not repaint
+void fill_rect(int x, int y, int cx, int cy, int colour, int opcode = 0xc)
+{
+ int i, j;
+
+ for (i = 0; i < cy; i++)
+ for (j = 0; j < cx; j++)
+ set_pixel(x + j, y + i, colour, opcode);
+}
+
+//*****************************************************************************
+void ui_rect(int x, int y, int cx, int cy, int colour)
+{
+ fill_rect(x, y, cx, cy, colour);
+ redraw(x, y, cx, cy);
+}
+
+//*****************************************************************************
+void ui_patblt(uint8 opcode, int x, int y, int cx, int cy,
+ BRUSH * brush, int bgcolour, int fgcolour)
+{
+ int i, j;
+ uint8 ipattern[8];
+
+ switch (brush->style)
+ {
+ case 0:
+ fill_rect(x, y, cx, cy, fgcolour, opcode);
+ break;
+ case 3:
+ for (i = 0; i < 8; i++)
+ ipattern[i] = ~brush->pattern[7 - i];
+ for (i = 0; i < cy; i++)
+ for (j = 0; j < cx; j++)
+ if (is_pixel_on(ipattern, (x + j + brush->xorigin) % 8,
+ (y + i + brush->yorigin) % 8, 8, 1))
+ set_pixel(x + j, y + i, fgcolour, opcode);
+ else
+ set_pixel(x + j, y + i, bgcolour, opcode);
+ break;
+ }
+ redraw(x, y, cx, cy);
+}
+
+//*****************************************************************************
+void ui_screenblt(uint8 opcode, int x, int y, int cx, int cy,
+ int srcx, int srcy)
+{
+ int i, j;
+ uint8* temp;
+
+ temp = (uint8*)xmalloc(cx * cy);
+ for (i = 0; i < cy; i++)
+ for (j = 0; j < cx; j++)
+ temp[i * cx + j] = get_pixel(srcx + j, srcy + i);
+ for (i = 0; i < cy; i++)
+ for (j = 0; j < cx; j++)
+ set_pixel(x + j, y + i, temp[i * cx + j], opcode);
+ xfree(temp);
+ redraw(x, y, cx, cy);
+}
+
+//*****************************************************************************
+void ui_memblt(uint8 opcode, int x, int y, int cx, int cy,
+ HBITMAP src, int srcx, int srcy)
+{
+ int i, j;
+ struct bitmap* the_bitmap;
+
+ the_bitmap = (struct bitmap*)src;
+ if (the_bitmap == NULL)
+ return;
+ for (i = 0; i < cy; i++)
+ for (j = 0; j < cx; j++)
+ if ((i + srcy) < the_bitmap->h && (j + srcx) < the_bitmap->w)
+ set_pixel(x + j, y + i, the_bitmap->data[(i + srcy) * the_bitmap->w + (j + srcx)], opcode);
+ redraw(x, y, cx, cy);
+}
+
+//*****************************************************************************
+// not used
+void ui_triblt(uint8 /*opcode*/, int /*x*/, int /*y*/, int /*cx*/, int /*cy*/,
+ HBITMAP /*src*/, int /*srcx*/, int /*srcy*/, BRUSH * /*brush*/,
+ int /*bgcolour*/, int /*fgcolour*/)
+{
+}
+
+//*****************************************************************************
+// Bresenham's line drawing algorithm
+void ui_line(uint8 opcode, int startx, int starty, int endx,
+ int endy, PEN * pen)
+{
+ int dx, dy, incx, incy, dpr, dpru, p, left, top, right, bottom;
+
+ if (startx > endx)
+ {
+ dx = startx - endx;
+ incx = -1;
+ left = endx;
+ right = startx;
+ }
+ else
+ {
+ dx = endx - startx;
+ incx = 1;
+ left = startx;
+ right = endx;
+ }
+ if (starty > endy)
+ {
+ dy = starty - endy;
+ incy = -1;
+ top = endy;
+ bottom = starty;
+ }
+ else
+ {
+ dy = endy - starty;
+ incy = 1;
+ top = starty;
+ bottom = endy;
+ }
+ if (dx >= dy)
+ {
+ dpr = dy << 1;
+ dpru = dpr - (dx << 1);
+ p = dpr - dx;
+ for (; dx >= 0; dx--)
+ {
+ set_pixel(startx, starty, pen->colour, opcode);
+ if (p > 0)
+ {
+ startx += incx;
+ starty += incy;
+ p += dpru;
+ }
+ else
+ {
+ startx += incx;
+ p += dpr;
+ }
+ }
+ }
+ else
+ {
+ dpr = dx << 1;
+ dpru = dpr - (dy << 1);
+ p = dpr - dy;
+ for (; dy >= 0; dy--)
+ {
+ set_pixel(startx, starty, pen->colour, opcode);
+ if (p > 0)
+ {
+ startx += incx;
+ starty += incy;
+ p += dpru;
+ }
+ else
+ {
+ starty += incy;
+ p += dpr;
+ }
+ }
+ }
+ redraw(left, top, (right - left) + 1, (bottom - top) + 1);
+}
+
+//*****************************************************************************
+void draw_glyph (int x, int y, HGLYPH glyph, int fgcolour)
+{
+ struct bitmap* the_glyph;
+ int i, j;
+
+ the_glyph = (struct bitmap*)glyph;
+ if (the_glyph == NULL)
+ return;
+ for (i = 0; i < the_glyph->h; i++)
+ for (j = 0; j < the_glyph->w; j++)
+ if (is_pixel_on(the_glyph->data, j, i, the_glyph->w, 8))
+ set_pixel(x + j, y + i, fgcolour);
+}
+
+#define DO_GLYPH(ttext,idx) \
+{\
+ glyph = cache_get_font (font, ttext[idx]);\
+ if (!(flags & TEXT2_IMPLICIT_X))\
+ {\
+ xyoffset = ttext[++idx];\
+ if ((xyoffset & 0x80))\
+ {\
+ if (flags & TEXT2_VERTICAL) \
+ y += ttext[idx+1] | (ttext[idx+2] << 8);\
+ else\
+ x += ttext[idx+1] | (ttext[idx+2] << 8);\
+ idx += 2;\
+ }\
+ else\
+ {\
+ if (flags & TEXT2_VERTICAL) \
+ y += xyoffset;\
+ else\
+ x += xyoffset;\
+ }\
+ }\
+ if (glyph != NULL)\
+ {\
+ draw_glyph (x + glyph->offset, y + glyph->baseline, glyph->pixmap, fgcolour);\
+ if (flags & TEXT2_IMPLICIT_X)\
+ x += glyph->width;\
+ }\
+}
+
+//*****************************************************************************
+void ui_draw_text(uint8 font, uint8 flags, int mixmode,
+ int x, int y, int clipx, int clipy,
+ int clipcx, int clipcy, int boxx,
+ int boxy, int boxcx, int boxcy, int bgcolour,
+ int fgcolour, uint8 * text, uint8 length)
+{
+ FONTGLYPH *glyph;
+ int i, j, xyoffset;
+ DATABLOB *entry;
+
+ if (boxcx > 1)
+ fill_rect(boxx, boxy, boxcx, boxcy, bgcolour);
+ else if (mixmode == MIX_OPAQUE)
+ fill_rect(clipx, clipy, clipcx, clipcy, bgcolour);
+
+ /* Paint text, character by character */
+ for (i = 0; i < length;)
+ {
+ switch (text[i])
+ {
+ case 0xff:
+ if (i + 2 < length)
+ cache_put_text(text[i + 1], text, text[i + 2]);
+ else
+ {
+ error("this shouldn't be happening\n");
+ exit(1);
+ }
+ /* this will move pointer from start to first character after FF command */
+ length -= i + 3;
+ text = &(text[i + 3]);
+ i = 0;
+ break;
+
+ case 0xfe:
+ entry = cache_get_text(text[i + 1]);
+ if (entry != NULL)
+ {
+ if ((((uint8 *) (entry->data))[1] == 0) && (!(flags & TEXT2_IMPLICIT_X)))
+ {
+ if (flags & TEXT2_VERTICAL)
+ y += text[i + 2];
+ else
+ x += text[i + 2];
+ }
+ for (j = 0; j < entry->size; j++)
+ DO_GLYPH(((uint8 *) (entry->data)), j);
+ }
+ if (i + 2 < length)
+ i += 3;
+ else
+ i += 2;
+ length -= i;
+ /* this will move pointer from start to first character after FE command */
+ text = &(text[i]);
+ i = 0;
+ break;
+
+ default:
+ DO_GLYPH(text, i);
+ i++;
+ break;
+ }
+ }
+ if (boxcx > 1)
+ redraw(boxx, boxy, boxcx, boxcy);
+ else
+ redraw(clipx, clipy, clipcx, clipcy);
+}
+
+//*****************************************************************************
+void ui_desktop_save(uint32 offset, int x, int y, int cx, int cy)
+{
+ uint8* data;
+ int i, j;
+
+ data = (uint8*)xmalloc(cx * cy);
+ for (i = 0; i < cy; i++)
+ for (j = 0; j < cx; j++)
+ data[i * cx + j] = get_pixel(x + j, y + i);
+ cache_put_desktop(offset, cx, cy, cx, 1, data);
+ xfree(data);
+}
+
+//*****************************************************************************
+void ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy)
+{
+ uint8* data;
+ int i, j;
+
+ data = cache_get_desktop(offset, cx, cy, 1);
+ for (i = 0; i < cy; i++)
+ for (j = 0; j < cx; j++)
+ set_pixel(x + j, y + i, data[i * cx + j]);
+ redraw(x, y, cx, cy);
+}
+
+//*****************************************************************************
+int main(int argc, char** argv)
+{
+ CM = NULL;
+ BS = NULL;
+#ifdef SHARP
+ App = new QPEApplication(argc, argv);
+#else
+ App = new QApplication(argc, argv, QApplication::GuiServer);
+#endif
+ SV = new QMyScrollView();
+ App->setMainWidget(SV);
+ SV->showMaximized();
+ SV->timer_id = SV->startTimer(1000);
+ App->exec();
+ delete SV;
+ delete App;
+ if (CM != NULL)
+ xfree(CM);
+ if (BS !=NULL)
+ xfree(BS);
+ return 0;
+}
+
+/*
+ MW = new QMyMainWindow();
+ MW->resize(width, height);
+ SV->resize(width + 4, height + 4);
+ App->setMainWidget(SV);
+ SV->addChild(MW);
+ MW->setMouseTracking(true);
+ SocketNotifier = new QSocketNotifier(global_sock, QSocketNotifier::Read, MW);
+ MW->connect(SocketNotifier, SIGNAL(activated(int)), MW, SLOT(dataReceived()));
+ if (fullscreen)
+ SV->showFullScreen();
+ else
+ SV->showMaximized();
+ BS = (uint8*)xmalloc(width * height);
+ memset(BS, 0, width * height);
+ clipx = 0;
+ clipy = 0;
+ clipcx = width;
+ clipcy = height;
+ CM = (QColorMap*)xmalloc(sizeof(struct QColorMap));
+ memset(CM, 0, sizeof(struct QColorMap));
+ SV->timer_id = SV->startTimer(1000);
+ return True;
+
+
+
+
+
+int main(int argc, char ** argv)
+{
+ uint32 flags;
+ int i, total_params;
+ char server[64] = "192.168.0.164";
+ char domain[16] = "";
+ char password[16] = "";
+ char shell[128] = "";
+ char directory[32] = "";
+ char* p;
+ QString param, s1, s2, s3;
+
+ flags = RDP_LOGON_NORMAL;
+
+ g_argc = argc;
+ g_argv = argv;
+
+ if (!ui_init())
+ return 1;
+
+ total_params = App->argc();
+
+ for (i = 1; (i + 1) < total_params; i = i + 2)
+ {
+ s1 = App->argv()[i];
+ s2 = App->argv()[i + 1];
+ if (s1 == "-g")
+ {
+ width = strtol((const char*)s2, &p, 10);
+ if (*p == 'x')
+ height = strtol(p + 1, NULL, 10);
+ }
+ else if (s1 = "-u")
+ strcpy(username, (const char*)s2);
+ }
+ if (i < total_params)
+ strcpy(server, App->argv()[i]);
+
+// printf("server %s width %d height %d\n", server, width, height);
+
+ if (width == 0 || height == 0)
+ {
+ ui_deinit();
+ return 1;
+ }
+
+ if (!rdp_connect(server, flags, domain, password, shell, directory))
+ {
+ ui_deinit();
+ return 1;
+ }
+ if (ui_create_window())
+ {
+ ui_main_loop();
+ ui_destroy_window();
+ }
+ rdp_disconnect();
+ ui_deinit();
+}
+*/
diff --git a/noncore/net/opierdesktop/qtwin.h b/noncore/net/opierdesktop/qtwin.h
new file mode 100644
index 0000000..38ad190
--- a/dev/null
+++ b/noncore/net/opierdesktop/qtwin.h
@@ -0,0 +1,105 @@
+
+#include <qwidget.h>
+#include <qscrollview.h>
+#include <qdialog.h>
+#include <qlistbox.h>
+#include <qlineedit.h>
+#include <qcombobox.h>
+#include <qlabel.h>
+#include <qcheckbox.h>
+#include <qpopupmenu.h>
+
+class QMyConnectionItem
+{
+ public:
+ QString ServerName;
+ QString UserName;
+ QString ServerIP;
+ int Width;
+ int Height;
+ int FullScreen;
+};
+
+class QMyDialog: public QDialog
+{
+ Q_OBJECT
+ public:
+ QMyDialog(QWidget*);
+ ~QMyDialog();
+ public:
+ QListBox* ListBox;
+ QPushButton* OKButton;
+ QPushButton* CancelButton;
+ QLabel* Label1;
+ QLineEdit* ServerNameEdit;
+ QLabel* Label2;
+ QLineEdit* UserNameEdit;
+ QLabel* Label3;
+ QLineEdit* IPEdit;
+ QLineEdit* WidthEdit;
+ QLineEdit* HeightEdit;
+ QComboBox* WidthHeightBox;
+ QPushButton* AddButton;
+ QPushButton* EditButton;
+ QPushButton* SaveButton;
+ QPushButton* RemoveButton;
+ QCheckBox* FullScreenCheckBox;
+ public slots:
+ void ComboChanged(int);
+ void OKClicked();
+ void CancelClicked();
+ void AddClicked();
+ void EditClicked();
+ void SaveClicked();
+ void RemoveClicked();
+ void ListBoxChanged();
+ void ListBoxSelected(int);
+ public:
+ QString ServerName;
+ QString UserName;
+ QString ServerIP;
+ int Width;
+ int Height;
+ int FullScreen;
+ QMyConnectionItem* ConnectionList[10];
+};
+
+class QMyScrollView: public QScrollView
+{
+ Q_OBJECT
+ public:
+ QMyScrollView();
+ ~QMyScrollView();
+ void keyPressEvent(QKeyEvent*);
+ void keyReleaseEvent(QKeyEvent*);
+ void showEvent(QShowEvent*);
+ void show();
+ void polish();
+ void timerEvent(QTimerEvent*);
+ public:
+ int timer_id;
+};
+
+class QMyMainWindow: public QWidget
+{
+ Q_OBJECT
+ public:
+ QMyMainWindow();
+ ~QMyMainWindow();
+ void paintEvent(QPaintEvent*);
+ void mouseMoveEvent(QMouseEvent*);
+ void mousePressEvent(QMouseEvent*);
+ void mouseReleaseEvent(QMouseEvent*);
+ void wheelEvent(QWheelEvent*);
+ void closeEvent(QCloseEvent*);
+ void timerEvent(QTimerEvent*);
+ public slots:
+ void dataReceived();
+ void MemuClicked(int);
+ public:
+ QPopupMenu* PopupMenu;
+ int timer_id;
+ int mx;
+ int my;
+};
+
diff --git a/noncore/net/opierdesktop/rdesktop.cpp b/noncore/net/opierdesktop/rdesktop.cpp
new file mode 100644
index 0000000..1a9a087
--- a/dev/null
+++ b/noncore/net/opierdesktop/rdesktop.cpp
@@ -0,0 +1,313 @@
+/*
+ rdesktop: A Remote Desktop Protocol client.
+ Entrypoint and utility functions
+ Copyright (C) Matthew Chapman 1999-2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+//#include <stdarg.h> /* va_list va_start va_end */
+#include <unistd.h> /* read close getuid getgid getpid getppid gethostname */
+#include <fcntl.h> /* open */
+#include <pwd.h> /* getpwuid */
+//#include <termios.h> /* tcgetattr tcsetattr */
+#include <sys/stat.h> /* stat */
+#include <sys/time.h> /* gettimeofday */
+#include <sys/times.h> /* times */
+#include <errno.h>
+#include "rdesktop.h"
+
+#ifdef EGD_SOCKET
+#include <sys/socket.h> /* socket connect */
+#include <sys/un.h> /* sockaddr_un */
+#endif
+
+//#ifdef WITH_OPENSSL
+#include <openssl/md5.h>
+//#else
+//#include "crypto/md5.h"
+//#endif
+
+/*extern "C" */void ui_main_loop(void);
+
+int g_argc;
+char ** g_argv;
+
+char title[32] = "";
+char username[16] = "j";
+char hostname[16] = "sharp";
+char keymapname[16];
+int keylayout = 0x409; /* Defaults to US keyboard layout */
+int g_width = 800; /* If width or height are reset to zero, the geometry will
+ be fetched from _NET_WORKAREA */
+int g_height = 600;
+int tcp_port_rdp = TCP_PORT_RDP;
+int server_bpp = 8;
+int win_button_size = 0; /* If zero, disable single app mode */
+BOOL bitmap_compression = True;
+BOOL sendmotion = True;
+BOOL orders = True;
+BOOL encryption = True;
+BOOL desktop_save = True;
+BOOL fullscreen = False;
+BOOL grab_keyboard = True;
+BOOL hide_decorations = False;
+extern BOOL owncolmap;
+
+/* report an unimplemented protocol feature */
+void
+unimpl(char *format, ...)
+{
+}
+
+/* malloc; exit if out of memory */
+void *
+xmalloc(int size)
+{
+ void *mem = malloc(size);
+ if (mem == NULL)
+ {
+ error("xmalloc %d\n", size);
+ exit(1);
+ }
+ return mem;
+}
+
+/* realloc; exit if out of memory */
+void *
+xrealloc(void *oldmem, int size)
+{
+ void *mem = realloc(oldmem, size);
+ if (mem == NULL)
+ {
+ error("xrealloc %d\n", size);
+ exit(1);
+ }
+ return mem;
+}
+
+/* free */
+void
+xfree(void *mem)
+{
+ free(mem);
+}
+
+/* report an error */
+void
+error(char *format, ...)
+{
+}
+
+/* report a warning */
+void
+warning(char *format, ...)
+{
+}
+
+/* Generate a 32-byte random for the secure transport code. */
+void
+generate_random(uint8 * random)
+{
+ struct stat st;
+ struct tms tmsbuf;
+ MD5_CTX md5;
+ uint32 *r;
+ int fd, n;
+
+ /* If we have a kernel random device, try that first */
+ if (((fd = open("/dev/urandom", O_RDONLY)) != -1)
+ || ((fd = open("/dev/random", O_RDONLY)) != -1))
+ {
+ n = read(fd, random, 32);
+ close(fd);
+ if (n == 32)
+ return;
+ }
+ /* Otherwise use whatever entropy we can gather - ideas welcome. */
+ r = (uint32 *) random;
+ r[0] = (getpid()) | (getppid() << 16);
+ r[1] = (getuid()) | (getgid() << 16);
+ r[2] = times(&tmsbuf); /* system uptime (clocks) */
+ gettimeofday((struct timeval *) &r[3], NULL); /* sec and usec */
+ stat("/tmp", &st);
+ r[5] = st.st_atime;
+ r[6] = st.st_mtime;
+ r[7] = st.st_ctime;
+
+ /* Hash both halves with MD5 to obscure possible patterns */
+ MD5_Init(&md5);
+ MD5_Update(&md5, random, 16);
+ MD5_Final(random, &md5);
+ MD5_Update(&md5, random + 16, 16);
+ MD5_Final(random + 16, &md5);
+}
+
+int
+load_licence(unsigned char **data)
+{
+ char *path;
+ char *home;
+ struct stat st;
+ int fd;
+
+ home = getenv("HOME");
+ if (home == NULL)
+ return -1;
+
+ path = (char*)xmalloc(strlen(home) + strlen(hostname) + 20);
+ sprintf(path, "%s/.rdesktop/licence.%s", home, hostname);
+
+ fd = open(path, O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ if (fstat(fd, &st))
+ return -1;
+
+ *data = (unsigned char*)xmalloc(st.st_size);
+ return read(fd, *data, st.st_size);
+}
+
+void
+save_licence(unsigned char *data, int length)
+{
+ char *fpath; /* file path for licence */
+ char *fname, *fnamewrk; /* file name for licence .inkl path. */
+ char *home;
+ uint32 y;
+ struct flock fnfl;
+ int fnfd, fnwrkfd, i, wlen;
+ struct stream s, *s_ptr;
+ uint32 len;
+
+ /* Construct a stream, so that we can use macros to extract the
+ * licence.
+ */
+ s_ptr = &s;
+ s_ptr->p = data;
+ /* Skip first two bytes */
+ in_uint16(s_ptr, len);
+
+ /* Skip three strings */
+ for (i = 0; i < 3; i++)
+ {
+ in_uint32(s_ptr, len);
+ s_ptr->p += len;
+ /* Make sure that we won't be past the end of data after
+ * reading the next length value
+ */
+ if ((s_ptr->p) + 4 > data + length)
+ {
+ printf("Error in parsing licence key.\n");
+ printf("Strings %d end value %x > supplied length (%x)\n", i,
+ (unsigned int) s_ptr->p, (unsigned int) data + length);
+ return;
+ }
+ }
+ in_uint32(s_ptr, len);
+ if (s_ptr->p + len > data + length)
+ {
+ printf("Error in parsing licence key.\n");
+ printf("End of licence %x > supplied length (%x)\n",
+ (unsigned int) s_ptr->p + len, (unsigned int) data + length);
+ return;
+ }
+
+ home = getenv("HOME");
+ if (home == NULL)
+ return;
+
+ /* set and create the directory -- if it doesn't exist. */
+ fpath = (char*)xmalloc(strlen(home) + 11);
+ STRNCPY(fpath, home, strlen(home) + 1);
+
+ sprintf(fpath, "%s/.rdesktop", fpath);
+ if (mkdir(fpath, 0700) == -1 && errno != EEXIST)
+ {
+ perror("mkdir");
+ exit(1);
+ }
+
+ /* set the real licence filename, and put a write lock on it. */
+ fname = (char*)xmalloc(strlen(fpath) + strlen(hostname) + 10);
+ sprintf(fname, "%s/licence.%s", fpath, hostname);
+ fnfd = open(fname, O_RDONLY);
+ if (fnfd != -1)
+ {
+ fnfl.l_type = F_WRLCK;
+ fnfl.l_whence = SEEK_SET;
+ fnfl.l_start = 0;
+ fnfl.l_len = 1;
+ fcntl(fnfd, F_SETLK, &fnfl);
+ }
+
+ /* create a temporary licence file */
+ fnamewrk = (char*)xmalloc(strlen(fname) + 12);
+ for (y = 0;; y++)
+ {
+ sprintf(fnamewrk, "%s.%lu", fname, (long unsigned int) y);
+ fnwrkfd = open(fnamewrk, O_WRONLY | O_CREAT | O_EXCL, 0600);
+ if (fnwrkfd == -1)
+ {
+ if (errno == EINTR || errno == EEXIST)
+ continue;
+ perror("create");
+ exit(1);
+ }
+ break;
+ }
+ /* write to the licence file */
+ for (y = 0; y < len;)
+ {
+ do
+ {
+ wlen = write(fnwrkfd, s_ptr->p + y, len - y);
+ }
+ while (wlen == -1 && errno == EINTR);
+ if (wlen < 1)
+ {
+ perror("write");
+ unlink(fnamewrk);
+ exit(1);
+ }
+ y += wlen;
+ }
+
+ /* close the file and rename it to fname */
+ if (close(fnwrkfd) == -1)
+ {
+ perror("close");
+ unlink(fnamewrk);
+ exit(1);
+ }
+ if (rename(fnamewrk, fname) == -1)
+ {
+ perror("rename");
+ unlink(fnamewrk);
+ exit(1);
+ }
+ /* close the file lock on fname */
+ if (fnfd != -1)
+ {
+ fnfl.l_type = F_UNLCK;
+ fnfl.l_whence = SEEK_SET;
+ fnfl.l_start = 0;
+ fnfl.l_len = 1;
+ fcntl(fnfd, F_SETLK, &fnfl);
+ close(fnfd);
+ }
+
+}
diff --git a/noncore/net/opierdesktop/rdesktop.h b/noncore/net/opierdesktop/rdesktop.h
new file mode 100644
index 0000000..0fca123
--- a/dev/null
+++ b/noncore/net/opierdesktop/rdesktop.h
@@ -0,0 +1,66 @@
+/*
+ rdesktop: A Remote Desktop Protocol client.
+ Master include file
+ Copyright (C) Matthew Chapman 1999-2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+//#define __LITTLE_ENDIAN 1234
+//#define __BIG_ENDIAN 4321
+//#define __BYTE_ORDER __BIG_ENDIAN
+
+//#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define L_ENDIAN
+#define NEED_ALIGN
+//#error le
+//#elif __BYTE_ORDER == __BIG_ENDIAN
+//#define B_ENDIAN
+//#error be
+//#else
+//#error Unknown endianness. Edit rdesktop.h.
+//#endif
+
+
+//#define B_ENDIAN
+//#define B_ENDIAN_PREFERRED
+
+#define VERSION "1.2.0"
+
+#ifdef WITH_DEBUG
+#define DEBUG(args) printf args;
+#else
+#define DEBUG(args)
+#endif
+
+#ifdef WITH_DEBUG_KBD
+#define DEBUG_KBD(args) printf args;
+#else
+#define DEBUG_KBD(args)
+#endif
+
+#define STRNCPY(dst,src,n) { strncpy(dst,src,n-1); dst[n-1] = 0; }
+
+#include "constants.h"
+#include "types.h"
+#include "parse.h"
+
+#ifndef MAKE_PROTO
+#include "proto.h"
+#endif
diff --git a/noncore/net/opierdesktop/rdp.cpp b/noncore/net/opierdesktop/rdp.cpp
new file mode 100644
index 0000000..bab8568
--- a/dev/null
+++ b/noncore/net/opierdesktop/rdp.cpp
@@ -0,0 +1,748 @@
+/*
+ rdesktop: A Remote Desktop Protocol client.
+ Protocol services - RDP layer
+ Copyright (C) Matthew Chapman 1999-2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "rdesktop.h"
+
+extern uint16 mcs_userid;
+extern char username[16];
+extern BOOL bitmap_compression;
+extern BOOL orders;
+extern BOOL encryption;
+extern BOOL desktop_save;
+
+uint8 *next_packet;
+uint32 rdp_shareid;
+
+/* Initialise an RDP packet */
+static STREAM
+rdp_init(int maxlen)
+{
+ STREAM s;
+
+ s = sec_init(encryption ? SEC_ENCRYPT : 0, maxlen + 6);
+ s_push_layer(s, rdp_hdr, 6);
+
+ return s;
+}
+
+/* Send an RDP packet */
+static void
+rdp_send(STREAM s, uint8 pdu_type)
+{
+ uint16 length;
+
+ s_pop_layer(s, rdp_hdr);
+ length = s->end - s->p;
+
+ out_uint16_le(s, length);
+ out_uint16_le(s, (pdu_type | 0x10)); /* Version 1 */
+ out_uint16_le(s, (mcs_userid + 1001));
+
+ sec_send(s, encryption ? SEC_ENCRYPT : 0);
+}
+
+/* Receive an RDP packet */
+STREAM
+rdp_recv(uint8 * type)
+{
+ static STREAM rdp_s;
+ uint16 length, pdu_type;
+
+ if ((rdp_s == NULL) || (next_packet >= rdp_s->end))
+ {
+ rdp_s = sec_recv();
+ if (rdp_s == NULL)
+ return NULL;
+
+ next_packet = rdp_s->p;
+ }
+ else
+ {
+ rdp_s->p = next_packet;
+ }
+
+ in_uint16_le(rdp_s, length);
+ /* 32k packets are really 8, keepalive fix */
+ if (length == 0x8000)
+ {
+ next_packet += 8;
+ *type = 0;
+ return rdp_s;
+ }
+ in_uint16_le(rdp_s, pdu_type);
+ in_uint8s(rdp_s, 2); /* userid */
+ *type = pdu_type & 0xf;
+
+#if WITH_DEBUG
+ DEBUG(("RDP packet (type %x):\n", *type));
+ hexdump(next_packet, length);
+#endif /* */
+
+ next_packet += length;
+ return rdp_s;
+}
+
+/* Initialise an RDP data packet */
+static STREAM
+rdp_init_data(int maxlen)
+{
+ STREAM s;
+
+ s = sec_init(encryption ? SEC_ENCRYPT : 0, maxlen + 18);
+ s_push_layer(s, rdp_hdr, 18);
+
+ return s;
+}
+
+/* Send an RDP data packet */
+static void
+rdp_send_data(STREAM s, uint8 data_pdu_type)
+{
+ uint16 length;
+
+ s_pop_layer(s, rdp_hdr);
+ length = s->end - s->p;
+
+ out_uint16_le(s, length);
+ out_uint16_le(s, (RDP_PDU_DATA | 0x10));
+ out_uint16_le(s, (mcs_userid + 1001));
+
+ out_uint32_le(s, rdp_shareid);
+ out_uint8(s, 0); /* pad */
+ out_uint8(s, 1); /* streamid */
+ out_uint16_le(s, (length - 14));
+ out_uint8(s, data_pdu_type);
+ out_uint8(s, 0); /* compress_type */
+ out_uint16(s, 0); /* compress_len */
+
+ sec_send(s, encryption ? SEC_ENCRYPT : 0);
+}
+
+/* Output a string in Unicode */
+void
+rdp_out_unistr(STREAM s, char *string, int len)
+{
+ int i = 0, j = 0;
+
+ len += 2;
+
+ while (i < len)
+ {
+ s->p[i++] = string[j++];
+ s->p[i++] = 0;
+ }
+
+ s->p += len;
+}
+
+/* Parse a logon info packet */
+static void
+rdp_send_logon_info(uint32 flags, char *domain, char *user,
+ char *password, char *program, char *directory)
+{
+ int len_domain = 2 * strlen(domain);
+ int len_user = 2 * strlen(user);
+ int len_password = 2 * strlen(password);
+ int len_program = 2 * strlen(program);
+ int len_directory = 2 * strlen(directory);
+ uint32 sec_flags = encryption ? (SEC_LOGON_INFO | SEC_ENCRYPT) : SEC_LOGON_INFO;
+ STREAM s;
+
+ s = sec_init(sec_flags, 18 + len_domain + len_user + len_password
+ + len_program + len_directory + 10);
+
+ out_uint32(s, 0);
+ out_uint32_le(s, flags);
+ out_uint16_le(s, len_domain);
+ out_uint16_le(s, len_user);
+ out_uint16_le(s, len_password);
+ out_uint16_le(s, len_program);
+ out_uint16_le(s, len_directory);
+ rdp_out_unistr(s, domain, len_domain);
+ rdp_out_unistr(s, user, len_user);
+ rdp_out_unistr(s, password, len_password);
+ rdp_out_unistr(s, program, len_program);
+ rdp_out_unistr(s, directory, len_directory);
+
+ s_mark_end(s);
+ sec_send(s, sec_flags);
+}
+
+/* Send a control PDU */
+static void
+rdp_send_control(uint16 action)
+{
+ STREAM s;
+
+ s = rdp_init_data(8);
+
+ out_uint16_le(s, action);
+ out_uint16(s, 0); /* userid */
+ out_uint32(s, 0); /* control id */
+
+ s_mark_end(s);
+ rdp_send_data(s, RDP_DATA_PDU_CONTROL);
+}
+
+/* Send a synchronisation PDU */
+static void
+rdp_send_synchronise(void)
+{
+ STREAM s;
+
+ s = rdp_init_data(4);
+
+ out_uint16_le(s, 1); /* type */
+ out_uint16_le(s, 1002);
+
+ s_mark_end(s);
+ rdp_send_data(s, RDP_DATA_PDU_SYNCHRONISE);
+}
+
+/* Send a single input event */
+void
+rdp_send_input(uint32 time, uint16 message_type, uint16 device_flags, uint16 param1, uint16 param2)
+{
+ STREAM s;
+
+ s = rdp_init_data(16);
+
+ out_uint16_le(s, 1); /* number of events */
+ out_uint16(s, 0); /* pad */
+
+ out_uint32_le(s, time);
+ out_uint16_le(s, message_type);
+ out_uint16_le(s, device_flags);
+ out_uint16_le(s, param1);
+ out_uint16_le(s, param2);
+
+ s_mark_end(s);
+ rdp_send_data(s, RDP_DATA_PDU_INPUT);
+}
+
+/* Send an (empty) font information PDU */
+static void
+rdp_send_fonts(uint16 seq)
+{
+ STREAM s;
+
+ s = rdp_init_data(8);
+
+ out_uint16(s, 0); /* number of fonts */
+ out_uint16_le(s, 0x3e); /* unknown */
+ out_uint16_le(s, seq); /* unknown */
+ out_uint16_le(s, 0x32); /* entry size */
+
+ s_mark_end(s);
+ rdp_send_data(s, RDP_DATA_PDU_FONT2);
+}
+
+/* Output general capability set */
+static void
+rdp_out_general_caps(STREAM s)
+{
+ out_uint16_le(s, RDP_CAPSET_GENERAL);
+ out_uint16_le(s, RDP_CAPLEN_GENERAL);
+
+ out_uint16_le(s, 1); /* OS major type */
+ out_uint16_le(s, 3); /* OS minor type */
+ out_uint16_le(s, 0x200); /* Protocol version */
+ out_uint16(s, 0); /* Pad */
+ out_uint16(s, 0); /* Compression types */
+ out_uint16(s, 0); /* Pad */
+ out_uint16(s, 0); /* Update capability */
+ out_uint16(s, 0); /* Remote unshare capability */
+ out_uint16(s, 0); /* Compression level */
+ out_uint16(s, 0); /* Pad */
+}
+
+/* Output bitmap capability set */
+static void
+rdp_out_bitmap_caps(STREAM s)
+{
+ out_uint16_le(s, RDP_CAPSET_BITMAP);
+ out_uint16_le(s, RDP_CAPLEN_BITMAP);
+
+ out_uint16_le(s, 8); /* Preferred BPP */
+ out_uint16_le(s, 1); /* Receive 1 BPP */
+ out_uint16_le(s, 1); /* Receive 4 BPP */
+ out_uint16_le(s, 1); /* Receive 8 BPP */
+ out_uint16_le(s, 800); /* Desktop width */
+ out_uint16_le(s, 600); /* Desktop height */
+ out_uint16(s, 0); /* Pad */
+ out_uint16(s, 0); /* Allow resize */
+ out_uint16_le(s, bitmap_compression ? 1 : 0); /* Support compression */
+ out_uint16(s, 0); /* Unknown */
+ out_uint16_le(s, 1); /* Unknown */
+ out_uint16(s, 0); /* Pad */
+}
+
+/* Output order capability set */
+static void
+rdp_out_order_caps(STREAM s)
+{
+ uint8 order_caps[32];
+
+
+ memset(order_caps, 0, 32);
+ order_caps[0] = 1; /* dest blt */
+ order_caps[1] = 1; /* pat blt */
+ order_caps[2] = 1; /* screen blt */
+// order_caps[3] = 1; /* required for memblt? */
+ order_caps[8] = 1; /* line */
+ order_caps[9] = 1; /* line */
+ order_caps[10] = 1; /* rect */
+ order_caps[11] = (desktop_save == False ? 0 : 1); /* desksave */
+ order_caps[13] = 1; /* memblt */
+ order_caps[14] = 1; /* triblt */
+ order_caps[22] = 1; /* polyline */
+ order_caps[27] = 1; /* text2 */
+ out_uint16_le(s, RDP_CAPSET_ORDER);
+ out_uint16_le(s, RDP_CAPLEN_ORDER);
+
+ out_uint8s(s, 20); /* Terminal desc, pad */
+ out_uint16_le(s, 1); /* Cache X granularity */
+ out_uint16_le(s, 20); /* Cache Y granularity */
+ out_uint16(s, 0); /* Pad */
+ out_uint16_le(s, 1); /* Max order level */
+ out_uint16_le(s, 0x147); /* Number of fonts */
+ out_uint16_le(s, 0x2a); /* Capability flags */
+ out_uint8p(s, order_caps, 32); /* Orders supported */
+ out_uint16_le(s, 0x6a1); /* Text capability flags */
+ out_uint8s(s, 6); /* Pad */
+ out_uint32_le(s, desktop_save == False ? 0 : 0x38400); /* Desktop cache size */
+// out_uint32_le(s, 0); // desktop cache set to 0
+ out_uint32(s, 0); /* Unknown */
+ out_uint32_le(s, 0x4e4); /* Unknown */
+}
+
+/* Output bitmap cache capability set */
+static void
+rdp_out_bmpcache_caps(STREAM s)
+{
+ out_uint16_le(s, RDP_CAPSET_BMPCACHE);
+ out_uint16_le(s, RDP_CAPLEN_BMPCACHE);
+
+ out_uint8s(s, 24); /* unused */
+ out_uint16_le(s, 0x258); /* entries */
+ out_uint16_le(s, 0x100); /* max cell size */
+ out_uint16_le(s, 0x12c); /* entries */
+ out_uint16_le(s, 0x400); /* max cell size */
+ out_uint16_le(s, 0x106); /* entries */
+ out_uint16_le(s, 0x1000); /* max cell size */
+}
+
+/* Output control capability set */
+static void
+rdp_out_control_caps(STREAM s)
+{
+ out_uint16_le(s, RDP_CAPSET_CONTROL);
+ out_uint16_le(s, RDP_CAPLEN_CONTROL);
+
+ out_uint16(s, 0); /* Control capabilities */
+ out_uint16(s, 0); /* Remote detach */
+ out_uint16_le(s, 2); /* Control interest */
+ out_uint16_le(s, 2); /* Detach interest */
+}
+
+/* Output activation capability set */
+static void
+rdp_out_activate_caps(STREAM s)
+{
+ out_uint16_le(s, RDP_CAPSET_ACTIVATE);
+ out_uint16_le(s, RDP_CAPLEN_ACTIVATE);
+
+ out_uint16(s, 0); /* Help key */
+ out_uint16(s, 0); /* Help index key */
+ out_uint16(s, 0); /* Extended help key */
+ out_uint16(s, 0); /* Window activate */
+}
+
+/* Output pointer capability set */
+static void
+rdp_out_pointer_caps(STREAM s)
+{
+ out_uint16_le(s, RDP_CAPSET_POINTER);
+ out_uint16_le(s, RDP_CAPLEN_POINTER);
+
+ out_uint16(s, 0); /* Colour pointer */
+ out_uint16_le(s, 20); /* Cache size */
+}
+
+/* Output share capability set */
+static void
+rdp_out_share_caps(STREAM s)
+{
+ out_uint16_le(s, RDP_CAPSET_SHARE);
+ out_uint16_le(s, RDP_CAPLEN_SHARE);
+
+ out_uint16(s, 0); /* userid */
+ out_uint16(s, 0); /* pad */
+}
+
+/* Output colour cache capability set */
+static void
+rdp_out_colcache_caps(STREAM s)
+{
+ out_uint16_le(s, RDP_CAPSET_COLCACHE);
+ out_uint16_le(s, RDP_CAPLEN_COLCACHE);
+
+ out_uint16_le(s, 6); /* cache size */
+ out_uint16(s, 0); /* pad */
+}
+
+static uint8 canned_caps[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00, 0x04,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0C, 0x00, 0x08, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x0E, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x34, 0x00, 0xFE,
+ 0x00, 0x04, 0x00, 0xFE, 0x00, 0x04, 0x00, 0xFE, 0x00, 0x08, 0x00,
+ 0xFE, 0x00, 0x08, 0x00, 0xFE,
+ 0x00, 0x10, 0x00, 0xFE, 0x00, 0x20, 0x00, 0xFE, 0x00, 0x40, 0x00,
+ 0xFE, 0x00, 0x80, 0x00, 0xFE,
+ 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x01,
+ 0x02, 0x00, 0x00, 0x00
+};
+
+/* Output unknown capability set */
+static void
+rdp_out_unknown_caps(STREAM s)
+{
+ out_uint16_le(s, RDP_CAPSET_UNKNOWN);
+ out_uint16_le(s, 0x58);
+
+ out_uint8p(s, canned_caps, RDP_CAPLEN_UNKNOWN - 4);
+}
+
+/* Send a confirm active PDU */
+static void
+rdp_send_confirm_active(void)
+{
+ STREAM s;
+ uint16 caplen =
+ RDP_CAPLEN_GENERAL + RDP_CAPLEN_BITMAP + RDP_CAPLEN_ORDER +
+ RDP_CAPLEN_BMPCACHE + RDP_CAPLEN_COLCACHE +
+ RDP_CAPLEN_ACTIVATE + RDP_CAPLEN_CONTROL +
+ RDP_CAPLEN_POINTER + RDP_CAPLEN_SHARE + RDP_CAPLEN_UNKNOWN + 4 /* w2k fix, why? */ ;
+
+ s = rdp_init(14 + caplen + sizeof(RDP_SOURCE));
+
+ out_uint32_le(s, rdp_shareid);
+ out_uint16_le(s, 0x3ea); /* userid */
+ out_uint16_le(s, sizeof(RDP_SOURCE));
+ out_uint16_le(s, caplen);
+
+ out_uint8p(s, RDP_SOURCE, sizeof(RDP_SOURCE));
+ out_uint16_le(s, 0xd); /* num_caps */
+ out_uint8s(s, 2); /* pad */
+
+ rdp_out_general_caps(s);
+ rdp_out_bitmap_caps(s);
+ rdp_out_order_caps(s);
+ rdp_out_bmpcache_caps(s);
+ rdp_out_colcache_caps(s);
+ rdp_out_activate_caps(s);
+ rdp_out_control_caps(s);
+ rdp_out_pointer_caps(s);
+ rdp_out_share_caps(s);
+ rdp_out_unknown_caps(s);
+
+ s_mark_end(s);
+ rdp_send(s, RDP_PDU_CONFIRM_ACTIVE);
+}
+
+/* Respond to a demand active PDU */
+void
+process_demand_active(STREAM s)
+{
+ uint8 type;
+
+ in_uint32_le(s, rdp_shareid);
+
+ DEBUG(("DEMAND_ACTIVE(id=0x%x)\n", rdp_shareid));
+
+ rdp_send_confirm_active();
+ rdp_send_synchronise();
+ rdp_send_control(RDP_CTL_COOPERATE);
+ rdp_send_control(RDP_CTL_REQUEST_CONTROL);
+ rdp_recv(&type); /* RDP_PDU_SYNCHRONIZE */
+ rdp_recv(&type); /* RDP_CTL_COOPERATE */
+ rdp_recv(&type); /* RDP_CTL_GRANT_CONTROL */
+ rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, 0, 0);
+ rdp_send_fonts(1);
+ rdp_send_fonts(2);
+ rdp_recv(&type); /* RDP_PDU_UNKNOWN 0x28 */
+ reset_order_state();
+}
+
+/* Process a pointer PDU */
+static void
+process_pointer_pdu(STREAM s)
+{
+ uint16 message_type;
+ uint16 x, y, width, height, cache_idx, masklen, datalen;
+ uint8 *mask, *data;
+ HCURSOR cursor;
+
+ in_uint16_le(s, message_type);
+ in_uint8s(s, 2); /* pad */
+
+ switch (message_type)
+ {
+ case RDP_POINTER_MOVE:
+ in_uint16_le(s, x);
+ in_uint16_le(s, y);
+ if (s_check(s))
+ ui_move_pointer(x, y);
+ break;
+
+ case RDP_POINTER_COLOR:
+ in_uint16_le(s, cache_idx);
+ in_uint16_le(s, x);
+ in_uint16_le(s, y);
+ in_uint16_le(s, width);
+ in_uint16_le(s, height);
+ in_uint16_le(s, masklen);
+ in_uint16_le(s, datalen);
+ in_uint8p(s, data, datalen);
+ in_uint8p(s, mask, masklen);
+ cursor = ui_create_cursor(x, y, width, height, mask, data);
+ ui_set_cursor(cursor);
+ cache_put_cursor(cache_idx, cursor);
+ break;
+
+ case RDP_POINTER_CACHED:
+ in_uint16_le(s, cache_idx);
+ ui_set_cursor(cache_get_cursor(cache_idx));
+ break;
+
+ default:
+ DEBUG(("Pointer message 0x%x\n", message_type));
+ }
+}
+
+/* Process bitmap updates */
+static void
+process_bitmap_updates(STREAM s)
+{
+ uint16 num_updates;
+ uint16 left, top, right, bottom, width, height;
+ uint16 cx, cy, bpp, Bpp, compress, bufsize, size;
+ uint8 *data, *bmpdata;
+ int i;
+
+ in_uint16_le(s, num_updates);
+
+ for (i = 0; i < num_updates; i++)
+ {
+ in_uint16_le(s, left);
+ in_uint16_le(s, top);
+ in_uint16_le(s, right);
+ in_uint16_le(s, bottom);
+ in_uint16_le(s, width);
+ in_uint16_le(s, height);
+ in_uint16_le(s, bpp);
+ Bpp = (bpp + 7) / 8;
+ in_uint16_le(s, compress);
+ in_uint16_le(s, bufsize);
+
+ cx = right - left + 1;
+ cy = bottom - top + 1;
+
+ DEBUG(("UPDATE(l=%d,t=%d,r=%d,b=%d,w=%d,h=%d,cmp=%d)\n",
+ left, top, right, bottom, width, height, compress));
+
+ if (!compress)
+ {
+ int y;
+ bmpdata = (uint8*)xmalloc(width * height * Bpp);
+ for (y = 0; y < height; y++)
+ {
+ in_uint8a(s, &bmpdata[(height - y - 1) * (width * Bpp)],
+ width * Bpp);
+ }
+ ui_paint_bitmap(left, top, cx, cy, width, height, bmpdata);
+ xfree(bmpdata);
+ continue;
+ }
+
+ in_uint8s(s, 2); /* pad */
+ in_uint16_le(s, size);
+ in_uint8s(s, 4); /* line_size, final_size */
+ in_uint8p(s, data, size);
+ bmpdata = (uint8*)xmalloc(width * height * Bpp);
+ if (bitmap_decompress(bmpdata, width, height, data, size, Bpp))
+ {
+ ui_paint_bitmap(left, top, cx, cy, width, height, bmpdata);
+ }
+ xfree(bmpdata);
+ }
+}
+
+/* Process a palette update */
+static void
+process_palette(STREAM s)
+{
+ COLOURENTRY *entry;
+ COLOURMAP map;
+ HCOLOURMAP hmap;
+ int i;
+ uint8 data[1536];
+
+ in_uint8s(s, 2); /* pad */
+ in_uint16_le(s, map.ncolours);
+ in_uint8s(s, 2); /* pad */
+
+ map.colours = (COLOURENTRY*)data;
+
+ for (i = 0; i < map.ncolours; i++)
+ {
+ entry = &map.colours[i];
+ in_uint8(s, entry->red);
+ in_uint8(s, entry->green);
+ in_uint8(s, entry->blue);
+ }
+ hmap = ui_create_colourmap(&map);
+ ui_set_colourmap(hmap);
+}
+
+/* Process an update PDU */
+static void
+process_update_pdu(STREAM s)
+{
+ uint16 update_type;
+
+ in_uint16_le(s, update_type);
+ ui_begin_update();
+ switch (update_type)
+ {
+ case RDP_UPDATE_ORDERS:
+ process_orders(s);
+ break;
+
+ case RDP_UPDATE_BITMAP:
+ process_bitmap_updates(s);
+ break;
+
+ case RDP_UPDATE_PALETTE:
+ process_palette(s);
+ break;
+
+ case RDP_UPDATE_SYNCHRONIZE:
+ break;
+
+ default:
+ unimpl("update %d\n", update_type);
+ }
+ ui_end_update();
+}
+
+/* Process data PDU */
+void
+process_data_pdu(STREAM s)
+{
+ uint8 data_pdu_type;
+
+ in_uint8s(s, 8); /* shareid, pad, streamid, length */
+ in_uint8(s, data_pdu_type);
+ in_uint8s(s, 3); /* compress_type, compress_len */
+
+ switch (data_pdu_type)
+ {
+ case RDP_DATA_PDU_UPDATE:
+ process_update_pdu(s);
+ break;
+
+ case RDP_DATA_PDU_POINTER:
+ process_pointer_pdu(s);
+ break;
+
+ case RDP_DATA_PDU_BELL:
+ ui_bell();
+ break;
+
+ case RDP_DATA_PDU_LOGON:
+ /* User logged on */
+ break;
+
+ default:
+ unimpl("data PDU %d\n", data_pdu_type);
+ }
+}
+
+/* Process incoming packets */
+BOOL
+rdp_main_loop(void)
+{
+ uint8 type;
+ STREAM s;
+ BOOL cont = True;
+ while (cont)
+ {
+ s = rdp_recv(&type);
+ if (s == NULL)
+ return False;
+ switch (type)
+ {
+ case RDP_PDU_DEMAND_ACTIVE:
+ process_demand_active(s);
+ break;
+ case RDP_PDU_DEACTIVATE:
+ break;
+ case RDP_PDU_DATA:
+ process_data_pdu(s);
+ break;
+ case 0:
+ break;
+ default:
+ unimpl("PDU %d\n", type);
+ }
+ cont = next_packet < s->end;
+ }
+ return True;
+}
+
+/* Establish a connection up to the RDP layer */
+BOOL
+rdp_connect(char *server, uint32 flags, char *domain, char *password,
+ char *command, char *directory)
+{
+ if (!sec_connect(server))
+ return False;
+
+ rdp_send_logon_info(flags, domain, username, password, command, directory);
+ return True;
+}
+
+/* Disconnect from the RDP layer */
+void
+rdp_disconnect(void)
+{
+ sec_disconnect();
+}
diff --git a/noncore/net/opierdesktop/secure.cpp b/noncore/net/opierdesktop/secure.cpp
new file mode 100644
index 0000000..5e50f8d
--- a/dev/null
+++ b/noncore/net/opierdesktop/secure.cpp
@@ -0,0 +1,658 @@
+/*
+ rdesktop: A Remote Desktop Protocol client.
+ Protocol services - RDP encryption and licensing
+ Copyright (C) Matthew Chapman 1999-2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "rdesktop.h"
+
+//#ifdef WITH_OPENSSL
+#include <openssl/rc4.h>
+#include <openssl/md5.h>
+#include <openssl/sha.h>
+#include <openssl/bn.h>
+//#else
+//#include "crypto/rc4.h"
+//#include "crypto/md5.h"
+//#include "crypto/sha.h"
+//#include "crypto/bn.h"
+//#endif
+
+extern char hostname[16];
+extern int g_width;
+extern int g_height;
+extern int keylayout;
+extern BOOL encryption;
+extern BOOL licence_issued;
+extern int server_bpp;
+
+static int rc4_key_len;
+static RC4_KEY rc4_decrypt_key;
+static RC4_KEY rc4_encrypt_key;
+
+static uint8 sec_sign_key[16];
+static uint8 sec_decrypt_key[16];
+static uint8 sec_encrypt_key[16];
+static uint8 sec_decrypt_update_key[16];
+static uint8 sec_encrypt_update_key[16];
+static uint8 sec_crypted_random[SEC_MODULUS_SIZE];
+
+/*
+ * General purpose 48-byte transformation, using two 32-byte salts (generally,
+ * a client and server salt) and a global salt value used for padding.
+ * Both SHA1 and MD5 algorithms are used.
+ */
+void
+sec_hash_48(uint8 * out, uint8 * in, uint8 * salt1, uint8 * salt2, uint8 salt)
+{
+ uint8 shasig[20];
+ uint8 pad[4];
+ SHA_CTX sha;
+ MD5_CTX md5;
+ int i;
+
+ for (i = 0; i < 3; i++)
+ {
+ memset(pad, salt + i, i + 1);
+
+ SHA1_Init(&sha);
+ SHA1_Update(&sha, pad, i + 1);
+ SHA1_Update(&sha, in, 48);
+ SHA1_Update(&sha, salt1, 32);
+ SHA1_Update(&sha, salt2, 32);
+ SHA1_Final(shasig, &sha);
+
+ MD5_Init(&md5);
+ MD5_Update(&md5, in, 48);
+ MD5_Update(&md5, shasig, 20);
+ MD5_Final(&out[i * 16], &md5);
+ }
+}
+
+/*
+ * Weaker 16-byte transformation, also using two 32-byte salts, but
+ * only using a single round of MD5.
+ */
+void
+sec_hash_16(uint8 * out, uint8 * in, uint8 * salt1, uint8 * salt2)
+{
+ MD5_CTX md5;
+
+ MD5_Init(&md5);
+ MD5_Update(&md5, in, 16);
+ MD5_Update(&md5, salt1, 32);
+ MD5_Update(&md5, salt2, 32);
+ MD5_Final(out, &md5);
+}
+
+/* Reduce key entropy from 64 to 40 bits */
+static void
+sec_make_40bit(uint8 * key)
+{
+ key[0] = 0xd1;
+ key[1] = 0x26;
+ key[2] = 0x9e;
+}
+
+/* Generate a session key and RC4 keys, given client and server randoms */
+static void
+sec_generate_keys(uint8 * client_key, uint8 * server_key, int rc4_key_size)
+{
+ uint8 session_key[48];
+ uint8 temp_hash[48];
+ uint8 input[48];
+
+ /* Construct input data to hash */
+ memcpy(input, client_key, 24);
+ memcpy(input + 24, server_key, 24);
+
+ /* Generate session key - two rounds of sec_hash_48 */
+ sec_hash_48(temp_hash, input, client_key, server_key, 65);
+ sec_hash_48(session_key, temp_hash, client_key, server_key, 88);
+
+ /* Store first 16 bytes of session key, for generating signatures */
+ memcpy(sec_sign_key, session_key, 16);
+
+ /* Generate RC4 keys */
+ sec_hash_16(sec_decrypt_key, &session_key[16], client_key, server_key);
+ sec_hash_16(sec_encrypt_key, &session_key[32], client_key, server_key);
+
+ if (rc4_key_size == 1)
+ {
+ DEBUG(("40-bit encryption enabled\n"));
+ sec_make_40bit(sec_sign_key);
+ sec_make_40bit(sec_decrypt_key);
+ sec_make_40bit(sec_encrypt_key);
+ rc4_key_len = 8;
+ }
+ else
+ {
+ DEBUG(("128-bit encryption enabled\n"));
+ rc4_key_len = 16;
+ }
+
+ /* Save initial RC4 keys as update keys */
+ memcpy(sec_decrypt_update_key, sec_decrypt_key, 16);
+ memcpy(sec_encrypt_update_key, sec_encrypt_key, 16);
+
+ /* Initialise RC4 state arrays */
+ RC4_set_key(&rc4_decrypt_key, rc4_key_len, sec_decrypt_key);
+ RC4_set_key(&rc4_encrypt_key, rc4_key_len, sec_encrypt_key);
+}
+
+static uint8 pad_54[40] = {
+ 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+ 54, 54, 54,
+ 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+ 54, 54, 54
+};
+
+static uint8 pad_92[48] = {
+ 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92,
+ 92, 92, 92, 92, 92, 92, 92,
+ 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92,
+ 92, 92, 92, 92, 92, 92, 92
+};
+
+/* Output a uint32 into a buffer (little-endian) */
+void
+buf_out_uint32(uint8 * buffer, uint32 value)
+{
+ buffer[0] = (value) & 0xff;
+ buffer[1] = (value >> 8) & 0xff;
+ buffer[2] = (value >> 16) & 0xff;
+ buffer[3] = (value >> 24) & 0xff;
+}
+
+/* Generate a signature hash, using a combination of SHA1 and MD5 */
+void
+sec_sign(uint8 * signature, int siglen, uint8 * session_key, int keylen, uint8 * data, int datalen)
+{
+ uint8 shasig[20];
+ uint8 md5sig[16];
+ uint8 lenhdr[4];
+ SHA_CTX sha;
+ MD5_CTX md5;
+
+ buf_out_uint32(lenhdr, datalen);
+
+ SHA1_Init(&sha);
+ SHA1_Update(&sha, session_key, keylen);
+ SHA1_Update(&sha, pad_54, 40);
+ SHA1_Update(&sha, lenhdr, 4);
+ SHA1_Update(&sha, data, datalen);
+ SHA1_Final(shasig, &sha);
+
+ MD5_Init(&md5);
+ MD5_Update(&md5, session_key, keylen);
+ MD5_Update(&md5, pad_92, 48);
+ MD5_Update(&md5, shasig, 20);
+ MD5_Final(md5sig, &md5);
+
+ memcpy(signature, md5sig, siglen);
+}
+
+/* Update an encryption key - similar to the signing process */
+static void
+sec_update(uint8 * key, uint8 * update_key)
+{
+ uint8 shasig[20];
+ SHA_CTX sha;
+ MD5_CTX md5;
+ RC4_KEY update;
+
+ SHA1_Init(&sha);
+ SHA1_Update(&sha, update_key, rc4_key_len);
+ SHA1_Update(&sha, pad_54, 40);
+ SHA1_Update(&sha, key, rc4_key_len);
+ SHA1_Final(shasig, &sha);
+
+ MD5_Init(&md5);
+ MD5_Update(&md5, update_key, rc4_key_len);
+ MD5_Update(&md5, pad_92, 48);
+ MD5_Update(&md5, shasig, 20);
+ MD5_Final(key, &md5);
+
+ RC4_set_key(&update, rc4_key_len, key);
+ RC4(&update, rc4_key_len, key, key);
+
+ if (rc4_key_len == 8)
+ sec_make_40bit(key);
+}
+
+/* Encrypt data using RC4 */
+static void
+sec_encrypt(uint8 * data, int length)
+{
+ static int use_count;
+
+ if (use_count == 4096)
+ {
+ sec_update(sec_encrypt_key, sec_encrypt_update_key);
+ RC4_set_key(&rc4_encrypt_key, rc4_key_len, sec_encrypt_key);
+ use_count = 0;
+ }
+
+ RC4(&rc4_encrypt_key, length, data, data);
+ use_count++;
+}
+
+/* Decrypt data using RC4 */
+static void
+sec_decrypt(uint8 * data, int length)
+{
+ static int use_count;
+
+ if (use_count == 4096)
+ {
+ sec_update(sec_decrypt_key, sec_decrypt_update_key);
+ RC4_set_key(&rc4_decrypt_key, rc4_key_len, sec_decrypt_key);
+ use_count = 0;
+ }
+
+ RC4(&rc4_decrypt_key, length, data, data);
+ use_count++;
+}
+
+static void
+reverse(uint8 * p, int len)
+{
+ int i, j;
+ uint8 temp;
+
+ for (i = 0, j = len - 1; i < j; i++, j--)
+ {
+ temp = p[i];
+ p[i] = p[j];
+ p[j] = temp;
+ }
+}
+
+/* Perform an RSA public key encryption operation */
+static void
+sec_rsa_encrypt(uint8 * out, uint8 * in, int len, uint8 * modulus, uint8 * exponent)
+{
+ BN_CTX *ctx;
+ BIGNUM mod, exp, x, y;
+ uint8 inr[SEC_MODULUS_SIZE];
+ int outlen;
+
+ reverse(modulus, SEC_MODULUS_SIZE);
+ reverse(exponent, SEC_EXPONENT_SIZE);
+ memcpy(inr, in, len);
+ reverse(inr, len);
+
+ ctx = BN_CTX_new();
+ BN_init(&mod);
+ BN_init(&exp);
+ BN_init(&x);
+ BN_init(&y);
+
+ BN_bin2bn(modulus, SEC_MODULUS_SIZE, &mod);
+ BN_bin2bn(exponent, SEC_EXPONENT_SIZE, &exp);
+ BN_bin2bn(inr, len, &x);
+ BN_mod_exp(&y, &x, &exp, &mod, ctx);
+ outlen = BN_bn2bin(&y, out);
+ reverse(out, outlen);
+ if (outlen < SEC_MODULUS_SIZE)
+ memset(out + outlen, 0, SEC_MODULUS_SIZE - outlen);
+
+ BN_free(&y);
+ BN_clear_free(&x);
+ BN_free(&exp);
+ BN_free(&mod);
+ BN_CTX_free(ctx);
+}
+
+/* Initialise secure transport packet */
+STREAM
+sec_init(uint32 flags, int maxlen)
+{
+ int hdrlen;
+ STREAM s;
+
+ if (!licence_issued)
+ hdrlen = (flags & SEC_ENCRYPT) ? 12 : 4;
+ else
+ hdrlen = (flags & SEC_ENCRYPT) ? 12 : 0;
+ s = mcs_init(maxlen + hdrlen);
+ s_push_layer(s, sec_hdr, hdrlen);
+
+ return s;
+}
+
+/* Transmit secure transport packet */
+void
+sec_send(STREAM s, uint32 flags)
+{
+ int datalen;
+
+ s_pop_layer(s, sec_hdr);
+ if (!licence_issued || (flags & SEC_ENCRYPT))
+ out_uint32_le(s, flags);
+
+ if (flags & SEC_ENCRYPT)
+ {
+ flags &= ~SEC_ENCRYPT;
+ datalen = s->end - s->p - 8;
+
+#if WITH_DEBUG
+ DEBUG(("Sending encrypted packet:\n"));
+ hexdump(s->p + 8, datalen);
+#endif
+
+ sec_sign(s->p, 8, sec_sign_key, rc4_key_len, s->p + 8, datalen);
+ sec_encrypt(s->p + 8, datalen);
+ }
+
+ mcs_send(s);
+}
+
+/* Transfer the client random to the server */
+static void
+sec_establish_key(void)
+{
+ uint32 length = SEC_MODULUS_SIZE + SEC_PADDING_SIZE;
+ uint32 flags = SEC_CLIENT_RANDOM;
+ STREAM s;
+
+ s = sec_init(flags, 76);
+
+ out_uint32_le(s, length);
+ out_uint8p(s, sec_crypted_random, SEC_MODULUS_SIZE);
+ out_uint8s(s, SEC_PADDING_SIZE);
+
+ s_mark_end(s);
+ sec_send(s, flags);
+}
+
+/* Output connect initial data blob */
+static void
+sec_out_mcs_data(STREAM s)
+{
+ int hostlen = 2 * strlen(hostname);
+
+ if (hostlen > 30)
+ hostlen = 30;
+
+ out_uint16_be(s, 5); /* unknown */
+ out_uint16_be(s, 0x14);
+ out_uint8(s, 0x7c);
+ out_uint16_be(s, 1);
+
+ out_uint16_be(s, (158 | 0x8000)); /* remaining length */
+
+ out_uint16_be(s, 8); /* length? */
+ out_uint16_be(s, 16);
+ out_uint8(s, 0);
+ out_uint16_le(s, 0xc001);
+ out_uint8(s, 0);
+
+ out_uint32_le(s, 0x61637544); /* "Duca" ?! */
+ out_uint16_be(s, (144 | 0x8000)); /* remaining length */
+
+ /* Client information */
+ out_uint16_le(s, SEC_TAG_CLI_INFO);
+ out_uint16_le(s, 136); /* length */
+ out_uint16_le(s, 1);
+ out_uint16_le(s, 8);
+ out_uint16_le(s, g_width);
+ out_uint16_le(s, g_height);
+ out_uint16_le(s, 0xca01);
+ out_uint16_le(s, 0xaa03);
+ out_uint32_le(s, keylayout);
+ out_uint32_le(s, 419); /* client build? we are 419 compatible :-) */
+
+ /* Unicode name of client, padded to 32 bytes */
+ rdp_out_unistr(s, hostname, hostlen);
+ out_uint8s(s, 30 - hostlen);
+
+ out_uint32_le(s, 4);
+ out_uint32(s, 0);
+ out_uint32_le(s, 12);
+ out_uint8s(s, 64); /* reserved? 4 + 12 doublewords */
+
+ switch (server_bpp)
+ {
+ case 8:
+ out_uint16_le(s, 0xca01);
+ break;
+ case 15:
+ out_uint16_le(s, 0xca02);
+ break;
+ case 16:
+ out_uint16_le(s, 0xca03);
+ break;
+ case 24:
+ out_uint16_le(s, 0xca04);
+ break;
+ }
+ out_uint16(s, 0);
+
+ /* Client encryption settings */
+ out_uint16_le(s, SEC_TAG_CLI_CRYPT);
+ out_uint16_le(s, 8); /* length */
+ out_uint32_le(s, encryption ? 0x3 : 0); /* encryption supported, 128-bit supported */
+ s_mark_end(s);
+}
+
+/* Parse a public key structure */
+static BOOL
+sec_parse_public_key(STREAM s, uint8 ** modulus, uint8 ** exponent)
+{
+ uint32 magic, modulus_len;
+
+ in_uint32_le(s, magic);
+ if (magic != SEC_RSA_MAGIC)
+ {
+ error("RSA magic 0x%x\n", magic);
+ return False;
+ }
+
+ in_uint32_le(s, modulus_len);
+ if (modulus_len != SEC_MODULUS_SIZE + SEC_PADDING_SIZE)
+ {
+ error("modulus len 0x%x\n", modulus_len);
+ return False;
+ }
+
+ in_uint8s(s, 8); /* modulus_bits, unknown */
+ in_uint8p(s, *exponent, SEC_EXPONENT_SIZE);
+ in_uint8p(s, *modulus, SEC_MODULUS_SIZE);
+ in_uint8s(s, SEC_PADDING_SIZE);
+
+ return s_check(s);
+}
+
+/* Parse a crypto information structure */
+static BOOL
+sec_parse_crypt_info(STREAM s, uint32 * rc4_key_size,
+ uint8 ** server_random, uint8 ** modulus, uint8 ** exponent)
+{
+ uint32 crypt_level, random_len, rsa_info_len;
+ uint16 tag, length;
+ uint8 *next_tag, *end;
+
+ in_uint32_le(s, *rc4_key_size); /* 1 = 40-bit, 2 = 128-bit */
+ in_uint32_le(s, crypt_level); /* 1 = low, 2 = medium, 3 = high */
+ if (crypt_level == 0) /* no encryptation */
+ return False;
+ in_uint32_le(s, random_len);
+ in_uint32_le(s, rsa_info_len);
+
+ if (random_len != SEC_RANDOM_SIZE)
+ {
+ error("random len %d\n", random_len);
+ return False;
+ }
+
+ in_uint8p(s, *server_random, random_len);
+
+ /* RSA info */
+ end = s->p + rsa_info_len;
+ if (end > s->end)
+ return False;
+
+ in_uint8s(s, 12); /* unknown */
+
+ while (s->p < end)
+ {
+ in_uint16_le(s, tag);
+ in_uint16_le(s, length);
+
+ next_tag = s->p + length;
+
+ switch (tag)
+ {
+ case SEC_TAG_PUBKEY:
+ if (!sec_parse_public_key(s, modulus, exponent))
+ return False;
+
+ break;
+
+ case SEC_TAG_KEYSIG:
+ /* Is this a Microsoft key that we just got? */
+ /* Care factor: zero! */
+ break;
+
+ default:
+ unimpl("crypt tag 0x%x\n", tag);
+ }
+
+ s->p = next_tag;
+ }
+
+ return s_check_end(s);
+}
+
+/* Process crypto information blob */
+static void
+sec_process_crypt_info(STREAM s)
+{
+ uint8 *server_random, *modulus, *exponent;
+ uint8 client_random[SEC_RANDOM_SIZE];
+ uint32 rc4_key_size;
+
+ if (!sec_parse_crypt_info(s, &rc4_key_size, &server_random, &modulus, &exponent))
+ return;
+
+ /* Generate a client random, and hence determine encryption keys */
+ generate_random(client_random);
+ sec_rsa_encrypt(sec_crypted_random, client_random, SEC_RANDOM_SIZE, modulus, exponent);
+ sec_generate_keys(client_random, server_random, rc4_key_size);
+}
+
+/* Process connect response data blob */
+static void
+sec_process_mcs_data(STREAM s)
+{
+ uint16 tag, length;
+ uint8 *next_tag;
+ uint8 len;
+
+ in_uint8s(s, 21); /* header */
+ in_uint8(s, len);
+ if (len & 0x80)
+ in_uint8(s, len);
+
+ while (s->p < s->end)
+ {
+ in_uint16_le(s, tag);
+ in_uint16_le(s, length);
+
+ if (length <= 4)
+ return;
+
+ next_tag = s->p + length - 4;
+
+ switch (tag)
+ {
+ case SEC_TAG_SRV_INFO:
+ case SEC_TAG_SRV_3:
+ break;
+
+ case SEC_TAG_SRV_CRYPT:
+ sec_process_crypt_info(s);
+ break;
+
+ default:
+ unimpl("response tag 0x%x\n", tag);
+ }
+
+ s->p = next_tag;
+ }
+}
+
+/* Receive secure transport packet */
+STREAM
+sec_recv(void)
+{
+ uint32 sec_flags;
+ STREAM s;
+
+ while ((s = mcs_recv()) != NULL)
+ {
+ if (encryption || !licence_issued)
+ {
+ in_uint32_le(s, sec_flags);
+
+ if (sec_flags & SEC_LICENCE_NEG)
+ {
+ licence_process(s);
+ continue;
+ }
+
+ if (sec_flags & SEC_ENCRYPT)
+ {
+ in_uint8s(s, 8); /* signature */
+ sec_decrypt(s->p, s->end - s->p);
+ }
+ }
+
+ return s;
+ }
+
+ return NULL;
+}
+
+/* Establish a secure connection */
+BOOL
+sec_connect(char *server)
+{
+ struct stream mcs_data;
+
+ /* We exchange some RDP data during the MCS-Connect */
+ mcs_data.size = 512;
+ mcs_data.p = mcs_data.data = (unsigned char*)xmalloc(mcs_data.size);
+ sec_out_mcs_data(&mcs_data);
+
+ if (!mcs_connect(server, &mcs_data))
+ return False;
+
+ sec_process_mcs_data(&mcs_data);
+ if (encryption)
+ sec_establish_key();
+ xfree(mcs_data.data);
+ return True;
+}
+
+/* Disconnect a connection */
+void
+sec_disconnect(void)
+{
+ mcs_disconnect();
+}
diff --git a/noncore/net/opierdesktop/tcp.cpp b/noncore/net/opierdesktop/tcp.cpp
new file mode 100644
index 0000000..0a2ca3e
--- a/dev/null
+++ b/noncore/net/opierdesktop/tcp.cpp
@@ -0,0 +1,181 @@
+/*
+ rdesktop: A Remote Desktop Protocol client.
+ Protocol services - TCP layer
+ Copyright (C) Matthew Chapman 1999-2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <unistd.h> /* select read write close */
+#include <sys/socket.h> /* socket connect setsockopt */
+#include <sys/time.h> /* timeval */
+#include <netdb.h> /* gethostbyname */
+#include <netinet/in.h> /* sockaddr_in */
+#include <netinet/tcp.h> /* TCP_NODELAY */
+#include <arpa/inet.h> /* inet_addr */
+#include <fcntl.h>
+#include <errno.h> /* errno */
+#include "rdesktop.h"
+
+#ifndef INADDR_NONE
+#define INADDR_NONE ((unsigned long) -1)
+#endif
+
+static int sock;
+static struct stream in;
+static struct stream out;
+extern int tcp_port_rdp;
+
+/* Initialise TCP transport data packet */
+STREAM
+tcp_init(unsigned int maxlen)
+{
+ if (maxlen > out.size)
+ {
+ out.data = (unsigned char*)xrealloc(out.data, maxlen);
+ out.size = maxlen;
+ }
+
+ out.p = out.data;
+ out.end = out.data + out.size;
+ return &out;
+}
+
+/* Send TCP transport data packet */
+void
+tcp_send(STREAM s)
+{
+ int length = s->end - s->data;
+ int sent, total = 0;
+
+ while (total < length)
+ {
+ sent = send(sock, s->data + total, length - total, 0);
+ if (sent == -1 && errno == EWOULDBLOCK)
+ {
+ usleep(1000);
+ }
+ else if (sent <= 0)
+ {
+ error("send: %s\n", strerror(errno));
+ return;
+ }
+ else
+ total += sent;
+ }
+}
+
+/* Receive a message on the TCP layer */
+STREAM
+tcp_recv(unsigned int length)
+{
+ int rcvd = 0;
+
+ if (length > in.size)
+ {
+ in.data = (unsigned char*)xrealloc(in.data, length);
+ in.size = length;
+ }
+
+ in.end = in.p = in.data;
+
+ while (length > 0)
+ {
+ if (!ui_select(sock))
+ /* User quit */
+ return NULL;
+
+ rcvd = recv(sock, in.end, length, 0);
+ if (rcvd == -1 && errno == EWOULDBLOCK)
+ {
+ usleep(1000);
+ }
+ else if (rcvd == -1)
+ {
+ error("recv: %s\n", strerror(errno));
+ return NULL;
+ }
+ else if (rcvd == 0)
+ return NULL;
+ else
+ {
+ in.end += rcvd;
+ length -= rcvd;
+ }
+ }
+
+ return &in;
+}
+
+/* Establish a connection on the TCP layer */
+BOOL
+tcp_connect(char *server)
+{
+ struct hostent *nslookup;
+ struct sockaddr_in servaddr;
+ int l_true = 1;
+
+ if ((nslookup = gethostbyname(server)) != NULL)
+ {
+ memcpy(&servaddr.sin_addr, nslookup->h_addr, sizeof(servaddr.sin_addr));
+ }
+ else if ((servaddr.sin_addr.s_addr = inet_addr(server)) == INADDR_NONE)
+ {
+ error("%s: unable to resolve host\n", server);
+ return False;
+ }
+
+ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+ {
+ error("socket: %s\n", strerror(errno));
+ return False;
+ }
+
+ servaddr.sin_family = AF_INET;
+ servaddr.sin_port = htons(tcp_port_rdp);
+
+ if (connect(sock, (struct sockaddr *) &servaddr, sizeof(struct sockaddr)) < 0)
+ {
+ error("connect: %s\n", strerror(errno));
+ close(sock);
+ return False;
+ }
+
+ /* set non blocking */
+ {
+ int op;
+ op = fcntl(sock, F_GETFL);
+ op |= O_NONBLOCK;
+ fcntl(sock, F_SETFL, op);
+ }
+
+// fcntl(sock, O_NONBLOCK);
+ setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void *) &l_true, sizeof(l_true));
+
+ in.size = 4096;
+ in.data = (unsigned char*)xmalloc(in.size);
+
+ out.size = 4096;
+ out.data = (unsigned char*)xmalloc(out.size);
+
+ return True;
+}
+
+/* Disconnect on the TCP layer */
+void
+tcp_disconnect(void)
+{
+ close(sock);
+}
diff --git a/noncore/net/opierdesktop/types.h b/noncore/net/opierdesktop/types.h
new file mode 100644
index 0000000..4cb59e6
--- a/dev/null
+++ b/noncore/net/opierdesktop/types.h
@@ -0,0 +1,110 @@
+/*
+ rdesktop: A Remote Desktop Protocol client.
+ Common data types
+ Copyright (C) Matthew Chapman 1999-2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+typedef int BOOL;
+
+#ifndef True
+#define True (1)
+#define False (0)
+#endif
+
+typedef unsigned char uint8;
+typedef signed char sint8;
+typedef unsigned short uint16;
+typedef signed short sint16;
+typedef unsigned int uint32;
+typedef signed int sint32;
+
+typedef void *HBITMAP;
+typedef void *HGLYPH;
+typedef void *HCOLOURMAP;
+typedef void *HCURSOR;
+
+typedef struct _COLOURENTRY
+{
+ uint8 red;
+ uint8 green;
+ uint8 blue;
+
+}
+COLOURENTRY;
+
+typedef struct _COLOURMAP
+{
+ uint16 ncolours;
+ COLOURENTRY *colours;
+
+}
+COLOURMAP;
+
+typedef struct _BOUNDS
+{
+ sint16 left;
+ sint16 top;
+ sint16 right;
+ sint16 bottom;
+
+}
+BOUNDS;
+
+typedef struct _PEN
+{
+ uint8 style;
+ uint8 width;
+ uint32 colour;
+
+}
+PEN;
+
+typedef struct _BRUSH
+{
+ uint8 xorigin;
+ uint8 yorigin;
+ uint8 style;
+ uint8 pattern[8];
+
+}
+BRUSH;
+
+typedef struct _FONTGLYPH
+{
+ sint16 offset;
+ sint16 baseline;
+ uint16 width;
+ uint16 height;
+ HBITMAP pixmap;
+
+}
+FONTGLYPH;
+
+typedef struct _DATABLOB
+{
+ void *data;
+ int size;
+
+}
+DATABLOB;
+
+typedef struct _key_translation
+{
+ uint8 scancode;
+ uint16 modifiers;
+}
+key_translation;