diff options
-rw-r--r-- | sesman/chansrv/clipboard.c | 743 | ||||
-rw-r--r-- | sesman/chansrv/clipboard.h | 27 |
2 files changed, 603 insertions, 167 deletions
diff --git a/sesman/chansrv/clipboard.c b/sesman/chansrv/clipboard.c index 183703f4..18712dc8 100644 --- a/sesman/chansrv/clipboard.c +++ b/sesman/chansrv/clipboard.c @@ -56,7 +56,15 @@ xlsatoms - dump atoms #define LLOG_LEVEL 11 #define LLOGLN(_level, _args) \ - do { if (_level < LLOG_LEVEL) { g_writeln _args ; } } while (0) + do \ + { \ + if (_level < LLOG_LEVEL) \ + { \ + g_write("chansrv:clip [%10.10u]: ", g_time3()); \ + g_writeln _args ; \ + } \ + } \ + while (0) static char g_bmp_image_header[] = { @@ -98,8 +106,9 @@ static int g_xfixes_event_base = 0; static int g_last_clip_size = 0; static char *g_last_clip_data = 0; static Atom g_last_clip_type = 0; +static int g_last_xrdp_clip_type = 0; +static Time g_last_clip_time = 0; -static int g_in_file_copy = 0; static int g_got_selection = 0; /* boolean */ static Time g_selection_time = 0; @@ -126,8 +135,7 @@ static char *g_incr_data = 0; static int g_incr_data_size = 0; static int g_incr_in_progress = 0; -static int g_clipboard_format_id = CB_FORMAT_UNICODETEXT; - +/* default version and flags */ static int g_cliprdr_version = 2; static int g_cliprdr_flags = CB_USE_LONG_FORMAT_NAMES | CB_STREAM_FILECLIP_ENABLED | @@ -137,6 +145,17 @@ static int g_cliprdr_flags = CB_USE_LONG_FORMAT_NAMES | static int g_formatIds[16]; static int g_num_formatIds = 0; +struct cb_file_info +{ + char pathname[256]; + char filename[256]; + int flags; + int size; +}; + +static struct cb_file_info g_files[64]; +static int g_num_files = 0; + /*****************************************************************************/ /* this is one way to get the current time from the x server */ static Time APP_CC @@ -344,7 +363,7 @@ clipboard_deinit(void) /*****************************************************************************/ static int APP_CC -clipboard_send_data_request(void) +clipboard_send_data_request(int format_id) { struct stream *s; int size; @@ -362,10 +381,11 @@ clipboard_send_data_request(void) g_got_format_announce = 0; make_stream(s); init_stream(s, 8192); - out_uint16_le(s, 4); /* CLIPRDR_DATA_REQUEST */ + out_uint16_le(s, CB_FORMAT_DATA_REQUEST); /* 4 CLIPRDR_DATA_REQUEST */ out_uint16_le(s, 0); /* status */ out_uint32_le(s, 4); /* length */ - out_uint32_le(s, g_clipboard_format_id); + out_uint32_le(s, format_id); + out_uint32_le(s, 0); s_mark_end(s); size = (int)(s->end - s->data); LOGM((LOG_LEVEL_DEBUG, "clipboard_send_data_request: data out, sending " @@ -476,54 +496,67 @@ static char windows_native_format[] = /*****************************************************************************/ static int APP_CC -clipboard_send_format_announce(tui32 format_id, char *format_name) +clipboard_send_format_announce(int xrdp_clip_type) { struct stream *s; int size; int rv; char *holdp; - LLOGLN(10, ("clipboard_send_format_announce: format_id 0x%8.8x " - "format_name [%s]", format_id, format_name)); + LLOGLN(10, ("clipboard_send_format_announce:")); make_stream(s); init_stream(s, 8192); - out_uint16_le(s, CB_FORMAT_LIST); /* CLIPRDR_FORMAT_ANNOUNCE */ + out_uint16_le(s, CB_FORMAT_LIST); /* 2 CLIPRDR_FORMAT_ANNOUNCE */ out_uint16_le(s, 0); /* status */ holdp = s->p; out_uint32_le(s, 0); /* set later */ if (g_cliprdr_flags & CB_USE_LONG_FORMAT_NAMES) { - if (format_id == CB_FORMAT_FILE) + switch (xrdp_clip_type) { - /* canned response for "file" */ - out_uint32_le(s, 0x0000c0bc); - clipboard_out_unicode(s, "FileGroupDescriptorW", 21); - out_uint32_le(s, 0x0000c0ba); - clipboard_out_unicode(s, "FileContents", 13); - out_uint32_le(s, 0x0000c0c1); - clipboard_out_unicode(s, "DropEffect", 11); - } - else if (format_id == CB_FORMAT_DIB) - { - /* canned response for "bitmap" */ - out_uint32_le(s, 0x0000c004); - clipboard_out_unicode(s, "Native", 7); - out_uint32_le(s, 0x00000003); - clipboard_out_unicode(s, "", 1); - out_uint32_le(s, 0x00000008); - clipboard_out_unicode(s, "", 1); - out_uint32_le(s, 0x00000011); - clipboard_out_unicode(s, "", 1); - } - else - { - out_uint32_le(s, format_id); - clipboard_out_unicode(s, format_name, g_mbstowcs(0, format_name, 0) + 1); + case XRDP_CB_FILE: + LLOGLN(10, ("clipboard_send_format_announce: XRDP_CB_FILE")); + /* canned response for "file" */ + out_uint32_le(s, 0x0000c0bc); + clipboard_out_unicode(s, "FileGroupDescriptorW", 21); + out_uint32_le(s, 0x0000c0ba); + clipboard_out_unicode(s, "FileContents", 13); + out_uint32_le(s, 0x0000c0c1); + clipboard_out_unicode(s, "DropEffect", 11); + break; + case XRDP_CB_BITMAP: + LLOGLN(10, ("clipboard_send_format_announce: XRDP_CB_BITMAP")); + /* canned response for "bitmap" */ + out_uint32_le(s, 0x0000c004); + clipboard_out_unicode(s, "Native", 7); + out_uint32_le(s, 0x00000003); + clipboard_out_unicode(s, "", 1); + out_uint32_le(s, 0x00000008); + clipboard_out_unicode(s, "", 1); + out_uint32_le(s, 0x00000011); + clipboard_out_unicode(s, "", 1); + break; + case XRDP_CB_TEXT: + LLOGLN(10, ("clipboard_send_format_announce: XRDP_CB_TEXT")); + /* canned response for "bitmap" */ + out_uint32_le(s, 0x0000000d); + clipboard_out_unicode(s, "", 1); + out_uint32_le(s, 0x00000010); + clipboard_out_unicode(s, "", 1); + out_uint32_le(s, 0x00000001); + clipboard_out_unicode(s, "", 1); + out_uint32_le(s, 0x00000007); + clipboard_out_unicode(s, "", 1); + break; + default: + LLOGLN(10, ("clipboard_send_format_announce: unknown " + "xrdp_clip_type %d", xrdp_clip_type)); + break; } } else { - out_uint32_le(s, format_id); + out_uint32_le(s, g_last_clip_type); out_uint8p(s, windows_native_format, sizeof(windows_native_format)); } size = (int)(s->p - holdp); @@ -532,7 +565,7 @@ clipboard_send_format_announce(tui32 format_id, char *format_name) holdp[1] = (size >> 8) & 0xff; holdp[2] = (size >> 16) & 0xff; holdp[3] = (size >> 24) & 0xff; - out_uint8s(s, 4); + out_uint32_le(s, 0); s_mark_end(s); size = (int)(s->end - s->data); g_hexdump(s->data, size); @@ -545,34 +578,23 @@ clipboard_send_format_announce(tui32 format_id, char *format_name) /*****************************************************************************/ static int APP_CC -clipboard_send_data_response_for_image(void) +clipboard_send_data_response_for_image(char* data, int data_size) { struct stream *s; int size; int rv; - LOG(10, ("clipboard_send_data_response_for_image: g_last_clip_size %d\n", - g_last_clip_size)); + LLOGLN(10, ("clipboard_send_data_response_for_image: data_size %d", + data_size)); make_stream(s); - init_stream(s, 64 + g_last_clip_size); - out_uint16_le(s, 5); /* CLIPRDR_DATA_RESPONSE */ - out_uint16_le(s, 1); /* status */ - out_uint32_le(s, g_last_clip_size); /* length */ - - /* insert image data */ - if (g_last_clip_type == g_image_bmp_atom) - { - /* do not insert first header */ - out_uint8p(s, g_last_clip_data + 14, g_last_clip_size - 14); - } - - out_uint16_le(s, 0); /* nil for string */ - out_uint32_le(s, 0); - out_uint32_le(s, 0); + init_stream(s, 64 + data_size); + out_uint16_le(s, CB_FORMAT_DATA_RESPONSE); /* 5 CLIPRDR_DATA_RESPONSE */ + out_uint16_le(s, CB_RESPONSE_OK); /* 1 status */ + out_uint32_le(s, data_size); /* length */ + out_uint8p(s, data, data_size); out_uint32_le(s, 0); s_mark_end(s); size = (int)(s->end - s->data); - /* HANGING HERE WHEN IMAGE DATA IS TOO BIG!!!! */ rv = send_channel_data(g_cliprdr_chan_id, s->data, size); free_stream(s); return rv; @@ -580,56 +602,200 @@ clipboard_send_data_response_for_image(void) /*****************************************************************************/ static int APP_CC -clipboard_send_data_response(void) +clipboard_send_data_response_for_text(char* data, int data_size) { struct stream *s; int size; int rv; int num_chars; - LOG(10, ("clipboard_send_data_response:")); - num_chars = 0; + LLOGLN(10, ("clipboard_send_data_response_for_text: data_size %d", + data_size)); + //g_hexdump(data, data_size); + num_chars = g_mbstowcs(0, data, 0); + if (num_chars < 0) + { + LOGM((LOG_LEVEL_ERROR, "clipboard_send_data_response_for_text: " + "bad string")); + num_chars = 0; + } + LLOGLN(10, ("clipboard_send_data_response_for_text: data_size %d " + "num_chars %d", data_size, num_chars)); + make_stream(s); + init_stream(s, 64 + num_chars * 2); + out_uint16_le(s, CB_FORMAT_DATA_RESPONSE); /* 5 CLIPRDR_DATA_RESPONSE */ + out_uint16_le(s, CB_RESPONSE_OK); /* 1 status */ + out_uint32_le(s, num_chars * 2 + 2); /* length */ + if (clipboard_out_unicode(s, data, num_chars) != num_chars * 2) + { + LOGM((LOG_LEVEL_ERROR, "clipboard_send_data_response_for_text: error " + "clipboard_out_unicode didn't write right number of bytes")); + } + out_uint16_le(s, 0); /* nil for string */ + out_uint32_le(s, 0); + s_mark_end(s); + size = (int)(s->end - s->data); + LOGM((LOG_LEVEL_DEBUG, "clipboard_send_data_response_for_text: data out, " + "sending CLIPRDR_DATA_RESPONSE (clip_msg_id = 5) size %d " + "num_chars %d", size, num_chars)); + rv = send_channel_data(g_cliprdr_chan_id, s->data, size); + free_stream(s); + return rv; +} - if (g_last_clip_data != 0) +/*****************************************************************************/ +static int APP_CC +clipboard_get_file(char* file, int bytes) +{ + int sindex; + int pindex; + char full_fn[256]; + char filename[256]; + char pathname[256]; + + sindex = 0; + if (g_strncmp(file, "file:///", 8) == 0) + { + sindex = 7; + } + pindex = bytes; + while (pindex > sindex) { - if (g_last_clip_type == g_image_bmp_atom) + if (file[pindex] == '/') { - return clipboard_send_data_response_for_image(); + break; } + pindex--; + } + g_memset(pathname, 0, 256); + g_memset(filename, 0, 256); + g_memcpy(pathname, file + sindex, pindex - sindex); + if (pathname[0] == 0) + { + pathname[0] = '/'; + } + g_memcpy(filename, file + pindex + 1, (bytes - 1) - pindex); + g_snprintf(full_fn, 255, "%s/%s", pathname, filename); + if (g_directory_exist(full_fn)) + { + LLOGLN(0, ("clipboard_get_file: file [%s] is a directory, " + "not supported", full_fn)); + return 1; + } + if (!g_file_exist(full_fn)) + { + LLOGLN(0, ("clipboard_get_file: file [%s] does not exist", + full_fn)); + return 1; + } + else + { + g_strcpy(g_files[g_num_files].filename, filename); + g_strcpy(g_files[g_num_files].pathname, pathname); + g_files[g_num_files].size = g_file_get_size(full_fn); + g_writeln("ok filename [%s] pathname [%s] size [%d]", + g_files[g_num_files].filename, + g_files[g_num_files].pathname, + g_files[g_num_files].size); + g_num_files++; + } + return 0; +} - if ((g_last_clip_type == XA_STRING) || (g_last_clip_type == g_utf8_atom)) - { - num_chars = g_mbstowcs(0, g_last_clip_data, 0); +/*****************************************************************************/ +static int APP_CC +clipboard_get_files(char* files, int bytes) +{ + int index; + int file_index; + char file[512]; - if (num_chars < 0) + g_num_files = 0; + file_index = 0; + for (index = 0; index < bytes; index++) + { + if (files[index] == '\n' || files[index] == '\r') + { + if (file_index > 0) { - LOGM((LOG_LEVEL_ERROR, "clipboard_send_data_response: bad string")); - num_chars = 0; + if (clipboard_get_file(file, file_index) == 0) + { + } + file_index = 0; } } + else + { + file[file_index] = files[index]; + file_index++; + } + if (g_num_files > 60) + { + break; + } } - - LOG(10, ("clipboard_send_data_response: g_last_clip_size %d " - "num_chars %d", g_last_clip_size, num_chars)); - make_stream(s); - init_stream(s, 64 + num_chars * 2); - out_uint16_le(s, 5); /* CLIPRDR_DATA_RESPONSE */ - out_uint16_le(s, 1); /* status */ - out_uint32_le(s, num_chars * 2 + 2); /* length */ - - if (clipboard_out_unicode(s, g_last_clip_data, num_chars) != num_chars * 2) + if (file_index > 0) { - LOGM((LOG_LEVEL_ERROR, "clipboard_send_data_response: error " - "clipboard_out_unicode didn't write right number of bytes")); + if (clipboard_get_file(file, file_index) == 0) + { + } + } + if (g_num_files < 1) + { + return 1; } + return 0; +} - out_uint16_le(s, 0); /* nil for string */ +/*****************************************************************************/ +static int APP_CC +clipboard_send_data_response_for_file(char *data, int data_size) +{ + struct stream *s; + int size; + int rv; + int bytes_after_header; + int cItems; + int flags; + int index; + char fn[256]; + + LLOGLN(10, ("clipboard_send_data_response_for_file: g_last_clip_size %d", + g_last_clip_size)); + g_hexdump(data, data_size); + clipboard_get_files(data, data_size); + cItems = g_num_files; + bytes_after_header = cItems * 592 + 4; + make_stream(s); + init_stream(s, 64 + bytes_after_header); + out_uint16_le(s, CB_FORMAT_DATA_RESPONSE); /* 5 CLIPRDR_DATA_RESPONSE */ + out_uint16_le(s, 1); // CB_RESPONSE_OK); /* 1 status */ + out_uint32_le(s, bytes_after_header); + out_uint32_le(s, cItems); + for (index = 0; index < cItems; index++) + { + flags = CB_FD_ATTRIBUTES | CB_FD_FILESIZE | CB_FD_WRITESTIME | CB_FD_PROGRESSUI; + out_uint32_le(s, flags); + out_uint8s(s, 32); /* reserved1 */ + flags = CB_FILE_ATTRIBUTE_ARCHIVE; + //flags = CB_FILE_ATTRIBUTE_NORMAL; + out_uint32_le(s, flags); + out_uint8s(s, 16); /* reserved2 */ + /* file time */ + out_uint32_le(s, 0x2c305d08); + out_uint32_le(s, 0x01ca55f3); + /* file size */ + out_uint32_le(s, 0); + out_uint32_le(s, g_files[index].size); + g_writeln("jay size %d", g_files[index].size); + g_snprintf(fn, 255, "%s", g_files[index].filename); + clipboard_out_unicode(s, fn, 256); + out_uint8s(s, 8); /* pad */ + } out_uint32_le(s, 0); s_mark_end(s); size = (int)(s->end - s->data); - LOGM((LOG_LEVEL_DEBUG, "clipboard_send_data_response: data out, sending " - "CLIPRDR_DATA_RESPONSE (clip_msg_id = 5) size %d num_chars %d", - size, num_chars)); + g_hexdump(s->data, size); rv = send_channel_data(g_cliprdr_chan_id, s->data, size); free_stream(s); return rv; @@ -637,10 +803,44 @@ clipboard_send_data_response(void) /*****************************************************************************/ static int APP_CC +clipboard_send_data_response(int xrdp_clip_type, char *data, int data_size) +{ + LLOGLN(10, ("clipboard_send_data_response:")); + if (g_last_clip_data != 0) + { + if (g_last_xrdp_clip_type == XRDP_CB_FILE) + { + return clipboard_send_data_response_for_file(data, data_size); + } + else if (g_last_xrdp_clip_type == XRDP_CB_BITMAP) + { + return clipboard_send_data_response_for_image(data, data_size); + } + else if (g_last_xrdp_clip_type == XRDP_CB_TEXT) + { + return clipboard_send_data_response_for_text(data, data_size); + } + else + { + LLOGLN(0, ("clipboard_send_data_response: unknown " + "g_last_xrdp_clip_type %d", g_last_xrdp_clip_type)); + } + } + else + { + LLOGLN(0, ("clipboard_send_data_response: g_last_clip_data " + "is nil")); + } + return 0; +} + +/*****************************************************************************/ +static int APP_CC clipboard_set_selection_owner(void) { Window owner; + LLOGLN(10, ("clipboard_set_selection_owner:")); g_selection_time = clipboard_get_server_time(); XSetSelectionOwner(g_display, g_clipboard_atom, g_wnd, g_selection_time); owner = XGetSelectionOwner(g_display, g_clipboard_atom); @@ -778,17 +978,65 @@ clipboard_prcoess_format_ack(struct stream *s, int clip_msg_status, } /*****************************************************************************/ +static int +clipboard_send_data_response_failed(void) +{ + struct stream *s; + int size; + int rv; + + LLOGLN(10, ("clipboard_send_data_response_failed:")); + make_stream(s); + init_stream(s, 64); + out_uint16_le(s, CB_FORMAT_DATA_RESPONSE); /* 5 CLIPRDR_DATA_RESPONSE */ + out_uint16_le(s, CB_RESPONSE_FAIL); /* 2 status */ + out_uint32_le(s, 0); + s_mark_end(s); + size = (int)(s->end - s->data); + rv = send_channel_data(g_cliprdr_chan_id, s->data, size); + free_stream(s); + return rv; +} + +/*****************************************************************************/ /* sent by recipient of CB_FORMAT_LIST; used to request data for one of the formats that was listed in CB_FORMAT_LIST */ static int APP_CC clipboard_process_data_request(struct stream *s, int clip_msg_status, int clip_msg_len) { + int requestedFormatId; + LOGM((LOG_LEVEL_DEBUG, "clipboard_process_data_request: " "CLIPRDR_DATA_REQUEST")); LLOGLN(10, ("clipboard_process_data_request:")); g_hexdump(s->p, s->end - s->p); - clipboard_send_data_response(); + in_uint32_le(s, requestedFormatId); + switch (requestedFormatId) + { + case CB_FORMAT_FILE: /* 0xC0BC */ + LLOGLN(10, ("clipboard_process_data_request: CB_FORMAT_FILE %d", g_last_clip_type)); + XConvertSelection(g_display, g_clipboard_atom, g_last_clip_type, + g_clip_property_atom, g_wnd, CurrentTime); + break; + case CB_FORMAT_DIB: /* 0x0008 */ + LLOGLN(10, ("clipboard_process_data_request: CB_FORMAT_DIB")); + XConvertSelection(g_display, g_clipboard_atom, g_last_clip_type, + g_clip_property_atom, g_wnd, CurrentTime); + break; + case CB_FORMAT_UNICODETEXT: /* 0x000D */ + LLOGLN(10, ("clipboard_process_data_request: CB_FORMAT_UNICODETEXT")); + XConvertSelection(g_display, g_clipboard_atom, g_last_clip_type, + g_clip_property_atom, g_wnd, CurrentTime); + break; + default: + LLOGLN(10, ("clipboard_process_data_request: unknown type %d", + requestedFormatId)); + clipboard_send_data_response_failed(); + break; + } + //g_sleep(100); /* ? this seems to prevent case where XConvertSelection does not + // yeild a SelectionNotify */ return 0; } @@ -1005,6 +1253,119 @@ clipboard_process_clip_caps(struct stream *s, int clip_msg_status, } /*****************************************************************************/ +static int APP_CC +clipboard_send_file_size(int streamId, int lindex) +{ + struct stream *s; + int size; + int rv; + int file_size; + + file_size = g_files[lindex].size; + LLOGLN(10, ("clipboard_send_file_size: streamId %d file_size %d", + streamId, file_size)); + make_stream(s); + init_stream(s, 8192); + out_uint16_le(s, CB_FILECONTENTS_RESPONSE); /* 9 */ + out_uint16_le(s, CB_RESPONSE_OK); /* 1 status */ + out_uint32_le(s, 12); + out_uint32_le(s, streamId); + out_uint32_le(s, file_size); + g_writeln("file_size %d", file_size); + out_uint32_le(s, 0); + out_uint32_le(s, 0); + s_mark_end(s); + size = (int)(s->end - s->data); + rv = send_channel_data(g_cliprdr_chan_id, s->data, size); + free_stream(s); + return rv; +} + +/*****************************************************************************/ +static int APP_CC +clipboard_send_file_data(int streamId, int lindex, + int nPositionLow, int cbRequested) +{ + struct stream *s; + int size; + int rv; + int fd; + char full_fn[256]; + + LLOGLN(10, ("clipboard_send_file_data: streamId %d lindex %d " + "nPositionLow %d cbRequested %d", streamId, lindex, + nPositionLow, cbRequested)); + g_snprintf(full_fn, 255, "%s/%s", g_files[lindex].pathname, + g_files[lindex].filename); + fd = g_file_open_ex(full_fn, 1, 0, 0, 0); + if (fd == -1) + { + LLOGLN(0, ("clipboard_send_file_data: file open [%s] failed", + full_fn)); + return 1; + } + g_file_seek(fd, nPositionLow); + make_stream(s); + init_stream(s, cbRequested + 64); + //g_memset(s->data + 12, 26, cbRequested); + size = g_file_read(fd, s->data + 12, cbRequested); + g_writeln("size %d", size); + if (size < 1) + { + LLOGLN(10, ("clipboard_send_file_data: read error, want %d got %d", + cbRequested, size)); + free_stream(s); + g_file_close(fd); + return 1; + } + out_uint16_le(s, CB_FILECONTENTS_RESPONSE); /* 9 */ + out_uint16_le(s, CB_RESPONSE_OK); /* 1 status */ + out_uint32_le(s, size + 4); + out_uint32_le(s, streamId); + s->p += size; + out_uint32_le(s, 0); + s_mark_end(s); + size = (int)(s->end - s->data); + rv = send_channel_data(g_cliprdr_chan_id, s->data, size); + free_stream(s); + g_file_close(fd); + return rv; +} + +/*****************************************************************************/ +static int APP_CC +clipboard_process_file_request(struct stream *s, int clip_msg_status, + int clip_msg_len) +{ + int streamId; + int lindex; + int dwFlags; + int nPositionLow; + int nPositionHigh; + int cbRequested; + //int clipDataId; + + LLOGLN(10, ("clipboard_process_file_request:")); + g_hexdump(s->p, clip_msg_len); + in_uint32_le(s, streamId); + in_uint32_le(s, lindex); + in_uint32_le(s, dwFlags); + in_uint32_le(s, nPositionLow); + in_uint32_le(s, nPositionHigh); + in_uint32_le(s, cbRequested); + //in_uint32_le(s, clipDataId); /* options, used when locking */ + if (dwFlags & CB_FILECONTENTS_SIZE) + { + clipboard_send_file_size(streamId, lindex); + } + if (dwFlags & CB_FILECONTENTS_RANGE) + { + clipboard_send_file_data(streamId, lindex, nPositionLow, cbRequested); + } + return 0; +} + +/*****************************************************************************/ int APP_CC clipboard_data_in(struct stream *s, int chan_id, int chan_flags, int length, int total_length) @@ -1056,19 +1417,19 @@ clipboard_data_in(struct stream *s, int chan_id, int chan_flags, int length, /* sent by client or server when its local system clipboard is */ /* updated with new clipboard data; contains Clipboard Format ID */ /* and name pairs of new Clipboard Formats on the clipboard. */ - case CB_FORMAT_LIST: /* CLIPRDR_FORMAT_ANNOUNCE */ + case CB_FORMAT_LIST: /* 2 CLIPRDR_FORMAT_ANNOUNCE */ rv = clipboard_process_format_announce(ls, clip_msg_status, clip_msg_len); break; /* response to CB_FORMAT_LIST; used to indicate whether */ /* processing of the Format List PDU was successful */ - case CB_FORMAT_LIST_RESPONSE: /* CLIPRDR_FORMAT_ACK */ + case CB_FORMAT_LIST_RESPONSE: /* 3 CLIPRDR_FORMAT_ACK */ rv = clipboard_prcoess_format_ack(ls, clip_msg_status, clip_msg_len); break; /* sent by recipient of CB_FORMAT_LIST; used to request data for one */ /* of the formats that was listed in CB_FORMAT_LIST */ - case CB_FORMAT_DATA_REQUEST: /* CLIPRDR_DATA_REQUEST */ + case CB_FORMAT_DATA_REQUEST: /* 4 CLIPRDR_DATA_REQUEST */ rv = clipboard_process_data_request(ls, clip_msg_status, clip_msg_len); break; @@ -1077,14 +1438,18 @@ clipboard_data_in(struct stream *s, int chan_id, int chan_flags, int length, /* successful; if processing was successful, */ /* CB_FORMAT_DATA_RESPONSE includes contents of requested */ /* clipboard data. */ - case CB_FORMAT_DATA_RESPONSE: /* CLIPRDR_DATA_RESPONSE */ + case CB_FORMAT_DATA_RESPONSE: /* 5 CLIPRDR_DATA_RESPONSE */ rv = clipboard_process_data_response(ls, clip_msg_status, clip_msg_len); break; - case CB_CLIP_CAPS: + case CB_CLIP_CAPS: /* 7 */ rv = clipboard_process_clip_caps(ls, clip_msg_status, clip_msg_len); break; + case CB_FILECONTENTS_REQUEST: /* 8 */ + rv = clipboard_process_file_request(ls, clip_msg_status, + clip_msg_len); + break; default: LLOGLN(0, ("clipboard_data_in: unknown clip_msg_id %d", clip_msg_id)); LOGM((LOG_LEVEL_ERROR, "clipboard_data_in: unknown clip_msg_id %d", @@ -1118,6 +1483,9 @@ clipboard_event_selection_owner_notify(XEvent *xevent) XFixesSelectionNotifyEvent *lxevent; LLOGLN(0, ("clipboard_event_selection_owner_notify:")); + + //return 0; + lxevent = (XFixesSelectionNotifyEvent *)xevent; LOGM((LOG_LEVEL_DEBUG, "clipboard_event_selection_owner_notify: " "window %d subtype %d owner %d g_wnd %d", @@ -1171,7 +1539,8 @@ clipboard_get_window_property(Window wnd, Atom prop, Atom *type, int *fmt, if (ltype == g_incr_atom) { - LOGM((LOG_LEVEL_DEBUG, "clipboard_event_property_notify: INCR start")); + LOGM((LOG_LEVEL_DEBUG, "clipboard_get_window_property: INCR start")); + LLOGLN(10, ("clipboard_get_window_property: INCR start")); g_incr_in_progress = 1; g_incr_atom_type = prop; g_incr_data_size = 0; @@ -1286,32 +1655,29 @@ clipboard_event_selection_notify(XEvent *xevent) int fmt; int rv; int index; - int convert_to_string; - int convert_to_utf8; - int convert_to_bmp_image; - int convert_to_file; + int got_string; + int got_utf8; + int got_bmp_image; + int got_file; int send_format_announce; int atom; Atom *atoms; Atom type; - tui32 format_id; - char format_name[32]; + LLOGLN(10, ("clipboard_event_selection_notify:")); LOGM((LOG_LEVEL_DEBUG, "clipboard_event_selection_notify:")); data_size = 0; n_items = 0; fmt = 0; - convert_to_string = 0; - convert_to_utf8 = 0; - convert_to_bmp_image = 0; - convert_to_file = 0; + got_string = 0; + got_utf8 = 0; + got_bmp_image = 0; + got_file = 0; send_format_announce = 0; - format_id = 0; rv = 0; data = 0; type = 0; lxevent = (XSelectionEvent *)xevent; - g_memset(format_name, 0, 32); if (lxevent->property == None) { @@ -1352,7 +1718,6 @@ clipboard_event_selection_notify(XEvent *xevent) if ((type == XA_ATOM) && (fmt == 32)) { atoms = (Atom *)data; - g_in_file_copy = 0; for (index = 0; index < n_items; index++) { atom = atoms[index]; @@ -1362,20 +1727,20 @@ clipboard_event_selection_notify(XEvent *xevent) atom, XGetAtomName(g_display, atom))); if (atom == g_utf8_atom) { - convert_to_utf8 = 1; + got_utf8 = 1; } else if (atom == XA_STRING) { - convert_to_string = 1; + got_string = 1; } else if (atom == g_image_bmp_atom) { - convert_to_bmp_image = 1; + got_bmp_image = 1; } else if ((atom == g_file_atom1) || (atom == g_file_atom2)) { LLOGLN(10, ("clipboard_event_selection_notify: file")); - convert_to_file = 1; + got_file = 1; } else { @@ -1392,54 +1757,64 @@ clipboard_event_selection_notify(XEvent *xevent) } else if (lxevent->target == g_utf8_atom) { - LLOGLN(10, ("here---------------------%d", g_in_file_copy)); LOGM((LOG_LEVEL_DEBUG, "clipboard_event_selection_notify: UTF8_STRING " "data_size %d", data_size)); - g_free(g_last_clip_data); - g_last_clip_data = 0; - g_last_clip_size = data_size; - g_last_clip_data = (char *) g_malloc(g_last_clip_size + 1, 0); - g_last_clip_type = g_utf8_atom; - g_memcpy(g_last_clip_data, data, g_last_clip_size); - g_last_clip_data[g_last_clip_size] = 0; - send_format_announce = 1; - if (g_in_file_copy) + LLOGLN(10, ("clipboard_event_selection_notify: UTF8_STRING " + "data_size %d", data_size)); + if ((!g_incr_in_progress) && (data_size > 0)) { - format_id = CB_FORMAT_FILE; - g_strcpy(format_name, "FileGroupDescriptorW"); - } - else - { - format_id = CB_FORMAT_UNICODETEXT; + g_free(g_last_clip_data); + g_last_clip_data = 0; + g_last_clip_size = data_size; + g_last_clip_data = (char *) g_malloc(g_last_clip_size + 1, 0); + g_memcpy(g_last_clip_data, data, g_last_clip_size); + g_last_clip_data[g_last_clip_size] = 0; + if (g_last_xrdp_clip_type == XRDP_CB_FILE) + { + clipboard_send_data_response_for_file(g_last_clip_data, + g_last_clip_size); + } + else + { + clipboard_send_data_response_for_text(g_last_clip_data, + g_last_clip_size); + } } } else if (lxevent->target == XA_STRING) { LOGM((LOG_LEVEL_DEBUG, "clipboard_event_selection_notify: XA_STRING " "data_size %d", data_size)); - g_free(g_last_clip_data); - g_last_clip_data = 0; - g_last_clip_size = data_size; - g_last_clip_data = (char *) g_malloc(g_last_clip_size + 1, 0); - g_last_clip_type = XA_STRING; - g_memcpy(g_last_clip_data, data, g_last_clip_size); - g_last_clip_data[g_last_clip_size] = 0; - send_format_announce = 1; - format_id = CB_FORMAT_UNICODETEXT; + LLOGLN(10, ("clipboard_event_selection_notify: XA_STRING " + "data_size %d", data_size)); + if ((!g_incr_in_progress) && (data_size > 0)) + { + g_free(g_last_clip_data); + g_last_clip_data = 0; + g_last_clip_size = data_size; + g_last_clip_data = (char *) g_malloc(g_last_clip_size + 1, 0); + g_memcpy(g_last_clip_data, data, g_last_clip_size); + g_last_clip_data[g_last_clip_size] = 0; + clipboard_send_data_response_for_text(g_last_clip_data, + g_last_clip_size); + } } else if (lxevent->target == g_image_bmp_atom) { LOGM((LOG_LEVEL_DEBUG, "clipboard_event_selection_notify: image/bmp " "data_size %d", data_size)); - g_free(g_last_clip_data); - g_last_clip_data = 0; - g_last_clip_size = data_size; - g_last_clip_data = (char *) g_malloc(data_size, 0); - g_last_clip_type = g_image_bmp_atom; - g_memcpy(g_last_clip_data, data, data_size); - send_format_announce = 1; - format_id = CB_FORMAT_DIB; - g_strcpy(format_name, "image/bmp"); + LLOGLN(10, ("clipboard_event_selection_notify: image/bmp " + "data_size %d", data_size)); + if ((!g_incr_in_progress) && (data_size > 14)) + { + g_free(g_last_clip_data); + g_last_clip_data = 0; + g_last_clip_size = data_size; + g_last_clip_data = (char *) g_malloc(data_size, 0); + g_memcpy(g_last_clip_data, data, data_size); + clipboard_send_data_response_for_image(g_last_clip_data + 14, + g_last_clip_size - 14); + } } else { @@ -1454,32 +1829,38 @@ clipboard_event_selection_notify(XEvent *xevent) } } - if (convert_to_file) + if (got_file) { - LLOGLN(10, ("convert_to_file and convert_to_utf8 set")); - XConvertSelection(g_display, g_clipboard_atom, g_utf8_atom, - g_clip_property_atom, g_wnd, lxevent->time); - g_in_file_copy = 1; + g_last_clip_type = g_utf8_atom; + g_last_xrdp_clip_type = XRDP_CB_FILE; + g_last_clip_time = lxevent->time; + send_format_announce = 1; } - else if (convert_to_utf8) + else if (got_utf8) { - XConvertSelection(g_display, g_clipboard_atom, g_utf8_atom, - g_clip_property_atom, g_wnd, lxevent->time); + g_last_clip_type = g_utf8_atom; + g_last_xrdp_clip_type = XRDP_CB_TEXT; + g_last_clip_time = lxevent->time; + send_format_announce = 1; } - else if (convert_to_string) + else if (got_string) { - XConvertSelection(g_display, g_clipboard_atom, XA_STRING, - g_clip_property_atom, g_wnd, lxevent->time); + g_last_clip_type = XA_STRING; + g_last_xrdp_clip_type = XRDP_CB_TEXT; + g_last_clip_time = lxevent->time; + send_format_announce = 1; } - else if (convert_to_bmp_image) + else if (got_bmp_image) { - XConvertSelection(g_display, g_clipboard_atom, g_image_bmp_atom, - g_clip_property_atom, g_wnd, lxevent->time); + g_last_clip_type = g_image_bmp_atom; + g_last_xrdp_clip_type = XRDP_CB_BITMAP; + g_last_clip_time = lxevent->time; + send_format_announce = 1; } if (send_format_announce) { - if (clipboard_send_format_announce(format_id, format_name) != 0) + if (clipboard_send_format_announce(g_last_xrdp_clip_type) != 0) { rv = 4; } @@ -1581,7 +1962,6 @@ clipboard_event_selection_request(XEvent *xevent) { LOGM((LOG_LEVEL_DEBUG, "clipboard_event_selection_request: %s", XGetAtomName(g_display, lxev->target))); - g_clipboard_format_id = CB_FORMAT_UNICODETEXT; if (g_data_in_up_to_date) { @@ -1601,7 +1981,7 @@ clipboard_event_selection_request(XEvent *xevent) if (g_selection_request_event_count == 0) { - clipboard_send_data_request(); + clipboard_send_data_request(CB_FORMAT_UNICODETEXT); g_waiting_for_data_response = 1; g_waiting_for_data_response_time = xcommon_get_local_time(); } @@ -1615,9 +1995,9 @@ clipboard_event_selection_request(XEvent *xevent) g_memcpy(&g_saved_selection_req_event, lxev, sizeof(g_saved_selection_req_event)); g_last_clip_type = g_image_bmp_atom; + g_last_xrdp_clip_type = XRDP_CB_BITMAP; g_want_image_data = 1; - g_clipboard_format_id = CB_FORMAT_DIB; - clipboard_send_data_request(); + clipboard_send_data_request(CB_FORMAT_DIB); g_waiting_for_data_response = 1; g_waiting_for_data_response_time = clipboard_get_local_time(); return 0; @@ -1677,9 +2057,9 @@ clipboard_event_property_notify(XEvent *xevent) int format_in_bytes; int new_data_len; char *cptr; - char format_name[32]; - LOG(10, ("clipboard_check_wait_objs: PropertyNotify .window %d " + LLOGLN(10, ("clipboard_event_property_notify:")); + LOG(10, ("clipboard_event_property_notify: PropertyNotify .window %d " ".state %d .atom %d", xevent->xproperty.window, xevent->xproperty.state, xevent->xproperty.atom)); @@ -1700,7 +2080,6 @@ clipboard_event_property_notify(XEvent *xevent) if (bytes_left <= 0) { LOGM((LOG_LEVEL_DEBUG, "clipboard_event_property_notify: INCR done")); - g_memset(format_name, 0, 32); /* clipboard INCR cycle has completed */ g_incr_in_progress = 0; g_last_clip_size = g_incr_data_size; @@ -1710,8 +2089,26 @@ clipboard_event_property_notify(XEvent *xevent) if (g_incr_atom_target == g_image_bmp_atom) { - g_snprintf(format_name, 31, "image/bmp"); - clipboard_send_format_announce(CB_FORMAT_DIB, format_name); + g_last_xrdp_clip_type = XRDP_CB_BITMAP; + //g_hexdump(g_last_clip_data, 64); + /* skip header */ + clipboard_send_data_response(g_last_xrdp_clip_type, + g_last_clip_data + 14, + g_last_clip_size - 14); + } + else if ((g_incr_atom_target == XA_STRING) || + (g_incr_atom_target == g_utf8_atom)) + { + g_last_xrdp_clip_type = XRDP_CB_TEXT; + clipboard_send_data_response(g_last_xrdp_clip_type, + g_last_clip_data, + g_last_clip_size); + } + else + { + LLOGLN(0, ("clipboard_event_property_notify: error unknown type %d", + g_incr_atom_target)); + clipboard_send_data_response_failed(); } XDeleteProperty(g_display, g_wnd, g_incr_atom_type); @@ -1810,6 +2207,18 @@ clipboard_xevent(void *xevent) clipboard_event_selection_owner_notify(lxevent); break; } + if (lxevent->type == g_xfixes_event_base + + XFixesSelectionWindowDestroyNotify) + { + LLOGLN(0, ("clipboard_xevent: got XFixesSelectionWindowDestroyNotify")); + break; + } + if (lxevent->type == g_xfixes_event_base + + XFixesSelectionClientCloseNotify) + { + LLOGLN(0, ("clipboard_xevent: got XFixesSelectionClientCloseNotify")); + break; + } /* we didn't handle this message */ return 1; diff --git a/sesman/chansrv/clipboard.h b/sesman/chansrv/clipboard.h index deb70b6b..80d8da3e 100644 --- a/sesman/chansrv/clipboard.h +++ b/sesman/chansrv/clipboard.h @@ -42,6 +42,9 @@ #define CB_FILECLIP_NO_FILE_PATHS 0x00000008 #define CB_CAN_LOCK_CLIPDATA 0x00000010 +#define CB_FILECONTENTS_SIZE 0x00000001 +#define CB_FILECONTENTS_RANGE 0x00000002 + #define CB_FORMAT_RAW 0x0000 #define CB_FORMAT_TEXT 0x0001 #define CB_FORMAT_DIB 0x0008 @@ -52,11 +55,35 @@ #define CB_FORMAT_GIF 0xD013 #define CB_FORMAT_FILE 0xC0BC +/* Used by the Format List Response PDU, Format Data Response PDU, and File + Contents Response PDU to indicate that the associated request Format List + PDU, Format Data Request PDU, and File Contents Request PDU were processed + successfully. */ +#define CB_RESPONSE_OK 0x0001 + +/* Used by the Format List Response PDU, Format Data Response PDU, and File + Contents Response PDU to indicate that the associated Format List PDU, + Format Data Request PDU, and File Contents Request PDU were not processed + successfully. */ +#define CB_RESPONSE_FAIL 0x0002 + +/* Used by the Short Format Name variant of the Format List Response PDU to + indicate the format names are in ASCII 8. */ +#define CB_ASCII_NAMES 0x0004 + /* these are the supported general types */ #define XRDP_CB_TEXT 1 #define XRDP_CB_BITMAP 2 #define XRDP_CB_FILE 3 +#define CB_FD_ATTRIBUTES 0x00000004 +#define CB_FD_FILESIZE 0x00000040 +#define CB_FD_WRITESTIME 0x00000020 +#define CB_FD_PROGRESSUI 0x00004000 + +#define CB_FILE_ATTRIBUTE_ARCHIVE 0x00000020; +#define CB_FILE_ATTRIBUTE_NORMAL 0x00000080; + int APP_CC clipboard_init(void); int APP_CC |