diff --git a/Makefile b/Makefile index 23269a3..c739d68 100644 --- a/Makefile +++ b/Makefile @@ -14,19 +14,20 @@ datadir = $(prefix)/share/rdesktop KEYMAP_PATH = $(datadir)/keymaps/ -RDPOBJ = rdesktop.o tcp.o iso.o mcs.o secure.o licence.o rdp.o orders.o bitmap.o cache.o xwin.o xkeymap.o ewmhints.o rdp5.o channels.o cliprdr.o ipc.o -RDP2VNCOBJ = vnc/rdp2vnc.o tcp.o iso.o mcs.o secure.o licence.o rdp.o orders.o bitmap.o cache.o vnc/vnc.o vnc/xkeymap.o vnc/x11stubs.o rdp5.o +RDPOBJ = tcp.o iso.o mcs.o secure.o licence.o rdp.o orders.o bitmap.o cache.o rdp5.o channels.o rdpsnd.o rdpdr.o serial.o printer.o +X11OBJ = rdesktop.o xwin.o xkeymap.o ewmhints.o xclip.o cliprdr.o +VNCOBJ = vnc/rdp2vnc.o vnc/vnc.o vnc/xkeymap.o vnc/x11stubs.o CRYPTOBJ = crypto/rc4_enc.o crypto/rc4_skey.o crypto/md5_dgst.o crypto/sha1dgst.o crypto/bn_exp.o crypto/bn_mul.o crypto/bn_div.o crypto/bn_sqr.o crypto/bn_add.o crypto/bn_shift.o crypto/bn_asm.o crypto/bn_ctx.o crypto/bn_lib.o include Makeconf # configure-generated all: $(TARGETS) -rdesktop: $(RDPOBJ) $(CRYPTOBJ) - $(CC) $(CFLAGS) -o rdesktop $(RDPOBJ) $(CRYPTOBJ) $(LDFLAGS) -lX11 +rdesktop: $(X11OBJ) $(RDPOBJ) $(CRYPTOBJ) + $(CC) $(CFLAGS) -o rdesktop $(X11OBJ) $(RDPOBJ) $(CRYPTOBJ) $(LDFLAGS) -lX11 -rdp2vnc: $(RDP2VNCOBJ) $(CRYPTOBJ) - $(CCLD) $(CFLAGS) -o rdp2vnc $(RDP2VNCOBJ) $(CRYPTOBJ) $(LDFLAGS) $(LDVNC) +rdp2vnc: $(VNCOBJ) $(RDPOBJ) $(CRYPTOBJ) + $(CCLD) $(CFLAGS) -o rdp2vnc $(VNCOBJ) $(RDPOBJ) $(CRYPTOBJ) $(LDFLAGS) $(LDVNC) vnc/rdp2vnc.o: rdesktop.c $(CC) $(CFLAGS) $(VNCINC) -DRDP2VNC -o vnc/rdp2vnc.o -c rdesktop.c diff --git a/channels.c b/channels.c index bd04390..dccf59d 100644 --- a/channels.c +++ b/channels.c @@ -1,7 +1,8 @@ /* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. - Protocol services - Channel register + Protocol services - Virtual channels Copyright (C) Erik Forsberg 2003 + Copyright (C) Matthew Chapman 2003 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,85 +21,151 @@ #include "rdesktop.h" -static uint16 num_channels; -static rdp5_channel *channels[MAX_RDP5_CHANNELS]; +#define MAX_CHANNELS 4 +#define CHANNEL_CHUNK_LENGTH 1600 +#define CHANNEL_FLAG_FIRST 0x01 +#define CHANNEL_FLAG_LAST 0x02 +#define CHANNEL_FLAG_SHOW_PROTOCOL 0x10 -uint16 -get_num_channels(void) -{ - return num_channels; -} +extern BOOL use_rdp5; +extern BOOL encryption; -/* FIXME: We should use the information in TAG_SRV_SRV_3 to map RDP5 +VCHANNEL g_channels[MAX_CHANNELS]; +unsigned int g_num_channels; + +/* FIXME: We should use the information in TAG_SRV_CHANNELS to map RDP5 channels to MCS channels. - The format of TAG_SRV_SRV_3 seems to be + The format of TAG_SRV_CHANNELS seems to be global_channel_no (uint16le) number_of_other_channels (uint16le) ..followed by uint16les for the other channels. - Might be a few (two) bytes of padding at the end. - */ -void -register_channel(char *name, uint32 flags, void (*callback) (STREAM, uint16)) +VCHANNEL * +channel_register(char *name, uint32 flags, void (*callback) (STREAM)) { - if (num_channels > MAX_RDP5_CHANNELS) - { - error("Maximum number of RDP5 channels reached. Redefine MAX_RDP5_CHANNELS in constants.h and recompile!\n!"); - } - num_channels++; - channels[num_channels - 1] = xrealloc(channels[num_channels - 1], - sizeof(rdp5_channel) * num_channels); - channels[num_channels - 1]->channelno = MCS_GLOBAL_CHANNEL + num_channels; - strcpy(channels[num_channels - 1]->name, name); - channels[num_channels - 1]->channelflags = flags; - channels[num_channels - 1]->channelcallback = callback; -} + VCHANNEL *channel; -rdp5_channel * -find_channel_by_channelno(uint16 channelno) -{ - if (channelno > MCS_GLOBAL_CHANNEL + num_channels) + if (!use_rdp5) + return NULL; + + if (g_num_channels >= MAX_CHANNELS) { - warning("Channel %d not defined. Highest channel defined is %d\n", - channelno, MCS_GLOBAL_CHANNEL + num_channels); + error("Channel table full, increase MAX_CHANNELS\n"); return NULL; } - else - { - return channels[channelno - MCS_GLOBAL_CHANNEL - 1]; - } + + channel = &g_channels[g_num_channels]; + channel->mcs_id = MCS_GLOBAL_CHANNEL + 1 + g_num_channels; + strncpy(channel->name, name, 8); + channel->flags = flags; + channel->process = callback; + g_num_channels++; + return channel; } -rdp5_channel * -find_channel_by_num(uint16 num) +STREAM +channel_init(VCHANNEL *channel, uint32 length) { - if (num > num_channels) - { - error("There are only %d channels defined, channel %d doesn't exist\n", - num_channels, num); - } - else - { - return channels[num]; - } - return NULL; // Shut the compiler up -} + STREAM s; - - -void -dummy_callback(STREAM s, uint16 channelno) -{ - warning("Server is sending information on our dummy channel (%d). Why?\n", channelno); + s = sec_init(encryption ? SEC_ENCRYPT : 0, length + 8); + s_push_layer(s, channel_hdr, 8); + return s; } void -channels_init(void) +channel_send(STREAM s, VCHANNEL *channel) { - DEBUG_RDP5(("channels_init\n")); - register_channel("dummych", 0xc0a0, dummy_callback); - register_channel("cliprdr", 0xc0a0, cliprdr_callback); + uint32 length, flags; + uint32 thislength, remaining; + char *data; + + /* first fragment sent in-place */ + s_pop_layer(s, channel_hdr); + length = s->end - s->p - 8; + + thislength = MIN(length, CHANNEL_CHUNK_LENGTH); + remaining = length - thislength; + flags = (remaining == 0) ? CHANNEL_FLAG_FIRST|CHANNEL_FLAG_LAST : CHANNEL_FLAG_FIRST; + if (channel->flags & CHANNEL_OPTION_SHOW_PROTOCOL) + flags |= CHANNEL_FLAG_SHOW_PROTOCOL; + + out_uint32_le(s, length); + out_uint32_le(s, flags); + data = s->end = s->p + thislength; + sec_send_to_channel(s, encryption ? SEC_ENCRYPT : 0, channel->mcs_id); + + /* subsequent segments copied (otherwise would have to generate headers backwards) */ + while (remaining > 0) + { + thislength = MIN(remaining, CHANNEL_CHUNK_LENGTH); + remaining -= thislength; + flags = (remaining == 0) ? CHANNEL_FLAG_LAST : 0; + + s = sec_init(encryption ? SEC_ENCRYPT : 0, thislength + 8); + out_uint32_le(s, length); + out_uint32_le(s, flags); + out_uint8p(s, data, thislength); + s_mark_end(s); + sec_send_to_channel(s, encryption ? SEC_ENCRYPT : 0, channel->mcs_id); + + data += thislength; + } } + +void +channel_process(STREAM s, uint16 mcs_channel) +{ + uint32 length, flags; + uint32 thislength; + VCHANNEL *channel; + unsigned int i; + STREAM in; + + for (i = 0; i < g_num_channels; i++) + { + channel = &g_channels[i]; + if (channel->mcs_id == mcs_channel) + break; + } + + if (i >= g_num_channels) + return; + + in_uint32_le(s, length); + in_uint32_le(s, flags); + if ((flags & CHANNEL_FLAG_FIRST) && (flags & CHANNEL_FLAG_LAST)) + { + /* single fragment - pass straight up */ + channel->process(s); + } + else + { + /* add fragment to defragmentation buffer */ + in = &channel->in; + if (flags & CHANNEL_FLAG_FIRST) + { + if (length > in->size) + { + in->data = xrealloc(in->data, length); + in->size = length; + } + in->p = in->data; + } + + thislength = s->end - s->p; + memcpy(in->p, s->p, thislength); + s->p += thislength; + s->end += thislength; + + if (flags & CHANNEL_FLAG_LAST) + { + in->p = in->data; + channel->process(in); + } + } +} + diff --git a/cliprdr.c b/cliprdr.c index b2ca5bc..8e6a796 100644 --- a/cliprdr.c +++ b/cliprdr.c @@ -2,6 +2,7 @@ rdesktop: A Remote Desktop Protocol client. Protocol services - Clipboard functions Copyright (C) Erik Forsberg 2003 + Copyright (C) Matthew Chapman 2003 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,767 +19,133 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include -#include -#include -#include -#include #include "rdesktop.h" -extern BOOL encryption; -extern Display *display; -extern Window wnd; -extern Time last_gesturetime; -extern Atom ipc_atom; +#define CLIPRDR_CONNECT 1 +#define CLIPRDR_FORMAT_ANNOUNCE 2 +#define CLIPRDR_FORMAT_ACK 3 +#define CLIPRDR_DATA_REQUEST 4 +#define CLIPRDR_DATA_RESPONSE 5 -// static Time selection_timestamp; -static Atom clipboard_atom, primary_atom, targets_atom, timestamp_atom; -static Atom rdesktop_clipboard_target_atom, incr_atom; -static cliprdr_dataformat *server_formats = NULL; -static uint16 num_server_formats = 0; -static XSelectionEvent selection_event; -static uint16 clipboard_channelno; -static Atom targets[NUM_TARGETS]; -static int have_primary = 0; -static int rdesktop_is_selection_owner = 0; +#define CLIPRDR_REQUEST 0 +#define CLIPRDR_RESPONSE 1 +#define CLIPRDR_ERROR 2 + +static VCHANNEL *cliprdr_channel; static void -cliprdr_print_server_formats(void) -{ -#ifdef WITH_DEBUG_CLIPBOARD - cliprdr_dataformat *this; - uint16 i = 0; - this = server_formats; - DEBUG_CLIPBOARD(("There should be %d server formats.\n", num_server_formats)); - while (NULL != this) - { - DEBUG_CLIPBOARD(("Format code %d\n", this->identifier)); - i++; - this = this->next; - } - DEBUG_CLIPBOARD(("There were %d server formats.\n", i)); -#endif -} - -/* -static void -cliprdr_set_selection_timestamp(void) -{ - XEvent xev; - DEBUG_CLIPBOARD(("Changing a property in order to get a timestamp\n")); - fflush(stdout); - XChangeProperty(display, wnd, rdesktop_clipboard_target_atom, - XA_ATOM, 32, PropModeAppend, 0, 0); - DEBUG_CLIPBOARD(("Waiting for PropertyChange on wnd\n")); - fflush(stdout); - XWindowEvent(display, wnd, - PropertyChangeMask, &xev); - DEBUG_CLIPBOARD(("Setting selection_timestamp\n")); - fflush(stdout); - selection_timestamp = xev.xproperty.time; -} -*/ - -static void -cliprdr_send_format_announce(void) +cliprdr_send_packet(uint16 type, uint16 status, uint8 *data, uint32 length) { STREAM s; - int number_of_formats = 1; - DEBUG_CLIPBOARD(("Sending (empty) format announce\n")); - s = sec_init(encryption ? SEC_ENCRYPT : 0, number_of_formats * 36 + 12 + 4 + 4); - out_uint32_le(s, number_of_formats * 36 + 12); - out_uint32_le(s, 0x13); - out_uint16_le(s, 2); - out_uint16_le(s, 0); - out_uint32_le(s, number_of_formats * 36); - // out_uint32_le(s, 0xd); // FIXME: This is a rather bogus unicode text description.. - // rdp_out_unistr(s, "", 16); - // out_uint8s(s, 32); + DEBUG_CLIPBOARD(("CLIPRDR send: type=%d, status=%d, length=%d\n", type, status, length)); - - out_uint32_le(s, 1); // FIXME: This is a rather bogus text description.. - out_uint8s(s, 32); - - out_uint32_le(s, 0); - - s_mark_end(s); - sec_send_to_channel(s, encryption ? SEC_ENCRYPT : 0, clipboard_channelno); -} - -void -cliprdr_ipc_format_announce(unsigned char *data, uint16 length) -{ - STREAM s; - rdesktop_is_selection_owner = 1; - DEBUG_CLIPBOARD(("cliprdr_ipc_format_announce called, length is %d, data is %s, sending native format announce\n", length, data)); - - s = sec_init(encryption ? SEC_ENCRYPT : 0, length + 12 + 4 + 4); - out_uint32_le(s, length + 12); - out_uint32_le(s, 0x13); - out_uint16_le(s, 2); - out_uint16_le(s, 0); + s = channel_init(cliprdr_channel, length + 12); + out_uint16_le(s, type); + out_uint16_le(s, status); out_uint32_le(s, length); out_uint8p(s, data, length); - out_uint32_le(s, 0); // Pad + out_uint32(s, 0); /* pad? */ s_mark_end(s); - - sec_send_to_channel(s, encryption ? SEC_ENCRYPT : 0, clipboard_channelno); -} - - - - -static void -cliprdr_send_empty_datapacket(void) -{ - STREAM out; - out = sec_init(encryption ? SEC_ENCRYPT : 0, 20); - out_uint32_le(out, 12); - out_uint32_le(out, 0x13); - out_uint16_le(out, 5); - out_uint16_le(out, 1); - out_uint32_le(out, 0); - /* Insert null string here? */ - out_uint32_le(out, 0); - s_mark_end(out); - - sec_send_to_channel(out, encryption ? SEC_ENCRYPT : 0, clipboard_channelno); -} - - -void -cliprdr_handle_SelectionNotify(XSelectionEvent * event) -{ - - unsigned char *data, *datap; - unsigned long nitems, bytes_left; - - unsigned long bytes_left_to_transfer; - int res, i; - - int format; - Atom type_return; - Atom best_target, text_target; - Atom *supported_targets; - - STREAM out; - - DEBUG_CLIPBOARD(("cliprdr_handle_SelectionNotify\n")); - - if (None == event->property) - { - cliprdr_send_empty_datapacket(); - return; /* Selection failed */ - } - - DEBUG_CLIPBOARD(("selection: %s, target: %s, property: %s\n", - XGetAtomName(display, event->selection), - XGetAtomName(display, event->target), - XGetAtomName(display, event->property))); - - if (targets_atom == event->target) - { - /* Response to TARGETS request. Let's find the target - we want and request that */ - res = XGetWindowProperty(display, wnd, - rdesktop_clipboard_target_atom, - 0L, 4096L, False, AnyPropertyType, - &type_return, &format, &nitems, &bytes_left, &data); - - if (Success != res) - { - DEBUG_CLIPBOARD(("XGetWindowProperty failed!\n")); - cliprdr_send_empty_datapacket(); - return; - } - - if (None == type_return) - /* The owner might no support TARGETS. Just try - STRING */ - best_target = XA_STRING; - else - { - /* FIXME: We should choose format here based - on what the server wanted */ - supported_targets = (Atom *) data; - best_target = XInternAtom(display, "STRING", False); - text_target = XInternAtom(display, "TEXT", False); - for (i = 0; i < nitems; i++) - { - DEBUG_CLIPBOARD(("Target %d: %s\n", - i, XGetAtomName(display, supported_targets[i]))); - if (text_target == supported_targets[i]) - { - DEBUG_CLIPBOARD(("Other party supports TEXT, choosing that as best_target\n")); - best_target = supported_targets[i]; - } - } - - - - } - - XConvertSelection(display, primary_atom, - best_target, rdesktop_clipboard_target_atom, wnd, event->time); - - } - - else /* Other clipboard data */ - { - - res = XGetWindowProperty(display, wnd, - rdesktop_clipboard_target_atom, - 0L, 0x1FFFFFF, - True, AnyPropertyType, - &type_return, &format, &nitems, &bytes_left, &data); - - - /* FIXME: We need to handle INCR as well, - this is a temporary solution. */ - - if (incr_atom == type_return) - { - warning("We don't support INCR transfers at this time. Try cutting less data\n"); - cliprdr_send_empty_datapacket(); - } - - - if (Success != res) - { - DEBUG_CLIPBOARD(("XGetWindowProperty failed!\n")); - cliprdr_send_empty_datapacket(); - return; - } - - datap = data; - - if (nitems + 1 <= MAX_CLIPRDR_STANDALONE_DATASIZE) - { - out = sec_init(encryption ? SEC_ENCRYPT : 0, 20 + nitems + 1); - out_uint32_le(out, 12 + nitems + 1); - out_uint32_le(out, 0x13); - out_uint16_le(out, 5); - out_uint16_le(out, 1); - out_uint32_le(out, nitems + 1); - out_uint8p(out, datap, nitems + 1); - out_uint32_le(out, 0); - s_mark_end(out); - - sec_send_to_channel(out, encryption ? SEC_ENCRYPT : 0, clipboard_channelno); - - } - else - { - DEBUG_CLIPBOARD(("Sending %d bytes of data\n", - 16 + MAX_CLIPRDR_STANDALONE_DATASIZE)); - out = sec_init(encryption ? SEC_ENCRYPT : 0, - 16 + MAX_CLIPRDR_STANDALONE_DATASIZE); - out_uint32_le(out, nitems + 12); - out_uint32_le(out, 0x11); - out_uint16_le(out, 5); - out_uint16_le(out, 1); - out_uint32_le(out, nitems); - out_uint8p(out, datap, MAX_CLIPRDR_STANDALONE_DATASIZE); - s_mark_end(out); - - sec_send_to_channel(out, encryption ? SEC_ENCRYPT : 0, clipboard_channelno); - - bytes_left_to_transfer = nitems - MAX_CLIPRDR_STANDALONE_DATASIZE; - datap += MAX_CLIPRDR_STANDALONE_DATASIZE; - - while (bytes_left_to_transfer > MAX_CLIPRDR_STANDALONE_DATASIZE) - { - DEBUG_CLIPBOARD(("Sending %d bytes of data\n", - 16 + MAX_CLIPRDR_CONTINUATION_DATASIZE)); - out = sec_init(encryption ? SEC_ENCRYPT : 0, - 8 + MAX_CLIPRDR_CONTINUATION_DATASIZE); - out_uint32_le(out, nitems); - out_uint32_le(out, 0x10); - out_uint8p(out, datap, MAX_CLIPRDR_CONTINUATION_DATASIZE); - s_mark_end(out); - - sec_send_to_channel(out, - encryption ? SEC_ENCRYPT : 0, - clipboard_channelno); - bytes_left_to_transfer -= MAX_CLIPRDR_CONTINUATION_DATASIZE; - datap += MAX_CLIPRDR_CONTINUATION_DATASIZE; - - } - DEBUG_CLIPBOARD(("Sending %u bytes of data\n", - 12 + bytes_left_to_transfer)); - out = sec_init(encryption ? SEC_ENCRYPT : 0, 12 + bytes_left_to_transfer); - out_uint32_le(out, nitems); - out_uint32_le(out, 0x12); - out_uint8p(out, datap, bytes_left_to_transfer); - out_uint32_le(out, 0x0); - s_mark_end(out); - - sec_send_to_channel(out, encryption ? SEC_ENCRYPT : 0, clipboard_channelno); - - } - - - XFree(data); - if (!rdesktop_is_selection_owner) - cliprdr_send_format_announce(); - - } - - + channel_send(s, cliprdr_channel); } void -cliprdr_handle_SelectionClear(void) +cliprdr_send_text_format_announce(void) { - DEBUG_CLIPBOARD(("cliprdr_handle_SelectionClear\n")); - have_primary = 0; - ipc_send_message(RDESKTOP_IPC_CLIPRDR_PRIMARY_LOST, "", 0); - cliprdr_send_format_announce(); -} + uint8 buffer[36]; - -static void -cliprdr_request_clipboard_data(uint32 formatcode) -{ - STREAM s; - s = sec_init(encryption ? SEC_ENCRYPT : 0, 24); - out_uint32_le(s, 16); - out_uint32_le(s, 0x13); - out_uint16_le(s, 4); - out_uint16_le(s, 0); - out_uint32_le(s, 4); // Remaining length - out_uint32_le(s, formatcode); - out_uint32_le(s, 0); // Unknown. Garbage pad? - - s_mark_end(s); - - sec_send_to_channel(s, encryption ? SEC_ENCRYPT : 0, clipboard_channelno); -} - - -void -cliprdr_handle_SelectionRequest(XSelectionRequestEvent * xevent) -{ - - XSelectionEvent xev; - unsigned long nitems, bytes_left; - Atom type_return; - uint32 *wanted_formatcode; - int format; - - DEBUG_CLIPBOARD(("cliprdr_handle_SelectionRequest\n")); - DEBUG_CLIPBOARD(("Requestor window id 0x%x ", (unsigned) xevent->requestor)); - if (clipboard_atom == xevent->selection) - { - DEBUG_CLIPBOARD(("wants CLIPBOARD\n")); - } - if (primary_atom == xevent->selection) - { - DEBUG_CLIPBOARD(("wants PRIMARY\n")); - } - DEBUG_CLIPBOARD(("Target is %s (0x%x), property is %s (0x%x)\n", - XGetAtomName(display, xevent->target), - (unsigned) xevent->target, - XGetAtomName(display, xevent->property), (unsigned) xevent->property)); - - xev.type = SelectionNotify; - xev.serial = 0; - xev.send_event = True; - xev.requestor = xevent->requestor; - xev.selection = xevent->selection; - xev.target = xevent->target; - xev.property = xevent->property; - xev.time = xevent->time; - - memcpy(&selection_event, &xev, sizeof(xev)); - - if (ipc_atom == xevent->target) - { - DEBUG_CLIPBOARD(("Target atom is ipc_atom, getting INTEGER from requestor\n")); - XGetWindowProperty(display, xevent->requestor, - rdesktop_clipboard_target_atom, - 0, - 1, - True, XA_INTEGER, - &type_return, - &format, - &nitems, &bytes_left, (unsigned char **) &wanted_formatcode); - DEBUG_CLIPBOARD(("Got wanted formatcode %d, format is %d\n", *wanted_formatcode, - format)); - cliprdr_request_clipboard_data(*wanted_formatcode); - } - - else if (targets_atom == xevent->target) - { - DEBUG_CLIPBOARD(("TARGETS requested, sending list..\n")); - XChangeProperty(display, - xevent->requestor, - xevent->property, - XA_ATOM, - 32, PropModeAppend, (unsigned char *) &targets, NUM_TARGETS); - - XSendEvent(display, xevent->requestor, False, NoEventMask, (XEvent *) & xev); - return; - } - else if (timestamp_atom == xevent->target) - { - DEBUG_CLIPBOARD(("Sending TIMESTAMP\n")); - XChangeProperty(display, - xevent->requestor, - xevent->property, - XA_INTEGER, - 32, PropModeAppend, (unsigned char *) &last_gesturetime, 1); - XSendEvent(display, xevent->requestor, False, NoEventMask, (XEvent *) & xev); - } - else /* Some other target */ - { - cliprdr_request_clipboard_data(CF_TEXT); - /* Return and wait for data, handled by - cliprdr_handle_server_data */ - } -} - - -static void -cliprdr_ack_format_list(void) -{ - STREAM s; - s = sec_init(encryption ? SEC_ENCRYPT : 0, 20); - out_uint32_le(s, 12); - out_uint32_le(s, 0x13); - out_uint16_le(s, 3); - out_uint16_le(s, 1); - out_uint32_le(s, 0); - out_uint32_le(s, 0x0000c0da); - - s_mark_end(s); - - sec_send_to_channel(s, encryption ? SEC_ENCRYPT : 0, clipboard_channelno); -} - - - - - -static void -cliprdr_register_server_formats(STREAM s) -{ - uint32 remaining_length, pad; - uint16 num_formats; - cliprdr_dataformat *this, *next; - - in_uint32_le(s, remaining_length); - DEBUG_CLIPBOARD(("cliprdr_register_server_formats, remaining_length is %d\n", - remaining_length)); - - - num_formats = remaining_length / 36; - - ipc_send_message(RDESKTOP_IPC_CLIPRDR_FORMAT_ANNOUNCE, s->p, remaining_length); - if (NULL != server_formats) - { - this = server_formats; - next = this->next; - while (NULL != next) - { - xfree(this); - this = NULL; - this = next; - next = this->next; - } - } - this = xmalloc(sizeof(cliprdr_dataformat)); - this->next = NULL; - server_formats = this; - num_server_formats = num_formats; - while (1 < num_formats) - { - in_uint32_le(s, this->identifier); - in_uint8a(s, this->textual_description, 32); - DEBUG_CLIPBOARD(("Stored format description with numeric id %d\n", - this->identifier)); - this->next = xmalloc(sizeof(cliprdr_dataformat)); - this = this->next; - num_formats--; - } - in_uint32_le(s, this->identifier); - DEBUG_CLIPBOARD(("Stored format description with numeric id %d\n", this->identifier)); - in_uint8a(s, this->textual_description, 32); - this->next = NULL; - in_uint32_le(s, pad); - cliprdr_print_server_formats(); -} - -static void -cliprdr_select_X_clipboards(void) -{ - XSetSelectionOwner(display, primary_atom, wnd, last_gesturetime); - if (wnd != XGetSelectionOwner(display, primary_atom)) - { - warning("Failed to aquire ownership of PRIMARY clipboard\n"); - } - else - { - have_primary = 1; - } - XSetSelectionOwner(display, clipboard_atom, wnd, last_gesturetime); - if (wnd != XGetSelectionOwner(display, clipboard_atom)) - { - warning("Failed to aquire ownership of CLIPBOARD clipboard\n"); - } - -} - - - -static void -cliprdr_handle_first_handshake(STREAM s) -{ - uint32 remaining_length, pad; - in_uint32_le(s, remaining_length); - in_uint32_le(s, pad); - DEBUG_CLIPBOARD(("Remaining length in first handshake frm server is %d, pad is %d\n", - remaining_length, pad)); - cliprdr_send_format_announce(); + buf_out_uint32(buffer, CF_TEXT); + memset(buffer+4, 0, sizeof(buffer)-4); /* description */ + cliprdr_send_packet(CLIPRDR_FORMAT_ANNOUNCE, CLIPRDR_REQUEST, buffer, sizeof(buffer)); } void -cliprdr_handle_server_data(uint32 length, uint32 flags, STREAM s) +cliprdr_send_blah_format_announce(void) { - static uint32 remaining_length; - static char *data, *datap; - static uint32 bytes_left_to_read; - DEBUG_CLIPBOARD(("In cliprdr_handle_server_data, flags is %d\n", flags)); - if (3 == flags) /* One-op write, no packets follows */ - { - in_uint32_le(s, remaining_length); - data = s->p; - } - else if (1 == flags) /* First of several packets */ - { - in_uint32_le(s, remaining_length); - DEBUG_CLIPBOARD(("Remaining length is %d\n", remaining_length)); - data = xmalloc(remaining_length); - datap = data; - DEBUG_CLIPBOARD(("Copying first %d bytes\n", MAX_CLIPRDR_STANDALONE_DATASIZE)); - memcpy(datap, s->p, MAX_CLIPRDR_STANDALONE_DATASIZE); - - datap += MAX_CLIPRDR_STANDALONE_DATASIZE; - bytes_left_to_read = remaining_length - MAX_CLIPRDR_STANDALONE_DATASIZE; - return; - } - else if (0 == flags) - { - DEBUG_CLIPBOARD(("Copying %d middle bytes", MAX_CLIPRDR_CONTINUATION_DATASIZE)); - memcpy(datap, s->p, MAX_CLIPRDR_CONTINUATION_DATASIZE); - - datap += MAX_CLIPRDR_CONTINUATION_DATASIZE; - bytes_left_to_read -= MAX_CLIPRDR_CONTINUATION_DATASIZE; - return; - } - else if (2 == flags) - { - DEBUG_CLIPBOARD(("Copying last %d bytes\n", bytes_left_to_read)); - memcpy(datap, s->p, bytes_left_to_read); - } - DEBUG_CLIPBOARD(("Setting target atom (%s) on %d\n", - XGetAtomName(display, selection_event.property), - selection_event.requestor)); - XChangeProperty(display, - selection_event.requestor, - selection_event.property, - XInternAtom(display, "STRING", False), - 8, PropModeAppend, data, remaining_length - 1); - - XSendEvent(display, - selection_event.requestor, False, NoEventMask, (XEvent *) & selection_event); - - if (2 == flags) - xfree(data); + uint8 buffer[36]; + buf_out_uint32(buffer, CF_OEMTEXT); + memset(buffer+4, 0, sizeof(buffer)-4); /* description */ + cliprdr_send_packet(CLIPRDR_FORMAT_ANNOUNCE, CLIPRDR_REQUEST, buffer, sizeof(buffer)); } void -cliprdr_handle_server_data_request(STREAM s) +cliprdr_send_native_format_announce(uint8 *data, uint32 length) { - Window selectionowner; - uint32 remaining_length; - uint32 wanted_formatcode, pad; - - in_uint32_le(s, remaining_length); - in_uint32_le(s, wanted_formatcode); - in_uint32_le(s, pad); - - /* FIXME: Check that we support this formatcode */ - - DEBUG_CLIPBOARD(("Request from server for format %d\n", wanted_formatcode)); - - selectionowner = XGetSelectionOwner(display, primary_atom); - - if (rdesktop_is_selection_owner) - { - DEBUG_CLIPBOARD(("XChangeProperty, rdesktop_is_selection_owner\n")); - XChangeProperty(display, wnd, rdesktop_clipboard_target_atom, - XA_INTEGER, 32, PropModeReplace, - (unsigned char *) &wanted_formatcode, 1); - - XConvertSelection(display, primary_atom, - ipc_atom, rdesktop_clipboard_target_atom, wnd, CurrentTime); - return; - } - - - if (None != selectionowner) - { - - /* FIXME: Perhaps we should check if we are the owner? */ - - XConvertSelection(display, primary_atom, - targets_atom, rdesktop_clipboard_target_atom, wnd, CurrentTime); - - /* The rest of the transfer is handled in - cliprdr_handle_SelectionNotify */ - - } - else - { - - selectionowner = XGetSelectionOwner(display, clipboard_atom); - if (None != selectionowner) - { - XConvertSelection(display, clipboard_atom, - targets_atom, - rdesktop_clipboard_target_atom, wnd, CurrentTime); - - /* The rest of the transfer is handled in - cliprdr_handle_SelectionNotify */ - - } - else - { - - DEBUG_CLIPBOARD(("There were no owner for PRIMARY nor CLIPBOARD, sending empty string\n")); // FIXME: Should we always send an empty string? - - cliprdr_send_empty_datapacket(); - } - } - - + cliprdr_send_packet(CLIPRDR_FORMAT_ANNOUNCE, CLIPRDR_REQUEST, data, length); } +void +cliprdr_send_data_request(uint32 format) +{ + uint8 buffer[4]; + + buf_out_uint32(buffer, format); + cliprdr_send_packet(CLIPRDR_DATA_REQUEST, CLIPRDR_REQUEST, buffer, sizeof(buffer)); +} void -cliprdr_callback(STREAM s, uint16 channelno) +cliprdr_send_data(uint8 *data, uint32 length) { - static int failed_clipboard_acks = 0; - struct timeval timeval; - uint32 length, flags; - uint16 ptype0, ptype1; - clipboard_channelno = channelno; - DEBUG_CLIPBOARD(("cliprdr_callback called with channelno %d, clipboard data:\n", - channelno)); -#ifdef WITH_DEBUG_CLIPBOARD - // hexdump(s->p, s->end - s->p); -#endif + cliprdr_send_packet(CLIPRDR_DATA_RESPONSE, CLIPRDR_RESPONSE, data, length); +} + +static void +cliprdr_process(STREAM s) +{ + uint16 type, status; + uint32 length, format; + char *data; + + in_uint16_le(s, type); + in_uint16_le(s, status); in_uint32_le(s, length); - in_uint32_le(s, flags); + data = s->p; - DEBUG_CLIPBOARD(("length is %d, flags are %d\n", length, flags)); + DEBUG_CLIPBOARD(("CLIPRDR recv: type=%d, status=%d, length=%d\n", type, status, length)); - if (3 == flags || 1 == flags) /* Single-write op or first-packet-of-several op */ + if (status == CLIPRDR_ERROR) { - in_uint16_le(s, ptype0); - in_uint16_le(s, ptype1); - DEBUG_CLIPBOARD(("ptype0 is %d, ptype1 is %d\n", ptype0, ptype1)); - if (1 == ptype0 && 0 == ptype1) + if (type == CLIPRDR_FORMAT_ACK) { - cliprdr_handle_first_handshake(s); + /* FIXME: We seem to get this when we send an announce while the server is + still processing a paste. Try sending another announce. */ + cliprdr_send_text_format_announce(); return; } - else if (3 == ptype0 && 1 == ptype1) - { - // Acknowledgment on our format announce. Do we care? Not right now. - // There is a strange pad in this packet that we might need some time, - // but probably not. - DEBUG_CLIPBOARD(("Received format announce ACK\n")); - failed_clipboard_acks = 0; - return; - - } - else if (3 == ptype0 && 2 == ptype1) - { - DEBUG_CLIPBOARD(("Received failed clipboard format announce ACK, retrying\n")); - - /* This is a fairly portable way to sleep 1/10 of - a second.. */ - timeval.tv_sec = 0; - timeval.tv_usec = 100; - select(0, NULL, NULL, NULL, &timeval); - if (failed_clipboard_acks < 3) - { - - cliprdr_send_format_announce(); - /* Make sure we don't get stuck in this loop */ - failed_clipboard_acks++; - } - else - { - warning("Reached maximum number of clipboard format announce attempts. Pasting in Windows probably won't work well now.\n"); - } - } - else if (2 == ptype0 && 0 == ptype1) - { - cliprdr_register_server_formats(s); - cliprdr_select_X_clipboards(); - cliprdr_ack_format_list(); - return; - } - else if (5 == ptype0 && 1 == ptype1) - { - cliprdr_handle_server_data(length, flags, s); - } - else if (4 == ptype0 && 0 == ptype1) - { - cliprdr_handle_server_data_request(s); - } - + error("CLIPRDR error (type=%d)\n", type); + return; } - else + + switch (type) { - DEBUG_CLIPBOARD(("Handling middle or last packet\n")); - cliprdr_handle_server_data(length, flags, s); + case CLIPRDR_CONNECT: + ui_clip_sync(); + break; + case CLIPRDR_FORMAT_ANNOUNCE: + ui_clip_format_announce(data, length); + cliprdr_send_packet(CLIPRDR_FORMAT_ACK, CLIPRDR_RESPONSE, NULL, 0); + return; + case CLIPRDR_FORMAT_ACK: + break; + case CLIPRDR_DATA_REQUEST: + in_uint32_le(s, format); + ui_clip_request_data(format); + break; + case CLIPRDR_DATA_RESPONSE: + ui_clip_handle_data(data, length); + break; + default: + unimpl("CLIPRDR packet type %d\n", type); } } -void -cliprdr_ipc_primary_lost(unsigned char *data, uint16 length) -{ - DEBUG_CLIPBOARD(("cliprdr_ipc_primary_lost called\n")); - if (!have_primary) - cliprdr_send_format_announce(); - rdesktop_is_selection_owner = 0; -} - - -void +BOOL cliprdr_init(void) { - primary_atom = XInternAtom(display, "PRIMARY", False); - clipboard_atom = XInternAtom(display, "CLIPBOARD", False); - targets_atom = XInternAtom(display, "TARGETS", False); - timestamp_atom = XInternAtom(display, "TIMESTAMP", False); - rdesktop_clipboard_target_atom = XInternAtom(display, "_RDESKTOP_CLIPBOARD_TARGET", False); - incr_atom = XInternAtom(display, "INCR", False); - targets[0] = targets_atom; - targets[1] = XInternAtom(display, "TEXT", False); - targets[2] = XInternAtom(display, "UTF8_STRING", False); - targets[3] = XInternAtom(display, "text/unicode", False); - targets[4] = XInternAtom(display, "TIMESTAMP", False); - targets[5] = XInternAtom(display, "STRING", False); - ipc_register_ipcnotify(RDESKTOP_IPC_CLIPRDR_FORMAT_ANNOUNCE, cliprdr_ipc_format_announce); - ipc_register_ipcnotify(RDESKTOP_IPC_CLIPRDR_FORMAT_ANNOUNCE, cliprdr_ipc_primary_lost); - - + cliprdr_channel = channel_register("cliprdr", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP \ + | CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL, cliprdr_process); + return (cliprdr_channel != NULL); } diff --git a/constants.h b/constants.h index af3665e..204e8eb 100644 --- a/constants.h +++ b/constants.h @@ -69,12 +69,12 @@ enum MCS_PDU_TYPE #define SEC_TAG_SRV_INFO 0x0c01 #define SEC_TAG_SRV_CRYPT 0x0c02 -#define SEC_TAG_SRV_3 0x0c03 +#define SEC_TAG_SRV_CHANNELS 0x0c03 #define SEC_TAG_CLI_INFO 0xc001 #define SEC_TAG_CLI_CRYPT 0xc002 -#define SEC_TAG_CLI_4 0xc004 #define SEC_TAG_CLI_CHANNELS 0xc003 +#define SEC_TAG_CLI_4 0xc004 #define SEC_TAG_PUBKEY 0x0006 #define SEC_TAG_KEYSIG 0x0008 @@ -262,10 +262,6 @@ enum RDP_INPUT_DEVICE #define MASK_HAS_BITS(var, mask) ((var & mask)>0) #define MASK_CHANGE_BIT(var, mask, active) (var = ((var & ~mask) | (active ? mask : 0))) -/* RDP5 channel constants */ -#define MAX_RDP5_CHANNELS 10 -#define CHANNEL_TAGDATA_SIZE 12 - /* Clipboard constants, "borrowed" from GCC system headers in the w32 cross compiler */ @@ -296,10 +292,15 @@ enum RDP_INPUT_DEVICE #define CF_GDIOBJFIRST 768 #define CF_GDIOBJLAST 1023 -#define NUM_TARGETS 6 -#define MAX_CLIPRDR_STANDALONE_DATASIZE 1592 -#define MAX_CLIPRDR_CONTINUATION_DATASIZE 1600 +/* Virtual channel options */ +#define CHANNEL_OPTION_INITIALIZED 0x80000000 +#define CHANNEL_OPTION_ENCRYPT_RDP 0x40000000 +#define CHANNEL_OPTION_COMPRESS_RDP 0x00800000 +#define CHANNEL_OPTION_SHOW_PROTOCOL 0x00200000 + +/* NT status codes for RDPDR */ +#define STATUS_SUCCESS 0x00000000 +#define STATUS_INVALID_PARAMETER 0xc000000d +#define STATUS_INVALID_DEVICE_REQUEST 0xc0000010 +#define STATUS_ACCESS_DENIED 0xc0000022 -#define RDESKTOP_IPC_VERSION 1 -#define RDESKTOP_IPC_CLIPRDR_FORMAT_ANNOUNCE 2 -#define RDESKTOP_IPC_CLIPRDR_PRIMARY_LOST 3 diff --git a/ipc.c b/ipc.c deleted file mode 100644 index 2e5e5ba..0000000 --- a/ipc.c +++ /dev/null @@ -1,205 +0,0 @@ -/* -*- c-basic-offset: 8 -*- - rdesktop: A Remote Desktop Protocol client. - Communication between different rdesktop processes using X properties - Copyright (C) Erik Forsberg 2003 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include "rdesktop.h" -#include "xproto.h" - -Atom ipc_atom; - -extern Display *display; -extern Window wnd; - -static struct stream in; -static struct stream out; -static const uint16 headerlen = 12; - -struct _ipc_channel; - -typedef struct _ipc_channel -{ - uint16 messagetype; - void (*callback) (unsigned char *, uint16 length); - struct _ipc_channel *next; -} -ipc_channel; - -static ipc_channel *ipc_channels = NULL; - -void -ipc_register_ipcnotify(uint16 messagetype, void (*notifycallback) (unsigned char *, uint16)) -{ - ipc_channel *this; - if (NULL != ipc_channels) - { - this = ipc_channels; - while (NULL != this->next) - this = this->next; - this->next = xmalloc(sizeof(ipc_channel)); - this->next->next = NULL; - this = this->next; - } - else - { - this = xmalloc(sizeof(ipc_channel)); - this->next = NULL; - ipc_channels = this; - } - this->messagetype = messagetype; - this->callback = notifycallback; -} - -void -ipc_deregister_ipcnotify(uint16 messagetype) -{ - ipc_channel *this, *prev; - prev = this = ipc_channels; - while (NULL != this) - { - if (this->messagetype == messagetype) - { - if (prev == this) - ipc_channels = this->next; - else - prev->next = this->next; - xfree(this); - return; - } - } -} - -void -ipc_recv_message(XPropertyEvent * xev) -{ - int actual_format_return; - unsigned long nitems_return, bytes_after_return; - unsigned char *prop_return; - unsigned char *data = NULL; - uint16 totalsize, rdesktop_ipc_version, messagetype; - uint32 sender_wnd; - Atom actual_type_return; - ipc_channel *channel = ipc_channels; - - DEBUG_RDP5(("Got event in ipc_recv_message\n")); - - in.end = in.p = in.data; - - XGetWindowProperty(display, DefaultRootWindow(display), ipc_atom, 0, 1, False, // Delete - AnyPropertyType, - &actual_type_return, - &actual_format_return, - &nitems_return, &bytes_after_return, &prop_return); - - memcpy(in.end, prop_return, 2); - XFree(prop_return); - in_uint32_le(&in, totalsize); - in.end += 4; - - DEBUG_RDP5(("ipc totalsize is %d\n", totalsize)); - - XGetWindowProperty(display, DefaultRootWindow(display), ipc_atom, 1, (totalsize - 1) / 4, False, // Delete - AnyPropertyType, - &actual_type_return, - &actual_format_return, - &nitems_return, &bytes_after_return, &prop_return); - - memcpy(in.end, prop_return, totalsize - 4); - XFree(prop_return); - - in_uint16_le(&in, rdesktop_ipc_version); - - DEBUG_RDP5(("Got rdesktop_ipc_version %d\n", rdesktop_ipc_version)); - - if (rdesktop_ipc_version > RDESKTOP_IPC_VERSION) - { - warning("IPC version of sending Rdesktop is higher than ours. Returning without trying to parse message\n"); - return; - } - - in_uint16_le(&in, messagetype); - in_uint32_le(&in, sender_wnd); - - DEBUG_RDP5(("header: %d, %d, %d\n", rdesktop_ipc_version, messagetype, sender_wnd)); - - - if (sender_wnd == wnd) - { - DEBUG_RDP5(("We sent this message, returning..\n")); - return; /* We are not interested in our own events.. */ - } - - DEBUG_RDP5(("Not our window..\n")); - - /* Check if we are interested by traversing our callback list */ - while (NULL != channel) - { - DEBUG_RDP5(("Found channel for messagetype %d\n", channel->messagetype)); - if (messagetype == channel->messagetype) - { - data = xmalloc(in.size - headerlen); - in_uint8p(&in, data, totalsize - headerlen); - channel->callback(data, totalsize - headerlen); - return; - } - /* Callback is responsible for freeing data */ - channel = channel->next; - } -} - -void -ipc_init(void) -{ - ipc_atom = XInternAtom(display, "_RDESKTOP_IPC", False); - xwin_register_propertynotify(DefaultRootWindow(display), ipc_atom, ipc_recv_message); - in.size = 4096; - in.data = xmalloc(in.size); - out.size = 4096; - out.data = xmalloc(out.size); -} - -void -ipc_send_message(uint16 messagetype, unsigned char *data, uint16 length) -{ - - if ((length + headerlen) > out.size) - { - out.data = xrealloc(out.data, length + headerlen); - out.size = length + headerlen; - } - out.p = out.data; - out.end = out.data + out.size; - - out_uint32_le(&out, length + headerlen); - - out_uint16_le(&out, RDESKTOP_IPC_VERSION); - out_uint16_le(&out, messagetype); - out_uint32_le(&out, wnd); - - out_uint8p(&out, data, length); - s_mark_end(&out); - - DEBUG_RDP5(("length+headerlen is %d\n", length + headerlen)); - - XChangeProperty(display, - DefaultRootWindow(display), - ipc_atom, XA_STRING, 8, PropModeReplace, out.data, out.end - out.data); - XFlush(display); -} diff --git a/mcs.c b/mcs.c index b980621..7e162b0 100644 --- a/mcs.c +++ b/mcs.c @@ -21,7 +21,8 @@ #include "rdesktop.h" uint16 g_mcs_userid; -extern BOOL use_rdp5; +extern VCHANNEL g_channels[]; +extern unsigned int g_num_channels; /* Parse an ASN.1 BER header */ static BOOL @@ -374,8 +375,8 @@ mcs_recv(uint16 * channel) BOOL mcs_connect(char *server, STREAM mcs_data, char *username) { - uint16 num_channels, i; - rdp5_channel *channel; + unsigned int i; + if (!iso_connect(server, username)) return False; @@ -398,18 +399,12 @@ mcs_connect(char *server, STREAM mcs_data, char *username) if (!mcs_recv_cjcf()) goto error; - if (use_rdp5) + for (i = 0; i < g_num_channels; i++) { - num_channels = get_num_channels(); - for (i = 0; i < num_channels; i++) - { - channel = find_channel_by_num(i); - mcs_send_cjrq(channel->channelno); - if (!mcs_recv_cjcf()) - goto error; - } + mcs_send_cjrq(g_channels[i].mcs_id); + if (!mcs_recv_cjcf()) + goto error; } - return True; error: diff --git a/parse.h b/parse.h index d0412b7..cacea51 100644 --- a/parse.h +++ b/parse.h @@ -31,6 +31,7 @@ typedef struct stream unsigned char *mcs_hdr; unsigned char *sec_hdr; unsigned char *rdp_hdr; + unsigned char *channel_hdr; } *STREAM; diff --git a/printer.c b/printer.c new file mode 100644 index 0000000..331034a --- /dev/null +++ b/printer.c @@ -0,0 +1,35 @@ +#include "rdesktop.h" + +FILE *printer_fp; + +static NTSTATUS +printer_create(HANDLE *handle) +{ + printer_fp = popen("lpr", "w"); + *handle = 0; + return STATUS_SUCCESS; +} + +static NTSTATUS +printer_close(HANDLE handle) +{ + pclose(printer_fp); + return STATUS_SUCCESS; +} + +static NTSTATUS +printer_write(HANDLE handle, uint8 *data, uint32 length, uint32 *result) +{ + *result = fwrite(data, 1, length, printer_fp); + return STATUS_SUCCESS; +} + +DEVICE_FNS printer_fns = +{ + printer_create, + printer_close, + NULL, /* read */ + printer_write, + NULL /* device_control */ +}; + diff --git a/proto.h b/proto.h index 0364a10..cc25eef 100644 --- a/proto.h +++ b/proto.h @@ -1,41 +1,29 @@ /* bitmap.c */ -BOOL bitmap_decompress(unsigned char *output, int width, int height, unsigned char *input, int size, - int Bpp); +BOOL bitmap_decompress(unsigned char *output, int width, int height, unsigned char *input, int size, int Bpp); /* cache.c */ HBITMAP cache_get_bitmap(uint8 cache_id, uint16 cache_idx); void cache_put_bitmap(uint8 cache_id, uint16 cache_idx, HBITMAP bitmap); FONTGLYPH *cache_get_font(uint8 font, uint16 character); -void cache_put_font(uint8 font, uint16 character, uint16 offset, uint16 baseline, uint16 width, - uint16 height, HGLYPH pixmap); +void cache_put_font(uint8 font, uint16 character, uint16 offset, uint16 baseline, uint16 width, uint16 height, HGLYPH pixmap); DATABLOB *cache_get_text(uint8 cache_id); void cache_put_text(uint8 cache_id, void *data, int length); uint8 *cache_get_desktop(uint32 offset, int cx, int cy, int bytes_per_pixel); -void cache_put_desktop(uint32 offset, int cx, int cy, int scanline, int bytes_per_pixel, - uint8 * data); +void cache_put_desktop(uint32 offset, int cx, int cy, int scanline, int bytes_per_pixel, uint8 *data); HCURSOR cache_get_cursor(uint16 cache_idx); void cache_put_cursor(uint16 cache_idx, HCURSOR cursor); /* channels.c */ -uint16 get_num_channels(void); -void register_channel(char *name, uint32 flags, void (*callback) (STREAM, uint16)); -rdp5_channel *find_channel_by_channelno(uint16 channelno); -rdp5_channel *find_channel_by_num(uint16 num); -void dummy_callback(STREAM s, uint16 channelno); -void channels_init(void); +VCHANNEL *channel_register(char *name, uint32 flags, void (*callback)(STREAM)); +STREAM channel_init(VCHANNEL *channel, uint32 length); +void channel_send(STREAM s, VCHANNEL *channel); +void channel_process(STREAM s, uint16 mcs_channel); /* cliprdr.c */ -void cliprdr_ipc_format_announce(unsigned char *data, uint16 length); -void cliprdr_handle_SelectionClear(void); -void cliprdr_handle_server_data(uint32 length, uint32 flags, STREAM s); -void cliprdr_handle_server_data_request(STREAM s); -void cliprdr_callback(STREAM s, uint16 channelno); -void cliprdr_ipc_primary_lost(unsigned char *data, uint16 length); -void cliprdr_init(void); +void cliprdr_send_text_format_announce(void); +void cliprdr_send_native_format_announce(uint8 *data, uint32 length); +void cliprdr_send_data_request(uint32 format); +void cliprdr_send_data(uint8 *data, uint32 length); +BOOL cliprdr_init(void); /* ewmhints.c */ -int get_current_workarea(uint32 * x, uint32 * y, uint32 * width, uint32 * height); -/* ipc.c */ -void ipc_register_ipcnotify(uint16 messagetype, void (*notifycallback) (unsigned char *, uint16)); -void ipc_deregister_ipcnotify(uint16 messagetype); -void ipc_init(void); -void ipc_send_message(uint16 messagetype, unsigned char *data, uint16 length); +int get_current_workarea(uint32 *x, uint32 *y, uint32 *width, uint32 *height); /* iso.c */ STREAM iso_init(int length); void iso_send(STREAM s); @@ -48,7 +36,7 @@ void licence_process(STREAM s); STREAM mcs_init(int length); void mcs_send_to_channel(STREAM s, uint16 channel); void mcs_send(STREAM s); -STREAM mcs_recv(uint16 * channel); +STREAM mcs_recv(uint16 *channel); BOOL mcs_connect(char *server, STREAM mcs_data, char *username); void mcs_disconnect(void); /* orders.c */ @@ -56,7 +44,7 @@ void process_orders(STREAM s, uint16 num_orders); void reset_order_state(void); /* rdesktop.c */ int main(int argc, char *argv[]); -void generate_random(uint8 * random); +void generate_random(uint8 *random); void *xmalloc(int size); void *xrealloc(void *oldmem, int size); void xfree(void *mem); @@ -68,27 +56,29 @@ int load_licence(unsigned char **data); void save_licence(unsigned char *data, int length); /* rdp.c */ void rdp_out_unistr(STREAM s, char *string, int len); -void rdp_send_input(uint32 time, uint16 message_type, uint16 device_flags, uint16 param1, - uint16 param2); +void rdp_send_input(uint32 time, uint16 message_type, uint16 device_flags, uint16 param1, uint16 param2); void process_null_system_pointer_pdu(STREAM s); void process_colour_pointer_pdu(STREAM s); void process_cached_pointer_pdu(STREAM s); void process_bitmap_updates(STREAM s); void process_palette(STREAM s); BOOL rdp_main_loop(void); -BOOL rdp_connect(char *server, uint32 flags, char *domain, char *password, char *command, - char *directory); +BOOL rdp_connect(char *server, uint32 flags, char *domain, char *password, char *command, char *directory); void rdp_disconnect(void); /* rdp5.c */ void rdp5_process(STREAM s, BOOL encryption); -void rdp5_process_channel(STREAM s, uint16 channelno); +/* rdpdr.c */ +void rdpdr_send_connect(void); +void rdpdr_send_name(void); +void rdpdr_send_available(void); +void rdpdr_send_completion(uint32 device, uint32 id, uint32 status, uint32 result, uint8 *buffer, uint32 length); +BOOL rdpdr_init(void); /* secure.c */ -void sec_hash_48(uint8 * out, uint8 * in, uint8 * salt1, uint8 * salt2, uint8 salt); -void sec_hash_16(uint8 * out, uint8 * in, uint8 * salt1, uint8 * salt2); -void buf_out_uint32(uint8 * buffer, uint32 value); -void sec_sign(uint8 * signature, int siglen, uint8 * session_key, int keylen, uint8 * data, - int datalen); -void sec_decrypt(uint8 * data, int length); +void sec_hash_48(uint8 *out, uint8 *in, uint8 *salt1, uint8 *salt2, uint8 salt); +void sec_hash_16(uint8 *out, uint8 *in, uint8 *salt1, uint8 *salt2); +void buf_out_uint32(uint8 *buffer, uint32 value); +void sec_sign(uint8 *signature, int siglen, uint8 *session_key, int keylen, uint8 *data, int datalen); +void sec_decrypt(uint8 *data, int length); STREAM sec_init(uint32 flags, int maxlen); void sec_send_to_channel(STREAM s, uint32 flags, uint16 channel); void sec_send(STREAM s, uint32 flags); @@ -102,6 +92,12 @@ void tcp_send(STREAM s); STREAM tcp_recv(STREAM s, uint32 length); BOOL tcp_connect(char *server); void tcp_disconnect(void); +/* xclip.c */ +void ui_clip_format_announce(char *data, uint32 length); +void ui_clip_handle_data(char *data, uint32 length); +void ui_clip_request_data(uint32 format); +void ui_clip_sync(void); +void xclip_init(void); /* xkeymap.c */ void xkeymap_init(void); BOOL handle_special_keys(uint32 keysym, unsigned int state, uint32 ev_time, BOOL pressed); @@ -120,34 +116,28 @@ void ui_destroy_window(void); void xwin_toggle_fullscreen(void); int ui_select(int rdp_socket); void ui_move_pointer(int x, int y); -HBITMAP ui_create_bitmap(int width, int height, uint8 * data); -void ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * data); +HBITMAP ui_create_bitmap(int width, int height, uint8 *data); +void ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 *data); void ui_destroy_bitmap(HBITMAP bmp); -HGLYPH ui_create_glyph(int width, int height, uint8 * data); +HGLYPH ui_create_glyph(int width, int height, uint8 *data); void ui_destroy_glyph(HGLYPH glyph); -HCURSOR ui_create_cursor(unsigned int x, unsigned int y, int width, int height, uint8 * andmask, - uint8 * xormask); +HCURSOR ui_create_cursor(unsigned int x, unsigned int y, int width, int height, uint8 *andmask, uint8 *xormask); void ui_set_cursor(HCURSOR cursor); void ui_destroy_cursor(HCURSOR cursor); -HCOLOURMAP ui_create_colourmap(COLOURMAP * colours); +HCOLOURMAP ui_create_colourmap(COLOURMAP *colours); void ui_destroy_colourmap(HCOLOURMAP map); void ui_set_colourmap(HCOLOURMAP map); void ui_set_clip(int x, int y, int cx, int cy); void ui_reset_clip(void); void ui_bell(void); void ui_destblt(uint8 opcode, int x, int y, int cx, int cy); -void ui_patblt(uint8 opcode, int x, int y, int cx, int cy, BRUSH * brush, int bgcolour, - int fgcolour); +void ui_patblt(uint8 opcode, int x, int y, int cx, int cy, BRUSH *brush, int bgcolour, int fgcolour); void ui_screenblt(uint8 opcode, int x, int y, int cx, int cy, int srcx, int srcy); void ui_memblt(uint8 opcode, int x, int y, int cx, int cy, HBITMAP src, int srcx, int srcy); -void ui_triblt(uint8 opcode, int x, int y, int cx, int cy, HBITMAP src, int srcx, int srcy, - BRUSH * brush, int bgcolour, int fgcolour); -void ui_line(uint8 opcode, int startx, int starty, int endx, int endy, PEN * pen); +void ui_triblt(uint8 opcode, int x, int y, int cx, int cy, HBITMAP src, int srcx, int srcy, BRUSH *brush, int bgcolour, int fgcolour); +void ui_line(uint8 opcode, int startx, int starty, int endx, int endy, PEN *pen); void ui_rect(int x, int y, int cx, int cy, int colour); -void ui_draw_glyph(int mixmode, int x, int y, int cx, int cy, HGLYPH glyph, int srcx, int srcy, - int bgcolour, int fgcolour); -void ui_draw_text(uint8 font, uint8 flags, int mixmode, int x, int y, int clipx, int clipy, - int clipcx, int clipcy, int boxx, int boxy, int boxcx, int boxcy, int bgcolour, - int fgcolour, uint8 * text, uint8 length); +void ui_draw_glyph(int mixmode, int x, int y, int cx, int cy, HGLYPH glyph, int srcx, int srcy, int bgcolour, int fgcolour); +void ui_draw_text(uint8 font, uint8 flags, int mixmode, int x, int y, int clipx, int clipy, int clipcx, int clipcy, int boxx, int boxy, int boxcx, int boxcy, int bgcolour, int fgcolour, uint8 *text, uint8 length); void ui_desktop_save(uint32 offset, int x, int y, int cx, int cy); void ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy); diff --git a/rdesktop.c b/rdesktop.c index b62bf87..4ef7e75 100644 --- a/rdesktop.c +++ b/rdesktop.c @@ -376,10 +376,8 @@ main(int argc, char *argv[]) if (!ui_init()) return 1; - ipc_init(); // Must be run after ui_init, we need X to be setup. - - if (use_rdp5) - cliprdr_init(); // FIXME: Should perhaps be integrated into the channel management code? + /* rdpsnd_init(); */ + /* rdpdr_init(); */ if (!rdp_connect(server, flags, domain, password, shell, directory)) return 1; diff --git a/rdesktop.h b/rdesktop.h index 1f2d72c..bf9b373 100644 --- a/rdesktop.h +++ b/rdesktop.h @@ -48,21 +48,12 @@ #define DEBUG_CLIPBOARD(args) #endif -#define STRNCPY(dst,src,n) { strncpy(dst,src,n-1); dst[n-1] = 0; } +#define STRNCPY(dst,src,n) { strncpy(dst,src,n-1); dst[n-1] = 0; } +#define MIN(x,y) (((x) < (y)) ? (x) : (y)) +#include "parse.h" #include "constants.h" #include "types.h" -#include "parse.h" - -/* Declared here since it uses STREAM that's declared in parse.h */ -typedef struct _rdp5_channel -{ - uint16 channelno; - char name[8]; - uint32 channelflags; - void (*channelcallback) (STREAM, uint16); -} -rdp5_channel; #ifndef MAKE_PROTO #include "proto.h" diff --git a/rdp.c b/rdp.c index 5a83c3e..6664056 100644 --- a/rdp.c +++ b/rdp.c @@ -895,9 +895,6 @@ BOOL rdp_connect(char *server, uint32 flags, char *domain, char *password, char *command, char *directory) { - if (use_rdp5) - channels_init(); - if (!sec_connect(server, username)) return False; diff --git a/rdp5.c b/rdp5.c index f7b049d..e3c4412 100644 --- a/rdp5.c +++ b/rdp5.c @@ -89,14 +89,3 @@ rdp5_process(STREAM s, BOOL encryption) s->p = next; } } - -void -rdp5_process_channel(STREAM s, uint16 channelno) -{ - rdp5_channel *channel; - channel = find_channel_by_channelno(channelno); - if (NULL != channel) - { - channel->channelcallback(s, channelno); - } -} diff --git a/rdpdr.c b/rdpdr.c new file mode 100644 index 0000000..3fc65fd --- /dev/null +++ b/rdpdr.c @@ -0,0 +1,252 @@ +#include "rdesktop.h" + +#define IRP_MJ_CREATE 0x00 +#define IRP_MJ_CLOSE 0x02 +#define IRP_MJ_READ 0x03 +#define IRP_MJ_WRITE 0x04 +#define IRP_MJ_DEVICE_CONTROL 0x0e + +extern char hostname[16]; +extern DEVICE_FNS serial_fns; +extern DEVICE_FNS printer_fns; + +static VCHANNEL *rdpdr_channel; + +void +rdpdr_send_connect(void) +{ + uint8 magic[4] = "rDCC"; + STREAM s; + + s = channel_init(rdpdr_channel, 12); + out_uint8a(s, magic, 4); + out_uint16_le(s, 1); /* unknown */ + out_uint16_le(s, 5); + out_uint32_be(s, 0x815ed39d); /* IP address (use 127.0.0.1) 0x815ed39d */ + s_mark_end(s); + channel_send(s, rdpdr_channel); +} + +void +rdpdr_send_name(void) +{ + uint8 magic[4] = "rDNC"; + uint32 hostlen = (strlen(hostname)+1)*2; + STREAM s; + + s = channel_init(rdpdr_channel, 16+hostlen); + out_uint8a(s, magic, 4); + out_uint16_le(s, 0x63); /* unknown */ + out_uint16_le(s, 0x72); + out_uint32(s, 0); + out_uint32_le(s, hostlen); + rdp_out_unistr(s, hostname, hostlen-2); + s_mark_end(s); + channel_send(s, rdpdr_channel); +} + +void +rdpdr_send_available(void) +{ + uint8 magic[4] = "rDAD"; + char *driver = "Digital turbo PrintServer 20"; /* Fairly generic PostScript driver */ + char *printer = "PostScript"; + uint32 driverlen = (strlen(driver)+1)*2; + uint32 printerlen = (strlen(printer)+1)*2; + STREAM s; + + s = channel_init(rdpdr_channel, 8+20); + out_uint8a(s, magic, 4); + out_uint32_le(s, 1); /* Number of devices */ + +#if 1 + out_uint32_le(s, 0x1); /* Device type 0x1 - serial */ + out_uint32_le(s, 0); /* Handle */ + out_uint8p(s, "COM2", 4); + out_uint8s(s, 4); /* Pad to 8 */ + out_uint32(s, 0); +#endif +#if 0 + out_uint32_le(s, 0x2); /* Device type 0x2 - parallel */ + out_uint32_le(s, 0); + out_uint8p(s, "LPT2", 4); + out_uint8s(s, 4); + out_uint32(s, 0); +#endif +#if 1 + out_uint32_le(s, 0x4); /* Device type 0x4 - printer */ + out_uint32_le(s, 1); + out_uint8p(s, "PRN1", 4); + out_uint8s(s, 4); + out_uint32_le(s, 24+driverlen+printerlen); /* length of extra info */ + out_uint32_le(s, 2); /* unknown */ + out_uint8s(s, 8); /* unknown */ + out_uint32_le(s, driverlen); /* length of driver name */ + out_uint32_le(s, printerlen); /* length of printer name */ + out_uint32(s, 0); /* unknown */ + rdp_out_unistr(s, driver, driverlen-2); + rdp_out_unistr(s, printer, printerlen-2); +#endif +#if 0 + out_uint32_le(s, 0x8); /* Device type 0x8 - disk */ + out_uint32_le(s, 0); + out_uint8p(s, "Z:", 2); + out_uint8s(s, 6); + out_uint32(s, 0); +#endif +#if 0 + out_uint32_le(s, 0x20); /* Device type 0x20 - smart card */ + out_uint32_le(s, 0); + out_uint8p(s, "SCARD", 5); + out_uint8s(s, 3); + out_uint32(s, 0); +#endif + + s_mark_end(s); + channel_send(s, rdpdr_channel); +} + +void +rdpdr_send_completion(uint32 device, uint32 id, uint32 status, uint32 result, uint8 *buffer, uint32 length) +{ + uint8 magic[4] = "rDCI"; + STREAM s; + + s = channel_init(rdpdr_channel, 20 + length); + out_uint8a(s, magic, 4); + out_uint32_le(s, device); + out_uint32_le(s, id); + out_uint32_le(s, status); + out_uint32_le(s, result); + out_uint8p(s, buffer, length); + s_mark_end(s); + hexdump(s->channel_hdr+8, s->end-s->channel_hdr-8); + channel_send(s, rdpdr_channel); +} + +static void +rdpdr_process_irp(STREAM s) +{ + uint32 device, file, id, major, minor; + NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST; + uint32 result = 0, length, request, bytes_in, bytes_out; + uint8 buffer[256]; + uint32 buffer_len = 1; + struct stream out; + DEVICE_FNS *fns; + + in_uint32_le(s, device); + in_uint32_le(s, file); + in_uint32_le(s, id); + in_uint32_le(s, major); + in_uint32_le(s, minor); + + memset(buffer, 0, sizeof(buffer)); + + /* FIXME: this should probably be a more dynamic mapping */ + switch (device) + { + case 0: + fns = &serial_fns; + case 1: + fns = &printer_fns; + default: + error("IRP for bad device %ld\n", device); + return; + } + + switch (major) + { + case IRP_MJ_CREATE: + if (fns->create) + status = fns->create(&result); + break; + + case IRP_MJ_CLOSE: + if (fns->close) + status = fns->close(file); + break; + + case IRP_MJ_READ: + if (fns->read) + { + if (length > sizeof(buffer)) + length = sizeof(buffer); + status = fns->read(file, buffer, length, &result); + buffer_len = result; + } + break; + + case IRP_MJ_WRITE: + if (fns->write) + status = fns->write(file, s->p, length, &result); + break; + + case IRP_MJ_DEVICE_CONTROL: + if (fns->device_control) + { + in_uint32_le(s, bytes_out); + in_uint32_le(s, bytes_in); + in_uint32_le(s, request); + in_uint8s(s, 0x14); + out.data = out.p = buffer; + out.size = sizeof(buffer); + status = fns->device_control(file, request, s, &out); + result = buffer_len = out.p - out.data; + } + break; + + default: + unimpl("IRP major=0x%x minor=0x%x\n", major, minor); + break; + } + + rdpdr_send_completion(device, id, status, result, buffer, buffer_len); +} + +static void +rdpdr_process(STREAM s) +{ + uint32 handle; + char *magic; + + printf("rdpdr_process\n"); + hexdump(s->p, s->end-s->p); + in_uint8p(s, magic, 4); + + if ((magic[0] == 'r') && (magic[1] == 'D')) + { + if ((magic[2] == 'R') && (magic[3] == 'I')) + { + rdpdr_process_irp(s); + return; + } + if ((magic[2] == 'n') && (magic[3] == 'I')) + { + rdpdr_send_connect(); + rdpdr_send_name(); + rdpdr_send_available(); + return; + } + else if ((magic[2] == 'C') && (magic[3] == 'C')) + { + /* connect from server */ + return; + } + else if ((magic[2] == 'r') && (magic[3] == 'd')) + { + /* connect to a specific resource */ + in_uint32(s, handle); + printf("Server connected to resource %d\n", handle); + return; + } + } + unimpl("RDPDR packet type %c%c%c%c\n", magic[0], magic[1], magic[2], magic[3]); +} + +BOOL +rdpdr_init(void) +{ + rdpdr_channel = channel_register("rdpdr", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_COMPRESS_RDP, rdpdr_process); + return (rdpdr_channel != NULL); +} diff --git a/rdpsnd.c b/rdpsnd.c new file mode 100644 index 0000000..dff43a8 --- /dev/null +++ b/rdpsnd.c @@ -0,0 +1,17 @@ +#include "rdesktop.h" + +static VCHANNEL *rdpsnd_channel; + +static void +rdpsnd_process(STREAM s) +{ + printf("rdpsnd_process\n"); + hexdump(s->p, s->end-s->p); +} + +BOOL +rdpsnd_init(void) +{ + rdpsnd_channel = channel_register("rdpsnd", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP, rdpsnd_process); + return (rdpsnd_channel != NULL); +} diff --git a/secure.c b/secure.c index 83d84a8..bc13db6 100644 --- a/secure.c +++ b/secure.c @@ -42,6 +42,8 @@ extern BOOL g_licence_issued; extern BOOL use_rdp5; extern int server_bpp; extern uint16 mcs_userid; +extern VCHANNEL g_channels[]; +extern unsigned int g_num_channels; static int rc4_key_len; static RC4_KEY rc4_decrypt_key; @@ -399,16 +401,12 @@ sec_establish_key(void) static void sec_out_mcs_data(STREAM s) { - uint16 num_channels = get_num_channels(); int hostlen = 2 * strlen(hostname); - int length = 158 + 76 + 12 + 4 + (CHANNEL_TAGDATA_SIZE * num_channels); - uint16 i; - rdp5_channel *channel; + int length = 158 + 76 + 12 + 4; + unsigned int i; - if (0 < num_channels) - { - length += +4 + 4; - } + if (g_num_channels > 0) + length += g_num_channels*12 + 8; if (hostlen > 30) hostlen = 30; @@ -485,18 +483,17 @@ sec_out_mcs_data(STREAM s) out_uint32_le(s, encryption ? 0x3 : 0); /* encryption supported, 128-bit supported */ out_uint32(s, 0); /* Unknown */ - DEBUG_RDP5(("num_channels is %d\n", num_channels)); - if (0 < num_channels) + DEBUG_RDP5(("g_num_channels is %d\n", g_num_channels)); + if (g_num_channels > 0) { out_uint16_le(s, SEC_TAG_CLI_CHANNELS); - out_uint16_le(s, num_channels * CHANNEL_TAGDATA_SIZE + 4 + 4); /* length */ - out_uint32_le(s, num_channels); /* number of virtual channels */ - for (i = 0; i < num_channels; i++) + out_uint16_le(s, g_num_channels * 12 + 8); /* length */ + out_uint32_le(s, g_num_channels); /* number of virtual channels */ + for (i = 0; i < g_num_channels; i++) { - channel = find_channel_by_num(i); - DEBUG_RDP5(("Requesting channel %s\n", channel->name)); - out_uint8p(s, channel->name, 8); - out_uint32_be(s, channel->channelflags); + DEBUG_RDP5(("Requesting channel %s\n", g_channels[i].name)); + out_uint8a(s, g_channels[i].name, 8); + out_uint32_be(s, g_channels[i].flags); } } @@ -775,16 +772,16 @@ sec_process_mcs_data(STREAM s) sec_process_srv_info(s); break; - case SEC_TAG_SRV_3: + case SEC_TAG_SRV_CRYPT: + sec_process_crypt_info(s); + break; + + case SEC_TAG_SRV_CHANNELS: /* FIXME: We should parse this information and use it to map RDP5 channels to MCS channels */ break; - case SEC_TAG_SRV_CRYPT: - sec_process_crypt_info(s); - break; - default: unimpl("response tag 0x%x\n", tag); } @@ -807,30 +804,26 @@ sec_recv(void) { in_uint32_le(s, sec_flags); - if (sec_flags & SEC_LICENCE_NEG) - { - if (sec_flags & SEC_ENCRYPT) - { - DEBUG_RDP5(("Encrypted license detected\n")); - } - licence_process(s); - continue; - } - if (sec_flags & SEC_ENCRYPT) { in_uint8s(s, 8); /* signature */ sec_decrypt(s->p, s->end - s->p); } + + if (sec_flags & SEC_LICENCE_NEG) + { + licence_process(s); + continue; + } } - if (MCS_GLOBAL_CHANNEL == channel) + if (channel != MCS_GLOBAL_CHANNEL) { - return s; + channel_process(s, channel); + continue; } - else - rdp5_process_channel(s, channel); + return s; } return NULL; diff --git a/serial.c b/serial.c new file mode 100644 index 0000000..4bc7ad4 --- /dev/null +++ b/serial.c @@ -0,0 +1,320 @@ +#include +#include +#include +#include "rdesktop.h" + +#define FILE_DEVICE_SERIAL_PORT 0x1b + +#define SERIAL_SET_BAUD_RATE 1 +#define SERIAL_SET_QUEUE_SIZE 2 +#define SERIAL_SET_LINE_CONTROL 3 +#define SERIAL_SET_BREAK_ON 4 +#define SERIAL_SET_BREAK_OFF 5 +#define SERIAL_IMMEDIATE_CHAR 6 +#define SERIAL_SET_TIMEOUTS 7 +#define SERIAL_GET_TIMEOUTS 8 +#define SERIAL_SET_DTR 9 +#define SERIAL_CLR_DTR 10 +#define SERIAL_RESET_DEVICE 11 +#define SERIAL_SET_RTS 12 +#define SERIAL_CLR_RTS 13 +#define SERIAL_SET_XOFF 14 +#define SERIAL_SET_XON 15 +#define SERIAL_GET_WAIT_MASK 16 +#define SERIAL_SET_WAIT_MASK 17 +#define SERIAL_WAIT_ON_MASK 18 +#define SERIAL_PURGE 19 +#define SERIAL_GET_BAUD_RATE 20 +#define SERIAL_GET_LINE_CONTROL 21 +#define SERIAL_GET_CHARS 22 +#define SERIAL_SET_CHARS 23 +#define SERIAL_GET_HANDFLOW 24 +#define SERIAL_SET_HANDFLOW 25 +#define SERIAL_GET_MODEMSTATUS 26 +#define SERIAL_GET_COMMSTATUS 27 +#define SERIAL_XOFF_COUNTER 28 +#define SERIAL_GET_PROPERTIES 29 +#define SERIAL_GET_DTRRTS 30 +#define SERIAL_LSRMST_INSERT 31 +#define SERIAL_CONFIG_SIZE 32 +#define SERIAL_GET_COMMCONFIG 33 +#define SERIAL_SET_COMMCONFIG 34 +#define SERIAL_GET_STATS 35 +#define SERIAL_CLEAR_STATS 36 +#define SERIAL_GET_MODEM_CONTROL 37 +#define SERIAL_SET_MODEM_CONTROL 38 +#define SERIAL_SET_FIFO_CONTROL 39 + +#define STOP_BITS_1 0 +#define STOP_BITS_2 2 + +#define NO_PARITY 0 +#define ODD_PARITY 1 +#define EVEN_PARITY 2 + +int serial_fd; +struct termios termios; + +int dtr; +uint32 baud_rate; +uint32 queue_in_size, queue_out_size; +uint32 wait_mask; +uint8 stop_bits, parity, word_length; + +static BOOL +get_termios(void) +{ + speed_t speed; + + if (tcgetattr(serial_fd, &termios) == -1) + return False; + + speed = cfgetispeed(&termios); + switch (speed) + { + case B75: baud_rate = 75; break; + case B110: baud_rate = 110; break; + case B134: baud_rate = 134; break; + case B150: baud_rate = 150; break; + case B300: baud_rate = 300; break; + case B600: baud_rate = 600; break; + case B1200: baud_rate = 1200; break; + case B1800: baud_rate = 1800; break; + case B2400: baud_rate = 2400; break; + case B4800: baud_rate = 4800; break; + case B9600: baud_rate = 9600; break; + case B19200: baud_rate = 19200; break; + case B38400: baud_rate = 38400; break; + case B57600: baud_rate = 57600; break; + case B115200: baud_rate = 115200; break; + default: baud_rate = 0; break; + } + + speed = cfgetospeed(&termios); + dtr = (speed == B0) ? 0 : 1; + + stop_bits = (termios.c_cflag & CSTOPB) ? STOP_BITS_2 : STOP_BITS_1; + parity = (termios.c_cflag & PARENB) ? ((termios.c_cflag & PARODD) ? ODD_PARITY : EVEN_PARITY) : NO_PARITY; + switch (termios.c_cflag & CSIZE) + { + case CS5: word_length = 5; break; + case CS6: word_length = 6; break; + case CS7: word_length = 7; break; + default: word_length = 8; break; + } + + return True; +} + +static void +set_termios(void) +{ + speed_t speed; + + switch (baud_rate) + { + case 75: speed = B75; break; + case 110: speed = B110; break; + case 134: speed = B134; break; + case 150: speed = B150; break; + case 300: speed = B300; break; + case 600: speed = B600; break; + case 1200: speed = B1200; break; + case 1800: speed = B1800; break; + case 2400: speed = B2400; break; + case 4800: speed = B4800; break; + case 9600: speed = B9600; break; + case 19200: speed = B19200; break; + case 38400: speed = B38400; break; + case 57600: speed = B57600; break; + case 115200: speed = B115200; break; + default: speed = B0; break; + } + + /* on systems with separate ispeed and ospeed, we can remember the speed + in ispeed while changing DTR with ospeed */ + cfsetispeed(&termios, speed); + cfsetospeed(&termios, dtr ? speed : 0); + + termios.c_cflag &= ~(CSTOPB|PARENB|PARODD|CSIZE); + switch (stop_bits) + { + case STOP_BITS_2: + termios.c_cflag |= CSTOPB; + break; + } + switch (parity) + { + case EVEN_PARITY: + termios.c_cflag |= PARENB; + break; + case ODD_PARITY: + termios.c_cflag |= PARENB|PARODD; + break; + } + switch (word_length) + { + case 5: termios.c_cflag |= CS5; break; + case 6: termios.c_cflag |= CS6; break; + case 7: termios.c_cflag |= CS7; break; + default: termios.c_cflag |= CS8; break; + } + + tcsetattr(serial_fd, TCSANOW, &termios); +} + +static NTSTATUS +serial_create(HANDLE *handle) +{ + /* XXX do we have to handle concurrent open attempts? */ + serial_fd = open("/dev/ttyS0", O_RDWR); + if (serial_fd == -1) + return STATUS_ACCESS_DENIED; + + if (!get_termios()) + return STATUS_ACCESS_DENIED; + + *handle = 0; + return STATUS_SUCCESS; +} + +static NTSTATUS +serial_close(HANDLE handle) +{ + close(serial_fd); + return STATUS_SUCCESS; +} + +static NTSTATUS +serial_read(HANDLE handle, uint8 *data, uint32 length, uint32 *result) +{ + *result = read(serial_fd, data, length); + return STATUS_SUCCESS; +} + +static NTSTATUS +serial_write(HANDLE handle, uint8 *data, uint32 length, uint32 *result) +{ + *result = write(serial_fd, data, length); + return STATUS_SUCCESS; +} + +static NTSTATUS +serial_device_control(HANDLE handle, uint32 request, STREAM in, STREAM out) +{ + uint32 result; + uint8 immediate; + + if ((request >> 16) != FILE_DEVICE_SERIAL_PORT) + return STATUS_INVALID_PARAMETER; + + /* extract operation */ + request >>= 2; + request &= 0xfff; + + printf("SERIAL IOCTL %d\n", request); + + switch (request) + { + case SERIAL_SET_BAUD_RATE: + in_uint32_le(in, baud_rate); + set_termios(); + break; + case SERIAL_GET_BAUD_RATE: + out_uint32_le(out, baud_rate); + break; + case SERIAL_SET_QUEUE_SIZE: + in_uint32_le(in, queue_in_size); + in_uint32_le(in, queue_out_size); + break; + case SERIAL_SET_LINE_CONTROL: + in_uint8(in, stop_bits); + in_uint8(in, parity); + in_uint8(in, word_length); + set_termios(); + break; + case SERIAL_GET_LINE_CONTROL: + out_uint8(out, stop_bits); + out_uint8(out, parity); + out_uint8(out, word_length); + break; + case SERIAL_IMMEDIATE_CHAR: + in_uint8(in, immediate); + serial_write(handle, &immediate, 1, &result); + break; + case SERIAL_CONFIG_SIZE: + out_uint32_le(out, 0); + break; + case SERIAL_GET_CHARS: + out_uint8s(out, 6); + break; + case SERIAL_SET_CHARS: + in_uint8s(in, 6); + break; + case SERIAL_GET_HANDFLOW: + out_uint32_le(out, 0); + out_uint32_le(out, 3); /* Xon/Xoff */ + out_uint32_le(out, 0); + out_uint32_le(out, 0); + break; + case SERIAL_SET_HANDFLOW: + in_uint8s(in, 16); + break; + case SERIAL_SET_TIMEOUTS: + in_uint8s(in, 20); + break; + case SERIAL_GET_TIMEOUTS: + out_uint8s(out, 20); + break; + case SERIAL_GET_WAIT_MASK: + out_uint32(out, wait_mask); + break; + case SERIAL_SET_WAIT_MASK: + in_uint32(in, wait_mask); + break; + case SERIAL_SET_DTR: + dtr = 1; + set_termios(); + break; + case SERIAL_CLR_DTR: + dtr = 0; + set_termios(); + break; +#if 0 + case SERIAL_WAIT_ON_MASK: + /* XXX implement me */ + break; + case SERIAL_SET_BREAK_ON: + tcsendbreak(serial_fd, 0); + break; + case SERIAL_PURGE: + in_uint32(purge_mask); + /* tcflush */ + break; + case SERIAL_RESET_DEVICE: + case SERIAL_SET_BREAK_OFF: + case SERIAL_SET_RTS: + case SERIAL_CLR_RTS: + case SERIAL_SET_XOFF: + case SERIAL_SET_XON: + /* ignore */ + break; +#endif + + default: + unimpl("SERIAL IOCTL %d\n", request); + return STATUS_INVALID_PARAMETER; + } + + return STATUS_SUCCESS; +} + +DEVICE_FNS serial_fns = +{ + serial_create, + serial_close, + serial_read, + serial_write, + serial_device_control +}; + diff --git a/types.h b/types.h index daf2629..7535e7f 100644 --- a/types.h +++ b/types.h @@ -109,12 +109,27 @@ typedef struct _key_translation } key_translation; -struct _cliprdr_dataformat; - -typedef struct _cliprdr_dataformat +typedef struct _VCHANNEL { - uint32 identifier; - uint8 textual_description[32]; - struct _cliprdr_dataformat *next; + uint16 mcs_id; + char name[8]; + uint32 flags; + struct stream in; + void (*process) (STREAM); } -cliprdr_dataformat; +VCHANNEL; + +/* RDPDR */ +typedef uint32 NTSTATUS; +typedef uint32 HANDLE; + +typedef struct _DEVICE_FNS +{ + NTSTATUS (*create)(HANDLE *handle); + NTSTATUS (*close)(HANDLE handle); + NTSTATUS (*read)(HANDLE handle, uint8 *data, uint32 length, uint32 *result); + NTSTATUS (*write)(HANDLE handle, uint8 *data, uint32 length, uint32 *result); + NTSTATUS (*device_control)(HANDLE handle, uint32 request, STREAM in, STREAM out); +} +DEVICE_FNS; + diff --git a/xclip.c b/xclip.c new file mode 100644 index 0000000..3923df9 --- /dev/null +++ b/xclip.c @@ -0,0 +1,306 @@ +/* -*- c-basic-offset: 8 -*- + rdesktop: A Remote Desktop Protocol client. + Protocol services - Clipboard functions + Copyright (C) Erik Forsberg 2003 + Copyright (C) Matthew Chapman 2003 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include "rdesktop.h" + +#define NUM_TARGETS 6 + +extern Display *display; +extern Window wnd; +extern Time last_gesturetime; + +static Atom clipboard_atom, primary_atom, targets_atom, timestamp_atom; +static Atom rdesktop_clipboard_target_atom, rdesktop_clipboard_formats_atom, incr_atom; +static XSelectionRequestEvent selection_request; +static Atom targets[NUM_TARGETS]; +static int have_primary = 0; +static int rdesktop_is_selection_owner = 0; + +static void +xclip_provide_selection(XSelectionRequestEvent *req, Atom type, unsigned int format, uint8 *data, uint32 length) +{ + XEvent xev; + + XChangeProperty(display, req->requestor, req->property, + type, format, PropModeReplace, data, length); + + xev.xselection.type = SelectionNotify; + xev.xselection.serial = 0; + xev.xselection.send_event = True; + xev.xselection.requestor = req->requestor; + xev.xselection.selection = req->selection; + xev.xselection.target = req->target; + xev.xselection.property = req->property; + xev.xselection.time = req->time; + XSendEvent(display, req->requestor, False, NoEventMask, &xev); +} + +void +xclip_handle_SelectionNotify(XSelectionEvent * event) +{ + unsigned long nitems, bytes_left; + Atom type, best_target, text_target; + Atom *supported_targets; + int res, i, format; + uint8 *data; + + if (event->property == None) + goto fail; + + DEBUG_CLIPBOARD(("xclip_handle_SelectionNotify: selection=%s, target=%s, property=%s\n", + XGetAtomName(display, event->selection), + XGetAtomName(display, event->target), + XGetAtomName(display, event->property))); + + if (event->property == None) + goto fail; + + res = XGetWindowProperty(display, wnd, rdesktop_clipboard_target_atom, + 0, XMaxRequestSize(display), True, AnyPropertyType, + &type, &format, &nitems, &bytes_left, &data); + + if (res != Success) + { + DEBUG_CLIPBOARD(("XGetWindowProperty failed!\n")); + goto fail; + } + + if (event->target == targets_atom) + { + /* FIXME: We should choose format here based on what the server wanted */ + best_target = XA_STRING; + if (type != None) + { + supported_targets = (Atom *) data; + text_target = XInternAtom(display, "TEXT", False); + for (i = 0; i < nitems; i++) + { + DEBUG_CLIPBOARD(("Target %d: %s\n", i, XGetAtomName(display, supported_targets[i]))); + if (supported_targets[i] == text_target) + { + DEBUG_CLIPBOARD(("Other party supports TEXT, choosing that as best_target\n")); + best_target = text_target; + } + } + XFree(data); + } + + XConvertSelection(display, primary_atom, best_target, rdesktop_clipboard_target_atom, wnd, event->time); + return; + } + + if (type == incr_atom) + { + warning("We don't support INCR transfers at this time. Try cutting less data.\n"); + goto fail; + } + + cliprdr_send_data(data, nitems+1); + XFree(data); + + if (!rdesktop_is_selection_owner) + cliprdr_send_text_format_announce(); + return; + +fail: + cliprdr_send_data(NULL, 0); +} + +void +xclip_handle_SelectionRequest(XSelectionRequestEvent *event) +{ + unsigned long nitems, bytes_left; + uint32 *wanted_format; + int format, res; + Atom type; + + DEBUG_CLIPBOARD(("xclip_handle_SelectionRequest: selection=%s, target=%s, property=%s\n", + XGetAtomName(display, event->selection), + XGetAtomName(display, event->target), + XGetAtomName(display, event->property))); + + if (event->target == targets_atom) + { + xclip_provide_selection(event, XA_ATOM, 32, (uint8 *)&targets, NUM_TARGETS); + return; + } + else if (event->target == timestamp_atom) + { + xclip_provide_selection(event, XA_INTEGER, 32, (uint8 *)&last_gesturetime, 1); + return; + } + else if (event->target == rdesktop_clipboard_formats_atom) + { + res = XGetWindowProperty(display, event->requestor, + rdesktop_clipboard_target_atom, 0, 1, True, XA_INTEGER, + &type, &format, &nitems, &bytes_left, (unsigned char **) &wanted_format); + format = (res == Success) ? *wanted_format : CF_TEXT; + } + else + { + format = CF_TEXT; + } + + cliprdr_send_data_request(format); + selection_request = *event; + /* wait for data */ +} + +void +xclip_handle_SelectionClear(void) +{ + DEBUG_CLIPBOARD(("xclip_handle_SelectionClear\n")); + have_primary = 0; + XDeleteProperty(display, DefaultRootWindow(display), rdesktop_clipboard_formats_atom); + cliprdr_send_text_format_announce(); +} + +void +xclip_handle_PropertyNotify(XPropertyEvent *event) +{ + unsigned long nitems, bytes_left; + int format, res; + uint8 *data; + Atom type; + + if (event->atom != rdesktop_clipboard_formats_atom) + return; + + if (have_primary) /* from us */ + return; + + if (event->state == PropertyNewValue) + { + res = XGetWindowProperty(display, DefaultRootWindow(display), + rdesktop_clipboard_formats_atom, 0, XMaxRequestSize(display), False, XA_STRING, + &type, &format, &nitems, &bytes_left, &data); + + if ((res == Success) && (nitems > 0)) + { + cliprdr_send_native_format_announce(data, nitems); + rdesktop_is_selection_owner = 1; + return; + } + } + + /* PropertyDelete, or XGetWindowProperty failed */ + cliprdr_send_text_format_announce(); + rdesktop_is_selection_owner = 0; +} + + +void +ui_clip_format_announce(char *data, uint32 length) +{ + XSetSelectionOwner(display, primary_atom, wnd, last_gesturetime); + if (XGetSelectionOwner(display, primary_atom) != wnd) + { + warning("Failed to aquire ownership of PRIMARY clipboard\n"); + return; + } + + have_primary = 1; + XChangeProperty(display, DefaultRootWindow(display), + rdesktop_clipboard_formats_atom, XA_STRING, 8, PropModeReplace, data, length); + + XSetSelectionOwner(display, clipboard_atom, wnd, last_gesturetime); + if (XGetSelectionOwner(display, clipboard_atom) != wnd) + warning("Failed to aquire ownership of CLIPBOARD clipboard\n"); +} + + +void +ui_clip_handle_data(char *data, uint32 length) +{ + xclip_provide_selection(&selection_request, XA_STRING, 8, data, length-1); +} + +void +ui_clip_request_data(uint32 format) +{ + Window selectionowner; + + DEBUG_CLIPBOARD(("Request from server for format %d\n", format)); + + if (rdesktop_is_selection_owner) + { + XChangeProperty(display, wnd, rdesktop_clipboard_target_atom, + XA_INTEGER, 32, PropModeReplace, (unsigned char *) &format, 1); + + XConvertSelection(display, primary_atom, rdesktop_clipboard_formats_atom, + rdesktop_clipboard_target_atom, wnd, CurrentTime); + return; + } + + selectionowner = XGetSelectionOwner(display, primary_atom); + if (selectionowner != None) + { + XConvertSelection(display, primary_atom, targets_atom, + rdesktop_clipboard_target_atom, wnd, CurrentTime); + return; + } + + /* No PRIMARY, try CLIPBOARD */ + selectionowner = XGetSelectionOwner(display, clipboard_atom); + if (selectionowner != None) + { + XConvertSelection(display, clipboard_atom, targets_atom, + rdesktop_clipboard_target_atom, wnd, CurrentTime); + return; + } + + /* No data available */ + cliprdr_send_data(NULL, 0); +} + +void +ui_clip_sync(void) +{ + cliprdr_send_text_format_announce(); +} + + +void +xclip_init(void) +{ + if (!cliprdr_init()) + return; + + primary_atom = XInternAtom(display, "PRIMARY", False); + clipboard_atom = XInternAtom(display, "CLIPBOARD", False); + targets_atom = XInternAtom(display, "TARGETS", False); + timestamp_atom = XInternAtom(display, "TIMESTAMP", False); + rdesktop_clipboard_target_atom = XInternAtom(display, "_RDESKTOP_CLIPBOARD_TARGET", False); + incr_atom = XInternAtom(display, "INCR", False); + targets[0] = targets_atom; + targets[1] = XInternAtom(display, "TEXT", False); + targets[2] = XInternAtom(display, "UTF8_STRING", False); + targets[3] = XInternAtom(display, "text/unicode", False); + targets[4] = XInternAtom(display, "TIMESTAMP", False); + targets[5] = XA_STRING; + + /* rdesktop sets _RDESKTOP_CLIPBOARD_FORMATS on the root window when acquiring the clipboard. + Other interested rdesktops can use this to notify their server of the available formats. */ + rdesktop_clipboard_formats_atom = XInternAtom(display, "_RDESKTOP_CLIPBOARD_FORMATS", False); + XSelectInput(display, DefaultRootWindow(display), PropertyChangeMask); +} diff --git a/xproto.h b/xproto.h index ecc3f2e..a3997c3 100644 --- a/xproto.h +++ b/xproto.h @@ -1,7 +1,4 @@ -/* cliprdr.c */ -void cliprdr_handle_SelectionNotify(XSelectionEvent * event); -void cliprdr_handle_SelectionRequest(XSelectionRequestEvent * xevent); -/* xwin.c */ -void xwin_register_propertynotify(Window event_wnd, Atom atom, - void (*propertycallback) (XPropertyEvent *)); -void xwin_deregister_propertynotify(Window event_wnd, Atom atom); +void xclip_handle_SelectionNotify(XSelectionEvent *event); +void xclip_handle_SelectionRequest(XSelectionRequestEvent *xevent); +void xclip_handle_SelectionClear(void); +void xclip_handle_PropertyNotify(XPropertyEvent *xev); diff --git a/xwin.c b/xwin.c index 969e258..f003810 100644 --- a/xwin.c +++ b/xwin.c @@ -52,9 +52,6 @@ static XIC IC; static XModifierKeymap *mod_map; static Cursor current_cursor; static Atom protocol_atom, kill_atom; -static long input_mask; /* Needs to be global since we access it in - both ui_create_window and the PropertyNotify - callback functions */ /* endianness */ static BOOL host_be; @@ -90,20 +87,6 @@ typedef struct } PixelColour; -struct _PropNotifyCb; - -typedef struct _PropNotifyCb -{ - Window wnd; - Atom atom; - void (*callback) (XPropertyEvent *); - struct _PropNotifyCb *next; -} -PropNotifyCb; - - -static PropNotifyCb *propnotify_callbacks = NULL; - #define FILL_RECTANGLE(x,y,cx,cy)\ { \ @@ -630,12 +613,11 @@ ui_init(void) IM = XOpenIM(display, NULL, NULL, NULL); xkeymap_init(); + xclip_init(); /* todo take this out when high colour is done */ printf("server bpp %d client bpp %d depth %d\n", server_bpp, bpp, depth); - - return True; } @@ -662,7 +644,7 @@ ui_create_window(void) XClassHint *classhints; XSizeHints *sizehints; int wndwidth, wndheight; - long ic_input_mask; + long input_mask, ic_input_mask; XEvent xevent; wndwidth = fullscreen ? WidthOfScreen(screen) : width; @@ -776,21 +758,6 @@ xwin_toggle_fullscreen(void) } } -static void -xwin_process_propertynotify(XPropertyEvent * xev) -{ - PropNotifyCb *this = propnotify_callbacks; - while (NULL != this) - { - if (xev->window == this->wnd && xev->atom == this->atom) - { - this->callback(xev); - } - this = this->next; - } -} - - /* Process all events in Xlib queue Returns 0 after user quit, 1 otherwise */ static int @@ -830,13 +797,12 @@ xwin_process_events(void) break; case KeyPress: - last_gesturetime = ((XKeyEvent *) & xevent)->time; + last_gesturetime = xevent.xkey.time; if (IC != NULL) /* Multi_key compatible version */ { XmbLookupString(IC, - (XKeyPressedEvent *) & - xevent, str, sizeof(str), &keysym, &status); + &xevent.xkey, str, sizeof(str), &keysym, &status); if (!((status == XLookupKeySym) || (status == XLookupBoth))) { error("XmbLookupString failed with status 0x%x\n", @@ -871,7 +837,7 @@ xwin_process_events(void) break; case KeyRelease: - last_gesturetime = ((XKeyEvent *) & xevent)->time; + last_gesturetime = xevent.xkey.time; XLookupString((XKeyEvent *) & xevent, str, sizeof(str), &keysym, NULL); @@ -892,12 +858,11 @@ xwin_process_events(void) break; case ButtonPress: - last_gesturetime = ((XButtonEvent *) & xevent)->time; flags = MOUSE_FLAG_DOWN; /* fall through */ case ButtonRelease: - last_gesturetime = ((XButtonEvent *) & xevent)->time; + last_gesturetime = xevent.xbutton.time; button = xkeymap_translate_button(xevent.xbutton.button); if (button == 0) break; @@ -1033,23 +998,20 @@ xwin_process_events(void) mod_map = XGetModifierMapping(display); } break; - /* Clipboard stuff */ - case SelectionClear: - cliprdr_handle_SelectionClear(); - break; + + /* clipboard stuff */ case SelectionNotify: - cliprdr_handle_SelectionNotify((XSelectionEvent *) & xevent); + xclip_handle_SelectionNotify(&xevent.xselection); break; case SelectionRequest: - cliprdr_handle_SelectionRequest((XSelectionRequestEvent *) & - xevent); + xclip_handle_SelectionRequest(&xevent.xselectionrequest); + break; + case SelectionClear: + xclip_handle_SelectionClear(); break; - case PropertyNotify: - xwin_process_propertynotify((XPropertyEvent *) & xevent); + xclip_handle_PropertyNotify(&xevent.xproperty); break; - - } } /* Keep going */ @@ -1758,98 +1720,3 @@ ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy) XFree(image); } - -void -xwin_register_propertynotify(Window event_wnd, Atom atom, - void (*propertycallback) (XPropertyEvent *)) -{ - PropNotifyCb *this; - int window_already_registrered = 0; - if (NULL != propnotify_callbacks) - { - this = propnotify_callbacks; - if (event_wnd == this->wnd) - { - window_already_registrered = 1; - if (atom == this->atom) - return; - } - while (NULL != this->next) - { - if (event_wnd == this->wnd) - { - window_already_registrered = 1; - if (atom == this->atom) - return; - /* Find last entry in list */ - } - this = this->next; - } - this->next = xmalloc(sizeof(PropNotifyCb)); - this->next->next = NULL; - this = this->next; - - } - else - { - this = xmalloc(sizeof(PropNotifyCb)); - this->next = NULL; - propnotify_callbacks = this; - } - if (!window_already_registrered) - { - if (wnd == event_wnd) - XSelectInput(display, wnd, input_mask | PropertyChangeMask); - else - XSelectInput(display, event_wnd, PropertyChangeMask); - } - this->wnd = event_wnd; - this->atom = atom; - this->callback = propertycallback; -} - - -void -xwin_deregister_propertynotify(Window event_wnd, Atom atom) -{ - PropNotifyCb *this = propnotify_callbacks; - PropNotifyCb *prev; - int window_needed = 0; - prev = this; - while (NULL != this) - { - if (event_wnd == this->wnd) - { - if (atom == this->atom) - { - if (prev == this) - { - propnotify_callbacks = this->next; - } - else - { - prev->next = this->next; - } - xfree(this); - continue; - } - else - { - window_needed = 1; - } - } - prev = this; - this = this->next; - } - if (!window_needed) - { - if (wnd != event_wnd) - { - XSelectInput(display, event_wnd, NoEventMask); - } - else - { - XSelectInput(display, wnd, input_mask); - } - } -}