diff -Nru rdesktop-1.8.6/asn.c rdesktop-1.9.0/asn.c --- rdesktop-1.8.6/asn.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/asn.c 2019-09-19 07:15:51.000000000 +0000 @@ -1,7 +1,8 @@ /* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. ASN.1 utility functions - Copyright 2012 Henrik Andersson for Cendio AB + Copyright 2012-2017 Henrik Andersson for Cendio AB + Copyright 2017 Alexander Zakharov 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 @@ -17,8 +18,20 @@ along with this program. If not, see . */ +#include +#include +#include + #include "rdesktop.h" +#include "asn.h" + +// Generated by asn1Parser +#include "pkix_asn1_tab.c" + +static asn1_node *asn_defs = NULL; +#define MAX_ERROR_DESCRIPTION_SIZE 1024 +char errstr[MAX_ERROR_DESCRIPTION_SIZE]; /* Parse an ASN.1 BER header */ RD_BOOL @@ -43,7 +56,7 @@ if (tag != tagval) { - error("expected tag %d, got %d\n", tagval, tag); + logger(Core, Error, "ber_parse_header(), expected tag %d, got %d", tagval, tag); return False; } @@ -68,6 +81,17 @@ return True; } +void +ber_out_sequence(STREAM out, STREAM content) +{ + size_t length; + length = (content ? s_length(content) : 0); + ber_out_header(out, BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED, length); + if (content) + out_stream(out, content); +} + + /* Output an ASN.1 BER header */ void ber_out_header(STREAM s, int tagval, int length) @@ -119,3 +143,201 @@ return False; } + + +int init_asn1_lib(void) +{ + int asn1_rv; + + if (asn_defs) { + return 0; + } + + asn_defs = malloc(sizeof(*asn_defs)); + + if (!asn_defs) { + logger(Core, Error, "%s:%s:%d Failed to allocate memory for ASN.1 parser\n", + __FILE__, __func__, __LINE__); + return 1; + } + + *asn_defs = NULL; + + if (ASN1_SUCCESS != (asn1_rv = asn1_array2tree(pkix_asn1_tab, asn_defs, errstr))) { + logger(Core, Error, "%s:%s:%d Failed to init ASN.1 parser. Error = 0x%x (%s)\n", + __FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv)); + + return 1; + } + + return 0; +} + +/* Encode RSA public key into DER PKCS#1 */ +/* Returns; 0 - success, 1 - fatal error, 2 - insufficient space in buffer */ +int write_pkcs1_der_pubkey(const gnutls_datum_t *m, const gnutls_datum_t *e, uint8_t *out, int *out_len) +{ + int asn1_rv; + asn1_node asn_cert; + + if (!asn_defs) { + if (init_asn1_lib() != 0) { + return 1; + } + } + + if (ASN1_SUCCESS != (asn1_rv = asn1_create_element(*asn_defs, "PKIX1Implicit88.RSAPublicKey", &asn_cert))) { + logger(Core, Error, "%s:%s:%d Failed to create ASN.1 parser element for RSAPublicKey. Error = 0x%x (%s)\n", + __FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv)); + return 1; + } + + if (ASN1_SUCCESS != (asn1_rv = asn1_write_value(asn_cert, "modulus", m->data, m->size))) { + logger(Core, Error, "%s:%s:%d Failed to write modulus. Error = 0x%x (%s)\n", + __FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv)); + + return 1; + } + + if (ASN1_SUCCESS != (asn1_rv = asn1_write_value(asn_cert, "publicExponent", e->data, e->size))) { + logger(Core, Error, "%s:%s:%d Failed to write publicExponent. Error = 0x%x (%s)\n", + __FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv)); + return 1; + } + + if (ASN1_SUCCESS != (asn1_rv = asn1_der_coding(asn_cert, "", out, out_len, errstr))) { + logger(Core, Error, "%s:%s:%d Failed to encode PKIX1Implicit88.RSAPublicKey. Error = 0x%x (%s)\n", + __FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv)); + + if (asn1_rv == ASN1_MEM_ERROR) { + return 2; + } + + return 1; + } + + return 0; +} + +int libtasn_read_cert_pk_oid(uint8_t *data, size_t len, char *oid, size_t *oid_size) +{ + int asn1_rv; + asn1_node asn_cert; + + /* Parse DER encoded x.509 certificate */ + if (!asn_defs) { + if (init_asn1_lib() != 0) { + return 1; + } + } + + if (ASN1_SUCCESS != (asn1_rv = asn1_create_element(*asn_defs, "PKIX1Implicit88.Certificate", &asn_cert))) { + logger(Core, Error, "%s:%s:%d Failed to create ASN.1 parser element. Error = 0x%x (%s)\n", + __FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv)); + return 1; + } + + if (ASN1_SUCCESS != (asn1_rv = asn1_der_decoding(&asn_cert, data, len, errstr))) { + logger(Core, Error, "%s:%s:%d Failed to decode certificate object. Error = 0x%x (%s)\n", + __FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv)); + return 1; + } + + if (ASN1_SUCCESS != (asn1_rv = asn1_read_value(asn_cert, "tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm", + oid, (int *)oid_size))) + { + logger(Core, Error, "%s:%s:%d Failed to get cert's public key algorithm. Error = 0x%x (%s)\n", + __FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv)); + return 1; + } + + return 0; +} + +int libtasn_read_cert_pk_parameters(uint8_t *data, size_t len, gnutls_datum_t *m, gnutls_datum_t *e) +{ + int asn1_rv; + asn1_node asn_cert; + + int buflen; + uint8_t buf[16384]; + + asn1_node asn_key; + int nblen; + uint8_t newbuf[16384]; + + /* Parse DER encoded x.509 certificate */ + init_asn1_lib(); + + if (ASN1_SUCCESS != (asn1_rv = asn1_create_element(*asn_defs, "PKIX1Implicit88.Certificate", &asn_cert))) { + logger(Core, Error, "%s:%s:%d Failed to create ASN.1 parser element. Error = 0x%x (%s)\n", + __FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv)); + return 1; + } + + if (ASN1_SUCCESS != (asn1_rv = asn1_der_decoding(&asn_cert, data, len, errstr))) { + logger(Core, Error, "%s:%s:%d Failed to decode certificate object. Error = 0x%x (%s)\n", + __FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv)); + return 1; + } + + buflen = sizeof(buf) - 1; + if (ASN1_SUCCESS != (asn1_rv = asn1_read_value(asn_cert, "tbsCertificate.subjectPublicKeyInfo.subjectPublicKey", buf, &buflen))) { + logger(Core, Error, "%s:%s:%d Failed to get cert's public key. Error = 0x%x (%s)\n", + __FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv)); + return 1; + } + + if (ASN1_SUCCESS != (asn1_rv = asn1_create_element(*asn_defs, "PKIX1Implicit88.RSAPublicKey", &asn_key))) { + logger(Core, Error, "%s:%s:%d Failed to create ASN.1 parser element. Error = 0x%x (%s)\n", + __FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv)); + return 1; + } + + // As it' a BIT STRING the len constitutes the number of BITS, not BYTES + if (ASN1_SUCCESS != (asn1_rv = asn1_der_decoding(&asn_key, buf, buflen / 8, errstr))) { + logger(Core, Error, "%s:%s:%d Failed to decode public key object. Error = 0x%x (%s)\n", + __FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv)); + return 1; + } + + /* Get RSA public key's modulus and exponent */ + nblen = sizeof(newbuf); + + if (ASN1_SUCCESS != (asn1_rv = asn1_read_value(asn_key, "modulus", newbuf, &nblen))) { + logger(Core, Error, "%s:%s:%d Failed to get RSA public key's modulus. Error = 0x%x (%s)\n", + __FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv)); + return 1; + } + + m->size = nblen; + + if (!(m->data = malloc(m->size))) { + logger(Core, Error, "%s:%s:%d Failed to allocate memory for modulus.\n", __FILE__, __func__, __LINE__); + return 1; + } + + memcpy((void *)m->data, newbuf, m->size); + + nblen = sizeof(newbuf); + + if (ASN1_SUCCESS != (asn1_rv = asn1_read_value(asn_key, "publicExponent", newbuf, &nblen))) { + logger(Core, Error, "%s:%s:%d Failed to get RSA public key's exponent. Error = 0x%x (%s)\n", + __FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv)); + return 1; + } + + e->size = nblen; + + if (!(e->data = malloc(e->size))) { + logger(Core, Error, "%s:%s:%d Failed to allocate memory for exponent.\n", __FILE__, __func__, __LINE__); + if (m->data) { + free(m->data); + } + return 1; + } + + memcpy((void *)e->data, newbuf, e->size); + + return 0; +} diff -Nru rdesktop-1.8.6/asn.h rdesktop-1.9.0/asn.h --- rdesktop-1.8.6/asn.h 1970-01-01 00:00:00.000000000 +0000 +++ rdesktop-1.9.0/asn.h 2019-09-19 07:20:08.000000000 +0000 @@ -0,0 +1,45 @@ +/* -*- c-basic-offset: 8 -*- + rdesktop: A Remote Desktop Protocol client. + ASN.1 utility functions header + Copyright 2017 Alexander Zakharov + + 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 3 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, see . +*/ +#ifndef _RDASN_H +#define _RDASN_H + +#include +#include +#include + +#include "utils.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define OID_SHA_WITH_RSA_SIGNATURE "1.3.14.3.2.15" +#define OID_MD5_WITH_RSA_SIGNATURE "1.3.14.3.2.25" + +int init_asn1_lib(void); +int write_pkcs1_der_pubkey(const gnutls_datum_t *m, const gnutls_datum_t *e, uint8_t *out, int *out_len); + +int libtasn_read_cert_pk_oid(uint8_t *data, size_t len, char *oid, size_t *oid_size); +int libtasn_read_cert_pk_parameters(uint8_t *data, size_t len, gnutls_datum_t *m, gnutls_datum_t *e); + +#ifdef __cplusplus +} +#endif + +#endif /* _RDASN_H */ diff -Nru rdesktop-1.8.6/bitmap.c rdesktop-1.9.0/bitmap.c --- rdesktop-1.8.6/bitmap.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/bitmap.c 2019-06-13 12:10:15.000000000 +0000 @@ -17,8 +17,8 @@ along with this program. If not, see . */ -/* three seperate function for speed when decompressing the bitmaps - when modifing one function make the change in the others +/* three separate function for speed when decompressing the bitmaps + when modifying one function make the change in the others jay.sorg@gmail.com */ /* indent is confused by this file */ @@ -135,6 +135,8 @@ break; case 8: /* Bicolour */ colour1 = CVAL(input); + colour2 = CVAL(input); + break; case 3: /* Colour */ colour2 = CVAL(input); break; @@ -252,7 +254,7 @@ REPEAT(line[x] = 0) break; default: - unimpl("bitmap opcode 0x%x\n", opcode); + logger(Core, Warning, "bitmap_decompress(), unhandled bitmap opcode 0x%x", opcode); return False; } } @@ -333,6 +335,8 @@ break; case 8: /* Bicolour */ CVAL2(input, colour1); + CVAL2(input, colour2); + break; case 3: /* Colour */ CVAL2(input, colour2); break; @@ -451,7 +455,7 @@ REPEAT(line[x] = 0) break; default: - unimpl("bitmap opcode 0x%x\n", opcode); + logger(Core, Warning, "bitmap_decompress2(), unhandled bitmap opcode 0x%x", opcode); return False; } } @@ -535,6 +539,10 @@ colour1[0] = CVAL(input); colour1[1] = CVAL(input); colour1[2] = CVAL(input); + colour2[0] = CVAL(input); + colour2[1] = CVAL(input); + colour2[2] = CVAL(input); + break; case 3: /* Colour */ colour2[0] = CVAL(input); colour2[1] = CVAL(input); @@ -737,7 +745,7 @@ ) break; default: - unimpl("bitmap opcode 0x%x\n", opcode); + logger(Core, Warning, "bitmap_decompress3(), unhandled bitmap opcode 0x%x", opcode); return False; } } @@ -749,6 +757,7 @@ static int process_plane(uint8 * in, int width, int height, uint8 * out, int size) { + UNUSED(size); int indexw; int indexh; int code; @@ -900,7 +909,7 @@ rv = bitmap_decompress4(output, width, height, input, size); break; default: - unimpl("Bpp %d\n", Bpp); + logger(Core, Debug, "bitmap_decompress(), unhandled BPP %d", Bpp); break; } return rv; diff -Nru rdesktop-1.8.6/cache.c rdesktop-1.9.0/cache.c --- rdesktop-1.8.6/cache.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/cache.c 2019-06-13 12:10:15.000000000 +0000 @@ -31,9 +31,9 @@ #define IS_SET(idx) (idx >= 0) /* - * TODO: Test for optimal value of BUMP_COUNT. TO_TOP gives lowest cpu utilisation but using + * TODO: Test for optimal value of BUMP_COUNT. TO_TOP gives lowest CPU utilisation but using * a positive value will hopefully result in less frequently used bitmaps having a greater chance - * of being evicted from the cache, and therby reducing the need to load bitmaps from disk. + * of being evicted from the cache, and thereby reducing the need to load bitmaps from disk. * (Jeroen) */ #define BUMP_COUNT 40 @@ -93,8 +93,9 @@ if (c != g_bmpcache_count[id]) { - error("Oops. %d in bitmap cache linked list, %d in ui cache...\n", c, - g_bmpcache_count[id]); + logger(Core, Error, + "cache_rebuild_bmpcache_linked_list(), %d in bitmap cache linked list, %d in ui cache...", + c, g_bmpcache_count[id]); exit(EX_SOFTWARE); } } @@ -111,7 +112,7 @@ if (g_bmpcache_mru[id] == idx) return; - DEBUG_RDP5(("bump bitmap: id=%d, idx=%d, bump=%d\n", id, idx, bump)); + logger(Core, Debug, "cache_bump_bitmap(), id=%d, idx=%d, bump=%d", id, idx, bump); n_idx = g_bmpcache[id][idx].next; p_idx = g_bmpcache[id][idx].previous; @@ -177,8 +178,9 @@ idx = g_bmpcache_lru[id]; n_idx = g_bmpcache[id][idx].next; - DEBUG_RDP5(("evict bitmap: id=%d idx=%d n_idx=%d bmp=%p\n", id, idx, n_idx, - g_bmpcache[id][idx].bitmap)); + + logger(Core, Debug, "cache_evict_bitmap(), id=%d idx=%d n_idx=%d bmp=%p", id, idx, n_idx, + g_bmpcache[id][idx].bitmap); ui_destroy_bitmap(g_bmpcache[id][idx].bitmap); --g_bmpcache_count[id]; @@ -209,7 +211,8 @@ return g_volatile_bc[id]; } - error("get bitmap %d:%d\n", id, idx); + logger(Core, Debug, "cache_get_bitmap(), id=%d, idx=%d", id, idx); + return NULL; } @@ -245,7 +248,7 @@ } else { - error("put bitmap %d:%d\n", id, idx); + logger(Core, Error, "cache_put_bitmap(), failed, id=%d, idx=%d\n", id, idx); } } @@ -259,14 +262,15 @@ for (id = 0; id < NUM_ELEMENTS(g_bmpcache); id++) if (IS_PERSISTENT(id)) { - DEBUG_RDP5(("Saving cache state for bitmap cache %d...", id)); + logger(Core, Debug, + "cache_save_state(), saving cache state for bitmap cache %d", id); idx = g_bmpcache_lru[id]; while (idx >= 0) { pstcache_touch_bitmap(id, idx, ++t); idx = g_bmpcache[id][idx].next; } - DEBUG_RDP5((" %d stamps written.\n", t)); + logger(Core, Debug, "cache_save_state(), %d stamps written", t); } } @@ -287,7 +291,7 @@ return glyph; } - error("get font %d:%d\n", font, character); + logger(Core, Debug, "cache_get_font(), font=%d, char=%d", font, character); return NULL; } @@ -312,7 +316,7 @@ } else { - error("put font %d:%d\n", font, character); + logger(Core, Error, "cache_put_font(), failed, font=%d, char=%d", font, character); } } @@ -362,7 +366,7 @@ return &g_deskcache[offset]; } - error("get desktop %d:%d\n", offset, length); + logger(Core, Debug, "cache_get_desktop(), offset=%d, length=%d", offset, length); return NULL; } @@ -387,7 +391,7 @@ } else { - error("put desktop %d:%d\n", offset, length); + logger(Core, Error, "cache_put_desktop(), offset=%d, length=%d", offset, length); } } @@ -408,7 +412,7 @@ return cursor; } - error("get cursor %d\n", cache_idx); + logger(Core, Debug, "cache_get_cursor(), idx=%d", cache_idx); return NULL; } @@ -428,12 +432,12 @@ } else { - error("put cursor %d\n", cache_idx); + logger(Core, Error, "cache_put_cursor(), failed, idx=%d", cache_idx); } } /* BRUSH CACHE */ -/* index 0 is 2 colour brush, index 1 is muti colour brush */ +/* index 0 is 2 colour brush, index 1 is multi colour brush */ static BRUSHDATA g_brushcache[2][64]; /* Retrieve brush from cache */ @@ -445,12 +449,12 @@ { return &g_brushcache[colour_code][idx]; } - error("get brush %d %d\n", colour_code, idx); + logger(Core, Debug, "cache_get_brush_data(), colour=%d, idx=%d", colour_code, idx); return NULL; } /* Store brush in cache */ -/* this function takes over the data pointer in struct, eg, caller gives it up */ +/* this function takes over the data pointer in struct, e.g. caller gives it up */ void cache_put_brush_data(uint8 colour_code, uint8 idx, BRUSHDATA * brush_data) { @@ -468,6 +472,6 @@ } else { - error("put brush %d %d\n", colour_code, idx); + logger(Core, Error, "cache_put_brush_data(), colour=%d, idx=%d", colour_code, idx); } } diff -Nru rdesktop-1.8.6/channels.c rdesktop-1.9.0/channels.c --- rdesktop-1.8.6/channels.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/channels.c 2019-09-17 14:58:24.000000000 +0000 @@ -3,6 +3,7 @@ Protocol services - Virtual channels Copyright 2003 Erik Forsberg for Cendio AB Copyright (C) Matthew Chapman 2003-2008 + Copyright 2016 Alexander Zakharov 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 @@ -29,6 +30,8 @@ extern RDP_VERSION g_rdp_version; extern RD_BOOL g_encryption; +uint32 vc_chunk_size = CHANNEL_CHUNK_LENGTH; + VCHANNEL g_channels[MAX_CHANNELS]; unsigned int g_num_channels; @@ -52,7 +55,8 @@ if (g_num_channels >= MAX_CHANNELS) { - error("Channel table full, increase MAX_CHANNELS\n"); + logger(Core, Error, + "channel_register(), channel table full, increase MAX_CHANNELS"); return NULL; } @@ -68,6 +72,7 @@ STREAM channel_init(VCHANNEL * channel, uint32 length) { + UNUSED(channel); STREAM s; s = sec_init(g_encryption ? SEC_ENCRYPT : 0, length + 8); @@ -88,7 +93,11 @@ to work so.. This applies only to *this* length, not the length of continuation or ending packets. */ - thislength = MIN(s_remaining(s), CHANNEL_CHUNK_LENGTH); + /* Actually, CHANNEL_CHUNK_LENGTH (default value is 1600 bytes) is described + in MS-RDPBCGR (s. 2.2.6, s.3.1.5.2.1) and can be set by server only + in the optional field VCChunkSize of VC Caps) */ + + thislength = MIN(s_remaining(s), vc_chunk_size); flags = 0; if (length == s_remaining(s)) @@ -104,8 +113,8 @@ flags |= CHANNEL_FLAG_SHOW_PROTOCOL; } - DEBUG_CHANNEL(("channel_send_chunk(), sending %d bytes with flags 0x%x\n", - thislength, flags)); + logger(Protocol, Debug, "channel_send_chunk(), sending %d bytes with flags 0x%x", + thislength, flags); /* first fragment sent in-place */ inplace = False; @@ -160,7 +169,8 @@ in_uint8s(s, 8); length = s_remaining(s); - DEBUG_CHANNEL(("channel_send, length = %d\n", length)); + logger(Protocol, Debug, "channel_send(), channel = %d, length = %d", channel->mcs_id, + length); while (!s_check_end(s)) { @@ -176,6 +186,7 @@ channel_process(STREAM s, uint16 mcs_channel) { uint32 length, flags; + uint32 thislength; VCHANNEL *channel = NULL; unsigned int i; STREAM in; @@ -207,7 +218,8 @@ s_reset(in); } - out_uint8stream(in, s, s_remaining(s)); + thislength = s_remaining(s); + out_uint8stream(in, s, thislength); if (flags & CHANNEL_FLAG_LAST) { diff -Nru rdesktop-1.8.6/cliprdr.c rdesktop-1.9.0/cliprdr.c --- rdesktop-1.8.6/cliprdr.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/cliprdr.c 2019-06-13 12:10:15.000000000 +0000 @@ -3,6 +3,7 @@ Protocol services - Clipboard functions Copyright 2003 Erik Forsberg for Cendio AB Copyright (C) Matthew Chapman 2003-2008 + Copyright 2017 Henrik Andersson for Cendio AB 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 @@ -40,7 +41,8 @@ { STREAM s; - DEBUG_CLIPBOARD(("CLIPRDR send: type=%d, status=%d, length=%d\n", type, status, length)); + logger(Clipboard, Debug, "cliprdr_send_packet(), type=%d, status=%d, length=%d", type, + status, length); s = channel_init(cliprdr_channel, length + 12); out_uint16_le(s, type); @@ -63,7 +65,8 @@ { uint8 buffer[36]; - DEBUG_CLIPBOARD(("cliprdr_send_simple_native_format_announce\n")); + logger(Clipboard, Debug, "cliprdr_send_simple_native_format_announce() format 0x%x", + format); buf_out_uint32(buffer, format); memset(buffer + 4, 0, sizeof(buffer) - 4); /* description */ @@ -77,7 +80,7 @@ void cliprdr_send_native_format_announce(uint8 * formats_data, uint32 formats_data_length) { - DEBUG_CLIPBOARD(("cliprdr_send_native_format_announce\n")); + logger(Clipboard, Debug, "cliprdr_send_native_format_announce()"); cliprdr_send_packet(CLIPRDR_FORMAT_ANNOUNCE, CLIPRDR_REQUEST, formats_data, formats_data_length); @@ -98,7 +101,7 @@ { uint8 buffer[4]; - DEBUG_CLIPBOARD(("cliprdr_send_data_request\n")); + logger(Clipboard, Debug, "cliprdr_send_data_request(), format 0x%x", format); buf_out_uint32(buffer, format); cliprdr_send_packet(CLIPRDR_DATA_REQUEST, CLIPRDR_REQUEST, buffer, sizeof(buffer)); } @@ -106,7 +109,7 @@ void cliprdr_send_data(uint8 * data, uint32 length) { - DEBUG_CLIPBOARD(("cliprdr_send_data\n")); + logger(Clipboard, Debug, "cliprdr_send_data(), length %d bytes", length); cliprdr_send_packet(CLIPRDR_DATA_RESPONSE, CLIPRDR_RESPONSE, data, length); } @@ -121,7 +124,8 @@ in_uint16_le(s, status); in_uint32_le(s, length); - DEBUG_CLIPBOARD(("CLIPRDR recv: type=%d, status=%d, length=%d\n", type, status, length)); + logger(Clipboard, Debug, "cliprdr_process(), type=%d, status=%d, length=%d", type, status, + length); if (status == CLIPRDR_ERROR) { @@ -137,7 +141,8 @@ ui_clip_request_failed(); break; default: - DEBUG_CLIPBOARD(("CLIPRDR error (type=%d)\n", type)); + logger(Clipboard, Warning, + "cliprdr_process(), unhandled error (type=%d)", type); } return; @@ -166,7 +171,8 @@ case 7: /* TODO: W2K3 SP1 sends this on connect with a value of 1 */ break; default: - unimpl("CLIPRDR packet type %d\n", type); + logger(Clipboard, Warning, "cliprdr_process(), unhandled packet type %d", + type); } } diff -Nru rdesktop-1.8.6/config.guess rdesktop-1.9.0/config.guess --- rdesktop-1.8.6/config.guess 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/config.guess 2019-06-13 12:10:15.000000000 +0000 @@ -148,7 +148,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or - # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward diff -Nru rdesktop-1.8.6/configure rdesktop-1.9.0/configure --- rdesktop-1.8.6/configure 1970-01-01 00:00:00.000000000 +0000 +++ rdesktop-1.9.0/configure 2019-09-20 06:39:32.000000000 +0000 @@ -0,0 +1,9150 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.69 for rdesktop 1.9.0. +# +# +# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +as_fn_exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1 +test -x / || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +test -n "$DJDIR" || exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME='rdesktop' +PACKAGE_TARNAME='rdesktop' +PACKAGE_VERSION='1.9.0' +PACKAGE_STRING='rdesktop 1.9.0' +PACKAGE_BUGREPORT='' +PACKAGE_URL='' + +ac_unique_file="rdesktop.c" +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='LTLIBOBJS +LIBICONV +LIBOBJS +SOUNDOBJ +LIBSAMPLERATE_LIBS +LIBSAMPLERATE_CFLAGS +ALSA_LIBS +ALSA_CFLAGS +PULSE_LIBS +PULSE_CFLAGS +LIBAO_LIBS +LIBAO_CFLAGS +SCARDOBJ +PNP_NOTIFICATIONS_LIBS +PNP_NOTIFICATIONS_CFLAGS +PCSCLITE_LIBS +PCSCLITE_CFLAGS +GNUTLS_LIBS +GNUTLS_CFLAGS +HOGWEED_LIBS +HOGWEED_CFLAGS +NETTLE_LIBS +NETTLE_CFLAGS +LIBTASN1_LIBS +LIBTASN1_CFLAGS +XCURSOR_LIBS +XCURSOR_CFLAGS +XRANDR_LIBS +XRANDR_CFLAGS +CREDSSPOBJ +GSSAPI_LIBS +GSSAPI_CFLAGS +PKG_CONFIG_LIBDIR +PKG_CONFIG_PATH +STRIP +PKG_CONFIG +X_EXTRA_LIBS +X_LIBS +X_PRE_LIBS +X_CFLAGS +XMKMF +EGREP +GREP +CPP +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +with_x +enable_address_sanitizer +enable_credssp +enable_smartcard +with_egd_socket +with_sound +enable_static_libsamplerate +with_libiconv_prefix +enable_largefile +with_ipv6 +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CPP +XMKMF +PKG_CONFIG +PKG_CONFIG_PATH +PKG_CONFIG_LIBDIR +GSSAPI_CFLAGS +GSSAPI_LIBS +XRANDR_CFLAGS +XRANDR_LIBS +XCURSOR_CFLAGS +XCURSOR_LIBS +LIBTASN1_CFLAGS +LIBTASN1_LIBS +NETTLE_CFLAGS +NETTLE_LIBS +HOGWEED_CFLAGS +HOGWEED_LIBS +GNUTLS_CFLAGS +GNUTLS_LIBS +PCSCLITE_CFLAGS +PCSCLITE_LIBS +PNP_NOTIFICATIONS_CFLAGS +PNP_NOTIFICATIONS_LIBS +LIBAO_CFLAGS +LIBAO_LIBS +PULSE_CFLAGS +PULSE_LIBS +ALSA_CFLAGS +ALSA_LIBS +LIBSAMPLERATE_CFLAGS +LIBSAMPLERATE_LIBS' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures rdesktop 1.9.0 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/rdesktop] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +X features: + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of rdesktop 1.9.0:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-address-sanitizer + enable AddressSanitizer support for detecting a wide + variety of memory allocation and deallocation errors + --disable-credssp disable support for CredSSP + --disable-smartcard disable support for smartcard + --enable-static-libsamplerate link libsamplerate statically + --disable-largefile omit support for large files + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-x use the X Window System + --with-egd-socket=PATH look for Entropy Gathering Daemon socket at PATH + --with-sound select sound system ("oss", "sgi", "sun", "alsa", "pulse" or "libao") + --with-libiconv-prefix=DIR search for libiconv in DIR/include and DIR/lib + --with-ipv6 enable IPv6-support + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CPP C preprocessor + XMKMF Path to xmkmf, Makefile generator for X Window System + PKG_CONFIG path to pkg-config utility + PKG_CONFIG_PATH + directories to add to pkg-config's search path + PKG_CONFIG_LIBDIR + path overriding pkg-config's built-in search path + GSSAPI_CFLAGS + C compiler flags for GSSAPI, overriding pkg-config + GSSAPI_LIBS linker flags for GSSAPI, overriding pkg-config + XRANDR_CFLAGS + C compiler flags for XRANDR, overriding pkg-config + XRANDR_LIBS linker flags for XRANDR, overriding pkg-config + XCURSOR_CFLAGS + C compiler flags for XCURSOR, overriding pkg-config + XCURSOR_LIBS + linker flags for XCURSOR, overriding pkg-config + LIBTASN1_CFLAGS + C compiler flags for LIBTASN1, overriding pkg-config + LIBTASN1_LIBS + linker flags for LIBTASN1, overriding pkg-config + NETTLE_CFLAGS + C compiler flags for NETTLE, overriding pkg-config + NETTLE_LIBS linker flags for NETTLE, overriding pkg-config + HOGWEED_CFLAGS + C compiler flags for HOGWEED, overriding pkg-config + HOGWEED_LIBS + linker flags for HOGWEED, overriding pkg-config + GNUTLS_CFLAGS + C compiler flags for GNUTLS, overriding pkg-config + GNUTLS_LIBS linker flags for GNUTLS, overriding pkg-config + PCSCLITE_CFLAGS + C compiler flags for PCSCLITE, overriding pkg-config + PCSCLITE_LIBS + linker flags for PCSCLITE, overriding pkg-config + PNP_NOTIFICATIONS_CFLAGS + C compiler flags for PNP_NOTIFICATIONS, overriding pkg-config + PNP_NOTIFICATIONS_LIBS + linker flags for PNP_NOTIFICATIONS, overriding pkg-config + LIBAO_CFLAGS + C compiler flags for LIBAO, overriding pkg-config + LIBAO_LIBS linker flags for LIBAO, overriding pkg-config + PULSE_CFLAGS + C compiler flags for PULSE, overriding pkg-config + PULSE_LIBS linker flags for PULSE, overriding pkg-config + ALSA_CFLAGS C compiler flags for ALSA, overriding pkg-config + ALSA_LIBS linker flags for ALSA, overriding pkg-config + LIBSAMPLERATE_CFLAGS + C compiler flags for LIBSAMPLERATE, overriding pkg-config + LIBSAMPLERATE_LIBS + linker flags for LIBSAMPLERATE, overriding pkg-config + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to the package provider. +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +rdesktop configure 1.9.0 +generated by GNU Autoconf 2.69 + +Copyright (C) 2012 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_compile + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + test -x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link + +# ac_fn_c_check_func LINENO FUNC VAR +# ---------------------------------- +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_c_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case declares $2. + For example, HP-UX 11i declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main () +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_func + +# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists, giving a warning if it cannot be compiled using +# the include files in INCLUDES and setting the cache variable VAR +# accordingly. +ac_fn_c_check_header_mongrel () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if eval \${$3+:} false; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 +$as_echo_n "checking $2 usability... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_header_compiler=yes +else + ac_header_compiler=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 +$as_echo_n "checking $2 presence... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <$2> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + ac_header_preproc=yes +else + ac_header_preproc=no +fi +rm -f conftest.err conftest.i conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( + yes:no: ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; + no:yes:* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=\$ac_header_compiler" +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_mongrel + +# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES +# --------------------------------------------- +# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR +# accordingly. +ac_fn_c_check_decl () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + as_decl_name=`echo $2|sed 's/ *(.*//'` + as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 +$as_echo_n "checking whether $as_decl_name is declared... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +#ifndef $as_decl_name +#ifdef __cplusplus + (void) $as_decl_use; +#else + (void) $as_decl_name; +#endif +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_decl + +# ac_fn_c_check_type LINENO TYPE VAR INCLUDES +# ------------------------------------------- +# Tests whether TYPE exists after having included INCLUDES, setting cache +# variable VAR accordingly. +ac_fn_c_check_type () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=no" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof ($2)) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof (($2))) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + eval "$3=yes" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_type + +# ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES +# ---------------------------------------------------- +# Tries to find if the field MEMBER exists in type AGGR, after including +# INCLUDES, setting cache variable VAR accordingly. +ac_fn_c_check_member () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 +$as_echo_n "checking for $2.$3... " >&6; } +if eval \${$4+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$5 +int +main () +{ +static $2 ac_aggr; +if (ac_aggr.$3) +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$4=yes" +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$5 +int +main () +{ +static $2 ac_aggr; +if (sizeof ac_aggr.$3) +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$4=yes" +else + eval "$4=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$4 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_member +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by rdesktop $as_me 1.9.0, which was +generated by GNU Autoconf 2.69. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + $as_echo "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + $as_echo "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + $as_echo "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Make sure we can run config.sub. +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +$as_echo_n "checking build system type... " >&6; } +if ${ac_cv_build+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +$as_echo "$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +$as_echo_n "checking host system type... " >&6; } +if ${ac_cv_host+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +$as_echo "$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if ${ac_cv_objext+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +struct stat; +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +if test "$GCC" = yes; then + CFLAGS="$CFLAGS -Wall -Wextra" +fi + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +$as_echo_n "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if ${ac_cv_path_install+:} false; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in #(( + ./ | .// | /[cC]/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + + done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +$as_echo "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if ${ac_cv_prog_CPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if ${ac_cv_path_GREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_GREP" || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if ${ac_cv_path_EGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_EGREP" || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 +$as_echo_n "checking whether byte ordering is bigendian... " >&6; } +if ${ac_cv_c_bigendian+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_c_bigendian=unknown + # See if we're dealing with a universal compiler. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifndef __APPLE_CC__ + not a universal capable compiler + #endif + typedef int dummy; + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + # Check for potential -arch flags. It is not universal unless + # there are at least two -arch flags with different values. + ac_arch= + ac_prev= + for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do + if test -n "$ac_prev"; then + case $ac_word in + i?86 | x86_64 | ppc | ppc64) + if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then + ac_arch=$ac_word + else + ac_cv_c_bigendian=universal + break + fi + ;; + esac + ac_prev= + elif test "x$ac_word" = "x-arch"; then + ac_prev=arch + fi + done +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if test $ac_cv_c_bigendian = unknown; then + # See if sys/param.h defines the BYTE_ORDER macro. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + +int +main () +{ +#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ + && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ + && LITTLE_ENDIAN) + bogus endian macros + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + # It does; now see whether it defined to BIG_ENDIAN or not. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + +int +main () +{ +#if BYTE_ORDER != BIG_ENDIAN + not big endian + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_bigendian=yes +else + ac_cv_c_bigendian=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + if test $ac_cv_c_bigendian = unknown; then + # See if defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris). + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +int +main () +{ +#if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) + bogus endian macros + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + # It does; now see whether it defined to _BIG_ENDIAN or not. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +int +main () +{ +#ifndef _BIG_ENDIAN + not big endian + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_bigendian=yes +else + ac_cv_c_bigendian=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + if test $ac_cv_c_bigendian = unknown; then + # Compile a test program. + if test "$cross_compiling" = yes; then : + # Try to guess by grepping values from an object file. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +short int ascii_mm[] = + { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; + short int ascii_ii[] = + { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; + int use_ascii (int i) { + return ascii_mm[i] + ascii_ii[i]; + } + short int ebcdic_ii[] = + { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; + short int ebcdic_mm[] = + { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; + int use_ebcdic (int i) { + return ebcdic_mm[i] + ebcdic_ii[i]; + } + extern int foo; + +int +main () +{ +return use_ascii (foo) == use_ebcdic (foo); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then + ac_cv_c_bigendian=yes + fi + if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then + if test "$ac_cv_c_bigendian" = unknown; then + ac_cv_c_bigendian=no + else + # finding both strings is unlikely to happen, but who knows? + ac_cv_c_bigendian=unknown + fi + fi +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ + + /* Are we little or big endian? From Harbison&Steele. */ + union + { + long int l; + char c[sizeof (long int)]; + } u; + u.l = 1; + return u.c[sizeof (long int) - 1] == 1; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_c_bigendian=no +else + ac_cv_c_bigendian=yes +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 +$as_echo "$ac_cv_c_bigendian" >&6; } + case $ac_cv_c_bigendian in #( + yes) + $as_echo "#define B_ENDIAN 1" >>confdefs.h +;; #( + no) + $as_echo "#define L_ENDIAN 1" >>confdefs.h + ;; #( + universal) + +$as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h + + ;; #( + *) + as_fn_error $? "unknown endianness + presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; + esac + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for X" >&5 +$as_echo_n "checking for X... " >&6; } + + +# Check whether --with-x was given. +if test "${with_x+set}" = set; then : + withval=$with_x; +fi + +# $have_x is `yes', `no', `disabled', or empty when we do not yet know. +if test "x$with_x" = xno; then + # The user explicitly disabled X. + have_x=disabled +else + case $x_includes,$x_libraries in #( + *\'*) as_fn_error $? "cannot use X directory names containing '" "$LINENO" 5;; #( + *,NONE | NONE,*) if ${ac_cv_have_x+:} false; then : + $as_echo_n "(cached) " >&6 +else + # One or both of the vars are not set, and there is no cached value. +ac_x_includes=no ac_x_libraries=no +rm -f -r conftest.dir +if mkdir conftest.dir; then + cd conftest.dir + cat >Imakefile <<'_ACEOF' +incroot: + @echo incroot='${INCROOT}' +usrlibdir: + @echo usrlibdir='${USRLIBDIR}' +libdir: + @echo libdir='${LIBDIR}' +_ACEOF + if (export CC; ${XMKMF-xmkmf}) >/dev/null 2>/dev/null && test -f Makefile; then + # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. + for ac_var in incroot usrlibdir libdir; do + eval "ac_im_$ac_var=\`\${MAKE-make} $ac_var 2>/dev/null | sed -n 's/^$ac_var=//p'\`" + done + # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR. + for ac_extension in a so sl dylib la dll; do + if test ! -f "$ac_im_usrlibdir/libX11.$ac_extension" && + test -f "$ac_im_libdir/libX11.$ac_extension"; then + ac_im_usrlibdir=$ac_im_libdir; break + fi + done + # Screen out bogus values from the imake configuration. They are + # bogus both because they are the default anyway, and because + # using them would break gcc on systems where it needs fixed includes. + case $ac_im_incroot in + /usr/include) ac_x_includes= ;; + *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes=$ac_im_incroot;; + esac + case $ac_im_usrlibdir in + /usr/lib | /usr/lib64 | /lib | /lib64) ;; + *) test -d "$ac_im_usrlibdir" && ac_x_libraries=$ac_im_usrlibdir ;; + esac + fi + cd .. + rm -f -r conftest.dir +fi + +# Standard set of common directories for X headers. +# Check X11 before X11Rn because it is often a symlink to the current release. +ac_x_header_dirs=' +/usr/X11/include +/usr/X11R7/include +/usr/X11R6/include +/usr/X11R5/include +/usr/X11R4/include + +/usr/include/X11 +/usr/include/X11R7 +/usr/include/X11R6 +/usr/include/X11R5 +/usr/include/X11R4 + +/usr/local/X11/include +/usr/local/X11R7/include +/usr/local/X11R6/include +/usr/local/X11R5/include +/usr/local/X11R4/include + +/usr/local/include/X11 +/usr/local/include/X11R7 +/usr/local/include/X11R6 +/usr/local/include/X11R5 +/usr/local/include/X11R4 + +/usr/X386/include +/usr/x386/include +/usr/XFree86/include/X11 + +/usr/include +/usr/local/include +/usr/unsupported/include +/usr/athena/include +/usr/local/x11r5/include +/usr/lpp/Xamples/include + +/usr/openwin/include +/usr/openwin/share/include' + +if test "$ac_x_includes" = no; then + # Guess where to find include files, by looking for Xlib.h. + # First, try using that file with no special directory specified. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # We can compile using X headers with no special include directory. +ac_x_includes= +else + for ac_dir in $ac_x_header_dirs; do + if test -r "$ac_dir/X11/Xlib.h"; then + ac_x_includes=$ac_dir + break + fi +done +fi +rm -f conftest.err conftest.i conftest.$ac_ext +fi # $ac_x_includes = no + +if test "$ac_x_libraries" = no; then + # Check for the libraries. + # See if we find them without any special options. + # Don't add to $LIBS permanently. + ac_save_LIBS=$LIBS + LIBS="-lX11 $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +XrmInitialize () + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + LIBS=$ac_save_LIBS +# We can link X programs with no special library path. +ac_x_libraries= +else + LIBS=$ac_save_LIBS +for ac_dir in `$as_echo "$ac_x_includes $ac_x_header_dirs" | sed s/include/lib/g` +do + # Don't even attempt the hair of trying to link an X program! + for ac_extension in a so sl dylib la dll; do + if test -r "$ac_dir/libX11.$ac_extension"; then + ac_x_libraries=$ac_dir + break 2 + fi + done +done +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi # $ac_x_libraries = no + +case $ac_x_includes,$ac_x_libraries in #( + no,* | *,no | *\'*) + # Didn't find X, or a directory has "'" in its name. + ac_cv_have_x="have_x=no";; #( + *) + # Record where we found X for the cache. + ac_cv_have_x="have_x=yes\ + ac_x_includes='$ac_x_includes'\ + ac_x_libraries='$ac_x_libraries'" +esac +fi +;; #( + *) have_x=yes;; + esac + eval "$ac_cv_have_x" +fi # $with_x != no + +if test "$have_x" != yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_x" >&5 +$as_echo "$have_x" >&6; } + no_x=yes +else + # If each of the values was on the command line, it overrides each guess. + test "x$x_includes" = xNONE && x_includes=$ac_x_includes + test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries + # Update the cache value to reflect the command line values. + ac_cv_have_x="have_x=yes\ + ac_x_includes='$x_includes'\ + ac_x_libraries='$x_libraries'" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: libraries $x_libraries, headers $x_includes" >&5 +$as_echo "libraries $x_libraries, headers $x_includes" >&6; } +fi + +if test "$no_x" = yes; then + # Not all programs may use this symbol, but it does not hurt to define it. + +$as_echo "#define X_DISPLAY_MISSING 1" >>confdefs.h + + X_CFLAGS= X_PRE_LIBS= X_LIBS= X_EXTRA_LIBS= +else + if test -n "$x_includes"; then + X_CFLAGS="$X_CFLAGS -I$x_includes" + fi + + # It would also be nice to do this for all -L options, not just this one. + if test -n "$x_libraries"; then + X_LIBS="$X_LIBS -L$x_libraries" + # For Solaris; some versions of Sun CC require a space after -R and + # others require no space. Words are not sufficient . . . . + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -R must be followed by a space" >&5 +$as_echo_n "checking whether -R must be followed by a space... " >&6; } + ac_xsave_LIBS=$LIBS; LIBS="$LIBS -R$x_libraries" + ac_xsave_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + X_LIBS="$X_LIBS -R$x_libraries" +else + LIBS="$ac_xsave_LIBS -R $x_libraries" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + X_LIBS="$X_LIBS -R $x_libraries" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: neither works" >&5 +$as_echo "neither works" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + ac_c_werror_flag=$ac_xsave_c_werror_flag + LIBS=$ac_xsave_LIBS + fi + + # Check for system-dependent libraries X programs must link with. + # Do this before checking for the system-independent R6 libraries + # (-lICE), since we may need -lsocket or whatever for X linking. + + if test "$ISC" = yes; then + X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl_s -linet" + else + # Martyn Johnson says this is needed for Ultrix, if the X + # libraries were built with DECnet support. And Karl Berry says + # the Alpha needs dnet_stub (dnet does not exist). + ac_xsave_LIBS="$LIBS"; LIBS="$LIBS $X_LIBS -lX11" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char XOpenDisplay (); +int +main () +{ +return XOpenDisplay (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dnet_ntoa in -ldnet" >&5 +$as_echo_n "checking for dnet_ntoa in -ldnet... " >&6; } +if ${ac_cv_lib_dnet_dnet_ntoa+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldnet $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dnet_ntoa (); +int +main () +{ +return dnet_ntoa (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dnet_dnet_ntoa=yes +else + ac_cv_lib_dnet_dnet_ntoa=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dnet_dnet_ntoa" >&5 +$as_echo "$ac_cv_lib_dnet_dnet_ntoa" >&6; } +if test "x$ac_cv_lib_dnet_dnet_ntoa" = xyes; then : + X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet" +fi + + if test $ac_cv_lib_dnet_dnet_ntoa = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dnet_ntoa in -ldnet_stub" >&5 +$as_echo_n "checking for dnet_ntoa in -ldnet_stub... " >&6; } +if ${ac_cv_lib_dnet_stub_dnet_ntoa+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldnet_stub $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dnet_ntoa (); +int +main () +{ +return dnet_ntoa (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dnet_stub_dnet_ntoa=yes +else + ac_cv_lib_dnet_stub_dnet_ntoa=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dnet_stub_dnet_ntoa" >&5 +$as_echo "$ac_cv_lib_dnet_stub_dnet_ntoa" >&6; } +if test "x$ac_cv_lib_dnet_stub_dnet_ntoa" = xyes; then : + X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet_stub" +fi + + fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LIBS="$ac_xsave_LIBS" + + # msh@cis.ufl.edu says -lnsl (and -lsocket) are needed for his 386/AT, + # to get the SysV transport functions. + # Chad R. Larson says the Pyramis MIS-ES running DC/OSx (SVR4) + # needs -lnsl. + # The nsl library prevents programs from opening the X display + # on Irix 5.2, according to T.E. Dickey. + # The functions gethostbyname, getservbyname, and inet_addr are + # in -lbsd on LynxOS 3.0.1/i386, according to Lars Hecking. + ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname" +if test "x$ac_cv_func_gethostbyname" = xyes; then : + +fi + + if test $ac_cv_func_gethostbyname = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5 +$as_echo_n "checking for gethostbyname in -lnsl... " >&6; } +if ${ac_cv_lib_nsl_gethostbyname+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lnsl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char gethostbyname (); +int +main () +{ +return gethostbyname (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_nsl_gethostbyname=yes +else + ac_cv_lib_nsl_gethostbyname=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_gethostbyname" >&5 +$as_echo "$ac_cv_lib_nsl_gethostbyname" >&6; } +if test "x$ac_cv_lib_nsl_gethostbyname" = xyes; then : + X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl" +fi + + if test $ac_cv_lib_nsl_gethostbyname = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lbsd" >&5 +$as_echo_n "checking for gethostbyname in -lbsd... " >&6; } +if ${ac_cv_lib_bsd_gethostbyname+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lbsd $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char gethostbyname (); +int +main () +{ +return gethostbyname (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_bsd_gethostbyname=yes +else + ac_cv_lib_bsd_gethostbyname=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_gethostbyname" >&5 +$as_echo "$ac_cv_lib_bsd_gethostbyname" >&6; } +if test "x$ac_cv_lib_bsd_gethostbyname" = xyes; then : + X_EXTRA_LIBS="$X_EXTRA_LIBS -lbsd" +fi + + fi + fi + + # lieder@skyler.mavd.honeywell.com says without -lsocket, + # socket/setsockopt and other routines are undefined under SCO ODT + # 2.0. But -lsocket is broken on IRIX 5.2 (and is not necessary + # on later versions), says Simon Leinen: it contains gethostby* + # variants that don't use the name server (or something). -lsocket + # must be given before -lnsl if both are needed. We assume that + # if connect needs -lnsl, so does gethostbyname. + ac_fn_c_check_func "$LINENO" "connect" "ac_cv_func_connect" +if test "x$ac_cv_func_connect" = xyes; then : + +fi + + if test $ac_cv_func_connect = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for connect in -lsocket" >&5 +$as_echo_n "checking for connect in -lsocket... " >&6; } +if ${ac_cv_lib_socket_connect+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsocket $X_EXTRA_LIBS $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char connect (); +int +main () +{ +return connect (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_socket_connect=yes +else + ac_cv_lib_socket_connect=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_connect" >&5 +$as_echo "$ac_cv_lib_socket_connect" >&6; } +if test "x$ac_cv_lib_socket_connect" = xyes; then : + X_EXTRA_LIBS="-lsocket $X_EXTRA_LIBS" +fi + + fi + + # Guillermo Gomez says -lposix is necessary on A/UX. + ac_fn_c_check_func "$LINENO" "remove" "ac_cv_func_remove" +if test "x$ac_cv_func_remove" = xyes; then : + +fi + + if test $ac_cv_func_remove = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for remove in -lposix" >&5 +$as_echo_n "checking for remove in -lposix... " >&6; } +if ${ac_cv_lib_posix_remove+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lposix $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char remove (); +int +main () +{ +return remove (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_posix_remove=yes +else + ac_cv_lib_posix_remove=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_posix_remove" >&5 +$as_echo "$ac_cv_lib_posix_remove" >&6; } +if test "x$ac_cv_lib_posix_remove" = xyes; then : + X_EXTRA_LIBS="$X_EXTRA_LIBS -lposix" +fi + + fi + + # BSDI BSD/OS 2.1 needs -lipc for XOpenDisplay. + ac_fn_c_check_func "$LINENO" "shmat" "ac_cv_func_shmat" +if test "x$ac_cv_func_shmat" = xyes; then : + +fi + + if test $ac_cv_func_shmat = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shmat in -lipc" >&5 +$as_echo_n "checking for shmat in -lipc... " >&6; } +if ${ac_cv_lib_ipc_shmat+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lipc $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char shmat (); +int +main () +{ +return shmat (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_ipc_shmat=yes +else + ac_cv_lib_ipc_shmat=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ipc_shmat" >&5 +$as_echo "$ac_cv_lib_ipc_shmat" >&6; } +if test "x$ac_cv_lib_ipc_shmat" = xyes; then : + X_EXTRA_LIBS="$X_EXTRA_LIBS -lipc" +fi + + fi + fi + + # Check for libraries that X11R6 Xt/Xaw programs need. + ac_save_LDFLAGS=$LDFLAGS + test -n "$x_libraries" && LDFLAGS="$LDFLAGS -L$x_libraries" + # SM needs ICE to (dynamically) link under SunOS 4.x (so we have to + # check for ICE first), but we must link in the order -lSM -lICE or + # we get undefined symbols. So assume we have SM if we have ICE. + # These have to be linked with before -lX11, unlike the other + # libraries we check for below, so use a different variable. + # John Interrante, Karl Berry + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for IceConnectionNumber in -lICE" >&5 +$as_echo_n "checking for IceConnectionNumber in -lICE... " >&6; } +if ${ac_cv_lib_ICE_IceConnectionNumber+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lICE $X_EXTRA_LIBS $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char IceConnectionNumber (); +int +main () +{ +return IceConnectionNumber (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_ICE_IceConnectionNumber=yes +else + ac_cv_lib_ICE_IceConnectionNumber=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ICE_IceConnectionNumber" >&5 +$as_echo "$ac_cv_lib_ICE_IceConnectionNumber" >&6; } +if test "x$ac_cv_lib_ICE_IceConnectionNumber" = xyes; then : + X_PRE_LIBS="$X_PRE_LIBS -lSM -lICE" +fi + + LDFLAGS=$ac_save_LDFLAGS + +fi + +if test "$no_x" = "yes"; then + echo + echo "ERROR: Could not find X Window System headers/libraries." + if test -f /etc/debian_version; then + echo "Probably you need to install the libx11-dev package." + elif test -f /etc/redhat-release; then + echo "Probably you need to install the libX11-devel package." + fi + echo "To specify paths manually, use the options --x-includes and --x-libraries." + echo + exit 1 +fi + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_PKG_CONFIG+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $PKG_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PKG_CONFIG=$ac_cv_path_PKG_CONFIG +if test -n "$PKG_CONFIG"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 +$as_echo "$PKG_CONFIG" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_PKG_CONFIG"; then + ac_pt_PKG_CONFIG=$PKG_CONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $ac_pt_PKG_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG +if test -n "$ac_pt_PKG_CONFIG"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 +$as_echo "$ac_pt_PKG_CONFIG" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_pt_PKG_CONFIG" = x; then + PKG_CONFIG="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + PKG_CONFIG=$ac_pt_PKG_CONFIG + fi +else + PKG_CONFIG="$ac_cv_path_PKG_CONFIG" +fi + + +# no .pc for GMP +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing __gmpz_init" >&5 +$as_echo_n "checking for library containing __gmpz_init... " >&6; } +if ${ac_cv_search___gmpz_init+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char __gmpz_init (); +int +main () +{ +return __gmpz_init (); + ; + return 0; +} +_ACEOF +for ac_lib in '' gmp; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search___gmpz_init=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search___gmpz_init+:} false; then : + break +fi +done +if ${ac_cv_search___gmpz_init+:} false; then : + +else + ac_cv_search___gmpz_init=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search___gmpz_init" >&5 +$as_echo "$ac_cv_search___gmpz_init" >&6; } +ac_res=$ac_cv_search___gmpz_init +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing socket" >&5 +$as_echo_n "checking for library containing socket... " >&6; } +if ${ac_cv_search_socket+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char socket (); +int +main () +{ +return socket (); + ; + return 0; +} +_ACEOF +for ac_lib in '' socket; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_socket=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_socket+:} false; then : + break +fi +done +if ${ac_cv_search_socket+:} false; then : + +else + ac_cv_search_socket=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_socket" >&5 +$as_echo "$ac_cv_search_socket" >&6; } +ac_res=$ac_cv_search_socket +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing inet_aton" >&5 +$as_echo_n "checking for library containing inet_aton... " >&6; } +if ${ac_cv_search_inet_aton+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char inet_aton (); +int +main () +{ +return inet_aton (); + ; + return 0; +} +_ACEOF +for ac_lib in '' resolv; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_inet_aton=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_inet_aton+:} false; then : + break +fi +done +if ${ac_cv_search_inet_aton+:} false; then : + +else + ac_cv_search_inet_aton=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_inet_aton" >&5 +$as_echo "$ac_cv_search_inet_aton" >&6; } +ac_res=$ac_cv_search_inet_aton +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + + +ac_fn_c_check_header_mongrel "$LINENO" "sys/select.h" "ac_cv_header_sys_select_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_select_h" = xyes; then : + $as_echo "#define HAVE_SYS_SELECT_H 1" >>confdefs.h + +fi + + +ac_fn_c_check_header_mongrel "$LINENO" "sys/modem.h" "ac_cv_header_sys_modem_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_modem_h" = xyes; then : + $as_echo "#define HAVE_SYS_MODEM_H 1" >>confdefs.h + +fi + + +ac_fn_c_check_header_mongrel "$LINENO" "sys/filio.h" "ac_cv_header_sys_filio_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_filio_h" = xyes; then : + $as_echo "#define HAVE_SYS_FILIO_H 1" >>confdefs.h + +fi + + +ac_fn_c_check_header_mongrel "$LINENO" "sys/strtio.h" "ac_cv_header_sys_strtio_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_strtio_h" = xyes; then : + $as_echo "#define HAVE_SYS_STRTIO_H 1" >>confdefs.h + +fi + + +ac_fn_c_check_header_mongrel "$LINENO" "locale.h" "ac_cv_header_locale_h" "$ac_includes_default" +if test "x$ac_cv_header_locale_h" = xyes; then : + $as_echo "#define HAVE_LOCALE_H 1" >>confdefs.h + +fi + + +ac_fn_c_check_header_mongrel "$LINENO" "langinfo.h" "ac_cv_header_langinfo_h" "$ac_includes_default" +if test "x$ac_cv_header_langinfo_h" = xyes; then : + $as_echo "#define HAVE_LANGINFO_H 1" >>confdefs.h + +fi + + +ac_fn_c_check_header_mongrel "$LINENO" "sysexits.h" "ac_cv_header_sysexits_h" "$ac_includes_default" +if test "x$ac_cv_header_sysexits_h" = xyes; then : + $as_echo "#define HAVE_SYSEXITS_H 1" >>confdefs.h + +fi + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + + + + +# Check whether --enable-address-sanitizer was given. +if test "${enable_address_sanitizer+set}" = set; then : + enableval=$enable_address_sanitizer; \ + +$as_echo "#define HAVE_ADDRESS_SANITIZER 1" >>confdefs.h + + CFLAGS="$CFLAGS -fsanitize=address -fno-omit-frame-pointer" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +const int i=0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: Address Sanitizer Enabled" >&5 +$as_echo "$as_me: Address Sanitizer Enabled" >&6;} +else + as_fn_error $? "Address Sanitizer not available" "$LINENO" 5 +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi + + + +# Check whether --enable-credssp was given. +if test "${enable_credssp+set}" = set; then : + enableval=$enable_credssp; +fi + + + + + + + + +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_PKG_CONFIG+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $PKG_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PKG_CONFIG=$ac_cv_path_PKG_CONFIG +if test -n "$PKG_CONFIG"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 +$as_echo "$PKG_CONFIG" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_PKG_CONFIG"; then + ac_pt_PKG_CONFIG=$PKG_CONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $ac_pt_PKG_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG +if test -n "$ac_pt_PKG_CONFIG"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 +$as_echo "$ac_pt_PKG_CONFIG" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_pt_PKG_CONFIG" = x; then + PKG_CONFIG="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + PKG_CONFIG=$ac_pt_PKG_CONFIG + fi +else + PKG_CONFIG="$ac_cv_path_PKG_CONFIG" +fi + +fi +if test -n "$PKG_CONFIG"; then + _pkg_min_version=0.9.0 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 +$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; } + if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + PKG_CONFIG="" + fi +fi +if test "x$enable_credssp" != "xno"; then : + + case "$OSTYPE" in + darwin*) + ac_fn_c_check_header_mongrel "$LINENO" "Kerberos/gssapi_krb5.h" "ac_cv_header_Kerberos_gssapi_krb5_h" "$ac_includes_default" +if test "x$ac_cv_header_Kerberos_gssapi_krb5_h" = xyes; then : + WITH_CREDSSP=1 +else + WITH_CREDSSP=0 +fi + + + GSSAPI_CFLAGS="" + GSSAPI_LIBS="-framework Kerberos" + ;; + *) + #if 'OSTYPE' is not set use 'host' instead + if test x"$OSTYPE" = "x"; then + case "$host" in + *-*-freebsd*) + if test -n "$PKG_CONFIG"; then + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GSSAPI" >&5 +$as_echo_n "checking for GSSAPI... " >&6; } + +if test -n "$GSSAPI_CFLAGS"; then + pkg_cv_GSSAPI_CFLAGS="$GSSAPI_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gss\""; } >&5 + ($PKG_CONFIG --exists --print-errors "gss") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_GSSAPI_CFLAGS=`$PKG_CONFIG --cflags "gss" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$GSSAPI_LIBS"; then + pkg_cv_GSSAPI_LIBS="$GSSAPI_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gss\""; } >&5 + ($PKG_CONFIG --exists --print-errors "gss") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_GSSAPI_LIBS=`$PKG_CONFIG --libs "gss" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + GSSAPI_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "gss" 2>&1` + else + GSSAPI_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "gss" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$GSSAPI_PKG_ERRORS" >&5 + + WITH_CREDSSP=0 +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + WITH_CREDSSP=0 +else + GSSAPI_CFLAGS=$pkg_cv_GSSAPI_CFLAGS + GSSAPI_LIBS=$pkg_cv_GSSAPI_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + WITH_CREDSSP=1 +fi + fi + ;; + *) + ;; + esac + else + if test -n "$PKG_CONFIG"; then + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GSSAPI" >&5 +$as_echo_n "checking for GSSAPI... " >&6; } + +if test -n "$GSSAPI_CFLAGS"; then + pkg_cv_GSSAPI_CFLAGS="$GSSAPI_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"krb5-gssapi\""; } >&5 + ($PKG_CONFIG --exists --print-errors "krb5-gssapi") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_GSSAPI_CFLAGS=`$PKG_CONFIG --cflags "krb5-gssapi" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$GSSAPI_LIBS"; then + pkg_cv_GSSAPI_LIBS="$GSSAPI_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"krb5-gssapi\""; } >&5 + ($PKG_CONFIG --exists --print-errors "krb5-gssapi") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_GSSAPI_LIBS=`$PKG_CONFIG --libs "krb5-gssapi" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + GSSAPI_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "krb5-gssapi" 2>&1` + else + GSSAPI_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "krb5-gssapi" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$GSSAPI_PKG_ERRORS" >&5 + + WITH_CREDSSP=0 +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + WITH_CREDSSP=0 +else + GSSAPI_CFLAGS=$pkg_cv_GSSAPI_CFLAGS + GSSAPI_LIBS=$pkg_cv_GSSAPI_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + WITH_CREDSSP=1 +fi + fi + fi + ;; + esac + + + if test x"$WITH_CREDSSP" = "x1"; then + CREDSSPOBJ="cssp.o" + CFLAGS="$CFLAGS $GSSAPI_CFLAGS" + LIBS="$LIBS $GSSAPI_LIBS" + + $as_echo "#define WITH_CREDSSP 1" >>confdefs.h + + else + echo + echo "CredSSP support requires GSSAPI, install the dependency" + echo "or disable the feature using --disable-credssp." + echo + exit 1 + fi + +fi + + +# xrandr +if test -n "$PKG_CONFIG"; then + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for XRANDR" >&5 +$as_echo_n "checking for XRANDR... " >&6; } + +if test -n "$XRANDR_CFLAGS"; then + pkg_cv_XRANDR_CFLAGS="$XRANDR_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"xrandr\""; } >&5 + ($PKG_CONFIG --exists --print-errors "xrandr") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_XRANDR_CFLAGS=`$PKG_CONFIG --cflags "xrandr" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$XRANDR_LIBS"; then + pkg_cv_XRANDR_LIBS="$XRANDR_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"xrandr\""; } >&5 + ($PKG_CONFIG --exists --print-errors "xrandr") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_XRANDR_LIBS=`$PKG_CONFIG --libs "xrandr" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + XRANDR_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "xrandr" 2>&1` + else + XRANDR_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "xrandr" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$XRANDR_PKG_ERRORS" >&5 + + HAVE_XRANDR=0 +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + HAVE_XRANDR=0 +else + XRANDR_CFLAGS=$pkg_cv_XRANDR_CFLAGS + XRANDR_LIBS=$pkg_cv_XRANDR_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + HAVE_XRANDR=1 +fi +fi +if test x"$HAVE_XRANDR" = "x1"; then + CFLAGS="$CFLAGS $XRANDR_CFLAGS" + LIBS="$LIBS $XRANDR_LIBS" + $as_echo "#define HAVE_XRANDR 1" >>confdefs.h + +fi + +# Xcursor +if test -n "$PKG_CONFIG"; then + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for XCURSOR" >&5 +$as_echo_n "checking for XCURSOR... " >&6; } + +if test -n "$XCURSOR_CFLAGS"; then + pkg_cv_XCURSOR_CFLAGS="$XCURSOR_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"xcursor\""; } >&5 + ($PKG_CONFIG --exists --print-errors "xcursor") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_XCURSOR_CFLAGS=`$PKG_CONFIG --cflags "xcursor" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$XCURSOR_LIBS"; then + pkg_cv_XCURSOR_LIBS="$XCURSOR_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"xcursor\""; } >&5 + ($PKG_CONFIG --exists --print-errors "xcursor") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_XCURSOR_LIBS=`$PKG_CONFIG --libs "xcursor" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + XCURSOR_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "xcursor" 2>&1` + else + XCURSOR_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "xcursor" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$XCURSOR_PKG_ERRORS" >&5 + + HAVE_XCURSOR=0 +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + HAVE_XCURSOR=0 +else + XCURSOR_CFLAGS=$pkg_cv_XCURSOR_CFLAGS + XCURSOR_LIBS=$pkg_cv_XCURSOR_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + HAVE_XCURSOR=1 +fi +fi +if test x"$HAVE_XCURSOR" = "x1"; then + CFLAGS="$CFLAGS $XCURSOR_CFLAGS" + LIBS="$LIBS $XCURSOR_LIBS" + $as_echo "#define HAVE_XCURSOR 1" >>confdefs.h + +else + echo + echo "rdesktop requires libXcursor, install the dependency" + echo + exit 1 +fi + +# libtasn1 +if test -n "$PKG_CONFIG"; then + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBTASN1" >&5 +$as_echo_n "checking for LIBTASN1... " >&6; } + +if test -n "$LIBTASN1_CFLAGS"; then + pkg_cv_LIBTASN1_CFLAGS="$LIBTASN1_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libtasn1\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libtasn1") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_LIBTASN1_CFLAGS=`$PKG_CONFIG --cflags "libtasn1" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$LIBTASN1_LIBS"; then + pkg_cv_LIBTASN1_LIBS="$LIBTASN1_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libtasn1\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libtasn1") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_LIBTASN1_LIBS=`$PKG_CONFIG --libs "libtasn1" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + LIBTASN1_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libtasn1" 2>&1` + else + LIBTASN1_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libtasn1" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$LIBTASN1_PKG_ERRORS" >&5 + + HAVE_LIBTASN1=0 +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + HAVE_LIBTASN1=0 +else + LIBTASN1_CFLAGS=$pkg_cv_LIBTASN1_CFLAGS + LIBTASN1_LIBS=$pkg_cv_LIBTASN1_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + HAVE_LIBTASN1=1 +fi +fi +if test x"$HAVE_LIBTASN1" = "x1"; then + CFLAGS="$CFLAGS $LIBTASN1_CFLAGS" + LIBS="$LIBS $LIBTASN1_LIBS" +else + echo + echo "rdesktop requires libtasn1. Please install the dependency" + echo + exit 1 +fi + +# nettle +if test -n "$PKG_CONFIG"; then + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for NETTLE" >&5 +$as_echo_n "checking for NETTLE... " >&6; } + +if test -n "$NETTLE_CFLAGS"; then + pkg_cv_NETTLE_CFLAGS="$NETTLE_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"nettle\""; } >&5 + ($PKG_CONFIG --exists --print-errors "nettle") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_NETTLE_CFLAGS=`$PKG_CONFIG --cflags "nettle" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$NETTLE_LIBS"; then + pkg_cv_NETTLE_LIBS="$NETTLE_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"nettle\""; } >&5 + ($PKG_CONFIG --exists --print-errors "nettle") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_NETTLE_LIBS=`$PKG_CONFIG --libs "nettle" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + NETTLE_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "nettle" 2>&1` + else + NETTLE_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "nettle" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$NETTLE_PKG_ERRORS" >&5 + + HAVE_NETTLE=0 +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + HAVE_NETTLE=0 +else + NETTLE_CFLAGS=$pkg_cv_NETTLE_CFLAGS + NETTLE_LIBS=$pkg_cv_NETTLE_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + HAVE_NETTLE=1 +fi +fi +if test x"$HAVE_NETTLE" = "x1"; then + CFLAGS="$CFLAGS $NETTLE_CFLAGS" + LIBS="$LIBS $NETTLE_LIBS" +else + echo + echo "rdesktop requires Nettle. Please install the dependency" + echo + exit 1 +fi + +# hogweed +if test -n "$PKG_CONFIG"; then + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for HOGWEED" >&5 +$as_echo_n "checking for HOGWEED... " >&6; } + +if test -n "$HOGWEED_CFLAGS"; then + pkg_cv_HOGWEED_CFLAGS="$HOGWEED_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"hogweed\""; } >&5 + ($PKG_CONFIG --exists --print-errors "hogweed") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_HOGWEED_CFLAGS=`$PKG_CONFIG --cflags "hogweed" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$HOGWEED_LIBS"; then + pkg_cv_HOGWEED_LIBS="$HOGWEED_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"hogweed\""; } >&5 + ($PKG_CONFIG --exists --print-errors "hogweed") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_HOGWEED_LIBS=`$PKG_CONFIG --libs "hogweed" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + HOGWEED_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "hogweed" 2>&1` + else + HOGWEED_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "hogweed" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$HOGWEED_PKG_ERRORS" >&5 + + HAVE_HOGWEED=0 +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + HAVE_HOGWEED=0 +else + HOGWEED_CFLAGS=$pkg_cv_HOGWEED_CFLAGS + HOGWEED_LIBS=$pkg_cv_HOGWEED_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + HAVE_HOGWEED=1 +fi +fi +if test x"$HAVE_HOGWEED" = "x1"; then + CFLAGS="$CFLAGS $HOGWEED_CFLAGS" + LIBS="$LIBS $HOGWEED_LIBS" +else + echo + echo "rdesktop requires hogweed. Please install the dependency" + echo + exit 1 +fi + +# GnuTLS + +if test -n "$PKG_CONFIG"; then + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNUTLS" >&5 +$as_echo_n "checking for GNUTLS... " >&6; } + +if test -n "$GNUTLS_CFLAGS"; then + pkg_cv_GNUTLS_CFLAGS="$GNUTLS_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gnutls >= 3.2.0\""; } >&5 + ($PKG_CONFIG --exists --print-errors "gnutls >= 3.2.0") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_GNUTLS_CFLAGS=`$PKG_CONFIG --cflags "gnutls >= 3.2.0" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$GNUTLS_LIBS"; then + pkg_cv_GNUTLS_LIBS="$GNUTLS_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gnutls >= 3.2.0\""; } >&5 + ($PKG_CONFIG --exists --print-errors "gnutls >= 3.2.0") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_GNUTLS_LIBS=`$PKG_CONFIG --libs "gnutls >= 3.2.0" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + GNUTLS_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "gnutls >= 3.2.0" 2>&1` + else + GNUTLS_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "gnutls >= 3.2.0" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$GNUTLS_PKG_ERRORS" >&5 + + HAVE_GNUTLS=0 +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + HAVE_GNUTLS=0 +else + GNUTLS_CFLAGS=$pkg_cv_GNUTLS_CFLAGS + GNUTLS_LIBS=$pkg_cv_GNUTLS_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + HAVE_GNUTLS=1 +fi +fi +if test x"$HAVE_GNUTLS" = "x1"; then + CFLAGS="$CFLAGS $GNUTLS_CFLAGS" + LIBS="$LIBS $GNUTLS_LIBS" +else + echo + echo "rdesktop requires GnuTLS. Please install the dependency" + echo + exit 1 +fi + +# Check whether --enable-smartcard was given. +if test "${enable_smartcard+set}" = set; then : + enableval=$enable_smartcard; +fi + +if test "x$enable_smartcard" != "xno"; then : + + case "$OSTYPE" in + darwin*) + ac_fn_c_check_header_mongrel "$LINENO" "PCSC/pcsclite.h" "ac_cv_header_PCSC_pcsclite_h" "$ac_includes_default" +if test "x$ac_cv_header_PCSC_pcsclite_h" = xyes; then : + WITH_SCARD=1 +else + WITH_SCARD=0 +fi + + + PCSCLITE_CFLAGS="" + PCSCLITE_LIBS="-framework PCSC" + ;; + *) + if test -n "$PKG_CONFIG"; then + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PCSCLITE" >&5 +$as_echo_n "checking for PCSCLITE... " >&6; } + +if test -n "$PCSCLITE_CFLAGS"; then + pkg_cv_PCSCLITE_CFLAGS="$PCSCLITE_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libpcsclite\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libpcsclite") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_PCSCLITE_CFLAGS=`$PKG_CONFIG --cflags "libpcsclite" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$PCSCLITE_LIBS"; then + pkg_cv_PCSCLITE_LIBS="$PCSCLITE_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libpcsclite\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libpcsclite") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_PCSCLITE_LIBS=`$PKG_CONFIG --libs "libpcsclite" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + PCSCLITE_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libpcsclite" 2>&1` + else + PCSCLITE_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libpcsclite" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$PCSCLITE_PKG_ERRORS" >&5 + + WITH_SCARD=0 +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + WITH_SCARD=0 +else + PCSCLITE_CFLAGS=$pkg_cv_PCSCLITE_CFLAGS + PCSCLITE_LIBS=$pkg_cv_PCSCLITE_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + WITH_SCARD=1 +fi + fi + ;; + esac + + if test x"$WITH_SCARD" = "x1"; then + SCARDOBJ="scard.o" + CFLAGS="$CFLAGS $PCSCLITE_CFLAGS" + LIBS="$LIBS $PCSCLITE_LIBS" + $as_echo "#define WITH_SCARD 1" >>confdefs.h + + else + echo + echo "SmartCard support requires PCSC, install the dependency" + echo "or disable the feature using --disable-smartcard." + echo + exit 1 + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PCSC-lite >= 1.6.0 (PnP/Notifications support)" >&5 +$as_echo_n "checking for PCSC-lite >= 1.6.0 (PnP/Notifications support)... " >&6; } + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PNP_NOTIFICATIONS" >&5 +$as_echo_n "checking for PNP_NOTIFICATIONS... " >&6; } + +if test -n "$PNP_NOTIFICATIONS_CFLAGS"; then + pkg_cv_PNP_NOTIFICATIONS_CFLAGS="$PNP_NOTIFICATIONS_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libpcsclite >= 1.6.0\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libpcsclite >= 1.6.0") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_PNP_NOTIFICATIONS_CFLAGS=`$PKG_CONFIG --cflags "libpcsclite >= 1.6.0" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$PNP_NOTIFICATIONS_LIBS"; then + pkg_cv_PNP_NOTIFICATIONS_LIBS="$PNP_NOTIFICATIONS_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libpcsclite >= 1.6.0\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libpcsclite >= 1.6.0") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_PNP_NOTIFICATIONS_LIBS=`$PKG_CONFIG --libs "libpcsclite >= 1.6.0" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + PNP_NOTIFICATIONS_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libpcsclite >= 1.6.0" 2>&1` + else + PNP_NOTIFICATIONS_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libpcsclite >= 1.6.0" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$PNP_NOTIFICATIONS_PKG_ERRORS" >&5 + + WITH_PNP_NOTIFICATIONS=0 +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + WITH_PNP_NOTIFICATIONS=0 +else + PNP_NOTIFICATIONS_CFLAGS=$pkg_cv_PNP_NOTIFICATIONS_CFLAGS + PNP_NOTIFICATIONS_LIBS=$pkg_cv_PNP_NOTIFICATIONS_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + WITH_PNP_NOTIFICATIONS=1 +fi + $as_echo "#define WITH_PNP_NOTIFICATIONS 1" >>confdefs.h + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for old version of PCSC" >&5 +$as_echo_n "checking for old version of PCSC... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + #ifdef __APPLE__ + #include + #include + #else + #include + #endif + +int +main () +{ +SCardControl(NULL, NULL, 0, NULL, NULL); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +$as_echo "#define WITH_PCSC120 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + +fi + + +# +# Alignment +# +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if architecture needs alignment" >&5 +$as_echo_n "checking if architecture needs alignment... " >&6; } +if test "$cross_compiling" = yes; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: assuming yes" >&5 +$as_echo "assuming yes" >&6; } + $as_echo "#define NEED_ALIGN 1" >>confdefs.h + +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +int main(int argc, char **argv) +{ + unsigned char test[8] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 }; + signal(SIGBUS, exit); + signal(SIGABRT, exit); + signal(SIGSEGV, exit); + if (*((unsigned int *)(test + 1)) != 0x55443322 && *((unsigned int *)(test + 1)) != 0x22334455) { + return 1; + } + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + $as_echo "#define NEED_ALIGN 1" >>confdefs.h + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + + +# +# EGD +# + +# Check whether --with-egd-socket was given. +if test "${with_egd_socket+set}" = set; then : + withval=$with_egd_socket; EGD_SOCKET="$withval" +else + EGD_SOCKET="/var/run/egd-pool" + +fi + +cat >>confdefs.h <<_ACEOF +#define EGD_SOCKET "$EGD_SOCKET" +_ACEOF + + + +# +# sound +# + +sound="yes" + +# Check whether --with-sound was given. +if test "${with_sound+set}" = set; then : + withval=$with_sound; + sound="$withval" + +fi + + +ac_fn_c_check_header_mongrel "$LINENO" "sys/soundcard.h" "ac_cv_header_sys_soundcard_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_soundcard_h" = xyes; then : + HAVE_OSS=1 +else + HAVE_OSS=0 +fi + + +ac_fn_c_check_header_mongrel "$LINENO" "dmedia/audio.h" "ac_cv_header_dmedia_audio_h" "$ac_includes_default" +if test "x$ac_cv_header_dmedia_audio_h" = xyes; then : + HAVE_SGI=1 +else + HAVE_SGI=0 +fi + + +ac_fn_c_check_header_mongrel "$LINENO" "sys/audioio.h" "ac_cv_header_sys_audioio_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_audioio_h" = xyes; then : + HAVE_SUN=1 +else + HAVE_SUN=0 +fi + + + +# Check whether --enable-static-libsamplerate was given. +if test "${enable_static_libsamplerate+set}" = set; then : + enableval=$enable_static_libsamplerate; static_libsamplerate=yes +else + static_libsamplerate=no +fi + + +if test -n "$PKG_CONFIG"; then + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBAO" >&5 +$as_echo_n "checking for LIBAO... " >&6; } + +if test -n "$LIBAO_CFLAGS"; then + pkg_cv_LIBAO_CFLAGS="$LIBAO_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"ao\""; } >&5 + ($PKG_CONFIG --exists --print-errors "ao") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_LIBAO_CFLAGS=`$PKG_CONFIG --cflags "ao" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$LIBAO_LIBS"; then + pkg_cv_LIBAO_LIBS="$LIBAO_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"ao\""; } >&5 + ($PKG_CONFIG --exists --print-errors "ao") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_LIBAO_LIBS=`$PKG_CONFIG --libs "ao" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + LIBAO_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "ao" 2>&1` + else + LIBAO_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "ao" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$LIBAO_PKG_ERRORS" >&5 + + HAVE_LIBAO=0 +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + HAVE_LIBAO=0 +else + LIBAO_CFLAGS=$pkg_cv_LIBAO_CFLAGS + LIBAO_LIBS=$pkg_cv_LIBAO_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + HAVE_LIBAO=1 +fi + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PULSE" >&5 +$as_echo_n "checking for PULSE... " >&6; } + +if test -n "$PULSE_CFLAGS"; then + pkg_cv_PULSE_CFLAGS="$PULSE_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libpulse\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libpulse") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_PULSE_CFLAGS=`$PKG_CONFIG --cflags "libpulse" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$PULSE_LIBS"; then + pkg_cv_PULSE_LIBS="$PULSE_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libpulse\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libpulse") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_PULSE_LIBS=`$PKG_CONFIG --libs "libpulse" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + PULSE_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libpulse" 2>&1` + else + PULSE_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libpulse" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$PULSE_PKG_ERRORS" >&5 + + HAVE_PULSE=0 +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + HAVE_PULSE=0 +else + PULSE_CFLAGS=$pkg_cv_PULSE_CFLAGS + PULSE_LIBS=$pkg_cv_PULSE_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + HAVE_PULSE=1 +fi + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ALSA" >&5 +$as_echo_n "checking for ALSA... " >&6; } + +if test -n "$ALSA_CFLAGS"; then + pkg_cv_ALSA_CFLAGS="$ALSA_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"alsa\""; } >&5 + ($PKG_CONFIG --exists --print-errors "alsa") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_ALSA_CFLAGS=`$PKG_CONFIG --cflags "alsa" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$ALSA_LIBS"; then + pkg_cv_ALSA_LIBS="$ALSA_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"alsa\""; } >&5 + ($PKG_CONFIG --exists --print-errors "alsa") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_ALSA_LIBS=`$PKG_CONFIG --libs "alsa" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + ALSA_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "alsa" 2>&1` + else + ALSA_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "alsa" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$ALSA_PKG_ERRORS" >&5 + + HAVE_ALSA=0 +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + HAVE_ALSA=0 +else + ALSA_CFLAGS=$pkg_cv_ALSA_CFLAGS + ALSA_LIBS=$pkg_cv_ALSA_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + HAVE_ALSA=1 +fi + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBSAMPLERATE" >&5 +$as_echo_n "checking for LIBSAMPLERATE... " >&6; } + +if test -n "$LIBSAMPLERATE_CFLAGS"; then + pkg_cv_LIBSAMPLERATE_CFLAGS="$LIBSAMPLERATE_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"samplerate\""; } >&5 + ($PKG_CONFIG --exists --print-errors "samplerate") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_LIBSAMPLERATE_CFLAGS=`$PKG_CONFIG --cflags "samplerate" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$LIBSAMPLERATE_LIBS"; then + pkg_cv_LIBSAMPLERATE_LIBS="$LIBSAMPLERATE_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"samplerate\""; } >&5 + ($PKG_CONFIG --exists --print-errors "samplerate") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_LIBSAMPLERATE_LIBS=`$PKG_CONFIG --libs "samplerate" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + LIBSAMPLERATE_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "samplerate" 2>&1` + else + LIBSAMPLERATE_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "samplerate" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$LIBSAMPLERATE_PKG_ERRORS" >&5 + + HAVE_LIBSAMPLERATE=0 +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + HAVE_LIBSAMPLERATE=0 +else + LIBSAMPLERATE_CFLAGS=$pkg_cv_LIBSAMPLERATE_CFLAGS + LIBSAMPLERATE_LIBS=$pkg_cv_LIBSAMPLERATE_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + HAVE_LIBSAMPLERATE=1 +fi + if test x"$HAVE_LIBSAMPLERATE" = "x1"; then + $as_echo "#define HAVE_LIBSAMPLERATE 1" >>confdefs.h + + if test x"$static_libsamplerate" = "xyes"; then + _libsamplerate_libdir=`$PKG_CONFIG --errors-to-stdout --variable=libdir samplerate` + LIBSAMPLERATE_LIBS="$_libsamplerate_libdir""/libsamplerate.a" + LIBSAMPLERATE_LIBS="$LIBSAMPLERATE_LIBS -lm" + fi + fi +fi + +if test "$sound" != "no"; then + SOUNDOBJ="$SOUNDOBJ rdpsnd.o rdpsnd_dsp.o" + CFLAGS="$CFLAGS $LIBSAMPLERATE_CFLAGS" + LIBS="$LIBS $LIBSAMPLERATE_LIBS" + $as_echo "#define WITH_RDPSND 1" >>confdefs.h + +fi + +case $sound in + yes) + if test x"$HAVE_OSS" = "x1"; then + SOUNDOBJ="$SOUNDOBJ rdpsnd_oss.o" + $as_echo "#define RDPSND_OSS 1" >>confdefs.h + + fi + + if test x"$HAVE_SGI" = "x1"; then + SOUNDOBJ="$SOUNDOBJ rdpsnd_sgi.o" + LIBS="$LIBS -laudio" + $as_echo "#define RDPSND_SGI 1" >>confdefs.h + + fi + + if test x"$HAVE_SUN" = "x1"; then + SOUNDOBJ="$SOUNDOBJ rdpsnd_sun.o" + $as_echo "#define RDPSND_SUN 1" >>confdefs.h + + fi + + if test x"$HAVE_ALSA" = "x1"; then + SOUNDOBJ="$SOUNDOBJ rdpsnd_alsa.o" + CFLAGS="$CFLAGS $ALSA_CFLAGS" + LIBS="$LIBS $ALSA_LIBS" + $as_echo "#define RDPSND_ALSA 1" >>confdefs.h + + fi + + if test x"$HAVE_PULSE" = "x1"; then + SOUNDOBJ="$SOUNDOBJ rdpsnd_pulse.o" + CFLAGS="$CFLAGS $PULSE_CFLAGS" + LIBS="$LIBS $PULSE_LIBS" + $as_echo "#define RDPSND_PULSE 1" >>confdefs.h + + fi + + if test x"$HAVE_LIBAO" = "x1"; then + SOUNDOBJ="$SOUNDOBJ rdpsnd_libao.o" + CFLAGS="$CFLAGS $LIBAO_CFLAGS" + LIBS="$LIBS $LIBAO_LIBS" + $as_echo "#define RDPSND_LIBAO 1" >>confdefs.h + + fi + + ;; + + oss) + if test x"$HAVE_OSS" = "x1"; then + SOUNDOBJ="$SOUNDOBJ rdpsnd_oss.o" + $as_echo "#define RDPSND_OSS 1" >>confdefs.h + + else + as_fn_error $? "Selected sound system is not available." "$LINENO" 5 + fi + ;; + + sgi) + if test x"$HAVE_SGI" = "x1"; then + SOUNDOBJ="$SOUNDOBJ rdpsnd_sgi.o" + LIBS="$LIBS -laudio" + $as_echo "#define RDPSND_SGI 1" >>confdefs.h + + else + as_fn_error $? "Selected sound system is not available." "$LINENO" 5 + fi + ;; + + sun) + if test x"$HAVE_SUN" = "x1"; then + SOUNDOBJ="$SOUNDOBJ rdpsnd_sun.o" + $as_echo "#define RDPSND_SUN 1" >>confdefs.h + + else + as_fn_error $? "Selected sound system is not available." "$LINENO" 5 + fi + ;; + + alsa) + if test x"$HAVE_ALSA" = "x1"; then + SOUNDOBJ="$SOUNDOBJ rdpsnd_alsa.o" + CFLAGS="$CFLAGS $ALSA_CFLAGS" + LIBS="$LIBS $ALSA_LIBS" + $as_echo "#define RDPSND_ALSA 1" >>confdefs.h + + else + as_fn_error $? "Selected sound system is not available." "$LINENO" 5 + fi + ;; + + pulse) + if test x"$HAVE_PULSE" = "x1"; then + SOUNDOBJ="$SOUNDOBJ rdpsnd_pulse.o" + CFLAGS="$CFLAGS $PULSE_CFLAGS" + LIBS="$LIBS $PULSE_LIBS" + $as_echo "#define RDPSND_PULSE 1" >>confdefs.h + + else + as_fn_error $? "Selected sound system is not available." "$LINENO" 5 + fi + ;; + + libao) + if test x"$HAVE_LIBAO" = "x1"; then + SOUNDOBJ="$SOUNDOBJ rdpsnd_libao.o" + CFLAGS="$CFLAGS $LIBAO_CFLAGS" + LIBS="$LIBS $LIBAO_LIBS" + $as_echo "#define RDPSND_LIBAO 1" >>confdefs.h + + else + as_fn_error $? "Selected sound system is not available." "$LINENO" 5 + fi + ;; + + no) + ;; + + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: sound support disabled" >&5 +$as_echo "$as_me: WARNING: sound support disabled" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Currently supported systems are Open Sound System (oss), SGI AL (sgi), Sun/BSD (sun), ALSA (alsa), PulseAudio (pulse) and libao" >&5 +$as_echo "$as_me: WARNING: Currently supported systems are Open Sound System (oss), SGI AL (sgi), Sun/BSD (sun), ALSA (alsa), PulseAudio (pulse) and libao" >&2;} + ;; +esac + + + +# +# dirfd +# + + + + + + ac_header_dirent=no +for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do + as_ac_Header=`$as_echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh` +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5 +$as_echo_n "checking for $ac_hdr that defines DIR... " >&6; } +if eval \${$as_ac_Header+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include <$ac_hdr> + +int +main () +{ +if ((DIR *) 0) +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$as_ac_Header=yes" +else + eval "$as_ac_Header=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$as_ac_Header + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_hdr" | $as_tr_cpp` 1 +_ACEOF + +ac_header_dirent=$ac_hdr; break +fi + +done +# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. +if test $ac_header_dirent = dirent.h; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 +$as_echo_n "checking for library containing opendir... " >&6; } +if ${ac_cv_search_opendir+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char opendir (); +int +main () +{ +return opendir (); + ; + return 0; +} +_ACEOF +for ac_lib in '' dir; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_opendir=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_opendir+:} false; then : + break +fi +done +if ${ac_cv_search_opendir+:} false; then : + +else + ac_cv_search_opendir=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 +$as_echo "$ac_cv_search_opendir" >&6; } +ac_res=$ac_cv_search_opendir +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 +$as_echo_n "checking for library containing opendir... " >&6; } +if ${ac_cv_search_opendir+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char opendir (); +int +main () +{ +return opendir (); + ; + return 0; +} +_ACEOF +for ac_lib in '' x; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_opendir=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_opendir+:} false; then : + break +fi +done +if ${ac_cv_search_opendir+:} false; then : + +else + ac_cv_search_opendir=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 +$as_echo "$ac_cv_search_opendir" >&6; } +ac_res=$ac_cv_search_opendir +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + +fi + + dirfd_headers=' +#if HAVE_DIRENT_H +# include +#else /* not HAVE_DIRENT_H */ +# define dirent direct +# if HAVE_SYS_NDIR_H +# include +# endif /* HAVE_SYS_NDIR_H */ +# if HAVE_SYS_DIR_H +# include +# endif /* HAVE_SYS_DIR_H */ +# if HAVE_NDIR_H +# include +# endif /* HAVE_NDIR_H */ +#endif /* HAVE_DIRENT_H */ +' + for ac_func in dirfd +do : + ac_fn_c_check_func "$LINENO" "dirfd" "ac_cv_func_dirfd" +if test "x$ac_cv_func_dirfd" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_DIRFD 1 +_ACEOF + +fi +done + + ac_fn_c_check_decl "$LINENO" "dirfd" "ac_cv_have_decl_dirfd" "$dirfd_headers +" +if test "x$ac_cv_have_decl_dirfd" = xyes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_DIRFD $ac_have_decl +_ACEOF + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether dirfd is a macro" >&5 +$as_echo_n "checking whether dirfd is a macro... " >&6; } +if ${jm_cv_func_dirfd_macro+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$dirfd_headers +#ifdef dirfd + dirent_header_defines_dirfd +#endif +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "dirent_header_defines_dirfd" >/dev/null 2>&1; then : + jm_cv_func_dirfd_macro=yes +else + jm_cv_func_dirfd_macro=no +fi +rm -f conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $jm_cv_func_dirfd_macro" >&5 +$as_echo "$jm_cv_func_dirfd_macro" >&6; } + + # Use the replacement only if we have no function, macro, + # or declaration with that name. + if test $ac_cv_func_dirfd,$ac_cv_have_decl_dirfd,$jm_cv_func_dirfd_macro \ + = no,no,no; then + ac_fn_c_check_func "$LINENO" "dirfd" "ac_cv_func_dirfd" +if test "x$ac_cv_func_dirfd" = xyes; then : + $as_echo "#define HAVE_DIRFD 1" >>confdefs.h + +else + case " $LIBOBJS " in + *" dirfd.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS dirfd.$ac_objext" + ;; +esac + +fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to get the file descriptor associated with an open DIR*" >&5 +$as_echo_n "checking how to get the file descriptor associated with an open DIR*... " >&6; } +if ${gl_cv_sys_dir_fd_member_name+:} false; then : + $as_echo_n "(cached) " >&6 +else + + dirfd_save_CFLAGS=$CFLAGS + for ac_expr in d_fd dd_fd; do + + CFLAGS="$CFLAGS -DDIR_FD_MEMBER_NAME=$ac_expr" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$dirfd_headers + +int +main () +{ +DIR *dir_p = opendir("."); (void) dir_p->DIR_FD_MEMBER_NAME; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + dir_fd_found=yes + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS=$dirfd_save_CFLAGS + test "$dir_fd_found" = yes && break + done + test "$dir_fd_found" = yes || ac_expr=no_such_member + + gl_cv_sys_dir_fd_member_name=$ac_expr + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_sys_dir_fd_member_name" >&5 +$as_echo "$gl_cv_sys_dir_fd_member_name" >&6; } + if test $gl_cv_sys_dir_fd_member_name != no_such_member; then + +cat >>confdefs.h <<_ACEOF +#define DIR_FD_MEMBER_NAME $gl_cv_sys_dir_fd_member_name +_ACEOF + + fi + + fi + + +# +# iconv +# + + + + + + + +# Check whether --with-libiconv-prefix was given. +if test "${with_libiconv_prefix+set}" = set; then : + withval=$with_libiconv_prefix; + for dir in `echo "$withval" | tr : ' '`; do + if test -d $dir/include; then CPPFLAGS="$CPPFLAGS -I$dir/include"; fi + if test -d $dir/lib; then LDFLAGS="$LDFLAGS -L$dir/lib"; fi + done + +fi + + ac_fn_c_check_header_mongrel "$LINENO" "iconv.h" "ac_cv_header_iconv_h" "$ac_includes_default" +if test "x$ac_cv_header_iconv_h" = xyes; then : + $as_echo "#define HAVE_ICONV_H 1" >>confdefs.h + +fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for iconv" >&5 +$as_echo_n "checking for iconv... " >&6; } +if ${am_cv_func_iconv+:} false; then : + $as_echo_n "(cached) " >&6 +else + + am_cv_func_iconv="no, consider installing GNU libiconv" + am_cv_lib_iconv=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +int +main () +{ +iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + am_cv_func_iconv=yes +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test "$am_cv_func_iconv" != yes; then + am_save_LIBS="$LIBS" + LIBS="$LIBS -liconv" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +int +main () +{ +iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + am_cv_lib_iconv=yes + am_cv_func_iconv=yes +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LIBS="$am_save_LIBS" + fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_func_iconv" >&5 +$as_echo "$am_cv_func_iconv" >&6; } + if test "$am_cv_func_iconv" = yes; then + +$as_echo "#define HAVE_ICONV 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for iconv declaration" >&5 +$as_echo_n "checking for iconv declaration... " >&6; } + if ${am_cv_proto_iconv+:} false; then : + $as_echo_n "(cached) " >&6 +else + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +extern +#ifdef __cplusplus +"C" +#endif +#if defined(__STDC__) || defined(__cplusplus) +size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); +#else +size_t iconv(); +#endif + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + am_cv_proto_iconv_arg1="" +else + am_cv_proto_iconv_arg1="const" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);" +fi + + am_cv_proto_iconv=`echo "$am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${ac_t:- + }$am_cv_proto_iconv" >&5 +$as_echo "${ac_t:- + }$am_cv_proto_iconv" >&6; } + +cat >>confdefs.h <<_ACEOF +#define ICONV_CONST $am_cv_proto_iconv_arg1 +_ACEOF + + fi + LIBICONV= + if test "$am_cv_lib_iconv" = yes; then + LIBICONV="-liconv" + fi + + +LIBS="$LIBS $LIBICONV" + +# +# socklen_t +# from curl + + + + + ac_fn_c_check_type "$LINENO" "socklen_t" "ac_cv_type_socklen_t" "#include +#include +" +if test "x$ac_cv_type_socklen_t" = xyes; then : + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for socklen_t equivalent" >&5 +$as_echo_n "checking for socklen_t equivalent... " >&6; } + if ${socklen_t_cv_equiv+:} false; then : + $as_echo_n "(cached) " >&6 +else + + # Systems have either "struct sockaddr *" or + # "void *" as the second argument to getpeername + socklen_t_cv_equiv= + for arg2 in "struct sockaddr" void; do + for t in int size_t unsigned long "unsigned long"; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + #include + + int getpeername (int, $arg2 *, $t *); + +int +main () +{ + + $t len; + getpeername(0,0,&len); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + socklen_t_cv_equiv="$t" + break + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done + done + + if test "x$socklen_t_cv_equiv" = x; then + as_fn_error $? "Cannot find a type to use in place of socklen_t" "$LINENO" 5 + fi + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $socklen_t_cv_equiv" >&5 +$as_echo "$socklen_t_cv_equiv" >&6; } + +cat >>confdefs.h <<_ACEOF +#define socklen_t $socklen_t_cv_equiv +_ACEOF + +fi + + + +# +# statfs stuff +# +for ac_header in sys/vfs.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "sys/vfs.h" "ac_cv_header_sys_vfs_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_vfs_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SYS_VFS_H 1 +_ACEOF + +fi + +done + +for ac_header in sys/statvfs.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "sys/statvfs.h" "ac_cv_header_sys_statvfs_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_statvfs_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SYS_STATVFS_H 1 +_ACEOF + +fi + +done + +for ac_header in sys/statfs.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "sys/statfs.h" "ac_cv_header_sys_statfs_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_statfs_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SYS_STATFS_H 1 +_ACEOF + +fi + +done + +for ac_header in sys/param.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "sys/param.h" "ac_cv_header_sys_param_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_param_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SYS_PARAM_H 1 +_ACEOF + +fi + +done + + +mount_includes="\ + $ac_includes_default + #if HAVE_SYS_PARAM_H + # include + #endif + " + +for ac_header in sys/mount.h +do : + ac_fn_c_check_header_compile "$LINENO" "sys/mount.h" "ac_cv_header_sys_mount_h" "$mount_includes +" +if test "x$ac_cv_header_sys_mount_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SYS_MOUNT_H 1 +_ACEOF + +fi + +done + + +################################################# +# these tests are taken from the GNU fileutils package +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to get filesystem space usage..." >&5 +$as_echo "$as_me: checking how to get filesystem space usage..." >&6;} +space=no + +# Test for statvfs64. +if test $space = no; then + # SVR4 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking statvfs64 function (SVR4)" >&5 +$as_echo_n "checking statvfs64 function (SVR4)... " >&6; } +if ${fu_cv_sys_stat_statvfs64+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + fu_cv_sys_stat_statvfs64=cross +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#if defined(HAVE_UNISTD_H) +#include +#endif +#include +#include + main () + { + struct statvfs64 fsd; + exit (statvfs64 (".", &fsd)); + } +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + fu_cv_sys_stat_statvfs64=yes +else + fu_cv_sys_stat_statvfs64=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $fu_cv_sys_stat_statvfs64" >&5 +$as_echo "$fu_cv_sys_stat_statvfs64" >&6; } + if test $fu_cv_sys_stat_statvfs64 = yes; then + space=yes + +$as_echo "#define STAT_STATVFS64 1" >>confdefs.h + + fi +fi + +# Perform only the link test since it seems there are no variants of the +# statvfs function. This check is more than just AC_CHECK_FUNCS(statvfs) +# because that got a false positive on SCO OSR5. Adding the declaration +# of a `struct statvfs' causes this test to fail (as it should) on such +# systems. That system is reported to work fine with STAT_STATFS4 which +# is what it gets when this test fails. +if test $space = no; then + # SVR4 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking statvfs function (SVR4)" >&5 +$as_echo_n "checking statvfs function (SVR4)... " >&6; } +if ${fu_cv_sys_stat_statvfs+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +int +main () +{ +struct statvfs fsd; statvfs (0, &fsd); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + fu_cv_sys_stat_statvfs=yes +else + fu_cv_sys_stat_statvfs=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $fu_cv_sys_stat_statvfs" >&5 +$as_echo "$fu_cv_sys_stat_statvfs" >&6; } + if test $fu_cv_sys_stat_statvfs = yes; then + space=yes + +$as_echo "#define STAT_STATVFS 1" >>confdefs.h + + fi +fi + +if test $space = no; then + # DEC Alpha running OSF/1 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 3-argument statfs function (DEC OSF/1)" >&5 +$as_echo_n "checking for 3-argument statfs function (DEC OSF/1)... " >&6; } + if ${fu_cv_sys_stat_statfs3_osf1+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + fu_cv_sys_stat_statfs3_osf1=no +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +#include + main () + { + struct statfs fsd; + fsd.f_fsize = 0; + exit (statfs (".", &fsd, sizeof (struct statfs))); + } +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + fu_cv_sys_stat_statfs3_osf1=yes +else + fu_cv_sys_stat_statfs3_osf1=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi + + + +#C_MSG_RESULT($fu_cv_sys_stat_statfs3_osf1) + if test $fu_cv_sys_stat_statfs3_osf1 = yes; then + space=yes + +$as_echo "#define STAT_STATFS3_OSF1 1" >>confdefs.h + + fi +fi + +if test $space = no; then +# AIX + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for two-argument statfs with statfs.bsize member (AIX, 4.3BSD)" >&5 +$as_echo_n "checking for two-argument statfs with statfs.bsize member (AIX, 4.3BSD)... " >&6; } + if ${fu_cv_sys_stat_statfs2_bsize+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + fu_cv_sys_stat_statfs2_bsize=no +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#ifdef HAVE_SYS_PARAM_H +#include +#endif +#ifdef HAVE_SYS_MOUNT_H +#include +#endif +#ifdef HAVE_SYS_VFS_H +#include +#endif + main () + { + struct statfs fsd; + fsd.f_bsize = 0; + exit (statfs (".", &fsd)); + } +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + fu_cv_sys_stat_statfs2_bsize=yes +else + fu_cv_sys_stat_statfs2_bsize=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $fu_cv_sys_stat_statfs2_bsize" >&5 +$as_echo "$fu_cv_sys_stat_statfs2_bsize" >&6; } + if test $fu_cv_sys_stat_statfs2_bsize = yes; then + space=yes + +$as_echo "#define STAT_STATFS2_BSIZE 1" >>confdefs.h + + fi +fi + +if test $space = no; then +# SVR3 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for four-argument statfs (AIX-3.2.5, SVR3)" >&5 +$as_echo_n "checking for four-argument statfs (AIX-3.2.5, SVR3)... " >&6; } + if ${fu_cv_sys_stat_statfs4+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + fu_cv_sys_stat_statfs4=no +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include + main () + { + struct statfs fsd; + exit (statfs (".", &fsd, sizeof fsd, 0)); + } +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + fu_cv_sys_stat_statfs4=yes +else + fu_cv_sys_stat_statfs4=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $fu_cv_sys_stat_statfs4" >&5 +$as_echo "$fu_cv_sys_stat_statfs4" >&6; } + if test $fu_cv_sys_stat_statfs4 = yes; then + space=yes + +$as_echo "#define STAT_STATFS4 1" >>confdefs.h + + fi +fi + +if test $space = no; then +# 4.4BSD and NetBSD + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for two-argument statfs with statfs.fsize member (4.4BSD and NetBSD)" >&5 +$as_echo_n "checking for two-argument statfs with statfs.fsize member (4.4BSD and NetBSD)... " >&6; } + if ${fu_cv_sys_stat_statfs2_fsize+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + fu_cv_sys_stat_statfs2_fsize=no +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#ifdef HAVE_SYS_PARAM_H +#include +#endif +#ifdef HAVE_SYS_MOUNT_H +#include +#endif + main () + { + struct statfs fsd; + fsd.f_fsize = 0; + exit (statfs (".", &fsd)); + } +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + fu_cv_sys_stat_statfs2_fsize=yes +else + fu_cv_sys_stat_statfs2_fsize=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $fu_cv_sys_stat_statfs2_fsize" >&5 +$as_echo "$fu_cv_sys_stat_statfs2_fsize" >&6; } + if test $fu_cv_sys_stat_statfs2_fsize = yes; then + space=yes + +$as_echo "#define STAT_STATFS2_FSIZE 1" >>confdefs.h + + fi +fi + +if test $space = no; then + # Ultrix + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for two-argument statfs with struct fs_data (Ultrix)" >&5 +$as_echo_n "checking for two-argument statfs with struct fs_data (Ultrix)... " >&6; } + if ${fu_cv_sys_stat_fs_data+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + fu_cv_sys_stat_fs_data=no +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#ifdef HAVE_SYS_PARAM_H +#include +#endif +#ifdef HAVE_SYS_MOUNT_H +#include +#endif +#ifdef HAVE_SYS_FS_TYPES_H +#include +#endif + main () + { + struct fs_data fsd; + /* Ultrix's statfs returns 1 for success, + 0 for not mounted, -1 for failure. */ + exit (statfs (".", &fsd) != 1); + } +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + fu_cv_sys_stat_fs_data=yes +else + fu_cv_sys_stat_fs_data=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $fu_cv_sys_stat_fs_data" >&5 +$as_echo "$fu_cv_sys_stat_fs_data" >&6; } + if test $fu_cv_sys_stat_fs_data = yes; then + space=yes + +$as_echo "#define STAT_STATFS2_FS_DATA 1" >>confdefs.h + + fi +fi + + statxfs_includes="\ +$ac_includes_default +#if HAVE_SYS_STATVFS_H +# include +#endif +#if HAVE_SYS_VFS_H +# include +#endif +#if !HAVE_SYS_STATVFS_H && !HAVE_SYS_VFS_H +# if HAVE_SYS_MOUNT_H && HAVE_SYS_PARAM_H +/* NetBSD 1.5.2 needs these, for the declaration of struct statfs. */ +# include +# include +# elif HAVE_NETINET_IN_H && HAVE_NFS_NFS_CLNT_H && HAVE_NFS_VFS_H +/* Ultrix 4.4 needs these for the declaration of struct statfs. */ +# include +# include +# include +# endif +#endif +" + +ac_fn_c_check_member "$LINENO" "struct statfs" "f_namemax" "ac_cv_member_struct_statfs_f_namemax" "$statxfs_includes +" +if test "x$ac_cv_member_struct_statfs_f_namemax" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_STATFS_F_NAMEMAX 1 +_ACEOF + + +fi + +ac_fn_c_check_member "$LINENO" "struct statvfs" "f_namemax" "ac_cv_member_struct_statvfs_f_namemax" "$statxfs_includes +" +if test "x$ac_cv_member_struct_statvfs_f_namemax" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_STATVFS_F_NAMEMAX 1 +_ACEOF + + +fi + +ac_fn_c_check_member "$LINENO" "struct statfs" "f_namelen" "ac_cv_member_struct_statfs_f_namelen" "$statxfs_includes +" +if test "x$ac_cv_member_struct_statfs_f_namelen" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_STATFS_F_NAMELEN 1 +_ACEOF + + +fi + +ac_fn_c_check_member "$LINENO" "struct statvfs" "f_namelen" "ac_cv_member_struct_statvfs_f_namelen" "$statxfs_includes +" +if test "x$ac_cv_member_struct_statvfs_f_namelen" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_STATVFS_F_NAMELEN 1 +_ACEOF + + +fi + + +# +# Large file support +# +# Check whether --enable-largefile was given. +if test "${enable_largefile+set}" = set; then : + enableval=$enable_largefile; +fi + +if test "$enable_largefile" != no; then + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 +$as_echo_n "checking for special C compiler options needed for large files... " >&6; } +if ${ac_cv_sys_largefile_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_sys_largefile_CC=no + if test "$GCC" != yes; then + ac_save_CC=$CC + while :; do + # IRIX 6.2 and later do not support large files by default, + # so use the C compiler's -n32 option if that helps. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF + if ac_fn_c_try_compile "$LINENO"; then : + break +fi +rm -f core conftest.err conftest.$ac_objext + CC="$CC -n32" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_largefile_CC=' -n32'; break +fi +rm -f core conftest.err conftest.$ac_objext + break + done + CC=$ac_save_CC + rm -f conftest.$ac_ext + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 +$as_echo "$ac_cv_sys_largefile_CC" >&6; } + if test "$ac_cv_sys_largefile_CC" != no; then + CC=$CC$ac_cv_sys_largefile_CC + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 +$as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } +if ${ac_cv_sys_file_offset_bits+:} false; then : + $as_echo_n "(cached) " >&6 +else + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_file_offset_bits=no; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _FILE_OFFSET_BITS 64 +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_file_offset_bits=64; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cv_sys_file_offset_bits=unknown + break +done +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 +$as_echo "$ac_cv_sys_file_offset_bits" >&6; } +case $ac_cv_sys_file_offset_bits in #( + no | unknown) ;; + *) +cat >>confdefs.h <<_ACEOF +#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits +_ACEOF +;; +esac +rm -rf conftest* + if test $ac_cv_sys_file_offset_bits = unknown; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 +$as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; } +if ${ac_cv_sys_large_files+:} false; then : + $as_echo_n "(cached) " >&6 +else + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_large_files=no; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _LARGE_FILES 1 +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_large_files=1; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cv_sys_large_files=unknown + break +done +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 +$as_echo "$ac_cv_sys_large_files" >&6; } +case $ac_cv_sys_large_files in #( + no | unknown) ;; + *) +cat >>confdefs.h <<_ACEOF +#define _LARGE_FILES $ac_cv_sys_large_files +_ACEOF +;; +esac +rm -rf conftest* + fi + + +fi + + +# +# mntent +# +ac_fn_c_check_header_mongrel "$LINENO" "mntent.h" "ac_cv_header_mntent_h" "$ac_includes_default" +if test "x$ac_cv_header_mntent_h" = xyes; then : + $as_echo "#define HAVE_MNTENT_H 1" >>confdefs.h + +fi + + +for ac_func in setmntent +do : + ac_fn_c_check_func "$LINENO" "setmntent" "ac_cv_func_setmntent" +if test "x$ac_cv_func_setmntent" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SETMNTENT 1 +_ACEOF + +fi +done + + +# +# IPv6 +# + +# Check whether --with-ipv6 was given. +if test "${with_ipv6+set}" = set; then : + withval=$with_ipv6; + if test $withval != "no"; + then + $as_echo "#define IPv6 1" >>confdefs.h + + fi + +fi + + +# +# target-specific stuff +# +case "$host" in +*-*-hpux*) + CFLAGS="$CFLAGS -D_XOPEN_SOURCE_EXTENDED" + ;; +*-*-irix6.5*) + LIBS="-L$ssldir/lib32 $LIBS" + CFLAGS="$CFLAGS -D__SGI_IRIX__" + ;; +esac + +ac_config_files="$ac_config_files Makefile" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Transform confdefs.h into DEFS. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +# +# If the first sed substitution is executed (which looks for macros that +# take arguments), then branch to the quote section. Otherwise, +# look for a macro that doesn't take arguments. +ac_script=' +:mline +/\\$/{ + N + s,\\\n,, + b mline +} +t clear +:clear +s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g +t quote +s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g +t quote +b any +:quote +s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g +s/\[/\\&/g +s/\]/\\&/g +s/\$/$$/g +H +:any +${ + g + s/^\n// + s/\n/ /g + p +} +' +DEFS=`sed -n "$ac_script" confdefs.h` + + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by rdesktop $as_me 1.9.0, which was +generated by GNU Autoconf 2.69. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + +Configuration files: +$config_files + +Report bugs to the package provider." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +rdesktop config.status 1.9.0 +configured by $0, generated by GNU Autoconf 2.69, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2012 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h | --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' >$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + + +eval set X " :F $CONFIG_FILES " +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + + + + esac + +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + + diff -Nru rdesktop-1.8.6/configure.ac rdesktop-1.9.0/configure.ac --- rdesktop-1.8.6/configure.ac 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/configure.ac 2019-09-20 06:39:29.000000000 +0000 @@ -1,4 +1,4 @@ -AC_INIT(rdesktop, 1.8.6) +AC_INIT(rdesktop, 1.9.0) AC_CONFIG_SRCDIR([rdesktop.c]) @@ -6,7 +6,7 @@ AC_PROG_CC if test "$GCC" = yes; then - CFLAGS="$CFLAGS -Wall" + CFLAGS="$CFLAGS -Wall -Wextra" fi AC_PROG_INSTALL @@ -26,9 +26,12 @@ echo exit 1 fi - + AC_PATH_TOOL(PKG_CONFIG, pkg-config) +# no .pc for GMP +AC_SEARCH_LIBS([__gmpz_init], [gmp]) + AC_SEARCH_LIBS(socket, socket) AC_SEARCH_LIBS(inet_aton, resolv) @@ -51,98 +54,56 @@ ]) ]) -# -# OpenSSL detection borrowed from stunnel -# -checkssldir() { : - if test -f "$1/include/openssl/ssl.h"; then - ssldir="$1" - return 0 - fi - return 1 -} -AC_MSG_CHECKING([for OpenSSL directory]) -AC_ARG_WITH(openssl, - [ --with-openssl=DIR look for OpenSSL at DIR/include, DIR/lib], - [ - dnl Check the specified location only - checkssldir "$withval" - ], - [ - dnl Search default locations of OpenSSL library - for maindir in /usr/local /usr/lib /usr/pkg /usr /var/ssl /opt; do - for dir in $maindir $maindir/openssl $maindir/ssl; do - checkssldir $dir && break 2 - done - done - ] -) -if test -z "$ssldir"; then - AC_MSG_RESULT([Not found]) - echo - echo "ERROR: Could not find OpenSSL headers/libraries." - if test -f /etc/debian_version; then - echo "Probably you need to install the libssl-dev package." - elif test -f /etc/redhat-release; then - echo "Probably you need to install the openssl-devel package." - fi - echo "To specify a path manually, use the --with-openssl option." - echo - exit 1 -fi -AC_MSG_RESULT([$ssldir]) -AC_SUBST(ssldir) -AC_DEFINE_UNQUOTED(ssldir, "$ssldir") - -dnl Add OpenSSL includes and libraries -CFLAGS="$CFLAGS -I$ssldir/include" -AC_ARG_ENABLE(static-openssl, - [ --enable-static-openssl link OpenSSL statically], - [static_openssl=yes], - [static_openssl=no]) -if test x"$static_openssl" = "xyes"; then - # OpenSSL generally relies on libz - AC_SEARCH_LIBS(deflate, z) - LIBS="-L$ssldir/lib -L$ssldir/lib64 -Wl,-Bstatic -lssl -lcrypto -Wl,-Bdynamic $LIBS" -else - LIBS="-L$ssldir/lib -L$ssldir/lib64 -lssl -lcrypto $LIBS" +dnl Add option to build with using address sanitizer +AC_ARG_ENABLE([address-sanitizer], AS_HELP_STRING([--enable-address-sanitizer], \ + [enable AddressSanitizer support for detecting a wide variety of \ + memory allocation and deallocation errors]), \ + [AC_DEFINE(HAVE_ADDRESS_SANITIZER, 1, [enable AddressSanitizer]) + CFLAGS="$CFLAGS -fsanitize=address -fno-omit-frame-pointer" + AC_TRY_COMPILE([],[const int i=0;],[AC_MSG_NOTICE([Address Sanitizer Enabled])], + [AC_MSG_ERROR([Address Sanitizer not available])]) + ]) - # - # target-specific stuff - # - case "$host" in - *-*-solaris*) - LDFLAGS="$LDFLAGS -R$ssldir/lib" - ;; - *-dec-osf*) - LDFLAGS="$LDFLAGS -Wl,-rpath,$ssldir/lib" - ;; - esac -fi dnl CredSSP feature AC_ARG_ENABLE([credssp], AS_HELP_STRING([--disable-credssp], [disable support for CredSSP])) -AC_ARG_ENABLE([static-gssglue], AS_HELP_STRING([--enable-static-gssglue]), - [static_gssglue=yes], [static_gssglue=no]) AS_IF([test "x$enable_credssp" != "xno"], [ - if test -n "$PKG_CONFIG"; then - PKG_CHECK_MODULES(GSSGLUE, libgssglue, [WITH_CREDSSP=1], [WITH_CREDSSP=0]) - fi + case "$OSTYPE" in + darwin*) + AC_CHECK_HEADER(Kerberos/gssapi_krb5.h, [WITH_CREDSSP=1], [WITH_CREDSSP=0]) + GSSAPI_CFLAGS="" + GSSAPI_LIBS="-framework Kerberos" + ;; + *) + #if 'OSTYPE' is not set use 'host' instead + if test x"$OSTYPE" = "x"; then + case "$host" in + *-*-freebsd*) + if test -n "$PKG_CONFIG"; then + PKG_CHECK_MODULES(GSSAPI, gss, [WITH_CREDSSP=1], [WITH_CREDSSP=0]) + fi + ;; + *) + ;; + esac + else + if test -n "$PKG_CONFIG"; then + PKG_CHECK_MODULES(GSSAPI, krb5-gssapi, [WITH_CREDSSP=1], [WITH_CREDSSP=0]) + fi + fi + ;; + esac + if test x"$WITH_CREDSSP" = "x1"; then CREDSSPOBJ="cssp.o" - CFLAGS="$CFLAGS $GSSGLUE_CFLAGS" - - AS_IF([test "x$static_gssglue" != "xno"], [ - LIBS="$LIBS -Wl,-Bstatic -lgssglue -Wl,-Bdynamic" - ], [ - LIBS="$LIBS -lgssglue" - ]) + CFLAGS="$CFLAGS $GSSAPI_CFLAGS" + LIBS="$LIBS $GSSAPI_LIBS" AC_DEFINE(WITH_CREDSSP) else echo - echo "CredSSP support requires libgssglue, install the dependency" + echo "CredSSP support requires GSSAPI, install the dependency" echo "or disable the feature using --disable-credssp." echo exit 1 @@ -160,6 +121,78 @@ AC_DEFINE(HAVE_XRANDR) fi +# Xcursor +if test -n "$PKG_CONFIG"; then + PKG_CHECK_MODULES(XCURSOR, xcursor, [HAVE_XCURSOR=1], [HAVE_XCURSOR=0]) +fi +if test x"$HAVE_XCURSOR" = "x1"; then + CFLAGS="$CFLAGS $XCURSOR_CFLAGS" + LIBS="$LIBS $XCURSOR_LIBS" + AC_DEFINE(HAVE_XCURSOR) +else + echo + echo "rdesktop requires libXcursor, install the dependency" + echo + exit 1 +fi + +# libtasn1 +if test -n "$PKG_CONFIG"; then + PKG_CHECK_MODULES(LIBTASN1, libtasn1, [HAVE_LIBTASN1=1], [HAVE_LIBTASN1=0]) +fi +if test x"$HAVE_LIBTASN1" = "x1"; then + CFLAGS="$CFLAGS $LIBTASN1_CFLAGS" + LIBS="$LIBS $LIBTASN1_LIBS" +else + echo + echo "rdesktop requires libtasn1. Please install the dependency" + echo + exit 1 +fi + +# nettle +if test -n "$PKG_CONFIG"; then + PKG_CHECK_MODULES(NETTLE, nettle, [HAVE_NETTLE=1], [HAVE_NETTLE=0]) +fi +if test x"$HAVE_NETTLE" = "x1"; then + CFLAGS="$CFLAGS $NETTLE_CFLAGS" + LIBS="$LIBS $NETTLE_LIBS" +else + echo + echo "rdesktop requires Nettle. Please install the dependency" + echo + exit 1 +fi + +# hogweed +if test -n "$PKG_CONFIG"; then + PKG_CHECK_MODULES(HOGWEED, hogweed, [HAVE_HOGWEED=1], [HAVE_HOGWEED=0]) +fi +if test x"$HAVE_HOGWEED" = "x1"; then + CFLAGS="$CFLAGS $HOGWEED_CFLAGS" + LIBS="$LIBS $HOGWEED_LIBS" +else + echo + echo "rdesktop requires hogweed. Please install the dependency" + echo + exit 1 +fi + +# GnuTLS + +if test -n "$PKG_CONFIG"; then + PKG_CHECK_MODULES(GNUTLS, gnutls >= 3.2.0, [HAVE_GNUTLS=1], [HAVE_GNUTLS=0]) +fi +if test x"$HAVE_GNUTLS" = "x1"; then + CFLAGS="$CFLAGS $GNUTLS_CFLAGS" + LIBS="$LIBS $GNUTLS_LIBS" +else + echo + echo "rdesktop requires GnuTLS. Please install the dependency" + echo + exit 1 +fi + dnl Smartcard support AC_ARG_ENABLE(smartcard, AS_HELP_STRING([--disable-smartcard], [disable support for smartcard])) AS_IF([test "x$enable_smartcard" != "xno"], [ @@ -189,6 +222,10 @@ exit 1 fi + AC_MSG_CHECKING([for PCSC-lite >= 1.6.0 (PnP/Notifications support)]) + PKG_CHECK_MODULES(PNP_NOTIFICATIONS, libpcsclite >= 1.6.0, [WITH_PNP_NOTIFICATIONS=1], [WITH_PNP_NOTIFICATIONS=0]) + AC_DEFINE(WITH_PNP_NOTIFICATIONS) + AC_MSG_CHECKING([for old version of PCSC]) AC_TRY_LINK([ #include @@ -222,11 +259,11 @@ return 1; } return 0; -}], - [AC_MSG_RESULT(no)], - [AC_MSG_RESULT(yes) - AC_DEFINE(NEED_ALIGN)], - [AC_MSG_RESULT(assuming yes) +}], + [AC_MSG_RESULT(no)], + [AC_MSG_RESULT(yes) + AC_DEFINE(NEED_ALIGN)], + [AC_MSG_RESULT(assuming yes) AC_DEFINE(NEED_ALIGN)]) @@ -242,49 +279,28 @@ # -# rdp2vnc -# -vncserverconfig=libvncserver-config -AC_ARG_WITH(libvncserver-config, - [ --with-libvncserver-config=CMD use CMD as libvncserver-config], - [vncserverconfig="$withval"] -) -AC_ARG_WITH(libvncserver, - [ --with-libvncserver make rdp2vnc], - [ - VNCINC=`$vncserverconfig --cflags` - AC_SUBST(VNCINC) - LDVNC=`$vncserverconfig --libs` - AC_SUBST(LDVNC) - VNCLINK=`$vncserverconfig --link` - AC_SUBST(VNCLINK) - RDP2VNCTARGET="rdp2vnc" - AC_SUBST(RDP2VNCTARGET) - ] -) - -# # sound # sound="yes" AC_ARG_WITH(sound, - [ --with-sound select sound system ("oss", "sgi", "sun", "alsa" or "libao") ], - [ - sound="$withval" + [ --with-sound select sound system ("oss", "sgi", "sun", "alsa", "pulse" or "libao") ], + [ + sound="$withval" ]) AC_CHECK_HEADER(sys/soundcard.h, [HAVE_OSS=1], [HAVE_OSS=0]) AC_CHECK_HEADER(dmedia/audio.h, [HAVE_SGI=1], [HAVE_SGI=0]) AC_CHECK_HEADER(sys/audioio.h, [HAVE_SUN=1], [HAVE_SUN=0]) -AC_ARG_ENABLE(static-libsamplerate, - [ --enable-static-libsamplerate link libsamplerate statically], - [static_libsamplerate=yes], +AC_ARG_ENABLE(static-libsamplerate, + [ --enable-static-libsamplerate link libsamplerate statically], + [static_libsamplerate=yes], [static_libsamplerate=no]) if test -n "$PKG_CONFIG"; then PKG_CHECK_MODULES(LIBAO, ao, [HAVE_LIBAO=1], [HAVE_LIBAO=0]) + PKG_CHECK_MODULES(PULSE, libpulse, [HAVE_PULSE=1], [HAVE_PULSE=0]) PKG_CHECK_MODULES(ALSA, alsa, [HAVE_ALSA=1], [HAVE_ALSA=0]) PKG_CHECK_MODULES(LIBSAMPLERATE, samplerate, [HAVE_LIBSAMPLERATE=1], [HAVE_LIBSAMPLERATE=0]) if test x"$HAVE_LIBSAMPLERATE" = "x1"; then @@ -329,6 +345,13 @@ AC_DEFINE(RDPSND_ALSA) fi + if test x"$HAVE_PULSE" = "x1"; then + SOUNDOBJ="$SOUNDOBJ rdpsnd_pulse.o" + CFLAGS="$CFLAGS $PULSE_CFLAGS" + LIBS="$LIBS $PULSE_LIBS" + AC_DEFINE(RDPSND_PULSE) + fi + if test x"$HAVE_LIBAO" = "x1"; then SOUNDOBJ="$SOUNDOBJ rdpsnd_libao.o" CFLAGS="$CFLAGS $LIBAO_CFLAGS" @@ -377,6 +400,17 @@ fi ;; + pulse) + if test x"$HAVE_PULSE" = "x1"; then + SOUNDOBJ="$SOUNDOBJ rdpsnd_pulse.o" + CFLAGS="$CFLAGS $PULSE_CFLAGS" + LIBS="$LIBS $PULSE_LIBS" + AC_DEFINE(RDPSND_PULSE) + else + AC_MSG_ERROR([Selected sound system is not available.]) + fi + ;; + libao) if test x"$HAVE_LIBAO" = "x1"; then SOUNDOBJ="$SOUNDOBJ rdpsnd_libao.o" @@ -393,7 +427,7 @@ *) AC_MSG_WARN([sound support disabled]) - AC_MSG_WARN([Currently supported systems are Open Sound System (oss), SGI AL (sgi), Sun/BSD (sun), ALSA (alsa) and libao]) + AC_MSG_WARN([Currently supported systems are Open Sound System (oss), SGI AL (sgi), Sun/BSD (sun), ALSA (alsa), PulseAudio (pulse) and libao]) ;; esac @@ -853,99 +887,10 @@ # AC_ARG_WITH(ipv6, [ --with-ipv6 enable IPv6-support], - [ - if test $withval != "no"; - then - AC_DEFINE(IPv6,1) - fi - ]) - - -# -# debugging -# -AC_ARG_WITH(debug, - [ --with-debug enable protocol debugging output], - [ - if test $withval != "no"; - then - AC_DEFINE(WITH_DEBUG,1) - fi - ]) - -AC_ARG_WITH(debug-kbd, - [ --with-debug-kbd enable debugging of keyboard handling], - [ - if test $withval != "no"; - then - AC_DEFINE(WITH_DEBUG_KBD,1) - fi - ]) - -AC_ARG_WITH(debug-rdp5, - [ --with-debug-rdp5 enable debugging of RDP5 code], - [ - if test $withval != "no"; - then - AC_DEFINE(WITH_DEBUG_RDP5,1) - fi - ]) - -AC_ARG_WITH(debug-clipboard, - [ --with-debug-clipboard enable debugging of clipboard code], - [ - if test $withval != "no"; - then - AC_DEFINE(WITH_DEBUG_CLIPBOARD,1) - fi - ]) - -AC_ARG_WITH(debug-sound, - [ --with-debug-sound enable debugging of sound code], - [ - if test $withval != "no"; - then - AC_DEFINE(WITH_DEBUG_SOUND,1) - fi - ]) - -AC_ARG_WITH(debug-channel, - [ --with-debug-channel enable debugging of virtual channel code], - [ - if test $withval != "no"; - then - AC_DEFINE(WITH_DEBUG_CHANNEL,1) - fi - ]) - -AC_ARG_WITH(debug-seamless, - [ --with-debug-seamless enable debugging of SeamlessRDP code], - [ - if test $withval != "no"; - then - AC_DEFINE(WITH_DEBUG_SEAMLESS,1) - fi - ]) - -AC_ARG_WITH(debug-smartcard, - [ --with-debug-smartcard enable debugging of smart-card code], [ if test $withval != "no"; then - if test x"$WITH_SCARD" = "x1"; then - AC_DEFINE(WITH_DEBUG_SCARD,1) - fi - fi - ]) - -AC_ARG_WITH(debug-credssp, - [ --with-debug-credssp enable debugging of CredSSP code], - [ - if test $withval != "no"; - then - if test x"$WITH_CREDSSP" = "x1"; then - AC_DEFINE(WITH_DEBUG_CREDSSP,1) - fi + AC_DEFINE(IPv6,1) fi ]) diff -Nru rdesktop-1.8.6/constants.h rdesktop-1.9.0/constants.h --- rdesktop-1.8.6/constants.h 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/constants.h 2019-06-13 12:10:15.000000000 +0000 @@ -2,6 +2,8 @@ rdesktop: A Remote Desktop Protocol client. Miscellaneous protocol constants Copyright (C) Matthew Chapman 1999-2008 + Copyright 2016 Alexander Zakharov + Copyright 2017-2018 Henrik Andersson for Cendio AB 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 @@ -17,12 +19,48 @@ along with this program. If not, see . */ +#ifndef _CONSTANTS_H +#define _CONSTANTS_H + /* TCP port for Remote Desktop Protocol */ #define TCP_PORT_RDP 3389 #define DEFAULT_CODEPAGE "UTF-8" #define WINDOWS_CODEPAGE "UTF-16LE" +/* T-REC-T.123-200701, section 8 */ +#define T123_HEADER_VERSION 0x3 + +/* [MS-RDPBCGR] 2.2.9.1.2 */ +#define FASTPATH_OUTPUT_ACTION_FASTPATH 0x0 +#define FASTPATH_OUTPUT_ACTION_X224 T123_HEADER_VERSION + +#define FASTPATH_OUTPUT_SECURE_CHECKSUM 0x1 +#define FASTPATH_OUTPUT_ENCRYPTED 0x2 + +/* [MS-RDPBCGR] 2.2.9.1.2.1 */ +/* adjusted for position in updateHeader */ +#define FASTPATH_UPDATETYPE_ORDERS 0x0 +#define FASTPATH_UPDATETYPE_BITMAP 0x1 +#define FASTPATH_UPDATETYPE_PALETTE 0x2 +#define FASTPATH_UPDATETYPE_SYNCHRONIZE 0x3 +#define FASTPATH_UPDATETYPE_SURFCMDS 0x4 +#define FASTPATH_UPDATETYPE_PTR_NULL 0x5 +#define FASTPATH_UPDATETYPE_PTR_DEFAULT 0x6 +#define FASTPATH_UPDATETYPE_PTR_POSITION 0x8 +#define FASTPATH_UPDATETYPE_COLOR 0x9 +#define FASTPATH_UPDATETYPE_CACHED 0xA +#define FASTPATH_UPDATETYPE_POINTER 0xB + +#define FASTPATH_FRAGMENT_SINGLE (0x0 << 4) +#define FASTPATH_FRAGMENT_LAST (0x1 << 4) +#define FASTPATH_FRAGMENT_FIRST (0x2 << 4) +#define FASTPATH_FRAGMENT_NEXT (0x3 << 4) + +#define FASTPATH_OUTPUT_COMPRESSION_USED (0x2 << 6) + +#define RDESKTOP_FASTPATH_MULTIFRAGMENT_MAX_SIZE 65535 + /* ISO PDU codes */ enum ISO_PDU_CODE { @@ -87,6 +125,17 @@ #define MCS_GLOBAL_CHANNEL 1003 #define MCS_USERCHANNEL_BASE 1001 +/* ITU-T Rec. T.125, Reason enumeration used with Disconnect Provider + Ultimatum, see mcs_send_dpu(reason) */ +enum MCS_DPU_REASON +{ + RN_DOMAIN_DISCONNECTED = 0, + RN_PROVIDER_INITIATED, + RN_TOKEN_PURGED, + RN_USER_REQUESTED, + RN_CHANNEL_PURGED, +}; + /* RDP secure transport constants */ #define SEC_RANDOM_SIZE 32 #define SEC_MODULUS_SIZE 64 @@ -94,20 +143,32 @@ #define SEC_PADDING_SIZE 8 #define SEC_EXPONENT_SIZE 4 -#define SEC_CLIENT_RANDOM 0x0001 +/* TS_SECURITY_HEADER.flags */ +#define SEC_EXCHANGE_PKT 0x0001 +#define SEC_TRANSPORT_REQ 0x0002 +#define RDP_SEC_TRANSPORT_RSP 0x0004 #define SEC_ENCRYPT 0x0008 -#define SEC_LOGON_INFO 0x0040 -#define SEC_LICENCE_NEG 0x0080 -#define SEC_REDIRECT_ENCRYPT 0x0C00 +#define SEC_RESET_SEQNO 0x0010 +#define SEC_IGNORE_SEQNO 0x0020 +#define SEC_INFO_PKT 0x0040 +#define SEC_LICENSE_PKT 0x0080 +#define SEC_LICENSE_ENCRYPT_CS 0x0200 +#define SEC_LICENSE_ENCRYPT_SC 0x0200 +#define SEC_REDIRECTION_PKT 0x0400 +#define SEC_SECURE_CHECKSUM 0x0800 +#define SEC_AUTODETECT_REQ 0x1000 +#define SEC_AUTODETECT_RSP 0x2000 +#define SEC_HEARTBEAT 0x4000 +#define SEC_FLAGSHI_VALID 0x8000 #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_CLUSTER 0xc004 +#define CS_CORE 0xc001 +#define CS_SECURITY 0xc002 +#define CS_NET 0xc003 +#define CS_CLUSTER 0xc004 #define SEC_TAG_PUBKEY 0x0006 #define SEC_TAG_KEYSIG 0x0008 @@ -131,12 +192,12 @@ #define LICENCE_SIGNATURE_SIZE 16 #define LICENCE_TAG_REQUEST 0x01 -#define LICENCE_TAG_PLATFORM_CHALLANGE 0x02 +#define LICENCE_TAG_PLATFORM_CHALLENGE 0x02 #define LICENCE_TAG_NEW_LICENCE 0x03 #define LICENCE_TAG_UPGRADE_LICENCE 0x04 #define LICENCE_TAG_LICENCE_INFO 0x12 #define LICENCE_TAG_NEW_LICENCE_REQUEST 0x13 -#define LICENCE_TAG_PLATFORM_CHALLANGE_RESPONSE 0x15 +#define LICENCE_TAG_PLATFORM_CHALLENGE_RESPONSE 0x15 #define LICENCE_TAG_ERROR_ALERT 0xff #define BB_CLIENT_USER_NAME_BLOB 0x000f @@ -155,18 +216,18 @@ 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, /* PDUTYPE2_SAVE_SESSION_INFO */ - RDP_DATA_PDU_FONT2 = 39, - RDP_DATA_PDU_KEYBOARD_INDICATORS = 41, - RDP_DATA_PDU_DISCONNECT = 47, - RDP_DATA_PDU_AUTORECONNECT_STATUS = 50 + RDP_DATA_PDU_UPDATE = 0x02, /* PDUTYPE2_UPDATE */ + RDP_DATA_PDU_CONTROL = 0x14, /* PDUTYPE2_CONTROL */ + RDP_DATA_PDU_POINTER = 0x1b, /* PDUTYPE2_POINTER */ + RDP_DATA_PDU_INPUT = 0x1c, /* PDUTYPE2_INPUT */ + RDP_DATA_PDU_SYNCHRONISE = 0x1f, /* PDUTYPE2_SYNCHRONIZE */ + RDP_DATA_PDU_BELL = 0x22, /* PDUTYPE2_PLAY_SOUND */ + RDP_DATA_PDU_CLIENT_WINDOW_STATUS = 0x23, /* PDUTYPE2_SUPRESS_OUTPUT */ + RDP_DATA_PDU_LOGON = 0x26, /* PDUTYPE2_SAVE_SESSION_INFO */ + RDP_DATA_PDU_FONT2 = 0x27, /* PDUTYPE2_FONTLIST */ + RDP_DATA_PDU_KEYBOARD_INDICATORS = 0x29, /* PDUTYPE2_SET_KEYBOARD_INDICATORS */ + RDP_DATA_PDU_SET_ERROR_INFO = 0x2f, /* PDUTYPE2_SET_ERROR_INFO */ + RDP_DATA_PDU_AUTORECONNECT_STATUS = 0x32, /* PDUTYPE2_ARC_STATUS_PDU */ }; enum RDP_SAVE_SESSION_PDU_TYPE @@ -208,10 +269,11 @@ RDP_POINTER_NEW = 8 }; +/* [MS-RDPBCGR] 2.2.9.1.1.4.3 */ enum RDP_SYSTEM_POINTER_TYPE { - RDP_NULL_POINTER = 0, - RDP_DEFAULT_POINTER = 0x7F00 + SYSPTR_NULL = 0x00000000, + SYSPTR_DEFAULT = 0x00007F00 }; enum RDP_INPUT_DEVICE @@ -220,12 +282,14 @@ RDP_INPUT_CODEPOINT = 1, RDP_INPUT_VIRTKEY = 2, RDP_INPUT_SCANCODE = 4, - RDP_INPUT_MOUSE = 0x8001 + RDP_INPUT_MOUSE = 0x8001, + RDP_INPUT_MOUSEX = 0x8002 }; /* Device flags */ #define KBD_FLAG_RIGHT 0x0001 #define KBD_FLAG_EXT 0x0100 +#define KBD_FLAG_EXT1 0x0200 #define KBD_FLAG_QUIET 0x1000 #define KBD_FLAG_DOWN 0x4000 #define KBD_FLAG_UP 0x8000 @@ -245,6 +309,8 @@ #define MOUSE_FLAG_BUTTON3 0x4000 #define MOUSE_FLAG_BUTTON4 0x0280 #define MOUSE_FLAG_BUTTON5 0x0380 +#define MOUSEX_FLAG_BUTTON1 0x0001 +#define MOUSEX_FLAG_BUTTON2 0x0002 #define MOUSE_FLAG_DOWN 0x8000 /* Raster operation masks */ @@ -308,13 +374,34 @@ #define RDP_CAPSET_COLCACHE 10 #define RDP_CAPLEN_COLCACHE 0x08 +#define RDP_CAPSET_SOUND 12 +#define RDP_CAPLEN_SOUND 8 + +#define RDP_CAPSET_INPUT 13 +#define RDP_CAPLEN_INPUT 88 + +#define RDP_CAPSET_FONT 14 +#define RDP_CAPLEN_FONT 8 + #define RDP_CAPSET_BRUSHCACHE 15 #define RDP_CAPLEN_BRUSHCACHE 0x08 +#define RDP_CAPSET_GLYPHCACHE 16 +#define RDP_CAPLEN_GLYPHCACHE 52 + #define RDP_CAPSET_BMPCACHE2 19 #define RDP_CAPLEN_BMPCACHE2 0x28 #define BMPCACHE2_FLAG_PERSIST ((uint32)1<<31) +#define RDP_CAPSET_MULTIFRAGMENTUPDATE 26 +#define RDP_CAPLEN_MULTIFRAGMENTUPDATE 8 + +#define RDP_CAPSET_LARGE_POINTER 27 +#define RDP_CAPLEN_LARGE_POINTER 6 + +#define RDP_CAPSET_VC 20 +#define RDP_CAPLEN_VC 0x08 + #define RDP_SOURCE "MSTSC" /* Logon flags */ @@ -323,19 +410,20 @@ #define RDP_INFO_AUTOLOGON 0x00000008 #define RDP_INFO_UNICODE 0x00000010 #define RDP_INFO_MAXIMIZESHELL 0x00000020 -#define RDP_INFO_COMPRESSION 0x00000080 /* mppc compression with 8kB histroy buffer */ +#define RDP_INFO_COMPRESSION 0x00000080 /* mppc compression with 8kB history buffer */ #define RDP_INFO_ENABLEWINDOWSKEY 0x00000100 #define RDP_INFO_COMPRESSION2 0x00000200 /* rdp5 mppc compression with 64kB history buffer */ #define RDP_INFO_REMOTE_CONSOLE_AUDIO 0x00002000 #define RDP_INFO_PASSWORD_IS_SC_PIN 0x00040000 -#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 */ +/* TS_EXTENDED_INFO_PACKET.performanceFlags */ +#define PERF_DISABLE_WALLPAPER 0x01 +#define PERF_DISABLE_FULLWINDOWDRAG 0x02 +#define PERF_DISABLE_MENUANIMATIONS 0x04 +#define PERF_DISABLE_THEMING 0x08 +#define PERF_DISABLE_CURSOR_SHADOW 0x20 +#define PERF_DISABLE_CURSORSETTINGS 0x40 /* disables cursor blinking */ +#define PERF_ENABLE_FONT_SMOOTHING 0x80 /* compression types */ #define RDP_MPPC_BIG 0x01 @@ -436,6 +524,7 @@ #define RD_STATUS_NO_SUCH_FILE 0xc000000f #define RD_STATUS_INVALID_DEVICE_REQUEST 0xc0000010 #define RD_STATUS_ACCESS_DENIED 0xc0000022 +#define RD_STATUS_BUFFER_TOO_SMALL 0xc0000023 #define RD_STATUS_OBJECT_NAME_COLLISION 0xc0000035 #define RD_STATUS_DISK_FULL 0xc000007f #define RD_STATUS_FILE_IS_A_DIRECTORY 0xc00000ba @@ -481,35 +570,93 @@ #define FILE_DELETE_ON_CLOSE 0x00001000 #define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000 -/* [MS-RDPBCGR], TS_BITMAP_DATA, flags */ -#define BITMAP_COMPRESSION 0x0001 -#define NO_BITMAP_COMPRESSION_HDR 0x0400 - -/* 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 exDiscReasonServerInsufficientPrivileges 0x0009 -#define exDiscReasonServerFreshCredentialsRequired 0x000a -#define exDiscReasonRPCInitiatedDisconnectByUser 0x000b -#define exDiscReasonByUser 0x000c -#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 +#define CAP_GENERAL_TYPE 0x0001 +#define CAP_PRINTER_TYPE 0x0002 +#define CAP_PORT_TYPE 0x0003 +#define CAP_DRIVE_TYPE 0x0004 +#define CAP_SMARTCARD_TYPE 0x0005 + +#define GENERAL_CAPABILITY_VERSION_01 0x00000001 +#define GENERAL_CAPABILITY_VERSION_02 0x00000002 +#define PRINT_CAPABILITY_VERSION_01 0x00000001 +#define PORT_CAPABILITY_VERSION_01 0x00000001 +#define DRIVE_CAPABILITY_VERSION_01 0x00000001 +#define DRIVE_CAPABILITY_VERSION_02 0x00000002 +#define SMARTCARD_CAPABILITY_VERSION_01 0x00000001 + +#define RDPDR_IRP_MJ_CREATE 0x00000001 +#define RDPDR_IRP_MJ_CLEANUP 0x00000002 +#define RDPDR_IRP_MJ_CLOSE 0x00000004 +#define RDPDR_IRP_MJ_READ 0x00000008 +#define RDPDR_IRP_MJ_WRITE 0x00000010 +#define RDPDR_IRP_MJ_FLUSH_BUFFERS 0x00000020 +#define RDPDR_IRP_MJ_SHUTDOWN 0x00000040 +#define RDPDR_IRP_MJ_DEVICE_CONTROL 0x00000080 +#define RDPDR_IRP_MJ_QUERY_VOLUME_INFORMATION 0x00000100 +#define RDPDR_IRP_MJ_SET_VOLUME_INFORMATION 0x00000200 +#define RDPDR_IRP_MJ_QUERY_INFORMATION 0x00000400 +#define RDPDR_IRP_MJ_SET_INFORMATION 0x00000800 +#define RDPDR_IRP_MJ_DIRECTORY_CONTROL 0x00001000 +#define RDPDR_IRP_MJ_LOCK_CONTROL 0x00002000 +#define RDPDR_IRP_MJ_QUERY_SECURITY 0x00004000 +#define RDPDR_IRP_MJ_SET_SECURITY 0x00008000 +#define ALL_RDPDR_IRP_MJ 0x0000FFFF + +#define RDPDR_PRINTER_ANNOUNCE_FLAG_ASCII 0x00000001 +#define RDPDR_PRINTER_ANNOUNCE_FLAG_DEFAULTPRINTER 0x00000002 +#define RDPDR_PRINTER_ANNOUNCE_FLAG_NETWORKPRINTER 0x00000004 +#define RDPDR_PRINTER_ANNOUNCE_FLAG_TSPRINTER 0x00000008 +#define RDPDR_PRINTER_ANNOUNCE_FLAG_XPSFORMAT 0x00000010 + +#define RDPDR_DEVICE_REMOVE_PDUS 0x00000001 +#define RDPDR_CLIENT_DISPLAY_NAME_PDU 0x00000002 +#define RDPDR_USER_LOGGEDON_PDU 0x00000004 + +/* RDP5 disconnect PDU + * + * Named after the corresponding names on the server side: + * https://msdn.microsoft.com/en-us/library/cc240544.aspx + */ +#define ERRINFO_UNSET (unsigned)(-1) +#define ERRINFO_NO_INFO 0x0000 +#define ERRINFO_RPC_INITIATED_DISCONNECT 0x0001 +#define ERRINFO_RPC_INITIATED_LOGOFF 0x0002 +#define ERRINFO_IDLE_TIMEOUT 0x0003 +#define ERRINFO_LOGON_TIMEOUT 0x0004 +#define ERRINFO_DISCONNECTED_BY_OTHERCONNECTION 0x0005 +#define ERRINFO_OUT_OF_MEMORY 0x0006 +#define ERRINFO_SERVER_DENIED_CONNECTION 0x0007 +#define ERRINFO_SERVER_DENIED_CONNECTION_FIPS 0x0008 +#define ERRINFO_SERVER_INSUFFICIENT_PRIVILEGES 0x0009 +#define ERRINFO_SERVER_FRESH_CREDENTIALS_REQUIRED 0x000a +#define ERRINFO_RPC_INITIATED_DISCONNECT_BYUSER 0x000b +#define ERRINFO_LOGOFF_BYUSER 0x000c +#define ERRINFO_LICENSE_INTERNAL 0x0100 +#define ERRINFO_LICENSE_NO_LICENSE_SERVER 0x0101 +#define ERRINFO_LICENSE_NO_LICENSE 0x0102 +#define ERRINFO_LICENSE_BAD_CLIENT_MSG 0x0103 +#define ERRINFO_LICENSE_HWID_DOESNT_MATCH_LICENSE 0x0104 +#define ERRINFO_LICENSE_BAD_CLIENT_LICENSE 0x0105 +#define ERRINFO_LICENSE_CANT_FINISH_PROTOCOL 0x0106 +#define ERRINFO_LICENSE_CLIENT_ENDED_PROTOCOL 0x0107 +#define ERRINFO_LICENSE_BAD_CLIENT_ENCRYPTION 0x0108 +#define ERRINFO_LICENSE_CANT_UPGRADE_LICENSE 0x0109 +#define ERRINFO_LICENSE_NO_REMOTE_CONNECTIONS 0x010a +#define ERRINFO_CB_DESTINATION_NOT_FOUND 0x0400 +#define ERRINFO_CB_LOADING_DESTINATION 0x0402 +#define ERRINFO_CB_REDIRECTING_TO_DESTINATION 0x0404 +#define ERRINFO_CB_SESSION_ONLINE_VM_WAKE 0x0405 +#define ERRINFO_CB_SESSION_ONLINE_VM_BOOT 0x0406 +#define ERRINFO_CB_SESSION_ONLINE_VM_NO_DNS 0x0407 +#define ERRINFO_CB_DESTINATION_POOL_NOT_FREE 0x0408 +#define ERRINFO_CB_CONNECTION_CANCELLED 0x0409 +#define ERRINFO_CB_CONNECTION_ERROR_INVALID_SETTINGS 0x0410 +#define ERRINFO_CB_SESSION_ONLINE_VM_BOOT_TIMEOUT 0x0411 +#define ERRINFO_CB_SESSION_ONLINE_VM_SESSMON_FAILED 0x0412 +#define ERRINFO_REMOTEAPPSNOTENABLED 0x10f3 +#define ERRINFO_UPDATESESSIONKEYFAILED 0x1191 +#define ERRINFO_DECRYPTFAILED 0x1192 +#define ERRINFO_ENCRYPTFAILED 0x1193 /* SeamlessRDP constants */ #define SEAMLESSRDP_NOTYETMAPPED -1 @@ -535,15 +682,144 @@ /* redirect flags, from [MS-RDPBCGR] 2.2.13.1 */ enum RDP_PDU_REDIRECT_FLAGS { - PDU_REDIRECT_HAS_IP = 0x1, - PDU_REDIRECT_HAS_LOAD_BALANCE_INFO = 0x2, - PDU_REDIRECT_HAS_USERNAME = 0x4, - PDU_REDIRECT_HAS_DOMAIN = 0x8, - PDU_REDIRECT_HAS_PASSWORD = 0x10, - PDU_REDIRECT_DONT_STORE_USERNAME = 0x20, - PDU_REDIRECT_USE_SMARTCARD = 0x40, - PDU_REDIRECT_INFORMATIONAL = 0x80, - PDU_REDIRECT_HAS_TARGET_FQDN = 0x100, - PDU_REDIRECT_HAS_TARGET_NETBIOS = 0x200, - PDU_REDIRECT_HAS_TARGET_IP_ARRAY = 0x800 + LB_TARGET_NET_ADDRESS = 0x1, + LB_LOAD_BALANCE_INFO = 0x2, + LB_USERNAME = 0x4, + LB_DOMAIN = 0x8, + LB_PASSWORD = 0x10, + LB_DONTSTOREUSERNAME = 0x20, + LB_SMARTCARD_LOGON = 0x40, + LB_NOREDIRECT = 0x80, + LB_TARGET_FQDN = 0x100, + LB_TARGET_NETBIOS = 0x200, + LB_TARGET_NET_ADDRESSES = 0x800, + LB_CLIENT_TSV_URL = 0x1000, + LB_SERVER_TSV_CAPABLE = 0x2000, + LB_PASSWORD_IS_PK_ENCRYPTED = 0x4000, + LB_REDIRECTION_GUID = 0x8000, + LB_TARGET_CERTIFICATE = 0x10000 +}; + +/* desktop orientation */ +enum RDP_DESKTOP_ORIENTATION +{ + ORIENTATION_LANDSCAPE = 0, + ORIENTATION_PORTRAIT = 90, + ORIENTATION_LANDSCAPE_FLIPPED = 180, + ORIENTATION_PORTRAIT_FLIPPED = 270 +}; +/* color depths, from [MS-RDPBCGR] 2.2.1.3.2 */ +#define RNS_UD_COLOR_4BPP 0xCA00 +#define RNS_UD_COLOR_8BPP 0xCA01 +#define RNS_UD_COLOR_16BPP_555 0xCA02 +#define RNS_UD_COLOR_16BPP_565 0xCA03 +#define RNS_UD_COLOR_24BPP 0xCA04 + +#define RNS_UD_SAS_DEL 0xAA03 + +/* version, [MS-RDPBCGR] 2.2.1.3.2 */ +#define RDP_40 0x00080001 /* RDP 4.0 clients */ +#define RDP_50 0x00080004 /* RDP 5.0, 5.1, 5.2, 6.0, 6.1, 7.0, 7.1, 8.0, and 8.1 clients */ +#define RDP_10_0 0x00080005 /* RDP 10.0 clients */ +#define RDP_10_1 0x00080006 /* RDP 10.1 clients */ +#define RDP_10_2 0x00080007 /* RDP 10.2 clients */ +#define RDP_10_3 0x00080008 /* RDP 10.3 clients */ + +/* supportedColorDepths, [MS-RDPBCGR] 2.2.1.3.2 */ +#define RNS_UD_24BPP_SUPPORT 0x0001 +#define RNS_UD_16BPP_SUPPORT 0x0002 +#define RNS_UD_15BPP_SUPPORT 0x0004 +#define RNS_UD_32BPP_SUPPORT 0x0008 + +/* earlyCapabilityFlags, [MS-RDPBCGR] 2.2.1.3.2 */ +#define RNS_UD_CS_SUPPORT_ERRINFO_PDU 0x0001 +#define RNS_UD_CS_WANT_32BPP_SESSION 0x0002 +#define RNS_UD_CS_SUPPORT_STATUSINFO_PDU 0x0004 +#define RNS_UD_CS_STRONG_ASYMMETRIC_KEYS 0x0008 +#define RNS_UD_CS_UNUSED 0x0010 +#define RNS_UD_CS_VALID_CONNECTION_TYPE 0x0020 +#define RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU 0x0040 +#define RNS_UD_CS_SUPPORT_NETCHAR_AUTODETECT 0x0080 +#define RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL 0x0100 +#define RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE 0x0200 +#define RNS_UD_CS_SUPPORT_HEARTBEAT_PDU 0x0400 + +/* [MS-RDPBCGR] 2.2.7.1.1 */ +#define OSMAJORTYPE_WINDOWS 0x0001 +#define OSMINORTYPE_WINDOWSNT 0x0003 +#define TS_CAPS_PROTOCOLVERSION 0x0200 + +/* extraFlags, [MS-RDPBCGR] 2.2.7.1.1 */ +#define FASTPATH_OUTPUT_SUPPORTED 0x0001 +#define LONG_CREDENTIALS_SUPPORTED 0x0004 +#define AUTORECONNECT_SUPPORTED 0x0008 +#define ENC_SALTED_CHECKSUM 0x0010 +#define NO_BITMAP_COMPRESSION_HDR 0x0400 + +/* [MS-RDPBCGR], TS_BITMAP_DATA, flags */ +#define BITMAP_COMPRESSION 0x0001 + +/* orderFlags, [MS-RDPBCGR] 2.2.7.1.3 */ +#define NEGOTIATEORDERSUPPORT 0x0002 +#define ZEROBOUNDSDELTASSUPPORT 0x0008 +#define COLORINDEXSUPPORT 0x0020 +#define SOLIDPATTERNBRUSHONLY 0x0040 +#define ORDERFLAGS_EXTRA_FLAGS 0x0080 + +/* orderSupport index, [MS-RDPBCGR] 2.2.7.1.3 */ +#define TS_NEG_DSTBLT_INDEX 0x00 +#define TS_NEG_PATBLT_INDEX 0x01 +#define TS_NEG_SCRBLT_INDEX 0x02 +#define TS_NEG_MEMBLT_INDEX 0x03 +#define TS_NEG_MEM3BLT_INDEX 0x04 +#define TS_NEG_DRAWNINEGRID_INDEX 0x07 +#define TS_NEG_LINETO_INDEX 0x08 +#define TS_NEG_MULTI_DRAWNINEGRID_INDEX 0x09 +#define TS_NEG_SAVEBITMAP_INDEX 0x0B +#define TS_NEG_MULTIDSTBLT_INDEX 0x0F +#define TS_NEG_MULTIPATBLT_INDEX 0x10 +#define TS_NEG_MULTISCRBLT_INDEX 0x11 +#define TS_NEG_MULTIOPAQUERECT_INDEX 0x12 +#define TS_NEG_FAST_INDEX_INDEX 0x13 +#define TS_NEG_POLYGON_SC_INDEX 0x14 +#define TS_NEG_POLYGON_CB_INDEX 0x15 +#define TS_NEG_POLYLINE_INDEX 0x16 +#define TS_NEG_FAST_GLYPH_INDEX 0x18 +#define TS_NEG_ELLIPSE_SC_INDEX 0x19 +#define TS_NEG_ELLIPSE_CB_INDEX 0x1A +#define TS_NEG_INDEX_INDEX 0x1B + +/* [MS-RDPBCGR] 2.2.7.1.6 */ +#define INPUT_FLAG_SCANCODES 0x0001 +#define INPUT_FLAG_MOUSEX 0x0004 +#define INPUT_FLAG_FASTPATH_INPUT 0x0008 +#define INPUT_FLAG_UNICODE 0x0010 +#define INPUT_FLAG_FASTPATH_INPUT2 0x0020 +#define INPUT_FLAG_UNUSED1 0x0040 +#define INPUT_FLAG_UNUSED2 0x0080 +#define TS_INPUT_FLAG_MOUSE_HWHEEL 0x0100 +#define TS_INPUT_FLAG_QOE_TIMESTAMPS 0x0200 + +/* [MS-RDPBCGR] 2.2.7.1.8 */ +#define GLYPH_SUPPORT_NONE 0x0000 +#define GLYPH_SUPPORT_PARTIAL 0x0001 +#define GLYPH_SUPPORT_FULL 0x0002 +#define GLYPH_SUPPORT_ENCODE 0x0003 + +/* [MS-RDPBCGR] 2.2.7.1.11 */ +#define SOUND_BEEPS_FLAG 0x0001 + +/* [MS-RDPBCGR] 2.2.7.2.5 */ +#define FONTSUPPORT_FONTLIST 0x0001 + +/* [MS-RDPBCGR] 2.2.7.2.7 */ +#define LARGE_POINTER_FLAG_96x96 1 + +/* [MS-RDPBCGR] TS_SUPPRESS_OUTPUT_PDU allowDisplayUpdates */ +enum RDP_SUPPRESS_STATUS +{ + SUPPRESS_DISPLAY_UPDATES = 0x00, + ALLOW_DISPLAY_UPDATES = 0x01 }; + +#endif /* _CONSTANTS_H */ diff -Nru rdesktop-1.8.6/cssp.c rdesktop-1.9.0/cssp.c --- rdesktop-1.8.6/cssp.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/cssp.c 2019-06-13 12:10:15.000000000 +0000 @@ -1,7 +1,7 @@ /* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. - CredSSP layer and kerberos support. - Copyright 2012-2013 Henrik Andersson for Cendio AB + CredSSP layer and Kerberos support. + Copyright 2012-2017 Henrik Andersson for Cendio AB 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 @@ -51,10 +51,10 @@ OM_uint32 msgctx = 0, ms; gss_buffer_desc status_string; - error("GSS error [%d:%d:%d]: %s\n", (major_status & 0xff000000) >> 24, // Calling error - (major_status & 0xff0000) >> 16, // Routine error - major_status & 0xffff, // Supplementary info bits - str); + logger(Core, Debug, "GSS error [%d:%d:%d]: %s", (major_status & 0xff000000) >> 24, // Calling error + (major_status & 0xff0000) >> 16, // Routine error + major_status & 0xffff, // Supplementary info bits + str); do { @@ -63,7 +63,7 @@ if (ms != GSS_S_COMPLETE) continue; - error(" - %s\n", status_string.value); + logger(Core, Debug, " - %s", status_string.value); } while (ms == GSS_S_COMPLETE && msgctx); @@ -140,7 +140,7 @@ } static STREAM -cssp_gss_wrap(gss_ctx_id_t * ctx, STREAM in) +cssp_gss_wrap(gss_ctx_id_t ctx, STREAM in) { int conf_state; OM_uint32 major_status; @@ -165,7 +165,8 @@ if (!conf_state) { - error("GSS Confidentiality failed, no encryption of message performed."); + logger(Core, Error, + "cssp_gss_wrap(), GSS Confidentiality failed, no encryption of message performed."); return NULL; } @@ -181,7 +182,7 @@ } static STREAM -cssp_gss_unwrap(gss_ctx_id_t * ctx, STREAM in) +cssp_gss_unwrap(gss_ctx_id_t ctx, STREAM in) { OM_uint32 major_status; OM_uint32 minor_status; @@ -214,15 +215,6 @@ return out; } -#ifdef WITH_DEBUG_CREDSSP -void -streamsave(STREAM s, char *fn) -{ - FILE *f = fopen(fn, "wb"); - fwrite(s->data, s_length(s), 1, f); - fclose(f); -} -#endif static STREAM cssp_encode_tspasswordcreds(char *username, char *password, char *domain) @@ -234,10 +226,11 @@ memset(&tmp, 0, sizeof(tmp)); memset(&message, 0, sizeof(message)); + s_realloc(&tmp, 512 * 4); + // domainName [0] - s_realloc(&tmp, 4 + strlen(domain) * sizeof(uint16)); s_reset(&tmp); - rdp_out_unistr(&tmp, domain, strlen(domain) * sizeof(uint16)); + out_utf16s(&tmp, domain); s_mark_end(&tmp); h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0, h2); @@ -248,9 +241,8 @@ s_free(h1); // userName [1] - s_realloc(&tmp, 4 + strlen(username) * sizeof(uint16)); s_reset(&tmp); - rdp_out_unistr(&tmp, username, strlen(username) * sizeof(uint16)); + out_utf16s(&tmp, username); s_mark_end(&tmp); h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp); @@ -262,9 +254,8 @@ s_free(h1); // password [2] - s_realloc(&tmp, 4 + strlen(password) * sizeof(uint16)); s_reset(&tmp); - rdp_out_unistr(&tmp, password, strlen(password) * sizeof(uint16)); + out_utf16s(&tmp, password); s_mark_end(&tmp); h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 2, h2); @@ -296,8 +287,9 @@ struct stream tmp = { 0 }; struct stream message = { 0 }; + s_realloc(&tmp, 512 * 4); + // keySpec [0] - s_realloc(&tmp, sizeof(uint8)); s_reset(&tmp); out_uint8(&tmp, keyspec); s_mark_end(&tmp); @@ -312,9 +304,8 @@ // cardName [1] if (card) { - s_realloc(&tmp, 4 + strlen(card) * sizeof(uint16)); s_reset(&tmp); - rdp_out_unistr(&tmp, card, strlen(card) * sizeof(uint16)); + out_utf16s(&tmp, card); s_mark_end(&tmp); h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 1, h2); @@ -328,9 +319,8 @@ // readerName [2] if (reader) { - s_realloc(&tmp, 4 + strlen(reader) * sizeof(uint16)); s_reset(&tmp); - rdp_out_unistr(&tmp, reader, strlen(reader) * sizeof(uint16)); + out_utf16s(&tmp, reader); s_mark_end(&tmp); h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 2, h2); @@ -344,9 +334,8 @@ // containerName [3] if (container) { - s_realloc(&tmp, 4 + strlen(container) * sizeof(uint16)); s_reset(&tmp); - rdp_out_unistr(&tmp, container, strlen(container) * sizeof(uint16)); + out_utf16s(&tmp, container); s_mark_end(&tmp); h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 3, h2); @@ -360,9 +349,8 @@ // cspName [4] if (csp) { - s_realloc(&tmp, 4 + strlen(csp) * sizeof(uint16)); s_reset(&tmp); - rdp_out_unistr(&tmp, csp, strlen(csp) * sizeof(uint16)); + out_utf16s(&tmp, csp); s_mark_end(&tmp); h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 4, h2); @@ -391,10 +379,11 @@ struct stream tmp = { 0 }; struct stream message = { 0 }; + s_realloc(&tmp, 512 * 4); + // pin [0] - s_realloc(&tmp, strlen(password) * sizeof(uint16)); s_reset(&tmp); - rdp_out_unistr(&tmp, password, strlen(password) * sizeof(uint16)); + out_utf16s(&tmp, password); s_mark_end(&tmp); h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0, h2); @@ -404,7 +393,7 @@ s_free(h2); s_free(h1); - // cspData[1] + // cspData [1] h2 = cssp_encode_tscspdatadetail(AT_KEYEXCHANGE, g_sc_card_name, g_sc_reader_name, g_sc_container_name, g_sc_csp_name); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 1, h2); @@ -417,9 +406,8 @@ // userHint [2] if (username && strlen(username)) { - s_realloc(&tmp, strlen(username) * sizeof(uint16)); s_reset(&tmp); - rdp_out_unistr(&tmp, username, strlen(username) * sizeof(uint16)); + out_utf16s(&tmp, username); s_mark_end(&tmp); h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 2, h2); @@ -433,9 +421,8 @@ // domainHint [3] if (domain && strlen(domain)) { - s_realloc(&tmp, strlen(domain) * sizeof(uint16)); s_reset(&tmp); - rdp_out_unistr(&tmp, domain, strlen(domain) * sizeof(uint16)); + out_utf16s(&tmp, domain); s_mark_end(&tmp); h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 3, h2); @@ -508,12 +495,6 @@ // Construct ASN.1 message out = ber_wrap_hdr_data(BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED, &message); -#if WITH_DEBUG_CREDSSP - streamsave(out, "tscredentials.raw"); - printf("Out TSCredentials %ld bytes\n", s_length(out)); - hexdump(out->data, s_length(out)); -#endif - // cleanup xfree(message.data); xfree(tmp.data); @@ -599,12 +580,6 @@ s_mark_end(s); s_free(h1); -#if WITH_DEBUG_CREDSSP - streamsave(s, "tsrequest_out.raw"); - printf("Out TSRequest %ld bytes\n", s_length(s)); - hexdump(s->data, s_length(s)); -#endif - tcp_send(s); s_free(s); @@ -644,12 +619,6 @@ return NULL; packet = *s; -#if WITH_DEBUG_CREDSSP - streamsave(s, "tsrequest_in.raw"); - printf("In TSRequest token %ld bytes\n", s_length(s)); - hexdump(s->data, s_length(s)); -#endif - // version [0] if (!ber_in_header(s, &tagval, &length) || tagval != (BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0)) @@ -715,6 +684,7 @@ RD_BOOL cssp_connect(char *server, char *user, char *domain, char *password, STREAM s) { + UNUSED(s); OM_uint32 actual_time; gss_cred_id_t cred; gss_buffer_desc input_tok, output_tok; @@ -737,21 +707,22 @@ // Verify that system gss support spnego if (!cssp_gss_mech_available(desired_mech)) { - warning("CredSSP: System doesn't have support for desired authentication mechanism.\n"); + logger(Core, Debug, + "cssp_connect(), system doesn't have support for desired authentication mechanism"); return False; } // Get service name if (!cssp_gss_get_service_name(server, &target_name)) { - warning("CredSSP: Failed to get target service name.\n"); + logger(Core, Debug, "cssp_connect(), failed to get target service name"); return False; } - // Establish tls connection to server + // Establish TLS connection to server if (!tcp_tls_connect()) { - warning("CredSSP: Failed to establish TLS connection.\n"); + logger(Core, Debug, "cssp_connect(), failed to establish TLS connection"); return False; } @@ -760,10 +731,6 @@ return False; pubkey_cmp = NULL; -#ifdef WITH_DEBUG_CREDSSP - streamsave(&pubkey, "PubKey.raw"); -#endif - // Enter the spnego loop OM_uint32 actual_services; gss_OID actual_mech; @@ -800,21 +767,21 @@ if (GSS_ERROR(major_status)) { if (i == 0) - error("CredSSP: Initialize failed, do you have correct kerberos tgt initialized ?\n"); + logger(Core, Notice, + "Failed to initialize NLA, do you have correct Kerberos TGT initialized ?"); else - error("CredSSP: Negotiation failed.\n"); + logger(Core, Error, "cssp_connect(), negotiation failed"); -#ifdef WITH_DEBUG_CREDSSP - cssp_gss_report_error(GSS_C_GSS_CODE, "CredSSP: SPNEGO negotiation failed.", + cssp_gss_report_error(GSS_C_GSS_CODE, "cssp_connect(), negotiation failed.", major_status, minor_status); -#endif goto bail_out; } // validate required services if (!(actual_services & GSS_C_CONF_FLAG)) { - error("CredSSP: Confidiality service required but is not available.\n"); + logger(Core, Error, + "cssp_connect(), confidentiality service required but is not available"); goto bail_out; } @@ -895,8 +862,8 @@ if ((s_length(pubkey) != s_length(pubkey_cmp)) || (memcmp(pubkey_data, pubkey_cmp_data, s_length(pubkey)) != 0)) { - error("CredSSP: Cannot guarantee integrity of server connection, MITM ? " - "(public key data mismatch)\n"); + logger(Core, Error, + "cssp_connect(), public key mismatch, cannot guarantee integrity of server connection"); goto bail_out; } diff -Nru rdesktop-1.8.6/ctrl.c rdesktop-1.9.0/ctrl.c --- rdesktop-1.8.6/ctrl.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/ctrl.c 2019-06-13 12:10:15.000000000 +0000 @@ -1,7 +1,7 @@ /* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Master/Slave remote controlling - Copyright 2013 Henrik Andersson for Cendio AB + Copyright 2013-2017 Henrik Andersson for Cendio AB 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 @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -39,6 +40,7 @@ extern RD_BOOL g_seamless_rdp; extern uint8 g_static_rdesktop_salt_16[]; +extern char g_codepage[16]; static RD_BOOL _ctrl_is_slave; static int ctrlsock; @@ -80,7 +82,7 @@ } else { - /* no elemnts in list, lets add first */ + /* no elements in list, lets add first */ _ctrl_slaves = ns; } } @@ -185,7 +187,8 @@ if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { - perror("Error creating ctrl client socket: socket()"); + logger(Core, Error, "_ctrl_verify_unix_socket(), socket() failed: %s", + strerror(errno)); exit(1); } @@ -273,7 +276,7 @@ path[sizeof(path) - 1] = '\0'; if (utils_mkdir_p(path, 0700) == -1) { - perror(path); + logger(Core, Error, "ctrl_init(), utils_mkdir_p() failed: %s", strerror(errno)); return -1; } @@ -295,7 +298,7 @@ /* setup ctrl socket and start listening for connections */ if ((ctrlsock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { - perror("Error creating ctrl socket:"); + logger(Core, Error, "ctrl_init(), socket() failed: %s", strerror(errno)); exit(1); } @@ -305,13 +308,13 @@ strncpy(saun.sun_path, ctrlsock_name, sizeof(saun.sun_path)); if (bind(ctrlsock, (struct sockaddr *) &saun, sizeof(struct sockaddr_un)) < 0) { - perror("Error binding ctrl socket:"); + logger(Core, Error, "ctrl_init(), bind() failed: %s", strerror(errno)); exit(1); } if (listen(ctrlsock, 5) < 0) { - perror("Error listening on socket:"); + logger(Core, Error, "ctrl_init(), listen() failed: %s", strerror(errno)); exit(1); } @@ -362,6 +365,7 @@ void ctrl_check_fds(fd_set * rfds, fd_set * wfds) { + UNUSED(wfds); int ns, res, offs; struct sockaddr_un fsaun; socklen_t fromlen; @@ -380,7 +384,8 @@ ns = accept(ctrlsock, (struct sockaddr *) &fsaun, &fromlen); if (ns < 0) { - perror("server: accept()"); + logger(Core, Error, "ctrl_check_fds(), accept() failed: %s", + strerror(errno)); exit(1); } @@ -422,7 +427,7 @@ p = strchr(p + 1, '\n'); } - /* If we havent found an nonescaped \n we need more data */ + /* If we haven't found a nonescaped \n we need more data */ if (p == NULL) continue; @@ -442,10 +447,6 @@ } } -#if HAVE_ICONV -extern char g_codepage[16]; -#endif - int ctrl_send_command(const char *cmd, const char *arg) { @@ -462,7 +463,7 @@ if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { - perror("Error creating ctrl client socket: socket()"); + logger(Core, Error, "ctrl_send_command(), socket() failed: %s", strerror(errno)); exit(1); } @@ -473,7 +474,7 @@ if (connect(s, (struct sockaddr *) &saun, len) < 0) { - perror("Error connecting to ctrl socket: connect()"); + logger(Core, Error, "ctrl_send_command(), connect() failed: %s", strerror(errno)); exit(1); } @@ -484,12 +485,12 @@ if (ret != 0) goto bail_out; - /* escape the utf-8 string */ + /* escape the UTF-8 string */ escaped = utils_string_escape(tmp); if ((strlen(escaped) + 1) > CTRL_LINEBUF_SIZE - 1) goto bail_out; - /* send escaped utf-8 command to master */ + /* send escaped UTF-8 command to master */ send(s, escaped, strlen(escaped), 0); send(s, "\n", 1, 0); diff -Nru rdesktop-1.8.6/.cvsignore rdesktop-1.9.0/.cvsignore --- rdesktop-1.8.6/.cvsignore 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/.cvsignore 1970-01-01 00:00:00.000000000 +0000 @@ -1,8 +0,0 @@ -rdesktop -rdp2vnc -autom4te.cache -Makefile -config.log -config.status -configure -rdesktop*.tar.gz diff -Nru rdesktop-1.8.6/debian/changelog rdesktop-1.9.0/debian/changelog --- rdesktop-1.8.6/debian/changelog 2019-09-05 11:08:08.000000000 +0000 +++ rdesktop-1.9.0/debian/changelog 2019-10-13 08:19:11.000000000 +0000 @@ -1,8 +1,13 @@ -rdesktop (1.8.6-2build1) eoan; urgency=medium +rdesktop (1.9.0-1) unstable; urgency=medium - * No-change upload with strops.h and sys/strops.h removed in glibc. + * New upstream release. + * Update build dependencies. + * Update patches. + * Use short debhelper rules format. + * Update watch file. + * Update Standards-Version to 4.4.1 . - -- Matthias Klose Thu, 05 Sep 2019 11:08:08 +0000 + -- Laszlo Boszormenyi (GCS) Sun, 13 Oct 2019 08:19:11 +0000 rdesktop (1.8.6-2) unstable; urgency=medium diff -Nru rdesktop-1.8.6/debian/control rdesktop-1.9.0/debian/control --- rdesktop-1.8.6/debian/control 2019-01-07 23:03:14.000000000 +0000 +++ rdesktop-1.9.0/debian/control 2019-10-13 08:19:11.000000000 +0000 @@ -2,8 +2,8 @@ Section: x11 Priority: optional Maintainer: Laszlo Boszormenyi (GCS) -Build-Depends: debhelper (>= 11), dh-autoreconf, pkg-config, autoconf, automake, autotools-dev, libasound2-dev, libxt-dev, libx11-dev, libssl-dev, libxrandr-dev, libpcsclite-dev, libgssglue-dev -Standards-Version: 4.3.0 +Build-Depends: debhelper (>= 11), pkg-config, autoconf, automake, libasound2-dev, libxt-dev, libx11-dev, libxcursor-dev, libxrandr-dev, libkrb5-dev, gnutls-dev, libpcsclite-dev, libgssglue-dev, libtasn1-dev, nettle-dev +Standards-Version: 4.4.1 Homepage: https://www.rdesktop.org/ Package: rdesktop diff -Nru rdesktop-1.8.6/debian/patches/20_update_manpage.dpatch rdesktop-1.9.0/debian/patches/20_update_manpage.dpatch --- rdesktop-1.8.6/debian/patches/20_update_manpage.dpatch 2014-08-30 16:04:47.000000000 +0000 +++ rdesktop-1.9.0/debian/patches/20_update_manpage.dpatch 1970-01-01 00:00:00.000000000 +0000 @@ -1,20 +0,0 @@ -#! /bin/sh /usr/share/dpatch/dpatch-run -## 20_update_manpage.dpatch by Laszlo Boszormenyi -## -## All lines beginning with `## DP:' are a description of the patch. -## DP: Add the missing '-r clipboard' option to manpage. - -@DPATCH@ ---- del/rdesktop-1.6.0/doc/rdesktop.1 2007-01-19 14:47:35.000000000 +0100 -+++ rdesktop-1.6.0/doc/rdesktop.1 2011-03-26 13:55:09.806570001 +0100 -@@ -231,6 +231,10 @@ - - optional device vendor name. For list of examples run - rdesktop without parameters. - .TP -+.BR "-r clipboard:[off|PRIMARYCLIPBOARD|CLIPBOARD]" -+Enable clipboard redirection. 'PRIMARYCLIPBOARD' looks at both PRIMARY and -+CLIPBOARD when sending data to server. 'CLIPBOARD' looks at only CLIPBOARD. -+.TP - .BR "-0" - Attach to the console of the server (requires Windows Server 2003 - or newer). diff -Nru rdesktop-1.8.6/debian/patches/80_handle_nostrip_option.dpatch rdesktop-1.9.0/debian/patches/80_handle_nostrip_option.dpatch --- rdesktop-1.8.6/debian/patches/80_handle_nostrip_option.dpatch 2012-01-03 18:08:07.000000000 +0000 +++ rdesktop-1.9.0/debian/patches/80_handle_nostrip_option.dpatch 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -#! /bin/sh /usr/share/dpatch/dpatch-run -## 80_handle_nostrip_option.dpatch by Laszlo Boszormenyi . -## -## All lines beginning with `## DP:' are a description of the patch. -## DP: Don't strip binary if asked for nostrip via DEB_BUILD_OPTIONS . - -@DPATCH@ ---- rdesktop-1.6.0.orig/Makefile.in -+++ rdesktop-1.6.0/Makefile.in -@@ -18,7 +18,11 @@ - INSTALL = @INSTALL@ - CFLAGS = @CFLAGS@ @X_CFLAGS@ @DEFS@ -DKEYMAP_PATH=\"$(KEYMAP_PATH)\" - LDFLAGS = @LDFLAGS@ @LIBS@ @X_LIBS@ @X_EXTRA_LIBS@ -+ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS))) - STRIP = @STRIP@ -+else -+STRIP=/bin/true -+endif - - TARGETS = rdesktop @RDP2VNCTARGET@ - VNCINC = @VNCINC@ diff -Nru rdesktop-1.8.6/debian/patches/80_handle_nostrip_option.patch rdesktop-1.9.0/debian/patches/80_handle_nostrip_option.patch --- rdesktop-1.8.6/debian/patches/80_handle_nostrip_option.patch 1970-01-01 00:00:00.000000000 +0000 +++ rdesktop-1.9.0/debian/patches/80_handle_nostrip_option.patch 2019-10-13 08:19:11.000000000 +0000 @@ -0,0 +1,22 @@ +Description: Don't force strip the binary + Skip strip when asked to. +Author: Laszlo Boszormenyi (GCS) +Forwarded: not-needed +Last-Update: 2019-10-13 + +--- + +--- rdesktop-1.9.0.orig/Makefile.in ++++ rdesktop-1.9.0/Makefile.in +@@ -18,7 +18,11 @@ CC = @CC@ + INSTALL = @INSTALL@ + CFLAGS = @CFLAGS@ @X_CFLAGS@ @DEFS@ -DKEYMAP_PATH=\"$(KEYMAP_PATH)\" + LDFLAGS = @LDFLAGS@ @LIBS@ @X_LIBS@ @X_EXTRA_LIBS@ ++ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS))) + STRIP = @STRIP@ ++else ++STRIP=/bin/true ++endif + + TARGETS = rdesktop + SOUNDOBJ = @SOUNDOBJ@ diff -Nru rdesktop-1.8.6/debian/patches/90-fixed_version_number_and_typo.patch rdesktop-1.9.0/debian/patches/90-fixed_version_number_and_typo.patch --- rdesktop-1.8.6/debian/patches/90-fixed_version_number_and_typo.patch 2019-06-14 15:32:01.000000000 +0000 +++ rdesktop-1.9.0/debian/patches/90-fixed_version_number_and_typo.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ -From 231502e1cf934bac130432f42bf44efcac34f517 Mon Sep 17 00:00:00 2001 -From: Markus Beth -Date: Wed, 22 May 2019 19:51:40 +0200 -Subject: [PATCH] fixed version number and typo - ---- - doc/ChangeLog | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/doc/ChangeLog b/doc/ChangeLog -index 3a054d18..62eb5ef6 100644 ---- a/doc/ChangeLog -+++ b/doc/ChangeLog -@@ -1,4 +1,4 @@ --rdesktop (1.8.5) -+rdesktop (1.8.6) - * Fix protocol code handling new licenses - - -- Pierre Ossman 2019-05-16 -@@ -81,7 +81,7 @@ rdesktop (1.8.1) - * Fix issue with reconnect, make use of deactivate variable - * Added 4 new disconnect reasons with exit codes - * Fix issues of window handling in SeamlessRDP parts of rdesktop -- * Fix a backward compability with OpenSSL < 0.9.9 -+ * Fix a backward compatibility with OpenSSL < 0.9.9 - * Fix a bug when code needs a x window available but there are none. - * Fix a sigsegv zeroing memory - * Fix a 64bit portability issue diff -Nru rdesktop-1.8.6/debian/patches/91-sec_decrypt_the_correct_amount_of_data.patch rdesktop-1.9.0/debian/patches/91-sec_decrypt_the_correct_amount_of_data.patch --- rdesktop-1.8.6/debian/patches/91-sec_decrypt_the_correct_amount_of_data.patch 2019-06-14 15:32:25.000000000 +0000 +++ rdesktop-1.9.0/debian/patches/91-sec_decrypt_the_correct_amount_of_data.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,59 +0,0 @@ -From 7841030279c5300d5073b2348b58f3f41e136f82 Mon Sep 17 00:00:00 2001 -From: Markus Beth -Date: Tue, 11 Jun 2019 22:57:31 +0200 -Subject: [PATCH] sec_decrypt() the correct amount of data - -Save the correct amount of data to sec_decrypt() because after -inout_uint8p() the macro s_remaining(s) will find nothing left. ---- - secure.c | 16 ++++++++++------ - 1 file changed, 10 insertions(+), 6 deletions(-) - -diff --git a/secure.c b/secure.c -index 8f65b3aa..9b301e1f 100644 ---- a/secure.c -+++ b/secure.c -@@ -813,6 +813,7 @@ sec_recv(uint8 * rdpver) - STREAM s; - struct stream packet; - size_t data_offset; -+ size_t remaining; - unsigned char *data; - - while ((s = mcs_recv(&channel, rdpver)) != NULL) -@@ -832,8 +833,9 @@ sec_recv(uint8 * rdpver) - - data_offset = s_tell(s); - -- inout_uint8p(s, data, s_remaining(s)); -- sec_decrypt(data, s_remaining(s)); -+ remaining = s_remaining(s); -+ inout_uint8p(s, data, remaining); -+ sec_decrypt(data, remaining); - - s_seek(s, data_offset); - } -@@ -860,8 +862,9 @@ sec_recv(uint8 * rdpver) - - data_offset = s_tell(s); - -- inout_uint8p(s, data, s_remaining(s)); -- sec_decrypt(data, s_remaining(s)); -+ remaining = s_remaining(s); -+ inout_uint8p(s, data, remaining); -+ sec_decrypt(data, remaining); - } - - if (sec_flags & SEC_LICENCE_NEG) -@@ -883,8 +886,9 @@ sec_recv(uint8 * rdpver) - - data_offset = s_tell(s); - -- inout_uint8p(s, data, s_remaining(s)); -- sec_decrypt(data, s_remaining(s)); -+ remaining = s_remaining(s); -+ inout_uint8p(s, data, remaining); -+ sec_decrypt(data, remaining); - - /* Check for a redirect packet, starts with 00 04 */ - if (data[0] == 0 && data[1] == 4) diff -Nru rdesktop-1.8.6/debian/patches/series rdesktop-1.9.0/debian/patches/series --- rdesktop-1.8.6/debian/patches/series 2019-06-14 15:32:25.000000000 +0000 +++ rdesktop-1.9.0/debian/patches/series 2019-10-13 08:19:11.000000000 +0000 @@ -1,23 +1,2 @@ -# Nomenclature for the file ordering/naming -# First digit: -# 1 -> Has been applied in some branch upstream. -# It will eventually be applied in a release -# 2 -> Has been or will be fixed differently upstream -# 3 -> Pending upstream. Waiting to land on a branch or some review, -# or some asked modifications -# 6 -> Not yet sent upstream -# 8 -> Debian specific. This we don't want to send upstream or that -# upstream don't want to apply. -# -# Second digit: -# 0 -> Build system -# 1 -> Mostly build -# 2 -> Preferences -# 5 -> General code -# 8 -> Fix for some architectures support -# -01_paging.patch -20_update_manpage.dpatch -80_handle_nostrip_option.dpatch -90-fixed_version_number_and_typo.patch -91-sec_decrypt_the_correct_amount_of_data.patch +#01_paging.patch +80_handle_nostrip_option.patch diff -Nru rdesktop-1.8.6/debian/rules rdesktop-1.9.0/debian/rules --- rdesktop-1.8.6/debian/rules 2014-10-16 16:23:42.000000000 +0000 +++ rdesktop-1.9.0/debian/rules 2019-10-13 08:19:11.000000000 +0000 @@ -4,77 +4,10 @@ # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 -# These are used for cross-compiling and for saving the configure script -# from having to guess our platform (since we know it already) -DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) -DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) +override_dh_auto_configure: + dh_auto_configure -- --with-ipv6 --with-sound=alsa --enable-smartcard -CFLAGS = `dpkg-buildflags --get CFLAGS` -CFLAGS += -Wall +%: + dh $@ -LDFLAGS_DEF += `dpkg-buildflags --get LDFLAGS` -CPPFLAGS_DEF = `dpkg-buildflags --get CPPFLAGS` - -config.status: configure.ac - dh_testdir - dh_autotools-dev_updateconfig - dh_autoreconf - ./bootstrap - - CFLAGS="$(CFLAGS)" CPPFLAGS="$(CPPFLAGS_DEF)" LDFLAGS="$(LDFLAGS_DEF)" ./configure --host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info --with-ipv6 --with-sound=alsa --enable-smartcard - -build-arch: build-stamp -build-indep: build-stamp - -build: build-arch build-indep - -build-stamp: config.status - dh_testdir - - $(MAKE) - - touch build-stamp - -clean: - dh_testdir - dh_testroot - dh_autoreconf_clean - rm -f build-stamp - - [ ! -f Makefile ] || $(MAKE) distclean - - rm -f config.log aclocal.m4 configure - dh_autotools-dev_restoreconfig - dh_clean - -install: build - dh_testdir - dh_testroot - dh_prep - dh_installdirs - - $(MAKE) install DESTDIR=$(CURDIR)/debian/rdesktop - -binary-indep: build install - -binary-arch: build install - dh_testdir - dh_testroot - dh_installchangelogs doc/ChangeLog - dh_installexamples - dh_install - dh_installmenu - dh_installman - dh_installdocs - dh_link - dh_strip - dh_compress - dh_fixperms - dh_installdeb - dh_shlibdeps - dh_gencontrol - dh_md5sums - dh_builddeb - -binary: binary-indep binary-arch -.PHONY: build clean binary-indep binary-arch binary install +.PHONY: dh_auto_configure diff -Nru rdesktop-1.8.6/debian/watch rdesktop-1.9.0/debian/watch --- rdesktop-1.8.6/debian/watch 2016-09-23 17:24:14.000000000 +0000 +++ rdesktop-1.9.0/debian/watch 2019-10-13 08:19:11.000000000 +0000 @@ -1,4 +1,4 @@ -version=3 -opts=uversionmangle=s/-b(\d+)$/~beta$1/,dversionmangle=s/\.dfsg// \ +version=4 +opts=uversionmangle=s/-beta$/~beta/,dversionmangle=s/\.dfsg// \ https://github.com/rdesktop/rdesktop/tags \ (?:|.*/)v?(\d\S*)\.(?:tar\.xz|txz|tar\.bz2|tbz2|tar\.gz|tgz) diff -Nru rdesktop-1.8.6/disk.c rdesktop-1.9.0/disk.c --- rdesktop-1.8.6/disk.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/disk.c 2019-06-13 12:10:15.000000000 +0000 @@ -3,6 +3,9 @@ Disk Redirection Copyright (C) Jeroen Meijer 2003-2008 Copyright 2003-2011 Peter Astrand for Cendio AB + Copyright 2017 Henrik Andersson for Cendio AB + Copyright 2017 Karl Mikaelsson for Cendio AB + Copyright 2017 Alexander Zakharov 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 @@ -219,35 +222,36 @@ /* Get current position */ if ((pos = lseek(fd, 0, SEEK_CUR)) == -1) { - perror("lseek"); + logger(Disk, Error, "ftruncate_growable(), lseek() failed: %s", strerror(errno)); return -1; } /* Seek to new size */ if (lseek(fd, length, SEEK_SET) == -1) { - perror("lseek"); + logger(Disk, Error, "ftruncate_growable(), lseek() failed: %s", strerror(errno)); return -1; } /* Write a zero */ if (write(fd, &zero, 1) == -1) { - perror("write"); + logger(Disk, Error, "ftruncate_growable(), write() failed: %s", strerror(errno)); return -1; } /* Truncate. This shouldn't fail. */ if (ftruncate(fd, length) == -1) { - perror("ftruncate"); + logger(Disk, Error, "ftruncate_growable(), ftruncate() failed: %s", + strerror(errno)); return -1; } /* Restore position */ if (lseek(fd, pos, SEEK_SET) == -1) { - perror("lseek"); + logger(Disk, Error, "ftruncate_growable(), lseek() failed: %s", strerror(errno)); return -1; } @@ -273,7 +277,7 @@ return ret; } - /* An error occured, and we are using O_EXCL. In case the FS + /* An error occurred, and we are using O_EXCL. In case the FS doesn't support O_EXCL, some kind of error will be returned. Unfortunately, we don't know which one. Linux 2.6.8 seems to return 524, but I cannot find a documented @@ -306,7 +310,7 @@ } /* Enumeration of devices from rdesktop.c */ -/* returns numer of units found and initialized. */ +/* returns number of units found and initialized. */ /* optarg looks like ':h=/mnt/floppy,b=/mnt/usbdevice1' */ /* when it arrives to this function. */ int @@ -315,6 +319,7 @@ char *pos = optarg; char *pos2; int count = 0; + DISK_DEVICE *pdisk_data; /* skip the first colon */ optarg++; @@ -322,14 +327,16 @@ { pos2 = next_arg(optarg, '='); + pdisk_data = (DISK_DEVICE *) xmalloc(sizeof(DISK_DEVICE)); + memset(pdisk_data, 0, sizeof(DISK_DEVICE)); + strncpy(pdisk_data->name, optarg, sizeof(pdisk_data->name) - 1); strncpy(g_rdpdr_device[*id].name, optarg, sizeof(g_rdpdr_device[*id].name) - 1); - if (strlen(optarg) > (sizeof(g_rdpdr_device[*id].name) - 1)) - fprintf(stderr, "share name %s truncated to %s\n", optarg, - g_rdpdr_device[*id].name); g_rdpdr_device[*id].local_path = (char *) xmalloc(strlen(pos2) + 1); strcpy(g_rdpdr_device[*id].local_path, pos2); g_rdpdr_device[*id].device_type = DEVICE_TYPE_DISK; + g_rdpdr_device[*id].pdevice_data = (void *) pdisk_data; + count++; (*id)++; @@ -343,12 +350,15 @@ disk_create(uint32 device_id, uint32 accessmask, uint32 sharemode, uint32 create_disposition, uint32 flags_and_attributes, char *filename, RD_NTHANDLE * phandle) { - RD_NTHANDLE handle; + int handle; DIR *dirp; int flags, mode; char path[PATH_MAX]; struct stat filestat; + logger(Disk, Debug, "disk_create(device_id=0x%x, accessmask=0x%x, sharemode=0x%x, " + "create_disp=%d, flags=0x%x, fname=%s, ...)", device_id, accessmask, + sharemode, create_disposition, flags_and_attributes, filename); handle = 0; dirp = NULL; flags = 0; @@ -359,7 +369,7 @@ sprintf(path, "%s%s", g_rdpdr_device[device_id].local_path, filename ? filename : ""); - /* Protect against mailicous servers: + /* Protect against malicious servers: somelongpath/.. not allowed somelongpath/../b not allowed somelongpath/..b in principle ok, but currently not allowed @@ -407,7 +417,7 @@ /*printf("Open: \"%s\" flags: %X, accessmask: %X sharemode: %X create disp: %X\n", path, flags_and_attributes, accessmask, sharemode, create_disposition); */ - /* Get information about file and set that flag ourselfs */ + /* Get information about file and set that flag ourselves */ if ((stat(path, &filestat) == 0) && (S_ISDIR(filestat.st_mode))) { if (flags_and_attributes & FILE_NON_DIRECTORY_FILE) @@ -437,8 +447,8 @@ return RD_STATUS_NO_SUCH_FILE; default: - - perror("opendir"); + logger(Disk, Error, "disk_create(), opendir() failed: %s", + strerror(errno)); return RD_STATUS_NO_SUCH_FILE; } } @@ -481,21 +491,23 @@ return RD_STATUS_OBJECT_NAME_COLLISION; default: - - perror("open"); + logger(Disk, Error, "disk_create(), open() failed: %s", + strerror(errno)); return RD_STATUS_NO_SUCH_FILE; } } /* all read and writes of files should be non blocking */ if (fcntl(handle, F_SETFL, O_NONBLOCK) == -1) - perror("fcntl"); + logger(Disk, Error, "disk_create(), fcntl() failed: %s", strerror(errno)); + } if (handle >= MAX_OPEN_FILES) { - error("Maximum number of open files (%s) reached. Increase MAX_OPEN_FILES!\n", - handle); + logger(Disk, Error, + "disk_create(), handle (%d) is greater than or equal to MAX_OPEN_FILES (%d)!", + handle, MAX_OPEN_FILES); exit(EX_SOFTWARE); } @@ -522,6 +534,8 @@ { struct fileinfo *pfinfo; + logger(Disk, Debug, "disk_close(handle=0x%x)", handle); + pfinfo = &(g_fileinfo[handle]); if (pfinfo->accessmask & GENERIC_ALL || pfinfo->accessmask & GENERIC_WRITE) @@ -533,14 +547,15 @@ { if (closedir(pfinfo->pdir) < 0) { - perror("closedir"); + logger(Disk, Error, "disk_close(), closedir() failed: %s", strerror(errno)); return RD_STATUS_INVALID_HANDLE; } if (pfinfo->delete_on_close) if (rmdir(pfinfo->path) < 0) { - perror(pfinfo->path); + logger(Disk, Error, "disk_close(), rmdir() failed: %s", + strerror(errno)); return RD_STATUS_ACCESS_DENIED; } pfinfo->delete_on_close = False; @@ -549,13 +564,14 @@ { if (close(handle) < 0) { - perror("close"); + logger(Disk, Error, "disk_close(), close() failed: %s", strerror(errno)); return RD_STATUS_INVALID_HANDLE; } if (pfinfo->delete_on_close) if (unlink(pfinfo->path) < 0) { - perror(pfinfo->path); + logger(Disk, Error, "disk_close(), unlink() failed: %s", + strerror(errno)); return RD_STATUS_ACCESS_DENIED; } @@ -566,7 +582,7 @@ } static RD_NTSTATUS -disk_read(RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result) +disk_read(RD_NTHANDLE handle, uint8 * data, uint32 length, uint64 offset, uint32 * result) { int n; @@ -595,7 +611,8 @@ /* return STATUS_FILE_IS_A_DIRECTORY; */ return RD_STATUS_NOT_IMPLEMENTED; default: - perror("read"); + logger(Disk, Error, "disk_read(), read failed: %s", + strerror(errno)); return RD_STATUS_INVALID_PARAMETER; } } @@ -606,7 +623,7 @@ } static RD_NTSTATUS -disk_write(RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result) +disk_write(RD_NTHANDLE handle, uint8 * data, uint32 length, uint64 offset, uint32 * result) { int n; @@ -616,7 +633,7 @@ if (n < 0) { - perror("write"); + logger(Disk, Error, "disk_write(), write() failed: %s", strerror(errno)); *result = 0; switch (errno) { @@ -632,6 +649,7 @@ return RD_STATUS_SUCCESS; } +/* Btw, all used Flie* structures are described in [MS-FSCC] */ RD_NTSTATUS disk_query_information(RD_NTHANDLE handle, uint32 info_class, STREAM out) { @@ -639,12 +657,15 @@ struct stat filestat; char *path, *filename; + logger(Disk, Debug, "disk_query_information(handle=0x%x, info_class=0x%x)", handle, + info_class); + path = g_fileinfo[handle].path; /* Get information about file */ if (fstat(handle, &filestat) != 0) { - perror("stat"); + logger(Disk, Error, "disk_query_information(), stat() failed: %s", strerror(errno)); out_uint8(out, 0); return RD_STATUS_ACCESS_DENIED; } @@ -654,7 +675,10 @@ if (S_ISDIR(filestat.st_mode)) file_attributes |= FILE_ATTRIBUTE_DIRECTORY; - filename = 1 + strrchr(path, '/'); + filename = strrchr(path, '/'); + if (filename) + filename += 1; + if (filename && filename[0] == '.') file_attributes |= FILE_ATTRIBUTE_HIDDEN; @@ -690,10 +714,9 @@ case FileStandardInformation: - out_uint32_le(out, filestat.st_size); /* Allocation size */ - out_uint32_le(out, 0); - out_uint32_le(out, filestat.st_size); /* End of file */ - out_uint32_le(out, 0); + out_uint64_le(out, filestat.st_size); /* Allocation size */ + out_uint64_le(out, filestat.st_size); /* End of file */ + out_uint32_le(out, filestat.st_nlink); /* Number of links */ out_uint8(out, 0); /* Delete pending */ out_uint8(out, S_ISDIR(filestat.st_mode) ? 1 : 0); /* Directory */ @@ -706,16 +729,19 @@ break; default: - - unimpl("IRP Query (File) Information class: 0x%x\n", info_class); + logger(Disk, Warning, + "disk_query_information(), unhandled query information class 0x%x", + info_class); return RD_STATUS_INVALID_PARAMETER; } return RD_STATUS_SUCCESS; } +/* 2.2.3.3.9 [MS-RDPEFS] */ RD_NTSTATUS disk_set_information(RD_NTHANDLE handle, uint32 info_class, STREAM in, STREAM out) { + UNUSED(out); uint32 length, file_attributes, ft_high, ft_low; char *newname, fullpath[PATH_MAX]; struct fileinfo *pfinfo; @@ -725,6 +751,9 @@ struct utimbuf tvs; struct STATFS_T stat_fs; + logger(Disk, Debug, "disk_set_information(handle=0x%x, info_class=0x%x, ...)", handle, + info_class); + pfinfo = &(g_fileinfo[handle]); g_notify_stamp = True; newname = NULL; @@ -734,8 +763,8 @@ case FileBasicInformation: write_time = change_time = access_time = 0; - in_uint8s(in, 4); /* Handle of root dir? */ - in_uint8s(in, 24); /* unknown */ + in_uint8s(in, 4); /* length of SetBuffer */ + in_uint8s(in, 24); /* padding */ /* CreationTime */ in_uint32_le(in, ft_low); @@ -781,12 +810,9 @@ if (access_time || write_time || change_time) { -#if WITH_DEBUG_RDP5 - printf("FileBasicInformation access time %s", - ctime(&tvs.actime)); - printf("FileBasicInformation modification time %s", - ctime(&tvs.modtime)); -#endif + logger(Disk, Debug, + "disk_set_information(), access time='%s', modify time='%s'", + ctime(&tvs.actime), ctime(&tvs.modtime)); if (utime(pfinfo->path, &tvs) && errno != EPERM) return RD_STATUS_ACCESS_DENIED; } @@ -802,9 +828,8 @@ mode |= S_IWUSR; mode &= 0777; -#if WITH_DEBUG_RDP5 - printf("FileBasicInformation set access mode 0%o", mode); -#endif + + logger(Disk, Debug, "disk_set_information(), access mode 0%o", mode); if (fchmod(handle, mode)) return RD_STATUS_ACCESS_DENIED; @@ -833,7 +858,8 @@ if (rename(pfinfo->path, fullpath) != 0) { - perror("rename"); + logger(Disk, Error, "disk_set_information(), rename() failed: %s", + strerror(errno)); return RD_STATUS_ACCESS_DENIED; } break; @@ -915,8 +941,9 @@ break; default: - - unimpl("IRP Set File Information class: 0x%x\n", info_class); + logger(Disk, Warning, + "disk_set_information(), unhandled information class 0x%x", + info_class); return RD_STATUS_INVALID_PARAMETER; } return RD_STATUS_SUCCESS; @@ -927,9 +954,10 @@ { struct fileinfo *pfinfo; RD_NTSTATUS status = RD_STATUS_PENDING; - NOTIFY notify; + logger(Disk, Debug, "disk_check_notify(handle=0x%x)", handle); + pfinfo = &(g_fileinfo[handle]); if (!pfinfo->pdir) return RD_STATUS_INVALID_DEVICE_REQUEST; @@ -956,11 +984,10 @@ RD_NTSTATUS disk_create_notify(RD_NTHANDLE handle, uint32 info_class) { - struct fileinfo *pfinfo; RD_NTSTATUS ret = RD_STATUS_PENDING; - /* printf("start disk_create_notify info_class %X\n", info_class); */ + logger(Disk, Debug, "disk_create_notify(handle=0x%x, info_class=0x%x)", handle, info_class); pfinfo = &(g_fileinfo[handle]); pfinfo->info_class = info_class; @@ -983,6 +1010,7 @@ static RD_NTSTATUS NotifyInfo(RD_NTHANDLE handle, uint32 info_class, NOTIFY * p) { + UNUSED(info_class); struct fileinfo *pfinfo; struct stat filestat; struct dirent *dp; @@ -992,7 +1020,7 @@ pfinfo = &(g_fileinfo[handle]); if (fstat(handle, &filestat) < 0) { - perror("NotifyInfo"); + logger(Disk, Error, "NotifyInfo(), fstat failed: %s", strerror(errno)); return RD_STATUS_ACCESS_DENIED; } p->modify_time = filestat.st_mtime; @@ -1004,7 +1032,7 @@ dpr = opendir(pfinfo->path); if (!dpr) { - perror("NotifyInfo"); + logger(Disk, Error, "NotifyInfo(), opendir failed: %s", strerror(errno)); return RD_STATUS_ACCESS_DENIED; } @@ -1103,12 +1131,17 @@ struct STATFS_T stat_fs; struct fileinfo *pfinfo; FsInfoType *fsinfo; + STREAM stmp; + + logger(Disk, Debug, "disk_query_volume_information(handle=0x%x, info_class=0x%x)", handle, + info_class); pfinfo = &(g_fileinfo[handle]); if (STATFS_FN(pfinfo->path, &stat_fs) != 0) { - perror("statfs"); + logger(Disk, Error, "disk_query_volume_information(), statfs() failed: %s", + strerror(errno)); return RD_STATUS_ACCESS_DENIED; } @@ -1117,46 +1150,47 @@ switch (info_class) { case FileFsVolumeInformation: + stmp = s_alloc(PATH_MAX * 4); + out_utf16s(stmp, fsinfo->label); + s_mark_end(stmp); out_uint32_le(out, 0); /* volume creation time low */ out_uint32_le(out, 0); /* volume creation time high */ out_uint32_le(out, fsinfo->serial); /* serial */ - - out_uint32_le(out, 2 * strlen(fsinfo->label)); /* length of string */ - + out_uint32_le(out, s_length(stmp)); /* length of string */ out_uint8(out, 0); /* support objects? */ - rdp_out_unistr(out, fsinfo->label, 2 * strlen(fsinfo->label) - 2); + out_stream(out, stmp); /* fsinfo->label string */ + s_free(stmp); break; case FileFsSizeInformation: - out_uint32_le(out, stat_fs.f_blocks); /* Total allocation units low */ - out_uint32_le(out, 0); /* Total allocation high units */ - out_uint32_le(out, stat_fs.f_bfree); /* Available allocation units */ - out_uint32_le(out, 0); /* Available allowcation units */ + out_uint64_le(out, stat_fs.f_blocks); /* Total allocation units */ + out_uint64_le(out, stat_fs.f_bfree); /* Available allocation units */ out_uint32_le(out, stat_fs.f_bsize / 0x200); /* Sectors per allocation unit */ out_uint32_le(out, 0x200); /* Bytes per sector */ break; case FileFsFullSizeInformation: - out_uint32_le(out, stat_fs.f_blocks); /* Total allocation units low */ - out_uint32_le(out, 0); /* Total allocation units high */ - out_uint32_le(out, stat_fs.f_bavail); /* Caller allocation units low */ - out_uint32_le(out, 0); /* Caller allocation units high */ - out_uint32_le(out, stat_fs.f_bfree); /* Available allocation units */ - out_uint32_le(out, 0); /* Available allowcation units */ + out_uint64_le(out, stat_fs.f_blocks); /* Total allocation units */ + out_uint64_le(out, stat_fs.f_bavail); /* Caller allocation units */ + out_uint64_le(out, stat_fs.f_bfree); /* Available allocation units */ out_uint32_le(out, stat_fs.f_bsize / 0x200); /* Sectors per allocation unit */ out_uint32_le(out, 0x200); /* Bytes per sector */ break; case FileFsAttributeInformation: + stmp = s_alloc(PATH_MAX * 4); + out_utf16s_no_eos(stmp, fsinfo->type); + s_mark_end(stmp); out_uint32_le(out, FS_CASE_SENSITIVE | FS_CASE_IS_PRESERVED); /* fs attributes */ out_uint32_le(out, F_NAMELEN(stat_fs)); /* max length of filename */ - out_uint32_le(out, 2 * strlen(fsinfo->type)); /* length of fs_type */ - rdp_out_unistr(out, fsinfo->type, 2 * strlen(fsinfo->type) - 2); + out_uint32_le(out, s_length(stmp)); /* length of fsinfo->type string */ + out_stream(out, stmp); /* fsinfo->typ string */ + s_free(stmp); break; case FileFsLabelInformation: @@ -1166,8 +1200,9 @@ case FileFsMaximumInformation: default: - - unimpl("IRP Query Volume Information class: 0x%x\n", info_class); + logger(Disk, Warning, + "disk_query_volume_information(), unhandled volume info class 0x%x", + info_class); return RD_STATUS_INVALID_PARAMETER; } return RD_STATUS_SUCCESS; @@ -1182,13 +1217,16 @@ struct dirent *pdirent; struct stat filestat; struct fileinfo *pfinfo; + STREAM stmp; + + logger(Disk, Debug, "disk_query_directory(handle=0x%x, info_class=0x%x, pattern=%s, ...)", + handle, info_class, pattern); pfinfo = &(g_fileinfo[handle]); pdir = pfinfo->pdir; dirname = pfinfo->path; file_attributes = 0; - switch (info_class) { case FileBothDirectoryInformation: @@ -1227,7 +1265,9 @@ default: /* Fatal error. By returning STATUS_NO_SUCH_FILE, the directory list operation will be aborted */ - perror(fullpath); + logger(Disk, Error, + "disk_query_directory(), stat() failed: %s", + strerror(errno)); out_uint8(out, 0); return RD_STATUS_NO_SUCH_FILE; } @@ -1248,10 +1288,17 @@ break; default: - unimpl("IRP Query Directory sub: 0x%x\n", info_class); + logger(Disk, Warning, + "disk_query_directory(), unhandled directory info class 0x%x", + info_class); return RD_STATUS_INVALID_PARAMETER; } + // Write entry name as utf16 into stmp + stmp = s_alloc(PATH_MAX * 4); + out_utf16s_no_eos(stmp, pdirent->d_name); + s_mark_end(stmp); + switch (info_class) { case FileBothDirectoryInformation: @@ -1273,19 +1320,14 @@ out_uint32_le(out, ft_low); /* change_write_time */ out_uint32_le(out, ft_high); - out_uint32_le(out, filestat.st_size); /* filesize low */ - out_uint32_le(out, 0); /* filesize high */ - out_uint32_le(out, filestat.st_size); /* filesize low */ - out_uint32_le(out, 0); /* filesize high */ + out_uint64_le(out, filestat.st_size); /* filesize */ + out_uint64_le(out, filestat.st_size); /* filesize */ out_uint32_le(out, file_attributes); /* FileAttributes */ - out_uint32_le(out, 2 * strlen(pdirent->d_name) + 2); /* unicode length */ + out_uint32_le(out, s_length(stmp)); /* length of dir entry name string */ out_uint32_le(out, 0); /* EaSize */ out_uint8(out, 0); /* ShortNameLength */ - /* this should be correct according to MS-FSCC specification - but it only works when commented out... */ - /* out_uint8(out, 0); *//* Reserved/Padding */ - out_uint8s(out, 2 * 12); /* ShortName (8.3 name) */ - rdp_out_unistr(out, pdirent->d_name, 2 * strlen(pdirent->d_name)); + out_uint8s(out, 24); /* ShortName (8.3 name) */ + out_stream(out, stmp); /* dir entry name string */ break; @@ -1308,13 +1350,11 @@ out_uint32_le(out, ft_low); /* change_write_time */ out_uint32_le(out, ft_high); - out_uint32_le(out, filestat.st_size); /* filesize low */ - out_uint32_le(out, 0); /* filesize high */ - out_uint32_le(out, filestat.st_size); /* filesize low */ - out_uint32_le(out, 0); /* filesize high */ + out_uint64_le(out, filestat.st_size); /* filesize */ + out_uint64_le(out, filestat.st_size); /* filesize */ out_uint32_le(out, file_attributes); - out_uint32_le(out, 2 * strlen(pdirent->d_name) + 2); /* unicode length */ - rdp_out_unistr(out, pdirent->d_name, 2 * strlen(pdirent->d_name)); + out_uint32_le(out, s_length(stmp)); /* dir entry name string length */ + out_stream(out, stmp); /* dir entry name */ break; @@ -1337,30 +1377,32 @@ out_uint32_le(out, ft_low); /* change_write_time */ out_uint32_le(out, ft_high); - out_uint32_le(out, filestat.st_size); /* filesize low */ - out_uint32_le(out, 0); /* filesize high */ - out_uint32_le(out, filestat.st_size); /* filesize low */ - out_uint32_le(out, 0); /* filesize high */ + out_uint64_le(out, filestat.st_size); /* filesize */ + out_uint64_le(out, filestat.st_size); /* filesize */ out_uint32_le(out, file_attributes); - out_uint32_le(out, 2 * strlen(pdirent->d_name) + 2); /* unicode length */ + out_uint32_le(out, s_length(stmp)); /* dir entry name string length */ out_uint32_le(out, 0); /* EaSize */ - rdp_out_unistr(out, pdirent->d_name, 2 * strlen(pdirent->d_name)); + out_stream(out, stmp); /* dir entry name */ break; case FileNamesInformation: - out_uint32_le(out, 2 * strlen(pdirent->d_name) + 2); /* unicode length */ - rdp_out_unistr(out, pdirent->d_name, 2 * strlen(pdirent->d_name)); + out_uint32_le(out, s_length(stmp)); /* dir entry name string length */ + out_stream(out, stmp); /* dir entry name */ break; default: - - unimpl("IRP Query Directory sub: 0x%x\n", info_class); + logger(Disk, Warning, + "disk_query_directory(), unhandled directory info class 0x%x", + info_class); + s_free(stmp); return RD_STATUS_INVALID_PARAMETER; } + s_free(stmp); + return RD_STATUS_SUCCESS; } @@ -1369,6 +1411,10 @@ static RD_NTSTATUS disk_device_control(RD_NTHANDLE handle, uint32 request, STREAM in, STREAM out) { + UNUSED(in); + UNUSED(out); + + logger(Disk, Debug, "disk_device_control(handle=0x%x, request=0x%x, ...)", handle, request); if (((request >> 16) != 20) || ((request >> 16) != 9)) return RD_STATUS_INVALID_PARAMETER; @@ -1376,14 +1422,13 @@ request >>= 2; request &= 0xfff; - printf("DISK IOCTL %d\n", request); - switch (request) { case 25: /* ? */ case 42: /* ? */ default: - unimpl("DISK IOCTL %d\n", request); + logger(Disk, Warning, "disk_device_control(), unhandled disk ioctl %d", + request); return RD_STATUS_INVALID_PARAMETER; } diff -Nru rdesktop-1.8.6/doc/ChangeLog rdesktop-1.9.0/doc/ChangeLog --- rdesktop-1.8.6/doc/ChangeLog 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/doc/ChangeLog 2019-09-18 09:01:43.000000000 +0000 @@ -1,4 +1,23 @@ -rdesktop (1.8.5) +rdesktop (1.9.0) + * Use GnuTLS and nettle instead of OpenSSL + * Improved certificate handling + * Add support for dynamic resize of sessions + * Add support for alpha cursors + * Add PulseAudio support + * Add Kerberos support on macOS + * Kerberos support no longer requires libgssglue + * Remove support for rdesktop's custom microphone extension + * Several fixes to improve compatibility with modern desktops + * macOS compatibility fixes + * Improved handling of redirections + * Many smart card bug fixes + * Many disk redirection bug fixes + * Improved logging + * Lots of other small bug fixes + + -- Pierre Ossman 2019-09-18 + +rdesktop (1.8.6) * Fix protocol code handling new licenses -- Pierre Ossman 2019-05-16 @@ -81,15 +100,15 @@ * Fix issue with reconnect, make use of deactivate variable * Added 4 new disconnect reasons with exit codes * Fix issues of window handling in SeamlessRDP parts of rdesktop - * Fix a backward compability with OpenSSL < 0.9.9 + * Fix a backward compatibility with OpenSSL < 0.9.9 * Fix a bug when code needs a x window available but there are none. * Fix a sigsegv zeroing memory - * Fix a 64bit portability issue + * Fix a 64-bit portability issue -- Henrik Andersson 2013-11-18 rdesktop (1.8.0) - * Support for protocol negotiation eg. SSL/TLSv1 and CredSSP + * Support for protocol negotiation e.g. SSL/TLSv1 and CredSSP * Support for CredSSP + Kerberos authentication (NLA) * Support for smart card single-sign-on * Support passing smart card pin as password as argument @@ -107,10 +126,10 @@ rdesktop (1.7.1) * Fix clipboard issue when not building with unicode support - * Fix compilation against newer PCSC lite versions + * Fix compilation against newer PCSC-lite versions * Fix for per-device license mode on Windows 2008 R2 terminal server - * Fix building 64bit version with static openssl linkage - * Rewrite of smartcard handling for 64bit support, fixes several bugs + * Fix building 64-bit version with static openssl linkage + * Rewrite of smartcard handling for 64-bit support, fixes several bugs * Improved license handling using XDG directories -- Henrik Andersson 2012-01-09 @@ -153,7 +172,7 @@ rdesktop (1.5.0) * SeamlessRDP - seamless windows support * Keymap fixes - * Fix connection issues with Windows XP RTM + * Fix connection issues with Microsoft Windows XP RTM * Keyboard handling improvements and fixes * SGI/Irix sound-driver fixes * Support for clipboard INCR protocol @@ -165,7 +184,7 @@ * Large file support * The default color depth is now the depth of the root window * Basic support for Windows Vista Beta 2 - * Fix high cpu-usage in OSS-driver + * Fix high CPU-usage in OSS-driver -- Peter Astrand Wed, 13 Sep 2006 15:11:39 +0200 (CEST) @@ -202,7 +221,7 @@ rdesktop (1.3.1) * Crypto fixes for RDP5 * Keyboard and keymap fixes - * some endianess fixes for high color + * some endianness fixes for high color * portability enhancements -- Matthew Chapman Tue, 21 Jan 2004 20:34 @@ -210,7 +229,7 @@ rdesktop (1.3.0) * RDP5 - * 15, 16 and 24 bit color depths + * 15, 16 and 24-bit color depths * Basic clipboard redirection * Sound * IPv6 diff -Nru rdesktop-1.8.6/doc/ctrl.txt rdesktop-1.9.0/doc/ctrl.txt --- rdesktop-1.8.6/doc/ctrl.txt 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/doc/ctrl.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,61 +0,0 @@ -TODO ----- - -Overview -======== - -The protocol is a UTF-8 line based bidirectional protocol were a slave sends -a method with optional argument to the master and a result of operation is -returned to the slave in a synchronous send recv operation. - - -A method call from Slave to the Master have the following syntax: - - METHOD [ARG1[ ARG2 [...]]] - -Argument string sent for a method call should be escaped as descibed below under -String escaping section. - - -A result from Master to the Slave have the following syntax: - - "OK" || "ERROR" - -Result CODE is specific to the method implementation except for 0xffffffff which -is internal to the protocol and means that method does not exist. - - -One line may not exceed 1024 bytes, including newline. - - -String escaping -=============== -Percentage sign has been choosen as escaping character. - -The rules for escaping are: - - Characters < 32 and % are escaped to %xx where xx is the byte value of the - escaped character. - - -Implemented methods -======================= - -seamless.spawn --------------- - -Spawns a new windows command in the current seamless channel of the master. - -Syntax: - seamless.spawn - -Spawns a seamless process in the current seamless channel of the master with COMMANDLINE. - -Errorcodes: - - 0x1 Master does not have a seamless rdp channel established. - - - - - diff -Nru rdesktop-1.8.6/doc/ipv6.txt rdesktop-1.9.0/doc/ipv6.txt --- rdesktop-1.8.6/doc/ipv6.txt 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/doc/ipv6.txt 2019-06-13 12:10:15.000000000 +0000 @@ -5,9 +5,9 @@ Attached is a patch to tcp.c to enable IPv6 support. Build with 'IPv6' defined to enable it. It's so far only been tested on - Linux 2.4.21 connecting to Windows XP SP1. + Linux 2.4.21 connecting to Microsoft Windows XP SP1. - Since terminal services doesn't seem to bind to the ipv6 interface + Since terminal services doesn't seem to bind to the IPv6 interface on XP I had to run 'netsh interface portproxy add v6tov4 listenport=3389 connectport=3389' from the windows command prompt to get it to work. @@ -20,10 +20,10 @@ rdesktop 2001:1:2:3::4 - without it getting confused with an ipv4:port specification. I've + without it getting confused with an IPv4:port specification. I've also followed the square bracket convention used by browsers (http://www.ietf.org/rfc/rfc2732.txt) so if you want to specify a - non-standard port with an ipv6 address you can use the format: + non-standard port with an IPv6 address you can use the format: rdesktop [2001:1:2:3::4]:3390 diff -Nru rdesktop-1.8.6/doc/keymapping.txt rdesktop-1.9.0/doc/keymapping.txt --- rdesktop-1.8.6/doc/keymapping.txt 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/doc/keymapping.txt 2019-06-13 12:10:15.000000000 +0000 @@ -2,7 +2,7 @@ ================ This release of rdesktop uses a new, portable keyboard mapping implementation. It should hopefully work on all X11 systems. This new -implementation only looks at X11 keysyms: Not on (nonportable) +implementation only looks at X11 keysyms: Not on (non-portable) keycodes or modifier status. This means that rdesktop will obey your local keyboard configuration. For example, if you have swapped CapsLock and Control, rdesktop will use this mapping. @@ -224,7 +224,7 @@ xmodmap -e "keycode 49 = egrave" -4. Test a char generated with AltGr, such as @ on a swedish keyboard. +4. Test a char generated with AltGr, such as @ on a Swedish keyboard. 5. Test Ctrl-Alt-Delete. @@ -244,7 +244,7 @@ KEYMAP_PATH, $CWD/keymaps, and from an absolute path. 11. Press Shift, then press a key modified by shift, the release - shift, then release the other key. Do this in a speedy fasion. + shift, then release the other key. Do this in a speedy fashion. Make sure the shift state is not stuck down. 12. Test all numpad keys, when not using the -N option. Binary files /tmp/tmpZWfgXB/O87Q9cu2WM/rdesktop-1.8.6/doc/keynums.png and /tmp/tmpZWfgXB/E40k3bOtjZ/rdesktop-1.9.0/doc/keynums.png differ diff -Nru rdesktop-1.8.6/doc/licensing.txt rdesktop-1.9.0/doc/licensing.txt --- rdesktop-1.8.6/doc/licensing.txt 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/doc/licensing.txt 2019-06-13 12:10:15.000000000 +0000 @@ -2,7 +2,7 @@ To be able to connect to Microsoft Windows 2000 Terminal Services (and probably later versions), you'll need to deal with licensing. This is complicated. This file is supposed to contain some information about -how rdesktop works with Microsofts license systems. +how rdesktop works with Microsoft's license systems. There's a lot of information on the MS web site, for example, http://support.microsoft.com/default.aspx?scid=kb;EN-US;287687. @@ -19,7 +19,7 @@ > to A was reached today, and no more connections could be made until we > changed the client name (by using -n). > -> We also have another similiar systems, with Linux machine C and W2K server +> We also have another similar systems, with Linux machine C and W2K server > D. This server has 200 licenses installed of the type "Select". On this > server, the issued licenses seems to be permanent: The expire date is set > to "-", and we have no problem with this system. diff -Nru rdesktop-1.8.6/doc/lspci-channel.txt rdesktop-1.9.0/doc/lspci-channel.txt --- rdesktop-1.8.6/doc/lspci-channel.txt 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/doc/lspci-channel.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,39 +0,0 @@ - -Protocol overview -================= - -The lspci virtual channel makes it possible for the remote RDP server -to enumerate the local PCI devices. The protocol on this channel is -text based and line oriented: One single line per request or -response. UNIX-style LF line breaks are used. The maximum line length -is 1023, newline included. - -rdesktop acts as a server, with only one request: - - LSPCI - -The response is several lines with this syntax: - -,,,,,, - -After the last line, a line with a single dot is sent. - -Example: - -0300,102b,0525,102b,0338,04,00 -0401,8086,24d5,1028,0174,02,8f -. - - -Usage -===== - -To enable to lspci virtual channel, run rdesktop with "-r lspci". - - -References -========== - -http://www.microsoft.com/msj/1099/terminal/terminal.aspx -http://msdn.microsoft.com/library/default.asp?url=/library/en-us/termserv/termserv/terminal_services_virtual_channels.asp - diff -Nru rdesktop-1.8.6/doc/makerelease.txt rdesktop-1.9.0/doc/makerelease.txt --- rdesktop-1.8.6/doc/makerelease.txt 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/doc/makerelease.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ - -* Update doc/ChangeLog - -* Update version in configure.ac and rdesktop.spec - -* Create a tarball: "make dist". Verify that it contains only relevant files - -* Test build the tarball on a few systems. Test "rpmbuild -ta" as well - -* Tag: - svn copy https://rdesktop.svn.sourceforge.net/svnroot/rdesktop/rdesktop/trunk \ - https://rdesktop.svn.sourceforge.net/svnroot/rdesktop/rdesktop/tags/rdesktop-x.y.z - -* Do a new SF file release - -* Update web page - -* Send announcement to the mailing list - -* Update Freshmeat entry - -* Append "post" to VERSION diff -Nru rdesktop-1.8.6/doc/patches.txt rdesktop-1.9.0/doc/patches.txt --- rdesktop-1.8.6/doc/patches.txt 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/doc/patches.txt 2019-06-13 12:10:15.000000000 +0000 @@ -102,7 +102,7 @@ URL: http://bibl4.oru.se/projects/rdesktop/patch19/patches/frank_fasttext.patch.txt Description: -Some kind of performence improvements. +Some kind of performance improvements. Status: From what I can tell, this patch is no longer necessary. @@ -115,7 +115,7 @@ rdesktop uses gethostname to figure out the hostname, but gethostname under linux returns an error when the hostname is longer than the buffer. This hack gives gethostname a 64 char buffer and then strips -the first 16 chars or upto the first '.' and puts the result in +the first 16 chars or up to the first '.' and puts the result in hostname[16]. Status: @@ -134,7 +134,7 @@ URL: http://bibl4.oru.se/projects/rdesktop/patch19/patches/mmihalik_19-7-3-keyfix-4.patch Description: -Some kind of new alternative keyboard mapping imlementation. +Some kind of new alternative keyboard mapping implementation. Status: Not needed anymore, with the new keyboard mapping implementation. @@ -286,7 +286,7 @@ URL: http://bibl4.oru.se/projects/rdesktop/patch19/patches/svenni_dis_wmkeybnds.patch Description: -Commandline flag to disable keyboard grabbing. +Command line flag to disable keyboard grabbing. Status: Applied. @@ -311,7 +311,7 @@ http://bibl4.oru.se/projects/rdesktop/patch19/patches/vincent_19-7-2.secure.patch Description: Fixes a problem during the connection to a French NT4 TSE (a French -NT4 TSE doesn't use encryptation). +NT4 TSE doesn't use encryption). Status: Applied. diff -Nru rdesktop-1.8.6/doc/rdesktop.1 rdesktop-1.9.0/doc/rdesktop.1 --- rdesktop-1.8.6/doc/rdesktop.1 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/doc/rdesktop.1 2019-09-11 08:25:57.000000000 +0000 @@ -1,4 +1,4 @@ -.TH rdesktop 1 "November 2005" +.TH rdesktop 1 "2017-10-28" .SH NAME .I rdesktop \- Remote Desktop Protocol client @@ -7,9 +7,9 @@ .br .SH DESCRIPTION .I rdesktop -is a client for Remote Desktop Protocol (RDP), used in a number of Microsoft -products including Windows NT Terminal Server, Windows 2000 Server, Windows XP -and Windows 2003 Server. +is a client for Remote Desktop Protocol (RDP), used in a number of Microsoft products. +It is known to work with Microsoft Windows server versions ranging from NT 4 terminal +server to Windows Server 2012 R2. .SH OPTIONS .TP @@ -21,7 +21,7 @@ .TP .BR "-s " Startup shell for the user - starts a specific application instead of Explore. -If SeamlessRDP is enabled this is the application which i started in seamless mode. +If SeamlessRDP is enabled this is the application which is started in seamless mode. .TP .BR "-c " The initial working directory for the user. Often used in combination with -s @@ -63,15 +63,24 @@ so its use is discouraged. .TP .BR "-g " -Desktop geometry (WxH). If geometry is the special word "workarea", the geometry -will be fetched from the extended window manager hints property _NET_WORKAREA, from -the root window. The geometry can also be specified as a percentage of the whole -screen, e.g. "-g 80%". +Desktop geometry (WxH[@DPI][+X[+Y]]). If geometry is the special word +"workarea", the geometry will be fetched from the extended window +manager hints property _NET_WORKAREA, from the root window. The +geometry can also be specified as a percentage of the whole screen, +e.g. "-g 80%", "-g 80%x70%". If the specified geometry depends on the screen size, and the screen size is changed, rdesktop will automatically reconnect using the new screen size. This requires that rdesktop has been compiled with RandR support. + +The optional DPI parameter should be specified if the screen rdesktop +is being displayed on is too far from 96 DPI for unscaled Windows to +be readable. Windows currently accepts values from 96 to 480. + +Offset placement of window is optional. Starting point is upper left corner of screen. +Window manager might push into visible area, if a panel would be covered. +The schema is "-g ++, f.e. "-g 30%+200+600". .TP .BR "-i" Use password as smartcard pin. If a valid user certificate is matched in smart card @@ -102,11 +111,16 @@ Example: rdesktop -A 'c:\\seamlessrdp\\seamlessrdpshell.exe' -s 'notepad' mywts.domain.com -Any subsequential call to the above commandline example will make use of the seamless +Any subsequential call to the above command line example will make use of the seamless connection sharing feature which spawns another notepad in the current connection to the specified server and then exit. .TP +.BR "-V " +Set the Transport Level Security (also known as SSL) Version used. +Should be one of the following values: 1.0, 1.1, 1.2. By default all +versions are supported. +.TP .BR "-B" Use the BackingStore of the Xserver instead of the integrated one in rdesktop. @@ -123,6 +137,11 @@ Do not send mouse motion events. This saves bandwidth, although some Windows applications may rely on receiving mouse motion. .TP +.BR "-M" +Use local X cursor inherited from window manager instead of server cursor. This +is mostly useful with -m, but is also useful if the server is sending bogus +mouse cursors. +.TP .BR "-C" Use private colourmap. This will improve colour accuracy on an 8-bit display, but rdesktop will appear in false colour when not focused. @@ -146,7 +165,7 @@ Sets the window title. The title must be specified using an UTF-8 string. .TP .BR "-N" -Enable numlock syncronization between the Xserver and the remote RDP +Enable numlock synchronization between the Xserver and the remote RDP session. This is useful with applications that looks at the numlock state, but might cause problems with some Xservers like Xvnc. .TP @@ -170,7 +189,7 @@ to modem (56 Kbps)). Setting experience to b[roadband] enables menu animations and full window dragging. Setting experience to l[an] will also enable the desktop wallpaper. Setting experience to m[odem] -disables all (including themes). Experience can also be a hexidecimal +disables all (including themes). Experience can also be a hexadecimal number containing the flags. .TP .BR "-P" @@ -225,12 +244,16 @@ .TP .BR "-r scard[:=[;][,...]]" Enables redirection of one or more smart-cards. You can provide -static name binding between linux and windows. To do this you +static name binding between GNU/Linux and Windows. To do this you can use optional parameters as described: - device name in -Linux/Unix enviroment, - device name shown in Windows enviroment +GNU/Linux and UNIX environment, - device name shown in Windows environment - optional device vendor name. For list of examples run rdesktop without parameters. .TP +.BR "-r clipboard:[off|PRIMARYCLIPBOARD|CLIPBOARD]" +Enable clipboard redirection. 'PRIMARYCLIPBOARD' looks at both PRIMARY and +CLIPBOARD when sending data to server. 'CLIPBOARD' looks at only 'CLIPBOARD'. +.TP .BR "-0" Attach to the console of the server (requires Windows Server 2003 or newer). @@ -240,6 +263,9 @@ .TP .BR "-5" Use RDP version 5 (default). +.TP +.BR "-v" +Enable verbose output .PP .SH "CredSSP Smartcard options" @@ -247,11 +273,11 @@ .BR "--sc-csp-name " Specify the CSP (Crypto Service Provider) to use on the windows side for the smartcard authentication. CSP is the driver for your smartcard and it seems like this is required -to be specified for CredSSP authentication. For swedish NetID the following CSP name is +to be specified for CredSSP authentication. For Swedish NetID the following CSP name is used; "Net iD - CSP". .TP .BR "--sc-container-name " -Specify the container name, usally this is the username for default container and it seems +Specify the container name, usually this is the username for default container and it seems like this is required to be specified for CredSSP authentication. .TP .BR "--sc-reader-name " @@ -267,13 +293,13 @@ .IP "\fB0\fP" RDP session terminated normally .IP "\fB1\fP" -Server initiated disconnect (also returned for logoff by XP joined to a domain) +Administrator initiated disconnect (also returned for logoff by Windows XP joined to a domain) .IP "\fB2\fP" -Server initiated logoff +Administrator initiated logout .IP "\fB3\fP" -Server idle timeout reached +Server idle session time limit reached .IP "\fB4\fP" -Server logon timeout reached +Server active session time limit reached .IP "\fB5\fP" The session was replaced .IP "\fB6\fP" @@ -281,7 +307,7 @@ .IP "\fB7\fP" The server denied the connection .IP "\fB8\fP" -The server denied the connection for security reason +The server denied the connection for security reasons .IP "\fB9\fP" The user cannot connect to the server due to insufficient access privileges @@ -289,9 +315,9 @@ The server does not accept saved user credentials and requires that the user enter their credentials for each connection .IP "\fB11\fP" -Disconnect initiated by administration tool -.IP "\fB12\fP" Disconnect initiated by user +.IP "\fB12\fP" +Logout initiated by user .IP "\fB16\fP" Internal licensing error .IP "\fB17\fP" @@ -299,25 +325,55 @@ .IP "\fB18\fP" No valid license available .IP "\fB19\fP" -Invalid licensing message +Invalid licensing message from client .IP "\fB20\fP" -Hardware id doesn't match software license +The client license has been modified and does no longer match the hardware ID .IP "\fB21\fP" -Client license error +The client license is in an invalid format .IP "\fB22\fP" Network error during licensing protocol .IP "\fB23\fP" Licensing protocol was not completed .IP "\fB24\fP" -Incorrect client license enryption +Incorrect client license encryption .IP "\fB25\fP" -Can't upgrade license +Can't upgrade or renew license .IP "\fB26\fP" The server is not licensed to accept remote connections +.IP "\fB30\fP" +The target endpoint chosen by the broker could not be found +.IP "\fB32\fP" +The target endpoint is disconnecting from the broker +.IP "\fB34\fP" +Error occurred while being redirected by broker +.IP "\fB35\fP" +Error while the endpoint VM was being awakened by the broker +.IP "\fB36\fP" +Error while the endpoint VM was being started by the broker +.IP "\fB37\fP" +The IP address of the endpoint VM could not be determined by the broker +.IP "\fB38\fP" +No available endpoints in the connection broker pool +.IP "\fB39\fP" +Connection processing cancelled by the broker +.IP "\fB40\fP" +The connection settings could not be validated by the broker +.IP "\fB41\fP" +Timeout while the endpoint VM was being started by the broker +.IP "\fB42\fP" +Session monitoring error while the endpoint VM was being started by the broker +.IP "\fB50\fP" +The server can only host Remote Applications +.IP "\fB51\fP" +Update of session keys failed +.IP "\fB52\fP" +Decryption or session key creation failed +.IP "\fB53\fP" +Encryption failed .IP "\fB62\fP" The local client window was closed .IP "\fB63\fP" -Some other, unknown error occured +Some other, unknown error occurred .IP "\fB64\fP" Command line usage error .IP "\fB69\fP" diff -Nru rdesktop-1.8.6/doc/rdpsnd-rec.txt rdesktop-1.9.0/doc/rdpsnd-rec.txt --- rdesktop-1.8.6/doc/rdpsnd-rec.txt 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/doc/rdpsnd-rec.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,181 +0,0 @@ -Overview -======== - -This is a rdesktop specific extension to the RDPSND protocol to -support recording. - -The basic protocol is the same as RDPSND (described in rdpsnd.txt), -but with a bunch of new opcodes. - -A client indicates to the server that it can support recording by -setting bit 24 (0x00800000) in "Flags" in RDPSND_NEGOTIATE. - -New opcodes - - 0x27 RDPSND_REC_NEGOTIATE - 0x28 RDPSND_REC_START - 0x29 RDPSND_REC_STOP - 0x2A RDPSND_REC_DATA - 0x2B RDPSND_REC_SET_VOLUME - -Opcodes -======= - -The following is a list of the new opcodes and their payload. - -RDPSND_REC_NEGOTIATE --------------------- - -Sent immediatly after RDPSND_NEGOTIATE when the client indicates that -it supports recording. Allows the server to determine the -capabilities of the client. - -The client should reply with an identical packet, with the relevant -fields filled in, and a filtered list of formats (based on what the -client supports). - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Flags | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Left channel | Right channel | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Format count | Version | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| ... | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Format tag | Channels | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Frames per sec. | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Bytes per sec. | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Block align | Bits per sample | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Extra size | Extra data ... | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| ... | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - -Flags - - Flags for capabilities. Currently unused. - -Left channel - - Initial volume for left channel. Reserved when sent from server. - -Right channel - - Initial volume for right channel. Reserved when sent from server. - -Format count - - Number of format structures following the header. - -Version - - Version of the RDPSND record protocol. Current version is 1. - -Format tag - - Audio format type as registered at Microsoft. - -Channels - - Number of channels per frame. - -Frames per sec. - - Frames per second in Hz. - -Bytes per sec. - - Number of bytes per second. Should be the product of - "Frames per sec." and "Block align". - -Block align - - The size of each frame. Note that not all bytes may contain - useful data. - -Bits per sample - - Number of bits per sample. Commonly 8 or 16. - -Extra size - - Number of bytes of extra information following this format - description. - -Extra data - - Optional extra format data. Contents specific to each format - type. - -RDPSND_REC_START ----------------- - -Sent from the server to tell the client to start recording. - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Format index | | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - -Format index - - Waveform data format in the form of an index to the previously - negotiated format list. - -RDPSND_REC_STOP ---------------- - -Tells the client to stop sending record data. Must be sent before a -new RDPSND_REC_START is sent. - -No payload and no response. - -RDPSND_REC_DATA ---------------- - -Chunk of recorded data. The client is free to choose how much data -should be queued up before a packet is sent. The payload must not -exceed 32768 bytes though. - -No response. - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Waveform data | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| ... | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - -Waveform data - - Binary waveform data in the format specified by the format index. - Size defined by the packet boundary. - -RDPSND_REC_SET_VOLUME ---------------------- - -Request from the server to the client to change the input volume. -No response. - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Left channel | Right channel | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - -Left channel - - Volume of left channel in the range [0, 65535]. - -Right channel - - Volume of right channel in the range [0, 65535]. diff -Nru rdesktop-1.8.6/doc/rdpsnd.txt rdesktop-1.9.0/doc/rdpsnd.txt --- rdesktop-1.8.6/doc/rdpsnd.txt 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/doc/rdpsnd.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,298 +0,0 @@ -Overview -======== - -The RDPSND protocol is a binary, packet based protocol that maps -Microsoft's legacy wave API to a RDP channel. - -All values are in little endian ordering. - -Responses are sent with the same opcode as the request, and usually -also with the same packet structure. - -The basic structure of a packet is: - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Opcode | Unknown | Payload size | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| ... | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - -Opcode - - Command or response type. Known values: - - 0x01 RDPSND_CLOSE - 0x02 RDPSND_WRITE - 0x03 RDPSND_SET_VOLUME - 0x04 Unknown (4 bytes payload, no response) - 0x05 RDPSND_COMPLETION - 0x06 RDPSND_PING - 0x07 RDPSND_NEGOTIATE - -Unknown - - Usage not known. Not valid when message comes from server - -Payload size - - Number of bytes following the header. - -Opcodes -======= - -Following is a list of all known opcodes and the contents in their -payloads. - -RDPSND_CLOSE ------------- - -Tells the client that all applications on the server have released -control of the sound system, allowing the client to free any local -resources. - -No payload and no response. - -RDPSND_WRITE ------------- - -Request to play a chunk of data. The client is expected to queue up -the data and send a RDPSND_COMPLETION when playback has finished. - -No response. - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Tick | Format index | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Packet index | Pad | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Waveform data | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| ... | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - -Tick - - Low 16 bits of clock tick count when packet was scheduled for - playback. - -Format index - - Waveform data format in the form of an index to the previously - negotiated format list. - -Packet index - - Index number of this packet. - -Pad - - Unused padding. - -Waveform data - - Binary waveform data in the format specified by the format index. - Size defined by the packet boundary. - - Because of a strange design in Microsoft's server, the length of - the packet will be 4 bytes short and bytes 12 to 15 (4 bytes) of - the payload should be removed. - -RDPSND_SET_VOLUME ------------------ - -Request from the server to the client to change the output volume. -No response. - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Left channel | Right channel | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - -Left channel - - Volume of left channel in the range [0, 65535]. - -Right channel - - Volume of right channel in the range [0, 65535]. - -RDPSND_COMPLETION ------------------ - -Sent by the client to the server when a packet, queued by -RDPSND_WRITE, has finished playing. - -No response is sent by the server. - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Tick | Packet index | Reserved | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - -Tick - - Clock tick count when packet finished playing on device. - -Packet index - - Index number of packet played. - -Reserved - - Reserved. Always 0. - -RDPSND_PING ------------ - -Sent by the server to the client to determine transport latency. -The client must respond by echoing the first four bytes of this -packet. - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Tick | Reserved | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Garbage | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| ... | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - -Tick - - Clock tick count when sent from server. - -Reserved - - Reserved. Always 0. - -Garbage - - 1016 optional bytes of random data. Purpose unknown. - Only sent from server. - -RDPSND_NEGOTIATE ----------------- - -Initial packet sent by server when the client [re]connects. Allows -the server to determine the capabilities of the client. - -The client should reply with an identical packet, with the relevant -fields filled in, and a filtered list of formats (based on what the -client supports). - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Flags | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Left channel | Right channel | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Pitch | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| UDP port | Format count | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Initial idx | Version | Padding | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| ... | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Format tag | Channels | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Frames per sec. | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Bytes per sec. | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Block align | Bits per sample | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Extra size | Extra data ... | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| ... | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - -Flags - - Flags for client capabilities. Data not valid when from server. - - 0000 0001 Do UDP song and dance (details unknown). Must be - set for sound to work. - 0000 0002 Volume control support. Indicates that volume - fields are valid and that the client understands - RDPSND_SET_VOLUME. - 0000 0004 Pitch field is valid. - -Left channel - - Initial volume for left channel. Data not valid when from server. - -Right channel - - Initial volume for right channel. Data not valid when from server. - -Pitch - - Initial pitch of the sound device. Data not valid when from server. - -UDP port - - Port used for UDP transfers. Sent in network (big endian) order. - Data not valid when from server. - -Format count - - Number of format structures following the header. - -Initial index - - Initial packet index. The first RDPSND_WRITE will have a packet - index one larger than this value. Data not valid when from client. - -Version - - Software version. Server (XP & 2K3) sets this to 5. Client (XP) - also sets this to 5. - -Padding - - Unused. - -Format tag - - Audio format type as registered at Microsoft. - -Channels - - Number of channels per frame. - -Frames per sec. - - Frames per second in Hz. - -Bytes per sec. - - Number of bytes per second. Should be the product of - "Frames per sec." and "Block align". - -Block align - - The size of each frame. Note that not all bytes may contain - useful data. - -Bits per sample - - Number of bits per sample. Commonly 8 or 16. - -Extra size - - Number of bytes of extra information following this format - description. - -Extra data - - Optional extra format data. Contents specific to each format - type. diff -Nru rdesktop-1.8.6/doc/seamlessrdp-channel.txt rdesktop-1.9.0/doc/seamlessrdp-channel.txt --- rdesktop-1.8.6/doc/seamlessrdp-channel.txt 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/doc/seamlessrdp-channel.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,468 +0,0 @@ -TODO ----- - -* Commands for changing z order and focus. - -* Think about protocol version management - -* Try to assure that messages aren't repeated or are sent for hidden windows. - -Overview -======== - -The protocol is a line based protocol following this simple syntax: - - OPERATION,SERIAL[,ARG1[,ARG2,[...]]] - -Each operation will have an increasing serial number. The initial value is -implementation defined. - -The goal is to have a generic protocol that can be used for other display -systems (e.g. VNC) as well. - -One line may not exceed 1024 bytes, including newline. - -The protocol has no concept of hidden or unmapped windows. A window does not -exist unless it is visible. Note that a minimized window is an exception to -this rule. - -The protocol has no way of indicating failure, meaning that all commands are -expected to succeed. If a command fails, the receiving end must send a -corresponding command back, indicating the actual state. - -Data types -========== -Window ID are written in hex, like 0x4321. - -Window positions can be negative. This happens when a window is moved -outside the desktop. - -All integers fit inside 32 bits. - -Strings are sent in UTF-8 and do not contain any characters less than 0x20 or -the character , (comma). - -Server to Client Operations -=========================== - -CREATE ------- - -Allocate structures for a new window. - -Syntax: - CREATE,,,,, - -Indicates that a window has appeared on the server. If PARENT is non-zero then -the new window is a child of that window (it's transient for it). The special -value 0xFFFFFFFF for PARENT means that the window is a popup window without a -parent. It's commonly used for splash screens, tool tips and context menus. - -The group id identifies a set of windows that belong together. It is currently -only used for modal windows and DESTROYGRP. - -Flags: - 0x0001 : Create a window that's modal with regard to the other windows - in the same group. - -Note that very little information is included in this message. Things like -title and state will come in subsequent messages. This message should only -be used to allocate data structures for the new window. - -DESTROY -------- - -Remove a window. - -Syntax: - DESTROY,,, - -Remove the window and deallocate all associated structures. - -DESTROYGRP ----------- - -Destroy an entire group of windows. - -Syntax: - DESTROYGRP,,, - -Every window that belongs to the group GRPID should be destroyed as if they -each got a DESTROY message. - -POSITION --------- - -Move and/or resize a window. - -Syntax: - POSITION,,,,,,, - -If the window isn't visible yet (because a -STATE hasn't been set or because it's minimized), you must store the position -and size. A new POSITION is not guaranteed to be sent when the window changes -state. - -TITLE ------ - -Sets a window title. - -Syntax: - TITLE,,,,<FLAGS> - -The text is guaranteed to be stripped of control characters (< 0x20). - -Note that this has the same requirement as POSITION, that the title needs to -be stored for newly created windows until a STATE is sent. It is however not -guaranteed that a TITLE will be sent before the first STATE. - - -ZCHANGE -------- - -The window moved in z order. - -Syntax: - ZCHANGE,<SERIAL>,<ID>,<BEHIND>,<FLAGS> - -The window with the id ID is behind the window with the id BEHIND. If -BEHIND is 0, then this window should be brought to the front. The ID -window is the window to be moved, while the BEHIND window is only used -as a reference. - - -STATE ------ - -Changes the window's state and/or title. - -Syntax: - STATE,<SERIAL>,<ID>,<STATE>,<FLAGS> - -State can have one of three values: - 0 : "Normal" window. - 1 : Minimized. - 2 : Maximized. - -The initial STATE for a window will always be preceeded by one CREATE and one -POSITION. Optionally, a TITLE may also be sent before the first STATE. - -DEBUG ------ - -Debug output from the server component. - -Syntax: - DEBUG,<SERIAL>,<STRING> - -Used for debugging. - -SYNCBEGIN ---------- - -Indicates that a synchronisation has begun. - -Syntax: - SYNCBEGIN,<SERIAL>,<FLAGS> - -Sent when the server starts a synchronisation. The client should flush all -information at this point. - -SYNCEND -------- - -Indicates that a synchronisation is complete. - -Syntac: - SYNCEND,<SERIAL>,<FLAGS> - -Sent when the last message that is part of the synchronisation has been sent. -This may be followed by duplicate messages and/or messages referring invalid -windows that were queued up during the synchronisation. - -HELLO ------ - -Initial message sent by server. - -Syntax: - HELLO,<SERIAL>,<FLAGS> - -The server starts each connection by sending this message. Normally the client -will react by sending a SYNC back to the server. - -Flags: - 0x0001 : This is a reconnect to an existing session. - 0x0002 : The desktop is currently hidden (see HIDE). - -ACK ---- - -Acknowledgement of a request to manipulate a window. - -Syntax: - ACK,<SERIAL>,<ACKSERIAL> - -Whenever one of the commands POSITION, ZCHANGE, STATE or FOCUS is executed on -the server, the server will send an ACK back to the client. The purpose of this -is to inform the client of when the operation was actually performed, allowing -high latencies in the channel. - -HIDE ----- - -The desktop has become hidden on the server. - -Syntax: - HIDE,<SERIAL>,<FLAGS> - -This message is sent when the desktop on the server is obscured by something -that cannot be tracked. The client should remove all windows and display the -entire desktop, allowing the user to handle whatever is blocking the view. - -Note that updates to windows will still be sent as the windows still exist on -the server, they are merely not visible. - -UNHIDE ------- - -The desktop has been restored on the server. - -Syntax: - UNHIDE,<SERIAL>,<FLAGS> - -This message is sent some time after a HIDE, indicating that the windowed view -has been restored. If the client has dropped all information about windows then -it can send a SYNC to re-enumerate them. - -SETICON -------- - -Sets an icon for a window. - -Syntax: - SETICON,<SERIAL>,<ID>,<CHUNK>,<FORMAT>,<WIDTH>,<HEIGHT>,<DATA> - -This message is sent when a window is initially created and at any time when -the application modifies its icon. - -A window can have multiple icons, but only one of a given format and size. A -SETICON received for an already existing format and size is expected to over- -write that icon. - -Since icons can potentially be very large, it can easily overflow the line -limitation in the protocol. To handle this, multiple SETICON will be issued -with an ever increasing chunk number. - -The initial chunk is 0 (zero) and all chunks must be sent in order. Multiple -SETICON sets for the same window may not interleave. SETICON sets for -different windows may interleave though. - -Formats: - RGBA : Four bytes of data per pixel, representing red, green, blue and - alpha, in that order. - -Data is the raw icon data written in hex (e.g. 3fab32...). Chunks must be -divided on a whole byte boundary. Case is not specified. - -DELICON -------- - -Removes an icon for a window. - -Syntax: - DELICON,<SERIAL>,<ID>,<FORMAT>,<WIDTH>,<HEIGHT> - -Removes the icon of a window matching the given format and size, previously -set with SETICON. - -This command may not be interleaved with a SETICON set. - -Client to Server Operations -=========================== - -SYNC ----- - -Request a synchronisation of window information. - -Syntax: - SYNC,<SERIAL>,<FLAGS> - -For each window, the server will send CREATE, POSITION and STATE, in that -order, just as if the window was created. Note that a TITLE may also, -optionally, be sent before the STATE. - -PERSISTENT ----------- - -Change persistent mode for the session. - -Syntax: - PERSISTENT,<SERIAL>,<ENABLE> - -A seamless session always starts in persistent mode. This means that -the session will not terminate if all applications is closed. -Upon re-connection to a session, the session will reset to persistent -mode and client needs to change this if non persistent mode is wanted. -If a persistent session not have any application running and is in -disconnected state, it will terminate after a timeout is reached that -matches the lifetime of the re-connection cookie. - -POSITION --------- - -Identical to the command sent from server to client. - -TITLE ------ - -Identical to the command sent from server to client. - -ZCHANGE -------- - -Identical to the command sent from server to client. - -STATE ------ - -Identical to the command sent from server to client. - -FOCUS ------ - -Sets which window has input focus. - -Syntax: - FOCUS,<SERIAL>,<ID>,<FLAGS> - -Changes which window that will recieve the keyboard events. Note that this -might cause the window to change z order. - -DESTROY -------- - -Identical to the command sent from server to client. - -SPAWN -------- - -Spawn a new application. - -Syntax: - SPAWN,<SERIAL>,<COMMANDLINE> - -Spawns a new application specified by commandline. - - -Test Cases -========== - -A list of test cases is found below. These should be verified before -commit, ideally with different window managers (KWin, Metacity, -Blackbox, IceWM etc). You can also test without a window manager. - -1 Start Wordpad. Verify taskbar icon. - -2 Resize Wordpad main window. - -3 Open "Open Dialog". Resize, bigger than main window. Verify no - additional task bar icons. Verify that the Open dialog is focused. - -4 Open File Format box dropdown. Verify that it correctly appears - outside main window. Verify no additional task bar icons. - -5 Abort Open. Select About Wordpad. Verify no additional task bar - icons. Verify that the About dialog is focused. - -6 Minimize and restore Wordpad using the WM. Verify that both the - Wordpad and About window is minimized and restored, and that the - About window ends up in front of Wordpad. This test is known to fail - with some WMs. Close the About dialog. - -7 Open Wordpad Help. Verify task bar icon. - -8 Switch between Help and Wordpad window using a X11 taskbar. - -9 In Wordpad, right click at the bottom of the document, and verify - that the menu correctly appears outside the main window. Verify no - additional task bar icons. - -10 Click on the New icon. Select Text Document. Verify that the taskbar - icon is updated. - -11 Write something. Try the Find dialog (Ctrl-F). Move it outside the - main window. Verify no task bar icons. - -12 Make Wordpad very small and try to use the menus. - - -13 Start Internet Explorer. - -14 Minimize IE using the IE button. Restore. - -15 Minimize IE using the taskbar. Restore. - -16 Maximize IE using the IE button. Restore. - -17 Maximize IE using the taskbar. Restore. - -18 Open an additional IE window and verify you can switch between them. - - -19 Try the menus in Microsoft Office XP, which uses shaded menus. - - -20 Test transient windows: Run a program (ie Excel) seamlessly and open - a modal dialog (ie Open). Move the dialog so it partially overlaps - its parent window. Cover both windows with a third (ie a maximized - xterm). Click on Excel's taskbar entry to bring it to the front. - - -21 Test topmost windows: Run Task Manager seamlessly - (...\seamlessrdpshell.exe taskmgr). From Task Manager's File menu, - select 'New Task (Run)' and run Notepad. Move Notepad so it - partially overlaps Task Manager. Cover both windows with a native - window (ie a maximized xterm). Click on Notepad's taskbar entry to - bring it to the front. - - -22 Test X11 window close: Start Notepad and open the Help - Browser. Close the Help Browser window on the X11 side using your - window manager. Verify that rdesktop still runs and that the Notepad - application window still exists. - - -23 Test window restacking: Run Mozilla Seamonkey and open two separate - windows. From the first one, select the other one from the windows - menu. Verify that the other window is brought to the front. Test - this using both the mouse and the keyboard. - - -24 Test restacking of a bottom window. For this test, you'll need to - the tool "notepadbehindwordpad.exe". Run Task Manager - seamlessly. Start Notepad and Wordpad from it. Manually stack the - windows as (from top to bottom) Task Manager - Notepad - xterm - - Wordpad. Make sure the windows partially overlaps. From Task - Manager, execute notepadbehindwordpad.exe. This - test is expected to fail when rdesktop emits the warning about - broken WM at startup. - - -25 Test restacking of a middle window. For this test, you'll need to - the tool "notepadbehindwordpad.exe". Run Task Manager - seamlessly. Start Paint, Notepad, and Wordpad from it. Manually - stack the windows as (from top to bottom) Task Manager - Notepad - - xterm - Wordpad - Paint. Make sure the windows partially - overlaps. From Task Manager, execute notepadbehindwordpad.exe. This - test is expected to fail when rdesktop emits the warning about - broken WM at startup. - - -26 If running on a 64 bit Windows version, try a 32 bit application: - Run Task Manager seamlessly (...\seamlessrdpshell.exe - taskmgr). From Task Manager's File menu, select 'New Task (Run)' - and run %windir%\syswow64\notepad.exe. Try various window - operations. diff -Nru rdesktop-1.8.6/doc/TODO rdesktop-1.9.0/doc/TODO --- rdesktop-1.8.6/doc/TODO 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/doc/TODO 2019-06-13 12:10:15.000000000 +0000 @@ -40,7 +40,7 @@ * Use timestamps in audio packets. - * Add resampling to supported samplerates of audio-hardware. + * Add resampling to supported sample rates of audio-hardware. * Lower CPU-usage with an audio thread. @@ -84,7 +84,7 @@ * Support for sending focus information from client to server. - * Implement something similiar to explhook.dll - support for running + * Implement something similar to explhook.dll - support for running explorer.exe in non-shell mode. * Better compatibility with Task Manager. diff -Nru rdesktop-1.8.6/dvc.c rdesktop-1.9.0/dvc.c --- rdesktop-1.8.6/dvc.c 1970-01-01 00:00:00.000000000 +0000 +++ rdesktop-1.9.0/dvc.c 2019-06-13 12:10:15.000000000 +0000 @@ -0,0 +1,469 @@ +/* -*- c-basic-offset: 8 -*- + rdesktop: A Remote Desktop Protocol client. + Dynamic Channel Virtual Channel Extension. + Copyright 2017 Henrik Andersson <hean01@cendio.com> for Cendio AB + Copyright 2017 Karl Mikaelsson <derfian@cendio.se> for Cendio AB + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "rdesktop.h" + +#define MAX_DVC_CHANNELS 20 +#define INVALID_CHANNEL ((uint32)-1) + +#define DYNVC_CREATE_REQ 0x01 +#define DYNVC_DATA_FIRST 0x02 +#define DYNVC_DATA 0x03 +#define DYNVC_CLOSE 0x04 +#define DYNVC_CAPABILITIES 0x05 +#define DYNVC_DATA_FIRST_COMPRESSED 0x06 +#define DYNVC_DATA_COMPRESSED 0x07 +#define DYNVC_SOFT_SYNC_REQUEST 0x08 +#define DYNVC_SOFT_SYNC_RESPONSE 0x09 + +typedef union dvc_hdr_t +{ + uint8 data; + struct + { + uint8 cbid:2; + uint8 sp:2; + uint8 cmd:4; + } hdr; +} dvc_hdr_t; + +typedef struct dvc_channel_t +{ + uint32 hash; + uint32 channel_id; + dvc_channel_process_fn handler; +} dvc_channel_t; + +static VCHANNEL *dvc_channel; +static dvc_channel_t channels[MAX_DVC_CHANNELS]; + +static uint32 dvc_in_channelid(STREAM s, dvc_hdr_t hdr); + +static RD_BOOL +dvc_channels_exists(const char *name) +{ + int i; + uint32 hash; + hash = utils_djb2_hash(name); + for (i = 0; i < MAX_DVC_CHANNELS; i++) + { + if (channels[i].hash == hash) + return True; + } + + return False; +} + +static const dvc_channel_t * +dvc_channels_get_by_id(uint32 id) +{ + int i; + + for (i = 0; i < MAX_DVC_CHANNELS; i++) + { + if (channels[i].channel_id == id) + { + return &channels[i]; + } + } + + return NULL; +} + +static uint32 +dvc_channels_get_id(const char *name) +{ + int i; + uint32 hash; + hash = utils_djb2_hash(name); + + for (i = 0; i < MAX_DVC_CHANNELS; i++) + { + if (channels[i].hash == hash) + { + return channels[i].channel_id; + } + } + + return INVALID_CHANNEL; +} + +static RD_BOOL +dvc_channels_remove_by_id(uint32 channelid) +{ + int i; + + for (i = 0; i < MAX_DVC_CHANNELS; i++) + { + if (channels[i].channel_id == channelid) + { + memset(&channels[i], 0, sizeof(dvc_channel_t)); + return True; + } + } + return False; +} + +static RD_BOOL +dvc_channels_add(const char *name, dvc_channel_process_fn handler, uint32 channel_id) +{ + int i; + uint32 hash; + + if (dvc_channels_exists(name) == True) + { + logger(Core, Warning, "dvc_channels_add(), channel with name '%s' already exists", + name); + return False; + } + + for (i = 0; i < MAX_DVC_CHANNELS; i++) + { + if (channels[i].hash == 0) + { + hash = utils_djb2_hash(name); + channels[i].hash = hash; + channels[i].handler = handler; + channels[i].channel_id = channel_id; + logger(Core, Debug, + "dvc_channels_add(), Added hash=%x, channel_id=%d, name=%s, handler=%p", + hash, channel_id, name, handler); + return True; + } + } + + logger(Core, Warning, + "dvc_channels_add(), Failed to add channel, maximum number of channels are being used"); + return False; +} + +static int +dvc_channels_set_id(const char *name, uint32 channel_id) +{ + int i; + uint32 hash; + + hash = utils_djb2_hash(name); + + for (i = 0; i < MAX_DVC_CHANNELS; i++) + { + if (channels[i].hash == hash) + { + logger(Core, Debug, "dvc_channels_set_id(), name = '%s', channel_id = %d", + name, channel_id); + channels[i].channel_id = channel_id; + return 0; + } + } + + return -1; +} + +RD_BOOL +dvc_channels_is_available(const char *name) +{ + int i; + uint32 hash; + hash = utils_djb2_hash(name); + + for (i = 0; i < MAX_DVC_CHANNELS; i++) + { + if (channels[i].hash == hash) + { + return (channels[i].channel_id != INVALID_CHANNEL); + } + } + + return False; +} + +RD_BOOL +dvc_channels_register(const char *name, dvc_channel_process_fn handler) +{ + return dvc_channels_add(name, handler, INVALID_CHANNEL); +} + + +static STREAM +dvc_init_packet(dvc_hdr_t hdr, uint32 channelid, size_t length) +{ + STREAM s; + + length += 1; /* add 1 byte hdr */ + + if (channelid != INVALID_CHANNEL) + { + if (hdr.hdr.cbid == 0) + length += 1; + else if (hdr.hdr.cbid == 1) + length += 2; + else if (hdr.hdr.cbid == 2) + length += 4; + } + + s = channel_init(dvc_channel, length); + out_uint8(s, hdr.data); /* DVC header */ + + if (channelid != INVALID_CHANNEL) + { + if (hdr.hdr.cbid == 0) + { + out_uint8(s, channelid); + } + else if (hdr.hdr.cbid == 1) + { + out_uint16_le(s, channelid); + } + else if (hdr.hdr.cbid == 2) + { + out_uint32_le(s, channelid); + } + } + + return s; +} + +void +dvc_send(const char *name, STREAM s) +{ + STREAM ls; + dvc_hdr_t hdr; + uint32 channel_id; + + channel_id = dvc_channels_get_id(name); + if (channel_id == INVALID_CHANNEL) + { + logger(Core, Error, "dvc_send(), Trying to send data on invalid channel '%s'", + name); + return; + } + + /* FIXME: we assume length is less than 1600 */ + + hdr.hdr.cmd = DYNVC_DATA; + hdr.hdr.cbid = 2; + hdr.hdr.sp = 0; + + ls = dvc_init_packet(hdr, channel_id, s_length(s)); + + out_stream(ls, s); + + s_mark_end(ls); + + channel_send(ls, dvc_channel); + s_free(ls); +} + + +static void +dvc_send_capabilities_response() +{ + STREAM s; + dvc_hdr_t hdr; + uint16 supportedversion = 0x01; + + hdr.hdr.cbid = 0x00; + hdr.hdr.sp = 0x00; + hdr.hdr.cmd = DYNVC_CAPABILITIES; + + logger(Protocol, Debug, + "dvc_send_capabilities_response(), offering support for dvc %d", supportedversion); + + s = dvc_init_packet(hdr, -1, 3); + out_uint8(s, 0x00); /* pad */ + out_uint16_le(s, supportedversion); /* version */ + + s_mark_end(s); + + channel_send(s, dvc_channel); + s_free(s); +} + +static void +dvc_process_caps_pdu(STREAM s) +{ + uint16 version; + + /* VERSION1 */ + in_uint8s(s, 1); /* pad */ + in_uint16_le(s, version); /* version */ + + logger(Protocol, Debug, "dvc_process_caps(), server supports dvc %d", version); + + dvc_send_capabilities_response(); +} + +static void +dvc_send_create_response(RD_BOOL success, dvc_hdr_t hdr, uint32 channelid) +{ + STREAM s; + + logger(Protocol, Debug, "dvc_send_create_response(), %s request to create channelid %d", + (success ? "granted" : "denied"), channelid); + s = dvc_init_packet(hdr, channelid, 4); + out_uint32_le(s, success ? 0 : -1); + s_mark_end(s); + + channel_send(s, dvc_channel); + s_free(s); +} + +static void +dvc_process_create_pdu(STREAM s, dvc_hdr_t hdr) +{ + char name[512]; + uint32 channelid; + + channelid = dvc_in_channelid(s, hdr); + + in_ansi_string(s, name, sizeof(name)); + + logger(Protocol, Debug, "dvc_process_create(), server requests channelid = %d, name = '%s'", + channelid, name); + + if (dvc_channels_exists(name)) + { + logger(Core, Verbose, "Established dynamic virtual channel '%s'", name); + + dvc_channels_set_id(name, channelid); + dvc_send_create_response(True, hdr, channelid); + } + else + { + dvc_send_create_response(False, hdr, channelid); + } + +} + +static uint32 +dvc_in_channelid(STREAM s, dvc_hdr_t hdr) +{ + uint32 id; + + id = (uint32) - 1; + + switch (hdr.hdr.cbid) + { + case 0: + in_uint8(s, id); + break; + case 1: + in_uint16_le(s, id); + break; + case 2: + in_uint32_le(s, id); + break; + } + return id; +} + +static void +dvc_process_data_pdu(STREAM s, dvc_hdr_t hdr) +{ + const dvc_channel_t *ch; + uint32 channelid; + + channelid = dvc_in_channelid(s, hdr); + ch = dvc_channels_get_by_id(channelid); + if (ch == NULL) + { + logger(Protocol, Warning, + "dvc_process_data(), Received data on unregistered channel %d", channelid); + return; + } + + /* dispatch packet to channel handler */ + ch->handler(s); +} + +static void +dvc_process_close_pdu(STREAM s, dvc_hdr_t hdr) +{ + uint32 channelid; + + channelid = dvc_in_channelid(s, hdr); + logger(Protocol, Debug, "dvc_process_close_pdu(), close channel %d", channelid); + + if (!dvc_channels_remove_by_id(channelid)) + { + logger(Protocol, Warning, + "dvc_process_close_pdu(), Received close request for unregistered channel %d", + channelid); + return; + } +} + + +static void +dvc_process_pdu(STREAM s) +{ + dvc_hdr_t hdr; + + in_uint8(s, hdr.data); + + switch (hdr.hdr.cmd) + { + case DYNVC_CAPABILITIES: + dvc_process_caps_pdu(s); + break; + case DYNVC_CREATE_REQ: + dvc_process_create_pdu(s, hdr); + break; + + case DYNVC_DATA: + dvc_process_data_pdu(s, hdr); + break; + + case DYNVC_CLOSE: + dvc_process_close_pdu(s, hdr); + break; + +#if 0 /* Unimplemented */ + + case DYNVC_DATA_FIRST: + break; + case DYNVC_DATA_FIRST_COMPRESSED: + break; + case DYNVC_DATA_COMPRESSED: + break; + case DYNVC_SOFT_SYNC_REQUEST: + break; + case DYNVC_SOFT_SYNC_RESPONSE: + break; + +#endif + + default: + logger(Protocol, Warning, "dvc_process_pdu(), Unhandled command type 0x%x", + hdr.hdr.cmd); + break; + } +} + +RD_BOOL +dvc_init() +{ + memset(channels, 0, sizeof(channels)); + dvc_channel = channel_register("drdynvc", + CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP, + dvc_process_pdu); + + return (dvc_channel != NULL); +} diff -Nru rdesktop-1.8.6/ewmhints.c rdesktop-1.9.0/ewmhints.c --- rdesktop-1.8.6/ewmhints.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/ewmhints.c 2019-06-13 12:10:15.000000000 +0000 @@ -6,6 +6,7 @@ Copyright 2005-2011 Peter Astrand <astrand@cendio.se> for Cendio AB Copyright 2007 Pierre Ossman <ossman@cendio.se> for Cendio AB + Copyright 2015 Henrik Andersson <hean01@cendio.se> for Cendio AB 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 @@ -35,12 +36,12 @@ static Atom g_net_wm_state_maximized_vert_atom, g_net_wm_state_maximized_horz_atom, g_net_wm_state_hidden_atom, g_net_wm_name_atom, g_utf8_string_atom, g_net_wm_state_skip_taskbar_atom, g_net_wm_state_skip_pager_atom, - g_net_wm_state_modal_atom, g_net_wm_icon_atom, g_net_wm_state_above_atom; + g_net_wm_state_modal_atom, g_net_wm_icon_atom, g_net_wm_state_above_atom, g_net_wm_pid_atom; -Atom g_net_wm_state_atom, g_net_wm_desktop_atom; +Atom g_net_wm_state_atom, g_net_wm_desktop_atom, g_net_wm_ping_atom; /* - Get window property value (32 bit format) + Get window property value (32-bit format) Returns zero on success, -1 on error */ static int @@ -56,7 +57,7 @@ property = XInternAtom(g_display, propname, True); if (property == None) { - fprintf(stderr, "Atom %s does not exist\n", propname); + logger(GUI, Error, "get_property_value(), atom '%s' does not exist", propname); return (-1); } @@ -70,26 +71,27 @@ if (result != Success) { - fprintf(stderr, "XGetWindowProperty failed\n"); + logger(GUI, Error, "get_property_value(), XGetWindowProperty failed"); return (-1); } if (actual_type_return == None || actual_format_return == 0) { if (!nowarn) - fprintf(stderr, "Window is missing property %s\n", propname); + logger(GUI, Error, "get_property_value(), window is missing atom '%s'", + propname); return (-1); } if (bytes_after_return) { - fprintf(stderr, "%s is too big for me\n", propname); + logger(GUI, Error, "get_property_value(), atom '%s' is too big for me", propname); return (-1); } if (actual_format_return != 32) { - fprintf(stderr, "%s has bad format\n", propname); + logger(GUI, Error, "get_property_value(), atom '%s' has bad format", propname); return (-1); } @@ -114,7 +116,7 @@ if (nitems_return != 1) { - fprintf(stderr, "_NET_CURRENT_DESKTOP has bad length\n"); + logger(GUI, Error, "get_current_desktop(), _NET_CURRENT_DESKTOP has bad length"); return (-1); } @@ -148,7 +150,7 @@ if (nitems_return % 4) { - fprintf(stderr, "_NET_WORKAREA has odd length\n"); + logger(GUI, Error, "get_current_workarea(),_NET_WORKAREA has bad length"); return (-1); } @@ -190,6 +192,8 @@ g_net_wm_desktop_atom = XInternAtom(g_display, "_NET_WM_DESKTOP", False); g_net_wm_name_atom = XInternAtom(g_display, "_NET_WM_NAME", False); g_net_wm_icon_atom = XInternAtom(g_display, "_NET_WM_ICON", False); + g_net_wm_pid_atom = XInternAtom(g_display, "_NET_WM_PID", False); + g_net_wm_ping_atom = XInternAtom(g_display, "_NET_WM_PING", False); g_utf8_string_atom = XInternAtom(g_display, "UTF8_STRING", False); } @@ -197,7 +201,7 @@ /* Get the window state: normal/minimized/maximized. */ -#ifndef MAKE_PROTO + int ewmh_get_window_state(Window w) { @@ -242,7 +246,7 @@ XEvent xevent; int result; - unsigned long nitems; + unsigned long i, nitems; unsigned char *props; uint32 state = WithdrawnState; @@ -277,7 +281,6 @@ else { Atom *atoms; - int i; if (get_property_value(wnd, "_NET_WM_STATE", 64, &nitems, &props, 1) < 0) return 0; @@ -366,7 +369,7 @@ if (nitems_return != 1) { - fprintf(stderr, "_NET_WM_DESKTOP has bad length\n"); + logger(GUI, Error, "ewmh_get_window_desktop(), _NET_WM_DESKTOP has bad length"); return (-1); } @@ -409,6 +412,12 @@ 8, PropModeReplace, (unsigned char *) title, len); } +void +ewmh_set_wm_pid(Window wnd, pid_t pid) +{ + XChangeProperty(g_display, wnd, g_net_wm_pid_atom, + XA_CARDINAL, sizeof(pid_t) * 8, PropModeReplace, (unsigned char *) &pid, 1); +} int ewmh_set_window_popup(Window wnd) @@ -428,7 +437,7 @@ } void -ewmh_set_icon(Window wnd, int width, int height, const char *rgba_data) +ewmh_set_icon(Window wnd, uint32 width, uint32 height, const char *rgba_data) { unsigned long nitems, i; unsigned char *props; @@ -471,7 +480,7 @@ icon[1] = height; /* Convert RGBA -> ARGB */ - for (i = 0; i < width * height; i++) + for (i = 0; i < (width * height); i++) { icon[i + 2] = rgba_data[i * 4 + 3] << 24 | @@ -490,7 +499,7 @@ } void -ewmh_del_icon(Window wnd, int width, int height) +ewmh_del_icon(Window wnd, uint32 width, uint32 height) { unsigned long nitems, i, icon_size; unsigned char *props; @@ -570,9 +579,6 @@ return above; } -#endif /* MAKE_PROTO */ - - #if 0 /* FIXME: _NET_MOVERESIZE_WINDOW is for pagers, not for diff -Nru rdesktop-1.8.6/genauthors rdesktop-1.9.0/genauthors --- rdesktop-1.8.6/genauthors 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/genauthors 1970-01-01 00:00:00.000000000 +0000 @@ -1,58 +0,0 @@ -#!/usr/bin/env python -# -*-mode: python; coding: utf-8 -*- - -import re -import sys - -# Filled in with historical authors which are not mentioned in the source -authors = { - "Hugo Trippaers <spark@ision.nl>": 1, - "Michal Mihalik <mmihalik@sme.sk>": 1, - "Norbert Federa <nob@thinstuff.com>": 1, - "Peter Kallden <peter.kallden@ub.oru.se>": 1, - } - - -def dostatement(s): - # Get rid of (C) - s = re.sub('\(C\)', '', s).strip() - - # Get rid of years - s = re.sub('\d\d\d\d(-\d\d\d\d)?', '', s).strip() - - # Get rid of in-code statements - if s.find('"') != -1: - return - - global authors - authors[s] = 1 - - -def dofile(fname): - f = open(fname) - pt = re.compile('\sCopyright (.*)') - for line in f: - m = pt.search(line) - if m != None: - dostatement(m.group(1).strip()) - - -def main(): - for fname in sys.argv[1:]: - dofile(fname) - - print """This is an attempt at a list of people who have made significant -contributions to the code. If you have been unintentionally omitted -please let one of the team members know. -""" - - keys = authors.keys() - keys.sort() - for k in keys: - print k - - - - - -main() diff -Nru rdesktop-1.8.6/indent-all.sh rdesktop-1.9.0/indent-all.sh --- rdesktop-1.8.6/indent-all.sh 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/indent-all.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -#!/bin/sh -indent -bli0 -i8 -cli8 -npcs -l100 *.h *.c vnc/*.h vnc/*.c -# Tweak in order to support both indent 2.2.10 and 2.2.11 -perl -pi -e 's|!!|! !|g' *.c - diff -Nru rdesktop-1.8.6/iso.c rdesktop-1.9.0/iso.c --- rdesktop-1.8.6/iso.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/iso.c 2019-09-20 06:39:29.000000000 +0000 @@ -3,7 +3,7 @@ Protocol services - ISO layer Copyright (C) Matthew Chapman <matthewc.unsw.edu.au> 1999-2008 Copyright 2005-2011 Peter Astrand <astrand@cendio.se> for Cendio AB - Copyright 2012 Henrik Andersson <hean01@cendio.se> for Cendio AB + Copyright 2012-2018 Henrik Andersson <hean01@cendio.se> for Cendio AB 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 @@ -32,6 +32,7 @@ extern char *g_sc_reader_name; extern char *g_sc_card_name; extern char *g_sc_container_name; +extern char g_tls_version[]; /* Send a self-contained ISO PDU */ @@ -86,7 +87,7 @@ if (g_rdp_version >= RDP_V5 && g_negotiate_rdp_protocol) { - /* optional rdp protocol negotiation request for RDPv5 */ + /* optional RDP protocol negotiation request for RDPv5 */ out_uint8(s, RDP_NEG_REQ); out_uint8(s, 0); out_uint16(s, 8); @@ -100,7 +101,7 @@ /* Receive a message on the ISO layer, return code */ static STREAM -iso_recv_msg(uint8 * code, uint8 * rdpver) +iso_recv_msg(uint8 * code, RD_BOOL * is_fastpath, uint8 * fastpath_hdr) { STREAM s; uint16 length; @@ -109,33 +110,45 @@ s = tcp_recv(NULL, 4); if (s == NULL) return NULL; - in_uint8(s, version); - if (rdpver != NULL) - *rdpver = version; - if (version == 3) + + in_uint8(s, version); /* T.123 version or Fastpath output header */ + + /* detect if this is a slow or fast path PDU */ + *fastpath_hdr = 0x00; + *is_fastpath = False; + if (version == T123_HEADER_VERSION) { - in_uint8s(s, 1); /* pad */ - in_uint16_be(s, length); + in_uint8s(s, 1); /* reserved */ + in_uint16_be(s, length); /* length */ } else { - in_uint8(s, length); + /* if version is not an expected T.123 version eg. 3, then this + stream is a fast path pdu */ + *is_fastpath = True; + *fastpath_hdr = version; + in_uint8(s, length); /* length1 */ if (length & 0x80) { + /* length2 is only present if the most significant bit of length1 is set */ length &= ~0x80; next_be(s, length); } } + if (length < 4) { - error("Bad packet header\n"); + logger(Protocol, Error, "iso_recv_msg(), bad packet header, length < 4"); return NULL; } + s = tcp_recv(s, length - 4); if (s == NULL) return NULL; - if (version != 3) + + if (*is_fastpath == True) return s; + in_uint8s(s, 1); /* hdrlen */ in_uint8(s, *code); if (*code == ISO_PDU_DT) @@ -168,7 +181,7 @@ s_pop_layer(s, iso_hdr); length = s_remaining(s); - out_uint8(s, 3); /* version */ + out_uint8(s, T123_HEADER_VERSION); /* version */ out_uint8(s, 0); /* reserved */ out_uint16_be(s, length); @@ -181,33 +194,51 @@ /* Receive ISO transport data packet */ STREAM -iso_recv(uint8 * rdpver) +iso_recv(RD_BOOL * is_fastpath, uint8 * fastpath_hdr) { STREAM s; uint8 code = 0; - s = iso_recv_msg(&code, rdpver); + s = iso_recv_msg(&code, is_fastpath, fastpath_hdr); if (s == NULL) return NULL; - if (rdpver != NULL) - if (*rdpver != 3) - return s; + + if (*is_fastpath == True) + return s; + if (code != ISO_PDU_DT) { - error("expected DT, got 0x%x\n", code); + logger(Protocol, Error, "iso_recv(), expected ISO_PDU_DT, got 0x%x", code); return NULL; } return s; } + +/* try to setup a more helpful error message about TLS */ +char *get_credSSP_reason(uint32 neg_proto) +{ +static char msg[256]; + +strcat(msg, "CredSSP required by server"); +if ((neg_proto & PROTOCOL_SSL) && + ( (g_tls_version[0] == 0) || + (strcmp(g_tls_version, "1.2") < 0))) + strcat(msg, " (check if server has disabled old TLS versions, if yes use -V option)"); +return msg; +} + /* Establish a connection up to the ISO layer */ RD_BOOL iso_connect(char *server, char *username, char *domain, char *password, RD_BOOL reconnect, uint32 * selected_protocol) { + UNUSED(reconnect); STREAM s; uint8 code; uint32 neg_proto; + RD_BOOL is_fastpath; + uint8 fastpath_hdr; g_negotiate_rdp_protocol = True; @@ -219,8 +250,13 @@ else if (g_sc_csp_name || g_sc_reader_name || g_sc_card_name || g_sc_container_name) neg_proto |= PROTOCOL_HYBRID; else - warning("Disables CredSSP due to missing smartcard information for SSO.\n"); + logger(Core, Warning, + "iso_connect(), missing smartcard information for SSO, disabling CredSSP"); #endif + if (neg_proto & PROTOCOL_HYBRID) + logger(Core, Verbose, "Connecting to server using NLA..."); + else + logger(Core, Verbose, "Connecting to server using SSL..."); retry: *selected_protocol = PROTOCOL_RDP; @@ -231,13 +267,13 @@ iso_send_connection_request(username, neg_proto); - s = iso_recv_msg(&code, NULL); + s = iso_recv_msg(&code, &is_fastpath, &fastpath_hdr); if (s == NULL) return False; if (code != ISO_PDU_CC) { - error("expected CC, got 0x%x\n", code); + logger(Protocol, Error, "iso_connect(), expected ISO_PDU_CC, got 0x%x", code); tcp_disconnect(); return False; } @@ -247,13 +283,12 @@ /* handle RDP_NEG_REQ response */ const char *reason = NULL; - uint8 type = 0, flags = 0; - uint16 length = 0; + uint8 type = 0; uint32 data = 0; in_uint8(s, type); - in_uint8(s, flags); - in_uint16(s, length); + in_uint8s(s, 1); /* skip flags */ + in_uint8s(s, 2); /* skip length */ in_uint32(s, data); if (type == RDP_NEG_FAILURE) @@ -280,7 +315,7 @@ reason = "SSL required by server"; break; case HYBRID_REQUIRED_BY_SERVER: - reason = "CredSSP required by server"; + reason = get_credSSP_reason(neg_proto); break; default: reason = "unknown reason"; @@ -290,20 +325,27 @@ if (retry_without_neg) { - fprintf(stderr, - "Failed to negotiate protocol, retrying with plain RDP.\n"); + if (reason != NULL) + { + logger(Protocol, Warning, + "Protocol negotiation failed with reason: %s", + reason); + } + + logger(Core, Notice, "Retrying with plain RDP."); g_negotiate_rdp_protocol = False; goto retry; } - fprintf(stderr, "Failed to connect, %s.\n", reason); + logger(Core, Notice, "Failed to connect, %s.\n", reason); return False; } if (type != RDP_NEG_RSP) { tcp_disconnect(); - error("Expected RDP_NEG_RSP, got type = 0x%x\n", type); + logger(Protocol, Error, "iso_connect(), expected RDP_NEG_RSP, got 0x%x", + type); return False; } @@ -313,13 +355,15 @@ if (!tcp_tls_connect()) { /* failed to connect using cssp, let retry with plain TLS */ + logger(Core, Verbose, + "Failed to connect using SSL, trying with plain RDP."); tcp_disconnect(); neg_proto = PROTOCOL_RDP; goto retry; } /* do not use encryption when using TLS */ g_encryption = False; - fprintf(stderr, "Connection established using SSL.\n"); + logger(Core, Notice, "Connection established using SSL."); } #ifdef WITH_CREDSSP else if (data == PROTOCOL_HYBRID) @@ -327,25 +371,28 @@ if (!cssp_connect(server, username, domain, password, s)) { /* failed to connect using cssp, let retry with plain TLS */ + logger(Core, Verbose, + "Failed to connect using NLA, trying with SSL"); tcp_disconnect(); neg_proto = PROTOCOL_SSL; goto retry; } /* do not use encryption when using TLS */ - fprintf(stderr, "Connection established using CredSSP.\n"); + logger(Core, Notice, "Connection established using CredSSP."); g_encryption = False; } #endif else if (data == PROTOCOL_RDP) { - fprintf(stderr, "Connection established using plain RDP.\n"); + logger(Core, Notice, "Connection established using plain RDP."); } else if (data != PROTOCOL_RDP) { tcp_disconnect(); - error("Unexpected protocol in negotiation response, got data = 0x%x.\n", - data); + logger(Protocol, Error, + "iso_connect(), unexpected protocol in negotiation response, got 0x%x", + data); return False; } diff -Nru rdesktop-1.8.6/keymaps/ru rdesktop-1.9.0/keymaps/ru --- rdesktop-1.8.6/keymaps/ru 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/keymaps/ru 2019-06-13 12:10:15.000000000 +0000 @@ -1,109 +1,80 @@ -# generated from XKB map ru -include common +include modifiers map 0x419 -exclam 0x02 shift -at 0x03 shift -quotedbl 0x03 shift altgr -numbersign 0x04 shift -dollar 0x05 shift -asterisk 0x05 shift altgr -percent 0x06 shift -colon 0x06 shift altgr -asciicircum 0x07 shift -comma 0x07 shift altgr -ampersand 0x08 shift -period 0x08 shift altgr -asterisk 0x09 shift -semicolon 0x09 shift altgr -parenleft 0x0a shift -parenright 0x0b shift -minus 0x0c -underscore 0x0c shift -equal 0x0d -plus 0x0d shift -Cyrillic_shorti 0x10 altgr -Cyrillic_SHORTI 0x10 shift altgr -Cyrillic_tse 0x11 altgr -Cyrillic_TSE 0x11 shift altgr -Cyrillic_u 0x12 altgr -Cyrillic_U 0x12 shift altgr -Cyrillic_ka 0x13 altgr -Cyrillic_KA 0x13 shift altgr -Cyrillic_ie 0x14 altgr -Cyrillic_IE 0x14 shift altgr -Cyrillic_en 0x15 altgr -Cyrillic_EN 0x15 shift altgr -Cyrillic_ghe 0x16 altgr -Cyrillic_GHE 0x16 shift altgr -Cyrillic_sha 0x17 altgr -Cyrillic_SHA 0x17 shift altgr -Cyrillic_shcha 0x18 altgr -Cyrillic_SHCHA 0x18 shift altgr -Cyrillic_ze 0x19 altgr -Cyrillic_ZE 0x19 shift altgr -bracketleft 0x1a -braceleft 0x1a shift -Cyrillic_ha 0x1a altgr -Cyrillic_HA 0x1a shift altgr -bracketright 0x1b -braceright 0x1b shift -Cyrillic_hardsign 0x1b altgr -Cyrillic_HARDSIGN 0x1b shift altgr -Cyrillic_ef 0x1e altgr -Cyrillic_EF 0x1e shift altgr -Cyrillic_yeru 0x1f altgr -Cyrillic_YERU 0x1f shift altgr -Cyrillic_ve 0x20 altgr -Cyrillic_VE 0x20 shift altgr -Cyrillic_a 0x21 altgr -Cyrillic_A 0x21 shift altgr -Cyrillic_pe 0x22 altgr -Cyrillic_PE 0x22 shift altgr -Cyrillic_er 0x23 altgr -Cyrillic_ER 0x23 shift altgr -Cyrillic_o 0x24 altgr -Cyrillic_O 0x24 shift altgr -Cyrillic_el 0x25 altgr -Cyrillic_EL 0x25 shift altgr -Cyrillic_de 0x26 altgr -Cyrillic_DE 0x26 shift altgr -semicolon 0x27 -colon 0x27 shift -Cyrillic_zhe 0x27 altgr -Cyrillic_ZHE 0x27 shift altgr -apostrophe 0x28 -quotedbl 0x28 shift -Cyrillic_e 0x28 altgr -Cyrillic_E 0x28 shift altgr -grave 0x29 -asciitilde 0x29 shift -Cyrillic_io 0x29 altgr -Cyrillic_IO 0x29 shift altgr -backslash 0x2b -bar 0x2b shift -Cyrillic_ya 0x2c altgr -Cyrillic_YA 0x2c shift altgr -Cyrillic_che 0x2d altgr -Cyrillic_CHE 0x2d shift altgr -Cyrillic_es 0x2e altgr -Cyrillic_ES 0x2e shift altgr -Cyrillic_em 0x2f altgr -Cyrillic_EM 0x2f shift altgr -Cyrillic_i 0x30 altgr -Cyrillic_I 0x30 shift altgr -Cyrillic_te 0x31 altgr -Cyrillic_TE 0x31 shift altgr -Cyrillic_softsign 0x32 altgr -Cyrillic_SOFTSIGN 0x32 shift altgr -comma 0x33 -less 0x33 shift -Cyrillic_be 0x33 altgr -Cyrillic_BE 0x33 shift altgr -period 0x34 -greater 0x34 shift -Cyrillic_yu 0x34 altgr -Cyrillic_YU 0x34 shift altgr -slash 0x35 -question 0x35 shift -slash 0x56 altgr -bar 0x56 shift altgr +# +# Arrow keys +# +Left 0xcb localstate +Up 0xc8 localstate +Down 0xd0 localstate +Right 0xcd localstate + +# +# Numpad +# +Num_Lock 0x45 +KP_Divide 0xb5 localstate +KP_Multiply 0x37 localstate +KP_Subtract 0x4a localstate +KP_Add 0x4e localstate +KP_Enter 0x9c localstate + +KP_Decimal 0x53 numlock +KP_Separator 0x53 numlock +KP_Delete 0x53 + +KP_0 0x52 numlock +KP_Insert 0x52 localstate + +KP_1 0x4f numlock +KP_End 0x4f localstate + +KP_2 0x50 numlock +KP_Down 0x50 localstate + +KP_3 0x51 numlock +KP_Next 0x51 localstate + +KP_4 0x4b numlock +KP_Left 0x4b localstate + +KP_5 0x4c numlock +KP_Begin 0x4c localstate + +KP_6 0x4d numlock +KP_Right 0x4d localstate + +KP_7 0x47 numlock +KP_Home 0x47 localstate + +KP_8 0x48 numlock +KP_Up 0x48 localstate + +KP_9 0x49 numlock +KP_Prior 0x49 localstate +# +# Esc and Function keys +# +Escape 0x1 localstate +F1 0x3b localstate +F2 0x3c localstate +F3 0x3d localstate +F4 0x3e localstate +F5 0x3f localstate +F6 0x40 localstate +F7 0x41 localstate +F8 0x42 localstate +F9 0x43 localstate +F10 0x44 localstate +F11 0x57 localstate +F12 0x58 localstate + +# +# Insert - PgDown +# +Insert 0xd2 localstate +Delete 0xd3 localstate +Home 0xc7 localstate +End 0xcf localstate +Page_Up 0xc9 localstate +Page_Down 0xd1 localstate + diff -Nru rdesktop-1.8.6/licence.c rdesktop-1.9.0/licence.c --- rdesktop-1.8.6/licence.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/licence.c 2019-06-13 12:10:15.000000000 +0000 @@ -58,12 +58,12 @@ strncpy((char *) (hwid + 4), g_hostname, LICENCE_HWID_SIZE - 4); } -/* Send a lincece info packet to server */ +/* Send a licence info packet to server */ static void licence_info(uint8 * client_random, uint8 * rsa_data, uint8 * licence_data, int licence_size, uint8 * hwid, uint8 * signature) { - uint32 sec_flags = SEC_LICENCE_NEG; + uint32 sec_flags = SEC_LICENSE_PKT; uint16 length = 24 + SEC_RANDOM_SIZE + SEC_MODULUS_SIZE + SEC_PADDING_SIZE + licence_size + LICENCE_HWID_SIZE + LICENCE_SIGNATURE_SIZE; @@ -104,7 +104,7 @@ static void licence_send_new_licence_request(uint8 * client_random, uint8 * rsa_data, char *user, char *host) { - uint32 sec_flags = SEC_LICENCE_NEG; + uint32 sec_flags = SEC_LICENSE_PKT; uint16 userlen = strlen(user) + 1; uint16 hostlen = strlen(host) + 1; uint16 length = @@ -173,32 +173,34 @@ rdssl_rc4_set_key(&crypt_key, g_licence_key, 16); rdssl_rc4_crypt(&crypt_key, hwid, hwid, sizeof(hwid)); -#if WITH_DEBUG - DEBUG(("Sending licensing PDU (message type 0x%02x)\n", LICENCE_TAG_LICENCE_INFO)); -#endif + logger(Protocol, Debug, + "license_process_request(), sending licensing PDU (message type 0x%02x)", + LICENCE_TAG_LICENCE_INFO); + licence_info(null_data, null_data, licence_data, licence_size, hwid, signature); xfree(licence_data); return; } -#if WITH_DEBUG - DEBUG(("Sending licensing PDU (message type 0x%02x)\n", LICENCE_TAG_NEW_LICENCE_REQUEST)); -#endif + logger(Protocol, Debug, + "license_process_request(), sending licensing PDU (message type 0x%02x)", + LICENCE_TAG_NEW_LICENCE_REQUEST); + licence_send_new_licence_request(null_data, null_data, g_username, g_hostname); } -/* Send a platform challange response packet */ +/* Send a platform challenge response packet */ static void -licence_send_platform_challange_response(uint8 * token, uint8 * crypt_hwid, uint8 * signature) +licence_send_platform_challenge_response(uint8 * token, uint8 * crypt_hwid, uint8 * signature) { - uint32 sec_flags = SEC_LICENCE_NEG; + uint32 sec_flags = SEC_LICENSE_PKT; uint16 length = 58; STREAM s; s = sec_init(sec_flags, length + 2); - out_uint8(s, LICENCE_TAG_PLATFORM_CHALLANGE_RESPONSE); + out_uint8(s, LICENCE_TAG_PLATFORM_CHALLENGE_RESPONSE); out_uint8(s, ((g_rdp_version >= RDP_V5) ? 3 : 2)); /* version */ out_uint16_le(s, length); @@ -217,9 +219,9 @@ s_free(s); } -/* Parse an platform challange request packet */ +/* Parse an platform challenge request packet */ static RD_BOOL -licence_parse_platform_challange(STREAM s, uint8 ** token, uint8 ** signature) +licence_parse_platform_challenge(STREAM s, uint8 ** token, uint8 ** signature) { uint16 tokenlen; @@ -228,7 +230,8 @@ in_uint16_le(s, tokenlen); if (tokenlen != LICENCE_TOKEN_SIZE) { - error("token len %d\n", tokenlen); + logger(Protocol, Error, + "license_parse_platform_challenge(), tokenlen != LICENSE_TOKEN_SIZE"); return False; } @@ -238,9 +241,9 @@ return s_check_end(s); } -/* Process a platform challange packet */ +/* Process a platform challenge packet */ static void -licence_process_platform_challange(STREAM s) +licence_process_platform_challenge(STREAM s) { uint8 *in_token = NULL, *in_sig; uint8 out_token[LICENCE_TOKEN_SIZE], decrypt_token[LICENCE_TOKEN_SIZE]; @@ -250,7 +253,7 @@ RDSSL_RC4 crypt_key; /* Parse incoming packet and save the encrypted token */ - licence_parse_platform_challange(s, &in_token, &in_sig); + licence_parse_platform_challenge(s, &in_token, &in_sig); memcpy(out_token, in_token, LICENCE_TOKEN_SIZE); /* Decrypt the token. It should read TEST in Unicode. */ @@ -267,7 +270,7 @@ rdssl_rc4_set_key(&crypt_key, g_licence_key, 16); rdssl_rc4_crypt(&crypt_key, hwid, crypt_hwid, LICENCE_HWID_SIZE); - licence_send_platform_challange_response(out_token, crypt_hwid, out_sig); + licence_send_platform_challenge_response(out_token, crypt_hwid, out_sig); } /* Process a new licence packet */ @@ -318,10 +321,10 @@ { uint32 error_code; uint32 state_transition; - uint32 error_info; + in_uint32(s, error_code); in_uint32(s, state_transition); - in_uint32(s, error_info); + in_uint8s(s, 4); /* Skip error_info */ /* There is a special case in the error alert handling, when licensing is all good and the server is not sending a license to client, a "Server License Error PDU - @@ -335,23 +338,24 @@ return; } - /* handle error codes, for now, jsut report them */ + /* handle error codes, for now, just report them */ switch (error_code) { case 0x6: // ERR_NO_LICENSE_SERVER - warning("License error alert from server: No license server\n"); + logger(Core, Notice, "License error alert from server: No license server"); break; case 0x8: // ERR_INVALID_CLIENT - warning("License error alert from server: Invalid client\n"); + logger(Core, Notice, "License error alert from server: Invalid client"); break; case 0x4: // ERR_INVALID_SCOPE case 0xb: // ERR_INVALID_PRODUCTID case 0xc: // ERR_INVALID_MESSAGE_LENGTH default: - warning("License error alert from server: code %u, state transition %u\n", - error_code, state_transition); + logger(Core, Notice, + "License error alert from server: code %u, state transition %u", + error_code, state_transition); break; } @@ -368,9 +372,8 @@ in_uint8(s, tag); in_uint8s(s, 3); /* version, length */ -#if WITH_DEBUG - DEBUG(("Received licensing PDU (message type 0x%02x)\n", tag)); -#endif + logger(Protocol, Debug, "license_process(), processing licensing PDU (message type 0x%02x)", + tag); switch (tag) { @@ -378,8 +381,8 @@ licence_process_request(s); break; - case LICENCE_TAG_PLATFORM_CHALLANGE: - licence_process_platform_challange(s); + case LICENCE_TAG_PLATFORM_CHALLENGE: + licence_process_platform_challenge(s); break; case LICENCE_TAG_NEW_LICENCE: @@ -393,6 +396,7 @@ break; default: - unimpl("licence tag 0x%02x\n", tag); + logger(Protocol, Warning, + "license_process(), unhandled license PDU tag 0x%02", tag); } } diff -Nru rdesktop-1.8.6/lspci.c rdesktop-1.9.0/lspci.c --- rdesktop-1.8.6/lspci.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/lspci.c 2019-06-13 12:10:15.000000000 +0000 @@ -44,13 +44,14 @@ static RD_BOOL handle_child_line(const char *line, void *data) { + UNUSED(data); const char *val; char buf[1024]; if (str_startswith(line, "Class:")) { val = line + sizeof("Class:"); - /* Skip whitespace and second Class: occurance */ + /* Skip whitespace and second Class: occurrence */ val += strspn(val, " \t") + sizeof("Class"); current_device.klass = strtol(val, NULL, 16); } @@ -99,7 +100,7 @@ } else { - warning("lspci: Unrecoqnized line '%s'\n", line); + logger(Core, Warning, "handle_child_line(), Unrecognized lspci line '%s'", line); } return True; } @@ -109,6 +110,7 @@ static RD_BOOL lspci_process_line(const char *line, void *data) { + UNUSED(data); char *lspci_command[5] = { "lspci", "-m", "-n", "-v", NULL }; if (!strcmp(line, "LSPCI")) @@ -120,7 +122,7 @@ } else { - error("lspci protocol error: Invalid line '%s'\n", line); + logger(Core, Error, "lspci_process_line(), invalid line '%s'", line); } return True; } @@ -139,11 +141,6 @@ buf = xmalloc(pkglen + 1); in_uint8a(s, buf, pkglen); buf[pkglen] = '\0'; -#if 0 - printf("lspci recv:\n"); - hexdump(s->p, pkglen); -#endif - str_handle_lines(buf, &rest, lspci_process_line, NULL); xfree(buf); } @@ -168,12 +165,6 @@ len = strlen(output); s = channel_init(lspci_channel, len); out_uint8a(s, output, len) s_mark_end(s); - -#if 0 - printf("lspci send:\n"); - hexdump(s->channel_hdr + 8, s->end - s->channel_hdr - 8); -#endif - channel_send(s, lspci_channel); s_free(s); } diff -Nru rdesktop-1.8.6/Makefile.in rdesktop-1.9.0/Makefile.in --- rdesktop-1.8.6/Makefile.in 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/Makefile.in 2019-06-13 12:10:15.000000000 +0000 @@ -20,17 +20,13 @@ LDFLAGS = @LDFLAGS@ @LIBS@ @X_LIBS@ @X_EXTRA_LIBS@ STRIP = @STRIP@ -TARGETS = rdesktop @RDP2VNCTARGET@ -VNCINC = @VNCINC@ -LDVNC = @LDVNC@ -VNCLINK = @VNCLINK@ +TARGETS = rdesktop SOUNDOBJ = @SOUNDOBJ@ SCARDOBJ = @SCARDOBJ@ CREDSSPOBJ = @CREDSSPOBJ@ -RDPOBJ = tcp.o asn.o iso.o mcs.o secure.o licence.o rdp.o orders.o bitmap.o cache.o rdp5.o channels.o rdpdr.o serial.o printer.o disk.o parallel.o printercache.o mppc.o pstcache.o lspci.o seamless.o ssl.o utils.o parse.o +RDPOBJ = tcp.o asn.o iso.o mcs.o secure.o licence.o rdp.o orders.o bitmap.o cache.o rdp5.o channels.o rdpdr.o serial.o printer.o disk.o parallel.o printercache.o mppc.o pstcache.o lspci.o seamless.o ssl.o utils.o stream.o dvc.o rdpedisp.o X11OBJ = rdesktop.o xwin.o xkeymap.o ewmhints.o xclip.o cliprdr.o ctrl.o -VNCOBJ = vnc/rdp2vnc.o vnc/vnc.o vnc/xkeymap.o vnc/x11stubs.o .PHONY: all all: $(TARGETS) @@ -38,21 +34,6 @@ rdesktop: $(X11OBJ) $(SOUNDOBJ) $(RDPOBJ) $(SCARDOBJ) $(CREDSSPOBJ) $(CC) $(CFLAGS) -o rdesktop $(X11OBJ) $(SOUNDOBJ) $(RDPOBJ) $(SCARDOBJ) $(CREDSSPOBJ) $(LDFLAGS) -lX11 -rdp2vnc: $(VNCOBJ) $(SOUNDOBJ) $(RDPOBJ) $(SCARDOBJ) $(CREDSSPOBJ) - $(VNCLINK) $(CFLAGS) -o rdp2vnc $(VNCOBJ) $(SOUNDOBJ) $(RDPOBJ) $(SCARDOBJ) $(CREDSSPOBJ) $(LDFLAGS) $(LDVNC) - -vnc/rdp2vnc.o: rdesktop.c - $(CC) $(CFLAGS) $(VNCINC) -DRDP2VNC -o vnc/rdp2vnc.o -c rdesktop.c - -vnc/vnc.o: vnc/vnc.c - $(CC) $(CFLAGS) $(VNCINC) -DRDP2VNC -o vnc/vnc.o -c vnc/vnc.c - -vnc/xkeymap.o: xkeymap.c - $(CC) $(CFLAGS) $(VNCINC) -DRDP2VNC -o vnc/xkeymap.o -c xkeymap.c - -vnc/x11stubs.o: vnc/x11stubs.c - $(CC) $(CFLAGS) $(VNCINC) -o vnc/x11stubs.o -c vnc/x11stubs.c - .PHONY: install install: installbin installkeymaps installman @@ -73,25 +54,14 @@ installkeymaps: mkdir -p $(DESTDIR)$(KEYMAP_PATH) # Prevent copying the CVS directory - cp keymaps/?? keymaps/??-?? $(DESTDIR)$(KEYMAP_PATH) + cp keymaps/?? keymaps/??-?? keymaps/??-??-???? $(DESTDIR)$(KEYMAP_PATH) cp keymaps/common $(DESTDIR)$(KEYMAP_PATH) cp keymaps/modifiers $(DESTDIR)$(KEYMAP_PATH) chmod 644 $(DESTDIR)$(KEYMAP_PATH)/* -.PHONY: proto -proto: - cat proto.head > proto.h - cproto -DMAKE_PROTO \ - bitmap.c cache.c channels.c cliprdr.c disk.c mppc.c ewmhints.c \ - iso.c licence.c mcs.c orders.c parallel.c printer.c printercache.c \ - pstcache.c rdesktop.c rdp5.c rdp.c rdpdr.c rdpsnd.c \ - secure.c serial.c tcp.c xclip.c xkeymap.c xwin.c lspci.c seamless.c \ - scard.c >> proto.h - cat proto.tail >> proto.h - .PHONY: clean clean: - rm -f *.o *~ vnc/*.o vnc/*~ rdesktop rdp2vnc + rm -f *.o *~ rdesktop .PHONY: distclean distclean: clean @@ -106,7 +76,7 @@ (cd /tmp/rdesktop-make-dist-dir; \ tar zcvf rdesktop-$(VERSION)/rdesktop-$(VERSION).tar.gz \ rdesktop-$(VERSION)/COPYING \ - rdesktop-$(VERSION)/README \ + rdesktop-$(VERSION)/README.md \ rdesktop-$(VERSION)/configure \ rdesktop-$(VERSION)/configure.ac \ rdesktop-$(VERSION)/config.sub \ @@ -117,10 +87,8 @@ rdesktop-$(VERSION)/rdesktop.spec \ rdesktop-$(VERSION)/*.c \ rdesktop-$(VERSION)/*.h \ - rdesktop-$(VERSION)/proto.head \ - rdesktop-$(VERSION)/proto.tail \ rdesktop-$(VERSION)/keymaps/?? \ - rdesktop-$(VERSION)/keymaps/??-?? \ + rdesktop-$(VERSION)/keymaps/??-* \ rdesktop-$(VERSION)/keymaps/common \ rdesktop-$(VERSION)/keymaps/modifiers \ rdesktop-$(VERSION)/keymaps/convert-map \ diff -Nru rdesktop-1.8.6/mcs.c rdesktop-1.9.0/mcs.c --- rdesktop-1.8.6/mcs.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/mcs.c 2019-06-13 12:10:15.000000000 +0000 @@ -3,6 +3,7 @@ Protocol services - Multipoint Communications Service Copyright (C) Matthew Chapman <matthewc.unsw.edu.au> 1999-2008 Copyright 2005-2011 Peter Astrand <astrand@cendio.se> for Cendio AB + Copyright 2018 Henrik Andersson <hean01@cendio.com> for Cendio AB 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 @@ -64,7 +65,7 @@ int datalen = s_length(mcs_data); int length = 9 + 3 * 34 + 4 + datalen; STREAM s; - + logger(Protocol, Debug, "%s()", __func__); s = iso_init(length + 5); ber_out_header(s, MCS_CONNECT_INITIAL, length); @@ -92,14 +93,20 @@ static RD_BOOL mcs_recv_connect_response(STREAM mcs_data) { + UNUSED(mcs_data); uint8 result; uint32 length; STREAM s; struct stream packet; - s = iso_recv(NULL); + RD_BOOL is_fastpath; + uint8 fastpath_hdr; + + logger(Protocol, Debug, "%s()", __func__); + s = iso_recv(&is_fastpath, &fastpath_hdr); + if (s == NULL) return False; - + packet = *s; ber_parse_header(s, MCS_CONNECT_RESPONSE, &length); @@ -108,7 +115,7 @@ in_uint8(s, result); if (result != 0) { - error("MCS connect: %d\n", result); + logger(Protocol, Error, "mcs_recv_connect_response(), result=%d", result); return False; } @@ -128,8 +135,7 @@ /* if (length > mcs_data->size) { - error("MCS data length %d, expected %d\n", length, - mcs_data->size); + logger(Protocol, Error, "mcs_recv_connect_response(), expected length=%d, got %d",length, mcs_data->size); length = mcs_data->size; } @@ -146,7 +152,7 @@ mcs_send_edrq(void) { STREAM s; - + logger(Protocol, Debug, "%s()", __func__); s = iso_init(5); out_uint8(s, (MCS_EDRQ << 2)); @@ -163,7 +169,7 @@ mcs_send_aurq(void) { STREAM s; - + logger(Protocol, Debug, "%s()", __func__); s = iso_init(1); out_uint8(s, (MCS_AURQ << 2)); @@ -177,24 +183,28 @@ static RD_BOOL mcs_recv_aucf(uint16 * mcs_userid) { + RD_BOOL is_fastpath; + uint8 fastpath_hdr; uint8 opcode, result; STREAM s; - s = iso_recv(NULL); + logger(Protocol, Debug, "%s()", __func__); + s = iso_recv(&is_fastpath, &fastpath_hdr); + if (s == NULL) return False; in_uint8(s, opcode); if ((opcode >> 2) != MCS_AUCF) { - error("expected AUcf, got %d\n", opcode); + logger(Protocol, Error, "mcs_recv_aucf(), expected opcode AUcf, got %d", opcode); return False; } in_uint8(s, result); if (result != 0) { - error("AUrq: %d\n", result); + logger(Protocol, Error, "mcs_recv_aucf(), expected result 0, got %d", result); return False; } @@ -210,7 +220,7 @@ { STREAM s; - DEBUG_RDP5(("Sending CJRQ for channel #%d\n", chanid)); + logger(Protocol, Debug, "mcs_send_cjrq(), chanid=%d", chanid); s = iso_init(5); @@ -227,24 +237,28 @@ static RD_BOOL mcs_recv_cjcf(void) { + RD_BOOL is_fastpath; + uint8 fastpath_hdr; uint8 opcode, result; STREAM s; - s = iso_recv(NULL); + logger(Protocol, Debug, "%s()", __func__); + s = iso_recv(&is_fastpath, &fastpath_hdr); + if (s == NULL) return False; in_uint8(s, opcode); if ((opcode >> 2) != MCS_CJCF) { - error("expected CJcf, got %d\n", opcode); + logger(Protocol, Error, "mcs_recv_cjcf(), expected opcode CJcf, got %d", opcode); return False; } in_uint8(s, result); if (result != 0) { - error("CJrq: %d\n", result); + logger(Protocol, Error, "mcs_recv_cjcf(), expected result 0, got %d", result); return False; } @@ -255,6 +269,30 @@ return s_check_end(s); } + +/* Send MCS Disconnect provider ultimatum PDU */ +void +mcs_send_dpu(unsigned short reason) +{ + STREAM s, contents; + + logger(Protocol, Debug, "mcs_send_dpu(), reason=%d", reason); + + contents = s_alloc(6); + ber_out_integer(contents, reason); /* Reason */ + ber_out_sequence(contents, NULL); /* SEQUENCE OF NonStandradParameters OPTIONAL */ + s_mark_end(contents); + + s = iso_init(8); + ber_out_sequence(s, contents); + s_free(contents); + + s_mark_end(s); + + iso_send(s); + s_free(s); +} + /* Initialise an MCS transport data packet */ STREAM mcs_init(int length) @@ -295,24 +333,25 @@ /* Receive an MCS transport data packet */ STREAM -mcs_recv(uint16 * channel, uint8 * rdpver) +mcs_recv(uint16 * channel, RD_BOOL * is_fastpath, uint8 * fastpath_hdr) { uint8 opcode, appid, length; STREAM s; - s = iso_recv(rdpver); + s = iso_recv(is_fastpath, fastpath_hdr); if (s == NULL) return NULL; - if (rdpver != NULL) - if (*rdpver != 3) - return s; + + if (*is_fastpath == True) + return s; + in_uint8(s, opcode); appid = opcode >> 2; if (appid != MCS_SDIN) { if (appid != MCS_DPUM) { - error("expected data, got %d\n", opcode); + logger(Protocol, Error, "mcs_recv(), expected data, got %d", opcode); } return NULL; } @@ -329,6 +368,7 @@ mcs_connect_start(char *server, char *username, char *domain, char *password, RD_BOOL reconnect, uint32 * selected_protocol) { + logger(Protocol, Debug, "%s()", __func__); return iso_connect(server, username, domain, password, reconnect, selected_protocol); } @@ -337,6 +377,7 @@ { unsigned int i; + logger(Protocol, Debug, "%s()", __func__); mcs_send_connect_initial(mcs_data); if (!mcs_recv_connect_response(mcs_data)) goto error; @@ -371,8 +412,9 @@ /* Disconnect from the MCS layer */ void -mcs_disconnect(void) +mcs_disconnect(int reason) { + mcs_send_dpu(reason); iso_disconnect(); } diff -Nru rdesktop-1.8.6/mppc.c rdesktop-1.9.0/mppc.c --- rdesktop-1.8.6/mppc.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/mppc.c 2019-06-13 12:10:15.000000000 +0000 @@ -27,7 +27,7 @@ /* Contacts: */ -/* hifn contact mentioned in the faq is */ +/* hifn contact mentioned in the FAQ is */ /* Robert Friend rfriend at hifn dot com */ /* if you have questions regarding MPPC */ @@ -41,7 +41,7 @@ /* Algorithm: */ -/* as the rfc states the algorithm seems to */ +/* as the RFC states the algorithm seems to */ /* be LZ77 with a sliding buffer */ /* that is empty at init. */ @@ -349,9 +349,9 @@ } match_bits = match_len; - match_len = - ((walker >> (32 - match_bits)) & (~(-1 << match_bits))) | (1 << - match_bits); + match_len = (walker >> (32 - match_bits)); + match_len &= ((1 << match_bits) - 1); + match_len |= (1 << match_bits); walker <<= match_bits; walker_len -= match_bits; } diff -Nru rdesktop-1.8.6/orders.c rdesktop-1.9.0/orders.c --- rdesktop-1.8.6/orders.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/orders.c 2019-06-13 12:10:15.000000000 +0000 @@ -158,7 +158,8 @@ brush_data = cache_get_brush_data(colour_code, cache_idx); if ((brush_data == NULL) || (brush_data->data == NULL)) { - error("error getting brush data, style %x\n", out_brush->style); + logger(Graphics, Error, "setup_brush(), error getting brush data, style %x", + out_brush->style); out_brush->bd = NULL; memset(out_brush->pattern, 0, 8); } @@ -209,8 +210,8 @@ if (present & 0x10) in_uint8(s, os->opcode); - DEBUG(("DESTBLT(op=0x%x,x=%d,y=%d,cx=%d,cy=%d)\n", - os->opcode, os->x, os->y, os->cx, os->cy)); + logger(Graphics, Debug, "process_destblt(), op=0x%x, x=%d, y=%d, cx=%d, cy=%d", + os->opcode, os->x, os->y, os->cx, os->cy); ui_destblt(ROP2_S(os->opcode), os->x, os->y, os->cx, os->cy); } @@ -244,8 +245,10 @@ rdp_parse_brush(s, &os->brush, present >> 7); - DEBUG(("PATBLT(op=0x%x,x=%d,y=%d,cx=%d,cy=%d,bs=%d,bg=0x%x,fg=0x%x)\n", os->opcode, os->x, - os->y, os->cx, os->cy, os->brush.style, os->bgcolour, os->fgcolour)); + logger(Graphics, Debug, + "process_patblt(), op=0x%x, x=%d, y=%d, cx=%d, cy=%d, bs=%d, bg=0x%x, fg=0x%x)", + os->opcode, os->x, os->y, os->cx, os->cy, os->brush.style, os->bgcolour, + os->fgcolour); setup_brush(&brush, &os->brush); @@ -278,8 +281,9 @@ if (present & 0x0040) rdp_in_coord(s, &os->srcy, delta); - DEBUG(("SCREENBLT(op=0x%x,x=%d,y=%d,cx=%d,cy=%d,srcx=%d,srcy=%d)\n", - os->opcode, os->x, os->y, os->cx, os->cy, os->srcx, os->srcy)); + logger(Graphics, Debug, + "process_screenblt(), op=0x%x, x=%d, y=%d, cx=%d, cy=%d, srcx=%d, srcy=%d)", + os->opcode, os->x, os->y, os->cx, os->cy, os->srcx, os->srcy); ui_screenblt(ROP2_S(os->opcode), os->x, os->y, os->cx, os->cy, os->srcx, os->srcy); } @@ -311,12 +315,12 @@ rdp_parse_pen(s, &os->pen, present >> 7); - DEBUG(("LINE(op=0x%x,sx=%d,sy=%d,dx=%d,dy=%d,fg=0x%x)\n", - os->opcode, os->startx, os->starty, os->endx, os->endy, os->pen.colour)); + logger(Graphics, Debug, "process_line(), op=0x%x, sx=%d, sy=%d, dx=%d, dy=%d, fg=0x%x)", + os->opcode, os->startx, os->starty, os->endx, os->endy, os->pen.colour); if (os->opcode < 0x01 || os->opcode > 0x10) { - error("bad ROP2 0x%x\n", os->opcode); + logger(Graphics, Error, "process_line(), bad ROP2 0x%x", os->opcode); return; } @@ -358,7 +362,8 @@ os->colour = (os->colour & 0xff00ffff) | (i << 16); } - DEBUG(("RECT(x=%d,y=%d,cx=%d,cy=%d,fg=0x%x)\n", os->x, os->y, os->cx, os->cy, os->colour)); + logger(Graphics, Debug, "process_rect(), x=%d, y=%d, cx=%d, cy=%d, fg=0x%x", + os->x, os->y, os->cx, os->cy, os->colour); ui_rect(os->x, os->y, os->cx, os->cy, os->colour); } @@ -387,8 +392,8 @@ if (present & 0x20) in_uint8(s, os->action); - DEBUG(("DESKSAVE(l=%d,t=%d,r=%d,b=%d,off=%d,op=%d)\n", - os->left, os->top, os->right, os->bottom, os->offset, os->action)); + logger(Graphics, Debug, "process_desksave(), l=%d, t=%d, r=%d, b=%d, off=%d, op=%d", + os->left, os->top, os->right, os->bottom, os->offset, os->action); width = os->right - os->left + 1; height = os->bottom - os->top + 1; @@ -435,8 +440,9 @@ if (present & 0x0100) in_uint16_le(s, os->cache_idx); - DEBUG(("MEMBLT(op=0x%x,x=%d,y=%d,cx=%d,cy=%d,id=%d,idx=%d)\n", - os->opcode, os->x, os->y, os->cx, os->cy, os->cache_id, os->cache_idx)); + logger(Graphics, Debug, + "process_memblt(), op=0x%x, x=%d, y=%d, cx=%d, cy=%d, id=%d, idx=%d", os->opcode, + os->x, os->y, os->cx, os->cy, os->cache_id, os->cache_idx); bitmap = cache_get_bitmap(os->cache_id, os->cache_idx); if (bitmap == NULL) @@ -493,9 +499,10 @@ if (present & 0x010000) in_uint16_le(s, os->unknown); - DEBUG(("TRIBLT(op=0x%x,x=%d,y=%d,cx=%d,cy=%d,id=%d,idx=%d,bs=%d,bg=0x%x,fg=0x%x)\n", + logger(Graphics, Debug, + "process_triblt(), op=0x%x, x=%d, y=%d, cx=%d, cy=%d, id=%d, idx=%d, bs=%d, bg=0x%x, fg=0x%x", os->opcode, os->x, os->y, os->cx, os->cy, os->cache_id, os->cache_idx, - os->brush.style, os->bgcolour, os->fgcolour)); + os->brush.style, os->bgcolour, os->fgcolour); bitmap = cache_get_bitmap(os->cache_id, os->cache_idx); if (bitmap == NULL) @@ -539,19 +546,13 @@ in_uint8a(s, os->data, os->datasize); } - DEBUG(("POLYGON(x=%d,y=%d,op=0x%x,fm=%d,fg=0x%x,n=%d,sz=%d)\n", - os->x, os->y, os->opcode, os->fillmode, os->fgcolour, os->npoints, os->datasize)); - - DEBUG(("Data: ")); - - for (index = 0; index < os->datasize; index++) - DEBUG(("%02x ", os->data[index])); - - DEBUG(("\n")); + logger(Graphics, Debug, + "process_polygon(), x=%d, y=%d, op=0x%x, fm=%d, fg=0x%x, n=%d, sz=%d", os->x, os->y, + os->opcode, os->fillmode, os->fgcolour, os->npoints, os->datasize); if (os->opcode < 0x01 || os->opcode > 0x10) { - error("bad ROP2 0x%x\n", os->opcode); + logger(Graphics, Error, "process_polygon(), bad ROP2 0x%x", os->opcode); return; } @@ -581,7 +582,7 @@ ui_polygon(os->opcode - 1, os->fillmode, points, os->npoints + 1, NULL, 0, os->fgcolour); else - error("polygon parse error\n"); + logger(Graphics, Error, "process_polygon(), polygon parse error"); xfree(points); } @@ -624,20 +625,14 @@ in_uint8a(s, os->data, os->datasize); } - DEBUG(("POLYGON2(x=%d,y=%d,op=0x%x,fm=%d,bs=%d,bg=0x%x,fg=0x%x,n=%d,sz=%d)\n", + logger(Graphics, Debug, + "process_polygon2(), x=%d, y=%d, op=0x%x, fm=%d, bs=%d, bg=0x%x, fg=0x%x, n=%d, sz=%d)", os->x, os->y, os->opcode, os->fillmode, os->brush.style, os->bgcolour, os->fgcolour, - os->npoints, os->datasize)); - - DEBUG(("Data: ")); - - for (index = 0; index < os->datasize; index++) - DEBUG(("%02x ", os->data[index])); - - DEBUG(("\n")); + os->npoints, os->datasize); if (os->opcode < 0x01 || os->opcode > 0x10) { - error("bad ROP2 0x%x\n", os->opcode); + logger(Graphics, Error, "process_polygon2(), bad ROP2 0x%x", os->opcode); return; } @@ -669,7 +664,7 @@ ui_polygon(os->opcode - 1, os->fillmode, points, os->npoints + 1, &brush, os->bgcolour, os->fgcolour); else - error("polygon2 parse error\n"); + logger(Graphics, Error, "process_polygon2(), polygon parse error"); xfree(points); } @@ -704,19 +699,12 @@ in_uint8a(s, os->data, os->datasize); } - DEBUG(("POLYLINE(x=%d,y=%d,op=0x%x,fg=0x%x,n=%d,sz=%d)\n", - os->x, os->y, os->opcode, os->fgcolour, os->lines, os->datasize)); - - DEBUG(("Data: ")); - - for (index = 0; index < os->datasize; index++) - DEBUG(("%02x ", os->data[index])); - - DEBUG(("\n")); + logger(Graphics, Debug, "process_polyline(), x=%d, y=%d, op=0x%x, fg=0x%x, n=%d, sz=%d)", + os->x, os->y, os->opcode, os->fgcolour, os->lines, os->datasize); if (os->opcode < 0x01 || os->opcode > 0x10) { - error("bad ROP2 0x%x\n", os->opcode); + logger(Graphics, Error, "process_polyline(), bad ROP2 0x%x", os->opcode); return; } @@ -747,7 +735,7 @@ if (next - 1 == os->lines) ui_polyline(os->opcode - 1, points, os->lines + 1, &pen); else - error("polyline parse error\n"); + logger(Graphics, Error, "process_polyline(), parse error"); xfree(points); } @@ -777,8 +765,9 @@ if (present & 0x40) rdp_in_colour(s, &os->fgcolour); - 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)); + logger(Graphics, Debug, + "process_ellipse(), l=%d, t=%d, r=%d, b=%d, op=0x%x, fm=%d, fg=0x%x", 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, os->bottom - os->top, NULL, 0, os->fgcolour); @@ -816,9 +805,10 @@ rdp_parse_brush(s, &os->brush, present >> 8); - DEBUG(("ELLIPSE2(l=%d,t=%d,r=%d,b=%d,op=0x%x,fm=%d,bs=%d,bg=0x%x,fg=0x%x)\n", + logger(Graphics, Debug, + "process_ellipse2(), l=%d, t=%d, r=%d, b=%d, op=0x%x, fm=%d, bs=%d, bg=0x%x, fg=0x%x", os->left, os->top, os->right, os->bottom, os->opcode, os->fillmode, os->brush.style, - os->bgcolour, os->fgcolour)); + os->bgcolour, os->fgcolour); setup_brush(&brush, &os->brush); @@ -830,7 +820,7 @@ static void process_text2(STREAM s, TEXT2_ORDER * os, uint32 present, RD_BOOL delta) { - int i; + UNUSED(delta); BRUSH brush; if (present & 0x000001) @@ -889,14 +879,11 @@ in_uint8a(s, os->text, os->length); } - DEBUG(("TEXT2(x=%d,y=%d,cl=%d,ct=%d,cr=%d,cb=%d,bl=%d,bt=%d,br=%d,bb=%d,bs=%d,bg=0x%x,fg=0x%x,font=%d,fl=0x%x,op=0x%x,mix=%d,n=%d)\n", os->x, os->y, os->clipleft, os->cliptop, os->clipright, os->clipbottom, os->boxleft, os->boxtop, os->boxright, os->boxbottom, os->brush.style, os->bgcolour, os->fgcolour, os->font, os->flags, os->opcode, os->mixmode, os->length)); - - DEBUG(("Text: ")); - - for (i = 0; i < os->length; i++) - DEBUG(("%02x ", os->text[i])); - - DEBUG(("\n")); + logger(Graphics, Debug, + "process_text2(), x=%d, y=%d, cl=%d, ct=%d, cr=%d, cb=%d, bl=%d, bt=%d, br=%d, bb=%d, bs=%d, bg=0x%x, fg=0x%x, font=%d, fl=0x%x, op=0x%x, mix=%d, n=%d", + os->x, os->y, os->clipleft, os->cliptop, os->clipright, os->clipbottom, os->boxleft, + os->boxtop, os->boxright, os->boxbottom, os->brush.style, os->bgcolour, os->fgcolour, + os->font, os->flags, os->opcode, os->mixmode, os->length); setup_brush(&brush, &os->brush); @@ -927,7 +914,8 @@ in_uint16_le(s, cache_idx); in_uint8p(s, data, bufsize); - DEBUG(("RAW_BMPCACHE(cx=%d,cy=%d,id=%d,idx=%d)\n", width, height, cache_id, cache_idx)); + logger(Graphics, Debug, "process_raw_bpmcache(), cx=%d, cy=%d, id=%d, idx=%d", width, + height, cache_id, cache_idx); inverted = (uint8 *) xmalloc(width * height * Bpp); for (y = 0; y < height; y++) { @@ -978,8 +966,10 @@ } in_uint8p(s, data, size); - - 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)); + logger(Graphics, Debug, + "process_bmpcache(), cx=%d, cy=%d, id=%d, idx=%d, bpp=%d, size=%d, pad1=%d, bufsize=%d, pad2=%d, rs=%d, fs=%d", + width, height, cache_id, cache_idx, bpp, size, pad1, bufsize, pad2, row_size, + final_size); bmpdata = (uint8 *) xmalloc(width * height * Bpp); @@ -990,7 +980,7 @@ } else { - DEBUG(("Failed to decompress bitmap data\n")); + logger(Graphics, Error, "process_bmpcache(), Failed to decompress bitmap data"); } xfree(bmpdata); @@ -1038,8 +1028,9 @@ in_uint8p(s, data, bufsize); - 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)); + logger(Graphics, Debug, + "process_bmpcache2(), compr=%d, flags=%x, cx=%d, cy=%d, id=%d, idx=%d, Bpp=%d, bs=%d", + compressed, flags, width, height, cache_id, cache_idx, Bpp, bufsize); bmpdata = (uint8 *) xmalloc(width * height * Bpp); @@ -1047,7 +1038,8 @@ { if (!bitmap_decompress(bmpdata, width, height, data, bufsize, Bpp)) { - DEBUG(("Failed to decompress bitmap data\n")); + logger(Graphics, Error, + "process_bmpcache2(), failed to decompress bitmap data"); xfree(bmpdata); return; } @@ -1070,7 +1062,7 @@ } else { - DEBUG(("process_bmpcache2: ui_create_bitmap failed\n")); + logger(Graphics, Error, "process_bmpcache2(), ui_create_bitmap(), failed"); } xfree(bmpdata); @@ -1100,7 +1092,7 @@ in_uint8s(s, 1); /* pad */ } - DEBUG(("COLCACHE(id=%d,n=%d)\n", cache_id, map.ncolours)); + logger(Graphics, Debug, "process_colcache(), id=%d, n=%d", cache_id, map.ncolours); hmap = ui_create_colourmap(&map); @@ -1123,7 +1115,7 @@ in_uint8(s, font); in_uint8(s, nglyphs); - DEBUG(("FONTCACHE(font=%d,n=%d)\n", font, nglyphs)); + logger(Graphics, Debug, "process_fontcache(), font=%d, n=%d", font, nglyphs); for (i = 0; i < nglyphs; i++) { @@ -1178,6 +1170,7 @@ static void process_brushcache(STREAM s, uint16 flags) { + UNUSED(flags); BRUSHDATA brush_data; uint8 cache_idx, colour_code, width, height, size, type; uint8 *comp_brush; @@ -1191,7 +1184,8 @@ in_uint8(s, type); /* type, 0x8x = cached */ in_uint8(s, size); - DEBUG(("BRUSHCACHE(idx=%d,wd=%d,ht=%d,sz=%d)\n", cache_idx, width, height, size)); + logger(Graphics, Debug, "process_brushcache(), idx=%d, wd=%d, ht=%d, type=0x%x sz=%d", + cache_idx, width, height, type, size); if ((width == 8) && (height == 8)) { @@ -1210,8 +1204,9 @@ } else { - warning("incompatible brush, colour_code %d size %d\n", colour_code, - size); + logger(Graphics, Warning, + "process_brushcache(), incompatible brush, colour_code %d size %d", + colour_code, size); } cache_put_brush_data(1, cache_idx, &brush_data); } @@ -1234,12 +1229,16 @@ } else { - warning("incompatible brush, colour_code %d size %d\n", colour_code, size); + logger(Graphics, Warning, + "process_brushcache(), incompatible brush, colour_code %d size %d", + colour_code, size); } } else { - warning("incompatible brush, width height %d %d\n", width, height); + logger(Graphics, Warning, + "process_brushcache(), incompatible brush, width height %d %d", width, + height); } } @@ -1250,7 +1249,7 @@ /* The length isn't calculated correctly by the server. * For very compact orders the length becomes negative * so a signed integer must be used. */ - uint16 length; + sint16 length; uint16 flags; uint8 type; size_t next_order; @@ -1260,12 +1259,17 @@ in_uint16_le(s, flags); /* used by bmpcache2 */ in_uint8(s, type); - if (!s_check_rem(s, length + 7)) + length += 13; /* MS-RDPEGDI is ridiculous and says that you need to add 13 to this + field to get the total packet length. "For historical reasons". */ + length -= 6; /* Subtract six bytes of headers and you'll get the size of the remaining + order data. */ + + if (!s_check_rem(s, length)) { rdp_protocol_error("next order pointer would overrun stream", &packet); } - next_order = s_tell(s) + length + 7; + next_order = s_tell(s) + length; switch (type) { @@ -1298,7 +1302,8 @@ break; default: - unimpl("secondary order %d\n", type); + logger(Graphics, Warning, + "process_secondary_order(), unhandled secondary order %d", type); } s_seek(s, next_order); @@ -1320,7 +1325,7 @@ if (!(order_flags & RDP_ORDER_STANDARD)) { - error("order parsing failed\n"); + logger(Graphics, Error, "process_orders(), order parsing failed"); break; } @@ -1429,7 +1434,9 @@ break; default: - unimpl("order %d\n", os->order_type); + logger(Graphics, Warning, + "process_orders(), unhandled order type %d", + os->order_type); return; } @@ -1442,7 +1449,8 @@ #if 0 /* not true when RDP_COMPRESSION is set */ if (s_tell(s) != g_next_packet) - error("%d bytes remaining\n", (int) (g_next_packet - s_tell(s))); + logger(Graphics, Error, "process_orders(), %d bytes remaining", + (int) (g_next_packet - s_tell(s))); #endif } diff -Nru rdesktop-1.8.6/parallel.c rdesktop-1.9.0/parallel.c --- rdesktop-1.8.6/parallel.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/parallel.c 2019-06-13 12:10:15.000000000 +0000 @@ -35,7 +35,7 @@ /* Enumeration of devices from rdesktop.c */ -/* returns numer of units found and initialized. */ +/* returns number of units found and initialized. */ /* optarg looks like ':LPT1=/dev/lp0' */ /* when it arrives to this function. */ int @@ -60,7 +60,7 @@ g_rdpdr_device[*id].local_path = xmalloc(strlen(pos2) + 1); strcpy(g_rdpdr_device[*id].local_path, pos2); - printf("PARALLEL %s to %s\n", optarg, pos2); + logger(Core, Debug, "parallel_enum_devices(), %s to %s", optarg, pos2); /* set device type */ g_rdpdr_device[*id].device_type = DEVICE_TYPE_PARALLEL; @@ -78,18 +78,23 @@ parallel_create(uint32 device_id, uint32 access, uint32 share_mode, uint32 disposition, uint32 flags, char *filename, RD_NTHANDLE * handle) { + UNUSED(access); + UNUSED(share_mode); + UNUSED(disposition); + UNUSED(flags); + UNUSED(filename); int parallel_fd; parallel_fd = open(g_rdpdr_device[device_id].local_path, O_RDWR); if (parallel_fd == -1) { - perror("open"); + logger(Core, Error, "parallel_create(), open failed: %s", strerror(errno)); return RD_STATUS_ACCESS_DENIED; } /* all read and writes should be non blocking */ if (fcntl(parallel_fd, F_SETFL, O_NONBLOCK) == -1) - perror("fcntl"); + logger(Core, Error, "parallel_create(), fcntl failed: %s", strerror(errno)); #if defined(LPABORT) /* Retry on errors */ @@ -114,15 +119,17 @@ } static RD_NTSTATUS -parallel_read(RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result) +parallel_read(RD_NTHANDLE handle, uint8 * data, uint32 length, uint64 offset, uint32 * result) { + UNUSED(offset); /* Offset must always be zero according to MS-RDPESP */ *result = read(handle, data, length); return RD_STATUS_SUCCESS; } static RD_NTSTATUS -parallel_write(RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result) +parallel_write(RD_NTHANDLE handle, uint8 * data, uint32 length, uint64 offset, uint32 * result) { + UNUSED(offset); /* Offset must always be zero according to MS-RDPESP */ int rc = RD_STATUS_SUCCESS; int n = write(handle, data, length); @@ -137,18 +144,21 @@ { case EAGAIN: rc = RD_STATUS_DEVICE_OFF_LINE; + break; case ENOSPC: rc = RD_STATUS_DEVICE_PAPER_EMPTY; + break; case EIO: rc = RD_STATUS_DEVICE_OFF_LINE; + break; default: rc = RD_STATUS_DEVICE_POWERED_OFF; + break; } #if defined(LPGETSTATUS) if (ioctl(handle, LPGETSTATUS, &status) == 0) { - /* coming soon: take care for the printer status */ - printf("parallel_write: status = %d, errno = %d\n", status, errno); + logger(Core, Error, "parellel_write(), ioctl failed: %s", strerror(errno)); } #endif } @@ -159,6 +169,9 @@ static RD_NTSTATUS parallel_device_control(RD_NTHANDLE handle, uint32 request, STREAM in, STREAM out) { + UNUSED(handle); + UNUSED(in); + UNUSED(out); if ((request >> 16) != FILE_DEVICE_PARALLEL) return RD_STATUS_INVALID_PARAMETER; @@ -166,16 +179,15 @@ request >>= 2; request &= 0xfff; - printf("PARALLEL IOCTL %d: ", request); + logger(Protocol, Debug, "parallel_device_control(), ioctl %d", request); switch (request) { case IOCTL_PAR_QUERY_RAW_DEVICE_ID: default: - - printf("\n"); - unimpl("UNKNOWN IOCTL %d\n", request); + logger(Protocol, Warning, "parallel_device_control(), unhandled ioctl %d", + request); } return RD_STATUS_SUCCESS; } diff -Nru rdesktop-1.8.6/parse.c rdesktop-1.9.0/parse.c --- rdesktop-1.8.6/parse.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/parse.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,88 +0,0 @@ -/* - rdesktop: A Remote Desktop Protocol client. - Parsing primitives - Copyright 2017 Henrik Andersson <hean01@cendio.se> for Cendio AB - - 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 3 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, see <http://www.gnu.org/licenses/>. -*/ - -#include <stdlib.h> -#include "rdesktop.h" - -#include "parse.h" - -STREAM -s_alloc(unsigned int size) -{ - STREAM s; - - s = xmalloc(sizeof(struct stream)); - memset(s, 0, sizeof(struct stream)); - s_realloc(s, size); - - return s; -} - -STREAM -s_inherit(unsigned char *data, unsigned int size) -{ - STREAM s; - - s = xmalloc(sizeof(struct stream)); - memset(s, 0, sizeof(struct stream)); - s->p = s->data = data; - s->size = size; - - return s; -} - -void -s_realloc(STREAM s, unsigned int size) -{ - unsigned char *data; - - if (s->size >= size) - return; - - data = s->data; - s->size = size; - s->data = xrealloc(data, size); - s->p = s->data + (s->p - data); - s->end = s->data + (s->end - data); - s->iso_hdr = s->data + (s->iso_hdr - data); - s->mcs_hdr = s->data + (s->mcs_hdr - data); - s->sec_hdr = s->data + (s->sec_hdr - data); - s->rdp_hdr = s->data + (s->rdp_hdr - data); - s->channel_hdr = s->data + (s->channel_hdr - data); -} - -void -s_reset(STREAM s) -{ - struct stream tmp; - tmp = *s; - memset(s, 0, sizeof(struct stream)); - s->size = tmp.size; - s->end = s->p = s->data = tmp.data; -} - - -void -s_free(STREAM s) -{ - if (s == NULL) - return; - free(s->data); - free(s); -} diff -Nru rdesktop-1.8.6/parse.h rdesktop-1.9.0/parse.h --- rdesktop-1.8.6/parse.h 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/parse.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,138 +0,0 @@ -/* - rdesktop: A Remote Desktop Protocol client. - Parsing primitives - Copyright (C) Matthew Chapman 1999-2008 - Copyright 2012-2017 Henrik Andersson <hean01@cendio.se> for Cendio AB - - 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 3 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, see <http://www.gnu.org/licenses/>. -*/ - -#ifndef _PARSE_H -#define _PARSE_H - -/* Parser state */ -typedef struct stream -{ - unsigned char *p; - unsigned char *end; - unsigned char *data; - unsigned int size; - - /* Offsets of various headers */ - unsigned char *iso_hdr; - unsigned char *mcs_hdr; - unsigned char *sec_hdr; - unsigned char *rdp_hdr; - unsigned char *channel_hdr; - -} - *STREAM; - -/* Return a newly allocated STREAM object of the specified size */ -STREAM s_alloc(unsigned int size); -/* Wrap an existing buffer in a STREAM object, transferring ownership */ -STREAM s_inherit(unsigned char *data, unsigned int size); -/* Resize an existing STREAM object, keeping all data and offsets intact */ -void s_realloc(STREAM s, unsigned int size); -/* Free STREAM object and its associated buffer */ -void s_free(STREAM s); -/* Reset all internal offsets, but keep the allocated size */ -void s_reset(STREAM s); - -#define s_push_layer(s,h,n) { (s)->h = (s)->p; (s)->p += n; } -#define s_pop_layer(s,h) (s)->p = (s)->h; -#define s_mark_end(s) (s)->end = (s)->p; -/* Return current read offset in the STREAM */ -#define s_tell(s) (size_t)((s)->p - (s)->data) -/* Set current read offset in the STREAM */ -#define s_seek(s,o) (s)->p = (s)->data; s_assert_r(s,o); (s)->p += o; -/* Returns number of bytes that can still be read from STREAM */ -#define s_remaining(s) (size_t)((s)->end - (s)->p) -#define s_check_rem(s,n) (((s)->p <= (s)->end) && ((size_t)n <= s_remaining(s))) -#define s_check_end(s) ((s)->p == (s)->end) -#define s_length(s) ((s)->end - (s)->data) -#define s_left(s) ((s)->size - (size_t)((s)->p - (s)->data)) - -/* Verify that there is enough data/space before accessing a STREAM */ -#define s_assert_r(s,n) { if (!s_check_rem(s, n)) rdp_protocol_error( "unexpected stream overrun", s); } -#define s_assert_w(s,n) { if (s_left(s) < (size_t)n) { error("%s:%d: %s(), %s", __FILE__, __LINE__, __func__, "unexpected stream overrun"); exit(0); } } - -#if defined(L_ENDIAN) && !defined(NEED_ALIGN) -#define in_uint16_le(s,v) { s_assert_r(s, 2); v = *(uint16 *)((s)->p); (s)->p += 2; } -#define in_uint32_le(s,v) { s_assert_r(s, 4); v = *(uint32 *)((s)->p); (s)->p += 4; } -#define out_uint16_le(s,v) { s_assert_w(s, 2); *(uint16 *)((s)->p) = v; (s)->p += 2; } -#define out_uint32_le(s,v) { s_assert_w(s, 4); *(uint32 *)((s)->p) = v; (s)->p += 4; } - -#else -#define in_uint16_le(s,v) { s_assert_r(s, 2); v = *((s)->p++); v += *((s)->p++) << 8; } -#define in_uint32_le(s,v) { s_assert_r(s, 4); in_uint16_le(s,v) \ - v += *((s)->p++) << 16; v += *((s)->p++) << 24; } -#define out_uint16_le(s,v) { s_assert_w(s, 2); *((s)->p++) = (v) & 0xff; *((s)->p++) = ((v) >> 8) & 0xff; } -#define out_uint32_le(s,v) { s_assert_w(s, 4); out_uint16_le(s, (v) & 0xffff); out_uint16_le(s, ((v) >> 16) & 0xffff); } -#endif - -#if defined(B_ENDIAN) && !defined(NEED_ALIGN) -#define in_uint16_be(s,v) { s_assert_r(s, 2); v = *(uint16 *)((s)->p); (s)->p += 2; } -#define in_uint32_be(s,v) { s_assert_r(s, 4); v = *(uint32 *)((s)->p); (s)->p += 4; } -#define out_uint16_be(s,v) { s_assert_w(s, 2); *(uint16 *)((s)->p) = v; (s)->p += 2; } -#define out_uint32_be(s,v) { s_assert_w(s, 4); *(uint32 *)((s)->p) = v; (s)->p += 4; } - -#define B_ENDIAN_PREFERRED -#define in_uint16(s,v) in_uint16_be(s,v) -#define in_uint32(s,v) in_uint32_be(s,v) -#define out_uint16(s,v) out_uint16_be(s,v) -#define out_uint32(s,v) out_uint32_be(s,v) - -#else -#define in_uint16_be(s,v) { s_assert_r(s, 2); v = *((s)->p++); next_be(s,v); } -#define in_uint32_be(s,v) { s_assert_r(s, 4); in_uint16_be(s,v); next_be(s,v); next_be(s,v); } -#define out_uint16_be(s,v) { s_assert_w(s, 2); *((s)->p++) = ((v) >> 8) & 0xff; *((s)->p++) = (v) & 0xff; } -#define out_uint32_be(s,v) { s_assert_w(s, 4); out_uint16_be(s, ((v) >> 16) & 0xffff); out_uint16_be(s, (v) & 0xffff); } -#endif - -#ifndef B_ENDIAN_PREFERRED -#define in_uint16(s,v) in_uint16_le(s,v) -#define in_uint32(s,v) in_uint32_le(s,v) -#define out_uint16(s,v) out_uint16_le(s,v) -#define out_uint32(s,v) out_uint32_le(s,v) -#endif - -#define in_uint8(s,v) { s_assert_r(s, 1); v = *((s)->p++); } -/* Return a pointer in v to manually read n bytes from STREAM s */ -#define in_uint8p(s,v,n) { s_assert_r(s, n); v = (s)->p; (s)->p += n; } -/* Copy n bytes from STREAM s in to array v */ -#define in_uint8a(s,v,n) { s_assert_r(s, n); memcpy(v,(s)->p,n); (s)->p += n; } -#define in_uint8s(s,n) { s_assert_r(s, n); (s)->p += n; } -#define out_uint8(s,v) { s_assert_w(s, 1); *((s)->p++) = v; } -/* Return a pointer in v to manually fill in n bytes in STREAM s */ -#define out_uint8p(s,v,n) { s_assert_w(s, n); v = (s)->p; (s)->p += n; } -/* Copy n bytes from array v in to STREAM s */ -#define out_uint8a(s,v,n) { s_assert_w(s, n); memcpy((s)->p,v,n); (s)->p += n; } -#define out_uint8s(s,n) { s_assert_w(s, n); memset((s)->p,0,n); (s)->p += n; } - -/* Copy n bytes from STREAM s in to STREAM v */ -#define in_uint8stream(s,v,n) { s_assert_r(s, n); out_uint8a((v), (s)->p, n); (s)->p += n; } -/* Copy n bytes in to STREAM s from STREAM v */ -#define out_uint8stream(s,v,n) in_uint8stream(v,s,n) - -/* Copy the entire STREAM v (ignoring offsets) in to STREAM s */ -#define out_stream(s, v) out_uint8a(s, (v)->data, s_length((v))) - -/* Return a pointer in v to manually modify n bytes of STREAM s in place */ -#define inout_uint8p(s,v,n) { s_assert_r(s, n); s_assert_w(s, n); v = (s)->p; (s)->p += n; } - -#define next_be(s,v) { s_assert_r(s, 1); v = ((v) << 8) + *((s)->p++); } - - -#endif /* _PARSE_H */ diff -Nru rdesktop-1.8.6/pkix_asn1_tab.c rdesktop-1.9.0/pkix_asn1_tab.c --- rdesktop-1.8.6/pkix_asn1_tab.c 1970-01-01 00:00:00.000000000 +0000 +++ rdesktop-1.9.0/pkix_asn1_tab.c 2019-06-13 12:10:15.000000000 +0000 @@ -0,0 +1,920 @@ +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include <libtasn1.h> + +const asn1_static_node pkix_asn1_tab[] = { + { "PKIX1Implicit88", 536875024, NULL }, + { NULL, 1610612748, NULL }, + { "iso", 1073741825, "1"}, + { "identified-organization", 1073741825, "3"}, + { "dod", 1073741825, "6"}, + { "internet", 1073741825, "1"}, + { "security", 1073741825, "5"}, + { "mechanisms", 1073741825, "5"}, + { "pkix", 1073741825, "7"}, + { "id-mod", 1073741825, "0"}, + { "id-pkix1-implicit-88", 1, "2"}, + { "id-ce", 1879048204, NULL }, + { "joint-iso-ccitt", 1073741825, "2"}, + { "ds", 1073741825, "5"}, + { NULL, 1, "29"}, + { "id-ce-authorityKeyIdentifier", 1879048204, NULL }, + { NULL, 1073741825, "id-ce"}, + { NULL, 1, "35"}, + { "AuthorityKeyIdentifier", 1610612741, NULL }, + { "keyIdentifier", 1610637314, "KeyIdentifier"}, + { NULL, 4104, "0"}, + { "authorityCertIssuer", 1610637314, "GeneralNames"}, + { NULL, 4104, "1"}, + { "authorityCertSerialNumber", 536895490, "CertificateSerialNumber"}, + { NULL, 4104, "2"}, + { "KeyIdentifier", 1073741831, NULL }, + { "id-ce-subjectKeyIdentifier", 1879048204, NULL }, + { NULL, 1073741825, "id-ce"}, + { NULL, 1, "14"}, + { "SubjectKeyIdentifier", 1073741826, "KeyIdentifier"}, + { "id-ce-keyUsage", 1879048204, NULL }, + { NULL, 1073741825, "id-ce"}, + { NULL, 1, "15"}, + { "KeyUsage", 1610874886, NULL }, + { "digitalSignature", 1073741825, "0"}, + { "nonRepudiation", 1073741825, "1"}, + { "keyEncipherment", 1073741825, "2"}, + { "dataEncipherment", 1073741825, "3"}, + { "keyAgreement", 1073741825, "4"}, + { "keyCertSign", 1073741825, "5"}, + { "cRLSign", 1073741825, "6"}, + { "encipherOnly", 1073741825, "7"}, + { "decipherOnly", 1, "8"}, + { "id-ce-privateKeyUsagePeriod", 1879048204, NULL }, + { NULL, 1073741825, "id-ce"}, + { NULL, 1, "16"}, + { "PrivateKeyUsagePeriod", 1610612741, NULL }, + { "notBefore", 1610637349, NULL }, + { NULL, 4104, "0"}, + { "notAfter", 536895525, NULL }, + { NULL, 4104, "1"}, + { "id-ce-certificatePolicies", 1879048204, NULL }, + { NULL, 1073741825, "id-ce"}, + { NULL, 1, "32"}, + { "CertificatePolicies", 1612709899, NULL }, + { "MAX", 1074266122, "1"}, + { NULL, 2, "PolicyInformation"}, + { "PolicyInformation", 1610612741, NULL }, + { "policyIdentifier", 1073741826, "CertPolicyId"}, + { "policyQualifiers", 538984459, NULL }, + { "MAX", 1074266122, "1"}, + { NULL, 2, "PolicyQualifierInfo"}, + { "CertPolicyId", 1073741836, NULL }, + { "PolicyQualifierInfo", 1610612741, NULL }, + { "policyQualifierId", 1073741826, "PolicyQualifierId"}, + { "qualifier", 541065229, NULL }, + { "policyQualifierId", 1, NULL }, + { "PolicyQualifierId", 1073741836, NULL }, + { "CPSuri", 1073741853, NULL }, + { "UserNotice", 1610612741, NULL }, + { "noticeRef", 1073758210, "NoticeReference"}, + { "explicitText", 16386, "DisplayText"}, + { "NoticeReference", 1610612741, NULL }, + { "organization", 1073741826, "DisplayText"}, + { "noticeNumbers", 536870923, NULL }, + { NULL, 3, NULL }, + { "DisplayText", 1610612754, NULL }, + { "visibleString", 1612709923, NULL }, + { "200", 524298, "1"}, + { "bmpString", 1612709921, NULL }, + { "200", 524298, "1"}, + { "utf8String", 538968098, NULL }, + { "200", 524298, "1"}, + { "id-ce-policyMappings", 1879048204, NULL }, + { NULL, 1073741825, "id-ce"}, + { NULL, 1, "33"}, + { "PolicyMappings", 1612709899, NULL }, + { "MAX", 1074266122, "1"}, + { NULL, 536870917, NULL }, + { "issuerDomainPolicy", 1073741826, "CertPolicyId"}, + { "subjectDomainPolicy", 2, "CertPolicyId"}, + { "id-ce-subjectAltName", 1879048204, NULL }, + { NULL, 1073741825, "id-ce"}, + { NULL, 1, "17"}, + { "SubjectAltName", 1073741826, "GeneralNames"}, + { "GeneralNames", 1612709899, NULL }, + { "MAX", 1074266122, "1"}, + { NULL, 2, "GeneralName"}, + { "GeneralName", 1610612754, NULL }, + { "otherName", 1610620930, "AnotherName"}, + { NULL, 4104, "0"}, + { "rfc822Name", 1610620957, NULL }, + { NULL, 4104, "1"}, + { "dNSName", 1610620957, NULL }, + { NULL, 4104, "2"}, + { "x400Address", 1610620930, "ORAddress"}, + { NULL, 4104, "3"}, + { "directoryName", 1610620930, "Name"}, + { NULL, 4104, "4"}, + { "ediPartyName", 1610620930, "EDIPartyName"}, + { NULL, 4104, "5"}, + { "uniformResourceIdentifier", 1610620957, NULL }, + { NULL, 4104, "6"}, + { "iPAddress", 1610620935, NULL }, + { NULL, 4104, "7"}, + { "registeredID", 536879116, NULL }, + { NULL, 4104, "8"}, + { "AnotherName", 1610612741, NULL }, + { "type-id", 1073741836, NULL }, + { "value", 541073421, NULL }, + { NULL, 1073743880, "0"}, + { "type-id", 1, NULL }, + { "EDIPartyName", 1610612741, NULL }, + { "nameAssigner", 1610637314, "DirectoryString"}, + { NULL, 4104, "0"}, + { "partyName", 536879106, "DirectoryString"}, + { NULL, 4104, "1"}, + { "id-ce-issuerAltName", 1879048204, NULL }, + { NULL, 1073741825, "id-ce"}, + { NULL, 1, "18"}, + { "IssuerAltName", 1073741826, "GeneralNames"}, + { "id-ce-subjectDirectoryAttributes", 1879048204, NULL }, + { NULL, 1073741825, "id-ce"}, + { NULL, 1, "9"}, + { "SubjectDirectoryAttributes", 1612709899, NULL }, + { "MAX", 1074266122, "1"}, + { NULL, 2, "Attribute"}, + { "id-ce-basicConstraints", 1879048204, NULL }, + { NULL, 1073741825, "id-ce"}, + { NULL, 1, "19"}, + { "BasicConstraints", 1610612741, NULL }, + { "cA", 1610645508, NULL }, + { NULL, 131081, NULL }, + { "pathLenConstraint", 537411587, NULL }, + { "0", 10, "MAX"}, + { "id-ce-nameConstraints", 1879048204, NULL }, + { NULL, 1073741825, "id-ce"}, + { NULL, 1, "30"}, + { "NameConstraints", 1610612741, NULL }, + { "permittedSubtrees", 1610637314, "GeneralSubtrees"}, + { NULL, 4104, "0"}, + { "excludedSubtrees", 536895490, "GeneralSubtrees"}, + { NULL, 4104, "1"}, + { "GeneralSubtrees", 1612709899, NULL }, + { "MAX", 1074266122, "1"}, + { NULL, 2, "GeneralSubtree"}, + { "GeneralSubtree", 1610612741, NULL }, + { "base", 1073741826, "GeneralName"}, + { "minimum", 1610653698, "BaseDistance"}, + { NULL, 1073741833, "0"}, + { NULL, 4104, "0"}, + { "maximum", 536895490, "BaseDistance"}, + { NULL, 4104, "1"}, + { "BaseDistance", 1611137027, NULL }, + { "0", 10, "MAX"}, + { "id-ce-policyConstraints", 1879048204, NULL }, + { NULL, 1073741825, "id-ce"}, + { NULL, 1, "36"}, + { "PolicyConstraints", 1610612741, NULL }, + { "requireExplicitPolicy", 1610637314, "SkipCerts"}, + { NULL, 4104, "0"}, + { "inhibitPolicyMapping", 536895490, "SkipCerts"}, + { NULL, 4104, "1"}, + { "SkipCerts", 1611137027, NULL }, + { "0", 10, "MAX"}, + { "id-ce-cRLDistributionPoints", 1879048204, NULL }, + { NULL, 1073741825, "id-ce"}, + { NULL, 1, "31"}, + { "CRLDistPointsSyntax", 1612709899, NULL }, + { "MAX", 1074266122, "1"}, + { NULL, 2, "DistributionPoint"}, + { "DistributionPoint", 1610612741, NULL }, + { "distributionPoint", 1610637314, "DistributionPointName"}, + { NULL, 4104, "0"}, + { "reasons", 1610637314, "ReasonFlags"}, + { NULL, 4104, "1"}, + { "cRLIssuer", 536895490, "GeneralNames"}, + { NULL, 4104, "2"}, + { "DistributionPointName", 1610612741, NULL }, + { "fullName", 1610637314, "GeneralNames"}, + { NULL, 4104, "0"}, + { "nameRelativeToCRLIssuer", 536895490, "RelativeDistinguishedName"}, + { NULL, 4104, "1"}, + { "ReasonFlags", 1610874886, NULL }, + { "unused", 1073741825, "0"}, + { "keyCompromise", 1073741825, "1"}, + { "cACompromise", 1073741825, "2"}, + { "affiliationChanged", 1073741825, "3"}, + { "superseded", 1073741825, "4"}, + { "cessationOfOperation", 1073741825, "5"}, + { "certificateHold", 1, "6"}, + { "id-ce-extKeyUsage", 1879048204, NULL }, + { NULL, 1073741825, "id-ce"}, + { NULL, 1, "37"}, + { "ExtKeyUsageSyntax", 1612709899, NULL }, + { "MAX", 1074266122, "1"}, + { NULL, 2, "KeyPurposeId"}, + { "KeyPurposeId", 1073741836, NULL }, + { "id-kp-serverAuth", 1879048204, NULL }, + { NULL, 1073741825, "id-kp"}, + { NULL, 1, "1"}, + { "id-kp-clientAuth", 1879048204, NULL }, + { NULL, 1073741825, "id-kp"}, + { NULL, 1, "2"}, + { "id-kp-codeSigning", 1879048204, NULL }, + { NULL, 1073741825, "id-kp"}, + { NULL, 1, "3"}, + { "id-kp-emailProtection", 1879048204, NULL }, + { NULL, 1073741825, "id-kp"}, + { NULL, 1, "4"}, + { "id-kp-ipsecEndSystem", 1879048204, NULL }, + { NULL, 1073741825, "id-kp"}, + { NULL, 1, "5"}, + { "id-kp-ipsecTunnel", 1879048204, NULL }, + { NULL, 1073741825, "id-kp"}, + { NULL, 1, "6"}, + { "id-kp-ipsecUser", 1879048204, NULL }, + { NULL, 1073741825, "id-kp"}, + { NULL, 1, "7"}, + { "id-kp-timeStamping", 1879048204, NULL }, + { NULL, 1073741825, "id-kp"}, + { NULL, 1, "8"}, + { "id-pe-authorityInfoAccess", 1879048204, NULL }, + { NULL, 1073741825, "id-pe"}, + { NULL, 1, "1"}, + { "AuthorityInfoAccessSyntax", 1612709899, NULL }, + { "MAX", 1074266122, "1"}, + { NULL, 2, "AccessDescription"}, + { "AccessDescription", 1610612741, NULL }, + { "accessMethod", 1073741836, NULL }, + { "accessLocation", 2, "GeneralName"}, + { "id-ce-cRLNumber", 1879048204, NULL }, + { NULL, 1073741825, "id-ce"}, + { NULL, 1, "20"}, + { "CRLNumber", 1611137027, NULL }, + { "0", 10, "MAX"}, + { "id-ce-issuingDistributionPoint", 1879048204, NULL }, + { NULL, 1073741825, "id-ce"}, + { NULL, 1, "28"}, + { "IssuingDistributionPoint", 1610612741, NULL }, + { "distributionPoint", 1610637314, "DistributionPointName"}, + { NULL, 4104, "0"}, + { "onlyContainsUserCerts", 1610653700, NULL }, + { NULL, 1073872905, NULL }, + { NULL, 4104, "1"}, + { "onlyContainsCACerts", 1610653700, NULL }, + { NULL, 1073872905, NULL }, + { NULL, 4104, "2"}, + { "onlySomeReasons", 1610637314, "ReasonFlags"}, + { NULL, 4104, "3"}, + { "indirectCRL", 536911876, NULL }, + { NULL, 1073872905, NULL }, + { NULL, 4104, "4"}, + { "id-ce-deltaCRLIndicator", 1879048204, NULL }, + { NULL, 1073741825, "id-ce"}, + { NULL, 1, "27"}, + { "BaseCRLNumber", 1073741826, "CRLNumber"}, + { "id-ce-cRLReasons", 1879048204, NULL }, + { NULL, 1073741825, "id-ce"}, + { NULL, 1, "21"}, + { "CRLReason", 1610874901, NULL }, + { "unspecified", 1073741825, "0"}, + { "keyCompromise", 1073741825, "1"}, + { "cACompromise", 1073741825, "2"}, + { "affiliationChanged", 1073741825, "3"}, + { "superseded", 1073741825, "4"}, + { "cessationOfOperation", 1073741825, "5"}, + { "certificateHold", 1073741825, "6"}, + { "removeFromCRL", 1, "8"}, + { "id-ce-certificateIssuer", 1879048204, NULL }, + { NULL, 1073741825, "id-ce"}, + { NULL, 1, "29"}, + { "CertificateIssuer", 1073741826, "GeneralNames"}, + { "id-ce-holdInstructionCode", 1879048204, NULL }, + { NULL, 1073741825, "id-ce"}, + { NULL, 1, "23"}, + { "HoldInstructionCode", 1073741836, NULL }, + { "holdInstruction", 1879048204, NULL }, + { "joint-iso-itu-t", 1073741825, "2"}, + { "member-body", 1073741825, "2"}, + { "us", 1073741825, "840"}, + { "x9cm", 1073741825, "10040"}, + { NULL, 1, "2"}, + { "id-holdinstruction-none", 1879048204, NULL }, + { NULL, 1073741825, "holdInstruction"}, + { NULL, 1, "1"}, + { "id-holdinstruction-callissuer", 1879048204, NULL }, + { NULL, 1073741825, "holdInstruction"}, + { NULL, 1, "2"}, + { "id-holdinstruction-reject", 1879048204, NULL }, + { NULL, 1073741825, "holdInstruction"}, + { NULL, 1, "3"}, + { "id-ce-invalidityDate", 1879048204, NULL }, + { NULL, 1073741825, "id-ce"}, + { NULL, 1, "24"}, + { "InvalidityDate", 1073741861, NULL }, + { "id-netscape", 1879048204, NULL }, + { "joint-iso-itu-t", 1073741825, "2"}, + { "country", 1073741825, "16"}, + { "us", 1073741825, "840"}, + { "organization", 1073741825, "1"}, + { "netscape", 1, "113730"}, + { "id-netscape-certExtension", 1879048204, NULL }, + { NULL, 1073741825, "id-netscape"}, + { NULL, 1, "1"}, + { "id-netscape-certType", 1879048204, NULL }, + { NULL, 1073741825, "id-netscape-certExtension"}, + { NULL, 1, "1"}, + { "CertType", 1610874886, NULL }, + { "sslClient", 1073741825, "0"}, + { "sslServer", 1073741825, "1"}, + { "smime", 1073741825, "2"}, + { "objectSigning", 1073741825, "3"}, + { "reserved", 1073741825, "4"}, + { "sslCA", 1073741825, "5"}, + { "smimeCA", 1073741825, "6"}, + { "objectSigningCA", 1, "7"}, + { "VisibleString", 1610620935, NULL }, + { NULL, 4360, "26"}, + { "NumericString", 1610620935, NULL }, + { NULL, 4360, "18"}, + { "IA5String", 1610620935, NULL }, + { NULL, 4360, "22"}, + { "TeletexString", 1610620935, NULL }, + { NULL, 4360, "20"}, + { "PrintableString", 1610620935, NULL }, + { NULL, 4360, "19"}, + { "UniversalString", 1610620935, NULL }, + { NULL, 4360, "28"}, + { "BMPString", 1610620935, NULL }, + { NULL, 4360, "30"}, + { "UTF8String", 1610620935, NULL }, + { NULL, 4360, "12"}, + { "id-pkix", 1879048204, NULL }, + { "iso", 1073741825, "1"}, + { "identified-organization", 1073741825, "3"}, + { "dod", 1073741825, "6"}, + { "internet", 1073741825, "1"}, + { "security", 1073741825, "5"}, + { "mechanisms", 1073741825, "5"}, + { "pkix", 1, "7"}, + { "id-pe", 1879048204, NULL }, + { NULL, 1073741825, "id-pkix"}, + { NULL, 1, "1"}, + { "id-qt", 1879048204, NULL }, + { NULL, 1073741825, "id-pkix"}, + { NULL, 1, "2"}, + { "id-kp", 1879048204, NULL }, + { NULL, 1073741825, "id-pkix"}, + { NULL, 1, "3"}, + { "id-ad", 1879048204, NULL }, + { NULL, 1073741825, "id-pkix"}, + { NULL, 1, "48"}, + { "id-qt-cps", 1879048204, NULL }, + { NULL, 1073741825, "id-qt"}, + { NULL, 1, "1"}, + { "id-qt-unotice", 1879048204, NULL }, + { NULL, 1073741825, "id-qt"}, + { NULL, 1, "2"}, + { "id-ad-ocsp", 1879048204, NULL }, + { NULL, 1073741825, "id-ad"}, + { NULL, 1, "1"}, + { "id-ad-caIssuers", 1879048204, NULL }, + { NULL, 1073741825, "id-ad"}, + { NULL, 1, "2"}, + { "Attribute", 1610612741, NULL }, + { "type", 1073741826, "AttributeType"}, + { "values", 536870927, NULL }, + { NULL, 2, "AttributeValue"}, + { "AttributeType", 1073741836, NULL }, + { "AttributeValue", 1073741837, NULL }, + { "AttributeTypeAndValue", 1610612741, NULL }, + { "type", 1073741826, "AttributeType"}, + { "value", 2, "AttributeValue"}, + { "id-at", 1879048204, NULL }, + { "joint-iso-ccitt", 1073741825, "2"}, + { "ds", 1073741825, "5"}, + { NULL, 1, "4"}, + { "id-at-name", 1880096780, "AttributeType"}, + { NULL, 1073741825, "id-at"}, + { NULL, 1, "41"}, + { "id-at-surname", 1880096780, "AttributeType"}, + { NULL, 1073741825, "id-at"}, + { NULL, 1, "4"}, + { "id-at-givenName", 1880096780, "AttributeType"}, + { NULL, 1073741825, "id-at"}, + { NULL, 1, "42"}, + { "id-at-initials", 1880096780, "AttributeType"}, + { NULL, 1073741825, "id-at"}, + { NULL, 1, "43"}, + { "id-at-generationQualifier", 1880096780, "AttributeType"}, + { NULL, 1073741825, "id-at"}, + { NULL, 1, "44"}, + { "X520name", 1610612754, NULL }, + { "teletexString", 1612709918, NULL }, + { "ub-name", 524298, "1"}, + { "printableString", 1612709919, NULL }, + { "ub-name", 524298, "1"}, + { "universalString", 1612709920, NULL }, + { "ub-name", 524298, "1"}, + { "utf8String", 1612709922, NULL }, + { "ub-name", 524298, "1"}, + { "bmpString", 538968097, NULL }, + { "ub-name", 524298, "1"}, + { "id-at-commonName", 1880096780, "AttributeType"}, + { NULL, 1073741825, "id-at"}, + { NULL, 1, "3"}, + { "X520CommonName", 1610612754, NULL }, + { "teletexString", 1612709918, NULL }, + { "ub-common-name", 524298, "1"}, + { "printableString", 1612709919, NULL }, + { "ub-common-name", 524298, "1"}, + { "universalString", 1612709920, NULL }, + { "ub-common-name", 524298, "1"}, + { "utf8String", 1612709922, NULL }, + { "ub-common-name", 524298, "1"}, + { "bmpString", 538968097, NULL }, + { "ub-common-name", 524298, "1"}, + { "id-at-localityName", 1880096780, "AttributeType"}, + { NULL, 1073741825, "id-at"}, + { NULL, 1, "7"}, + { "X520LocalityName", 1610612754, NULL }, + { "teletexString", 1612709918, NULL }, + { "ub-locality-name", 524298, "1"}, + { "printableString", 1612709919, NULL }, + { "ub-locality-name", 524298, "1"}, + { "universalString", 1612709920, NULL }, + { "ub-locality-name", 524298, "1"}, + { "utf8String", 1612709922, NULL }, + { "ub-locality-name", 524298, "1"}, + { "bmpString", 538968097, NULL }, + { "ub-locality-name", 524298, "1"}, + { "id-at-stateOrProvinceName", 1880096780, "AttributeType"}, + { NULL, 1073741825, "id-at"}, + { NULL, 1, "8"}, + { "X520StateOrProvinceName", 1610612754, NULL }, + { "teletexString", 1612709918, NULL }, + { "ub-state-name", 524298, "1"}, + { "printableString", 1612709919, NULL }, + { "ub-state-name", 524298, "1"}, + { "universalString", 1612709920, NULL }, + { "ub-state-name", 524298, "1"}, + { "utf8String", 1612709922, NULL }, + { "ub-state-name", 524298, "1"}, + { "bmpString", 538968097, NULL }, + { "ub-state-name", 524298, "1"}, + { "id-at-organizationName", 1880096780, "AttributeType"}, + { NULL, 1073741825, "id-at"}, + { NULL, 1, "10"}, + { "X520OrganizationName", 1610612754, NULL }, + { "teletexString", 1612709918, NULL }, + { "ub-organization-name", 524298, "1"}, + { "printableString", 1612709919, NULL }, + { "ub-organization-name", 524298, "1"}, + { "universalString", 1612709920, NULL }, + { "ub-organization-name", 524298, "1"}, + { "utf8String", 1612709922, NULL }, + { "ub-organization-name", 524298, "1"}, + { "bmpString", 538968097, NULL }, + { "ub-organization-name", 524298, "1"}, + { "id-at-organizationalUnitName", 1880096780, "AttributeType"}, + { NULL, 1073741825, "id-at"}, + { NULL, 1, "11"}, + { "X520OrganizationalUnitName", 1610612754, NULL }, + { "teletexString", 1612709918, NULL }, + { "ub-organizational-unit-name", 524298, "1"}, + { "printableString", 1612709919, NULL }, + { "ub-organizational-unit-name", 524298, "1"}, + { "universalString", 1612709920, NULL }, + { "ub-organizational-unit-name", 524298, "1"}, + { "utf8String", 1612709922, NULL }, + { "ub-organizational-unit-name", 524298, "1"}, + { "bmpString", 538968097, NULL }, + { "ub-organizational-unit-name", 524298, "1"}, + { "id-at-title", 1880096780, "AttributeType"}, + { NULL, 1073741825, "id-at"}, + { NULL, 1, "12"}, + { "X520Title", 1610612754, NULL }, + { "teletexString", 1612709918, NULL }, + { "ub-title", 524298, "1"}, + { "printableString", 1612709919, NULL }, + { "ub-title", 524298, "1"}, + { "universalString", 1612709920, NULL }, + { "ub-title", 524298, "1"}, + { "utf8String", 1612709922, NULL }, + { "ub-title", 524298, "1"}, + { "bmpString", 538968097, NULL }, + { "ub-title", 524298, "1"}, + { "id-at-dnQualifier", 1880096780, "AttributeType"}, + { NULL, 1073741825, "id-at"}, + { NULL, 1, "46"}, + { "X520dnQualifier", 1073741855, NULL }, + { "id-at-countryName", 1880096780, "AttributeType"}, + { NULL, 1073741825, "id-at"}, + { NULL, 1, "6"}, + { "X520countryName", 1612709919, NULL }, + { NULL, 1048586, "2"}, + { "pkcs-9", 1879048204, NULL }, + { "iso", 1073741825, "1"}, + { "member-body", 1073741825, "2"}, + { "us", 1073741825, "840"}, + { "rsadsi", 1073741825, "113549"}, + { "pkcs", 1073741825, "1"}, + { NULL, 1, "9"}, + { "emailAddress", 1880096780, "AttributeType"}, + { NULL, 1073741825, "pkcs-9"}, + { NULL, 1, "1"}, + { "Pkcs9email", 1612709917, NULL }, + { "ub-emailaddress-length", 524298, "1"}, + { "Name", 1610612754, NULL }, + { "rdnSequence", 2, "RDNSequence"}, + { "RDNSequence", 1610612747, NULL }, + { NULL, 2, "RelativeDistinguishedName"}, + { "DistinguishedName", 1073741826, "RDNSequence"}, + { "RelativeDistinguishedName", 1612709903, NULL }, + { "MAX", 1074266122, "1"}, + { NULL, 2, "AttributeTypeAndValue"}, + { "DirectoryString", 1610612754, NULL }, + { "teletexString", 1612709918, NULL }, + { "MAX", 524298, "1"}, + { "printableString", 1612709919, NULL }, + { "MAX", 524298, "1"}, + { "universalString", 1612709920, NULL }, + { "MAX", 524298, "1"}, + { "utf8String", 1612709922, NULL }, + { "MAX", 524298, "1"}, + { "bmpString", 538968097, NULL }, + { "MAX", 524298, "1"}, + { "Certificate", 1610612741, NULL }, + { "tbsCertificate", 1073741826, "TBSCertificate"}, + { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"}, + { "signature", 6, NULL }, + { "TBSCertificate", 1610612741, NULL }, + { "version", 1610653698, "Version"}, + { NULL, 1073741833, "v1"}, + { NULL, 2056, "0"}, + { "serialNumber", 1073741826, "CertificateSerialNumber"}, + { "signature", 1073741826, "AlgorithmIdentifier"}, + { "issuer", 1073741826, "Name"}, + { "validity", 1073741826, "Validity"}, + { "subject", 1073741826, "Name"}, + { "subjectPublicKeyInfo", 1073741826, "SubjectPublicKeyInfo"}, + { "issuerUniqueID", 1610637314, "UniqueIdentifier"}, + { NULL, 4104, "1"}, + { "subjectUniqueID", 1610637314, "UniqueIdentifier"}, + { NULL, 4104, "2"}, + { "extensions", 536895490, "Extensions"}, + { NULL, 2056, "3"}, + { "Version", 1610874883, NULL }, + { "v1", 1073741825, "0"}, + { "v2", 1073741825, "1"}, + { "v3", 1, "2"}, + { "CertificateSerialNumber", 1073741827, NULL }, + { "Validity", 1610612741, NULL }, + { "notBefore", 1073741826, "Time"}, + { "notAfter", 2, "Time"}, + { "Time", 1610612754, NULL }, + { "utcTime", 1073741860, NULL }, + { "generalTime", 37, NULL }, + { "UniqueIdentifier", 1073741830, NULL }, + { "SubjectPublicKeyInfo", 1610612741, NULL }, + { "algorithm", 1073741826, "AlgorithmIdentifier"}, + { "subjectPublicKey", 6, NULL }, + { "Extensions", 1612709899, NULL }, + { "MAX", 1074266122, "1"}, + { NULL, 2, "Extension"}, + { "Extension", 1610612741, NULL }, + { "extnID", 1073741836, NULL }, + { "critical", 1610645508, NULL }, + { NULL, 131081, NULL }, + { "extnValue", 7, NULL }, + { "CertificateList", 1610612741, NULL }, + { "tbsCertList", 1073741826, "TBSCertList"}, + { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"}, + { "signature", 6, NULL }, + { "TBSCertList", 1610612741, NULL }, + { "version", 1073758210, "Version"}, + { "signature", 1073741826, "AlgorithmIdentifier"}, + { "issuer", 1073741826, "Name"}, + { "thisUpdate", 1073741826, "Time"}, + { "nextUpdate", 1073758210, "Time"}, + { "revokedCertificates", 1610629131, NULL }, + { NULL, 536870917, NULL }, + { "userCertificate", 1073741826, "CertificateSerialNumber"}, + { "revocationDate", 1073741826, "Time"}, + { "crlEntryExtensions", 16386, "Extensions"}, + { "crlExtensions", 536895490, "Extensions"}, + { NULL, 2056, "0"}, + { "AlgorithmIdentifier", 1610612741, NULL }, + { "algorithm", 1073741836, NULL }, + { "parameters", 541081613, NULL }, + { "algorithm", 1, NULL }, + { "pkcs-1", 1879048204, NULL }, + { "iso", 1073741825, "1"}, + { "member-body", 1073741825, "2"}, + { "us", 1073741825, "840"}, + { "rsadsi", 1073741825, "113549"}, + { "pkcs", 1073741825, "1"}, + { NULL, 1, "1"}, + { "rsaEncryption", 1879048204, NULL }, + { NULL, 1073741825, "pkcs-1"}, + { NULL, 1, "1"}, + { "md2WithRSAEncryption", 1879048204, NULL }, + { NULL, 1073741825, "pkcs-1"}, + { NULL, 1, "2"}, + { "md5WithRSAEncryption", 1879048204, NULL }, + { NULL, 1073741825, "pkcs-1"}, + { NULL, 1, "4"}, + { "sha1WithRSAEncryption", 1879048204, NULL }, + { NULL, 1073741825, "pkcs-1"}, + { NULL, 1, "5"}, + { "sha256WithRSAEncryption", 1879048204, NULL }, + { NULL, 1073741825, "pkcs-1"}, + { NULL, 1, "11"}, + { "sha384WithRSAEncryption", 1879048204, NULL }, + { NULL, 1073741825, "pkcs-1"}, + { NULL, 1, "12"}, + { "sha512WithRSAEncryption", 1879048204, NULL }, + { NULL, 1073741825, "pkcs-1"}, + { NULL, 1, "13"}, + { "RSAPublicKey", 1610612741, NULL }, + { "modulus", 1073741827, NULL }, + { "publicExponent", 3, NULL }, + { "RSAPrivateKey", 1610612741, NULL }, + { "version", 1073741826, "Version"}, + { "modulus", 1073741827, NULL }, + { "publicExponent", 1073741827, NULL }, + { "privateExponent", 1073741827, NULL }, + { "prime1", 1073741827, NULL }, + { "prime2", 1073741827, NULL }, + { "exponent1", 1073741827, NULL }, + { "exponent2", 1073741827, NULL }, + { "coefficient", 3, NULL }, + { "id-dsa-with-sha1", 1879048204, NULL }, + { "iso", 1073741825, "1"}, + { "member-body", 1073741825, "2"}, + { "us", 1073741825, "840"}, + { "x9-57", 1073741825, "10040"}, + { "x9algorithm", 1073741825, "4"}, + { NULL, 1, "3"}, + { "Dss-Sig-Value", 1610612741, NULL }, + { "r", 1073741827, NULL }, + { "s", 3, NULL }, + { "dhpublicnumber", 1879048204, NULL }, + { "iso", 1073741825, "1"}, + { "member-body", 1073741825, "2"}, + { "us", 1073741825, "840"}, + { "ansi-x942", 1073741825, "10046"}, + { "number-type", 1073741825, "2"}, + { NULL, 1, "1"}, + { "DomainParameters", 1610612741, NULL }, + { "p", 1073741827, NULL }, + { "g", 1073741827, NULL }, + { "q", 1073741827, NULL }, + { "j", 1073758211, NULL }, + { "validationParms", 16386, "ValidationParms"}, + { "ValidationParms", 1610612741, NULL }, + { "seed", 1073741830, NULL }, + { "pgenCounter", 3, NULL }, + { "id-dsa", 1879048204, NULL }, + { "iso", 1073741825, "1"}, + { "member-body", 1073741825, "2"}, + { "us", 1073741825, "840"}, + { "x9-57", 1073741825, "10040"}, + { "x9algorithm", 1073741825, "4"}, + { NULL, 1, "1"}, + { "Dss-Parms", 1610612741, NULL }, + { "p", 1073741827, NULL }, + { "q", 1073741827, NULL }, + { "g", 3, NULL }, + { "ORAddress", 1610612741, NULL }, + { "built-in-standard-attributes", 1073741826, "BuiltInStandardAttributes"}, + { "built-in-domain-defined-attributes", 1073758210, "BuiltInDomainDefinedAttributes"}, + { "extension-attributes", 16386, "ExtensionAttributes"}, + { "BuiltInStandardAttributes", 1610612741, NULL }, + { "country-name", 1073758210, "CountryName"}, + { "administration-domain-name", 1073758210, "AdministrationDomainName"}, + { "network-address", 1610637314, "NetworkAddress"}, + { NULL, 2056, "0"}, + { "terminal-identifier", 1610637314, "TerminalIdentifier"}, + { NULL, 2056, "1"}, + { "private-domain-name", 1610637314, "PrivateDomainName"}, + { NULL, 2056, "2"}, + { "organization-name", 1610637314, "OrganizationName"}, + { NULL, 2056, "3"}, + { "numeric-user-identifier", 1610637314, "NumericUserIdentifier"}, + { NULL, 2056, "4"}, + { "personal-name", 1610637314, "PersonalName"}, + { NULL, 2056, "5"}, + { "organizational-unit-names", 536895490, "OrganizationalUnitNames"}, + { NULL, 2056, "6"}, + { "CountryName", 1610620946, NULL }, + { NULL, 1073746952, "1"}, + { "x121-dcc-code", 1612709916, NULL }, + { NULL, 1048586, "ub-country-name-numeric-length"}, + { "iso-3166-alpha2-code", 538968095, NULL }, + { NULL, 1048586, "ub-country-name-alpha-length"}, + { "AdministrationDomainName", 1610620946, NULL }, + { NULL, 1073744904, "2"}, + { "numeric", 1612709916, NULL }, + { "ub-domain-name-length", 524298, "0"}, + { "printable", 538968095, NULL }, + { "ub-domain-name-length", 524298, "0"}, + { "NetworkAddress", 1073741826, "X121Address"}, + { "X121Address", 1612709916, NULL }, + { "ub-x121-address-length", 524298, "1"}, + { "TerminalIdentifier", 1612709919, NULL }, + { "ub-terminal-id-length", 524298, "1"}, + { "PrivateDomainName", 1610612754, NULL }, + { "numeric", 1612709916, NULL }, + { "ub-domain-name-length", 524298, "1"}, + { "printable", 538968095, NULL }, + { "ub-domain-name-length", 524298, "1"}, + { "OrganizationName", 1612709919, NULL }, + { "ub-organization-name-length", 524298, "1"}, + { "NumericUserIdentifier", 1612709916, NULL }, + { "ub-numeric-user-id-length", 524298, "1"}, + { "PersonalName", 1610612750, NULL }, + { "surname", 1814044703, NULL }, + { NULL, 1073745928, "0"}, + { "ub-surname-length", 524298, "1"}, + { "given-name", 1814061087, NULL }, + { NULL, 1073745928, "1"}, + { "ub-given-name-length", 524298, "1"}, + { "initials", 1814061087, NULL }, + { NULL, 1073745928, "2"}, + { "ub-initials-length", 524298, "1"}, + { "generation-qualifier", 740319263, NULL }, + { NULL, 1073745928, "3"}, + { "ub-generation-qualifier-length", 524298, "1"}, + { "OrganizationalUnitNames", 1612709899, NULL }, + { "ub-organizational-units", 1074266122, "1"}, + { NULL, 2, "OrganizationalUnitName"}, + { "OrganizationalUnitName", 1612709919, NULL }, + { "ub-organizational-unit-name-length", 524298, "1"}, + { "BuiltInDomainDefinedAttributes", 1612709899, NULL }, + { "ub-domain-defined-attributes", 1074266122, "1"}, + { NULL, 2, "BuiltInDomainDefinedAttribute"}, + { "BuiltInDomainDefinedAttribute", 1610612741, NULL }, + { "type", 1612709919, NULL }, + { "ub-domain-defined-attribute-type-length", 524298, "1"}, + { "value", 538968095, NULL }, + { "ub-domain-defined-attribute-value-length", 524298, "1"}, + { "ExtensionAttributes", 1612709903, NULL }, + { "ub-extension-attributes", 1074266122, "1"}, + { NULL, 2, "ExtensionAttribute"}, + { "ExtensionAttribute", 1610612741, NULL }, + { "extension-attribute-type", 1611145219, NULL }, + { NULL, 1073743880, "0"}, + { "0", 10, "ub-extension-attributes"}, + { "extension-attribute-value", 541073421, NULL }, + { NULL, 1073743880, "1"}, + { "extension-attribute-type", 1, NULL }, + { "common-name", 1342177283, "1"}, + { "CommonName", 1612709919, NULL }, + { "ub-common-name-length", 524298, "1"}, + { "teletex-common-name", 1342177283, "2"}, + { "TeletexCommonName", 1612709918, NULL }, + { "ub-common-name-length", 524298, "1"}, + { "teletex-organization-name", 1342177283, "3"}, + { "TeletexOrganizationName", 1612709918, NULL }, + { "ub-organization-name-length", 524298, "1"}, + { "teletex-personal-name", 1342177283, "4"}, + { "TeletexPersonalName", 1610612750, NULL }, + { "surname", 1814044702, NULL }, + { NULL, 1073743880, "0"}, + { "ub-surname-length", 524298, "1"}, + { "given-name", 1814061086, NULL }, + { NULL, 1073743880, "1"}, + { "ub-given-name-length", 524298, "1"}, + { "initials", 1814061086, NULL }, + { NULL, 1073743880, "2"}, + { "ub-initials-length", 524298, "1"}, + { "generation-qualifier", 740319262, NULL }, + { NULL, 1073743880, "3"}, + { "ub-generation-qualifier-length", 524298, "1"}, + { "teletex-organizational-unit-names", 1342177283, "5"}, + { "TeletexOrganizationalUnitNames", 1612709899, NULL }, + { "ub-organizational-units", 1074266122, "1"}, + { NULL, 2, "TeletexOrganizationalUnitName"}, + { "TeletexOrganizationalUnitName", 1612709918, NULL }, + { "ub-organizational-unit-name-length", 524298, "1"}, + { "pds-name", 1342177283, "7"}, + { "PDSName", 1612709919, NULL }, + { "ub-pds-name-length", 524298, "1"}, + { "physical-delivery-country-name", 1342177283, "8"}, + { "PhysicalDeliveryCountryName", 1610612754, NULL }, + { "x121-dcc-code", 1612709916, NULL }, + { NULL, 1048586, "ub-country-name-numeric-length"}, + { "iso-3166-alpha2-code", 538968095, NULL }, + { NULL, 1048586, "ub-country-name-alpha-length"}, + { "postal-code", 1342177283, "9"}, + { "PostalCode", 1610612754, NULL }, + { "numeric-code", 1612709916, NULL }, + { "ub-postal-code-length", 524298, "1"}, + { "printable-code", 538968095, NULL }, + { "ub-postal-code-length", 524298, "1"}, + { "physical-delivery-office-name", 1342177283, "10"}, + { "PhysicalDeliveryOfficeName", 1073741826, "PDSParameter"}, + { "physical-delivery-office-number", 1342177283, "11"}, + { "PhysicalDeliveryOfficeNumber", 1073741826, "PDSParameter"}, + { "extension-OR-address-components", 1342177283, "12"}, + { "ExtensionORAddressComponents", 1073741826, "PDSParameter"}, + { "physical-delivery-personal-name", 1342177283, "13"}, + { "PhysicalDeliveryPersonalName", 1073741826, "PDSParameter"}, + { "physical-delivery-organization-name", 1342177283, "14"}, + { "PhysicalDeliveryOrganizationName", 1073741826, "PDSParameter"}, + { "extension-physical-delivery-address-components", 1342177283, "15"}, + { "ExtensionPhysicalDeliveryAddressComponents", 1073741826, "PDSParameter"}, + { "unformatted-postal-address", 1342177283, "16"}, + { "UnformattedPostalAddress", 1610612750, NULL }, + { "printable-address", 1814052875, NULL }, + { "ub-pds-physical-address-lines", 1074266122, "1"}, + { NULL, 538968095, NULL }, + { "ub-pds-parameter-length", 524298, "1"}, + { "teletex-string", 740311070, NULL }, + { "ub-unformatted-address-length", 524298, "1"}, + { "street-address", 1342177283, "17"}, + { "StreetAddress", 1073741826, "PDSParameter"}, + { "post-office-box-address", 1342177283, "18"}, + { "PostOfficeBoxAddress", 1073741826, "PDSParameter"}, + { "poste-restante-address", 1342177283, "19"}, + { "PosteRestanteAddress", 1073741826, "PDSParameter"}, + { "unique-postal-name", 1342177283, "20"}, + { "UniquePostalName", 1073741826, "PDSParameter"}, + { "local-postal-attributes", 1342177283, "21"}, + { "LocalPostalAttributes", 1073741826, "PDSParameter"}, + { "PDSParameter", 1610612750, NULL }, + { "printable-string", 1814052895, NULL }, + { "ub-pds-parameter-length", 524298, "1"}, + { "teletex-string", 740311070, NULL }, + { "ub-pds-parameter-length", 524298, "1"}, + { "extended-network-address", 1342177283, "22"}, + { "ExtendedNetworkAddress", 1610612754, NULL }, + { "e163-4-address", 1610612741, NULL }, + { "number", 1612718108, NULL }, + { NULL, 1073743880, "0"}, + { "ub-e163-4-number-length", 524298, "1"}, + { "sub-address", 538992668, NULL }, + { NULL, 1073743880, "1"}, + { "ub-e163-4-sub-address-length", 524298, "1"}, + { "psap-address", 536879106, "PresentationAddress"}, + { NULL, 2056, "0"}, + { "PresentationAddress", 1610612741, NULL }, + { "pSelector", 1610637319, NULL }, + { NULL, 2056, "0"}, + { "sSelector", 1610637319, NULL }, + { NULL, 2056, "1"}, + { "tSelector", 1610637319, NULL }, + { NULL, 2056, "2"}, + { "nAddresses", 538976271, NULL }, + { NULL, 1073743880, "3"}, + { "MAX", 1074266122, "1"}, + { NULL, 7, NULL }, + { "terminal-type", 1342177283, "23"}, + { "TerminalType", 1611137027, NULL }, + { "0", 10, "ub-integer-options"}, + { "teletex-domain-defined-attributes", 1342177283, "6"}, + { "TeletexDomainDefinedAttributes", 1612709899, NULL }, + { "ub-domain-defined-attributes", 1074266122, "1"}, + { NULL, 2, "TeletexDomainDefinedAttribute"}, + { "TeletexDomainDefinedAttribute", 1610612741, NULL }, + { "type", 1612709918, NULL }, + { "ub-domain-defined-attribute-type-length", 524298, "1"}, + { "value", 538968094, NULL }, + { "ub-domain-defined-attribute-value-length", 524298, "1"}, + { "ub-name", 1342177283, "32768"}, + { "ub-common-name", 1342177283, "64"}, + { "ub-locality-name", 1342177283, "128"}, + { "ub-state-name", 1342177283, "128"}, + { "ub-organization-name", 1342177283, "64"}, + { "ub-organizational-unit-name", 1342177283, "64"}, + { "ub-title", 1342177283, "64"}, + { "ub-match", 1342177283, "128"}, + { "ub-emailaddress-length", 1342177283, "128"}, + { "ub-common-name-length", 1342177283, "64"}, + { "ub-country-name-alpha-length", 1342177283, "2"}, + { "ub-country-name-numeric-length", 1342177283, "3"}, + { "ub-domain-defined-attributes", 1342177283, "4"}, + { "ub-domain-defined-attribute-type-length", 1342177283, "8"}, + { "ub-domain-defined-attribute-value-length", 1342177283, "128"}, + { "ub-domain-name-length", 1342177283, "16"}, + { "ub-extension-attributes", 1342177283, "256"}, + { "ub-e163-4-number-length", 1342177283, "15"}, + { "ub-e163-4-sub-address-length", 1342177283, "40"}, + { "ub-generation-qualifier-length", 1342177283, "3"}, + { "ub-given-name-length", 1342177283, "16"}, + { "ub-initials-length", 1342177283, "5"}, + { "ub-integer-options", 1342177283, "256"}, + { "ub-numeric-user-id-length", 1342177283, "32"}, + { "ub-organization-name-length", 1342177283, "64"}, + { "ub-organizational-unit-name-length", 1342177283, "32"}, + { "ub-organizational-units", 1342177283, "4"}, + { "ub-pds-name-length", 1342177283, "16"}, + { "ub-pds-parameter-length", 1342177283, "30"}, + { "ub-pds-physical-address-lines", 1342177283, "6"}, + { "ub-postal-code-length", 1342177283, "16"}, + { "ub-surname-length", 1342177283, "40"}, + { "ub-terminal-id-length", 1342177283, "24"}, + { "ub-unformatted-address-length", 1342177283, "180"}, + { "ub-x121-address-length", 268435459, "16"}, + { NULL, 0, NULL } +}; diff -Nru rdesktop-1.8.6/printer.c rdesktop-1.9.0/printer.c --- rdesktop-1.8.6/printer.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/printer.c 2019-06-13 12:10:15.000000000 +0000 @@ -40,7 +40,7 @@ char *pos = optarg; char *pos2; - int count = 0; + size_t count = 0; int already = 0; /* we need to know how many printers we've already set up @@ -87,8 +87,8 @@ strcpy(pprinter_data->driver, pos2); } - printf("PRINTER %s to %s driver %s\n", g_rdpdr_device[*id].name, - pprinter_data->printer, pprinter_data->driver); + logger(Core, Debug, "printer_enum_devices(), %s to %s driver %s", + g_rdpdr_device[*id].name, pprinter_data->printer, pprinter_data->driver); g_rdpdr_device[*id].device_type = DEVICE_TYPE_PRINTER; g_rdpdr_device[*id].pdevice_data = (void *) pprinter_data; count++; @@ -103,6 +103,11 @@ printer_create(uint32 device_id, uint32 access, uint32 share_mode, uint32 disposition, uint32 flags, char *filename, RD_NTHANDLE * handle) { + UNUSED(access); + UNUSED(share_mode); + UNUSED(disposition); + UNUSED(flags); + UNUSED(filename); char cmd[256]; PRINTER *pprinter_data; @@ -139,8 +144,9 @@ } static RD_NTSTATUS -printer_write(RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result) +printer_write(RD_NTHANDLE handle, uint8 * data, uint32 length, uint64 offset, uint32 * result) { + UNUSED(offset); /* Currently unused, MS-RDPEPC reserves for later use */ PRINTER *pprinter_data; pprinter_data = get_printer_data(handle); diff -Nru rdesktop-1.8.6/printercache.c rdesktop-1.9.0/printercache.c --- rdesktop-1.8.6/printercache.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/printercache.c 2019-06-13 12:10:15.000000000 +0000 @@ -3,7 +3,7 @@ Entrypoint and utility functions Copyright (C) Matthew Chapman <matthewc.unsw.edu.au> 1999-2008 Copyright (C) Jeroen Meijer <jeroen@oldambt7.com> 2003-2008 - Copyright (C) Henrik Andersson <hean01@cendio.com> 2013 + Copyright (C) Henrik Andersson <hean01@cendio.se> 2013-2017 This program is free software: you can redistribute it and/or modify @@ -47,7 +47,7 @@ sprintf(path, "%s/.rdesktop", base); if ((mkdir(path, 0700) == -1) && errno != EEXIST) { - perror(path); + logger(Core, Error, "printercache_mkdir(), mkdir() failed: %s", strerror(errno)); xfree(path); return False; } @@ -55,7 +55,7 @@ strcat(path, "/rdpdr"); if ((mkdir(path, 0700) == -1) && errno != EEXIST) { - perror(path); + logger(Core, Error, "printercache_mkdir(), mkdir() failed: %s", strerror(errno)); xfree(path); return False; } @@ -64,7 +64,7 @@ strcat(path, printer); if ((mkdir(path, 0700) == -1) && errno != EEXIST) { - perror(path); + logger(Core, Error, "printercache_mkdir(), mkdir() failed: %s", strerror(errno)); xfree(path); return False; } @@ -137,9 +137,12 @@ sprintf(printer_path, "%s/.rdesktop/rdpdr/%s", home, printer); sprintf(new_printer_path, "%s/.rdesktop/rdpdr/%s", home, new_printer); - printf("%s,%s\n", printer_path, new_printer_path); + logger(Core, Debug, "printercache_rename_blob(), printer_path=%s, new_printer_path=%s", + printer_path, new_printer_path); if (rename(printer_path, new_printer_path) < 0) { + logger(Core, Error, "printercache_rename_blob(), rename() failed: %s", + strerror(errno)); xfree(printer_path); xfree(new_printer_path); return False; @@ -214,14 +217,15 @@ fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600); if (fd == -1) { - perror(path); + logger(Core, Error, "printercache_save_blob(), open() failed: %s", strerror(errno)); xfree(path); return; } if (write(fd, data, length) != length) { - perror(path); + logger(Core, Error, "printercache_save_blob(), write() failed: %s", + strerror(errno)); unlink(path); } @@ -310,8 +314,8 @@ printercache_save_blob(device_name, blob, blob_length); break; default: - - unimpl("RDPDR Printer Cache Packet Type: %d\n", type); + logger(Protocol, Warning, + "printercache_process(), unhandled packet type %d", type); break; } } diff -Nru rdesktop-1.8.6/proto.h rdesktop-1.9.0/proto.h --- rdesktop-1.8.6/proto.h 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/proto.h 2019-06-13 12:10:15.000000000 +0000 @@ -24,12 +24,12 @@ extern "C" { #endif /* *INDENT-ON* */ -/* utils.c */ -char *utils_string_escape(const char *str); -char *utils_string_unescape(const char *str); -int utils_locale_to_utf8(const char *src, size_t is, char *dest, size_t os); -int utils_mkdir_safe(const char *path, int mask); -int utils_mkdir_p(const char *path, int mask); +#define UNUSED(param) ((void)param) +#ifdef __GNUC__ +# define NORETURN __attribute__((noreturn)) +#else +# define NORETURN +#endif // __GNUC__ /* bitmap.c */ RD_BOOL bitmap_decompress(uint8 * output, int width, int height, uint8 * input, int size, int Bpp); /* cache.c */ @@ -87,7 +87,7 @@ /* iso.c */ STREAM iso_init(int length); void iso_send(STREAM s); -STREAM iso_recv(uint8 * rdpver); +STREAM iso_recv(RD_BOOL * is_fastpath, uint8 * fastpath_hdr); RD_BOOL iso_connect(char *server, char *username, char *domain, char *password, RD_BOOL reconnect, uint32 * selected_protocol); void iso_disconnect(void); @@ -100,11 +100,11 @@ 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); +STREAM mcs_recv(uint16 * channel, RD_BOOL * is_fastpath, uint8 * fastpath_hdr); RD_BOOL mcs_connect_start(char *server, char *username, char *domain, char *password, RD_BOOL reconnect, uint32 * selected_protocol); RD_BOOL mcs_connect_finalize(STREAM s); -void mcs_disconnect(void); +void mcs_disconnect(int reason); void mcs_reset_state(void); /* orders.c */ void process_orders(STREAM s, uint16 num_orders); @@ -131,9 +131,6 @@ char *xstrdup(const char *s); void *xrealloc(void *oldmem, size_t 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); @@ -146,6 +143,7 @@ void save_licence(unsigned char *data, int length); void rd_create_ui(void); RD_BOOL rd_pstcache_mkdir(void); +RD_BOOL rd_certcache_mkdir(void); int rd_open_file(char *filename); void rd_close_file(int fd); int rd_read_file(int fd, void *ptr, int len); @@ -153,20 +151,19 @@ int rd_lseek_file(int fd, int offset); RD_BOOL rd_lock_file(int fd, int start, int len); /* rdp5.c */ -void rdp5_process(STREAM s); +void process_ts_fp_updates(STREAM s); /* rdp.c */ -void rdp_out_unistr(STREAM s, char *string, int len); void rdp_in_unistr(STREAM s, int in_len, char **string, uint32 * str_size); 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 rdp_send_suppress_output_pdu(enum RDP_SUPPRESS_STATUS allowupdates); void process_colour_pointer_pdu(STREAM s); void process_new_pointer_pdu(STREAM s); void process_cached_pointer_pdu(STREAM s); void process_system_pointer_pdu(STREAM s); +void set_system_pointer(uint32 ptr); 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(RD_BOOL * deactivated, uint32 * ext_disc_reason); RD_BOOL rdp_loop(RD_BOOL * deactivated, uint32 * ext_disc_reason); RD_BOOL rdp_connect(char *server, uint32 flags, char *domain, char *password, char *command, @@ -175,7 +172,7 @@ void rdp_disconnect(void); #define rdp_protocol_error(m, s) _rdp_protocol_error(__FILE__, __LINE__, __func__, m, s) void _rdp_protocol_error(const char *file, int line, const char *func, - const char *message, STREAM s); + const char *message, STREAM s) NORETURN; /* rdpdr.c */ int get_device_index(RD_NTHANDLE handle); void convert_to_unix_filename(char *filename); @@ -211,7 +208,7 @@ 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); +STREAM sec_recv(RD_BOOL * is_fastpath); RD_BOOL sec_connect(char *server, char *username, char *domain, char *password, RD_BOOL reconnect); void sec_disconnect(void); void sec_reset_state(void); @@ -238,6 +235,7 @@ void ber_out_header(STREAM s, int tagval, int length); RD_BOOL ber_parse_header(STREAM s, int tagval, uint32 *length); void ber_out_integer(STREAM s, int value); +void ber_out_sequence(STREAM s, STREAM contents); /* xclip.c */ void ui_clip_format_announce(uint8 * data, uint32 length); @@ -256,7 +254,7 @@ 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, RD_BOOL pressed, uint8 nesting); -uint16 xkeymap_translate_button(unsigned int button); +uint16 xkeymap_translate_button(unsigned int button, uint16 * input_type); char *get_ksname(uint32 keysym); void save_remote_modifiers(uint8 scancode); void restore_remote_modifiers(uint32 ev_time, uint8 scancode); @@ -268,25 +266,29 @@ /* xwin.c */ RD_BOOL get_key_state(unsigned int state, uint32 keysym); RD_BOOL ui_init(void); -void ui_init_connection(void); +void ui_get_screen_size(uint32 * width, uint32 * height); +void ui_get_screen_size_from_percentage(uint32 pw, uint32 ph, uint32 * width, uint32 * height); +void ui_get_workarea_size(uint32 * width, uint32 * height); void ui_deinit(void); -RD_BOOL ui_create_window(void); -void ui_resize_window(void); +RD_BOOL ui_create_window(uint32 width, uint32 height); +void ui_resize_window(uint32 width, uint32 height); void ui_destroy_window(void); +void ui_update_window_sizehints(uint32 width, uint32 height); RD_BOOL ui_have_window(void); void xwin_toggle_fullscreen(void); -int ui_select(int rdp_socket); +void ui_select(int rdp_socket); void ui_move_pointer(int x, int y); RD_HBITMAP ui_create_bitmap(int width, int height, uint8 * data); void ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * data); void ui_destroy_bitmap(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, int bpp); +RD_HCURSOR ui_create_cursor(unsigned int x, unsigned int y, uint32 width, uint32 height, + uint8 * andmask, uint8 * xormask, int bpp); void ui_set_cursor(RD_HCURSOR cursor); void ui_destroy_cursor(RD_HCURSOR cursor); void ui_set_null_cursor(void); +void ui_set_standard_cursor(void); RD_HCOLOURMAP ui_create_colourmap(COLOURMAP * colours); void ui_destroy_colourmap(RD_HCOLOURMAP map); void ui_set_colourmap(RD_HCOLOURMAP map); @@ -294,24 +296,24 @@ 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_patblt(uint8 opcode, int x, int y, int cx, int cy, BRUSH * brush, uint32 bgcolour, + uint32 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); + BRUSH * brush, uint32 bgcolour, uint32 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_rect(int x, int y, int cx, int cy, uint32 colour); void ui_polygon(uint8 opcode, uint8 fillmode, RD_POINT * point, int npoints, BRUSH * brush, - int bgcolour, int fgcolour); + uint32 bgcolour, uint32 fgcolour); void ui_polyline(uint8 opcode, RD_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); + uint32 bgcolour, uint32 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); + uint32 bgcolour, uint32 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); + BRUSH * brush, uint32 bgcolour, uint32 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); @@ -326,7 +328,7 @@ void ui_seamless_destroy_window(unsigned long id, unsigned long flags); void ui_seamless_destroy_group(unsigned long id, unsigned long flags); void ui_seamless_seticon(unsigned long id, const char *format, int width, int height, int chunk, - const char *data, int chunk_len); + const char *data, size_t chunk_len); void ui_seamless_delicon(unsigned long id, const char *format, int width, int height); void ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags); @@ -337,6 +339,16 @@ void ui_seamless_ack(unsigned int serial); /* lspci.c */ RD_BOOL lspci_init(void); +/* rdpedisp.c */ +void rdpedisp_init(void); +RD_BOOL rdpedisp_is_available(); +void rdpedisp_set_session_size(uint32 width, uint32 height); +/* dvc.c */ +typedef void (*dvc_channel_process_fn) (STREAM s); +RD_BOOL dvc_init(void); +RD_BOOL dvc_channels_register(const char *name, dvc_channel_process_fn handler); +RD_BOOL dvc_channels_is_available(const char *name); +void dvc_send(const char *name, STREAM s); /* seamless.c */ RD_BOOL seamless_init(void); void seamless_reset_state(void); @@ -357,6 +369,7 @@ int scard_enum_devices(uint32 * id, char *optarg); void scardSetInfo(uint32 epoch, uint32 device, uint32 id, uint32 bytes_out); void scard_reset_state(); +void scard_release_all_contexts(void); /* *INDENT-OFF* */ #ifdef __cplusplus diff -Nru rdesktop-1.8.6/proto.head rdesktop-1.9.0/proto.head --- rdesktop-1.8.6/proto.head 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/proto.head 1970-01-01 00:00:00.000000000 +0000 @@ -1,26 +0,0 @@ -/* -*- c-basic-offset: 8 -*- - rdesktop: A Remote Desktop Protocol client. - Copyright (C) Matthew Chapman 1999-2007 - - 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 3 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, see <http://www.gnu.org/licenses/>. -*/ - -#ifndef RDESKTOP_PROTO_H -#define RDESKTOP_PROTO_H - -/* *INDENT-OFF* */ -#ifdef __cplusplus -extern "C" { -#endif -/* *INDENT-ON* */ diff -Nru rdesktop-1.8.6/proto.tail rdesktop-1.9.0/proto.tail --- rdesktop-1.8.6/proto.tail 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/proto.tail 1970-01-01 00:00:00.000000000 +0000 @@ -1,8 +0,0 @@ - -/* *INDENT-OFF* */ -#ifdef __cplusplus -} -#endif -/* *INDENT-ON* */ - -#endif diff -Nru rdesktop-1.8.6/pstcache.c rdesktop-1.9.0/pstcache.c --- rdesktop-1.8.6/pstcache.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/pstcache.c 2019-06-13 12:10:15.000000000 +0000 @@ -70,7 +70,8 @@ rd_read_file(fd, celldata, cellhdr.length); bitmap = ui_create_bitmap(cellhdr.width, cellhdr.height, celldata); - DEBUG(("Load bitmap from disk: id=%d, idx=%d, bmp=%p)\n", cache_id, cache_idx, bitmap)); + logger(Core, Debug, "pstcache_load_bitmap(), load bitmap from disk: id=%d, idx=%d, bmp=%p)", + cache_id, cache_idx, bitmap); cache_put_bitmap(cache_id, cache_idx, bitmap); xfree(celldata); @@ -119,7 +120,7 @@ if (g_pstcache_enumerated) return 0; - DEBUG_RDP5(("Persistent bitmap cache enumeration... ")); + logger(Core, Debug, "pstcache_enumerate(), start enumeration"); for (idx = 0; idx < BMPCACHE2_NUM_PSTCELLS; idx++) { fd = g_pstcache_fd[id]; @@ -131,7 +132,7 @@ { memcpy(keylist[idx], cellhdr.key, sizeof(HASH_KEY)); - /* Pre-cache (not possible for 8 bit colour depth cause it needs a colourmap) */ + /* Pre-cache (not possible for 8-bit colour depth cause it needs a colourmap) */ if (g_bitmap_cache_precache && cellhdr.stamp && g_server_depth > 8) pstcache_load_bitmap(id, idx); @@ -151,7 +152,7 @@ } } - DEBUG_RDP5(("%d cached bitmaps.\n", idx)); + logger(Core, Debug, "pstcache_enumerate(), %d cached bitmaps", idx); cache_rebuild_bmpcache_linked_list(id, mru_idx, idx); g_pstcache_enumerated = True; @@ -175,13 +176,14 @@ if (!rd_pstcache_mkdir()) { - DEBUG(("failed to get/make cache directory!\n")); + logger(Core, Error, + "pstcache_init(), failed to get/make cache directory, disabling feature"); return False; } g_pstcache_Bpp = (g_server_depth + 7) / 8; sprintf(filename, "cache/pstcache_%d_%d", cache_id, g_pstcache_Bpp); - DEBUG(("persistent bitmap cache file: %s\n", filename)); + logger(Core, Debug, "pstcache_init(), bitmap cache file %s", filename); fd = rd_open_file(filename); if (fd == -1) @@ -189,7 +191,8 @@ if (!rd_lock_file(fd, 0, 0)) { - warning("Persistent bitmap caching is disabled. (The file is already in use)\n"); + logger(Core, Error, + "pstcache_init(), failed to lock persistent cache file, disabling feature"); rd_close_file(fd); return False; } diff -Nru rdesktop-1.8.6/rdesktop.c rdesktop-1.9.0/rdesktop.c --- rdesktop-1.8.6/rdesktop.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/rdesktop.c 2019-09-11 14:33:07.000000000 +0000 @@ -3,7 +3,8 @@ Entrypoint and utility functions Copyright (C) Matthew Chapman <matthewc.unsw.edu.au> 1999-2008 Copyright 2002-2011 Peter Astrand <astrand@cendio.se> for Cendio AB - Copyright 2010-2014 Henrik Andersson <hean01@cendio.se> for Cendio AB + Copyright 2010-2018 Henrik Andersson <hean01@cendio.se> for Cendio AB + Copyright 2017-2018 Alexander Zakharov <uglym8@gmail.com> 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 @@ -31,16 +32,15 @@ #include <limits.h> #include <errno.h> #include <signal.h> + #include "rdesktop.h" #ifdef HAVE_LOCALE_H #include <locale.h> #endif -#ifdef HAVE_ICONV #ifdef HAVE_LANGINFO_H #include <langinfo.h> #endif -#endif #ifdef EGD_SOCKET #include <sys/types.h> @@ -50,7 +50,7 @@ #include "ssl.h" -/* Reconnect timeout based on approxiamted cookie life-time */ +/* Reconnect timeout based on approximated cookie life-time */ #define RECONNECT_TIMEOUT (3600+600) #define RDESKTOP_LICENSE_STORE "/.local/share/rdesktop/licenses" @@ -68,12 +68,17 @@ 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 */ -int g_sizeopt = 0; /* If non-zero, a special size has been - requested. If 1, the geometry will be fetched - from _NET_WORKAREA. If negative, absolute value - specifies the percent of the whole screen. */ -int g_width = 800; -int g_height = 600; +int g_dpi = 0; /* device DPI: default not set */ + +/* Following variables holds the requested width and height for a + rdesktop window, this is sent upon connect and tells the server + what size of session we want to have. Set to decent defaults. */ +uint32 g_requested_session_width = 1024; +uint32 g_requested_session_height = 768; + +window_size_type_t g_window_size_type = Fixed; + + int g_xpos = 0; int g_ypos = 0; int g_pos = 0; /* 0 position unspecified, @@ -84,7 +89,6 @@ int g_server_depth = -1; int g_win_button_size = 0; /* If zero, disable single app mode */ RD_BOOL g_network_error = False; -RD_BOOL g_bitmap_compression = True; RD_BOOL g_sendmotion = True; RD_BOOL g_bitmap_cache = True; RD_BOOL g_bitmap_cache_persist_enable = False; @@ -97,6 +101,7 @@ RD_BOOL g_polygon_ellipse_orders = True; /* polygon / ellipse orders */ RD_BOOL g_fullscreen = False; RD_BOOL g_grab_keyboard = True; +RD_BOOL g_local_cursor = False; RD_BOOL g_hide_decorations = False; RDP_VERSION g_rdp_version = RDP_V5; /* Default to version 5 */ RD_BOOL g_rdpclip = True; @@ -109,11 +114,12 @@ RD_BOOL g_use_password_as_pin = False; char g_seamless_shell[512]; char g_seamless_spawn_cmd[512]; +char g_tls_version[4]; RD_BOOL g_seamless_persistent_mode = True; RD_BOOL g_user_quit = False; uint32 g_embed_wnd; -uint32 g_rdp5_performanceflags = - RDP5_NO_WALLPAPER | RDP5_NO_FULLWINDOWDRAG | RDP5_NO_MENUANIMATIONS | RDP5_NO_CURSOR_SHADOW; +uint32 g_rdp5_performanceflags = (PERF_DISABLE_FULLWINDOWDRAG | + PERF_DISABLE_MENUANIMATIONS | PERF_ENABLE_FONT_SMOOTHING); /* Session Directory redirection */ RD_BOOL g_redirect = False; char *g_redirect_server; @@ -136,14 +142,14 @@ RD_BOOL g_reconnect_loop = False; uint8 g_client_random[SEC_RANDOM_SIZE]; RD_BOOL g_pending_resize = False; +RD_BOOL g_pending_resize_defer = True; +struct timeval g_pending_resize_defer_timer = { 0 }; #ifdef WITH_RDPSND RD_BOOL g_rdpsnd = False; #endif -#ifdef HAVE_ICONV char g_codepage[16] = ""; -#endif char *g_sc_csp_name = NULL; /* Smartcard CSP name */ char *g_sc_reader_name = NULL; @@ -154,55 +160,44 @@ extern uint32 g_num_devices; extern char *g_rdpdr_clientname; -#ifdef RDP2VNC -extern int rfb_port; -extern int defer_time; -void -rdp2vnc_connect(char *server, uint32 flags, char *domain, char *password, - char *shell, char *directory); -#endif /* Display usage information */ static void usage(char *program) { fprintf(stderr, "rdesktop: A Remote Desktop Protocol client.\n"); fprintf(stderr, - "Version " PACKAGE_VERSION ". Copyright (C) 1999-2011 Matthew Chapman et al.\n"); + "Version " PACKAGE_VERSION ". Copyright (C) 1999-2016 Matthew Chapman et al.\n"); fprintf(stderr, "See http://www.rdesktop.org/ for more information.\n\n"); fprintf(stderr, "Usage: %s [options] server[:port]\n", program); -#ifdef RDP2VNC - fprintf(stderr, " -V: vnc port\n"); - fprintf(stderr, " -Q: defer time (ms)\n"); -#endif fprintf(stderr, " -u: user name\n"); fprintf(stderr, " -d: domain\n"); - fprintf(stderr, " -s: shell / seamless application to start remotly\n"); + fprintf(stderr, " -s: shell / seamless application to start remotely\n"); fprintf(stderr, " -c: working directory\n"); fprintf(stderr, " -p: password (- to prompt)\n"); fprintf(stderr, " -n: client hostname\n"); fprintf(stderr, " -k: keyboard layout on server (en-us, de, sv, etc.)\n"); - fprintf(stderr, " -g: desktop geometry (WxH)\n"); + fprintf(stderr, " -g: desktop geometry (WxH[@DPI][+X[+Y]])\n"); #ifdef WITH_SCARD fprintf(stderr, " -i: enables smartcard authentication, password is used as pin\n"); #endif fprintf(stderr, " -f: full-screen mode\n"); fprintf(stderr, " -b: force bitmap updates\n"); -#ifdef HAVE_ICONV fprintf(stderr, " -L: local codepage\n"); -#endif fprintf(stderr, " -A: path to SeamlessRDP shell, this enables SeamlessRDP mode\n"); + fprintf(stderr, " -V: tls version (1.0, 1.1, 1.2, defaults to negotiation)\n"); fprintf(stderr, " -B: use BackingStore of X-server (if available)\n"); fprintf(stderr, " -e: disable encryption (French TS)\n"); fprintf(stderr, " -E: disable encryption from client to server\n"); fprintf(stderr, " -m: do not send motion events\n"); + fprintf(stderr, " -M: use local mouse cursor\n"); fprintf(stderr, " -C: use private colour map\n"); fprintf(stderr, " -D: hide window manager decorations\n"); fprintf(stderr, " -K: keep window manager key bindings\n"); fprintf(stderr, " -S: caption button size (single application mode)\n"); fprintf(stderr, " -T: window title\n"); fprintf(stderr, " -t: disable use of remote ctrl\n"); - fprintf(stderr, " -N: enable numlock syncronization\n"); + fprintf(stderr, " -N: enable numlock synchronization\n"); fprintf(stderr, " -X: embed into another window with a given id.\n"); fprintf(stderr, " -a: connection colour depth\n"); fprintf(stderr, " -z: enable rdp compression\n"); @@ -241,14 +236,14 @@ fprintf(stderr, " '-r scard[:\"Scard Name\"=\"Alias Name[;Vendor Name]\"[,...]]\n"); fprintf(stderr, " example: -r scard:\"eToken PRO 00 00\"=\"AKS ifdh 0\"\n"); fprintf(stderr, - " \"eToken PRO 00 00\" -> Device in Linux/Unix enviroment\n"); + " \"eToken PRO 00 00\" -> Device in GNU/Linux and UNIX environment\n"); fprintf(stderr, - " \"AKS ifdh 0\" -> Device shown in Windows enviroment \n"); + " \"AKS ifdh 0\" -> Device shown in Windows environment \n"); fprintf(stderr, " example: -r scard:\"eToken PRO 00 00\"=\"AKS ifdh 0;AKS\"\n"); fprintf(stderr, - " \"eToken PRO 00 00\" -> Device in Linux/Unix enviroment\n"); + " \"eToken PRO 00 00\" -> Device in GNU/Linux and UNIX environment\n"); fprintf(stderr, - " \"AKS ifdh 0\" -> Device shown in Windows enviroment \n"); + " \"AKS ifdh 0\" -> Device shown in Microsoft Windows environment \n"); fprintf(stderr, " \"AKS\" -> Device vendor name \n"); #endif @@ -262,11 +257,12 @@ fprintf(stderr, " is used to authenticate the user by smartcard\n"); fprintf(stderr, - " sc-container-name Specifies the container name, this is usally the username\n"); + " sc-container-name Specifies the container name, this is usually the username\n"); fprintf(stderr, " sc-reader-name Smartcard reader name to use\n"); fprintf(stderr, " sc-card-name Specifies the card name of the smartcard to use\n"); #endif + fprintf(stderr, " -v: enable verbose logging\n"); fprintf(stderr, "\n"); @@ -280,7 +276,7 @@ switch (reason) { - case exDiscReasonNoInfo: + case ERRINFO_NO_INFO: text = "No information available"; if (deactivated) retval = EX_OK; @@ -288,134 +284,209 @@ retval = EXRD_UNKNOWN; break; - case exDiscReasonAPIInitiatedDisconnect: - text = "Server initiated disconnect"; - retval = EXRD_API_DISCONNECT; + case ERRINFO_RPC_INITIATED_DISCONNECT: + text = "Administrator initiated disconnect"; + retval = EXRD_DISCONNECT_BY_ADMIN; break; - case exDiscReasonAPIInitiatedLogoff: - text = "Server initiated logoff"; - retval = EXRD_API_LOGOFF; + case ERRINFO_RPC_INITIATED_LOGOFF: + text = "Administrator initiated logout"; + retval = EXRD_LOGOFF_BY_ADMIN; break; - case exDiscReasonServerIdleTimeout: - text = "Server idle timeout reached"; + case ERRINFO_IDLE_TIMEOUT: + text = "Server idle session time limit reached"; retval = EXRD_IDLE_TIMEOUT; break; - case exDiscReasonServerLogonTimeout: - text = "Server logon timeout reached"; + case ERRINFO_LOGON_TIMEOUT: + text = "Server active session time limit reached"; retval = EXRD_LOGON_TIMEOUT; break; - case exDiscReasonReplacedByOtherConnection: + case ERRINFO_DISCONNECTED_BY_OTHERCONNECTION: text = "The session was replaced"; retval = EXRD_REPLACED; break; - case exDiscReasonOutOfMemory: + case ERRINFO_OUT_OF_MEMORY: text = "The server is out of memory"; retval = EXRD_OUT_OF_MEM; break; - case exDiscReasonServerDeniedConnection: + case ERRINFO_SERVER_DENIED_CONNECTION: text = "The server denied the connection"; retval = EXRD_DENIED; break; - case exDiscReasonServerDeniedConnectionFips: - text = "The server denied the connection for security reason"; + case ERRINFO_SERVER_DENIED_CONNECTION_FIPS: + text = "The server denied the connection for security reasons"; retval = EXRD_DENIED_FIPS; break; - case exDiscReasonServerInsufficientPrivileges: + case ERRINFO_SERVER_INSUFFICIENT_PRIVILEGES: text = "The user cannot connect to the server due to insufficient access privileges."; retval = EXRD_INSUFFICIENT_PRIVILEGES; break; - case exDiscReasonServerFreshCredentialsRequired: + case ERRINFO_SERVER_FRESH_CREDENTIALS_REQUIRED: text = "The server does not accept saved user credentials and requires that the user enter their credentials for each connection."; retval = EXRD_FRESH_CREDENTIALS_REQUIRED; break; - case exDiscReasonRPCInitiatedDisconnectByUser: - text = "Disconnect initiated by administration tool"; - retval = EXRD_RPC_DISCONNECT_BY_USER; - break; - - case exDiscReasonByUser: + case ERRINFO_RPC_INITIATED_DISCONNECT_BYUSER: text = "Disconnect initiated by user"; retval = EXRD_DISCONNECT_BY_USER; break; - case exDiscReasonLicenseInternal: + case ERRINFO_LOGOFF_BYUSER: + text = "Logout initiated by user"; + retval = EXRD_LOGOFF_BY_USER; + break; + + case ERRINFO_LICENSE_INTERNAL: text = "Internal licensing error"; retval = EXRD_LIC_INTERNAL; break; - case exDiscReasonLicenseNoLicenseServer: + case ERRINFO_LICENSE_NO_LICENSE_SERVER: text = "No license server available"; retval = EXRD_LIC_NOSERVER; break; - case exDiscReasonLicenseNoLicense: + case ERRINFO_LICENSE_NO_LICENSE: text = "No valid license available"; retval = EXRD_LIC_NOLICENSE; break; - case exDiscReasonLicenseErrClientMsg: - text = "Invalid licensing message"; + case ERRINFO_LICENSE_BAD_CLIENT_MSG: + text = "Invalid licensing message from client"; retval = EXRD_LIC_MSG; break; - case exDiscReasonLicenseHwidDoesntMatchLicense: - text = "Hardware id doesn't match software license"; + case ERRINFO_LICENSE_HWID_DOESNT_MATCH_LICENSE: + text = "The client license has been modified and does no longer match the hardware ID"; retval = EXRD_LIC_HWID; break; - case exDiscReasonLicenseErrClientLicense: - text = "Client license error"; + case ERRINFO_LICENSE_BAD_CLIENT_LICENSE: + text = "The client license is in an invalid format"; retval = EXRD_LIC_CLIENT; break; - case exDiscReasonLicenseCantFinishProtocol: + case ERRINFO_LICENSE_CANT_FINISH_PROTOCOL: text = "Network error during licensing protocol"; retval = EXRD_LIC_NET; break; - case exDiscReasonLicenseClientEndedProtocol: + case ERRINFO_LICENSE_CLIENT_ENDED_PROTOCOL: text = "Licensing protocol was not completed"; retval = EXRD_LIC_PROTO; break; - case exDiscReasonLicenseErrClientEncryption: + case ERRINFO_LICENSE_BAD_CLIENT_ENCRYPTION: text = "Incorrect client license encryption"; retval = EXRD_LIC_ENC; break; - case exDiscReasonLicenseCantUpgradeLicense: - text = "Can't upgrade license"; + case ERRINFO_LICENSE_CANT_UPGRADE_LICENSE: + text = "Can't upgrade or renew license"; retval = EXRD_LIC_UPGRADE; break; - case exDiscReasonLicenseNoRemoteConnections: + case ERRINFO_LICENSE_NO_REMOTE_CONNECTIONS: text = "The server is not licensed to accept remote connections"; retval = EXRD_LIC_NOREMOTE; break; + case ERRINFO_CB_DESTINATION_NOT_FOUND: + text = "The target endpoint chosen by the broker could not be found"; + retval = EXRD_CB_DEST_NOT_FOUND; + break; + + case ERRINFO_CB_LOADING_DESTINATION: + text = "The target endpoint is disconnecting from the broker"; + retval = EXRD_CB_DEST_LOADING; + break; + + case ERRINFO_CB_REDIRECTING_TO_DESTINATION: + text = "Error occurred while being redirected by broker"; + retval = EXRD_CB_REDIR_DEST; + break; + + case ERRINFO_CB_SESSION_ONLINE_VM_WAKE: + text = "Error while the endpoint VM was being awakened by the broker"; + retval = EXRD_CB_VM_WAKE; + break; + + case ERRINFO_CB_SESSION_ONLINE_VM_BOOT: + text = "Error while the endpoint VM was being started by the broker"; + retval = EXRD_CB_VM_BOOT; + break; + + case ERRINFO_CB_SESSION_ONLINE_VM_NO_DNS: + text = "The IP address of the endpoint VM could not be determined by the broker"; + retval = EXRD_CB_VM_NODNS; + break; + + case ERRINFO_CB_DESTINATION_POOL_NOT_FREE: + text = "No available endpoints in the connection broker pool"; + retval = EXRD_CB_DEST_POOL_NOT_FREE; + break; + + case ERRINFO_CB_CONNECTION_CANCELLED: + text = "Connection processing cancelled by the broker"; + retval = EXRD_CB_CONNECTION_CANCELLED; + break; + + case ERRINFO_CB_CONNECTION_ERROR_INVALID_SETTINGS: + text = "The connection settings could not be validated by the broker"; + retval = EXRD_CB_INVALID_SETTINGS; + break; + + case ERRINFO_CB_SESSION_ONLINE_VM_BOOT_TIMEOUT: + text = "Timeout while the endpoint VM was being started by the broker"; + retval = EXRD_CB_VM_BOOT_TIMEOUT; + break; + + case ERRINFO_CB_SESSION_ONLINE_VM_SESSMON_FAILED: + text = "Session monitoring error while the endpoint VM was being started by the broker"; + retval = EXRD_CB_VM_BOOT_SESSMON_FAILED; + break; + + case ERRINFO_REMOTEAPPSNOTENABLED: + text = "The server can only host Remote Applications"; + retval = EXRD_RDP_REMOTEAPPSNOTENABLED; + break; + + case ERRINFO_UPDATESESSIONKEYFAILED: + text = "Update of session keys failed"; + retval = EXRD_RDP_UPDATESESSIONKEYFAILED; + break; + + case ERRINFO_DECRYPTFAILED: + text = "Decryption or session key creation failed"; + retval = EXRD_RDP_DECRYPTFAILED; + break; + + case ERRINFO_ENCRYPTFAILED: + text = "Encryption failed"; + retval = EXRD_RDP_ENCRYPTFAILED; + break; + default: - if (reason > 0x1000 && reason < 0x7fff) - { - text = "Internal protocol error"; - } - else - { - text = "Unknown reason"; - } + text = "Unknown reason"; retval = EXRD_UNKNOWN; } - if (reason != exDiscReasonNoInfo) + + if (reason > 0x1000 && reason < 0x7fff && retval == EXRD_UNKNOWN) + { + fprintf(stderr, "Internal protocol error: %x", reason); + } + else if (reason != ERRINFO_NO_INFO) + { fprintf(stderr, "disconnect: %s.\n", text); + } return retval; } @@ -423,6 +494,8 @@ static void rdesktop_reset_state(void) { + g_pending_resize_defer = True; + rdp_reset_state(); #ifdef WITH_SCARD scard_reset_state(); @@ -438,11 +511,22 @@ struct termios tios; RD_BOOL ret = False; int istty = 0; + const char *prompt; char *p; + + if (g_use_password_as_pin) + { + prompt = "Smart card PIN: "; + } + else + { + prompt = "Password: "; + } + if (tcgetattr(STDIN_FILENO, &tios) == 0) { - fprintf(stderr, "Password: "); + fputs(prompt, stderr); tios.c_lflag &= ~ECHO; tcsetattr(STDIN_FILENO, TCSANOW, &tios); istty = 1; @@ -497,7 +581,7 @@ } else { - /* dns name or IPv4 style address format - server.example.com:port or 1.2.3.4:port */ + /* DNS name or IPv4 style address format - server.example.com:port or 1.2.3.4:port */ p = strchr(server, ':'); if (p != NULL) { @@ -516,6 +600,173 @@ } +// [WxH|P%|W%xH%][@DPI][+X[+Y]]|workarea +int +parse_geometry_string(const char *optarg) +{ + sint32 value; + const char *ps; + char *pe; + + /* special keywords */ + if (strcmp(optarg, "workarea") == 0) + { + g_window_size_type = Workarea; + return 0; + } + + /* parse first integer */ + ps = optarg; + value = strtol(ps, &pe, 10); + if (ps == pe || value <= 0) + { + logger(Core, Error, "invalid geometry, expected positive integer for width"); + return -1; + } + + g_requested_session_width = value; + ps = pe; + + /* expect % or x */ + if (*ps != '%' && *ps != 'x') + { + logger(Core, Error, "invalid geometry, expected '%%' or 'x' after width"); + return -1; + } + + if (*ps == '%') + { + g_window_size_type = PercentageOfScreen; + ps++; + pe++; + } + + if (*ps == 'x') + { + ps++; + value = strtol(ps, &pe, 10); + if (ps == pe || value <= 0) + { + logger(Core, Error, + "invalid geometry, expected positive integer for height"); + return -1; + } + + g_requested_session_height = value; + ps = pe; + + if (*ps == '%' && g_window_size_type == Fixed) + { + logger(Core, Error, "invalid geometry, unexpected '%%' after height"); + return -1; + } + + if (g_window_size_type == PercentageOfScreen) + { + if (*ps != '%') + { + logger(Core, Error, "invalid geometry, expected '%%' after height"); + return -1; + } + ps++; + pe++; + } + } + else + { + if (g_window_size_type == PercentageOfScreen) + { + /* percentage of screen used for both width and height */ + g_requested_session_height = g_requested_session_width; + } + else + { + logger(Core, Error, "invalid geometry, missing height (WxH)"); + return -1; + } + } + + /* parse optional dpi */ + if (*ps == '@') + { + ps++; + pe++; + value = strtol(ps, &pe, 10); + if (ps == pe || value <= 0) + { + logger(Core, Error, "invalid geometry, expected positive integer for DPI"); + return -1; + } + + g_dpi = value; + ps = pe; + } + + /* parse optional window position */ + if (*ps == '+' || *ps == '-') + { + /* parse x position */ + value = strtol(ps, &pe, 10); + if (ps == pe) + { + logger(Core, Error, "invalid geometry, expected an integer for X position"); + return -1; + } + + g_pos |= (value < 0) ? 2 : 1; + g_xpos = value; + ps = pe; + } + + if (*ps == '+' || *ps == '-') + { + /* parse y position */ + value = strtol(ps, &pe, 10); + if (ps == pe) + { + logger(Core, Error, "invalid geometry, expected an integer for Y position"); + return -1; + } + g_pos |= (value < 0) ? 4 : 1; + g_ypos = value; + ps = pe; + } + + if (*pe != '\0') + { + logger(Core, Error, "invalid geometry, unexpected characters at end of string"); + return -1; + } + return 0; +} + +static void +setup_user_requested_session_size() +{ + switch (g_window_size_type) + { + case Fullscreen: + ui_get_screen_size(&g_requested_session_width, &g_requested_session_height); + break; + + case Workarea: + ui_get_workarea_size(&g_requested_session_width, + &g_requested_session_height); + break; + + case Fixed: + break; + + case PercentageOfScreen: + ui_get_screen_size_from_percentage(g_requested_session_width, + g_requested_session_height, + &g_requested_session_width, + &g_requested_session_height); + break; + } +} + + /* Client program */ int main(int argc, char *argv[]) @@ -537,6 +788,9 @@ char *rdpsnd_optarg = NULL; #endif + /* setup debug logging from environment */ + logger_set_subjects(getenv("RDESKTOP_DEBUG")); + #ifdef HAVE_LOCALE_H /* Set locale according to environment */ locale = setlocale(LC_ALL, ""); @@ -560,52 +814,33 @@ | RDP_INFO_UNICODE | RDP_INFO_MAXIMIZESHELL | RDP_INFO_ENABLEWINDOWSKEY; prompt_password = False; - g_seamless_spawn_cmd[0] = domain[0] = g_password[0] = shell[0] = directory[0] = 0; + g_seamless_spawn_cmd[0] = g_tls_version[0] = domain[0] = g_password[0] = shell[0] = directory[0] = 0; g_embed_wnd = 0; g_num_devices = 0; -#ifdef RDP2VNC -#define VNCOPT "V:Q:" -#else -#define VNCOPT -#endif while ((c = getopt(argc, argv, - VNCOPT "A:u:L:d:s:c:p:n:k:g:o:fbBeEitmzCDKS:T:NX:a:x:Pr:045h?")) != -1) + "A:V:u:L:d:s:c:p:n:k:g:o:fbBeEitmMzCDKS:T:NX:a:x:Pr:045vh?")) != -1) { switch (c) { -#ifdef RDP2VNC - case 'V': - rfb_port = strtol(optarg, NULL, 10); - if (rfb_port < 100) - rfb_port += 5900; - break; - - case 'Q': - defer_time = strtol(optarg, NULL, 10); - if (defer_time < 0) - defer_time = 0; - break; -#endif - case 'A': g_seamless_rdp = True; STRNCPY(g_seamless_shell, optarg, sizeof(g_seamless_shell)); break; + case 'V': + STRNCPY(g_tls_version, optarg, sizeof(g_tls_version)); + break; + case 'u': g_username = (char *) xmalloc(strlen(optarg) + 1); - STRNCPY(g_username, optarg, strlen(optarg) + 1); + strcpy(g_username, optarg); username_option = 1; break; case 'L': -#ifdef HAVE_ICONV STRNCPY(g_codepage, optarg, sizeof(g_codepage)); -#else - error("iconv support not available\n"); -#endif break; case 'd': @@ -657,50 +892,14 @@ case 'g': geometry_option = True; g_fullscreen = False; - if (!strcmp(optarg, "workarea")) - { - g_sizeopt = 1; - break; - } - - g_width = strtol(optarg, &p, 10); - if (g_width <= 0) - { - error("invalid geometry\n"); - return EX_USAGE; - } - - if (*p == 'x') - g_height = strtol(p + 1, &p, 10); - - if (g_height <= 0) + if (parse_geometry_string(optarg) != 0) { - error("invalid geometry\n"); return EX_USAGE; } - - if (*p == '%') - { - g_sizeopt = -g_width; - g_width = 800; - p++; - } - - if (*p == '+' || *p == '-') - { - g_pos |= (*p == '-') ? 2 : 1; - g_xpos = strtol(p, &p, 10); - - } - if (*p == '+' || *p == '-') - { - g_pos |= (*p == '-') ? 4 : 1; - g_ypos = strtol(p, NULL, 10); - } - break; case 'f': + g_window_size_type = Fullscreen; g_fullscreen = True; break; @@ -721,6 +920,9 @@ case 'm': g_sendmotion = False; break; + case 'M': + g_local_cursor = True; + break; case 'C': g_owncolmap = True; @@ -745,7 +947,7 @@ if (*p) { - error("invalid button size\n"); + logger(Core, Error, "invalid button size"); return EX_USAGE; } @@ -770,37 +972,38 @@ g_server_depth != 15 && g_server_depth != 24 && g_server_depth != 32) { - error("Invalid server colour depth.\n"); + logger(Core, Error, + "Invalid server colour depth specified"); return EX_USAGE; } break; case 'z': - DEBUG(("rdp compression enabled\n")); + logger(Core, Debug, "rdp compression enabled"); flags |= (RDP_INFO_COMPRESSION | RDP_INFO_COMPRESSION2); break; case 'x': if (str_startswith(optarg, "m")) /* modem */ { - g_rdp5_performanceflags = RDP5_NO_CURSOR_SHADOW | - RDP5_NO_WALLPAPER | RDP5_NO_FULLWINDOWDRAG | - RDP5_NO_MENUANIMATIONS | RDP5_NO_THEMING; + g_rdp5_performanceflags = (PERF_DISABLE_CURSOR_SHADOW | + PERF_DISABLE_WALLPAPER | + PERF_DISABLE_FULLWINDOWDRAG | + PERF_DISABLE_MENUANIMATIONS | + PERF_DISABLE_THEMING); } else if (str_startswith(optarg, "b")) /* broadband */ { - g_rdp5_performanceflags = - RDP5_NO_CURSOR_SHADOW | RDP5_NO_WALLPAPER; + g_rdp5_performanceflags = (PERF_DISABLE_WALLPAPER | + PERF_ENABLE_FONT_SMOOTHING); } - else if (str_startswith(optarg, "l")) /* lan */ + else if (str_startswith(optarg, "l")) /* LAN */ { - g_rdp5_performanceflags = - RDP5_NO_CURSOR_SHADOW | RDP5_DISABLE_NOTHING; + g_rdp5_performanceflags = PERF_ENABLE_FONT_SMOOTHING; } else { - g_rdp5_performanceflags = - RDP5_NO_CURSOR_SHADOW | strtol(optarg, NULL, 16); + g_rdp5_performanceflags = strtol(optarg, NULL, 16); } break; @@ -831,14 +1034,16 @@ } #else - warning("Not compiled with sound support\n"); + logger(Core, Warning, + "Not compiled with sound support"); #endif if (str_startswith(optarg, "off")) #ifdef WITH_RDPSND g_rdpsnd = False; #else - warning("Not compiled with sound support\n"); + logger(Core, Warning, + "Not compiled with sound support"); #endif optarg = p; @@ -849,7 +1054,8 @@ #ifdef WITH_RDPSND g_rdpsnd = True; #else - warning("Not compiled with sound support\n"); + logger(Core, Warning, + "Not compiled with sound support"); #endif } } @@ -900,12 +1106,15 @@ #ifdef WITH_SCARD scard_enum_devices(&g_num_devices, optarg + 5); #else - warning("Not compiled with smartcard support\n"); + logger(Core, Warning, + "Not compiled with smartcard support\n"); #endif } else { - warning("Unknown -r argument\n\n\tPossible arguments are: comport, disk, lptport, printer, sound, clipboard, scard\n"); + logger(Core, Warning, + "Unknown -r argument '%s'. Possible arguments are: comport, disk, lptport, printer, sound, clipboard, scard", + optarg); } break; @@ -926,7 +1135,9 @@ char *p = strchr(optarg, '='); if (p == NULL) { - warning("Skipping option '%s' specified, lacks name=value format.\n"); + logger(Core, Warning, + "Skipping specified option '%s', lacks name=value format", + optarg); continue; } @@ -949,6 +1160,9 @@ } break; #endif + case 'v': + logger_set_verbose(1); + break; case 'h': case '?': default: @@ -962,6 +1176,12 @@ usage(argv[0]); return EX_USAGE; } + if (g_local_cursor) + { + /* there is no point wasting bandwidth on cursor shadows + * that we're just going to throw out anyway */ + g_rdp5_performanceflags |= PERF_DISABLE_CURSOR_SHADOW; + } STRNCPY(server, argv[optind], sizeof(server)); parse_server_and_port(server); @@ -975,36 +1195,37 @@ if (g_win_button_size) { - error("You cannot use -S and -A at the same time\n"); + logger(Core, Error, "You cannot use -S and -A at the same time"); return EX_USAGE; } - g_rdp5_performanceflags &= ~RDP5_NO_FULLWINDOWDRAG; + g_rdp5_performanceflags &= ~PERF_DISABLE_FULLWINDOWDRAG; if (geometry_option) { - error("You cannot use -g and -A at the same time\n"); + logger(Core, Error, "You cannot use -g and -A at the same time"); return EX_USAGE; } if (g_fullscreen) { - error("You cannot use -f and -A at the same time\n"); + logger(Core, Error, "You cannot use -f and -A at the same time"); return EX_USAGE; } if (g_hide_decorations) { - error("You cannot use -D and -A at the same time\n"); + logger(Core, Error, "You cannot use -D and -A at the same time"); return EX_USAGE; } if (g_embed_wnd) { - error("You cannot use -X and -A at the same time\n"); + logger(Core, Error, "You cannot use -X and -A at the same time"); return EX_USAGE; } if (g_rdp_version < RDP_V5) { - error("You cannot use -4 and -A at the same time\n"); + logger(Core, Error, "You cannot use -4 and -A at the same time"); return EX_USAGE; } - g_sizeopt = -100; + + g_window_size_type = Fullscreen; g_grab_keyboard = False; } @@ -1013,7 +1234,8 @@ pw = getpwuid(getuid()); if ((pw == NULL) || (pw->pw_name == NULL)) { - error("could not determine username, use -u\n"); + logger(Core, Error, + "could not determine username, use -u <username> to set one"); return EX_OSERR; } /* +1 for trailing \0 */ @@ -1022,7 +1244,6 @@ STRNCPY(g_username, pw->pw_name, pwlen); } -#ifdef HAVE_ICONV if (g_codepage[0] == 0) { if (setlocale(LC_CTYPE, "")) @@ -1034,13 +1255,12 @@ STRNCPY(g_codepage, DEFAULT_CODEPAGE, sizeof(g_codepage)); } } -#endif if (g_hostname[0] == 0) { if (gethostname(fullhostname, sizeof(fullhostname)) == -1) { - error("could not determine local hostname, use -n\n"); + logger(Core, Error, "could not determine local hostname, use -n\n"); return EX_OSERR; } @@ -1055,7 +1275,8 @@ { if (locale && xkeymap_from_locale(locale)) { - fprintf(stderr, "Autoselected keyboard map %s\n", g_keymapname); + logger(Core, Notice, "Autoselecting keyboard map '%s' from locale", + g_keymapname); } else { @@ -1065,9 +1286,18 @@ if (locale) xfree(locale); - - if (prompt_password && read_password(g_password, sizeof(g_password))) - flags |= RDP_INFO_AUTOLOGON; + if (prompt_password) + { + if (read_password(g_password, sizeof(g_password))) + { + flags |= RDP_INFO_AUTOLOGON; + } + else + { + logger(Core, Error, "Failed to read password or pin from stdin"); + return EX_OSERR; + } + } if (g_title[0] == 0) { @@ -1075,29 +1305,24 @@ strncat(g_title, server, sizeof(g_title) - sizeof("rdesktop - ")); } -#ifdef RDP2VNC - rdp2vnc_connect(server, flags, domain, g_password, shell, directory); - return EX_OK; -#else - /* Only startup ctrl functionality is seamless are used for now. */ if (g_use_ctrl && g_seamless_rdp) { if (ctrl_init(server, domain, g_username) < 0) { - error("Failed to initialize ctrl mode."); + logger(Core, Error, "Failed to initialize ctrl mode"); exit(1); } if (ctrl_is_slave()) { - fprintf(stdout, - "rdesktop in slave mode sending command to master process.\n"); + logger(Core, Notice, + "rdesktop in slave mode sending command to master process"); if (g_seamless_spawn_cmd[0]) return ctrl_send_command("seamless.spawn", g_seamless_spawn_cmd); - fprintf(stdout, "No command specified to be spawn in seamless mode.\n"); + logger(Core, Notice, "No command specified to be spawned in seamless mode"); return EX_USAGE; } } @@ -1107,13 +1332,19 @@ #ifdef WITH_RDPSND if (!rdpsnd_init(rdpsnd_optarg)) - warning("Initializing sound-support failed!\n"); + logger(Core, Warning, "Initializing sound-support failed"); #endif if (g_lspci_enabled) lspci_init(); rdpdr_init(); + + dvc_init(); + rdpedisp_init(); + + setup_user_requested_session_size(); + g_reconnect_loop = False; while (1) { @@ -1124,21 +1355,22 @@ STRNCPY(domain, g_redirect_domain, sizeof(domain)); xfree(g_username); g_username = (char *) xmalloc(strlen(g_redirect_username) + 1); - STRNCPY(g_username, g_redirect_username, strlen(g_redirect_username) + 1); + strcpy(g_username, g_redirect_username); STRNCPY(server, g_redirect_server, sizeof(server)); flags |= RDP_INFO_AUTOLOGON; - fprintf(stderr, "Redirected to %s@%s session %d.\n", - g_redirect_username, g_redirect_server, g_redirect_session_id); + logger(Core, Notice, "Redirected to %s@%s session %d.", + g_redirect_username, g_redirect_server, g_redirect_session_id); /* A redirect on SSL from a 2003 WTS will result in a 'connection reset by peer' and therefor we just clear this error before we connect to redirected server. */ g_network_error = False; - g_redirect = False; } - ui_init_connection(); + utils_apply_session_size_limitations(&g_requested_session_width, + &g_requested_session_height); + if (!rdp_connect (server, flags, domain, g_password, shell, directory, g_reconnect_loop)) { @@ -1151,8 +1383,9 @@ /* check if auto reconnect cookie has timed out */ if (time(NULL) - g_reconnect_random_ts > RECONNECT_TIMEOUT) { - fprintf(stderr, "Tried to reconnect for %d minutes, giving up.\n", - RECONNECT_TIMEOUT / 60); + logger(Core, Notice, + "Tried to reconnect for %d minutes, giving up.", + RECONNECT_TIMEOUT / 60); return EX_PROTOCOL; } @@ -1166,52 +1399,98 @@ continue; } - /* By setting encryption to False here, we have an encrypted login + /* By setting encryption to False here, we have an encrypted login packet but unencrypted transfer of other packets */ if (!g_packet_encryption) g_encryption_initial = g_encryption = False; - DEBUG(("Connection successful.\n")); + logger(Core, Verbose, "Connection successful"); rd_create_ui(); tcp_run_ui(True); deactivated = False; g_reconnect_loop = False; + ext_disc_reason = ERRINFO_UNSET; rdp_main_loop(&deactivated, &ext_disc_reason); tcp_run_ui(False); - DEBUG(("Disconnecting...\n")); + logger(Core, Verbose, "Disconnecting..."); rdp_disconnect(); - if (g_redirect) - continue; + /* Version <= Windows 2008 server have a different behaviour for + user initiated disconnected. Lets translate this specific + behaviour into the same as for later versions for proper + handling. + */ + if (deactivated == True && ext_disc_reason == ERRINFO_NO_INFO) + { + deactivated = 0; + ext_disc_reason = ERRINFO_LOGOFF_BYUSER; + } + else if (ext_disc_reason == 0) + { + /* We do not know how to handle error info value of 0 */ + ext_disc_reason = ERRINFO_UNSET; + } - /* handle network error and start autoreconnect */ - if (g_network_error && !deactivated) + /* Handler disconnect */ + if (g_user_quit || deactivated == True || ext_disc_reason != ERRINFO_UNSET) { - fprintf(stderr, - "Disconnected due to network error, retrying to reconnect for %d minutes.\n", - RECONNECT_TIMEOUT / 60); - g_network_error = False; - g_reconnect_loop = True; - continue; + /* We should exit the rdesktop instance */ + break; } + else + { + /* We should handle a reconnect for any reason */ + if (g_redirect) + { + logger(Core, Verbose, "Redirect reconnect loop triggered."); + } + else if (g_network_error) + { + if (g_reconnect_random_ts == 0) + { + /* If there is no auto reconnect cookie available + for reconnect, do not enter reconnect loop. Windows + 2016 server does not send any for unknown reasons. + */ + logger(Core, Notice, + "Disconnected due to network error, exiting..."); + break; + } - ui_seamless_end(); - ui_destroy_window(); + /* handle network error and start autoreconnect */ + logger(Core, Notice, + "Disconnected due to network error, retrying to reconnect for %d minutes.", + RECONNECT_TIMEOUT / 60); + g_network_error = False; + g_reconnect_loop = True; + } + else if (g_pending_resize) + { + /* Enter a reconnect loop if we have a pending resize request */ + logger(Core, Verbose, + "Resize reconnect loop triggered, new size %dx%d", + g_requested_session_width, g_requested_session_height); + g_pending_resize = False; + g_reconnect_loop = True; - /* Enter a reconnect loop if we have a pending resize request */ - if (g_pending_resize) - { - g_pending_resize = False; - g_reconnect_loop = True; - continue; + ui_seamless_end(); + ui_destroy_window(); + } + else + { + logger(Core, Debug, "Unhandled reconnect reason, exiting..."); + break; + } } - break; } + ui_seamless_end(); + ui_destroy_window(); + cache_save_state(); ui_deinit(); @@ -1220,7 +1499,6 @@ return handle_disconnect_reason(deactivated, ext_disc_reason); -#endif if (g_redirect_username) xfree(g_redirect_username); @@ -1317,7 +1595,7 @@ void *mem = malloc(size); if (mem == NULL) { - error("xmalloc %d\n", size); + logger(Core, Error, "xmalloc, failed to allocate %d bytes", size); exit(EX_UNAVAILABLE); } return mem; @@ -1329,7 +1607,7 @@ { if (ptr == NULL) { - error("unexpected null pointer. Out of memory?\n"); + logger(Core, Error, "unexpected null pointer. Out of memory?"); exit(EX_UNAVAILABLE); } } @@ -1341,7 +1619,7 @@ char *mem = strdup(s); if (mem == NULL) { - perror("strdup"); + logger(Core, Error, "xstrdup(), strdup() failed: %s", strerror(errno)); exit(EX_UNAVAILABLE); } return mem; @@ -1358,7 +1636,7 @@ mem = realloc(oldmem, size); if (mem == NULL) { - error("xrealloc %ld\n", size); + logger(Core, Error, "xrealloc, failed to reallocate %ld bytes", size); exit(EX_UNAVAILABLE); } return mem; @@ -1371,51 +1649,13 @@ free(mem); } -/* report an error */ -void -error(char *format, ...) -{ - va_list ap; - - fprintf(stderr, "ERROR: "); - - va_start(ap, format); - vfprintf(stderr, format, ap); - va_end(ap); -} - -/* report a warning */ -void -warning(char *format, ...) -{ - va_list ap; - - fprintf(stderr, "WARNING: "); - - va_start(ap, format); - vfprintf(stderr, format, ap); - va_end(ap); -} - -/* report an unimplemented protocol feature */ -void -unimpl(char *format, ...) -{ - va_list ap; - - fprintf(stderr, "NOT IMPLEMENTED: "); - - va_start(ap, format); - vfprintf(stderr, format, ap); - va_end(ap); -} - /* produce a hex dump */ void hexdump(unsigned char *p, unsigned int len) { unsigned char *line = p; - int i, thisline, offset = 0; + unsigned offset = 0; + int i, thisline; while (offset < len) { @@ -1444,7 +1684,7 @@ Needle may be escaped by a backslash, in that case we ignore that particular needle. return value: returns next src pointer, for - succesive executions, like in a while loop + successive executions, like in a while loop if retval is 0, then there are no more args. pitfalls: src is modified. 0x00 chars are inserted to @@ -1598,13 +1838,13 @@ if (pipe(fd) < 0) { - perror("pipe"); + logger(Core, Error, "subprocess(), pipe() failed: %s", strerror(errno)); return False; } if ((child = fork()) < 0) { - perror("fork"); + logger(Core, Error, "subprocess(), fork() failed: %s", strerror(errno)); return False; } @@ -1620,7 +1860,7 @@ /* Execute */ execvp(argv[0], argv); - perror("Error executing child"); + logger(Core, Error, "subprocess(), execvp() failed: %s", strerror(errno)); _exit(128); } @@ -1650,7 +1890,7 @@ register int divrem; - if (base < 36 || 2 > base) + if (base > 36 || 2 > base) base = 10; if (N < 0) @@ -1731,7 +1971,7 @@ path[sizeof(path) - 1] = '\0'; if (utils_mkdir_p(path, 0700) == -1) { - perror(path); + logger(Core, Error, "save_license(), utils_mkdir_p() failed: %s", strerror(errno)); return; } @@ -1740,7 +1980,7 @@ sec_hash_sha1_16(ho, hi, g_static_rdesktop_salt_16); sec_hash_to_string(hash, sizeof(hash), ho, sizeof(ho)); - /* write licence to {sha1}.cal.new, then atomically + /* write licence to {sha1}.cal.new, then atomically rename to {sha1}.cal */ snprintf(path, PATH_MAX, "%s" RDESKTOP_LICENSE_STORE "/%s.cal", home, hash); path[sizeof(path) - 1] = '\0'; @@ -1751,18 +1991,18 @@ fd = open(tmppath, O_WRONLY | O_CREAT | O_TRUNC, 0600); if (fd == -1) { - perror(tmppath); + logger(Core, Error, "save_license(), open() failed: %s", strerror(errno)); return; } if (write(fd, data, length) != length) { - perror(tmppath); + logger(Core, Error, "save_license(), write() failed: %s", strerror(errno)); unlink(tmppath); } else if (rename(tmppath, path) == -1) { - perror(path); + logger(Core, Error, "save_license(), rename() failed: %s", strerror(errno)); unlink(tmppath); } @@ -1773,12 +2013,63 @@ void rd_create_ui() { - /* only create a window if we dont have one intialized */ if (!ui_have_window()) { - if (!ui_create_window()) + /* create a window if we don't have one initialized */ + if (!ui_create_window(g_requested_session_width, g_requested_session_height)) exit(EX_OSERR); } + else + { + /* reset clipping if we already have a window */ + ui_reset_clip(); + } +} + +/* TODO: Replace with recursive mkdir */ +RD_BOOL rd_certcache_mkdir(void) +{ + char *home; + char certcache_dir[PATH_MAX]; + + home = getenv("HOME"); + + if (home == NULL) + return False; + + snprintf(certcache_dir, sizeof(certcache_dir) - 1, "%s/%s", home, ".local"); + + if ((mkdir(certcache_dir, S_IRWXU) == -1) && errno != EEXIST) + { + logger(Core, Error, "%s: mkdir() failed: %s", __func__, strerror(errno)); + return False; + } + + snprintf(certcache_dir, sizeof(certcache_dir) - 1, "%s/%s", home, ".local/share"); + + if ((mkdir(certcache_dir, S_IRWXU) == -1) && errno != EEXIST) + { + logger(Core, Error, "%s: mkdir() failed: %s", __func__, strerror(errno)); + return False; + } + + snprintf(certcache_dir, sizeof(certcache_dir) - 1, "%s/%s", home, ".local/share/rdesktop"); + + if ((mkdir(certcache_dir, S_IRWXU) == -1) && errno != EEXIST) + { + logger(Core, Error, "%s: mkdir() failed: %s", __func__, strerror(errno)); + return False; + } + + snprintf(certcache_dir, sizeof(certcache_dir) - 1, "%s/%s", home, ".local/share/rdesktop/certs"); + + if ((mkdir(certcache_dir, S_IRWXU) == -1) && errno != EEXIST) + { + logger(Core, Error, "%s: mkdir() failed: %s", __func__, strerror(errno)); + return False; + } + + return True; } /* Create the bitmap cache directory */ @@ -1797,7 +2088,7 @@ if ((mkdir(bmpcache_dir, S_IRWXU) == -1) && errno != EEXIST) { - perror(bmpcache_dir); + logger(Core, Error, "rd_pstcache_mkdir(), mkdir() failed: %s", strerror(errno)); return False; } @@ -1805,7 +2096,7 @@ if ((mkdir(bmpcache_dir, S_IRWXU) == -1) && errno != EEXIST) { - perror(bmpcache_dir); + logger(Core, Error, "rd_pstcache_mkdir(), mkdir() failed: %s", strerror(errno)); return False; } @@ -1826,7 +2117,8 @@ sprintf(fn, "%s/.rdesktop/%s", home, filename); fd = open(fn, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); if (fd == -1) - perror(fn); + logger(Core, Error, "rd_open_file(), open() failed: %s", strerror(errno)); + return fd; } diff -Nru rdesktop-1.8.6/rdesktop.h rdesktop-1.9.0/rdesktop.h --- rdesktop-1.8.6/rdesktop.h 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/rdesktop.h 2019-06-13 12:10:15.000000000 +0000 @@ -92,75 +92,51 @@ #endif /* rdesktop specific exit codes, lined up with disconnect PDU reasons */ -#define EXRD_API_DISCONNECT 1 -#define EXRD_API_LOGOFF 2 -#define EXRD_IDLE_TIMEOUT 3 -#define EXRD_LOGON_TIMEOUT 4 -#define EXRD_REPLACED 5 -#define EXRD_OUT_OF_MEM 6 -#define EXRD_DENIED 7 -#define EXRD_DENIED_FIPS 8 -#define EXRD_INSUFFICIENT_PRIVILEGES 9 -#define EXRD_FRESH_CREDENTIALS_REQUIRED 10 -#define EXRD_RPC_DISCONNECT_BY_USER 11 -#define EXRD_DISCONNECT_BY_USER 12 -#define EXRD_LIC_INTERNAL 16 -#define EXRD_LIC_NOSERVER 17 -#define EXRD_LIC_NOLICENSE 18 -#define EXRD_LIC_MSG 19 -#define EXRD_LIC_HWID 20 -#define EXRD_LIC_CLIENT 21 -#define EXRD_LIC_NET 22 -#define EXRD_LIC_PROTO 23 -#define EXRD_LIC_ENC 24 -#define EXRD_LIC_UPGRADE 25 -#define EXRD_LIC_NOREMOTE 26 +#define EXRD_DISCONNECT_BY_ADMIN 1 +#define EXRD_LOGOFF_BY_ADMIN 2 +#define EXRD_IDLE_TIMEOUT 3 +#define EXRD_LOGON_TIMEOUT 4 +#define EXRD_REPLACED 5 +#define EXRD_OUT_OF_MEM 6 +#define EXRD_DENIED 7 +#define EXRD_DENIED_FIPS 8 +#define EXRD_INSUFFICIENT_PRIVILEGES 9 +#define EXRD_FRESH_CREDENTIALS_REQUIRED 10 +#define EXRD_DISCONNECT_BY_USER 11 +#define EXRD_LOGOFF_BY_USER 12 + +#define EXRD_LIC_INTERNAL 16 +#define EXRD_LIC_NOSERVER 17 +#define EXRD_LIC_NOLICENSE 18 +#define EXRD_LIC_MSG 19 +#define EXRD_LIC_HWID 20 +#define EXRD_LIC_CLIENT 21 +#define EXRD_LIC_NET 22 +#define EXRD_LIC_PROTO 23 +#define EXRD_LIC_ENC 24 +#define EXRD_LIC_UPGRADE 25 +#define EXRD_LIC_NOREMOTE 26 + +#define EXRD_CB_DEST_NOT_FOUND 30 +#define EXRD_CB_DEST_LOADING 32 +#define EXRD_CB_REDIR_DEST 34 +#define EXRD_CB_VM_WAKE 35 +#define EXRD_CB_VM_BOOT 36 +#define EXRD_CB_VM_NODNS 37 +#define EXRD_CB_DEST_POOL_NOT_FREE 38 +#define EXRD_CB_CONNECTION_CANCELLED 39 +#define EXRD_CB_INVALID_SETTINGS 40 +#define EXRD_CB_VM_BOOT_TIMEOUT 41 +#define EXRD_CB_VM_BOOT_SESSMON_FAILED 42 + +#define EXRD_RDP_REMOTEAPPSNOTENABLED 50 +#define EXRD_RDP_UPDATESESSIONKEYFAILED 51 +#define EXRD_RDP_DECRYPTFAILED 52 +#define EXRD_RDP_ENCRYPTFAILED 53 /* other exit codes */ -#define EXRD_WINDOW_CLOSED 62 -#define EXRD_UNKNOWN 63 - -#ifdef WITH_DEBUG -#define DEBUG(args) printf args; -#else -#define DEBUG(args) -#endif - -#ifdef WITH_DEBUG_KBD -#define DEBUG_KBD(args) printf args; -#else -#define DEBUG_KBD(args) -#endif - -#ifdef WITH_DEBUG_RDP5 -#define DEBUG_RDP5(args) printf args; -#else -#define DEBUG_RDP5(args) -#endif - -#ifdef WITH_DEBUG_CLIPBOARD -#define DEBUG_CLIPBOARD(args) printf args; -#else -#define DEBUG_CLIPBOARD(args) -#endif - -#ifdef WITH_DEBUG_SOUND -#define DEBUG_SOUND(args) printf args; -#else -#define DEBUG_SOUND(args) -#endif - -#ifdef WITH_DEBUG_CHANNEL -#define DEBUG_CHANNEL(args) printf args; -#else -#define DEBUG_CHANNEL(args) -#endif - -#ifdef WITH_DEBUG_SCARD -#define DEBUG_SCARD(args) printf args; -#else -#define DEBUG_SCARD(args) -#endif +#define EXRD_WINDOW_CLOSED 62 +#define EXRD_UNKNOWN 63 #define STRNCPY(dst,src,n) { strncpy(dst,src,n-1); dst[n-1] = 0; } @@ -188,7 +164,7 @@ ((tvp)->tv_sec = (tvp)->tv_usec = 0) #endif -/* If configure does not define the endianess, try +/* If configure does not define the endianness, try to find it out */ #if !defined(L_ENDIAN) && !defined(B_ENDIAN) #if __BYTE_ORDER == __LITTLE_ENDIAN @@ -209,10 +185,8 @@ #endif #endif -#include "parse.h" +#include "utils.h" +#include "stream.h" #include "constants.h" #include "types.h" - -#ifndef MAKE_PROTO #include "proto.h" -#endif diff -Nru rdesktop-1.8.6/rdesktop.spec rdesktop-1.9.0/rdesktop.spec --- rdesktop-1.8.6/rdesktop.spec 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/rdesktop.spec 2019-09-18 09:03:44.000000000 +0000 @@ -1,6 +1,6 @@ Summary: Remote Desktop Protocol client Name: rdesktop -Version: 1.8.6 +Version: 1.9.0 Release: 1 License: GPL; see COPYING Group: Applications/Communications @@ -10,8 +10,7 @@ %description rdesktop is a client for Remote Desktop Protocol (RDP), used in a number of -Microsoft products including Windows NT Terminal Server, Windows 2000 Server, -Windows XP, Windows 2003 Server and Windows 2008r2. +Microsoft products. It is known to work with Microsoft Windows server versions ranging from NT 4 terminal server to Windows Server 2012 R2. %prep rm -rf $RPM_BUILD_ROOT diff -Nru rdesktop-1.8.6/rdp5.c rdesktop-1.9.0/rdp5.c --- rdesktop-1.8.6/rdp5.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/rdp5.c 2019-06-13 12:10:15.000000000 +0000 @@ -1,8 +1,9 @@ /* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. - Protocol services - RDP5 short form PDU processing + Protocol services - RDP Fast-Path PDU processing Copyright (C) Matthew Chapman <matthewc.unsw.edu.au> 1999-2008 Copyright 2003-2008 Erik Forsberg <forsberg@cendio.se> for Cendio AB + Copyright 2017 Karl Mikaelsson <derfian@cendio.se> for Cendio AB 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 @@ -24,11 +25,59 @@ extern RDPCOMP g_mppc_dict; + +static void +process_ts_fp_update_by_code(STREAM s, uint8 code) +{ + uint16 count, x, y; + + switch (code) + { + case FASTPATH_UPDATETYPE_ORDERS: + in_uint16_le(s, count); + process_orders(s, count); + break; + case FASTPATH_UPDATETYPE_BITMAP: + in_uint8s(s, 2); /* part length */ + process_bitmap_updates(s); + break; + case FASTPATH_UPDATETYPE_PALETTE: + in_uint8s(s, 2); /* uint16 = 2 */ + process_palette(s); + break; + case FASTPATH_UPDATETYPE_SYNCHRONIZE: + break; + case FASTPATH_UPDATETYPE_PTR_NULL: + ui_set_null_cursor(); + break; + case FASTPATH_UPDATETYPE_PTR_DEFAULT: + set_system_pointer(SYSPTR_DEFAULT); + break; + case FASTPATH_UPDATETYPE_PTR_POSITION: + in_uint16_le(s, x); + in_uint16_le(s, y); + ui_move_pointer(x, y); + break; + case FASTPATH_UPDATETYPE_COLOR: + process_colour_pointer_pdu(s); + break; + case FASTPATH_UPDATETYPE_CACHED: + process_cached_pointer_pdu(s); + break; + case FASTPATH_UPDATETYPE_POINTER: + process_new_pointer_pdu(s); + break; + default: + logger(Protocol, Warning, + "process_ts_fp_updates_by_code(), unhandled opcode %d", code); + } +} + void -rdp5_process(STREAM s) +process_ts_fp_updates(STREAM s) { - uint16 length, count, x, y; - uint8 type, ctype; + uint16 length; + uint8 hdr, code, frag, comp, ctype = 0; size_t next; uint8 *buf; @@ -36,33 +85,30 @@ struct stream *ns = &(g_mppc_dict.ns); struct stream *ts; -#if 0 - printf("RDP5 data:\n"); - hexdump(s->p, s_remaining(s)); -#endif + static STREAM assembled[16] = { 0 }; ui_begin_update(); while (!s_check_end(s)) { - in_uint8(s, type); - if (type & RDP5_COMPRESSED) - { - in_uint8(s, ctype); - in_uint16_le(s, length); - type ^= RDP5_COMPRESSED; - } - else - { - ctype = 0; - in_uint16_le(s, length); - } + /* Reading a number of TS_FP_UPDATE structures from the stream here.. */ + in_uint8(s, hdr); /* updateHeader */ + code = hdr & 0x0F; /* |- updateCode */ + frag = hdr & 0x30; /* |- fragmentation */ + comp = hdr & 0xC0; /* `- compression */ + + if (comp & FASTPATH_OUTPUT_COMPRESSION_USED) + in_uint8(s, ctype); /* compressionFlags */ + + in_uint16_le(s, length); /* length */ + g_next_packet = next = s_tell(s) + length; if (ctype & RDP_MPPC_COMPRESSED) { in_uint8p(s, buf, length); if (mppc_expand(buf, length, ctype, &roff, &rlen) == -1) - error("error while decompressing packet\n"); + logger(Protocol, Error, + "process_ts_fp_update_pdu(), error while decompressing packet"); /* allocate memory and copy the uncompressed data into the temporary stream */ s_realloc(ns, rlen); @@ -74,48 +120,36 @@ s_seek(ns, 0); s_push_layer(ns, rdp_hdr, 0); + length = rlen; ts = ns; } else ts = s; - switch (type) + if (frag == FASTPATH_FRAGMENT_SINGLE) + { + process_ts_fp_update_by_code(ts, code); + } + else /* Fragmented packet, we must reassemble */ { - case 0: /* update orders */ - in_uint16_le(ts, count); - process_orders(ts, count); - break; - case 1: /* update bitmap */ - in_uint8s(ts, 2); /* part length */ - process_bitmap_updates(ts); - break; - case 2: /* update palette */ - in_uint8s(ts, 2); /* uint16 = 2 */ - process_palette(ts); - break; - case 3: /* update synchronize */ - break; - case 5: /* null pointer */ - ui_set_null_cursor(); - break; - case 6: /* default pointer */ - break; - case 8: /* pointer position */ - in_uint16_le(ts, x); - in_uint16_le(ts, y); - ui_move_pointer(x, y); - break; - case 9: /* color pointer */ - process_colour_pointer_pdu(ts); - break; - case 10: /* cached pointer */ - process_cached_pointer_pdu(ts); - break; - case 11: - process_new_pointer_pdu(ts); - break; - default: - unimpl("RDP5 opcode %d\n", type); + if (assembled[code] == NULL) + { + assembled[code] = s_alloc(RDESKTOP_FASTPATH_MULTIFRAGMENT_MAX_SIZE); + } + + if (frag == FASTPATH_FRAGMENT_FIRST) + { + s_reset(assembled[code]); + } + + out_uint8stream(assembled[code], ts, length); + + if (frag == FASTPATH_FRAGMENT_LAST) + { + s_mark_end(assembled[code]); + s_seek(assembled[code], 0); + process_ts_fp_update_by_code(assembled[code], code); + } } s_seek(s, next); diff -Nru rdesktop-1.8.6/rdp.c rdesktop-1.9.0/rdp.c --- rdesktop-1.8.6/rdp.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/rdp.c 2019-09-19 07:18:39.000000000 +0000 @@ -4,6 +4,8 @@ Copyright (C) Matthew Chapman <matthewc.unsw.edu.au> 1999-2008 Copyright 2003-2011 Peter Astrand <astrand@cendio.se> for Cendio AB Copyright 2011-2018 Henrik Andersson <hean01@cendio.se> for Cendio AB + Copyright 2016 Alexander Zakharov <uglym8gmail.com> + Copyright 2017 Karl Mikaelsson <derfian@cendio.se> for Cendio AB 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 @@ -20,6 +22,8 @@ */ #include <time.h> +#include <iconv.h> + #ifndef _WIN32 #include <errno.h> #include <unistd.h> @@ -27,21 +31,11 @@ #include "rdesktop.h" #include "ssl.h" -#ifdef HAVE_ICONV -#ifdef HAVE_ICONV_H -#include <iconv.h> -#endif - -#ifndef ICONV_CONST -#define ICONV_CONST "" -#endif -#endif extern uint16 g_mcs_userid; extern char *g_username; extern char g_password[64]; extern char g_codepage[16]; -extern RD_BOOL g_bitmap_compression; extern RD_BOOL g_orders; extern RD_BOOL g_encryption; extern RD_BOOL g_desktop_save; @@ -50,19 +44,28 @@ 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 uint32 g_requested_session_width; +extern uint32 g_requested_session_height; extern RD_BOOL g_bitmap_cache; extern RD_BOOL g_bitmap_cache_persist_enable; extern RD_BOOL g_numlock_sync; extern RD_BOOL g_pending_resize; +extern RD_BOOL g_pending_resize_defer; +extern struct timeval g_pending_resize_defer_timer; extern RD_BOOL g_network_error; +extern time_t g_wait_for_deactivate_ts; + +extern RD_BOOL g_dynamic_session_resize; + +RD_BOOL g_exit_mainloop = False; size_t g_next_packet; uint32 g_rdp_shareid; extern RDPCOMP g_mppc_dict; +extern uint32 vc_chunk_size; + /* Session Directory support */ extern RD_BOOL g_redirect; extern char *g_redirect_server; @@ -85,67 +88,113 @@ extern time_t g_reconnect_random_ts; extern RD_BOOL g_has_reconnect_random; extern uint8 g_client_random[SEC_RANDOM_SIZE]; - -#if WITH_DEBUG static uint32 g_packetno; -#endif -#ifdef HAVE_ICONV -static RD_BOOL g_iconv_works = True; -#endif +extern RD_BOOL g_fullscreen; + +/* holds the actual session size reported by server */ +uint16 g_session_width; +uint16 g_session_height; + +static void rdp_out_unistr(STREAM s, char *string, int len); + +/* reads a TS_SHARECONTROLHEADER from stream, returns True of there is + a PDU available otherwise False */ +static RD_BOOL +rdp_ts_in_share_control_header(STREAM s, uint8 * type, uint16 * length) +{ + uint16 pdu_type; + uint16 pdu_source; + + UNUSED(pdu_source); + + in_uint16_le(s, *length); /* totalLength */ + + /* If the totalLength field equals 0x8000, then the Share + Control Header and any data that follows MAY be interpreted + as a T.128 FlowPDU as described in [T128] section 8.5 (the + ASN.1 structure definition is detailed in [T128] section + 9.1) and MUST be ignored. + */ + if (*length == 0x8000) + { + /* skip over this message in stream */ + g_next_packet += 8; + return False; + } + + in_uint16_le(s, pdu_type); /* pduType */ + *type = pdu_type & 0xf; + + /* XP omits pduSource for PDUTYPE_DEACTIVATEALLPDU for some reason */ + if (*length == 4) { + logger(Protocol, Debug, + "rdp_ts_in_share_control_header(), missing pduSource field for 0x%x PDU", + *type); + } else { + in_uint16(s, pdu_source); /* pduSource */ + } + + /* Give just the size of the data */ + if (*length >= 6) + *length -= 6; + else + *length = 0; + + return True; +} /* Receive an RDP packet */ static STREAM rdp_recv(uint8 * type) { + RD_BOOL is_fastpath; static STREAM rdp_s; - uint16 length, pdu_type; - uint8 rdpver; + uint16 length; - if ((g_next_packet == 0) || (g_next_packet == s_length(rdp_s))) + while (1) { - rdp_s = sec_recv(&rdpver); - if (rdp_s == NULL) - return NULL; - if (rdpver == 0xff) + /* fill stream with data if needed for parsing a new packet */ + if (g_next_packet == 0) { - g_next_packet = s_length(rdp_s); - *type = 0; - return rdp_s; + rdp_s = sec_recv(&is_fastpath); + if (rdp_s == NULL) + return NULL; + + if (is_fastpath == True) + { + /* process_ts_fp_updates moves g_next_packet */ + process_ts_fp_updates(rdp_s); + continue; + } + + g_next_packet = s_tell(rdp_s); } - else if (rdpver != 3) + else { - /* rdp5_process should move g_next_packet ok */ - rdp5_process(rdp_s); - *type = 0; - return rdp_s; + s_seek(rdp_s, g_next_packet); + if (s_check_end(rdp_s)) + { + g_next_packet = 0; + continue; + } } - g_next_packet = s_tell(rdp_s); - } - else - { - s_seek(rdp_s, g_next_packet); + /* parse a TS_SHARECONTROLHEADER */ + if (rdp_ts_in_share_control_header(rdp_s, type, &length) == False) + continue; + + break; } - in_uint16_le(rdp_s, length); - /* 32k packets are really 8, keepalive fix */ - if (length == 0x8000) + logger(Protocol, Debug, "rdp_recv(), RDP packet #%d, type 0x%x", ++g_packetno, *type); + + if (!s_check_rem(rdp_s, length)) { - g_next_packet += 8; - *type = 0; - return rdp_s; + rdp_protocol_error("not enough data for PDU", 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(rdp_s->data + g_next_packet, length); -#endif /* */ - - g_next_packet += length; + g_next_packet = s_tell(rdp_s) + length; return rdp_s; } @@ -186,66 +235,68 @@ sec_send(s, g_encryption ? SEC_ENCRYPT : 0); } +/* Output a string in Unicode with mandatory null termination. If + string is NULL or len is 0, write an unicode null termination to + stream. */ +static void +rdp_out_unistr_mandatory_null(STREAM s, char *string, int len) +{ + /* LEGACY: + * + * Do not write new code that uses this function, use the ones defined + * in stream.h for writing utf16 strings to a stream. + * + */ + if (string && len > 0) + rdp_out_unistr(s, string, len); + else + out_uint16_le(s, 0); +} + /* Output a string in Unicode */ -void +static void rdp_out_unistr(STREAM s, char *string, int len) { - if (string == NULL || len == 0) - return; + /* LEGACY: + * + * Do not write new code that uses this function, use the ones defined + * in stream.h for writing utf16 strings to a stream. + * + */ + static iconv_t icv_local_to_utf16; + size_t ibl, obl; + char *pin; + unsigned char *pout; -#ifdef HAVE_ICONV - size_t ibl = strlen(string), obl = len + 2; - static iconv_t iconv_h = (iconv_t) - 1; - char *pin = string, *pout; - size_t start; - start = s_tell(s); - out_uint8p(s, pout, len + 2); - // FIXME: hack so that s_seek() works - s_mark_end(s); - memset(pout, 0, len + 2); + if (string == NULL || len == 0) + return; - if (g_iconv_works) + // if not already open + if (!icv_local_to_utf16) { - if (iconv_h == (iconv_t) - 1) + icv_local_to_utf16 = iconv_open(WINDOWS_CODEPAGE, g_codepage); + if (icv_local_to_utf16 == (iconv_t) - 1) { - if ((iconv_h = iconv_open(WINDOWS_CODEPAGE, g_codepage)) == (iconv_t) - 1) - { - warning("rdp_out_unistr: iconv_open[%s -> %s] fail %p\n", - g_codepage, WINDOWS_CODEPAGE, iconv_h); - - g_iconv_works = False; - s_seek(s, start); - rdp_out_unistr(s, string, len); - return; - } - } - - 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; - s_seek(s, start); - rdp_out_unistr(s, string, len); - return; + logger(Protocol, Error, "rdo_out_unistr(), iconv_open[%s -> %s] fail %p", + g_codepage, WINDOWS_CODEPAGE, icv_local_to_utf16); + abort(); } } - else -#endif - { - int i = 0, j = 0; - len += 2; - while (i < len) - { - out_uint8(s, string[j++]); - out_uint8(s, 0); - i += 2; - } + ibl = strlen(string); + obl = len + 2; + pin = string; + out_uint8p(s, pout, len + 2); + + memset(pout, 0, len + 2); + + + if (iconv(icv_local_to_utf16, (char **) &pin, &ibl, (char **)&pout, &obl) == (size_t) - 1) + { + logger(Protocol, Error, "rdp_out_unistr(), iconv(2) fail, errno %d", errno); + abort(); } } @@ -256,15 +307,16 @@ void rdp_in_unistr(STREAM s, int in_len, char **string, uint32 * str_size) { - /* Dynamic allocate of destination string if not provided */ - *string = xmalloc(in_len * 2); - *str_size = in_len * 2; + static iconv_t icv_utf16_to_local; + size_t ibl, obl; + unsigned char *pin; + char *pout; struct stream packet = *s; if ((in_len < 0) || ((uint32)in_len >= (RD_UINT32_MAX / 2))) { - error("rdp_in_unistr(), length of unicode data is out of bounds."); + logger(Protocol, Error, "rdp_in_unistr(), length of unicode data is out of bounds."); abort(); } @@ -284,83 +336,61 @@ rdp_protocol_error("consume of unicode data from stream would overrun", &packet); } - -#ifdef HAVE_ICONV - size_t ibl = in_len, obl = *str_size - 1; - char *pin, *pout = *string; - static iconv_t iconv_h = (iconv_t) - 1; - size_t start; - - start = s_tell(s); - in_uint8p(s, pin, in_len); - - if (g_iconv_works) + // if not already open + if (!icv_utf16_to_local) { - if (iconv_h == (iconv_t) - 1) + icv_utf16_to_local = iconv_open(g_codepage, WINDOWS_CODEPAGE); + if (icv_utf16_to_local == (iconv_t) - 1) { - if ((iconv_h = iconv_open(g_codepage, WINDOWS_CODEPAGE)) == (iconv_t) - 1) - { - warning("rdp_in_unistr: iconv_open[%s -> %s] fail %p\n", - WINDOWS_CODEPAGE, g_codepage, iconv_h); - - g_iconv_works = False; - s_seek(s, start); - return rdp_in_unistr(s, in_len, string, str_size); - } + logger(Protocol, Error, "rdp_in_unistr(), iconv_open[%s -> %s] fail %p", + WINDOWS_CODEPAGE, g_codepage, icv_utf16_to_local); + abort(); } + } - if (iconv(iconv_h, (ICONV_CONST char **) &pin, &ibl, &pout, &obl) == (size_t) - 1) - { - if (errno == E2BIG) - { - warning("server sent an unexpectedly long string, truncating\n"); - } - else - { - warning("rdp_in_unistr: iconv fail, errno %d\n", errno); + /* Dynamic allocate of destination string if not provided */ + if (*string == NULL) + { - free(*string); - *string = NULL; - *str_size = 0; - } - } + *string = xmalloc(in_len * 2); + *str_size = in_len * 2; + } - *pout = 0; + ibl = in_len; + obl = *str_size - 1; + in_uint8p(s, pin, in_len); + pout = *string; - if (*string) - *str_size = pout - *string; - } - else -#endif + if (iconv(icv_utf16_to_local, (char **) &pin, &ibl, &pout, &obl) == (size_t) - 1) { - int i = 0; - int rem = 0; - uint32 len = in_len / 2; - - if (len > *str_size - 1) + if (errno == E2BIG) { - warning("server sent an unexpectedly long string, truncating\n"); - len = *str_size - 1; - rem = in_len - 2 * len; + logger(Protocol, Warning, + "rdp_in_unistr(), server sent an unexpectedly long string, truncating"); } - - while (i < len) + else { - in_uint8a(s, &string[i++], 1); - in_uint8s(s, 1); - } + logger(Protocol, Warning, "rdp_in_unistr(), iconv fail, errno %d", errno); - in_uint8s(s, rem); - string[len] = 0; - *str_size = len; + free(*string); + *string = NULL; + *str_size = 0; + } + abort(); } + + /* Always force the last byte to be a null */ + *pout = 0; + + if (*string) + *str_size = pout - *string; } -/* Parse a logon info packet */ +/* Send a Client Info PDU */ static void -rdp_send_logon_info(uint32 flags, char *domain, char *user, - char *password, char *program, char *directory) +rdp_send_client_info_pdu(uint32 flags, char *domain, char *user, + char *password, char *program, char *directory) { char *ipaddr = tcp_get_address(); /* length of string in TS_INFO_PACKET excludes null terminator */ @@ -375,7 +405,7 @@ int len_dll = 2 * strlen("C:\\WINNT\\System32\\mstscax.dll") + 2; int packetlen = 0; - uint32 sec_flags = g_encryption ? (SEC_LOGON_INFO | SEC_ENCRYPT) : SEC_LOGON_INFO; + uint32 sec_flags = g_encryption ? (SEC_INFO_PKT | SEC_ENCRYPT) : SEC_INFO_PKT; STREAM s; time_t t = time(NULL); time_t tzone; @@ -383,7 +413,7 @@ if (g_rdp_version == RDP_V4 || 1 == g_server_rdp_version) { - DEBUG_RDP5(("Sending RDP4-style Logon packet\n")); + logger(Protocol, Debug, "rdp_send_logon_info(), sending RDP4-style Logon packet"); s = sec_init(sec_flags, 18 + len_domain + len_user + len_password + len_program + len_directory + 10); @@ -395,21 +425,27 @@ 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); + + rdp_out_unistr_mandatory_null(s, domain, len_domain); + rdp_out_unistr_mandatory_null(s, user, len_user); + rdp_out_unistr_mandatory_null(s, password, len_password); + rdp_out_unistr_mandatory_null(s, program, len_program); + rdp_out_unistr_mandatory_null(s, directory, len_directory); } else { - DEBUG_RDP5(("Sending RDP5-style Logon packet\n")); + logger(Protocol, Debug, "rdp_send_logon_info(), sending RDP5-style Logon packet"); if (g_redirect == True && g_redirect_cookie_len > 0) { + flags &= ~RDP_INFO_PASSWORD_IS_SC_PIN; + flags |= RDP_INFO_AUTOLOGON; len_password = g_redirect_cookie_len; - len_password -= 2; /* substract 2 bytes which is added below */ + len_password -= 2; /* subtract 2 bytes which is added below */ + logger(Protocol, Debug, + "rdp_send_logon_info(), Using %d bytes redirect cookie as password", + g_redirect_cookie_len); } packetlen = @@ -427,8 +463,8 @@ 2 + len_program + /* AlternateShell */ 2 + len_directory + /* WorkingDir */ /* size of TS_EXTENDED_INFO_PACKET */ - 2 + /* clientAdressFamily */ - 2 + /* cbClientAdress */ + 2 + /* clientAddressFamily */ + 2 + /* cbClientAddress */ len_ip + /* clientAddress */ 2 + /* cbClientDir */ len_dll + /* clientDir */ @@ -448,7 +484,9 @@ s = sec_init(sec_flags, packetlen); - DEBUG_RDP5(("Called sec_init with packetlen %d\n", packetlen)); + + logger(Protocol, Debug, "rdp_send_logon_info(), called sec_init with packetlen %d", + packetlen); /* TS_INFO_PACKET */ out_uint32(s, 0); /* Code Page */ @@ -459,46 +497,28 @@ 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); /* mandatory 2 bytes null terminator */ + rdp_out_unistr_mandatory_null(s, domain, len_domain); + rdp_out_unistr_mandatory_null(s, user, len_user); - if (0 < len_user) - rdp_out_unistr(s, user, len_user); - else - out_uint16_le(s, 0); /* mandatory 2 bytes null terminator */ - - if (0 < len_password) + if (g_redirect == True && 0 < g_redirect_cookie_len) { - if (g_redirect == True && 0 < g_redirect_cookie_len) - { - out_uint8a(s, g_redirect_cookie, g_redirect_cookie_len); - } - else - { - rdp_out_unistr(s, password, len_password); - } + out_uint8a(s, g_redirect_cookie, g_redirect_cookie_len); } else - out_uint16_le(s, 0); /* mandatory 2 bytes null terminator */ + { + rdp_out_unistr_mandatory_null(s, password, len_password); + } - if (0 < len_program) - rdp_out_unistr(s, program, len_program); - else - out_uint16_le(s, 0); /* mandatory 2 bytes null terminator */ - if (0 < len_directory) - rdp_out_unistr(s, directory, len_directory); - else - out_uint16_le(s, 0); /* mandatory 2 bytes null terminator */ + rdp_out_unistr_mandatory_null(s, program, len_program); + rdp_out_unistr_mandatory_null(s, directory, len_directory); /* TS_EXTENDED_INFO_PACKET */ out_uint16_le(s, 2); /* clientAddressFamily = AF_INET */ - out_uint16_le(s, len_ip); /* cbClientAddress, Length of client ip */ - rdp_out_unistr(s, ipaddr, len_ip - 2); /* clientAddress */ + out_uint16_le(s, len_ip); /* cbClientAddress */ + rdp_out_unistr_mandatory_null(s, ipaddr, len_ip - 2); /* clientAddress */ out_uint16_le(s, len_dll); /* cbClientDir */ - rdp_out_unistr(s, "C:\\WINNT\\System32\\mstscax.dll", len_dll - 2); /* clientDir */ + rdp_out_unistr_mandatory_null(s, "C:\\WINNT\\System32\\mstscax.dll", len_dll - 2); /* clientDir */ /* TS_TIME_ZONE_INFORMATION */ tzone = (mktime(gmtime(&t)) - mktime(localtime(&t))) / 60; @@ -525,6 +545,8 @@ /* Client Auto-Reconnect */ if (g_has_reconnect_random) { + logger(Protocol, Debug, + "rdp_send_logon_info(), Sending auto-reconnect cookie."); out_uint16_le(s, 28); /* cbAutoReconnectLen */ /* ARC_CS_PRIVATE_PACKET */ out_uint32_le(s, 28); /* cbLen */ @@ -572,6 +594,8 @@ { STREAM s; + logger(Protocol, Debug, "%s()", __func__); + s = rdp_init_data(4); out_uint16_le(s, 1); /* type */ @@ -588,6 +612,8 @@ { STREAM s; + logger(Protocol, Debug, "%s()", __func__); + s = rdp_init_data(16); out_uint16_le(s, 1); /* number of events */ @@ -604,39 +630,43 @@ s_free(s); } -/* Send a client window information PDU */ +/* Send a Suppress Output PDU */ void -rdp_send_client_window_status(int status) +rdp_send_suppress_output_pdu(enum RDP_SUPPRESS_STATUS allowupdates) { STREAM s; - static int current_status = 1; + static enum RDP_SUPPRESS_STATUS current_status = ALLOW_DISPLAY_UPDATES; + + logger(Protocol, Debug, "%s()", __func__); - if (current_status == status) + if (current_status == allowupdates) return; s = rdp_init_data(12); - out_uint32_le(s, status); + out_uint8(s, allowupdates); /* allowDisplayUpdates */ + out_uint8s(s, 3); /* pad3Octets */ - switch (status) + switch (allowupdates) { - case 0: /* shut the server up */ + case SUPPRESS_DISPLAY_UPDATES: /* 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); + case ALLOW_DISPLAY_UPDATES: /* receive data again */ + out_uint16_le(s, 0); /* left */ + out_uint16_le(s, 0); /* top */ + out_uint16_le(s, g_session_width); /* right */ + out_uint16_le(s, g_session_height); /* bottom */ break; } s_mark_end(s); rdp_send_data(s, RDP_DATA_PDU_CLIENT_WINDOW_STATUS); s_free(s); - current_status = status; + current_status = allowupdates; } -/* Send persistent bitmap cache enumeration PDU's */ +/* Send persistent bitmap cache enumeration PDUs */ static void rdp_enum_bmpcache2(void) { @@ -644,6 +674,8 @@ HASH_KEY keylist[BMPCACHE2_NUM_PSTCELLS]; uint32 num_keys, offset, count, flags; + logger(Protocol, Debug, "%s()", __func__); + offset = 0; num_keys = pstcache_enumerate(2, keylist); @@ -687,6 +719,8 @@ { STREAM s; + logger(Protocol, Debug, "%s()", __func__); + s = rdp_init_data(8); out_uint16(s, 0); /* number of fonts */ @@ -699,93 +733,114 @@ s_free(s); } -/* Output general capability set */ +/* Output general capability set (TS_GENERAL_CAPABILITYSET) */ static void -rdp_out_general_caps(STREAM s) +rdp_out_ts_general_capabilityset(STREAM s) { + uint16 extraFlags = 0; + if (g_rdp_version >= RDP_V5) + { + extraFlags |= NO_BITMAP_COMPRESSION_HDR; + extraFlags |= AUTORECONNECT_SUPPORTED; + extraFlags |= LONG_CREDENTIALS_SUPPORTED; + extraFlags |= FASTPATH_OUTPUT_SUPPORTED; + } + 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_rdp_version >= RDP_V5) ? 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 */ + out_uint16_le(s, OSMAJORTYPE_WINDOWS); /* osMajorType */ + out_uint16_le(s, OSMINORTYPE_WINDOWSNT); /* osMinorType */ + out_uint16_le(s, TS_CAPS_PROTOCOLVERSION); /* protocolVersion (must be TS_CAPS_PROTOCOLVERSION) */ + out_uint16_le(s, 0); /* pad2OctetsA */ + out_uint16_le(s, 0); /* generalCompressionTypes (must be 0) */ + out_uint16_le(s, extraFlags); /* extraFlags */ + out_uint16_le(s, 0); /* updateCapabilityFlag (must be 0) */ + out_uint16_le(s, 0); /* remoteUnshareFlag (must be 0) */ + out_uint16_le(s, 0); /* generalCompressionLevel (must be 0) */ + out_uint8(s, 0); /* refreshRectSupport */ + out_uint8(s, 0); /* suppressOutputSupport */ } /* Output bitmap capability set */ static void -rdp_out_bitmap_caps(STREAM s) +rdp_out_ts_bitmap_capabilityset(STREAM s) { + logger(Protocol, Debug, "rdp_out_ts_bitmap_capabilityset(), %dx%d", + g_session_width, g_session_height); 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 */ + out_uint16_le(s, g_server_depth); /* preferredBitsPerPixel */ + out_uint16_le(s, 1); /* receive1BitPerPixel (ignored, should be 1) */ + out_uint16_le(s, 1); /* receive4BitPerPixel (ignored, should be 1) */ + out_uint16_le(s, 1); /* receive8BitPerPixel (ignored, should be 1) */ + out_uint16_le(s, g_session_width); /* desktopWidth */ + out_uint16_le(s, g_session_height); /* desktopHeight */ + out_uint16_le(s, 0); /* pad2Octets */ + out_uint16_le(s, 1); /* desktopResizeFlag */ + out_uint16_le(s, 1); /* bitmapCompressionFlag (must be 1) */ + out_uint8(s, 0); /* highColorFlags (ignored, should be 0) */ + out_uint8(s, 0); /* drawingFlags */ + out_uint16_le(s, 1); /* multipleRectangleSupport (must be 1) */ + out_uint16_le(s, 0); /* pad2OctetsB */ } /* Output order capability set */ static void -rdp_out_order_caps(STREAM s) +rdp_out_ts_order_capabilityset(STREAM s) { uint8 order_caps[32]; + uint16 orderflags = 0; + uint32 cachesize = 0; + + orderflags |= (NEGOTIATEORDERSUPPORT | ZEROBOUNDSDELTASSUPPORT); /* mandatory flags */ + orderflags |= COLORINDEXSUPPORT; 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 */ + + order_caps[TS_NEG_DSTBLT_INDEX] = 1; + order_caps[TS_NEG_PATBLT_INDEX] = 1; + order_caps[TS_NEG_SCRBLT_INDEX] = 1; + order_caps[TS_NEG_LINETO_INDEX] = 1; + order_caps[TS_NEG_MULTI_DRAWNINEGRID_INDEX] = 1; + order_caps[TS_NEG_POLYLINE_INDEX] = 1; + order_caps[TS_NEG_INDEX_INDEX] = 1; + + if (g_bitmap_cache) + order_caps[TS_NEG_MEMBLT_INDEX] = 1; + + if (g_desktop_save) + { + cachesize = 230400; + order_caps[TS_NEG_SAVEBITMAP_INDEX] = 1; + } + + if (g_polygon_ellipse_orders) + { + order_caps[TS_NEG_POLYGON_SC_INDEX] = 1; + order_caps[TS_NEG_POLYGON_CB_INDEX] = 1; + order_caps[TS_NEG_ELLIPSE_SC_INDEX] = 1; + order_caps[TS_NEG_ELLIPSE_CB_INDEX] = 1; + } + 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_uint8a(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 */ + out_uint8s(s, 16); /* terminalDescriptor (ignored, should be 0) */ + out_uint8s(s, 4); /* pad4OctetsA */ + out_uint16_le(s, 1); /* desktopSaveXGranularity (ignored, assumed to be 1) */ + out_uint16_le(s, 20); /* desktopSaveYGranularity (ignored, assumed to be 20) */ + out_uint16_le(s, 0); /* Pad */ + out_uint16_le(s, 1); /* maximumOrderLevel (ignored, should be 1) */ + out_uint16_le(s, 0); /* numberFonts (ignored, should be 0) */ + out_uint16_le(s, orderflags); /* orderFlags */ + out_uint8a(s, order_caps, 32); /* orderSupport */ + out_uint16_le(s, 0); /* textFlags (ignored) */ + out_uint16_le(s, 0); /* orderSupportExFlags */ + out_uint32_le(s, 0); /* pad4OctetsB */ + out_uint32_le(s, cachesize); /* desktopSaveSize */ + out_uint16_le(s, 0); /* pad2OctetsC */ + out_uint16_le(s, 0); /* pad2OctetsD */ + out_uint16_le(s, 1252); /* textANSICodePage */ + out_uint16_le(s, 0); /* pad2OctetsE */ } /* Output bitmap cache capability set */ @@ -793,6 +848,9 @@ rdp_out_bmpcache_caps(STREAM s) { int Bpp; + + logger(Protocol, Debug, "%s()", __func__); + out_uint16_le(s, RDP_CAPSET_BMPCACHE); out_uint16_le(s, RDP_CAPLEN_BMPCACHE); @@ -911,41 +969,123 @@ out_uint32_le(s, 1); /* cache type */ } -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 -}; +/* 2.2.7.1.10 MS-RDPBCGR */ +/* Output virtual channel capability set */ +static void +rdp_out_virtchan_caps(STREAM s) +{ + out_uint16_le(s, RDP_CAPSET_VC); + out_uint16_le(s, RDP_CAPLEN_VC); + /* VCCAPS_COMPR_SC */ + out_uint32_le(s, 0x00000001); /* compression flags */ +} -/* Output unknown capability sets */ static void -rdp_out_unknown_caps(STREAM s, uint16 id, uint16 length, uint8 * caps) +rdp_process_virtchan_caps(STREAM s) { - out_uint16_le(s, id); - out_uint16_le(s, length); + uint32 flags, chunk_size; + + in_uint32_le(s, flags); + in_uint32_le(s, chunk_size); + + UNUSED(flags); + vc_chunk_size = chunk_size; +} + +/* Output Input Capability Set */ +static void +rdp_out_ts_input_capabilityset(STREAM s) +{ + uint16 inputflags = 0; + inputflags |= INPUT_FLAG_SCANCODES; + + out_uint16_le(s, RDP_CAPSET_INPUT); + out_uint16_le(s, RDP_CAPLEN_INPUT); + + out_uint16_le(s, inputflags); /* inputFlags */ + out_uint16_le(s, 0); /* pad2OctetsA */ + out_uint32_le(s, 0x409); /* keyboardLayout */ + out_uint32_le(s, 0x4); /* keyboardType */ + out_uint32_le(s, 0); /* keyboardSubtype */ + out_uint32_le(s, 0xC); /* keyboardFunctionKey */ + out_utf16s_padded(s, "", 64, 0); /* imeFileName */ +} + +/* Output Sound Capability Set */ +static void +rdp_out_ts_sound_capabilityset(STREAM s) +{ + uint16 soundflags = SOUND_BEEPS_FLAG; + + out_uint16_le(s, RDP_CAPSET_SOUND); + out_uint16_le(s, RDP_CAPLEN_SOUND); + + out_uint16_le(s, soundflags); /* soundFlags */ + out_uint16_le(s, 0); /* pad2OctetsA */ +} + +/* Output Font Capability Set */ +static void +rdp_out_ts_font_capabilityset(STREAM s) +{ + uint16 flags = FONTSUPPORT_FONTLIST; + + out_uint16_le(s, RDP_CAPSET_FONT); + out_uint16_le(s, RDP_CAPLEN_FONT); + + out_uint16_le(s, flags); /* fontSupportFlags */ + out_uint16_le(s, 0); /* pad2octets */ +} + +static void +rdp_out_ts_cache_definition(STREAM s, uint16 entries, uint16 maxcellsize) +{ + out_uint16_le(s, entries); + out_uint16_le(s, maxcellsize); +} + +/* Output Glyph Cache Capability Set */ +static void +rdp_out_ts_glyphcache_capabilityset(STREAM s) +{ + uint16 supportlvl = GLYPH_SUPPORT_FULL; + uint32 fragcache = 0x01000100; + out_uint16_le(s, RDP_CAPSET_GLYPHCACHE); + out_uint16_le(s, RDP_CAPLEN_GLYPHCACHE); + + /* GlyphCache - 10 TS_CACHE_DEFINITION structures */ + rdp_out_ts_cache_definition(s, 254, 4); + rdp_out_ts_cache_definition(s, 254, 4); + rdp_out_ts_cache_definition(s, 254, 8); + rdp_out_ts_cache_definition(s, 254, 8); + rdp_out_ts_cache_definition(s, 254, 16); + rdp_out_ts_cache_definition(s, 254, 32); + rdp_out_ts_cache_definition(s, 254, 64); + rdp_out_ts_cache_definition(s, 254, 128); + rdp_out_ts_cache_definition(s, 254, 256); + rdp_out_ts_cache_definition(s, 64, 2048); - out_uint8a(s, caps, length - 4); + out_uint32_le(s, fragcache); /* FragCache */ + out_uint16_le(s, supportlvl); /* GlyphSupportLevel */ + out_uint16_le(s, 0); /* pad2octets */ +} + +static void +rdp_out_ts_multifragmentupdate_capabilityset(STREAM s) +{ + out_uint16_le(s, RDP_CAPSET_MULTIFRAGMENTUPDATE); + out_uint16_le(s, RDP_CAPLEN_MULTIFRAGMENTUPDATE); + out_uint32_le(s, RDESKTOP_FASTPATH_MULTIFRAGMENT_MAX_SIZE); /* MaxRequestSize */ +} + +static void +rdp_out_ts_large_pointer_capabilityset(STREAM s) +{ + uint16 flags = LARGE_POINTER_FLAG_96x96; + + out_uint16_le(s, RDP_CAPSET_LARGE_POINTER); + out_uint16_le(s, RDP_CAPLEN_LARGE_POINTER); + out_uint16_le(s, flags); /* largePointerSupportFlags */ } #define RDP5_FLAG 0x0030 @@ -956,12 +1096,23 @@ 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_GENERAL + + RDP_CAPLEN_BITMAP + + RDP_CAPLEN_ORDER + RDP_CAPLEN_COLCACHE + - RDP_CAPLEN_ACTIVATE + RDP_CAPLEN_CONTROL + + RDP_CAPLEN_ACTIVATE + + RDP_CAPLEN_CONTROL + RDP_CAPLEN_SHARE + - RDP_CAPLEN_BRUSHCACHE + 0x58 + 0x08 + 0x08 + 0x34 /* unknown caps */ + - 4 /* w2k fix, sessionid */ ; + RDP_CAPLEN_BRUSHCACHE + + RDP_CAPLEN_INPUT + + RDP_CAPLEN_FONT + + RDP_CAPLEN_SOUND + + RDP_CAPLEN_GLYPHCACHE + + RDP_CAPLEN_MULTIFRAGMENTUPDATE + + RDP_CAPLEN_LARGE_POINTER + + RDP_CAPLEN_VC + 4 /* w2k fix, sessionid */ ; + + logger(Protocol, Debug, "%s()", __func__); if (g_rdp_version >= RDP_V5) { @@ -986,12 +1137,12 @@ out_uint16_le(s, caplen); out_uint8a(s, RDP_SOURCE, sizeof(RDP_SOURCE)); - out_uint16_le(s, 0xe); /* num_caps */ + out_uint16_le(s, 17); /* num_caps */ out_uint8s(s, 2); /* pad */ - rdp_out_general_caps(s); - rdp_out_bitmap_caps(s); - rdp_out_order_caps(s); + rdp_out_ts_general_capabilityset(s); + rdp_out_ts_bitmap_capabilityset(s); + rdp_out_ts_order_capabilityset(s); if (g_rdp_version >= RDP_V5) { rdp_out_bmpcache2_caps(s); @@ -1007,11 +1158,14 @@ rdp_out_control_caps(s); rdp_out_share_caps(s); rdp_out_brushcache_caps(s); + rdp_out_virtchan_caps(s); - rdp_out_unknown_caps(s, 0x0d, 0x58, caps_0x0d); /* CAPSTYPE_INPUT */ - rdp_out_unknown_caps(s, 0x0c, 0x08, caps_0x0c); /* CAPSTYPE_SOUND */ - rdp_out_unknown_caps(s, 0x0e, 0x08, caps_0x0e); /* CAPSTYPE_FONT */ - rdp_out_unknown_caps(s, 0x10, 0x34, caps_0x10); /* CAPSTYPE_GLYPHCACHE */ + rdp_out_ts_input_capabilityset(s); + rdp_out_ts_sound_capabilityset(s); + rdp_out_ts_font_capabilityset(s); + rdp_out_ts_glyphcache_capabilityset(s); + rdp_out_ts_multifragmentupdate_capabilityset(s); + rdp_out_ts_large_pointer_capabilityset(s); s_mark_end(s); sec_send(s, sec_flags); @@ -1024,6 +1178,8 @@ { uint16 pad2octetsB; /* rdp5 flags? */ + logger(Protocol, Debug, "%s()", __func__); + in_uint8s(s, 10); in_uint16_le(s, pad2octetsB); @@ -1031,19 +1187,35 @@ g_rdp_version = RDP_V4; } +static RD_BOOL g_first_bitmap_caps = True; + /* Process a bitmap capability set */ static void rdp_process_bitmap_caps(STREAM s) { - uint16 width, height, depth; + + uint16 depth; + + logger(Protocol, Debug, "%s()", __func__); in_uint16_le(s, depth); in_uint8s(s, 6); - in_uint16_le(s, width); - in_uint16_le(s, height); + in_uint16_le(s, g_session_width); + in_uint16_le(s, g_session_height); - DEBUG(("setting desktop size and depth to: %dx%dx%d\n", width, height, depth)); + logger(Protocol, Debug, + "rdp_process_bitmap_caps(), setting desktop size and depth to: %dx%dx%d", + g_session_width, g_session_height, depth); + + /* Detect if we can have dynamic session resize enabled, only once. */ + if (g_first_bitmap_caps == True && !(g_session_width == g_requested_session_width + && g_session_height == g_requested_session_height)) + { + logger(Core, Notice, "Disabling dynamic session resize"); + g_dynamic_session_resize = False; + } + g_first_bitmap_caps = False; /* * The server may limit depth and change the size of the desktop (for @@ -1051,18 +1223,28 @@ */ if (g_server_depth != depth) { - warning("Remote desktop does not support colour depth %d; falling back to %d\n", - g_server_depth, depth); + logger(Core, Verbose, + "Remote desktop does not support colour depth %d; falling back to %d", + g_server_depth, depth); g_server_depth = depth; } - if (g_width != width || g_height != height) + + /* Resize window size to match session size, except when we're in + fullscreen, where we want the window to always cover the entire + screen. */ + + if (g_fullscreen == True) + return; + + /* If dynamic session resize is disabled, set window size hints to + fixed session size */ + if (g_dynamic_session_resize == False) { - 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(); + ui_update_window_sizehints(g_session_width, g_session_height); + return; } + + ui_resize_window(g_session_width, g_session_height); } /* Process server capabilities */ @@ -1073,6 +1255,8 @@ size_t next, start; uint16 ncapsets, capset_type, capset_length; + logger(Protocol, Debug, "%s()", __func__); + start = s_tell(s); in_uint16_le(s, ncapsets); @@ -1097,6 +1281,12 @@ case RDP_CAPSET_BITMAP: rdp_process_bitmap_caps(s); break; + case RDP_CAPSET_VC: + /* Parse only if we got VCChunkSize */ + if (capset_length > 8) { + rdp_process_virtchan_caps(s); + } + break; } s_seek(s, next); @@ -1124,7 +1314,8 @@ } in_uint8s(s, len_src_descriptor); - DEBUG(("DEMAND_ACTIVE(id=0x%x)\n", g_rdp_shareid)); + logger(Protocol, Debug, "process_demand_active(), shareid=0x%x", g_rdp_shareid); + rdp_process_server_caps(s, len_combined_caps); rdp_send_confirm_active(); @@ -1156,6 +1347,7 @@ static void process_colour_pointer_common(STREAM s, int bpp) { + extern RD_BOOL g_local_cursor; uint16 width, height, cache_idx, masklen, datalen; uint16 x, y; uint8 *mask; @@ -1171,14 +1363,16 @@ in_uint16_le(s, datalen); in_uint8p(s, data, datalen); in_uint8p(s, mask, masklen); - if ((width != 32) || (height != 32)) - { - warning("process_colour_pointer_common: " "width %d height %d\n", width, height); - } + + logger(Protocol, Debug, + "process_colour_pointer_common(), new pointer %d with width %d and height %d", + cache_idx, width, height); /* keep hotspot within cursor bounding box */ x = MIN(x, width - 1); y = MIN(y, height - 1); + if (g_local_cursor) + return; /* don't bother creating a cursor we won't use */ cursor = ui_create_cursor(x, y, width, height, mask, data, bpp); ui_set_cursor(cursor); cache_put_cursor(cache_idx, cursor); @@ -1188,6 +1382,8 @@ void process_colour_pointer_pdu(STREAM s) { + logger(Protocol, Debug, "%s()", __func__); + process_colour_pointer_common(s, 24); } @@ -1196,6 +1392,8 @@ process_new_pointer_pdu(STREAM s) { int xor_bpp; + logger(Protocol, Debug, "%s()", __func__); + in_uint16_le(s, xor_bpp); process_colour_pointer_common(s, xor_bpp); @@ -1206,6 +1404,8 @@ process_cached_pointer_pdu(STREAM s) { uint16 cache_idx; + logger(Protocol, Debug, "%s()", __func__); + in_uint16_le(s, cache_idx); ui_set_cursor(cache_get_cursor(cache_idx)); @@ -1215,17 +1415,29 @@ void process_system_pointer_pdu(STREAM s) { - uint16 system_pointer_type; + uint32 system_pointer_type; + logger(Protocol, Debug, "%s()", __func__); + + in_uint32_le(s, system_pointer_type); - in_uint16_le(s, system_pointer_type); - switch (system_pointer_type) + set_system_pointer(system_pointer_type); +} + +/* Set a given system pointer */ +void +set_system_pointer(uint32 ptr) +{ + switch (ptr) { - case RDP_NULL_POINTER: + case SYSPTR_NULL: ui_set_null_cursor(); break; - + case SYSPTR_DEFAULT: + ui_set_standard_cursor(); + break; default: - unimpl("System pointer message 0x%x\n", system_pointer_type); + logger(Protocol, Warning, + "set_system_pointer(), unhandled pointer type 0x%x", ptr); } } @@ -1236,6 +1448,8 @@ uint16 message_type; uint16 x, y; + logger(Protocol, Debug, "%s()", __func__); + in_uint16_le(s, message_type); in_uint8s(s, 2); /* pad */ @@ -1264,7 +1478,8 @@ break; default: - unimpl("Pointer message 0x%x\n", message_type); + logger(Protocol, Warning, + "process_pointer_pdu(), unhandled message type 0x%x", message_type); } } @@ -1275,64 +1490,57 @@ uint16 left, top, right, bottom, width, height; uint16 cx, cy, bpp, Bpp, flags, bufsize, size; uint8 *data, *bmpdata; + + logger(Protocol, Debug, "%s()", __func__); struct stream packet = *s; - in_uint16_le(s, left); /* destLeft */ - in_uint16_le(s, top); /* destTop */ - in_uint16_le(s, right); /* destRight */ - in_uint16_le(s, bottom); /* destBottom */ - in_uint16_le(s, width); /* width */ - in_uint16_le(s, height); /* height */ - in_uint16_le(s, bpp); /* bitsPerPixel */ + in_uint16_le(s, left); /* destLeft */ + in_uint16_le(s, top); /* destTop */ + in_uint16_le(s, right); /* destRight */ + in_uint16_le(s, bottom); /* destBottom */ + in_uint16_le(s, width); /* width */ + in_uint16_le(s, height); /* height */ + in_uint16_le(s, bpp); /*bitsPerPixel */ Bpp = (bpp + 7) / 8; - in_uint16_le(s, flags); /* flags */ - in_uint16_le(s, bufsize); /* bitmapLength */ + in_uint16_le(s, flags); /* flags */ + in_uint16_le(s, bufsize); /* bitmapLength */ cx = right - left + 1; cy = bottom - top + 1; /* FIXME: There are a assumtion that we do not consider in - this code. The value of bpp is not passed to - ui_paint_bitmap() which relies on g_server_bpp for drawing - the bitmap data. - - Does this means that we can sanity check bpp with g_server_bpp ? - */ + this code. The value of bpp is not passed to + ui_paint_bitmap() which relies on g_server_bpp for drawing + the bitmap data. + Does this means that we can sanity check bpp with g_server_bpp ? + */ if (Bpp == 0 || width == 0 || height == 0) { - warning("%s(), [%d,%d,%d,%d], [%d,%d], bpp=%d, flags=%x", __func__, - left, top, right, bottom, width, height, bpp, flags); - rdp_protocol_error - ("TS_BITMAP_DATA, unsafe size of bitmap data received from server", - &packet); + logger(Protocol, Warning, "%s(), [%d,%d,%d,%d], [%d,%d], bpp=%d, flags=%x", __func__, + left, top, right, bottom, width, height, bpp, flags); + rdp_protocol_error("TS_BITMAP_DATA, unsafe size of bitmap data received from server", &packet); } if ((RD_UINT32_MAX / Bpp) <= (width * height)) { - warning("%s(), [%d,%d,%d,%d], [%d,%d], bpp=%d, flags=%x", __func__, - left, top, right, bottom, width, height, bpp, flags); - rdp_protocol_error - ("TS_BITMAP_DATA, unsafe size of bitmap data received from server", - &packet); + logger(Protocol, Warning, "%s(), [%d,%d,%d,%d], [%d,%d], bpp=%d, flags=%x", __func__, + left, top, right, bottom, width, height, bpp, flags); + rdp_protocol_error("TS_BITMAP_DATA, unsafe size of bitmap data received from server", &packet); } - - -#if DEBUG - printf("%s(), [%d,%d,%d,%d], [%d,%d], bpp=%d, flags=%x", __func__, - left, top, right, bottom, width, height, bpp, flags); -#endif + if (flags == 0) { - /* read uncompresssed bitmap data */ + /* read uncompressed bitmap data */ 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); return; @@ -1345,10 +1553,10 @@ else { /* Read TS_CD_HEADER */ - in_uint8s(s, 2); /* skip cbCompFirstRowSize (must be 0x0000) */ - in_uint16_le(s, size); /* cbCompMainBodySize */ - in_uint8s(s, 2); /* skip cbScanWidth */ - in_uint8s(s, 2); /* skip cbUncompressedSize */ + in_uint8s(s, 2); /* skip cbCompFirstRowSize (must be 0x0000) */ + in_uint16_le(s, size); /* cbCompMainBodySize */ + in_uint8s(s, 2); /* skip cbScanWidth */ + in_uint8s(s, 2); /* skip cbUncompressedSize */ } /* read compressed bitmap data */ @@ -1364,22 +1572,20 @@ } else { - warning("%s(), failed to decompress bitmap", __func__); + logger(Protocol, Warning, "%s(), failed to decompress bitmap", __func__); } xfree(bmpdata); } - - /* Process TS_UPDATE_BITMAP_DATA */ void process_bitmap_updates(STREAM s) { - uint16 num_updates; int i; - - in_uint16_le(s, num_updates); /* rectangles */ + uint16 num_updates; + + in_uint16_le(s, num_updates); /* rectangles */ for (i = 0; i < num_updates; i++) { @@ -1402,7 +1608,7 @@ map.colours = (COLOURENTRY *) xmalloc(sizeof(COLOURENTRY) * map.ncolours); - DEBUG(("PALETTE(c=%d)\n", map.ncolours)); + logger(Graphics, Debug, "process_palette(), colour count %d", map.ncolours); for (i = 0; i < map.ncolours; i++) { @@ -1430,6 +1636,8 @@ switch (update_type) { case RDP_UPDATE_ORDERS: + logger(Protocol, Debug, "%s(), RDP_UPDATE_ORDERS", __func__); + in_uint8s(s, 2); /* pad */ in_uint16_le(s, count); in_uint8s(s, 2); /* pad */ @@ -1437,75 +1645,109 @@ break; case RDP_UPDATE_BITMAP: + logger(Protocol, Debug, "%s(), RDP_UPDATE_BITMAP", __func__); process_bitmap_updates(s); break; case RDP_UPDATE_PALETTE: + logger(Protocol, Debug, "%s(), RDP_UPDATE_PALETTE", __func__); process_palette(s); break; case RDP_UPDATE_SYNCHRONIZE: + logger(Protocol, Debug, "%s(), RDP_UPDATE_SYNCHRONIZE", __func__); break; default: - unimpl("update %d\n", update_type); + logger(Protocol, Warning, "process_update_pdu(), unhandled update type %d", + update_type); } ui_end_update(); } -/* Process a Save Session Info PDU */ -void -process_pdu_logon(STREAM s) +/* Process TS_LOGIN_INFO_EXTENDED data structure */ +static void +process_ts_logon_info_extended(STREAM s) { - uint32 infotype; - in_uint32_le(s, infotype); - if (infotype == INFOTYPE_LOGON_EXTENDED_INF) + uint32 fieldspresent; + uint32 len; + uint32 version; + + logger(Protocol, Debug, "%s()", __func__); + + in_uint8s(s, 2); /* Length */ + in_uint32_le(s, fieldspresent); + if (fieldspresent & LOGON_EX_AUTORECONNECTCOOKIE) { - uint32 fieldspresent; + /* TS_LOGON_INFO_FIELD */ + in_uint8s(s, 4); /* cbFieldData */ - in_uint8s(s, 2); /* Length */ - in_uint32_le(s, fieldspresent); - if (fieldspresent & LOGON_EX_AUTORECONNECTCOOKIE) + /* ARC_SC_PRIVATE_PACKET */ + in_uint32_le(s, len); + if (len != 28) { - uint32 len; - uint32 version; + logger(Protocol, Error, + "process_ts_logon_info_extended(), invalid length in Auto-Reconnect packet"); + return; + } - /* TS_LOGON_INFO_FIELD */ - in_uint8s(s, 4); /* cbFieldData */ + in_uint32_le(s, version); + if (version != 1) + { + logger(Protocol, Error, + "process_ts_logon_info_extended(), unsupported version of Auto-Reconnect packet"); + return; + } - /* ARC_SC_PRIVATE_PACKET */ - in_uint32_le(s, len); - if (len != 28) - { - warning("Invalid length in Auto-Reconnect packet\n"); - return; - } + in_uint32_le(s, g_reconnect_logonid); + in_uint8a(s, g_reconnect_random, 16); + g_has_reconnect_random = True; + g_reconnect_random_ts = time(NULL); + logger(Protocol, Debug, + "process_ts_logon_info_extended(), saving Auto-Reconnect cookie, id=%u", + g_reconnect_logonid); - in_uint32_le(s, version); - if (version != 1) - { - warning("Unsupported version of Auto-Reconnect packet\n"); - return; - } + gettimeofday(&g_pending_resize_defer_timer, NULL); + } +} - in_uint32_le(s, g_reconnect_logonid); - in_uint8a(s, g_reconnect_random, 16); - g_has_reconnect_random = True; - g_reconnect_random_ts = time(NULL); - DEBUG(("Saving auto-reconnect cookie, id=%u\n", g_reconnect_logonid)); - } +/* Process TS_SAVE_SESSION_INFO_PDU_DATA data structure */ +void +process_pdu_logon(STREAM s) +{ + uint32 infotype; + in_uint32_le(s, infotype); + + switch (infotype) + { + case INFOTYPE_LOGON_PLAINNOTIFY: /* TS_PLAIN_NOTIFY */ + logger(Protocol, Debug, + "process_pdu_logon(), Received TS_LOGIN_PLAIN_NOTIFY"); + in_uint8s(s, 576); /* pad */ + break; + + case INFOTYPE_LOGON_EXTENDED_INF: /* TS_LOGON_INFO_EXTENDED */ + logger(Protocol, Debug, + "process_pdu_logon(), Received TS_LOGIN_INFO_EXTENDED"); + process_ts_logon_info_extended(s); + break; + + default: + logger(Protocol, Warning, + "process_pdu_logon(), Unhandled login infotype %d", infotype); } } -/* Process a disconnect PDU */ -void -process_disconnect_pdu(STREAM s, uint32 * ext_disc_reason) +/* Process a Set Error Info PDU */ +static void +process_ts_set_error_info_pdu(STREAM s, uint32 * ext_disc_reason) { in_uint32_le(s, *ext_disc_reason); - DEBUG(("Received disconnect PDU\n")); + logger(Protocol, Debug, "process_ts_set_error_info_pdu(), error info = %d", + *ext_disc_reason); } /* Process data PDU */ @@ -1532,10 +1774,12 @@ if (ctype & RDP_MPPC_COMPRESSED) { if (len > RDP_MPPC_DICT_SIZE) - error("error decompressed packet size exceeds max\n"); + logger(Protocol, Error, + "process_data_pdu(), error decompressed packet size exceeds max"); in_uint8p(s, buf, clen); if (mppc_expand(buf, clen, ctype, &roff, &rlen) == -1) - error("error while decompressing packet\n"); + logger(Protocol, Error, + "process_data_pdu(), error while decompressing packet"); /* len -= 18; */ @@ -1559,11 +1803,11 @@ break; case RDP_DATA_PDU_CONTROL: - DEBUG(("Received Control PDU\n")); + logger(Protocol, Debug, "process_data_pdu(), received Control PDU"); break; case RDP_DATA_PDU_SYNCHRONISE: - DEBUG(("Received Sync PDU\n")); + logger(Protocol, Debug, "process_data_pdu(), received Sync PDU"); break; case RDP_DATA_PDU_POINTER: @@ -1575,13 +1819,13 @@ break; case RDP_DATA_PDU_LOGON: - DEBUG(("Received Logon PDU\n")); + logger(Protocol, Debug, "process_data_pdu(), received Logon PDU"); /* User logged on */ process_pdu_logon(s); break; - case RDP_DATA_PDU_DISCONNECT: - process_disconnect_pdu(s, ext_disc_reason); + case RDP_DATA_PDU_SET_ERROR_INFO: + process_ts_set_error_info_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 @@ -1591,11 +1835,13 @@ break; case RDP_DATA_PDU_AUTORECONNECT_STATUS: - warning("Automatic reconnect using cookie, failed.\n"); + logger(Protocol, Warning, + "process_data_pdu(), automatic reconnect using cookie, failed"); break; default: - unimpl("data PDU %d\n", data_pdu_type); + logger(Protocol, Warning, "process_data_pdu(), unhandled data PDU type %d", + data_pdu_type); } return False; } @@ -1607,6 +1853,8 @@ uint32 len; uint16 redirect_identifier; + logger(Protocol, Debug, "%s()", __func__); + /* reset any previous redirection information */ g_redirect = True; free(g_redirect_server); @@ -1634,7 +1882,7 @@ /* read identifier */ in_uint16_le(s, redirect_identifier); if (redirect_identifier != 0x0400) - error("Protocol error in server redirection, unexpected data."); + logger(Protocol, Error, "unexpected data in server redirection packet"); /* FIXME: skip total length */ in_uint8s(s, 2); @@ -1646,7 +1894,7 @@ /* read connection flags */ in_uint32_le(s, g_redirect_flags); - if (g_redirect_flags & PDU_REDIRECT_HAS_IP) + if (g_redirect_flags & LB_TARGET_NET_ADDRESS) { /* read length of ip string */ in_uint32_le(s, len); @@ -1655,7 +1903,7 @@ rdp_in_unistr(s, len, &g_redirect_server, &g_redirect_server_len); } - if (g_redirect_flags & PDU_REDIRECT_HAS_LOAD_BALANCE_INFO) + if (g_redirect_flags & LB_LOAD_BALANCE_INFO) { /* read length of load balance info blob */ in_uint32_le(s, g_redirect_lb_info_len); @@ -1670,7 +1918,7 @@ in_uint8p(s, g_redirect_lb_info, g_redirect_lb_info_len); } - if (g_redirect_flags & PDU_REDIRECT_HAS_USERNAME) + if (g_redirect_flags & LB_USERNAME) { /* read length of username string */ in_uint32_le(s, len); @@ -1679,7 +1927,7 @@ rdp_in_unistr(s, len, &g_redirect_username, &g_redirect_username_len); } - if (g_redirect_flags & PDU_REDIRECT_HAS_DOMAIN) + if (g_redirect_flags & LB_DOMAIN) { /* read length of domain string */ in_uint32_le(s, len); @@ -1688,7 +1936,7 @@ rdp_in_unistr(s, len, &g_redirect_domain, &g_redirect_domain_len); } - if (g_redirect_flags & PDU_REDIRECT_HAS_PASSWORD) + if (g_redirect_flags & LB_PASSWORD) { /* the information in this blob is either a password or a cookie that should be passed though as blob and not parsed as a unicode string */ @@ -1703,68 +1951,102 @@ g_redirect_cookie = xmalloc(g_redirect_cookie_len); /* read cookie as is */ - in_uint8p(s, g_redirect_cookie, g_redirect_cookie_len); + in_uint8a(s, g_redirect_cookie, g_redirect_cookie_len); + + logger(Protocol, Debug, "process_redirect_pdu(), Read %d bytes redirection cookie", + g_redirect_cookie_len); } - if (g_redirect_flags & PDU_REDIRECT_DONT_STORE_USERNAME) + if (g_redirect_flags & LB_DONTSTOREUSERNAME) { - warning("PDU_REDIRECT_DONT_STORE_USERNAME set\n"); + logger(Protocol, Warning, + "process_redirect_pdu(), unhandled LB_DONTSTOREUSERNAME set"); } - if (g_redirect_flags & PDU_REDIRECT_USE_SMARTCARD) + if (g_redirect_flags & LB_SMARTCARD_LOGON) { - warning("PDU_REDIRECT_USE_SMARTCARD set\n"); + logger(Protocol, Warning, + "process_redirect_pdu(), unhandled LB_SMARTCARD_LOGON set"); } - if (g_redirect_flags & PDU_REDIRECT_INFORMATIONAL) + if (g_redirect_flags & LB_NOREDIRECT) { /* By spec this is only for information and doesn't mean that an actual redirect should be performed. How it should be used is not mentioned. */ g_redirect = False; } - if (g_redirect_flags & PDU_REDIRECT_HAS_TARGET_FQDN) + if (g_redirect_flags & LB_TARGET_FQDN) { in_uint32_le(s, len); - /* Let target fqdn replace target ip address */ + /* Let target FQDN replace target IP address */ if (g_redirect_server) { free(g_redirect_server); g_redirect_server = NULL; } - /* read fqdn string */ + /* read FQDN string */ rdp_in_unistr(s, len, &g_redirect_server, &g_redirect_server_len); } - if (g_redirect_flags & PDU_REDIRECT_HAS_TARGET_NETBIOS) + if (g_redirect_flags & LB_TARGET_NETBIOS) { - warning("PDU_REDIRECT_HAS_TARGET_NETBIOS set\n"); + logger(Protocol, Warning, "process_redirect_pdu(), unhandled LB_TARGET_NETBIOS"); } - if (g_redirect_flags & PDU_REDIRECT_HAS_TARGET_IP_ARRAY) + if (g_redirect_flags & LB_TARGET_NET_ADDRESSES) { - warning("PDU_REDIRECT_HAS_TARGET_IP_ARRAY set\n"); + logger(Protocol, Warning, + "process_redirect_pdu(), unhandled LB_TARGET_NET_ADDRESSES"); } - return True; + if (g_redirect_flags & LB_CLIENT_TSV_URL) + { + logger(Protocol, Warning, "process_redirect_pdu(), unhandled LB_CLIENT_TSV_URL"); + } + + if (g_redirect_flags & LB_SERVER_TSV_CAPABLE) + { + logger(Protocol, Warning, "process_redirect_pdu(), unhandled LB_SERVER_TSV_URL"); + } + + if (g_redirect_flags & LB_PASSWORD_IS_PK_ENCRYPTED) + { + logger(Protocol, Warning, + "process_redirect_pdu(), unhandled LB_PASSWORD_IS_PK_ENCRYPTED "); + } + + if (g_redirect_flags & LB_REDIRECTION_GUID) + { + logger(Protocol, Warning, "process_redirect_pdu(), unhandled LB_REDIRECTION_GUID "); + } + + if (g_redirect_flags & LB_TARGET_CERTIFICATE) + { + logger(Protocol, Warning, + "process_redirect_pdu(), unhandled LB_TARGET_CERTIFICATE"); + } + + return g_redirect; } /* Process incoming packets */ void rdp_main_loop(RD_BOOL * deactivated, uint32 * ext_disc_reason) { - while (rdp_loop(deactivated, ext_disc_reason)) + do { - if (g_pending_resize || g_redirect) + if (rdp_loop(deactivated, ext_disc_reason) == False) { - return; + g_exit_mainloop = True; } } + while (g_exit_mainloop == False); } -/* used in uiports and rdp_main_loop, processes the rdp packets waiting */ +/* used in uiports and rdp_main_loop, processes the RDP packets waiting */ RD_BOOL rdp_loop(RD_BOOL * deactivated, uint32 * ext_disc_reason) { @@ -1772,7 +2054,7 @@ RD_BOOL cont = True; STREAM s; - while (cont) + while (g_exit_mainloop == False && cont) { s = rdp_recv(&type); if (s == NULL) @@ -1784,14 +2066,18 @@ *deactivated = False; break; case RDP_PDU_DEACTIVATE: - DEBUG(("RDP_PDU_DEACTIVATE\n")); + logger(Protocol, Debug, + "rdp_loop(), RDP_PDU_DEACTIVATE packet received"); *deactivated = True; + g_wait_for_deactivate_ts = 0; break; case RDP_PDU_REDIRECT: - return process_redirect_pdu(s, False); - break; case RDP_PDU_ENHANCED_REDIRECT: - return process_redirect_pdu(s, True); + if (process_redirect_pdu(s, !(type == RDP_PDU_REDIRECT)) == True) + { + g_exit_mainloop = True; + continue; + } break; case RDP_PDU_DATA: /* If we got a data PDU, we don't need to keep the password in memory @@ -1801,10 +2087,9 @@ process_data_pdu(s, ext_disc_reason); break; - case 0: - break; default: - unimpl("PDU %d\n", type); + logger(Protocol, Warning, + "rdp_loop(), unhandled PDU type %d received", type); } cont = g_next_packet < s_length(s); } @@ -1822,7 +2107,7 @@ if (!sec_connect(server, g_username, domain, password, reconnect)) return False; - rdp_send_logon_info(flags, domain, g_username, password, command, directory); + rdp_send_client_info_pdu(flags, domain, g_username, password, command, directory); /* run RDP loop until first licence demand active PDU */ while (!g_rdp_shareid) @@ -1843,8 +2128,11 @@ void rdp_reset_state(void) { + logger(Protocol, Debug, "%s()", __func__); g_next_packet = 0; /* reset the packet information */ g_rdp_shareid = 0; + g_exit_mainloop = False; + g_first_bitmap_caps = True; sec_reset_state(); } @@ -1852,6 +2140,7 @@ void rdp_disconnect(void) { + logger(Protocol, Debug, "%s()", __func__); sec_disconnect(); } @@ -1868,7 +2157,7 @@ _rdp_protocol_error(const char *file, int line, const char *func, const char *message, STREAM s) { - error("%s:%d: %s(), %s", file, line, func, message); + logger(Protocol, Error, "%s:%d: %s(), %s", file, line, func, message); if (s) hexdump(s->data, s_length(s)); exit(0); diff -Nru rdesktop-1.8.6/rdpdr.c rdesktop-1.9.0/rdpdr.c --- rdesktop-1.8.6/rdpdr.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/rdpdr.c 2019-06-13 12:10:15.000000000 +0000 @@ -2,7 +2,9 @@ rdesktop: A Remote Desktop Protocol client. Copyright (C) Matthew Chapman <matthewc.unsw.edu.au> 1999-2008 Copyright 2004-2011 Peter Astrand <astrand@cendio.se> for Cendio AB - Copyright 2010-2014 Henrik Andersson <hean01@cendio.se> for Cendio AB + Copyright 2010-2017 Henrik Andersson <hean01@cendio.se> for Cendio AB + Copyright 2017-2019 Karl Mikaelsson <derfian@cendio.se> for Cendio AB + Copyright 2016, 2018 Alexander Zakharov <uglym8@gmail.com> 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 @@ -82,10 +84,11 @@ /* Used to store incoming io request, until they are ready to be completed */ /* using a linked list ensures that they are processed in the right order, */ -/* if multiple ios are being done on the same fd */ +/* if multiple IOs are being done on the same FD */ struct async_iorequest { - uint32 fd, major, minor, offset, device, id, length, partial_len; + uint32 fd, major, minor, device, id, length, partial_len; + uint64 offset; long timeout, /* Total timeout */ itv_timeout; /* Interval timeout (between serial characters) */ uint8 *buffer; @@ -122,7 +125,7 @@ } static RD_BOOL -rdpdr_handle_ok(int device, int handle) +rdpdr_handle_ok(uint32 device, RD_NTHANDLE handle) { switch (g_rdpdr_device[device].device_type) { @@ -145,7 +148,7 @@ static RD_BOOL add_async_iorequest(uint32 device, uint32 file, uint32 id, uint32 major, uint32 length, DEVICE_FNS * fns, uint32 total_timeout, uint32 interval_timeout, uint8 * buffer, - uint32 offset) + uint64 offset) { struct async_iorequest *iorq; @@ -210,48 +213,66 @@ { /* DR_CORE_CLIENT_NAME_REQ */ STREAM s; - uint32 hostlen; + struct stream name = { 0 }; if (NULL == g_rdpdr_clientname) { g_rdpdr_clientname = g_hostname; } - hostlen = (strlen(g_rdpdr_clientname) + 1) * 2; - s = channel_init(rdpdr_channel, 16 + hostlen); + s_realloc(&name, 512 * 4); + s_reset(&name); + out_utf16s(&name, g_rdpdr_clientname); + s_mark_end(&name); + + s = channel_init(rdpdr_channel, 16 + s_length(&name)); out_uint16_le(s, RDPDR_CTYP_CORE); out_uint16_le(s, PAKID_CORE_CLIENT_NAME); out_uint32_le(s, 1); /* UnicodeFlag */ out_uint32_le(s, 0); /* CodePage */ - out_uint32_le(s, hostlen); /* ComputerNameLen */ - rdp_out_unistr(s, g_rdpdr_clientname, hostlen - 2); + out_uint32_le(s, s_length(&name)); /* ComputerNameLen */ + out_stream(s, &name); s_mark_end(s); channel_send(s, rdpdr_channel); s_free(s); } /* Returns the size of the payload of the announce packet */ -static int +static size_t announcedata_size() { - int size, i; + size_t size, i; PRINTER *printerinfo; + DISK_DEVICE *diskinfo; - size = 8; /* static announce size */ - size += g_num_devices * 0x14; + size = 8; /* Header + DeviceCount */ for (i = 0; i < g_num_devices; i++) { - if (g_rdpdr_device[i].device_type == DEVICE_TYPE_PRINTER) + size += 4; /* DeviceType */ + size += 4; /* DeviceId */ + size += 8; /* PreferredDosName */ + size += 4; /* DeviceDataLength */ + + switch (g_rdpdr_device[i].device_type) { - printerinfo = (PRINTER *) g_rdpdr_device[i].pdevice_data; - printerinfo->bloblen = - printercache_load_blob(printerinfo->printer, &(printerinfo->blob)); - - size += 0x18; - size += 2 * strlen(printerinfo->driver) + 2; - size += 2 * strlen(printerinfo->printer) + 2; - size += printerinfo->bloblen; + case DEVICE_TYPE_DISK: + diskinfo = (DISK_DEVICE *) g_rdpdr_device[i].pdevice_data; + size += 2 * strlen(diskinfo->name) + 2; + break; + case DEVICE_TYPE_PRINTER: + printerinfo = (PRINTER *) g_rdpdr_device[i].pdevice_data; + printerinfo->bloblen = + printercache_load_blob(printerinfo->printer, + &(printerinfo->blob)); + + size += 0x18; + size += 2 * strlen(printerinfo->driver) + 2; + size += 2 * strlen(printerinfo->printer) + 2; + size += printerinfo->bloblen; + break; + default: + break; } } @@ -262,10 +283,14 @@ rdpdr_send_client_device_list_announce(void) { /* DR_CORE_CLIENT_ANNOUNCE_RSP */ - uint32 driverlen, printerlen, bloblen; - int i; + uint32 bloblen, disklen, flags; + size_t i; STREAM s; PRINTER *printerinfo; + DISK_DEVICE *diskinfo; + struct stream drv = { 0 }, prt = + { + 0}; s = channel_init(rdpdr_channel, announcedata_size()); out_uint16_le(s, RDPDR_CTYP_CORE); @@ -273,32 +298,56 @@ out_uint32_le(s, g_num_devices); - for (i = 0; i < g_num_devices; i++) + for (i = 0; i < g_num_devices; i++) /* DEVICE_ANNOUNCE */ { out_uint32_le(s, g_rdpdr_device[i].device_type); out_uint32_le(s, i); /* RDP Device ID */ - /* Is it possible to use share names longer than 8 chars? - /astrand */ - out_uint8a(s, g_rdpdr_device[i].name, 8); - + out_uint8a(s, g_rdpdr_device[i].name, 8); /* preferredDosName, limited to 8 characters */ switch (g_rdpdr_device[i].device_type) { + case DEVICE_TYPE_DISK: + diskinfo = (DISK_DEVICE *) g_rdpdr_device[i].pdevice_data; + + /* The RDP specification says that the DeviceData is supposed to be + a null-terminated Unicode string, but that does not work. In + practice the string is expected to be an ASCII string, like a + variable-length preferredDosName. */ + + disklen = strlen(diskinfo->name) + 1; + + out_uint32_le(s, disklen); /* DeviceDataLength */ + out_uint8a(s, diskinfo->name, disklen); /* DeviceData */ + break; + case DEVICE_TYPE_PRINTER: printerinfo = (PRINTER *) g_rdpdr_device[i].pdevice_data; - driverlen = 2 * strlen(printerinfo->driver) + 2; - printerlen = 2 * strlen(printerinfo->printer) + 2; - bloblen = printerinfo->bloblen; + s_realloc(&prt, 512 * 4); + s_reset(&prt); + out_utf16s(&prt, printerinfo->printer); + s_mark_end(&prt); + + s_realloc(&drv, 512 * 4); + s_reset(&drv); + out_utf16s(&drv, printerinfo->driver); + s_mark_end(&drv); - out_uint32_le(s, 24 + driverlen + printerlen + bloblen); /* length of extra info */ - out_uint32_le(s, printerinfo->default_printer ? 2 : 0); - out_uint8s(s, 8); /* unknown */ - out_uint32_le(s, driverlen); - out_uint32_le(s, printerlen); - out_uint32_le(s, bloblen); - rdp_out_unistr(s, printerinfo->driver, driverlen - 2); - rdp_out_unistr(s, printerinfo->printer, printerlen - 2); - out_uint8a(s, printerinfo->blob, bloblen); + bloblen = printerinfo->bloblen; + flags = 0; + if (printerinfo->default_printer) + flags |= RDPDR_PRINTER_ANNOUNCE_FLAG_DEFAULTPRINTER; + + out_uint32_le(s, 24 + s_length(&drv) + s_length(&prt) + bloblen); /* DeviceDataLength */ + out_uint32_le(s, flags); /* Flags */ + out_uint32_le(s, 0); /* Codepage */ + out_uint32_le(s, 0); /* PnPNameLen */ + out_uint32_le(s, s_length(&drv)); /* DriverNameLen */ + out_uint32_le(s, s_length(&prt)); /* PrinterNameLen */ + out_uint32_le(s, bloblen); /* CachedFieldsLen */ + // out_uint8s(s, 0); /* PnPName (Skipped) */ + out_stream(s, &drv); /* DriverName */ + out_stream(s, &prt); /* PrinterName */ + out_uint8a(s, printerinfo->blob, bloblen); /* CachedPrinterConfigData */ if (printerinfo->blob) xfree(printerinfo->blob); /* Blob is sent twice if reconnecting */ @@ -322,6 +371,15 @@ #ifdef WITH_SCARD scard_lock(SCARD_LOCK_RDPDR); #endif + if (status == RD_STATUS_BUFFER_TOO_SMALL) { + /* + * Not enough space has been allocated by server to store the result. + * Send STATUS_BUFFER_TOO_SMALL error as a IoStatus. + */ + result = 0; + length = 0; + } + s = channel_init(rdpdr_channel, 20 + length); out_uint16_le(s, RDPDR_CTYP_CORE); out_uint16_le(s, PAKID_CORE_DEVICE_IOCOMPLETION); @@ -329,13 +387,13 @@ out_uint32_le(s, id); out_uint32_le(s, status); out_uint32_le(s, result); - out_uint8a(s, buffer, length); + if (length) + out_uint8a(s, buffer, length); s_mark_end(s); - /* JIF */ -#ifdef WITH_DEBUG_RDP5 - printf("--> rdpdr_send_completion\n"); + + logger(Protocol, Debug, "rdpdr_send_completion()"); /* hexdump(s->channel_hdr + 8, s->end - s->channel_hdr - 8); */ -#endif + channel_send(s, rdpdr_channel); s_free(s); #ifdef WITH_SCARD @@ -343,6 +401,7 @@ #endif } +/* Processes a DR_DEVICE_IOREQUEST (minus the leading header field) */ static void rdpdr_process_irp(STREAM s) { @@ -356,12 +415,11 @@ major, minor, device, - offset, - bytes_in, bytes_out, - error_mode, share_mode, disposition, total_timeout, interval_timeout, flags_and_attributes = 0; + uint64 offset; + char *filename; uint32 filename_len; @@ -383,8 +441,9 @@ if (device >= RDPDR_MAX_DEVICES) { - error("invalid irp device 0x%lx file 0x%lx id 0x%lx major 0x%lx minor 0x%lx\n", - device, file, id, major, minor); + logger(Protocol, Error, + "rdpdr_process_irp(), invalid irp device=0x%lx, file=0x%lx, id=0x%lx, major=0x%lx, minor=0x%lx", + device, file, id, major, minor); return; } @@ -420,8 +479,9 @@ break; #endif default: - - error("IRP for bad device %ld\n", device); + logger(Protocol, Error, + "rdpdr_process_irp(), received IRP for unknown device type %ld", + device); return; } @@ -431,7 +491,7 @@ in_uint32_be(s, desired_access); in_uint8s(s, 0x08); /* unknown */ - in_uint32_le(s, error_mode); + in_uint8s(s, 4); /* skip error_mode */ in_uint32_le(s, share_mode); in_uint32_le(s, disposition); in_uint32_le(s, flags_and_attributes); @@ -479,10 +539,13 @@ } in_uint32_le(s, length); - in_uint32_le(s, offset); -#if WITH_DEBUG_RDP5 - DEBUG(("RDPDR IRP Read (length: %d, offset: %d)\n", length, offset)); -#endif + in_uint64_le(s, offset); + in_uint8s(s, 20); /* 20 bytes of padding */ + + logger(Protocol, Debug, + "rdpdr_process_irp(), IRP Read length=%d, offset=%ld", + length, offset); + if (!rdpdr_handle_ok(device, file)) { status = RD_STATUS_INVALID_HANDLE; @@ -533,11 +596,13 @@ } in_uint32_le(s, length); - in_uint32_le(s, offset); - in_uint8s(s, 0x18); -#if WITH_DEBUG_RDP5 - DEBUG(("RDPDR IRP Write (length: %d)\n", result)); -#endif + in_uint64_le(s, offset); + in_uint8s(s, 20); /* 20 bytes of padding before WriteData */ + + logger(Protocol, Debug, + "rdpdr_process_irp(), IRP Write length=%d, offset=%ld", + result, offset); + if (!rdpdr_handle_ok(device, file)) { status = RD_STATUS_INVALID_HANDLE; @@ -676,7 +741,9 @@ status = RD_STATUS_INVALID_PARAMETER; /* JIF */ - unimpl("IRP major=0x%x minor=0x%x\n", major, minor); + logger(Protocol, Warning, + "rdpdr_process_irp(), unhandled minor opcode, major=0x%x, minor=0x%x", + major, minor); } break; @@ -688,11 +755,15 @@ break; } + /* DR_CONTROL_REQ (2.2.1.4.5 of MS-RDPEFS) */ + /* OutputBufferLength */ in_uint32_le(s, bytes_out); - in_uint32_le(s, bytes_in); + in_uint8s(s, 4); /* skip bytes_in */ in_uint32_le(s, request); + /* Padding */ in_uint8s(s, 0x14); + /* TODO: Why do we need to increase length by padlen? Or is it hdr len? */ out = s_alloc(bytes_out + 0x14); #ifdef WITH_SCARD @@ -738,7 +809,9 @@ break; default: - unimpl("IRP major=0x%x minor=0x%x\n", major, minor); + logger(Protocol, Warning, + "rdpdr_process_irp(), unhandled major opcode, major=0x%x, minor=0x%x", + major, minor); break; } @@ -771,35 +844,40 @@ /* DR_CORE_CAPABILITY_RSP */ STREAM s; s = channel_init(rdpdr_channel, 0x50); - out_uint16_le(s, RDPDR_CTYP_CORE); - out_uint16_le(s, PAKID_CORE_CLIENT_CAPABILITY); - out_uint32_le(s, 5); /* count */ - out_uint16_le(s, 1); /* first */ - out_uint16_le(s, 0x28); /* length */ - out_uint32_le(s, 1); - out_uint32_le(s, 2); - out_uint16_le(s, 2); - out_uint16_le(s, 5); - out_uint16_le(s, 1); - out_uint16_le(s, 5); - out_uint16_le(s, 0xFFFF); - out_uint16_le(s, 0); - out_uint32_le(s, 0); - out_uint32_le(s, 3); - out_uint32_le(s, 0); - out_uint32_le(s, 0); - out_uint16_le(s, 2); /* second */ - out_uint16_le(s, 8); /* length */ - out_uint32_le(s, 1); - out_uint16_le(s, 3); /* third */ - out_uint16_le(s, 8); /* length */ - out_uint32_le(s, 1); - out_uint16_le(s, 4); /* fourth */ - out_uint16_le(s, 8); /* length */ - out_uint32_le(s, 1); - out_uint16_le(s, 5); /* fifth */ - out_uint16_le(s, 8); /* length */ - out_uint32_le(s, 1); + + out_uint16_le(s, RDPDR_CTYP_CORE); /* Header */ + out_uint16_le(s, PAKID_CORE_CLIENT_CAPABILITY); /* Header */ + out_uint16_le(s, 5); /* numCapabilities */ + out_uint16_le(s, 0); /* Padding */ + + out_uint16_le(s, CAP_GENERAL_TYPE); /* CapabilityType */ + out_uint16_le(s, 0x28); /* CapabilityLength */ + out_uint32_le(s, GENERAL_CAPABILITY_VERSION_01); /* Version */ + out_uint32_le(s, 0); /* osType */ + out_uint32_le(s, 0); /* osVersion */ + out_uint16_le(s, 1); /* protocolMajorVersion */ + out_uint16_le(s, 5); /* protocolMinorVersion */ + out_uint32_le(s, ALL_RDPDR_IRP_MJ); /* ioCode1 */ + out_uint32_le(s, 0); /* ioCode2 */ + out_uint32_le(s, RDPDR_DEVICE_REMOVE_PDUS | RDPDR_CLIENT_DISPLAY_NAME_PDU); /* extendedPDU */ + out_uint32_le(s, 0); /* extraFlags1 */ + out_uint32_le(s, 0); /* extraFlags2 */ + + out_uint16_le(s, CAP_PRINTER_TYPE); /* CapabilityType */ + out_uint16_le(s, 8); /* CapabilityLength */ + out_uint32_le(s, PRINT_CAPABILITY_VERSION_01); /* Version */ + + out_uint16_le(s, CAP_PORT_TYPE); /* CapabilityType */ + out_uint16_le(s, 8); /* CapabilityLength */ + out_uint32_le(s, PORT_CAPABILITY_VERSION_01); /* Version */ + + out_uint16_le(s, CAP_DRIVE_TYPE); /* CapabilityType */ + out_uint16_le(s, 8); /* CapabilityLength */ + out_uint32_le(s, DRIVE_CAPABILITY_VERSION_02); /* Version */ + + out_uint16_le(s, CAP_SMARTCARD_TYPE); /* CapabilityType */ + out_uint16_le(s, 8); /* CapabilityLength */ + out_uint32_le(s, SMARTCARD_CAPABILITY_VERSION_01); /* Version */ s_mark_end(s); channel_send(s, rdpdr_channel); @@ -814,13 +892,11 @@ uint16 component; uint16 pakid; -#if WITH_DEBUG_RDP5 - printf("--- rdpdr_process ---\n"); - hexdump(s->p, s_remaining(s)); -#endif + logger(Protocol, Debug, "rdpdr_process()"); + /* hexdump(s->p, s_remaining(s)); */ - in_uint16(s, component); - in_uint16(s, pakid); + in_uint16(s, component); /* RDPDR_HEADER.Component */ + in_uint16(s, pakid); /* RDPDR_HEADER.PacketId */ if (component == RDPDR_CTYP_CORE) { @@ -843,6 +919,30 @@ g_client_id = 0x815ed39d; /* IP address (use 127.0.0.1) 0x815ed39d */ g_epoch++; +#if WITH_SCARD + /* + * We need to release all SCARD contexts to end all + * current transactions and pending calls + */ + scard_release_all_contexts(); + + /* + * According to [MS-RDPEFS] 3.2.5.1.2: + * + * If this packet appears after a sequence of other packets, + * it is a signal that the server has reconnected to a new session + * and the whole sequence has been reset. The client MUST treat + * this packet as the beginning of a new sequence. + * The client MUST also cancel all outstanding requests and release + * previous references to all devices. + * + * If any problem arises in the future, please, pay attention to the + * "If this packet appears after a sequence of other packets" part + * + */ + +#endif + rdpdr_send_client_announce_reply(); rdpdr_send_client_name_request(); break; @@ -853,9 +953,8 @@ case PAKID_CORE_DEVICE_REPLY: in_uint32(s, handle); -#if WITH_DEBUG_RDP5 - DEBUG(("RDPDR: Server connected to resource %d\n", handle)); -#endif + logger(Protocol, Debug, + "rdpdr_process(), server connected to resource %d", handle); break; case PAKID_CORE_SERVER_CAPABILITY: @@ -863,7 +962,9 @@ break; default: - unimpl("RDPDR pakid 0x%x of component 0x%x\n", pakid, component); + logger(Protocol, Debug, + "rdpdr_process(), pakid 0x%x of component 0x%x", pakid, + component); break; } @@ -874,7 +975,7 @@ printercache_process(s); } else - unimpl("RDPDR component 0x%x\n", component); + logger(Protocol, Warning, "rdpdr_process(), unhandled component 0x%x", component); } RD_BOOL @@ -892,7 +993,7 @@ void rdpdr_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv, RD_BOOL * timeout) { - uint32 select_timeout = 0; /* Timeout value to be used for select() (in millisecons). */ + uint32 select_timeout = 0; /* Timeout value to be used for select() (in milliseconds). */ struct async_iorequest *iorq; char c; @@ -910,7 +1011,7 @@ support for reconnects. */ FD_SET(iorq->fd, rfds); - *n = MAX(*n, iorq->fd); + *n = MAX(*n, (int) iorq->fd); /* Check if io request timeout is smaller than current (but not 0). */ if (iorq->timeout @@ -945,7 +1046,7 @@ break; FD_SET(iorq->fd, wfds); - *n = MAX(*n, iorq->fd); + *n = MAX(*n, (int) iorq->fd); break; case IRP_MJ_DEVICE_CONTROL: @@ -1074,17 +1175,19 @@ iorq->partial_len += result; iorq->offset += result; } -#if WITH_DEBUG_RDP5 - DEBUG(("RDPDR: %d bytes of data read\n", result)); -#endif + + logger(Protocol, Debug, + "_rdpdr_check_fds(), %d bytes of data read", + result); + /* only delete link if all data has been transfered */ /* or if result was 0 and status success - EOF */ if ((iorq->partial_len == iorq->length) || (result == 0)) { -#if WITH_DEBUG_RDP5 - DEBUG(("RDPDR: AIO total %u bytes read of %u\n", iorq->partial_len, iorq->length)); -#endif + logger(Protocol, Debug, + "_rdpdr_check_fds(), AIO total %u bytes read of %u", + iorq->partial_len, iorq->length); rdpdr_send_completion(iorq->device, iorq->id, status, iorq->partial_len, @@ -1117,18 +1220,18 @@ iorq->offset += result; } -#if WITH_DEBUG_RDP5 - DEBUG(("RDPDR: %d bytes of data written\n", - result)); -#endif + logger(Protocol, Debug, + "_rdpdr_check_fds(), %d bytes of data written", + result); + /* only delete link if all data has been transfered */ /* or we couldn't write */ if ((iorq->partial_len == iorq->length) || (result == 0)) { -#if WITH_DEBUG_RDP5 - DEBUG(("RDPDR: AIO total %u bytes written of %u\n", iorq->partial_len, iorq->length)); -#endif + logger(Protocol, Debug, + "_rdpdr_check_fds(), AIO total %u bytes written of %u", + iorq->partial_len, iorq->length); rdpdr_send_completion(iorq->device, iorq->id, status, iorq->partial_len, diff -Nru rdesktop-1.8.6/rdpedisp.c rdesktop-1.9.0/rdpedisp.c --- rdesktop-1.8.6/rdpedisp.c 1970-01-01 00:00:00.000000000 +0000 +++ rdesktop-1.9.0/rdpedisp.c 2019-06-13 12:10:15.000000000 +0000 @@ -0,0 +1,157 @@ +/* -*- c-basic-offset: 8 -*- + rdesktop: A Remote Desktop Protocol client. + Display Update Virtual Channel Extension. + Copyright 2017 Henrik Andersson <hean01@cendio.com> for Cendio AB + Copyright 2017 Karl Mikaelsson <derfian@cendio.se> for Cendio AB + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "rdesktop.h" + +#define DISPLAYCONTROL_PDU_TYPE_CAPS 0x5 +#define DISPLAYCONTROL_PDU_TYPE_MONITOR_LAYOUT 0x2 + +#define DISPLAYCONTROL_MONITOR_PRIMARY 0x1 +#define RDPEDISP_CHANNEL_NAME "Microsoft::Windows::RDS::DisplayControl" + +extern int g_dpi; +extern RD_BOOL g_pending_resize_defer; +extern struct timeval g_pending_resize_defer_timer; + +static void rdpedisp_send(STREAM s); +static void rdpedisp_init_packet(STREAM s, uint32 type, uint32 length); + +static void +rdpedisp_process_caps_pdu(STREAM s) +{ + uint32 tmp[3]; + + in_uint32_le(s, tmp[0]); /* MaxNumMonitors */ + in_uint32_le(s, tmp[1]); /* MaxMonitorAreaFactorA */ + in_uint32_le(s, tmp[2]); /* MaxMonitorAreaFactorB */ + + logger(Protocol, Debug, + "rdpedisp_process_caps_pdu(), Max supported monitor area (square pixels) is %d", + tmp[0] * tmp[1] * tmp[2]); + + /* When the RDPEDISP channel is established, we allow dynamic + session resize straight away by clearing the defer flag and + the defer timer. This lets process_pending_resize() start + processing pending resizes immediately. We expect that + process_pending_resize will prefer RDPEDISP resizes over + disconnect/reconnect resizes. */ + g_pending_resize_defer = False; + g_pending_resize_defer_timer.tv_sec = 0; + g_pending_resize_defer_timer.tv_usec = 0; +} + +static void +rdpedisp_process_pdu(STREAM s) +{ + uint32 type; + + /* Read DISPLAYCONTROL_HEADER */ + in_uint32_le(s, type); /* type */ + in_uint8s(s, 4); /* length */ + + logger(Protocol, Debug, "rdpedisp_process_pdu(), Got PDU type %d", type); + + switch (type) + { + case DISPLAYCONTROL_PDU_TYPE_CAPS: + rdpedisp_process_caps_pdu(s); + break; + + default: + logger(Protocol, Warning, "rdpedisp_process_pdu(), Unhandled PDU type %d", + type); + break; + } +} + +static void +rdpedisp_send_monitor_layout_pdu(uint32 width, uint32 height) +{ + struct stream s; + uint32 physwidth, physheight, desktopscale, devicescale; + + memset(&s, 0, sizeof(s)); + + logger(Protocol, Debug, "rdpedisp_send_monitor_layout_pdu(), width = %d, height = %d", + width, height); + + rdpedisp_init_packet(&s, DISPLAYCONTROL_PDU_TYPE_MONITOR_LAYOUT, 16 + 1 * 40); + + out_uint32_le(&s, 40); /* MonitorLayoutSize - spec mandates 40 */ + out_uint32_le(&s, 1); /* NumMonitors */ + + out_uint32_le(&s, DISPLAYCONTROL_MONITOR_PRIMARY); /* flags */ + out_uint32_le(&s, 0); /* left */ + out_uint32_le(&s, 0); /* top */ + out_uint32_le(&s, width); /* width */ + out_uint32_le(&s, height); /* height */ + + utils_calculate_dpi_scale_factors(width, height, g_dpi, + &physwidth, &physheight, &desktopscale, &devicescale); + + out_uint32_le(&s, physwidth); /* physicalwidth */ + out_uint32_le(&s, physheight); /* physicalheight */ + out_uint32_le(&s, ORIENTATION_LANDSCAPE); /* Orientation */ + out_uint32_le(&s, desktopscale); /* DesktopScaleFactor */ + out_uint32_le(&s, devicescale); /* DeviceScaleFactor */ + s_mark_end(&s); + + rdpedisp_send(&s); +} + +static void +rdpedisp_init_packet(STREAM s, uint32 type, uint32 length) +{ + s_realloc(s, length); + s_reset(s); + + out_uint32_le(s, type); + out_uint32_le(s, length); +} + +static void +rdpedisp_send(STREAM s) +{ + dvc_send(RDPEDISP_CHANNEL_NAME, s); +} + +RD_BOOL +rdpedisp_is_available() +{ + return dvc_channels_is_available(RDPEDISP_CHANNEL_NAME); +} + +void +rdpedisp_set_session_size(uint32 width, uint32 height) +{ + if (rdpedisp_is_available() == False) + return; + + /* monitor width MUST be even number */ + utils_apply_session_size_limitations(&width, &height); + + rdpedisp_send_monitor_layout_pdu(width, height); +} + +void +rdpedisp_init(void) +{ + dvc_channels_register(RDPEDISP_CHANNEL_NAME, rdpedisp_process_pdu); +} diff -Nru rdesktop-1.8.6/rdpsnd_alsa.c rdesktop-1.9.0/rdpsnd_alsa.c --- rdesktop-1.8.6/rdpsnd_alsa.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/rdpsnd_alsa.c 2019-09-17 14:58:24.000000000 +0000 @@ -33,10 +33,10 @@ #define MAX_FRAMES 32 static struct pollfd pfds_out[32]; -static int num_fds_out; +static size_t num_fds_out; static struct pollfd pfds_in[32]; -static int num_fds_in; +static size_t num_fds_in; static snd_pcm_t *out_handle = NULL; static snd_pcm_t *in_handle = NULL; @@ -59,6 +59,7 @@ void alsa_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv) { + UNUSED(tv); int err; struct pollfd *f; @@ -168,27 +169,26 @@ snd_pcm_hw_params_t *hwparams = NULL; int err; unsigned int buffertime; - short samplewidth; - int audiochannels; unsigned int rate; - samplewidth = pwfx->wBitsPerSample / 8; - if ((err = snd_pcm_hw_params_malloc(&hwparams)) < 0) { - error("snd_pcm_hw_params_malloc: %s\n", snd_strerror(err)); + logger(Sound, Error, "alsa_set_format(), snd_pcm_hw_params_malloc() failed: %s", + snd_strerror(err)); return False; } if ((err = snd_pcm_hw_params_any(pcm, hwparams)) < 0) { - error("snd_pcm_hw_params_any: %s\n", snd_strerror(err)); + logger(Sound, Error, "alsa_set_format(), snd_pcm_hw_params_any() failed: %s", + snd_strerror(err)); return False; } if ((err = snd_pcm_hw_params_set_access(pcm, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { - error("snd_pcm_hw_params_set_access: %s\n", snd_strerror(err)); + logger(Sound, Error, "alsa_set_format(), snd_pcm_hw_params_set_access() failed: %s", + snd_strerror(err)); return False; } @@ -196,7 +196,9 @@ { if ((err = snd_pcm_hw_params_set_format(pcm, hwparams, SND_PCM_FORMAT_S16_LE)) < 0) { - error("snd_pcm_hw_params_set_format: %s\n", snd_strerror(err)); + logger(Sound, Error, + "alsa_set_format(), snd_pcm_hw_params_set_format() failed: %s", + snd_strerror(err)); return False; } } @@ -204,7 +206,9 @@ { if ((err = snd_pcm_hw_params_set_format(pcm, hwparams, SND_PCM_FORMAT_S8)) < 0) { - error("snd_pcm_hw_params_set_format: %s\n", snd_strerror(err)); + logger(Sound, Error, + "alsa_set_format(), snd_pcm_hw_params_set_format() failed: %s", + snd_strerror(err)); return False; } } @@ -212,7 +216,9 @@ #if 0 if ((err = snd_pcm_hw_params_set_rate_resample(pcm, hwparams, 1)) < 0) { - error("snd_pcm_hw_params_set_rate_resample: %s\n", snd_strerror(err)); + logger(Sound, Error, + "alsa_set_format(), snd_pcm_hw_params_set_rate_resample() failed: %s", + snd_strerror(err)); return False; } #endif @@ -220,14 +226,17 @@ rate = pwfx->nSamplesPerSec; if ((err = snd_pcm_hw_params_set_rate_near(pcm, hwparams, &rate, 0)) < 0) { - error("snd_pcm_hw_params_set_rate_near: %s\n", snd_strerror(err)); + logger(Sound, Error, + "alsa_set_format(), snd_pcm_hw_params_set_rate_near() failed: %s", + snd_strerror(err)); return False; } - audiochannels = pwfx->nChannels; if ((err = snd_pcm_hw_params_set_channels(pcm, hwparams, pwfx->nChannels)) < 0) { - error("snd_pcm_hw_params_set_channels: %s\n", snd_strerror(err)); + logger(Sound, Error, + "alsa_set_format(), snd_pcm_hw_params_set_channels() failed: %s", + snd_strerror(err)); return False; } @@ -235,13 +244,16 @@ buffertime = 500000; /* microseconds */ if ((err = snd_pcm_hw_params_set_buffer_time_near(pcm, hwparams, &buffertime, 0)) < 0) { - error("snd_pcm_hw_params_set_buffer_time_near: %s\n", snd_strerror(err)); + logger(Sound, Error, + "alsa_set_format(), snd_pcm_hw_params_set_buffer_time_near() failed: %s", + snd_strerror(err)); return False; } if ((err = snd_pcm_hw_params(pcm, hwparams)) < 0) { - error("snd_pcm_hw_params: %s\n", snd_strerror(err)); + logger(Sound, Error, "alsa_set_format(), snd_pcm_hw_params(): %s", + snd_strerror(err)); return False; } @@ -249,7 +261,8 @@ if ((err = snd_pcm_prepare(pcm)) < 0) { - error("snd_pcm_prepare: %s\n", snd_strerror(err)); + logger(Sound, Error, "alsa_set_format(), snd_pcm_prepare() failed: %s\n", + snd_strerror(err)); return False; } @@ -265,7 +278,8 @@ if ((err = snd_pcm_open(&out_handle, pcm_name, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { - error("snd_pcm_open: %s\n", snd_strerror(err)); + logger(Sound, Error, "alsa_open_out(), snd_pcm_open() failed: %s", + snd_strerror(err)); return False; } @@ -297,13 +311,17 @@ if ((err = snd_pcm_hw_params_malloc(&hwparams)) < 0) { - error("snd_pcm_hw_params_malloc: %s\n", snd_strerror(err)); + logger(Sound, Error, + "alsa_format_supported(), snd_pcm_hw_params_malloc() failed: %s", + snd_strerror(err)); return False; } if ((err = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0) { - error("snd_pcm_hw_params_malloc: %s\n", snd_strerror(err)); + logger(Sound, Error, + "alsa_format_supported(), snd_pcm_hw_params_any() failed: %s\n", + snd_strerror(err)); return False; } snd_pcm_hw_params_free(hwparams); @@ -343,7 +361,7 @@ const unsigned char *data; size_t before; static long prev_s, prev_us; - unsigned int duration; + int duration; struct timeval tv; int next_tick; @@ -373,7 +391,6 @@ len = snd_pcm_writei(out_handle, data, len); if (len < 0) { - printf("Fooo!\n"); snd_pcm_prepare(out_handle); len = 0; } @@ -398,9 +415,10 @@ if (abs((next_tick - packet->tick) - duration) > 20) { - DEBUG(("duration: %d, calc: %d, ", duration, next_tick - packet->tick)); - DEBUG(("last: %d, is: %d, should: %d\n", packet->tick, - (packet->tick + duration) % 65536, next_tick % 65536)); + logger(Sound, Debug, + "alsa_play(), duration=%d, calc=%d, last=%d, is=%d, should=%d", + duration, next_tick - packet->tick, packet->tick, + (packet->tick + duration) % 65536, next_tick % 65536); } if (snd_pcm_delay(out_handle, &delay_frames) < 0) @@ -422,7 +440,8 @@ if ((err = snd_pcm_open(&in_handle, pcm_name, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) { - error("snd_pcm_open: %s\n", snd_strerror(err)); + logger(Sound, Error, "alsa_open_in(), snd_pcm_open() failed: %s", + snd_strerror(err)); return False; } @@ -449,7 +468,8 @@ if ((err = snd_pcm_start(in_handle)) < 0) { - error("snd_pcm_start: %s\n", snd_strerror(err)); + logger(Sound, Error, "alsa_open_in(), snd_pcm_start() failed: %s", + snd_strerror(err)); return False; } diff -Nru rdesktop-1.8.6/rdpsnd.c rdesktop-1.9.0/rdpsnd.c --- rdesktop-1.8.6/rdpsnd.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/rdpsnd.c 2019-09-17 14:58:24.000000000 +0000 @@ -3,8 +3,10 @@ Sound Channel Process Functions Copyright 2006-2010 Pierre Ossman <ossman@cendio.se> for Cendio AB Copyright 2009-2011 Peter Astrand <astrand@cendio.se> for Cendio AB + Copyright 2017 Henrik Andersson <hean01@cendio.se> for Cendio AB Copyright (C) Matthew Chapman <matthewc.unsw.edu.au> 2003-2008 Copyright (C) GuoJunBo <guojunbo@ict.ac.cn> 2003 + Copyright 2017 Karl Mikaelsson <derfian@cendio.se> for Cendio AB 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 @@ -26,26 +28,19 @@ #include "rdpsnd.h" #include "rdpsnd_dsp.h" -#define RDPSND_CLOSE 1 -#define RDPSND_WRITE 2 -#define RDPSND_SET_VOLUME 3 -#define RDPSND_UNKNOWN4 4 -#define RDPSND_COMPLETION 5 -#define RDPSND_PING 6 -#define RDPSND_NEGOTIATE 7 - -#define RDPSND_REC_NEGOTIATE 39 -#define RDPSND_REC_START 40 -#define RDPSND_REC_STOP 41 -#define RDPSND_REC_DATA 42 -#define RDPSND_REC_SET_VOLUME 43 - -/* Special flag for RDPSND recording extension, - not defined in MS specs. - - See doc/rdpsnd-rec.txt for more information. -*/ -#define RDPSND_FLAG_RECORD 0x00800000 +#define SNDC_CLOSE 0x01 +#define SNDC_WAVE 0x02 +#define SNDC_SETVOLUME 0x03 +#define SNDC_SETPITCH 0x04 +#define SNDC_WAVECONFIRM 0x05 +#define SNDC_TRAINING 0x06 +#define SNDC_FORMATS 0x07 +#define SNDC_CRYPTKEY 0x08 +#define SNDC_WAVEENCRYPT 0x09 +#define SNDC_UDPWAVE 0x0A +#define SNDC_UDPWAVELAST 0x0B +#define SNDC_QUALITYMODE 0x0C +#define SNDC_WAVE2 0x0D #define MAX_FORMATS 10 #define MAX_QUEUE 50 @@ -58,25 +53,16 @@ struct audio_driver *current_driver = NULL; static RD_BOOL rdpsnd_negotiated; -static RD_BOOL rdpsnd_rec_negotiated; static RD_BOOL device_open; -static RD_BOOL rec_device_open; static RD_WAVEFORMATEX formats[MAX_FORMATS]; static unsigned int format_count; static unsigned int current_format; -static RD_WAVEFORMATEX rec_formats[MAX_FORMATS]; -static unsigned int rec_format_count; -static unsigned int rec_current_format; - unsigned int queue_hi, queue_lo, queue_pending; struct audio_packet packet_queue[MAX_QUEUE]; -static char record_buffer[8192]; -static uint32 record_buffer_size; - static uint8 packet_opcode; static size_t packet_len; static struct stream packet; @@ -90,12 +76,13 @@ static long rdpsnd_queue_next_completion(void); static STREAM -rdpsnd_init_packet(uint16 type, uint16 size) +rdpsnd_init_packet(uint8 type, uint16 size) { STREAM s; s = channel_init(rdpsnd_channel, size + 4); - out_uint16_le(s, type); + out_uint8(s, type); + out_uint8(s, 0); /* protocol-mandated padding */ out_uint16_le(s, size); return s; } @@ -107,11 +94,11 @@ } static void -rdpsnd_send_completion(uint16 tick, uint8 packet_index) +rdpsnd_send_waveconfirm(uint16 tick, uint8 packet_index) { STREAM s; - s = rdpsnd_init_packet(RDPSND_COMPLETION, 4); + s = rdpsnd_init_packet(SNDC_WAVECONFIRM, 4); out_uint16_le(s, tick); out_uint8(s, packet_index); out_uint8(s, 0); @@ -119,94 +106,16 @@ rdpsnd_send(s); s_free(s); - DEBUG_SOUND(("RDPSND: -> RDPSND_COMPLETION(tick: %u, index: %u)\n", - (unsigned) tick, (unsigned) packet_index)); -} - -static void -rdpsnd_flush_record(void) -{ - STREAM s; - unsigned int chunk_size; - char *data; - - if (record_buffer_size == 0) - return; - - assert(record_buffer_size <= sizeof(record_buffer)); - - data = record_buffer; - - /* - * Microsoft's RDP server keeps dropping chunks, so we need to - * transmit everything inside one channel fragment or we risk - * making the rdpsnd server go out of sync with the byte stream. - */ - while (record_buffer_size) - { - if (record_buffer_size < 1596) - chunk_size = record_buffer_size; - else - chunk_size = 1596; - - s = rdpsnd_init_packet(RDPSND_REC_DATA, chunk_size); - out_uint8a(s, data, chunk_size); - - s_mark_end(s); - rdpsnd_send(s); - s_free(s); - - data = data + chunk_size; - record_buffer_size -= chunk_size; - - DEBUG_SOUND(("RDPSND: -> RDPSND_REC_DATA(length: %u)\n", (unsigned) chunk_size)); - } - - record_buffer_size = 0; -} - -static void -rdpsnd_clear_record(void) -{ - /* - * Silently drop everything we have in the record buffer as - * we've somehow gotten a reset in regard to the server. - */ - record_buffer_size = 0; + logger(Sound, Debug, "rdpsnd_send_waveconfirm(), tick=%u, index=%u", + (unsigned) tick, (unsigned) packet_index); } void rdpsnd_record(const void *data, unsigned int size) { - uint32 remain, chunk; - - assert(rec_device_open); - - while (size) - { - remain = sizeof(record_buffer) - record_buffer_size; - - if (size >= remain) - chunk = remain; - else - chunk = size; - - memcpy(record_buffer + record_buffer_size, data, chunk); - -#ifdef B_ENDIAN - if (current_driver->need_byteswap_on_be) - rdpsnd_dsp_swapbytes(record_buffer + record_buffer_size, - chunk, &rec_formats[rec_current_format]); -#endif - - record_buffer_size += chunk; - - data = (const char *) data + chunk; - size -= chunk; - - if (record_buffer_size == sizeof(record_buffer)) - rdpsnd_flush_record(); - } + UNUSED(data); + UNUSED(size); + /* TODO: Send audio over RDP */ } static RD_BOOL @@ -219,17 +128,19 @@ current_driver = drivers; while (current_driver != NULL) { - DEBUG(("trying %s...\n", current_driver->name)); + logger(Sound, Debug, "rdpsnd_auto_select(), trying driver '%s'", + current_driver->name); if (current_driver->wave_out_open()) { - DEBUG(("selected %s\n", current_driver->name)); + logger(Sound, Verbose, "rdpsnd_auto_select(), using driver '%s'", + current_driver->name); current_driver->wave_out_close(); return True; } current_driver = current_driver->next; } - warning("no working audio-driver found\n"); + logger(Sound, Debug, "no working audio-driver found"); failed = True; current_driver = NULL; } @@ -255,12 +166,12 @@ in_uint16_le(in, version); in_uint8s(in, 1); /* padding */ - DEBUG_SOUND(("RDPSND: RDPSND_NEGOTIATE(formats: %d, pad: 0x%02x, version: %x)\n", - (int) in_format_count, (unsigned) pad, (unsigned) version)); + logger(Sound, Debug, + "rdpsnd_process_negotiate(), formats = %d, pad = 0x%02x, version = 0x%x", + (int) in_format_count, (unsigned) pad, (unsigned) version); if (rdpsnd_negotiated) { - error("RDPSND: Extra RDPSND_NEGOTIATE in the middle of a session\n"); /* Do a complete reset of the sound state */ rdpsnd_reset_state(); } @@ -293,8 +204,9 @@ discardcnt = 0; if (format->cbSize > MAX_CBSIZE) { - fprintf(stderr, "cbSize too large for buffer: %d\n", - format->cbSize); + logger(Sound, Debug, + "rdpsnd_process_negotiate(), cbSize too large for buffer: %d", + format->cbSize); readcnt = MAX_CBSIZE; discardcnt = format->cbSize - MAX_CBSIZE; } @@ -310,16 +222,15 @@ } } - out = rdpsnd_init_packet(RDPSND_NEGOTIATE | 0x200, 20 + 18 * format_count); + out = rdpsnd_init_packet(SNDC_FORMATS, 20 + 18 * format_count); uint32 flags = TSSNDCAPS_VOLUME; /* if sound is enabled, set snd caps to alive to enable - transmision of audio from server */ + transmission of audio from server */ if (g_rdpsnd) { flags |= TSSNDCAPS_ALIVE; - flags |= RDPSND_FLAG_RECORD; } out_uint32_le(out, flags); /* TSSNDCAPS flags */ @@ -346,7 +257,8 @@ s_mark_end(out); - DEBUG_SOUND(("RDPSND: -> RDPSND_NEGOTIATE(formats: %d)\n", (int) format_count)); + logger(Sound, Debug, "rdpsnd_process_negotiate(), %d formats available", + (int) format_count); rdpsnd_send(out); s_free(out); @@ -355,9 +267,10 @@ } static void -rdpsnd_process_ping(STREAM in) +rdpsnd_process_training(STREAM in) { uint16 tick; + uint16 packsize; STREAM out; struct stream packet = *in; @@ -367,117 +280,16 @@ } in_uint16_le(in, tick); + in_uint16_le(in, packsize); - DEBUG_SOUND(("RDPSND: RDPSND_PING(tick: 0x%04x)\n", (unsigned) tick)); + logger(Sound, Debug, "rdpsnd_process_training(), tick=0x%04x", (unsigned) tick); - out = rdpsnd_init_packet(RDPSND_PING | 0x2300, 4); + out = rdpsnd_init_packet(SNDC_TRAINING, 4); out_uint16_le(out, tick); - out_uint16_le(out, 0); - s_mark_end(out); - rdpsnd_send(out); - s_free(out); - - DEBUG_SOUND(("RDPSND: -> (tick: 0x%04x)\n", (unsigned) tick)); -} - -static void -rdpsnd_process_rec_negotiate(STREAM in) -{ - uint16 in_format_count, i; - uint16 version; - RD_WAVEFORMATEX *format; - STREAM out; - RD_BOOL device_available = False; - int readcnt; - int discardcnt; - - in_uint8s(in, 8); /* initial bytes not valid from server */ - in_uint16_le(in, in_format_count); - in_uint16_le(in, version); - - DEBUG_SOUND(("RDPSND: RDPSND_REC_NEGOTIATE(formats: %d, version: %x)\n", - (int) in_format_count, (unsigned) version)); - - if (rdpsnd_rec_negotiated) - { - error("RDPSND: Extra RDPSND_REC_NEGOTIATE in the middle of a session\n"); - /* Do a complete reset of the sound state */ - rdpsnd_reset_state(); - } - - if (!current_driver) - device_available = rdpsnd_auto_select(); - - if (current_driver && !device_available && current_driver->wave_in_open - && current_driver->wave_in_open()) - { - current_driver->wave_in_close(); - device_available = True; - } - - rec_format_count = 0; - if (s_check_rem(in, 18 * in_format_count)) - { - for (i = 0; i < in_format_count; i++) - { - format = &rec_formats[rec_format_count]; - in_uint16_le(in, format->wFormatTag); - in_uint16_le(in, format->nChannels); - in_uint32_le(in, format->nSamplesPerSec); - in_uint32_le(in, format->nAvgBytesPerSec); - in_uint16_le(in, format->nBlockAlign); - in_uint16_le(in, format->wBitsPerSample); - in_uint16_le(in, format->cbSize); - - /* read in the buffer of unknown use */ - readcnt = format->cbSize; - discardcnt = 0; - if (format->cbSize > MAX_CBSIZE) - { - fprintf(stderr, "cbSize too large for buffer: %d\n", - format->cbSize); - readcnt = MAX_CBSIZE; - discardcnt = format->cbSize - MAX_CBSIZE; - } - in_uint8a(in, format->cb, readcnt); - in_uint8s(in, discardcnt); - - if (current_driver && current_driver->wave_in_format_supported - && current_driver->wave_in_format_supported(format)) - { - rec_format_count++; - if (rec_format_count == MAX_FORMATS) - break; - } - } - } - - out = rdpsnd_init_packet(RDPSND_REC_NEGOTIATE, 12 + 18 * rec_format_count); - out_uint32_le(out, 0x00000000); /* flags */ - out_uint32_le(out, 0xffffffff); /* volume */ - out_uint16_le(out, rec_format_count); - out_uint16_le(out, 1); /* version */ - - for (i = 0; i < rec_format_count; i++) - { - format = &rec_formats[i]; - out_uint16_le(out, format->wFormatTag); - out_uint16_le(out, format->nChannels); - out_uint32_le(out, format->nSamplesPerSec); - out_uint32_le(out, format->nAvgBytesPerSec); - out_uint16_le(out, format->nBlockAlign); - out_uint16_le(out, format->wBitsPerSample); - out_uint16(out, 0); /* cbSize */ - } - + out_uint16_le(out, packsize); s_mark_end(out); - - DEBUG_SOUND(("RDPSND: -> RDPSND_REC_NEGOTIATE(formats: %d)\n", (int) rec_format_count)); - rdpsnd_send(out); s_free(out); - - rdpsnd_rec_negotiated = True; } static void @@ -492,16 +304,20 @@ switch (opcode) { - case RDPSND_WRITE: + case SNDC_WAVE: in_uint16_le(s, tick); in_uint16_le(s, format); in_uint8(s, packet_index); in_uint8s(s, 3); - DEBUG_SOUND(("RDPSND: RDPSND_WRITE(tick: %u, format: %u, index: %u, data: %u bytes)\n", (unsigned) tick, (unsigned) format, (unsigned) packet_index, (unsigned) s->size - 8)); + logger(Sound, Debug, + "rdpsnd_process_packet(), RDPSND_WRITE(tick: %u, format: %u, index: %u, data: %u bytes)\n", + (unsigned) tick, (unsigned) format, (unsigned) packet_index, + (unsigned) s->size - 8); if (format >= MAX_FORMATS) { - error("RDPSND: Invalid format index\n"); + logger(Sound, Error, + "rdpsnd_process_packet(), invalid format index"); break; } @@ -510,21 +326,21 @@ /* * If we haven't selected a device by now, then either * we've failed to find a working device, or the server - * is sending bogus RDPSND_WRITE. + * is sending bogus SNDC_WAVE. */ if (!current_driver) { - rdpsnd_send_completion(tick, packet_index); + rdpsnd_send_waveconfirm(tick, packet_index); break; } if (!device_open && !current_driver->wave_out_open()) { - rdpsnd_send_completion(tick, packet_index); + rdpsnd_send_waveconfirm(tick, packet_index); break; } if (!current_driver->wave_out_set_format(&formats[format])) { - rdpsnd_send_completion(tick, packet_index); + rdpsnd_send_waveconfirm(tick, packet_index); current_driver->wave_out_close(); device_open = False; break; @@ -541,72 +357,31 @@ tick, packet_index); return; break; - case RDPSND_CLOSE: - DEBUG_SOUND(("RDPSND: RDPSND_CLOSE()\n")); + case SNDC_CLOSE: + logger(Sound, Debug, "rdpsnd_process_packet(), SNDC_CLOSE()"); if (device_open) current_driver->wave_out_close(); device_open = False; break; - case RDPSND_NEGOTIATE: + case SNDC_FORMATS: rdpsnd_process_negotiate(s); break; - case RDPSND_PING: - rdpsnd_process_ping(s); + case SNDC_TRAINING: + rdpsnd_process_training(s); break; - case RDPSND_SET_VOLUME: + case SNDC_SETVOLUME: in_uint16_le(s, vol_left); in_uint16_le(s, vol_right); - DEBUG_SOUND(("RDPSND: RDPSND_VOLUME(left: 0x%04x (%u %%), right: 0x%04x (%u %%))\n", (unsigned) vol_left, (unsigned) vol_left / 655, (unsigned) vol_right, (unsigned) vol_right / 655)); + logger(Sound, Debug, + "rdpsnd_process_packet(), SNDC_SETVOLUME(left: 0x%04x (%u %%), right: 0x%04x (%u %%))", + (unsigned) vol_left, (unsigned) vol_left / 655, (unsigned) vol_right, + (unsigned) vol_right / 655); if (device_open) current_driver->wave_out_volume(vol_left, vol_right); break; - case RDPSND_REC_NEGOTIATE: - rdpsnd_process_rec_negotiate(s); - break; - case RDPSND_REC_START: - in_uint16_le(s, format); - DEBUG_SOUND(("RDPSND: RDPSND_REC_START(format: %u)\n", (unsigned) format)); - - if (format >= MAX_FORMATS) - { - error("RDPSND: Invalid format index\n"); - break; - } - - if (rec_device_open) - { - error("RDPSND: Multiple RDPSND_REC_START\n"); - break; - } - - if (!current_driver->wave_in_open()) - break; - - if (!current_driver->wave_in_set_format(&rec_formats[format])) - { - error("RDPSND: Device not accepting format\n"); - current_driver->wave_in_close(); - break; - } - rec_current_format = format; - rec_device_open = True; - break; - case RDPSND_REC_STOP: - DEBUG_SOUND(("RDPSND: RDPSND_REC_STOP()\n")); - rdpsnd_flush_record(); - if (rec_device_open) - current_driver->wave_in_close(); - rec_device_open = False; - break; - case RDPSND_REC_SET_VOLUME: - in_uint16_le(s, vol_left); - in_uint16_le(s, vol_right); - DEBUG_SOUND(("RDPSND: RDPSND_REC_VOLUME(left: 0x%04x (%u %%), right: 0x%04x (%u %%))\n", (unsigned) vol_left, (unsigned) vol_left / 655, (unsigned) vol_right, (unsigned) vol_right / 655)); - if (rec_device_open) - current_driver->wave_in_volume(vol_left, vol_right); - break; default: - unimpl("RDPSND packet type %x\n", opcode); + logger(Sound, Warning, "rdpsnd_process_packet(), Unhandled opcode 0x%x", + opcode); break; } } @@ -621,15 +396,16 @@ { if (!s_check_rem(s, 4)) { - error("RDPSND: Split at packet header. Things will go south from here...\n"); + logger(Sound, Error, + "rdpsnd_process(), split at packet header, things will go south from here..."); return; } in_uint8(s, packet_opcode); in_uint8s(s, 1); /* Padding */ in_uint16_le(s, packet_len); - DEBUG_SOUND(("RDPSND: == Opcode %x Length: %d ==\n", - (int) packet_opcode, (int) len)); + logger(Sound, Debug, "rdpsnd_process(), Opcode = 0x%x Length= %d", + (int) packet_opcode, (int) packet_len); } else { @@ -638,14 +414,15 @@ len = MIN(s_remaining(s), packet_len - s_length(&packet)); /* Microsoft's server is so broken it's not even funny... */ - if (packet_opcode == RDPSND_WRITE) + if (packet_opcode == SNDC_WAVE) { if (s_length(&packet) < 12) len = MIN(len, 12 - s_length(&packet)); else if (s_length(&packet) == 12) { - DEBUG_SOUND(("RDPSND: Eating 4 bytes of %d bytes...\n", - len)); + logger(Sound, Debug, + "rdpsnd_process(), eating 4 bytes of %d bytes...", + len); in_uint8s(s, 4); len -= 4; } @@ -670,9 +447,8 @@ static RD_BOOL rdpsnddbg_line_handler(const char *line, void *data) { -#ifdef WITH_DEBUG_SOUND - fprintf(stderr, "SNDDBG: %s\n", line); -#endif + UNUSED(data); + logger(Sound, Debug, "rdpsnddbg_line_handler(), \"%s\"", line); return True; } @@ -702,6 +478,11 @@ /* The order of registrations define the probe-order when opening the device for the first time */ reg = &drivers; +#if defined(RDPSND_PULSE) + *reg = pulse_register(options); + assert(*reg); + reg = &((*reg)->next); +#endif #if defined(RDPSND_ALSA) *reg = alsa_register(options); assert(*reg); @@ -750,7 +531,8 @@ if ((rdpsnd_channel == NULL) || (rdpsnddbg_channel == NULL)) { - error("channel_register\n"); + logger(Sound, Error, + "rdpsnd_init(), failed to register rdpsnd / snddbg virtual channels"); return False; } @@ -783,7 +565,7 @@ { if (!strcmp(pos->name, driver)) { - DEBUG(("selected %s\n", pos->name)); + logger(Sound, Debug, "rdpsnd_init(), using driver '%s'", pos->name); current_driver = pos; return True; } @@ -800,12 +582,6 @@ device_open = False; rdpsnd_queue_clear(); rdpsnd_negotiated = False; - - if (rec_device_open) - current_driver->wave_in_close(); - rec_device_open = False; - rdpsnd_clear_record(); - rdpsnd_rec_negotiated = False; } @@ -829,7 +605,7 @@ { long next_pending; - if (device_open || rec_device_open) + if (device_open) current_driver->add_fds(n, rfds, wfds, tv); next_pending = rdpsnd_queue_next_completion(); @@ -851,7 +627,7 @@ { rdpsnd_queue_complete_pending(); - if (device_open || rec_device_open) + if (device_open) current_driver->check_fds(rfds, wfds); } @@ -863,7 +639,7 @@ if (next_hi == queue_pending) { - error("No space to queue audio packet\n"); + logger(Sound, Error, "rdpsnd_queue_write(), no space to queue audio packet"); return; } @@ -969,7 +745,7 @@ elapsed /= 1000; s_free(packet->s); - rdpsnd_send_completion((packet->tick + elapsed) % 65536, packet->index); + rdpsnd_send_waveconfirm((packet->tick + elapsed) % 65536, packet->index); queue_pending = (queue_pending + 1) % MAX_QUEUE; } } diff -Nru rdesktop-1.8.6/rdpsnd_dsp.c rdesktop-1.9.0/rdpsnd_dsp.c --- rdesktop-1.8.6/rdpsnd_dsp.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/rdpsnd_dsp.c 2019-09-17 12:34:36.000000000 +0000 @@ -2,6 +2,7 @@ rdesktop: A Remote Desktop Protocol client. Sound DSP routines Copyright (C) Michael Gernoth <mike@zerfleddert.de> 2006-2008 + Copyright 2017 Henrik Andersson <hean01@cendio.se> for Cendio AB 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 @@ -45,7 +46,7 @@ { softvol_left = left; softvol_right = right; - DEBUG(("rdpsnd_dsp_softvol_set: left: %u, right: %u\n", left, right)); + logger(Sound, Debug, "rdpsnd_dsp_softvol_set(), left: %u, right: %u\n", left, right); } void @@ -105,8 +106,9 @@ } } - DEBUG(("using softvol with factors left: %d, right: %d (%d/%d)\n", factor_left, - factor_right, format->wBitsPerSample, format->nChannels)); + logger(Sound, Debug, + "rdpsnd_dsp_softvol(), using softvol with factors left: %d, right: %d (%d/%d)", + factor_left, factor_right, format->wBitsPerSample, format->nChannels); } void @@ -119,7 +121,7 @@ return; if (size & 0x1) - warning("badly aligned sound data"); + logger(Sound, Warning, "rdpsnd_dsp_swapbytes(), badly aligned sound data"); for (i = 0; i < (int) size; i += 2) { @@ -152,7 +154,7 @@ if ((src_converter = src_new(SRC_CONVERTER, device_channels, &err)) == NULL) { - warning("src_new failed: %d!\n", err); + logger(Sound, Warning, "rdpsnd_dsp_resample_set(), src_new() failed with %d", err); return False; } #endif @@ -177,6 +179,7 @@ rdpsnd_dsp_resample(unsigned char *in, unsigned int size, RD_WAVEFORMATEX * format, RD_BOOL stream_be) { + UNUSED(stream_be); #ifdef HAVE_LIBSAMPLERATE SRC_DATA resample_data; float *infloat, *outfloat; @@ -227,12 +230,12 @@ } - /* Expand 8bit input-samples to 16bit */ -#ifndef HAVE_LIBSAMPLERATE /* libsamplerate needs 16bit samples */ + /* Expand 8-bit input-samples to 16-bit */ +#ifndef HAVE_LIBSAMPLERATE /* libsamplerate needs 16-bit samples */ if (format->wBitsPerSample != resample_to_bitspersample) #endif { - /* source: 8 bit, dest: 16bit */ + /* source: 8 bit, dest: 16 bit */ if (format->wBitsPerSample == 8) { tmp = tmpdata; @@ -257,7 +260,8 @@ #ifdef HAVE_LIBSAMPLERATE if (src_converter == NULL) { - warning("no samplerate converter available!\n"); + logger(Sound, Warning, + "rdpsndp_dsp_resample_set(), no sample rate converter available"); return NULL; } @@ -277,7 +281,8 @@ resample_data.end_of_input = 0; if ((err = src_process(src_converter, &resample_data)) != 0) - error("src_process: %s", src_strerror(err)); + logger(Sound, Warning, "rdpsnd_dsp_resample_set(), src_process(): '%s'", + src_strerror(err)); xfree(infloat); @@ -292,7 +297,8 @@ /* Michaels simple linear resampler */ if (resample_to_srate < format->nSamplesPerSec) { - warning("downsampling currently not supported!\n"); + logger(Sound, Warning, + "rdpsnd_dsp_reasmple_set(), downsampling currently not supported"); return 0; } @@ -366,8 +372,8 @@ if (tmpdata != NULL) xfree(tmpdata); - /* Shrink 16bit output-samples to 8bit */ -#ifndef HAVE_LIBSAMPLERATE /* libsamplerate produces 16bit samples */ + /* Shrink 16-bit output-samples to 8-bit */ +#ifndef HAVE_LIBSAMPLERATE /* libsamplerate produces 16-bit samples */ if (format->wBitsPerSample != resample_to_bitspersample) #endif { diff -Nru rdesktop-1.8.6/rdpsnd.h rdesktop-1.9.0/rdpsnd.h --- rdesktop-1.8.6/rdpsnd.h 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/rdpsnd.h 2019-09-17 12:34:36.000000000 +0000 @@ -52,6 +52,7 @@ }; /* Driver register functions */ +struct audio_driver *pulse_register(char *options); struct audio_driver *alsa_register(char *options); struct audio_driver *libao_register(char *options); struct audio_driver *oss_register(char *options); diff -Nru rdesktop-1.8.6/rdpsnd_libao.c rdesktop-1.9.0/rdpsnd_libao.c --- rdesktop-1.8.6/rdpsnd_libao.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/rdpsnd_libao.c 2019-09-17 12:34:36.000000000 +0000 @@ -41,6 +41,10 @@ void libao_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv) { + UNUSED(n); + UNUSED(rfds); + UNUSED(tv); + /* We need to be called rather often... */ if (o_device != NULL && !rdpsnd_queue_empty()) FD_SET(0, wfds); @@ -49,6 +53,9 @@ void libao_check_fds(fd_set * rfds, fd_set * wfds) { + UNUSED(rfds); + UNUSED(wfds); + if (o_device == NULL) return; @@ -144,7 +151,7 @@ unsigned char *data; int len; static long prev_s, prev_us; - unsigned int duration; + int duration; struct timeval tv; int next_tick; @@ -185,9 +192,11 @@ if (abs((next_tick - packet->tick) - duration) > 20) { - DEBUG(("duration: %d, calc: %d, ", duration, next_tick - packet->tick)); - DEBUG(("last: %d, is: %d, should: %d\n", packet->tick, - (packet->tick + duration) % 65536, next_tick % 65536)); + logger(Sound, Debug, + "libao_play(), duration: %d, calc: %d, last: %d, is: %d, should: %d", + duration, next_tick - packet->tick, + (packet->tick + duration) % 65536, next_tick % 65536); + } delay_us = ((out->size / 4) * (1000000 / 44100)); diff -Nru rdesktop-1.8.6/rdpsnd_oss.c rdesktop-1.9.0/rdpsnd_oss.c --- rdesktop-1.8.6/rdpsnd_oss.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/rdpsnd_oss.c 2019-09-17 12:34:36.000000000 +0000 @@ -5,6 +5,7 @@ Copyright (C) GuoJunBo <guojunbo@ict.ac.cn> 2003 Copyright 2006-2008 Pierre Ossman <ossman@cendio.se> for Cendio AB Copyright 2005-2011 Peter Astrand <astrand@cendio.se> for Cendio AB + Copyright 2017 Henrik Andersson <hean01@cendio.se> for Cendio AB 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 @@ -33,6 +34,7 @@ #include "rdesktop.h" #include "rdpsnd.h" #include "rdpsnd_dsp.h" + #include <unistd.h> #include <fcntl.h> #include <errno.h> @@ -69,6 +71,7 @@ static void oss_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv) { + UNUSED(tv); if (dsp_fd == -1) return; @@ -154,7 +157,8 @@ if ((ioctl(dsp_fd, SNDCTL_DSP_GETCAPS, &caps) < 0) || !(caps & DSP_CAP_DUPLEX)) { - warning("This device is not capable of full duplex operation.\n"); + logger(Sound, Warning, + "this OSS device is not capable of full duplex operation"); return False; } close(dsp_fd); @@ -173,7 +177,7 @@ if (dsp_fd == -1) { - perror(dsp_dev); + logger(Sound, Error, "oss_open(), open() failed: %s", strerror(errno)); return False; } @@ -282,7 +286,8 @@ if (ioctl(dsp_fd, SNDCTL_DSP_SETFMT, &format) == -1) { - perror("SNDCTL_DSP_SETFMT"); + logger(Sound, Error, "oss_set_format(), ioctl(SNDCTL_DSP_SETFMT) failed: %s", + strerror(errno)); oss_close(); return False; } @@ -299,7 +304,8 @@ if (ioctl(dsp_fd, SNDCTL_DSP_STEREO, &stereo) == -1) { - perror("SNDCTL_DSP_CHANNELS"); + logger(Sound, Error, "oss_set_format(), ioctl(SNDCTL_DSP_CHANNELS) failed: %s", + strerror(errno)); oss_close(); return False; } @@ -321,7 +327,8 @@ if (rdpsnd_dsp_resample_set (snd_rate, pwfx->wBitsPerSample, pwfx->nChannels) == False) { - error("rdpsnd_dsp_resample_set failed"); + logger(Sound, Error, + "oss_set_format(), rdpsnd_dsp_resample_set() failed"); oss_close(); return False; } @@ -333,7 +340,8 @@ if (*prates == 0) { - perror("SNDCTL_DSP_SPEED"); + logger(Sound, Error, "oss_set_format(), SNDCTL_DSP_SPEED failed: %s", + strerror(errno)); oss_close(); return False; } @@ -350,16 +358,17 @@ memset(&info, 0, sizeof(info)); if (ioctl(dsp_fd, SNDCTL_DSP_GETOSPACE, &info) == -1) { - perror("SNDCTL_DSP_GETOSPACE"); + logger(Sound, Error, "SNDCTL_DSP_GETOSPACE ioctl failed: %s", + strerror(errno)); oss_close(); return False; } if (info.fragments == 0 || info.fragstotal == 0 || info.fragsize == 0) { - fprintf(stderr, - "Broken OSS-driver detected: fragments: %d, fragstotal: %d, fragsize: %d\n", - info.fragments, info.fragstotal, info.fragsize); + logger(Sound, Error, + "broken OSS-driver detected: fragments: %d, fragstotal: %d, fragsize: %d\n", + info.fragments, info.fragstotal, info.fragsize); driver_broken = True; } } @@ -379,7 +388,8 @@ if (ioctl(dsp_fd, MIXER_WRITE(SOUND_MIXER_PCM), &volume) == -1) { - warning("hardware volume control unavailable, falling back to software volume control!\n"); + logger(Sound, Warning, + "hardware volume control unavailable, falling back to software volume control"); oss_driver.wave_out_volume = rdpsnd_dsp_softvol_set; rdpsnd_dsp_softvol_set(left, right); return; @@ -415,7 +425,7 @@ if (errno != EWOULDBLOCK) { if (!dsp_broken) - perror("RDPSND: write()"); + logger(Sound, Error, "failed to write buffer: %s", strerror(errno)); dsp_broken = True; rdpsnd_queue_next(0); } @@ -477,7 +487,7 @@ if (errno != EWOULDBLOCK) { if (!dsp_broken) - perror("RDPSND: read()"); + logger(Sound, Error, "failed to read samples: %s", strerror(errno)); dsp_broken = True; rdpsnd_queue_next(0); } diff -Nru rdesktop-1.8.6/rdpsnd_pulse.c rdesktop-1.9.0/rdpsnd_pulse.c --- rdesktop-1.8.6/rdpsnd_pulse.c 1970-01-01 00:00:00.000000000 +0000 +++ rdesktop-1.9.0/rdpsnd_pulse.c 2019-09-17 12:34:36.000000000 +0000 @@ -0,0 +1,1475 @@ +/* -*- c-basic-offset: 8 -*- + rdesktop: A Remote Desktop Protocol client. + Sound Channel Process Functions - PulseAudio + Copyright (C) Krupen'ko Nikita <krnekit@gmail.com> 2010 + Copyright (C) Henrik Andersson <hean01@cendio.com> 2017 + + 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 "rdpsnd.h" +#include "rdpsnd_dsp.h" +#include <unistd.h> +#include <fcntl.h> +#include <assert.h> +#include <errno.h> +#include <sys/time.h> + +#include <pulse/version.h> + +#ifndef PA_CHECK_VERSION +#define PA_CHECK_VERSION(major, minor, micro) (0) +#endif + +#include <pulse/thread-mainloop.h> +#if PA_CHECK_VERSION(0,9,11) +#include <pulse/proplist.h> +#endif +#include <pulse/context.h> +#include <pulse/sample.h> +#include <pulse/stream.h> +#include <pulse/error.h> + +#define DEFAULTDEVICE NULL + +/* Messages that may be sent from the PulseAudio thread */ +enum RDPSND_PULSE_MSG_TYPE +{ + RDPSND_PULSE_OUT_AVAIL, // Output space available in output stream + RDPSND_PULSE_IN_AVAIL, // Input data available in input stream + RDPSND_PULSE_OUT_ERR, // An error occured in the output stream + RDPSND_PULSE_IN_ERR // An error occured in the input strem +}; + +static pa_threaded_mainloop *mainloop; +#if PA_CHECK_VERSION(0,9,11) +static pa_proplist *proplist; +#endif +static pa_context *context; +static pa_stream *playback_stream; +static pa_stream *capture_stream; +static int pulse_ctl[2] = { -1, -1 }; // Pipe for comminicating with main thread + +/* Streams states for the possibility of the proper reinitialization */ +static RD_BOOL playback_started = False; +static RD_BOOL capture_started = False; + +/* Device's parameters */ +static const char *device; +static int playback_channels; +static int playback_samplerate; +static int playback_samplewidth; +static int capture_channels; +static int capture_samplerate; +static int capture_samplewidth; + +/* Internal audio buffer sizes (latency) */ +static const int playback_latency_part = 10; // Playback latency (in part of second) +static const int capture_latency_part = 10; // Capture latency (in part of second) + +/* Capture buffer */ +static void *capture_buf = NULL; +static size_t capture_buf_size = 0; + +static RD_BOOL pulse_init(void); +static void pulse_deinit(void); +static RD_BOOL pulse_context_init(void); +static void pulse_context_deinit(void); +static RD_BOOL pulse_stream_open(pa_stream ** stream, int channels, int samplerate, int samplewidth, + pa_stream_flags_t flags); +static void pulse_stream_close(pa_stream ** stream); + +static void pulse_send_msg(int fd, char message); + +static RD_BOOL pulse_playback_start(void); +static RD_BOOL pulse_playback_stop(void); +static RD_BOOL pulse_playback_set_audio(int channels, int samplerate, int samplewidth); +static RD_BOOL pulse_play(void); + +static RD_BOOL pulse_capture_start(void); +static RD_BOOL pulse_capture_stop(void); +static RD_BOOL pulse_capture_set_audio(int channels, int samplerate, int samplewidth); +static RD_BOOL pulse_record(void); + +static RD_BOOL pulse_recover(pa_stream ** stream); + +/* Callbacks for the PulseAudio events */ +static void pulse_context_state_cb(pa_context * c, void *userdata); +static void pulse_stream_state_cb(pa_stream * p, void *userdata); +static void pulse_write_cb(pa_stream *, size_t nbytes, void *userdata); +static void pulse_read_cb(pa_stream * p, size_t nbytes, void *userdata); + +static void pulse_cork_cb(pa_stream * p, int success, void *userdata); +static void pulse_flush_cb(pa_stream * p, int success, void *userdata); +static void pulse_update_timing_cb(pa_stream * p, int success, void *userdata); + +static RD_BOOL +pulse_init(void) +{ + RD_BOOL ret = False; + + + do + { + /* PulsaAudio mainloop thread initialization */ + mainloop = pa_threaded_mainloop_new(); + if (mainloop == NULL) + { + logger(Sound, Error, + "pulse_init(), Error creating PulseAudio threaded mainloop"); + break; + } + if (pa_threaded_mainloop_start(mainloop) != 0) + { + logger(Sound, Error, + "pulse_init(), Error starting PulseAudio threaded mainloop"); + break; + } +#if PA_CHECK_VERSION(0,9,11) + /* PulseAudio proplist initialization */ + proplist = pa_proplist_new(); + if (proplist == NULL) + { + logger(Sound, Error, "pulse_init(), Error creating PulseAudio proplist"); + break; + } + if (pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, "rdesktop") != 0) + { + logger(Sound, Error, + "pulse_init(), Error setting option to PulseAudio proplist"); + break; + } +#endif + + if (pulse_context_init() != True) + break; + + ret = True; + } + while (0); + + if (ret != True) + pulse_deinit(); + + return ret; +} + +static void +pulse_deinit(void) +{ + pulse_stream_close(&capture_stream); + pulse_stream_close(&playback_stream); + pulse_context_deinit(); +#if PA_CHECK_VERSION(0,9,11) + if (proplist != NULL) + { + pa_proplist_free(proplist); + proplist = NULL; + } +#endif + if (mainloop != NULL) + { + pa_threaded_mainloop_stop(mainloop); + pa_threaded_mainloop_free(mainloop); + mainloop = NULL; + } +} + +static RD_BOOL +pulse_context_init(void) +{ + pa_context_flags_t flags; + pa_context_state_t context_state; + int err; + RD_BOOL ret = False; + + + pa_threaded_mainloop_lock(mainloop); + + do + { + /* Pipe for the control information from the audio thread */ + if (pipe(pulse_ctl) != 0) + { + logger(Sound, Error, "pulse_context_init(), pipe: %s", strerror(errno)); + pulse_ctl[0] = pulse_ctl[1] = -1; + break; + } + if (fcntl(pulse_ctl[0], F_SETFL, O_NONBLOCK) == -1) + { + logger(Sound, Error, "pulse_context_init(), fcntl: %s", strerror(errno)); + break; + } +#if PA_CHECK_VERSION(0,9,11) + context = + pa_context_new_with_proplist(pa_threaded_mainloop_get_api(mainloop), NULL, + proplist); +#else + context = pa_context_new(pa_threaded_mainloop_get_api(mainloop), "rdesktop"); +#endif + if (context == NULL) + { + logger(Sound, Error, + "pulse_context_init(), error creating PulseAudio context"); + break; + } + pa_context_set_state_callback(context, pulse_context_state_cb, mainloop); + /* PulseAudio context connection */ +#if PA_CHECK_VERSION(0,9,15) + flags = PA_CONTEXT_NOFAIL; +#else + flags = 0; +#endif + if (pa_context_connect(context, NULL, flags, NULL) != 0) + { + err = pa_context_errno(context); + logger(Sound, Error, "pulse_context_init(), %s", pa_strerror(err)); + break; + } + do + { + context_state = pa_context_get_state(context); + if (context_state == PA_CONTEXT_READY || context_state == PA_CONTEXT_FAILED) + break; + else + pa_threaded_mainloop_wait(mainloop); + } + while (1); + if (context_state != PA_CONTEXT_READY) + { + err = pa_context_errno(context); + logger(Sound, Error, "pulse_context_init(), %s", pa_strerror(err)); + break; + } + + ret = True; + } + while (0); + + pa_threaded_mainloop_unlock(mainloop); + + return ret; +} + +static void +pulse_context_deinit(void) +{ + int err; + + + if (context != NULL) + { + pa_threaded_mainloop_lock(mainloop); + + pa_context_disconnect(context); + pa_context_unref(context); + context = NULL; + + pa_threaded_mainloop_unlock(mainloop); + } + + if (pulse_ctl[0] != -1) + { + do + err = close(pulse_ctl[0]); + while (err == -1 && errno == EINTR); + if (err == -1) + logger(Sound, Error, "pulse_context_deinit(), close: %s", strerror(errno)); + pulse_ctl[0] = -1; + } + if (pulse_ctl[1] != -1) + { + do + err = close(pulse_ctl[1]); + while (err == -1 && errno == EINTR); + if (err == -1) + logger(Sound, Error, "pulse_context_deinit(), close: %s", strerror(errno)); + pulse_ctl[1] = 0; + } +} + +static RD_BOOL +pulse_stream_open(pa_stream ** stream, int channels, int samplerate, int samplewidth, + pa_stream_flags_t flags) +{ + pa_sample_spec samples; + pa_buffer_attr buffer_attr; + pa_stream_state_t state; + int err; + RD_BOOL ret = False; + + + assert(stream != NULL); + assert(stream == &playback_stream || stream == &capture_stream); + + logger(Sound, Debug, "pulse_stream_open(), channels=%d, samplerate=%d, samplewidth=%d", + channels, samplerate, samplewidth); + + pa_threaded_mainloop_lock(mainloop); + + do + { + /* PulseAudio sample format initialization */ +#if PA_CHECK_VERSION(0,9,13) + if (pa_sample_spec_init(&samples) == NULL) + { + logger(Sound, Error, + "pulse_stream_open(), error initializing PulseAudio sample format"); + break; + } +#endif + if (samplewidth == 2) + samples.format = PA_SAMPLE_S16LE; + else if (samplewidth == 1) + samples.format = PA_SAMPLE_U8; + else + { + logger(Sound, Error, + "pulse_stream_open(), wrong samplewidth for the PulseAudio stream: %d", + samplewidth); + break; + } + samples.rate = samplerate; + samples.channels = channels; + if (!pa_sample_spec_valid(&samples)) + { + logger(Sound, Error, + "pulse_stream_open(), Invalid PulseAudio sample format"); + break; + } + /* PulseAudio stream creation */ +#if PA_CHECK_VERSION(0,9,11) + if (stream == &playback_stream) + *stream = + pa_stream_new_with_proplist(context, "Playback Stream", &samples, + NULL, proplist); + else + *stream = + pa_stream_new_with_proplist(context, "Capture Stream", &samples, + NULL, proplist); +#else + if (stream == &playback_stream) + *stream = pa_stream_new(context, "Playback Stream", &samples, NULL); + else + *stream = pa_stream_new(context, "Capture Stream", &samples, NULL); +#endif + if (*stream == NULL) + { + err = pa_context_errno(context); + logger(Sound, Error, "pulse_stream_open(), pa_stream_new: %s", + pa_strerror(err)); + break; + } + pa_stream_set_state_callback(*stream, pulse_stream_state_cb, mainloop); + + buffer_attr.maxlength = (uint32_t) - 1; + buffer_attr.minreq = (uint32_t) - 1; + buffer_attr.prebuf = (uint32_t) - 1; + buffer_attr.tlength = (uint32_t) - 1; + buffer_attr.fragsize = (uint32_t) - 1; + + /* PulseAudio stream connection */ + if (stream == &playback_stream) + { +#if PA_CHECK_VERSION(0,9,0) + buffer_attr.tlength = + pa_usec_to_bytes(1000000 / playback_latency_part, &samples); +#else + buffer_attr.tlength = + (samples.rate / playback_latency_part) * samples.channels * + (samples.format == PA_SAMPLE_S16LE ? 2 : 1); +#endif + buffer_attr.prebuf = 0; + buffer_attr.maxlength = buffer_attr.tlength; + } + else + { +#if PA_CHECK_VERSION(0,9,0) + buffer_attr.fragsize = + pa_usec_to_bytes(1000000 / capture_latency_part, &samples); +#else + buffer_attr.fragsize = + (samples.rate / capture_latency_part) * samples.channels * + (samples.format == PA_SAMPLE_S16LE ? 2 : 1); +#endif + buffer_attr.maxlength = buffer_attr.fragsize; + } + +#if !PA_CHECK_VERSION(0,9,16) + buffer_attr.minreq = (samples.rate / 50) * samples.channels * (samples.format == PA_SAMPLE_S16LE ? 2 : 1); // 20 ms +#endif + + if (stream == &playback_stream) + err = pa_stream_connect_playback(*stream, device, &buffer_attr, flags, NULL, + NULL); + else + err = pa_stream_connect_record(*stream, device, &buffer_attr, flags); + if (err) + { + err = pa_context_errno(context); + logger(Sound, Error, + "pulse_stream_open(), error connecting PulseAudio stream: %s", + pa_strerror(err)); + break; + } + do + { + state = pa_stream_get_state(*stream); + if (state == PA_STREAM_READY || state == PA_STREAM_FAILED) + break; + else + pa_threaded_mainloop_wait(mainloop); + } + while (1); + if (state != PA_STREAM_READY) + { + err = pa_context_errno(context); + logger(Sound, Error, + "pulse_stream_open(), error connecting PulseAudio stream: %s", + pa_strerror(err)); + break; + } + +#if PA_CHECK_VERSION(0,9,8) + logger(Sound, Debug, "pulse_stream_open(), opened PulseAudio stream on device %s", + pa_stream_get_device_name(*stream)); +#endif +#if PA_CHECK_VERSION(0,9,0) + const pa_buffer_attr *res_ba; + res_ba = pa_stream_get_buffer_attr(*stream); + logger(Sound, Debug, + "pulse_stream_open(), PulseAudio stream buffer metrics: maxlength %u, minreq %u, prebuf %u, tlength %u, fragsize %u", + res_ba->maxlength, res_ba->minreq, res_ba->prebuf, res_ba->tlength, + res_ba->fragsize); +#endif + + /* Set the data callbacks for the PulseAudio stream */ + if (stream == &playback_stream) + pa_stream_set_write_callback(*stream, pulse_write_cb, mainloop); + else + pa_stream_set_read_callback(*stream, pulse_read_cb, mainloop); + + ret = True; + } + while (0); + + pa_threaded_mainloop_unlock(mainloop); + + return ret; +} + +static void +pulse_stream_close(pa_stream ** stream) +{ + pa_stream_state_t state; + int err; + + + assert(stream != NULL); + + if (*stream != NULL) + { + pa_threaded_mainloop_lock(mainloop); + + state = pa_stream_get_state(*stream); + if (state == PA_STREAM_READY) + { + if (pa_stream_disconnect(*stream) != 0) + { + err = pa_context_errno(context); + logger(Sound, Error, + "pulse_stream_close(), pa_stream_disconnect: %s\n", + pa_strerror(err)); + } + } + pa_stream_unref(*stream); + *stream = NULL; + + pa_threaded_mainloop_unlock(mainloop); + } +} + +static void +pulse_send_msg(int fd, char message) +{ + int ret; + + + do + ret = write(fd, &message, sizeof message); + while (ret == -1 && errno == EINTR); + if (ret == -1) + logger(Sound, Error, "pulse_send_msg(), error writing message to the pipe: %s\n", + strerror(errno)); +} + +static RD_BOOL +pulse_playback_start(void) +{ + RD_BOOL result = False; + int ret; + int err; + pa_operation *po; + + + if (playback_stream == NULL) + { + logger(Sound, Warning, + "pulse_playback_start(), trying to start PulseAudio stream while it's not exists"); + return True; + } + + pa_threaded_mainloop_lock(mainloop); + + do + { + if (pa_stream_get_state(playback_stream) != PA_STREAM_READY) + { + logger(Sound, Warning, + "pulse_playback_start(), trying to start PulseAudio stream while it's not ready"); + break; + } +#if PA_CHECK_VERSION(0,9,11) + ret = pa_stream_is_corked(playback_stream); +#else + ret = 1; +#endif + if (ret < 0) + { + err = pa_context_errno(context); + logger(Sound, Error, "pulse_playback_start(), pa_stream_is_corked: %s", + pa_strerror(err)); + break; + } + else if (ret != 0) + { + po = pa_stream_cork(playback_stream, 0, pulse_cork_cb, mainloop); + if (po == NULL) + { + err = pa_context_errno(context); + logger(Sound, Error, "pulse_playback_start(), pa_stream_corked: %s", + pa_strerror(err)); + break; + } + while (pa_operation_get_state(po) == PA_OPERATION_RUNNING) + pa_threaded_mainloop_wait(mainloop); + pa_operation_unref(po); + } + + result = True; + } + while (0); + + pa_threaded_mainloop_unlock(mainloop); + + return result; +} + +static RD_BOOL +pulse_playback_stop(void) +{ + RD_BOOL result = False; + int ret; + int err; + pa_operation *po; + + + if (playback_stream == NULL) + { + logger(Sound, Debug, + "pulse_playback_stop(), trying to stop PulseAudio stream while it's not exists"); + return True; + } + + pa_threaded_mainloop_lock(mainloop); + + do + { + if (pa_stream_get_state(playback_stream) != PA_STREAM_READY) + { + logger(Sound, Error, + "pulse_playback_stop(), trying to stop PulseAudio stream while it's not ready"); + break; + } +#if PA_CHECK_VERSION(0,9,11) + ret = pa_stream_is_corked(playback_stream); +#else + ret = 0; +#endif + if (ret < 0) + { + err = pa_context_errno(context); + logger(Sound, Error, "pulse_playback_stop(), pa_stream_is_corked: %s", + pa_strerror(err)); + break; + } + else if (ret == 0) + { + po = pa_stream_cork(playback_stream, 1, pulse_cork_cb, mainloop); + if (po == NULL) + { + err = pa_context_errno(context); + logger(Sound, Error, "pulse_playback_stop(), pa_stream_cork: %s", + pa_strerror(err)); + break; + } + while (pa_operation_get_state(po) == PA_OPERATION_RUNNING) + pa_threaded_mainloop_wait(mainloop); + pa_operation_unref(po); + } + po = pa_stream_flush(playback_stream, pulse_flush_cb, mainloop); + if (po == NULL) + { + err = pa_context_errno(context); + logger(Sound, Error, "pulse_playback_stop(), pa_stream_flush: %s", + pa_strerror(err)); + break; + } + while (pa_operation_get_state(po) == PA_OPERATION_RUNNING) + pa_threaded_mainloop_wait(mainloop); + pa_operation_unref(po); + + result = True; + } + while (0); + + pa_threaded_mainloop_unlock(mainloop); + + return result; +} + +static RD_BOOL +pulse_playback_set_audio(int channels, int samplerate, int samplewidth) +{ + pa_stream_flags_t flags; + + + pulse_stream_close(&playback_stream); + + flags = PA_STREAM_START_CORKED | PA_STREAM_INTERPOLATE_TIMING | + PA_STREAM_AUTO_TIMING_UPDATE; +#if PA_CHECK_VERSION(0,9,11) + flags |= PA_STREAM_ADJUST_LATENCY; +#endif + if (pulse_stream_open(&playback_stream, channels, samplerate, samplewidth, flags) != True) + return False; + + return True; +} + +static RD_BOOL +pulse_capture_start(void) +{ + RD_BOOL result = False; + int ret; + int err; + pa_operation *po; + + + if (capture_stream == NULL) + { + logger(Sound, Warning, + "pulse_capture_start(), trying to start PulseAudio stream while it's not exists"); + return True; + } + + pa_threaded_mainloop_lock(mainloop); + + do + { + if (pa_stream_get_state(capture_stream) != PA_STREAM_READY) + { + logger(Sound, Error, + "pulse_capture_start(), trying to start PulseAudio stream while it's not exists"); + break; + } +#if PA_CHECK_VERSION(0,9,11) + ret = pa_stream_is_corked(capture_stream); +#else + ret = 1; +#endif + if (ret < 0) + { + err = pa_context_errno(context); + logger(Sound, Error, "pulse_capture_start(), pa_stream_is_corked: %s", + pa_strerror(err)); + break; + } + else if (ret != 0) + { + po = pa_stream_cork(capture_stream, 0, pulse_cork_cb, mainloop); + if (po == NULL) + { + err = pa_context_errno(context); + logger(Sound, Error, "pulse_capture_start(), pa_stream_cork: %s\n", + pa_strerror(err)); + break; + } + while (pa_operation_get_state(po) == PA_OPERATION_RUNNING) + pa_threaded_mainloop_wait(mainloop); + pa_operation_unref(po); + } + + result = True; + } + while (0); + + pa_threaded_mainloop_unlock(mainloop); + + return result; +} + +static RD_BOOL +pulse_capture_stop(void) +{ + RD_BOOL result = False; + int ret; + int err; + pa_operation *po; + + + if (capture_stream == NULL) + { + logger(Sound, Debug, + "pulse_capture_stop(), trying to stop PulseAudio stream while it's not exists"); + return True; + } + + pa_threaded_mainloop_lock(mainloop); + + do + { + if (pa_stream_get_state(capture_stream) != PA_STREAM_READY) + { + logger(Sound, Error, + "pulse_capture_stop(), trying to stop PulseAudio stream while it's not exists"); + break; + } +#if PA_CHECK_VERSION(0,9,11) + ret = pa_stream_is_corked(capture_stream); +#else + ret = 0; +#endif + if (ret < 0) + { + err = pa_context_errno(context); + logger(Sound, Error, "pulse_capture_stop(), pa_stream_is_corked: %s\n", + pa_strerror(err)); + break; + } + else if (ret == 0) + { + po = pa_stream_cork(capture_stream, 1, pulse_cork_cb, mainloop); + if (po == NULL) + { + err = pa_context_errno(context); + logger(Sound, Error, "pulse_capture_stop(), pa_stream_cork: %s\n", + pa_strerror(err)); + break; + } + while (pa_operation_get_state(po) == PA_OPERATION_RUNNING) + pa_threaded_mainloop_wait(mainloop); + pa_operation_unref(po); + } + + result = True; + } + while (0); + + pa_threaded_mainloop_unlock(mainloop); + + return result; +} + +static RD_BOOL +pulse_capture_set_audio(int channels, int samplerate, int samplewidth) +{ + pa_stream_flags_t flags; + pa_stream_state_t state; + int ret; + int err; + + + flags = PA_STREAM_START_CORKED; +#if PA_CHECK_VERSION(0,9,11) + flags |= PA_STREAM_ADJUST_LATENCY; +#endif + + if (capture_stream != NULL) + { + pa_threaded_mainloop_lock(mainloop); + state = pa_stream_get_state(capture_stream); + if (state == PA_STREAM_READY) + { +#if PA_CHECK_VERSION(0,9,11) + ret = pa_stream_is_corked(capture_stream); +#else + ret = (capture_started == False); +#endif + if (ret == 0) + flags &= ~PA_STREAM_START_CORKED; + else if (ret < 0) + { + err = pa_context_errno(context); + pa_threaded_mainloop_unlock(mainloop); + logger(Sound, Error, + "pulse_capture_set_audio(), pa_stream_is_corked: %s\n", + pa_strerror(err)); + return False; + } + } + pa_threaded_mainloop_unlock(mainloop); + } + + pulse_stream_close(&capture_stream); + + if (pulse_stream_open(&capture_stream, channels, samplerate, samplewidth, flags) != True) + return False; + + return True; +} + +static void +pulse_context_state_cb(pa_context * c, void *userdata) +{ + pa_context_state_t state; + + + assert(userdata != NULL); + + state = pa_context_get_state(c); + if (state == PA_CONTEXT_READY || state == PA_CONTEXT_FAILED) + pa_threaded_mainloop_signal((pa_threaded_mainloop *) userdata, 0); +} + +static void +pulse_stream_state_cb(pa_stream * p, void *userdata) +{ + pa_stream_state_t state; + + + assert(userdata != NULL); + + state = pa_stream_get_state(p); + if (state == PA_STREAM_FAILED) + { + if (p == playback_stream) + { + logger(Sound, Debug, + "pulse_stream_state_cb(), PulseAudio playback stream is in a fail state"); + pulse_send_msg(pulse_ctl[1], RDPSND_PULSE_OUT_ERR); + } + else + { + logger(Sound, Debug, + "pulse_stream_state_cb(), PulseAudio capture stream is in a fail state"); + pulse_send_msg(pulse_ctl[1], RDPSND_PULSE_IN_ERR); + } + } + if (state == PA_STREAM_READY || state == PA_STREAM_FAILED) + pa_threaded_mainloop_signal((pa_threaded_mainloop *) userdata, 0); +} + +static void +pulse_read_cb(pa_stream * p, size_t nbytes, void *userdata) +{ + assert(userdata != NULL); + + pulse_send_msg(pulse_ctl[1], RDPSND_PULSE_IN_AVAIL); +} + +static void +pulse_write_cb(pa_stream * p, size_t nbytes, void *userdata) +{ + assert(userdata != NULL); + + pulse_send_msg(pulse_ctl[1], RDPSND_PULSE_OUT_AVAIL); +} + +static void +pulse_cork_cb(pa_stream * p, int success, void *userdata) +{ + assert(userdata != NULL); + + if (!success) + { + if (p == playback_stream) + { + logger(Sound, Warning, + "pulse_cork_cb(), fail to cork/uncork the PulseAudio playback stream: %s", + pa_strerror(pa_context_errno(context))); + pulse_send_msg(pulse_ctl[1], RDPSND_PULSE_OUT_ERR); + } + else + { + logger(Sound, Warning, + "pulse_cork_cb(), fail to cork/uncork the PulseAudio capture stream: %s", + pa_strerror(pa_context_errno(context))); + pulse_send_msg(pulse_ctl[1], RDPSND_PULSE_IN_ERR); + } + } + + pa_threaded_mainloop_signal((pa_threaded_mainloop *) userdata, 0); +} + +static void +pulse_flush_cb(pa_stream * p, int success, void *userdata) +{ + assert(userdata != NULL); + + if (!success) + { + logger(Sound, Warning, "pulse_flush_cb(), Fail to flush the PulseAudio stream: %s", + pa_strerror(pa_context_errno(context))); + pulse_send_msg(pulse_ctl[1], RDPSND_PULSE_OUT_ERR); + } + + pa_threaded_mainloop_signal((pa_threaded_mainloop *) userdata, 0); +} + +static void +pulse_update_timing_cb(pa_stream * p, int success, void *userdata) +{ + assert(userdata != NULL); + + if (!success) + { + logger(Sound, Warning, + "pulse_update_timing_cb(), fail to update timing info of the PulseAudio stream: %s", + pa_strerror(pa_context_errno(context))); + pulse_send_msg(pulse_ctl[1], RDPSND_PULSE_OUT_ERR); + } + + pa_threaded_mainloop_signal((pa_threaded_mainloop *) userdata, 0); +} + +void +pulse_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv) +{ + if (pulse_ctl[0] != -1) + { + if (pulse_ctl[0] > *n) + *n = pulse_ctl[0]; + + FD_SET(pulse_ctl[0], rfds); + } +} + +void +pulse_check_fds(fd_set * rfds, fd_set * wfds) +{ + char audio_cmd; + int n; + + + if (pulse_ctl[0] == -1) + return; + + if (FD_ISSET(pulse_ctl[0], rfds)) + { + do + { + n = read(pulse_ctl[0], &audio_cmd, sizeof audio_cmd); + if (n == -1) + { + if (errno == EINTR) + continue; + else if (errno == EAGAIN || errno == EWOULDBLOCK) + break; + else + { + logger(Sound, Error, "pulse_check_fds(), read: %s\n", + strerror(errno)); + return; + } + } + else if (n == 0) + { + logger(Sound, Warning, + "pulse_check_fds(), audio control pipe was closed"); + break; + } + else + switch (audio_cmd) + { + case RDPSND_PULSE_OUT_AVAIL: + if (pulse_play() != True) + if (pulse_recover(&playback_stream) != True) + { + logger(Sound, Error, + "pulse_check_fds(), PulseAudio playback error"); + return; + } + break; + case RDPSND_PULSE_IN_AVAIL: + if (pulse_record() != True) + if (pulse_recover(&capture_stream) != True) + { + logger(Sound, Error, + "pulse_check_fds(), PulseAudio capture error"); + return; + } + break; + case RDPSND_PULSE_OUT_ERR: + if (pulse_recover(&playback_stream) != True) + { + logger(Sound, Error, + "pulse_check_fds(), an error occured in audio thread with PulseAudio playback stream"); + return; + } + break; + case RDPSND_PULSE_IN_ERR: + if (pulse_recover(&capture_stream) != True) + { + logger(Sound, Error, + "pulse_check_fds(), an error occured in audio thread with PulseAudio capture stream"); + return; + } + break; + default: + logger(Sound, Error, + "pulse_check_fds(), wrong command from the audio thread: %d", + audio_cmd); + break; + } + } + while (1); + } + + return; +} + +RD_BOOL +pulse_open_out(void) +{ + if (context == NULL || mainloop == NULL) + if (pulse_init() != True) + return False; + + return True; +} + +void +pulse_close_out(void) +{ + /* Ack all remaining packets */ + while (!rdpsnd_queue_empty()) + rdpsnd_queue_next(0); + + playback_started = False; + + if (playback_stream && pulse_playback_stop() != True) + if (pulse_recover(&playback_stream) != True) + { + logger(Sound, Error, + "pulse_close_out(), fail to close the PulseAudio playback stream"); + return; + } +} + +RD_BOOL +pulse_format_supported(RD_WAVEFORMATEX * pwfx) +{ + if (pwfx->wFormatTag != WAVE_FORMAT_PCM) + return False; + if ((pwfx->nChannels != 1) && (pwfx->nChannels != 2)) + return False; + if ((pwfx->wBitsPerSample != 8) && (pwfx->wBitsPerSample != 16)) + return False; + + return True; +} + +RD_BOOL +pulse_set_format_out(RD_WAVEFORMATEX * pwfx) +{ + if (playback_stream == NULL + || playback_channels != pwfx->nChannels + || playback_samplerate != pwfx->nSamplesPerSec + || playback_samplewidth != pwfx->wBitsPerSample / 8) + { + playback_channels = pwfx->nChannels; + playback_samplerate = pwfx->nSamplesPerSec; + playback_samplewidth = pwfx->wBitsPerSample / 8; + + if (pulse_playback_set_audio + (pwfx->nChannels, pwfx->nSamplesPerSec, pwfx->wBitsPerSample / 8) != True) + if (pulse_recover(&playback_stream) != True) + { + logger(Sound, Error, + "pulse_set_format_out(), fail to open the PulseAudio playback stream"); + return False; + } + } + + playback_started = True; + + if (pulse_playback_start() != True) + if (pulse_recover(&playback_stream) != True) + { + logger(Sound, Error, + "pulse_set_format_out(), fail to start the PulseAudio playback stream"); + return False; + } + + return True; +} + +RD_BOOL +pulse_play(void) +{ + struct audio_packet *packet; + STREAM out; + const pa_timing_info *ti; + pa_operation *po; + pa_seek_mode_t playback_seek; + size_t avail_space, audio_size; + pa_usec_t delay = 0; + int ret; + int err; + RD_BOOL result = False; + + + if (rdpsnd_queue_empty()) + return True; + + if (playback_stream == NULL) + return False; + + pa_threaded_mainloop_lock(mainloop); + + do + { + packet = rdpsnd_queue_current_packet(); + out = packet->s; + + ti = pa_stream_get_timing_info(playback_stream); + if (ti == NULL) + { + err = pa_context_errno(context); + logger(Sound, Error, "pulse_play(), pa_stream_get_timing_info: %s", + pa_strerror(err)); + break; + } + + if (ti->read_index_corrupt || ti->write_index_corrupt) + { + po = pa_stream_update_timing_info(playback_stream, pulse_update_timing_cb, + mainloop); + if (po == NULL) + { + err = pa_context_errno(context); + logger(Sound, Error, + "pulse_play(), pa_stream_update_timing_info: %s", + pa_strerror(err)); + break; + } + while (pa_operation_get_state(po) == PA_OPERATION_RUNNING) + pa_threaded_mainloop_wait(mainloop); + pa_operation_unref(po); + } + + if (ti->read_index > ti->write_index) + { + logger(Sound, Debug, "pulse_play(), PulseAudio stream underflow %ld bytes", + (long) (ti->read_index - ti->write_index)); + playback_seek = PA_SEEK_RELATIVE_ON_READ; + } + else + playback_seek = PA_SEEK_RELATIVE; + + avail_space = pa_stream_writable_size(playback_stream); + audio_size = MIN(s_remaining(out), avail_space); + if (audio_size) + { + unsigned char *data; + + in_uint8p(out, data, audio_size); + if (pa_stream_write + (playback_stream, data, audio_size, NULL, 0, playback_seek) != 0) + { + err = pa_context_errno(context); + logger(Sound, Error, "pulse_play(), pa_stream_write: %s", + pa_strerror(err)); + break; + } + else if (playback_seek == PA_SEEK_RELATIVE_ON_READ) + playback_seek = PA_SEEK_RELATIVE; + } + + if (s_check_end(out)) + { + ret = pa_stream_get_latency(playback_stream, &delay, NULL); + if (ret != 0 && (err = pa_context_errno(context)) == PA_ERR_NODATA) + { + po = pa_stream_update_timing_info(playback_stream, + pulse_update_timing_cb, mainloop); + if (po == NULL) + { + delay = 0; + err = pa_context_errno(context); + logger(Sound, Error, + "pulse_play(), pa_stream_update_timing_info: %s", + pa_strerror(err)); + break; + } + while (pa_operation_get_state(po) == PA_OPERATION_RUNNING) + pa_threaded_mainloop_wait(mainloop); + pa_operation_unref(po); + + ret = pa_stream_get_latency(playback_stream, &delay, NULL); + } + if (ret != 0) + { + delay = 0; + err = pa_context_errno(context); + logger(Sound, Error, "pulse_play(), pa_stream_get_latency: %s", + pa_strerror(err)); + break; + } + + logger(Sound, Debug, + "pulse_play(), PulseAudio playback stream latency %lu usec", + (long) delay); + } + + result = True; + } + while (0); + + pa_threaded_mainloop_unlock(mainloop); + + if (s_check_end(out)) + rdpsnd_queue_next(delay); + + return result; +} + +RD_BOOL +pulse_open_in(void) +{ + if (context == NULL || mainloop == NULL) + if (pulse_init() != True) + return False; + + return True; +} + +void +pulse_close_in(void) +{ + capture_started = False; + + if (capture_stream && pulse_capture_stop() != True) + if (pulse_recover(&capture_stream) != True) + { + logger(Sound, Error, + "pulse_close_in(), fail to close the PulseAudio capture stream"); + return; + } +} + +RD_BOOL +pulse_set_format_in(RD_WAVEFORMATEX * pwfx) +{ + if (capture_stream == NULL + || capture_channels != pwfx->nChannels + || capture_samplerate != pwfx->nSamplesPerSec + || capture_samplewidth != pwfx->wBitsPerSample / 8) + { + capture_channels = pwfx->nChannels; + capture_samplerate = pwfx->nSamplesPerSec; + capture_samplewidth = pwfx->wBitsPerSample / 8; + + if (pulse_capture_set_audio + (pwfx->nChannels, pwfx->nSamplesPerSec, pwfx->wBitsPerSample / 8) != True) + if (pulse_recover(&capture_stream) != True) + { + logger(Sound, Error, + "pulse_set_format_in(), fail to open the PulseAudio capture stream"); + return False; + } + } + + capture_started = True; + + if (pulse_capture_start() != True) + if (pulse_recover(&capture_stream) != True) + { + logger(Sound, Error, + "pulse_set_format_in(), fail to start the PulseAudio capture stream"); + return False; + } + + return True; +} + +RD_BOOL +pulse_record(void) +{ + const void *pulse_buf; + size_t audio_size; + RD_BOOL result = False; + + + if (capture_stream == NULL) + return False; + + pa_threaded_mainloop_lock(mainloop); + + do + { + if (pa_stream_peek(capture_stream, &pulse_buf, &audio_size) != 0) + { + logger(Sound, Error, "pulse_record(), pa_stream_peek: %s", + pa_strerror(pa_context_errno(context))); + break; + } + + /* Stretch the buffer, if needed */ + if (capture_buf_size < audio_size) + { + capture_buf_size = audio_size; + if (capture_buf != NULL) + free(capture_buf); + capture_buf = malloc(capture_buf_size); + if (capture_buf == NULL) + { + logger(Sound, Error, "pulse_record(), malloc error"); + capture_buf_size = 0; + break; + } + } + + memcpy(capture_buf, pulse_buf, audio_size); + + if (pa_stream_drop(capture_stream) != 0) + { + logger(Sound, Error, "pulse_record(), pa_stream_drop: %s", + pa_strerror(pa_context_errno(context))); + break; + } + + result = True; + } + while (0); + + pa_threaded_mainloop_unlock(mainloop); + + if (result == True) + rdpsnd_record(capture_buf, audio_size); + + return result; +} + +static RD_BOOL +pulse_recover(pa_stream ** stream) +{ + RD_BOOL playback, capture; + + + playback = capture = False; + + if (playback_stream != NULL) + playback = True; + if (capture_stream != NULL) + capture = True; + + if (stream == &playback_stream) + { + if (pulse_playback_set_audio + (playback_channels, playback_samplerate, playback_samplewidth) == True) + if (playback_started != True || pulse_playback_start() == True) + return True; + } + else if (stream == &capture_stream) + { + if (pulse_capture_set_audio + (capture_channels, capture_samplerate, capture_samplewidth) == True) + if (capture_started != True || pulse_capture_start() == True) + return True; + } + + pulse_deinit(); + + if (pulse_init() != True) + return False; + + do + { + if (playback == True) + { + if (pulse_playback_set_audio + (playback_channels, playback_samplerate, playback_samplewidth) != True + || (playback_started == True && pulse_playback_start() != True)) + break; + } + if (capture == True) + { + if (pulse_capture_set_audio + (capture_channels, capture_samplerate, capture_samplewidth) != True + || (capture_started == True && pulse_capture_start() != True)) + break; + } + + return True; + } + while (0); + + pulse_deinit(); + + return False; +} + +struct audio_driver * +pulse_register(char *options) +{ + static struct audio_driver pulse_driver; + + memset(&pulse_driver, 0, sizeof(pulse_driver)); + + pulse_driver.name = "pulse"; + pulse_driver.description = "PulseAudio output driver, default device: system dependent"; + + pulse_driver.add_fds = pulse_add_fds; + pulse_driver.check_fds = pulse_check_fds; + + pulse_driver.wave_out_open = pulse_open_out; + pulse_driver.wave_out_close = pulse_close_out; + pulse_driver.wave_out_format_supported = pulse_format_supported; + pulse_driver.wave_out_set_format = pulse_set_format_out; + pulse_driver.wave_out_volume = rdpsnd_dsp_softvol_set; + + pulse_driver.wave_in_open = pulse_open_in; + pulse_driver.wave_in_close = pulse_close_in; + pulse_driver.wave_in_format_supported = pulse_format_supported; + pulse_driver.wave_in_set_format = pulse_set_format_in; + pulse_driver.wave_in_volume = NULL; /* FIXME */ + + pulse_driver.need_byteswap_on_be = 0; + pulse_driver.need_resampling = 0; + + if (options != NULL) + { + device = xstrdup(options); + } + else + { + device = DEFAULTDEVICE; + } + + return &pulse_driver; +} diff -Nru rdesktop-1.8.6/rdpsnd_sgi.c rdesktop-1.9.0/rdpsnd_sgi.c --- rdesktop-1.8.6/rdpsnd_sgi.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/rdpsnd_sgi.c 2019-09-17 12:34:36.000000000 +0000 @@ -20,8 +20,10 @@ */ #include "rdesktop.h" +#include "rdpsnd.h" #include <errno.h> #include <dmedia/audio.h> +#include <unistd.h> /* #define IRIX_DEBUG 1 */ @@ -65,45 +67,45 @@ static int warned = 0; #if (defined(IRIX_DEBUG)) - fprintf(stderr, "sgi_open: begin\n"); + logger(Sound, Debug, "sgi_open()"); #endif if (!warned && sgi_output_device) { - warning("device-options not supported for libao-driver\n"); + logger(Sound, Warning, "sgi_open(), device-options not supported for libao-driver"); warned = 1; } if (alGetParamInfo(AL_DEFAULT_OUTPUT, AL_GAIN, &pinfo) < 0) { - fprintf(stderr, "sgi_open: alGetParamInfo failed: %s\n", - alGetErrorString(oserror())); + logger(Sound, Error, "sgi_open(), alGetParamInfo failed: %s", + alGetErrorString(oserror())); } min_volume = alFixedToDouble(pinfo.min.ll); max_volume = alFixedToDouble(pinfo.max.ll); volume_range = (max_volume - min_volume); -#if (defined(IRIX_DEBUG)) - fprintf(stderr, "sgi_open: minvol = %lf, maxvol= %lf, range = %lf.\n", - min_volume, max_volume, volume_range); -#endif + + logger(Sound, Debug, "sgi_open(), minvol = %lf, maxvol= %lf, range = %lf", + min_volume, max_volume, volume_range); + audioconfig = alNewConfig(); if (audioconfig == (ALconfig) 0) { - fprintf(stderr, "sgi_open: alNewConfig failed: %s\n", alGetErrorString(oserror())); + logger(Sound, Error, "sgi_open(), alNewConfig failed: %s", + alGetErrorString(oserror())); return False; } output_port = alOpenPort("rdpsnd", "w", 0); if (output_port == (ALport) 0) { - fprintf(stderr, "sgi_open: alOpenPort failed: %s\n", alGetErrorString(oserror())); + logger(Sound, Error, "sgi_open(), alOpenPort failed: %s", + alGetErrorString(oserror())); return False; } -#if (defined(IRIX_DEBUG)) - fprintf(stderr, "sgi_open: returning\n"); -#endif + logger(Sound, Debug, "sgi_open(), done"); return True; } @@ -111,9 +113,7 @@ sgi_close(void) { /* Ack all remaining packets */ -#if (defined(IRIX_DEBUG)) - fprintf(stderr, "sgi_close: begin\n"); -#endif + logger(Sound, Debug, "sgi_close()"); while (!rdpsnd_queue_empty()) rdpsnd_queue_next(0); @@ -122,9 +122,8 @@ alClosePort(output_port); output_port = (ALport) 0; alFreeConfig(audioconfig); -#if (defined(IRIX_DEBUG)) - fprintf(stderr, "sgi_close: returning\n"); -#endif + + logger(Sound, Debug, "sgi_close(), done"); } RD_BOOL @@ -147,9 +146,7 @@ int frameSize, channelCount; ALpv params; -#if (defined(IRIX_DEBUG)) - fprintf(stderr, "sgi_set_format: init...\n"); -#endif + logger(Sound, Debug, "sgi_set_format()"); if (pwfx->wBitsPerSample == 8) width = AL_SAMPLE_8; @@ -175,8 +172,8 @@ if (output_port == (ALport) 0) { - fprintf(stderr, "sgi_set_format: alOpenPort failed: %s\n", - alGetErrorString(oserror())); + logger(Sound, Error, "sgi_set_format(), alOpenPort failed: %s", + alGetErrorString(oserror())); return False; } @@ -189,7 +186,7 @@ if (frameSize == 0 || channelCount == 0) { - fprintf(stderr, "sgi_set_format: bad frameSize or channelCount\n"); + logger(Sound, Error, "sgi_set_format(), bad frameSize or channelCount"); return False; } combinedFrameSize = frameSize * channelCount; @@ -199,19 +196,18 @@ if (alSetParams(resource, ¶ms, 1) < 0) { - fprintf(stderr, "wave_set_format: alSetParams failed: %s\n", - alGetErrorString(oserror())); + logger(Sound, Error, "sgi_set_format(), alSetParams failed: %s", + alGetErrorString(oserror())); return False; } if (params.sizeOut < 0) { - fprintf(stderr, "wave_set_format: invalid rate %d\n", g_snd_rate); + logger(Sound, Error, "sgi_set_format(), invalid rate %d", g_snd_rate); return False; } -#if (defined(IRIX_DEBUG)) - fprintf(stderr, "sgi_set_format: returning...\n"); -#endif + logger(Sound, Debug, "sgi_set_format(), done"); + return True; } @@ -222,10 +218,8 @@ ALpv pv[1]; ALfixed gain[8]; -#if (defined(IRIX_DEBUG)) - fprintf(stderr, "sgi_volume: begin\n"); - fprintf(stderr, "left='%d', right='%d'\n", left, right); -#endif + + logger(Sound, Debug, "sgi_volume(), left=%d, right=%d", left, right); gainleft = (double) left / IRIX_MAX_VOL; gainright = (double) right / IRIX_MAX_VOL; @@ -238,14 +232,12 @@ pv[0].sizeIn = 8; if (alSetParams(AL_DEFAULT_OUTPUT, pv, 1) < 0) { - fprintf(stderr, "sgi_volume: alSetParams failed: %s\n", - alGetErrorString(oserror())); + logger(Sound, Error, "sgi_volume(), alSetParams failed: %s", + alGetErrorString(oserror())); return; } -#if (defined(IRIX_DEBUG)) - fprintf(stderr, "sgi_volume: returning\n"); -#endif + logger(Sound, Debug, "sgi_volume(), done"); } void @@ -253,7 +245,6 @@ { struct audio_packet *packet; ssize_t len; - unsigned int i; STREAM out; unsigned char *data; int gf; @@ -280,9 +271,7 @@ } else { -#if (defined(IRIX_DEBUG)) -/* fprintf(stderr,"Busy playing...\n"); */ -#endif +/* logger(Sound,Debug, "sgi_play(), busy playing..."); */ usleep(10); return; } diff -Nru rdesktop-1.8.6/rdpsnd_sun.c rdesktop-1.9.0/rdpsnd_sun.c --- rdesktop-1.8.6/rdpsnd_sun.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/rdpsnd_sun.c 2019-09-17 12:34:36.000000000 +0000 @@ -6,6 +6,7 @@ Copyright (C) Michael Gernoth <mike@zerfleddert.de> 2003-2008 Copyright 2007-2008 Pierre Ossman <ossman@cendio.se> for Cendio AB Copyright 2008-2011 Peter Astrand <astrand@cendio.se> for Cendio AB + Copyright 2017 Henrik Andersson <hean01@cendio.se> for Cendio AB 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 @@ -162,7 +163,7 @@ dsp_fd = open(dsp_dev, dsp_mode | O_NONBLOCK); if (dsp_fd == -1) { - perror(dsp_dev); + logger(Sound, Error, "sun_open(), open() failed: %s", strerror(errno)); return False; } } @@ -357,7 +358,8 @@ if (ioctl(dsp_fd, AUDIO_SETINFO, &info) == -1) { - perror("AUDIO_SETINFO"); + logger(Sound, Error, "sun_set_format(), ioctl(AUDIO_SETINFO) failed: %s", + strerror(errno)); sun_close(); return False; } @@ -397,7 +399,8 @@ if (ioctl(dsp_fd, AUDIO_SETINFO, &info) == -1) { - perror("AUDIO_SETINFO"); + logger(Sound, Error, "sun_set_volume(), ioctl(AUDIO_SETINFO) failed: %s", + strerror(errno)); return; } } @@ -429,7 +432,8 @@ if (errno != EWOULDBLOCK) { if (!dsp_broken) - perror("RDPSND: write()"); + logger(Sound, Error, "sun_play(), write() failed: %s", + strerror(errno)); dsp_broken = True; rdpsnd_queue_next(0); } @@ -469,7 +473,7 @@ if (len == -1) { if (errno != EWOULDBLOCK) - perror("read audio"); + logger(Sound, Error, "sun_record(), read() failed: %s", strerror(errno)); return; } diff -Nru rdesktop-1.8.6/README rdesktop-1.9.0/README --- rdesktop-1.8.6/README 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/README 1970-01-01 00:00:00.000000000 +0000 @@ -1,50 +0,0 @@ -========================================== -rdesktop: A Remote Desktop Protocol client -========================================== - -rdesktop is an open source client for Microsoft's RDP protocol. It is -known to work with Windows versions such as NT 4 Terminal Server, -2000, XP, 2003, 2003 R2, Vista, 2008, 7, and 2008 R2. rdesktop -currently implements the RDP version 4 and 5 protocols. - -Installation ------------- -rdesktop uses a GNU-style build procedure. Typically all that is necessary -to install rdesktop is the following:: - - % ./configure - % make - % make install - -The default is to install under /usr/local. This can be changed by adding ---prefix=directory to the configure line. - -Note for Subversion users -------------------------- -If you have downloaded a snapshot of rdesktop using Subversion, you -will first need to run ./bootstrap in order to generate the build -infrastructure. This is not necessary for release versions of -rdesktop. - -Invocation ----------- -Simply run:: - - % rdesktop server - -where server is the name of the Terminal Services machine. (If you receive -"Connection refused", this probably means that the server does not have -Terminal Services enabled, or there is a firewall blocking access.) - -You can also specify a number of options on the command line. These are listed -in the rdesktop manual page (run "man rdesktop"). - -Smart-card support notes ------------------------- -The smart-card support module uses PCSC-lite. You should use PCSC-lite 1.2.9 or -later. - -To enable smart-card support in the rdesktop just run "./configure" with the -"--enable-smartcard" option. Also you can enable smart-card debug with -additional "--with-debug-smartcard" option. - diff -Nru rdesktop-1.8.6/README.md rdesktop-1.9.0/README.md --- rdesktop-1.8.6/README.md 1970-01-01 00:00:00.000000000 +0000 +++ rdesktop-1.9.0/README.md 2019-06-13 12:10:15.000000000 +0000 @@ -0,0 +1,44 @@ +# rdesktop - A Remote Desktop Protocol client + +rdesktop is an open source client for Microsoft's RDP protocol. It is +known to work with Windows versions ranging from NT 4 Terminal Server +to Windows 2012 R2 RDS. rdesktop currently has implemented the RDP version 4 +and 5 protocols. + + +## Installation + +rdesktop uses a GNU-style build procedure. Typically all that is necessary +to install rdesktop is the following: + + % ./configure + % make + % make install + +The default is to install under `/usr/local`. This can be changed by adding +`--prefix=<directory>` to the configure line. + +The smart-card support module uses PCSC-lite. You should use PCSC-lite 1.2.9 or +later. To enable smart-card support in the rdesktop add `--enable-smartcard` to +the configure line. + + +## Note for users building from source + +If you have retrieved a snapshot of the rdesktop source, you will first +need to run `./bootstrap` in order to generate the build infrastructure. +This is not necessary for release versions of rdesktop. + + +## Usage + +Connect to an RDP server with: + + % rdesktop server + +where `server` is the name of the Terminal Services machine. If you receive +"Connection refused", this probably means that the server does not have +Terminal Services enabled, or there is a firewall blocking access. + +You can also specify a number of options on the command line. These are listed +in the rdesktop manual page (run `man rdesktop`). diff -Nru rdesktop-1.8.6/scancodes.h rdesktop-1.9.0/scancodes.h --- rdesktop-1.8.6/scancodes.h 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/scancodes.h 2019-06-13 12:10:15.000000000 +0000 @@ -13,7 +13,7 @@ 0x61 - 0x79: Normal 0xfa - : keyboard drivers interpret these as responses from the 8042 chip - We use bit 7 to indicate 0xe0 prefix instead of two-byte sequence (0xe0, something). Eq., + We use bit 7 to indicate 0xe0 prefix instead of two-byte sequence (0xe0, something). E.g. 0xe 0x38 is defined as (0x80 | 0x38) */ diff -Nru rdesktop-1.8.6/scard.c rdesktop-1.9.0/scard.c --- rdesktop-1.8.6/scard.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/scard.c 2019-06-13 12:10:15.000000000 +0000 @@ -3,7 +3,10 @@ Smart Card support Copyright (C) Alexi Volkov <alexi@myrealbox.com> 2006 Copyright 2010-2013 Pierre Ossman <ossman@cendio.se> for Cendio AB - Copyright 2011-2014 Henrik Andersson <hean01@cendio.se> for Cendio AB + Copyright 2011-2017 Henrik Andersson <hean01@cendio.se> for Cendio AB + Copyright 2015 Rostislav Kondratenko <r.kondratenk@wwpass.com> + Copyright 2017 Karl Mikaelsson <derfian@cendio.se> for Cendio AB + Copyright 2016-2018 Alexander Zakharov <uglym8@gmail.com> 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 @@ -27,11 +30,11 @@ #include <sys/types.h> #include <time.h> #include <arpa/inet.h> -#ifndef MAKE_PROTO #ifdef __APPLE__ #include <PCSC/wintypes.h> #include <PCSC/pcsclite.h> #include <PCSC/winscard.h> +#define SCARD_CTL_CODE(code) (0x42000000 + (code)) #else #include <wintypes.h> #include <pcsclite.h> @@ -85,7 +88,6 @@ /* code segment */ -#endif /* MAKE_PROTO */ void scardSetInfo(uint32 epoch, uint32 device, uint32 id, uint32 bytes_out) { @@ -95,33 +97,49 @@ curEpoch = epoch; } -#ifndef MAKE_PROTO - static RD_NTSTATUS scard_create(uint32 device_id, uint32 accessmask, uint32 sharemode, uint32 create_disposition, uint32 flags_and_attributes, char *filename, RD_NTHANDLE * phandle) { + UNUSED(device_id); + UNUSED(accessmask); + UNUSED(sharemode); + UNUSED(create_disposition); + UNUSED(flags_and_attributes); + UNUSED(filename); + UNUSED(phandle); + return RD_STATUS_SUCCESS; } static RD_NTSTATUS scard_close(RD_NTHANDLE handle) { + UNUSED(handle); return RD_STATUS_SUCCESS; } static RD_NTSTATUS -scard_read(RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result) +scard_read(RD_NTHANDLE handle, uint8 * data, uint32 length, uint64 offset, uint32 * result) { + UNUSED(handle); + UNUSED(data); + UNUSED(length); + UNUSED(offset); + UNUSED(result); return RD_STATUS_SUCCESS; } static RD_NTSTATUS -scard_write(RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result) +scard_write(RD_NTHANDLE handle, uint8 * data, uint32 length, uint64 offset, uint32 * result) { + UNUSED(handle); + UNUSED(data); + UNUSED(length); + UNUSED(offset); + UNUSED(result); return RD_STATUS_SUCCESS; } -#endif /* MAKE_PROTO */ /* Enumeration of devices from rdesktop.c */ /* returns numer of units found and initialized. */ @@ -143,7 +161,7 @@ rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext); if (rv != SCARD_S_SUCCESS) { - error("scard_enum_devices: PCSC service not available\n"); + logger(SmartCard, Error, "scard_enum_devices(), PCSC service not available"); return 0; } else @@ -153,26 +171,29 @@ if (0 != pthread_mutex_init(&queueAccess, NULL)) { - error("scard_enum_devices: Can't initialize queue access mutex\n"); + logger(SmartCard, Error, + "scard_enum_devices(), can't initialize queue access mutex"); return 0; } if (0 != pthread_cond_init(&queueEmpty, NULL)) { - error("scard_enum_devices: Can't initialize queue control cv\n"); + logger(SmartCard, Error, "scard_enum_devices(), can't initialize queue control cv"); return 0; } if (0 != pthread_mutex_init(&hcardAccess, NULL)) { - error("scard_enum_devices: Can't initialize hcard list access mutex\n"); + logger(SmartCard, Error, + "scard_enum_devices(), can't initialize hcard list access mutex"); return 0; } if (0 != pthread_create(&queueHandler, NULL, (void *(*)(void *)) queue_handler_function, NULL)) { - error("scard_enum_devices: Can't create queue handling Thread\n"); + logger(SmartCard, Error, + "scard_enum_devices(), can't create queue handling thread"); return 0; } @@ -202,10 +223,9 @@ vendor = "\0"; } - printf("Static/aliased Device:\n"); - printf(" Lin name: [%s]\n", name); - printf(" Win name: [%s]\n", alias); - printf(" Vendor : [%s]\n", vendor); + logger(SmartCard, Debug, + "scard_enum_devices(), name='%s', alias='%s', vendor='%s'", + name, alias, vendor); nameMapCount++; if (nameMapList == NULL) @@ -242,14 +262,13 @@ return count; } -#ifndef MAKE_PROTO typedef struct _scard_handle_list_t { struct _scard_handle_list_t *next; - /* pcsc handles is datatype long which - is arch sizedependent */ + /* PCSC handle is datatype long which + is arch size-dependent */ long handle; - /* rdp server handles are always 32bit */ + /* RDP server handles are always 32 bit */ uint32_t server; } _scard_handle_list_t; @@ -265,7 +284,7 @@ _scard_handle_list_add(long handle) { _scard_handle_list_t *list = g_scard_handle_list; - /* we dont care of order of list so to simplify the add + /* we don't care of order of list so to simplify the add we add new items to front of list */ _scard_handle_list_t *item = xmalloc(sizeof(_scard_handle_list_t)); item->next = list; @@ -281,7 +300,11 @@ g_scard_handle_counter++; if (g_scard_handle_counter == 0 && overlap) - assert(!"broken smartcard client software, handles are not freed and there is no more handles left to allocate."); + { + logger(SmartCard, Error, + "_scard_handle_list_add(), broken smartcard client software, handles are not freed and no more handles left to allocate"); + abort(); + } if (g_scard_handle_counter == 0) overlap = g_scard_handle_counter = 1; @@ -514,7 +537,7 @@ static void outBufferFinishWithLimit(STREAM out, char *buffer, unsigned int length, unsigned int highLimit) { - int header = (length < 0) ? (0) : ((length > highLimit) ? (highLimit) : (length)); + unsigned int header = (length > highLimit) ? (highLimit) : (length); out_uint32_le(out, header); if (length <= 0) @@ -556,7 +579,7 @@ if (wide) { - int i; + unsigned int i; in_uint8a(in, buffer, 2 * dataLength); for (i = 0; i < dataLength; i++) if ((buffer[2 * i] < 0) || (buffer[2 * i + 1] != 0)) @@ -590,7 +613,7 @@ if (wide) { - int i; + unsigned int i; char *buffer = SC_xmalloc(&lcHandle, Result); for (i = 0; i < dataLength; i++) @@ -640,6 +663,7 @@ static MYPCSC_DWORD SC_returnCode(MYPCSC_DWORD rc, PMEM_HANDLE * handle, STREAM in, STREAM out) { + UNUSED(in); SC_xfreeallmemory(handle); out_uint8s(out, 256); return rc; @@ -654,39 +678,42 @@ static MYPCSC_DWORD TS_SCardEstablishContext(STREAM in, STREAM out) { + UNUSED(in); MYPCSC_DWORD rv; MYPCSC_SCARDCONTEXT myHContext; SERVER_SCARDCONTEXT hContext; + hContext = 0; + /* code segment */ + logger(SmartCard, Debug, "TS_SCardEstablishContext()"); - DEBUG_SCARD(("SCARD: SCardEstablishContext()\n")); rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &myHContext); - - hContext = 0; - if (myHContext) + if (rv != SCARD_S_SUCCESS) { - _scard_handle_list_add(myHContext); - hContext = _scard_handle_list_get_server_handle(myHContext); + logger(SmartCard, Debug, "TS_SCardEstablishContext(), failed: %s (0x%08x)", + pcsc_stringify_error(rv), (unsigned int) rv); + goto bail_out; } - - if (rv) - { - DEBUG_SCARD(("SCARD: -> Failure: %s (0x%08x)\n", - pcsc_stringify_error(rv), (unsigned int) rv)); - } - else + if (!myHContext) { - DEBUG_SCARD(("SCARD: -> Success (context: 0x%08x [0x%lx])\n", hContext, - myHContext)); + logger(SmartCard, Debug, "TS_SCardEstablishedContext(), myHContext == NULL"); + goto bail_out; } + /* add context to list of handle and get server handle */ + _scard_handle_list_add(myHContext); + hContext = _scard_handle_list_get_server_handle(myHContext); + logger(SmartCard, Debug, + "TS_SCardEstablishContext(), success. context: 0x%08x, [0x%lx]", hContext, + myHContext); + bail_out: out_uint32_le(out, 0x00000004); out_uint32_le(out, hContext); /* must not be 0 (Seems to be pointer), don't know what is this (I use hContext as value) */ - /* i hope it's not a pointer because i just downcasted it - jlj */ + /* I hope it's not a pointer because i just downcasted it - jlj */ out_uint32_le(out, 0x00000004); out_uint32_le(out, hContext); outForceAlignment(out, 8); @@ -705,8 +732,8 @@ in_uint32_le(in, hContext); myHContext = _scard_handle_list_get_pcsc_handle(hContext); - DEBUG_SCARD(("SCARD: SCardReleaseContext(context: 0x%08x [0x%lx])\n", (unsigned) hContext, - myHContext)); + logger(SmartCard, Debug, "TS_SCardReleaseContext(), context=0x%08x [0x%lx]", + (unsigned) hContext, myHContext); rv = SCardReleaseContext(myHContext); @@ -714,12 +741,15 @@ if (rv) { - DEBUG_SCARD(("SCARD: -> Failure: %s (0x%08x)\n", - pcsc_stringify_error(rv), (unsigned int) rv)); + logger(SmartCard, Debug, "TS_SCardReleaseContext(), failed: %s (0x%08x)", + pcsc_stringify_error(rv), (unsigned int) rv); } else { - DEBUG_SCARD(("SCARD: -> Success\n")); + logger(SmartCard, Debug, + "TS_SCardReleaseContext(), success, context: 0x%08x, [0x%lx]", hContext, + myHContext); + } outForceAlignment(out, 8); @@ -733,39 +763,32 @@ MYPCSC_DWORD rv; SERVER_SCARDCONTEXT hContext; MYPCSC_SCARDCONTEXT myHContext; - char *readers; - DWORD readerCount = 1024; - PMEM_HANDLE lcHandle = NULL; in_uint8s(in, 0x1C); in_uint32_le(in, hContext); myHContext = _scard_handle_list_get_pcsc_handle(hContext); - DEBUG_SCARD(("SCARD: SCardIsValidContext(context: 0x%08x [0x%lx])\n", - (unsigned) hContext, myHContext)); - /* There is no realization of SCardIsValidContext in PC/SC Lite so we call SCardListReaders */ + logger(SmartCard, Debug, "TS_SCardIsValidContext(), context: 0x%08x [0x%lx]", + (unsigned) hContext, myHContext); - readers = SC_xmalloc(&lcHandle, 1024); - if (!readers) - return SC_returnNoMemoryError(&lcHandle, in, out); - - rv = SCardListReaders(myHContext, NULL, readers, &readerCount); + rv = SCardIsValidContext(myHContext); if (rv) { - DEBUG_SCARD(("SCARD: -> Failure: %s (0x%08x)\n", - pcsc_stringify_error(rv), (unsigned int) rv)); + logger(SmartCard, Debug, "TS_SCardIsValidContext(), failed: %s (0x%08x)", + pcsc_stringify_error(rv), (unsigned int) rv); rv = SCARD_E_INVALID_HANDLE; } else { - DEBUG_SCARD(("SCARD: -> Success\n")); + logger(SmartCard, Debug, + "TS_SCardIsValidContext(), success, context: 0x%08x, [0x%lx]", hContext, + myHContext); } outForceAlignment(out, 8); s_mark_end(out); - SC_xfreeallmemory(&lcHandle); return rv; } @@ -786,8 +809,10 @@ in_uint8s(in, 0x2C); in_uint32_le(in, hContext); myHContext = _scard_handle_list_get_pcsc_handle(hContext); - DEBUG_SCARD(("SCARD: SCardListReaders(context: 0x%08x [0x%lx])\n", - (unsigned) hContext, myHContext)); + + logger(SmartCard, Debug, "TS_SCardListReaders(), context: 0x%08x [0x%lx])", + (unsigned) hContext, myHContext); + plen1 = s_tell(out); out_uint32_le(out, 0x00000000); /* Temp value for data length as 0x0 */ out_uint32_le(out, 0x01760650); @@ -806,14 +831,16 @@ cur = readers; if (rv != SCARD_S_SUCCESS) { - DEBUG_SCARD(("SCARD: -> Failure: %s (0x%08x)\n", - pcsc_stringify_error(rv), (unsigned int) rv)); + logger(SmartCard, Debug, "TS_SCardListReaders(), failed: %s (0x%08x)", + pcsc_stringify_error(rv), (unsigned int) rv); } else { int i; PSCNameMapRec tmpMap; - DEBUG_SCARD(("SCARD: -> Success\n")); + logger(SmartCard, Debug, "TS_SCardListReaders(), success, context: 0x%08x [0x%lx]", + (unsigned) hContext, myHContext); + for (i = 0, tmpMap = nameMapList; i < nameMapCount; i++, tmpMap++) { dataLength += outString(out, tmpMap->alias, wide); @@ -827,7 +854,8 @@ { if (!hasAlias(cur)) { - DEBUG_SCARD(("SCARD: \"%s\"\n", cur)); + logger(SmartCard, Debug, "TS_SCardListReaders(), '%s'", + cur); dataLength += outString(out, cur, wide); } cur = (void *) ((unsigned char *) cur + lenSC + 1); @@ -878,7 +906,10 @@ myHContext = _scard_handle_list_get_pcsc_handle(hContext); - DEBUG_SCARD(("SCARD: SCardConnect(context: 0x%08x [0x%lx], share: 0x%08x, proto: 0x%08x, reader: \"%s\")\n", (unsigned) hContext, myHContext, (unsigned) dwShareMode, (unsigned) dwPreferredProtocol, szReader ? szReader : "NULL")); + logger(SmartCard, Debug, + "TS_SCardConnect(), context: 0x%08x [0x%lx], share: 0x%08x, proto: 0x%08x, reader: '%s'", + (unsigned) hContext, myHContext, (unsigned) dwShareMode, + (unsigned) dwPreferredProtocol, szReader ? szReader : "NULL"); rv = SCardConnect(myHContext, szReader, (MYPCSC_DWORD) dwShareMode, (MYPCSC_DWORD) dwPreferredProtocol, &myHCard, &dwActiveProtocol); @@ -890,37 +921,45 @@ hCard = _scard_handle_list_get_server_handle(myHCard); } - if (rv != SCARD_S_SUCCESS) - { - DEBUG_SCARD(("SCARD: -> Failure: %s (0x%08x)\n", - pcsc_stringify_error(rv), (unsigned int) rv)); - } - else + switch (rv) { - char *szVendor = getVendor(szReader); - DEBUG_SCARD(("SCARD: -> Success (hcard: 0x%08x [0x%lx])\n", - (unsigned) hCard, myHCard)); - if (szVendor && (strlen(szVendor) > 0)) - { - DEBUG_SCARD(("SCARD: Set Attribute ATTR_VENDOR_NAME\n")); - pthread_mutex_lock(&hcardAccess); - PSCHCardRec hcard = xmalloc(sizeof(TSCHCardRec)); - if (hcard) + case SCARD_S_SUCCESS: { - hcard->hCard = hCard; - hcard->vendor = szVendor; - hcard->next = NULL; - hcard->prev = NULL; + char *szVendor = getVendor(szReader); + logger(SmartCard, Debug, + "TS_SCardConnect(), success, hcard: 0x%08x [0x%lx]", + (unsigned) hCard, myHCard); - if (hcardFirst) + if (szVendor && (strlen(szVendor) > 0)) { - hcardFirst->prev = hcard; - hcard->next = hcardFirst; + logger(SmartCard, Debug, + "TS_SCardConnect(), set attribute ATTR_VENDOR_NAME"); + pthread_mutex_lock(&hcardAccess); + PSCHCardRec hcard = xmalloc(sizeof(TSCHCardRec)); + if (hcard) + { + hcard->hCard = hCard; + hcard->vendor = szVendor; + hcard->next = NULL; + hcard->prev = NULL; + + if (hcardFirst) + { + hcardFirst->prev = hcard; + hcard->next = hcardFirst; + } + hcardFirst = hcard; + } + pthread_mutex_unlock(&hcardAccess); } - hcardFirst = hcard; } - pthread_mutex_unlock(&hcardAccess); - } + break; + + default: + logger(SmartCard, Debug, + "TS_SCardConnect(), SCardConnect failed: %s (0x%08x)", + pcsc_stringify_error(rv), rv); + break; } out_uint32_le(out, 0x00000000); @@ -961,17 +1000,23 @@ myHCard = _scard_handle_list_get_pcsc_handle(hCard); - DEBUG_SCARD(("SCARD: SCardReconnect(context: 0x%08x, hcard: 0x%08x [%lx], share: 0x%08x, proto: 0x%08x, init: 0x%08x)\n", (unsigned) hContext, (unsigned) hCard, myHCard, (unsigned) dwShareMode, (unsigned) dwPreferredProtocol, (unsigned) dwInitialization)); + + logger(SmartCard, Debug, + "TS_SCardReconnect(), context: 0x%08x, hcard: 0x%08x [%lx], share: 0x%08x, proto: 0x%08x, init: 0x%08x", + (unsigned) hContext, (unsigned) hCard, myHCard, (unsigned) dwShareMode, + (unsigned) dwPreferredProtocol, (unsigned) dwInitialization); + rv = SCardReconnect(myHCard, (MYPCSC_DWORD) dwShareMode, (MYPCSC_DWORD) dwPreferredProtocol, (MYPCSC_DWORD) dwInitialization, &dwActiveProtocol); if (rv != SCARD_S_SUCCESS) { - DEBUG_SCARD(("SCARD: -> Failure: %s (0x%08x)\n", - pcsc_stringify_error(rv), (unsigned int) rv)); + logger(SmartCard, Debug, "TS_SCardReconnect(), failed: %s (0x%08x)", + pcsc_stringify_error(rv), (unsigned int) rv); } else { - DEBUG_SCARD(("SCARD: -> Success (proto: 0x%08x)\n", (unsigned) dwActiveProtocol)); + logger(SmartCard, Debug, "TS_SCardReconnect(), success, proto=0x%08x", + (unsigned) dwActiveProtocol); } out_uint32_le(out, (SERVER_DWORD) dwActiveProtocol); @@ -1000,7 +1045,10 @@ myHContext = _scard_handle_list_get_pcsc_handle(hContext); myHCard = _scard_handle_list_get_pcsc_handle(hCard); - DEBUG_SCARD(("SCARD: SCardDisconnect(context: 0x%08x [0x%lx], hcard: 0x%08x [0x%lx], disposition: 0x%08x)\n", (unsigned) hContext, myHContext, (unsigned) hCard, myHCard, (unsigned) dwDisposition)); + logger(SmartCard, Debug, + "TS_SCardDisconnect(), context: 0x%08x [0x%lx], hcard: 0x%08x [0x%lx], disposition: 0x%08x", + (unsigned) hContext, myHContext, (unsigned) hCard, myHCard, + (unsigned) dwDisposition); pthread_mutex_lock(&hcardAccess); PSCHCardRec hcard = hcardFirst; @@ -1027,12 +1075,12 @@ if (rv != SCARD_S_SUCCESS) { - DEBUG_SCARD(("SCARD: -> Failure: %s (0x%08x)\n", - pcsc_stringify_error(rv), (unsigned int) rv)); + logger(SmartCard, Debug, "TS_SCardDisconnect(), failed: %s (0x%08x)", + pcsc_stringify_error(rv), (unsigned int) rv); } else { - DEBUG_SCARD(("SCARD: -> Success\n")); + logger(SmartCard, Debug, "TS_SCardReconnect(), success"); } outForceAlignment(out, 8); @@ -1132,7 +1180,9 @@ myHContext = _scard_handle_list_get_pcsc_handle(hContext); - DEBUG_SCARD(("SCARD: SCardGetStatusChange(context: 0x%08x [0x%lx], timeout: 0x%08x, count: %d)\n", (unsigned) hContext, myHContext, (unsigned) dwTimeout, (int) dwCount)); + logger(SmartCard, Debug, + "TS_SCardGetStatusChange(), context: 0x%08x [0x%lx], timeout: 0x%08x, count: %d", + (unsigned) hContext, myHContext, (unsigned) dwTimeout, (int) dwCount); if (dwCount > 0) { @@ -1162,14 +1212,16 @@ inString(&lcHandle, in, (char **) &(cur->szReader), dataLength, wide)); +#if !WITH_PNP_NOTIFICATIONS if (strcmp(cur->szReader, "\\\\?PnP?\\Notification") == 0) cur->dwCurrentState |= SCARD_STATE_IGNORE; +#endif } - DEBUG_SCARD(("SCARD: \"%s\"\n", cur->szReader ? cur->szReader : "NULL")); - DEBUG_SCARD(("SCARD: user: %p, state: 0x%08x, event: 0x%08x\n", - cur->pvUserData, (unsigned) cur->dwCurrentState, - (unsigned) cur->dwEventState)); + logger(SmartCard, Debug, + "TS_SCardGetStatusChange(), reader='%s', user=%p, state=0x%08x, event=0x%08x", + cur->szReader ? cur->szReader : "NULL", cur->pvUserData, + (unsigned) cur->dwCurrentState, (unsigned) cur->dwEventState); } } else @@ -1183,24 +1235,18 @@ memset(myRsArray, 0, dwCount * sizeof(SERVER_SCARD_READERSTATE_A)); copyReaderState_ServerToMyPCSC(rsArray, myRsArray, (SERVER_DWORD) dwCount); - /* Workaround for a bug in pcsclite, timeout value of 0 is handled as INFINIT + /* Workaround for a bug in pcsc-lite, timeout value of 0 is handled as INFINIT but is by Windows PCSC spec. used for polling current state. */ if (dwTimeout == 0) - dwTimeout = 1; + dwTimeout = 1; rv = SCardGetStatusChange(myHContext, (MYPCSC_DWORD) dwTimeout, myRsArray, (MYPCSC_DWORD) dwCount); copyReaderState_MyPCSCToServer(myRsArray, rsArray, (MYPCSC_DWORD) dwCount); - if (rv != SCARD_S_SUCCESS) - { - DEBUG_SCARD(("SCARD: -> Failure: %s (0x%08x)\n", - pcsc_stringify_error(rv), (unsigned int) rv)); - } - else - { - DEBUG_SCARD(("SCARD: -> Success\n")); - } + logger(SmartCard, Debug, + "TS_SCardGetStatusChange(), SCardGetStatusChange returned \"%s\" (0x%08x)", + pcsc_stringify_error(rv), rv); out_uint32_le(out, dwCount); out_uint32_le(out, 0x00084dd8); @@ -1208,10 +1254,10 @@ for (i = 0, cur = rsArray; i < dwCount; i++, cur++) { - DEBUG_SCARD(("SCARD: \"%s\"\n", cur->szReader ? cur->szReader : "NULL")); - DEBUG_SCARD(("SCARD: user: %p, state: 0x%08x, event: 0x%08x\n", - cur->pvUserData, (unsigned) cur->dwCurrentState, - (unsigned) cur->dwEventState)); + logger(SmartCard, Debug, + "TS_SCardGetStatusChange(), reader='%s', user=%p, state=0x%08x, event=0x%08x", + cur->szReader ? cur->szReader : "NULL", cur->pvUserData, + (unsigned) cur->dwCurrentState, (unsigned) cur->dwEventState); /* Do endian swaps... */ cur->dwCurrentState = swap32(cur->dwCurrentState); @@ -1239,17 +1285,18 @@ myHContext = _scard_handle_list_get_pcsc_handle(hContext); - DEBUG_SCARD(("SCARD: SCardCancel(context: 0x%08x [0x%08lx])\n", (unsigned) hContext, - (unsigned long) myHContext)); + logger(SmartCard, Debug, "TS_SCardCancel(), context: 0x%08x [0x%08lx]", + (unsigned) hContext, (unsigned long) myHContext); + rv = SCardCancel(myHContext); if (rv != SCARD_S_SUCCESS) { - DEBUG_SCARD(("SCARD: -> Failure: %s (0x%08x)\n", - pcsc_stringify_error(rv), (unsigned int) rv)); + logger(SmartCard, Debug, "TS_SCardCancel(), failed: %s (0x%08x)", + pcsc_stringify_error(rv), (unsigned int) rv); } else { - DEBUG_SCARD(("SCARD: -> Success\n")); + logger(SmartCard, Debug, "TS_SCardCancel(), success"); } outForceAlignment(out, 8); s_mark_end(out); @@ -1259,7 +1306,7 @@ static MYPCSC_DWORD TS_SCardLocateCardsByATR(STREAM in, STREAM out, RD_BOOL wide) { - int i, j, k; + unsigned int i, j, k; MYPCSC_DWORD rv; SERVER_SCARDCONTEXT hContext; MYPCSC_SCARDCONTEXT myHContext; @@ -1289,26 +1336,15 @@ myHContext = _scard_handle_list_get_pcsc_handle(hContext); - DEBUG_SCARD(("SCARD: SCardLocateCardsByATR(context: 0x%08x [0x%08lx], atrs: %d, readers: %d)\n", (unsigned) hContext, (unsigned long) myHContext, (int) atrMaskCount, (int) readerCount)); + logger(SmartCard, Debug, + "TS_SCardLocateCardsByATR(), context: 0x%08x [0x%08lx], atrs: %d, readers: %d", + (unsigned) hContext, (unsigned long) myHContext, (int) atrMaskCount, + (int) readerCount); for (i = 0, cur = pAtrMasks; i < atrMaskCount; i++, cur++) { cur->cbAtr = swap32(cur->cbAtr); - - DEBUG_SCARD(("SCARD: ATR: ")); - for (j = 0; j < pAtrMasks->cbAtr; j++) - { - DEBUG_SCARD(("%02x%c", - (unsigned) (unsigned char) cur->rgbAtr[j], - (j == pAtrMasks->cbAtr - 1) ? ' ' : ':'))} - DEBUG_SCARD(("\n")); - DEBUG_SCARD(("SCARD: ")); - for (j = 0; j < pAtrMasks->cbAtr; j++) - { - DEBUG_SCARD(("%02x%c", - (unsigned) (unsigned char) cur->rgbMask[j], - (j == pAtrMasks->cbAtr - 1) ? ' ' : ':'))} - DEBUG_SCARD(("\n")); + /* Fixme, we might want to log the ATR and mask here */ } for (i = 0, rsCur = (SERVER_LPSCARD_READERSTATE_A) ((unsigned char **) rsArray + 2); @@ -1330,10 +1366,11 @@ rsCur->cbAtr = swap32(rsCur->cbAtr); inReaderName(&lcHandle, in, (char **) &rsCur->szReader, wide); - DEBUG_SCARD(("SCARD: \"%s\"\n", rsCur->szReader ? rsCur->szReader : "NULL")); - DEBUG_SCARD(("SCARD: user: %p, state: 0x%08x, event: 0x%08x\n", - rsCur->pvUserData, (unsigned) rsCur->dwCurrentState, - (unsigned) rsCur->dwEventState)); + + logger(SmartCard, Debug, + "TS_SCardLocateCardsByATR(), reader='%s', user=%p, state=0x%08x, event=0x%08x", + rsCur->szReader ? rsCur->szReader : "NULL", rsCur->pvUserData, + (unsigned) rsCur->dwCurrentState, (unsigned) rsCur->dwEventState); } memcpy(ResArray, rsArray, readerCount * sizeof(SERVER_SCARD_READERSTATE_A)); @@ -1346,12 +1383,12 @@ copyReaderState_MyPCSCToServer(myRsArray, rsArray, readerCount); if (rv != SCARD_S_SUCCESS) { - DEBUG_SCARD(("SCARD: -> Failure: %s (0x%08x)\n", - pcsc_stringify_error(rv), (unsigned int) rv)); + logger(SmartCard, Debug, "TS_SCardLocateCardsByATR(), failed: %s (0x%08x)", + pcsc_stringify_error(rv), (unsigned int) rv); } else { - DEBUG_SCARD(("SCARD: -> Success\n")); + logger(SmartCard, Debug, "TS_SCardLocateCardsByATR(), success"); cur = pAtrMasks; for (i = 0, cur = pAtrMasks; i < atrMaskCount; i++, cur++) { @@ -1371,9 +1408,12 @@ { rsCur->dwEventState |= 0x00000040; /* SCARD_STATE_ATRMATCH 0x00000040 */ memcpy(ResArray + j, rsCur, sizeof(SCARD_READERSTATE)); - DEBUG_SCARD(("SCARD: \"%s\"\n", - rsCur->szReader ? rsCur->szReader : "NULL")); - DEBUG_SCARD(("SCARD: user: %p, state: 0x%08x, event: 0x%08x\n", rsCur->pvUserData, (unsigned) rsCur->dwCurrentState, (unsigned) rsCur->dwEventState)); + + logger(SmartCard, Debug, + "TS_SCardLocateCardsByATR(), reader='%s', user=%p, state=0x%08x, event=0x%08x", + rsCur->szReader ? rsCur->szReader : "NULL", + rsCur->pvUserData, (unsigned) rsCur->dwCurrentState, + (unsigned) rsCur->dwEventState); } } } @@ -1410,17 +1450,17 @@ in_uint8s(in, 0x30); in_uint32_le(in, hCard); myHCard = _scard_handle_list_get_pcsc_handle(hCard); - DEBUG_SCARD(("SCARD: SCardBeginTransaction(hcard: 0x%08x [0x%lx])\n", - (unsigned) hCard, myHCard)); + logger(SmartCard, Debug, "TS_SCardBeginTransaction(), hcard: 0x%08x [0x%lx])", + (unsigned) hCard, myHCard); rv = SCardBeginTransaction(myHCard); if (rv != SCARD_S_SUCCESS) { - DEBUG_SCARD(("SCARD: -> Failure: %s (0x%08x)\n", - pcsc_stringify_error(rv), (unsigned int) rv)); + logger(SmartCard, Debug, "TS_SCardBeginTransaction(), failed: %s (0x%08x)", + pcsc_stringify_error(rv), (unsigned int) rv); } else { - DEBUG_SCARD(("SCARD: -> Success\n")); + logger(SmartCard, Debug, "TS_SCardBeginTransaction(), success"); } outForceAlignment(out, 8); s_mark_end(out); @@ -1442,17 +1482,18 @@ myHCard = _scard_handle_list_get_pcsc_handle(hCard); - DEBUG_SCARD(("SCARD: SCardEndTransaction(hcard: 0x%08x [0x%lx], disposition: 0x%08x)\n", - (unsigned) hCard, (unsigned long) myHCard, (unsigned) dwDisposition)); + logger(SmartCard, Debug, + "TS_SCardEndTransaction(), hcard: 0x%08x [0x%lx], disposition: 0x%08x)", + (unsigned) hCard, (unsigned long) myHCard, (unsigned) dwDisposition); rv = SCardEndTransaction(myHCard, (MYPCSC_DWORD) dwDisposition); if (rv != SCARD_S_SUCCESS) { - DEBUG_SCARD(("SCARD: -> Failure: %s (0x%08x)\n", - pcsc_stringify_error(rv), (unsigned int) rv)); + logger(SmartCard, Debug, "TS_SCardEndTransaction(), failed: %s (0x%08x)", + pcsc_stringify_error(rv), (unsigned int) rv); } else { - DEBUG_SCARD(("SCARD: -> Success\n")); + logger(SmartCard, Debug, "TS_SCardEndTransaction(), success"); } outForceAlignment(out, 8); s_mark_end(out); @@ -1489,7 +1530,7 @@ static DWORD -TS_SCardTransmit(STREAM in, STREAM out) +TS_SCardTransmit(STREAM in, STREAM out, uint32 srv_buf_len) { MYPCSC_DWORD rv; SERVER_DWORD map[7], linkedLen; @@ -1503,6 +1544,7 @@ MYPCSC_DWORD myCbRecvLength; PMEM_HANDLE lcHandle = NULL; + in_uint8s(in, 0x14); in_uint32_le(in, map[0]); in_uint8s(in, 0x04); @@ -1520,6 +1562,9 @@ if (map[0] & INPUT_LINKED) inSkipLinked(in); + if (srv_buf_len <= cbRecvLength) + cbRecvLength = srv_buf_len; + in_uint8s(in, 0x04); in_uint32_le(in, hCard); myHCard = _scard_handle_list_get_pcsc_handle(hCard); @@ -1588,7 +1633,9 @@ else pioRecvPci = NULL; - DEBUG_SCARD(("SCARD: SCardTransmit(hcard: 0x%08x [0x%08lx], send: %d bytes, recv: %d bytes)\n", (unsigned) hCard, (unsigned long) myHCard, (int) cbSendLength, (int) cbRecvLength)); + logger(SmartCard, Debug, + "TS_SCardTransmit(), 0x%08x [0x%08lx], send: %d bytes, recv: %d bytes", + (unsigned) hCard, (unsigned long) myHCard, (int) cbSendLength, (int) cbRecvLength); myCbRecvLength = cbRecvLength; myPioSendPci = SC_xmalloc(&lcHandle, @@ -1616,13 +1663,6 @@ myPioRecvPci, recvBuf, &myCbRecvLength); cbRecvLength = myCbRecvLength; - /* FIXME: handle responses with length > 448 bytes */ - if (cbRecvLength > 448) - { - warning("Card response limited from %d to 448 bytes!\n", cbRecvLength); - DEBUG_SCARD(("SCARD: Truncated %d to %d\n", (unsigned int) cbRecvLength, 448)); - cbRecvLength = 448; - } if (pioRecvPci) { @@ -1636,12 +1676,13 @@ if (rv != SCARD_S_SUCCESS) { - DEBUG_SCARD(("SCARD: -> Failure: %s (0x%08x)\n", - pcsc_stringify_error(rv), (unsigned int) rv)); + logger(SmartCard, Debug, "TS_SCardTransmit(), failed: %s (0x%08x)", + pcsc_stringify_error(rv), (unsigned int) rv); } else { - DEBUG_SCARD(("SCARD: -> Success (%d bytes)\n", (int) cbRecvLength)); + logger(SmartCard, Debug, "TS_SCardTransmit(), success, %d bytes", + (int) cbRecvLength); #if 0 if ((pioRecvPci != NULL) && (mypioRecvPci->cbPciLength > 0)) { @@ -1693,11 +1734,15 @@ in_uint32_le(in, hCard); in_uint8s(in, 0x04); myHCard = _scard_handle_list_get_pcsc_handle(hCard); - DEBUG_SCARD(("SCARD: SCardStatus(hcard: 0x%08x [0x%08lx], reader len: %d bytes, atr len: %d bytes)\n", (unsigned) hCard, (unsigned long) myHCard, (int) dwReaderLen, (int) dwAtrLen)); + logger(SmartCard, Debug, + "TS_SCardStatus(), hcard: 0x%08x [0x%08lx], reader len: %d bytes, atr len: %d bytes", + (unsigned) hCard, (unsigned long) myHCard, (int) dwReaderLen, (int) dwAtrLen); - if (dwReaderLen <= 0 || dwReaderLen == SCARD_AUTOALLOCATE || dwReaderLen > SCARD_MAX_MEM) + if (dwReaderLen == 0 || dwReaderLen == (SERVER_DWORD) SCARD_AUTOALLOCATE + || dwReaderLen > SCARD_MAX_MEM) dwReaderLen = SCARD_MAX_MEM; - if (dwAtrLen <= 0 || dwAtrLen == SCARD_AUTOALLOCATE || dwAtrLen > SCARD_MAX_MEM) + if (dwAtrLen == 0 || dwAtrLen == (SERVER_DWORD) SCARD_AUTOALLOCATE + || dwAtrLen > SCARD_MAX_MEM) dwAtrLen = SCARD_MAX_MEM; #if 1 @@ -1730,23 +1775,14 @@ if (rv != SCARD_S_SUCCESS) { - DEBUG_SCARD(("SCARD: -> Failure: %s (0x%08x)\n", - pcsc_stringify_error(rv), (unsigned int) rv)); + logger(SmartCard, Debug, "TS_SCardTransmit(), failed: %s (0x%08x)", + pcsc_stringify_error(rv), (unsigned int) rv); return SC_returnCode(rv, &lcHandle, in, out); } else { - int i; - - DEBUG_SCARD(("SCARD: -> Success (state: 0x%08x, proto: 0x%08x)\n", - (unsigned) dwState, (unsigned) dwProtocol)); - DEBUG_SCARD(("SCARD: Reader: \"%s\"\n", readerName ? readerName : "NULL")); - DEBUG_SCARD(("SCARD: ATR: ")); - for (i = 0; i < dwAtrLen; i++) - { - DEBUG_SCARD(("%02x%c", atr[i], (i == dwAtrLen - 1) ? ' ' : ':')); - } - DEBUG_SCARD(("\n")); + logger(SmartCard, Debug, "TS_SCardTransmit(), success, state=0x%08x, proto=0x%08x", + (unsigned) dwState, (unsigned) dwProtocol); if (dwState & (SCARD_SPECIFIC | SCARD_NEGOTIABLE)) dwState = 0x00000006; @@ -1819,11 +1855,12 @@ in_uint8s(in, 0x04); myHCard = _scard_handle_list_get_pcsc_handle(hCard); - DEBUG_SCARD(("SCARD: SCardState(hcard: 0x%08x [0x%08lx], atr len: %d bytes)\n", - (unsigned) hCard, (unsigned long) myHCard, (int) dwAtrLen)); + logger(SmartCard, Debug, "TS_SCardState(), hcard: 0x%08x [0x%08lx], atrlen: %d bytes", + (unsigned) hCard, (unsigned long) myHCard, (int) dwAtrLen); dwReaderLen = SCARD_MAX_MEM; - if (dwAtrLen <= 0 || dwAtrLen == SCARD_AUTOALLOCATE || dwAtrLen > SCARD_MAX_MEM) + if (dwAtrLen <= 0 || dwAtrLen == (SERVER_DWORD) SCARD_AUTOALLOCATE + || dwAtrLen > SCARD_MAX_MEM) dwAtrLen = SCARD_MAX_MEM; readerName = SC_xmalloc(&lcHandle, dwReaderLen + 2); @@ -1846,22 +1883,14 @@ if (rv != SCARD_S_SUCCESS) { - DEBUG_SCARD(("SCARD: -> Failure: %s (0x%08x)\n", - pcsc_stringify_error(rv), (unsigned int) rv)); + logger(SmartCard, Debug, "TS_SCardState(), failed: %s (0x%08x)", + pcsc_stringify_error(rv), (unsigned int) rv); return SC_returnCode(rv, &lcHandle, in, out); } else { - int i; - - DEBUG_SCARD(("SCARD: -> Success (state: 0x%08x, proto: 0x%08x)\n", - (unsigned) dwState, (unsigned) dwProtocol)); - DEBUG_SCARD(("SCARD: ATR: ")); - for (i = 0; i < dwAtrLen; i++) - { - DEBUG_SCARD(("%02x%c", atr[i], (i == dwAtrLen - 1) ? ' ' : ':')); - } - DEBUG_SCARD(("\n")); + logger(SmartCard, Debug, "TS_SCardState(), success, state=0x%08x, proto=0x%08x", + (unsigned) dwState, (unsigned) dwProtocol); if (dwState & (SCARD_SPECIFIC | SCARD_NEGOTIABLE)) dwState = 0x00000006; @@ -1922,8 +1951,8 @@ myHContext = _scard_handle_list_get_pcsc_handle(hContext); - DEBUG_SCARD(("SCARD: SCardListReaderGroups(context: 0x%08x [0x%08lx], groups: %d)\n", - (unsigned) hContext, (unsigned int) myHContext, (int) dwGroups)); + logger(SmartCard, Debug, "TS_SCardListReaderGroups(), ontext: 0x%08x [0x%08lx], groups: %d", + (unsigned) hContext, (unsigned int) myHContext, (int) dwGroups); if (dwGroups <= 0 || dwGroups == SCARD_AUTOALLOCATE || dwGroups > SCARD_MAX_MEM) dwGroups = SCARD_MAX_MEM; @@ -1938,8 +1967,8 @@ if (rv) { - DEBUG_SCARD(("SCARD: -> Failure: %s (0x%08x)\n", - pcsc_stringify_error(rv), (unsigned int) rv)); + logger(SmartCard, Error, "TS_SCardListReaderGroups(), failed: %s (0x%08x)", + pcsc_stringify_error(rv), (unsigned int) rv); return SC_returnCode(rv, &lcHandle, in, out); } else @@ -1947,10 +1976,10 @@ int i; char *cur; - DEBUG_SCARD(("SCARD: -> Success\n")); + logger(SmartCard, Debug, "TS_SCardListReaderGroups(), success"); for (i = 0, cur = szGroups; i < dwGroups; i++, cur += strlen(cur) + 1) { - DEBUG_SCARD(("SCARD: %s\n", cur)); + logger(SmartCard, Debug, "TS_SCardListReaderGroups(), %s", cur); } } @@ -1988,23 +2017,18 @@ in_uint32_le(in, hCard); myHCard = _scard_handle_list_get_pcsc_handle(hCard); - DEBUG_SCARD(("SCARD: SCardGetAttrib(hcard: 0x%08x [0x%08lx], attrib: 0x%08x (%d bytes))\n", - (unsigned) hCard, (unsigned long) myHCard, - (unsigned) dwAttrId, (int) dwAttrLen)); + logger(SmartCard, Debug, + "TS_SCardGetAttrib(), hcard: 0x%08x [0x%08lx], attrib: 0x%08x (%d bytes)", + (unsigned) hCard, (unsigned long) myHCard, (unsigned) dwAttrId, (int) dwAttrLen); - if (dwAttrLen > MAX_BUFFER_SIZE) - dwAttrLen = MAX_BUFFER_SIZE; - - - if (dwAttrLen > SCARD_AUTOALLOCATE) - pbAttr = NULL; - else if ((dwAttrLen < 0) || (dwAttrLen > SCARD_MAX_MEM)) - { - dwAttrLen = (SERVER_DWORD) SCARD_AUTOALLOCATE; - pbAttr = NULL; - } - else + pbAttr = NULL; + if (dwAttrLen != (SERVER_DWORD) SCARD_AUTOALLOCATE) { + if (dwAttrLen > MAX_BUFFER_SIZE) + { + dwAttrLen = MAX_BUFFER_SIZE; + } + pbAttr = SC_xmalloc(&lcHandle, dwAttrLen); if (!pbAttr) return SC_returnNoMemoryError(&lcHandle, in, out); @@ -2016,13 +2040,13 @@ if (rv != SCARD_S_SUCCESS) { - DEBUG_SCARD(("SCARD: -> Failure: %s (0x%08x)\n", - pcsc_stringify_error(rv), (unsigned int) rv)); + logger(SmartCard, Debug, "TS_SCardGetAttrib(), failed: %s (0x%08x)", + pcsc_stringify_error(rv), (unsigned int) rv); return SC_returnCode(rv, &lcHandle, in, out); } else { - DEBUG_SCARD(("SCARD: -> Success (%d bytes)\n", (int) dwAttrLen)); + logger(SmartCard, Debug, "TS_SCardGetAttrib(), %d bytes", (int) dwAttrLen); out_uint32_le(out, dwAttrLen); out_uint32_le(out, 0x00000200); @@ -2064,9 +2088,10 @@ in_uint32_le(in, hCard); myHCard = scHandleToMyPCSC(hCard); - DEBUG_SCARD(("SCARD: SCardSetAttrib(hcard: 0x%08x [0x%08lx], attrib: 0x%08x (%d bytes))\n", - (unsigned) hCard, (unsigned long) myHCard, - (unsigned) dwAttrId, (int) dwAttrLen)); + + logger(SmartCard, Debug, + "TS_SCardSetAttrib(), hcard: 0x%08x [0x%08lx], attrib: 0x%08x (%d bytes)", + (unsigned) hCard, (unsigned long) myHCard, (unsigned) dwAttrId, (int) dwAttrLen); if (dwAttrLen > MAX_BUFFER_SIZE) dwAttrLen = MAX_BUFFER_SIZE; @@ -2080,12 +2105,12 @@ if (rv != SCARD_S_SUCCESS) { - DEBUG_SCARD(("SCARD: -> Failure: %s (0x%08x)\n", - pcsc_stringify_error(rv), (unsigned int) rv)); + logger(SmartCard, Error, "TS_SCardSetAttrib(), failed: %s (0x%08x)", + pcsc_stringify_error(rv), (unsigned int) rv); } else { - DEBUG_SCARD(("SCARD: -> Success\n")); + logger(SmartCard, Debug, "TS_SCardSetAttrib(), success"); } out_uint32_le(out, 0x00000000); @@ -2148,9 +2173,14 @@ myHCard = _scard_handle_list_get_pcsc_handle(hCard); myHContext = _scard_handle_list_get_pcsc_handle(hContext); - DEBUG_SCARD(("SCARD: SCardControl(context: 0x%08x [0x%08lx], hcard: 0x%08x [0x%08lx], code: 0x%08x, in: %d bytes, out: %d bytes)\n", (unsigned) hContext, (unsigned long) myHContext, (unsigned) hCard, (unsigned long) myHCard, (unsigned) dwControlCode, (int) nInBufferSize, (int) nOutBufferSize)); + logger(SmartCard, Debug, + "TS_SCardControl(), context: 0x%08x [0x%08lx], hcard: 0x%08x [0x%08lx], code: 0x%08x, in: %d bytes, out: %d bytes)\n", + (unsigned) hContext, (unsigned long) myHContext, (unsigned) hCard, + (unsigned long) myHCard, (unsigned) dwControlCode, (int) nInBufferSize, + (int) nOutBufferSize); /* Is this a proper Windows smart card ioctl? */ + /* FILE_DEVICE_SMARTCARD defined as 0x000031 in Winsmcrd.h */ if ((dwControlCode & 0xffff0000) == (49 << 16)) { /* Translate to local encoding */ @@ -2159,7 +2189,28 @@ } else { - warning("Bogus smart card control code 0x%08x\n", dwControlCode); + /* + * According to "Interoperability Specification for ICCs and Personal Computer Systems. + * Part 10 IFDs with Secure PIN Entry Capabilities Supplement - IFDs with Feature Capabilities" + * you have to issue GET_FEATURE_REQUEST to get codes for supported features. + * + * You have to use only those codes not some hardcoded values. + * + * So the correct way to do fix this would be to parse received TLV from + * CM_IOCTL_GET_FEATURE_REQUEST and get all codes for the corresponding features for + * the particular reader as these values are defined by the driver itself and not + * by pcsclite. + * + */ + + /* ATM, I removed features code transformations */ + /* You know what to do if any problem arises in the future. */ + if ((dwControlCode & 0xff000000) != SCARD_CTL_CODE(0)) + { + logger(SmartCard, Warning, + "TS_SCardControl(), bogus smart card control code 0x%08x", + dwControlCode); + } } #if 0 @@ -2192,32 +2243,15 @@ if (rv != SCARD_S_SUCCESS) { - DEBUG_SCARD(("SCARD: -> Failure: %s (0x%08x)\n", - pcsc_stringify_error(rv), (unsigned int) rv)); + logger(SmartCard, Debug, "TS_SCardControl(), failed: %s (0x%08x)", + pcsc_stringify_error(rv), (unsigned int) rv); } else { - DEBUG_SCARD(("SCARD: -> Success (out: %d bytes)\n", (int) nBytesReturned)); + logger(SmartCard, Debug, "TS_SCardControl(), success, out: %d bytes", + (int) nBytesReturned); } -#ifdef PCSCLITE_VERSION_NUMBER - if (dwControlCode == SCARD_CTL_CODE(3400)) - { - int i; - SERVER_DWORD cc; - - for (i = 0; i < nBytesReturned / 6; i++) - { - memcpy(&cc, pOutBuffer + 2 + i * 6, 4); - cc = ntohl(cc); - cc = cc - 0x42000000; - cc = (49 << 16) | (cc << 2); - cc = htonl(cc); - memcpy(pOutBuffer + 2 + i * 6, &cc, 4); - } - } -#endif - out_uint32_le(out, nBytesReturned); out_uint32_le(out, 0x00000004); out_uint32_le(out, nBytesReturned); @@ -2236,26 +2270,32 @@ static MYPCSC_DWORD TS_SCardAccessStartedEvent(STREAM in, STREAM out) { - DEBUG_SCARD(("SCARD: SCardAccessStartedEvent()\n")); + UNUSED(in); + logger(SmartCard, Debug, "TS_SCardAccessStartedEvent()"); out_uint8s(out, 8); return SCARD_S_SUCCESS; } static RD_NTSTATUS -scard_device_control(RD_NTHANDLE handle, uint32 request, STREAM in, STREAM out) +scard_device_control(RD_NTHANDLE handle, uint32 request, STREAM in, STREAM out, uint32 srv_buf_len) { + UNUSED(handle); SERVER_DWORD Result = 0x00000000; size_t psize, pend, pStatusCode; SERVER_DWORD addToEnd = 0; /* Processing request */ + /* See MS-RSPESC 1.3 Overview for protocol flow */ + + /* Set CommonTypeHeader (MS-RPCE 2.2.6.1) */ out_uint32_le(out, 0x00081001); /* Header lines */ out_uint32_le(out, 0xCCCCCCCC); psize = s_tell(out); + /* Set PrivateTypeHeader (MS-RPCE 2.2.6.2) */ out_uint32_le(out, 0x00000000); /* Size of data portion */ - out_uint32_le(out, 0x00000000); /* Zero bytes (may be usefull) */ + out_uint32_le(out, 0x00000000); /* Zero bytes (may be useful) */ pStatusCode = s_tell(out); out_uint32_le(out, 0x00000000); /* Status Code */ @@ -2344,7 +2384,7 @@ /* ScardTransmit */ case SC_TRANSMIT: { - Result = (SERVER_DWORD) TS_SCardTransmit(in, out); + Result = (SERVER_DWORD) TS_SCardTransmit(in, out, srv_buf_len); break; } /* SCardControl */ @@ -2380,7 +2420,9 @@ } default: { - warning("SCARD: Unknown function %d\n", (int) request); + logger(SmartCard, Warning, + "scard_device_control(), unhandled operation %d", + (int) request); Result = 0x80100014; out_uint8s(out, 256); break; @@ -2403,6 +2445,7 @@ /* finish */ s_seek(out, pend); + /* TODO: Check MS-RPCE 2.2.6.2 for alignment requirements (IIRC length must be integral multiple of 8) */ addToEnd = (pend - pStatusCode) % 16; if (addToEnd < 16 && addToEnd > 0) { @@ -2410,6 +2453,8 @@ s_mark_end(out); } + if (Result == SCARD_E_INSUFFICIENT_BUFFER) return RD_STATUS_BUFFER_TOO_SMALL; + return RD_STATUS_SUCCESS; } @@ -2484,6 +2529,7 @@ data->epoch = curEpoch; data->handle = handle; data->request = request; + data->srv_buf_len = curBytesOut - 0x14; data->in = duplicateStream(&(data->memHandle), in, 0, SC_TRUE); if (data->in == NULL) { @@ -2550,20 +2596,20 @@ static void SC_deviceControl(PSCThreadData data) { + RD_NTSTATUS status; size_t buffer_len = 0; - scard_device_control(data->handle, data->request, data->in, data->out); + status = scard_device_control(data->handle, data->request, data->in, data->out, data->srv_buf_len); buffer_len = s_tell(data->out); /* if iorequest belongs to another epoch, don't send response - back to server due to it's considered as abdonend. + back to server due to it's considered as abandoned. */ if (data->epoch == curEpoch) { uint8 *buf; s_seek(data->out, 0); in_uint8p(data->out, buf, buffer_len); - rdpdr_send_completion(data->device, data->id, 0, buffer_len, buf, - buffer_len); + rdpdr_send_completion(data->device, data->id, status, buffer_len, buf, buffer_len); } SC_destroyThreadData(data); @@ -2627,7 +2673,8 @@ Result = pthread_create(&cur->thread, NULL, (void *(*)(void *)) thread_function, cur); if (0 != Result) { - error("[THREAD CREATE ERROR 0x%.8x]\n", Result); + logger(SmartCard, Debug, "SC_handleRequest(), pthread_create() failed with 0x%.8x", + Result); SC_xfree(&threadListHandle, cur); SC_destroyThreadData(data); data = NULL; @@ -2639,6 +2686,7 @@ static void * queue_handler_function(void *data) { + UNUSED(data); PSCThreadData cur_data = NULL; while (1) { @@ -2677,7 +2725,6 @@ scard_write, thread_wrapper }; -#endif /* MAKE_PROTO */ void scard_lock(int lock) @@ -2719,3 +2766,25 @@ queueFirst = queueLast = NULL; } + +void +scard_release_all_contexts(void) +{ + _scard_handle_list_t *item, *next; + + item = g_scard_handle_list; + + while (item) + { + /* Cancelling ScardGetStatusChange calls */ + SCardCancel(item->handle); + /* releasing context to end all transactions on it */ + SCardReleaseContext(item->handle); + + next = item->next; + xfree(item); + item = next; + } + + g_scard_handle_list = NULL; +} diff -Nru rdesktop-1.8.6/scard.h rdesktop-1.9.0/scard.h --- rdesktop-1.8.6/scard.h 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/scard.h 2019-06-13 12:10:15.000000000 +0000 @@ -2,6 +2,7 @@ rdesktop: A Remote Desktop Protocol client. Smart Card support Copyright (C) Alexi Volkov <alexi@myrealbox.com> 2006 + Copyright 2016 Alexander Zakharov <uglym8@gmail.com> 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 @@ -155,6 +156,7 @@ uint32 device; uint32 id; uint32 epoch; + uint32 srv_buf_len; RD_NTHANDLE handle; uint32 request; STREAM in; diff -Nru rdesktop-1.8.6/seamless.c rdesktop-1.9.0/seamless.c --- rdesktop-1.8.6/seamless.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/seamless.c 2019-06-13 12:10:15.000000000 +0000 @@ -3,7 +3,7 @@ Seamless Windows support Copyright 2005-2008 Peter Astrand <astrand@cendio.se> for Cendio AB Copyright 2007-2008 Pierre Ossman <ossman@cendio.se> for Cendio AB - Copyright 2013-2014 Henrik Andersson <hean01@cendio.se> for Cendio AB + Copyright 2013-2017 Henrik Andersson <hean01@cendio.se> for Cendio AB 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 @@ -23,12 +23,6 @@ #include <stdarg.h> #include <assert.h> -#ifdef WITH_DEBUG_SEAMLESS -#define DEBUG_SEAMLESS(args) printf args; -#else -#define DEBUG_SEAMLESS(args) -#endif - extern RD_BOOL g_seamless_rdp; static VCHANNEL *seamless_channel; static unsigned int seamless_serial; @@ -62,18 +56,19 @@ static RD_BOOL seamless_process_line(const char *line, void *data) { + UNUSED(data); char *p, *l; - char *tok1, *tok2, *tok3, *tok4, *tok5, *tok6, *tok7, *tok8; + char *tok1, *tok3, *tok4, *tok5, *tok6, *tok7, *tok8; unsigned long id, flags; char *endptr; l = xstrdup(line); p = l; - DEBUG_SEAMLESS(("seamlessrdp got:%s\n", p)); + logger(Core, Debug, "seamless_process_line(), got '%s'", p); tok1 = seamless_get_token(&p); - tok2 = seamless_get_token(&p); + (void) seamless_get_token(&p); tok3 = seamless_get_token(&p); tok4 = seamless_get_token(&p); tok5 = seamless_get_token(&p); @@ -176,7 +171,7 @@ if ((size_t)len >= sizeof(icon_buf)) { - warning("seamless_process_line(), icon data would overrun icon_buf"); + logger(Protocol, Warning, "seamless_process_line(), icon data would overrun icon_buf"); break; } } @@ -291,7 +286,7 @@ } else if (!strcmp("DEBUG", tok1)) { - DEBUG_SEAMLESS(("SeamlessRDP:%s\n", line)); + logger(Core, Debug, "seamless_process_line(), %s", line); } else if (!strcmp("SYNCBEGIN", tok1)) { @@ -370,7 +365,7 @@ { if (!seamless_process_line(line, data)) { - warning("SeamlessRDP: Invalid request:%s\n", line); + logger(Core, Warning, "seamless_line_handler(), invalid request '%s'", line); } return True; } @@ -387,11 +382,6 @@ buf = xmalloc(pkglen + 1); in_uint8a(s, buf, pkglen); buf[pkglen] = '\0'; -#if 0 - printf("seamless recv:\n"); - hexdump(buf, pkglen); -#endif - str_handle_lines(buf, &seamless_rest, seamless_line_handler, NULL); xfree(buf); @@ -453,12 +443,7 @@ s = channel_init(seamless_channel, len); out_uint8a(s, buf, len) s_mark_end(s); - DEBUG_SEAMLESS(("seamlessrdp sending:%s", buf)); - -#if 0 - printf("seamless send:\n"); - hexdump(s->channel_hdr + 8, s->end - s->channel_hdr - 8); -#endif + logger(Core, Debug, "seamless_send(), sending '%s'", buf); channel_send(s, seamless_channel); s_free(s); @@ -557,8 +542,10 @@ unsigned int res; if (!g_seamless_rdp) return (unsigned int) -1; - printf("%s persistent seamless mode.\n", enable?"Enable":"Disable"); + + logger(Core, Debug, "seamless_send_persistent(), %s persistent seamless mode", + enable ? "enable" : "disable"); res = seamless_send("PERSISTENT", "%d", enable); - + return res; } diff -Nru rdesktop-1.8.6/secure.c rdesktop-1.9.0/secure.c --- rdesktop-1.8.6/secure.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/secure.c 2019-06-13 12:11:35.000000000 +0000 @@ -3,6 +3,7 @@ Protocol services - RDP encryption and licensing Copyright (C) Matthew Chapman <matthewc.unsw.edu.au> 1999-2008 Copyright 2005-2011 Peter Astrand <astrand@cendio.se> for Cendio AB + Copyright 2017-2018 Henrik Andersson <hean01@cendio.se> for Cendio AB 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 @@ -22,8 +23,9 @@ #include "ssl.h" extern char g_hostname[16]; -extern int g_width; -extern int g_height; +extern uint32 g_requested_session_width; +extern uint32 g_requested_session_height; +extern int g_dpi; extern unsigned int g_keylayout; extern int g_keyboard_type; extern int g_keyboard_subtype; @@ -172,7 +174,7 @@ if (rc4_key_size == 1) { - DEBUG(("40-bit encryption enabled\n")); + logger(Protocol, Debug, "sec_generate_keys(), 40-bit encryption enabled"); sec_make_40bit(g_sec_sign_key); sec_make_40bit(g_sec_decrypt_key); sec_make_40bit(g_sec_encrypt_key); @@ -180,7 +182,9 @@ } else { - DEBUG(("rc_4_key_size == %d, 128-bit encryption enabled\n", rc4_key_size)); + logger(Protocol, Debug, + "sec_generate_key(), rc_4_key_size == %d, 128-bit encryption enabled", + rc4_key_size); g_rc4_key_len = 16; } @@ -351,12 +355,6 @@ flags &= ~SEC_ENCRYPT; datalen = s_remaining(s) - 8; inout_uint8p(s, data, datalen + 8); - -#if WITH_DEBUG - DEBUG(("Sending encrypted packet:\n")); - hexdump(data + 8, datalen); -#endif - sec_sign(data, 8, g_sec_sign_key, g_rc4_key_len, data + 8, datalen); sec_encrypt(data + 8, datalen); } @@ -382,7 +380,7 @@ sec_establish_key(void) { uint32 length = g_server_public_key_len + SEC_PADDING_SIZE; - uint32 flags = SEC_CLIENT_RANDOM; + uint32 flags = SEC_EXCHANGE_PKT; STREAM s; s = sec_init(flags, length + 4); @@ -398,18 +396,23 @@ /* Output connect initial data blob */ static void -sec_out_mcs_data(STREAM s, uint32 selected_protocol) +sec_out_mcs_connect_initial_pdu(STREAM s, uint32 selected_protocol) { - int hostlen = 2 * strlen(g_hostname); - int length = 162 + 76 + 12 + 4; + int length = 162 + 76 + 12 + 4 + (g_dpi > 0 ? 18 : 0); unsigned int i; + uint32 rdpversion = RDP_40; + uint16 capflags = RNS_UD_CS_SUPPORT_ERRINFO_PDU; + uint16 colorsupport = RNS_UD_24BPP_SUPPORT | RNS_UD_16BPP_SUPPORT | RNS_UD_32BPP_SUPPORT; + uint32 physwidth, physheight, desktopscale, devicescale; + + logger(Protocol, Debug, "%s()", __func__); + + if (g_rdp_version >= RDP_V5) + rdpversion = RDP_50; if (g_num_channels > 0) length += g_num_channels * 12 + 8; - if (hostlen > 30) - hostlen = 30; - /* Generic Conference Control (T.124) ConferenceCreateRequest */ out_uint16_be(s, 5); out_uint16_be(s, 0x14); @@ -427,46 +430,64 @@ out_uint32_le(s, 0x61637544); /* OEM ID: "Duca", as in Ducati. */ out_uint16_be(s, ((length - 14) | 0x8000)); /* remaining length */ - /* Client information */ - out_uint16_le(s, SEC_TAG_CLI_INFO); - out_uint16_le(s, 216); /* length */ - out_uint16_le(s, (g_rdp_version >= RDP_V5) ? 4 : 1); /* RDP version. 1 == RDP4, 4 >= RDP5 to RDP8 */ - out_uint16_le(s, 8); - out_uint16_le(s, g_width); - out_uint16_le(s, g_height); - out_uint16_le(s, 0xca01); - out_uint16_le(s, 0xaa03); - out_uint32_le(s, g_keylayout); - out_uint32_le(s, 2600); /* Client build. We are now 2600 compatible :-) */ + /* Client information (TS_UD_CS_CORE) */ + out_uint16_le(s, CS_CORE); /* type */ + out_uint16_le(s, 216 + (g_dpi > 0 ? 18 : 0)); /* length */ + out_uint32_le(s, rdpversion); /* version */ + out_uint16_le(s, g_requested_session_width); /* desktopWidth */ + out_uint16_le(s, g_requested_session_height); /* desktopHeight */ + out_uint16_le(s, RNS_UD_COLOR_8BPP); /* colorDepth */ + out_uint16_le(s, RNS_UD_SAS_DEL); /* SASSequence */ + out_uint32_le(s, g_keylayout); /* keyboardLayout */ + /* + * According to s.1.7 of MS-RDPESC if the build number is at least 4,304, + * SCREDIR_VERSION_LONGHORN is assumed; otherwise SCREDIR_VERSIONXP is to be used + */ + out_uint32_le(s, 2600); /* Client build. We are now 2600 compatible :-) */ /* Unicode name of client, padded to 32 bytes */ - rdp_out_unistr(s, g_hostname, hostlen); - out_uint8s(s, 30 - hostlen); + out_utf16s_padded(s, g_hostname, 32, 0x00); - /* See - http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wceddk40/html/cxtsksupportingremotedesktopprotocol.asp */ - out_uint32_le(s, g_keyboard_type); - out_uint32_le(s, g_keyboard_subtype); - out_uint32_le(s, g_keyboard_functionkeys); - out_uint8s(s, 64); /* reserved? 4 + 12 doublewords */ - out_uint16_le(s, 0xca01); /* colour depth? */ - out_uint16_le(s, 1); - - out_uint32(s, 0); - out_uint8(s, g_server_depth); - out_uint16_le(s, 0x0700); - out_uint8(s, 0); - out_uint32_le(s, 1); - out_uint8s(s, 64); - out_uint32_le(s, selected_protocol); /* End of client info */ + out_uint32_le(s, g_keyboard_type); /* keyboardType */ + out_uint32_le(s, g_keyboard_subtype); /* keyboardSubtype */ + out_uint32_le(s, g_keyboard_functionkeys); /* keyboardFunctionKey */ + out_uint8s(s, 64); /* imeFileName */ + out_uint16_le(s, RNS_UD_COLOR_8BPP); /* postBeta2ColorDepth (overrides colorDepth) */ + out_uint16_le(s, 1); /* clientProductId (should be 1) */ + out_uint32_le(s, 0); /* serialNumber (should be 0) */ + + /* highColorDepth (overrides postBeta2ColorDepth). Capped at 24BPP. + To get 32BPP sessions, we need to set a capability flag. */ + out_uint16_le(s, MIN(g_server_depth, 24)); + if (g_server_depth == 32) + capflags |= RNS_UD_CS_WANT_32BPP_SESSION; + + out_uint16_le(s, colorsupport); /* supportedColorDepths */ + out_uint16_le(s, capflags); /* earlyCapabilityFlags */ + out_uint8s(s, 64); /* clientDigProductId */ + out_uint8(s, 0); /* connectionType */ + out_uint8(s, 0); /* pad */ + out_uint32_le(s, selected_protocol); /* serverSelectedProtocol */ + if (g_dpi > 0) + { + /* Extended client info describing monitor geometry */ + utils_calculate_dpi_scale_factors(g_requested_session_width, + g_requested_session_height, g_dpi, &physwidth, + &physheight, &desktopscale, &devicescale); + out_uint32_le(s, physwidth); /* physicalwidth */ + out_uint32_le(s, physheight); /* physicalheight */ + out_uint16_le(s, ORIENTATION_LANDSCAPE); /* Orientation */ + out_uint32_le(s, desktopscale); /* DesktopScaleFactor */ + out_uint32_le(s, devicescale); /* DeviceScaleFactor */ + } /* Write a Client Cluster Data (TS_UD_CS_CLUSTER) */ uint32 cluster_flags = 0; - out_uint16_le(s, SEC_TAG_CLI_CLUSTER); /* header.type */ + out_uint16_le(s, CS_CLUSTER); /* header.type */ out_uint16_le(s, 12); /* length */ cluster_flags |= SEC_CC_REDIRECTION_SUPPORTED; - cluster_flags |= (SEC_CC_REDIRECT_VERSION_3 << 2); + cluster_flags |= (SEC_CC_REDIRECT_VERSION_4 << 2); if (g_console_session || g_redirect_session_id != 0) cluster_flags |= SEC_CC_REDIRECT_SESSIONID_FIELD_VALID; @@ -474,21 +495,23 @@ out_uint32_le(s, cluster_flags); out_uint32(s, g_redirect_session_id); - /* Client encryption settings */ - out_uint16_le(s, SEC_TAG_CLI_CRYPT); + /* Client encryption settings (TS_UD_CS_SEC) */ + out_uint16_le(s, CS_SECURITY); /* type */ out_uint16_le(s, 12); /* length */ - out_uint32_le(s, g_encryption ? 0x3 : 0); /* encryption supported, 128-bit supported */ - out_uint32(s, 0); /* Unknown */ + out_uint32_le(s, g_encryption ? 0x3 : 0); /* encryptionMethods */ + out_uint32(s, 0); /* extEncryptionMethods */ - DEBUG_RDP5(("g_num_channels is %d\n", g_num_channels)); + /* Channel definitions (TS_UD_CS_NET) */ + logger(Protocol, Debug, "sec_out_mcs_data(), g_num_channels is %d", g_num_channels); if (g_num_channels > 0) { - out_uint16_le(s, SEC_TAG_CLI_CHANNELS); + out_uint16_le(s, CS_NET); /* type */ out_uint16_le(s, g_num_channels * 12 + 8); /* length */ out_uint32_le(s, g_num_channels); /* number of virtual channels */ for (i = 0; i < g_num_channels; i++) { - DEBUG_RDP5(("Requesting channel %s\n", g_channels[i].name)); + logger(Protocol, Debug, "sec_out_mcs_data(), requesting channel %s", + g_channels[i].name); out_uint8a(s, g_channels[i].name, 8); out_uint32_be(s, g_channels[i].flags); } @@ -510,7 +533,8 @@ in_uint32_le(s, magic); if (magic != SEC_RSA_MAGIC) { - error("RSA magic 0x%x\n", magic); + logger(Protocol, Error, "sec_parse_public_key(), magic (0x%x) != SEC_RSA_MAGIC", + magic); return False; } @@ -518,7 +542,9 @@ modulus_len -= SEC_PADDING_SIZE; if ((modulus_len < SEC_MODULUS_SIZE) || (modulus_len > SEC_MAX_MODULUS_SIZE)) { - error("Bad server public key size (%u bits)\n", modulus_len * 8); + logger(Protocol, Error, + "sec_parse_public_key(), invalid public key size (%u bits) from server", + modulus_len * 8); return False; } @@ -565,11 +591,14 @@ uint16 tag, length; size_t next_tag; + logger(Protocol, Debug, "%s()", __func__); + in_uint32_le(s, *rc4_key_size); /* 1 = 40-bit, 2 = 128-bit */ in_uint32_le(s, crypt_level); /* 1 = low, 2 = medium, 3 = high */ if (crypt_level == 0) { /* no encryption */ + logger(Protocol, Debug, "sec_parse_crypt_info(), got ENCRYPTION_LEVEL_NONE"); return False; } @@ -578,7 +607,8 @@ if (random_len != SEC_RANDOM_SIZE) { - error("random len %d, expected %d\n", random_len, SEC_RANDOM_SIZE); + logger(Protocol, Error, "sec_parse_crypt_info(), got random len %d, expected %d", + random_len, SEC_RANDOM_SIZE); return False; } @@ -586,12 +616,16 @@ /* RSA info */ if (!s_check_rem(s, rsa_info_len)) + { + logger(Protocol, Error, "sec_parse_crypt_info(), !s_check_rem(s, rsa_info_len)"); return False; + } in_uint32_le(s, flags); /* 1 = RDP4-style, 0x80000002 = X.509 */ if (flags & 1) { - DEBUG_RDP5(("We're going for the RDP4-style encryption\n")); + logger(Protocol, Debug, + "sec_parse_crypt_info(), We're going for the RDP4-style encryption"); in_uint8s(s, 8); /* unknown */ while (!s_check_end(s)) @@ -605,18 +639,29 @@ { case SEC_TAG_PUBKEY: if (!sec_parse_public_key(s, modulus, exponent)) + { + logger(Protocol, Error, + "sec_parse_crypt_info(), invalid public key"); return False; - DEBUG_RDP5(("Got Public key, RDP4-style\n")); + } + logger(Protocol, Debug, + "sec_parse_crypt_info(), got public key"); break; case SEC_TAG_KEYSIG: if (!sec_parse_public_sig(s, length, modulus, exponent)) + { + logger(Protocol, Error, + "sec_parse_crypt_info(), invalid public sig"); return False; + } break; default: - unimpl("crypt tag 0x%x\n", tag); + logger(Protocol, Warning, + "sec_parse_crypt_info(), unhandled crypt tag 0x%x", + tag); } s_seek(s, next_tag); @@ -627,11 +672,13 @@ uint32 certcount; unsigned char *certdata; - DEBUG_RDP5(("We're going for the RDP5-style encryption\n")); + logger(Protocol, Debug, + "sec_parse_crypt_info(), We're going for the RDP5-style encryption"); in_uint32_le(s, certcount); /* Number of certificates */ if (certcount < 2) { - error("Server didn't send enough X509 certificates\n"); + logger(Protocol, Error, + "sec_parse_crypt_info(), server didn't send enough x509 certificates"); return False; } for (; certcount > 2; certcount--) @@ -640,19 +687,18 @@ RDSSL_CERT *ignorecert; unsigned char *ignoredata; - DEBUG_RDP5(("Ignored certs left: %d\n", certcount)); in_uint32_le(s, ignorelen); in_uint8p(s, ignoredata, ignorelen); ignorecert = rdssl_cert_read(ignoredata, ignorelen); if (ignorecert == NULL) { /* XXX: error out? */ - DEBUG_RDP5(("got a bad cert: this will probably screw up the rest of the communication\n")); + logger(Protocol, Error, + "sec_parse_crypt_info(), got a bad cert: this will probably screw up the rest of the communication"); + } + else + { + rdssl_cert_free(ignorecert); } - -#ifdef WITH_DEBUG_RDP5 - DEBUG_RDP5(("cert #%d (ignored):\n", certcount)); - rdssl_cert_print_fp(stdout, ignorecert); -#endif } /* Do da funky X.509 stuffy @@ -663,29 +709,34 @@ http://www.cs.auckland.ac.nz/~pgut001/pubs/x509guide.txt */ in_uint32_le(s, cacert_len); - DEBUG_RDP5(("CA Certificate length is %d\n", cacert_len)); in_uint8p(s, certdata, cacert_len); + logger(Protocol, Debug, + "sec_parse_crypt_info(), server CA Certificate length is %d", cacert_len); cacert = rdssl_cert_read(certdata, cacert_len); if (NULL == cacert) { - error("Couldn't load CA Certificate from server\n"); + logger(Protocol, Error, + "sec_parse_crypt_info(), couldn't load CA Certificate from server"); return False; } in_uint32_le(s, cert_len); - DEBUG_RDP5(("Certificate length is %d\n", cert_len)); in_uint8p(s, certdata, cert_len); + logger(Protocol, Debug, "sec_parse_crypt_info(), certificate length is %d", + cert_len); server_cert = rdssl_cert_read(certdata, cert_len); if (NULL == server_cert) { rdssl_cert_free(cacert); - error("Couldn't load Certificate from server\n"); + logger(Protocol, Error, + "sec_parse_crypt_info(), couldn't load Certificate from server"); return False; } if (!rdssl_certs_ok(server_cert, cacert)) { rdssl_cert_free(server_cert); rdssl_cert_free(cacert); - error("Security error CA Certificate invalid\n"); + logger(Protocol, Error, + "sec_parse_crypt_info(), security error, CA Certificate invalid"); return False; } rdssl_cert_free(cacert); @@ -693,7 +744,8 @@ server_public_key = rdssl_cert_to_rkey(server_cert, &g_server_public_key_len); if (NULL == server_public_key) { - DEBUG_RDP5(("Didn't parse X509 correctly\n")); + logger(Protocol, Debug, + "sec_parse_crypt_info(). failed to parse X509 correctly"); rdssl_cert_free(server_cert); return False; } @@ -701,15 +753,17 @@ if ((g_server_public_key_len < SEC_MODULUS_SIZE) || (g_server_public_key_len > SEC_MAX_MODULUS_SIZE)) { - error("Bad server public key size (%u bits)\n", - g_server_public_key_len * 8); + logger(Protocol, Error, + "sec_parse_crypt_info(), bad server public key size (%u bits)", + g_server_public_key_len * 8); rdssl_rkey_free(server_public_key); return False; } if (rdssl_rkey_get_exp_mod(server_public_key, exponent, SEC_EXPONENT_SIZE, modulus, SEC_MAX_MODULUS_SIZE) != 0) { - error("Problem extracting RSA exponent, modulus"); + logger(Protocol, Error, + "sec_parse_crypt_info(), problem extracting RSA exponent, modulus"); rdssl_rkey_free(server_public_key); return False; } @@ -728,14 +782,14 @@ uint8 exponent[SEC_EXPONENT_SIZE]; uint32 rc4_key_size; + logger(Protocol, Debug, "%s()", __func__); + memset(modulus, 0, sizeof(modulus)); memset(exponent, 0, sizeof(exponent)); if (!sec_parse_crypt_info(s, &rc4_key_size, &server_random, modulus, exponent)) - { - DEBUG(("Failed to parse crypt info\n")); return; - } - DEBUG(("Generating client random\n")); + + logger(Protocol, Debug, "sec_parse_crypt_info(), generating client random"); generate_random(g_client_random); sec_rsa_encrypt(g_sec_crypted_random, g_client_random, SEC_RANDOM_SIZE, g_server_public_key_len, modulus, exponent); @@ -748,7 +802,8 @@ sec_process_srv_info(STREAM s) { in_uint16_le(s, g_server_rdp_version); - DEBUG_RDP5(("Server RDP version is %d\n", g_server_rdp_version)); + logger(Protocol, Debug, "sec_process_srv_info(), server RDP version is %d", + g_server_rdp_version); if (1 == g_server_rdp_version) { g_rdp_version = RDP_V4; @@ -769,6 +824,7 @@ in_uint8(s, len); if (len & 0x80) in_uint8(s, len); + logger(Protocol, Debug, "%s()", __func__); while (!s_check_end(s)) { @@ -783,21 +839,24 @@ switch (tag) { case SEC_TAG_SRV_INFO: + logger(Protocol, Debug, "%s(), SEC_TAG_SRV_INFO", __func__); sec_process_srv_info(s); break; case SEC_TAG_SRV_CRYPT: + logger(Protocol, Debug, "%s(), SEC_TAG_SRV_CRYPT", __func__); sec_process_crypt_info(s); break; case SEC_TAG_SRV_CHANNELS: + logger(Protocol, Debug, "%s(), SEC_TAG_SRV_CHANNELS", __func__); /* FIXME: We should parse this information and use it to map RDP5 channels to MCS channels */ break; default: - unimpl("response tag 0x%x\n", tag); + logger(Protocol, Warning, "Unhandled response tag 0x%x", tag); } s_seek(s, next_tag); @@ -806,45 +865,52 @@ /* Receive secure transport packet */ STREAM -sec_recv(uint8 * rdpver) +sec_recv(RD_BOOL * is_fastpath) { - uint32 sec_flags; + uint8 fastpath_hdr, fastpath_flags; + uint16 sec_flags; uint16 channel; STREAM s; struct stream packet; size_t data_offset; + size_t remaining; unsigned char *data; - while ((s = mcs_recv(&channel, rdpver)) != NULL) + while ((s = mcs_recv(&channel, is_fastpath, &fastpath_hdr)) != NULL) { packet = *s; - if (rdpver != NULL) + if (*is_fastpath == True) { - if (*rdpver != 3) + /* If fastpath packet is encrypted, read data + signature and decrypt */ + /* FIXME: extracting flags from hdr could be made less obscure */ + fastpath_flags = (fastpath_hdr & 0xC0) >> 6; + if (fastpath_flags & FASTPATH_OUTPUT_ENCRYPTED) { - if (*rdpver & 0x80) - { - if (!s_check_rem(s, 8)) { - rdp_protocol_error("consume fastpath signature from stream would overrun", &packet); - } + if (!s_check_rem(s, 8)) { + rdp_protocol_error("consume fastpath signature from stream would overrun", &packet); + } - in_uint8s(s, 8); /* signature */ + in_uint8s(s, 8); /* signature */ - data_offset = s_tell(s); + data_offset = s_tell(s); - inout_uint8p(s, data, s_remaining(s)); - sec_decrypt(data, s_remaining(s)); + remaining = s_remaining(s); + inout_uint8p(s, data, remaining); + sec_decrypt(data, remaining); - s_seek(s, data_offset); - } - return s; + s_seek(s, data_offset); } + return s; } + if (g_encryption || (!g_licence_issued && !g_licence_error_result)) { data_offset = s_tell(s); - in_uint32_le(s, sec_flags); + /* TS_SECURITY_HEADER */ + in_uint16_le(s, sec_flags); + in_uint8s(s, 2); /* skip sec_flags_hi */ if (g_encryption) { @@ -860,18 +926,19 @@ data_offset = s_tell(s); - inout_uint8p(s, data, s_remaining(s)); - sec_decrypt(data, s_remaining(s)); + remaining = s_remaining(s); + inout_uint8p(s, data, remaining); + sec_decrypt(data, remaining); } - if (sec_flags & SEC_LICENCE_NEG) + if (sec_flags & SEC_LICENSE_PKT) { s_seek(s, data_offset); licence_process(s); continue; } - if (sec_flags & 0x0400) /* SEC_REDIRECT_ENCRYPT */ + if (sec_flags & SEC_REDIRECTION_PKT) { uint8 swapbyte; @@ -883,15 +950,16 @@ data_offset = s_tell(s); - inout_uint8p(s, data, s_remaining(s)); - sec_decrypt(data, s_remaining(s)); + remaining = s_remaining(s); + inout_uint8p(s, data, remaining); + sec_decrypt(data, remaining); /* Check for a redirect packet, starts with 00 04 */ if (data[0] == 0 && data[1] == 4) { /* for some reason the PDU and the length seem to be swapped. This isn't good, but we're going to do a byte for byte - swap. So the first foure value appear as: 00 04 XX YY, + swap. So the first four value appear as: 00 04 XX YY, where XX YY is the little endian length. We're going to use 04 00 as the PDU type, so after our swap this will look like: XX YY 04 00 */ @@ -907,15 +975,11 @@ data[2] = data[3]; data[3] = swapbyte; } -#ifdef WITH_DEBUG - /* warning! this debug statement will show passwords in the clear! */ - hexdump(s->p, s_remaining(s)); -#endif } } else { - if ((sec_flags & 0xffff) == SEC_LICENCE_NEG) + if (sec_flags & SEC_LICENSE_PKT) { licence_process(s); continue; @@ -928,9 +992,7 @@ if (channel != MCS_GLOBAL_CHANNEL) { channel_process(s, channel); - if (rdpver != NULL) - *rdpver = 0xff; - return s; + continue; } return s; @@ -952,9 +1014,9 @@ /* We exchange some RDP data during the MCS-Connect */ mcs_data = s_alloc(512); - sec_out_mcs_data(mcs_data, selected_proto); + sec_out_mcs_connect_initial_pdu(mcs_data, selected_proto); - /* finialize the MCS connect sequence */ + /* finalize the MCS connect sequence */ if (!mcs_connect_finalize(mcs_data)) return False; @@ -969,7 +1031,9 @@ void sec_disconnect(void) { - mcs_disconnect(); + /* Perform a User-initiated disconnect sequence, see + [MS-RDPBCGR] 1.3.1.4 Disconnect Sequences */ + mcs_disconnect(RN_USER_REQUESTED); } /* reset the state of the sec layer */ diff -Nru rdesktop-1.8.6/serial.c rdesktop-1.9.0/serial.c --- rdesktop-1.8.6/serial.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/serial.c 2019-06-13 12:10:15.000000000 +0000 @@ -17,6 +17,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <unistd.h> +#include <errno.h> #include <fcntl.h> #include <termios.h> #include <strings.h> @@ -34,12 +35,6 @@ #include "rdesktop.h" -#ifdef WITH_DEBUG_SERIAL -#define DEBUG_SERIAL(args) printf args; -#else -#define DEBUG_SERIAL(args) -#endif - #define FILE_DEVICE_SERIAL_PORT 0x1b #define SERIAL_SET_BAUD_RATE 1 @@ -97,14 +92,14 @@ /* SERIAL_WAIT_ON_MASK */ #define SERIAL_EV_RXCHAR 0x0001 /* Any Character received */ #define SERIAL_EV_RXFLAG 0x0002 /* Received certain character */ -#define SERIAL_EV_TXEMPTY 0x0004 /* Transmitt Queue Empty */ +#define SERIAL_EV_TXEMPTY 0x0004 /* Transmit Queue Empty */ #define SERIAL_EV_CTS 0x0008 /* CTS changed state */ #define SERIAL_EV_DSR 0x0010 /* DSR changed state */ #define SERIAL_EV_RLSD 0x0020 /* RLSD changed state */ #define SERIAL_EV_BREAK 0x0040 /* BREAK received */ #define SERIAL_EV_ERR 0x0080 /* Line status error occurred */ #define SERIAL_EV_RING 0x0100 /* Ring signal detected */ -#define SERIAL_EV_PERR 0x0200 /* Printer error occured */ +#define SERIAL_EV_PERR 0x0200 /* Printer error occurred */ #define SERIAL_EV_RX80FULL 0x0400 /* Receive buffer is 80 percent full */ #define SERIAL_EV_EVENT1 0x0800 /* Provider specific event 1 */ #define SERIAL_EV_EVENT2 0x1000 /* Provider specific event 2 */ @@ -507,7 +502,7 @@ } /* Enumeration of devices from rdesktop.c */ -/* returns numer of units found and initialized. */ +/* returns number of units found and initialized. */ /* optarg looks like ':com1=/dev/ttyS0' */ /* when it arrives to this function. */ /* :com1=/dev/ttyS0,com2=/dev/ttyS1 */ @@ -538,8 +533,10 @@ g_rdpdr_device[*id].local_path = xmalloc(strlen(pos2) + 1); strcpy(g_rdpdr_device[*id].local_path, pos2); - printf("SERIAL %s to %s\n", g_rdpdr_device[*id].name, + + logger(Core, Debug, "serial_enum_devices(), %s to %s", g_rdpdr_device[*id].name, g_rdpdr_device[*id].local_path); + /* set device type */ g_rdpdr_device[*id].device_type = DEVICE_TYPE_SERIAL; g_rdpdr_device[*id].pdevice_data = (void *) pser_inf; @@ -555,23 +552,28 @@ serial_create(uint32 device_id, uint32 access, uint32 share_mode, uint32 disposition, uint32 flags_and_attributes, char *filename, RD_NTHANDLE * handle) { - RD_NTHANDLE serial_fd; + UNUSED(access); + UNUSED(share_mode); + UNUSED(disposition); + UNUSED(flags_and_attributes); + UNUSED(filename); + int serial_fd; SERIAL_DEVICE *pser_inf; - struct termios *ptermios; pser_inf = (SERIAL_DEVICE *) g_rdpdr_device[device_id].pdevice_data; - ptermios = pser_inf->ptermios; - serial_fd = open(g_rdpdr_device[device_id].local_path, O_RDWR | O_NOCTTY | O_NONBLOCK); + serial_fd = open(g_rdpdr_device[device_id].local_path, O_RDWR | O_NOCTTY | O_NONBLOCK); if (serial_fd == -1) { - perror("open"); + logger(Core, Error, "serial_create(), open '%s' failed: %s", + g_rdpdr_device[device_id].local_path, strerror(errno)); return RD_STATUS_ACCESS_DENIED; } if (!get_termios(pser_inf, serial_fd)) { - printf("INFO: SERIAL %s access denied\n", g_rdpdr_device[device_id].name); + logger(Core, Error, "serial_create(), access denied to %s", + g_rdpdr_device[device_id].name); fflush(stdout); return RD_STATUS_ACCESS_DENIED; } @@ -580,7 +582,11 @@ g_rdpdr_device[device_id].handle = serial_fd; /* some sane information */ - DEBUG_SERIAL(("INFO: SERIAL %s to %s\nINFO: speed %u baud, stop bits %u, parity %u, word length %u bits, dtr %u, rts %u\n", g_rdpdr_device[device_id].name, g_rdpdr_device[device_id].local_path, pser_inf->baud_rate, pser_inf->stop_bits, pser_inf->parity, pser_inf->word_length, pser_inf->dtr, pser_inf->rts)); + logger(Core, Debug, + "serial_create(), %s to %s, speed %u baud, stop bits %u, parity %u, word length %u bits, dtr %u, rts %u", + g_rdpdr_device[device_id].name, g_rdpdr_device[device_id].local_path, + pser_inf->baud_rate, pser_inf->stop_bits, pser_inf->parity, pser_inf->word_length, + pser_inf->dtr, pser_inf->rts); pser_inf->ptermios->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); @@ -601,7 +607,8 @@ /* all read and writes should be non blocking */ if (fcntl(*handle, F_SETFL, O_NONBLOCK) == -1) - perror("fcntl"); + logger(Core, Error, "serial_create(), failed to set non blocking: %s", + strerror(errno)); pser_inf->read_total_timeout_constant = 5; @@ -621,12 +628,13 @@ } static RD_NTSTATUS -serial_read(RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result) +serial_read(RD_NTHANDLE handle, uint8 * data, uint32 length, uint64 offset, uint32 * result) { + UNUSED(offset); /* Offset must always be zero according to MS-RDPESP */ long timeout; SERIAL_DEVICE *pser_inf; struct termios *ptermios; -#ifdef WITH_DEBUG_SERIAL +#ifdef TIOCINQ int bytes_inqueue; #endif @@ -663,25 +671,22 @@ } tcsetattr(handle, TCSANOW, ptermios); -#if defined(WITH_DEBUG_SERIAL) && defined(TIOCINQ) +#if defined(TIOCINQ) ioctl(handle, TIOCINQ, &bytes_inqueue); - DEBUG_SERIAL(("serial_read inqueue: %d expected %d\n", bytes_inqueue, length)); + logger(Core, Debug, "serial_read(), inqueue: %d expected %d\n", bytes_inqueue, length); #endif *result = read(handle, data, length); -#ifdef WITH_DEBUG_SERIAL - DEBUG_SERIAL(("serial_read Bytes %d\n", *result)); - if (*result > 0) - hexdump(data, *result); -#endif + logger(Core, Debug, "serial_read(), %d bytes read", *result); return RD_STATUS_SUCCESS; } static RD_NTSTATUS -serial_write(RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result) +serial_write(RD_NTHANDLE handle, uint8 * data, uint32 length, uint64 offset, uint32 * result) { + UNUSED(offset); /* Offset must always be zero according to MS-RDPESP */ SERIAL_DEVICE *pser_inf; pser_inf = get_serial_info(handle); @@ -691,7 +696,7 @@ if (*result > 0) pser_inf->event_txempty = *result; - DEBUG_SERIAL(("serial_write length %d, offset %d result %d\n", length, offset, *result)); + logger(Core, Debug, "serial_write(), %d bytes written", *result); return RD_STATUS_SUCCESS; } @@ -703,13 +708,11 @@ uint32 result, modemstate; uint8 immediate; SERIAL_DEVICE *pser_inf; - struct termios *ptermios; if ((request >> 16) != FILE_DEVICE_SERIAL_PORT) return RD_STATUS_INVALID_PARAMETER; pser_inf = get_serial_info(handle); - ptermios = pser_inf->ptermios; /* extract operation */ request >>= 2; @@ -720,56 +723,56 @@ case SERIAL_SET_BAUD_RATE: in_uint32_le(in, pser_inf->baud_rate); set_termios(pser_inf, handle); - DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_BAUD_RATE %d\n", - pser_inf->baud_rate)); + logger(Protocol, Debug, "serial_device_control(), set baud rate %d", + pser_inf->baud_rate); break; case SERIAL_GET_BAUD_RATE: out_uint32_le(out, pser_inf->baud_rate); - DEBUG_SERIAL(("serial_ioctl -> SERIAL_GET_BAUD_RATE %d\n", - pser_inf->baud_rate)); + logger(Protocol, Debug, "serial_device_control(), get baud rate %d", + pser_inf->baud_rate); break; case SERIAL_SET_QUEUE_SIZE: in_uint32_le(in, pser_inf->queue_in_size); in_uint32_le(in, pser_inf->queue_out_size); - DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_QUEUE_SIZE in %d out %d\n", - pser_inf->queue_in_size, pser_inf->queue_out_size)); + logger(Protocol, Debug, + "serial_device_control(), set queue size, in=%d out=%d", + pser_inf->queue_in_size, pser_inf->queue_out_size); break; case SERIAL_SET_LINE_CONTROL: in_uint8(in, pser_inf->stop_bits); in_uint8(in, pser_inf->parity); in_uint8(in, pser_inf->word_length); set_termios(pser_inf, handle); - DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_LINE_CONTROL stop %d parity %d word %d\n", pser_inf->stop_bits, pser_inf->parity, pser_inf->word_length)); + logger(Protocol, Debug, + "serial_device_control(), set line control, stop=%d, parity=%d, word=%d", + pser_inf->stop_bits, pser_inf->parity, pser_inf->word_length); break; case SERIAL_GET_LINE_CONTROL: - DEBUG_SERIAL(("serial_ioctl -> SERIAL_GET_LINE_CONTROL\n")); + logger(Protocol, Debug, "serial_device_control(), get line control"); out_uint8(out, pser_inf->stop_bits); out_uint8(out, pser_inf->parity); out_uint8(out, pser_inf->word_length); break; case SERIAL_IMMEDIATE_CHAR: - DEBUG_SERIAL(("serial_ioctl -> SERIAL_IMMEDIATE_CHAR\n")); + logger(Protocol, Debug, "serial_device_control(), immediate char"); in_uint8(in, immediate); serial_write(handle, &immediate, 1, 0, &result); break; case SERIAL_CONFIG_SIZE: - DEBUG_SERIAL(("serial_ioctl -> SERIAL_CONFIG_SIZE\n")); + logger(Protocol, Debug, "serial_device_control(), config size"); out_uint32_le(out, 0); break; case SERIAL_GET_CHARS: - DEBUG_SERIAL(("serial_ioctl -> SERIAL_GET_CHARS\n")); + logger(Protocol, Debug, "serial_device_control(), get chars"); out_uint8a(out, pser_inf->chars, 6); break; case SERIAL_SET_CHARS: - DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_CHARS\n")); + logger(Protocol, Debug, "serial_device_control(), set chars"); in_uint8a(in, pser_inf->chars, 6); -#ifdef WITH_DEBUG_SERIAL - hexdump(pser_inf->chars, 6); -#endif set_termios(pser_inf, handle); break; case SERIAL_GET_HANDFLOW: - DEBUG_SERIAL(("serial_ioctl -> SERIAL_GET_HANDFLOW\n")); + logger(Protocol, Debug, "serial_device_control(), get handflow"); get_termios(pser_inf, handle); out_uint32_le(out, pser_inf->control); out_uint32_le(out, pser_inf->xonoff); /* Xon/Xoff */ @@ -781,9 +784,10 @@ in_uint32_le(in, pser_inf->xonoff); in_uint32_le(in, pser_inf->onlimit); in_uint32_le(in, pser_inf->offlimit); - DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_HANDFLOW %x %x %x %x\n", - pser_inf->control, pser_inf->xonoff, pser_inf->onlimit, - pser_inf->onlimit)); + logger(Protocol, Debug, + "serial_device_control(), set handflow, control=%x, xonoff=%x, onlimit=%x, offlimit=%x", + pser_inf->control, pser_inf->xonoff, pser_inf->onlimit, + pser_inf->offlimit); set_termios(pser_inf, handle); break; case SERIAL_SET_TIMEOUTS: @@ -792,16 +796,18 @@ in_uint32(in, pser_inf->read_total_timeout_constant); in_uint32(in, pser_inf->write_total_timeout_multiplier); in_uint32(in, pser_inf->write_total_timeout_constant); - DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_TIMEOUTS read timeout %d %d %d\n", - pser_inf->read_interval_timeout, - pser_inf->read_total_timeout_multiplier, - pser_inf->read_total_timeout_constant)); + logger(Protocol, Debug, + "serial_device_control(), set timeouts, timeout=%d, multiplier=%d, constant=%d", + pser_inf->read_interval_timeout, + pser_inf->read_total_timeout_multiplier, + pser_inf->read_total_timeout_constant); break; case SERIAL_GET_TIMEOUTS: - DEBUG_SERIAL(("serial_ioctl -> SERIAL_GET_TIMEOUTS read timeout %d %d %d\n", - pser_inf->read_interval_timeout, - pser_inf->read_total_timeout_multiplier, - pser_inf->read_total_timeout_constant)); + logger(Protocol, Debug, + "serial_device_control(), get timeouts, timeout=%d, multiplier=%d, constant=%d", + pser_inf->read_interval_timeout, + pser_inf->read_total_timeout_multiplier, + pser_inf->read_total_timeout_constant); out_uint32(out, pser_inf->read_interval_timeout); out_uint32(out, pser_inf->read_total_timeout_multiplier); @@ -810,38 +816,38 @@ out_uint32(out, pser_inf->write_total_timeout_constant); break; case SERIAL_GET_WAIT_MASK: - DEBUG_SERIAL(("serial_ioctl -> SERIAL_GET_WAIT_MASK %X\n", - pser_inf->wait_mask)); + logger(Protocol, Debug, "serial_device_control(), get wait mask, mask=0x%x", + pser_inf->wait_mask); out_uint32(out, pser_inf->wait_mask); break; case SERIAL_SET_WAIT_MASK: in_uint32(in, pser_inf->wait_mask); - DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_WAIT_MASK %X\n", - pser_inf->wait_mask)); + logger(Protocol, Debug, "serial_device_control(), set wait mask, mask=0x%x", + pser_inf->wait_mask); break; case SERIAL_SET_DTR: - DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_DTR\n")); + logger(Protocol, Debug, "serial_device_control(), set dtr"); ioctl(handle, TIOCMGET, &result); result |= TIOCM_DTR; ioctl(handle, TIOCMSET, &result); pser_inf->dtr = 1; break; case SERIAL_CLR_DTR: - DEBUG_SERIAL(("serial_ioctl -> SERIAL_CLR_DTR\n")); + logger(Protocol, Debug, "serial_device_control(), clear dtr"); ioctl(handle, TIOCMGET, &result); result &= ~TIOCM_DTR; ioctl(handle, TIOCMSET, &result); pser_inf->dtr = 0; break; case SERIAL_SET_RTS: - DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_RTS\n")); + logger(Protocol, Debug, "serial_device_control(), set rts"); ioctl(handle, TIOCMGET, &result); result |= TIOCM_RTS; ioctl(handle, TIOCMSET, &result); pser_inf->rts = 1; break; case SERIAL_CLR_RTS: - DEBUG_SERIAL(("serial_ioctl -> SERIAL_CLR_RTS\n")); + logger(Protocol, Debug, "serial_device_control(), clear rts"); ioctl(handle, TIOCMGET, &result); result &= ~TIOCM_RTS; ioctl(handle, TIOCMSET, &result); @@ -864,7 +870,8 @@ if (result & TIOCM_RTS) modemstate |= SERIAL_MS_RTS; #endif - DEBUG_SERIAL(("serial_ioctl -> SERIAL_GET_MODEMSTATUS %X\n", modemstate)); + logger(Protocol, Debug, + "serial_device_control(), get modem status, state=0x%x", modemstate); out_uint32_le(out, modemstate); break; case SERIAL_GET_COMMSTATUS: @@ -877,8 +884,9 @@ #endif out_uint32_le(out, result); /* Amount in in queue */ if (result) - DEBUG_SERIAL(("serial_ioctl -> SERIAL_GET_COMMSTATUS in queue %d\n", - result)); + logger(Protocol, Debug, + "serial_device_control(), get comm status, %d bytes in input queue", + result); result = 0; #ifdef TIOCOUTQ @@ -886,14 +894,17 @@ #endif out_uint32_le(out, result); /* Amount in out queue */ if (result) - DEBUG_SERIAL(("serial_ioctl -> SERIAL_GET_COMMSTATUS out queue %d\n", result)); + logger(Protocol, Debug, + "serial_device_control(), get comm status, %d bytes in output queue", + result); out_uint8(out, 0); /* EofReceived */ out_uint8(out, 0); /* WaitForImmediate */ break; case SERIAL_PURGE: in_uint32(in, purge_mask); - DEBUG_SERIAL(("serial_ioctl -> SERIAL_PURGE purge_mask %X\n", purge_mask)); + logger(Protocol, Debug, "serial_device_control(), purge, mask=0x%x", + purge_mask); if ((purge_mask & SERIAL_PURGE_TXCLEAR) && (purge_mask & SERIAL_PURGE_RXCLEAR)) tcflush(handle, TCIOFLUSH); @@ -907,36 +918,38 @@ rdpdr_abort_io(handle, 3, RD_STATUS_CANCELLED); break; case SERIAL_WAIT_ON_MASK: - DEBUG_SERIAL(("serial_ioctl -> SERIAL_WAIT_ON_MASK %X\n", - pser_inf->wait_mask)); + logger(Protocol, Debug, "serial_device_control(), wait on mask, mask=0x%x", + pser_inf->wait_mask); pser_inf->event_pending = 1; if (serial_get_event(handle, &result)) { - DEBUG_SERIAL(("WAIT end event = %x\n", result)); + logger(Protocol, Debug, + "serial_device_control(), wait end, event=0x%x", result); out_uint32_le(out, result); break; } return RD_STATUS_PENDING; break; case SERIAL_SET_BREAK_ON: - DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_BREAK_ON\n")); + logger(Protocol, Debug, "serial_device_control(), set break on"); tcsendbreak(handle, 0); break; case SERIAL_RESET_DEVICE: - DEBUG_SERIAL(("serial_ioctl -> SERIAL_RESET_DEVICE\n")); + logger(Protocol, Debug, "serial_device_control(), reset device"); break; case SERIAL_SET_BREAK_OFF: - DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_BREAK_OFF\n")); + logger(Protocol, Debug, "serial_device_control(), set break off"); break; case SERIAL_SET_XOFF: - DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_XOFF\n")); + logger(Protocol, Debug, "serial_device_control(), set xoff"); break; case SERIAL_SET_XON: - DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_XON\n")); + logger(Protocol, Debug, "serial_device_control(), set xon"); tcflow(handle, TCION); break; default: - unimpl("SERIAL IOCTL %d\n", request); + logger(Protocol, Warning, "serial_device_control(), unhandled ioctl %d", + request); return RD_STATUS_INVALID_PARAMETER; } @@ -963,13 +976,14 @@ if (bytes > 0) { - DEBUG_SERIAL(("serial_get_event Bytes %d\n", bytes)); + logger(Protocol, Debug, "serial_get_event(), %d bytes", bytes); if (bytes > pser_inf->event_rlsd) { pser_inf->event_rlsd = bytes; if (pser_inf->wait_mask & SERIAL_EV_RLSD) { - DEBUG_SERIAL(("Event -> SERIAL_EV_RLSD \n")); + logger(Protocol, Debug, + "serial_get_event(), SERIAL_EV_RLSD is set"); *result |= SERIAL_EV_RLSD; ret = True; } @@ -978,13 +992,15 @@ if ((bytes > 1) && (pser_inf->wait_mask & SERIAL_EV_RXFLAG)) { - DEBUG_SERIAL(("Event -> SERIAL_EV_RXFLAG Bytes %d\n", bytes)); + logger(Protocol, Debug, + "serial_get_event(), SERIAL_EV_RXFLAG is set, %d bytes", bytes); *result |= SERIAL_EV_RXFLAG; ret = True; } if ((pser_inf->wait_mask & SERIAL_EV_RXCHAR)) { - DEBUG_SERIAL(("Event -> SERIAL_EV_RXCHAR Bytes %d\n", bytes)); + logger(Protocol, Debug, + "serial_get_event(), SERIAL_EV_RXCHAR is set, %d bytes", bytes); *result |= SERIAL_EV_RXCHAR; ret = True; } @@ -1001,8 +1017,7 @@ if ((bytes == 0) && (pser_inf->event_txempty > 0) && (pser_inf->wait_mask & SERIAL_EV_TXEMPTY)) { - - DEBUG_SERIAL(("Event -> SERIAL_EV_TXEMPTY\n")); + logger(Protocol, Debug, "serial_get_event(), SERIAL_EV_TXEMPT is set"); *result |= SERIAL_EV_TXEMPTY; ret = True; } @@ -1015,8 +1030,8 @@ pser_inf->event_dsr = bytes & TIOCM_DSR; if (pser_inf->wait_mask & SERIAL_EV_DSR) { - DEBUG_SERIAL(("event -> SERIAL_EV_DSR %s\n", - (bytes & TIOCM_DSR) ? "ON" : "OFF")); + logger(Protocol, Debug, "serial_get_event(), SERIAL_EV_DSR=%s", + (bytes & TIOCM_DSR) ? "ON" : "OFF"); *result |= SERIAL_EV_DSR; ret = True; } @@ -1027,8 +1042,8 @@ pser_inf->event_cts = bytes & TIOCM_CTS; if (pser_inf->wait_mask & SERIAL_EV_CTS) { - DEBUG_SERIAL((" EVENT-> SERIAL_EV_CTS %s\n", - (bytes & TIOCM_CTS) ? "ON" : "OFF")); + logger(Protocol, Debug, "serial_get_event(), SERIAL_EV_CTS=%s", + (bytes & TIOCM_CTS) ? "ON" : "OFF"); *result |= SERIAL_EV_CTS; ret = True; } @@ -1040,7 +1055,7 @@ return ret; } -/* Read timeout for a given file descripter (device) when adding fd's to select() */ +/* Read timeout for a given file descriptor (device) when adding FDs to select() */ RD_BOOL serial_get_timeout(RD_NTHANDLE handle, uint32 length, uint32 * timeout, uint32 * itv_timeout) { diff -Nru rdesktop-1.8.6/ssl.c rdesktop-1.9.0/ssl.c --- rdesktop-1.8.6/ssl.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/ssl.c 2019-09-19 10:34:03.000000000 +0000 @@ -3,7 +3,8 @@ Secure sockets abstraction layer Copyright (C) Matthew Chapman <matthewc.unsw.edu.au> 1999-2008 Copyright (C) Jay Sorg <j@american-data.com> 2006-2008 - Copyright (C) Henrik Andersson <hean01@cendio.com> 2016 + Copyright 2016-2017 Henrik Andersson <hean01@cendio.se> for Cendio AB + Copyright 2017 Alexander Zakharov <uglym8@gmail.com> 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 @@ -21,176 +22,248 @@ #include "rdesktop.h" #include "ssl.h" +#include "asn.h" + +#include <gnutls/x509.h> void rdssl_sha1_init(RDSSL_SHA1 * sha1) { - SHA1_Init(sha1); + sha1_init(sha1); } void rdssl_sha1_update(RDSSL_SHA1 * sha1, uint8 * data, uint32 len) { - SHA1_Update(sha1, data, len); + sha1_update(sha1, len, data); } void rdssl_sha1_final(RDSSL_SHA1 * sha1, uint8 * out_data) { - SHA1_Final(out_data, sha1); + sha1_digest(sha1, SHA1_DIGEST_SIZE, out_data); } void rdssl_md5_init(RDSSL_MD5 * md5) { - MD5_Init(md5); + md5_init(md5); } void rdssl_md5_update(RDSSL_MD5 * md5, uint8 * data, uint32 len) { - MD5_Update(md5, data, len); + md5_update(md5, len, data); } void rdssl_md5_final(RDSSL_MD5 * md5, uint8 * out_data) { - MD5_Final(out_data, md5); + md5_digest(md5, MD5_DIGEST_SIZE, out_data); } void rdssl_rc4_set_key(RDSSL_RC4 * rc4, uint8 * key, uint32 len) { - RC4_set_key(rc4, len, key); + arcfour_set_key(rc4, len, key); } void rdssl_rc4_crypt(RDSSL_RC4 * rc4, uint8 * in_data, uint8 * out_data, uint32 len) { - RC4(rc4, len, in_data, out_data); -} - -static void -reverse(uint8 * p, int len) -{ - int i, j; - uint8 temp; - - for (i = 0, j = len - 1; i < j; i++, j--) - { - temp = p[i]; - p[i] = p[j]; - p[j] = temp; - } + arcfour_crypt(rc4, len, out_data, in_data); } void rdssl_rsa_encrypt(uint8 * out, uint8 * in, int len, uint32 modulus_size, uint8 * modulus, uint8 * exponent) { - BN_CTX *ctx; - BIGNUM *mod, *exp, *x, *y; - uint8 inr[SEC_MAX_MODULUS_SIZE]; - int outlen; - - reverse(modulus, modulus_size); - reverse(exponent, SEC_EXPONENT_SIZE); - memcpy(inr, in, len); - reverse(inr, len); - - ctx = BN_CTX_new(); - mod = BN_new(); - exp = BN_new(); - x = BN_new(); - y = BN_new(); - - BN_bin2bn(modulus, 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); + mpz_t exp, mod; + + mpz_t y; + mpz_t x; + + size_t outlen; + + mpz_init(y); + mpz_init(x); + mpz_init(exp); + mpz_init(mod); + + mpz_import(mod, modulus_size, -1, sizeof(modulus[0]), 0, 0, modulus); + mpz_import(exp, SEC_EXPONENT_SIZE, -1, sizeof(exponent[0]), 0, 0, exponent); + + mpz_import(x, len, -1, sizeof(in[0]), 0, 0, in); + + mpz_powm(y, x, exp, mod); + + mpz_export(out, &outlen, -1, sizeof(out[0]), 0, 0, y); + + mpz_clear(y); + mpz_clear(x); + mpz_clear(exp); + mpz_clear(mod); + if (outlen < (int) modulus_size) memset(out + outlen, 0, modulus_size - outlen); - - BN_free(y); - BN_clear_free(x); - BN_free(exp); - BN_free(mod); - BN_CTX_free(ctx); } /* returns newly allocated RDSSL_CERT or NULL */ RDSSL_CERT * rdssl_cert_read(uint8 * data, uint32 len) { - /* this will move the data pointer but we don't care, we don't use it again */ - return d2i_X509(NULL, (D2I_X509_CONST unsigned char **) &data, len); + int ret; + gnutls_datum_t cert_data; + gnutls_x509_crt_t *cert; + + cert = malloc(sizeof(*cert)); + + if (!cert) { + logger(Protocol, Error, "%s:%s:%d: Failed to allocate memory for certificate structure.\n", + __FILE__, __func__, __LINE__); + return NULL; + } + + if ((ret = gnutls_x509_crt_init(cert)) != GNUTLS_E_SUCCESS) { + logger(Protocol, Error, "%s:%s:%d: Failed to init certificate structure. GnuTLS error = 0x%02x (%s)\n", + __FILE__, __func__, __LINE__, ret, gnutls_strerror(ret)); + + return NULL; + } + + cert_data.size = len; + cert_data.data = data; + + if ((ret = gnutls_x509_crt_import(*cert, &cert_data, GNUTLS_X509_FMT_DER)) != GNUTLS_E_SUCCESS) { + logger(Protocol, Error, "%s:%s:%d: Failed to import DER encoded certificate. GnuTLS error = 0x%02x (%s)\n", + __FILE__, __func__, __LINE__, ret, gnutls_strerror(ret)); + return NULL; + } + + return cert; } void rdssl_cert_free(RDSSL_CERT * cert) { - X509_free(cert); + gnutls_x509_crt_deinit(*cert); + free(cert); } + +/* + * AFAIK, there's no way to alter the decoded certificate using GnuTLS. + * + * Upon detecting "problem" (wrong public RSA key OID) certificate + * we basically have two options: + * + * 1)) encode certificate back to DER, then parse it using libtasn1, + * fix public key OID (set it to 1.2.840.113549.1.1.1), encode to DER again + * and finally reparse using GnuTLS + * + * 2) encode cert back to DER, get RSA public key parameters using libtasn1 + * + * Or can rewrite the whole certificate related stuff later. + */ + /* returns newly allocated RDSSL_RKEY or NULL */ RDSSL_RKEY * rdssl_cert_to_rkey(RDSSL_CERT * cert, uint32 * key_len) { - EVP_PKEY *epk = NULL; - RDSSL_RKEY *lkey; - int nid; int ret; + RDSSL_RKEY *pkey; + gnutls_datum_t m, e; + + unsigned int algo, bits; + char oid[64]; + size_t oid_size = sizeof(oid); + + uint8_t data[2048]; + size_t len; + + algo = gnutls_x509_crt_get_pk_algorithm(*cert, &bits); + /* 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. */ + Kudos to Richard Levitte for the finding this and proposed the fix + using OpenSSL. */ - X509_PUBKEY *key = NULL; - X509_ALGOR *algor = NULL; + if (algo == GNUTLS_PK_RSA) { - key = X509_get_X509_PUBKEY(cert); - if (key == NULL) - { - error("Failed to get public key from certificate.\n"); + if ((ret = gnutls_x509_crt_get_pk_rsa_raw(*cert, &m, &e)) != GNUTLS_E_SUCCESS) { + logger(Protocol, Error, "%s:%s:%d: Failed to get RSA public key parameters from certificate. GnuTLS error = 0x%02x (%s)\n", + __FILE__, __func__, __LINE__, ret, gnutls_strerror(ret)); + return NULL; + } + + } else if (algo == GNUTLS_E_UNIMPLEMENTED_FEATURE) { + + len = sizeof(data); + if ((ret = gnutls_x509_crt_export(*cert, GNUTLS_X509_FMT_DER, data, &len)) != GNUTLS_E_SUCCESS) { + logger(Protocol, Error, "%s:%s:%d: Failed to encode X.509 certificate to DER. GnuTLS error = 0x%02x (%s)\n", + __FILE__, __func__, __LINE__, ret, gnutls_strerror(ret)); + return NULL; + } + + /* Validate public key algorithm as OID_SHA_WITH_RSA_SIGNATURE + or OID_MD5_WITH_RSA_SIGNATURE + */ + if ((ret = libtasn_read_cert_pk_oid(data, len, oid, &oid_size)) != 0) { + logger(Protocol, Error, "%s:%s:%d: Failed to get OID of public key algorithm.\n", + __FILE__, __func__, __LINE__); + return NULL; + } + + if (!(strncmp(oid, OID_SHA_WITH_RSA_SIGNATURE, strlen(OID_SHA_WITH_RSA_SIGNATURE)) == 0 + || strncmp(oid, OID_MD5_WITH_RSA_SIGNATURE, strlen(OID_MD5_WITH_RSA_SIGNATURE)) == 0)) + { + logger(Protocol, Error, "%s:%s:%d: Wrong public key algorithm algo = 0x%02x (%s)\n", + __FILE__, __func__, __LINE__, algo, oid); + return NULL; + } + + /* Get public key parameters */ + if ((ret = libtasn_read_cert_pk_parameters(data, len, &m, &e)) != 0) { + logger(Protocol, Error, "%s:%s:%d: Failed to read RSA public key parameters\n", + __FILE__, __func__, __LINE__); + + return NULL; + } + + } else { + logger(Protocol, Error, "%s:%s:%d: Failed to get public key algorithm from certificate. algo = 0x%02x (%d)\n", + __FILE__, __func__, __LINE__, algo, algo); return NULL; } - ret = X509_PUBKEY_get0_param(NULL, NULL, 0, &algor, key); - if (ret != 1) - { - error("Faild to get algorithm used for public key.\n"); + pkey = malloc(sizeof(*pkey)); + + if (!pkey) { + logger(Protocol, Error, "%s:%s:%d: Failed to allocate memory for RSA public key\n", + __FILE__, __func__, __LINE__); return NULL; } - nid = OBJ_obj2nid(algor->algorithm); + rsa_public_key_init(pkey); - if ((nid == NID_md5WithRSAEncryption) || (nid == NID_shaWithRSAEncryption)) - { - DEBUG_RDP5(("Re-setting algorithm type to RSA in server certificate\n")); - X509_PUBKEY_set0_param(key, OBJ_nid2obj(NID_rsaEncryption), - 0, NULL, NULL, 0); - } - epk = X509_get_pubkey(cert); - if (NULL == epk) - { - error("Failed to extract public key from certificate\n"); - return NULL; - } + mpz_import(pkey->n, m.size, 1, sizeof(m.data[0]), 0, 0, m.data); + mpz_import(pkey->e, e.size, 1, sizeof(e.data[0]), 0, 0, e.data); + + rsa_public_key_prepare(pkey); + + *key_len = pkey->size; - lkey = RSAPublicKey_dup(EVP_PKEY_get1_RSA(epk)); - EVP_PKEY_free(epk); - *key_len = RSA_size(lkey); - return lkey; + return pkey; } /* returns boolean */ RD_BOOL rdssl_certs_ok(RDSSL_CERT * server_cert, RDSSL_CERT * cacert) { + UNUSED(server_cert); + UNUSED(cacert); /* Currently, we don't use the CA Certificate. FIXME: *) Verify the server certificate (server_cert) with the @@ -206,41 +279,58 @@ int rdssl_cert_print_fp(FILE * fp, RDSSL_CERT * cert) { - return X509_print_fp(fp, cert); + int ret; + gnutls_datum_t cinfo; + + ret = gnutls_x509_crt_print(*cert, GNUTLS_CRT_PRINT_ONELINE, &cinfo); + + if (ret == 0) { + fprintf (fp, "\t%s\n", cinfo.data); + gnutls_free(cinfo.data); + } + + return 0; } void rdssl_rkey_free(RDSSL_RKEY * rkey) { - RSA_free(rkey); + rsa_public_key_clear(rkey); + free(rkey); } +/* Actually we can get rid of this function and use rsa_public)_key in rdssl_rsa_encrypt */ /* returns error */ int rdssl_rkey_get_exp_mod(RDSSL_RKEY * rkey, uint8 * exponent, uint32 max_exp_len, uint8 * modulus, uint32 max_mod_len) { - int len; - - BIGNUM *e = NULL; - BIGNUM *n = NULL; + size_t outlen; -#if OPENSSL_VERSION_NUMBER < 0x10100000L - e = rkey->e; - n = rkey->n; -#else - RSA_get0_key(rkey, &e, &n, NULL); -#endif - - if ((BN_num_bytes(e) > (int) max_exp_len) || - (BN_num_bytes(n) > (int) max_mod_len)) - { + outlen = (mpz_sizeinbase(modulus, 2) + 7) / 8; + if (outlen > max_mod_len) return 1; - } - len = BN_bn2bin(e, exponent); - reverse(exponent, len); - len = BN_bn2bin(n, modulus); - reverse(modulus, len); + outlen = (mpz_sizeinbase(exponent, 2) + 7) / 8; + if (outlen > max_exp_len) + return 1; + + mpz_export(modulus, &outlen, -1, sizeof(uint8), 0, 0, rkey->n); + mpz_export(exponent, &outlen, -1, sizeof(uint8), 0, 0, rkey->e); + + /* + * Note that gnutls_x509_crt_get_pk_rsa_raw() exports modulus with additional + * zero byte as signed bignum. We can easily import this value using mpz_import() + * After we use mpz_export() on pkey.n (modulus) it will (according to GMP docs) + * export data without sign byte. + * + * This is only important if you get modulus from certificate using GnuTLS, + * save it somewhere, import it into mpz and then export it from the said mpz to some + * buffer. If you then compare initiail (saved) modulus with newly exported one they + * will be different. + * + * On the other hand if we use mpz_t all the way, there will be no such situation. + */ + return 0; } @@ -249,6 +339,12 @@ rdssl_sig_ok(uint8 * exponent, uint32 exp_len, uint8 * modulus, uint32 mod_len, uint8 * signature, uint32 sig_len) { + UNUSED(exponent); + UNUSED(exp_len); + UNUSED(modulus); + UNUSED(mod_len); + UNUSED(signature); + UNUSED(sig_len); /* Currently, we don't check the signature FIXME: */ @@ -260,5 +356,9 @@ rdssl_hmac_md5(const void *key, int key_len, const unsigned char *msg, int msg_len, unsigned char *md) { - HMAC(EVP_md5(), key, key_len, msg, msg_len, md, NULL); + struct hmac_md5_ctx ctx; + + hmac_md5_set_key(&ctx, key_len, key); + hmac_md5_update(&ctx, msg_len, msg); + hmac_md5_digest(&ctx, MD5_DIGEST_SIZE, md); } diff -Nru rdesktop-1.8.6/ssl.h rdesktop-1.9.0/ssl.h --- rdesktop-1.8.6/ssl.h 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/ssl.h 2019-09-20 06:39:29.000000000 +0000 @@ -3,6 +3,8 @@ Secure sockets abstraction layer Copyright (C) Matthew Chapman 1999-2008 Copyright (C) Jay Sorg 2006-2008 + Copyright 2017 Henrik Andersson <hean01@cendio.se> for Cendio AB + Copyright 2017 Alexander Zakharov <uglym8@gmail.com> 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 @@ -21,24 +23,19 @@ #ifndef _RDSSL_H #define _RDSSL_H -#include <openssl/rc4.h> -#include <openssl/md5.h> -#include <openssl/sha.h> -#include <openssl/bn.h> -#include <openssl/x509v3.h> -#include <openssl/hmac.h> - -#if defined(OPENSSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER >= 0x0090800f) -#define D2I_X509_CONST const -#else -#define D2I_X509_CONST -#endif - -#define RDSSL_RC4 RC4_KEY -#define RDSSL_SHA1 SHA_CTX -#define RDSSL_MD5 MD5_CTX -#define RDSSL_CERT X509 -#define RDSSL_RKEY RSA +#include <nettle/md5.h> +#include <nettle/sha1.h> +#include <nettle/arcfour.h> +#include <nettle/hmac.h> +#include <nettle/rsa.h> + +#include <gnutls/x509.h> + +#define RDSSL_RC4 struct arcfour_ctx +#define RDSSL_SHA1 struct sha1_ctx +#define RDSSL_MD5 struct md5_ctx +#define RDSSL_CERT gnutls_x509_crt_t +#define RDSSL_RKEY struct rsa_public_key void rdssl_sha1_init(RDSSL_SHA1 * sha1); void rdssl_sha1_update(RDSSL_SHA1 * sha1, uint8 * data, uint32 len); @@ -63,5 +60,4 @@ void rdssl_hmac_md5(const void *key, int key_len, const unsigned char *msg, int msg_len, unsigned char *md); - #endif diff -Nru rdesktop-1.8.6/stream.c rdesktop-1.9.0/stream.c --- rdesktop-1.8.6/stream.c 1970-01-01 00:00:00.000000000 +0000 +++ rdesktop-1.9.0/stream.c 2019-06-13 12:10:15.000000000 +0000 @@ -0,0 +1,209 @@ +/* + rdesktop: A Remote Desktop Protocol client. + Parsing primitives + Copyright 2017 Henrik Andersson <hean01@cendio.se> for Cendio AB + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include <errno.h> +#include <iconv.h> +#include <stdlib.h> + +#include "rdesktop.h" + +extern char g_codepage[16]; + +STREAM +s_alloc(unsigned int size) +{ + STREAM s; + + s = xmalloc(sizeof(struct stream)); + memset(s, 0, sizeof(struct stream)); + s_realloc(s, size); + + return s; +} + +STREAM +s_inherit(unsigned char *data, unsigned int size) +{ + STREAM s; + + s = xmalloc(sizeof(struct stream)); + memset(s, 0, sizeof(struct stream)); + s->p = s->data = data; + s->size = size; + + return s; +} + +void +s_realloc(STREAM s, unsigned int size) +{ + unsigned char *data; + + if (s->size >= size) + return; + + data = s->data; + s->size = size; + s->data = xrealloc(data, size); + s->p = s->data + (s->p - data); + s->end = s->data + (s->end - data); + s->iso_hdr = s->data + (s->iso_hdr - data); + s->mcs_hdr = s->data + (s->mcs_hdr - data); + s->sec_hdr = s->data + (s->sec_hdr - data); + s->rdp_hdr = s->data + (s->rdp_hdr - data); + s->channel_hdr = s->data + (s->channel_hdr - data); +} + +void +s_reset(STREAM s) +{ + struct stream tmp; + tmp = *s; + memset(s, 0, sizeof(struct stream)); + s->size = tmp.size; + s->end = s->p = s->data = tmp.data; +} + + +void +s_free(STREAM s) +{ + if (s == NULL) + return; + free(s->data); + free(s); +} + +static iconv_t +local_to_utf16() +{ + iconv_t icv; + icv = iconv_open(WINDOWS_CODEPAGE, g_codepage); + if (icv == (iconv_t) - 1) + { + logger(Core, Error, "locale_to_utf16(), iconv_open[%s -> %s] fail %p", + g_codepage, WINDOWS_CODEPAGE, icv); + abort(); + } + return icv; +} + +/* Writes a utf16 encoded string into stream excluding null termination. + This function assumes that input is ASCII compatible, such as UTF-8. + */ +static inline size_t +_out_utf16s(STREAM s, size_t maxlength, const char *string) +{ + static iconv_t icv_local_to_utf16; + size_t bl, ibl, obl; + const char *pin; + char *pout; + + if (string == NULL) + return 0; + + if (!icv_local_to_utf16) + { + icv_local_to_utf16 = local_to_utf16(); + } + + ibl = strlen(string); + obl = maxlength ? maxlength : (size_t) s_left(s); + pin = string; + pout = (char *) s->p; + + if (iconv(icv_local_to_utf16, (char **) &pin, &ibl, &pout, &obl) == (size_t) - 1) + { + logger(Protocol, Error, "out_utf16s(), iconv(2) fail, errno %d", errno); + abort(); + } + + bl = (unsigned char *) pout - s->p; + + s->p = (unsigned char *) pout; + + return bl; +} + +/* Writes a utf16 encoded string into stream including a null + termination. The length is fixed and defined by width. If result is + longer than specified width, the string is truncated. pad, + specifies a character to pad with. +*/ +void +out_utf16s_padded(STREAM s, const char *string, size_t length, unsigned char pad) +{ + size_t i, bl; + bl = _out_utf16s(s, length - 2, string); + + // append utf16 null termination + out_uint16(s, 0); + bl += 2; + + for (i = 0; i < (length - bl); i++) + out_uint8(s, pad); +} + +/* Writes a utf16 encoded string into stream including a null + termination. +*/ +void +out_utf16s(STREAM s, const char *string) +{ + _out_utf16s(s, 0, string); + + // append utf16 null termination + out_uint16(s, 0); +} + + +/* Writes a utf16 encoded string into stream excluding null + termination. */ +void +out_utf16s_no_eos(STREAM s, const char *string) +{ + _out_utf16s(s, 0, string); +} + +/* Read bytes from STREAM s into *string until a null terminator is + found, or len bytes are read from the stream. Returns the number of + bytes read. */ +size_t +in_ansi_string(STREAM s, char *string, size_t len) +{ + char *ps; + size_t left; + ps = string; + + left = len; + while (left--) + { + if (left == 0) + break; + + in_uint8(s, *ps); + + if (*ps == '\0') + break; + + ps++; + } + + return len - left; +} diff -Nru rdesktop-1.8.6/stream.h rdesktop-1.9.0/stream.h --- rdesktop-1.8.6/stream.h 1970-01-01 00:00:00.000000000 +0000 +++ rdesktop-1.9.0/stream.h 2019-06-13 12:10:15.000000000 +0000 @@ -0,0 +1,175 @@ +/* + rdesktop: A Remote Desktop Protocol client. + Parsing primitives + Copyright (C) Matthew Chapman 1999-2008 + Copyright 2012-2017 Henrik Andersson <hean01@cendio.se> for Cendio AB + Copyright 2017 Alexander Zakharov <uglym8@gmail.com> + Copyright 2019 Karl Mikaelsson <derfian@cendio.se> for Cendio AB + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _STREAM_H +#define _STREAM_H + +/* Parser state */ +typedef struct stream +{ + unsigned char *p; + unsigned char *end; + unsigned char *data; + unsigned int size; + + /* Offsets of various headers */ + unsigned char *iso_hdr; + unsigned char *mcs_hdr; + unsigned char *sec_hdr; + unsigned char *rdp_hdr; + unsigned char *channel_hdr; + +} + *STREAM; + +/* Return a newly allocated STREAM object of the specified size */ +STREAM s_alloc(unsigned int size); +/* Wrap an existing buffer in a STREAM object, transferring ownership */ +STREAM s_inherit(unsigned char *data, unsigned int size); +/* Resize an existing STREAM object, keeping all data and offsets intact */ +void s_realloc(STREAM s, unsigned int size); +/* Free STREAM object and its associated buffer */ +void s_free(STREAM s); +/* Reset all internal offsets, but keep the allocated size */ +void s_reset(STREAM s); + +void out_utf16s(STREAM s, const char *string); +void out_utf16s_padded(STREAM s, const char *string, size_t width, unsigned char pad); +void out_utf16s_no_eos(STREAM s, const char *string); + +size_t in_ansi_string(STREAM s, char *string, size_t len); + + +/* Store current offset as header h and skip n bytes */ +#define s_push_layer(s,h,n) { (s)->h = (s)->p; (s)->p += n; } +/* Set header h as current offset */ +#define s_pop_layer(s,h) (s)->p = (s)->h; +/* Mark current offset as end of readable data */ +#define s_mark_end(s) (s)->end = (s)->p; +/* Return current read offset in the STREAM */ +#define s_tell(s) (size_t)((s)->p - (s)->data) +/* Set current read offset in the STREAM */ +#define s_seek(s,o) (s)->p = (s)->data; s_assert_r(s,o); (s)->p += o; +/* Returns number of bytes that can still be read from STREAM */ +#define s_remaining(s) (size_t)((s)->end - (s)->p) +/* True if at least n bytes can still be read */ +#define s_check_rem(s,n) (((s)->p <= (s)->end) && ((size_t)n <= s_remaining(s))) +/* True if all data has been read */ +#define s_check_end(s) ((s)->p == (s)->end) +/* Return the total number of bytes that can be read */ +#define s_length(s) ((s)->end - (s)->data) +/* Return the number of bytes that can still be written */ +#define s_left(s) ((s)->size - (size_t)((s)->p - (s)->data)) + +/* Verify that there is enough data/space before accessing a STREAM */ +#define s_assert_r(s,n) { if (!s_check_rem(s, n)) rdp_protocol_error( "unexpected stream overrun", s); } +#define s_assert_w(s,n) { if (s_left(s) < (size_t)n) { logger(Core, Error, "%s:%d: %s(), %s", __FILE__, __LINE__, __func__, "unexpected stream overrun"); exit(0); } } + +/* Read/write an unsigned integer in little-endian order */ +#if defined(L_ENDIAN) && !defined(NEED_ALIGN) +#define in_uint16_le(s,v) { s_assert_r(s, 2); v = *(uint16 *)((s)->p); (s)->p += 2; } +#define in_uint32_le(s,v) { s_assert_r(s, 4); v = *(uint32 *)((s)->p); (s)->p += 4; } +#define in_uint64_le(s,v) { s_assert_r(s, 8); v = *(uint64 *)((s)->p); (s)->p += 8; } +#define out_uint16_le(s,v) { s_assert_w(s, 2); *(uint16 *)((s)->p) = v; (s)->p += 2; } +#define out_uint32_le(s,v) { s_assert_w(s, 4); *(uint32 *)((s)->p) = v; (s)->p += 4; } +#define out_uint64_le(s,v) { s_assert_w(s, 8); *(uint64 *)((s)->p) = v; (s)->p += 8; } +#else +#define in_uint16_le(s,v) { s_assert_r(s, 2); v = *((s)->p++); v += *((s)->p++) << 8; } +#define in_uint32_le(s,v) { s_assert_r(s, 4); in_uint16_le(s,v) \ + v += *((s)->p++) << 16; v += *((s)->p++) << 24; } +#define in_uint64_le(s,v) { s_assert_r(s, 8); in_uint32_le(s,v) \ + v += *((s)->p++) << 32; v += *((s)->p++) << 40; \ + v += *((s)->p++) << 48; v += *((s)->p++) << 56; } +#define out_uint16_le(s,v) { s_assert_w(s, 2); *((s)->p++) = (v) & 0xff; *((s)->p++) = ((v) >> 8) & 0xff; } +#define out_uint32_le(s,v) { s_assert_w(s, 4); out_uint16_le(s, (v) & 0xffff); out_uint16_le(s, ((v) >> 16) & 0xffff); } +#define out_uint64_le(s,v) { s_assert_w(s, 8); out_uint32_le(s, (v) & 0xffffffff); out_uint32_le(s, ((v) >> 32) & 0xffffffff); } +#endif + + +/* Read/write an unsigned integer in big-endian order */ +#if defined(B_ENDIAN) && !defined(NEED_ALIGN) +#define in_uint16_be(s,v) { s_assert_r(s, 2); v = *(uint16 *)((s)->p); (s)->p += 2; } +#define in_uint32_be(s,v) { s_assert_r(s, 4); v = *(uint32 *)((s)->p); (s)->p += 4; } +#define in_uint64_be(s,v) { s_assert_r(s, 8); v = *(uint64 *)((s)->p); (s)->p += 8; } +#define out_uint16_be(s,v) { s_assert_w(s, 2); *(uint16 *)((s)->p) = v; (s)->p += 2; } +#define out_uint32_be(s,v) { s_assert_w(s, 4); *(uint32 *)((s)->p) = v; (s)->p += 4; } +#define out_uint64_be(s,v) { s_assert_w(s, 8); *(uint64 *)((s)->p) = v; (s)->p += 8; } + +#define B_ENDIAN_PREFERRED +#define in_uint16(s,v) in_uint16_be(s,v) +#define in_uint32(s,v) in_uint32_be(s,v) +#define in_uint64(s,v) in_uint64_be(s,v) + +#define out_uint16(s,v) out_uint16_be(s,v) +#define out_uint32(s,v) out_uint32_be(s,v) +#define out_uint64(s,v) out_uint64_be(s,v) + +#else +#define in_uint16_be(s,v) { s_assert_r(s, 2); v = *((s)->p++); next_be(s,v); } +#define in_uint32_be(s,v) { s_assert_r(s, 4); in_uint16_be(s,v); next_be(s,v); next_be(s,v); } +#define in_uint64_be(s,v) { s_assert_r(s, 8); in_uint32_be(s,v); next_be(s,v); next_be(s,v); next_be(s,v); next_be(s,v); } +#define out_uint16_be(s,v) { s_assert_w(s, 2); *((s)->p++) = ((v) >> 8) & 0xff; *((s)->p++) = (v) & 0xff; } +#define out_uint32_be(s,v) { s_assert_w(s, 4); out_uint16_be(s, ((v) >> 16) & 0xffff); out_uint16_be(s, (v) & 0xffff); } +#define out_uint64_be(s,v) { s_assert_w(s, 8); out_uint32_be(s, ((v) >> 32) & 0xffffffff); out_uint32_be(s, (v) & 0xffffffff); } +#endif + +#ifndef B_ENDIAN_PREFERRED +#define in_uint16(s,v) in_uint16_le(s,v) +#define in_uint32(s,v) in_uint32_le(s,v) +#define in_uint64(s,v) in_uint64_le(s,v) +#define out_uint16(s,v) out_uint16_le(s,v) +#define out_uint32(s,v) out_uint32_le(s,v) +#define out_uint64(s,v) out_uint64_le(s,v) +#endif + +/* Read a single unsigned byte in v from STREAM s */ +#define in_uint8(s,v) { s_assert_r(s, 1); v = *((s)->p++); } +/* Return a pointer in v to manually read n bytes from STREAM s */ +#define in_uint8p(s,v,n) { s_assert_r(s, n); v = (s)->p; (s)->p += n; } +/* Copy n bytes from STREAM s in to array v */ +#define in_uint8a(s,v,n) { s_assert_r(s, n); memcpy(v,(s)->p,n); (s)->p += n; } +/* Skip reading n bytes in STREAM s */ +#define in_uint8s(s,n) { s_assert_r(s, n); (s)->p += n; } +/* Write a single unsigned byte from v to STREAM s */ +#define out_uint8(s,v) { s_assert_w(s, 1); *((s)->p++) = v; } +/* Return a pointer in v to manually fill in n bytes in STREAM s */ +#define out_uint8p(s,v,n) { s_assert_w(s, n); v = (s)->p; (s)->p += n; } +/* Copy n bytes from array v in to STREAM s */ +#define out_uint8a(s,v,n) { s_assert_w(s, n); memcpy((s)->p,v,n); (s)->p += n; } +/* Fill n bytes with 0:s in STREAM s */ +#define out_uint8s(s,n) { s_assert_w(s, n); memset((s)->p,0,n); (s)->p += n; } + +/* Copy n bytes from STREAM s in to STREAM v */ +#define in_uint8stream(s,v,n) { s_assert_r(s, n); out_uint8a((v), (s)->p, n); (s)->p += n; } +/* Copy n bytes in to STREAM s from STREAM v */ +#define out_uint8stream(s,v,n) in_uint8stream(v,s,n) +/* Copy the entire STREAM v (ignoring offsets) in to STREAM s */ +#define out_stream(s, v) out_uint8a(s, (v)->data, s_length((v))) + +/* Return a pointer in v to manually modify n bytes of STREAM s in place */ +#define inout_uint8p(s,v,n) { s_assert_r(s, n); s_assert_w(s, n); v = (s)->p; (s)->p += n; } + +/* Read one more byte of an unsigned big-endian integer */ +#define next_be(s,v) { s_assert_r(s, 1); v = ((v) << 8) + *((s)->p++); } + + +#endif /* _STREAM_H */ diff -Nru rdesktop-1.8.6/tcp.c rdesktop-1.9.0/tcp.c --- rdesktop-1.8.6/tcp.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/tcp.c 2019-09-20 06:57:45.000000000 +0000 @@ -3,7 +3,8 @@ Protocol services - TCP layer Copyright (C) Matthew Chapman <matthewc.unsw.edu.au> 1999-2008 Copyright 2005-2011 Peter Astrand <astrand@cendio.se> for Cendio AB - Copyright 2012-2013 Henrik Andersson <hean01@cendio.se> for Cendio AB + Copyright 2012-2019 Henrik Andersson <hean01@cendio.se> for Cendio AB + Copyright 2017-2018 Alexander Zakharov <uglym8@gmail.com> 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 @@ -23,18 +24,21 @@ #include <unistd.h> /* select read write close */ #include <sys/socket.h> /* socket connect setsockopt */ #include <sys/time.h> /* timeval */ +#include <sys/stat.h> #include <netdb.h> /* gethostbyname */ #include <netinet/in.h> /* sockaddr_in */ #include <netinet/tcp.h> /* TCP_NODELAY */ #include <arpa/inet.h> /* inet_addr */ #include <errno.h> /* errno */ +#include <assert.h> #endif -#include <openssl/ssl.h> -#include <openssl/x509.h> -#include <openssl/err.h> +#include <gnutls/gnutls.h> +#include <gnutls/x509.h> #include "rdesktop.h" +#include "ssl.h" +#include "asn.h" #ifdef _WIN32 #define socklen_t int @@ -51,16 +55,30 @@ #define INADDR_NONE ((unsigned long) -1) #endif +/* Windows' self signed certificates omit the required Digital + Signature key usage flag, and only %COMPAT makes GnuTLS ignore + that violation. */ +#define GNUTLS_PRIORITY "NORMAL:%COMPAT" + +#ifdef IPv6 +static struct addrinfo *g_server_address = NULL; +#else +struct sockaddr_in *g_server_address = NULL; +#endif + +static char *g_last_server_name = NULL; static RD_BOOL g_ssl_initialized = False; -static SSL *g_ssl = NULL; -static SSL_CTX *g_ssl_ctx = NULL; static int g_sock; static RD_BOOL g_run_ui = False; static struct stream g_in; int g_tcp_port_rdp = TCP_PORT_RDP; -extern RD_BOOL g_user_quit; + +extern RD_BOOL g_exit_mainloop; extern RD_BOOL g_network_error; extern RD_BOOL g_reconnect_loop; +extern char g_tls_version[]; + +static gnutls_session_t g_tls_session; /* wait till socket is ready to write or timeout */ static RD_BOOL @@ -93,10 +111,8 @@ void tcp_send(STREAM s) { - int ssl_err; size_t before; - int length; - int sent; + int length, sent; unsigned char *data; if (g_network_error == True) @@ -105,6 +121,7 @@ #ifdef WITH_SCARD scard_lock(SCARD_LOCK_TCP); #endif + s_seek(s, 0); while (!s_check_end(s)) @@ -113,27 +130,19 @@ length = s_remaining(s); in_uint8p(s, data, length); - if (g_ssl) - { - sent = SSL_write(g_ssl, data, length); - if (sent <= 0) - { - ssl_err = SSL_get_error(g_ssl, sent); - if (sent < 0 && (ssl_err == SSL_ERROR_WANT_READ || - ssl_err == SSL_ERROR_WANT_WRITE)) - { - tcp_can_send(g_sock, 100); - sent = 0; - } - else - { + if (g_ssl_initialized) { + sent = gnutls_record_send(g_tls_session, data, length); + if (sent <= 0) { + if (gnutls_error_is_fatal(sent)) { #ifdef WITH_SCARD scard_unlock(SCARD_LOCK_TCP); #endif - - error("SSL_write: %d (%s)\n", ssl_err, TCP_STRERROR); + logger(Core, Error, "tcp_send(), gnutls_record_send() failed with %d: %s\n", sent, gnutls_strerror(sent)); g_network_error = True; return; + } else { + tcp_can_send(g_sock, 100); + sent = 0; } } } @@ -152,8 +161,8 @@ #ifdef WITH_SCARD scard_unlock(SCARD_LOCK_TCP); #endif - - error("send: %s\n", TCP_STRERROR); + logger(Core, Error, "tcp_send(), send() failed: %s", + TCP_STRERROR); g_network_error = True; return; } @@ -174,7 +183,7 @@ { size_t before; unsigned char *data; - int rcvd = 0, ssl_err; + int rcvd = 0; if (g_network_error == True) return NULL; @@ -194,14 +203,15 @@ while (length > 0) { - if ((!g_ssl || SSL_pending(g_ssl) <= 0) && g_run_ui) + + if ((!g_ssl_initialized || (gnutls_record_check_pending(g_tls_session) <= 0)) && g_run_ui) { - if (!ui_select(g_sock)) - { - /* User quit */ - g_user_quit = True; + ui_select(g_sock); + + /* break out of recv, if request of exiting + main loop has been done */ + if (g_exit_mainloop == True) return NULL; - } } before = s_tell(s); @@ -211,33 +221,17 @@ s_seek(s, before); - if (g_ssl) - { - rcvd = SSL_read(g_ssl, data, length); - ssl_err = SSL_get_error(g_ssl, rcvd); + if (g_ssl_initialized) { + rcvd = gnutls_record_recv(g_tls_session, data, length); - if (ssl_err == SSL_ERROR_SSL) - { - if (SSL_get_shutdown(g_ssl) & SSL_RECEIVED_SHUTDOWN) - { - error("Remote peer initiated ssl shutdown.\n"); + if (rcvd < 0) { + if (gnutls_error_is_fatal(rcvd)) { + logger(Core, Error, "tcp_recv(), gnutls_record_recv() failed with %d: %s\n", rcvd, gnutls_strerror(rcvd)); + g_network_error = True; return NULL; + } else { + rcvd = 0; } - - ERR_print_errors_fp(stdout); - g_network_error = True; - return NULL; - } - - if (ssl_err == SSL_ERROR_WANT_READ || ssl_err == SSL_ERROR_WANT_WRITE) - { - rcvd = 0; - } - else if (ssl_err != SSL_ERROR_NONE) - { - error("SSL_read: %d (%s)\n", ssl_err, TCP_STRERROR); - g_network_error = True; - return NULL; } } @@ -252,14 +246,15 @@ } else { - error("recv: %s\n", TCP_STRERROR); + logger(Core, Error, "tcp_recv(), recv() failed: %s", + TCP_STRERROR); g_network_error = True; return NULL; } } else if (rcvd == 0) { - error("Connection closed\n"); + logger(Core, Error, "rcp_recv(), connection closed by peer"); return NULL; } } @@ -272,205 +267,414 @@ return s; } +/* + * Callback during handshake to verify peer certificate + */ +static int +cert_verify_callback(gnutls_session_t session) +{ + int rv; + int type; + RD_BOOL hostname_mismatch = False; + unsigned int status; + gnutls_x509_crt_t cert; + const gnutls_datum_t *cert_list; + unsigned int cert_list_size; + + /* + * verify certificate against system trust store + */ + rv = gnutls_certificate_verify_peers2(session, &status); + if (rv == GNUTLS_E_SUCCESS) + { + logger(Core, Debug, "%s(), certificate verify status flags: %x", __func__, status); + + if (status == 0) + { + /* get list of certificates */ + cert_list = NULL; + cert_list_size = 0; + + type = gnutls_certificate_type_get(session); + if (type == GNUTLS_CRT_X509) { + cert_list = gnutls_certificate_get_peers(session, &cert_list_size); + } + + if (cert_list_size > 0) + { + /* validate hostname */ + gnutls_x509_crt_init(&cert); + gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER); + if (gnutls_x509_crt_check_hostname(cert, g_last_server_name) != 0) + { + logger(Core, Debug, "%s(), certificate is valid", __func__); + return 0; + } + else + { + logger(Core, Warning, "%s(), certificate hostname mismatch", __func__); + hostname_mismatch = True; + } + } + else + { + logger(Core, Error, "%s(), failed to get certificate list for peers", __func__); + return 1; + } + } + } + + /* + * Use local store as fallback + */ + return utils_cert_handle_exception(session, status, hostname_mismatch, g_last_server_name); +} + +static void +gnutls_fatal(const char *text, int status) +{ + logger(Core, Error, "%s: %s", text, gnutls_strerror(status)); + /* TODO: Lookup if exit(1) is just plain wrong, its used here to breakout of + fallback code path for connection, eg. if TLS fails, a retry with plain + RDP is made. + */ + exit(1); +} + /* Establish a SSL/TLS 1.0 connection */ RD_BOOL tcp_tls_connect(void) { int err; - long options; + const char* priority; + gnutls_certificate_credentials_t xcred; + + /* Initialize TLS session */ if (!g_ssl_initialized) { - SSL_load_error_strings(); - SSL_library_init(); + gnutls_global_init(); + err = gnutls_init(&g_tls_session, GNUTLS_CLIENT); + if (err < 0) { + gnutls_fatal("Could not initialize GnuTLS", err); + } g_ssl_initialized = True; } - /* create process context */ - if (g_ssl_ctx == NULL) - { - g_ssl_ctx = SSL_CTX_new(TLSv1_client_method()); - if (g_ssl_ctx == NULL) - { - error("tcp_tls_connect: SSL_CTX_new() failed to create TLS v1.0 context\n"); - goto fail; - } - - options = 0; -#ifdef SSL_OP_NO_COMPRESSION - options |= SSL_OP_NO_COMPRESSION; -#endif // __SSL_OP_NO_COMPRESSION - options |= SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; - SSL_CTX_set_options(g_ssl_ctx, options); - } + /* FIXME: It is recommended to use the default priorities, but + appending things requires GnuTLS 3.6.3 */ - /* free old connection */ - if (g_ssl) - SSL_free(g_ssl); + priority = NULL; + if (g_tls_version[0] == 0) + priority = GNUTLS_PRIORITY; + else if (!strcmp(g_tls_version, "1.0")) + priority = GNUTLS_PRIORITY ":-VERS-ALL:+VERS-TLS1.0"; + else if (!strcmp(g_tls_version, "1.1")) + priority = GNUTLS_PRIORITY ":-VERS-ALL:+VERS-TLS1.1"; + else if (!strcmp(g_tls_version, "1.2")) + priority = GNUTLS_PRIORITY ":-VERS-ALL:+VERS-TLS1.2"; - /* create new ssl connection */ - g_ssl = SSL_new(g_ssl_ctx); - if (g_ssl == NULL) + if (priority == NULL) { - error("tcp_tls_connect: SSL_new() failed\n"); + logger(Core, Error, + "tcp_tls_connect(), TLS method should be 1.0, 1.1, or 1.2"); goto fail; } - if (SSL_set_fd(g_ssl, g_sock) < 1) - { - error("tcp_tls_connect: SSL_set_fd() failed\n"); - goto fail; + err = gnutls_priority_set_direct(g_tls_session, priority, NULL); + if (err < 0) { + gnutls_fatal("Could not set GnuTLS priority setting", err); } - do - { - err = SSL_connect(g_ssl); + err = gnutls_certificate_allocate_credentials(&xcred); + if (err < 0) { + gnutls_fatal("Could not allocate TLS certificate structure", err); + } + err = gnutls_credentials_set(g_tls_session, GNUTLS_CRD_CERTIFICATE, xcred); + if (err < 0) { + gnutls_fatal("Could not set TLS certificate structure", err); + } + err = gnutls_certificate_set_x509_system_trust(xcred); + if (err < 0) { + logger(Core, Error, "%s(), Could not load system trust database: %s", + __func__, gnutls_strerror(err)); } - while (SSL_get_error(g_ssl, err) == SSL_ERROR_WANT_READ); + gnutls_certificate_set_verify_function(xcred, cert_verify_callback); + gnutls_transport_set_int(g_tls_session, g_sock); + gnutls_handshake_set_timeout(g_tls_session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT); + + /* Perform the TLS handshake */ + do { + err = gnutls_handshake(g_tls_session); + } while (err < 0 && gnutls_error_is_fatal(err) == 0); + + + if (err < 0) { + + if (err == GNUTLS_E_CERTIFICATE_ERROR) + { + gnutls_fatal("Certificate error during TLS handshake", err); + } + + /* Handshake failed with unknown error, lets log */ + logger(Core, Error, "%s(), TLS handshake failed. GnuTLS error: %s", + __func__, gnutls_strerror(err)); - if (err < 0) - { - ERR_print_errors_fp(stdout); goto fail; + + } else { + char *desc; + desc = gnutls_session_get_desc(g_tls_session); + logger(Core, Verbose, "TLS Session info: %s\n", desc); + gnutls_free(desc); } return True; - fail: - if (g_ssl) - SSL_free(g_ssl); - if (g_ssl_ctx) - SSL_CTX_free(g_ssl_ctx); +fail: + + if (g_ssl_initialized) { + gnutls_deinit(g_tls_session); + // Not needed since 3.3.0 + gnutls_global_deinit(); + + g_ssl_initialized = False; + } - g_ssl = NULL; - g_ssl_ctx = NULL; return False; } -/* Get public key from server of TLS 1.0 connection */ +/* Get public key from server of TLS 1.x connection */ STREAM tcp_tls_get_server_pubkey() { - X509 *cert = NULL; - EVP_PKEY *pkey = NULL; + int ret; + unsigned int list_size; + const gnutls_datum_t *cert_list; + gnutls_x509_crt_t cert; + + unsigned int algo, bits; + gnutls_datum_t m, e; + + int pk_size; + uint8_t pk_data[1024]; - size_t len; - unsigned char *data; STREAM s = NULL; - if (g_ssl == NULL) - goto out; + cert_list = gnutls_certificate_get_peers(g_tls_session, &list_size); - cert = SSL_get_peer_certificate(g_ssl); - if (cert == NULL) - { - error("tcp_tls_get_server_pubkey: SSL_get_peer_certificate() failed\n"); + if (!cert_list) { + logger(Core, Error, "%s:%s:%d Failed to get peer's certs' list\n", __FILE__, __func__, __LINE__); goto out; } - pkey = X509_get_pubkey(cert); - if (pkey == NULL) - { - error("tcp_tls_get_server_pubkey: X509_get_pubkey() failed\n"); + if ((ret = gnutls_x509_crt_init(&cert)) != GNUTLS_E_SUCCESS) { + logger(Core, Error, "%s:%s:%d Failed to init certificate structure. GnuTLS error: %s\n", + __FILE__, __func__, __LINE__, gnutls_strerror(ret)); goto out; } - len = i2d_PublicKey(pkey, NULL); - if (len < 1) - { - error("tcp_tls_get_server_pubkey: i2d_PublicKey() failed\n"); + if ((ret = gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER)) != GNUTLS_E_SUCCESS) { + logger(Core, Error, "%s:%s:%d Failed to import DER certificate. GnuTLS error:%s\n", + __FILE__, __func__, __LINE__, gnutls_strerror(ret)); goto out; } - s = s_alloc(len); - out_uint8p(s, data, len); - i2d_PublicKey(pkey, &data); + algo = gnutls_x509_crt_get_pk_algorithm(cert, &bits); + + if (algo == GNUTLS_PK_RSA) { + if ((ret = gnutls_x509_crt_get_pk_rsa_raw(cert, &m, &e)) != GNUTLS_E_SUCCESS) { + logger(Core, Error, "%s:%s:%d Failed to get RSA public key parameters from certificate. GnuTLS error:%s\n", + __FILE__, __func__, __LINE__, gnutls_strerror(ret)); + goto out; + } + } else { + logger(Core, Error, "%s:%s:%d Peer's certificate public key algorithm is not RSA. GnuTLS error:%s\n", + __FILE__, __func__, __LINE__, gnutls_strerror(algo)); + goto out; + } + + pk_size = sizeof(pk_data); + + /* + * This key will be used further in cssp_connect() for server's key comparison. + * + * Note that we need to encode this RSA public key into PKCS#1 DER + * ATM there's no way to encode/export RSA public key to PKCS#1 using GnuTLS, + * gnutls_pubkey_export() encodes into PKCS#8. So besides fixing GnuTLS + * we can use libtasn1 for encoding. + */ + + if ((ret = write_pkcs1_der_pubkey(&m, &e, pk_data, &pk_size)) != 0) { + logger(Core, Error, "%s:%s:%d Failed to encode RSA public key to PKCS#1 DER\n", + __FILE__, __func__, __LINE__); + goto out; + } + + s = s_alloc(pk_size); + out_uint8a(s, pk_data, pk_size); s_mark_end(s); s_seek(s, 0); - out: - if (cert) - X509_free(cert); - if (pkey) - EVP_PKEY_free(pkey); +out: + if ((e.size != 0) && (e.data)) { + free(e.data); + } + + if ((m.size != 0) && (m.data)) { + free(m.data); + } + return s; } -/* Establish a connection on the TCP layer */ +/* Helper function to determine if rdesktop should resolve hostnames again or not */ +static RD_BOOL +tcp_connect_resolve_hostname(const char *server) +{ + return (g_server_address == NULL || + g_last_server_name == NULL || strcmp(g_last_server_name, server) != 0); +} + +/* Establish a connection on the TCP layer + + This function tries to avoid resolving any server address twice. The + official Windows 2008 documentation states that the windows farm name + should be a round-robin DNS entry containing all the terminal servers + in the farm. When connected to the farm address, if we look up the + address again when reconnecting (for any reason) we risk reconnecting + to a different server in the farm. +*/ + RD_BOOL tcp_connect(char *server) { socklen_t option_len; uint32 option_value; + char buf[NI_MAXHOST]; #ifdef IPv6 int n; - struct addrinfo hints, *res, *ressave; + struct addrinfo hints, *res, *addr; + struct sockaddr *oldaddr; char tcp_port_rdp_s[10]; - snprintf(tcp_port_rdp_s, 10, "%d", g_tcp_port_rdp); + if (tcp_connect_resolve_hostname(server)) + { + snprintf(tcp_port_rdp_s, 10, "%d", g_tcp_port_rdp); - memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; - if ((n = getaddrinfo(server, tcp_port_rdp_s, &hints, &res))) + if ((n = getaddrinfo(server, tcp_port_rdp_s, &hints, &res))) + { + logger(Core, Error, "tcp_connect(), getaddrinfo() failed: %s", + gai_strerror(n)); + return False; + } + } + else { - error("getaddrinfo: %s\n", gai_strerror(n)); - return False; + res = g_server_address; } - ressave = res; g_sock = -1; - while (res) + + for (addr = res; addr != NULL; addr = addr->ai_next) { - g_sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); - if (!(g_sock < 0)) + g_sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); + if (g_sock < 0) { - if (connect(g_sock, res->ai_addr, res->ai_addrlen) == 0) - break; - TCP_CLOSE(g_sock); - g_sock = -1; + logger(Core, Debug, "tcp_connect(), socket() failed: %s", TCP_STRERROR); + continue; } - res = res->ai_next; + + n = getnameinfo(addr->ai_addr, addr->ai_addrlen, buf, sizeof(buf), NULL, 0, + NI_NUMERICHOST); + if (n != 0) + { + logger(Core, Error, "tcp_connect(), getnameinfo() failed: %s", + gai_strerror(n)); + return False; + } + + logger(Core, Debug, "tcp_connect(), trying %s (%s)", server, buf); + + if (connect(g_sock, addr->ai_addr, addr->ai_addrlen) == 0) + break; + + TCP_CLOSE(g_sock); + g_sock = -1; } - freeaddrinfo(ressave); if (g_sock == -1) { - error("%s: unable to connect\n", server); + logger(Core, Error, "tcp_connect(), unable to connect to %s", server); return False; } -#else /* no IPv6 support */ + /* Save server address for later use, if we haven't already. */ - struct hostent *nslookup; - struct sockaddr_in servaddr; + if (g_server_address == NULL) + { + g_server_address = xmalloc(sizeof(struct addrinfo)); + g_server_address->ai_addr = xmalloc(sizeof(struct sockaddr_storage)); + } - if ((nslookup = gethostbyname(server)) != NULL) + if (g_server_address != addr) { - memcpy(&servaddr.sin_addr, nslookup->h_addr, sizeof(servaddr.sin_addr)); + /* don't overwrite ptr to allocated sockaddr */ + oldaddr = g_server_address->ai_addr; + memcpy(g_server_address, addr, sizeof(struct addrinfo)); + g_server_address->ai_addr = oldaddr; + + memcpy(g_server_address->ai_addr, addr->ai_addr, addr->ai_addrlen); + + g_server_address->ai_canonname = NULL; + g_server_address->ai_next = NULL; + + freeaddrinfo(res); } - else if ((servaddr.sin_addr.s_addr = inet_addr(server)) == INADDR_NONE) + +#else /* no IPv6 support */ + struct hostent *nslookup = NULL; + + if (tcp_connect_resolve_hostname(server)) { - error("%s: unable to resolve host\n", server); - return False; + if (g_server_address != NULL) + xfree(g_server_address); + g_server_address = xmalloc(sizeof(struct sockaddr_in)); + g_server_address->sin_family = AF_INET; + g_server_address->sin_port = htons((uint16) g_tcp_port_rdp); + + if ((nslookup = gethostbyname(server)) != NULL) + { + memcpy(&g_server_address->sin_addr, nslookup->h_addr, + sizeof(g_server_address->sin_addr)); + } + else if ((g_server_address->sin_addr.s_addr = inet_addr(server)) == INADDR_NONE) + { + logger(Core, Error, "tcp_connect(), unable to resolve host '%s'", server); + return False; + } } if ((g_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - error("socket: %s\n", TCP_STRERROR); + logger(Core, Error, "tcp_connect(), socket() failed: %s", TCP_STRERROR); return False; } - servaddr.sin_family = AF_INET; - servaddr.sin_port = htons((uint16) g_tcp_port_rdp); + logger(Core, Debug, "tcp_connect(), trying %s (%s)", + server, inet_ntop(g_server_address->sin_family, + &g_server_address->sin_addr, buf, sizeof(buf))); - if (connect(g_sock, (struct sockaddr *) &servaddr, sizeof(struct sockaddr)) < 0) + if (connect(g_sock, (struct sockaddr *) g_server_address, sizeof(struct sockaddr)) < 0) { if (!g_reconnect_loop) - error("connect: %s\n", TCP_STRERROR); + logger(Core, Error, "tcp_connect(), connect() failed: %s", TCP_STRERROR); TCP_CLOSE(g_sock); g_sock = -1; @@ -497,6 +701,10 @@ g_in.size = 4096; g_in.data = (uint8 *) xmalloc(g_in.size); + /* After successful connect: update the last server name */ + if (g_last_server_name) + xfree(g_last_server_name); + g_last_server_name = strdup(server); return True; } @@ -504,18 +712,21 @@ void tcp_disconnect(void) { - if (g_ssl) - { - if (!g_network_error) - (void) SSL_shutdown(g_ssl); - SSL_free(g_ssl); - g_ssl = NULL; - SSL_CTX_free(g_ssl_ctx); - g_ssl_ctx = NULL; + if (g_ssl_initialized) { + (void)gnutls_bye(g_tls_session, GNUTLS_SHUT_WR); + gnutls_deinit(g_tls_session); + // Not needed since 3.3.0 + gnutls_global_deinit(); + + g_ssl_initialized = False; } TCP_CLOSE(g_sock); g_sock = -1; + + g_in.size = 0; + xfree(g_in.data); + g_in.data = NULL; } char * @@ -550,17 +761,7 @@ tcp_reset_state(void) { /* Clear the incoming stream */ - if (g_in.data != NULL) - xfree(g_in.data); - g_in.p = NULL; - g_in.end = NULL; - g_in.data = NULL; - g_in.size = 0; - g_in.iso_hdr = NULL; - g_in.mcs_hdr = NULL; - g_in.sec_hdr = NULL; - g_in.rdp_hdr = NULL; - g_in.channel_hdr = NULL; + s_reset(&g_in); } void diff -Nru rdesktop-1.8.6/tests/brushtest.c rdesktop-1.9.0/tests/brushtest.c --- rdesktop-1.8.6/tests/brushtest.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/tests/brushtest.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,215 +0,0 @@ - -/* by Jay Sorg, public domain - for testing brush cache */ - -#include <windows.h> - -static HWND g_wnd; -static HWND g_button; -static HWND g_pulldown; - -/*****************************************************************************/ -static int WINAPI -brush_test(int selindex, int orgx, int orgy) -{ - HDC dc; - RECT rect; - HBRUSH br; - BITMAPINFO* bi; - RGBQUAD ce; - int bi_size; - int i; - int j; - UCHAR* d8; - - bi_size = sizeof(BITMAPINFO) + 15 * sizeof(RGBQUAD) + 4 * 8; - bi = malloc(bi_size); - memset(bi, 0, bi_size); - bi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bi->bmiHeader.biWidth = 8; - bi->bmiHeader.biHeight = 8; - bi->bmiHeader.biPlanes = 1; - bi->bmiHeader.biBitCount = 4; - bi->bmiHeader.biCompression = BI_RGB; - bi->bmiHeader.biSizeImage = 32; - ce.rgbBlue = 0xff; - ce.rgbGreen = 0; - ce.rgbRed = 0; - ce.rgbReserved = 0; - bi->bmiColors[0] = ce; - ce.rgbBlue = 0; - ce.rgbGreen = 0xff; - ce.rgbRed = 0; - ce.rgbReserved = 0; - bi->bmiColors[1] = ce; - ce.rgbBlue = 0; - ce.rgbGreen = 0; - ce.rgbRed = 0xff; - ce.rgbReserved = 0; - bi->bmiColors[2] = ce; - ce.rgbBlue = 0x0f; - ce.rgbGreen = 0; - ce.rgbRed = 0; - ce.rgbReserved = 0; - bi->bmiColors[3] = ce; - ce.rgbBlue = 0; - ce.rgbGreen = 0x0f; - ce.rgbRed = 0; - ce.rgbReserved = 0; - bi->bmiColors[4] = ce; - d8 = (UCHAR*)bi; - d8 = (d8 + bi_size) - 32; - if (selindex == 1) /* 2 color */ - { - d8[0] = 0x10; - } - else if (selindex == 2) /* 4 color */ - { - d8[0] = 0x12; - d8[1] = 0x33; - } - else if (selindex == 3) /* > 4 color */ - { - d8[0] = 0x12; - d8[1] = 0x34; - } - br = CreateDIBPatternBrushPt(bi, DIB_RGB_COLORS); - if (br == 0) - { - MessageBox(g_wnd, "error in CreateDIBPatternBrushPt", "error", MB_OK); - } - dc = GetDC(g_wnd); - rect.left = 100; - rect.top = 60; - rect.right = rect.left + 128; - rect.bottom = rect.top + 128; - for (j = 0; j < 128; j += 5) - { - for (i = 0; i < 128; i += 5) - { - SetBrushOrgEx(dc, orgx + i, orgy + j, 0); - FillRect(dc, &rect, br); - } - } - DeleteObject(br); - free(bi); - ReleaseDC(g_wnd, dc); - return 0; -} - -/*****************************************************************************/ -static LRESULT CALLBACK -WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - HWND hwndCtl; - int selindex; - - switch (message) - { - case WM_DESTROY: - PostQuitMessage(0); - break; - case WM_COMMAND: - hwndCtl = (HWND) lParam; - if (hwndCtl == g_button) - { - selindex = SendMessage(g_pulldown, CB_GETCURSEL, 0, 0); - if (selindex < 1) - { - MessageBox(g_wnd, "please select one", "info", MB_OK); - } - else - { - brush_test(selindex, 4, 4); - } - } - break; - } - return DefWindowProc(hWnd, message, wParam, lParam); -} - -/*****************************************************************************/ -static int WINAPI -create_window(void) -{ - WNDCLASS wc; - DWORD style; - int x; - int y; - int w; - int h; - - ZeroMemory(&wc, sizeof(wc)); - wc.lpfnWndProc = WndProc; /* points to window procedure */ - wc.lpszClassName = "brushtest"; - wc.hbrBackground = CreateSolidBrush(GetSysColor(COLOR_BTNFACE)); - wc.hCursor = LoadCursor(0, IDC_ARROW); - /* Register the window class. */ - if (!RegisterClass(&wc)) - { - return 1; /* Failed to register window class */ - } - style = WS_OVERLAPPED | WS_CAPTION | WS_POPUP | WS_MINIMIZEBOX | - WS_SYSMENU | WS_SIZEBOX | WS_MAXIMIZEBOX; - x = CW_USEDEFAULT; - y = CW_USEDEFAULT; - w = 640; - h = 480; - g_wnd = CreateWindow(wc.lpszClassName, "brushtest", - style, x, y, w, h, 0, 0, 0, 0); - /* button */ - style = WS_CHILD | WS_VISIBLE; - g_button = CreateWindow("BUTTON", "Go", style, 300, 10, 80, 24, g_wnd, - 0, 0, 0); - /* pull down */ - style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST; - g_pulldown = CreateWindow("COMBOBOX", "", style, 100, 10, 160, 150, g_wnd, - 0, 0, 0); - ShowWindow(g_wnd, SW_SHOWNORMAL); - SendMessage(g_pulldown, CB_ADDSTRING, 0, (LPARAM) (LPCTSTR) ""); - SendMessage(g_pulldown, CB_ADDSTRING, 0, (LPARAM) (LPCTSTR) "2 color test"); - SendMessage(g_pulldown, CB_ADDSTRING, 0, (LPARAM) (LPCTSTR) "4 color test"); - SendMessage(g_pulldown, CB_ADDSTRING, 0, (LPARAM) (LPCTSTR) "> 4 color test"); - return 0; -} - -/*****************************************************************************/ -static int WINAPI -main_loop(void) -{ - BOOL cont; - BOOL gmcode; - MSG msg1; - - create_window(); - cont = TRUE; - while (cont) - { - MsgWaitForMultipleObjects(0, 0, 0, INFINITE, QS_ALLINPUT); - while (cont && PeekMessage(&msg1, 0, 0, 0, PM_NOREMOVE)) - { - gmcode = GetMessage(&msg1, 0, 0, 0); - if (gmcode && (gmcode != -1)) - { - TranslateMessage(&msg1); - DispatchMessage(&msg1); - } - else - { - cont = FALSE; - } - } - } - return 0; -} - -/*****************************************************************************/ -int WINAPI -WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, - LPSTR lpCmdLine, int nCmdShow) -{ - int rv; - - rv = main_loop(); - return rv; -} Binary files /tmp/tmpZWfgXB/O87Q9cu2WM/rdesktop-1.8.6/tests/brushtest.exe and /tmp/tmpZWfgXB/E40k3bOtjZ/rdesktop-1.9.0/tests/brushtest.exe differ diff -Nru rdesktop-1.8.6/tests/brushtestMakefile rdesktop-1.9.0/tests/brushtestMakefile --- rdesktop-1.8.6/tests/brushtestMakefile 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/tests/brushtestMakefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ - -# by Jay Sorg, public domain -# borland makefile - -OBJS = brushtest.obj - -CFLAGS = -O2 -LDFLAGS = -W - -all: brushtest.exe - -brushtest.exe: $(OBJS) - $(CC) -ebrushtest.exe $(LDFLAGS) $(OBJS) - -clean: - del /q $(OBJS) brushtest.exe *.tds diff -Nru rdesktop-1.8.6/tests/notepadbehindwordpad.c rdesktop-1.9.0/tests/notepadbehindwordpad.c --- rdesktop-1.8.6/tests/notepadbehindwordpad.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/tests/notepadbehindwordpad.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -#include <windows.h> -#include <stdio.h> -#include <stdlib.h> - - - -int -main(int argc, char *argv[]) -{ - HWND notepad, wordpad; - - notepad = FindWindow("Notepad", NULL); - wordpad = FindWindow("WordPadClass", NULL); - - SetWindowPos(notepad, wordpad, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); - - return 0; -} Binary files /tmp/tmpZWfgXB/O87Q9cu2WM/rdesktop-1.8.6/tests/notepadbehindwordpad.exe and /tmp/tmpZWfgXB/E40k3bOtjZ/rdesktop-1.9.0/tests/notepadbehindwordpad.exe differ diff -Nru rdesktop-1.8.6/types.h rdesktop-1.9.0/types.h --- rdesktop-1.8.6/types.h 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/types.h 2019-06-13 12:10:15.000000000 +0000 @@ -3,6 +3,7 @@ Common data types Copyright (C) Matthew Chapman 1999-2008 Copyright 2014 Henrik Andersson <hean01@cendio.se> for Cendio AB + Copyright 2017 Karl Mikaelsson <derfian@cendio.se> for Cendio AB 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 @@ -18,6 +19,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#ifndef _TYPES_H +#define _TYPES_H + +#include <stdint.h> +#include "constants.h" +#include "stream.h" + typedef int RD_BOOL; #ifndef True @@ -25,12 +33,18 @@ #define False (0) #endif +#ifndef PATH_MAX +#define PATH_MAX 256 +#endif + typedef unsigned char uint8; typedef signed char sint8; typedef unsigned short uint16; typedef signed short sint16; typedef unsigned int uint32; typedef signed int sint32; +typedef uint64_t uint64; +typedef int64_t sint64; #define RD_UINT32_MAX (uint32)(-1) @@ -205,9 +219,9 @@ uint32 create_disposition, uint32 flags_and_attributes, char *filename, RD_NTHANDLE * handle); RD_NTSTATUS(*close) (RD_NTHANDLE handle); - RD_NTSTATUS(*read) (RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, + RD_NTSTATUS(*read) (RD_NTHANDLE handle, uint8 * data, uint32 length, uint64 offset, uint32 * result); - RD_NTSTATUS(*write) (RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, + RD_NTSTATUS(*write) (RD_NTHANDLE handle, uint8 * data, uint32 length, uint64 offset, uint32 * result); RD_NTSTATUS(*device_control) (RD_NTHANDLE handle, uint32 request, STREAM in, STREAM out); } @@ -224,6 +238,12 @@ } RDPDR_DEVICE; +typedef struct rdpdr_disk_device_info +{ + char name[PATH_MAX]; +} +DISK_DEVICE; + typedef struct rdpdr_serial_device_info { int dtr; @@ -278,10 +298,6 @@ } NOTIFY; -#ifndef PATH_MAX -#define PATH_MAX 256 -#endif - typedef struct fileinfo { uint32 device_id, flags_and_attributes, accessmask; @@ -296,3 +312,13 @@ FILEINFO; typedef RD_BOOL(*str_handle_lines_t) (const char *line, void *data); + +typedef enum +{ + Fixed, + PercentageOfScreen, + Workarea, + Fullscreen, +} window_size_type_t; + +#endif /* _TYPES_H */ diff -Nru rdesktop-1.8.6/uiports/makefile_nanox rdesktop-1.9.0/uiports/makefile_nanox --- rdesktop-1.8.6/uiports/makefile_nanox 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/uiports/makefile_nanox 1970-01-01 00:00:00.000000000 +0000 @@ -1,25 +0,0 @@ -# -# nanoxrdesktop makefile -# -# These two following lines must point to the currently installed version of -# nano-X. You can override them on the make command line to point at your -# installation without changing this file. -# -NXINCLUDES=/usr/local/nanox/src/include -NXLIBS=/usr/local/nanox/src/lib/libnano-X.a - -CC = gcc -CFLAGS = -Os -Wall -I$(NXINCLUDES) -RESTOBJ = ../tcp.o ../iso.o ../mcs.o ../secure.o ../rdp.o ../rdp5.o ../orders.o ../cache.o ../mppc.o ../licence.o ../bitmap.o ../channels.o ../pstcache.o -LDFLAGS = -lcrypto - -all: nanoxrd - -nanoxrd: $(RESTOBJ) nanoxwin.o - $(CC) -o nanoxrdesktop nanoxwin.o $(NXLIBS) $(RESTOBJ) $(LDFLAGS) - strip nanoxrdesktop - -clean: - rm -f nanoxrdesktop - rm -f *.o - rm -f ../*.o diff -Nru rdesktop-1.8.6/uiports/makefile_qt rdesktop-1.9.0/uiports/makefile_qt --- rdesktop-1.8.6/uiports/makefile_qt 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/uiports/makefile_qt 1970-01-01 00:00:00.000000000 +0000 @@ -1,86 +0,0 @@ -# -# qtrdesktop makefile -# qt should be installed in /usr/local/qt or /usr/lib/qt3 -# set QTBDIR to this location - -QTBDIR = /usr/lib/qt3 - -CC = g++ -CPPFLAGS = -O2 -Wall -I$(QTBDIR)/include -I.. -# the next line is for sound -#CPPFLAGS += -DWITH_RDPSND -RESTOBJ = tcp.o iso.o mcs.o secure.o rdp.o rdp5.o -RESTOBJ += orders.o cache.o mppc.o licence.o bitmap.o -RESTOBJ += channels.o pstcache.o ssl.o -# the next line is for sound -#RESTOBJ += rdpsnd.o rdpsnd_oss.o rdpsnd_dsp.o -LD2FLAGS = -L$(QTBDIR)/lib -L/usr/X11R6/lib -LDFLAGS = -lcrypto -lqt-mt -lXext -lX11 -lm -MOCFILE = $(QTBDIR)/bin/moc - -all: qtrd - -qtrd: $(RESTOBJ) qtwin.o - $(MOCFILE) qtwin.h > moc_qtwin.cpp - $(CC) $(CPPFLAGS) -c moc_qtwin.cpp - $(CC) -o qtrdesktop $(LD2FLAGS) qtwin.o moc_qtwin.o $(RESTOBJ) $(LDFLAGS) - strip qtrdesktop - -clean: - rm -f qtrdesktop - rm -f *.o - rm -f ../*.o - rm -f moc_qtwin.cpp - -# common files - -tcp.o: ../tcp.c - $(CC) $(CPPFLAGS) -c ../tcp.c - -iso.o: ../iso.c - $(CC) $(CPPFLAGS) -c ../iso.c - -mcs.o: ../mcs.c - $(CC) $(CPPFLAGS) -c ../mcs.c - -secure.o: ../secure.c - $(CC) $(CPPFLAGS) -c ../secure.c - -rdp.o: ../rdp.c - $(CC) $(CPPFLAGS) -c ../rdp.c - -rdp5.o: ../rdp5.c - $(CC) $(CPPFLAGS) -c ../rdp5.c - -orders.o: ../orders.c - $(CC) $(CPPFLAGS) -c ../orders.c - -cache.o: ../cache.c - $(CC) $(CPPFLAGS) -c ../cache.c - -mppc.o: ../mppc.c - $(CC) $(CPPFLAGS) -c ../mppc.c - -licence.o: ../licence.c - $(CC) $(CPPFLAGS) -c ../licence.c - -bitmap.o: ../bitmap.c - $(CC) $(CPPFLAGS) -c ../bitmap.c - -channels.o: ../channels.c - $(CC) $(CPPFLAGS) -c ../channels.c - -pstcache.o: ../pstcache.c - $(CC) $(CPPFLAGS) -c ../pstcache.c - -ssl.o: ../ssl.c - $(CC) $(CPPFLAGS) -c ../ssl.c - -rdpsnd.o: ../rdpsnd.c - $(CC) $(CPPFLAGS) -c ../rdpsnd.c - -rdpsnd_oss.o: ../rdpsnd_oss.c - $(CC) $(CPPFLAGS) -c ../rdpsnd_oss.c - -rdpsnd_dsp.o: ../rdpsnd_dsp.c - $(CC) $(CPPFLAGS) -c ../rdpsnd_dsp.c diff -Nru rdesktop-1.8.6/uiports/makefile_qte rdesktop-1.9.0/uiports/makefile_qte --- rdesktop-1.8.6/uiports/makefile_qte 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/uiports/makefile_qte 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ -# -# qterdesktop makefile -# qt should be installed in /usr/local/qt -# -CC = g++ -CPPFLAGS = -DQWS -fno-exceptions -fno-rtti -Wall -Os -Wall -I/usr/local/qt/include -DWITH_RDPSND -DNO_DEBUG -RESTOBJ = ../tcp.o ../iso.o ../mcs.o ../secure.o ../rdp.o ../rdp5.o ../orders.o ../cache.o ../mppc.o ../licence.o ../bitmap.o ../channels.o ../pstcache.o ../rdpsnd.o ../rdpsnd_oss.o -LD2FLAGS = -L/usr/local/qt/lib -LDFLAGS = -lcrypto -lqte -MOCFILE = /usr/local/qt/bin/moc - -all: qtrd - -qtrd: $(RESTOBJ) qtewin.o - $(MOCFILE) qtewin.h > moc_qtewin.cpp - $(CC) $(CPPFLAGS) -c moc_qtewin.cpp - $(CC) -o qterdesktop $(LD2FLAGS) qtewin.o moc_qtewin.o $(RESTOBJ) $(LDFLAGS) - strip qterdesktop - -clean: - rm -f qterdesktop - rm -f *.o - rm -f ../*.o - rm -f moc_qtewin.cpp diff -Nru rdesktop-1.8.6/uiports/makefile_svga rdesktop-1.9.0/uiports/makefile_svga --- rdesktop-1.8.6/uiports/makefile_svga 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/uiports/makefile_svga 1970-01-01 00:00:00.000000000 +0000 @@ -1,36 +0,0 @@ -CC = gcc -CFLAGS = -Os -DWITH_OPENSSL -DL_ENDIAN -Wall -RESTOBJ = ../tcp.o ../iso.o ../mcs.o ../secure.o ../rdp.o ../rdp5.o ../orders.o ../cache.o ../mppc.o ../licence.o ../bitmap.o ../channels.o ../pstcache.o ../ssl.o -LDFLAGS = -lvga -lcrypto - -#LDFLAGS = -lm /usr/local/lib/libvga.a /usr/lib/libcrypto.a -#LDFLAGS = -lvga /usr/lib/libcrypto.a - -all: svgard -svgard: svgawin.o $(RESTOBJ) - $(CC) -o svgardesktop svgawin.o $(RESTOBJ) $(LDFLAGS) - strip svgardesktop - -#rest: $(RESTOBJ) -#rest: tcp.o iso.o mcs.o secure.o rdp.o rdp5.o orders.o cache.o mppc.o licence.o bitmap.o channels.o pstcache.o -rest: ../tcp.c ../iso.c ../mcs.c ../secure.c ../rdp.c ../rdp5.c ../orders.c ../cache.c ../mppc.c ../licence.c ../bitmap.c ../channels.c ../pstcache.c - $(CC) $(CFLAGS) -c ../tcp.c -o ../tcp.o - $(CC) $(CFLAGS) -c ../iso.c -o ../iso.o - $(CC) $(CFLAGS) -c ../mcs.c -o ../mcs.o - $(CC) $(CFLAGS) -c ../secure.c -o ../secue.o - $(CC) $(CFLAGS) -c ../rdp.c -o ../rdp.o - $(CC) $(CFLAGS) -c ../rdp5.c -o ../rdp5.o - $(CC) $(CFLAGS) -c ../orders.c -o ../orders.o - $(CC) $(CFLAGS) -c ../cache.c -o ../cache.o - $(CC) $(CFLAGS) -c ../mppc.c -o ../mppc.o - $(CC) $(CFLAGS) -c ../licence.c -o ../licence.o - $(CC) $(CFLAGS) -c ../bitmap.c -o ../bitmap.o - $(CC) $(CFLAGS) -c ../channels.c -o ../channels.o - $(CC) $(CFLAGS) -c ../pstcache.c -o ../pstcache.o - -svgawin.o: svgawin.c - $(CC) $(CFLAGS) -c $*.c -clean: - rm -f svgardesktop - rm -f *.o - rm -f ../*.o diff -Nru rdesktop-1.8.6/uiports/makefile_xxx rdesktop-1.9.0/uiports/makefile_xxx --- rdesktop-1.8.6/uiports/makefile_xxx 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/uiports/makefile_xxx 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -# -# xxxrdesktop makefile -# -CC = gcc -CFLAGS = -O2 -Wall -RESTOBJ = ../tcp.o ../iso.o ../mcs.o ../secure.o ../rdp.o ../rdp5.o ../orders.o ../cache.o ../mppc.o ../licence.o ../bitmap.o ../channels.o ../pstcache.o ../ssl.o -LDFLAGS = -lcrypto - -all: xxxrd - -xxxrd: $(RESTOBJ) xxxwin.o - $(CC) -o xxxrdesktop xxxwin.o $(RESTOBJ) $(LDFLAGS) - strip xxxrdesktop - -clean: - rm -f xxxrdesktop - rm -f *.o - rm -f ../*.o diff -Nru rdesktop-1.8.6/uiports/nanoxreadme.txt rdesktop-1.9.0/uiports/nanoxreadme.txt --- rdesktop-1.8.6/uiports/nanoxreadme.txt 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/uiports/nanoxreadme.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,9 +0,0 @@ -This is the nanox ui port -tested with versions 0.90 - -makefile_nanox can be edited to change file localtions -run make -f makefile_nanox in this directory to compile it - -nanoxreadme.txt - notes, this file -makefile_nanox - makefile -nanoxwin.cpp - ui lib diff -Nru rdesktop-1.8.6/uiports/nanoxwin.c rdesktop-1.9.0/uiports/nanoxwin.c --- rdesktop-1.8.6/uiports/nanoxwin.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/uiports/nanoxwin.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1546 +0,0 @@ -/* -*- c-basic-offset: 8 -*- - rdesktop: A Remote Desktop Protocol client. - User interface services - NanoX(microwindows) - Copyright (C) Jay Sorg 2004-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 3 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, see <http://www.gnu.org/licenses/>. -*/ -/* - problems with nanox lib - opcodes don't work, can only rely on copy - stipple orgins don't work - clip seems to affect source too, it should only affect dest - in copyarea functions -*/ - -#include "../rdesktop.h" - -#include <stdarg.h> /* va_list va_start va_end */ -#include <unistd.h> /* gethostname */ -#include <pwd.h> /* getpwuid */ - -#include <nano-X.h> - -extern int g_tcp_port_rdp; -int g_use_rdp5 = 1; -char g_hostname[16]; -char g_username[64]; -int g_width = 800; -int g_height = 600; -int g_server_bpp = 16; -int g_encryption = 1; -int g_desktop_save = 0; /* todo */ -int g_polygon_ellipse_orders = 0; -int g_bitmap_cache = 1; -int g_bitmap_cache_persist_enable = 0; -int g_bitmap_cache_precache = 1; -int g_bitmap_compression = 1; -uint32 g_rdp5_performanceflags = - RDP5_NO_WALLPAPER | RDP5_NO_FULLWINDOWDRAG | RDP5_NO_MENUANIMATIONS; -int g_console_session = 0; -int 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 */ - -static int g_sck = 0; -static char g_servername[256] = ""; -static char g_password[64] = ""; -static char g_domain[64] = ""; -static char g_shell[64] = ""; -static char g_directory[64] = ""; -static GR_WINDOW_ID g_wnd = 0; -static GR_GC_ID g_gc = 0; -static GR_GC_ID g_gc_clean = 0; -static int g_deactivated = 0; -static int g_ext_disc_reason = 0; -static GR_SCREEN_INFO g_screen_info; -static int g_bpp = 0; -static int g_Bpp = 0; -static GR_RECT g_clip; /* set in main */ -static GR_CURSOR_ID g_null_cursor; /* set in main */ -static int g_flags = RDP_LOGON_NORMAL; - -struct key -{ - int ch1; - int ch2; - int ch3; - int chs; /* shift char */ -}; - -static struct key g_keys[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; - -#define COLOR16TO32(color) \ -( \ - ((((color >> 8) & 0xf8) | ((color >> 13) & 0x7)) << 0) | \ - ((((color >> 3) & 0xfc) | ((color >> 9) & 0x3)) << 8) | \ - ((((color << 3) & 0xf8) | ((color >> 2) & 0x7)) << 16) \ -) - -static uint32 g_ops[16] = -{ - GR_MODE_CLEAR, /* 0 */ - GR_MODE_NOR, /* ~(src | dst) */ - GR_MODE_ANDINVERTED, /* (~src) & dst */ - GR_MODE_COPYINVERTED, /* ~src */ - GR_MODE_ANDREVERSE, /* src & (~dst) */ - GR_MODE_INVERT, /* ~(dst) */ - GR_MODE_XOR, /* src ^ dst */ - GR_MODE_NAND, /* ~(src & dst) */ - GR_MODE_AND, /* src & dst */ - GR_MODE_EQUIV, /* ~(src) ^ dst or is it ~(src ^ dst) */ - GR_MODE_NOOP, /* dst */ - GR_MODE_ORINVERTED, /* (~src) | dst */ - GR_MODE_COPY, /* src */ - GR_MODE_ORREVERSE, /* src | (~dst) */ - GR_MODE_OR, /* src | dst */ - GR_MODE_SETTO1 /* ~0 */ -}; - -/*****************************************************************************/ -/* do a raster op */ -static int 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; -} - -/*****************************************************************************/ -static int get_pixel32(uint8 * data, int x, int y, - int width, int height) -{ - if (x >= 0 && y >= 0 && x < width && y < height) - { - return *(((int*)data) + (y * width + x)); - } - else - { - return 0; - } -} - -/*****************************************************************************/ -static void set_pixel32(uint8 * data, int x, int y, - int width, int height, int pixel) -{ - if (x >= 0 && y >= 0 && x < width && y < height) - { - *(((int*)data) + (y * width + x)) = pixel; - } -} - -/*****************************************************************************/ -static int warp_coords(int * x, int * y, int * cx, int * cy, - int * srcx, int * srcy) -{ - int dx; - int dy; - - if (g_clip.x > *x) - { - dx = g_clip.x - *x; - } - else - { - dx = 0; - } - if (g_clip.y > *y) - { - dy = g_clip.y - *y; - } - else - { - dy = 0; - } - if (*x + *cx > g_clip.x + g_clip.width) - { - *cx = (*cx - ((*x + *cx) - (g_clip.x + g_clip.width))); - } - if (*y + *cy > g_clip.y + g_clip.height) - { - *cy = (*cy - ((*y + *cy) - (g_clip.y + g_clip.height))); - } - *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; -} - -/******************************************************************************/ -/* check if a certain pixel is set in a bitmap */ -static int is_pixel_on(uint8 * 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 - return 0; -} - -/*****************************************************************************/ -int ui_select(int in) -{ - if (g_sck == 0) - { - g_sck = in; - } - return 1; -} - -/*****************************************************************************/ -void ui_set_clip(int x, int y, int cx, int cy) -{ - GR_REGION_ID region; - - g_clip.x = x; - g_clip.y = y; - g_clip.width = cx; - g_clip.height = cy; - region = GrNewRegion(); - GrUnionRectWithRegion(region, &g_clip); - GrSetGCRegion(g_gc, region); /* can't destroy region here, i guess gc */ - /* takes owership, if you destroy it */ - /* clip is reset, hum */ -} - -/*****************************************************************************/ -void ui_reset_clip(void) -{ - GrSetGCRegion(g_gc, 0); - g_clip.x = 0; - g_clip.y = 0; - g_clip.width = g_width; - g_clip.height = g_height; -} - -/*****************************************************************************/ -void ui_bell(void) -{ - GrBell(); -} - -/*****************************************************************************/ -/* gota convert the rdp glyph to nanox glyph */ -void * ui_create_glyph(int width, int height, uint8 * data) -{ - char * p, * q, * r; - int datasize, i, j; - - datasize = GR_BITMAP_SIZE(width, height) * sizeof(GR_BITMAP); - p = xmalloc(datasize); - q = p; - r = data; - memset(p, 0, datasize); - for (i = 0; i < height; i++) - { - j = 0; - while (j + 8 < width) - { - *q = *(r + 1); - q++; - r++; - *q = *(r - 1); - q++; - r++; - j += 16; - } - if ((width % 16) <= 8 && (width % 16) > 0) - { - q++; - *q = *r; - q++; - r++; - j += 8; - } - } - return p; -} - -/*****************************************************************************/ -void ui_destroy_glyph(void * glyph) -{ - xfree(glyph); -} - -/*****************************************************************************/ -void * ui_create_colourmap(COLOURMAP * colors) -{ - return 0; -} - -/*****************************************************************************/ -void ui_set_colourmap(void * map) -{ -} - -/*****************************************************************************/ -void * ui_create_bitmap(int width, int height, uint8 * data) -{ - GR_WINDOW_ID pixmap; - uint8 * p; - uint32 i, j, pixel; - - p = data; - pixmap = GrNewPixmap(width, height, 0); - if (g_server_bpp == 16 && g_bpp == 32) - { - p = xmalloc(width * height * g_Bpp); - for (i = 0; i < height; i++) - { - for (j = 0; j < width; j++) - { - pixel = *(((uint16 *) data) + (i * width + j)); - pixel = COLOR16TO32(pixel); - *(((uint32 *) p) + (i * width + j)) = pixel; - } - } - } - GrArea(pixmap, g_gc_clean, 0, 0, width, height, p, MWPF_RGB); - if (p != data) - { - xfree(p); - } - return (void *) pixmap; -} - -/*****************************************************************************/ -void ui_destroy_bitmap(void * bmp) -{ - GrDestroyWindow((GR_WINDOW_ID)bmp); -} - -/*****************************************************************************/ -#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) \ - { \ - x1 = x + glyph->offset; \ - y1 = y + glyph->baseline; \ - GrBitmap(g_wnd, g_gc, x1, y1, glyph->width, glyph->height, glyph->pixmap); \ - 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 bgcolor, int fgcolor, uint8 * text, uint8 length) -{ - FONTGLYPH * glyph; - int i, j, xyoffset, x1, y1; - DATABLOB * entry; - - GrSetGCMode(g_gc, GR_MODE_COPY); - GrSetGCUseBackground(g_gc, 0); /* this can be set when gc is created */ - if (g_server_bpp == 16 && g_bpp == 32) - { - fgcolor = COLOR16TO32(fgcolor); - bgcolor = COLOR16TO32(bgcolor); - } - GrSetGCForeground(g_gc, bgcolor); - if (boxx + boxcx > g_width) - { - boxcx = g_width - boxx; - } - if (boxcx > 1) - { - GrFillRect(g_wnd, g_gc, boxx, boxy, boxcx, boxcy); - } - else if (mixmode == MIX_OPAQUE) - { - GrFillRect(g_wnd, g_gc, clipx, clipy, clipcx, clipcy); - } - GrSetGCForeground(g_gc, fgcolor); - /* 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; - } - } -} - -/*****************************************************************************/ -void ui_line(uint8 opcode, int startx, int starty, int endx, int endy, - PEN * pen) -{ - uint32 op; - uint32 color; - - color = pen->colour; - if (opcode == 5) /* GR_MODE_INVERT, not supported so convert it */ - { /* i think x ^ -1 = ~x */ - color = 0xffffffff; - opcode = 6; /* GR_MODE_XOR */ - } - if (opcode == 12 || opcode == 6) /* nanox only supports these 2 opcode */ - { - op = g_ops[opcode]; - GrSetGCMode(g_gc, op); - if (g_server_bpp == 16 && g_bpp == 32) - { - color = COLOR16TO32(color); - } - GrSetGCForeground(g_gc, color); - GrLine(g_wnd, g_gc, startx, starty, endx, endy); - GrSetGCMode(g_gc, GR_MODE_COPY); - } - else - { - unimpl("opcode %d in ui_line\n", opcode); - } -} - -/*****************************************************************************/ -void ui_triblt(uint8 opcode, int x, int y, int cx, int cy, - void * src, int srcx, int srcy, - BRUSH * brush, int bgcolor, int fgcolor) -{ -/* not used, turned off */ -} - -/*****************************************************************************/ -void ui_memblt(uint8 opcode, int x, int y, int cx, int cy, - void * src, int srcx, int srcy) -{ - uint8 * dest; - uint8 * source; - uint8 * final; - GR_WINDOW_INFO wi; - int i, j, s, d; - GR_WINDOW_ID pixmap; - - if (opcode == 12) - { - GrCopyArea(g_wnd, g_gc, x, y, cx, cy, (GR_DRAW_ID)src, srcx, srcy, - GR_MODE_COPY); - } - else /* do opcodes ourself */ - { /* slow but its correct, ok to be slow here, these are rare */ - GrGetWindowInfo((GR_DRAW_ID)src, &wi); - dest = xmalloc(cx * cy * g_Bpp); - source = xmalloc(wi.width * wi.height * g_Bpp); - final = xmalloc(cx * cy * g_Bpp); - memset(final, 0, cx * cy * g_Bpp); - /* dest */ - GrReadArea(g_wnd, x, y, cx, cy, (GR_PIXELVAL*)dest); - /* source */ - GrReadArea((GR_DRAW_ID)src, 0, 0, - wi.width, wi.height, (GR_PIXELVAL*)source); - for (i = 0; i < cy; i++) - { - for (j = 0; j < cx; j++) - { - s = get_pixel32(source, j + srcx, i + srcy, wi.width, wi.height); - d = get_pixel32(dest, j, i, cx ,cy); - set_pixel32(final, j, i, cx, cy, rop(opcode, s, d)); - } - } - pixmap = GrNewPixmap(cx, cy, 0); - GrArea(pixmap, g_gc_clean, 0, 0, cx, cy, final, MWPF_TRUECOLOR0888); - GrCopyArea(g_wnd, g_gc, x, y, cx, cy, pixmap, 0, 0, GR_MODE_COPY); - GrDestroyWindow(pixmap); - xfree(dest); - xfree(source); - xfree(final); - } -} - -/*****************************************************************************/ -void ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy) -{ -/* not used, turned off */ -} - -/*****************************************************************************/ -void ui_desktop_save(uint32 offset, int x, int y, int cx, int cy) -{ -/* not used, turned off */ -} - -/*****************************************************************************/ -void ui_rect(int x, int y, int cx, int cy, int color) -{ - if (g_server_bpp == 16 && g_bpp == 32) - { - color = COLOR16TO32(color); - } - GrSetGCForeground(g_gc, color); - GrFillRect(g_wnd, g_gc, x, y, cx, cy); -} - -/*****************************************************************************/ -/* using warp_coords cause clip seems to affect source in GrCopyArea */ -void ui_screenblt(uint8 opcode, int x, int y, int cx, int cy, - int srcx, int srcy) -{ - if (opcode == 12) - { - if (warp_coords(&x, &y, &cx, &cy, &srcx, &srcy)) - { - GrCopyArea(g_wnd, g_gc_clean, x, y, cx, cy, g_wnd, srcx, srcy, - GR_MODE_COPY); - } - } - else - { - unimpl("opcode %d in ui_screenblt\n", opcode); - } -} - -/******************************************************************************/ -/* can't use stipple cause tsorigin don't work, GrPoint too slow, - GrPoints too slow but better, using a copy from the screen, - do the pattern and copy it back */ -void ui_patblt(uint8 opcode, int x, int y, int cx, int cy, - BRUSH * brush, int bgcolor, int fgcolor) -{ - uint8 ipattern[8], * dest, * final; - uint32 op; - int i, j, s, d; - GR_WINDOW_ID pixmap; - - if (g_server_bpp == 16 && g_bpp == 32) - { - fgcolor = COLOR16TO32(fgcolor); - bgcolor = COLOR16TO32(bgcolor); - } - switch (brush->style) - { - case 0: /* Solid */ - if (opcode == 12 || opcode == 6) - { - op = g_ops[opcode]; - GrSetGCMode(g_gc, op); - GrSetGCForeground(g_gc, fgcolor); - GrFillRect(g_wnd, g_gc, x, y, cx, cy); - GrSetGCMode(g_gc, GR_MODE_COPY); - } - else - { - unimpl("opcode %d in ui_patblt solid brush\n", opcode); - } - break; - case 3: /* Pattern - all opcodes ok */ - for (i = 0; i != 8; i++) - { - ipattern[7 - i] = brush->pattern[i]; - } - dest = xmalloc(cx * cy * g_Bpp); - final = xmalloc(cx * cy * g_Bpp); - memset(final, 0, cx * cy * g_Bpp); - /* dest */ - if (opcode != 12) - { - GrReadArea(g_wnd, x, y, cx, cy, (GR_PIXELVAL*)dest); - } - for (i = 0; i < cy; i++) - { - for (j = 0; j < cx; j++) - { - if (is_pixel_on(ipattern, (x + j + brush->xorigin) % 8, - (y + i + brush->yorigin) % 8, 8, 1)) - { - s = fgcolor; - } - else - { - s = bgcolor; - } - d = get_pixel32(dest, j, i, cx ,cy); - set_pixel32(final, j, i, cx, cy, rop(opcode, s, d)); - } - } - pixmap = GrNewPixmap(cx, cy, 0); - GrArea(pixmap, g_gc_clean, 0, 0, cx, cy, final, MWPF_TRUECOLOR0888); - GrCopyArea(g_wnd, g_gc, x, y, cx, cy, pixmap, 0, 0, GR_MODE_COPY); - GrDestroyWindow(pixmap); - xfree(dest); - xfree(final); - break; - } -} - -/*****************************************************************************/ -void ui_destblt(uint8 opcode, int x, int y, int cx, int cy) -{ - uint32 op; - - if (opcode == 0) /* black */ - { - GrSetGCForeground(g_gc, 0); - opcode = 12; - } - else if (opcode == 5) /* invert */ - { - GrSetGCForeground(g_gc, 0xffffffff); - opcode = 6; - } - else if (opcode == 15) /* white */ - { - GrSetGCForeground(g_gc, 0xffffffff); - opcode = 12; - } - if (opcode == 12 || opcode == 6) - { - op = g_ops[opcode]; - GrSetGCMode(g_gc, op); - GrFillRect(g_wnd, g_gc, x, y, cx, cy); - GrSetGCMode(g_gc, GR_MODE_COPY); - } - else - { - unimpl("opcode %d in ui_destblt\n", opcode); - } -} - -/*****************************************************************************/ -void ui_paint_bitmap(int x, int y, int cx, int cy, - int width, int height, uint8 * data) -{ - void * b; - - b = ui_create_bitmap(width, height, data); - ui_memblt(12, x, y, cx, cy, b, 0, 0); - ui_destroy_bitmap(b); -} - -/*****************************************************************************/ -void ui_move_pointer(int x, int y) -{ - GrMoveCursor(x, y); -} - -/*****************************************************************************/ -void ui_set_null_cursor(void) -{ - GrSetWindowCursor(g_wnd, g_null_cursor); -} - -/*****************************************************************************/ -void ui_set_cursor(void * cursor) -{ - GrSetWindowCursor(g_wnd, (GR_CURSOR_ID)cursor); -} - -//****************************************************************************** -static int is24on(uint8 * data, int x, int y) -{ - uint8 r, g, b; - int start; - - if (data == 0) - { - return 0; - } - start = y * 32 * 3 + x * 3; - r = data[start]; - g = data[start + 1]; - b = data[start + 2]; - return !((r == 0) && (g == 0) && (b == 0)); -} - -//****************************************************************************** -static int is1on(uint8 * data, int x, int y) -{ - int start; - int shift; - - if (data == 0) - { - return 0; - } - start = (y * 32) / 8 + x / 8; - shift = x % 8; - return (data[start] & (0x80 >> shift)) == 0; -} - -//****************************************************************************** -static void set1(uint8 * data, int x, int y) -{ - int start; - int shift; - - if (data == 0) - { - return; - } - start = (y * 32) / 8 + x / 8; - shift = x % 8; - data[start] = data[start] | (0x80 >> shift); -} - -//****************************************************************************** -static void flipover(uint8 * data) -{ - uint8 adata[128]; - int index; - - if (data == 0) - { - return; - } - memcpy(adata, data, 128); - for (index = 0; index <= 31; index++) - { - data[127 - (index * 4 + 3)] = adata[index * 4]; - data[127 - (index * 4 + 2)] = adata[index * 4 + 1]; - data[127 - (index * 4 + 1)] = adata[index * 4 + 2]; - data[127 - index * 4] = adata[index * 4 + 3]; - } -} - -/*****************************************************************************/ -void * ui_create_cursor(uint32 x, uint32 y, - int width, int height, - uint8 * andmask, uint8 * xormask) -{ - uint8 adata[128]; - uint8 amask[128]; - GR_BITMAP * databitmap; - GR_BITMAP * maskbitmap; - GR_CURSOR_ID cursor; - int i1, i2, bon, mon; - - if (width != 32 || height != 32) - { - return 0; - } - memset(adata, 0, 128); - memset(amask, 0, 128); - for (i1 = 0; i1 <= 31; i1++) - { - for (i2 = 0; i2 <= 31; i2++) - { - mon = is24on(xormask, i1, i2); - bon = is1on(andmask, i1, i2); - if (bon ^ mon) // xor - { - set1(adata, i1, i2); - if (!mon) - { - set1(amask, i1, i2); - } - } - if (mon) - { - set1(amask, i1, i2); - } - } - } - flipover(adata); - flipover(amask); - databitmap = ui_create_glyph(32, 32, adata); - maskbitmap = ui_create_glyph(32, 32, amask); - cursor = GrNewCursor(32, 32, x, y, 0xffffff, 0, databitmap, maskbitmap); - ui_destroy_glyph(databitmap); - ui_destroy_glyph(maskbitmap); - return (void*)cursor; -} - -/*****************************************************************************/ -void ui_destroy_cursor(void * cursor) -{ - GrDestroyCursor((GR_CURSOR_ID)cursor); -} - -/*****************************************************************************/ -uint16 ui_get_numlock_state(uint32 state) -{ - return 0; -} - -/*****************************************************************************/ -uint32 read_keyboard_state(void) -{ - return 0; -} - -/*****************************************************************************/ -void ui_resize_window(void) -{ -} - -/*****************************************************************************/ -void ui_begin_update(void) -{ -} - -/*****************************************************************************/ -void ui_end_update(void) -{ -} - -/*****************************************************************************/ -void ui_polygon(uint8 opcode, uint8 fillmode, POINT * point, int npoints, - BRUSH * brush, int bgcolor, int fgcolor) -{ -/* not used, turned off */ -} - -/*****************************************************************************/ -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 bgcolor, int fgcolor) -{ -/* not used, turned off */ -} - -/*****************************************************************************/ -void generate_random(uint8 * random) -{ - memcpy(random, "12345678901234567890123456789012", 32); -} - -/*****************************************************************************/ -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) -{ - return malloc(size); -} - -/*****************************************************************************/ -void xfree(void * in) -{ - if (in != 0) - { - free(in); - } -} - -/*****************************************************************************/ -char * xstrdup(const char * s) -{ - char * mem = strdup(s); - if (mem == NULL) - { - perror("strdup"); - exit(1); - } - return mem; -} - -/*****************************************************************************/ -void warning(char * format, ...) -{ - va_list ap; - - fprintf(stderr, "WARNING: "); - va_start(ap, format); - vfprintf(stderr, format, ap); - va_end(ap); -} - -/*****************************************************************************/ -void unimpl(char * format, ...) -{ - va_list ap; - - fprintf(stderr, "NOT IMPLEMENTED: "); - va_start(ap, format); - vfprintf(stderr, format, ap); - va_end(ap); -} - -/*****************************************************************************/ -void error(char * format, ...) -{ - va_list ap; - - fprintf(stderr, "ERROR: "); - va_start(ap, format); - vfprintf(stderr, format, ap); - va_end(ap); -} - -/*****************************************************************************/ -int 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; -} - -/*****************************************************************************/ -int rd_lock_file(int fd, int start, int len) -{ - return False; -} - -/*****************************************************************************/ -/*static int key(int ch, int flags) -{ - return (ch & 0xffff) | ((flags & 0xffff) << 16); -}*/ - -/*****************************************************************************/ -static void init_keys(void) -{ - memset(&g_keys, 0, sizeof(g_keys)); - g_keys[0x01].ch1 = 27; /* esc */ - g_keys[0x02].ch1 = '1'; - g_keys[0x02].chs = '!'; - g_keys[0x03].ch1 = '2'; - g_keys[0x03].chs = '@'; - g_keys[0x04].ch1 = '3'; - g_keys[0x04].chs = '#'; - g_keys[0x05].ch1 = '4'; - g_keys[0x05].chs = '$'; - g_keys[0x06].ch1 = '5'; - g_keys[0x06].chs = '%'; - g_keys[0x07].ch1 = '6'; - g_keys[0x07].chs = '^'; - g_keys[0x08].ch1 = '7'; - g_keys[0x08].chs = '&'; - g_keys[0x09].ch1 = '8'; - g_keys[0x09].chs = '*'; - g_keys[0x0a].ch1 = '9'; - g_keys[0x0a].chs = '('; - g_keys[0x0b].ch1 = '0'; - g_keys[0x0b].chs = ')'; - g_keys[0x0c].ch1 = '-'; - g_keys[0x0c].chs = '_'; - g_keys[0x0d].ch1 = '='; - g_keys[0x0d].chs = '+'; - g_keys[0x0e].ch1 = 8; /* backspace */ - g_keys[0x0f].ch1 = 9; /* tab */ - g_keys[0x10].ch1 = 'q'; - g_keys[0x10].chs = 'Q'; - g_keys[0x11].ch1 = 'w'; - g_keys[0x11].chs = 'W'; - g_keys[0x12].ch1 = 'e'; - g_keys[0x12].chs = 'E'; - g_keys[0x13].ch1 = 'r'; - g_keys[0x13].chs = 'R'; - g_keys[0x14].ch1 = 't'; - g_keys[0x14].chs = 'T'; - g_keys[0x15].ch1 = 'y'; - g_keys[0x15].chs = 'Y'; - g_keys[0x16].ch1 = 'u'; - g_keys[0x16].chs = 'U'; - g_keys[0x17].ch1 = 'i'; - g_keys[0x17].chs = 'I'; - g_keys[0x18].ch1 = 'o'; - g_keys[0x18].chs = 'O'; - g_keys[0x19].ch1 = 'p'; - g_keys[0x19].chs = 'P'; - g_keys[0x1a].ch1 = '['; - g_keys[0x1a].chs = '{'; - g_keys[0x1b].ch1 = ']'; - g_keys[0x1b].chs = '}'; - g_keys[0x1c].ch2 = 13; /* enter */ - g_keys[0x1d].ch1 = 63533; /* left control */ - g_keys[0x1d].ch2 = 63534; /* right control */ - g_keys[0x1e].ch1 = 'a'; - g_keys[0x1e].chs = 'A'; - g_keys[0x1f].ch1 = 's'; - g_keys[0x1f].chs = 'S'; - g_keys[0x20].ch1 = 'd'; - g_keys[0x20].chs = 'D'; - g_keys[0x21].ch1 = 'f'; - g_keys[0x21].chs = 'F'; - g_keys[0x22].ch1 = 'g'; - g_keys[0x22].chs = 'G'; - g_keys[0x23].ch1 = 'h'; - g_keys[0x23].chs = 'H'; - g_keys[0x24].ch1 = 'j'; - g_keys[0x24].chs = 'J'; - g_keys[0x25].ch1 = 'k'; - g_keys[0x25].chs = 'K'; - g_keys[0x26].ch1 = 'l'; - g_keys[0x26].chs = 'L'; - g_keys[0x27].ch1 = ';'; - g_keys[0x27].chs = ':'; - g_keys[0x28].ch1 = '\''; - g_keys[0x28].chs = '"'; - g_keys[0x29].ch1 = '`'; - g_keys[0x29].chs = '~'; - g_keys[0x2a].ch1 = 63531; /* left shift */ - g_keys[0x2b].ch1 = '\\'; - g_keys[0x2c].ch1 = 'z'; - g_keys[0x2c].chs = 'Z'; - g_keys[0x2d].ch1 = 'x'; - g_keys[0x2d].chs = 'X'; - g_keys[0x2e].ch1 = 'c'; - g_keys[0x2e].chs = 'C'; - g_keys[0x2f].ch1 = 'v'; - g_keys[0x2f].chs = 'V'; - g_keys[0x30].ch1 = 'b'; - g_keys[0x30].chs = 'B'; - g_keys[0x31].ch1 = 'n'; - g_keys[0x31].chs = 'N'; - g_keys[0x32].ch1 = 'm'; - g_keys[0x32].chs = 'M'; - g_keys[0x33].ch1 = ','; - g_keys[0x33].chs = '<'; - g_keys[0x34].ch1 = '.'; - g_keys[0x34].chs = '>'; - g_keys[0x35].ch1 = '/'; - g_keys[0x35].ch2 = 63509; - g_keys[0x35].chs = '?'; - g_keys[0x36].ch1 = 63532; /* right shift */ - g_keys[0x37].ch1 = '*'; /* star on keypad */ - g_keys[0x37].ch2 = 63510; /* star on keypad */ - g_keys[0x38].ch1 = 63535; /* alt */ - g_keys[0x38].ch2 = 63536; /* alt */ - g_keys[0x39].ch1 = ' '; - g_keys[0x3a].ch1 = 0; /* caps lock */ - g_keys[0x3b].ch1 = 63515; /* f1 */ - g_keys[0x3c].ch1 = 63516; /* f2 */ - g_keys[0x3d].ch1 = 63517; /* f3 */ - g_keys[0x3e].ch1 = 63518; /* f4 */ - g_keys[0x3f].ch1 = 63519; /* f5 */ - g_keys[0x40].ch1 = 63520; /* f6 */ - g_keys[0x41].ch1 = 63521; /* f7 */ - g_keys[0x42].ch1 = 63522; /* f8 */ - g_keys[0x43].ch1 = 63523; /* f9 */ - g_keys[0x44].ch1 = 63524; /* f10 */ - g_keys[0x45].ch1 = 0; /* num lock */ - g_keys[0x46].ch1 = 0; /* scroll lock */ - g_keys[0x47].ch1 = 63505; /* home */ - g_keys[0x47].ch2 = 63494; /* home */ - g_keys[0x48].ch1 = 63490; /* arrow up */ - g_keys[0x48].ch2 = 63506; /* arrow up */ - g_keys[0x49].ch1 = 63507; /* page up */ - g_keys[0x49].ch2 = 63496; /* page up */ - g_keys[0x4a].ch1 = '-'; /* -(minus) on keypad */ - g_keys[0x4a].ch2 = 63511; /* -(minus) on keypad */ - g_keys[0x4b].ch1 = 63502; /* arrow left */ - g_keys[0x4b].ch2 = 63488; /* arrow left */ - g_keys[0x4c].ch1 = 63503; /* middle(5 key) on keypad */ - g_keys[0x4d].ch1 = 63504; /* arrow right */ - g_keys[0x4d].ch2 = 63489; /* arrow right */ - g_keys[0x4e].ch1 = '+'; /* +(plus) on keypad */ - g_keys[0x4e].ch2 = 63512; /* +(plus) on keypad */ - g_keys[0x4f].ch1 = 63499; /* end */ - g_keys[0x4f].ch2 = 63495; /* end */ - g_keys[0x50].ch1 = 63500; /* arrow down */ - g_keys[0x50].ch2 = 63491; /* arrow down */ - g_keys[0x51].ch1 = 63501; /* page down */ - g_keys[0x51].ch2 = 63497; /* page down */ - g_keys[0x52].ch1 = 63498; /* insert */ - g_keys[0x52].ch2 = 63492; /* insert */ - g_keys[0x53].ch1 = 63508; /* delete */ - g_keys[0x53].ch2 = 63493; /* delete */ - g_keys[0x54].ch1 = 63525; /* f11 */ - g_keys[0x54].ch1 = 63527; /* f12 */ -} - -/*****************************************************************************/ -/* returns 0 if found key */ -static int get_sc(GR_EVENT_KEYSTROKE * event_keystroke, int * sc, int * ec) -{ - int i; - - //printf("%d %d\n", event_keystroke->ch, event_keystroke->modifiers); - *sc = 0; - *ec = 0; - for (i = 0; i < 256; i++) - { - if (event_keystroke->modifiers & 1) /* shift is down */ - { - if (event_keystroke->ch == g_keys[i].chs) - { - *sc = i; - break; - } - } - if (event_keystroke->ch == g_keys[i].ch1 || - event_keystroke->ch == g_keys[i].ch2 || - event_keystroke->ch == g_keys[i].ch3) - { - *sc = i; - break; - } - } - if (*sc == 0) - { - return 1; - } - else - { - return 0; - } -} - -/*****************************************************************************/ -void static process_keystroke(GR_EVENT_KEYSTROKE * event_keystroke, int down) -{ - int sc, ec; - - if (get_sc(event_keystroke, &sc, &ec) == 0) - { - if (down) - { - rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYPRESS, sc, ec); - } - else - { - rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYRELEASE, sc, ec); - } - } -} - -/*****************************************************************************/ -void nanox_event(GR_EVENT * ev) -{ - GR_EVENT_MOUSE * event_mouse; - GR_EVENT_BUTTON * event_button; - GR_EVENT_FDINPUT * event_fdinput; - GR_EVENT_KEYSTROKE * event_keystroke; - - do - { - if (ev->type == GR_EVENT_TYPE_FDINPUT) /* 12 */ - { - event_fdinput = (GR_EVENT_FDINPUT *) ev; - if (event_fdinput->fd == g_sck) - { - if (!rdp_loop(&g_deactivated, &g_ext_disc_reason)) - { - fprintf(stderr, "rdp_loop in nanox_event exit codes %d %d\n", - g_deactivated, g_ext_disc_reason); - exit(1); - } - } - } - else if (ev->type == GR_EVENT_TYPE_BUTTON_DOWN) /* 2 */ - { - event_button = (GR_EVENT_BUTTON *) ev; - if (event_button->changebuttons & 4) /* left */ - { - rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON1, - event_button->x, event_button->y); - } - else if (event_button->changebuttons & 1) /* right */ - { - rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON2, - event_button->x, event_button->y); - } - } - else if (ev->type == GR_EVENT_TYPE_BUTTON_UP) /* 3 */ - { - event_button = (GR_EVENT_BUTTON *) ev; - if (event_button->changebuttons & 4) /* left */ - { - rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON1, - event_button->x, event_button->y); - } - else if (event_button->changebuttons & 1) /* right */ - { - rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON2, - event_button->x, event_button->y); - } - } - else if (ev->type == GR_EVENT_TYPE_MOUSE_MOTION) /* 6 */ - { - event_mouse = (GR_EVENT_MOUSE *) ev; - rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE, - event_mouse->x, event_mouse->y); - } - else if (ev->type == GR_EVENT_TYPE_MOUSE_POSITION) /* 7 */ - { - /* use GR_EVENT_TYPE_MOUSE_MOTION */ - } - else if (ev->type == GR_EVENT_TYPE_KEY_DOWN) /* 8 */ - { - event_keystroke = (GR_EVENT_KEYSTROKE *) ev; - process_keystroke(event_keystroke, 1); - } - else if (ev->type == GR_EVENT_TYPE_KEY_UP) /* 9 */ - { - event_keystroke = (GR_EVENT_KEYSTROKE *) ev; - process_keystroke(event_keystroke, 0); - } - else if (ev->type == GR_EVENT_TYPE_FOCUS_IN) /* 10 */ - { - } - else if (ev->type == GR_EVENT_TYPE_FOCUS_OUT) /* 11 */ - { - } - else if (ev->type == GR_EVENT_TYPE_UPDATE) /* 13 */ - { - } - GrCheckNextEvent(ev); - } while (ev->type != GR_EVENT_TYPE_NONE); -} - -/*****************************************************************************/ -static void get_username_and_hostname(void) -{ - char fullhostname[64]; - char * p; - struct passwd * pw; - - STRNCPY(g_username, "unknown", sizeof(g_username)); - STRNCPY(g_hostname, "unknown", sizeof(g_hostname)); - pw = getpwuid(getuid()); - if (pw != NULL && pw->pw_name != NULL) - { - STRNCPY(g_username, pw->pw_name, sizeof(g_username)); - } - if (gethostname(fullhostname, sizeof(fullhostname)) != -1) - { - p = strchr(fullhostname, '.'); - if (p != NULL) - { - *p = 0; - } - STRNCPY(g_hostname, fullhostname, sizeof(g_hostname)); - } -} -/*****************************************************************************/ -static void out_params(void) -{ - fprintf(stderr, "rdesktop: A Remote Desktop Protocol client.\n"); - fprintf(stderr, "Version " VERSION ". Copyright (C) 1999-2005 Matt Chapman.\n"); - fprintf(stderr, "nanox uiport by Jay Sorg\n"); - fprintf(stderr, "See http://www.rdesktop.org/ for more information.\n\n"); - fprintf(stderr, "Usage: nanoxrdesktop [options] server\n"); - fprintf(stderr, " -u: user name\n"); - fprintf(stderr, " -n: client hostname\n"); - fprintf(stderr, " -p: password\n"); - fprintf(stderr, " -d: domain\n"); - fprintf(stderr, " -s: shell\n"); - fprintf(stderr, " -c: working directory\n"); - fprintf(stderr, "\n"); -} - -/*****************************************************************************/ -static int parse_parameters(int in_argc, char ** in_argv) -{ - int i; - - if (in_argc <= 1) - { - out_params(); - return 0; - } - for (i = 1; i < in_argc; i++) - { - strcpy(g_servername, in_argv[i]); - if (strcmp(in_argv[i], "-h") == 0) - { - out_params(); - return 0; - } - else if (strcmp(in_argv[i], "-n") == 0) - { - STRNCPY(g_hostname, in_argv[i + 1], sizeof(g_hostname)); - } - else if (strcmp(in_argv[i], "-u") == 0) - { - STRNCPY(g_username, in_argv[i + 1], sizeof(g_username)); - } - else if (strcmp(in_argv[i], "-p") == 0) - { - STRNCPY(g_password, in_argv[i + 1], sizeof(g_password)); - g_flags |= RDP_LOGON_AUTO; - i++; - } - else if (strcmp(in_argv[i], "-d") == 0) - { - STRNCPY(g_domain, in_argv[i + 1], sizeof(g_domain)); - i++; - } - else if (strcmp(in_argv[i], "-s") == 0) - { - STRNCPY(g_shell, in_argv[i + 1], sizeof(g_shell)); - i++; - } - else if (strcmp(in_argv[i], "-c") == 0) - { - STRNCPY(g_directory, in_argv[i + 1], sizeof(g_directory)); - i++; - } - } - return 1; -} - -/*****************************************************************************/ -int main(int in_argc, char ** in_argv) -{ - get_username_and_hostname(); - /* read command line options */ - if (!parse_parameters(in_argc, in_argv)) - { - exit(0); - } - /* connect to server */ - if (GrOpen() < 0) - { - fprintf(stderr, "Couldn't connect to Nano-X server\n"); - exit(1); - } - GrGetScreenInfo(&g_screen_info); - g_bpp = g_screen_info.bpp; - g_Bpp = (g_screen_info.bpp + 7) / 8; - g_width = g_screen_info.vs_width; - g_height = g_screen_info.vs_height; - g_clip.x = 0; - g_clip.y = 0; - g_clip.width = g_width; - g_clip.height = g_height; - if (!((g_bpp == 32 && g_server_bpp == 16) || - (g_bpp == 16 && g_server_bpp == 16))) - { - fprintf(stderr, "unsupported bpp, server = %d, client = %d\n", - g_server_bpp, g_bpp); - GrClose(); - exit(0); - } - init_keys(); - /* connect to server */ - if (!rdp_connect(g_servername, g_flags, g_domain, g_password, g_shell, - g_directory)) - { - fprintf(stderr, "Error connecting\n"); - GrClose(); - exit(1); - } - /* create window */ - g_wnd = GrNewWindow(GR_ROOT_WINDOW_ID, 0, 0, g_width, g_height, 0, 0, 0); - /* show window */ - GrMapWindow(g_wnd); - /* create graphic context */ - g_gc = GrNewGC(); - g_gc_clean = GrNewGC(); - /* clear screen */ - GrSetGCForeground(g_gc, 0); - GrFillRect(g_wnd, g_gc, 0, 0, g_width, g_height); - /* create null cursor */ - g_null_cursor = (GR_CURSOR_ID)ui_create_cursor(0, 0, 32, 32, 0, 0); - /* register callbacks, set mask, and run main loop */ - GrSelectEvents(g_wnd, -1); /* all events */ - GrRegisterInput(g_sck); - GrMainLoop(nanox_event); - /* free null cursor */ - ui_destroy_cursor((void*)g_null_cursor); - /* free graphic context */ - GrDestroyGC(g_gc); - GrDestroyGC(g_gc_clean); - /* free window */ - GrDestroyWindow(g_wnd); - /* close connection */ - GrClose(); - return 0; -} diff -Nru rdesktop-1.8.6/uiports/qtereadme.txt rdesktop-1.9.0/uiports/qtereadme.txt --- rdesktop-1.8.6/uiports/qtereadme.txt 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/uiports/qtereadme.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,12 +0,0 @@ -This is the Qt/Emb ui port -qt should be installed in /usr/local/qt -you may need to have LD_LIBRARY_PATH and QTDIR defined to run qtrdesktop -tested with versions 2.3, 3.1 - -makefile_qte can be edited to change file localtions -run make -f makefile_qte in this directory to compile it - -qtereadme.txt - notes, this file -makefile_qte - makefile -qtewin.cpp - ui lib -qtewin.h - header diff -Nru rdesktop-1.8.6/uiports/qtewin.cpp rdesktop-1.9.0/uiports/qtewin.cpp --- rdesktop-1.8.6/uiports/qtewin.cpp 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/uiports/qtewin.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,2556 +0,0 @@ -/* -*- c-basic-offset: 8 -*- - rdesktop: A Remote Desktop Protocol client. - User interface services - QT Emb System - Copyright (C) Jay Sorg 2004-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 3 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, see <http://www.gnu.org/licenses/>. -*/ - -//#define SHARP - -#ifdef SHARP -#include <qpe/qpeapplication.h> -#else -#include <qapplication.h> -#endif -#include <qcursor.h> -#include <qmainwindow.h> -#include <qwidget.h> -#include <qpainter.h> -#include <qimage.h> -#include <qsocketnotifier.h> -#include <qscrollview.h> -#include <qmessagebox.h> -#include <qpushbutton.h> -#include <qlineedit.h> -#include <qcombobox.h> -#include <qlabel.h> -#include <qfile.h> -#include <qcheckbox.h> -#include <qpopupmenu.h> - -#include <stdlib.h> -#include <stdarg.h> // va_list va_start va_end -#include <unistd.h> // gethostname -#include <pwd.h> // getpwuid - -#include "../rdesktop.h" -#include "qtewin.h" - -#define QT_OPTI - -extern int g_tcp_port_rdp; -int g_encryption = 1; -int g_bitmap_cache = 1; -int g_bitmap_cache_persist_enable = 0; -int g_bitmap_cache_precache = 1; -int g_use_rdp5 = 1; -int g_desktop_save = 1; -int g_bitmap_compression = 1; -int g_polygon_ellipse_orders = 0; -int g_rdp5_performanceflags = - RDP5_NO_WALLPAPER | RDP5_NO_FULLWINDOWDRAG | RDP5_NO_MENUANIMATIONS; -int g_console_session = 0; -int 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 */ -int g_width = 640; -int g_height = 480; -int g_server_bpp = 8; -char g_hostname[16] = ""; -char g_username[100] = ""; - -#ifdef WITH_RDPSND -extern int g_dsp_busy; -extern int g_dsp_fd; -int g_rdpsnd = 0; -static QSocketNotifier * g_SoundNotifier = 0; -#endif - -/* types */ -struct QColorMap -{ - uint32 RGBColors[256]; - uint32 NumColors; -}; - -struct bitmap -{ - int w; - int h; - uint8 * data; -}; - -static int g_client_width = 640; -static int g_client_height = 480; -static uint32 g_flags = RDP_LOGON_NORMAL; -static char g_server[64] = ""; -static char g_domain[16] = ""; -static char g_password[16] = ""; -static char g_shell[128] = ""; -static char g_directory[32] = ""; -static int g_fullscreen = 0; -static int g_global_sock = 0; -static int g_deactivated = 0; -static uint32 g_ext_disc_reason = 0; - -static QSocketNotifier * g_SocketNotifier = 0; -#ifdef SHARP -static QPEApplication * g_App = 0; -#else -static QApplication * g_App = 0; -#endif -static QMyMainWindow * g_MW = 0; -static QMyScrollView * g_SV = 0; -static struct QColorMap * g_CM = 0; -static uint8 * g_BS = 0; /* the screen data */ -static int g_clipx = 0; -static int g_clipy = 0; -static int g_clipcx = 0; -static int g_clipcy = 0; - -/* 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; - -#define BPP ((g_server_bpp + 7) / 8) -#define GETPIXEL8(d, x, y, w) (*(((uint8*)d) + ((y) * (w) + (x)))) -#define GETPIXEL16(d, x, y, w) (*(((uint16*)d) + ((y) * (w) + (x)))) -#define GETPIXEL32(d, x, y, w) (*(((uint32*)d) + ((y) * (w) + (x)))) -#define SETPIXEL8(d, x, y, w, v) *(((uint8*)d) + ((y) * (w) + (x))) = v -#define SETPIXEL16(d, x, y, w, v) *(((uint16*)d) + ((y) * (w) + (x))) = v -#define SETPIXEL32(d, x, y, w, v) *(((uint32*)d) + ((y) * (w) + (x))) = v - -/******************************************************************************/ -void CleanString(QString * Item) -{ - int i; - - i = Item->length() - 1; - while (i >= 0) - { - if (Item->at(i) == 10 || Item->at(i) == 13) - { - Item->remove(i, 1); - } - i--; - } -} - -/******************************************************************************/ -QMyDialog::QMyDialog(QWidget * parent) : QDialog(parent, "Settings", true) -{ - int i, j; - char * home; - char Text[256]; - QString Line; - QString ItemName; - QString ItemValue; - - // resize dialog - resize(230, 270); - // main list box - ListBox = new QListBox(this); - ListBox->move(10, 10); - ListBox->resize(200, 100); - connect(ListBox, SIGNAL(selectionChanged()), this, SLOT(ListBoxChanged())); - connect(ListBox, SIGNAL(selected(int)), this, SLOT(ListBoxSelected(int))); - // server - Label1 = new QLabel(this); - Label1->setText("Server Desc"); - Label1->move(10, 120); - Label1->resize(100, 20); - ServerNameEdit = new QLineEdit(this); - ServerNameEdit->move(75, 120); - ServerNameEdit->resize(100, 20); - // username - Label2 = new QLabel(this); - Label2->setText("User Name"); - Label2->move(10, 150); - Label2->resize(100, 20); - UserNameEdit = new QLineEdit(this); - UserNameEdit->move(75, 150); - UserNameEdit->resize(100, 20); - // ip - Label3 = new QLabel(this); - Label3->setText("Server IP"); - Label3->move(10, 180); - Label3->resize(100, 20); - IPEdit = new QLineEdit(this); - IPEdit->move(75, 180); - IPEdit->resize(100, 20); - // width and height - WidthHeightBox = new QComboBox(this); - WidthHeightBox->move(10, 210); - WidthHeightBox->resize(100, 20); - WidthHeightBox->insertItem("240x320"); - WidthHeightBox->insertItem("640x480"); - WidthHeightBox->insertItem("800x600"); - connect(WidthHeightBox, SIGNAL(activated(int)), this, SLOT(ComboChanged(int))); - WidthHeightBox->setCurrentItem(1); - WidthEdit = new QLineEdit(this); - WidthEdit->move(110, 210); - WidthEdit->resize(30, 20); - WidthEdit->setText("800"); - HeightEdit = new QLineEdit(this); - HeightEdit->move(140, 210); - HeightEdit->resize(30, 20); - HeightEdit->setText("600"); - // add to list button - AddButton = new QPushButton(this); - AddButton->move(180, 120); - AddButton->resize(50, 20); - AddButton->setText("Add"); - connect(AddButton, SIGNAL(clicked()), this, SLOT(AddClicked())); - // change list item button - EditButton = new QPushButton(this); - EditButton->move(180, 140); - EditButton->resize(50, 20); - EditButton->setText("Edit"); - connect(EditButton, SIGNAL(clicked()), this, SLOT(EditClicked())); - // save to file button - SaveButton = new QPushButton(this); - SaveButton->move(180, 160); - SaveButton->resize(50, 20); - SaveButton->setText("Save"); - connect(SaveButton, SIGNAL(clicked()), this, SLOT(SaveClicked())); - // remove an item button - RemoveButton = new QPushButton(this); - RemoveButton->move(180, 180); - RemoveButton->resize(50, 20); - RemoveButton->setText("Remove"); - connect(RemoveButton, SIGNAL(clicked()), this, SLOT(RemoveClicked())); - // full screen check box - FullScreenCheckBox = new QCheckBox(this, "Full Screen"); - FullScreenCheckBox->setText("Full Screen"); - FullScreenCheckBox->move(10, 230); - // ok button - OKButton = new QPushButton(this); - OKButton->setText("OK"); - OKButton->move(100, 240); - OKButton->resize(50, 20); - connect(OKButton, SIGNAL(clicked()), this, SLOT(OKClicked())); - // cancel button - CancelButton = new QPushButton(this); - CancelButton->setText("Cancel"); - CancelButton->move(160, 240); - CancelButton->resize(50, 20); - connect(CancelButton, SIGNAL(clicked()), this, SLOT(CancelClicked())); - - for (i = 0; i < 10; i++) - { - ConnectionList[i] = new QMyConnectionItem; - ConnectionList[i]->ServerName = ""; - ConnectionList[i]->UserName = ""; - ConnectionList[i]->ServerIP = ""; - ConnectionList[i]->Width = 0; - ConnectionList[i]->Height = 0; - ConnectionList[i]->FullScreen = 0; - } - home = getenv("HOME"); - if (home != NULL) - { - sprintf(Text, "%s/rdesktop.ini", home); - QFile * File = new QFile(Text); - if (File->open(IO_ReadOnly)) - { - i = -1; - while (!File->atEnd()) - { - File->readLine(Line, 255); - j = Line.find("="); - if (j > 0) - { - ItemName = Line.mid(0, j); - CleanString(&ItemName); - ItemValue = Line.mid(j + 1); - CleanString(&ItemValue); - if (ItemName == "Server") - { - i++; - ConnectionList[i]->ServerName = ItemValue; - ListBox->insertItem(ItemValue); - } - else if (ItemName == "UserName") - ConnectionList[i]->UserName = ItemValue; - else if (ItemName == "Width") - ConnectionList[i]->Width = ItemValue.toInt(); - else if (ItemName == "Height") - ConnectionList[i]->Height = ItemValue.toInt(); - else if (ItemName == "IP") - ConnectionList[i]->ServerIP = ItemValue; - else if (ItemName == "FullScreen") - ConnectionList[i]->FullScreen = (ItemValue != "0"); - } - } - } - delete File; - } -} - -/******************************************************************************/ -QMyDialog::~QMyDialog() -{ - QMyConnectionItem * Item; - int i; - - for (i = 0; i < 10; i++) - { - Item = ConnectionList[i]; - delete Item; - } -} - -/******************************************************************************/ -void QMyDialog::ComboChanged(int index) -{ - if (index == 0) - { - WidthEdit->setText("240"); - HeightEdit->setText("320"); - } - if (index == 1) - { - WidthEdit->setText("640"); - HeightEdit->setText("480"); - } - else if (index == 2) - { - WidthEdit->setText("800"); - HeightEdit->setText("600"); - } -} - -/******************************************************************************/ -void QMyDialog::OKClicked() -{ - ServerName = ServerNameEdit->text(); - UserName = UserNameEdit->text(); - Width = WidthEdit->text().toInt(); - Height = HeightEdit->text().toInt(); - ServerIP = IPEdit->text(); - FullScreen = FullScreenCheckBox->isChecked(); - done(1); -} - -/******************************************************************************/ -void QMyDialog::CancelClicked() -{ - done(0); -} - -/******************************************************************************/ -void QMyDialog::AddClicked() -{ - int i; - QMyConnectionItem * Item; - - i = ListBox->count(); - if (i < 10) - { - ListBox->insertItem(ServerNameEdit->text()); - Item = ConnectionList[i]; - Item->ServerName = ServerNameEdit->text(); - Item->UserName = UserNameEdit->text(); - Item->Width = WidthEdit->text().toInt(); - Item->Height = HeightEdit->text().toInt(); - Item->ServerIP = IPEdit->text(); - Item->FullScreen = FullScreenCheckBox->isChecked(); - } -} - -/******************************************************************************/ -void QMyDialog::EditClicked() -{ - int i; - QMyConnectionItem * Item; - - i = ListBox->currentItem(); - if (i >= 0) - { - Item = ConnectionList[i]; - Item->ServerName = ServerNameEdit->text(); - Item->UserName = UserNameEdit->text(); - Item->Width = WidthEdit->text().toInt(); - Item->Height = HeightEdit->text().toInt(); - Item->ServerIP = IPEdit->text(); - Item->FullScreen = FullScreenCheckBox->isChecked(); - ListBox->changeItem(ServerNameEdit->text(), i); - } -} - -/******************************************************************************/ -void WriteString(QFile* File, QString* Line) -{ - File->writeBlock((const char*)(*Line), Line->length()); -} - -/******************************************************************************/ -void QMyDialog::SaveClicked() -{ - int i, j; - QMyConnectionItem * Item; - QString Line; - char * home; - char Text[256]; - QFile* File; - - home = getenv("HOME"); - if (home != NULL) - { - sprintf(Text, "%s/rdesktop.ini", home); - File = new QFile(Text); - if (File->open(IO_Truncate | IO_ReadWrite)) - { - i = ListBox->count(); - for (j = 0; j < i; j++) - { - Item = ConnectionList[j]; - Line = "Server="; - Line += Item->ServerName; - Line += (char)10; - WriteString(File, &Line); - Line = "UserName="; - Line += Item->UserName; - Line += (char)10; - WriteString(File, &Line); - Line = "Width="; - sprintf(Text, "%d", Item->Width); - Line += Text; - Line += (char)10; - WriteString(File, &Line); - Line = "Height="; - sprintf(Text, "%d", Item->Height); - Line += Text; - Line += (char)10; - WriteString(File, &Line); - Line = "IP="; - Line += Item->ServerIP; - Line += (char)10; - WriteString(File, &Line); - Line = "FullScreen="; - if (Item->FullScreen) - Line += "1"; - else - Line += "0"; - Line += (char)10; - WriteString(File, &Line); - } - } - File->flush(); - File->close(); - delete File; - } -} - -/******************************************************************************/ -void QMyDialog::RemoveClicked() -{ - int i, j, c; - QMyConnectionItem * Item1; - QMyConnectionItem * Item2; - - i = ListBox->currentItem(); - if (i >= 0) - { - c = ListBox->count(); - for (j = i; j < c - 1; j++) - { - Item1 = ConnectionList[i]; - Item2 = ConnectionList[i + 1]; - Item1->ServerName = Item2->ServerName; - Item1->UserName = Item2->UserName; - Item1->Width = Item2->Width; - Item1->Height = Item2->Height; - Item1->ServerIP = Item2->ServerIP; - Item1->FullScreen = Item2->FullScreen; - } - ListBox->removeItem(i); - } -} - -/******************************************************************************/ -void QMyDialog::ListBoxChanged() -{ - int i; - QMyConnectionItem * Item; - char Text[100]; - - i = ListBox->currentItem(); - if (i >= 0 && i < 10) - { - Item = ConnectionList[i]; - ServerNameEdit->setText(Item->ServerName); - UserNameEdit->setText(Item->UserName); - sprintf(Text, "%d", Item->Width); - WidthEdit->setText(Text); - sprintf(Text, "%d", Item->Height); - HeightEdit->setText(Text); - IPEdit->setText(Item->ServerIP); - FullScreenCheckBox->setChecked(Item->FullScreen != 0); - } -} - -/******************************************************************************/ -void QMyDialog::ListBoxSelected(int /*index*/) -{ -} - -/******************************************************************************/ -void GetScanCode(QKeyEvent * e, int * ScanCode, int * code) -{ - int key; - int mod; - int ascii; - - key = e->key(); - mod = e->state(); - ascii = e->ascii(); - - *ScanCode = 0; - *code = mod; // 8 shift, 16 control, 32 alt - - switch (key) - { - case 4096: // esc - case 4097: // tab - case 4099: // backspace - case 4100: // enter - case 4101: // enter - case 4103: // delete - ascii = 0; - } - - if (ascii == 0) - { - switch (key) - { - case 4096: *ScanCode = 0x01; break; // esc - case 4097: *ScanCode = 0x0f; break; // tab - case 4099: *ScanCode = 0x0e; break; // backspace - case 4100: *ScanCode = 0x1c; break; // enter - case 4101: *ScanCode = 0x1c; break; // enter - case 4112: *ScanCode = 0xc7; break; // home - case 4113: *ScanCode = 0xcf; break; // end - case 4102: *ScanCode = 0xd2; break; // insert - case 4103: *ScanCode = 0xd3; break; // delete - case 4118: *ScanCode = 0xc9; break; // page up - case 4119: *ScanCode = 0xd1; break; // page down - case 4117: *ScanCode = 0xd0; break; // down arrow - case 4115: *ScanCode = 0xc8; break; // up arrow - case 4114: *ScanCode = 0xcb; break; // left arrow - case 4116: *ScanCode = 0xcd; break; // right arrow - case 4128: *ScanCode = 0x2a; break; // shift - case 4131: *ScanCode = 0x38; break; // alt - case 4129: *ScanCode = 0x1d; break; // ctrl - } - if (*ScanCode != 0) - return; - } - - switch (ascii) - { - // first row - case 'q': *ScanCode = 0x10; break; - case 'Q': *ScanCode = 0x10; *code |= 8; break; - case '1': *ScanCode = 0x02; break; - case 'w': *ScanCode = 0x11; break; - case 'W': *ScanCode = 0x11; *code |= 8; break; - case '2': *ScanCode = 0x03; break; - case 'e': *ScanCode = 0x12; break; - case 'E': *ScanCode = 0x12; *code |= 8; break; - case '3': *ScanCode = 0x04; break; - case 'r': *ScanCode = 0x13; break; - case 'R': *ScanCode = 0x13; *code |= 8; break; - case '4': *ScanCode = 0x05; break; - case 't': *ScanCode = 0x14; break; - case 'T': *ScanCode = 0x14; *code |= 8; break; - case '5': *ScanCode = 0x06; break; - case 'y': *ScanCode = 0x15; break; - case 'Y': *ScanCode = 0x15; *code |= 8; break; - case '6': *ScanCode = 0x07; break; - case 'u': *ScanCode = 0x16; break; - case 'U': *ScanCode = 0x16; *code |= 8; break; - case '7': *ScanCode = 0x08; break; - case 'i': *ScanCode = 0x17; break; - case 'I': *ScanCode = 0x17; *code |= 8; break; - case '8': *ScanCode = 0x09; break; - case 'o': *ScanCode = 0x18; break; - case 'O': *ScanCode = 0x18; *code |= 8; break; - case '9': *ScanCode = 0x0a; break; - case 'p': *ScanCode = 0x19; break; - case 'P': *ScanCode = 0x19; *code |= 8; break; - case '0': *ScanCode = 0x0b; break; - // second row - case 'a': *ScanCode = 0x1e; break; - case 'A': *ScanCode = 0x1e; *code |= 8; break; - case '!': *ScanCode = 0x02; *code |= 8; break; - case 's': *ScanCode = 0x1f; break; - case 'S': *ScanCode = 0x1f; *code |= 8; break; - case '@': *ScanCode = 0x03; *code |= 8; break; - case 'd': *ScanCode = 0x20; break; - case 'D': *ScanCode = 0x20; *code |= 8; break; - case '#': *ScanCode = 0x04; *code |= 8; break; - case 'f': *ScanCode = 0x21; break; - case 'F': *ScanCode = 0x21; *code |= 8; break; - case '$': *ScanCode = 0x05; *code |= 8; break; - case 'g': *ScanCode = 0x22; break; - case 'G': *ScanCode = 0x22; *code |= 8; break; - case '%': *ScanCode = 0x06; *code |= 8; break; - case 'h': *ScanCode = 0x23; break; - case 'H': *ScanCode = 0x23; *code |= 8; break; - case '_': *ScanCode = 0x0c; *code |= 8; break; - case 'j': *ScanCode = 0x24; break; - case 'J': *ScanCode = 0x24; *code |= 8; break; - case '&': *ScanCode = 0x08; *code |= 8; break; - case 'k': *ScanCode = 0x25; break; - case 'K': *ScanCode = 0x25; *code |= 8; break; - case '*': *ScanCode = 0x09; *code |= 8; break; - case 'l': *ScanCode = 0x26; break; - case 'L': *ScanCode = 0x26; *code |= 8; break; - case '(': *ScanCode = 0x0a; *code |= 8; break; -// case 8: *ScanCode = 0x0e; break; // backspace - // third row - case 'z': *ScanCode = 0x2c; break; - case 'Z': *ScanCode = 0x2c; *code |= 8; break; - case 'x': *ScanCode = 0x2d; break; - case 'X': *ScanCode = 0x2d; *code |= 8; break; - case 'c': *ScanCode = 0x2e; break; - case 'C': *ScanCode = 0x2e; *code |= 8; break; - case 'v': *ScanCode = 0x2f; break; - case 'V': *ScanCode = 0x2f; *code |= 8; break; - case 'b': *ScanCode = 0x30; break; - case 'B': *ScanCode = 0x30; *code |= 8; break; - case '-': *ScanCode = 0x0c; break; - case 'n': *ScanCode = 0x31; break; - case 'N': *ScanCode = 0x31; *code |= 8; break; - case '+': *ScanCode = 0x0d; *code |= 8; break; - case 'm': *ScanCode = 0x32; break; - case 'M': *ScanCode = 0x32; *code |= 8; break; - case '=': *ScanCode = 0x0d; break; - case ',': *ScanCode = 0x33; break; - case ';': *ScanCode = 0x27; break; - case ')': *ScanCode = 0x0b; *code |= 8; break; - // fourth row -// case 9: *ScanCode = 0x0f; break; // tab - case '/': *ScanCode = 0x35; break; - case '?': *ScanCode = 0x35; *code |= 8; break; - case ' ': *ScanCode = 0x39; break; - case '\'': *ScanCode = 0x28; break; - case '"': *ScanCode = 0x28; *code |= 8; break; - case '~': *ScanCode = 0x29; *code |= 8; break; - case '.': *ScanCode = 0x34; break; - case ':': *ScanCode = 0x27; *code |= 8; break; - case '<': *ScanCode = 0x33; *code |= 8; break; -// case 13: *ScanCode = 0x1c; break; // enter - case '>': *ScanCode = 0x34; *code |= 8; break; - // others -// case 27: *ScanCode = 0x01; break; // esc - case '`': *ScanCode = 0x29; break; - case '^': *ScanCode = 0x07; *code |= 8; break; - case '[': *ScanCode = 0x1a; break; - case '{': *ScanCode = 0x1a; *code |= 8; break; - case ']': *ScanCode = 0x1b; break; - case '}': *ScanCode = 0x1b; *code |= 8; break; - case '\\': *ScanCode = 0x2b; break; - case '|': *ScanCode = 0x2b; *code |= 8; break; - // ctrl keys - case 1: *ScanCode = 0x1e; *code |= 16; break; // a - case 2: *ScanCode = 0x30; *code |= 16; break; // b - } - - if (*ScanCode == 0 && key < 3000) - printf("unknown key %d mod %d ascii %d\n", key, mod, ascii); - -} - -/******************************************************************************/ -QMyScrollView::QMyScrollView() : QScrollView() -{ -} - -/******************************************************************************/ -QMyScrollView::~QMyScrollView() -{ -} - -/******************************************************************************/ -void QMyScrollView::keyPressEvent(QKeyEvent* e) -{ - int ScanCode, code; - GetScanCode(e, &ScanCode, &code); - if (ScanCode != 0) - { - if (code & 8) // send shift - rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x2a, 0); - if (code & 16) // send control - rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x1d, 0); - if (code & 32) // send alt - rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x38, 0); - rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYPRESS, ScanCode, 0); - e->accept(); - } -} - -/******************************************************************************/ -void QMyScrollView::keyReleaseEvent(QKeyEvent* e) -{ - int ScanCode, code; - GetScanCode(e, &ScanCode, &code); - if (ScanCode != 0) - { - rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYRELEASE, ScanCode, 0); - if (code & 8) // send shift - rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYRELEASE, 0x2a, 0); - if (code & 16) // send control - rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYRELEASE, 0x1d, 0); - if (code & 32) // send alt - rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYRELEASE, 0x38, 0); - e->accept(); - } -} - -/******************************************************************************/ -void QMyScrollView::showEvent(QShowEvent* e) -{ - QScrollView::showEvent(e); -} - -/******************************************************************************/ -void QMyScrollView::show() -{ - QScrollView::show(); -} - -/******************************************************************************/ -void QMyScrollView::polish() -{ - QScrollView::polish(); -} - -/******************************************************************************/ -void QMyScrollView::timerEvent(QTimerEvent * e) -{ - QMyDialog * d; - QWidget * Desktop; - int dw; - int dh; - - QScrollView::timerEvent(e); - killTimer(timer_id); - d = new QMyDialog(this); - if (d->exec() == 1) // ok clicked - { - g_width = d->Width; - g_height = d->Height; - g_client_width = g_width; - g_client_height = g_height; - g_fullscreen = d->FullScreen; - sprintf(g_server, "%s", (const char*)d->ServerIP); - sprintf(g_username, "%s", (const char*)d->UserName); -#ifdef WITH_RDPSND - // init sound - if (g_rdpsnd) - { - rdpsnd_init(); - } -#endif - if (!rdp_connect(g_server, g_flags, g_domain, g_password, g_shell, - g_directory)) - { - delete d; - g_SV->close(); - return; - } - g_BS = (uint8*)xmalloc(g_width * g_height * 4); - memset(g_BS, 0, g_width * g_height * 4); - g_clipx = 0; - g_clipy = 0; - g_clipcx = g_width; - g_clipcy = g_height; - g_CM = (QColorMap*)xmalloc(sizeof(struct QColorMap)); - memset(g_CM, 0, sizeof(struct QColorMap)); - g_CM->NumColors = 256; - g_MW = new QMyMainWindow(); - g_MW->resize(g_client_width, g_client_height); - g_MW->show(); - g_SV->addChild(g_MW); - g_MW->setMouseTracking(true); - g_MW->setCursor((int)10); /* Qt::BlankCursor */ - g_SocketNotifier = new QSocketNotifier(g_global_sock, - QSocketNotifier::Read, - g_MW); - g_MW->connect(g_SocketNotifier, SIGNAL(activated(int)), g_MW, - SLOT(dataReceived())); - if (g_fullscreen) - { - Desktop = g_App->desktop(); - dw = Desktop->width(); - dh = Desktop->height(); - if (dw == g_client_width && dh == g_client_height) - { - g_MW->resize(g_client_width - 4, g_client_height - 4); - } - g_SV->showFullScreen(); - } - delete d; - } - else // cancel clicked - { - delete d; - g_SV->close(); - } -} - -/******************************************************************************/ -QMyMainWindow::QMyMainWindow() : QWidget(g_SV->viewport()) -{ - PopupMenu = new QPopupMenu(this); - PopupMenu->insertItem("Right click", 1, 0); - PopupMenu->insertItem("Toggle fullscreen", 2, 1); - PopupMenu->insertItem("Reset keyboard", 3, 2); - PopupMenu->insertItem("Double click", 4, 3); - connect(PopupMenu, SIGNAL(activated(int)), this, SLOT(MemuClicked(int))); -} - -/******************************************************************************/ -QMyMainWindow::~QMyMainWindow() -{ - delete PopupMenu; -} - -/******************************************************************************/ -int rd(double in) -{ - return (int)(in + 0.50); -} - -/******************************************************************************/ -int c2sx(int cx) -{ - double sx; - - sx = (double)g_client_width / (double)g_width; - return rd(cx / sx); -} - -/******************************************************************************/ -int c2sy(int cy) -{ - double sy; - - sy = (double)g_client_height / (double)g_height; - return rd(cy / sy); -} - -/******************************************************************************/ -void QMyMainWindow::timerEvent(QTimerEvent * e) -{ - QWidget::timerEvent(e); - if (e->timerId() == timer_id) - { - // send mouse up - rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON1, - rd(c2sx(mx)), rd(c2sy(my))); - // if in fullscreen, take it out or the menu won't work - if (g_fullscreen) - { - g_fullscreen = 0; - g_SV->showNormal(); - g_SV->showMaximized(); - } - else - PopupMenu->popup(mapToGlobal(QPoint(mx, my))); - } - killTimer(timer_id); -} - -/******************************************************************************/ -void QMyMainWindow::MemuClicked(int MenuID) -{ - QWidget * Desktop; - int dw; - int dh; - - if (MenuID == 1) // right click - { - rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON2, - rd(c2sx(mx)), rd(c2sy(my))); - rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON2, - rd(c2sx(mx)), rd(c2sy(my))); - } - else if (MenuID == 2) // toggle full screen - { - g_fullscreen = ~g_fullscreen; - if (g_fullscreen) - { - Desktop = g_App->desktop(); - dw = Desktop->width(); - dh = Desktop->height(); - if (dw == g_client_width && dh == g_client_height) - g_MW->resize(g_client_width - 4, g_client_height - 4); - g_SV->showFullScreen(); - } - else - { - g_SV->showNormal(); - g_SV->showMaximized(); - g_MW->resize(g_client_width, g_client_height); - } - } - else if (MenuID == 3) // reset keyboard - { - rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYRELEASE, 0x2a, 0); // shift - rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYRELEASE, 0x1d, 0); // control - rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYRELEASE, 0x38, 0); // alt - } - else if (MenuID == 4) // double click - { - rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON1, - rd(c2sx(mx)), rd(c2sy(my))); - rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON1, - rd(c2sx(mx)), rd(c2sy(my))); - rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON1, - rd(c2sx(mx)), rd(c2sy(my))); - rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON1, - rd(c2sx(mx)), rd(c2sy(my))); - } -} - -/******************************************************************************/ -void QMyMainWindow::mouseMoveEvent(QMouseEvent* e) -{ - int x, y; - - x = e->x(); - y = e->y(); - if (timer_id) - { - x = x - mx; - y = y - my; - if (x < -10 || x > 10 || y < -10 || y > 10) - { - killTimer(timer_id); - timer_id = 0; - } - } - rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE, c2sx(e->x()), - c2sy(e->y())); -} - -/******************************************************************************/ -void QMyMainWindow::mousePressEvent(QMouseEvent* e) -{ - timer_id = startTimer(1000); - mx = e->x(); - my = e->y(); - if (e->button() == LeftButton) - rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON1, - c2sx(e->x()), c2sy(e->y())); - else if (e->button() == RightButton) - rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON2, - c2sx(e->x()), c2sy(e->y())); - else if (e->button() == MidButton) - rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON3, - c2sx(e->x()), c2sy(e->y())); -} - -/******************************************************************************/ -void QMyMainWindow::mouseReleaseEvent(QMouseEvent* e) -{ - killTimer(timer_id); - timer_id = 0; - if (e->button() == LeftButton) - rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON1, c2sx(e->x()), - c2sy(e->y())); - else if (e->button() == RightButton) - rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON2, c2sx(e->x()), - c2sy(e->y())); - else if (e->button() == MidButton) - rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON3, c2sx(e->x()), - c2sy(e->y())); -} - -/******************************************************************************/ -void QMyMainWindow::wheelEvent(QWheelEvent* e) -{ - if (e->delta() > 0) - rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON4, c2sx(e->x()), - c2sy(e->y())); - else if (e->delta() < 0) - rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON5, c2sx(e->x()), - c2sy(e->y())); -} - -#define NOT(x) (~x) - -/******************************************************************************/ -int rop(int rop, int src, int dst) -{ - switch (rop) - { - case 0x0: return 0; - case 0x1: return NOT (src | dst); - case 0x2: return NOT (src) & dst; - case 0x3: return NOT (src); - case 0x4: return src & NOT (dst); - case 0x5: return NOT (dst); - case 0x6: return src ^ dst; - case 0x7: return NOT (src & dst); - case 0x8: return src & dst; - case 0x9: return NOT (src) ^ dst; - case 0xa: return dst; - case 0xb: return NOT (src) | dst; - case 0xc: return src; - case 0xd: return src | NOT (dst); - case 0xe: return src | dst; - case 0xf: return NOT (0); - } - return dst; -} - -/*****************************************************************************/ -int get_pixel(int x, int y) -{ - if (x >= 0 && x < g_width && y >= 0 && y < g_height) - { - if (g_server_bpp == 8) - return GETPIXEL8(g_BS, x, y, g_width); - else if (g_server_bpp == 16) - return GETPIXEL16(g_BS, x, y, g_width); - else if (g_server_bpp == 24) - return GETPIXEL32(g_BS, x, y, g_width); - else - return 0; - } - else - return 0; -} - -/******************************************************************************/ -void set_pixel(int x, int y, int pixel, int op = 0xc) -{ - int p; - - if (x >= g_clipx && x < (g_clipx + g_clipcx) && - y >= g_clipy && y < (g_clipy + g_clipcy)) - { - if (x >= 0 && x < g_width && y >= 0 && y < g_height) - { - if (op == 0xc) - { - if (g_server_bpp == 8) - { - SETPIXEL8(g_BS, x, y, g_width, pixel); - } - else if (g_server_bpp == 16) - { - SETPIXEL16(g_BS, x, y, g_width, pixel); - } - else if (g_server_bpp == 24) - { - SETPIXEL32(g_BS, x, y, g_width, pixel); - } - } - else - { - if (g_server_bpp == 8) - { - p = GETPIXEL8(g_BS, x, y, g_width); - p = rop(op, pixel, p); - SETPIXEL8(g_BS, x, y, g_width, p); - } - else if (g_server_bpp == 16) - { - p = GETPIXEL16(g_BS, x, y, g_width); - p = rop(op, pixel, p); - SETPIXEL16(g_BS, x, y, g_width, p); - } - else if (g_server_bpp == 24) - { - p = GETPIXEL32(g_BS, x, y, g_width); - p = rop(op, pixel, p); - SETPIXEL32(g_BS, x, y, g_width, p); - } - } - } - } -} - -/******************************************************************************/ -// adjust coordinates for cliping rect -bool WarpCoords(int * x, int * y, int * cx, int * cy, int * srcx, int * srcy) -{ - int dx, dy; - QRect InRect(*x, *y, *cx, *cy); - QRect OutRect; - QRect CRect(g_clipx, g_clipy, g_clipcx, g_clipcy); - OutRect = InRect.intersect(CRect); - if (OutRect.isEmpty()) - return false; - dx = OutRect.x() - InRect.x(); - dy = OutRect.y() - InRect.y(); - *x = OutRect.x(); - *y = OutRect.y(); - *cx = OutRect.width(); - *cy = OutRect.height(); - if (srcx != NULL) - *srcx = *srcx + dx; - if (srcy != NULL) - *srcy = *srcy + dy; - return true; -} - -/******************************************************************************/ -void QMyMainWindow::paintEvent(QPaintEvent * pe) -{ - QImage * Image; - QPainter * Painter; - QRect Rect; - int i, j, w, h, l, t, pixel, r, g, b; - uint8 * data; - double sx, sy; - - Image = 0; - data = 0; - if (!testWFlags(WRepaintNoErase)) - setWFlags(WRepaintNoErase); - if (g_CM != NULL || g_server_bpp > 8) - { - sx = (double)g_client_width / (double)g_width; - sy = (double)g_client_height / (double)g_height; - Rect = pe->rect(); - l = rd(Rect.left() / sx); - t = rd(Rect.top() / sy); - w = rd(Rect.width() / sx); - h = rd(Rect.height() / sy); - if (w > 0 && h > 0) - { - if (g_server_bpp == 8 && g_CM->NumColors > 0) - { - w = (w + 3) & ~3; - data = (uint8*)xmalloc(w * h); - for (i = 0; i < h; i++) - for (j = 0; j < w; j++) - data[i * w + j] = GETPIXEL8(g_BS, l + j, t + i, g_width); - Image = new QImage(data, w, h, 8,(QRgb*)g_CM->RGBColors, - g_CM->NumColors, QImage::IgnoreEndian); - } - else if (g_server_bpp == 16) - { - w = (w + 3) & ~3; - data = (uint8*)xmalloc(w * h * 4); - for (i = 0; i < h; i++) - for (j = 0; j < w; j++) - { - pixel = GETPIXEL16(g_BS, l + j, t + i, g_width); - r = ((pixel >> 8) & 0xf8) | ((pixel >> 13) & 0x7); - g = ((pixel >> 3) & 0xfc) | ((pixel >> 9) & 0x3); - b = ((pixel << 3) & 0xf8) | ((pixel >> 2) & 0x7); - pixel = ((r << 16) | (g << 8) | b); - SETPIXEL32(data, j, i, w, pixel); - } - Image = new QImage(data, w, h, 32, NULL, - 0, QImage::IgnoreEndian); - } - else if (g_server_bpp == 24) - { - w = (w + 3) & ~3; - data = (uint8*)xmalloc(w * h * 4); - for (i = 0; i < h; i++) - for (j = 0; j < w; j++) - { - pixel = GETPIXEL32(g_BS, l + j, t + i, g_width); - r = (pixel >> 0) & 0xff; - g = (pixel >> 8) & 0xff; - b = (pixel >> 16) & 0xff; - pixel = ((r << 16) | (g << 8) | b); - SETPIXEL32(data, j, i, w, pixel); - } - Image = new QImage(data, w, h, 32, NULL, - 0, QImage::IgnoreEndian); - } - if (Image != 0) - { - Painter = new QPainter(this); - Painter->scale(sx, sy); - Painter->drawImage(l, t, *Image, 0, 0, w, h); - delete Painter; - delete Image; - } - xfree(data); - } - } -} - -/******************************************************************************/ -void QMyMainWindow::closeEvent(QCloseEvent * e) -{ - e->accept(); -} - -/******************************************************************************/ -void QMyMainWindow::dataReceived() -{ - if (!rdp_loop(&g_deactivated, &g_ext_disc_reason)) - g_SV->close(); -#ifdef WITH_RDPSND - if (g_dsp_busy) - { - if (g_SoundNotifier == 0) - { - g_SoundNotifier = new QSocketNotifier(g_dsp_fd, QSocketNotifier::Write, - g_MW); - g_MW->connect(g_SoundNotifier, SIGNAL(activated(int)), g_MW, - SLOT(soundSend())); - } - else - { - if (!g_SoundNotifier->isEnabled()) - g_SoundNotifier->setEnabled(true); - } - } -#endif -} - -/******************************************************************************/ -void QMyMainWindow::soundSend() -{ -#ifdef WITH_RDPSND - g_SoundNotifier->setEnabled(false); - wave_out_play(); - if (g_dsp_busy) - { - g_SoundNotifier->setEnabled(true); - } -#endif -} - -/******************************************************************************/ -void redraw(int x, int y, int cx, int cy) -{ - double sx, sy; - - if (WarpCoords(&x, &y, &cx, &cy, NULL, NULL)) - { - sx = (double)g_client_width / (double)g_width; - sy = (double)g_client_height / (double)g_height; - x = rd(x * sx); - y = rd(y * sy); - cx = rd(cx * sx); - cy = rd(cy * sy); - g_MW->update(x, y, cx, cy); - } -} - -/******************************************************************************/ -/* Returns 0 after user quit, 1 otherwise */ -int ui_select(int rdp_socket) -{ - if (g_global_sock == 0) - g_global_sock = rdp_socket; - return 1; -} - -/******************************************************************************/ -void ui_move_pointer(int /*x*/, int /*y*/) -{ -} - -/******************************************************************************/ -void ui_set_null_cursor(void) -{ -} - -/******************************************************************************/ -HBITMAP ui_create_bitmap(int width, int height, uint8 * data) -{ - struct bitmap * the_bitmap; - uint8 * bitmap_data; - int i, j; - int r, g, b, pixel; - - bitmap_data = (uint8*)xmalloc(width * height * 4); - the_bitmap = (struct bitmap*)xmalloc(sizeof(struct bitmap)); - the_bitmap->w = width; - the_bitmap->h = height; - the_bitmap->data = bitmap_data; - if (g_server_bpp == 8) - { - for (i = 0; i < height; i++) - for (j = 0; j < width; j++) - bitmap_data[i * width + j] = data[i * width + j]; - } - else if (g_server_bpp == 16) - { - for (i = 0; i < height; i++) - for (j = 0; j < width; j++) - *(((uint16*)bitmap_data) + (i * width + j)) = - *(((uint16*)data) + (i * width + j)); - } - else if (g_server_bpp == 24) - { - for (i = 0; i < height; i++) - for (j = 0; j < width; j++) - { - r = data[(i * width + j) * 3 + 0]; - g = data[(i * width + j) * 3 + 1]; - b = data[(i * width + j) * 3 + 2]; - pixel = (r << 16) | (g << 8) | b; - SETPIXEL32(bitmap_data, j, i, width, pixel); - } - } - return the_bitmap; -} - -/******************************************************************************/ -void ui_paint_bitmap(int x, int y, int cx, int cy, int width, - int height, uint8 * data) -{ - int i, j; - int r, g, b, pixel; - - if (g_server_bpp == 8) - { - for (i = 0; i < cy; i++) - for (j = 0; j < cx; j++) - if (i < height) - if (j < width) - set_pixel(x + j, y + i, data[i * width + j]); - } - else if (g_server_bpp == 16) - { - for (i = 0; i < cy; i++) - for (j = 0; j < cx; j++) - if (i < height) - if (j < width) - set_pixel(x + j, y + i, *(((uint16*)data) + (i * width + j))); - } - else if (g_server_bpp == 24) - { - for (i = 0; i < cy; i++) - for (j = 0; j < cx; j++) - if (i < height) - if (j < width) - { - r = data[(i * width + j) * 3 + 0]; - g = data[(i * width + j) * 3 + 1]; - b = data[(i * width + j) * 3 + 2]; - pixel = (r << 16) | (g << 8) | b; - set_pixel(x + j, y + i, pixel); - } - } - redraw(x, y, cx, cy); -} - -/******************************************************************************/ -void ui_destroy_bitmap(HBITMAP bmp) -{ - struct bitmap* the_bitmap; - - the_bitmap = (struct bitmap*)bmp; - if (the_bitmap != NULL) - { - if (the_bitmap->data != NULL) - xfree(the_bitmap->data); - xfree(the_bitmap); - } -} - -/******************************************************************************/ -bool is_pixel_on(uint8 * data, int x, int y, int width, int bpp) -{ - int start, shift; - - if (bpp == 1) - { - width = (width + 7) / 8; - start = (y * width) + x / 8; - shift = x % 8; - return (data[start] & (0x80 >> shift)) != 0; - } - else if (bpp == 8) - return data[y * width + x] != 0; - else - return false; -} - -/******************************************************************************/ -void set_pixel_on(uint8 * data, int x, int y, int width, int bpp, uint8 pixel) -{ - if (bpp == 8) - data[y * width + x] = pixel; -} - -/******************************************************************************/ -HGLYPH ui_create_glyph(int width, int height, uint8 * data) -{ - int i, j; - uint8* glyph_data; - struct bitmap* the_glyph; - - glyph_data = (uint8*)xmalloc(width * height); - the_glyph = (struct bitmap*)xmalloc(sizeof(struct bitmap)); - the_glyph->w = width; - the_glyph->h = height; - the_glyph->data = glyph_data; - memset(glyph_data, 0, width * height); - for (i = 0; i < height; i++) - for (j = 0; j < width; j++) - if (is_pixel_on(data, j, i, width, 1)) - set_pixel_on(glyph_data, j, i, width, 8, 255); - return the_glyph; -} - -/******************************************************************************/ -void ui_destroy_glyph(HGLYPH glyph) -{ - struct bitmap* the_glyph; - - the_glyph = (struct bitmap*)glyph; - if (the_glyph != NULL) - { - if (the_glyph->data != NULL) - xfree(the_glyph->data); - xfree(the_glyph); - } -} - -/******************************************************************************/ -HCURSOR ui_create_cursor(uint32 x, uint32 y, - int width, int height, - uint8 * andmask, uint8 * xormask) -{ - return (void*)1; -} - -/******************************************************************************/ -void ui_set_cursor(HCURSOR /*cursor*/) -{ -} - -/*****************************************************************************/ -uint16 ui_get_numlock_state(uint32 state) -{ - return 0; -} - -/*****************************************************************************/ -unsigned int read_keyboard_state(void) -{ - return 0; -} - -/*****************************************************************************/ -void ui_resize_window(void) -{ -} - -/*****************************************************************************/ -void ui_polygon(uint8 opcode, uint8 fillmode, POINT * point, int npoints, - BRUSH * brush, int bgcolour, int fgcolour) -{ -} - -/*****************************************************************************/ -/* todo, use qt function for this (QPainter::drawPolyline) */ -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) -{ -} - -/******************************************************************************/ -void ui_destroy_cursor(HCURSOR /*cursor*/) -{ -} - -/******************************************************************************/ -HCOLOURMAP ui_create_colourmap(COLOURMAP * colours) -{ - int i; - int x; - uint8 r, g, b; - i = 0; - while (i < colours->ncolours && i < 256) - { - r = colours->colours[i].red; - g = colours->colours[i].green; - b = colours->colours[i].blue; - x = (r << 16) | (g << 8) | b; - g_CM->RGBColors[i] = x; - i++; - } - g_CM->NumColors = colours->ncolours; - return g_CM; -} - -/******************************************************************************/ -void ui_set_colourmap(HCOLOURMAP map) -{ -} - -/******************************************************************************/ -void ui_destroy_colourmap(HCOLOURMAP map) -{ -} - -/******************************************************************************/ -void ui_begin_update(void) -{ -} - -/******************************************************************************/ -void ui_end_update(void) -{ -} - -/******************************************************************************/ -void ui_set_clip(int x, int y, int cx, int cy) -{ - g_clipx = x; - g_clipy = y; - g_clipcx = cx; - g_clipcy = cy; -} - -/******************************************************************************/ -void ui_reset_clip(void) -{ - g_clipx = 0; - g_clipy = 0; - g_clipcx = g_width; - g_clipcy = g_height; -} - -/******************************************************************************/ -void ui_bell(void) -{ - g_App->beep(); -} - -/******************************************************************************/ -void ui_destblt(uint8 opcode, int x, int y, int cx, int cy) -{ - int i, j; - - - if (opcode == 0x0) /* black */ - { - for (i = 0; i < cy; i++) - for (j = 0; j < cx; j++) - set_pixel(x + j, y + i, 0, 0xc); - } - else if (opcode == 0xf) /* white */ - { - for (i = 0; i < cy; i++) - for (j = 0; j < cx; j++) - set_pixel(x + j, y + i, 0xffffff, 0xc); - } - else - { - for (i = 0; i < cy; i++) - for (j = 0; j < cx; j++) - set_pixel(x + j, y + i, get_pixel(x + j, y + i), opcode); - } - redraw(x, y, cx, cy); -} - -/******************************************************************************/ -// does not repaint -void fill_rect(int x, int y, int cx, int cy, int colour, int opcode = 0xc) -{ - int i, j; - - if (x + cx > g_width) - cx = g_width - x; - if (y + cy > g_height) - cy = g_height - y; -#ifdef QT_OPTI - if (opcode == 0xc) /* optimize */ - { - if (WarpCoords(&x, &y, &cx, &cy, 0, 0)) - { - if (g_server_bpp == 8) - { - for (i = 0; i < cy; i++) - for (j = 0; j < cx; j++) - SETPIXEL8(g_BS, x + j, y + i, g_width, colour); - } - else if (g_server_bpp == 16) - { - for (i = 0; i < cy; i++) - for (j = 0; j < cx; j++) - SETPIXEL16(g_BS, x + j, y + i, g_width, colour); - } - else if (g_server_bpp == 24) - { - for (i = 0; i < cy; i++) - for (j = 0; j < cx; j++) - SETPIXEL32(g_BS, x + j, y + i, g_width, colour); - } - } - } - else -#endif - { - for (i = 0; i < cy; i++) - for (j = 0; j < cx; j++) - set_pixel(x + j, y + i, colour, opcode); - } -} - -/******************************************************************************/ -void ui_rect(int x, int y, int cx, int cy, int colour) -{ - fill_rect(x, y, cx, cy, colour); - redraw(x, y, cx, cy); -} - -/******************************************************************************/ -void ui_patblt(uint8 opcode, int x, int y, int cx, int cy, - BRUSH * brush, int bgcolour, int fgcolour) -{ - int i, j; - uint8 ipattern[8]; - - switch (brush->style) - { - case 0: - fill_rect(x, y, cx, cy, fgcolour, opcode); - break; - case 3: - for (i = 0; i < 8; i++) - ipattern[i] = ~brush->pattern[7 - i]; - for (i = 0; i < cy; i++) - for (j = 0; j < cx; j++) - if (is_pixel_on(ipattern, (x + j + brush->xorigin) % 8, - (y + i + brush->yorigin) % 8, 8, 1)) - set_pixel(x + j, y + i, fgcolour, opcode); - else - set_pixel(x + j, y + i, bgcolour, opcode); - break; - } - redraw(x, y, cx, cy); -} - -/******************************************************************************/ -void ui_screenblt(uint8 opcode, int x, int y, int cx, int cy, - int srcx, int srcy) -{ - int i, j, pixel; - uint8 * temp; - - temp = (uint8*)xmalloc(cx * cy * 4); -#ifdef QT_OPTI - if (opcode == 0xc) - { - if (WarpCoords(&x, &y, &cx, &cy, &srcx, &srcy)) - { - if (g_server_bpp == 8) - { - for (i = 0; i < cy; i++) - for (j = 0; j < cx; j++) - { - pixel = GETPIXEL8(g_BS, srcx + j, srcy + i, g_width); - SETPIXEL8(temp, j, i, cx, pixel); - } - for (i = 0; i < cy; i++) - for (j = 0; j < cx; j++) - { - pixel = GETPIXEL8(temp, j, i, cx); - SETPIXEL8(g_BS, x + j, y + i, g_width, pixel); - } - } - else if (g_server_bpp == 16) - { - for (i = 0; i < cy; i++) - for (j = 0; j < cx; j++) - { - pixel = GETPIXEL16(g_BS, srcx + j, srcy + i, g_width); - SETPIXEL16(temp, j, i, cx, pixel); - } - for (i = 0; i < cy; i++) - for (j = 0; j < cx; j++) - { - pixel = GETPIXEL16(temp, j, i, cx); - SETPIXEL16(g_BS, x + j, y + i, g_width, pixel); - } - } - else if (g_server_bpp == 24) - { - for (i = 0; i < cy; i++) - for (j = 0; j < cx; j++) - { - pixel = GETPIXEL32(g_BS, srcx + j, srcy + i, g_width); - SETPIXEL32(temp, j, i, cx, pixel); - } - for (i = 0; i < cy; i++) - for (j = 0; j < cx; j++) - { - pixel = GETPIXEL32(temp, j, i, cx); - SETPIXEL32(g_BS, x + j, y + i, g_width, pixel); - } - } - } - } - else -#endif - { - if (g_server_bpp == 8) - { - for (i = 0; i < cy; i++) - for (j = 0; j < cx; j++) - temp[i * cx + j] = get_pixel(srcx + j, srcy + i); - for (i = 0; i < cy; i++) - for (j = 0; j < cx; j++) - set_pixel(x + j, y + i, temp[i * cx + j], opcode); - } - else if (g_server_bpp == 16) - { - for (i = 0; i < cy; i++) - for (j = 0; j < cx; j++) - { - pixel = get_pixel(srcx + j, srcy + i); - SETPIXEL16(temp, j, i, cx, pixel); - } - for (i = 0; i < cy; i++) - for (j = 0; j < cx; j++) - { - pixel = GETPIXEL16(temp, j, i, cx); - set_pixel(x + j, y + i, pixel, opcode); - } - } - else if (g_server_bpp == 24) - { - for (i = 0; i < cy; i++) - for (j = 0; j < cx; j++) - *(((uint32*)temp) + (i * cx + j)) = get_pixel(srcx + j, srcy + i); - for (i = 0; i < cy; i++) - for (j = 0; j < cx; j++) - set_pixel(x + j, y + i, *(((uint32*)temp) + (i * cx + j)), opcode); - } - } - xfree(temp); - redraw(x, y, cx, cy); -} - -/******************************************************************************/ -void ui_memblt(uint8 opcode, int x, int y, int cx, int cy, - HBITMAP src, int srcx, int srcy) -{ - int i, j, p; - struct bitmap * the_bitmap; - - the_bitmap = (struct bitmap*)src; - if (the_bitmap == NULL) - return; -#ifdef QT_OPTI - if (opcode == 0xc) /* optimize */ - { - if (WarpCoords(&x, &y, &cx, &cy, &srcx, &srcy)) - { - if (g_server_bpp == 8) - { - for (i = 0; i < cy; i++) - for (j = 0; j < cx; j++) - { - p = GETPIXEL8(the_bitmap->data, srcx + j, srcy + i, the_bitmap->w); - SETPIXEL8(g_BS, x + j, y + i, g_width, p); - } - } - else if (g_server_bpp == 16) - { - for (i = 0; i < cy; i++) - for (j = 0; j < cx; j++) - { - p = GETPIXEL16(the_bitmap->data, srcx + j, srcy + i, the_bitmap->w); - SETPIXEL16(g_BS, x + j, y + i, g_width, p); - } - } - else if (g_server_bpp == 24) - { - for (i = 0; i < cy; i++) - for (j = 0; j < cx; j++) - { - p = GETPIXEL32(the_bitmap->data, srcx + j, srcy + i, the_bitmap->w); - SETPIXEL32(g_BS, x + j, y + i, g_width, p); - } - } - } - } - else -#endif - { - if (g_server_bpp == 8) - { - for (i = 0; i < cy; i++) - for (j = 0; j < cx; j++) - if ((i + srcy) < the_bitmap->h && (j + srcx) < the_bitmap->w) - set_pixel(x + j, y + i, - the_bitmap->data[(i + srcy) * the_bitmap->w + (j + srcx)], - opcode); - } - else if (g_server_bpp == 16) - { - for (i = 0; i < cy; i++) - for (j = 0; j < cx; j++) - if ((i + srcy) < the_bitmap->h && (j + srcx) < the_bitmap->w) - set_pixel(x + j, y + i, - *(((uint16*)the_bitmap->data) + ((i + srcy) * the_bitmap->w + (j + srcx))), - opcode); - } - else if (g_server_bpp == 24) - { - for (i = 0; i < cy; i++) - for (j = 0; j < cx; j++) - if ((i + srcy) < the_bitmap->h && (j + srcx) < the_bitmap->w) - set_pixel(x + j, y + i, - *(((uint32*)the_bitmap->data) + ((i + srcy) * the_bitmap->w + (j + srcx))), - opcode); - } - } - redraw(x, y, cx, cy); -} - -/******************************************************************************/ -// not used -void ui_triblt(uint8 opcode, int x, int y, int cx, int cy, - HBITMAP src, int srcx, int srcy, BRUSH * brush, - int bgcolour, int fgcolour) -{ -} - -/******************************************************************************/ -/* Bresenham's line drawing algorithm */ -void ui_line(uint8 opcode, int startx, int starty, int endx, - int endy, PEN * pen) -{ - int dx, dy, incx, incy, dpr, dpru, p, left, top, right, bottom; - - if (startx > endx) - { - dx = startx - endx; - incx = -1; - left = endx; - right = startx; - } - else - { - dx = endx - startx; - incx = 1; - left = startx; - right = endx; - } - if (starty > endy) - { - dy = starty - endy; - incy = -1; - top = endy; - bottom = starty; - } - else - { - dy = endy - starty; - incy = 1; - top = starty; - bottom = endy; - } - if (dx >= dy) - { - dpr = dy << 1; - dpru = dpr - (dx << 1); - p = dpr - dx; - for (; dx >= 0; dx--) - { - set_pixel(startx, starty, pen->colour, opcode); - if (p > 0) - { - startx += incx; - starty += incy; - p += dpru; - } - else - { - startx += incx; - p += dpr; - } - } - } - else - { - dpr = dx << 1; - dpru = dpr - (dy << 1); - p = dpr - dy; - for (; dy >= 0; dy--) - { - set_pixel(startx, starty, pen->colour, opcode); - if (p > 0) - { - startx += incx; - starty += incy; - p += dpru; - } - else - { - starty += incy; - p += dpr; - } - } - } - redraw(left, top, (right - left) + 1, (bottom - top) + 1); -} - -/******************************************************************************/ -void draw_glyph (int x, int y, HGLYPH glyph, int fgcolour) -{ - struct bitmap *the_glyph; - int i, j; - - the_glyph = (struct bitmap*)glyph; - if (the_glyph == NULL) - return; - for (i = 0; i < the_glyph->h; i++) - for (j = 0; j < the_glyph->w; j++) - if (is_pixel_on(the_glyph->data, j, i, the_glyph->w, 8)) - set_pixel(x + j, y + i, fgcolour); -} - -#define DO_GLYPH(ttext,idx) \ -{\ - glyph = cache_get_font (font, ttext[idx]);\ - if (!(flags & TEXT2_IMPLICIT_X))\ - {\ - xyoffset = ttext[++idx];\ - if ((xyoffset & 0x80))\ - {\ - if (flags & TEXT2_VERTICAL) \ - y += ttext[idx+1] | (ttext[idx+2] << 8);\ - else\ - x += ttext[idx+1] | (ttext[idx+2] << 8);\ - idx += 2;\ - }\ - else\ - {\ - if (flags & TEXT2_VERTICAL) \ - y += xyoffset;\ - else\ - x += xyoffset;\ - }\ - }\ - if (glyph != NULL)\ - {\ - draw_glyph (x + glyph->offset, y + glyph->baseline, glyph->pixmap, fgcolour);\ - if (flags & TEXT2_IMPLICIT_X)\ - x += glyph->width;\ - }\ -} - -/******************************************************************************/ -//***************************************************************************** -void ui_draw_text(uint8 font, uint8 flags, 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) -{ - FONTGLYPH * glyph; - int i, j, xyoffset; - DATABLOB * entry; - - if (boxx + boxcx > g_width) - boxcx = g_width - boxx; - if (boxy + boxcy > g_height) - boxcy = g_height - boxy; - - if (boxcx > 1) - fill_rect(boxx, boxy, boxcx, boxcy, bgcolour); - else if (mixmode == MIX_OPAQUE) - fill_rect(clipx, clipy, clipcx, clipcy, bgcolour); - - /* Paint text, character by character */ - for (i = 0; i < length;) - { - switch (text[i]) - { - case 0xff: - if (i + 2 < length) - cache_put_text(text[i + 1], text, text[i + 2]); - else - { - error("this shouldn't be happening\n"); - exit(1); - } - /* this will move pointer from start to first character after FF command */ - length -= i + 3; - text = &(text[i + 3]); - i = 0; - break; - - case 0xfe: - entry = cache_get_text(text[i + 1]); - if (entry != NULL) - { - if ((((uint8 *) (entry->data))[1] == 0) && (!(flags & TEXT2_IMPLICIT_X))) - { - if (flags & TEXT2_VERTICAL) - y += text[i + 2]; - else - x += text[i + 2]; - } - for (j = 0; j < entry->size; j++) - DO_GLYPH(((uint8 *) (entry->data)), j); - } - if (i + 2 < length) - i += 3; - else - i += 2; - length -= i; - /* this will move pointer from start to first character after FE command */ - text = &(text[i]); - i = 0; - break; - - default: - DO_GLYPH(text, i); - i++; - break; - } - } - if (boxcx > 1) - redraw(boxx, boxy, boxcx, boxcy); - else - redraw(clipx, clipy, clipcx, clipcy); -} - -/******************************************************************************/ -void ui_desktop_save(uint32 offset, int x, int y, int cx, int cy) -{ - uint8 * data; - int i, j, Bpp, pixel; - - Bpp = 4; - switch (g_server_bpp) - { - case 8: Bpp = 1; break; - case 15: Bpp = 2; break; - case 16: Bpp = 2; break; - } - data = (uint8*)xmalloc(cx * cy * Bpp); - if (g_server_bpp == 8) - { - for (i = 0; i < cy; i++) - for (j = 0; j < cx; j++) - { - pixel = get_pixel(x + j, y + i); - SETPIXEL8(data, j, i, cx, pixel); - } - } - else if (g_server_bpp == 16) - { - for (i = 0; i < cy; i++) - for (j = 0; j < cx; j++) - { - pixel = get_pixel(x + j, y + i); - SETPIXEL16(data, j, i, cx, pixel); - } - } - else if (g_server_bpp == 24) - { - for (i = 0; i < cy; i++) - for (j = 0; j < cx; j++) - *(((uint32*)data) + (i * cx + j)) = get_pixel(x + j, y + i); - } - offset *= Bpp; - cache_put_desktop(offset, cx, cy, cx * Bpp, Bpp, data); - xfree(data); -} - -/******************************************************************************/ -void ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy) -{ - uint8 * data; - int i, j; - int Bpp; - - Bpp = 4; - switch (g_server_bpp) - { - case 8: Bpp = 1; break; - case 15: Bpp = 2; break; - case 16: Bpp = 2; break; - } - offset *= Bpp; - data = cache_get_desktop(offset, cx, cy, Bpp); - if (g_server_bpp == 8) - { - for (i = 0; i < cy; i++) - for (j = 0; j < cx; j++) - set_pixel(x + j, y + i, data[i * cx + j]); - } - else if (g_server_bpp == 16) - { - for (i = 0; i < cy; i++) - for (j = 0; j < cx; j++) - set_pixel(x + j, y + i, *(((uint16*)data) + (i * cx + j))); - } - else if (g_server_bpp == 24) - { - for (i = 0; i < cy; i++) - for (j = 0; j < cx; j++) - set_pixel(x + j, y + i, *(((uint32*)data) + (i * cx + j))); - } - redraw(x, y, cx, cy); -} - -/*****************************************************************************/ -void * xrealloc(void * in_val, int size) -{ - if (size < 1) - { - size = 1; - } - return realloc(in_val, size); -} - -/*****************************************************************************/ -void * xmalloc(int size) -{ - return malloc(size); -} - -/*****************************************************************************/ -void xfree(void * in_val) -{ - if (in_val != NULL) - { - free(in_val); - } -} - -/*****************************************************************************/ -char * xstrdup(const char * s) -{ - char * mem = strdup(s); - if (mem == NULL) - { - perror("strdup"); - exit(1); - } - return mem; -} - -/*****************************************************************************/ -void warning(char * format, ...) -{ - va_list ap; - - fprintf(stderr, "WARNING: "); - va_start(ap, format); - vfprintf(stderr, format, ap); - va_end(ap); -} - -/*****************************************************************************/ -void unimpl(char * format, ...) -{ - va_list ap; - - fprintf(stderr, "NOT IMPLEMENTED: "); - va_start(ap, format); - vfprintf(stderr, format, ap); - va_end(ap); -} - -/*****************************************************************************/ -void error(char * format, ...) -{ - va_list ap; - - fprintf(stderr, "ERROR: "); - va_start(ap, format); - vfprintf(stderr, format, ap); - va_end(ap); -} - -/*****************************************************************************/ -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; -} - -/*****************************************************************************/ -int load_licence(uint8 ** data) -{ - return 0; -} - -/*****************************************************************************/ -void save_licence(uint8 * data, int length) -{ -} - -/*****************************************************************************/ -void generate_random(uint8 * random) -{ - QFile File("/dev/random"); - File.open(IO_ReadOnly); - if (File.readBlock((char*)random, 32) == 32) - { - return; - } - warning("no /dev/random\n"); - memcpy(random, "12345678901234567890123456789012", 32); -} - -/*****************************************************************************/ -/* produce a hex dump */ -void hexdump(uint8 * p, uint32 len) -{ - uint8 * line = p; - int i, thisline; - uint32 offset = 0; - - while (offset < 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; - } -} - -/*****************************************************************************/ -void get_username_and_hostname(void) -{ - char fullhostname[64]; - char * p; - struct passwd * pw; - - STRNCPY(g_username, "unknown", sizeof(g_username)); - STRNCPY(g_hostname, "unknown", sizeof(g_hostname)); - pw = getpwuid(getuid()); - if (pw != NULL && pw->pw_name != NULL) - { - STRNCPY(g_username, pw->pw_name, sizeof(g_username)); - } - if (gethostname(fullhostname, sizeof(fullhostname)) != -1) - { - p = strchr(fullhostname, '.'); - if (p != NULL) - { - *p = 0; - } - STRNCPY(g_hostname, fullhostname, sizeof(g_hostname)); - } -} - -/*****************************************************************************/ -void out_params(void) -{ - fprintf(stderr, "qterdesktop: A Remote Desktop Protocol client.\n"); - fprintf(stderr, "Version " VERSION ". Copyright (C) 1999-2004 Matt Chapman.\n"); - fprintf(stderr, "See http://www.rdesktop.org/ for more information.\n\n"); - fprintf(stderr, "Usage: qterdesktop [options] server\n"); - fprintf(stderr, " -g: desktop geometry (WxH)\n"); - fprintf(stderr, " -4: use RDP version 4\n"); - fprintf(stderr, " -5: use RDP version 5 (default)\n"); - fprintf(stderr, " -t: tcp port)\n"); - fprintf(stderr, " -a: connection colour depth\n"); - fprintf(stderr, " -u: user name\n"); - fprintf(stderr, " -d: domain\n"); - fprintf(stderr, " -s: shell\n"); - fprintf(stderr, " -c: working directory\n"); - fprintf(stderr, " -p: password (- to prompt)\n"); - fprintf(stderr, " -n: client hostname\n"); - fprintf(stderr, " -f: full screen\n"); - fprintf(stderr, " -r sound: enable sound\n"); - fprintf(stderr, "\n"); -} - -/*****************************************************************************/ -int parse_parameters(int in_argc, char ** in_argv) -{ - int i; - char * p; - - for (i = 1; i < in_argc; i++) - { - strcpy(g_server, in_argv[i]); - if (strcmp(in_argv[i], "-h") == 0) - { - out_params(); - return 0; - } - else if (strcmp(in_argv[i], "-g") == 0) - { - g_width = strtol(in_argv[i + 1], &p, 10); - if (*p == 'x') - { - g_height = strtol(p + 1, &p, 10); - } - if (*p == '-') - { - g_client_width = strtol(p + 1, &p, 10); - } - else - { - g_client_width = g_width; - g_client_height = g_height; - } - if (*p == 'x') - { - g_client_height = strtol(p + 1, NULL, 10); - } - g_width = (g_width + 3) & ~3; - g_height = (g_height + 3) & ~3; - g_client_width = (g_client_width + 3) & ~3; - g_client_height = (g_client_height + 3) & ~3; - i++; - } - else if (strcmp(in_argv[i], "-4") == 0) - { - g_use_rdp5 = 0; - } - else if (strcmp(in_argv[i], "-5") == 0) - { - g_use_rdp5 = 1; - } - else if (strcmp(in_argv[i], "-a") == 0) - { - g_server_bpp = strtol(in_argv[i + 1], &p, 10); - if (g_server_bpp != 8 && - g_server_bpp != 16 && g_server_bpp != 24) - { - error("invalid bpp\n"); - return 0; - } - i++; - } - else if (strcmp(in_argv[i], "-t") == 0) - { - g_tcp_port_rdp = strtol(in_argv[i + 1], &p, 10); - i++; - } - else if (strcmp(in_argv[i], "-u") == 0) - { - STRNCPY(g_username, in_argv[i + 1], sizeof(g_username)); - i++; - } - else if (strcmp(in_argv[i], "-d") == 0) - { - STRNCPY(g_domain, in_argv[i + 1], sizeof(g_domain)); - i++; - } - else if (strcmp(in_argv[i], "-s") == 0) - { - STRNCPY(g_shell, in_argv[i + 1], sizeof(g_shell)); - i++; - } - else if (strcmp(in_argv[i], "-c") == 0) - { - STRNCPY(g_directory, in_argv[i + 1], sizeof(g_directory)); - i++; - } - else if (strcmp(in_argv[i], "-p") == 0) - { - STRNCPY(g_password, in_argv[i + 1], sizeof(g_password)); - g_flags |= RDP_LOGON_AUTO; - i++; - } - else if (strcmp(in_argv[i], "-n") == 0) - { - STRNCPY(g_hostname, in_argv[i + 1], sizeof(g_hostname)); - i++; - } - else if (strcmp(in_argv[i], "-f") == 0) - { - g_fullscreen = 1; - } - else if (strcmp(in_argv[i], "-r") == 0) - { - if (strcmp(in_argv[i + 1], "sound") == 0) - { -#ifdef WITH_RDPSND - g_rdpsnd = 1; -#endif - } - i++; - } - } - return 1; -} - -/******************************************************************************/ -int param_connect(void) -{ - QWidget * Desktop; - int dw, dh; - -#ifdef WITH_RDPSND - // init sound - if (g_rdpsnd) - { - rdpsnd_init(); - } -#endif - if (rdp_connect(g_server, g_flags, g_domain, g_password, g_shell, - g_directory)) - { - g_BS = (uint8*)xmalloc(g_width * g_height * 4); - memset(g_BS, 0, g_width * g_height * 4); - g_clipx = 0; - g_clipy = 0; - g_clipcx = g_width; - g_clipcy = g_height; - g_CM = (QColorMap*)xmalloc(sizeof(struct QColorMap)); - memset(g_CM, 0, sizeof(struct QColorMap)); - g_CM->NumColors = 256; - g_MW = new QMyMainWindow(); - g_MW->resize(g_client_width, g_client_height); - g_MW->show(); - g_SV->addChild(g_MW); - g_MW->setMouseTracking(true); - g_SocketNotifier = new QSocketNotifier(g_global_sock, - QSocketNotifier::Read, - g_MW); - g_MW->connect(g_SocketNotifier, SIGNAL(activated(int)), g_MW, - SLOT(dataReceived())); - if (g_fullscreen) - { - Desktop = g_App->desktop(); - dw = Desktop->width(); - dh = Desktop->height(); - if (dw == g_client_width && dh == g_client_height) - { - g_MW->resize(g_client_width - 4, g_client_height - 4); - } - g_SV->showFullScreen(); - } - g_MW->setCursor((int)10); /* Qt::BlankCursor */ - g_App->exec(); - } - return 0; -} - -/******************************************************************************/ -int main(int argc, char ** argv) -{ -#ifdef SHARP - g_App = new QPEApplication(argc, argv); -#else - g_App = new QApplication(argc, argv, QApplication::GuiServer); - //g_App = new QApplication(argc, argv); -#endif - g_SV = new QMyScrollView(); - g_App->setMainWidget(g_SV); - g_SV->showMaximized(); - if (argc > 1) - { - get_username_and_hostname(); - if (parse_parameters(argc, argv)) - { - param_connect(); - } - } - else - { - g_SV->timer_id = g_SV->startTimer(1000); /* one sec delay, then dialog */ - g_App->exec(); - } - delete g_SV; - delete g_App; - xfree(g_CM); - xfree(g_BS); - return 0; -} diff -Nru rdesktop-1.8.6/uiports/qtewin.h rdesktop-1.9.0/uiports/qtewin.h --- rdesktop-1.8.6/uiports/qtewin.h 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/uiports/qtewin.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,107 +0,0 @@ - -#include <qwidget.h> -#include <qscrollview.h> -#include <qdialog.h> -#include <qlistbox.h> -#include <qlineedit.h> -#include <qcombobox.h> -#include <qlabel.h> -#include <qcheckbox.h> -#include <qpopupmenu.h> - -class QMyConnectionItem -{ - public: - QString ServerName; - QString UserName; - QString ServerIP; - int Width; - int Height; - int FullScreen; -}; - -class QMyDialog: public QDialog -{ - Q_OBJECT - public: - QMyDialog(QWidget*); - ~QMyDialog(); - public: - QListBox* ListBox; - QPushButton* OKButton; - QPushButton* CancelButton; - QLabel* Label1; - QLineEdit* ServerNameEdit; - QLabel* Label2; - QLineEdit* UserNameEdit; - QLabel* Label3; - QLineEdit* IPEdit; - QLineEdit* WidthEdit; - QLineEdit* HeightEdit; - QComboBox* WidthHeightBox; - QPushButton* AddButton; - QPushButton* EditButton; - QPushButton* SaveButton; - QPushButton* RemoveButton; - QCheckBox* FullScreenCheckBox; - public slots: - void ComboChanged(int); - void OKClicked(); - void CancelClicked(); - void AddClicked(); - void EditClicked(); - void SaveClicked(); - void RemoveClicked(); - void ListBoxChanged(); - void ListBoxSelected(int); - public: - QString ServerName; - QString UserName; - QString ServerIP; - int Width; - int Height; - int FullScreen; - QMyConnectionItem* ConnectionList[10]; -}; - -class QMyScrollView: public QScrollView -{ - Q_OBJECT - public: - QMyScrollView(); - ~QMyScrollView(); - void keyPressEvent(QKeyEvent*); - void keyReleaseEvent(QKeyEvent*); - void showEvent(QShowEvent*); - void show(); - void polish(); - void timerEvent(QTimerEvent*); - public: - int timer_id; - int sound_timer_id; -}; - -class QMyMainWindow: public QWidget -{ - Q_OBJECT - public: - QMyMainWindow(); - ~QMyMainWindow(); - void paintEvent(QPaintEvent*); - void mouseMoveEvent(QMouseEvent*); - void mousePressEvent(QMouseEvent*); - void mouseReleaseEvent(QMouseEvent*); - void wheelEvent(QWheelEvent*); - void closeEvent(QCloseEvent*); - void timerEvent(QTimerEvent*); - public slots: - void dataReceived(); - void soundSend(); - void MemuClicked(int); - public: - QPopupMenu* PopupMenu; - int timer_id; - int mx; - int my; -}; - diff -Nru rdesktop-1.8.6/uiports/qtreadme.txt rdesktop-1.9.0/uiports/qtreadme.txt --- rdesktop-1.8.6/uiports/qtreadme.txt 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/uiports/qtreadme.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,12 +0,0 @@ -This is the Qt/X11 ui port -qt should be installed in /usr/local/qt -you may need to have LD_LIBRARY_PATH defined to run qtrdesktop -tested with versions 2.3.2, 3.1.2 - -makefile_qt can be edited to change file localtions -run make -f makefile_qt in this directory to compile it - -qtreadme.txt - notes, this file -makefile_qt - makefile -qtwin.cpp - ui lib -qtwin.h - header diff -Nru rdesktop-1.8.6/uiports/qtwin.cpp rdesktop-1.9.0/uiports/qtwin.cpp --- rdesktop-1.8.6/uiports/qtwin.cpp 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/uiports/qtwin.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,1826 +0,0 @@ -/* -*- c-basic-offset: 8 -*- - rdesktop: A Remote Desktop Protocol client. - User interface services - QT Window System - Copyright (C) Jay Sorg 2004-2007 - - 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 3 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, see <http://www.gnu.org/licenses/>. -*/ - -#include "rdesktop.h" - -#include <qapplication.h> -#include <qmainwindow.h> -#include <qwidget.h> -#include <qpainter.h> -#include <qpixmap.h> -#include <qbrush.h> -#include <qimage.h> -#include <qbitmap.h> -#include <qcursor.h> -#include <qsocketnotifier.h> -#include <qscrollview.h> -#include <qfile.h> - -#include "qtwin.h" - -#include <unistd.h> // gethostname -#include <pwd.h> // getpwuid -#include <stdarg.h> // va_list va_start va_end - -#include <errno.h> -#include <fcntl.h> - -/* rdesktop globals */ -extern int g_tcp_port_rdp; -RD_BOOL g_use_rdp5 = True; -char g_hostname[16]; -char g_username[64]; -int g_height = 600; -int g_width = 800; -int g_server_depth = 8; -int g_encryption = 1; -int g_desktop_save = 1; -int g_polygon_ellipse_orders = 0; -int g_bitmap_cache = 1; -int g_bitmap_cache_persist_enable = False; -int g_bitmap_cache_precache = True; -int g_bitmap_compression = 1; -int g_rdp5_performanceflags = 0; -int g_console_session = 0; -int 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 */ -int g_numlock_sync = 0; - -/* hack globals */ -static int g_argc = 0; -static char ** g_argv = 0; -static int g_UpAndRunning = 0; -static int g_sock = 0; -static int g_deactivated = 0; -static uint32 g_ext_disc_reason = 0; -static char g_servername[128]; -static char g_title[128] = ""; -static int g_flags = RDP_LOGON_NORMAL; - -#ifdef WITH_RDPSND -extern int g_dsp_busy; -extern int g_dsp_fd; -static int g_rdpsnd = 0; -static QSocketNotifier * g_SoundNotifier = 0; -#endif - -/* qt globals */ -static QSocketNotifier * g_SocketNotifier = 0; -static QApplication * g_App = 0; -static QMyMainWindow * g_MW = 0; -static QMyScrollView * g_SV = 0; -static QPixmap * g_BS = 0; -static QPixmap * g_DS = 0; -static QPainter * g_P1 = 0; -static QPainter * g_P2 = 0; -static QColor g_Color1; -static QColor g_Color2; - -struct QColorMap -{ - uint32 RGBColors[256]; - int NumColors; -}; -static struct QColorMap * g_CM = 0; -static QRegion * g_ClipRect; - -static Qt::RasterOp g_OpCodes[16] = { - Qt::ClearROP, // BLACKNESS 0 - Qt::NorROP, // NOTSRCERASE DSon - Qt::NotAndROP, // DSna - Qt::NotCopyROP, // NOTSRCCOPY Sn - Qt::AndNotROP, // SRCERASE SDna - Qt::NotROP, // DSTINVERT Dn - Qt::XorROP, // SRCINVERT DSx - Qt::NandROP, // DSan - Qt::AndROP, // SRCAND DSa - Qt::NotXorROP, // DSxn - Qt::NopROP, // D - Qt::NotOrROP, // MERGEPAINT DSno - Qt::CopyROP, // SRCCOPY S - Qt::OrNotROP, // SDno - Qt::OrROP, // SRCPAINT DSo - Qt::SetROP}; // WHITENESS 1 - -/* Session Directory redirection */ -RD_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; - -//***************************************************************************** -uint32 Color15to32(uint32 InColor) -{ - uint32 r, g, b; - - r = (InColor & 0x7c00) >> 10; - r = (r * 0xff) / 0x1f; - g = (InColor & 0x03e0) >> 5; - g = (g * 0xff) / 0x1f; - b = (InColor & 0x001f); - b = (b * 0xff) / 0x1f; - return (r << 16) | (g << 8) | b; -} - -//***************************************************************************** -uint32 Color16to32(uint32 InColor) -{ - uint32 r, g, b; - - r = (InColor & 0xf800) >> 11; - r = (r * 0xff) / 0x1f; - g = (InColor & 0x07e0) >> 5; - g = (g * 0xff) / 0x3f; - b = (InColor & 0x001f); - b = (b * 0xff) / 0x1f; - return (r << 16) | (g << 8) | b; -} - -//***************************************************************************** -uint32 Color24to32(uint32 InColor) -{ - return ((InColor & 0x00ff0000) >> 16) | - ((InColor & 0x000000ff) << 16) | - (InColor & 0x0000ff00); -} - -//***************************************************************************** -void SetColorx(QColor * Color, uint32 InColor) -{ - switch (g_server_depth) - { - case 8: - if (g_CM == NULL || InColor > 255) - { - Color->setRgb(0); - return; - } - Color->setRgb(g_CM->RGBColors[InColor]); - break; - case 15: - Color->setRgb(Color15to32(InColor)); - break; - case 16: - Color->setRgb(Color16to32(InColor)); - break; - case 24: - Color->setRgb(Color24to32(InColor)); - break; - default: - Color->setRgb(0); - } -} - -//***************************************************************************** -void SetOpCode(int opcode) -{ - if (opcode >= 0 && opcode < 16) - { - Qt::RasterOp op = g_OpCodes[opcode]; - if (op != Qt::CopyROP) - { - g_P1->setRasterOp(op); - g_P2->setRasterOp(op); - } - } -} - -//***************************************************************************** -void ResetOpCode(int opcode) -{ - if (opcode >= 0 && opcode < 16) - { - Qt::RasterOp op = g_OpCodes[opcode]; - if (op != Qt::CopyROP) - { - g_P1->setRasterOp(Qt::CopyROP); - g_P2->setRasterOp(Qt::CopyROP); - } - } -} - -/*****************************************************************************/ -QMyMainWindow::QMyMainWindow(): QWidget() -{ -} - -/*****************************************************************************/ -QMyMainWindow::~QMyMainWindow() -{ -} - -//***************************************************************************** -void QMyMainWindow::mouseMoveEvent(QMouseEvent * e) -{ - if (!g_UpAndRunning) - { - return; - } - rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE, e->x(), e->y()); -} - -//***************************************************************************** -void QMyMainWindow::mousePressEvent(QMouseEvent * e) -{ - if (!g_UpAndRunning) - { - return; - } - if (e->button() == LeftButton) - { - rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON1, - e->x(), e->y()); - } - else if (e->button() == RightButton) - { - rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON2, - e->x(), e->y()); - } - else if (e->button() == MidButton) - { - rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON3, - e->x(), e->y()); - } -} - -//***************************************************************************** -void QMyMainWindow::mouseReleaseEvent(QMouseEvent * e) -{ - if (!g_UpAndRunning) - { - return; - } - if (e->button() == LeftButton) - { - rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON1, e->x(), e->y()); - } - else if (e->button() == RightButton) - { - rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON2, e->x(), e->y()); - } - else if (e->button() == MidButton) - { - rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON3, e->x(), e->y()); - } -} - -//***************************************************************************** -void QMyMainWindow::wheelEvent(QWheelEvent * e) -{ - if (!g_UpAndRunning) - { - return; - } - if (e->delta() > 0) - { - rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON4, e->x(), e->y()); - } - else if (e->delta() < 0) - { - rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON5, e->x(), e->y()); - } -} - -//***************************************************************************** -int GetScanCode(QKeyEvent* e) -{ - int Key = e->key(); - int ScanCode = 0; - Qt::ButtonState bs = e->state(); - if (!(bs & Qt::ShiftButton)) // shift is not down - { - if (Key == 42) // * - return 0x37; - if (Key == 43) // + - return 0x4e; - } - switch (Key) - { - case 4100: ScanCode = 0x1c; break; // enter - case 4101: ScanCode = 0x1c; break; - case 4117: ScanCode = 0xd0; break; // down arrow - case 4115: ScanCode = 0xc8; break; // up arrow - case 4114: ScanCode = 0xcb; break; // left arrow - case 4116: ScanCode = 0xcd; break; // right arrow - case 4112: ScanCode = 0xc7; break; // home - case 4113: ScanCode = 0xcf; break; // end - case 4102: ScanCode = 0xd2; break; // insert - case 4103: ScanCode = 0xd3; break; // delete - case 4118: ScanCode = 0xc9; break; // page up - case 4119: ScanCode = 0xd1; break; // page down - case 4143: ScanCode = 0x00; break; // num lock - case 47: ScanCode = 0x35; break; // / - case 42: ScanCode = 0x37; break; // * - case 45: ScanCode = 0x0c; break; // - - case 95: ScanCode = 0x0c; break; // _ - case 43: ScanCode = 0x0d; break; // + - case 46: ScanCode = 0x34; break; // . - case 48: ScanCode = 0x0b; break; // 0 - case 41: ScanCode = 0x0b; break; // ) - case 49: ScanCode = 0x02; break; // 1 - case 33: ScanCode = 0x02; break; // ! - case 50: ScanCode = 0x03; break; // 2 - case 64: ScanCode = 0x03; break; // @ - case 51: ScanCode = 0x04; break; // 3 - case 35: ScanCode = 0x04; break; // # - case 52: ScanCode = 0x05; break; // 4 - case 36: ScanCode = 0x05; break; // $ - case 53: ScanCode = 0x06; break; // 5 - case 37: ScanCode = 0x06; break; // % - case 54: ScanCode = 0x07; break; // 6 - case 94: ScanCode = 0x07; break; // ^ - case 55: ScanCode = 0x08; break; // 7 - case 38: ScanCode = 0x08; break; // & - case 56: ScanCode = 0x09; break; // 8 - case 57: ScanCode = 0x0a; break; // 9 - case 40: ScanCode = 0x0a; break; // ( - case 61: ScanCode = 0x0d; break; // = - case 65: ScanCode = 0x1e; break; // a - case 66: ScanCode = 0x30; break; // b - case 67: ScanCode = 0x2e; break; // c - case 68: ScanCode = 0x20; break; // d - case 69: ScanCode = 0x12; break; // e - case 70: ScanCode = 0x21; break; // f - case 71: ScanCode = 0x22; break; // g - case 72: ScanCode = 0x23; break; // h - case 73: ScanCode = 0x17; break; // i - case 74: ScanCode = 0x24; break; // j - case 75: ScanCode = 0x25; break; // k - case 76: ScanCode = 0x26; break; // l - case 77: ScanCode = 0x32; break; // m - case 78: ScanCode = 0x31; break; // n - case 79: ScanCode = 0x18; break; // o - case 80: ScanCode = 0x19; break; // p - case 81: ScanCode = 0x10; break; // q - case 82: ScanCode = 0x13; break; // r - case 83: ScanCode = 0x1f; break; // s - case 84: ScanCode = 0x14; break; // t - case 85: ScanCode = 0x16; break; // u - case 86: ScanCode = 0x2f; break; // v - case 87: ScanCode = 0x11; break; // w - case 88: ScanCode = 0x2d; break; // x - case 89: ScanCode = 0x15; break; // y - case 90: ScanCode = 0x2c; break; // z - case 32: ScanCode = 0x39; break; // space - case 44: ScanCode = 0x33; break; // , - case 60: ScanCode = 0x33; break; // < - case 62: ScanCode = 0x34; break; // > - case 63: ScanCode = 0x35; break; // ? - case 92: ScanCode = 0x2b; break; // backslash - case 124: ScanCode = 0x2b; break; // bar - case 4097: ScanCode = 0x0f; break; // tab - case 4132: ScanCode = 0x3a; break; // caps lock - case 4096: ScanCode = 0x01; break; // esc - case 59: ScanCode = 0x27; break; // ; - case 58: ScanCode = 0x27; break; // : - case 39: ScanCode = 0x28; break; // ' - case 34: ScanCode = 0x28; break; // " - case 91: ScanCode = 0x1a; break; // [ - case 123: ScanCode = 0x1a; break; // { - case 93: ScanCode = 0x1b; break; // ] - case 125: ScanCode = 0x1b; break; // } - case 4144: ScanCode = 0x3b; break; // f1 - case 4145: ScanCode = 0x3c; break; // f2 - case 4146: ScanCode = 0x3d; break; // f3 - case 4147: ScanCode = 0x3e; break; // f4 - case 4148: ScanCode = 0x3f; break; // f5 - case 4149: ScanCode = 0x40; break; // f6 - case 4150: ScanCode = 0x41; break; // f7 - case 4151: ScanCode = 0x42; break; // f8 - case 4152: ScanCode = 0x43; break; // f9 - case 4153: ScanCode = 0x44; break; // f10 - case 4154: ScanCode = 0x57; break; // f11 - case 4155: ScanCode = 0x58; break; // f12 - case 4128: ScanCode = 0x2a; break; // shift - case 4131: ScanCode = 0x38; break; // alt - case 4129: ScanCode = 0x1d; break; // ctrl - case 96: ScanCode = 0x29; break; // ` - case 126: ScanCode = 0x29; break; // ~ - case 4099: ScanCode = 0x0e; break; // backspace - } -// if (ScanCode == 0) -// printf("key %d scancode %d\n", Key, ScanCode); - return ScanCode; -} - -//***************************************************************************** -void QMyMainWindow::keyPressEvent(QKeyEvent* e) -{ - if (!g_UpAndRunning) - return; - int ScanCode = GetScanCode(e); - if (ScanCode != 0) - { - rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYPRESS, ScanCode, 0); - e->accept(); - } -} - -//***************************************************************************** -void QMyMainWindow::keyReleaseEvent(QKeyEvent* e) -{ - if (!g_UpAndRunning) - { - return; - } - int ScanCode = GetScanCode(e); - if (ScanCode != 0) - { - rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYRELEASE, ScanCode, 0); - e->accept(); - } -} - -//***************************************************************************** -void QMyMainWindow::paintEvent(QPaintEvent * pe) -{ - QRect Rect; - - Rect = pe->rect(); - bitBlt(this, Rect.left(), Rect.top(), g_BS, Rect.left(), Rect.top(), - Rect.width(), Rect.height()); -} - -//***************************************************************************** -void QMyMainWindow::closeEvent(QCloseEvent * e) -{ - e->accept(); -} - -//***************************************************************************** -bool QMyMainWindow::event(QEvent * e) -{ - return QWidget::event(e); -} - -//***************************************************************************** -void QMyMainWindow::dataReceived() -{ - if (!rdp_loop(&g_deactivated, &g_ext_disc_reason)) - { - g_SV->close(); - } -#ifdef WITH_RDPSND - if (g_dsp_busy) - { - if (g_SoundNotifier == 0) - { - g_SoundNotifier = new QSocketNotifier(g_dsp_fd, QSocketNotifier::Write, - g_MW); - g_MW->connect(g_SoundNotifier, SIGNAL(activated(int)), g_MW, - SLOT(soundSend())); - } - else - { - if (!g_SoundNotifier->isEnabled()) - { - g_SoundNotifier->setEnabled(true); - } - } - } -#endif -} - -/******************************************************************************/ -void QMyMainWindow::soundSend() -{ -#ifdef WITH_RDPSND - g_SoundNotifier->setEnabled(false); - wave_out_play(); - if (g_dsp_busy) - { - g_SoundNotifier->setEnabled(true); - } -#endif -} - -//***************************************************************************** -void QMyScrollView::keyPressEvent(QKeyEvent * e) -{ - g_MW->keyPressEvent(e); -} - -//***************************************************************************** -void QMyScrollView::keyReleaseEvent(QKeyEvent * e) -{ - g_MW->keyReleaseEvent(e); -} - - -//***************************************************************************** -void ui_begin_update(void) -{ - g_P1->begin(g_MW); - g_P2->begin(g_BS); -} - -//***************************************************************************** -void ui_end_update(void) -{ - g_P1->end(); - g_P2->end(); -} - -/*****************************************************************************/ -int ui_init(void) -{ - g_App = new QApplication(g_argc, g_argv); - return 1; -} - -/*****************************************************************************/ -void ui_deinit(void) -{ - delete g_App; -} - -/*****************************************************************************/ -int ui_create_window(void) -{ - int w, h; - QPainter * painter; - QWidget * desktop; - - g_MW = new QMyMainWindow(); - g_SV = new QMyScrollView(); - g_SV->addChild(g_MW); - g_BS = new QPixmap(g_width, g_height); - painter = new QPainter(g_BS); - painter->fillRect(0, 0, g_width, g_height, QBrush(QColor("white"))); - painter->fillRect(0, 0, g_width, g_height, QBrush(QBrush::CrossPattern)); - delete painter; - g_DS = new QPixmap(480, 480); - g_P1 = new QPainter(); - g_P2 = new QPainter(); - g_ClipRect = new QRegion(0, 0, g_width, g_height); - desktop = QApplication::desktop(); - w = desktop->width(); // returns screen width - h = desktop->height(); // returns screen height - g_MW->resize(g_width, g_height); - if (w < g_width || h < g_height) - { - g_SV->resize(w, h); - } - else - { - g_SV->resize(g_width + 4, g_height + 4); - } - g_SV->setMaximumWidth(g_width + 4); - g_SV->setMaximumHeight(g_height + 4); - g_App->setMainWidget(g_SV); - g_SV->show(); - g_MW->setMouseTracking(true); - if (g_title[0] != 0) - { - g_SV->setCaption(g_title); - } - -/* XGrayKey(0, 64, AnyModifie, SV->winId(), 0, GrabModeAsync, GrabModeAsync); - XGrayKey(0, 113, AnyModifie, SV->winId(), 0, GrabModeAsync, GrabModeAsync); - XGrayKey(0, 37, AnyModifie, SV-winId(), 0, GrabModeAsync, GrabModeAsync); - XGrayKey(0, 109, AnyModifie, SV->winId(), 0, GrabModeAsync, GrabModeAsync); - XGrayKey(0, 115, AnyModifie, SV->winId(), 0, GrabModeAsync, GrabModeAsync); - XGrayKey(0, 116, AnyModifie, SV->winId(), 0, GrabModeAsync, GrabModeAsync); - XGrayKey(0, 117, AnyModifie, SV->winId(), 0, GrabModeAsync, GrabModeAsync); - XGrayKey(0, 62, AnyModifie, SV->winId(), 0, GrabModeAsync, GrabModeAsync); - XGrayKey(0, 50, AnyModifie, SV->winId(), 0, GrabModeAsync, GrabModeAsync);*/ - - return 1; -} - -//***************************************************************************** -void ui_main_loop(void) -{ -#ifdef WITH_RDPSND - // init sound - if (g_rdpsnd) - { - rdpsnd_init(0); - } -#endif - // connect - if (!rdp_connect(g_servername, g_flags, "", "", "", "")) - { - return; - } - // start notifier - g_SocketNotifier = new QSocketNotifier(g_sock, QSocketNotifier::Read, g_MW); - g_MW->connect(g_SocketNotifier, SIGNAL(activated(int)), - g_MW, SLOT(dataReceived())); - g_UpAndRunning = 1; - // app main loop - g_App->exec(); -} - -//***************************************************************************** -void ui_destroy_window(void) -{ - delete g_MW; - delete g_SV; - delete g_BS; - delete g_DS; - delete g_P1; - delete g_P2; - delete g_ClipRect; -} - -/*****************************************************************************/ -void ui_bell(void) -{ -} - -/*****************************************************************************/ -int ui_select(int in_val) -{ - if (g_sock == 0) - { - g_sock = in_val; - } - return 1; -} - -/*****************************************************************************/ -void ui_destroy_cursor(void * cursor) -{ - QCursor * Cursor; - Cursor = (QCursor*)cursor; - if (Cursor != NULL) - { - delete Cursor; - } -} - -/*****************************************************************************/ -void* ui_create_glyph(int width, int height, uint8 * data) -{ - QBitmap * Bitmap; - Bitmap = new QBitmap(width, height, data); - Bitmap->setMask(*Bitmap); - return (RD_HGLYPH)Bitmap; -} - -/*****************************************************************************/ -void ui_destroy_glyph(void * glyph) -{ - QBitmap* Bitmap; - Bitmap = (QBitmap*)glyph; - delete Bitmap; -} - -/*****************************************************************************/ -void ui_destroy_bitmap(void * bmp) -{ - QPixmap * Pixmap; - Pixmap = (QPixmap*)bmp; - delete Pixmap; -} - -/*****************************************************************************/ -void ui_reset_clip(void) -{ - g_P1->setClipRect(0, 0, g_width, g_height); - g_P2->setClipRect(0, 0, g_width, g_height); - delete g_ClipRect; - g_ClipRect = new QRegion(0, 0, g_width, g_height); -} - -/*****************************************************************************/ -void ui_set_clip(int x, int y, int cx, int cy) -{ - g_P1->setClipRect(x, y, cx, cy); - g_P2->setClipRect(x, y, cx, cy); - delete g_ClipRect; - g_ClipRect = new QRegion(x, y, cx, cy); -} - -/*****************************************************************************/ -void * ui_create_colourmap(COLOURMAP * colours) -{ - QColorMap* LCM; - int i, r, g, b; - LCM = (QColorMap*)malloc(sizeof(QColorMap)); - memset(LCM, 0, sizeof(QColorMap)); - i = 0; - while (i < colours->ncolours && i < 256) - { - r = colours->colours[i].red; - g = colours->colours[i].green; - b = colours->colours[i].blue; - LCM->RGBColors[i] = (r << 16) | (g << 8) | b; - i++; - } - LCM->NumColors = colours->ncolours; - return LCM; -} - -//***************************************************************************** -// todo, does this leak at end of program -void ui_destroy_colourmap(RD_HCOLOURMAP map) -{ - QColorMap * LCM; - LCM = (QColorMap*)map; - if (LCM == NULL) - return; - free(LCM); -} - -/*****************************************************************************/ -void ui_set_colourmap(void * map) -{ - // destoy old colormap - ui_destroy_colourmap(g_CM); - g_CM = (QColorMap*)map; -} - -/*****************************************************************************/ -RD_HBITMAP ui_create_bitmap(int width, int height, uint8 * data) -{ - QImage * Image = NULL; - QPixmap * Pixmap; - uint32 * d = NULL; - uint16 * s; - int i; - - switch (g_server_depth) - { - case 8: - Image = new QImage(data, width, height, 8, (QRgb*)&g_CM->RGBColors, - g_CM->NumColors, QImage::IgnoreEndian); - break; - case 15: - d = (uint32*)malloc(width * height * 4); - s = (uint16*)data; - for (i = 0; i < width * height; i++) - { - d[i] = Color15to32(s[i]); - } - Image = new QImage((uint8*)d, width, height, 32, NULL, - 0, QImage::IgnoreEndian); - break; - case 16: - d = (uint32*)malloc(width * height * 4); - s = (uint16*)data; - for (i = 0; i < width * height; i++) - { - d[i] = Color16to32(s[i]); - } - Image = new QImage((uint8*)d, width, height, 32, NULL, - 0, QImage::IgnoreEndian); - break; - case 24: - d = (uint32*)malloc(width * height * 4); - memset(d, 0, width * height * 4); - for (i = 0; i < width * height; i++) - { - memcpy(d + i, data + i * 3, 3); - } - Image = new QImage((uint8*)d, width, height, 32, NULL, - 0, QImage::IgnoreEndian); - break; - } - if (Image == NULL) - { - return NULL; - } - Pixmap = new QPixmap(); - Pixmap->convertFromImage(*Image); - delete Image; - if (d != NULL) - { - free(d); - } - return (RD_HBITMAP)Pixmap; -} - -//****************************************************************************** -// adjust coordinates for cliping rect -int WarpCoords(int * x, int * y, int * cx, int * cy, int * srcx, int * srcy) -{ - int dx, dy; - QRect InRect(*x, *y, *cx, *cy); - QRect OutRect; - QRect CRect = g_ClipRect->boundingRect(); - OutRect = InRect.intersect(CRect); - if (OutRect.isEmpty()) - { - return False; - } - dx = OutRect.x() - InRect.x(); - dy = OutRect.y() - InRect.y(); - *x = OutRect.x(); - *y = OutRect.y(); - *cx = OutRect.width(); - *cy = OutRect.height(); - *srcx = *srcx + dx; - *srcy = *srcy + dy; - return True; -} - -//****************************************************************************** -// needed because bitBlt don't seem to care about clipping rects -// also has 2 dsts and src can be null -void bitBltClip(QPaintDevice * dst1, QPaintDevice * dst2, int dx, int dy, - QPaintDevice * src, int sx, int sy, int sw, int sh, - Qt::RasterOp rop, bool im) -{ - if (WarpCoords(&dx, &dy, &sw, &sh, &sx, &sy)) - { - if (dst1 != NULL) - { - if (src == NULL) - { - bitBlt(dst1, dx, dy, dst1, sx, sy, sw, sh, rop, im); - } - else - { - bitBlt(dst1, dx, dy, src, sx, sy, sw, sh, rop, im); - } - } - if (dst2 != NULL) - { - if (src == NULL) - { - bitBlt(dst2, dx, dy, dst2, sx, sy, sw, sh, rop, im); - } - else - { - bitBlt(dst2, dx, dy, src, sx, sy, sw, sh, rop, im); - } - } - } -} - -#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) \ - { \ - g_P2->drawPixmap(x + glyph->offset, y + glyph->baseline, \ - *((QBitmap*)glyph->pixmap)); \ - 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) -{ - FONTGLYPH * glyph; - int i, j, xyoffset; - DATABLOB * entry; - - SetColorx(&g_Color1, fgcolour); - SetColorx(&g_Color2, bgcolour); - g_P2->setBackgroundColor(g_Color2); - g_P2->setPen(g_Color1); - if (boxcx > 1) - { - g_P2->fillRect(boxx, boxy, boxcx, boxcy, QBrush(g_Color2)); - } - else if (mixmode == MIX_OPAQUE) - { - g_P2->fillRect(clipx, clipy, clipcx, clipcy, QBrush(g_Color2)); - } - - /* 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) - { - bitBltClip(g_MW, NULL, boxx, boxy, g_BS, boxx, boxy, boxcx, boxcy, - Qt::CopyROP, true); - } - else - { - bitBltClip(g_MW, NULL, clipx, clipy, g_BS, clipx, clipy, clipcx, - clipcy, Qt::CopyROP, true); - } -} - -/*****************************************************************************/ -void ui_line(uint8 opcode, int startx, int starty, int endx, int endy, - PEN * pen) -{ - SetColorx(&g_Color1, pen->colour); - SetOpCode(opcode); - g_P1->setPen(g_Color1); - g_P1->moveTo(startx, starty); - g_P1->lineTo(endx, endy); - g_P2->setPen(g_Color1); - g_P2->moveTo(startx, starty); - g_P2->lineTo(endx, endy); - ResetOpCode(opcode); -} - -/*****************************************************************************/ -// not used -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_memblt(uint8 opcode, int x, int y, int cx, int cy, - RD_HBITMAP src, int srcx, int srcy) -{ - QPixmap* Pixmap; - Pixmap = (QPixmap*)src; - if (Pixmap != NULL) - { - SetOpCode(opcode); - g_P1->drawPixmap(x, y, *Pixmap, srcx, srcy, cx, cy); - g_P2->drawPixmap(x, y, *Pixmap, srcx, srcy, cx, cy); - ResetOpCode(opcode); - } -} - -//****************************************************************************** -void CommonDeskSave(QPixmap* Pixmap1, QPixmap* Pixmap2, int Offset, int x, - int y, int cx, int cy, int dir) -{ - int lx; - int ly; - int x1; - int y1; - int width; - int lcx; - int right; - int bottom; - lx = Offset % 480; - ly = Offset / 480; - y1 = y; - right = x + cx; - bottom = y + cy; - while (y1 < bottom) - { - x1 = x; - lcx = cx; - while (x1 < right) - { - width = 480 - lx; - if (width > lcx) - width = lcx; - if (dir == 0) - bitBlt(Pixmap1, lx, ly, Pixmap2, x1, y1, width, 1, Qt::CopyROP, true); - else - bitBlt(Pixmap2, x1, y1, Pixmap1, lx, ly, width, 1, Qt::CopyROP, true); - lx = lx + width; - if (lx >= 480) - { - lx = 0; - ly++; - if (ly >= 480) - ly = 0; - } - lcx = lcx - width; - x1 = x1 + width; - } - y1++; - } -} - -/*****************************************************************************/ -void ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy) -{ - QPixmap * Pixmap; - - Pixmap = new QPixmap(cx, cy); - CommonDeskSave(g_DS, Pixmap, offset, 0, 0, cx, cy, 1); - bitBltClip(g_MW, g_BS, x, y, Pixmap, 0, 0, cx, cy, Qt::CopyROP, true); - delete Pixmap; -} - -/*****************************************************************************/ -void ui_desktop_save(uint32 offset, int x, int y, int cx, int cy) -{ - CommonDeskSave(g_DS, g_BS, offset, x, y, cx, cy, 0); -} - -/*****************************************************************************/ -void ui_rect(int x, int y, int cx, int cy, int colour) -{ - SetColorx(&g_Color1, colour); - g_P1->fillRect(x, y, cx, cy, QBrush(g_Color1)); - g_P2->fillRect(x, y, cx, cy, QBrush(g_Color1)); -} - -/*****************************************************************************/ -void ui_screenblt(uint8 opcode, int x, int y, int cx, int cy, - int srcx, int srcy) -{ - SetOpCode(opcode); - bitBltClip(g_MW, g_BS, x, y, NULL, srcx, srcy, cx, cy, Qt::CopyROP, true); - ResetOpCode(opcode); -} - -/*****************************************************************************/ -void ui_patblt(uint8 opcode, int x, int y, int cx, int cy, - BRUSH* brush, int bgcolour, int fgcolour) -{ - QBitmap* Bitmap; - QBrush* Brush; - uint8 ipattern[8], i; - SetOpCode(opcode); - switch (brush->style) - { - case 0: - SetColorx(&g_Color1, fgcolour); - g_P2->fillRect(x, y, cx, cy, QBrush(g_Color1)); - break; - case 3: - SetColorx(&g_Color1, fgcolour); - SetColorx(&g_Color2, bgcolour); - for (i = 0; i != 8; i++) - { - ipattern[7 - i] = ~brush->pattern[i]; - } - Bitmap = new QBitmap(8, 8, ipattern); - Brush = new QBrush(g_Color1, *Bitmap); - g_P2->setBackgroundMode(Qt::OpaqueMode); - g_P2->setBrushOrigin(brush->xorigin, brush->yorigin); - g_P2->setBackgroundColor(g_Color2); - g_P2->fillRect(x, y, cx, cy, *Brush); - delete Brush; - delete Bitmap; - g_P2->setBackgroundMode(Qt::TransparentMode); - g_P2->setBrushOrigin(0, 0); - break; - } - ResetOpCode(opcode); - bitBltClip(g_MW, NULL, x, y, g_BS, x, y, cx, cy, Qt::CopyROP, true); -} - -/*****************************************************************************/ -void ui_destblt(uint8 opcode, int x, int y, int cx, int cy) -{ - SetOpCode(opcode); - g_P1->fillRect(x, y, cx, cy, QBrush(QColor("black"))); - g_P2->fillRect(x, y, cx, cy, QBrush(QColor("black"))); - ResetOpCode(opcode); -} - -/*****************************************************************************/ -void ui_move_pointer(int x, int y) -{ -} - -/*****************************************************************************/ -void ui_set_null_cursor(void) -{ - g_MW->setCursor(10); // Qt::BlankCursor -} - -/*****************************************************************************/ -void ui_paint_bitmap(int x, int y, int cx, int cy, - int width, int height, uint8* data) -{ - QImage * Image = NULL; - QPixmap * Pixmap; - uint32 * d = NULL; - uint16 * s; - int i; - - switch (g_server_depth) - { - case 8: - Image = new QImage(data, width, height, 8, (QRgb*)&g_CM->RGBColors, - g_CM->NumColors, QImage::IgnoreEndian); - break; - case 15: - d = (uint32*)malloc(width * height * 4); - s = (uint16*)data; - for (i = 0; i < width * height; i++) - { - d[i] = Color15to32(s[i]); - } - Image = new QImage((uint8*)d, width, height, 32, NULL, - 0, QImage::IgnoreEndian); - break; - case 16: - d = (uint32*)malloc(width * height * 4); - s = (uint16*)data; - for (i = 0; i < width * height; i++) - { - d[i] = Color16to32(s[i]); - } - Image = new QImage((uint8*)d, width, height, 32, NULL, - 0, QImage::IgnoreEndian); - break; - case 24: - d = (uint32*)malloc(width * height * 4); - memset(d, 0, width * height * 4); - for (i = 0; i < width * height; i++) - { - memcpy(d + i, data + i * 3, 3); - } - Image = new QImage((uint8*)d, width, height, 32, NULL, - 0, QImage::IgnoreEndian); - break; - } - if (Image == NULL) - { - return; - } - Pixmap = new QPixmap(); - Pixmap->convertFromImage(*Image); - g_P1->drawPixmap(x, y, *Pixmap, 0, 0, cx, cy); - g_P2->drawPixmap(x, y, *Pixmap, 0, 0, cx, cy); - delete Image; - delete Pixmap; - if (d != NULL) - { - free(d); - } -} - -//****************************************************************************** -int Is24On(uint8* Data, int X, int Y) -{ - uint8 R, G, B; - int Start; - Start = Y * 32 * 3 + X * 3; - R = Data[Start]; - G = Data[Start + 1]; - B = Data[Start + 2]; - return !((R == 0) && (G == 0) && (B == 0)); -} - -//****************************************************************************** -int Is1On(uint8* Data, int X, int Y) -{ - int Start; - int Shift; - Start = (Y * 32) / 8 + X / 8; - Shift = X % 8; - return (Data[Start] & (0x80 >> Shift)) == 0; -} - -//****************************************************************************** -void Set1(uint8* Data, int X, int Y) -{ - int Start; - int Shift; - Start = (Y * 32) / 8 + X / 8; - Shift = X % 8; - Data[Start] = Data[Start] | (0x80 >> Shift); -} - -//****************************************************************************** -void FlipOver(uint8* Data) -{ - uint8 AData[128]; - int Index; - memcpy(AData, Data, 128); - for (Index = 0; Index <= 31; Index++) - { - Data[127 - (Index * 4 + 3)] = AData[Index * 4]; - Data[127 - (Index * 4 + 2)] = AData[Index * 4 + 1]; - Data[127 - (Index * 4 + 1)] = AData[Index * 4 + 2]; - Data[127 - Index * 4] = AData[Index * 4 + 3]; - } -} - -/*****************************************************************************/ -void ui_set_cursor(RD_HCURSOR cursor) -{ - QCursor* Cursor; - Cursor = (QCursor*)cursor; - if (Cursor != NULL) - g_MW->setCursor(*Cursor); -} - -/*****************************************************************************/ -RD_HCURSOR ui_create_cursor(unsigned int x, unsigned int y, - int width, int height, - uint8* andmask, uint8* xormask) -{ - uint8 AData[128]; - uint8 AMask[128]; - QBitmap* DataBitmap; - QBitmap* MaskBitmap; - QCursor* Cursor; - int I1, I2, BOn, MOn; - - if (width != 32 || height != 32) - { - return 0; - } - memset(AData, 0, 128); - memset(AMask, 0, 128); - for (I1 = 0; I1 <= 31; I1++) - { - for (I2 = 0; I2 <= 31; I2++) - { - MOn = Is24On(xormask, I1, I2); - BOn = Is1On(andmask, I1, I2); - if (BOn ^ MOn) // xor - { - Set1(AData, I1, I2); - if (!MOn) - { - Set1(AMask, I1, I2); - } - } - if (MOn) - { - Set1(AMask, I1, I2); - } - } - } - FlipOver(AData); - FlipOver(AMask); - DataBitmap = new QBitmap(32, 32, AData); - MaskBitmap = new QBitmap(32, 32, AMask); - Cursor = new QCursor(*DataBitmap, *MaskBitmap, x, y); - delete DataBitmap; - delete MaskBitmap; - return Cursor; -} - -/*****************************************************************************/ -uint16 ui_get_numlock_state(uint32 state) -{ - return 0; -} - -/*****************************************************************************/ -uint32 read_keyboard_state(void) -{ - return 0; -} - -/*****************************************************************************/ -void ui_resize_window(void) -{ -} - -/*****************************************************************************/ -void ui_polygon(uint8 opcode, uint8 fillmode, RD_POINT * point, int npoints, - BRUSH * brush, int bgcolour, int fgcolour) -{ -} - -/*****************************************************************************/ -/* todo, use qt function for this (QPainter::drawPolyline) */ -void ui_polyline(uint8 opcode, RD_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) -{ -} - -/*****************************************************************************/ -void generate_random(uint8 * random) -{ - QFile File("/dev/random"); - File.open(IO_ReadOnly); - if (File.readBlock((char*)random, 32) == 32) - { - return; - } - warning("no /dev/random\n"); - memcpy(random, "12345678901234567890123456789012", 32); -} - -/*****************************************************************************/ -void save_licence(uint8 * data, int length) -{ - char * home, * path, * tmppath; - int fd; - - home = getenv("HOME"); - if (home == NULL) - { - return; - } - path = (char *) xmalloc(strlen(home) + strlen(g_hostname) + - sizeof("/.rdesktop/licence.")); - sprintf(path, "%s/.rdesktop", home); - if ((mkdir(path, 0700) == -1) && errno != EEXIST) - { - perror(path); - return; - } - /* write licence to licence.hostname.new, then atomically rename to - licence.hostname */ - sprintf(path, "%s/.rdesktop/licence.%s", home, g_hostname); - tmppath = (char *) xmalloc(strlen(path) + sizeof(".new")); - strcpy(tmppath, path); - strcat(tmppath, ".new"); - fd = open(tmppath, O_WRONLY | O_CREAT | O_TRUNC, 0600); - if (fd == -1) - { - perror(tmppath); - return; - } - if (write(fd, data, length) != length) - { - perror(tmppath); - unlink(tmppath); - } - else if (rename(tmppath, path) == -1) - { - perror(path); - unlink(tmppath); - } - close(fd); - xfree(tmppath); - xfree(path); -} - -/*****************************************************************************/ -int load_licence(uint8 ** data) -{ - char * home, * path; - struct stat st; - int fd, length; - - home = getenv("HOME"); - if (home == NULL) - { - return -1; - } - path = (char *) xmalloc(strlen(home) + strlen(g_hostname) + - sizeof("/.rdesktop/licence.")); - sprintf(path, "%s/.rdesktop/licence.%s", home, g_hostname); - fd = open(path, O_RDONLY); - if (fd == -1) - { - return -1; - } - if (fstat(fd, &st)) - { - return -1; - } - *data = (uint8 *) xmalloc(st.st_size); - length = read(fd, *data, st.st_size); - close(fd); - xfree(path); - return length; -} - -/*****************************************************************************/ -void* xrealloc(void * in_val, int size) -{ - return realloc(in_val, size); -} - -/*****************************************************************************/ -void* xmalloc(int size) -{ - return malloc(size); -} - -/*****************************************************************************/ -void xfree(void * in_val) -{ - if (in_val != NULL) - { - free(in_val); - } -} - -/*****************************************************************************/ -char * xstrdup(const char * s) -{ - char * mem = strdup(s); - if (mem == NULL) - { - perror("strdup"); - exit(1); - } - return mem; -} - -/*****************************************************************************/ -void warning(char * format, ...) -{ - va_list ap; - - fprintf(stderr, "WARNING: "); - va_start(ap, format); - vfprintf(stderr, format, ap); - va_end(ap); -} - -/*****************************************************************************/ -void unimpl(char * format, ...) -{ - va_list ap; - - fprintf(stderr, "NOT IMPLEMENTED: "); - va_start(ap, format); - vfprintf(stderr, format, ap); - va_end(ap); -} - -/*****************************************************************************/ -void error(char * format, ...) -{ - va_list ap; - - fprintf(stderr, "ERROR: "); - va_start(ap, format); - vfprintf(stderr, format, ap); - va_end(ap); -} - -/*****************************************************************************/ -void out_params(void) -{ - fprintf(stderr, "rdesktop: A Remote Desktop Protocol client.\n"); - fprintf(stderr, "Version " VERSION ". Copyright (C) 1999-2007 Matt Chapman.\n"); - fprintf(stderr, "QT uiport by Jay Sorg\n"); - fprintf(stderr, "See http://www.rdesktop.org/ for more information.\n\n"); - fprintf(stderr, "Usage: qtrdesktop [options] server\n"); - fprintf(stderr, " -g WxH: desktop geometry\n"); - fprintf(stderr, " -4: use RDP version 4\n"); - fprintf(stderr, " -5: use RDP version 5 (default)\n"); - fprintf(stderr, " -t 3389: tcp port)\n"); - fprintf(stderr, " -a 8|16|24: connection colour depth\n"); - fprintf(stderr, " -T title: window title\n"); - fprintf(stderr, " -P: use persistent bitmap caching\n"); - fprintf(stderr, " -0: attach to console\n"); - fprintf(stderr, " -z: enable rdp compression\n"); - fprintf(stderr, " -r sound: enable sound\n"); - fprintf(stderr, "\n"); -} - -/*****************************************************************************/ -/* produce a hex dump */ -void hexdump(uint8 * p, uint32 len) -{ - uint8 * line = p; - int i, thisline; - uint32 offset = 0; - - while (offset < 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; - } -} - -/*****************************************************************************/ -int rd_pstcache_mkdir(void) -{ - char * home; - char bmpcache_dir[256]; - - home = getenv("HOME"); - if (home == NULL) - { - return False; - } - sprintf(bmpcache_dir, "%s/%s", home, ".rdesktop"); - if ((mkdir(bmpcache_dir, S_IRWXU) == -1) && errno != EEXIST) - { - perror(bmpcache_dir); - return False; - } - sprintf(bmpcache_dir, "%s/%s", home, ".rdesktop/cache"); - if ((mkdir(bmpcache_dir, S_IRWXU) == -1) && errno != EEXIST) - { - perror(bmpcache_dir); - return False; - } - return True; -} - -/*****************************************************************************/ -int rd_open_file(char * filename) -{ - char * home; - char fn[256]; - int fd; - - home = getenv("HOME"); - if (home == NULL) - { - return -1; - } - sprintf(fn, "%s/.rdesktop/%s", home, filename); - fd = open(fn, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); - if (fd == -1) - { - perror(fn); - } - return fd; -} - -/*****************************************************************************/ -void rd_close_file(int fd) -{ - close(fd); -} - -/*****************************************************************************/ -int rd_read_file(int fd, void * ptr, int len) -{ - return read(fd, ptr, len); -} - -/*****************************************************************************/ -int rd_write_file(int fd, void * ptr, int len) -{ - return write(fd, ptr, len); -} - -/*****************************************************************************/ -int rd_lseek_file(int fd, int offset) -{ - return lseek(fd, offset, SEEK_SET); -} - -/*****************************************************************************/ -int rd_lock_file(int fd, int start, int len) -{ - struct flock lock; - - lock.l_type = F_WRLCK; - lock.l_whence = SEEK_SET; - lock.l_start = start; - lock.l_len = len; - if (fcntl(fd, F_SETLK, &lock) == -1) - { - return False; - } - return True; -} - -/*****************************************************************************/ -void get_username_and_hostname(void) -{ - char fullhostname[64]; - char * p; - struct passwd * pw; - - STRNCPY(g_username, "unknown", sizeof(g_username)); - STRNCPY(g_hostname, "unknown", sizeof(g_hostname)); - pw = getpwuid(getuid()); - if (pw != NULL && pw->pw_name != NULL) - { - STRNCPY(g_username, pw->pw_name, sizeof(g_username)); - } - if (gethostname(fullhostname, sizeof(fullhostname)) != -1) - { - p = strchr(fullhostname, '.'); - if (p != NULL) - { - *p = 0; - } - STRNCPY(g_hostname, fullhostname, sizeof(g_hostname)); - } -} - -/*****************************************************************************/ -int parse_parameters(int in_argc, char ** in_argv) -{ - int i; - char * p; - - if (in_argc <= 1) - { - out_params(); - return 0; - } - g_argc = in_argc; - g_argv = in_argv; - for (i = 1; i < in_argc; i++) - { - strcpy(g_servername, in_argv[i]); - if (strcmp(in_argv[i], "-g") == 0) - { - g_width = strtol(in_argv[i + 1], &p, 10); - if (g_width <= 0) - { - error("invalid geometry\n"); - return 0; - } - if (*p == 'x') - { - g_height = strtol(p + 1, NULL, 10); - } - if (g_height <= 0) - { - error("invalid geometry\n"); - return 0; - } - g_width = (g_width + 3) & ~3; - } - else if (strcmp(in_argv[i], "-T") == 0) - { - strcpy(g_title, in_argv[i + 1]); - } - else if (strcmp(in_argv[i], "-4") == 0) - { - g_use_rdp5 = 0; - } - else if (strcmp(in_argv[i], "-5") == 0) - { - g_use_rdp5 = 1; - } - else if (strcmp(in_argv[i], "-a") == 0) - { - g_server_depth = strtol(in_argv[i + 1], &p, 10); - if (g_server_depth != 8 && g_server_depth != 15 && - g_server_depth != 16 && g_server_depth != 24) - { - error("invalid bpp\n"); - return 0; - } - } - else if (strcmp(in_argv[i], "-t") == 0) - { - g_tcp_port_rdp = strtol(in_argv[i + 1], &p, 10); - } - else if (strcmp(in_argv[i], "-P") == 0) - { - g_bitmap_cache_persist_enable = 1; - } - else if (strcmp(in_argv[i], "-0") == 0) - { - g_console_session = 1; - } - else if (strcmp(in_argv[i], "-z") == 0) - { - g_flags |= (RDP_LOGON_COMPRESSION | RDP_LOGON_COMPRESSION2); - } - else if (strcmp(in_argv[i], "-r") == 0) - { - if (strcmp(in_argv[i + 1], "sound") == 0) - { -#ifdef WITH_RDPSND - g_rdpsnd = 1; -#endif - } - } - } - return 1; -} - -/*****************************************************************************/ -int main(int in_argc, char** in_argv) -{ - get_username_and_hostname(); - if (!parse_parameters(in_argc, in_argv)) - { - return 0; - } - if (!ui_init()) - { - return 1; - } - if (!ui_create_window()) - { - return 1; - } - ui_main_loop(); - ui_destroy_window(); - ui_deinit(); - return 0; -} diff -Nru rdesktop-1.8.6/uiports/qtwin.h rdesktop-1.9.0/uiports/qtwin.h --- rdesktop-1.8.6/uiports/qtwin.h 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/uiports/qtwin.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ - -#include <qwidget.h> -#include <qscrollview.h> - -class QMyScrollView: public QScrollView -{ - Q_OBJECT - public: - void keyPressEvent(QKeyEvent*); - void keyReleaseEvent(QKeyEvent*); -}; - -class QMyMainWindow: public QWidget -{ - Q_OBJECT - public: - QMyMainWindow(); - ~QMyMainWindow(); - void paintEvent(QPaintEvent*); - void mouseMoveEvent(QMouseEvent*); - void mousePressEvent(QMouseEvent*); - void mouseReleaseEvent(QMouseEvent*); - void wheelEvent(QWheelEvent*); - void keyPressEvent(QKeyEvent*); - void keyReleaseEvent(QKeyEvent*); - void closeEvent(QCloseEvent*); - bool event(QEvent*); - public slots: - void dataReceived(); - void soundSend(); -}; - diff -Nru rdesktop-1.8.6/uiports/readme.txt rdesktop-1.9.0/uiports/readme.txt --- rdesktop-1.8.6/uiports/readme.txt 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/uiports/readme.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,17 +0,0 @@ -This directory contains information on uiports. -uiports are different graphics libraries using the same core -rdesktop files. - -This directory is provided to include information and examples -on how to do a new uiport. Not all ports of rdesktop can -be included. - -see xxxreadme.txt for info on a blank empty uiport - -see qtreadme.txt for info on the Qt/X11 uiport - -see qtereadme.txt for info on the Qt embeded uiport - -see svgareadme.txt for info on the svga uiport - -see nanoxreadme.txt for info on the nanox uiport diff -Nru rdesktop-1.8.6/uiports/svgareadme.txt rdesktop-1.9.0/uiports/svgareadme.txt --- rdesktop-1.8.6/uiports/svgareadme.txt 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/uiports/svgareadme.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,39 +0,0 @@ -This is the svga ui port -send any fixes or improvments to me Jay Sorg(j@american-data.com) -svgalib should be installed -tested with versions 1.4.3, 1.9.x - -thanks to - Donald Gordon - original work - Peter Nikolow - misc fixes - -run make -f makefile_svga to compile it - -svgareadme.txt - notes, this file -makefile_svga - makefile -svgawin.c - ui lib - -svgalib has some support for acceleration but most drivers -do not support it. I hope they fix this. -The ones that do are Cirus Logic and ATI Mach 32 cards. -If running on really slow hardware(486), use one of these cards, -it improves performance alot. - -run ./svgardesktop with no parameters to see a list of -commnad line options - -You will need to modify the libvga.config file most likely. -Its in /etc/vga. -Here is what mine looks like. -BOF - mouse imps2 - mouse_fake_kbd_event 112 113 - mouse_accel_mult 1.5 - mouse_accel_type normal - HorizSync 31.5 56.0 - VertRefresh 50 90 - nosigint -EOF -The mouse_fake_kbd_event line makes the wheel mouse work. - -Jay diff -Nru rdesktop-1.8.6/uiports/svgawin.c rdesktop-1.9.0/uiports/svgawin.c --- rdesktop-1.8.6/uiports/svgawin.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/uiports/svgawin.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1947 +0,0 @@ -/* -*- c-basic-offset: 8 -*- - rdesktop: A Remote Desktop Protocol client. - User interface services - SVGA lib - Copyright (C) Jay Sorg 2004-2007 - - 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 3 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, see <http://www.gnu.org/licenses/>. -*/ - -#include "../rdesktop.h" - -#include <vga.h> -#include <vgakeyboard.h> -#include <vgamouse.h> -#include <vgagl.h> - -#include <unistd.h> // gethostname -#include <pwd.h> // getpwuid -#include <stdarg.h> // va_list va_start va_end - -#include <sys/ioctl.h> -#include <linux/keyboard.h> -#include <linux/kd.h> -#include <fcntl.h> - -extern int g_tcp_port_rdp; -int g_use_rdp5 = 0; -char g_hostname[16] = ""; -char g_username[64] = ""; -int g_height = 600; -int g_width = 800; -int g_server_depth = 8; -int g_encryption = 1; -int g_desktop_save = 1; -int g_polygon_ellipse_orders = 0; -int g_bitmap_cache = 1; -int g_bitmap_cache_persist_enable = False; -int g_bitmap_cache_precache = True; -int g_bitmap_compression = 1; -int g_rdp5_performanceflags = 0; -int g_console_session = 0; -int 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 */ -RD_BOOL g_numlock_sync = False; - -/* hack globals */ -int g_argc = 0; -char** g_argv = 0; -int UpAndRunning = 0; -int g_sock = 0; -int deactivated = 0; -uint32 ext_disc_reason = 0; -char g_servername[128] = ""; -static uint32* colmap = 0; -static uint8* desk_save = 0; -static int g_server_Bpp = 1; - -/* Keyboard LEDS */ -static int numlock; -static int capslock; -static int scrolllock; - -// this is non null if vgalib has non accel functions available -// reading from video memory is sooo slow -static uint8* sdata = 0; -static int g_save_mem = 0; // for video memory use eg sdata == 0 - -// video acceleration -static int use_accel = 1; -static int has_fill_box = 0; -static int has_screen_copy = 0; -static int has_put_image = 0; - -// clip -int clip_startx; -int clip_starty; -int clip_endx; -int clip_endy; - -// mouse -uint8 mouse_under[32 * 32 * 4]; // save area under mouse -int mousex = 0; -int mousey = 0; -int mouseb = 0; - -// mouse info -typedef struct -{ - uint8 andmask[32 * 32]; - uint8 xormask[32 * 32]; - int x; - int y; - int w; - int h; -} tcursor; - -// mouse global -static tcursor mcursor; - -static int g_draw_mouse = 1; - -/* Session Directory redirection */ -RD_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; - -// bitmap -typedef struct -{ - int width; - int height; - uint8* data; - uint8 Bpp; -} bitmap; - -typedef struct -{ - int x; - int y; - int cx; - int cy; - void* prev; - void* next; -} myrect; - -myrect* head_rect = 0; - -//***************************************************************************** -// Keyboard stuff - PeterS -static void setled(int mask, int state) -{ - int fd; - long int leds; - - if (( fd=open("/dev/console", O_NOCTTY)) != -1 ) - { - if (ioctl (fd, KDGETLED, &leds) != -1) - { - leds &= 7; - if (state) - leds |= mask; - else - leds &= ~mask; - ioctl (fd, KDSETLED, leds); - } - close(fd); - } -} - - -//***************************************************************************** -// do a raster op -int 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 screen pixel -int get_pixel(int x, int y) -{ - if (x >= 0 && x < g_width && y >= 0 && y < g_height) - { - if (sdata != 0) - { - if (g_server_Bpp == 1) - return sdata[y * g_width + x]; - else if (g_server_Bpp == 2) - return ((uint16*)sdata)[y * g_width + x]; - else - return 0; - } - else - return vga_getpixel(x, y); - } - else - return 0; -} - -//***************************************************************************** -// set a screen pixel -void set_pixel(int x, int y, int pixel, int op) -{ - if (x >= clip_startx && x < clip_endx && y >= clip_starty && y < clip_endy) - { - if (x >= 0 && x < g_width && y >= 0 && y < g_height) - { - if (op == 0x0) - pixel = 0; - else if (op == 0xf) - pixel = -1; - else if (op != 0xc) - pixel = rop(op, pixel, get_pixel(x, y)); - if (sdata != 0) - { - if (g_server_Bpp == 1) - sdata[y * g_width + x] = pixel; - else if (g_server_Bpp == 2) - ((uint16*)sdata)[y * g_width + x] = pixel; - } - else - { - vga_setcolor(pixel); - vga_drawpixel(x, y); - } - } - } -} - -//***************************************************************************** -// get a pixel from a bitmap -int get_pixel2(int x, int y, uint8* data, int width, int bpp) -{ - if (bpp == 8) - return data[y * width + x]; - else if (bpp == 16) - return ((uint16*)data)[y * width + x]; - else - return 0; -} - -//***************************************************************************** -// set a pixel in a bitmap -void set_pixel2(int x, int y, int pixel, uint8* data, int width, int bpp) -{ - if (bpp == 8) - data[y * width + x] = pixel; - else if (bpp == 16) - ((uint16*)data)[y * width + x] = pixel; -} - -//***************************************************************************** -// get a pointer into a bitmap -uint8* get_ptr(int x, int y, uint8* data, int width, int bpp) -{ - if (bpp == 8) - return data + (y * width + x); - else if (bpp == 16) - return data + (y * width + x) * 2; - else - return 0; -} - -//***************************************************************************** -// check if a certain pixel is set in a bitmap -RD_BOOL is_pixel_on(uint8* 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 False; -} - -//***************************************************************************** -void set_pixel_on(uint8* data, int x, int y, int width, int bpp, int pixel) -{ - if (bpp == 8) - { - data[y * width + x] = pixel; - } -} - -/*****************************************************************************/ -int warp_coords(int* x, int* y, int* cx, int* cy, int* srcx, int* srcy) -{ - int dx; - int dy; -// int lx = *x, ly = *y, lcx = *cx, lcy = *cy; - - if (clip_startx > *x) - dx = clip_startx - *x; - else - dx = 0; - if (clip_starty > *y) - dy = clip_starty - *y; - else - dy = 0; - if (*x + *cx > clip_endx) - *cx = (*cx - ((*x + *cx) - clip_endx)) /*+ 1*/; - if (*y + *cy > clip_endy) - *cy = (*cy - ((*y + *cy) - clip_endy)) /*+ 1*/; - *cx = *cx - dx; - *cy = *cy - dy; - if (*cx <= 0) - return False; - if (*cy <= 0) - return False; - *x = *x + dx; - *y = *y + dy; - if (srcx != NULL) - *srcx = *srcx + dx; - if (srcy != NULL) - *srcy = *srcy + dy; - -// if (*x != lx || *y != ly || *cx != lcx || *cy != lcy) -// printf("%d %d %d %d to %d %d %d %d\n", lx, ly, lcx, lcy, *x, *y, *cx, *cy); - - return True; -} - -//***************************************************************************** -void copy_mem(uint8* d, uint8* 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 copy_memb(uint8* d, uint8* 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--; - } -} - -//***************************************************************************** -// all in pixel except line_size is in bytes -void accel_draw_box(int x, int y, int cx, int cy, uint8* data, int line_size) -{ - int i; - uint8* s; - uint8* d; - - if (sdata != 0) - { - s = data; - d = get_ptr(x, y, sdata, g_width, g_server_depth); - for (i = 0; i < cy; i++) - { - copy_mem(d, s, cx * g_server_Bpp); - s = s + line_size; - d = d + g_width * g_server_Bpp; - } - } - else if (has_put_image && line_size == cx * g_server_Bpp) - { - vga_accel(ACCEL_PUTIMAGE, x, y, cx, cy, data); - } - else - { - s = data; - for (i = 0; i < cy; i++) - { - vga_drawscansegment(s, x, y + i, cx * g_server_Bpp); - s = s + line_size; - } - } -} - -//***************************************************************************** -void accel_fill_rect(int x, int y, int cx, int cy, int color) -{ - int i; - uint8* temp; - uint8* d; - - if (sdata != 0) - { - temp = xmalloc(cx * g_server_Bpp); - if (g_server_Bpp == 1) - for (i = 0; i < cx; i++) - temp[i] = color; - else if (g_server_Bpp == 2) - for (i = 0; i < cx; i++) - ((uint16*)temp)[i] = color; - d = get_ptr(x, y, sdata, g_width, g_server_depth); - for (i = 0; i < cy; i++) - { - copy_mem(d, temp, cx * g_server_Bpp); - d = d + g_width * g_server_Bpp; - } - xfree(temp); - } - else if (has_fill_box) - { - vga_accel(ACCEL_SETFGCOLOR, color); - vga_accel(ACCEL_FILLBOX, x, y, cx, cy); - } - else - { - temp = xmalloc(cx * g_server_Bpp); - if (g_server_Bpp == 1) - for (i = 0; i < cx; i++) - temp[i] = color; - else if (g_server_Bpp == 2) - for (i = 0; i < cx; i++) - ((uint16*)temp)[i] = color; - for (i = 0; i < cy; i++) - vga_drawscansegment(temp, x, y + i, cx * g_server_Bpp); - xfree(temp); - } -} - -//***************************************************************************** -void accel_screen_copy(int x, int y, int cx, int cy, int srcx, int srcy) -{ - uint8* temp; - uint8* s; - uint8* d; - int i; - - if (sdata != 0) - { - if (srcy < y) - { // bottom to top - s = get_ptr(srcx, (srcy + cy) - 1, sdata, g_width, g_server_depth); - d = get_ptr(x, (y + cy) - 1, sdata, g_width, g_server_depth); - for (i = 0; i < cy; i++) // copy down - { - copy_mem(d, s, cx * g_server_Bpp); - s = s - g_width * g_server_Bpp; - d = d - g_width * g_server_Bpp; - } - } - else if (srcy > y || srcx > x) // copy up or left - { // top to bottom - s = get_ptr(srcx, srcy, sdata, g_width, g_server_depth); - d = get_ptr(x, y, sdata, g_width, g_server_depth); - for (i = 0; i < cy; i++) - { - copy_mem(d, s, cx * g_server_Bpp); - s = s + g_width * g_server_Bpp; - d = d + g_width * g_server_Bpp; - } - } - else // copy straight right - { - s = get_ptr(srcx, srcy, sdata, g_width, g_server_depth); - d = get_ptr(x, y, sdata, g_width, g_server_depth); - for (i = 0; i < cy; i++) - { - copy_memb(d, s, cx * g_server_Bpp); - s = s + g_width * g_server_Bpp; - d = d + g_width * g_server_Bpp; - } - } - } - else if (has_screen_copy) - { - vga_accel(ACCEL_SCREENCOPY, srcx, srcy, x, y, cx, cy); - } - else - { - // slow - temp = (uint8*)xmalloc(cx * cy * g_server_Bpp); - for (i = 0; i < cy; i++) - vga_getscansegment(get_ptr(0, i, temp, cx, g_server_depth), srcx, srcy + i, cx * g_server_Bpp); - for (i = 0; i < cy; i++) - vga_drawscansegment(get_ptr(0, i, temp, cx, g_server_depth), x, y + i, cx * g_server_Bpp); - xfree(temp); - } -} - -//***************************************************************************** -// return bool -int contains_mouse(int x, int y, int cx, int cy) -{ - if (mousex + 32 >= x && - mousey + 32 >= y && - mousex <= x + cx && - mousey <= y + cy) - return 1; - else - return 0; -} - -//***************************************************************************** -void fill_rect(int x, int y, int cx, int cy, int colour, int opcode) -{ - int i; - int j; - - if (warp_coords(&x, &y, &cx, &cy, NULL, NULL)) - { - if (opcode == 0xc) - accel_fill_rect(x, y, cx, cy, colour); - else if (opcode == 0xf) - accel_fill_rect(x, y, cx, cy, -1); - else if (opcode == 0x0) - accel_fill_rect(x, y, cx, cy, 0); - else - { - for (i = 0; i < cy; i++) - for (j = 0; j < cx; j++) - set_pixel(x + j, y + i, colour, opcode); - } - } -} - -//***************************************************************************** -void get_rect(int x, int y, int cx, int cy, uint8* p) -{ - int i; - - if (x < 0) - { - cx = cx + x; - x = 0; - } - if (y < 0) - { - cy = cy + y; - y = 0; - } - if (sdata != 0) - { - for (i = 0; i < cy; i++) - { - copy_mem(p, get_ptr(x, y + i, sdata, g_width, g_server_depth), cx * g_server_Bpp); - p = p + cx * g_server_Bpp; - } - } - else - { - for (i = 0; i < cy; i++) - { - vga_getscansegment(p, x, y + i, cx * g_server_Bpp); - p = p + cx * g_server_Bpp; - } - } -} - -/*****************************************************************************/ -// return true if r1 is contained by r2 -int is_contained_by(myrect* r1, myrect* r2) -{ - if (r1->x >= r2->x && - r1->y >= r2->y && - r1->x + r1->cx <= r2->x + r2->cx && - r1->y + r1->cy <= r2->y + r2->cy) - return 1; - else - return 0; -} - -/*****************************************************************************/ -void draw_cursor_under(int ox, int oy) -{ - int i; - int j; - int k; - uint8* ptr; - int len; - - if (ox < 0) - k = -ox; - else - k = 0; - j = g_width - ox; - if (j > 32) - j = 32; - if (j > 0) - { - for (i = 0; i < 32; i++) - { - ptr = get_ptr(k, i, mouse_under, 32, g_server_depth); - len = (j - k) * g_server_Bpp; - if (ox + k >= 0 && oy + i >= 0 && ox + k < g_width && oy + i < g_height) - vga_drawscansegment(ptr, ox + k, oy + i, len); - } - } - g_draw_mouse = 1; -} - -/*****************************************************************************/ -void draw_cursor(void) -{ - int i; - int j; - int k; - int pixel; - uint8 mouse_a[32 * 32 * 4]; - uint8* ptr; - int len; - - if (!g_draw_mouse) - return; - memset(mouse_under, 0, sizeof(mouse_under)); - for (i = 0; i < 32; i++) - { - for (j = 0; j < 32; j++) - { - pixel = get_pixel(mousex + j, mousey + i); - set_pixel2(j, i, pixel, mouse_under, 32, g_server_depth); - if (mcursor.andmask[i * 32 + j] == 0) - k = 0; - else - k = ~0; - pixel = rop(0x8, k, pixel); - if (mcursor.xormask[i * 32 + j] == 0) - k = 0; - else - k = ~0; - pixel = rop(0x6, k, pixel); - set_pixel2(j, i, pixel, mouse_a, 32, g_server_depth); - } - } - if (mousex < 0) - k = -mousex; - else - k = 0; - j = g_width - mousex; - if (j > 32) - j = 32; - if (j > 0) - { - for (i = mousey; i < mousey + 32; i++) - if (i < g_height && i >= 0) - { - ptr = get_ptr(k, i - mousey, mouse_a, 32, g_server_depth); - len = (j - k) * g_server_Bpp; - vga_drawscansegment(ptr, mousex + k, i, len); - } - } - g_draw_mouse = 0; -} - -/*****************************************************************************/ -// add a rect to cache -void cache_rect(int x, int y, int cx, int cy, int do_warp) -{ - myrect* rect; - myrect* walk_rect; - - if (sdata == 0) - { - draw_cursor(); - return; - } - if (do_warp) - if (!warp_coords(&x, &y, &cx, &cy, NULL, NULL)) - return; - rect = (myrect*)xmalloc(sizeof(myrect)); - rect->x = x; - rect->y = y; - rect->cx = cx; - rect->cy = cy; - rect->next = 0; - rect->prev = 0; - if (head_rect == 0) - head_rect = rect; - else - { - walk_rect = 0; - do - { - if (walk_rect == 0) - walk_rect = head_rect; - else - walk_rect = walk_rect->next; - if (is_contained_by(rect, walk_rect)) - { - xfree(rect); - return; - } - } - while (walk_rect->next != 0); - walk_rect->next = rect; - rect->prev = walk_rect; - } -} - -//***************************************************************************** -void draw_cache_rects(void) -{ - int i; - myrect* rect; - myrect* rect1; - uint8* p; - - // draw all the rects - rect = head_rect; - while (rect != 0) - { - p = get_ptr(rect->x, rect->y, sdata, g_width, g_server_depth); - for (i = 0; i < rect->cy; i++) - { - vga_drawscansegment(p, rect->x, rect->y + i, rect->cx * g_server_Bpp); - p = p + g_width * g_server_Bpp; - } - rect1 = rect; - rect = rect->next; - xfree(rect1); - } - head_rect = 0; -} - -/*****************************************************************************/ -void key_event(int scancode, int pressed) -{ - int rdpkey; - int ext; - - if (!UpAndRunning) - return; - rdpkey = scancode; - ext = 0; - - // Keyboard LEDS - if ((scancode == SCANCODE_CAPSLOCK) && pressed) - { - capslock = !capslock; - setled(LED_CAP, capslock); - } - if ((scancode == SCANCODE_SCROLLLOCK) && pressed) - { - scrolllock = !scrolllock; - setled(LED_SCR, scrolllock); - } - - if ((scancode == SCANCODE_NUMLOCK) && pressed) - { - numlock = !numlock; - setled(LED_NUM, numlock); - } - - switch (scancode) - { - case SCANCODE_CURSORBLOCKUP: rdpkey = 0xc8; ext = KBD_FLAG_EXT; break; // up arrow - case SCANCODE_CURSORBLOCKDOWN: rdpkey = 0xd0; ext = KBD_FLAG_EXT; break; // down arrow - case SCANCODE_CURSORBLOCKRIGHT: rdpkey = 0xcd; ext = KBD_FLAG_EXT; break; // right arrow - case SCANCODE_CURSORBLOCKLEFT: rdpkey = 0xcb; ext = KBD_FLAG_EXT; break; // left arrow - case SCANCODE_PAGEDOWN: rdpkey = 0xd1; ext = KBD_FLAG_EXT; break; // page down - case SCANCODE_PAGEUP: rdpkey = 0xc9; ext = KBD_FLAG_EXT; break; // page up - case SCANCODE_HOME: rdpkey = 0xc7; ext = KBD_FLAG_EXT; break; // home - case SCANCODE_END: rdpkey = 0xcf; ext = KBD_FLAG_EXT; break; // end - case SCANCODE_INSERT: rdpkey = 0xd2; ext = KBD_FLAG_EXT; break; // insert - case SCANCODE_REMOVE: rdpkey = 0xd3; ext = KBD_FLAG_EXT; break; // delete - case SCANCODE_KEYPADDIVIDE: rdpkey = 0x35; break; // / - case SCANCODE_KEYPADENTER: rdpkey = 0x1c; break; // enter - case SCANCODE_RIGHTCONTROL: rdpkey = 0x1d; break; // right ctrl - case SCANCODE_RIGHTALT: rdpkey = 0x38; break; // right alt - case SCANCODE_LEFTWIN: rdpkey = 0x5b; ext = KBD_FLAG_EXT; break; // left win - case SCANCODE_RIGHTWIN: rdpkey = 0x5c; ext = KBD_FLAG_EXT; break; // right win - case 127: rdpkey = 0x5d; ext = KBD_FLAG_EXT; break; // menu key - case SCANCODE_PRINTSCREEN: rdpkey = 0x37; ext = KBD_FLAG_EXT; break; // print screen - case SCANCODE_BREAK: //rdpkey = 0; break; // break - { - if (pressed) - { - ext = KBD_FLAG_EXT; - rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYPRESS | ext, 0x46, 0); - rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYPRESS | ext, 0xc6, 0); - } - rdpkey = 0; - } - case SCANCODE_SCROLLLOCK: rdpkey = 0x46; break; // scroll lock - case 112: // mouse down - { - rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON4, - mouse_getx(), mouse_gety()); - return; - } - case 113: // mouse up - { - rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON5, - mouse_getx(), mouse_gety()); - return; - } - } -// printf("%d %d\n", scancode, pressed); - if (pressed) - rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYPRESS | ext, rdpkey, 0); - else - rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYRELEASE | ext, rdpkey, 0); - - -} - -/*****************************************************************************/ -int ui_init(void) -{ - vga_init(); - memset(&mcursor, 0, sizeof(tcursor)); - desk_save = (uint8*)xmalloc(0x38400 * g_server_Bpp); - return 1; -} - -/*****************************************************************************/ -void ui_deinit(void) -{ - xfree(desk_save); -} - -/*****************************************************************************/ -int ui_create_window(void) -{ - int vgamode; - int i; - - vgamode = G800x600x256; - if (g_width == 640 && g_height == 480) - { - if (g_server_Bpp == 1) - vgamode = G640x480x256; - else if (g_server_Bpp == 2) - vgamode = G640x480x64K; - } - else if (g_width == 800 && g_height == 600) - { - if (g_server_Bpp == 1) - vgamode = G800x600x256; - else if (g_server_Bpp == 2) - vgamode = G800x600x64K; - } - else if (g_width == 1024 && g_height == 768) - { - if (g_server_Bpp == 1) - vgamode = G1024x768x256; - else if (g_server_Bpp == 2) - vgamode = G1024x768x64K; - } - else - { - error("Invalid width / height"); - return 0; - } - ui_reset_clip(); - if (!vga_hasmode(vgamode)) - { - error("Graphics unavailable"); - return 0; - } - vga_setmousesupport(1); - mouse_setposition(g_width / 2, g_height / 2); - vga_setmode(vgamode); - if (keyboard_init()) - { - error("Keyboard unavailable"); - return 0; - } - keyboard_seteventhandler(key_event); - if (use_accel) - { - i = vga_ext_set(VGA_EXT_AVAILABLE, VGA_AVAIL_ACCEL); - if (i & ACCELFLAG_PUTIMAGE) - has_put_image = 1; - if (i & ACCELFLAG_SCREENCOPY) - has_screen_copy = 1; - if (i & ACCELFLAG_FILLBOX) - has_fill_box = 1; - printf("accel %d\n", i); - } - if (!has_screen_copy && !g_save_mem) - sdata = xmalloc(g_width * g_height * g_server_Bpp); - return 1; -} - -/*****************************************************************************/ -void ui_destroy_window(void) -{ - keyboard_close(); /* Don't forget this! */ - vga_setmode(TEXT); - if (sdata != 0) - xfree(sdata); -} - -/*****************************************************************************/ -void process_mouse(void) -{ - int ox = mousex; - int oy = mousey; - int ob = mouseb; - - if (!UpAndRunning) - return; - mousex = mouse_getx() - mcursor.x; - mousey = mouse_gety() - mcursor.y; - mouseb = mouse_getbutton(); - - if (mouseb != ob) // button - { - // right button - if (mouseb & 1) - if (!(ob & 1)) - rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON2, - mousex + mcursor.x, mousey + mcursor.y); - if (ob & 1) - if (!(mouseb & 1)) - rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON2, - mousex + mcursor.x, mousey + mcursor.y); - // middle button - if (mouseb & 2) - if (!(ob & 2)) - rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON3, - mousex + mcursor.x, mousey + mcursor.y); - if (ob & 2) - if (!(mouseb & 2)) - rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON3, - mousex + mcursor.x, mousey + mcursor.y); - // left button - if (mouseb & 4) - if (!(ob & 4)) - rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON1, - mousex + mcursor.x, mousey + mcursor.y); - if (ob & 4) - if (!(mouseb & 4)) - rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON1, - mousex + mcursor.x, mousey + mcursor.y); - } - if (mousex != ox || mousey != oy) // movement - { - rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE, - mousex + mcursor.x, mousey + mcursor.y); - draw_cursor_under(ox, oy); - draw_cursor(); - } -} - -/*****************************************************************************/ -void process_keyboard(void) -{ - if (!UpAndRunning) - return; -} - -/*****************************************************************************/ -RD_BOOL ui_main_loop(void) -{ - int sel; - fd_set rfds; - - if (!rdp_connect(g_servername, RDP_LOGON_NORMAL, "", "", "", "")) - return False; - UpAndRunning = 1; - FD_ZERO(&rfds); - FD_SET(g_sock, &rfds); - sel = vga_waitevent(3, &rfds, NULL, NULL, NULL); - while (sel >= 0) - { - if (sel & 1) /* mouse */ - { - process_mouse(); - } - else if (sel & 2) /* keyboard */ - { - process_keyboard(); - } - else - { - if (!rdp_loop(&deactivated, &ext_disc_reason)) - return True; /* ok */ - } - FD_ZERO(&rfds); - FD_SET(g_sock, &rfds); - sel = vga_waitevent(3, &rfds, NULL, NULL, NULL); - } - return True; -} - -/*****************************************************************************/ -void ui_bell(void) -{ -} - -/*****************************************************************************/ -int ui_select(int in) -{ - g_sock = in; - return 1; -} - -/*****************************************************************************/ -void* ui_create_glyph(int width, int height, uint8* data) -{ - int i, j; - uint8* glyph_data; - bitmap* the_glyph; - - glyph_data = (uint8*)xmalloc(width * height); - the_glyph = (bitmap*)xmalloc(sizeof(bitmap)); - the_glyph->width = width; - the_glyph->height = height; - the_glyph->data = glyph_data; - memset(glyph_data, 0, width * height); - for (i = 0; i < height; i++) - for (j = 0; j < width; j++) - if (is_pixel_on(data, j, i, width, 1)) - set_pixel_on(glyph_data, j, i, width, 8, 255); - return the_glyph; -} - -/*****************************************************************************/ -void ui_destroy_glyph(void* glyph) -{ - bitmap* the_glyph; - - the_glyph = (bitmap*)glyph; - if (the_glyph != NULL) - { - if (the_glyph->data != NULL) - xfree(the_glyph->data); - xfree(the_glyph); - } -} - -/*****************************************************************************/ -void ui_destroy_bitmap(void* bmp) -{ - bitmap* b; - - b = (bitmap*)bmp; - xfree(b->data); - xfree(b); -} - -/*****************************************************************************/ -void ui_reset_clip(void) -{ - clip_startx = 0; - clip_starty = 0; - clip_endx = g_width; - clip_endy = g_height; -} - -/*****************************************************************************/ -void ui_set_clip(int x, int y, int cx, int cy) -{ - clip_startx = x; - clip_starty = y; - clip_endx = x + cx; - clip_endy = y + cy; -} - -/*****************************************************************************/ -void* ui_create_colourmap(COLOURMAP * colours) -{ - int i = 0; - int n = colours->ncolours; - COLOURENTRY* c = colours->colours; - int* cmap = (int*)xmalloc(3 * 256 * sizeof (int)); - if (n > 256) - n = 256; - bzero(cmap, 256 * 3 * sizeof (int)); - for (i = 0; i < (3 * n); c++) - { - cmap[i++] = (c->red) >> 2; - cmap[i++] = (c->green) >> 2; - cmap[i++] = (c->blue) >> 2; - } - return cmap; -} - -/*****************************************************************************/ -void ui_destroy_colourmap(RD_HCOLOURMAP map) -{ - if (colmap == map) - colmap = 0; - xfree(map); -} - -/*****************************************************************************/ -void ui_set_colourmap(void* map) -{ - if (colmap != 0) - xfree(colmap); - vga_setpalvec(0, 256, (int*)map); - colmap = map; -} - -/*****************************************************************************/ -RD_HBITMAP ui_create_bitmap(int width, int height, uint8* data) -{ - bitmap* b; - - b = (bitmap*)xmalloc(sizeof(bitmap)); - b->data = (uint8*)xmalloc(width * height * g_server_Bpp); - b->width = width; - b->height = height; - b->Bpp = g_server_Bpp; - copy_mem(b->data, data, width * height * g_server_Bpp); - return (void*)b; -} - -//***************************************************************************** -void draw_glyph (int x, int y, RD_HGLYPH glyph, int fgcolour) -{ - bitmap* the_glyph; - int i, j; - - the_glyph = (bitmap*)glyph; - if (the_glyph == NULL) - return; - for (i = 0; i < the_glyph->height; i++) - for (j = 0; j < the_glyph->width; j++) - if (is_pixel_on(the_glyph->data, j, i, the_glyph->width, 8)) - set_pixel(x + j, y + i, fgcolour, 0xc); -} - -#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; - - if (boxcx > 1) - { - if (contains_mouse(boxx, boxy, boxcx, boxcy)) - draw_cursor_under(mousex, mousey); - fill_rect(boxx, boxy, boxcx, boxcy, bgcolour, 0xc); - } - else - { - if (contains_mouse(clipx, clipy, clipcx, clipcy)) - draw_cursor_under(mousex, mousey); - if (mixmode == MIX_OPAQUE) - fill_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) - cache_rect(boxx, boxy, boxcx, boxcy, True); - else - cache_rect(clipx, clipy, clipcx, clipcy, True); -} - -//***************************************************************************** -// Bresenham's line drawing algorithm -void ui_line(uint8 opcode, int startx, int starty, int endx, - int endy, PEN* pen) -{ - int dx; - int dy; - int incx; - int incy; - int dpr; - int dpru; - int p; - int left; - int top; - int right; - int bottom; - - if (startx > endx) - { - dx = startx - endx; - incx = -1; - left = endx; - right = startx; - } - else - { - dx = endx - startx; - incx = 1; - left = startx; - right = endx; - } - if (starty > endy) - { - dy = starty - endy; - incy = -1; - top = endy; - bottom = starty; - } - else - { - dy = endy - starty; - incy = 1; - top = starty; - bottom = endy; - } - if (contains_mouse(left, top, (right - left) + 1, (bottom - top) + 1)) - draw_cursor_under(mousex, mousey); - if (dx >= dy) - { - dpr = dy << 1; - dpru = dpr - (dx << 1); - p = dpr - dx; - for (; dx >= 0; dx--) - { - set_pixel(startx, starty, pen->colour, opcode); - if (p > 0) - { - startx += incx; - starty += incy; - p += dpru; - } - else - { - startx += incx; - p += dpr; - } - } - } - else - { - dpr = dx << 1; - dpru = dpr - (dy << 1); - p = dpr - dy; - for (; dy >= 0; dy--) - { - set_pixel(startx, starty, pen->colour, opcode); - if (p > 0) - { - startx += incx; - starty += incy; - p += dpru; - } - else - { - starty += incy; - p += dpr; - } - } - } - cache_rect(left, top, (right - left) + 1, (bottom - top) + 1, True); -} - -/*****************************************************************************/ -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) -{ - // non used -} - -/*****************************************************************************/ -void ui_memblt(uint8 opcode, int x, int y, int cx, int cy, - RD_HBITMAP src, int srcx, int srcy) -{ - bitmap* b; - int i; - int j; - int pixel; - - if (warp_coords(&x, &y, &cx, &cy, &srcx, &srcy)) - { - if (contains_mouse(x, y, cx, cy)) - draw_cursor_under(mousex, mousey); - b = (bitmap*)src; - if (opcode == 0xc) - accel_draw_box(x, y, cx, cy, get_ptr(srcx, srcy, b->data, b->width, g_server_depth), - b->width * g_server_Bpp); - else - { - for (i = 0; i < cy; i++) - { - for (j = 0; j < cx; j++) - { - pixel = get_pixel2(srcx + j, srcy + i, b->data, b->width, g_server_depth); - set_pixel(x + j, y + i, pixel, opcode); - } - } - } - cache_rect(x, y, cx, cy, False); - } -} - -/*****************************************************************************/ -void ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy) -{ - uint8* p; - - if (offset > 0x38400) - offset = 0; - if (offset + cx * cy > 0x38400) - return; - p = desk_save + offset * g_server_Bpp; - ui_paint_bitmap(x, y, cx, cy, cx, cy, p); -} - -/*****************************************************************************/ -void ui_desktop_save(uint32 offset, int x, int y, int cx, int cy) -{ - uint8* p; - - if (offset > 0x38400) - offset = 0; - if (offset + cx * cy > 0x38400) - return; - if (contains_mouse(x, y, cx, cy)) - draw_cursor_under(mousex, mousey); - p = desk_save + offset * g_server_Bpp; - get_rect(x, y, cx, cy, p); -} - -/*****************************************************************************/ -void ui_rect(int x, int y, int cx, int cy, int colour) -{ - if (warp_coords(&x, &y, &cx, &cy, NULL, NULL)) - { - if (contains_mouse(x, y, cx, cy)) - draw_cursor_under(mousex, mousey); - accel_fill_rect(x, y, cx, cy, colour); - cache_rect(x, y, cx, cy, False); - } -} - -/*****************************************************************************/ -void ui_screenblt(uint8 opcode, int x, int y, int cx, int cy, - int srcx, int srcy) -{ - int i; - int j; - uint8* temp; - - if (x == srcx && y == srcy) - return; - if (warp_coords(&x, &y, &cx, &cy, &srcx, &srcy)) - { - if (contains_mouse(x, y, cx, cy) || contains_mouse(srcx, srcy, cx, cy)) - draw_cursor_under(mousex, mousey); - if (opcode == 0xc) /* copy */ - accel_screen_copy(x, y, cx, cy, srcx, srcy); - else - { - temp = (uint8*)xmalloc(cx * cy * g_server_Bpp); - for (i = 0; i < cy; i++) - for (j = 0; j < cx; j++) - set_pixel2(j, i, get_pixel(srcx + j, srcy + i), temp, cx, g_server_depth); - for (i = 0; i < cy; i++) - for (j = 0; j < cx; j++) - set_pixel(x + j, y + i, get_pixel2(j, i, temp, cx, g_server_depth), opcode); - xfree(temp); - } - cache_rect(x, y, cx, cy, False); - draw_cache_rects(); // draw them all so screen is not jumpy - } -} - -/*****************************************************************************/ -void ui_patblt(uint8 opcode, int x, int y, int cx, int cy, - BRUSH * brush, int bgcolour, int fgcolour) -{ - int i; - int j; - uint8 ipattern[8]; - - if (warp_coords(&x, &y, &cx, &cy, NULL, NULL)) - { - if (contains_mouse(x, y, cx, cy)) - draw_cursor_under(mousex, mousey); - switch (brush->style) - { - case 0: - fill_rect(x, y, cx, cy, fgcolour, opcode); - break; - case 3: - for (i = 0; i < 8; i++) - ipattern[i] = ~brush->pattern[7 - i]; - for (i = 0; i < cy; i++) - for (j = 0; j < cx; j++) - if (is_pixel_on(ipattern, (x + j + brush->xorigin) % 8, - (y + i + brush->yorigin) % 8, 8, 1)) - set_pixel(x + j, y + i, fgcolour, opcode); - else - set_pixel(x + j, y + i, bgcolour, opcode); - break; - } - cache_rect(x, y, cx, cy, False); - } -} - -/*****************************************************************************/ -void ui_destblt(uint8 opcode, int x, int y, int cx, int cy) -{ - if (warp_coords(&x, &y, &cx, &cy, NULL, NULL)) - { - if (contains_mouse(x, y, cx, cy)) - draw_cursor_under(mousex, mousey); - fill_rect(x, y, cx, cy, -1, opcode); - cache_rect(x, y, cx, cy, False); - } -} - -/*****************************************************************************/ -void ui_move_pointer(int x, int y) -{ -} - -/*****************************************************************************/ -void ui_set_null_cursor(void) -{ - draw_cursor_under(mousex, mousey); - mousex = mousex - mcursor.x; - mousey = mousey - mcursor.y; - memset(&mcursor, 0, sizeof(mcursor)); - memset(mcursor.andmask, 255, sizeof(mcursor.andmask)); - memset(mcursor.xormask, 0, sizeof(mcursor.xormask)); - draw_cursor(); -} - -/*****************************************************************************/ -void ui_paint_bitmap(int x, int y, int cx, int cy, - int width, int height, uint8* data) -{ - if (warp_coords(&x, &y, &cx, &cy, NULL, NULL)) - { - if (contains_mouse(x, y, cx, cy)) - draw_cursor_under(mousex, mousey); - accel_draw_box(x, y, cx, cy, data, width * g_server_Bpp); - cache_rect(x, y, cx, cy, False); - } -} - -/*****************************************************************************/ -void* ui_create_cursor(unsigned int x, unsigned int y, - int width, int height, - uint8* andmask, uint8* xormask) -{ - tcursor* c; - int i; - int j; - - c = (tcursor*)xmalloc(sizeof(tcursor)); - memset(c, 0, sizeof(tcursor)); - c->w = width; - c->h = height; - c->x = x; - c->y = y; - for (i = 0; i < 32; i++) - { - for (j = 0; j < 32; j++) - { - if (is_pixel_on(andmask, j, i, 32, 1)) - set_pixel_on(c->andmask, j, 31 - i, 32, 8, 255); - if (is_pixel_on(xormask, j, i, 32, 24)) - set_pixel_on(c->xormask, j, 31 - i, 32, 8, 255); - } - } - return (void*)c; -} - -/*****************************************************************************/ -void ui_destroy_cursor(void* cursor) -{ - if (cursor != NULL) - xfree(cursor); -} - -/*****************************************************************************/ -void ui_set_cursor(void* cursor) -{ - int x; - int y; - int ox; - int oy; - - ox = mousex; - oy = mousey; - x = mousex + mcursor.x; - y = mousey + mcursor.y; - memcpy(&mcursor, cursor, sizeof(tcursor)); - mousex = x - mcursor.x; - mousey = y - mcursor.y; - draw_cursor_under(ox, oy); - draw_cursor(); -} - -/*****************************************************************************/ -uint16 ui_get_numlock_state(unsigned int state) -{ - return 0; -} - -/*****************************************************************************/ -unsigned int read_keyboard_state(void) -{ - return 0; -} - -/*****************************************************************************/ -void ui_resize_window(void) -{ -} - -/*****************************************************************************/ -void ui_begin_update(void) -{ -} - -/*****************************************************************************/ -void ui_end_update(void) -{ - draw_cache_rects(); - draw_cursor(); -} - -/*****************************************************************************/ -void ui_polygon(uint8 opcode, uint8 fillmode, RD_POINT * point, int npoints, - BRUSH * brush, int bgcolour, int fgcolour) -{ -} - -/*****************************************************************************/ -void ui_polyline(uint8 opcode, RD_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 generate_random(uint8* random) -{ - memcpy(random, "12345678901234567890123456789012", 32); -} - -/*****************************************************************************/ -void save_licence(uint8* data, int length) -{ -} - -/*****************************************************************************/ -int load_licence(uint8** data) -{ - return 0; -} - -/*****************************************************************************/ -void* xrealloc(void* in_val, int size) -{ - return realloc(in_val, size); -} - -/*****************************************************************************/ -void* xmalloc(int size) -{ - return malloc(size); -} - -/*****************************************************************************/ -void xfree(void* in_val) -{ - free(in_val); -} - -/*****************************************************************************/ -char * xstrdup(const char * s) -{ - char * mem = strdup(s); - if (mem == NULL) - { - perror("strdup"); - exit(1); - } - return mem; -} - -/*****************************************************************************/ -void warning(char* format, ...) -{ - va_list ap; - - fprintf(stderr, "WARNING: "); - va_start(ap, format); - vfprintf(stderr, format, ap); - va_end(ap); -} - -/*****************************************************************************/ -void unimpl(char* format, ...) -{ - va_list ap; - - fprintf(stderr, "NOT IMPLEMENTED: "); - va_start(ap, format); - vfprintf(stderr, format, ap); - va_end(ap); -} - -/*****************************************************************************/ -void error(char* format, ...) -{ - va_list ap; - - fprintf(stderr, "ERROR: "); - va_start(ap, format); - vfprintf(stderr, format, ap); - va_end(ap); -} - -RD_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; -} - -/*****************************************************************************/ -RD_BOOL rd_lock_file(int fd, int start, int len) -{ - return False; -} - -/*****************************************************************************/ -void get_username_and_hostname(void) -{ - char fullhostname[64]; - char* p; - struct passwd* pw; - - STRNCPY(g_username, "unknown", sizeof(g_username)); - STRNCPY(g_hostname, "unknown", sizeof(g_hostname)); - pw = getpwuid(getuid()); - if (pw != NULL && pw->pw_name != NULL) - { - STRNCPY(g_username, pw->pw_name, sizeof(g_username)); - } - if (gethostname(fullhostname, sizeof(fullhostname)) != -1) - { - p = strchr(fullhostname, '.'); - if (p != NULL) - *p = 0; - STRNCPY(g_hostname, fullhostname, sizeof(g_hostname)); - } -} - -/*****************************************************************************/ -void out_params(void) -{ - fprintf(stderr, "rdesktop: A Remote Desktop Protocol client.\n"); - fprintf(stderr, "Version " VERSION ". Copyright (C) 1999-2003 Matt Chapman.\n"); - fprintf(stderr, "See http://www.rdesktop.org/ for more information.\n\n"); - fprintf(stderr, "Usage: svgardesktop [options] server\n"); - fprintf(stderr, " -g: desktop geometry (WxH)\n"); - fprintf(stderr, " -4: use RDP version 4\n"); - fprintf(stderr, " -5: use RDP version 5 (default)\n"); - fprintf(stderr, " -t: tcp port\n"); - fprintf(stderr, " -u: user name\n"); - fprintf(stderr, " -n: client hostname\n"); - fprintf(stderr, " -d: disable accel funcs\n"); - fprintf(stderr, " -a: connection colour depth\n"); - fprintf(stderr, " -l: low memory\n"); - fprintf(stderr, "\n"); -} - -/* produce a hex dump */ -void hexdump(uint8* p, uint32 len) -{ - uint8* line; - int i; - int thisline; - int offset; - - line = p; - offset = 0; - while (offset < 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; - } -} - -/*****************************************************************************/ -int parse_parameters(int in_argc, char** in_argv) -{ - int i; - char* p; - - if (in_argc <= 1) - { - out_params(); - return 0; - } - g_argc = in_argc; - g_argv = in_argv; - for (i = 1; i < in_argc; i++) - { - strcpy(g_servername, in_argv[i]); - if (strcmp(in_argv[i], "-g") == 0) - { - g_width = strtol(in_argv[i + 1], &p, 10); - if (g_width <= 0) - { - error("invalid geometry\n"); - return 0; - } - if (*p == 'x') - g_height = strtol(p + 1, NULL, 10); - if (g_height <= 0) - { - error("invalid geometry\n"); - return 0; - } - g_width = (g_width + 3) & ~3; - } - else if (strcmp(in_argv[i], "-4") == 0) - g_use_rdp5 = 0; - else if (strcmp(in_argv[i], "-5") == 0) - g_use_rdp5 = 1; - else if (strcmp(in_argv[i], "-t") == 0) - g_tcp_port_rdp = strtol(in_argv[i + 1], &p, 10); - else if (strcmp(in_argv[i], "-h") == 0) - { - out_params(); - return 0; - } - else if (strcmp(in_argv[i], "-n") == 0) - { - STRNCPY(g_hostname, in_argv[i + 1], sizeof(g_hostname)); - } - else if (strcmp(in_argv[i], "-u") == 0) - { - STRNCPY(g_username, in_argv[i + 1], sizeof(g_username)); - } - else if (strcmp(in_argv[i], "-d") == 0) - { - use_accel = 0; - } - else if (strcmp(in_argv[i], "-a") == 0) - { - g_server_depth = strtol(in_argv[i + 1], NULL, 10); - if (g_server_depth != 8 && g_server_depth != 16) - { - error("invalid server bpp\n"); - return 0; - } - g_server_Bpp = (g_server_depth + 7) / 8; - } - else if (strcmp(in_argv[i], "-l") == 0) - g_save_mem = 1; - } - return 1; -} - -/*****************************************************************************/ -int main(int in_argc, char** in_argv) -{ - get_username_and_hostname(); - if (!parse_parameters(in_argc, in_argv)) - return 0; - if (!ui_init()) - return 1; - if (!ui_create_window()) - return 1; - ui_main_loop(); - ui_destroy_window(); - ui_deinit(); - return 0; -} diff -Nru rdesktop-1.8.6/uiports/xxxwin.c rdesktop-1.9.0/uiports/xxxwin.c --- rdesktop-1.8.6/uiports/xxxwin.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/uiports/xxxwin.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,366 +0,0 @@ -/* -*- c-basic-offset: 8 -*- - rdesktop: A Remote Desktop Protocol client. - User interface services - Generic - Copyright (C) Jay Sorg 2004-2007 - - 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 3 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, see <http://www.gnu.org/licenses/>. -*/ - -#include "../rdesktop.h" - -extern int g_tcp_port_rdp; /* in tcp.c */ -RD_BOOL g_use_rdp5 = False; -char g_hostname[16]; -char g_username[64]; -int g_height = 600; -int g_width = 800; -int g_server_depth = 8; -RD_BOOL g_encryption = True; -RD_BOOL g_desktop_save = True; -RD_BOOL g_polygon_ellipse_orders = False; -RD_BOOL g_bitmap_cache = True; -RD_BOOL g_bitmap_cache_persist_enable = False; -RD_BOOL g_bitmap_cache_precache = True; -RD_BOOL g_bitmap_compression = True; -uint32 g_rdp5_performanceflags = 0; -RD_BOOL g_console_session = False; -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 */ -/* Session Directory redirection */ -RD_BOOL g_redirect = False; -RD_BOOL g_numlock_sync = 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; -char g_codepage[16] = ""; - -/*****************************************************************************/ -void ui_bell(void) -{ -} - -/*****************************************************************************/ -int ui_select(int in) -{ - return 1; -} - -/*****************************************************************************/ -void ui_destroy_cursor(void* cursor) -{ -} - -/*****************************************************************************/ -void* ui_create_glyph(int width, int height, uint8* data) -{ - return 0; -} - -/*****************************************************************************/ -void ui_destroy_glyph(void* glyph) -{ -} - -/*****************************************************************************/ -void ui_destroy_bitmap(void* bmp) -{ -} - -/*****************************************************************************/ -void ui_reset_clip(void) -{ -} - -/*****************************************************************************/ -void ui_set_clip(int x, int y, int cx, int cy) -{ -} - -/*****************************************************************************/ -void* ui_create_colourmap(COLOURMAP * colours) -{ - return 0; -} - -/*****************************************************************************/ -void ui_set_colourmap(void* map) -{ -} - -/*****************************************************************************/ -RD_HBITMAP ui_create_bitmap(int width, int height, uint8* data) -{ - return 0; -} - -/*****************************************************************************/ -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_line(uint8 opcode, int startx, int starty, int endx, int endy, - PEN * pen) -{ -} - -/*****************************************************************************/ -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_memblt(uint8 opcode, int x, int y, int cx, int cy, - RD_HBITMAP src, int srcx, int srcy) -{ -} - -/*****************************************************************************/ -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) -{ -} - -/*****************************************************************************/ -void ui_screenblt(uint8 opcode, int x, int y, int cx, int cy, - int srcx, int srcy) -{ -} - -/*****************************************************************************/ -void ui_patblt(uint8 opcode, int x, int y, int cx, int cy, - BRUSH * brush, int bgcolour, int fgcolour) -{ -} - -/*****************************************************************************/ -void ui_destblt(uint8 opcode, int x, int y, int cx, int cy) -{ -} - -/*****************************************************************************/ -void ui_move_pointer(int x, int y) -{ -} - -/*****************************************************************************/ -void ui_set_null_cursor(void) -{ -} - -/*****************************************************************************/ -void ui_paint_bitmap(int x, int y, int cx, int cy, - int width, int height, uint8* data) -{ -} - -/*****************************************************************************/ -void ui_set_cursor(RD_HCURSOR cursor) -{ -} - -/*****************************************************************************/ -RD_HCURSOR ui_create_cursor(unsigned int x, unsigned int y, - int width, int height, - uint8* andmask, uint8* xormask) -{ - return 0; -} - -/*****************************************************************************/ -uint16 ui_get_numlock_state(unsigned int state) -{ - return 0; -} - -/*****************************************************************************/ -unsigned int read_keyboard_state(void) -{ - return 0; -} - -/*****************************************************************************/ -void ui_resize_window(void) -{ -} - -/*****************************************************************************/ -void ui_begin_update(void) -{ -} - -/*****************************************************************************/ -void ui_end_update(void) -{ -} - -/*****************************************************************************/ -void ui_polygon(uint8 opcode, uint8 fillmode, RD_POINT * point, int npoints, - BRUSH * brush, int bgcolour, int fgcolour) -{ -} - -/*****************************************************************************/ -/* todo, use qt function for this (QPainter::drawPolyline) */ -void ui_polyline(uint8 opcode, RD_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) -{ -} - -/*****************************************************************************/ -void generate_random(uint8* random) -{ -} - -/*****************************************************************************/ -void save_licence(uint8* data, int length) -{ -} - -/*****************************************************************************/ -int load_licence(uint8** data) -{ - return 0; -} - -/*****************************************************************************/ -void* xrealloc(void* in, int size) -{ - return 0; -} - -/*****************************************************************************/ -void* xmalloc(int size) -{ - return 0; -} - -/*****************************************************************************/ -void xfree(void* in) -{ -} - -/*****************************************************************************/ -char * xstrdup(const char * s) -{ - char * mem = strdup(s); - if (mem == NULL) - { - perror("strdup"); - exit(1); - } - return mem; -} -/*****************************************************************************/ -void warning(char* format, ...) -{ -} - -/*****************************************************************************/ -void unimpl(char* format, ...) -{ -} - -/*****************************************************************************/ -void error(char* format, ...) -{ -} - -/*****************************************************************************/ -RD_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; -} - -/*****************************************************************************/ -RD_BOOL rd_lock_file(int fd, int start, int len) -{ - return False; -} - -/*****************************************************************************/ -int main(int c, char** p) -{ - return 0; -} diff -Nru rdesktop-1.8.6/utils.c rdesktop-1.9.0/utils.c --- rdesktop-1.8.6/utils.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/utils.c 2019-09-17 14:58:22.000000000 +0000 @@ -1,7 +1,7 @@ /* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Generic utility functions - Copyright 2013 Henrik Andersson <hean01@cendio.se> for Cendio AB + Copyright 2013-2019 Henrik Andersson <hean01@cendio.se> for Cendio AB 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 @@ -21,18 +21,32 @@ #include <string.h> #include <sys/stat.h> #include <errno.h> -#ifdef HAVE_ICONV_H #include <iconv.h> -#endif +#include <stdarg.h> +#include <assert.h> + #include "rdesktop.h" +#include "utils.h" -#ifdef HAVE_ICONV extern char g_codepage[16]; + static RD_BOOL g_iconv_works = True; -#endif +uint32 +utils_djb2_hash(const char *str) +{ + uint8 c; + uint8 *pstr; + uint32 hash = 5381; + pstr = (uint8 *) str; + while ((c = *pstr++)) + { + hash = ((hash << 5) + hash) + c; + } + return hash; +} char * utils_string_escape(const char *str) @@ -81,7 +95,8 @@ char * utils_string_unescape(const char *str) { - char *ns, *ps, *pd, c; + char *ns, *ps, *pd; + unsigned char c; ns = xmalloc(strlen(str) + 1); memcpy(ns, str, strlen(str) + 1); @@ -94,7 +109,7 @@ { if (sscanf(ps, "%%%2hhX", &c) == 1) { - pd[0] = c; + pd[0] = (char) c; ps += 3; pd++; continue; @@ -173,11 +188,10 @@ return 0; } -/* Convert from system locale string to utf-8 */ +/* Convert from system locale string to UTF-8 */ int utils_locale_to_utf8(const char *src, size_t is, char *dest, size_t os) { -#ifdef HAVE_ICONV static iconv_t *iconv_h = (iconv_t) - 1; if (strncmp(g_codepage, "UTF-8", strlen("UTF-8")) == 0) goto pass_trough_as_is; @@ -190,8 +204,9 @@ { if ((iconv_h = iconv_open("UTF-8", g_codepage)) == (iconv_t) - 1) { - warning("utils_string_to_utf8: iconv_open[%s -> %s] fail %p\n", - g_codepage, "UTF-8", iconv_h); + logger(Core, Warning, + "utils_string_to_utf8(), iconv_open[%s -> %s] fail %p", g_codepage, + "UTF-8", iconv_h); g_iconv_works = False; goto pass_trough_as_is; @@ -199,21 +214,20 @@ } /* convert string */ - if (iconv(iconv_h, (ICONV_CONST char **) &src, &is, &dest, &os) == (size_t) - 1) + if (iconv(iconv_h, (char **) &src, &is, &dest, &os) == (size_t) - 1) { iconv_close(iconv_h); iconv_h = (iconv_t) - 1; - warning("utils_string_to_utf8: iconv(1) fail, errno %d\n", errno); + logger(Core, Warning, "utils_string_to_utf8, iconv(1) fail, errno %d", errno); g_iconv_works = False; goto pass_trough_as_is; } - /* Out couldn't hold the entire convertion */ + /* Out couldn't hold the entire conversion */ if (is != 0) return -1; -#endif pass_trough_as_is: /* can dest hold strcpy of src */ if (os < (strlen(src) + 1)) @@ -222,3 +236,825 @@ memcpy(dest, src, strlen(src) + 1); return 0; } + + +void +utils_calculate_dpi_scale_factors(uint32 width, uint32 height, uint32 dpi, + uint32 * physwidth, uint32 * physheight, + uint32 * desktopscale, uint32 * devicescale) +{ + *physwidth = *physheight = *desktopscale = *devicescale = 0; + + if (dpi > 0) + { + *physwidth = width * 254 / (dpi * 10); + *physheight = height * 254 / (dpi * 10); + + /* the spec calls this out as being valid for range + 100-500 but I doubt the upper range is accurate */ + *desktopscale = dpi < 96 ? 100 : (dpi * 100 + 48) / 96; + + /* the only allowed values for device scale factor are + 100, 140, and 180. */ + *devicescale = dpi < 134 ? 100 : (dpi < 173 ? 140 : 180); + + } +} + + +void +utils_apply_session_size_limitations(uint32 * width, uint32 * height) +{ + /* width MUST be even number */ + *width -= (*width) % 2; + + if (*width > 8192) + *width = 8192; + else if (*width < 200) + *width = 200; + + if (*height > 8192) + *height = 8192; + else if (*height < 200) + *height = 200; +} + +#define MAX_CHOICES 10 +const char * +util_dialog_choice(const char *message, ...) +{ + int i; + va_list ap; + char *p; + const char *choice; + char response[512]; + const char *choices[MAX_CHOICES] = {0}; + + /* gather choices into array */ + va_start(ap, message); + for (i = 0; i < MAX_CHOICES; i++) + { + choices[i] = va_arg(ap, const char *); + if (choices[i] == NULL) + break; + } + va_end(ap); + + choice = NULL; + while (choice == NULL) + { + /* display message */ + fprintf(stderr,"\n%s", message); + + /* read input */ + if (fgets(response, sizeof(response), stdin) != NULL) + { + /* strip final newline */ + p = strchr(response, '\n'); + if (p != NULL) + *p = 0; + + for (i = 0; i < MAX_CHOICES; i++) + { + if (choices[i] == NULL) + break; + + if (strcmp(response, choices[i]) == 0) + { + choice = choices[i]; + break; + } + } + } + else + { + logger(Core, Error, "Failed to read response from stdin"); + break; + } + } + + return choice; +} + +/* + * component logging + * + */ + +static char *level[] = { + "debug", + "verbose", /* Verbose message for end user, no prefixed lines */ + "warning", + "error", + "notice" /* Normal messages for end user, no prefixed lines */ +}; + +static char *subject[] = { + "UI", + "Keyboard", + "Clipboard", + "Sound", + "Protocol", + "Graphics", + "Core", + "SmartCard", + "Disk" +}; + +static log_level_t _logger_level = Warning; + +#define DEFAULT_LOGGER_SUBJECTS (1 << Core) + +#define ALL_LOGGER_SUBJECTS \ + (1 << GUI) \ + | (1 << Keyboard) \ + | (1 << Clipboard) \ + | (1 << Sound) \ + | (1 << Protocol) \ + | (1 << Graphics) \ + | (1 << Core) \ + | (1 << SmartCard) \ + | (1 << Disk) + + +static int _logger_subjects = DEFAULT_LOGGER_SUBJECTS; + +void +logger(log_subject_t s, log_level_t lvl, char *format, ...) +{ + va_list ap; + char buf[1024]; + + // Do not log if message is below global log level + if (_logger_level > lvl) + return; + + // Skip debug logging for non specified subjects + if (lvl < Verbose && !(_logger_subjects & (1 << s))) + return; + + va_start(ap, format); + vsnprintf(buf, sizeof(buf), format, ap); + + // Notice and Verbose messages goes without prefix + if (lvl == Notice || lvl == Verbose) + fprintf(stdout, "%s\n", buf); + else + fprintf(stderr, "%s(%s): %s\n", subject[s], level[lvl], buf); + + fflush(stdout); + + va_end(ap); +} + +void +logger_set_verbose(int verbose) +{ + if (_logger_level < Verbose) + return; + + if (verbose) + _logger_level = Verbose; + else + _logger_level = Warning; +} + +void +logger_set_subjects(char *subjects) +{ + int clear; + int bit; + char *pcs; + char *token; + + if (!subjects || !strlen(subjects)) + return; + + pcs = strdup(subjects); + + token = strtok(pcs, ","); + if (token == NULL) + { + free(pcs); + return; + } + + _logger_subjects = 0; + + do + { + + if (token == NULL) + break; + + bit = 0; + clear = (token[0] == '-') ? 1 : 0; + + if (clear == 1) + token++; + + if (strcmp(token, "All") == 0) + _logger_subjects |= ALL_LOGGER_SUBJECTS; + else if (strcmp(token, "UI") == 0) + bit = (1 << GUI); + else if (strcmp(token, "Keyboard") == 0) + bit = (1 << Keyboard); + else if (strcmp(token, "Clipboard") == 0) + bit = (1 << Clipboard); + else if (strcmp(token, "Sound") == 0) + bit = (1 << Sound); + else if (strcmp(token, "Protocol") == 0) + bit = (1 << Protocol); + else if (strcmp(token, "Graphics") == 0) + bit = (1 << Graphics); + else if (strcmp(token, "Core") == 0) + bit = (1 << Core); + else if (strcmp(token, "SmartCard") == 0) + bit = (1 << SmartCard); + else if (strcmp(token, "Disk") == 0) + bit = (1 << Disk); + else + continue; + + // set or clear logger subject bit + if (clear) + _logger_subjects &= ~bit; + else + _logger_subjects |= bit; + + } + while ((token = strtok(NULL, ",")) != NULL); + + _logger_level = Debug; + + free(pcs); +} + +static size_t +_utils_data_to_hex(uint8 *data, size_t len, char *out, size_t size) +{ + size_t i; + char hex[4]; + + assert((len * 2) < size); + + memset(out, 0, size); + for (i = 0; i < len; i++) + { + snprintf(hex, sizeof(hex), "%.2x", data[i]); + strcat(out, hex); + } + + return (len*2); +} + +static size_t +_utils_oid_to_string(const char *oid, char *out, size_t size) +{ + memset(out, 0, size); + if (strcmp(oid, "0.9.2342.19200300.100.1.25") == 0) { + snprintf(out, size, "%s", "DC"); + } + else if (strcmp(oid, "2.5.4.3") == 0) { + snprintf(out, size, "%s", "CN"); + } + else if (strcmp(oid, "1.2.840.113549.1.1.13") == 0) + { + snprintf(out, size, "%s", "sha512WithRSAEncryption"); + } + else + { + snprintf(out, size, "%s", oid); + } + + return strlen(out); +} + +static int +_utils_dn_to_string(gnutls_x509_dn_t dn, RD_BOOL exclude_oid, + char *out, size_t size) +{ + int i, j; + char buf[128] = {0}; + char name[64] = {0}; + char result[1024] = {0}; + size_t left; + gnutls_x509_ava_st ava; + + left = sizeof(result); + + for (j = 0; j < 100; j++) + { + for (i = 0; i < 100; i++) + { + if (gnutls_x509_dn_get_rdn_ava(dn, j, i, &ava) != 0) + { + break; + } + + if (exclude_oid) + { + snprintf(buf, sizeof(buf), "%.*s", ava.value.size, ava.value.data); + strncat(result, buf, left); + left -= strlen(buf); + } + else + { + _utils_oid_to_string((char *)ava.oid.data, name, sizeof(name)); + snprintf(buf, sizeof(buf), "%s%s=%.*s", + (j > 0)?", ":"", name, ava.value.size, ava.value.data); + strncat(result, buf, left); + left -= strlen(buf); + } + } + + if (i == 0) + { + break; + } + } + + snprintf(out, size, "%s", result); + + return 0; +} + +static void +_utils_cert_get_info(gnutls_x509_crt_t cert, char *out, size_t size) +{ + char buf[128]; + size_t buf_size; + char digest[128]; + gnutls_x509_dn_t dn; + time_t expire_ts, activated_ts; + + char subject[256]; + char issuer[256]; + char valid_from[256]; + char valid_to[256]; + char sha1[256]; + char sha256[256]; + + /* get subject */ + gnutls_x509_crt_get_subject(cert, &dn); + if (_utils_dn_to_string(dn, False, buf, sizeof(buf)) == 0) + { + snprintf(subject, sizeof(subject), " Subject: %s", buf); + } + + /* get issuer */ + gnutls_x509_crt_get_issuer(cert, &dn); + if (_utils_dn_to_string(dn, False, buf, sizeof(buf)) == 0) + { + snprintf(issuer, sizeof(issuer), " Issuer: %s", buf); + } + + /* get activation / expiration time */ + activated_ts = gnutls_x509_crt_get_activation_time(cert); + snprintf(valid_from, sizeof(valid_from), " Valid From: %s", ctime(&activated_ts)); + + expire_ts = gnutls_x509_crt_get_expiration_time(cert); + snprintf(valid_to, sizeof(valid_to), " To: %s", ctime(&expire_ts)); + + /* get sha1 / sha256 fingerprint */ + buf_size = sizeof(buf); + gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA1, buf, &buf_size); + _utils_data_to_hex((uint8 *)buf, buf_size, digest, sizeof(digest)); + snprintf(sha1, sizeof(sha1), " sha1: %s", digest); + + buf_size = sizeof(buf); + gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA256, buf, &buf_size); + _utils_data_to_hex((uint8 *)buf, buf_size, digest, sizeof(digest)); + snprintf(sha256, sizeof(sha256), " sha256: %s", digest); + + /* render cert info into out */ + snprintf(out, size, + "%s\n" + "%s\n" + "%s" + "%s" + "\n" + " Certificate fingerprints:\n\n" + "%s\n" + "%s\n", subject, issuer, valid_from, valid_to, sha1, sha256); +} + +static int +_utils_cert_san_to_string(gnutls_x509_crt_t cert, char *out, size_t size) +{ + int i, res; + char entries[1024] = {0}; + char san[128] = {0}; + ssize_t left; + size_t san_size; + unsigned int san_type, critical; + + left = sizeof(entries); + + for(i = 0; i < 50; i++) + { + san_size = sizeof(san); + res = gnutls_x509_crt_get_subject_alt_name2(cert, i, san, &san_size, &san_type, &critical); + + /* break if there are no more SAN entries */ + if (res <= 0) + break; + + /* log if we cant handle more san entires in buffer */ + if (left <= 0) + { + logger(Core, Warning, "%s(), buffer is full, at least one SAN entry is missing from list", __func__); + break; + } + + /* add SAN entry to list */ + switch(san_type) + { + case GNUTLS_SAN_IPADDRESS: + case GNUTLS_SAN_DNSNAME: + + if (left < (ssize_t)sizeof(entries)) + { + strncat(entries, ", ", left); + left -= 2; + } + + strncat(entries, san, left); + left -= strlen(san); + + break; + } + } + + if (strlen(entries) == 0) + { + return 1; + } + snprintf(out, size, "%s", entries); + + return 0; +} + +static void +_utils_cert_get_status_report(gnutls_x509_crt_t cert, unsigned int status, + RD_BOOL hostname_mismatch, const char *hostname, + char *out, size_t size) +{ + int i; + char buf[1024]; + char str[1024 + 64]; + + i = 1; + + if (hostname_mismatch == True) + { + snprintf(buf, sizeof(buf), + " %d. The hostname used for this connection does not match any of the names\n" + " given in the certificate.\n\n" + " Hostname: %s\n" + , i++, hostname); + strncat(out, buf, size - 1); + size -= strlen(buf); + + /* parse subject dn */ + gnutls_x509_dn_t dn; + gnutls_x509_crt_get_subject(cert, &dn); + + memset(buf, 0, sizeof(buf)); + if (_utils_dn_to_string(dn, True, buf, sizeof(buf)) == 0) + { + snprintf(str, sizeof(str), " Common Name: %s\n", buf); + strncat(out, str, size); + size -= strlen(str); + } + + /* get SAN entries */ + if (_utils_cert_san_to_string(cert, buf, sizeof(buf)) == 0) + { + snprintf(str, sizeof(str), " Alternate names: %s\n", buf); + strncat(out, str, size); + size -= strlen(str); + } + + strcat(out, "\n"); + size -= 1; + } + + if (status & GNUTLS_CERT_REVOKED) { + snprintf(buf, sizeof(buf), + " %d. Certificate is revoked by its authority\n\n", i++); + strncat(out, buf, size); + size -= strlen(buf); + } + + if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) { + snprintf(buf, sizeof(buf), + " %d. Certificate issuer is not trusted by this system.\n\n", i++); + strncat(out, buf, size); + size -= strlen(buf); + + /* parse subject dn */ + gnutls_x509_dn_t dn; + gnutls_x509_crt_get_issuer(cert, &dn); + + memset(buf, 0, sizeof(buf)); + if (_utils_dn_to_string(dn, False, buf, sizeof(buf)) == 0) + { + snprintf(str, sizeof(str), " Issuer: %s\n\n", buf); + strncat(out, str, size); + size -= strlen(str); + } + } + + if (status & GNUTLS_CERT_SIGNER_NOT_CA) { + snprintf(buf, sizeof(buf), + " %d. Certificate signer is not a CA.\n\n", i++); + strncat(out, buf, size); + size -= strlen(buf); + } + + if (status & GNUTLS_CERT_INSECURE_ALGORITHM) { + snprintf(buf, sizeof(buf), + " %d. Certificate was signed using an insecure algorithm.\n\n", i++); + strncat(out, buf, size); + size -= strlen(buf); + /* TODO: print algorithm*/ + } + + if (status & GNUTLS_CERT_NOT_ACTIVATED) { + snprintf(buf, sizeof(buf), + " %d. Certificate is not yet activated.\n\n", i++); + strncat(out, buf, size); + size -= strlen(buf); + + time_t ts = gnutls_x509_crt_get_activation_time(cert); + snprintf(buf, sizeof(buf), " Valid From: %s\n\n", ctime(&ts)); + strncat(out, buf, size); + size -= strlen(buf); + } + + if (status & GNUTLS_CERT_EXPIRED) { + snprintf(buf, sizeof(buf), + " %d. Certificate has expired.\n\n", i++); + strncat(out, buf, size); + size -= strlen(buf); + + time_t ts = gnutls_x509_crt_get_expiration_time(cert); + snprintf(buf, sizeof(buf), " Valid to: %s\n\n", ctime(&ts)); + strncat(out, buf, size); + size -= strlen(buf); + } + + if (status & GNUTLS_CERT_SIGNATURE_FAILURE) { + snprintf(buf, sizeof(buf), + " %d. Failed to verify the signature of the certificate.\n\n", i++); + strncat(out, buf, size); + size -= strlen(buf); + } + + if (status & GNUTLS_CERT_REVOCATION_DATA_SUPERSEDED) { + snprintf(buf, sizeof(buf), + " %d. Revocation data are old and have been superseded.\n\n", i++); + strncat(out, buf, size); + size -= strlen(buf); + } + + if (status & GNUTLS_CERT_UNEXPECTED_OWNER) { + snprintf(buf, sizeof(buf), + " %d. The owner is not the expected one.\n\n", i++); + strncat(out, buf, size); + size -= strlen(buf); + } + + if (status & GNUTLS_CERT_REVOCATION_DATA_ISSUED_IN_FUTURE) { + snprintf(buf, sizeof(buf), + " %d. The revocation data have a future issue date.\n\n", i++); + strncat(out, buf, size); + size -= strlen(buf); + } + + if (status & GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE) { + snprintf(buf, sizeof(buf), + " %d. The certificate's signer constraints were violated.\n\n", i++); + strncat(out, buf, size); + size -= strlen(buf); + } + + if (status & GNUTLS_CERT_MISMATCH) { + snprintf(buf, sizeof(buf), + " %d. The certificate presented isn't the expected one (TOFU)\n\n", i++); + strncat(out, buf, size); + size -= strlen(buf); + } + +#if GNUTLS_VERSION_NUMBER >= 0x030400 + if (status & GNUTLS_CERT_PURPOSE_MISMATCH) { + snprintf(buf, sizeof(buf), + " %d. The certificate or an intermediate does not match the\n" + " intended purpose (extended key usage).\n\n", i++); + strncat(out, buf, size); + size -= strlen(buf); + } +#endif + +#if GNUTLS_VERSION_NUMBER >= 0x030501 + if (status & GNUTLS_CERT_MISSING_OCSP_STATUS) { + snprintf(buf, sizeof(buf), + " %d. The certificate requires the server to send the certifiate\n" + " status, but no status was received.\n\n", i++); + strncat(out, buf, size); + size -= strlen(buf); + } + + if (status & GNUTLS_CERT_INVALID_OCSP_STATUS) { + snprintf(buf, sizeof(buf), + " %d. The received OCSP status response is invalid.\n\n", i++); + strncat(out, buf, size); + size -= strlen(buf); + } +#endif + +#if GNUTLS_VERSION_NUMBER >= 0x030600 + if (status & GNUTLS_CERT_UNKNOWN_CRIT_EXTENSIONS) { + snprintf(buf, sizeof(buf), + " %d. The certificate has extensions marked as critical which are\n" + " not supported.\n\n", i++); + strncat(out, buf, size); + size -= strlen(buf); + } +#endif +} + +static int +_utils_cert_store_get_filename(char *out, size_t size) +{ + int rv; + char *home; + char dir[PATH_MAX - 12]; + struct stat sb; + + home = getenv("HOME"); + + if (home == NULL) + return 1; + + if (snprintf(dir, sizeof(dir) - 1, "%s/%s", home, ".local/share/rdesktop/certs/") > (int)sizeof(dir)) + { + logger(Core, Error, "%s(), certificate store directory is truncated", __func__); + return 1; + } + + if ((rv = stat(dir, &sb)) == -1) + { + if (errno == ENOENT) + { + if (rd_certcache_mkdir() == False) { + logger(Core, Error, "%s(), failed to create directory '%s'", __func__, dir); + return 1; + } + } + } + else + { + if ((sb.st_mode & S_IFMT) != S_IFDIR) + { + logger(Core, Error, "%s(), %s exists but it's not a directory", + __func__, dir); + return 1; + } + } + + if (snprintf(out, size, "%s/known_certs", dir) > (int)size) + { + logger(Core, Error, "%s(), certificate store filename is truncated", __func__); + return 1; + } + + return 0; +} + +#define TRUST_CERT_PROMPT_TEXT "Do you trust this certificate (yes/no)? " +#define REVIEW_CERT_TEXT \ + "Review the following certificate info before you trust it to be added as an exception.\n" \ + "If you do not trust the certificate the connection atempt will be aborted:" + +int +utils_cert_handle_exception(gnutls_session_t session, unsigned int status, + RD_BOOL hostname_mismatch, const char *hostname) +{ + int rv; + int type; + time_t exp_time; + gnutls_x509_crt_t cert; + const gnutls_datum_t *cert_list; + unsigned int cert_list_size = 0; + + char certcache_fn[PATH_MAX]; + char cert_info[2048] = {0}; + char cert_invalid_reasons[2048] = {0}; + char message[8192] = {0}; + const char *response; + + /* get filename for certificate exception store */ + if (_utils_cert_store_get_filename(certcache_fn, sizeof(certcache_fn)) != 0) + { + logger(Core, Error, "%s(), Failed to get certificate store file, " + "disabling exception handling.", __func__); + return 1; + } + + type = gnutls_certificate_type_get(session); + if (type != GNUTLS_CRT_X509) + { + logger(Core, Error, "%s(), Certificate for session is not an x509 certificate, " + "disabling exception handling.", __func__); + return 1; + } + + + cert_list = gnutls_certificate_get_peers(session, &cert_list_size); + if (cert_list_size == 0) + { + logger(Core, Error, "%s(), Failed to get certificate, " + "disabling exception handling.", __func__); + return 1; + } + + rv = gnutls_verify_stored_pubkey(certcache_fn, NULL, hostname, "rdesktop", type, &cert_list[0], 0); + if (rv == GNUTLS_E_SUCCESS) + { + /* Certificate found in store and matches server */ + logger(Core, Warning, "Certificate received from server is NOT trusted by this system, " + "an exception has been added by the user to trust this specific certificate."); + return 0; + } + else if (rv != GNUTLS_E_CERTIFICATE_KEY_MISMATCH && rv != GNUTLS_E_NO_CERTIFICATE_FOUND) + { + /* Unhandled errors */ + logger(Core, Error, "%s(), verification for host '%s' certificate failed. Error = 0x%x (%s)", + __func__, hostname, rv, gnutls_strerror(rv)); + return 1; + } + + /* + * Give user possibility to add / update certificate to store + */ + + gnutls_x509_crt_init(&cert); + gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER); + _utils_cert_get_info(cert, cert_info, sizeof(cert_info)); + + if (rv == GNUTLS_E_CERTIFICATE_KEY_MISMATCH) + { + /* Certificate from server mismatches the one in store */ + + snprintf(message, sizeof(message), + "ATTENTION! Found a certificate stored for host '%s', but it does not match the certificate\n" + "received from server.\n" + REVIEW_CERT_TEXT + "\n\n" + "%s" + "\n\n" + TRUST_CERT_PROMPT_TEXT + , hostname, cert_info); + + + } + else if (rv == GNUTLS_E_NO_CERTIFICATE_FOUND) + { + /* Certificate is not found in store, propose to add an exception */ + _utils_cert_get_status_report(cert, status, hostname_mismatch, hostname, + cert_invalid_reasons, sizeof(cert_invalid_reasons)); + + snprintf(message, sizeof(message), + "ATTENTION! The server uses and invalid security certificate which can not be trusted for\n" + "the following identified reasons(s);\n\n" + "%s" + "\n" + REVIEW_CERT_TEXT + "\n\n" + "%s" + "\n\n" + TRUST_CERT_PROMPT_TEXT, + cert_invalid_reasons, cert_info); + } + + /* show dialog */ + response = util_dialog_choice(message, "no", "yes", NULL); + if (strcmp(response, "no") == 0 || response == NULL) + { + return 1; + } + + /* user responded with yes, lets add certificate to store */ + logger(Core, Debug, "%s(), adding a new certificate for the host '%s'", __func__, hostname); + exp_time = gnutls_x509_crt_get_expiration_time(cert); + rv = gnutls_store_pubkey(certcache_fn, NULL, hostname, "rdesktop", type, &cert_list[0], exp_time, 0); + if (rv != GNUTLS_E_SUCCESS) + { + logger(Core, Error, "%s(), failed to store certificate. error = 0x%x (%s)", __func__, rv, gnutls_strerror(rv)); + return 1; + } + + return 0; +} diff -Nru rdesktop-1.8.6/utils.h rdesktop-1.9.0/utils.h --- rdesktop-1.8.6/utils.h 1970-01-01 00:00:00.000000000 +0000 +++ rdesktop-1.9.0/utils.h 2019-09-16 07:31:42.000000000 +0000 @@ -0,0 +1,70 @@ +/* -*- c-basic-offset: 8 -*- + rdesktop: A Remote Desktop Protocol client. + + Copyright 2017-2019 Henrik Andersson <hean01@cendio.se> for Cendio AB + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _utils_h +#define _utils_h + +#include <gnutls/gnutls.h> +#include <gnutls/x509.h> + +#include "types.h" + +uint32 utils_djb2_hash(const char *str); +char *utils_string_escape(const char *str); +char *utils_string_unescape(const char *str); +int utils_locale_to_utf8(const char *src, size_t is, char *dest, size_t os); +int utils_mkdir_safe(const char *path, int mask); +int utils_mkdir_p(const char *path, int mask); +void utils_calculate_dpi_scale_factors(uint32 width, uint32 height, uint32 dpi, + uint32 * physwidth, uint32 * physheight, + uint32 * desktopscale, uint32 * devicescale); +void utils_apply_session_size_limitations(uint32 * width, uint32 * height); + +const char* util_dialog_choice(const char *message, ...); + +int utils_cert_handle_exception(gnutls_session_t session, unsigned int status, + RD_BOOL hostname_mismatch, const char *hostname); + +typedef enum log_level_t +{ + Debug = 0, + Verbose, + Warning, + Error, + Notice /* special message level for end user messages with prefix */ +} log_level_t; + +typedef enum log_subject_t +{ + GUI = 0, + Keyboard, + Clipboard, + Sound, + Protocol, + Graphics, + Core, + SmartCard, + Disk +} log_subject_t; + +void logger(log_subject_t c, log_level_t lvl, char *format, ...); +void logger_set_verbose(int verbose); +void logger_set_subjects(char *subjects); + +#endif /* _utils_h */ diff -Nru rdesktop-1.8.6/vnc/vnc.c rdesktop-1.9.0/vnc/vnc.c --- rdesktop-1.8.6/vnc/vnc.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/vnc/vnc.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1375 +0,0 @@ -/* - rdesktop: A Remote Desktop Protocol client. - User interface services - VNC target - Copyright (C) Matthew Chapman 1999-2000 - Copyright (C) 2000 Tim Edmonds - Copyright (C) 2001 James "Wez" Weatherall - Copyright (C) 2001 Johannes E. Schindelin - - 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 3 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, see <http://www.gnu.org/licenses/>. -*/ - - -#include <stdio.h> -#include <time.h> - -#ifdef WIN32 -#define close closesocket -#define strcasecmp _strcmpi -#else -#include <unistd.h> -#include <sys/time.h> /* timeval */ -#include <sys/socket.h> -#endif - -#include "../rdesktop.h" -#undef VERSION - -#ifdef WIN32 -#define HBITMAP R_HBITMAP -#define HCURSOR R_HCURSOR -#define WORD R_WORD -#endif -#include "vnc.h" -#ifdef WIN32 -#undef HBITMAP -#undef HCURSOR -#undef WORD -#endif - -#include <errno.h> -#include <sys/socket.h> -extern int ListenOnTCPPort(int port); -extern int rfbClientSocket; - -#include <rfb/rfbregion.h> - -#define BITSPERBYTES 8 -#define TOBYTES(bits) ((bits)/BITSPERBYTES) - -extern int g_width; -extern int g_height; -extern int keylayout; -extern BOOL sendmotion; -#ifdef ENABLE_SHADOW -extern int client_counter; -#endif - - -int rfb_port = 5923; -int defer_time = 5; -int rfbClientSocket = 0; -static rfbScreenInfoPtr server = NULL; -static vncBuffer *frameBuffer = NULL; -static uint8_t reverseByte[0x100]; -BOOL g_enable_compose = False; -int g_display = 0; - -/* ignored */ -BOOL owncolmap = False; -BOOL enable_compose = False; - -void -vncHideCursor() -{ - if (server->clientHead) - rfbUndrawCursor(server); -} - -/* -=- mouseLookup - * Table converting mouse button number (0-2) to flag - */ - -int mouseLookup[3] = { - MOUSE_FLAG_BUTTON1, MOUSE_FLAG_BUTTON3, MOUSE_FLAG_BUTTON2 -}; - -int clipX, clipY, clipW, clipH; - -BOOL -vncwinClipRect(int *x, int *y, int *cx, int *cy) -{ - if (*x + *cx > clipX + clipW) - *cx = clipX + clipW - *x; - if (*y + *cy > clipY + clipH) - *cy = clipY + clipH - *y; - if (*x < clipX) - { - *cx -= clipX - *x; - *x = clipX; - } - if (*y < clipY) - { - *cy -= clipY - *y; - *y = clipY; - } - if (*cx < 0 || *cy < 0) - *cx = *cy = 0; - return (*cx > 0 && *cy > 0 && *x < server->width && *y < server->height); -} - -void -xwin_toggle_fullscreen(void) -{ -} - -static int lastbuttons = 0; - -#define FIRST_MODIFIER XK_Shift_L -#define LAST_MODIFIER XK_Hyper_R - -static BOOL keystate[LAST_MODIFIER - FIRST_MODIFIER]; - -void -init_keyboard() -{ - int i; - for (i = 0; i < LAST_MODIFIER - FIRST_MODIFIER; i++) - keystate[i] = 0; - - xkeymap_init(); -} - -BOOL -get_key_state(unsigned int state, uint32 keysym) -{ - if (keysym >= FIRST_MODIFIER && keysym <= LAST_MODIFIER) - return keystate[keysym - FIRST_MODIFIER]; - return 0; -} - -void -vncKey(rfbBool down, rfbKeySym keysym, struct _rfbClientRec *cl) -{ - uint32 ev_time = time(NULL); - key_translation tr = { 0, 0 }; - - if (keysym >= FIRST_MODIFIER && keysym <= LAST_MODIFIER) - { - /* TODO: fake local state */ - keystate[keysym - FIRST_MODIFIER] = down; - } - - if (down) - { - /* TODO: fake local state */ - if (handle_special_keys(keysym, 0, ev_time, True)) - return; - - /* TODO: fake local state */ - tr = xkeymap_translate_key(keysym, 0, 0); - - if (tr.scancode == 0) - return; - - ensure_remote_modifiers(ev_time, tr); - - rdp_send_scancode(ev_time, RDP_KEYPRESS, tr.scancode); - } - else - { - /* todO: fake local state */ - if (handle_special_keys(keysym, 0, ev_time, False)) - return; - - /* todO: fake local state */ - tr = xkeymap_translate_key(keysym, 0, 0); - - if (tr.scancode == 0) - return; - - rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode); - } -} - -void -vncMouse(int buttonMask, int x, int y, struct _rfbClientRec *cl) -{ - int b; - uint32 ev_time = time(NULL); - - rdp_send_input(ev_time, RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE, x, y); - - for (b = 0; b < 3; b++) - { - int bb = 1 << (b); - if (!(lastbuttons & bb) && (buttonMask & bb)) - { - rdp_send_input(ev_time, RDP_INPUT_MOUSE, - (mouseLookup[b]) | MOUSE_FLAG_DOWN, x, y); - } - else if ((lastbuttons & bb) && !(buttonMask & bb)) - { - rdp_send_input(ev_time, RDP_INPUT_MOUSE, (mouseLookup[b]), x, y); - } - } - lastbuttons = buttonMask; - - /* handle cursor */ - rfbDefaultPtrAddEvent(buttonMask, x, y, cl); -} - - -void -rdp2vnc_connect(char *server, uint32 flags, char *domain, char *password, - char *shell, char *directory) -{ - struct sockaddr addr; - fd_set fdset; - struct timeval tv; - int rfbListenSock, addrlen = sizeof(addr); - - rfbListenSock = rfbListenOnTCPPort(rfb_port); - fprintf(stderr, "Listening on VNC port %d\n", rfb_port); - if (rfbListenSock <= 0) - error("Cannot listen on port %d", rfb_port); - else - while (1) - { - FD_ZERO(&fdset); - FD_SET(rfbListenSock, &fdset); - tv.tv_sec = 5; - tv.tv_usec = 0; - if (select(rfbListenSock + 1, &fdset, NULL, NULL, &tv) > 0) - { - rfbClientSocket = accept(rfbListenSock, &addr, &addrlen); - if (rfbClientSocket < 0) - { - error("Error accepting client (%d: %s.\n", - errno, strerror(errno)); - continue; - } - ui_create_window(); - if (!rdp_connect(server, flags, domain, password, shell, directory)) - { - error("Error connecting to RDP server.\n"); - continue; - } - if (!fork()) - { - BOOL deactivated; - uint32_t ext_disc_reason; - printf("Connection successful.\n"); - rdp_main_loop(&deactivated, &ext_disc_reason); - printf("Disconnecting...\n"); - rdp_disconnect(); - ui_destroy_window(); - exit(0); - } - } - } -} - - - - - -extern char g_title[]; -BOOL -ui_create_window() -{ - int i; - - for (i = 0; i < 0x100; i++) - reverseByte[i] = - (((i >> 7) & 1)) | (((i >> 6) & 1) << 1) | (((i >> 5) & 1) << 2) | - (((i >> 4) & 1) << 3) | (((i >> 3) & 1) << 4) | (((i >> 2) & 1) << 5) | - (((i >> 1) & 1) << 6) | (((i >> 0) & 1) << 7); - - server = rfbGetScreen(0, NULL, g_width, g_height, 8, 1, 1); - server->desktopName = g_title; - server->frameBuffer = (char *) malloc(g_width * g_height); - server->ptrAddEvent = vncMouse; - server->kbdAddEvent = vncKey; -#ifdef ENABLE_SHADOW - server->httpPort = 6124 + client_counter; - server->port = 5924 + client_counter; - rfbInitSockets(server); - server->alwaysShared = TRUE; - server->neverShared = FALSE; -#else - server->port = -1; - server->alwaysShared = FALSE; - server->neverShared = FALSE; -#endif - server->inetdSock = rfbClientSocket; - server->serverFormat.trueColour = FALSE; /* activate colour maps */ - server->deferUpdateTime = defer_time; - - frameBuffer = (vncBuffer *) malloc(sizeof(vncBuffer)); - frameBuffer->w = g_width; - frameBuffer->h = g_height; - frameBuffer->linew = g_width; - frameBuffer->data = server->frameBuffer; - frameBuffer->owner = FALSE; - frameBuffer->format = &server->serverFormat; - - ui_set_clip(0, 0, g_width, g_height); - - rfbInitServer(server); -#ifndef ENABLE_SHADOW - server->port = rfb_port; -#else - fprintf(stderr, "server listening on port %d (socket %d)\n", server->port, - server->listenSock); -#endif - - init_keyboard(); - - return (server != NULL); -} - -void -ui_destroy_window() -{ - rfbCloseClient(server->clientHead); -} - - -int -ui_select(int rdpSocket) -{ - fd_set fds; - struct timeval tv; - int n, m = server->maxFd; - - if (rdpSocket > m) - m = rdpSocket; - while (1) - { - fds = server->allFds; - FD_SET(rdpSocket, &fds); - tv.tv_sec = defer_time / 1000; - tv.tv_usec = (defer_time % 1000) * 1000; - n = select(m + 1, &fds, NULL, NULL, &tv); - rfbProcessEvents(server, 0); - /* if client is gone, close connection */ - if (!server->clientHead) - close(rdpSocket); - if (FD_ISSET(rdpSocket, &fds)) - return 1; - } - return 0; -} - -void -ui_move_pointer(int x, int y) -{ - // TODO: Is there a way to send x,y even if cursor encoding is active? - rfbUndrawCursor(server); - server->cursorX = x; - server->cursorY = y; -} - -HBITMAP -ui_create_bitmap(int width, int height, uint8 * data) -{ - vncBuffer *buf; - - buf = vncNewBuffer(width, height, 8); - memcpy(buf->data, data, width * height); - - return (HBITMAP) buf; -} - -void -ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * data) -{ - vncBuffer *buf; - buf = ui_create_bitmap(width, height, data); - vncCopyBlitFrom(server, x, y, cx, cy, buf, 0, 0); - vncDeleteBuffer(buf); -} - -void -ui_destroy_bitmap(HBITMAP bmp) -{ - vncDeleteBuffer((vncBuffer *) bmp); -} - -uint8_t -vncLookupColour(rfbColourMap * colourMap, uint8_t * p) -{ - uint8_t i, i1 = 0; - uint8_t *cm = colourMap->data.bytes; - uint32_t m, m1 = abs(cm[0] - p[0]) + abs(cm[1] - p[1]) + abs(cm[2] - p[2]); - for (i = 1; i < 255; i++) - { - m = abs(cm[i * 3] - p[0]) + abs(cm[i * 3 + 1] - p[1]) + abs(cm[i * 3 + 2] - p[2]); - if (m < m1) - { - m1 = m; - i1 = i; - } - } - return (i1); -} - -HCURSOR -ui_create_cursor(unsigned int x, unsigned int y, int width, int height, uint8 * mask, uint8 * data) -{ - int i, j; - uint8_t *d0, *d1; - uint8_t *cdata; - uint8_t white[3] = { 0xff, 0xff, 0xff }; - uint8_t black[3] = { 0, 0, 0 }; - uint8_t *cur; - rfbCursorPtr cursor; - rfbColourMap *colourMap = &server->colourMap; - - cdata = xmalloc(sizeof(uint8_t) * width * height); - d0 = xmalloc(sizeof(uint32_t) * width * height / 4); - d1 = (uint8_t *) mask; - for (j = 0; j < height; j++) - for (i = 0; i < width / 8; i++) - { - d0[j * width / 8 + i] = d1[(height - 1 - j) * width / 8 + i] ^ 0xffffffff; - } - for (j = 0; j < height; j++) - { - for (i = 0; i < width; i++) - { - //strange that the pointer is in 24bit depth when everything - //else is in 8bit palletized. - cur = data + ((height - 1 - j) * width + i) * 3; - if (cur[0] > 0x80 || cur[1] > 0x80 || cur[2] > 0x80) - { - if (!(d0[(j * width + i) / 8] & (0x80 >> (i & 7)))) - { - /* text cursor! */ - cdata[j * width + i] = vncLookupColour(colourMap, black); - d0[(j * width + i) / 8] |= 0x80 >> (i & 7); - } - else - cdata[j * width + i] = vncLookupColour(colourMap, white); - } - else - cdata[j * width + i] = vncLookupColour(colourMap, cur); - } - } - cursor = (rfbCursorPtr) xmalloc(sizeof(rfbCursor)); - cursor->width = width; - cursor->height = height; - cursor->xhot = x; - cursor->yhot = y; - cursor->mask = (char *) d0; - cursor->source = 0; - cursor->richSource = cdata; - cursor->cleanup = 0; // workaround: this produces a memleak - - cursor->backRed = cursor->backGreen = cursor->backBlue = 0xffff; - cursor->foreRed = cursor->foreGreen = cursor->foreBlue = 0; - - return (HCURSOR) cursor; -} - -void -ui_set_cursor(HCURSOR cursor) -{ - /* FALSE means: don't delete old cursor */ - rfbSetCursor(server, (rfbCursorPtr) cursor, FALSE); -} - -void -ui_destroy_cursor(HCURSOR cursor) -{ - if (cursor) - rfbFreeCursor((rfbCursorPtr) cursor); -} - -void -ui_set_null_cursor(void) -{ - rfbSetCursor(server, 0, FALSE); -} - -HGLYPH -ui_create_glyph(int width, int height, uint8 * data) -{ - int x, y; - vncBuffer *buf; - - buf = vncNewBuffer(width, height, 8); - - //data is padded to multiple of 16bit line lengths - for (y = 0; y < height; y++) - { - for (x = 0; x < width; x++) - { - int byte = x / 8 + (y * ((width + 7) / 8)); - byte = rfbEndianTest ? reverseByte[data[byte]] : data[byte]; - byte = (byte >> (x & 7)) & 0x01; - vncSetPixel(buf, x, y, byte ? 0x7f : 0x00); - } - } - - return (HGLYPH) buf; -} - -void -ui_destroy_glyph(HGLYPH glyph) -{ - ui_destroy_bitmap((HBITMAP) glyph); -} - -HCOLOURMAP -ui_create_colourmap(COLOURMAP * colours) -{ - int i; - rfbColourMap *map = vncNewColourMap(server, colours->ncolours); - for (i = 0; i < colours->ncolours; i++) - { - vncSetColourMapEntry(map, i, colours->colours[i].red, - colours->colours[i].green, colours->colours[i].blue); - } - return map; -} - -void -ui_destroy_colourmap(HCOLOURMAP map) -{ - vncDeleteColourMap(map); -} - -void -ui_set_colourmap(HCOLOURMAP map) -{ - vncSetColourMap(server, map); -} - -void -ui_set_clip(int x, int y, int cx, int cy) -{ - clipX = x; - clipY = y; - clipW = cx; - clipH = cy; -} - -void -ui_reset_clip() -{ - clipX = 0; - clipY = 0; - clipW = 64000; - clipH = 64000; -} - -void -ui_bell() -{ - rfbSendBell(server); -} - -void -ui_destblt(uint8 opcode, - /* dest */ int x, int y, int cx, int cy) -{ - int i; - vncBuffer *buf; - - switch (opcode) - { - case 0: - case 15: - ui_rect(x, y, cx, cy, 0xff); - break; - case 5: // invert - buf = vncGetRect(server, x, y, cx, cy); - for (i = 0; i < cx * cy; i++) - ((char *) (buf->data))[i] = !((char *) (buf->data))[i]; - break; - default: - unimpl("ui_destblt: opcode=%d %d,%d %dx%d\n", opcode, x, y, cx, cy); - } -} - -void -ui_patblt(uint8 opcode, - /* dest */ int x, int y, int cx, int cy, - /* brush */ BRUSH * brush, int bgcolour, int fgcolour) -{ - switch (brush->style) - { - case 0: /* Solid */ - switch (opcode) - { - case ROP2_XOR: - { - int xx, yy; - vncBuffer *fill = vncNewBuffer(cx, cy, 8); - for (yy = 0; yy < cy; yy++) - for (xx = 0; xx < cx; xx++) - vncSetPixel(fill, xx, yy, fgcolour); - if (vncwinClipRect(&x, &y, &cx, &cy)) - vncXorBlitFrom(server, x, y, cx, cy, fill, - 0, 0); - break; - } - - default: - if (vncwinClipRect(&x, &y, &cx, &cy)) - vncSetRect(server, x, y, cx, cy, fgcolour); - } - break; - - case 3: /* Pattern */ - { - int xx, yy; - vncBuffer *fill; - fill = (vncBuffer *) ui_create_glyph(8, 8, brush->pattern); - - for (yy = 0; yy < 8; yy++) - { - for (xx = 0; xx < 8; xx++) - { - vncSetPixel(fill, xx, yy, - vncGetPixel(fill, xx, - yy) ? fgcolour : bgcolour); - } - } - - if (vncwinClipRect(&x, &y, &cx, &cy)) - { - switch (opcode) - { - case ROP2_COPY: - vncCopyBlitFrom(server, x, y, cx, cy, fill, - 0, 0); - break; - case ROP2_XOR: - vncXorBlitFrom(server, x, y, cx, cy, fill, - 0, 0); - break; - default: - unimpl("pattern blit (%d,%d) opcode=%d bg=%d fg=%d\n", x, y, opcode, bgcolour, fgcolour); - vncCopyBlitFrom(server, x, y, cx, cy, fill, - 0, 0); - break; - } - } - - ui_destroy_glyph((HGLYPH) fill); - break; - - } - default: - unimpl("brush %d\n", brush->style); - } -} - -void -ui_screenblt(uint8 opcode, - /* dest */ int x, int y, int cx, int cy, - /* src */ int srcx, int srcy) -{ - int ox, oy; - - ox = x; - oy = y; - if (vncwinClipRect(&x, &y, &cx, &cy)) - { - //if we clipped top or left, we have to adjust srcx,srcy; - srcx += x - ox; - srcy += y - oy; - vncCopyBlit(server, x, y, cx, cy, srcx, srcy); - } -} - -void -ui_memblt(uint8 opcode, - /* dest */ int x, int y, int cx, int cy, - /* src */ HBITMAP src, int srcx, int srcy) -{ - int ox, oy; - ox = x; - oy = y; - - if (vncwinClipRect(&x, &y, &cx, &cy)) - { - //if we clipped top or left, we have to adjust srcx,srcy; - srcx += x - ox; - srcy += y - oy; - switch (ROP2_S(opcode)) - { - case ROP2_OR: - vncTransBlitFrom(server, x, y, cx, cy, (vncBuffer *) src, srcx, - srcy, 0x0); - break; - case ROP2_XOR: - vncXorBlitFrom(server, x, y, cx, cy, (vncBuffer *) src, srcx, srcy); - break; - case ROP2_AND: - vncAndBlitFrom(server, x, y, cx, cy, (vncBuffer *) src, srcx, srcy); - break; - case ROP2_COPY: - vncCopyBlitFrom(server, x, y, cx, cy, (vncBuffer *) src, srcx, - srcy); - break; - default: - unimpl("ui_memblt: op%d %d,%d %dx%d\n", opcode, x, y, cx, cy); - vncCopyBlitFrom(server, x, y, cx, cy, (vncBuffer *) src, srcx, - srcy); - break; - } - } -} - -void -ui_triblt(uint8 opcode, - /* dest */ int x, int y, int cx, int cy, - /* src */ HBITMAP src, int srcx, int srcy, - /* brush */ BRUSH * brush, int bgcolour, int fgcolour) -{ - /* This is potentially difficult to do in general. Until someone - comes up with a more efficient way of doing it I am using cases. */ - - switch (opcode) - { - case 0x69: /* PDSxxn */ - ui_memblt(ROP2_XOR, x, y, cx, cy, src, srcx, srcy); - ui_patblt(ROP2_NXOR, x, y, cx, cy, brush, bgcolour, fgcolour); - break; - - case 0xb8: /* PSDPxax */ - ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour); - ui_memblt(ROP2_AND, x, y, cx, cy, src, srcx, srcy); - ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour); - break; - - default: - unimpl("ui_triblt 1x%x\n", opcode); - ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy); - } - -} - -void -ui_line(uint8 opcode, - /* dest */ int startx, int starty, int endx, int endy, - /* pen */ PEN * pen) -{ - //vncSetRect(server,startx,starty,1+endx-startx,endy-starty,pen->colour); - //unimpl("drawline: pen colour=%d\n",pen->colour); - /* TODO: implement opcodes */ - rfbDrawLine(server, startx, starty, endx, endy, pen->colour); -} - -void -ui_rect( - /* dest */ int x, int y, int cx, int cy, - /* brush */ int colour) -{ - if (vncwinClipRect(&x, &y, &cx, &cy)) - { - vncSetRect(server, x, y, cx, cy, colour); - } -} - -void -ui_draw_glyph(int mixmode, - /* dest */ int x, int y, int cx, int cy, - /* src */ HGLYPH glyph, int srcx, int srcy, - /* colours */ int bgcolour, int fgcolour) -{ - int xx, yy; - int ox, oy; - vncBuffer *buf = vncDupBuffer(glyph); - - x &= 0xffff; - y &= 0xffff; - - /* yes, sometimes same fgcolour and bgcolour are sent, but because - * of transparency, we have to change that! */ - if (mixmode == MIX_TRANSPARENT && fgcolour == bgcolour) - bgcolour = fgcolour ^ 0xff; - - ox = x; - oy = y; - - for (yy = srcy; yy < srcy + cy; yy++) - { - for (xx = srcx; xx < srcx + cx; xx++) - { - vncSetPixel(buf, xx, yy, vncGetPixel(buf, xx, yy) ? fgcolour : bgcolour); - } - } - - switch (mixmode) - { - case MIX_TRANSPARENT: - if (vncwinClipRect(&x, &y, &cx, &cy)) - { - //if we clipped top or left, we have to adjust srcx,srcy; - srcx += x - ox; - srcy += y - oy; - vncTransBlitFrom(server, x, y, cx, cy, buf, srcx, srcy, bgcolour); - } - break; - case MIX_OPAQUE: - if (vncwinClipRect(&x, &y, &cx, &cy)) - { - //if we clipped top or left, we have to adjust srcx,srcy; - srcx += x - ox; - srcy += y - oy; - vncCopyBlitFrom(server, x, y, cx, cy, buf, srcx, srcy); - } - break; - - default: - unimpl("mix %d\n", mixmode); - } - vncDeleteBuffer(buf); -} - -#define DO_GLYPH(ttext,idx) \ -{\ - glyph = cache_get_font (font, ttext[idx]);\ - if (!(flags & TEXT2_IMPLICIT_X))\ - {\ - offset = ttext[++idx];\ - if ((offset & 0x80))\ - offset = ((offset & 0x7f) << 8) | ttext[++idx];\ - if (flags & TEXT2_VERTICAL)\ - y += offset;\ - else\ - x += offset;\ - }\ - if (glyph != NULL)\ - {\ - ui_draw_glyph (mixmode, x + (short) glyph->offset,\ - y + (short) glyph->baseline,\ - glyph->width, glyph->height,\ - glyph->pixmap, 0, 0, bgcolour, fgcolour);\ - if (flags & TEXT2_IMPLICIT_X)\ - x += glyph->width;\ - }\ -} - - -void -ui_draw_text(uint8 font, uint8 flags, int mixmode, int x, int y, - int clipx, int clipy, int clipcx, int clipcy, - int boxx, int boxy, int boxcx, int boxcy, - int bgcolour, int fgcolour, uint8 * text, uint8 length) -{ - FONTGLYPH *glyph; - int i, j, offset; - DATABLOB *entry; - - if (boxcx > 1) - { - ui_rect(boxx, boxy, boxcx, boxcy, bgcolour); - } - else if (mixmode == MIX_OPAQUE) - { - ui_rect(clipx, clipy, clipcx, clipcy, bgcolour); - } - - /* Paint text, character by character */ - for (i = 0; i < length;) - { - switch (text[i]) - { - case 0xff: - if (i + 2 < length) - cache_put_text(text[i + 1], &(text[i - text[i + 2]]), - text[i + 2]); - else - { - error("this shouldn't be happening\n"); - break; - } - /* 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 & 0x04) /* vertical text */ - y += text[i + 2]; - else - x += text[i + 2]; - } - 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; - for (j = 0; j < entry->size; j++) - DO_GLYPH(((uint8 *) (entry->data)), j); - } - break; - default: - DO_GLYPH(text, i); - i++; - break; - } - } -} - -void -ui_desktop_save(uint32 offset, int x, int y, int cx, int cy) -{ - vncBuffer *buf; - - buf = vncGetRect(server, x, y, cx, cy); - offset *= TOBYTES(server->serverFormat.bitsPerPixel); - cache_put_desktop(offset, cx, cy, cx, TOBYTES(server->serverFormat.bitsPerPixel), - (buf->data)); -} - -void -ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy) -{ - uint8 *data; - vncBuffer *buf; - int ox, oy, srcx, srcy; - - srcx = srcy = 0; - ox = x; - oy = y; - - offset *= TOBYTES(server->serverFormat.bitsPerPixel); - data = cache_get_desktop(offset, cx, cy, TOBYTES(server->serverFormat.bitsPerPixel)); - if (data == NULL) - return; - - buf = vncNewBuffer(cx, cy, 8); - memcpy(buf->data, data, cx * cy * 1); - - if (vncwinClipRect(&x, &y, &cx, &cy)) - { - srcx += x - ox; - srcy += y - oy; - vncCopyBlitFrom(server, x, y, cx, cy, buf, srcx, srcy); - } - vncDeleteBuffer(buf); -} - -rfbPixelFormat vnc_formats[] = { - /* bpp, depth,BE,TC, rmax, gmax, bmax, rsh, gsh, bsh */ - {8, 8, 1, 0, 7, 7, 3, 0, 3, 6} - , - {16, 16, 1, 1, 31, 63, 31, 0, 5, 10} - , - {32, 24, 1, 1, 255, 255, 255, 0, 8, 16} - , //non-existant - {32, 32, 1, 1, 2047, 2047, 1023, 0, 11, 22} -}; - -rfbPixelFormat * -vncNewFormat(int depth) -{ - return &(vnc_formats[(depth + 1) / 8 - 1]); -} - -vncBuffer * -vncNewBuffer(int w, int h, int depth) -{ - vncBuffer *b = (vncBuffer *) xmalloc(sizeof(vncBuffer)); - b->format = vncNewFormat(depth); - b->data = (void *) xmalloc(w * h * (b->format->bitsPerPixel / 8)); - b->owner = 1; - b->w = w; - b->h = h; - b->linew = w; - return b; -} - -vncBuffer * -vncDupBuffer(vncBuffer * b) -{ - vncBuffer *buf = vncNewBuffer(b->w, b->h, b->format->depth); - memcpy(buf->data, b->data, b->linew * b->h * b->format->bitsPerPixel / 8); - return buf; -} - -void -vncPrintStats() -{ - if (server && server->clientHead) - rfbPrintStats(server->clientHead); -} - -/* blit */ - -#define GETPIXEL(buf,x,y) \ - (((uint8_t*)(buf->data))[(x)+((y)*buf->linew)]) -#define SETPIXEL(buf,x,y,p) \ - (((uint8_t*)(buf->data))[(x)+((y)*buf->linew)] = (uint8_t)p) - -void -vncCopyBlitFromNoEncode(rfbScreenInfoPtr s, int x, int y, int w, int h, - vncBuffer * src, int srcx, int srcy) -{ - int xx, yy; - - vncHideCursor(); - - if (s->serverFormat.bitsPerPixel == src->format->bitsPerPixel - && srcx + w <= src->w && srcy + h <= src->h) - { - //simple copy - uint8_t *srcdata, *dstdata; - srcdata = src->data + (srcy * src->linew + srcx); - dstdata = s->frameBuffer + (y * s->paddedWidthInBytes + x); - for (yy = 0; yy < h; yy++) - { - memcpy(dstdata, srcdata, w); - dstdata += s->paddedWidthInBytes; - srcdata += src->linew; - } - } - else - { - // xsrc,ysrc provide tiling copy support. - for (yy = y; yy < y + h; yy++) - { - int ysrc = srcy + yy - y; - while (ysrc >= src->h) - ysrc -= src->h; - for (xx = x; xx < x + w; xx++) - { - vncPixel p; - int xsrc = srcx + xx - x; - while (xsrc >= src->linew) - xsrc -= src->linew; - p = GETPIXEL(src, xsrc, ysrc); - SETPIXEL(frameBuffer, xx, yy, p); - } - } - } -} - -void -vncCopyBlit(rfbScreenInfoPtr s, int x, int y, int w, int h, int srcx, int srcy) -{ - /* LibVNCServer already knows how to copy the data. */ - rfbDoCopyRect(s, x, y, x + w, y + h, x - srcx, y - srcy); -} - -void -vncCopyBlitFrom(rfbScreenInfoPtr s, int x, int y, int w, int h, vncBuffer * src, int srcx, int srcy) -{ - vncCopyBlitFromNoEncode(s, x, y, w, h, src, srcx, srcy); - rfbMarkRectAsModified(s, x, y, x + w, y + h); -} - -void -vncTransBlitFrom(rfbScreenInfoPtr s, int x, int y, int w, int h, - vncBuffer * src, int srcx, int srcy, int bg) -{ - int xx, yy; - - vncHideCursor(); - - // xsrc,ysrc provide tiling copy support. - for (yy = y; yy < y + h; yy++) - { - int ysrc = srcy + yy - y; - while (ysrc >= src->h) - ysrc -= src->h; - for (xx = x; xx < x + w; xx++) - { - vncPixel p; - int xsrc = srcx + xx - x; - while (xsrc >= src->linew) - xsrc -= src->linew; - p = GETPIXEL(src, xsrc, ysrc); - // transparent blit! - if (p != bg) - SETPIXEL(frameBuffer, xx, yy, p); - } - } - - rfbMarkRectAsModified(s, x, y, x + w, y + h); -} - -void -vncXorBlitFrom(rfbScreenInfoPtr s, int x, int y, int w, int h, vncBuffer * src, int srcx, int srcy) -{ - int xx, yy; - - vncHideCursor(); - - // xsrc,ysrc provide tiling copy support. - for (yy = y; yy < y + h; yy++) - { - int ysrc = srcy + yy - y; - while (ysrc >= src->h) - ysrc -= src->h; - for (xx = x; xx < x + w; xx++) - { - vncPixel p, pp; - int xsrc = srcx + xx - x; - while (xsrc >= src->linew) - xsrc -= src->linew; - p = GETPIXEL(src, xsrc, ysrc); - pp = GETPIXEL(frameBuffer, xx, yy); - // xor blit! - SETPIXEL(frameBuffer, xx, yy, p ^ pp); - } - } - - rfbMarkRectAsModified(s, x, y, x + w, y + h); -} - -void -vncAndBlitFrom(rfbScreenInfoPtr s, int x, int y, int w, int h, vncBuffer * src, int srcx, int srcy) -{ - int xx, yy; - - vncHideCursor(); - - // xsrc,ysrc provide tiling copy support. - for (yy = y; yy < y + h; yy++) - { - int ysrc = srcy + yy - y; - while (ysrc >= src->h) - ysrc -= src->h; - for (xx = x; xx < x + w; xx++) - { - vncPixel p, pp; - int xsrc = srcx + xx - x; - while (xsrc >= src->linew) - xsrc -= src->linew; - p = GETPIXEL(src, xsrc, ysrc); - pp = GETPIXEL(frameBuffer, xx, yy); - // and blit! - SETPIXEL(frameBuffer, xx, yy, p & pp); - } - } - - rfbMarkRectAsModified(s, x, y, x + w, y + h); -} - -void -vncDeleteBuffer(vncBuffer * b) -{ - if (b->owner) - xfree(b->data); - xfree(b); -} - -/* cursor */ -rfbCursorPtr -vncNewCursor(vncBuffer * mask, vncBuffer * pointer, int hotx, int hoty) -{ - int i, j, w = (mask->w + 7) / 8, mask_size = w * mask->h, - pointer_size = pointer->w * pointer->h; - rfbCursorPtr c = (rfbCursorPtr) xmalloc(sizeof(rfbCursor)); - - if (mask->w != pointer->w || mask->h != pointer->h) - error("ERROR! Mask is %dx%d, Pointer is %dx%d\n", - mask->w, mask->h, pointer->w, pointer->h); - - c->xhot = hotx; - c->yhot = hoty; - c->width = mask->w; - c->height = mask->h; - - c->mask = (char *) xmalloc(mask_size); - for (j = 0; j < c->height; j++) - for (i = 0; i < w; i++) - c->mask[j * w + i] = - reverseByte[((unsigned char *) mask->data)[(j) * w + i]]; - vncDeleteBuffer(mask); - - c->source = 0; - c->richSource = (char *) xmalloc(pointer_size); - memcpy(c->richSource, pointer->data, pointer_size); - vncDeleteBuffer(pointer); - - return c; -} - -/* No FreeCursor, because the cursors are buffered. We only get a "HANDLE" */ -void -vncSetCursor(rfbScreenInfoPtr s, rfbCursorPtr c) -{ - rfbSetCursor(s, c, FALSE); -} - -/* these functions work even if vncBuffer's pixel format is not 1 byte/pixel */ -vncPixel -vncGetPixel(vncBuffer * b, int x, int y) -{ - unsigned long offset = (x + (y * (b->linew))) * (b->format->bitsPerPixel >> 3); - return ((uint8_t *) (b->data))[offset]; -} - -void -vncSetPixel(vncBuffer * b, int x, int y, vncPixel c) -{ - unsigned long offset = (x + (y * (b->linew))) * (b->format->bitsPerPixel >> 3); - ((uint8_t *) (b->data))[offset] = c; -} - -void -vncSetRect(rfbScreenInfoPtr s, int x, int y, int w, int h, vncPixel c) -{ - int xx, yy; - - if (x + w > s->width) - w = s->width - x; - if (y + h > s->height) - h = s->height - y; - if (w <= 0 || h <= 0) - return; - - vncHideCursor(); - - // - Fill the rect in the local framebuffer - if (s->serverFormat.bitsPerPixel == 8) - { - // - Simple 8-bit fill - uint8_t *dstdata; - dstdata = s->frameBuffer + (y * s->paddedWidthInBytes + x); - for (yy = 0; yy < h; yy++) - { - memset(dstdata, c, w); - dstdata += s->paddedWidthInBytes; - } - } - else - { - for (yy = y; yy < y + h; yy++) - { - for (xx = x; xx < x + w; xx++) - { - SETPIXEL(frameBuffer, xx, yy, c); - } - } - } - - rfbMarkRectAsModified(s, x, y, x + w, y + h); -} - -vncBuffer * -vncGetRect(rfbScreenInfoPtr s, int x, int y, int w, int h) -{ - int xx, yy; - vncBuffer *b = vncNewBuffer(w, h, s->serverFormat.depth); - - vncHideCursor(); - - if (s->serverFormat.bitsPerPixel == 8) - { - //simple copy - int srcstep, dststep; - char *srcdata, *dstdata; - srcstep = s->paddedWidthInBytes * s->serverFormat.bitsPerPixel / 8; - dststep = w * s->serverFormat.bitsPerPixel / 8; - dstdata = b->data; - srcdata = s->frameBuffer + (y * srcstep + x * s->serverFormat.bitsPerPixel / 8); - for (yy = 0; yy < h; yy++) - { - memcpy(dstdata, srcdata, dststep); - dstdata += dststep; - srcdata += srcstep; - } - } - else - { - for (yy = y; yy < y + h; yy++) - { - for (xx = x; xx < x + w; xx++) - { - SETPIXEL(b, xx - x, yy - y, GETPIXEL(frameBuffer, xx, yy)); - } - } - } - - return b; -} - -/* colourmap */ - -rfbColourMap * -vncNewColourMap(rfbScreenInfoPtr s, int n) -{ - rfbColourMap *m = (rfbColourMap *) xmalloc(sizeof(rfbColourMap)); - m->is16 = FALSE; - m->count = n; - m->data.bytes = (uint8_t *) xmalloc(n * 3); - return m; -} - -void -vncSetColourMapEntry(rfbColourMap * m, int i, vncPixel r, vncPixel g, vncPixel b) -{ - if (i < m->count) - { - m->data.bytes[3 * i + 0] = r; - m->data.bytes[3 * i + 1] = g; - m->data.bytes[3 * i + 2] = b; - } -} - -void -vncDeleteColourMap(rfbColourMap * m) -{ - if (m->data.bytes) - free(m->data.bytes); - m->count = 0; -} - -void -vncSetColourMap(rfbScreenInfoPtr s, rfbColourMap * m) -{ - vncDeleteColourMap(&s->colourMap); - s->colourMap = *m; - rfbSetClientColourMaps(s, 0, 0); -} - -void -ui_begin_update() -{ -} - -void -ui_end_update() -{ -} - -void -ui_resize_window() -{ - rfbClientIteratorPtr iter; - rfbClientPtr cl; - - server->width = g_width; - server->height = g_height; - server->frameBuffer = (char *) realloc(server->frameBuffer, g_width * g_height); - server->paddedWidthInBytes = g_width; - - iter = rfbGetClientIterator(server); - while ((cl = rfbClientIteratorNext(iter))) - if (cl->useNewFBSize) - cl->newFBSizePending = TRUE; - else - rfbLog("Warning: Client %s does not support NewFBSize!\n ", cl->host); - rfbReleaseClientIterator(iter); -} diff -Nru rdesktop-1.8.6/vnc/vnc.h rdesktop-1.9.0/vnc/vnc.h --- rdesktop-1.8.6/vnc/vnc.h 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/vnc/vnc.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,68 +0,0 @@ -#ifndef VNC_H -#define VNC_H - -#define BOOL rfb_BOOL -#include <rfb/rfb.h> -#undef BOOL - -typedef unsigned int vncPixel; - -typedef struct -{ - uint16_t w, h; - uint16_t linew; - rfbPixelFormat *format; - char *data; - BOOL owner; -} -vncBuffer; - -extern int vncPreparedClientSocket; -extern int vncPreparedServerSocket; - -/* - Buffer management */ -extern vncBuffer *vncNewBuffer(int w, int h, int depth); -extern vncBuffer *vncDupBuffer(vncBuffer * b); -extern void vncDeleteBuffer(vncBuffer * b); - -/* - Colourmaps */ -typedef struct -{ - uint8_t r, g, b; -} -vncColour; - -extern void vncSetColourMap(rfbScreenInfoPtr s, rfbColourMap * m); -extern rfbColourMap *vncNewColourMap(rfbScreenInfoPtr s, int n); -extern void vncSetColourMapEntry(rfbColourMap * m, int i, vncPixel r, vncPixel g, vncPixel b); -extern void vncDeleteColourMap(rfbColourMap * m); - -/* - Simple pixel manipulation */ -extern vncPixel vncGetPixel(vncBuffer * b, int x, int y); -extern void vncSetPixel(vncBuffer * b, int x, int y, vncPixel c); - -/* - Drawing primitives */ -extern void vncSetRect(rfbScreenInfoPtr s, int x, int y, int w, int h, vncPixel c); -extern void vncCopyBlit(rfbScreenInfoPtr s, int x, int y, int w, int h, int srcx, int srcy); -extern void vncCopyBlitFrom(rfbScreenInfoPtr s, int x, int y, int w, int h, - vncBuffer * b, int srcx, int srcy); -extern void vncTransBlitFrom(rfbScreenInfoPtr s, int x, int y, int w, int h, - vncBuffer * b, int srcx, int srcy, int bg); -extern void vncXorBlitFrom(rfbScreenInfoPtr s, int x, int y, int w, int h, - vncBuffer * b, int srcx, int srcy); -extern void vncAndBlitFrom(rfbScreenInfoPtr s, int x, int y, int w, int h, - vncBuffer * b, int srcx, int srcy); -extern vncBuffer *vncGetRect(rfbScreenInfoPtr s, int x, int y, int w, int h); - -// - Low level VNC update primitives upon which the rest are based -extern void vncQueueCopyRect(rfbScreenInfoPtr s, int x, int y, int w, int h, int src_x, int src_y); -extern void vncQueueUpdate(rfbScreenInfoPtr s, int x, int y, int w, int h); - -/* cursor */ -extern rfbCursorPtr vncNewCursor(vncBuffer * mask, vncBuffer * pointer, int hotx, int hoty); -extern void vncSetCursor(rfbScreenInfoPtr s, rfbCursorPtr c); - -int vncListenAtTcpAddr(unsigned short port); -void vncPrintStats(); - -#endif diff -Nru rdesktop-1.8.6/vnc/x11stubs.c rdesktop-1.9.0/vnc/x11stubs.c --- rdesktop-1.8.6/vnc/x11stubs.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/vnc/x11stubs.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1405 +0,0 @@ -/* - -This file fakes some of X11's key handling for the special purpose of running -a standalone rdp2vnc (without linking to X11) - -*/ - -#include "x11stubs.h" -#include <string.h> - -/* ignored */ -int *display; - -typedef struct -{ - const char *string; - KeySym keysym; -} -StringToKeysym_t; - -StringToKeysym_t StringToKeysym[] = { -#ifndef KEYSYMFAKE_H - {"VoidSymbol", XK_VoidSymbol}, -#ifdef XK_MISCELLANY - {"BackSpace", XK_BackSpace}, - {"Tab", XK_Tab}, - {"Linefeed", XK_Linefeed}, - {"Clear", XK_Clear}, - {"Return", XK_Return}, - {"Pause", XK_Pause}, - {"Scroll_Lock", XK_Scroll_Lock}, - {"Sys_Req", XK_Sys_Req}, - {"Escape", XK_Escape}, - {"Delete", XK_Delete}, - {"Multi_key", XK_Multi_key}, - {"SingleCandidate", XK_SingleCandidate}, - {"MultipleCandidate", XK_MultipleCandidate}, - {"PreviousCandidate", XK_PreviousCandidate}, - {"Kanji", XK_Kanji}, - {"Muhenkan", XK_Muhenkan}, - {"Henkan_Mode", XK_Henkan_Mode}, - {"Henkan", XK_Henkan}, - {"Romaji", XK_Romaji}, - {"Hiragana", XK_Hiragana}, - {"Katakana", XK_Katakana}, - {"Hiragana_Katakana", XK_Hiragana_Katakana}, - {"Zenkaku", XK_Zenkaku}, - {"Hankaku", XK_Hankaku}, - {"Zenkaku_Hankaku", XK_Zenkaku_Hankaku}, - {"Touroku", XK_Touroku}, - {"Massyo", XK_Massyo}, - {"Kana_Lock", XK_Kana_Lock}, - {"Kana_Shift", XK_Kana_Shift}, - {"Eisu_Shift", XK_Eisu_Shift}, - {"Eisu_toggle", XK_Eisu_toggle}, - {"Zen_Koho", XK_Zen_Koho}, - {"Mae_Koho", XK_Mae_Koho}, - {"Home", XK_Home}, - {"Left", XK_Left}, - {"Up", XK_Up}, - {"Right", XK_Right}, - {"Down", XK_Down}, - {"Prior", XK_Prior}, - {"Page_Up", XK_Page_Up}, - {"Next", XK_Next}, - {"Page_Down", XK_Page_Down}, - {"End", XK_End}, - {"Begin", XK_Begin}, - {"Select", XK_Select}, - {"Print", XK_Print}, - {"Execute", XK_Execute}, - {"Insert", XK_Insert}, - {"Undo", XK_Undo}, - {"Redo", XK_Redo}, - {"Menu", XK_Menu}, - {"Find", XK_Find}, - {"Cancel", XK_Cancel}, - {"Help", XK_Help}, - {"Break", XK_Break}, - {"Mode_switch", XK_Mode_switch}, - {"script_switch", XK_script_switch}, - {"Num_Lock", XK_Num_Lock}, - {"KP_Space", XK_KP_Space}, - {"KP_Tab", XK_KP_Tab}, - {"KP_Enter", XK_KP_Enter}, - {"KP_F1", XK_KP_F1}, - {"KP_F2", XK_KP_F2}, - {"KP_F3", XK_KP_F3}, - {"KP_F4", XK_KP_F4}, - {"KP_Home", XK_KP_Home}, - {"KP_Left", XK_KP_Left}, - {"KP_Up", XK_KP_Up}, - {"KP_Right", XK_KP_Right}, - {"KP_Down", XK_KP_Down}, - {"KP_Prior", XK_KP_Prior}, - {"KP_Page_Up", XK_KP_Page_Up}, - {"KP_Next", XK_KP_Next}, - {"KP_Page_Down", XK_KP_Page_Down}, - {"KP_End", XK_KP_End}, - {"KP_Begin", XK_KP_Begin}, - {"KP_Insert", XK_KP_Insert}, - {"KP_Delete", XK_KP_Delete}, - {"KP_Equal", XK_KP_Equal}, - {"KP_Multiply", XK_KP_Multiply}, - {"KP_Add", XK_KP_Add}, - {"KP_Separator", XK_KP_Separator}, - {"KP_Subtract", XK_KP_Subtract}, - {"KP_Decimal", XK_KP_Decimal}, - {"KP_Divide", XK_KP_Divide}, - {"KP_0", XK_KP_0}, - {"KP_1", XK_KP_1}, - {"KP_2", XK_KP_2}, - {"KP_3", XK_KP_3}, - {"KP_4", XK_KP_4}, - {"KP_5", XK_KP_5}, - {"KP_6", XK_KP_6}, - {"KP_7", XK_KP_7}, - {"KP_8", XK_KP_8}, - {"KP_9", XK_KP_9}, - {"F1", XK_F1}, - {"F2", XK_F2}, - {"F3", XK_F3}, - {"F4", XK_F4}, - {"F5", XK_F5}, - {"F6", XK_F6}, - {"F7", XK_F7}, - {"F8", XK_F8}, - {"F9", XK_F9}, - {"F10", XK_F10}, - {"F11", XK_F11}, - {"L1", XK_L1}, - {"F12", XK_F12}, - {"L2", XK_L2}, - {"F13", XK_F13}, - {"L3", XK_L3}, - {"F14", XK_F14}, - {"L4", XK_L4}, - {"F15", XK_F15}, - {"L5", XK_L5}, - {"F16", XK_F16}, - {"L6", XK_L6}, - {"F17", XK_F17}, - {"L7", XK_L7}, - {"F18", XK_F18}, - {"L8", XK_L8}, - {"F19", XK_F19}, - {"L9", XK_L9}, - {"F20", XK_F20}, - {"L10", XK_L10}, - {"F21", XK_F21}, - {"R1", XK_R1}, - {"F22", XK_F22}, - {"R2", XK_R2}, - {"F23", XK_F23}, - {"R3", XK_R3}, - {"F24", XK_F24}, - {"R4", XK_R4}, - {"F25", XK_F25}, - {"R5", XK_R5}, - {"F26", XK_F26}, - {"R6", XK_R6}, - {"F27", XK_F27}, - {"R7", XK_R7}, - {"F28", XK_F28}, - {"R8", XK_R8}, - {"F29", XK_F29}, - {"R9", XK_R9}, - {"F30", XK_F30}, - {"R10", XK_R10}, - {"F31", XK_F31}, - {"R11", XK_R11}, - {"F32", XK_F32}, - {"R12", XK_R12}, - {"F33", XK_F33}, - {"R13", XK_R13}, - {"F34", XK_F34}, - {"R14", XK_R14}, - {"F35", XK_F35}, - {"R15", XK_R15}, - {"Shift_L", XK_Shift_L}, - {"Shift_R", XK_Shift_R}, - {"Control_L", XK_Control_L}, - {"Control_R", XK_Control_R}, - {"Caps_Lock", XK_Caps_Lock}, - {"Shift_Lock", XK_Shift_Lock}, - {"Meta_L", XK_Meta_L}, - {"Meta_R", XK_Meta_R}, - {"Alt_L", XK_Alt_L}, - {"Alt_R", XK_Alt_R}, - {"Super_L", XK_Super_L}, - {"Super_R", XK_Super_R}, - {"Hyper_L", XK_Hyper_L}, - {"Hyper_R", XK_Hyper_R}, -#endif /* XK_MISCELLANY */ -#ifdef XK_XKB_KEYS - {"ISO_Lock", XK_ISO_Lock}, - {"ISO_Level2_Latch", XK_ISO_Level2_Latch}, - {"ISO_Level3_Shift", XK_ISO_Level3_Shift}, - {"ISO_Level3_Latch", XK_ISO_Level3_Latch}, - {"ISO_Level3_Lock", XK_ISO_Level3_Lock}, - {"ISO_Group_Shift", XK_ISO_Group_Shift}, - {"ISO_Group_Latch", XK_ISO_Group_Latch}, - {"ISO_Group_Lock", XK_ISO_Group_Lock}, - {"ISO_Next_Group", XK_ISO_Next_Group}, - {"ISO_Next_Group_Lock", XK_ISO_Next_Group_Lock}, - {"ISO_Prev_Group", XK_ISO_Prev_Group}, - {"ISO_Prev_Group_Lock", XK_ISO_Prev_Group_Lock}, - {"ISO_First_Group", XK_ISO_First_Group}, - {"ISO_First_Group_Lock", XK_ISO_First_Group_Lock}, - {"ISO_Last_Group", XK_ISO_Last_Group}, - {"ISO_Last_Group_Lock", XK_ISO_Last_Group_Lock}, - {"ISO_Left_Tab", XK_ISO_Left_Tab}, - {"ISO_Move_Line_Up", XK_ISO_Move_Line_Up}, - {"ISO_Move_Line_Down", XK_ISO_Move_Line_Down}, - {"ISO_Partial_Line_Up", XK_ISO_Partial_Line_Up}, - {"ISO_Partial_Line_Down", XK_ISO_Partial_Line_Down}, - {"ISO_Partial_Space_Left", XK_ISO_Partial_Space_Left}, - {"ISO_Partial_Space_Right", XK_ISO_Partial_Space_Right}, - {"ISO_Set_Margin_Left", XK_ISO_Set_Margin_Left}, - {"ISO_Set_Margin_Right", XK_ISO_Set_Margin_Right}, - {"ISO_Release_Margin_Left", XK_ISO_Release_Margin_Left}, - {"ISO_Release_Margin_Right", XK_ISO_Release_Margin_Right}, - {"ISO_Release_Both_Margins", XK_ISO_Release_Both_Margins}, - {"ISO_Fast_Cursor_Left", XK_ISO_Fast_Cursor_Left}, - {"ISO_Fast_Cursor_Right", XK_ISO_Fast_Cursor_Right}, - {"ISO_Fast_Cursor_Up", XK_ISO_Fast_Cursor_Up}, - {"ISO_Fast_Cursor_Down", XK_ISO_Fast_Cursor_Down}, - {"ISO_Continuous_Underline", XK_ISO_Continuous_Underline}, - {"ISO_Discontinuous_Underline", XK_ISO_Discontinuous_Underline}, - {"ISO_Emphasize", XK_ISO_Emphasize}, - {"ISO_Center_Object", XK_ISO_Center_Object}, - {"ISO_Enter", XK_ISO_Enter}, - {"dead_grave", XK_dead_grave}, - {"dead_acute", XK_dead_acute}, - {"dead_circumflex", XK_dead_circumflex}, - {"dead_tilde", XK_dead_tilde}, - {"dead_macron", XK_dead_macron}, - {"dead_breve", XK_dead_breve}, - {"dead_abovedot", XK_dead_abovedot}, - {"dead_diaeresis", XK_dead_diaeresis}, - {"dead_abovering", XK_dead_abovering}, - {"dead_doubleacute", XK_dead_doubleacute}, - {"dead_caron", XK_dead_caron}, - {"dead_cedilla", XK_dead_cedilla}, - {"dead_ogonek", XK_dead_ogonek}, - {"dead_iota", XK_dead_iota}, - {"dead_voiced_sound", XK_dead_voiced_sound}, - {"dead_semivoiced_sound", XK_dead_semivoiced_sound}, - {"dead_belowdot", XK_dead_belowdot}, - {"First_Virtual_Screen", XK_First_Virtual_Screen}, - {"Prev_Virtual_Screen", XK_Prev_Virtual_Screen}, - {"Next_Virtual_Screen", XK_Next_Virtual_Screen}, - {"Last_Virtual_Screen", XK_Last_Virtual_Screen}, - {"Terminate_Server", XK_Terminate_Server}, - {"AccessX_Enable", XK_AccessX_Enable}, - {"AccessX_Feedback_Enable", XK_AccessX_Feedback_Enable}, - {"RepeatKeys_Enable", XK_RepeatKeys_Enable}, - {"SlowKeys_Enable", XK_SlowKeys_Enable}, - {"BounceKeys_Enable", XK_BounceKeys_Enable}, - {"StickyKeys_Enable", XK_StickyKeys_Enable}, - {"MouseKeys_Enable", XK_MouseKeys_Enable}, - {"MouseKeys_Accel_Enable", XK_MouseKeys_Accel_Enable}, - {"Overlay1_Enable", XK_Overlay1_Enable}, - {"Overlay2_Enable", XK_Overlay2_Enable}, - {"AudibleBell_Enable", XK_AudibleBell_Enable}, - {"Pointer_Left", XK_Pointer_Left}, - {"Pointer_Right", XK_Pointer_Right}, - {"Pointer_Up", XK_Pointer_Up}, - {"Pointer_Down", XK_Pointer_Down}, - {"Pointer_UpLeft", XK_Pointer_UpLeft}, - {"Pointer_UpRight", XK_Pointer_UpRight}, - {"Pointer_DownLeft", XK_Pointer_DownLeft}, - {"Pointer_DownRight", XK_Pointer_DownRight}, - {"Pointer_Button_Dflt", XK_Pointer_Button_Dflt}, - {"Pointer_Button1", XK_Pointer_Button1}, - {"Pointer_Button2", XK_Pointer_Button2}, - {"Pointer_Button3", XK_Pointer_Button3}, - {"Pointer_Button4", XK_Pointer_Button4}, - {"Pointer_Button5", XK_Pointer_Button5}, - {"Pointer_DblClick_Dflt", XK_Pointer_DblClick_Dflt}, - {"Pointer_DblClick1", XK_Pointer_DblClick1}, - {"Pointer_DblClick2", XK_Pointer_DblClick2}, - {"Pointer_DblClick3", XK_Pointer_DblClick3}, - {"Pointer_DblClick4", XK_Pointer_DblClick4}, - {"Pointer_DblClick5", XK_Pointer_DblClick5}, - {"Pointer_Drag_Dflt", XK_Pointer_Drag_Dflt}, - {"Pointer_Drag1", XK_Pointer_Drag1}, - {"Pointer_Drag2", XK_Pointer_Drag2}, - {"Pointer_Drag3", XK_Pointer_Drag3}, - {"Pointer_Drag4", XK_Pointer_Drag4}, - {"Pointer_Drag5", XK_Pointer_Drag5}, - {"Pointer_EnableKeys", XK_Pointer_EnableKeys}, - {"Pointer_Accelerate", XK_Pointer_Accelerate}, - {"Pointer_DfltBtnNext", XK_Pointer_DfltBtnNext}, - {"Pointer_DfltBtnPrev", XK_Pointer_DfltBtnPrev}, -#endif -#ifdef XK_3270 - {"3270_Duplicate", XK_3270_Duplicate}, - {"3270_FieldMark", XK_3270_FieldMark}, - {"3270_Right2", XK_3270_Right2}, - {"3270_Left2", XK_3270_Left2}, - {"3270_BackTab", XK_3270_BackTab}, - {"3270_EraseEOF", XK_3270_EraseEOF}, - {"3270_EraseInput", XK_3270_EraseInput}, - {"3270_Reset", XK_3270_Reset}, - {"3270_Quit", XK_3270_Quit}, - {"3270_PA1", XK_3270_PA1}, - {"3270_PA2", XK_3270_PA2}, - {"3270_PA3", XK_3270_PA3}, - {"3270_Test", XK_3270_Test}, - {"3270_Attn", XK_3270_Attn}, - {"3270_CursorBlink", XK_3270_CursorBlink}, - {"3270_AltCursor", XK_3270_AltCursor}, - {"3270_KeyClick", XK_3270_KeyClick}, - {"3270_Jump", XK_3270_Jump}, - {"3270_Ident", XK_3270_Ident}, - {"3270_Rule", XK_3270_Rule}, - {"3270_Copy", XK_3270_Copy}, - {"3270_Play", XK_3270_Play}, - {"3270_Setup", XK_3270_Setup}, - {"3270_Record", XK_3270_Record}, - {"3270_ChangeScreen", XK_3270_ChangeScreen}, - {"3270_DeleteWord", XK_3270_DeleteWord}, - {"3270_ExSelect", XK_3270_ExSelect}, - {"3270_CursorSelect", XK_3270_CursorSelect}, - {"3270_PrintScreen", XK_3270_PrintScreen}, - {"3270_Enter", XK_3270_Enter}, -#endif -#ifdef XK_LATIN1 - {"space", XK_space}, - {"exclam", XK_exclam}, - {"quotedbl", XK_quotedbl}, - {"numbersign", XK_numbersign}, - {"dollar", XK_dollar}, - {"percent", XK_percent}, - {"ampersand", XK_ampersand}, - {"apostrophe", XK_apostrophe}, - {"quoteright", XK_quoteright}, - {"parenleft", XK_parenleft}, - {"parenright", XK_parenright}, - {"asterisk", XK_asterisk}, - {"plus", XK_plus}, - {"comma", XK_comma}, - {"minus", XK_minus}, - {"period", XK_period}, - {"slash", XK_slash}, - {"0", XK_0}, - {"1", XK_1}, - {"2", XK_2}, - {"3", XK_3}, - {"4", XK_4}, - {"5", XK_5}, - {"6", XK_6}, - {"7", XK_7}, - {"8", XK_8}, - {"9", XK_9}, - {"colon", XK_colon}, - {"semicolon", XK_semicolon}, - {"less", XK_less}, - {"equal", XK_equal}, - {"greater", XK_greater}, - {"question", XK_question}, - {"at", XK_at}, - {"A", XK_A}, - {"B", XK_B}, - {"C", XK_C}, - {"D", XK_D}, - {"E", XK_E}, - {"F", XK_F}, - {"G", XK_G}, - {"H", XK_H}, - {"I", XK_I}, - {"J", XK_J}, - {"K", XK_K}, - {"L", XK_L}, - {"M", XK_M}, - {"N", XK_N}, - {"O", XK_O}, - {"P", XK_P}, - {"Q", XK_Q}, - {"R", XK_R}, - {"S", XK_S}, - {"T", XK_T}, - {"U", XK_U}, - {"V", XK_V}, - {"W", XK_W}, - {"X", XK_X}, - {"Y", XK_Y}, - {"Z", XK_Z}, - {"bracketleft", XK_bracketleft}, - {"backslash", XK_backslash}, - {"bracketright", XK_bracketright}, - {"asciicircum", XK_asciicircum}, - {"underscore", XK_underscore}, - {"grave", XK_grave}, - {"quoteleft", XK_quoteleft}, - {"a", XK_a}, - {"b", XK_b}, - {"c", XK_c}, - {"d", XK_d}, - {"e", XK_e}, - {"f", XK_f}, - {"g", XK_g}, - {"h", XK_h}, - {"i", XK_i}, - {"j", XK_j}, - {"k", XK_k}, - {"l", XK_l}, - {"m", XK_m}, - {"n", XK_n}, - {"o", XK_o}, - {"p", XK_p}, - {"q", XK_q}, - {"r", XK_r}, - {"s", XK_s}, - {"t", XK_t}, - {"u", XK_u}, - {"v", XK_v}, - {"w", XK_w}, - {"x", XK_x}, - {"y", XK_y}, - {"z", XK_z}, - {"braceleft", XK_braceleft}, - {"bar", XK_bar}, - {"braceright", XK_braceright}, - {"asciitilde", XK_asciitilde}, - {"nobreakspace", XK_nobreakspace}, - {"exclamdown", XK_exclamdown}, - {"cent", XK_cent}, - {"sterling", XK_sterling}, - {"currency", XK_currency}, - {"yen", XK_yen}, - {"brokenbar", XK_brokenbar}, - {"section", XK_section}, - {"diaeresis", XK_diaeresis}, - {"copyright", XK_copyright}, - {"ordfeminine", XK_ordfeminine}, - {"guillemotleft", XK_guillemotleft}, - {"notsign", XK_notsign}, - {"hyphen", XK_hyphen}, - {"registered", XK_registered}, - {"macron", XK_macron}, - {"degree", XK_degree}, - {"plusminus", XK_plusminus}, - {"twosuperior", XK_twosuperior}, - {"threesuperior", XK_threesuperior}, - {"acute", XK_acute}, - {"mu", XK_mu}, - {"paragraph", XK_paragraph}, - {"periodcentered", XK_periodcentered}, - {"cedilla", XK_cedilla}, - {"onesuperior", XK_onesuperior}, - {"masculine", XK_masculine}, - {"guillemotright", XK_guillemotright}, - {"onequarter", XK_onequarter}, - {"onehalf", XK_onehalf}, - {"threequarters", XK_threequarters}, - {"questiondown", XK_questiondown}, - {"Agrave", XK_Agrave}, - {"Aacute", XK_Aacute}, - {"Acircumflex", XK_Acircumflex}, - {"Atilde", XK_Atilde}, - {"Adiaeresis", XK_Adiaeresis}, - {"Aring", XK_Aring}, - {"AE", XK_AE}, - {"Ccedilla", XK_Ccedilla}, - {"Egrave", XK_Egrave}, - {"Eacute", XK_Eacute}, - {"Ecircumflex", XK_Ecircumflex}, - {"Ediaeresis", XK_Ediaeresis}, - {"Igrave", XK_Igrave}, - {"Iacute", XK_Iacute}, - {"Icircumflex", XK_Icircumflex}, - {"Idiaeresis", XK_Idiaeresis}, - {"ETH", XK_ETH}, - {"Eth", XK_Eth}, - {"Ntilde", XK_Ntilde}, - {"Ograve", XK_Ograve}, - {"Oacute", XK_Oacute}, - {"Ocircumflex", XK_Ocircumflex}, - {"Otilde", XK_Otilde}, - {"Odiaeresis", XK_Odiaeresis}, - {"multiply", XK_multiply}, - {"Ooblique", XK_Ooblique}, - {"Ugrave", XK_Ugrave}, - {"Uacute", XK_Uacute}, - {"Ucircumflex", XK_Ucircumflex}, - {"Udiaeresis", XK_Udiaeresis}, - {"Yacute", XK_Yacute}, - {"THORN", XK_THORN}, - {"Thorn", XK_Thorn}, - {"ssharp", XK_ssharp}, - {"agrave", XK_agrave}, - {"aacute", XK_aacute}, - {"acircumflex", XK_acircumflex}, - {"atilde", XK_atilde}, - {"adiaeresis", XK_adiaeresis}, - {"aring", XK_aring}, - {"ae", XK_ae}, - {"ccedilla", XK_ccedilla}, - {"egrave", XK_egrave}, - {"eacute", XK_eacute}, - {"ecircumflex", XK_ecircumflex}, - {"ediaeresis", XK_ediaeresis}, - {"igrave", XK_igrave}, - {"iacute", XK_iacute}, - {"icircumflex", XK_icircumflex}, - {"idiaeresis", XK_idiaeresis}, - {"eth", XK_eth}, - {"ntilde", XK_ntilde}, - {"ograve", XK_ograve}, - {"oacute", XK_oacute}, - {"ocircumflex", XK_ocircumflex}, - {"otilde", XK_otilde}, - {"odiaeresis", XK_odiaeresis}, - {"division", XK_division}, - {"oslash", XK_oslash}, - {"ugrave", XK_ugrave}, - {"uacute", XK_uacute}, - {"ucircumflex", XK_ucircumflex}, - {"udiaeresis", XK_udiaeresis}, - {"yacute", XK_yacute}, - {"thorn", XK_thorn}, - {"ydiaeresis", XK_ydiaeresis}, -#endif /* XK_LATIN1 */ -#ifdef XK_LATIN2 - {"Aogonek", XK_Aogonek}, - {"breve", XK_breve}, - {"Lstroke", XK_Lstroke}, - {"Lcaron", XK_Lcaron}, - {"Sacute", XK_Sacute}, - {"Scaron", XK_Scaron}, - {"Scedilla", XK_Scedilla}, - {"Tcaron", XK_Tcaron}, - {"Zacute", XK_Zacute}, - {"Zcaron", XK_Zcaron}, - {"Zabovedot", XK_Zabovedot}, - {"aogonek", XK_aogonek}, - {"ogonek", XK_ogonek}, - {"lstroke", XK_lstroke}, - {"lcaron", XK_lcaron}, - {"sacute", XK_sacute}, - {"caron", XK_caron}, - {"scaron", XK_scaron}, - {"scedilla", XK_scedilla}, - {"tcaron", XK_tcaron}, - {"zacute", XK_zacute}, - {"doubleacute", XK_doubleacute}, - {"zcaron", XK_zcaron}, - {"zabovedot", XK_zabovedot}, - {"Racute", XK_Racute}, - {"Abreve", XK_Abreve}, - {"Lacute", XK_Lacute}, - {"Cacute", XK_Cacute}, - {"Ccaron", XK_Ccaron}, - {"Eogonek", XK_Eogonek}, - {"Ecaron", XK_Ecaron}, - {"Dcaron", XK_Dcaron}, - {"Dstroke", XK_Dstroke}, - {"Nacute", XK_Nacute}, - {"Ncaron", XK_Ncaron}, - {"Odoubleacute", XK_Odoubleacute}, - {"Rcaron", XK_Rcaron}, - {"Uring", XK_Uring}, - {"Udoubleacute", XK_Udoubleacute}, - {"Tcedilla", XK_Tcedilla}, - {"racute", XK_racute}, - {"abreve", XK_abreve}, - {"lacute", XK_lacute}, - {"cacute", XK_cacute}, - {"ccaron", XK_ccaron}, - {"eogonek", XK_eogonek}, - {"ecaron", XK_ecaron}, - {"dcaron", XK_dcaron}, - {"dstroke", XK_dstroke}, - {"nacute", XK_nacute}, - {"ncaron", XK_ncaron}, - {"odoubleacute", XK_odoubleacute}, - {"udoubleacute", XK_udoubleacute}, - {"rcaron", XK_rcaron}, - {"uring", XK_uring}, - {"tcedilla", XK_tcedilla}, - {"abovedot", XK_abovedot}, -#endif /* XK_LATIN2 */ -#ifdef XK_LATIN3 - {"Hstroke", XK_Hstroke}, - {"Hcircumflex", XK_Hcircumflex}, - {"Iabovedot", XK_Iabovedot}, - {"Gbreve", XK_Gbreve}, - {"Jcircumflex", XK_Jcircumflex}, - {"hstroke", XK_hstroke}, - {"hcircumflex", XK_hcircumflex}, - {"idotless", XK_idotless}, - {"gbreve", XK_gbreve}, - {"jcircumflex", XK_jcircumflex}, - {"Cabovedot", XK_Cabovedot}, - {"Ccircumflex", XK_Ccircumflex}, - {"Gabovedot", XK_Gabovedot}, - {"Gcircumflex", XK_Gcircumflex}, - {"Ubreve", XK_Ubreve}, - {"Scircumflex", XK_Scircumflex}, - {"cabovedot", XK_cabovedot}, - {"ccircumflex", XK_ccircumflex}, - {"gabovedot", XK_gabovedot}, - {"gcircumflex", XK_gcircumflex}, - {"ubreve", XK_ubreve}, - {"scircumflex", XK_scircumflex}, -#endif /* XK_LATIN3 */ -#ifdef XK_LATIN4 - {"kra", XK_kra}, - {"kappa", XK_kappa}, - {"Rcedilla", XK_Rcedilla}, - {"Itilde", XK_Itilde}, - {"Lcedilla", XK_Lcedilla}, - {"Emacron", XK_Emacron}, - {"Gcedilla", XK_Gcedilla}, - {"Tslash", XK_Tslash}, - {"rcedilla", XK_rcedilla}, - {"itilde", XK_itilde}, - {"lcedilla", XK_lcedilla}, - {"emacron", XK_emacron}, - {"gcedilla", XK_gcedilla}, - {"tslash", XK_tslash}, - {"ENG", XK_ENG}, - {"eng", XK_eng}, - {"Amacron", XK_Amacron}, - {"Iogonek", XK_Iogonek}, - {"Eabovedot", XK_Eabovedot}, - {"Imacron", XK_Imacron}, - {"Ncedilla", XK_Ncedilla}, - {"Omacron", XK_Omacron}, - {"Kcedilla", XK_Kcedilla}, - {"Uogonek", XK_Uogonek}, - {"Utilde", XK_Utilde}, - {"Umacron", XK_Umacron}, - {"amacron", XK_amacron}, - {"iogonek", XK_iogonek}, - {"eabovedot", XK_eabovedot}, - {"imacron", XK_imacron}, - {"ncedilla", XK_ncedilla}, - {"omacron", XK_omacron}, - {"kcedilla", XK_kcedilla}, - {"uogonek", XK_uogonek}, - {"utilde", XK_utilde}, - {"umacron", XK_umacron}, -#endif /* XK_LATIN4 */ -#ifdef XK_KATAKANA - {"overline", XK_overline}, - {"kana_fullstop", XK_kana_fullstop}, - {"kana_openingbracket", XK_kana_openingbracket}, - {"kana_closingbracket", XK_kana_closingbracket}, - {"kana_comma", XK_kana_comma}, - {"kana_conjunctive", XK_kana_conjunctive}, - {"kana_middledot", XK_kana_middledot}, - {"kana_WO", XK_kana_WO}, - {"kana_a", XK_kana_a}, - {"kana_i", XK_kana_i}, - {"kana_u", XK_kana_u}, - {"kana_e", XK_kana_e}, - {"kana_o", XK_kana_o}, - {"kana_ya", XK_kana_ya}, - {"kana_yu", XK_kana_yu}, - {"kana_yo", XK_kana_yo}, - {"kana_tsu", XK_kana_tsu}, - {"kana_tu", XK_kana_tu}, - {"prolongedsound", XK_prolongedsound}, - {"kana_A", XK_kana_A}, - {"kana_I", XK_kana_I}, - {"kana_U", XK_kana_U}, - {"kana_E", XK_kana_E}, - {"kana_O", XK_kana_O}, - {"kana_KA", XK_kana_KA}, - {"kana_KI", XK_kana_KI}, - {"kana_KU", XK_kana_KU}, - {"kana_KE", XK_kana_KE}, - {"kana_KO", XK_kana_KO}, - {"kana_SA", XK_kana_SA}, - {"kana_SHI", XK_kana_SHI}, - {"kana_SU", XK_kana_SU}, - {"kana_SE", XK_kana_SE}, - {"kana_SO", XK_kana_SO}, - {"kana_TA", XK_kana_TA}, - {"kana_CHI", XK_kana_CHI}, - {"kana_TI", XK_kana_TI}, - {"kana_TSU", XK_kana_TSU}, - {"kana_TU", XK_kana_TU}, - {"kana_TE", XK_kana_TE}, - {"kana_TO", XK_kana_TO}, - {"kana_NA", XK_kana_NA}, - {"kana_NI", XK_kana_NI}, - {"kana_NU", XK_kana_NU}, - {"kana_NE", XK_kana_NE}, - {"kana_NO", XK_kana_NO}, - {"kana_HA", XK_kana_HA}, - {"kana_HI", XK_kana_HI}, - {"kana_FU", XK_kana_FU}, - {"kana_HU", XK_kana_HU}, - {"kana_HE", XK_kana_HE}, - {"kana_HO", XK_kana_HO}, - {"kana_MA", XK_kana_MA}, - {"kana_MI", XK_kana_MI}, - {"kana_MU", XK_kana_MU}, - {"kana_ME", XK_kana_ME}, - {"kana_MO", XK_kana_MO}, - {"kana_YA", XK_kana_YA}, - {"kana_YU", XK_kana_YU}, - {"kana_YO", XK_kana_YO}, - {"kana_RA", XK_kana_RA}, - {"kana_RI", XK_kana_RI}, - {"kana_RU", XK_kana_RU}, - {"kana_RE", XK_kana_RE}, - {"kana_RO", XK_kana_RO}, - {"kana_WA", XK_kana_WA}, - {"kana_N", XK_kana_N}, - {"voicedsound", XK_voicedsound}, - {"semivoicedsound", XK_semivoicedsound}, - {"kana_switch", XK_kana_switch}, -#endif /* XK_KATAKANA */ -#ifdef XK_ARABIC - {"Arabic_comma", XK_Arabic_comma}, - {"Arabic_semicolon", XK_Arabic_semicolon}, - {"Arabic_question_mark", XK_Arabic_question_mark}, - {"Arabic_hamza", XK_Arabic_hamza}, - {"Arabic_maddaonalef", XK_Arabic_maddaonalef}, - {"Arabic_hamzaonalef", XK_Arabic_hamzaonalef}, - {"Arabic_hamzaonwaw", XK_Arabic_hamzaonwaw}, - {"Arabic_hamzaunderalef", XK_Arabic_hamzaunderalef}, - {"Arabic_hamzaonyeh", XK_Arabic_hamzaonyeh}, - {"Arabic_alef", XK_Arabic_alef}, - {"Arabic_beh", XK_Arabic_beh}, - {"Arabic_tehmarbuta", XK_Arabic_tehmarbuta}, - {"Arabic_teh", XK_Arabic_teh}, - {"Arabic_theh", XK_Arabic_theh}, - {"Arabic_jeem", XK_Arabic_jeem}, - {"Arabic_hah", XK_Arabic_hah}, - {"Arabic_khah", XK_Arabic_khah}, - {"Arabic_dal", XK_Arabic_dal}, - {"Arabic_thal", XK_Arabic_thal}, - {"Arabic_ra", XK_Arabic_ra}, - {"Arabic_zain", XK_Arabic_zain}, - {"Arabic_seen", XK_Arabic_seen}, - {"Arabic_sheen", XK_Arabic_sheen}, - {"Arabic_sad", XK_Arabic_sad}, - {"Arabic_dad", XK_Arabic_dad}, - {"Arabic_tah", XK_Arabic_tah}, - {"Arabic_zah", XK_Arabic_zah}, - {"Arabic_ain", XK_Arabic_ain}, - {"Arabic_ghain", XK_Arabic_ghain}, - {"Arabic_tatweel", XK_Arabic_tatweel}, - {"Arabic_feh", XK_Arabic_feh}, - {"Arabic_qaf", XK_Arabic_qaf}, - {"Arabic_kaf", XK_Arabic_kaf}, - {"Arabic_lam", XK_Arabic_lam}, - {"Arabic_meem", XK_Arabic_meem}, - {"Arabic_noon", XK_Arabic_noon}, - {"Arabic_ha", XK_Arabic_ha}, - {"Arabic_heh", XK_Arabic_heh}, - {"Arabic_waw", XK_Arabic_waw}, - {"Arabic_alefmaksura", XK_Arabic_alefmaksura}, - {"Arabic_yeh", XK_Arabic_yeh}, - {"Arabic_fathatan", XK_Arabic_fathatan}, - {"Arabic_dammatan", XK_Arabic_dammatan}, - {"Arabic_kasratan", XK_Arabic_kasratan}, - {"Arabic_fatha", XK_Arabic_fatha}, - {"Arabic_damma", XK_Arabic_damma}, - {"Arabic_kasra", XK_Arabic_kasra}, - {"Arabic_shadda", XK_Arabic_shadda}, - {"Arabic_sukun", XK_Arabic_sukun}, - {"Arabic_switch", XK_Arabic_switch}, -#endif /* XK_ARABIC */ -#ifdef XK_CYRILLIC - {"Serbian_dje", XK_Serbian_dje}, - {"Macedonia_gje", XK_Macedonia_gje}, - {"Cyrillic_io", XK_Cyrillic_io}, - {"Ukrainian_ie", XK_Ukrainian_ie}, - {"Ukranian_je", XK_Ukranian_je}, - {"Macedonia_dse", XK_Macedonia_dse}, - {"Ukrainian_i", XK_Ukrainian_i}, - {"Ukranian_i", XK_Ukranian_i}, - {"Ukrainian_yi", XK_Ukrainian_yi}, - {"Ukranian_yi", XK_Ukranian_yi}, - {"Cyrillic_je", XK_Cyrillic_je}, - {"Serbian_je", XK_Serbian_je}, - {"Cyrillic_lje", XK_Cyrillic_lje}, - {"Serbian_lje", XK_Serbian_lje}, - {"Cyrillic_nje", XK_Cyrillic_nje}, - {"Serbian_nje", XK_Serbian_nje}, - {"Serbian_tshe", XK_Serbian_tshe}, - {"Macedonia_kje", XK_Macedonia_kje}, - {"Byelorussian_shortu", XK_Byelorussian_shortu}, - {"Cyrillic_dzhe", XK_Cyrillic_dzhe}, - {"Serbian_dze", XK_Serbian_dze}, - {"numerosign", XK_numerosign}, - {"Serbian_DJE", XK_Serbian_DJE}, - {"Macedonia_GJE", XK_Macedonia_GJE}, - {"Cyrillic_IO", XK_Cyrillic_IO}, - {"Ukrainian_IE", XK_Ukrainian_IE}, - {"Ukranian_JE", XK_Ukranian_JE}, - {"Macedonia_DSE", XK_Macedonia_DSE}, - {"Ukrainian_I", XK_Ukrainian_I}, - {"Ukranian_I", XK_Ukranian_I}, - {"Ukrainian_YI", XK_Ukrainian_YI}, - {"Ukranian_YI", XK_Ukranian_YI}, - {"Cyrillic_JE", XK_Cyrillic_JE}, - {"Serbian_JE", XK_Serbian_JE}, - {"Cyrillic_LJE", XK_Cyrillic_LJE}, - {"Serbian_LJE", XK_Serbian_LJE}, - {"Cyrillic_NJE", XK_Cyrillic_NJE}, - {"Serbian_NJE", XK_Serbian_NJE}, - {"Serbian_TSHE", XK_Serbian_TSHE}, - {"Macedonia_KJE", XK_Macedonia_KJE}, - {"Byelorussian_SHORTU", XK_Byelorussian_SHORTU}, - {"Cyrillic_DZHE", XK_Cyrillic_DZHE}, - {"Serbian_DZE", XK_Serbian_DZE}, - {"Cyrillic_yu", XK_Cyrillic_yu}, - {"Cyrillic_a", XK_Cyrillic_a}, - {"Cyrillic_be", XK_Cyrillic_be}, - {"Cyrillic_tse", XK_Cyrillic_tse}, - {"Cyrillic_de", XK_Cyrillic_de}, - {"Cyrillic_ie", XK_Cyrillic_ie}, - {"Cyrillic_ef", XK_Cyrillic_ef}, - {"Cyrillic_ghe", XK_Cyrillic_ghe}, - {"Cyrillic_ha", XK_Cyrillic_ha}, - {"Cyrillic_i", XK_Cyrillic_i}, - {"Cyrillic_shorti", XK_Cyrillic_shorti}, - {"Cyrillic_ka", XK_Cyrillic_ka}, - {"Cyrillic_el", XK_Cyrillic_el}, - {"Cyrillic_em", XK_Cyrillic_em}, - {"Cyrillic_en", XK_Cyrillic_en}, - {"Cyrillic_o", XK_Cyrillic_o}, - {"Cyrillic_pe", XK_Cyrillic_pe}, - {"Cyrillic_ya", XK_Cyrillic_ya}, - {"Cyrillic_er", XK_Cyrillic_er}, - {"Cyrillic_es", XK_Cyrillic_es}, - {"Cyrillic_te", XK_Cyrillic_te}, - {"Cyrillic_u", XK_Cyrillic_u}, - {"Cyrillic_zhe", XK_Cyrillic_zhe}, - {"Cyrillic_ve", XK_Cyrillic_ve}, - {"Cyrillic_softsign", XK_Cyrillic_softsign}, - {"Cyrillic_yeru", XK_Cyrillic_yeru}, - {"Cyrillic_ze", XK_Cyrillic_ze}, - {"Cyrillic_sha", XK_Cyrillic_sha}, - {"Cyrillic_e", XK_Cyrillic_e}, - {"Cyrillic_shcha", XK_Cyrillic_shcha}, - {"Cyrillic_che", XK_Cyrillic_che}, - {"Cyrillic_hardsign", XK_Cyrillic_hardsign}, - {"Cyrillic_YU", XK_Cyrillic_YU}, - {"Cyrillic_A", XK_Cyrillic_A}, - {"Cyrillic_BE", XK_Cyrillic_BE}, - {"Cyrillic_TSE", XK_Cyrillic_TSE}, - {"Cyrillic_DE", XK_Cyrillic_DE}, - {"Cyrillic_IE", XK_Cyrillic_IE}, - {"Cyrillic_EF", XK_Cyrillic_EF}, - {"Cyrillic_GHE", XK_Cyrillic_GHE}, - {"Cyrillic_HA", XK_Cyrillic_HA}, - {"Cyrillic_I", XK_Cyrillic_I}, - {"Cyrillic_SHORTI", XK_Cyrillic_SHORTI}, - {"Cyrillic_KA", XK_Cyrillic_KA}, - {"Cyrillic_EL", XK_Cyrillic_EL}, - {"Cyrillic_EM", XK_Cyrillic_EM}, - {"Cyrillic_EN", XK_Cyrillic_EN}, - {"Cyrillic_O", XK_Cyrillic_O}, - {"Cyrillic_PE", XK_Cyrillic_PE}, - {"Cyrillic_YA", XK_Cyrillic_YA}, - {"Cyrillic_ER", XK_Cyrillic_ER}, - {"Cyrillic_ES", XK_Cyrillic_ES}, - {"Cyrillic_TE", XK_Cyrillic_TE}, - {"Cyrillic_U", XK_Cyrillic_U}, - {"Cyrillic_ZHE", XK_Cyrillic_ZHE}, - {"Cyrillic_VE", XK_Cyrillic_VE}, - {"Cyrillic_SOFTSIGN", XK_Cyrillic_SOFTSIGN}, - {"Cyrillic_YERU", XK_Cyrillic_YERU}, - {"Cyrillic_ZE", XK_Cyrillic_ZE}, - {"Cyrillic_SHA", XK_Cyrillic_SHA}, - {"Cyrillic_E", XK_Cyrillic_E}, - {"Cyrillic_SHCHA", XK_Cyrillic_SHCHA}, - {"Cyrillic_CHE", XK_Cyrillic_CHE}, - {"Cyrillic_HARDSIGN", XK_Cyrillic_HARDSIGN}, -#endif /* XK_CYRILLIC */ -#ifdef XK_GREEK - {"Greek_ALPHAaccent", XK_Greek_ALPHAaccent}, - {"Greek_EPSILONaccent", XK_Greek_EPSILONaccent}, - {"Greek_ETAaccent", XK_Greek_ETAaccent}, - {"Greek_IOTAaccent", XK_Greek_IOTAaccent}, - {"Greek_IOTAdieresis", XK_Greek_IOTAdieresis}, - {"Greek_OMICRONaccent", XK_Greek_OMICRONaccent}, - {"Greek_UPSILONaccent", XK_Greek_UPSILONaccent}, - {"Greek_UPSILONdieresis", XK_Greek_UPSILONdieresis}, - {"Greek_OMEGAaccent", XK_Greek_OMEGAaccent}, - {"Greek_accentdieresis", XK_Greek_accentdieresis}, - {"Greek_horizbar", XK_Greek_horizbar}, - {"Greek_alphaaccent", XK_Greek_alphaaccent}, - {"Greek_epsilonaccent", XK_Greek_epsilonaccent}, - {"Greek_etaaccent", XK_Greek_etaaccent}, - {"Greek_iotaaccent", XK_Greek_iotaaccent}, - {"Greek_iotadieresis", XK_Greek_iotadieresis}, - {"Greek_iotaaccentdieresis", XK_Greek_iotaaccentdieresis}, - {"Greek_omicronaccent", XK_Greek_omicronaccent}, - {"Greek_upsilonaccent", XK_Greek_upsilonaccent}, - {"Greek_upsilondieresis", XK_Greek_upsilondieresis}, - {"Greek_upsilonaccentdieresis", XK_Greek_upsilonaccentdieresis}, - {"Greek_omegaaccent", XK_Greek_omegaaccent}, - {"Greek_ALPHA", XK_Greek_ALPHA}, - {"Greek_BETA", XK_Greek_BETA}, - {"Greek_GAMMA", XK_Greek_GAMMA}, - {"Greek_DELTA", XK_Greek_DELTA}, - {"Greek_EPSILON", XK_Greek_EPSILON}, - {"Greek_ZETA", XK_Greek_ZETA}, - {"Greek_ETA", XK_Greek_ETA}, - {"Greek_THETA", XK_Greek_THETA}, - {"Greek_IOTA", XK_Greek_IOTA}, - {"Greek_KAPPA", XK_Greek_KAPPA}, - {"Greek_LAMDA", XK_Greek_LAMDA}, - {"Greek_LAMBDA", XK_Greek_LAMBDA}, - {"Greek_MU", XK_Greek_MU}, - {"Greek_NU", XK_Greek_NU}, - {"Greek_XI", XK_Greek_XI}, - {"Greek_OMICRON", XK_Greek_OMICRON}, - {"Greek_PI", XK_Greek_PI}, - {"Greek_RHO", XK_Greek_RHO}, - {"Greek_SIGMA", XK_Greek_SIGMA}, - {"Greek_TAU", XK_Greek_TAU}, - {"Greek_UPSILON", XK_Greek_UPSILON}, - {"Greek_PHI", XK_Greek_PHI}, - {"Greek_CHI", XK_Greek_CHI}, - {"Greek_PSI", XK_Greek_PSI}, - {"Greek_OMEGA", XK_Greek_OMEGA}, - {"Greek_alpha", XK_Greek_alpha}, - {"Greek_beta", XK_Greek_beta}, - {"Greek_gamma", XK_Greek_gamma}, - {"Greek_delta", XK_Greek_delta}, - {"Greek_epsilon", XK_Greek_epsilon}, - {"Greek_zeta", XK_Greek_zeta}, - {"Greek_eta", XK_Greek_eta}, - {"Greek_theta", XK_Greek_theta}, - {"Greek_iota", XK_Greek_iota}, - {"Greek_kappa", XK_Greek_kappa}, - {"Greek_lamda", XK_Greek_lamda}, - {"Greek_lambda", XK_Greek_lambda}, - {"Greek_mu", XK_Greek_mu}, - {"Greek_nu", XK_Greek_nu}, - {"Greek_xi", XK_Greek_xi}, - {"Greek_omicron", XK_Greek_omicron}, - {"Greek_pi", XK_Greek_pi}, - {"Greek_rho", XK_Greek_rho}, - {"Greek_sigma", XK_Greek_sigma}, - {"Greek_finalsmallsigma", XK_Greek_finalsmallsigma}, - {"Greek_tau", XK_Greek_tau}, - {"Greek_upsilon", XK_Greek_upsilon}, - {"Greek_phi", XK_Greek_phi}, - {"Greek_chi", XK_Greek_chi}, - {"Greek_psi", XK_Greek_psi}, - {"Greek_omega", XK_Greek_omega}, - {"Greek_switch", XK_Greek_switch}, -#endif /* XK_GREEK */ -#ifdef XK_TECHNICAL - {"leftradical", XK_leftradical}, - {"topleftradical", XK_topleftradical}, - {"horizconnector", XK_horizconnector}, - {"topintegral", XK_topintegral}, - {"botintegral", XK_botintegral}, - {"vertconnector", XK_vertconnector}, - {"topleftsqbracket", XK_topleftsqbracket}, - {"botleftsqbracket", XK_botleftsqbracket}, - {"toprightsqbracket", XK_toprightsqbracket}, - {"botrightsqbracket", XK_botrightsqbracket}, - {"topleftparens", XK_topleftparens}, - {"botleftparens", XK_botleftparens}, - {"toprightparens", XK_toprightparens}, - {"botrightparens", XK_botrightparens}, - {"leftmiddlecurlybrace", XK_leftmiddlecurlybrace}, - {"rightmiddlecurlybrace", XK_rightmiddlecurlybrace}, - {"topleftsummation", XK_topleftsummation}, - {"botleftsummation", XK_botleftsummation}, - {"topvertsummationconnector", XK_topvertsummationconnector}, - {"botvertsummationconnector", XK_botvertsummationconnector}, - {"toprightsummation", XK_toprightsummation}, - {"botrightsummation", XK_botrightsummation}, - {"rightmiddlesummation", XK_rightmiddlesummation}, - {"lessthanequal", XK_lessthanequal}, - {"notequal", XK_notequal}, - {"greaterthanequal", XK_greaterthanequal}, - {"integral", XK_integral}, - {"therefore", XK_therefore}, - {"variation", XK_variation}, - {"infinity", XK_infinity}, - {"nabla", XK_nabla}, - {"approximate", XK_approximate}, - {"similarequal", XK_similarequal}, - {"ifonlyif", XK_ifonlyif}, - {"implies", XK_implies}, - {"identical", XK_identical}, - {"radical", XK_radical}, - {"includedin", XK_includedin}, - {"includes", XK_includes}, - {"intersection", XK_intersection}, - {"union", XK_union}, - {"logicaland", XK_logicaland}, - {"logicalor", XK_logicalor}, - {"partialderivative", XK_partialderivative}, - {"function", XK_function}, - {"leftarrow", XK_leftarrow}, - {"uparrow", XK_uparrow}, - {"rightarrow", XK_rightarrow}, - {"downarrow", XK_downarrow}, -#endif /* XK_TECHNICAL */ -#ifdef XK_SPECIAL - {"blank", XK_blank}, - {"soliddiamond", XK_soliddiamond}, - {"checkerboard", XK_checkerboard}, - {"ht", XK_ht}, - {"ff", XK_ff}, - {"cr", XK_cr}, - {"lf", XK_lf}, - {"nl", XK_nl}, - {"vt", XK_vt}, - {"lowrightcorner", XK_lowrightcorner}, - {"uprightcorner", XK_uprightcorner}, - {"upleftcorner", XK_upleftcorner}, - {"lowleftcorner", XK_lowleftcorner}, - {"crossinglines", XK_crossinglines}, - {"horizlinescan1", XK_horizlinescan1}, - {"horizlinescan3", XK_horizlinescan3}, - {"horizlinescan5", XK_horizlinescan5}, - {"horizlinescan7", XK_horizlinescan7}, - {"horizlinescan9", XK_horizlinescan9}, - {"leftt", XK_leftt}, - {"rightt", XK_rightt}, - {"bott", XK_bott}, - {"topt", XK_topt}, - {"vertbar", XK_vertbar}, -#endif /* XK_SPECIAL */ -#ifdef XK_PUBLISHING - {"emspace", XK_emspace}, - {"enspace", XK_enspace}, - {"em3space", XK_em3space}, - {"em4space", XK_em4space}, - {"digitspace", XK_digitspace}, - {"punctspace", XK_punctspace}, - {"thinspace", XK_thinspace}, - {"hairspace", XK_hairspace}, - {"emdash", XK_emdash}, - {"endash", XK_endash}, - {"signifblank", XK_signifblank}, - {"ellipsis", XK_ellipsis}, - {"doubbaselinedot", XK_doubbaselinedot}, - {"onethird", XK_onethird}, - {"twothirds", XK_twothirds}, - {"onefifth", XK_onefifth}, - {"twofifths", XK_twofifths}, - {"threefifths", XK_threefifths}, - {"fourfifths", XK_fourfifths}, - {"onesixth", XK_onesixth}, - {"fivesixths", XK_fivesixths}, - {"careof", XK_careof}, - {"figdash", XK_figdash}, - {"leftanglebracket", XK_leftanglebracket}, - {"decimalpoint", XK_decimalpoint}, - {"rightanglebracket", XK_rightanglebracket}, - {"marker", XK_marker}, - {"oneeighth", XK_oneeighth}, - {"threeeighths", XK_threeeighths}, - {"fiveeighths", XK_fiveeighths}, - {"seveneighths", XK_seveneighths}, - {"trademark", XK_trademark}, - {"signaturemark", XK_signaturemark}, - {"trademarkincircle", XK_trademarkincircle}, - {"leftopentriangle", XK_leftopentriangle}, - {"rightopentriangle", XK_rightopentriangle}, - {"emopencircle", XK_emopencircle}, - {"emopenrectangle", XK_emopenrectangle}, - {"leftsinglequotemark", XK_leftsinglequotemark}, - {"rightsinglequotemark", XK_rightsinglequotemark}, - {"leftdoublequotemark", XK_leftdoublequotemark}, - {"rightdoublequotemark", XK_rightdoublequotemark}, - {"prescription", XK_prescription}, - {"minutes", XK_minutes}, - {"seconds", XK_seconds}, - {"latincross", XK_latincross}, - {"hexagram", XK_hexagram}, - {"filledrectbullet", XK_filledrectbullet}, - {"filledlefttribullet", XK_filledlefttribullet}, - {"filledrighttribullet", XK_filledrighttribullet}, - {"emfilledcircle", XK_emfilledcircle}, - {"emfilledrect", XK_emfilledrect}, - {"enopencircbullet", XK_enopencircbullet}, - {"enopensquarebullet", XK_enopensquarebullet}, - {"openrectbullet", XK_openrectbullet}, - {"opentribulletup", XK_opentribulletup}, - {"opentribulletdown", XK_opentribulletdown}, - {"openstar", XK_openstar}, - {"enfilledcircbullet", XK_enfilledcircbullet}, - {"enfilledsqbullet", XK_enfilledsqbullet}, - {"filledtribulletup", XK_filledtribulletup}, - {"filledtribulletdown", XK_filledtribulletdown}, - {"leftpointer", XK_leftpointer}, - {"rightpointer", XK_rightpointer}, - {"club", XK_club}, - {"diamond", XK_diamond}, - {"heart", XK_heart}, - {"maltesecross", XK_maltesecross}, - {"dagger", XK_dagger}, - {"doubledagger", XK_doubledagger}, - {"checkmark", XK_checkmark}, - {"ballotcross", XK_ballotcross}, - {"musicalsharp", XK_musicalsharp}, - {"musicalflat", XK_musicalflat}, - {"malesymbol", XK_malesymbol}, - {"femalesymbol", XK_femalesymbol}, - {"telephone", XK_telephone}, - {"telephonerecorder", XK_telephonerecorder}, - {"phonographcopyright", XK_phonographcopyright}, - {"caret", XK_caret}, - {"singlelowquotemark", XK_singlelowquotemark}, - {"doublelowquotemark", XK_doublelowquotemark}, - {"cursor", XK_cursor}, -#endif /* XK_PUBLISHING */ -#ifdef XK_APL - {"leftcaret", XK_leftcaret}, - {"rightcaret", XK_rightcaret}, - {"downcaret", XK_downcaret}, - {"upcaret", XK_upcaret}, - {"overbar", XK_overbar}, - {"downtack", XK_downtack}, - {"upshoe", XK_upshoe}, - {"downstile", XK_downstile}, - {"underbar", XK_underbar}, - {"jot", XK_jot}, - {"quad", XK_quad}, - {"uptack", XK_uptack}, - {"circle", XK_circle}, - {"upstile", XK_upstile}, - {"downshoe", XK_downshoe}, - {"rightshoe", XK_rightshoe}, - {"leftshoe", XK_leftshoe}, - {"lefttack", XK_lefttack}, - {"righttack", XK_righttack}, -#endif /* XK_APL */ -#ifdef XK_HEBREW - {"hebrew_doublelowline", XK_hebrew_doublelowline}, - {"hebrew_aleph", XK_hebrew_aleph}, - {"hebrew_bet", XK_hebrew_bet}, - {"hebrew_beth", XK_hebrew_beth}, - {"hebrew_gimel", XK_hebrew_gimel}, - {"hebrew_gimmel", XK_hebrew_gimmel}, - {"hebrew_dalet", XK_hebrew_dalet}, - {"hebrew_daleth", XK_hebrew_daleth}, - {"hebrew_he", XK_hebrew_he}, - {"hebrew_waw", XK_hebrew_waw}, - {"hebrew_zain", XK_hebrew_zain}, - {"hebrew_zayin", XK_hebrew_zayin}, - {"hebrew_chet", XK_hebrew_chet}, - {"hebrew_het", XK_hebrew_het}, - {"hebrew_tet", XK_hebrew_tet}, - {"hebrew_teth", XK_hebrew_teth}, - {"hebrew_yod", XK_hebrew_yod}, - {"hebrew_finalkaph", XK_hebrew_finalkaph}, - {"hebrew_kaph", XK_hebrew_kaph}, - {"hebrew_lamed", XK_hebrew_lamed}, - {"hebrew_finalmem", XK_hebrew_finalmem}, - {"hebrew_mem", XK_hebrew_mem}, - {"hebrew_finalnun", XK_hebrew_finalnun}, - {"hebrew_nun", XK_hebrew_nun}, - {"hebrew_samech", XK_hebrew_samech}, - {"hebrew_samekh", XK_hebrew_samekh}, - {"hebrew_ayin", XK_hebrew_ayin}, - {"hebrew_finalpe", XK_hebrew_finalpe}, - {"hebrew_pe", XK_hebrew_pe}, - {"hebrew_finalzade", XK_hebrew_finalzade}, - {"hebrew_finalzadi", XK_hebrew_finalzadi}, - {"hebrew_zade", XK_hebrew_zade}, - {"hebrew_zadi", XK_hebrew_zadi}, - {"hebrew_qoph", XK_hebrew_qoph}, - {"hebrew_kuf", XK_hebrew_kuf}, - {"hebrew_resh", XK_hebrew_resh}, - {"hebrew_shin", XK_hebrew_shin}, - {"hebrew_taw", XK_hebrew_taw}, - {"hebrew_taf", XK_hebrew_taf}, - {"Hebrew_switch", XK_Hebrew_switch}, -#endif /* XK_HEBREW */ -#ifdef XK_THAI - {"Thai_kokai", XK_Thai_kokai}, - {"Thai_khokhai", XK_Thai_khokhai}, - {"Thai_khokhuat", XK_Thai_khokhuat}, - {"Thai_khokhwai", XK_Thai_khokhwai}, - {"Thai_khokhon", XK_Thai_khokhon}, - {"Thai_khorakhang", XK_Thai_khorakhang}, - {"Thai_ngongu", XK_Thai_ngongu}, - {"Thai_chochan", XK_Thai_chochan}, - {"Thai_choching", XK_Thai_choching}, - {"Thai_chochang", XK_Thai_chochang}, - {"Thai_soso", XK_Thai_soso}, - {"Thai_chochoe", XK_Thai_chochoe}, - {"Thai_yoying", XK_Thai_yoying}, - {"Thai_dochada", XK_Thai_dochada}, - {"Thai_topatak", XK_Thai_topatak}, - {"Thai_thothan", XK_Thai_thothan}, - {"Thai_thonangmontho", XK_Thai_thonangmontho}, - {"Thai_thophuthao", XK_Thai_thophuthao}, - {"Thai_nonen", XK_Thai_nonen}, - {"Thai_dodek", XK_Thai_dodek}, - {"Thai_totao", XK_Thai_totao}, - {"Thai_thothung", XK_Thai_thothung}, - {"Thai_thothahan", XK_Thai_thothahan}, - {"Thai_thothong", XK_Thai_thothong}, - {"Thai_nonu", XK_Thai_nonu}, - {"Thai_bobaimai", XK_Thai_bobaimai}, - {"Thai_popla", XK_Thai_popla}, - {"Thai_phophung", XK_Thai_phophung}, - {"Thai_fofa", XK_Thai_fofa}, - {"Thai_phophan", XK_Thai_phophan}, - {"Thai_fofan", XK_Thai_fofan}, - {"Thai_phosamphao", XK_Thai_phosamphao}, - {"Thai_moma", XK_Thai_moma}, - {"Thai_yoyak", XK_Thai_yoyak}, - {"Thai_rorua", XK_Thai_rorua}, - {"Thai_ru", XK_Thai_ru}, - {"Thai_loling", XK_Thai_loling}, - {"Thai_lu", XK_Thai_lu}, - {"Thai_wowaen", XK_Thai_wowaen}, - {"Thai_sosala", XK_Thai_sosala}, - {"Thai_sorusi", XK_Thai_sorusi}, - {"Thai_sosua", XK_Thai_sosua}, - {"Thai_hohip", XK_Thai_hohip}, - {"Thai_lochula", XK_Thai_lochula}, - {"Thai_oang", XK_Thai_oang}, - {"Thai_honokhuk", XK_Thai_honokhuk}, - {"Thai_paiyannoi", XK_Thai_paiyannoi}, - {"Thai_saraa", XK_Thai_saraa}, - {"Thai_maihanakat", XK_Thai_maihanakat}, - {"Thai_saraaa", XK_Thai_saraaa}, - {"Thai_saraam", XK_Thai_saraam}, - {"Thai_sarai", XK_Thai_sarai}, - {"Thai_saraii", XK_Thai_saraii}, - {"Thai_saraue", XK_Thai_saraue}, - {"Thai_sarauee", XK_Thai_sarauee}, - {"Thai_sarau", XK_Thai_sarau}, - {"Thai_sarauu", XK_Thai_sarauu}, - {"Thai_phinthu", XK_Thai_phinthu}, - {"Thai_maihanakat_maitho", XK_Thai_maihanakat_maitho}, - {"Thai_baht", XK_Thai_baht}, - {"Thai_sarae", XK_Thai_sarae}, - {"Thai_saraae", XK_Thai_saraae}, - {"Thai_sarao", XK_Thai_sarao}, - {"Thai_saraaimaimuan", XK_Thai_saraaimaimuan}, - {"Thai_saraaimaimalai", XK_Thai_saraaimaimalai}, - {"Thai_lakkhangyao", XK_Thai_lakkhangyao}, - {"Thai_maiyamok", XK_Thai_maiyamok}, - {"Thai_maitaikhu", XK_Thai_maitaikhu}, - {"Thai_maiek", XK_Thai_maiek}, - {"Thai_maitho", XK_Thai_maitho}, - {"Thai_maitri", XK_Thai_maitri}, - {"Thai_maichattawa", XK_Thai_maichattawa}, - {"Thai_thanthakhat", XK_Thai_thanthakhat}, - {"Thai_nikhahit", XK_Thai_nikhahit}, - {"Thai_leksun", XK_Thai_leksun}, - {"Thai_leknung", XK_Thai_leknung}, - {"Thai_leksong", XK_Thai_leksong}, - {"Thai_leksam", XK_Thai_leksam}, - {"Thai_leksi", XK_Thai_leksi}, - {"Thai_lekha", XK_Thai_lekha}, - {"Thai_lekhok", XK_Thai_lekhok}, - {"Thai_lekchet", XK_Thai_lekchet}, - {"Thai_lekpaet", XK_Thai_lekpaet}, - {"Thai_lekkao", XK_Thai_lekkao}, -#endif /* XK_THAI */ -#ifdef XK_KOREAN - {"Hangul", XK_Hangul}, - {"Hangul_Start", XK_Hangul_Start}, - {"Hangul_End", XK_Hangul_End}, - {"Hangul_Hanja", XK_Hangul_Hanja}, - {"Hangul_Jamo", XK_Hangul_Jamo}, - {"Hangul_Romaja", XK_Hangul_Romaja}, - {"Hangul_Codeinput", XK_Hangul_Codeinput}, - {"Hangul_Jeonja", XK_Hangul_Jeonja}, - {"Hangul_Banja", XK_Hangul_Banja}, - {"Hangul_PreHanja", XK_Hangul_PreHanja}, - {"Hangul_PostHanja", XK_Hangul_PostHanja}, - {"Hangul_SingleCandidate", XK_Hangul_SingleCandidate}, - {"Hangul_MultipleCandidate", XK_Hangul_MultipleCandidate}, - {"Hangul_PreviousCandidate", XK_Hangul_PreviousCandidate}, - {"Hangul_Special", XK_Hangul_Special}, - {"Hangul_switch", XK_Hangul_switch}, - {"Hangul_Kiyeog", XK_Hangul_Kiyeog}, - {"Hangul_SsangKiyeog", XK_Hangul_SsangKiyeog}, - {"Hangul_KiyeogSios", XK_Hangul_KiyeogSios}, - {"Hangul_Nieun", XK_Hangul_Nieun}, - {"Hangul_NieunJieuj", XK_Hangul_NieunJieuj}, - {"Hangul_NieunHieuh", XK_Hangul_NieunHieuh}, - {"Hangul_Dikeud", XK_Hangul_Dikeud}, - {"Hangul_SsangDikeud", XK_Hangul_SsangDikeud}, - {"Hangul_Rieul", XK_Hangul_Rieul}, - {"Hangul_RieulKiyeog", XK_Hangul_RieulKiyeog}, - {"Hangul_RieulMieum", XK_Hangul_RieulMieum}, - {"Hangul_RieulPieub", XK_Hangul_RieulPieub}, - {"Hangul_RieulSios", XK_Hangul_RieulSios}, - {"Hangul_RieulTieut", XK_Hangul_RieulTieut}, - {"Hangul_RieulPhieuf", XK_Hangul_RieulPhieuf}, - {"Hangul_RieulHieuh", XK_Hangul_RieulHieuh}, - {"Hangul_Mieum", XK_Hangul_Mieum}, - {"Hangul_Pieub", XK_Hangul_Pieub}, - {"Hangul_SsangPieub", XK_Hangul_SsangPieub}, - {"Hangul_PieubSios", XK_Hangul_PieubSios}, - {"Hangul_Sios", XK_Hangul_Sios}, - {"Hangul_SsangSios", XK_Hangul_SsangSios}, - {"Hangul_Ieung", XK_Hangul_Ieung}, - {"Hangul_Jieuj", XK_Hangul_Jieuj}, - {"Hangul_SsangJieuj", XK_Hangul_SsangJieuj}, - {"Hangul_Cieuc", XK_Hangul_Cieuc}, - {"Hangul_Khieuq", XK_Hangul_Khieuq}, - {"Hangul_Tieut", XK_Hangul_Tieut}, - {"Hangul_Phieuf", XK_Hangul_Phieuf}, - {"Hangul_Hieuh", XK_Hangul_Hieuh}, - {"Hangul_A", XK_Hangul_A}, - {"Hangul_AE", XK_Hangul_AE}, - {"Hangul_YA", XK_Hangul_YA}, - {"Hangul_YAE", XK_Hangul_YAE}, - {"Hangul_EO", XK_Hangul_EO}, - {"Hangul_E", XK_Hangul_E}, - {"Hangul_YEO", XK_Hangul_YEO}, - {"Hangul_YE", XK_Hangul_YE}, - {"Hangul_O", XK_Hangul_O}, - {"Hangul_WA", XK_Hangul_WA}, - {"Hangul_WAE", XK_Hangul_WAE}, - {"Hangul_OE", XK_Hangul_OE}, - {"Hangul_YO", XK_Hangul_YO}, - {"Hangul_U", XK_Hangul_U}, - {"Hangul_WEO", XK_Hangul_WEO}, - {"Hangul_WE", XK_Hangul_WE}, - {"Hangul_WI", XK_Hangul_WI}, - {"Hangul_YU", XK_Hangul_YU}, - {"Hangul_EU", XK_Hangul_EU}, - {"Hangul_YI", XK_Hangul_YI}, - {"Hangul_I", XK_Hangul_I}, - {"Hangul_J_Kiyeog", XK_Hangul_J_Kiyeog}, - {"Hangul_J_SsangKiyeog", XK_Hangul_J_SsangKiyeog}, - {"Hangul_J_KiyeogSios", XK_Hangul_J_KiyeogSios}, - {"Hangul_J_Nieun", XK_Hangul_J_Nieun}, - {"Hangul_J_NieunJieuj", XK_Hangul_J_NieunJieuj}, - {"Hangul_J_NieunHieuh", XK_Hangul_J_NieunHieuh}, - {"Hangul_J_Dikeud", XK_Hangul_J_Dikeud}, - {"Hangul_J_Rieul", XK_Hangul_J_Rieul}, - {"Hangul_J_RieulKiyeog", XK_Hangul_J_RieulKiyeog}, - {"Hangul_J_RieulMieum", XK_Hangul_J_RieulMieum}, - {"Hangul_J_RieulPieub", XK_Hangul_J_RieulPieub}, - {"Hangul_J_RieulSios", XK_Hangul_J_RieulSios}, - {"Hangul_J_RieulTieut", XK_Hangul_J_RieulTieut}, - {"Hangul_J_RieulPhieuf", XK_Hangul_J_RieulPhieuf}, - {"Hangul_J_RieulHieuh", XK_Hangul_J_RieulHieuh}, - {"Hangul_J_Mieum", XK_Hangul_J_Mieum}, - {"Hangul_J_Pieub", XK_Hangul_J_Pieub}, - {"Hangul_J_PieubSios", XK_Hangul_J_PieubSios}, - {"Hangul_J_Sios", XK_Hangul_J_Sios}, - {"Hangul_J_SsangSios", XK_Hangul_J_SsangSios}, - {"Hangul_J_Ieung", XK_Hangul_J_Ieung}, - {"Hangul_J_Jieuj", XK_Hangul_J_Jieuj}, - {"Hangul_J_Cieuc", XK_Hangul_J_Cieuc}, - {"Hangul_J_Khieuq", XK_Hangul_J_Khieuq}, - {"Hangul_J_Tieut", XK_Hangul_J_Tieut}, - {"Hangul_J_Phieuf", XK_Hangul_J_Phieuf}, - {"Hangul_J_Hieuh", XK_Hangul_J_Hieuh}, - {"Hangul_RieulYeorinHieuh", XK_Hangul_RieulYeorinHieuh}, - {"Hangul_SunkyeongeumMieum", XK_Hangul_SunkyeongeumMieum}, - {"Hangul_SunkyeongeumPieub", XK_Hangul_SunkyeongeumPieub}, - {"Hangul_PanSios", XK_Hangul_PanSios}, - {"Hangul_KkogjiDalrinIeung", XK_Hangul_KkogjiDalrinIeung}, - {"Hangul_SunkyeongeumPhieuf", XK_Hangul_SunkyeongeumPhieuf}, - {"Hangul_YeorinHieuh", XK_Hangul_YeorinHieuh}, - {"Hangul_AraeA", XK_Hangul_AraeA}, - {"Hangul_AraeAE", XK_Hangul_AraeAE}, - {"Hangul_J_PanSios", XK_Hangul_J_PanSios}, - {"Hangul_J_KkogjiDalrinIeung", XK_Hangul_J_KkogjiDalrinIeung}, - {"Hangul_J_YeorinHieuh", XK_Hangul_J_YeorinHieuh}, - {"Korean_Won", XK_Korean_Won}, -#endif /* XK_KOREAN */ - {"EuroSign", XK_EuroSign}, -#endif - {"NoSymbol", NoSymbol} -}; - -KeySym -XStringToKeysym(const char *str) -{ - int i; - for (i = 0; StringToKeysym[i].keysym != NoSymbol - && strcmp(StringToKeysym[i].string, str); i++); - return StringToKeysym[i].keysym; -} - -const char * -XKeysymToString(KeySym keysym) -{ - int i; - for (i = 0; StringToKeysym[i].keysym != NoSymbol - && StringToKeysym[i].keysym != keysym; i++); - return StringToKeysym[i].string; -} - -void -XDisplayKeycodes(Display * display, int *min_keycode, int *max_keycode) -{ - /* VNC keycodes are non-existant */ - *min_keycode = 0xffff; - *max_keycode = 0; -} diff -Nru rdesktop-1.8.6/vnc/x11stubs.h rdesktop-1.9.0/vnc/x11stubs.h --- rdesktop-1.8.6/vnc/x11stubs.h 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/vnc/x11stubs.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -#ifndef NOXKEYMAP_H -#define NOXKEYMAP_H - -/* Fake a few X11 calls */ - -#define XK_MISCELLANY -#include <rfb/rfb.h> -#include <rfb/keysym.h> - -#define NoSymbol 0L -#define ShiftMask (1<<0) -#define LockMask (1<<1) -#define ControlMask (1<<2) -#define Mod1Mask (1<<3) -#define Mod2Mask (1<<4) -#define Mod3Mask (1<<5) -#define Mod4Mask (1<<6) -#define Mod5Mask (1<<7) -#define Button1 1 -#define Button2 2 -#define Button3 3 -#define Button4 4 -#define Button5 5 - -typedef int Display; -typedef int Window; -typedef rfbKeySym KeySym; - -KeySym XStringToKeysym(const char *str); -const char *XKeysymToString(KeySym keysym); -void XDisplayKeycodes(Display * display, int *min_keycode, int *max_keycode); - -#endif diff -Nru rdesktop-1.8.6/xclip.c rdesktop-1.9.0/xclip.c --- rdesktop-1.8.6/xclip.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/xclip.c 2019-06-13 12:10:15.000000000 +0000 @@ -4,6 +4,8 @@ Copyright 2003-2008 Erik Forsberg <forsberg@cendio.se> for Cendio AB Copyright (C) Matthew Chapman <matthewc.unsw.edu.au> 2003-2008 Copyright 2006-2011 Pierre Ossman <ossman@cendio.se> for Cendio AB + Copyright 2016 Alexander Zakharov <uglym8@gmail.com> + Copyright 2017 Henrik Andersson <hean01@cendio.se> for Cendio AB 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 @@ -32,15 +34,11 @@ http://msdn.microsoft.com/library/en-us/winui/winui/windowsuserinterface/dataexchange/clipboard/clipboardformats.asp */ -#ifdef HAVE_ICONV #ifdef HAVE_LANGINFO_H -#ifdef HAVE_ICONV_H #include <langinfo.h> #include <iconv.h> #define USE_UNICODE_CLIPBOARD #endif -#endif -#endif #ifdef USE_UNICODE_CLIPBOARD #define RDP_CF_TEXT CF_UNICODETEXT @@ -157,7 +155,7 @@ { uint8 *result; uint16 *inptr, *outptr; - RD_BOOL swap_endianess; + RD_BOOL swap_endianness; /* Worst case: Every char is LF */ result = xmalloc((*size * 2) + 2); @@ -168,16 +166,16 @@ outptr = (uint16 *) result; /* Check for a reversed BOM */ - swap_endianess = (*inptr == 0xfffe); + swap_endianness = (*inptr == 0xfffe); uint16 uvalue_previous = 0; /* Kept so we'll avoid translating CR-LF to CR-CR-LF */ while ((uint8 *) inptr < data + *size) { uint16 uvalue = *inptr; - if (swap_endianess) + if (swap_endianness) uvalue = ((uvalue << 8) & 0xff00) + (uvalue >> 8); if ((uvalue == 0x0a) && (uvalue_previous != 0x0d)) - *outptr++ = swap_endianess ? 0x0d00 : 0x0d; + *outptr++ = swap_endianness ? 0x0d00 : 0x0d; uvalue_previous = uvalue; *outptr++ = *inptr++; } @@ -222,8 +220,15 @@ uint32 length) { XEvent xev; + char *target_name, *property_name; - DEBUG_CLIPBOARD(("xclip_provide_selection: requestor=0x%08x, target=%s, property=%s, length=%u\n", (unsigned) req->requestor, XGetAtomName(g_display, req->target), XGetAtomName(g_display, req->property), (unsigned) length)); + target_name = XGetAtomName(g_display, req->target); + property_name = XGetAtomName(g_display, req->property); + logger(Clipboard, Debug, + "xclip_provide_selection(), requestor=0x%08x, target=%s, property=%s, length=%u", + (unsigned) req->requestor, target_name, property_name, (unsigned) length); + XFree(target_name); + XFree(property_name); XChangeProperty(g_display, req->requestor, req->property, type, format, PropModeReplace, data, length); @@ -246,10 +251,15 @@ xclip_refuse_selection(XSelectionRequestEvent * req) { XEvent xev; + char *target_name, *property_name; - DEBUG_CLIPBOARD(("xclip_refuse_selection: requestor=0x%08x, target=%s, property=%s\n", - (unsigned) req->requestor, XGetAtomName(g_display, req->target), - XGetAtomName(g_display, req->property))); + target_name = XGetAtomName(g_display, req->target); + property_name = XGetAtomName(g_display, req->property); + logger(Clipboard, Debug, + "xclip_refuse_selection(), requestor=0x%08x, target=%s, property=%s", + (unsigned) req->requestor, target_name, property_name); + XFree(target_name); + XFree(property_name); xev.xselection.type = SelectionNotify; xev.xselection.serial = 0; @@ -290,8 +300,12 @@ static RD_BOOL xclip_send_data_with_convert(uint8 * source, size_t source_size, Atom target) { - DEBUG_CLIPBOARD(("xclip_send_data_with_convert: target=%s, size=%u\n", - XGetAtomName(g_display, target), (unsigned) source_size)); + char *target_name; + + target_name = XGetAtomName(g_display, target); + logger(Clipboard, Debug, "xclip_send_data_with_convert(), target=%s, size=%u", + target_name, (unsigned) source_size); + XFree(target_name); #ifdef USE_UNICODE_CLIPBOARD if (target == format_string_atom || @@ -321,7 +335,9 @@ cd = iconv_open(WINDOWS_CODEPAGE, locale_charset); if (cd == (iconv_t) - 1) { - DEBUG_CLIPBOARD(("Locale charset %s not found in iconv. Unable to convert clipboard text.\n", locale_charset)); + logger(Clipboard, Error, + "xclip_send_data_with_convert(), convert failed, locale charset %s not found", + locale_charset); return False; } unicode_buffer_size = source_size * 4; @@ -357,7 +373,7 @@ unicode_buffer_remaining = unicode_buffer; data_remaining = (char *) source; data_size_remaining = source_size; - iconv(cd, (ICONV_CONST char **) &data_remaining, &data_size_remaining, + iconv(cd, (char **) &data_remaining, &data_size_remaining, &unicode_buffer_remaining, &unicode_buffer_size_remaining); iconv_close(cd); @@ -366,8 +382,9 @@ translated_data = utf16_lf2crlf((uint8 *) unicode_buffer, &translated_data_size); if (translated_data != NULL) { - DEBUG_CLIPBOARD(("Sending Unicode string of %d bytes\n", - translated_data_size)); + logger(Clipboard, Debug, + "xclip_send_data_with_convert(), sending unicode string of %d bytes", + translated_data_size); helper_cliprdr_send_response(translated_data, translated_data_size); xfree(translated_data); /* Not the same thing as XFree! */ } @@ -385,7 +402,8 @@ if (rdp_clipboard_request_format != RDP_CF_TEXT) return False; - DEBUG_CLIPBOARD(("Translating linebreaks before sending data\n")); + logger(Clipboard, Debug, + "xclip_send_data_with_convert(), translating linebreaks before sending data"); translated_data = lf2crlf(source, &length); if (translated_data != NULL) { @@ -430,12 +448,13 @@ if (probing_selections) { - DEBUG_CLIPBOARD(("Already probing selections. Scheduling reprobe.\n")); + logger(Clipboard, Debug, + "xclip_probe_selection(), already probing selections, scheduling reprobe"); reprobe_selections = True; return; } - DEBUG_CLIPBOARD(("Probing selections.\n")); + logger(Clipboard, Debug, "xclip_probe_selection(), probing selections"); probing_selections = True; reprobe_selections = False; @@ -481,7 +500,7 @@ return; } - DEBUG_CLIPBOARD(("No owner of any selection.\n")); + logger(Clipboard, Debug, "xclip_probe_selection(), no owner of any selection"); /* FIXME: Without XFIXES, we cannot reliably know the formats offered by an @@ -497,24 +516,29 @@ The SelectionNotify event is sent from the clipboard owner to the requestor after his request was satisfied. If this function is called, we're the requestor side. */ -#ifndef MAKE_PROTO void xclip_handle_SelectionNotify(XSelectionEvent * event) { - unsigned long nitems, bytes_left; + unsigned long i, nitems, bytes_left; XWindowAttributes wa; Atom type; Atom *supported_targets; - int res, i, format; + int res, format; uint8 *data = NULL; + char *selection_name, *target_name, *property_name; if (event->property == None) goto fail; - DEBUG_CLIPBOARD(("xclip_handle_SelectionNotify: selection=%s, target=%s, property=%s\n", - XGetAtomName(g_display, event->selection), - XGetAtomName(g_display, event->target), - XGetAtomName(g_display, event->property))); + selection_name = XGetAtomName(g_display, event->selection); + target_name = XGetAtomName(g_display, event->target); + property_name = XGetAtomName(g_display, event->property); + logger(Clipboard, Debug, + "xclip_handle_SelectionNotify(), selection=%s, target=%s, property=%s", + selection_name, target_name, property_name); + XFree(selection_name); + XFree(target_name); + XFree(property_name); if (event->target == timestamp_atom) { @@ -536,7 +560,8 @@ if ((res != Success) || (nitems != 1) || (format != 32)) { - DEBUG_CLIPBOARD(("XGetWindowProperty failed!\n")); + logger(Clipboard, Error, + "xclip_handle_SelectionNotify(), XGetWindowProperty failed"); goto fail; } @@ -546,8 +571,9 @@ if (primary_timestamp == 0) primary_timestamp++; XDeleteProperty(g_display, g_wnd, rdesktop_primary_timestamp_target_atom); - DEBUG_CLIPBOARD(("Got PRIMARY timestamp: %u\n", - (unsigned) primary_timestamp)); + logger(Clipboard, Debug, + "xclip_handle_SelectionNotify(), got PRIMARY timestamp: %u", + (unsigned) primary_timestamp); } else { @@ -555,8 +581,9 @@ if (clipboard_timestamp == 0) clipboard_timestamp++; XDeleteProperty(g_display, g_wnd, rdesktop_clipboard_timestamp_target_atom); - DEBUG_CLIPBOARD(("Got CLIPBOARD timestamp: %u\n", - (unsigned) clipboard_timestamp)); + logger(Clipboard, Debug, + "xclip_handle_SelectionNotify(), got CLIPBOARD timestamp: %u", + (unsigned) clipboard_timestamp); } XFree(data); @@ -565,14 +592,16 @@ { if (primary_timestamp > clipboard_timestamp) { - DEBUG_CLIPBOARD(("PRIMARY is most recent selection.\n")); + logger(Clipboard, Debug, + "xclip_handle_SelectionNotify(), PRIMARY is most recent selection"); XConvertSelection(g_display, primary_atom, targets_atom, rdesktop_clipboard_target_atom, g_wnd, event->time); } else { - DEBUG_CLIPBOARD(("CLIPBOARD is most recent selection.\n")); + logger(Clipboard, Debug, + "xclip_handle_SelectionNotify(), CLIPBOARD is most recent selection"); XConvertSelection(g_display, clipboard_atom, targets_atom, rdesktop_clipboard_target_atom, g_wnd, event->time); @@ -597,13 +626,14 @@ if (res != Success) { - DEBUG_CLIPBOARD(("XGetWindowProperty failed!\n")); + logger(Clipboard, Error, + "xclip_handle_SelectionNotify(), XGetWindowProperty() failed"); goto fail; } if (type == incr_atom) { - DEBUG_CLIPBOARD(("Received INCR.\n")); + logger(Clipboard, Debug, "xclip_handle_SelectionNotify(), received INCR"); XGetWindowAttributes(g_display, g_wnd, &wa); if ((wa.your_event_mask | PropertyChangeMask) != wa.your_event_mask) @@ -611,6 +641,7 @@ XSelectInput(g_display, g_wnd, (wa.your_event_mask | PropertyChangeMask)); } XFree(data); + data = NULL; g_incr_target = event->target; g_waiting_for_INCR = 1; goto end; @@ -630,13 +661,17 @@ supported_targets = (Atom *) data; for (i = 0; i < nitems; i++) { - DEBUG_CLIPBOARD(("Target %d: %s\n", i, - XGetAtomName(g_display, supported_targets[i]))); + target_name = XGetAtomName(g_display, supported_targets[i]); + logger(Clipboard, Debug, + "xclip_handle_SelectionNotify(), target %d: %s", i, + target_name); + XFree(target_name); if (supported_targets[i] == format_string_atom) { if (text_target_satisfaction < 1) { - DEBUG_CLIPBOARD(("Other party supports STRING, choosing that as best_target\n")); + logger(Clipboard, Debug, + "xclip_handle_SelectionNotify(), other party supports STRING, choosing that as best_target"); best_text_target = supported_targets[i]; text_target_satisfaction = 1; } @@ -646,7 +681,8 @@ { if (text_target_satisfaction < 2) { - DEBUG_CLIPBOARD(("Other party supports text/unicode, choosing that as best_target\n")); + logger(Clipboard, Debug, + "xclip_handle_SelectionNotify(), other party supports text/unicode, choosing that as best_target"); best_text_target = supported_targets[i]; text_target_satisfaction = 2; } @@ -655,7 +691,8 @@ { if (text_target_satisfaction < 3) { - DEBUG_CLIPBOARD(("Other party supports UTF8_STRING, choosing that as best_target\n")); + logger(Clipboard, Debug, + "xclip_handle_SelectionNotify(), other party supports UTF8_STRING, choosing that as best_target"); best_text_target = supported_targets[i]; text_target_satisfaction = 3; } @@ -665,7 +702,8 @@ { if (probing_selections && (text_target_satisfaction < 4)) { - DEBUG_CLIPBOARD(("Other party supports native formats, choosing that as best_target\n")); + logger(Clipboard, Debug, + "xclip_handle_SelectionNotify(), other party supports native formats, choosing that as best_target"); best_text_target = supported_targets[i]; text_target_satisfaction = 4; } @@ -686,7 +724,8 @@ } else { - DEBUG_CLIPBOARD(("Unable to find a textual target to satisfy RDP clipboard text request\n")); + logger(Clipboard, Error, + "xclip_handle_SelectionNotify(), unable to find a textual target to satisfy RDP clipboard text request"); goto fail; } } @@ -712,7 +751,8 @@ if (primary_owner != clipboard_owner) goto fail; - DEBUG_CLIPBOARD(("Got fellow rdesktop formats\n")); + logger(Clipboard, Debug, + "xclip_handle_SelectionNotify(), got fellow rdesktop formats"); probing_selections = False; rdesktop_is_selection_owner = True; cliprdr_send_native_format_announce(data, nitems); @@ -733,7 +773,8 @@ xclip_clear_target_props(); if (probing_selections) { - DEBUG_CLIPBOARD(("Unable to find suitable target. Using default text format.\n")); + logger(Clipboard, Debug, + "xclip_handle_SelectionNotify(), unable to find suitable target, using default text format"); probing_selections = False; rdesktop_is_selection_owner = False; @@ -761,11 +802,17 @@ unsigned char *prop_return = NULL; int format, res; Atom type; + char *selection_name, *target_name, *property_name; - DEBUG_CLIPBOARD(("xclip_handle_SelectionRequest: selection=%s, target=%s, property=%s\n", - XGetAtomName(g_display, event->selection), - XGetAtomName(g_display, event->target), - XGetAtomName(g_display, event->property))); + selection_name = XGetAtomName(g_display, event->selection); + target_name = XGetAtomName(g_display, event->target); + property_name = XGetAtomName(g_display, event->property); + logger(Clipboard, Debug, + "xclip_handle_SelectionRequest(), selection=%s, target=%s, property=%s", + selection_name, target_name, property_name); + XFree(selection_name); + XFree(target_name); + XFree(property_name); if (event->target == targets_atom) { @@ -788,7 +835,8 @@ handle one such request at a time. */ if (has_selection_request) { - DEBUG_CLIPBOARD(("Error: Another clipboard request was already sent to the RDP server and not yet responded. Refusing this request.\n")); + logger(Clipboard, Warning, + "xclip_handle_SelectionRequest(), overlapping clipboard request, skipping."); xclip_refuse_selection(event); return; } @@ -802,7 +850,8 @@ &prop_return); if (res != Success || (!prop_return)) { - DEBUG_CLIPBOARD(("Requested native format but didn't specifiy which.\n")); + logger(Clipboard, Error, + "xclip_handle_SelectionRequest(), requested native format without specify which"); xclip_refuse_selection(event); return; } @@ -820,7 +869,8 @@ #ifdef USE_UNICODE_CLIPBOARD format = CF_UNICODETEXT; #else - DEBUG_CLIPBOARD(("Requested target unavailable due to lack of Unicode support. (It was not in TARGETS, so why did you ask for it?!)\n")); + logger(Clipboard, Warning, + "xclip_handle_SelectionRequest(), target unavailable due to lack of unicode support"); xclip_refuse_selection(event); return; #endif @@ -832,7 +882,11 @@ } else { - DEBUG_CLIPBOARD(("Requested target unavailable. (It was not in TARGETS, so why did you ask for it?!)\n")); + target_name = XGetAtomName(g_display, event->target); + logger(Clipboard, Warning, + "xclip_handle_SelectionRequest(), unsupported target format, target='%s'", + target_name); + XFree(target_name); xclip_refuse_selection(event); return; } @@ -848,13 +902,13 @@ is offered by the RDP server (and when it is pasted inside RDP, there's no network roundtrip). - This event (SelectionClear) symbolizes this rdesktop lost onwership of the clipboard + This event (SelectionClear) symbolizes this rdesktop lost ownership of the clipboard to some other X client. We should find out what clipboard formats this other client offers and announce that to RDP. */ void xclip_handle_SelectionClear(void) { - DEBUG_CLIPBOARD(("xclip_handle_SelectionClear\n")); + logger(Clipboard, Debug, "xclip_handle_SelectionClear()"); xclip_notify_change(); xclip_probe_selections(); } @@ -873,11 +927,11 @@ if (event->state == PropertyNewValue && g_waiting_for_INCR) { - DEBUG_CLIPBOARD(("x_clip_handle_PropertyNotify: g_waiting_for_INCR != 0\n")); + logger(Clipboard, Debug, "xclip_handle_PropertyNotify(), g_waiting_for_INCR != 0"); while (bytes_left > 0) { - /* Unlike the specification, we don't set the 'delete' arugment to True + /* Unlike the specification, we don't set the 'delete' argument to True since we slurp the INCR's chunks in even-smaller chunks of 4096 bytes. */ if ((XGetWindowProperty (g_display, g_wnd, rdesktop_clipboard_target_atom, offset, 4096L, @@ -928,7 +982,6 @@ (event->window == DefaultRootWindow(g_display))) xclip_probe_selections(); } -#endif /* Called when the RDP server announces new clipboard data formats. @@ -943,11 +996,11 @@ XSetSelectionOwner(g_display, primary_atom, g_wnd, acquire_time); if (XGetSelectionOwner(g_display, primary_atom) != g_wnd) - warning("Failed to aquire ownership of PRIMARY clipboard\n"); + logger(Clipboard, Warning, "failed to acquire ownership of PRIMARY clipboard"); XSetSelectionOwner(g_display, clipboard_atom, g_wnd, acquire_time); if (XGetSelectionOwner(g_display, clipboard_atom) != g_wnd) - warning("Failed to aquire ownership of CLIPBOARD clipboard\n"); + logger(Clipboard, Warning, "failed to acquire ownership of CLIPBOARD clipboard"); if (formats_data) xfree(formats_data); @@ -1004,7 +1057,7 @@ iconv_close(cd); return; } - iconv(cd, (ICONV_CONST char **) &data_remaining, &length_remaining, + iconv(cd, (char **) &data_remaining, &length_remaining, &utf8_data_remaining, &utf8_length_remaining); iconv_close(cd); free_data = True; @@ -1027,7 +1080,11 @@ } else { - DEBUG_CLIPBOARD(("ui_clip_handle_data: BUG! I don't know how to convert selection target %s!\n", XGetAtomName(g_display, selection_request.target))); + char *target_name = XGetAtomName(g_display, selection_request.target); + logger(Clipboard, Debug, + "ui_clip_handle_data(), no handler for selection target '%s'", + target_name); + XFree(target_name); xclip_refuse_selection(&selection_request); has_selection_request = False; return; @@ -1052,12 +1109,13 @@ { Window primary_owner, clipboard_owner; - DEBUG_CLIPBOARD(("Request from server for format %d\n", format)); + logger(Clipboard, Debug, "request from server for format %d", format); rdp_clipboard_request_format = format; if (probing_selections) { - DEBUG_CLIPBOARD(("ui_clip_request_data: Selection probe in progress. Cannot handle request.\n")); + logger(Clipboard, Debug, + "ui_clip_request_data(), selection probe in progress, cannot handle request"); helper_cliprdr_send_empty_response(); return; } @@ -1130,7 +1188,7 @@ auto_mode = False; else { - warning("Invalid clipboard mode '%s'.\n", optarg); + logger(Clipboard, Warning, "invalid clipboard mode '%s'", optarg); g_rdpclip = False; } } diff -Nru rdesktop-1.8.6/xkeymap.c rdesktop-1.9.0/xkeymap.c --- rdesktop-1.8.6/xkeymap.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/xkeymap.c 2019-06-13 12:10:15.000000000 +0000 @@ -4,7 +4,7 @@ Copyright (C) Matthew Chapman <matthewc.unsw.edu.au> 1999-2008 Copyright 2003-2008 Peter Astrand <astrand@cendio.se> for Cendio AB - Copyright 2014 Henrik Andersson <hean01@cendio.se> for Cendio AB + Copyright 2014-2017 Henrik Andersson <hean01@cendio.se> for Cendio AB 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 @@ -20,12 +20,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifdef RDP2VNC -#include "vnc/x11stubs.h" -#else #include <X11/Xlib.h> #include <X11/keysym.h> -#endif #include <ctype.h> #include <limits.h> @@ -48,6 +44,8 @@ extern int g_keyboard_functionkeys; extern int g_win_button_size; extern RD_BOOL g_enable_compose; +extern RD_BOOL g_seamless_rdp; +extern RD_BOOL g_seamless_active; extern RDP_VERSION g_rdp_version; extern RD_BOOL g_numlock_sync; @@ -165,12 +163,13 @@ keysym = XStringToKeysym(keyname); if (keysym == NoSymbol) { - DEBUG_KBD(("Bad keysym \"%s\" in keymap %s (ignoring)\n", keyname, mapname)); + logger(Keyboard, Error, "add_to_keymap(), ignoring bad keysym '%s' in keymap %s", + keyname, mapname); return; } - DEBUG_KBD(("Adding translation, keysym=0x%x, scancode=0x%x, " - "modifiers=0x%x\n", (unsigned int) keysym, scancode, modifiers)); + logger(Keyboard, Debug, "add_to_keymap(), adding translation, keysym=0x%x, scancode=0x%x, " + "modifiers=0x%x", (unsigned int) keysym, scancode, modifiers); /* Make a new entry in the table */ entry = new_key_translation_entry(keysym); @@ -206,11 +205,13 @@ keysym = XStringToKeysym(keyname); if (keysym == NoSymbol) { - DEBUG_KBD(("Bad keysym \"%s\" in keymap %s (ignoring line)\n", keyname, mapname)); + logger(Keyboard, Error, "add_sequence(), ignoring bad keysym '%s' in keymap %s", + keyname, mapname); return; } - DEBUG_KBD(("Adding sequence for keysym (0x%lx, %s) -> ", keysym, keyname)); + logger(Keyboard, Debug, "add_sequence(), adding sequence for keysym '%s' (0x%lx)", keyname, + keysym); entry = new_key_translation_entry(keysym); prev_next = &(entry->tr); @@ -233,8 +234,9 @@ seq_keysym = XStringToKeysym(keyname); if (seq_keysym == NoSymbol) { - DEBUG_KBD(("Bad keysym \"%s\" in keymap %s (ignoring line)\n", keyname, - mapname)); + logger(Keyboard, Error, + "add_sequence(), ignoring line with bad keysym '%s' in keymap %s", + keyname, mapname); delete_key_translation_entry(keysym); return; } @@ -250,10 +252,7 @@ *prev_next = tr; prev_next = &tr->next; tr->seq_keysym = seq_keysym; - - DEBUG_KBD(("0x%x, ", (unsigned int) seq_keysym)); } - DEBUG_KBD(("\n")); } RD_BOOL @@ -387,7 +386,7 @@ fp = xkeymap_open(mapname); if (fp == NULL) { - error("Failed to open keymap %s\n", mapname); + logger(Keyboard, Error, "xkeymap_read(), failed to open keymap %s", mapname); return False; } @@ -421,14 +420,14 @@ if (str_startswith(line, "map ")) { g_keylayout = strtoul(line + sizeof("map ") - 1, NULL, 16); - DEBUG_KBD(("Keylayout 0x%x\n", g_keylayout)); + logger(Keyboard, Debug, "xkeymap_read(), Keylayout 0x%x", g_keylayout); continue; } /* compose */ if (str_startswith(line, "enable_compose")) { - DEBUG_KBD(("Enabling compose handling\n")); + logger(Keyboard, Debug, "xkeymap_read(), enabling compose handling"); g_enable_compose = True; continue; } @@ -444,7 +443,8 @@ if (str_startswith(line, "keyboard_type ")) { g_keyboard_type = strtol(line + sizeof("keyboard_type ") - 1, NULL, 16); - DEBUG_KBD(("keyboard_type 0x%x\n", g_keyboard_type)); + logger(Keyboard, Debug, "xkeymap_read(), keyboard_type 0x%x", + g_keyboard_type); continue; } @@ -453,7 +453,8 @@ { g_keyboard_subtype = strtol(line + sizeof("keyboard_subtype ") - 1, NULL, 16); - DEBUG_KBD(("keyboard_subtype 0x%x\n", g_keyboard_subtype)); + logger(Keyboard, Debug, "xkeymap_read(), keyboard_subtype 0x%x", + g_keyboard_subtype); continue; } @@ -462,7 +463,8 @@ { g_keyboard_functionkeys = strtol(line + sizeof("keyboard_functionkeys ") - 1, NULL, 16); - DEBUG_KBD(("keyboard_functionkeys 0x%x\n", g_keyboard_functionkeys)); + logger(Keyboard, Debug, "xkeymap_read(), keyboard_functionkeys 0x%x", + g_keyboard_functionkeys); continue; } @@ -477,7 +479,8 @@ p = strchr(line, ' '); if (p == NULL) { - error("Bad line %d in keymap %s\n", line_num, mapname); + logger(Keyboard, Error, "xkeymap_read(), bad line %d in keymap %s", + line_num, mapname); continue; } else @@ -643,7 +646,21 @@ { /* Ctrl-Alt-Enter: toggle full screen */ if (pressed) - xwin_toggle_fullscreen(); + { + if (!g_seamless_rdp) + { + /* only allow toggle fullscreen when not running + rdesktop in seamless mode */ + xwin_toggle_fullscreen(); + } + else + { + /* deactivate seamless mode for debug purpose, one can + not activate seamless mode again */ + if (g_seamless_active) + ui_seamless_toggle(); + } + } return True; } break; @@ -662,28 +679,22 @@ break; case XK_Pause: - /* According to MS Keyboard Scan Code - Specification, pressing Pause should result - in E1 1D 45 E1 9D C5. I'm not exactly sure - of how this is supposed to be sent via - RDP. The code below seems to work, but with - the side effect that Left Ctrl stays - down. Therefore, we release it when Pause - is released. */ + /* According to the RDP documentation (MS-RDPBCGR, page 164), + pressing Pause must result in: + CTRL (0x1D) DOWN with the KBDFLAGS_EXTENDED1 flag + NUMLOCK (0x45) DOWN + CTRL (0x1D) UP with the KBDFLAGS_EXTENDED1 flag + NUMLOCK (0x45) UP + */ if (pressed) { - rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0); - rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x1d, 0); + rdp_send_input(ev_time, RDP_INPUT_SCANCODE, + RDP_KEYPRESS | KBD_FLAG_EXT1, 0x1d, 0); rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x45, 0); - rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0); - rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x9d, 0); - rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xc5, 0); - } - else - { - /* Release Left Ctrl */ - rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYRELEASE, - 0x1d, 0); + rdp_send_input(ev_time, RDP_INPUT_SCANCODE, + RDP_KEYRELEASE | KBD_FLAG_EXT1, 0x1d, 0); + rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYRELEASE, 0x45, + 0); } return True; break; @@ -746,7 +757,7 @@ { if (MASK_HAS_BITS(tr.modifiers, MapInhibitMask)) { - DEBUG_KBD(("Inhibiting key\n")); + logger(Keyboard, Debug, "xkeymap_translate_key(), inhibiting key"); tr.scancode = 0; return tr; } @@ -771,19 +782,21 @@ && MASK_HAS_BITS(remote_modifier_state, MapCtrlMask) && !MASK_HAS_BITS(state, ShiftMask)) { - DEBUG_KBD(("Non-physical Shift + Ctrl pressed, releasing Shift\n")); + logger(Keyboard, Debug, + "xkeymap_translate_key(), non-physical Shift + Ctrl pressed, releasing Shift"); MASK_REMOVE_BITS(tr.modifiers, MapShiftMask); } - DEBUG_KBD(("Found scancode translation, scancode=0x%x, modifiers=0x%x\n", - tr.scancode, tr.modifiers)); + logger(Keyboard, Debug, + "xkeymap_translate_key(), found scancode translation, scancode=0x%x, modifiers=0x%x", + tr.scancode, tr.modifiers); } } else { if (keymap_loaded) - warning("No translation for (keysym 0x%lx, %s)\n", keysym, - get_ksname(keysym)); + logger(Keyboard, Warning, "No translation for (keysym 0x%lx, %s)", keysym, + get_ksname(keysym)); /* not in keymap, try to interpret the raw scancode */ if (((int) keycode >= min_keycode) && (keycode <= 0x60)) @@ -798,11 +811,11 @@ tr.modifiers = MapLeftShiftMask; } - DEBUG_KBD(("Sending guessed scancode 0x%x\n", tr.scancode)); + logger(Keyboard, Debug, "Sending guessed scancode 0x%x", tr.scancode); } else { - DEBUG_KBD(("No good guess for keycode 0x%x found\n", keycode)); + logger(Keyboard, Debug, "No good guess for keycode 0x%x found", keycode); } } @@ -857,12 +870,13 @@ ptr = &tr; do { - DEBUG_KBD(("Handling sequence element, keysym=0x%x\n", - (unsigned int) ptr->seq_keysym)); + logger(Keyboard, Debug, + "xkeymap_send_keys(), handling sequence element, keysym=0x%x", + (unsigned int) ptr->seq_keysym); if (nesting++ > 32) { - error("Sequence nesting too deep\n"); + logger(Keyboard, Error, "Sequence nesting too deep"); return; } @@ -875,8 +889,10 @@ } uint16 -xkeymap_translate_button(unsigned int button) +xkeymap_translate_button(unsigned int button, uint16 * input_type) { + *input_type = RDP_INPUT_MOUSE; + switch (button) { case Button1: /* left */ @@ -889,6 +905,12 @@ return MOUSE_FLAG_BUTTON4; case Button5: /* wheel down */ return MOUSE_FLAG_BUTTON5; + case 8: /* button 4 */ + *input_type = RDP_INPUT_MOUSEX; + return MOUSEX_FLAG_BUTTON1; + case 9: /* button 5 */ + *input_type = RDP_INPUT_MOUSEX; + return MOUSEX_FLAG_BUTTON2; } return 0; @@ -919,7 +941,7 @@ void restore_remote_modifiers(uint32 ev_time, uint8 scancode) { - key_translation dummy = { }; + key_translation dummy = { 0 }; if (is_modifier(scancode)) return; @@ -947,13 +969,15 @@ if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask)) { - DEBUG_KBD(("Remote NumLock state is incorrect, activating NumLock.\n")); + logger(Keyboard, Debug, + "ensure_remote_modifiers(), remote NumLock state is incorrect, activating NumLock"); new_remote_state = KBD_FLAG_NUMLOCK; remote_modifier_state = MapNumLockMask; } else { - DEBUG_KBD(("Remote NumLock state is incorrect, deactivating NumLock.\n")); + logger(Keyboard, Debug, + "ensure_remote_modifiers(), remote NumLock state is incorrect, deactivating NumLock."); new_remote_state = 0; remote_modifier_state = 0; } @@ -1014,16 +1038,12 @@ unsigned int read_keyboard_state() { -#ifdef RDP2VNC - return 0; -#else unsigned int state; Window wdummy; int dummy; XQueryPointer(g_display, g_wnd, &wdummy, &wdummy, &dummy, &dummy, &dummy, &dummy, &state); return state; -#endif } @@ -1082,11 +1102,9 @@ static void update_modifier_state(uint8 scancode, RD_BOOL pressed) { -#ifdef WITH_DEBUG_KBD uint16 old_modifier_state; old_modifier_state = remote_modifier_state; -#endif switch (scancode) { @@ -1128,15 +1146,14 @@ } } -#ifdef WITH_DEBUG_KBD if (old_modifier_state != remote_modifier_state) { - DEBUG_KBD(("Before updating modifier_state:0x%x, pressed=0x%x\n", - old_modifier_state, pressed)); - DEBUG_KBD(("After updating modifier_state:0x%x\n", remote_modifier_state)); + logger(Keyboard, Debug, + "update_modifier_state(), before modifier_state:0x%x, pressed=0x%x", + old_modifier_state, pressed); + logger(Keyboard, Debug, "update_modifier_state(), after modifier_state:0x%x", + remote_modifier_state); } -#endif - } /* Send keyboard input */ @@ -1147,14 +1164,16 @@ if (scancode & SCANCODE_EXTENDED) { - DEBUG_KBD(("Sending extended scancode=0x%x, flags=0x%x\n", - scancode & ~SCANCODE_EXTENDED, flags)); + logger(Keyboard, Debug, + "rdp_send_scancode(), sending extended scancode=0x%x, flags=0x%x", + scancode & ~SCANCODE_EXTENDED, flags); rdp_send_input(time, RDP_INPUT_SCANCODE, flags | KBD_FLAG_EXT, scancode & ~SCANCODE_EXTENDED, 0); } else { - DEBUG_KBD(("Sending scancode=0x%x, flags=0x%x\n", scancode, flags)); + logger(Keyboard, Debug, "rdp_send_scancode(), sending scancode=0x%x, flags=0x%x", + scancode, flags); rdp_send_input(time, RDP_INPUT_SCANCODE, flags, scancode, 0); } } diff -Nru rdesktop-1.8.6/xproto.h rdesktop-1.9.0/xproto.h --- rdesktop-1.8.6/xproto.h 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/xproto.h 2019-06-13 12:10:15.000000000 +0000 @@ -7,6 +7,7 @@ int ewmh_move_to_desktop(Window wnd, unsigned int desktop); int ewmh_get_window_desktop(Window wnd); void ewmh_set_wm_name(Window wnd, const char *title); +void ewmh_set_wm_pid(Window wnd, pid_t pid); int ewmh_set_window_popup(Window wnd); int ewmh_set_window_modal(Window wnd); void ewmh_set_icon(Window wnd, int width, int height, const char *rgba_data); diff -Nru rdesktop-1.8.6/xwin.c rdesktop-1.9.0/xwin.c --- rdesktop-1.8.6/xwin.c 2019-05-16 10:44:12.000000000 +0000 +++ rdesktop-1.9.0/xwin.c 2019-06-13 12:10:15.000000000 +0000 @@ -4,7 +4,8 @@ Copyright (C) Matthew Chapman <matthewc.unsw.edu.au> 1999-2008 Copyright 2007-2008 Pierre Ossman <ossman@cendio.se> for Cendio AB Copyright 2002-2011 Peter Astrand <astrand@cendio.se> for Cendio AB - Copyright 2012-2013 Henrik Andersson <hean01@cendio.se> for Cendio AB + Copyright 2012-2018 Henrik Andersson <hean01@cendio.se> for Cendio AB + Copyright 2017-2019 Alexander Zakharov <uglym8@gmail.com> 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 @@ -20,9 +21,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <X11/Xatom.h> #include <X11/Xlib.h> #include <X11/Xutil.h> #include <X11/Xproto.h> +#include <assert.h> #include <unistd.h> #include <sys/time.h> #include <time.h> @@ -30,13 +33,33 @@ #include <strings.h> #include "rdesktop.h" #include "xproto.h" +#include <X11/Xcursor/Xcursor.h> #ifdef HAVE_XRANDR #include <X11/extensions/Xrandr.h> #endif -extern int g_sizeopt; -extern int g_width; -extern int g_height; +#ifdef __APPLE__ +#include <sys/param.h> +#define HOST_NAME_MAX MAXHOSTNAMELEN +#endif + +#ifdef __sun +#include <netdb.h> +#define HOST_NAME_MAX MAXHOSTNAMELEN +#endif + +#ifdef __FreeBSD__ +#define HOST_NAME_MAX _POSIX_HOST_NAME_MAX +#endif + +extern RD_BOOL g_user_quit; +extern RD_BOOL g_exit_mainloop; + +extern window_size_type_t g_window_size_type; +extern uint32 g_requested_session_width; +extern uint32 g_requested_session_height; +extern uint16 g_session_width; +extern uint16 g_session_height; extern int g_xpos; extern int g_ypos; extern int g_pos; @@ -45,6 +68,9 @@ extern RD_BOOL g_grab_keyboard; extern RD_BOOL g_hide_decorations; extern RD_BOOL g_pending_resize; +extern RD_BOOL g_pending_resize_defer; +extern struct timeval g_pending_resize_defer_timer; + extern char g_title[]; extern char g_seamless_spawn_cmd[]; /* Color depth of the RDP session. @@ -52,12 +78,23 @@ extern int g_server_depth; extern int g_win_button_size; +/* This is a timer used to rate limit actual resizing */ +static struct timeval g_resize_timer = { 0 }; + Display *g_display; Time g_last_gesturetime; static int g_x_socket; static Screen *g_screen; Window g_wnd; +static RD_BOOL g_has_wm = False; + +RD_BOOL g_dynamic_session_resize = True; + +/* These are the last known window sizes. They are updated whenever the window size is changed. */ +static uint32 g_window_width; +static uint32 g_window_height; + /* SeamlessRDP support */ typedef struct _seamless_group { @@ -91,7 +128,7 @@ static seamless_window *g_seamless_windows = NULL; static unsigned long g_seamless_focused = 0; static RD_BOOL g_seamless_started = False; /* Server end is up and running */ -static RD_BOOL g_seamless_active = False; /* We are currently in seamless mode */ +RD_BOOL g_seamless_active = False; /* We are currently in seamless mode */ static RD_BOOL g_seamless_hidden = False; /* Desktop is hidden on server */ static RD_BOOL g_seamless_broken_restack = False; /* WM does not properly restack */ extern RD_BOOL g_seamless_rdp; @@ -124,6 +161,8 @@ static Atom g_protocol_atom, g_kill_atom; extern Atom g_net_wm_state_atom; extern Atom g_net_wm_desktop_atom; +extern Atom g_net_wm_ping_atom; + static RD_BOOL g_focused; static RD_BOOL g_mouse_in_wnd; /* Indicates that: @@ -141,7 +180,7 @@ RDP(LE) <-> host(BE) <-> X-Server(LE) ('host' is the machine running rdesktop; the host simply memcpy's - so its endianess doesn't matter) + so its endianness doesn't matter) */ static RD_BOOL g_no_translate_image = False; @@ -507,6 +546,7 @@ sg->wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, CopyFromParent, CopyFromParent, CopyFromParent, 0, &attribs); + ewmh_set_wm_pid(sg->wnd, getpid()); sg->id = id; sg->refcnt = 0; @@ -529,7 +569,8 @@ hintsatom = XInternAtom(g_display, "_MOTIF_WM_HINTS", False); if (!hintsatom) { - warning("Failed to get atom _MOTIF_WM_HINTS: probably your window manager does not support MWM hints\n"); + logger(GUI, Warning, + "Failed to get atom _MOTIF_WM_HINTS: probably your window manager does not support MWM hints\n"); return; } @@ -548,6 +589,7 @@ static Bool sw_configurenotify_p(Display * display, XEvent * xevent, XPointer arg) { + UNUSED(display); sw_configurenotify_context *context = (sw_configurenotify_context *) arg; if (xevent->xany.type == ConfigureNotify && xevent->xconfigure.window == context->window @@ -563,9 +605,9 @@ throwing away crucial events like DestroyNotify. After a ConfigureWindow, according to ICCCM section 4.1.5, we - should recieve a ConfigureNotify, either a real or synthetic + should receive a ConfigureNotify, either a real or synthetic one. This indicates that the configure has been "completed". - However, some WMs such as several versions of Metacity fails to + However, some WMs such as several versions of Metacity fail to send synthetic events. See bug http://bugzilla.gnome.org/show_bug.cgi?id=322840. We need to use a timeout to avoid a hang. Tk uses the same approach. */ @@ -598,7 +640,8 @@ if (!got) { - warning("Broken Window Manager: Timeout while waiting for ConfigureNotify\n"); + logger(GUI, Warning, + "Broken Window Manager: Timeout while waiting for ConfigureNotify\n"); } } @@ -619,7 +662,7 @@ } else if (!parent) { - warning("Internal error: sw_get_toplevel called with root window\n"); + logger(GUI, Error, "sw_get_toplevel called with root window\n"); } wnd = parent; @@ -636,7 +679,7 @@ Window dummy1, dummy2; Window *child_list; unsigned int num_children; - unsigned int i; + int i; RD_BOOL found_behind = False; RD_BOOL found_wnd = False; @@ -664,12 +707,12 @@ if (!found_wnd) { - warning("sw_window_is_behind: Unable to find window 0x%lx\n", wnd); + logger(GUI, Warning, "sw_window_is_behind: Unable to find window 0x%lx", wnd); if (!found_behind) { - warning("sw_window_is_behind: Unable to find behind window 0x%lx\n", - behind); + logger(GUI, Warning, + "sw_window_is_behind: Unable to find behind window 0x%lx", behind); } } @@ -745,7 +788,7 @@ if (!sw_window_is_behind(wnds[0], wnds[1]) || !sw_window_is_behind(wnds[2], wnds[1])) { /* Ok, technically a WM is allowed to stack windows arbitrarily, but... */ - warning("Broken Window Manager: Unable to test window restacking\n"); + logger(GUI, Warning, "Broken Window Manager: Unable to test window restacking"); g_seamless_broken_restack = True; for (i = 0; i < 3; i++) XDestroyWindow(g_display, wnds[i]); @@ -765,12 +808,14 @@ bottom */ if (!sw_window_is_behind(wnds[1], wnds[0])) { - warning("Broken Window Manager: doesn't handle restack (restack request was ignored)\n"); + logger(GUI, Warning, + "Broken Window Manager: doesn't handle restack (restack request was ignored)"); g_seamless_broken_restack = True; } else if (sw_window_is_behind(wnds[1], wnds[2])) { - warning("Broken Window Manager: doesn't handle restack (window was moved to bottom)\n"); + logger(GUI, Warning, + "Broken Window Manager: doesn't handle restack (window was moved to bottom)"); g_seamless_broken_restack = True; } @@ -857,7 +902,7 @@ /* *INDENT-OFF* */ /* repeat and unroll, similar to bitmap.c */ -/* potentialy any of the following translate */ +/* potentially any of the following translate */ /* functions can use repeat but just doing */ /* the most common ones */ @@ -1537,9 +1582,12 @@ xwin_refresh_pointer_map(void) { unsigned char phys_to_log_map[sizeof(g_pointer_log_to_phys_map)]; - int i, pointer_buttons; + int i; + unsigned int pointer_buttons; - pointer_buttons = XGetPointerMapping(g_display, phys_to_log_map, sizeof(phys_to_log_map)); + pointer_buttons = + (unsigned int) XGetPointerMapping(g_display, phys_to_log_map, + sizeof(phys_to_log_map)); if (pointer_buttons > sizeof(phys_to_log_map)) pointer_buttons = sizeof(phys_to_log_map); @@ -1623,7 +1671,7 @@ pfm = XListPixmapFormats(g_display, &pixmap_formats_count); if (pfm == NULL) { - error("Unable to get list of pixmap formats from display.\n"); + logger(GUI, Error, "Unable to get list of pixmap formats from display"); XCloseDisplay(g_display); return False; } @@ -1745,7 +1793,8 @@ &template, &visuals_count); if (vmatches == NULL) { - error("No usable TrueColor or PseudoColor visuals on this display.\n"); + logger(GUI, Error, + "No usable TrueColor or PseudoColor visuals on this display"); XCloseDisplay(g_display); XFree(pfm); return False; @@ -1834,6 +1883,84 @@ return g_old_error_handler(dpy, eev); } +static void +set_wm_client_machine(Display * dpy, Window win) +{ + XTextProperty tp; + char hostname[HOST_NAME_MAX]; + + if (gethostname(hostname, sizeof(hostname)) != 0) + return; + + tp.value = (unsigned char *) hostname; + tp.nitems = strlen(hostname); + tp.encoding = XA_STRING; + tp.format = 8; + + XSetWMClientMachine(dpy, win, &tp); +} + +RD_BOOL is_wm_active(void) +{ + Atom prop, actual_type; + int actual_fmt; + unsigned long nitems, bytes_left; + unsigned char *data; + Window wid; + + prop = XInternAtom(g_display, "_NET_SUPPORTING_WM_CHECK", True); + + if (prop == None) return False; + + if (XGetWindowProperty(g_display, DefaultRootWindow(g_display), prop, 0, 1, False, + XA_WINDOW, &actual_type, &actual_fmt, &nitems, &bytes_left, &data) != Success) { + return False; + } + + if (!nitems) { + XFree(data); + return False; + } + + wid = ((Window *)data)[0]; + XFree(data); + + if (XGetWindowProperty(g_display, wid, prop, 0, 1, False, + XA_WINDOW, &actual_type, &actual_fmt, &nitems, &bytes_left, &data) != Success) { + return False; + } + + if (!nitems) { + XFree(data); + return False; + } + + if (wid != ((Window *)data)[0]) { + XFree(data); + return False; + } + + XFree(data); + + /* Just for the curious minds */ + prop = XInternAtom(g_display, "_NET_WM_NAME", True); + + if (prop == None) return False; + + + if (XGetWindowProperty(g_display, wid, prop, 0, 1, False, + AnyPropertyType, &actual_type, &actual_fmt, &nitems, &bytes_left, &data) == Success) { + if (nitems) { + logger(GUI, Verbose, "%s(): WM name: %s", __func__, data); + } + + XFree(data); + } + + return True; +} + + /* Initialize the UI. This is done once per process. */ RD_BOOL ui_init(void) @@ -1843,13 +1970,13 @@ g_display = XOpenDisplay(NULL); if (g_display == NULL) { - error("Failed to open display: %s\n", XDisplayName(NULL)); + logger(GUI, Error, "ui_init(), failed to open X11 display: %s", XDisplayName(NULL)); return False; } { - uint16 endianess_test = 1; - g_host_be = !(RD_BOOL) (*(uint8 *) (&endianess_test)); + uint16 endianness_test = 1; + g_host_be = !(RD_BOOL) (*(uint8 *) (&endianness_test)); } g_old_error_handler = XSetErrorHandler(error_handler); @@ -1864,17 +1991,20 @@ if (g_no_translate_image) { - DEBUG(("Performance optimization possible: avoiding image translation (colour depth conversion).\n")); + logger(GUI, Debug, + "Performance optimization possible: avoiding image translation (colour depth conversion)"); } if (g_server_depth > g_bpp) { - warning("Remote desktop colour depth %d higher than display colour depth %d.\n", - g_server_depth, g_bpp); + logger(GUI, Warning, + "Remote desktop colour depth %d higher than display colour depth %d", + g_server_depth, g_bpp); } - DEBUG(("RDP depth: %d, display depth: %d, display bpp: %d, X server BE: %d, host BE: %d\n", - g_server_depth, g_depth, g_bpp, g_xserver_be, g_host_be)); + logger(GUI, Debug, + "RDP depth: %d, display depth: %d, display bpp: %d, X server BE: %d, host BE: %d\n", + g_server_depth, g_depth, g_bpp, g_xserver_be, g_host_be); if (!g_owncolmap) { @@ -1882,12 +2012,14 @@ XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual, AllocNone); if (g_depth <= 8) - warning("Display colour depth is %d bit: you may want to use -C for a private colourmap.\n", g_depth); + logger(GUI, Warning, + "Display colour depth is %d bit: you may want to use -C for a private colourmap", + g_depth); } if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always)) { - warning("External BackingStore not available. Using internal.\n"); + logger(GUI, Warning, "External BackingStore not available. Using internal"); g_ownbackstore = True; } @@ -1906,55 +2038,43 @@ seamless_init(); } - DEBUG_RDP5(("server bpp %d client bpp %d depth %d\n", g_server_depth, g_bpp, g_depth)); + g_has_wm = is_wm_active(); return True; } +void +ui_get_screen_size(uint32 * width, uint32 * height) +{ + *width = WidthOfScreen(g_screen); + *height = HeightOfScreen(g_screen); +} -/* - Initialize connection specific data, such as session size. - */ void -ui_init_connection(void) +ui_get_screen_size_from_percentage(uint32 pw, uint32 ph, uint32 * width, uint32 * height) { - /* - * Determine desktop size - */ - if (g_fullscreen) + uint32 sw, sh; + ui_get_screen_size(&sw, &sh); + *width = sw * pw / 100; + *height = sh * ph / 100; +} + +void +ui_get_workarea_size(uint32 * width, uint32 * height) +{ + uint32 x, y, w, h; + if (get_current_workarea(&x, &y, &w, &h) == 0) { - g_width = WidthOfScreen(g_screen); - g_height = HeightOfScreen(g_screen); + *width = w; + *height = h; g_using_full_workarea = True; } - else if (g_sizeopt < 0) + else { - /* Percent of screen */ - if (-g_sizeopt >= 100) - g_using_full_workarea = True; - g_height = HeightOfScreen(g_screen) * (-g_sizeopt) / 100; - g_width = WidthOfScreen(g_screen) * (-g_sizeopt) / 100; - } - else if (g_sizeopt == 1) - { - /* Fetch geometry from _NET_WORKAREA */ - uint32 x, y, cx, cy; - if (get_current_workarea(&x, &y, &cx, &cy) == 0) - { - g_width = cx; - g_height = cy; - g_using_full_workarea = True; - } - else - { - warning("Failed to get workarea: probably your window manager does not support extended hints\n"); - g_width = WidthOfScreen(g_screen); - g_height = HeightOfScreen(g_screen); - } + logger(GUI, Warning, + "Failed to get workarea: probably your window manager does not support extended hints, using full screensize as fallback\n"); + ui_get_screen_size(width, height); } - - /* make sure width is a multiple of 4 */ - g_width = (g_width + 3) & ~3; } @@ -1967,7 +2087,7 @@ XCloseIM(g_IM); if (g_null_cursor != NULL) - ui_destroy_cursor(g_null_cursor); + XFreeCursor(g_display, (Cursor) g_null_cursor); XFreeModifiermap(g_mod_map); @@ -1977,14 +2097,30 @@ } -static void +static unsigned long get_window_attribs(XSetWindowAttributes * attribs) { + unsigned long vmask = 0; + + vmask = CWBackPixel | CWBorderPixel | CWBackingStore | CWOverrideRedirect | CWColormap; + attribs->background_pixel = BlackPixelOfScreen(g_screen); attribs->border_pixel = WhitePixelOfScreen(g_screen); attribs->backing_store = g_ownbackstore ? NotUseful : Always; - attribs->override_redirect = g_fullscreen; + if (g_has_wm) { + attribs->override_redirect = 0; + } else { + attribs->override_redirect = g_fullscreen; + } attribs->colormap = g_xcolmap; + + return vmask; +} + +static unsigned long +get_window_attribs_seamless(XSetWindowAttributes * attribs) +{ + return (get_window_attribs(attribs) & ~CWOverrideRedirect); } static void @@ -2003,8 +2139,58 @@ *input_mask |= LeaveWindowMask; } +static void +get_sizehints(XSizeHints * sizehints, uint32 width, uint32 height) +{ + if (sizehints == NULL) + return; + + /* user specified position, this is needed to override the choice of + window position by window manager when a window is mapped. */ + sizehints->flags = USPosition; + + /* set minimal size of rdesktop main window */ + sizehints->flags |= PMinSize; + sizehints->min_width = 200; + sizehints->min_height = 200; + + /* resize increment */ + sizehints->flags |= PResizeInc; + sizehints->width_inc = 2; /* session width must be divisible by two */ + sizehints->height_inc = 1; + + if (g_seamless_rdp || !g_dynamic_session_resize) + { + /* disable dynamic session resize based on window size for + rdesktop main window when seamless is enabled */ + sizehints->flags |= PMaxSize; + sizehints->min_width = sizehints->max_width = width; + sizehints->min_height = sizehints->max_height = height; + } +} + +void +ui_update_window_sizehints(uint32 width, uint32 height) +{ + XSizeHints *sizehints; + sizehints = XAllocSizeHints(); + if (sizehints) + { + get_sizehints(sizehints, width, height); + XSetWMNormalHints(g_display, g_wnd, sizehints); + XFree(sizehints); + } +} + +void request_wm_fullscreen(Display *dpy, Window win) +{ + Atom atom = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False); + XChangeProperty(dpy, win, XInternAtom(dpy, "_NET_WM_STATE", False), XA_ATOM, 32, PropModeReplace, (unsigned char *)&atom, 1); + XFlush(dpy); +} + RD_BOOL -ui_create_window(void) +ui_create_window(uint32 width, uint32 height) { uint8 null_pointer_mask[1] = { 0x80 }; uint8 null_pointer_data[24] = { 0x00 }; @@ -2012,25 +2198,29 @@ XSetWindowAttributes attribs; XClassHint *classhints; XSizeHints *sizehints; - int wndwidth, wndheight; + unsigned long value_mask; long input_mask, ic_input_mask; XEvent xevent; - wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width; - wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height; + /* reset stored window sizes */ + g_window_width = 0; + g_window_height = 0; + + logger(GUI, Debug, "ui_create_window() width = %d, height = %d", width, height); /* Handle -x-y portion of geometry string */ if (g_xpos < 0 || (g_xpos == 0 && (g_pos & 2))) - g_xpos = WidthOfScreen(g_screen) + g_xpos - g_width; + g_xpos = WidthOfScreen(g_screen) + g_xpos - width; if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4))) - g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height; + g_ypos = HeightOfScreen(g_screen) + g_ypos - height; - get_window_attribs(&attribs); + value_mask = get_window_attribs(&attribs); - g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), g_xpos, g_ypos, wndwidth, - wndheight, 0, g_depth, InputOutput, g_visual, - CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap | - CWBorderPixel, &attribs); + g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), g_xpos, g_ypos, width, + height, 0, g_depth, InputOutput, g_visual, value_mask, &attribs); + + ewmh_set_wm_pid(g_wnd, getpid()); + set_wm_client_machine(g_display, g_wnd); if (g_gc == NULL) { @@ -2043,11 +2233,11 @@ if ((g_ownbackstore) && (g_backstore == 0)) { - g_backstore = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth); + g_backstore = XCreatePixmap(g_display, g_wnd, width, height, g_depth); /* clear to prevent rubbish being exposed at startup */ XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen)); - XFillRectangle(g_display, g_backstore, g_gc, 0, 0, g_width, g_height); + XFillRectangle(g_display, g_backstore, g_gc, 0, 0, width, height); } XStoreName(g_display, g_wnd, g_title); @@ -2067,11 +2257,7 @@ sizehints = XAllocSizeHints(); if (sizehints) { - sizehints->flags = PMinSize | PMaxSize; - if (g_pos) - sizehints->flags |= PPosition; - sizehints->min_width = sizehints->max_width = g_width; - sizehints->min_height = sizehints->max_height = g_height; + get_sizehints(sizehints, width, height); XSetWMNormalHints(g_display, g_wnd, sizehints); XFree(sizehints); } @@ -2097,6 +2283,9 @@ #ifdef HAVE_XRANDR XSelectInput(g_display, RootWindowOfScreen(g_screen), StructureNotifyMask); #endif + if (g_fullscreen && g_has_wm) { + request_wm_fullscreen(g_display, g_wnd); + } XMapWindow(g_display, g_wnd); /* wait for VisibilityNotify */ @@ -2113,7 +2302,13 @@ /* handle the WM_DELETE_WINDOW protocol */ g_protocol_atom = XInternAtom(g_display, "WM_PROTOCOLS", True); g_kill_atom = XInternAtom(g_display, "WM_DELETE_WINDOW", True); - XSetWMProtocols(g_display, g_wnd, &g_kill_atom, 1); + + Atom supported[] = { + g_net_wm_ping_atom, + g_kill_atom + }; + + XSetWMProtocols(g_display, g_wnd, supported, 2); /* create invisible 1x1 cursor to be used as null cursor */ if (g_null_cursor == NULL) @@ -2130,36 +2325,49 @@ } void -ui_resize_window() +ui_resize_window(uint32 width, uint32 height) { + XWindowAttributes attr; XSizeHints *sizehints; Pixmap bs; + XGetWindowAttributes(g_display, g_wnd, &attr); + + if ((attr.width == (int) width && attr.height == (int) height)) + { + /* no-op */ + return; + } + + logger(GUI, Debug, + "ui_resize_window(), Changing window %dx%d to match new session %dx%d size", + attr.width, attr.height, width, height); + sizehints = XAllocSizeHints(); if (sizehints) { - sizehints->flags = PMinSize | PMaxSize; - sizehints->min_width = sizehints->max_width = g_width; - sizehints->min_height = sizehints->max_height = g_height; + get_sizehints(sizehints, width, height); XSetWMNormalHints(g_display, g_wnd, sizehints); XFree(sizehints); } - if (!(g_fullscreen || g_embed_wnd)) + if (!g_embed_wnd) { - XResizeWindow(g_display, g_wnd, g_width, g_height); + XResizeWindow(g_display, g_wnd, width, height); } /* create new backstore pixmap */ if (g_backstore != 0) { - bs = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth); + bs = XCreatePixmap(g_display, g_wnd, width, height, g_depth); XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen)); - XFillRectangle(g_display, bs, g_gc, 0, 0, g_width, g_height); - XCopyArea(g_display, g_backstore, bs, g_gc, 0, 0, g_width, g_height, 0, 0); + XFillRectangle(g_display, bs, g_gc, 0, 0, width, height); + XCopyArea(g_display, g_backstore, bs, g_gc, 0, 0, width, height, 0, 0); XFreePixmap(g_display, g_backstore); g_backstore = bs; } + + ui_set_clip(0, 0, width, height); } RD_BOOL @@ -2187,28 +2395,109 @@ void xwin_toggle_fullscreen(void) { + uint32 x, y, width, height; + XWindowAttributes attr; Pixmap contents = 0; + Window unused; + int dest_x, dest_y; + static uint32 windowed_x = 0; + static uint32 windowed_y = 0; + static uint32 windowed_height = 0; + static uint32 windowed_width = 0; - if (g_seamless_active) - /* Turn off SeamlessRDP mode */ - ui_seamless_toggle(); + /* When running rdesktop in seamless mode, toggling of fullscreen is not allowed */ + if (g_seamless_rdp) + return; + + /* get current window size and store it to be used when switching back + * from fullscreen mode. + */ + XGetWindowAttributes(g_display, g_wnd, &attr); + + if (!g_fullscreen || (windowed_width == 0 || windowed_height == 0)) + { + /* only stored if we toggle from windowed -> fullscreen or when + * going from fullscreen -> windowed when started in fullscreen mode. + */ + + XTranslateCoordinates(g_display, g_wnd, + DefaultRootWindow(g_display), + 0, 0, &dest_x, &dest_y, &unused); + + windowed_x = dest_x; + windowed_y = dest_y; + windowed_width = attr.width; + windowed_height = attr.height; + } if (!g_ownbackstore) { - /* need to save contents of window */ - contents = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth); - XCopyArea(g_display, g_wnd, contents, g_gc, 0, 0, g_width, g_height, 0, 0); + /* need to save contents of current window */ + contents = XCreatePixmap(g_display, g_wnd, attr.width, attr.height, g_depth); + XCopyArea(g_display, g_wnd, contents, g_gc, 0, 0, attr.width, attr.height, 0, 0); } - ui_destroy_window(); g_fullscreen = !g_fullscreen; - ui_create_window(); + + + /* What size should the new window have? */ + if (g_fullscreen) + { + /* Since we need to create a fullscreen window we need to know screen size */ + x = 0; + y = 0; + width = WidthOfScreen(g_screen); + height = HeightOfScreen(g_screen); + } + else + { + /* Switch from fullscreen to window mode */ + x = windowed_x; + y = windowed_y; + + if (g_dynamic_session_resize) + { + /* Restore "old" window size, resize session to fit */ + width = windowed_width; + height = windowed_height; + } + else + { + /* Resize window to fit session size */ + width = g_session_width; + height = g_session_height; + } + } + + logger(GUI, Debug, "xwin_toggle_fullscreen(), new window: %dx%d+%d+%d, last window: %dx%d", + width, height, x, y, windowed_width, windowed_height); + + /* Re-create the rdesktop window using new size and window + attributes. */ + g_xpos = x; + g_ypos = y; + ui_destroy_window(); + ui_create_window(width, height); + + /* If the window manager overrides our window size request, we trust + the normal window resize mechanism to take care of resizing the + session. When window is configured as override-redirect + (i.e. fullscreen), this disables the normal window resize + mechanism. In that case, we have to take care of the resize + ourselves setting g_pending_resize. */ + if (g_fullscreen) + { + g_pending_resize = True; + g_window_width = width; + g_window_height = height; + } XDefineCursor(g_display, g_wnd, g_current_cursor); if (!g_ownbackstore) { - XCopyArea(g_display, contents, g_wnd, g_gc, 0, 0, g_width, g_height, 0, 0); + /* copy back saved contents into new window */ + XCopyArea(g_display, contents, g_wnd, g_gc, 0, 0, attr.width, attr.height, 0, 0); XFreePixmap(g_display, contents); } } @@ -2216,7 +2505,11 @@ static void handle_button_event(XEvent xevent, RD_BOOL down) { - uint16 button, flags = 0; + XWindowAttributes attr; + uint16 button, input_type, flags = 0; + + XGetWindowAttributes(g_display, g_wnd, &attr); + g_last_gesturetime = xevent.xbutton.time; /* Reverse the pointer button mapping, e.g. in the case of "left-handed mouse mode"; the RDP session expects to @@ -2224,7 +2517,7 @@ logical button behavior depends on the remote desktop's own mouse settings */ xevent.xbutton.button = g_pointer_log_to_phys_map[xevent.xbutton.button - 1]; - button = xkeymap_translate_button(xevent.xbutton.button); + button = xkeymap_translate_button(xevent.xbutton.button, &input_type); if (button == 0) return; @@ -2239,12 +2532,12 @@ if (xevent.xbutton.y < g_win_button_size) { /* Check from right to left: */ - if (xevent.xbutton.x >= g_width - g_win_button_size) + if (xevent.xbutton.x >= attr.width - g_win_button_size) { /* The close button, continue */ ; } - else if (xevent.xbutton.x >= g_width - g_win_button_size * 2) + else if (xevent.xbutton.x >= attr.width - g_win_button_size * 2) { /* The maximize/restore button. Do not send to server. It might be a good idea to change the @@ -2253,14 +2546,14 @@ if (xevent.type == ButtonPress) return; } - else if (xevent.xbutton.x >= g_width - g_win_button_size * 3) + else if (xevent.xbutton.x >= attr.width - g_win_button_size * 3) { /* The minimize button. Iconify window. */ if (xevent.type == ButtonRelease) { /* Release the mouse button outside the minimize button, to prevent the - actual minimazation to happen */ - rdp_send_input(time(NULL), RDP_INPUT_MOUSE, button, 1, 1); + actual minimization to happen */ + rdp_send_input(time(NULL), input_type, button, 1, 1); XIconifyWindow(g_display, g_wnd, DefaultScreen(g_display)); return; } @@ -2297,18 +2590,17 @@ if (xevent.xmotion.window == g_wnd) { - rdp_send_input(time(NULL), RDP_INPUT_MOUSE, + rdp_send_input(time(NULL), input_type, flags | button, xevent.xbutton.x, xevent.xbutton.y); } else { /* SeamlessRDP */ - rdp_send_input(time(NULL), RDP_INPUT_MOUSE, + rdp_send_input(time(NULL), input_type, flags | button, xevent.xbutton.x_root, xevent.xbutton.y_root); } } - /* Process events in Xlib queue Returns 0 after user quit, 1 otherwise */ static int @@ -2321,6 +2613,7 @@ Status status; int events = 0; seamless_window *sw; + static RD_BOOL is_g_wnd_mapped = False; while ((XPending(g_display) > 0) && events++ < 20) { @@ -2337,7 +2630,7 @@ if ((g_IC != NULL) && (XFilterEvent(&xevent, None) == True)) { - DEBUG_KBD(("Filtering event\n")); + logger(GUI, Debug, "xwin_process_events(), filtering event"); continue; } @@ -2350,18 +2643,32 @@ break; case ClientMessage: - /* the window manager told us to quit */ - if ((xevent.xclient.message_type == g_protocol_atom) - && ((Atom) xevent.xclient.data.l[0] == g_kill_atom)) + if (xevent.xclient.message_type == g_protocol_atom) { - /* When killing a seamless window, close the window on the - serverside instead of terminating rdesktop */ - sw = sw_get_window_by_wnd(xevent.xclient.window); - if (!sw) - /* Otherwise, quit */ - return 0; - /* send seamless destroy process message */ - seamless_send_destroy(sw->id); + if (xevent.xclient.data.l[0] == (long) g_kill_atom) + { + /* the window manager told us to quit */ + + /* When killing a seamless window, close the window on the + serverside instead of terminating rdesktop */ + sw = sw_get_window_by_wnd(xevent.xclient.window); + if (!sw) + /* Otherwise, quit */ + return 0; + /* send seamless destroy process message */ + seamless_send_destroy(sw->id); + } + else if (xevent.xclient.data.l[0] == + (long) g_net_wm_ping_atom) + { + /* pass ping message further to root window */ + xevent.xclient.window = + RootWindowOfScreen(g_screen); + XSendEvent(g_display, xevent.xclient.window, False, + SubstructureRedirectMask | + SubstructureNotifyMask, &xevent); + break; + } } break; @@ -2375,21 +2682,23 @@ &status); if (!((status == XLookupKeySym) || (status == XLookupBoth))) { - error("XmbLookupString failed with status 0x%x\n", - status); + logger(GUI, Error, + "XmbLookupString failed with status 0x%x\n", + status); break; } } else { /* Plain old XLookupString */ - DEBUG_KBD(("\nNo input context, using XLookupString\n")); - XLookupString((XKeyEvent *) & xevent, - str, sizeof(str), &keysym, NULL); + logger(Keyboard, Debug, + "No input context, using fallback XLookupString"); + XLookupString((XKeyEvent *) & xevent, str, sizeof(str), + &keysym, NULL); } - DEBUG_KBD(("KeyPress for keysym (0x%lx, %s)\n", keysym, - get_ksname(keysym))); + logger(Keyboard, Debug, "KeyPress for keysym (0x%lx, %s)", keysym, + get_ksname(keysym)); set_keypress_keysym(xevent.xkey.keycode, keysym); ev_time = time(NULL); @@ -2405,8 +2714,8 @@ XLookupString((XKeyEvent *) & xevent, str, sizeof(str), &keysym, NULL); - DEBUG_KBD(("\nKeyRelease for keysym (0x%lx, %s)\n", keysym, - get_ksname(keysym))); + logger(Keyboard, Debug, "KeyRelease for keysym (0x%lx, %s)", keysym, + get_ksname(keysym)); keysym = reset_keypress_keysym(xevent.xkey.keycode, keysym); ev_time = time(NULL); @@ -2599,28 +2908,111 @@ break; case MapNotify: + if (xevent.xconfigure.window == g_wnd) + { + XWindowAttributes attr; + XGetWindowAttributes(g_display, g_wnd, &attr); + g_window_width = attr.width; + g_window_height = attr.height; + + logger(GUI, Debug, + "xwin_process_events(), Window mapped with size %dx%d", + g_window_width, g_window_height); + + is_g_wnd_mapped = True; + } + if (!g_seamless_active) - rdp_send_client_window_status(1); + { + rdp_send_suppress_output_pdu(ALLOW_DISPLAY_UPDATES); + } break; case UnmapNotify: + if (xevent.xconfigure.window == g_wnd) + { + is_g_wnd_mapped = False; + } + if (!g_seamless_active) - rdp_send_client_window_status(0); + { + rdp_send_suppress_output_pdu(SUPPRESS_DISPLAY_UPDATES); + } break; case ConfigureNotify: #ifdef HAVE_XRANDR - if ((g_sizeopt || g_fullscreen) - && xevent.xconfigure.window == DefaultRootWindow(g_display)) + /* Resize on root window size change */ + if (xevent.xconfigure.window == DefaultRootWindow(g_display)) { - if (xevent.xconfigure.width != WidthOfScreen(g_screen) - || xevent.xconfigure.height != HeightOfScreen(g_screen)) + /* only for fullscreen or x%-of-screen-sized windows */ + if (g_window_size_type == PercentageOfScreen + || g_window_size_type == Fullscreen || g_fullscreen) { - XRRUpdateConfiguration(&xevent); - XSync(g_display, False); - g_pending_resize = True; + if (xevent.xconfigure.width != + WidthOfScreen(g_screen) + || xevent.xconfigure.height != + HeightOfScreen(g_screen)) + { + + logger(GUI, Debug, + "xwin_process_events(), ConfigureNotify: Root window changed to %dx%d", + xevent.xconfigure.width, + xevent.xconfigure.height); + + gettimeofday(&g_resize_timer, NULL); + + /* Resize fullscreen window to match root window size */ + /* TODO: Handle percentage of screen */ + if (g_fullscreen) + ui_resize_window(xevent.xconfigure. + width, + xevent.xconfigure. + height); + g_pending_resize = True; + } } + XRRUpdateConfiguration(&xevent); + XSync(g_display, False); + } + else #endif + if (xevent.xconfigure.window == g_wnd && !g_seamless_rdp + && is_g_wnd_mapped) + { + + /* Update window size */ + g_window_width = xevent.xconfigure.width; + g_window_height = xevent.xconfigure.height; + + uint32 w, h; + w = g_window_width; + h = g_window_height; + + utils_apply_session_size_limitations(&w, &h); + + logger(GUI, Debug, + "xwin_process_events(), ConfigureNotify: session: %dx%d, new window: %dx%d (adj: %dx%d)", + g_session_width, g_session_height, g_window_width, + g_window_height, w, h); + + if (g_session_width != w || g_session_height != h) + { + logger(GUI, Debug, + "xwin_process_events(), ConfigureNotify: session: %dx%d, new window: %dx%d", + g_session_width, g_session_height, + g_window_width, g_window_height); + + /* perform a resize */ + gettimeofday(&g_resize_timer, NULL); + g_pending_resize = True; + } + else + { + g_pending_resize = False; + } + } + if (!g_seamless_active) break; @@ -2649,75 +3041,250 @@ return 1; } -/* Returns 0 after user quit, 1 otherwise */ -int -ui_select(int rdp_socket) +static inline uint32 +time_difference_in_ms(struct timeval then, struct timeval now) +{ + uint32 ms; + ms = 0; + ms += (now.tv_sec - then.tv_sec) * 1000; + ms += (now.tv_usec - then.tv_usec) / 1000; + return ms; +} + +time_t g_wait_for_deactivate_ts = 0; + +static RD_BOOL +process_fds(int rdp_socket, int ms) { - int n; + int n, ret; fd_set rfds, wfds; struct timeval tv; RD_BOOL s_timeout = False; - while (True) - { - n = (rdp_socket > g_x_socket) ? rdp_socket : g_x_socket; - /* Process any events already waiting */ - if (!xwin_process_events()) - /* User quit */ - return 0; + n = (rdp_socket > g_x_socket) ? rdp_socket : g_x_socket; - if (g_seamless_active) - sw_check_timers(); - - FD_ZERO(&rfds); - FD_ZERO(&wfds); - FD_SET(rdp_socket, &rfds); - FD_SET(g_x_socket, &rfds); - - /* default timeout */ - tv.tv_sec = 60; - tv.tv_usec = 0; + FD_ZERO(&rfds); + FD_ZERO(&wfds); + FD_SET(rdp_socket, &rfds); + FD_SET(g_x_socket, &rfds); + + /* default timeout */ + tv.tv_sec = ms / 1000; + tv.tv_usec = (ms - (tv.tv_sec * 1000)) * 1000; #ifdef WITH_RDPSND - rdpsnd_add_fds(&n, &rfds, &wfds, &tv); + rdpsnd_add_fds(&n, &rfds, &wfds, &tv); #endif - /* add redirection handles */ - rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout); - seamless_select_timeout(&tv); + /* add redirection handles */ + rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout); + seamless_select_timeout(&tv); - /* add ctrl slaves handles */ - ctrl_add_fds(&n, &rfds); + /* add ctrl slaves handles */ + ctrl_add_fds(&n, &rfds); - n++; + n++; - switch (select(n, &rfds, &wfds, NULL, &tv)) + ret = select(n, &rfds, &wfds, NULL, &tv); + if (ret <= 0) + { + if (ret == -1) { - case -1: - error("select: %s\n", strerror(errno)); - - case 0: + logger(GUI, Error, "process_fds(), select failed: %s", strerror(errno)); + } #ifdef WITH_RDPSND - rdpsnd_check_fds(&rfds, &wfds); + rdpsnd_check_fds(&rfds, &wfds); #endif - /* Abort serial read calls */ - if (s_timeout) - rdpdr_check_fds(&rfds, &wfds, (RD_BOOL) True); - continue; - } + /* Abort serial read calls */ + if (s_timeout) + rdpdr_check_fds(&rfds, &wfds, (RD_BOOL) True); + return False; + } #ifdef WITH_RDPSND - rdpsnd_check_fds(&rfds, &wfds); + rdpsnd_check_fds(&rfds, &wfds); #endif - rdpdr_check_fds(&rfds, &wfds, (RD_BOOL) False); + rdpdr_check_fds(&rfds, &wfds, (RD_BOOL) False); + + ctrl_check_fds(&rfds, &wfds); + + if (FD_ISSET(rdp_socket, &rfds)) + return True; + + return False; +} + +static RD_BOOL +timeval_is_set(struct timeval *time) +{ + return (time->tv_sec == 0 && time->tv_usec == 0) ? False : True; +} + +/* Handle a pending resize. Resize is handled by either a disconnect/reconnect + sequence or online using RDPEDISP messages. Windows 2008 requires the use of + disconnect/reconnect and to do that without user login credentials the + auto-reconnect cookie is used. Windows 2008 seems sensitive to disconnects + to early in the login sequence so we defer to resize until we get the cookie. + + Windows 2016 on the other hand does not seem to send cookies but uses + RDPEDISP so in this case we defer until the RDPEDISP channel is established. + */ +static RD_BOOL +process_pending_resize() +{ + time_t now_ts; + struct timeval now; + + /* Rate limit ConfigureNotify events before performing a + resize - enough time has to pass after the last event + */ + gettimeofday(&now, NULL); + if (time_difference_in_ms(g_resize_timer, now) <= 500) + return False; + + /* There is a race problem when using disconnect / reconnect + sequence were one sometimes would be presented with + unexpected login window. Waiting a little bit extra after + getting the reconnect cookie solves this problem. + + In addition to that delay, we also want to wait for + RDPEDISP to become available. In scenarios where we can use + both online and reconnect-based resizes, we prefer + online. Our brief investigation shows that RDPEDISP support + is established about 100-300 ms after the login info packet + was received. Thus, we want to wait a bit so we can avoid + resizes using reconnect. Once RDPEDISP is established, the + defer timer is cleared, so there will be no delay before + the first resize for servers that support RDPEDISP. Other + servers will get the initial resize delayed with 2 seconds. + */ + + if (timeval_is_set(&g_pending_resize_defer_timer) && + time_difference_in_ms(g_pending_resize_defer_timer, now) >= 2000) + { + g_pending_resize_defer_timer.tv_sec = g_pending_resize_defer_timer.tv_usec = 0; + g_pending_resize_defer = False; + } + + if (g_pending_resize_defer == True) + return False; + + /* Set up width and height for new session */ + if (g_fullscreen || g_seamless_rdp) + { + /* follow root window size */ + g_requested_session_width = WidthOfScreen(g_screen); + g_requested_session_height = HeightOfScreen(g_screen); + if (g_window_size_type == PercentageOfScreen) + { + /* TODO: Implement percentage of screen */ + } + } + else + { + /* Follow window size */ + g_requested_session_width = g_window_width; + g_requested_session_height = g_window_height; + } + + + /* Carry out a resize to desired size */ + if (rdpedisp_is_available() == False) + { + /* resize session using disconnect reconnect + * sequence when RDPEDISP is not supported by + * server by returning to outer loop. + */ + + logger(GUI, Verbose, "Window resize detected, reconnecting to new size %dx%d", + g_requested_session_width, g_requested_session_height); + + return True; + } + else + { + now_ts = time(NULL); + if (now_ts - g_wait_for_deactivate_ts <= 5) + return False; + + logger(GUI, Verbose, + "Window resize detected, requesting matching session size %dx%d", + g_requested_session_width, g_requested_session_height); + + rdpedisp_set_session_size(g_requested_session_width, g_requested_session_height); + + g_pending_resize = False; + g_wait_for_deactivate_ts = now_ts; + } + + return False; +} + +/* This function is the heart of the mainloop pump in + rdekstop. Handles processing of pending X11 events and data on all + file descriptors used by rdesktop except for rdp_socket. + Processing of data on rdp_socket is done by returning from this + function to the calling tcp_recv(). + + This function will return if there is data available for reading on + rdp_socket or if g_exit_mainloop flag is set. +*/ +void +ui_select(int rdp_socket) +{ + int timeout; + RD_BOOL rdp_socket_has_data = False; + + while (g_exit_mainloop == False && rdp_socket_has_data == False) + { + /* Process a limited amount of pending x11 events */ + if (!xwin_process_events()) + { + /* User quit */ + g_user_quit = True; + g_exit_mainloop = True; + g_pending_resize = False; + continue; + } + + if (g_pending_resize == True && g_dynamic_session_resize) + { + /* returns True on disconnect-reconnect resize */ + if (process_pending_resize() == True) + { + g_exit_mainloop = True; + continue; + } + } - ctrl_check_fds(&rfds, &wfds); + if (g_seamless_active) + sw_check_timers(); - if (FD_ISSET(rdp_socket, &rfds)) - return 1; + /* process_fds() is a little special, it does two + things in one. It will perform a select() on all + filedescriptors; rdpsnd / rdpdr / ctrl and + rdp_socket passed as argument. If data is available + on any filedescriptor except rdp_socket, it will be processed. + + If data is available on rdp_socket, the call return + true and we exit from ui_select() to let tcp_recv() + read data from rdp_socket. + + Use 60 seconds as default timeout for select. If + there is more X11 events on queue or g_pend is set, + use a low timeout. + */ + + timeout = 60000; + + if (XPending(g_display) > 0) + timeout = 0; + else if (g_pending_resize == True) + timeout = 100; + rdp_socket_has_data = process_fds(rdp_socket, timeout); } } @@ -2841,141 +3408,194 @@ XFreePixmap(g_display, (Pixmap) glyph); } -/* convert next pixel to 32 bpp */ -static int -get_next_xor_pixel(uint8 * xormask, int bpp, int *k) +#define GET_BIT(ptr, bit) (*(ptr + bit / 8) & (1 << (7 - (bit % 8)))) + +static uint32 +get_pixel(uint32 idx, uint8 * andmask, uint8 * xormask, int bpp, uint8 * xor_flag) { - int rv = 0; + uint32 offs; + uint32 argb; + uint8 alpha; + uint8 *pxor; PixelColour pc; - uint8 *s8; - uint16 *s16; + *xor_flag = 0; + + /* return a red pixel if bpp is not supported to signal failure */ + argb = 0xffff0000; switch (bpp) { case 1: - s8 = xormask + (*k) / 8; - rv = (*s8) & (0x80 >> ((*k) % 8)); - rv = rv ? 0xffffff : 0; - (*k) += 1; - break; - case 8: - s8 = xormask + *k; - /* should use colour map */ - rv = s8[0]; - rv = rv ? 0xffffff : 0; - (*k) += 1; - break; - case 15: - s16 = (uint16 *) xormask; - SPLITCOLOUR15(s16[*k], pc); - rv = (pc.red << 16) | (pc.green << 8) | pc.blue; - (*k) += 1; + offs = idx; + argb = GET_BIT(xormask, idx); + alpha = GET_BIT(andmask, idx) ? 0x00 : 0xff; + if (!GET_BIT(andmask, idx) == 0x00 && argb) + { + // If we have an xor bit is high and + // andmask bit is low, we should + // render a black pixel due to we can + // not xor blit in X11. + argb = 0xff000000; + *xor_flag = 1; + } + else + argb = (alpha << 24) | (argb ? 0xffffff : 0x000000); break; + case 16: - s16 = (uint16 *) xormask; - SPLITCOLOUR16(s16[*k], pc); - rv = (pc.red << 16) | (pc.green << 8) | pc.blue; - (*k) += 1; + offs = idx * 2; + pxor = xormask + offs; + SPLITCOLOUR16(*((uint16 *) pxor), pc); + alpha = GET_BIT(andmask, idx) ? 0x00 : 0xff; + argb = (alpha << 24) | (pc.red << 16) | (pc.green << 8) | pc.blue; break; + case 24: - s8 = xormask + *k; - rv = (s8[0] << 16) | (s8[1] << 8) | s8[2]; - (*k) += 3; + offs = idx * 3; + pxor = xormask + offs; + alpha = GET_BIT(andmask, idx) ? 0x00 : 0xff; + argb = (alpha << 24) | (pxor[2] << 16) | (pxor[1] << 8) | pxor[0]; break; + case 32: - s8 = xormask + *k; - rv = (s8[1] << 16) | (s8[2] << 8) | s8[3]; - (*k) += 4; - break; - default: - error("unknown bpp in get_next_xor_pixel %d\n", bpp); + offs = idx * 4; + pxor = xormask + offs; + argb = (pxor[3] << 24) | (pxor[2] << 16) | (pxor[1] << 8) | pxor[0]; break; } - return rv; + + return argb; } -RD_HCURSOR -ui_create_cursor(unsigned int x, unsigned int y, int width, int height, - uint8 * andmask, uint8 * xormask, int bpp) +/* Copies the pixels from src to dest with given color and offset */ +static inline void +xcursor_stencil(XcursorImage * src, XcursorImage * dst, int dx, int dy, uint32 argb) { - RD_HGLYPH maskglyph, cursorglyph; - XColor bg, fg; - Cursor xcursor; - uint8 *cursor, *pcursor; - uint8 *mask, *pmask; - uint8 nextbit; - int scanline, offset, delta; - int i, j, k; + int x, y, si, di; + assert(src->width == dst->width); + assert(src->height == dst->height); - k = 0; - scanline = (width + 7) / 8; - offset = scanline * height; + for (y = 0; y < (int) src->height; y++) + { + for (x = 0; x < (int) src->width; x++) + { + si = y * src->width + x; + if (!src->pixels[si]) + continue; - cursor = (uint8 *) xmalloc(offset); - memset(cursor, 0, offset); + if ((y + dy) < 0 || (y + dy) >= (int) dst->height) + continue; + if ((x + dx) < 0 || (x + dx) >= (int) dst->width) + continue; + di = (y + dy) * src->width + (x + dx); + dst->pixels[di] = argb; + } + } +} - mask = (uint8 *) xmalloc(offset); - memset(mask, 0, offset); - if (bpp == 1) +static inline void +xcursor_merge(XcursorImage * src, XcursorImage * dst) +{ + uint32 i; + assert(src->width == dst->width); + assert(src->height == dst->height); + for (i = 0; i < src->width * src->height; i++) { - offset = 0; - delta = scanline; + if (!src->pixels[i]) + continue; + dst->pixels[i] = src->pixels[i]; } - else +} + +RD_HCURSOR +ui_create_cursor(unsigned int xhot, unsigned int yhot, uint32 width, + uint32 height, uint8 * andmask, uint8 * xormask, int bpp) +{ + Cursor cursor; + XcursorPixel *out; + XcursorImage *cimg, *tmp; + uint32 x, y, oidx, idx, argb; + uint8 outline, xor; + + logger(GUI, Debug, "ui_create_cursor(): xhot=%d, yhot=%d, width=%d, height=%d, bpp=%d", + xhot, yhot, width, height, bpp); + + if (bpp != 1 && bpp != 16 && bpp != 24 && bpp != 32) { - offset = scanline * height - scanline; - delta = -scanline; + logger(GUI, Warning, "ui_create_xcursor_cursor(): Unhandled cursor bit depth %d", + bpp); + return g_null_cursor; } - /* approximate AND and XOR masks with a monochrome X pointer */ - for (i = 0; i < height; i++) + + cimg = XcursorImageCreate(width, height); + if (!cimg) { - pcursor = &cursor[offset]; - pmask = &mask[offset]; + logger(GUI, Error, "ui_create_xcursor_cursor(): XcursorImageCreate() failed"); + return g_null_cursor; + } - for (j = 0; j < scanline; j++) + cimg->xhot = xhot; + cimg->yhot = yhot; + + out = cimg->pixels; + xor = 0; + outline = 0; + for (y = 0; y < height; y++) + { + for (x = 0; x < width; x++) { - for (nextbit = 0x80; nextbit != 0; nextbit >>= 1) + oidx = y * width + x; + + // Flip cursor on Y axis if color pointer + if (bpp != 1) { - if (get_next_xor_pixel(xormask, bpp, &k)) - { - *pcursor |= (~(*andmask) & nextbit); - *pmask |= nextbit; - } - else - { - *pcursor |= ((*andmask) & nextbit); - *pmask |= (~(*andmask) & nextbit); - } + oidx = (height - 1 - y) * width + x; } - andmask++; - pcursor++; - pmask++; + idx = y * width + x; + argb = get_pixel(idx, andmask, xormask, bpp, &xor); + out[oidx] = argb; + if (xor) + outline = 1; } - offset += delta; } - fg.red = fg.blue = fg.green = 0xffff; - bg.red = bg.blue = bg.green = 0x0000; - fg.flags = bg.flags = DoRed | DoBlue | DoGreen; - cursorglyph = ui_create_glyph(width, height, cursor); - maskglyph = ui_create_glyph(width, height, mask); + // Render a white outline of cursor shape when xor + // pixels are identified in cursor + if (outline) + { + tmp = XcursorImageCreate(width, height); + memset(tmp->pixels, 0, tmp->width * tmp->height * 4); + xcursor_stencil(cimg, tmp, -1, 0, 0xffffffff); + xcursor_stencil(cimg, tmp, 1, 0, 0xffffffff); + xcursor_stencil(cimg, tmp, 0, -1, 0xffffffff); + xcursor_stencil(cimg, tmp, 0, 1, 0xffffffff); + xcursor_merge(cimg, tmp); + xcursor_merge(tmp, cimg); + XcursorImageDestroy(tmp); + } - xcursor = - XCreatePixmapCursor(g_display, (Pixmap) cursorglyph, - (Pixmap) maskglyph, &fg, &bg, x, y); + cursor = XcursorImageLoadCursor(g_display, cimg); + XcursorImageDestroy(cimg); + if (!cursor) + { + logger(GUI, Error, "ui_create_cursor(): XcursorImageLoadCursor() failed"); + return g_null_cursor; + } - ui_destroy_glyph(maskglyph); - ui_destroy_glyph(cursorglyph); - xfree(mask); - xfree(cursor); - return (RD_HCURSOR) xcursor; + return (RD_HCURSOR) cursor; } void ui_set_cursor(RD_HCURSOR cursor) { + extern RD_BOOL g_local_cursor; + if (g_local_cursor) + return; + logger(GUI, Debug, "ui_set_cursor(): g_current_cursor = %p, new = %p", + g_current_cursor, cursor); + g_current_cursor = (Cursor) cursor; XDefineCursor(g_display, g_wnd, g_current_cursor); ON_ALL_SEAMLESS_WINDOWS(XDefineCursor, (g_display, sw->wnd, g_current_cursor)); @@ -2984,6 +3604,10 @@ void ui_destroy_cursor(RD_HCURSOR cursor) { + // Do not destroy fallback null cursor + if (cursor == g_null_cursor) + return; + XFreeCursor(g_display, (Cursor) cursor); } @@ -2993,6 +3617,12 @@ ui_set_cursor(g_null_cursor); } +void +ui_set_standard_cursor(void) +{ + XUndefineCursor(g_display, g_wnd); +} + #define MAKE_XCOLOR(xc,c) \ (xc)->red = ((c)->red << 8) | (c)->red; \ (xc)->green = ((c)->green << 8) | (c)->green; \ @@ -3139,11 +3769,9 @@ void ui_reset_clip(void) { - g_clip_rectangle.x = 0; - g_clip_rectangle.y = 0; - g_clip_rectangle.width = g_width; - g_clip_rectangle.height = g_height; - XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded); + XWindowAttributes attr; + XGetWindowAttributes(g_display, g_wnd, &attr); + ui_set_clip(0, 0, attr.width, attr.height); } void @@ -3173,7 +3801,7 @@ void ui_patblt(uint8 opcode, /* dest */ int x, int y, int cx, int cy, - /* brush */ BRUSH * brush, int bgcolour, int fgcolour) + /* brush */ BRUSH * brush, uint32 bgcolour, uint32 fgcolour) { Pixmap fill; uint8 i, ipattern[8]; @@ -3244,7 +3872,8 @@ break; default: - unimpl("brush %d\n", brush->style); + logger(GUI, Warning, "Unimplemented support for brush type %d", + brush->style); } RESET_FUNCTION(opcode); @@ -3299,7 +3928,7 @@ ui_triblt(uint8 opcode, /* dest */ int x, int y, int cx, int cy, /* src */ RD_HBITMAP src, int srcx, int srcy, - /* brush */ BRUSH * brush, int bgcolour, int fgcolour) + /* brush */ BRUSH * brush, uint32 bgcolour, uint32 fgcolour) { /* This is potentially difficult to do in general. Until someone comes up with a more efficient way of doing it I am using cases. */ @@ -3323,7 +3952,7 @@ break; default: - unimpl("triblt 0x%x\n", opcode); + logger(GUI, Warning, "Unimplemented triblit opcode 0x%x", opcode); ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy); } } @@ -3347,7 +3976,7 @@ void ui_rect( /* dest */ int x, int y, int cx, int cy, - /* brush */ int colour) + /* brush */ uint32 colour) { SET_FOREGROUND(colour); FILL_RECTANGLE(x, y, cx, cy); @@ -3357,7 +3986,7 @@ ui_polygon(uint8 opcode, /* mode */ uint8 fillmode, /* dest */ RD_POINT * point, int npoints, - /* brush */ BRUSH * brush, int bgcolour, int fgcolour) + /* brush */ BRUSH * brush, uint32 bgcolour, uint32 fgcolour) { uint8 style, i, ipattern[8]; Pixmap fill; @@ -3373,7 +4002,7 @@ XSetFillRule(g_display, g_gc, WindingRule); break; default: - unimpl("fill mode %d\n", fillmode); + logger(GUI, Warning, "Unimplemented fill mode %d", fillmode); } if (brush) @@ -3445,7 +4074,7 @@ break; default: - unimpl("brush %d\n", brush->style); + logger(GUI, Warning, "Unimplemented brush style %d", brush->style); } RESET_FUNCTION(opcode); @@ -3474,7 +4103,7 @@ ui_ellipse(uint8 opcode, /* mode */ uint8 fillmode, /* dest */ int x, int y, int cx, int cy, - /* brush */ BRUSH * brush, int bgcolour, int fgcolour) + /* brush */ BRUSH * brush, uint32 bgcolour, uint32 fgcolour) { uint8 style, i, ipattern[8]; Pixmap fill; @@ -3550,7 +4179,7 @@ break; default: - unimpl("brush %d\n", brush->style); + logger(GUI, Warning, "Unimplemented brush style %d", brush->style); } RESET_FUNCTION(opcode); @@ -3561,8 +4190,11 @@ ui_draw_glyph(int mixmode, /* dest */ int x, int y, int cx, int cy, /* src */ RD_HGLYPH glyph, int srcx, int srcy, - int bgcolour, int fgcolour) + uint32 bgcolour, uint32 fgcolour) { + UNUSED(srcx); + UNUSED(srcy); + SET_FOREGROUND(fgcolour); SET_BACKGROUND(bgcolour); @@ -3614,8 +4246,14 @@ 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) + uint32 bgcolour, uint32 fgcolour, uint8 * text, uint8 length) { + XWindowAttributes attr; + UNUSED(opcode); + UNUSED(brush); + + XGetWindowAttributes(g_display, g_wnd, &attr); + /* TODO: use brush appropriately */ FONTGLYPH *glyph; @@ -3627,8 +4265,8 @@ /* Sometimes, the boxcx value is something really large, like 32691. This makes XCopyArea fail with Xvnc. The code below is a quick fix. */ - if (boxx + boxcx > g_width) - boxcx = g_width - boxx; + if (boxx + boxcx > attr.width) + boxcx = attr.width - boxx; if (boxcx > 1) { @@ -3652,10 +4290,8 @@ /* At least two bytes needs to follow */ if (i + 3 > length) { - warning("Skipping short 0xff command:"); - for (j = 0; j < length; j++) - fprintf(stderr, "%02x ", text[j]); - fprintf(stderr, "\n"); + logger(GUI, Warning, + "ui_draw_text(), skipping short 0xff command"); i = length = 0; break; } @@ -3671,10 +4307,8 @@ /* At least one byte needs to follow */ if (i + 2 > length) { - warning("Skipping short 0xfe command:"); - for (j = 0; j < length; j++) - fprintf(stderr, "%02x ", text[j]); - fprintf(stderr, "\n"); + logger(GUI, Warning, + "ui_draw_text(), skipping short 0xfe command"); i = length = 0; break; } @@ -3923,6 +4557,7 @@ XSizeHints *sizehints; XWMHints *wmhints; long input_mask; + unsigned long value_mask; seamless_window *sw, *sw_parent; if (!g_seamless_active) @@ -3933,10 +4568,12 @@ if (sw) return; - get_window_attribs(&attribs); + value_mask = get_window_attribs_seamless(&attribs); wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, g_depth, - InputOutput, g_visual, - CWBackPixel | CWBackingStore | CWColormap | CWBorderPixel, &attribs); + InputOutput, g_visual, value_mask, &attribs); + + ewmh_set_wm_pid(wnd, getpid()); + set_wm_client_machine(g_display, wnd); XStoreName(g_display, wnd, "SeamlessRDP"); ewmh_set_wm_name(wnd, "SeamlessRDP"); @@ -3965,7 +4602,7 @@ if (parent == 0xFFFFFFFF) { XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen)); - /* Some buggy wm:s (kwin) do not handle the above, so fake it + /* Some buggy WMs (kwin) do not handle the above, so fake it using some other hints. */ ewmh_set_window_popup(wnd); } @@ -3976,12 +4613,13 @@ if (sw_parent) XSetTransientForHint(g_display, wnd, sw_parent->wnd); else - warning("ui_seamless_create_window: No parent window 0x%lx\n", parent); + logger(GUI, Warning, + "ui_seamless_create_window(): no parent window 0x%lx\n", parent); } if (flags & SEAMLESSRDP_CREATE_MODAL) { - /* We do this to support buggy wm:s (*cough* metacity *cough*) + /* We do this to support buggy WMs (*cough* Metacity *cough*) somewhat at least */ if (parent == 0x00000000) XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen)); @@ -4001,8 +4639,13 @@ XSelectInput(g_display, wnd, input_mask); - /* handle the WM_DELETE_WINDOW protocol. */ - XSetWMProtocols(g_display, wnd, &g_kill_atom, 1); + /* setup supported protocols. */ + Atom supported[] = { + g_net_wm_ping_atom, + g_kill_atom + }; + + XSetWMProtocols(g_display, wnd, supported, 2); sw = xmalloc(sizeof(seamless_window)); @@ -4040,6 +4683,8 @@ void ui_seamless_destroy_window(unsigned long id, unsigned long flags) { + UNUSED(flags); + seamless_window *sw; if (!g_seamless_active) @@ -4048,7 +4693,8 @@ sw = sw_get_window_by_id(id); if (!sw) { - warning("ui_seamless_destroy_window: No information for window 0x%lx\n", id); + logger(GUI, Warning, + "ui_seamless_destroy_window(), no information for window 0x%lx", id); return; } @@ -4060,6 +4706,8 @@ void ui_seamless_destroy_group(unsigned long id, unsigned long flags) { + UNUSED(flags); + seamless_window *sw, *sw_next; if (!g_seamless_active) @@ -4080,7 +4728,7 @@ void ui_seamless_seticon(unsigned long id, const char *format, int width, int height, int chunk, - const char *data, int chunk_len) + const char *data, size_t chunk_len) { seamless_window *sw; @@ -4090,25 +4738,28 @@ sw = sw_get_window_by_id(id); if (!sw) { - warning("ui_seamless_seticon: No information for window 0x%lx\n", id); + logger(GUI, Warning, "ui_seamless_seticon(): No information for window 0x%lx", id); return; } if (chunk == 0) { if (sw->icon_size) - warning("ui_seamless_seticon: New icon started before previous completed\n"); + logger(GUI, Warning, + "ui_seamless_seticon(), new icon started before previous completed"); if (strcmp(format, "RGBA") != 0) { - warning("ui_seamless_seticon: Uknown icon format \"%s\"\n", format); + logger(GUI, Warning, "ui_seamless_seticon(), unknown icon format \"%s\"", + format); return; } sw->icon_size = width * height * 4; if (sw->icon_size > 32 * 32 * 4) { - warning("ui_seamless_seticon: Icon too large (%d bytes)\n", sw->icon_size); + logger(GUI, Warning, "ui_seamless_seticon(), icon too large (%d bytes)", + sw->icon_size); sw->icon_size = 0; return; } @@ -4123,8 +4774,9 @@ if (chunk_len > (sw->icon_size - sw->icon_offset)) { - warning("ui_seamless_seticon: Too large chunk received (%d bytes > %d bytes)\n", - chunk_len, sw->icon_size - sw->icon_offset); + logger(GUI, Warning, + "ui_seamless_seticon(), too large chunk received (%d bytes > %d bytes)", + chunk_len, sw->icon_size - sw->icon_offset); sw->icon_size = 0; return; } @@ -4151,13 +4803,13 @@ sw = sw_get_window_by_id(id); if (!sw) { - warning("ui_seamless_seticon: No information for window 0x%lx\n", id); + logger(GUI, Warning, "ui_seamless_seticon(), no information for window 0x%lx", id); return; } if (strcmp(format, "RGBA") != 0) { - warning("ui_seamless_seticon: Uknown icon format \"%s\"\n", format); + logger(GUI, Warning, "ui_seamless_seticon(), unknown icon format \"%s\"", format); return; } @@ -4168,6 +4820,8 @@ void ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags) { + UNUSED(flags); + seamless_window *sw; if (!g_seamless_active) @@ -4176,7 +4830,8 @@ sw = sw_get_window_by_id(id); if (!sw) { - warning("ui_seamless_move_window: No information for window 0x%lx\n", id); + logger(GUI, Warning, "ui_seamless_move_window(), no information for window 0x%lx", + id); return; } @@ -4222,7 +4877,8 @@ sw = sw_get_window_by_id(id); if (!sw) { - warning("ui_seamless_restack_window: No information for window 0x%lx\n", id); + logger(GUI, Warning, + "ui_seamless_restack_window(), no information for window 0x%lx", id); return; } @@ -4233,7 +4889,9 @@ sw_behind = sw_get_window_by_id(behind); if (!sw_behind) { - warning("ui_seamless_restack_window: No information for behind window 0x%lx\n", behind); + logger(GUI, Warning, + "ui_seamless_restack_window(), no information for behind window 0x%lx", + behind); return; } @@ -4287,6 +4945,8 @@ void ui_seamless_settitle(unsigned long id, const char *title, unsigned long flags) { + UNUSED(flags); + seamless_window *sw; if (!g_seamless_active) @@ -4295,7 +4955,7 @@ sw = sw_get_window_by_id(id); if (!sw) { - warning("ui_seamless_settitle: No information for window 0x%lx\n", id); + logger(GUI, Warning, "ui_seamless_settitle(), no information for window 0x%lx", id); return; } @@ -4308,6 +4968,8 @@ void ui_seamless_setstate(unsigned long id, unsigned int state, unsigned long flags) { + UNUSED(flags); + seamless_window *sw; if (!g_seamless_active) @@ -4316,7 +4978,7 @@ sw = sw_get_window_by_id(id); if (!sw) { - warning("ui_seamless_setstate: No information for window 0x%lx\n", id); + logger(GUI, Warning, "ui_seamless_setstate(), no information for window 0x%lx", id); return; } @@ -4350,7 +5012,7 @@ XIconifyWindow(g_display, sw->wnd, DefaultScreen(g_display)); break; default: - warning("SeamlessRDP: Invalid state %d\n", state); + logger(GUI, Warning, "ui_seamless_setstate(), invalid state %d", state); break; } @@ -4361,6 +5023,8 @@ void ui_seamless_syncbegin(unsigned long flags) { + UNUSED(flags); + if (!g_seamless_active) return;