summaryrefslogtreecommitdiffstats
path: root/uirdesktop
diff options
context:
space:
mode:
Diffstat (limited to 'uirdesktop')
-rw-r--r--uirdesktop/bitmap.c2274
-rwxr-xr-xuirdesktop/bsops.c822
-rwxr-xr-xuirdesktop/bsops.h49
-rw-r--r--uirdesktop/cache.c24
-rwxr-xr-xuirdesktop/constants.h435
-rwxr-xr-xuirdesktop/example-winrdesktop.ini8
-rwxr-xr-xuirdesktop/licence.c345
-rwxr-xr-xuirdesktop/makefile_win3219
-rw-r--r--uirdesktop/mcs.c4
-rw-r--r--uirdesktop/orders.c48
-rwxr-xr-xuirdesktop/proto.h315
-rw-r--r--uirdesktop/pstcache.c2
-rw-r--r--uirdesktop/rdesktop.h23
-rw-r--r--uirdesktop/rdp.c2904
-rw-r--r--uirdesktop/secure.c330
-rwxr-xr-xuirdesktop/ssl_calls.c1644
-rw-r--r--uirdesktop/tcp.c61
-rw-r--r--uirdesktop/types.h40
-rwxr-xr-xuirdesktop/uimain.c1124
-rwxr-xr-xuirdesktop/uimain.h83
-rwxr-xr-xuirdesktop/win32.c1733
21 files changed, 9590 insertions, 2697 deletions
diff --git a/uirdesktop/bitmap.c b/uirdesktop/bitmap.c
index 18e0cee7..e9e4ed3a 100644
--- a/uirdesktop/bitmap.c
+++ b/uirdesktop/bitmap.c
@@ -1,1021 +1,1253 @@
-/* -*- c-basic-offset: 8 -*-
- rdesktop: A Remote Desktop Protocol client.
- Bitmap decompression routines
- Copyright (C) Matthew Chapman 1999-2005
-
- 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.
-*/
-
-/* three seperate function for speed when decompressing the bitmaps */
-/* when modifing one function make the change in the others */
-/* comment out #define BITMAP_SPEED_OVER_SIZE below for one slower function */
-/* j@american-data.com */
-
-#define BITMAP_SPEED_OVER_SIZE
-
-/* indent is confused by this file */
-/* *INDENT-OFF* */
-
-#include "rdesktop.h"
-
-#define CVAL(p) (*(p++))
-#ifdef NEED_ALIGN
-#ifdef L_ENDIAN
-#define CVAL2(p, v) { v = (*(p++)); v |= (*(p++)) << 8; }
-#else
-#define CVAL2(p, v) { v = (*(p++)) << 8; v |= (*(p++)); }
-#endif /* L_ENDIAN */
-#else
-#define CVAL2(p, v) { v = (*((uint16*)p)); p += 2; }
-#endif /* NEED_ALIGN */
-
-#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; \
- } \
-}
-
-#ifdef BITMAP_SPEED_OVER_SIZE
-
-/* 1 byte bitmap decompress */
-static BOOL
-bitmap_decompress1(uint8 * output, int width, int height, uint8 * input, int size)
-{
- uint8 *end = input + size;
- uint8 *prevline = NULL, *line = NULL;
- int opcode, count, offset, isfillormix, x = width;
- int lastopcode = -1, insertmix = False, bicolour = False;
- uint8 code;
- uint8 colour1 = 0, colour2 = 0;
- uint8 mixmask, mask = 0;
- uint8 mix = 0xff;
- 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 = CVAL(input);
- case 3: /* Colour */
- colour2 = CVAL(input);
- break;
- case 6: /* SetMix/Mix */
- case 7: /* SetMix/FillOrMix */
- mix = CVAL(input);
- 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;
- }
- switch (opcode)
- {
- case 0: /* Fill */
- if (insertmix)
- {
- if (prevline == NULL)
- line[x] = mix;
- else
- line[x] = prevline[x] ^ mix;
- insertmix = False;
- count--;
- x++;
- }
- if (prevline == NULL)
- {
- REPEAT(line[x] = 0)
- }
- else
- {
- REPEAT(line[x] = prevline[x])
- }
- break;
- case 1: /* Mix */
- if (prevline == NULL)
- {
- REPEAT(line[x] = mix)
- }
- else
- {
- REPEAT(line[x] = prevline[x] ^ mix)
- }
- break;
- case 2: /* Fill or Mix */
- if (prevline == NULL)
- {
- REPEAT
- (
- MASK_UPDATE();
- if (mask & mixmask)
- line[x] = mix;
- else
- line[x] = 0;
- )
- }
- else
- {
- REPEAT
- (
- MASK_UPDATE();
- if (mask & mixmask)
- line[x] = prevline[x] ^ mix;
- else
- line[x] = prevline[x];
- )
- }
- break;
- case 3: /* Colour */
- REPEAT(line[x] = colour2)
- break;
- case 4: /* Copy */
- REPEAT(line[x] = CVAL(input))
- break;
- case 8: /* Bicolour */
- REPEAT
- (
- if (bicolour)
- {
- line[x] = colour2;
- bicolour = False;
- }
- else
- {
- line[x] = colour1;
- bicolour = True; count++;
- }
- )
- break;
- case 0xd: /* White */
- REPEAT(line[x] = 0xff)
- break;
- case 0xe: /* Black */
- REPEAT(line[x] = 0)
- break;
- default:
- unimpl("bitmap opcode 0x%x\n", opcode);
- return False;
- }
- }
- }
- return True;
-}
-
-/* 2 byte bitmap decompress */
-static BOOL
-bitmap_decompress2(uint8 * output, int width, int height, uint8 * input, int size)
-{
- uint8 *end = input + size;
- uint16 *prevline = NULL, *line = NULL;
- int opcode, count, offset, isfillormix, x = width;
- int lastopcode = -1, insertmix = False, bicolour = False;
- uint8 code;
- uint16 colour1 = 0, colour2 = 0;
- uint8 mixmask, mask = 0;
- uint16 mix = 0xffff;
- 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 */
- CVAL2(input, colour1);
- case 3: /* Colour */
- CVAL2(input, colour2);
- break;
- case 6: /* SetMix/Mix */
- case 7: /* SetMix/FillOrMix */
- CVAL2(input, mix);
- 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 = ((uint16 *) output) + height * width;
- }
- switch (opcode)
- {
- case 0: /* Fill */
- if (insertmix)
- {
- if (prevline == NULL)
- line[x] = mix;
- else
- line[x] = prevline[x] ^ mix;
- insertmix = False;
- count--;
- x++;
- }
- if (prevline == NULL)
- {
- REPEAT(line[x] = 0)
- }
- else
- {
- REPEAT(line[x] = prevline[x])
- }
- break;
- case 1: /* Mix */
- if (prevline == NULL)
- {
- REPEAT(line[x] = mix)
- }
- else
- {
- REPEAT(line[x] = prevline[x] ^ mix)
- }
- break;
- case 2: /* Fill or Mix */
- if (prevline == NULL)
- {
- REPEAT
- (
- MASK_UPDATE();
- if (mask & mixmask)
- line[x] = mix;
- else
- line[x] = 0;
- )
- }
- else
- {
- REPEAT
- (
- MASK_UPDATE();
- if (mask & mixmask)
- line[x] = prevline[x] ^ mix;
- else
- line[x] = prevline[x];
- )
- }
- break;
- case 3: /* Colour */
- REPEAT(line[x] = colour2)
- break;
- case 4: /* Copy */
- REPEAT(CVAL2(input, line[x]))
- break;
- case 8: /* Bicolour */
- REPEAT
- (
- if (bicolour)
- {
- line[x] = colour2;
- bicolour = False;
- }
- else
- {
- line[x] = colour1;
- bicolour = True;
- count++;
- }
- )
- break;
- case 0xd: /* White */
- REPEAT(line[x] = 0xffff)
- break;
- case 0xe: /* Black */
- REPEAT(line[x] = 0)
- break;
- default:
- unimpl("bitmap opcode 0x%x\n", opcode);
- return False;
- }
- }
- }
- return True;
-}
-
-/* 3 byte bitmap decompress */
-static BOOL
-bitmap_decompress3(uint8 * output, int width, int height, uint8 * input, int size)
-{
- uint8 *end = input + size;
- uint8 *prevline = NULL, *line = NULL;
- int opcode, count, offset, isfillormix, x = width;
- int lastopcode = -1, insertmix = False, bicolour = False;
- uint8 code;
- uint8 colour1[3] = {0, 0, 0}, colour2[3] = {0, 0, 0};
- uint8 mixmask, mask = 0;
- uint8 mix[3] = {0xff, 0xff, 0xff};
- 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[0] = CVAL(input);
- colour1[1] = CVAL(input);
- colour1[2] = CVAL(input);
- case 3: /* Colour */
- colour2[0] = CVAL(input);
- colour2[1] = CVAL(input);
- colour2[2] = CVAL(input);
- break;
- case 6: /* SetMix/Mix */
- case 7: /* SetMix/FillOrMix */
- mix[0] = CVAL(input);
- mix[1] = CVAL(input);
- mix[2] = CVAL(input);
- 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 * 3);
- }
- switch (opcode)
- {
- case 0: /* Fill */
- if (insertmix)
- {
- if (prevline == NULL)
- {
- line[x * 3] = mix[0];
- line[x * 3 + 1] = mix[1];
- line[x * 3 + 2] = mix[2];
- }
- else
- {
- line[x * 3] =
- prevline[x * 3] ^ mix[0];
- line[x * 3 + 1] =
- prevline[x * 3 + 1] ^ mix[1];
- line[x * 3 + 2] =
- prevline[x * 3 + 2] ^ mix[2];
- }
- insertmix = False;
- count--;
- x++;
- }
- if (prevline == NULL)
- {
- REPEAT
- (
- line[x * 3] = 0;
- line[x * 3 + 1] = 0;
- line[x * 3 + 2] = 0;
- )
- }
- else
- {
- REPEAT
- (
- line[x * 3] = prevline[x * 3];
- line[x * 3 + 1] = prevline[x * 3 + 1];
- line[x * 3 + 2] = prevline[x * 3 + 2];
- )
- }
- break;
- case 1: /* Mix */
- if (prevline == NULL)
- {
- REPEAT
- (
- line[x * 3] = mix[0];
- line[x * 3 + 1] = mix[1];
- line[x * 3 + 2] = mix[2];
- )
- }
- else
- {
- REPEAT
- (
- line[x * 3] =
- prevline[x * 3] ^ mix[0];
- line[x * 3 + 1] =
- prevline[x * 3 + 1] ^ mix[1];
- line[x * 3 + 2] =
- prevline[x * 3 + 2] ^ mix[2];
- )
- }
- break;
- case 2: /* Fill or Mix */
- if (prevline == NULL)
- {
- REPEAT
- (
- MASK_UPDATE();
- if (mask & mixmask)
- {
- line[x * 3] = mix[0];
- line[x * 3 + 1] = mix[1];
- line[x * 3 + 2] = mix[2];
- }
- else
- {
- line[x * 3] = 0;
- line[x * 3 + 1] = 0;
- line[x * 3 + 2] = 0;
- }
- )
- }
- else
- {
- REPEAT
- (
- MASK_UPDATE();
- if (mask & mixmask)
- {
- line[x * 3] =
- prevline[x * 3] ^ mix [0];
- line[x * 3 + 1] =
- prevline[x * 3 + 1] ^ mix [1];
- line[x * 3 + 2] =
- prevline[x * 3 + 2] ^ mix [2];
- }
- else
- {
- line[x * 3] =
- prevline[x * 3];
- line[x * 3 + 1] =
- prevline[x * 3 + 1];
- line[x * 3 + 2] =
- prevline[x * 3 + 2];
- }
- )
- }
- break;
- case 3: /* Colour */
- REPEAT
- (
- line[x * 3] = colour2 [0];
- line[x * 3 + 1] = colour2 [1];
- line[x * 3 + 2] = colour2 [2];
- )
- break;
- case 4: /* Copy */
- REPEAT
- (
- line[x * 3] = CVAL(input);
- line[x * 3 + 1] = CVAL(input);
- line[x * 3 + 2] = CVAL(input);
- )
- break;
- case 8: /* Bicolour */
- REPEAT
- (
- if (bicolour)
- {
- line[x * 3] = colour2[0];
- line[x * 3 + 1] = colour2[1];
- line[x * 3 + 2] = colour2[2];
- bicolour = False;
- }
- else
- {
- line[x * 3] = colour1[0];
- line[x * 3 + 1] = colour1[1];
- line[x * 3 + 2] = colour1[2];
- bicolour = True;
- count++;
- }
- )
- break;
- case 0xd: /* White */
- REPEAT
- (
- line[x * 3] = 0xff;
- line[x * 3 + 1] = 0xff;
- line[x * 3 + 2] = 0xff;
- )
- break;
- case 0xe: /* Black */
- REPEAT
- (
- line[x * 3] = 0;
- line[x * 3 + 1] = 0;
- line[x * 3 + 2] = 0;
- )
- break;
- default:
- unimpl("bitmap opcode 0x%x\n", opcode);
- return False;
- }
- }
- }
- return True;
-}
-
-#else
-
-static uint32
-cvalx(uint8 **input, int Bpp)
-{
- uint32 rv = 0;
- memcpy(&rv, *input, Bpp);
- *input += Bpp;
- return rv;
-}
-
-static void
-setli(uint8 *input, int offset, uint32 value, int Bpp)
-{
- input += offset * Bpp;
- memcpy(input, &value, Bpp);
-}
-
-static uint32
-getli(uint8 *input, int offset, int Bpp)
-{
- uint32 rv = 0;
- input += offset * Bpp;
- memcpy(&rv, input, Bpp);
- return rv;
-}
-
-static BOOL
-bitmap_decompressx(uint8 *output, int width, int height, uint8 *input, int size, int Bpp)
-{
- uint8 *end = input + size;
- uint8 *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;
-}
-
-#endif
-
-/* main decompress function */
-BOOL
-bitmap_decompress(uint8 * output, int width, int height, uint8 * input, int size, int Bpp)
-{
-#ifdef BITMAP_SPEED_OVER_SIZE
- BOOL rv = False;
- switch (Bpp)
- {
- case 1:
- rv = bitmap_decompress1(output, width, height, input, size);
- break;
- case 2:
- rv = bitmap_decompress2(output, width, height, input, size);
- break;
- case 3:
- rv = bitmap_decompress3(output, width, height, input, size);
- break;
- }
-#else
- BOOL rv;
- rv = bitmap_decompressx(output, width, height, input, size, Bpp);
-#endif
- return rv;
-}
-
-/* *INDENT-ON* */
+/* -*- c-basic-offset: 8 -*-
+ rdesktop: A Remote Desktop Protocol client.
+ Bitmap decompression routines
+ Copyright (C) Matthew Chapman 1999-2005
+
+ 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.
+*/
+
+/* three seperate function for speed when decompressing the bitmaps */
+/* when modifing one function make the change in the others */
+/* comment out #define BITMAP_SPEED_OVER_SIZE below for one slower function */
+/* j@american-data.com */
+
+/* indent is confused by this file */
+/* *INDENT-OFF* */
+
+#include "rdesktop.h"
+#include "uimain.h"
+
+#define CVAL(p) (*(p++))
+#ifdef NEED_ALIGN
+#ifdef L_ENDIAN
+#define CVAL2(p, v) { v = (*(p++)); v |= (*(p++)) << 8; }
+#else
+#define CVAL2(p, v) { v = (*(p++)) << 8; v |= (*(p++)); }
+#endif /* L_ENDIAN */
+#else
+#define CVAL2(p, v) { v = (*((uint16*)p)); p += 2; }
+#endif /* NEED_ALIGN */
+
+#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; \
+ } \
+}
+
+/* 1 byte bitmap decompress */
+static BOOL
+bitmap_decompress1(uint8 * output, int width, int height, uint8 * input, int size)
+{
+ uint8 *end = input + size;
+ uint8 *prevline = NULL, *line = NULL;
+ int opcode, count, offset, isfillormix, x = width;
+ int lastopcode = -1, insertmix = False, bicolour = False;
+ uint8 code;
+ uint8 colour1 = 0, colour2 = 0;
+ uint8 mixmask, mask = 0;
+ uint8 mix = 0xff;
+ int fom_mask;
+
+ 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 = CVAL(input);
+ case 3: /* Colour */
+ colour2 = CVAL(input);
+ break;
+ case 6: /* SetMix/Mix */
+ case 7: /* SetMix/FillOrMix */
+ mix = CVAL(input);
+ 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;
+ }
+ switch (opcode)
+ {
+ case 0: /* Fill */
+ if (insertmix)
+ {
+ if (prevline == NULL)
+ line[x] = mix;
+ else
+ line[x] = prevline[x] ^ mix;
+ insertmix = False;
+ count--;
+ x++;
+ }
+ if (prevline == NULL)
+ {
+ REPEAT(line[x] = 0)
+ }
+ else
+ {
+ REPEAT(line[x] = prevline[x])
+ }
+ break;
+ case 1: /* Mix */
+ if (prevline == NULL)
+ {
+ REPEAT(line[x] = mix)
+ }
+ else
+ {
+ REPEAT(line[x] = prevline[x] ^ mix)
+ }
+ break;
+ case 2: /* Fill or Mix */
+ if (prevline == NULL)
+ {
+ REPEAT
+ (
+ MASK_UPDATE();
+ if (mask & mixmask)
+ line[x] = mix;
+ else
+ line[x] = 0;
+ )
+ }
+ else
+ {
+ REPEAT
+ (
+ MASK_UPDATE();
+ if (mask & mixmask)
+ line[x] = prevline[x] ^ mix;
+ else
+ line[x] = prevline[x];
+ )
+ }
+ break;
+ case 3: /* Colour */
+ REPEAT(line[x] = colour2)
+ break;
+ case 4: /* Copy */
+ REPEAT(line[x] = CVAL(input))
+ break;
+ case 8: /* Bicolour */
+ REPEAT
+ (
+ if (bicolour)
+ {
+ line[x] = colour2;
+ bicolour = False;
+ }
+ else
+ {
+ line[x] = colour1;
+ bicolour = True; count++;
+ }
+ )
+ break;
+ case 0xd: /* White */
+ REPEAT(line[x] = 0xff)
+ break;
+ case 0xe: /* Black */
+ REPEAT(line[x] = 0)
+ break;
+ default:
+ unimpl("bitmap opcode 0x%x\n", opcode);
+ return False;
+ }
+ }
+ }
+ return True;
+}
+
+/* 2 byte bitmap decompress */
+static BOOL
+bitmap_decompress2(uint8 * output, int width, int height, uint8 * input, int size)
+{
+ uint8 *end = input + size;
+ uint16 *prevline = NULL, *line = NULL;
+ int opcode, count, offset, isfillormix, x = width;
+ int lastopcode = -1, insertmix = False, bicolour = False;
+ uint8 code;
+ uint16 colour1 = 0, colour2 = 0;
+ uint8 mixmask, mask = 0;
+ uint16 mix = 0xffff;
+ int fom_mask;
+
+ 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 */
+ CVAL2(input, colour1);
+ case 3: /* Colour */
+ CVAL2(input, colour2);
+ break;
+ case 6: /* SetMix/Mix */
+ case 7: /* SetMix/FillOrMix */
+ CVAL2(input, mix);
+ 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 = ((uint16 *) output) + height * width;
+ }
+ switch (opcode)
+ {
+ case 0: /* Fill */
+ if (insertmix)
+ {
+ if (prevline == NULL)
+ line[x] = mix;
+ else
+ line[x] = prevline[x] ^ mix;
+ insertmix = False;
+ count--;
+ x++;
+ }
+ if (prevline == NULL)
+ {
+ REPEAT(line[x] = 0)
+ }
+ else
+ {
+ REPEAT(line[x] = prevline[x])
+ }
+ break;
+ case 1: /* Mix */
+ if (prevline == NULL)
+ {
+ REPEAT(line[x] = mix)
+ }
+ else
+ {
+ REPEAT(line[x] = prevline[x] ^ mix)
+ }
+ break;
+ case 2: /* Fill or Mix */
+ if (prevline == NULL)
+ {
+ REPEAT
+ (
+ MASK_UPDATE();
+ if (mask & mixmask)
+ line[x] = mix;
+ else
+ line[x] = 0;
+ )
+ }
+ else
+ {
+ REPEAT
+ (
+ MASK_UPDATE();
+ if (mask & mixmask)
+ line[x] = prevline[x] ^ mix;
+ else
+ line[x] = prevline[x];
+ )
+ }
+ break;
+ case 3: /* Colour */
+ REPEAT(line[x] = colour2)
+ break;
+ case 4: /* Copy */
+ REPEAT(CVAL2(input, line[x]))
+ break;
+ case 8: /* Bicolour */
+ REPEAT
+ (
+ if (bicolour)
+ {
+ line[x] = colour2;
+ bicolour = False;
+ }
+ else
+ {
+ line[x] = colour1;
+ bicolour = True;
+ count++;
+ }
+ )
+ break;
+ case 0xd: /* White */
+ REPEAT(line[x] = 0xffff)
+ break;
+ case 0xe: /* Black */
+ REPEAT(line[x] = 0)
+ break;
+ default:
+ unimpl("bitmap opcode 0x%x\n", opcode);
+ return False;
+ }
+ }
+ }
+ return True;
+}
+
+/* 3 byte bitmap decompress */
+static BOOL
+bitmap_decompress3(uint8 * output, int width, int height, uint8 * input, int size)
+{
+ uint8 *end = input + size;
+ uint8 *prevline = NULL, *line = NULL;
+ int opcode, count, offset, isfillormix, x = width;
+ int lastopcode = -1, insertmix = False, bicolour = False;
+ uint8 code;
+ uint8 colour1[3] = {0, 0, 0}, colour2[3] = {0, 0, 0};
+ uint8 mixmask, mask = 0;
+ uint8 mix[3] = {0xff, 0xff, 0xff};
+ int fom_mask;
+
+ 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[0] = CVAL(input);
+ colour1[1] = CVAL(input);
+ colour1[2] = CVAL(input);
+ case 3: /* Colour */
+ colour2[0] = CVAL(input);
+ colour2[1] = CVAL(input);
+ colour2[2] = CVAL(input);
+ break;
+ case 6: /* SetMix/Mix */
+ case 7: /* SetMix/FillOrMix */
+ mix[0] = CVAL(input);
+ mix[1] = CVAL(input);
+ mix[2] = CVAL(input);
+ 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 * 3);
+ }
+ switch (opcode)
+ {
+ case 0: /* Fill */
+ if (insertmix)
+ {
+ if (prevline == NULL)
+ {
+ line[x * 3] = mix[0];
+ line[x * 3 + 1] = mix[1];
+ line[x * 3 + 2] = mix[2];
+ }
+ else
+ {
+ line[x * 3] =
+ prevline[x * 3] ^ mix[0];
+ line[x * 3 + 1] =
+ prevline[x * 3 + 1] ^ mix[1];
+ line[x * 3 + 2] =
+ prevline[x * 3 + 2] ^ mix[2];
+ }
+ insertmix = False;
+ count--;
+ x++;
+ }
+ if (prevline == NULL)
+ {
+ REPEAT
+ (
+ line[x * 3] = 0;
+ line[x * 3 + 1] = 0;
+ line[x * 3 + 2] = 0;
+ )
+ }
+ else
+ {
+ REPEAT
+ (
+ line[x * 3] = prevline[x * 3];
+ line[x * 3 + 1] = prevline[x * 3 + 1];
+ line[x * 3 + 2] = prevline[x * 3 + 2];
+ )
+ }
+ break;
+ case 1: /* Mix */
+ if (prevline == NULL)
+ {
+ REPEAT
+ (
+ line[x * 3] = mix[0];
+ line[x * 3 + 1] = mix[1];
+ line[x * 3 + 2] = mix[2];
+ )
+ }
+ else
+ {
+ REPEAT
+ (
+ line[x * 3] =
+ prevline[x * 3] ^ mix[0];
+ line[x * 3 + 1] =
+ prevline[x * 3 + 1] ^ mix[1];
+ line[x * 3 + 2] =
+ prevline[x * 3 + 2] ^ mix[2];
+ )
+ }
+ break;
+ case 2: /* Fill or Mix */
+ if (prevline == NULL)
+ {
+ REPEAT
+ (
+ MASK_UPDATE();
+ if (mask & mixmask)
+ {
+ line[x * 3] = mix[0];
+ line[x * 3 + 1] = mix[1];
+ line[x * 3 + 2] = mix[2];
+ }
+ else
+ {
+ line[x * 3] = 0;
+ line[x * 3 + 1] = 0;
+ line[x * 3 + 2] = 0;
+ }
+ )
+ }
+ else
+ {
+ REPEAT
+ (
+ MASK_UPDATE();
+ if (mask & mixmask)
+ {
+ line[x * 3] =
+ prevline[x * 3] ^ mix [0];
+ line[x * 3 + 1] =
+ prevline[x * 3 + 1] ^ mix [1];
+ line[x * 3 + 2] =
+ prevline[x * 3 + 2] ^ mix [2];
+ }
+ else
+ {
+ line[x * 3] =
+ prevline[x * 3];
+ line[x * 3 + 1] =
+ prevline[x * 3 + 1];
+ line[x * 3 + 2] =
+ prevline[x * 3 + 2];
+ }
+ )
+ }
+ break;
+ case 3: /* Colour */
+ REPEAT
+ (
+ line[x * 3] = colour2 [0];
+ line[x * 3 + 1] = colour2 [1];
+ line[x * 3 + 2] = colour2 [2];
+ )
+ break;
+ case 4: /* Copy */
+ REPEAT
+ (
+ line[x * 3] = CVAL(input);
+ line[x * 3 + 1] = CVAL(input);
+ line[x * 3 + 2] = CVAL(input);
+ )
+ break;
+ case 8: /* Bicolour */
+ REPEAT
+ (
+ if (bicolour)
+ {
+ line[x * 3] = colour2[0];
+ line[x * 3 + 1] = colour2[1];
+ line[x * 3 + 2] = colour2[2];
+ bicolour = False;
+ }
+ else
+ {
+ line[x * 3] = colour1[0];
+ line[x * 3 + 1] = colour1[1];
+ line[x * 3 + 2] = colour1[2];
+ bicolour = True;
+ count++;
+ }
+ )
+ break;
+ case 0xd: /* White */
+ REPEAT
+ (
+ line[x * 3] = 0xff;
+ line[x * 3 + 1] = 0xff;
+ line[x * 3 + 2] = 0xff;
+ )
+ break;
+ case 0xe: /* Black */
+ REPEAT
+ (
+ line[x * 3] = 0;
+ line[x * 3 + 1] = 0;
+ line[x * 3 + 2] = 0;
+ )
+ break;
+ default:
+ unimpl("bitmap opcode 0x%x\n", opcode);
+ return False;
+ }
+ }
+ }
+ return True;
+}
+
+/* main decompress function */
+BOOL
+bitmap_decompress(uint8 * output, int width, int height, uint8 * input, int size, int Bpp)
+{
+ BOOL rv = False;
+ switch (Bpp)
+ {
+ case 1:
+ rv = bitmap_decompress1(output, width, height, input, size);
+ break;
+ case 2:
+ rv = bitmap_decompress2(output, width, height, input, size);
+ break;
+ case 3:
+ rv = bitmap_decompress3(output, width, height, input, size);
+ break;
+ }
+ return rv;
+}
+
+/* 2 byte bitmap decompress */
+static BOOL
+bitmap_decompress_ex_16_to_32(uint8 * output, int width, int height, uint8 * input, int size)
+{
+ uint8 * end = input + size;
+ int * prevline = NULL, * line = NULL;
+ int opcode, count, offset, isfillormix, x = width;
+ int lastopcode = -1, insertmix = False, bicolour = False;
+ uint8 code;
+ int colour1 = 0, colour2 = 0;
+ uint8 mixmask, mask = 0;
+ int mix = 0xffffff;
+ int fom_mask;
+ int p, r, g, b;
+
+ 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 */
+ CVAL2(input, p);
+ SPLIT_COLOUR16(p, r, g, b);
+ MAKE_COLOUR32(p, r, g, b);
+ colour1 = p;
+ case 3: /* Colour */
+ CVAL2(input, p);
+ SPLIT_COLOUR16(p, r, g, b);
+ MAKE_COLOUR32(p, r, g, b);
+ colour2 = p;
+ break;
+ case 6: /* SetMix/Mix */
+ case 7: /* SetMix/FillOrMix */
+ CVAL2(input, p);
+ SPLIT_COLOUR16(p, r, g, b);
+ MAKE_COLOUR32(p, r, g, b);
+ mix = p;
+ 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 = ((int *) output) + height * width;
+ }
+ switch (opcode)
+ {
+ case 0: /* Fill */
+ if (insertmix)
+ {
+ if (prevline == NULL)
+ {
+ line[x] = mix;
+ }
+ else
+ {
+ line[x] = prevline[x] ^ mix;
+ }
+ insertmix = False;
+ count--;
+ x++;
+ }
+ if (prevline == NULL)
+ {
+ REPEAT(line[x] = 0)
+ }
+ else
+ {
+ REPEAT(line[x] = prevline[x])
+ }
+ break;
+ case 1: /* Mix */
+ if (prevline == NULL)
+ {
+ REPEAT(line[x] = mix)
+ }
+ else
+ {
+ REPEAT(line[x] = prevline[x] ^ mix)
+ }
+ break;
+ case 2: /* Fill or Mix */
+ if (prevline == NULL)
+ {
+ REPEAT
+ (
+ MASK_UPDATE();
+ if (mask & mixmask)
+ {
+ line[x] = mix;
+ }
+ else
+ {
+ line[x] = 0;
+ }
+ )
+ }
+ else
+ {
+ REPEAT
+ (
+ MASK_UPDATE();
+ if (mask & mixmask)
+ {
+ line[x] = prevline[x] ^ mix;
+ }
+ else
+ {
+ line[x] = prevline[x];
+ }
+ )
+ }
+ break;
+ case 3: /* Colour */
+ REPEAT(line[x] = colour2)
+ break;
+ case 4: /* Copy */
+ REPEAT
+ (
+ CVAL2(input, p);
+ SPLIT_COLOUR16(p, r, g, b);
+ MAKE_COLOUR32(p, r, g, b);
+ line[x] = p;
+ )
+ break;
+ case 8: /* Bicolour */
+ REPEAT
+ (
+ if (bicolour)
+ {
+ line[x] = colour2;
+ bicolour = False;
+ }
+ else
+ {
+ line[x] = colour1;
+ bicolour = True;
+ count++;
+ }
+ )
+ break;
+ case 0xd: /* White */
+ REPEAT(line[x] = 0xffffff)
+ break;
+ case 0xe: /* Black */
+ REPEAT(line[x] = 0)
+ break;
+ default:
+ unimpl("bitmap opcode 0x%x\n", opcode);
+ return False;
+ }
+ }
+ }
+ return True;
+}
+
+/* 3 byte bitmap decompress */
+static BOOL
+bitmap_decompress_ex_24_to_32(uint8 * output, int width, int height, uint8 * input, int size)
+{
+ uint8 * end = input + size;
+ int * prevline = NULL, * line = NULL;
+ int opcode, count, offset, isfillormix, x = width;
+ int lastopcode = -1, insertmix = False, bicolour = False;
+ uint8 code;
+ int colour1 = 0, colour2 = 0;
+ uint8 mixmask, mask = 0;
+ int mix = 0xffffff;
+ int fom_mask;
+ int p, r, g, b;
+
+ 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 */
+ b = CVAL(input);
+ g = CVAL(input);
+ r = CVAL(input);
+ MAKE_COLOUR32(p, r, g, b);
+ colour1 = p;
+ case 3: /* Colour */
+ b = CVAL(input);
+ g = CVAL(input);
+ r = CVAL(input);
+ MAKE_COLOUR32(p, r, g, b);
+ colour2 = p;
+ break;
+ case 6: /* SetMix/Mix */
+ case 7: /* SetMix/FillOrMix */
+ b = CVAL(input);
+ g = CVAL(input);
+ r = CVAL(input);
+ MAKE_COLOUR32(p, r, g, b);
+ mix = p;
+ 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 = ((int *) output) + height * width;
+ }
+ switch (opcode)
+ {
+ case 0: /* Fill */
+ if (insertmix)
+ {
+ if (prevline == NULL)
+ {
+ line[x] = mix;
+ }
+ else
+ {
+ line[x] = prevline[x] ^ mix;
+ }
+ insertmix = False;
+ count--;
+ x++;
+ }
+ if (prevline == NULL)
+ {
+ REPEAT(line[x] = 0)
+ }
+ else
+ {
+ REPEAT(line[x] = prevline[x])
+ }
+ break;
+ case 1: /* Mix */
+ if (prevline == NULL)
+ {
+ REPEAT(line[x] = mix)
+ }
+ else
+ {
+ REPEAT(line[x] = prevline[x] ^ mix)
+ }
+ break;
+ case 2: /* Fill or Mix */
+ if (prevline == NULL)
+ {
+ REPEAT
+ (
+ MASK_UPDATE();
+ if (mask & mixmask)
+ {
+ line[x] = mix;
+ }
+ else
+ {
+ line[x] = 0;
+ }
+ )
+ }
+ else
+ {
+ REPEAT
+ (
+ MASK_UPDATE();
+ if (mask & mixmask)
+ {
+ line[x] = prevline[x] ^ mix;
+ }
+ else
+ {
+ line[x] = prevline[x];
+ }
+ )
+ }
+ break;
+ case 3: /* Colour */
+ REPEAT(line[x] = colour2)
+ break;
+ case 4: /* Copy */
+ REPEAT
+ (
+ b = CVAL(input);
+ g = CVAL(input);
+ r = CVAL(input);
+ MAKE_COLOUR32(p, r, g, b);
+ line[x] = p;
+ )
+ break;
+ case 8: /* Bicolour */
+ REPEAT
+ (
+ if (bicolour)
+ {
+ line[x] = colour2;
+ bicolour = False;
+ }
+ else
+ {
+ line[x] = colour1;
+ bicolour = True;
+ count++;
+ }
+ )
+ break;
+ case 0xd: /* White */
+ REPEAT(line[x] = 0xffffff);
+ break;
+ case 0xe: /* Black */
+ REPEAT(line[x] = 0);
+ break;
+ default:
+ unimpl("bitmap opcode 0x%x\n", opcode);
+ return False;
+ }
+ }
+ }
+ return True;
+}
+
+BOOL
+bitmap_decompress_ex(uint8 * output, int width, int height, uint8 * input, int size,
+ int in_bpp, int out_bpp)
+{
+ if (in_bpp == 16 && out_bpp == 32)
+ {
+ return bitmap_decompress_ex_16_to_32(output, width, height, input, size);
+ }
+ else if (in_bpp == 24 && out_bpp == 32)
+ {
+ return bitmap_decompress_ex_24_to_32(output, width, height, input, size);
+ }
+ return False;
+}
+
+/* *INDENT-ON* */
diff --git a/uirdesktop/bsops.c b/uirdesktop/bsops.c
new file mode 100755
index 00000000..d70ef9c3
--- /dev/null
+++ b/uirdesktop/bsops.c
@@ -0,0 +1,822 @@
+/* -*- c-basic-offset: 8 -*-
+ rdesktop: A Remote Desktop Protocol client.
+ Generics backingstore operations
+ Copyright (C) Jay Sorg 2005-2006
+
+ 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 <string.h>
+#include "bsops.h"
+
+/* externals */
+extern int g_width;
+extern int g_height;
+extern int g_bs_bpp;
+extern int g_bs_Bpp;
+extern char * g_bs;
+
+/* globals */
+static int g_clip_left = 0;
+static int g_clip_top = 0;
+static int g_clip_right = 800;
+static int g_clip_bottom = 600;
+
+/* for bs_patblt */
+static unsigned char g_hatch_patterns[] =
+{
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, /* 0 - bsHorizontal */
+ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 1 - bsVertical */
+ 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, /* 2 - bsFDiagonal */
+ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, /* 3 - bsBDiagonal */
+ 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08, /* 4 - bsCross */
+ 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 /* 5 - bsDiagCross */
+};
+
+
+/*****************************************************************************/
+/* do a raster op */
+int
+bs_do_rop(int rop, int src, int dst)
+{
+ switch (rop)
+ {
+ case 0x0: return 0;
+ case 0x1: return ~(src | dst);
+ case 0x2: return (~src) & dst;
+ case 0x3: return ~src;
+ case 0x4: return src & (~dst);
+ case 0x5: return ~(dst);
+ case 0x6: return src ^ dst;
+ case 0x7: return ~(src & dst);
+ case 0x8: return src & dst;
+ case 0x9: return ~(src) ^ dst;
+ case 0xa: return dst;
+ case 0xb: return (~src) | dst;
+ case 0xc: return src;
+ case 0xd: return src | (~dst);
+ case 0xe: return src | dst;
+ case 0xf: return ~0;
+ }
+ return dst;
+}
+
+/*****************************************************************************/
+/* get a pixel from the in memory copy of whats on the screen */
+int
+bs_get_pixel(int x, int y)
+{
+ char * p;
+
+ if (x >= 0 && x < g_width && y >= 0 && y < g_height)
+ {
+ p = g_bs + (y * g_width * g_bs_Bpp) + (x * g_bs_Bpp);
+ if (g_bs_Bpp == 1)
+ {
+ return *((unsigned char *) p);
+ }
+ else if (g_bs_Bpp == 2)
+ {
+ return *((unsigned short *) p);
+ }
+ else
+ {
+ return *((unsigned int *) p);
+ }
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+/*****************************************************************************/
+/* set a pixel on the screen using the clip */
+void
+bs_set_pixel(int x, int y, int pixel, int rop, int use_clip)
+{
+ char * p;
+
+ if (!use_clip ||
+ (x >= g_clip_left && x < g_clip_right &&
+ y >= g_clip_top && y < g_clip_bottom))
+ {
+ if (x >= 0 && x < g_width && y >= 0 && y < g_height)
+ {
+ p = g_bs + (y * g_width * g_bs_Bpp) + (x * g_bs_Bpp);
+ if (rop != 12)
+ {
+ pixel = bs_do_rop(rop, pixel, bs_get_pixel(x, y));
+ }
+ if (g_bs_Bpp == 1)
+ {
+ *((unsigned char *) p) = pixel;
+ }
+ else if (g_bs_Bpp == 2)
+ {
+ *((unsigned short *) p) = pixel;
+ }
+ else
+ {
+ *((unsigned int *) p) = pixel;
+ }
+ }
+ }
+}
+
+/*****************************************************************************/
+static char *
+get_bs_ptr(int x, int y)
+{
+ char * p;
+
+ if (x >= 0 && x < g_width && y >= 0 && y < g_height)
+ {
+ p = g_bs + (y * g_width * g_bs_Bpp) + (x * g_bs_Bpp);
+ return p;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+/*****************************************************************************/
+void
+bs_init(void)
+{
+ g_clip_left = 0;
+ g_clip_top = 0;
+ g_clip_right = g_width;
+ g_clip_bottom = g_height;
+}
+
+/*****************************************************************************/
+void
+bs_exit(void)
+{
+}
+
+/*****************************************************************************/
+void
+bs_set_clip(int x, int y, int cx, int cy)
+{
+ g_clip_left = x;
+ g_clip_top = y;
+ g_clip_right = x + cx;
+ g_clip_bottom = y + cy;
+}
+
+/*****************************************************************************/
+void
+bs_reset_clip(void)
+{
+ g_clip_left = 0;
+ g_clip_top = 0;
+ g_clip_right = g_width;
+ g_clip_bottom = g_height;
+}
+
+/*****************************************************************************/
+/* check if a certain pixel is set in a bitmap */
+int
+bs_is_pixel_on(char * data, int x, int y, int width, int bpp)
+{
+ int start;
+ int 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 if (bpp == 24)
+ {
+ return data[(y * 3) * width + (x * 3)] != 0 &&
+ data[(y * 3) * width + (x * 3) + 1] != 0 &&
+ data[(y * 3) * width + (x * 3) + 2] != 0;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+/*****************************************************************************/
+void
+bs_set_pixel_on(char * data, int x, int y, int width, int bpp,
+ int pixel)
+{
+ int start;
+ int shift;
+
+ if (bpp == 1)
+ {
+ width = (width + 7) / 8;
+ start = (y * width) + x / 8;
+ shift = x % 8;
+ if (pixel != 0)
+ {
+ data[start] = data[start] | (0x80 >> shift);
+ }
+ else
+ {
+ data[start] = data[start] & ~(0x80 >> shift);
+ }
+ }
+ else if (bpp == 8)
+ {
+ data[y * width + x] = pixel;
+ }
+ else if (bpp == 15 || bpp == 16)
+ {
+ ((unsigned short *) data)[y * width + x] = pixel;
+ }
+}
+
+/*****************************************************************************/
+void
+bs_copy_mem(char * d, char * s, int n)
+{
+ while (n & (~7))
+ {
+ *(d++) = *(s++);
+ *(d++) = *(s++);
+ *(d++) = *(s++);
+ *(d++) = *(s++);
+ *(d++) = *(s++);
+ *(d++) = *(s++);
+ *(d++) = *(s++);
+ *(d++) = *(s++);
+ n = n - 8;
+ }
+ while (n > 0)
+ {
+ *(d++) = *(s++);
+ n--;
+ }
+}
+
+/*****************************************************************************/
+void
+bs_copy_memb(char * d, char * s, int n)
+{
+ d = (d + n) - 1;
+ s = (s + n) - 1;
+ while (n & (~7))
+ {
+ *(d--) = *(s--);
+ *(d--) = *(s--);
+ *(d--) = *(s--);
+ *(d--) = *(s--);
+ *(d--) = *(s--);
+ *(d--) = *(s--);
+ *(d--) = *(s--);
+ *(d--) = *(s--);
+ n = n - 8;
+ }
+ while (n > 0)
+ {
+ *(d--) = *(s--);
+ n--;
+ }
+}
+
+/*****************************************************************************/
+/* return true is the is something to draw */
+int
+bs_warp_coords(int * x, int * y, int * cx, int * cy,
+ int * srcx, int * srcy)
+{
+ int dx;
+ int dy;
+
+ if (g_clip_left > *x)
+ {
+ dx = g_clip_left - *x;
+ }
+ else
+ {
+ dx = 0;
+ }
+ if (g_clip_top > *y)
+ {
+ dy = g_clip_top - *y;
+ }
+ else
+ {
+ dy = 0;
+ }
+ if (*x + *cx > g_clip_right)
+ {
+ *cx = (*cx - ((*x + *cx) - g_clip_right));
+ }
+ if (*y + *cy > g_clip_bottom)
+ {
+ *cy = (*cy - ((*y + *cy) - g_clip_bottom));
+ }
+ *cx = *cx - dx;
+ *cy = *cy - dy;
+ if (*cx <= 0)
+ {
+ return 0;
+ }
+ if (*cy <= 0)
+ {
+ return 0;
+ }
+ *x = *x + dx;
+ *y = *y + dy;
+ if (srcx != 0)
+ {
+ *srcx = *srcx + dx;
+ }
+ if (srcy != 0)
+ {
+ *srcy = *srcy + dy;
+ }
+ return 1;
+}
+
+/*****************************************************************************/
+void
+bs_rect(int x, int y, int cx, int cy, int colour, int rop)
+{
+ int i;
+ int j;
+ unsigned char * p8;
+ unsigned short * p16;
+ unsigned int * p32;
+
+ if (bs_warp_coords(&x, &y, &cx, &cy, 0, 0))
+ {
+ if (rop == 0) /* black */
+ {
+ rop = 12;
+ colour = 0;
+ }
+ else if (rop == 15) /* white */
+ {
+ rop = 12;
+ colour = 0xffffff;
+ }
+ if (rop == 12) /* copy */
+ {
+ if (g_bs_Bpp == 1)
+ {
+ for (i = 0; i < cy; i++)
+ {
+ p8 = (unsigned char *) get_bs_ptr(x, y + i);
+ if (p8 != 0)
+ {
+ for (j = 0; j < cx; j++)
+ {
+ *p8 = colour;
+ p8++;
+ }
+ }
+ }
+ }
+ else if (g_bs_Bpp == 2)
+ {
+ for (i = 0; i < cy; i++)
+ {
+ p16 = (unsigned short *) get_bs_ptr(x, y + i);
+ if (p16 != 0)
+ {
+ for (j = 0; j < cx; j++)
+ {
+ *p16 = colour;
+ p16++;
+ }
+ }
+ }
+ }
+ else
+ {
+ for (i = 0; i < cy; i++)
+ {
+ p32 = (unsigned int *) get_bs_ptr(x, y + i);
+ if (p32 != 0)
+ {
+ for (j = 0; j < cx; j++)
+ {
+ *p32 = colour;
+ p32++;
+ }
+ }
+ }
+ }
+ }
+ else /* slow */
+ {
+ for (i = 0; i < cy; i++)
+ {
+ for (j = 0; j < cx; j++)
+ {
+ bs_set_pixel(j + x, i + y, colour, rop, 0);
+ }
+ }
+ }
+ }
+}
+
+/*****************************************************************************/
+void
+bs_screenblt(int rop, int x, int y, int cx, int cy,
+ int srcx, int srcy)
+{
+ int p;
+ int i;
+ int j;
+ char * src;
+ char * dst;
+
+ if (bs_warp_coords(&x, &y, &cx, &cy, &srcx, &srcy))
+ {
+ if (rop == 12) /* copy */
+ {
+ if (srcy < y) /* copy down - bottom to top */
+ {
+ for (i = cy - 1; i >= 0; i--)
+ {
+ src = get_bs_ptr(srcx, srcy + i);
+ dst = get_bs_ptr(x, y + i);
+ if (src != 0 && dst != 0)
+ {
+ bs_copy_mem(dst, src, cx * g_bs_Bpp);
+ }
+ }
+ }
+ else if (srcy > y || srcx > x) /* copy up or left - top to bottom */
+ {
+ for (i = 0; i < cy; i++)
+ {
+ src = get_bs_ptr(srcx, srcy + i);
+ dst = get_bs_ptr(x, y + i);
+ if (src != 0 && dst != 0)
+ {
+ bs_copy_mem(dst, src, cx * g_bs_Bpp);
+ }
+ }
+ }
+ else /* copy straight right */
+ {
+ for (i = 0; i < cy; i++)
+ {
+ src = get_bs_ptr(srcx, srcy + i);
+ dst = get_bs_ptr(x, y + i);
+ if (src != 0 && dst != 0)
+ {
+ bs_copy_memb(dst, src, cx * g_bs_Bpp);
+ }
+ }
+ }
+ }
+ else /* slow */
+ {
+ if (srcy < y) /* copy down - bottom to top */
+ {
+ for (i = cy - 1; i >= 0; i--)
+ {
+ for (j = 0; j < cx; j++)
+ {
+ p = bs_get_pixel(srcx + j, srcy + i);
+ bs_set_pixel(x + j, y + i, p, rop, 0);
+ }
+ }
+ }
+ else if (srcy > y || srcx > x) /* copy up or left - top to bottom */
+ {
+ for (i = 0; i < cy; i++)
+ {
+ for (j = 0; j < cx; j++)
+ {
+ p = bs_get_pixel(srcx + j, srcy + i);
+ bs_set_pixel(x + j, y + i, p, rop, 0);
+ }
+ }
+ }
+ else /* copy straight right */
+ {
+ for (i = 0; i < cy; i++)
+ {
+ for (j = cx - 1; j >= 0; j--)
+ {
+ p = bs_get_pixel(srcx + j, srcy + i);
+ bs_set_pixel(x + j, y + i, p, rop, 0);
+ }
+ }
+ }
+ }
+ }
+}
+
+/*****************************************************************************/
+void
+bs_memblt(int opcode, int x, int y, int cx, int cy,
+ void * srcdata, int srcwidth, int srcheight,
+ int srcx, int srcy)
+{
+ int i;
+ int j;
+ int p;
+ char * dst;
+ char * src;
+
+ if (bs_warp_coords(&x, &y, &cx, &cy, &srcx, &srcy))
+ {
+ if (opcode == 12) /* copy */
+ {
+ if (g_bs_Bpp == 1)
+ {
+ src = (char *) (((unsigned char *) srcdata) + srcy * srcwidth + srcx);
+ }
+ else if (g_bs_Bpp == 2)
+ {
+ src = (char *) (((unsigned short *) srcdata) + srcy * srcwidth + srcx);
+ }
+ else
+ {
+ src = (char *) (((unsigned int *) srcdata) + srcy * srcwidth + srcx);
+ }
+ for (i = 0; i < cy; i++)
+ {
+ dst = get_bs_ptr(x, y + i);
+ if (dst != 0)
+ {
+ bs_copy_mem(dst, src, cx * g_bs_Bpp);
+ src += srcwidth * g_bs_Bpp;
+ }
+ }
+ }
+ else /* slow */
+ {
+ if (g_bs_Bpp == 1)
+ {
+ for (i = 0; i < cy; i++)
+ {
+ for (j = 0; j < cx; j++)
+ {
+ p = *(((unsigned char *) srcdata) +
+ ((i + srcy) * srcwidth + (j + srcx)));
+ bs_set_pixel(x + j, y + i, p, opcode, 0);
+ }
+ }
+ }
+ else if (g_bs_Bpp == 2)
+ {
+ for (i = 0; i < cy; i++)
+ {
+ for (j = 0; j < cx; j++)
+ {
+ p = *(((unsigned short *) srcdata) +
+ ((i + srcy) * srcwidth + (j + srcx)));
+ bs_set_pixel(x + j, y + i, p, opcode, 0);
+ }
+ }
+ }
+ else
+ {
+ for (i = 0; i < cy; i++)
+ {
+ for (j = 0; j < cx; j++)
+ {
+ p = *(((unsigned int *) srcdata) +
+ ((i + srcy) * srcwidth + (j + srcx)));
+ bs_set_pixel(x + j, y + i, p, opcode, 0);
+ }
+ }
+ }
+ }
+ }
+}
+
+/*****************************************************************************/
+void
+bs_draw_glyph(int x, int y, char * glyph_data, int glyph_width,
+ int glyph_height, int fgcolour)
+{
+ int i;
+ int j;
+
+ for (i = 0; i < glyph_height; i++)
+ {
+ for (j = 0; j < glyph_width; j++)
+ {
+ if (bs_is_pixel_on(glyph_data, j, i, glyph_width, 8))
+ {
+ bs_set_pixel(x + j, y + i, fgcolour, 12, 1);
+ }
+ }
+ }
+}
+
+/*****************************************************************************/
+/* Bresenham's line drawing algorithm */
+void
+bs_line(int opcode, int startx, int starty, int endx, int endy,
+ int pen_width, int pen_style, int pen_colour)
+{
+ int dx;
+ int dy;
+ int incx;
+ int incy;
+ int dpr;
+ int dpru;
+ int p;
+
+ if (startx > endx)
+ {
+ dx = startx - endx;
+ incx = -1;
+ }
+ else
+ {
+ dx = endx - startx;
+ incx = 1;
+ }
+ if (starty > endy)
+ {
+ dy = starty - endy;
+ incy = -1;
+ }
+ else
+ {
+ dy = endy - starty;
+ incy = 1;
+ }
+ if (dx >= dy)
+ {
+ dpr = dy << 1;
+ dpru = dpr - (dx << 1);
+ p = dpr - dx;
+ for (; dx >= 0; dx--)
+ {
+ if (startx != endx || starty != endy)
+ {
+ bs_set_pixel(startx, starty, pen_colour, opcode, 1);
+ }
+ 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--)
+ {
+ if (startx != endx || starty != endy)
+ {
+ bs_set_pixel(startx, starty, pen_colour, opcode, 1);
+ }
+ if (p > 0)
+ {
+ startx += incx;
+ starty += incy;
+ p += dpru;
+ }
+ else
+ {
+ starty += incy;
+ p += dpr;
+ }
+ }
+ }
+}
+
+/*****************************************************************************/
+void
+bs_patblt(int opcode, int x, int y, int cx, int cy,
+ int brush_style, char * brush_pattern,
+ int brush_x_org, int brush_y_org,
+ int bgcolour, int fgcolour)
+{
+ int i;
+ int j;
+ char ipattern[8];
+ char * b;
+
+ b = 0;
+ switch (brush_style)
+ {
+ case 0:
+ bs_rect(x, y, cx, cy, fgcolour, opcode);
+ break;
+ case 2: /* Hatch */
+ b = g_hatch_patterns + brush_pattern[0] * 8;
+ break;
+ case 3:
+ for (i = 0; i < 8; i++)
+ {
+ ipattern[i] = ~brush_pattern[7 - i];
+ }
+ b = ipattern;
+ break;
+ }
+ if (b != 0)
+ {
+ for (i = 0; i < cy; i++)
+ {
+ for (j = 0; j < cx; j++)
+ {
+ if (bs_is_pixel_on(b, (x + j + brush_x_org) % 8,
+ (y + i + brush_y_org) % 8, 8, 1))
+ {
+ bs_set_pixel(x + j, y + i, fgcolour, opcode, 1);
+ }
+ else
+ {
+ bs_set_pixel(x + j, y + i, bgcolour, opcode, 1);
+ }
+ }
+ }
+ }
+}
+
+/*****************************************************************************/
+void
+bs_copy_box(char * dst, int x, int y, int cx, int cy, int line_size)
+{
+ char * src;
+ int i;
+
+ /* shouldn't happen */
+ if (cx < 1 || cy < 1)
+ {
+ return;
+ }
+ /* nothing to draw, memset and leave */
+ if (x + cx < 0 || y + cy < 0 || x >= g_width || y >= g_height)
+ {
+ memset(dst, 0, cx * cy * g_bs_Bpp);
+ return;
+ }
+ /* check if it goes over an edge */
+ if (x < 0 || y < 0 || x + cx > g_width || y + cy > g_height)
+ {
+ memset(dst, 0, cx * cy * g_bs_Bpp);
+ if (x < 0)
+ {
+ cx += x;
+ dst += -x * g_bs_Bpp;
+ x = 0;
+ }
+ if (x + cx > g_width)
+ {
+ cx = g_width - x;
+ }
+ for (i = 0; i < cy; i++)
+ {
+ src = get_bs_ptr(x, y + i);
+ if (src != 0)
+ {
+ bs_copy_mem(dst, src, cx * g_bs_Bpp);
+ }
+ dst += line_size;
+ }
+ }
+ else /* whole box is within */
+ {
+ for (i = 0; i < cy; i++)
+ {
+ src = get_bs_ptr(x, y + i);
+ if (src != 0)
+ {
+ bs_copy_mem(dst, src, cx * g_bs_Bpp);
+ }
+ dst += line_size;
+ }
+ }
+}
+
diff --git a/uirdesktop/bsops.h b/uirdesktop/bsops.h
new file mode 100755
index 00000000..25df2208
--- /dev/null
+++ b/uirdesktop/bsops.h
@@ -0,0 +1,49 @@
+/* -*- c-basic-offset: 8 -*-
+ rdesktop: A Remote Desktop Protocol client.
+ Generics backingstore operations
+ Copyright (C) Jay Sorg 2005-2006
+
+ 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.
+*/
+
+int bs_get_pixel(int x, int y);
+void bs_set_pixel(int x, int y, int pixel, int rop, int use_clip);
+int bs_do_rop(int rop, int src, int dst);
+void bs_init(void);
+void bs_exit(void);
+void bs_set_clip(int x, int y, int cx, int cy);
+void bs_reset_clip(void);
+void bs_set_pixel_on(char * data, int x, int y, int width, int bpp,
+ int pixel);
+int bs_is_pixel_on(char * data, int x, int y, int width, int bpp);
+void bs_copy_mem(char * d, char * s, int n);
+void bs_copy_memb(char * d, char * s, int n);
+int bs_warp_coords(int * x, int * y, int * cx, int * cy,
+ int * srcx, int * srcy);
+void bs_rect(int x, int y, int cx, int cy, int colour, int rop);
+void bs_screenblt(int opcode, int x, int y, int cx, int cy,
+ int srcx, int srcy);
+void bs_memblt(int opcode, int x, int y, int cx, int cy,
+ void * srcdata, int srcwidth, int srcheight,
+ int srcx, int srcy);
+void bs_copy_box(char * dst, int x, int y, int cx, int cy, int line_size);
+void bs_draw_glyph(int x, int y, char * glyph_data, int glyph_width,
+ int glyph_height, int fgcolour);
+void bs_line(int opcode, int startx, int starty, int endx, int endy,
+ int pen_width, int pen_style, int pen_colour);
+void bs_patblt(int opcode, int x, int y, int cx, int cy,
+ int brush_style, char * brush_pattern,
+ int brush_x_org, int brush_y_org,
+ int bgcolour, int fgcolour);
diff --git a/uirdesktop/cache.c b/uirdesktop/cache.c
index 70fcf2cf..54636379 100644
--- a/uirdesktop/cache.c
+++ b/uirdesktop/cache.c
@@ -40,13 +40,13 @@ extern int g_pstcache_fd[];
struct bmpcache_entry
{
- HBITMAP bitmap;
+ RD_HBITMAP bitmap;
sint16 previous;
sint16 next;
};
static struct bmpcache_entry g_bmpcache[3][0xa00];
-static HBITMAP g_volatile_bc[3];
+static RD_HBITMAP g_volatile_bc[3];
static int g_bmpcache_lru[3] = { NOT_SET, NOT_SET, NOT_SET };
static int g_bmpcache_mru[3] = { NOT_SET, NOT_SET, NOT_SET };
@@ -190,7 +190,7 @@ cache_evict_bitmap(uint8 id)
}
/* Retrieve a bitmap from the cache */
-HBITMAP
+RD_HBITMAP
cache_get_bitmap(uint8 id, uint16 idx)
{
if ((id < NUM_ELEMENTS(g_bmpcache)) && (idx < NUM_ELEMENTS(g_bmpcache[0])))
@@ -214,9 +214,9 @@ cache_get_bitmap(uint8 id, uint16 idx)
/* Store a bitmap in the cache */
void
-cache_put_bitmap(uint8 id, uint16 idx, HBITMAP bitmap)
+cache_put_bitmap(uint8 id, uint16 idx, RD_HBITMAP bitmap)
{
- HBITMAP old;
+ RD_HBITMAP old;
if ((id < NUM_ELEMENTS(g_bmpcache)) && (idx < NUM_ELEMENTS(g_bmpcache[0])))
{
@@ -262,7 +262,7 @@ cache_save_state(void)
idx = g_bmpcache_lru[id];
while (idx >= 0)
{
- pstcache_touch_bitmap(id, idx, ++t);
+ pstcache_touch_bitmap((uint8) id, (uint16) idx, ++t);
idx = g_bmpcache[id][idx].next;
}
DEBUG_RDP5((" %d stamps written.\n", t));
@@ -293,7 +293,7 @@ cache_get_font(uint8 font, uint16 character)
/* 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)
+ uint16 baseline, uint16 width, uint16 height, RD_HGLYPH pixmap)
{
FONTGLYPH *glyph;
@@ -392,13 +392,13 @@ cache_put_desktop(uint32 offset, int cx, int cy, int scanline, int bytes_per_pix
/* CURSOR CACHE */
-static HCURSOR g_cursorcache[0x20];
+static RD_HCURSOR g_cursorcache[0x20];
/* Retrieve cursor from cache */
-HCURSOR
+RD_HCURSOR
cache_get_cursor(uint16 cache_idx)
{
- HCURSOR cursor;
+ RD_HCURSOR cursor;
if (cache_idx < NUM_ELEMENTS(g_cursorcache))
{
@@ -413,9 +413,9 @@ cache_get_cursor(uint16 cache_idx)
/* Store cursor in cache */
void
-cache_put_cursor(uint16 cache_idx, HCURSOR cursor)
+cache_put_cursor(uint16 cache_idx, RD_HCURSOR cursor)
{
- HCURSOR old;
+ RD_HCURSOR old;
if (cache_idx < NUM_ELEMENTS(g_cursorcache))
{
diff --git a/uirdesktop/constants.h b/uirdesktop/constants.h
new file mode 100755
index 00000000..a2349a09
--- /dev/null
+++ b/uirdesktop/constants.h
@@ -0,0 +1,435 @@
+/*
+ rdesktop: A Remote Desktop Protocol client.
+ Miscellaneous protocol constants
+ Copyright (C) Matthew Chapman 1999-2005
+
+ 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
+
+#define DEFAULT_CODEPAGE "UTF-8"
+#define WINDOWS_CODEPAGE "UTF-16LE"
+
+/* 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
+#define MCS_USERCHANNEL_BASE 1001
+
+/* 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_REDIRECT_ENCRYPT 0x0C00
+
+#define SEC_TAG_SRV_INFO 0x0c01
+#define SEC_TAG_SRV_CRYPT 0x0c02
+#define SEC_TAG_SRV_CHANNELS 0x0c03
+
+#define SEC_TAG_CLI_INFO 0xc001
+#define SEC_TAG_CLI_CRYPT 0xc002
+#define SEC_TAG_CLI_CHANNELS 0xc003
+#define SEC_TAG_CLI_4 0xc004
+
+#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 0x01
+#define LICENCE_TAG_AUTHREQ 0x02
+#define LICENCE_TAG_ISSUE 0x03
+#define LICENCE_TAG_REISSUE 0x04
+#define LICENCE_TAG_PRESENT 0x12
+#define LICENCE_TAG_REQUEST 0x13
+#define LICENCE_TAG_AUTHRESP 0x15
+#define LICENCE_TAG_RESULT 0xff
+
+#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_REDIRECT = 4, /* MS Server 2003 Session Redirect */
+ 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_CLIENT_WINDOW_STATUS = 35,
+ RDP_DATA_PDU_LOGON = 38,
+ RDP_DATA_PDU_FONT2 = 39,
+ RDP_DATA_PDU_KEYBOARD_INDICATORS = 41,
+ RDP_DATA_PDU_DISCONNECT = 47
+};
+
+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_SYSTEM = 1,
+ RDP_POINTER_MOVE = 3,
+ RDP_POINTER_COLOR = 6,
+ RDP_POINTER_CACHED = 7
+};
+
+enum RDP_SYSTEM_POINTER_TYPE
+{
+ RDP_NULL_POINTER = 0,
+ RDP_DEFAULT_POINTER = 0x7F00
+};
+
+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) ((uint8) (rop3 & 0xf))
+#define ROP2_P(rop3) ((uint8) ((rop3 & 0x3) | ((rop3 & 0x30) >> 2)))
+#define ROP_MINUS_1(rop) ((uint8) (rop - 1))
+
+#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
+
+#define ALTERNATE 1
+#define WINDING 2
+
+/* RDP bitmap cache (version 2) constants */
+#define BMPCACHE2_C0_CELLS 0x78
+#define BMPCACHE2_C1_CELLS 0x78
+#define BMPCACHE2_C2_CELLS 0x150
+#define BMPCACHE2_NUM_PSTCELLS 0x9f6
+
+#define PDU_FLAG_FIRST 0x01
+#define PDU_FLAG_LAST 0x02
+
+/* RDP capabilities */
+#define RDP_CAPSET_GENERAL 1 /* Maps to generalCapabilitySet in T.128 page 138 */
+#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_BMPCACHE2 19
+#define RDP_CAPLEN_BMPCACHE2 0x28
+#define BMPCACHE2_FLAG_PERSIST ((uint32)1<<31)
+
+#define RDP_SOURCE "MSTSC"
+
+/* Logon flags */
+#define RDP_LOGON_AUTO 0x0008
+#define RDP_LOGON_NORMAL 0x0033
+#define RDP_LOGON_COMPRESSION 0x0080 /* mppc compression with 8kB histroy buffer */
+#define RDP_LOGON_BLOB 0x0100
+#define RDP_LOGON_COMPRESSION2 0x0200 /* rdp5 mppc compression with 64kB history buffer */
+#define RDP_LOGON_LEAVE_AUDIO 0x2000
+
+#define RDP5_DISABLE_NOTHING 0x00
+#define RDP5_NO_WALLPAPER 0x01
+#define RDP5_NO_FULLWINDOWDRAG 0x02
+#define RDP5_NO_MENUANIMATIONS 0x04
+#define RDP5_NO_THEMING 0x08
+#define RDP5_NO_CURSOR_SHADOW 0x20
+#define RDP5_NO_CURSORSETTINGS 0x40 /* disables cursor blinking */
+
+/* compression types */
+#define RDP_MPPC_BIG 0x01
+#define RDP_MPPC_COMPRESSED 0x20
+#define RDP_MPPC_RESET 0x40
+#define RDP_MPPC_FLUSH 0x80
+#define RDP_MPPC_DICT_SIZE 65536
+
+#define RDP5_COMPRESSED 0x80
+
+/* 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)))
+
+/* Clipboard constants, "borrowed" from GCC system headers in
+ the w32 cross compiler */
+
+#ifndef CF_TEXT
+#define CF_TEXT 1
+#define CF_BITMAP 2
+#define CF_METAFILEPICT 3
+#define CF_SYLK 4
+#define CF_DIF 5
+#define CF_TIFF 6
+#define CF_OEMTEXT 7
+#define CF_DIB 8
+#define CF_PALETTE 9
+#define CF_PENDATA 10
+#define CF_RIFF 11
+#define CF_WAVE 12
+#define CF_UNICODETEXT 13
+#define CF_ENHMETAFILE 14
+#define CF_HDROP 15
+#define CF_LOCALE 16
+#define CF_MAX 17
+#define CF_OWNERDISPLAY 128
+#define CF_DSPTEXT 129
+#define CF_DSPBITMAP 130
+#define CF_DSPMETAFILEPICT 131
+#define CF_DSPENHMETAFILE 142
+#define CF_PRIVATEFIRST 512
+#define CF_PRIVATELAST 767
+#define CF_GDIOBJFIRST 768
+#define CF_GDIOBJLAST 1023
+#endif
+
+/* Sound format constants */
+#define WAVE_FORMAT_PCM 1
+#define WAVE_FORMAT_ADPCM 2
+#define WAVE_FORMAT_ALAW 6
+#define WAVE_FORMAT_MULAW 7
+
+/* Virtual channel options */
+#define CHANNEL_OPTION_INITIALIZED 0x80000000
+#define CHANNEL_OPTION_ENCRYPT_RDP 0x40000000
+#define CHANNEL_OPTION_COMPRESS_RDP 0x00800000
+#define CHANNEL_OPTION_SHOW_PROTOCOL 0x00200000
+
+/* NT status codes for RDPDR */
+#undef STATUS_SUCCESS
+#define STATUS_SUCCESS 0x00000000
+#undef STATUS_NOT_IMPLEMENTED
+#define STATUS_NOT_IMPLEMENTED 0x00000001
+#undef STATUS_PENDING
+#define STATUS_PENDING 0x00000103
+
+#ifndef STATUS_NO_MORE_FILES
+#define STATUS_NO_MORE_FILES 0x80000006
+#define STATUS_DEVICE_PAPER_EMPTY 0x8000000e
+#define STATUS_DEVICE_POWERED_OFF 0x8000000f
+#define STATUS_DEVICE_OFF_LINE 0x80000010
+#define STATUS_DEVICE_BUSY 0x80000011
+#endif
+
+#ifndef STATUS_INVALID_HANDLE
+#define STATUS_INVALID_HANDLE 0xc0000008
+#define STATUS_INVALID_PARAMETER 0xc000000d
+#define STATUS_NO_SUCH_FILE 0xc000000f
+#define STATUS_INVALID_DEVICE_REQUEST 0xc0000010
+#define STATUS_ACCESS_DENIED 0xc0000022
+#define STATUS_OBJECT_NAME_COLLISION 0xc0000035
+#define STATUS_DISK_FULL 0xc000007f
+#define STATUS_FILE_IS_A_DIRECTORY 0xc00000ba
+#define STATUS_NOT_SUPPORTED 0xc00000bb
+#define STATUS_TIMEOUT 0xc0000102
+#define STATUS_NOTIFY_ENUM_DIR 0xc000010c
+#define STATUS_CANCELLED 0xc0000120
+#endif
+
+/* RDPDR constants */
+#define RDPDR_MAX_DEVICES 0x10
+#define DEVICE_TYPE_SERIAL 0x01
+#define DEVICE_TYPE_PARALLEL 0x02
+#define DEVICE_TYPE_PRINTER 0x04
+#define DEVICE_TYPE_DISK 0x08
+#define DEVICE_TYPE_SCARD 0x20
+
+#define FILE_DIRECTORY_FILE 0x00000001
+#define FILE_NON_DIRECTORY_FILE 0x00000040
+#define FILE_COMPLETE_IF_OPLOCKED 0x00000100
+#define FILE_DELETE_ON_CLOSE 0x00001000
+#define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000
+
+/* RDP5 disconnect PDU */
+#define exDiscReasonNoInfo 0x0000
+#define exDiscReasonAPIInitiatedDisconnect 0x0001
+#define exDiscReasonAPIInitiatedLogoff 0x0002
+#define exDiscReasonServerIdleTimeout 0x0003
+#define exDiscReasonServerLogonTimeout 0x0004
+#define exDiscReasonReplacedByOtherConnection 0x0005
+#define exDiscReasonOutOfMemory 0x0006
+#define exDiscReasonServerDeniedConnection 0x0007
+#define exDiscReasonServerDeniedConnectionFips 0x0008
+#define exDiscReasonLicenseInternal 0x0100
+#define exDiscReasonLicenseNoLicenseServer 0x0101
+#define exDiscReasonLicenseNoLicense 0x0102
+#define exDiscReasonLicenseErrClientMsg 0x0103
+#define exDiscReasonLicenseHwidDoesntMatchLicense 0x0104
+#define exDiscReasonLicenseErrClientLicense 0x0105
+#define exDiscReasonLicenseCantFinishProtocol 0x0106
+#define exDiscReasonLicenseClientEndedProtocol 0x0107
+#define exDiscReasonLicenseErrClientEncryption 0x0108
+#define exDiscReasonLicenseCantUpgradeLicense 0x0109
+#define exDiscReasonLicenseNoRemoteConnections 0x010a
+
+/* SeamlessRDP constants */
+#define SEAMLESSRDP_NOTYETMAPPED -1
+#define SEAMLESSRDP_NORMAL 0
+#define SEAMLESSRDP_MINIMIZED 1
+#define SEAMLESSRDP_MAXIMIZED 2
+#define SEAMLESSRDP_POSITION_TIMER 200000
+
+#define SEAMLESSRDP_CREATE_MODAL 0x0001
+
+#define SEAMLESSRDP_HELLO_RECONNECT 0x0001
+#define SEAMLESSRDP_HELLO_HIDDEN 0x0002
diff --git a/uirdesktop/example-winrdesktop.ini b/uirdesktop/example-winrdesktop.ini
new file mode 100755
index 00000000..cbb88b64
--- /dev/null
+++ b/uirdesktop/example-winrdesktop.ini
@@ -0,0 +1,8 @@
+[main]
+server=192.168.1.1
+port=3389
+username=user1
+password=password1
+bpp=16
+#geometry=300x400
+fullscreen
diff --git a/uirdesktop/licence.c b/uirdesktop/licence.c
new file mode 100755
index 00000000..32918011
--- /dev/null
+++ b/uirdesktop/licence.c
@@ -0,0 +1,345 @@
+/* -*- c-basic-offset: 8 -*-
+ rdesktop: A Remote Desktop Protocol client.
+ RDP licensing negotiation
+ Copyright (C) Matthew Chapman 1999-2005
+
+ 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 <openssl/rc4.h>
+
+void *
+ssl_rc4_info_create(void);
+void
+ssl_rc4_info_delete(void * rc4_info);
+void
+ssl_rc4_set_key(void * rc4_info, char * key, int len);
+void
+ssl_rc4_crypt(void * rc4_info, char * in_data, char * out_data, int len);
+int
+ssl_mod_exp(char* out, int out_len, char* in, int in_len,
+ char* mod, int mod_len, char* exp, int exp_len);
+
+extern char g_username[64];
+extern char g_hostname[16];
+
+static uint8 g_licence_key[16];
+static uint8 g_licence_sign_key[16];
+
+BOOL g_licence_issued = False;
+
+/* Generate a session key and RC4 keys, given client and server randoms */
+static void
+licence_generate_keys(uint8 * client_random, uint8 * server_random, uint8 * pre_master_secret)
+{
+ uint8 master_secret[48];
+ uint8 key_block[48];
+
+ /* Generate master secret and then key material */
+ sec_hash_48(master_secret, pre_master_secret, client_random, server_random, 'A');
+ sec_hash_48(key_block, master_secret, server_random, client_random, 'A');
+
+ /* Store first 16 bytes of session key as MAC secret */
+ memcpy(g_licence_sign_key, key_block, 16);
+
+ /* Generate RC4 key from next 16 bytes */
+ sec_hash_16(g_licence_key, &key_block[16], client_random, server_random);
+}
+
+static void
+licence_generate_hwid(uint8 * hwid)
+{
+ buf_out_uint32(hwid, 2);
+ strncpy((char *) (hwid + 4), g_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_uint8(s, LICENCE_TAG_PRESENT);
+ out_uint8(s, 2); /* version */
+ 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_uint8(s, LICENCE_TAG_REQUEST);
+ out_uint8(s, 2); /* version */
+ 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_le(s, LICENCE_TAG_USER);
+ out_uint16_le(s, userlen);
+ out_uint8p(s, user, userlen);
+
+ out_uint16_le(s, LICENCE_TAG_HOST);
+ out_uint16_le(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;
+ void * 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 > 0)
+ {
+ /* Generate a signature for the HWID buffer */
+ licence_generate_hwid(hwid);
+ sec_sign(signature, 16, g_licence_sign_key, 16, hwid, sizeof(hwid));
+
+ /* Now encrypt the HWID */
+ crypt_key = ssl_rc4_info_create();
+ ssl_rc4_set_key(crypt_key, g_licence_key, 16);
+ ssl_rc4_crypt(crypt_key, hwid, hwid, sizeof(hwid));
+ ssl_rc4_info_delete(crypt_key);
+
+ licence_present(null_data, null_data, licence_data, licence_size, hwid, signature);
+ xfree(licence_data);
+ return;
+ }
+
+ licence_send_request(null_data, null_data, g_username, g_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_uint8(s, LICENCE_TAG_AUTHRESP);
+ out_uint8(s, 2); /* version */
+ 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];
+ void * 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. */
+ crypt_key = ssl_rc4_info_create();
+ ssl_rc4_set_key(crypt_key, g_licence_key, 16);
+ ssl_rc4_crypt(crypt_key, in_token, decrypt_token, LICENCE_TOKEN_SIZE);
+ ssl_rc4_info_delete(crypt_key);
+
+ /* 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, g_licence_sign_key, 16, sealed_buffer, sizeof(sealed_buffer));
+
+ /* Now encrypt the HWID */
+ crypt_key = ssl_rc4_info_create();
+ ssl_rc4_set_key(crypt_key, g_licence_key, 16);
+ ssl_rc4_crypt(crypt_key, hwid, crypt_hwid, LICENCE_HWID_SIZE);
+ ssl_rc4_info_delete(crypt_key);
+
+ licence_send_authresp(out_token, crypt_hwid, out_sig);
+}
+
+/* Process an licence issue packet */
+static void
+licence_process_issue(STREAM s)
+{
+ void * crypt_key;
+ uint32 length;
+ uint16 check;
+ int i;
+
+ in_uint8s(s, 2); /* 3d 45 - unknown */
+ in_uint16_le(s, length);
+ if (!s_check_rem(s, length))
+ return;
+
+ crypt_key = ssl_rc4_info_create();
+ ssl_rc4_set_key(crypt_key, g_licence_key, 16);
+ ssl_rc4_crypt(crypt_key, s->p, s->p, length);
+ ssl_rc4_info_delete(crypt_key);
+
+ in_uint16(s, check);
+ if (check != 0)
+ return;
+
+ g_licence_issued = True;
+
+ in_uint8s(s, 2); /* pad */
+
+ /* advance to fourth string */
+ length = 0;
+ for (i = 0; i < 4; i++)
+ {
+ in_uint8s(s, length);
+ in_uint32_le(s, length);
+ if (!s_check_rem(s, length))
+ return;
+ }
+
+ g_licence_issued = True;
+ save_licence(s->p, length);
+}
+
+/* Process a licence packet */
+void
+licence_process(STREAM s)
+{
+ uint8 tag;
+
+ in_uint8(s, tag);
+ in_uint8s(s, 3); /* version, 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:
+ case LICENCE_TAG_RESULT:
+ break;
+
+ default:
+ unimpl("licence tag 0x%x\n", tag);
+ }
+}
diff --git a/uirdesktop/makefile_win32 b/uirdesktop/makefile_win32
new file mode 100755
index 00000000..96a7c8ff
--- /dev/null
+++ b/uirdesktop/makefile_win32
@@ -0,0 +1,19 @@
+# makefile
+
+OBJS = tcp.obj iso.obj mcs.obj secure.obj rdp.obj rdp5.obj orders.obj \
+bitmap.obj cache.obj mppc.obj pstcache.obj channels.obj licence.obj \
+ssl_calls.obj
+
+UIOBJS = uimain.obj bsops.obj win32.obj
+
+#-w-aus -w-rch
+CFLAGS = -O2 -w-par -I.. -Ic:\borland\bcc55\include
+LDFLAGS = -W -Lc:\borland\bcc55\lib
+
+all: rd
+
+rd: $(OBJS) $(UIOBJS)
+ $(CC) -ewinrdesktop.exe $(LDFLAGS) $(OBJS) $(UIOBJS)
+
+clean:
+ del /q $(OBJS) $(UIOBJS) winrdesktop.exe *.tds
diff --git a/uirdesktop/mcs.c b/uirdesktop/mcs.c
index f6468307..c954d5e0 100644
--- a/uirdesktop/mcs.c
+++ b/uirdesktop/mcs.c
@@ -390,7 +390,7 @@ mcs_connect(char *server, STREAM mcs_data, char *username)
if (!mcs_recv_aucf(&g_mcs_userid))
goto error;
- mcs_send_cjrq(g_mcs_userid + MCS_USERCHANNEL_BASE);
+ mcs_send_cjrq((uint16) (g_mcs_userid + MCS_USERCHANNEL_BASE));
if (!mcs_recv_cjcf())
goto error;
@@ -431,7 +431,7 @@ mcs_reconnect(char *server, STREAM mcs_data)
if (!mcs_recv_aucf(&g_mcs_userid))
goto error;
- mcs_send_cjrq(g_mcs_userid + MCS_USERCHANNEL_BASE);
+ mcs_send_cjrq((uint16) (g_mcs_userid + MCS_USERCHANNEL_BASE));
if (!mcs_recv_cjcf())
goto error;
diff --git a/uirdesktop/orders.c b/uirdesktop/orders.c
index 418988ba..c870f2c3 100644
--- a/uirdesktop/orders.c
+++ b/uirdesktop/orders.c
@@ -296,7 +296,7 @@ process_line(STREAM s, LINE_ORDER * os, uint32 present, BOOL delta)
return;
}
- ui_line(os->opcode - 1, os->startx, os->starty, os->endx, os->endy, &os->pen);
+ ui_line(ROP_MINUS_1(os->opcode), os->startx, os->starty, os->endx, os->endy, &os->pen);
}
/* Process an opaque rectangle order */
@@ -379,7 +379,7 @@ process_desksave(STREAM s, DESKSAVE_ORDER * os, uint32 present, BOOL delta)
static void
process_memblt(STREAM s, MEMBLT_ORDER * os, uint32 present, BOOL delta)
{
- HBITMAP bitmap;
+ RD_HBITMAP bitmap;
if (present & 0x0001)
{
@@ -425,7 +425,7 @@ process_memblt(STREAM s, MEMBLT_ORDER * os, uint32 present, BOOL delta)
static void
process_triblt(STREAM s, TRIBLT_ORDER * os, uint32 present, BOOL delta)
{
- HBITMAP bitmap;
+ RD_HBITMAP bitmap;
if (present & 0x000001)
{
@@ -551,7 +551,7 @@ process_polygon(STREAM s, POLYGON_ORDER * os, uint32 present, BOOL delta)
}
if (next - 1 == os->npoints)
- ui_polygon(os->opcode - 1, os->fillmode, points, os->npoints + 1, NULL, 0,
+ ui_polygon(ROP_MINUS_1(os->opcode), os->fillmode, points, os->npoints + 1, NULL, 0,
os->fgcolour);
else
error("polygon parse error\n");
@@ -636,7 +636,7 @@ process_polygon2(STREAM s, POLYGON2_ORDER * os, uint32 present, BOOL delta)
}
if (next - 1 == os->npoints)
- ui_polygon(os->opcode - 1, os->fillmode, points, os->npoints + 1,
+ ui_polygon(ROP_MINUS_1(os->opcode), os->fillmode, points, os->npoints + 1,
&os->brush, os->bgcolour, os->fgcolour);
else
error("polygon2 parse error\n");
@@ -715,7 +715,7 @@ process_polyline(STREAM s, POLYLINE_ORDER * os, uint32 present, BOOL delta)
}
if (next - 1 == os->lines)
- ui_polyline(os->opcode - 1, points, os->lines + 1, &pen);
+ ui_polyline(ROP_MINUS_1(os->opcode), points, os->lines + 1, &pen);
else
error("polyline parse error\n");
@@ -750,7 +750,7 @@ process_ellipse(STREAM s, ELLIPSE_ORDER * os, uint32 present, BOOL delta)
DEBUG(("ELLIPSE(l=%d,t=%d,r=%d,b=%d,op=0x%x,fm=%d,fg=0x%x)\n", os->left, os->top,
os->right, os->bottom, os->opcode, os->fillmode, os->fgcolour));
- ui_ellipse(os->opcode - 1, os->fillmode, os->left, os->top, os->right - os->left,
+ ui_ellipse(ROP_MINUS_1(os->opcode), os->fillmode, os->left, os->top, os->right - os->left,
os->bottom - os->top, NULL, 0, os->fgcolour);
}
@@ -788,7 +788,7 @@ process_ellipse2(STREAM s, ELLIPSE2_ORDER * os, uint32 present, BOOL delta)
os->left, os->top, os->right, os->bottom, os->opcode, os->fillmode, os->brush.style,
os->bgcolour, os->fgcolour));
- ui_ellipse(os->opcode - 1, os->fillmode, os->left, os->top, os->right - os->left,
+ ui_ellipse(ROP_MINUS_1(os->opcode), os->fillmode, os->left, os->top, os->right - os->left,
os->bottom - os->top, &os->brush, os->bgcolour, os->fgcolour);
}
@@ -863,7 +863,7 @@ process_text2(STREAM s, TEXT2_ORDER * os, uint32 present, BOOL delta)
DEBUG(("\n"));
- ui_draw_text(os->font, os->flags, os->opcode - 1, os->mixmode, os->x, os->y,
+ ui_draw_text(os->font, os->flags, ROP_MINUS_1(os->opcode), 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,
@@ -874,10 +874,10 @@ process_text2(STREAM s, TEXT2_ORDER * os, uint32 present, BOOL delta)
static void
process_raw_bmpcache(STREAM s)
{
- HBITMAP bitmap;
+ RD_HBITMAP bitmap;
uint16 cache_idx, bufsize;
uint8 cache_id, width, height, bpp, Bpp;
- uint8 *data, *inverted;
+ uint8 *data/*, *inverted*/;
int y;
in_uint8(s, cache_id);
@@ -889,7 +889,8 @@ process_raw_bmpcache(STREAM s)
in_uint16_le(s, bufsize);
in_uint16_le(s, cache_idx);
in_uint8p(s, data, bufsize);
-
+ bitmap = ui_create_bitmap_ex(width, height, data, bufsize, False);
+/*
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++)
@@ -900,6 +901,7 @@ process_raw_bmpcache(STREAM s)
bitmap = ui_create_bitmap(width, height, inverted);
xfree(inverted);
+*/
cache_put_bitmap(cache_id, cache_idx, bitmap);
}
@@ -907,10 +909,10 @@ process_raw_bmpcache(STREAM s)
static void
process_bmpcache(STREAM s)
{
- HBITMAP bitmap;
+ RD_HBITMAP bitmap;
uint16 cache_idx, size;
uint8 cache_id, width, height, bpp, Bpp;
- uint8 *data, *bmpdata;
+ uint8 *data/*, *bmpdata*/;
uint16 bufsize, pad2, row_size, final_size;
uint8 pad1;
@@ -944,6 +946,9 @@ process_bmpcache(STREAM s)
DEBUG(("BMPCACHE(cx=%d,cy=%d,id=%d,idx=%d,bpp=%d,size=%d,pad1=%d,bufsize=%d,pad2=%d,rs=%d,fs=%d)\n", width, height, cache_id, cache_idx, bpp, size, pad1, bufsize, pad2, row_size, final_size));
+ bitmap = ui_create_bitmap_ex(width, height, data, size, True);
+ cache_put_bitmap(cache_id, cache_idx, bitmap);
+/*
bmpdata = (uint8 *) xmalloc(width * height * Bpp);
if (bitmap_decompress(bmpdata, width, height, data, size, Bpp))
@@ -957,13 +962,14 @@ process_bmpcache(STREAM s)
}
xfree(bmpdata);
+*/
}
/* Process a bitmap cache v2 order */
static void
process_bmpcache2(STREAM s, uint16 flags, BOOL compressed)
{
- HBITMAP bitmap;
+ RD_HBITMAP bitmap;
int y;
uint8 cache_id, cache_idx_low, width, height, Bpp;
uint16 cache_idx, bufsize;
@@ -1004,6 +1010,11 @@ process_bmpcache2(STREAM s, uint16 flags, BOOL compressed)
DEBUG(("BMPCACHE2(compr=%d,flags=%x,cx=%d,cy=%d,id=%d,idx=%d,Bpp=%d,bs=%d)\n",
compressed, flags, width, height, cache_id, cache_idx, Bpp, bufsize));
+ bitmap = ui_create_bitmap_ex(width, height, data, bufsize, compressed);
+ cache_put_bitmap(cache_id, cache_idx, bitmap);
+
+ /* todo, persitant bitmap not working this was */
+/*
bmpdata = (uint8 *) xmalloc(width * height * Bpp);
if (compressed)
@@ -1029,7 +1040,7 @@ process_bmpcache2(STREAM s, uint16 flags, BOOL compressed)
cache_put_bitmap(cache_id, cache_idx, bitmap);
if (flags & PERSIST)
pstcache_save_bitmap(cache_id, cache_idx, bitmap_id, width, height,
- width * height * Bpp, bmpdata);
+ (uint16) (width * height * Bpp), bmpdata);
}
else
{
@@ -1037,6 +1048,7 @@ process_bmpcache2(STREAM s, uint16 flags, BOOL compressed)
}
xfree(bmpdata);
+*/
}
/* Process a colourmap cache order */
@@ -1045,7 +1057,7 @@ process_colcache(STREAM s)
{
COLOURENTRY *entry;
COLOURMAP map;
- HCOLOURMAP hmap;
+ RD_HCOLOURMAP hmap;
uint8 cache_id;
int i;
@@ -1077,7 +1089,7 @@ process_colcache(STREAM s)
static void
process_fontcache(STREAM s)
{
- HGLYPH bitmap;
+ RD_HGLYPH bitmap;
uint8 font, nglyphs;
uint16 character, offset, baseline, width, height;
int i, datasize;
diff --git a/uirdesktop/proto.h b/uirdesktop/proto.h
new file mode 100755
index 00000000..826f932f
--- /dev/null
+++ b/uirdesktop/proto.h
@@ -0,0 +1,315 @@
+/* -*- c-basic-offset: 8 -*-
+ rdesktop: A Remote Desktop Protocol client.
+ Copyright (C) Matthew Chapman 1999-2005
+
+ 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.
+*/
+
+#ifndef RDESKTOP_PROTO_H
+#define RDESKTOP_PROTO_H
+
+/* *INDENT-OFF* */
+#ifdef __cplusplus
+extern "C" {
+#endif
+/* *INDENT-ON* */
+/* bitmap.c */
+BOOL bitmap_decompress(uint8 * output, int width, int height, uint8 * input, int size, int Bpp);
+BOOL bitmap_decompress_ex(uint8 * output, int width, int height, uint8 * input, int size,
+ int in_bpp, int out_bpp);
+/* cache.c */
+void cache_rebuild_bmpcache_linked_list(uint8 id, sint16 * idx, int count);
+void cache_bump_bitmap(uint8 id, uint16 idx, int bump);
+void cache_evict_bitmap(uint8 id);
+RD_HBITMAP cache_get_bitmap(uint8 id, uint16 idx);
+void cache_put_bitmap(uint8 id, uint16 idx, RD_HBITMAP bitmap);
+void cache_save_state(void);
+FONTGLYPH *cache_get_font(uint8 font, uint16 character);
+void cache_put_font(uint8 font, uint16 character, uint16 offset, uint16 baseline, uint16 width,
+ uint16 height, RD_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);
+RD_HCURSOR cache_get_cursor(uint16 cache_idx);
+void cache_put_cursor(uint16 cache_idx, RD_HCURSOR cursor);
+/* channels.c */
+VCHANNEL *channel_register(char *name, uint32 flags, void (*callback) (STREAM));
+STREAM channel_init(VCHANNEL * channel, uint32 length);
+void channel_send(STREAM s, VCHANNEL * channel);
+void channel_process(STREAM s, uint16 mcs_channel);
+/* cliprdr.c */
+void cliprdr_send_simple_native_format_announce(uint32 format);
+void cliprdr_send_native_format_announce(uint8 * formats_data, uint32 formats_data_length);
+void cliprdr_send_data_request(uint32 format);
+void cliprdr_send_data(uint8 * data, uint32 length);
+void cliprdr_set_mode(const char *optarg);
+BOOL cliprdr_init(void);
+/* disk.c */
+int disk_enum_devices(uint32 * id, char *optarg);
+RD_NTSTATUS disk_query_information(RD_NTHANDLE handle, uint32 info_class, STREAM out);
+RD_NTSTATUS disk_set_information(RD_NTHANDLE handle, uint32 info_class, STREAM in, STREAM out);
+RD_NTSTATUS disk_check_notify(RD_NTHANDLE handle);
+RD_NTSTATUS disk_create_notify(RD_NTHANDLE handle, uint32 info_class);
+RD_NTSTATUS disk_query_volume_information(RD_NTHANDLE handle, uint32 info_class, STREAM out);
+RD_NTSTATUS disk_query_directory(RD_NTHANDLE handle, uint32 info_class, char *pattern, STREAM out);
+/* mppc.c */
+int mppc_expand(uint8 * data, uint32 clen, uint8 ctype, uint32 * roff, uint32 * rlen);
+/* ewmhints.c */
+int get_current_workarea(uint32 * x, uint32 * y, uint32 * width, uint32 * height);
+void ewmh_init(void);
+/* iso.c */
+STREAM iso_init(int length);
+void iso_send(STREAM s);
+STREAM iso_recv(uint8 * rdpver);
+BOOL iso_connect(char *server, char *username);
+BOOL iso_reconnect(char *server);
+void iso_disconnect(void);
+void iso_reset_state(void);
+/* licence.c */
+void licence_process(STREAM s);
+/* mcs.c */
+STREAM mcs_init(int length);
+void mcs_send_to_channel(STREAM s, uint16 channel);
+void mcs_send(STREAM s);
+STREAM mcs_recv(uint16 * channel, uint8 * rdpver);
+BOOL mcs_connect(char *server, STREAM mcs_data, char *username);
+BOOL mcs_reconnect(char *server, STREAM mcs_data);
+void mcs_disconnect(void);
+void mcs_reset_state(void);
+/* orders.c */
+void process_orders(STREAM s, uint16 num_orders);
+void reset_order_state(void);
+/* parallel.c */
+int parallel_enum_devices(uint32 * id, char *optarg);
+/* printer.c */
+int printer_enum_devices(uint32 * id, char *optarg);
+/* printercache.c */
+int printercache_load_blob(char *printer_name, uint8 ** data);
+void printercache_process(STREAM s);
+/* pstcache.c */
+void pstcache_touch_bitmap(uint8 cache_id, uint16 cache_idx, uint32 stamp);
+BOOL pstcache_load_bitmap(uint8 cache_id, uint16 cache_idx);
+BOOL pstcache_save_bitmap(uint8 cache_id, uint16 cache_idx, uint8 * key, uint8 width,
+ uint8 height, uint16 length, uint8 * data);
+int pstcache_enumerate(uint8 id, HASH_KEY * keylist);
+BOOL pstcache_init(uint8 cache_id);
+/* rdesktop.c */
+int main(int argc, char *argv[]);
+void generate_random(uint8 * random);
+void *xmalloc(int size);
+char *xstrdup(const char *s);
+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);
+char *next_arg(char *src, char needle);
+void toupper_str(char *p);
+BOOL str_startswith(const char *s, const char *prefix);
+BOOL str_handle_lines(const char *input, char **rest, str_handle_lines_t linehandler, void *data);
+BOOL subprocess(char *const argv[], str_handle_lines_t linehandler, void *data);
+char *l_to_a(long N, int base);
+int load_licence(unsigned char **data);
+void save_licence(unsigned char *data, int length);
+BOOL rd_pstcache_mkdir(void);
+int rd_open_file(char *filename);
+void rd_close_file(int fd);
+int rd_read_file(int fd, void *ptr, int len);
+int rd_write_file(int fd, void *ptr, int len);
+int rd_lseek_file(int fd, int offset);
+BOOL rd_lock_file(int fd, int start, int len);
+/* rdp5.c */
+void rdp5_process(STREAM s);
+/* rdp.c */
+void rdp_out_unistr(STREAM s, char *string, int len);
+int rdp_in_unistr(STREAM s, char *string, int uni_len);
+void rdp_send_input(uint32 time, uint16 message_type, uint16 device_flags, uint16 param1,
+ uint16 param2);
+void rdp_send_client_window_status(int status);
+void process_colour_pointer_pdu(STREAM s);
+void process_cached_pointer_pdu(STREAM s);
+void process_system_pointer_pdu(STREAM s);
+void process_bitmap_updates(STREAM s);
+void process_palette(STREAM s);
+void process_disconnect_pdu(STREAM s, uint32 * ext_disc_reason);
+void rdp_main_loop(BOOL * deactivated, uint32 * ext_disc_reason);
+BOOL rdp_loop(BOOL * deactivated, uint32 * ext_disc_reason);
+BOOL rdp_connect(char *server, uint32 flags, char *domain, char *password, char *command,
+ char *directory);
+BOOL rdp_reconnect(char *server, uint32 flags, char *domain, char *password, char *command,
+ char *directory, char *cookie);
+void rdp_reset_state(void);
+void rdp_disconnect(void);
+/* rdpdr.c */
+int get_device_index(RD_NTHANDLE handle);
+void convert_to_unix_filename(char *filename);
+BOOL rdpdr_init(void);
+void rdpdr_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv, BOOL * timeout);
+struct async_iorequest *rdpdr_remove_iorequest(struct async_iorequest *prev,
+ struct async_iorequest *iorq);
+void rdpdr_check_fds(fd_set * rfds, fd_set * wfds, BOOL timed_out);
+BOOL rdpdr_abort_io(uint32 fd, uint32 major, RD_NTSTATUS status);
+/* rdpsnd.c */
+void rdpsnd_send_completion(uint16 tick, uint8 packet_index);
+BOOL rdpsnd_init(void);
+/* rdpsnd_oss.c */
+BOOL wave_out_open(void);
+void wave_out_close(void);
+BOOL wave_out_format_supported(WAVEFORMATEX * pwfx);
+BOOL wave_out_set_format(WAVEFORMATEX * pwfx);
+void wave_out_volume(uint16 left, uint16 right);
+void wave_out_write(STREAM s, uint16 tick, uint8 index);
+void wave_out_play(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);
+void sec_decrypt(uint8 * data, int length);
+STREAM sec_init(uint32 flags, int maxlen);
+void sec_send_to_channel(STREAM s, uint32 flags, uint16 channel);
+void sec_send(STREAM s, uint32 flags);
+void sec_process_mcs_data(STREAM s);
+STREAM sec_recv(uint8 * rdpver);
+BOOL sec_connect(char *server, char *username);
+BOOL sec_reconnect(char *server);
+void sec_disconnect(void);
+void sec_reset_state(void);
+/* serial.c */
+int serial_enum_devices(uint32 * id, char *optarg);
+BOOL serial_get_event(RD_NTHANDLE handle, uint32 * result);
+BOOL serial_get_timeout(RD_NTHANDLE handle, uint32 length, uint32 * timeout, uint32 * itv_timeout);
+/* tcp.c */
+STREAM tcp_init(uint32 maxlen);
+void tcp_send(STREAM s);
+STREAM tcp_recv(STREAM s, uint32 length);
+BOOL tcp_connect(char *server);
+void tcp_disconnect(void);
+char *tcp_get_address(void);
+void tcp_reset_state(void);
+/* xclip.c */
+void ui_clip_format_announce(uint8 * data, uint32 length);
+void ui_clip_handle_data(uint8 * data, uint32 length);
+void ui_clip_request_failed(void);
+void ui_clip_request_data(uint32 format);
+void ui_clip_sync(void);
+void ui_clip_set_mode(const char *optarg);
+void xclip_init(void);
+/* xkeymap.c */
+BOOL xkeymap_from_locale(const char *locale);
+FILE *xkeymap_open(const char *filename);
+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);
+void xkeymap_send_keys(uint32 keysym, unsigned int keycode, unsigned int state, uint32 ev_time,
+ BOOL pressed, uint8 nesting);
+uint16 xkeymap_translate_button(unsigned int button);
+char *get_ksname(uint32 keysym);
+void save_remote_modifiers(uint8 scancode);
+void restore_remote_modifiers(uint32 ev_time, uint8 scancode);
+void ensure_remote_modifiers(uint32 ev_time, key_translation tr);
+unsigned int read_keyboard_state(void);
+uint16 ui_get_numlock_state(unsigned int state);
+void reset_modifier_keys(void);
+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_resize_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);
+RD_HBITMAP ui_create_bitmap(int width, int height, uint8 * data);
+RD_HBITMAP ui_create_bitmap_ex(int width, int height, uint8 * data, int data_size, int compressed);
+void ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * data);
+void ui_paint_bitmap_ex(int x, int y, int cx, int cy, int width, int height, uint8 * data,
+ int data_size, int compressed);
+void ui_destroy_bitmap(RD_HBITMAP bmp);
+RD_HGLYPH ui_create_glyph(int width, int height, uint8 * data);
+void ui_destroy_glyph(RD_HGLYPH glyph);
+RD_HCURSOR ui_create_cursor(unsigned int x, unsigned int y, int width, int height, uint8 * andmask,
+ uint8 * xormask);
+void ui_set_cursor(RD_HCURSOR cursor);
+void ui_destroy_cursor(RD_HCURSOR cursor);
+void ui_set_null_cursor(void);
+RD_HCOLOURMAP ui_create_colourmap(COLOURMAP * colours);
+void ui_destroy_colourmap(RD_HCOLOURMAP map);
+void ui_set_colourmap(RD_HCOLOURMAP map);
+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, RD_HBITMAP src, int srcx, int srcy);
+void ui_triblt(uint8 opcode, int x, int y, int cx, int cy, RD_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_polygon(uint8 opcode, uint8 fillmode, POINT * point, int npoints, BRUSH * brush,
+ int bgcolour, int fgcolour);
+void ui_polyline(uint8 opcode, POINT * points, int npoints, PEN * pen);
+void ui_ellipse(uint8 opcode, uint8 fillmode, int x, int y, int cx, int cy, BRUSH * brush,
+ int bgcolour, int fgcolour);
+void ui_draw_glyph(int mixmode, int x, int y, int cx, int cy, RD_HGLYPH glyph, int srcx, int srcy,
+ int bgcolour, int fgcolour);
+void ui_draw_text(uint8 font, uint8 flags, uint8 opcode, int mixmode, int x, int y, int clipx,
+ int clipy, int clipcx, int clipcy, int boxx, int boxy, int boxcx, int boxcy,
+ BRUSH * brush, 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);
+void ui_begin_update(void);
+void ui_end_update(void);
+void ui_seamless_begin(BOOL hidden);
+void ui_seamless_hide_desktop(void);
+void ui_seamless_unhide_desktop(void);
+void ui_seamless_toggle(void);
+void ui_seamless_create_window(unsigned long id, unsigned long group, unsigned long parent,
+ unsigned long flags);
+void ui_seamless_destroy_window(unsigned long id, unsigned long flags);
+void ui_seamless_move_window(unsigned long id, int x, int y, int width, int height,
+ unsigned long flags);
+void ui_seamless_restack_window(unsigned long id, unsigned long behind, unsigned long flags);
+void ui_seamless_settitle(unsigned long id, const char *title, unsigned long flags);
+void ui_seamless_setstate(unsigned long id, unsigned int state, unsigned long flags);
+void ui_seamless_syncbegin(unsigned long flags);
+void ui_seamless_ack(unsigned int serial);
+/* lspci.c */
+BOOL lspci_init(void);
+/* seamless.c */
+BOOL seamless_init(void);
+unsigned int seamless_send_sync(void);
+unsigned int seamless_send_state(unsigned long id, unsigned int state, unsigned long flags);
+unsigned int seamless_send_position(unsigned long id, int x, int y, int width, int height,
+ unsigned long flags);
+void seamless_select_timeout(struct timeval *tv);
+unsigned int seamless_send_zchange(unsigned long id, unsigned long below, unsigned long flags);
+unsigned int seamless_send_focus(unsigned long id, unsigned long flags);
+
+/* *INDENT-OFF* */
+#ifdef __cplusplus
+}
+#endif
+/* *INDENT-ON* */
+
+#endif
diff --git a/uirdesktop/pstcache.c b/uirdesktop/pstcache.c
index 9e6432bd..7704d943 100644
--- a/uirdesktop/pstcache.c
+++ b/uirdesktop/pstcache.c
@@ -107,7 +107,7 @@ pstcache_save_bitmap(uint8 cache_id, uint16 cache_idx, uint8 * key,
int
pstcache_enumerate(uint8 id, HASH_KEY * keylist)
{
- int fd, n;
+ int fd, n;
uint16 idx;
sint16 mru_idx[0xa00];
uint32 mru_stamp[0xa00];
diff --git a/uirdesktop/rdesktop.h b/uirdesktop/rdesktop.h
index 989f6c39..e835231e 100644
--- a/uirdesktop/rdesktop.h
+++ b/uirdesktop/rdesktop.h
@@ -2,17 +2,17 @@
rdesktop: A Remote Desktop Protocol client.
Master include file
Copyright (C) Matthew Chapman 1999-2005
-
+
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.
@@ -20,15 +20,22 @@
#include <stdlib.h>
#include <stdio.h>
-#include <string.h>
-#include <dirent.h>
-#include <sys/time.h>
+#include <string.h>
+#ifdef _WIN32
+#include <winsock2.h> /* winsock2.h first */
+#include <windows.h>
+#include <time.h>
+#else /* WIN32 */
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/time.h>
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
-#else
+#else /* HAVE_SYS_SELECT_H */
#include <sys/types.h>
#include <unistd.h>
-#endif
+#endif /* HAVE_SYS_SELECT_H */
+#endif /* WIN32 */
#include <limits.h> /* PATH_MAX */
#define VERSION "1.4.1"
diff --git a/uirdesktop/rdp.c b/uirdesktop/rdp.c
index 045cc93f..d9810371 100644
--- a/uirdesktop/rdp.c
+++ b/uirdesktop/rdp.c
@@ -1,1447 +1,1457 @@
-/* -*- c-basic-offset: 8 -*-
- rdesktop: A Remote Desktop Protocol client.
- Protocol services - RDP layer
- Copyright (C) Matthew Chapman 1999-2005
-
- 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 <time.h>
-#include <errno.h>
-#include <unistd.h>
-#include "rdesktop.h"
-
-#ifdef HAVE_ICONV
-#ifdef HAVE_ICONV_H
-#include <iconv.h>
-#endif
-
-#ifndef ICONV_CONST
-#define ICONV_CONST ""
-#endif
-#endif
-
-extern uint16 g_mcs_userid;
-extern char g_username[64];
-extern char g_codepage[16];
-extern BOOL g_bitmap_compression;
-extern BOOL g_orders;
-extern BOOL g_encryption;
-extern BOOL g_desktop_save;
-extern BOOL g_polygon_ellipse_orders;
-extern BOOL g_use_rdp5;
-extern uint16 g_server_rdp_version;
-extern uint32 g_rdp5_performanceflags;
-extern int g_server_depth;
-extern int g_width;
-extern int g_height;
-extern BOOL g_bitmap_cache;
-extern BOOL g_bitmap_cache_persist_enable;
-extern BOOL g_numlock_sync;
-
-uint8 *g_next_packet;
-uint32 g_rdp_shareid;
-
-extern RDPCOMP g_mppc_dict;
-
-/* Session Directory support */
-extern BOOL g_redirect;
-extern char g_redirect_server[64];
-extern char g_redirect_domain[16];
-extern char g_redirect_password[64];
-extern char g_redirect_username[64];
-extern char g_redirect_cookie[128];
-extern uint32 g_redirect_flags;
-/* END Session Directory support */
-
-#if WITH_DEBUG
-static uint32 g_packetno;
-#endif
-
-#ifdef HAVE_ICONV
-static BOOL g_iconv_works = True;
-#endif
-
-/* Receive an RDP packet */
-static STREAM
-rdp_recv(uint8 * type)
-{
- static STREAM rdp_s;
- uint16 length, pdu_type;
- uint8 rdpver;
-
- if ((rdp_s == NULL) || (g_next_packet >= rdp_s->end) || (g_next_packet == NULL))
- {
- rdp_s = sec_recv(&rdpver);
- if (rdp_s == NULL)
- return NULL;
- if (rdpver == 0xff)
- {
- g_next_packet = rdp_s->end;
- *type = 0;
- return rdp_s;
- }
- else if (rdpver != 3)
- {
- /* rdp5_process should move g_next_packet ok */
- rdp5_process(rdp_s);
- *type = 0;
- return rdp_s;
- }
-
- g_next_packet = rdp_s->p;
- }
- else
- {
- rdp_s->p = g_next_packet;
- }
-
- in_uint16_le(rdp_s, length);
- /* 32k packets are really 8, keepalive fix */
- if (length == 0x8000)
- {
- g_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 #%d, (type %x)\n", ++g_packetno, *type));
- hexdump(g_next_packet, length);
-#endif /* */
-
- g_next_packet += length;
- return rdp_s;
-}
-
-/* Initialise an RDP data packet */
-static STREAM
-rdp_init_data(int maxlen)
-{
- STREAM s;
-
- s = sec_init(g_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, (g_mcs_userid + 1001));
-
- out_uint32_le(s, g_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, g_encryption ? SEC_ENCRYPT : 0);
-}
-
-/* Output a string in Unicode */
-void
-rdp_out_unistr(STREAM s, char *string, int len)
-{
-#ifdef HAVE_ICONV
- size_t ibl = strlen(string), obl = len + 2;
- static iconv_t iconv_h = (iconv_t) - 1;
- char *pin = string, *pout = (char *) s->p;
-
- memset(pout, 0, len + 4);
-
- if (g_iconv_works)
- {
- if (iconv_h == (iconv_t) - 1)
- {
- size_t i = 1, o = 4;
- if ((iconv_h = iconv_open(WINDOWS_CODEPAGE, g_codepage)) == (iconv_t) - 1)
- {
- warning("rdp_out_unistr: iconv_open[%s -> %s] fail %d\n",
- g_codepage, WINDOWS_CODEPAGE, (int) iconv_h);
-
- g_iconv_works = False;
- rdp_out_unistr(s, string, len);
- return;
- }
- if (iconv(iconv_h, (ICONV_CONST char **) &pin, &i, &pout, &o) ==
- (size_t) - 1)
- {
- iconv_close(iconv_h);
- iconv_h = (iconv_t) - 1;
- warning("rdp_out_unistr: iconv(1) fail, errno %d\n", errno);
-
- g_iconv_works = False;
- rdp_out_unistr(s, string, len);
- return;
- }
- pin = string;
- pout = (char *) s->p;
- }
-
- if (iconv(iconv_h, (ICONV_CONST char **) &pin, &ibl, &pout, &obl) == (size_t) - 1)
- {
- iconv_close(iconv_h);
- iconv_h = (iconv_t) - 1;
- warning("rdp_out_unistr: iconv(2) fail, errno %d\n", errno);
-
- g_iconv_works = False;
- rdp_out_unistr(s, string, len);
- return;
- }
-
- s->p += len + 2;
-
- }
- else
-#endif
- {
- int i = 0, j = 0;
-
- len += 2;
-
- while (i < len)
- {
- s->p[i++] = string[j++];
- s->p[i++] = 0;
- }
-
- s->p += len;
- }
-}
-
-/* Input a string in Unicode
- *
- * Returns str_len of string
- */
-int
-rdp_in_unistr(STREAM s, char *string, int uni_len)
-{
-#ifdef HAVE_ICONV
- size_t ibl = uni_len, obl = uni_len;
- char *pin = (char *) s->p, *pout = string;
- static iconv_t iconv_h = (iconv_t) - 1;
-
- if (g_iconv_works)
- {
- if (iconv_h == (iconv_t) - 1)
- {
- if ((iconv_h = iconv_open(g_codepage, WINDOWS_CODEPAGE)) == (iconv_t) - 1)
- {
- warning("rdp_in_unistr: iconv_open[%s -> %s] fail %d\n",
- WINDOWS_CODEPAGE, g_codepage, (int) iconv_h);
-
- g_iconv_works = False;
- return rdp_in_unistr(s, string, uni_len);
- }
- }
-
- if (iconv(iconv_h, (ICONV_CONST char **) &pin, &ibl, &pout, &obl) == (size_t) - 1)
- {
- iconv_close(iconv_h);
- iconv_h = (iconv_t) - 1;
- warning("rdp_in_unistr: iconv fail, errno %d\n", errno);
-
- g_iconv_works = False;
- return rdp_in_unistr(s, string, uni_len);
- }
-
- /* we must update the location of the current STREAM for future reads of s->p */
- s->p += uni_len;
-
- return pout - string;
- }
- else
-#endif
- {
- int i = 0;
-
- while (i < uni_len / 2)
- {
- in_uint8a(s, &string[i++], 1);
- in_uint8s(s, 1);
- }
-
- return i - 1;
- }
-}
-
-
-/* Parse a logon info packet */
-static void
-rdp_send_logon_info(uint32 flags, char *domain, char *user,
- char *password, char *program, char *directory)
-{
- char *ipaddr = tcp_get_address();
- 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);
- int len_ip = 2 * strlen(ipaddr);
- int len_dll = 2 * strlen("C:\\WINNT\\System32\\mstscax.dll");
- int packetlen = 0;
- uint32 sec_flags = g_encryption ? (SEC_LOGON_INFO | SEC_ENCRYPT) : SEC_LOGON_INFO;
- STREAM s;
- time_t t = time(NULL);
- time_t tzone;
-
- if (!g_use_rdp5 || 1 == g_server_rdp_version)
- {
- DEBUG_RDP5(("Sending RDP4-style Logon packet\n"));
-
- 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);
- }
- else
- {
-
- flags |= RDP_LOGON_BLOB;
- DEBUG_RDP5(("Sending RDP5-style Logon packet\n"));
- packetlen = 4 + /* Unknown uint32 */
- 4 + /* flags */
- 2 + /* len_domain */
- 2 + /* len_user */
- (flags & RDP_LOGON_AUTO ? 2 : 0) + /* len_password */
- (flags & RDP_LOGON_BLOB ? 2 : 0) + /* Length of BLOB */
- 2 + /* len_program */
- 2 + /* len_directory */
- (0 < len_domain ? len_domain : 2) + /* domain */
- len_user + (flags & RDP_LOGON_AUTO ? len_password : 0) + 0 + /* We have no 512 byte BLOB. Perhaps we must? */
- (flags & RDP_LOGON_BLOB && !(flags & RDP_LOGON_AUTO) ? 2 : 0) + /* After the BLOB is a unknown int16. If there is a BLOB, that is. */
- (0 < len_program ? len_program : 2) + (0 < len_directory ? len_directory : 2) + 2 + /* Unknown (2) */
- 2 + /* Client ip length */
- len_ip + /* Client ip */
- 2 + /* DLL string length */
- len_dll + /* DLL string */
- 2 + /* Unknown */
- 2 + /* Unknown */
- 64 + /* Time zone #0 */
- 2 + /* Unknown */
- 64 + /* Time zone #1 */
- 32; /* Unknown */
-
- s = sec_init(sec_flags, packetlen);
- DEBUG_RDP5(("Called sec_init with packetlen %d\n", packetlen));
-
- out_uint32(s, 0); /* Unknown */
- out_uint32_le(s, flags);
- out_uint16_le(s, len_domain);
- out_uint16_le(s, len_user);
- if (flags & RDP_LOGON_AUTO)
- {
- out_uint16_le(s, len_password);
-
- }
- if (flags & RDP_LOGON_BLOB && !(flags & RDP_LOGON_AUTO))
- {
- out_uint16_le(s, 0);
- }
- out_uint16_le(s, len_program);
- out_uint16_le(s, len_directory);
- if (0 < len_domain)
- rdp_out_unistr(s, domain, len_domain);
- else
- out_uint16_le(s, 0);
- rdp_out_unistr(s, user, len_user);
- if (flags & RDP_LOGON_AUTO)
- {
- rdp_out_unistr(s, password, len_password);
- }
- if (flags & RDP_LOGON_BLOB && !(flags & RDP_LOGON_AUTO))
- {
- out_uint16_le(s, 0);
- }
- if (0 < len_program)
- {
- rdp_out_unistr(s, program, len_program);
-
- }
- else
- {
- out_uint16_le(s, 0);
- }
- if (0 < len_directory)
- {
- rdp_out_unistr(s, directory, len_directory);
- }
- else
- {
- out_uint16_le(s, 0);
- }
- out_uint16_le(s, 2);
- out_uint16_le(s, len_ip + 2); /* Length of client ip */
- rdp_out_unistr(s, ipaddr, len_ip);
- out_uint16_le(s, len_dll + 2);
- rdp_out_unistr(s, "C:\\WINNT\\System32\\mstscax.dll", len_dll);
-
- tzone = (mktime(gmtime(&t)) - mktime(localtime(&t))) / 60;
- out_uint32_le(s, tzone);
-
- rdp_out_unistr(s, "GTB, normaltid", 2 * strlen("GTB, normaltid"));
- out_uint8s(s, 62 - 2 * strlen("GTB, normaltid"));
-
- out_uint32_le(s, 0x0a0000);
- out_uint32_le(s, 0x050000);
- out_uint32_le(s, 3);
- out_uint32_le(s, 0);
- out_uint32_le(s, 0);
-
- rdp_out_unistr(s, "GTB, sommartid", 2 * strlen("GTB, sommartid"));
- out_uint8s(s, 62 - 2 * strlen("GTB, sommartid"));
-
- out_uint32_le(s, 0x30000);
- out_uint32_le(s, 0x050000);
- out_uint32_le(s, 2);
- out_uint32(s, 0);
- out_uint32_le(s, 0xffffffc4);
- out_uint32_le(s, 0xfffffffe);
- out_uint32_le(s, g_rdp5_performanceflags);
- out_uint32(s, 0);
-
-
- }
- 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 a client window information PDU */
-void
-rdp_send_client_window_status(int status)
-{
- STREAM s;
- static int current_status = 1;
-
- if (current_status == status)
- return;
-
- s = rdp_init_data(12);
-
- out_uint32_le(s, status);
-
- switch (status)
- {
- case 0: /* shut the server up */
- break;
-
- case 1: /* receive data again */
- out_uint32_le(s, 0); /* unknown */
- out_uint16_le(s, g_width);
- out_uint16_le(s, g_height);
- break;
- }
-
- s_mark_end(s);
- rdp_send_data(s, RDP_DATA_PDU_CLIENT_WINDOW_STATUS);
- current_status = status;
-}
-
-/* Send persistent bitmap cache enumeration PDU's */
-static void
-rdp_enum_bmpcache2(void)
-{
- STREAM s;
- HASH_KEY keylist[BMPCACHE2_NUM_PSTCELLS];
- uint32 num_keys, offset, count, flags;
-
- offset = 0;
- num_keys = pstcache_enumerate(2, keylist);
-
- while (offset < num_keys)
- {
- count = MIN(num_keys - offset, 169);
-
- s = rdp_init_data(24 + count * sizeof(HASH_KEY));
-
- flags = 0;
- if (offset == 0)
- flags |= PDU_FLAG_FIRST;
- if (num_keys - offset <= 169)
- flags |= PDU_FLAG_LAST;
-
- /* header */
- out_uint32_le(s, 0);
- out_uint16_le(s, count);
- out_uint16_le(s, 0);
- out_uint16_le(s, 0);
- out_uint16_le(s, 0);
- out_uint16_le(s, 0);
- out_uint16_le(s, num_keys);
- out_uint32_le(s, 0);
- out_uint32_le(s, flags);
-
- /* list */
- out_uint8a(s, keylist[offset], count * sizeof(HASH_KEY));
-
- s_mark_end(s);
- rdp_send_data(s, 0x2b);
-
- offset += 169;
- }
-}
-
-/* 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, 0); /* pad? */
- 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_le(s, g_use_rdp5 ? 0x40d : 0);
- /* Pad, according to T.128. 0x40d seems to
- trigger
- the server to start sending RDP5 packets.
- However, the value is 0x1d04 with W2KTSK and
- NT4MS. Hmm.. Anyway, thankyou, Microsoft,
- for sending such information in a padding
- field.. */
- 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, g_server_depth); /* Preferred colour depth */
- 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, 1); /* Allow resize */
- out_uint16_le(s, g_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] = (g_bitmap_cache ? 1 : 0); /* memblt */
- order_caps[4] = 0; /* triblt */
- order_caps[8] = 1; /* line */
- order_caps[9] = 1; /* line */
- order_caps[10] = 1; /* rect */
- order_caps[11] = (g_desktop_save ? 1 : 0); /* desksave */
- order_caps[13] = 1; /* memblt */
- order_caps[14] = 1; /* triblt */
- order_caps[20] = (g_polygon_ellipse_orders ? 1 : 0); /* polygon */
- order_caps[21] = (g_polygon_ellipse_orders ? 1 : 0); /* polygon2 */
- order_caps[22] = 1; /* polyline */
- order_caps[25] = (g_polygon_ellipse_orders ? 1 : 0); /* ellipse */
- order_caps[26] = (g_polygon_ellipse_orders ? 1 : 0); /* ellipse2 */
- 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, g_desktop_save == False ? 0 : 0x38400); /* Desktop cache size */
- out_uint32(s, 0); /* Unknown */
- out_uint32_le(s, 0x4e4); /* Unknown */
-}
-
-/* Output bitmap cache capability set */
-static void
-rdp_out_bmpcache_caps(STREAM s)
-{
- int Bpp;
- out_uint16_le(s, RDP_CAPSET_BMPCACHE);
- out_uint16_le(s, RDP_CAPLEN_BMPCACHE);
-
- Bpp = (g_server_depth + 7) / 8; /* bytes per pixel */
- out_uint8s(s, 24); /* unused */
- out_uint16_le(s, 0x258); /* entries */
- out_uint16_le(s, 0x100 * Bpp); /* max cell size */
- out_uint16_le(s, 0x12c); /* entries */
- out_uint16_le(s, 0x400 * Bpp); /* max cell size */
- out_uint16_le(s, 0x106); /* entries */
- out_uint16_le(s, 0x1000 * Bpp); /* max cell size */
-}
-
-/* Output bitmap cache v2 capability set */
-static void
-rdp_out_bmpcache2_caps(STREAM s)
-{
- out_uint16_le(s, RDP_CAPSET_BMPCACHE2);
- out_uint16_le(s, RDP_CAPLEN_BMPCACHE2);
-
- out_uint16_le(s, g_bitmap_cache_persist_enable ? 2 : 0); /* version */
-
- out_uint16_be(s, 3); /* number of caches in this set */
-
- /* max cell size for cache 0 is 16x16, 1 = 32x32, 2 = 64x64, etc */
- out_uint32_le(s, BMPCACHE2_C0_CELLS);
- out_uint32_le(s, BMPCACHE2_C1_CELLS);
- if (pstcache_init(2))
- {
- out_uint32_le(s, BMPCACHE2_NUM_PSTCELLS | BMPCACHE2_FLAG_PERSIST);
- }
- else
- {
- out_uint32_le(s, BMPCACHE2_C2_CELLS);
- }
- out_uint8s(s, 20); /* other bitmap caches not used */
-}
-
-/* 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 caps_0x0d[] = {
- 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
-};
-
-static uint8 caps_0x0c[] = { 0x01, 0x00, 0x00, 0x00 };
-
-static uint8 caps_0x0e[] = { 0x01, 0x00, 0x00, 0x00 };
-
-static uint8 caps_0x10[] = {
- 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 sets */
-static void
-rdp_out_unknown_caps(STREAM s, uint16 id, uint16 length, uint8 * caps)
-{
- out_uint16_le(s, id);
- out_uint16_le(s, length);
-
- out_uint8p(s, caps, length - 4);
-}
-
-#define RDP5_FLAG 0x0030
-/* Send a confirm active PDU */
-static void
-rdp_send_confirm_active(void)
-{
- STREAM s;
- uint32 sec_flags = g_encryption ? (RDP5_FLAG | SEC_ENCRYPT) : RDP5_FLAG;
- 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 +
- 0x58 + 0x08 + 0x08 + 0x34 /* unknown caps */ +
- 4 /* w2k fix, why? */ ;
-
- s = sec_init(sec_flags, 6 + 14 + caplen + sizeof(RDP_SOURCE));
-
- out_uint16_le(s, 2 + 14 + caplen + sizeof(RDP_SOURCE));
- out_uint16_le(s, (RDP_PDU_CONFIRM_ACTIVE | 0x10)); /* Version 1 */
- out_uint16_le(s, (g_mcs_userid + 1001));
-
- out_uint32_le(s, g_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);
- g_use_rdp5 ? rdp_out_bmpcache2_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, 0x0d, 0x58, caps_0x0d); /* international? */
- rdp_out_unknown_caps(s, 0x0c, 0x08, caps_0x0c);
- rdp_out_unknown_caps(s, 0x0e, 0x08, caps_0x0e);
- rdp_out_unknown_caps(s, 0x10, 0x34, caps_0x10); /* glyph cache? */
-
- s_mark_end(s);
- sec_send(s, sec_flags);
-}
-
-/* Process a general capability set */
-static void
-rdp_process_general_caps(STREAM s)
-{
- uint16 pad2octetsB; /* rdp5 flags? */
-
- in_uint8s(s, 10);
- in_uint16_le(s, pad2octetsB);
-
- if (!pad2octetsB)
- g_use_rdp5 = False;
-}
-
-/* Process a bitmap capability set */
-static void
-rdp_process_bitmap_caps(STREAM s)
-{
- uint16 width, height, depth;
-
- in_uint16_le(s, depth);
- in_uint8s(s, 6);
-
- in_uint16_le(s, width);
- in_uint16_le(s, height);
-
- DEBUG(("setting desktop size and depth to: %dx%dx%d\n", width, height, depth));
-
- /*
- * The server may limit depth and change the size of the desktop (for
- * example when shadowing another session).
- */
- if (g_server_depth != depth)
- {
- warning("Remote desktop does not support colour depth %d; falling back to %d\n",
- g_server_depth, depth);
- g_server_depth = depth;
- }
- if (g_width != width || g_height != height)
- {
- warning("Remote desktop changed from %dx%d to %dx%d.\n", g_width, g_height,
- width, height);
- g_width = width;
- g_height = height;
- ui_resize_window();
- }
-}
-
-/* Process server capabilities */
-static void
-rdp_process_server_caps(STREAM s, uint16 length)
-{
- int n;
- uint8 *next, *start;
- uint16 ncapsets, capset_type, capset_length;
-
- start = s->p;
-
- in_uint16_le(s, ncapsets);
- in_uint8s(s, 2); /* pad */
-
- for (n = 0; n < ncapsets; n++)
- {
- if (s->p > start + length)
- return;
-
- in_uint16_le(s, capset_type);
- in_uint16_le(s, capset_length);
-
- next = s->p + capset_length - 4;
-
- switch (capset_type)
- {
- case RDP_CAPSET_GENERAL:
- rdp_process_general_caps(s);
- break;
-
- case RDP_CAPSET_BITMAP:
- rdp_process_bitmap_caps(s);
- break;
- }
-
- s->p = next;
- }
-}
-
-/* Respond to a demand active PDU */
-static void
-process_demand_active(STREAM s)
-{
- uint8 type;
- uint16 len_src_descriptor, len_combined_caps;
-
- in_uint32_le(s, g_rdp_shareid);
- in_uint16_le(s, len_src_descriptor);
- in_uint16_le(s, len_combined_caps);
- in_uint8s(s, len_src_descriptor);
-
- DEBUG(("DEMAND_ACTIVE(id=0x%x)\n", g_rdp_shareid));
- rdp_process_server_caps(s, len_combined_caps);
-
- 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,
- g_numlock_sync ? ui_get_numlock_state(read_keyboard_state()) : 0, 0);
-
- if (g_use_rdp5)
- {
- rdp_enum_bmpcache2();
- rdp_send_fonts(3);
- }
- else
- {
- rdp_send_fonts(1);
- rdp_send_fonts(2);
- }
-
- rdp_recv(&type); /* RDP_PDU_UNKNOWN 0x28 (Fonts?) */
- reset_order_state();
-}
-
-/* Process a colour pointer PDU */
-void
-process_colour_pointer_pdu(STREAM s)
-{
- uint16 x, y, width, height, cache_idx, masklen, datalen;
- uint8 *mask, *data;
- HCURSOR cursor;
-
- 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);
-}
-
-/* Process a cached pointer PDU */
-void
-process_cached_pointer_pdu(STREAM s)
-{
- uint16 cache_idx;
-
- in_uint16_le(s, cache_idx);
- ui_set_cursor(cache_get_cursor(cache_idx));
-}
-
-/* Process a system pointer PDU */
-void
-process_system_pointer_pdu(STREAM s)
-{
- uint16 system_pointer_type;
-
- in_uint16(s, system_pointer_type);
- switch (system_pointer_type)
- {
- case RDP_NULL_POINTER:
- ui_set_null_cursor();
- break;
-
- default:
- unimpl("System pointer message 0x%x\n", system_pointer_type);
- }
-}
-
-/* Process a pointer PDU */
-static void
-process_pointer_pdu(STREAM s)
-{
- uint16 message_type;
- uint16 x, y;
-
- 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:
- process_colour_pointer_pdu(s);
- break;
-
- case RDP_POINTER_CACHED:
- process_cached_pointer_pdu(s);
- break;
-
- case RDP_POINTER_SYSTEM:
- process_system_pointer_pdu(s);
- break;
-
- default:
- unimpl("Pointer message 0x%x\n", message_type);
- }
-}
-
-/* Process bitmap updates */
-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(("BITMAP_UPDATE(l=%d,t=%d,r=%d,b=%d,w=%d,h=%d,Bpp=%d,cmp=%d)\n",
- left, top, right, bottom, width, height, Bpp, 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;
- }
-
-
- if (compress & 0x400)
- {
- size = bufsize;
- }
- else
- {
- 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);
- }
- else
- {
- DEBUG_RDP5(("Failed to decompress data\n"));
- }
-
- xfree(bmpdata);
- }
-}
-
-/* Process a palette update */
-void
-process_palette(STREAM s)
-{
- COLOURENTRY *entry;
- COLOURMAP map;
- HCOLOURMAP hmap;
- int i;
-
- in_uint8s(s, 2); /* pad */
- in_uint16_le(s, map.ncolours);
- in_uint8s(s, 2); /* pad */
-
- map.colours = (COLOURENTRY *) xmalloc(sizeof(COLOURENTRY) * map.ncolours);
-
- DEBUG(("PALETTE(c=%d)\n", map.ncolours));
-
- 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);
-
- xfree(map.colours);
-}
-
-/* Process an update PDU */
-static void
-process_update_pdu(STREAM s)
-{
- uint16 update_type, count;
-
- in_uint16_le(s, update_type);
-
- ui_begin_update();
- switch (update_type)
- {
- case RDP_UPDATE_ORDERS:
- in_uint8s(s, 2); /* pad */
- in_uint16_le(s, count);
- in_uint8s(s, 2); /* pad */
- process_orders(s, count);
- 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 a disconnect PDU */
-void
-process_disconnect_pdu(STREAM s, uint32 * ext_disc_reason)
-{
- in_uint32_le(s, *ext_disc_reason);
-
- DEBUG(("Received disconnect PDU\n"));
-}
-
-/* Process data PDU */
-static BOOL
-process_data_pdu(STREAM s, uint32 * ext_disc_reason)
-{
- uint8 data_pdu_type;
- uint8 ctype;
- uint16 clen;
- uint32 len;
-
- uint32 roff, rlen;
-
- struct stream *ns = &(g_mppc_dict.ns);
-
- in_uint8s(s, 6); /* shareid, pad, streamid */
- in_uint16(s, len);
- in_uint8(s, data_pdu_type);
- in_uint8(s, ctype);
- in_uint16(s, clen);
- clen -= 18;
-
- if (ctype & RDP_MPPC_COMPRESSED)
- {
- if (len > RDP_MPPC_DICT_SIZE)
- error("error decompressed packet size exceeds max\n");
- if (mppc_expand(s->p, clen, ctype, &roff, &rlen) == -1)
- error("error while decompressing packet\n");
-
- /* len -= 18; */
-
- /* allocate memory and copy the uncompressed data into the temporary stream */
- ns->data = (uint8 *) xrealloc(ns->data, rlen);
-
- memcpy((ns->data), (unsigned char *) (g_mppc_dict.hist + roff), rlen);
-
- ns->size = rlen;
- ns->end = (ns->data + ns->size);
- ns->p = ns->data;
- ns->rdp_hdr = ns->p;
-
- s = ns;
- }
-
- switch (data_pdu_type)
- {
- case RDP_DATA_PDU_UPDATE:
- process_update_pdu(s);
- break;
-
- case RDP_DATA_PDU_CONTROL:
- DEBUG(("Received Control PDU\n"));
- break;
-
- case RDP_DATA_PDU_SYNCHRONISE:
- DEBUG(("Received Sync PDU\n"));
- break;
-
- case RDP_DATA_PDU_POINTER:
- process_pointer_pdu(s);
- break;
-
- case RDP_DATA_PDU_BELL:
- ui_bell();
- break;
-
- case RDP_DATA_PDU_LOGON:
- DEBUG(("Received Logon PDU\n"));
- /* User logged on */
- break;
-
- case RDP_DATA_PDU_DISCONNECT:
- process_disconnect_pdu(s, ext_disc_reason);
-
- /* We used to return true and disconnect immediately here, but
- * Windows Vista sends a disconnect PDU with reason 0 when
- * reconnecting to a disconnected session, and MSTSC doesn't
- * drop the connection. I think we should just save the status.
- */
- break;
-
- default:
- unimpl("data PDU %d\n", data_pdu_type);
- }
- return False;
-}
-
-/* Process redirect PDU from Session Directory */
-static BOOL
-process_redirect_pdu(STREAM s /*, uint32 * ext_disc_reason */ )
-{
- uint32 len;
-
- /* these 2 bytes are unknown, seem to be zeros */
- in_uint8s(s, 2);
-
- /* read connection flags */
- in_uint32_le(s, g_redirect_flags);
-
- /* read length of ip string */
- in_uint32_le(s, len);
-
- /* read ip string */
- rdp_in_unistr(s, g_redirect_server, len);
-
- /* read length of cookie string */
- in_uint32_le(s, len);
-
- /* read cookie string (plain ASCII) */
- in_uint8a(s, g_redirect_cookie, len);
- g_redirect_cookie[len] = 0;
-
- /* read length of username string */
- in_uint32_le(s, len);
-
- /* read username string */
- rdp_in_unistr(s, g_redirect_username, len);
-
- /* read length of domain string */
- in_uint32_le(s, len);
-
- /* read domain string */
- rdp_in_unistr(s, g_redirect_domain, len);
-
- /* read length of password string */
- in_uint32_le(s, len);
-
- /* read password string */
- rdp_in_unistr(s, g_redirect_password, len);
-
- g_redirect = True;
-
- return True;
-}
-
-/* Process incoming packets */
-/* nevers gets out of here till app is done */
-void
-rdp_main_loop(BOOL * deactivated, uint32 * ext_disc_reason)
-{
- while (rdp_loop(deactivated, ext_disc_reason))
- ;
-}
-
-/* used in uiports and rdp_main_loop, processes the rdp packets waiting */
-BOOL
-rdp_loop(BOOL * deactivated, uint32 * ext_disc_reason)
-{
- uint8 type;
- BOOL disc = False; /* True when a disconnect PDU was received */
- BOOL cont = True;
- STREAM s;
-
- while (cont)
- {
- s = rdp_recv(&type);
- if (s == NULL)
- return False;
- switch (type)
- {
- case RDP_PDU_DEMAND_ACTIVE:
- process_demand_active(s);
- *deactivated = False;
- break;
- case RDP_PDU_DEACTIVATE:
- DEBUG(("RDP_PDU_DEACTIVATE\n"));
- *deactivated = True;
- break;
- case RDP_PDU_REDIRECT:
- return process_redirect_pdu(s);
- break;
- case RDP_PDU_DATA:
- disc = process_data_pdu(s, ext_disc_reason);
- break;
- case 0:
- break;
- default:
- unimpl("PDU %d\n", type);
- }
- if (disc)
- return False;
- cont = g_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, g_username))
- return False;
-
- rdp_send_logon_info(flags, domain, g_username, password, command, directory);
- return True;
-}
-
-/* Establish a reconnection up to the RDP layer */
-BOOL
-rdp_reconnect(char *server, uint32 flags, char *domain, char *password,
- char *command, char *directory, char *cookie)
-{
- if (!sec_reconnect(server))
- return False;
-
- rdp_send_logon_info(flags, domain, g_username, password, command, directory);
- return True;
-}
-
-/* Called during redirection to reset the state to support redirection */
-void
-rdp_reset_state(void)
-{
- g_next_packet = NULL; /* reset the packet information */
- g_rdp_shareid = 0;
- sec_reset_state();
-}
-
-/* Disconnect from the RDP layer */
-void
-rdp_disconnect(void)
-{
- sec_disconnect();
-}
+/* -*- c-basic-offset: 8 -*-
+ rdesktop: A Remote Desktop Protocol client.
+ Protocol services - RDP layer
+ Copyright (C) Matthew Chapman 1999-2005
+
+ 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 <time.h>
+#ifndef _WIN32
+#include <errno.h>
+#include <unistd.h>
+#endif
+#include "rdesktop.h"
+
+#ifdef HAVE_ICONV
+#ifdef HAVE_ICONV_H
+#include <iconv.h>
+#endif
+
+#ifndef ICONV_CONST
+#define ICONV_CONST ""
+#endif
+#endif
+
+extern uint16 g_mcs_userid;
+extern char g_username[64];
+extern char g_codepage[16];
+extern BOOL g_bitmap_compression;
+extern BOOL g_orders;
+extern BOOL g_encryption;
+extern BOOL g_desktop_save;
+extern BOOL g_polygon_ellipse_orders;
+extern BOOL g_use_rdp5;
+extern uint16 g_server_rdp_version;
+extern uint32 g_rdp5_performanceflags;
+extern int g_server_depth;
+extern int g_width;
+extern int g_height;
+extern BOOL g_bitmap_cache;
+extern BOOL g_bitmap_cache_persist_enable;
+
+uint8 *g_next_packet;
+uint32 g_rdp_shareid;
+
+extern RDPCOMP g_mppc_dict;
+
+/* Session Directory support */
+extern BOOL g_redirect;
+extern char g_redirect_server[64];
+extern char g_redirect_domain[16];
+extern char g_redirect_password[64];
+extern char g_redirect_username[64];
+extern char g_redirect_cookie[128];
+extern uint32 g_redirect_flags;
+/* END Session Directory support */
+
+#ifdef WITH_DEBUG
+static uint32 g_packetno;
+#endif
+
+#ifdef HAVE_ICONV
+static BOOL g_iconv_works = True;
+#endif
+
+/* Receive an RDP packet */
+static STREAM
+rdp_recv(uint8 * type)
+{
+ static STREAM rdp_s;
+ uint16 length, pdu_type;
+ uint8 rdpver;
+
+ if ((rdp_s == NULL) || (g_next_packet >= rdp_s->end) || (g_next_packet == NULL))
+ {
+ rdp_s = sec_recv(&rdpver);
+ if (rdp_s == NULL)
+ return NULL;
+ if (rdpver == 0xff)
+ {
+ g_next_packet = rdp_s->end;
+ *type = 0;
+ return rdp_s;
+ }
+ else if (rdpver != 3)
+ {
+ /* rdp5_process should move g_next_packet ok */
+ rdp5_process(rdp_s);
+ *type = 0;
+ return rdp_s;
+ }
+
+ g_next_packet = rdp_s->p;
+ }
+ else
+ {
+ rdp_s->p = g_next_packet;
+ }
+
+ in_uint16_le(rdp_s, length);
+ /* 32k packets are really 8, keepalive fix */
+ if (length == 0x8000)
+ {
+ g_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;
+
+#ifdef WITH_DEBUG
+ DEBUG(("RDP packet #%d, (type %x)\n", ++g_packetno, *type));
+ hexdump(g_next_packet, length);
+#endif /* */
+
+ g_next_packet += length;
+ return rdp_s;
+}
+
+/* Initialise an RDP data packet */
+static STREAM
+rdp_init_data(int maxlen)
+{
+ STREAM s;
+
+ s = sec_init(g_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, (g_mcs_userid + 1001));
+
+ out_uint32_le(s, g_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, g_encryption ? SEC_ENCRYPT : 0);
+}
+
+/* Output a string in Unicode */
+void
+rdp_out_unistr(STREAM s, char *string, int len)
+{
+#ifdef HAVE_ICONV
+ size_t ibl = strlen(string), obl = len + 2;
+ static iconv_t iconv_h = (iconv_t) - 1;
+ char *pin = string, *pout = (char *) s->p;
+
+ memset(pout, 0, len + 4);
+
+ if (g_iconv_works)
+ {
+ if (iconv_h == (iconv_t) - 1)
+ {
+ size_t i = 1, o = 4;
+ if ((iconv_h = iconv_open(WINDOWS_CODEPAGE, g_codepage)) == (iconv_t) - 1)
+ {
+ warning("rdp_out_unistr: iconv_open[%s -> %s] fail %d\n",
+ g_codepage, WINDOWS_CODEPAGE, (int) iconv_h);
+
+ g_iconv_works = False;
+ rdp_out_unistr(s, string, len);
+ return;
+ }
+ if (iconv(iconv_h, (ICONV_CONST char **) &pin, &i, &pout, &o) ==
+ (size_t) - 1)
+ {
+ iconv_close(iconv_h);
+ iconv_h = (iconv_t) - 1;
+ warning("rdp_out_unistr: iconv(1) fail, errno %d\n", errno);
+
+ g_iconv_works = False;
+ rdp_out_unistr(s, string, len);
+ return;
+ }
+ pin = string;
+ pout = (char *) s->p;
+ }
+
+ if (iconv(iconv_h, (ICONV_CONST char **) &pin, &ibl, &pout, &obl) == (size_t) - 1)
+ {
+ iconv_close(iconv_h);
+ iconv_h = (iconv_t) - 1;
+ warning("rdp_out_unistr: iconv(2) fail, errno %d\n", errno);
+
+ g_iconv_works = False;
+ rdp_out_unistr(s, string, len);
+ return;
+ }
+
+ s->p += len + 2;
+
+ }
+ else
+#endif
+ {
+ int i = 0, j = 0;
+
+ len += 2;
+
+ while (i < len)
+ {
+ s->p[i++] = string[j++];
+ s->p[i++] = 0;
+ }
+
+ s->p += len;
+ }
+}
+
+/* Input a string in Unicode
+ *
+ * Returns str_len of string
+ */
+int
+rdp_in_unistr(STREAM s, char *string, int uni_len)
+{
+#ifdef HAVE_ICONV
+ size_t ibl = uni_len, obl = uni_len;
+ char *pin = (char *) s->p, *pout = string;
+ static iconv_t iconv_h = (iconv_t) - 1;
+
+ if (g_iconv_works)
+ {
+ if (iconv_h == (iconv_t) - 1)
+ {
+ if ((iconv_h = iconv_open(g_codepage, WINDOWS_CODEPAGE)) == (iconv_t) - 1)
+ {
+ warning("rdp_in_unistr: iconv_open[%s -> %s] fail %d\n",
+ WINDOWS_CODEPAGE, g_codepage, (int) iconv_h);
+
+ g_iconv_works = False;
+ return rdp_in_unistr(s, string, uni_len);
+ }
+ }
+
+ if (iconv(iconv_h, (ICONV_CONST char **) &pin, &ibl, &pout, &obl) == (size_t) - 1)
+ {
+ iconv_close(iconv_h);
+ iconv_h = (iconv_t) - 1;
+ warning("rdp_in_unistr: iconv fail, errno %d\n", errno);
+
+ g_iconv_works = False;
+ return rdp_in_unistr(s, string, uni_len);
+ }
+
+ /* we must update the location of the current STREAM for future reads of s->p */
+ s->p += uni_len;
+
+ return pout - string;
+ }
+ else
+#endif
+ {
+ int i = 0;
+
+ while (i < uni_len / 2)
+ {
+ in_uint8a(s, &string[i++], 1);
+ in_uint8s(s, 1);
+ }
+
+ return i - 1;
+ }
+}
+
+
+/* Parse a logon info packet */
+static void
+rdp_send_logon_info(uint32 flags, char *domain, char *user,
+ char *password, char *program, char *directory)
+{
+ char *ipaddr = tcp_get_address();
+ 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);
+ int len_ip = 2 * strlen(ipaddr);
+ int len_dll = 2 * strlen("C:\\WINNT\\System32\\mstscax.dll");
+ int packetlen = 0;
+ uint32 sec_flags = g_encryption ? (SEC_LOGON_INFO | SEC_ENCRYPT) : SEC_LOGON_INFO;
+ STREAM s;
+ //time_t t = time(NULL);
+ //time_t tzone;
+
+ if (!g_use_rdp5 || 1 == g_server_rdp_version)
+ {
+ DEBUG_RDP5(("Sending RDP4-style Logon packet\n"));
+
+ 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);
+ }
+ else
+ {
+#if 0
+ flags |= RDP_LOGON_BLOB;
+ DEBUG_RDP5(("Sending RDP5-style Logon packet\n"));
+ packetlen = 4 + /* Unknown uint32 */
+ 4 + /* flags */
+ 2 + /* len_domain */
+ 2 + /* len_user */
+ (flags & RDP_LOGON_AUTO ? 2 : 0) + /* len_password */
+ (flags & RDP_LOGON_BLOB ? 2 : 0) + /* Length of BLOB */
+ 2 + /* len_program */
+ 2 + /* len_directory */
+ (0 < len_domain ? len_domain : 2) + /* domain */
+ len_user + (flags & RDP_LOGON_AUTO ? len_password : 0) + 0 + /* We have no 512 byte BLOB. Perhaps we must? */
+ (flags & RDP_LOGON_BLOB && !(flags & RDP_LOGON_AUTO) ? 2 : 0) + /* After the BLOB is a unknown int16. If there is a BLOB, that is. */
+ (0 < len_program ? len_program : 2) + (0 < len_directory ? len_directory : 2) + 2 + /* Unknown (2) */
+ 2 + /* Client ip length */
+ len_ip + /* Client ip */
+ 2 + /* DLL string length */
+ len_dll + /* DLL string */
+ 2 + /* Unknown */
+ 2 + /* Unknown */
+ 64 + /* Time zone #0 */
+ 2 + /* Unknown */
+ 64 + /* Time zone #1 */
+ 32; /* Unknown */
+
+ s = sec_init(sec_flags, packetlen);
+ DEBUG_RDP5(("Called sec_init with packetlen %d\n", packetlen));
+
+ out_uint32(s, 0); /* Unknown */
+ out_uint32_le(s, flags);
+ out_uint16_le(s, len_domain);
+ out_uint16_le(s, len_user);
+ if (flags & RDP_LOGON_AUTO)
+ {
+ out_uint16_le(s, len_password);
+
+ }
+ if (flags & RDP_LOGON_BLOB && !(flags & RDP_LOGON_AUTO))
+ {
+ out_uint16_le(s, 0);
+ }
+ out_uint16_le(s, len_program);
+ out_uint16_le(s, len_directory);
+ if (0 < len_domain)
+ rdp_out_unistr(s, domain, len_domain);
+ else
+ out_uint16_le(s, 0);
+ rdp_out_unistr(s, user, len_user);
+ if (flags & RDP_LOGON_AUTO)
+ {
+ rdp_out_unistr(s, password, len_password);
+ }
+ if (flags & RDP_LOGON_BLOB && !(flags & RDP_LOGON_AUTO))
+ {
+ out_uint16_le(s, 0);
+ }
+ if (0 < len_program)
+ {
+ rdp_out_unistr(s, program, len_program);
+
+ }
+ else
+ {
+ out_uint16_le(s, 0);
+ }
+ if (0 < len_directory)
+ {
+ rdp_out_unistr(s, directory, len_directory);
+ }
+ else
+ {
+ out_uint16_le(s, 0);
+ }
+ out_uint16_le(s, 2);
+ out_uint16_le(s, len_ip + 2); /* Length of client ip */
+ rdp_out_unistr(s, ipaddr, len_ip);
+ out_uint16_le(s, len_dll + 2);
+ rdp_out_unistr(s, "C:\\WINNT\\System32\\mstscax.dll", len_dll);
+
+ tzone = (mktime(gmtime(&t)) - mktime(localtime(&t))) / 60;
+ out_uint32_le(s, tzone);
+
+ rdp_out_unistr(s, "GTB, normaltid", 2 * strlen("GTB, normaltid"));
+ out_uint8s(s, 62 - 2 * strlen("GTB, normaltid"));
+
+ out_uint32_le(s, 0x0a0000);
+ out_uint32_le(s, 0x050000);
+ out_uint32_le(s, 3);
+ out_uint32_le(s, 0);
+ out_uint32_le(s, 0);
+
+ rdp_out_unistr(s, "GTB, sommartid", 2 * strlen("GTB, sommartid"));
+ out_uint8s(s, 62 - 2 * strlen("GTB, sommartid"));
+
+ out_uint32_le(s, 0x30000);
+ out_uint32_le(s, 0x050000);
+ out_uint32_le(s, 2);
+ out_uint32(s, 0);
+ out_uint32_le(s, 0xffffffc4);
+ out_uint32_le(s, 0xfffffffe);
+ out_uint32_le(s, g_rdp5_performanceflags);
+ out_uint32(s, 0);
+
+#endif
+ }
+ 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 a client window information PDU */
+void
+rdp_send_client_window_status(int status)
+{
+ STREAM s;
+ static int current_status = 1;
+
+ if (current_status == status)
+ return;
+
+ s = rdp_init_data(12);
+
+ out_uint32_le(s, status);
+
+ switch (status)
+ {
+ case 0: /* shut the server up */
+ break;
+
+ case 1: /* receive data again */
+ out_uint32_le(s, 0); /* unknown */
+ out_uint16_le(s, g_width);
+ out_uint16_le(s, g_height);
+ break;
+ }
+
+ s_mark_end(s);
+ rdp_send_data(s, RDP_DATA_PDU_CLIENT_WINDOW_STATUS);
+ current_status = status;
+}
+
+/* Send persistent bitmap cache enumeration PDU's */
+static void
+rdp_enum_bmpcache2(void)
+{
+ STREAM s;
+ HASH_KEY keylist[BMPCACHE2_NUM_PSTCELLS];
+ uint32 num_keys, offset, count, flags;
+
+ offset = 0;
+ num_keys = pstcache_enumerate(2, keylist);
+
+ while (offset < num_keys)
+ {
+ count = MIN(num_keys - offset, 169);
+
+ s = rdp_init_data(24 + count * sizeof(HASH_KEY));
+
+ flags = 0;
+ if (offset == 0)
+ flags |= PDU_FLAG_FIRST;
+ if (num_keys - offset <= 169)
+ flags |= PDU_FLAG_LAST;
+
+ /* header */
+ out_uint32_le(s, 0);
+ out_uint16_le(s, count);
+ out_uint16_le(s, 0);
+ out_uint16_le(s, 0);
+ out_uint16_le(s, 0);
+ out_uint16_le(s, 0);
+ out_uint16_le(s, num_keys);
+ out_uint32_le(s, 0);
+ out_uint32_le(s, flags);
+
+ /* list */
+ out_uint8a(s, keylist[offset], count * sizeof(HASH_KEY));
+
+ s_mark_end(s);
+ rdp_send_data(s, 0x2b);
+
+ offset += 169;
+ }
+}
+
+/* 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, 0); /* pad? */
+ 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_le(s, g_use_rdp5 ? 0x40d : 0);
+ /* Pad, according to T.128. 0x40d seems to
+ trigger
+ the server to start sending RDP5 packets.
+ However, the value is 0x1d04 with W2KTSK and
+ NT4MS. Hmm.. Anyway, thankyou, Microsoft,
+ for sending such information in a padding
+ field.. */
+ 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, g_server_depth); /* Preferred colour depth */
+ 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, 1); /* Allow resize */
+ out_uint16_le(s, g_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] = (g_bitmap_cache ? 1 : 0); /* memblt */
+ order_caps[4] = 0; /* triblt */
+ order_caps[8] = 1; /* line */
+ order_caps[9] = 1; /* line */
+ order_caps[10] = 1; /* rect */
+ order_caps[11] = (g_desktop_save ? 1 : 0); /* desksave */
+ order_caps[13] = 1; /* memblt */
+ order_caps[14] = 1; /* triblt */
+ order_caps[20] = (g_polygon_ellipse_orders ? 1 : 0); /* polygon */
+ order_caps[21] = (g_polygon_ellipse_orders ? 1 : 0); /* polygon2 */
+ order_caps[22] = 1; /* polyline */
+ order_caps[25] = (g_polygon_ellipse_orders ? 1 : 0); /* ellipse */
+ order_caps[26] = (g_polygon_ellipse_orders ? 1 : 0); /* ellipse2 */
+ 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, g_desktop_save == False ? 0 : 0x38400); /* Desktop cache size */
+ out_uint32(s, 0); /* Unknown */
+ out_uint32_le(s, 0x4e4); /* Unknown */
+}
+
+/* Output bitmap cache capability set */
+static void
+rdp_out_bmpcache_caps(STREAM s)
+{
+ int Bpp;
+ out_uint16_le(s, RDP_CAPSET_BMPCACHE);
+ out_uint16_le(s, RDP_CAPLEN_BMPCACHE);
+
+ Bpp = (g_server_depth + 7) / 8; /* bytes per pixel */
+ out_uint8s(s, 24); /* unused */
+ out_uint16_le(s, 0x258); /* entries */
+ out_uint16_le(s, 0x100 * Bpp); /* max cell size */
+ out_uint16_le(s, 0x12c); /* entries */
+ out_uint16_le(s, 0x400 * Bpp); /* max cell size */
+ out_uint16_le(s, 0x106); /* entries */
+ out_uint16_le(s, 0x1000 * Bpp); /* max cell size */
+}
+
+/* Output bitmap cache v2 capability set */
+static void
+rdp_out_bmpcache2_caps(STREAM s)
+{
+ out_uint16_le(s, RDP_CAPSET_BMPCACHE2);
+ out_uint16_le(s, RDP_CAPLEN_BMPCACHE2);
+
+ out_uint16_le(s, g_bitmap_cache_persist_enable ? 2 : 0); /* version */
+
+ out_uint16_be(s, 3); /* number of caches in this set */
+
+ /* max cell size for cache 0 is 16x16, 1 = 32x32, 2 = 64x64, etc */
+ out_uint32_le(s, BMPCACHE2_C0_CELLS);
+ out_uint32_le(s, BMPCACHE2_C1_CELLS);
+ if (pstcache_init(2))
+ {
+ out_uint32_le(s, BMPCACHE2_NUM_PSTCELLS | BMPCACHE2_FLAG_PERSIST);
+ }
+ else
+ {
+ out_uint32_le(s, BMPCACHE2_C2_CELLS);
+ }
+ out_uint8s(s, 20); /* other bitmap caches not used */
+}
+
+/* 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 caps_0x0d[] = {
+ 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
+};
+
+static uint8 caps_0x0c[] = { 0x01, 0x00, 0x00, 0x00 };
+
+static uint8 caps_0x0e[] = { 0x01, 0x00, 0x00, 0x00 };
+
+static uint8 caps_0x10[] = {
+ 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 sets */
+static void
+rdp_out_unknown_caps(STREAM s, uint16 id, uint16 length, uint8 * caps)
+{
+ out_uint16_le(s, id);
+ out_uint16_le(s, length);
+
+ out_uint8p(s, caps, length - 4);
+}
+
+#define RDP5_FLAG 0x0030
+/* Send a confirm active PDU */
+static void
+rdp_send_confirm_active(void)
+{
+ STREAM s;
+ uint32 sec_flags = g_encryption ? (RDP5_FLAG | SEC_ENCRYPT) : RDP5_FLAG;
+ 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 +
+ 0x58 + 0x08 + 0x08 + 0x34 /* unknown caps */ +
+ 4 /* w2k fix, why? */ ;
+
+ s = sec_init(sec_flags, 6 + 14 + caplen + sizeof(RDP_SOURCE));
+
+ out_uint16_le(s, 2 + 14 + caplen + sizeof(RDP_SOURCE));
+ out_uint16_le(s, (RDP_PDU_CONFIRM_ACTIVE | 0x10)); /* Version 1 */
+ out_uint16_le(s, (g_mcs_userid + 1001));
+
+ out_uint32_le(s, g_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);
+ g_use_rdp5 ? rdp_out_bmpcache2_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, 0x0d, 0x58, caps_0x0d); /* international? */
+ rdp_out_unknown_caps(s, 0x0c, 0x08, caps_0x0c);
+ rdp_out_unknown_caps(s, 0x0e, 0x08, caps_0x0e);
+ rdp_out_unknown_caps(s, 0x10, 0x34, caps_0x10); /* glyph cache? */
+
+ s_mark_end(s);
+ sec_send(s, sec_flags);
+}
+
+/* Process a general capability set */
+static void
+rdp_process_general_caps(STREAM s)
+{
+ uint16 pad2octetsB; /* rdp5 flags? */
+
+ in_uint8s(s, 10);
+ in_uint16_le(s, pad2octetsB);
+
+ if (!pad2octetsB)
+ g_use_rdp5 = False;
+}
+
+/* Process a bitmap capability set */
+static void
+rdp_process_bitmap_caps(STREAM s)
+{
+ uint16 width, height, depth;
+
+ in_uint16_le(s, depth);
+ in_uint8s(s, 6);
+
+ in_uint16_le(s, width);
+ in_uint16_le(s, height);
+
+ DEBUG(("setting desktop size and depth to: %dx%dx%d\n", width, height, depth));
+
+ /*
+ * The server may limit depth and change the size of the desktop (for
+ * example when shadowing another session).
+ */
+ if (g_server_depth != depth)
+ {
+ warning("Remote desktop does not support colour depth %d; falling back to %d\n",
+ g_server_depth, depth);
+ g_server_depth = depth;
+ }
+ if (g_width != width || g_height != height)
+ {
+ warning("Remote desktop changed from %dx%d to %dx%d.\n", g_width, g_height,
+ width, height);
+ g_width = width;
+ g_height = height;
+ ui_resize_window();
+ }
+}
+
+/* Process server capabilities */
+static void
+rdp_process_server_caps(STREAM s, uint16 length)
+{
+ int n;
+ uint8 *next, *start;
+ uint16 ncapsets, capset_type, capset_length;
+
+ start = s->p;
+
+ in_uint16_le(s, ncapsets);
+ in_uint8s(s, 2); /* pad */
+
+ for (n = 0; n < ncapsets; n++)
+ {
+ if (s->p > start + length)
+ return;
+
+ in_uint16_le(s, capset_type);
+ in_uint16_le(s, capset_length);
+
+ next = s->p + capset_length - 4;
+
+ switch (capset_type)
+ {
+ case RDP_CAPSET_GENERAL:
+ rdp_process_general_caps(s);
+ break;
+
+ case RDP_CAPSET_BITMAP:
+ rdp_process_bitmap_caps(s);
+ break;
+ }
+
+ s->p = next;
+ }
+}
+
+/* Respond to a demand active PDU */
+static void
+process_demand_active(STREAM s)
+{
+ uint8 type;
+ uint16 len_src_descriptor, len_combined_caps;
+
+ in_uint32_le(s, g_rdp_shareid);
+ in_uint16_le(s, len_src_descriptor);
+ in_uint16_le(s, len_combined_caps);
+ in_uint8s(s, len_src_descriptor);
+
+ DEBUG(("DEMAND_ACTIVE(id=0x%x)\n", g_rdp_shareid));
+ rdp_process_server_caps(s, len_combined_caps);
+
+ 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, ui_get_numlock_state(read_keyboard_state()), 0);
+
+ if (g_use_rdp5)
+ {
+ rdp_enum_bmpcache2();
+ rdp_send_fonts(3);
+ }
+ else
+ {
+ rdp_send_fonts(1);
+ rdp_send_fonts(2);
+ }
+
+ rdp_recv(&type); /* RDP_PDU_UNKNOWN 0x28 (Fonts?) */
+ reset_order_state();
+}
+
+/* Process a colour pointer PDU */
+void
+process_colour_pointer_pdu(STREAM s)
+{
+ uint16 x, y, width, height, cache_idx, masklen, datalen;
+ uint8 *mask, *data;
+ HCURSOR cursor;
+
+ 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);
+}
+
+/* Process a cached pointer PDU */
+void
+process_cached_pointer_pdu(STREAM s)
+{
+ uint16 cache_idx;
+
+ in_uint16_le(s, cache_idx);
+ ui_set_cursor(cache_get_cursor(cache_idx));
+}
+
+/* Process a system pointer PDU */
+void
+process_system_pointer_pdu(STREAM s)
+{
+ uint16 system_pointer_type;
+
+ in_uint16(s, system_pointer_type);
+ switch (system_pointer_type)
+ {
+ case RDP_NULL_POINTER:
+ ui_set_null_cursor();
+ break;
+
+ default:
+ unimpl("System pointer message 0x%x\n", system_pointer_type);
+ }
+}
+
+/* Process a pointer PDU */
+static void
+process_pointer_pdu(STREAM s)
+{
+ uint16 message_type;
+ uint16 x, y;
+
+ 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:
+ process_colour_pointer_pdu(s);
+ break;
+
+ case RDP_POINTER_CACHED:
+ process_cached_pointer_pdu(s);
+ break;
+
+ case RDP_POINTER_SYSTEM:
+ process_system_pointer_pdu(s);
+ break;
+
+ default:
+ unimpl("Pointer message 0x%x\n", message_type);
+ }
+}
+
+/* Process bitmap updates */
+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(("BITMAP_UPDATE(l=%d,t=%d,r=%d,b=%d,w=%d,h=%d,Bpp=%d,cmp=%d)\n",
+ left, top, right, bottom, width, height, Bpp, compress));
+ if (!compress)
+ {
+ size = width * height * Bpp; /* same as bufsize */
+ }
+ else if (compress & 0x400)
+ {
+ size = bufsize;
+ }
+ else
+ {
+ in_uint8s(s, 2); /* pad */
+ in_uint16_le(s, size);
+ in_uint8s(s, 4);
+ }
+ in_uint8p(s, data, size);
+ ui_paint_bitmap_ex(left, top, cx, cy, width, height, data, size, compress);
+#if 0
+ 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;
+ }
+
+
+ if (compress & 0x400)
+ {
+ size = bufsize;
+ }
+ else
+ {
+ 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);
+ }
+ else
+ {
+ DEBUG_RDP5(("Failed to decompress data\n"));
+ }
+ xfree(bmpdata);
+#endif
+ }
+}
+
+/* Process a palette update */
+void
+process_palette(STREAM s)
+{
+ COLOURENTRY *entry;
+ COLOURMAP map;
+ RD_HCOLOURMAP hmap;
+ int i;
+
+ in_uint8s(s, 2); /* pad */
+ in_uint16_le(s, map.ncolours);
+ in_uint8s(s, 2); /* pad */
+
+ map.colours = (COLOURENTRY *) xmalloc(sizeof(COLOURENTRY) * map.ncolours);
+
+ DEBUG(("PALETTE(c=%d)\n", map.ncolours));
+
+ 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);
+
+ xfree(map.colours);
+}
+
+/* Process an update PDU */
+static void
+process_update_pdu(STREAM s)
+{
+ uint16 update_type, count;
+
+ in_uint16_le(s, update_type);
+
+ ui_begin_update();
+ switch (update_type)
+ {
+ case RDP_UPDATE_ORDERS:
+ in_uint8s(s, 2); /* pad */
+ in_uint16_le(s, count);
+ in_uint8s(s, 2); /* pad */
+ process_orders(s, count);
+ 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 a disconnect PDU */
+void
+process_disconnect_pdu(STREAM s, uint32 * ext_disc_reason)
+{
+ in_uint32_le(s, *ext_disc_reason);
+
+ DEBUG(("Received disconnect PDU\n"));
+}
+
+/* Process data PDU */
+static BOOL
+process_data_pdu(STREAM s, uint32 * ext_disc_reason)
+{
+ uint8 data_pdu_type;
+ uint8 ctype;
+ uint16 clen;
+ uint32 len;
+
+ uint32 roff, rlen;
+
+ struct stream *ns = &(g_mppc_dict.ns);
+
+ in_uint8s(s, 6); /* shareid, pad, streamid */
+ in_uint16(s, len);
+ in_uint8(s, data_pdu_type);
+ in_uint8(s, ctype);
+ in_uint16(s, clen);
+ clen -= 18;
+
+ if (ctype & RDP_MPPC_COMPRESSED)
+ {
+ if (len > RDP_MPPC_DICT_SIZE)
+ error("error decompressed packet size exceeds max\n");
+ if (mppc_expand(s->p, clen, ctype, &roff, &rlen) == -1)
+ error("error while decompressing packet\n");
+
+ /* len -= 18; */
+
+ /* allocate memory and copy the uncompressed data into the temporary stream */
+ ns->data = (uint8 *) xrealloc(ns->data, rlen);
+
+ memcpy((ns->data), (unsigned char *) (g_mppc_dict.hist + roff), rlen);
+
+ ns->size = rlen;
+ ns->end = (ns->data + ns->size);
+ ns->p = ns->data;
+ ns->rdp_hdr = ns->p;
+
+ s = ns;
+ }
+
+ switch (data_pdu_type)
+ {
+ case RDP_DATA_PDU_UPDATE:
+ process_update_pdu(s);
+ break;
+
+ case RDP_DATA_PDU_CONTROL:
+ DEBUG(("Received Control PDU\n"));
+ break;
+
+ case RDP_DATA_PDU_SYNCHRONISE:
+ DEBUG(("Received Sync PDU\n"));
+ break;
+
+ case RDP_DATA_PDU_POINTER:
+ process_pointer_pdu(s);
+ break;
+
+ case RDP_DATA_PDU_BELL:
+ ui_bell();
+ break;
+
+ case RDP_DATA_PDU_LOGON:
+ DEBUG(("Received Logon PDU\n"));
+ /* User logged on */
+ break;
+
+ case RDP_DATA_PDU_DISCONNECT:
+ process_disconnect_pdu(s, ext_disc_reason);
+ return True;
+
+ default:
+ unimpl("data PDU %d\n", data_pdu_type);
+ }
+ return False;
+}
+
+/* Process redirect PDU from Session Directory */
+static BOOL
+process_redirect_pdu(STREAM s /*, uint32 * ext_disc_reason */ )
+{
+ uint32 len;
+
+ /* these 2 bytes are unknown, seem to be zeros */
+ in_uint8s(s, 2);
+
+ /* read connection flags */
+ in_uint32_le(s, g_redirect_flags);
+
+ /* read length of ip string */
+ in_uint32_le(s, len);
+
+ /* read ip string */
+ rdp_in_unistr(s, g_redirect_server, len);
+
+ /* read length of cookie string */
+ in_uint32_le(s, len);
+
+ /* read cookie string (plain ASCII) */
+ in_uint8a(s, g_redirect_cookie, len);
+ g_redirect_cookie[len] = 0;
+
+ /* read length of username string */
+ in_uint32_le(s, len);
+
+ /* read username string */
+ rdp_in_unistr(s, g_redirect_username, len);
+
+ /* read length of domain string */
+ in_uint32_le(s, len);
+
+ /* read domain string */
+ rdp_in_unistr(s, g_redirect_domain, len);
+
+ /* read length of password string */
+ in_uint32_le(s, len);
+
+ /* read password string */
+ rdp_in_unistr(s, g_redirect_password, len);
+
+ g_redirect = True;
+
+ return True;
+}
+
+/* Process incoming packets */
+/* nevers gets out of here till app is done */
+void
+rdp_main_loop(BOOL * deactivated, uint32 * ext_disc_reason)
+{
+ while (rdp_loop(deactivated, ext_disc_reason))
+ ;
+}
+
+/* used in uiports and rdp_main_loop, processes the rdp packets waiting */
+BOOL
+rdp_loop(BOOL * deactivated, uint32 * ext_disc_reason)
+{
+ uint8 type;
+ BOOL disc = False; /* True when a disconnect PDU was received */
+ BOOL cont = True;
+ STREAM s;
+
+ while (cont)
+ {
+ s = rdp_recv(&type);
+ if (s == NULL)
+ return False;
+ switch (type)
+ {
+ case RDP_PDU_DEMAND_ACTIVE:
+ process_demand_active(s);
+ *deactivated = False;
+ break;
+ case RDP_PDU_DEACTIVATE:
+ DEBUG(("RDP_PDU_DEACTIVATE\n"));
+ *deactivated = True;
+ break;
+ case RDP_PDU_REDIRECT:
+ return process_redirect_pdu(s);
+ break;
+ case RDP_PDU_DATA:
+ disc = process_data_pdu(s, ext_disc_reason);
+ break;
+ case 0:
+ break;
+ default:
+ unimpl("PDU %d\n", type);
+ }
+ if (disc)
+ return False;
+ cont = g_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, g_username))
+ return False;
+
+ rdp_send_logon_info(flags, domain, g_username, password, command, directory);
+ return True;
+}
+
+/* Establish a reconnection up to the RDP layer */
+BOOL
+rdp_reconnect(char *server, uint32 flags, char *domain, char *password,
+ char *command, char *directory, char *cookie)
+{
+ if (!sec_reconnect(server))
+ return False;
+
+ rdp_send_logon_info(flags, domain, g_username, password, command, directory);
+ return True;
+}
+
+/* Called during redirection to reset the state to support redirection */
+void
+rdp_reset_state(void)
+{
+ g_next_packet = NULL; /* reset the packet information */
+ g_rdp_shareid = 0;
+ sec_reset_state();
+}
+
+/* Disconnect from the RDP layer */
+void
+rdp_disconnect(void)
+{
+ sec_disconnect();
+}
diff --git a/uirdesktop/secure.c b/uirdesktop/secure.c
index 0d22ecc3..90b8eedb 100644
--- a/uirdesktop/secure.c
+++ b/uirdesktop/secure.c
@@ -20,12 +20,48 @@
#include "rdesktop.h"
-#include <openssl/rc4.h>
-#include <openssl/md5.h>
-#include <openssl/sha.h>
-#include <openssl/bn.h>
-#include <openssl/x509v3.h>
-
+//#include <openssl/rc4.h>
+//#include <openssl/md5.h>
+//#include <openssl/sha.h>
+//#include <openssl/bn.h>
+//#include <openssl/x509v3.h>
+
+void *
+ssl_sha1_info_create(void);
+void
+ssl_sha1_info_delete(void * sha1_info);
+void
+ssl_sha1_clear(void * sha1_info);
+void
+ssl_sha1_transform(void * sha1_info, char * data, int len);
+void
+ssl_sha1_complete(void * sha1_info, char * data);
+void *
+ssl_md5_info_create(void);
+void
+ssl_md5_info_delete(void * md5_info);
+void *
+ssl_md5_info_create(void);
+void
+ssl_md5_info_delete(void * md5_info);
+void
+ssl_md5_clear(void * md5_info);
+void
+ssl_md5_transform(void * md5_info, char * data, int len);
+void
+ssl_md5_complete(void * md5_info, char * data);
+void *
+ssl_rc4_info_create(void);
+void
+ssl_rc4_info_delete(void * rc4_info);
+void
+ssl_rc4_set_key(void * rc4_info, char * key, int len);
+void
+ssl_rc4_crypt(void * rc4_info, char * in_data, char * out_data, int len);
+int
+ssl_mod_exp(char* out, int out_len, char* in, int in_len,
+ char* mod, int mod_len, char* exp, int exp_len);
+
extern char g_hostname[16];
extern int g_width;
extern int g_height;
@@ -43,17 +79,17 @@ extern VCHANNEL g_channels[];
extern unsigned int g_num_channels;
static int rc4_key_len;
-static RC4_KEY rc4_decrypt_key;
-static RC4_KEY rc4_encrypt_key;
-static RSA *server_public_key;
-static uint32 server_public_key_len;
+static void * rc4_decrypt_key = 0;
+static void * rc4_encrypt_key = 0;
+//static RSA *server_public_key;
+static void * server_public_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_MAX_MODULUS_SIZE];
+static uint8 sec_crypted_random[SEC_MODULUS_SIZE];
uint16 g_server_rdp_version = 0;
@@ -80,25 +116,27 @@ 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;
+ void * sha;
+ void * 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);
+ sha = ssl_sha1_info_create();
+ ssl_sha1_clear(sha);
+ ssl_sha1_transform(sha, pad, i + 1);
+ ssl_sha1_transform(sha, in, 48);
+ ssl_sha1_transform(sha, salt1, 32);
+ ssl_sha1_transform(sha, salt2, 32);
+ ssl_sha1_complete(sha, shasig);
+ ssl_sha1_info_delete(sha);
+ md5 = ssl_md5_info_create();
+ ssl_md5_clear(md5);
+ ssl_md5_transform(md5, in, 48);
+ ssl_md5_transform(md5, shasig, 20);
+ ssl_md5_complete(md5, out + i * 16);
+ ssl_md5_info_delete(md5);
}
}
@@ -108,13 +146,15 @@ 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)
{
- 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);
+ void * md5;
+
+ md5 = ssl_md5_info_create();
+ ssl_md5_clear(md5);
+ ssl_md5_transform(md5, in, 16);
+ ssl_md5_transform(md5, salt1, 32);
+ ssl_md5_transform(md5, salt2, 32);
+ ssl_md5_complete(md5, out);
+ ssl_md5_info_delete(md5);
}
/* Reduce key entropy from 64 to 40 bits */
@@ -167,9 +207,15 @@ sec_generate_keys(uint8 * client_random, uint8 * server_random, int rc4_key_size
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);
+ /* Initialise RC4 state arrays */
+
+ ssl_rc4_info_delete(rc4_decrypt_key);
+ rc4_decrypt_key = ssl_rc4_info_create();
+ ssl_rc4_set_key(rc4_decrypt_key, sec_decrypt_key, rc4_key_len);
+
+ ssl_rc4_info_delete(rc4_encrypt_key);
+ rc4_encrypt_key = ssl_rc4_info_create();
+ ssl_rc4_set_key(rc4_encrypt_key, sec_encrypt_key, rc4_key_len);
}
static uint8 pad_54[40] = {
@@ -203,24 +249,28 @@ sec_sign(uint8 * signature, int siglen, uint8 * session_key, int keylen, uint8 *
uint8 shasig[20];
uint8 md5sig[16];
uint8 lenhdr[4];
- SHA_CTX sha;
- MD5_CTX md5;
+ void * sha;
+ void * 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);
-
+ sha = ssl_sha1_info_create();
+ ssl_sha1_clear(sha);
+ ssl_sha1_transform(sha, session_key, keylen);
+ ssl_sha1_transform(sha, pad_54, 40);
+ ssl_sha1_transform(sha, lenhdr, 4);
+ ssl_sha1_transform(sha, data, datalen);
+ ssl_sha1_complete(sha, shasig);
+ ssl_sha1_info_delete(sha);
+
+ md5 = ssl_md5_info_create();
+ ssl_md5_clear(md5);
+ ssl_md5_transform(md5, session_key, keylen);
+ ssl_md5_transform(md5, pad_92, 48);
+ ssl_md5_transform(md5, shasig, 20);
+ ssl_md5_complete(md5, md5sig);
+ ssl_md5_info_delete(md5);
+
memcpy(signature, md5sig, siglen);
}
@@ -229,25 +279,32 @@ 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);
-
+ void * sha;
+ void * md5;
+ void * update;
+
+ sha = ssl_sha1_info_create();
+ ssl_sha1_clear(sha);
+ ssl_sha1_transform(sha, update_key, rc4_key_len);
+ ssl_sha1_transform(sha, pad_54, 40);
+ ssl_sha1_transform(sha, key, rc4_key_len);
+ ssl_sha1_complete(sha, shasig);
+ ssl_sha1_info_delete(sha);
+
+ md5 = ssl_md5_info_create();
+ ssl_md5_clear(md5);
+ ssl_md5_transform(md5, update_key, rc4_key_len);
+ ssl_md5_transform(md5, pad_92, 48);
+ ssl_md5_transform(md5, shasig, 20);
+ ssl_md5_complete(md5, key);
+ ssl_md5_info_delete(md5);
+
+
+ update = ssl_rc4_info_create();
+ ssl_rc4_set_key(update, key, rc4_key_len);
+ ssl_rc4_crypt(update, key, key, rc4_key_len);
+ ssl_rc4_info_delete(update);
+
if (rc4_key_len == 8)
sec_make_40bit(key);
}
@@ -258,12 +315,11 @@ sec_encrypt(uint8 * data, int length)
{
if (sec_encrypt_use_count == 4096)
{
- sec_update(sec_encrypt_key, sec_encrypt_update_key);
- RC4_set_key(&rc4_encrypt_key, rc4_key_len, sec_encrypt_key);
+ sec_update(sec_encrypt_key, sec_encrypt_update_key);
+ ssl_rc4_set_key(rc4_encrypt_key, sec_encrypt_key, rc4_key_len);
sec_encrypt_use_count = 0;
}
-
- RC4(&rc4_encrypt_key, length, data, data);
+ ssl_rc4_crypt(rc4_encrypt_key, data, data, length);
sec_encrypt_use_count++;
}
@@ -274,15 +330,14 @@ sec_decrypt(uint8 * data, int length)
if (sec_decrypt_use_count == 4096)
{
sec_update(sec_decrypt_key, sec_decrypt_update_key);
- RC4_set_key(&rc4_decrypt_key, rc4_key_len, sec_decrypt_key);
+ ssl_rc4_set_key(rc4_decrypt_key, sec_decrypt_key, rc4_key_len);
sec_decrypt_use_count = 0;
}
-
- RC4(&rc4_decrypt_key, length, data, data);
+ ssl_rc4_crypt(rc4_decrypt_key, data, data, length);
sec_decrypt_use_count++;
}
-static void
+/*static void
reverse(uint8 * p, int len)
{
int i, j;
@@ -294,18 +349,20 @@ reverse(uint8 * p, int len)
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, uint32 modulus_size, uint8 * modulus, uint8 * exponent)
-{
+sec_rsa_encrypt(uint8 * out, uint8 * in, int len, uint8 * modulus, uint8 * exponent)
+{
+ ssl_mod_exp(out, 64, in, 32, modulus, 64, exponent, 4);
+/*
BN_CTX *ctx;
BIGNUM mod, exp, x, y;
- uint8 inr[SEC_MAX_MODULUS_SIZE];
+ uint8 inr[SEC_MODULUS_SIZE];
int outlen;
- reverse(modulus, modulus_size);
+ reverse(modulus, SEC_MODULUS_SIZE);
reverse(exponent, SEC_EXPONENT_SIZE);
memcpy(inr, in, len);
reverse(inr, len);
@@ -316,20 +373,20 @@ sec_rsa_encrypt(uint8 * out, uint8 * in, int len, uint32 modulus_size, uint8 * m
BN_init(&x);
BN_init(&y);
- BN_bin2bn(modulus, modulus_size, &mod);
+ 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 < modulus_size)
- memset(out + outlen, 0, modulus_size - 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);
+ BN_CTX_free(ctx);*/
}
/* Initialise secure transport packet */
@@ -364,7 +421,7 @@ sec_send_to_channel(STREAM s, uint32 flags, uint16 channel)
flags &= ~SEC_ENCRYPT;
datalen = s->end - s->p - 8;
-#if WITH_DEBUG
+#ifdef WITH_DEBUG
DEBUG(("Sending encrypted packet:\n"));
hexdump(s->p + 8, datalen);
#endif
@@ -389,14 +446,14 @@ sec_send(STREAM s, uint32 flags)
static void
sec_establish_key(void)
{
- uint32 length = server_public_key_len + SEC_PADDING_SIZE;
+ uint32 length = SEC_MODULUS_SIZE + SEC_PADDING_SIZE;
uint32 flags = SEC_CLIENT_RANDOM;
STREAM s;
- s = sec_init(flags, length+4);
+ s = sec_init(flags, 76);
out_uint32_le(s, length);
- out_uint8p(s, sec_crypted_random, server_public_key_len);
+ out_uint8p(s, sec_crypted_random, SEC_MODULUS_SIZE);
out_uint8s(s, SEC_PADDING_SIZE);
s_mark_end(s);
@@ -508,66 +565,28 @@ sec_parse_public_key(STREAM s, uint8 ** modulus, uint8 ** exponent)
}
in_uint32_le(s, modulus_len);
- modulus_len -= SEC_PADDING_SIZE;
- if ((modulus_len < 64) || (modulus_len > SEC_MAX_MODULUS_SIZE))
+ if (modulus_len != SEC_MODULUS_SIZE + SEC_PADDING_SIZE)
{
- error("Bad server public key size (%u bits)\n", modulus_len*8);
+ 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, modulus_len);
+ in_uint8p(s, *modulus, SEC_MODULUS_SIZE);
in_uint8s(s, SEC_PADDING_SIZE);
- server_public_key_len = modulus_len;
return s_check(s);
}
-
-static BOOL
-sec_parse_x509_key(X509 * cert)
-{
- EVP_PKEY *epk = NULL;
- /* By some reason, Microsoft sets the OID of the Public RSA key to
- the oid for "MD5 with RSA Encryption" instead of "RSA Encryption"
-
- Kudos to Richard Levitte for the following (. intiutive .)
- lines of code that resets the OID and let's us extract the key. */
- if (OBJ_obj2nid(cert->cert_info->key->algor->algorithm) == NID_md5WithRSAEncryption)
- {
- DEBUG_RDP5(("Re-setting algorithm type to RSA in server certificate\n"));
- ASN1_OBJECT_free(cert->cert_info->key->algor->algorithm);
- cert->cert_info->key->algor->algorithm = OBJ_nid2obj(NID_rsaEncryption);
- }
- epk = X509_get_pubkey(cert);
- if (NULL == epk)
- {
- error("Failed to extract public key from certificate\n");
- return False;
- }
-
- server_public_key = RSAPublicKey_dup((RSA *) epk->pkey.ptr);
- EVP_PKEY_free(epk);
-
- server_public_key_len = RSA_size(server_public_key);
- if ((server_public_key_len < 64) || (server_public_key_len > SEC_MAX_MODULUS_SIZE))
- {
- error("Bad server public key size (%u bits)\n", server_public_key_len*8);
- return False;
- }
-
- return True;
-}
-
-
+
/* 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;
- uint32 cacert_len, cert_len, flags;
- X509 *cacert, *server_cert;
+ uint32 /*cacert_len, cert_len,*/ flags;
+ //X509 *cacert, *server_cert;
uint16 tag, length;
uint8 *next_tag, *end;
@@ -628,7 +647,8 @@ sec_parse_crypt_info(STREAM s, uint32 * rc4_key_size,
}
}
else
- {
+ {
+#if 0
uint32 certcount;
DEBUG_RDP5(("We're going for the RDP5-style encryption\n"));
@@ -717,6 +737,7 @@ sec_parse_crypt_info(STREAM s, uint32 * rc4_key_size,
}
X509_free(server_cert);
return True; /* There's some garbage here we don't care about */
+#endif
}
return s_check_end(s);
}
@@ -728,6 +749,7 @@ sec_process_crypt_info(STREAM s)
uint8 *server_random, *modulus, *exponent;
uint8 client_random[SEC_RANDOM_SIZE];
uint32 rc4_key_size;
+ uint8 inr[SEC_MODULUS_SIZE];
if (!sec_parse_crypt_info(s, &rc4_key_size, &server_random, &modulus, &exponent))
{
@@ -736,38 +758,38 @@ sec_process_crypt_info(STREAM s)
}
DEBUG(("Generating client random\n"));
- generate_random(client_random);
+ /* Generate a client random, and hence determine encryption keys */
+ /* This is what the MS client do: */
+ memset(inr, 0, SEC_RANDOM_SIZE);
+ /* *ARIGL!* Plaintext attack, anyone?
+ I tried doing:
+ generate_random(inr);
+ ..but that generates connection errors now and then (yes,
+ "now and then". Something like 0 to 3 attempts needed before a
+ successful connection. Nice. Not!
+ */
+ generate_random(client_random);
if (NULL != server_public_key)
{ /* Which means we should use
RDP5-style encryption */
- uint8 inr[SEC_MAX_MODULUS_SIZE];
- uint32 padding_len = server_public_key_len - SEC_RANDOM_SIZE;
-
- /* This is what the MS client do: */
- memset(inr, 0, padding_len);
- /* *ARIGL!* Plaintext attack, anyone?
- I tried doing:
- generate_random(inr);
- ..but that generates connection errors now and then (yes,
- "now and then". Something like 0 to 3 attempts needed before a
- successful connection. Nice. Not!
- */
- memcpy(inr + padding_len, client_random, SEC_RANDOM_SIZE);
- reverse(inr + padding_len, SEC_RANDOM_SIZE);
+#if 0
+ memcpy(inr + SEC_RANDOM_SIZE, client_random, SEC_RANDOM_SIZE);
+ reverse(inr + SEC_RANDOM_SIZE, SEC_RANDOM_SIZE);
- RSA_public_encrypt(server_public_key_len,
+ RSA_public_encrypt(SEC_MODULUS_SIZE,
inr, sec_crypted_random, server_public_key, RSA_NO_PADDING);
- reverse(sec_crypted_random, server_public_key_len);
+ reverse(sec_crypted_random, SEC_MODULUS_SIZE);
RSA_free(server_public_key);
- server_public_key = NULL;
+ server_public_key = NULL;
+#endif
}
else
{ /* RDP4-style encryption */
sec_rsa_encrypt(sec_crypted_random,
- client_random, SEC_RANDOM_SIZE, server_public_key_len, modulus, exponent);
+ client_random, SEC_RANDOM_SIZE, modulus, exponent);
}
sec_generate_keys(client_random, server_random, rc4_key_size);
}
diff --git a/uirdesktop/ssl_calls.c b/uirdesktop/ssl_calls.c
new file mode 100755
index 00000000..da05b135
--- /dev/null
+++ b/uirdesktop/ssl_calls.c
@@ -0,0 +1,1644 @@
+/*
+ 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.
+
+ xrdp: A Remote Desktop Protocol server.
+ Copyright (C) Jay Sorg 2004-2005
+
+ ssl calls
+
+*/
+
+#include "rdesktop.h"
+
+#define APP_CC
+
+/*****************************************************************************/
+static void * g_malloc(int size, int zero)
+{
+ void * p;
+
+ p = xmalloc(size);
+ if (zero)
+ {
+ memset(p, 0, size);
+ }
+ return p;
+}
+
+/*****************************************************************************/
+static void g_free(void * in)
+{
+ xfree(in);
+}
+
+/*****************************************************************************/
+/*****************************************************************************/
+/* rc4 stuff */
+/* An implementation of the ARC4 algorithm
+ *
+ * Copyright (C) 2001-2003 Christophe Devine
+ */
+struct rc4_state
+{
+ int x;
+ int y;
+ int m[256];
+};
+
+/*****************************************************************************/
+void* APP_CC
+ssl_rc4_info_create(void)
+{
+ return g_malloc(sizeof(struct rc4_state), 1);;
+}
+
+/*****************************************************************************/
+void APP_CC
+ssl_rc4_info_delete(void* rc4_info)
+{
+ g_free(rc4_info);
+}
+
+/*****************************************************************************/
+void APP_CC
+ssl_rc4_set_key(void* rc4_info, char* key, int len)
+{
+ int i;
+ int j;
+ int k;
+ int a;
+ int* m;
+ struct rc4_state* s;
+
+ s = (struct rc4_state*)rc4_info;
+ s->x = 0;
+ s->y = 0;
+ m = s->m;
+ for (i = 0; i < 256; i++)
+ {
+ m[i] = i;
+ }
+ j = 0;
+ k = 0;
+ for (i = 0; i < 256; i++)
+ {
+ a = m[i];
+ j = (unsigned char)(j + a + key[k]);
+ m[i] = m[j];
+ m[j] = a;
+ k++;
+ if (k >= len)
+ {
+ k = 0;
+ }
+ }
+}
+
+/*****************************************************************************/
+void APP_CC
+ssl_rc4_crypt(void* rc4_info, char* in_data, char* out_data, int len)
+{
+ int i;
+ int x;
+ int y;
+ int a;
+ int b;
+ int* m;
+ struct rc4_state* s;
+
+ s = (struct rc4_state*)rc4_info;
+ x = s->x;
+ y = s->y;
+ m = s->m;
+ for (i = 0; i < len; i++)
+ {
+ x = (unsigned char)(x + 1);
+ a = m[x];
+ y = (unsigned char)(y + a);
+ b = m[y];
+ m[x] = b;
+ m[y] = a;
+ out_data[i] = in_data[i] ^ (m[(unsigned char)(a + b)]);
+ }
+ s->x = x;
+ s->y = y;
+}
+
+/*****************************************************************************/
+/*****************************************************************************/
+/* sha1 stuff */
+/* FIPS-180-1 compliant SHA-1 implementation
+ *
+ * Copyright (C) 2001-2003 Christophe Devine
+ */
+struct sha1_context
+{
+ int total[2];
+ int state[5];
+ char buffer[64];
+};
+
+/*****************************************************************************/
+void* APP_CC
+ssl_sha1_info_create(void)
+{
+ return g_malloc(sizeof(struct sha1_context), 1);
+}
+
+/*****************************************************************************/
+void APP_CC
+ssl_sha1_info_delete(void* sha1_info)
+{
+ g_free(sha1_info);
+}
+
+/*****************************************************************************/
+void APP_CC
+ssl_sha1_clear(void* sha1_info)
+{
+ struct sha1_context* ctx;
+
+ ctx = (struct sha1_context*)sha1_info;
+ memset(ctx, 0, sizeof(struct sha1_context));
+ ctx->state[0] = 0x67452301;
+ ctx->state[1] = 0xEFCDAB89;
+ ctx->state[2] = 0x98BADCFE;
+ ctx->state[3] = 0x10325476;
+ ctx->state[4] = 0xC3D2E1F0;
+}
+
+#undef GET_UINT32
+#define GET_UINT32(n, b, i) \
+{ \
+ (n) = ((b)[(i) + 0] << 24) | \
+ ((b)[(i) + 1] << 16) | \
+ ((b)[(i) + 2] << 8) | \
+ ((b)[(i) + 3] << 0); \
+}
+
+#undef PUT_UINT32
+#define PUT_UINT32(n, b, i) \
+{ \
+ (b)[(i) + 0] = ((n) >> 24); \
+ (b)[(i) + 1] = ((n) >> 16); \
+ (b)[(i) + 2] = ((n) >> 8); \
+ (b)[(i) + 3] = ((n) >> 0); \
+}
+
+/*****************************************************************************/
+static void APP_CC
+sha1_process(struct sha1_context* ctx, char* in_data)
+{
+ int temp;
+ int W[16];
+ int A;
+ int B;
+ int C;
+ int D;
+ int E;
+ unsigned char* data;
+
+ data = (unsigned char*)in_data;
+
+ GET_UINT32(W[0], data, 0);
+ GET_UINT32(W[1], data, 4);
+ GET_UINT32(W[2], data, 8);
+ GET_UINT32(W[3], data, 12);
+ GET_UINT32(W[4], data, 16);
+ GET_UINT32(W[5], data, 20);
+ GET_UINT32(W[6], data, 24);
+ GET_UINT32(W[7], data, 28);
+ GET_UINT32(W[8], data, 32);
+ GET_UINT32(W[9], data, 36);
+ GET_UINT32(W[10], data, 40);
+ GET_UINT32(W[11], data, 44);
+ GET_UINT32(W[12], data, 48);
+ GET_UINT32(W[13], data, 52);
+ GET_UINT32(W[14], data, 56);
+ GET_UINT32(W[15], data, 60);
+
+#define S(x, n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
+
+#define R(t) \
+( \
+ temp = W[(t - 3) & 0x0F] ^ \
+ W[(t - 8) & 0x0F] ^ \
+ W[(t - 14) & 0x0F] ^ \
+ W[(t - 0) & 0x0F], \
+ (W[t & 0x0F] = S(temp, 1)) \
+)
+
+#undef P
+#define P(a, b, c, d, e, x) \
+{ \
+ e += S(a, 5) + F(b, c, d) + K + x; \
+ b = S(b, 30); \
+}
+
+ A = ctx->state[0];
+ B = ctx->state[1];
+ C = ctx->state[2];
+ D = ctx->state[3];
+ E = ctx->state[4];
+
+#define F(x, y, z) (z ^ (x & (y ^ z)))
+#define K 0x5A827999
+
+ P(A, B, C, D, E, W[0]);
+ P(E, A, B, C, D, W[1]);
+ P(D, E, A, B, C, W[2]);
+ P(C, D, E, A, B, W[3]);
+ P(B, C, D, E, A, W[4]);
+ P(A, B, C, D, E, W[5]);
+ P(E, A, B, C, D, W[6]);
+ P(D, E, A, B, C, W[7]);
+ P(C, D, E, A, B, W[8]);
+ P(B, C, D, E, A, W[9]);
+ P(A, B, C, D, E, W[10]);
+ P(E, A, B, C, D, W[11]);
+ P(D, E, A, B, C, W[12]);
+ P(C, D, E, A, B, W[13]);
+ P(B, C, D, E, A, W[14]);
+ P(A, B, C, D, E, W[15]);
+ P(E, A, B, C, D, R(16));
+ P(D, E, A, B, C, R(17));
+ P(C, D, E, A, B, R(18));
+ P(B, C, D, E, A, R(19));
+
+#undef K
+#undef F
+
+#define F(x, y, z) (x ^ y ^ z)
+#define K 0x6ED9EBA1
+
+ P(A, B, C, D, E, R(20));
+ P(E, A, B, C, D, R(21));
+ P(D, E, A, B, C, R(22));
+ P(C, D, E, A, B, R(23));
+ P(B, C, D, E, A, R(24));
+ P(A, B, C, D, E, R(25));
+ P(E, A, B, C, D, R(26));
+ P(D, E, A, B, C, R(27));
+ P(C, D, E, A, B, R(28));
+ P(B, C, D, E, A, R(29));
+ P(A, B, C, D, E, R(30));
+ P(E, A, B, C, D, R(31));
+ P(D, E, A, B, C, R(32));
+ P(C, D, E, A, B, R(33));
+ P(B, C, D, E, A, R(34));
+ P(A, B, C, D, E, R(35));
+ P(E, A, B, C, D, R(36));
+ P(D, E, A, B, C, R(37));
+ P(C, D, E, A, B, R(38));
+ P(B, C, D, E, A, R(39));
+
+#undef K
+#undef F
+
+#define F(x, y, z) ((x & y) | (z & (x | y)))
+#define K 0x8F1BBCDC
+
+ P(A, B, C, D, E, R(40));
+ P(E, A, B, C, D, R(41));
+ P(D, E, A, B, C, R(42));
+ P(C, D, E, A, B, R(43));
+ P(B, C, D, E, A, R(44));
+ P(A, B, C, D, E, R(45));
+ P(E, A, B, C, D, R(46));
+ P(D, E, A, B, C, R(47));
+ P(C, D, E, A, B, R(48));
+ P(B, C, D, E, A, R(49));
+ P(A, B, C, D, E, R(50));
+ P(E, A, B, C, D, R(51));
+ P(D, E, A, B, C, R(52));
+ P(C, D, E, A, B, R(53));
+ P(B, C, D, E, A, R(54));
+ P(A, B, C, D, E, R(55));
+ P(E, A, B, C, D, R(56));
+ P(D, E, A, B, C, R(57));
+ P(C, D, E, A, B, R(58));
+ P(B, C, D, E, A, R(59));
+
+#undef K
+#undef F
+
+#define F(x, y, z) (x ^ y ^ z)
+#define K 0xCA62C1D6
+
+ P(A, B, C, D, E, R(60));
+ P(E, A, B, C, D, R(61));
+ P(D, E, A, B, C, R(62));
+ P(C, D, E, A, B, R(63));
+ P(B, C, D, E, A, R(64));
+ P(A, B, C, D, E, R(65));
+ P(E, A, B, C, D, R(66));
+ P(D, E, A, B, C, R(67));
+ P(C, D, E, A, B, R(68));
+ P(B, C, D, E, A, R(69));
+ P(A, B, C, D, E, R(70));
+ P(E, A, B, C, D, R(71));
+ P(D, E, A, B, C, R(72));
+ P(C, D, E, A, B, R(73));
+ P(B, C, D, E, A, R(74));
+ P(A, B, C, D, E, R(75));
+ P(E, A, B, C, D, R(76));
+ P(D, E, A, B, C, R(77));
+ P(C, D, E, A, B, R(78));
+ P(B, C, D, E, A, R(79));
+
+#undef K
+#undef F
+
+ ctx->state[0] += A;
+ ctx->state[1] += B;
+ ctx->state[2] += C;
+ ctx->state[3] += D;
+ ctx->state[4] += E;
+}
+
+/*****************************************************************************/
+void APP_CC
+ssl_sha1_transform(void* sha1_info, char* data, int len)
+{
+ int left;
+ int fill;
+ struct sha1_context* ctx;
+
+ ctx = (struct sha1_context*)sha1_info;
+ if (len == 0)
+ {
+ return;
+ }
+ left = ctx->total[0] & 0x3F;
+ fill = 64 - left;
+ ctx->total[0] += len;
+ ctx->total[0] &= 0xFFFFFFFF;
+ if (ctx->total[0] < len)
+ {
+ ctx->total[1]++;
+ }
+ if (left && (len >= fill))
+ {
+ memcpy(ctx->buffer + left, data, fill);
+ sha1_process(ctx, ctx->buffer);
+ len -= fill;
+ data += fill;
+ left = 0;
+ }
+ while (len >= 64)
+ {
+ sha1_process(ctx, data);
+ len -= 64;
+ data += 64;
+ }
+ if (len != 0)
+ {
+ memcpy(ctx->buffer + left, data, len);
+ }
+}
+
+static unsigned char sha1_padding[64] =
+{
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/*****************************************************************************/
+void APP_CC
+ssl_sha1_complete(void* sha1_info, char* data)
+{
+ int last;
+ int padn;
+ int high;
+ int low;
+ char msglen[8];
+ struct sha1_context* ctx;
+
+ ctx = (struct sha1_context*)sha1_info;
+ high = (ctx->total[0] >> 29) | (ctx->total[1] << 3);
+ low = (ctx->total[0] << 3);
+ PUT_UINT32(high, msglen, 0);
+ PUT_UINT32(low, msglen, 4);
+ last = ctx->total[0] & 0x3F;
+ padn = (last < 56) ? (56 - last) : (120 - last);
+ ssl_sha1_transform(ctx, sha1_padding, padn);
+ ssl_sha1_transform(ctx, msglen, 8);
+ PUT_UINT32(ctx->state[0], data, 0);
+ PUT_UINT32(ctx->state[1], data, 4);
+ PUT_UINT32(ctx->state[2], data, 8);
+ PUT_UINT32(ctx->state[3], data, 12);
+ PUT_UINT32(ctx->state[4], data, 16);
+}
+
+/*****************************************************************************/
+/*****************************************************************************/
+/* md5 stuff */
+/* RFC 1321 compliant MD5 implementation
+ *
+ * Copyright (C) 2001-2003 Christophe Devine
+ */
+
+struct md5_context
+{
+ int total[2];
+ int state[4];
+ char buffer[64];
+};
+
+/*****************************************************************************/
+void* APP_CC
+ssl_md5_info_create(void)
+{
+ return g_malloc(sizeof(struct md5_context), 1);
+}
+
+/*****************************************************************************/
+void APP_CC
+ssl_md5_info_delete(void* md5_info)
+{
+ g_free(md5_info);
+}
+
+/*****************************************************************************/
+void APP_CC
+ssl_md5_clear(void* md5_info)
+{
+ struct md5_context* ctx;
+
+ ctx = (struct md5_context*)md5_info;
+ memset(ctx, 0, sizeof(struct md5_context));
+ ctx->state[0] = 0x67452301;
+ ctx->state[1] = 0xEFCDAB89;
+ ctx->state[2] = 0x98BADCFE;
+ ctx->state[3] = 0x10325476;
+}
+
+#undef GET_UINT32
+#define GET_UINT32(n, b, i) \
+{ \
+ (n) = ((b)[(i) + 0] << 0) | \
+ ((b)[(i) + 1] << 8) | \
+ ((b)[(i) + 2] << 16) | \
+ ((b)[(i) + 3] << 24); \
+}
+
+#undef PUT_UINT32
+#define PUT_UINT32(n, b, i) \
+{ \
+ (b)[(i) + 0] = ((n) >> 0); \
+ (b)[(i) + 1] = ((n) >> 8); \
+ (b)[(i) + 2] = ((n) >> 16); \
+ (b)[(i) + 3] = ((n) >> 24); \
+}
+
+/*****************************************************************************/
+static void
+md5_process(struct md5_context* ctx, char* in_data)
+{
+ int X[16];
+ int A;
+ int B;
+ int C;
+ int D;
+ unsigned char* data;
+
+ data = (unsigned char*)in_data;
+ GET_UINT32(X[0], data, 0);
+ GET_UINT32(X[1], data, 4);
+ GET_UINT32(X[2], data, 8);
+ GET_UINT32(X[3], data, 12);
+ GET_UINT32(X[4], data, 16);
+ GET_UINT32(X[5], data, 20);
+ GET_UINT32(X[6], data, 24);
+ GET_UINT32(X[7], data, 28);
+ GET_UINT32(X[8], data, 32);
+ GET_UINT32(X[9], data, 36);
+ GET_UINT32(X[10], data, 40);
+ GET_UINT32(X[11], data, 44);
+ GET_UINT32(X[12], data, 48);
+ GET_UINT32(X[13], data, 52);
+ GET_UINT32(X[14], data, 56);
+ GET_UINT32(X[15], data, 60);
+
+#define S(x, n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
+
+#undef P
+#define P(a, b, c, d, k, s, t) \
+{ \
+ a += F(b, c, d) + X[k] + t; \
+ a = S(a, s) + b; \
+}
+
+ A = ctx->state[0];
+ B = ctx->state[1];
+ C = ctx->state[2];
+ D = ctx->state[3];
+
+#define F(x, y, z) (z ^ (x & (y ^ z)))
+
+ P(A, B, C, D, 0, 7, 0xD76AA478);
+ P(D, A, B, C, 1, 12, 0xE8C7B756);
+ P(C, D, A, B, 2, 17, 0x242070DB);
+ P(B, C, D, A, 3, 22, 0xC1BDCEEE);
+ P(A, B, C, D, 4, 7, 0xF57C0FAF);
+ P(D, A, B, C, 5, 12, 0x4787C62A);
+ P(C, D, A, B, 6, 17, 0xA8304613);
+ P(B, C, D, A, 7, 22, 0xFD469501);
+ P(A, B, C, D, 8, 7, 0x698098D8);
+ P(D, A, B, C, 9, 12, 0x8B44F7AF);
+ P(C, D, A, B, 10, 17, 0xFFFF5BB1);
+ P(B, C, D, A, 11, 22, 0x895CD7BE);
+ P(A, B, C, D, 12, 7, 0x6B901122);
+ P(D, A, B, C, 13, 12, 0xFD987193);
+ P(C, D, A, B, 14, 17, 0xA679438E);
+ P(B, C, D, A, 15, 22, 0x49B40821);
+
+#undef F
+
+#define F(x, y, z) (y ^ (z & (x ^ y)))
+
+ P(A, B, C, D, 1, 5, 0xF61E2562);
+ P(D, A, B, C, 6, 9, 0xC040B340);
+ P(C, D, A, B, 11, 14, 0x265E5A51);
+ P(B, C, D, A, 0, 20, 0xE9B6C7AA);
+ P(A, B, C, D, 5, 5, 0xD62F105D);
+ P(D, A, B, C, 10, 9, 0x02441453);
+ P(C, D, A, B, 15, 14, 0xD8A1E681);
+ P(B, C, D, A, 4, 20, 0xE7D3FBC8);
+ P(A, B, C, D, 9, 5, 0x21E1CDE6);
+ P(D, A, B, C, 14, 9, 0xC33707D6);
+ P(C, D, A, B, 3, 14, 0xF4D50D87);
+ P(B, C, D, A, 8, 20, 0x455A14ED);
+ P(A, B, C, D, 13, 5, 0xA9E3E905);
+ P(D, A, B, C, 2, 9, 0xFCEFA3F8);
+ P(C, D, A, B, 7, 14, 0x676F02D9);
+ P(B, C, D, A, 12, 20, 0x8D2A4C8A);
+
+#undef F
+
+#define F(x, y, z) (x ^ y ^ z)
+
+ P(A, B, C, D, 5, 4, 0xFFFA3942);
+ P(D, A, B, C, 8, 11, 0x8771F681);
+ P(C, D, A, B, 11, 16, 0x6D9D6122);
+ P(B, C, D, A, 14, 23, 0xFDE5380C);
+ P(A, B, C, D, 1, 4, 0xA4BEEA44);
+ P(D, A, B, C, 4, 11, 0x4BDECFA9);
+ P(C, D, A, B, 7, 16, 0xF6BB4B60);
+ P(B, C, D, A, 10, 23, 0xBEBFBC70);
+ P(A, B, C, D, 13, 4, 0x289B7EC6);
+ P(D, A, B, C, 0, 11, 0xEAA127FA);
+ P(C, D, A, B, 3, 16, 0xD4EF3085);
+ P(B, C, D, A, 6, 23, 0x04881D05);
+ P(A, B, C, D, 9, 4, 0xD9D4D039);
+ P(D, A, B, C, 12, 11, 0xE6DB99E5);
+ P(C, D, A, B, 15, 16, 0x1FA27CF8);
+ P(B, C, D, A, 2, 23, 0xC4AC5665);
+
+#undef F
+
+#define F(x, y, z) (y ^ (x | ~z))
+
+ P(A, B, C, D, 0, 6, 0xF4292244);
+ P(D, A, B, C, 7, 10, 0x432AFF97);
+ P(C, D, A, B, 14, 15, 0xAB9423A7);
+ P(B, C, D, A, 5, 21, 0xFC93A039);
+ P(A, B, C, D, 12, 6, 0x655B59C3);
+ P(D, A, B, C, 3, 10, 0x8F0CCC92);
+ P(C, D, A, B, 10, 15, 0xFFEFF47D);
+ P(B, C, D, A, 1, 21, 0x85845DD1);
+ P(A, B, C, D, 8, 6, 0x6FA87E4F);
+ P(D, A, B, C, 15, 10, 0xFE2CE6E0);
+ P(C, D, A, B, 6, 15, 0xA3014314);
+ P(B, C, D, A, 13, 21, 0x4E0811A1);
+ P(A, B, C, D, 4, 6, 0xF7537E82);
+ P(D, A, B, C, 11, 10, 0xBD3AF235);
+ P(C, D, A, B, 2, 15, 0x2AD7D2BB);
+ P(B, C, D, A, 9, 21, 0xEB86D391);
+
+#undef F
+
+ ctx->state[0] += A;
+ ctx->state[1] += B;
+ ctx->state[2] += C;
+ ctx->state[3] += D;
+}
+
+/*****************************************************************************/
+void APP_CC
+ssl_md5_transform(void* md5_info, char* data, int len)
+{
+ int left;
+ int fill;
+ struct md5_context* ctx;
+
+ ctx = (struct md5_context*)md5_info;
+ if (len == 0)
+ {
+ return;
+ }
+ left = ctx->total[0] & 0x3F;
+ fill = 64 - left;
+ ctx->total[0] += len;
+ ctx->total[0] &= 0xFFFFFFFF;
+ if (ctx->total[0] < len)
+ {
+ ctx->total[1]++;
+ }
+ if (left && (len >= fill))
+ {
+ memcpy(ctx->buffer + left, data, fill);
+ md5_process(ctx, ctx->buffer);
+ len -= fill;
+ data += fill;
+ left = 0;
+ }
+ while (len >= 64)
+ {
+ md5_process(ctx, data);
+ len -= 64;
+ data += 64;
+ }
+ if (len != 0)
+ {
+ memcpy(ctx->buffer + left, data, len);
+ }
+}
+
+static unsigned char md5_padding[64] =
+{
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/*****************************************************************************/
+void APP_CC
+ssl_md5_complete(void* md5_info, char* data)
+{
+ int last;
+ int padn;
+ int high;
+ int low;
+ char msglen[8];
+ struct md5_context* ctx;
+
+ ctx = (struct md5_context*)md5_info;
+ high = (ctx->total[0] >> 29) | (ctx->total[1] << 3);
+ low = (ctx->total[0] << 3);
+ PUT_UINT32(low, msglen, 0);
+ PUT_UINT32(high, msglen, 4);
+ last = ctx->total[0] & 0x3F;
+ padn = (last < 56) ? (56 - last) : (120 - last);
+ ssl_md5_transform(ctx, md5_padding, padn);
+ ssl_md5_transform(ctx, msglen, 8);
+ PUT_UINT32(ctx->state[0], data, 0);
+ PUT_UINT32(ctx->state[1], data, 4);
+ PUT_UINT32(ctx->state[2], data, 8);
+ PUT_UINT32(ctx->state[3], data, 12);
+}
+
+/*****************************************************************************/
+/*****************************************************************************/
+/* big number stuff */
+/******************* SHORT COPYRIGHT NOTICE*************************
+This source code is part of the BigDigits multiple-precision
+arithmetic library Version 1.0 originally written by David Ireland,
+copyright (c) 2001 D.I. Management Services Pty Limited, all rights
+reserved. It is provided "as is" with no warranties. You may use
+this software under the terms of the full copyright notice
+"bigdigitsCopyright.txt" that should have been included with
+this library. To obtain a copy send an email to
+<code@di-mgt.com.au> or visit <www.di-mgt.com.au/crypto.html>.
+This notice must be retained in any copy.
+****************** END OF COPYRIGHT NOTICE*************************/
+/************************* COPYRIGHT NOTICE*************************
+This source code is part of the BigDigits multiple-precision
+arithmetic library Version 1.0 originally written by David Ireland,
+copyright (c) 2001 D.I. Management Services Pty Limited, all rights
+reserved. You are permitted to use compiled versions of this code as
+part of your own executable files and to distribute unlimited copies
+of such executable files for any purposes including commercial ones
+provided you keep the copyright notices intact in the source code
+and that you ensure that the following characters remain in any
+object or executable files you distribute:
+
+"Contains multiple-precision arithmetic code originally written
+by David Ireland, copyright (c) 2001 by D.I. Management Services
+Pty Limited <www.di-mgt.com.au>, and is used with permission."
+
+David Ireland and DI Management Services Pty Limited make no
+representations concerning either the merchantability of this
+software or the suitability of this software for any particular
+purpose. It is provided "as is" without express or implied warranty
+of any kind.
+
+Please forward any comments and bug reports to <code@di-mgt.com.au>.
+The latest version of the source code can be downloaded from
+www.di-mgt.com.au/crypto.html.
+****************** END OF COPYRIGHT NOTICE*************************/
+
+typedef unsigned int DIGIT_T;
+#define HIBITMASK 0x80000000
+#define MAX_DIG_LEN 51
+#define MAX_DIGIT 0xffffffff
+#define BITS_PER_DIGIT 32
+#define MAX_HALF_DIGIT 0xffff
+#define B_J (MAX_HALF_DIGIT + 1)
+#define LOHALF(x) ((DIGIT_T)((x) & 0xffff))
+#define HIHALF(x) ((DIGIT_T)((x) >> 16 & 0xffff))
+#define TOHIGH(x) ((DIGIT_T)((x) << 16))
+
+#define mpNEXTBITMASK(mask, n) \
+{ \
+ if (mask == 1) \
+ { \
+ mask = HIBITMASK; \
+ n--; \
+ } \
+ else \
+ { \
+ mask >>= 1; \
+ } \
+}
+
+/*****************************************************************************/
+static DIGIT_T APP_CC
+mpAdd(DIGIT_T* w, DIGIT_T* u, DIGIT_T* v, unsigned int ndigits)
+{
+ /* Calculates w = u + v
+ where w, u, v are multiprecision integers of ndigits each
+ Returns carry if overflow. Carry = 0 or 1.
+
+ Ref: Knuth Vol 2 Ch 4.3.1 p 266 Algorithm A. */
+ DIGIT_T k;
+ unsigned int j;
+
+ /* Step A1. Initialise */
+ k = 0;
+ for (j = 0; j < ndigits; j++)
+ {
+ /* Step A2. Add digits w_j = (u_j + v_j + k)
+ Set k = 1 if carry (overflow) occurs */
+ w[j] = u[j] + k;
+ if (w[j] < k)
+ {
+ k = 1;
+ }
+ else
+ {
+ k = 0;
+ }
+ w[j] += v[j];
+ if (w[j] < v[j])
+ {
+ k++;
+ }
+ } /* Step A3. Loop on j */
+ return k; /* w_n = k */
+}
+
+/*****************************************************************************/
+static void APP_CC
+mpSetDigit(DIGIT_T* a, DIGIT_T d, unsigned int ndigits)
+{ /* Sets a = d where d is a single digit */
+ unsigned int i;
+
+ for (i = 1; i < ndigits; i++)
+ {
+ a[i] = 0;
+ }
+ a[0] = d;
+}
+
+/*****************************************************************************/
+static int APP_CC
+mpCompare(DIGIT_T* a, DIGIT_T* b, unsigned int ndigits)
+{
+ /* Returns sign of (a - b) */
+ if (ndigits == 0)
+ {
+ return 0;
+ }
+ while (ndigits--)
+ {
+ if (a[ndigits] > b[ndigits])
+ {
+ return 1; /* GT */
+ }
+ if (a[ndigits] < b[ndigits])
+ {
+ return -1; /* LT */
+ }
+ }
+ return 0; /* EQ */
+}
+
+/*****************************************************************************/
+static void APP_CC
+mpSetZero(DIGIT_T* a, unsigned int ndigits)
+{ /* Sets a = 0 */
+ unsigned int i;
+
+ for (i = 0; i < ndigits; i++)
+ {
+ a[i] = 0;
+ }
+}
+
+/*****************************************************************************/
+static void APP_CC
+mpSetEqual(DIGIT_T* a, DIGIT_T* b, unsigned int ndigits)
+{ /* Sets a = b */
+ unsigned int i;
+
+ for (i = 0; i < ndigits; i++)
+ {
+ a[i] = b[i];
+ }
+}
+
+/*****************************************************************************/
+static unsigned int APP_CC
+mpSizeof(DIGIT_T* a, unsigned int ndigits)
+{ /* Returns size of significant digits in a */
+ while (ndigits--)
+ {
+ if (a[ndigits] != 0)
+ {
+ return (++ndigits);
+ }
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+static DIGIT_T APP_CC
+mpShiftLeft(DIGIT_T* a, DIGIT_T* b, unsigned int x, unsigned int ndigits)
+{ /* Computes a = b << x */
+ unsigned int i;
+ unsigned int y;
+ DIGIT_T mask;
+ DIGIT_T carry;
+ DIGIT_T nextcarry;
+
+ /* Check input - NB unspecified result */
+ if (x >= BITS_PER_DIGIT)
+ {
+ return 0;
+ }
+ /* Construct mask */
+ mask = HIBITMASK;
+ for (i = 1; i < x; i++)
+ {
+ mask = (mask >> 1) | mask;
+ }
+ if (x == 0)
+ {
+ mask = 0x0;
+ }
+ y = BITS_PER_DIGIT - x;
+ carry = 0;
+ for (i = 0; i < ndigits; i++)
+ {
+ nextcarry = (b[i] & mask) >> y;
+ a[i] = b[i] << x | carry;
+ carry = nextcarry;
+ }
+ return carry;
+}
+
+/*****************************************************************************/
+static DIGIT_T APP_CC
+mpShiftRight(DIGIT_T* a, DIGIT_T* b, unsigned int x, unsigned int ndigits)
+{ /* Computes a = b >> x */
+ unsigned int i;
+ unsigned int y;
+ DIGIT_T mask;
+ DIGIT_T carry;
+ DIGIT_T nextcarry;
+
+ /* Check input - NB unspecified result */
+ if (x >= BITS_PER_DIGIT)
+ {
+ return 0;
+ }
+ /* Construct mask */
+ mask = 0x1;
+ for (i = 1; i < x; i++)
+ {
+ mask = (mask << 1) | mask;
+ }
+ if (x == 0)
+ {
+ mask = 0x0;
+ }
+ y = BITS_PER_DIGIT - x;
+ carry = 0;
+ i = ndigits;
+ while (i--)
+ {
+ nextcarry = (b[i] & mask) << y;
+ a[i] = b[i] >> x | carry;
+ carry = nextcarry;
+ }
+ return carry;
+}
+
+/*****************************************************************************/
+static void APP_CC
+spMultSub(DIGIT_T* uu, DIGIT_T qhat, DIGIT_T v1, DIGIT_T v0)
+{
+ /* Compute uu = uu - q(v1v0)
+ where uu = u3u2u1u0, u3 = 0
+ and u_n, v_n are all half-digits
+ even though v1, v2 are passed as full digits. */
+ DIGIT_T p0;
+ DIGIT_T p1;
+ DIGIT_T t;
+
+ p0 = qhat * v0;
+ p1 = qhat * v1;
+ t = p0 + TOHIGH(LOHALF(p1));
+ uu[0] -= t;
+ if (uu[0] > MAX_DIGIT - t)
+ {
+ uu[1]--; /* Borrow */
+ }
+ uu[1] -= HIHALF(p1);
+}
+
+/*****************************************************************************/
+static int APP_CC
+spMultiply(DIGIT_T* p, DIGIT_T x, DIGIT_T y)
+{ /* Computes p = x * y */
+ /* Ref: Arbitrary Precision Computation
+ http://numbers.computation.free.fr/Constants/constants.html
+
+ high p1 p0 low
+ +--------+--------+--------+--------+
+ | x1*y1 | x0*y0 |
+ +--------+--------+--------+--------+
+ +-+--------+--------+
+ |1| (x0*y1 + x1*y1) |
+ +-+--------+--------+
+ ^carry from adding (x0*y1+x1*y1) together
+ +-+
+ |1|< carry from adding LOHALF t
+ +-+ to high half of p0 */
+ DIGIT_T x0;
+ DIGIT_T y0;
+ DIGIT_T x1;
+ DIGIT_T y1;
+ DIGIT_T t;
+ DIGIT_T u;
+ DIGIT_T carry;
+
+ /* Split each x,y into two halves
+ x = x0 + B * x1
+ y = y0 + B * y1
+ where B = 2^16, half the digit size
+ Product is
+ xy = x0y0 + B(x0y1 + x1y0) + B^2(x1y1) */
+
+ x0 = LOHALF(x);
+ x1 = HIHALF(x);
+ y0 = LOHALF(y);
+ y1 = HIHALF(y);
+
+ /* Calc low part - no carry */
+ p[0] = x0 * y0;
+
+ /* Calc middle part */
+ t = x0 * y1;
+ u = x1 * y0;
+ t += u;
+ if (t < u)
+ {
+ carry = 1;
+ }
+ else
+ {
+ carry = 0;
+ }
+ /* This carry will go to high half of p[1]
+ + high half of t into low half of p[1] */
+ carry = TOHIGH(carry) + HIHALF(t);
+
+ /* Add low half of t to high half of p[0] */
+ t = TOHIGH(t);
+ p[0] += t;
+ if (p[0] < t)
+ {
+ carry++;
+ }
+
+ p[1] = x1 * y1;
+ p[1] += carry;
+
+ return 0;
+}
+
+/*****************************************************************************/
+static DIGIT_T APP_CC
+spDivide(DIGIT_T* q, DIGIT_T* r, DIGIT_T* u, DIGIT_T v)
+{ /* Computes quotient q = u / v, remainder r = u mod v
+ where u is a double digit
+ and q, v, r are single precision digits.
+ Returns high digit of quotient (max value is 1)
+ Assumes normalised such that v1 >= b/2
+ where b is size of HALF_DIGIT
+ i.e. the most significant bit of v should be one
+
+ In terms of half-digits in Knuth notation:
+ (q2q1q0) = (u4u3u2u1u0) / (v1v0)
+ (r1r0) = (u4u3u2u1u0) mod (v1v0)
+ for m = 2, n = 2 where u4 = 0
+ q2 is either 0 or 1.
+ We set q = (q1q0) and return q2 as "overflow' */
+ DIGIT_T qhat;
+ DIGIT_T rhat;
+ DIGIT_T t;
+ DIGIT_T v0;
+ DIGIT_T v1;
+ DIGIT_T u0;
+ DIGIT_T u1;
+ DIGIT_T u2;
+ DIGIT_T u3;
+ DIGIT_T uu[2];
+ DIGIT_T q2;
+
+ /* Check for normalisation */
+ if (!(v & HIBITMASK))
+ {
+ *q = *r = 0;
+ return MAX_DIGIT;
+ }
+
+ /* Split up into half-digits */
+ v0 = LOHALF(v);
+ v1 = HIHALF(v);
+ u0 = LOHALF(u[0]);
+ u1 = HIHALF(u[0]);
+ u2 = LOHALF(u[1]);
+ u3 = HIHALF(u[1]);
+
+ /* Do three rounds of Knuth Algorithm D Vol 2 p272 */
+
+ /* ROUND 1. Set j = 2 and calculate q2 */
+ /* Estimate qhat = (u4u3)/v1 = 0 or 1
+ then set (u4u3u2) -= qhat(v1v0)
+ where u4 = 0. */
+ qhat = u3 / v1;
+ if (qhat > 0)
+ {
+ rhat = u3 - qhat * v1;
+ t = TOHIGH(rhat) | u2;
+ if (qhat * v0 > t)
+ {
+ qhat--;
+ }
+ }
+ uu[1] = 0; /* (u4) */
+ uu[0] = u[1]; /* (u3u2) */
+ if (qhat > 0)
+ {
+ /* (u4u3u2) -= qhat(v1v0) where u4 = 0 */
+ spMultSub(uu, qhat, v1, v0);
+ if (HIHALF(uu[1]) != 0)
+ { /* Add back */
+ qhat--;
+ uu[0] += v;
+ uu[1] = 0;
+ }
+ }
+ q2 = qhat;
+ /* ROUND 2. Set j = 1 and calculate q1 */
+ /* Estimate qhat = (u3u2) / v1
+ then set (u3u2u1) -= qhat(v1v0) */
+ t = uu[0];
+ qhat = t / v1;
+ rhat = t - qhat * v1;
+ /* Test on v0 */
+ t = TOHIGH(rhat) | u1;
+ if ((qhat == B_J) || (qhat * v0 > t))
+ {
+ qhat--;
+ rhat += v1;
+ t = TOHIGH(rhat) | u1;
+ if ((rhat < B_J) && (qhat * v0 > t))
+ {
+ qhat--;
+ }
+ }
+ /* Multiply and subtract
+ (u3u2u1)' = (u3u2u1) - qhat(v1v0) */
+ uu[1] = HIHALF(uu[0]); /* (0u3) */
+ uu[0] = TOHIGH(LOHALF(uu[0])) | u1; /* (u2u1) */
+ spMultSub(uu, qhat, v1, v0);
+ if (HIHALF(uu[1]) != 0)
+ { /* Add back */
+ qhat--;
+ uu[0] += v;
+ uu[1] = 0;
+ }
+ /* q1 = qhat */
+ *q = TOHIGH(qhat);
+ /* ROUND 3. Set j = 0 and calculate q0 */
+ /* Estimate qhat = (u2u1) / v1
+ then set (u2u1u0) -= qhat(v1v0) */
+ t = uu[0];
+ qhat = t / v1;
+ rhat = t - qhat * v1;
+ /* Test on v0 */
+ t = TOHIGH(rhat) | u0;
+ if ((qhat == B_J) || (qhat * v0 > t))
+ {
+ qhat--;
+ rhat += v1;
+ t = TOHIGH(rhat) | u0;
+ if ((rhat < B_J) && (qhat * v0 > t))
+ {
+ qhat--;
+ }
+ }
+ /* Multiply and subtract
+ (u2u1u0)" = (u2u1u0)' - qhat(v1v0) */
+ uu[1] = HIHALF(uu[0]); /* (0u2) */
+ uu[0] = TOHIGH(LOHALF(uu[0])) | u0; /* (u1u0) */
+ spMultSub(uu, qhat, v1, v0);
+ if (HIHALF(uu[1]) != 0)
+ { /* Add back */
+ qhat--;
+ uu[0] += v;
+ uu[1] = 0;
+ }
+ /* q0 = qhat */
+ *q |= LOHALF(qhat);
+ /* Remainder is in (u1u0) i.e. uu[0] */
+ *r = uu[0];
+ return q2;
+}
+
+/*****************************************************************************/
+static int APP_CC
+QhatTooBig(DIGIT_T qhat, DIGIT_T rhat, DIGIT_T vn2, DIGIT_T ujn2)
+{ /* Returns true if Qhat is too big
+ i.e. if (Qhat * Vn-2) > (b.Rhat + Uj+n-2) */
+ DIGIT_T t[2];
+
+ spMultiply(t, qhat, vn2);
+ if (t[1] < rhat)
+ {
+ return 0;
+ }
+ else if (t[1] > rhat)
+ {
+ return 1;
+ }
+ else if (t[0] > ujn2)
+ {
+ return 1;
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+static DIGIT_T APP_CC
+mpShortDiv(DIGIT_T* q, DIGIT_T* u, DIGIT_T v, unsigned int ndigits)
+{
+ /* Calculates quotient q = u div v
+ Returns remainder r = u mod v
+ where q, u are multiprecision integers of ndigits each
+ and d, v are single precision digits.
+
+ Makes no assumptions about normalisation.
+
+ Ref: Knuth Vol 2 Ch 4.3.1 Exercise 16 p625 */
+ unsigned int j;
+ unsigned int shift;
+ DIGIT_T t[2];
+ DIGIT_T r;
+ DIGIT_T bitmask;
+ DIGIT_T overflow;
+ DIGIT_T* uu;
+
+ if (ndigits == 0)
+ {
+ return 0;
+ }
+ if (v == 0)
+ {
+ return 0; /* Divide by zero error */
+ }
+ /* Normalise first */
+ /* Requires high bit of V
+ to be set, so find most signif. bit then shift left,
+ i.e. d = 2^shift, u' = u * d, v' = v * d. */
+ bitmask = HIBITMASK;
+ for (shift = 0; shift < BITS_PER_DIGIT; shift++)
+ {
+ if (v & bitmask)
+ {
+ break;
+ }
+ bitmask >>= 1;
+ }
+ v <<= shift;
+ overflow = mpShiftLeft(q, u, shift, ndigits);
+ uu = q;
+ /* Step S1 - modified for extra digit. */
+ r = overflow; /* New digit Un */
+ j = ndigits;
+ while (j--)
+ {
+ /* Step S2. */
+ t[1] = r;
+ t[0] = uu[j];
+ overflow = spDivide(&q[j], &r, t, v);
+ }
+ /* Unnormalise */
+ r >>= shift;
+ return r;
+}
+
+/*****************************************************************************/
+static DIGIT_T APP_CC
+mpMultSub(DIGIT_T wn, DIGIT_T* w, DIGIT_T* v, DIGIT_T q, unsigned int n)
+{ /* Compute w = w - qv
+ where w = (WnW[n-1]...W[0])
+ return modified Wn. */
+ DIGIT_T k;
+ DIGIT_T t[2];
+ unsigned int i;
+
+ if (q == 0) /* No change */
+ {
+ return wn;
+ }
+ k = 0;
+ for (i = 0; i < n; i++)
+ {
+ spMultiply(t, q, v[i]);
+ w[i] -= k;
+ if (w[i] > MAX_DIGIT - k)
+ {
+ k = 1;
+ }
+ else
+ {
+ k = 0;
+ }
+ w[i] -= t[0];
+ if (w[i] > MAX_DIGIT - t[0])
+ {
+ k++;
+ }
+ k += t[1];
+ }
+ /* Cope with Wn not stored in array w[0..n-1] */
+ wn -= k;
+ return wn;
+}
+
+/*****************************************************************************/
+static int APP_CC
+mpDivide(DIGIT_T* q, DIGIT_T* r, DIGIT_T* u, unsigned int udigits,
+ DIGIT_T* v, unsigned int vdigits)
+{ /* Computes quotient q = u / v and remainder r = u mod v
+ where q, r, u are multiple precision digits
+ all of udigits and the divisor v is vdigits.
+
+ Ref: Knuth Vol 2 Ch 4.3.1 p 272 Algorithm D.
+
+ Do without extra storage space, i.e. use r[] for
+ normalised u[], unnormalise v[] at end, and cope with
+ extra digit Uj+n added to u after normalisation.
+
+ WARNING: this trashes q and r first, so cannot do
+ u = u / v or v = u mod v. */
+ unsigned int shift;
+ int n;
+ int m;
+ int j;
+ int qhatOK;
+ int cmp;
+ DIGIT_T bitmask;
+ DIGIT_T overflow;
+ DIGIT_T qhat;
+ DIGIT_T rhat;
+ DIGIT_T t[2];
+ DIGIT_T* uu;
+ DIGIT_T* ww;
+
+ /* Clear q and r */
+ mpSetZero(q, udigits);
+ mpSetZero(r, udigits);
+ /* Work out exact sizes of u and v */
+ n = (int)mpSizeof(v, vdigits);
+ m = (int)mpSizeof(u, udigits);
+ m -= n;
+ /* Catch special cases */
+ if (n == 0)
+ {
+ return -1; /* Error: divide by zero */
+ }
+ if (n == 1)
+ { /* Use short division instead */
+ r[0] = mpShortDiv(q, u, v[0], udigits);
+ return 0;
+ }
+ if (m < 0)
+ { /* v > u, so just set q = 0 and r = u */
+ mpSetEqual(r, u, udigits);
+ return 0;
+ }
+ if (m == 0)
+ { /* u and v are the same length */
+ cmp = mpCompare(u, v, (unsigned int)n);
+ if (cmp < 0)
+ { /* v > u, as above */
+ mpSetEqual(r, u, udigits);
+ return 0;
+ }
+ else if (cmp == 0)
+ { /* v == u, so set q = 1 and r = 0 */
+ mpSetDigit(q, 1, udigits);
+ return 0;
+ }
+ }
+ /* In Knuth notation, we have:
+ Given
+ u = (Um+n-1 ... U1U0)
+ v = (Vn-1 ... V1V0)
+ Compute
+ q = u/v = (QmQm-1 ... Q0)
+ r = u mod v = (Rn-1 ... R1R0) */
+ /* Step D1. Normalise */
+ /* Requires high bit of Vn-1
+ to be set, so find most signif. bit then shift left,
+ i.e. d = 2^shift, u' = u * d, v' = v * d. */
+ bitmask = HIBITMASK;
+ for (shift = 0; shift < BITS_PER_DIGIT; shift++)
+ {
+ if (v[n - 1] & bitmask)
+ {
+ break;
+ }
+ bitmask >>= 1;
+ }
+ /* Normalise v in situ - NB only shift non-zero digits */
+ overflow = mpShiftLeft(v, v, shift, n);
+ /* Copy normalised dividend u*d into r */
+ overflow = mpShiftLeft(r, u, shift, n + m);
+ uu = r; /* Use ptr to keep notation constant */
+ t[0] = overflow; /* New digit Um+n */
+ /* Step D2. Initialise j. Set j = m */
+ for (j = m; j >= 0; j--)
+ {
+ /* Step D3. Calculate Qhat = (b.Uj+n + Uj+n-1)/Vn-1 */
+ qhatOK = 0;
+ t[1] = t[0]; /* This is Uj+n */
+ t[0] = uu[j+n-1];
+ overflow = spDivide(&qhat, &rhat, t, v[n - 1]);
+ /* Test Qhat */
+ if (overflow)
+ { /* Qhat = b */
+ qhat = MAX_DIGIT;
+ rhat = uu[j + n - 1];
+ rhat += v[n - 1];
+ if (rhat < v[n - 1]) /* Overflow */
+ {
+ qhatOK = 1;
+ }
+ }
+ if (!qhatOK && QhatTooBig(qhat, rhat, v[n - 2], uu[j + n - 2]))
+ { /* Qhat.Vn-2 > b.Rhat + Uj+n-2 */
+ qhat--;
+ rhat += v[n - 1];
+ if (!(rhat < v[n - 1]))
+ {
+ if (QhatTooBig(qhat, rhat, v[n - 2], uu[j + n - 2]))
+ {
+ qhat--;
+ }
+ }
+ }
+ /* Step D4. Multiply and subtract */
+ ww = &uu[j];
+ overflow = mpMultSub(t[1], ww, v, qhat, (unsigned int)n);
+ /* Step D5. Test remainder. Set Qj = Qhat */
+ q[j] = qhat;
+ if (overflow)
+ { /* Step D6. Add back if D4 was negative */
+ q[j]--;
+ overflow = mpAdd(ww, ww, v, (unsigned int)n);
+ }
+ t[0] = uu[j + n - 1]; /* Uj+n on next round */
+ } /* Step D7. Loop on j */
+ /* Clear high digits in uu */
+ for (j = n; j < m+n; j++)
+ {
+ uu[j] = 0;
+ }
+ /* Step D8. Unnormalise. */
+ mpShiftRight(r, r, shift, n);
+ mpShiftRight(v, v, shift, n);
+ return 0;
+}
+
+/*****************************************************************************/
+static int APP_CC
+mpModulo(DIGIT_T* r, DIGIT_T* u, unsigned int udigits,
+ DIGIT_T* v, unsigned int vdigits)
+{
+ /* Calculates r = u mod v
+ where r, v are multiprecision integers of length vdigits
+ and u is a multiprecision integer of length udigits.
+ r may overlap v.
+
+ Note that r here is only vdigits long,
+ whereas in mpDivide it is udigits long.
+
+ Use remainder from mpDivide function. */
+ /* Double-length temp variable for divide fn */
+ DIGIT_T qq[MAX_DIG_LEN * 2];
+ /* Use a double-length temp for r to allow overlap of r and v */
+ DIGIT_T rr[MAX_DIG_LEN * 2];
+
+ /* rr[2n] = u[2n] mod v[n] */
+ mpDivide(qq, rr, u, udigits, v, vdigits);
+ mpSetEqual(r, rr, vdigits);
+ mpSetZero(rr, udigits);
+ mpSetZero(qq, udigits);
+ return 0;
+}
+
+/*****************************************************************************/
+static int APP_CC
+mpMultiply(DIGIT_T* w, DIGIT_T* u, DIGIT_T* v, unsigned int ndigits)
+{
+ /* Computes product w = u * v
+ where u, v are multiprecision integers of ndigits each
+ and w is a multiprecision integer of 2*ndigits
+ Ref: Knuth Vol 2 Ch 4.3.1 p 268 Algorithm M. */
+ DIGIT_T k;
+ DIGIT_T t[2];
+ unsigned int i;
+ unsigned int j;
+ unsigned int m;
+ unsigned int n;
+
+ n = ndigits;
+ m = n;
+ /* Step M1. Initialise */
+ for (i = 0; i < 2 * m; i++)
+ {
+ w[i] = 0;
+ }
+ for (j = 0; j < n; j++)
+ {
+ /* Step M2. Zero multiplier? */
+ if (v[j] == 0)
+ {
+ w[j + m] = 0;
+ }
+ else
+ {
+ /* Step M3. Initialise i */
+ k = 0;
+ for (i = 0; i < m; i++)
+ {
+ /* Step M4. Multiply and add */
+ /* t = u_i * v_j + w_(i+j) + k */
+ spMultiply(t, u[i], v[j]);
+ t[0] += k;
+ if (t[0] < k)
+ {
+ t[1]++;
+ }
+ t[0] += w[i + j];
+ if (t[0] < w[i+j])
+ {
+ t[1]++;
+ }
+ w[i + j] = t[0];
+ k = t[1];
+ }
+ /* Step M5. Loop on i, set w_(j+m) = k */
+ w[j + m] = k;
+ }
+ } /* Step M6. Loop on j */
+ return 0;
+}
+
+/*****************************************************************************/
+static int APP_CC
+mpModMult(DIGIT_T* a, DIGIT_T* x, DIGIT_T* y,
+ DIGIT_T* m, unsigned int ndigits)
+{ /* Computes a = (x * y) mod m */
+ /* Double-length temp variable */
+ DIGIT_T p[MAX_DIG_LEN * 2];
+
+ /* Calc p[2n] = x * y */
+ mpMultiply(p, x, y, ndigits);
+ /* Then modulo */
+ mpModulo(a, p, ndigits * 2, m, ndigits);
+ mpSetZero(p, ndigits * 2);
+ return 0;
+}
+
+/*****************************************************************************/
+int APP_CC
+ssl_mod_exp(char* out, int out_len, char* in, int in_len,
+ char* mod, int mod_len, char* exp, int exp_len)
+{
+ /* Computes y = x ^ e mod m */
+ /* Binary left-to-right method */
+ DIGIT_T mask;
+ DIGIT_T* e;
+ DIGIT_T* x;
+ DIGIT_T* y;
+ DIGIT_T* m;
+ unsigned int n;
+ int max_size;
+ char* l_out;
+ char* l_in;
+ char* l_mod;
+ char* l_exp;
+
+ if (in_len > out_len || in_len == 0 ||
+ out_len == 0 || mod_len == 0 || exp_len == 0)
+ {
+ return 0;
+ }
+ max_size = out_len;
+ if (in_len > max_size)
+ {
+ max_size = in_len;
+ }
+ if (mod_len > max_size)
+ {
+ max_size = mod_len;
+ }
+ if (exp_len > max_size)
+ {
+ max_size = exp_len;
+ }
+ l_out = (char*)g_malloc(max_size, 1);
+ l_in = (char*)g_malloc(max_size, 1);
+ l_mod = (char*)g_malloc(max_size, 1);
+ l_exp = (char*)g_malloc(max_size, 1);
+ memcpy(l_in, in, in_len);
+ memcpy(l_mod, mod, mod_len);
+ memcpy(l_exp, exp, exp_len);
+ e = (DIGIT_T*)l_exp;
+ x = (DIGIT_T*)l_in;
+ y = (DIGIT_T*)l_out;
+ m = (DIGIT_T*)l_mod;
+ /* Find second-most significant bit in e */
+ n = mpSizeof(e, max_size / 4);
+ for (mask = HIBITMASK; mask > 0; mask >>= 1)
+ {
+ if (e[n - 1] & mask)
+ {
+ break;
+ }
+ }
+ mpNEXTBITMASK(mask, n);
+ /* Set y = x */
+ mpSetEqual(y, x, max_size / 4);
+ /* For bit j = k - 2 downto 0 step -1 */
+ while (n)
+ {
+ mpModMult(y, y, y, m, max_size / 4); /* Square */
+ if (e[n - 1] & mask)
+ {
+ mpModMult(y, y, x, m, max_size / 4); /* Multiply */
+ }
+ /* Move to next bit */
+ mpNEXTBITMASK(mask, n);
+ }
+ memcpy(out, l_out, out_len);
+ g_free(l_out);
+ g_free(l_in);
+ g_free(l_mod);
+ g_free(l_exp);
+ return out_len;
+}
+
diff --git a/uirdesktop/tcp.c b/uirdesktop/tcp.c
index dde4ddfa..35097263 100644
--- a/uirdesktop/tcp.c
+++ b/uirdesktop/tcp.c
@@ -2,12 +2,12 @@
rdesktop: A Remote Desktop Protocol client.
Protocol services - TCP layer
Copyright (C) Matthew Chapman 1999-2005
-
+
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
@@ -18,6 +18,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#ifndef _WIN32
#include <unistd.h> /* select read write close */
#include <sys/socket.h> /* socket connect setsockopt */
#include <sys/time.h> /* timeval */
@@ -26,8 +27,23 @@
#include <netinet/tcp.h> /* TCP_NODELAY */
#include <arpa/inet.h> /* inet_addr */
#include <errno.h> /* errno */
-#include "rdesktop.h"
-
+#endif /* _WIN32 */
+
+#include "rdesktop.h"
+
+#ifdef _WIN32
+#define socklen_t int
+#define TCP_CLOSE(_sck) closesocket(_sck)
+#define TCP_STRERROR "tcp error"
+#define TCP_SLEEP(_n) Sleep(_n)
+#define TCP_BLOCKS (WSAGetLastError() == WSAEWOULDBLOCK)
+#else /* _WIN32 */
+#define TCP_CLOSE(_sck) close(_sck)
+#define TCP_STRERROR strerror(errno)
+#define TCP_SLEEP(_n) sleep(_n)
+#define TCP_BLOCKS (errno == EWOULDBLOCK)
+#endif /* _WIN32 */
+
#ifndef INADDR_NONE
#define INADDR_NONE ((unsigned long) -1)
#endif
@@ -64,10 +80,17 @@ tcp_send(STREAM s)
sent = send(sock, s->data + total, length - total, 0);
if (sent <= 0)
{
- error("send: %s\n", strerror(errno));
- return;
+ if (sent == -1 && TCP_BLOCKS)
+ {
+ TCP_SLEEP(0);
+ sent = 0;
+ }
+ else
+ {
+ error("send: %s\n", TCP_STRERROR);
+ return;
+ }
}
-
total += sent;
}
}
@@ -114,8 +137,16 @@ tcp_recv(STREAM s, uint32 length)
rcvd = recv(sock, s->end, length, 0);
if (rcvd < 0)
{
- error("recv: %s\n", strerror(errno));
- return NULL;
+ if (rcvd == -1 && TCP_BLOCKS)
+ {
+ TCP_SLEEP(0);
+ rcvd = 0;
+ }
+ else
+ {
+ error("recv: %s\n", TCP_STRERROR);
+ return NULL;
+ }
}
else if (rcvd == 0)
{
@@ -163,7 +194,7 @@ tcp_connect(char *server)
{
if (connect(sock, res->ai_addr, res->ai_addrlen) == 0)
break;
- close(sock);
+ TCP_CLOSE(sock);
sock = -1;
}
res = res->ai_next;
@@ -193,17 +224,17 @@ tcp_connect(char *server)
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
- error("socket: %s\n", strerror(errno));
+ error("socket: %s\n", TCP_STRERROR);
return False;
}
servaddr.sin_family = AF_INET;
- servaddr.sin_port = htons(g_tcp_port_rdp);
+ servaddr.sin_port = htons((uint16) g_tcp_port_rdp);
if (connect(sock, (struct sockaddr *) &servaddr, sizeof(struct sockaddr)) < 0)
{
- error("connect: %s\n", strerror(errno));
- close(sock);
+ error("connect: %s\n", TCP_STRERROR);
+ TCP_CLOSE(sock);
return False;
}
@@ -224,7 +255,7 @@ tcp_connect(char *server)
void
tcp_disconnect(void)
{
- close(sock);
+ TCP_CLOSE(sock);
}
char *
diff --git a/uirdesktop/types.h b/uirdesktop/types.h
index eed9d8ab..2dc230dc 100644
--- a/uirdesktop/types.h
+++ b/uirdesktop/types.h
@@ -32,16 +32,16 @@ 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 void *RD_HBITMAP;
+typedef void *RD_HGLYPH;
+typedef void *RD_HCOLOURMAP;
+typedef void *RD_HCURSOR;
-typedef struct _POINT
+typedef struct _RD_POINT
{
sint16 x, y;
}
-POINT;
+RD_POINT;
typedef struct _COLOURENTRY
{
@@ -95,7 +95,7 @@ typedef struct _FONTGLYPH
sint16 baseline;
uint16 width;
uint16 height;
- HBITMAP pixmap;
+ RD_HBITMAP pixmap;
}
FONTGLYPH;
@@ -155,7 +155,7 @@ typedef struct
uint16 wBitsPerSample;
uint16 cbSize;
uint8 cb[MAX_CBSIZE];
-} WAVEFORMATEX;
+} RD_WAVEFORMATEX;
typedef struct _RDPCOMP
{
@@ -166,20 +166,20 @@ typedef struct _RDPCOMP
RDPCOMP;
/* RDPDR */
-typedef uint32 NTSTATUS;
-typedef uint32 NTHANDLE;
+typedef uint32 RD_NTSTATUS;
+typedef uint32 RD_NTHANDLE;
typedef struct _DEVICE_FNS
{
- NTSTATUS(*create) (uint32 device, uint32 desired_access, uint32 share_mode,
+ RD_NTSTATUS(*create) (uint32 device, uint32 desired_access, uint32 share_mode,
uint32 create_disposition, uint32 flags_and_attributes, char *filename,
- NTHANDLE * handle);
- NTSTATUS(*close) (NTHANDLE handle);
- NTSTATUS(*read) (NTHANDLE handle, uint8 * data, uint32 length, uint32 offset,
+ RD_NTHANDLE * handle);
+ RD_NTSTATUS(*close) (RD_NTHANDLE handle);
+ RD_NTSTATUS(*read) (RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset,
uint32 * result);
- NTSTATUS(*write) (NTHANDLE handle, uint8 * data, uint32 length, uint32 offset,
+ RD_NTSTATUS(*write) (RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset,
uint32 * result);
- NTSTATUS(*device_control) (NTHANDLE handle, uint32 request, STREAM in, STREAM out);
+ RD_NTSTATUS(*device_control) (RD_NTHANDLE handle, uint32 request, STREAM in, STREAM out);
}
DEVICE_FNS;
@@ -187,7 +187,7 @@ DEVICE_FNS;
typedef struct rdpdr_device_info
{
uint32 device_type;
- NTHANDLE handle;
+ RD_NTHANDLE handle;
char name[8];
char *local_path;
void *pdevice_data;
@@ -251,7 +251,8 @@ NOTIFY;
#ifndef PATH_MAX
#define PATH_MAX 256
#endif
-
+
+#ifndef _WIN32
typedef struct fileinfo
{
uint32 device_id, flags_and_attributes, accessmask;
@@ -263,6 +264,7 @@ typedef struct fileinfo
NOTIFY notify;
uint32 info_class;
}
-FILEINFO;
+FILEINFO;
+#endif
typedef BOOL(*str_handle_lines_t) (const char *line, void *data);
diff --git a/uirdesktop/uimain.c b/uirdesktop/uimain.c
new file mode 100755
index 00000000..9f9bcac7
--- /dev/null
+++ b/uirdesktop/uimain.c
@@ -0,0 +1,1124 @@
+/* -*- c-basic-offset: 8 -*-
+ rdesktop: A Remote Desktop Protocol client.
+ Main ui file
+ Copyright (C) Jay Sorg 2006
+
+ 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 "bsops.h"
+#include "uimain.h"
+
+char g_username[256] = "";
+char g_hostname[256] = "";
+char g_servername[256] = "";
+char g_password[256] = "";
+char g_shell[256] = "";
+char g_directory[256] = "";
+char g_domain[256] = "";
+char * g_bs = 0; /* created in hardware file, used in bsops.c */
+int g_bs_Bpp = 4;
+int g_bs_bpp = 32;
+BOOL g_desktop_save = False; /* desktop save order */
+BOOL g_polygon_ellipse_orders = False; /* polygon / ellipse orders */
+BOOL g_bitmap_compression = True;
+uint32 g_rdp5_performanceflags =
+ RDP5_NO_WALLPAPER | RDP5_NO_FULLWINDOWDRAG | RDP5_NO_MENUANIMATIONS;
+BOOL g_bitmap_cache_persist_enable = False;
+BOOL g_bitmap_cache_precache = True;
+BOOL g_bitmap_cache = True;
+BOOL g_encryption = True;
+int g_server_depth = 8;
+BOOL g_use_rdp5 = False;
+int g_width = 800;
+int g_height = 600;
+uint32 g_keylayout = 0x409; /* Defaults to US keyboard layout */
+int g_keyboard_type = 0x4; /* Defaults to US keyboard layout */
+int g_keyboard_subtype = 0x0; /* Defaults to US keyboard layout */
+int g_keyboard_functionkeys = 0xc; /* Defaults to US keyboard layout */
+BOOL g_console_session = False;
+
+/* can't be static, hardware file or bsops need these */
+int g_tcp_sck = 0;
+int pal_entries[256];
+
+/* Session Directory redirection */
+BOOL g_redirect = False;
+char g_redirect_server[64];
+char g_redirect_domain[16];
+char g_redirect_password[64];
+char g_redirect_username[64];
+char g_redirect_cookie[128];
+uint32 g_redirect_flags = 0;
+
+extern int g_tcp_port_rdp;
+
+static int g_deactivated = 0;
+static uint32 g_ext_disc_reason = 0;
+
+struct bitmap
+{
+ uint8 * data;
+ uint32 width;
+ uint32 height;
+};
+
+/* in ui specific file eg win32.c, qt.c, dfb.c, ... */
+int
+mi_create_window(void);
+void
+mi_invalidate(int x, int y, int cx, int cy);
+int
+mi_create_bs(void);
+int
+mi_main_loop(void);
+void
+mi_error(char * msg);
+void
+mi_warning(char * msg);
+void
+ui_invalidate(int x, int y, int cx, int cy);
+void
+mi_paint_rect(char * data, int width, int height, int x, int y, int cx, int cy);
+void
+mi_begin_update(void);
+void
+mi_end_update(void);
+void
+mi_fill_rect(int x, int y, int cx, int cy, int colour);
+void
+mi_screen_copy(int x, int y, int cx, int cy, int srcx, int srcy);
+void
+mi_set_clip(int x, int y, int cx, int cy);
+void
+mi_reset_clip(void);
+void
+mi_line(int x1, int y1, int x2, int y2, int colour);
+mi_create_cursor(unsigned int x, unsigned int y,
+ int width, int height,
+ unsigned char * andmask, unsigned char * xormask);
+void
+mi_destroy_cursor(void * cursor);
+void
+mi_set_cursor(void * cursor);
+void
+mi_set_null_cursor(void);
+int
+mi_read_keyboard_state(void);
+
+/*****************************************************************************/
+/* put part of the screen from the backing store to the display */
+void
+ui_invalidate(int x, int y, int cx, int cy)
+{
+ if (cx < 1 || cy < 1 || g_bs == 0)
+ {
+ return;
+ }
+ if (bs_warp_coords(&x, &y, &cx, &cy, 0, 0))
+ {
+ mi_invalidate(x, y, cx, cy);
+ }
+/*
+ if (bs_warp_coords(&x, &y, &cx, &cy, 0, 0))
+ {
+ cx = (cx + 3) & ~3;
+ data = (char *) xmalloc(cx * cy * 4);
+ bs_copy_box(data, x, y, cx, cy, cx * ((g_server_depth + 7) / 8));
+ mi_paint_rect(data, cx, cy, x, y, cx, cy);
+ xfree(data);
+ }
+*/
+}
+
+/*****************************************************************************/
+static int
+convert_colour(int in_colour)
+{
+ int r;
+ int g;
+ int b;
+
+ if (g_server_depth == 8)
+ {
+ r = (pal_entries[in_colour & 0xff] & 0xff0000) >> 16;
+ g = (pal_entries[in_colour & 0xff] & 0xff00) >> 8;
+ b = pal_entries[in_colour & 0xff] & 0xff;
+ }
+ else if (g_server_depth == 15)
+ {
+ SPLIT_COLOUR15(in_colour, r, g, b);
+ }
+ else if (g_server_depth == 16)
+ {
+ SPLIT_COLOUR16(in_colour, r, g, b);
+ }
+ else if (g_server_depth == 24)
+ {
+ SPLIT_COLOUR32(in_colour, r, g, b);
+ }
+ if (g_bs_bpp == 32)
+ {
+ MAKE_COLOUR32(in_colour, r, g, b);
+ }
+ return in_colour;
+}
+
+/*****************************************************************************/
+void
+ui_bell(void)
+{
+}
+
+/*****************************************************************************/
+int
+ui_select(int in)
+{
+ if (g_tcp_sck == 0)
+ {
+ g_tcp_sck = in;
+ }
+ return 1;
+}
+
+/*****************************************************************************/
+void *
+ui_create_cursor(uint32 x, uint32 y,
+ int width, int height,
+ uint8 * andmask, uint8 * xormask)
+{
+ int i;
+ int j;
+ char am[32 * 4];
+ char xm[32 * 4];
+
+ if (width != 32 || height != 32)
+ {
+ return 0;
+ }
+ memset(am, 0, 32 * 4);
+ memset(xm, 0, 32 * 4);
+ for (i = 0; i < 32; i++)
+ {
+ for (j = 0; j < 32; j++)
+ {
+ if (bs_is_pixel_on(andmask, j, i, 32, 1))
+ {
+ bs_set_pixel_on(am, j, 31 - i, 32, 1, 1);
+ }
+ if (bs_is_pixel_on(xormask, j, i, 32, 24))
+ {
+ bs_set_pixel_on(xm, j, 31 - i, 32, 1, 1);
+ }
+ }
+ }
+ return (void *) mi_create_cursor(x, y, width, height, am, xm);
+}
+
+/*****************************************************************************/
+void
+ui_destroy_cursor(void * cursor)
+{
+ mi_destroy_cursor(cursor);
+}
+
+/*****************************************************************************/
+void
+ui_set_cursor(void * cursor)
+{
+ mi_set_cursor(cursor);
+}
+
+/*****************************************************************************/
+void
+ui_set_null_cursor(void)
+{
+ mi_set_null_cursor();
+}
+
+/*****************************************************************************/
+void *
+ui_create_glyph(int width, int height, uint8 * data)
+{
+ int i;
+ int j;
+ char * glyph_data;
+ struct bitmap * the_glyph;
+
+ glyph_data = (char *) xmalloc(width * height);
+ memset(glyph_data, 0, width * height);
+ the_glyph = (struct bitmap *) xmalloc(sizeof(struct bitmap));
+ memset(the_glyph, 0, sizeof(struct bitmap));
+ the_glyph->width = width;
+ the_glyph->height = height;
+ the_glyph->data = glyph_data;
+ for (i = 0; i < height; i++)
+ {
+ for (j = 0; j < width; j++)
+ {
+ if (bs_is_pixel_on(data, j, i, width, 1))
+ {
+ bs_set_pixel_on(glyph_data, j, i, width, 8, 255);
+ }
+ }
+ }
+ return the_glyph;
+}
+
+/*****************************************************************************/
+void
+ui_destroy_glyph(void * glyph)
+{
+ struct bitmap * the_glyph;
+
+ the_glyph = glyph;
+ if (the_glyph != 0)
+ {
+ xfree(the_glyph->data);
+ }
+ xfree(the_glyph);
+}
+
+/*****************************************************************************/
+void *
+ui_create_bitmap(int width, int height, uint8 * data)
+{
+#if 0
+ struct bitmap * b;
+ int size;
+
+ size = width * height * ((g_server_depth + 7) / 8);
+ b = (struct bitmap *) xmalloc(sizeof(struct bitmap));
+ b->data = (uint8 *) xmalloc(size);
+ memcpy(b->data, data, size);
+ b->width = width;
+ b->height = height;
+ return b;
+#endif
+ return 0;
+}
+
+/*****************************************************************************/
+void *
+ui_create_bitmap_ex(int width, int height, uint8 * data, int data_size,
+ int compressed)
+{
+ struct bitmap * b;
+ int size;
+ int i;
+ int j;
+ int pixel;
+ int red;
+ int green;
+ int blue;
+ unsigned short * s16;
+ unsigned char * s8;
+ unsigned int * d32;
+
+ size = width * height * 4;
+ b = (struct bitmap *) xmalloc(sizeof(struct bitmap));
+ b->data = (uint8 *) xmalloc(size);
+ if (compressed)
+ {
+ bitmap_decompress_ex(b->data, width, height, data, data_size,
+ g_server_depth, 32);
+ }
+ else
+ {
+ if (g_server_depth == 16 && g_bs_bpp == 32)
+ {
+ for (i = 0; i < height; i++)
+ {
+ s16 = ((unsigned short *) data) + (i * width);
+ d32 = ((unsigned int *) b->data) + (height - i - 1) * width;
+ for (j = 0; j < width; j++)
+ {
+ pixel = *s16;
+ s16++;
+ SPLIT_COLOUR16(pixel, red, green, blue);
+ MAKE_COLOUR32(pixel, red, green, blue);
+ *d32 = pixel;
+ d32++;
+ }
+ }
+ }
+ else if (g_server_depth == 24 && g_bs_bpp == 32)
+ {
+ for (i = 0; i < height; i++)
+ {
+ s8 = ((unsigned char *) data) + (i * width * 3);
+ d32 = ((unsigned int *) b->data) + (height - i - 1) * width;
+ for (j = 0; j < width; j++)
+ {
+ blue = *s8;
+ s8++;
+ green = *s8;
+ s8++;
+ red = *s8;
+ s8++;
+ MAKE_COLOUR32(pixel, red, green, blue);
+ *d32 = pixel;
+ d32++;
+ }
+ }
+ }
+ }
+ b->width = width;
+ b->height = height;
+ return b;
+}
+
+/*****************************************************************************/
+void
+ui_destroy_bitmap(void * bmp)
+{
+ struct bitmap * b;
+
+ b = (struct bitmap *) bmp;
+ if (b != 0)
+ {
+ xfree(b->data);
+ }
+ xfree(b);
+}
+
+/*****************************************************************************/
+void
+ui_paint_bitmap(int x, int y, int cx, int cy,
+ int width, int height, uint8 * data)
+{
+/* struct bitmap b;
+
+ b.width = width;
+ b.height = height;
+ b.data = data;
+ ui_memblt(12, x, y, cx, cy, &b, 0, 0); */
+}
+
+/*****************************************************************************/
+void
+ui_paint_bitmap_ex(int x, int y, int cx, int cy,
+ int width, int height, uint8 * data, int data_size,
+ int compressed)
+{
+ struct bitmap * b;
+
+ b = ui_create_bitmap_ex(width, height, data, data_size, compressed);
+ ui_memblt(12, x, y, cx, cy, b, 0, 0);
+ ui_destroy_bitmap(b);
+}
+
+/*****************************************************************************/
+void
+ui_set_clip(int x, int y, int cx, int cy)
+{
+ bs_set_clip(x, y, cx, cy);
+ mi_set_clip(x, y, cx, cy);
+}
+
+/*****************************************************************************/
+void
+ui_reset_clip(void)
+{
+ bs_reset_clip();
+ mi_reset_clip();
+}
+
+/*****************************************************************************/
+void *
+ui_create_colourmap(COLOURMAP * colours)
+{
+ int i;
+ int n;
+
+ n = MIN(256, colours->ncolours);
+ memset(pal_entries, 0, sizeof(pal_entries));
+ for (i = 0; i < n; i++)
+ {
+ pal_entries[i] = (colours->colours[i].red << 16) |
+ (colours->colours[i].green << 8) |
+ colours->colours[i].blue;
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+void
+ui_set_colourmap(void * map)
+{
+}
+
+/*****************************************************************************/
+/* don't convert colour here */
+static void
+draw_glyph(int x, int y, void * glyph, int fgcolor)
+{
+ struct bitmap * b;
+
+ b = glyph;
+ bs_draw_glyph(x, y, b->data, b->width, b->height, fgcolor);
+}
+
+/*****************************************************************************/
+#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, uint8 opcode, int mixmode,
+ int x, int y,
+ int clipx, int clipy, int clipcx, int clipcy,
+ int boxx, int boxy, int boxcx, int boxcy, BRUSH * brush,
+ int bgcolour, int fgcolour, uint8 * text, uint8 length)
+{
+ int i;
+ int j;
+ int xyoffset;
+ DATABLOB * entry;
+ FONTGLYPH * glyph;
+
+ fgcolour = convert_colour(fgcolour);
+ bgcolour = convert_colour(bgcolour);
+ if (boxx + boxcx > g_width)
+ {
+ boxcx = g_width - boxx;
+ }
+ if (boxcx > 1)
+ {
+ bs_rect(boxx, boxy, boxcx, boxcy, bgcolour, 0xc);
+ }
+ else
+ {
+ if (mixmode == MIX_OPAQUE)
+ {
+ bs_rect(clipx, clipy, clipcx, clipcy, bgcolour, 0xc);
+ }
+ }
+ /* 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)
+ {
+ ui_invalidate(boxx, boxy, boxcx, boxcy);
+ }
+ else
+ {
+ ui_invalidate(clipx, clipy, clipcx, clipcy);
+ }
+}
+
+/*****************************************************************************/
+void
+ui_line(uint8 opcode, int startx, int starty, int endx, int endy,
+ PEN * pen)
+{
+ int x;
+ int y;
+ int cx;
+ int cy;
+ int colour;
+
+ colour = convert_colour(pen->colour);
+
+ bs_line(opcode, startx, starty, endx, endy, pen->width, pen->style,
+ colour);
+ if (pen->style == 0 && pen->width < 2 && opcode == 12)
+ {
+ mi_line(startx, starty, endx, endy, colour);
+ }
+ else
+ {
+ x = MIN(startx, endx);
+ y = MIN(starty, endy);
+ cx = (MAX(startx, endx) + 1) - x;
+ cy = (MAX(starty, endy) + 1) - y;
+ ui_invalidate(x, y, cx, cy);
+ }
+}
+
+/*****************************************************************************/
+void
+ui_triblt(uint8 opcode, int x, int y, int cx, int cy,
+ void * src, int srcx, int srcy,
+ BRUSH* brush, int bgcolour, int fgcolour)
+{
+ /* not used */
+}
+
+/*****************************************************************************/
+void
+ui_memblt(uint8 opcode, int x, int y, int cx, int cy,
+ void * src, int srcx, int srcy)
+{
+ struct bitmap* b;
+
+ b = (struct bitmap *) src;
+ bs_memblt(opcode, x, y, cx, cy, b->data, b->width, b->height,
+ srcx, srcy);
+ ui_invalidate(x, y, cx, cy);
+}
+
+/*****************************************************************************/
+void
+ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy)
+{
+}
+
+/*****************************************************************************/
+void
+ui_desktop_save(uint32 offset, int x, int y, int cx, int cy)
+{
+}
+
+/*****************************************************************************/
+void
+ui_rect(int x, int y, int cx, int cy, int colour)
+{
+ colour = convert_colour(colour);
+ bs_rect(x, y, cx, cy, colour, 12);
+ mi_fill_rect(x, y, cx, cy, colour);
+}
+
+/*****************************************************************************/
+void
+ui_screenblt(uint8 opcode, int x, int y, int cx, int cy,
+ int srcx, int srcy)
+{
+ bs_screenblt(opcode, x, y, cx, cy, srcx, srcy);
+ if (opcode == 12)
+ {
+ mi_screen_copy(x, y, cx, cy, srcx, srcy);
+ }
+ else
+ {
+ ui_invalidate(x, y, cx, cy);
+ }
+}
+
+/*****************************************************************************/
+void
+ui_patblt(uint8 opcode, int x, int y, int cx, int cy,
+ BRUSH * brush, int bgcolour, int fgcolour)
+{
+ bgcolour = convert_colour(bgcolour);
+ fgcolour = convert_colour(fgcolour);
+ bs_patblt(opcode, x, y, cx, cy, brush->style, brush->pattern,
+ brush->xorigin, brush->yorigin, bgcolour, fgcolour);
+ ui_invalidate(x, y, cx, cy);
+}
+
+/*****************************************************************************/
+void
+ui_destblt(uint8 opcode, int x, int y, int cx, int cy)
+{
+ bs_rect(x, y, cx, cy, 0, opcode);
+ ui_invalidate(x, y, cx, cy);
+ /* todo */
+}
+
+/*****************************************************************************/
+void
+ui_move_pointer(int x, int y)
+{
+}
+
+/*****************************************************************************/
+uint16
+ui_get_numlock_state(uint32 state)
+{
+ return (uint16) state;
+}
+
+/*****************************************************************************/
+/* get the num, caps, and scroll lock state */
+/* scroll lock is 1, num lock is 2 and caps lock is 4 */
+/* just returning 0, the hardware specific file is responsable for this */
+uint32
+read_keyboard_state(void)
+{
+ return (uint32) mi_read_keyboard_state();
+}
+
+/*****************************************************************************/
+void
+ui_set_modifier_state(int code)
+ {
+ //error("%8.8x", code);
+ rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, (uint16) code, 0);
+ }
+
+/*****************************************************************************/
+void
+ui_resize_window(void)
+{
+}
+
+/*****************************************************************************/
+void
+ui_begin_update(void)
+{
+ mi_begin_update();
+}
+
+/*****************************************************************************/
+void
+ui_end_update(void)
+{
+ mi_end_update();
+}
+
+/*****************************************************************************/
+void
+ui_polygon(uint8 opcode, uint8 fillmode, POINT * point, int npoints,
+ BRUSH * brush, int bgcolour, int fgcolour)
+{
+ /* not used */
+}
+
+/*****************************************************************************/
+void
+ui_polyline(uint8 opcode, POINT * points, int npoints, PEN * pen)
+{
+ int i, x, y, dx, dy;
+ if (npoints > 0)
+ {
+ x = points[0].x;
+ y = points[0].y;
+ for (i = 1; i < npoints; i++)
+ {
+ dx = points[i].x;
+ dy = points[i].y;
+ ui_line(opcode, x, y, x + dx, y + dy, pen);
+ x = x + dx;
+ y = y + dy;
+ }
+ }
+}
+
+/*****************************************************************************/
+void
+ui_ellipse(uint8 opcode, uint8 fillmode,
+ int x, int y, int cx, int cy,
+ BRUSH * brush, int bgcolour, int fgcolour)
+{
+ /* not used */
+}
+
+/*****************************************************************************/
+/* get a 32 byte random */
+void
+generate_random(uint8 * random)
+{
+ int i;
+
+ rand();
+ rand();
+ for (i = 0; i < 32; i++)
+ {
+ random[i] = rand() >> 16; /* higher bits are more random */
+ }
+}
+
+/*****************************************************************************/
+void
+save_licence(uint8 * data, int length)
+{
+}
+
+/*****************************************************************************/
+int
+load_licence(uint8 ** data)
+{
+ return 0;
+}
+
+/*****************************************************************************/
+void *
+xrealloc(void * in, int size)
+{
+ if (size < 1)
+ {
+ size = 1;
+ }
+ return realloc(in, size);
+}
+
+/*****************************************************************************/
+void *
+xmalloc(int size)
+{
+ if (size < 1)
+ {
+ size = 1;
+ }
+ return malloc(size);
+}
+
+/*****************************************************************************/
+void
+xfree(void * in)
+{
+ if (in != 0)
+ {
+ free(in);
+ }
+}
+
+/*****************************************************************************/
+char *
+xstrdup(const char * s)
+{
+ int len;
+ char * p;
+
+ if (s == 0)
+ {
+ return 0;
+ }
+ len = strlen(s);
+ p = (char *) xmalloc(len + 1);
+ strcpy(p, s);
+ return p;
+}
+
+/*****************************************************************************/
+void
+warning(char * format, ...)
+{
+ va_list ap;
+ char text[512];
+ char text1[512];
+
+ sprintf(text1, "WARNING: ");
+ va_start(ap, format);
+ vsprintf(text, format, ap);
+ va_end(ap);
+ strcat(text1, text);
+ mi_warning(text1);
+}
+
+/*****************************************************************************/
+void
+unimpl(char * format, ...)
+{
+ va_list ap;
+ char text[512];
+ char text1[512];
+
+ sprintf(text1, "UNIMPL: ");
+ va_start(ap, format);
+ vsprintf(text, format, ap);
+ va_end(ap);
+ strcat(text1, text);
+ mi_warning(text1);
+}
+
+/*****************************************************************************/
+void
+error(char * format, ...)
+{
+ va_list ap;
+ char text[512];
+ char text1[512];
+
+ sprintf(text1, "ERROR: ");
+ va_start(ap, format);
+ vsprintf(text, format, ap);
+ va_end(ap);
+ strcat(text1, text);
+ mi_error(text1);
+}
+
+/*****************************************************************************/
+BOOL
+rd_pstcache_mkdir(void)
+{
+ return 0;
+}
+
+/*****************************************************************************/
+int
+rd_open_file(char * filename)
+{
+ return 0;
+}
+
+/*****************************************************************************/
+void
+rd_close_file(int fd)
+{
+ return;
+}
+
+/*****************************************************************************/
+int
+rd_read_file(int fd, void * ptr, int len)
+{
+ return 0;
+}
+
+/*****************************************************************************/
+int
+rd_write_file(int fd, void * ptr, int len)
+{
+ return 0;
+}
+
+/*****************************************************************************/
+int
+rd_lseek_file(int fd, int offset)
+{
+ return 0;
+}
+
+/*****************************************************************************/
+BOOL
+rd_lock_file(int fd, int start, int len)
+{
+ return False;
+}
+
+
+/*****************************************************************************/
+void
+ui_mouse_move(int x, int y)
+{
+ rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE, (uint16) x, (uint16) y);
+}
+
+
+/*****************************************************************************/
+void
+ui_mouse_button(int button, int x, int y, int down)
+{
+ uint16 flags;
+
+ flags = 0;
+ if (down)
+ {
+ flags |= MOUSE_FLAG_DOWN;
+ }
+ switch (button)
+ {
+ case 1:
+ flags |= MOUSE_FLAG_BUTTON1;
+ break;
+ case 2:
+ flags |= MOUSE_FLAG_BUTTON2;
+ break;
+ case 3:
+ flags |= MOUSE_FLAG_BUTTON3;
+ break;
+ case 4:
+ flags |= MOUSE_FLAG_BUTTON4;
+ break;
+ case 5:
+ flags |= MOUSE_FLAG_BUTTON5;
+ break;
+ }
+ rdp_send_input(0, RDP_INPUT_MOUSE, flags, (uint16) x, (uint16) y);
+}
+
+
+/*****************************************************************************/
+void
+ui_key_down(int key, int ext)
+
+{
+ rdp_send_input(0, RDP_INPUT_SCANCODE, (uint16) (RDP_KEYPRESS | ext),
+ (uint16) key, 0);
+}
+
+/*****************************************************************************/
+void
+ui_key_up(int key, int ext)
+{
+ rdp_send_input(0, RDP_INPUT_SCANCODE, (uint16) (RDP_KEYRELEASE | ext),
+ (uint16) key, 0);
+}
+
+/*****************************************************************************/
+/* returns boolean, non zero is good */
+int
+ui_read_wire(void)
+{
+ return rdp_loop(&g_deactivated, &g_ext_disc_reason);
+}
+
+/*****************************************************************************/
+/* called after the command line parameters are processed */
+/* returns boolean, non zero is ok */
+int
+ui_main(void)
+{
+ uint32 flags;
+
+ /* try to connect */
+ flags = RDP_LOGON_NORMAL;
+ if (g_password[0] != 0)
+ {
+ flags |= RDP_LOGON_AUTO;
+ }
+ if (!rdp_connect(g_servername, flags, g_domain, g_password,
+ g_shell, g_directory))
+ {
+ return 0;
+ }
+ /* create the window */
+ if (!mi_create_window())
+ {
+ error("mi_create_window failed\r\n");
+ return 0;
+ }
+ /* create backingstore stuff for use in bsops.c */
+ if (!mi_create_bs())
+ {
+ error("mi_create_bs failed\r\n");
+ return 0;
+ }
+ /* init backingstore */
+ bs_init();
+ /* if all ok, enter main loop */
+ return mi_main_loop();
+}
+
+/*****************************************************************************/
+/* produce a hex dump */
+void
+hexdump(uint8 * p, uint32 len)
+{
+ uint8 * line = p;
+ int i, thisline, offset = 0;
+
+ while (offset < (int)len)
+ {
+ printf("%04x ", offset);
+ thisline = len - offset;
+ if (thisline > 16)
+ thisline = 16;
+
+ for (i = 0; i < thisline; i++)
+ printf("%02x ", line[i]);
+
+ for (; i < 16; i++)
+ printf(" ");
+
+ for (i = 0; i < thisline; i++)
+ printf("%c", (line[i] >= 0x20 && line[i] < 0x7f) ? line[i] : '.');
+
+ printf("\n");
+ offset += thisline;
+ line += thisline;
+ }
+}
+
diff --git a/uirdesktop/uimain.h b/uirdesktop/uimain.h
new file mode 100755
index 00000000..a9d55c47
--- /dev/null
+++ b/uirdesktop/uimain.h
@@ -0,0 +1,83 @@
+/* -*- c-basic-offset: 8 -*-
+ rdesktop: A Remote Desktop Protocol client.
+ main ui header
+ Copyright (C) Jay Sorg 2005-2006
+
+ 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.
+*/
+
+/* in uimain.c */
+int
+ui_main(void);
+void
+ui_invalidate(int x, int y, int cx, int cy);
+int
+ui_read_wire(void);
+void
+ui_mouse_move(int x, int y);
+void
+ui_mouse_button(int button, int x, int y, int down);
+void
+ui_key_down(int key, int ext);
+void
+ui_key_up(int key, int ext);
+ void
+ ui_set_modifier_state(int code);
+
+#define SPLIT_COLOUR15(c, r, g, b) \
+{ \
+ r = ((c >> 7) & 0xf8) | ((c >> 12) & 0x7); \
+ g = ((c >> 2) & 0xf8) | ((c >> 8) & 0x7); \
+ b = ((c << 3) & 0xf8) | ((c >> 2) & 0x7); \
+}
+
+#define SPLIT_COLOUR16(c, r, g, b) \
+{ \
+ r = ((c >> 8) & 0xf8) | ((c >> 13) & 0x7); \
+ g = ((c >> 3) & 0xfc) | ((c >> 9) & 0x3); \
+ b = ((c << 3) & 0xf8) | ((c >> 2) & 0x7); \
+}
+
+#define SPLIT_COLOUR32(c, r, g, b) \
+{ \
+ r = ((c >> 0) & 0xff); \
+ g = ((c >> 8) & 0xff); \
+ b = ((c >> 16) & 0xff); \
+}
+
+#define MAKE_COLOUR15(c, r, g, b) \
+{ \
+ c = ( \
+ (((r & 0xff) >> 3) << 10) | \
+ (((g & 0xff) >> 3) << 5) | \
+ (((b & 0xff) >> 3) << 0) \
+ ); \
+}
+
+#define MAKE_COLOUR32(c, r, g, b) \
+{ \
+ c = ( \
+ ((r & 0xff) << 16) | \
+ ((g & 0xff) << 8) | \
+ ((b & 0xff) << 0) \
+ ); \
+}
+
+#undef UI_MAX
+#define UI_MAX(a, b) (((a) > (b)) ? (a) : (b))
+#undef UI_MIN
+#define UI_MIN(a, b) (((a) < (b)) ? (a) : (b))
+
+
diff --git a/uirdesktop/win32.c b/uirdesktop/win32.c
new file mode 100755
index 00000000..75862216
--- /dev/null
+++ b/uirdesktop/win32.c
@@ -0,0 +1,1733 @@
+/* -*- c-basic-offset: 8 -*-
+ rdesktop: A Remote Desktop Protocol client.
+ win32 calls
+ Copyright (C) Jay Sorg 2006
+
+ 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.
+*/
+
+#ifdef _WIN32_WCE
+#define MYWINCE
+#endif
+
+#include <winsock2.h> /* winsock2.h first */
+#include <windows.h>
+#ifdef MYWINCE
+#include <aygshell.h> /* aygshell.lib */
+#endif /* MYWINCE */
+#include <winuser.h>
+#include <stdio.h>
+#include "uimain.h"
+
+extern char g_username[];
+extern char g_hostname[];
+extern char g_servername[];
+extern char g_password[];
+extern char g_shell[];
+extern char g_directory[];
+extern char g_domain[];
+extern int g_width;
+extern int g_height;
+extern int g_tcp_sck;
+extern int g_server_depth;
+extern int g_tcp_port_rdp; /* in tcp.c */
+extern int pal_entries[];
+extern char * g_bs;
+extern int g_bs_bpp;
+extern int g_bs_Bpp;
+
+static HWND g_Wnd = 0;
+static HINSTANCE g_Instance = 0;
+static HCURSOR g_cursor = 0;
+static HBITMAP g_bs_bitmap = 0;
+static int g_block = 0;
+static int g_xoff = 0; /* offset from window to client coords */
+static int g_yoff = 0;
+static int g_xscroll = 0; /* current scroll position */
+static int g_yscroll = 0;
+static int g_screen_width = 0;
+static int g_screen_height = 0;
+static int g_wnd_cwidth = 0; /* set from WM_SIZE */
+static int g_wnd_cheight = 0;
+static int g_fullscreen = 0;
+static int g_workarea = 0;
+static int g_mousex = 0; /* in client coords */
+static int g_mousey = 0;
+static int g_width_height_set = 0;
+
+static int g_clip_left = 0;
+static int g_clip_top = 0;
+static int g_clip_right = 800;
+static int g_clip_bottom = 600;
+static RECT g_wnd_clip; /* this client area of whats actually visable */
+ /* set from WM_SIZE */
+#ifdef MYWINCE
+static int g_sip_up = 0;
+#endif
+
+/*****************************************************************************/
+static void
+str_to_uni(TCHAR * sizex, char * size1)
+{
+ int len;
+ int i;
+
+ len = strlen(size1);
+ for (i = 0; i < len; i++)
+ {
+ sizex[i] = size1[i];
+ }
+ sizex[len] = 0;
+}
+
+/*****************************************************************************/
+/* returns non zero if it processed something */
+static int
+check_sck(void)
+{
+ fd_set rfds;
+ struct timeval tm;
+ int count;
+ int rv;
+
+ rv = 0;
+ if (g_block == 0)
+ {
+ g_block = 1;
+ /* see if there really is data */
+ FD_ZERO(&rfds);
+ FD_SET((unsigned int)g_tcp_sck, &rfds);
+ ZeroMemory(&tm, sizeof(tm));
+ count = select(g_tcp_sck + 1, &rfds, 0, 0, &tm);
+ if (count > 0)
+ {
+ if (ui_read_wire())
+ {
+ rv = 1;
+ }
+ else
+ {
+ PostQuitMessage(0);
+ }
+ }
+ g_block = 0;
+ }
+ return rv;
+}
+
+/*****************************************************************************/
+void
+mi_error(char * msg)
+{
+#ifdef WITH_DEBUG
+ printf(msg);
+#else /* WITH_DEBUG */
+ TCHAR lmsg[512];
+ TCHAR ltitle[512];
+
+ str_to_uni(lmsg, msg);
+ str_to_uni(ltitle, "Error");
+ MessageBox(g_Wnd, lmsg, ltitle, MB_OK);
+#endif /* WITH_DEBUG */
+}
+
+/*****************************************************************************/
+static int
+get_scan_code_from_ascii(int code)
+{
+ int rv;
+
+ rv = 0;
+ switch (code & 0xff)
+ {
+ case 0x30: rv = 0x0b; break; // 0
+ case 0x31: rv = 0x02; break; // 1
+ case 0x32: rv = 0x03; break; // 2
+ case 0x33: rv = 0x04; break; // 3
+ case 0x34: rv = 0x05; break; // 4
+ case 0x35: rv = 0x06; break; // 5
+ case 0x36: rv = 0x07; break; // 6
+ case 0x37: rv = 0x08; break; // 7
+ case 0x38: rv = 0x09; break; // 8
+ case 0x39: rv = 0x0a; break; // 9
+
+ case 0xbd: rv = 0x0c; break; // -
+ case 0xbb: rv = 0x0d; break; // =
+ case 0x08: rv = 0x0e; break; // backspace
+ case 0x09: rv = 0x0f; break; // tab
+ case 0xdb: rv = 0x1b; break; // ]
+ case 0xdd: rv = 0x1a; break; // [
+ case 0x14: rv = 0x3a; break; // capslock
+ case 0xba: rv = 0x27; break; // ;
+ case 0xde: rv = 0x28; break; // '
+ case 0x10: rv = 0x2a; break; // shift
+ case 0xbc: rv = 0x33; break; // ,
+ case 0xbe: rv = 0x34; break; // .
+ case 0xbf: rv = 0x35; break; // /
+ case 0x0d: rv = 0x1c; break; // enter
+ case 0x27: rv = 0x4d; break; // arrow right
+ case 0x25: rv = 0x4b; break; // arrow left
+ case 0x26: rv = 0x48; break; // arrow up
+ case 0x28: rv = 0x50; break; // arrow down
+ case 0x20: rv = 0x39; break; // space
+ case 0xdc: rv = 0x2b; break; // backslash
+ case 0xc0: rv = 0x29; break; // `
+ case 0x11: rv = 0x1d; break; // ctl
+
+ case 0x41: rv = 0x1e; break; // a
+ case 0x42: rv = 0x30; break; // b
+ case 0x43: rv = 0x2e; break; // c
+ case 0x44: rv = 0x20; break; // d
+ case 0x45: rv = 0x12; break; // e
+ case 0x46: rv = 0x21; break; // f
+ case 0x47: rv = 0x22; break; // g
+ case 0x48: rv = 0x23; break; // h
+ case 0x49: rv = 0x17; break; // i
+ case 0x4a: rv = 0x24; break; // j
+ case 0x4b: rv = 0x25; break; // k
+ case 0x4c: rv = 0x26; break; // l
+ case 0x4d: rv = 0x32; break; // m
+ case 0x4e: rv = 0x31; break; // n
+ case 0x4f: rv = 0x18; break; // o
+ case 0x50: rv = 0x19; break; // p
+ case 0x51: rv = 0x10; break; // q
+ case 0x52: rv = 0x13; break; // r
+ case 0x53: rv = 0x1f; break; // s
+ case 0x54: rv = 0x14; break; // t
+ case 0x55: rv = 0x16; break; // u
+ case 0x56: rv = 0x2f; break; // v
+ case 0x57: rv = 0x11; break; // w
+ case 0x58: rv = 0x2d; break; // x
+ case 0x59: rv = 0x15; break; // y
+ case 0x5a: rv = 0x2c; break; // z
+ }
+ return rv;
+}
+
+/*****************************************************************************/
+static void
+mi_scroll(int dx, int dy)
+{
+ HRGN rgn;
+
+ rgn = CreateRectRgn(0, 0, 0, 0);
+ ScrollWindowEx(g_Wnd, dx, dy, 0, 0, rgn, 0, SW_ERASE);
+ InvalidateRgn(g_Wnd, rgn, 0);
+ DeleteObject(rgn);
+}
+
+/*****************************************************************************/
+int
+mi_read_keyboard_state(void)
+{
+ short keydata;
+ int code;
+
+ code = 0;
+ keydata = GetKeyState(VK_SCROLL);
+ if (keydata & 0x0001)
+ {
+ code |= 1;
+ }
+ keydata = GetKeyState(VK_NUMLOCK);
+ if (keydata & 0x0001)
+ {
+ code |= 2;
+ }
+ keydata = GetKeyState(VK_CAPITAL);
+ if (keydata & 0x0001)
+ {
+ code |= 4;
+ }
+ return code;
+}
+
+/*****************************************************************************/
+static void
+mi_check_modifier(void)
+{
+ int code;
+
+ code = mi_read_keyboard_state();
+ ui_set_modifier_state(code);
+}
+
+/*****************************************************************************/
+static LRESULT
+handle_WM_SETCURSOR(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ if (g_mousex >= g_wnd_clip.left &&
+ g_mousey >= g_wnd_clip.top &&
+ g_mousex < g_wnd_clip.right &&
+ g_mousey < g_wnd_clip.bottom)
+ {
+ SetCursor(g_cursor);
+ }
+ /* need default behavoir here */
+ return DefWindowProc(hWnd, message, wParam, lParam);
+}
+
+/*****************************************************************************/
+static LRESULT
+handle_WM_NCHITTEST(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ POINT pt;
+
+ pt.x = LOWORD(lParam);
+ pt.y = HIWORD(lParam);
+ if (ScreenToClient(g_Wnd, &pt))
+ {
+ g_mousex = pt.x;
+ g_mousey = pt.y;
+ }
+ return DefWindowProc(hWnd, message, wParam, lParam);
+}
+
+/*****************************************************************************/
+static LRESULT
+handle_WM_MOUSEMOVE(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ g_mousex = LOWORD(lParam);
+ g_mousey = HIWORD(lParam);
+ ui_mouse_move(g_mousex + g_xscroll, g_mousey + g_yscroll);
+ return 0;
+}
+
+/*****************************************************************************/
+static LRESULT
+handle_WM_LBUTTONDOWN(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ g_mousex = LOWORD(lParam);
+ g_mousey = HIWORD(lParam);
+ ui_mouse_button(1, g_mousex + g_xscroll, g_mousey + g_yscroll, 1);
+ return 0;
+}
+
+/*****************************************************************************/
+static LRESULT
+handle_WM_LBUTTONUP(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ g_mousex = LOWORD(lParam);
+ g_mousey = HIWORD(lParam);
+ ui_mouse_button(1, g_mousex + g_xscroll, g_mousey + g_yscroll, 0);
+ return 0;
+}
+
+/*****************************************************************************/
+static LRESULT
+handle_WM_RBUTTONDOWN(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ g_mousex = LOWORD(lParam);
+ g_mousey = HIWORD(lParam);
+ ui_mouse_button(2, g_mousex + g_xscroll, g_mousey + g_yscroll, 1);
+ return 0;
+}
+
+/*****************************************************************************/
+static LRESULT
+handle_WM_RBUTTONUP(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ g_mousex = LOWORD(lParam);
+ g_mousey = HIWORD(lParam);
+ ui_mouse_button(2, g_mousex + g_xscroll, g_mousey + g_yscroll, 0);
+ return 0;
+}
+
+/*****************************************************************************/
+static LRESULT
+handle_WM_MBUTTONDOWN(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ g_mousex = LOWORD(lParam);
+ g_mousey = HIWORD(lParam);
+ ui_mouse_button(3, g_mousex + g_xscroll, g_mousey + g_yscroll, 1);
+ return 0;
+}
+
+/*****************************************************************************/
+static LRESULT
+handle_WM_MBUTTONUP(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ g_mousex = LOWORD(lParam);
+ g_mousey = HIWORD(lParam);
+ ui_mouse_button(3, g_mousex + g_xscroll, g_mousey + g_yscroll, 0);
+ return 0;
+}
+
+/*****************************************************************************/
+static LRESULT
+handle_WM_MOUSEWHEEL(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ int delta;
+
+ delta = ((signed short)HIWORD(wParam)); /* GET_WHEEL_DELTA_WPARAM(wParam); */
+ if (delta > 0)
+ {
+ ui_mouse_button(4, 0, 0, 1);
+ ui_mouse_button(4, 0, 0, 0);
+ }
+ else
+ {
+ ui_mouse_button(5, 0, 0, 1);
+ ui_mouse_button(5, 0, 0, 0);
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+static LRESULT
+handle_WM_KEY(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ int scancode;
+ int ext;
+ int down;
+
+ ext = HIWORD(lParam);
+ scancode = ext;
+ down = !(ext & 0x8000);
+ scancode &= 0xff;
+ if (scancode == 0)
+ {
+ scancode = get_scan_code_from_ascii(wParam);
+ }
+ ext &= 0x0100;
+ if (scancode == 0x0045) /* num lock */
+ {
+ ext &= ~0x0100;
+ }
+ if (down)
+ {
+ ui_key_down(scancode, ext);
+ }
+ else
+ {
+ ui_key_up(scancode, ext);
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+static LRESULT
+handle_WM_PAINT(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ PAINTSTRUCT ps;
+ RECT rect;
+ HBRUSH brush;
+
+ BeginPaint(hWnd, &ps);
+ /* paint the area outside the rdp screen with one colour */
+ rect = ps.rcPaint;
+ rect.left = UI_MAX(rect.left, g_width);
+ if (!IsRectEmpty(&rect))
+ {
+ brush = CreateSolidBrush(RGB(0, 0, 255));
+ FillRect(ps.hdc, &rect, brush);
+ DeleteObject(brush);
+ }
+ rect = ps.rcPaint;
+ rect.top = UI_MAX(rect.top, g_height);
+ if (!IsRectEmpty(&rect))
+ {
+ brush = CreateSolidBrush(RGB(0, 0, 255));
+ FillRect(ps.hdc, &rect, brush);
+ DeleteObject(brush);
+ }
+ rect = ps.rcPaint;
+ EndPaint(hWnd, &ps);
+ ui_invalidate(rect.left + g_xscroll,
+ rect.top + g_yscroll,
+ (rect.right - rect.left) + 1,
+ (rect.bottom - rect.top) + 1);
+ return 0;
+}
+
+/*****************************************************************************/
+static LRESULT
+handle_WM_SIZE(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ int oldxscroll;
+ int oldyscroll;
+
+ if (wParam == SIZE_MINIMIZED)
+ {
+ return DefWindowProc(hWnd, message, wParam, lParam);
+ }
+ g_wnd_cwidth = LOWORD(lParam); /* client width / height */
+ g_wnd_cheight = HIWORD(lParam);
+ g_wnd_clip.left = 0;
+ g_wnd_clip.top = 0;
+ g_wnd_clip.right = g_wnd_clip.left + g_wnd_cwidth;
+ g_wnd_clip.bottom = g_wnd_clip.top + g_wnd_cheight;
+ if (g_wnd_cwidth < g_width || g_wnd_cheight < g_height)
+ {
+ SetScrollRange(g_Wnd, SB_HORZ, 0, g_width - g_wnd_cwidth, 1);
+ SetScrollRange(g_Wnd, SB_VERT, 0, g_height - g_wnd_cheight, 1);
+ }
+ oldxscroll = g_xscroll;
+ oldyscroll = g_yscroll;
+ if (g_wnd_cwidth >= g_width)
+ {
+ g_xscroll = 0;
+ }
+ else
+ {
+ g_xscroll = UI_MIN(g_xscroll, g_width - g_wnd_cwidth);
+ }
+ if (g_wnd_cheight >= g_height)
+ {
+ g_yscroll = 0;
+ }
+ else
+ {
+ g_yscroll = UI_MIN(g_yscroll, g_height - g_wnd_cheight);
+ }
+ mi_scroll(oldxscroll - g_xscroll, oldyscroll - g_yscroll);
+ if (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED)
+ {
+ /* check the caps, num, and scroll lock here */
+ mi_check_modifier();
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+static LRESULT
+handle_WM_SIZING(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ LPRECT prect;
+ int width;
+ int height;
+ int style;
+
+ prect = (LPRECT) lParam; /* total window rect */
+ width = (prect->right - prect->left) - (g_xoff * 2);
+ height = (prect->bottom - prect->top) - (g_yoff + g_xoff);
+ if (height < g_height || width < g_width)
+ {
+ style = GetWindowLong(g_Wnd, GWL_STYLE);
+ if (!(style & WS_HSCROLL))
+ {
+ style |= WS_HSCROLL | WS_VSCROLL;
+ SetWindowLong(g_Wnd, GWL_STYLE, style);
+ g_xscroll = 0;
+ g_yscroll = 0;
+ SetScrollPos(g_Wnd, SB_HORZ, g_xscroll, 1);
+ SetScrollPos(g_Wnd, SB_VERT, g_yscroll, 1);
+ }
+ }
+ else if (height >= g_height && width >= g_width)
+ {
+ style = GetWindowLong(g_Wnd, GWL_STYLE);
+ if (style & WS_HSCROLL)
+ {
+ style &= ~WS_HSCROLL;
+ style &= ~WS_VSCROLL;
+ SetWindowLong(g_Wnd, GWL_STYLE, style);
+ g_xscroll = 0;
+ g_yscroll = 0;
+ }
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+static LRESULT
+handle_WM_HSCROLL(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ int code;
+ int oldxscroll;
+
+ code = (int) LOWORD(wParam); /* scroll bar value */
+ if (code == SB_LINELEFT)
+ {
+ oldxscroll = g_xscroll;
+ g_xscroll--;
+ g_xscroll = UI_MAX(g_xscroll, 0);
+ SetScrollPos(g_Wnd, SB_HORZ, g_xscroll, 1);
+ mi_scroll(oldxscroll - g_xscroll, 0);
+ }
+ else if (code == SB_LINERIGHT)
+ {
+ oldxscroll = g_xscroll;
+ g_xscroll++;
+ g_xscroll = UI_MIN(g_xscroll, g_width - g_wnd_cwidth);
+ SetScrollPos(g_Wnd, SB_HORZ, g_xscroll, 1);
+ mi_scroll(oldxscroll - g_xscroll, 0);
+ }
+ else if (code == SB_PAGELEFT)
+ {
+ oldxscroll = g_xscroll;
+ g_xscroll -= g_wnd_cwidth / 2;
+ g_xscroll = UI_MAX(g_xscroll, 0);
+ SetScrollPos(g_Wnd, SB_HORZ, g_xscroll, 1);
+ mi_scroll(oldxscroll - g_xscroll, 0);
+ }
+ else if (code == SB_PAGERIGHT)
+ {
+ oldxscroll = g_xscroll;
+ g_xscroll += g_wnd_cwidth / 2;
+ g_xscroll = UI_MIN(g_xscroll, g_width - g_wnd_cwidth);
+ SetScrollPos(g_Wnd, SB_HORZ, g_xscroll, 1);
+ mi_scroll(oldxscroll - g_xscroll, 0);
+ }
+ else if (code == SB_BOTTOM)
+ {
+ oldxscroll = g_xscroll;
+ g_xscroll = g_width - g_wnd_cwidth;
+ SetScrollPos(g_Wnd, SB_HORZ, g_xscroll, 1);
+ mi_scroll(oldxscroll - g_xscroll, 0);
+ }
+ else if (code == SB_TOP)
+ {
+ oldxscroll = g_xscroll;
+ g_xscroll = 0;
+ SetScrollPos(g_Wnd, SB_HORZ, g_xscroll, 1);
+ mi_scroll(oldxscroll - g_xscroll, 0);
+ }
+ else if (code == SB_THUMBPOSITION)
+ {
+ oldxscroll = g_xscroll;
+ g_xscroll = (signed short) HIWORD(wParam);
+ SetScrollPos(g_Wnd, SB_HORZ, g_xscroll, 1);
+ mi_scroll(oldxscroll - g_xscroll, 0);
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+static LRESULT
+handle_WM_VSCROLL(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ int code;
+ int oldyscroll;
+
+ code = (int) LOWORD(wParam); /* scroll bar value */
+ if (code == SB_LINELEFT)
+ {
+ oldyscroll = g_yscroll;
+ g_yscroll--;
+ g_yscroll = UI_MAX(g_yscroll, 0);
+ SetScrollPos(g_Wnd, SB_VERT, g_yscroll, 1);
+ mi_scroll(0, oldyscroll - g_yscroll);
+ }
+ else if (code == SB_LINERIGHT)
+ {
+ oldyscroll = g_yscroll;
+ g_yscroll++;
+ g_yscroll = UI_MIN(g_yscroll, g_height - g_wnd_cheight);
+ SetScrollPos(g_Wnd, SB_VERT, g_yscroll, 1);
+ mi_scroll(0, oldyscroll - g_yscroll);
+ }
+ else if (code == SB_PAGELEFT)
+ {
+ oldyscroll = g_yscroll;
+ g_yscroll -= g_wnd_cheight / 2;
+ g_yscroll = UI_MAX(g_yscroll, 0);
+ SetScrollPos(g_Wnd, SB_VERT, g_yscroll, 1);
+ mi_scroll(0, oldyscroll - g_yscroll);
+ }
+ else if (code == SB_PAGERIGHT)
+ {
+ oldyscroll = g_yscroll;
+ g_yscroll += g_wnd_cheight / 2;
+ g_yscroll = UI_MIN(g_yscroll, g_height - g_wnd_cheight);
+ SetScrollPos(g_Wnd, SB_VERT, g_yscroll, 1);
+ mi_scroll(0, oldyscroll - g_yscroll);
+ }
+ else if (code == SB_BOTTOM)
+ {
+ oldyscroll = g_yscroll;
+ g_yscroll = g_height - g_wnd_cheight;
+ SetScrollPos(g_Wnd, SB_VERT, g_yscroll, 1);
+ mi_scroll(0, oldyscroll - g_yscroll);
+ }
+ else if (code == SB_TOP)
+ {
+ oldyscroll = g_yscroll;
+ g_yscroll = 0;
+ SetScrollPos(g_Wnd, SB_VERT, g_yscroll, 1);
+ mi_scroll(0, oldyscroll - g_yscroll);
+ }
+ else if (code == SB_THUMBPOSITION)
+ {
+ oldyscroll = g_yscroll;
+ g_yscroll = (signed short) HIWORD(wParam);
+ SetScrollPos(g_Wnd, SB_VERT, g_yscroll, 1);
+ mi_scroll(0, oldyscroll - g_yscroll);
+ }
+ return 0;
+}
+
+#ifdef MYWINCE
+/*****************************************************************************/
+static LRESULT
+handle_WM_SETTINGCHANGE(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ SIPINFO si;
+ SHMENUBARINFO mb;
+ int x;
+ int y;
+ int w;
+ int h;
+ int style;
+
+ ZeroMemory(&si, sizeof(SIPINFO));
+ si.cbSize = sizeof(SIPINFO);
+ SHSipInfo(SPI_GETSIPINFO, lParam, &si, 0);
+ x = si.rcVisibleDesktop.left;
+ y = si.rcVisibleDesktop.top;
+ w = si.rcVisibleDesktop.right - x;
+ h = si.rcVisibleDesktop.bottom - y;
+ /* get rid of menu */
+ DestroyWindow(SHFindMenuBar(g_Wnd));
+ if (si.fdwFlags & SIPF_ON)
+ {
+ g_sip_up = 1; /* used for WM_SETFOCUS */
+ ZeroMemory(&mb, sizeof(SHMENUBARINFO));
+ mb.cbSize = sizeof(SHMENUBARINFO);
+ mb.hwndParent = g_Wnd;
+ mb.dwFlags = SHCMBF_EMPTYBAR;
+ SHCreateMenuBar(&mb);
+ MoveWindow(g_Wnd, x, y, w, h, FALSE);
+ SHFullScreen(g_Wnd, SHFS_SHOWTASKBAR | SHFS_SHOWSIPBUTTON |
+ SHFS_SHOWSTARTICON);
+ }
+ else
+ {
+ g_sip_up = 0;
+ if (g_fullscreen)
+ {
+ MoveWindow(g_Wnd, 0, 0, g_screen_width, g_screen_height, FALSE);
+ }
+ else
+ {
+ MoveWindow(g_Wnd, x, y, w, h, FALSE);
+ }
+ if ((g_fullscreen && g_width <= g_screen_width &&
+ g_height <= g_screen_height) ||
+ (!g_fullscreen && g_width <= w && g_height <= h))
+ {
+ style = GetWindowLong(g_Wnd, GWL_STYLE);
+ if (style & WS_HSCROLL)
+ {
+ style &= ~WS_HSCROLL;
+ style &= ~WS_VSCROLL;
+ SetWindowLong(g_Wnd, GWL_STYLE, style);
+ g_xscroll = 0;
+ g_yscroll = 0;
+ }
+ }
+ if (g_fullscreen)
+ {
+ SHFullScreen(g_Wnd, SHFS_HIDETASKBAR | SHFS_SHOWSIPBUTTON |
+ SHFS_SHOWSTARTICON);
+ }
+ else
+ {
+ SHFullScreen(g_Wnd, SHFS_SHOWTASKBAR | SHFS_SHOWSIPBUTTON |
+ SHFS_SHOWSTARTICON);
+ }
+ }
+ return 0;
+}
+#endif /* MYWINCE */
+
+/*****************************************************************************/
+LRESULT CALLBACK
+WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message)
+ {
+ case WM_SETCURSOR:
+ return handle_WM_SETCURSOR(hWnd, message, wParam, lParam);
+ case 0x0084: /* WinCE don't have this WM_NCHITTEST: */
+ return handle_WM_NCHITTEST(hWnd, message, wParam, lParam);
+ case WM_MOUSEMOVE:
+ return handle_WM_MOUSEMOVE(hWnd, message, wParam, lParam);
+ case WM_LBUTTONDOWN:
+ return handle_WM_LBUTTONDOWN(hWnd, message, wParam, lParam);
+ case WM_LBUTTONUP:
+ return handle_WM_LBUTTONUP(hWnd, message, wParam, lParam);
+ case WM_RBUTTONDOWN:
+ return handle_WM_RBUTTONDOWN(hWnd, message, wParam, lParam);
+ case WM_RBUTTONUP:
+ return handle_WM_RBUTTONUP(hWnd, message, wParam, lParam);
+ case WM_MBUTTONDOWN:
+ return handle_WM_MBUTTONDOWN(hWnd, message, wParam, lParam);
+ case WM_MBUTTONUP:
+ return handle_WM_MBUTTONUP(hWnd, message, wParam, lParam);
+ /* some windows compilers don't have these defined like vc6 */
+ case 0x020a: /* WM_MOUSEWHEEL: */
+ return handle_WM_MOUSEWHEEL(hWnd, message, wParam, lParam);
+ case WM_KEYDOWN:
+ case WM_KEYUP:
+ case WM_SYSKEYDOWN:
+ case WM_SYSKEYUP:
+ return handle_WM_KEY(hWnd, message, wParam, lParam);
+ case WM_CHAR:
+ case WM_DEADCHAR:
+ case WM_SYSCHAR:
+ case WM_SYSDEADCHAR:
+ break;
+ case WM_PAINT:
+ return handle_WM_PAINT(hWnd, message, wParam, lParam);
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ break;
+ case WM_APP + 1:
+ case WM_TIMER:
+ check_sck();
+ break;
+ case WM_SIZE:
+ return handle_WM_SIZE(hWnd, message, wParam, lParam);
+ case 532: /* not defined in wince WM_SIZING: */
+ return handle_WM_SIZING(hWnd, message, wParam, lParam);
+ case WM_HSCROLL:
+ return handle_WM_HSCROLL(hWnd, message, wParam, lParam);
+ case WM_VSCROLL:
+ return handle_WM_VSCROLL(hWnd, message, wParam, lParam);
+#ifdef MYWINCE
+ case WM_SETTINGCHANGE:
+ return handle_WM_SETTINGCHANGE(hWnd, message, wParam, lParam);
+#endif /* MYWINCE */
+ case WM_SETFOCUS:
+ mi_check_modifier();
+#ifdef MYWINCE
+ if (g_sip_up)
+ {
+ SHSipPreference(hWnd, SIP_UP);
+ }
+#endif
+ return DefWindowProc(hWnd, message, wParam, lParam);
+ default:
+ return DefWindowProc(hWnd, message, wParam, lParam);
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+static HRGN
+mi_clip(HDC dc)
+{
+ HRGN rgn;
+
+ rgn = CreateRectRgn(g_clip_left + g_xoff - g_xscroll,
+ g_clip_top + g_yoff - g_yscroll,
+ g_clip_right + g_xoff - g_xscroll,
+ g_clip_bottom + g_yoff - g_yscroll);
+ SelectClipRgn(dc, rgn);
+ IntersectClipRect(dc, g_wnd_clip.left + g_xoff, g_wnd_clip.top + g_yoff,
+ g_wnd_clip.right + g_xoff, g_wnd_clip.bottom + g_yoff);
+ return rgn;
+}
+
+/*****************************************************************************/
+static void
+mi_show_error(char * caption)
+{
+ LPVOID lpMsgBuf;
+ TCHAR lcaption[512];
+
+ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &lpMsgBuf, 0, NULL);
+#ifdef WITH_DEBUG
+ printf(lpMsgBuf);
+#else /* WITH_DEBUG */
+ str_to_uni(lcaption, caption);
+ MessageBox(g_Wnd, (LPTSTR) lpMsgBuf, lcaption,
+ MB_OK | MB_ICONINFORMATION);
+#endif /* WITH_DEBUG */
+ LocalFree(lpMsgBuf);
+}
+
+/*****************************************************************************/
+void
+mi_invalidate(int x, int y, int cx, int cy)
+{
+ HDC dc;
+ HDC maindc;
+ HGDIOBJ save;
+ HRGN rgn;
+ int dstx;
+ int dsty;
+
+ maindc = GetWindowDC(g_Wnd);
+ dc = CreateCompatibleDC(maindc);
+ if (dc == 0)
+ {
+ mi_show_error("CreateCompatibleDC failed in mi_invalidate");
+ }
+ save = SelectObject(dc, g_bs_bitmap);
+ dstx = (x + g_xoff) - g_xscroll;
+ dsty = (y + g_yoff) - g_yscroll;
+ rgn = mi_clip(maindc);
+ BitBlt(maindc, dstx, dsty, cx, cy, dc, x, y, SRCCOPY);
+ SelectObject(dc, save);
+ DeleteDC(dc);
+ ReleaseDC(g_Wnd, maindc);
+ DeleteObject(rgn);
+}
+
+/*****************************************************************************/
+int
+mi_create_bs(void)
+{
+ HBITMAP bitmap;
+ BITMAPINFO bi;
+ HDC maindc;
+
+ ZeroMemory(&bi, sizeof(bi));
+ bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
+ bi.bmiHeader.biWidth = g_width;
+ bi.bmiHeader.biHeight = -g_height;
+ bi.bmiHeader.biPlanes = 1;
+ bi.bmiHeader.biBitCount = 32;
+ bi.bmiHeader.biCompression = BI_RGB;
+ maindc = GetWindowDC(g_Wnd);
+ g_bs_bitmap = CreateDIBSection(maindc, &bi, DIB_RGB_COLORS, (void **) &g_bs, 0, 0);
+ ReleaseDC(g_Wnd, maindc);
+ g_bs_bpp = 32;
+ g_bs_Bpp = 4;
+ if (g_bs_bitmap != 0)
+ {
+ //FillMemory(g_bs, g_width * g_height * 4, 0xff);
+ ZeroMemory(g_bs, g_width * g_height * 4);
+ UpdateWindow(g_Wnd);
+ return 1;
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+/* returns non zero if ok */
+int
+mi_create_window(void)
+{
+ RECT rc;
+ WNDCLASS wc;
+ TCHAR classname[512];
+ TCHAR caption[512];
+ DWORD style;
+ int x;
+ int y;
+ int w;
+ int h;
+
+ if (g_Wnd != 0 || g_Instance != 0)
+ {
+ return 0;
+ }
+ g_Instance = GetModuleHandle(NULL);
+ ZeroMemory(&wc, sizeof(wc));
+ wc.lpfnWndProc = WndProc; /* points to window procedure */
+ /* name of window class */
+ str_to_uni(classname, "rdesktop");
+ wc.lpszClassName = classname;
+ str_to_uni(caption, "WinRDesktop");
+ /* Register the window class. */
+ if (!RegisterClass(&wc))
+ {
+ return 0; /* Failed to register window class */
+ }
+ rc.left = 0;
+ rc.right = rc.left + UI_MIN(g_width, g_screen_width);
+ rc.top = 0;
+ rc.bottom = rc.top + UI_MIN(g_height, g_screen_height);
+#ifdef MYWINCE
+ SHInitExtraControls();
+ x = CW_USEDEFAULT;
+ y = CW_USEDEFAULT;
+ w = CW_USEDEFAULT;
+ h = CW_USEDEFAULT;
+ style = WS_VISIBLE;
+ if (g_fullscreen)
+ {
+ x = 0;
+ y = 0;
+ w = g_screen_width;
+ h = g_screen_height;
+ }
+#else /* MYWINCE */
+ if (g_fullscreen)
+ {
+ style = WS_POPUP;
+ }
+ else
+ {
+ style = WS_OVERLAPPED | WS_CAPTION | WS_POPUP | WS_MINIMIZEBOX |
+ WS_SYSMENU | WS_SIZEBOX | WS_MAXIMIZEBOX;
+ }
+ if (g_screen_width < g_width || g_screen_height < g_height)
+ {
+ style |= WS_HSCROLL | WS_VSCROLL;
+ }
+ AdjustWindowRectEx(&rc, style, 0, 0);
+ x = CW_USEDEFAULT;
+ y = CW_USEDEFAULT;
+ w = rc.right - rc.left;
+ h = rc.bottom - rc.top;
+#endif /* MYWINCE */
+ g_Wnd = CreateWindow(wc.lpszClassName, caption,
+ style, x, y, w, h,
+ (HWND) NULL, (HMENU) NULL, g_Instance,
+ (LPVOID) NULL);
+ g_clip_left = 0;
+ g_clip_top = 0;
+ g_clip_right = g_clip_left + g_width;
+ g_clip_bottom = g_clip_top + g_height;
+ if (g_workarea)
+ {
+ ShowWindow(g_Wnd, SW_SHOWMAXIMIZED);
+ }
+ else
+ {
+ ShowWindow(g_Wnd, SW_SHOWNORMAL);
+ }
+
+#ifdef MYWINCE
+ if (g_fullscreen)
+ {
+ SHFullScreen(g_Wnd, SHFS_HIDETASKBAR | SHFS_SHOWSIPBUTTON |
+ SHFS_SHOWSTARTICON);
+ }
+ else
+ {
+ SHFullScreen(g_Wnd, SHFS_SHOWTASKBAR | SHFS_SHOWSIPBUTTON |
+ SHFS_SHOWSTARTICON);
+ }
+#endif /* MYWINCE */
+
+ /* WinCE doesn't have WSAAsyncSelect */
+#ifdef MYWINCE
+ SetTimer(g_Wnd, 1, 1000 / 60, 0); /* 60 per second */
+#else /* MYWINCE */
+ WSAAsyncSelect(g_tcp_sck, g_Wnd, WM_APP + 1, FD_READ);
+ SetTimer(g_Wnd, 1, 333, 0);
+#endif /* MYWINCE */
+ return 1;
+}
+
+/*****************************************************************************/
+int
+mi_main_loop(void)
+{
+ MSG msg;
+
+ while (GetMessage(&msg, NULL, 0, 0))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ return msg.wParam;
+}
+
+/*****************************************************************************/
+void
+mi_warning(char * msg)
+{
+}
+
+/*****************************************************************************/
+void
+mi_paint_rect(char * data, int width, int height, int x, int y, int cx, int cy)
+{
+ HBITMAP bitmap;
+ BITMAPINFO bi;
+ HDC dc;
+ HDC maindc;
+ HGDIOBJ save;
+ HRGN rgn;
+ void * bits;
+ int i;
+ int j;
+ int colour;
+ int red;
+ int green;
+ int blue;
+
+ ZeroMemory(&bi, sizeof(bi));
+ bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
+ bi.bmiHeader.biWidth = width;
+ bi.bmiHeader.biHeight = -height;
+ bi.bmiHeader.biPlanes = 1;
+ bi.bmiHeader.biBitCount = 32;
+ bi.bmiHeader.biCompression = BI_RGB;
+ maindc = GetWindowDC(g_Wnd);
+ bitmap = CreateDIBSection(maindc, &bi, DIB_RGB_COLORS, (void **) &bits, 0, 0);
+ if (bitmap == 0)
+ {
+ mi_show_error("CreateDIBSection failed");
+ }
+
+ if (g_server_depth == 8)
+ {
+ for (i = cy - 1; i >= 0; i--)
+ {
+ for (j = cx - 1; j >= 0; j--)
+ {
+ colour = ((unsigned char*)data)[i * cx + j];
+ red = (pal_entries[colour & 0xff] & 0xff0000) >> 16;
+ green = (pal_entries[colour & 0xff] & 0xff00) >> 8;
+ blue = pal_entries[colour & 0xff] & 0xff;
+ MAKE_COLOUR32(colour, red, green, blue);
+ ((unsigned int*)bits)[i * cx + j] = colour;
+ }
+ }
+ }
+ else if (g_server_depth == 15)
+ {
+ for (i = cy - 1; i >= 0; i--)
+ {
+ for (j = cx - 1; j >= 0; j--)
+ {
+ colour = ((unsigned short*)data)[i * cx + j];
+ SPLIT_COLOUR15(colour, red, green, blue);
+ MAKE_COLOUR32(colour, red, green, blue);
+ ((unsigned int*)bits)[i * cx + j] = colour;
+ }
+ }
+ }
+ else if (g_server_depth == 16)
+ {
+ for (i = cy - 1; i >= 0; i--)
+ {
+ for (j = cx - 1; j >= 0; j--)
+ {
+ colour = ((unsigned short*)data)[i * cx + j];
+ SPLIT_COLOUR16(colour, red, green, blue);
+ MAKE_COLOUR32(colour, red, green, blue);
+ ((unsigned int*)bits)[i * cx + j] = colour;
+ }
+ }
+ }
+ dc = CreateCompatibleDC(maindc);
+ if (dc == 0)
+ {
+ mi_show_error("CreateCompatibleDC failed");
+ }
+ save = SelectObject(dc, bitmap);
+ rgn = mi_clip(maindc);
+ BitBlt(maindc, x + g_xoff - g_xscroll, y + g_yoff - g_yscroll, cx, cy, dc,
+ 0, 0, SRCCOPY);
+ SelectObject(dc, save);
+ DeleteObject(bitmap);
+ DeleteDC(dc);
+ ReleaseDC(g_Wnd, maindc);
+ DeleteObject(rgn);
+
+}
+
+/*****************************************************************************/
+static int
+mi_process_a_param(char * param1, int state)
+{
+ char * p;
+
+ if (state == 0)
+ {
+ if (strcmp(param1, "-g") == 0 || strcmp(param1, "geometry") == 0)
+ {
+ state = 1;
+ }
+ if (strcmp(param1, "-t") == 0 || strcmp(param1, "port") == 0)
+ {
+ state = 2;
+ }
+ if (strcmp(param1, "-a") == 0 || strcmp(param1, "bpp") == 0)
+ {
+ state = 3;
+ }
+ if (strcmp(param1, "-f") == 0 || strcmp(param1, "fullscreen") == 0)
+ {
+ g_fullscreen = 1;
+ }
+ if (strcmp(param1, "-u") == 0 || strcmp(param1, "username") == 0)
+ {
+ state = 5;
+ }
+ if (strcmp(param1, "-p") == 0 || strcmp(param1, "password") == 0)
+ {
+ state = 6;
+ }
+ if (strcmp(param1, "-d") == 0 || strcmp(param1, "domain") == 0)
+ {
+ state = 7;
+ }
+ if (strcmp(param1, "-s") == 0 || strcmp(param1, "shell") == 0)
+ {
+ state = 8;
+ }
+ if (strcmp(param1, "-c") == 0 || strcmp(param1, "directory") == 0)
+ {
+ state = 9;
+ }
+ if (strcmp(param1, "-n") == 0 || strcmp(param1, "hostname") == 0)
+ {
+ state = 10;
+ }
+ }
+ else
+ {
+ if (state == 1) /* -g */
+ {
+ state = 0;
+ if (strcmp(param1, "workarea") == 0)
+ {
+ g_workarea = 1;
+ return state;
+ }
+ g_width = strtol(param1, &p, 10);
+ if (g_width <= 0)
+ {
+ mi_error("invalid geometry\r\n");
+ }
+ if (*p == 'x')
+ {
+ g_height = strtol(p + 1, &p, 10);
+ }
+ if (g_height <= 0)
+ {
+ mi_error("invalid geometry\r\n");
+ }
+ g_width_height_set = 1;
+ }
+ if (state == 2) /* -t */
+ {
+ state = 0;
+ g_tcp_port_rdp = atol(param1);
+ }
+ if (state == 3) /* -a */
+ {
+ state = 0;
+ g_server_depth = atol(param1);
+ if (g_server_depth != 8 && g_server_depth != 15 &&
+ g_server_depth != 16 && g_server_depth != 24)
+ {
+ mi_error("invalid server bpp\r\n");
+ }
+ }
+ if (state == 5) /* -u */
+ {
+ state = 0;
+ strcpy(g_username, param1);
+ }
+ if (state == 6) /* -p */
+ {
+ state = 0;
+ strcpy(g_password, param1);
+ }
+ if (state == 7) /* -d */
+ {
+ state = 0;
+ strcpy(g_domain, param1);
+ }
+ if (state == 8) /* -s */
+ {
+ state = 0;
+ strcpy(g_shell, param1);
+ }
+ if (state == 9) /* -c */
+ {
+ state = 0;
+ strcpy(g_directory, param1);
+ }
+ if (state == 10) /* -n */
+ {
+ state = 0;
+ strcpy(g_hostname, param1);
+ }
+ }
+ return state;
+}
+
+/*****************************************************************************/
+static int
+mi_post_param(void)
+{
+ /* after parameters */
+ if (g_fullscreen)
+ {
+ g_xoff = 0;
+ g_yoff = 0;
+ if (!g_width_height_set)
+ {
+ g_width = g_screen_width;
+ g_height = g_screen_height;
+ }
+ }
+ else if (g_workarea)
+ {
+#ifdef MYWINCE
+ g_xoff = 0;
+ g_yoff = 0;
+ g_width = g_screen_width;
+ g_height = g_screen_height - 26; /* start menu size is 26 */
+#else /* MYWINCE */
+ g_xoff = GetSystemMetrics(SM_CXEDGE) * 2;
+ g_yoff = GetSystemMetrics(SM_CYCAPTION) +
+ GetSystemMetrics(SM_CYEDGE) * 2;
+ g_width = g_screen_width;
+ g_height = g_screen_height;
+ g_height = (g_height - g_yoff) - g_xoff - 20; /* todo */
+#endif /* MYWINCE */
+ g_width_height_set = 1;
+ }
+ else
+ {
+#ifdef MYWINCE
+ g_xoff = 0;
+ g_yoff = 0;
+#else /* MYWINCE */
+ g_xoff = GetSystemMetrics(SM_CXEDGE) * 2;
+ g_yoff = GetSystemMetrics(SM_CYCAPTION) +
+ GetSystemMetrics(SM_CYEDGE) * 2;
+#endif /* MYWINCE */
+ }
+ g_width = g_width & (~3);
+ return 1;
+}
+
+/*****************************************************************************/
+static int
+mi_check_config_file(void)
+{
+ HANDLE fd;
+ DWORD count;
+ TCHAR filename[256];
+ char buffer[256];
+ char vname[256];
+ char value[256];
+ int index;
+ int mode;
+ int vnameindex;
+ int valueindex;
+ int state;
+ int rv;
+
+ rv = 0;
+ mode = 0;
+ vnameindex = 0;
+ valueindex = 0;
+ vname[vnameindex] = 0;
+ value[valueindex] = 0;
+#ifdef MYWINCE
+ str_to_uni(filename, "\\My Documents\\winrdesktop.ini");
+#else /* MYWINCE */
+ str_to_uni(filename, ".\\winrdesktop.ini");
+#endif /* MYWINCE */
+ fd = CreateFile(filename, GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ count = 255;
+ while (ReadFile(fd, buffer, count, &count, NULL))
+ {
+ if (count == 0)
+ {
+ break;
+ }
+ buffer[count] = 0;
+ index = 0;
+ while (index < (int) count)
+ {
+ if (buffer[index] == '=')
+ {
+ mode = 1;
+ }
+ else if (buffer[index] == 10 || buffer[index] == 13)
+ {
+ mode = 0;
+ vname[vnameindex] = 0;
+ value[valueindex] = 0;
+ if (strlen(vname) > 0 || strlen(value) > 0)
+ {
+ if (strcmp(vname, "server") == 0)
+ {
+ strcpy(g_servername, value);
+ rv = 1;
+ }
+ else
+ {
+ state = mi_process_a_param(vname, 0);
+ mi_process_a_param(value, state);
+ }
+ }
+ vnameindex = 0;
+ valueindex = 0;
+ }
+ else if (mode == 0)
+ {
+ vname[vnameindex] = buffer[index];
+ vnameindex++;
+ }
+ else
+ {
+ value[valueindex] = buffer[index];
+ valueindex++;
+ }
+ index++;
+ }
+ count = 255;
+ }
+ CloseHandle(fd);
+ if (rv)
+ {
+ mi_post_param();
+ }
+ return rv;
+}
+
+/*****************************************************************************/
+/* process the command line parameters */
+/* returns boolean, non zero is ok */
+static int
+mi_process_cl(LPTSTR lpCmdLine)
+{
+ char param[256];
+ char param1[256];
+#ifndef MYWINCE
+ TCHAR l_username[256];
+#endif
+ DWORD size;
+ int len;
+ int i;
+ int i1;
+ int state;
+
+ strcpy(g_hostname, "test");
+ strcpy(g_username, "pda");
+ /* get username and convert it from unicode */
+ size = 255;
+#ifndef MYWINCE
+ /* WinCE doesn't have GetUserName */
+ if (GetUserName(l_username, &size))
+ {
+ for (i = size; i >= 0; i--)
+ {
+ g_username[i] = (char) l_username[i];
+ }
+ g_username[size] = 0;
+ }
+ else
+ {
+ mi_show_error("GetUserName");
+ }
+#endif /* MYWINCE */
+ /* get computer name */
+ if (gethostname(g_hostname, 255) != 0)
+ {
+ mi_show_error("gethostname");
+ }
+ /* defaults */
+ strcpy(g_servername, "127.0.0.1");
+ g_server_depth = 8;
+ g_screen_width = GetSystemMetrics(SM_CXSCREEN);
+ g_screen_height = GetSystemMetrics(SM_CYSCREEN);
+ /* process parameters */
+ i1 = 0;
+ state = 0;
+ len = lstrlen(lpCmdLine);
+ if (len == 0)
+ {
+ return mi_check_config_file();
+ }
+ for (i = 0; i < len; i++)
+ {
+ if (lpCmdLine[i] != 32 && lpCmdLine[i] != 9) /* space or tab */
+ {
+ param[i1] = (char) lpCmdLine[i];
+ i1++;
+ }
+ else
+ {
+ param[i1] = 0;
+ i1 = 0;
+ strcpy(param1, param);
+ state = mi_process_a_param(param1, state);
+ strcpy(g_servername, param1);
+ }
+ }
+ if (i1 > 0)
+ {
+ param[i1] = 0;
+ strcpy(param1, param);
+ state = mi_process_a_param(param1, state);
+ strcpy(g_servername, param1);
+ }
+ if (state == 0)
+ {
+ mi_post_param();
+ }
+ return (state == 0);
+}
+
+/*****************************************************************************/
+/* display the command line options available */
+static void
+mi_show_params(void)
+{
+ char text1[512 * 4];
+ TCHAR textx[512 * 4];
+ TCHAR lcaption[64];
+
+ strcpy(text1, "");
+ strcat(text1, "WinRDesktop - an RDP client based on rdesktop\r\n");
+ strcat(text1, "You can't run this application without " );
+ strcat(text1, "correct parameters\r\n");
+ strcat(text1, "\r\n");
+ strcat(text1, "command line options\r\n");
+ strcat(text1, "\r\n");
+ strcat(text1, "WinRDesktop [-g widthxheight] [-t port] [-a bpp]\r\n");
+ strcat(text1, " [-f] [-u username] [-p password] [-d domain]\r\n");
+ strcat(text1, " [-s shell] [-c working directory] [-n host name]\r\n");
+ strcat(text1, " server-name-or-ip\r\n");
+ strcat(text1, "\r\n");
+ strcat(text1, "You can use a config file in the current directory\r\n");
+ strcat(text1, "called WinRDesktop.ini\r\n");
+ strcat(text1, "The file should look like this...\r\n");
+ strcat(text1, "[main]\r\n");
+ strcat(text1, "server=192.168.1.1\r\n");
+ strcat(text1, "port=3389\r\n");
+ strcat(text1, "username=user1\r\n");
+ strcat(text1, "password=password1\r\n");
+ strcat(text1, "bpp=16\r\n");
+ strcat(text1, "geometry=800x600\r\n");
+#ifdef WITH_DEBUG
+ printf(text1);
+#else /* WITH_DEBUG */
+ str_to_uni(lcaption, "WinRDesktop");
+ str_to_uni(textx, text1);
+ MessageBox(g_Wnd, textx, lcaption, MB_OK);
+#endif /* WITH_DEBUG */
+}
+
+#ifdef WITH_DEBUG
+/*****************************************************************************/
+int
+main(int argc, char ** argv)
+{
+ WSADATA d;
+
+ WSAStartup(MAKEWORD(2, 0), &d);
+ if (!mi_process_cl(argv[0]))
+ {
+ mi_show_params();
+ WSACleanup();
+ return 0;
+ }
+ return ui_main();
+}
+#else /* WITH_DEBUG */
+/*****************************************************************************/
+int WINAPI
+WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
+ LPTSTR lpCmdLine, int nCmdShow)
+{
+ WSADATA d;
+
+ WSAStartup(MAKEWORD(2, 0), &d);
+ if (!mi_process_cl(lpCmdLine))
+ {
+ mi_show_params();
+ WSACleanup();
+ return 0;
+ }
+ return ui_main();
+}
+#endif /* WITH_DEBUG */
+
+/*****************************************************************************/
+void
+mi_begin_update(void)
+{
+}
+
+/*****************************************************************************/
+void
+mi_end_update(void)
+{
+}
+
+/*****************************************************************************/
+void
+mi_fill_rect(int x, int y, int cx, int cy, int colour)
+{
+ HBRUSH brush;
+ RECT rect;
+ HDC maindc;
+ HRGN rgn;
+ int red;
+ int green;
+ int blue;
+
+ red = (colour & 0xff0000) >> 16;
+ green = (colour & 0xff00) >> 8;
+ blue = colour & 0xff;
+ maindc = GetWindowDC(g_Wnd);
+ rgn = mi_clip(maindc);
+ brush = CreateSolidBrush(RGB(red, green, blue));
+ rect.left = x + g_xoff - g_xscroll;
+ rect.top = y + g_yoff - g_yscroll;
+ rect.right = rect.left + cx;
+ rect.bottom = rect.top + cy;
+ FillRect(maindc, &rect, brush);
+ DeleteObject(brush);
+ ReleaseDC(g_Wnd, maindc);
+ DeleteObject(rgn);
+}
+
+/*****************************************************************************/
+void
+mi_line(int x1, int y1, int x2, int y2, int colour)
+{
+ HPEN pen;
+ HDC maindc;
+ HGDIOBJ save;
+ HRGN rgn;
+ int red;
+ int green;
+ int blue;
+
+ red = (colour & 0xff0000) >> 16;
+ green = (colour & 0xff00) >> 8;
+ blue = colour & 0xff;
+ maindc = GetWindowDC(g_Wnd);
+ rgn = mi_clip(maindc);
+ pen = CreatePen(PS_SOLID, 0, RGB(red, green, blue));
+ save = SelectObject(maindc, pen);
+ MoveToEx(maindc, x1 + g_xoff - g_xscroll, y1 + g_yoff - g_yscroll, 0);
+ LineTo(maindc, x2 + g_xoff - g_xscroll, y2 + g_yoff - g_yscroll);
+ SelectObject(maindc, save);
+ DeleteObject(pen);
+ ReleaseDC(g_Wnd, maindc);
+ DeleteObject(rgn);
+}
+
+/*****************************************************************************/
+void
+mi_screen_copy(int x, int y, int cx, int cy, int srcx, int srcy)
+{
+ RECT rect;
+ RECT clip_rect;
+ RECT draw_rect;
+ HRGN rgn;
+ int ok_to_ScrollWindowEx;
+
+ /* WinCE can't scroll in 2 directions at once */
+#ifdef MYWINCE
+ ok_to_ScrollWindowEx = cx == 0 || cy == 0;
+#else /* MYWINCE */
+ ok_to_ScrollWindowEx = 1;
+#endif /* MYWINCE */
+ if (!ok_to_ScrollWindowEx)
+ {
+ rgn = CreateRectRgn(x - g_xscroll, y - g_yscroll,
+ (x - g_xscroll) + cx,
+ (y - g_yscroll) + cy);
+ InvalidateRgn(g_Wnd, rgn, 0);
+ DeleteObject(rgn);
+ }
+ else
+ {
+ /* this is all in client coords */
+ rect.left = srcx - g_xscroll;
+ rect.top = srcy - g_yscroll;
+ rect.right = rect.left + cx;
+ rect.bottom = rect.top + cy;
+ clip_rect.left = g_clip_left - g_xscroll;
+ clip_rect.top = g_clip_top - g_yscroll;
+ clip_rect.right = g_clip_right - g_xscroll;
+ clip_rect.bottom = g_clip_bottom - g_yscroll;
+ if (IntersectRect(&draw_rect, &clip_rect, &g_wnd_clip))
+ {
+ rgn = CreateRectRgn(0, 0, 0, 0);
+ ScrollWindowEx(g_Wnd, x - srcx, y - srcy, &rect, &draw_rect,
+ rgn, 0, SW_ERASE);
+ InvalidateRgn(g_Wnd, rgn, 0);
+ DeleteObject(rgn);
+ }
+ }
+}
+
+/*****************************************************************************/
+void
+mi_set_clip(int x, int y, int cx, int cy)
+{
+ g_clip_left = x;
+ g_clip_top = y;
+ g_clip_right = g_clip_left + cx;
+ g_clip_bottom = g_clip_top + cy;
+}
+
+/*****************************************************************************/
+void
+mi_reset_clip(void)
+{
+ g_clip_left = 0;
+ g_clip_top = 0;
+ g_clip_right = g_clip_left + g_width;
+ g_clip_bottom = g_clip_top + g_height;
+}
+
+/*****************************************************************************/
+void *
+mi_create_cursor(unsigned int x, unsigned int y,
+ int width, int height,
+ unsigned char * andmask, unsigned char * xormask)
+{
+#ifdef MYWINCE
+ return (void *) 1;
+#else /* MYWINCE */
+ HCURSOR hCur;
+
+ hCur = CreateCursor(g_Instance, x, y, width, height, andmask, xormask);
+ if (hCur == 0)
+ {
+ hCur = LoadCursor(NULL, IDC_ARROW);
+ }
+ return hCur;
+#endif /* MYWINCE */
+}
+
+/*****************************************************************************/
+void
+mi_destroy_cursor(void * cursor)
+{
+#ifdef MYWINCE
+#else /* MYWINCE */
+ if (g_cursor == cursor)
+ {
+ g_cursor = 0;
+ }
+ DestroyCursor(cursor);
+#endif /* MYWINCE */
+}
+
+/*****************************************************************************/
+void
+mi_set_cursor(void * cursor)
+{
+#ifdef MYWINCE
+#else /* MYWINCE */
+ g_cursor = cursor;
+ SetCursor(g_cursor);
+#endif /* MYWINCE */
+}
+
+/*****************************************************************************/
+void
+mi_set_null_cursor(void)
+{
+}
+