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 +#include +#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 + +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 #include -#include -#include -#include +#include +#ifdef _WIN32 +#include /* winsock2.h first */ +#include +#include +#else /* WIN32 */ +#include +#include +#include #ifdef HAVE_SYS_SELECT_H #include -#else +#else /* HAVE_SYS_SELECT_H */ #include #include -#endif +#endif /* HAVE_SYS_SELECT_H */ +#endif /* WIN32 */ #include /* 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 -#include -#include -#include "rdesktop.h" - -#ifdef HAVE_ICONV -#ifdef HAVE_ICONV_H -#include -#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 +#ifndef _WIN32 +#include +#include +#endif +#include "rdesktop.h" + +#ifdef HAVE_ICONV +#ifdef HAVE_ICONV_H +#include +#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 -#include -#include -#include -#include - +//#include +//#include +//#include +//#include +//#include + +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 + or visit . +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 , 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 . +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 /* select read write close */ #include /* socket connect setsockopt */ #include /* timeval */ @@ -26,8 +27,23 @@ #include /* TCP_NODELAY */ #include /* inet_addr */ #include /* 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 first */ +#include +#ifdef MYWINCE +#include /* aygshell.lib */ +#endif /* MYWINCE */ +#include +#include +#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) +{ +} +