diff options
124 files changed, 16057 insertions, 5185 deletions
diff --git a/Makefile.am b/Makefile.am index 26dcb8aa..e8905c98 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,11 +1,5 @@ EXTRA_DIST = bootstrap COPYING design.txt faq-compile.txt faq-general.txt file-loc.txt install.txt prog_std.txt readme.txt -if XRDP_FREERDP1 -FREERDPDIR = freerdp1 -else -FREERDPDIR = -endif - if XRDP_NEUTRINORDP NEUTRINORDPDIR = neutrinordp else @@ -24,7 +18,6 @@ SUBDIRS = \ rdp \ xup \ mc \ - $(FREERDPDIR) \ $(NEUTRINORDPDIR) \ libxrdp \ xrdp \ diff --git a/common/arch.h b/common/arch.h index b8780926..6a29b0a9 100644 --- a/common/arch.h +++ b/common/arch.h @@ -1,7 +1,7 @@ /** * xrdp: A Remote Desktop Protocol server. * - * Copyright (C) Jay Sorg 2004-2012 + * Copyright (C) Jay Sorg 2004-2013 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/common/log.c b/common/log.c index ce0000aa..55353a8f 100644 --- a/common/log.c +++ b/common/log.c @@ -363,7 +363,7 @@ internal_config_read_logging(int file, struct log_config *lc, if (0 == g_strcasecmp(buf, SESMAN_CFG_LOG_ENABLE_SYSLOG)) { - lc->enable_syslog = text2bool((char *)list_get_item(param_v, i)); + lc->enable_syslog = g_text2bool((char *)list_get_item(param_v, i)); } if (0 == g_strcasecmp(buf, SESMAN_CFG_LOG_SYSLOG_LEVEL)) @@ -413,28 +413,6 @@ internalInitAndAllocStruct(void) * Here below the public functions */ - -/** - * - * @brief Reads sesman configuration - * @param s translates the strings "1", "true" and "yes" in 1 (true) and other strings in 0 - * @return 0 on false, 1 on 1,true, yes - * - */ -int APP_CC -text2bool(char *s) -{ - if ( (g_atoi(s) != 0) || - (0 == g_strcasecmp(s, "true")) || - (0 == g_strcasecmp(s, "on")) || - (0 == g_strcasecmp(s, "yes"))) - { - return 1; - } - - return 0; -} - enum logReturns DEFAULT_CC log_start_from_param(const struct log_config *iniParams) { diff --git a/common/os_calls.c b/common/os_calls.c index f5f5cd60..2d5b4280 100644 --- a/common/os_calls.c +++ b/common/os_calls.c @@ -493,6 +493,96 @@ g_tcp_socket(void) } /*****************************************************************************/ +/* returns error */ +int APP_CC +g_sck_set_send_buffer_bytes(int sck, int bytes) +{ + int option_value; +#if defined(_WIN32) + int option_len; +#else + unsigned int option_len; +#endif + + option_value = bytes; + option_len = sizeof(option_value); + if (setsockopt(sck, SOL_SOCKET, SO_SNDBUF, (char *)&option_value, + option_len) != 0) + { + return 1; + } + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +g_sck_get_send_buffer_bytes(int sck, int *bytes) +{ + int option_value; +#if defined(_WIN32) + int option_len; +#else + unsigned int option_len; +#endif + + option_value = 0; + option_len = sizeof(option_value); + if (getsockopt(sck, SOL_SOCKET, SO_SNDBUF, (char *)&option_value, + &option_len) != 0) + { + return 1; + } + *bytes = option_value; + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +g_sck_set_recv_buffer_bytes(int sck, int bytes) +{ + int option_value; +#if defined(_WIN32) + int option_len; +#else + unsigned int option_len; +#endif + + option_value = bytes; + option_len = sizeof(option_value); + if (setsockopt(sck, SOL_SOCKET, SO_RCVBUF, (char *)&option_value, + option_len) != 0) + { + return 1; + } + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +g_sck_get_recv_buffer_bytes(int sck, int *bytes) +{ + int option_value; +#if defined(_WIN32) + int option_len; +#else + unsigned int option_len; +#endif + + option_value = 0; + option_len = sizeof(option_value); + if (getsockopt(sck, SOL_SOCKET, SO_RCVBUF, (char *)&option_value, + &option_len) != 0) + { + return 1; + } + *bytes = option_value; + return 0; +} + +/*****************************************************************************/ int APP_CC g_tcp_local_socket(void) { @@ -504,6 +594,38 @@ g_tcp_local_socket(void) } /*****************************************************************************/ +int APP_CC +g_sck_get_peer_cred(int sck, int *pid, int *uid, int *gid) +{ + int ucred_length; + struct myucred + { + pid_t pid; + uid_t uid; + gid_t gid; + } credentials; + + ucred_length = sizeof(credentials); + if (getsockopt(sck, SOL_SOCKET, SO_PEERCRED, &credentials, &ucred_length)) + { + return 1; + } + if (pid != 0) + { + *pid = credentials.pid; + } + if (uid != 0) + { + *uid = credentials.uid; + } + if (gid != 0) + { + *gid = credentials.gid; + } + return 0; +} + +/*****************************************************************************/ void APP_CC g_tcp_close(int sck) { @@ -848,6 +970,41 @@ g_tcp_accept(int sck) } /*****************************************************************************/ +int APP_CC +g_sck_accept(int sck, char *addr, int addr_bytes, char *port, int port_bytes) +{ + int ret; + char ipAddr[256]; + struct sockaddr_in s; +#if defined(_WIN32) + signed int i; +#else + unsigned int i; +#endif + + i = sizeof(struct sockaddr_in); + memset(&s, 0, i); + ret = accept(sck, (struct sockaddr *)&s, &i); + if (ret > 0) + { + g_snprintf(ipAddr, 255, "A connection received from: %s port %d", + inet_ntoa(s.sin_addr), ntohs(s.sin_port)); + log_message(LOG_LEVEL_INFO,ipAddr); + if (s.sin_family == AF_INET) + { + g_snprintf(addr, addr_bytes, "%s", inet_ntoa(s.sin_addr)); + g_snprintf(port, port_bytes, "%d", ntohs(s.sin_port)); + } + if (s.sin_family == AF_UNIX) + { + g_strncpy(addr, "", addr_bytes - 1); + g_strncpy(port, "", port_bytes - 1); + } + } + return ret; +} + +/*****************************************************************************/ void APP_CC g_write_ip_address(int rcv_sck, char *ip_address, int bytes) { @@ -2501,6 +2658,17 @@ g_signal_child_stop(void (*func)(int)) } /*****************************************************************************/ + +void APP_CC +g_signal_segfault(void (*func)(int)) +{ +#if defined(_WIN32) +#else + signal(SIGSEGV, func); +#endif +} + +/*****************************************************************************/ /* does not work in win32 */ void APP_CC g_signal_hang_up(void (*func)(int)) @@ -2935,3 +3103,18 @@ g_time3(void) return (tp.tv_sec * 1000) + (tp.tv_usec / 1000); #endif } + +/*****************************************************************************/ +/* returns boolean */ +int APP_CC +g_text2bool(const char *s) +{ + if ( (g_atoi(s) != 0) || + (0 == g_strcasecmp(s, "true")) || + (0 == g_strcasecmp(s, "on")) || + (0 == g_strcasecmp(s, "yes"))) + { + return 1; + } + return 0; +} diff --git a/common/os_calls.h b/common/os_calls.h index cba37588..b6e1c91a 100644 --- a/common/os_calls.h +++ b/common/os_calls.h @@ -45,7 +45,12 @@ int APP_CC g_getchar(void); int APP_CC g_tcp_set_no_delay(int sck); int APP_CC g_tcp_set_keepalive(int sck); int APP_CC g_tcp_socket(void); +int APP_CC g_sck_set_send_buffer_bytes(int sck, int bytes); +int APP_CC g_sck_get_send_buffer_bytes(int sck, int *bytes); +int APP_CC g_sck_set_recv_buffer_bytes(int sck, int bytes); +int APP_CC g_sck_get_recv_buffer_bytes(int sck, int *bytes); int APP_CC g_tcp_local_socket(void); +int APP_CC g_sck_get_peer_cred(int sck, int *pid, int *uid, int *gid); void APP_CC g_tcp_close(int sck); int APP_CC g_tcp_connect(int sck, const char* address, const char* port); int APP_CC g_tcp_local_connect(int sck, const char* port); @@ -57,6 +62,8 @@ int APP_CC g_tcp_local_bind(int sck, const char* port); int APP_CC g_tcp_bind_address(int sck, const char* port, const char* address); int APP_CC g_tcp_listen(int sck); int APP_CC g_tcp_accept(int sck); +int APP_CC g_sck_accept(int sck, char *addr, int addr_bytes, + char *port, int port_bytes); int APP_CC g_tcp_recv(int sck, void* ptr, int len, int flags); int APP_CC g_tcp_send(int sck, const void* ptr, int len, int flags); int APP_CC g_tcp_last_error_would_block(int sck); @@ -125,6 +132,7 @@ int APP_CC g_get_errno(void); int APP_CC g_execvp(const char* p1, char* args[]); int APP_CC g_execlp3(const char* a1, const char* a2, const char* a3); void APP_CC g_signal_child_stop(void (*func)(int)); +void APP_CC g_signal_segfault(void (*func)(int)); void APP_CC g_signal_hang_up(void (*func)(int)); void APP_CC g_signal_user_interrupt(void (*func)(int)); void APP_CC g_signal_kill(void (*func)(int)); @@ -152,5 +160,6 @@ int APP_CC g_check_user_in_group(const char* username, int gid, int* ok); int APP_CC g_time1(void); int APP_CC g_time2(void); int APP_CC g_time3(void); +int APP_CC g_text2bool(const char *s); #endif diff --git a/common/parse.h b/common/parse.h index f92e76de..69a57ff8 100644 --- a/common/parse.h +++ b/common/parse.h @@ -56,6 +56,9 @@ struct stream #define s_check_rem(s, n) ((s)->p + (n) <= (s)->end) /******************************************************************************/ +#define s_check_rem_out(s, n) ((s)->p + (n) <= (s)->data + (s)->size) + +/******************************************************************************/ #define s_check_end(s) ((s)->p == (s)->end) /******************************************************************************/ @@ -279,6 +282,35 @@ struct stream #endif /******************************************************************************/ +#if defined(B_ENDIAN) || defined(NEED_ALIGN) +#define out_uint64_le(s, v) do \ +{ \ + *((s)->p) = (unsigned char)((v) >> 0); \ + (s)->p++; \ + *((s)->p) = (unsigned char)((v) >> 8); \ + (s)->p++; \ + *((s)->p) = (unsigned char)((v) >> 16); \ + (s)->p++; \ + *((s)->p) = (unsigned char)((v) >> 24); \ + (s)->p++; \ + *((s)->p) = (unsigned char)((v) >> 32); \ + (s)->p++; \ + *((s)->p) = (unsigned char)((v) >> 40); \ + (s)->p++; \ + *((s)->p) = (unsigned char)((v) >> 48); \ + (s)->p++; \ + *((s)->p) = (unsigned char)((v) >> 56); \ + (s)->p++; \ +} while (0) +#else +#define out_uint64_le(s, v) do \ +{ \ + *((tui64*)((s)->p)) = (v); \ + (s)->p += 8; \ +} while (0) +#endif + +/******************************************************************************/ #define out_uint32_be(s, v) do \ { \ *((s)->p) = (unsigned char)((v) >> 24); \ diff --git a/common/trans.c b/common/trans.c index e862249e..bb349298 100644 --- a/common/trans.c +++ b/common/trans.c @@ -92,6 +92,86 @@ trans_get_wait_objs(struct trans *self, tbus *objs, int *count) /*****************************************************************************/ int APP_CC +trans_get_wait_objs_rw(struct trans *self, + tbus *robjs, int *rcount, + tbus *wobjs, int *wcount) +{ + if (self == 0) + { + return 1; + } + + if (self->status != TRANS_STATUS_UP) + { + return 1; + } + + robjs[*rcount] = self->sck; + (*rcount)++; + + if (self->wait_s != 0) + { + wobjs[*wcount] = self->sck; + (*wcount)++; + } + + return 0; +} + +/*****************************************************************************/ +int APP_CC +send_waiting(struct trans *self, int block) +{ + struct stream *temp_s; + int bytes; + int sent; + int timeout; + int cont; + + timeout = block ? 100 : 0; + cont = 1; + while (cont) + { + if (self->wait_s != 0) + { + temp_s = self->wait_s; + if (g_tcp_can_send(self->sck, timeout)) + { + bytes = (int) (temp_s->end - temp_s->p); + sent = g_tcp_send(self->sck, temp_s->p, bytes, 0); + if (sent > 0) + { + temp_s->p += sent; + if (temp_s->p >= temp_s->end) + { + self->wait_s = (struct stream *) (temp_s->next_packet); + free_stream(temp_s); + } + } + else if (sent == 0) + { + return 1; + } + else + { + if (!g_tcp_last_error_would_block(self->sck)) + { + return 1; + } + } + } + } + else + { + break; + } + cont = block; + } + return 0; +} + +/*****************************************************************************/ +int APP_CC trans_check_wait_objs(struct trans *self) { tbus in_sck = (tbus)0; @@ -117,7 +197,8 @@ trans_check_wait_objs(struct trans *self) { if (g_tcp_can_recv(self->sck, 0)) { - in_sck = g_tcp_accept(self->sck); + in_sck = g_sck_accept(self->sck, self->addr, sizeof(self->addr), + self->port, sizeof(self->port)); if (in_sck == -1) { @@ -142,6 +223,9 @@ trans_check_wait_objs(struct trans *self) in_trans->sck = in_sck; in_trans->type1 = TRANS_TYPE_SERVER; in_trans->status = TRANS_STATUS_UP; + in_trans->is_term = self->is_term; + g_strncpy(in_trans->addr, self->addr, sizeof(self->addr) - 1); + g_strncpy(in_trans->port, self->port, sizeof(self->port) - 1); if (self->trans_conn_in(self, in_trans) != 0) { @@ -202,6 +286,12 @@ trans_check_wait_objs(struct trans *self) } } } + if (send_waiting(self, 0) != 0) + { + /* error */ + self->status = TRANS_STATUS_DOWN; + return 1; + } } return rv; @@ -220,15 +310,28 @@ trans_force_read_s(struct trans *self, struct stream *in_s, int size) while (size > 0) { + /* make sure stream has room */ + if ((in_s->end + size) > (in_s->data + in_s->size)) + { + return 1; + } rcvd = g_tcp_recv(self->sck, in_s->end, size, 0); - if (rcvd == -1) { if (g_tcp_last_error_would_block(self->sck)) { - if (!g_tcp_can_recv(self->sck, 10)) + if (!g_tcp_can_recv(self->sck, 100)) { /* check for term here */ + if (self->is_term != 0) + { + if (self->is_term()) + { + /* term */ + self->status = TRANS_STATUS_DOWN; + return 1; + } + } } } else @@ -277,6 +380,12 @@ trans_force_write_s(struct trans *self, struct stream *out_s) size = (int)(out_s->end - out_s->data); total = 0; + if (send_waiting(self, 1) != 0) + { + self->status = TRANS_STATUS_DOWN; + return 1; + } + while (total < size) { sent = g_tcp_send(self->sck, out_s->data + total, size - total, 0); @@ -285,9 +394,18 @@ trans_force_write_s(struct trans *self, struct stream *out_s) { if (g_tcp_last_error_would_block(self->sck)) { - if (!g_tcp_can_send(self->sck, 10)) + if (!g_tcp_can_send(self->sck, 100)) { /* check for term here */ + if (self->is_term != 0) + { + if (self->is_term()) + { + /* term */ + self->status = TRANS_STATUS_DOWN; + return 1; + } + } } } else @@ -321,6 +439,43 @@ trans_force_write(struct trans *self) /*****************************************************************************/ int APP_CC +trans_write_copy(struct trans *self) +{ + int size; + struct stream *out_s; + struct stream *wait_s; + struct stream *temp_s; + + if (self->status != TRANS_STATUS_UP) + { + return 1; + } + + out_s = self->out_s; + size = (int)(out_s->end - out_s->data); + make_stream(wait_s); + init_stream(wait_s, size); + out_uint8a(wait_s, out_s->data, size); + s_mark_end(wait_s); + wait_s->p = wait_s->data; + if (self->wait_s == 0) + { + self->wait_s = wait_s; + } + else + { + temp_s = self->wait_s; + while (temp_s->next_packet != 0) + { + temp_s = (struct stream *) (temp_s->next_packet); + } + temp_s->next_packet = (char *) wait_s; + } + return 0; +} + +/*****************************************************************************/ +int APP_CC trans_connect(struct trans *self, const char *server, const char *port, int timeout) { diff --git a/common/trans.h b/common/trans.h index 8daa980a..350f05cc 100644 --- a/common/trans.h +++ b/common/trans.h @@ -38,6 +38,7 @@ struct trans; /* forward declaration */ typedef int (*ttrans_data_in)(struct trans* self); typedef int (*ttrans_conn_in)(struct trans* self, struct trans* new_self); +typedef int (*tis_term)(void); struct trans { @@ -52,6 +53,10 @@ struct trans struct stream* in_s; struct stream* out_s; char* listen_filename; + tis_term is_term; /* used to test for exit */ + struct stream* wait_s; + char addr[256]; + char port[256]; }; struct trans* APP_CC @@ -71,6 +76,8 @@ trans_force_read(struct trans* self, int size); int APP_CC trans_force_write(struct trans* self); int APP_CC +trans_write_copy(struct trans* self); +int APP_CC trans_connect(struct trans* self, const char* server, const char* port, int timeout); int APP_CC diff --git a/common/xrdp_client_info.h b/common/xrdp_client_info.h index 43ff3f82..acd145e6 100644 --- a/common/xrdp_client_info.h +++ b/common/xrdp_client_info.h @@ -21,6 +21,15 @@ #if !defined(XRDP_CLIENT_INFO_H) #define XRDP_CLIENT_INFO_H +struct monitor_info +{ + int left; + int top; + int right; + int bottom; + int is_primary; +}; + struct xrdp_client_info { int size; /* bytes for this structure */ @@ -69,6 +78,7 @@ struct xrdp_client_info int offscreen_cache_size; int offscreen_cache_entries; int rfx; + /* CAPSETTYPE_RAIL */ int rail_support_level; /* CAPSETTYPE_WINDOW */ @@ -93,6 +103,13 @@ struct xrdp_client_info int pointer_flags; /* 0 color, 1 new, 2 no new */ int use_fast_path; int require_credentials; /* when true, credentials *must* be passed on cmd line */ + char client_addr[256]; + char client_port[256]; + + int nego_sec_layer; /* 0, 1, 2 = RDP security layer, TLS , Negotiate */ + int multimon; /* 0 = deny , 1 = allow */ + int monitorCount; /* number of monitors detected (max = 16) */ + struct monitor_info minfo[16]; /* client monitor data */ }; #endif diff --git a/common/xrdp_constants.h b/common/xrdp_constants.h index b978d2de..ed74fd01 100644 --- a/common/xrdp_constants.h +++ b/common/xrdp_constants.h @@ -25,12 +25,36 @@ /* TCP port for Remote Desktop Protocol */ #define TCP_PORT_RDP 3389 -#define ISO_PDU_CR 0xE0 /* Connection Request */ -#define ISO_PDU_CC 0xD0 /* Connection Confirm */ +#define ISO_PDU_CR 0xE0 /* X.224 Connection Request */ +#define ISO_PDU_CC 0xD0 /* X.224 Connection Confirm */ #define ISO_PDU_DR 0x80 /* Disconnect Request */ #define ISO_PDU_DT 0xF0 /* Data */ #define ISO_PDU_ER 0x70 /* Error */ + +/* RDP Security Negotiation codes */ +#define RDP_NEG_REQ 0x01 +#define RDP_NEG_RSP 0x02 +#define RDP_NEG_FAILURE 0x03 +#define RDP_CORRELATION_INFO 0x06 +/* Protocol types codes */ +#define PROTOCOL_RDP 0x0 +#define PROTOCOL_SSL 0x1 +#define PROTOCOL_HYBRID 0x2 +#define PROTOCOL_HYBRID_EX 0x8 +/* Negotiation packet flags */ +#define EXTENDED_CLIENT_DATA_SUPPORTED 0x1 +#define DYNVC_GFX_PROTOCOL_SUPPORTED 0x2 +#define RDP_NEGRSP_RESERVED 0x4 +/* Failure Codes */ +#define SSL_REQUIRED_BY_SERVER 0x1 +#define SSL_NOT_ALLOWED_BY_SERVER 0x2 +#define SSL_CERT_NOT_ON_SERVER 0x3 +#define INCONSISTENT_FLAGS 0x4 +#define HYBRID_REQUIRED_BY_SERVER 0x5 +#define SSL_WITH_USER_AUTH_REQUIRED_BY_SERVER 0x6 + + /* MCS PDU codes */ #define MCS_EDRQ 1 /* Erect Domain Request */ #define MCS_DPUM 8 /* Disconnect Provider Ultimatum */ @@ -72,6 +96,7 @@ #define SEC_TAG_CLI_CRYPT 0xc002 #define SEC_TAG_CLI_CHANNELS 0xc003 #define SEC_TAG_CLI_4 0xc004 +#define SEC_TAG_CLI_MONITOR 0xc005 #define SEC_TAG_PUBKEY 0x0006 #define SEC_TAG_KEYSIG 0x0008 @@ -416,6 +441,7 @@ #define RDP_ORDER_TRIBLT 14 #define RDP_ORDER_POLYLINE 22 #define RDP_ORDER_TEXT2 27 +#define RDP_ORDER_COMPOSITE 37 /* 0x25 */ #define RDP_ORDER_RAW_BMPCACHE 0 #define RDP_ORDER_COLCACHE 1 @@ -463,6 +489,10 @@ #define WM_BUTTON4DOWN 108 #define WM_BUTTON5UP 109 #define WM_BUTTON5DOWN 110 +#define WM_BUTTON6UP 111 +#define WM_BUTTON6DOWN 112 +#define WM_BUTTON7UP 113 +#define WM_BUTTON7DOWN 114 #define WM_INVALIDATE 200 #define CB_ITEMCHANGE 300 @@ -559,4 +589,8 @@ #define CMDTYPE_FRAME_MARKER 0x0004 #define CMDTYPE_STREAM_SURFACE_BITS 0x0006 +#define XRDP_MAX_BITMAP_CACHE_ID 3 +#define XRDP_MAX_BITMAP_CACHE_IDX 2000 +#define XRDP_BITMAP_CACHE_ENTRIES 2048 + #endif diff --git a/configure.ac b/configure.ac index a2a80aa2..6c0134e6 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@ # Process this file with autoconf to produce a configure script AC_PREREQ(2.59) -AC_INIT([xrdp], [0.6.0], [xrdp-devel@lists.sourceforge.net]) +AC_INIT([xrdp], [0.7.0], [xrdp-devel@lists.sourceforge.net]) AC_CONFIG_HEADERS(config_ac.h:config_ac-h.in) AM_INIT_AUTOMAKE([1.6 foreign]) AC_PROG_CC @@ -31,10 +31,6 @@ AC_ARG_ENABLE(xrdpdebug, AS_HELP_STRING([--enable-xrdpdebug], [Build debug (default: no)]), [xrdpdebug=true], [xrdpdebug=false]) AM_CONDITIONAL(XRDP_DEBUG, [test x$xrdpdebug = xtrue]) -AC_ARG_ENABLE(freerdp1, AS_HELP_STRING([--enable-freerdp1], - [Build freerdp1 module (default: no)]), - [freerdp1=true], [freerdp1=false]) -AM_CONDITIONAL(XRDP_FREERDP1, [test x$freerdp1 = xtrue]) AC_ARG_ENABLE(neutrinordp, AS_HELP_STRING([--enable-neutrinordp], [Build neutrinordp module (default: no)]), [neutrinordp=true], [neutrinordp=false]) @@ -43,6 +39,10 @@ AC_ARG_ENABLE(jpeg, AS_HELP_STRING([--enable-jpeg], [Build jpeg module (default: no)]), [jpeg=true], [jpeg=false]) AM_CONDITIONAL(XRDP_JPEG, [test x$jpeg = xtrue]) +AC_ARG_ENABLE(tjpeg, AS_HELP_STRING([--enable-tjpeg], + [Build turbo jpeg module(assumes /opt/libjpeg-turbo) (default: no)]), + [tjpeg=true], [tjpeg=false]) +AM_CONDITIONAL(XRDP_TJPEG, [test x$tjpeg = xtrue]) AC_ARG_ENABLE(simplesound, AS_HELP_STRING([--enable-simplesound], [Build simple pulse audio interface (default: no)]), [simplesound=true], [simplesound=false]) @@ -83,8 +83,6 @@ then AC_DEFINE([USE_NOPAM],1,[Disable PAM]) fi -AS_IF( [test "x$enable_freerdp1" = "xyes"] , [PKG_CHECK_MODULES(FREERDP, freerdp >= 1.0.0)] ) - AS_IF( [test "x$enable_neutrinordp" = "xyes"] , [PKG_CHECK_MODULES(FREERDP, freerdp >= 1.0.0)] ) # checking for libjpeg @@ -94,6 +92,11 @@ then [AC_MSG_ERROR([please install libjpeg-dev or libjpeg-devel])]) fi +if ! test -z "$enable_xrdpdebug" +then + CFLAGS="-g -O0" +fi + # checking for fuse if ! test -z "$enable_fuse" then @@ -128,7 +131,6 @@ AC_CONFIG_FILES([Makefile libxrdp/Makefile xup/Makefile mc/Makefile - freerdp1/Makefile neutrinordp/Makefile xrdp/Makefile sesman/Makefile @@ -141,8 +143,8 @@ AC_CONFIG_FILES([Makefile docs/man/Makefile instfiles/Makefile instfiles/pam.d/Makefile - instfiles/init.d/Makefile - instfiles/default/Makefile + instfiles/init.d/Makefile + instfiles/default/Makefile genkeymap/Makefile xrdpapi/Makefile xrdpvr/Makefile diff --git a/docs/man/sesman.ini.5 b/docs/man/sesman.ini.5 index 2bf69297..84beafb4 100644 --- a/docs/man/sesman.ini.5 +++ b/docs/man/sesman.ini.5 @@ -98,9 +98,8 @@ If unset or set to \fI0\fR, unlimited session are allowed. .TP \fBKillDisconnected\fR=\fI[0|1]\fR -If set to \fB1\fR, \fBtrue\fR or \fByes\fR, every session will be killed when the user disconnects. +If set to \fB1\fR, \fBtrue\fR or \fByes\fR, every session will be killed within 60 seconds when the user disconnects. .br -\fI\-this option is currently ignored!\-\fR .TP \fBIdleTimeLimit\fR=\fI<number>\fR @@ -112,11 +111,10 @@ If set to \fI0\fR, automatic disconnection is disabled. .TP \fBDisconnectedTimeLimit\fR=\fI<number>\fR -Sets the the time limit before a disconnected session is killed. +Sets the time(in seconds) limit before a disconnected session is killed. .br If set to \fI0\fR, automatic killing is disabled. .br -\fI\-this option is currently ignored!\-\fR .SH "SECURITY" The following parameters can be used in the \fB[Sessions]\fR section: diff --git a/freerdp/Makefile.am b/freerdp/Makefile.am deleted file mode 100644 index 21f78741..00000000 --- a/freerdp/Makefile.am +++ /dev/null @@ -1,20 +0,0 @@ -EXTRA_DIST = xrdp-freerdp.h - -AM_CFLAGS = \ - -DXRDP_CFG_PATH=\"${sysconfdir}/xrdp\" \ - -DXRDP_SBIN_PATH=\"${sbindir}\" \ - -DXRDP_SHARE_PATH=\"${datadir}/xrdp\" \ - -DXRDP_PID_PATH=\"${localstatedir}/run\" - -INCLUDES = \ - -I$(top_srcdir)/common \ - $(FREERDP_CFLAGS) - -lib_LTLIBRARIES = \ - libxrdpfreerdp.la - -libxrdpfreerdp_la_SOURCES = xrdp-freerdp.c xrdp-color.c - -libxrdpfreerdp_la_LIBADD = \ - $(top_builddir)/common/libcommon.la \ - $(FREERDP_LIBS) diff --git a/freerdp/xrdp-color.c b/freerdp/xrdp-color.c deleted file mode 100644 index 0ecf4dbf..00000000 --- a/freerdp/xrdp-color.c +++ /dev/null @@ -1,314 +0,0 @@ -/** - * xrdp: A Remote Desktop Protocol server. - * - * Copyright (C) Jay Sorg 2004-2012 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * freerdp wrapper - */ - -#include "xrdp-freerdp.h" - -char *APP_CC -convert_bitmap(int in_bpp, int out_bpp, char *bmpdata, - int width, int height, int *palette) -{ - char *out; - char *src; - char *dst; - int i; - int j; - int red; - int green; - int blue; - int pixel; - - if ((in_bpp == 8) && (out_bpp == 8)) - { - out = (char *)g_malloc(width * height, 0); - src = bmpdata; - dst = out; - - for (i = 0; i < height; i++) - { - for (j = 0; j < width; j++) - { - pixel = *((tui8 *)src); - pixel = palette[pixel]; - SPLITCOLOR32(red, green, blue, pixel); - pixel = COLOR8(red, green, blue); - *dst = pixel; - src++; - dst++; - } - } - - return out; - } - - if ((in_bpp == 8) && (out_bpp == 16)) - { - out = (char *)g_malloc(width * height * 2, 0); - src = bmpdata; - dst = out; - - for (i = 0; i < height; i++) - { - for (j = 0; j < width; j++) - { - pixel = *((tui8 *)src); - pixel = palette[pixel]; - SPLITCOLOR32(red, green, blue, pixel); - pixel = COLOR16(red, green, blue); - *((tui16 *)dst) = pixel; - src++; - dst += 2; - } - } - - return out; - } - - if ((in_bpp == 8) && (out_bpp == 24)) - { - out = (char *)g_malloc(width * height * 4, 0); - src = bmpdata; - dst = out; - - for (i = 0; i < height; i++) - { - for (j = 0; j < width; j++) - { - pixel = *((tui8 *)src); - pixel = palette[pixel]; - SPLITCOLOR32(red, green, blue, pixel); - pixel = COLOR24RGB(red, green, blue); - *((tui32 *)dst) = pixel; - src++; - dst += 4; - } - } - - return out; - } - - if ((in_bpp == 15) && (out_bpp == 16)) - { - out = (char *)g_malloc(width * height * 2, 0); - src = bmpdata; - dst = out; - - for (i = 0; i < height; i++) - { - for (j = 0; j < width; j++) - { - pixel = *((tui16 *)src); - SPLITCOLOR15(red, green, blue, pixel); - pixel = COLOR16(red, green, blue); - *((tui16 *)dst) = pixel; - src += 2; - dst += 2; - } - } - - return out; - } - - if ((in_bpp == 15) && (out_bpp == 24)) - { - out = (char *)g_malloc(width * height * 4, 0); - src = bmpdata; - dst = out; - - for (i = 0; i < height; i++) - { - for (j = 0; j < width; j++) - { - pixel = *((tui16 *)src); - SPLITCOLOR15(red, green, blue, pixel); - pixel = COLOR24RGB(red, green, blue); - *((tui32 *)dst) = pixel; - src += 2; - dst += 4; - } - } - - return out; - } - - if ((in_bpp == 16) && (out_bpp == 16)) - { - return bmpdata; - } - - if ((in_bpp == 16) && (out_bpp == 24)) - { - out = (char *)g_malloc(width * height * 4, 0); - src = bmpdata; - dst = out; - - for (i = 0; i < height; i++) - { - for (j = 0; j < width; j++) - { - pixel = *((tui16 *)src); - SPLITCOLOR16(red, green, blue, pixel); - pixel = COLOR24RGB(red, green, blue); - *((tui32 *)dst) = pixel; - src += 2; - dst += 4; - } - } - - return out; - } - - if ((in_bpp == 24) && (out_bpp == 24)) - { - out = (char *)g_malloc(width * height * 4, 0); - src = bmpdata; - dst = out; - - for (i = 0; i < height; i++) - { - for (j = 0; j < width; j++) - { - blue = *((tui8 *)src); - src++; - green = *((tui8 *)src); - src++; - red = *((tui8 *)src); - src++; - pixel = COLOR24RGB(red, green, blue); - *((tui32 *)dst) = pixel; - dst += 4; - } - } - - return out; - } - - if ((in_bpp == 32) && (out_bpp == 24)) - { - return bmpdata; - } - - if ((in_bpp == 32) && (out_bpp == 32)) - { - return bmpdata; - } - - if ((in_bpp == 15) && (out_bpp == 15)) - { - return bmpdata; - } - - g_writeln("convert_bitmap: error unknown conversion from %d to %d", - in_bpp, out_bpp); - return 0; -} - -/*****************************************************************************/ -/* returns color or 0 */ -int APP_CC -convert_color(int in_bpp, int out_bpp, int in_color, int *palette) -{ - int pixel; - int red; - int green; - int blue; - - if ((in_bpp == 1) && (out_bpp == 24)) - { - pixel = in_color == 0 ? 0 : 0xffffff; - return pixel; - } - - if ((in_bpp == 8) && (out_bpp == 8)) - { - pixel = palette[in_color]; - SPLITCOLOR32(red, green, blue, pixel); - pixel = COLOR8(red, green, blue); - return pixel; - } - - if ((in_bpp == 8) && (out_bpp == 16)) - { - pixel = palette[in_color]; - SPLITCOLOR32(red, green, blue, pixel); - pixel = COLOR16(red, green, blue); - return pixel; - } - - if ((in_bpp == 8) && (out_bpp == 24)) - { - pixel = palette[in_color]; - SPLITCOLOR32(red, green, blue, pixel); - pixel = COLOR24BGR(red, green, blue); - return pixel; - } - - if ((in_bpp == 15) && (out_bpp == 16)) - { - pixel = in_color; - SPLITCOLOR15(red, green, blue, pixel); - pixel = COLOR16(red, green, blue); - return pixel; - } - - if ((in_bpp == 15) && (out_bpp == 24)) - { - pixel = in_color; - SPLITCOLOR15(red, green, blue, pixel); - pixel = COLOR24BGR(red, green, blue); - return pixel; - } - - if ((in_bpp == 16) && (out_bpp == 16)) - { - return in_color; - } - - if ((in_bpp == 16) && (out_bpp == 24)) - { - pixel = in_color; - SPLITCOLOR16(red, green, blue, pixel); - pixel = COLOR24BGR(red, green, blue); - return pixel; - } - - if ((in_bpp == 24) && (out_bpp == 24)) - { - return in_color; - } - - if ((in_bpp == 32) && (out_bpp == 24)) - { - return in_color; - } - - if ((in_bpp == 32) && (out_bpp == 32)) - { - return in_color; - } - - if ((in_bpp == 15) && (out_bpp == 15)) - { - return in_color; - } - - g_writeln("convert_color: error unknown conversion from %d to %d", - in_bpp, out_bpp); - return 0; -} diff --git a/freerdp/xrdp-freerdp.c b/freerdp/xrdp-freerdp.c deleted file mode 100644 index 5ee58800..00000000 --- a/freerdp/xrdp-freerdp.c +++ /dev/null @@ -1,1049 +0,0 @@ -/** - * xrdp: A Remote Desktop Protocol server. - * - * Copyright (C) Jay Sorg 2004-2012 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * freerdp wrapper - */ - -#include "xrdp-freerdp.h" -#include "xrdp-color.h" - -#define GET_MOD(_inst) ((struct mod*)((_inst)->param1)) -#define SET_MOD(_inst, _mod) ((_inst)->param1) = _mod - -struct my_bitmap -{ - char *data; - int width; - int height; - int bpp; -}; - -struct my_cursor -{ - char *andmask; - int andbpp; - char *xormask; - int xorbpp; - int width; - int height; - int hotx; - int hoty; -}; - -/*****************************************************************************/ -/* return error */ -static int DEFAULT_CC -lib_mod_start(struct mod *mod, int w, int h, int bpp) -{ - LIB_DEBUG(mod, "in lib_mod_start"); - g_writeln("lib_mod_start: w %d h %d bpp %d", w, h, bpp); - mod->width = w; - mod->height = h; - mod->bpp = bpp; - - if (bpp == 24) - { - mod->settings->server_depth = 32; - } - else - { - mod->settings->server_depth = mod->bpp; - } - - mod->settings->width = mod->width; - mod->settings->height = mod->height; - LIB_DEBUG(mod, "out lib_mod_start"); - return 0; -} - -/******************************************************************************/ -/* return error */ -static int DEFAULT_CC -lib_mod_connect(struct mod *mod) -{ - int code; - - LIB_DEBUG(mod, "in lib_mod_connect"); - code = mod->inst->rdp_connect(mod->inst); - g_writeln("lib_mod_connect: code %d", code); - LIB_DEBUG(mod, "out lib_mod_connect"); - return code; -} - -/******************************************************************************/ -/* return error */ -static int DEFAULT_CC -lib_mod_event(struct mod *mod, int msg, long param1, long param2, - long param3, long param4) -{ - LIB_DEBUG(mod, "in lib_mod_event"); - int ext; - - //g_writeln("%d %d %d %d %d", msg, param1, param2, param3, param4); - switch (msg) - { - case 15: - ext = param4 & 0x100 ? 1 : 0; - mod->inst->rdp_send_input_scancode(mod->inst, 0, ext, param3); - break; - case 16: - ext = param4 & 0x100 ? 1 : 0; - mod->inst->rdp_send_input_scancode(mod->inst, 1, ext, param3); - break; - case 17: - mod->inst->rdp_sync_input(mod->inst, param4); - break; - case 100: - mod->inst->rdp_send_input_mouse(mod->inst, PTRFLAGS_MOVE, - param1, param2); - break; - case 101: - mod->inst->rdp_send_input_mouse(mod->inst, PTRFLAGS_BUTTON1, - param1, param2); - break; - case 102: - mod->inst->rdp_send_input_mouse(mod->inst, - PTRFLAGS_BUTTON1 | PTRFLAGS_DOWN, - param1, param2); - break; - case 103: - mod->inst->rdp_send_input_mouse(mod->inst, - PTRFLAGS_BUTTON2, param1, param2); - break; - case 104: - mod->inst->rdp_send_input_mouse(mod->inst, - PTRFLAGS_BUTTON2 | PTRFLAGS_DOWN, - param1, param2); - break; - case 105: - mod->inst->rdp_send_input_mouse(mod->inst, - PTRFLAGS_BUTTON3, param1, param2); - break; - case 106: - mod->inst->rdp_send_input_mouse(mod->inst, - PTRFLAGS_BUTTON3 | PTRFLAGS_DOWN, - param1, param2); - break; - case 107: - mod->inst->rdp_send_input_mouse(mod->inst, - PTRFLAGS_WHEEL | 0x0078, 0, 0); - break; - case 108: - break; - case 109: - mod->inst->rdp_send_input_mouse(mod->inst, - PTRFLAGS_WHEEL | - PTRFLAGS_WHEEL_NEGATIVE | 0x0088, 0, 0); - break; - case 110: - break; - } - - LIB_DEBUG(mod, "out lib_mod_event"); - return 0; -} - -/******************************************************************************/ -/* return error */ -static int DEFAULT_CC -lib_mod_signal(struct mod *mod) -{ - LIB_DEBUG(mod, "in lib_mod_signal"); - g_writeln("lib_mod_signal:"); - LIB_DEBUG(mod, "out lib_mod_signal"); - return 0; -} - -/******************************************************************************/ -/* return error */ -static int DEFAULT_CC -lib_mod_end(struct mod *mod) -{ - g_writeln("lib_mod_end:"); - return 0; -} - -/******************************************************************************/ -/* return error */ -static int DEFAULT_CC -lib_mod_set_param(struct mod *mod, char *name, char *value) -{ - g_writeln("lib_mod_set_param: name [%s] value [%s]", name, value); - - if (g_strcmp(name, "hostname") == 0) - { - g_strncpy(mod->settings->hostname, value, sizeof(mod->settings->hostname)); - } - else if (g_strcmp(name, "ip") == 0) - { - g_strncpy(mod->settings->server, value, sizeof(mod->settings->server)); - } - else if (g_strcmp(name, "port") == 0) - { - mod->settings->tcp_port_rdp = g_atoi(value); - } - else if (g_strcmp(name, "keylayout") == 0) - { - mod->settings->keyboard_layout = g_atoi(value); - } - else if (g_strcmp(name, "name") == 0) - { - } - else if (g_strcmp(name, "lib") == 0) - { - } - else - { - g_writeln("lib_mod_set_param: unknown name [%s] value [%s]", name, value); - } - - return 0; -} - -/******************************************************************************/ -static int DEFAULT_CC -mod_session_change(struct mod *v, int a, int b) -{ - g_writeln("mod_session_change:"); - return 0; -} - -/******************************************************************************/ -static int DEFAULT_CC -mod_get_wait_objs(struct mod *v, tbus *read_objs, int *rcount, - tbus *write_objs, int *wcount, int *timeout) -{ - void **rfds; - void **wfds; - - rfds = (void **)read_objs; - wfds = (void **)write_objs; - return v->inst->rdp_get_fds(v->inst, rfds, rcount, wfds, wcount); -} - -/******************************************************************************/ -static int DEFAULT_CC -mod_check_wait_objs(struct mod *v) -{ - return v->inst->rdp_check_fds(v->inst); -} - -/******************************************************************************/ -static void DEFAULT_CC -ui_error(rdpInst *inst, const char *text) -{ - g_writeln("ui_error: %s", text); -} - -/******************************************************************************/ -static void DEFAULT_CC -ui_warning(rdpInst *inst, const char *text) -{ - g_writeln("ui_warning: %s", text); -} - -/******************************************************************************/ -static void DEFAULT_CC -ui_unimpl(rdpInst *inst, const char *text) -{ - g_writeln("ui_unimpl: %s", text); -} - -/******************************************************************************/ -static void DEFAULT_CC -ui_begin_update(rdpInst *inst) -{ - struct mod *mod; - - mod = GET_MOD(inst); - mod->server_begin_update(mod); -} - -/******************************************************************************/ -static void DEFAULT_CC -ui_end_update(rdpInst *inst) -{ - struct mod *mod; - - mod = GET_MOD(inst); - mod->server_end_update(mod); -} - -/******************************************************************************/ -static void DEFAULT_CC -ui_desktop_save(rdpInst *inst, int offset, int x, int y, - int cx, int cy) -{ - g_writeln("ui_desktop_save:"); -} - -/******************************************************************************/ -static void DEFAULT_CC -ui_desktop_restore(rdpInst *inst, int offset, int x, int y, - int cx, int cy) -{ - g_writeln("ui_desktop_restore:"); -} - -/******************************************************************************/ -static RD_HBITMAP DEFAULT_CC -ui_create_bitmap(rdpInst *inst, int width, int height, uint8 *data) -{ - struct my_bitmap *bm; - struct mod *mod; - int size; - int bpp; - char *bmpdata; - - mod = GET_MOD(inst); - bpp = mod->bpp == 24 ? 32 : mod->bpp; - bm = (struct my_bitmap *)g_malloc(sizeof(struct my_bitmap), 1); - bm->width = width; - bm->height = height; - bm->bpp = bpp; - bmpdata = convert_bitmap(mod->settings->server_depth, bpp, - data, width, height, mod->cmap); - - if (bmpdata == (char *)data) - { - size = width * height * ((bpp + 7) / 8); - bm->data = (char *)g_malloc(size, 0); - g_memcpy(bm->data, bmpdata, size); - } - else - { - bm->data = bmpdata; - } - - return bm; -} - -/******************************************************************************/ -static void DEFAULT_CC -ui_paint_bitmap(rdpInst *inst, int x, int y, int cx, int cy, int width, - int height, uint8 *data) -{ - struct mod *mod; - char *bmpdata; - - mod = GET_MOD(inst); - bmpdata = convert_bitmap(mod->settings->server_depth, mod->bpp, - data, width, height, mod->cmap); - - if (bmpdata != 0) - { - mod->server_paint_rect(mod, x, y, cx, cy, bmpdata, width, height, 0, 0); - } - - if (bmpdata != (char *)data) - { - g_free(bmpdata); - } -} - -/******************************************************************************/ -static void DEFAULT_CC -ui_destroy_bitmap(rdpInst *inst, RD_HBITMAP bmp) -{ - struct my_bitmap *bm; - - bm = (struct my_bitmap *)bmp; - g_free(bm->data); - g_free(bm); -} - -/******************************************************************************/ -static void DEFAULT_CC -ui_line(rdpInst *inst, uint8 opcode, int startx, int starty, int endx, - int endy, RD_PEN *pen) -{ - g_writeln("ui_line:"); -} - -/******************************************************************************/ -static void DEFAULT_CC -ui_rect(rdpInst *inst, int x, int y, int cx, int cy, uint32 color) -{ - struct mod *mod; - - mod = GET_MOD(inst); - color = convert_color(mod->settings->server_depth, mod->bpp, - color, mod->cmap); - mod->server_set_fgcolor(mod, color); - mod->server_fill_rect(mod, x, y, cx, cy); -} - -/******************************************************************************/ -static void DEFAULT_CC -ui_polygon(rdpInst *inst, uint8 opcode, uint8 fillmode, RD_POINT *point, - int npoints, RD_BRUSH *brush, uint32 bgcolor, uint32 fgcolor) -{ - g_writeln("ui_polygon:"); -} - -/******************************************************************************/ -static void DEFAULT_CC -ui_polyline(rdpInst *inst, uint8 opcode, RD_POINT *points, int npoints, - RD_PEN *pen) -{ - g_writeln("ui_polyline:"); -} - -/******************************************************************************/ -static void DEFAULT_CC -ui_ellipse(rdpInst *inst, uint8 opcode, uint8 fillmode, int x, int y, - int cx, int cy, RD_BRUSH *brush, uint32 bgcolor, uint32 fgcolor) -{ - g_writeln("ui_ellipse:"); -} - -/******************************************************************************/ -static void DEFAULT_CC -ui_add_char(rdpInst *inst, uint8 font, uint16 character, sint16 offset, - sint16 baseline, uint16 width, uint16 height, uint8 *data) -{ - struct mod *mod; - - //g_writeln("ui_add_char:"); - mod = GET_MOD(inst); - mod->server_add_char(mod, font, character, offset, baseline, - width, height, (char *)data); -} - -/******************************************************************************/ -static void DEFAULT_CC -ui_draw_text(rdpInst *inst, 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, RD_BRUSH *brush, - uint32 bgcolor, uint32 fgcolor, uint8 *text, uint8 length) -{ - struct mod *mod; - - //g_writeln("ui_draw_text: flags %d mixmode %d x %d y %d", flags, mixmode, x, y); - //g_writeln("%d %d %d %d %d %d %d %d", clipx, clipy, clipcx, clipcy, boxx, boxy, boxcx, boxcy); - mod = GET_MOD(inst); - fgcolor = convert_color(mod->settings->server_depth, mod->bpp, - fgcolor, mod->cmap); - mod->server_set_fgcolor(mod, fgcolor); - bgcolor = convert_color(mod->settings->server_depth, mod->bpp, - bgcolor, mod->cmap); - mod->server_set_bgcolor(mod, bgcolor); - mod->server_draw_text(mod, font, flags, mixmode, - clipx, clipy, clipx + clipcx, clipy + clipcy, - boxx, boxy, boxx + boxcx, boxy + boxcy, x, y, - (char *)text, length); -} - -/******************************************************************************/ -static void DEFAULT_CC -ui_start_draw_glyphs(rdpInst *inst, uint32 bgcolor, uint32 fgcolor) -{ - g_writeln("ui_start_draw_glyphs:"); -} - -/******************************************************************************/ -static void DEFAULT_CC -ui_draw_glyph(rdpInst *inst, int x, int y, int cx, int cy, - RD_HGLYPH glyph) -{ - g_writeln("ui_draw_glyph:"); -} - -/******************************************************************************/ -static void DEFAULT_CC -ui_end_draw_glyphs(rdpInst *inst, int x, int y, int cx, int cy) -{ - g_writeln("ui_end_draw_glyphs:"); -} - -/******************************************************************************/ -static uint32 DEFAULT_CC -ui_get_toggle_keys_state(rdpInst *inst) -{ - g_writeln("ui_get_toggle_keys_state:"); - return 0; -} - -/******************************************************************************/ -static void DEFAULT_CC -ui_bell(rdpInst *inst) -{ - g_writeln("ui_bell:"); -} - -/******************************************************************************/ -static void DEFAULT_CC -ui_destblt(rdpInst *inst, uint8 opcode, int x, int y, int cx, int cy) -{ - struct mod *mod; - - g_writeln("ui_destblt:"); - mod = GET_MOD(inst); - mod->server_set_opcode(mod, opcode); - mod->server_fill_rect(mod, x, y, cx, cy); - mod->server_set_opcode(mod, 0xcc); -} - -/******************************************************************************/ -static void DEFAULT_CC -ui_patblt(rdpInst *inst, uint8 opcode, int x, int y, int cx, int cy, - RD_BRUSH *brush, uint32 bgcolor, uint32 fgcolor) -{ - struct mod *mod; - uint8 idata[8]; - int index; - - mod = GET_MOD(inst); - mod->server_set_opcode(mod, opcode); - fgcolor = convert_color(mod->settings->server_depth, mod->bpp, - fgcolor, mod->cmap); - mod->server_set_fgcolor(mod, fgcolor); - bgcolor = convert_color(mod->settings->server_depth, mod->bpp, - bgcolor, mod->cmap); - mod->server_set_bgcolor(mod, bgcolor); - mod->server_set_mixmode(mod, 1); - - if (brush->bd != 0) - { - if (brush->bd->color_code == 1) /* 8x8 1 bpp */ - { - for (index = 0; index < 8; index++) - { - idata[index] = ~(brush->bd->data[index]); - } - - mod->server_set_brush(mod, brush->xorigin, brush->yorigin, - brush->style, idata); - } - else - { - g_writeln("ui_patblt: error color_code %d", brush->bd->color_code); - } - } - else - { - for (index = 0; index < 8; index++) - { - idata[index] = ~(brush->pattern[index]); - } - - mod->server_set_brush(mod, brush->xorigin, brush->yorigin, - brush->style, idata); - } - - mod->server_fill_rect(mod, x, y, cx, cy); - mod->server_set_opcode(mod, 0xcc); - mod->server_set_mixmode(mod, 0); -} - -/******************************************************************************/ -static void DEFAULT_CC -ui_screenblt(rdpInst *inst, uint8 opcode, int x, int y, int cx, int cy, - int srcx, int srcy) -{ - struct mod *mod; - - mod = GET_MOD(inst); - mod->server_set_opcode(mod, opcode); - mod->server_screen_blt(mod, x, y, cx, cy, srcx, srcy); - mod->server_set_opcode(mod, 0xcc); -} - -/******************************************************************************/ -static void DEFAULT_CC -ui_memblt(rdpInst *inst, uint8 opcode, int x, int y, int cx, int cy, - RD_HBITMAP src, int srcx, int srcy) -{ - struct my_bitmap *bitmap; - struct mod *mod; - char *bmpdata; - - mod = GET_MOD(inst); - bitmap = (struct my_bitmap *)src; - mod->server_set_opcode(mod, opcode); - mod->server_paint_rect(mod, x, y, cx, cy, bitmap->data, - bitmap->width, bitmap->height, srcx, srcy); - mod->server_set_opcode(mod, 0xcc); -} - -/******************************************************************************/ -static void DEFAULT_CC -ui_triblt(rdpInst *inst, uint8 opcode, int x, int y, int cx, int cy, - RD_HBITMAP src, int srcx, int srcy, RD_BRUSH *brush, - uint32 bgcolor, uint32 fgcolor) -{ - g_writeln("ui_triblt:"); -} - -/******************************************************************************/ -static RD_HGLYPH DEFAULT_CC -ui_create_glyph(rdpInst *inst, int width, int height, uint8 *data) -{ - g_writeln("ui_create_glyph:"); - return 0; -} - -/******************************************************************************/ -static void DEFAULT_CC -ui_destroy_glyph(rdpInst *inst, RD_HGLYPH glyph) -{ - g_writeln("ui_destroy_glyph:"); -} - -/******************************************************************************/ -static int DEFAULT_CC -ui_select(rdpInst *inst, int rdp_socket) -{ - return 1; -} - -/******************************************************************************/ -static void DEFAULT_CC -ui_set_clip(rdpInst *inst, int x, int y, int cx, int cy) -{ - struct mod *mod; - - mod = GET_MOD(inst); - mod->server_set_clip(mod, x, y, cx, cy); -} - -/******************************************************************************/ -static void DEFAULT_CC -ui_reset_clip(rdpInst *inst) -{ - struct mod *mod; - - mod = GET_MOD(inst); - mod->server_reset_clip(mod); -} - -/******************************************************************************/ -static void DEFAULT_CC -ui_resize_window(rdpInst *inst) -{ - g_writeln("ui_resize_window:"); -} - -/******************************************************************************/ -static void DEFAULT_CC -ui_set_cursor(rdpInst *inst, RD_HCURSOR cursor) -{ - struct mod *mod; - struct my_cursor *cur; - - //g_writeln("ui_set_cursor:"); - mod = GET_MOD(inst); - cur = (struct my_cursor *)cursor; - - if (cur != 0) - { - mod->server_set_cursor(mod, cur->hotx, cur->hoty, - cur->xormask, cur->andmask); - } - else - { - g_writeln("ui_set_cursor: nil cursor"); - } -} - -/******************************************************************************/ -static void DEFAULT_CC -ui_destroy_cursor(rdpInst *inst, RD_HCURSOR cursor) -{ - struct my_cursor *cur; - - //g_writeln("ui_destroy_cursor:"); - cur = (struct my_cursor *)cursor; - - if (cur != 0) - { - g_free(cur->andmask); - g_free(cur->xormask); - } - - g_free(cur); -} - -#define RGB24(_r, _g, _b) \ - (_r << 16) | (_g << 8) | _b; - -/******************************************************************************/ -static int -l_get_pixel(tui8 *data, int x, int y, int width, int height, int bpp) -{ - int start; - int shift; - tui16 *src16; - tui32 *src32; - int red, green, blue; - - switch (bpp) - { - case 1: - width = (width + 7) / 8; - start = (y * width) + x / 8; - shift = x % 8; - return (data[start] & (0x80 >> shift)) != 0; - case 8: - return data[y * width + x]; - case 15: - case 16: - src16 = (uint16 *) data; - return src16[y * width + x]; - case 24: - data += y * width * 3; - data += x * 3; - red = data[0]; - green = data[1]; - blue = data[2]; - return RGB24(red, green, blue); - case 32: - src32 = (uint32 *) data; - return src32[y * width + x]; - default: - g_writeln("l_get_pixel: unknown bpp %d", bpp); - break; - } - - return 0; -} - -/******************************************************************************/ -static void -l_set_pixel(tui8 *data, int x, int y, int width, int height, - int bpp, int pixel) -{ - int start; - int shift; - int *dst32; - tui8 *dst8; - - if (bpp == 1) - { - width = (width + 7) / 8; - start = (y * width) + x / 8; - shift = x % 8; - - if (pixel) - { - data[start] = data[start] | (0x80 >> shift); - } - else - { - data[start] = data[start] & ~(0x80 >> shift); - } - } - else if (bpp == 24) - { - dst8 = data + (y * width + x) * 3; - *(dst8++) = (pixel >> 16) & 0xff; - *(dst8++) = (pixel >> 8) & 0xff; - *(dst8++) = (pixel >> 0) & 0xff; - } - else if (bpp == 32) - { - dst32 = (int *) data; - dst32[y * width + x] = pixel; - } - else - { - g_writeln("l_set_pixel: unknown bpp %d", bpp); - } -} - - -/******************************************************************************/ -/* andmask = mask = 32 * 32 / 8 - xormask = data = 32 * 32 * 3 */ -static RD_HCURSOR DEFAULT_CC -ui_create_cursor(rdpInst *inst, unsigned int x, unsigned int y, - int width, int height, uint8 *andmask, - uint8 *xormask, int bpp) -{ - struct mod *mod; - struct my_cursor *cur; - int i; - int j; - int jj; - int apixel; - int xpixel; - char *dst; - - mod = GET_MOD(inst); - g_writeln("ui_create_cursor: x %d y %d width %d height %d bpp %d", - x, y, width, height, bpp); - cur = (struct my_cursor *)g_malloc(sizeof(struct my_cursor), 1); - cur->width = width; - cur->height = height; - cur->hotx = x; - cur->hoty = y; - cur->andmask = g_malloc(32 * 32 * 4, 1); - cur->xormask = g_malloc(32 * 32 * 4, 1); - - for (j = 0; j < height; j++) - { - jj = (bpp != 1) ? j : (height - 1) - j; - - for (i = 0; i < width; i++) - { - apixel = l_get_pixel(andmask, i, jj, width, height, 1); - xpixel = l_get_pixel(xormask, i, jj, width, height, bpp); - xpixel = convert_color(bpp, 24, xpixel, mod->cmap); - l_set_pixel(cur->andmask, i, j, width, height, 1, apixel); - l_set_pixel(cur->xormask, i, j, width, height, 24, xpixel); - } - } - - return (RD_HCURSOR)cur; -} - -/******************************************************************************/ -static void DEFAULT_CC -ui_set_null_cursor(rdpInst *inst) -{ - g_writeln("ui_set_null_cursor:"); -} - -/******************************************************************************/ -static void DEFAULT_CC -ui_set_default_cursor(rdpInst *inst) -{ - g_writeln("ui_set_default_cursor:"); -} - -/******************************************************************************/ -static RD_HPALETTE DEFAULT_CC -ui_create_palette(rdpInst *inst, RD_PALETTE *colors) -{ - struct mod *mod; - int index; - int red; - int green; - int blue; - int pixel; - int count; - int *cmap; - - mod = GET_MOD(inst); - g_writeln("ui_create_palette:"); - count = 256; - - if (count > colors->count) - { - count = colors->count; - } - - cmap = (int *)g_malloc(256 * 4, 1); - - for (index = 0; index < count; index++) - { - red = colors->entries[index].red; - green = colors->entries[index].green; - blue = colors->entries[index].blue; - pixel = COLOR24RGB(red, green, blue); - cmap[index] = pixel; - } - - return (RD_HPALETTE)cmap; -} - -/******************************************************************************/ -static void DEFAULT_CC -ui_move_pointer(rdpInst *inst, int x, int y) -{ - g_writeln("ui_move_pointer:"); -} - -/******************************************************************************/ -static void DEFAULT_CC -ui_set_palette(rdpInst *inst, RD_HPALETTE map) -{ - struct mod *mod; - - mod = GET_MOD(inst); - g_writeln("ui_set_palette:"); - g_memcpy(mod->cmap, map, 256 * 4); - g_free(map); -} - -/******************************************************************************/ -static RD_HBITMAP DEFAULT_CC -ui_create_surface(rdpInst *inst, int width, int height, RD_HBITMAP old) -{ - g_writeln("ui_create_surface:"); - return 0; -} - -/******************************************************************************/ -static void DEFAULT_CC -ui_set_surface(rdpInst *inst, RD_HBITMAP surface) -{ - g_writeln("ui_set_surface:"); -} - -/******************************************************************************/ -static void DEFAULT_CC -ui_destroy_surface(rdpInst *inst, RD_HBITMAP surface) -{ - g_writeln("ui_destroy_surface:"); -} - -/******************************************************************************/ -static void DEFAULT_CC -ui_channel_data(rdpInst *inst, int chan_id, char *data, int data_size, - int flags, int total_size) -{ - g_writeln("ui_channel_data:"); -} - -/******************************************************************************/ -static RD_BOOL DEFAULT_CC -ui_authenticate(rdpInst *inst) -{ - return 1; -} - -/******************************************************************************/ -static int DEFAULT_CC -ui_decode(rdpInst *inst, uint8 *data, int data_size) -{ - return 0; -} - -/******************************************************************************/ -static RD_BOOL DEFAULT_CC -ui_check_certificate(rdpInst *inst, const char *fingerprint, - const char *subject, const char *issuer, RD_BOOL verified) -{ - return 1; -} - -/******************************************************************************/ -struct mod *EXPORT_CC -mod_init(void) -{ - struct mod *mod; - - //g_writeln("1"); - //freerdp_global_init(); - //g_writeln("2"); - mod = (struct mod *)g_malloc(sizeof(struct mod), 1); - mod->size = sizeof(struct mod); - mod->version = CURRENT_MOD_VER; - mod->handle = (tbus)mod; - mod->mod_connect = lib_mod_connect; - mod->mod_start = lib_mod_start; - mod->mod_event = lib_mod_event; - mod->mod_signal = lib_mod_signal; - mod->mod_end = lib_mod_end; - mod->mod_set_param = lib_mod_set_param; - mod->mod_session_change = mod_session_change; - mod->mod_get_wait_objs = mod_get_wait_objs; - mod->mod_check_wait_objs = mod_check_wait_objs; - mod->settings = (struct rdp_set *)g_malloc(sizeof(struct rdp_set), 1); - - mod->settings->width = 1280; - mod->settings->height = 1024; - mod->settings->encryption = 1; - mod->settings->rdp_security = 1; - mod->settings->tls_security = 1; - mod->settings->server_depth = 16; - mod->settings->bitmap_cache = 1; - mod->settings->bitmap_compression = 1; - mod->settings->performanceflags = - PERF_DISABLE_WALLPAPER | PERF_DISABLE_FULLWINDOWDRAG | PERF_DISABLE_MENUANIMATIONS; - mod->settings->new_cursors = 1; - mod->settings->rdp_version = 5; - mod->settings->text_flags = 1; - - mod->inst = freerdp_new(mod->settings); - - if (mod->inst == 0) - { - return 0; - } - - SET_MOD(mod->inst, mod); - mod->inst->ui_error = ui_error; - mod->inst->ui_warning = ui_warning; - mod->inst->ui_unimpl = ui_unimpl; - mod->inst->ui_begin_update = ui_begin_update; - mod->inst->ui_end_update = ui_end_update; - mod->inst->ui_desktop_save = ui_desktop_save; - mod->inst->ui_desktop_restore = ui_desktop_restore; - mod->inst->ui_create_bitmap = ui_create_bitmap; - mod->inst->ui_paint_bitmap = ui_paint_bitmap; - mod->inst->ui_destroy_bitmap = ui_destroy_bitmap; - mod->inst->ui_line = ui_line; - mod->inst->ui_rect = ui_rect; - mod->inst->ui_polygon = ui_polygon; - mod->inst->ui_polyline = ui_polyline; - mod->inst->ui_ellipse = ui_ellipse; - mod->inst->ui_add_char = ui_add_char; - mod->inst->ui_draw_text = ui_draw_text; - mod->inst->ui_start_draw_glyphs = ui_start_draw_glyphs; - mod->inst->ui_draw_glyph = ui_draw_glyph; - mod->inst->ui_end_draw_glyphs = ui_end_draw_glyphs; - mod->inst->ui_get_toggle_keys_state = ui_get_toggle_keys_state; - mod->inst->ui_bell = ui_bell; - mod->inst->ui_destblt = ui_destblt; - mod->inst->ui_patblt = ui_patblt; - mod->inst->ui_screenblt = ui_screenblt; - mod->inst->ui_memblt = ui_memblt; - mod->inst->ui_triblt = ui_triblt; - mod->inst->ui_create_glyph = ui_create_glyph; - mod->inst->ui_destroy_glyph = ui_destroy_glyph; - mod->inst->ui_select = ui_select; - mod->inst->ui_set_clip = ui_set_clip; - mod->inst->ui_reset_clip = ui_reset_clip; - mod->inst->ui_resize_window = ui_resize_window; - mod->inst->ui_set_cursor = ui_set_cursor; - mod->inst->ui_destroy_cursor = ui_destroy_cursor; - mod->inst->ui_create_cursor = ui_create_cursor; - mod->inst->ui_set_null_cursor = ui_set_null_cursor; - mod->inst->ui_set_default_cursor = ui_set_default_cursor; - mod->inst->ui_create_palette = ui_create_palette; - mod->inst->ui_move_pointer = ui_move_pointer; - mod->inst->ui_set_palette = ui_set_palette; - mod->inst->ui_create_surface = ui_create_surface; - mod->inst->ui_set_surface = ui_set_surface; - mod->inst->ui_destroy_surface = ui_destroy_surface; - mod->inst->ui_channel_data = ui_channel_data; - - mod->inst->ui_authenticate = ui_authenticate; - mod->inst->ui_decode = ui_decode; - mod->inst->ui_check_certificate = ui_check_certificate; - - return mod; -} - -/******************************************************************************/ -int EXPORT_CC -mod_exit(struct mod *mod) -{ - if (mod == 0) - { - return 0; - } - - freerdp_free(mod->inst); - g_free(mod->settings); - g_free(mod); - //freerdp_global_finish(); - return 0; -} diff --git a/freerdp/xrdp-freerdp.h b/freerdp/xrdp-freerdp.h deleted file mode 100644 index b62c8206..00000000 --- a/freerdp/xrdp-freerdp.h +++ /dev/null @@ -1,105 +0,0 @@ -/** - * xrdp: A Remote Desktop Protocol server. - * - * Copyright (C) Jay Sorg 2004-2012 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * freerdp wrapper - */ - -/* include other h files */ -#include "arch.h" -#include "parse.h" -#include "os_calls.h" -#include "defines.h" - -/* this is the freerdp main header */ -#include <freerdp/freerdp.h> - -#define CURRENT_MOD_VER 2 - -struct mod -{ - int size; /* size of this struct */ - int version; /* internal version */ - /* client functions */ - int (*mod_start)(struct mod* v, int w, int h, int bpp); - int (*mod_connect)(struct mod* v); - int (*mod_event)(struct mod* v, int msg, long param1, long param2, - long param3, long param4); - int (*mod_signal)(struct mod* v); - int (*mod_end)(struct mod* v); - int (*mod_set_param)(struct mod* v, char* name, char* value); - int (*mod_session_change)(struct mod* v, int, int); - int (*mod_get_wait_objs)(struct mod* v, tbus* read_objs, int* rcount, - tbus* write_objs, int* wcount, int* timeout); - int (*mod_check_wait_objs)(struct mod* v); - long mod_dumby[100 - 9]; /* align, 100 minus the number of mod - functions above */ - /* server functions */ - int (*server_begin_update)(struct mod* v); - int (*server_end_update)(struct mod* v); - int (*server_fill_rect)(struct mod* v, int x, int y, int cx, int cy); - int (*server_screen_blt)(struct mod* v, int x, int y, int cx, int cy, - int srcx, int srcy); - int (*server_paint_rect)(struct mod* v, int x, int y, int cx, int cy, - char* data, int width, int height, int srcx, int srcy); - int (*server_set_cursor)(struct mod* v, int x, int y, char* data, char* mask); - int (*server_palette)(struct mod* v, int* palette); - int (*server_msg)(struct mod* v, char* msg, int code); - int (*server_is_term)(struct mod* v); - int (*server_set_clip)(struct mod* v, int x, int y, int cx, int cy); - int (*server_reset_clip)(struct mod* v); - int (*server_set_fgcolor)(struct mod* v, int fgcolor); - int (*server_set_bgcolor)(struct mod* v, int bgcolor); - int (*server_set_opcode)(struct mod* v, int opcode); - int (*server_set_mixmode)(struct mod* v, int mixmode); - int (*server_set_brush)(struct mod* v, int x_orgin, int y_orgin, - int style, char* pattern); - int (*server_set_pen)(struct mod* v, int style, - int width); - int (*server_draw_line)(struct mod* v, int x1, int y1, int x2, int y2); - int (*server_add_char)(struct mod* v, int font, int charactor, - int offset, int baseline, - int width, int height, char* data); - int (*server_draw_text)(struct mod* v, int font, - int flags, int mixmode, int clip_left, int clip_top, - int clip_right, int clip_bottom, - int box_left, int box_top, - int box_right, int box_bottom, - int x, int y, char* data, int data_len); - int (*server_reset)(struct mod* v, int width, int height, int bpp); - int (*server_query_channel)(struct mod* v, int index, - char* channel_name, - int* channel_flags); - int (*server_get_channel_id)(struct mod* v, char* name); - int (*server_send_to_channel)(struct mod* v, int channel_id, - char* data, int data_len, - int total_data_len, int flags); - int (*server_bell_trigger)(struct mod* v); - long server_dumby[100 - 25]; /* align, 100 minus the number of server - functions above */ - /* common */ - tbus handle; /* pointer to self as long */ - tbus wm; - tbus painter; - int sck; - /* mod data */ - int width; - int height; - int bpp; - struct rdp_set* settings; - struct rdp_inst* inst; - int cmap[256]; -}; diff --git a/freerdp1/Makefile.am b/freerdp1/Makefile.am deleted file mode 100644 index d1d49440..00000000 --- a/freerdp1/Makefile.am +++ /dev/null @@ -1,28 +0,0 @@ -EXTRA_DIST = xrdp-freerdp.h -EXTRA_DEFINES = - -if XRDP_DEBUG -EXTRA_DEFINES += -DXRDP_DEBUG -else -EXTRA_DEFINES += -DXRDP_NODEBUG -endif - -AM_CFLAGS = \ - -DXRDP_CFG_PATH=\"${sysconfdir}/xrdp\" \ - -DXRDP_SBIN_PATH=\"${sbindir}\" \ - -DXRDP_SHARE_PATH=\"${datadir}/xrdp\" \ - -DXRDP_PID_PATH=\"${localstatedir}/run\" \ - $(EXTRA_DEFINES) - -INCLUDES = \ - -I$(top_srcdir)/common \ - $(FREERDP_CFLAGS) - -lib_LTLIBRARIES = \ - libxrdpfreerdp1.la - -libxrdpfreerdp1_la_SOURCES = xrdp-freerdp.c xrdp-color.c - -libxrdpfreerdp1_la_LIBADD = \ - $(top_builddir)/common/libcommon.la \ - $(FREERDP_LIBS) diff --git a/freerdp1/xrdp-color.c b/freerdp1/xrdp-color.c deleted file mode 100644 index 6b99140a..00000000 --- a/freerdp1/xrdp-color.c +++ /dev/null @@ -1,313 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Server - * freerdp wrapper - * - * Copyright 2011-2012 Jay Sorg - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "xrdp-freerdp.h" - -char *APP_CC -convert_bitmap(int in_bpp, int out_bpp, char *bmpdata, - int width, int height, int *palette) -{ - char *out; - char *src; - char *dst; - int i; - int j; - int red; - int green; - int blue; - int pixel; - - if ((in_bpp == 8) && (out_bpp == 8)) - { - out = (char *)g_malloc(width * height, 0); - src = bmpdata; - dst = out; - - for (i = 0; i < height; i++) - { - for (j = 0; j < width; j++) - { - pixel = *((tui8 *)src); - pixel = palette[pixel]; - SPLITCOLOR32(red, green, blue, pixel); - pixel = COLOR8(red, green, blue); - *dst = pixel; - src++; - dst++; - } - } - - return out; - } - - if ((in_bpp == 8) && (out_bpp == 16)) - { - out = (char *)g_malloc(width * height * 2, 0); - src = bmpdata; - dst = out; - - for (i = 0; i < height; i++) - { - for (j = 0; j < width; j++) - { - pixel = *((tui8 *)src); - pixel = palette[pixel]; - SPLITCOLOR32(red, green, blue, pixel); - pixel = COLOR16(red, green, blue); - *((tui16 *)dst) = pixel; - src++; - dst += 2; - } - } - - return out; - } - - if ((in_bpp == 8) && (out_bpp == 24)) - { - out = (char *)g_malloc(width * height * 4, 0); - src = bmpdata; - dst = out; - - for (i = 0; i < height; i++) - { - for (j = 0; j < width; j++) - { - pixel = *((tui8 *)src); - pixel = palette[pixel]; - SPLITCOLOR32(red, green, blue, pixel); - pixel = COLOR24RGB(red, green, blue); - *((tui32 *)dst) = pixel; - src++; - dst += 4; - } - } - - return out; - } - - if ((in_bpp == 15) && (out_bpp == 16)) - { - out = (char *)g_malloc(width * height * 2, 0); - src = bmpdata; - dst = out; - - for (i = 0; i < height; i++) - { - for (j = 0; j < width; j++) - { - pixel = *((tui16 *)src); - SPLITCOLOR15(red, green, blue, pixel); - pixel = COLOR16(red, green, blue); - *((tui16 *)dst) = pixel; - src += 2; - dst += 2; - } - } - - return out; - } - - if ((in_bpp == 15) && (out_bpp == 24)) - { - out = (char *)g_malloc(width * height * 4, 0); - src = bmpdata; - dst = out; - - for (i = 0; i < height; i++) - { - for (j = 0; j < width; j++) - { - pixel = *((tui16 *)src); - SPLITCOLOR15(red, green, blue, pixel); - pixel = COLOR24RGB(red, green, blue); - *((tui32 *)dst) = pixel; - src += 2; - dst += 4; - } - } - - return out; - } - - if ((in_bpp == 15) && (out_bpp == 15)) - { - return bmpdata; - } - - if ((in_bpp == 16) && (out_bpp == 16)) - { - return bmpdata; - } - - if ((in_bpp == 16) && (out_bpp == 24)) - { - out = (char *)g_malloc(width * height * 4, 0); - src = bmpdata; - dst = out; - - for (i = 0; i < height; i++) - { - for (j = 0; j < width; j++) - { - pixel = *((tui16 *)src); - SPLITCOLOR16(red, green, blue, pixel); - pixel = COLOR24RGB(red, green, blue); - *((tui32 *)dst) = pixel; - src += 2; - dst += 4; - } - } - - return out; - } - - if ((in_bpp == 24) && (out_bpp == 24)) - { - out = (char *)g_malloc(width * height * 4, 0); - src = bmpdata; - dst = out; - - for (i = 0; i < height; i++) - { - for (j = 0; j < width; j++) - { - blue = *((tui8 *)src); - src++; - green = *((tui8 *)src); - src++; - red = *((tui8 *)src); - src++; - pixel = COLOR24RGB(red, green, blue); - *((tui32 *)dst) = pixel; - dst += 4; - } - } - - return out; - } - - if ((in_bpp == 32) && (out_bpp == 24)) - { - return bmpdata; - } - - if ((in_bpp == 32) && (out_bpp == 32)) - { - return bmpdata; - } - - g_writeln("convert_bitmap: error unknown conversion from %d to %d", - in_bpp, out_bpp); - return 0; -} - -/*****************************************************************************/ -/* returns color or 0 */ -int APP_CC -convert_color(int in_bpp, int out_bpp, int in_color, int *palette) -{ - int pixel; - int red; - int green; - int blue; - - if ((in_bpp == 1) && (out_bpp == 24)) - { - pixel = in_color == 0 ? 0 : 0xffffff; - return pixel; - } - - if ((in_bpp == 8) && (out_bpp == 8)) - { - pixel = palette[in_color]; - SPLITCOLOR32(red, green, blue, pixel); - pixel = COLOR8(red, green, blue); - return pixel; - } - - if ((in_bpp == 8) && (out_bpp == 16)) - { - pixel = palette[in_color]; - SPLITCOLOR32(red, green, blue, pixel); - pixel = COLOR16(red, green, blue); - return pixel; - } - - if ((in_bpp == 8) && (out_bpp == 24)) - { - pixel = palette[in_color]; - SPLITCOLOR32(red, green, blue, pixel); - pixel = COLOR24BGR(red, green, blue); - return pixel; - } - - if ((in_bpp == 15) && (out_bpp == 16)) - { - pixel = in_color; - SPLITCOLOR15(red, green, blue, pixel); - pixel = COLOR16(red, green, blue); - return pixel; - } - - if ((in_bpp == 15) && (out_bpp == 24)) - { - pixel = in_color; - SPLITCOLOR15(red, green, blue, pixel); - pixel = COLOR24BGR(red, green, blue); - return pixel; - } - - if ((in_bpp == 15) && (out_bpp == 15)) - { - return in_color; - } - - if ((in_bpp == 16) && (out_bpp == 16)) - { - return in_color; - } - - if ((in_bpp == 16) && (out_bpp == 24)) - { - pixel = in_color; - SPLITCOLOR16(red, green, blue, pixel); - pixel = COLOR24BGR(red, green, blue); - return pixel; - } - - if ((in_bpp == 24) && (out_bpp == 24)) - { - return in_color; - } - - if ((in_bpp == 32) && (out_bpp == 24)) - { - return in_color; - } - - if ((in_bpp == 32) && (out_bpp == 32)) - { - return in_color; - } - - g_writeln("convert_color: error unknown conversion from %d to %d", - in_bpp, out_bpp); - return 0; -} diff --git a/freerdp1/xrdp-color.h b/freerdp1/xrdp-color.h deleted file mode 100644 index 6a3f7362..00000000 --- a/freerdp1/xrdp-color.h +++ /dev/null @@ -1,29 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Server - * freerdp wrapper - * - * Copyright 2011-2012 Jay Sorg - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __XRDP_COLOR_H -#define __XRDP_COLOR_H - -char* APP_CC -convert_bitmap(int in_bpp, int out_bpp, char* bmpdata, - int width, int height, int* palette); -int APP_CC -convert_color(int in_bpp, int out_bpp, int in_color, int* palette); - -#endif diff --git a/freerdp1/xrdp-freerdp.c b/freerdp1/xrdp-freerdp.c deleted file mode 100644 index ca4fe31f..00000000 --- a/freerdp1/xrdp-freerdp.c +++ /dev/null @@ -1,1858 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Server - * freerdp wrapper - * - * Copyright 2011-2012 Jay Sorg - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <freerdp/settings.h> -#include <X11/Xlib.h> -#include "xrdp-freerdp.h" -#include "xrdp-color.h" -#include "xrdp_rail.h" -#include "log.h" - -#ifdef XRDP_DEBUG -#define LOG_LEVEL 99 -#else -#define LOG_LEVEL 0 -#endif - -#define LLOG(_level, _args) \ - do { if (_level < LOG_LEVEL) { g_write _args ; } } while (0) -#define LLOGLN(_level, _args) \ - do { if (_level < LOG_LEVEL) { g_writeln _args ; } } while (0) - -struct mod_context -{ - rdpContext _p; - struct mod *modi; -}; -typedef struct mod_context modContext; - -void verifyColorMap(struct mod *mod) -{ - int i ; - for( i = 0 ;i<255 ; i++) - { - if(mod->colormap[i]!=0) - { - return ; - } - } - LLOGLN(0, ("The colormap is all NULL\n")); -} -/*****************************************************************************/ -/* return error */ -static int DEFAULT_CC -lxrdp_start(struct mod *mod, int w, int h, int bpp) -{ - rdpSettings *settings; - - LLOGLN(10, ("lxrdp_start: w %d h %d bpp %d", w, h, bpp)); - settings = mod->inst->settings; - settings->DesktopWidth = w; - settings->DesktopHeight = h; - settings->ColorDepth = bpp; - mod->bpp = bpp; - // TODO what does this really become - settings->DisableEncryption = 1; // settings->encryption = 1; - settings->TlsSecurity = 1; - settings->NlaSecurity = 0; - settings->RdpSecurity = 1; - - return 0; -} - -/******************************************************************************/ -/* return error */ -static int DEFAULT_CC -lxrdp_connect(struct mod *mod) -{ - BOOL ok; - - LLOGLN(10, ("lxrdp_connect:")); - - ok = freerdp_connect(mod->inst); - LLOGLN(0, ("lxrdp_connect: freerdp_connect returned %d", ok)); - - if (!ok) - { - LLOGLN(0, ("Failure to connect")); -#ifdef ERRORSTART - - if (connectErrorCode != 0) - { - char buf[128]; - - if (connectErrorCode < ERRORSTART) - { - if (strerror_r(connectErrorCode, buf, 128) != 0) - { - g_snprintf(buf, 128, "Errorcode from connect : %d", connectErrorCode); - } - } - else - { - switch (connectErrorCode) - { - case PREECONNECTERROR: - g_snprintf(buf, 128, "The error code from connect is " - "PREECONNECTERROR"); - break; - case UNDEFINEDCONNECTERROR: - g_snprintf(buf, 128, "The error code from connect is " - "UNDEFINEDCONNECTERROR"); - break; - case POSTCONNECTERROR: - g_snprintf(buf, 128, "The error code from connect is " - "POSTCONNECTERROR"); - break; - case DNSERROR: - g_snprintf(buf, 128, "The DNS system generated an error"); - break; - case DNSNAMENOTFOUND: - g_snprintf(buf, 128, "The DNS system could not find the " - "specified name"); - break; - case CONNECTERROR: - g_snprintf(buf, 128, "A general connect error was returned"); - break; - case MCSCONNECTINITIALERROR: - g_snprintf(buf, 128, "The error code from connect is " - "MCSCONNECTINITIALERROR"); - break; - case TLSCONNECTERROR: - g_snprintf(buf, 128, "Error in TLS handshake"); - break; - case AUTHENTICATIONERROR: - g_snprintf(buf, 128, "Authentication error check your password " - "and username"); - break; - default: - g_snprintf(buf, 128, "Unhandled Errorcode from connect : %d", - connectErrorCode); - break; - } - } - log_message(LOG_LEVEL_INFO,buf); - mod->server_msg(mod, buf, 0); - } - -#endif - log_message(LOG_LEVEL_INFO,"freerdp_connect Failed to destination :%s:%d",mod->inst->settings->ServerHostname,mod->inst->settings->ServerPort); - return 1; - } - else - { - log_message(LOG_LEVEL_INFO,"freerdp_connect returned Success to destination :%s:%d",mod->inst->settings->ServerHostname,mod->inst->settings->ServerPort); - } - - return 0; -} - -/******************************************************************************/ -/* return error */ -static int DEFAULT_CC -lxrdp_event(struct mod *mod, int msg, long param1, long param2, - long param3, long param4) -{ - int x; - int y; - int flags; - int size; - int total_size; - int chanid; - int lchid; - char *data; - - LLOGLN(12, ("lxrdp_event: msg %d", msg)); - - switch (msg) - { - case 15: /* key down */ - mod->inst->input->KeyboardEvent(mod->inst->input, param4, param3); - break; - case 16: /* key up */ - mod->inst->input->KeyboardEvent(mod->inst->input, param4, param3); - break; - case 17: /*Synchronize*/ - LLOGLN(11, ("Synchronized event handled")); - mod->inst->input->SynchronizeEvent(mod->inst->input, 0); - break; - case 100: /* mouse move */ - LLOGLN(12, ("mouse move %d %d", param1, param2)); - x = param1; - y = param2; - flags = PTR_FLAGS_MOVE; - mod->inst->input->MouseEvent(mod->inst->input, flags, x, y); - break; - case 101: /* left button up */ - LLOGLN(12, ("left button up %d %d", param1, param2)); - x = param1; - y = param2; - flags = PTR_FLAGS_BUTTON1; - mod->inst->input->MouseEvent(mod->inst->input, flags, x, y); - break; - case 102: /* left button down */ - LLOGLN(12, ("left button down %d %d", param1, param2)); - x = param1; - y = param2; - flags = PTR_FLAGS_BUTTON1 | PTR_FLAGS_DOWN; - mod->inst->input->MouseEvent(mod->inst->input, flags, x, y); - break; - case 103: /* right button up */ - LLOGLN(12, ("right button up %d %d", param1, param2)); - x = param1; - y = param2; - flags = PTR_FLAGS_BUTTON2; - mod->inst->input->MouseEvent(mod->inst->input, flags, x, y); - break; - case 104: /* right button down */ - LLOGLN(12, ("right button down %d %d", param1, param2)); - x = param1; - y = param2; - flags = PTR_FLAGS_BUTTON2 | PTR_FLAGS_DOWN; - mod->inst->input->MouseEvent(mod->inst->input, flags, x, y); - break; - case 105: /* middle button up */ - LLOGLN(12, ("middle button up %d %d", param1, param2)); - x = param1; - y = param2; - flags = PTR_FLAGS_BUTTON3; - mod->inst->input->MouseEvent(mod->inst->input, flags, x, y); - break; - case 106: /* middle button down */ - LLOGLN(12, ("middle button down %d %d", param1, param2)); - x = param1; - y = param2; - flags = PTR_FLAGS_BUTTON3 | PTR_FLAGS_DOWN; - mod->inst->input->MouseEvent(mod->inst->input, flags, x, y); - break; - case 107: /* wheel up */ - flags = PTR_FLAGS_WHEEL | 0x0078; - mod->inst->input->MouseEvent(mod->inst->input, flags, 0, 0); - case 108: - break; - case 109: /* wheel down */ - flags = PTR_FLAGS_WHEEL | PTR_FLAGS_WHEEL_NEGATIVE | 0x0088; - mod->inst->input->MouseEvent(mod->inst->input, flags, 0, 0); - case 110: - break; - case 200: - LLOGLN(12, ("Invalidate request sent from client")); - RECTANGLE_16 *rectangle = (RECTANGLE_16 *) g_malloc(sizeof(RECTANGLE_16), 0); - /* The parameters are coded as follows param1 = MAKELONG(y, x), param2 =MAKELONG(h, w) - * #define MAKELONG(lo, hi) ((((hi) & 0xffff) << 16) | ((lo) & 0xffff)) - */ - rectangle->left = (param1 >> 16) & 0xffff; - rectangle->top = param1 & 0xffff; - rectangle->right = (((param2 >> 16) & 0xffff) + rectangle->left) - 1; - rectangle->bottom = ((param2 & 0xffff) + rectangle->top) - 1; - - if (mod->inst->settings->RefreshRect) - { - if (mod->inst->update != NULL) - { - if (mod->inst->update->RefreshRect != NULL) - { - if (mod->inst->context != NULL) - { - LLOGLN(0, ("update rectangle left: %d top: %d bottom: %d right: %d", - rectangle->left, rectangle->top, rectangle->bottom, rectangle->right)); - mod->inst->update->RefreshRect(mod->inst->context, 1, rectangle); - } - else - { - LLOGLN(0, ("Invalidate request -The context is null")); - } - } - else - { - LLOGLN(0, ("Invalidate request - RefreshRect is Null")); - } - } - else - { - LLOGLN(0, ("Invalidate request -the update pointer is null")); - } - } - else - { - LLOGLN(0, ("Invalidate request - warning - update rectangle is disabled")); - } - - g_free(rectangle); - break; - case 0x5555: - chanid = LOWORD(param1); - flags = HIWORD(param1); - size = (int)param2; - data = (char *)param3; - total_size = (int)param4; - LLOGLN(12, ("lxrdp_event: client to server flags %d", flags)); - - if ((chanid < 0) || (chanid >= mod->inst->settings->ChannelDefArraySize)) - { - LLOGLN(0, ("lxrdp_event: error chanid %d", chanid)); - break; - } - - lchid = mod->inst->settings->ChannelDefArray[chanid].ChannelId; - - switch (flags & 3) - { - case 3: - mod->inst->SendChannelData(mod->inst, lchid, (tui8 *)data, total_size); - break; - case 2: - /* end */ - g_memcpy(mod->chan_buf + mod->chan_buf_valid, data, size); - mod->chan_buf_valid += size; - mod->inst->SendChannelData(mod->inst, lchid, (tui8 *)(mod->chan_buf), - total_size); - g_free(mod->chan_buf); - mod->chan_buf = 0; - mod->chan_buf_bytes = 0; - mod->chan_buf_valid = 0; - break; - case 1: - /* start */ - g_free(mod->chan_buf); - mod->chan_buf = (char *)g_malloc(total_size, 0); - mod->chan_buf_bytes = total_size; - mod->chan_buf_valid = 0; - g_memcpy(mod->chan_buf + mod->chan_buf_valid, data, size); - mod->chan_buf_valid += size; - break; - default: - /* middle */ - g_memcpy(mod->chan_buf + mod->chan_buf_valid, data, size); - mod->chan_buf_valid += size; - break; - } - - break; - default: - LLOGLN(0, ("Unhandled message type in eventhandler %d", msg)); - break; - } - - return 0; -} - -/******************************************************************************/ -/* return error */ -static int DEFAULT_CC -lxrdp_signal(struct mod *mod) -{ - LLOGLN(10, ("lxrdp_signal:")); - return 0; -} - -/******************************************************************************/ -/* return error */ -static int DEFAULT_CC -lxrdp_end(struct mod *mod) -{ - int i; - int j; - - for (j = 0; j < 4; j++) - { - for (i = 0; i < 4096; i++) - { - g_free(mod->bitmap_cache[j][i].data); - } - } - - for (i = 0; i < 64; i++) - { - if (mod->brush_cache[i].data != mod->brush_cache[i].b8x8) - { - g_free(mod->brush_cache[i].data); - } - } - - LLOGLN(10, ("lxrdp_end:")); - return 0; -} - -/******************************************************************************/ -/* return error */ -static int DEFAULT_CC -lxrdp_set_param(struct mod *mod, char *name, char *value) -{ - rdpSettings *settings; - - LLOGLN(10, ("lxrdp_set_param: name [%s] value [%s]", name, value)); - settings = mod->inst->settings; - - LLOGLN(10, ("%p %d", settings->ServerHostname, settings->DisableEncryption)); - - if (g_strcmp(name, "hostname") == 0) - { - } - else if (g_strcmp(name, "ip") == 0) - { - settings->ServerHostname = g_strdup(value); - } - else if (g_strcmp(name, "port") == 0) - { - settings->ServerPort = g_atoi(value); - } - else if (g_strcmp(name, "keylayout") == 0) - { - } - else if (g_strcmp(name, "name") == 0) - { - } - else if (g_strcmp(name, "lib") == 0) - { - } - else if (g_strcmp(name, "username") == 0) - { - g_strncpy(mod->username, value, 255); - } - else if (g_strcmp(name, "password") == 0) - { - g_strncpy(mod->password, value, 255); - } - else if (g_strcmp(name, "client_info") == 0) - { - g_memcpy(&(mod->client_info), value, sizeof(mod->client_info)); - /* This is a Struct and cannot be printed in next else*/ - LLOGLN(10, ("Client_info struct ignored")); - } - else - { - LLOGLN(0, ("lxrdp_set_param: unknown name [%s] value [%s]", name, value)); - } - - return 0; -} - -/******************************************************************************/ -static int DEFAULT_CC -lxrdp_session_change(struct mod *mod, int a, int b) -{ - LLOGLN(0, ("lxrdp_session_change: - no code here")); - return 0; -} - -/******************************************************************************/ -static int DEFAULT_CC -lxrdp_get_wait_objs(struct mod *mod, tbus *read_objs, int *rcount, - tbus *write_objs, int *wcount, int *timeout) -{ - void **rfds; - void **wfds; - BOOL ok; - - LLOGLN(12, ("lxrdp_get_wait_objs:")); - rfds = (void **)read_objs; - wfds = (void **)write_objs; - ok = freerdp_get_fds(mod->inst, rfds, rcount, wfds, wcount); - - if (!ok) - { - LLOGLN(0, ("lxrdp_get_wait_objs: freerdp_get_fds failed")); - return 1; - } - - return 0; -} - -/******************************************************************************/ -static int DEFAULT_CC -lxrdp_check_wait_objs(struct mod *mod) -{ - BOOL ok; - - LLOGLN(12, ("lxrdp_check_wait_objs:")); - ok = freerdp_check_fds(mod->inst); - - if (!ok) - { - LLOGLN(0, ("lxrdp_check_wait_objs: freerdp_check_fds failed")); - return 1; - } - - return 0; -} - -/******************************************************************************/ -static void DEFAULT_CC -lfreerdp_begin_paint(rdpContext *context) -{ - struct mod *mod; - - LLOGLN(10, ("lfreerdp_begin_paint:")); - mod = ((struct mod_context *)context)->modi; - mod->server_begin_update(mod); -} - -/******************************************************************************/ -static void DEFAULT_CC -lfreerdp_end_paint(rdpContext *context) -{ - struct mod *mod; - - LLOGLN(10, ("lfreerdp_end_paint:")); - mod = ((struct mod_context *)context)->modi; - mod->server_end_update(mod); -} - -/******************************************************************************/ -static void DEFAULT_CC -lfreerdp_set_bounds(rdpContext *context, rdpBounds *bounds) -{ - struct mod *mod; - int x; - int y; - int cx; - int cy; - - LLOGLN(10, ("lfreerdp_set_bounds: %p", bounds)); - mod = ((struct mod_context *)context)->modi; - - if (bounds != 0) - { - x = bounds->left; - y = bounds->top; - cx = (bounds->right - bounds->left) + 1; - cy = (bounds->bottom - bounds->top) + 1; - mod->server_set_clip(mod, x, y, cx, cy); - } - else - { - mod->server_reset_clip(mod); - } -} - -/******************************************************************************/ -static void DEFAULT_CC -lfreerdp_bitmap_update(rdpContext *context, BITMAP_UPDATE *bitmap) -{ - struct mod *mod; - int index; - int cx; - int cy; - int server_bpp; - int server_Bpp; - int client_bpp; - int j; - int line_bytes; - BITMAP_DATA *bd; - char *dst_data; - char *dst_data1; - char *src; - char *dst; - - mod = ((struct mod_context *)context)->modi; - LLOGLN(10, ("lfreerdp_bitmap_update: %d %d", bitmap->number, bitmap->count)); - - server_bpp = mod->inst->settings->ColorDepth; - server_Bpp = (server_bpp + 7) / 8; - client_bpp = mod->bpp; - - for (index = 0; index < bitmap->number; index++) - { - bd = &bitmap->rectangles[index]; - cx = (bd->destRight - bd->destLeft) + 1; - cy = (bd->destBottom - bd->destTop) + 1; - line_bytes = server_Bpp * bd->width; - dst_data = (char *)g_malloc(bd->height * line_bytes + 16, 0); - - if (bd->compressed) - { - LLOGLN(20,("decompress size : %d",bd->bitmapLength)); - if(!bitmap_decompress(bd->bitmapDataStream, (tui8 *)dst_data, bd->width, - bd->height, bd->bitmapLength, server_bpp, server_bpp)){ - LLOGLN(0,("Failure to decompress the bitmap")); - } - } - else - { - /* bitmap is upside down */ - LLOGLN(10,("bitmap upside down")); - src = (char *)(bd->bitmapDataStream); - dst = dst_data + bd->height * line_bytes; - - for (j = 0; j < bd->height; j++) - { - dst -= line_bytes; - g_memcpy(dst, src, line_bytes); - src += line_bytes; - } - } - - dst_data1 = convert_bitmap(server_bpp, client_bpp, dst_data, - bd->width, bd->height, mod->colormap); - mod->server_paint_rect(mod, bd->destLeft, bd->destTop, cx, cy, - dst_data1, bd->width, bd->height, 0, 0); - - if (dst_data1 != dst_data) - { - g_free(dst_data1); - } - - g_free(dst_data); - } -} - -/******************************************************************************/ -static void DEFAULT_CC -lfreerdp_dst_blt(rdpContext *context, DSTBLT_ORDER *dstblt) -{ - struct mod *mod; - - mod = ((struct mod_context *)context)->modi; - LLOGLN(10, ("lfreerdp_dst_blt:")); - mod->server_set_opcode(mod, dstblt->bRop); - mod->server_fill_rect(mod, dstblt->nLeftRect, dstblt->nTopRect, - dstblt->nWidth, dstblt->nHeight); - mod->server_set_opcode(mod, 0xcc); -} - -/******************************************************************************/ -static void DEFAULT_CC -lfreerdp_pat_blt(rdpContext *context, PATBLT_ORDER *patblt) -{ - struct mod *mod; - int idx; - int fgcolor; - int bgcolor; - int server_bpp; - int client_bpp; - struct brush_item *bi; - - mod = ((struct mod_context *)context)->modi; - LLOGLN(10, ("lfreerdp_pat_blt:")); - - server_bpp = mod->inst->settings->ColorDepth; - client_bpp = mod->bpp; - LLOGLN(0, ("lfreerdp_pat_blt: bpp %d %d", server_bpp, client_bpp)); - - fgcolor = convert_color(server_bpp, client_bpp, - patblt->foreColor, mod->colormap); - bgcolor = convert_color(server_bpp, client_bpp, - patblt->backColor, mod->colormap); - - if(fgcolor==bgcolor) - { - LLOGLN(0, ("Warning same color on both bg and fg")); - } - mod->server_set_mixmode(mod, 1); - mod->server_set_opcode(mod, patblt->bRop); - mod->server_set_fgcolor(mod, fgcolor); - mod->server_set_bgcolor(mod, bgcolor); - - if (patblt->brush.style & 0x80) - { - idx = patblt->brush.hatch; - - if ((idx < 0) || (idx >= 64)) - { - LLOGLN(0, ("lfreerdp_pat_blt: error")); - return; - } - - bi = mod->brush_cache + idx; - mod->server_set_brush(mod, patblt->brush.x, patblt->brush.y, - 3, bi->b8x8); - } - else - { - mod->server_set_brush(mod, patblt->brush.x, patblt->brush.y, - patblt->brush.style, - (char *)(patblt->brush.p8x8)); - } - - mod->server_fill_rect(mod, patblt->nLeftRect, patblt->nTopRect, - patblt->nWidth, patblt->nHeight); - mod->server_set_opcode(mod, 0xcc); - mod->server_set_mixmode(mod, 0); - -} - -/******************************************************************************/ -static void DEFAULT_CC -lfreerdp_scr_blt(rdpContext *context, SCRBLT_ORDER *scrblt) -{ - struct mod *mod; - - mod = ((struct mod_context *)context)->modi; - LLOGLN(10, ("lfreerdp_scr_blt:")); - mod->server_set_opcode(mod, scrblt->bRop); - mod->server_screen_blt(mod, scrblt->nLeftRect, scrblt->nTopRect, - scrblt->nWidth, scrblt->nHeight, - scrblt->nXSrc, scrblt->nYSrc); - mod->server_set_opcode(mod, 0xcc); -} - -/******************************************************************************/ -static void DEFAULT_CC -lfreerdp_opaque_rect(rdpContext *context, OPAQUE_RECT_ORDER *opaque_rect) -{ - struct mod *mod; - int server_bpp; - int client_bpp; - int fgcolor; - - mod = ((struct mod_context *)context)->modi; - LLOGLN(10, ("lfreerdp_opaque_rect:")); - server_bpp = mod->inst->settings->ColorDepth; - client_bpp = mod->bpp; - fgcolor = convert_color(server_bpp, client_bpp, - opaque_rect->color, mod->colormap); - mod->server_set_fgcolor(mod, fgcolor); - mod->server_fill_rect(mod, opaque_rect->nLeftRect, opaque_rect->nTopRect, - opaque_rect->nWidth, opaque_rect->nHeight); -} - -/******************************************************************************/ -static void DEFAULT_CC -lfreerdp_mem_blt(rdpContext *context, MEMBLT_ORDER *memblt) -{ - int id; - int idx; - struct mod *mod; - struct bitmap_item *bi; - - mod = ((struct mod_context *)context)->modi; - LLOGLN(10, ("lfreerdp_mem_blt: cacheId %d cacheIndex %d", - memblt->cacheId, memblt->cacheIndex)); - - id = memblt->cacheId; - idx = memblt->cacheIndex; - - if (idx == 32767) /* BITMAPCACHE_WAITING_LIST_INDEX */ - { - idx = 4096 - 1; - } - - if ((id < 0) || (id >= 4)) - { - LLOGLN(0, ("lfreerdp_mem_blt: bad id [%d]", id)); - return; - } - - if ((idx < 0) || (idx >= 4096)) - { - LLOGLN(0, ("lfreerdp_mem_blt: bad idx [%d]", idx)); - return; - } - - bi = &(mod->bitmap_cache[id][idx]); - - mod->server_set_opcode(mod, memblt->bRop); - mod->server_paint_rect(mod, memblt->nLeftRect, memblt->nTopRect, - memblt->nWidth, memblt->nHeight, - bi->data, bi->width, bi->height, - memblt->nXSrc, memblt->nYSrc); - mod->server_set_opcode(mod, 0xcc); - -} - -/******************************************************************************/ -static void DEFAULT_CC -lfreerdp_glyph_index(rdpContext *context, GLYPH_INDEX_ORDER *glyph_index) -{ - struct mod *mod; - int server_bpp; - int client_bpp; - int fgcolor; - int bgcolor; - - mod = ((struct mod_context *)context)->modi; - LLOGLN(10, ("lfreerdp_glyph_index:")); - server_bpp = mod->inst->settings->ColorDepth; - client_bpp = mod->bpp; - fgcolor = convert_color(server_bpp, client_bpp, - glyph_index->foreColor, mod->colormap); - bgcolor = convert_color(server_bpp, client_bpp, - glyph_index->backColor, mod->colormap); - mod->server_set_bgcolor(mod, fgcolor); - mod->server_set_fgcolor(mod, bgcolor); - mod->server_draw_text(mod, glyph_index->cacheId, glyph_index->flAccel, - glyph_index->fOpRedundant, - glyph_index->bkLeft, glyph_index->bkTop, - glyph_index->bkRight, glyph_index->bkBottom, - glyph_index->opLeft, glyph_index->opTop, - glyph_index->opRight, glyph_index->opBottom, - glyph_index->x, glyph_index->y, - (char *)(glyph_index->data), glyph_index->cbData); -} - -/******************************************************************************/ -static void DEFAULT_CC -lfreerdp_line_to(rdpContext *context, LINE_TO_ORDER *line_to) -{ - struct mod *mod; - int server_bpp; - int client_bpp; - int fgcolor; - int bgcolor; - - mod = ((struct mod_context *)context)->modi; - LLOGLN(10, ("lfreerdp_line_to:")); - mod->server_set_opcode(mod, line_to->bRop2); - server_bpp = mod->inst->settings->ColorDepth; - client_bpp = mod->bpp; - fgcolor = convert_color(server_bpp, client_bpp, - line_to->penColor, mod->colormap); - bgcolor = convert_color(server_bpp, client_bpp, - line_to->backColor, mod->colormap); - mod->server_set_fgcolor(mod, fgcolor); - mod->server_set_bgcolor(mod, bgcolor); - mod->server_set_pen(mod, line_to->penStyle, line_to->penWidth); - mod->server_draw_line(mod, line_to->nXStart, line_to->nYStart, - line_to->nXEnd, line_to->nYEnd); - mod->server_set_opcode(mod, 0xcc); -} - -/******************************************************************************/ -static void DEFAULT_CC -lfreerdp_cache_bitmap(rdpContext *context, CACHE_BITMAP_ORDER *cache_bitmap_order) -{ - LLOGLN(0, ("lfreerdp_cache_bitmap: - no code here")); -} - -/******************************************************************************/ -/* Turn the bitmap upside down*/ -static void DEFAULT_CC -lfreerdp_upsidedown(UINT8 *destination, CACHE_BITMAP_V2_ORDER *cache_bitmap_v2_order, int server_Bpp) -{ - tui8 *src; - tui8 *dst; - int line_bytes; - int j; - - if (destination == NULL) - { - LLOGLN(0, ("lfreerdp_upsidedown: destination pointer is NULL !!!")); - return; - } - - line_bytes = server_Bpp * cache_bitmap_v2_order->bitmapWidth; - src = cache_bitmap_v2_order->bitmapDataStream; - dst = destination + ((cache_bitmap_v2_order->bitmapHeight) * line_bytes); - - for (j = 0; j < cache_bitmap_v2_order->bitmapHeight; j++) - { - dst -= line_bytes; - g_memcpy(dst, src, line_bytes); - src += line_bytes; - } -} - -/******************************************************************************/ -static void DEFAULT_CC -lfreerdp_cache_bitmapV2(rdpContext *context, - CACHE_BITMAP_V2_ORDER *cache_bitmap_v2_order) -{ - char *dst_data; - char *dst_data1; - int bytes; - int width; - int height; - int id; - int idx; - int flags; - int server_bpp; - int server_Bpp; - int client_bpp; - struct mod *mod; - - LLOGLN(10, ("lfreerdp_cache_bitmapV2: %d %d 0x%8.8x compressed %d", - cache_bitmap_v2_order->cacheId, - cache_bitmap_v2_order->cacheIndex, - cache_bitmap_v2_order->flags, - cache_bitmap_v2_order->compressed)); - - mod = ((struct mod_context *)context)->modi; - id = cache_bitmap_v2_order->cacheId; - idx = cache_bitmap_v2_order->cacheIndex; - flags = cache_bitmap_v2_order->flags; - - if (flags & 0x10) /* CBR2_DO_NOT_CACHE */ - { - LLOGLN(0, ("lfreerdp_cache_bitmapV2: CBR2_DO_NOT_CACHE")); - idx = 4096 - 1; - } - - if ((id < 0) || (id >= 4)) - { - LLOGLN(0, ("lfreerdp_cache_bitmapV2: bad id [%d]", id)); - return; - } - - if ((idx < 0) || (idx >= 4096)) - { - LLOGLN(0, ("lfreerdp_cache_bitmapV2: bad idx [%d]", idx)); - return; - } - - server_bpp = mod->inst->settings->ColorDepth; - server_Bpp = (server_bpp + 7) / 8; - client_bpp = mod->bpp; - - width = cache_bitmap_v2_order->bitmapWidth; - height = cache_bitmap_v2_order->bitmapHeight; - bytes = width * height * server_Bpp + 16; - dst_data = (char *)g_malloc(bytes, 0); - - if (cache_bitmap_v2_order->compressed) - { - bitmap_decompress(cache_bitmap_v2_order->bitmapDataStream, - (tui8 *)dst_data, width, height, - cache_bitmap_v2_order->bitmapLength, - server_bpp, server_bpp); - } - else - { - /* Uncompressed bitmaps are upside down */ - lfreerdp_upsidedown((tui8 *)dst_data, cache_bitmap_v2_order, server_Bpp); - LLOGLN(10, ("lfreerdp_cache_bitmapV2: upside down progressed")); - } - - dst_data1 = convert_bitmap(server_bpp, client_bpp, dst_data, - width, height, mod->colormap); - g_free(mod->bitmap_cache[id][idx].data); - mod->bitmap_cache[id][idx].width = width; - mod->bitmap_cache[id][idx].height = height; - mod->bitmap_cache[id][idx].data = dst_data1; - - if (dst_data != dst_data1) - { - g_free(dst_data); - } -} - -/******************************************************************************/ -static void DEFAULT_CC -lfreerdp_cache_glyph(rdpContext *context, CACHE_GLYPH_ORDER *cache_glyph_order) -{ - int index; - GLYPH_DATA *gd; - struct mod *mod; - - mod = ((struct mod_context *)context)->modi; - LLOGLN(10, ("lfreerdp_cache_glyph: %d", cache_glyph_order->cGlyphs)); - - for (index = 0; index < cache_glyph_order->cGlyphs; index++) - { - gd = cache_glyph_order->glyphData[index]; - LLOGLN(10, (" %d %d %d %d %d", gd->cacheIndex, gd->x, gd->y, - gd->cx, gd->cy)); - mod->server_add_char(mod, cache_glyph_order->cacheId, gd->cacheIndex, - gd->x, gd->y, gd->cx, gd->cy, (char *)(gd->aj)); - free(gd->aj); - gd->aj = 0; - free(gd); - cache_glyph_order->glyphData[index] = 0; - } - - free(cache_glyph_order->unicodeCharacters); - cache_glyph_order->unicodeCharacters = 0; -} - -/******************************************************************************/ -static void DEFAULT_CC -lfreerdp_cache_brush(rdpContext *context, CACHE_BRUSH_ORDER *cache_brush_order) -{ - int idx; - int bytes; - int bpp; - int cx; - int cy; - struct mod *mod; - - mod = ((struct mod_context *)context)->modi; - bpp = cache_brush_order->bpp; - cx = cache_brush_order->cx; - cy = cache_brush_order->cy; - idx = cache_brush_order->index; - bytes = cache_brush_order->length; - LLOGLN(10, ("lfreerdp_cache_brush: bpp %d cx %d cy %d idx %d bytes %d", - bpp, cx, cy, idx, bytes)); - - if ((idx < 0) || (idx >= 64)) - { - LLOGLN(0, ("lfreerdp_cache_brush: error idx %d", idx)); - return; - } - - if ((bpp != 1) || (cx != 8) || (cy != 8)) - { - LLOGLN(0, ("lfreerdp_cache_brush: error unsupported brush " - "bpp %d cx %d cy %d", bpp, cx, cy)); - return; - } - - mod->brush_cache[idx].bpp = bpp; - mod->brush_cache[idx].width = cx; - mod->brush_cache[idx].height = cy; - mod->brush_cache[idx].data = mod->brush_cache[idx].b8x8; - - if (bytes > 8) - { - bytes = 8; - } - - g_memset(mod->brush_cache[idx].data, 0, 8); - - if (bytes > 0) - { - if (bytes > 8) - { - LLOGLN(0, ("lfreerdp_cache_brush: bytes to big %d", bytes)); - bytes = 8; - } - - g_memcpy(mod->brush_cache[idx].data, cache_brush_order->data, bytes); - } - - LLOGLN(10, ("lfreerdp_cache_brush: out bpp %d cx %d cy %d idx %d bytes %d", - bpp, cx, cy, idx, bytes)); - - free(cache_brush_order->data); - cache_brush_order->data = 0; - -} - -/******************************************************************************/ -static void DEFAULT_CC -lfreerdp_pointer_position(rdpContext *context, - POINTER_POSITION_UPDATE *pointer_position) -{ - LLOGLN(0, ("lfreerdp_pointer_position: - no code here")); -} - -/******************************************************************************/ -static void DEFAULT_CC -lfreerdp_pointer_system(rdpContext *context, - POINTER_SYSTEM_UPDATE *pointer_system) -{ - LLOGLN(0, ("lfreerdp_pointer_system: - no code here type value = %d",pointer_system->type)); -} - -/******************************************************************************/ -static void DEFAULT_CC -lfreerdp_pointer_color(rdpContext *context, - POINTER_COLOR_UPDATE *pointer_color) -{ - LLOGLN(0, ("lfreerdp_pointer_color: - no code here")); -} - -/******************************************************************************/ -static int APP_CC -lfreerdp_get_pixel(void *bits, int width, int height, int bpp, - int delta, int x, int y) -{ - int start; - int shift; - int pixel; - tui8 *src8; - - if (bpp == 1) - { - src8 = (tui8 *)bits; - start = (y * delta) + x / 8; - shift = x % 8; - pixel = (src8[start] & (0x80 >> shift)) != 0; - return pixel ? 0xffffff : 0; - } - else - { - LLOGLN(0, ("lfreerdp_get_pixel: unknown bpp %d", bpp)); - } - - return 0; -} - -/******************************************************************************/ -static int APP_CC -lfreerdp_set_pixel(int pixel, void *bits, int width, int height, int bpp, - int delta, int x, int y) -{ - tui8 *dst8; - int start; - int shift; - - if (bpp == 1) - { - dst8 = (tui8 *)bits; - start = (y * delta) + x / 8; - shift = x % 8; - - if (pixel) - { - dst8[start] = dst8[start] | (0x80 >> shift); - } - else - { - dst8[start] = dst8[start] & ~(0x80 >> shift); - } - } - else if (bpp == 24) - { - dst8 = (tui8 *)bits; - dst8 += y * delta + x * 3; - dst8[0] = (pixel >> 0) & 0xff; - dst8[1] = (pixel >> 8) & 0xff; - dst8[2] = (pixel >> 16) & 0xff; - } - else - { - LLOGLN(0, ("lfreerdp_set_pixel: unknown bpp %d", bpp)); - } - - return 0; -} - -/******************************************************************************/ -static int APP_CC -lfreerdp_convert_color_image(void *dst, int dst_width, int dst_height, - int dst_bpp, int dst_delta, - void *src, int src_width, int src_height, - int src_bpp, int src_delta) -{ - int i; - int j; - int pixel; - - for (j = 0; j < dst_height; j++) - { - for (i = 0; i < dst_width; i++) - { - pixel = lfreerdp_get_pixel(src, src_width, src_height, src_bpp, - src_delta, i, j); - lfreerdp_set_pixel(pixel, dst, dst_width, dst_height, dst_bpp, - dst_delta, i, j); - } - } - - return 0; -} - -/******************************************************************************/ -static void DEFAULT_CC -lfreerdp_pointer_new(rdpContext *context, - POINTER_NEW_UPDATE *pointer_new) -{ - struct mod *mod; - int index; - tui8 *dst; - tui8 *src; - - mod = ((struct mod_context *)context)->modi; - LLOGLN(20, ("lfreerdp_pointer_new:")); - LLOGLN(20, (" bpp %d", pointer_new->xorBpp)); - LLOGLN(20, (" width %d height %d", pointer_new->colorPtrAttr.width, - pointer_new->colorPtrAttr.height)); - - LLOGLN(20, (" lengthXorMask %d lengthAndMask %d", - pointer_new->colorPtrAttr.lengthXorMask, - pointer_new->colorPtrAttr.lengthAndMask)); - - index = pointer_new->colorPtrAttr.cacheIndex; - if(index>=32) - { - LLOGLN(0,("pointer index too big")); - return ; - } - // In this fix we remove the xorBpp check, even if - // the mouse pointers are not correct we can use them. - // Configure your destination not to use windows Aero as pointer scheme - else if ( // pointer_new->xorBpp == 1 && - pointer_new->colorPtrAttr.width == 32 && - pointer_new->colorPtrAttr.height == 32 && - index < 32) - { - mod->pointer_cache[index].hotx = pointer_new->colorPtrAttr.xPos; - mod->pointer_cache[index].hoty = pointer_new->colorPtrAttr.yPos; - - dst = (tui8 *)(mod->pointer_cache[index].data); - dst += 32 * 32 * 3 - 32 * 3; - src = pointer_new->colorPtrAttr.xorMaskData; - lfreerdp_convert_color_image(dst, 32, 32, 24, 32 * -3, - src, 32, 32, 1, 32 / 8); - - dst = (tui8 *)(mod->pointer_cache[index].mask); - dst += ( 32 * 32 / 8) - (32 / 8); - src = pointer_new->colorPtrAttr.andMaskData; - lfreerdp_convert_color_image(dst, 32, 32, 1, 32 / -8, - src, 32, 32, 1, 32 / 8); - - //memcpy(mod->pointer_cache[index].mask, - // pointer_new->colorPtrAttr.andMaskData, 32 * 32 / 8); - - mod->server_set_pointer(mod, mod->pointer_cache[index].hotx, - mod->pointer_cache[index].hoty, mod->pointer_cache[index].data, - mod->pointer_cache[index].mask); - } - else - { - LLOGLN(0, ("lfreerdp_pointer_new: error bpp %d width %d height %d index: %d", - pointer_new->xorBpp, pointer_new->colorPtrAttr.width, - pointer_new->colorPtrAttr.height,index)); - } - - free(pointer_new->colorPtrAttr.xorMaskData); - pointer_new->colorPtrAttr.xorMaskData = 0; - free(pointer_new->colorPtrAttr.andMaskData); - pointer_new->colorPtrAttr.andMaskData = 0; - -} - -/******************************************************************************/ -static void DEFAULT_CC -lfreerdp_pointer_cached(rdpContext *context, - POINTER_CACHED_UPDATE *pointer_cached) -{ - struct mod *mod; - int index; - - mod = ((struct mod_context *)context)->modi; - index = pointer_cached->cacheIndex; - LLOGLN(10, ("lfreerdp_pointer_cached:%d", index)); - mod->server_set_pointer(mod, mod->pointer_cache[index].hotx, - mod->pointer_cache[index].hoty, mod->pointer_cache[index].data, - mod->pointer_cache[index].mask); -} - -static void DEFAULT_CC lfreerdp_polygon_cb(rdpContext* context, POLYGON_CB_ORDER* polygon_cb) -{ - LLOGLN(0, ("lfreerdp_polygon_sc called:- not supported!!!!!!!!!!!!!!!!!!!!")); -} - -static void DEFAULT_CC lfreerdp_polygon_sc(rdpContext* context, POLYGON_SC_ORDER* polygon_sc) -{ - struct mod *mod; - int i, npoints; - XPoint points[4]; - int fgcolor; - int server_bpp, client_bpp; - - mod = ((struct mod_context *)context)->modi; - LLOGLN(10, ("lfreerdp_polygon_sc :%d(points) %d(color) %d(fillmode) %d(bRop) %d(cbData) %d(x) %d(y)", polygon_sc->numPoints,polygon_sc->brushColor,polygon_sc->fillMode,polygon_sc->bRop2,polygon_sc->cbData,polygon_sc->xStart,polygon_sc->yStart)); - if(polygon_sc->numPoints==3) - { - server_bpp = mod->inst->settings->ColorDepth; - client_bpp = mod->bpp; - - points[0].x = polygon_sc->xStart; - points[0].y = polygon_sc->yStart; - - for (i = 0; i < polygon_sc->numPoints; i++) - { - points[i + 1].x = polygon_sc->points[i].x; - points[i + 1].y = polygon_sc->points[i].y; - } - fgcolor = convert_color(server_bpp, client_bpp, - polygon_sc->brushColor, mod->colormap); - - mod->server_set_opcode(mod, polygon_sc->bRop2); - mod->server_set_bgcolor(mod, 255); - mod->server_set_fgcolor(mod, fgcolor); - mod->server_set_pen(mod, 1, 1); // style, width - // TODO replace with correct brush; this is a workaround - // This workaround handles the text cursor in microsoft word. - mod->server_draw_line(mod,polygon_sc->xStart,polygon_sc->yStart,polygon_sc->xStart,polygon_sc->yStart+points[2].y); -// mod->server_fill_rect(mod, points[0].x, points[0].y, -// points[0].x-points[3].x, points[0].y-points[2].y); -// mod->server_set_brush(mod,); // howto use this on our indata?? - mod->server_set_opcode(mod, 0xcc); - } - else - { - LLOGLN(0, ("Not handled number of points in lfreerdp_polygon_sc")); - } -} - -static void DEFAULT_CC lfreerdp_syncronize(rdpContext* context) -{ - struct mod *mod; - mod = ((struct mod_context *)context)->modi; - LLOGLN(0, ("lfreerdp_synchronize received - not handled")); -} - -/******************************************************************************/ -static BOOL DEFAULT_CC -lfreerdp_pre_connect(freerdp *instance) -{ - struct mod *mod; - int index; - int error; - int num_chans; - int ch_flags; - char ch_name[256]; - char *dst_ch_name; - - LLOGLN(0, ("lfreerdp_pre_connect:")); - mod = ((struct mod_context *)(instance->context))->modi; - verifyColorMap(mod); - num_chans = 0; - index = 0; - error = mod->server_query_channel(mod, index, ch_name, &ch_flags); - - while (error == 0) - { - num_chans++; - LLOGLN(10, ("lfreerdp_pre_connect: got channel [%s], flags [0x%8.8x]", - ch_name, ch_flags)); - dst_ch_name = instance->settings->ChannelDefArray[index].Name; - g_memset(dst_ch_name, 0, 8); - g_snprintf(dst_ch_name, 8, "%s", ch_name); - instance->settings->ChannelDefArray[index].options = ch_flags; - index++; - error = mod->server_query_channel(mod, index, ch_name, &ch_flags); - } - - instance->settings->ChannelCount = num_chans; - - // TODO - // instance->settings->offscreen_bitmap_cache = false; - instance->settings->OffscreenSupportLevel = 0; - instance->settings->DrawNineGridEnabled = 0 ; - - // TODO - //instance->settings->glyph_cache = true; - instance->settings->GlyphSupportLevel = GLYPH_SUPPORT_FULL; - instance->settings->OrderSupport[NEG_GLYPH_INDEX_INDEX] = TRUE; - instance->settings->OrderSupport[NEG_FAST_GLYPH_INDEX] = FALSE; - instance->settings->OrderSupport[NEG_FAST_INDEX_INDEX] = FALSE; - instance->settings->OrderSupport[NEG_SCRBLT_INDEX] = TRUE; - instance->settings->OrderSupport[NEG_SAVEBITMAP_INDEX] = FALSE; - - instance->settings->BitmapCacheEnabled = TRUE; - instance->settings->OrderSupport[NEG_MEMBLT_INDEX] = TRUE; - instance->settings->OrderSupport[NEG_MEMBLT_V2_INDEX] = TRUE; - instance->settings->OrderSupport[NEG_MEM3BLT_INDEX] = FALSE; - instance->settings->OrderSupport[NEG_MEM3BLT_V2_INDEX] = FALSE; - instance->settings->BitmapCacheV2NumCells = 3; // 5; - instance->settings->BitmapCacheV2CellInfo[0].numEntries = 0x78; // 600; - instance->settings->BitmapCacheV2CellInfo[0].persistent = FALSE; - instance->settings->BitmapCacheV2CellInfo[1].numEntries = 0x78; // 600; - instance->settings->BitmapCacheV2CellInfo[1].persistent = FALSE; - instance->settings->BitmapCacheV2CellInfo[2].numEntries = 0x150; // 2048; - instance->settings->BitmapCacheV2CellInfo[2].persistent = FALSE; - instance->settings->BitmapCacheV2CellInfo[3].numEntries = 0; // 4096; - instance->settings->BitmapCacheV2CellInfo[3].persistent = FALSE; - instance->settings->BitmapCacheV2CellInfo[4].numEntries = 0; // 2048; - instance->settings->BitmapCacheV2CellInfo[4].persistent = FALSE; - - // instance->settings->BitmapCacheV3Enabled = FALSE; - instance->settings->OrderSupport[NEG_MULTIDSTBLT_INDEX] = FALSE; - instance->settings->OrderSupport[NEG_MULTIPATBLT_INDEX] = FALSE; - instance->settings->OrderSupport[NEG_MULTISCRBLT_INDEX] = FALSE; - instance->settings->OrderSupport[NEG_MULTIOPAQUERECT_INDEX] = FALSE; - instance->settings->OrderSupport[NEG_POLYLINE_INDEX] = FALSE; - - instance->settings->Username = g_strdup(mod->username); - instance->settings->Password = g_strdup(mod->password); - - if (mod->client_info.rail_support_level > 0) - { - LLOGLN(0, ("Railsupport !!!!!!!!!!!!!!!!!!")); - instance->settings->RemoteApplicationMode = TRUE; - instance->settings->RemoteAppLanguageBarSupported = TRUE; - instance->settings->Workarea = TRUE; - instance->settings->PerformanceFlags = PERF_DISABLE_WALLPAPER | PERF_DISABLE_FULLWINDOWDRAG; - } - else - { - LLOGLN(10, ("Special PerformanceFlags changed")); - instance->settings->PerformanceFlags = PERF_DISABLE_WALLPAPER | PERF_DISABLE_FULLWINDOWDRAG | PERF_DISABLE_MENUANIMATIONS | PERF_DISABLE_THEMING ; // | PERF_DISABLE_CURSOR_SHADOW | PERF_DISABLE_CURSORSETTINGS ; - } - instance->settings->CompressionEnabled = FALSE ; - instance->settings->IgnoreCertificate = TRUE ; - - // here - //instance->settings->RdpVersion = 4; - - instance->update->BeginPaint = lfreerdp_begin_paint; - instance->update->EndPaint = lfreerdp_end_paint; - instance->update->SetBounds = lfreerdp_set_bounds; - instance->update->BitmapUpdate = lfreerdp_bitmap_update; - instance->update->Synchronize = lfreerdp_syncronize ; - instance->update->primary->DstBlt = lfreerdp_dst_blt; - instance->update->primary->PatBlt = lfreerdp_pat_blt; - instance->update->primary->ScrBlt = lfreerdp_scr_blt; - instance->update->primary->OpaqueRect = lfreerdp_opaque_rect; - instance->update->primary->MemBlt = lfreerdp_mem_blt; - instance->update->primary->GlyphIndex = lfreerdp_glyph_index; - instance->update->primary->LineTo = lfreerdp_line_to; - instance->update->primary->PolygonSC = lfreerdp_polygon_sc ; - instance->update->primary->PolygonCB = lfreerdp_polygon_cb; - instance->update->secondary->CacheBitmap = lfreerdp_cache_bitmap; - instance->update->secondary->CacheBitmapV2 = lfreerdp_cache_bitmapV2; - instance->update->secondary->CacheGlyph = lfreerdp_cache_glyph; - instance->update->secondary->CacheBrush = lfreerdp_cache_brush; - - instance->update->pointer->PointerPosition = lfreerdp_pointer_position; - instance->update->pointer->PointerSystem = lfreerdp_pointer_system; - instance->update->pointer->PointerColor = lfreerdp_pointer_color; - instance->update->pointer->PointerNew = lfreerdp_pointer_new; - instance->update->pointer->PointerCached = lfreerdp_pointer_cached; - - if ((mod->username[0] != 0) && (mod->password[0] != 0)) - { - /* since we have username and password, we can try nla */ - instance->settings->NlaSecurity = 1; - } - else - { - instance->settings->NlaSecurity = 0; - } - - return TRUE; -} - -/*****************************************************************************/ -void DEFAULT_CC -lrail_WindowCreate(rdpContext *context, WINDOW_ORDER_INFO *orderInfo, - WINDOW_STATE_ORDER *window_state) -{ - int index; - struct mod *mod; - struct rail_window_state_order wso; - - LLOGLN(0, ("llrail_WindowCreate:")); - mod = ((struct mod_context *)context)->modi; - memset(&wso, 0, sizeof(wso)); - /* copy the window state order */ - wso.owner_window_id = window_state->ownerWindowId; - wso.style = window_state->style; - wso.extended_style = window_state->extendedStyle; - wso.show_state = window_state->showState; - - if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_TITLE) - { - freerdp_UnicodeToAsciiAlloc(window_state->titleInfo.string, &wso.title_info, window_state->titleInfo.length / 2); - } - - LLOGLN(0, ("lrail_WindowCreate: %s", wso.title_info)); - wso.client_offset_x = window_state->clientOffsetX; - wso.client_offset_y = window_state->clientOffsetY; - wso.client_area_width = window_state->clientAreaWidth; - wso.client_area_height = window_state->clientAreaHeight; - wso.rp_content = window_state->RPContent; - wso.root_parent_handle = window_state->rootParentHandle; - wso.window_offset_x = window_state->windowOffsetX; - wso.window_offset_y = window_state->windowOffsetY; - wso.window_client_delta_x = window_state->windowClientDeltaX; - wso.window_client_delta_y = window_state->windowClientDeltaY; - wso.window_width = window_state->windowWidth; - wso.window_height = window_state->windowHeight; - wso.num_window_rects = window_state->numWindowRects; - - if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_WND_RECTS) - { - wso.window_rects = (struct rail_window_rect *) - g_malloc(sizeof(struct rail_window_rect) * wso.num_window_rects, 0); - - for (index = 0; index < wso.num_window_rects; index++) - { - wso.window_rects[index].left = window_state->windowRects[index].left; - wso.window_rects[index].top = window_state->windowRects[index].top; - wso.window_rects[index].right = window_state->windowRects[index].right; - wso.window_rects[index].bottom = window_state->windowRects[index].bottom; - } - } - - wso.visible_offset_x = window_state->visibleOffsetX; - wso.visible_offset_y = window_state->visibleOffsetY; - wso.num_visibility_rects = window_state->numVisibilityRects; - - if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_VISIBILITY) - { - wso.visibility_rects = (struct rail_window_rect *) - g_malloc(sizeof(struct rail_window_rect) * wso.num_visibility_rects, 0); - - for (index = 0; index < wso.num_visibility_rects; index++) - { - wso.visibility_rects[index].left = window_state->visibilityRects[index].left; - wso.visibility_rects[index].top = window_state->visibilityRects[index].top; - wso.visibility_rects[index].right = window_state->visibilityRects[index].right; - wso.visibility_rects[index].bottom = window_state->visibilityRects[index].bottom; - } - } - - mod->server_window_new_update(mod, orderInfo->windowId, &wso, - orderInfo->fieldFlags); - - free(wso.title_info); - g_free(wso.window_rects); - g_free(wso.visibility_rects); -} - -/*****************************************************************************/ -void DEFAULT_CC -lrail_WindowUpdate(rdpContext *context, WINDOW_ORDER_INFO *orderInfo, - WINDOW_STATE_ORDER *window_state) -{ - LLOGLN(0, ("lrail_WindowUpdate:")); - lrail_WindowCreate(context, orderInfo, window_state); -} - -/*****************************************************************************/ -void DEFAULT_CC -lrail_WindowDelete(rdpContext *context, WINDOW_ORDER_INFO *orderInfo) -{ - struct mod *mod; - - LLOGLN(0, ("lrail_WindowDelete:")); - mod = ((struct mod_context *)context)->modi; - mod->server_window_delete(mod, orderInfo->windowId); -} - -/*****************************************************************************/ -void DEFAULT_CC -lrail_WindowIcon(rdpContext *context, WINDOW_ORDER_INFO *orderInfo, - WINDOW_ICON_ORDER *window_icon) -{ - struct mod *mod; - struct rail_icon_info rii; - - LLOGLN(0, ("lrail_WindowIcon:")); - mod = ((struct mod_context *)context)->modi; - memset(&rii, 0, sizeof(rii)); - rii.bpp = window_icon->iconInfo->bpp; - rii.width = window_icon->iconInfo->width; - rii.height = window_icon->iconInfo->height; - rii.cmap_bytes = window_icon->iconInfo->cbColorTable; - rii.mask_bytes = window_icon->iconInfo->cbBitsMask; - rii.data_bytes = window_icon->iconInfo->cbBitsColor; - rii.mask = (char *)(window_icon->iconInfo->bitsMask); - rii.cmap = (char *)(window_icon->iconInfo->colorTable); - rii.data = (char *)(window_icon->iconInfo->bitsColor); - mod->server_window_icon(mod, orderInfo->windowId, - window_icon->iconInfo->cacheEntry, - window_icon->iconInfo->cacheId, &rii, - orderInfo->fieldFlags); -} - -/*****************************************************************************/ -void DEFAULT_CC -lrail_WindowCachedIcon(rdpContext *context, WINDOW_ORDER_INFO *orderInfo, - WINDOW_CACHED_ICON_ORDER *window_cached_icon) -{ - struct mod *mod; - - LLOGLN(0, ("lrail_WindowCachedIcon:")); - mod = ((struct mod_context *)context)->modi; - mod->server_window_cached_icon(mod, orderInfo->windowId, - window_cached_icon->cachedIcon.cacheEntry, - window_cached_icon->cachedIcon.cacheId, - orderInfo->fieldFlags); -} - -/*****************************************************************************/ -void DEFAULT_CC -lrail_NotifyIconCreate(rdpContext *context, WINDOW_ORDER_INFO *orderInfo, - NOTIFY_ICON_STATE_ORDER *notify_icon_state) -{ - struct mod *mod; - struct rail_notify_state_order rnso; - - LLOGLN(0, ("lrail_NotifyIconCreate:")); - - mod = ((struct mod_context *)context)->modi; - - memset(&rnso, 0, sizeof(rnso)); - rnso.version = notify_icon_state->version; - - if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_TIP) - { - freerdp_UnicodeToAsciiAlloc(notify_icon_state->toolTip.string, - &rnso.tool_tip, notify_icon_state->toolTip.length / 2); - } - - if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_INFO_TIP) - { - rnso.infotip.timeout = notify_icon_state->infoTip.timeout; - rnso.infotip.flags = notify_icon_state->infoTip.flags; - freerdp_UnicodeToAsciiAlloc(notify_icon_state->infoTip.text.string, - &rnso.infotip.text, notify_icon_state->infoTip.text.length / 2); - freerdp_UnicodeToAsciiAlloc(notify_icon_state->infoTip.title.string, - &rnso.infotip.title, notify_icon_state->infoTip.title.length / 2); - } - - rnso.state = notify_icon_state->state; - rnso.icon_cache_entry = notify_icon_state->icon.cacheEntry; - rnso.icon_cache_id = notify_icon_state->icon.cacheId; - - rnso.icon_info.bpp = notify_icon_state->icon.bpp; - rnso.icon_info.width = notify_icon_state->icon.width; - rnso.icon_info.height = notify_icon_state->icon.height; - rnso.icon_info.cmap_bytes = notify_icon_state->icon.cbColorTable; - rnso.icon_info.mask_bytes = notify_icon_state->icon.cbBitsMask; - rnso.icon_info.data_bytes = notify_icon_state->icon.cbBitsColor; - rnso.icon_info.mask = (char *)(notify_icon_state->icon.bitsMask); - rnso.icon_info.cmap = (char *)(notify_icon_state->icon.colorTable); - rnso.icon_info.data = (char *)(notify_icon_state->icon.bitsColor); - - mod->server_notify_new_update(mod, orderInfo->windowId, - orderInfo->notifyIconId, - &rnso, orderInfo->fieldFlags); - - free(rnso.tool_tip); - free(rnso.infotip.text); - free(rnso.infotip.title); -} - -/*****************************************************************************/ -void DEFAULT_CC -lrail_NotifyIconUpdate(rdpContext *context, WINDOW_ORDER_INFO *orderInfo, - NOTIFY_ICON_STATE_ORDER *notify_icon_state) -{ - LLOGLN(0, ("lrail_NotifyIconUpdate:")); - lrail_NotifyIconCreate(context, orderInfo, notify_icon_state); -} - -/*****************************************************************************/ -void DEFAULT_CC -lrail_NotifyIconDelete(rdpContext *context, WINDOW_ORDER_INFO *orderInfo) -{ - struct mod *mod; - - LLOGLN(0, ("lrail_NotifyIconDelete:")); - mod = ((struct mod_context *)context)->modi; - mod->server_notify_delete(mod, orderInfo->windowId, - orderInfo->notifyIconId); -} - -/*****************************************************************************/ -void DEFAULT_CC -lrail_MonitoredDesktop(rdpContext *context, WINDOW_ORDER_INFO *orderInfo, - MONITORED_DESKTOP_ORDER *monitored_desktop) -{ - int index; - struct mod *mod; - struct rail_monitored_desktop_order rmdo; - - LLOGLN(0, ("lrail_MonitoredDesktop:")); - mod = ((struct mod_context *)context)->modi; - memset(&rmdo, 0, sizeof(rmdo)); - rmdo.active_window_id = monitored_desktop->activeWindowId; - rmdo.num_window_ids = monitored_desktop->numWindowIds; - - if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_DESKTOP_ZORDER) - { - if (rmdo.num_window_ids > 0) - { - rmdo.window_ids = (int *)g_malloc(sizeof(int) * rmdo.num_window_ids, 0); - - for (index = 0; index < rmdo.num_window_ids; index++) - { - rmdo.window_ids[index] = monitored_desktop->windowIds[index]; - } - } - } - - mod->server_monitored_desktop(mod, &rmdo, orderInfo->fieldFlags); - g_free(rmdo.window_ids); -} - -/*****************************************************************************/ -void DEFAULT_CC -lrail_NonMonitoredDesktop(rdpContext *context, WINDOW_ORDER_INFO *orderInfo) -{ - struct mod *mod; - struct rail_monitored_desktop_order rmdo; - - LLOGLN(0, ("lrail_NonMonitoredDesktop:")); - mod = ((struct mod_context *)context)->modi; - memset(&rmdo, 0, sizeof(rmdo)); - mod->server_monitored_desktop(mod, &rmdo, orderInfo->fieldFlags); -} - -/******************************************************************************/ -static BOOL DEFAULT_CC -lfreerdp_post_connect(freerdp *instance) -{ - struct mod *mod; - - LLOGLN(0, ("lfreerdp_post_connect:")); - mod = ((struct mod_context *)(instance->context))->modi; - g_memset(mod->password, 0, sizeof(mod->password)); - - mod->inst->update->window->WindowCreate = lrail_WindowCreate; - mod->inst->update->window->WindowUpdate = lrail_WindowUpdate; - mod->inst->update->window->WindowDelete = lrail_WindowDelete; - mod->inst->update->window->WindowIcon = lrail_WindowIcon; - mod->inst->update->window->WindowCachedIcon = lrail_WindowCachedIcon; - mod->inst->update->window->NotifyIconCreate = lrail_NotifyIconCreate; - mod->inst->update->window->NotifyIconUpdate = lrail_NotifyIconUpdate; - mod->inst->update->window->NotifyIconDelete = lrail_NotifyIconDelete; - mod->inst->update->window->MonitoredDesktop = lrail_MonitoredDesktop; - mod->inst->update->window->NonMonitoredDesktop = lrail_NonMonitoredDesktop; - - return TRUE; -} - -/******************************************************************************/ -static void DEFAULT_CC -lfreerdp_context_new(freerdp *instance, rdpContext *context) -{ - LLOGLN(0, ("lfreerdp_context_new: %p", context)); -} - -/******************************************************************************/ -static void DEFAULT_CC -lfreerdp_context_free(freerdp *instance, rdpContext *context) -{ - LLOGLN(0, ("lfreerdp_context_free: - no code here")); -} - -/******************************************************************************/ -static int DEFAULT_CC -lfreerdp_receive_channel_data(freerdp *instance, int channelId, UINT8 *data, - int size, int flags, int total_size) -{ - struct mod *mod; - int lchid; - int index; - int error; - - mod = ((struct mod_context *)(instance->context))->modi; - lchid = -1; - - for (index = 0; index < instance->settings->ChannelDefArraySize; index++) - { - if (instance->settings->ChannelDefArray[index].ChannelId == channelId) - { - lchid = index; - break; - } - } - - if (lchid >= 0) - { - LLOGLN(10, ("lfreerdp_receive_channel_data: server to client")); - error = mod->server_send_to_channel(mod, lchid, (char *)data, size, - total_size, flags); - - if (error != 0) - { - LLOGLN(0, ("lfreerdp_receive_channel_data: error %d", error)); - } - } - else - { - LLOGLN(0, ("lfreerdp_receive_channel_data: bad lchid")); - } - - return 0; -} - -/******************************************************************************/ -static BOOL DEFAULT_CC -lfreerdp_authenticate(freerdp *instance, char **username, - char **password, char **domain) -{ - LLOGLN(0, ("lfreerdp_authenticate: - no code here")); - return TRUE; -} - -/******************************************************************************/ -static BOOL DEFAULT_CC -lfreerdp_verify_certificate(freerdp *instance, char *subject, char *issuer, - char *fingerprint) -{ - LLOGLN(0, ("lfreerdp_verify_certificate: - no code here")); - return TRUE; -} - -/******************************************************************************/ -struct mod *EXPORT_CC -mod_init(void) -{ - struct mod *mod; - modContext *lcon; - - LLOGLN(0, ("mod_init:")); - mod = (struct mod *)g_malloc(sizeof(struct mod), 1); - freerdp_get_version(&(mod->vmaj), &(mod->vmin), &(mod->vrev)); - LLOGLN(0, (" FreeRDP version major %d minor %d revision %d", - mod->vmaj, mod->vmin, mod->vrev)); - mod->size = sizeof(struct mod); - mod->version = CURRENT_MOD_VER; - mod->handle = (tbus)mod; - mod->mod_connect = lxrdp_connect; - mod->mod_start = lxrdp_start; - mod->mod_event = lxrdp_event; - mod->mod_signal = lxrdp_signal; - mod->mod_end = lxrdp_end; - mod->mod_set_param = lxrdp_set_param; - mod->mod_session_change = lxrdp_session_change; - mod->mod_get_wait_objs = lxrdp_get_wait_objs; - mod->mod_check_wait_objs = lxrdp_check_wait_objs; - - mod->inst = freerdp_new(); - mod->inst->PreConnect = lfreerdp_pre_connect; - mod->inst->PostConnect = lfreerdp_post_connect; - mod->inst->context_size = sizeof(modContext); - mod->inst->ContextNew = lfreerdp_context_new; - mod->inst->ContextFree = lfreerdp_context_free; - mod->inst->ReceiveChannelData = lfreerdp_receive_channel_data; - mod->inst->Authenticate = lfreerdp_authenticate; - mod->inst->VerifyCertificate = lfreerdp_verify_certificate; - - freerdp_context_new(mod->inst); - - lcon = (modContext *)(mod->inst->context); - lcon->modi = mod; - LLOGLN(10, ("mod_init: mod %p", mod)); - - return mod; -} - -/******************************************************************************/ -int EXPORT_CC -mod_exit(struct mod *mod) -{ - LLOGLN(0, ("mod_exit:")); - - if (mod == 0) - { - return 0; - } - - if (mod->inst == NULL) - { - LLOGLN(0, ("mod_exit - null pointer for inst:")); - g_free(mod); - return 0 ; - } - - freerdp_disconnect(mod->inst); - - if ((mod->vmaj == 1) && (mod->vmin == 0) && (mod->vrev == 1)) - { - /* this version has a bug with double free in freerdp_free */ - } - else - { - freerdp_context_free(mod->inst); - } - - freerdp_free(mod->inst); - g_free(mod); - return 0; -} diff --git a/freerdp1/xrdp-freerdp.h b/freerdp1/xrdp-freerdp.h deleted file mode 100644 index c2956b4d..00000000 --- a/freerdp1/xrdp-freerdp.h +++ /dev/null @@ -1,180 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Server - * freerdp wrapper - * - * Copyright 2011-2012 Jay Sorg - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* include other h files */ -#include "arch.h" -#include "parse.h" -#include "os_calls.h" -#include "defines.h" -#include "xrdp_rail.h" -#include "xrdp_client_info.h" - -/* this is the freerdp main header */ -#include <freerdp/freerdp.h> -#include <freerdp/rail.h> -#include <freerdp/rail/rail.h> -#include <freerdp/codec/bitmap.h> -//#include <freerdp/utils/memory.h> -//#include "/home/jay/git/jsorg71/staging/include/freerdp/freerdp.h" - -struct bitmap_item -{ - int width; - int height; - char* data; -}; - -struct brush_item -{ - int bpp; - int width; - int height; - char* data; - char b8x8[8]; -}; - -struct pointer_item -{ - int hotx; - int hoty; - char data[32 * 32 * 3]; - char mask[32 * 32 / 8]; -}; - -#define CURRENT_MOD_VER 2 - -struct mod -{ - int size; /* size of this struct */ - int version; /* internal version */ - /* client functions */ - int (*mod_start)(struct mod* v, int w, int h, int bpp); - int (*mod_connect)(struct mod* v); - int (*mod_event)(struct mod* v, int msg, long param1, long param2, - long param3, long param4); - int (*mod_signal)(struct mod* v); - int (*mod_end)(struct mod* v); - int (*mod_set_param)(struct mod* v, char* name, char* value); - int (*mod_session_change)(struct mod* v, int, int); - int (*mod_get_wait_objs)(struct mod* v, tbus* read_objs, int* rcount, - tbus* write_objs, int* wcount, int* timeout); - int (*mod_check_wait_objs)(struct mod* v); - long mod_dumby[100 - 9]; /* align, 100 minus the number of mod - functions above */ - /* server functions */ - int (*server_begin_update)(struct mod* v); - int (*server_end_update)(struct mod* v); - int (*server_fill_rect)(struct mod* v, int x, int y, int cx, int cy); - int (*server_screen_blt)(struct mod* v, int x, int y, int cx, int cy, - int srcx, int srcy); - int (*server_paint_rect)(struct mod* v, int x, int y, int cx, int cy, - char* data, int width, int height, int srcx, int srcy); - int (*server_set_pointer)(struct mod* v, int x, int y, char* data, char* mask); - int (*server_palette)(struct mod* v, int* palette); - int (*server_msg)(struct mod* v, char* msg, int code); - int (*server_is_term)(struct mod* v); - int (*server_set_clip)(struct mod* v, int x, int y, int cx, int cy); - int (*server_reset_clip)(struct mod* v); - int (*server_set_fgcolor)(struct mod* v, int fgcolor); - int (*server_set_bgcolor)(struct mod* v, int bgcolor); - int (*server_set_opcode)(struct mod* v, int opcode); - int (*server_set_mixmode)(struct mod* v, int mixmode); - int (*server_set_brush)(struct mod* v, int x_orgin, int y_orgin, - int style, char* pattern); - int (*server_set_pen)(struct mod* v, int style, - int width); - int (*server_draw_line)(struct mod* v, int x1, int y1, int x2, int y2); - int (*server_add_char)(struct mod* v, int font, int charactor, - int offset, int baseline, - int width, int height, char* data); - int (*server_draw_text)(struct mod* v, int font, - int flags, int mixmode, int clip_left, int clip_top, - int clip_right, int clip_bottom, - int box_left, int box_top, - int box_right, int box_bottom, - int x, int y, char* data, int data_len); - int (*server_reset)(struct mod* v, int width, int height, int bpp); - int (*server_query_channel)(struct mod* v, int index, - char* channel_name, - int* channel_flags); - int (*server_get_channel_id)(struct mod* v, char* name); - int (*server_send_to_channel)(struct mod* v, int channel_id, - char* data, int data_len, - int total_data_len, int flags); - int (*server_bell_trigger)(struct mod* v); - /* off screen bitmaps */ - int (*server_create_os_surface)(struct mod* v, int rdpindex, - int width, int height); - int (*server_switch_os_surface)(struct mod* v, int rdpindex); - int (*server_delete_os_surface)(struct mod* v, int rdpindex); - int (*server_paint_rect_os)(struct mod* mod, int x, int y, - int cx, int cy, - int rdpindex, int srcx, int srcy); - int (*server_set_hints)(struct mod* mod, int hints, int mask); - /* rail */ - int (*server_window_new_update)(struct mod* mod, int window_id, - struct rail_window_state_order* window_state, - int flags); - int (*server_window_delete)(struct mod* mod, int window_id); - int (*server_window_icon)(struct mod* mod, - int window_id, int cache_entry, int cache_id, - struct rail_icon_info* icon_info, - int flags); - int (*server_window_cached_icon)(struct mod* mod, - int window_id, int cache_entry, - int cache_id, int flags); - int (*server_notify_new_update)(struct mod* mod, - int window_id, int notify_id, - struct rail_notify_state_order* notify_state, - int flags); - int (*server_notify_delete)(struct mod* mod, int window_id, - int notify_id); - int (*server_monitored_desktop)(struct mod* mod, - struct rail_monitored_desktop_order* mdo, - int flags); - - long server_dumby[100 - 37]; /* align, 100 minus the number of server - functions above */ - /* common */ - tbus handle; /* pointer to self as long */ - tbus wm; - tbus painter; - int sck; - /* mod data */ - int width; - int height; - int bpp; - int colormap[256]; - char* chan_buf; - int chan_buf_valid; - int chan_buf_bytes; - int vmaj; - int vmin; - int vrev; - char username[256]; - char password[256]; - - struct xrdp_client_info client_info; - - struct rdp_freerdp* inst; - struct bitmap_item bitmap_cache[4][4096]; - struct brush_item brush_cache[64]; - struct pointer_item pointer_cache[32]; - -}; diff --git a/libxrdp/Makefile.am b/libxrdp/Makefile.am index 4aba9e7e..6564da36 100644 --- a/libxrdp/Makefile.am +++ b/libxrdp/Makefile.am @@ -11,15 +11,22 @@ else EXTRA_DEFINES += -DXRDP_NODEBUG endif -if XRDP_FREERDP1 -EXTRA_DEFINES += -DXRDP_FREERDP1 +if XRDP_NEUTRINORDP +EXTRA_DEFINES += -DXRDP_NEUTRINORDP EXTRA_LIBS += $(FREERDP_LIBS) endif +if XRDP_TJPEG +EXTRA_DEFINES += -DXRDP_JPEG -DXRDP_TJPEG +EXTRA_INCLUDES += -I/opt/libjpeg-turbo/include +EXTRA_FLAGS += -L/opt/libjpeg-turbo/lib -Wl,-rpath -Wl,/opt/libjpeg-turbo/lib +EXTRA_LIBS += -lturbojpeg +else if XRDP_JPEG EXTRA_DEFINES += -DXRDP_JPEG EXTRA_LIBS += -ljpeg endif +endif if GOT_PREFIX EXTRA_INCLUDES += -I$(prefix)/include diff --git a/libxrdp/libxrdp.c b/libxrdp/libxrdp.c index 15e34e91..e72fa1d0 100644 --- a/libxrdp/libxrdp.c +++ b/libxrdp/libxrdp.c @@ -629,6 +629,25 @@ libxrdp_orders_mem_blt(struct xrdp_session *session, int cache_id, } /******************************************************************************/ +int DEFAULT_CC +libxrdp_orders_composite_blt(struct xrdp_session* session, int srcidx, + int srcformat, int srcwidth, int srcrepeat, + int* srctransform, int mskflags, + int mskidx, int mskformat, int mskwidth, + int mskrepeat, int op, int srcx, int srcy, + int mskx, int msky, int dstx, int dsty, + int width, int height, int dstformat, + struct xrdp_rect* rect) +{ + return xrdp_orders_composite_blt((struct xrdp_orders*)session->orders, + srcidx, srcformat, srcwidth, srcrepeat, + srctransform, mskflags, + mskidx, mskformat, mskwidth, mskrepeat, + op, srcx, srcy, mskx, msky, dstx, dsty, + width, height, dstformat, rect); +} + +/******************************************************************************/ int EXPORT_CC libxrdp_orders_text(struct xrdp_session *session, int font, int flags, int mixmode, diff --git a/libxrdp/libxrdp.h b/libxrdp/libxrdp.h index d31edbb4..5bf627b5 100644 --- a/libxrdp/libxrdp.h +++ b/libxrdp/libxrdp.h @@ -49,6 +49,8 @@ struct xrdp_iso { struct xrdp_mcs* mcs_layer; /* owner */ struct xrdp_tcp* tcp_layer; + int requestedProtocol; + int selectedProtocol; }; /* used in mcs */ @@ -99,6 +101,7 @@ struct xrdp_sec char pub_sig[64]; char pri_exp[64]; int channel_code; + int multimon; }; /* channel */ @@ -197,6 +200,28 @@ struct xrdp_orders_state int text_y; int text_len; char* text_data; + + int com_blt_srcidx; /* RDP_ORDER_COMPOSITE */ /* 2 */ + int com_blt_srcformat; /* 2 */ + int com_blt_srcwidth; /* 2 */ + int com_blt_srcrepeat; /* 1 */ + int com_blt_srctransform[10]; /* 40 */ + int com_blt_mskflags; /* 1 */ + int com_blt_mskidx; /* 2 */ + int com_blt_mskformat; /* 2 */ + int com_blt_mskwidth; /* 2 */ + int com_blt_mskrepeat; /* 1 */ + int com_blt_op; /* 1 */ + int com_blt_srcx; /* 2 */ + int com_blt_srcy; /* 2 */ + int com_blt_mskx; /* 2 */ + int com_blt_msky; /* 2 */ + int com_blt_dstx; /* 2 */ + int com_blt_dsty; /* 2 */ + int com_blt_width; /* 2 */ + int com_blt_height; /* 2 */ + int com_blt_dstformat; /* 2 */ + }; /* orders */ @@ -211,6 +236,8 @@ struct xrdp_orders int order_count; int order_level; /* inc for every call to xrdp_orders_init */ struct xrdp_orders_state orders_state; + void* jpeg_han; + int rfx_min_pixel; }; #define PROTO_RDP_40 1 @@ -285,7 +312,7 @@ xrdp_mcs_disconnect(struct xrdp_mcs* self); /* xrdp_sec.c */ struct xrdp_sec* APP_CC xrdp_sec_create(struct xrdp_rdp* owner, struct trans* trans, int crypt_level, - int channel_code); + int channel_code, int multimon); void APP_CC xrdp_sec_delete(struct xrdp_sec* self); int APP_CC @@ -378,6 +405,15 @@ xrdp_orders_mem_blt(struct xrdp_orders* self, int cache_id, int rop, int srcx, int srcy, int cache_idx, struct xrdp_rect* rect); int APP_CC +xrdp_orders_composite_blt(struct xrdp_orders* self, int srcidx, + int srcformat, int srcwidth, + int srcrepeat, int* srctransform, int mskflags, + int mskidx, int mskformat, int mskwidth, + int mskrepeat, int op, int srcx, int srcy, + int mskx, int msky, int dstx, int dsty, + int width, int height, int dstformat, + struct xrdp_rect* rect); +int APP_CC xrdp_orders_text(struct xrdp_orders* self, int font, int flags, int mixmode, int fg_color, int bg_color, @@ -431,10 +467,14 @@ xrdp_bitmap_compress(char* in_data, int width, int height, int start_line, struct stream* temp_s, int e); int APP_CC -xrdp_jpeg_compress(char* in_data, int width, int height, +xrdp_jpeg_compress(void *handle, char* in_data, int width, int height, struct stream* s, int bpp, int byte_limit, int start_line, struct stream* temp_s, int e, int quality); +void *APP_CC +xrdp_jpeg_init(void); +int APP_CC +xrdp_jpeg_deinit(void *handle); /* xrdp_channel.c */ struct xrdp_channel* APP_CC diff --git a/libxrdp/libxrdpinc.h b/libxrdp/libxrdpinc.h index b971204e..e5f52a05 100644 --- a/libxrdp/libxrdpinc.h +++ b/libxrdp/libxrdpinc.h @@ -40,13 +40,15 @@ struct xrdp_pen int color; }; +/* 2.2.2.2.1.2.5.1 Cache Glyph Data (TS_CACHE_GLYPH_DATA) */ struct xrdp_font_char { - int offset; - int baseline; - int width; - int height; + int offset; /* x */ + int baseline; /* y */ + int width; /* cx */ + int height; /* cy */ int incby; + int bpp; char* data; }; @@ -128,6 +130,16 @@ libxrdp_orders_mem_blt(struct xrdp_session* session, int cache_id, int rop, int srcx, int srcy, int cache_idx, struct xrdp_rect* rect); int DEFAULT_CC +libxrdp_orders_composite_blt(struct xrdp_session* session, int srcidx, + int srcformat, int srcwidth, int srcrepeat, + int* srctransform, int mskflags, + int mskidx, int mskformat, int mskwidth, + int mskrepeat, int op, int srcx, int srcy, + int mskx, int msky, int dstx, int dsty, + int width, int height, int dstformat, + struct xrdp_rect* rect); + +int DEFAULT_CC libxrdp_orders_text(struct xrdp_session* session, int font, int flags, int mixmode, int fg_color, int bg_color, diff --git a/libxrdp/xrdp_iso.c b/libxrdp/xrdp_iso.c index d851c1bb..69c242d3 100644 --- a/libxrdp/xrdp_iso.c +++ b/libxrdp/xrdp_iso.c @@ -2,6 +2,7 @@ * xrdp: A Remote Desktop Protocol server. * * Copyright (C) Jay Sorg 2004-2013 + * Copyright (C) Idan Freiberg 2013 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -50,12 +51,49 @@ xrdp_iso_delete(struct xrdp_iso *self) /*****************************************************************************/ /* returns error */ static int APP_CC -xrdp_iso_recv_msg(struct xrdp_iso *self, struct stream *s, int *code) +xrdp_iso_recv_rdpnegreq(struct xrdp_iso *self, struct stream *s) { - int ver; + int flags; int len; - *code = 0; + DEBUG((" in xrdp_iso_recv_rdpnegreq")); + + in_uint8(s, flags); + if (flags != 0x0) + { + DEBUG((" xrdp_iso_recv_rdpnegreq: flags: %x",flags)); + return 1; + } + + in_uint16_le(s, len); + if (len != 8) // fixed length + { + DEBUG((" xrdp_iso_recv_rdpnegreq: length: %x",len)); + return 1; + } + + in_uint32_le(s, self->requestedProtocol); + + //TODO: think of protocol verification logic +// if (requestedProtocol != PROTOCOL_RDP || PROTOCOL_SSL || PROTOCOL_HYBRID || PROTOCOL_HYBRID_EX) +// { +// DEBUG((" xrdp_iso_recv_rdpnegreq: wrong requestedProtocol: %x",requestedProtocol)); +// return 1; +// } + + DEBUG((" out xrdp_iso_recv_rdpnegreq")); + return 0; +} +/*****************************************************************************/ +/* returns error */ +static int APP_CC +xrdp_iso_recv_msg(struct xrdp_iso *self, struct stream *s, int *code, int *len) +{ + int ver; // TPKT Version + int plen; // TPKT PacketLength + + *code = 0; // X.224 Packet Type + *len = 0; // X.224 Length Indicator if (xrdp_tcp_recv(self->tcp_layer, s, 4) != 0) { @@ -70,46 +108,64 @@ xrdp_iso_recv_msg(struct xrdp_iso *self, struct stream *s, int *code) } in_uint8s(s, 1); - in_uint16_be(s, len); + in_uint16_be(s, plen); - if (xrdp_tcp_recv(self->tcp_layer, s, len - 4) != 0) + if (plen < 4) { return 1; } - in_uint8s(s, 1); + if (xrdp_tcp_recv(self->tcp_layer, s, plen - 4) != 0) + { + return 1; + } + + if (!s_check_rem(s, 2)) + { + return 1; + } + + in_uint8(s, *len); in_uint8(s, *code); if (*code == ISO_PDU_DT) { + if (!s_check_rem(s, 1)) + { + return 1; + } in_uint8s(s, 1); } else { + if (!s_check_rem(s, 5)) + { + return 1; + } in_uint8s(s, 5); } return 0; } - /*****************************************************************************/ /* returns error */ int APP_CC xrdp_iso_recv(struct xrdp_iso *self, struct stream *s) { int code; + int len; DEBUG((" in xrdp_iso_recv")); - if (xrdp_iso_recv_msg(self, s, &code) != 0) + if (xrdp_iso_recv_msg(self, s, &code, &len) != 0) { DEBUG((" out xrdp_iso_recv xrdp_iso_recv_msg return non zero")); return 1; } - if (code != ISO_PDU_DT) + if (code != ISO_PDU_DT || len != 2) { - DEBUG((" out xrdp_iso_recv code != ISO_PDU_DT")); + DEBUG((" out xrdp_iso_recv code != ISO_PDU_DT or length != 2")); return 1; } @@ -119,21 +175,79 @@ xrdp_iso_recv(struct xrdp_iso *self, struct stream *s) /*****************************************************************************/ static int APP_CC -xrdp_iso_send_msg(struct xrdp_iso *self, struct stream *s, int code) +xrdp_iso_send_rdpnegrsp(struct xrdp_iso *self, struct stream *s, int code) { if (xrdp_tcp_init(self->tcp_layer, s) != 0) { return 1; } - out_uint8(s, 3); + /* TPKT HEADER - 4 bytes */ + out_uint8(s, 3); /* version */ + out_uint8(s, 0); /* RESERVED */ + if (self->selectedProtocol != -1) + { + out_uint16_be(s, 19); /* length */ //rdp negotiation happens. + } + else + { + out_uint16_be(s, 11); /* length */ //rdp negotiation doesn't happen. + } + /* ISO LAYER - X.224 - 7 bytes*/ + if (self->selectedProtocol != -1) + { + out_uint8(s, 14); /* length */ + } + else + { + out_uint8(s, 6); /* length */ + } + out_uint8(s, code); /* SHOULD BE 0xD for CC */ + out_uint16_be(s, 0); + out_uint16_be(s, 0x1234); out_uint8(s, 0); - out_uint16_be(s, 11); /* length */ - out_uint8(s, 6); - out_uint8(s, code); - out_uint16_le(s, 0); - out_uint16_le(s, 0); + if (self->selectedProtocol != -1) + { + /* RDP_NEG_RSP - 8 bytes*/ + out_uint8(s, RDP_NEG_RSP); + out_uint8(s, EXTENDED_CLIENT_DATA_SUPPORTED); /* flags */ + out_uint16_le(s, 8); /* fixed length */ + out_uint32_le(s, self->selectedProtocol); /* selected protocol */ + } + + s_mark_end(s); + + if (xrdp_tcp_send(self->tcp_layer, s) != 0) + { + return 1; + } + + return 0; +} +/*****************************************************************************/ +static int APP_CC +xrdp_iso_send_rdpnegfailure(struct xrdp_iso *self, struct stream *s, int code, int failureCode) +{ + if (xrdp_tcp_init(self->tcp_layer, s) != 0) + { + return 1; + } + + /* TPKT HEADER - 4 bytes */ + out_uint8(s, 3); /* version */ + out_uint8(s, 0); /* RESERVED */ + out_uint16_be(s, 19); /* length */ + /* ISO LAYER - X.224 - 7 bytes*/ + out_uint8(s, 14); /* length */ + out_uint8(s, code); /* SHOULD BE 0xD for CC */ + out_uint16_be(s, 0); + out_uint16_be(s, 0x1234); out_uint8(s, 0); + /* RDP_NEG_FAILURE - 8 bytes*/ + out_uint8(s, RDP_NEG_FAILURE); + out_uint8(s, 0); /* no flags available */ + out_uint16_le(s, 8); /* fixed length */ + out_uint32_le(s, failureCode); /* failure code */ s_mark_end(s); if (xrdp_tcp_send(self->tcp_layer, s) != 0) @@ -145,30 +259,111 @@ xrdp_iso_send_msg(struct xrdp_iso *self, struct stream *s, int code) } /*****************************************************************************/ +static int APP_CC +xrdp_iso_send_nego(struct xrdp_iso *self) +{ + struct stream *s; + + make_stream(s); + init_stream(s, 8192); + + //TODO: negotiation logic here. + if (self->requestedProtocol != PROTOCOL_RDP) + { + // Send RDP_NEG_FAILURE back to client + if (xrdp_iso_send_rdpnegfailure(self, s, ISO_PDU_CC, + SSL_NOT_ALLOWED_BY_SERVER) != 0) + { + free_stream(s); + return 1; + } + } + else + { + self->selectedProtocol = PROTOCOL_RDP; + // Send RDP_NEG_RSP back to client + if (xrdp_iso_send_rdpnegrsp(self, s, ISO_PDU_CC) != 0) + { + free_stream(s); + return 1; + } + } + free_stream(s); + return 0; +} + +/*****************************************************************************/ /* returns error */ int APP_CC xrdp_iso_incoming(struct xrdp_iso *self) { int code; + int len; + int cookie_index; + int cc_type; + char text[256]; + char *pend; struct stream *s; make_stream(s); init_stream(s, 8192); DEBUG((" in xrdp_iso_incoming")); - if (xrdp_iso_recv_msg(self, s, &code) != 0) + if (xrdp_iso_recv_msg(self, s, &code, &len) != 0) { + DEBUG((" in xrdp_iso_recv_msg error!!")); free_stream(s); return 1; } - if (code != ISO_PDU_CR) + if ((code != ISO_PDU_CR) || (len < 6)) { free_stream(s); return 1; } - if (xrdp_iso_send_msg(self, s, ISO_PDU_CC) != 0) + self->selectedProtocol = -1; + self->requestedProtocol = PROTOCOL_RDP; + + pend = s->p + (len - 6); + cookie_index = 0; + while (s->p < pend) + { + in_uint8(s, cc_type); + switch (cc_type) + { + default: + break; + case RDP_NEG_REQ: /* rdpNegReq 1 */ + if (xrdp_iso_recv_rdpnegreq(self, s) != 0) + { + free_stream(s); + return 1; + } + break; + case RDP_CORRELATION_INFO: /* rdpCorrelationInfo 6 */ + // TODO + in_uint8s(s, 1 + 2 + 16 + 16); + break; + case 'C': /* Cookie routingToken */ + while (s->p < pend) + { + text[cookie_index] = cc_type; + cookie_index++; + if ((s->p[0] == 0x0D) && (s->p[1] == 0x0A)) + { + in_uint8s(s, 2); + text[cookie_index] = 0; + cookie_index = 0; + break; + } + in_uint8(s, cc_type); + } + break; + } + } + + if (xrdp_iso_send_nego(self) != 0) { free_stream(s); return 1; @@ -198,7 +393,7 @@ xrdp_iso_send(struct xrdp_iso *self, struct stream *s) DEBUG((" in xrdp_iso_send")); s_pop_layer(s, iso_hdr); - len = s->end - s->p; + len = (int)(s->end - s->p); out_uint8(s, 3); out_uint8(s, 0); out_uint16_be(s, len); diff --git a/libxrdp/xrdp_jpeg_compress.c b/libxrdp/xrdp_jpeg_compress.c index 82a816a0..a41bd1cf 100644 --- a/libxrdp/xrdp_jpeg_compress.c +++ b/libxrdp/xrdp_jpeg_compress.c @@ -20,7 +20,112 @@ #include "libxrdp.h" -#if defined(XRDP_JPEG) +#if defined(XRDP_TJPEG) + +/* turbo jpeg */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <turbojpeg.h> + +/*****************************************************************************/ +int APP_CC +xrdp_jpeg_compress(void *handle, char *in_data, int width, int height, + struct stream *s, int bpp, int byte_limit, + int start_line, struct stream *temp_s, + int e, int quality) +{ + int error; + int i; + int j; + unsigned int pixel; + unsigned int *src32; + unsigned int *dst32; + unsigned long cdata_bytes; + unsigned char *src_buf; + unsigned char *dst_buf; + char *temp_buf; + tjhandle tj_han; + + if (bpp != 24) + { + g_writeln("xrdp_jpeg_compress: bpp wrong %d", bpp); + return height; + } + if (handle == 0) + { + g_writeln("xrdp_jpeg_compress: handle is nil"); + return height; + } + tj_han = (tjhandle) handle; + cdata_bytes = byte_limit; + src_buf = (unsigned char *) in_data; + dst_buf = (unsigned char *) (s->p); + temp_buf = 0; + if (e == 0) + { + src_buf = (unsigned char*)in_data; + } + else + { + temp_buf = (char *) g_malloc((width + e) * height * 4, 0); + dst32 = (unsigned int *) temp_buf; + src32 = (unsigned int *) in_data; + for (j = 0; j < height; j++) + { + for (i = 0; i < width; i++) + { + pixel = *src32; + src32++; + *dst32 = pixel; + dst32++; + } + for (i = 0; i < e; i++) + { + *dst32 = pixel; + dst32++; + } + } + src_buf = (unsigned char *) temp_buf; + } + dst_buf = (unsigned char*)(s->p); + error = tjCompress(tj_han, src_buf, width + e, (width + e) * 4, height, + TJPF_XBGR, dst_buf, &cdata_bytes, + TJSAMP_420, quality, 0); + s->p += cdata_bytes; + g_free(temp_buf); + return height; +} + +/*****************************************************************************/ +void *APP_CC +xrdp_jpeg_init(void) +{ + tjhandle tj_han; + + tj_han = tjInitCompress(); + return tj_han; +} + +/*****************************************************************************/ +int APP_CC +xrdp_jpeg_deinit(void *handle) +{ + tjhandle tj_han; + + if (handle == 0) + { + return 0; + } + tj_han = (tjhandle) handle; + tjDestroy(tj_han); + return 0; +} + +#elif defined(XRDP_JPEG) + +/* libjpeg */ #include <stdio.h> #include <stdlib.h> @@ -205,7 +310,7 @@ jpeg_compress(char *in_data, int width, int height, /*****************************************************************************/ int APP_CC -xrdp_jpeg_compress(char *in_data, int width, int height, +xrdp_jpeg_compress(void *handle, char *in_data, int width, int height, struct stream *s, int bpp, int byte_limit, int start_line, struct stream *temp_s, int e, int quality) @@ -215,11 +320,25 @@ xrdp_jpeg_compress(char *in_data, int width, int height, return height; } +/*****************************************************************************/ +void *APP_CC +xrdp_jpeg_init(void) +{ + return 0; +} + +/*****************************************************************************/ +int APP_CC +xrdp_jpeg_deinit(void *handle) +{ + return 0; +} + #else /*****************************************************************************/ int APP_CC -xrdp_jpeg_compress(char *in_data, int width, int height, +xrdp_jpeg_compress(void *handle, char *in_data, int width, int height, struct stream *s, int bpp, int byte_limit, int start_line, struct stream *temp_s, int e, int quality) @@ -227,4 +346,18 @@ xrdp_jpeg_compress(char *in_data, int width, int height, return height; } +/*****************************************************************************/ +void *APP_CC +xrdp_jpeg_init(void) +{ + return 0; +} + +/*****************************************************************************/ +int APP_CC +xrdp_jpeg_deinit(void *handle) +{ + return 0; +} + #endif diff --git a/libxrdp/xrdp_mcs.c b/libxrdp/xrdp_mcs.c index 4bf3d025..c145158c 100644 --- a/libxrdp/xrdp_mcs.c +++ b/libxrdp/xrdp_mcs.c @@ -66,6 +66,7 @@ xrdp_mcs_delete(struct xrdp_mcs *self) } list_delete(self->channel_list); + xrdp_iso_delete(self->iso_layer); /* make sure we get null pointer exception if struct is used again. */ DEBUG(("xrdp_mcs_delete processed")) @@ -132,6 +133,11 @@ xrdp_mcs_recv(struct xrdp_mcs *self, struct stream *s, int *chan) return 1; } + if (!s_check_rem(s, 1)) + { + return 1; + } + in_uint8(s, opcode); appid = opcode >> 2; @@ -145,6 +151,11 @@ xrdp_mcs_recv(struct xrdp_mcs *self, struct stream *s, int *chan) /* this is channels getting added from the client */ if (appid == MCS_CJRQ) { + if (!s_check_rem(s, 4)) + { + return 1; + } + in_uint16_be(s, userid); in_uint16_be(s, chanid); log_message(LOG_LEVEL_DEBUG,"MCS_CJRQ - channel join request received"); @@ -176,6 +187,11 @@ xrdp_mcs_recv(struct xrdp_mcs *self, struct stream *s, int *chan) return 1; } + if (!s_check_rem(s, 6)) + { + return 1; + } + in_uint8s(s, 2); in_uint16_be(s, *chan); in_uint8s(s, 1); @@ -183,6 +199,10 @@ xrdp_mcs_recv(struct xrdp_mcs *self, struct stream *s, int *chan) if (len & 0x80) { + if (!s_check_rem(s, 1)) + { + return 1; + } in_uint8s(s, 1); } @@ -202,10 +222,18 @@ xrdp_mcs_ber_parse_header(struct xrdp_mcs *self, struct stream *s, if (tag_val > 0xff) { + if (!s_check_rem(s, 2)) + { + return 1; + } in_uint16_be(s, tag); } else { + if (!s_check_rem(s, 1)) + { + return 1; + } in_uint8(s, tag); } @@ -214,6 +242,11 @@ xrdp_mcs_ber_parse_header(struct xrdp_mcs *self, struct stream *s, return 1; } + if (!s_check_rem(s, 1)) + { + return 1; + } + in_uint8(s, l); if (l & 0x80) @@ -223,6 +256,10 @@ xrdp_mcs_ber_parse_header(struct xrdp_mcs *self, struct stream *s, while (l > 0) { + if (!s_check_rem(s, 1)) + { + return 1; + } in_uint8(s, i); *len = (*len << 8) | i; l--; @@ -255,6 +292,11 @@ xrdp_mcs_parse_domain_params(struct xrdp_mcs *self, struct stream *s) return 1; } + if ((len < 0) || !s_check_rem(s, len)) + { + return 1; + } + in_uint8s(s, len); if (s_check(s)) @@ -276,7 +318,7 @@ xrdp_mcs_recv_connect_initial(struct xrdp_mcs *self) struct stream *s; make_stream(s); - init_stream(s, 8192); + init_stream(s, 16 * 1024); if (xrdp_iso_recv(self->iso_layer, s) != 0) { @@ -296,6 +338,12 @@ xrdp_mcs_recv_connect_initial(struct xrdp_mcs *self) return 1; } + if ((len < 0) || !s_check_rem(s, len)) + { + free_stream(s); + return 1; + } + in_uint8s(s, len); if (xrdp_mcs_ber_parse_header(self, s, BER_TAG_OCTET_STRING, &len) != 0) @@ -304,6 +352,12 @@ xrdp_mcs_recv_connect_initial(struct xrdp_mcs *self) return 1; } + if ((len < 0) || !s_check_rem(s, len)) + { + free_stream(s); + return 1; + } + in_uint8s(s, len); if (xrdp_mcs_ber_parse_header(self, s, BER_TAG_BOOLEAN, &len) != 0) @@ -312,6 +366,12 @@ xrdp_mcs_recv_connect_initial(struct xrdp_mcs *self) return 1; } + if ((len < 0) || !s_check_rem(s, len)) + { + free_stream(s); + return 1; + } + in_uint8s(s, len); if (xrdp_mcs_parse_domain_params(self, s) != 0) @@ -338,6 +398,19 @@ xrdp_mcs_recv_connect_initial(struct xrdp_mcs *self) return 1; } + /* mcs data can not be zero length */ + if ((len <= 0) || (len > 16 * 1024)) + { + free_stream(s); + return 1; + } + + if (!s_check_rem(s, len)) + { + free_stream(s); + return 1; + } + /* make a copy of client mcs data */ init_stream(self->client_mcs_data, len); out_uint8a(self->client_mcs_data, s->p, len); @@ -364,6 +437,7 @@ xrdp_mcs_recv_edrq(struct xrdp_mcs *self) int opcode; struct stream *s; + DEBUG((" in xrdp_mcs_recv_edrq")); make_stream(s); init_stream(s, 8192); @@ -372,6 +446,12 @@ xrdp_mcs_recv_edrq(struct xrdp_mcs *self) free_stream(s); return 1; } + + if (!s_check_rem(s, 1)) + { + free_stream(s); + return 1; + } in_uint8(s, opcode); @@ -381,11 +461,22 @@ xrdp_mcs_recv_edrq(struct xrdp_mcs *self) return 1; } + if (!s_check_rem(s, 4)) + { + free_stream(s); + return 1; + } + in_uint8s(s, 2); in_uint8s(s, 2); if (opcode & 2) { + if (!s_check_rem(s, 2)) + { + free_stream(s); + return 1; + } in_uint16_be(s, self->userid); } @@ -396,6 +487,7 @@ xrdp_mcs_recv_edrq(struct xrdp_mcs *self) } free_stream(s); + DEBUG((" out xrdp_mcs_recv_edrq")); return 0; } @@ -407,6 +499,7 @@ xrdp_mcs_recv_aurq(struct xrdp_mcs *self) int opcode; struct stream *s; + DEBUG((" in xrdp_mcs_recv_aurq")); make_stream(s); init_stream(s, 8192); @@ -416,6 +509,12 @@ xrdp_mcs_recv_aurq(struct xrdp_mcs *self) return 1; } + if (!s_check_rem(s, 1)) + { + free_stream(s); + return 1; + } + in_uint8(s, opcode); if ((opcode >> 2) != MCS_AURQ) @@ -426,6 +525,11 @@ xrdp_mcs_recv_aurq(struct xrdp_mcs *self) if (opcode & 2) { + if (!s_check_rem(s, 2)) + { + free_stream(s); + return 1; + } in_uint16_be(s, self->userid); } @@ -436,6 +540,7 @@ xrdp_mcs_recv_aurq(struct xrdp_mcs *self) } free_stream(s); + DEBUG((" out xrdp_mcs_recv_aurq")); return 0; } @@ -491,6 +596,12 @@ xrdp_mcs_recv_cjrq(struct xrdp_mcs *self) return 1; } + if (!s_check_rem(s, 1)) + { + free_stream(s); + return 1; + } + in_uint8(s, opcode); if ((opcode >> 2) != MCS_CJRQ) @@ -499,10 +610,21 @@ xrdp_mcs_recv_cjrq(struct xrdp_mcs *self) return 1; } + if (!s_check_rem(s, 4)) + { + free_stream(s); + return 1; + } + in_uint8s(s, 4); if (opcode & 2) { + if (!s_check_rem(s, 2)) + { + free_stream(s); + return 1; + } in_uint8s(s, 2); } diff --git a/libxrdp/xrdp_mppc_enc.c b/libxrdp/xrdp_mppc_enc.c index 05aa6bb6..15125d54 100644 --- a/libxrdp/xrdp_mppc_enc.c +++ b/libxrdp/xrdp_mppc_enc.c @@ -573,18 +573,21 @@ compress_rdp_5(struct xrdp_mppc_enc *enc, tui8 *srcData, int len) outputBuffer = enc->outputBuffer; g_memset(outputBuffer, 0, len); enc->flags = PACKET_COMPR_TYPE_64K; + if (enc->first_pkt) { enc->first_pkt = 0; enc->flagsHold |= PACKET_AT_FRONT; } - if ((enc->historyOffset + len) > enc->buf_len) + if ((enc->historyOffset + len) >= enc->buf_len) { /* historyBuffer cannot hold srcData - rewind it */ enc->historyOffset = 0; - enc->flagsHold |= PACKET_AT_FRONT; g_memset(hash_table, 0, enc->buf_len * 2); + g_memset(enc->historyBuffer, 0, enc->buf_len); // added + enc->first_pkt = 0; + enc->flagsHold |= PACKET_AT_FRONT; } /* point to next free byte in historyBuffer */ @@ -602,7 +605,7 @@ compress_rdp_5(struct xrdp_mppc_enc *enc, tui8 *srcData, int len) /* first 2 bytes,because minimum LoM is 3 */ if (historyOffset == 0) { - /* encode first two bytes are literals */ + /* encode first two bytes as literals */ for (x = 0; x < 2; x++) { data = *(historyPointer + x); @@ -974,8 +977,14 @@ compress_rdp_5(struct xrdp_mppc_enc *enc, tui8 *srcData, int len) /* give up */ enc->historyOffset = 0; g_memset(hash_table, 0, enc->buf_len * 2); + g_memset(enc->historyBuffer, 0, enc->buf_len); enc->flagsHold |= PACKET_FLUSHED; enc->first_pkt = 1; + + g_memcpy(enc->outputBuffer, srcData, len); + enc->bytes_in_opb = len; + enc->flags = 0x81; + return 1; } else if (opb_index + 1 > len) @@ -984,8 +993,14 @@ compress_rdp_5(struct xrdp_mppc_enc *enc, tui8 *srcData, int len) /* give up */ enc->historyOffset = 0; g_memset(hash_table, 0, enc->buf_len * 2); + g_memset(enc->historyBuffer, 0, enc->buf_len); enc->flagsHold |= PACKET_FLUSHED; enc->first_pkt = 1; + + g_memcpy(enc->outputBuffer, srcData, len); + enc->bytes_in_opb = len; + enc->flags = 0x81; + return 1; } @@ -1000,8 +1015,14 @@ compress_rdp_5(struct xrdp_mppc_enc *enc, tui8 *srcData, int len) /* give up */ enc->historyOffset = 0; g_memset(hash_table, 0, enc->buf_len * 2); + g_memset(enc->historyBuffer, 0, enc->buf_len); enc->flagsHold |= PACKET_FLUSHED; enc->first_pkt = 1; + + g_memcpy(enc->outputBuffer, srcData, len); + enc->bytes_in_opb = len; + enc->flags = 0x81; + return 1; } enc->flags |= PACKET_COMPRESSED; @@ -1011,6 +1032,8 @@ compress_rdp_5(struct xrdp_mppc_enc *enc, tui8 *srcData, int len) enc->flagsHold = 0; DLOG(("\n")); + //g_writeln("compression ratio: %f", (float) len / (float) enc->bytes_in_opb); + return 1; } diff --git a/libxrdp/xrdp_orders.c b/libxrdp/xrdp_orders.c index 29234173..0e2d90d2 100644 --- a/libxrdp/xrdp_orders.c +++ b/libxrdp/xrdp_orders.c @@ -20,7 +20,7 @@ #include "libxrdp.h" -#if defined(XRDP_FREERDP1) +#if defined(XRDP_NEUTRINORDP) #include <freerdp/codec/rfx.h> #endif @@ -47,6 +47,12 @@ xrdp_orders_create(struct xrdp_session *session, struct xrdp_rdp *rdp_layer) init_stream(self->out_s, 16384); self->orders_state.clip_right = 1; /* silly rdp right clip */ self->orders_state.clip_bottom = 1; /* silly rdp bottom clip */ + self->jpeg_han = xrdp_jpeg_init(); + self->rfx_min_pixel = rdp_layer->client_info.rfx_min_pixel; + if (self->rfx_min_pixel == 0) + { + self->rfx_min_pixel = 64 * 32; + } return self; } @@ -59,6 +65,7 @@ xrdp_orders_delete(struct xrdp_orders *self) return; } + xrdp_jpeg_deinit(self->jpeg_han); free_stream(self->out_s); g_free(self->orders_state.text_data); g_free(self); @@ -200,6 +207,7 @@ xrdp_orders_check(struct xrdp_orders *self, int max_size) } else { + xrdp_orders_init(self); return 0; } } @@ -462,7 +470,10 @@ xrdp_orders_rect(struct xrdp_orders *self, int x, int y, int cx, int cy, char *present_ptr; char *order_flags_ptr; - xrdp_orders_check(self, 23); + if (xrdp_orders_check(self, 23) != 0) + { + return 1; + } self->order_count++; order_flags = RDP_ORDER_STANDARD; @@ -630,7 +641,10 @@ xrdp_orders_screen_blt(struct xrdp_orders *self, int x, int y, char *present_ptr = (char *)NULL; char *order_flags_ptr = (char *)NULL; - xrdp_orders_check(self, 25); + if (xrdp_orders_check(self, 25) != 0) + { + return 1; + } self->order_count++; order_flags = RDP_ORDER_STANDARD; @@ -819,7 +833,10 @@ xrdp_orders_pat_blt(struct xrdp_orders *self, int x, int y, char *order_flags_ptr; struct xrdp_brush blank_brush; - xrdp_orders_check(self, 39); + if (xrdp_orders_check(self, 39) != 0) + { + return 1; + } self->order_count++; order_flags = RDP_ORDER_STANDARD; @@ -1033,7 +1050,10 @@ xrdp_orders_dest_blt(struct xrdp_orders *self, int x, int y, char *present_ptr; char *order_flags_ptr; - xrdp_orders_check(self, 21); + if (xrdp_orders_check(self, 21) != 0) + { + return 1; + } self->order_count++; order_flags = RDP_ORDER_STANDARD; @@ -1201,7 +1221,10 @@ xrdp_orders_line(struct xrdp_orders *self, int mix_mode, rop = 0x0d; /* R2_COPYPEN */ } - xrdp_orders_check(self, 32); + if (xrdp_orders_check(self, 32) != 0) + { + return 1; + } self->order_count++; order_flags = RDP_ORDER_STANDARD; @@ -1400,7 +1423,10 @@ xrdp_orders_mem_blt(struct xrdp_orders *self, int cache_id, char *present_ptr = (char *)NULL; char *order_flags_ptr = (char *)NULL; - xrdp_orders_check(self, 30); + if (xrdp_orders_check(self, 30) != 0) + { + return 1; + } self->order_count++; order_flags = RDP_ORDER_STANDARD; @@ -1592,6 +1618,335 @@ xrdp_orders_mem_blt(struct xrdp_orders *self, int cache_id, /*****************************************************************************/ /* returns error */ int APP_CC +xrdp_orders_composite_blt(struct xrdp_orders* self, int srcidx, int srcformat, + int srcwidth, int srcrepeat, int* srctransform, + int mskflags, int mskidx, int mskformat, + int mskwidth, int mskrepeat, int op, + int srcx, int srcy, int mskx, int msky, + int dstx, int dsty, int width, int height, + int dstformat, + struct xrdp_rect* rect) +{ + int order_flags; + int vals[20]; + int present; + char* present_ptr; + char* order_flags_ptr; + + if (xrdp_orders_check(self, 80) != 0) + { + return 1; + } + self->order_count++; + order_flags = RDP_ORDER_STANDARD; + if (self->orders_state.last_order != RDP_ORDER_COMPOSITE) + { + order_flags |= RDP_ORDER_CHANGE; + } + self->orders_state.last_order = RDP_ORDER_COMPOSITE; + if (rect != 0) + { + /* if clip is present, still check if its needed */ + if (dstx < rect->left || dsty < rect->top || + dstx + width > rect->right || dsty + height > rect->bottom) + { + order_flags |= RDP_ORDER_BOUNDS; + if (xrdp_orders_last_bounds(self, rect)) + { + + order_flags |= RDP_ORDER_LASTBOUNDS; + + } + } + } + vals[0] = srcx; + vals[1] = self->orders_state.com_blt_srcx; + vals[2] = srcy; + vals[3] = self->orders_state.com_blt_srcy; + vals[4] = mskx; + vals[5] = self->orders_state.com_blt_mskx; + vals[6] = msky; + vals[7] = self->orders_state.com_blt_msky; + vals[8] = dstx; + vals[9] = self->orders_state.com_blt_dstx; + vals[10] = dsty; + vals[11] = self->orders_state.com_blt_dsty; + vals[12] = width; + vals[13] = self->orders_state.com_blt_width; + vals[14] = height; + vals[15] = self->orders_state.com_blt_height; + vals[16] = srcwidth; + vals[17] = self->orders_state.com_blt_srcwidth; + vals[18] = mskwidth; + vals[19] = self->orders_state.com_blt_mskwidth; + if (xrdp_orders_send_delta(self, vals, 20)) + { + order_flags |= RDP_ORDER_DELTA; + } + /* order_flags, set later, 1 byte */ + order_flags_ptr = self->out_s->p; + out_uint8s(self->out_s, 1); + if (order_flags & RDP_ORDER_CHANGE) + { + out_uint8(self->out_s, self->orders_state.last_order); + } + present = 0; + /* present, set later, 3 bytes */ + present_ptr = self->out_s->p; + out_uint8s(self->out_s, 3); + if ((order_flags & RDP_ORDER_BOUNDS) && + !(order_flags & RDP_ORDER_LASTBOUNDS)) + { + xrdp_orders_out_bounds(self, rect); + } + + if (srcidx != self->orders_state.com_blt_srcidx) + { + present |= 0x000001; + out_uint16_le(self->out_s, srcidx); + self->orders_state.com_blt_srcidx = srcidx; + } + + if (srcformat != self->orders_state.com_blt_srcformat) + { + present |= 0x000002; + out_uint32_le(self->out_s, srcformat); + self->orders_state.com_blt_srcformat = srcformat; + } + + if (srcwidth != self->orders_state.com_blt_srcwidth) + { + present |= 0x000004; + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, srcwidth - self->orders_state.com_blt_srcwidth); + } + else + { + out_uint16_le(self->out_s, srcwidth); + } + self->orders_state.com_blt_srcwidth = srcwidth; + } + + if (srcrepeat != self->orders_state.com_blt_srcrepeat) + { + present |= 0x000008; + out_uint8(self->out_s, srcrepeat); + self->orders_state.com_blt_srcrepeat = srcrepeat; + } + + if (srctransform != 0) + { + if (srctransform[0] != self->orders_state.com_blt_srctransform[0]) + { + present |= 0x000010; + out_uint32_le(self->out_s, srctransform[0]); + self->orders_state.com_blt_srctransform[0] = srctransform[0]; + } + if (g_memcmp(&(srctransform[1]), + &(self->orders_state.com_blt_srctransform[1]), + 36) != 0) + { + present |= 0x000020; + out_uint32_le(self->out_s, srctransform[1]); + out_uint32_le(self->out_s, srctransform[2]); + out_uint32_le(self->out_s, srctransform[3]); + out_uint32_le(self->out_s, srctransform[4]); + out_uint32_le(self->out_s, srctransform[5]); + out_uint32_le(self->out_s, srctransform[6]); + out_uint32_le(self->out_s, srctransform[7]); + out_uint32_le(self->out_s, srctransform[8]); + out_uint32_le(self->out_s, srctransform[9]); + } + } + else + { + if (self->orders_state.com_blt_srctransform[0] != 0) + { + present |= 0x000010; + out_uint32_le(self->out_s, 0); + self->orders_state.com_blt_srctransform[0] = 0; + } + } + + if (mskflags != self->orders_state.com_blt_mskflags) + { + present |= 0x000040; + out_uint8(self->out_s, mskflags); + self->orders_state.com_blt_mskflags = mskflags; + } + + if (mskidx != self->orders_state.com_blt_mskidx) + { + present |= 0x000080; + out_uint16_le(self->out_s, mskidx); + self->orders_state.com_blt_mskidx = mskidx; + } + + if (mskformat != self->orders_state.com_blt_mskformat) + { + present |= 0x000100; + out_uint32_le(self->out_s, mskformat); + self->orders_state.com_blt_mskformat = mskformat; + } + + if (mskwidth != self->orders_state.com_blt_mskwidth) + { + present |= 0x000200; + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, mskwidth - self->orders_state.com_blt_mskwidth); + } + else + { + out_uint16_le(self->out_s, mskwidth); + } + self->orders_state.com_blt_mskwidth = mskwidth; + } + + if (mskrepeat != self->orders_state.com_blt_mskrepeat) + { + present |= 0x000400; + out_uint8(self->out_s, mskrepeat); + self->orders_state.com_blt_mskrepeat = mskrepeat; + } + + if (op != self->orders_state.com_blt_op) + { + present |= 0x000800; + out_uint8(self->out_s, op); + self->orders_state.com_blt_op = op; + } + + if (srcx != self->orders_state.com_blt_srcx) + { + present |= 0x001000; + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, srcx - self->orders_state.com_blt_srcx); + } + else + { + out_uint16_le(self->out_s, srcx); + } + self->orders_state.com_blt_srcx = srcx; + } + + if (srcy != self->orders_state.com_blt_srcy) + { + present |= 0x002000; + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, srcy - self->orders_state.com_blt_srcy); + } + else + { + out_uint16_le(self->out_s, srcy); + } + self->orders_state.com_blt_srcy = srcy; + } + + if (mskx != self->orders_state.com_blt_mskx) + { + present |= 0x004000; + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, mskx - self->orders_state.com_blt_mskx); + } + else + { + out_uint16_le(self->out_s, mskx); + } + self->orders_state.com_blt_mskx = mskx; + } + + if (msky != self->orders_state.com_blt_msky) + { + present |= 0x008000; + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, msky - self->orders_state.com_blt_msky); + } + else + { + out_uint16_le(self->out_s, msky); + } + self->orders_state.com_blt_msky = msky; + } + + if (dstx != self->orders_state.com_blt_dstx) + { + present |= 0x010000; + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, dstx - self->orders_state.com_blt_dstx); + } + else + { + out_uint16_le(self->out_s, dstx); + } + self->orders_state.com_blt_dstx = dstx; + } + + if (dsty != self->orders_state.com_blt_dsty) + { + present |= 0x020000; + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, dsty - self->orders_state.com_blt_dsty); + } + else + { + out_uint16_le(self->out_s, dsty); + } + self->orders_state.com_blt_dsty = dsty; + } + + if (width != self->orders_state.com_blt_width) + { + present |= 0x040000; + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, width - self->orders_state.com_blt_width); + } + else + { + out_uint16_le(self->out_s, width); + } + self->orders_state.com_blt_width = width; + } + + if (height != self->orders_state.com_blt_height) + { + present |= 0x080000; + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, height - self->orders_state.com_blt_height); + } + else + { + out_uint16_le(self->out_s, height); + } + self->orders_state.com_blt_height = height; + } + + if (dstformat != self->orders_state.com_blt_dstformat) + { + present |= 0x100000; + out_uint32_le(self->out_s, dstformat); + self->orders_state.com_blt_dstformat = dstformat; + } + + xrdp_order_pack_small_or_tiny(self, order_flags_ptr, order_flags, + + present_ptr, present, 3); + + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC xrdp_orders_text(struct xrdp_orders *self, int font, int flags, int mixmode, int fg_color, int bg_color, @@ -1607,8 +1962,10 @@ xrdp_orders_text(struct xrdp_orders *self, char *present_ptr = (char *)NULL; char *order_flags_ptr = (char *)NULL; - //xrdp_orders_check(self, 100); - xrdp_orders_check(self, 44+data_len); + if (xrdp_orders_check(self, 44 + data_len) != 0) + { + return 1; + } self->order_count++; order_flags = RDP_ORDER_STANDARD; @@ -1794,7 +2151,10 @@ xrdp_orders_send_palette(struct xrdp_orders *self, int *palette, int len; int i; - xrdp_orders_check(self, 2000); + if (xrdp_orders_check(self, 2000) != 0) + { + return 1; + } self->order_count++; order_flags = RDP_ORDER_STANDARD | RDP_ORDER_SECONDARY; out_uint8(self->out_s, order_flags); @@ -1854,7 +2214,10 @@ xrdp_orders_send_raw_bitmap(struct xrdp_orders *self, Bpp = (bpp + 7) / 8; bufsize = (width + e) * height * Bpp; - xrdp_orders_check(self, bufsize + 16); + if (xrdp_orders_check(self, bufsize + 16) != 0) + { + return 1; + } self->order_count++; order_flags = RDP_ORDER_STANDARD | RDP_ORDER_SECONDARY; out_uint8(self->out_s, order_flags); @@ -1961,7 +2324,10 @@ height(%d)", lines_sending, height); bufsize = (int)(s->p - p); Bpp = (bpp + 7) / 8; - xrdp_orders_check(self, bufsize + 16); + if (xrdp_orders_check(self, bufsize + 16) != 0) + { + return 1; + } self->order_count++; order_flags = RDP_ORDER_STANDARD | RDP_ORDER_SECONDARY; out_uint8(self->out_s, order_flags); @@ -2015,15 +2381,28 @@ xrdp_orders_send_font(struct xrdp_orders *self, int order_flags = 0; int datasize = 0; int len = 0; + int flags; - datasize = FONT_DATASIZE(font_char); - xrdp_orders_check(self, datasize + 18); + if (font_char->bpp == 8) /* alpha font */ + { + datasize = ((font_char->width + 3) & ~3) * font_char->height; + flags = 8 | 0x4000; + } + else + { + datasize = FONT_DATASIZE(font_char); + flags = 8; + } + if (xrdp_orders_check(self, datasize + 18) != 0) + { + return 1; + } self->order_count++; order_flags = RDP_ORDER_STANDARD | RDP_ORDER_SECONDARY; out_uint8(self->out_s, order_flags); len = (datasize + 12) - 7; /* length after type minus 7 */ out_uint16_le(self->out_s, len); - out_uint16_le(self->out_s, 8); /* flags */ + out_uint16_le(self->out_s, flags); out_uint8(self->out_s, RDP_ORDER_FONTCACHE); /* type */ out_uint8(self->out_s, font_index); out_uint8(self->out_s, 1); /* num of chars */ @@ -2074,7 +2453,10 @@ xrdp_orders_send_raw_bitmap2(struct xrdp_orders *self, Bpp = (bpp + 7) / 8; bufsize = (width + e) * height * Bpp; - xrdp_orders_check(self, bufsize + 14); + if (xrdp_orders_check(self, bufsize + 14) != 0) + { + return 1; + } self->order_count++; order_flags = RDP_ORDER_STANDARD | RDP_ORDER_SECONDARY; out_uint8(self->out_s, order_flags); @@ -2091,6 +2473,25 @@ xrdp_orders_send_raw_bitmap2(struct xrdp_orders *self, i = cache_idx & 0xff; out_uint8(self->out_s, i); + if (1 && Bpp == 3) + { + for (i = height - 1; i >= 0; i--) + { + for (j = 0; j < width; j++) + { + pixel = GETPIXEL32(data, j, i, width); + out_uint8(self->out_s, pixel); + out_uint8(self->out_s, pixel >> 8); + out_uint8(self->out_s, pixel >> 16); + } + for (j = 0; j < e; j++) + { + out_uint8s(self->out_s, Bpp); + } + } + } + else + { for (i = height - 1; i >= 0; i--) { for (j = 0; j < width; j++) @@ -2120,6 +2521,7 @@ xrdp_orders_send_raw_bitmap2(struct xrdp_orders *self, out_uint8s(self->out_s, Bpp); } } + } return 0; } @@ -2182,7 +2584,10 @@ height(%d)", lines_sending, height); bufsize = (int)(s->p - p); Bpp = (bpp + 7) / 8; - xrdp_orders_check(self, bufsize + 14); + if (xrdp_orders_check(self, bufsize + 14) != 0) + { + return 1; + } self->order_count++; order_flags = RDP_ORDER_STANDARD | RDP_ORDER_SECONDARY; out_uint8(self->out_s, order_flags); @@ -2228,7 +2633,7 @@ xrdp_orders_send_as_jpeg(struct xrdp_orders *self, return 1; } -#if defined(XRDP_FREERDP1) +#if defined(XRDP_NEUTRINORDP) /*****************************************************************************/ /* secondary drawing order (bitmap v3) using remotefx compression */ static int APP_CC @@ -2246,7 +2651,9 @@ xrdp_orders_send_as_rfx(struct xrdp_orders *self, return 0; } - if (width * height < 64) + LLOGLN(10, ("width %d height %d rfx_min_pixel %d", width, height, + self->rfx_min_pixel)); + if (width * height < self->rfx_min_pixel) { return 0; } @@ -2267,7 +2674,10 @@ xrdp_orders_out_v3(struct xrdp_orders *self, int cache_id, int cache_idx, int i; Bpp = (bpp + 7) / 8; - xrdp_orders_check(self, bufsize + 30); + if (xrdp_orders_check(self, bufsize + 30) != 0) + { + return 1; + } self->order_count++; order_flags = RDP_ORDER_STANDARD | RDP_ORDER_SECONDARY; out_uint8(self->out_s, order_flags); @@ -2306,7 +2716,7 @@ xrdp_orders_send_bitmap3(struct xrdp_orders *self, struct stream *xr_s; /* xrdp stream */ struct stream *temp_s; /* xrdp stream */ struct xrdp_client_info *ci; -#if defined(XRDP_FREERDP1) +#if defined(XRDP_NEUTRINORDP) STREAM *fr_s; /* FreeRDP stream */ RFX_CONTEXT *context; RFX_RECT rect; @@ -2321,7 +2731,7 @@ xrdp_orders_send_bitmap3(struct xrdp_orders *self, if (ci->v3_codec_id == ci->rfx_codec_id) { -#if defined(XRDP_FREERDP1) +#if defined(XRDP_NEUTRINORDP) if (!xrdp_orders_send_as_rfx(self, width, height, bpp, hints)) { @@ -2374,7 +2784,7 @@ xrdp_orders_send_bitmap3(struct xrdp_orders *self, make_stream(temp_s); init_stream(temp_s, 16384); quality = ci->jpeg_prop[0]; - xrdp_jpeg_compress(data, width, height, xr_s, bpp, 16384, + xrdp_jpeg_compress(self->jpeg_han, data, width, height, xr_s, bpp, 16384, height - 1, temp_s, e, quality); s_mark_end(xr_s); bufsize = (int)(xr_s->end - xr_s->data); @@ -2406,7 +2816,10 @@ xrdp_orders_send_brush(struct xrdp_orders *self, int width, int height, int order_flags = 0; int len = 0; - xrdp_orders_check(self, size + 12); + if (xrdp_orders_check(self, size + 12) != 0) + { + return 1; + } self->order_count++; order_flags = RDP_ORDER_STANDARD | RDP_ORDER_SECONDARY; out_uint8(self->out_s, order_flags); @@ -2448,7 +2861,10 @@ xrdp_orders_send_create_os_surface(struct xrdp_orders *self, int id, bytes += num_del_list * 2; } - xrdp_orders_check(self, bytes); + if (xrdp_orders_check(self, bytes) != 0) + { + return 1; + } self->order_count++; order_flags = RDP_ORDER_SECONDARY; order_flags |= 1 << 2; /* type RDP_ORDER_ALTSEC_CREATE_OFFSCR_BITMAP */ @@ -2489,7 +2905,10 @@ xrdp_orders_send_switch_os_surface(struct xrdp_orders *self, int id) int order_flags; int cache_id; - xrdp_orders_check(self, 3); + if (xrdp_orders_check(self, 3) != 0) + { + return 1; + } self->order_count++; order_flags = RDP_ORDER_SECONDARY; order_flags |= 0 << 2; /* type RDP_ORDER_ALTSEC_SWITCH_SURFACE */ diff --git a/libxrdp/xrdp_orders_rail.c b/libxrdp/xrdp_orders_rail.c index bd91b543..91d4b607 100644 --- a/libxrdp/xrdp_orders_rail.c +++ b/libxrdp/xrdp_orders_rail.c @@ -34,7 +34,10 @@ xrdp_orders_send_window_delete(struct xrdp_orders *self, int window_id) int field_present_flags; order_size = 11; - xrdp_orders_check(self, order_size); + if (xrdp_orders_check(self, order_size) != 0) + { + return 1; + } self->order_count++; order_flags = RDP_ORDER_SECONDARY; order_flags |= 0xb << 2; /* type TS_ALTSEC_WINDOW */ @@ -64,7 +67,10 @@ xrdp_orders_send_window_cached_icon(struct xrdp_orders *self, int field_present_flags; order_size = 14; - xrdp_orders_check(self, order_size); + if (xrdp_orders_check(self, order_size) != 0) + { + return 1; + } self->order_count++; order_flags = RDP_ORDER_SECONDARY; order_flags |= 0xb << 2; /* type TS_ALTSEC_WINDOW */ @@ -155,7 +161,10 @@ xrdp_orders_send_window_icon(struct xrdp_orders *self, order_size += icon_info->cmap_bytes + 2; } - xrdp_orders_check(self, order_size); + if (xrdp_orders_check(self, order_size) != 0) + { + return 1; + } self->order_count++; order_flags = RDP_ORDER_SECONDARY; order_flags |= 0xb << 2; /* type TS_ALTSEC_WINDOW */ @@ -324,7 +333,10 @@ xrdp_orders_send_window_new_update(struct xrdp_orders *self, int window_id, order_size += 8 * window_state->num_visibility_rects; } - xrdp_orders_check(self, order_size); + if (xrdp_orders_check(self, order_size) != 0) + { + return 1; + } self->order_count++; order_flags = RDP_ORDER_SECONDARY; order_flags |= 0xb << 2; /* type TS_ALTSEC_WINDOW */ @@ -465,7 +477,10 @@ xrdp_orders_send_notify_delete(struct xrdp_orders *self, int window_id, int field_present_flags; order_size = 15; - xrdp_orders_check(self, order_size); + if (xrdp_orders_check(self, order_size) != 0) + { + return 1; + } self->order_count++; order_flags = RDP_ORDER_SECONDARY; order_flags |= 0xb << 2; /* type TS_ALTSEC_WINDOW */ @@ -560,7 +575,10 @@ xrdp_orders_send_notify_new_update(struct xrdp_orders *self, order_size += 3; } - xrdp_orders_check(self, order_size); + if (xrdp_orders_check(self, order_size) != 0) + { + return 1; + } self->order_count++; order_flags = RDP_ORDER_SECONDARY; order_flags |= 0xb << 2; /* type TS_ALTSEC_WINDOW */ @@ -651,7 +669,10 @@ xrdp_orders_send_monitored_desktop(struct xrdp_orders *self, order_size += mdo->num_window_ids * 4; } - xrdp_orders_check(self, order_size); + if (xrdp_orders_check(self, order_size) != 0) + { + return 1; + } self->order_count++; order_flags = RDP_ORDER_SECONDARY; order_flags |= 0xb << 2; /* type TS_ALTSEC_WINDOW */ diff --git a/libxrdp/xrdp_rdp.c b/libxrdp/xrdp_rdp.c index 93219968..9147287e 100644 --- a/libxrdp/xrdp_rdp.c +++ b/libxrdp/xrdp_rdp.c @@ -21,7 +21,7 @@ #include "libxrdp.h" #include "log.h" -#if defined(XRDP_FREERDP1) +#if defined(XRDP_NEUTRINORDP) #include <freerdp/codec/rfx.h> #endif @@ -88,15 +88,15 @@ xrdp_rdp_read_config(struct xrdp_client_info *client_info) if (g_strcasecmp(item, "bitmap_cache") == 0) { - client_info->use_bitmap_cache = text2bool(value); + client_info->use_bitmap_cache = g_text2bool(value); } else if (g_strcasecmp(item, "bitmap_compression") == 0) { - client_info->use_bitmap_comp = text2bool(value); + client_info->use_bitmap_comp = g_text2bool(value); } else if (g_strcasecmp(item, "bulk_compression") == 0) { - client_info->use_bulk_comp = text2bool(value); + client_info->use_bulk_comp = g_text2bool(value); } else if (g_strcasecmp(item, "crypt_level") == 0) { @@ -121,23 +121,35 @@ xrdp_rdp_read_config(struct xrdp_client_info *client_info) } else if (g_strcasecmp(item, "allow_channels") == 0) { - client_info->channel_code = text2bool(value); + client_info->channel_code = g_text2bool(value); if (client_info->channel_code == 0) { log_message(LOG_LEVEL_DEBUG,"Info - All channels are disabled"); } } + else if (g_strcasecmp(item, "allow_multimon") == 0) + { + client_info->multimon = g_text2bool(value); + if (client_info->multimon == 0) + { + log_message(LOG_LEVEL_DEBUG,"Info - Multi monitor server support disabled"); + } + } else if (g_strcasecmp(item, "max_bpp") == 0) { client_info->max_bpp = g_atoi(value); } + else if (g_strcasecmp(item, "rfx_min_pixel") == 0) + { + client_info->rfx_min_pixel = g_atoi(value); + } else if (g_strcasecmp(item, "new_cursors") == 0) { - client_info->pointer_flags = text2bool(value) == 0 ? 2 : 0; + client_info->pointer_flags = g_text2bool(value) == 0 ? 2 : 0; } else if (g_strcasecmp(item, "require_credentials") == 0) { - client_info->require_credentials = text2bool(value); + client_info->require_credentials = g_text2bool(value); } } @@ -146,7 +158,7 @@ xrdp_rdp_read_config(struct xrdp_client_info *client_info) return 0; } -#if defined(XRDP_FREERDP1) +#if defined(XRDP_NEUTRINORDP) /*****************************************************************************/ static void cpuid(tui32 info, tui32 *eax, tui32 *ebx, tui32 *ecx, tui32 *edx) @@ -215,7 +227,7 @@ xrdp_rdp_create(struct xrdp_session *session, struct trans *trans) xrdp_rdp_read_config(&self->client_info); /* create sec layer */ self->sec_layer = xrdp_sec_create(self, trans, self->client_info.crypt_level, - self->client_info.channel_code); + self->client_info.channel_code, self->client_info.multimon); /* default 8 bit v1 color bitmap cache entries and size */ self->client_info.cache1_entries = 600; self->client_info.cache1_size = 256; @@ -227,7 +239,7 @@ xrdp_rdp_create(struct xrdp_session *session, struct trans *trans) bytes = sizeof(self->client_info.client_ip) - 1; g_write_ip_address(trans->sck, self->client_info.client_ip, bytes); self->mppc_enc = mppc_enc_new(PROTO_RDP_50); -#if defined(XRDP_FREERDP1) +#if defined(XRDP_NEUTRINORDP) self->rfx_enc = rfx_context_new(); rfx_context_set_cpu_opt(self->rfx_enc, xrdp_rdp_detect_cpu()); #endif @@ -247,7 +259,7 @@ xrdp_rdp_delete(struct xrdp_rdp *self) xrdp_sec_delete(self->sec_layer); mppc_enc_free(self->mppc_enc); -#if defined(XRDP_FREERDP1) +#if defined(XRDP_NEUTRINORDP) rfx_context_free((RFX_CONTEXT *)(self->rfx_enc)); #endif g_free(self); @@ -421,29 +433,26 @@ xrdp_rdp_send_data(struct xrdp_rdp *self, struct stream *s, "tocomplen %d", mppc_enc->flags, mppc_enc->bytes_in_opb, mppc_enc->historyOffset, tocomplen)); - if (mppc_enc->flags & RDP_MPPC_COMPRESSED) - { - clen = mppc_enc->bytes_in_opb + 18; - pdulen = clen; - ctype = mppc_enc->flags; - iso_offset = (int)(s->iso_hdr - s->data); - mcs_offset = (int)(s->mcs_hdr - s->data); - sec_offset = (int)(s->sec_hdr - s->data); - rdp_offset = (int)(s->rdp_hdr - s->data); - - /* outputBuffer has 64 bytes preceding it */ - ls.data = mppc_enc->outputBuffer - (rdp_offset + 18); - ls.p = ls.data + rdp_offset; - ls.end = ls.p + clen; - ls.size = clen; - ls.iso_hdr = ls.data + iso_offset; - ls.mcs_hdr = ls.data + mcs_offset; - ls.sec_hdr = ls.data + sec_offset; - ls.rdp_hdr = ls.data + rdp_offset; - ls.channel_hdr = 0; - ls.next_packet = 0; - s = &ls; - } + clen = mppc_enc->bytes_in_opb + 18; + pdulen = clen; + ctype = mppc_enc->flags; + iso_offset = (int)(s->iso_hdr - s->data); + mcs_offset = (int)(s->mcs_hdr - s->data); + sec_offset = (int)(s->sec_hdr - s->data); + rdp_offset = (int)(s->rdp_hdr - s->data); + + /* outputBuffer has 64 bytes preceding it */ + ls.data = mppc_enc->outputBuffer - (rdp_offset + 18); + ls.p = ls.data + rdp_offset; + ls.end = ls.p + clen; + ls.size = clen; + ls.iso_hdr = ls.data + iso_offset; + ls.mcs_hdr = ls.data + mcs_offset; + ls.sec_hdr = ls.data + sec_offset; + ls.rdp_hdr = ls.data + rdp_offset; + ls.channel_hdr = 0; + ls.next_packet = 0; + s = &ls; } else { @@ -514,6 +523,11 @@ xrdp_rdp_parse_client_mcs_data(struct xrdp_rdp *self) p = &(self->sec_layer->client_mcs_data); p->p = p->data; + if (!s_check_rem(p, 31 + 2 + 2 + 120 + 2)) + { + g_writeln("xrdp_rdp_parse_client_mcs_data: error"); + return 1; + } in_uint8s(p, 31); in_uint16_le(p, self->client_info.width); in_uint16_le(p, self->client_info.height); @@ -524,6 +538,10 @@ xrdp_rdp_parse_client_mcs_data(struct xrdp_rdp *self) switch (i) { case 0xca01: + if (!s_check_rem(p, 6 + 1)) + { + return 1; + } in_uint8s(p, 6); in_uint8(p, i); @@ -574,6 +592,14 @@ xrdp_rdp_incoming(struct xrdp_rdp *self) MCS_USERCHANNEL_BASE; xrdp_rdp_parse_client_mcs_data(self); DEBUG(("out xrdp_rdp_incoming mcs channel %d", self->mcs_channel)); + + g_strncpy(self->client_info.client_addr, + self->sec_layer->mcs_layer->iso_layer->tcp_layer->trans->addr, + sizeof(self->client_info.client_addr) - 1); + g_strncpy(self->client_info.client_port, + self->sec_layer->mcs_layer->iso_layer->tcp_layer->trans->port, + sizeof(self->client_info.client_port) - 1); + return 0; } @@ -586,6 +612,7 @@ xrdp_rdp_send_demand_active(struct xrdp_rdp *self) int caps_size; int codec_caps_count; int codec_caps_size; + int flags; char *caps_count_ptr; char *caps_size_ptr; char *caps_ptr; @@ -679,38 +706,38 @@ xrdp_rdp_send_demand_active(struct xrdp_rdp *self) out_uint16_le(s, 0x2f); /* Number of fonts */ out_uint16_le(s, 0x22); /* Capability flags */ /* caps */ - out_uint8(s, 1); /* dest blt */ - out_uint8(s, 1); /* pat blt */ - out_uint8(s, 1); /* screen blt */ - out_uint8(s, 1); /* mem blt */ - out_uint8(s, 0); /* tri blt */ - out_uint8(s, 0); /* unused */ - out_uint8(s, 0); /* unused */ - out_uint8(s, 0); /* nine grid */ - out_uint8(s, 1); /* line to */ - out_uint8(s, 0); /* multi nine grid */ - out_uint8(s, 1); /* rect */ - out_uint8(s, 0); /* desk save */ - out_uint8(s, 0); /* unused */ - out_uint8(s, 0); /* unused */ - out_uint8(s, 0); /* unused */ - out_uint8(s, 0); /* multi dest blt */ - out_uint8(s, 0); /* multi pat blt */ - out_uint8(s, 0); /* multi screen blt */ - out_uint8(s, 1); /* multi rect */ - out_uint8(s, 0); /* fast index */ - out_uint8(s, 0); /* polygonSC ([MS-RDPEGDI], 2.2.2.2.1.1.2.16) */ - out_uint8(s, 0); /* polygonCB ([MS-RDPEGDI], 2.2.2.2.1.1.2.17) */ - out_uint8(s, 0); /* polyline */ - out_uint8(s, 0); /* unused */ - out_uint8(s, 0); /* fast glyph */ - out_uint8(s, 0); /* ellipse */ - out_uint8(s, 0); /* ellipse */ - out_uint8(s, 0); /* ? */ - out_uint8(s, 0); /* unused */ - out_uint8(s, 0); /* unused */ - out_uint8(s, 0); /* unused */ - out_uint8(s, 0); /* unused */ + out_uint8(s, 1); /* NEG_DSTBLT_INDEX 0x00 0 */ + out_uint8(s, 1); /* NEG_PATBLT_INDEX 0x01 1 */ + out_uint8(s, 1); /* NEG_SCRBLT_INDEX 0x02 2 */ + out_uint8(s, 1); /* NEG_MEMBLT_INDEX 0x03 3 */ + out_uint8(s, 0); /* NEG_MEM3BLT_INDEX 0x04 4 */ + out_uint8(s, 0); /* NEG_ATEXTOUT_INDEX 0x05 5 */ + out_uint8(s, 0); /* NEG_AEXTTEXTOUT_INDEX 0x06 6 */ + out_uint8(s, 0); /* NEG_DRAWNINEGRID_INDEX 0x07 7 */ + out_uint8(s, 1); /* NEG_LINETO_INDEX 0x08 8 */ + out_uint8(s, 0); /* NEG_MULTI_DRAWNINEGRID_INDEX 0x09 9 */ + out_uint8(s, 1); /* NEG_OPAQUE_RECT_INDEX 0x0A 10 */ + out_uint8(s, 0); /* NEG_SAVEBITMAP_INDEX 0x0B 11 */ + out_uint8(s, 0); /* NEG_WTEXTOUT_INDEX 0x0C 12 */ + out_uint8(s, 0); /* NEG_MEMBLT_V2_INDEX 0x0D 13 */ + out_uint8(s, 0); /* NEG_MEM3BLT_V2_INDEX 0x0E 14 */ + out_uint8(s, 0); /* NEG_MULTIDSTBLT_INDEX 0x0F 15 */ + out_uint8(s, 0); /* NEG_MULTIPATBLT_INDEX 0x10 16 */ + out_uint8(s, 0); /* NEG_MULTISCRBLT_INDEX 0x11 17 */ + out_uint8(s, 1); /* NEG_MULTIOPAQUERECT_INDEX 0x12 18 */ + out_uint8(s, 0); /* NEG_FAST_INDEX_INDEX 0x13 19 */ + out_uint8(s, 0); /* NEG_POLYGON_SC_INDEX 0x14 20 */ + out_uint8(s, 0); /* NEG_POLYGON_CB_INDEX 0x15 21 */ + out_uint8(s, 0); /* NEG_POLYLINE_INDEX 0x16 22 */ + out_uint8(s, 0); /* unused 0x17 23 */ + out_uint8(s, 0); /* NEG_FAST_GLYPH_INDEX 0x18 24 */ + out_uint8(s, 0); /* NEG_ELLIPSE_SC_INDEX 0x19 25 */ + out_uint8(s, 0); /* NEG_ELLIPSE_CB_INDEX 0x1A 26 */ + out_uint8(s, 1); /* NEG_GLYPH_INDEX_INDEX 0x1B 27 */ + out_uint8(s, 0); /* NEG_GLYPH_WEXTTEXTOUT_INDEX 0x1C 28 */ + out_uint8(s, 0); /* NEG_GLYPH_WLONGTEXTOUT_INDEX 0x1D 29 */ + out_uint8(s, 0); /* NEG_GLYPH_WLONGEXTTEXTOUT_INDEX 0x1E 30 */ + out_uint8(s, 0); /* unused 0x1F 31 */ out_uint16_le(s, 0x6a1); /* declare support of bitmap cache rev3 */ out_uint16_le(s, XR_ORDERFLAGS_EX_CACHE_BITMAP_REV3_SUPPORT); @@ -773,18 +800,16 @@ xrdp_rdp_send_demand_active(struct xrdp_rdp *self) caps_count++; out_uint16_le(s, RDP_CAPSET_INPUT); /* 13(0xd) */ out_uint16_le(s, RDP_CAPLEN_INPUT); /* 88(0x58) */ + + /* INPUT_FLAG_SCANCODES 0x0001 + INPUT_FLAG_MOUSEX 0x0004 + INPUT_FLAG_FASTPATH_INPUT 0x0008 + INPUT_FLAG_FASTPATH_INPUT2 0x0020 */ + flags = 0x0001 | 0x0004; if (self->client_info.use_fast_path & 2) - { - /* INPUT_FLAG_SCANCODES 0x0001 - INPUT_FLAG_FASTPATH_INPUT 0x0008 - INPUT_FLAG_FASTPATH_INPUT2 0x0020 */ - out_uint8(s, 1 | 8 | 0x20); - } - else - { - out_uint8(s, 1); - } - out_uint8s(s, 83); + flags |= 0x0008 | 0x0020; + out_uint16_le(s, flags); + out_uint8s(s, 82); /* Remote Programs Capability Set */ caps_count++; @@ -837,6 +862,11 @@ xrdp_process_capset_general(struct xrdp_rdp *self, struct stream *s, { int i; + if (len < 10 + 2) + { + g_writeln("xrdp_process_capset_general: error"); + return 1; + } in_uint8s(s, 10); in_uint16_le(s, i); /* use_compact_packets is pretty much 'use rdp5' */ @@ -858,6 +888,11 @@ xrdp_process_capset_order(struct xrdp_rdp *self, struct stream *s, int cap_flags; DEBUG(("order capabilities")); + if (len < 20 + 2 + 2 + 2 + 2 + 2 + 2 + 32 + 2 + 2 + 4 + 4 + 4 + 4) + { + g_writeln("xrdp_process_capset_order: error"); + return 1; + } in_uint8s(s, 20); /* Terminal desc, pad */ in_uint8s(s, 2); /* Cache X granularity */ in_uint8s(s, 2); /* Cache Y granularity */ @@ -915,13 +950,32 @@ static int APP_CC xrdp_process_capset_bmpcache(struct xrdp_rdp *self, struct stream *s, int len) { + int i; + + if (len < 24 + 2 + 2 + 2 + 2 + 2 + 2) + { + g_writeln("xrdp_process_capset_bmpcache: error"); + return 1; + } self->client_info.bitmap_cache_version |= 1; in_uint8s(s, 24); - in_uint16_le(s, self->client_info.cache1_entries); + /* cache 1 */ + in_uint16_le(s, i); + i = MIN(i, XRDP_MAX_BITMAP_CACHE_IDX); + i = MAX(i, 0); + self->client_info.cache1_entries = i; in_uint16_le(s, self->client_info.cache1_size); - in_uint16_le(s, self->client_info.cache2_entries); + /* cache 2 */ + in_uint16_le(s, i); + i = MIN(i, XRDP_MAX_BITMAP_CACHE_IDX); + i = MAX(i, 0); + self->client_info.cache2_entries = i; in_uint16_le(s, self->client_info.cache2_size); - in_uint16_le(s, self->client_info.cache3_entries); + /* caceh 3 */ + in_uint16_le(s, i); + i = MIN(i, XRDP_MAX_BITMAP_CACHE_IDX); + i = MAX(i, 0); + self->client_info.cache3_entries = i; in_uint16_le(s, self->client_info.cache3_size); DEBUG(("cache1 entries %d size %d", self->client_info.cache1_entries, self->client_info.cache1_size)); @@ -941,22 +995,30 @@ xrdp_process_capset_bmpcache2(struct xrdp_rdp *self, struct stream *s, int Bpp = 0; int i = 0; + if (len < 2 + 2 + 4 + 4 + 4) + { + g_writeln("xrdp_process_capset_bmpcache2: error"); + return 1; + } self->client_info.bitmap_cache_version |= 2; Bpp = (self->client_info.bpp + 7) / 8; in_uint16_le(s, i); /* cache flags */ self->client_info.bitmap_cache_persist_enable = i; in_uint8s(s, 2); /* number of caches in set, 3 */ in_uint32_le(s, i); - i = MIN(i, 2000); + i = MIN(i, XRDP_MAX_BITMAP_CACHE_IDX); + i = MAX(i, 0); self->client_info.cache1_entries = i; self->client_info.cache1_size = 256 * Bpp; in_uint32_le(s, i); - i = MIN(i, 2000); + i = MIN(i, XRDP_MAX_BITMAP_CACHE_IDX); + i = MAX(i, 0); self->client_info.cache2_entries = i; self->client_info.cache2_size = 1024 * Bpp; in_uint32_le(s, i); i = i & 0x7fffffff; - i = MIN(i, 2000); + i = MIN(i, XRDP_MAX_BITMAP_CACHE_IDX); + i = MAX(i, 0); self->client_info.cache3_entries = i; self->client_info.cache3_size = 4096 * Bpp; DEBUG(("cache1 entries %d size %d", self->client_info.cache1_entries, @@ -975,6 +1037,11 @@ xrdp_process_capset_cache_v3_codec_id(struct xrdp_rdp *self, struct stream *s, { int codec_id; + if (len < 1) + { + g_writeln("xrdp_process_capset_cache_v3_codec_id: error"); + return 1; + } in_uint8(s, codec_id); g_writeln("xrdp_process_capset_cache_v3_codec_id: cache_v3_codec_id %d", codec_id); @@ -992,6 +1059,11 @@ xrdp_process_capset_pointercache(struct xrdp_rdp *self, struct stream *s, int colorPointerFlag; int no_new_cursor; + if (len < 2 + 2 + 2) + { + g_writeln("xrdp_process_capset_pointercache: error"); + return 1; + } no_new_cursor = self->client_info.pointer_flags & 2; in_uint16_le(s, colorPointerFlag); self->client_info.pointer_flags = colorPointerFlag; @@ -1028,6 +1100,11 @@ xrdp_process_capset_brushcache(struct xrdp_rdp *self, struct stream *s, { int code; + if (len < 4) + { + g_writeln("xrdp_process_capset_brushcache: error"); + return 1; + } in_uint32_le(s, code); self->client_info.brush_cache_code = code; return 0; @@ -1040,12 +1117,11 @@ xrdp_process_offscreen_bmpcache(struct xrdp_rdp *self, struct stream *s, { int i32; - if (len - 4 < 8) + if (len < 4 + 2 + 2) { - g_writeln("xrdp_process_offscreen_bmpcache: bad len"); + g_writeln("xrdp_process_offscreen_bmpcache: error"); return 1; } - in_uint32_le(s, i32); self->client_info.offscreen_support_level = i32; in_uint16_le(s, i32); @@ -1066,12 +1142,11 @@ xrdp_process_capset_rail(struct xrdp_rdp *self, struct stream *s, int len) { int i32; - if (len - 4 < 4) + if (len < 4) { - g_writeln("xrdp_process_capset_rail: bad len"); + g_writeln("xrdp_process_capset_rail: error"); return 1; } - in_uint32_le(s, i32); self->client_info.rail_support_level = i32; g_writeln("xrdp_process_capset_rail: rail_support_level %d", @@ -1085,12 +1160,11 @@ xrdp_process_capset_window(struct xrdp_rdp *self, struct stream *s, int len) { int i32; - if (len - 4 < 7) + if (len < 4 + 1 + 2) { - g_writeln("xrdp_process_capset_window: bad len"); + g_writeln("xrdp_process_capset_window: error"); return 1; } - in_uint32_le(s, i32); self->client_info.wnd_support_level = i32; in_uint8(s, i32); @@ -1117,14 +1191,32 @@ xrdp_process_capset_codecs(struct xrdp_rdp *self, struct stream *s, int len) char *codec_guid; char *next_guid; + if (len < 1) + { + g_writeln("xrdp_process_capset_codecs: error"); + return 1; + } in_uint8(s, codec_count); + len--; for (index = 0; index < codec_count; index++) { codec_guid = s->p; + if (len < 16 + 1 + 2) + { + g_writeln("xrdp_process_capset_codecs: error"); + return 1; + } in_uint8s(s, 16); in_uint8(s, codec_id); in_uint16_le(s, codec_properties_length); + len -= 16 + 1 + 2; + if (len < codec_properties_length) + { + g_writeln("xrdp_process_capset_codecs: error"); + return 1; + } + len -= codec_properties_length; next_guid = s->p + codec_properties_length; if (g_memcmp(codec_guid, XR_CODEC_GUID_NSCODEC, 16) == 0) @@ -1190,9 +1282,19 @@ xrdp_rdp_process_confirm_active(struct xrdp_rdp *self, struct stream *s) for (index = 0; index < num_caps; index++) { p = s->p; + if (!s_check_rem(s, 4)) + { + g_writeln("xrdp_rdp_process_confirm_active: error 1"); + return 1; + } in_uint16_le(s, type); in_uint16_le(s, len); - + if ((len < 4) || !s_check_rem(s, len - 4)) + { + g_writeln("xrdp_rdp_process_confirm_active: error len %d", len, s->end - s->p); + return 1; + } + len -= 4; switch (type) { case RDP_CAPSET_GENERAL: /* 1 */ @@ -1278,7 +1380,7 @@ xrdp_rdp_process_confirm_active(struct xrdp_rdp *self, struct stream *s) break; } - s->p = p + len; + s->p = p + len + 4; } DEBUG(("out xrdp_rdp_process_confirm_active")); @@ -1305,26 +1407,35 @@ xrdp_rdp_process_data_input(struct xrdp_rdp *self, struct stream *s) int param2; int time; + if (!s_check_rem(s, 4)) + { + return 1; + } in_uint16_le(s, num_events); in_uint8s(s, 2); /* pad */ DEBUG(("in xrdp_rdp_process_data_input %d events", num_events)); for (index = 0; index < num_events; index++) { + if (!s_check_rem(s, 12)) + { + return 1; + } in_uint32_le(s, time); in_uint16_le(s, msg_type); in_uint16_le(s, device_flags); in_sint16_le(s, param1); in_sint16_le(s, param2); - DEBUG(("xrdp_rdp_process_data_input event %4.4x flags %4.4x param1 %d \ -param2 %d time %d", msg_type, device_flags, param1, param2, time)); + DEBUG(("xrdp_rdp_process_data_input event %4.4x flags %4.4x param1 %d " + "param2 %d time %d", msg_type, device_flags, param1, param2, time)); if (self->session->callback != 0) { /* msg_type can be RDP_INPUT_SYNCHRONIZE - 0 RDP_INPUT_SCANCODE - 4 - RDP_INPUT_MOUSE - 0x8001 */ + RDP_INPUT_MOUSE - 0x8001 + RDP_INPUT_MOUSEX - 0x8002 */ /* call to xrdp_wm.c : callback */ self->session->callback(self->session->id, msg_type, param1, param2, device_flags, time); diff --git a/libxrdp/xrdp_sec.c b/libxrdp/xrdp_sec.c index 726fcde4..f52a080d 100644 --- a/libxrdp/xrdp_sec.c +++ b/libxrdp/xrdp_sec.c @@ -138,7 +138,7 @@ hex_str_to_bin(char *in, char *out, int out_len) /*****************************************************************************/ struct xrdp_sec *APP_CC xrdp_sec_create(struct xrdp_rdp *owner, struct trans *trans, int crypt_level, - int channel_code) + int channel_code, int multimon) { struct xrdp_sec *self; @@ -168,6 +168,7 @@ xrdp_sec_create(struct xrdp_rdp *owner, struct trans *trans, int crypt_level, } self->channel_code = channel_code; + self->multimon = multimon; if (self->decrypt_rc4_info != NULL) { @@ -331,12 +332,20 @@ unicode_in(struct stream *s, int uni_len, char *dst, int dst_len) break; } + if (!s_check_rem(s, 2)) + { + return 1; + } in_uint8(s, dst[dst_index]); in_uint8s(s, 1); dst_index++; src_index += 2; } + if (!s_check_rem(s, 2)) + { + return 1; + } in_uint8s(s, 2); return 0; } @@ -359,6 +368,10 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s) /* initialize (zero out) local variables */ g_memset(tmpdata, 0, sizeof(char) * 256); + if (!s_check_rem(s, 8)) + { + return 1; + } in_uint8s(s, 4); in_uint32_le(s, flags); DEBUG(("in xrdp_sec_process_logon_info flags $%x", flags)); @@ -398,6 +411,10 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s) } } + if (!s_check_rem(s, 2)) + { + return 1; + } in_uint16_le(s, len_domain); if (len_domain > 511) @@ -406,6 +423,10 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s) return 1; } + if (!s_check_rem(s, 2)) + { + return 1; + } in_uint16_le(s, len_user); if (len_user > 511) @@ -414,6 +435,10 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s) return 1; } + if (!s_check_rem(s, 2)) + { + return 1; + } in_uint16_le(s, len_password); if (len_password > 511) @@ -422,6 +447,10 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s) return 1; } + if (!s_check_rem(s, 2)) + { + return 1; + } in_uint16_le(s, len_program); if (len_program > 511) @@ -430,6 +459,10 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s) return 1; } + if (!s_check_rem(s, 2)) + { + return 1; + } in_uint16_le(s, len_directory); if (len_directory > 511) @@ -438,36 +471,76 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s) return 1; } - unicode_in(s, len_domain, self->rdp_layer->client_info.domain, 255); + if (unicode_in(s, len_domain, self->rdp_layer->client_info.domain, 255) != 0) + { + return 1; + } DEBUG(("domain %s", self->rdp_layer->client_info.domain)); - unicode_in(s, len_user, self->rdp_layer->client_info.username, 255); + if (unicode_in(s, len_user, self->rdp_layer->client_info.username, 255) != 0) + { + return 1; + } DEBUG(("username %s", self->rdp_layer->client_info.username)); if (flags & RDP_LOGON_AUTO) { - unicode_in(s, len_password, self->rdp_layer->client_info.password, 255); + if (unicode_in(s, len_password, self->rdp_layer->client_info.password, 255) != 0) + { + return 1; + } DEBUG(("flag RDP_LOGON_AUTO found")); } else { + if (!s_check_rem(s, len_password + 2)) + { + return 1; + } in_uint8s(s, len_password + 2); if (self->rdp_layer->client_info.require_credentials) + { + g_writeln("xrdp_sec_process_logon_info: credentials on cmd line is mandatory"); return 1; /* credentials on cmd line is mandatory */ + } } - unicode_in(s, len_program, self->rdp_layer->client_info.program, 255); + if (unicode_in(s, len_program, self->rdp_layer->client_info.program, 255) != 0) + { + return 1; + } DEBUG(("program %s", self->rdp_layer->client_info.program)); - unicode_in(s, len_directory, self->rdp_layer->client_info.directory, 255); + if (unicode_in(s, len_directory, self->rdp_layer->client_info.directory, 255) != 0) + { + return 1; + } DEBUG(("directory %s", self->rdp_layer->client_info.directory)); if (flags & RDP_LOGON_BLOB) { + if (!s_check_rem(s, 4)) + { + return 1; + } in_uint8s(s, 2); /* unknown */ in_uint16_le(s, len_ip); - unicode_in(s, len_ip - 2, tmpdata, 255); + if (unicode_in(s, len_ip - 2, tmpdata, 255) != 0) + { + return 1; + } + if (!s_check_rem(s, 2)) + { + return 1; + } in_uint16_le(s, len_dll); - unicode_in(s, len_dll - 2, tmpdata, 255); - in_uint32_le(s, tzone); /* len of timetone */ + if (unicode_in(s, len_dll - 2, tmpdata, 255) != 0) + { + return 1; + } + if (!s_check_rem(s, 4 + 62 + 22 + 62 + 26 + 4)) + { + return 1; + } + in_uint32_le(s, tzone); /* len of timezone */ in_uint8s(s, 62); /* skip */ in_uint8s(s, 22); /* skip misc. */ in_uint8s(s, 62); /* skip */ @@ -676,17 +749,29 @@ xrdp_sec_recv(struct xrdp_sec *self, struct stream *s, int *chan) return 1; } + if (!s_check_rem(s, 4)) + { + return 1; + } in_uint32_le(s, flags); DEBUG((" in xrdp_sec_recv flags $%x", flags)); if (flags & SEC_ENCRYPT) /* 0x08 */ { + if (!s_check_rem(s, 8)) + { + return 1; + } in_uint8s(s, 8); /* signature */ xrdp_sec_decrypt(self, s->p, (int)(s->end - s->p)); } if (flags & SEC_CLIENT_RANDOM) /* 0x01 */ { + if (!s_check_rem(s, 4 + 64)) + { + return 1; + } in_uint32_le(s, len); in_uint8a(s, self->client_crypt_random, 64); xrdp_sec_rsa_op(self->client_random, self->client_crypt_random, @@ -836,23 +921,91 @@ xrdp_sec_process_mcs_data_channels(struct xrdp_sec *self, struct stream *s) return 0; } + if (!s_check_rem(s, 4)) + { + return 1; + } + in_uint32_le(s, num_channels); + if (num_channels > 31) + { + return 1; + } + for (index = 0; index < num_channels; index++) { channel_item = (struct mcs_channel_item *) g_malloc(sizeof(struct mcs_channel_item), 1); + if (!s_check_rem(s, 12)) + { + return 1; + } in_uint8a(s, channel_item->name, 8); in_uint32_le(s, channel_item->flags); channel_item->chanid = MCS_GLOBAL_CHANNEL + (index + 1); - list_add_item(self->mcs_layer->channel_list, (long)channel_item); + list_add_item(self->mcs_layer->channel_list, (tintptr)channel_item); DEBUG(("got channel flags %8.8x name %s", channel_item->flags, channel_item->name)); } return 0; } +/*****************************************************************************/ +/* reads the client monitors data */ +static int APP_CC +xrdp_sec_process_mcs_data_monitors(struct xrdp_sec *self, struct stream *s) +{ + int index; + int monitorCount; + int flags; + struct xrdp_client_info *client_info = (struct xrdp_client_info *)NULL; + + client_info = &(self->rdp_layer->client_info); + DEBUG(("processing monitors data, allow_multimon is %d", self->multimon)); + /* this is an option set in xrdp.ini */ + if (self->multimon != 1) /* are multi-monitors allowed ? */ + { + DEBUG(("[INFO] xrdp_sec_process_mcs_data_monitors: multimon is not " + "allowed, skipping")); + return 0; + } + in_uint32_le(s, flags); /* flags */ + //verify flags - must be 0x0 + if (flags != 0) + { + DEBUG(("[ERROR] xrdp_sec_process_mcs_data_monitors: flags MUST be " + "zero, detected: %d", flags)); + return 1; + } + in_uint32_le(s, monitorCount); + //verify monitorCount - max 16 + if (monitorCount > 16) + { + DEBUG(("[ERROR] xrdp_sec_process_mcs_data_monitors: max allowed " + "monitors is 16, detected: %d", monitorCount)); + return 1; + } + + g_writeln("monitorCount= %d", monitorCount); // for debugging only + + client_info->monitorCount = monitorCount; + + /* Add client_monitor_data to client_info struct, will later pass to X11rdp */ + for (index = 0; index < monitorCount; index++) + { + in_uint32_le(s, client_info->minfo[index].left); + in_uint32_le(s, client_info->minfo[index].top); + in_uint32_le(s, client_info->minfo[index].right); + in_uint32_le(s, client_info->minfo[index].bottom); + in_uint32_le(s, client_info->minfo[index].is_primary); + + g_writeln("got a monitor: left= %d, top= %d, right= %d, bottom= %d, is_primary?= %d", client_info->minfo[index].left, + client_info->minfo[index].top, client_info->minfo[index].right, client_info->minfo[index].bottom, client_info->minfo[index].is_primary); + } + return 0; +} /*****************************************************************************/ /* process client mcs data, we need some things in here to create the server mcs data */ @@ -864,10 +1017,14 @@ xrdp_sec_process_mcs_data(struct xrdp_sec *self) int tag = 0; int size = 0; - s = &self->client_mcs_data; + s = &(self->client_mcs_data); /* set p to beginning */ s->p = s->data; /* skip header */ + if (!s_check_rem(s, 23)) + { + return 1; + } in_uint8s(s, 23); while (s_check_rem(s, 4)) @@ -890,10 +1047,19 @@ xrdp_sec_process_mcs_data(struct xrdp_sec *self) case SEC_TAG_CLI_CRYPT: break; case SEC_TAG_CLI_CHANNELS: - xrdp_sec_process_mcs_data_channels(self, s); + if (xrdp_sec_process_mcs_data_channels(self, s) != 0) + { + return 1; + } break; case SEC_TAG_CLI_4: break; + case SEC_TAG_CLI_MONITOR: + if (xrdp_sec_process_mcs_data_monitors(self, s) != 0) + { + return 1; + } + break; default: g_writeln("error unknown xrdp_sec_process_mcs_data tag %d size %d", tag, size); @@ -940,13 +1106,32 @@ xrdp_sec_out_mcs_data(struct xrdp_sec *self) out_uint8(s, 0x63); /* c */ out_uint8(s, 0x44); /* D */ out_uint8(s, 0x6e); /* n */ - out_uint16_be(s, 0x80fc + (num_channels_even * 2)); + if (self->mcs_layer->iso_layer->selectedProtocol != -1) + { // Check for RDPNEGDATA availability + out_uint16_be(s, 0x80fc + (num_channels_even * 2) + 4); + } + else + { + out_uint16_be(s, 0x80fc + (num_channels_even * 2)); + } out_uint16_le(s, SEC_TAG_SRV_INFO); - out_uint16_le(s, 8); /* len */ + if (self->mcs_layer->iso_layer->selectedProtocol != -1) + { + out_uint16_le(s, 12); /* len */ + } + else + { + out_uint16_le(s, 8); /* len */ + } out_uint8(s, 4); /* 4 = rdp5 1 = rdp4 */ out_uint8(s, 0); out_uint8(s, 8); out_uint8(s, 0); + if (self->mcs_layer->iso_layer->selectedProtocol != -1) + { + /* clientReqeustedProtocol */ + out_uint32_le(s, self->mcs_layer->iso_layer->selectedProtocol); + } out_uint16_le(s, SEC_TAG_SRV_CHANNELS); out_uint16_le(s, 8 + (num_channels_even * 2)); /* len */ out_uint16_le(s, MCS_GLOBAL_CHANNEL); /* 1003, 0x03eb main channel */ @@ -999,7 +1184,7 @@ xrdp_sec_out_mcs_data(struct xrdp_sec *self) /*****************************************************************************/ /* process the mcs client data we received from the mcs layer */ -static void APP_CC +static int APP_CC xrdp_sec_in_mcs_data(struct xrdp_sec *self) { struct stream *s = (struct stream *)NULL; @@ -1011,6 +1196,10 @@ xrdp_sec_in_mcs_data(struct xrdp_sec *self) s = &(self->client_mcs_data); /* get hostname, its unicode */ s->p = s->data; + if (!s_check_rem(s, 47)) + { + return 1; + } in_uint8s(s, 47); g_memset(client_info->hostname, 0, 32); c = 1; @@ -1018,21 +1207,33 @@ xrdp_sec_in_mcs_data(struct xrdp_sec *self) while (index < 16 && c != 0) { + if (!s_check_rem(s, 2)) + { + return 1; + } in_uint8(s, c); in_uint8s(s, 1); client_info->hostname[index] = c; index++; } - /* get build */ s->p = s->data; + if (!s_check_rem(s, 43 + 4)) + { + return 1; + } in_uint8s(s, 43); in_uint32_le(s, client_info->build); /* get keylayout */ s->p = s->data; + if (!s_check_rem(s, 39 + 4)) + { + return 1; + } in_uint8s(s, 39); in_uint32_le(s, client_info->keylayout); s->p = s->data; + return 0; } /*****************************************************************************/ @@ -1059,7 +1260,8 @@ xrdp_sec_incoming(struct xrdp_sec *self) if (file_by_name_read_section(key_file, "keys", items, values) != 0) { /* this is a show stopper */ - log_message(LOG_LEVEL_ALWAYS,"XRDP cannot read file: %s (check permissions)", key_file); + log_message(LOG_LEVEL_ALWAYS, "XRDP cannot read file: %s " + "(check permissions)", key_file); list_delete(items); list_delete(values); return 1; @@ -1105,7 +1307,10 @@ xrdp_sec_incoming(struct xrdp_sec *self) (int)(self->server_mcs_data.end - self->server_mcs_data.data)); #endif DEBUG((" out xrdp_sec_incoming")); - xrdp_sec_in_mcs_data(self); + if (xrdp_sec_in_mcs_data(self) != 0) + { + return 1; + } return 0; } diff --git a/sesman/auth.h b/sesman/auth.h index 39acc0b8..e06b9eb3 100644 --- a/sesman/auth.h +++ b/sesman/auth.h @@ -57,6 +57,16 @@ auth_start_session(long in_val, int in_display); * */ int DEFAULT_CC +auth_stop_session(long in_val); + +/** + * + * @brief FIXME + * @param in_val + * @return 0 on success, 1 on failure + * + */ +int DEFAULT_CC auth_end(long in_val); /** diff --git a/sesman/chansrv/Makefile.am b/sesman/chansrv/Makefile.am index 7cecdb1e..2d73f05c 100644 --- a/sesman/chansrv/Makefile.am +++ b/sesman/chansrv/Makefile.am @@ -8,7 +8,8 @@ EXTRA_DIST = \ drdynvc.h \ rail.h \ sound.h \ - xcommon.h + xcommon.h \ + mlog.h EXTRA_DEFINES = EXTRA_INCLUDES = @@ -51,7 +52,8 @@ xrdp_chansrv_SOURCES = \ xcommon.c \ drdynvc.c \ chansrv_fuse.c \ - irp.c + irp.c \ + fifo.c xrdp_chansrv_LDFLAGS = \ $(EXTRA_FLAGS) @@ -59,5 +61,5 @@ xrdp_chansrv_LDFLAGS = \ xrdp_chansrv_LDADD = \ -L/usr/X11R6/lib \ $(top_builddir)/common/libcommon.la \ - -lX11 -lXfixes \ + -lX11 -lXfixes -lXrandr \ $(EXTRA_LIBS) diff --git a/sesman/chansrv/chansrv.c b/sesman/chansrv/chansrv.c index 388d0273..01c6a43d 100644 --- a/sesman/chansrv/chansrv.c +++ b/sesman/chansrv/chansrv.c @@ -72,10 +72,156 @@ tbus g_exec_mutex; tbus g_exec_sem; int g_exec_pid = 0; +#define ARRAYSIZE(x) (sizeof(x)/sizeof(*(x))) + /* each time we create a DVC we need a unique DVC channel id */ /* this variable gets bumped up once per DVC we create */ tui32 g_dvc_chan_id = 100; +struct timeout_obj +{ + tui32 mstime; + void *data; + void (*callback)(void *data); + struct timeout_obj *next; +}; + +static struct timeout_obj *g_timeout_head = 0; +static struct timeout_obj *g_timeout_tail = 0; + +/*****************************************************************************/ +int APP_CC +add_timeout(int msoffset, void (*callback)(void *data), void *data) +{ + struct timeout_obj *tobj; + tui32 now; + + LOG(10, ("add_timeout:")); + now = g_time3(); + tobj = g_malloc(sizeof(struct timeout_obj), 1); + tobj->mstime = now + msoffset; + tobj->callback = callback; + tobj->data = data; + if (g_timeout_tail == 0) + { + g_timeout_head = tobj; + g_timeout_tail = tobj; + } + else + { + g_timeout_tail->next = tobj; + g_timeout_tail = tobj; + } + return 0; +} + +/*****************************************************************************/ +static int APP_CC +get_timeout(int *timeout) +{ + struct timeout_obj *tobj; + tui32 now; + int ltimeout; + + LOG(10, ("get_timeout:")); + ltimeout = *timeout; + if (ltimeout < 1) + { + ltimeout = 0; + } + tobj = g_timeout_head; + if (tobj != 0) + { + now = g_time3(); + while (tobj != 0) + { + LOG(10, (" now %u tobj->mstime %u", now, tobj->mstime)); + if (now < tobj->mstime) + { + ltimeout = tobj->mstime - now; + } + tobj = tobj->next; + } + } + if (ltimeout > 0) + { + LOG(10, (" ltimeout %d", ltimeout)); + if (*timeout < 1) + { + *timeout = ltimeout; + } + else + { + if (*timeout > ltimeout) + { + *timeout = ltimeout; + } + } + } + return 0; +} + +/*****************************************************************************/ +static int APP_CC +check_timeout(void) +{ + struct timeout_obj *tobj; + struct timeout_obj *last_tobj; + struct timeout_obj *temp_tobj; + int count; + tui32 now; + + LOG(10, ("check_timeout:")); + count = 0; + tobj = g_timeout_head; + if (tobj != 0) + { + last_tobj = 0; + while (tobj != 0) + { + count++; + now = g_time3(); + if (now >= tobj->mstime) + { + tobj->callback(tobj->data); + if (last_tobj == 0) + { + g_timeout_head = tobj->next; + if (g_timeout_head == 0) + { + g_timeout_tail = 0; + } + } + else + { + last_tobj->next = tobj->next; + if (g_timeout_tail == tobj) + { + g_timeout_tail = last_tobj; + } + } + temp_tobj = tobj; + tobj = tobj->next; + g_free(temp_tobj); + } + else + { + last_tobj = tobj; + tobj = tobj->next; + } + } + } + LOG(10, (" count %d", count)); + return 0; +} + +/*****************************************************************************/ +int DEFAULT_CC +g_is_term(void) +{ + return g_is_wait_obj_set(g_term_event); +} + /*****************************************************************************/ /* add data to chan_item, on its way to the client */ /* returns error */ @@ -149,11 +295,11 @@ send_data_from_chan_item(struct chan_item *chan_item) out_uint32_le(s, cod->s->size); out_uint8a(s, cod->s->p, size); s_mark_end(s); - LOGM((LOG_LEVEL_DEBUG, "chansrv::send_channel_data: -- " + LOGM((LOG_LEVEL_DEBUG, "chansrv::send_data_from_chan_item: -- " "size %d chan_flags 0x%8.8x", size, chan_flags)); g_sent = 1; - error = trans_force_write(g_con_trans); + error = trans_write_copy(g_con_trans); if (error != 0) { return 1; @@ -230,6 +376,31 @@ send_channel_data(int chan_id, char *data, int size) /*****************************************************************************/ /* returns error */ +int APP_CC +send_rail_drawing_orders(char* data, int size) +{ + LOGM((LOG_LEVEL_DEBUG, "chansrv::send_rail_drawing_orders: size %d", size)); + + struct stream* s; + int error; + + s = trans_get_out_s(g_con_trans, 8192); + out_uint32_le(s, 0); /* version */ + out_uint32_le(s, 8 + 8 + size); /* size */ + out_uint32_le(s, 10); /* msg id */ + out_uint32_le(s, 8 + size); /* size */ + out_uint8a(s, data, size); + s_mark_end(s); + error = trans_force_write(g_con_trans); + if (error != 0) + { + return 1; + } + return 0; +} + +/*****************************************************************************/ +/* returns error */ static int APP_CC send_init_response_message(void) { @@ -248,7 +419,7 @@ send_init_response_message(void) out_uint32_le(s, 2); /* msg id */ out_uint32_le(s, 8); /* size */ s_mark_end(s); - return trans_force_write(g_con_trans); + return trans_write_copy(g_con_trans); } /*****************************************************************************/ @@ -271,7 +442,7 @@ send_channel_setup_response_message(void) out_uint32_le(s, 4); /* msg id */ out_uint32_le(s, 8); /* size */ s_mark_end(s); - return trans_force_write(g_con_trans); + return trans_write_copy(g_con_trans); } /*****************************************************************************/ @@ -294,7 +465,7 @@ send_channel_data_response_message(void) out_uint32_le(s, 6); /* msg id */ out_uint32_le(s, 8); /* size */ s_mark_end(s); - return trans_force_write(g_con_trans); + return trans_write_copy(g_con_trans); } /*****************************************************************************/ @@ -493,7 +664,7 @@ process_message_channel_data(struct stream *s) if (chan_flags & 2) /* last */ { s_mark_end(ls); - trans_force_write(g_api_con_trans); + trans_write_copy(g_api_con_trans); } } } @@ -844,13 +1015,15 @@ setup_listen(void) if (g_use_unix_socket) { - g_lis_trans = trans_create(2, 8192, 8192); + g_lis_trans = trans_create(TRANS_MODE_UNIX, 8192, 8192); + g_lis_trans->is_term = g_is_term; g_snprintf(port, 255, "/tmp/.xrdp/xrdp_chansrv_socket_%d", 7200 + g_display_num); } else { - g_lis_trans = trans_create(1, 8192, 8192); + g_lis_trans = trans_create(TRANS_MODE_TCP, 8192, 8192); + g_lis_trans->is_term = g_is_term; g_snprintf(port, 255, "%d", 7200 + g_display_num); } @@ -875,6 +1048,7 @@ setup_api_listen(void) int error = 0; g_api_lis_trans = trans_create(TRANS_MODE_UNIX, 8192 * 4, 8192 * 4); + g_api_lis_trans->is_term = g_is_term; g_snprintf(port, 255, "/tmp/.xrdp/xrdpapi_%d", g_display_num); g_api_lis_trans->trans_conn_in = my_api_trans_conn_in; error = trans_listen(g_api_lis_trans, port); @@ -894,7 +1068,9 @@ THREAD_RV THREAD_CC channel_thread_loop(void *in_val) { tbus objs[32]; + tbus wobjs[32]; int num_objs; + int num_wobjs; int timeout; int error; THREAD_RV rv; @@ -908,13 +1084,15 @@ channel_thread_loop(void *in_val) { timeout = -1; num_objs = 0; + num_wobjs = 0; objs[num_objs] = g_term_event; num_objs++; trans_get_wait_objs(g_lis_trans, objs, &num_objs); trans_get_wait_objs(g_api_lis_trans, objs, &num_objs); - while (g_obj_wait(objs, num_objs, 0, 0, timeout) == 0) + while (g_obj_wait(objs, num_objs, wobjs, num_wobjs, timeout) == 0) { + check_timeout(); if (g_is_wait_obj_set(g_term_event)) { LOGM((LOG_LEVEL_INFO, "channel_thread_loop: g_term_event set")); @@ -987,16 +1165,19 @@ channel_thread_loop(void *in_val) xfuse_check_wait_objs(); timeout = -1; num_objs = 0; + num_wobjs = 0; objs[num_objs] = g_term_event; num_objs++; trans_get_wait_objs(g_lis_trans, objs, &num_objs); - trans_get_wait_objs(g_con_trans, objs, &num_objs); + trans_get_wait_objs_rw(g_con_trans, objs, &num_objs, + wobjs, &num_wobjs); trans_get_wait_objs(g_api_lis_trans, objs, &num_objs); trans_get_wait_objs(g_api_con_trans, objs, &num_objs); xcommon_get_wait_objs(objs, &num_objs, &timeout); sound_get_wait_objs(objs, &num_objs, &timeout); dev_redir_get_wait_objs(objs, &num_objs, &timeout); xfuse_get_wait_objs(objs, &num_objs, &timeout); + get_timeout(&timeout); } /* end while (g_obj_wait(objs, num_objs, 0, 0, timeout) == 0) */ } @@ -1034,7 +1215,7 @@ child_signal_handler(int sig) { int i1; - LOG(10, ("child_signal_handler:")); + LOG(0, ("child_signal_handler:")); do { @@ -1051,6 +1232,14 @@ child_signal_handler(int sig) while (i1 >= 0); } +void DEFAULT_CC +segfault_signal_handler(int sig) +{ + LOG(0, ("segfault_signal_handler: entered.......")); + xfuse_deinit(); + exit(0); +} + /*****************************************************************************/ static int APP_CC get_display_num_from_display(char *display_text) @@ -1164,6 +1353,47 @@ read_ini(void) } /*****************************************************************************/ +static char* APP_CC +get_log_path() +{ + char* log_path = 0; + + log_path = g_getenv("CHANSRV_LOG_PATH"); + if (log_path == 0) + { + log_path = g_getenv("HOME"); + } + return log_path; +} + +/*****************************************************************************/ +static unsigned int APP_CC +get_log_level(const char* level_str, unsigned int default_level) +{ + static const char* levels[] = { + "LOG_LEVEL_ALWAYS", + "LOG_LEVEL_ERROR", + "LOG_LEVEL_WARNING", + "LOG_LEVEL_INFO", + "LOG_LEVEL_DEBUG" + }; + unsigned int i; + + if (level_str == NULL || level_str[0] == 0) + { + return default_level; + } + for (i = 0; i < ARRAYSIZE(levels); ++i) + { + if (g_strcasecmp(levels[i], level_str) == 0) + { + return i; + } + } + return default_level; +} + +/*****************************************************************************/ static int APP_CC run_exec(void) { @@ -1197,19 +1427,19 @@ main(int argc, char **argv) tbus waiters[4]; int pid = 0; char text[256]; - char *home_text; + char* log_path; char *display_text; char log_file[256]; enum logReturns error; struct log_config logconfig; + unsigned int log_level; g_init("xrdp-chansrv"); /* os_calls */ - home_text = g_getenv("HOME"); - - if (home_text == 0) + log_path = get_log_path(); + if (log_path == 0) { - g_writeln("error reading HOME environment variable"); + g_writeln("error reading CHANSRV_LOG_PATH and HOME environment variable"); g_deinit(); return 1; } @@ -1217,10 +1447,12 @@ main(int argc, char **argv) read_ini(); pid = g_getpid(); + log_level = get_log_level(g_getenv("CHANSRV_LOG_LEVEL"), LOG_LEVEL_ERROR); + /* starting logging subsystem */ g_memset(&logconfig, 0, sizeof(struct log_config)); logconfig.program_name = "XRDP-Chansrv"; - g_snprintf(log_file, 255, "%s/xrdp-chansrv.log", home_text); + g_snprintf(log_file, 255, "%s/xrdp-chansrv.log", log_path); g_writeln("chansrv::main: using log file [%s]", log_file); if (g_file_exist(log_file)) @@ -1230,7 +1462,7 @@ main(int argc, char **argv) logconfig.log_file = log_file; logconfig.fd = -1; - logconfig.log_level = LOG_LEVEL_ERROR; + logconfig.log_level = log_level; logconfig.enable_syslog = 0; logconfig.syslog_level = 0; error = log_start_from_param(&logconfig); @@ -1262,6 +1494,8 @@ main(int argc, char **argv) g_signal_user_interrupt(term_signal_handler); /* SIGINT */ g_signal_pipe(nil_signal_handler); /* SIGPIPE */ g_signal_child_stop(child_signal_handler); /* SIGCHLD */ + g_signal_segfault(segfault_signal_handler); + display_text = g_getenv("DISPLAY"); LOGM((LOG_LEVEL_INFO, "main: DISPLAY env var set to %s", display_text)); get_display_num_from_display(display_text); diff --git a/sesman/chansrv/chansrv.h b/sesman/chansrv/chansrv.h index bca30ca4..a3e8ed51 100644 --- a/sesman/chansrv/chansrv.h +++ b/sesman/chansrv/chansrv.h @@ -1,8 +1,8 @@ /** * xrdp: A Remote Desktop Protocol server. * - * Copyright (C) Jay Sorg 2009-2012 - * Copyright (C) Laxmikant Rashinkar 2009-2012 + * Copyright (C) Jay Sorg 2009-2013 + * Copyright (C) Laxmikant Rashinkar 2009-2013 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -54,8 +54,13 @@ struct xrdp_api_data int is_connected; }; +int DEFAULT_CC +g_is_term(void); + int APP_CC send_channel_data(int chan_id, char *data, int size); +int APP_CC send_rail_drawing_orders(char* data, int size); int APP_CC main_cleanup(void); +int APP_CC add_timeout(int msoffset, void (*callback)(void* data), void* data); int APP_CC find_empty_slot_in_dvc_channels(); struct xrdp_api_data * APP_CC struct_from_dvc_chan_id(tui32 dvc_chan_id); int remove_struct_with_chan_id(tui32 dvc_chan_id); diff --git a/sesman/chansrv/chansrv_fuse.c b/sesman/chansrv/chansrv_fuse.c index 572679eb..2eb78ea0 100644 --- a/sesman/chansrv/chansrv_fuse.c +++ b/sesman/chansrv/chansrv_fuse.c @@ -102,6 +102,7 @@ void xfuse_devredir_cb_file_close(void *vp) {} #include "os_calls.h" #include "chansrv_fuse.h" #include "list.h" +#include "fifo.h" #define min(x, y) ((x) < (y) ? (x) : (y)) @@ -223,6 +224,16 @@ struct dir_info int index; }; +/* queue FUSE opendir commands so we run only one at a time */ +struct opendir_req +{ + fuse_req_t req; + fuse_ino_t ino; + struct fuse_file_info *fi; +}; + +FIFO g_fifo_opendir; + static struct list *g_req_list = 0; static struct xrdp_fs g_xrdp_fs; /* an inst of xrdp file system */ static char *g_mount_point = 0; /* our FUSE mount point */ @@ -338,19 +349,22 @@ static void xfuse_cb_create(fuse_req_t req, fuse_ino_t parent, static void xfuse_cb_fsync(fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_info *fi); -/* clipboard calls */ -int clipboard_request_file_data(int stream_id, int lindex, int offset, - int request_bytes); - static void xfuse_cb_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, int to_set, struct fuse_file_info *fi); static void xfuse_cb_opendir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); +static int xfuse_proc_opendir_req(fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); + static void xfuse_cb_releasedir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); +/* clipboard calls */ +int clipboard_request_file_data(int stream_id, int lindex, int offset, + int request_bytes); + /* misc calls */ static void xfuse_mark_as_stale(int pinode); static void xfuse_delete_stale_entries(int pinode); @@ -403,6 +417,9 @@ int xfuse_init() if (xfuse_init_xrdp_fs()) return -1; + /* setup FIFOs */ + fifo_init(&g_fifo_opendir, 30); + /* setup FUSE callbacks */ g_memset(&g_xfuse_ops, 0, sizeof(g_xfuse_ops)); g_xfuse_ops.lookup = xfuse_cb_lookup; @@ -424,6 +441,8 @@ int xfuse_init() fuse_opt_add_arg(&args, "xrdp-chansrv"); fuse_opt_add_arg(&args, g_fuse_root_path); + //fuse_opt_add_arg(&args, "-s"); /* single threaded mode */ + //fuse_opt_add_arg(&args, "-d"); /* debug mode */ if (xfuse_init_lib(&args)) { @@ -444,6 +463,7 @@ int xfuse_init() int xfuse_deinit() { xfuse_deinit_xrdp_fs(); + fifo_deinit(&g_fifo_opendir); if (g_ch != 0) { @@ -901,12 +921,11 @@ static int xfuse_deinit_xrdp_fs() static int xfuse_is_inode_valid(int ino) { - /* our lowest ino is FIRST_INODE */ - if (ino < FIRST_INODE) + /* is ino present in our table? */ + if ((ino < FIRST_INODE) || (ino >= g_xrdp_fs.next_node)) return 0; - /* is ino present in our table? */ - if (ino >= g_xrdp_fs.next_node) + if (g_xrdp_fs.inode_table[ino] == NULL) return 0; return 1; @@ -989,6 +1008,11 @@ static void xfuse_dump_fs() log_debug("found %d entries", g_xrdp_fs.num_entries - FIRST_INODE); +#if 0 + log_debug("not dumping xrdp fs"); + return; +#endif + for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++) { if ((xinode = g_xrdp_fs.inode_table[i]) == NULL) @@ -1229,6 +1253,9 @@ static int xfuse_delete_file_with_xinode(XRDP_INODE *xinode) if ((xinode == NULL) || (xinode->mode & S_IFDIR)) return -1; + log_always("deleting: inode=%d name=%s", xinode->inode, xinode->name); + log_debug("deleting: inode=%d name=%s", xinode->inode, xinode->name); + g_xrdp_fs.inode_table[xinode->parent_inode]->nentries--; g_xrdp_fs.inode_table[xinode->inode] = NULL; free(xinode); @@ -1281,6 +1308,12 @@ static int xfuse_recursive_delete_dir_with_xinode(XRDP_INODE *xinode) if ((xinode == NULL) || (xinode->mode & S_IFREG)) return -1; + log_always("recursively deleting dir with inode=%d name=%s", + xinode->inode, xinode->name); + + log_debug("recursively deleting dir with inode=%d name=%s", + xinode->inode, xinode->name); + for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++) { if ((xip = g_xrdp_fs.inode_table[i]) == NULL) @@ -1342,60 +1375,6 @@ static void xfuse_update_xrdpfs_size() g_xrdp_fs.inode_table = vp; } -/* LK_TODO do we still need this function */ -#if 0 -static void xfuse_enum_dir(fuse_req_t req, fuse_ino_t ino, size_t size, - off_t off, struct fuse_file_info *fi) -{ - XRDP_INODE *xinode; - XRDP_INODE *xinode1; - struct dirbuf b; - int first_time = 1; - int i; - - memset(&b, 0, sizeof(struct dirbuf)); - - for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++) - { - if ((xinode = g_xrdp_fs.inode_table[i]) == NULL) - continue; - - /* match parent inode */ - if (xinode->parent_inode != ino) - continue; - - if (first_time) - { - first_time = 0; - if (ino == 1) - { - xfuse_dirbuf_add(req, &b, ".", 1); - xfuse_dirbuf_add(req, &b, "..", 1); - } - else - { - xinode1 = g_xrdp_fs.inode_table[ino]; - xfuse_dirbuf_add(req, &b, ".", ino); - xfuse_dirbuf_add(req, &b, "..", xinode1->parent_inode); - } - } - - xfuse_dirbuf_add(req, &b, xinode->name, xinode->inode); - } - - if (!first_time) - { - if (off < b.size) - fuse_reply_buf(req, b.p + off, min(b.size - off, size)); - else - fuse_reply_buf(req, NULL, 0); - } - - if (b.p) - free(b.p); -} -#endif - /****************************************************************************** ** ** ** callbacks for devredir ** @@ -1464,8 +1443,9 @@ void xfuse_devredir_cb_enum_dir(void *vp, struct xrdp_inode *xinode) void xfuse_devredir_cb_enum_dir_done(void *vp, tui32 IoStatus) { - XFUSE_INFO *fip; - struct dir_info *di; + XFUSE_INFO *fip; + struct dir_info *di; + struct opendir_req *odreq; log_debug("vp=%p IoStatus=0x%x", vp, IoStatus); @@ -1473,7 +1453,7 @@ void xfuse_devredir_cb_enum_dir_done(void *vp, tui32 IoStatus) if (fip == NULL) { log_debug("fip is NULL"); - return; + goto done; } if (IoStatus != 0) @@ -1506,6 +1486,22 @@ done: if (fip) free(fip); + + /* remove current request */ + g_free(fifo_remove(&g_fifo_opendir)); + + while (1) + { + /* process next request */ + odreq = fifo_peek(&g_fifo_opendir); + if (!odreq) + return; + + if (xfuse_proc_opendir_req(odreq->req, odreq->ino, odreq->fi)) + g_free(fifo_remove(&g_fifo_opendir)); /* req failed */ + else + break; /* req has been queued */ + } } void xfuse_devredir_cb_open_file(void *vp, tui32 IoStatus, tui32 DeviceId, @@ -1903,15 +1899,19 @@ static void xfuse_cb_getattr(fuse_req_t req, fuse_ino_t ino, } xino = g_xrdp_fs.inode_table[ino]; + if (!xino) + { + log_debug("****** invalid ino=%d", (int) ino); + fuse_reply_err(req, EBADF); + return; + } memset(&stbuf, 0, sizeof(stbuf)); stbuf.st_ino = ino; stbuf.st_mode = xino->mode; stbuf.st_nlink = xino->nlink; stbuf.st_size = xino->size; - fuse_reply_attr(req, &stbuf, 1.0); - log_debug("exiting"); } /** @@ -1977,8 +1977,7 @@ static void xfuse_cb_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, int i; int first_time; - log_debug("req=%p inode=%d name=%s size=%d offset=%d", req, ino, - g_xrdp_fs.inode_table[ino]->name, size, off); + log_debug("req=%p inode=%d size=%d offset=%d", req, ino, size, off); /* do we have a valid inode? */ if (!xfuse_is_inode_valid(ino)) @@ -2014,6 +2013,12 @@ static void xfuse_cb_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, { first_time = 0; ti = g_xrdp_fs.inode_table[ino]; + if (!ti) + { + log_debug("****** g_xrdp_fs.inode_table[%d] is NULL", ino); + fuse_reply_buf(req, NULL, 0); + return; + } xfuse_dirbuf_add1(req, &b, ".", ino); xfuse_dirbuf_add1(req, &b, "..", ti->parent_inode); } @@ -2451,6 +2456,12 @@ static void xfuse_cb_open(fuse_req_t req, fuse_ino_t ino, /* if ino points to a dir, fail the open request */ xinode = g_xrdp_fs.inode_table[ino]; + if (!xinode) + { + log_debug("****** g_xrdp_fs.inode_table[%d] is NULL", ino); + fuse_reply_err(req, EBADF); + return; + } if (xinode->mode & S_IFDIR) { log_debug("reading a dir not allowed!"); @@ -2491,8 +2502,6 @@ static void xfuse_cb_open(fuse_req_t req, fuse_ino_t ino, fip->name[1023] = 0; fip->reply_type = RT_FUSE_REPLY_OPEN; - /* LK_TODO need to handle open permissions */ - /* we want path minus 'root node of the share' */ if ((cptr = strchr(full_path, '/')) == NULL) { @@ -2532,6 +2541,12 @@ static void xfuse_cb_release(fuse_req_t req, fuse_ino_t ino, struct } XRDP_INODE *xinode = g_xrdp_fs.inode_table[ino]; + if (!xinode) + { + log_debug("****** g_xrdp_fs.inode_table[%d] is NULL", ino); + fuse_reply_err(req, 0); + return; + } if (xinode->is_loc_resource) { /* specified file is a local resource */ @@ -2748,7 +2763,12 @@ static void xfuse_cb_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, return; } - xinode = g_xrdp_fs.inode_table[ino]; + if ((xinode = g_xrdp_fs.inode_table[ino]) == NULL) + { + log_debug("g_xrdp_fs.inode_table[%d] is NULL", ino); + fuse_reply_err(req, EBADF); + return; + } if (to_set & FUSE_SET_ATTR_MODE) { @@ -2813,9 +2833,40 @@ static void xfuse_cb_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, fuse_reply_attr(req, &st, 1.0); /* LK_TODO just faking for now */ } +/** + * Get dir listing + *****************************************************************************/ static void xfuse_cb_opendir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { + struct opendir_req *odreq; + + /* save request */ + odreq = malloc(sizeof(struct opendir_req)); + odreq->req = req; + odreq->ino = ino; + odreq->fi = fi; + + if (fifo_is_empty(&g_fifo_opendir)) + { + fifo_insert(&g_fifo_opendir, odreq); + xfuse_proc_opendir_req(req, ino, fi); + } + else + { + /* place req in FIFO; xfuse_devredir_cb_enum_dir_done() will handle it */ + fifo_insert(&g_fifo_opendir, odreq); + } +} + +/** + * Process the next opendir req + * + * @return 0 of the request was sent for remote lookup, -1 otherwise + *****************************************************************************/ +static int xfuse_proc_opendir_req(fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi) +{ struct dir_info *di; XRDP_INODE *xinode; XFUSE_INFO *fip; @@ -2823,19 +2874,26 @@ static void xfuse_cb_opendir(fuse_req_t req, fuse_ino_t ino, char full_path[4096]; char *cptr; - log_debug("inode=%d name=%s", ino, g_xrdp_fs.inode_table[ino]->name); + log_debug("inode=%d", ino); if (!xfuse_is_inode_valid(ino)) { log_error("inode %d is not valid", ino); fuse_reply_err(req, EBADF); - return; + g_free(fifo_remove(&g_fifo_opendir)); + return -1; } if (ino == 1) goto done; /* special case; enumerate top level dir */ - xinode = g_xrdp_fs.inode_table[ino]; + if ((xinode = g_xrdp_fs.inode_table[ino]) == NULL) + { + log_debug("g_xrdp_fs.inode_table[%d] is NULL", ino); + fuse_reply_err(req, EBADF); + g_free(fifo_remove(&g_fifo_opendir)); + return -1; + } if (xinode->is_loc_resource) goto done; @@ -2846,7 +2904,8 @@ static void xfuse_cb_opendir(fuse_req_t req, fuse_ino_t ino, if (xinode->is_synced) { xfuse_enum_dir(req, ino, size, off, fi); - return; + g_free(fifo_remove(&g_fifo_opendir)); + return -1; } else { @@ -2867,7 +2926,8 @@ do_remote_lookup: { log_error("system out of memory"); fuse_reply_err(req, ENOMEM); - return; + g_free(fifo_remove(&g_fifo_opendir)); + return -1; } fip->req = req; @@ -2900,7 +2960,7 @@ do_remote_lookup: } } - return; + return 0; done: @@ -2908,6 +2968,8 @@ done: di->index = FIRST_INODE; fi->fh = (long) di; fuse_reply_open(req, fi); + g_free(fifo_remove(&g_fifo_opendir)); + return -1; } /** diff --git a/sesman/chansrv/clipboard.c b/sesman/chansrv/clipboard.c index c2062605..25775f3b 100644 --- a/sesman/chansrv/clipboard.c +++ b/sesman/chansrv/clipboard.c @@ -277,6 +277,39 @@ static int g_num_formatIds = 0; static int g_file_format_id = -1; +static char g_last_atom_name[256] = ""; + +/*****************************************************************************/ +static char* APP_CC +get_atom_text(Atom atom) +{ + char* name; + int failed; + + failed = 0; + /* sanity check */ + if ((atom < 1) || (atom > 512)) + { + failed = 1; + } + if (!failed) + { + name = XGetAtomName(g_display, atom); + if (name == 0) + { + failed = 1; + } + } + if (failed) + { + g_snprintf(g_last_atom_name, 255, "unknown atom 0x%8.8x", (int)atom); + return g_last_atom_name; + } + g_strncpy(g_last_atom_name, name, 255); + XFree(name); + return g_last_atom_name; +} + /*****************************************************************************/ /* this is one way to get the current time from the x server */ static Time APP_CC @@ -895,8 +928,8 @@ clipboard_provide_selection_c2s(XSelectionRequestEvent *req, Atom type) g_clip_c2s.property = req->property; g_clip_c2s.window = req->requestor; log_debug("clipboard_provide_selection_c2s: start INCR property %s " - "type %s", XGetAtomName(g_display, req->property), - XGetAtomName(g_display, type)); + "type %s", get_atom_text(req->property), + get_atom_text(type)); val1[0] = g_clip_c2s.total_bytes; val1[1] = 0; XChangeProperty(g_display, req->requestor, req->property, @@ -1697,7 +1730,7 @@ clipboard_get_window_property(Window wnd, Atom prop, Atom *type, int *fmt, Atom ltype; log_debug("clipboard_get_window_property:"); - log_debug(" prop %d name %s", prop, XGetAtomName(g_display, prop)); + log_debug(" prop %d name %s", prop, get_atom_text(prop)); lxdata = 0; ltype = 0; XGetWindowProperty(g_display, wnd, prop, 0, 0, 0, @@ -1837,7 +1870,7 @@ clipboard_event_selection_notify(XEvent *xevent) { log_debug("clipboard_event_selection_notify: wnd %p prop %s", lxevent->requestor, - XGetAtomName(g_display, lxevent->property)); + get_atom_text(lxevent->property)); rv = clipboard_get_window_property(lxevent->requestor, lxevent->property, &type, &fmt, &n_items, &data, &data_size); @@ -1855,8 +1888,8 @@ clipboard_event_selection_notify(XEvent *xevent) PropertyNotify */ log_debug("clipboard_event_selection_notify: type is INCR " "data_size %d property name %s type %s", data_size, - XGetAtomName(g_display, lxevent->property), - XGetAtomName(g_display, lxevent->type)); + get_atom_text(lxevent->property), + get_atom_text(lxevent->type)); g_clip_s2c.incr_in_progress = 1; g_clip_s2c.property = lxevent->property; g_clip_s2c.type = lxevent->target; @@ -1882,10 +1915,10 @@ clipboard_event_selection_notify(XEvent *xevent) for (index = 0; index < n_items; index++) { atom = atoms[index]; - log_debug("clipboard_event_selection_notify: %d %s %d", - atom, XGetAtomName(g_display, atom), XA_STRING); + LOGM((LOG_LEVEL_DEBUG, "clipboard_event_selection_notify: %d %s %d", + atom, get_atom_text(atom), XA_STRING)); log_debug("clipboard_event_selection_notify: 0x%x %s", - atom, XGetAtomName(g_display, atom)); + atom, get_atom_text(atom)); if (atom == g_utf8_atom) { got_utf8 = 1; @@ -2091,7 +2124,6 @@ static int APP_CC clipboard_event_selection_request(XEvent *xevent) { XSelectionRequestEvent *lxev; - XEvent xev; Atom atom_buf[10]; Atom type; int atom_count; @@ -2105,7 +2137,7 @@ clipboard_event_selection_request(XEvent *xevent) log_debug("clipboard_event_selection_request: g_wnd %d, " ".requestor %d .owner %d .selection %d '%s' .target %d .property %d", g_wnd, lxev->requestor, lxev->owner, lxev->selection, - XGetAtomName(g_display, lxev->selection), + get_atom_text(lxev->selection), lxev->target, lxev->property); if (lxev->property == None) @@ -2164,8 +2196,7 @@ clipboard_event_selection_request(XEvent *xevent) "g_multiple_atom"); xdata = 0; - if (clipboard_get_window_property(xev.xselection.requestor, - xev.xselection.property, + if (clipboard_get_window_property(lxev->requestor, lxev->property, &type, &fmt, &n_items, &xdata, &xdata_size) == 0) { @@ -2235,9 +2266,9 @@ clipboard_event_selection_request(XEvent *xevent) else { log_debug("clipboard_event_selection_request: unknown " - "target %s", XGetAtomName(g_display, lxev->target)); - log_error("clipboard_event_selection_request: unknown " - "target %s", XGetAtomName(g_display, lxev->target)); + "target %s", get_atom_text(lxev->target)); + LOGM((LOG_LEVEL_ERROR, "clipboard_event_selection_request: unknown " + "target %s", get_atom_text(lxev->target))); } clipboard_refuse_selection(lxev); @@ -2293,7 +2324,7 @@ clipboard_event_property_notify(XEvent *xevent) log_debug("clipboard_event_property_notify: PropertyNotify .window %d " ".state %d .atom %d %s", xevent->xproperty.window, xevent->xproperty.state, xevent->xproperty.atom, - XGetAtomName(g_display, xevent->xproperty.atom)); + get_atom_text(xevent->xproperty.atom)); if (g_clip_c2s.incr_in_progress && (xevent->xproperty.window == g_clip_c2s.window) && diff --git a/sesman/chansrv/devredir.c b/sesman/chansrv/devredir.c index 418c29e7..cdcc9e94 100644 --- a/sesman/chansrv/devredir.c +++ b/sesman/chansrv/devredir.c @@ -68,7 +68,7 @@ #define log_info(_params...) \ { \ - if (LOG_INFO <= LOG_LEVEL) \ + if (LOG_INFO <= LOG_LEVEL) \ { \ g_write("[%10.10u]: DEV_REDIR %s: %d : ", \ g_time3(), __func__, __LINE__); \ @@ -78,7 +78,7 @@ #define log_debug(_params...) \ { \ - if (LOG_DEBUG <= LOG_LEVEL) \ + if (LOG_DEBUG <= LOG_LEVEL) \ { \ g_write("[%10.10u]: DEV_REDIR %s: %d : ", \ g_time3(), __func__, __LINE__); \ @@ -587,53 +587,50 @@ void dev_redir_proc_client_core_cap_resp(struct stream *s) tui16 cap_type; tui16 cap_len; tui32 cap_version; + char* holdp; xstream_rd_u16_le(s, num_caps); xstream_seek(s, 2); /* padding */ for (i = 0; i < num_caps; i++) { + holdp = s->p; xstream_rd_u16_le(s, cap_type); xstream_rd_u16_le(s, cap_len); xstream_rd_u32_le(s, cap_version); - /* remove header length and version */ - cap_len -= 8; - switch (cap_type) { case CAP_GENERAL_TYPE: log_debug("got CAP_GENERAL_TYPE"); - xstream_seek(s, cap_len); break; case CAP_PRINTER_TYPE: log_debug("got CAP_PRINTER_TYPE"); g_is_printer_redir_supported = 1; - xstream_seek(s, cap_len); break; case CAP_PORT_TYPE: log_debug("got CAP_PORT_TYPE"); g_is_port_redir_supported = 1; - xstream_seek(s, cap_len); break; case CAP_DRIVE_TYPE: log_debug("got CAP_DRIVE_TYPE"); g_is_drive_redir_supported = 1; if (cap_version == 2) + { g_drive_redir_version = 2; - xstream_seek(s, cap_len); + } break; case CAP_SMARTCARD_TYPE: log_debug("got CAP_SMARTCARD_TYPE"); g_is_smartcard_redir_supported = 1; scard_init(); - xstream_seek(s, cap_len); break; } + s->p = holdp + cap_len; } } @@ -1101,7 +1098,11 @@ dev_redir_file_open(void *fusep, tui32 device_id, char *path, #if 1 /* without the 0x00000010 rdesktop opens files in */ /* O_RDONLY instead of O_RDWR mode */ - DesiredAccess = DA_FILE_READ_DATA | DA_FILE_WRITE_DATA | DA_SYNCHRONIZE | 0x00000010; + if (mode & O_RDWR) + DesiredAccess = DA_FILE_READ_DATA | DA_FILE_WRITE_DATA | DA_SYNCHRONIZE | 0x00000010; + else + DesiredAccess = DA_FILE_READ_DATA | DA_SYNCHRONIZE; + CreateOptions = CO_FILE_SYNCHRONOUS_IO_NONALERT; CreateDisposition = CD_FILE_OPEN; // WAS 1 #else diff --git a/sesman/chansrv/fifo.c b/sesman/chansrv/fifo.c new file mode 100644 index 00000000..630df3cd --- /dev/null +++ b/sesman/chansrv/fifo.c @@ -0,0 +1,255 @@ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Laxmikant Rashinkar 2013 LK.Rashinkar@gmail.com + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /* FIFO implementation to store a pointer to a user struct */ + +/* module based logging */ +#define MODULE_NAME "FIFO " +#define LOCAL_DEBUG + +#include "fifo.h" +#include "mlog.h" + +/** + * Initialize a FIFO that grows as required + * + * @param fp pointer to a FIFO + * @param num_entries initial size + * + * @return 0 on success, -1 on failure + *****************************************************************************/ +int +fifo_init(FIFO* fp, int num_entries) +{ + log_debug_high("entered"); + + /* validate params */ + if (!fp) + { + log_debug_high("invalid parameters"); + return -1; + } + + if (num_entries < 1) + num_entries = 10; + + fp->rd_ptr = 0; + fp->wr_ptr = 0; + fp->user_data = (long *) g_malloc(sizeof(long) * num_entries); + + if (fp->user_data) + { + fp->entries = num_entries; + log_debug_low("FIFO created; rd_ptr=%d wr_ptr=%d entries=%d", + fp->rd_ptr, fp->wr_ptr, fp->entries); + return 0; + } + else + { + log_error("FIFO create error; system out of memory"); + fp->entries = 0; + return -1; + } +} + +/** + * Deinit FIFO and release resources + * + * @param fp FIFO to deinit + * + * @return 0 on success, -1 on error + *****************************************************************************/ +int +fifo_deinit(FIFO* fp) +{ + log_debug_high("entered"); + + if (!fp) + { + log_debug_high("FIFO is null"); + return -1; + } + + if (fp->user_data) + { + g_free(fp->user_data); + fp->user_data = 0; + } + + fp->rd_ptr = 0; + fp->wr_ptr = 0; + fp->entries = 0; +} + +/** + * Check if FIFO is empty + * + * @param fp FIFO + * + * @return 1 if FIFO is empty, 0 otherwise + *****************************************************************************/ +int +fifo_is_empty(FIFO* fp) +{ + log_debug_high("entered"); + + if (!fp) + { + log_debug_high("FIFO is null"); + return 0; + } + + return (fp->rd_ptr == fp->wr_ptr) ? 1 : 0; +} + +/** + * Insert an item at the end + * + * @param fp FIFO + * @param data data to insert into FIFO + * + * @param 0 on success, -1 on error + *****************************************************************************/ + +int +fifo_insert(FIFO* fp, void* data) +{ + long* lp; + int next_val; /* next value for wr_ptr */ + int i; + + log_debug_high("entered"); + + if (!fp) + { + log_debug_high("FIFO is null"); + return -1; + } + + next_val = fp->wr_ptr + 1; + if (next_val >= fp->entries) + next_val = 0; + + if (next_val == fp->rd_ptr) + { + /* FIFO is full, expand it by 10 entries */ + lp = (long *) g_malloc(sizeof(long) * (fp->entries + 10)); + if (!lp) + { + log_debug_low("FIFO full; cannot expand, no memory"); + return -1; + } + + log_debug_low("FIFO full, expanding by 10 entries"); + + /* copy old data new location */ + for (i = 0; i < (fp->entries - 1); i++) + { + lp[i] = fp->user_data[fp->rd_ptr++]; + if (fp->rd_ptr >= fp->entries) + fp->rd_ptr = 0; + } + + /* update pointers */ + fp->rd_ptr = 0; + fp->wr_ptr = fp->entries - 1; + next_val = fp->entries; + fp->entries += 10; + + /* free old data */ + g_free(fp->user_data); + fp->user_data = lp; + } + + log_debug_low("inserting data at index %d", fp->wr_ptr); + + fp->user_data[fp->wr_ptr] = (long) data; + fp->wr_ptr = next_val; + + return 0; +} + +/** + * Remove an item from the head + * + * @param fp FIFO + * + * @param data on success, NULL on error + *****************************************************************************/ +void* +fifo_remove(FIFO* fp) +{ + long data; + + log_debug_high("entered"); + + if (!fp) + { + log_debug_high("FIFO is null"); + return 0; + } + + if (fp->rd_ptr == fp->wr_ptr) + { + log_debug_high("FIFO is empty"); + return 0; + } + + log_debug_low("removing data at index %d", fp->rd_ptr); + + data = fp->user_data[fp->rd_ptr++]; + + if (fp->rd_ptr >= fp->entries) + { + log_debug_high("FIFO rd_ptr wrapped around"); + fp->rd_ptr = 0; + } + + return (void *) data; +} + +/** + * Return item from head, but do not remove it + * + * @param fp FIFO + * + * @param data on success, NULL on error + *****************************************************************************/ +void* +fifo_peek(FIFO* fp) +{ + long data; + + log_debug_high("entered\n"); + + if (!fp) + { + log_debug_high("FIFO is null\n"); + return 0; + } + + if (fp->rd_ptr == fp->wr_ptr) + { + log_debug_high("FIFO is empty\n"); + return 0; + } + + log_debug_low("peeking data at index %d\n", fp->rd_ptr); + + return (void *) fp->user_data[fp->rd_ptr]; +} diff --git a/freerdp/xrdp-color.h b/sesman/chansrv/fifo.h index 3c58c032..0a23592c 100644 --- a/freerdp/xrdp-color.h +++ b/sesman/chansrv/fifo.h @@ -1,7 +1,7 @@ /** * xrdp: A Remote Desktop Protocol server. * - * Copyright (C) Jay Sorg 2004-2012 + * Copyright (C) Laxmikant Rashinkar 2013 LK.Rashinkar@gmail.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,20 @@ * limitations under the License. */ -#ifndef __XRDP_COLOR_H -#define __XRDP_COLOR_H + /* FIFO implementation to store a pointer to a user struct */ -char* APP_CC -convert_bitmap(int in_bpp, int out_bpp, char* bmpdata, - int width, int height, int* palette); -int APP_CC -convert_color(int in_bpp, int out_bpp, int in_color, int* palette); +typedef struct fifo +{ + long* user_data; + int rd_ptr; + int wr_ptr; + int entries; +} FIFO; + +int fifo_init(FIFO* fp, int num_entries); +int fifo_deinit(FIFO* fp); +int fifo_is_empty(FIFO* fp); +int fifo_insert(FIFO* fp, void* data); +void* fifo_remove(FIFO* fp); +void* fifo_peek(FIFO* fp); -#endif diff --git a/sesman/chansrv/irp.h b/sesman/chansrv/irp.h index e1a65d83..a13ea8e5 100644 --- a/sesman/chansrv/irp.h +++ b/sesman/chansrv/irp.h @@ -52,6 +52,7 @@ struct irp void (*callback)(struct stream *s, IRP *irp, tui32 DeviceId, tui32 CompletionId, tui32 IoStatus); + void *user_data; }; IRP * APP_CC devredir_irp_new(void); diff --git a/sesman/chansrv/mlog.h b/sesman/chansrv/mlog.h new file mode 100644 index 00000000..866c9692 --- /dev/null +++ b/sesman/chansrv/mlog.h @@ -0,0 +1,112 @@ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Laxmikant Rashinkar 2013 LK.Rashinkar@gmail.com + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /* module based logging */ + +#ifndef _MLOG_H +#define _MLOG_H + +/* + * Note1: to enable debug messages, in your .c file, #define LOCAL_DEBUG + * BEFORE including this file + * + * Note2: in your .c file, #define MODULE_NAME, 8 chars long, to print each + * log entry with your module name + */ + +#define LOG_ERROR 0 +#define LOG_INFO 1 +#define LOG_DEBUG_LOW 2 +#define LOG_DEBUG_HIGH 3 +#define LOG_LEVEL LOG_ERROR + +/* + * print always + */ + +#define log_error(_params...) \ +do \ +{ \ + g_write("[%10.10u]: %s %s: %d: ERROR: ", g_time3(), \ + MODULE_NAME, __func__, __LINE__); \ + g_writeln (_params); \ +} \ +while(0) + +#define log_always(_params...) \ +do \ +{ \ + g_write("[%10.10u]: %s %s: %d: ALWAYS: ", g_time3(), \ + MODULE_NAME, __func__, __LINE__); \ + g_writeln (_params); \ +} \ +while(0) + +/* + * print conditionally + */ + +#ifdef LOCAL_DEBUG +#define log_info(_params...) \ +do \ +{ \ + if (LOG_INFO <= LOG_LEVEL) \ + { \ + g_write("[%10.10u]: %s %s: %d: INFO: ", g_time3(), \ + MODULE_NAME, __func__, __LINE__); \ + g_writeln (_params); \ + } \ +} \ +while(0) +#else +#define log_info(_params...) +#endif + +#ifdef LOCAL_DEBUG +#define log_debug_low(_params...) \ +do \ +{ \ + if (LOG_DEBUG_LOW <= LOG_LEVEL) \ + { \ + g_write("[%10.10u]: %s %s: %d: DEBUG: ", g_time3(), \ + MODULE_NAME, __func__, __LINE__); \ + g_writeln (_params); \ + } \ +} \ +while(0) +#else +#define log_debug_low(_params...) +#endif + +#ifdef LOCAL_DEBUG +#define log_debug_high(_params...) \ +do \ +{ \ + if (LOG_DEBUG_HIGH <= LOG_LEVEL) \ + { \ + g_write("[%10.10u]: %s %s: %d: DEBUG: ", g_time3(), \ + MODULE_NAME, __func__, __LINE__); \ + g_writeln (_params); \ + } \ +} \ +while(0) +#else +#define log_debug_high(_params...) +#endif + +#endif /* #ifndef _MLOG_H */ diff --git a/sesman/chansrv/pcsc/Makefile b/sesman/chansrv/pcsc/Makefile new file mode 100644 index 00000000..483151f2 --- /dev/null +++ b/sesman/chansrv/pcsc/Makefile @@ -0,0 +1,12 @@ + +OBJS = xrdp_pcsc.o + +CFLAGS = -Wall -O2 -fPIC + +all: libpcsclite.so + +libpcsclite.so: $(OBJS) + $(CC) $(LDFLAGS) -shared -o libpcsclite.so $(OBJS) + +clean: + rm -f $(OBJS) libpcsclite.so diff --git a/sesman/chansrv/pcsc/xrdp_pcsc.c b/sesman/chansrv/pcsc/xrdp_pcsc.c new file mode 100644 index 00000000..502d3096 --- /dev/null +++ b/sesman/chansrv/pcsc/xrdp_pcsc.c @@ -0,0 +1,1157 @@ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <pthread.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <sys/stat.h> + +#define PCSC_API + +typedef unsigned char BYTE; +typedef BYTE *LPBYTE; +typedef unsigned int LONG; +typedef unsigned int DWORD; +typedef DWORD *LPDWORD; +typedef const void *LPCVOID; +typedef const char *LPCSTR; +typedef char *LPSTR; +typedef void *LPVOID; +typedef const BYTE *LPCBYTE; + +typedef LONG SCARDCONTEXT; +typedef SCARDCONTEXT *LPSCARDCONTEXT; + +typedef LONG SCARDHANDLE; +typedef SCARDHANDLE *LPSCARDHANDLE; + +#define MAX_ATR_SIZE 33 + +typedef struct _SCARD_READERSTATE +{ + const char *szReader; + void *pvUserData; + DWORD dwCurrentState; + DWORD dwEventState; + DWORD cbAtr; + unsigned char rgbAtr[MAX_ATR_SIZE]; +} SCARD_READERSTATE, *LPSCARD_READERSTATE; + +typedef struct _SCARD_IO_REQUEST +{ + unsigned long dwProtocol; + unsigned long cbPciLength; +} SCARD_IO_REQUEST, *PSCARD_IO_REQUEST, *LPSCARD_IO_REQUEST; + +#define SCARD_PROTOCOL_T0 0x0001 /**< T=0 active protocol. */ +#define SCARD_PROTOCOL_T1 0x0002 /**< T=1 active protocol. */ +#define SCARD_PROTOCOL_RAW 0x0004 /**< Raw active protocol. */ + +PCSC_API SCARD_IO_REQUEST g_rgSCardRawPci = { SCARD_PROTOCOL_T0, 8 }; +PCSC_API SCARD_IO_REQUEST g_rgSCardT1Pci = { SCARD_PROTOCOL_T1, 8 }; +PCSC_API SCARD_IO_REQUEST g_rgSCardT0Pci = { SCARD_PROTOCOL_RAW, 8 }; + +#define LLOG_LEVEL 5 +#define LLOGLN(_level, _args) \ + do { if (_level < LLOG_LEVEL) { printf _args ; printf("\n"); } } while (0) + +#define SCARD_ESTABLISH_CONTEXT 0x01 +#define SCARD_RELEASE_CONTEXT 0x02 +#define SCARD_LIST_READERS 0x03 +#define SCARD_CONNECT 0x04 +#define SCARD_RECONNECT 0x05 +#define SCARD_DISCONNECT 0x06 +#define SCARD_BEGIN_TRANSACTION 0x07 +#define SCARD_END_TRANSACTION 0x08 +#define SCARD_TRANSMIT 0x09 +#define SCARD_CONTROL 0x0A +#define SCARD_STATUS 0x0B +#define SCARD_GET_STATUS_CHANGE 0x0C +#define SCARD_CANCEL 0x0D +#define SCARD_CANCEL_TRANSACTION 0x0E +#define SCARD_GET_ATTRIB 0x0F +#define SCARD_SET_ATTRIB 0x10 + +#define SCARD_S_SUCCESS 0x00000000 +#define SCARD_F_INTERNAL_ERROR ((LONG)0x80100001) + +#define SET_UINT32(_data, _offset, _val) do { \ + (((BYTE*)(_data)) + (_offset))[0] = ((_val) >> 0) & 0xff; \ + (((BYTE*)(_data)) + (_offset))[1] = ((_val) >> 8) & 0xff; \ + (((BYTE*)(_data)) + (_offset))[2] = ((_val) >> 16) & 0xff; \ + (((BYTE*)(_data)) + (_offset))[3] = ((_val) >> 24) & 0xff; } while (0) + +#define GET_UINT32(_data, _offset) \ + ((((BYTE*)(_data)) + (_offset))[0] << 0) | \ + ((((BYTE*)(_data)) + (_offset))[1] << 8) | \ + ((((BYTE*)(_data)) + (_offset))[2] << 16) | \ + ((((BYTE*)(_data)) + (_offset))[3] << 24) + +#define LMIN(_val1, _val2) (_val1) < (_val2) ? (_val1) : (_val2) +#define LMAX(_val1, _val2) (_val1) > (_val2) ? (_val1) : (_val2) + +static int g_sck = -1; /* unix domain socket */ + +static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER; + +/* for pcsc_stringify_error */ +static char g_error_str[512]; + +/*****************************************************************************/ +static int +get_display_num_from_display(const char *display_text) +{ + int rv; + int index; + int mode; + int host_index; + int disp_index; + int scre_index; + char host[256]; + char disp[256]; + char scre[256]; + + memset(host, 0, 256); + memset(disp, 0, 256); + memset(scre, 0, 256); + + index = 0; + host_index = 0; + disp_index = 0; + scre_index = 0; + mode = 0; + + while (display_text[index] != 0) + { + if (display_text[index] == ':') + { + mode = 1; + } + else if (display_text[index] == '.') + { + mode = 2; + } + else if (mode == 0) + { + host[host_index] = display_text[index]; + host_index++; + } + else if (mode == 1) + { + disp[disp_index] = display_text[index]; + disp_index++; + } + else if (mode == 2) + { + scre[scre_index] = display_text[index]; + scre_index++; + } + index++; + } + host[host_index] = 0; + disp[disp_index] = 0; + scre[scre_index] = 0; + LLOGLN(0, ("get_display_num_from_display: host [%s] disp [%s] scre [%s]", + host, disp, scre)); + rv = atoi(disp); + return rv; +} + +/*****************************************************************************/ +static int +connect_to_chansrv(void) +{ + int bytes; + int dis; + int error; + char *xrdp_session; + char *xrdp_display; + char *home_str; + struct sockaddr_un saddr; + struct sockaddr *psaddr; + + if (g_sck != -1) + { + /* already connected */ + return 0; + } + xrdp_session = getenv("XRDP_SESSION"); + if (xrdp_session == NULL) + { + /* XRDP_SESSION must be set */ + LLOGLN(0, ("connect_to_chansrv: error, not xrdp session")); + return 1; + } + xrdp_display = getenv("DISPLAY"); + if (xrdp_display == NULL) + { + /* DISPLAY must be set */ + LLOGLN(0, ("connect_to_chansrv: error, display not set")); + return 1; + } + home_str = getenv("HOME"); + if (home_str == NULL) + { + /* HOME must be set */ + LLOGLN(0, ("connect_to_chansrv: error, home not set")); + return 1; + } + dis = get_display_num_from_display(xrdp_display); + if (dis < 10) + { + /* DISPLAY must be > 9 */ + LLOGLN(0, ("connect_to_chansrv: error, display not > 9 %d", dis)); + return 1; + } + g_sck = socket(PF_LOCAL, SOCK_STREAM, 0); + if (g_sck == -1) + { + LLOGLN(0, ("connect_to_chansrv: error, socket failed")); + return 1; + } + memset(&saddr, 0, sizeof(struct sockaddr_un)); + saddr.sun_family = AF_UNIX; + bytes = sizeof(saddr.sun_path); + snprintf(saddr.sun_path, bytes, "%s/.pcsc%d/pcscd.comm", home_str, dis); + saddr.sun_path[bytes - 1] = 0; + LLOGLN(0, ("connect_to_chansrv: connecting to %s", saddr.sun_path)); + psaddr = (struct sockaddr *) &saddr; + bytes = sizeof(struct sockaddr_un); + error = connect(g_sck, psaddr, bytes); + if (error == 0) + { + } + else + { + perror("connect_to_chansrv"); + close(g_sck); + g_sck = -1; + LLOGLN(0, ("connect_to_chansrv: error, open %s", saddr.sun_path)); + return 1; + } + return 0; +} + +/*****************************************************************************/ +static int +send_message(int code, char *data, int bytes) +{ + char header[8]; + + SET_UINT32(header, 0, bytes); + SET_UINT32(header, 4, code); + if (send(g_sck, header, 8, 0) != 8) + { + return 1; + } + if (send(g_sck, data, bytes, 0) != bytes) + { + return 1; + } + return 0; +} + +/*****************************************************************************/ +static int +get_message(int *code, char *data, int *bytes) +{ + char header[8]; + int max_bytes; + + if (recv(g_sck, header, 8, 0) != 8) + { + return 1; + } + max_bytes = *bytes; + *bytes = GET_UINT32(header, 0); + *code = GET_UINT32(header, 4); + if (*bytes > max_bytes) + { + return 1; + } + if (recv(g_sck, data, *bytes, 0) != *bytes) + { + return 1; + } + return 0; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1, LPCVOID pvReserved2, + LPSCARDCONTEXT phContext) +{ + char msg[256]; + DWORD context; + int code; + int bytes; + int status; + + LLOGLN(10, ("SCardEstablishContext:")); + if (g_sck == -1) + { + if (connect_to_chansrv() != 0) + { + LLOGLN(0, ("SCardEstablishContext: error, can not connect " + "to chansrv")); + return SCARD_F_INTERNAL_ERROR; + } + } + pthread_mutex_lock(&g_mutex); + SET_UINT32(msg, 0, dwScope); + if (send_message(SCARD_ESTABLISH_CONTEXT, msg, 4) != 0) + { + LLOGLN(0, ("SCardEstablishContext: error, send_message")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + bytes = 256; + if (get_message(&code, msg, &bytes) != 0) + { + LLOGLN(0, ("SCardEstablishContext: error, get_message")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + if ((code != SCARD_ESTABLISH_CONTEXT) || (bytes != 8)) + { + LLOGLN(0, ("SCardEstablishContext: error, bad code")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_unlock(&g_mutex); + context = GET_UINT32(msg, 0); + status = GET_UINT32(msg, 4); + LLOGLN(10, ("SCardEstablishContext: got context 0x%8.8x", context)); + *phContext = context; + return status; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardReleaseContext(SCARDCONTEXT hContext) +{ + char msg[256]; + int code; + int bytes; + int status; + + LLOGLN(10, ("SCardReleaseContext:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardReleaseContext: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_lock(&g_mutex); + SET_UINT32(msg, 0, hContext); + if (send_message(SCARD_RELEASE_CONTEXT, msg, 4) != 0) + { + LLOGLN(0, ("SCardReleaseContext: error, send_message")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + bytes = 256; + if (get_message(&code, msg, &bytes) != 0) + { + LLOGLN(0, ("SCardReleaseContext: error, get_message")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + if ((code != SCARD_RELEASE_CONTEXT) || (bytes != 4)) + { + LLOGLN(0, ("SCardReleaseContext: error, bad code")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_unlock(&g_mutex); + status = GET_UINT32(msg, 0); + LLOGLN(10, ("SCardReleaseContext: got status 0x%8.8x", status)); + return status; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardIsValidContext(SCARDCONTEXT hContext) +{ + LLOGLN(10, ("SCardIsValidContext:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardIsValidContext: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_lock(&g_mutex); + pthread_mutex_unlock(&g_mutex); + return SCARD_S_SUCCESS; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader, DWORD dwShareMode, + DWORD dwPreferredProtocols, LPSCARDHANDLE phCard, + LPDWORD pdwActiveProtocol) +{ + char msg[256]; + int code; + int bytes; + int status; + int offset; + + LLOGLN(10, ("SCardConnect:")); + LLOGLN(10, ("SCardConnect: hContext %p szReader %s dwShareMode %d " + "dwPreferredProtocols %d", + (void*)hContext, szReader, dwShareMode, dwPreferredProtocols)); + if (g_sck == -1) + { + LLOGLN(0, ("SCardConnect: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + offset = 0; + SET_UINT32(msg, offset, hContext); + offset += 4; + bytes = strlen(szReader); + if (bytes > 99) + { + LLOGLN(0, ("SCardConnect: error, name too long")); + return SCARD_F_INTERNAL_ERROR; + } + memcpy(msg + offset, szReader, bytes); + memset(msg + offset + bytes, 0, 100 - bytes); + offset += 100; + SET_UINT32(msg, offset, dwShareMode); + offset += 4; + SET_UINT32(msg, offset, dwPreferredProtocols); + offset += 4; + pthread_mutex_lock(&g_mutex); + if (send_message(SCARD_CONNECT, msg, offset) != 0) + { + LLOGLN(0, ("SCardConnect: error, send_message")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + bytes = 256; + if (get_message(&code, msg, &bytes) != 0) + { + LLOGLN(0, ("SCardConnect: error, get_message")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + if (code != SCARD_CONNECT) + { + LLOGLN(0, ("SCardConnect: error, bad code")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_unlock(&g_mutex); + *phCard = GET_UINT32(msg, 0); + *pdwActiveProtocol = GET_UINT32(msg, 4); + status = GET_UINT32(msg, 8); + LLOGLN(10, ("SCardReleaseContext: got status 0x%8.8x", status)); + return status; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode, + DWORD dwPreferredProtocols, DWORD dwInitialization, + LPDWORD pdwActiveProtocol) +{ + LLOGLN(0, ("SCardReconnect:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardReconnect: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_lock(&g_mutex); + pthread_mutex_unlock(&g_mutex); + return SCARD_S_SUCCESS; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition) +{ + char msg[256]; + int code; + int bytes; + int status; + + LLOGLN(10, ("SCardDisconnect:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardDisconnect: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_lock(&g_mutex); + SET_UINT32(msg, 0, hCard); + SET_UINT32(msg, 4, dwDisposition); + if (send_message(SCARD_DISCONNECT, msg, 8) != 0) + { + LLOGLN(0, ("SCardDisconnect: error, send_message")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + bytes = 256; + if (get_message(&code, msg, &bytes) != 0) + { + LLOGLN(0, ("SCardDisconnect: error, get_message")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + if ((code != SCARD_DISCONNECT) || (bytes != 4)) + { + LLOGLN(0, ("SCardDisconnect: error, bad code")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_unlock(&g_mutex); + status = GET_UINT32(msg, 0); + LLOGLN(10, ("SCardDisconnect: got status 0x%8.8x", status)); + return status; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardBeginTransaction(SCARDHANDLE hCard) +{ + char msg[256]; + int code; + int bytes; + int status; + + LLOGLN(10, ("SCardBeginTransaction:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardBeginTransaction: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_lock(&g_mutex); + SET_UINT32(msg, 0, hCard); + if (send_message(SCARD_BEGIN_TRANSACTION, msg, 4) != 0) + { + LLOGLN(0, ("SCardBeginTransaction: error, send_message")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + bytes = 256; + if (get_message(&code, msg, &bytes) != 0) + { + LLOGLN(0, ("SCardBeginTransaction: error, get_message")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + if ((code != SCARD_BEGIN_TRANSACTION) || (bytes != 4)) + { + LLOGLN(0, ("SCardBeginTransaction: error, bad code")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_unlock(&g_mutex); + status = GET_UINT32(msg, 0); + LLOGLN(10, ("SCardBeginTransaction: got status 0x%8.8x", status)); + return status; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition) +{ + char msg[256]; + int code; + int bytes; + int status; + + LLOGLN(10, ("SCardEndTransaction:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardEndTransaction: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_lock(&g_mutex); + SET_UINT32(msg, 0, hCard); + SET_UINT32(msg, 4, dwDisposition); + if (send_message(SCARD_END_TRANSACTION, msg, 8) != 0) + { + LLOGLN(0, ("SCardEndTransaction: error, send_message")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + bytes = 256; + if (get_message(&code, msg, &bytes) != 0) + { + LLOGLN(0, ("SCardEndTransaction: error, get_message")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + if ((code != SCARD_END_TRANSACTION) || (bytes != 4)) + { + LLOGLN(0, ("SCardEndTransaction: error, bad code")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_unlock(&g_mutex); + status = GET_UINT32(msg, 0); + LLOGLN(10, ("SCardEndTransaction: got status 0x%8.8x", status)); + return status; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardStatus(SCARDHANDLE hCard, LPSTR mszReaderName, LPDWORD pcchReaderLen, + LPDWORD pdwState, LPDWORD pdwProtocol, LPBYTE pbAtr, + LPDWORD pcbAtrLen) +{ + char *msg; + int code; + int bytes; + int status; + int offset; + int cchReaderLen; + int to_copy; + + LLOGLN(10, ("SCardStatus:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardStatus: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + cchReaderLen = *pcchReaderLen; + msg = (char *) malloc(8192); + SET_UINT32(msg, 0, hCard); + SET_UINT32(msg, 4, cchReaderLen); + SET_UINT32(msg, 8, *pcbAtrLen); + pthread_mutex_lock(&g_mutex); + if (send_message(SCARD_STATUS, msg, 12) != 0) + { + LLOGLN(0, ("SCardStatus: error, send_message")); + free(msg); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + bytes = 8192; + if (get_message(&code, msg, &bytes) != 0) + { + LLOGLN(0, ("SCardStatus: error, get_message")); + free(msg); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + if (code != SCARD_STATUS) + { + LLOGLN(0, ("SCardStatus: error, bad code")); + free(msg); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_unlock(&g_mutex); + + LLOGLN(10, ("SCardStatus: cchReaderLen %d", *pcchReaderLen)); + offset = 0; + *pcchReaderLen = GET_UINT32(msg, offset); + LLOGLN(10, ("SCardStatus: cchReaderLen %d", *pcchReaderLen)); + offset += 4; + if (cchReaderLen > 0) + { + to_copy = cchReaderLen - 1; + if (*pcchReaderLen < to_copy) + { + to_copy = *pcchReaderLen; + } + memcpy(mszReaderName, msg + offset, to_copy); + mszReaderName[to_copy] = 0; + } + LLOGLN(10, ("SCardStatus: mszReaderName %s", mszReaderName)); + offset += *pcchReaderLen; + *pdwState = GET_UINT32(msg, offset); + LLOGLN(10, ("SCardStatus: dwState %d", *pdwState)); + offset += 4; + *pdwProtocol = GET_UINT32(msg, offset); + LLOGLN(10, ("SCardStatus: dwProtocol %d", *pdwProtocol)); + offset += 4; + *pcbAtrLen = GET_UINT32(msg, offset); + offset += 4; + LLOGLN(10, ("SCardStatus: cbAtrLen %d", *pcbAtrLen)); + memcpy(pbAtr, msg + offset, *pcbAtrLen); + offset += *pcbAtrLen; + status = GET_UINT32(msg, offset); + LLOGLN(10, ("SCardStatus: status %d", status)); + offset += 4; + free(msg); + return status; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout, + LPSCARD_READERSTATE rgReaderStates, DWORD cReaders) +{ + char *msg; + int bytes; + int code; + int index; + int offset; + int str_len; + int status; + + LLOGLN(10, ("SCardGetStatusChange:")); + LLOGLN(10, (" dwTimeout %d cReaders %d", dwTimeout, cReaders)); + if (g_sck == -1) + { + LLOGLN(0, ("SCardGetStatusChange: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + msg = (char *) malloc(8192); + SET_UINT32(msg, 0, hContext); + SET_UINT32(msg, 4, dwTimeout); + SET_UINT32(msg, 8, cReaders); + offset = 12; + for (index = 0; index < cReaders; index++) + { + str_len = strlen(rgReaderStates[index].szReader); + str_len = LMIN(str_len, 99); + memset(msg + offset, 0, 100); + memcpy(msg + offset, rgReaderStates[index].szReader, str_len); + offset += 100; + LLOGLN(10, (" in dwCurrentState %d", rgReaderStates[index].dwCurrentState)); + SET_UINT32(msg, offset, rgReaderStates[index].dwCurrentState); + offset += 4; + LLOGLN(10, (" in dwEventState %d", rgReaderStates[index].dwEventState)); + SET_UINT32(msg, offset, rgReaderStates[index].dwEventState); + offset += 4; + LLOGLN(10, (" in cbAtr %d", rgReaderStates[index].cbAtr)); + SET_UINT32(msg, offset, rgReaderStates[index].cbAtr); + offset += 4; + memset(msg + offset, 0, 36); + memcpy(msg + offset, rgReaderStates[index].rgbAtr, 33); + offset += 36; + } + pthread_mutex_lock(&g_mutex); + if (send_message(SCARD_GET_STATUS_CHANGE, msg, offset) != 0) + { + LLOGLN(0, ("SCardGetStatusChange: error, send_message")); + free(msg); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + bytes = 8192; + if (get_message(&code, msg, &bytes) != 0) + { + LLOGLN(0, ("SCardGetStatusChange: error, get_message")); + free(msg); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + if (code != SCARD_GET_STATUS_CHANGE) + { + LLOGLN(0, ("SCardGetStatusChange: error, bad code")); + free(msg); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_unlock(&g_mutex); + cReaders = GET_UINT32(msg, 0); + offset = 4; + LLOGLN(10, ("SCardGetStatusChange: got back cReaders %d", cReaders)); + for (index = 0; index < cReaders; index++) + { + rgReaderStates[index].dwCurrentState = GET_UINT32(msg, offset); + offset += 4; + LLOGLN(10, (" out dwCurrentState %d", rgReaderStates[index].dwCurrentState)); + rgReaderStates[index].dwEventState = GET_UINT32(msg, offset); + offset += 4; + LLOGLN(10, (" out dwEventState %d", rgReaderStates[index].dwEventState)); + rgReaderStates[index].cbAtr = GET_UINT32(msg, offset); + offset += 4; + LLOGLN(10, (" out cbAtr %d", rgReaderStates[index].cbAtr)); + memcpy(rgReaderStates[index].rgbAtr, msg + offset, 33); + offset += 36; + } + status = GET_UINT32(msg, offset); + offset += 4; + free(msg); + return status; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer, + DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength, + LPDWORD lpBytesReturned) +{ + char *msg; + int bytes; + int code; + int offset; + int status = 0; + + LLOGLN(10, ("SCardControl:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardControl: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + LLOGLN(10, ("SCardControl: dwControlCode 0x%8.8x", dwControlCode)); + LLOGLN(10, ("SCardControl: cbSendLength %d", cbSendLength)); + LLOGLN(10, ("SCardControl: cbRecvLength %d", cbRecvLength)); + + /* #define SCARD_CTL_CODE(code) (0x42000000 + (code)) + control_code = (control_code & 0x3ffc) >> 2; + control_code = SCARD_CTL_CODE(control_code); */ + + /* PCSC to Windows control code conversion */ + dwControlCode = dwControlCode - 0x42000000; + dwControlCode = dwControlCode << 2; + dwControlCode = dwControlCode | (49 << 16); + LLOGLN(10, ("SCardControl: dwControlCode 0x%8.8x", dwControlCode)); + + msg = (char *) malloc(8192); + offset = 0; + SET_UINT32(msg, offset, hCard); + offset += 4; + SET_UINT32(msg, offset, dwControlCode); + offset += 4; + SET_UINT32(msg, offset, cbSendLength); + offset += 4; + memcpy(msg + offset, pbSendBuffer, cbSendLength); + offset += cbSendLength; + SET_UINT32(msg, offset, cbRecvLength); + offset += 4; + pthread_mutex_lock(&g_mutex); + if (send_message(SCARD_CONTROL, msg, offset) != 0) + { + LLOGLN(0, ("SCardControl: error, send_message")); + free(msg); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + bytes = 8192; + if (get_message(&code, msg, &bytes) != 0) + { + LLOGLN(0, ("SCardControl: error, get_message")); + free(msg); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + if (code != SCARD_CONTROL) + { + LLOGLN(0, ("SCardControl: error, bad code")); + free(msg); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_unlock(&g_mutex); + offset = 0; + *lpBytesReturned = GET_UINT32(msg, offset); + offset += 4; + memcpy(pbRecvBuffer, msg + offset, *lpBytesReturned); + offset += *lpBytesReturned; + status = GET_UINT32(msg, offset); + free(msg); + return status; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci, + LPCBYTE pbSendBuffer, DWORD cbSendLength, + SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer, + LPDWORD pcbRecvLength) +{ + char *msg; + int bytes; + int code; + int offset; + int status; + int extra_len; + + LLOGLN(10, ("SCardTransmit:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardTransmit: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + LLOGLN(10, ("SCardTransmit: cbSendLength %d", cbSendLength)); + LLOGLN(10, ("SCardTransmit: pioRecvPci %p", pioRecvPci)); + if (pioRecvPci != 0) + { + LLOGLN(10, ("SCardTransmit: pioRecvPci->dwProtocol %d", + (int)pioRecvPci->dwProtocol)); + LLOGLN(10, ("SCardTransmit: pioRecvPci->cbPciLength %d", + (int)pioRecvPci->cbPciLength)); + } + msg = (char *) malloc(8192); + offset = 0; + SET_UINT32(msg, offset, hCard); + offset += 4; + SET_UINT32(msg, offset, pioSendPci->dwProtocol); + offset += 4; + SET_UINT32(msg, offset, pioSendPci->cbPciLength); + offset += 4; + extra_len = pioSendPci->cbPciLength - 8; + SET_UINT32(msg, offset, extra_len); + offset += 4; + memcpy(msg + offset, pioSendPci + 1, extra_len); + offset += extra_len; + SET_UINT32(msg, offset, cbSendLength); + offset += 4; + memcpy(msg + offset, pbSendBuffer, cbSendLength); + offset += cbSendLength; + if ((pioRecvPci == 0) || (pioRecvPci->cbPciLength < 8)) + { + SET_UINT32(msg, offset, 0); /* dwProtocol */ + offset += 4; + SET_UINT32(msg, offset, 0); /* cbPciLength */ + offset += 4; + SET_UINT32(msg, offset, 0); /* extra_len */ + offset += 4; + } + else + { + SET_UINT32(msg, offset, pioRecvPci->dwProtocol); + offset += 4; + SET_UINT32(msg, offset, pioRecvPci->cbPciLength); + offset += 4; + extra_len = pioRecvPci->cbPciLength - 8; + SET_UINT32(msg, offset, extra_len); + offset += 4; + memcpy(msg + offset, pioRecvPci + 1, extra_len); + offset += extra_len; + } + SET_UINT32(msg, offset, *pcbRecvLength); + offset += 4; + pthread_mutex_lock(&g_mutex); + if (send_message(SCARD_TRANSMIT, msg, offset) != 0) + { + LLOGLN(0, ("SCardTransmit: error, send_message")); + free(msg); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + bytes = 8192; + if (get_message(&code, msg, &bytes) != 0) + { + LLOGLN(0, ("SCardTransmit: error, get_message")); + free(msg); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + if (code != SCARD_TRANSMIT) + { + LLOGLN(0, ("SCardTransmit: error, bad code")); + free(msg); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_unlock(&g_mutex); + offset = 0; + if (pioRecvPci == 0) + { + offset += 8; + extra_len = GET_UINT32(msg, offset); + offset += 4; + offset += extra_len; + } + else + { + pioRecvPci->dwProtocol = GET_UINT32(msg, offset); + offset += 4; + pioRecvPci->cbPciLength = GET_UINT32(msg, offset); + offset += 4; + extra_len = GET_UINT32(msg, offset); + offset += 4; + offset += extra_len; + } + *pcbRecvLength = GET_UINT32(msg, offset); + offset += 4; + LLOGLN(10, ("SCardTransmit: cbRecvLength %d", *pcbRecvLength)); + memcpy(pbRecvBuffer, msg + offset, *pcbRecvLength); + offset += *pcbRecvLength; + status = GET_UINT32(msg, offset); + free(msg); + return status; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups, + LPDWORD pcchGroups) +{ + LLOGLN(10, ("SCardListReaderGroups:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardListReaderGroups: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_lock(&g_mutex); + pthread_mutex_unlock(&g_mutex); + return SCARD_S_SUCCESS; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardListReaders(SCARDCONTEXT hContext, LPCSTR mszGroups, LPSTR mszReaders, + LPDWORD pcchReaders) +{ + char* msg; + char* reader_names; + int reader_names_index; + int code; + int bytes; + int num_readers; + int status; + int offset; + int index; + char reader[100]; + + LLOGLN(10, ("SCardListReaders:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardListReaders: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + msg = (char *) malloc(8192); + pthread_mutex_lock(&g_mutex); + SET_UINT32(msg, 0, hContext); + if (send_message(SCARD_LIST_READERS, msg, 4) != 0) + { + LLOGLN(0, ("SCardListReaders: error, send_message")); + free(msg); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + bytes = 8192; + if (get_message(&code, msg, &bytes) != 0) + { + LLOGLN(0, ("SCardListReaders: error, get_message")); + free(msg); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + if (code != SCARD_LIST_READERS) + { + LLOGLN(0, ("SCardListReaders: error, bad code")); + free(msg); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_unlock(&g_mutex); + offset = 0; + num_readers = GET_UINT32(msg, offset); + offset += 4; + LLOGLN(10, ("SCardListReaders: mszReaders %p pcchReaders %p num_readers %d", + mszReaders, pcchReaders, num_readers)); + reader_names = (char *) malloc(8192); + reader_names_index = 0; + for (index = 0; index < num_readers; index++) + { + memcpy(reader, msg + offset, 100); + bytes = strlen(reader); + memcpy(reader_names + reader_names_index, reader, bytes); + reader_names_index += bytes; + reader_names[reader_names_index] = 0; + reader_names_index++; + offset += 100; + LLOGLN(10, ("SCardListReaders: readername %s", reader)); + } + reader_names[reader_names_index] = 0; + reader_names_index++; + status = GET_UINT32(msg, offset); + offset += 4; + if (pcchReaders != 0) + { + *pcchReaders = reader_names_index; + } + if (mszReaders != 0) + { + memcpy(mszReaders, reader_names, reader_names_index); + } + free(msg); + free(reader_names); + return status; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem) +{ + LLOGLN(0, ("SCardFreeMemory:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardFreeMemory: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_lock(&g_mutex); + pthread_mutex_unlock(&g_mutex); + return SCARD_S_SUCCESS; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardCancel(SCARDCONTEXT hContext) +{ + LLOGLN(0, ("SCardCancel:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardCancel: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_lock(&g_mutex); + pthread_mutex_unlock(&g_mutex); + return SCARD_S_SUCCESS; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr, + LPDWORD pcbAttrLen) +{ + LLOGLN(0, ("SCardGetAttrib:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardGetAttrib: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_lock(&g_mutex); + pthread_mutex_unlock(&g_mutex); + return SCARD_S_SUCCESS; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr, + DWORD cbAttrLen) +{ + LLOGLN(0, ("SCardSetAttrib:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardSetAttrib: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_lock(&g_mutex); + pthread_mutex_unlock(&g_mutex); + return SCARD_S_SUCCESS; +} + +/*****************************************************************************/ +PCSC_API char * +pcsc_stringify_error(const long code) +{ + LLOGLN(10, ("pcsc_stringify_error: %d", (int)code)); + switch (code) + { + case SCARD_S_SUCCESS: + snprintf(g_error_str, 511, "Command successful."); + break; + case SCARD_F_INTERNAL_ERROR: + snprintf(g_error_str, 511, "Internal error."); + break; + default: + snprintf(g_error_str, 511, "error 0x%8.8x", (int)code); + break; + } + g_error_str[511] = 0; + return g_error_str; +} diff --git a/sesman/chansrv/rail.c b/sesman/chansrv/rail.c index cfa3c5de..fb1075c6 100644 --- a/sesman/chansrv/rail.c +++ b/sesman/chansrv/rail.c @@ -19,15 +19,24 @@ /* window manager info http://www.freedesktop.org/wiki/Specifications/wm-spec + + rail + [MS-RDPERP]: Remote Desktop Protocol: + Remote Programs Virtual Channel Extension + http://msdn.microsoft.com/en-us/library/cc242568(v=prot.20).aspx */ #include <X11/Xlib.h> +#include <X11/Xatom.h> +#include <X11/extensions/Xrandr.h> +#include <X11/cursorfont.h> #include "chansrv.h" #include "rail.h" #include "xcommon.h" #include "log.h" #include "os_calls.h" #include "thread_calls.h" +#include "list.h" extern int g_rail_chan_id; /* in chansrv.c */ extern int g_display_num; /* in chansrv.c */ @@ -41,11 +50,43 @@ extern Screen *g_screen; /* in xcommon.c */ extern Window g_root_window; /* in xcommon.c */ extern Atom g_wm_delete_window_atom; /* in xcommon.c */ extern Atom g_wm_protocols_atom; /* in xcommon.c */ +extern Atom g_utf8_string; /* in xcommon.c */ +extern Atom g_net_wm_name; /* in xcommon.c */ +extern Atom g_wm_state; /* in xcommon.c */ + +static Atom g_rwd_atom = 0; int g_rail_up = 0; /* for rail_is_another_wm_running */ static int g_rail_running = 1; +/* list of valid rail windows */ +static struct list* g_window_list = 0; + +static int g_got_focus = 0; +static int g_focus_counter = 0; +static Window g_focus_win = 0; + +static int g_xrr_event_base = 0; /* non zero means we got extension */ + +static Cursor g_default_cursor = 0; + +/* used in valid field of struct rail_window_data */ +#define RWD_X (1 << 0) +#define RWD_Y (1 << 1) +#define RWD_WIDTH (1 << 2) +#define RWD_HEIGHT (1 << 3) +#define RWD_TITLE (1 << 4) + +struct rail_window_data +{ + int valid; /* bits for which fields are valid */ + int x; + int y; + int width; + int height; + int title_crc; /* crc of title for compare */ +}; /* Indicates a Client Execute PDU from client to server. */ #define TS_RAIL_ORDER_EXEC 0x0001 @@ -101,6 +142,133 @@ static int g_rail_running = 1; /* Perform the default action of the window's system menu. */ #define SC_DEFAULT 0xF160 +/* for tooltips */ +#define RAIL_STYLE_TOOLTIP (0x80000000) +#define RAIL_EXT_STYLE_TOOLTIP (0x00000080 | 0x00000008) + +/* for normal desktop windows */ +#define RAIL_STYLE_NORMAL (0x00C00000 | 0x00080000 | 0x00040000 | 0x00010000 | 0x00020000) +#define RAIL_EXT_STYLE_NORMAL (0x00040000) + +/* for dialogs */ +#define RAIL_STYLE_DIALOG (0x80000000) +#define RAIL_EXT_STYLE_DIALOG (0x00040000) + +static int APP_CC rail_win_get_state(Window win); +static int APP_CC rail_create_window(Window window_id, Window owner_id); +static int APP_CC rail_win_set_state(Window win, unsigned long state); +static int APP_CC rail_show_window(Window window_id, int show_state); +static int APP_CC rail_win_send_text(Window win); + +/*****************************************************************************/ +static int APP_CC +rail_send_key_esc(int window_id) +{ + XEvent event; + + g_memset(&event, 0, sizeof(event)); + event.type = KeyPress; + event.xkey.same_screen = True; + event.xkey.root = g_root_window; + event.xkey.window = window_id; + event.xkey.keycode = 9; + XSendEvent(g_display, window_id, True, 0xfff, &event); + event.type = KeyRelease; + XSendEvent(g_display, window_id, True, 0xfff, &event); + return 0; +} + +/*****************************************************************************/ +static struct rail_window_data* APP_CC +rail_get_window_data(Window window) +{ + int bytes; + Atom actual_type_return; + int actual_format_return; + unsigned long nitems_return; + unsigned long bytes_after_return; + unsigned char* prop_return; + struct rail_window_data* rv; + + LOG(10, ("chansrv::rail_get_window_data:")); + rv = 0; + actual_type_return = 0; + actual_format_return = 0; + nitems_return = 0; + prop_return = 0; + bytes = sizeof(struct rail_window_data); + XGetWindowProperty(g_display, window, g_rwd_atom, 0, bytes, 0, + XA_STRING, &actual_type_return, + &actual_format_return, &nitems_return, + &bytes_after_return, &prop_return); + if (prop_return == 0) + { + return 0; + } + if (nitems_return == bytes) + { + rv = (struct rail_window_data*)prop_return; + } + return rv; +} + +/*****************************************************************************/ +static int APP_CC +rail_set_window_data(Window window, struct rail_window_data* rwd) +{ + int bytes; + + bytes = sizeof(struct rail_window_data); + XChangeProperty(g_display, window, g_rwd_atom, XA_STRING, 8, + PropModeReplace, (unsigned char*)rwd, bytes); + return 0; +} + +/*****************************************************************************/ +/* get the rail window data, if not exist, try to create it and return */ +static struct rail_window_data* APP_CC +rail_get_window_data_safe(Window window) +{ + struct rail_window_data* rv; + + rv = rail_get_window_data(window); + if (rv != 0) + { + return rv; + } + rv = g_malloc(sizeof(struct rail_window_data), 1); + rail_set_window_data(window, rv); + g_free(rv); + return rail_get_window_data(window); +} + +/******************************************************************************/ +static int APP_CC +is_window_valid_child_of_root(unsigned int window_id) +{ + int found; + unsigned int i; + unsigned int nchild; + Window r; + Window p; + Window *children; + + found = 0; + XQueryTree(g_display, g_root_window, &r, &p, &children, &nchild); + + for (i = 0; i < nchild; i++) + { + if (window_id == children[i]) + { + found = 1; + break; + } + } + + XFree(children); + return found; +} + /*****************************************************************************/ static int APP_CC rail_send_init(void) @@ -163,6 +331,11 @@ rail_is_another_wm_running(void) int APP_CC rail_init(void) { + int dummy; + int ver_maj; + int ver_min; + Status st; + LOG(10, ("chansrv::rail_init:")); xcommon_init(); @@ -171,9 +344,34 @@ rail_init(void) log_message(LOG_LEVEL_ERROR, "rail_init: another window manager " "is running"); } - + list_delete(g_window_list); + g_window_list = list_create(); rail_send_init(); g_rail_up = 1; + g_rwd_atom = XInternAtom(g_display, "XRDP_RAIL_WINDOW_DATA", 0); + + if (!XRRQueryExtension(g_display, &g_xrr_event_base, &dummy)) + { + g_xrr_event_base = 0; + log_message(LOG_LEVEL_ERROR, "rail_init: RandR extension not found"); + } + + if (g_xrr_event_base > 0) + { + LOG(0, ("rail_init: found RandR entension")); + st = XRRQueryVersion(g_display, &ver_maj, &ver_min); + if (st) + { + LOG(0, ("rail_init: RandR version major %d minor %d", ver_maj, ver_min)); + } + XRRSelectInput(g_display, g_root_window, RRScreenChangeNotifyMask); + } + + if (g_default_cursor == 0) + { + g_default_cursor = XCreateFontCursor(g_display, XC_left_ptr); + XDefineCursor(g_display, g_root_window, g_default_cursor); + } return 0; } @@ -183,6 +381,8 @@ rail_deinit(void) { if (g_rail_up) { + list_delete(g_window_list); + g_window_list = 0; /* no longer window manager */ XSelectInput(g_display, g_root_window, 0); g_rail_up = 0; @@ -270,26 +470,173 @@ rail_process_exec(struct stream *s, int size) return 0; } +/******************************************************************************/ +static int APP_CC +rail_win_popdown(void) +{ + int rv = 0; + int i; + unsigned int nchild; + Window r; + Window p; + Window* children; + XWindowAttributes window_attributes; + + /* + * Check the tree of current existing X windows and dismiss + * the managed rail popups by simulating a esc key, so + * that the requested window can be closed properly. + */ + + XQueryTree(g_display, g_root_window, &r, &p, &children, &nchild); + for (i = nchild - 1; i >= 0; i--) + { + XGetWindowAttributes(g_display, children[i], &window_attributes); + if (window_attributes.override_redirect && + window_attributes.map_state == IsViewable && + list_index_of(g_window_list, children[i]) >= 0) + { + LOG(10, (" dismiss pop up 0x%8.8x", children[i])); + rail_send_key_esc(children[i]); + rv = 1; + } + } + + XFree(children); + return rv; +} + +/******************************************************************************/ +static int APP_CC +rail_close_window(int window_id) +{ + XEvent ce; + + LOG(0, ("chansrv::rail_close_window:")); + + rail_win_popdown(); + + g_memset(&ce, 0, sizeof(ce)); + ce.xclient.type = ClientMessage; + ce.xclient.message_type = g_wm_protocols_atom; + ce.xclient.display = g_display; + ce.xclient.window = window_id; + ce.xclient.format = 32; + ce.xclient.data.l[0] = g_wm_delete_window_atom; + ce.xclient.data.l[1] = CurrentTime; + XSendEvent(g_display, window_id, False, NoEventMask, &ce); + + return 0; +} + +/*****************************************************************************/ +void DEFAULT_CC +my_timoeut(void* data) +{ + LOG(10, ("my_timoeut: g_got_focus %d", g_got_focus)); + if (g_focus_counter == (int)(long)data) + { + LOG(10, ("my_timoeut: g_focus_counter %d", g_focus_counter)); + rail_win_popdown(); + } +} + /*****************************************************************************/ static int APP_CC rail_process_activate(struct stream *s, int size) { int window_id; int enabled; + int index; + XWindowAttributes window_attributes; + Window transient_for = 0; LOG(10, ("chansrv::rail_process_activate:")); in_uint32_le(s, window_id); in_uint8(s, enabled); + + index = list_index_of(g_window_list, window_id); + if (index < 0) + { + LOG(10, ("chansrv::rail_process_activate: window 0x%8.8x not in list", + window_id)); + return 0; + } + + g_focus_counter++; + g_got_focus = enabled; LOG(10, (" window_id 0x%8.8x enabled %d", window_id, enabled)); + XGetWindowAttributes(g_display, window_id, &window_attributes); + if (enabled) { + if (g_focus_win == window_id) + { + /* In case that window is unmapped upon minimization and not yet mapped*/ + XMapWindow(g_display, window_id); + } + else + { + rail_win_popdown(); + if (window_attributes.map_state != IsViewable) + { + /* In case that window is unmapped upon minimization and not yet mapped */ + XMapWindow(g_display, window_id); + } + XGetTransientForHint(g_display, window_id, &transient_for); + if (transient_for > 0) + { + /* Owner window should be raised up as well */ + XRaiseWindow(g_display, transient_for); + } + LOG(10, ("chansrv::rail_process_activate: calling XRaiseWindow 0x%8.8x", window_id)); + XRaiseWindow(g_display, window_id); + LOG(10, ("chansrv::rail_process_activate: calling XSetInputFocus 0x%8.8x", window_id)); + XSetInputFocus(g_display, window_id, RevertToParent, CurrentTime); + } LOG(10, ("chansrv::rail_process_activate: calling XRaiseWindow 0x%8.8x", window_id)); XRaiseWindow(g_display, window_id); LOG(10, ("chansrv::rail_process_activate: calling XSetInputFocus 0x%8.8x", window_id)); XSetInputFocus(g_display, window_id, RevertToParent, CurrentTime); + } else { + XWindowAttributes window_attributes; + XGetWindowAttributes(g_display, window_id, &window_attributes); + + LOG(10, (" window attributes: override_redirect %d", + window_attributes.override_redirect)); + add_timeout(200, my_timoeut, (void*)(long)g_focus_counter); } + return 0; +} +/*****************************************************************************/ +static int APP_CC +rail_restore_windows(void) +{ + unsigned int i; + unsigned int nchild; + Window r; + Window p; + Window* children; + + XQueryTree(g_display, g_root_window, &r, &p, &children, &nchild); + for (i = 0; i < nchild; i++) + { + XWindowAttributes window_attributes; + XGetWindowAttributes(g_display, children[i], &window_attributes); + if (!window_attributes.override_redirect) + { + if (window_attributes.map_state == IsViewable) + { + rail_win_set_state(children[i], 0x0); /* WithdrawnState */ + rail_create_window(children[i], g_root_window); + rail_win_set_state(children[i], 0x1); /* NormalState */ + rail_win_send_text(children[i]); + } + } + } + XFree(children); return 0; } @@ -302,25 +649,173 @@ rail_process_system_param(struct stream *s, int size) LOG(10, ("chansrv::rail_process_system_param:")); in_uint32_le(s, system_param); LOG(10, (" system_param 0x%8.8x", system_param)); + /* + * Ask client to re-create the existing rail windows. This is supposed + * to be done after handshake and client is initialised properly, we + * consider client is ready when it sends "SET_WORKAREA" sysparam. + */ + if (system_param == 0x0000002F) /*SPI_SET_WORK_AREA*/ + { + LOG(10, (" restore rail windows")); + rail_restore_windows(); + } + return 0; +} + +/*****************************************************************************/ +static int APP_CC +rail_get_property(Display* display, Window target, Atom type, Atom property, + unsigned char** data, unsigned long* count) +{ + Atom atom_return; + int size; + unsigned long nitems, bytes_left; + char* prop_name; + + int ret = XGetWindowProperty(display, target, property, + 0l, 1l, False, + type, &atom_return, &size, + &nitems, &bytes_left, data); + if ((ret != Success || nitems < 1) && atom_return == None) + { + prop_name = XGetAtomName(g_display, property); + LOG(10, (" rail_get_property %s: failed", prop_name)); + XFree(prop_name); + return 1; + } + + if (bytes_left != 0) + { + XFree(*data); + unsigned long remain = ((size / 8) * nitems) + bytes_left; + ret = XGetWindowProperty(g_display, target, + property, 0l, remain, False, + atom_return, &atom_return, &size, + &nitems, &bytes_left, data); + if (ret != Success) + { + return 1; + } + } + + *count = nitems; return 0; } +/*****************************************************************************/ +static int APP_CC +rail_win_get_state(Window win) +{ + unsigned long nitems = 0; + int rv = -1; + char* data = 0; + + rail_get_property(g_display, win, g_wm_state, g_wm_state, + (unsigned char **)&data, + &nitems); + + if (data || nitems > 0) + { + rv = *(unsigned long *)data; + XFree(data); + LOG(10, (" rail_win_get_state: %d", rv)); + } + + return rv; +} + +/*****************************************************************************/ +static int APP_CC +rail_win_set_state(Window win, unsigned long state) +{ + int old_state; + unsigned long data[2] = { state, None }; + + LOG(10, (" rail_win_set_state: %d", state)); + /* check whether WM_STATE exists */ + old_state = rail_win_get_state(win); + if (old_state == -1) + { + /* create WM_STATE property */ + XChangeProperty(g_display, win, g_wm_state, g_wm_state, 32, PropModeAppend, + (unsigned char *)data, 2); + LOG(10, (" rail_win_set_state: create WM_STATE property")); + } + else + { + XChangeProperty(g_display, win, g_wm_state, g_wm_state, 32, PropModeReplace, + (unsigned char *)data, 2); + } + return 0; +} + +/*****************************************************************************/ +static int APP_CC +rail_win_get_text(Window win, char **data) +{ + int ret = 0; + int i = 0; + unsigned long nitems = 0; + + ret = rail_get_property(g_display, win, g_utf8_string, g_net_wm_name, + (unsigned char **)data, &nitems); + if (ret != 0) + { + /* _NET_WM_NAME isn't set, use WM_NAME (XFetchName) instead */ + XFetchName(g_display, win, data); + } + + if (data) + { + char *ptr = *data; + for (; ptr != NULL; i++) + { + if (ptr[i] == '\0') + { + break; + } + } + } + + return i; +} + /******************************************************************************/ static int APP_CC -rail_close_window(int window_id) +rail_minmax_window(int window_id, int max) { - XEvent ce; + LOG(10, ("chansrv::rail_minmax_window 0x%8.8x:", window_id)); + if (max) + { + + } else { + XUnmapWindow(g_display, window_id); + /* change window state to IconicState (3) */ + rail_win_set_state(window_id, 0x3); + /* + * TODO dismiss popups opened so far + */ + } + return 0; +} - LOG(0, ("chansrv::rail_close_window:")); - g_memset(&ce, 0, sizeof(ce)); - ce.xclient.type = ClientMessage; - ce.xclient.message_type = g_wm_protocols_atom; - ce.xclient.display = g_display; - ce.xclient.window = window_id; - ce.xclient.format = 32; - ce.xclient.data.l[0] = g_wm_delete_window_atom; - ce.xclient.data.l[1] = CurrentTime; - XSendEvent(g_display, window_id, False, NoEventMask, &ce); +/*****************************************************************************/ +static int APP_CC +rail_restore_window(int window_id) +{ + XWindowAttributes window_attributes; + + LOG(10, ("chansrv::rail_restore_window 0x%8.8x:", window_id)); + XGetWindowAttributes(g_display, window_id, &window_attributes); + if (window_attributes.map_state != IsViewable) + { + XMapWindow(g_display, window_id); + } + LOG(10, ("chansrv::rail_process_activate: calling XRaiseWindow 0x%8.8x", window_id)); + XRaiseWindow(g_display, window_id); + LOG(10, ("chansrv::rail_process_activate: calling XSetInputFocus 0x%8.8x", window_id)); + XSetInputFocus(g_display, window_id, RevertToParent, CurrentTime); + return 0; } @@ -330,11 +825,20 @@ rail_process_system_command(struct stream *s, int size) { int window_id; int command; + int index; LOG(10, ("chansrv::rail_process_system_command:")); in_uint32_le(s, window_id); in_uint16_le(s, command); + index = list_index_of(g_window_list, window_id); + if (index < 0) + { + LOG(10, ("chansrv::rail_process_system_command: window 0x%8.8x not in list", + window_id)); + return 0; + } + switch (command) { case SC_SIZE: @@ -345,6 +849,7 @@ rail_process_system_command(struct stream *s, int size) break; case SC_MINIMIZE: LOG(10, (" window_id 0x%8.8x SC_MINIMIZE", window_id)); + rail_minmax_window(window_id, 0); break; case SC_MAXIMIZE: LOG(10, (" window_id 0x%8.8x SC_MAXIMIZE", window_id)); @@ -358,6 +863,7 @@ rail_process_system_command(struct stream *s, int size) break; case SC_RESTORE: LOG(10, (" window_id 0x%8.8x SC_RESTORE", window_id)); + rail_restore_window(window_id); break; case SC_DEFAULT: LOG(10, (" window_id 0x%8.8x SC_DEFAULT", window_id)); @@ -409,16 +915,30 @@ rail_process_window_move(struct stream *s, int size) int top; int right; int bottom; + tsi16 si16; + struct rail_window_data* rwd; LOG(10, ("chansrv::rail_process_window_move:")); in_uint32_le(s, window_id); - in_uint16_le(s, left); - in_uint16_le(s, top); - in_uint16_le(s, right); - in_uint16_le(s, bottom); + in_uint16_le(s, si16); + left = si16; + in_uint16_le(s, si16); + top = si16; + in_uint16_le(s, si16); + right = si16; + in_uint16_le(s, si16); + bottom = si16; LOG(10, (" window_id 0x%8.8x left %d top %d right %d bottom %d width %d height %d", window_id, left, top, right, bottom, right - left, bottom - top)); XMoveResizeWindow(g_display, window_id, left, top, right - left, bottom - top); + rwd = (struct rail_window_data*) + g_malloc(sizeof(struct rail_window_data), 1); + rwd->x = left; + rwd->y = top; + rwd->width = right - left; + rwd->height = bottom - top; + rail_set_window_data(window_id, rwd); + g_free(rwd); return 0; } @@ -431,13 +951,16 @@ rail_process_local_move_size(struct stream *s, int size) int move_size_type; int pos_x; int pos_y; + tsi16 si16; LOG(10, ("chansrv::rail_process_local_move_size:")); in_uint32_le(s, window_id); in_uint16_le(s, is_move_size_start); in_uint16_le(s, move_size_type); - in_uint16_le(s, pos_x); - in_uint16_le(s, pos_y); + in_uint16_le(s, si16); + pos_x = si16; + in_uint16_le(s, si16); + pos_y = si16; LOG(10, (" window_id 0x%8.8x is_move_size_start %d move_size_type %d " "pos_x %d pos_y %d", window_id, is_move_size_start, move_size_type, pos_x, pos_y)); @@ -472,11 +995,14 @@ rail_process_sys_menu(struct stream *s, int size) int window_id; int left; int top; + tsi16 si16; LOG(10, ("chansrv::rail_process_sys_menu:")); in_uint32_le(s, window_id); - in_uint16_le(s, left); - in_uint16_le(s, top); + in_uint16_le(s, si16); + left = si16; + in_uint16_le(s, si16); + top = si16; LOG(10, (" window_id 0x%8.8x left %d top %d", window_id, left, top)); return 0; } @@ -588,14 +1114,646 @@ rail_data_in(struct stream *s, int chan_id, int chan_flags, int length, return 0; } +static int g_crc_seed = 0xffffffff; +static int g_crc_table[256] = +{ + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +#define CRC_START(in_crc) (in_crc) = g_crc_seed +#define CRC_PASS(in_pixel, in_crc) \ + (in_crc) = g_crc_table[((in_crc) ^ (in_pixel)) & 0xff] ^ ((in_crc) >> 8) +#define CRC_END(in_crc) (in_crc) = ((in_crc) ^ g_crc_seed) + +/*****************************************************************************/ +static int +get_string_crc(const char* text) +{ + int index; + int crc; + + CRC_START(crc); + index = 0; + while (text[index] != 0) + { + CRC_PASS(text[index], crc); + index++; + } + CRC_END(crc); + return crc; +} + +/*****************************************************************************/ +/* returns 0, event handled, 1 unhandled */ +static int APP_CC +rail_win_send_text(Window win) +{ + char* data = 0; + struct stream* s; + int len = 0; + int flags; + int crc; + struct rail_window_data* rwd; + + len = rail_win_get_text(win, &data); + rwd = rail_get_window_data_safe(win); + if (rwd != 0) + { + if (data != 0) + { + if (rwd->valid & RWD_TITLE) + { + crc = get_string_crc(data); + if (rwd->title_crc == crc) + { + LOG(10, ("chansrv::rail_win_send_text: skipping, title not changed")); + XFree(data); + XFree(rwd); + return 0; + } + } + } + } + else + { + LOG(0, ("chansrv::rail_win_send_text: error rail_get_window_data_safe failed")); + return 1; + } + if (data && len > 0) { + LOG(10, ("chansrv::rail_win_send_text: 0x%8.8x text %s length %d", + win, data, len)); + make_stream(s); + init_stream(s, 1024); + flags = WINDOW_ORDER_TYPE_WINDOW | WINDOW_ORDER_FIELD_TITLE; + out_uint32_le(s, 8); /* update title info */ + out_uint32_le(s, win); /* window id */ + out_uint32_le(s, flags); /* flags */ + out_uint32_le(s, len); /* title size */ + out_uint8a(s, data, len); /* title */ + s_mark_end(s); + send_rail_drawing_orders(s->data, (int)(s->end - s->data)); + free_stream(s); + /* update rail window data */ + rwd->valid |= RWD_TITLE; + crc = get_string_crc(data); + rwd->title_crc = crc; + rail_set_window_data(win, rwd); + } + if (data != 0) + { + XFree(data); + } + XFree(rwd); + return 0; +} + +/*****************************************************************************/ +static int APP_CC +rail_destroy_window(Window window_id) +{ + struct stream *s; + + LOG(10, ("chansrv::rail_destroy_window 0x%8.8x", window_id)); + make_stream(s); + init_stream(s, 1024); + + out_uint32_le(s, 4); /* destroy_window */ + out_uint32_le(s, window_id); + s_mark_end(s); + send_rail_drawing_orders(s->data, (int)(s->end - s->data)); + free_stream(s); + + return 0; +} + +/*****************************************************************************/ +static int APP_CC +rail_show_window(Window window_id, int show_state) +{ + int flags; + struct stream* s; + + LOG(10, ("chansrv::rail_show_window 0x%8.8x 0x%x", window_id, show_state)); + make_stream(s); + init_stream(s, 1024); + + flags = WINDOW_ORDER_TYPE_WINDOW | WINDOW_ORDER_FIELD_SHOW; + out_uint32_le(s, 6); /* show_window */ + out_uint32_le(s, window_id); /* window_id */ + out_uint32_le(s, flags); /* flags */ + out_uint32_le(s, show_state); /* show_state */ + s_mark_end(s); + send_rail_drawing_orders(s->data, (int)(s->end - s->data)); + free_stream(s); + return 0; +} + +/*****************************************************************************/ +static int APP_CC +rail_create_window(Window window_id, Window owner_id) +{ + int x; + int y; + tui32 width; + tui32 height; + tui32 border; + Window root; + tui32 depth; + char* title_bytes = 0; + int title_size = 0; + XWindowAttributes attributes; + int style; + int ext_style; + int num_window_rects = 1; + int num_visibility_rects = 1; + int i = 0; + + int flags; + int index; + int crc; + Window transient_for = 0; + struct rail_window_data* rwd; + struct stream* s; + + LOG(10, ("chansrv::rail_create_window 0x%8.8x", window_id)); + + rwd = rail_get_window_data_safe(window_id); + if (rwd == 0) + { + LOG(0, ("chansrv::rail_create_window: error rail_get_window_data_safe failed")); + return 0; + } + XGetGeometry(g_display, window_id, &root, &x, &y, &width, &height, + &border, &depth); + XGetWindowAttributes(g_display, window_id, &attributes); + + LOG(10, (" x %d y %d width %d height %d border_width %d", x, y, width, + height, border)); + + index = list_index_of(g_window_list, window_id); + if (index == -1) + { + LOG(10, (" create new window")); + flags = WINDOW_ORDER_TYPE_WINDOW | WINDOW_ORDER_STATE_NEW; + list_add_item(g_window_list, window_id); + } + else + { + LOG(10, (" update existing window")); + flags = WINDOW_ORDER_TYPE_WINDOW; + } + + title_size = rail_win_get_text(window_id, &title_bytes); + + XGetTransientForHint(g_display, window_id, &transient_for); + + if (attributes.override_redirect) + { + style = RAIL_STYLE_TOOLTIP; + ext_style = RAIL_EXT_STYLE_TOOLTIP; + } + else if (transient_for > 0) + { + style = RAIL_STYLE_DIALOG; + ext_style = RAIL_EXT_STYLE_DIALOG; + owner_id = transient_for; + } + else + { + style = RAIL_STYLE_NORMAL; + ext_style = RAIL_EXT_STYLE_NORMAL; + } + + make_stream(s); + init_stream(s, 1024); + + out_uint32_le(s, 2); /* create_window */ + out_uint32_le(s, window_id); /* window_id */ + out_uint32_le(s, owner_id); /* owner_window_id */ + flags |= WINDOW_ORDER_FIELD_OWNER; + out_uint32_le(s, style); /* style */ + out_uint32_le(s, ext_style); /* extended_style */ + flags |= WINDOW_ORDER_FIELD_STYLE; + out_uint32_le(s, 0x05); /* show_state */ + flags |= WINDOW_ORDER_FIELD_SHOW; + if (title_size > 0) + { + out_uint16_le(s, title_size); /* title_size */ + out_uint8a(s, title_bytes, title_size); /* title */ + rwd->valid |= RWD_TITLE; + crc = get_string_crc(title_bytes); + rwd->title_crc = crc; + } + else + { + out_uint16_le(s, 5); /* title_size */ + out_uint8a(s, "title", 5); /* title */ + rwd->valid |= RWD_TITLE; + rwd->title_crc = 0; + } + LOG(10, (" set title info %d", title_size)); + flags |= WINDOW_ORDER_FIELD_TITLE; + out_uint32_le(s, 0); /* client_offset_x */ + out_uint32_le(s, 0); /* client_offset_y */ + flags |= WINDOW_ORDER_FIELD_CLIENT_AREA_OFFSET; + out_uint32_le(s, width); /* client_area_width */ + out_uint32_le(s, height); /* client_area_height */ + flags |= WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE; + out_uint32_le(s, 0); /* rp_content */ + out_uint32_le(s, g_root_window); /* root_parent_handle */ + flags |= WINDOW_ORDER_FIELD_ROOT_PARENT; + out_uint32_le(s, x); /* window_offset_x */ + out_uint32_le(s, y); /* window_offset_y */ + flags |= WINDOW_ORDER_FIELD_WND_OFFSET; + out_uint32_le(s, 0); /* window_client_delta_x */ + out_uint32_le(s, 0); /* window_client_delta_y */ + flags |= WINDOW_ORDER_FIELD_WND_CLIENT_DELTA; + out_uint32_le(s, width); /* window_width */ + out_uint32_le(s, height); /* window_height */ + flags |= WINDOW_ORDER_FIELD_WND_SIZE; + out_uint16_le(s, num_window_rects); /* num_window_rects */ + for (i = 0; i < num_window_rects; i++) + { + out_uint16_le(s, 0); /* left */ + out_uint16_le(s, 0); /* top */ + out_uint16_le(s, width); /* right */ + out_uint16_le(s, height); /* bottom */ + } + flags |= WINDOW_ORDER_FIELD_WND_RECTS; + out_uint32_le(s, x); /* visible_offset_x */ + out_uint32_le(s, y); /* visible_offset_y */ + flags |= WINDOW_ORDER_FIELD_VIS_OFFSET; + out_uint16_le(s, num_visibility_rects); /* num_visibility_rects */ + for (i = 0; i < num_visibility_rects; i++) + { + out_uint16_le(s, 0); /* left */ + out_uint16_le(s, 0); /* top */ + out_uint16_le(s, width); /* right */ + out_uint16_le(s, height); /* bottom */ + } + flags |= WINDOW_ORDER_FIELD_VISIBILITY; + out_uint32_le(s, flags); /*flags*/ + + s_mark_end(s); + send_rail_drawing_orders(s->data, (int)(s->end - s->data)); + free_stream(s); + XFree(title_bytes); + rail_set_window_data(window_id, rwd); + XFree(rwd); + return 0; +} + +/*****************************************************************************/ +/* returns 0, event handled, 1 unhandled */ +int APP_CC +rail_configure_request_window(XConfigureRequestEvent* config) +{ + int num_window_rects = 1; + int num_visibility_rects = 1; + int i = 0; + int flags; + int index; + int window_id; + int mask; + int resized = 0; + struct rail_window_data* rwd; + + struct stream* s; + + window_id = config->window; + mask = config->value_mask; + LOG(10, ("chansrv::rail_configure_request_window: mask %d", mask)); + if (mask & CWStackMode) + { + LOG(10, ("chansrv::rail_configure_request_window: CWStackMode " + "detail 0x%8.8x above 0x%8.8x", config->detail, config->above)); + if (config->detail == Above) + { + LOG(10, ("chansrv::rail_configure_request_window: bring to front " + "window_id 0x%8.8x", window_id)); + /* 0x05 - Show the window in its current size and position. */ + rail_show_window(window_id, 5); + } + } + rwd = rail_get_window_data(window_id); + if (rwd == 0) + { + rwd = (struct rail_window_data*)g_malloc(sizeof(struct rail_window_data), 1); + rwd->x = config->x; + rwd->y = config->y; + rwd->width = config->width; + rwd->height = config->height; + rwd->valid |= RWD_X | RWD_Y | RWD_WIDTH | RWD_HEIGHT; + rail_set_window_data(window_id, rwd); + g_free(rwd); + return 0; + } + if (!resized) + { + if (mask & CWX) + { + if (rwd->valid & RWD_X) + { + if (rwd->x != config->x) + { + resized = 1; + rwd->x = config->x; + } + } + else + { + resized = 1; + rwd->x = config->x; + rwd->valid |= RWD_X; + } + } + } + if (!resized) + { + if (mask & CWY) + { + if (rwd->valid & RWD_Y) + { + if (rwd->y != config->y) + { + resized = 1; + rwd->y = config->y; + } + } + else + { + resized = 1; + rwd->y = config->y; + rwd->valid |= RWD_Y; + } + } + } + if (!resized) + { + if (mask & CWWidth) + { + if (rwd->valid & RWD_WIDTH) + { + if (rwd->width != config->width) + { + resized = 1; + rwd->width = config->width; + } + } + else + { + resized = 1; + rwd->width = config->width; + rwd->valid |= RWD_WIDTH; + } + } + } + if (!resized) + { + if (mask & CWHeight) + { + if (rwd->valid & RWD_HEIGHT) + { + if (rwd->height != config->height) + { + resized = 1; + rwd->height = config->height; + } + } + else + { + resized = 1; + rwd->height = config->height; + rwd->valid |= RWD_HEIGHT; + } + } + } + if (resized) + { + rail_set_window_data(window_id, rwd); + XFree(rwd); + } + else + { + XFree(rwd); + return 0; + } + + LOG(10, ("chansrv::rail_configure_request_window: 0x%8.8x", window_id)); + + + LOG(10, (" x %d y %d width %d height %d border_width %d", config->x, + config->y, config->width, config->height, config->border_width)); + + index = list_index_of(g_window_list, window_id); + if (index == -1) + { + /* window isn't mapped yet */ + LOG(0, ("chansrv::rail_configure_request_window: window not mapped")); + return 0; + } + + flags = WINDOW_ORDER_TYPE_WINDOW; + + make_stream(s); + init_stream(s, 1024); + + out_uint32_le(s, 10); /* configure_window */ + out_uint32_le(s, window_id); /* window_id */ + + out_uint32_le(s, 0); /* client_offset_x */ + out_uint32_le(s, 0); /* client_offset_y */ + flags |= WINDOW_ORDER_FIELD_CLIENT_AREA_OFFSET; + out_uint32_le(s, config->width); /* client_area_width */ + out_uint32_le(s, config->height); /* client_area_height */ + flags |= WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE; + out_uint32_le(s, 0); /* rp_content */ + out_uint32_le(s, g_root_window); /* root_parent_handle */ + flags |= WINDOW_ORDER_FIELD_ROOT_PARENT; + out_uint32_le(s, config->x); /* window_offset_x */ + out_uint32_le(s, config->y); /* window_offset_y */ + flags |= WINDOW_ORDER_FIELD_WND_OFFSET; + out_uint32_le(s, 0); /* window_client_delta_x */ + out_uint32_le(s, 0); /* window_client_delta_y */ + flags |= WINDOW_ORDER_FIELD_WND_CLIENT_DELTA; + out_uint32_le(s, config->width); /* window_width */ + out_uint32_le(s, config->height); /* window_height */ + flags |= WINDOW_ORDER_FIELD_WND_SIZE; + out_uint16_le(s, num_window_rects); /* num_window_rects */ + for (i = 0; i < num_window_rects; i++) + { + out_uint16_le(s, 0); /* left */ + out_uint16_le(s, 0); /* top */ + out_uint16_le(s, config->width); /* right */ + out_uint16_le(s, config->height); /* bottom */ + } + flags |= WINDOW_ORDER_FIELD_WND_RECTS; + out_uint32_le(s, config->x); /* visible_offset_x */ + out_uint32_le(s, config->y); /* visible_offset_y */ + flags |= WINDOW_ORDER_FIELD_VIS_OFFSET; + out_uint16_le(s, num_visibility_rects); /* num_visibility_rects */ + for (i = 0; i < num_visibility_rects; i++) + { + out_uint16_le(s, 0); /* left */ + out_uint16_le(s, 0); /* top */ + out_uint16_le(s, config->width); /* right */ + out_uint16_le(s, config->height); /* bottom */ + } + flags |= WINDOW_ORDER_FIELD_VISIBILITY; + out_uint32_le(s, flags); /*flags*/ + + s_mark_end(s); + send_rail_drawing_orders(s->data, (int)(s->end - s->data)); + free_stream(s); + return 0; +} + +/*****************************************************************************/ +/* returns 0, event handled, 1 unhandled */ +int APP_CC +rail_configure_window(XConfigureEvent *config) +{ + int num_window_rects = 1; + int num_visibility_rects = 1; + int i = 0; + int flags; + int index; + int window_id; + + struct stream* s; + + window_id = config->window; + + LOG(10, ("chansrv::rail_configure_window 0x%8.8x", window_id)); + + + LOG(10, (" x %d y %d width %d height %d border_width %d", config->x, + config->y, config->width, config->height, config->border_width)); + + index = list_index_of(g_window_list, window_id); + if (index == -1) + { + /* window isn't mapped yet */ + return 0; + } + + flags = WINDOW_ORDER_TYPE_WINDOW; + + make_stream(s); + init_stream(s, 1024); + + out_uint32_le(s, 10); /* configure_window */ + out_uint32_le(s, window_id); /* window_id */ + + out_uint32_le(s, 0); /* client_offset_x */ + out_uint32_le(s, 0); /* client_offset_y */ + flags |= WINDOW_ORDER_FIELD_CLIENT_AREA_OFFSET; + out_uint32_le(s, config->width); /* client_area_width */ + out_uint32_le(s, config->height); /* client_area_height */ + flags |= WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE; + out_uint32_le(s, 0); /* rp_content */ + out_uint32_le(s, g_root_window); /* root_parent_handle */ + flags |= WINDOW_ORDER_FIELD_ROOT_PARENT; + out_uint32_le(s, config->x); /* window_offset_x */ + out_uint32_le(s, config->y); /* window_offset_y */ + flags |= WINDOW_ORDER_FIELD_WND_OFFSET; + out_uint32_le(s, 0); /* window_client_delta_x */ + out_uint32_le(s, 0); /* window_client_delta_y */ + flags |= WINDOW_ORDER_FIELD_WND_CLIENT_DELTA; + out_uint32_le(s, config->width); /* window_width */ + out_uint32_le(s, config->height); /* window_height */ + flags |= WINDOW_ORDER_FIELD_WND_SIZE; + out_uint16_le(s, num_window_rects); /* num_window_rects */ + for (i = 0; i < num_window_rects; i++) + { + out_uint16_le(s, 0); /* left */ + out_uint16_le(s, 0); /* top */ + out_uint16_le(s, config->width); /* right */ + out_uint16_le(s, config->height); /* bottom */ + } + flags |= WINDOW_ORDER_FIELD_WND_RECTS; + out_uint32_le(s, config->x); /* visible_offset_x */ + out_uint32_le(s, config->y); /* visible_offset_y */ + flags |= WINDOW_ORDER_FIELD_VIS_OFFSET; + out_uint16_le(s, num_visibility_rects); /* num_visibility_rects */ + for (i = 0; i < num_visibility_rects; i++) + { + out_uint16_le(s, 0); /* left */ + out_uint16_le(s, 0); /* top */ + out_uint16_le(s, config->width); /* right */ + out_uint16_le(s, config->height); /* bottom */ + } + flags |= WINDOW_ORDER_FIELD_VISIBILITY; + out_uint32_le(s, flags); /*flags*/ + + s_mark_end(s); + send_rail_drawing_orders(s->data, (int)(s->end - s->data)); + free_stream(s); + return 0; +} + +/*****************************************************************************/ +static int +rail_desktop_resize(lxevent) +{ + LOG(0, ("rail_desktop_resize:")); + return 0; +} + /*****************************************************************************/ /* returns 0, event handled, 1 unhandled */ int APP_CC rail_xevent(void *xevent) { XEvent *lxevent; + XEvent lastevent; XWindowChanges xwc; int rv; + int index; + XWindowAttributes wnd_attributes; + char* prop_name; LOG(10, ("chansrv::rail_xevent:")); @@ -609,6 +1767,30 @@ rail_xevent(void *xevent) switch (lxevent->type) { + case PropertyNotify: + prop_name = XGetAtomName(g_display, lxevent->xproperty.atom); + LOG(10, (" got PropertyNotify window_id 0x%8.8x %s state new %d", + lxevent->xproperty.window, prop_name, + lxevent->xproperty.state == PropertyNewValue)); + + if (list_index_of(g_window_list, lxevent->xproperty.window) < 0) + { + break; + } + + if (g_strcmp(prop_name, "WM_NAME") == 0 || + g_strcmp(prop_name, "_NET_WM_NAME") == 0) + { + XGetWindowAttributes(g_display, lxevent->xproperty.window, &wnd_attributes); + if (wnd_attributes.map_state == IsViewable) + { + rail_win_send_text(lxevent->xproperty.window); + rv = 0; + } + } + XFree(prop_name); + break; + case ConfigureRequest: LOG(10, (" got ConfigureRequest window_id 0x%8.8x", lxevent->xconfigurerequest.window)); g_memset(&xwc, 0, sizeof(xwc)); @@ -623,31 +1805,118 @@ rail_xevent(void *xevent) lxevent->xconfigurerequest.window, lxevent->xconfigurerequest.value_mask, &xwc); + rail_configure_request_window(&(lxevent->xconfigurerequest)); rv = 0; break; + case CreateNotify: + LOG(10, (" got CreateNotify window 0x%8.8x parent 0x%8.8x", + lxevent->xcreatewindow.window, lxevent->xcreatewindow.parent)); + XSelectInput(g_display, lxevent->xcreatewindow.window, + PropertyChangeMask | StructureNotifyMask | + SubstructureNotifyMask | FocusChangeMask | + EnterWindowMask | LeaveWindowMask); + break; + + case DestroyNotify: + LOG(10, (" got DestroyNotify window 0x%8.8x event 0x%8.8x", + lxevent->xdestroywindow.window, lxevent->xdestroywindow.event)); + if (lxevent->xdestroywindow.window != lxevent->xdestroywindow.event) + { + break; + } + index = list_index_of(g_window_list, lxevent->xdestroywindow.window); + if (index >= 0) + { + rail_destroy_window(lxevent->xdestroywindow.window); + list_remove_item(g_window_list, index); + } + rv = 0; + break; + case MapRequest: - LOG(10, (" got MapRequest")); + LOG(10, (" got MapRequest window 0x%8.8x", lxevent->xmaprequest.window)); XMapWindow(g_display, lxevent->xmaprequest.window); - rv = 0; break; case MapNotify: - LOG(10, (" got MapNotify")); + LOG(10, (" got MapNotify window 0x%8.8x event 0x%8.8x", + lxevent->xmap.window, lxevent->xmap.event)); + if (lxevent->xmap.window != lxevent->xmap.event) + { + break; + } + + if (!is_window_valid_child_of_root(lxevent->xmap.window)) + { + break; + } + + XGetWindowAttributes(g_display, lxevent->xmap.window, &wnd_attributes); + if (wnd_attributes.map_state == IsViewable) + { + rail_create_window(lxevent->xmap.window, lxevent->xmap.event); + if (!wnd_attributes.override_redirect) + { + rail_win_set_state(lxevent->xmap.window, 0x1); /* NormalState */ + rail_win_send_text(lxevent->xmap.window); + } + rv = 0; + } break; case UnmapNotify: - LOG(10, (" got UnmapNotify")); + LOG(10, (" got UnmapNotify 0x%8.8x", lxevent->xunmap.event)); + if (lxevent->xunmap.window != lxevent->xunmap.event) + { + break; + } + if (is_window_valid_child_of_root(lxevent->xunmap.window)) + { + index = list_index_of(g_window_list, lxevent->xunmap.window); + LOG(10, (" window 0x%8.8x is unmapped", lxevent->xunmap.window)); + if (index >= 0) + { + rail_show_window(lxevent->xunmap.window, 0x0); + rv = 0; + } + } break; case ConfigureNotify: - LOG(10, (" got ConfigureNotify")); + LOG(10, (" got ConfigureNotify 0x%8.8x event 0x%8.8x", lxevent->xconfigure.window, + lxevent->xconfigure.event)); + rv = 0; + if (lxevent->xconfigure.event != lxevent->xconfigure.window || + lxevent->xconfigure.override_redirect) + { + break; + } + /* skip dup ConfigureNotify */ + while (XCheckTypedWindowEvent(g_display, + lxevent->xconfigure.window, + ConfigureNotify, &lastevent)) + { + if (lastevent.xconfigure.event == lastevent.xconfigure.window && + lxevent->xconfigure.override_redirect == 0) + { + lxevent = &lastevent; + } + } +#if 0 + rail_configure_window(&(lxevent->xconfigure)); +#endif break; case FocusIn: LOG(10, (" got FocusIn")); + g_focus_win = lxevent->xfocus.window; break; + case FocusOut: + LOG(10, (" got FocusOut")); + break; + case ButtonPress: LOG(10, (" got ButtonPress")); break; @@ -660,6 +1929,39 @@ rail_xevent(void *xevent) LOG(10, (" got LeaveNotify")); break; + case ReparentNotify: + LOG(10, (" got ReparentNotify window 0x%8.8x parent 0x%8.8x " + "event 0x%8.8x x %d y %d overrider redirect %d", + lxevent->xreparent.window, lxevent->xreparent.parent, + lxevent->xreparent.event, lxevent->xreparent.x, + lxevent->xreparent.y, lxevent->xreparent.override_redirect)); + + if (lxevent->xreparent.window != lxevent->xreparent.event) + { + break; + } + if (lxevent->xreparent.parent != g_root_window) + { + index = list_index_of(g_window_list, lxevent->xreparent.window); + if (index >= 0) + { + rail_destroy_window(lxevent->xreparent.window); + list_remove_item(g_window_list, index); + } + } + rv = 0; + break; + + default: + if (g_xrr_event_base > 0) + { + if (lxevent->type == g_xrr_event_base + RRScreenChangeNotify) + { + rail_desktop_resize(lxevent); + rv = 0; + break; + } + } } return rv; diff --git a/sesman/chansrv/rail.h b/sesman/chansrv/rail.h index 7dbcbc5a..3be3a15d 100644 --- a/sesman/chansrv/rail.h +++ b/sesman/chansrv/rail.h @@ -19,6 +19,7 @@ #ifndef _RAIL_H_ #define _RAIL_H_ +#include "../../common/rail.h" #include "arch.h" #include "parse.h" @@ -31,5 +32,6 @@ rail_data_in(struct stream* s, int chan_id, int chan_flags, int length, int total_length); int APP_CC rail_xevent(void* xevent); +int APP_CC rail_request_title(int window_id); #endif diff --git a/sesman/chansrv/smartcard.c b/sesman/chansrv/smartcard.c index c370479e..29406d62 100644 --- a/sesman/chansrv/smartcard.c +++ b/sesman/chansrv/smartcard.c @@ -21,6 +21,7 @@ * smartcard redirection support */ +#include <string.h> #include "os_calls.h" #include "smartcard.h" #include "log.h" @@ -31,6 +32,8 @@ /* * TODO * + * o ensure that all wide calls are handled correctly + * * o need to query client for build number and determine whether we should use * SCREDIR_VERSION_XP or SCREDIR_VERSION_LONGHORN * @@ -56,17 +59,19 @@ #define LOG_DEBUG 2 #ifndef LOG_LEVEL -#define LOG_LEVEL LOG_DEBUG +#define LOG_LEVEL LOG_INFO #endif #define log_error(_params...) \ +do \ { \ g_write("[%10.10u]: SMART_CARD %s: %d : ERROR: ", \ g_time3(), __func__, __LINE__); \ g_writeln (_params); \ -} +} while (0) #define log_info(_params...) \ +do \ { \ if (LOG_INFO <= LOG_LEVEL) \ { \ @@ -74,9 +79,10 @@ g_time3(), __func__, __LINE__); \ g_writeln (_params); \ } \ -} +} while (0) #define log_debug(_params...) \ +do \ { \ if (LOG_DEBUG <= LOG_LEVEL) \ { \ @@ -84,7 +90,7 @@ g_time3(), __func__, __LINE__); \ g_writeln (_params); \ } \ -} +} while (0) /* [MS-RDPESC] 3.1.4 */ #define SCARD_IOCTL_ESTABLISH_CONTEXT 0x00090014 /* EstablishContext */ @@ -98,16 +104,19 @@ #define SCARD_IOCTL_INTRODUCE_READER 0x00090060 /* IntroduceReader */ #define SCARD_IOCTL_FORGET_READER 0x00090068 /* IntroduceReader */ #define SCARD_IOCTL_ADD_READER_TO_GROUP 0x00090070 /* AddReaderToGroup */ -#define SCARD_IOCTL_REMOVE_READER_FROM_GROUP 0x00090078 /* RemoveReaderFromGroup */ -#define SCARD_IOCTL_GET_STATUS_CHANGE 0x000900A0 /* GetStatusChangeA */ +#define SCARD_IOCTL_REMOVE_READER_FROM_GROUP 0x00090078 /* RemoveReaderFromGroup*/ +#define SCARD_IOCTL_GET_STATUS_CHANGE_A 0x000900A0 /* GetStatusChangeA */ +#define SCARD_IOCTL_GET_STATUS_CHANGE_W 0x000900A4 /* GetStatusChangeW */ #define SCARD_IOCTL_CANCEL 0x000900A8 /* Cancel */ -#define SCARD_IOCTL_CONNECT 0x000900AC /* ConnectA */ +#define SCARD_IOCTL_CONNECT_A 0x000900AC /* ConnectA */ +#define SCARD_IOCTL_CONNECT_W 0x000900B0 /* ConnectW */ #define SCARD_IOCTL_RECONNECT 0x000900B4 /* Reconnect */ #define SCARD_IOCTL_DISCONNECT 0x000900B8 /* Disconnect */ #define SCARD_IOCTL_BEGIN_TRANSACTION 0x000900BC /* BeginTransaction */ #define SCARD_IOCTL_END_TRANSACTION 0x000900C0 /* EndTransaction */ #define SCARD_IOCTL_STATE 0x000900C4 /* State */ -#define SCARD_IOCTL_STATUS 0x000900C8 /* StatusA */ +#define SCARD_IOCTL_STATUS_A 0x000900C8 /* StatusA */ +#define SCARD_IOCTL_STATUS_W 0x000900CC /* StatusW */ #define SCARD_IOCTL_TRANSMIT 0x000900D0 /* Transmit */ #define SCARD_IOCTL_CONTROL 0x000900D4 /* Control */ #define SCARD_IOCTL_GETATTRIB 0x000900D8 /* GetAttrib */ @@ -120,191 +129,818 @@ #define SCARD_SCOPE_TERMINAL 0x00000001 #define SCARD_SCOPE_SYSTEM 0x00000002 +/* disposition - action to take on card */ +#define SCARD_LEAVE_CARD 0x00000000 +#define SCARD_RESET_CARD 0x00000001 +#define SCARD_UNPOWER_CARD 0x00000002 +#define SCARD_EJECT_CARD 0x00000003 + #define MAX_SMARTCARDS 16 /* stores info about a smart card */ typedef struct smartcard { tui32 DeviceId; - char Context[16]; /* opaque context; save as passed to us */ - int Context_len; /* Context len in bytes */ } SMARTCARD; -SMARTCARD *smartcards[MAX_SMARTCARDS]; -int g_smartcards_inited = 0; +/* globals */ +SMARTCARD* smartcards[MAX_SMARTCARDS]; +int g_smartcards_inited = 0; +static tui32 g_device_id = 0; +static int g_scard_index = 0; +/* externs */ extern tui32 g_completion_id; -extern int g_rdpdr_chan_id; /* in chansrv.c */ +extern int g_rdpdr_chan_id; /* in chansrv.c */ + + +/****************************************************************************** +** static functions local to this file ** +******************************************************************************/ +static struct stream * APP_CC scard_make_new_ioctl(IRP *irp, tui32 ioctl); +static int APP_CC scard_add_new_device(tui32 device_id); +static int APP_CC scard_get_free_slot(void); +#if 0 +static void APP_CC scard_release_resources(void); +#endif +static void APP_CC scard_send_EstablishContext(IRP* irp, int scope); +static void APP_CC scard_send_ReleaseContext(IRP* irp, tui32 context); +static void APP_CC scard_send_IsContextValid(IRP* irp, tui32 context); +static void APP_CC scard_send_ListReaders(IRP* irp, tui32 context, int wide); +static void APP_CC scard_send_GetStatusChange(IRP* irp, tui32 context, int wide, + tui32 timeout, tui32 num_readers, + READER_STATE* rsa); +static void APP_CC scard_send_Connect(IRP* irp, tui32 context, int wide, + READER_STATE* rs); +static void APP_CC scard_send_Reconnect(IRP* irp, tui32 context, + tui32 sc_handle, READER_STATE* rs); +static void APP_CC scard_send_BeginTransaction(IRP* irp, tui32 sc_handle); +static void APP_CC scard_send_EndTransaction(IRP* irp, tui32 sc_handle, + tui32 dwDisposition); +static void APP_CC scard_send_Status(IRP* irp, int wide, tui32 sc_handle, + int cchReaderLen, int cbAtrLen); +static void APP_CC scard_send_Disconnect(IRP* irp, tui32 context, + tui32 sc_handle, int dwDisposition); +static int APP_CC scard_send_Transmit(IRP* irp, tui32 sc_handle, + char *send_data, int send_bytes, + int recv_bytes, + struct xrdp_scard_io_request *send_ior, + struct xrdp_scard_io_request *recv_ior); +static int APP_CC scard_send_Control(IRP* irp, tui32 context, tui32 sc_handle, + char *send_data, int send_bytes, + int recv_bytes, int control_code); +static int APP_CC scard_send_Cancel(IRP* irp, tui32 context); +static int APP_CC scard_send_GetAttrib(IRP* irp, tui32 sc_handle, + READER_STATE* rs); + +/****************************************************************************** +** local callbacks into this module ** +******************************************************************************/ + +static void APP_CC scard_handle_EstablishContext_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus); + +static void APP_CC scard_handle_ReleaseContext_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus); + + +static void APP_CC scard_handle_IsContextValid_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus); + +static void APP_CC scard_handle_ListReaders_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus); + +static void APP_CC scard_handle_GetStatusChange_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus); + +static void APP_CC scard_handle_Connect_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus); -/* forward declarations specific to this file */ -static void scard_send_EstablishContext(IRP *irp); -static void scard_send_ListReaders(IRP *irp, int wide); -static struct stream *scard_make_new_ioctl(IRP *irp, tui32 ioctl); -static int scard_add_new_device(tui32 device_id); -static int scard_get_free_slot(void); -static void scard_release_resources(void); +static void APP_CC scard_handle_Reconnect_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus); + +static void APP_CC scard_handle_BeginTransaction_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus); + +static void APP_CC scard_handle_EndTransaction_Return(struct stream *s, IRP *irp, + tui32 DeviceId, + tui32 CompletionId, + tui32 IoStatus); + +static void APP_CC scard_handle_Status_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus); + +static void APP_CC scard_handle_Disconnect_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus); + + +static void APP_CC scard_handle_Transmit_Return(struct stream *s, IRP *irp, + tui32 DeviceId, + tui32 CompletionId, + tui32 IoStatus); + +static void APP_CC scard_handle_Control_Return(struct stream *s, IRP *irp, + tui32 DeviceId, + tui32 CompletionId, + tui32 IoStatus); + +static void APP_CC scard_handle_Cancel_Return(struct stream *s, IRP *irp, + tui32 DeviceId, + tui32 CompletionId, + tui32 IoStatus); + +static void APP_CC scard_handle_GetAttrib_Return(struct stream *s, IRP *irp, + tui32 DeviceId, + tui32 CompletionId, + tui32 IoStatus); /****************************************************************************** -** non static functions ** +** ** +** externally accessible functions, defined in smartcard.h ** +** ** ******************************************************************************/ +/** + *****************************************************************************/ void APP_CC scard_device_announce(tui32 device_id) { + log_debug("entered: device_id=%d", device_id); + + if (g_smartcards_inited) + return; + + g_memset(&smartcards, 0, sizeof(smartcards)); + g_smartcards_inited = 1; + g_device_id = device_id; + g_scard_index = scard_add_new_device(device_id); + + if (g_scard_index < 0) + log_debug("scard_add_new_device failed with DeviceId=%d", g_device_id); + else + log_debug("added smartcard with DeviceId=%d to list", g_device_id); +} + +/** + * + *****************************************************************************/ +int APP_CC +scard_get_wait_objs(tbus *objs, int *count, int *timeout) +{ + return scard_pcsc_get_wait_objs(objs, count, timeout); +} + +/** + * + *****************************************************************************/ +int APP_CC +scard_check_wait_objs(void) +{ + return scard_pcsc_check_wait_objs(); +} + +/** + * + *****************************************************************************/ +int APP_CC +scard_init(void) +{ + log_debug("init"); + return scard_pcsc_init(); +} + +/** + * + *****************************************************************************/ +int APP_CC +scard_deinit(void) +{ + log_debug("deinit"); + return scard_pcsc_deinit(); +} + +/** + * + *****************************************************************************/ +int APP_CC +scard_send_establish_context(struct trans *con, int scope) +{ IRP *irp; - log_debug("entered: device_id=%d", device_id); + /* setup up IRP */ + if ((irp = devredir_irp_new()) == NULL) + { + log_error("system out of memory"); + return 1; + } + + irp->scard_index = g_scard_index; + irp->CompletionId = g_completion_id++; + irp->DeviceId = g_device_id; + irp->callback = scard_handle_EstablishContext_Return; + irp->user_data = con; + + /* send IRP to client */ + scard_send_EstablishContext(irp, scope); - if (!g_smartcards_inited) + return 0; +} + +/** + * Release a previously established Smart Card context + *****************************************************************************/ +int APP_CC +scard_send_release_context(struct trans *con, tui32 context) +{ + IRP *irp; + + /* setup up IRP */ + if ((irp = devredir_irp_new()) == NULL) { - g_memset(&smartcards, 0, sizeof(smartcards)); - g_smartcards_inited = 1; + log_error("system out of memory"); + return 1; } + irp->scard_index = g_scard_index; + irp->CompletionId = g_completion_id++; + irp->DeviceId = g_device_id; + irp->callback = scard_handle_ReleaseContext_Return; + irp->user_data = con; + + /* send IRP to client */ + scard_send_ReleaseContext(irp, context); + + return 0; +} + +/** + * Checks if a previously established context is still valid + *****************************************************************************/ +int APP_CC +scard_send_is_valid_context(struct trans *con, tui32 context) +{ + IRP *irp; + + /* setup up IRP */ if ((irp = devredir_irp_new()) == NULL) { log_error("system out of memory"); - return; + return 1; } - irp->scard_index = scard_add_new_device(device_id); - if (irp->scard_index < 0) + irp->scard_index = g_scard_index; + irp->CompletionId = g_completion_id++; + irp->DeviceId = g_device_id; + irp->callback = scard_handle_IsContextValid_Return; + irp->user_data = con; + + /* send IRP to client */ + scard_send_IsContextValid(irp, context); + + return 0; +} + +/** + * + *****************************************************************************/ +int APP_CC +scard_send_list_readers(struct trans *con, tui32 context, int wide) +{ + IRP *irp; + + /* setup up IRP */ + if ((irp = devredir_irp_new()) == NULL) { - log_debug("NOT adding smartcard with DeviceId=%d to list", device_id); - devredir_irp_delete(irp); - return; + log_error("system out of memory"); + return 1; } + irp->scard_index = g_scard_index; + irp->CompletionId = g_completion_id++; + irp->DeviceId = g_device_id; + irp->callback = scard_handle_ListReaders_Return; + irp->user_data = con; - log_debug("added smartcard with DeviceId=%d to list", device_id); + /* send IRP to client */ + scard_send_ListReaders(irp, context, wide); + return 0; +} + +/** + * Send get change in status command + * + * @param con connection to client + * @param wide TRUE if unicode string + * @param timeout timeout in milliseconds, -1 for infinity + * @param num_readers number of entries in rsa + * @param rsa array of READER_STATEs + *****************************************************************************/ +int APP_CC +scard_send_get_status_change(struct trans *con, tui32 context, int wide, + tui32 timeout, tui32 num_readers, + READER_STATE* rsa) +{ + IRP *irp; + + /* setup up IRP */ + if ((irp = devredir_irp_new()) == NULL) + { + log_error("system out of memory"); + return 1; + } + + irp->scard_index = g_scard_index; irp->CompletionId = g_completion_id++; - irp->DeviceId = device_id; - irp->callback = scard_handle_EstablishContext_Return; + irp->DeviceId = g_device_id; + irp->callback = scard_handle_GetStatusChange_Return; + irp->user_data = con; - scard_send_EstablishContext(irp); - log_debug("leaving"); + /* send IRP to client */ + scard_send_GetStatusChange(irp, context, wide, timeout, num_readers, rsa); + + return 0; } -/****************************************************************************** -** callbacks into this module ** -******************************************************************************/ +/** + * Open a connection to the smart card located in the reader + * + * @param con connection to client + * @param wide TRUE if unicode string + *****************************************************************************/ +int APP_CC +scard_send_connect(struct trans *con, tui32 context, int wide, + READER_STATE* rs) +{ + IRP *irp; -void APP_CC -scard_handle_EstablishContext_Return(struct stream *s, IRP *irp, - tui32 DeviceId, tui32 CompletionId, - tui32 IoStatus) + /* setup up IRP */ + if ((irp = devredir_irp_new()) == NULL) + { + log_error("system out of memory"); + return 1; + } + + irp->scard_index = g_scard_index; + irp->CompletionId = g_completion_id++; + irp->DeviceId = g_device_id; + irp->callback = scard_handle_Connect_Return; + irp->user_data = con; + + /* send IRP to client */ + scard_send_Connect(irp, context, wide, rs); + + return 0; +} + +/** + * The reconnect method re-establishes a smart card reader handle. On success, + * the handle is valid once again. + * + * @param con connection to client + * @param sc_handle handle to device + * @param rs reader state where following fields are set + * rs.shared_mode_flag + * rs.preferred_protocol + * rs.init_type + *****************************************************************************/ +int APP_CC +scard_send_reconnect(struct trans *con, tui32 context, tui32 sc_handle, + READER_STATE* rs) { - tui32 len; - int tmp; - SMARTCARD *sc; + IRP *irp; - log_debug("entered"); + /* setup up IRP */ + if ((irp = devredir_irp_new()) == NULL) + { + log_error("system out of memory"); + return 1; + } - /* sanity check */ - if ((DeviceId != irp->DeviceId) || (CompletionId != irp->CompletionId)) + irp->scard_index = g_scard_index; + irp->CompletionId = g_completion_id++; + irp->DeviceId = g_device_id; + irp->callback = scard_handle_Reconnect_Return; + irp->user_data = con; + + /* send IRP to client */ + scard_send_Reconnect(irp, context, sc_handle, rs); + + return 0; +} + +/** + * Lock smart card reader for exclusive access for specified smart + * card reader handle. + * + * @param con connection to client + *****************************************************************************/ +int APP_CC +scard_send_begin_transaction(struct trans *con, tui32 sc_handle) +{ + IRP *irp; + + /* setup up IRP */ + if ((irp = devredir_irp_new()) == NULL) { - log_error("DeviceId/CompletionId do not match those in IRP"); - return; + log_error("system out of memory"); + return 1; } - if (IoStatus != 0) + irp->scard_index = g_scard_index; + irp->CompletionId = g_completion_id++; + irp->DeviceId = g_device_id; + irp->callback = scard_handle_BeginTransaction_Return; + irp->user_data = con; + + /* send IRP to client */ + scard_send_BeginTransaction(irp, sc_handle); + + return 0; +} + +/** + * Release a smart card reader after being locked by a previously + * successful call to Begin Transaction + * + * @param con connection to client + * @param sc_handle handle to smartcard + *****************************************************************************/ +int APP_CC +scard_send_end_transaction(struct trans *con, tui32 sc_handle, + tui32 dwDisposition) +{ + IRP *irp; + + /* setup up IRP */ + if ((irp = devredir_irp_new()) == NULL) { - log_error("failed to establish context - device not usable"); - /* LK_TODO delete irp and smartcard entry */ - return; + log_error("system out of memory"); + return 1; } - sc = smartcards[irp->scard_index]; + irp->scard_index = g_scard_index; + irp->CompletionId = g_completion_id++; + irp->DeviceId = g_device_id; + irp->callback = scard_handle_EndTransaction_Return; + irp->user_data = con; - /* get OutputBufferLen */ - xstream_rd_u32_le(s, len); + /* send IRP to client */ + scard_send_EndTransaction(irp, sc_handle, dwDisposition); - /* LK_TODO */ - g_hexdump(s->p, len); + return 0; +} - xstream_rd_u32_le(s, tmp); /* should be len 8, LE, V1 */ - xstream_rd_u32_le(s, tmp); /* marshalling flag */ - xstream_rd_u32_le(s, tmp); /* ?? */ - xstream_rd_u32_le(s, tmp); /* ?? */ - xstream_rd_u32_le(s, tmp); /* ?? */ - xstream_rd_u32_le(s, tmp); /* ?? */ - xstream_rd_u32_le(s, tmp); /* ?? */ - xstream_rd_u32_le(s, len); /* len of context in bytes */ - sc->Context_len = len; - xstream_copyout(sc->Context, s, len); +/** + * Get the status of a connection for a valid smart card reader handle + * + * @param con connection to client + * @param wide TRUE if unicode string + *****************************************************************************/ +int APP_CC +scard_send_status(struct trans *con, int wide, tui32 sc_handle, + int cchReaderLen, int cbAtrLen) +{ + IRP *irp; - if (LOG_LEVEL == LOG_DEBUG) + /* setup up IRP */ + if ((irp = devredir_irp_new()) == NULL) { - log_debug("dumping context (%d bytes)", sc->Context_len); - g_hexdump(sc->Context, sc->Context_len); + log_error("system out of memory"); + return 1; } - irp->callback = scard_handle_ListReaders_Return; - scard_send_ListReaders(irp, 1); + irp->scard_index = g_scard_index; + irp->CompletionId = g_completion_id++; + irp->DeviceId = g_device_id; + irp->callback = scard_handle_Status_Return; + irp->user_data = con; - /* LK_TODO need to delete IRP */ - log_debug("leaving"); + /* send IRP to client */ + scard_send_Status(irp, wide, sc_handle, cchReaderLen, cbAtrLen); + + return 0; } -void APP_CC -scard_handle_ListReaders_Return(struct stream *s, IRP *irp, - tui32 DeviceId, tui32 CompletionId, - tui32 IoStatus) +/** + * Release a smart card reader handle that was acquired in ConnectA/ConnectW + * + * @param con connection to client + * @param sc_handle handle to smartcard + *****************************************************************************/ +int APP_CC +scard_send_disconnect(struct trans *con, tui32 context, tui32 sc_handle, + int dwDisposition) { - tui32 len; + IRP *irp; - log_debug("entered"); + /* setup up IRP */ + if ((irp = devredir_irp_new()) == NULL) + { + log_error("system out of memory"); + return 1; + } - /* sanity check */ - if ((DeviceId != irp->DeviceId) || (CompletionId != irp->CompletionId)) + irp->scard_index = g_scard_index; + irp->CompletionId = g_completion_id++; + irp->DeviceId = g_device_id; + irp->callback = scard_handle_Disconnect_Return; + irp->user_data = con; + + /* send IRP to client */ + scard_send_Disconnect(irp, context, sc_handle, dwDisposition); + + return 0; +} + +/** + * The Transmit_Call structure is used to send data to the smart card + * associated with a valid context. + *****************************************************************************/ +int APP_CC +scard_send_transmit(struct trans *con, tui32 sc_handle, + char *send_data, int send_bytes, int recv_bytes, + struct xrdp_scard_io_request *send_ior, + struct xrdp_scard_io_request *recv_ior) +{ + IRP *irp; + + /* setup up IRP */ + if ((irp = devredir_irp_new()) == NULL) { - log_error("DeviceId/CompletionId do not match those in IRP"); - return; + log_error("system out of memory"); + return 1; } - if (IoStatus != 0) + irp->scard_index = g_scard_index; + irp->CompletionId = g_completion_id++; + irp->DeviceId = g_device_id; + irp->callback = scard_handle_Transmit_Return; + irp->user_data = con; + + /* send IRP to client */ + scard_send_Transmit(irp, sc_handle, send_data, send_bytes, recv_bytes, + send_ior, recv_ior); + + return 0; +} + +/** + * Communicate directly with the smart card reader + *****************************************************************************/ +int APP_CC +scard_send_control(struct trans *con, tui32 context, tui32 sc_handle, + char *send_data, int send_bytes, + int recv_bytes, int control_code) +{ + IRP *irp; + + /* setup up IRP */ + if ((irp = devredir_irp_new()) == NULL) { - log_error("failed to list readers - device not usable"); - /* LK_TODO delete irp and smartcard entry */ - return; + log_error("system out of memory"); + return 1; } - /* get OutputBufferLen */ - xstream_rd_u32_le(s, len); + irp->scard_index = g_scard_index; + irp->CompletionId = g_completion_id++; + irp->DeviceId = g_device_id; + irp->callback = scard_handle_Control_Return; + irp->user_data = con; - /* LK_TODO */ - log_debug("dumping %d bytes", len); - g_hexdump(s->p, len); + /* send IRP to client */ + scard_send_Control(irp, context, sc_handle, send_data, + send_bytes, recv_bytes, control_code); - log_debug("leaving"); + return 0; +} + +/** + * Cancel any outstanding calls + *****************************************************************************/ +int APP_CC +scard_send_cancel(struct trans *con, tui32 context) +{ + IRP *irp; + + /* setup up IRP */ + if ((irp = devredir_irp_new()) == NULL) + { + log_error("system out of memory"); + return 1; + } + + irp->scard_index = g_scard_index; + irp->CompletionId = g_completion_id++; + irp->DeviceId = g_device_id; + irp->callback = scard_handle_Cancel_Return; + irp->user_data = con; + + /* send IRP to client */ + scard_send_Cancel(irp, context); + + return 0; +} + +/** + * Get reader attributes + *****************************************************************************/ +int APP_CC +scard_send_get_attrib(struct trans *con, tui32 sc_handle, READER_STATE* rs) +{ + IRP *irp; + + /* setup up IRP */ + if ((irp = devredir_irp_new()) == NULL) + { + log_error("system out of memory"); + return 1; + } + + irp->scard_index = g_scard_index; + irp->CompletionId = g_completion_id++; + irp->DeviceId = g_device_id; + irp->callback = scard_handle_GetAttrib_Return; + irp->user_data = con; + + /* send IRP to client */ + scard_send_GetAttrib(irp, sc_handle, rs); + + return 0; } /****************************************************************************** +** ** ** static functions local to this file ** +** ** ******************************************************************************/ /** + * Crate a new stream and insert specified IOCTL + * + * @param irp information about the I/O + * @param ioctl the IOCTL code * + * @return stream with IOCTL inserted in it, NULL on error *****************************************************************************/ +static struct stream * APP_CC +scard_make_new_ioctl(IRP *irp, tui32 ioctl) +{ + /* + * format of device control request + * + * DeviceIoRequest + * u16 RDPDR_CTYP_CORE + * u16 PAKID_CORE_DEVICE_IOREQUEST + * u32 DeviceId + * u32 FileId + * u32 CompletionId + * u32 MajorFunction + * u32 MinorFunction + * + * u32 OutputBufferLength SHOULD be 2048 + * u32 InputBufferLength + * u32 IoControlCode + * 20 bytes padding + * xx bytes InputBuffer (variable) + */ + + struct stream *s; + + xstream_new(s, 1024 * 4); + if (s == NULL) + { + log_error("system out of memory"); + return s; + } + + devredir_insert_DeviceIoRequest(s, + irp->DeviceId, + irp->FileId, + irp->CompletionId, + IRP_MJ_DEVICE_CONTROL, + 0); + + xstream_wr_u32_le(s, 2048); /* OutputBufferLength */ + xstream_wr_u32_le(s, 0); /* InputBufferLength - insert later */ + xstream_wr_u32_le(s, ioctl); /* Ioctl Code */ + xstream_seek(s, 20); /* padding */ + + /* [MS-RPCE] 2.2.6.1 */ + xstream_wr_u32_le(s, 0x00081001); /* len 8, LE, v1 */ + xstream_wr_u32_le(s, 0xcccccccc); /* filler */ + + return s; +} + +/** + * Create a new smart card device entry and insert it into smartcards[] + * + * @param device_id DeviceId of new card + * + * @return index into smartcards[] on success, -1 on failure + *****************************************************************************/ +static int APP_CC +scard_add_new_device(tui32 device_id) +{ + int index; + SMARTCARD *sc; + + if ((index = scard_get_free_slot()) < 0) + { + log_error("scard_get_free_slot failed"); + return -1; + } + + if ((sc = g_malloc(sizeof(SMARTCARD), 1)) == NULL) + { + log_error("system out of memory"); + return -1; + } + + sc->DeviceId = device_id; + smartcards[index] = sc; + + return index; +} + +/** + * Find first unused entry in smartcards + * + * @return index of first unused entry in smartcards or -1 if smartcards + * is full + *****************************************************************************/ +static int APP_CC +scard_get_free_slot(void) +{ + int i; + + for (i = 0; i < MAX_SMARTCARDS; i++) + { + if (smartcards[i] == NULL) + { + log_debug("found free slot at index %d", i); + return i; + } + } + + log_error("too many smart card devices; rejecting this one"); + return -1; +} + +#if 0 +/** + * Release resources prior to shutting down + *****************************************************************************/ +static void APP_CC +scard_release_resources(void) +{ + int i; + + for (i = 0; i < MAX_SMARTCARDS; i++) + { + if (smartcards[i] != NULL) + { + g_free(smartcards[i]); + smartcards[i] = NULL; + } + } +} +#endif +/** + * + *****************************************************************************/ static void APP_CC -scard_send_EstablishContext(IRP *irp) +scard_send_EstablishContext(IRP *irp, int scope) { struct stream *s; int bytes; if ((s = scard_make_new_ioctl(irp, SCARD_IOCTL_ESTABLISH_CONTEXT)) == NULL) + { + log_error("scard_make_new_ioctl failed"); return; + } - xstream_wr_u32_le(s, 0x08); /* len */ - xstream_wr_u32_le(s, 0); /* unused */ - xstream_wr_u32_le(s, SCARD_SCOPE_SYSTEM); /* Ioctl specific data */ - xstream_wr_u32_le(s, 0); /* don't know what this is, */ - /* but Win7 is sending it */ + xstream_wr_u32_le(s, 0x08); /* len */ + xstream_wr_u32_le(s, 0); /* unused */ + xstream_wr_u32_le(s, scope); /* Ioctl specific data */ + xstream_wr_u32_le(s, 0); /* don't know what this is, */ + /* but Win7 is sending it */ /* get stream len */ bytes = xstream_len(s); - /* InputBufferLength is number of bytes AFTER 20 byte padding */ + /* InputBufferLength is number of bytes AFTER 20 byte padding */ *(s->data + 28) = bytes - 56; /* send to client */ @@ -313,11 +949,112 @@ scard_send_EstablishContext(IRP *irp) } /** - * + * Release a previously established Smart Card context *****************************************************************************/ +static void APP_CC +scard_send_ReleaseContext(IRP* irp, tui32 context) +{ + /* see [MS-RDPESC] 3.1.4.2 */ + + SMARTCARD* sc; + struct stream* s; + int bytes; + + if ((sc = smartcards[irp->scard_index]) == NULL) + { + log_error("smartcards[%d] is NULL", irp->scard_index); + return; + } + if ((s = scard_make_new_ioctl(irp, SCARD_IOCTL_RELEASE_CONTEXT)) == NULL) + return; + + /* + * command format + * + * ...... + * 20 bytes padding + * u32 4 bytes len 8, LE, v1 + * u32 4 bytes filler + * 4 bytes len - don't know what this is, zero for now + * 12 bytes unused + * u32 4 bytes context len + * 4 bytes context + */ + + xstream_wr_u32_le(s, 0); + xstream_seek(s, 12); + + /* insert context */ + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, context); + + /* get stream len */ + bytes = xstream_len(s); + + /* InputBufferLength is number of bytes AFTER 20 byte padding */ + *(s->data + 28) = bytes - 56; + + /* send to client */ + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + xstream_free(s); +} + +/** + * Checks if a previously established context is still valid + *****************************************************************************/ static void APP_CC -scard_send_ListReaders(IRP *irp, int wide) +scard_send_IsContextValid(IRP* irp, tui32 context) +{ + /* see [MS-RDPESC] 3.1.4.3 */ + + SMARTCARD* sc; + struct stream* s; + int bytes; + + if ((sc = smartcards[irp->scard_index]) == NULL) + { + log_error("smartcards[%d] is NULL", irp->scard_index); + return; + } + + if ((s = scard_make_new_ioctl(irp, SCARD_IOCTL_IS_VALID_CONTEXT)) == NULL) + return; + + /* + * command format + * + * ...... + * 20 bytes padding + * u32 4 bytes len 8, LE, v1 + * u32 4 bytes filler + * 16 bytes unused (s->p currently pointed here at unused[0]) + * u32 4 bytes context len + * u32 4 bytes context + */ + + xstream_wr_u32_le(s, 16); + + /* insert context */ + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, context); + + /* get stream len */ + bytes = xstream_len(s); + + /* InputBufferLength is number of bytes AFTER 20 byte padding */ + *(s->data + 28) = bytes - 56; + + /* send to client */ + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + xstream_free(s); +} + +/** + * + *****************************************************************************/ +static void APP_CC +scard_send_ListReaders(IRP *irp, tui32 context, int wide) { /* see [MS-RDPESC] 2.2.2.4 */ @@ -332,18 +1069,18 @@ scard_send_ListReaders(IRP *irp, int wide) return; } - ioctl = (wide > 0) ? SCARD_IOCTL_LIST_READERS_W : - SCARD_IOCTL_LIST_READERS_A; + ioctl = (wide) ? SCARD_IOCTL_LIST_READERS_W : + SCARD_IOCTL_LIST_READERS_A; if ((s = scard_make_new_ioctl(irp, ioctl)) == NULL) return; xstream_wr_u32_le(s, 72); /* number of bytes to follow */ - xstream_seek(s, 0x1c); /* freerdp does not use this */ + xstream_seek(s, 28); /* freerdp does not use this */ /* insert context */ - xstream_wr_u32_le(s, sc->Context_len); - xstream_copyin(s, sc->Context, sc->Context_len); + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, context); xstream_wr_u32_le(s, 36); /* length of mszGroups */ xstream_wr_u16_le(s, 0x0053); @@ -389,185 +1126,1361 @@ scard_send_ListReaders(IRP *irp, int wide) */ /* - scard_device_control: dumping 120 bytes of data - 0000 00 08 00 00 80 00 00 00 14 00 09 00 00 00 00 00 ................ - 0010 2e 2e 00 00 00 00 00 00 02 00 00 00 00 00 00 00 ................ - 0020 01 10 08 00 cc cc cc cc 48 00 00 00 00 00 00 00 ........H....... - 0030 02 00 00 00 00 00 00 00 72 64 00 00 00 00 00 00 ........rd...... - 0040 81 27 00 00 00 00 00 00 04 00 00 00 84 b3 03 01 .'.............. - 0050 24 00 00 00 53 00 43 00 61 00 72 00 64 00 24 00 $...S.C.a.r.d.$. - 0060 41 00 6c 00 6c 00 52 00 65 00 61 00 64 00 65 00 A.l.l.R.e.a.d.e. - 0070 72 00 73 00 00 00 00 00 r.s..... - scard_device_control: output_len=2048 input_len=128 ioctl_code=0x90014 + scard_device_control: dumping 120 bytes of data + 0000 00 08 00 00 80 00 00 00 14 00 09 00 00 00 00 00 ................ + 0010 2e 2e 00 00 00 00 00 00 02 00 00 00 00 00 00 00 ................ + 0020 01 10 08 00 cc cc cc cc 48 00 00 00 00 00 00 00 ........H....... + 0030 02 00 00 00 00 00 00 00 72 64 00 00 00 00 00 00 ........rd...... + 0040 81 27 00 00 00 00 00 00 04 00 00 00 84 b3 03 01 .'.............. + 0050 24 00 00 00 53 00 43 00 61 00 72 00 64 00 24 00 $...S.C.a.r.d.$. + 0060 41 00 6c 00 6c 00 52 00 65 00 61 00 64 00 65 00 A.l.l.R.e.a.d.e. + 0070 72 00 73 00 00 00 00 00 r.s..... + scard_device_control: output_len=2048 input_len=128 ioctl_code=0x90014 */ } +/*****************************************************************************/ +static int +align_s(struct stream *s, int bytes) +{ + int i32; + + i32 = (int) (s->p - s->data); + while ((i32 % bytes) != 0) + { + out_uint8s(s, 1); + i32 = (int) (s->p - s->data); + } + return 0; +} + /** - * Crate a new stream and insert specified IOCTL - * - * @param irp information about the I/O - * @param ioctl the IOCTL code + * Get change in status * - * @return stream with IOCTL inserted in it, NULL on error + * @param irp I/O resource pkt + * @param wide TRUE if unicode string + * @param timeout timeout in milliseconds, -1 for infinity + * @param num_readers number of entries in rsa + * @param rsa array of READER_STATEs *****************************************************************************/ +static void APP_CC +scard_send_GetStatusChange(IRP* irp, tui32 context, int wide, tui32 timeout, + tui32 num_readers, READER_STATE* rsa) +{ + /* see [MS-RDPESC] 2.2.2.11 for ASCII */ + /* see [MS-RDPESC] 2.2.2.12 for Wide char */ -static struct stream * APP_CC -scard_make_new_ioctl(IRP *irp, tui32 ioctl) + SMARTCARD* sc; + READER_STATE* rs; + struct stream* s; + tui32 ioctl; + int bytes; + int i; + int num_chars; + int index; + twchar w_reader_name[100]; + + if ((sc = smartcards[irp->scard_index]) == NULL) + { + log_error("smartcards[%d] is NULL", irp->scard_index); + return; + } + + ioctl = (wide) ? SCARD_IOCTL_GET_STATUS_CHANGE_W : + SCARD_IOCTL_GET_STATUS_CHANGE_A; + + if ((s = scard_make_new_ioctl(irp, ioctl)) == NULL) + return; + + xstream_seek(s, 16); /* unused */ + xstream_wr_u32_le(s, timeout); + xstream_wr_u32_le(s, num_readers); + xstream_wr_u32_le(s, 0); /* unused */ + + /* insert context */ + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, context); + + xstream_wr_u32_le(s, 0); /* unused */ + + /* insert card reader state */ + for (i = 0; i < num_readers; i++) + { + rs = &rsa[i]; + xstream_wr_u32_le(s, 0); /* unused */ + xstream_wr_u32_le(s, rs->current_state); + xstream_wr_u32_le(s, rs->event_state); + xstream_wr_u32_le(s, rs->atr_len); + xstream_copyin(s, rs->atr, 33); + out_uint8s(s, 3); + } + + if (wide) + { + /* insert card reader names */ + for (i = 0; i < num_readers; i++) + { + rs = &rsa[i]; + num_chars = g_mbstowcs(w_reader_name, rs->reader_name, 99); + xstream_wr_u32_le(s, 0); /* unused */ + xstream_wr_u32_le(s, 0); /* unused */ + xstream_wr_u32_le(s, num_chars); + for (index = 0; index < num_chars; index++) + { + xstream_wr_u16_le(s, w_reader_name[index]); + } + align_s(s, 4); + } + } + else + { + /* insert card reader names */ + for (i = 0; i < num_readers; i++) + { + rs = &rsa[i]; + num_chars = g_mbstowcs(w_reader_name, rs->reader_name, 99); + xstream_wr_u32_le(s, 0); /* unused */ + xstream_wr_u32_le(s, 0); /* unused */ + xstream_wr_u32_le(s, num_chars); + for (index = 0; index < num_chars; index++) + { + xstream_wr_u8(s, w_reader_name[index]); + } + align_s(s, 4); + } + } + + /* get stream len */ + bytes = xstream_len(s); + + /* InputBufferLength is number of bytes AFTER 20 byte padding */ + *(s->data + 28) = bytes - 56; + + /* send to client */ + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + xstream_free(s); +} + +/** + * Send connect command + * + * @param irp I/O resource pkt + * @param wide TRUE if unicode string + * @param rs reader state + *****************************************************************************/ +static void APP_CC +scard_send_Connect(IRP* irp, tui32 context, int wide, READER_STATE* rs) { + /* see [MS-RDPESC] 2.2.2.13 for ASCII */ + /* see [MS-RDPESC] 2.2.2.14 for Wide char */ + + SMARTCARD* sc; + struct stream* s; + tui32 ioctl; + int bytes; + int num_chars; + int index; + twchar w_reader_name[100]; + + if ((sc = smartcards[irp->scard_index]) == NULL) + { + log_error("smartcards[%d] is NULL", irp->scard_index); + return; + } + + ioctl = (wide) ? SCARD_IOCTL_CONNECT_W : + SCARD_IOCTL_CONNECT_A; + + if ((s = scard_make_new_ioctl(irp, ioctl)) == NULL) + return; + /* - * format of device control request + * command format * - * DeviceIoRequest - * u16 RDPDR_CTYP_CORE - * u16 PAKID_CORE_DEVICE_IOREQUEST - * u32 DeviceId - * u32 FileId - * u32 CompletionId - * u32 MajorFunction - * u32 MinorFunction + * ...... + * 20 bytes padding + * u32 4 bytes len 8, LE, v1 + * u32 4 bytes filler + * 20 bytes unused (s->p currently pointed here at unused[0]) + * u32 4 bytes dwShareMode + * u32 4 bytes dwPreferredProtocols + * xx bytes reader name + * u32 4 bytes context length (len) + * len bytes context + */ + + xstream_seek(s, 20); + xstream_wr_u32_le(s, rs->dwShareMode); + xstream_wr_u32_le(s, rs->dwPreferredProtocols); + + /* insert reader name */ + num_chars = g_mbstowcs(w_reader_name, rs->reader_name, 99); + xstream_wr_u32_le(s, 0); + xstream_wr_u32_le(s, 0); + xstream_wr_u32_le(s, num_chars); + if (wide) + { + for (index = 0; index < num_chars; index++) + { + xstream_wr_u16_le(s, w_reader_name[index]); + } + } + else + { + for (index = 0; index < num_chars; index++) + { + xstream_wr_u8(s, w_reader_name[index]); + } + } + align_s(s, 4); + + /* insert context */ + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, context); + + /* get stream len */ + bytes = xstream_len(s); + + /* InputBufferLength is number of bytes AFTER 20 byte padding */ + *(s->data + 28) = bytes - 56; + + /* send to client */ + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + xstream_free(s); +} + +/** + * The reconnect method re-establishes a smart card reader handle. On success, + * the handle is valid once again. + * + * @param con connection to client + * @param sc_handle handle to device + * @param rs reader state where following fields are set + * rs.shared_mode_flag + * rs.preferred_protocol + * rs.init_type + *****************************************************************************/ +static void APP_CC +scard_send_Reconnect(IRP* irp, tui32 context, tui32 sc_handle, READER_STATE* rs) +{ + /* see [MS-RDPESC] 2.2.2.15 */ + /* see [MS-RDPESC] 3.1.4.36 */ + + SMARTCARD* sc; + struct stream* s; + int bytes; + + if ((sc = smartcards[irp->scard_index]) == NULL) + { + log_error("smartcards[%d] is NULL", irp->scard_index); + return; + } + + if ((s = scard_make_new_ioctl(irp, SCARD_IOCTL_RECONNECT)) == NULL) + return; + + /* + * command format * - * u32 OutputBufferLength SHOULD be 2048 - * u32 InputBufferLength - * u32 IoControlCode - * 20 bytes padding - * xx bytes InputBuffer (variable) + * ...... + * 20 bytes padding + * u32 4 bytes len 8, LE, v1 + * u32 4 bytes filler + * 24 bytes unused (s->p currently pointed here at unused[0]) + * u32 4 bytes dwShareMode + * u32 4 bytes dwPreferredProtocols + * u32 4 bytes dwInitialization + * u32 4 bytes context length + * u32 4 bytes context + * u32 4 bytes handle length + * u32 4 bytes handle */ + xstream_seek(s, 24); + xstream_wr_u32_le(s, rs->dwShareMode); + xstream_wr_u32_le(s, rs->dwPreferredProtocols); + xstream_wr_u32_le(s, rs->init_type); + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, context); + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, sc_handle); + + /* get stream len */ + bytes = xstream_len(s); + + /* InputBufferLength is number of bytes AFTER 20 byte padding */ + *(s->data + 28) = bytes - 56; + + /* send to client */ + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + xstream_free(s); +} + +/** + * Lock smart card reader for exclusive access for specified smart + * card reader handle. + * + * @param con connection to client + *****************************************************************************/ +static void APP_CC +scard_send_BeginTransaction(IRP *irp, tui32 sc_handle) +{ + /* see [MS-RDPESC] 4.9 */ + + SMARTCARD *sc; struct stream *s; + int bytes; - xstream_new(s, 1024 * 3); - if (s == NULL) + if ((sc = smartcards[irp->scard_index]) == NULL) { - log_error("system out of memory"); - return s; + log_error("smartcards[%d] is NULL", irp->scard_index); + return; } - devredir_insert_DeviceIoRequest(s, - irp->DeviceId, - irp->FileId, - irp->CompletionId, - IRP_MJ_DEVICE_CONTROL, - 0); + if ((s = scard_make_new_ioctl(irp, SCARD_IOCTL_BEGIN_TRANSACTION)) == NULL) + return; - xstream_wr_u32_le(s, 2048); /* OutputBufferLength */ - xstream_wr_u32_le(s, 0); /* InputBufferLength - insert later */ - xstream_wr_u32_le(s, ioctl); /* Ioctl Code */ - xstream_seek(s, 20); /* padding */ + /* + * command format + * + * ...... + * 20 bytes padding + * u32 4 bytes len 8, LE, v1 + * u32 4 bytes filler + * 36 bytes unused (s->p currently pointed here at unused[0]) + * u32 4 bytes len of sc_handle + * 4 bytes sc_handle + */ - /* [MS-RPCE] 2.2.6.1 */ - xstream_wr_u32_le(s, 0x00081001); /* len 8, LE, v1 */ - xstream_wr_u32_le(s, 0xcccccccc); /* filler */ + xstream_seek(s, 36); - return s; + /* insert handle */ + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, sc_handle); + + /* get stream len */ + bytes = xstream_len(s); + + /* InputBufferLength is number of bytes AFTER 20 byte padding */ + *(s->data + 28) = bytes - 56; + + /* send to client */ + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + xstream_free(s); } /** - * Create a new smart card device entry and insert it into smartcards[] + * Release a smart card reader after being locked by a previously + * successful call to Begin Transaction * - * @param device_id DeviceId of new card - * - * @return index into smartcards[] on success, -1 on failure + * @param con connection to client + * @param sc_handle handle to smartcard *****************************************************************************/ +static void APP_CC +scard_send_EndTransaction(IRP *irp, tui32 sc_handle, tui32 dwDisposition) +{ + /* see [MS-RDPESC] 3.1.4.32 */ -static int APP_CC -scard_add_new_device(tui32 device_id) + SMARTCARD *sc; + struct stream *s; + int bytes; + + if ((sc = smartcards[irp->scard_index]) == NULL) + { + log_error("smartcards[%d] is NULL", irp->scard_index); + return; + } + + if ((s = scard_make_new_ioctl(irp, SCARD_IOCTL_END_TRANSACTION)) == NULL) + return; + + /* + * command format + * + * ...... + * 20 bytes padding + * u32 4 bytes len 8, LE, v1 + * u32 4 bytes filler + * 24 bytes unused (s->p currently pointed here at unused[0]) + * u32 4 bytes disposition + * 8 unused + * u32 4 bytes length of sc_handle + * 4 bytes sc_handle + */ + + xstream_seek(s, 24); + xstream_wr_u32_le(s, dwDisposition); + xstream_seek(s, 8); + + /* insert handle */ + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, sc_handle); + + /* get stream len */ + bytes = xstream_len(s); + + /* InputBufferLength is number of bytes AFTER 20 byte padding */ + *(s->data + 28) = bytes - 56; + + /* send to client */ + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + xstream_free(s); +} + +/** + * Get the status of a connection for a valid smart card reader handle + * + * @param con connection to client + * @param wide TRUE if unicode string + *****************************************************************************/ +static void APP_CC +scard_send_Status(IRP *irp, int wide, tui32 sc_handle, + int cchReaderLen, int cbAtrLen) { - int index; - SMARTCARD *sc; + /* see [MS-RDPESC] 2.2.2.18 */ - if ((index = scard_get_free_slot()) < 0) - return -1; + SMARTCARD *sc; + struct stream *s; + int bytes; + tui32 ioctl; - if ((sc = g_malloc(sizeof(SMARTCARD), 1)) == NULL) + if ((sc = smartcards[irp->scard_index]) == NULL) { - log_error("system out of memory"); - return -1; + log_error("smartcards[%d] is NULL", irp->scard_index); + return; } - sc->DeviceId = device_id; - smartcards[index] = sc; + ioctl = wide ? SCARD_IOCTL_STATUS_W : SCARD_IOCTL_STATUS_A; + if ((s = scard_make_new_ioctl(irp, ioctl)) == NULL) + { + log_error("scard_make_new_ioctl"); + return; + } - return index; + /* + * command format + * + * ...... + * 20 bytes padding + * u32 4 bytes len 8, LE, v1 + * u32 4 bytes filler + * 28 bytes unused (s->p currently pointed here at unused[0]) + * u32 4 bytes reader len + * u32 4 bytes ATR len + * 8 bytes unused + * u32 4 bytes len of sc_handle + * 4 bytes sc_handle + * 4 bytes unused + */ + + xstream_seek(s, 28); + xstream_wr_u32_le(s, cchReaderLen); /* readerLen, see [MS-RDPESC] 4.11 */ + xstream_wr_u32_le(s, cbAtrLen); /* atrLen, see [MS-RDPESC] 4.11 */ + xstream_seek(s, 8); + + /* insert sc_handle */ + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, sc_handle); + + xstream_wr_u32_le(s, 0); + + /* get stream len */ + bytes = xstream_len(s); + + /* InputBufferLength is number of bytes AFTER 20 byte padding */ + *(s->data + 28) = bytes - 56; + + /* send to client */ + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + xstream_free(s); } /** - * Find first unused entry in smartcards + * Release a smart card reader handle that was acquired in ConnectA/ConnectW * - * @return index of first unused entry in smartcards or -1 if smartcards - * is full + * @param con connection to client + * @param sc_handle handle to smartcard *****************************************************************************/ +static void APP_CC +scard_send_Disconnect(IRP *irp, tui32 context, tui32 sc_handle, + int dwDisposition) +{ + /* see [MS-RDPESC] 3.1.4.30 */ + SMARTCARD* sc; + struct stream* s; + int bytes; + + if ((sc = smartcards[irp->scard_index]) == NULL) + { + log_error("smartcards[%d] is NULL", irp->scard_index); + return; + } + + if ((s = scard_make_new_ioctl(irp, SCARD_IOCTL_DISCONNECT)) == NULL) + return; + + /* + * command format + * + * ...... + * 20 bytes padding + * u32 4 bytes len 8, LE, v1 + * u32 4 bytes filler + * 24 bytes unused (s->p currently pointed here at unused[0]) + * u32 4 bytes disposition + * u32 4 bytes context len + * 4 bytes context + * u32 4 bytes length of sc_handle + * 4 bytes sc_handle + */ + + xstream_seek(s, 24); + xstream_wr_u32_le(s, dwDisposition); + + /* insert context */ + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, context); + + /* insert handle */ + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, sc_handle); + + /* get stream len */ + bytes = xstream_len(s); + + /* InputBufferLength is number of bytes AFTER 20 byte padding */ + *(s->data + 28) = bytes - 56; + + /* send to client */ + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + xstream_free(s); +} + +/** + * The Transmit_Call structure is used to send data to the smart card + * associated with a valid context. + *****************************************************************************/ static int APP_CC -scard_get_free_slot(void) +scard_send_Transmit(IRP* irp, tui32 sc_handle, char *send_data, + int send_bytes, int recv_bytes, + struct xrdp_scard_io_request *send_ior, + struct xrdp_scard_io_request *recv_ior) { - int i; + /* see [MS-RDPESC] 2.2.2.19 */ - for (i = 0; i < MAX_SMARTCARDS; i++) + SMARTCARD* sc; + struct stream* s; + int bytes; + int val; + + if ((sc = smartcards[irp->scard_index]) == NULL) { - if (smartcards[i] == NULL) + log_error("smartcards[%d] is NULL", irp->scard_index); + return 1; + } + + if ((s = scard_make_new_ioctl(irp, SCARD_IOCTL_TRANSMIT)) == NULL) + { + log_error("scard_make_new_ioctl"); + return 1; + } + + log_debug("send_bytes %d recv_bytes %d send dwProtocol %d cbPciLength %d " + "extra_bytes %d recv dwProtocol %d cbPciLength %d", send_bytes, + recv_bytes, send_ior->dwProtocol, send_ior->cbPciLength, + send_ior->extra_bytes, recv_ior->dwProtocol, recv_ior->cbPciLength, + recv_ior->extra_bytes); + + /* + * command format + * + * ...... + * 20 bytes padding + * u32 4 bytes len 8, LE, v1 + * u32 4 bytes filler + * 12 bytes unused (s->p currently pointed here at unused[0]) + * u32 4 bytes map0 + * 4 bytes unused + * u32 4 bytes map1 + * u32 4 bytes dwProtocol + * u32 4 bytes cbPciLength + * u32 4 bytes map2 + * u32 4 byts cbSendLength + * u32 4 bytes map3 + * u32 4 bytes map4 + * u32 4 bytes map5 + * u32 4 bytes map6 + * u32 4 bytes cbRecvLength + * u32 4 bytes len of sc_handle + * u32 4 bytes sc_handle + */ + + xstream_seek(s, 12); + xstream_wr_u32_le(s, 0); // map0 + xstream_seek(s, 4); + xstream_wr_u32_le(s, 0); // map1 + xstream_wr_u32_le(s, send_ior->dwProtocol); + xstream_wr_u32_le(s, send_ior->cbPciLength); + val = send_ior->extra_bytes > 0 ? 1 : 0; + xstream_wr_u32_le(s, val); // map2 + xstream_wr_u32_le(s, send_bytes); + val = send_bytes > 0 ? 1 : 0; + xstream_wr_u32_le(s, val); // map3 + val = recv_ior->cbPciLength > 0 ? 1 : 0; + xstream_wr_u32_le(s, val); // map 4 + xstream_wr_u32_le(s, 0); // map5 + xstream_wr_u32_le(s, recv_bytes); + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, sc_handle); + + if (send_ior->extra_bytes > 0) + { + xstream_wr_u32_le(s, send_ior->extra_bytes); + out_uint8a(s, send_ior->extra_data, send_ior->extra_bytes); + } + + if (send_bytes > 0) + { + xstream_wr_u32_le(s, send_bytes); + out_uint8a(s, send_data, send_bytes); + } + + if (recv_ior->cbPciLength > 0) + { + xstream_wr_u32_le(s, recv_ior->dwProtocol); + xstream_wr_u32_le(s, recv_ior->cbPciLength); + val = recv_ior->extra_bytes > 0 ? 1 : 0; + xstream_wr_u32_le(s, val); + if (val) { - log_debug("found free slot at index %d", i); - return i; + xstream_wr_u32_le(s, recv_ior->extra_bytes); + out_uint8a(s, recv_ior->extra_data, recv_ior->extra_bytes); } } - log_error("too many smart card devices; rejecting this one"); - return -1; + /* get stream len */ + bytes = xstream_len(s); + + /* InputBufferLength is number of bytes AFTER 20 byte padding */ + *(s->data + 28) = bytes - 56; + + /* send to client */ + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + xstream_free(s); + return 0; } /** - * Release resources prior to shutting down + * Communicate directly with the smart card reader *****************************************************************************/ +static int APP_CC +scard_send_Control(IRP* irp, tui32 context, tui32 sc_handle, char *send_data, + int send_bytes, int recv_bytes, int control_code) +{ + /* see [MS-RDPESC] 2.2.2.19 */ + + SMARTCARD* sc; + struct stream* s; + int bytes; + int val; + + if ((sc = smartcards[irp->scard_index]) == NULL) + { + log_error("smartcards[%d] is NULL", irp->scard_index); + return 1; + } + + if ((s = scard_make_new_ioctl(irp, SCARD_IOCTL_CONTROL)) == NULL) + { + log_error("scard_make_new_ioctl"); + return 1; + } + + /* + * command format + * + * ...... + * 20 bytes padding + * u32 4 bytes len 8, LE, v1 + * u32 4 bytes filler + * 12 bytes unused (s->p currently pointed here at unused[0]) + * u32 4 bytes map0 + * 4 bytes unused + * u32 4 bytes map1 + * u32 4 bytes dwControlCode + * u32 4 bytes cbRecvLength + * u32 4 bytes map2 + * 4 bytes unused + * u32 4 bytes cbOutBufferSize + * u32 4 bytes context len + * u32 4 bytes context + * u32 4 bytes handle len + * u32 4 bytes handle + */ + + xstream_seek(s, 12); + xstream_wr_u32_le(s, 0); // map0 + xstream_seek(s, 4); + xstream_wr_u32_le(s, 0); // map1 + + xstream_wr_u32_le(s, control_code); + + xstream_wr_u32_le(s, send_bytes); + + val = send_bytes > 0 ? 1 : 0; + xstream_wr_u32_le(s, val); // map2 + + xstream_wr_u32_le(s, 0); + xstream_wr_u32_le(s, recv_bytes); + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, context); + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, sc_handle); + + if (send_bytes > 0) + { + xstream_wr_u32_le(s, send_bytes); + out_uint8a(s, send_data, send_bytes); + } + + /* get stream len */ + bytes = xstream_len(s); + + /* InputBufferLength is number of bytes AFTER 20 byte padding */ + *(s->data + 28) = bytes - 56; + + /* send to client */ + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + xstream_free(s); + return 0; +} + +/** + * Cancel any outstanding calls + *****************************************************************************/ +static int APP_CC +scard_send_Cancel(IRP* irp, tui32 context) +{ + /* see [MS-RDPESC] 3.1.4.27 */ + + SMARTCARD* sc; + struct stream* s; + int bytes; + + if ((sc = smartcards[irp->scard_index]) == NULL) + { + log_error("smartcards[%d] is NULL", irp->scard_index); + return 1; + } + + if ((s = scard_make_new_ioctl(irp, SCARD_IOCTL_CANCEL)) == NULL) + { + log_error("scard_make_new_ioctl"); + return 1; + } + + /* + * command format + * + * ...... + * 20 bytes padding + * u32 4 bytes len 8, LE, v1 + * u32 4 bytes filler + * 16 bytes unused (s->p currently pointed here at unused[0]) + * u32 4 bytes context len + * u32 4 bytes context + */ + + xstream_seek(s, 16); + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, context); + + /* get stream len */ + bytes = xstream_len(s); + + /* InputBufferLength is number of bytes AFTER 20 byte padding */ + *(s->data + 28) = bytes - 56; + + /* send to client */ + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + xstream_free(s); + return 0; +} + +/** + * Get reader attributes + *****************************************************************************/ +static int APP_CC +scard_send_GetAttrib(IRP* irp, tui32 sc_handle, READER_STATE* rs) +{ + /* see [MS-RDPESC] 2.2.2.21 */ + SMARTCARD* sc; + struct stream* s; + int bytes; + + if ((sc = smartcards[irp->scard_index]) == NULL) + { + log_error("smartcards[%d] is NULL", irp->scard_index); + return 1; + } + + if ((s = scard_make_new_ioctl(irp, SCARD_IOCTL_GETATTRIB)) == NULL) + { + log_error("scard_make_new_ioctl"); + return 1; + } + + /* + * command format + * + * ...... + * 20 bytes padding + * u32 4 bytes len 8, LE, v1 + * u32 4 bytes filler + * 24 bytes unused (s->p currently pointed here at unused[0]) + * u32 4 bytes dwAttribId + * 4 bytes unused + * u32 4 bytes dwAttrLen + * 8 bytes unused + * u32 4 bytes handle len + * u32 4 bytes handle + */ + + xstream_seek(s, 24); + xstream_wr_u32_le(s, rs->dwAttribId); + xstream_wr_u32_le(s, 0); + xstream_wr_u32_le(s, rs->dwAttrLen); + xstream_seek(s, 8); + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, sc_handle); + + /* get stream len */ + bytes = xstream_len(s); + + /* InputBufferLength is number of bytes AFTER 20 byte padding */ + *(s->data + 28) = bytes - 56; + + /* send to client */ + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + xstream_free(s); + return 0; +} + +/****************************************************************************** +** ** +** local callbacks into this module ** +** ** +******************************************************************************/ + +/** + * + *****************************************************************************/ static void APP_CC -scard_release_resources(void) +scard_handle_EstablishContext_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus) { - int i; + tui32 len; + struct trans *con; - for (i = 0; i < MAX_SMARTCARDS; i++) + log_debug("entered"); + /* sanity check */ + if ((DeviceId != irp->DeviceId) || (CompletionId != irp->CompletionId)) { - if (smartcards[i] != NULL) - { - g_free(smartcards[i]); - smartcards[i] = NULL; - } + log_error("DeviceId/CompletionId do not match those in IRP"); + return; } + if (IoStatus != 0) + { + log_error("failed to establish context - device not usable"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + con = (struct trans *) (irp->user_data); + scard_function_establish_context_return(con, s, len); + devredir_irp_delete(irp); + log_debug("leaving"); } /** * *****************************************************************************/ -int APP_CC -scard_get_wait_objs(tbus *objs, int *count, int *timeout) +static void +scard_handle_ReleaseContext_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus) { - return scard_pcsc_get_wait_objs(objs, count, timeout); + tui32 len; + struct trans *con; + + log_debug("entered"); + /* sanity check */ + if ((DeviceId != irp->DeviceId) || (CompletionId != irp->CompletionId)) + { + log_error("DeviceId/CompletionId do not match those in IRP"); + return; + } + if (IoStatus != 0) + { + log_error("ReleaseContext failed"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + con = (struct trans *) (irp->user_data); + scard_function_release_context_return(con, s, len); + devredir_irp_delete(irp); + log_debug("leaving"); } /** * *****************************************************************************/ -int APP_CC -scard_check_wait_objs(void) +static void +APP_CC scard_handle_IsContextValid_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus) { - return scard_pcsc_check_wait_objs(); + tui32 len; + struct trans *con; + + log_debug("entered"); + + /* sanity check */ + if ((DeviceId != irp->DeviceId) || (CompletionId != irp->CompletionId)) + { + log_error("DeviceId/CompletionId do not match those in IRP"); + return; + } + + if (IoStatus != 0) + { + log_error("Error checking context validity"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + con = (struct trans *) (irp->user_data); + scard_function_is_context_valid_return(con, s, len); + devredir_irp_delete(irp); + log_debug("leaving"); } /** * *****************************************************************************/ -int APP_CC -scard_init(void) +static void APP_CC +scard_handle_ListReaders_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus) { - log_debug("init") - return scard_pcsc_init(); + tui32 len; + struct trans *con; + + log_debug("entered"); + /* sanity check */ + if ((DeviceId != irp->DeviceId) || (CompletionId != irp->CompletionId)) + { + log_error("DeviceId/CompletionId do not match those in IRP"); + return; + } + if (IoStatus != 0) + { + log_error("failed to list readers"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + con = (struct trans *) (irp->user_data); + scard_function_list_readers_return(con, s, len); + devredir_irp_delete(irp); + log_debug("leaving"); } /** * *****************************************************************************/ -int APP_CC -scard_deinit(void) +static void +scard_handle_GetStatusChange_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus) { - log_debug("deinit") - return scard_pcsc_deinit(); + tui32 len; + struct trans *con; + + log_debug("entered"); + /* sanity check */ + if ((DeviceId != irp->DeviceId) || (CompletionId != irp->CompletionId)) + { + log_error("DeviceId/CompletionId do not match those in IRP"); + return; + } + if (IoStatus != 0) + { + log_error("failed to get status change"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + con = (struct trans *) (irp->user_data); + scard_function_get_status_change_return(con, s, len); + devredir_irp_delete(irp); + log_debug("leaving"); +} + +/** + * + *****************************************************************************/ +static void +scard_handle_Connect_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus) +{ + tui32 len; + struct trans *con; + + log_debug("entered"); + + /* sanity check */ + if ((DeviceId != irp->DeviceId) || (CompletionId != irp->CompletionId)) + { + log_error("DeviceId/CompletionId do not match those in IRP"); + return; + } + + if (IoStatus != 0) + { + log_error("failed to connect"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + + con = (struct trans *) (irp->user_data); + scard_function_connect_return(con, s, len); + devredir_irp_delete(irp); + + log_debug("leaving"); +} + +/** + * + *****************************************************************************/ +static void APP_CC +scard_handle_Reconnect_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus) +{ + tui32 len; + struct trans *con; + + log_debug("entered"); + + /* sanity check */ + if ((DeviceId != irp->DeviceId) || (CompletionId != irp->CompletionId)) + { + log_error("DeviceId/CompletionId do not match those in IRP"); + return; + } + + if (IoStatus != 0) + { + log_error("failed to reconnect"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + con = (struct trans *) (irp->user_data); + scard_function_reconnect_return(con, s, len); + devredir_irp_delete(irp); + log_debug("leaving"); +} + +/** + * + *****************************************************************************/ +static void +scard_handle_BeginTransaction_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus) +{ + tui32 len; + struct trans *con; + + log_debug("entered"); + + /* sanity check */ + if ((DeviceId != irp->DeviceId) || (CompletionId != irp->CompletionId)) + { + log_error("DeviceId/CompletionId do not match those in IRP"); + return; + } + + if (IoStatus != 0) + { + log_error("BeginTransaction failed"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + con = (struct trans *) (irp->user_data); + scard_function_begin_transaction_return(con, s, len); + devredir_irp_delete(irp); + log_debug("leaving"); +} + +/** + * + *****************************************************************************/ +static void +scard_handle_EndTransaction_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus) +{ + tui32 len; + struct trans *con; + + log_debug("entered"); + + /* sanity check */ + if ((DeviceId != irp->DeviceId) || (CompletionId != irp->CompletionId)) + { + log_error("DeviceId/CompletionId do not match those in IRP"); + return; + } + + if (IoStatus != 0) + { + log_error("EndTransaction failed"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + con = (struct trans *) (irp->user_data); + scard_function_end_transaction_return(con, s, len); + devredir_irp_delete(irp); + log_debug("leaving"); +} + +/** + * + *****************************************************************************/ +static void +scard_handle_Status_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus) +{ + tui32 len; + struct trans *con; + + log_debug("entered"); + + /* sanity check */ + if ((DeviceId != irp->DeviceId) || (CompletionId != irp->CompletionId)) + { + log_error("DeviceId/CompletionId do not match those in IRP"); + return; + } + + if (IoStatus != 0) + { + log_error("StatusCall failed"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + con = (struct trans *) (irp->user_data); + scard_function_status_return(con, s, len); + devredir_irp_delete(irp); + log_debug("leaving"); +} + +/** + * + *****************************************************************************/ +static void +scard_handle_Disconnect_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus) +{ + tui32 len; + struct trans *con; + + log_debug("entered"); + + /* sanity check */ + if ((DeviceId != irp->DeviceId) || (CompletionId != irp->CompletionId)) + { + log_error("DeviceId/CompletionId do not match those in IRP"); + return; + } + + if (IoStatus != 0) + { + log_error("Disconnect failed"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + con = (struct trans *) (irp->user_data); + scard_function_disconnect_return(con, s, len); + devredir_irp_delete(irp); + log_debug("leaving"); +} + +/** + * + *****************************************************************************/ +static void APP_CC +scard_handle_Transmit_Return(struct stream *s, IRP *irp, tui32 DeviceId, + tui32 CompletionId, tui32 IoStatus) +{ + tui32 len; + struct trans *con; + + log_debug("entered"); + + /* sanity check */ + if ((DeviceId != irp->DeviceId) || (CompletionId != irp->CompletionId)) + { + log_error("DeviceId/CompletionId do not match those in IRP"); + return; + } + + if (IoStatus != 0) + { + log_error("Transmit failed"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + con = (struct trans *) (irp->user_data); + scard_function_transmit_return(con, s, len); + devredir_irp_delete(irp); + log_debug("leaving"); +} + +/** + * + *****************************************************************************/ +static void APP_CC +scard_handle_Control_Return(struct stream *s, IRP *irp, tui32 DeviceId, + tui32 CompletionId,tui32 IoStatus) +{ + tui32 len; + struct trans *con; + + log_debug("entered"); + + /* sanity check */ + if ((DeviceId != irp->DeviceId) || (CompletionId != irp->CompletionId)) + { + log_error("DeviceId/CompletionId do not match those in IRP"); + return; + } + + if (IoStatus != 0) + { + log_error("Control failed"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + con = (struct trans *) (irp->user_data); + scard_function_control_return(con, s, len); + devredir_irp_delete(irp); + log_debug("leaving"); +} + +/** + * + *****************************************************************************/ +static void APP_CC +scard_handle_Cancel_Return(struct stream *s, IRP *irp, tui32 DeviceId, + tui32 CompletionId, tui32 IoStatus) +{ + tui32 len; + struct trans *con; + + log_debug("entered"); + + /* sanity check */ + if ((DeviceId != irp->DeviceId) || (CompletionId != irp->CompletionId)) + { + log_error("DeviceId/CompletionId do not match those in IRP"); + return; + } + + if (IoStatus != 0) + { + log_error("Cancel_call failed"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + con = (struct trans *) (irp->user_data); + scard_function_cancel_return(con, s, len); + devredir_irp_delete(irp); + log_debug("leaving"); +} + +/** + * + *****************************************************************************/ +static void APP_CC +scard_handle_GetAttrib_Return(struct stream *s, IRP *irp, tui32 DeviceId, + tui32 CompletionId, tui32 IoStatus) +{ + tui32 len; + struct trans *con; + + log_debug("entered"); + + /* sanity check */ + if ((DeviceId != irp->DeviceId) || (CompletionId != irp->CompletionId)) + { + log_error("DeviceId/CompletionId do not match those in IRP"); + return; + } + + if (IoStatus != 0) + { + log_error("GetAttrib_call failed"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + con = (struct trans *) (irp->user_data); + scard_function_get_attrib_return(con, s, len); + devredir_irp_delete(irp); + log_debug("leaving"); } diff --git a/sesman/chansrv/smartcard.h b/sesman/chansrv/smartcard.h index a85b9f5f..88f4cdf6 100644 --- a/sesman/chansrv/smartcard.h +++ b/sesman/chansrv/smartcard.h @@ -26,26 +26,132 @@ #include "parse.h" #include "irp.h" +#include "trans.h" + +#define SCARD_SHARE_EXCLUSIVE 0x00000001 +#define SCARD_SHARE_SHARED 0x00000002 +#define SCARD_SHARE_DIRECT 0x00000003 + +/* see [MS-RDPESC] 2.2.5 protocol identifier - Table A */ +#define SCARD_PROTOCOL_UNDEFINED 0x00000000 +#define SCARD_PROTOCOL_T0 0x00000001 +#define SCARD_PROTOCOL_T1 0x00000002 +#define SCARD_PROTOCOL_Tx 0x00000003 +#define SCARD_PROTOCOL_RAW 0x00010000 + +/* see [MS-RDPESC] 2.2.5 protocol identifier - Table B */ +#define SCARD_PROTOCOL_DEFAULT 0x80000000 +#define SCARD_PROTOCOL_OPTIMAL 0x00000000 + +/* initialization type */ +#define SCARD_LEAVE_CARD 0x00000000 /* do not do anything */ +#define SCARD_RESET_CARD 0x00000001 /* reset smart card */ +#define SCARD_UNPOWER_CARD 0x00000002 /* turn off and reset card */ + +struct xrdp_scard_io_request +{ + tui32 dwProtocol; + tui32 cbPciLength; + int extra_bytes; + char *extra_data; +}; + +typedef struct reader_state +{ + char reader_name[128]; + tui32 current_state; + tui32 event_state; + tui32 atr_len; /* number of bytes in atr[] */ + tui8 atr[36]; + + /* + * share mode flag, can be one of: + * SCARD_SHARE_EXCLUSIVE app not willing to share smartcard with other apps + * SCARD_SHARE_SHARED app willing to share smartcard with other apps + * SCARD_SHARE_DIRECT app demands direct control of smart card, hence + * it is not available to other readers + */ + tui32 dwShareMode; + + /* + * This field MUST have a value from Table A which is logically + * OR'ed with a value from Table B. + */ + tui32 dwPreferredProtocols; + + /* + * initialization type, must be one of the initialization type + * defined above + */ + tui32 init_type; + + /* required by scard_send_transmit(), scard_send_control() */ + tui32 map0; + tui32 map1; + tui32 map2; + tui32 map3; + tui32 map4; + tui32 map5; + tui32 map6; + + tui32 dwProtocol; + tui32 cbPciLength; + tui32 cbSendLength; + tui32 cbRecvLength; + tui32 dwControlCode; + tui32 cbOutBufferSize; + tui32 dwAttribId; + tui32 dwAttrLen; + +} READER_STATE; -/* forward declarations */ void scard_device_announce(tui32 device_id); +int APP_CC scard_get_wait_objs(tbus *objs, int *count, int *timeout); +int APP_CC scard_check_wait_objs(void); +int APP_CC scard_init(void); +int APP_CC scard_deinit(void); +int APP_CC scard_send_establish_context(struct trans *con, int scope); +int APP_CC scard_send_release_context(struct trans *con, tui32 context); +int APP_CC scard_send_is_valid_context(struct trans *con, tui32 context); +int APP_CC scard_send_list_readers(struct trans *con, tui32 context, int wide); + +int APP_CC scard_send_get_status_change(struct trans *con, tui32 context, + int wide, tui32 timeout, + tui32 num_readers, READER_STATE* rsa); + +int APP_CC scard_send_connect(struct trans *con, tui32 context, int wide, + READER_STATE* rs); + +int APP_CC scard_send_reconnect(struct trans *con, tui32 context, + tui32 sc_handle, READER_STATE* rs); -/* callbacks into this module */ -void scard_handle_EstablishContext_Return(struct stream *s, IRP *irp, - tui32 DeviceId, tui32 CompletionId, - tui32 IoStatus); +int APP_CC scard_send_begin_transaction(struct trans *con, tui32 sc_handle); +int APP_CC scard_send_end_transaction(struct trans *con, tui32 sc_handle, + tui32 dwDisposition); +int APP_CC scard_send_status(struct trans *con, int wide, tui32 sc_handle, + int cchReaderLen, int cbAtrLen); +int APP_CC scard_send_disconnect(struct trans *con, tui32 context, + tui32 sc_handle, int dwDisposition); -void scard_handle_ListReaders_Return(struct stream *s, IRP *irp, - tui32 DeviceId, tui32 CompletionId, - tui32 IoStatus); +int APP_CC scard_send_transmit(struct trans *con, tui32 sc_handle, + char *send_data, int send_bytes, int recv_bytes, + struct xrdp_scard_io_request *send_ior, + struct xrdp_scard_io_request *recv_ior); -int APP_CC -scard_get_wait_objs(tbus *objs, int *count, int *timeout); -int APP_CC -scard_check_wait_objs(void); -int APP_CC -scard_init(void); -int APP_CC -scard_deinit(void); +int APP_CC scard_send_control(struct trans *con, tui32 context, tui32 sc_handle, + char *send_data, int send_bytes, + int recv_bytes, int control_code); +int APP_CC scard_send_cancel(struct trans *con, tui32 context); + +int APP_CC scard_send_get_attrib(struct trans *con, tui32 sc_handle, + READER_STATE* rs); + +/* + * Notes: + * SCardTransmit - partially done + * SCardControl - partially done + * SCardListReaderGroups - not supported + * SCardSetAttrib - not supported + */ #endif /* end #ifndef _SMARTCARD_C */ diff --git a/sesman/chansrv/smartcard_pcsc.c b/sesman/chansrv/smartcard_pcsc.c index a3a269d7..29f60c8d 100644 --- a/sesman/chansrv/smartcard_pcsc.c +++ b/sesman/chansrv/smartcard_pcsc.c @@ -20,8 +20,12 @@ /* * smartcard redirection support, PCSC daemon standin * this will act like pcsc daemon + * pcsc lib and daemon write struct on unix domain socket for communication */ +#define JAY_TODO_CONTEXT 0 +#define JAY_TODO_WIDE 1 + #define PCSC_STANDIN 1 #include "os_calls.h" @@ -30,77 +34,37 @@ #include "irp.h" #include "devredir.h" #include "trans.h" +#include "chansrv.h" #if PCSC_STANDIN -/* module based logging */ -#define LOG_ERROR 0 -#define LOG_INFO 1 -#define LOG_DEBUG 2 -#define LOG_LEVEL LOG_ERROR - -#define log_error(_params...) \ -{ \ - g_write("[%10.10u]: PCSC %s: %d : ERROR: ", \ - g_time3(), __func__, __LINE__); \ - g_writeln (_params); \ -} - -#define log_always(_params...) \ -{ \ - g_write("[%10.10u]: PCSC %s: %d : ALWAYS: ", \ - g_time3(), __func__, __LINE__); \ - g_writeln (_params); \ -} - -#define log_info(_params...) \ -{ \ - if (LOG_INFO <= LOG_LEVEL) \ - { \ - g_write("[%10.10u]: PCSC %s: %d : ", \ - g_time3(), __func__, __LINE__); \ - g_writeln (_params); \ - } \ -} - -#define log_debug(_params...) \ -{ \ - if (LOG_DEBUG <= LOG_LEVEL) \ - { \ - g_write("[%10.10u]: PCSC %s: %d : ", \ - g_time3(), __func__, __LINE__); \ - g_writeln (_params); \ - } \ -} - -#define PCSCLITE_MSG_KEY_LEN 16 -#define PCSCLITE_MAX_MESSAGE_SIZE 2048 - -struct version_struct -{ - tsi32 major; /**< IPC major \ref PROTOCOL_VERSION_MAJOR */ - tsi32 minor; /**< IPC minor \ref PROTOCOL_VERSION_MINOR */ - tui32 rv; -}; -typedef struct version_struct version_struct; +#define LLOG_LEVEL 1 +#define LLOGLN(_level, _args) \ + do \ + { \ + if (_level < LLOG_LEVEL) \ + { \ + g_write("chansrv:smartcard_pcsc [%10.10u]: ", g_time3()); \ + g_writeln _args ; \ + } \ + } \ + while (0) -struct rxSharedSegment -{ - tui32 mtype; /** one of the \c pcsc_adm_commands */ - tui32 user_id; - tui32 group_id; - tui32 command; /** one of the \c pcsc_msg_commands */ - tui64 date; - tui8 key[PCSCLITE_MSG_KEY_LEN]; /* 16 bytes */ - union _u - { - tui8 data[PCSCLITE_MAX_MESSAGE_SIZE]; - struct version_struct veStr; - } u; -}; -typedef struct rxSharedSegment sharedSegmentMsg, *psharedSegmentMsg; +#define XRDP_PCSC_STATE_NONE 0 +#define XRDP_PCSC_STATE_GOT_EC (1 << 0) /* establish context */ +#define XRDP_PCSC_STATE_GOT_LR (1 << 1) /* list readers */ +#define XRDP_PCSC_STATE_GOT_RC (1 << 2) /* release context */ +#define XRDP_PCSC_STATE_GOT_GSC (1 << 3) /* get status change */ +#define XRDP_PCSC_STATE_GOT_C (1 << 4) /* connect */ +#define XRDP_PCSC_STATE_GOT_BT (1 << 5) /* begin transaction */ +#define XRDP_PCSC_STATE_GOT_ET (1 << 6) /* end transaction */ +#define XRDP_PCSC_STATE_GOT_TR (1 << 7) /* transmit */ +#define XRDP_PCSC_STATE_GOT_CO (1 << 8) /* control */ +#define XRDP_PCSC_STATE_GOT_D (1 << 9) /* disconnect */ +#define XRDP_PCSC_STATE_GOT_ST (1 << 10) /* get status */ -#define RXSHAREDSEGMENT_BYTES 2088 +/* TODO: put this in con */ +static int g_xrdp_pcsc_state = XRDP_PCSC_STATE_NONE; extern int g_display_num; /* in chansrv.c */ @@ -110,20 +74,21 @@ struct pcsc_client struct trans *con; }; +#if 0 static struct pcsc_client *g_head = 0; static struct pcsc_client *g_tail = 0; +#endif static struct trans *g_lis = 0; static struct trans *g_con = 0; /* todo, remove this */ - -static char g_pcsc_directory[256] = ""; +static char g_pcsclite_ipc_dir[256] = ""; +static int g_pub_file_fd = 0; /*****************************************************************************/ int APP_CC scard_pcsc_get_wait_objs(tbus *objs, int *count, int *timeout) { - log_debug("scard_pcsc_get_wait_objs"); - + LLOGLN(10, ("scard_pcsc_get_wait_objs")); if (g_lis != 0) { trans_get_wait_objs(g_lis, objs, count); @@ -139,8 +104,7 @@ scard_pcsc_get_wait_objs(tbus *objs, int *count, int *timeout) int APP_CC scard_pcsc_check_wait_objs(void) { - log_debug("scard_pcsc_check_wait_objs"); - + LLOGLN(10, ("scard_pcsc_check_wait_objs")); if (g_lis != 0) { trans_check_wait_objs(g_lis); @@ -155,34 +119,955 @@ scard_pcsc_check_wait_objs(void) /*****************************************************************************/ /* returns error */ int APP_CC -scard_process_version(psharedSegmentMsg msg) +scard_process_establish_context(struct trans *con, struct stream *in_s) { + int dwScope; + + LLOGLN(10, ("scard_process_establish_context:")); + if (g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_EC) + { + LLOGLN(0, ("scard_process_establish_context: opps")); + return 1; + } + g_xrdp_pcsc_state |= XRDP_PCSC_STATE_GOT_EC; + in_uint32_le(in_s, dwScope); + LLOGLN(10, ("scard_process_establish_context: dwScope 0x%8.8x", dwScope)); + scard_send_establish_context(con, dwScope); return 0; } /*****************************************************************************/ /* returns error */ int APP_CC -scard_process_msg(struct stream *s) +scard_function_establish_context_return(struct trans *con, + struct stream *in_s, + int len) { - sharedSegmentMsg msg; - int rv; + int bytes; + tui32 context; + tui32 context_len; + struct stream *out_s; - g_memset(&msg, 0, sizeof(msg)); - in_uint32_le(s, msg.mtype); - in_uint32_le(s, msg.user_id); - in_uint32_le(s, msg.group_id); - in_uint32_le(s, msg.command); - in_uint64_le(s, msg.date); + LLOGLN(10, ("scard_function_establish_context_return:")); + if ((g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_EC) == 0) + { + LLOGLN(0, ("scard_function_establish_context_return: opps")); + return 1; + } + g_xrdp_pcsc_state &= ~XRDP_PCSC_STATE_GOT_EC; + in_uint8s(in_s, 28); + in_uint32_le(in_s, context_len); + if (context_len != 4) + { + LLOGLN(0, ("scard_function_establish_context_return: opps")); + return 1; + } + in_uint32_le(in_s, context); + LLOGLN(10, ("scard_function_establish_context_return: context 0x%8.8x", context)); + out_s = trans_get_out_s(con, 8192); + s_push_layer(out_s, iso_hdr, 8); + out_uint32_le(out_s, context); + out_uint32_le(out_s, 0); /* SCARD_S_SUCCESS status */ + s_mark_end(out_s); + bytes = (int) (out_s->end - out_s->data); + s_pop_layer(out_s, iso_hdr); + out_uint32_le(out_s, bytes - 8); + out_uint32_le(out_s, 0x01); /* SCARD_ESTABLISH_CONTEXT 0x01 */ + return trans_force_write(con); +} - log_debug("scard_process_msg: mtype 0x%2.2x command 0x%2.2x", - msg.mtype, msg.command); +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_process_release_context(struct trans *con, struct stream *in_s) +{ + int hContext; + + LLOGLN(10, ("scard_process_release_context:")); + if (g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_RC) + { + LLOGLN(0, ("scard_process_establish_context: opps")); + return 1; + } + g_xrdp_pcsc_state |= XRDP_PCSC_STATE_GOT_RC; + in_uint32_le(in_s, hContext); + LLOGLN(10, ("scard_process_release_context: hContext 0x%8.8x", hContext)); + scard_send_release_context(con, hContext); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_function_release_context_return(struct trans *con, + struct stream *in_s, + int len) +{ + int bytes; + struct stream *out_s; + + LLOGLN(10, ("scard_function_release_context_return:")); + if ((g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_RC) == 0) + { + LLOGLN(0, ("scard_function_release_context_return: opps")); + return 1; + } + g_xrdp_pcsc_state &= ~XRDP_PCSC_STATE_GOT_RC; + out_s = trans_get_out_s(con, 8192); + s_push_layer(out_s, iso_hdr, 8); + out_uint32_le(out_s, 0); /* SCARD_S_SUCCESS status */ + s_mark_end(out_s); + bytes = (int) (out_s->end - out_s->data); + s_pop_layer(out_s, iso_hdr); + out_uint32_le(out_s, bytes - 8); + out_uint32_le(out_s, 0x02); /* SCARD_RELEASE_CONTEXT 0x02 */ + return trans_force_write(con); +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_process_list_readers(struct trans *con, struct stream *in_s) +{ + int hContext; + + LLOGLN(10, ("scard_process_list_readers:")); + if (g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_LR) + { + LLOGLN(0, ("scard_process_list_readers: opps")); + return 1; + } + g_xrdp_pcsc_state |= XRDP_PCSC_STATE_GOT_LR; + in_uint32_le(in_s, hContext); + LLOGLN(10, ("scard_process_list_readers: dwScope 0x%8.8x", hContext)); + scard_send_list_readers(con, hContext, 1); + return 0; +} + +/*****************************************************************************/ +int APP_CC +scard_function_list_readers_return(struct trans *con, + struct stream *in_s, + int len) +{ + struct stream *out_s; + int chr; + int readers; + int rn_index; + int index; + int bytes; + twchar reader_name[100]; + char lreader_name[16][100]; + + LLOGLN(10, ("scard_function_list_readers_return:")); + //g_hexdump(in_s->p, len); + if ((g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_LR) == 0) + { + LLOGLN(0, ("scard_function_list_readers_return: opps")); + return 1; + } + g_xrdp_pcsc_state &= ~XRDP_PCSC_STATE_GOT_LR; + + g_memset(reader_name, 0, sizeof(reader_name)); + g_memset(lreader_name, 0, sizeof(lreader_name)); + in_uint8s(in_s, 28); + len -= 28; + in_uint32_le(in_s, len); + //g_writeln("len %d", len); + rn_index = 0; + readers = 0; + while (len > 0) + { + in_uint16_le(in_s, chr); + len -= 2; + if (chr == 0) + { + if (reader_name[0] != 0) + { + g_wcstombs(lreader_name[readers], reader_name, 99); + //g_writeln("1 %s", lreader_name[readers]); + g_memset(reader_name, 0, sizeof(reader_name)); + readers++; + } + reader_name[0] = 0; + rn_index = 0; + } + else + { + reader_name[rn_index] = chr; + rn_index++; + } + } + if (rn_index > 0) + { + if (reader_name[0] != 0) + { + g_wcstombs(lreader_name[readers], reader_name, 99); + //g_writeln("2 %s", lreader_name[readers]); + g_memset(reader_name, 0, sizeof(reader_name)); + readers++; + } + } + + out_s = trans_get_out_s(con, 8192); + s_push_layer(out_s, iso_hdr, 8); + out_uint32_le(out_s, readers); + for (index = 0; index < readers; index++) + { + //g_writeln("3 - %s", lreader_name[index]); + out_uint8a(out_s, lreader_name[index], 100); + } + out_uint32_le(out_s, 0); /* SCARD_S_SUCCESS status */ + s_mark_end(out_s); + bytes = (int) (out_s->end - out_s->data); + s_pop_layer(out_s, iso_hdr); + out_uint32_le(out_s, bytes - 8); + out_uint32_le(out_s, 0x03); /* SCARD_LIST_READERS 0x03 */ + return trans_force_write(con); +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_process_connect(struct trans *con, struct stream *in_s) +{ + int hContext; + READER_STATE rs; + LLOGLN(10, ("scard_process_connect:")); + if (g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_C) + { + LLOGLN(0, ("scard_process_connect: opps")); + return 1; + } + g_memset(&rs, 0, sizeof(rs)); + g_xrdp_pcsc_state |= XRDP_PCSC_STATE_GOT_C; + in_uint32_le(in_s, hContext); + in_uint8a(in_s, rs.reader_name, 100); + in_uint32_le(in_s, rs.dwShareMode); + in_uint32_le(in_s, rs.dwPreferredProtocols); + LLOGLN(10, ("scard_process_connect: rs.reader_name %s dwShareMode 0x%8.8x " + "dwPreferredProtocols 0x%8.8x", rs.reader_name, rs.dwShareMode, + rs.dwPreferredProtocols)); + scard_send_connect(con, hContext, 1, &rs); + return 0; +} + +/*****************************************************************************/ +int APP_CC +scard_function_connect_return(struct trans *con, + struct stream *in_s, + int len) +{ + int dwActiveProtocol; + int hCard; + int bytes; + struct stream *out_s; + + //g_hexdump(in_s->p, len); + if ((g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_C) == 0) + { + LLOGLN(0, ("scard_function_connect_return: opps")); + return 1; + } + g_xrdp_pcsc_state &= ~XRDP_PCSC_STATE_GOT_C; + in_uint8s(in_s, 36); + in_uint32_le(in_s, dwActiveProtocol); + in_uint8s(in_s, 4); + in_uint32_le(in_s, hCard); + LLOGLN(10, ("scard_function_connect_return: hCard %d dwActiveProtocol %d", hCard, dwActiveProtocol)); + out_s = trans_get_out_s(con, 8192); + s_push_layer(out_s, iso_hdr, 8); + out_uint32_le(out_s, hCard); + out_uint32_le(out_s, dwActiveProtocol); + out_uint32_le(out_s, 0); /* SCARD_S_SUCCESS status */ + s_mark_end(out_s); + bytes = (int) (out_s->end - out_s->data); + s_pop_layer(out_s, iso_hdr); + out_uint32_le(out_s, bytes - 8); + out_uint32_le(out_s, 0x04); /* SCARD_CONNECT 0x04 */ + return trans_force_write(con); +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_process_disconnect(struct trans *con, struct stream *in_s) +{ + int hContext; + int hCard; + int dwDisposition; + + LLOGLN(10, ("scard_process_disconnect:")); + if (g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_D) + { + LLOGLN(0, ("scard_process_disconnect: opps")); + return 1; + } + g_xrdp_pcsc_state |= XRDP_PCSC_STATE_GOT_D; + in_uint32_le(in_s, hCard); + in_uint32_le(in_s, dwDisposition); + + hContext = 1; + + scard_send_disconnect(con, hContext, hCard, dwDisposition); + + return 0; +} + +/*****************************************************************************/ +int APP_CC +scard_function_disconnect_return(struct trans *con, + struct stream *in_s, + int len) +{ + int dwActiveProtocol; + int hCard; + int bytes; + struct stream *out_s; + + //g_hexdump(in_s->p, len); + if ((g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_D) == 0) + { + LLOGLN(0, ("scard_function_connect_return: opps")); + return 1; + } + g_xrdp_pcsc_state &= ~XRDP_PCSC_STATE_GOT_D; + in_uint8s(in_s, 36); + in_uint32_le(in_s, dwActiveProtocol); + in_uint8s(in_s, 4); + in_uint32_le(in_s, hCard); + LLOGLN(10, ("scard_function_connect_return: hCard %d dwActiveProtocol %d", hCard, dwActiveProtocol)); + out_s = trans_get_out_s(con, 8192); + s_push_layer(out_s, iso_hdr, 8); + out_uint32_le(out_s, 0); /* SCARD_S_SUCCESS status */ + s_mark_end(out_s); + bytes = (int) (out_s->end - out_s->data); + s_pop_layer(out_s, iso_hdr); + out_uint32_le(out_s, bytes - 8); + out_uint32_le(out_s, 0x06); /* SCARD_DISCONNECT 0x06 */ + return trans_force_write(con); +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_process_begin_transaction(struct trans *con, struct stream *in_s) +{ + int hCard; + + LLOGLN(10, ("scard_process_begin_transaction:")); + if (g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_BT) + { + LLOGLN(0, ("scard_process_begin_transaction: opps")); + return 1; + } + g_xrdp_pcsc_state |= XRDP_PCSC_STATE_GOT_BT; + in_uint32_le(in_s, hCard); + LLOGLN(10, ("scard_process_begin_transaction: hCard 0x%8.8x", hCard)); + scard_send_begin_transaction(con, hCard); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_function_begin_transaction_return(struct trans *con, + struct stream *in_s, + int len) +{ + struct stream *out_s; + int bytes; + + //g_hexdump(in_s->p, len); + if ((g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_BT) == 0) + { + LLOGLN(0, ("scard_function_begin_transaction_return: opps")); + return 1; + } + g_xrdp_pcsc_state &= ~XRDP_PCSC_STATE_GOT_BT; + + out_s = trans_get_out_s(con, 8192); + s_push_layer(out_s, iso_hdr, 8); + out_uint32_le(out_s, 0); /* SCARD_S_SUCCESS status */ + s_mark_end(out_s); + bytes = (int) (out_s->end - out_s->data); + s_pop_layer(out_s, iso_hdr); + out_uint32_le(out_s, bytes - 8); + out_uint32_le(out_s, 0x07); /* SCARD_BEGIN_TRANSACTION 0x07 */ + return trans_force_write(con); +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_process_end_transaction(struct trans *con, struct stream *in_s) +{ + int hCard; + int dwDisposition; + + LLOGLN(10, ("scard_process_end_transaction:")); + if (g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_ET) + { + LLOGLN(0, ("scard_process_end_transaction: opps")); + return 1; + } + g_xrdp_pcsc_state |= XRDP_PCSC_STATE_GOT_ET; + in_uint32_le(in_s, hCard); + in_uint32_le(in_s, dwDisposition); + LLOGLN(10, ("scard_process_end_transaction: hCard 0x%8.8x", hCard)); + scard_send_end_transaction(con, hCard, dwDisposition); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_function_end_transaction_return(struct trans *con, + struct stream *in_s, + int len) +{ + struct stream *out_s; + int bytes; + + //g_hexdump(in_s->p, len); + if ((g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_ET) == 0) + { + LLOGLN(0, ("scard_function_end_transaction_return: opps")); + return 1; + } + g_xrdp_pcsc_state &= ~XRDP_PCSC_STATE_GOT_ET; + + out_s = trans_get_out_s(con, 8192); + s_push_layer(out_s, iso_hdr, 8); + out_uint32_le(out_s, 0); /* SCARD_S_SUCCESS status */ + s_mark_end(out_s); + bytes = (int) (out_s->end - out_s->data); + s_pop_layer(out_s, iso_hdr); + out_uint32_le(out_s, bytes - 8); + out_uint32_le(out_s, 0x08); /* SCARD_END_TRANSACTION 0x08 */ + return trans_force_write(con); +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_function_cancel_return(struct trans *con, + struct stream *in_s, + int len) +{ + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_function_get_attrib_return(struct trans *con, + struct stream *in_s, + int len) +{ + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_process_transmit(struct trans *con, struct stream *in_s) +{ + int hCard; + int recv_bytes; + int send_bytes; + char *send_data; + struct xrdp_scard_io_request send_ior; + struct xrdp_scard_io_request recv_ior; + + LLOGLN(10, ("scard_process_transmit:")); + if (g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_TR) + { + LLOGLN(0, ("scard_process_transmit: opps")); + return 1; + } + g_xrdp_pcsc_state |= XRDP_PCSC_STATE_GOT_TR; + LLOGLN(10, ("scard_process_transmit:")); + in_uint32_le(in_s, hCard); + in_uint32_le(in_s, send_ior.dwProtocol); + in_uint32_le(in_s, send_ior.cbPciLength); + in_uint32_le(in_s, send_ior.extra_bytes); + in_uint8p(in_s, send_ior.extra_data, send_ior.extra_bytes); + in_uint32_le(in_s, send_bytes); + in_uint8p(in_s, send_data, send_bytes); + in_uint32_le(in_s, recv_ior.dwProtocol); + in_uint32_le(in_s, recv_ior.cbPciLength); + in_uint32_le(in_s, recv_ior.extra_bytes); + in_uint8p(in_s, recv_ior.extra_data, recv_ior.extra_bytes); + in_uint32_le(in_s, recv_bytes); + LLOGLN(10, ("scard_process_transmit: send dwProtocol %d cbPciLength %d " + "recv dwProtocol %d cbPciLength %d send_bytes %d ", + send_ior.dwProtocol, send_ior.cbPciLength, recv_ior.dwProtocol, + recv_ior.cbPciLength, send_bytes)); + //g_hexdump(in_s->p, send_bytes); + LLOGLN(10, ("scard_process_transmit: recv_bytes %d", recv_bytes)); + scard_send_transmit(con, hCard, send_data, send_bytes, recv_bytes, + &send_ior, &recv_ior); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_function_transmit_return(struct trans *con, + struct stream *in_s, + int len) +{ + struct stream *out_s; + int bytes; + int val; + int cbRecvLength; + struct xrdp_scard_io_request recv_ior; + char *recvBuf; + + LLOGLN(10, ("scard_function_transmit_return:")); + //g_hexdump(in_s->p, len); + if ((g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_TR) == 0) + { + LLOGLN(0, ("scard_function_transmit_return: opps")); + return 1; + } + g_xrdp_pcsc_state &= ~XRDP_PCSC_STATE_GOT_TR; + + in_uint8s(in_s, 20); + in_uint32_le(in_s, val); + g_memset(&recv_ior, 0, sizeof(recv_ior)); + if (val != 0) + { + /* pioRecvPci */ + LLOGLN(0, ("scard_function_transmit_return: pioRecvPci not zero!")); + } + in_uint8s(in_s, 4); + in_uint32_le(in_s, val); + cbRecvLength = 0; + recvBuf = 0; + if (val != 0) + { + in_uint32_le(in_s, cbRecvLength); + in_uint8p(in_s, recvBuf, cbRecvLength); + } + LLOGLN(10, ("scard_function_transmit_return: cbRecvLength %d", cbRecvLength)); + out_s = trans_get_out_s(con, 8192); + s_push_layer(out_s, iso_hdr, 8); + out_uint32_le(out_s, recv_ior.dwProtocol); + out_uint32_le(out_s, recv_ior.cbPciLength); + out_uint32_le(out_s, recv_ior.extra_bytes); + out_uint8a(out_s, recv_ior.extra_data, recv_ior.extra_bytes); + out_uint32_le(out_s, cbRecvLength); + out_uint8a(out_s, recvBuf, cbRecvLength); + out_uint32_le(out_s, 0); /* SCARD_S_SUCCESS status */ + s_mark_end(out_s); + bytes = (int) (out_s->end - out_s->data); + s_pop_layer(out_s, iso_hdr); + out_uint32_le(out_s, bytes - 8); + out_uint32_le(out_s, 0x09); /* SCARD_TRANSMIT 0x09 */ + return trans_force_write(con); +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_process_control(struct trans *con, struct stream *in_s) +{ + tui32 context; + int hCard; + int send_bytes; + int recv_bytes; + int control_code; + char *send_data; + + LLOGLN(10, ("scard_process_control:")); + if (g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_CO) + { + LLOGLN(0, ("scard_process_control: opps")); + return 1; + } + g_xrdp_pcsc_state |= XRDP_PCSC_STATE_GOT_CO; + LLOGLN(10, ("scard_process_control:")); + + in_uint32_le(in_s, hCard); + in_uint32_le(in_s, control_code); + in_uint32_le(in_s, send_bytes); + in_uint8p(in_s, send_data, send_bytes); + in_uint32_le(in_s, recv_bytes); + + context = 1; + + scard_send_control(con, context, hCard, send_data, send_bytes, recv_bytes, + control_code); + + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_function_control_return(struct trans *con, + struct stream *in_s, + int len) +{ + struct stream *out_s; + int bytes; + int cbRecvLength; + char *recvBuf; + + //g_hexdump(in_s->p, len); + if ((g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_CO) == 0) + { + LLOGLN(0, ("scard_function_control_return: opps")); + return 1; + } + g_xrdp_pcsc_state &= ~XRDP_PCSC_STATE_GOT_CO; + + in_uint8s(in_s, 28); + in_uint32_le(in_s, cbRecvLength); + in_uint8p(in_s, recvBuf, cbRecvLength); + + LLOGLN(10, ("scard_function_control_return: cbRecvLength %d", cbRecvLength)); + out_s = trans_get_out_s(con, 8192); + s_push_layer(out_s, iso_hdr, 8); + out_uint32_le(out_s, cbRecvLength); + out_uint8a(out_s, recvBuf, cbRecvLength); + out_uint32_le(out_s, 0); /* SCARD_S_SUCCESS status */ + s_mark_end(out_s); + bytes = (int) (out_s->end - out_s->data); + s_pop_layer(out_s, iso_hdr); + out_uint32_le(out_s, bytes - 8); + out_uint32_le(out_s, 0x0A); /* SCARD_CONTROL 0x0A */ + return trans_force_write(con); +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_process_status(struct trans *con, struct stream *in_s) +{ + int hCard; + int cchReaderLen; + int cbAtrLen; + + LLOGLN(10, ("scard_process_status:")); + if (g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_ST) + { + LLOGLN(0, ("scard_process_status: opps")); + return 1; + } + g_xrdp_pcsc_state |= XRDP_PCSC_STATE_GOT_ST; + + in_uint32_le(in_s, hCard); + in_uint32_le(in_s, cchReaderLen); + in_uint32_le(in_s, cbAtrLen); + + scard_send_status(con, 1, hCard, cchReaderLen, cbAtrLen); + + return 0; +} + +#define MS_SCARD_UNKNOWN 0 +#define MS_SCARD_ABSENT 1 +#define MS_SCARD_PRESENT 2 +#define MS_SCARD_SWALLOWED 3 +#define MS_SCARD_POWERED 4 +#define MS_SCARD_NEGOTIABLE 5 +#define MS_SCARD_SPECIFIC 6 + +#define PC_SCARD_UNKNOWN 0x0001 /**< Unknown state */ +#define PC_SCARD_ABSENT 0x0002 /**< Card is absent */ +#define PC_SCARD_PRESENT 0x0004 /**< Card is present */ +#define PC_SCARD_SWALLOWED 0x0008 /**< Card not powered */ +#define PC_SCARD_POWERED 0x0010 /**< Card is powered */ +#define PC_SCARD_NEGOTIABLE 0x0020 /**< Ready for PTS */ +#define PC_SCARD_SPECIFIC 0x0040 /**< PTS has been set */ + +static int g_ms2pc[] = { PC_SCARD_UNKNOWN, PC_SCARD_ABSENT, + PC_SCARD_PRESENT, PC_SCARD_SWALLOWED, + PC_SCARD_POWERED, PC_SCARD_NEGOTIABLE, + PC_SCARD_SPECIFIC }; + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_function_status_return(struct trans *con, + struct stream *in_s, + int len) +{ + struct stream *out_s; + int index; + int bytes; + int dwReaderLen; + int dwState; + int dwProtocol; + int dwAtrLen; + char attr[32]; + twchar reader_name[100]; + char lreader_name[100]; + + //g_hexdump(in_s->p, len); + if ((g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_ST) == 0) + { + LLOGLN(0, ("scard_function_status_return: opps")); + return 1; + } + g_xrdp_pcsc_state &= ~XRDP_PCSC_STATE_GOT_ST; + in_uint8s(in_s, 20); + in_uint32_le(in_s, dwReaderLen); + in_uint8s(in_s, 4); + in_uint32_le(in_s, dwState); + dwState = g_ms2pc[dwState % 6]; + in_uint32_le(in_s, dwProtocol); + in_uint8a(in_s, attr, 32); + in_uint32_le(in_s, dwAtrLen); + in_uint32_le(in_s, dwReaderLen); + dwReaderLen /= 2; + g_memset(reader_name, 0, sizeof(reader_name)); + g_memset(lreader_name, 0, sizeof(lreader_name)); + for (index = 0; index < dwReaderLen; index++) + { + in_uint16_le(in_s, reader_name[index]); + } + g_wcstombs(lreader_name, reader_name, 99); + LLOGLN(10, ("scard_function_status_return: dwAtrLen %d dwReaderLen %d " + "dwProtocol %d dwState %d name %s", + dwAtrLen, dwReaderLen, dwProtocol, dwState, lreader_name)); + out_s = trans_get_out_s(con, 8192); + s_push_layer(out_s, iso_hdr, 8); + dwReaderLen = g_strlen(lreader_name); + out_uint32_le(out_s, dwReaderLen); + out_uint8a(out_s, lreader_name, dwReaderLen); + out_uint32_le(out_s, dwState); + out_uint32_le(out_s, dwProtocol); + out_uint32_le(out_s, dwAtrLen); + out_uint8a(out_s, attr, dwAtrLen); + out_uint32_le(out_s, 0); /* SCARD_S_SUCCESS status */ + s_mark_end(out_s); + bytes = (int) (out_s->end - out_s->data); + s_pop_layer(out_s, iso_hdr); + out_uint32_le(out_s, bytes - 8); + out_uint32_le(out_s, 0x0B); /* SCARD_STATUS 0x0B */ + return trans_force_write(con); +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_process_get_status_change(struct trans *con, struct stream *in_s) +{ + int index; + int hContext; + int dwTimeout; + int cReaders; + READER_STATE *rsa; + + LLOGLN(10, ("scard_process_get_status_change:")); + if (g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_GSC) + { + LLOGLN(0, ("scard_process_get_status_change: opps")); + return 1; + } + in_uint32_le(in_s, hContext); + in_uint32_le(in_s, dwTimeout); + in_uint32_le(in_s, cReaders); + if ((cReaders < 0) || (cReaders > 16)) + { + LLOGLN(0, ("scard_process_get_status_change: bad cReaders %d", cReaders)); + return 1; + } + rsa = (READER_STATE *) g_malloc(sizeof(READER_STATE) * cReaders, 1); + + for (index = 0; index < cReaders; index++) + { + in_uint8a(in_s, rsa[index].reader_name, 100); + LLOGLN(10, ("scard_process_get_status_change: reader_name %s", + rsa[index].reader_name)); + in_uint32_le(in_s, rsa[index].current_state); + LLOGLN(10, ("scard_process_get_status_change: current_state %d", + rsa[index].current_state)); + in_uint32_le(in_s, rsa[index].event_state); + LLOGLN(10, ("scard_process_get_status_change: event_state %d", + rsa[index].event_state)); + in_uint32_le(in_s, rsa[index].atr_len); + LLOGLN(10, ("scard_process_get_status_change: atr_len %d", + rsa[index].atr_len)); + in_uint8a(in_s, rsa[index].atr, 36); + } + + LLOGLN(10, ("scard_process_get_status_change: hContext 0x%8.8x dwTimeout " + "%d cReaders %d", hContext, dwTimeout, cReaders)); + + g_xrdp_pcsc_state |= XRDP_PCSC_STATE_GOT_GSC; + + scard_send_get_status_change(con, hContext, 1, dwTimeout, cReaders, rsa); + + g_free(rsa); + + return 0; +} + +/*****************************************************************************/ +int APP_CC +scard_function_get_status_change_return(struct trans *con, + struct stream *in_s, + int len) +{ + int bytes; + int index; + int cReaders; + tui32 current_state; + tui32 event_state; + tui32 atr_len; /* number of bytes in atr[] */ + tui8 atr[36]; + struct stream *out_s; + + LLOGLN(10, ("scard_function_get_status_change_return:")); + //g_hexdump(in_s->p, len); + if ((g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_GSC) == 0) + { + LLOGLN(0, ("scard_function_establish_context_return: opps")); + return 1; + } + g_xrdp_pcsc_state &= ~XRDP_PCSC_STATE_GOT_GSC; + in_uint8s(in_s, 28); + in_uint32_le(in_s, cReaders); + if (cReaders > 0) + { + out_s = trans_get_out_s(con, 8192); + s_push_layer(out_s, iso_hdr, 8); + out_uint32_le(out_s, cReaders); + for (index = 0; index < cReaders; index++) + { + in_uint32_le(in_s, current_state); + out_uint32_le(out_s, current_state); + in_uint32_le(in_s, event_state); + out_uint32_le(out_s, event_state); + in_uint32_le(in_s, atr_len); + out_uint32_le(out_s, atr_len); + in_uint8a(in_s, atr, 36); + out_uint8a(out_s, atr, 36); + } + out_uint32_le(out_s, 0); /* SCARD_S_SUCCESS status */ + s_mark_end(out_s); + bytes = (int) (out_s->end - out_s->data); + s_pop_layer(out_s, iso_hdr); + out_uint32_le(out_s, bytes - 8); + out_uint32_le(out_s, 0x0C); /* SCARD_ESTABLISH_CONTEXT 0x0C */ + return trans_force_write(con); + } + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_function_is_context_valid_return(struct trans *con, + struct stream *in_s, + int len) +{ + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC scard_function_reconnect_return(struct trans *con, + struct stream *in_s, + int len) +{ + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_process_msg(struct trans *con, struct stream *in_s, int command) +{ + int rv; + + LLOGLN(10, ("scard_process_msg: command 0x%4.4x", command)); rv = 0; - switch (msg.mtype) + switch (command) { - case 0xF8: /* CMD_VERSION */ - rv = scard_process_version(&msg); + case 0x01: /* SCARD_ESTABLISH_CONTEXT */ + LLOGLN(10, ("scard_process_msg: SCARD_ESTABLISH_CONTEXT")); + rv = scard_process_establish_context(con, in_s); + break; + case 0x02: /* SCARD_RELEASE_CONTEXT */ + LLOGLN(10, ("scard_process_msg: SCARD_RELEASE_CONTEXT")); + rv = scard_process_release_context(con, in_s); + break; + + case 0x03: /* SCARD_LIST_READERS */ + LLOGLN(10, ("scard_process_msg: SCARD_LIST_READERS")); + rv = scard_process_list_readers(con, in_s); + break; + + case 0x04: /* SCARD_CONNECT */ + LLOGLN(10, ("scard_process_msg: SCARD_CONNECT")); + rv = scard_process_connect(con, in_s); + break; + + case 0x05: /* SCARD_RECONNECT */ + LLOGLN(0, ("scard_process_msg: SCARD_RECONNECT")); + break; + + case 0x06: /* SCARD_DISCONNECT */ + LLOGLN(10, ("scard_process_msg: SCARD_DISCONNECT")); + rv = scard_process_disconnect(con, in_s); + break; + + case 0x07: /* SCARD_BEGIN_TRANSACTION */ + LLOGLN(10, ("scard_process_msg: SCARD_BEGIN_TRANSACTION")); + rv = scard_process_begin_transaction(con, in_s); + break; + + case 0x08: /* SCARD_END_TRANSACTION */ + LLOGLN(10, ("scard_process_msg: SCARD_END_TRANSACTION")); + rv = scard_process_end_transaction(con, in_s); + break; + + case 0x09: /* SCARD_TRANSMIT */ + LLOGLN(10, ("scard_process_msg: SCARD_TRANSMIT")); + rv = scard_process_transmit(con, in_s); + break; + + case 0x0A: /* SCARD_CONTROL */ + LLOGLN(10, ("scard_process_msg: SCARD_CONTROL")); + rv = scard_process_control(con, in_s); + break; + + case 0x0B: /* SCARD_STATUS */ + LLOGLN(10, ("scard_process_msg: SCARD_STATUS")); + rv = scard_process_status(con, in_s); + break; + + case 0x0C: /* SCARD_GET_STATUS_CHANGE */ + LLOGLN(10, ("scard_process_msg: SCARD_GET_STATUS_CHANGE")); + rv = scard_process_get_status_change(con, in_s); + break; + + case 0x0D: /* SCARD_CANCEL */ + LLOGLN(0, ("scard_process_msg: SCARD_CANCEL")); + break; + + case 0x0E: /* SCARD_CANCEL_TRANSACTION */ + LLOGLN(0, ("scard_process_msg: SCARD_CANCEL_TRANSACTION")); + break; + + case 0x0F: /* SCARD_GET_ATTRIB */ + LLOGLN(0, ("scard_process_msg: SCARD_GET_ATTRIB")); + break; + + case 0x10: /* SCARD_SET_ATTRIB */ + LLOGLN(0, ("scard_process_msg: SCARD_SET_ATTRIB")); + break; + + default: + LLOGLN(0, ("scard_process_msg: unknown mtype 0x%4.4x", command)); + rv = 1; break; } return rv; @@ -194,24 +1079,28 @@ int DEFAULT_CC my_pcsc_trans_data_in(struct trans *trans) { struct stream *s; - int id; int size; + int command; int error; - log_debug("my_pcsc_trans_data_in:"); - + LLOGLN(10, ("my_pcsc_trans_data_in:")); if (trans == 0) { return 0; } - if (trans != g_con) { return 1; } s = trans_get_in_s(trans); - g_hexdump(s->p, 64); - error = scard_process_msg(s); + in_uint32_le(s, size); + in_uint32_le(s, command); + LLOGLN(10, ("my_pcsc_trans_data_in: size %d command %d", size, command)); + error = trans_force_read(trans, size); + if (error == 0) + { + error = scard_process_msg(g_con, s, command); + } return error; } @@ -220,7 +1109,7 @@ my_pcsc_trans_data_in(struct trans *trans) int DEFAULT_CC my_pcsc_trans_conn_in(struct trans *trans, struct trans *new_trans) { - log_debug("my_pcsc_trans_conn_in:"); + LLOGLN(10, ("my_pcsc_trans_conn_in:")); if (trans == 0) { @@ -239,11 +1128,7 @@ my_pcsc_trans_conn_in(struct trans *trans, struct trans *new_trans) g_con = new_trans; g_con->trans_data_in = my_pcsc_trans_data_in; - g_con->header_size = RXSHAREDSEGMENT_BYTES; - - log_debug("my_pcsc_trans_conn_in: sizeof sharedSegmentMsg is %d", - sizeof(sharedSegmentMsg)); - + g_con->header_size = 8; return 0; } @@ -252,33 +1137,39 @@ int APP_CC scard_pcsc_init(void) { char port[256]; + char *home; + int disp; int error; - log_debug("scard_pcsc_init:"); - + LLOGLN(0, ("scard_pcsc_init:")); if (g_lis == 0) { g_lis = trans_create(2, 8192, 8192); - g_snprintf(g_pcsc_directory, 255, "/tmp/.xrdp/pcsc%d", g_display_num); - if (g_directory_exist(g_pcsc_directory)) + + //g_snprintf(g_pcsclite_ipc_dir, 255, "/tmp/.xrdp/pcsc%d", g_display_num); + home = g_getenv("HOME"); + disp = g_display_num; + g_snprintf(g_pcsclite_ipc_dir, 255, "%s/.pcsc%d", home, disp); + + if (g_directory_exist(g_pcsclite_ipc_dir)) { - if (g_remove_dir(g_pcsc_directory) != 0) + if (g_remove_dir(g_pcsclite_ipc_dir) != 0) { - log_error("scard_pcsc_init: g_remove_dir failed"); + LLOGLN(0, ("scard_pcsc_init: g_remove_dir failed")); } } - if (g_create_dir(g_pcsc_directory) != 0) + if (!g_create_dir(g_pcsclite_ipc_dir)) { - log_error("scard_pcsc_init: g_create_dir failed"); + LLOGLN(0, ("scard_pcsc_init: g_create_dir failed")); } - g_chmod_hex(g_pcsc_directory, 0x1777); - g_snprintf(port, 255, "%s/pcscd.comm", g_pcsc_directory); + g_chmod_hex(g_pcsclite_ipc_dir, 0x1777); + g_snprintf(port, 255, "%s/pcscd.comm", g_pcsclite_ipc_dir); g_lis->trans_conn_in = my_pcsc_trans_conn_in; error = trans_listen(g_lis, port); if (error != 0) { - log_error("scard_pcsc_init: trans_listen failed for port %s", - port); + LLOGLN(0, ("scard_pcsc_init: trans_listen failed for port %s", + port)); return 1; } } @@ -289,17 +1180,20 @@ scard_pcsc_init(void) int APP_CC scard_pcsc_deinit(void) { - log_debug("scard_pcsc_deinit:"); - + LLOGLN(0, ("scard_pcsc_deinit:")); if (g_lis != 0) { trans_delete(g_lis); g_lis = 0; - if (g_remove_dir(g_pcsc_directory) != 0) + + g_file_close(g_pub_file_fd); + g_pub_file_fd = 0; + + if (g_remove_dir(g_pcsclite_ipc_dir) != 0) { - log_error("scard_pcsc_deinit: g_remove_dir failed"); + LLOGLN(0, ("scard_pcsc_deinit: g_remove_dir failed")); } - g_pcsc_directory[0] = 0; + g_pcsclite_ipc_dir[0] = 0; } return 0; } diff --git a/sesman/chansrv/smartcard_pcsc.h b/sesman/chansrv/smartcard_pcsc.h index a97a70d3..bd5b9090 100644 --- a/sesman/chansrv/smartcard_pcsc.h +++ b/sesman/chansrv/smartcard_pcsc.h @@ -24,13 +24,66 @@ #ifndef _SMARTCARD_PCSC_H #define _SMARTCARD_PCSC_H -int APP_CC -scard_pcsc_get_wait_objs(tbus *objs, int *count, int *timeout); -int APP_CC -scard_pcsc_check_wait_objs(void); -int APP_CC -scard_pcsc_init(void); -int APP_CC -scard_pcsc_deinit(void); +int APP_CC scard_pcsc_get_wait_objs(tbus *objs, int *count, int *timeout); +int APP_CC scard_pcsc_check_wait_objs(void); +int APP_CC scard_pcsc_init(void); +int APP_CC scard_pcsc_deinit(void); +int APP_CC scard_function_establish_context_return(struct trans *con, + struct stream *in_s, + int len); +int APP_CC scard_function_release_context_return(struct trans *con, + struct stream *in_s, + int len); +int APP_CC scard_function_list_readers_return(struct trans *con, + struct stream *in_s, + int len); + +int APP_CC scard_function_transmit_return(struct trans *con, + struct stream *in_s, + int len); + +int APP_CC scard_function_control_return(struct trans *con, + struct stream *in_s, + int len); + +int APP_CC scard_function_get_status_change_return(struct trans *con, + struct stream *in_s, + int len); + +int APP_CC scard_function_connect_return(struct trans *con, + struct stream *in_s, + int len); + +int APP_CC scard_function_status_return(struct trans *con, + struct stream *in_s, + int len); + +int APP_CC scard_function_begin_transaction_return(struct trans *con, + struct stream *in_s, + int len); + +int APP_CC scard_function_end_transaction_return(struct trans *con, + struct stream *in_s, + int len); + +int APP_CC scard_function_is_context_valid_return(struct trans *con, + struct stream *in_s, + int len); + +int APP_CC scard_function_reconnect_return(struct trans *con, + struct stream *in_s, + int len); + +int APP_CC scard_function_disconnect_return(struct trans *con, + struct stream *in_s, + int len); + +int APP_CC scard_function_cancel_return(struct trans *con, + struct stream *in_s, + int len); + +int APP_CC scard_function_get_attrib_return(struct trans *con, + struct stream *in_s, + int len); #endif /* end #ifndef _SMARTCARD_PCSC_H */ diff --git a/sesman/chansrv/sound.c b/sesman/chansrv/sound.c index 9ee3c8c3..2e85f1f2 100644 --- a/sesman/chansrv/sound.c +++ b/sesman/chansrv/sound.c @@ -551,7 +551,8 @@ sound_init(void) LOG(0, ("sound_init:")); sound_send_server_formats(); - g_audio_l_trans = trans_create(2, 128 * 1024, 8192); + g_audio_l_trans = trans_create(TRANS_MODE_UNIX, 128 * 1024, 8192); + g_audio_l_trans->is_term = g_is_term; g_snprintf(port, 255, CHANSRV_PORT_STR, g_display_num); g_audio_l_trans->trans_conn_in = sound_trans_audio_conn_in; error = trans_listen(g_audio_l_trans, port); diff --git a/sesman/chansrv/xcommon.c b/sesman/chansrv/xcommon.c index c5a91cae..919bc41b 100644 --- a/sesman/chansrv/xcommon.c +++ b/sesman/chansrv/xcommon.c @@ -25,8 +25,10 @@ #include "clipboard.h" #include "rail.h" +/* #undef LOG_LEVEL #define LOG_LEVEL 11 +*/ extern int g_clip_up; /* in clipboard.c */ @@ -40,6 +42,9 @@ int g_screen_num = 0; Window g_root_window = 0; Atom g_wm_delete_window_atom = 0; Atom g_wm_protocols_atom = 0; +Atom g_utf8_string = 0; +Atom g_net_wm_name = 0; +Atom g_wm_state = 0; /*****************************************************************************/ static int DEFAULT_CC @@ -117,7 +122,10 @@ xcommon_init(void) g_wm_delete_window_atom = XInternAtom(g_display, "WM_DELETE_WINDOW", 0); g_wm_protocols_atom = XInternAtom(g_display, "WM_PROTOCOLS", 0); - + g_utf8_string = XInternAtom(g_display, "UTF8_STRING", 0); + g_net_wm_name = XInternAtom(g_display, "_NET_WM_NAME", 0); + g_wm_state = XInternAtom(g_display, "WM_STATE", 0); + return 0; } diff --git a/sesman/config.c b/sesman/config.c index c7c3de24..877a949c 100644 --- a/sesman/config.c +++ b/sesman/config.c @@ -130,7 +130,7 @@ config_read_globals(int file, struct config_sesman *cf, struct list *param_n, } else if (0 == g_strcasecmp(buf, SESMAN_CFG_ENABLE_USERWM)) { - cf->enable_user_wm = text2bool((char *)list_get_item(param_v, i)); + cf->enable_user_wm = g_text2bool((char *)list_get_item(param_v, i)); } else if (0 == g_strcasecmp(buf, SESMAN_CFG_PORT)) { @@ -212,7 +212,7 @@ config_read_logging(int file, struct log_config* lc, struct list* param_n, } if (0 == g_strcasecmp(buf, SESMAN_CFG_LOG_ENABLE_SYSLOG)) { - lc->enable_syslog = text2bool((char*)list_get_item(param_v, i)); + lc->enable_syslog = g_text2bool((char*)list_get_item(param_v, i)); } if (0 == g_strcasecmp(buf, SESMAN_CFG_LOG_SYSLOG_LEVEL)) { @@ -261,7 +261,7 @@ config_read_security(int file, struct config_security *sc, if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_ALLOW_ROOT)) { - sc->allow_root = text2bool((char *)list_get_item(param_v, i)); + sc->allow_root = g_text2bool((char *)list_get_item(param_v, i)); } if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_LOGIN_RETRY)) @@ -288,7 +288,7 @@ config_read_security(int file, struct config_security *sc, } if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_ALWAYSGROUPCHECK)) { - sc->ts_always_group_check = text2bool((char *)list_get_item(param_v, i)); + sc->ts_always_group_check = g_text2bool((char *)list_get_item(param_v, i)); } } @@ -355,7 +355,7 @@ config_read_sessions(int file, struct config_sessions *se, struct list *param_n, if (0 == g_strcasecmp(buf, SESMAN_CFG_SESS_KILL_DISC)) { - se->kill_disconnected = text2bool((char *)list_get_item(param_v, i)); + se->kill_disconnected = g_text2bool((char *)list_get_item(param_v, i)); } if (0 == g_strcasecmp(buf, SESMAN_CFG_SESS_IDLE_LIMIT)) diff --git a/sesman/sesman.ini b/sesman/sesman.ini index 571e063b..02fef5ba 100644 --- a/sesman/sesman.ini +++ b/sesman/sesman.ini @@ -17,8 +17,13 @@ AlwaysGroupCheck = false [Sessions] X11DisplayOffset=10 MaxSessions=10 +# if 1, true, or yes, kill session after 60 seconds KillDisconnected=0 +# if not zero, the seconds without mouse or keyboard input before disconnect +# not complete yet IdleTimeLimit=0 +# if not zero, the seconds before a disconnected session is killed +# min 60 seconds DisconnectedTimeLimit=0 [Logging] diff --git a/sesman/session.c b/sesman/session.c index 888604da..a5932736 100644 --- a/sesman/session.c +++ b/sesman/session.c @@ -62,11 +62,11 @@ static int g_sync_cmd; char *APP_CC dumpItemsToString(struct list *self, char *outstr, int len) { - g_memset(outstr, 0, len); int index; tbus item; int totalLen = 0; + g_memset(outstr, 0, len); if (self->count == 0) { g_writeln("List is empty"); @@ -385,6 +385,7 @@ session_start_fork(int width, int height, int bpp, char *username, int display = 0; int pid = 0; int wmpid = 0; + int pampid = 0; int xpid = 0; int i = 0; char geometry[32]; @@ -453,99 +454,105 @@ session_start_fork(int width, int height, int bpp, char *username, { g_tcp_close(g_sck); g_tcp_close(g_thread_sck); - auth_start_session(data, display); g_sprintf(geometry, "%dx%d", width, height); g_sprintf(depth, "%d", bpp); g_sprintf(screen, ":%d", display); wmpid = g_fork(); - if (wmpid == -1) { } else if (wmpid == 0) /* child (child sesman) xserver */ { wait_for_xserver(display); - env_set_user(username, 0, display); - - if (x_server_running(display)) + auth_start_session(data, display); + pampid = g_fork(); + if (pampid == -1) { - auth_set_env(data); - - if (directory != 0) + } + else if (pampid == 0) /* child: X11/client */ + { + env_set_user(username, 0, display); + if (x_server_running(display)) { - if (directory[0] != 0) + auth_set_env(data); + if (directory != 0) { - g_set_current_dir(directory); + if (directory[0] != 0) + { + g_set_current_dir(directory); + } } - } - - if (program != 0) - { - if (program[0] != 0) + if (program != 0) { - g_execlp3(program, program, 0); - log_message(LOG_LEVEL_ALWAYS, - "error starting program %s for user %s - pid %d", - program, username, g_getpid()); + if (program[0] != 0) + { + g_execlp3(program, program, 0); + log_message(LOG_LEVEL_ALWAYS, + "error starting program %s for user %s - pid %d", + program, username, g_getpid()); + } } - } - - /* try to execute user window manager if enabled */ - if (g_cfg->enable_user_wm) - { - g_sprintf(text, "%s/%s", g_getenv("HOME"), g_cfg->user_wm); - - if (g_file_exist(text)) + /* try to execute user window manager if enabled */ + if (g_cfg->enable_user_wm) { - g_execlp3(text, g_cfg->user_wm, 0); - log_message(LOG_LEVEL_ALWAYS, "error starting user " - "wm for user %s - pid %d", username, g_getpid()); - /* logging parameters */ - log_message(LOG_LEVEL_DEBUG, "errno: %d, " - "description: %s", errno, g_get_strerror()); - log_message(LOG_LEVEL_DEBUG, "execlp3 parameter " - "list:"); - log_message(LOG_LEVEL_DEBUG, " argv[0] = %s", - text); - log_message(LOG_LEVEL_DEBUG, " argv[1] = %s", - g_cfg->user_wm); + g_sprintf(text, "%s/%s", g_getenv("HOME"), g_cfg->user_wm); + if (g_file_exist(text)) + { + g_execlp3(text, g_cfg->user_wm, 0); + log_message(LOG_LEVEL_ALWAYS, "error starting user " + "wm for user %s - pid %d", username, g_getpid()); + /* logging parameters */ + log_message(LOG_LEVEL_DEBUG, "errno: %d, " + "description: %s", errno, g_get_strerror()); + log_message(LOG_LEVEL_DEBUG, "execlp3 parameter " + "list:"); + log_message(LOG_LEVEL_DEBUG, " argv[0] = %s", + text); + log_message(LOG_LEVEL_DEBUG, " argv[1] = %s", + g_cfg->user_wm); + } } + /* if we're here something happened to g_execlp3 + so we try running the default window manager */ + g_sprintf(text, "%s/%s", XRDP_CFG_PATH, g_cfg->default_wm); + g_execlp3(text, g_cfg->default_wm, 0); + + log_message(LOG_LEVEL_ALWAYS, "error starting default " + "wm for user %s - pid %d", username, g_getpid()); + /* logging parameters */ + log_message(LOG_LEVEL_DEBUG, "errno: %d, description: " + "%s", errno, g_get_strerror()); + log_message(LOG_LEVEL_DEBUG, "execlp3 parameter list:"); + log_message(LOG_LEVEL_DEBUG, " argv[0] = %s", + text); + log_message(LOG_LEVEL_DEBUG, " argv[1] = %s", + g_cfg->default_wm); + + /* still a problem starting window manager just start xterm */ + g_execlp3("xterm", "xterm", 0); + + /* should not get here */ + log_message(LOG_LEVEL_ALWAYS, "error starting xterm " + "for user %s - pid %d", username, g_getpid()); + /* logging parameters */ + log_message(LOG_LEVEL_DEBUG, "errno: %d, description: " + "%s", errno, g_get_strerror()); + } + else + { + log_message(LOG_LEVEL_ERROR, "another Xserver might " + "already be active on display %d - see log", display); } - /* if we're here something happened to g_execlp3 - so we try running the default window manager */ - g_sprintf(text, "%s/%s", XRDP_CFG_PATH, g_cfg->default_wm); - g_execlp3(text, g_cfg->default_wm, 0); - - log_message( LOG_LEVEL_ALWAYS, "error starting default " - "wm for user %s - pid %d", username, g_getpid()); - /* logging parameters */ - log_message( LOG_LEVEL_DEBUG, "errno: %d, description: " - "%s", errno, g_get_strerror()); - log_message(LOG_LEVEL_DEBUG, "execlp3 parameter list:"); - log_message(LOG_LEVEL_DEBUG, " argv[0] = %s", - text); - log_message(LOG_LEVEL_DEBUG, " argv[1] = %s", - g_cfg->default_wm); - - /* still a problem starting window manager just start xterm */ - g_execlp3("xterm", "xterm", 0); - - /* should not get here */ - log_message(LOG_LEVEL_ALWAYS, "error starting xterm " - "for user %s - pid %d", username, g_getpid()); - /* logging parameters */ - log_message(LOG_LEVEL_DEBUG, "errno: %d, description: " - "%s", errno, g_get_strerror()); + log_message(LOG_LEVEL_DEBUG, "aborting connection..."); + g_exit(0); } else { - log_message(LOG_LEVEL_ERROR, "another Xserver might " - "already be active on display %d - see log", display); + g_waitpid(pampid); + auth_stop_session(data); + g_exit(0); } - - log_message(LOG_LEVEL_DEBUG, "aborting connection..."); - g_exit(0); } else /* parent (child sesman) */ { @@ -559,6 +566,13 @@ session_start_fork(int width, int height, int bpp, char *username, env_set_user(username, passwd_file, display); env_check_password_file(passwd_file, password); + g_snprintf(text, 255, "%d", g_cfg->sess.max_idle_time); + g_setenv("XRDP_SESMAN_MAX_IDLE_TIME", text, 1); + g_snprintf(text, 255, "%d", g_cfg->sess.max_disc_time); + g_setenv("XRDP_SESMAN_MAX_DISC_TIME", text, 1); + g_snprintf(text, 255, "%d", g_cfg->sess.kill_disconnected); + g_setenv("XRDP_SESMAN_KILL_DISCONNECTED", text, 1); + if (type == SESMAN_SESSION_TYPE_XVNC) { xserver_params = list_create(); diff --git a/sesman/verify_user_kerberos.c b/sesman/verify_user_kerberos.c index a6480f56..bb7ba3d2 100644 --- a/sesman/verify_user_kerberos.c +++ b/sesman/verify_user_kerberos.c @@ -431,6 +431,14 @@ auth_start_session(void) } /******************************************************************************/ +/* returns error */ +int DEFAULT_CC +auth_stop_session(long in_val) +{ + return 0; +} + +/******************************************************************************/ int DEFAULT_CC auth_end(void) { diff --git a/sesman/verify_user_pam.c b/sesman/verify_user_pam.c index e53f72d5..4d73f85d 100644 --- a/sesman/verify_user_pam.c +++ b/sesman/verify_user_pam.c @@ -203,6 +203,26 @@ auth_start_session(long in_val, int in_display) /******************************************************************************/ /* returns error */ +int DEFAULT_CC +auth_stop_session(long in_val) +{ + struct t_auth_info *auth_info; + int error; + + auth_info = (struct t_auth_info *)in_val; + error = pam_close_session(auth_info->ph, 0); + if (error != PAM_SUCCESS) + { + g_printf("pam_close_session failed: %s\r\n", + pam_strerror(auth_info->ph, error)); + return 1; + } + auth_info->session_opened = 0; + return 0; +} + +/******************************************************************************/ +/* returns error */ /* cleanup */ int DEFAULT_CC auth_end(long in_val) diff --git a/sesman/verify_user_pam_userpass.c b/sesman/verify_user_pam_userpass.c index 7f31176e..b3d4de73 100644 --- a/sesman/verify_user_pam_userpass.c +++ b/sesman/verify_user_pam_userpass.c @@ -91,6 +91,14 @@ auth_start_session(void) } /******************************************************************************/ +/* returns error */ +int DEFAULT_CC +auth_stop_session(long in_val) +{ + return 0; +} + +/******************************************************************************/ int DEFAULT_CC auth_end(void) { diff --git a/tcutils/README.txt b/tcutils/README.txt new file mode 100644 index 00000000..de75f1b2 --- /dev/null +++ b/tcutils/README.txt @@ -0,0 +1,29 @@ +A QT based utility program for thinclients using xrdp and NeutrinoRDP + +This program sends commands to NeutrinoRDP to do something +useful on the client end (such as unmounting a USB drive, +or powering down the client) + +Required packages to build tcutils: +----------------------------------- +libqt4-gui +qt4-dev-tools + +to build tcutils: +----------------- +qmake +make + +To run tcutils: +--------------- +include xrdpapi/.libs in your LD_LIBRARY_PATH + +Example: +-------- +export LD_LIBRARY_PATH=../xrdpapi/.libs +run tcutils inside the xfreerdp session + +this is how we run xfreerdp: +---------------------------- +./xfreerdp --sec rdp --plugin tcutils 192.168.2.149 + diff --git a/tcutils/main.cpp b/tcutils/main.cpp new file mode 100644 index 00000000..d951345f --- /dev/null +++ b/tcutils/main.cpp @@ -0,0 +1,11 @@ +#include <QtGui/QApplication> +#include "mainwindow.h" + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.show(); + + return a.exec(); +} diff --git a/tcutils/mainwindow.cpp b/tcutils/mainwindow.cpp new file mode 100644 index 00000000..8cc0a988 --- /dev/null +++ b/tcutils/mainwindow.cpp @@ -0,0 +1,234 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" + +MainWindow::MainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::MainWindow) +{ + ui->setupUi(this); + + wtsChannel = NULL; + okToQuit = false; + savedGeometry = this->geometry(); + + /* setup tab to unmount drives */ + ui->tabWidget->setTabText(0, "Unmount drives"); + connect(ui->btnRefresh, SIGNAL(clicked()), this, SLOT(onBtnRefreshClicked())); + connect(ui->btnUnmount, SIGNAL(clicked()), this, SLOT(onBtnUnmountClicked())); + + ui->tabWidget->setTabText(1, ""); + if (initWtsChannel()) + { + okToQuit = true; + QTimer::singleShot(10, qApp, SLOT(quit())); + return; + } + setupSystemTray(); + + /* set up status bar to display messages */ + statusBar = new QStatusBar; + this->setStatusBar(statusBar); + setStatusMsg("Connected to client"); +} + +MainWindow::~MainWindow() +{ + delete ui; +} + +void MainWindow::setupSystemTray() +{ + trayMenu = new QMenu(this); + trayMenu->addAction("Launch Thinclient Utils", this, SLOT(onActionLaunch())); + trayMenu->addSeparator(); + trayMenu->addAction("Quit", this, SLOT(onActionQuit())); + + trayIcon = new QSystemTrayIcon; + trayIcon->setContextMenu(trayMenu); + trayIcon->setIcon(QIcon(":/images/resources/images/tools.gif")); + + trayIcon->show(); + + trayIcon->showMessage("TCutils", "Click on the tcutils icon to launch tcutils", + QSystemTrayIcon::Information, 3000); + + connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), + this, SLOT(onSystemTrayClicked(QSystemTrayIcon::ActivationReason))); +} + +/** + * + *****************************************************************************/ + +int MainWindow::initWtsChannel() +{ + /* init the channel just once */ + if (wtsChannel) + return 0; + + /* open a WTS channel and connect to remote client */ + wtsChannel = WTSVirtualChannelOpenEx(WTS_CURRENT_SESSION, "tcutils", 0); + if (wtsChannel == NULL) + { + QMessageBox::information(this, "Open virtual channel", "Error " + "connecting to remote client. This program " + "can only be used when connected via " + "NeutrinoRDP.\n\nClick ok to close this " + "application"); + return -1; + } + + return 0; +} + +/** + * + *****************************************************************************/ + +int MainWindow::deinitWtsChannel() +{ + if (!wtsChannel) + return -1; + + WTSVirtualChannelClose(wtsChannel); + return 0; +} + +/** + * Display a msg on the status bar + * + * @param msg message to display in status bar + *****************************************************************************/ + +void MainWindow::setStatusMsg(QString msg) +{ + statusBar->showMessage(msg, 30000); +} + +/** + * + *****************************************************************************/ + +void MainWindow::closeEvent(QCloseEvent *event) +{ + if (!okToQuit) + { + savedGeometry = this->geometry(); + this->hide(); + event->ignore(); + return; + } + + if (wtsChannel) + deinitWtsChannel(); + + event->accept(); +} + +/****************************************************************************** +** ** +** slots go here ** +** ** +******************************************************************************/ +#if 1 +void MainWindow::onBtnRefreshClicked() +{ + int i; + + /* clear drive list */ + if (itemList.count()) + { + for (i = 0; i < itemList.count(); i++) + ui->listWidget->removeItemWidget(itemList.at(i)); + + itemList.clear(); + } + ui->listWidget->clear(); + + if (Utils::getMountList(wtsChannel, &itemList)) + { + QMessageBox::information(this, "Get device list", "\nError getting " + "device list from client"); + return; + } + + if (itemList.count() == 0) + { + QMessageBox::information(this, "Get device list", + "\nNo devices found!"); + return; + } + + /* add mount point to list widget */ + for (i = 0; i < itemList.count(); i++) + ui->listWidget->insertItem(i, itemList.at(i)); +} +#else +void MainWindow::onBtnRefreshClicked() +{ + QListWidgetItem *item; + int i; + int j; + + /* clear drive list */ + if (itemList.count()) + { + for (i = 0; i < itemList.count(); i++) + ui->listWidget->removeItemWidget(itemList.at(i)); + + itemList.clear(); + } + ui->listWidget->clear(); + + QDir dir(QDir::homePath() + "/xrdp_client"); + QStringList sl = dir.entryList(); + + for (i = 0, j = 0; i < sl.count(); i++) + { + /* skip files starting with . */ + if (sl.at(i).startsWith(".")) + continue; + + /* add mount point to list widget */ + item = new QListWidgetItem; + item->setText(sl.at(i)); + ui->listWidget->insertItem(j++, item); + itemList.append(item); + } +} +#endif + +void MainWindow::onBtnUnmountClicked() +{ + QListWidgetItem *item = ui->listWidget->currentItem(); + + if (!item) + { + QMessageBox::information(this, "Unmount device", "\nNo device selected. " + "You must select a device to unmount"); + return; + } + + if (Utils::unmountDevice(wtsChannel, item->text(), statusBar) == 0) + { + delete ui->listWidget->takeItem(itemList.indexOf(item)); + itemList.removeOne(item); + } +} + +void MainWindow::onActionQuit() +{ + okToQuit = true; + this->close(); +} + +void MainWindow::onActionLaunch() +{ + this->show(); + this->setGeometry(savedGeometry); +} + +void MainWindow::onSystemTrayClicked(QSystemTrayIcon::ActivationReason) +{ + trayMenu->popup(QCursor::pos()); +} diff --git a/tcutils/mainwindow.h b/tcutils/mainwindow.h new file mode 100644 index 00000000..1639522f --- /dev/null +++ b/tcutils/mainwindow.h @@ -0,0 +1,57 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include <QMainWindow> +#include <xrdpapi.h> +#include <QSystemTrayIcon> +#include <QMenu> +#include <QCloseEvent> +#include <QFileDialog> +#include <QDir> +#include <QListWidgetItem> +#include <QList> +#include <QMessageBox> +#include <QTimer> +#include <QStatusBar> +//#include <QDebug> + +#include "utils.h" + +namespace Ui { +class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = 0); + ~MainWindow(); + +private: + Ui::MainWindow *ui; + void *wtsChannel; + QSystemTrayIcon *trayIcon; + QMenu *trayMenu; + bool okToQuit; + QRect savedGeometry; + QStatusBar *statusBar; + + QList<QListWidgetItem *> itemList; + + void setupSystemTray(); + int initWtsChannel(); + int deinitWtsChannel(); + void setStatusMsg(QString msg); + void closeEvent(QCloseEvent * event); + +private slots: + void onBtnRefreshClicked(); + void onBtnUnmountClicked(); + void onActionQuit(); + void onActionLaunch(); + void onSystemTrayClicked(QSystemTrayIcon::ActivationReason); +}; + +#endif // MAINWINDOW_H diff --git a/tcutils/mainwindow.ui b/tcutils/mainwindow.ui new file mode 100644 index 00000000..802d01a3 --- /dev/null +++ b/tcutils/mainwindow.ui @@ -0,0 +1,100 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>MainWindow</class> + <widget class="QMainWindow" name="MainWindow"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>541</width> + <height>355</height> + </rect> + </property> + <property name="windowTitle"> + <string>TC Utils</string> + </property> + <widget class="QWidget" name="centralWidget"> + <widget class="QTabWidget" name="tabWidget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>511</width> + <height>291</height> + </rect> + </property> + <property name="currentIndex"> + <number>0</number> + </property> + <widget class="QWidget" name="tabUnmount"> + <attribute name="title"> + <string>Tab 1</string> + </attribute> + <widget class="QListWidget" name="listWidget"> + <property name="geometry"> + <rect> + <x>10</x> + <y>10</y> + <width>321</width> + <height>221</height> + </rect> + </property> + </widget> + <widget class="QPushButton" name="btnUnmount"> + <property name="geometry"> + <rect> + <x>350</x> + <y>60</y> + <width>141</width> + <height>27</height> + </rect> + </property> + <property name="text"> + <string>Unmount device</string> + </property> + </widget> + <widget class="QPushButton" name="btnRefresh"> + <property name="geometry"> + <rect> + <x>350</x> + <y>10</y> + <width>141</width> + <height>27</height> + </rect> + </property> + <property name="text"> + <string>Get device list</string> + </property> + </widget> + </widget> + <widget class="QWidget" name="tab_2"> + <attribute name="title"> + <string>Tab 2</string> + </attribute> + </widget> + </widget> + </widget> + <widget class="QMenuBar" name="menuBar"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>541</width> + <height>25</height> + </rect> + </property> + </widget> + <widget class="QToolBar" name="mainToolBar"> + <attribute name="toolBarArea"> + <enum>TopToolBarArea</enum> + </attribute> + <attribute name="toolBarBreak"> + <bool>false</bool> + </attribute> + </widget> + <widget class="QStatusBar" name="statusBar"/> + </widget> + <layoutdefault spacing="6" margin="11"/> + <resources/> + <connections/> +</ui> diff --git a/tcutils/moc_mainwindow.cpp b/tcutils/moc_mainwindow.cpp new file mode 100644 index 00000000..85806598 --- /dev/null +++ b/tcutils/moc_mainwindow.cpp @@ -0,0 +1,104 @@ +/**************************************************************************** +** Meta object code from reading C++ file 'mainwindow.h' +** +** Created: Sun Aug 25 15:11:44 2013 +** by: The Qt Meta Object Compiler version 63 (Qt 4.8.1) +** +** WARNING! All changes made in this file will be lost! +*****************************************************************************/ + +#include "mainwindow.h" +#if !defined(Q_MOC_OUTPUT_REVISION) +#error "The header file 'mainwindow.h' doesn't include <QObject>." +#elif Q_MOC_OUTPUT_REVISION != 63 +#error "This file was generated using the moc from 4.8.1. It" +#error "cannot be used with the include files from this version of Qt." +#error "(The moc has changed too much.)" +#endif + +QT_BEGIN_MOC_NAMESPACE +static const uint qt_meta_data_MainWindow[] = { + + // content: + 6, // revision + 0, // classname + 0, 0, // classinfo + 5, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 12, 11, 11, 11, 0x08, + 34, 11, 11, 11, 0x08, + 56, 11, 11, 11, 0x08, + 71, 11, 11, 11, 0x08, + 88, 11, 11, 11, 0x08, + + 0 // eod +}; + +static const char qt_meta_stringdata_MainWindow[] = { + "MainWindow\0\0onBtnRefreshClicked()\0" + "onBtnUnmountClicked()\0onActionQuit()\0" + "onActionLaunch()\0" + "onSystemTrayClicked(QSystemTrayIcon::ActivationReason)\0" +}; + +void MainWindow::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) +{ + if (_c == QMetaObject::InvokeMetaMethod) { + Q_ASSERT(staticMetaObject.cast(_o)); + MainWindow *_t = static_cast<MainWindow *>(_o); + switch (_id) { + case 0: _t->onBtnRefreshClicked(); break; + case 1: _t->onBtnUnmountClicked(); break; + case 2: _t->onActionQuit(); break; + case 3: _t->onActionLaunch(); break; + case 4: _t->onSystemTrayClicked((*reinterpret_cast< QSystemTrayIcon::ActivationReason(*)>(_a[1]))); break; + default: ; + } + } +} + +const QMetaObjectExtraData MainWindow::staticMetaObjectExtraData = { + 0, qt_static_metacall +}; + +const QMetaObject MainWindow::staticMetaObject = { + { &QMainWindow::staticMetaObject, qt_meta_stringdata_MainWindow, + qt_meta_data_MainWindow, &staticMetaObjectExtraData } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &MainWindow::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *MainWindow::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *MainWindow::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_MainWindow)) + return static_cast<void*>(const_cast< MainWindow*>(this)); + return QMainWindow::qt_metacast(_clname); +} + +int MainWindow::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QMainWindow::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + if (_id < 5) + qt_static_metacall(this, _c, _id, _a); + _id -= 5; + } + return _id; +} +QT_END_MOC_NAMESPACE diff --git a/tcutils/qrc_resources.cpp b/tcutils/qrc_resources.cpp new file mode 100644 index 00000000..3f2366cb --- /dev/null +++ b/tcutils/qrc_resources.cpp @@ -0,0 +1,1191 @@ +/**************************************************************************** +** Resource object code +** +** Created: Sun Aug 25 15:11:45 2013 +** by: The Resource Compiler for Qt version 4.8.1 +** +** WARNING! All changes made in this file will be lost! +*****************************************************************************/ + +#include <QtCore/qglobal.h> + +static const unsigned char qt_resource_data[] = { + // /home/lk/projects/jtech/nlabs_xrdp_tcutils/tcutils/resources/images/tools.gif + 0x0,0x0,0x45,0x65, + 0x47, + 0x49,0x46,0x38,0x39,0x61,0xab,0x0,0xb7,0x0,0xe7,0xff,0x0,0x22,0x26,0x9a,0x18, + 0x2a,0x95,0x24,0x29,0x8f,0x1d,0x2e,0x92,0x1d,0x32,0x71,0x23,0x33,0x64,0x15,0x37, + 0x6c,0x16,0x34,0x96,0x22,0x31,0x96,0x1f,0x37,0x65,0x25,0x3b,0x5a,0x28,0x35,0x93, + 0x1d,0x38,0x9a,0x2c,0x38,0x70,0x1f,0x39,0x95,0x24,0x3a,0x87,0x14,0x3d,0x9f,0x15, + 0x3e,0x99,0x2a,0x40,0x65,0x24,0x3f,0x81,0x1f,0x41,0x7d,0x21,0x42,0x6e,0x25,0x3d, + 0x99,0x29,0x40,0x70,0x2c,0x3e,0x7b,0x1b,0x41,0x9c,0x24,0x42,0x78,0xd,0x46,0x99, + 0x10,0x46,0xa0,0x29,0x40,0x97,0x1f,0x43,0x9e,0x1f,0x44,0x99,0x2b,0x40,0x9e,0x1e, + 0x45,0x93,0x24,0x44,0x8c,0x21,0x43,0xa6,0x1e,0x49,0x84,0x23,0x45,0xa1,0x16,0x49, + 0xa3,0x29,0x43,0xab,0x2a,0x48,0x77,0x22,0x49,0x8a,0x19,0x4b,0x99,0x26,0x47,0x9d, + 0x30,0x45,0x95,0x2b,0x49,0x7f,0x1a,0x4b,0x9f,0x1c,0x4a,0xac,0x3d,0x47,0x6f,0x28, + 0x48,0xa4,0x31,0x48,0x8a,0x28,0x49,0x9f,0x2e,0x4a,0x87,0x1c,0x4e,0x95,0x1d,0x4c, + 0xa7,0x29,0x4a,0x98,0x27,0x4e,0x79,0x1e,0x4d,0xa1,0x2a,0x4a,0xa0,0x1d,0x50,0x90, + 0x11,0x51,0xab,0x25,0x4f,0x84,0x37,0x4a,0x82,0x2c,0x4f,0x73,0x2c,0x4a,0xa7,0x12, + 0x52,0xa5,0x11,0x53,0x9f,0x21,0x4e,0xa3,0x20,0x4f,0x9d,0x2a,0x4d,0x95,0x2a,0x4e, + 0x90,0x22,0x4f,0xa4,0x33,0x4e,0x7d,0x2d,0x4d,0x9c,0x29,0x50,0x8c,0x32,0x4f,0x86, + 0x23,0x51,0x9f,0x25,0x50,0xa5,0x30,0x4c,0xb1,0x16,0x56,0x9c,0x30,0x4e,0xa4,0x18, + 0x55,0xa8,0x30,0x4f,0x9f,0x26,0x50,0xb3,0x26,0x52,0xa1,0x1a,0x54,0xb5,0x1a,0x56, + 0xa3,0x28,0x51,0xad,0x1a,0x55,0xaf,0x26,0x54,0x9b,0x9,0x5b,0xad,0x25,0x55,0x96, + 0x31,0x51,0x9b,0x28,0x53,0xa2,0x29,0x53,0xa8,0x29,0x54,0xa3,0x38,0x53,0x83,0x1e, + 0x57,0xab,0x34,0x53,0x96,0x2a,0x55,0xa4,0x31,0x55,0x91,0x1e,0x59,0xa6,0x1e,0x5a, + 0xa0,0x2c,0x55,0xab,0x3c,0x56,0x75,0x1e,0x5b,0x9c,0x2c,0x56,0xa5,0x2a,0x58,0x9a, + 0x22,0x58,0xb3,0x32,0x58,0x84,0x22,0x59,0xad,0x3c,0x55,0x8d,0x2c,0x58,0xa0,0x30, + 0x55,0xb2,0x2e,0x57,0xa6,0x2a,0x5a,0x95,0x22,0x5b,0xa8,0x32,0x59,0x8f,0x46,0x55, + 0x7d,0x3a,0x54,0xac,0x47,0x53,0x9a,0x3c,0x59,0x7f,0x2e,0x5b,0x9d,0x32,0x59,0xaf, + 0x3a,0x58,0xa3,0x2b,0x5a,0xbe,0x3a,0x59,0x9c,0x41,0x59,0x89,0x46,0x55,0xa6,0x38, + 0x5b,0x98,0x26,0x60,0xa7,0x33,0x5d,0xa5,0x2a,0x60,0xaf,0x2c,0x5f,0xb4,0x39,0x5c, + 0xba,0x30,0x63,0xa1,0x37,0x62,0xa5,0x40,0x61,0x9f,0x3e,0x60,0xb0,0x32,0x63,0xb8, + 0x40,0x63,0x90,0x40,0x62,0x9a,0x48,0x62,0x83,0x46,0x63,0x89,0x44,0x61,0xa5,0x49, + 0x62,0x92,0x50,0x61,0x94,0x40,0x66,0xb0,0x37,0x69,0xb2,0x53,0x63,0x9e,0x3a,0x6a, + 0xb9,0x50,0x6d,0x85,0x52,0x6e,0x9d,0x58,0x71,0x99,0x58,0x73,0x94,0x54,0x72,0xab, + 0x5e,0x71,0xa6,0x65,0x7c,0x95,0x61,0x7b,0xac,0x63,0x7d,0xa5,0x6b,0x7a,0xad,0x64, + 0x7f,0xa1,0x60,0x80,0xbf,0x68,0x7d,0xd4,0x78,0x86,0xbb,0x6f,0x89,0xb9,0x71,0x8a, + 0xb3,0x73,0x8b,0xae,0x75,0x8d,0xa8,0x82,0x8f,0xc1,0x82,0x95,0xc5,0x7c,0x99,0xb8, + 0x7c,0x99,0xc4,0x78,0x99,0xd9,0x7c,0x99,0xce,0x88,0x98,0xba,0x8c,0xa7,0xb8,0x8e, + 0xa4,0xd2,0x8e,0xa6,0xc7,0x9c,0xa5,0xc9,0x96,0xb2,0xe4,0x9a,0xb3,0xcf,0xa4,0xb1, + 0xd0,0x94,0xb5,0xda,0x9f,0xb4,0xdb,0xa5,0xb3,0xe0,0xa4,0xb4,0xf0,0xa5,0xbf,0xf3, + 0xb0,0xc1,0xd4,0xb1,0xbf,0xeb,0xb7,0xbe,0xed,0xab,0xc3,0xeb,0xad,0xc4,0xe1,0xb9, + 0xc7,0xd4,0xb6,0xcd,0xf6,0xbb,0xd0,0xf0,0xc0,0xce,0xfd,0xb8,0xd7,0xed,0xcd,0xd3, + 0xeb,0xc3,0xd6,0xf0,0xbf,0xd8,0xff,0xc5,0xde,0xfd,0xcd,0xdc,0xfe,0xb7,0xe3,0xff, + 0xd4,0xe4,0xfe,0xdd,0xe5,0xeb,0xd1,0xeb,0xff,0xdd,0xea,0xff,0xf1,0xed,0xe4,0xcb, + 0xf6,0xfe,0xf0,0xec,0xff,0xe4,0xf0,0xfe,0xdd,0xf3,0xff,0xeb,0xef,0xff,0xf1,0xef, + 0xf7,0xe6,0xf3,0xf4,0xf0,0xf2,0xef,0xed,0xf4,0xe9,0xe9,0xf5,0xef,0xf8,0xf1,0xf0, + 0xf1,0xf5,0xe4,0xef,0xf4,0xf7,0xed,0xf5,0xfe,0xe7,0xf8,0xff,0xff,0xf1,0xfe,0xf5, + 0xf5,0xff,0xe2,0xfb,0xff,0xfb,0xf4,0xff,0xdf,0xfd,0xfa,0xdb,0xfe,0xff,0xf9,0xf8, + 0xee,0xf0,0xf9,0xff,0xf9,0xf7,0xfb,0xff,0xf7,0xf0,0xee,0xfb,0xfc,0xf7,0xf9,0xf6, + 0xff,0xf6,0xfd,0xed,0xfd,0xf0,0xfe,0xf8,0xf6,0xf5,0xfa,0xfd,0xff,0xfa,0xea,0xec, + 0xff,0xf8,0xea,0xff,0xfe,0xfa,0xfe,0xe6,0xf4,0xfe,0xf9,0xf9,0xfe,0xed,0xfd,0xfb, + 0xff,0xf7,0xfe,0xf3,0xf1,0xff,0xff,0xff,0xfc,0xfa,0xf9,0xfe,0xff,0xfc,0xfe,0xfb, + 0xff,0xfe,0xf5,0xff,0xfd,0xff,0xfe,0xff,0xfc,0xff,0xff,0xff,0x21,0xfe,0x11,0x43, + 0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50, + 0x0,0x21,0xf9,0x4,0x1,0xa,0x0,0xff,0x0,0x2c,0x0,0x0,0x0,0x0,0xab,0x0, + 0xb7,0x0,0x0,0x8,0xfe,0x0,0xbb,0x78,0x19,0xe8,0x25,0x48,0x97,0x2e,0x63,0xbe, + 0x28,0x5c,0xc8,0xb0,0xe1,0x98,0x87,0x10,0x23,0x4a,0x9c,0x48,0xb1,0xa2,0x45,0x88, + 0xd,0x33,0x6a,0xdc,0xc8,0xb1,0x21,0x93,0x8f,0x20,0x43,0x8a,0x64,0x42,0xa4,0xa4, + 0xc9,0x92,0x39,0x52,0xaa,0x74,0xc1,0xd2,0xc5,0x8c,0x15,0x33,0x5e,0xae,0xe0,0x40, + 0xb3,0xa6,0x4d,0xf,0x1e,0x32,0xe8,0xd4,0xe9,0x80,0x81,0xc0,0x81,0x41,0xbe,0x1c, + 0x4c,0xd8,0x91,0xe1,0xc5,0xa3,0x48,0x93,0x5e,0x2c,0xca,0x94,0xe3,0xc8,0xa7,0x20, + 0x4f,0x9e,0x1c,0x32,0x44,0x65,0xe,0x96,0x29,0x63,0x6a,0x9d,0x61,0xb3,0x2b,0x4d, + 0x9c,0x3b,0x4b,0x58,0x80,0x40,0x30,0x4a,0xd0,0x83,0x4d,0x17,0x2a,0x5d,0xcb,0xf6, + 0x68,0xda,0xb7,0xb,0xa1,0x42,0x95,0x6a,0x92,0x6a,0xd5,0x94,0x58,0x73,0xe8,0x98, + 0xa1,0x63,0xef,0xc,0x13,0x26,0xbc,0xde,0x4,0x6b,0x1,0x84,0x87,0xb2,0x6,0xd1, + 0xbe,0x6d,0xcb,0xb8,0xf1,0x43,0xb8,0x70,0xe5,0x3e,0xa5,0x5b,0xf2,0x88,0x5d,0xab, + 0x29,0xfb,0x6a,0xfe,0xb,0x58,0x70,0x4d,0x9c,0x1e,0x20,0x80,0xc8,0x50,0xf6,0x8b, + 0x15,0x2e,0x59,0xe0,0x3a,0x5e,0x4d,0x51,0x8d,0xeb,0xd7,0xae,0x21,0xbf,0x95,0x3c, + 0x92,0x32,0x91,0x23,0x96,0xa9,0x62,0xd6,0xac,0x19,0x70,0x67,0xcf,0x1c,0x70,0x1a, + 0x26,0x3d,0x30,0x8a,0xe9,0x2c,0xa9,0x17,0xb3,0x5e,0xfe,0x10,0x36,0x6c,0xd9,0x69, + 0x69,0x8b,0xb4,0x8d,0x3b,0xf7,0x6e,0xde,0x3a,0x7c,0x7,0x6,0x2e,0xbc,0x4,0x87, + 0x33,0x67,0xbc,0xfe,0x3c,0xb4,0x92,0xc5,0xca,0x46,0xe6,0xe8,0xd3,0x4b,0x3c,0x4f, + 0x71,0x63,0x6d,0x22,0x50,0xed,0x5e,0x56,0x89,0x3d,0xbb,0x76,0xee,0xa0,0x3f,0x84, + 0xf,0xf3,0xd8,0x8a,0x7f,0x8d,0xea,0x5,0x88,0x1e,0x7b,0x13,0x6d,0xd4,0x45,0x6d, + 0xf1,0xc9,0x77,0x57,0x66,0xd8,0x69,0xb7,0x9d,0x60,0xa0,0x79,0xf0,0x81,0x17,0xfc, + 0x99,0xe6,0xdf,0x7f,0x19,0x9,0xa8,0xe1,0x6a,0x4,0xae,0xa7,0xd1,0x41,0xd2,0x7d, + 0xa4,0xe0,0x82,0x7a,0x35,0xe8,0xa0,0x67,0x11,0x76,0xf0,0x98,0x85,0xfe,0x6d,0xe8, + 0xe2,0x80,0x0,0xb6,0xf7,0x21,0x88,0xd2,0x8d,0x68,0x55,0x7d,0x36,0x38,0xf8,0xe0, + 0x60,0x1d,0xf4,0xa8,0x10,0x86,0xa,0xbd,0x28,0x24,0x87,0x31,0x16,0x38,0x23,0x8d, + 0x92,0xd9,0x48,0x1f,0x76,0x36,0x34,0x79,0x62,0x57,0x1e,0x74,0xf0,0xc1,0x7,0x19, + 0x5c,0x68,0x9e,0x15,0x43,0x66,0xd9,0x58,0x87,0x11,0x19,0x78,0x10,0x92,0x9,0xca, + 0x77,0x23,0x93,0x4d,0xe6,0xe8,0x9b,0x57,0x51,0x4e,0x99,0x41,0x79,0x17,0x8e,0xc1, + 0x9f,0x73,0xaf,0x69,0x29,0xa7,0x87,0x19,0xca,0x98,0xd1,0x97,0x5f,0x26,0xa9,0xe0, + 0x98,0xbc,0x95,0x69,0xe6,0x6f,0x37,0x7d,0xc0,0x2,0xb,0x55,0x5a,0x9,0x11,0x9c, + 0xae,0x31,0x67,0xe5,0x85,0xb0,0x85,0xe1,0xe8,0xa3,0x88,0x46,0x3a,0x86,0xa1,0x10, + 0x61,0xe9,0x5c,0x45,0x5c,0x62,0xa4,0x11,0x41,0x78,0xca,0xb5,0xe7,0x8d,0x7a,0x69, + 0x85,0x5d,0x4c,0x3b,0x7e,0x35,0x25,0x95,0x6d,0x3a,0x16,0x29,0xa2,0x65,0xc0,0x61, + 0x86,0x19,0xfe,0x65,0xc4,0x2a,0xc7,0xa3,0x61,0xb0,0x61,0x6b,0x1c,0xb6,0x82,0xa7, + 0xeb,0xae,0xbc,0x86,0xd1,0x2a,0x1c,0xc0,0xc6,0x5a,0xc6,0x6b,0xb4,0x86,0xa1,0xc6, + 0x5a,0x6f,0x45,0x31,0x50,0x13,0x5e,0x1c,0x84,0xdc,0xb3,0x59,0x7c,0x54,0x59,0x75, + 0x47,0x34,0x61,0xad,0xb5,0x96,0x59,0x15,0xd3,0xa,0xdc,0x76,0xeb,0x6d,0x4d,0xa7, + 0x96,0xc0,0xdc,0xaa,0x70,0xc6,0xa,0xab,0xb0,0xb3,0x3e,0x6a,0xeb,0xba,0x67,0x14, + 0xeb,0xee,0xa3,0x72,0x58,0x1,0xac,0x19,0xc1,0x96,0xe1,0x9f,0x6b,0xb4,0x1e,0xab, + 0x54,0xb2,0xcb,0x36,0xdb,0x5,0xb4,0xc8,0x49,0xb,0x1f,0x13,0xd4,0x5e,0xdb,0x44, + 0x6e,0x43,0xdc,0x70,0x43,0x4b,0x2d,0x79,0xcb,0xad,0x60,0xe3,0x92,0x2b,0xb1,0x1a, + 0x72,0x54,0x6c,0xb1,0xc5,0x70,0xac,0xa1,0xf1,0xc6,0x1c,0x73,0x4c,0xaf,0x7f,0x70, + 0xc8,0x6b,0x85,0xbd,0x58,0x12,0xd9,0x94,0xb2,0x9c,0xfe,0xb,0x2d,0x48,0x54,0x95, + 0x24,0x5,0x11,0x52,0x8c,0x94,0xc4,0xcc,0xa,0x33,0xcc,0x92,0xc3,0x33,0x79,0x15, + 0xf1,0xc4,0xae,0xf1,0x8a,0xe8,0x85,0x19,0x77,0x2c,0x34,0xc7,0x21,0xab,0xb1,0xe8, + 0xd1,0x2d,0x22,0x9b,0x96,0xb2,0xcc,0xfa,0xfb,0xaf,0x48,0xb9,0x9d,0xf4,0x72,0xcc, + 0x53,0x27,0x71,0x12,0x5e,0xd,0x3b,0xc,0xf1,0x72,0x3c,0xe3,0xeb,0x45,0x78,0xe0, + 0x1d,0x2a,0x2f,0xb0,0x1a,0xc3,0x41,0x71,0x18,0xb3,0xa6,0x8d,0xf6,0xda,0x69,0xcb, + 0xe1,0x1c,0xc8,0x70,0x0,0xc,0x7,0x5b,0xfc,0xa6,0x8c,0x64,0x75,0x2d,0x4b,0x65, + 0xf5,0xfe,0xde,0x52,0xad,0x74,0xb3,0xd6,0x3a,0x73,0xdd,0x75,0x18,0x5f,0x83,0x27, + 0x9e,0x14,0x63,0x18,0xd,0x6c,0xc6,0xc0,0x3a,0xda,0xee,0xe3,0x61,0x40,0xe,0x39, + 0xad,0x15,0x1b,0x3d,0x36,0xb4,0x73,0x2b,0x9d,0x56,0x10,0x76,0x1f,0xc8,0xc4,0xc1, + 0xb8,0xd9,0x30,0xc4,0x11,0x52,0x94,0x6e,0xfa,0xcc,0x49,0x48,0x81,0xfa,0xd,0x39, + 0x24,0xe1,0xb7,0x4c,0xdd,0x6e,0xcd,0x5a,0xd7,0x14,0xeb,0x7a,0xec,0xed,0x6f,0xab, + 0x21,0xac,0xee,0xbc,0xf,0xeb,0x7b,0xef,0x91,0x53,0xee,0xf6,0x78,0x63,0x87,0xac, + 0x39,0x74,0x2,0x61,0xb,0x5,0x14,0x7e,0xe2,0x36,0xa2,0x6e,0x39,0x2c,0xe8,0x3a, + 0x5e,0xdb,0xc6,0x1e,0xf8,0xec,0xb4,0xc3,0x76,0xb1,0xc5,0x94,0xb,0xeb,0xfd,0xf7, + 0xde,0xbf,0xeb,0x76,0xc9,0x94,0xee,0xb,0x9d,0x42,0xcb,0x36,0xb1,0x3c,0xf3,0x7e, + 0x5e,0xd1,0x24,0xf3,0x43,0xbc,0xef,0xa7,0xd,0x3a,0x4c,0x7f,0x55,0xf5,0xf,0x5f, + 0x9f,0x54,0xf6,0xac,0xc2,0x21,0x8,0xb0,0x56,0xa0,0x3,0x21,0xe8,0x50,0x8,0x37, + 0xb8,0x61,0x5d,0x71,0xe0,0x81,0xaf,0xe8,0xc0,0xc0,0x58,0x5,0x90,0xe,0x8b,0x4a, + 0x97,0xbb,0xa,0xc1,0xc0,0x2b,0x95,0x21,0x5e,0xcb,0xd9,0x88,0x7f,0xe,0x12,0x4, + 0xce,0x79,0xc1,0x5a,0x4,0x39,0x82,0xe,0x6c,0x70,0x85,0x2a,0x5c,0xe1,0x84,0x36, + 0xa0,0x49,0x1c,0x52,0x68,0x82,0x32,0x5d,0x21,0x7,0x52,0x60,0x49,0xe9,0xb8,0x55, + 0x3d,0xd9,0xed,0x8f,0x7f,0xce,0x29,0xc3,0x13,0x9e,0x20,0x88,0x1e,0x6e,0x30,0x8, + 0xfe,0x6e,0x28,0x4,0x1b,0x6c,0x0,0x84,0x2b,0xb0,0x61,0xf,0x95,0x1b,0x3,0x88, + 0x2c,0xa6,0xc4,0x2f,0xc9,0xc1,0x7b,0xc,0x84,0xa0,0x15,0xe4,0xa0,0x85,0x2a,0x76, + 0x50,0x5f,0x26,0x6b,0xc8,0x6,0xbb,0xd0,0x41,0x82,0x84,0x27,0x7,0x47,0x90,0x83, + 0x14,0x36,0x80,0xc2,0xf7,0x7d,0x6d,0x42,0x50,0xc8,0x80,0x7,0xae,0x10,0x87,0x12, + 0xd4,0xf,0x2b,0x2e,0xf8,0xc0,0x11,0x6a,0xa8,0x3f,0xa4,0xe0,0x30,0x87,0x82,0x48, + 0xc3,0x13,0xcc,0xd0,0xc3,0x28,0x76,0x1,0x8c,0x67,0xd8,0x3,0x1b,0xae,0xa0,0x3, + 0x2f,0xec,0xa1,0x10,0x88,0xdc,0xc3,0x19,0x98,0x15,0x48,0x44,0x16,0x42,0x11,0x59, + 0xd0,0x98,0x1e,0xf4,0x40,0x2f,0x38,0x8,0x90,0xe,0x61,0xe8,0xa0,0x16,0x8,0x81, + 0x45,0xc7,0x68,0xd0,0x3c,0xb,0xe9,0xa0,0x1b,0xbc,0x10,0xb3,0x1b,0x84,0x80,0x8, + 0x72,0x70,0x41,0xe,0x48,0x29,0x5,0x2e,0x70,0xa1,0x8,0xaf,0xbc,0x81,0x18,0x37, + 0xe0,0x82,0x3d,0xac,0x80,0x96,0x78,0x59,0x81,0x5f,0xf2,0xd7,0x15,0xb6,0xdc,0x11, + 0x36,0x65,0x10,0x84,0x19,0xf6,0xf8,0xaa,0x2c,0xd4,0x20,0xb,0x8b,0x23,0x49,0x17, + 0xe0,0xe0,0x7,0x31,0xc8,0x40,0x6,0x13,0x90,0x81,0x11,0xc4,0xe0,0x87,0x6a,0x8a, + 0xc1,0x8,0xd0,0xa4,0x80,0x12,0x7a,0x50,0x87,0x3a,0xcc,0x81,0xc,0x5b,0xd8,0x81, + 0x1e,0x42,0xc6,0x40,0x2d,0x84,0x21,0xa,0x9d,0xdc,0x52,0x46,0x2e,0xc4,0x90,0xe, + 0x9e,0x21,0x75,0x7c,0x18,0x44,0xdc,0x8e,0x99,0x5,0x23,0xa4,0x60,0x2,0x18,0xfe, + 0xa0,0x81,0xf,0xf4,0x89,0x81,0x9,0x4c,0xc0,0x8,0x59,0xe0,0x82,0xea,0xae,0xa2, + 0xca,0x1c,0x68,0x85,0x97,0x36,0xf1,0xe5,0x2f,0x5d,0x53,0x6,0x21,0x94,0x81,0xe, + 0x65,0xc8,0x82,0x19,0x26,0xb9,0x86,0x40,0x4,0x62,0x9,0x2d,0x68,0xc1,0x1b,0x22, + 0xa1,0x9,0x54,0xd4,0x62,0x18,0xcf,0xa0,0xc6,0x37,0xa8,0x21,0xf,0x79,0x88,0x83, + 0x1a,0xcf,0x48,0xc6,0x30,0x86,0xb1,0x8a,0x53,0x64,0x22,0xf,0x48,0x40,0x2,0x37, + 0x95,0xb0,0x6,0x44,0xc0,0xa1,0x6,0x44,0xa0,0x83,0x25,0x4a,0x96,0xc5,0x85,0x58, + 0x29,0x94,0x6,0x91,0x3,0x1f,0x6a,0x90,0x2,0x23,0x90,0x81,0xc,0x4b,0xb8,0x0, + 0xa,0x22,0xa1,0x8a,0x5e,0x28,0x83,0x19,0xf8,0x98,0xc6,0x33,0x98,0x91,0xb,0x4c, + 0x5c,0x80,0x2,0x2,0x2d,0xdd,0x7,0x5c,0xd0,0x84,0x5d,0xe6,0xac,0x97,0x6b,0x59, + 0xa8,0x6b,0xe4,0xe0,0x6,0x47,0x95,0x61,0x10,0x7a,0x58,0xc3,0x36,0x51,0x80,0x84, + 0x47,0x98,0xe2,0x16,0xc9,0xf8,0x6,0x3e,0xf4,0x41,0x57,0x7c,0xd8,0xf5,0x1d,0x78, + 0xb5,0xeb,0x5d,0xe5,0x6a,0xd7,0x6f,0x24,0x43,0x16,0x9f,0x60,0x44,0xf,0x7a,0x40, + 0x86,0x35,0xc8,0xf3,0xb,0x4c,0x60,0x8e,0x46,0x16,0xa5,0x90,0xa0,0xa8,0x41,0x5, + 0x45,0xa8,0xa8,0x12,0x48,0x0,0x86,0x4c,0xd4,0x82,0x1a,0x76,0xf5,0xc6,0x3b,0xf4, + 0x11,0x8e,0x77,0x54,0xe3,0x19,0x76,0x1d,0x6,0x26,0x44,0xf0,0x1,0x29,0x0,0x22, + 0x8e,0x2f,0xa1,0x23,0x58,0x95,0x22,0x56,0x35,0xd4,0xa,0xb,0x7b,0x50,0xfe,0x4, + 0x21,0x88,0xba,0x4,0x4c,0xb0,0x22,0x19,0xf2,0xd0,0xab,0x3e,0xba,0x81,0xe,0x74, + 0xd8,0xe3,0xb7,0xbd,0xfd,0xad,0x70,0xfd,0x41,0xdc,0x73,0x6c,0x56,0x1f,0x76,0x35, + 0xa9,0x30,0x5c,0xd1,0x88,0xa2,0xe,0x62,0x10,0x3c,0xed,0xe9,0x8f,0x7e,0xba,0x10, + 0x39,0x30,0x73,0xd,0x24,0xe8,0x81,0x2b,0x9c,0x61,0xd7,0x73,0x78,0x83,0xb7,0xee, + 0x8,0x6f,0x3e,0xf4,0x81,0xd7,0x73,0xe0,0x43,0x1e,0xa2,0x18,0x63,0xe9,0x36,0x30, + 0x25,0xd5,0x26,0x34,0xac,0xac,0xda,0x1d,0xc5,0xb6,0xf7,0x1a,0x39,0xec,0x41,0x3c, + 0x70,0x48,0x41,0xb,0x4a,0x21,0xc,0xbd,0xaa,0xc3,0x1b,0xea,0x98,0x2b,0x71,0xc3, + 0x1b,0x5e,0x7b,0x10,0xf8,0xc0,0xc4,0xa5,0x6b,0x79,0xbd,0xf1,0x8d,0x6f,0x88,0x43, + 0x1e,0xe4,0x20,0x86,0x28,0xec,0x9,0xdd,0xc,0xae,0x13,0x94,0xa,0x71,0x96,0x11, + 0x76,0xa0,0x1,0x30,0xc4,0x82,0xa4,0xd,0x9e,0xab,0x3e,0x8,0xec,0xf,0x7e,0xa4, + 0x23,0x1d,0xc4,0x55,0xc7,0x35,0xbe,0x21,0x8f,0x56,0x88,0xa0,0x8,0x49,0xf8,0x80, + 0xe,0xae,0x0,0x18,0x9c,0xe5,0xac,0x22,0xb4,0xfb,0x15,0xbd,0x2e,0xe8,0xa8,0x2, + 0x46,0x81,0x82,0x1,0xbc,0x20,0x1f,0x68,0x60,0x87,0x55,0x4c,0x43,0x1f,0xe7,0x10, + 0xae,0x3d,0xf4,0xe1,0xf,0x7a,0xd0,0x23,0xc0,0x78,0x55,0x32,0x3b,0xa6,0xfc,0xdb, + 0x75,0xac,0x83,0xae,0x75,0xd5,0xab,0x49,0xa9,0x51,0xe,0x72,0x94,0xc3,0x15,0x84, + 0x35,0x1b,0x9c,0xe8,0xf6,0xa1,0x30,0xb8,0x21,0x25,0x84,0x10,0x41,0xfe,0x23,0x90, + 0x90,0x7,0x54,0x40,0xd5,0xb3,0xe8,0xc0,0x7,0x3d,0xc8,0xfb,0x5b,0x76,0x18,0x38, + 0x1d,0xe6,0xe0,0x7,0x3f,0xe8,0xa1,0x8d,0x6,0xcb,0xc3,0x13,0x3e,0xb8,0x81,0xe, + 0xe2,0x70,0x80,0x17,0x0,0xc1,0x6,0x2e,0x50,0x98,0xc2,0x56,0x50,0x2,0x71,0xb5, + 0xa6,0x6b,0xad,0x7a,0x15,0x8f,0x1d,0xf5,0x81,0x1f,0x77,0x81,0x10,0x82,0xa8,0x1, + 0x22,0x44,0x40,0x6,0x56,0x70,0xf7,0x1a,0xd8,0xe0,0x87,0x3b,0xd0,0x61,0x67,0x7b, + 0xf8,0xe3,0x1e,0xf4,0x10,0xb1,0x3f,0xc,0x4c,0x65,0x7b,0xa0,0x23,0x1c,0x9d,0xed, + 0x2b,0x33,0x7a,0x11,0xb,0x53,0x64,0x2,0x13,0x91,0xf8,0xc3,0x1f,0x1a,0xb1,0x9, + 0x51,0x4,0x82,0x4,0x6b,0x10,0xf3,0xa5,0x8e,0xa7,0x16,0x20,0x82,0x31,0xc,0x44, + 0xd0,0x83,0x1,0xf2,0x50,0x8b,0xb9,0x86,0xc3,0x1a,0x76,0x76,0x32,0x9d,0xed,0x31, + 0xe5,0x6d,0xb8,0x43,0xcf,0x4d,0xee,0x2b,0x3e,0x90,0x81,0x4,0xd2,0x42,0xe0,0x5, + 0x2f,0x68,0x52,0xa2,0x15,0xfd,0x81,0x46,0xe3,0x18,0xd2,0x92,0x2e,0x3,0xad,0xa, + 0x41,0x8,0x22,0xa0,0xd5,0x8,0x81,0xd0,0x80,0x2b,0x70,0xfb,0x8d,0x6b,0x94,0x18, + 0x1a,0xee,0xa0,0x76,0xa9,0x89,0xeb,0x6a,0xdf,0xfa,0xc3,0x1d,0xc4,0xbd,0x32,0x72, + 0xf1,0x41,0xd,0x5c,0x98,0xe2,0xf,0xfb,0xa4,0x0,0x5,0x68,0xf0,0x86,0x66,0xfa, + 0x21,0xb,0x45,0x18,0x4,0x1f,0xe2,0x29,0x29,0x62,0x7,0xc9,0xb,0xd5,0xa,0xc3, + 0xd,0xe0,0x40,0x2,0x46,0xc,0x43,0xae,0xef,0xf0,0xad,0x81,0xfe,0x4b,0xbc,0x8f, + 0x3a,0xb3,0x3,0x1d,0xd7,0xe6,0xc7,0x3a,0xb0,0xd1,0x8d,0x73,0xa8,0x43,0xa4,0xf2, + 0x70,0x85,0x8,0xf6,0x50,0x82,0x29,0x34,0x69,0x6,0x2c,0x21,0xb7,0xb9,0x1f,0xcd, + 0xb3,0x5f,0xc5,0xca,0xcc,0x3d,0xb6,0xc2,0x20,0xc4,0x30,0x87,0x1e,0xfc,0x41,0x18, + 0x25,0xb5,0x2b,0x3d,0xb2,0x71,0x8f,0x7f,0x2b,0xf9,0xe9,0xbf,0x5,0xb8,0x3f,0xf0, + 0x11,0x60,0x6a,0x0,0xe3,0x13,0x60,0x50,0x82,0x1e,0xc4,0x20,0x6,0x2e,0x4c,0x9c, + 0xf,0xc3,0xab,0xd8,0x7,0x1d,0x95,0x3,0xb7,0x8d,0xd9,0xe2,0x5f,0x18,0x43,0x13, + 0x72,0xe0,0x86,0x2f,0x14,0x41,0xc,0x91,0x40,0x6,0xd5,0xcf,0xc1,0x64,0x7f,0xa0, + 0x63,0x1b,0xd8,0xce,0x77,0xd4,0xb7,0x41,0x5c,0x7f,0x60,0x59,0x1d,0xf2,0x70,0x46, + 0x29,0xde,0xf0,0x0,0x2f,0x44,0xc0,0x7d,0x3a,0x68,0xc9,0xd,0xb8,0x55,0x6e,0x47, + 0x4f,0x24,0x7b,0x3f,0x37,0xb3,0x1,0xc3,0xc0,0x4,0x4a,0x90,0xa1,0xe,0x60,0x30, + 0x5,0x66,0xa9,0xae,0xe,0x27,0xdf,0xe3,0x1e,0xda,0xd0,0x7,0xd4,0x9f,0x8e,0xe, + 0xe4,0x9a,0xb4,0x16,0x8f,0x40,0xc1,0x1c,0x10,0x41,0x7,0x15,0x54,0x4c,0x89,0x1f, + 0x4,0x61,0xe1,0x78,0x50,0x88,0x45,0xb8,0xc1,0xec,0xc3,0x36,0x5f,0x43,0xc2,0x60, + 0x2,0x36,0x9c,0x81,0x8,0x46,0x78,0xc3,0x2f,0xf0,0xf1,0xc,0xba,0xaf,0x1a,0x1b, + 0xd8,0x58,0x87,0x9e,0xd3,0xa1,0xf7,0x91,0xfb,0xe3,0x1d,0xc6,0x7d,0xc7,0x33,0x90, + 0x91,0x89,0x16,0x50,0xa0,0x8,0x63,0x58,0xc1,0x22,0x3e,0xfe,0x90,0x92,0x9a,0x31, + 0xba,0xd1,0x3b,0x7f,0x7c,0x8e,0x2b,0x26,0x79,0x2d,0x4,0x73,0xd,0x3d,0x68,0x3, + 0x2e,0xe6,0xba,0x59,0xcf,0xd7,0xa3,0x1e,0xa8,0x16,0xfd,0xd3,0xd9,0xe1,0x8e,0x6d, + 0x6c,0x63,0xc9,0xf8,0x60,0xc6,0x2d,0x70,0xd0,0x83,0x39,0xac,0xa1,0x6,0x2a,0x70, + 0x69,0xb7,0x67,0x40,0x4,0x58,0x56,0x3d,0x26,0x79,0x68,0x83,0x28,0x64,0xb6,0x7b, + 0x3c,0x40,0x4a,0x62,0x40,0x3,0xc3,0xb7,0x59,0xae,0xb6,0xd,0x56,0x46,0x5c,0xcb, + 0xd7,0x7c,0x9b,0xf5,0xe,0x0,0xf6,0xd,0xc2,0x0,0xa,0x6,0x40,0x1,0x46,0x0, + 0x7,0x44,0x30,0x4,0x53,0x82,0x6c,0x26,0xe1,0x2,0x2b,0x0,0x2,0x20,0x0,0x7e, + 0xe7,0xd6,0x35,0x12,0x14,0x6,0x10,0x65,0x6,0x87,0xa0,0x1,0x98,0x90,0xc,0xf8, + 0x50,0xd,0xa2,0xa7,0x7c,0xfc,0xf0,0x79,0xa8,0xe6,0x77,0xf2,0xa7,0x64,0x27,0xb6, + 0x64,0xcf,0x80,0xb,0x9e,0x30,0x1,0x83,0x0,0x41,0xbe,0x52,0x6,0xb0,0x62,0x5, + 0x66,0xc0,0x40,0x82,0xd0,0x40,0xae,0xc2,0x47,0x52,0x8,0x7,0xc3,0x72,0x76,0xba, + 0xc7,0x10,0xb5,0x92,0x3,0x4c,0xf0,0x6,0xa0,0x30,0x57,0xd6,0x60,0x60,0x52,0x57, + 0x81,0x7a,0x56,0x60,0x79,0x35,0xd,0x54,0x7,0xc,0x91,0x50,0x0,0x13,0x0,0x9, + 0xb1,0xa4,0x6,0x1f,0x50,0x8,0x41,0xa0,0x2,0x44,0x50,0x4,0x44,0xb0,0x30,0x25, + 0x30,0x2,0x23,0xc0,0x82,0x3c,0x37,0x31,0xea,0x86,0x36,0x15,0xa3,0x84,0xd8,0x55, + 0xa,0xdc,0x75,0xe,0xe8,0xe0,0xf,0xe9,0xc0,0xf,0xfe,0xe6,0x90,0x67,0xfc,0xd0, + 0x64,0x73,0x86,0x65,0xc2,0x25,0x75,0xfa,0xf0,0xc,0xa6,0xb0,0x4,0x45,0x70,0x6, + 0x46,0xc4,0x6,0x8e,0x42,0x7,0xaf,0x92,0x47,0xaf,0xb2,0x43,0xaf,0x92,0x6,0x87, + 0xa0,0x31,0x3b,0x90,0x6,0x69,0xa0,0x7,0x55,0x98,0x7b,0x49,0x1,0x20,0x8a,0x54, + 0x4,0x2d,0x40,0xd,0x38,0x8,0x86,0xe1,0xb5,0xe,0xc4,0x45,0xf,0xfe,0x50,0x72, + 0x79,0x75,0x5e,0xe2,0x80,0x7a,0x15,0xd0,0x2,0x7e,0xc0,0x5,0x2c,0x70,0x3,0x6e, + 0x70,0x4,0x2e,0xe0,0x5,0xf,0x10,0x4,0x44,0x50,0x3,0x35,0x40,0x87,0x33,0x70, + 0x87,0x79,0x18,0x7e,0x12,0x91,0x63,0x61,0x60,0x9,0xa6,0x41,0x8,0x4f,0x90,0x6, + 0x24,0xc0,0xa,0x98,0xa5,0x59,0x29,0xc7,0x7c,0x52,0xe7,0x83,0x4d,0xd6,0x77,0xfb, + 0xe0,0xe,0xeb,0x60,0x57,0xbc,0x90,0x7,0x2d,0x20,0x6,0x61,0x10,0x7,0x55,0xb0, + 0x8e,0x98,0x8,0x88,0x6b,0x60,0x6,0x6b,0x90,0x6,0xf1,0x48,0x8a,0xf4,0x98,0x6, + 0x73,0x70,0x8f,0xc1,0x46,0x3b,0xe7,0xa6,0x29,0x63,0xe0,0x5,0x5f,0x60,0x4,0xb4, + 0x80,0xf,0xde,0x80,0x72,0x7,0x6,0x70,0x4e,0x46,0xf,0xfb,0x30,0x70,0xf2,0x40, + 0xd,0xab,0xf0,0x3,0xfc,0xa7,0x4,0x35,0x20,0x5,0x65,0xc2,0x3,0x65,0x92,0x3, + 0x41,0x20,0x4,0xc8,0x88,0x53,0xcb,0x88,0x87,0x7a,0x28,0x7e,0x3d,0x27,0x7,0x2, + 0x4,0x7,0x3b,0x40,0x6,0x3d,0xe0,0x69,0xf2,0xe0,0xd,0xde,0x50,0x62,0x87,0x58, + 0x60,0xbf,0x85,0x65,0x4e,0x96,0xd,0x4d,0x66,0xfe,0x65,0xfa,0x20,0xf,0xb2,0x80, + 0x3,0x38,0xd0,0x8,0x82,0x50,0x2b,0x6c,0x50,0x5,0xb6,0xe2,0x2b,0xf3,0x12,0x85, + 0xaf,0xf2,0x2a,0x43,0x43,0x2f,0xfa,0xf8,0x68,0xfc,0x48,0x4,0x70,0x50,0x7,0x50, + 0xd5,0xd,0x86,0xc8,0x8d,0xe1,0xc5,0x88,0xf4,0xd0,0xd,0xde,0x80,0xf,0xc9,0xc0, + 0xa,0x6d,0x50,0x1,0x3d,0xa0,0x4,0x5b,0x10,0x2d,0x3c,0x0,0x6e,0x36,0x40,0x91, + 0x4d,0x62,0x91,0xc7,0x88,0x8c,0x44,0xb0,0x91,0xcd,0xe8,0x78,0xcf,0x8,0x69,0x56, + 0xc0,0x4,0x70,0x80,0x8,0x64,0xd0,0x2,0xd8,0x98,0x59,0x4c,0x76,0x62,0xa2,0xf6, + 0x74,0x74,0x45,0xf,0x3c,0xf8,0x64,0x91,0xc8,0xa,0x73,0xa0,0x4,0x87,0xb0,0x5, + 0x35,0x20,0x40,0xe6,0xe4,0x28,0xc3,0x33,0x5f,0x95,0x3,0x27,0x8c,0x62,0x5,0xd9, + 0xb3,0x8f,0x2b,0xf2,0x5,0x5c,0x60,0x4,0xac,0x40,0x75,0xca,0x77,0x62,0xee,0x60, + 0x67,0x6,0x49,0x8b,0xfa,0xf0,0xd,0x9d,0x0,0x53,0x4a,0x90,0x2,0xcf,0xf2,0x39, + 0x57,0xe0,0x95,0xf3,0x93,0x3,0x73,0x48,0x96,0x2e,0xc0,0x8c,0x1d,0x99,0x96,0x5d, + 0x43,0x1e,0x5b,0x30,0x7,0x8c,0x10,0xa,0x98,0x35,0xd,0xe7,0x30,0x60,0xd8,0xc0, + 0x8d,0x50,0x47,0x5c,0xd9,0xe0,0x64,0x7d,0x75,0xa,0x29,0x20,0x4,0x94,0x40,0x9, + 0x35,0xf0,0x4,0xc0,0x19,0x2c,0xae,0xc5,0x2b,0xe0,0xe1,0x2e,0xc6,0x89,0x7b,0x13, + 0xc3,0x98,0x44,0x91,0x5,0x7e,0xa0,0x1,0xcc,0x90,0x5b,0xf7,0x50,0xf,0x75,0xb9, + 0x6f,0x9f,0x47,0xf,0xd7,0x80,0xf,0x97,0xfe,0x80,0x4,0x24,0xe0,0x7,0x1f,0xd1, + 0x41,0x41,0xd0,0x4,0x3c,0xe0,0x3e,0x3c,0x10,0x3f,0x65,0xa2,0x3,0x37,0x30,0x87, + 0x74,0x78,0x9a,0x1c,0xe9,0x8c,0x11,0x91,0x63,0x6d,0x79,0x79,0x99,0x20,0xe,0xf8, + 0x40,0x77,0xfb,0xe0,0xf,0x2b,0x17,0x70,0xfc,0xa6,0x64,0xb3,0x38,0x67,0x66,0xf8, + 0xa,0x60,0xf0,0x4,0x10,0x15,0x40,0xc2,0x84,0x4c,0xc4,0x19,0x39,0xc7,0x49,0x2b, + 0xba,0x12,0x3c,0x8e,0x93,0x80,0x5d,0xc3,0x9c,0xa,0x91,0x5,0x34,0x80,0x9,0xb, + 0xa9,0xf,0xd3,0x59,0x9d,0xbf,0x55,0x62,0xf7,0xc0,0xf,0xd8,0xe0,0xd,0xc0,0x80, + 0x4,0x62,0x70,0x3,0x7b,0xc0,0x3,0x24,0x8a,0x2d,0x96,0x31,0x33,0x7a,0x51,0x26, + 0x33,0x90,0x9e,0x45,0xb0,0x30,0x26,0x50,0x2,0x2f,0x90,0x9a,0xef,0x9,0x69,0x82, + 0xb0,0x3,0x75,0xd0,0x6,0xce,0xf0,0xd,0xfa,0x50,0x88,0xe6,0x80,0x67,0x2,0xa7, + 0xf,0xf4,0xb0,0x88,0x4a,0x26,0x8e,0xd9,0xa6,0xe,0xbf,0x0,0x6,0x21,0x28,0x8, + 0xfe,0x1,0x41,0xee,0x66,0x39,0xdf,0x33,0x5f,0x14,0x63,0x98,0x17,0x3,0x2f,0x45, + 0x29,0x7e,0x9a,0x92,0x5,0x1a,0x80,0xb,0xb9,0x45,0xf,0xf0,0x67,0xe,0xcd,0xf7, + 0x5b,0xfc,0x50,0xf,0xdc,0xe0,0x77,0xdf,0x80,0x9,0x7e,0xb0,0x2,0x24,0x74,0x5, + 0x3c,0x70,0x30,0xaa,0x63,0x12,0x29,0xa,0x4,0x40,0x80,0x73,0x8a,0x86,0x82,0xe0, + 0xe7,0x9e,0x87,0x2,0x69,0xd5,0xd8,0x3,0xc8,0x20,0xf,0xfa,0x60,0xd,0x88,0x8, + 0xd,0x26,0xe6,0x77,0xe6,0xf5,0x79,0xfe,0x42,0xa,0x86,0xb2,0xa8,0xf,0xd3,0xf0, + 0xd,0x91,0x20,0x3,0x19,0x73,0x8,0x4f,0x90,0x5,0x4,0x74,0x6,0x50,0x70,0x7, + 0xed,0xf2,0x44,0x66,0x40,0x8a,0x42,0x13,0x94,0x9a,0xea,0x3d,0x55,0x9a,0x96,0x57, + 0xfa,0x7,0xcf,0x20,0x57,0x5c,0xfa,0x79,0xc2,0x55,0x6a,0x61,0x4a,0x9d,0x48,0x96, + 0xb,0x13,0xb0,0x2,0x71,0xf0,0x2,0x26,0x34,0x4,0x49,0x50,0x4,0xb2,0x9a,0x8c, + 0x49,0xa0,0x3,0x40,0x10,0x3,0xb8,0xba,0xa2,0x8a,0xb6,0x2,0x2f,0x2a,0xa3,0x77, + 0xfa,0x1a,0xb1,0x12,0x29,0x70,0x10,0x6f,0xb7,0x40,0x9f,0x29,0x99,0xe,0xf0,0x0, + 0xf,0x26,0x76,0x65,0x9b,0x75,0x9d,0xab,0x6,0x86,0xe9,0x90,0x90,0xf8,0x20,0xc, + 0x14,0x30,0x9,0x72,0x70,0x8,0x73,0x90,0x6,0x66,0xa0,0x98,0x8a,0x44,0xa9,0x68, + 0xa3,0x84,0x98,0x3a,0x94,0xef,0xa8,0xa9,0xb0,0x92,0x3d,0xd1,0xf5,0x10,0x95,0x83, + 0x25,0xfe,0x21,0x6,0x9e,0xa0,0x57,0xed,0x0,0x7f,0xfc,0x0,0x75,0xfc,0x0,0xf, + 0xf3,0x0,0xf,0x64,0xfa,0x6,0x52,0x0,0x4,0xe0,0x6,0x4,0x3a,0x20,0xab,0x46, + 0x60,0x4,0xb2,0x2a,0x68,0x44,0x4,0xa7,0xe8,0xe9,0x7d,0xbc,0xa,0x7e,0x91,0xf2, + 0x3d,0x21,0x43,0x1e,0xc0,0xc2,0x26,0x56,0xb0,0x5,0x48,0x10,0xa,0xdf,0x60,0x5c, + 0x4c,0xa6,0x83,0x63,0xa8,0x77,0x7a,0xf6,0x83,0x6,0x96,0x67,0xc8,0x55,0xb,0x2d, + 0xc0,0x7,0x44,0x0,0x8f,0xef,0x18,0x6c,0xc0,0xe2,0xa4,0xde,0x3,0x94,0x8b,0x93, + 0xb2,0x8b,0x13,0xac,0x2e,0x68,0xfe,0x2c,0xc4,0x93,0x38,0x66,0xa6,0x5,0x10,0xc5, + 0x4c,0x24,0x20,0xc,0x66,0x88,0xf,0x4c,0xf7,0x79,0xeb,0xa0,0x77,0x27,0x77,0x6d, + 0xef,0xc7,0xf,0x9,0x59,0xb,0x22,0xe0,0x3e,0x57,0xe0,0x4,0x40,0xc0,0x5,0x7e, + 0x20,0x2,0x65,0x70,0x3,0x2c,0xb0,0x2,0x65,0xd4,0x4,0x67,0xb0,0x1,0x21,0x50, + 0xab,0xba,0x4,0x4,0x8,0x1b,0x5f,0xb1,0x92,0xb2,0x6,0xba,0x38,0x56,0xa0,0x4, + 0x30,0x60,0xc,0xfa,0x80,0x83,0xfa,0x20,0x8b,0x25,0x26,0x6a,0x2c,0x99,0x60,0xd3, + 0xa6,0xa1,0x53,0x27,0xb,0x60,0x0,0x7,0xf1,0x2,0x94,0xf0,0x8,0x8f,0x2b,0x7b, + 0x41,0x4f,0x4,0x3e,0x76,0xcb,0xb2,0x3c,0x93,0x2e,0x93,0x72,0x28,0x8e,0xe2,0x6, + 0x4c,0x30,0x8,0x6b,0xb0,0x5,0x8c,0xf0,0xc,0xc7,0x45,0xa8,0x56,0xf6,0x74,0xf9, + 0xe0,0xf,0xf0,0x50,0xf,0xc9,0xea,0xf,0xe2,0x40,0x6,0x39,0x60,0x2,0x2f,0x70, + 0x2,0x40,0xf0,0x62,0x44,0xf0,0x5,0x52,0x0,0x5,0x3a,0xc0,0x1,0x36,0x80,0x89, + 0x4d,0xb0,0x1,0x30,0xf3,0x0,0x2c,0xd0,0x55,0x19,0x70,0xb5,0xe5,0x22,0x2c,0x0, + 0x4,0x32,0xf6,0xf2,0x50,0x6a,0x90,0x2,0x99,0x40,0x5e,0x74,0xa7,0xf,0xd8,0x60, + 0x81,0xff,0xd6,0x7c,0x68,0xfb,0xe,0x19,0xba,0x83,0xa9,0xf6,0xa1,0xac,0xf7,0x2b, + 0x51,0xe8,0x2a,0x29,0xeb,0x3b,0x77,0x3b,0xbc,0xb4,0xa3,0xb7,0x3c,0xe5,0x5a,0xe7, + 0x24,0x2f,0x7a,0x90,0x2,0x91,0x79,0xa1,0x88,0xb8,0xe,0xa3,0x47,0xa4,0x8a,0xb, + 0xf,0xd8,0xa0,0xe,0xac,0xfe,0x20,0x2,0x5e,0xf0,0x2,0x23,0x70,0x7,0x1d,0x70, + 0x3,0x63,0x40,0x4,0x1f,0x30,0x3,0x5e,0x80,0x5,0x3c,0xc0,0x12,0x44,0xf0,0x4a, + 0xae,0x24,0x5,0x1f,0x10,0x1,0x6d,0xd4,0x68,0x9,0x8b,0xba,0xf5,0xd2,0x40,0x2, + 0xd4,0xba,0xc0,0xa0,0xf,0xde,0xa0,0x60,0xf8,0xd9,0x77,0x5f,0x7a,0xbb,0xb9,0xcb, + 0xf,0xda,0x40,0x70,0x28,0x80,0x8,0x23,0x3,0xbf,0x2a,0x4b,0x85,0xc3,0x7b,0xc0, + 0xc5,0xeb,0x28,0xcf,0xe8,0x28,0x41,0x40,0x8d,0xbf,0x36,0xc,0xfa,0xc0,0xb8,0x63, + 0x58,0x67,0x4a,0x96,0xb8,0x53,0xf7,0xe,0x7a,0x66,0xf,0xef,0x20,0xe,0x3d,0x60, + 0x89,0x32,0x36,0x42,0x61,0xe0,0x2,0x67,0x90,0x42,0x1c,0x90,0x3,0x7,0x51,0x3, + 0x5b,0x60,0x4,0xfe,0xf4,0x0,0x80,0x0,0x5,0x1c,0xd0,0xab,0x9,0x6b,0xc0,0xdf, + 0x23,0xbf,0x84,0x20,0x7,0x3b,0x40,0xd,0xb0,0x86,0xbf,0xb3,0x5b,0xbb,0xfc,0xe9, + 0x83,0xb8,0x6b,0x6a,0x79,0x46,0xf,0x53,0x89,0x9,0x4a,0x90,0x5,0x74,0xbb,0x3d, + 0x27,0x3b,0xb7,0x7,0xcc,0xa9,0x2d,0x9b,0x4e,0xae,0x65,0x10,0x82,0xa0,0x56,0x98, + 0xf0,0xd,0xb0,0xa8,0x64,0xc1,0x55,0x8b,0xe6,0x90,0xd,0xff,0x8b,0xf,0xa1,0x76, + 0x72,0xf8,0x70,0xa,0x22,0x10,0x7,0x39,0xb0,0x1,0xfa,0xa,0x46,0x1c,0x80,0x5, + 0x67,0x30,0x4,0x48,0x29,0x6,0x14,0x90,0x51,0x9b,0xa0,0xb,0x7e,0x10,0x2,0x13, + 0x2,0xc3,0xa7,0x2b,0xc3,0xb2,0x2,0x92,0x20,0x19,0x45,0x81,0xf0,0xd,0x9b,0xd5, + 0xd,0x63,0x4b,0xb6,0xfe,0x3c,0xfc,0x88,0x3e,0x88,0x65,0x25,0x66,0xe,0xcf,0x87, + 0xf,0xbf,0xa0,0x1,0x6b,0x60,0x5,0xef,0x92,0x80,0xbe,0x5b,0x2f,0x4b,0x8c,0xb7, + 0x7c,0x98,0x28,0x8f,0x91,0x38,0x6e,0xe0,0x2,0xd4,0xd8,0x8,0x2d,0x10,0xb,0xf8, + 0x30,0xe,0xa5,0x36,0x65,0xbd,0x15,0x70,0x7,0x89,0x5c,0xe2,0x20,0xe,0xfa,0x70, + 0x7f,0xec,0xf0,0xe,0xdf,0x90,0x2,0x2e,0x90,0x5,0x44,0xd0,0xaa,0xdf,0x71,0x6, + 0x1f,0xb0,0x1,0x6c,0xc9,0x61,0x17,0x90,0x9,0xbf,0x50,0x52,0xa2,0x20,0x2,0x72, + 0xf0,0x1,0x74,0x9c,0x43,0x46,0xa3,0x3b,0x47,0x9c,0x2e,0xc,0xf4,0x5,0x84,0xd0, + 0x8,0x3a,0xba,0x5b,0xf8,0x9,0xc8,0x5f,0x9a,0xa1,0x58,0x56,0x77,0x2a,0xe7,0x77, + 0x4,0x87,0x9,0x64,0x0,0x7,0x8d,0xfc,0xad,0x2a,0x1b,0xc9,0xf2,0xd5,0x73,0x94, + 0x1c,0x24,0x66,0x36,0x6,0x74,0xb0,0x6,0x75,0xf0,0x7,0x50,0x35,0xe,0xe0,0x50, + 0x6a,0xe8,0xb0,0xe,0x9f,0xd7,0xe,0xed,0xa0,0x57,0xcf,0xa0,0xc,0xa5,0xf0,0x9, + 0xcf,0xf0,0x85,0xdb,0x80,0xd,0xf8,0x50,0xa,0x22,0xf0,0x4,0x4c,0x70,0x42,0x1c, + 0xe0,0x5,0x2e,0x80,0x94,0x6b,0xa0,0x1,0x15,0xf0,0x9,0xc3,0x80,0xf,0x7e,0x46, + 0xb,0x4,0xc0,0x4,0x1b,0xf0,0xcb,0x88,0x39,0x56,0x16,0xa3,0x5,0x41,0x0,0x83, + 0xd,0x45,0x8,0x9b,0x80,0xf,0xef,0xe0,0xc7,0xfe,0x30,0xbb,0x64,0x3b,0x7a,0x4b, + 0x46,0xc8,0xb5,0x88,0x9f,0xa4,0x2c,0xb,0x28,0xe0,0x7,0x67,0xd3,0x2e,0x98,0xf8, + 0x28,0x91,0x46,0xfe,0xb2,0xda,0x2c,0xc9,0x12,0xe3,0x3b,0x58,0x82,0x3e,0x8e,0x32, + 0x5b,0x8d,0xa0,0x1,0x9f,0x20,0x90,0xf6,0x0,0xe,0xe0,0xd0,0x92,0x4e,0xd6,0xe, + 0xf1,0xd0,0x57,0xc3,0x0,0xa,0x1a,0xa0,0x4,0x6,0xf0,0xa,0xf6,0x60,0xd,0xe1, + 0x15,0xe,0xca,0xd0,0x3,0x3b,0x90,0x5,0x39,0xb0,0x48,0x37,0xf0,0x98,0x6d,0x5c, + 0xa,0x36,0x68,0xd1,0xe1,0x50,0xd,0xf9,0xd7,0x0,0x59,0xb0,0x78,0xee,0x1b,0x29, + 0x8a,0x79,0x36,0x31,0xdd,0xc0,0x84,0x20,0x4,0xfe,0x83,0xcc,0x1,0x77,0x9f,0x80, + 0xcc,0xd1,0xcf,0xac,0x9f,0xdb,0x90,0x57,0xdf,0xf0,0x9,0x4a,0x50,0x4,0x1,0x14, + 0x6,0x6c,0x77,0xd2,0x68,0xe3,0x2a,0xef,0x68,0xc7,0x4b,0x9c,0x63,0xe,0x44,0x14, + 0x40,0x41,0x4,0x7e,0xd0,0x8,0x15,0x60,0xb,0x73,0x65,0xf,0xf7,0x47,0x5e,0x33, + 0x9,0x61,0x10,0x56,0xb,0x98,0x40,0x3,0x83,0x62,0x4,0x4b,0x0,0xaa,0x84,0xed, + 0x6a,0xdf,0x10,0xa,0x10,0x99,0x5,0x2a,0x10,0x2,0x7c,0x80,0x1,0x6f,0x90,0xa, + 0x72,0x57,0x9f,0xc0,0x65,0xd,0x91,0xb8,0x4,0x62,0x10,0x2,0x7,0x8b,0x28,0xb8, + 0xa7,0x36,0x99,0x24,0x40,0x44,0xd0,0x43,0x29,0xf0,0x7,0xcd,0x70,0x9f,0x7d,0x57, + 0x81,0xcf,0xa,0x75,0x69,0xdd,0x77,0xf7,0xe7,0x72,0x54,0xd9,0x3,0x89,0x20,0x6, + 0x35,0xa0,0x6,0x8a,0x90,0x3,0x8b,0x70,0xd2,0xd6,0x15,0xb7,0x78,0x8d,0xc0,0x90, + 0xb6,0xd7,0xfd,0x38,0x10,0x43,0x50,0x6,0x8e,0x9d,0x9,0xcf,0x40,0x57,0xd9,0xb0, + 0x67,0xfa,0xfe,0x10,0x60,0x25,0x25,0xf,0xb0,0x70,0x9,0x79,0xf0,0x6,0x13,0x70, + 0x7,0xa3,0xd0,0xa,0x3d,0x80,0x4,0xb3,0x10,0xd9,0xec,0xa0,0xf,0xc5,0x60,0x0, + 0x8d,0xa0,0x4,0x4a,0x20,0x3,0x6f,0x10,0xb,0xca,0x60,0x57,0xd5,0x10,0xe,0xf6, + 0x60,0x62,0x95,0x69,0xbf,0x48,0x7a,0x3,0x7f,0x51,0x2,0xa6,0x5d,0x5f,0xc5,0x62, + 0x9,0x4c,0x10,0x49,0x15,0x85,0x2,0xc1,0x90,0x7c,0xc9,0x47,0x5c,0xb0,0x8d,0xd6, + 0x75,0xa7,0xbf,0xbf,0xa5,0x81,0xe7,0xf5,0xb,0x2d,0x50,0x7,0x89,0xe0,0xca,0x96, + 0xd0,0x4,0xf0,0x62,0xd7,0x3b,0xb6,0xd2,0x7a,0x6d,0x2f,0xf,0x41,0x10,0x39,0x0, + 0xb8,0x6,0x30,0xb,0x73,0xb5,0xe,0xef,0x47,0xf,0x7e,0x46,0xd,0xb2,0xf0,0x3, + 0x68,0x80,0x6,0x12,0x80,0x4,0xf3,0xb6,0x90,0x91,0x80,0x2,0x76,0xf0,0x6c,0xd4, + 0xb6,0xe,0xf2,0xa0,0x9,0xe9,0xd7,0x6,0xb1,0x30,0xd,0x62,0x1b,0xe,0xbe,0x65, + 0x62,0x80,0x6a,0xf,0xe1,0xe0,0xd,0x3e,0x10,0xa2,0xf7,0x9d,0xdf,0x6a,0xd0,0x2e, + 0xf0,0x2,0x41,0x19,0xb3,0x5,0x4a,0xf0,0x6,0x76,0x30,0xd,0x1,0x7,0xc8,0xfb, + 0x49,0xdb,0x7d,0x37,0x60,0x4a,0xf6,0xe,0x80,0x27,0xf,0xbf,0xb0,0x54,0x64,0x90, + 0x5,0x8a,0x70,0x4,0x46,0x3e,0xdc,0xaf,0x52,0xdc,0xc4,0x7b,0xdc,0x18,0x4e,0x10, + 0x1f,0x34,0x8,0x64,0x0,0x6,0xcc,0xf0,0xe,0xeb,0x60,0xe,0xf3,0xc0,0xd,0x76, + 0xf5,0xc,0xa9,0xf0,0x6,0x3e,0xf0,0x7,0x12,0x80,0x6,0xb0,0x80,0x59,0x23,0x45, + 0x93,0xfe,0x17,0x70,0x1,0xb6,0xa0,0xf,0xe3,0x60,0xf,0x57,0x56,0xc,0xcc,0x86, + 0x59,0xd5,0x60,0xf,0xe3,0xf0,0x85,0x82,0x9e,0xac,0x41,0x58,0xd,0xcc,0xa0,0x1, + 0x5c,0xb0,0x78,0x2f,0x4a,0xe4,0x46,0x4e,0x98,0x74,0x20,0x4,0x88,0xb0,0x5,0x8d, + 0x50,0x7,0x59,0x2a,0x7a,0x4f,0x39,0xe5,0xa0,0xbe,0x9f,0x7,0x1e,0xe5,0x76,0x36, + 0x70,0x72,0x5,0xc,0x12,0xa0,0xdb,0x70,0xf0,0x5,0xf0,0x12,0x69,0x15,0xae,0xcd, + 0x39,0xd6,0x26,0x66,0x3e,0x6,0x45,0xa0,0x4,0xac,0xa0,0xe,0xe7,0x90,0x72,0x76, + 0x35,0xb,0x4,0x20,0x3,0x22,0x20,0x3,0x92,0x50,0xb,0xf4,0x99,0x5b,0xc8,0x35, + 0x52,0x76,0x80,0x4,0x76,0x80,0xf,0xf0,0xed,0xf,0xff,0x4b,0x52,0x37,0xf8,0x74, + 0x6d,0xae,0x88,0xee,0xb0,0x59,0xaa,0x2a,0x68,0x80,0x81,0xdf,0x70,0xe2,0x36,0x95, + 0x8e,0xd2,0x59,0xb0,0x3,0x73,0x90,0x54,0xa9,0xa0,0xec,0xf6,0xc7,0x77,0x1f,0x1d, + 0xea,0xa2,0xe,0xea,0xfa,0x96,0xa1,0x73,0x66,0xd0,0xf8,0x0,0xc,0x15,0xf0,0x6, + 0x46,0x40,0x7,0xe9,0xf2,0x44,0x76,0x2d,0xe6,0x77,0x1b,0xeb,0x2d,0x32,0x10,0x58, + 0x20,0x1e,0x45,0xf0,0x6,0xcc,0xa0,0xe,0x65,0xeb,0xf,0xde,0x30,0xd,0x92,0x20, + 0x3,0x80,0x30,0x9,0xba,0x90,0x5b,0x72,0x46,0xa8,0x51,0x89,0xf,0xab,0x50,0x1, + 0x28,0xd0,0xb,0x3b,0x2a,0x8e,0xa9,0xc6,0xa7,0xd4,0x86,0x60,0xba,0x9b,0x90,0xc8, + 0xc5,0x9,0x45,0xd0,0x1,0x57,0x10,0x3,0x93,0x9e,0xed,0x9,0xa,0x2f,0x5d,0x20, + 0xfe,0x8,0x29,0x10,0x8,0x2d,0x80,0x9,0x50,0xa5,0xb1,0xae,0x66,0x6a,0x53,0x8e, + 0x6d,0x2d,0xd9,0x64,0x8b,0xf8,0x6f,0xad,0xa6,0xce,0xed,0x10,0x60,0x72,0x35,0xc, + 0x1a,0x10,0x8,0x66,0x43,0x98,0x3a,0x66,0xef,0x76,0x8b,0xef,0x58,0xa2,0xef,0xcd, + 0x92,0x5,0xad,0x20,0xf,0xdf,0x50,0x62,0xf0,0xb0,0xf,0xc6,0x45,0xa,0x18,0x80, + 0x7,0xba,0x10,0x60,0x9d,0xb7,0xa1,0xa2,0x96,0xb8,0xf8,0xe0,0xc,0x38,0xe0,0x7, + 0x92,0xe0,0xd,0xf0,0xbd,0xd,0xf0,0xa7,0xcc,0x94,0x49,0xe0,0xda,0x30,0x67,0x1, + 0x36,0xad,0x34,0x90,0x4,0x30,0xa,0xf2,0xd8,0xee,0x1c,0x2f,0x88,0x36,0xf2,0x12, + 0x8,0x9e,0x60,0x95,0xb0,0xa9,0xe,0x9c,0x15,0x75,0xe1,0x25,0x72,0x1d,0xdd,0x77, + 0xf2,0x37,0xea,0x4e,0xe7,0x5b,0xf7,0xa9,0xbb,0x74,0xc5,0x62,0xbf,0x20,0xda,0x63, + 0xa0,0x2b,0xd6,0xa5,0x31,0x95,0x54,0xc0,0x90,0xcc,0xc4,0xda,0x43,0x31,0x59,0x5b, + 0xb2,0x55,0x48,0x38,0xf,0x91,0x5,0x81,0x40,0x9f,0xef,0x80,0x77,0xf0,0xb0,0xd, + 0xf6,0xcb,0xc,0x3e,0x80,0x1,0x95,0xf0,0x5f,0x4c,0xd6,0xa3,0xa2,0xc6,0x77,0xe7, + 0x65,0xa,0xfa,0x74,0xc,0x39,0x8,0x7f,0xb4,0x78,0x81,0xe9,0xa0,0x7c,0x7,0x69, + 0xd0,0x7f,0x36,0x1,0x1f,0xa0,0xbd,0x6a,0x8f,0x28,0x66,0x46,0xbe,0x6e,0x40,0x4, + 0x90,0x40,0x3,0x48,0x90,0xa3,0xff,0xd5,0x59,0xa2,0x67,0xd6,0xe4,0x5e,0xd4,0xae, + 0xd6,0x59,0xd0,0x97,0x81,0xa,0xf6,0xcc,0x60,0x68,0x81,0x84,0xba,0x88,0x48,0xfe, + 0x86,0xf,0xbd,0x80,0x1,0xf9,0xa,0x4,0x71,0x10,0x5,0x35,0x0,0x8a,0xe3,0x4a, + 0xae,0xc1,0x7b,0x41,0x59,0x1b,0xf9,0x8e,0xe3,0x36,0x64,0xf3,0x8e,0xb5,0x52,0x8, + 0x51,0x0,0xd0,0x45,0xb7,0xa7,0xe2,0x3e,0x86,0xf6,0x8b,0xf,0xae,0x40,0x3,0x14, + 0x80,0xc,0x38,0x1e,0xe8,0xd6,0x16,0x5e,0x99,0x79,0xf5,0x17,0x60,0x7,0xa1,0xa0, + 0xf0,0xf1,0xd0,0xe,0x3d,0x58,0x7f,0xe1,0x85,0x67,0x0,0xc1,0x8f,0x9e,0x3c,0x71, + 0xf2,0x62,0xd1,0x8,0x31,0xe5,0xc4,0x89,0x11,0x26,0x4a,0xa8,0x81,0x18,0x51,0x4d, + 0x98,0x42,0x3c,0xa,0xd,0xe1,0x23,0x6,0x8c,0xad,0x69,0xde,0xd6,0x7d,0x5c,0xe7, + 0xce,0x1f,0x3f,0x73,0xeb,0xfc,0x85,0xb4,0x67,0x4f,0xdf,0x3b,0x96,0xf8,0x5c,0x4e, + 0xc3,0xd7,0x52,0xdf,0xca,0x99,0x1f,0x4f,0x9a,0xf4,0x37,0x92,0x9f,0xbf,0x6e,0xfa, + 0xa6,0xf9,0x92,0x1,0x8,0xc8,0x95,0x42,0x82,0x52,0x1c,0x5a,0x3,0xc7,0xcc,0x52, + 0x33,0x6b,0x9a,0xc2,0x81,0x5a,0xa6,0x8c,0x1c,0xa9,0x70,0xa4,0x4e,0xc,0x13,0xe6, + 0x8c,0x1c,0x35,0x4a,0xd7,0xa4,0x31,0xb3,0xc8,0x46,0xa1,0x20,0x70,0xf4,0xd4,0xa9, + 0x20,0x8b,0x5a,0x4c,0x7d,0xee,0xf8,0xf1,0x73,0xa7,0xf2,0x1b,0xb2,0x1e,0x4b,0x3c, + 0xc5,0xb4,0xc7,0x2e,0x65,0x5c,0x7d,0xdf,0xf0,0x7d,0xf3,0xe4,0x23,0xc1,0x30,0x79, + 0xf2,0xe2,0xdd,0xbb,0xe7,0x2f,0xa5,0x3d,0x77,0x22,0xfd,0x69,0x53,0xe7,0xb7,0x16, + 0x98,0x14,0x52,0x46,0x20,0x38,0x11,0xc3,0xa1,0xc4,0x88,0x72,0xc2,0x10,0xfe,0x62, + 0x42,0xc7,0x8f,0x6,0x56,0xf8,0xce,0xbd,0x5b,0xb7,0xaf,0xb1,0xbb,0x7c,0xeb,0x76, + 0xfa,0x7b,0x37,0xd3,0x9b,0x3e,0x7c,0xcc,0x6c,0xa1,0xa,0x75,0x4a,0x96,0xad,0x61, + 0x7e,0x5d,0x7a,0x8b,0xad,0x2f,0xa7,0x3f,0x74,0x8b,0xf7,0xe5,0x5c,0x17,0x1b,0xdf, + 0x2e,0xc,0x62,0xf8,0x30,0x51,0x21,0xa8,0x6,0x54,0xa8,0x4b,0x95,0x52,0xb7,0xaa, + 0x46,0xea,0xf6,0x32,0x10,0xe5,0x78,0xfe,0x5e,0x46,0xa9,0x19,0x38,0x61,0xd8,0xe4, + 0x20,0x82,0x68,0x4e,0x8f,0x50,0xe2,0x5c,0xbe,0xf3,0xe7,0xd6,0x1c,0x3c,0x7e,0xfa, + 0xa8,0xc9,0xb,0x85,0xa3,0xc2,0xb0,0x98,0xe7,0xf4,0x75,0x8b,0xed,0x1b,0x79,0x70, + 0xa9,0x84,0xb,0x40,0x8,0xc8,0xc5,0x25,0xc4,0xf8,0xc9,0x8b,0x1d,0x76,0xb6,0xf1, + 0x7,0x9b,0x9e,0x5c,0xc2,0x25,0x92,0x6,0x8a,0x90,0xc2,0x84,0x17,0x5e,0xd0,0xec, + 0x21,0xce,0xb4,0x93,0x4a,0x10,0x23,0x1a,0xc1,0x64,0xad,0x95,0x4c,0xda,0x67,0x9b, + 0x6d,0xf6,0x31,0xe9,0xbf,0x99,0xde,0xa1,0xf0,0x11,0x1c,0xc0,0x0,0x3,0x5,0x14, + 0x5a,0x68,0xc1,0x8e,0x4c,0x6c,0x79,0x46,0x1d,0x7c,0x66,0x12,0x6e,0x31,0x21,0xed, + 0x81,0xd,0x46,0x7c,0x7e,0xb9,0x20,0x90,0x1a,0x6e,0xd8,0x23,0xc,0xaa,0xaa,0xc2, + 0x8e,0x3a,0xee,0xb8,0xeb,0xec,0x3b,0xaa,0x40,0x94,0x23,0x8a,0x30,0xe8,0xc8,0x62, + 0x87,0x3a,0x18,0x59,0x8b,0xad,0x93,0x46,0x82,0xa7,0x9e,0x7b,0x7c,0x2c,0x46,0x1, + 0x34,0x56,0x91,0xc7,0x19,0x7c,0xe4,0xf1,0x51,0x1e,0x5e,0x1c,0xb9,0xfe,0xc0,0x8f, + 0x7,0x58,0x10,0x85,0x99,0xd8,0xde,0x8a,0xcb,0x41,0x22,0xb1,0x99,0xe9,0x9c,0x69, + 0x7a,0xf1,0xa1,0x39,0x2e,0x1e,0x70,0xe1,0x8c,0xf,0x4c,0xd8,0xec,0x43,0xf1,0xb6, + 0xd8,0xa2,0xe,0x30,0x9c,0xf1,0x4b,0x1f,0x7b,0x70,0x72,0x67,0x1b,0xc7,0x92,0xd3, + 0xe7,0x99,0x37,0x4d,0x89,0x64,0x89,0x3a,0x2,0x21,0x63,0xb,0x3d,0x6,0xe1,0xc2, + 0x8f,0x37,0xc0,0xc8,0x43,0x16,0x97,0x56,0x7a,0x27,0x25,0x3f,0xed,0x41,0x7,0x9d, + 0x9c,0xe8,0xc1,0xc7,0x47,0x5e,0x2a,0x20,0x83,0x8f,0x2b,0xae,0xd8,0xca,0x4a,0x2b, + 0xb9,0xc3,0x8e,0x2b,0x88,0xa6,0xfc,0x2e,0x2b,0x65,0x8f,0x20,0x24,0x8b,0x35,0xea, + 0x40,0x81,0x9a,0x6f,0xd4,0x89,0xed,0x26,0x7b,0xf6,0xa9,0xa7,0x1e,0x6e,0x70,0xc5, + 0xa7,0x13,0x34,0x24,0x70,0x86,0x1c,0x71,0xc9,0x81,0x5,0x8d,0xa,0x68,0xf4,0x81, + 0x14,0x65,0x58,0x1a,0xd2,0x4f,0x7a,0xb4,0xd1,0xc7,0x1b,0x75,0xa6,0x21,0x65,0x82, + 0x3b,0x59,0xb8,0x21,0x84,0x10,0x44,0x50,0x61,0x86,0x46,0x39,0xb3,0x62,0xd,0x25, + 0xa0,0xfd,0xc5,0xbd,0xd8,0x18,0x6b,0x8c,0x56,0x91,0x0,0xa5,0xed,0x4d,0x56,0x7a, + 0x50,0x62,0x8d,0x53,0x7,0x29,0xa3,0x8b,0x26,0x86,0x90,0xc3,0xf,0x25,0x34,0xc8, + 0x63,0x15,0x13,0x63,0xb5,0x67,0x1c,0x91,0x85,0x1c,0xe9,0x9e,0x77,0xf1,0x29,0x6, + 0x5,0x31,0x62,0x88,0xe3,0xc,0x65,0x5f,0x76,0x52,0x3b,0xea,0xac,0x0,0xf,0xc4, + 0xed,0x3c,0x33,0x8f,0xd,0x9d,0xe5,0x80,0xc3,0x88,0x55,0x9f,0xfe,0xf9,0xe6,0x45, + 0xc6,0x70,0xda,0x87,0x9f,0x7a,0xde,0x4a,0xee,0x18,0x5,0x18,0x71,0xa5,0x9c,0x65, + 0x68,0x79,0x44,0x1,0x47,0x7e,0x40,0xc2,0x14,0x66,0xf0,0xf1,0xa6,0x1a,0x69,0x86, + 0x5c,0xec,0xcd,0xfb,0x7e,0xa9,0x44,0x84,0x7,0x74,0x0,0xc2,0x83,0x19,0xa4,0x28, + 0x42,0x84,0x22,0x5c,0xf8,0x57,0x22,0x38,0x94,0x88,0xa4,0x8d,0x55,0xf0,0x99,0x66, + 0xa6,0xf8,0x12,0xde,0xeb,0x2d,0x7f,0xfa,0xc2,0x7,0x97,0xb,0xc8,0xd0,0x3,0x8e, + 0x2e,0x82,0xd0,0xf2,0x8c,0x33,0xbc,0x8,0x82,0x88,0x41,0x10,0x59,0x55,0x96,0xab, + 0x2d,0x45,0x67,0x1b,0x7b,0x24,0x37,0xee,0x9e,0x6c,0xef,0xd1,0x6,0x1f,0x61,0x30, + 0x0,0xe4,0xe,0x97,0x61,0x56,0x96,0x2a,0xec,0x26,0xe2,0x6a,0xca,0x32,0xb2,0x62, + 0x23,0x8e,0x2a,0xd8,0xa0,0x23,0x85,0x46,0xc0,0x40,0xe6,0x47,0x4b,0x73,0x72,0xe7, + 0x38,0x9a,0x86,0xb3,0x27,0x1c,0x7d,0x1e,0x41,0xa1,0x8e,0x56,0x94,0x68,0x1,0x9, + 0x14,0xd0,0x80,0xc5,0x3d,0x6a,0x2d,0xb5,0x87,0x1f,0x78,0xe6,0x39,0x7a,0x6f,0x7c, + 0xa,0x72,0xc6,0x94,0x16,0x64,0x60,0x61,0x6,0x10,0x40,0x0,0x2,0xa,0x29,0xb8, + 0xa8,0x61,0xed,0xb6,0x23,0x82,0x23,0x10,0x30,0x34,0x9,0xf3,0x1a,0x7f,0xf6,0xc9, + 0xc7,0x9d,0xe2,0x52,0x5a,0x27,0x1d,0xb8,0xde,0x39,0xe7,0x19,0x14,0xde,0x40,0x44, + 0x70,0x37,0xa,0x29,0x84,0x8d,0x42,0xb2,0x72,0x83,0x2a,0x2b,0x6a,0x48,0x84,0x1, + 0x62,0xf1,0xb1,0xa2,0xed,0x24,0x25,0xe8,0x10,0x89,0xd1,0xfe,0xea,0x41,0xf,0x1f, + 0xf5,0x42,0x6,0x52,0x18,0x83,0x1a,0x3c,0xe3,0x32,0x36,0xbc,0x4c,0x3c,0x4f,0xc1, + 0xca,0x93,0x6e,0x86,0xba,0x38,0xb4,0x2c,0xb,0x75,0x40,0x82,0x30,0xb0,0x86,0x40, + 0xb7,0xc0,0x65,0x6f,0xca,0x41,0x9e,0x5e,0xaa,0x1,0xc,0x14,0x90,0x60,0x7,0x5b, + 0x20,0x1,0x18,0x72,0xe1,0xd,0x7c,0xc4,0xe3,0x1a,0xfa,0xa8,0x55,0xf2,0xe6,0xb1, + 0xc3,0x5,0xba,0x44,0x1e,0xd4,0x58,0x5,0xa,0x34,0x20,0x6,0x11,0xac,0x40,0x7, + 0x71,0x0,0x41,0x9,0x80,0xf0,0x81,0x1b,0x70,0xe1,0x6,0xfe,0xf2,0x10,0x67,0xe0, + 0xf0,0x86,0x48,0x50,0x4a,0x1d,0xfa,0xa0,0xc7,0x4e,0xe2,0x22,0x24,0x77,0xb8,0x4f, + 0x72,0xfa,0x78,0x5,0x12,0x96,0x20,0x6,0x2b,0x28,0x4b,0x67,0x6e,0x60,0xca,0xe9, + 0x9c,0x34,0x6,0x48,0x90,0x26,0x68,0xf4,0xe0,0x46,0x3d,0xe8,0xb3,0xe,0x92,0x19, + 0xed,0x1e,0xfa,0xf0,0x91,0x2f,0x68,0xe0,0x87,0x1a,0x58,0x81,0x10,0x61,0x70,0xc1, + 0xfd,0x42,0xe7,0x95,0x35,0x64,0x90,0x3b,0x74,0xa0,0x3,0x21,0xba,0x90,0xa8,0x33, + 0x8c,0x81,0x2,0x98,0xe0,0xf,0x3e,0xc2,0x91,0x40,0xbd,0xed,0xad,0x61,0x3f,0x12, + 0xd2,0x3b,0x1e,0x71,0x81,0x16,0x70,0x62,0x17,0x31,0x41,0x7,0x3d,0xcc,0xf4,0x91, + 0xc6,0x28,0xf0,0x1e,0xf1,0x78,0x53,0x31,0x58,0x21,0x46,0x25,0x18,0xa1,0x8,0x45, + 0xb8,0x81,0xe,0x74,0x60,0x3,0x1b,0xcc,0xc0,0x96,0xb6,0x5c,0xc1,0xf7,0x20,0x2, + 0x7,0x1a,0xfc,0xc2,0x37,0xda,0x20,0x9,0x5c,0x86,0xfe,0xe4,0x96,0x74,0xb8,0x43, + 0x77,0xca,0x40,0x41,0x23,0xe0,0x80,0x15,0x9d,0x39,0x29,0xd,0x87,0x0,0x8b,0x1b, + 0xcc,0x73,0x86,0x1b,0x24,0x2,0x5,0x73,0xc3,0x87,0xe5,0xb2,0xb5,0x8f,0x3,0xa6, + 0xc4,0x1f,0xf7,0xd8,0x89,0x7f,0x6,0xd5,0x82,0x44,0x18,0x21,0xb,0x72,0x50,0xc4, + 0x6,0xf2,0x97,0x15,0x9e,0x35,0x65,0xd,0x34,0x73,0x52,0x78,0xe4,0x20,0x4,0x2b, + 0x10,0x81,0xe,0x83,0xe8,0x82,0x1c,0x8c,0x80,0x89,0x63,0xe4,0xea,0x1c,0x8c,0x79, + 0x4b,0x25,0x67,0xe2,0x92,0x1f,0xdd,0x2d,0x25,0xcc,0x78,0xc5,0x2f,0xde,0x53,0x9c, + 0xe1,0xc,0x87,0x45,0xd,0xa3,0x6,0x2f,0x34,0xf1,0x3,0x1c,0x18,0x81,0x8,0x44, + 0x28,0xc2,0x45,0x89,0x70,0x83,0x1b,0xb8,0x40,0x7,0x33,0xb0,0x41,0xc,0x4a,0xa0, + 0x19,0x5d,0x76,0xc5,0xf,0x6e,0x9a,0x16,0x1c,0xf9,0x34,0xcc,0x74,0xa4,0x43,0x2f, + 0x7f,0xf1,0x84,0x12,0xe0,0x80,0xb3,0xcf,0xc1,0x21,0xd,0x73,0x0,0x8b,0x16,0x74, + 0xc6,0x6,0x37,0x14,0x61,0x9,0x38,0x80,0x85,0x4b,0x44,0x59,0x8f,0x9c,0x70,0x11, + 0x27,0x34,0x39,0x92,0x6,0xea,0x90,0x88,0x1a,0xa8,0x40,0x11,0x4d,0x18,0xa4,0x3b, + 0x97,0x69,0x25,0x65,0x31,0xc1,0x12,0x83,0x10,0x81,0x1e,0x2,0xa1,0x4,0x4c,0x30, + 0xa3,0x52,0xc2,0xf1,0x7,0x34,0x2,0x9a,0x13,0x20,0xb9,0x44,0x27,0x7a,0xd3,0x87, + 0x7f,0xde,0xa1,0xbb,0x94,0x8c,0x43,0x25,0x40,0xa2,0x8d,0x3a,0x90,0xa1,0x8a,0x46, + 0xb4,0xa0,0x7,0x6d,0x98,0x43,0x12,0x6c,0xa0,0xfe,0x83,0x1c,0x24,0x1,0xa3,0xaf, + 0xdc,0xe8,0xc,0x80,0x10,0x83,0x11,0x8c,0xa0,0x43,0x1f,0x52,0xc3,0x18,0xfc,0xf0, + 0x8d,0x69,0xa9,0x3,0x9c,0x6f,0x19,0x66,0x7c,0xb6,0x81,0x8e,0x70,0xbc,0xa9,0x11, + 0x5b,0x80,0x67,0x56,0x76,0x79,0xd3,0x34,0x94,0x41,0xb,0xe6,0xa1,0x48,0x16,0xc8, + 0xd0,0x86,0x1f,0xa0,0xa2,0x1c,0xf8,0xa0,0x7,0x3d,0x70,0xc7,0x45,0xe4,0x74,0xc3, + 0x25,0xbf,0xa8,0xc0,0x1f,0x94,0x50,0x3,0x39,0x4,0xe1,0x73,0xed,0x7c,0x8a,0x55, + 0xd4,0xc8,0x4e,0x22,0x84,0x4f,0x52,0x9f,0xb8,0xda,0x6c,0x56,0x72,0x9c,0x80,0xbe, + 0x6,0x48,0xa9,0x5,0x27,0x3c,0x94,0x4b,0x12,0x6c,0x1c,0x27,0x27,0xc,0xb,0x47, + 0x35,0x68,0xf8,0x8d,0x61,0xc4,0x42,0x12,0x32,0x10,0x1,0x17,0x98,0x20,0x82,0x14, + 0x30,0xc1,0x6,0x2f,0xb0,0x1,0x14,0xfc,0x5a,0x84,0xee,0x5,0x76,0xb0,0x85,0x2d, + 0x41,0x49,0xd5,0x70,0x3,0x5d,0xc8,0x3,0x1f,0xd7,0xc8,0x86,0xd1,0x14,0xa3,0x17, + 0x6f,0xc6,0x87,0x1d,0xe1,0x38,0x87,0x38,0x68,0x41,0x1,0x41,0x4c,0x85,0x9d,0x5d, + 0xc1,0xce,0x54,0x3c,0xa3,0x5,0x2e,0xed,0xa0,0x11,0x3d,0xc0,0x1,0x2b,0xdc,0x3, + 0x2b,0xda,0x2d,0x66,0x7d,0x64,0xf5,0xb,0x30,0x62,0x9b,0x88,0x2c,0x74,0x21,0x74, + 0x17,0x5c,0x83,0x53,0xac,0x92,0xb3,0x33,0xe4,0x80,0xf,0x46,0x0,0x61,0x28,0xfc, + 0xe2,0x8d,0x9c,0xd8,0xca,0x26,0xd,0xb5,0x64,0x4e,0x8a,0x5b,0x5c,0x73,0xec,0x84, + 0x61,0xbf,0x61,0xc6,0x2e,0x48,0x91,0x8,0xfe,0x19,0x4c,0xe0,0x95,0x45,0xb0,0x98, + 0x9,0x6c,0xd0,0x87,0xd,0x1,0xc1,0x6,0x43,0x18,0x6f,0x46,0x3b,0x6a,0x3,0x20, + 0x70,0xe8,0xb0,0x1f,0x1a,0x83,0x14,0xc4,0x20,0xc,0xf7,0xc0,0x91,0xa8,0xd,0xaa, + 0x6f,0x71,0xfa,0x12,0x8b,0x16,0x20,0x42,0x8,0x5a,0x90,0x66,0x18,0xc4,0x3,0x87, + 0x2c,0x24,0x59,0xa,0xc7,0xa,0xd1,0x13,0x4,0xb1,0x85,0x35,0x88,0xc1,0x8,0xae, + 0xa0,0xc6,0x8b,0x54,0x6b,0x92,0x2d,0x7a,0x73,0x27,0x7c,0x63,0x61,0x1d,0x8c,0x30, + 0x8,0x9c,0x89,0xce,0x9d,0x4e,0x39,0x5d,0xea,0xe2,0x50,0x88,0x2e,0x24,0xe2,0x2, + 0xa7,0xf8,0xcb,0x3b,0x8e,0xe3,0xe,0x9c,0x8c,0x69,0x38,0x40,0xca,0x47,0x25,0x1b, + 0xda,0xd2,0x74,0xac,0x83,0x36,0xf2,0x48,0x46,0x2c,0x3c,0xf1,0x6,0xec,0x72,0x54, + 0xa,0x6e,0x50,0x84,0xa2,0x22,0xd0,0x41,0x8,0xbc,0xc0,0xc7,0x36,0xc8,0x1,0x90, + 0x93,0xc0,0x51,0x17,0x78,0x94,0x51,0xa7,0x8e,0xa2,0x44,0xc6,0x70,0x7,0x11,0xfc, + 0xa1,0x16,0xf8,0x68,0x7,0x62,0xfa,0x44,0xdf,0x9c,0xbc,0xc3,0x53,0xb2,0x40,0x81, + 0x12,0x28,0x61,0x5,0x37,0xf4,0x5a,0xb,0xe2,0x59,0x43,0x16,0xee,0x30,0x94,0x33, + 0xa8,0xa1,0x29,0x69,0x78,0xe6,0x13,0xe8,0x10,0x6,0x1b,0x18,0x82,0x5,0xb1,0x60, + 0x86,0xdd,0xb2,0x25,0x4c,0xe3,0xbc,0x85,0x36,0x6b,0xf9,0x85,0x6,0x2,0x31,0x8, + 0x43,0x42,0xe5,0x2b,0x60,0xc9,0x73,0x15,0xe2,0xb0,0x7,0x3e,0x8,0xf0,0x55,0x23, + 0x71,0x1f,0x3f,0xd6,0x81,0xd,0x7f,0xfe,0xa8,0x96,0xac,0x40,0x5a,0x4d,0x4a,0x80, + 0xb4,0x18,0xbd,0x78,0xa3,0x16,0x8c,0xa8,0x3,0xd,0x52,0x90,0x2,0x23,0x6c,0xe1, + 0x9,0x65,0xc4,0xc2,0x86,0xfa,0x10,0x7,0x26,0xca,0x41,0x7,0x50,0x8,0x2f,0x14, + 0x14,0xe,0x5,0xbe,0xf2,0x35,0x7,0x2e,0xe8,0x28,0x14,0x11,0xab,0x6,0x2f,0xe0, + 0x81,0x2,0x76,0xe0,0x45,0xae,0x66,0x32,0xcc,0xbe,0xc8,0x83,0x15,0x28,0x0,0x9c, + 0x10,0x8,0xe1,0xeb,0xaa,0xf8,0x81,0xb,0x57,0x98,0xc2,0x15,0xbc,0xd0,0x95,0x6f, + 0x8b,0x99,0xe,0x5e,0x30,0xc4,0x14,0xee,0x40,0x80,0x58,0xf8,0x85,0x1e,0x96,0x33, + 0x20,0xc9,0x4e,0xf2,0x23,0xbf,0xfc,0xa2,0x5,0x46,0x18,0x83,0xe1,0xb6,0x2,0x87, + 0x6f,0x27,0x25,0xc,0xaa,0x9b,0x42,0x1c,0xa4,0x30,0x1,0x5a,0xc8,0xc3,0xe6,0xf7, + 0x68,0x31,0x49,0x6e,0xd5,0xee,0xd4,0xe,0x27,0x1f,0x6,0x55,0xc9,0xab,0x74,0x87, + 0x50,0x24,0x68,0x1b,0xe,0x4c,0xe0,0xc3,0x20,0xb2,0xe0,0x6f,0x2b,0xc,0xe1,0xbb, + 0x4e,0x18,0x1,0x10,0xb6,0x27,0x82,0x24,0xe4,0x20,0x7,0xb,0xa7,0xa5,0x2c,0x75, + 0x50,0x6a,0x88,0xbb,0x0,0x8a,0x63,0xc0,0x7b,0x95,0xe4,0x10,0x2,0x31,0xd0,0x0, + 0x5,0xae,0x32,0xd,0x4b,0xe8,0x28,0x6f,0x79,0xb4,0xc2,0x9c,0x35,0xc8,0x2,0x21, + 0xe8,0x10,0x1e,0x28,0x59,0x41,0xd,0x2e,0x13,0x5d,0x80,0xfd,0xcb,0xce,0x9,0x28, + 0x18,0xb5,0x2b,0x3d,0xe0,0x40,0xfd,0x61,0x8e,0xbd,0x9d,0x3,0x1f,0xbd,0xa0,0x81, + 0x14,0x80,0x90,0x74,0x37,0xd4,0xfe,0xa0,0x11,0x87,0x38,0x44,0x16,0xbc,0xd0,0x7, + 0x27,0x38,0xe1,0x4,0x71,0x10,0x41,0x2e,0xdc,0x3,0xeb,0x58,0xa3,0x98,0xea,0xa9, + 0x55,0xb4,0xf2,0xc4,0xea,0xf,0x98,0x14,0x86,0x1a,0xb1,0x78,0x43,0xa,0xb8,0xc0, + 0x87,0x2f,0xc8,0x81,0x9,0xc7,0xef,0xc2,0xf1,0x99,0x70,0x84,0x23,0x34,0x81,0xf9, + 0x47,0x18,0xc2,0x45,0x93,0x30,0x84,0x21,0xb8,0x3d,0x7,0x72,0x9f,0xfb,0x2d,0xed, + 0xbe,0x82,0x12,0x94,0x0,0xef,0x11,0xf4,0x8e,0x1c,0xec,0xc9,0x87,0x2c,0x88,0xe1, + 0xd,0xa6,0x8,0xd3,0x8f,0xba,0x91,0x92,0x73,0xb4,0x2,0x34,0x8a,0xb7,0x2,0x1d, + 0xac,0x60,0x3a,0xfa,0xd7,0x7f,0x3b,0x4d,0xb0,0x84,0x12,0x58,0x21,0xf,0xe1,0x34, + 0x86,0xbe,0xe8,0x8,0xe,0x9d,0x80,0xd,0x9f,0x0,0xa,0x45,0x18,0x8a,0x42,0xa0, + 0x84,0x1d,0x38,0x84,0x1d,0xb0,0x82,0x3d,0x40,0xb9,0x11,0xb8,0x83,0x9,0xc8,0x5, + 0xdf,0x88,0x35,0x93,0x51,0x8c,0xbd,0x51,0x31,0xc4,0x78,0xac,0xd7,0x8,0x28,0x9, + 0xc9,0x15,0x79,0xd8,0x85,0x39,0x10,0x83,0x22,0x90,0x83,0x3d,0x38,0x82,0xf0,0x6a, + 0x82,0x2e,0x50,0x41,0xe5,0x63,0xc1,0x16,0xa4,0xbe,0x17,0xac,0xbe,0x87,0xb3,0xbb, + 0x19,0xc0,0xbe,0xee,0xf3,0xbe,0xbc,0xb,0xbf,0x31,0x50,0x84,0x1b,0x50,0x81,0x49, + 0x20,0x83,0x1e,0x30,0x85,0x36,0xf9,0x8b,0x1f,0xa9,0x86,0x57,0x48,0x1,0x7b,0x22, + 0x4,0x2b,0x88,0x3f,0xfb,0x63,0x42,0xd3,0x69,0x96,0x1f,0x7c,0x5,0x50,0x12,0x89, + 0x2d,0x9a,0x37,0xe7,0xb2,0xfe,0xa4,0xe5,0x68,0xe,0x3e,0xb8,0x28,0x41,0xc8,0x2, + 0x4a,0x90,0xe,0x33,0xd0,0x18,0x14,0x88,0x24,0x75,0x58,0xb3,0xf5,0x21,0x12,0xdb, + 0x43,0x43,0x6c,0x68,0x11,0x1,0x31,0x5,0x88,0xc9,0x82,0x65,0xba,0x18,0x28,0x18, + 0x82,0x14,0x5c,0xc1,0x16,0xb4,0x43,0x18,0xa4,0x3e,0xb7,0x2b,0x35,0x5b,0xaa,0xc1, + 0xee,0xfb,0xbe,0x2a,0x9,0x82,0x5e,0x93,0x3,0x3a,0x78,0x1b,0x14,0x78,0x4,0x72, + 0x28,0x8c,0xc2,0x38,0x85,0xb,0x10,0x3,0x42,0x0,0xd,0x22,0x88,0x3f,0x3a,0x68, + 0xc2,0x49,0x84,0x83,0x31,0xdb,0x2,0x32,0x68,0x1,0x55,0xf8,0x6,0x96,0x10,0x40, + 0x95,0x18,0x12,0x9e,0xa0,0xa1,0x23,0x49,0x92,0x2c,0x60,0x2,0x37,0x68,0x2,0x17, + 0x48,0x8f,0x46,0x68,0x3,0x34,0x28,0x6,0x79,0x20,0x7,0xd4,0x9a,0x2f,0x5a,0x43, + 0x43,0xdc,0x29,0xaa,0xb7,0x52,0x87,0x67,0xc8,0x4,0x14,0x58,0x82,0xa4,0xb0,0x82, + 0x2f,0x8,0x83,0x3d,0x68,0x82,0x15,0xa0,0xc3,0xe4,0xb3,0x43,0x17,0xc4,0x43,0x3d, + 0x9c,0xc1,0x3e,0xbc,0x41,0xf0,0x93,0x20,0x39,0x58,0x84,0x40,0x5c,0x84,0x23,0x20, + 0x2,0x3d,0x98,0x83,0x36,0xc8,0x84,0x5b,0x48,0x6,0x64,0x88,0x84,0x16,0x8,0x84, + 0x2c,0x90,0x3f,0x48,0x2c,0x3,0x25,0x9c,0xc4,0x26,0x34,0x83,0x34,0xd8,0x82,0x1a, + 0x40,0x15,0x19,0xd0,0xc4,0x1f,0xc1,0x39,0x59,0x39,0x20,0x5b,0xd9,0x7,0x7a,0xc0, + 0x23,0x7c,0xd8,0x95,0x40,0x98,0x84,0x2b,0x78,0x1,0x43,0x68,0x82,0x41,0xa8,0xc6, + 0x65,0x28,0x7,0x44,0xfe,0x7c,0xaf,0xe2,0x0,0x7,0x70,0xa0,0x2f,0xae,0x31,0xc8, + 0xbd,0x89,0x8c,0x64,0x40,0x82,0x4,0x68,0x84,0x35,0x28,0xaf,0x2e,0xf0,0x2,0xe7, + 0x1b,0x46,0x62,0x2c,0x46,0xe5,0xc3,0xc3,0x18,0xdc,0x43,0x1a,0x94,0x3b,0x1b,0xfc, + 0xc3,0xf0,0x5b,0x4,0x2f,0xe0,0x81,0x33,0x28,0x4,0x37,0x30,0x8b,0x39,0xa8,0x83, + 0x1e,0xa8,0x83,0x39,0x28,0xa7,0xaf,0x93,0x8a,0x25,0x5c,0xc2,0x71,0xb4,0x3f,0x33, + 0x58,0x40,0x38,0x20,0x2,0x39,0x28,0x82,0x14,0x18,0x20,0xd4,0x2,0xa7,0x7c,0x60, + 0x7,0xb7,0xaa,0x23,0x93,0xc9,0x1c,0x5e,0x50,0x19,0x20,0xe8,0x83,0x13,0x58,0x84, + 0x2e,0x78,0x24,0x34,0x40,0x85,0x62,0x28,0x7,0x79,0xf8,0x27,0x76,0x20,0xc8,0xc6, + 0x50,0xc,0x83,0x5c,0xc,0xb2,0x9a,0x6,0x6a,0x10,0x6,0x14,0x40,0x82,0x46,0x48, + 0x1,0x74,0xac,0xa7,0xe5,0xb,0xb5,0x31,0x60,0x2,0x15,0xa4,0xc8,0x8a,0x64,0x82, + 0x8b,0x44,0x46,0x3e,0xdc,0x48,0x3f,0xc4,0xc1,0x66,0x54,0x81,0xfb,0x39,0x3,0x69, + 0xea,0x2,0x33,0x40,0x4,0x12,0xb8,0xac,0x14,0xc8,0x2,0x4b,0xd8,0x80,0x41,0x44, + 0x24,0x71,0x94,0x44,0x98,0xac,0x3f,0xa5,0xa0,0x4,0x22,0x70,0x83,0x3d,0xb8,0x1, + 0x3f,0x68,0x1,0x59,0x70,0x93,0xfe,0xd3,0x8b,0x82,0x24,0x12,0xc4,0x30,0x93,0xcc, + 0xf9,0x5,0xce,0x89,0x3,0xd6,0xbb,0x2,0x39,0xd8,0x82,0x43,0xe8,0x81,0x16,0x88, + 0x84,0x5d,0xf8,0x86,0x73,0xd8,0x1a,0xe5,0x79,0x8d,0xa9,0xe4,0x1a,0x4b,0xb2,0x8f, + 0x5d,0xd0,0x80,0xfe,0x25,0x48,0x4,0x31,0x78,0xc3,0x2e,0xb8,0xa8,0x60,0x91,0x82, + 0x1b,0x18,0xcb,0x3a,0x34,0xcb,0xb3,0x3c,0x46,0x19,0x54,0x4b,0x59,0xe2,0xc8,0xb6, + 0xfc,0xe,0x42,0x20,0x82,0x1c,0x38,0x9c,0x30,0x70,0x83,0xff,0x81,0xa6,0x35,0xa0, + 0xb3,0x21,0xf0,0x2,0x39,0x98,0xbf,0x70,0x94,0x44,0x22,0x0,0x4c,0xfb,0xb3,0x82, + 0x2e,0x18,0x49,0x37,0xa0,0x83,0x1a,0x98,0x83,0x4,0x90,0x85,0x5,0x5b,0x8d,0xf8, + 0x58,0x9f,0xab,0xd3,0xa6,0x76,0x68,0x20,0x19,0x10,0x2c,0x27,0xb8,0x3,0x29,0xc8, + 0x2,0x74,0xe4,0x3,0x39,0x10,0x81,0x4a,0xf0,0x85,0x1f,0x31,0x9a,0xd1,0x24,0xcd, + 0xaa,0x2c,0x2b,0x5a,0x30,0x82,0x14,0xd0,0x3,0xf2,0xa2,0x3,0x22,0xf0,0xc5,0x28, + 0x8,0x82,0x2e,0x18,0x83,0xef,0x20,0xcb,0xb2,0xac,0x48,0xb4,0xc4,0x4d,0x8d,0xd4, + 0x4d,0xb6,0xfc,0x3e,0xbc,0x53,0x42,0x78,0x32,0x9c,0x30,0xe8,0xa,0xeb,0xc8,0x33, + 0x36,0xd0,0xa0,0xe7,0x6c,0x42,0xcf,0xa8,0x20,0xaa,0x58,0x8a,0x35,0x68,0x4,0x3, + 0x60,0x85,0xa0,0x41,0xa0,0xb1,0xa2,0x15,0x37,0x43,0x8c,0x21,0xd4,0x23,0x19,0xb8, + 0x81,0x22,0x90,0x1,0x23,0xe0,0x2,0x29,0x80,0x2,0x20,0x30,0x84,0x8,0x34,0x85, + 0x82,0x68,0x87,0xd4,0x72,0x37,0xac,0x53,0x9,0x18,0xf9,0x6,0x5e,0xa8,0x3,0x2e, + 0xc8,0x82,0x2c,0xe8,0x45,0xbc,0xfb,0x82,0x2f,0x8,0x82,0xfe,0xc,0x50,0xb2,0xac, + 0xcd,0xe3,0x7b,0x41,0xeb,0xa3,0x3b,0x17,0x58,0x81,0x15,0x98,0x81,0x26,0xe5,0x3e, + 0x4,0x4d,0xfe,0xd0,0x31,0x80,0x8a,0xc4,0xf2,0x2,0xc3,0x51,0x4e,0xeb,0x98,0x88, + 0x9d,0xa1,0xd0,0x71,0x3c,0xba,0x38,0xd0,0xb2,0x72,0x5c,0x8a,0x2c,0x40,0x4,0x1a, + 0x50,0x85,0x82,0x52,0x20,0x7f,0xc8,0x87,0x1c,0x7a,0x4c,0x81,0x98,0x8d,0x41,0xf9, + 0x84,0x58,0xf8,0x5,0x5c,0x28,0x85,0x46,0x10,0x83,0x10,0xd8,0x3,0x1b,0x38,0x3, + 0x2e,0xa8,0x83,0x3c,0x68,0x45,0xf7,0xd2,0x7,0x93,0x30,0x89,0x6d,0x58,0xd3,0xb4, + 0x72,0x89,0x60,0x40,0x83,0x2d,0x8,0x52,0xbc,0xd3,0x92,0x30,0x88,0x2,0xfe,0x24, + 0xd2,0x22,0x15,0xd0,0x62,0x4c,0x52,0x64,0x2c,0xb5,0x26,0x7d,0xd2,0x26,0xdd,0xcd, + 0x29,0xb5,0x2,0x2e,0xc3,0x3b,0x2f,0xb8,0x52,0x0,0x8b,0xa,0xad,0xd8,0x8a,0x2e, + 0x9d,0xc4,0x30,0x10,0x37,0x2d,0x43,0x36,0xb0,0x20,0x84,0x26,0x52,0x47,0xa1,0x32, + 0x93,0x5a,0xdc,0xb,0x9c,0x8,0x8e,0xe0,0x78,0x93,0x37,0x1,0x86,0x52,0x20,0x1, + 0x3f,0xe8,0xd1,0x2d,0x68,0x84,0xa,0xb8,0x5,0x79,0xb8,0x6,0xf5,0x33,0x34,0xd8, + 0xc8,0x95,0x62,0xb8,0x4,0x14,0xc8,0x82,0x47,0xc5,0x3b,0x65,0x79,0xd4,0x21,0xd, + 0x82,0x2f,0x90,0xd4,0x23,0xb5,0xcd,0x18,0x94,0xc1,0x4b,0x75,0x52,0x28,0xdd,0xd4, + 0x4,0xed,0xd4,0x2c,0xf8,0x2,0x29,0x38,0x9c,0x62,0xeb,0x54,0xa5,0x98,0xa,0xc3, + 0xb1,0x19,0x53,0xad,0x3f,0x39,0x68,0xa6,0x72,0x4,0xb7,0x42,0x38,0x82,0xed,0x69, + 0x81,0x57,0x70,0xaf,0x1a,0x8d,0x4f,0x7b,0xb8,0xba,0xf3,0x11,0x34,0x33,0x41,0xc, + 0x54,0xfe,0x7a,0x1e,0x60,0x60,0x84,0x1e,0x8,0x84,0x35,0x30,0x82,0xba,0x64,0x13, + 0xf7,0x2a,0xa8,0x2b,0xc4,0x87,0x64,0x68,0x3,0xbc,0xea,0xb2,0x30,0x18,0x3,0x87, + 0x75,0xd8,0x28,0x10,0x52,0x68,0x8d,0x54,0xda,0x34,0xcb,0x4a,0xbd,0x56,0x26,0xcd, + 0x56,0x4d,0x95,0xd2,0x4,0x85,0x8a,0xa0,0x3b,0x3,0x2c,0x30,0xd7,0x0,0xd3,0x2c, + 0x74,0xad,0xd0,0x27,0x31,0x3,0xa9,0x90,0x3,0x37,0x8,0x82,0x1b,0x18,0x4,0xe0, + 0xb1,0xbc,0x17,0x91,0x55,0x5a,0x61,0xa8,0x91,0xa8,0x87,0x79,0x88,0x23,0x70,0x42, + 0xc8,0x6f,0x58,0x85,0xa,0x68,0x84,0x2c,0x70,0xd9,0x1e,0xf8,0x4,0x71,0xf0,0x8d, + 0x17,0x71,0x89,0x64,0xf8,0x83,0x25,0x30,0x2,0x38,0x50,0xc2,0x31,0xb0,0x82,0x31, + 0xf8,0x82,0x28,0x18,0x3,0x8a,0x5,0x55,0xc4,0x9,0x50,0x6a,0xc5,0xd8,0x25,0xc5, + 0x54,0x6d,0xed,0xd8,0xef,0x73,0x3c,0xc3,0xd9,0xa9,0x62,0xab,0x8e,0xd,0x73,0x50, + 0x93,0xb5,0xbf,0xf1,0x20,0xdb,0xac,0x20,0x84,0x2f,0x18,0x84,0x1a,0x58,0x83,0x1d, + 0x20,0x81,0x1,0x52,0xb3,0xf3,0x41,0x89,0x10,0xd5,0x89,0x69,0x7b,0xb,0x35,0xdc, + 0x9b,0x61,0x5,0x6,0x24,0x40,0x84,0x1b,0xe8,0x2,0xc4,0x8c,0x4,0xa7,0x93,0x1d, + 0x3c,0x62,0x6,0x46,0x20,0x1,0x38,0xc8,0x81,0x26,0x70,0xda,0x5,0xfd,0xd1,0x20, + 0x1d,0x52,0x50,0x7d,0xd4,0x61,0xc4,0xda,0x3c,0xb4,0x54,0x8d,0xcd,0xd4,0x28,0x5d, + 0xc6,0x29,0x95,0xa0,0x33,0xd0,0xb3,0x38,0xa8,0xa0,0xb,0x4a,0x59,0xcf,0x30,0xdb, + 0xfe,0x98,0x9c,0x83,0x39,0x30,0x3,0x75,0xed,0x20,0x36,0xe8,0x2,0x4a,0x20,0x33, + 0x87,0x24,0x4,0x11,0x80,0x36,0xbb,0xc1,0x39,0xca,0x71,0x33,0xce,0x43,0x1e,0xd6, + 0xea,0x86,0x6f,0x70,0x86,0x48,0x48,0x81,0x41,0xe0,0x3,0x55,0x41,0x82,0x64,0x20, + 0x28,0xba,0xc9,0x83,0x25,0x18,0x84,0x15,0xe8,0x83,0x29,0x8,0x3,0xa6,0x75,0x5c, + 0x69,0xed,0x2,0x21,0x7d,0x54,0x2f,0x88,0x2,0xca,0x3d,0xd2,0xac,0xa5,0xbb,0xad, + 0xe5,0xd8,0xcd,0x4d,0x50,0x9,0xd2,0x8a,0x9d,0xca,0x8a,0xaa,0x50,0xd9,0x9,0x2d, + 0x5d,0xee,0x30,0x83,0xd3,0x4d,0x5d,0x36,0x48,0x55,0x22,0x78,0x2,0xa4,0x30,0x3, + 0x41,0x8,0x2,0x42,0xa0,0x80,0x9c,0x14,0xe,0xbd,0xd1,0x39,0xc5,0x40,0x9e,0x71, + 0xa0,0x2f,0xa9,0xc4,0x23,0x67,0x28,0x5,0xa,0x20,0x41,0x23,0x58,0x82,0x3f,0x20, + 0xc,0x82,0x70,0x4,0x24,0x8,0x4,0x26,0x60,0x83,0x29,0x78,0x1,0x2f,0x70,0x5c, + 0x25,0x84,0xde,0x20,0x8d,0xda,0x28,0x88,0x48,0x23,0xbd,0x5e,0xcb,0xcd,0x58,0x28, + 0xe5,0x5a,0xee,0xfd,0xbe,0x45,0xc5,0x8a,0x78,0x42,0x96,0xf2,0xd,0xcc,0xaf,0x18, + 0x5d,0x76,0x12,0x5d,0xa6,0x30,0x3,0x3d,0x20,0x81,0xfd,0xdb,0xc4,0xfb,0x4d,0x31, + 0xaa,0x34,0x89,0x77,0xe8,0x89,0x22,0x9c,0x0,0x3e,0x28,0x2,0x23,0x50,0x82,0x25, + 0xf0,0xc7,0x3a,0xa8,0x3,0x32,0xa8,0x30,0x2f,0xb8,0x2,0x2c,0x88,0x2,0x49,0xfd, + 0x2,0xa8,0xd,0xd2,0xc1,0x19,0xd2,0x26,0x50,0xe2,0xe7,0xa3,0x3e,0x26,0xb6,0xfe, + 0x5c,0x6b,0xcd,0xd8,0x25,0xd5,0xd8,0x6d,0x4d,0x50,0x9,0xee,0xc8,0x89,0x13,0x61, + 0xd3,0x19,0x8f,0xa5,0xd0,0xe2,0x2d,0x5e,0x8a,0x43,0x50,0x2,0x52,0xc0,0x9a,0xaa, + 0x14,0x28,0xb0,0x9a,0x45,0xe4,0xc8,0x89,0x69,0x70,0x85,0x9,0x80,0x4,0x81,0x45, + 0x84,0x35,0x10,0x85,0x27,0xe0,0xb2,0x5e,0xc,0x2,0xc4,0x89,0x56,0x9,0xb6,0x62, + 0x9,0x36,0x52,0x25,0x76,0x3e,0xe6,0x6b,0x62,0x3f,0xc6,0x60,0xeb,0x8b,0x62,0x29, + 0x76,0x1,0x2a,0xee,0xe0,0x45,0x6d,0x4b,0xc4,0xca,0xe2,0x29,0xf1,0xe2,0xb3,0x55, + 0x8a,0x27,0xd8,0x1,0x3f,0x30,0xd3,0x77,0xa8,0x6,0x22,0x29,0x63,0x33,0xb6,0xbd, + 0x13,0x6b,0x11,0x67,0xa0,0x85,0x16,0x20,0x81,0x40,0x60,0xcd,0x2f,0x80,0x8,0xbc, + 0xeb,0x82,0x5,0xc5,0x63,0x3c,0x36,0x62,0xe8,0x4d,0x3e,0x3e,0x76,0x62,0x27,0x86, + 0x62,0x25,0x25,0xe4,0x25,0x35,0x64,0x20,0x45,0x64,0x66,0x54,0xe4,0x45,0xde,0x8e, + 0x46,0x1e,0x5f,0xc6,0xab,0x8a,0x27,0xd8,0x82,0x2c,0xf0,0x3,0xc,0x78,0x85,0xff, + 0x18,0xab,0x33,0x46,0xb1,0x42,0x5b,0x7,0xd7,0x92,0x7,0x59,0x68,0x3,0x25,0x40, + 0x4,0x88,0xc4,0x82,0x68,0xf6,0x82,0x2f,0xb0,0x82,0x1e,0x8d,0xde,0x53,0x2e,0x62, + 0x3d,0x5e,0x41,0x56,0x6,0x64,0x57,0x16,0x64,0x58,0x8e,0xe5,0x52,0x9b,0xe5,0x54, + 0xbe,0xe2,0x5b,0xc6,0xe5,0x13,0xd6,0x2d,0xd0,0x79,0x12,0x38,0x38,0x4,0x3d,0xe0, + 0x2,0x2e,0x10,0x83,0x3f,0xf8,0x86,0xa1,0x62,0x90,0xfa,0x9a,0x45,0x9c,0xfe,0x28, + 0xb4,0x99,0xf0,0xb,0x5b,0x0,0x3,0x31,0xf0,0xae,0x2a,0x10,0x37,0x2c,0xf8,0x82, + 0x2c,0x30,0xc7,0x5e,0xc4,0xe6,0x54,0xde,0xe3,0x25,0xee,0x66,0x40,0x7e,0xe5,0xcb, + 0x8d,0xe5,0x71,0xb6,0xe2,0x44,0x76,0x94,0x73,0xc6,0x30,0xf2,0x98,0xbc,0x97,0x31, + 0x16,0x38,0xd8,0x82,0x1d,0x90,0x83,0xed,0xf1,0x84,0x79,0xde,0xa1,0x7a,0xb6,0xe7, + 0x4c,0x46,0x8e,0x13,0x33,0x7,0x7a,0x80,0x11,0x5c,0x68,0x81,0x41,0xf0,0x82,0xe, + 0x12,0xd9,0x81,0x2e,0x68,0x6c,0xce,0xe6,0x23,0xde,0x66,0x85,0x86,0xbe,0x21,0xf0, + 0xe6,0x6f,0x1e,0x64,0x29,0x86,0xe8,0x5a,0x9e,0x38,0x30,0x3b,0x67,0xaf,0xb0,0xe8, + 0x64,0xc1,0x68,0x35,0x8,0x98,0x1e,0x68,0x84,0xf,0xd8,0x83,0x7,0xf0,0x4,0x79, + 0xc8,0x86,0x90,0x76,0x61,0x63,0x1e,0xe,0xfa,0xd8,0x9b,0x6f,0x38,0x8,0x15,0xb8, + 0x52,0x2c,0x8,0x83,0x81,0x7e,0x82,0x27,0xb8,0xe6,0x53,0x46,0xe8,0x9a,0xee,0xe3, + 0x9b,0xce,0xe9,0x6f,0xe,0x67,0xba,0xeb,0xe9,0x22,0x96,0x68,0xce,0xa0,0x68,0x74, + 0xbe,0xe8,0x98,0x1,0x30,0x32,0xa0,0x85,0x4d,0x50,0x84,0xc,0x90,0x82,0x4d,0x28, + 0x87,0x78,0xd8,0xa1,0xf8,0x94,0xea,0x92,0xce,0x9,0xe5,0x82,0xd,0x75,0x90,0x87, + 0x52,0x20,0x3,0x32,0x7a,0x5a,0x69,0x85,0x60,0x99,0xe,0xeb,0x55,0xb6,0xe9,0x3f, + 0xbe,0xe9,0x86,0xde,0x69,0x59,0xee,0xda,0x29,0xa5,0xec,0xca,0x6e,0xeb,0xea,0x48, + 0xd9,0xc9,0x3b,0x2,0xf1,0xcb,0x82,0x41,0x48,0x1,0xb9,0x26,0x87,0xfe,0x52,0x10, + 0x3d,0x28,0x50,0x82,0xbc,0x66,0x1e,0x77,0xd0,0x5f,0xb7,0xea,0x6b,0x14,0xab,0x24, + 0xcf,0x13,0x7,0x56,0xa8,0x80,0x3a,0x30,0xce,0x2f,0xb8,0xd2,0x26,0xb8,0xe3,0x53, + 0xbe,0x5a,0xe5,0x7b,0xbe,0xdd,0x7e,0xec,0xdb,0x3c,0x6b,0x8d,0xdd,0xde,0xca,0x16, + 0xee,0xe1,0xbe,0x6c,0x29,0xf1,0xaf,0xef,0xe8,0x54,0x3f,0x20,0x83,0x37,0xa0,0x5, + 0x6a,0x10,0x7,0x5c,0xe0,0x2,0x28,0xd8,0x83,0x14,0x28,0x6,0x72,0x68,0x87,0x7a, + 0xe8,0x13,0xd5,0x5e,0xed,0xe1,0xd8,0xce,0x77,0xf0,0xb,0x20,0x8a,0xed,0x1d,0x28, + 0x83,0x3d,0x28,0x81,0x38,0x98,0x66,0x6c,0xce,0xed,0xe3,0xe3,0x6d,0x57,0xf6,0xed, + 0xb3,0xd6,0xe0,0x71,0x1e,0x6e,0xcb,0x2e,0xee,0x5d,0x2e,0x83,0x1e,0xd,0x84,0x46, + 0x40,0x82,0x5f,0x70,0xaf,0x6f,0x60,0x6,0x1a,0xf8,0xcf,0x1a,0x38,0x5,0xf7,0xba, + 0x87,0x2d,0xd2,0x8b,0xed,0xae,0xc5,0xc8,0xc9,0x89,0xcc,0x79,0x9e,0x4e,0x90,0x80, + 0x3a,0xc8,0x82,0x1c,0xf8,0x95,0xf3,0xc6,0x6d,0xb,0x56,0xef,0xf5,0xee,0x6d,0x18, + 0x74,0x68,0x29,0x7e,0xef,0xc9,0x8e,0x6f,0xf9,0x6e,0xeb,0x9b,0xe9,0xe,0x2e,0xb, + 0x84,0x3a,0xb0,0x83,0xd8,0x1,0xe,0x18,0x91,0x4,0x31,0xe0,0x99,0x36,0x70,0x93, + 0x77,0x58,0x9f,0x2,0x37,0x70,0xe2,0x98,0x1c,0x15,0x3b,0x19,0x79,0xe8,0x4,0x90, + 0xe3,0x83,0xf,0x38,0x1c,0x99,0x4e,0xef,0xe5,0xb3,0xf0,0x8b,0xb4,0xdc,0xdf,0xde, + 0x70,0xe,0xee,0x70,0xf,0xff,0xf0,0xf0,0xe8,0x54,0xd,0xb5,0xfe,0x3,0x65,0xc0, + 0x9a,0x83,0xf1,0x86,0x83,0x80,0x83,0x41,0x58,0x61,0xfe,0x1b,0x12,0xf8,0x30,0xf0, + 0x6a,0x71,0xd,0xb4,0x12,0x90,0x4c,0xe8,0x1,0x31,0x18,0x4,0xfd,0xe4,0x71,0xa, + 0xf7,0xf1,0xf5,0x6,0x72,0x8c,0x74,0xef,0xd,0x2e,0xf2,0x22,0xff,0x70,0x1,0xb, + 0xf,0xa2,0x23,0x3,0x24,0x58,0x8b,0xd9,0xc8,0x89,0x7c,0xb0,0x86,0x69,0x78,0x3, + 0x52,0xac,0x81,0x37,0x48,0x6,0x4b,0x49,0x18,0xd8,0x30,0x70,0xb8,0x52,0x31,0x3, + 0xb2,0x86,0x37,0xc1,0xb7,0x1d,0xf0,0xd1,0x30,0xb7,0x58,0xb,0xbf,0xf0,0x4a,0x15, + 0x72,0x34,0x4f,0xf3,0xf8,0x6e,0x6b,0xef,0x5,0x61,0xa2,0x6b,0x84,0xa6,0xfc,0x11, + 0xd7,0x68,0x31,0x7b,0xc0,0x7,0x56,0x10,0x3,0x48,0x4c,0x81,0x52,0x60,0x6,0x84, + 0x49,0xb1,0xed,0x6e,0x18,0x77,0xe3,0x87,0x62,0xd2,0x8b,0xbe,0x20,0x87,0x7f,0x9d, + 0x3,0x6f,0x45,0x6f,0x31,0x57,0xf4,0x32,0xcf,0x70,0xad,0x75,0xf4,0x47,0x17,0x6e, + 0xa,0x8d,0x8a,0x26,0xec,0xb6,0x35,0x98,0x3,0x30,0x28,0xc,0xac,0xc9,0x9,0xf7, + 0x49,0x7,0x7b,0x38,0x7,0x6a,0x50,0xa6,0x24,0x18,0x4,0xa,0xc0,0x85,0x6f,0xb8, + 0x6,0xce,0x8b,0xf1,0x2b,0xd4,0x7,0x16,0x89,0xb7,0xdc,0xf1,0x8b,0x64,0x70,0x4, + 0x1c,0xc0,0x2c,0x25,0xb4,0x66,0x8b,0xe1,0xe3,0x20,0x50,0x3e,0x29,0xf8,0x71,0x20, + 0x77,0xbb,0xb9,0xcb,0x3e,0xbb,0x63,0x52,0xe0,0xd6,0x5c,0x5b,0x57,0x77,0x5b,0x8e, + 0x8,0x28,0x31,0xee,0xf8,0x8b,0xbf,0xb5,0xed,0x2,0x8a,0xfe,0x8b,0x2,0x3a,0x10, + 0x83,0x1e,0x40,0x2,0x11,0x93,0x9d,0x86,0xca,0x7,0xc9,0x41,0x7,0x7d,0xc8,0x5, + 0xc,0xe0,0x82,0x81,0xc6,0x81,0xea,0x8e,0x7,0xb8,0x70,0x8c,0x9b,0x40,0x43,0xb8, + 0x2,0x92,0x86,0x9a,0x1c,0x22,0xa1,0x89,0x66,0x40,0x3,0x32,0x68,0xdb,0x2d,0x98, + 0x83,0x5f,0xee,0x82,0xef,0xda,0x10,0x1b,0x60,0x2,0x48,0x99,0xbe,0x32,0x7f,0x65, + 0x59,0xda,0xab,0x5a,0x32,0x1,0x7f,0xc9,0xa5,0x15,0xe0,0x0,0x94,0xe7,0x0,0xf8, + 0x5e,0x77,0xca,0x9e,0xb8,0x75,0xa6,0x8e,0x94,0x15,0x84,0x6f,0x64,0x2,0x35,0x88, + 0x82,0x42,0x20,0x4,0xeb,0xac,0x80,0x50,0x38,0xb7,0xd5,0x1a,0x92,0x6a,0x48,0x5, + 0x2,0x18,0x4,0x41,0xa8,0xc6,0x68,0x28,0x87,0xfe,0x3b,0xb1,0xf3,0x49,0x78,0xd3, + 0xb4,0x1b,0x34,0x14,0xd4,0x86,0xa,0x86,0x1e,0x38,0x4,0x8b,0xbf,0xf8,0x2c,0x70, + 0x81,0xb3,0x3,0x2f,0x26,0x18,0xbb,0x8f,0x97,0x75,0x41,0xa6,0x25,0x5a,0x3a,0xb5, + 0xb0,0x37,0x1,0xe,0x20,0xfb,0x95,0xe7,0xf0,0x96,0x77,0xf9,0xf,0x91,0x83,0x6, + 0x15,0x5d,0xb0,0x78,0x82,0x2c,0x28,0x3,0x3a,0xc0,0x1f,0x7,0xae,0x81,0x40,0x20, + 0xd,0x79,0xa8,0x1b,0x4c,0xe6,0x1a,0xdd,0x79,0x6,0x49,0xa0,0x1,0x31,0x50,0xf, + 0x46,0xc0,0x7b,0x5b,0x41,0x31,0x9d,0x63,0xf8,0x7b,0x6e,0x28,0x93,0xc0,0x87,0x5b, + 0x68,0x81,0x46,0x20,0x81,0x5f,0xfe,0x0,0x2f,0xf8,0x7a,0x1b,0x60,0xbe,0xe3,0xe3, + 0x7a,0x71,0xf7,0xfa,0xaf,0x17,0x7b,0x46,0x29,0x7b,0xfe,0xb2,0x67,0x79,0xb4,0x2f, + 0xe7,0x88,0x8,0x83,0x68,0x1e,0xba,0x63,0x5b,0x40,0x65,0x73,0x83,0x33,0xb0,0x1, + 0x17,0x80,0x83,0x39,0x48,0x4c,0x71,0xf0,0x91,0x6e,0xb0,0xbd,0x94,0xc0,0x86,0xc5, + 0x88,0x8d,0xbe,0xa5,0x81,0x49,0x8,0x81,0x1b,0xd8,0x84,0x98,0x80,0x8f,0xd7,0xd8, + 0x22,0x33,0x1c,0xe,0x7a,0x35,0xe6,0xe3,0x38,0x7,0x79,0xb8,0x85,0x4,0x20,0x83, + 0x22,0x48,0x82,0x23,0x80,0x2,0xde,0x6e,0x2,0x1e,0xe0,0x81,0x50,0x3,0xf9,0x6f, + 0xd6,0xfc,0xcd,0xef,0x7c,0xcf,0x3f,0x7b,0xd0,0xf,0x7d,0x88,0xf8,0x52,0xad,0x2e, + 0x3,0x76,0x45,0x36,0x41,0x10,0x84,0x31,0x0,0x62,0x39,0x50,0x2,0x1c,0x8,0xd6, + 0xf7,0x40,0xc3,0x33,0x94,0x71,0x7f,0xa0,0x21,0x59,0x40,0x82,0x22,0x50,0x88,0x19, + 0x10,0x5,0x1f,0xd1,0x86,0xc4,0x50,0x8c,0xe2,0x28,0xc8,0xc,0x84,0x4f,0xa7,0x7, + 0x8,0x7f,0x2,0xdf,0x7d,0x93,0xc7,0x8a,0x2,0x17,0x28,0x86,0x6c,0x1c,0x61,0x22, + 0x44,0x8,0x13,0x1e,0x2f,0x5e,0x40,0x19,0x62,0xf1,0x22,0xc6,0x1c,0x1a,0x35,0xda, + 0x30,0xe1,0xf1,0x23,0x87,0x90,0x22,0x45,0x96,0x28,0x39,0xe6,0x24,0xca,0x94,0x2a, + 0x57,0xb2,0x4c,0xa9,0xe6,0x25,0x4c,0x35,0x61,0xae,0x5c,0xf1,0xe2,0x65,0xc,0x1c, + 0x33,0x69,0xb6,0xac,0x11,0x94,0x85,0x8e,0xa5,0x23,0x45,0xc0,0xd4,0x12,0x87,0xf, + 0x9f,0xbe,0x6b,0x2,0xf9,0x9,0xf4,0x67,0x4f,0x5f,0x53,0x7f,0x50,0xd7,0xe9,0xfb, + 0xa6,0x4a,0x6,0x10,0x27,0x4e,0x1e,0x94,0x92,0xfe,0x7,0x15,0x9b,0x53,0x74,0xf6, + 0xc6,0xda,0x6b,0xca,0x8f,0x69,0xd4,0xb4,0xfe,0xf6,0x35,0xdd,0xa7,0xef,0x9d,0x37, + 0x7c,0xa0,0x26,0xb0,0xb8,0xe3,0xc5,0x61,0x96,0x2c,0x4d,0xae,0x4c,0xb4,0x81,0xf1, + 0xef,0x90,0x8d,0x1a,0x3f,0x82,0x1c,0x69,0xb8,0x64,0x89,0x96,0x8a,0x17,0xab,0x8c, + 0x9,0x33,0x8c,0xcd,0x33,0x5e,0x5e,0x5a,0xa9,0xc,0x7,0x4e,0x8d,0xcb,0x22,0x2, + 0xfd,0xfa,0x76,0xb4,0x1b,0xbe,0xa5,0x68,0x9d,0xea,0xd3,0xb7,0x4e,0x20,0xb6,0xd3, + 0xa5,0xf1,0x71,0xaa,0x3b,0x83,0xf,0x99,0x53,0xd3,0xf4,0x79,0xeb,0x6,0x55,0x2d, + 0xee,0xb4,0xeb,0x4e,0xb,0xdc,0x2d,0x50,0xdf,0x39,0x7c,0x95,0xc4,0x24,0x91,0x82, + 0xd7,0xca,0xde,0xbe,0x80,0x33,0xa,0x26,0x6c,0xc2,0x30,0x74,0xc4,0x8c,0xa7,0x2b, + 0x76,0xc,0xf3,0xa4,0x1a,0x2f,0x67,0xb6,0x9f,0x9,0xd3,0x5,0x4e,0x16,0x32,0x3d, + 0x1a,0x9,0xc3,0xa7,0xe,0xe9,0xd4,0xb3,0xa3,0xa5,0x9a,0xf6,0x77,0x9a,0xad,0xbf, + 0x77,0xef,0xd4,0x71,0x9a,0x0,0xa9,0x48,0x8a,0x16,0xaf,0xbc,0xd1,0x2e,0xed,0x4f, + 0xfd,0x59,0xec,0xdd,0x96,0x9b,0x7b,0xbc,0xe5,0xe3,0xe,0x3b,0xe8,0xc0,0x55,0x9f, + 0x18,0x35,0x30,0xc1,0x44,0x10,0x7b,0x55,0x61,0x43,0x45,0xcb,0x59,0x24,0x58,0xe, + 0xce,0x41,0x37,0x92,0x7,0xd2,0xb1,0xf4,0x5,0x88,0x21,0x82,0x68,0xdd,0x4b,0xd4, + 0x9d,0x64,0xc5,0x13,0x4f,0x94,0x11,0xc6,0x19,0x6c,0xf4,0x51,0x45,0x1c,0x7b,0x14, + 0xb1,0x6,0x12,0x8c,0x24,0x23,0xf,0x7a,0xfe,0x66,0xa9,0xf7,0x5b,0x69,0x3,0xa, + 0x44,0x56,0x38,0xfa,0x38,0x73,0x49,0x1b,0x3d,0x3c,0x31,0x8,0x5,0xa4,0x78,0x16, + 0xd7,0x3d,0xf5,0xcc,0x53,0xf,0x3c,0x68,0xd9,0x23,0x16,0x81,0x69,0xe5,0xc3,0xce, + 0x38,0xf6,0xbc,0x83,0xf,0x33,0x99,0x18,0xa0,0x47,0x8,0x1f,0xb0,0xf1,0x9c,0x17, + 0x47,0x98,0x79,0xc4,0x45,0x18,0x62,0x48,0xd8,0x86,0x22,0x79,0xf0,0xe6,0x9b,0x2d, + 0x89,0x28,0x22,0x89,0x6a,0x98,0x38,0x86,0x15,0x3b,0x65,0xf1,0x85,0x17,0x71,0xf4, + 0x31,0x5,0x10,0x2b,0x40,0xd2,0x42,0x1e,0xce,0x18,0xe5,0x23,0x80,0x4d,0xf5,0xe8, + 0xa3,0x53,0x63,0xf9,0xa3,0xd,0x3d,0xe4,0x5c,0xc2,0xc8,0x13,0x61,0x70,0x31,0x1, + 0x28,0x9e,0x5d,0x93,0x8d,0x93,0x4f,0x32,0x15,0x4e,0x96,0x65,0x55,0xd9,0x14,0x59, + 0x53,0x82,0x56,0x4c,0x26,0x34,0x14,0xb1,0x87,0xd,0x7b,0xe4,0x10,0xc2,0x17,0x52, + 0x98,0x99,0xa6,0x9a,0x1b,0xb1,0xd9,0x26,0x7,0x70,0xc6,0xf9,0xe1,0x9c,0x20,0xde, + 0xd9,0x52,0x9e,0x73,0x3c,0x61,0x85,0x17,0x7c,0x1,0x1,0x84,0x22,0x13,0x60,0xe2, + 0xc,0x35,0xf8,0xd0,0x33,0xaa,0x80,0x8c,0xea,0x33,0xd6,0x3a,0xf7,0xcc,0x13,0x4f, + 0x39,0x9a,0x98,0xc1,0x3,0x14,0x52,0xc8,0xe0,0x9,0x8e,0xf8,0xb4,0xe3,0x24,0x37, + 0xe6,0xac,0x13,0xe,0x59,0xd0,0xfe,0x98,0x25,0x3a,0x6c,0xe9,0x83,0x8f,0x33,0x60, + 0xf8,0xf1,0xc1,0x1e,0x2b,0x7c,0x31,0x48,0x11,0xb2,0xa2,0x79,0x61,0xad,0x83,0x15, + 0xd6,0xa6,0xae,0x1e,0xc8,0xd9,0xeb,0xfe,0x17,0xbf,0xb2,0x64,0xc5,0x16,0x87,0xc, + 0x62,0xc5,0x11,0x5e,0xdc,0x71,0xc6,0xa5,0x98,0x7c,0xa3,0x8e,0x3a,0xf4,0xdc,0x3, + 0x6d,0x8f,0x69,0x2d,0xba,0x4f,0x3d,0xf5,0xb4,0x23,0x4f,0x34,0x94,0x70,0x10,0x47, + 0x4,0x93,0x28,0xd1,0x46,0xb8,0x16,0x33,0xe5,0x4e,0xa9,0xea,0x3a,0xc5,0xee,0x7f, + 0xf7,0x9c,0x97,0xcc,0x1b,0x32,0xdc,0x20,0xc7,0xd,0x44,0x64,0xa1,0x2f,0xad,0xfd, + 0xde,0xa,0xb0,0xae,0x3,0xf7,0x6a,0xf0,0xc1,0x84,0xd0,0x41,0x44,0x17,0x74,0xc0, + 0xe1,0xc7,0x12,0x9e,0x9c,0xe7,0xcd,0x3a,0xfc,0x98,0xa3,0xd6,0xa2,0xfe,0x51,0xbd, + 0xa8,0x3f,0xe6,0xdc,0x83,0x8f,0x38,0xc8,0x6c,0xd1,0x84,0xd,0x6c,0xa8,0x1,0x47, + 0xf,0x79,0x34,0x7b,0x1e,0x54,0x7,0xa6,0xab,0xee,0xb4,0xd6,0x8,0x74,0xf,0x53, + 0xe7,0x31,0x13,0x49,0xcd,0x5c,0x74,0x71,0xc3,0x99,0x3d,0xd7,0xfa,0xf3,0x86,0x1, + 0xb,0x4d,0xf0,0xd0,0x26,0x86,0xc1,0x3,0x1b,0x77,0xd,0xb2,0x46,0xb,0x28,0x9c, + 0x62,0xde,0x3b,0x65,0xa5,0xc3,0x54,0x3e,0x4f,0x91,0x55,0x35,0x6e,0x19,0x67,0xed, + 0x4f,0x38,0xde,0x8,0xa3,0x41,0xa,0x74,0x34,0xb1,0x48,0x14,0x56,0xe8,0x51,0xc7, + 0x1f,0xcc,0x1c,0x15,0xe,0x3a,0xfe,0xb8,0x93,0x8e,0xcb,0x3c,0xda,0xb6,0x1b,0x3f, + 0xbb,0x81,0xf6,0x4d,0x26,0x14,0xe4,0x5b,0xd1,0xac,0xfc,0xba,0xb0,0x3b,0xef,0xbb, + 0xf3,0xd,0x9d,0xdf,0xbc,0x2,0x1e,0x38,0x75,0x61,0x4c,0x31,0xc5,0x15,0x72,0xe8, + 0xd1,0x43,0x1b,0xa8,0xc8,0x73,0xfe,0xde,0x3b,0x7,0xba,0xc3,0x72,0xa9,0xd3,0x52, + 0x1e,0x95,0x3b,0x52,0x39,0x7b,0xcf,0x3d,0xf4,0xbc,0xe5,0xb,0x6,0x7e,0xe8,0xb1, + 0x3,0x21,0x2e,0x10,0xa2,0x2,0x17,0x62,0xd0,0x20,0x89,0x32,0xef,0xe8,0x13,0xce, + 0x7f,0xf0,0xd4,0xd3,0xba,0x3f,0xde,0xbf,0xa5,0x3a,0x36,0x52,0xbf,0x4b,0x4d,0x29, + 0x13,0x44,0x10,0x7,0x14,0x72,0x17,0x98,0x1c,0xf4,0xae,0x77,0xbf,0x33,0x4c,0xf0, + 0x84,0x37,0x3c,0x10,0x55,0xc6,0xa,0x63,0x88,0x89,0x65,0x2e,0xf3,0xc0,0x16,0xf5, + 0xa1,0xf,0x3c,0xc8,0x82,0x12,0x70,0xb0,0x8a,0x70,0x75,0x3,0x1d,0xd3,0x9b,0xde, + 0xe4,0xaa,0x66,0xb9,0x7c,0xfc,0x87,0x1f,0x4f,0xd1,0x7,0x3d,0x52,0x28,0x1f,0x62, + 0x88,0x81,0xb,0x5c,0xe8,0x89,0x15,0xb4,0x10,0x84,0x30,0x44,0xe1,0xb,0x45,0x90, + 0xc1,0x1b,0x88,0x81,0x8f,0xc6,0xf1,0x3,0x1e,0x51,0xd2,0x98,0x8,0xfd,0x41,0xc2, + 0x14,0xaa,0x63,0x5a,0xa9,0x33,0x87,0xd6,0x8e,0x62,0x95,0x9,0xe4,0x4c,0xa,0x39, + 0xd0,0x81,0xd,0x6c,0xa0,0x91,0x9c,0x11,0x81,0x8,0x2e,0x98,0x41,0xc,0x62,0x70, + 0x40,0xe,0xc1,0x29,0x3,0x5d,0xf8,0x22,0x18,0xbb,0x50,0x30,0x96,0x90,0xc8,0xa, + 0x62,0x10,0x3,0x9f,0x6c,0xe2,0x5,0x2b,0xd4,0x20,0xd,0x3b,0x21,0x44,0x21,0xaa, + 0x70,0x3c,0xf,0xc8,0x21,0x10,0x38,0xa8,0x5,0x3e,0xf8,0x53,0x2a,0x51,0x89,0x70, + 0x40,0x8b,0xb2,0x47,0x3e,0xce,0x62,0xae,0xf8,0xac,0xe6,0x17,0x8d,0x90,0xc1,0x20, + 0xc6,0x50,0x86,0x20,0xa0,0xfe,0x24,0xc,0x34,0xec,0x42,0x16,0x52,0xf0,0x86,0xf2, + 0x4c,0xe3,0x1c,0xa6,0x31,0xc7,0x59,0x54,0xe3,0xbe,0x3f,0x2,0x92,0x84,0x3c,0xf2, + 0xa4,0x7b,0x7a,0xf4,0xe,0x5e,0x28,0xe0,0xd,0x45,0xd0,0x41,0xc,0x46,0xe0,0x84, + 0x17,0xe4,0x80,0x8,0x35,0xd8,0x81,0x11,0x6e,0x50,0x82,0x13,0x9c,0x20,0x6,0x88, + 0xb9,0x25,0x62,0xba,0x98,0x81,0x5d,0x5a,0x20,0x8c,0x61,0x6c,0x49,0x19,0xb7,0xb0, + 0x5,0x3e,0x61,0x1,0xb,0x67,0x18,0x83,0x19,0x76,0x90,0x86,0x43,0x94,0xa1,0x9, + 0x72,0x4c,0x9e,0x11,0x90,0x80,0x47,0x7c,0x58,0x63,0x8f,0x81,0x64,0x8a,0xe5,0xa2, + 0xd2,0xa3,0xb1,0x4,0xd2,0x87,0xfe,0x40,0x47,0x90,0xf0,0x81,0xc,0x4c,0x50,0x0, + 0x11,0x84,0x80,0x50,0x10,0x7c,0x35,0x6,0x47,0x8e,0xe1,0xb,0x70,0x20,0x43,0xb, + 0x7e,0x61,0x1e,0x4b,0x66,0x6d,0x6a,0xeb,0x70,0x9f,0x6d,0xb6,0xc9,0x4d,0x50,0x46, + 0xc5,0x37,0xee,0x11,0x88,0x31,0xec,0x40,0x17,0x43,0x38,0xe1,0x4,0x53,0xe0,0x80, + 0x2b,0x61,0x29,0x4b,0x5a,0x8e,0x0,0x97,0xb8,0xd4,0xa5,0x5,0x22,0xea,0x4b,0x30, + 0xde,0xc9,0x8c,0x68,0x54,0x63,0x77,0xac,0x20,0x8,0x33,0xd4,0xc0,0xa,0x84,0xd8, + 0x83,0xb,0xe0,0x40,0x2,0x24,0x0,0xe3,0x28,0xea,0x10,0x22,0x59,0x48,0x18,0x20, + 0x45,0xf9,0xa7,0x6a,0x80,0xcc,0x5a,0x26,0xe5,0x83,0xf,0x65,0x60,0xa2,0x5,0x34, + 0xa8,0x1,0x1d,0xe4,0xb0,0x1,0x3a,0xa8,0x13,0x32,0x61,0x18,0x83,0xa,0xc4,0x50, + 0x87,0x4,0xe0,0xe2,0xfe,0x28,0xee,0xeb,0x8d,0x6a,0x38,0xb9,0xb6,0x2a,0xa5,0x26, + 0x3e,0xcc,0xc0,0xc4,0x4,0x42,0x0,0x84,0x17,0x80,0xa0,0xa,0xad,0x2c,0x42,0x11, + 0x6e,0xd0,0x81,0x11,0x9c,0xc0,0xa1,0xf,0x7d,0x13,0x2f,0x25,0x3a,0xd1,0x2e,0xdc, + 0xe9,0xb,0x59,0x18,0xd6,0x3a,0x6d,0x12,0x86,0x20,0x10,0xa1,0xc,0x82,0x10,0x82, + 0x8,0xe0,0x80,0x88,0x16,0xfc,0x61,0x18,0xf8,0xf8,0x86,0xca,0x4,0xe2,0xe,0x95, + 0xf2,0xe3,0x62,0x2c,0x2d,0x8d,0xe4,0xf2,0x21,0x58,0xd1,0x50,0xe5,0xae,0xdf,0xc0, + 0x84,0x1,0x2,0x81,0x8,0x11,0x8,0xe1,0x68,0x3c,0xb5,0x2,0x88,0x7c,0x1a,0x85, + 0x2e,0xd4,0x40,0x9,0x43,0x7d,0x85,0x79,0xf8,0x73,0xbf,0x7f,0xa,0x51,0xb0,0x91, + 0xb3,0x1a,0x6e,0xf6,0xc1,0x1b,0xf7,0x74,0xe3,0x3c,0xa5,0xc0,0x80,0x14,0xa0,0x0, + 0x4,0x8,0xd8,0x40,0x7,0x37,0x78,0xed,0xa,0x3a,0xe0,0xd5,0xaf,0x7a,0x20,0xac, + 0xbd,0x1c,0xeb,0xdf,0x42,0xd4,0x5,0x2b,0x64,0xa1,0x81,0x69,0x65,0xc3,0x7,0xc2, + 0x40,0x8,0x11,0xec,0x60,0xe,0x28,0xc8,0x84,0x32,0x8e,0x82,0xf,0xb8,0x61,0x52, + 0x75,0x9e,0xec,0x6b,0xf7,0x78,0x64,0x4d,0xd1,0xf0,0x3,0x1b,0xef,0x9a,0x86,0x3c, + 0x18,0xd1,0x83,0x39,0xec,0x20,0xb,0x82,0xb0,0x2,0x11,0x8,0x41,0x84,0xca,0x44, + 0xd6,0xa7,0x44,0x0,0x4f,0xa,0x1a,0x91,0x80,0x52,0x68,0x4a,0xb3,0x60,0xa9,0x1c, + 0xa3,0x9a,0x92,0x9a,0x75,0xc0,0x87,0x3d,0xd3,0xc0,0x7,0x2e,0x30,0x20,0x2,0xd5, + 0x1e,0xcb,0x6,0xfe,0x33,0x70,0xc1,0x6b,0x37,0xb0,0x82,0xd9,0x96,0x4,0xa2,0x62, + 0x9d,0x68,0x6e,0x43,0xd4,0xc0,0xcb,0x58,0x81,0x45,0x36,0x30,0x4,0xf,0x36,0x80, + 0x88,0x3a,0xe0,0xe0,0x11,0xc9,0xb8,0x2f,0x7f,0xfc,0x1,0xd,0x7e,0x80,0x70,0x2c, + 0xb7,0xb1,0xd8,0x6f,0xf6,0x68,0x8f,0xec,0xa9,0x87,0x2a,0xfa,0xc0,0xee,0x23,0x7a, + 0xa0,0x4,0x3d,0xc0,0x21,0xbc,0x74,0x50,0x41,0x19,0x98,0x90,0x97,0x31,0x42,0xc6, + 0xb,0x43,0x38,0x2f,0x1c,0x52,0x90,0x8,0x1a,0x94,0xc2,0x19,0x38,0xda,0xec,0xe3, + 0x76,0xf4,0x9b,0xdc,0xc0,0x87,0xbe,0xa2,0xed,0xd1,0x7d,0x85,0xf1,0x87,0x9,0x24, + 0x61,0x5,0x5a,0x34,0xc1,0xa,0x6e,0xa0,0x2,0x15,0xc,0x98,0xc0,0x6,0xbe,0x2d, + 0x82,0x15,0xa8,0xdb,0x93,0xe4,0xe4,0x9,0x70,0x18,0xc3,0x19,0x1e,0x7c,0x5,0x45, + 0x24,0xa2,0x2,0x97,0x70,0x6,0x52,0xac,0x81,0xba,0xbd,0x6e,0x43,0xc4,0xfe,0xf1, + 0xeb,0xb4,0x44,0x5c,0x42,0x7e,0x94,0x26,0x2e,0x99,0x40,0xc1,0x1c,0xd6,0xa0,0x2, + 0x42,0x84,0x81,0x8,0x74,0xb0,0x42,0x11,0xc0,0xb3,0xa7,0x93,0x38,0x52,0x32,0x8b, + 0x70,0x1,0x13,0x26,0x21,0x2,0x2e,0x50,0xe0,0x13,0x68,0xfe,0xc6,0x3b,0xa8,0xbb, + 0x52,0xa9,0x10,0x48,0xb4,0x6a,0xe9,0x86,0xfb,0x66,0xa,0xa,0x2,0x88,0x60,0x5, + 0x2b,0x80,0xb2,0x94,0xa9,0x4c,0xe0,0x12,0x5c,0x79,0xac,0x64,0xd5,0x72,0x88,0xbc, + 0x10,0x6,0x2b,0x98,0x61,0xd,0xc3,0xea,0x13,0x10,0xf6,0xc0,0x5,0x3,0x84,0x22, + 0x1a,0x5e,0xfe,0x41,0xd7,0x58,0x10,0xe4,0xe6,0x37,0xff,0x48,0xc4,0xa2,0x62,0x8a, + 0x72,0x43,0x81,0xe7,0x1d,0x78,0x74,0x3,0x41,0x60,0xab,0xd2,0x66,0x4c,0x63,0x9b, + 0xb8,0xe1,0x8,0x7b,0x8,0x83,0xb,0xe4,0xc0,0x4,0x38,0x24,0x40,0x13,0x76,0xc5, + 0x47,0x38,0xe,0x94,0xa8,0x21,0xe7,0xc6,0x37,0xeb,0x68,0xaa,0xa3,0xba,0x11,0x17, + 0x6a,0x98,0xa2,0x5,0x36,0xe3,0x9d,0xa,0x6e,0x50,0xe5,0x5b,0x76,0xa8,0xc0,0x60, + 0xcd,0x40,0x44,0xb1,0x2c,0x46,0x5f,0x2d,0xb0,0x57,0x47,0x70,0x3,0x8a,0x5c,0x3d, + 0x8,0x37,0xdc,0xc1,0x6,0x80,0x90,0xc1,0x27,0xe4,0x21,0xf0,0x38,0x53,0x6f,0xc4, + 0xd9,0x3,0x61,0x69,0x22,0xfd,0x2c,0x94,0x92,0x85,0x1d,0x64,0x1,0xcb,0x96,0xc4, + 0x61,0xa,0x14,0x34,0x42,0xf,0x8d,0x75,0xa4,0x23,0xcd,0x9a,0x17,0xbb,0xcd,0x3b, + 0xa,0x18,0x95,0x8c,0x1a,0xbf,0x30,0x87,0xa,0xd8,0x8,0x29,0x63,0xd9,0x86,0x90, + 0x39,0xab,0x2e,0xb2,0x64,0x2f,0x85,0x47,0xb1,0xc5,0x5,0x68,0x20,0x2,0x29,0x7c, + 0x60,0x5,0x19,0xe0,0x0,0x6d,0xdf,0xbd,0x4b,0x78,0x1f,0x78,0xde,0xf5,0x26,0x98, + 0xaa,0x85,0x60,0x6,0x33,0x6c,0x21,0xb,0x4c,0x90,0x82,0x22,0x8a,0xb0,0x9,0x71, + 0x8,0xdc,0x62,0x83,0xf4,0xc7,0x36,0xb2,0x37,0x67,0xf7,0xbc,0xb7,0x29,0x91,0x1b, + 0x8b,0xc3,0xc5,0x82,0x8e,0xb7,0xe0,0x83,0xdc,0x60,0xa8,0x83,0xab,0x1b,0x5c,0x4c, + 0x47,0xf2,0x76,0xe3,0x5f,0xc,0x51,0x14,0x3c,0x6e,0x93,0x62,0x16,0x33,0x8,0x35, + 0xa8,0xfe,0x43,0x1d,0x2a,0x90,0x5c,0x6f,0x88,0x65,0x1b,0xbd,0xa1,0x5f,0xaf,0x47, + 0x1c,0x33,0x7a,0xdc,0x15,0x18,0x48,0xa0,0xc1,0x3,0xce,0x40,0x6a,0x87,0xea,0x6a, + 0xe7,0x3b,0x8f,0xb7,0x2f,0x7f,0x4e,0xb0,0x66,0x7f,0x7,0xe,0x4f,0xc8,0x8b,0x1f, + 0x26,0x90,0x8a,0x89,0x21,0xa5,0x49,0xf5,0xb8,0xc7,0xd4,0x4,0x82,0x49,0x6e,0x70, + 0xe3,0x49,0x97,0x5f,0xcf,0xd5,0xc7,0x52,0xcd,0xb7,0x54,0xe5,0x1b,0xac,0xd0,0x40, + 0xf,0x12,0x91,0x19,0x39,0xb8,0x0,0xb,0x18,0x2f,0x7b,0x16,0xc0,0x8,0xa2,0x8e, + 0xab,0xdd,0xb,0xc5,0xf4,0x2,0x11,0xd6,0x90,0x82,0x3a,0x5c,0x0,0x19,0xfc,0x89, + 0x74,0x54,0x16,0xee,0xb2,0x52,0xb9,0x83,0x1f,0x1d,0xbb,0x47,0x55,0x92,0x81,0x4, + 0x19,0x7c,0x20,0xe,0x10,0xc8,0xb9,0xe1,0xf,0xdf,0xf3,0xb3,0x2b,0x5e,0x44,0x6b, + 0xa5,0x43,0x19,0x74,0xe6,0x7,0x44,0x50,0xc0,0x69,0x48,0xe9,0x46,0xcc,0xda,0xe1, + 0xbd,0x77,0x74,0xa3,0x1b,0x51,0xeb,0x94,0xe7,0x2f,0x56,0x9a,0xc1,0x1e,0xdc,0xc3, + 0xfa,0x78,0x6,0x3e,0x64,0xd1,0x82,0x1d,0x1c,0x62,0xd,0x35,0x58,0xe4,0x10,0x54, + 0x1d,0x86,0x2f,0xc0,0xbe,0xb,0xc7,0x9e,0xfd,0x6e,0x9d,0x9d,0xda,0x61,0x81,0x17, + 0x6c,0xc0,0x20,0x64,0x81,0x11,0xbc,0xc1,0x5,0x94,0x7,0x7a,0xc,0xc8,0x7a,0x8c, + 0x4a,0xcb,0x9c,0xc5,0xe5,0x65,0xc3,0xbb,0x8,0x83,0xf,0xdc,0x80,0x3,0x34,0x54, + 0x2e,0xe9,0x5c,0xf4,0xf1,0x9c,0x5,0x3c,0xc8,0x44,0x55,0x1f,0x88,0x1c,0x9b,0x1b, + 0xfe,0x74,0x1,0x11,0xf0,0x81,0x18,0xbc,0xc1,0x1f,0xc8,0xc3,0x7d,0x5,0x49,0xf6, + 0x68,0x83,0x49,0x1d,0x5,0x6d,0x58,0x4c,0xc7,0x78,0x9e,0x54,0x70,0xd3,0xd4,0xad, + 0x83,0x6d,0x14,0x84,0x2c,0x80,0xc1,0xe,0x50,0x42,0xd,0x34,0x16,0x13,0xdc,0x9b, + 0x17,0xd4,0xd0,0x17,0xf1,0x16,0xb1,0x78,0x41,0x3a,0xed,0x56,0x5e,0xf4,0xd6,0x17, + 0x5,0x41,0x17,0xa8,0xd1,0x6,0xc8,0x1,0x7e,0x2c,0xc1,0x2,0x1e,0xc5,0x6c,0xe8, + 0x43,0xfe,0xe0,0x5d,0x53,0x7c,0x50,0x9,0xd1,0x83,0x67,0xfc,0x2,0x1,0x48,0xc1, + 0xe0,0x91,0x5a,0x6d,0x75,0xa0,0xe1,0xc5,0xdb,0x83,0x30,0x41,0xe2,0x55,0xdf,0x17, + 0x35,0x4c,0xe,0x78,0x81,0x1c,0xe4,0xc7,0x2f,0x9c,0x87,0xf9,0xb5,0x19,0x3a,0x1c, + 0x5,0x35,0xc,0x43,0x2e,0xf4,0x82,0xe9,0xbc,0x8b,0x36,0x30,0xd7,0x3a,0xec,0x51, + 0x9,0x45,0x49,0x61,0xc9,0x3,0x2e,0x54,0xc0,0x12,0x98,0xc1,0x8b,0xc9,0x81,0x1c, + 0x4,0x81,0x22,0xa8,0xdd,0x11,0x36,0x50,0xc8,0x41,0x52,0x13,0xe6,0x85,0x15,0x3c, + 0x61,0x10,0xb0,0x1,0xf,0x7c,0x80,0x1c,0xb8,0x52,0x20,0x20,0x41,0x51,0xe5,0x91, + 0x69,0x4c,0x9a,0xba,0x70,0x4f,0xa3,0xe4,0xda,0x69,0x94,0x96,0x5c,0x3c,0x80,0xe, + 0x74,0x8,0x7,0xa2,0x61,0x4,0xa8,0xe1,0x1a,0x86,0x91,0x8,0x6,0xa0,0x17,0xb4, + 0x8a,0x1a,0x28,0xb,0xd3,0xe9,0x83,0xd4,0xb8,0x3,0x38,0xd8,0xc3,0x37,0x98,0xc2, + 0x5,0x60,0x80,0xc,0x4c,0x0,0xd,0x80,0x82,0x32,0x94,0x6,0xfc,0xd8,0x3,0xfe, + 0xae,0xa5,0x4b,0xf,0xc1,0xc3,0xc5,0x7c,0xc3,0x1e,0x4a,0x40,0x1d,0x4,0x2,0x11, + 0x84,0x81,0x1b,0xb8,0x41,0xe,0x4,0x1,0xce,0x84,0x51,0x3,0x45,0xa1,0x4d,0x40, + 0x61,0x5e,0x88,0x81,0x30,0x35,0xe1,0x17,0x81,0xd,0x1b,0x5c,0x81,0x27,0xbe,0x90, + 0x6,0x30,0x82,0x5d,0x65,0xd8,0x86,0xb5,0x8e,0xf1,0xd5,0x83,0xf7,0xd8,0x3,0x3b, + 0x38,0xdc,0x36,0xb8,0x85,0x37,0xa8,0x3,0x31,0x10,0xc0,0xd,0x7c,0x80,0x2e,0xa1, + 0x61,0x6,0x44,0xc0,0x2c,0x46,0xd4,0x1a,0xb2,0xa1,0x2d,0x56,0x9f,0x3,0xb9,0x41, + 0x13,0xec,0x1,0x11,0x28,0x1,0x2b,0x98,0x47,0x73,0x55,0x53,0x35,0xd8,0xc1,0x1b, + 0x88,0xc1,0xd,0x48,0x1,0x20,0xb0,0x0,0x6,0x80,0xc1,0x30,0x0,0x87,0x58,0x38, + 0x5c,0x4a,0x4d,0xdd,0x79,0x0,0x43,0x5,0xf4,0x0,0x19,0x64,0x81,0x1b,0x44,0x41, + 0x18,0xe4,0x80,0x23,0x4d,0xe1,0x44,0x65,0xa2,0x1a,0x41,0x61,0x17,0x70,0xc1,0x25, + 0xe6,0xc5,0x83,0x34,0x41,0x1c,0x44,0x51,0xe,0x1c,0x81,0xd,0x21,0xc2,0x1b,0x80, + 0x1,0x32,0xe0,0xc3,0x34,0x2c,0x85,0x5a,0x48,0x8e,0xa3,0x98,0x45,0xc7,0xdc,0x63, + 0x3e,0x3a,0x5c,0xb5,0xbc,0x8b,0x32,0x10,0x0,0xb,0x74,0x40,0x2c,0xee,0x9c,0x41, + 0x66,0x65,0xbc,0x9d,0x9,0x57,0x1e,0x81,0xa9,0x1,0x4e,0x16,0xe0,0x54,0x19,0x94, + 0x81,0x1e,0xa0,0x40,0x32,0xbc,0xc3,0x3e,0x44,0x89,0x3d,0x9c,0xc3,0x37,0x6c,0x2, + 0xd,0x88,0x81,0x14,0xa4,0x56,0xb7,0x88,0xc1,0x12,0xd8,0x41,0xb3,0x84,0xfe,0x3, + 0x49,0xa6,0xce,0x6e,0x9c,0x6,0x55,0x78,0x6,0x30,0xb4,0x1,0x9,0x20,0x42,0x8b, + 0x85,0xc8,0xb1,0xb5,0xa1,0x3a,0x5,0x81,0x1a,0x35,0xc1,0x17,0x25,0x64,0x42,0x1e, + 0x1,0xf,0x5c,0x1,0xf,0x34,0x41,0x13,0x98,0x9,0x11,0xdc,0x50,0x25,0xc0,0x9f, + 0x7c,0xf4,0xd3,0x40,0x6c,0x12,0x60,0xa9,0x4e,0xfd,0x74,0xcf,0x3e,0xe0,0x63,0x3e, + 0xfa,0x3,0x37,0x78,0x8c,0x3c,0x20,0xc3,0x3,0x38,0xc0,0x40,0xc6,0x1b,0x6b,0xc6, + 0x1b,0x4,0xbc,0x66,0x57,0x9e,0x89,0xa9,0x99,0x1a,0x26,0xb2,0xda,0x21,0x30,0x2, + 0x35,0xf8,0x22,0x3c,0x68,0xcf,0x2e,0x18,0x1,0x17,0x48,0x41,0x13,0x40,0x1,0x4d, + 0x78,0x41,0x78,0xa0,0x0,0x1e,0x4d,0x8b,0xc3,0x15,0x88,0x54,0xd8,0xc6,0x7d,0xfd, + 0x65,0x1d,0x20,0x82,0xa,0xb8,0xc1,0x5a,0xcd,0xe6,0x44,0x25,0xa6,0x64,0x4a,0x66, + 0x6c,0xc6,0xe6,0x75,0x1e,0x41,0x13,0x78,0x4b,0x25,0x18,0x65,0x69,0x7c,0x1b,0x6f, + 0x58,0xcf,0x1f,0x35,0x45,0xa,0xad,0xc,0x3e,0xda,0x83,0xd6,0x74,0x8f,0x3c,0xfc, + 0xc2,0x3,0x58,0x40,0x17,0x81,0x40,0x6b,0xce,0xe7,0x6b,0x42,0x40,0x76,0x7a,0x25, + 0x75,0xfa,0x52,0x16,0xc0,0x81,0x10,0x58,0x41,0x19,0xa4,0x1,0x26,0x20,0x45,0x3a, + 0xc0,0x43,0x3a,0xd8,0x3,0x3e,0xf4,0x4f,0xec,0x15,0x4b,0x15,0x54,0x1,0x16,0x74, + 0xc1,0x16,0xa0,0x80,0x26,0x14,0x51,0xae,0x15,0x48,0x69,0x9c,0xc3,0x79,0xc,0x43, + 0x1e,0xe0,0x99,0x18,0xd0,0x81,0xb,0xb8,0x81,0x4d,0xe6,0xe7,0x17,0xfe,0x59,0xe7, + 0x76,0x66,0xe7,0x10,0x9c,0x9,0x13,0x60,0x67,0x13,0xdc,0x80,0x8,0xf0,0x98,0x51, + 0x46,0x9a,0x68,0xf9,0x53,0xb4,0x88,0x8a,0x3f,0xa0,0x62,0x68,0x3a,0x4a,0x5f,0x1d, + 0x85,0x3c,0x80,0x1,0x17,0x58,0xe5,0x19,0xca,0xe7,0x7c,0xb2,0x66,0x7d,0xde,0x27, + 0x88,0x86,0xd1,0x79,0x8d,0x97,0x15,0xac,0x41,0x80,0x76,0xc3,0xe3,0xa4,0x43,0x38, + 0xe0,0x3,0x26,0x28,0xc1,0x9e,0x60,0xc1,0x15,0x2c,0xe8,0x15,0x44,0x81,0x50,0xe5, + 0x81,0x38,0xbc,0x85,0xc1,0xb9,0x4b,0x5c,0xa8,0x43,0x32,0xe4,0x1,0xe,0x2c,0x41, + 0x20,0x14,0x1,0x13,0x1c,0x9a,0x17,0xc,0x69,0x88,0x5e,0xa7,0x9a,0xde,0xe7,0x11, + 0xc4,0xe5,0x1a,0x72,0xa7,0x9,0x9c,0xc1,0xd,0x88,0x81,0xf,0x4c,0xe4,0x51,0xf6, + 0xc6,0x7b,0x8d,0x56,0x54,0xd4,0x63,0x2a,0x16,0x1f,0x3f,0xe4,0x11,0x3e,0xa8,0xc2, + 0x4,0x88,0xc0,0x7,0xa4,0xe1,0x8f,0x2,0x29,0x3,0x30,0xc0,0x7d,0x32,0x66,0x2d, + 0x8e,0x15,0x11,0x7c,0x22,0x88,0x88,0x1,0x23,0xc8,0x83,0x37,0xa0,0x5c,0x3a,0x6c, + 0x9d,0x26,0xf4,0xc0,0x16,0x84,0x41,0x31,0x1d,0x4f,0x15,0x10,0x67,0x1d,0x60,0xe9, + 0xe,0xfd,0xd3,0x58,0x8c,0x9b,0x38,0x64,0x68,0x1d,0x74,0x57,0x17,0xe4,0xc0,0x19, + 0xe8,0xc0,0x99,0xa2,0xa9,0x9a,0x62,0x27,0x9b,0x4a,0x41,0x15,0xad,0xa1,0x64,0x5e, + 0x81,0x7f,0x89,0x80,0x2,0xca,0x93,0x35,0x50,0xcf,0xb7,0xad,0x5,0x6e,0xf0,0x29, + 0x34,0xc2,0x20,0x3e,0xe8,0xc2,0x3,0xf0,0xc1,0x3,0x68,0x95,0xfe,0xf4,0x1d,0x6a, + 0x44,0x25,0xaa,0xa2,0x66,0x27,0xa3,0x82,0xe0,0x44,0xb1,0xa1,0x1a,0x94,0xe8,0x77, + 0x44,0x82,0x57,0xac,0xe,0x3f,0xb8,0xf,0x2a,0x54,0xc0,0x16,0x88,0x9d,0x1c,0x7d, + 0x6a,0x16,0xb4,0x40,0x26,0x9c,0xc7,0x5a,0x30,0xc5,0x5a,0x56,0xc5,0xa9,0x6e,0xd7, + 0xe,0xc0,0x41,0x8,0x48,0xc1,0x1e,0xd0,0xb,0x9a,0xa6,0xe3,0x9a,0xce,0x2a,0xad, + 0x12,0x81,0xad,0xf2,0xa4,0x3,0x74,0x8b,0x8,0x90,0x1,0x12,0x24,0x83,0x11,0x8d, + 0x45,0x53,0x5,0x6b,0xc7,0xd4,0xa8,0x3d,0xa4,0xd0,0xbb,0xe4,0xc2,0x3,0x74,0x40, + 0x7,0xdc,0x40,0x8,0x74,0xc0,0xb2,0xfe,0xa8,0x3,0x38,0x80,0xb3,0x2e,0x6a,0xb4, + 0x8e,0x15,0x13,0xa8,0x41,0x14,0xb6,0x69,0x16,0x2c,0xc1,0x33,0x4c,0x8b,0xd4,0xe9, + 0x3,0x2f,0xa0,0x41,0x1d,0xc,0xcb,0x4c,0xd0,0x84,0x14,0x88,0x81,0x71,0x22,0x5, + 0x3d,0x9c,0x85,0x75,0x79,0x83,0x37,0xc8,0x43,0x1e,0xd4,0x1,0x19,0xd4,0xc0,0x24, + 0xdc,0x40,0x13,0xb4,0xea,0x1e,0xb4,0xe9,0xbc,0xd6,0x2b,0x9a,0x64,0xe7,0xbd,0x12, + 0x1,0x4e,0x9e,0x28,0xd8,0xbc,0xc0,0x15,0xf0,0xab,0x12,0x44,0xc2,0xc7,0x5a,0x83, + 0x58,0xec,0x15,0x52,0xee,0x69,0xc1,0xee,0xc3,0x26,0xdd,0x55,0x2f,0x2c,0x6c,0x6, + 0x38,0x80,0xb,0x3c,0x6c,0xc4,0xb6,0xe6,0xc4,0x52,0x6c,0xa2,0x5a,0x6c,0xb4,0x32, + 0xaa,0x14,0x7c,0xc1,0xd,0x84,0xc1,0x64,0x16,0x41,0x3,0x10,0x83,0xfb,0x0,0xdf, + 0x96,0x74,0x42,0x1b,0xcc,0xc1,0xb7,0xda,0x84,0x14,0x70,0xfe,0x81,0xf,0xfc,0xc1, + 0x7d,0xbd,0xc3,0x8e,0x54,0x43,0xd7,0x65,0x82,0x4a,0x3e,0x1,0x1d,0x30,0x41,0x21, + 0x84,0x19,0x14,0xac,0xc0,0xc,0x48,0x1,0xc6,0x46,0x6b,0xbd,0x5a,0x4,0xd0,0x56, + 0x11,0x17,0xd4,0x80,0xd1,0x71,0xe7,0xb,0x1c,0x4f,0x9,0x9c,0xa9,0x8,0xe8,0x47, + 0x35,0xbc,0xf,0xc1,0x4d,0x9d,0x8e,0xfc,0x86,0x72,0xf5,0x2,0x6,0x3c,0x40,0x9, + 0x44,0x14,0x7,0xcc,0x80,0xa1,0x4a,0xec,0xc4,0x3a,0xab,0x85,0x84,0x6d,0xb4,0x8e, + 0x6d,0x1c,0x9e,0xc1,0xc,0x84,0x0,0x24,0x28,0x89,0x3e,0x58,0xc3,0xda,0x12,0xc4, + 0x23,0x14,0x9,0x19,0xf8,0x81,0x1f,0xc8,0x0,0xd,0xd8,0xc1,0x32,0x96,0xe2,0x6e, + 0x6e,0x9,0x35,0x64,0x42,0x2,0x4,0x42,0xd,0x10,0x1,0x62,0x3e,0xe6,0xd1,0x6, + 0x90,0x71,0xa8,0x2e,0x63,0xb2,0x69,0x6c,0xc6,0x65,0x12,0x8,0xad,0x83,0x9c,0xa8, + 0xd,0x4c,0xc4,0xb,0x48,0x11,0x11,0xd0,0x80,0x4,0xbc,0x82,0xfb,0x4,0x9,0x3a, + 0x9c,0x46,0xca,0x7d,0x93,0x3d,0x60,0x3,0x3d,0x9c,0xc7,0x37,0xfc,0x2,0x6,0x54, + 0xe5,0xce,0x81,0x0,0x8,0x94,0x6e,0x44,0x75,0xad,0xfc,0xa2,0xee,0x72,0x38,0x6f, + 0xb4,0xde,0x40,0xe,0x4,0xe7,0xc,0x14,0xc1,0x1b,0xa8,0xc3,0xc7,0x7a,0x83,0xfb, + 0x58,0x83,0x3a,0x88,0xc3,0x2a,0xe0,0x0,0xa,0xb4,0x80,0x6,0xfc,0x81,0x29,0x3c, + 0x83,0x37,0x58,0x52,0xd4,0x98,0xd0,0x5d,0x7d,0xc2,0xd7,0x4d,0x40,0x22,0x15,0x13, + 0x4d,0x2c,0x6f,0x9b,0xda,0x6f,0x63,0x42,0x6f,0x57,0xfe,0xe,0xc1,0xbd,0xd6,0x0, + 0x17,0xc,0xe1,0xf5,0xf6,0x45,0xe,0xdc,0x80,0x11,0x5c,0x0,0xc,0xc4,0x23,0x7f, + 0xe8,0xa9,0xa2,0xd8,0x83,0x35,0xa0,0x10,0x35,0xa,0x3,0x5d,0x74,0xc0,0x7,0xd4, + 0x70,0x6,0xb8,0x2f,0xfc,0xca,0xef,0xfc,0x26,0x6a,0xea,0x6a,0xf0,0x1a,0x12,0x81, + 0x13,0xcd,0x80,0xe,0xa4,0xe8,0x4,0xc4,0x82,0x67,0x64,0xa1,0x82,0xe0,0x83,0x3c, + 0xec,0x21,0x2e,0x10,0x3,0x3,0x3,0x16,0xf8,0xa9,0xc6,0x33,0x94,0xc2,0x5,0x2c, + 0x81,0xfd,0x65,0x87,0x5,0x1f,0xad,0x64,0xba,0xa9,0xf,0xf,0x21,0x7,0x73,0xa5, + 0x7,0xdf,0x2b,0x17,0x10,0xc1,0x11,0x8c,0x70,0xf6,0x6a,0x44,0x15,0x22,0x1,0x33, + 0xa8,0x3,0x5c,0xac,0xc5,0x3e,0xbc,0xf1,0x1b,0x37,0xce,0xe5,0x36,0xc3,0x51,0xa8, + 0xef,0x3,0xec,0xd2,0x7,0x84,0x40,0x98,0xb8,0xef,0xfb,0xda,0x96,0x5,0xe8,0x70, + 0xd7,0x26,0xea,0x1,0xf4,0x70,0x17,0x13,0x1,0x9f,0xcc,0x80,0x9,0x74,0x4b,0x11, + 0x50,0x40,0x32,0x18,0x55,0x8f,0xf4,0x23,0x52,0x70,0x26,0xd3,0xf6,0x88,0x9a,0x1d, + 0xa8,0x6,0x90,0x81,0xfd,0x95,0x8f,0x17,0xf0,0x0,0x27,0x5f,0x67,0x17,0x6f,0x70, + 0x6c,0x2e,0x47,0xe,0xb4,0x56,0xe,0x4c,0x2f,0x11,0x24,0xc1,0x10,0xd8,0xc0,0x54, + 0x1,0x81,0x14,0xb5,0x12,0x17,0x18,0x1,0x5,0xfc,0x1,0x78,0xca,0x7,0x1c,0x1b, + 0xac,0x96,0x6c,0xc9,0x2f,0x18,0x0,0xb,0x58,0x0,0x8,0x78,0xc0,0x6,0xe8,0xf1, + 0x7,0x80,0xc0,0x9,0x40,0xc0,0x2e,0x1d,0x64,0xfe,0xfc,0x2,0xb2,0x3,0x1c,0x80, + 0x32,0x13,0xb2,0xf,0x8f,0x97,0x8d,0x99,0x80,0xab,0xf2,0x81,0xb2,0x84,0x8b,0x37, + 0x94,0x5,0x6d,0xd0,0xee,0xfb,0x58,0x83,0xdb,0x50,0xc5,0x39,0x60,0x98,0x2a,0x90, + 0xc0,0x16,0xd4,0x40,0x11,0x98,0xe0,0x43,0xc6,0x6a,0x10,0x7c,0xf2,0x9b,0x92,0x28, + 0x60,0x8c,0x32,0x29,0xe7,0xc,0xfe,0x42,0x51,0x14,0xb5,0xf2,0xd,0x6c,0x80,0x8a, + 0xd2,0x40,0x80,0xe2,0x43,0x35,0x34,0xce,0x7,0x1,0xc9,0x96,0xf4,0x2,0x55,0x96, + 0x0,0x4,0xbc,0x89,0x1e,0x87,0x89,0x5,0x40,0x80,0x5,0x14,0xa4,0x31,0xff,0x31, + 0x32,0x2b,0xf3,0x20,0xd7,0xef,0x27,0x5b,0x1,0x13,0xc,0x1,0x14,0x44,0x91,0x6b, + 0xc9,0x40,0xb,0x4,0xdc,0x37,0xcc,0x6e,0xf9,0x42,0x45,0xba,0x44,0x8d,0x54,0xb0, + 0x25,0x35,0xe4,0x82,0x1,0x88,0x40,0x19,0xa8,0xc0,0x83,0x6c,0x0,0x37,0x5e,0xe7, + 0x87,0xa2,0xb3,0x17,0x87,0xf2,0x72,0xf4,0x57,0x9,0x13,0xc1,0xd,0x24,0x1,0x14, + 0xb1,0xb2,0xe,0x94,0xf0,0xd,0x70,0x80,0x9,0x7c,0x40,0x11,0x68,0x80,0x2a,0x44, + 0x72,0xae,0x55,0xcf,0x34,0xf8,0x73,0x7,0xc4,0xc1,0x0,0xbc,0x40,0x9,0xe4,0x31, + 0x30,0x43,0x6c,0x56,0x26,0x34,0x32,0x27,0xf3,0x32,0x3b,0x74,0x17,0x57,0x46,0x44, + 0xc7,0xf3,0xa,0x30,0x1a,0xa,0x84,0x2,0x35,0x34,0x83,0x3d,0xd8,0x1d,0x8c,0xaa, + 0x7,0x3d,0x5c,0xc3,0x5d,0xb1,0x82,0xf,0x18,0x1,0x1d,0x18,0xdb,0x18,0xb8,0x80, + 0x4d,0x6c,0x80,0x27,0xef,0x56,0x65,0x54,0xfe,0x11,0x5c,0xc3,0x75,0xd8,0xde,0x67, + 0xbf,0xf4,0x85,0x6b,0x55,0xd1,0xd,0xe8,0x80,0xe,0xd8,0xf4,0x6b,0xdd,0xc0,0x82, + 0x46,0x40,0x8,0xf8,0x41,0x1,0xd8,0x2,0x0,0xfb,0x1a,0x3e,0xf0,0x42,0x3,0xb0, + 0xc0,0x9,0x4,0xc0,0x30,0x2b,0x75,0x98,0xd4,0xf0,0x7,0x34,0x35,0x6b,0x3e,0x35, + 0x43,0xe7,0x40,0x60,0x5c,0xb6,0x65,0xa3,0xf3,0x78,0xbd,0xa4,0x9,0xd8,0x80,0x5d, + 0x10,0x81,0x1f,0x28,0xc1,0x5,0xe4,0xc1,0x30,0x58,0x92,0x7c,0x6c,0x92,0x4c,0xe1, + 0xa8,0x33,0x7c,0x42,0xb,0xa4,0x40,0x16,0x4,0x1,0x37,0x6e,0xc0,0x19,0x34,0xc1, + 0x6,0xec,0x41,0x18,0xaf,0x21,0x44,0xc7,0x75,0x5c,0xcf,0x75,0x76,0xd6,0xca,0x5e, + 0x67,0xaf,0x6b,0xf5,0xb5,0x5e,0xf,0xf7,0x6b,0xe5,0x40,0x15,0xbc,0x0,0x16,0xdc, + 0xc0,0x4,0x2c,0x41,0x2,0xd8,0xc2,0x69,0xbf,0x3,0x3a,0x44,0xf7,0x3b,0xd4,0x82, + 0x4,0xc8,0x80,0x5,0x30,0x36,0x2,0x8c,0xc0,0x2f,0x6f,0x0,0x64,0xd7,0xb0,0x64, + 0xc7,0x1b,0x32,0x2f,0x0,0x43,0xdf,0x34,0x79,0x5f,0xb6,0x85,0x58,0x48,0x15,0xf1, + 0xcb,0x4d,0x97,0x70,0x11,0x64,0x81,0x8,0x4c,0x80,0x28,0xec,0x82,0xc0,0x29,0x97, + 0xc0,0x9,0x1c,0x32,0x94,0x42,0x1d,0x90,0x40,0xa,0x74,0x57,0x4b,0x7f,0xf1,0x79, + 0x2f,0xc7,0x7d,0x8a,0x32,0x45,0xff,0x17,0xef,0xc,0xf7,0xc,0x10,0xb8,0xb,0x74, + 0x44,0x94,0x89,0x80,0xc,0xf0,0xae,0x2b,0x34,0x8b,0x51,0x3d,0x83,0x2a,0x50,0x0, + 0xa1,0xde,0x70,0x2f,0xd7,0x56,0xa1,0xfe,0x16,0xf3,0x77,0x1f,0xb3,0xfc,0x2e,0x80, + 0x87,0x8b,0x37,0x2,0x20,0xc0,0x70,0xf,0xb7,0x65,0xff,0xb7,0x89,0x5f,0xc4,0x19, + 0xc,0x41,0x13,0xb8,0xc1,0x19,0x70,0xb7,0x8,0x44,0xc2,0x27,0xc4,0x82,0x30,0x20, + 0x83,0x30,0xd0,0x82,0x2b,0x34,0x42,0x20,0x18,0x41,0xa,0x38,0x2e,0x1c,0x40,0xf4, + 0x17,0xe7,0xcd,0x89,0x5f,0x44,0x80,0x2f,0xc7,0x15,0x1d,0xb8,0x91,0xb,0xb1,0xe, + 0x1c,0xb8,0xa7,0x2d,0xb9,0xa7,0xb9,0x0,0xb,0xa8,0xa8,0x8,0x3c,0x0,0x24,0xb4, + 0x2,0x31,0x10,0x43,0x2a,0x48,0x2,0x1,0x8,0x64,0xc0,0x9c,0x21,0x56,0x46,0x94, + 0x41,0x4e,0xb6,0xe,0x7f,0xf8,0x2,0x84,0xb8,0x88,0x8f,0xb8,0x5e,0x7,0xf9,0x89, + 0xdb,0x4,0x9a,0x34,0x81,0x4d,0x14,0x81,0x12,0x20,0xc1,0x1,0x6b,0x80,0x6,0xd0, + 0x40,0xa,0x50,0xc0,0x8e,0x3b,0x2e,0x5c,0xff,0x38,0x90,0xa3,0xf9,0x90,0x3,0x46, + 0x91,0x1f,0x39,0xa0,0x33,0xf9,0x47,0x2c,0x39,0xb,0xb0,0x80,0x8,0x44,0xf9,0x31, + 0x12,0x80,0x31,0x6a,0x79,0xc0,0xc0,0xef,0x7c,0x2,0xb2,0x98,0x93,0xf9,0x81,0x9b, + 0xb9,0x46,0xa0,0xf9,0x79,0x6f,0xc0,0x11,0x80,0x9c,0x76,0x7c,0x41,0xa,0xd0,0x80, + 0xa7,0x9f,0x51,0xb,0xc1,0x1,0x1f,0xa8,0x1,0x13,0xdc,0x80,0xb,0xfc,0xa4,0x9e, + 0xb,0x90,0xa5,0xaf,0x73,0xad,0x0,0xba,0xab,0x33,0xf9,0xba,0x95,0x4,0x64,0x3f, + 0x40,0xa1,0x1b,0xfa,0xa1,0x3f,0x40,0x86,0x13,0x64,0x42,0x73,0x2d,0xa4,0x7f,0xb8, + 0xa4,0x4f,0x3a,0x89,0x97,0xf8,0xfe,0xaa,0xff,0x45,0x13,0x58,0xb6,0xaa,0x79,0x41, + 0xd6,0xf2,0x81,0xb,0x61,0xd5,0x6b,0xc5,0xa5,0x46,0xe8,0x80,0x70,0xd6,0x44,0x89, + 0xea,0xf9,0xb0,0x8b,0x72,0xab,0xbb,0xba,0x92,0xc3,0xfa,0x80,0x8d,0x0,0xb7,0xbb, + 0x9b,0xe,0x30,0x6c,0xd,0xe3,0x7a,0x6c,0x11,0xa4,0x7,0x9a,0x6e,0x87,0x7f,0xb8, + 0x32,0x87,0xf8,0x0,0x10,0x2e,0xb0,0xeb,0xb5,0xb0,0x57,0xbb,0x45,0xb8,0xc1,0x10, + 0x6c,0x80,0xb,0xb0,0xb9,0x76,0x7c,0xc0,0x6,0x14,0x87,0x14,0xd8,0xd8,0xc,0x4, + 0xa7,0xd,0x5c,0x30,0xae,0x4e,0xfb,0x8f,0xc3,0xfb,0x5f,0xd4,0xca,0x9f,0x7,0xba, + 0xb6,0x6f,0x3b,0xb7,0x8f,0x0,0x9c,0x94,0x0,0x42,0x1b,0x24,0xc3,0xea,0xfa,0xae, + 0x83,0x79,0x98,0xa3,0xfb,0x1,0xc,0x0,0xc6,0x7b,0x9a,0x91,0x7,0x7b,0xbf,0xa8, + 0x89,0x85,0x9c,0x3a,0x9b,0x37,0xc1,0xee,0xe8,0xc0,0x76,0x94,0x89,0x99,0x77,0x44, + 0x14,0xd1,0x4,0xee,0x50,0xbb,0xa5,0xf7,0x4b,0x1,0xf1,0xe,0xb6,0xcf,0x40,0xc2, + 0xc7,0x7a,0xbb,0x39,0x7c,0x9,0x0,0xc1,0x2e,0xd9,0x52,0x4,0x10,0x24,0xaf,0x3f, + 0xb5,0x3,0x78,0x38,0x43,0x33,0x34,0xc6,0xaf,0xbb,0xc6,0x23,0xf9,0x7a,0x77,0x3c, + 0x86,0x58,0xc8,0x4f,0x36,0x41,0x89,0x62,0x67,0x3c,0x73,0x32,0x4d,0x34,0xc1,0xa, + 0xe8,0x35,0x14,0x54,0x3d,0x14,0xa0,0x3a,0xcb,0xa3,0xb9,0xcb,0xbf,0xfc,0xc1,0x1f, + 0xf9,0xcc,0xaf,0xc0,0x7,0x3c,0x94,0xd,0xec,0x7c,0x49,0x14,0xa4,0xd,0xf0,0x3c, + 0xc5,0x3f,0x35,0xd0,0x7,0xfe,0xfd,0xc5,0x63,0x7c,0xcc,0x23,0xbd,0xc7,0x5b,0xba, + 0x3a,0x5b,0x44,0x12,0xd4,0x7d,0xa5,0x13,0xbc,0xde,0x8,0x6,0xd7,0xef,0x7d,0x91, + 0x7f,0x3d,0xd8,0x77,0x37,0xe0,0x77,0x37,0x2,0x45,0x9f,0x56,0x82,0xb7,0xcf,0xaf, + 0x3d,0xdb,0xb7,0xfd,0x0,0xbc,0x3d,0xdc,0xb,0xc6,0xaa,0xbb,0xf4,0x8d,0x99,0x32, + 0x5c,0xa3,0x32,0xde,0xf,0x90,0x9a,0xf0,0x3d,0xd7,0xcb,0xfc,0xd7,0x77,0xf7,0x2f, + 0xf,0x74,0x98,0x84,0xc0,0x6,0x70,0x37,0x64,0x87,0x4,0x97,0x6b,0xb8,0x53,0x1f, + 0xbe,0x78,0x27,0xbe,0xe2,0xcf,0x7c,0xcc,0x63,0xbb,0xb,0xe0,0xbd,0x6e,0x57,0x66, + 0x11,0xd4,0x80,0x38,0x53,0x3e,0xde,0xbb,0x3c,0xb6,0xfb,0xfd,0xe6,0x43,0xf6,0x2f, + 0x8b,0x80,0xe7,0xf,0x74,0xe8,0xb,0xbe,0xe1,0x7d,0x79,0xda,0x57,0x3c,0xe2,0xb, + 0xfd,0xd0,0x13,0xbd,0xb6,0xb7,0x3e,0xb6,0x37,0x7e,0xbf,0xc4,0xbe,0xec,0x63,0x55, + 0x56,0x39,0x3f,0xf5,0x6f,0x44,0xd7,0x1b,0xb9,0xee,0x6b,0x7b,0xe0,0x77,0xbe,0xe7, + 0x7,0x3e,0x64,0xf,0x3f,0xf1,0x73,0x78,0x78,0x5b,0x7c,0xd0,0x27,0xbf,0xf2,0xc3, + 0xba,0x99,0xa7,0xff,0x88,0xcf,0x40,0xf5,0xab,0x49,0x5f,0xf7,0x75,0x15,0x61,0x95, + 0x4c,0xb7,0x3f,0xf5,0x5f,0x91,0xfa,0xc7,0x7c,0xc2,0x7b,0x3f,0xbe,0xeb,0x3f,0x64, + 0x47,0x3c,0xf8,0x17,0x3f,0x40,0x38,0x70,0xb0,0x80,0x60,0xc1,0x5,0x7,0x10,0x26, + 0x1c,0xb0,0x90,0xe1,0x80,0x15,0xf,0x21,0x3e,0x9c,0x31,0x91,0x62,0x45,0x8b,0x2b, + 0x5c,0xe4,0xd0,0xb8,0xfe,0x91,0x63,0x47,0x17,0x33,0x74,0x80,0x74,0x31,0xd2,0xc5, + 0xd,0x93,0x27,0x6f,0x74,0x54,0xb9,0x52,0x25,0x49,0x97,0x1f,0x75,0xc4,0x94,0xa9, + 0x23,0x62,0xcd,0x88,0x1f,0x70,0xe6,0xd4,0xb9,0x13,0x67,0x87,0xe,0x19,0x80,0x66, + 0xb0,0x30,0xd4,0x42,0x4,0xa3,0x11,0x86,0xa,0x54,0xaa,0xd4,0xa0,0xc1,0x84,0xa, + 0x1b,0x2e,0xb4,0x29,0xd1,0x62,0x55,0x8a,0x18,0x59,0xb6,0xc,0x69,0x63,0x86,0x8d, + 0x99,0x19,0xb3,0x86,0xd,0xfb,0x92,0x24,0xc8,0x99,0x31,0xa7,0xda,0xe4,0xb9,0x33, + 0x68,0x50,0xa2,0x16,0x20,0xc4,0x95,0x5b,0xf4,0xed,0x52,0xa6,0x4d,0xf,0x3e,0x3d, + 0x10,0xb5,0x61,0xc4,0x91,0x37,0x3e,0xce,0x58,0x21,0x98,0xf0,0x60,0xc3,0x82,0x57, + 0xe8,0xc8,0xa1,0x98,0xf1,0x62,0xc7,0x8c,0x43,0xce,0x88,0xd1,0xb5,0xeb,0xd9,0x99, + 0x1a,0x33,0x66,0xce,0xa1,0x99,0xf3,0x63,0xc7,0x33,0x3e,0x86,0x6,0x1d,0x13,0x64, + 0x69,0x9a,0x69,0x6f,0xae,0x58,0x8b,0xb3,0x2d,0x8,0x10,0x6f,0xe5,0xce,0xad,0x6b, + 0x77,0x60,0xd3,0x3,0x79,0x11,0xe,0xd8,0xcb,0x77,0x21,0x88,0x12,0x25,0x3e,0x6c, + 0x50,0x21,0x42,0xc5,0x60,0x13,0x33,0x8e,0x27,0x47,0xbe,0xfc,0xb8,0x57,0xe7,0x3a, + 0x9e,0x47,0x27,0x3d,0x31,0x64,0xf5,0x98,0x8e,0x31,0x8b,0xd6,0xe,0x9a,0xbb,0x8b, + 0x98,0xd2,0x95,0x2b,0x2f,0xb1,0x62,0x7c,0x79,0xf2,0x1f,0x80,0xa7,0x47,0xbf,0x5e, + 0xbd,0x87,0xe,0xee,0xe1,0x7b,0x68,0x3b,0x5f,0xe8,0x5b,0xb8,0x72,0x19,0xe4,0xd7, + 0xbf,0xff,0x29,0xfe,0x82,0x3,0xfe,0x75,0xe3,0x6d,0x80,0x5,0x6,0x10,0xc0,0x37, + 0xf,0x3e,0x60,0x21,0x4,0x15,0x42,0x58,0xc1,0x84,0x7,0x21,0x8c,0x50,0x42,0x1b, + 0x28,0xac,0xd0,0xc2,0xb,0xa7,0xb3,0xc8,0xb2,0xc,0xad,0xaa,0xea,0xc2,0xa,0x25, + 0x84,0xf0,0xb7,0x11,0x49,0x2c,0xd1,0x44,0x12,0x3d,0x48,0x51,0xc5,0x14,0xe9,0x6b, + 0xeb,0x28,0xa3,0xe0,0xda,0x4f,0x46,0xfe,0xfe,0x43,0xc0,0x46,0x4,0x4,0x2c,0x90, + 0xa1,0x0,0x74,0x7a,0xe8,0x3,0x7,0x43,0xc,0x52,0xc8,0x21,0x27,0x9a,0xaa,0x43, + 0xd4,0xa6,0x1a,0x32,0xc8,0x13,0x99,0x6c,0x72,0xc5,0x15,0x5b,0xcc,0xe0,0x45,0x18, + 0x2d,0x98,0xd1,0xca,0x84,0x6e,0xc4,0x31,0x47,0x1,0xb8,0xc,0x20,0x80,0x1b,0x36, + 0xf8,0xb1,0x44,0x25,0xc9,0x24,0x12,0xb1,0x9a,0x8e,0x44,0xb2,0xa6,0x32,0x23,0x6c, + 0xf2,0xc4,0x27,0x55,0x8c,0x92,0xbe,0x29,0xa9,0xac,0xd2,0x4a,0x1a,0x11,0xba,0x31, + 0xc7,0x2,0x5,0xf0,0xd2,0x4b,0x6,0x37,0xe0,0xa0,0x84,0x11,0x4e,0xf0,0x8d,0x83, + 0x43,0x11,0x4d,0x54,0x51,0x36,0x1f,0x2c,0xd2,0xa6,0x34,0xd5,0x84,0x48,0x48,0x45, + 0x11,0x75,0xd3,0x44,0x39,0x5b,0xb4,0x4f,0xd3,0xba,0xee,0xd4,0x4f,0x2f,0x1b,0xb7, + 0xe4,0xb2,0x4f,0x0,0x0,0x8,0x40,0x85,0xd,0x56,0xe0,0x60,0x4,0x10,0xa,0x2d, + 0x81,0xd2,0x57,0xf,0x65,0xd4,0x84,0x48,0x69,0x4d,0x6b,0xd2,0x57,0x2d,0x2d,0x11, + 0x53,0xfa,0x36,0xdd,0x54,0xa0,0x4e,0x19,0xd0,0x6b,0x37,0x1,0x45,0xed,0x92,0xd4, + 0x0,0x46,0x6f,0x12,0x74,0x84,0x55,0xd,0x85,0x95,0x52,0x59,0x6b,0x8d,0x36,0xa2, + 0x5b,0x29,0xcd,0x95,0xc4,0x5d,0xe7,0xeb,0xd5,0x3e,0xa5,0xee,0x14,0x36,0xb7,0x50, + 0x45,0xf5,0x33,0x0,0x41,0x5f,0x28,0xc1,0x3,0xd7,0x2c,0x70,0xd5,0xd9,0x45,0x19, + 0x95,0xd6,0x5d,0x6a,0x15,0x65,0x12,0x4e,0x16,0xb1,0x75,0x4b,0x5b,0xa2,0xb8,0x9d, + 0xd1,0xdb,0x6f,0x79,0x2b,0xb6,0x58,0x2f,0x5f,0x78,0x61,0x4,0x73,0x33,0xf0,0xe9, + 0x83,0x75,0x11,0x8e,0x35,0x44,0x77,0xa5,0x4d,0x38,0x51,0x79,0xe7,0xad,0xd7,0xde, + 0xa4,0x94,0xb2,0x80,0x36,0x7,0x3c,0xdd,0xf7,0xa9,0x7e,0xfd,0x15,0x75,0xa1,0x0, + 0x2,0x2,0x0,0x3b, + +}; + +static const unsigned char qt_resource_name[] = { + // images + 0x0,0x6, + 0x7,0x3,0x7d,0xc3, + 0x0,0x69, + 0x0,0x6d,0x0,0x61,0x0,0x67,0x0,0x65,0x0,0x73, + // resources + 0x0,0x9, + 0xa,0x6c,0x78,0x43, + 0x0,0x72, + 0x0,0x65,0x0,0x73,0x0,0x6f,0x0,0x75,0x0,0x72,0x0,0x63,0x0,0x65,0x0,0x73, + // tools.gif + 0x0,0x9, + 0x6,0x36,0xbb,0x36, + 0x0,0x74, + 0x0,0x6f,0x0,0x6f,0x0,0x6c,0x0,0x73,0x0,0x2e,0x0,0x67,0x0,0x69,0x0,0x66, + +}; + +static const unsigned char qt_resource_struct[] = { + // : + 0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1, + // :/images + 0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x2, + // :/images/resources + 0x0,0x0,0x0,0x12,0x0,0x2,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x3, + // :/images/resources/images + 0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x4, + // :/images/resources/images/tools.gif + 0x0,0x0,0x0,0x2a,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0, + +}; + +QT_BEGIN_NAMESPACE + +extern Q_CORE_EXPORT bool qRegisterResourceData + (int, const unsigned char *, const unsigned char *, const unsigned char *); + +extern Q_CORE_EXPORT bool qUnregisterResourceData + (int, const unsigned char *, const unsigned char *, const unsigned char *); + +QT_END_NAMESPACE + + +int QT_MANGLE_NAMESPACE(qInitResources_resources)() +{ + QT_PREPEND_NAMESPACE(qRegisterResourceData) + (0x01, qt_resource_struct, qt_resource_name, qt_resource_data); + return 1; +} + +Q_CONSTRUCTOR_FUNCTION(QT_MANGLE_NAMESPACE(qInitResources_resources)) + +int QT_MANGLE_NAMESPACE(qCleanupResources_resources)() +{ + QT_PREPEND_NAMESPACE(qUnregisterResourceData) + (0x01, qt_resource_struct, qt_resource_name, qt_resource_data); + return 1; +} + +Q_DESTRUCTOR_FUNCTION(QT_MANGLE_NAMESPACE(qCleanupResources_resources)) + diff --git a/tcutils/resources.qrc b/tcutils/resources.qrc new file mode 100644 index 00000000..76a1f852 --- /dev/null +++ b/tcutils/resources.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/images"> + <file>resources/images/tools.gif</file> + </qresource> +</RCC> diff --git a/tcutils/resources/images/tools.gif b/tcutils/resources/images/tools.gif Binary files differnew file mode 100644 index 00000000..c6596cc4 --- /dev/null +++ b/tcutils/resources/images/tools.gif diff --git a/tcutils/tcutils b/tcutils/tcutils Binary files differnew file mode 100755 index 00000000..73aa979a --- /dev/null +++ b/tcutils/tcutils diff --git a/tcutils/tcutils.pro b/tcutils/tcutils.pro new file mode 100644 index 00000000..a24029e8 --- /dev/null +++ b/tcutils/tcutils.pro @@ -0,0 +1,30 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2013-08-18T13:54:44 +# +#------------------------------------------------- + +QT += core gui + +TARGET = tcutils +TEMPLATE = app + + +SOURCES += main.cpp\ + mainwindow.cpp \ + utils.cpp + +HEADERS += mainwindow.h \ + utils.h + +FORMS += mainwindow.ui + +# added by LK Rashinkar +INCLUDEPATH += ../xrdpapi + +LIBS += -Wl,-rpath +LIBS += -Wl,/usr/local/lib/xrdp +LIBS += -L../xrdpapi/.libs -lxrdpapi + +RESOURCES += \ + resources.qrc diff --git a/tcutils/tcutils.pro.user b/tcutils/tcutils.pro.user new file mode 100644 index 00000000..50311334 --- /dev/null +++ b/tcutils/tcutils.pro.user @@ -0,0 +1,365 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE QtCreatorProject> +<!-- Written by Qt Creator 2.4.1, 2013-08-25T13:35:29. --> +<qtcreator> + <data> + <variable>ProjectExplorer.Project.ActiveTarget</variable> + <value type="int">0</value> + </data> + <data> + <variable>ProjectExplorer.Project.EditorSettings</variable> + <valuemap type="QVariantMap"> + <value type="bool" key="EditorConfiguration.AutoIndent">true</value> + <value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value> + <valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0"> + <value type="QString" key="language">Cpp</value> + <valuemap type="QVariantMap" key="value"> + <value type="QString" key="CurrentPreferences">CppGlobal</value> + </valuemap> + </valuemap> + <valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1"> + <value type="QString" key="language">QmlJS</value> + <valuemap type="QVariantMap" key="value"> + <value type="QString" key="CurrentPreferences">QmlJSGlobal</value> + </valuemap> + </valuemap> + <value type="int" key="EditorConfiguration.CodeStyle.Count">2</value> + <value type="QByteArray" key="EditorConfiguration.Codec">System</value> + <value type="bool" key="EditorConfiguration.ConstrainTooltips">true</value> + <value type="int" key="EditorConfiguration.IndentSize">4</value> + <value type="bool" key="EditorConfiguration.MouseNavigation">true</value> + <value type="int" key="EditorConfiguration.PaddingMode">1</value> + <value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value> + <value type="int" key="EditorConfiguration.SmartBackspaceBehavior">2</value> + <value type="bool" key="EditorConfiguration.SpacesForTabs">true</value> + <value type="int" key="EditorConfiguration.TabKeyBehavior">0</value> + <value type="int" key="EditorConfiguration.TabSize">8</value> + <value type="bool" key="EditorConfiguration.UseGlobal">true</value> + <value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value> + <value type="bool" key="EditorConfiguration.addFinalNewLine">true</value> + <value type="bool" key="EditorConfiguration.cleanIndentation">true</value> + <value type="bool" key="EditorConfiguration.cleanWhitespace">true</value> + <value type="bool" key="EditorConfiguration.inEntireDocument">true</value> + </valuemap> + </data> + <data> + <variable>ProjectExplorer.Project.PluginSettings</variable> + <valuemap type="QVariantMap"/> + </data> + <data> + <variable>ProjectExplorer.Project.Target.0</variable> + <valuemap type="QVariantMap"> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Target.DesktopTarget</value> + <value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value> + <value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value> + <value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value> + <valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0"> + <value type="QString" key="ProjectExplorer.BuildCOnfiguration.ToolChain">ProjectExplorer.ToolChain.Gcc:/usr/bin/g++.x86-linux-generic-elf-32bit./usr/bin/gdb</value> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0"> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0"> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value> + <value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">false</value> + <value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibraryAuto">true</value> + <value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value> + <value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value> + </valuemap> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1"> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value> + <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value> + <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value> + <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value> + </valuemap> + <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value> + </valuemap> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1"> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0"> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value> + <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value> + <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value> + <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value> + </valuemap> + <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value> + </valuemap> + <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value> + <value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value> + <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Qt 4.8.1 in PATH (System) Release</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value> + <value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value> + <value type="QString" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildDirectory">/home/lk/projects/jtech/nlabs_xrdp_tcutils/tcutils-build-desktop-Qt_4_8_1_in_PATH__System__Release</value> + <value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.QtVersionId">1</value> + <value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value> + </valuemap> + <valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1"> + <value type="QString" key="ProjectExplorer.BuildCOnfiguration.ToolChain">ProjectExplorer.ToolChain.Gcc:/usr/bin/g++.x86-linux-generic-elf-32bit./usr/bin/gdb</value> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0"> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0"> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value> + <value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">false</value> + <value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibraryAuto">true</value> + <value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value> + <value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value> + </valuemap> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1"> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value> + <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value> + <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value> + <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value> + </valuemap> + <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value> + </valuemap> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1"> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0"> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value> + <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value> + <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value> + <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value> + </valuemap> + <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value> + </valuemap> + <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value> + <value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value> + <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Qt 4.8.1 in PATH (System) Debug</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value> + <value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">2</value> + <value type="QString" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildDirectory">/home/lk/projects/jtech/nlabs_xrdp_tcutils/tcutils-build-desktop-Qt_4_8_1_in_PATH__System__Debug</value> + <value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.QtVersionId">1</value> + <value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value> + </valuemap> + <valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.2"> + <value type="QString" key="ProjectExplorer.BuildCOnfiguration.ToolChain">ProjectExplorer.ToolChain.Gcc:/usr/bin/g++.x86-linux-generic-elf-32bit./usr/bin/gdb</value> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0"> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0"> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value> + <value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">false</value> + <value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibraryAuto">true</value> + <value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value> + <value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value> + </valuemap> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1"> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value> + <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value> + <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value> + <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value> + </valuemap> + <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value> + </valuemap> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1"> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0"> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value> + <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value> + <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value> + <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value> + </valuemap> + <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value> + </valuemap> + <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value> + <value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value> + <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Qt 4.8.1 (System) Release</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value> + <value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value> + <value type="QString" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildDirectory">/home/lk/projects/jtech/nlabs_xrdp_tcutils/tcutils-build-desktop-Qt_4_8_1__System__Release</value> + <value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.QtVersionId">2</value> + <value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value> + </valuemap> + <valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.3"> + <value type="QString" key="ProjectExplorer.BuildCOnfiguration.ToolChain">ProjectExplorer.ToolChain.Gcc:/usr/bin/g++.x86-linux-generic-elf-32bit./usr/bin/gdb</value> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0"> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0"> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value> + <value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">false</value> + <value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibraryAuto">true</value> + <value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value> + <value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value> + </valuemap> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1"> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value> + <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value> + <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value> + <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value> + </valuemap> + <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value> + </valuemap> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1"> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0"> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value> + <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value> + <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value> + <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value> + </valuemap> + <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value> + </valuemap> + <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value> + <value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value> + <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Qt 4.8.1 (System) Debug</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value> + <value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">2</value> + <value type="QString" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildDirectory">/home/lk/projects/jtech/nlabs_xrdp_tcutils/tcutils-build-desktop-Qt_4_8_1__System__Debug</value> + <value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.QtVersionId">2</value> + <value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value> + </valuemap> + <value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">4</value> + <valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0"> + <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0"> + <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value> + </valuemap> + <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">No deployment</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value> + </valuemap> + <value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value> + <valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0"> + <value type="bool" key="Analyzer.Project.UseGlobal">true</value> + <value type="bool" key="Analyzer.Project.UseGlobal">true</value> + <valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/> + <valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/> + <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value> + <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value> + <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value> + <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value> + <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value> + <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value> + <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value> + <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value> + <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value> + <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value> + <value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value> + <value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value> + <value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value> + <value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value> + <value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value> + <value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value> + <value type="int" key="Analyzer.Valgrind.NumCallers">25</value> + <value type="int" key="Analyzer.Valgrind.NumCallers">25</value> + <valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/> + <valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/> + <value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value> + <value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value> + <value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value> + <value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value> + <valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds"> + <value type="int">0</value> + <value type="int">1</value> + <value type="int">2</value> + <value type="int">3</value> + <value type="int">4</value> + <value type="int">5</value> + <value type="int">6</value> + <value type="int">7</value> + <value type="int">8</value> + <value type="int">9</value> + <value type="int">10</value> + <value type="int">11</value> + <value type="int">12</value> + <value type="int">13</value> + <value type="int">14</value> + </valuelist> + <valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds"> + <value type="int">0</value> + <value type="int">1</value> + <value type="int">2</value> + <value type="int">3</value> + <value type="int">4</value> + <value type="int">5</value> + <value type="int">6</value> + <value type="int">7</value> + <value type="int">8</value> + <value type="int">9</value> + <value type="int">10</value> + <value type="int">11</value> + <value type="int">12</value> + <value type="int">13</value> + <value type="int">14</value> + </valuelist> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">tcutils</value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value> + <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4RunConfiguration</value> + <value type="int" key="Qt4ProjectManager.Qt4RunConfiguration.BaseEnvironmentBase">2</value> + <value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.CommandLineArguments"></value> + <value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.ProFile">tcutils.pro</value> + <value type="bool" key="Qt4ProjectManager.Qt4RunConfiguration.UseDyldImageSuffix">false</value> + <value type="bool" key="Qt4ProjectManager.Qt4RunConfiguration.UseTerminal">false</value> + <valuelist type="QVariantList" key="Qt4ProjectManager.Qt4RunConfiguration.UserEnvironmentChanges"/> + <value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.UserWorkingDirectory"></value> + <value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value> + <value type="bool" key="RunConfiguration.UseCppDebugger">true</value> + <value type="bool" key="RunConfiguration.UseQmlDebugger">false</value> + <value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">false</value> + </valuemap> + <value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value> + </valuemap> + </data> + <data> + <variable>ProjectExplorer.Project.TargetCount</variable> + <value type="int">1</value> + </data> + <data> + <variable>ProjectExplorer.Project.Updater.EnvironmentId</variable> + <value type="QString">{9a0d9632-2baf-44e0-864a-a12692180779}</value> + </data> + <data> + <variable>ProjectExplorer.Project.Updater.FileVersion</variable> + <value type="int">10</value> + </data> +</qtcreator> diff --git a/tcutils/ui_mainwindow.h b/tcutils/ui_mainwindow.h new file mode 100644 index 00000000..4c47aefa --- /dev/null +++ b/tcutils/ui_mainwindow.h @@ -0,0 +1,105 @@ +/******************************************************************************** +** Form generated from reading UI file 'mainwindow.ui' +** +** Created: Sun Aug 25 15:11:42 2013 +** by: Qt User Interface Compiler version 4.8.1 +** +** WARNING! All changes made in this file will be lost when recompiling UI file! +********************************************************************************/ + +#ifndef UI_MAINWINDOW_H +#define UI_MAINWINDOW_H + +#include <QtCore/QVariant> +#include <QtGui/QAction> +#include <QtGui/QApplication> +#include <QtGui/QButtonGroup> +#include <QtGui/QHeaderView> +#include <QtGui/QListWidget> +#include <QtGui/QMainWindow> +#include <QtGui/QMenuBar> +#include <QtGui/QPushButton> +#include <QtGui/QStatusBar> +#include <QtGui/QTabWidget> +#include <QtGui/QToolBar> +#include <QtGui/QWidget> + +QT_BEGIN_NAMESPACE + +class Ui_MainWindow +{ +public: + QWidget *centralWidget; + QTabWidget *tabWidget; + QWidget *tabUnmount; + QListWidget *listWidget; + QPushButton *btnUnmount; + QPushButton *btnRefresh; + QWidget *tab_2; + QMenuBar *menuBar; + QToolBar *mainToolBar; + QStatusBar *statusBar; + + void setupUi(QMainWindow *MainWindow) + { + if (MainWindow->objectName().isEmpty()) + MainWindow->setObjectName(QString::fromUtf8("MainWindow")); + MainWindow->resize(541, 355); + centralWidget = new QWidget(MainWindow); + centralWidget->setObjectName(QString::fromUtf8("centralWidget")); + tabWidget = new QTabWidget(centralWidget); + tabWidget->setObjectName(QString::fromUtf8("tabWidget")); + tabWidget->setGeometry(QRect(0, 0, 511, 291)); + tabUnmount = new QWidget(); + tabUnmount->setObjectName(QString::fromUtf8("tabUnmount")); + listWidget = new QListWidget(tabUnmount); + listWidget->setObjectName(QString::fromUtf8("listWidget")); + listWidget->setGeometry(QRect(10, 10, 321, 221)); + btnUnmount = new QPushButton(tabUnmount); + btnUnmount->setObjectName(QString::fromUtf8("btnUnmount")); + btnUnmount->setGeometry(QRect(350, 60, 141, 27)); + btnRefresh = new QPushButton(tabUnmount); + btnRefresh->setObjectName(QString::fromUtf8("btnRefresh")); + btnRefresh->setGeometry(QRect(350, 10, 141, 27)); + tabWidget->addTab(tabUnmount, QString()); + tab_2 = new QWidget(); + tab_2->setObjectName(QString::fromUtf8("tab_2")); + tabWidget->addTab(tab_2, QString()); + MainWindow->setCentralWidget(centralWidget); + menuBar = new QMenuBar(MainWindow); + menuBar->setObjectName(QString::fromUtf8("menuBar")); + menuBar->setGeometry(QRect(0, 0, 541, 25)); + MainWindow->setMenuBar(menuBar); + mainToolBar = new QToolBar(MainWindow); + mainToolBar->setObjectName(QString::fromUtf8("mainToolBar")); + MainWindow->addToolBar(Qt::TopToolBarArea, mainToolBar); + statusBar = new QStatusBar(MainWindow); + statusBar->setObjectName(QString::fromUtf8("statusBar")); + MainWindow->setStatusBar(statusBar); + + retranslateUi(MainWindow); + + tabWidget->setCurrentIndex(0); + + + QMetaObject::connectSlotsByName(MainWindow); + } // setupUi + + void retranslateUi(QMainWindow *MainWindow) + { + MainWindow->setWindowTitle(QApplication::translate("MainWindow", "TC Utils", 0, QApplication::UnicodeUTF8)); + btnUnmount->setText(QApplication::translate("MainWindow", "Unmount device", 0, QApplication::UnicodeUTF8)); + btnRefresh->setText(QApplication::translate("MainWindow", "Get device list", 0, QApplication::UnicodeUTF8)); + tabWidget->setTabText(tabWidget->indexOf(tabUnmount), QApplication::translate("MainWindow", "Tab 1", 0, QApplication::UnicodeUTF8)); + tabWidget->setTabText(tabWidget->indexOf(tab_2), QApplication::translate("MainWindow", "Tab 2", 0, QApplication::UnicodeUTF8)); + } // retranslateUi + +}; + +namespace Ui { + class MainWindow: public Ui_MainWindow {}; +} // namespace Ui + +QT_END_NAMESPACE + +#endif // UI_MAINWINDOW_H diff --git a/tcutils/utils.cpp b/tcutils/utils.cpp new file mode 100644 index 00000000..1b8548c7 --- /dev/null +++ b/tcutils/utils.cpp @@ -0,0 +1,217 @@ +#include "utils.h" + +Utils::Utils() +{ +} + +int Utils::getMountList(void *wtsChannel, QList<QListWidgetItem *> *itemList) +{ + QListWidgetItem *item; + + STREAM s; + quint32 bytesToSend; + quint32 bytesWritten; + quint32 bytesRead; + quint32 cmdLen; + quint32 cmd; + int rv; + int i; + int nentries; + char buf[2048]; + + if (!wtsChannel) + return -1; + + qstream_new(s, 1024 * 8); + + /* + * command format: + * 4 bytes cmd_len length of this command + * 1 byte cmd TCU_CMD_GET_MOUNT_LIST + */ + + /* setup command */ + qstream_wr_u32(&s, 1); + qstream_wr_u8(&s, TCU_CMD_GET_MOUNT_LIST); + bytesToSend = 5; + + /* send command */ + rv = WTSVirtualChannelWrite(wtsChannel, s.data, bytesToSend, &bytesWritten); + if (rv) + { + QMessageBox::information(NULL, "Get device list", "\nError sending " + "command to client"); + return -1; + } + + qstream_set_pos(&s, 0); /* reuse stream */ + + /* get response */ + + /* + * response format + * 4 bytes cmd_len length of this command + * 4 bytes cmd TCU_CMD_GET_MOUNT_LIST + * 1 byte nentries number of entries in this pkt + * n bytes entry_list nentries null terminated strings + */ + + rv = WTSVirtualChannelRead(wtsChannel, 1000 * 5, s.data, 1024 * 8, &bytesRead); + if (rv == 0 || bytesRead == 0) + goto error; + + /* did we get the entire cmd? */ + qstream_rd_u32(&s, cmdLen); + if (cmdLen != bytesRead - 4) + goto error; + + /* did we get the right response? */ + qstream_rd_u32(&s, cmd); + if (cmd != TCU_CMD_GET_MOUNT_LIST) + goto error; + + qstream_rd_u8(&s, nentries); + if (nentries == 0) + goto done; + + for (i = 0; i < nentries; i++) + { + strcpy(buf, s.pos); + qstream_inc_pos(&s, strlen(buf) + 1); + item = new QListWidgetItem; + item->setText(QString(buf)); + itemList->append(item); + } + +done: + qstream_free(&s); + return 0; + +error: + qstream_free(&s); + return -1; +} + +int Utils::unmountDevice(void *wtsChannel, QString device, QStatusBar *statusBar) +{ + STREAM s; + quint32 bytesRead; + quint32 cmdLen; + quint32 cmd; + quint32 bytesWritten; + int bytesToSend; + int rv; + int seconds = 0; + char status; + char* buf; + + if (!wtsChannel) + return -1; + + qstream_new(s, 1024); + buf = device.toAscii().data(); + + /* + * command format: + * 4 bytes cmd_len length of this command + * 4 bytes cmd TCU_CMD_UNMOUNT_DEVICE + * n bytes device null terminated device name + */ + + /* setup command */ + bytesToSend = 4 + 4 + device.count() + 1; + qstream_wr_u32(&s, bytesToSend - 4); + qstream_wr_u32(&s, TCU_CMD_UNMOUNT_DEVICE); + strcpy(s.pos, buf); + + /* send command */ + rv = WTSVirtualChannelWrite(wtsChannel, s.data, bytesToSend, &bytesWritten); + if (rv) + { + QMessageBox::information(NULL, "Unmount device", "\nError sending " + "command to client"); + return -1; + } + + qstream_set_pos(&s, 0); /* reuse stream */ + + /* get response */ + + /* + * command format + * 4 bytes cmd_len number of bytes in this pkt + * 4 bytes cmd TCU_CMD_UNMOUNT_DEVICE + * 1 byte status operation status code + */ + + while (1) + { + rv = WTSVirtualChannelRead(wtsChannel, 1000 * 1, s.data, 1024, &bytesRead); + if (rv == 0) + goto error; + + if (bytesRead) + break; + + statusBar->showMessage("Waiting for client to unmount device: " + + QString::number(++seconds) + " seconds", 30000); + } + + statusBar->showMessage(""); + + /* did we get the entire pkt? */ + qstream_rd_u32(&s, cmdLen); + if (cmdLen != bytesRead - 4) + goto error; + + /* did we get the right response? */ + qstream_rd_u32(&s, cmd); + if (cmd != TCU_CMD_UNMOUNT_DEVICE) + goto error; + + /* get status */ + qstream_rd_u8(&s, status); + switch(status) + { + case UMOUNT_SUCCESS: + goto done; + break; + + case UMOUNT_BUSY: + QMessageBox::information(NULL, "Unmount error", "\nCannot unmount device " + "because it is in use"); + break; + + case UMOUNT_NOT_MOUNTED: + QMessageBox::information(NULL, "Unmount error", "\nCannot unmount device " + "because it is not mounted"); + break; + + case UMOUNT_OP_NOT_PERMITTED: + QMessageBox::information(NULL, "Unmount error", "\nOperation not " + "permitted. The device may be in use"); + break; + + case UMOUNT_PERMISSION_DENIED: + QMessageBox::information(NULL, "Unmount error", "\nYou don't have " + "permission to unmount this device"); + break; + + case UMOUNT_UNKNOWN: + QMessageBox::information(NULL, "Unmount error", "Cannot unmount " + "device, an unknown error has occurred. The " + "drive may be in use or you do not have " + "permission to unmount it"); + break; + } + + goto error; + +done: + qstream_free(&s); + return 0; + +error: + qstream_free(&s); + return -1; +} diff --git a/tcutils/utils.h b/tcutils/utils.h new file mode 100644 index 00000000..f0512dc0 --- /dev/null +++ b/tcutils/utils.h @@ -0,0 +1,150 @@ +#ifndef UTILS_H +#define UTILS_H + +#include <QDebug> +#include <QListWidgetItem> +#include <QMessageBox> +#include <QStatusBar> +#include <xrdpapi.h> + +/* + * stream definition and macros to access them; + * all definitions default to little endian + */ + +typedef struct stream +{ + char* data; /* holds stream data */ + char* pos; /* current read/write position */ + int size; /* number of bytes in data */ +} STREAM; + +#define qstream_new(_s, _size) \ +do \ +{ \ + (_s).data = (char *) malloc(_size); \ + (_s).pos = (_s).data; \ + (_s).size = (_size); \ +} \ +while (0) + +#define qstream_new_zero(_s, _size) \ +do \ +{ \ + (_s).data = (char *) calloc((_size), 1); \ + (_s).pos = (_s).data; \ + (_s).size = (_size); \ +} \ +while (0) + +#define qstream_free(_s) \ +do \ +{ \ + if ((_s)->data) \ + free((_s)->data); \ +} \ +while (0) + +#define qstream_set_pos(_s, _p) \ +do \ +{ \ + (_s)->pos = (_s)->data + (_p); \ +} \ +while (0) + +#define qstream_inc_pos(_s, _v) \ +do \ +{ \ + (_s)->pos += (_v); \ +} \ +while (0) + +#define qstream_rd_u8(_s, _v) \ +do \ +{ \ + (_v) = *((unsigned char *) ((_s)->pos)); \ + (_s)->pos++; \ +} \ +while (0) + +#define qstream_rd_u16(_s, _v) \ +do \ +{ \ + (_v) = (unsigned short) \ + ( \ + (*((unsigned char *) ((_s)->pos + 0)) << 0) | \ + (*((unsigned char *) ((_s)->pos + 1)) << 8) \ + ); \ + (_s)->pos += 2; \ +} while (0) + +#define qstream_rd_u32(_s, _v) \ +do \ +{ \ + (_v) = (unsigned int) \ + ( \ + (*((unsigned char *) ((_s)->pos + 0)) << 0) | \ + (*((unsigned char *) ((_s)->pos + 1)) << 8) | \ + (*((unsigned char *) ((_s)->pos + 2)) << 16) | \ + (*((unsigned char *) ((_s)->pos + 3)) << 24) \ + ); \ + (_s)->pos += 4; \ +} while (0) + +#define qstream_wr_u8(_s, _v) \ +do \ +{ \ + *((_s)->pos) = (unsigned char) (_v); \ + (_s)->pos++; \ +} while (0) + +#define qstream_wr_u16(_s, _v) \ +do \ +{ \ + *((_s)->pos) = (unsigned char) ((_v) >> 0); \ + (_s)->pos++; \ + *((_s)->pos) = (unsigned char) ((_v) >> 8); \ + (_s)->pos++; \ +} while (0) + +#define qstream_wr_u32(_s, _v) \ +do \ +{ \ + *((_s)->pos) = (unsigned char) ((_v) >> 0); \ + (_s)->pos++; \ + *((_s)->pos) = (unsigned char) ((_v) >> 8); \ + (_s)->pos++; \ + *((_s)->pos) = (unsigned char) ((_v) >> 16); \ + (_s)->pos++; \ + *((_s)->pos) = (unsigned char) ((_v) >> 24); \ + (_s)->pos++; \ +} while (0) + +/* list of commands we support; this list should match the one in */ +/* NeutrinoRDP channels/tcutils/tcutils_main.h */ +enum TCU_COMMANDS +{ + TCU_CMD_GET_MOUNT_LIST = 1, + TCU_CMD_UNMOUNT_DEVICE +}; + +/* umount error codes */ +enum TCU_UMOUNT_ERROR +{ + UMOUNT_SUCCESS = 0, + UMOUNT_BUSY, + UMOUNT_NOT_MOUNTED, + UMOUNT_OP_NOT_PERMITTED, + UMOUNT_PERMISSION_DENIED, + UMOUNT_UNKNOWN +}; + +class Utils +{ +public: + Utils(); + static int getMountList(void *wtsChannel, QList<QListWidgetItem *> *itemList); + static int unmountDevice(void *wtsChannel, QString device, QStatusBar *statusBar); +}; + +#endif // UTILS_H diff --git a/tests/memtest/libmem.c b/tests/memtest/libmem.c index 2fa0dea7..f05ea481 100644 --- a/tests/memtest/libmem.c +++ b/tests/memtest/libmem.c @@ -402,3 +402,13 @@ libmem_clear_flags(void* obj, int flags) self->flags &= ~flags; return 0; } + +/*****************************************************************************/ +int +libmem_get_alloced_bytes(void* obj) +{ + struct mem_info* self; + + self = (struct mem_info*)obj; + return self->total_bytes; +} diff --git a/tests/memtest/libmem.h b/tests/memtest/libmem.h index 4bc4b1ec..cd000443 100644 --- a/tests/memtest/libmem.h +++ b/tests/memtest/libmem.h @@ -14,5 +14,7 @@ int libmem_set_flags(void* obj, int flags); int libmem_clear_flags(void* obj, int flags); +int +libmem_get_alloced_bytes(void* obj); #endif diff --git a/xorg/X11R7.6/cleanx.sh b/xorg/X11R7.6/cleanx.sh new file mode 100755 index 00000000..7ec804e0 --- /dev/null +++ b/xorg/X11R7.6/cleanx.sh @@ -0,0 +1,102 @@ +#!/bin/sh +# +# all directories can be read only except +# Read Write +# share/X11/xkb/compiled/ + +if test $# -lt 1 +then + echo "" + echo "usage: clean_build_dir.sh <installation dir>" + echo "" + exit 1 +fi + +BASEDIR=$1 + +if ! test -d $BASEDIR +then + echo "error directory $BASEDIR does not exist" + exit 1 +fi + +if ! test -w $BASEDIR +then + echo "error directory $BASEDIR is not writable" + exit 1 +fi + +echo cleaning $BASEDIR + +if ! test -x $BASEDIR/bin/X11rdp +then + echo "error $BASEDIR/bin/X11rdp does not exist" +fi + +bin_check_file() +{ + if [ "$1" = "X11rdp" ] + then + return 0 + fi + if [ "$1" = "xkbcomp" ] + then + return 0 + fi + rm -f $1 + return 0 +} + +HOLDPATH=$PWD +cd $BASEDIR + +# remove unused directories +rm -fr man/ +rm -fr include/ +rm -fr lib/python2.7/ +rm -fr lib/pkgconfig/ +rm -fr share/pkgconfig/ +rm -fr share/gtk-doc +rm -fr share/doc +rm -fr share/man +rm -fr share/aclocal +rm -fr share/intltool +rm -fr share/util-macros + +# remove development files +rm -f lib/*.a +rm -f lib/*.la +rm -f lib/xorg/modules/*.a +rm -f lib/xorg/modules/*.la + +# remove symbols +#strip lib/*.so +#strip lib/xorg/modules/*.so + +# remove hardware specific files +rm -f lib/dri/i915_dri.so +rm -f lib/dri/i965_dri.so +rm -f lib/dri/mach64_dri.so +rm -f lib/dri/mga_dri.so +rm -f lib/dri/r128_dri.so +rm -f lib/dri/r200_dri.so +rm -f lib/dri/r300_dri.so +rm -f lib/dri/r600_dri.so +rm -f lib/dri/radeon_dri.so +rm -f lib/dri/savage_dri.so +#strip lib/dri/swrast_dri.so +rm -f lib/dri/tdfx_dri.so +rm -f lib/dri/unichrome_dri.so + +# remove extra bin tools +cd bin +for i in * +do + if ! test -d "$i" + then + bin_check_file $i + fi +done +cd .. + +cd $HOLDPATH diff --git a/xorg/X11R7.6/rdp/Makefile b/xorg/X11R7.6/rdp/Makefile index e40b7473..3b84c43c 100644 --- a/xorg/X11R7.6/rdp/Makefile +++ b/xorg/X11R7.6/rdp/Makefile @@ -13,7 +13,7 @@ rdpPolylines.o rdpPolySegment.o rdpFillSpans.o rdpSetSpans.o \ rdpCopyPlane.o rdpPolyPoint.o rdpPolyArc.o rdpFillPolygon.o \ rdpPolyFillArc.o rdpPolyText8.o rdpPolyText16.o \ rdpImageText8.o rdpImageText16.o rdpImageGlyphBlt.o rdpPolyGlyphBlt.o \ -rdpPushPixels.o rdpxv.o \ +rdpPushPixels.o rdpxv.o rdpglyph.o rdpComposite.o \ miinitext.o \ fbcmap_mi.o @@ -43,7 +43,7 @@ LIBS = $(XSRCBASE)/dbe/.libs/libdbe.a \ LLIBS = -Wl,-rpath=$(LIBBASE) -lfreetype -lz -lm -lXfont -lXau \ -lXdmcp -lpixman-1 -lrt -ldl -lcrypto -lGL -lXdamage -CFLAGS = -O2 -Wall -fno-strength-reduce \ +CFLAGS = -g -O2 -Wall -fno-strength-reduce \ -I../../include \ -I../../cfb \ -I../../mfb \ diff --git a/xorg/X11R7.6/rdp/rdp.h b/xorg/X11R7.6/rdp/rdp.h index 6fd7c38a..32d05d6a 100644 --- a/xorg/X11R7.6/rdp/rdp.h +++ b/xorg/X11R7.6/rdp/rdp.h @@ -95,6 +95,23 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define PixelDPI 100 #define PixelToMM(_size) (((_size) * 254 + (PixelDPI) * 5) / ((PixelDPI) * 10)) +#define TAG_COMPOSITE 0 +#define TAG_COPYAREA 1 +#define TAG_POLYFILLRECT 2 +#define TAG_PUTIMAGE 3 +#define TAG_POLYRECTANGLE 4 +#define TAG_COPYPLANE 5 +#define TAG_POLYARC 6 +#define TAG_FILLPOLYGON 7 +#define TAG_POLYFILLARC 8 +#define TAG_IMAGETEXT8 9 +#define TAG_POLYTEXT8 10 +#define TAG_POLYTEXT16 11 +#define TAG_IMAGETEXT16 12 +#define TAG_IMAGEGLYPHBLT 13 +#define TAG_POLYGLYPHBLT 14 +#define TAG_PUSHPIXELS 15 + struct image_data { int width; @@ -103,6 +120,10 @@ struct image_data int Bpp; int lineBytes; char* pixels; + char* shmem_pixels; + int shmem_id; + int shmem_offset; + int shmem_lineBytes; }; /* Per-screen (framebuffer) structure. There is only one of these, since we @@ -114,7 +135,9 @@ struct _rdpScreenInfoRec int height; int depth; int bitsPerPixel; - int sizeInBytes; + int sizeInBytes; /* size of current used frame buffer */ + int sizeInBytesAlloc; /* size of current alloc frame buffer, + always >= sizeInBytes */ char* pfbMemory; Pixel blackPixel; Pixel whitePixel; @@ -142,6 +165,8 @@ struct _rdpScreenInfoRec CopyWindowProcPtr CopyWindow; ClearToBackgroundProcPtr ClearToBackground; ScreenWakeupHandlerProcPtr WakeupHandler; + CreatePictureProcPtr CreatePicture; + DestroyPictureProcPtr DestroyPicture; CompositeProcPtr Composite; GlyphsProcPtr Glyphs; /* Backing store procedures */ @@ -198,6 +223,7 @@ typedef rdpWindowRec* rdpWindowPtr; #define RDI_IMGLY 3 /* lossy */ #define RDI_LINE 4 #define RDI_SCRBLT 5 +#define RDI_TEXT 6 struct urdp_draw_item_fill { @@ -234,17 +260,25 @@ struct urdp_draw_item_scrblt int cy; }; +struct urdp_draw_item_text +{ + int opcode; + int fg_color; + struct rdp_text* rtext; /* in rdpglyph.h */ +}; + union urdp_draw_item { struct urdp_draw_item_fill fill; struct urdp_draw_item_img img; struct urdp_draw_item_line line; struct urdp_draw_item_scrblt scrblt; + struct urdp_draw_item_text text; }; struct rdp_draw_item { - int type; + int type; /* RDI_FILL, RDI_IMGLL, ... */ int flags; struct rdp_draw_item* prev; struct rdp_draw_item* next; @@ -252,6 +286,8 @@ struct rdp_draw_item union urdp_draw_item u; }; +#define XRDP_USE_COUNT_THRESHOLD 1 + struct _rdpPixmapRec { int status; @@ -259,6 +295,11 @@ struct _rdpPixmapRec int con_number; int is_dirty; int is_scratch; + int is_alpha_dirty_not; + /* number of times used in a remote operation + if this gets above XRDP_USE_COUNT_THRESHOLD + then we force remote the pixmap */ + int use_count; int kind_width; struct rdp_draw_item* draw_item_head; struct rdp_draw_item* draw_item_tail; @@ -325,6 +366,8 @@ void hexdump(unsigned char *p, unsigned int len); void RegionAroundSegs(RegionPtr reg, xSegment* segs, int nseg); +int +get_crc(char* data, int data_bytes); /* rdpdraw.c */ Bool @@ -353,6 +396,9 @@ int draw_item_add_srcblt_region(rdpPixmapRec* priv, RegionPtr reg, int srcx, int srcy, int dstx, int dsty, int cx, int cy); +int +draw_item_add_text_region(rdpPixmapRec* priv, RegionPtr reg, int color, + int opcode, struct rdp_text* rtext); PixmapPtr rdpCreatePixmap(ScreenPtr pScreen, int width, int height, int depth, @@ -411,15 +457,19 @@ rdpDisplayCursor(ScreenPtr pScreen, CursorPtr pCursor); void rdpRecolorCursor(ScreenPtr pScreen, CursorPtr pCursor, Bool displayed); + +/* rdpglyph.c */ +/* look in rdpglyph.h */ + +/* rdpComposite.c */ +int +rdpCreatePicture(PicturePtr pPicture); +void +rdpDestroyPicture(PicturePtr pPicture); void rdpComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height); -void -rdpGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst, - PictFormatPtr maskFormat, - INT16 xSrc, INT16 ySrc, int nlists, GlyphListPtr lists, - GlyphPtr* glyphs); /* rdpinput.c */ int @@ -461,6 +511,8 @@ int rdpup_add_os_bitmap(PixmapPtr pixmap, rdpPixmapPtr priv); int rdpup_remove_os_bitmap(int rdpindex); +int +rdpup_update_os_use(int rdpindex); void rdpup_get_screen_image_rect(struct image_data* id); void @@ -504,6 +556,8 @@ rdpup_set_cursor_ex(short x, short y, char *cur_data, char *cur_mask, int bpp); int rdpup_create_os_surface(int rdpindexd, int width, int height); int +rdpup_create_os_surface_bpp(int rdpindexd, int width, int height, int bpp); +int rdpup_switch_os_surface(int rdpindex); int rdpup_delete_os_surface(int rdpindex); @@ -520,7 +574,29 @@ rdpup_delete_window(WindowPtr pWindow, rdpWindowRec* priv); int rdpup_check_dirty(PixmapPtr pDirtyPixmap, rdpPixmapRec* pDirtyPriv); int +rdpup_check_alpha_dirty(PixmapPtr pDirtyPixmap, rdpPixmapRec* pDirtyPriv); +int rdpup_check_dirty_screen(rdpPixmapRec* pDirtyPriv); +int +rdpup_add_char(int font, int charactor, short x, short y, int cx, int cy, + char* bmpdata, int bmpdata_bytes); +int +rdpup_add_char_alpha(int font, int charactor, short x, short y, int cx, int cy, + char* bmpdata, int bmpdata_bytes); +int +rdpup_draw_text(int font, int flags, int mixmode, + short clip_left, short clip_top, + short clip_right, short clip_bottom, + short box_left, short box_top, + short box_right, short box_bottom, short x, short y, + char* data, int data_bytes); +int +rdpup_composite(short srcidx, int srcformat, short srcwidth, CARD8 srcrepeat, + PictTransform* srctransform, CARD8 mskflags, + short mskidx, int mskformat, short mskwidth, CARD8 mskrepeat, + CARD8 op, short srcx, short srcy, short mskx, short msky, + short dstx, short dsty, short width, short height, + int dstformat); void rdpScheduleDeferredUpdate(void); @@ -592,6 +668,13 @@ struct stream #endif /******************************************************************************/ +#define out_uint8(s, v) \ +{ \ + *((s)->p) = (unsigned char)((v) >> 0); \ + (s)->p++; \ +} + +/******************************************************************************/ #define init_stream(s, v) \ { \ if ((v) > (s)->size) \ @@ -619,6 +702,13 @@ struct stream } /******************************************************************************/ +#define out_uint8s(s, n) do \ +{ \ + memset((s)->p, 0, (n)); \ + (s)->p += (n); \ +} while (0) + +/******************************************************************************/ #if defined(B_ENDIAN) || defined(NEED_ALIGN) #define out_uint32_le(s, v) \ { \ diff --git a/xorg/X11R7.6/rdp/rdpComposite.c b/xorg/X11R7.6/rdp/rdpComposite.c new file mode 100644 index 00000000..f763783e --- /dev/null +++ b/xorg/X11R7.6/rdp/rdpComposite.c @@ -0,0 +1,846 @@ +/* + Copyright 2012-2013 Jay Sorg + + Permission to use, copy, modify, distribute, and sell this software and its + documentation for any purpose is hereby granted without fee, provided that + the above copyright notice appear in all copies and that both that + copyright notice and this permission notice appear in supporting + documentation. + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + */ + +#include "rdp.h" +#include "rdpdraw.h" + +#define LDEBUG 0 + +#define LOG_LEVEL 1 +#define LLOG(_level, _args) \ + do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) +#define LLOGLN(_level, _args) \ + do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) + +extern rdpScreenInfoRec g_rdpScreen; /* from rdpmain.c */ +extern DevPrivateKeyRec g_rdpGCIndex; /* from rdpmain.c */ +extern DevPrivateKeyRec g_rdpWindowIndex; /* from rdpmain.c */ +extern DevPrivateKeyRec g_rdpPixmapIndex; /* from rdpmain.c */ +extern int g_Bpp; /* from rdpmain.c */ +extern ScreenPtr g_pScreen; /* from rdpmain.c */ +extern Bool g_wrapPixmap; /* from rdpmain.c */ +extern int g_can_do_pix_to_pix; /* from rdpmain.c */ +extern int g_do_dirty_os; /* in rdpmain.c */ +extern int g_do_dirty_ons; /* in rdpmain.c */ +extern rdpPixmapRec g_screenPriv; /* in rdpmain.c */ +extern int g_do_glyph_cache; /* in rdpmain.c */ +extern int g_doing_font; /* in rdpmain.c */ +extern int g_do_composite; /* in rdpmain.c */ + +extern GCOps g_rdpGCOps; /* from rdpdraw.c */ + +extern int g_con_number; /* in rdpup.c */ + +extern int g_crc_seed; /* in rdpmisc.c */ +extern int g_crc_table[]; /* in rdpmisc.c */ + +/******************************************************************************/ +int +rdpCreatePicture(PicturePtr pPicture) +{ + PictureScreenPtr ps; + int rv; + + LLOGLN(10, ("rdpCreatePicture:")); + ps = GetPictureScreen(g_pScreen); + ps->CreatePicture = g_rdpScreen.CreatePicture; + rv = ps->CreatePicture(pPicture); + ps->CreatePicture = rdpCreatePicture; + return rv; +} + +/******************************************************************************/ +void +rdpDestroyPicture(PicturePtr pPicture) +{ + PictureScreenPtr ps; + + LLOGLN(10, ("rdpDestroyPicture:")); + ps = GetPictureScreen(g_pScreen); + ps->DestroyPicture = g_rdpScreen.DestroyPicture; + ps->DestroyPicture(pPicture); + ps->DestroyPicture = rdpDestroyPicture; +} + +/******************************************************************************/ +static int +print_format(PictFormatShort format) +{ + switch (format) + { + case PIXMAN_a2r10g10b10: + LLOGLN(0, (" PIXMAN_x2r10g10b10")); + break; + case PIXMAN_x2r10g10b10: + LLOGLN(0, (" PIXMAN_x2r10g10b10")); + break; + case PIXMAN_a2b10g10r10: + LLOGLN(0, (" PIXMAN_a2b10g10r10")); + break; + case PIXMAN_x2b10g10r10: + LLOGLN(0, (" PIXMAN_x2b10g10r10")); + break; + + case PIXMAN_a8r8g8b8: + LLOGLN(0, (" PIXMAN_a8r8g8b8")); + break; + case PIXMAN_x8r8g8b8: + LLOGLN(0, (" PIXMAN_x8r8g8b8")); + break; + case PIXMAN_a8b8g8r8: + LLOGLN(0, (" PIXMAN_a8b8g8r8")); + break; + case PIXMAN_x8b8g8r8: + LLOGLN(0, (" PIXMAN_x8b8g8r8")); + break; + case PIXMAN_b8g8r8a8: + LLOGLN(0, (" PIXMAN_b8g8r8a8")); + break; + case PIXMAN_b8g8r8x8: + LLOGLN(0, (" PIXMAN_b8g8r8x8")); + break; + + /* 24bpp formats */ + case PIXMAN_r8g8b8: + LLOGLN(0, (" PIXMAN_r8g8b8")); + break; + case PIXMAN_b8g8r8: + LLOGLN(0, (" PIXMAN_b8g8r8")); + break; + + /* 16bpp formats */ + case PIXMAN_r5g6b5: + LLOGLN(0, (" PIXMAN_r5g6b5")); + break; + case PIXMAN_b5g6r5: + LLOGLN(0, (" PIXMAN_b5g6r5")); + break; + + case PIXMAN_a1r5g5b5: + LLOGLN(0, (" PIXMAN_a1r5g5b5")); + break; + case PIXMAN_x1r5g5b5: + LLOGLN(0, (" PIXMAN_x1r5g5b5")); + break; + case PIXMAN_a1b5g5r5: + LLOGLN(0, (" PIXMAN_a1b5g5r5")); + break; + case PIXMAN_x1b5g5r5: + LLOGLN(0, (" PIXMAN_x1b5g5r5")); + break; + case PIXMAN_a4r4g4b4: + LLOGLN(0, (" PIXMAN_a4r4g4b4")); + break; + case PIXMAN_x4r4g4b4: + LLOGLN(0, (" PIXMAN_x4r4g4b4")); + break; + case PIXMAN_a4b4g4r4: + LLOGLN(0, (" PIXMAN_a4b4g4r4")); + break; + case PIXMAN_x4b4g4r4: + LLOGLN(0, (" PIXMAN_x4b4g4r4")); + break; + + /* 8bpp formats */ + case PIXMAN_a8: + LLOGLN(0, (" PIXMAN_a8")); + break; + case PIXMAN_r3g3b2: + LLOGLN(0, (" PIXMAN_r3g3b2")); + break; + case PIXMAN_b2g3r3: + LLOGLN(0, (" PIXMAN_b2g3r3")); + break; + case PIXMAN_a2r2g2b2: + LLOGLN(0, (" PIXMAN_a2r2g2b2")); + break; + case PIXMAN_a2b2g2r2: + LLOGLN(0, (" PIXMAN_a2b2g2r2")); + break; + + case PIXMAN_c8: + LLOGLN(0, (" PIXMAN_c8")); + break; + case PIXMAN_g8: + LLOGLN(0, (" PIXMAN_g8")); + break; + + case PIXMAN_x4a4: + LLOGLN(0, (" PIXMAN_x4a4")); + break; + + /* 4bpp formats */ + case PIXMAN_a4: + LLOGLN(0, (" PIXMAN_a4")); + break; + case PIXMAN_r1g2b1: + LLOGLN(0, (" PIXMAN_r1g2b1")); + break; + case PIXMAN_b1g2r1: + LLOGLN(0, (" PIXMAN_b1g2r1")); + break; + case PIXMAN_a1r1g1b1: + LLOGLN(0, (" PIXMAN_a1r1g1b1")); + break; + case PIXMAN_a1b1g1r1: + LLOGLN(0, (" PIXMAN_a1b1g1r1")); + break; + + case PIXMAN_c4: + LLOGLN(0, (" PIXMAN_c4")); + break; + case PIXMAN_g4: + LLOGLN(0, (" PIXMAN_g4")); + break; + + /* 1bpp formats */ + case PIXMAN_a1: + LLOGLN(0, (" PIXMAN_a1")); + break; + case PIXMAN_g1: + LLOGLN(0, (" PIXMAN_g1")); + break; + } + return 0; +} + +/******************************************************************************/ +static int +compsoite_print(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, + INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask, INT16 xDst, + INT16 yDst, CARD16 width, CARD16 height) +{ + PixmapPtr pSrcPixmap; + PixmapPtr pDstPixmap; + rdpPixmapRec* pSrcPriv; + rdpPixmapRec* pDstPriv; + + LLOGLN(0, ("compsoite_print: op %d xSrc %d ySrc %d xDst %d yDst %d " + "width %d height %d", + op, xSrc, ySrc, xDst, yDst, width, height)); + + if (pSrc != 0) + { + LLOGLN(0, (" src depth %d width %d height %d repeat %d repeatType %d " + "dither %d filter %d alphaMap %p componentAlpha %d", pSrc->pDrawable->depth, + pSrc->pDrawable->width, pSrc->pDrawable->height, + pSrc->repeat, pSrc->repeatType, pSrc->dither, pSrc->filter, + pSrc->alphaMap, pSrc->componentAlpha)); + LLOGLN(0, (" transform %p", pSrc->transform)); + LLOGLN(0, (" detail format red %d red mask %d green %d green mask %d " + "blue %d blue mask %d", + pSrc->pFormat->direct.red, pSrc->pFormat->direct.redMask, + pSrc->pFormat->direct.green, pSrc->pFormat->direct.greenMask, + pSrc->pFormat->direct.blue, pSrc->pFormat->direct.blueMask)); + print_format(pSrc->format); + if (pSrc->pDrawable->type == DRAWABLE_PIXMAP) + { + pSrcPixmap = (PixmapPtr)(pSrc->pDrawable); + pSrcPriv = GETPIXPRIV(pSrcPixmap); + LLOGLN(0, (" DRAWABLE_PIXMAP pSrcPriv %p status %d", pSrcPriv, pSrcPriv->status)); + } + else if (pSrc->pDrawable->type == DRAWABLE_WINDOW) + { + LLOGLN(0, (" DRAWABLE_WINDOW")); + } + else + { + LLOGLN(0, (" OTHER")); + } + } + if (pMask != 0) + { + LLOGLN(0, (" msk depth %d width %d height %d repeat %d repeatType %d", + pMask->pDrawable->depth, + pMask->pDrawable->width, + pMask->pDrawable->height, pMask->repeat, pMask->repeatType)); + print_format(pMask->format); + } + if (pDst != 0) + { + LLOGLN(0, (" dst depth %d width %d height %d repeat %d repeatType %d " + "dither %d filter %d alphaMap %p", pDst->pDrawable->depth, + pDst->pDrawable->width, pDst->pDrawable->height, + pDst->repeat, pDst->repeatType, pDst->dither, pDst->filter, + pDst->alphaMap)); + LLOGLN(0, (" transform %p", pDst->transform)); + print_format(pDst->format); + if (pDst->pDrawable->type == DRAWABLE_PIXMAP) + { + pDstPixmap = (PixmapPtr)(pDst->pDrawable); + pDstPriv = GETPIXPRIV(pDstPixmap); + LLOGLN(0, (" DRAWABLE_PIXMAP pDstPriv %p status %d", pDstPriv, pDstPriv->status)); + } + else if (pDst->pDrawable->type == DRAWABLE_WINDOW) + { + LLOGLN(0, (" DRAWABLE_WINDOW")); + } + else + { + LLOGLN(0, (" OTHER")); + } + } + return 0; +} + +/******************************************************************************/ +static int +src_alpha_needed(CARD8 op) +{ + int rv; + + rv = 0; + switch (op) + { + case 3: /* Over */ + case 6: /* InReverse */ + case 8: /* OutReverse */ + case 9: /* Atop */ + case 10: /* AtopReverse */ + case 11: /* Xor */ + case 13: /* Saturate */ + case 17: /* DisjointOver */ + case 18: /* DisjointOverReverse */ + case 19: /* DisjointIn */ + case 20: /* DisjointInReverse */ + case 21: /* DisjointOut */ + case 22: /* DisjointOutReverse */ + case 23: /* DisjointAtop */ + case 24: /* DisjointAtopReverse */ + case 25: /* DisjointXor */ + case 29: /* ConjointOver */ + case 30: /* ConjointOverReverse */ + case 31: /* ConjointIn */ + case 32: /* ConjointInReverse */ + case 33: /* ConjointOut */ + case 34: /* ConjointOutReverse */ + case 35: /* ConjointAtop */ + case 36: /* ConjointAtopReverse */ + case 37: /* ConjointXor */ + rv = 1; + break; + } + return rv; +} + +/******************************************************************************/ +static int +dst_alpha_needed(CARD8 op) +{ + int rv; + + rv = 0; + switch (op) + { + case 4: /* OverReverse */ + case 5: /* In */ + case 7: /* Out */ + case 9: /* Atop */ + case 10: /* AtopReverse */ + case 11: /* Xor */ + case 13: /* Saturate */ + case 17: /* DisjointOver */ + case 18: /* DisjointOverReverse */ + case 19: /* DisjointIn */ + case 20: /* DisjointInReverse */ + case 21: /* DisjointOut */ + case 22: /* DisjointOutReverse */ + case 23: /* DisjointAtop */ + case 24: /* DisjointAtopReverse */ + case 25: /* DisjointXor */ + case 29: /* ConjointOver */ + case 30: /* ConjointOverReverse */ + case 31: /* ConjointIn */ + case 32: /* ConjointInReverse */ + case 33: /* ConjointOut */ + case 34: /* ConjointOutReverse */ + case 35: /* ConjointAtop */ + case 36: /* ConjointAtopReverse */ + case 37: /* ConjointXor */ + rv = 1; + break; + } + return rv; +} + +struct msk_info +{ + int flags; + int idx; + int format; + int width; + int repeat; +}; + +static char g_com_fail_strings[][128] = +{ + "OK", + "src not remotable", + "dst not remotable", + "msk not remotable" +}; + +/******************************************************************************/ +/* returns boolean */ +static int +check_drawables(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, + INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask, INT16 xDst, + INT16 yDst, CARD16 width, CARD16 height, struct msk_info* msk) +{ + int rv; + int fail_reason; + PixmapPtr pSrcPixmap; + PixmapPtr pDstPixmap; + PixmapPtr pMskPixmap; + rdpPixmapRec* pSrcPriv; + rdpPixmapRec* pDstPriv; + rdpPixmapRec* pMskPriv; + + fail_reason = 0; + pSrcPixmap = 0; + pDstPixmap = 0; + pMskPixmap = 0; + pSrcPriv = 0; + pDstPriv = 0; + pMskPriv = 0; + rv = 0; + if (pSrc != 0) + { + if (pSrc->pDrawable != 0) + { + if (pSrc->pDrawable->type == DRAWABLE_PIXMAP) + { + pSrcPixmap = (PixmapPtr)(pSrc->pDrawable); + pSrcPriv = GETPIXPRIV(pSrcPixmap); + if (xrdp_is_os(pSrcPixmap, pSrcPriv)) + { + if (pDst != 0) + { + if (pDst->pDrawable != 0) + { + if (pDst->pDrawable->type == DRAWABLE_PIXMAP) + { + pDstPixmap = (PixmapPtr)(pDst->pDrawable); + pDstPriv = GETPIXPRIV(pDstPixmap); + if (xrdp_is_os(pDstPixmap, pDstPriv)) + { + rv = 1; + } + else + { + fail_reason = 2; + } + } + } + } + } + else + { + fail_reason = 1; + } + } + } + } + if (rv) + { + if (pMask != 0) + { +#if 1 + rv = 0; + if (pMask->pDrawable != 0) + { + if (pMask->pDrawable->type == DRAWABLE_PIXMAP) + { + pMskPixmap = (PixmapPtr)(pMask->pDrawable); + pMskPriv = GETPIXPRIV(pMskPixmap); + if (xrdp_is_os(pMskPixmap, pMskPriv)) + { + rv = 1; + msk->flags = 1; + msk->idx = pMskPriv->rdpindex; + msk->format = pMask->format; + msk->width = pMask->pDrawable->width; + msk->repeat = pMask->repeatType; + } + else + { + fail_reason = 3; + } + } + } +#endif + } + } + if (rv == 0) + { + LLOGLN(10, ("check_drawables: can not remote [%s]", g_com_fail_strings[fail_reason])); +#if 0 + compsoite_print(op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, + xDst, yDst, width, height); +#endif + } + else + { + LLOGLN(10, ("check_drawables: can remote [%s]", g_com_fail_strings[fail_reason])); +#if 0 + compsoite_print(op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, + xDst, yDst, width, height); +#endif + } + return rv; +} + +/******************************************************************************/ +static int +rdpRemoteComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, + INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask, INT16 xDst, + INT16 yDst, CARD16 width, CARD16 height) +{ + int ok_to_remote; + PixmapPtr pSrcPixmap; + PixmapPtr pMskPixmap; + PixmapPtr pDstPixmap; + rdpPixmapRec* pSrcPriv; + rdpPixmapRec* pMskPriv; + rdpPixmapRec* pDstPriv; + BoxRec box; + RegionRec reg1; + RegionRec reg2; + DrawablePtr p; + int j; + int num_clips; + struct msk_info msk; + + LLOGLN(10, ("rdpRemoteComposite:")); + + memset(&msk, 0, sizeof(msk)); + ok_to_remote = check_drawables(op, pSrc, pMask, pDst, xSrc, ySrc, + xMask, yMask, xDst, yDst, width, height, + &msk); + if (!ok_to_remote) + { + return 1; + } + + ValidatePicture(pSrc); + pSrcPixmap = (PixmapPtr)(pSrc->pDrawable); + pSrcPriv = GETPIXPRIV(pSrcPixmap); + rdpup_check_dirty(pSrcPixmap, pSrcPriv); + if (PIXMAN_FORMAT_A(pSrc->format) > 0) + { + if (src_alpha_needed(op)) + { + rdpup_check_alpha_dirty(pSrcPixmap, pSrcPriv); + } + } + + ValidatePicture(pDst); + pDstPixmap = (PixmapPtr)(pDst->pDrawable); + pDstPriv = GETPIXPRIV(pDstPixmap); + rdpup_check_dirty(pDstPixmap, pDstPriv); + + if (PIXMAN_FORMAT_A(pDst->format) > 0) + { + if (dst_alpha_needed(op)) + { + rdpup_check_alpha_dirty(pDstPixmap, pDstPriv); + } + } + + if (pMask != 0) + { + ValidatePicture(pMask); + pMskPixmap = (PixmapPtr)(pMask->pDrawable); + pMskPriv = GETPIXPRIV(pMskPixmap); + rdpup_check_dirty(pMskPixmap, pMskPriv); + if (PIXMAN_FORMAT_A(msk.format) > 0) + { + rdpup_check_alpha_dirty(pMskPixmap, pMskPriv); + } + } + + p = pDst->pDrawable; + rdpup_switch_os_surface(pDstPriv->rdpindex); + if (pDst->pCompositeClip != 0) + { + box.x1 = xDst; + box.y1 = yDst; + box.x2 = box.x1 + width; + box.y2 = box.y1 + height; + RegionInit(®1, &box, 0); + RegionInit(®2, NullBox, 0); + RegionCopy(®2, pDst->pCompositeClip); + RegionIntersect(®1, ®1, ®2); + RegionTranslate(®1, p->x, p->y); + num_clips = REGION_NUM_RECTS(®1); + if (num_clips > 0) + { + LLOGLN(10, ("num_clips %d", num_clips)); + rdpup_begin_update(); + for (j = num_clips - 1; j >= 0; j--) + { + box = REGION_RECTS(®1)[j]; + rdpup_set_clip(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + LLOGLN(10, ("pSrc->format 0x%x 0x%x 0x%x %d %d %d %d %d %d %d %d", + pSrc->format, msk.format, pDst->format, xSrc, ySrc, + xMask, yMask, xDst, yDst, width, height)); + rdpup_composite(pSrcPriv->rdpindex, pSrc->format, + pSrc->pDrawable->width, pSrc->repeatType, + pSrc->transform, msk.flags, msk.idx, msk.format, + msk.width, msk.repeat, op, xSrc, ySrc, + xMask, yMask, xDst, yDst, width, height, pDst->format); + } + rdpup_reset_clip(); + rdpup_end_update(); + } + RegionUninit(®1); + RegionUninit(®2); + } + else + { + rdpup_begin_update(); + rdpup_composite(pSrcPriv->rdpindex, pSrc->format, + pSrc->pDrawable->width, pSrc->repeatType, + pSrc->transform, msk.flags, msk.idx, msk.format, + msk.width, msk.repeat, op, xSrc, ySrc, + xMask, yMask, xDst, yDst, width, height, pDst->format); + rdpup_end_update(); + } + rdpup_switch_os_surface(-1); + + return 0; +} + +/******************************************************************************/ +static void +rdpCompositeOrg(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, + INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask, INT16 xDst, + INT16 yDst, CARD16 width, CARD16 height) +{ + PictureScreenPtr ps; + + ps = GetPictureScreen(g_pScreen); + ps->Composite = g_rdpScreen.Composite; + ps->Composite(op, pSrc, pMask, pDst, xSrc, ySrc, + xMask, yMask, xDst, yDst, width, height); + ps->Composite = rdpComposite; +} + +/******************************************************************************/ +/* it looks like all the antialias draws go through here + op is one of the following + #define PictOpMinimum 0 + #define PictOpClear 0 + #define PictOpSrc 1 + #define PictOpDst 2 + #define PictOpOver 3 + #define PictOpOverReverse 4 + #define PictOpIn 5 + #define PictOpInReverse 6 + #define PictOpOut 7 + #define PictOpOutReverse 8 + #define PictOpAtop 9 + #define PictOpAtopReverse 10 + #define PictOpXor 11 + #define PictOpAdd 12 + #define PictOpSaturate 13 + #define PictOpMaximum 13 + + see for porter duff + http://www.svgopen.org/2005/papers/abstractsvgopen/ + + */ +void +rdpComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, + INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask, INT16 xDst, + INT16 yDst, CARD16 width, CARD16 height) +{ + BoxRec box; + RegionRec reg1; + RegionRec reg2; + DrawablePtr p; + int dirty_type; + int j; + int num_clips; + int post_process; + int reset_surface; + int got_id; + WindowPtr pDstWnd; + PixmapPtr pDstPixmap; + rdpPixmapRec* pDstPriv; + rdpPixmapRec* pDirtyPriv; + struct image_data id; + + LLOGLN(10, ("rdpComposite:")); + + if (g_doing_font == 2) + { + rdpCompositeOrg(op, pSrc, pMask, pDst, xSrc, ySrc, + xMask, yMask, xDst, yDst, width, height); + + return; + } + +#if 0 + if (g_do_glyph_cache && g_do_alpha_glyphs) + { + if (pSrc->pDrawable->width == 1 && + pSrc->pDrawable->height == 1) + { + if (pMask != 0) + { + /* TODO: here we can try to send it as a gylph */ + } + } + } +#endif + + /* try to remote the composite call */ + if (g_do_composite && + rdpRemoteComposite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, + xDst, yDst, width, height) == 0) + { + rdpCompositeOrg(op, pSrc, pMask, pDst, xSrc, ySrc, + xMask, yMask, xDst, yDst, width, height); + return; + } + + rdpCompositeOrg(op, pSrc, pMask, pDst, xSrc, ySrc, + xMask, yMask, xDst, yDst, width, height); + + LLOGLN(10, ("rdpComposite: op %d %p %p %p w %d h %d", op, pSrc, pMask, pDst, width, height)); + + p = pDst->pDrawable; + + pDstPriv = 0; + dirty_type = 0; + pDirtyPriv = 0; + post_process = 0; + reset_surface = 0; + got_id = 0; + if (p->type == DRAWABLE_PIXMAP) + { + pDstPixmap = (PixmapPtr)p; + pDstPriv = GETPIXPRIV(pDstPixmap); + if (XRDP_IS_OS(pDstPriv)) + { + post_process = 1; + if (g_do_dirty_os) + { + LLOGLN(10, ("rdpComposite: gettig dirty")); + pDstPriv->is_dirty = 1; + dirty_type = g_doing_font ? RDI_IMGLL : RDI_IMGLY; + pDirtyPriv = pDstPriv; + } + else + { + rdpup_switch_os_surface(pDstPriv->rdpindex); + reset_surface = 1; + rdpup_get_pixmap_image_rect(pDstPixmap, &id); + got_id = 1; + LLOGLN(10, ("rdpComposite: offscreen")); + } + } + } + else + { + if (p->type == DRAWABLE_WINDOW) + { + pDstWnd = (WindowPtr)p; + if (pDstWnd->viewable) + { + post_process = 1; + if (g_do_dirty_ons) + { + LLOGLN(10, ("rdpComposite: getting dirty")); + g_screenPriv.is_dirty = 1; + pDirtyPriv = &g_screenPriv; + dirty_type = g_doing_font ? RDI_IMGLL : RDI_IMGLY; + } + else + { + rdpup_get_screen_image_rect(&id); + got_id = 1; + } + } + } + } + + if (!post_process) + { + return; + } + + if (pDst->pCompositeClip != 0) + { + box.x1 = p->x + xDst; + box.y1 = p->y + yDst; + box.x2 = box.x1 + width; + box.y2 = box.y1 + height; + RegionInit(®1, &box, 0); + RegionInit(®2, NullBox, 0); + RegionCopy(®2, pDst->pCompositeClip); + RegionIntersect(®1, ®1, ®2); + if (dirty_type != 0) + { + draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type, TAG_COMPOSITE); + } + else if (got_id) + { + num_clips = REGION_NUM_RECTS(®1); + if (num_clips > 0) + { + rdpup_begin_update(); + for (j = num_clips - 1; j >= 0; j--) + { + box = REGION_RECTS(®1)[j]; + rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + } + rdpup_end_update(); + } + } + RegionUninit(®1); + RegionUninit(®2); + } + else + { + box.x1 = p->x + xDst; + box.y1 = p->y + yDst; + box.x2 = box.x1 + width; + box.y2 = box.y1 + height; + if (dirty_type != 0) + { + RegionInit(®1, &box, 0); + draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type, TAG_COMPOSITE); + RegionUninit(®1); + } + else if (got_id) + { + rdpup_begin_update(); + rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + rdpup_end_update(); + } + } + if (reset_surface) + { + rdpup_switch_os_surface(-1); + } +} diff --git a/xorg/X11R7.6/rdp/rdpCopyArea.c b/xorg/X11R7.6/rdp/rdpCopyArea.c index a97aaf56..4718a89c 100644 --- a/xorg/X11R7.6/rdp/rdpCopyArea.c +++ b/xorg/X11R7.6/rdp/rdpCopyArea.c @@ -429,6 +429,8 @@ rdpCopyArea(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, pSrcPixmap = (PixmapPtr)pSrc; pSrcPriv = GETPIXPRIV(pSrcPixmap); + LLOGLN(10, ("rdpCopyArea: 3 %d %d", pSrcPixmap->usage_hint, pSrcPriv->is_scratch)); + if (xrdp_is_os(pSrcPixmap, pSrcPriv)) { if (pDst->type == DRAWABLE_WINDOW) @@ -468,10 +470,12 @@ rdpCopyArea(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, } else { - LLOGLN(10, ("rdpCopyArea: 2")); + LLOGLN(10, ("rdpCopyArea: 2 %d %d", pSrcPixmap->usage_hint, pSrcPriv->is_scratch)); } } + LLOGLN(10, ("rdpCopyArea: fallback")); + /* do original call */ rv = rdpCopyAreaOrg(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty); @@ -492,10 +496,10 @@ rdpCopyArea(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, if (g_do_dirty_os) { - LLOGLN(10, ("rdpCopyArea: gettig dirty")); + LLOGLN(10, ("rdpCopyArea: getting dirty")); pDstPriv->is_dirty = 1; pDirtyPriv = pDstPriv; - dirty_type = RDI_IMGLL; + dirty_type = RDI_IMGLY; } else { @@ -522,10 +526,10 @@ rdpCopyArea(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, if (g_do_dirty_ons) { - LLOGLN(10, ("rdpCopyArea: gettig dirty")); + LLOGLN(10, ("rdpCopyArea: getting dirty")); g_screenPriv.is_dirty = 1; pDirtyPriv = &g_screenPriv; - dirty_type = RDI_IMGLL; + dirty_type = RDI_IMGLY; } else { @@ -541,6 +545,8 @@ rdpCopyArea(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, return rv; } + LLOGLN(10, ("rdpCopyArea: post_process")); + RegionInit(&clip_reg, NullBox, 0); cd = rdp_get_clip(&clip_reg, pDst, pGC); @@ -553,7 +559,7 @@ rdpCopyArea(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, box.x2 = box.x1 + w; box.y2 = box.y1 + h; RegionInit(®1, &box, 0); - draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type, 1); + draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type, TAG_COPYAREA); RegionUninit(®1); } else if (got_id) @@ -577,7 +583,7 @@ rdpCopyArea(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, box.y2 = box.y1 + h; RegionInit(&box_reg, &box, 0); RegionIntersect(&clip_reg, &clip_reg, &box_reg); - draw_item_add_img_region(pDirtyPriv, &clip_reg, GXcopy, dirty_type, 1); + draw_item_add_img_region(pDirtyPriv, &clip_reg, GXcopy, dirty_type, TAG_COPYAREA); RegionUninit(&box_reg); } else if (got_id) diff --git a/xorg/X11R7.6/rdp/rdpCopyPlane.c b/xorg/X11R7.6/rdp/rdpCopyPlane.c index aac03287..063766ee 100644 --- a/xorg/X11R7.6/rdp/rdpCopyPlane.c +++ b/xorg/X11R7.6/rdp/rdpCopyPlane.c @@ -111,7 +111,7 @@ rdpCopyPlane(DrawablePtr pSrc, DrawablePtr pDst, if (g_do_dirty_os) { - LLOGLN(10, ("rdpCopyPlane: gettig dirty")); + LLOGLN(10, ("rdpCopyPlane: getting dirty")); pDstPriv->is_dirty = 1; pDirtyPriv = pDstPriv; dirty_type = RDI_IMGLL; @@ -137,7 +137,7 @@ rdpCopyPlane(DrawablePtr pSrc, DrawablePtr pDst, if (g_do_dirty_ons) { - LLOGLN(0, ("rdpCopyPlane: gettig dirty")); + LLOGLN(10, ("rdpCopyPlane: getting dirty")); g_screenPriv.is_dirty = 1; pDirtyPriv = &g_screenPriv; dirty_type = RDI_IMGLL; @@ -168,7 +168,7 @@ rdpCopyPlane(DrawablePtr pSrc, DrawablePtr pDst, box.x2 = box.x1 + w; box.y2 = box.y1 + h; RegionInit(®1, &box, 0); - draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type, 5); + draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type, TAG_COPYPLANE); RegionUninit(®1); } else if (got_id) @@ -194,7 +194,7 @@ rdpCopyPlane(DrawablePtr pSrc, DrawablePtr pDst, RegionInit(®2, NullBox, 0); RegionCopy(®2, &clip_reg); RegionIntersect(®1, ®1, ®2); - draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type, 5); + draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type, TAG_COPYPLANE); RegionUninit(®1); RegionUninit(®2); } diff --git a/xorg/X11R7.6/rdp/rdpFillPolygon.c b/xorg/X11R7.6/rdp/rdpFillPolygon.c index 4c54f447..960f619e 100644 --- a/xorg/X11R7.6/rdp/rdpFillPolygon.c +++ b/xorg/X11R7.6/rdp/rdpFillPolygon.c @@ -150,7 +150,7 @@ rdpFillPolygon(DrawablePtr pDrawable, GCPtr pGC, if (g_do_dirty_os) { - LLOGLN(10, ("rdpFillPolygon: gettig dirty")); + LLOGLN(10, ("rdpFillPolygon: getting dirty")); pDstPriv->is_dirty = 1; pDirtyPriv = pDstPriv; dirty_type = RDI_IMGLL; @@ -176,7 +176,7 @@ rdpFillPolygon(DrawablePtr pDrawable, GCPtr pGC, if (g_do_dirty_ons) { - LLOGLN(0, ("rdpFillPolygon: gettig dirty")); + LLOGLN(10, ("rdpFillPolygon: getting dirty")); g_screenPriv.is_dirty = 1; pDirtyPriv = &g_screenPriv; dirty_type = RDI_IMGLL; @@ -203,7 +203,7 @@ rdpFillPolygon(DrawablePtr pDrawable, GCPtr pGC, if (dirty_type != 0) { RegionInit(®1, &box, 0); - draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type, 7); + draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type, TAG_FILLPOLYGON); RegionUninit(®1); } else if (got_id) @@ -223,7 +223,7 @@ rdpFillPolygon(DrawablePtr pDrawable, GCPtr pGC, { if (dirty_type != 0) { - draw_item_add_img_region(pDirtyPriv, &clip_reg, GXcopy, dirty_type, 7); + draw_item_add_img_region(pDirtyPriv, &clip_reg, GXcopy, dirty_type, TAG_FILLPOLYGON); } else if (got_id) { diff --git a/xorg/X11R7.6/rdp/rdpImageGlyphBlt.c b/xorg/X11R7.6/rdp/rdpImageGlyphBlt.c index c5fcfaa7..d425a30b 100644 --- a/xorg/X11R7.6/rdp/rdpImageGlyphBlt.c +++ b/xorg/X11R7.6/rdp/rdpImageGlyphBlt.c @@ -108,7 +108,7 @@ rdpImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, if (g_do_dirty_os) { - LLOGLN(10, ("rdpImageGlyphBlt: gettig dirty")); + LLOGLN(10, ("rdpImageGlyphBlt: getting dirty")); pDstPriv->is_dirty = 1; pDirtyPriv = pDstPriv; dirty_type = RDI_IMGLL; @@ -134,7 +134,7 @@ rdpImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, if (g_do_dirty_ons) { - LLOGLN(0, ("rdpImageGlyphBlt: gettig dirty")); + LLOGLN(10, ("rdpImageGlyphBlt: getting dirty")); g_screenPriv.is_dirty = 1; pDirtyPriv = &g_screenPriv; dirty_type = RDI_IMGLL; @@ -169,7 +169,7 @@ rdpImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, if (dirty_type != 0) { RegionInit(®1, &box, 0); - draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type, 13); + draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type, TAG_IMAGEGLYPHBLT); RegionUninit(®1); } else if (got_id) @@ -189,7 +189,7 @@ rdpImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, { if (dirty_type != 0) { - draw_item_add_img_region(pDirtyPriv, ®, GXcopy, dirty_type, 13); + draw_item_add_img_region(pDirtyPriv, ®, GXcopy, dirty_type, TAG_IMAGEGLYPHBLT); } else if (got_id) { diff --git a/xorg/X11R7.6/rdp/rdpImageText16.c b/xorg/X11R7.6/rdp/rdpImageText16.c index e6048095..604d85e3 100644 --- a/xorg/X11R7.6/rdp/rdpImageText16.c +++ b/xorg/X11R7.6/rdp/rdpImageText16.c @@ -106,7 +106,7 @@ rdpImageText16(DrawablePtr pDrawable, GCPtr pGC, if (g_do_dirty_os) { - LLOGLN(10, ("rdpImageText16: gettig dirty")); + LLOGLN(10, ("rdpImageText16: getting dirty")); pDstPriv->is_dirty = 1; pDirtyPriv = pDstPriv; dirty_type = RDI_IMGLY; @@ -132,7 +132,7 @@ rdpImageText16(DrawablePtr pDrawable, GCPtr pGC, if (g_do_dirty_ons) { - LLOGLN(10, ("rdpImageText16: gettig dirty")); + LLOGLN(10, ("rdpImageText16: getting dirty")); g_screenPriv.is_dirty = 1; pDirtyPriv = &g_screenPriv; dirty_type = RDI_IMGLL; @@ -167,7 +167,7 @@ rdpImageText16(DrawablePtr pDrawable, GCPtr pGC, if (dirty_type != 0) { RegionInit(®1, &box, 0); - draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type, 12); + draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type, TAG_IMAGETEXT16); RegionUninit(®1); } else if (got_id) @@ -187,7 +187,7 @@ rdpImageText16(DrawablePtr pDrawable, GCPtr pGC, { if (dirty_type != 0) { - draw_item_add_img_region(pDirtyPriv, ®, GXcopy, dirty_type, 12); + draw_item_add_img_region(pDirtyPriv, ®, GXcopy, dirty_type, TAG_IMAGETEXT16); } else if (got_id) { diff --git a/xorg/X11R7.6/rdp/rdpImageText8.c b/xorg/X11R7.6/rdp/rdpImageText8.c index 641637e0..08dead18 100644 --- a/xorg/X11R7.6/rdp/rdpImageText8.c +++ b/xorg/X11R7.6/rdp/rdpImageText8.c @@ -106,7 +106,7 @@ rdpImageText8(DrawablePtr pDrawable, GCPtr pGC, if (g_do_dirty_os) { - LLOGLN(10, ("rdpImageText8: gettig dirty")); + LLOGLN(10, ("rdpImageText8: getting dirty")); pDstPriv->is_dirty = 1; pDirtyPriv = pDstPriv; dirty_type = RDI_IMGLL; @@ -132,7 +132,7 @@ rdpImageText8(DrawablePtr pDrawable, GCPtr pGC, if (g_do_dirty_ons) { - LLOGLN(0, ("rdpImageText8: gettig dirty")); + LLOGLN(10, ("rdpImageText8: getting dirty")); g_screenPriv.is_dirty = 1; pDirtyPriv = &g_screenPriv; dirty_type = RDI_IMGLL; @@ -167,7 +167,7 @@ rdpImageText8(DrawablePtr pDrawable, GCPtr pGC, if (dirty_type != 0) { RegionInit(®1, &box, 0); - draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type, 9); + draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type, TAG_IMAGETEXT8); RegionUninit(®1); } else if (got_id) @@ -187,7 +187,7 @@ rdpImageText8(DrawablePtr pDrawable, GCPtr pGC, { if (dirty_type != 0) { - draw_item_add_img_region(pDirtyPriv, ®, GXcopy, dirty_type, 9); + draw_item_add_img_region(pDirtyPriv, ®, GXcopy, dirty_type, TAG_IMAGETEXT8); } else if (got_id) { diff --git a/xorg/X11R7.6/rdp/rdpPolyArc.c b/xorg/X11R7.6/rdp/rdpPolyArc.c index 6d6651f1..84a85587 100644 --- a/xorg/X11R7.6/rdp/rdpPolyArc.c +++ b/xorg/X11R7.6/rdp/rdpPolyArc.c @@ -125,7 +125,7 @@ rdpPolyArc(DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc *parcs) if (g_do_dirty_os) { - LLOGLN(10, ("rdpPolyArc: gettig dirty")); + LLOGLN(10, ("rdpPolyArc: getting dirty")); pDstPriv->is_dirty = 1; pDirtyPriv = pDstPriv; dirty_type = RDI_IMGLL; @@ -151,7 +151,7 @@ rdpPolyArc(DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc *parcs) if (g_do_dirty_ons) { - LLOGLN(0, ("rdpPolyArc: gettig dirty")); + LLOGLN(10, ("rdpPolyArc: getting dirty")); g_screenPriv.is_dirty = 1; pDirtyPriv = &g_screenPriv; dirty_type = RDI_IMGLL; @@ -185,7 +185,7 @@ rdpPolyArc(DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc *parcs) { if (dirty_type != 0) { - draw_item_add_img_region(pDirtyPriv, tmpRegion, GXcopy, dirty_type, 6); + draw_item_add_img_region(pDirtyPriv, tmpRegion, GXcopy, dirty_type, TAG_POLYARC); } else if (got_id) { @@ -217,7 +217,7 @@ rdpPolyArc(DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc *parcs) { if (dirty_type != 0) { - draw_item_add_img_region(pDirtyPriv, tmpRegion, GXcopy, dirty_type, 6); + draw_item_add_img_region(pDirtyPriv, tmpRegion, GXcopy, dirty_type, TAG_POLYARC); } else if (got_id) { diff --git a/xorg/X11R7.6/rdp/rdpPolyFillArc.c b/xorg/X11R7.6/rdp/rdpPolyFillArc.c index 6582f69e..e3822215 100644 --- a/xorg/X11R7.6/rdp/rdpPolyFillArc.c +++ b/xorg/X11R7.6/rdp/rdpPolyFillArc.c @@ -125,7 +125,7 @@ rdpPolyFillArc(DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc *parcs) if (g_do_dirty_os) { - LLOGLN(10, ("rdpPolyFillArc: gettig dirty")); + LLOGLN(10, ("rdpPolyFillArc: getting dirty")); pDstPriv->is_dirty = 1; pDirtyPriv = pDstPriv; dirty_type = RDI_IMGLY; @@ -151,7 +151,7 @@ rdpPolyFillArc(DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc *parcs) if (g_do_dirty_ons) { - LLOGLN(0, ("rdpPolyFillArc: gettig dirty")); + LLOGLN(10, ("rdpPolyFillArc: getting dirty")); g_screenPriv.is_dirty = 1; pDirtyPriv = &g_screenPriv; dirty_type = RDI_IMGLL; @@ -185,7 +185,7 @@ rdpPolyFillArc(DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc *parcs) { if (dirty_type != 0) { - draw_item_add_img_region(pDirtyPriv, tmpRegion, GXcopy, dirty_type, 8); + draw_item_add_img_region(pDirtyPriv, tmpRegion, GXcopy, dirty_type, TAG_POLYFILLARC); } else if (got_id) { @@ -217,7 +217,7 @@ rdpPolyFillArc(DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc *parcs) { if (dirty_type != 0) { - draw_item_add_img_region(pDirtyPriv, tmpRegion, GXcopy, dirty_type, 8); + draw_item_add_img_region(pDirtyPriv, tmpRegion, GXcopy, dirty_type, TAG_POLYFILLARC); } else if (got_id) { diff --git a/xorg/X11R7.6/rdp/rdpPolyFillRect.c b/xorg/X11R7.6/rdp/rdpPolyFillRect.c index e51fca4c..7db4be69 100644 --- a/xorg/X11R7.6/rdp/rdpPolyFillRect.c +++ b/xorg/X11R7.6/rdp/rdpPolyFillRect.c @@ -105,10 +105,11 @@ rdpPolyFillRect(DrawablePtr pDrawable, GCPtr pGC, int nrectFill, if (g_do_dirty_ons) { - LLOGLN(10, ("rdpPolyFillRect: gettig dirty")); + LLOGLN(10, ("rdpPolyFillRect: getting dirty")); g_screenPriv.is_dirty = 1; pDirtyPriv = &g_screenPriv; - dirty_type = RDI_IMGLL; + dirty_type = (FillTiled == pGC->fillStyle) ? + RDI_IMGLY : RDI_IMGLL; } else { @@ -122,10 +123,11 @@ rdpPolyFillRect(DrawablePtr pDrawable, GCPtr pGC, int nrectFill, if (g_do_dirty_os) { - LLOGLN(10, ("rdpPolyFillRect: gettig dirty")); + LLOGLN(10, ("rdpPolyFillRect: getting dirty")); pDstPriv->is_dirty = 1; pDirtyPriv = pDstPriv; - dirty_type = RDI_FILL; + dirty_type = (FillTiled == pGC->fillStyle) ? + RDI_IMGLY : RDI_IMGLL; } else { @@ -148,10 +150,11 @@ rdpPolyFillRect(DrawablePtr pDrawable, GCPtr pGC, int nrectFill, if (g_do_dirty_ons) { - LLOGLN(10, ("rdpPolyFillRect: gettig dirty")); + LLOGLN(10, ("rdpPolyFillRect: getting dirty")); g_screenPriv.is_dirty = 1; pDirtyPriv = &g_screenPriv; - dirty_type = RDI_IMGLL; + dirty_type = (FillTiled == pGC->fillStyle) ? + RDI_IMGLY : RDI_IMGLL; } else { @@ -192,7 +195,8 @@ rdpPolyFillRect(DrawablePtr pDrawable, GCPtr pGC, int nrectFill, } else { - draw_item_add_img_region(pDirtyPriv, fill_reg, GXcopy, RDI_IMGLL, 2); + draw_item_add_img_region(pDirtyPriv, fill_reg, GXcopy, + dirty_type, TAG_POLYFILLRECT); } } else if (got_id) @@ -214,7 +218,8 @@ rdpPolyFillRect(DrawablePtr pDrawable, GCPtr pGC, int nrectFill, for (j = REGION_NUM_RECTS(fill_reg) - 1; j >= 0; j--) { box = REGION_RECTS(fill_reg)[j]; - rdpup_fill_rect(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + rdpup_fill_rect(box.x1, box.y1, + box.x2 - box.x1, box.y2 - box.y1); } rdpup_set_opcode(GXcopy); @@ -251,13 +256,15 @@ rdpPolyFillRect(DrawablePtr pDrawable, GCPtr pGC, int nrectFill, pGC->alu == GXxor*/)) /* todo, why dosen't xor work? */ { LLOGLN(10, ("rdpPolyFillRect: 3")); - draw_item_add_fill_region(pDirtyPriv, &clip_reg, pGC->fgPixel, + draw_item_add_fill_region(pDirtyPriv, &clip_reg, + pGC->fgPixel, pGC->alu); } else { LLOGLN(10, ("rdpPolyFillRect: 4")); - draw_item_add_img_region(pDirtyPriv, &clip_reg, GXcopy, RDI_IMGLL, 2); + draw_item_add_img_region(pDirtyPriv, &clip_reg, GXcopy, + dirty_type, TAG_POLYFILLRECT); } } else if (got_id) @@ -281,7 +288,8 @@ rdpPolyFillRect(DrawablePtr pDrawable, GCPtr pGC, int nrectFill, for (j = num_clips - 1; j >= 0; j--) { box = REGION_RECTS(&clip_reg)[j]; - rdpup_fill_rect(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + rdpup_fill_rect(box.x1, box.y1, + box.x2 - box.x1, box.y2 - box.y1); } rdpup_set_opcode(GXcopy); @@ -291,7 +299,8 @@ rdpPolyFillRect(DrawablePtr pDrawable, GCPtr pGC, int nrectFill, for (j = num_clips - 1; j >= 0; j--) { box = REGION_RECTS(&clip_reg)[j]; - rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + rdpup_send_area(&id, box.x1, box.y1, + box.x2 - box.x1, box.y2 - box.y1); } } diff --git a/xorg/X11R7.6/rdp/rdpPolyGlyphBlt.c b/xorg/X11R7.6/rdp/rdpPolyGlyphBlt.c index 298b4b98..8ce1db08 100644 --- a/xorg/X11R7.6/rdp/rdpPolyGlyphBlt.c +++ b/xorg/X11R7.6/rdp/rdpPolyGlyphBlt.c @@ -108,7 +108,7 @@ rdpPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, if (g_do_dirty_os) { - LLOGLN(10, ("rdpPolyGlyphBlt: gettig dirty")); + LLOGLN(10, ("rdpPolyGlyphBlt: getting dirty")); pDstPriv->is_dirty = 1; pDirtyPriv = pDstPriv; dirty_type = RDI_IMGLY; @@ -134,7 +134,7 @@ rdpPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, if (g_do_dirty_ons) { - LLOGLN(0, ("rdpPolyGlyphBlt: gettig dirty")); + LLOGLN(10, ("rdpPolyGlyphBlt: getting dirty")); g_screenPriv.is_dirty = 1; pDirtyPriv = &g_screenPriv; dirty_type = RDI_IMGLL; @@ -169,7 +169,7 @@ rdpPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, if (dirty_type != 0) { RegionInit(®1, &box, 0); - draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type, 14); + draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type, TAG_POLYGLYPHBLT); RegionUninit(®1); } else if (got_id) @@ -189,7 +189,7 @@ rdpPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, { if (dirty_type != 0) { - draw_item_add_img_region(pDirtyPriv, ®, GXcopy, dirty_type, 14); + draw_item_add_img_region(pDirtyPriv, ®, GXcopy, dirty_type, TAG_POLYGLYPHBLT); } else if (got_id) { diff --git a/xorg/X11R7.6/rdp/rdpPolyPoint.c b/xorg/X11R7.6/rdp/rdpPolyPoint.c index 28db831a..e2eadafd 100644 --- a/xorg/X11R7.6/rdp/rdpPolyPoint.c +++ b/xorg/X11R7.6/rdp/rdpPolyPoint.c @@ -156,7 +156,7 @@ rdpPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, if (g_do_dirty_os) { - LLOGLN(10, ("rdpPolyPoint: gettig dirty")); + LLOGLN(10, ("rdpPolyPoint: getting dirty")); pDstPriv->is_dirty = 1; pDirtyPriv = pDstPriv; dirty_type = RDI_IMGLL; @@ -182,7 +182,7 @@ rdpPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, if (g_do_dirty_ons) { - LLOGLN(0, ("rdpPolyPoint: gettig dirty")); + LLOGLN(10, ("rdpPolyPoint: getting dirty")); g_screenPriv.is_dirty = 1; pDirtyPriv = &g_screenPriv; dirty_type = RDI_IMGLL; diff --git a/xorg/X11R7.6/rdp/rdpPolyRectangle.c b/xorg/X11R7.6/rdp/rdpPolyRectangle.c index 85bef306..c1a5c971 100644 --- a/xorg/X11R7.6/rdp/rdpPolyRectangle.c +++ b/xorg/X11R7.6/rdp/rdpPolyRectangle.c @@ -118,7 +118,7 @@ rdpPolyRectangle(DrawablePtr pDrawable, GCPtr pGC, int nrects, if (g_do_dirty_os) { - LLOGLN(10, ("rdpPolyRectangle: gettig dirty")); + LLOGLN(10, ("rdpPolyRectangle: getting dirty")); pDstPriv->is_dirty = 1; pDirtyPriv = pDstPriv; dirty_type = RDI_IMGLL; @@ -144,7 +144,7 @@ rdpPolyRectangle(DrawablePtr pDrawable, GCPtr pGC, int nrects, if (g_do_dirty_ons) { - LLOGLN(10, ("rdpPolyRectangle: gettig dirty")); + LLOGLN(10, ("rdpPolyRectangle: getting dirty")); g_screenPriv.is_dirty = 1; pDirtyPriv = &g_screenPriv; dirty_type = RDI_IMGLL; @@ -221,7 +221,7 @@ rdpPolyRectangle(DrawablePtr pDrawable, GCPtr pGC, int nrects, } else { - draw_item_add_img_region(pDirtyPriv, fill_reg, GXcopy, dirty_type, 4); + draw_item_add_img_region(pDirtyPriv, fill_reg, GXcopy, dirty_type, TAG_POLYRECTANGLE); } RegionDestroy(fill_reg); @@ -275,7 +275,7 @@ rdpPolyRectangle(DrawablePtr pDrawable, GCPtr pGC, int nrects, } else { - draw_item_add_img_region(pDirtyPriv, &clip_reg, GXcopy, dirty_type, 4); + draw_item_add_img_region(pDirtyPriv, &clip_reg, GXcopy, dirty_type, TAG_POLYRECTANGLE); } } else if (got_id) diff --git a/xorg/X11R7.6/rdp/rdpPolySegment.c b/xorg/X11R7.6/rdp/rdpPolySegment.c index 623ec748..f4bcfe31 100644 --- a/xorg/X11R7.6/rdp/rdpPolySegment.c +++ b/xorg/X11R7.6/rdp/rdpPolySegment.c @@ -115,7 +115,7 @@ rdpPolySegment(DrawablePtr pDrawable, GCPtr pGC, int nseg, xSegment *pSegs) if (g_do_dirty_os) { - LLOGLN(10, ("rdpPolySegment: gettig dirty")); + LLOGLN(10, ("rdpPolySegment: getting dirty")); pDstPriv->is_dirty = 1; pDirtyPriv = pDstPriv; dirty_type = RDI_IMGLL; @@ -141,7 +141,7 @@ rdpPolySegment(DrawablePtr pDrawable, GCPtr pGC, int nseg, xSegment *pSegs) if (g_do_dirty_ons) { - LLOGLN(10, ("rdpPolySegment: gettig dirty")); + LLOGLN(10, ("rdpPolySegment: getting dirty")); g_screenPriv.is_dirty = 1; pDirtyPriv = &g_screenPriv; dirty_type = RDI_IMGLL; diff --git a/xorg/X11R7.6/rdp/rdpPolyText16.c b/xorg/X11R7.6/rdp/rdpPolyText16.c index 9a253464..a28030f0 100644 --- a/xorg/X11R7.6/rdp/rdpPolyText16.c +++ b/xorg/X11R7.6/rdp/rdpPolyText16.c @@ -109,7 +109,7 @@ rdpPolyText16(DrawablePtr pDrawable, GCPtr pGC, if (g_do_dirty_os) { - LLOGLN(10, ("rdpPolyText16: gettig dirty")); + LLOGLN(10, ("rdpPolyText16: getting dirty")); pDstPriv->is_dirty = 1; pDirtyPriv = pDstPriv; dirty_type = RDI_IMGLY; @@ -135,7 +135,7 @@ rdpPolyText16(DrawablePtr pDrawable, GCPtr pGC, if (g_do_dirty_ons) { - LLOGLN(0, ("rdpPolyText16: gettig dirty")); + LLOGLN(10, ("rdpPolyText16: getting dirty")); g_screenPriv.is_dirty = 1; pDirtyPriv = &g_screenPriv; dirty_type = RDI_IMGLL; @@ -170,7 +170,7 @@ rdpPolyText16(DrawablePtr pDrawable, GCPtr pGC, if (dirty_type != 0) { RegionInit(®1, &box, 0); - draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type, 11); + draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type, TAG_POLYTEXT16); RegionUninit(®1); } else if (got_id) @@ -190,7 +190,7 @@ rdpPolyText16(DrawablePtr pDrawable, GCPtr pGC, { if (dirty_type != 0) { - draw_item_add_img_region(pDirtyPriv, ®, GXcopy, dirty_type, 11); + draw_item_add_img_region(pDirtyPriv, ®, GXcopy, dirty_type, TAG_POLYTEXT16); } else if (got_id) { diff --git a/xorg/X11R7.6/rdp/rdpPolyText8.c b/xorg/X11R7.6/rdp/rdpPolyText8.c index 59f04d78..3157a538 100644 --- a/xorg/X11R7.6/rdp/rdpPolyText8.c +++ b/xorg/X11R7.6/rdp/rdpPolyText8.c @@ -109,7 +109,7 @@ rdpPolyText8(DrawablePtr pDrawable, GCPtr pGC, if (g_do_dirty_os) { - LLOGLN(10, ("rdpPolyText8: gettig dirty")); + LLOGLN(10, ("rdpPolyText8: getting dirty")); pDstPriv->is_dirty = 1; pDirtyPriv = pDstPriv; dirty_type = RDI_IMGLY; @@ -135,7 +135,7 @@ rdpPolyText8(DrawablePtr pDrawable, GCPtr pGC, if (g_do_dirty_ons) { - LLOGLN(0, ("rdpPolyText8: gettig dirty")); + LLOGLN(10, ("rdpPolyText8: getting dirty")); g_screenPriv.is_dirty = 1; pDirtyPriv = &g_screenPriv; dirty_type = RDI_IMGLL; @@ -170,7 +170,7 @@ rdpPolyText8(DrawablePtr pDrawable, GCPtr pGC, if (dirty_type != 0) { RegionInit(®1, &box, 0); - draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type, 10); + draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type, TAG_POLYTEXT8); RegionUninit(®1); } else if (got_id) @@ -190,7 +190,7 @@ rdpPolyText8(DrawablePtr pDrawable, GCPtr pGC, { if (dirty_type != 0) { - draw_item_add_img_region(pDirtyPriv, ®, GXcopy, dirty_type, 10); + draw_item_add_img_region(pDirtyPriv, ®, GXcopy, dirty_type, TAG_POLYTEXT8); } else if (got_id) { diff --git a/xorg/X11R7.6/rdp/rdpPolylines.c b/xorg/X11R7.6/rdp/rdpPolylines.c index 759d1ff9..ba6381b8 100644 --- a/xorg/X11R7.6/rdp/rdpPolylines.c +++ b/xorg/X11R7.6/rdp/rdpPolylines.c @@ -166,7 +166,7 @@ rdpPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode, if (g_do_dirty_os) { - LLOGLN(10, ("rdpPolylines: gettig dirty")); + LLOGLN(10, ("rdpPolylines: getting dirty")); pDstPriv->is_dirty = 1; pDirtyPriv = pDstPriv; dirty_type = RDI_IMGLL; @@ -192,7 +192,7 @@ rdpPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode, if (g_do_dirty_ons) { - LLOGLN(10, ("rdpPolylines: gettig dirty")); + LLOGLN(10, ("rdpPolylines: getting dirty")); g_screenPriv.is_dirty = 1; pDirtyPriv = &g_screenPriv; dirty_type = RDI_IMGLL; diff --git a/xorg/X11R7.6/rdp/rdpPushPixels.c b/xorg/X11R7.6/rdp/rdpPushPixels.c index 6a353977..e7d330d1 100644 --- a/xorg/X11R7.6/rdp/rdpPushPixels.c +++ b/xorg/X11R7.6/rdp/rdpPushPixels.c @@ -102,7 +102,7 @@ rdpPushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr pDst, if (g_do_dirty_os) { - LLOGLN(10, ("rdpPushPixels: gettig dirty")); + LLOGLN(10, ("rdpPushPixels: getting dirty")); pDstPriv->is_dirty = 1; pDirtyPriv = pDstPriv; dirty_type = RDI_IMGLY; @@ -128,7 +128,7 @@ rdpPushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr pDst, if (g_do_dirty_ons) { - LLOGLN(0, ("rdpPushPixels: gettig dirty")); + LLOGLN(10, ("rdpPushPixels: getting dirty")); g_screenPriv.is_dirty = 1; pDirtyPriv = &g_screenPriv; dirty_type = RDI_IMGLL; @@ -160,7 +160,7 @@ rdpPushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr pDst, box.x2 = box.x1 + w; box.y2 = box.y1 + h; RegionInit(®1, &box, 0); - draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type, 15); + draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type, TAG_PUSHPIXELS); RegionUninit(®1); } else if (got_id) @@ -185,7 +185,7 @@ rdpPushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr pDst, if (dirty_type != 0) { RegionInit(®1, &box, 0); - draw_item_add_img_region(pDirtyPriv, &clip_reg, GXcopy, dirty_type, 15); + draw_item_add_img_region(pDirtyPriv, &clip_reg, GXcopy, dirty_type, TAG_PUSHPIXELS); RegionUninit(®1); } else if (got_id) diff --git a/xorg/X11R7.6/rdp/rdpPutImage.c b/xorg/X11R7.6/rdp/rdpPutImage.c index 737e4b31..d244d895 100644 --- a/xorg/X11R7.6/rdp/rdpPutImage.c +++ b/xorg/X11R7.6/rdp/rdpPutImage.c @@ -106,7 +106,7 @@ rdpPutImage(DrawablePtr pDst, GCPtr pGC, int depth, int x, int y, if (g_do_dirty_os) { - LLOGLN(10, ("rdpPutImage: gettig dirty")); + LLOGLN(10, ("rdpPutImage: getting dirty")); pDstPriv->is_dirty = 1; pDirtyPriv = pDstPriv; dirty_type = RDI_IMGLY; @@ -132,10 +132,10 @@ rdpPutImage(DrawablePtr pDst, GCPtr pGC, int depth, int x, int y, if (g_do_dirty_ons) { - LLOGLN(10, ("rdpPutImage: gettig dirty")); + LLOGLN(10, ("rdpPutImage: getting dirty")); g_screenPriv.is_dirty = 1; pDirtyPriv = &g_screenPriv; - dirty_type = RDI_IMGLL; + dirty_type = RDI_IMGLY; } else { @@ -163,7 +163,7 @@ rdpPutImage(DrawablePtr pDst, GCPtr pGC, int depth, int x, int y, box.x2 = box.x1 + w; box.y2 = box.y1 + h; RegionInit(®1, &box, 0); - draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type, 3); + draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type, TAG_PUTIMAGE); RegionUninit(®1); } else if (got_id) @@ -185,7 +185,7 @@ rdpPutImage(DrawablePtr pDst, GCPtr pGC, int depth, int x, int y, RegionInit(®2, NullBox, 0); RegionCopy(®2, &clip_reg); RegionIntersect(®1, ®1, ®2); - draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type, 3); + draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type, TAG_PUTIMAGE); RegionUninit(®1); RegionUninit(®2); } diff --git a/xorg/X11R7.6/rdp/rdpSetSpans.c b/xorg/X11R7.6/rdp/rdpSetSpans.c index 2b650e94..62dd8c5c 100644 --- a/xorg/X11R7.6/rdp/rdpSetSpans.c +++ b/xorg/X11R7.6/rdp/rdpSetSpans.c @@ -38,6 +38,8 @@ extern int g_Bpp; /* from rdpmain.c */ extern ScreenPtr g_pScreen; /* from rdpmain.c */ extern Bool g_wrapPixmap; /* from rdpmain.c */ extern int g_do_dirty_os; /* in rdpmain.c */ +extern int g_do_dirty_ons; /* in rdpmain.c */ +extern rdpPixmapRec g_screenPriv; /* in rdpmain.c */ extern GCOps g_rdpGCOps; /* from rdpdraw.c */ @@ -95,7 +97,7 @@ rdpSetSpans(DrawablePtr pDrawable, GCPtr pGC, char *psrc, if (g_do_dirty_os) { - LLOGLN(10, ("rdpSetSpans: gettig dirty")); + LLOGLN(10, ("rdpSetSpans: getting dirty")); pDstPriv->is_dirty = 1; pDirtyPriv = pDstPriv; dirty_type = RDI_IMGLY; @@ -118,8 +120,18 @@ rdpSetSpans(DrawablePtr pDrawable, GCPtr pGC, char *psrc, if (pDstWnd->viewable) { post_process = 1; - rdpup_get_screen_image_rect(&id); - got_id = 1; + if (g_do_dirty_ons) + { + LLOGLN(10, ("rdpSetSpans: getting dirty")); + g_screenPriv.is_dirty = 1; + pDirtyPriv = &g_screenPriv; + dirty_type = RDI_IMGLL; + } + else + { + rdpup_get_screen_image_rect(&id); + got_id = 1; + } } } } diff --git a/xorg/X11R7.6/rdp/rdpdraw.c b/xorg/X11R7.6/rdp/rdpdraw.c index 4b900f4e..e276c0b7 100644 --- a/xorg/X11R7.6/rdp/rdpdraw.c +++ b/xorg/X11R7.6/rdp/rdpdraw.c @@ -45,6 +45,7 @@ Xserver drawing ops and funcs #include "rdpImageGlyphBlt.h" #include "rdpPolyGlyphBlt.h" #include "rdpPushPixels.h" +#include "rdpglyph.h" #define LOG_LEVEL 1 #define LLOG(_level, _args) \ @@ -65,11 +66,10 @@ extern int g_do_dirty_os; /* in rdpmain.c */ extern int g_do_dirty_ons; /* in rdpmain.c */ extern rdpPixmapRec g_screenPriv; /* in rdpmain.c */ extern int g_con_number; /* in rdpmain.c */ +extern int g_do_glyph_cache; /* in rdpmain.c */ ColormapPtr g_rdpInstalledColormap; -static int g_doing_font = 0; - GCFuncs g_rdpGCFuncs = { rdpValidateGC, rdpChangeGC, rdpCopyGC, rdpDestroyGC, rdpChangeClip, @@ -407,6 +407,8 @@ rdpCloseScreen(int i, ScreenPtr pScreen) int draw_item_add(rdpPixmapRec *priv, struct rdp_draw_item *di) { + priv->is_alpha_dirty_not = 0; + if (priv->draw_item_tail == 0) { priv->draw_item_tail = di; @@ -458,6 +460,11 @@ draw_item_remove(rdpPixmapRec *priv, struct rdp_draw_item *di) g_free(di->u.line.segs); } } + + if (di->type == RDI_TEXT) + { + delete_rdp_text(di->u.text.rtext); + } RegionDestroy(di->reg); g_free(di); @@ -483,13 +490,175 @@ draw_item_remove_all(rdpPixmapRec *priv) /******************************************************************************/ int +region_get_pixel_count(RegionPtr reg) +{ + int index; + int count; + int pixels; + int width; + int height; + BoxRec box; + + pixels = 0; + count = REGION_NUM_RECTS(reg); + for (index = 0; index < count; index++) + { + box = REGION_RECTS(reg)[index]; + width = box.x2 - box.x1; + height = box.y2 - box.y1; + pixels += width * height; + } + return pixels; +} + +/******************************************************************************/ +/* returns boolean */ +int +region_in_region(RegionPtr reg_small, int sreg_pcount, RegionPtr reg_big) +{ + int rv; + RegionRec reg; + + rv = 0; + RegionInit(®, NullBox, 0); + RegionIntersect(®, reg_small, reg_big); + if (sreg_pcount == -1) + { + sreg_pcount = region_get_pixel_count(reg_small); + } + if (sreg_pcount == 0) + { + /* empty region not even in */ + return 0; + } + if (region_get_pixel_count(®) == sreg_pcount) + { + rv = 1; + } + RegionUninit(®); + return rv; +} + +/******************************************************************************/ +static int +remove_empties(rdpPixmapRec* priv) +{ + struct rdp_draw_item* di; + struct rdp_draw_item* di_prev; + int rv; + + rv = 0; + /* remove draw items with empty regions */ + di = priv->draw_item_head; + di_prev = 0; + while (di != 0) + { + if (!RegionNotEmpty(di->reg)) + { + LLOGLN(10, ("remove_empties: removing empty item type %d", di->type)); + draw_item_remove(priv, di); + di = di_prev == 0 ? priv->draw_item_head : di_prev->next; + rv++; + } + else + { + di_prev = di; + di = di->next; + } + } + return rv; +} + +/******************************************************************************/ +static int +dump_draw_list(rdpPixmapRec* priv) +{ + struct rdp_draw_item* di; + int index; + int count; + BoxRec box; + + LLOGLN(0, ("dump_draw_list:")); + di = priv->draw_item_head; + while (di != 0) + { + LLOGLN(0, (" type %d", di->type)); + count = REGION_NUM_RECTS(di->reg); + if (count == 0) + { + LLOGLN(0, (" empty region")); + } + else + { + box = RegionExtents(di->reg)[0]; + LLOGLN(0, (" region list follows extents x1 %d y1 %d x2 %d y2 %d", + box.x1, box.y1, box.x2, box.y2)); + for (index = 0; index < count; index++) + { + box = REGION_RECTS(di->reg)[index]; + LLOGLN(0, (" index %d x1 %d y1 %d x2 %d y2 %d", + index, box.x1, box.y1, box.x2, box.y2)); + } + } + di = di->next; + } + return 0; +} + +/******************************************************************************/ +/* returns boolean */ +static int +region_interect_at_all(RegionPtr reg_small, RegionPtr reg_big) +{ + int rv; + RegionRec reg; + + if (!RegionNotEmpty(reg_small)) + { + return 0; + } + rv = 0; + RegionInit(®, NullBox, 0); + RegionIntersect(®, reg_big, reg_big); + if (RegionNotEmpty(®)) + { + rv = 1; + } + RegionUninit(®); + return rv; +} + +/******************************************************************************/ +int draw_item_pack(PixmapPtr pix, rdpPixmapRec *priv) { struct rdp_draw_item *di; struct rdp_draw_item *di_prev; + BoxRec box; + RegionRec treg; #if 1 + if (pix != 0) + { + box.x1 = 0; + box.x2 = pix->drawable.width; + box.y1 = 0; + box.y2 = pix->drawable.height; + RegionInit(&treg, &box, 0); + di = priv->draw_item_head; + di_prev = 0; + while (di != 0) + { + RegionIntersect(di->reg, di->reg, &treg); + di_prev = di; + di = di->next; + } + RegionUninit(&treg); + remove_empties(priv); + } +#endif +#if 1 /* look for repeating draw types */ if (priv->draw_item_head != 0) { @@ -500,6 +669,17 @@ draw_item_pack(PixmapPtr pix, rdpPixmapRec *priv) while (di != 0) { +#if 0 + if ((di_prev->type == RDI_IMGLL || di_prev->type == RDI_IMGLY) && + (di->type == RDI_IMGLL || di->type == RDI_IMGLY)) + { + LLOGLN(10, ("draw_item_pack: packing RDI_IMGLL and RDI_IMGLY")); + di_prev->type = RDI_IMGLY; + RegionUnion(di_prev->reg, di_prev->reg, di->reg); + draw_item_remove(priv, di); + di = di_prev->next; + } +#else if ((di_prev->type == RDI_IMGLL) && (di->type == RDI_IMGLL)) { LLOGLN(10, ("draw_item_pack: packing RDI_IMGLL")); @@ -507,6 +687,7 @@ draw_item_pack(PixmapPtr pix, rdpPixmapRec *priv) draw_item_remove(priv, di); di = di_prev->next; } +#endif else if ((di_prev->type == RDI_IMGLY) && (di->type == RDI_IMGLY)) { LLOGLN(10, ("draw_item_pack: packing RDI_IMGLY")); @@ -522,10 +703,37 @@ draw_item_pack(PixmapPtr pix, rdpPixmapRec *priv) } } } - + remove_empties(priv); #endif + #if 0 + if (priv->draw_item_tail != 0) + { + if (priv->draw_item_tail->prev != 0) + { + di = priv->draw_item_tail; + while (di->prev != 0) + { + di_prev = di->prev; + while (di_prev != 0) + { + if ((di->type == RDI_TEXT) && (di_prev->type == RDI_IMGLY)) + { + if (region_interect_at_all(di->reg, di_prev->reg)) + { + di_prev->type = RDI_IMGLL; + } + } + di_prev = di_prev->prev; + } + di = di->prev; + } + } + } + remove_empties(priv); +#endif +#if 0 /* subtract regions */ if (priv->draw_item_tail != 0) { @@ -546,8 +754,11 @@ draw_item_pack(PixmapPtr pix, rdpPixmapRec *priv) while (di_prev != 0) { - /* D = M - S */ - RegionSubtract(di_prev->reg, di_prev->reg, di->reg); + if (region_in_region(di_prev->reg, -1, di->reg)) + { + /* empty region so this draw item will get removed below */ + RegionEmpty(di_prev->reg); + } di_prev = di_prev->prev; } } @@ -556,30 +767,9 @@ draw_item_pack(PixmapPtr pix, rdpPixmapRec *priv) } } } - + remove_empties(priv); #endif -#if 1 - /* remove draw items with empty regions */ - di = priv->draw_item_head; - di_prev = 0; - - while (di != 0) - { - if (!RegionNotEmpty(di->reg)) - { - LLOGLN(10, ("draw_item_pack: removing empty item type %d", di->type)); - draw_item_remove(priv, di); - di = di_prev == 0 ? priv->draw_item_head : di_prev->next; - } - else - { - di_prev = di; - di = di->next; - } - } - -#endif return 0; } @@ -693,6 +883,25 @@ draw_item_add_srcblt_region(rdpPixmapRec *priv, RegionPtr reg, } /******************************************************************************/ +int +draw_item_add_text_region(rdpPixmapRec* priv, RegionPtr reg, int color, + int opcode, struct rdp_text* rtext) +{ + struct rdp_draw_item* di; + + LLOGLN(10, ("draw_item_add_text_region:")); + di = (struct rdp_draw_item*)g_malloc(sizeof(struct rdp_draw_item), 1); + di->type = RDI_TEXT; + di->u.text.fg_color = color; + di->u.text.opcode = opcode; + di->u.text.rtext = rtext; + di->reg = RegionCreate(NullBox, 0); + RegionCopy(di->reg, reg); + draw_item_add(priv, di); + return 0; +} + +/******************************************************************************/ PixmapPtr rdpCreatePixmap(ScreenPtr pScreen, int width, int height, int depth, unsigned usage_hint) @@ -708,14 +917,14 @@ rdpCreatePixmap(ScreenPtr pScreen, int width, int height, int depth, width, org_width, depth, g_rdpScreen.depth)); pScreen->CreatePixmap = g_rdpScreen.CreatePixmap; rv = pScreen->CreatePixmap(pScreen, width, height, depth, usage_hint); + pScreen->CreatePixmap = rdpCreatePixmap; priv = GETPIXPRIV(rv); priv->rdpindex = -1; - priv->con_number = g_con_number; priv->kind_width = width; pScreen->ModifyPixmapHeader(rv, org_width, 0, 0, 0, 0, 0); - pScreen->CreatePixmap = rdpCreatePixmap; - if (org_width == 0 && height == 0) + if ((org_width == 0) && (height == 0)) { + LLOGLN(10, ("rdpCreatePixmap: setting is_scratch")); priv->is_scratch = 1; } return rv; @@ -739,9 +948,11 @@ rdpDestroyPixmap(PixmapPtr pPixmap) { if (XRDP_IS_OS(priv)) { - rdpup_remove_os_bitmap(priv->rdpindex); - rdpup_delete_os_surface(priv->rdpindex); - draw_item_remove_all(priv); + if (priv->rdpindex >= 0) + { + rdpup_remove_os_bitmap(priv->rdpindex); + rdpup_delete_os_surface(priv->rdpindex); + } } } @@ -762,33 +973,41 @@ xrdp_is_os(PixmapPtr pix, rdpPixmapPtr priv) int height; struct image_data id; - if (!XRDP_IS_OS(priv)) + if (XRDP_IS_OS(priv)) + { + /* update time stamp */ + rdpup_update_os_use(priv->rdpindex); + } + else { width = pix->drawable.width; height = pix->drawable.height; if ((pix->usage_hint == 0) && (pix->drawable.depth >= g_rdpScreen.depth) && (width > 0) && (height > 0) && (priv->kind_width > 0) && - (priv->is_scratch == 0)) + (priv->is_scratch == 0) && (priv->use_count >= 0)) { - LLOGLN(10, ("%d %d", priv->kind_width, pix->drawable.width)); + width = (width + 3) & ~3; priv->rdpindex = rdpup_add_os_bitmap(pix, priv); if (priv->rdpindex >= 0) { priv->status = 1; - rdpup_create_os_surface(priv->rdpindex, - priv->kind_width, height); + rdpup_create_os_surface(priv->rdpindex, width, height); box.x1 = 0; box.y1 = 0; box.x2 = width; box.y2 = height; if (g_do_dirty_os) { + LLOGLN(10, ("xrdp_is_os: priv->con_number %d g_con_number %d", + priv->con_number, g_con_number)); + LLOGLN(10, ("xrdp_is_os: priv->use_count %d", priv->use_count)); if (priv->con_number != g_con_number) { + LLOGLN(10, ("xrdp_is_os: queuing invalidating all")); draw_item_remove_all(priv); RegionInit(®1, &box, 0); - draw_item_add_img_region(priv, ®1, GXcopy, RDI_IMGLL, 16); + draw_item_add_img_region(priv, ®1, GXcopy, RDI_IMGLY, 16); RegionUninit(®1); priv->is_dirty = 1; priv->con_number = g_con_number; @@ -804,11 +1023,18 @@ xrdp_is_os(PixmapPtr pix, rdpPixmapPtr priv) rdpup_end_update(); rdpup_switch_os_surface(-1); } + priv->use_count++; return 1; } + else + { + LLOGLN(10, ("xrdp_is_os: rdpup_add_os_bitmap failed")); + } } + priv->use_count++; return 0; } + priv->use_count++; return 1; } @@ -852,6 +1078,10 @@ rdpDestroyWindow(WindowPtr pWindow) if (g_use_rail) { +#ifdef XRDP_WM_RDPUP + LLOGLN(10, (" rdpup_delete_window")); + rdpup_delete_window(pWindow, priv); +#endif } return rv; @@ -913,7 +1143,9 @@ rdpRealizeWindow(WindowPtr pWindow) pWindow->drawable.x, pWindow->drawable.y, pWindow->drawable.width, pWindow->drawable.height)); priv->status = 1; +#ifdef XRDP_WM_RDPUP rdpup_create_window(pWindow, priv); +#endif } } } @@ -942,7 +1174,18 @@ rdpUnrealizeWindow(WindowPtr pWindow) { LLOGLN(10, ("rdpUnrealizeWindow:")); priv->status = 0; - rdpup_delete_window(pWindow, priv); + if (pWindow->overrideRedirect) { +#ifdef XRDP_WM_RDPUP + /* + * Popups are unmapped by X server, so probably + * they will be mapped again. Thereby we should + * just hide those popups instead of destroying + * them. + */ + LLOGLN(10, (" rdpup_show_window")); + rdpup_show_window(pWindow, priv, 0x0); /* 0x0 - do not show the window */ +#endif + } } } @@ -1035,7 +1278,9 @@ rdpCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr pOldRegion) BoxRec box2; BoxPtr box3; - LLOGLN(10, ("in rdpCopyWindow")); + LLOGLN(10, ("rdpCopyWindow:")); + LLOGLN(10, ("rdpCopyWindow: new x %d new y %d old x %d old y %d", + pWin->drawable.x, pWin->drawable.y, ptOldOrg.x, ptOldOrg.y)); RegionInit(®, NullBox, 0); RegionCopy(®, pOldRegion); RegionInit(&clip, NullBox, 0); @@ -1047,18 +1292,28 @@ rdpCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr pOldRegion) { rdpup_check_dirty_screen(&g_screenPriv); } - rdpup_begin_update(); + + g_pScreen->CopyWindow = g_rdpScreen.CopyWindow; + g_pScreen->CopyWindow(pWin, ptOldOrg, pOldRegion); + g_pScreen->CopyWindow = rdpCopyWindow; + num_clip_rects = REGION_NUM_RECTS(&clip); num_reg_rects = REGION_NUM_RECTS(®); LLOGLN(10, ("rdpCopyWindow: num_clip_rects %d num_reg_rects %d", num_clip_rects, num_reg_rects)); + if ((num_clip_rects == 0) || (num_reg_rects == 0)) + { + return; + } + rdpup_begin_update(); + /* when there is a huge list of screen copies, just send as bitmap firefox dragging test does this */ if ((num_clip_rects > 16) && (num_reg_rects > 16)) { box3 = RegionExtents(®); - rdpup_send_area(0, box3->x1, box3->y1, + rdpup_send_area(0, box3->x1 + dx, box3->y1 + dy, box3->x2 - box3->x1, box3->y2 - box3->y1); } @@ -1073,6 +1328,8 @@ rdpCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr pOldRegion) for (j = 0; j < num_clip_rects; j++) { box1 = REGION_RECTS(&clip)[j]; + LLOGLN(10, ("clip x %d y %d w %d h %d", box1.x1, box1.y1, + box1.x2 - box1.x1, box1.y2 - box1.y1)); rdpup_set_clip(box1.x1, box1.y1, box1.x2 - box1.x1, box1.y2 - box1.y1); @@ -1080,6 +1337,8 @@ rdpCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr pOldRegion) for (i = 0; i < num_reg_rects; i++) { box2 = REGION_RECTS(®)[i]; + LLOGLN(10, ("reg x %d y %d w %d h %d", box2.x1, box2.y1, + box2.x2 - box2.x1, box2.y2 - box2.y1)); rdpup_screen_blt(box2.x1 + dx, box2.y1 + dy, box2.x2 - box2.x1, box2.y2 - box2.y1, @@ -1092,6 +1351,8 @@ rdpCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr pOldRegion) for (j = num_clip_rects - 1; j >= 0; j--) { box1 = REGION_RECTS(&clip)[j]; + LLOGLN(10, ("clip x %d y %d w %d h %d", box1.x1, box1.y1, + box1.x2 - box1.x1, box1.y2 - box1.y1)); rdpup_set_clip(box1.x1, box1.y1, box1.x2 - box1.x1, box1.y2 - box1.y1); @@ -1099,6 +1360,8 @@ rdpCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr pOldRegion) for (i = num_reg_rects - 1; i >= 0; i--) { box2 = REGION_RECTS(®)[i]; + LLOGLN(10, ("reg x %d y %d w %d h %d", box2.x1, box2.y1, + box2.x2 - box2.x1, box2.y2 - box2.y1)); rdpup_screen_blt(box2.x1 + dx, box2.y1 + dy, box2.x2 - box2.x1, box2.y2 - box2.y1, @@ -1113,9 +1376,6 @@ rdpCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr pOldRegion) RegionUninit(®); RegionUninit(&clip); - g_pScreen->CopyWindow = g_rdpScreen.CopyWindow; - g_pScreen->CopyWindow(pWin, ptOldOrg, pOldRegion); - g_pScreen->CopyWindow = rdpCopyWindow; } /******************************************************************************/ @@ -1153,7 +1413,7 @@ rdpClearToBackground(WindowPtr pWin, int x, int y, int w, int h, if (g_do_dirty_ons) { - draw_item_add_img_region(&g_screenPriv, ®, GXcopy, RDI_IMGLL, 16); + draw_item_add_img_region(&g_screenPriv, ®, GXcopy, RDI_IMGLY, 16); } else { @@ -1191,7 +1451,7 @@ rdpRestoreAreas(WindowPtr pWin, RegionPtr prgnExposed) if (g_do_dirty_ons) { - draw_item_add_img_region(&g_screenPriv, ®, GXcopy, RDI_IMGLL, 16); + draw_item_add_img_region(&g_screenPriv, ®, GXcopy, RDI_IMGLY, 16); } else { @@ -1274,196 +1534,3 @@ rdpSaveScreen(ScreenPtr pScreen, int on) { return 1; } - -/******************************************************************************/ -/* it looks like all the antialias draws go through here */ -void -rdpComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, - INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask, INT16 xDst, - INT16 yDst, CARD16 width, CARD16 height) -{ - BoxRec box; - PictureScreenPtr ps; - RegionRec reg1; - RegionRec reg2; - DrawablePtr p; - int dirty_type; - int j; - int num_clips; - int post_process; - int reset_surface; - int got_id; - WindowPtr pDstWnd; - PixmapPtr pDstPixmap; - rdpPixmapRec *pDstPriv; - rdpPixmapRec *pDirtyPriv; - struct image_data id; - - LLOGLN(10, ("rdpComposite:")); - ps = GetPictureScreen(g_pScreen); - ps->Composite = g_rdpScreen.Composite; - ps->Composite(op, pSrc, pMask, pDst, xSrc, ySrc, - xMask, yMask, xDst, yDst, width, height); - ps->Composite = rdpComposite; - - p = pDst->pDrawable; - - dirty_type = 0; - pDirtyPriv = 0; - post_process = 0; - reset_surface = 0; - got_id = 0; - - if (p->type == DRAWABLE_PIXMAP) - { - pDstPixmap = (PixmapPtr)p; - pDstPriv = GETPIXPRIV(pDstPixmap); - - if (xrdp_is_os(pDstPixmap, pDstPriv)) - { - post_process = 1; - - if (g_do_dirty_os) - { - LLOGLN(10, ("rdpComposite: gettig dirty")); - pDstPriv->is_dirty = 1; - dirty_type = g_doing_font ? RDI_IMGLL : RDI_IMGLY; - pDirtyPriv = pDstPriv; - - } - else - { - rdpup_switch_os_surface(pDstPriv->rdpindex); - reset_surface = 1; - rdpup_get_pixmap_image_rect(pDstPixmap, &id); - got_id = 1; - LLOGLN(10, ("rdpComposite: offscreen")); - } - } - } - else - { - if (p->type == DRAWABLE_WINDOW) - { - pDstWnd = (WindowPtr)p; - - if (pDstWnd->viewable) - { - post_process = 1; - - if (g_do_dirty_ons) - { - LLOGLN(10, ("rdpComposite: gettig dirty")); - g_screenPriv.is_dirty = 1; - pDirtyPriv = &g_screenPriv; - dirty_type = RDI_IMGLL; - } - else - { - rdpup_get_screen_image_rect(&id); - got_id = 1; - LLOGLN(10, ("rdpComposite: screen")); - } - } - } - } - - if (!post_process) - { - return; - } - - if (pDst->pCompositeClip != 0) - { - box.x1 = p->x + xDst; - box.y1 = p->y + yDst; - box.x2 = box.x1 + width; - box.y2 = box.y1 + height; - RegionInit(®1, &box, 0); - RegionInit(®2, NullBox, 0); - RegionCopy(®2, pDst->pCompositeClip); - RegionIntersect(®1, ®1, ®2); - - if (dirty_type != 0) - { - draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type, 0); - } - else if (got_id) - { - num_clips = REGION_NUM_RECTS(®1); - - if (num_clips > 0) - { - rdpup_begin_update(); - - for (j = num_clips - 1; j >= 0; j--) - { - box = REGION_RECTS(®1)[j]; - rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); - } - - rdpup_end_update(); - } - } - - RegionUninit(®1); - RegionUninit(®2); - } - else - { - box.x1 = p->x + xDst; - box.y1 = p->y + yDst; - box.x2 = box.x1 + width; - box.y2 = box.y1 + height; - - if (dirty_type != 0) - { - RegionInit(®1, &box, 0); - draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type, 0); - RegionUninit(®1); - } - else if (got_id) - { - rdpup_begin_update(); - rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); - rdpup_end_update(); - } - } - - if (reset_surface) - { - rdpup_switch_os_surface(-1); - } -} - -/******************************************************************************/ -void -rdpGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst, - PictFormatPtr maskFormat, - INT16 xSrc, INT16 ySrc, int nlists, GlyphListPtr lists, - GlyphPtr *glyphs) -{ - PictureScreenPtr ps; - int index; - - LLOGLN(10, ("rdpGlyphs:")); - LLOGLN(10, ("rdpGlyphs: nlists %d len %d", nlists, lists->len)); - rdpup_set_hints(1, 1); - g_doing_font = 1; - - for (index = 0; index < lists->len; index++) - { - LLOGLN(10, (" index %d size %d refcnt %d width %d height %d", - index, (int)(glyphs[index]->size), (int)(glyphs[index]->refcnt), - glyphs[index]->info.width, glyphs[index]->info.height)); - } - - ps = GetPictureScreen(g_pScreen); - ps->Glyphs = g_rdpScreen.Glyphs; - ps->Glyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, - nlists, lists, glyphs); - ps->Glyphs = rdpGlyphs; - rdpup_set_hints(0, 1); - g_doing_font = 0; - LLOGLN(10, ("rdpGlyphs: out")); -} diff --git a/xorg/X11R7.6/rdp/rdpglyph.c b/xorg/X11R7.6/rdp/rdpglyph.c new file mode 100644 index 00000000..cb895ae5 --- /dev/null +++ b/xorg/X11R7.6/rdp/rdpglyph.c @@ -0,0 +1,862 @@ +/* + Copyright 2012 Jay Sorg + + Permission to use, copy, modify, distribute, and sell this software and its + documentation for any purpose is hereby granted without fee, provided that + the above copyright notice appear in all copies and that both that + copyright notice and this permission notice appear in supporting + documentation. + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + */ + +/* + http://msdn.microsoft.com/en-us/library/cc241863(v=prot.20).aspx + 4.6.1 "d" Character + This topic has not yet been rated - Rate this topic + The following shows glyph image data (1 bpp format) for character + "d" extracted from a Cache Glyph (Revision 2) (section 2.2.2.2.1.2.6) + Secondary Drawing Order. + + Glyph width = 5 pixels + Glyph height = 9 pixels + Glyph origin = (0, -9), marked with an "X" on the image grid + Bitmap = { 0x08, 0x08, 0x08, 0x78, 0x88, 0x88, 0x88, 0x88, 0x78 } + + http://msdn.microsoft.com/en-us/library/cc241864(v=prot.20).aspx + 4.6.2 "p" Character + This topic has not yet been rated - Rate this topic + The following shows glyph image data (1 bpp format) for character + "p" extracted from a Cache Glyph (Revision 2) (section 2.2.2.2.1.2.6) + Secondary Drawing Order. + + Glyph width = 5 pixels + Glyph height = 8 pixels + Glyph origin = (0, -6), marked with an "X" on the image grid + Bitmap = { 0xF0, 0x88, 0x88, 0x88, 0x88, 0xF0, 0x80, 0x80 } + */ + +#include "rdp.h" +#include "rdpdraw.h" +#include "rdpglyph.h" + +extern DevPrivateKeyRec g_rdpPixmapIndex; /* from rdpmain.c */ +extern int g_do_dirty_os; /* in rdpmain.c */ +extern int g_do_alpha_glyphs; /* in rdpmain.c */ +extern int g_do_glyph_cache; /* in rdpmain.c */ +extern int g_doing_font; /* in rdpmain.c */ +extern ScreenPtr g_pScreen; /* in rdpmain.c */ +extern rdpScreenInfoRec g_rdpScreen; /* in rdpmain.c */ + + +#define LOG_LEVEL 1 +#define LLOG(_level, _args) \ +do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) +#define LLOGLN(_level, _args) \ +do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) + +struct font_cache +{ + int offset; + int baseline; + int width; + int height; + int crc; + int stamp; +}; + +static struct font_cache g_font_cache[12][256]; +static int g_stamp = 0; + +/*****************************************************************************/ +static void +set_mono_pixel(char* data, int x, int y, int width, int pixel) +{ + int start; + int shift; + + width = (width + 7) / 8; + start = (y * width) + x / 8; + shift = x % 8; + if (pixel != 0) + { + data[start] = data[start] | (0x80 >> shift); + } + else + { + data[start] = data[start] & ~(0x80 >> shift); + } +} + +/*****************************************************************************/ +static int +lget_pixel(char* data, int x, int y, int depth, int stride_bytes) +{ + int start; + int shift; + + if (depth == 1) + { + start = (y * stride_bytes) + x / 8; + shift = x % 8; + return (data[start] & (0x01 << shift)) ? 0xff : 0; + } + else if (depth == 8) + { + return data[y * stride_bytes + x]; + } + return 0; +} + +/******************************************************************************/ +static int +glyph_get_data(ScreenPtr pScreen, GlyphPtr glyph, struct rdp_font_char* rfd) +{ + int i; + int j; + int src_xoff; + int src_yoff; + int src_stride_bytes; + int dst_stride_bytes; + int hh; + int ww; + int src_depth; + unsigned char pixel; + PicturePtr pPicture; + pixman_image_t *src; + uint32_t* pi32; + char* pi8; + + pPicture = GlyphPicture(glyph)[pScreen->myNum]; + if (pPicture == 0) + { + return 0; + } + src = image_from_pict(pPicture, FALSE, &src_xoff, &src_yoff); + if (src == 0) + { + return 0; + } + + src_stride_bytes = pixman_image_get_stride(src); + if (g_do_alpha_glyphs) + { + dst_stride_bytes = (glyph->info.width + 3) & ~3; + rfd->bpp = 8; + } + else + { + dst_stride_bytes = (((glyph->info.width + 7) / 8) + 3) & ~3; + rfd->bpp = 1; + } + src_depth = pixman_image_get_depth(src); + ww = pixman_image_get_width(src); + hh = pixman_image_get_height(src); + if ((ww != glyph->info.width) || (hh != glyph->info.height) || + ((src_depth != 1) && (src_depth != 8))) + { + LLOGLN(0, ("glyph_get_data: bad glyph")); + free_pixman_pict(pPicture, src); + return 0; + } + rfd->data_bytes = glyph->info.height * dst_stride_bytes; + rfd->data = (char*)g_malloc(rfd->data_bytes, 1); + rfd->offset = -glyph->info.x; + rfd->baseline = -glyph->info.y; + rfd->width = glyph->info.width; + rfd->height = glyph->info.height; + pi32 = pixman_image_get_data(src); + pi8 = (char*)pi32; + for (j = 0; j < rfd->height; j++) + { + for (i = 0; i < rfd->width; i++) + { + pixel = lget_pixel(pi8, i, j, src_depth, src_stride_bytes); + if (g_do_alpha_glyphs) + { + rfd->data[j * dst_stride_bytes + i] = pixel; + } + else + { + if (pixel > 0x7f) + { + set_mono_pixel(rfd->data, i, j, rfd->width, 1); + } + else + { + set_mono_pixel(rfd->data, i, j, rfd->width, 0); + } + } + } + } + free_pixman_pict(pPicture, src); + return 0; +} + +/******************************************************************************/ +struct rdp_text* +create_rdp_text(ScreenPtr pScreen, int nlists, GlyphListPtr lists, + GlyphPtr* glyphs) +{ + struct rdp_text* rv; + struct rdp_text* rtext; + struct rdp_text* last_rtext; + BoxRec box; + RegionRec reg1; + int n; + int lxoff; + int lyoff; + int count; + int lx; + int ly; + int font_index; + int max_height; + int min_height; + int force_new; + GlyphPtr glyph; + struct rdp_font_char* rfd; + + LLOGLN(10, ("create_rdp_text: nlists %d", nlists)); + + max_height = 0; + min_height = 0x7fffffff; + lx = lists->xOff; + ly = lists->yOff; + lxoff = 0; + lyoff = 0; + force_new = 0; + + rtext = (struct rdp_text*)g_malloc(sizeof(struct rdp_text), 1); + rtext->reg = RegionCreate(NullBox, 0); + rtext->flags = 3; + rtext->mixmode = 0; + rtext->x = lx; + rtext->y = ly; + + rv = rtext; + last_rtext = rtext; + + count = 0; + while (nlists--) + { + LLOGLN(10, ("lists->xOff %d lists->yOff %d", lists->xOff, lists->yOff)); + if (count != 0) + { + lx += lists->xOff; + ly += lists->yOff; + force_new = 1; + } + count++; + n = lists->len; + lists++; + while (n--) + { + glyph = *glyphs++; + /* process glyph here */ + if ((glyph->info.width > 0) && (glyph->info.height > 0)) + { + if (force_new) + { + LLOGLN(10, ("create_rdp_text: too many chars")); + force_new = 0; + rtext = (struct rdp_text*)g_malloc(sizeof(struct rdp_text), 1); + rtext->reg = RegionCreate(NullBox, 0); + rtext->flags = 3; + rtext->mixmode = 0; + rtext->x = lx; + rtext->y = ly; + last_rtext->next = rtext; + last_rtext = rtext; + lxoff = 0; + lyoff = 0; + } + LLOGLN(10, ("x %d y %d width %d height %d xOff %d yOff %d " + "num_chars %d lxoff %d lyoff %d lx %d ly %d", + glyph->info.x, glyph->info.y, + glyph->info.width, glyph->info.height, + glyph->info.xOff, glyph->info.yOff, rtext->num_chars, + lxoff, lyoff, lx, ly)); + rfd = (struct rdp_font_char*)g_malloc(sizeof(struct rdp_font_char), 1); + rtext->chars[rtext->num_chars] = rfd; + box.x1 = lx - glyph->info.x; + box.y1 = ly - glyph->info.y; + box.x2 = box.x1 + glyph->info.width; + box.y2 = box.y1 + glyph->info.height; + if (glyph->info.height > max_height) + { + max_height = glyph->info.height; + } + if (glyph->info.height < min_height) + { + min_height = glyph->info.height; + } + RegionInit(®1, &box, 0); + RegionUnion(rtext->reg, ®1, rtext->reg); + RegionUninit(®1); + + glyph_get_data(pScreen, glyph, rfd); + + rfd->incby = lxoff; + lxoff = glyph->info.xOff; + lyoff = glyph->info.yOff; + rtext->num_chars++; + if (rtext->num_chars > 63) + { + force_new = 1; + } + } + else + { + lxoff += glyph->info.xOff; + lyoff += glyph->info.yOff; + } + lx += glyph->info.xOff; + ly += glyph->info.yOff; + } + } + if (max_height > 10) + { + font_index = 8; + } + else if (max_height < 7) + { + font_index = 6; + } + else + { + font_index = 7; + } + LLOGLN(10, ("create_rdp_text: min_height %d max_height %d font_index %d", + min_height, max_height, font_index)); + rtext = rv; + while (rtext != 0) + { + rtext->font = font_index; + rtext = rtext->next; + } + return rv; +} + +/******************************************************************************/ +int +delete_rdp_text(struct rdp_text* rtext) +{ + int index; + + if (rtext == 0) + { + return 0; + } + for (index = 0; index < rtext->num_chars; index++) + { + if (rtext->chars[index] != 0) + { + g_free(rtext->chars[index]->data); + g_free(rtext->chars[index]); + } + } + RegionDestroy(rtext->reg); + delete_rdp_text(rtext->next); + g_free(rtext); + return 0; +} + +/******************************************************************************/ +static int +get_color(PicturePtr pPicture) +{ + int src_xoff; + int src_yoff; + int rv; + uint32_t* pi32; + pixman_image_t *src; + + src = image_from_pict(pPicture, FALSE, &src_xoff, &src_yoff); + if (src == 0) + { + return 0; + } + pi32 = pixman_image_get_data(src); + if (pi32 == 0) + { + return 0; + } + rv = *pi32; + LLOGLN(10, ("get_color: 0x%8.8x width %d height %d ", rv, + pixman_image_get_width(src), + pixman_image_get_height(src))); + free_pixman_pict(pPicture, src); + return rv; +} + +/******************************************************************************/ +static int +find_or_add_char(int font, struct rdp_font_char* rfd) +{ + int crc; + int index; + int char_index; + int oldest; + + crc = get_crc(rfd->data, rfd->data_bytes); + LLOGLN(10, ("find_or_add_char: crc 0x%8.8x", crc)); + char_index = 0; + oldest = 0x7fffffff; + for (index = 0; index < 250; index++) + { + if ((g_font_cache[font][index].crc == crc) && + (g_font_cache[font][index].width == rfd->width) && + (g_font_cache[font][index].height == rfd->height) && + (g_font_cache[font][index].offset == rfd->offset) && + (g_font_cache[font][index].baseline == rfd->baseline)) + { + g_stamp++; + g_font_cache[font][index].stamp = g_stamp; + LLOGLN(10, ("find_or_add_char: found char at %d %d", font, index)); + return index; + } + if (g_font_cache[font][index].stamp < oldest) + { + oldest = g_font_cache[font][index].stamp; + char_index = index; + } + } + g_stamp++; + g_font_cache[font][char_index].stamp = g_stamp; + g_font_cache[font][char_index].crc = crc; + g_font_cache[font][char_index].width = rfd->width; + g_font_cache[font][char_index].height = rfd->height; + g_font_cache[font][char_index].offset = rfd->offset; + g_font_cache[font][char_index].baseline = rfd->baseline; + LLOGLN(10, ("find_or_add_char: adding char at %d %d", font, char_index)); + if (rfd->bpp == 8) + { + rdpup_add_char_alpha(font, char_index, rfd->offset, rfd->baseline, + rfd->width, rfd->height, + rfd->data, rfd->data_bytes); + } + else + { + rdpup_add_char(font, char_index, rfd->offset, rfd->baseline, + rfd->width, rfd->height, + rfd->data, rfd->data_bytes); + } + return char_index; +} + +/******************************************************************************/ +int +rdp_text_chars_to_data(struct rdp_text* rtext) +{ + int index; + int data_bytes; + int char_index; + struct rdp_font_char* rfd; + + LLOGLN(10, ("rdp_text_chars_to_data: rtext->num_chars %d", rtext->num_chars)); + data_bytes = 0; + for (index = 0; index < rtext->num_chars; index++) + { + rfd = rtext->chars[index]; + if (rfd == 0) + { + LLOGLN(0, ("rdp_text_chars_to_data: error rfd is nil")); + continue; + } + char_index = find_or_add_char(rtext->font, rfd); + rtext->data[data_bytes] = char_index; + data_bytes++; + if (rfd->incby > 127) + { + rtext->data[data_bytes] = 0x80; + data_bytes++; + rtext->data[data_bytes] = (rfd->incby >> 0) & 0xff; + data_bytes++; + rtext->data[data_bytes] = (rfd->incby >> 8) & 0xff; + data_bytes++; + } + else + { + rtext->data[data_bytes] = rfd->incby; + data_bytes++; + } + } + rtext->data_bytes = data_bytes; + return 0; +} + +/******************************************************************************/ +/* + typedef struct _GlyphList { + INT16 xOff; + INT16 yOff; + CARD8 len; + PictFormatPtr format; + } GlyphListRec, *GlyphListPtr; + */ +/* see ghyphstr.h but the follow is not in there + typedef struct _XGlyphInfo { + unsigned short width; + unsigned short height; + short x; + short y; + short xOff; + short yOff; + } XGlyphInfo; + */ +static void +rdpGlyphu(CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, + int nlists, GlyphListPtr lists, GlyphPtr* glyphs, + BoxPtr extents) +{ + BoxRec box; + RegionRec reg1; + RegionRec reg2; + DrawablePtr p; + int dirty_type; + int j; + int num_clips; + int post_process; + int reset_surface; + int got_id; + int fg_color; + WindowPtr pDstWnd; + PixmapPtr pDstPixmap; + rdpPixmapRec* pDstPriv; + rdpPixmapRec* pDirtyPriv; + struct image_data id; + struct rdp_text* rtext; + struct rdp_text* trtext; + + LLOGLN(10, ("rdpGlyphu: xSrc %d ySrc %d", xSrc, ySrc)); + + p = pDst->pDrawable; + + dirty_type = 0; + pDirtyPriv = 0; + post_process = 0; + reset_surface = 0; + got_id = 0; + if (p->type == DRAWABLE_PIXMAP) + { + pDstPixmap = (PixmapPtr)p; + pDstPriv = GETPIXPRIV(pDstPixmap); + if (XRDP_IS_OS(pDstPriv)) + { + rdpup_check_dirty(pDstPixmap, pDstPriv); + post_process = 1; + if (g_do_dirty_os) + { + LLOGLN(10, ("rdpGlyphu: gettig dirty")); + pDstPriv->is_dirty = 1; + dirty_type = RDI_IMGLL; + pDirtyPriv = pDstPriv; + + } + else + { + rdpup_switch_os_surface(pDstPriv->rdpindex); + reset_surface = 1; + rdpup_get_pixmap_image_rect(pDstPixmap, &id); + got_id = 1; + LLOGLN(10, ("rdpGlyphu: offscreen")); + } + } + } + else + { + if (p->type == DRAWABLE_WINDOW) + { + pDstWnd = (WindowPtr)p; + if (pDstWnd->viewable) + { + post_process = 1; + rdpup_get_screen_image_rect(&id); + got_id = 1; + LLOGLN(10, ("rdpGlyphu: screen")); + } + } + } + if (!post_process) + { + return; + } + + rtext = create_rdp_text(pDst->pDrawable->pScreen, nlists, lists, glyphs); + if (rtext == 0) + { + LLOGLN(0, ("rdpGlyphu: create_rdp_text failed")); + return; + } + fg_color = get_color(pSrc); + + LLOGLN(10, ("rdpGlyphu: pDst->clientClipType %d pCompositeClip %p", + pDst->clientClipType, pDst->pCompositeClip)); + + if (pDst->pCompositeClip != 0) + { + box.x1 = p->x + extents->x1; + box.y1 = p->y + extents->y1; + box.x2 = p->x + extents->x2; + box.y2 = p->y + extents->y2; + RegionInit(®1, &box, 0); + RegionInit(®2, NullBox, 0); + RegionCopy(®2, pDst->pCompositeClip); + RegionIntersect(®1, ®1, ®2); + if (dirty_type != 0) + { + LLOGLN(10, ("1")); + draw_item_add_text_region(pDirtyPriv, ®1, fg_color, GXcopy, rtext); + rtext = 0; + } + else if (got_id) + { + num_clips = REGION_NUM_RECTS(®1); + if (num_clips > 0) + { + LLOGLN(10, (" num_clips %d", num_clips)); + rdpup_begin_update(); + rdpup_set_fgcolor(fg_color); + trtext = rtext; + while (trtext != 0) + { + rdp_text_chars_to_data(trtext); + for (j = num_clips - 1; j >= 0; j--) + { + box = REGION_RECTS(®1)[j]; + LLOGLN(10, ("2")); + rdpup_set_clip(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + LLOGLN(10, ("rdpGlyphu: rdpup_draw_text")); + box = RegionExtents(trtext->reg)[0]; + rdpup_draw_text(trtext->font, trtext->flags, trtext->mixmode, + box.x1 + p->x, box.y1 + p->y, + box.x2 + p->x, box.y2 + p->y, + //box.x1 + p->x, box.y1 + p->y, + //box.x2 + p->x, box.y2 + p->y, + 0, 0, 0, 0, + trtext->x + p->x, trtext->y + p->y, + trtext->data, trtext->data_bytes); + } + trtext = trtext->next; + } + rdpup_reset_clip(); + rdpup_end_update(); + } + } + RegionUninit(®1); + RegionUninit(®2); + } + else + { + box.x1 = p->x + extents->x1; + box.y1 = p->y + extents->y1; + box.x2 = p->x + extents->x2; + box.y2 = p->y + extents->y2; + if (dirty_type != 0) + { + RegionInit(®1, &box, 0); + LLOGLN(10, ("3")); + draw_item_add_text_region(pDirtyPriv, ®1, fg_color, GXcopy, rtext); + rtext = 0; + RegionUninit(®1); + } + else if (got_id) + { + rdpup_begin_update(); + LLOGLN(10, ("4")); + rdpup_set_fgcolor(fg_color); + trtext = rtext; + while (trtext != 0) + { + LLOGLN(10, ("rdpGlyphu: rdpup_draw_text")); + rdp_text_chars_to_data(trtext); + box = RegionExtents(trtext->reg)[0]; + rdpup_draw_text(trtext->font, trtext->flags, trtext->mixmode, + box.x1 + p->x, box.y1 + p->y, + box.x2 + p->x, box.y2 + p->y, + //box.x1 + p->x, box.y1 + p->y, + //box.x2 + p->x, box.y2 + p->y, + 0, 0, 0, 0, + trtext->x + p->x, trtext->y + p->y, + trtext->data, trtext->data_bytes); + trtext = trtext->next; + } + rdpup_end_update(); + } + } + if (reset_surface) + { + rdpup_switch_os_surface(-1); + } + delete_rdp_text(rtext); +} + +/******************************************************************************/ +static void +GlyphExtents(int nlist, GlyphListPtr list, GlyphPtr* glyphs, BoxPtr extents) +{ + int x1; + int x2; + int y1; + int y2; + int n; + int x; + int y; + GlyphPtr glyph; + + x = 0; + y = 0; + extents->x1 = MAXSHORT; + extents->x2 = MINSHORT; + extents->y1 = MAXSHORT; + extents->y2 = MINSHORT; + while (nlist--) + { + x += list->xOff; + y += list->yOff; + n = list->len; + list++; + while (n--) + { + glyph = *glyphs++; + x1 = x - glyph->info.x; + if (x1 < MINSHORT) + { + x1 = MINSHORT; + } + y1 = y - glyph->info.y; + if (y1 < MINSHORT) + { + y1 = MINSHORT; + } + x2 = x1 + glyph->info.width; + if (x2 > MAXSHORT) + { + x2 = MAXSHORT; + } + y2 = y1 + glyph->info.height; + if (y2 > MAXSHORT) + { + y2 = MAXSHORT; + } + if (x1 < extents->x1) + { + extents->x1 = x1; + } + if (x2 > extents->x2) + { + extents->x2 = x2; + } + if (y1 < extents->y1) + { + extents->y1 = y1; + } + if (y2 > extents->y2) + { + extents->y2 = y2; + } + x += glyph->info.xOff; + y += glyph->info.yOff; + } + } +} + +/******************************************************************************/ +static void +rdpGlypht(CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, + int nlists, GlyphListPtr lists, GlyphPtr* glyphs) +{ + BoxRec extents; + + GlyphExtents(nlists, lists, glyphs, &extents); + if ((extents.x2 <= extents.x1) || (extents.y2 <= extents.y1)) + { + return; + } + rdpGlyphu(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlists, lists, + glyphs, &extents); +} + +/******************************************************************************/ +/* make sure no glyph is too big */ +/* returns boolean */ +static int +rdpGlyphCheck(int nlist, GlyphListPtr list, GlyphPtr* glyphs) +{ + int n; + GlyphPtr glyph; + + while (nlist--) + { + n = list->len; + list++; + while (n--) + { + glyph = *glyphs++; + if ((glyph->info.width * glyph->info.height) > 8192) + { + LLOGLN(10, ("rdpGlyphCheck: too big")); + return 0; + } + } + } + return 1; +} + +/******************************************************************************/ +void +rdpGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, + INT16 xSrc, INT16 ySrc, int nlists, GlyphListPtr lists, + GlyphPtr* glyphs) +{ + PictureScreenPtr ps; + + LLOGLN(10, ("rdpGlyphs: op %d xSrc %d ySrc %d maskFormat %p", + op, xSrc, ySrc, maskFormat)); + + LLOGLN(10, ("rdpGlyphs: g_do_glyph_cache %d", g_do_glyph_cache)); + + if (g_do_glyph_cache && rdpGlyphCheck(nlists, lists, glyphs)) + { + g_doing_font = 2; + rdpGlypht(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlists, lists, glyphs); + ps = GetPictureScreen(g_pScreen); + ps->Glyphs = g_rdpScreen.Glyphs; + ps->Glyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, + nlists, lists, glyphs); + ps->Glyphs = rdpGlyphs; + } + else + { + g_doing_font = 1; + rdpup_set_hints(1, 1); + ps = GetPictureScreen(g_pScreen); + ps->Glyphs = g_rdpScreen.Glyphs; + ps->Glyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, + nlists, lists, glyphs); + ps->Glyphs = rdpGlyphs; + rdpup_set_hints(0, 1); + } + g_doing_font = 0; + LLOGLN(10, ("rdpGlyphs: out")); +} + +/******************************************************************************/ +int +rdpGlyphInit(void) +{ + memset(&g_font_cache, 0, sizeof(g_font_cache)); + return 0; +} diff --git a/xorg/X11R7.6/rdp/rdpglyph.h b/xorg/X11R7.6/rdp/rdpglyph.h new file mode 100644 index 00000000..6907f9e7 --- /dev/null +++ b/xorg/X11R7.6/rdp/rdpglyph.h @@ -0,0 +1,64 @@ +/* +Copyright 2012-2013 Jay Sorg + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*/ + +#ifndef __RDPGLYPH_H +#define __RDPGLYPH_H + +struct rdp_font_char +{ + int offset; /* x */ + int baseline; /* y */ + int width; /* cx */ + int height; /* cy */ + int incby; + int bpp; + char* data; + int data_bytes; +}; + +struct rdp_text +{ + RegionPtr reg; + int font; + int x; + int y; + int flags; + int mixmode; + char data[256]; + int data_bytes; + struct rdp_font_char* chars[256]; + int num_chars; + struct rdp_text* next; +}; + +int +delete_rdp_text(struct rdp_text* rtext); +int +rdp_text_chars_to_data(struct rdp_text* rtext); + +void +rdpGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, + int nlists, GlyphListPtr lists, GlyphPtr* glyphs); +int +rdpGlyphInit(void); + +#endif diff --git a/xorg/X11R7.6/rdp/rdpinput.c b/xorg/X11R7.6/rdp/rdpinput.c index 39cd78dd..c8739ba0 100644 --- a/xorg/X11R7.6/rdp/rdpinput.c +++ b/xorg/X11R7.6/rdp/rdpinput.c @@ -44,6 +44,12 @@ keyboard and mouse stuff #define DEBUG_OUT_INPUT(arg) ErrorF arg #endif +#define LOG_LEVEL 1 +#define LLOG(_level, _args) \ + do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) +#define LLOGLN(_level, _args) \ + do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) + extern ScreenPtr g_pScreen; /* in rdpmain.c */ extern DeviceIntPtr g_pointer; /* in rdpmain.c */ extern DeviceIntPtr g_keyboard; /* in rdpmain.c */ @@ -58,6 +64,13 @@ static int g_tab_down = 0; /* this is toggled every time num lock key is released, not like the above *_down vars */ static int g_scroll_lock_down = 0; +static OsTimerPtr g_kbtimer = 0; + +static OsTimerPtr g_timer = 0; +static int g_x = 0; +static int g_y = 0; +static int g_timer_schedualed = 0; +static int g_delay_motion = 1; /* turn on or off */ #define MIN_KEY_CODE 8 #define MAX_KEY_CODE 255 @@ -315,10 +328,57 @@ rdpBell(int volume, DeviceIntPtr pDev, pointer ctrl, int cls) } /******************************************************************************/ +static CARD32 +rdpInDeferredUpdateCallback(OsTimerPtr timer, CARD32 now, pointer arg) +{ + //ErrorF("rdpInDeferredUpdateCallback:\n"); + + /* our keyboard device */ + XkbSetRepeatKeys(g_keyboard, -1, AutoRepeatModeOff); + /* the main one for the server */ + XkbSetRepeatKeys(inputInfo.keyboard, -1, AutoRepeatModeOff); + + return 0; +} + +/******************************************************************************/ void rdpChangeKeyboardControl(DeviceIntPtr pDev, KeybdCtrl *ctrl) { + XkbControlsPtr ctrls; + ErrorF("rdpChangeKeyboardControl:\n"); + ctrls = 0; + if (pDev != 0) + { + if (pDev->key != 0) + { + if (pDev->key->xkbInfo != 0) + { + if (pDev->key->xkbInfo->desc != 0) + { + if (pDev->key->xkbInfo->desc->ctrls != 0) + { + ctrls = pDev->key->xkbInfo->desc->ctrls; + } + } + } + } + } + if (ctrls != 0) + { + if (ctrls->enabled_ctrls & XkbRepeatKeysMask) + { + //ErrorF("rdpChangeKeyboardControl: autoRepeat on\n"); + /* schedual to turn off the autorepeat after 100 ms so any app + * polling it will be happy it's on */ + g_kbtimer = TimerSet(g_kbtimer, 0, 100, rdpInDeferredUpdateCallback, 0);\ + } + else + { + //ErrorF("rdpChangeKeyboardControl: autoRepeat off\n"); + } + } } /******************************************************************************/ @@ -407,9 +467,9 @@ rdpMouseCtrl(DeviceIntPtr pDevice, PtrCtrl *pCtrl) int rdpMouseProc(DeviceIntPtr pDevice, int onoff) { - BYTE map[6]; + BYTE map[8]; DevicePtr pDev; - Atom btn_labels[6]; + Atom btn_labels[8]; Atom axes_labels[2]; DEBUG_OUT_INPUT(("rdpMouseProc\n")); @@ -425,17 +485,21 @@ rdpMouseProc(DeviceIntPtr pDevice, int onoff) map[3] = 3; map[4] = 4; map[5] = 5; + map[6] = 6; + map[7] = 7; btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT); btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE); btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT); btn_labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP); btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN); + btn_labels[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT); + btn_labels[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT); axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X); axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y); - InitPointerDeviceStruct(pDev, map, 5, btn_labels, rdpMouseCtrl, + InitPointerDeviceStruct(pDev, map, 7, btn_labels, rdpMouseCtrl, GetMotionHistorySize(), 2, axes_labels); break; @@ -744,12 +808,13 @@ rdpEnqueueMotion(int x, int y) EventListPtr rdp_events; xEvent *pev; + LLOGLN(10, ("rdpEnqueueMotion: x %d y %d", x, y)); # if 0 if (x < 128) { rdpup_begin_update(); - rdpup_send_area(0, 0, 1024, 768); + rdpup_send_area(0, 0, 0, 1024, 768); rdpup_end_update(); } @@ -779,6 +844,7 @@ rdpEnqueueButton(int type, int buttons) EventListPtr rdp_events; xEvent *pev; + LLOGLN(10, ("rdpEnqueueButton:")); i = GetEventList(&rdp_events); n = GetPointerEvents(rdp_events, g_pointer, type, buttons, 0, 0, 0, 0); @@ -809,35 +875,66 @@ rdpEnqueueKey(int type, int scancode) } /******************************************************************************/ +static CARD32 +rdpDeferredInputCallback(OsTimerPtr timer, CARD32 now, pointer arg) +{ + LLOGLN(10, ("rdpDeferredInputCallback:")); + g_timer_schedualed = 0; + rdpEnqueueMotion(g_x, g_y); + return 0; +} + +/******************************************************************************/ void PtrAddEvent(int buttonMask, int x, int y) { int i; int type; int buttons; + int send_now; - rdpEnqueueMotion(x, y); - - for (i = 0; i < 5; i++) + LLOGLN(10, ("PtrAddEvent: x %d y %d", x, y)); + send_now = (buttonMask ^ g_old_button_mask) || (g_delay_motion == 0); + LLOGLN(10, ("PtrAddEvent: send_now %d g_timer_schedualed %d", + send_now, g_timer_schedualed)); + if (send_now) { - if ((buttonMask ^ g_old_button_mask) & (1 << i)) + if (g_timer_schedualed) { - if (buttonMask & (1 << i)) - { - type = ButtonPress; - buttons = i + 1; - rdpEnqueueButton(type, buttons); - } - else + g_timer_schedualed = 0; + TimerCancel(g_timer); + } + rdpEnqueueMotion(x, y); + for (i = 0; i < 5; i++) + { + if ((buttonMask ^ g_old_button_mask) & (1 << i)) { - type = ButtonRelease; - buttons = i + 1; - rdpEnqueueButton(type, buttons); + if (buttonMask & (1 << i)) + { + type = ButtonPress; + buttons = i + 1; + rdpEnqueueButton(type, buttons); + } + else + { + type = ButtonRelease; + buttons = i + 1; + rdpEnqueueButton(type, buttons); + } } } + g_old_button_mask = buttonMask; + } + else + { + g_x = x; + g_y = y; + if (!g_timer_schedualed) + { + g_timer_schedualed = 1; + g_timer = TimerSet(g_timer, 0, 60, rdpDeferredInputCallback, 0); + } } - - g_old_button_mask = buttonMask; } /******************************************************************************/ @@ -916,9 +1013,13 @@ KbdAddEvent(int down, int param1, int param2, int param3, int param4) if (x_scancode > 0) { + /* left or right shift */ + if ((rdp_scancode == 42) || (rdp_scancode == 54)) + { + g_shift_down = down ? x_scancode : 0; + } rdpEnqueueKey(type, x_scancode); } - break; case 56: /* left - right alt button */ @@ -932,6 +1033,7 @@ KbdAddEvent(int down, int param1, int param2, int param3, int param4) x_scancode = 64; /* left alt button */ } + g_alt_down = down ? x_scancode : 0; rdpEnqueueKey(type, x_scancode); break; @@ -1065,6 +1167,14 @@ KbdAddEvent(int down, int param1, int param2, int param3, int param4) rdpEnqueueKey(type, 117); break; + case 89: /* left meta */ + rdpEnqueueKey(type, 156); + break; + + case 90: /* right meta */ + rdpEnqueueKey(type, 156); + break; + default: x_scancode = rdp_scancode + MIN_KEY_CODE; diff --git a/xorg/X11R7.6/rdp/rdpmain.c b/xorg/X11R7.6/rdp/rdpmain.c index f1645cfe..1b924db7 100644 --- a/xorg/X11R7.6/rdp/rdpmain.c +++ b/xorg/X11R7.6/rdp/rdpmain.c @@ -24,6 +24,7 @@ Sets up the functions #include "rdp.h" #include "rdprandr.h" +#include "rdpglyph.h" #if 1 #define DEBUG_OUT(arg) @@ -47,6 +48,9 @@ int g_can_do_pix_to_pix = 0; int g_do_dirty_os = 1; /* delay remoting off screen bitmaps */ int g_do_dirty_ons = 1; /* delay remoting screen */ +int g_do_glyph_cache = 0; /* rdpup.c may set this */ +int g_do_alpha_glyphs = 1; +int g_do_composite = 0; /* rdpup.c may set this */ Bool g_wrapWindow = 1; Bool g_wrapPixmap = 1; @@ -60,6 +64,7 @@ int g_use_rail = 0; int g_con_number = 0; /* increments for each connection */ WindowPtr g_invalidate_window = 0; +int g_doing_font = 0; /* if true, use a unix domain socket instead of a tcp socket */ int g_use_uds = 0; @@ -273,7 +278,8 @@ rdpScreenInit(int index, ScreenPtr pScreen, int argc, char **argv) g_rdpScreen.sizeInBytes = (g_rdpScreen.paddedWidthInBytes * g_rdpScreen.height); ErrorF("buffer size %d\n", g_rdpScreen.sizeInBytes); - g_rdpScreen.pfbMemory = (char *)g_malloc(2048 * 2048 * 4, 1); + g_rdpScreen.pfbMemory = (char *)g_malloc(g_rdpScreen.sizeInBytes, 1); + g_rdpScreen.sizeInBytesAlloc = g_rdpScreen.sizeInBytes; } if (g_rdpScreen.pfbMemory == 0) @@ -397,6 +403,8 @@ rdpScreenInit(int index, ScreenPtr pScreen, int argc, char **argv) if (ps) { + g_rdpScreen.CreatePicture = ps->CreatePicture; + g_rdpScreen.DestroyPicture = ps->DestroyPicture; g_rdpScreen.Composite = ps->Composite; g_rdpScreen.Glyphs = ps->Glyphs; @@ -410,6 +418,8 @@ rdpScreenInit(int index, ScreenPtr pScreen, int argc, char **argv) if (ps) { + ps->CreatePicture = rdpCreatePicture; + ps->DestroyPicture = rdpDestroyPicture; ps->Composite = rdpComposite; ps->Glyphs = rdpGlyphs; } @@ -529,6 +539,8 @@ rdpScreenInit(int index, ScreenPtr pScreen, int argc, char **argv) } + rdpGlyphInit(); + //rdpXvInit(pScreen); ErrorF("rdpScreenInit: ret %d\n", ret); diff --git a/xorg/X11R7.6/rdp/rdpmisc.c b/xorg/X11R7.6/rdp/rdpmisc.c index dc54581a..eb5bedad 100644 --- a/xorg/X11R7.6/rdp/rdpmisc.c +++ b/xorg/X11R7.6/rdp/rdpmisc.c @@ -27,6 +27,59 @@ the rest Bool noFontCacheExtension = 1; +static int g_crc_seed = 0xffffffff; +static int g_crc_table[256] = +{ + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +#define CRC_START(in_crc) (in_crc) = g_crc_seed +#define CRC_PASS(in_pixel, in_crc) \ + (in_crc) = g_crc_table[((in_crc) ^ (in_pixel)) & 0xff] ^ ((in_crc) >> 8) +#define CRC_END(in_crc) (in_crc) = ((in_crc) ^ g_crc_seed) + /******************************************************************************/ /* print a time-stamped message to the log file (stderr). */ void @@ -599,3 +652,19 @@ RegionAroundSegs(RegionPtr reg, xSegment *segs, int nseg) index++; } } + +/******************************************************************************/ +int +get_crc(char* data, int data_bytes) +{ + int crc; + int index; + + CRC_START(crc); + for (index = 0; index < data_bytes; index++) + { + CRC_PASS(data[index], crc); + } + CRC_END(crc); + return crc; +} diff --git a/xorg/X11R7.6/rdp/rdprandr.c b/xorg/X11R7.6/rdp/rdprandr.c index a767b1d8..8b3eb582 100644 --- a/xorg/X11R7.6/rdp/rdprandr.c +++ b/xorg/X11R7.6/rdp/rdprandr.c @@ -156,6 +156,13 @@ rdpRRScreenSetSize(ScreenPtr pScreen, CARD16 width, CARD16 height, ErrorF(" resizing screenPixmap [%p] to %dx%d, currently at %dx%d\n", (void *)screenPixmap, width, height, screenPixmap->drawable.width, screenPixmap->drawable.height); + if (g_rdpScreen.sizeInBytes > g_rdpScreen.sizeInBytesAlloc) + { + g_free(g_rdpScreen.pfbMemory); + g_rdpScreen.pfbMemory = (char*)g_malloc(g_rdpScreen.sizeInBytes, 1); + g_rdpScreen.sizeInBytesAlloc = g_rdpScreen.sizeInBytes; + ErrorF("new buffer size %d\n", g_rdpScreen.sizeInBytes); + } pScreen->ModifyPixmapHeader(screenPixmap, width, height, g_rdpScreen.depth, g_rdpScreen.bitsPerPixel, g_rdpScreen.paddedWidthInBytes, diff --git a/xorg/X11R7.6/rdp/rdpup.c b/xorg/X11R7.6/rdp/rdpup.c index 06c8bd73..52472121 100644 --- a/xorg/X11R7.6/rdp/rdpup.c +++ b/xorg/X11R7.6/rdp/rdpup.c @@ -21,6 +21,12 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "rdp.h" #include "xrdp_rail.h" +#include "rdpglyph.h" + +#include <signal.h> +#include <sys/ipc.h> +#include <sys/shm.h> +#include <sys/types.h> #define LOG_LEVEL 1 #define LLOG(_level, _args) \ @@ -28,6 +34,15 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define LLOGLN(_level, _args) \ do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) +static int g_use_shmem = 1; /* turns on or off */ +static int g_shmemid = 0; +static char *g_shmemptr = 0; +static int g_shmem_lineBytes = 0; +static RegionPtr g_shm_reg = 0; + +static int g_rect_id_ack = 0; +static int g_rect_id = 0; + static int g_listen_sck = 0; static int g_sck = 0; static int g_sck_closed = 0; @@ -53,8 +68,10 @@ extern ScreenPtr g_pScreen; /* from rdpmain.c */ extern int g_Bpp; /* from rdpmain.c */ extern int g_Bpp_mask; /* from rdpmain.c */ extern rdpScreenInfoRec g_rdpScreen; /* from rdpmain.c */ +extern int g_do_glyph_cache; /* from rdpmain.c */ extern int g_can_do_pix_to_pix; /* from rdpmain.c */ extern int g_use_rail; /* from rdpmain.c */ +extern int g_do_composite; /* from rdpmain.c */ /* true is to use unix domain socket */ extern int g_use_uds; /* in rdpmain.c */ @@ -71,9 +88,12 @@ struct rdpup_os_bitmap int stamp; }; +#define USE_MAX_OS_BYTES 1 +#define MAX_OS_BYTES (16 * 1024 * 1024) static struct rdpup_os_bitmap *g_os_bitmaps = 0; static int g_max_os_bitmaps = 0; static int g_os_bitmap_stamp = 0; +static int g_os_bitmap_alloc_size = 0; static int g_pixmap_byte_total = 0; static int g_pixmap_num_used = 0; @@ -123,12 +143,70 @@ static int g_rdp_opcodes[16] = 0xff /* GXset 0xf 1 */ }; +static int g_do_kill_disconnected = 0; /* turn on or off */ +static OsTimerPtr g_dis_timer = 0; +static int g_disconnect_scheduled = 0; +static CARD32 g_disconnect_timeout_s = 60; /* 60 seconds */ +static CARD32 g_disconnect_time_ms = 0; /* time of disconnect in milliseconds */ + +static int g_do_multimon = 0; /* multimon - turn on or off */ + +/******************************************************************************/ +static CARD32 +rdpDeferredDisconnectCallback(OsTimerPtr timer, CARD32 now, pointer arg) +{ + CARD32 lnow_ms; + + LLOGLN(10, ("rdpDeferredDisconnectCallback")); + if (g_connected) + { + /* this should not happen */ + LLOGLN(0, ("rdpDeferredDisconnectCallback: connected")); + if (g_dis_timer != 0) + { + LLOGLN(0, ("rdpDeferredDisconnectCallback: canceling g_dis_timer")); + TimerCancel(g_dis_timer); + TimerFree(g_dis_timer); + g_dis_timer = 0; + } + g_disconnect_scheduled = 0; + return 0; + } + else + { + LLOGLN(10, ("rdpDeferredDisconnectCallback: not connected")); + } + lnow_ms = GetTimeInMillis(); + if (lnow_ms - g_disconnect_time_ms > g_disconnect_timeout_s * 1000) + { + LLOGLN(0, ("rdpDeferredDisconnectCallback: exit X11rdp")); + kill(getpid(), SIGTERM); + return 0; + } + g_dis_timer = TimerSet(g_dis_timer, 0, 1000 * 10, + rdpDeferredDisconnectCallback, 0); + return 0; +} + /*****************************************************************************/ static int rdpup_disconnect(void) { int index; + LLOGLN(0, ("rdpup_disconnect:")); + if (g_do_kill_disconnected) + { + if (!g_disconnect_scheduled) + { + LLOGLN(0, ("rdpup_disconnect: starting g_dis_timer")); + g_dis_timer = TimerSet(g_dis_timer, 0, 1000 * 10, + rdpDeferredDisconnectCallback, 0); + g_disconnect_scheduled = 1; + } + g_disconnect_time_ms = GetTimeInMillis(); + } + RemoveEnabledDevice(g_sck); g_connected = 0; g_tcp_close(g_sck); @@ -151,15 +229,19 @@ rdpup_disconnect(void) } } } + g_os_bitmap_alloc_size = 0; g_max_os_bitmaps = 0; g_free(g_os_bitmaps); g_os_bitmaps = 0; g_use_rail = 0; + g_do_glyph_cache = 0; + g_do_composite = 0; return 0; } /*****************************************************************************/ +/* returns -1 on error */ int rdpup_add_os_bitmap(PixmapPtr pixmap, rdpPixmapPtr priv) { @@ -167,17 +249,32 @@ rdpup_add_os_bitmap(PixmapPtr pixmap, rdpPixmapPtr priv) int rv; int oldest; int oldest_index; + int this_bytes; + LLOGLN(10, ("rdpup_add_os_bitmap:")); if (!g_connected) { + LLOGLN(10, ("rdpup_add_os_bitmap: test error 1")); return -1; } if (g_os_bitmaps == 0) { + LLOGLN(10, ("rdpup_add_os_bitmap: test error 2")); + return -1; + } + + this_bytes = pixmap->devKind * pixmap->drawable.height; + if (this_bytes > MAX_OS_BYTES) + { + LLOGLN(10, ("rdpup_add_os_bitmap: error, too big this_bytes %d " + "width %d height %d", this_bytes, + pixmap->drawable.height, pixmap->drawable.height)); return -1; } + oldest = 0x7fffffff; + oldest_index = -1; rv = -1; index = 0; @@ -194,42 +291,83 @@ rdpup_add_os_bitmap(PixmapPtr pixmap, rdpPixmapPtr priv) rv = index; break; } - + else + { + if (g_os_bitmaps[index].stamp < oldest) + { + oldest = g_os_bitmaps[index].stamp; + oldest_index = index; + } + } index++; } if (rv == -1) { + if (oldest_index == -1) + { + LLOGLN(0, ("rdpup_add_os_bitmap: error")); + } + else + { + LLOGLN(10, ("rdpup_add_os_bitmap: too many pixmaps removing " + "oldest_index %d", oldest_index)); + rdpup_remove_os_bitmap(oldest_index); + rdpup_delete_os_surface(oldest_index); + g_os_bitmaps[oldest_index].used = 1; + g_os_bitmaps[oldest_index].pixmap = pixmap; + g_os_bitmaps[oldest_index].priv = priv; + g_os_bitmaps[oldest_index].stamp = g_os_bitmap_stamp; + g_os_bitmap_stamp++; + g_pixmap_num_used++; + rv = oldest_index; + } + } + + if (rv < 0) + { + LLOGLN(10, ("rdpup_add_os_bitmap: test error 3")); + return rv; + } + + g_os_bitmap_alloc_size += this_bytes; + LLOGLN(10, ("rdpup_add_os_bitmap: this_bytes %d g_os_bitmap_alloc_size %d", + this_bytes, g_os_bitmap_alloc_size)); +#if USE_MAX_OS_BYTES + while (g_os_bitmap_alloc_size > MAX_OS_BYTES) + { + LLOGLN(10, ("rdpup_add_os_bitmap: must delete g_pixmap_num_used %d", + g_pixmap_num_used)); /* find oldest */ oldest = 0x7fffffff; - oldest_index = 0; + oldest_index = -1; index = 0; - while (index < g_max_os_bitmaps) { - if (g_os_bitmaps[index].stamp < oldest) + if (g_os_bitmaps[index].used && (g_os_bitmaps[index].stamp < oldest)) { oldest = g_os_bitmaps[index].stamp; oldest_index = index; } - index++; } - - LLOGLN(10, ("rdpup_add_os_bitmap: evicting old, oldest_index %d", oldest_index)); - /* evict old */ - g_os_bitmaps[oldest_index].priv->status = 0; - g_os_bitmaps[oldest_index].priv->con_number = 0; - /* set new */ - g_os_bitmaps[oldest_index].pixmap = pixmap; - g_os_bitmaps[oldest_index].priv = priv; - g_os_bitmaps[oldest_index].stamp = g_os_bitmap_stamp; - g_os_bitmap_stamp++; - rv = oldest_index; + if (oldest_index == -1) + { + LLOGLN(0, ("rdpup_add_os_bitmap: error 1")); + break; + } + if (oldest_index == rv) + { + LLOGLN(0, ("rdpup_add_os_bitmap: error 2")); + break; + } + rdpup_remove_os_bitmap(oldest_index); + rdpup_delete_os_surface(oldest_index); } - +#endif LLOGLN(10, ("rdpup_add_os_bitmap: new bitmap index %d", rv)); - LLOGLN(10, (" g_pixmap_num_used %d", g_pixmap_num_used)); + LLOGLN(10, ("rdpup_add_os_bitmap: g_pixmap_num_used %d " + "g_os_bitmap_stamp 0x%8.8x", g_pixmap_num_used, g_os_bitmap_stamp)); return rv; } @@ -237,31 +375,84 @@ rdpup_add_os_bitmap(PixmapPtr pixmap, rdpPixmapPtr priv) int rdpup_remove_os_bitmap(int rdpindex) { + PixmapPtr pixmap; + rdpPixmapPtr priv; + int this_bytes; + LLOGLN(10, ("rdpup_remove_os_bitmap: index %d stamp %d", - rdpindex, g_os_bitmaps[rdpindex].stamp)); + rdpindex, g_os_bitmaps[rdpindex].stamp)); if (g_os_bitmaps == 0) { + LLOGLN(10, ("rdpup_remove_os_bitmap: test error 1")); return 1; } if ((rdpindex < 0) && (rdpindex >= g_max_os_bitmaps)) { + LLOGLN(10, ("rdpup_remove_os_bitmap: test error 2")); return 1; } if (g_os_bitmaps[rdpindex].used) { + pixmap = g_os_bitmaps[rdpindex].pixmap; + priv = g_os_bitmaps[rdpindex].priv; + draw_item_remove_all(priv); + this_bytes = pixmap->devKind * pixmap->drawable.height; + g_os_bitmap_alloc_size -= this_bytes; + LLOGLN(10, ("rdpup_remove_os_bitmap: this_bytes %d " + "g_os_bitmap_alloc_size %d", this_bytes, + g_os_bitmap_alloc_size)); g_os_bitmaps[rdpindex].used = 0; g_os_bitmaps[rdpindex].pixmap = 0; g_os_bitmaps[rdpindex].priv = 0; g_pixmap_num_used--; + priv->status = 0; + priv->con_number = 0; + priv->use_count = 0; + } + else + { + LLOGLN(0, ("rdpup_remove_os_bitmap: error")); + } + + LLOGLN(10, ("rdpup_remove_os_bitmap: g_pixmap_num_used %d", + g_pixmap_num_used)); + return 0; +} + +/*****************************************************************************/ +int +rdpup_update_os_use(int rdpindex) +{ + LLOGLN(10, ("rdpup_update_use: index %d stamp %d", + rdpindex, g_os_bitmaps[rdpindex].stamp)); + + if (g_os_bitmaps == 0) + { + return 1; + } + + if ((rdpindex < 0) && (rdpindex >= g_max_os_bitmaps)) + { + return 1; + } + + if (g_os_bitmaps[rdpindex].used) + { + g_os_bitmaps[rdpindex].stamp = g_os_bitmap_stamp; + g_os_bitmap_stamp++; + } + else + { + LLOGLN(0, ("rdpup_update_use: error rdpindex %d", rdpindex)); } - LLOGLN(10, (" g_pixmap_num_used %d", g_pixmap_num_used)); return 0; } + /*****************************************************************************/ /* returns error */ static int @@ -288,12 +479,14 @@ rdpup_send(char *data, int len) } else { + LLOGLN(0, ("rdpup_send: g_tcp_send failed(returned -1)")); rdpup_disconnect(); return 1; } } else if (sent == 0) { + LLOGLN(0, ("rdpup_send: g_tcp_send failed(returned zero)")); rdpup_disconnect(); return 1; } @@ -344,6 +537,9 @@ rdpup_send_msg(struct stream *s) static int rdpup_send_pending(void) { + int rv; + + rv = 0; if (g_connected && g_begin) { LLOGLN(10, ("end %d", g_count)); @@ -351,12 +547,16 @@ rdpup_send_pending(void) out_uint16_le(g_out_s, 4); g_count++; s_mark_end(g_out_s); - rdpup_send_msg(g_out_s); + if (rdpup_send_msg(g_out_s) != 0) + { + LLOGLN(0, ("rdpup_send_pending: rdpup_send_msg failed")); + rv = 1; + } } g_count = 0; g_begin = 0; - return 0; + return rv; } /******************************************************************************/ @@ -367,7 +567,14 @@ rdpDeferredUpdateCallback(OsTimerPtr timer, CARD32 now, pointer arg) if (g_do_dirty_ons) { - rdpup_check_dirty_screen(&g_screenPriv); + if (g_rect_id == g_rect_id_ack) + { + rdpup_check_dirty_screen(&g_screenPriv); + } + else + { + LLOGLN(0, ("rdpDeferredUpdateCallback: skipping")); + } } else { @@ -413,12 +620,14 @@ rdpup_recv(char *data, int len) } else { + LLOGLN(0, ("rdpup_recv: g_tcp_recv failed(returned -1)")); rdpup_disconnect(); return 1; } } else if (rcvd == 0) { + LLOGLN(0, ("rdpup_recv: g_tcp_recv failed(returned 0)")); rdpup_disconnect(); return 1; } @@ -466,6 +675,34 @@ rdpup_recv_msg(struct stream *s) return rv; } +/*****************************************************************************/ +/* wait 'millis' milliseconds for the socket to be able to receive */ +/* returns boolean */ +static int +sck_can_recv(int sck, int millis) +{ + fd_set rfds; + struct timeval time; + int rv; + + time.tv_sec = millis / 1000; + time.tv_usec = (millis * 1000) % 1000000; + FD_ZERO(&rfds); + + if (sck > 0) + { + FD_SET(((unsigned int)sck), &rfds); + rv = select(sck + 1, &rfds, 0, 0, &time); + + if (rv > 0) + { + return 1; + } + } + + return 0; +} + /******************************************************************************/ /* this from miScreenInit @@ -478,6 +715,7 @@ process_screen_size_msg(int width, int height, int bpp) RRScreenSizePtr pSize; int mmwidth; int mmheight; + int bytes; Bool ok; LLOGLN(0, ("process_screen_size_msg: set width %d height %d bpp %d", @@ -507,6 +745,28 @@ process_screen_size_msg(int width, int height, int bpp) g_rdpScreen.rdp_Bpp_mask = 0xffffff; } + if (g_use_shmem) + { + if (g_shmemptr != 0) + { + shmdt(g_shmemptr); + } + bytes = g_rdpScreen.rdp_width * g_rdpScreen.rdp_height * + g_rdpScreen.rdp_Bpp; + g_shmemid = shmget(IPC_PRIVATE, bytes, IPC_CREAT | 0777); + g_shmemptr = shmat(g_shmemid, 0, 0); + shmctl(g_shmemid, IPC_RMID, NULL); + LLOGLN(0, ("process_screen_size_msg: g_shmemid %d g_shmemptr %p", + g_shmemid, g_shmemptr)); + g_shmem_lineBytes = g_rdpScreen.rdp_Bpp * g_rdpScreen.rdp_width; + + if (g_shm_reg != 0) + { + RegionDestroy(g_shm_reg); + } + g_shm_reg = RegionCreate(NullBox, 0); + } + mmwidth = PixelToMM(width); mmheight = PixelToMM(height); @@ -631,6 +891,14 @@ rdpup_send_rail(void) return 0; } +#define XR_BUTTON1 1 +#define XR_BUTTON2 2 +#define XR_BUTTON3 4 +#define XR_BUTTON4 8 +#define XR_BUTTON5 16 +#define XR_BUTTON6 32 +#define XR_BUTTON7 64 + /******************************************************************************/ static int rdpup_process_msg(struct stream *s) @@ -643,6 +911,13 @@ rdpup_process_msg(struct stream *s) int param4; int bytes; int i1; + int flags; + int x; + int y; + int cx; + int cy; + RegionRec reg; + BoxRec box; in_uint16_le(s, msg_type); @@ -672,44 +947,74 @@ rdpup_process_msg(struct stream *s) g_cursor_y = l_bound_by(param2, 0, g_rdpScreen.height - 2); PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y); break; - case 101: - g_button_mask = g_button_mask & (~1); + case 101: /* left button up */ + g_button_mask = g_button_mask & (~XR_BUTTON1); + PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y); + break; + case 102: /* left button down */ + g_cursor_x = l_bound_by(param1, 0, g_rdpScreen.width - 2); + g_cursor_y = l_bound_by(param2, 0, g_rdpScreen.height - 2); + g_button_mask = g_button_mask | XR_BUTTON1; + PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y); + break; + case 103: /* right button up */ + g_button_mask = g_button_mask & (~XR_BUTTON3); PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y); break; - case 102: - g_button_mask = g_button_mask | 1; + case 104: /* right button down */ + g_cursor_x = l_bound_by(param1, 0, g_rdpScreen.width - 2); + g_cursor_y = l_bound_by(param2, 0, g_rdpScreen.height - 2); + g_button_mask = g_button_mask | XR_BUTTON3; PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y); break; - case 103: - g_button_mask = g_button_mask & (~4); + case 105: /* middle button down */ + g_button_mask = g_button_mask & (~XR_BUTTON2); PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y); break; - case 104: - g_button_mask = g_button_mask | 4; + case 106: /* middle button up */ + g_cursor_x = l_bound_by(param1, 0, g_rdpScreen.width - 2); + g_cursor_y = l_bound_by(param2, 0, g_rdpScreen.height - 2); + g_button_mask = g_button_mask | XR_BUTTON2; PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y); break; - case 105: - g_button_mask = g_button_mask & (~2); + case 107: /* button 4 up */ + g_button_mask = g_button_mask & (~XR_BUTTON4); PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y); break; - case 106: - g_button_mask = g_button_mask | 2; + case 108: /* button 4 down */ + g_cursor_x = l_bound_by(param1, 0, g_rdpScreen.width - 2); + g_cursor_y = l_bound_by(param2, 0, g_rdpScreen.height - 2); + g_button_mask = g_button_mask | XR_BUTTON4; PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y); break; - case 107: - g_button_mask = g_button_mask & (~8); + case 109: /* button 5 up */ + g_button_mask = g_button_mask & (~XR_BUTTON5); PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y); break; - case 108: - g_button_mask = g_button_mask | 8; + case 110: /* button 5 down */ + g_cursor_x = l_bound_by(param1, 0, g_rdpScreen.width - 2); + g_cursor_y = l_bound_by(param2, 0, g_rdpScreen.height - 2); + g_button_mask = g_button_mask | XR_BUTTON5; + PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y); + break; + case 111: /* button 6 up */ + g_button_mask = g_button_mask & (~XR_BUTTON6); PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y); break; - case 109: - g_button_mask = g_button_mask & (~16); + case 112: /* button 6 down */ + g_cursor_x = l_bound_by(param1, 0, g_rdpScreen.width - 2); + g_cursor_y = l_bound_by(param2, 0, g_rdpScreen.height - 2); + g_button_mask = g_button_mask | XR_BUTTON6; PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y); break; - case 110: - g_button_mask = g_button_mask | 16; + case 113: /* button 7 up */ + g_button_mask = g_button_mask & (~XR_BUTTON7); + PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y); + break; + case 114: /* button 7 down */ + g_cursor_x = l_bound_by(param1, 0, g_rdpScreen.width - 2); + g_cursor_y = l_bound_by(param2, 0, g_rdpScreen.height - 2); + g_button_mask = g_button_mask | XR_BUTTON7; PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y); break; case 200: @@ -760,8 +1065,28 @@ rdpup_process_msg(struct stream *s) if (g_rdpScreen.client_info.rail_support_level > 0) { g_use_rail = 1; +#ifdef XRDP_WM_RDPUP rdpup_send_rail(); +#endif + } + if (g_rdpScreen.client_info.orders[0x1b]) /* 27 NEG_GLYPH_INDEX_INDEX */ + { + LLOGLN(0, (" client supports glyph cache but server disabled")); + //g_do_glyph_cache = 1; + } + if (g_rdpScreen.client_info.order_flags_ex & 0x100) + { + g_do_composite = 1; + } + if (g_do_glyph_cache) + { + LLOGLN(0, (" using glyph cache")); + } + if (g_do_composite) + { + LLOGLN(0, (" using client composite")); } + LLOGLN(10, ("order_flags_ex 0x%x", g_rdpScreen.client_info.order_flags_ex)); if (g_rdpScreen.client_info.offscreen_cache_entries == 2000) { LLOGLN(0, (" client can do offscreen to offscreen blits")); @@ -780,7 +1105,43 @@ rdpup_process_msg(struct stream *s) { LLOGLN(0, (" client can not do new(color) cursor")); } + if (g_rdpScreen.client_info.monitorCount > 0) + { + LLOGLN(0, (" client can do multimon")); + LLOGLN(0, (" client monitor data, monitorCount= %d", g_rdpScreen.client_info.monitorCount)); + g_do_multimon = 1; + } + else + { + LLOGLN(0, (" client can not do multimon")); + g_do_multimon = 0; + } } + else if (msg_type == 105) + { + LLOGLN(10, ("rdpup_process_msg: got msg 105")); + in_uint32_le(s, flags); + in_uint32_le(s, g_rect_id_ack); + in_uint32_le(s, x); + in_uint32_le(s, y); + in_uint32_le(s, cx); + in_uint32_le(s, cy); + LLOGLN(10, ("rdpup_process_msg: %d %d %d %d", x, y, cx ,cy)); + LLOGLN(10, ("rdpup_process_msg: rect_id %d rect_id_ack %d", g_rect_id, g_rect_id_ack)); + + box.x1 = x; + box.y1 = y; + box.x2 = box.x1 + cx; + box.y2 = box.y1 + cy; + + RegionInit(®, &box, 0); + LLOGLN(10, ("rdpup_process_msg: %d %d %d %d", box.x1, box.y1, box.x2, box.y2)); + RegionSubtract(g_shm_reg, g_shm_reg, ®); + RegionUninit(®); + + } + + else { rdpLog("unknown message type in rdpup_process_msg %d\n", msg_type); @@ -799,6 +1160,10 @@ rdpup_get_screen_image_rect(struct image_data *id) id->Bpp = g_rdpScreen.rdp_Bpp; id->lineBytes = g_rdpScreen.paddedWidthInBytes; id->pixels = g_rdpScreen.pfbMemory; + id->shmem_pixels = g_shmemptr; + id->shmem_id = g_shmemid; + id->shmem_offset = 0; + id->shmem_lineBytes = g_shmem_lineBytes; } /******************************************************************************/ @@ -811,6 +1176,10 @@ rdpup_get_pixmap_image_rect(PixmapPtr pPixmap, struct image_data *id) id->Bpp = g_rdpScreen.rdp_Bpp; id->lineBytes = pPixmap->devKind; id->pixels = (char *)(pPixmap->devPrivate.ptr); + id->shmem_pixels = 0; + id->shmem_id = 0; + id->shmem_offset = 0; + id->shmem_lineBytes = 0; } /******************************************************************************/ @@ -818,6 +1187,7 @@ int rdpup_init(void) { char text[256]; + char *ptext; int i; if (!g_directory_exist("/tmp/.xrdp")) @@ -902,6 +1272,39 @@ rdpup_init(void) } } + ptext = getenv("XRDP_SESMAN_MAX_IDLE_TIME"); + if (ptext != 0) + { + } + ptext = getenv("XRDP_SESMAN_MAX_DISC_TIME"); + if (ptext != 0) + { + i = atoi(ptext); + if (i > 0) + { + g_do_kill_disconnected = 1; + g_disconnect_timeout_s = atoi(ptext); + } + } + ptext = getenv("XRDP_SESMAN_KILL_DISCONNECTED"); + if (ptext != 0) + { + i = atoi(ptext); + if (i != 0) + { + g_do_kill_disconnected = 1; + g_disconnect_timeout_s = 0; + } + } + + if (g_do_kill_disconnected && (g_disconnect_timeout_s < 60)) + { + g_disconnect_timeout_s = 60; + } + + rdpLog("kill disconencted [%d] timeout [%d] sec\n", g_do_kill_disconnected, + g_disconnect_timeout_s); + return 1; } @@ -939,7 +1342,18 @@ rdpup_check(void) g_sck_closed = 0; g_begin = 0; g_con_number++; + rdpGlyphInit(); AddEnabledDevice(g_sck); + + if (g_dis_timer != 0) + { + LLOGLN(0, ("rdpup_check: canceling g_dis_timer")); + TimerCancel(g_dis_timer); + TimerFree(g_dis_timer); + g_dis_timer = 0; + } + g_disconnect_scheduled = 0; + } } @@ -1016,6 +1430,9 @@ rdpup_end_update(void) int rdpup_pre_check(int in_size) { + int rv; + + rv = 0; if (!g_begin) { rdpup_begin_update(); @@ -1024,13 +1441,17 @@ rdpup_pre_check(int in_size) if ((g_out_s->p - g_out_s->data) > (g_out_s->size - (in_size + 20))) { s_mark_end(g_out_s); - rdpup_send_msg(g_out_s); + if (rdpup_send_msg(g_out_s) != 0) + { + LLOGLN(0, ("rdpup_pre_check: rdpup_send_msg failed")); + rv = 1; + } g_count = 0; init_stream(g_out_s, 0); s_push_layer(g_out_s, iso_hdr, 8); } - return 0; + return rv; } /******************************************************************************/ @@ -1256,6 +1677,25 @@ convert_pixels(void *src, void *dst, int num_pixels) /******************************************************************************/ int +alpha_pixels(void* src, void* dst, int num_pixels) +{ + unsigned int* src32; + unsigned char* dst8; + int index; + + src32 = (unsigned int*)src; + dst8 = (unsigned char*)dst; + for (index = 0; index < num_pixels; index++) + { + *dst8 = (*src32) >> 24; + dst8++; + src32++; + } + return 0; +} + +/******************************************************************************/ +int rdpup_set_fgcolor(int fgcolor) { if (g_connected) @@ -1427,6 +1867,26 @@ rdpup_create_os_surface(int rdpindex, int width, int height) /******************************************************************************/ int +rdpup_create_os_surface_bpp(int rdpindex, int width, int height, int bpp) +{ + LLOGLN(10, ("rdpup_create_os_surface_bpp:")); + if (g_connected) + { + LLOGLN(10, (" width %d height %d bpp %d", width, height, bpp)); + rdpup_pre_check(13); + out_uint16_le(g_out_s, 31); + out_uint16_le(g_out_s, 13); + g_count++; + out_uint32_le(g_out_s, rdpindex); + out_uint16_le(g_out_s, width); + out_uint16_le(g_out_s, height); + out_uint8(g_out_s, bpp); + } + return 0; +} + +/******************************************************************************/ +int rdpup_switch_os_surface(int rdpindex) { LLOGLN(10, ("rdpup_switch_os_surface:")); @@ -1559,11 +2019,13 @@ get_single_color(struct image_data *id, int x, int y, int w, int h) } /******************************************************************************/ -/* split the bitmap up into 64 x 64 pixel areas */ +/* split the bitmap up into 64 x 64 pixel areas + or send using shared memory */ void rdpup_send_area(struct image_data *id, int x, int y, int w, int h) { char *s; + char *d; int i; int single_color; int lx; @@ -1571,7 +2033,10 @@ rdpup_send_area(struct image_data *id, int x, int y, int w, int h) int lh; int lw; int size; + int safety; struct image_data lid; + BoxRec box; + RegionRec reg; LLOGLN(10, ("rdpup_send_area: id %p x %d y %d w %d h %d", id, x, y, w, h)); @@ -1628,9 +2093,76 @@ rdpup_send_area(struct image_data *id, int x, int y, int w, int h) if (g_connected && g_begin) { LLOGLN(10, (" rdpup_send_area")); - ly = y; - while (ly < y + h) + if (id->shmem_pixels != 0) + { + LLOGLN(10, ("rdpup_send_area: using shmem")); + box.x1 = x; + box.y1 = y; + box.x2 = box.x1 + w; + box.y2 = box.y1 + h; + LLOGLN(10, ("rdpup_send_area: 1 x %d y %d w %d h %d", x, y, w, h)); + safety = 0; + while (RegionContainsRect(g_shm_reg, &box)) + { + /* instread of rdpup_end_update, call rdpup_send_pending */ + rdpup_send_pending(); + rdpup_begin_update(); + safety++; + if (safety > 100) + { + LLOGLN(0, ("rdpup_send_area: shmem timeout")); + break; + } + if (sck_can_recv(g_sck, 100)) + { + if (rdpup_recv_msg(g_in_s) == 0) + { + rdpup_process_msg(g_in_s); + } + } + } + s = id->pixels; + s += y * id->lineBytes; + s += x * g_Bpp; + d = id->shmem_pixels + id->shmem_offset; + d += y * id->shmem_lineBytes; + d += x * g_rdpScreen.rdp_Bpp; + ly = y; + while (ly < y + h) + { + convert_pixels(s, d, w); + s += id->lineBytes; + d += id->shmem_lineBytes; + ly += 1; + } + size = 36; + rdpup_pre_check(size); + out_uint16_le(g_out_s, 60); + out_uint16_le(g_out_s, size); + g_count++; + LLOGLN(10, ("rdpup_send_area: 2 x %d y %d w %d h %d", x, y, w, h)); + out_uint16_le(g_out_s, x); + out_uint16_le(g_out_s, y); + out_uint16_le(g_out_s, w); + out_uint16_le(g_out_s, h); + out_uint32_le(g_out_s, 0); + g_rect_id++; + out_uint32_le(g_out_s, g_rect_id); + out_uint32_le(g_out_s, id->shmem_id); + out_uint32_le(g_out_s, id->shmem_offset); + out_uint16_le(g_out_s, id->width); + out_uint16_le(g_out_s, id->height); + out_uint16_le(g_out_s, x); + out_uint16_le(g_out_s, y); + RegionInit(®, &box, 0); + RegionUnion(g_shm_reg, g_shm_reg, ®); + RegionUninit(®); + return; + } + + ly = y; + while ((ly < y + h) && g_connected) { lx = x; @@ -1682,6 +2214,103 @@ rdpup_send_area(struct image_data *id, int x, int y, int w, int h) } /******************************************************************************/ +/* split the bitmap up into 64 x 64 pixel areas */ +void +rdpup_send_alpha_area(struct image_data* id, int x, int y, int w, int h) +{ + char* s; + int i; + int lx; + int ly; + int lh; + int lw; + int size; + struct image_data lid; + + LLOGLN(10, ("rdpup_send_alpha_area: id %p x %d y %d w %d h %d", + id, x, y, w, h)); + if (id == 0) + { + rdpup_get_screen_image_rect(&lid); + id = &lid; + } + + if (x >= id->width) + { + return; + } + if (y >= id->height) + { + return; + } + if (x < 0) + { + w += x; + x = 0; + } + if (y < 0) + { + h += y; + y = 0; + } + if (w <= 0) + { + return; + } + if (h <= 0) + { + return; + } + if (x + w > id->width) + { + w = id->width - x; + } + if (y + h > id->height) + { + h = id->height - y; + } + LLOGLN(10, ("%d", w * h)); + if (g_connected && g_begin) + { + LLOGLN(10, (" rdpup_send_area")); + ly = y; + while ((ly < y + h) && g_connected) + { + lx = x; + while ((lx < x + w) && g_connected) + { + lw = MIN(64, (x + w) - lx); + lh = MIN(64, (y + h) - ly); + size = lw * lh + 25; + rdpup_pre_check(size); + out_uint16_le(g_out_s, 32); /* server_paint_rect_bpp */ + out_uint16_le(g_out_s, size); + g_count++; + out_uint16_le(g_out_s, lx); + out_uint16_le(g_out_s, ly); + out_uint16_le(g_out_s, lw); + out_uint16_le(g_out_s, lh); + out_uint32_le(g_out_s, lw * lh); + for (i = 0; i < lh; i++) + { + s = (id->pixels + + ((ly + i) * id->lineBytes) + (lx * g_Bpp)); + alpha_pixels(s, g_out_s->p, lw); + g_out_s->p += lw; + } + out_uint16_le(g_out_s, lw); + out_uint16_le(g_out_s, lh); + out_uint16_le(g_out_s, 0); + out_uint16_le(g_out_s, 0); + out_uint8(g_out_s, 8); + lx += 64; + } + ly += 64; + } + } +} + +/******************************************************************************/ void rdpup_paint_rect_os(int x, int y, int cx, int cy, int rdpindex, int srcx, int srcy) @@ -1772,7 +2401,7 @@ rdpup_create_window(WindowPtr pWindow, rdpWindowRec *priv) out_uint32_le(g_out_s, style); /* style */ out_uint32_le(g_out_s, ext_style); /* extended_style */ flags |= WINDOW_ORDER_FIELD_STYLE; - out_uint32_le(g_out_s, 0); /* show_state */ + out_uint32_le(g_out_s, 0x05); /* show_state */ flags |= WINDOW_ORDER_FIELD_SHOW; out_uint16_le(g_out_s, title_bytes); /* title_info */ out_uint8a(g_out_s, title, title_bytes); @@ -1843,6 +2472,27 @@ rdpup_delete_window(WindowPtr pWindow, rdpWindowRec *priv) } /******************************************************************************/ +void +rdpup_show_window(WindowPtr pWindow, rdpWindowRec* priv, int showState) +{ + LLOGLN(10, ("rdpup_show_window: id 0x%8.8x state 0x%x", pWindow->drawable.id, + showState)); + if (g_connected) + { + int flags = WINDOW_ORDER_TYPE_WINDOW; + + rdpup_pre_check(16); + out_uint16_le(g_out_s, 27); + out_uint16_le(g_out_s, 16); + g_count++; + out_uint32_le(g_out_s, pWindow->drawable.id); + flags |= WINDOW_ORDER_FIELD_SHOW; + out_uint32_le(g_out_s, flags); + out_uint32_le(g_out_s, showState); + } +} + +/******************************************************************************/ int rdpup_check_dirty(PixmapPtr pDirtyPixmap, rdpPixmapRec *pDirtyPriv) { @@ -1854,6 +2504,8 @@ rdpup_check_dirty(PixmapPtr pDirtyPixmap, rdpPixmapRec *pDirtyPriv) xSegment *seg; struct image_data id; struct rdp_draw_item *di; + struct rdp_text* rtext; + struct rdp_text* trtext; if (pDirtyPriv == 0) { @@ -1865,10 +2517,6 @@ rdpup_check_dirty(PixmapPtr pDirtyPixmap, rdpPixmapRec *pDirtyPriv) return 0; } - /* update use time / count */ - g_os_bitmaps[pDirtyPriv->rdpindex].stamp = g_os_bitmap_stamp; - g_os_bitmap_stamp++; - LLOGLN(10, ("rdpup_check_dirty: got dirty")); rdpup_switch_os_surface(pDirtyPriv->rdpindex); rdpup_get_pixmap_image_rect(pDirtyPixmap, &id); @@ -1960,6 +2608,37 @@ rdpup_check_dirty(PixmapPtr pDirtyPixmap, rdpPixmapRec *pDirtyPriv) case RDI_SCRBLT: LLOGLN(10, (" RDI_SCRBLT")); break; + case RDI_TEXT: + LLOGLN(10, (" RDI_TEXT")); + num_clips = REGION_NUM_RECTS(di->reg); + if (num_clips > 0) + { + LLOGLN(10, (" num_clips %d", num_clips)); + rdpup_set_fgcolor(di->u.text.fg_color); + rdpup_set_opcode(di->u.text.opcode); + rtext = di->u.text.rtext; + trtext = rtext; + while (trtext != 0) + { + rdp_text_chars_to_data(trtext); + for (clip_index = num_clips - 1; clip_index >= 0; clip_index--) + { + box = REGION_RECTS(di->reg)[clip_index]; + rdpup_set_clip(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + LLOGLN(10, (" %d %d %d %d", box.x1, box.y1, box.x2, box.y2)); + box = RegionExtents(trtext->reg)[0]; + rdpup_draw_text(trtext->font, trtext->flags, trtext->mixmode, + box.x1, box.y1, box.x2, box.y2, + //box.x1, box.y1, box.x2, box.y2, + 0, 0, 0, 0, + trtext->x, trtext->y, trtext->data, trtext->data_bytes); + } + trtext = trtext->next; + } + } + rdpup_reset_clip(); + rdpup_set_opcode(GXcopy); + break; } di = di->next; @@ -2030,8 +2709,8 @@ rdpup_check_dirty_screen(rdpPixmapRec *pDirtyPriv) for (index = 0; index < count; index++) { box = REGION_RECTS(di->reg)[index]; - LLOGLN(10, (" RDI_IMGLL %d %d %d %d", box.x1, box.y1, - box.x2, box.y2)); + LLOGLN(10, (" RDI_IMGLL x %d y %d w %d h %d", box.x1, box.y1, + box.x2 - box.x1, box.y2 - box.y1)); rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); } @@ -2095,3 +2774,171 @@ rdpup_check_dirty_screen(rdpPixmapRec *pDirtyPriv) pDirtyPriv->is_dirty = 0; return 0; } + +/******************************************************************************/ +int +rdpup_check_alpha_dirty(PixmapPtr pDirtyPixmap, rdpPixmapRec* pDirtyPriv) +{ + struct image_data id; + + LLOGLN(10, ("rdpup_check_alpha_dirty: width %d height %d", + pDirtyPixmap->drawable.width, pDirtyPixmap->drawable.height)); + if (pDirtyPriv == 0) + { + return 0; + } + LLOGLN(10, ("rdpup_check_alpha_dirty: is_alpha_dirty_not %d", + pDirtyPriv->is_alpha_dirty_not)); + if (pDirtyPriv->is_alpha_dirty_not) + { + return 0; + } + pDirtyPriv->is_alpha_dirty_not = 1; + rdpup_switch_os_surface(pDirtyPriv->rdpindex); + rdpup_get_pixmap_image_rect(pDirtyPixmap, &id); + rdpup_begin_update(); + rdpup_send_alpha_area(&id, 0, 0, pDirtyPixmap->drawable.width, + pDirtyPixmap->drawable.height); + rdpup_end_update(); + rdpup_switch_os_surface(-1); + return 0; +} + +/******************************************************************************/ +int +rdpup_add_char(int font, int charactor, short x, short y, int cx, int cy, + char* bmpdata, int bmpdata_bytes) +{ + if (g_connected) + { + LLOGLN(10, (" rdpup_add_char")); + rdpup_pre_check(18 + bmpdata_bytes); + out_uint16_le(g_out_s, 28); /* add char */ + out_uint16_le(g_out_s, 18 + bmpdata_bytes); /* size */ + g_count++; + out_uint16_le(g_out_s, font); + out_uint16_le(g_out_s, charactor); + out_uint16_le(g_out_s, x); + out_uint16_le(g_out_s, y); + out_uint16_le(g_out_s, cx); + out_uint16_le(g_out_s, cy); + out_uint16_le(g_out_s, bmpdata_bytes); + out_uint8a(g_out_s, bmpdata, bmpdata_bytes); + } + return 0; +} + +/******************************************************************************/ +int +rdpup_add_char_alpha(int font, int charactor, short x, short y, int cx, int cy, + char* bmpdata, int bmpdata_bytes) +{ + if (g_connected) + { + LLOGLN(10, (" rdpup_add_char_alpha")); + rdpup_pre_check(18 + bmpdata_bytes); + out_uint16_le(g_out_s, 29); /* add char alpha */ + out_uint16_le(g_out_s, 18 + bmpdata_bytes); /* size */ + g_count++; + out_uint16_le(g_out_s, font); + out_uint16_le(g_out_s, charactor); + out_uint16_le(g_out_s, x); + out_uint16_le(g_out_s, y); + out_uint16_le(g_out_s, cx); + out_uint16_le(g_out_s, cy); + out_uint16_le(g_out_s, bmpdata_bytes); + out_uint8a(g_out_s, bmpdata, bmpdata_bytes); + } + return 0; +} + +/******************************************************************************/ +int +rdpup_draw_text(int font, int flags, int mixmode, + short clip_left, short clip_top, + short clip_right, short clip_bottom, + short box_left, short box_top, + short box_right, short box_bottom, short x, short y, + char* data, int data_bytes) +{ + if (g_connected) + { + LLOGLN(10, (" rdpup_draw_text")); + rdpup_pre_check(32 + data_bytes); + out_uint16_le(g_out_s, 30); /* draw text */ + out_uint16_le(g_out_s, 32 + data_bytes); /* size */ + g_count++; + out_uint16_le(g_out_s, font); + out_uint16_le(g_out_s, flags); + out_uint16_le(g_out_s, mixmode); + out_uint16_le(g_out_s, clip_left); + out_uint16_le(g_out_s, clip_top); + out_uint16_le(g_out_s, clip_right); + out_uint16_le(g_out_s, clip_bottom); + out_uint16_le(g_out_s, box_left); + out_uint16_le(g_out_s, box_top); + out_uint16_le(g_out_s, box_right); + out_uint16_le(g_out_s, box_bottom); + out_uint16_le(g_out_s, x); + out_uint16_le(g_out_s, y); + out_uint16_le(g_out_s, data_bytes); + out_uint8a(g_out_s, data, data_bytes); + } + return 0; +} + +/******************************************************************************/ +int +rdpup_composite(short srcidx, int srcformat, short srcwidth, CARD8 srcrepeat, + PictTransform* srctransform, CARD8 mskflags, + short mskidx, int mskformat, short mskwidth, CARD8 mskrepeat, + CARD8 op, short srcx, short srcy, short mskx, short msky, + short dstx, short dsty, short width, short height, + int dstformat) +{ + if (g_connected) + { + LLOGLN(10, (" rdpup_composite")); + rdpup_pre_check(84); + out_uint16_le(g_out_s, 33); + out_uint16_le(g_out_s, 84); /* size */ + g_count++; + out_uint16_le(g_out_s, srcidx); + out_uint32_le(g_out_s, srcformat); + out_uint16_le(g_out_s, srcwidth); + out_uint8(g_out_s, srcrepeat); + if (srctransform == 0) + { + out_uint8s(g_out_s, 10 * 4); + } + else + { + out_uint32_le(g_out_s, 1); + out_uint32_le(g_out_s, srctransform->matrix[0][0]); + out_uint32_le(g_out_s, srctransform->matrix[0][1]); + out_uint32_le(g_out_s, srctransform->matrix[0][2]); + out_uint32_le(g_out_s, srctransform->matrix[1][0]); + out_uint32_le(g_out_s, srctransform->matrix[1][1]); + out_uint32_le(g_out_s, srctransform->matrix[1][2]); + out_uint32_le(g_out_s, srctransform->matrix[2][0]); + out_uint32_le(g_out_s, srctransform->matrix[2][1]); + out_uint32_le(g_out_s, srctransform->matrix[2][2]); + } + out_uint8(g_out_s, mskflags); + out_uint16_le(g_out_s, mskidx); + out_uint32_le(g_out_s, mskformat); + out_uint16_le(g_out_s, mskwidth); + out_uint8(g_out_s, mskrepeat); + out_uint8(g_out_s, op); + out_uint16_le(g_out_s, srcx); + out_uint16_le(g_out_s, srcy); + out_uint16_le(g_out_s, mskx); + out_uint16_le(g_out_s, msky); + out_uint16_le(g_out_s, dstx); + out_uint16_le(g_out_s, dsty); + out_uint16_le(g_out_s, width); + out_uint16_le(g_out_s, height); + out_uint32_le(g_out_s, dstformat); + } + return 0; +} diff --git a/xrdp/Makefile.am b/xrdp/Makefile.am index ac3b7fe0..83d04a6c 100644 --- a/xrdp/Makefile.am +++ b/xrdp/Makefile.am @@ -1,11 +1,20 @@ EXTRA_DIST = xrdp.ini ad24b.bmp ad256.bmp xrdp24b.bmp xrdp256.bmp sans-10.fv1 cursor0.cur cursor1.cur xrdp.h xrdp_types.h +EXTRA_INCLUDES = +EXTRA_LIBS = +EXTRA_FLAGS = + if XRDP_DEBUG EXTRA_DEFINES = -DXRDP_DEBUG else EXTRA_DEFINES = -DXRDP_NODEBUG endif +if GOT_PREFIX +EXTRA_INCLUDES += -I$(prefix)/include +EXTRA_FLAGS += -L$(prefix)/lib -Wl,-rpath -Wl,$(prefix)/lib +endif + AM_CFLAGS = \ -DXRDP_CFG_PATH=\"${sysconfdir}/xrdp\" \ -DXRDP_SBIN_PATH=\"${sbindir}\" \ @@ -17,7 +26,8 @@ AM_CFLAGS = \ INCLUDES = \ -I$(top_builddir) \ -I$(top_srcdir)/common \ - -I$(top_srcdir)/libxrdp + -I$(top_srcdir)/libxrdp \ + $(EXTRA_INCLUDES) sbin_PROGRAMS = \ xrdp @@ -41,6 +51,9 @@ xrdp_LDADD = \ $(top_builddir)/common/libcommon.la \ $(top_builddir)/libxrdp/libxrdp.la +xrdp_LDFLAGS = \ + $(EXTRA_FLAGS) + xrdpsysconfdir=$(sysconfdir)/xrdp xrdpsysconf_DATA = \ diff --git a/xrdp/xrdp.c b/xrdp/xrdp.c index 0c340e55..887ada68 100644 --- a/xrdp/xrdp.c +++ b/xrdp/xrdp.c @@ -138,7 +138,7 @@ xrdp_child_fork(void) } /*****************************************************************************/ -int APP_CC +int DEFAULT_CC g_is_term(void) { return g_is_wait_obj_set(g_term_event); diff --git a/xrdp/xrdp.h b/xrdp/xrdp.h index 99d5743b..172d417a 100644 --- a/xrdp/xrdp.h +++ b/xrdp/xrdp.h @@ -27,8 +27,8 @@ #include "trans.h" #include "list.h" #include "libxrdpinc.h" -#include "xrdp_types.h" #include "xrdp_constants.h" +#include "xrdp_types.h" #include "defines.h" #include "os_calls.h" #include "ssl_calls.h" @@ -41,7 +41,7 @@ long APP_CC g_xrdp_sync(long (*sync_func)(long param1, long param2), long sync_param1, long sync_param2); -int APP_CC +int DEFAULT_CC g_is_term(void); void APP_CC g_set_term(int in_val); @@ -283,6 +283,20 @@ xrdp_painter_copy(struct xrdp_painter* self, int x, int y, int cx, int cy, int srcx, int srcy); int APP_CC +xrdp_painter_composite(struct xrdp_painter* self, + struct xrdp_bitmap* src, + int srcformat, + int srcwidth, + int srcrepeat, + struct xrdp_bitmap* dst, + int* srctransform, + int mskflags, + struct xrdp_bitmap* msk, + int mskformat, int mskwidth, int mskrepeat, int op, + int srcx, int srcy, int mskx, int msky, + int dstx, int dsty, int width, int height, + int dstformat); +int APP_CC xrdp_painter_line(struct xrdp_painter* self, struct xrdp_bitmap* bitmap, int x1, int y1, int x2, int y2); @@ -374,6 +388,16 @@ int DEFAULT_CC server_paint_rect(struct xrdp_mod* mod, int x, int y, int cx, int cy, char* data, int width, int height, int srcx, int srcy); int DEFAULT_CC +server_paint_rect_bpp(struct xrdp_mod* mod, int x, int y, int cx, int cy, + char* data, int width, int height, int srcx, int srcy, + int bpp); +int DEFAULT_CC +server_composite(struct xrdp_mod* mod, int srcidx, int srcformat, int srcwidth, + int srcrepeat, int* srctransform, int mskflags, int mskidx, + int mskformat, int mskwidth, int mskrepeat, int op, + int srcx, int srcy, int mskx, int msky, + int dstx, int dsty, int width, int height, int dstformat); +int DEFAULT_CC server_set_pointer(struct xrdp_mod* mod, int x, int y, char* data, char* mask); int DEFAULT_CC @@ -434,6 +458,9 @@ int DEFAULT_CC server_create_os_surface(struct xrdp_mod* mod, int id, int width, int height); int DEFAULT_CC +server_create_os_surface_bpp(struct xrdp_mod* mod, int id, + int width, int height, int bpp); +int DEFAULT_CC server_switch_os_surface(struct xrdp_mod* mod, int id); int DEFAULT_CC server_delete_os_surface(struct xrdp_mod* mod, int id); @@ -468,3 +495,7 @@ int DEFAULT_CC server_monitored_desktop(struct xrdp_mod* mod, struct rail_monitored_desktop_order* mdo, int flags); +int DEFAULT_CC +server_add_char_alpha(struct xrdp_mod* mod, int font, int charactor, + int offset, int baseline, + int width, int height, char* data); diff --git a/xrdp/xrdp.ini b/xrdp/xrdp.ini index 9a484dbf..0e8d302b 100644 --- a/xrdp/xrdp.ini +++ b/xrdp/xrdp.ini @@ -13,6 +13,8 @@ tcp_nodelay=yes # regulate if the listening socket use socket option keepalive # if the network connection disappear without close messages the connection will be closed tcp_keepalive=yes +#tcp_send_buffer_bytes=32768 +#tcp_recv_buffer_bytes=32768 #black=000000 #grey=d6d3ce #dark_grey=808080 @@ -32,6 +34,8 @@ tcp_keepalive=yes # You can set the PAM error text in a gateway setup (MAX 256 chars) #pamerrortxt=change your password according to policy at http://url #new_cursors=no +#nego_sec_layer=0 +allow_multimon=true [Logging] LogFile=xrdp.log @@ -112,8 +116,8 @@ ip=ask port=ask3389 [xrdp7] -name=freerdp-any -lib=libxrdpfreerdp1.so +name=neutrinordp-any +lib=libxrdpneutrinordp.so ip=ask port=ask3389 username=ask diff --git a/xrdp/xrdp_bitmap.c b/xrdp/xrdp_bitmap.c index 19620c40..b3faea41 100644 --- a/xrdp/xrdp_bitmap.c +++ b/xrdp/xrdp_bitmap.c @@ -821,6 +821,8 @@ xrdp_bitmap_copy_box_with_crc(struct xrdp_bitmap *self, unsigned char *d8 = (unsigned char *)NULL; unsigned short *s16 = (unsigned short *)NULL; unsigned short *d16 = (unsigned short *)NULL; + unsigned int *s32; + unsigned int *d32; if (self == 0) { @@ -864,16 +866,65 @@ xrdp_bitmap_copy_box_with_crc(struct xrdp_bitmap *self, if (self->bpp == 24) { + s32 = ((unsigned int *)(self->data)) + (self->width * y + x); + d32 = ((unsigned int *)(dest->data)) + (dest->width * desty + destx); + incs = self->width - cx; + incd = dest->width - cx; + for (i = 0; i < cy; i++) { - for (j = 0; j < cx; j++) + j = 0; + while (j < cx - 4) { - pixel = GETPIXEL32(self->data, j + x, i + y, self->width); + pixel = *s32; CRC_PASS(pixel, crc); CRC_PASS(pixel >> 8, crc); CRC_PASS(pixel >> 16, crc); - SETPIXEL32(dest->data, j + destx, i + desty, dest->width, pixel); + *d32 = pixel; + s32++; + d32++; + + pixel = *s32; + CRC_PASS(pixel, crc); + CRC_PASS(pixel >> 8, crc); + CRC_PASS(pixel >> 16, crc); + *d32 = pixel; + s32++; + d32++; + + pixel = *s32; + CRC_PASS(pixel, crc); + CRC_PASS(pixel >> 8, crc); + CRC_PASS(pixel >> 16, crc); + *d32 = pixel; + s32++; + d32++; + + pixel = *s32; + CRC_PASS(pixel, crc); + CRC_PASS(pixel >> 8, crc); + CRC_PASS(pixel >> 16, crc); + *d32 = pixel; + s32++; + d32++; + + j += 4; } + while (j < cx) + { + pixel = *s32; + CRC_PASS(pixel, crc); + CRC_PASS(pixel >> 8, crc); + CRC_PASS(pixel >> 16, crc); + *d32 = pixel; + s32++; + d32++; + + j += 1; + } + + s32 += incs; + d32 += incd; } } else if (self->bpp == 15 || self->bpp == 16) diff --git a/xrdp/xrdp_cache.c b/xrdp/xrdp_cache.c index cac7f114..c57fc2ad 100644 --- a/xrdp/xrdp_cache.c +++ b/xrdp/xrdp_cache.c @@ -21,6 +21,18 @@ #include "xrdp.h" #include "log.h" +#define LLOG_LEVEL 1 +#define LLOGLN(_level, _args) \ + do \ + { \ + if (_level < LLOG_LEVEL) \ + { \ + g_write("xrdp:xrdp_cache [%10.10u]: ", g_time3()); \ + g_writeln _args ; \ + } \ + } \ + while (0) + /*****************************************************************************/ struct xrdp_cache *APP_CC xrdp_cache_create(struct xrdp_wm *owner, @@ -33,16 +45,28 @@ xrdp_cache_create(struct xrdp_wm *owner, self->wm = owner; self->session = session; self->use_bitmap_comp = client_info->use_bitmap_comp; - self->cache1_entries = client_info->cache1_entries; + + self->cache1_entries = MIN(XRDP_MAX_BITMAP_CACHE_IDX, + client_info->cache1_entries); + self->cache1_entries = MAX(self->cache1_entries, 0); self->cache1_size = client_info->cache1_size; - self->cache2_entries = client_info->cache2_entries; + + self->cache2_entries = MIN(XRDP_MAX_BITMAP_CACHE_IDX, + client_info->cache2_entries); + self->cache2_entries = MAX(self->cache2_entries, 0); self->cache2_size = client_info->cache2_size; - self->cache3_entries = client_info->cache3_entries; + + self->cache3_entries = MIN(XRDP_MAX_BITMAP_CACHE_IDX, + client_info->cache3_entries); + self->cache3_entries = MAX(self->cache3_entries, 0); self->cache3_size = client_info->cache3_size; + self->bitmap_cache_persist_enable = client_info->bitmap_cache_persist_enable; self->bitmap_cache_version = client_info->bitmap_cache_version; self->pointer_cache_entries = client_info->pointer_cache_entries; self->xrdp_os_del_list = list_create(); + LLOGLN(10, ("xrdp_cache_create: 0 %d 1 %d 2 %d", + self->cache1_entries, self->cache2_entries, self->cache3_entries)); return self; } @@ -59,9 +83,9 @@ xrdp_cache_delete(struct xrdp_cache *self) } /* free all the cached bitmaps */ - for (i = 0; i < 3; i++) + for (i = 0; i < XRDP_MAX_BITMAP_CACHE_ID; i++) { - for (j = 0; j < 2000; j++) + for (j = 0; j < XRDP_MAX_BITMAP_CACHE_IDX; j++) { xrdp_bitmap_delete(self->bitmap_items[i][j].bitmap); } @@ -98,9 +122,9 @@ xrdp_cache_reset(struct xrdp_cache *self, int j; /* free all the cached bitmaps */ - for (i = 0; i < 3; i++) + for (i = 0; i < XRDP_MAX_BITMAP_CACHE_ID; i++) { - for (j = 0; j < 2000; j++) + for (j = 0; j < XRDP_MAX_BITMAP_CACHE_IDX; j++) { xrdp_bitmap_delete(self->bitmap_items[i][j].bitmap); } @@ -136,6 +160,11 @@ xrdp_cache_reset(struct xrdp_cache *self, return 0; } +#define COMPARE_WITH_CRC(_b1, _b2) \ + ((_b1 != 0) && (_b2 != 0) && (_b1->crc == _b2->crc) && \ + (_b1->bpp == _b2->bpp) && \ + (_b1->width == _b2->width) && (_b1->height == _b2->height)) + /*****************************************************************************/ /* returns cache id */ int APP_CC @@ -170,14 +199,13 @@ xrdp_cache_add_bitmap(struct xrdp_cache *self, struct xrdp_bitmap *bitmap, for (j = 0; j < self->cache1_entries; j++) { #ifdef USE_CRC - - if (xrdp_bitmap_compare_with_crc(self->bitmap_items[i][j].bitmap, bitmap)) + if (COMPARE_WITH_CRC(self->bitmap_items[i][j].bitmap, bitmap)) #else if (xrdp_bitmap_compare(self->bitmap_items[i][j].bitmap, bitmap)) #endif { self->bitmap_items[i][j].stamp = self->bitmap_stamp; - DEBUG(("found bitmap at %d %d", i, j)); + LLOGLN(10, ("found bitmap at %d %d", i, j)); xrdp_bitmap_delete(bitmap); return MAKELONG(j, i); } @@ -190,14 +218,13 @@ xrdp_cache_add_bitmap(struct xrdp_cache *self, struct xrdp_bitmap *bitmap, for (j = 0; j < self->cache2_entries; j++) { #ifdef USE_CRC - - if (xrdp_bitmap_compare_with_crc(self->bitmap_items[i][j].bitmap, bitmap)) + if (COMPARE_WITH_CRC(self->bitmap_items[i][j].bitmap, bitmap)) #else if (xrdp_bitmap_compare(self->bitmap_items[i][j].bitmap, bitmap)) #endif { self->bitmap_items[i][j].stamp = self->bitmap_stamp; - DEBUG(("found bitmap at %d %d", i, j)); + LLOGLN(10, ("found bitmap at %d %d", i, j)); xrdp_bitmap_delete(bitmap); return MAKELONG(j, i); } @@ -210,14 +237,13 @@ xrdp_cache_add_bitmap(struct xrdp_cache *self, struct xrdp_bitmap *bitmap, for (j = 0; j < self->cache3_entries; j++) { #ifdef USE_CRC - - if (xrdp_bitmap_compare_with_crc(self->bitmap_items[i][j].bitmap, bitmap)) + if (COMPARE_WITH_CRC(self->bitmap_items[i][j].bitmap, bitmap)) #else if (xrdp_bitmap_compare(self->bitmap_items[i][j].bitmap, bitmap)) #endif { self->bitmap_items[i][j].stamp = self->bitmap_stamp; - DEBUG(("found bitmap at %d %d", i, j)); + LLOGLN(10, ("found bitmap at %d %d", i, j)); xrdp_bitmap_delete(bitmap); return MAKELONG(j, i); } @@ -225,7 +251,7 @@ xrdp_cache_add_bitmap(struct xrdp_cache *self, struct xrdp_bitmap *bitmap, } else { - log_message(LOG_LEVEL_ERROR,"error in xrdp_cache_add_bitmap, too big(%d)", bmp_size); + log_message(LOG_LEVEL_ERROR,"error in xrdp_cache_add_bitmap, too big(%d) bpp %d", bmp_size, bitmap->bpp); } /* look for oldest */ @@ -276,7 +302,8 @@ xrdp_cache_add_bitmap(struct xrdp_cache *self, struct xrdp_bitmap *bitmap, } } - DEBUG(("adding bitmap at %d %d", cache_id, cache_idx)); + LLOGLN(10, ("adding bitmap at %d %d ptr %p", cache_id, cache_idx, + self->bitmap_items[cache_id][cache_idx].bitmap)); /* set, send bitmap and return */ xrdp_bitmap_delete(self->bitmap_items[cache_id][cache_idx].bitmap); self->bitmap_items[cache_id][cache_idx].bitmap = bitmap; diff --git a/xrdp/xrdp_listen.c b/xrdp/xrdp_listen.c index 965aa50d..5d7edf83 100644 --- a/xrdp/xrdp_listen.c +++ b/xrdp/xrdp_listen.c @@ -66,6 +66,10 @@ xrdp_listen_create(void) { log_message(LOG_LEVEL_ERROR,"xrdp_listen_create: trans_create failed"); } + else + { + self->listen_trans->is_term = g_is_term; + } return self; } @@ -199,19 +203,31 @@ xrdp_listen_get_port_address(char *port, int port_bytes, if (g_strcasecmp(val, "fork") == 0) { val = (char *)list_get_item(values, index); - startup_param->fork = text2bool(val); + startup_param->fork = g_text2bool(val); } if (g_strcasecmp(val, "tcp_nodelay") == 0) { val = (char *)list_get_item(values, index); - *tcp_nodelay = text2bool(val); + *tcp_nodelay = g_text2bool(val); } if (g_strcasecmp(val, "tcp_keepalive") == 0) { val = (char *)list_get_item(values, index); - *tcp_keepalive = text2bool(val); + *tcp_keepalive = g_text2bool(val); + } + + if (g_strcasecmp(val, "tcp_send_buffer_bytes") == 0) + { + val = (char *)list_get_item(values, index); + startup_param->send_buffer_bytes = g_atoi(val); + } + + if (g_strcasecmp(val, "tcp_recv_buffer_bytes") == 0) + { + val = (char *)list_get_item(values, index); + startup_param->recv_buffer_bytes = g_atoi(val); } } } @@ -318,6 +334,7 @@ xrdp_listen_main_loop(struct xrdp_listen *self) tbus done_obj; int tcp_nodelay; int tcp_keepalive; + int bytes; self->status = 1; @@ -352,6 +369,54 @@ xrdp_listen_main_loop(struct xrdp_listen *self) } } + if (self->startup_params->send_buffer_bytes > 0) + { + bytes = self->startup_params->send_buffer_bytes; + log_message(LOG_LEVEL_INFO, "setting send buffer to %d bytes", + bytes); + if (g_sck_set_send_buffer_bytes(self->listen_trans->sck, + bytes) != 0) + { + log_message(LOG_LEVEL_ERROR, "error setting send buffer"); + } + else + { + if (g_sck_get_send_buffer_bytes(self->listen_trans->sck, + &bytes) != 0) + { + log_message(LOG_LEVEL_ERROR, "error getting send buffer"); + } + else + { + log_message(LOG_LEVEL_INFO, "send buffer set to %d bytes", bytes); + } + } + } + + if (self->startup_params->recv_buffer_bytes > 0) + { + bytes = self->startup_params->recv_buffer_bytes; + log_message(LOG_LEVEL_INFO, "setting recv buffer to %d bytes", + bytes); + if (g_sck_set_recv_buffer_bytes(self->listen_trans->sck, + bytes) != 0) + { + log_message(LOG_LEVEL_ERROR, "error setting recv buffer"); + } + else + { + if (g_sck_get_recv_buffer_bytes(self->listen_trans->sck, + &bytes) != 0) + { + log_message(LOG_LEVEL_ERROR, "error getting recv buffer"); + } + else + { + log_message(LOG_LEVEL_INFO, "recv buffer set to %d bytes", bytes); + } + } + } + self->listen_trans->trans_conn_in = xrdp_listen_conn_in; self->listen_trans->callback_data = self; term_obj = g_get_term_event(); /*Global termination event */ diff --git a/xrdp/xrdp_mm.c b/xrdp/xrdp_mm.c index 0a79810b..560ebedb 100644 --- a/xrdp/xrdp_mm.c +++ b/xrdp/xrdp_mm.c @@ -413,6 +413,10 @@ xrdp_mm_setup_mod1(struct xrdp_mm *self) self->mod->server_notify_new_update = server_notify_new_update; self->mod->server_notify_delete = server_notify_delete; self->mod->server_monitored_desktop = server_monitored_desktop; + self->mod->server_add_char_alpha = server_add_char_alpha; + self->mod->server_create_os_surface_bpp = server_create_os_surface_bpp; + self->mod->server_paint_rect_bpp = server_paint_rect_bpp; + self->mod->server_composite = server_composite; } } @@ -677,6 +681,265 @@ xrdp_mm_trans_process_channel_data(struct xrdp_mm *self, struct trans *trans) /*****************************************************************************/ /* returns error + process rail create window order */ +static int APP_CC +xrdp_mm_process_rail_create_window(struct xrdp_mm* self, struct stream* s) +{ + int flags; + int window_id; + int title_bytes; + int index; + int bytes; + int rv; + struct rail_window_state_order rwso; + + g_memset(&rwso, 0, sizeof(rwso)); + in_uint32_le(s, window_id); + + g_writeln("xrdp_mm_process_rail_create_window: 0x%8.8x", window_id); + + in_uint32_le(s, rwso.owner_window_id); + in_uint32_le(s, rwso.style); + in_uint32_le(s, rwso.extended_style); + in_uint32_le(s, rwso.show_state); + in_uint16_le(s, title_bytes); + if (title_bytes > 0) + { + rwso.title_info = g_malloc(title_bytes + 1, 0); + in_uint8a(s, rwso.title_info, title_bytes); + rwso.title_info[title_bytes] = 0; + } + in_uint32_le(s, rwso.client_offset_x); + in_uint32_le(s, rwso.client_offset_y); + in_uint32_le(s, rwso.client_area_width); + in_uint32_le(s, rwso.client_area_height); + in_uint32_le(s, rwso.rp_content); + in_uint32_le(s, rwso.root_parent_handle); + in_uint32_le(s, rwso.window_offset_x); + in_uint32_le(s, rwso.window_offset_y); + in_uint32_le(s, rwso.window_client_delta_x); + in_uint32_le(s, rwso.window_client_delta_y); + in_uint32_le(s, rwso.window_width); + in_uint32_le(s, rwso.window_height); + in_uint16_le(s, rwso.num_window_rects); + if (rwso.num_window_rects > 0) + { + bytes = sizeof(struct rail_window_rect) * rwso.num_window_rects; + rwso.window_rects = (struct rail_window_rect*)g_malloc(bytes, 0); + for (index = 0; index < rwso.num_window_rects; index++) + { + in_uint16_le(s, rwso.window_rects[index].left); + in_uint16_le(s, rwso.window_rects[index].top); + in_uint16_le(s, rwso.window_rects[index].right); + in_uint16_le(s, rwso.window_rects[index].bottom); + } + } + in_uint32_le(s, rwso.visible_offset_x); + in_uint32_le(s, rwso.visible_offset_y); + in_uint16_le(s, rwso.num_visibility_rects); + if (rwso.num_visibility_rects > 0) + { + bytes = sizeof(struct rail_window_rect) * rwso.num_visibility_rects; + rwso.visibility_rects = (struct rail_window_rect*)g_malloc(bytes, 0); + for (index = 0; index < rwso.num_visibility_rects; index++) + { + in_uint16_le(s, rwso.visibility_rects[index].left); + in_uint16_le(s, rwso.visibility_rects[index].top); + in_uint16_le(s, rwso.visibility_rects[index].right); + in_uint16_le(s, rwso.visibility_rects[index].bottom); + } + } + in_uint32_le(s, flags); + rv = libxrdp_orders_init(self->wm->session); + rv = libxrdp_window_new_update(self->wm->session, window_id, &rwso, flags); + rv = libxrdp_orders_send(self->wm->session); + g_free(rwso.title_info); + g_free(rwso.window_rects); + g_free(rwso.visibility_rects); + return rv; +} + +/*****************************************************************************/ +/* returns error + process rail configure window order */ +static int APP_CC +xrdp_mm_process_rail_configure_window(struct xrdp_mm* self, struct stream* s) +{ + int flags; + int window_id; + int index; + int bytes; + int rv; + struct rail_window_state_order rwso; + + g_memset(&rwso, 0, sizeof(rwso)); + in_uint32_le(s, window_id); + + g_writeln("xrdp_mm_process_rail_configure_window: 0x%8.8x", window_id); + + in_uint32_le(s, rwso.client_offset_x); + in_uint32_le(s, rwso.client_offset_y); + in_uint32_le(s, rwso.client_area_width); + in_uint32_le(s, rwso.client_area_height); + in_uint32_le(s, rwso.rp_content); + in_uint32_le(s, rwso.root_parent_handle); + in_uint32_le(s, rwso.window_offset_x); + in_uint32_le(s, rwso.window_offset_y); + in_uint32_le(s, rwso.window_client_delta_x); + in_uint32_le(s, rwso.window_client_delta_y); + in_uint32_le(s, rwso.window_width); + in_uint32_le(s, rwso.window_height); + in_uint16_le(s, rwso.num_window_rects); + if (rwso.num_window_rects > 0) + { + bytes = sizeof(struct rail_window_rect) * rwso.num_window_rects; + rwso.window_rects = (struct rail_window_rect*)g_malloc(bytes, 0); + for (index = 0; index < rwso.num_window_rects; index++) + { + in_uint16_le(s, rwso.window_rects[index].left); + in_uint16_le(s, rwso.window_rects[index].top); + in_uint16_le(s, rwso.window_rects[index].right); + in_uint16_le(s, rwso.window_rects[index].bottom); + } + } + in_uint32_le(s, rwso.visible_offset_x); + in_uint32_le(s, rwso.visible_offset_y); + in_uint16_le(s, rwso.num_visibility_rects); + if (rwso.num_visibility_rects > 0) + { + bytes = sizeof(struct rail_window_rect) * rwso.num_visibility_rects; + rwso.visibility_rects = (struct rail_window_rect*)g_malloc(bytes, 0); + for (index = 0; index < rwso.num_visibility_rects; index++) + { + in_uint16_le(s, rwso.visibility_rects[index].left); + in_uint16_le(s, rwso.visibility_rects[index].top); + in_uint16_le(s, rwso.visibility_rects[index].right); + in_uint16_le(s, rwso.visibility_rects[index].bottom); + } + } + in_uint32_le(s, flags); + rv = libxrdp_orders_init(self->wm->session); + rv = libxrdp_window_new_update(self->wm->session, window_id, &rwso, flags); + rv = libxrdp_orders_send(self->wm->session); + g_free(rwso.window_rects); + g_free(rwso.visibility_rects); + return rv; +} + +/*****************************************************************************/ +/* returns error + process rail destroy window order */ +static int APP_CC +xrdp_mm_process_rail_destroy_window(struct xrdp_mm* self, struct stream* s) +{ + int window_id; + int rv; + + in_uint32_le(s, window_id); + g_writeln("xrdp_mm_process_rail_destroy_window 0x%8.8x", window_id); + rv = libxrdp_orders_init(self->wm->session); + rv = libxrdp_window_delete(self->wm->session, window_id); + rv = libxrdp_orders_send(self->wm->session); + return rv; +} + +/*****************************************************************************/ +/* returns error + process rail update window (show state) order */ +static int APP_CC +xrdp_mm_process_rail_show_window(struct xrdp_mm* self, struct stream* s) +{ + int window_id; + int rv; + int flags; + struct rail_window_state_order rwso; + + g_memset(&rwso, 0, sizeof(rwso)); + in_uint32_le(s, window_id); + in_uint32_le(s, flags); + in_uint32_le(s, rwso.show_state); + g_writeln("xrdp_mm_process_rail_show_window 0x%8.8x %x", window_id, + rwso.show_state); + rv = libxrdp_orders_init(self->wm->session); + rv = libxrdp_window_new_update(self->wm->session, window_id, &rwso, flags); + rv = libxrdp_orders_send(self->wm->session); + return rv; +} + +/*****************************************************************************/ +/* returns error + process rail update window (title) order */ +static int APP_CC +xrdp_mm_process_rail_update_window_text(struct xrdp_mm* self, struct stream* s) +{ + int size; + int flags; + int rv = 0; + int window_id; + struct rail_window_state_order rwso; + + g_writeln("xrdp_mm_process_rail_update_window_text:"); + + in_uint32_le(s, window_id); + in_uint32_le(s, flags); + g_writeln(" update window title info: 0x%8.8x", window_id); + + g_memset(&rwso, 0, sizeof(rwso)); + in_uint32_le(s, size); /* title size */ + rwso.title_info = g_malloc(size + 1, 0); + in_uint8a(s, rwso.title_info, size); + rwso.title_info[size] = 0; + g_writeln(" set window title %s size %d 0x%8.8x", rwso.title_info, size, flags); + rv = libxrdp_orders_init(self->wm->session); + rv = libxrdp_window_new_update(self->wm->session, window_id, &rwso, flags); + rv = libxrdp_orders_send(self->wm->session); + g_writeln(" set window title %s %d", rwso.title_info, rv); + + g_free(rwso.title_info); + + return rv; +} + +/*****************************************************************************/ +/* returns error + process alternate secondary drawing orders for rail channel */ +static int APP_CC +xrdp_mm_process_rail_drawing_orders(struct xrdp_mm* self, struct trans* trans) +{ + struct stream* s; + int order_type; + int rv = 0; + + s = trans_get_in_s(trans); + if (s == 0) + { + return 1; + } + in_uint32_le(s, order_type); + + switch(order_type) + { + case 2: /* create_window */ + xrdp_mm_process_rail_create_window(self, s); + break; + case 4: /* destroy_window */ + xrdp_mm_process_rail_destroy_window(self, s); + break; + case 6: /* show_window */ + rv = xrdp_mm_process_rail_show_window(self, s); + break; + case 8: /* update title info */ + rv = xrdp_mm_process_rail_update_window_text(self, s); + break; + default: + break; + } + + return rv; +} + +/*****************************************************************************/ +/* returns error process a message for the channel handler */ static int APP_CC xrdp_mm_chan_process_msg(struct xrdp_mm *self, struct trans *trans, @@ -708,6 +971,9 @@ xrdp_mm_chan_process_msg(struct xrdp_mm *self, struct trans *trans, case 8: /* channel data */ rv = xrdp_mm_trans_process_channel_data(self, trans); break; + case 10: /* rail alternate secondary drawing orders */ + rv = xrdp_mm_process_rail_drawing_orders(self, trans); + break; default: log_message(LOG_LEVEL_ERROR,"xrdp_mm_chan_process_msg: unknown id %d", id); break; @@ -793,15 +1059,17 @@ xrdp_mm_connect_chansrv(struct xrdp_mm *self, char *ip, char *port) self->usechansrv = 1; /* connect channel redir */ - if ((ip == 0) || (g_strcmp(ip, "127.0.0.1") == 0) || (ip[0] == 0)) + if ((g_strcmp(ip, "127.0.0.1") == 0) || (ip[0] == 0)) { /* unix socket */ self->chan_trans = trans_create(TRANS_MODE_UNIX, 8192, 8192); + self->chan_trans->is_term = g_is_term; } else { /* tcp */ self->chan_trans = trans_create(TRANS_MODE_TCP, 8192, 8192); + self->chan_trans->is_term = g_is_term; } self->chan_trans->trans_data_in = xrdp_mm_chan_data_in; @@ -1486,6 +1754,7 @@ xrdp_mm_connect(struct xrdp_mm *self) ok = 0; trans_delete(self->sesman_trans); self->sesman_trans = trans_create(TRANS_MODE_TCP, 8192, 8192); + self->sesman_trans->is_term = g_is_term; xrdp_mm_get_sesman_port(port, sizeof(port)); g_snprintf(text, 255, "connecting to sesman ip %s port %s", ip, port); xrdp_wm_log_msg(self->wm, text); @@ -1796,6 +2065,79 @@ server_paint_rect(struct xrdp_mod *mod, int x, int y, int cx, int cy, /*****************************************************************************/ int DEFAULT_CC +server_paint_rect_bpp(struct xrdp_mod* mod, int x, int y, int cx, int cy, + char* data, int width, int height, int srcx, int srcy, + int bpp) +{ + struct xrdp_wm* wm; + struct xrdp_bitmap* b; + struct xrdp_painter* p; + + p = (struct xrdp_painter*)(mod->painter); + if (p == 0) + { + return 0; + } + wm = (struct xrdp_wm*)(mod->wm); + b = xrdp_bitmap_create_with_data(width, height, bpp, data, wm); + xrdp_painter_copy(p, b, wm->target_surface, x, y, cx, cy, srcx, srcy); + xrdp_bitmap_delete(b); + return 0; +} + +/*****************************************************************************/ +int DEFAULT_CC +server_composite(struct xrdp_mod* mod, int srcidx, int srcformat, + int srcwidth, int srcrepeat, int* srctransform, + int mskflags, int mskidx, int mskformat, int mskwidth, + int mskrepeat, int op, int srcx, int srcy, + int mskx, int msky, int dstx, int dsty, + int width, int height, int dstformat) +{ + struct xrdp_wm* wm; + struct xrdp_bitmap* b; + struct xrdp_bitmap* msk; + struct xrdp_painter* p; + struct xrdp_os_bitmap_item* bi; + + p = (struct xrdp_painter*)(mod->painter); + if (p == 0) + { + return 0; + } + wm = (struct xrdp_wm*)(mod->wm); + b = 0; + msk = 0; + bi = xrdp_cache_get_os_bitmap(wm->cache, srcidx); + if (bi != 0) + { + b = bi->bitmap; + } + if (mskflags & 1) + { + bi = xrdp_cache_get_os_bitmap(wm->cache, mskidx); + if (bi != 0) + { + msk = bi->bitmap; + } + } + if (b != 0) + { + xrdp_painter_composite(p, b, srcformat, srcwidth, srcrepeat, + wm->target_surface, srctransform, + mskflags, msk, mskformat, mskwidth, mskrepeat, + op, srcx, srcy, mskx, msky, dstx, dsty, + width, height, dstformat); + } + else + { + g_writeln("server_composite: error finding id %d or %d", srcidx, mskidx); + } + return 0; +} + +/*****************************************************************************/ +int DEFAULT_CC server_set_pointer(struct xrdp_mod *mod, int x, int y, char *data, char *mask) { @@ -2030,6 +2372,7 @@ server_add_char(struct xrdp_mod *mod, int font, int charactor, fi.height = height; fi.incby = 0; fi.data = data; + fi.bpp = 1; return libxrdp_orders_send_font(((struct xrdp_wm *)mod->wm)->session, &fi, font, charactor); } @@ -2206,7 +2549,7 @@ is_channel_enabled(char *inName, struct list *names, struct list *values) if ( index >= 0 ) { val = (char *)list_get_item(values, index); - reply = text2bool(val); + reply = g_text2bool(val); if (reply == 0) { log_message(LOG_LEVEL_INFO,"This channel is disabled: %s", inName); @@ -2410,6 +2753,29 @@ server_create_os_surface(struct xrdp_mod *mod, int rdpindex, /*****************************************************************************/ int DEFAULT_CC +server_create_os_surface_bpp(struct xrdp_mod* mod, int rdpindex, + int width, int height, int bpp) +{ + struct xrdp_wm* wm; + struct xrdp_bitmap* bitmap; + int error; + + wm = (struct xrdp_wm*)(mod->wm); + bitmap = xrdp_bitmap_create(width, height, bpp, + WND_TYPE_OFFSCREEN, wm); + error = xrdp_cache_add_os_bitmap(wm->cache, bitmap, rdpindex); + if (error != 0) + { + g_writeln("server_create_os_surface_bpp: xrdp_cache_add_os_bitmap failed"); + return 1; + } + bitmap->item_index = rdpindex; + bitmap->id = rdpindex; + return 0; +} + +/*****************************************************************************/ +int DEFAULT_CC server_switch_os_surface(struct xrdp_mod *mod, int rdpindex) { struct xrdp_wm *wm; @@ -2436,7 +2802,7 @@ server_switch_os_surface(struct xrdp_mod *mod, int rdpindex) bi = xrdp_cache_get_os_bitmap(wm->cache, rdpindex); - if (bi != 0) + if ((bi != 0) && (bi->bitmap != 0)) { //g_writeln("server_switch_os_surface: setting target_surface to rdpid %d", id); wm->target_surface = bi->bitmap; @@ -2627,3 +2993,23 @@ server_monitored_desktop(struct xrdp_mod *mod, wm = (struct xrdp_wm *)(mod->wm); return libxrdp_monitored_desktop(wm->session, mdo, flags); } + +/*****************************************************************************/ +int DEFAULT_CC +server_add_char_alpha(struct xrdp_mod* mod, int font, int charactor, + int offset, int baseline, + int width, int height, char* data) +{ + struct xrdp_font_char fi; + + fi.offset = offset; + fi.baseline = baseline; + fi.width = width; + fi.height = height; + fi.incby = 0; + fi.data = data; + fi.bpp = 8; + return libxrdp_orders_send_font(((struct xrdp_wm*)mod->wm)->session, + &fi, font, charactor); +} + diff --git a/xrdp/xrdp_painter.c b/xrdp/xrdp_painter.c index 4457fee8..b9d1da16 100644 --- a/xrdp/xrdp_painter.c +++ b/xrdp/xrdp_painter.c @@ -849,7 +849,7 @@ xrdp_painter_copy(struct xrdp_painter *self, { w = MIN(64, ((srcx + cx) - i)); h = MIN(64, ((srcy + cy) - j)); - b = xrdp_bitmap_create(w, h, self->wm->screen->bpp, 0, self->wm); + b = xrdp_bitmap_create(w, h, src->bpp, 0, self->wm); xrdp_bitmap_copy_box_with_crc(src, b, i, j, w, h); bitmap_id = xrdp_cache_add_bitmap(self->wm->cache, b, self->wm->hints); cache_id = HIWORD(bitmap_id); @@ -889,6 +889,86 @@ xrdp_painter_copy(struct xrdp_painter *self, /*****************************************************************************/ int APP_CC +xrdp_painter_composite(struct xrdp_painter* self, + struct xrdp_bitmap* src, + int srcformat, + int srcwidth, + int srcrepeat, + struct xrdp_bitmap* dst, + int* srctransform, + int mskflags, + struct xrdp_bitmap* msk, + int mskformat, int mskwidth, int mskrepeat, int op, + int srcx, int srcy, int mskx, int msky, + int dstx, int dsty, int width, int height, int dstformat) +{ + struct xrdp_rect clip_rect; + struct xrdp_rect draw_rect; + struct xrdp_rect rect1; + struct xrdp_rect rect2; + struct xrdp_region* region; + int k; + int dx; + int dy; + int palette_id; + int cache_srcidx; + int cache_mskidx; + + if (self == 0 || src == 0 || dst == 0) + { + return 0; + } + + /* todo data */ + + if (dst->type == WND_TYPE_BITMAP) + { + return 0; + } + + if (src->type == WND_TYPE_OFFSCREEN) + { + xrdp_bitmap_get_screen_clip(dst, self, &clip_rect, &dx, &dy); + region = xrdp_region_create(self->wm); + xrdp_region_add_rect(region, &clip_rect); + dstx += dx; + dsty += dy; + + palette_id = 0; + cache_srcidx = src->item_index; + cache_mskidx = -1; + if (mskflags & 1) + { + if (msk != 0) + { + cache_mskidx = msk->item_index; // todo + } + } + + k = 0; + while (xrdp_region_get_rect(region, k, &rect1) == 0) + { + if (rect_intersect(&rect1, &clip_rect, &rect2)) + { + MAKERECT(rect1, dstx, dsty, width, height); + if (rect_intersect(&rect2, &rect1, &draw_rect)) + { + libxrdp_orders_composite_blt(self->session, cache_srcidx, srcformat, srcwidth, + srcrepeat, srctransform, mskflags, cache_mskidx, + mskformat, mskwidth, mskrepeat, op, srcx, srcy, + mskx, msky, dstx, dsty, width, height, dstformat, + &draw_rect); + } + } + k++; + } + xrdp_region_delete(region); + } + return 0; +} + +/*****************************************************************************/ +int APP_CC xrdp_painter_line(struct xrdp_painter *self, struct xrdp_bitmap *dst, int x1, int y1, int x2, int y2) diff --git a/xrdp/xrdp_process.c b/xrdp/xrdp_process.c index 228bf630..4c52eaac 100644 --- a/xrdp/xrdp_process.c +++ b/xrdp/xrdp_process.c @@ -203,6 +203,9 @@ xrdp_process_main_loop(struct xrdp_process *self) else { g_writeln("xrdp_process_main_loop: libxrdp_process_incomming failed"); + /* this will try to send a disconnect, + maybe should check that connection got far enough */ + libxrdp_disconnect(self->session); } /* Run end in module */ xrdp_process_mod_end(self); diff --git a/xrdp/xrdp_types.h b/xrdp/xrdp_types.h index e7bb7baf..3811b16b 100644 --- a/xrdp/xrdp_types.h +++ b/xrdp/xrdp_types.h @@ -22,6 +22,7 @@ #define LOG_WINDOW_CHAR_PER_LINE 60 #include "xrdp_rail.h" +#include "xrdp_constants.h" #define MAX_NR_CHANNELS 16 #define MAX_CHANNEL_NAME 16 @@ -51,8 +52,10 @@ struct xrdp_mod int (*server_screen_blt)(struct xrdp_mod* v, int x, int y, int cx, int cy, int srcx, int srcy); int (*server_paint_rect)(struct xrdp_mod* v, int x, int y, int cx, int cy, - char* data, int width, int height, int srcx, int srcy); - int (*server_set_pointer)(struct xrdp_mod* v, int x, int y, char* data, char* mask); + char* data, int width, int height, + int srcx, int srcy); + int (*server_set_pointer)(struct xrdp_mod* v, int x, int y, + char* data, char* mask); int (*server_palette)(struct xrdp_mod* v, int* palette); int (*server_msg)(struct xrdp_mod* v, char* msg, int code); int (*server_is_term)(struct xrdp_mod* v); @@ -117,8 +120,23 @@ struct xrdp_mod int flags); int (*server_set_pointer_ex)(struct xrdp_mod* v, int x, int y, char* data, char* mask, int bpp); + int (*server_add_char_alpha)(struct xrdp_mod* mod, int font, int charactor, + int offset, int baseline, + int width, int height, char* data); - long server_dumby[100 - 38]; /* align, 100 minus the number of server + int (*server_create_os_surface_bpp)(struct xrdp_mod* v, int rdpindex, + int width, int height, int bpp); + int (*server_paint_rect_bpp)(struct xrdp_mod* v, int x, int y, int cx, int cy, + char* data, int width, int height, + int srcx, int srcy, int bpp); + int (*server_composite)(struct xrdp_mod* v, int srcidx, int srcformat, + int srcwidth, int srcrepeat, int* srctransform, + int mskflags, int mskidx, int mskformat, + int mskwidth, int mskrepeat, int op, + int srcx, int srcy, int mskx, int msky, + int dstx, int dsty, int width, int height, + int dstformat); + long server_dumby[100 - 42]; /* align, 100 minus the number of server functions above */ /* common */ long handle; /* pointer to self as int */ @@ -185,6 +203,9 @@ struct xrdp_brush_item char pattern[8]; }; +/* moved to xrdp_constants.h +#define XRDP_BITMAP_CACHE_ENTRIES 2048 */ + /* differnce caches */ struct xrdp_cache { @@ -195,7 +216,8 @@ struct xrdp_cache struct xrdp_palette_item palette_items[6]; /* bitmap */ int bitmap_stamp; - struct xrdp_bitmap_item bitmap_items[3][2000]; + struct xrdp_bitmap_item bitmap_items[XRDP_MAX_BITMAP_CACHE_ID] + [XRDP_MAX_BITMAP_CACHE_IDX]; int use_bitmap_comp; int cache1_entries; int cache1_size; @@ -467,4 +489,6 @@ struct xrdp_startup_params int help; int version; int fork; + int send_buffer_bytes; + int recv_buffer_bytes; }; diff --git a/xrdp/xrdp_wm.c b/xrdp/xrdp_wm.c index bfcc7548..bba25c34 100644 --- a/xrdp/xrdp_wm.c +++ b/xrdp/xrdp_wm.c @@ -401,7 +401,7 @@ xrdp_wm_load_static_colors_plus(struct xrdp_wm *self, char *autorun_name) if (g_strcasecmp(val, "black") == 0) { val = (char *)list_get_item(values, index); - self->black = HCOLOR(self->screen->bpp, xrdp_wm_htoi(val)); + self->black = HCOLOR(self->screen->bpp,xrdp_wm_htoi(val)); } else if (g_strcasecmp(val, "grey") == 0) { @@ -455,7 +455,7 @@ xrdp_wm_load_static_colors_plus(struct xrdp_wm *self, char *autorun_name) else if (g_strcasecmp(val, "hidelogwindow") == 0) { val = (char *)list_get_item(values, index); - self->hide_log_window = text2bool(val); + self->hide_log_window = g_text2bool(val); } else if (g_strcasecmp(val, "pamerrortxt") == 0) { @@ -1221,6 +1221,22 @@ xrdp_wm_mouse_click(struct xrdp_wm *self, int x, int y, int but, int down) self->mm->mod->mod_event(self->mm->mod, WM_BUTTON5UP, self->mouse_x, self->mouse_y, 0, 0); } + if (but == 6 && down) + { + self->mm->mod->mod_event(self->mm->mod, WM_BUTTON6DOWN, x, y, 0, 0); + } + else if (but == 6 && !down) + { + self->mm->mod->mod_event(self->mm->mod, WM_BUTTON6UP, x, y, 0, 0); + } + if (but == 7 && down) + { + self->mm->mod->mod_event(self->mm->mod, WM_BUTTON7DOWN, x, y, 0, 0); + } + else if (but == 7 && !down) + { + self->mm->mod->mod_event(self->mm->mod, WM_BUTTON7UP, x, y, 0, 0); + } } } } @@ -1528,18 +1544,48 @@ xrdp_wm_process_input_mouse(struct xrdp_wm *self, int device_flags, } } - if (device_flags == MOUSE_FLAG_BUTTON4 || /* 0x0280 */ - device_flags == 0x0278) + if (device_flags & 0x200) /* PTRFLAGS_WHEEL */ { - xrdp_wm_mouse_click(self, 0, 0, 4, 0); + if (device_flags & 0x100) /* PTRFLAGS_WHEEL_NEGATIVE */ + { + xrdp_wm_mouse_click(self, 0, 0, 5, 0); + } + else + { + xrdp_wm_mouse_click(self, 0, 0, 4, 0); + } } - if (device_flags == MOUSE_FLAG_BUTTON5 || /* 0x0380 */ - device_flags == 0x0388) + return 0; +} + +/*****************************************************************************/ +static int APP_CC +xrdp_wm_process_input_mousex(struct xrdp_wm* self, int device_flags, + int x, int y) +{ + if (device_flags & 0x8000) /* PTRXFLAGS_DOWN */ { - xrdp_wm_mouse_click(self, 0, 0, 5, 0); + if (device_flags & 0x0001) /* PTRXFLAGS_BUTTON1 */ + { + xrdp_wm_mouse_click(self, x, y, 6, 1); + } + else if (device_flags & 0x0002) /* PTRXFLAGS_BUTTON2 */ + { + xrdp_wm_mouse_click(self, x, y, 7, 1); + } + } + else + { + if (device_flags & 0x0001) /* PTRXFLAGS_BUTTON1 */ + { + xrdp_wm_mouse_click(self, x, y, 6, 0); + } + else if (device_flags & 0x0002) /* PTRXFLAGS_BUTTON2 */ + { + xrdp_wm_mouse_click(self, x, y, 7, 0); + } } - return 0; } @@ -1616,6 +1662,9 @@ callback(long id, int msg, long param1, long param2, long param3, long param4) case 0x8001: /* RDP_INPUT_MOUSE */ rv = xrdp_wm_process_input_mouse(wm, param3, param1, param2); break; + case 0x8002: /* RDP_INPUT_MOUSEX (INPUT_EVENT_MOUSEX) */ + rv = xrdp_wm_process_input_mousex(wm, param3, param1, param2); + break; case 0x4444: /* invalidate, this is not from RDP_DATA_PDU_INPUT */ /* like the rest, its from RDP_PDU_DATA with code 33 */ /* its the rdp client asking for a screen update */ diff --git a/xrdpvr/xrdpvr.c b/xrdpvr/xrdpvr.c index 09a0a6b8..a6e7e894 100644 --- a/xrdpvr/xrdpvr.c +++ b/xrdpvr/xrdpvr.c @@ -28,6 +28,49 @@ PLAYER_STATE_INFO g_psi; int g_video_index = -1; int g_audio_index = -1; +/*****************************************************************************/ +/* produce a hex dump */ +void hexdump(char *p, int len) +{ + unsigned char *line; + int i; + int thisline; + int offset; + + line = (unsigned char *)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; + } +} + /** * initialize the media player * @@ -45,12 +88,14 @@ xrdpvr_init_player(void *channel, int stream_id, char *filename) return -1; } +#if 0 /* send metadata from media file to client */ if (xrdpvr_create_metadata_file(channel, filename)) { printf("error sending metadata to client\n"); return -1; } +#endif /* ask client to get video format from media file */ if (xrdpvr_set_video_format(channel, 101)) @@ -244,6 +289,9 @@ xrdpvr_play_media(void *channel, int stream_id, char *filename) return -1; } + g_psi.bsfc = av_bitstream_filter_init("h264_mp4toannexb"); + printf("g_psi.bsfc %p\n", g_psi.bsfc); + return 0; } @@ -252,9 +300,13 @@ static int firstVideoPkt = 1; int xrdpvr_get_frame(void **av_pkt_ret, int *is_video_frame, int *delay_in_us) { - AVPacket *av_pkt; - double dts; + AVPacket *av_pkt; + double dts; + int error; + AVBitStreamFilterContext *bsfc; + AVPacket new_pkt; + //printf("xrdpvr_get_frame:\n"); /* alloc an AVPacket */ if ((av_pkt = (AVPacket *) malloc(sizeof(AVPacket))) == NULL) return -1; @@ -292,6 +344,34 @@ int xrdpvr_get_frame(void **av_pkt_ret, int *is_video_frame, int *delay_in_us) } else if (av_pkt->stream_index == g_video_index) { + + bsfc = g_psi.bsfc; + printf("hi %p\n", bsfc); + while (bsfc != 0) + { + new_pkt = *av_pkt; + error = av_bitstream_filter_filter(bsfc, g_psi.p_video_codec_ctx, 0, + &new_pkt.data, &new_pkt.size, + av_pkt->data, av_pkt->size, + av_pkt->flags & AV_PKT_FLAG_KEY); + //printf("new size %d\n", new_pkt.size); + //hexdump(new_pkt.data, 32); + //printf("old size %d\n", av_pkt->size); + //hexdump(av_pkt->data, 32); + if (error > 0) + { + av_free_packet(av_pkt); + new_pkt.destruct = av_destruct_packet; + } + else if (error < 0) + { + printf("bitstream filter error\n"); + } + *av_pkt = new_pkt; + bsfc = bsfc->next; + } + + dts = av_pkt->dts; //printf("$$$ video raw_dts=%f raw_pts=%f\n", (double) av_pkt->dts, (double) av_pkt->dts); @@ -344,9 +424,14 @@ int send_video_pkt(void *channel, int stream_id, void *pkt_p) int xrdpvr_play_frame(void *channel, int stream_id, int *videoTimeout, int *audioTimeout) { - AVPacket av_pkt; - double dts; - int delay_in_us; + AVPacket av_pkt; + double dts; + int delay_in_us; + int error; + AVBitStreamFilterContext *bsfc; + AVPacket new_pkt; + + printf("xrdpvr_play_frame:\n"); if (av_read_frame(g_psi.p_format_ctx, &av_pkt) < 0) { @@ -381,6 +466,29 @@ int xrdpvr_play_frame(void *channel, int stream_id, int *videoTimeout, int *audi } else if (av_pkt.stream_index == g_video_index) { + bsfc = g_psi.bsfc; + printf("hi %p\n", bsfc); + while (bsfc != 0) + { + new_pkt= av_pkt; + error = av_bitstream_filter_filter(bsfc, g_psi.p_video_codec_ctx, 0, + &new_pkt.data, &new_pkt.size, + av_pkt.data, av_pkt.size, + av_pkt.flags & AV_PKT_FLAG_KEY); +// av_pkt.flags & PKT_FLAG_KEY); + if (error > 0) + { + av_free_packet(&av_pkt); + new_pkt.destruct = av_destruct_packet; + } + else if (error < 0) + { + printf("bitstream filter error\n"); + } + av_pkt = new_pkt; + bsfc = bsfc->next; + } + xrdpvr_send_video_data(channel, stream_id, av_pkt.size, av_pkt.data); dts = av_pkt.dts; diff --git a/xrdpvr/xrdpvr_internal.h b/xrdpvr/xrdpvr_internal.h index ca01941c..17e2acfa 100644 --- a/xrdpvr/xrdpvr_internal.h +++ b/xrdpvr/xrdpvr_internal.h @@ -217,6 +217,8 @@ typedef struct _player_state_info AVFrame *frame; AVPacket avpkt; + AVBitStreamFilterContext *bsfc; + } PLAYER_STATE_INFO; static int xrdpvr_write_to_client(void *channel, STREAM *s); @@ -19,6 +19,16 @@ */ #include "xup.h" +#include "log.h" + +#include <sys/ipc.h> +#include <sys/shm.h> + +#define LOG_LEVEL 1 +#define LLOG(_level, _args) \ + do { if (_level < LOG_LEVEL) { g_write _args ; } } while (0) +#define LLOGLN(_level, _args) \ + do { if (_level < LOG_LEVEL) { g_writeln _args ; } } while (0) /******************************************************************************/ /* returns error */ @@ -128,6 +138,33 @@ lib_mod_start(struct mod *mod, int w, int h, int bpp) } /******************************************************************************/ +static int APP_CC +lib_mod_log_peer(struct mod *mod) +{ + int my_pid; + int pid; + int uid; + int gid; + + my_pid = g_getpid(); + if (g_sck_get_peer_cred(mod->sck, &pid, &uid, &gid) == 0) + { + log_message(LOG_LEVEL_INFO, "lib_mod_log_peer: xrdp_pid=%d connected " + "to X11rdp_pid=%d X11rdp_uid=%d X11rdp_gid=%d " + "client_ip=%s client_port=%s", + my_pid, pid, uid, gid, + mod->client_info.client_addr, + mod->client_info.client_port); + } + else + { + log_message(LOG_LEVEL_ERROR, "lib_mod_log_peer: g_sck_get_peer_cred " + "failed"); + } + return 0; +} + +/******************************************************************************/ /* return error */ int DEFAULT_CC lib_mod_connect(struct mod *mod) @@ -245,6 +282,14 @@ lib_mod_connect(struct mod *mod) if (error == 0) { + if (use_uds) + { + lib_mod_log_peer(mod); + } + } + + if (error == 0) + { /* send version message */ init_stream(s, 8192); s_push_layer(s, iso_hdr, 4); @@ -476,6 +521,25 @@ process_server_window_new_update(struct mod *mod, struct stream *s) /******************************************************************************/ /* return error */ static int APP_CC +process_server_window_show(struct mod* mod, struct stream* s) +{ + int window_id; + int rv; + int flags; + struct rail_window_state_order rwso; + + g_memset(&rwso, 0, sizeof(rwso)); + in_uint32_le(s, window_id); + in_uint32_le(s, flags); + in_uint32_le(s, rwso.show_state); + mod->server_window_new_update(mod, window_id, &rwso, flags); + rv = 0; + return rv; +} + +/******************************************************************************/ +/* return error */ +static int APP_CC process_server_window_delete(struct mod *mod, struct stream *s) { int window_id; @@ -512,7 +576,35 @@ process_server_set_pointer_ex(struct mod *mod, struct stream *s) /******************************************************************************/ /* return error */ -static int +static int APP_CC +send_paint_rect_ack(struct mod *mod, int flags, int x, int y, int cx, int cy, + int frame_id) +{ + int len; + struct stream *s; + + make_stream(s); + init_stream(s, 8192); + s_push_layer(s, iso_hdr, 4); + out_uint16_le(s, 105); + out_uint32_le(s, flags); + out_uint32_le(s, frame_id); + out_uint32_le(s, x); + out_uint32_le(s, y); + out_uint32_le(s, cx); + out_uint32_le(s, cy); + s_mark_end(s); + len = (int)(s->end - s->data); + s_pop_layer(s, iso_hdr); + out_uint32_le(s, len); + lib_send(mod, s->data, len); + free_stream(s); + return 0; +} + +/******************************************************************************/ +/* return error */ +static int APP_CC lib_mod_process_orders(struct mod *mod, int type, struct stream *s) { int rv; @@ -522,12 +614,17 @@ lib_mod_process_orders(struct mod *mod, int type, struct stream *s) int cy; int srcx; int srcy; + int mskx; + int msky; + int dstx; + int dsty; int len_bmpdata; int style; int x1; int y1; int x2; int y2; + int bpp; int rdpid; int hints; int mask; @@ -536,6 +633,33 @@ lib_mod_process_orders(struct mod *mod, int type, struct stream *s) int fgcolor; int bgcolor; int opcode; + int flags; + int shmem_id; + int shmem_offset; + int frame_id; + int charactor; + int font; + int mixmode; + int clip_left; + int clip_top; + int clip_right; + int clip_bottom; + int box_left; + int box_top; + int box_right; + int box_bottom; + int srcrepeat; + int srcidx; + int srcformat; + int srcwidth; + int mskflags; + int mskidx; + int mskformat; + int mskwidth; + int mskrepeat; + int dstformat; + int op; + int transform[10]; char *bmpdata; char cur_data[32 * (32 * 3)]; char cur_mask[32 * (32 / 8)]; @@ -658,9 +782,143 @@ lib_mod_process_orders(struct mod *mod, int type, struct stream *s) case 26: /* server_window_delete */ rv = process_server_window_delete(mod, s); break; + case 27: /* server_window_new_update - show */ + rv = process_server_window_show(mod, s); + break; + case 28: /* server_add_char */ + in_uint16_le(s, font); + in_uint16_le(s, charactor); + in_sint16_le(s, x); + in_sint16_le(s, y); + in_uint16_le(s, cx); + in_uint16_le(s, cy); + in_uint16_le(s, len_bmpdata); + in_uint8p(s, bmpdata, len_bmpdata); + rv = mod->server_add_char(mod, font, charactor, x, y, cx, cy, bmpdata); + break; + case 29: /* server_add_char_alpha */ + in_uint16_le(s, font); + in_uint16_le(s, charactor); + in_sint16_le(s, x); + in_sint16_le(s, y); + in_uint16_le(s, cx); + in_uint16_le(s, cy); + in_uint16_le(s, len_bmpdata); + in_uint8p(s, bmpdata, len_bmpdata); + rv = mod->server_add_char_alpha(mod, font, charactor, x, y, cx, cy, bmpdata); + break; + case 30: /* server_draw_text */ + in_uint16_le(s, font); + in_uint16_le(s, flags); + in_uint16_le(s, mixmode); + in_sint16_le(s, clip_left); + in_sint16_le(s, clip_top); + in_sint16_le(s, clip_right); + in_sint16_le(s, clip_bottom); + in_sint16_le(s, box_left); + in_sint16_le(s, box_top); + in_sint16_le(s, box_right); + in_sint16_le(s, box_bottom); + in_sint16_le(s, x); + in_sint16_le(s, y); + in_uint16_le(s, len_bmpdata); + in_uint8p(s, bmpdata, len_bmpdata); + rv = mod->server_draw_text(mod, font, flags, mixmode, clip_left, clip_top, + clip_right, clip_bottom, box_left, box_top, + box_right, box_bottom, x, y, bmpdata, len_bmpdata); + break; + case 31: /* server_create_os_surface_bpp */ + in_uint32_le(s, rdpid); + in_uint16_le(s, width); + in_uint16_le(s, height); + in_uint8(s, bpp); + rv = mod->server_create_os_surface_bpp(mod, rdpid, width, height, bpp); + break; + case 32: /* server_paint_rect_bpp */ + in_sint16_le(s, x); + in_sint16_le(s, y); + in_uint16_le(s, cx); + in_uint16_le(s, cy); + in_uint32_le(s, len_bmpdata); + in_uint8p(s, bmpdata, len_bmpdata); + in_uint16_le(s, width); + in_uint16_le(s, height); + in_sint16_le(s, srcx); + in_sint16_le(s, srcy); + in_uint8(s, bpp); + rv = mod->server_paint_rect_bpp(mod, x, y, cx, cy, + bmpdata, width, height, + srcx, srcy, bpp); + break; + case 33: + in_uint16_le(s, srcidx); + in_uint32_le(s, srcformat); + in_uint16_le(s, srcwidth); + in_uint8(s, srcrepeat); + g_memcpy(transform, s->p, 40); + in_uint8s(s, 40); + in_uint8(s, mskflags); + in_uint16_le(s, mskidx); + in_uint32_le(s, mskformat); + in_uint16_le(s, mskwidth); + in_uint8(s, mskrepeat); + in_uint8(s, op); + in_sint16_le(s, srcx); + in_sint16_le(s, srcy); + in_sint16_le(s, mskx); + in_sint16_le(s, msky); + in_sint16_le(s, dstx); + in_sint16_le(s, dsty); + in_uint16_le(s, width); + in_uint16_le(s, height); + in_uint32_le(s, dstformat); + rv = mod->server_composite(mod, srcidx, srcformat, srcwidth, srcrepeat, + transform, mskflags, mskidx, mskformat, + mskwidth, mskrepeat, op, srcx, srcy, mskx, msky, + dstx, dsty, width, height, dstformat); + break; case 51: /* server_set_pointer_ex */ rv = process_server_set_pointer_ex(mod, s); break; + case 60: /* server_paint_rect_shmem */ + in_sint16_le(s, x); + in_sint16_le(s, y); + in_uint16_le(s, cx); + in_uint16_le(s, cy); + in_uint32_le(s, flags); + in_uint32_le(s, frame_id); + in_uint32_le(s, shmem_id); + in_uint32_le(s, shmem_offset); + in_uint16_le(s, width); + in_uint16_le(s, height); + in_sint16_le(s, srcx); + in_sint16_le(s, srcy); + bmpdata = 0; + if (flags == 0) /* screen */ + { + if (mod->screen_shmem_id == 0) + { + mod->screen_shmem_id = shmem_id; + mod->screen_shmem_pixels = shmat(mod->screen_shmem_id, 0, 0); + } + if (mod->screen_shmem_pixels != 0) + { + bmpdata = mod->screen_shmem_pixels + shmem_offset; + } + } + if (bmpdata != 0) + { + rv = mod->server_paint_rect(mod, x, y, cx, cy, + bmpdata, width, height, + srcx, srcy); + } + else + { + rv = 1; + } + send_paint_rect_ack(mod, flags, x, y, cx, cy, frame_id); + break; + default: g_writeln("lib_mod_process_orders: unknown order type %d", type); rv = 0; @@ -53,7 +53,8 @@ struct mod int (*server_screen_blt)(struct mod* v, int x, int y, int cx, int cy, int srcx, int srcy); int (*server_paint_rect)(struct mod* v, int x, int y, int cx, int cy, - char* data, int width, int height, int srcx, int srcy); + char* data, int width, int height, + int srcx, int srcy); int (*server_set_cursor)(struct mod* v, int x, int y, char* data, char* mask); int (*server_palette)(struct mod* v, int* palette); int (*server_msg)(struct mod* v, char* msg, int code); @@ -119,8 +120,21 @@ struct mod int flags); int (*server_set_cursor_ex)(struct mod* v, int x, int y, char* data, char* mask, int bpp); + int (*server_add_char_alpha)(struct mod* v, int font, int charactor, + int offset, int baseline, + int width, int height, char* data); + int (*server_create_os_surface_bpp)(struct mod* v, int rdpindex, + int width, int height, int bpp); + int (*server_paint_rect_bpp)(struct mod* v, int x, int y, int cx, int cy, + char* data, int width, int height, + int srcx, int srcy, int bpp); + int (*server_composite)(struct mod* v, int srcidx, int srcformat, int srcwidth, + int srcrepeat, int* srctransform, int mskflags, int mskidx, + int mskformat, int mskwidth, int mskrepeat, int op, + int srcx, int srcy, int mskx, int msky, + int dstx, int dsty, int width, int height, int dstformat); - tbus server_dumby[100 - 38]; /* align, 100 minus the number of server + tbus server_dumby[100 - 42]; /* align, 100 minus the number of server functions above */ /* common */ tbus handle; /* pointer to self as long */ @@ -139,4 +153,6 @@ struct mod tbus sck_obj; int shift_state; struct xrdp_client_info client_info; + int screen_shmem_id; + char *screen_shmem_pixels; }; |