From 4dbe450e390adf6d239f58ecea70fdff80f0251e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Tue, 1 Nov 2011 01:09:38 -0400 Subject: [PATCH] cliprdr: add support for long format names --- channels/cliprdr/cliprdr_format.c | 134 ++++++++++++++++++++++++------ channels/cliprdr/cliprdr_format.h | 2 +- channels/cliprdr/cliprdr_main.c | 7 +- channels/cliprdr/cliprdr_main.h | 13 ++- client/X11/xf_cliprdr.c | 24 +++--- libfreerdp-utils/unicode.c | 2 +- 6 files changed, 141 insertions(+), 41 deletions(-) diff --git a/channels/cliprdr/cliprdr_format.c b/channels/cliprdr/cliprdr_format.c index 290e5a992..b6a5e17ae 100644 --- a/channels/cliprdr/cliprdr_format.c +++ b/channels/cliprdr/cliprdr_format.c @@ -21,9 +21,10 @@ #include #include #include -#include #include +#include #include +#include #include #include @@ -38,8 +39,8 @@ void cliprdr_process_format_list_event(cliprdrPlugin* cliprdr, RDP_CB_FORMAT_LIST_EVENT* cb_event) { - STREAM* s; int i; + STREAM* s; if (cb_event->raw_format_data) { @@ -78,28 +79,107 @@ void cliprdr_process_format_list_event(cliprdrPlugin* cliprdr, RDP_CB_FORMAT_LIS static void cliprdr_send_format_list_response(cliprdrPlugin* cliprdr) { STREAM* s; - s = cliprdr_packet_new(CB_FORMAT_LIST_RESPONSE, CB_RESPONSE_OK, 0); cliprdr_packet_send(cliprdr, s); } -void cliprdr_process_format_list(cliprdrPlugin* cliprdr, STREAM* s, uint32 dataLen) +void cliprdr_process_short_format_names(cliprdrPlugin* cliprdr, STREAM* s, uint32 length, uint16 flags) +{ + boolean ascii; + int num_formats; + uint8* end_mark; + CLIPRDR_FORMAT_NAME* format_name; + + num_formats = length / 36; + + if (num_formats * 36 != length) + DEBUG_WARN("dataLen %d not divided by 36!", length); + + ascii = (flags & CB_ASCII_NAMES) ? True : False; + + stream_get_mark(s, end_mark); + end_mark += length; + + cliprdr->format_names = (CLIPRDR_FORMAT_NAME*) xmalloc(sizeof(CLIPRDR_FORMAT_NAME) * num_formats); + cliprdr->num_format_names = num_formats; + format_name = cliprdr->format_names; + + while (s->p < end_mark) + { + stream_read_uint32(s, format_name->id); + + if (ascii) + { + format_name->name = xstrdup((char*) s->p); + format_name->length = strlen(format_name->name); + } + else + { + format_name->name = freerdp_uniconv_in(cliprdr->uniconv, s->p, 32); + format_name->length = strlen(format_name->name); + } + + stream_seek(s, 32); + + format_name++; + } +} + +void cliprdr_process_long_format_names(cliprdrPlugin* cliprdr, STREAM* s, uint32 length, uint16 flags) +{ + int num_formats; + uint8* start_mark; + uint8* end_mark; + uint16 terminator; + CLIPRDR_FORMAT_NAME* format_name; + + num_formats = 0; + stream_get_mark(s, start_mark); + stream_get_mark(s, end_mark); + end_mark += length; + + while (s->p < end_mark) + { + stream_seek_uint32(s); + + do + { + stream_read_uint16(s, terminator); + } + while (terminator != 0x0000); + + num_formats++; + } + + stream_set_mark(s, start_mark); + + cliprdr->format_names = (CLIPRDR_FORMAT_NAME*) xmalloc(sizeof(CLIPRDR_FORMAT_NAME) * num_formats); + cliprdr->num_format_names = num_formats; + format_name = cliprdr->format_names; + + while (s->p < end_mark) + { + stream_read_uint32(s, format_name->id); + + format_name->name = freerdp_uniconv_in(cliprdr->uniconv, s->p, 32); + format_name->length = strlen(format_name->name); + stream_seek(s, format_name->length); + + format_name++; + } +} + +void cliprdr_process_format_list(cliprdrPlugin* cliprdr, STREAM* s, uint32 dataLen, uint16 msgFlags) { int i; uint32 format; - int num_formats; boolean supported; + CLIPRDR_FORMAT_NAME* format_name; RDP_CB_FORMAT_LIST_EVENT* cb_event; cb_event = (RDP_CB_FORMAT_LIST_EVENT*) freerdp_event_new(RDP_EVENT_CLASS_CLIPRDR, RDP_EVENT_TYPE_CB_FORMAT_LIST, NULL, NULL); - /* TODO: support long format names */ - - num_formats = dataLen / 36; - cb_event->formats = (uint32*) xmalloc(sizeof(uint32) * num_formats); - cb_event->num_formats = 0; - if (dataLen > 0) { cb_event->raw_format_data = (uint8*) xmalloc(dataLen); @@ -107,13 +187,19 @@ void cliprdr_process_format_list(cliprdrPlugin* cliprdr, STREAM* s, uint32 dataL cb_event->raw_format_data_size = dataLen; } - if (num_formats * 36 != dataLen) - DEBUG_WARN("dataLen %d not divided by 36!", dataLen); + if (cliprdr->use_long_format_names) + cliprdr_process_long_format_names(cliprdr, s, dataLen, msgFlags); + else + cliprdr_process_short_format_names(cliprdr, s, dataLen, msgFlags); - for (i = 0; i < num_formats; i++) + format_name = cliprdr->format_names; + cb_event->num_formats = cliprdr->num_format_names; + cb_event->formats = (uint32*) xmalloc(sizeof(uint32) * cb_event->num_formats); + + for (i = 0; i < cliprdr->num_format_names; i++) { supported = True; - stream_read_uint32(s, format); + format = format_name->id; switch (format) { @@ -123,22 +209,22 @@ void cliprdr_process_format_list(cliprdrPlugin* cliprdr, STREAM* s, uint32 dataL break; default: - if (memcmp(stream_get_tail(s), CFSTR_HTML, sizeof(CFSTR_HTML)) == 0) + if (strcmp(format_name->name, "HTML Format") == 0) { format = CB_FORMAT_HTML; break; } - if (memcmp(stream_get_tail(s), CFSTR_PNG, sizeof(CFSTR_PNG)) == 0) + if (strcmp(format_name->name, "PNG") == 0) { format = CB_FORMAT_PNG; break; } - if (memcmp(stream_get_tail(s), CFSTR_JPEG, sizeof(CFSTR_JPEG)) == 0) + if (strcmp(format_name->name, "JFIF") == 0) { format = CB_FORMAT_JPEG; break; } - if (memcmp(stream_get_tail(s), CFSTR_GIF, sizeof(CFSTR_GIF)) == 0) + if (strcmp(format_name->name, "GIF") == 0) { format = CB_FORMAT_GIF; break; @@ -147,10 +233,11 @@ void cliprdr_process_format_list(cliprdrPlugin* cliprdr, STREAM* s, uint32 dataL supported = False; break; } - stream_seek(s, 32); if (supported) cb_event->formats[cb_event->num_formats++] = format; + + format_name++; } svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (RDP_EVENT*) cb_event); @@ -172,11 +259,11 @@ void cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, STREAM* s) { RDP_CB_DATA_REQUEST_EVENT* cb_event; - cb_event = (RDP_CB_DATA_REQUEST_EVENT*)freerdp_event_new(RDP_EVENT_CLASS_CLIPRDR, + cb_event = (RDP_CB_DATA_REQUEST_EVENT*) freerdp_event_new(RDP_EVENT_CLASS_CLIPRDR, RDP_EVENT_TYPE_CB_DATA_REQUEST, NULL, NULL); stream_read_uint32(s, cb_event->format); - svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (RDP_EVENT*)cb_event); + svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (RDP_EVENT*) cb_event); } void cliprdr_process_format_data_response_event(cliprdrPlugin* cliprdr, RDP_CB_DATA_RESPONSE_EVENT* cb_event) @@ -199,7 +286,6 @@ void cliprdr_process_format_data_response_event(cliprdrPlugin* cliprdr, RDP_CB_D void cliprdr_process_format_data_request_event(cliprdrPlugin* cliprdr, RDP_CB_DATA_REQUEST_EVENT* cb_event) { STREAM* s; - s = cliprdr_packet_new(CB_FORMAT_DATA_REQUEST, 0, 4); stream_write_uint32(s, cb_event->format); cliprdr_packet_send(cliprdr, s); @@ -215,7 +301,7 @@ void cliprdr_process_format_data_response(cliprdrPlugin* cliprdr, STREAM* s, uin if (dataLen > 0) { cb_event->size = dataLen; - cb_event->data = (uint8*)xmalloc(dataLen); + cb_event->data = (uint8*) xmalloc(dataLen); memcpy(cb_event->data, stream_get_tail(s), dataLen); } diff --git a/channels/cliprdr/cliprdr_format.h b/channels/cliprdr/cliprdr_format.h index 280aa2bc6..6af05d79e 100644 --- a/channels/cliprdr/cliprdr_format.h +++ b/channels/cliprdr/cliprdr_format.h @@ -22,7 +22,7 @@ #define __CLIPRDR_FORMAT_H void cliprdr_process_format_list_event(cliprdrPlugin* cliprdr, RDP_CB_FORMAT_LIST_EVENT* cb_event); -void cliprdr_process_format_list(cliprdrPlugin* cliprdr, STREAM* data_in, uint32 dataLen); +void cliprdr_process_format_list(cliprdrPlugin* cliprdr, STREAM* s, uint32 dataLen, uint16 msgFlags); void cliprdr_process_format_list_response(cliprdrPlugin* cliprdr, uint16 msgFlags); void cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, STREAM* data_in); diff --git a/channels/cliprdr/cliprdr_main.c b/channels/cliprdr/cliprdr_main.c index 3b0874b99..a9425d7d9 100644 --- a/channels/cliprdr/cliprdr_main.c +++ b/channels/cliprdr/cliprdr_main.c @@ -21,9 +21,10 @@ #include #include #include -#include #include +#include #include +#include #include #include @@ -77,6 +78,8 @@ void cliprdr_packet_send(cliprdrPlugin* cliprdr, STREAM* s) static void cliprdr_process_connect(rdpSvcPlugin* plugin) { DEBUG_CLIPRDR("connecting"); + + ((cliprdrPlugin*) plugin)->uniconv = freerdp_uniconv_new(); } void cliprdr_print_general_capability_flags(uint32 flags) @@ -203,7 +206,7 @@ static void cliprdr_process_receive(rdpSvcPlugin* plugin, STREAM* s) break; case CB_FORMAT_LIST: - cliprdr_process_format_list(cliprdr, s, dataLen); + cliprdr_process_format_list(cliprdr, s, dataLen, msgFlags); break; case CB_FORMAT_LIST_RESPONSE: diff --git a/channels/cliprdr/cliprdr_main.h b/channels/cliprdr/cliprdr_main.h index 2730d02ce..043981498 100644 --- a/channels/cliprdr/cliprdr_main.h +++ b/channels/cliprdr/cliprdr_main.h @@ -24,15 +24,26 @@ #include #include -typedef struct cliprdr_plugin cliprdrPlugin; +struct _CLIPRDR_FORMAT_NAME +{ + uint32 id; + char* name; + int length; +}; +typedef struct _CLIPRDR_FORMAT_NAME CLIPRDR_FORMAT_NAME; + struct cliprdr_plugin { rdpSvcPlugin plugin; + UNICONV* uniconv; boolean use_long_format_names; boolean stream_fileclip_enabled; boolean fileclip_no_file_paths; boolean can_lock_clipdata; + CLIPRDR_FORMAT_NAME* format_names; + int num_format_names; }; +typedef struct cliprdr_plugin cliprdrPlugin; STREAM* cliprdr_packet_new(uint16 msgType, uint16 msgFlags, uint32 dataLen); void cliprdr_packet_send(cliprdrPlugin* cliprdr, STREAM* data_out); diff --git a/client/X11/xf_cliprdr.c b/client/X11/xf_cliprdr.c index 87e23b6be..5a546f388 100644 --- a/client/X11/xf_cliprdr.c +++ b/client/X11/xf_cliprdr.c @@ -249,7 +249,7 @@ static boolean xf_cliprdr_is_self_owned(xfInfo* xfi) XFree(pid); } - if (cb->owner == None || cb->owner == xfi->window->handle) + if (cb->owner == None || cb->owner == xfi->drawable) return False; if (result != Success) @@ -371,11 +371,11 @@ static void xf_cliprdr_send_format_list(xfInfo* xfi) { xf_cliprdr_send_null_format_list(xfi); } - else if (cb->owner != xfi->window->handle) + else if (cb->owner != xfi->drawable) { /* Request the owner for TARGETS, and wait for SelectionNotify event */ XConvertSelection(xfi->display, cb->clipboard_atom, - cb->targets[1], cb->property_atom, xfi->window->handle, CurrentTime); + cb->targets[1], cb->property_atom, xfi->drawable, CurrentTime); } } @@ -449,7 +449,7 @@ static void xf_cliprdr_process_cb_data_request_event(xfInfo* xfi, RDP_CB_DATA_RE XConvertSelection(xfi->display, cb->clipboard_atom, cb->format_mappings[i].target_format, cb->property_atom, - xfi->window->handle, CurrentTime); + xfi->drawable, CurrentTime); XFlush(xfi->display); /* After this point, we expect a SelectionNotify event from the clipboard owner. */ } @@ -466,7 +466,7 @@ static void xf_cliprdr_get_requested_targets(xfInfo* xfi) RDP_CB_FORMAT_LIST_EVENT* event; clipboardContext* cb = (clipboardContext*) xfi->clipboard_context; - XGetWindowProperty(xfi->display, xfi->window->handle, cb->property_atom, + XGetWindowProperty(xfi->display, xfi->drawable, cb->property_atom, 0, 200, 0, XA_ATOM, &atom, &format, &len, &bytes_left, &data); @@ -707,7 +707,7 @@ static boolean xf_cliprdr_get_requested_data(xfInfo* xfi, Atom target) return False; } - XGetWindowProperty(xfi->display, xfi->window->handle, + XGetWindowProperty(xfi->display, xfi->drawable, cb->property_atom, 0, 0, 0, target, &type, &format, &len, &bytes_left, &data); @@ -749,7 +749,7 @@ static boolean xf_cliprdr_get_requested_data(xfInfo* xfi, Atom target) DEBUG_X11("INCR finished"); has_data = True; } - else if (XGetWindowProperty(xfi->display, xfi->window->handle, + else if (XGetWindowProperty(xfi->display, xfi->drawable, cb->property_atom, 0, bytes_left, 0, target, &type, &format, &len, &dummy, &data) == Success) { @@ -770,7 +770,7 @@ static boolean xf_cliprdr_get_requested_data(xfInfo* xfi, Atom target) DEBUG_X11("XGetWindowProperty failed"); } } - XDeleteProperty(xfi->display, xfi->window->handle, cb->property_atom); + XDeleteProperty(xfi->display, xfi->drawable, cb->property_atom); xf_cliprdr_process_requested_data(xfi, has_data, data, (int) bytes_left); @@ -856,7 +856,7 @@ static void xf_cliprdr_process_cb_format_list_event(xfInfo* xfi, RDP_CB_FORMAT_L } } - XSetSelectionOwner(xfi->display, cb->clipboard_atom, xfi->window->handle, CurrentTime); + XSetSelectionOwner(xfi->display, cb->clipboard_atom, xfi->drawable, CurrentTime); if (event->raw_format_data) { XChangeProperty(xfi->display, cb->root_window, cb->property_atom, @@ -1083,7 +1083,7 @@ boolean xf_cliprdr_process_selection_request(xfInfo* xfi, XEvent* xevent) DEBUG_X11("target=%d", (int)xevent->xselectionrequest.target); - if (xevent->xselectionrequest.owner != xfi->window->handle) + if (xevent->xselectionrequest.owner != xfi->drawable) { DEBUG_X11("not owner"); return False; @@ -1112,7 +1112,7 @@ boolean xf_cliprdr_process_selection_request(xfInfo* xfi, XEvent* xevent) else { i = xf_cliprdr_select_format_by_atom(cb, xevent->xselectionrequest.target); - if (i >= 0 && xevent->xselectionrequest.requestor != xfi->window->handle) + if (i >= 0 && xevent->xselectionrequest.requestor != xfi->drawable) { format = cb->format_mappings[i].format_id; alt_format = format; @@ -1198,7 +1198,7 @@ boolean xf_cliprdr_process_property_notify(xfInfo* xfi, XEvent* xevent) DEBUG_X11("root window PropertyNotify"); xf_cliprdr_send_format_list(xfi); } - else if (xevent->xproperty.window == xfi->window->handle && + else if (xevent->xproperty.window == xfi->drawable && xevent->xproperty.state == PropertyNewValue && cb->incr_starts && cb->request_index >= 0) { diff --git a/libfreerdp-utils/unicode.c b/libfreerdp-utils/unicode.c index fb5150d1e..6524a35ad 100644 --- a/libfreerdp-utils/unicode.c +++ b/libfreerdp-utils/unicode.c @@ -25,7 +25,7 @@ /* Convert pin/in_len from WINDOWS_CODEPAGE - return like xstrdup, 0-terminated */ -char* freerdp_uniconv_in(UNICONV *uniconv, unsigned char* pin, size_t in_len) +char* freerdp_uniconv_in(UNICONV* uniconv, unsigned char* pin, size_t in_len) { unsigned char *conv_pin = pin; size_t conv_in_len = in_len;