diff options
| -rw-r--r-- | sesman/chansrv/Makefile.am | 3 | ||||
| -rw-r--r-- | sesman/chansrv/chansrv.c | 147 | ||||
| -rw-r--r-- | sesman/chansrv/clipboard.c | 710 | ||||
| -rw-r--r-- | sesman/chansrv/clipboard.h | 2 | ||||
| -rw-r--r-- | sesman/chansrv/devredir.c | 7 | ||||
| -rw-r--r-- | sesman/chansrv/devredir.h | 2 | ||||
| -rw-r--r-- | sesman/chansrv/sound.c | 7 | ||||
| -rw-r--r-- | sesman/chansrv/sound.h | 2 | 
8 files changed, 836 insertions, 44 deletions
| diff --git a/sesman/chansrv/Makefile.am b/sesman/chansrv/Makefile.am index fb4e8984..ec6e22c5 100644 --- a/sesman/chansrv/Makefile.am +++ b/sesman/chansrv/Makefile.am @@ -18,4 +18,5 @@ xrdp_chansrv_SOURCES = \    devredir.c  xrdp_chansrv_LDADD = \ -  $(top_srcdir)/common/libcommon.la +  $(top_srcdir)/common/libcommon.la \ +  -lX11 -lXfixes diff --git a/sesman/chansrv/chansrv.c b/sesman/chansrv/chansrv.c index 84a973f0..d1f8c3d2 100644 --- a/sesman/chansrv/chansrv.c +++ b/sesman/chansrv/chansrv.c @@ -37,7 +37,7 @@ static int g_rdpsnd_index = -1;  static int g_rdpdr_index = -1;  tbus g_term_event = 0; -int g_display = 0; +int g_display_num = 0;  int g_cliprdr_chan_id = -1; /* cliprdr */  int g_rdpsnd_chan_id = -1; /* rdpsnd */  int g_rdpdr_chan_id = -1; /* rdpdr */ @@ -100,7 +100,7 @@ send_init_response_message(void)  {    struct stream* s; -  g_writeln("xrdp-chansrv: in send_init_response_message"); +  g_writeln("xrdp-chansrv: send_init_response_message:");    s = trans_get_out_s(g_con_trans, 8192);    if (s == 0)    { @@ -121,7 +121,7 @@ send_channel_setup_response_message(void)  {    struct stream* s; -  g_writeln("xrdp-chansrv: in send_channel_setup_response_message"); +  g_writeln("xrdp-chansrv: send_channel_setup_response_message:");    s = trans_get_out_s(g_con_trans, 8192);    if (s == 0)    { @@ -142,7 +142,7 @@ send_channel_data_response_message(void)  {    struct stream* s; -  g_writeln("xrdp-chansrv: in send_channel_data_response_message"); +  g_writeln("xrdp-chansrv: send_channel_data_response_message:");    s = trans_get_out_s(g_con_trans, 8192);    if (s == 0)    { @@ -161,7 +161,7 @@ send_channel_data_response_message(void)  static int APP_CC  process_message_init(struct stream* s)  { -  g_writeln("xrdp-chansrv: in process_message_init"); +  g_writeln("xrdp-chansrv: process_message_init:");    return send_init_response_message();  } @@ -175,9 +175,10 @@ process_message_channel_setup(struct stream* s)    int rv;    struct chan_item* ci; -  g_writeln("xrdp-chansrv: in process_message_channel_setup"); +  g_writeln("xrdp-chansrv: process_message_channel_setup:");    in_uint16_le(s, num_chans); -  g_writeln("xrdp-chansrv: num_chans %d", num_chans); +  g_writeln("xrdp-chansrv: process_message_channel_setup: num_chans %d", +            num_chans);    for (index = 0; index < num_chans; index++)    {      ci = &(g_chan_items[g_num_chan_items]); @@ -185,8 +186,8 @@ process_message_channel_setup(struct stream* s)      in_uint8a(s, ci->name, 8);      in_uint16_le(s, ci->id);      in_uint16_le(s, ci->flags); -    g_writeln("xrdp-chansrv: chan name %s id %d flags %8.8x", -              ci->name, ci->id, ci->flags); +    g_writeln("xrdp-chansrv: process_message_channel_setup: chan name %s " +              "id %d flags %8.8x", ci->name, ci->id, ci->flags);      if (g_strcasecmp(ci->name, "cliprdr") == 0)      {        g_cliprdr_index = g_num_chan_items; @@ -235,8 +236,8 @@ process_message_channel_data(struct stream* s)    in_uint16_le(s, chan_flags);    in_uint16_le(s, length);    in_uint32_le(s, total_length); -  g_writeln("xrdp-chansrv: log channel data chan_id %d chan_flags %d", -            chan_id, chan_flags); +  g_writeln("xrdp-chansrv: process_message_channel_data: chan_id %d " +            "chan_flags %d", chan_id, chan_flags);    rv = send_channel_data_response_message();    if (rv == 0)    { @@ -261,7 +262,7 @@ process_message_channel_data(struct stream* s)  static int APP_CC  process_message_channel_data_response(struct stream* s)  { -  g_writeln("xrdp-chansrv: in process_message_channel_data_response"); +  g_writeln("xrdp-chansrv: process_message_channel_data_response:");    return 0;  } @@ -307,8 +308,8 @@ process_message(void)          rv = process_message_channel_data_response(s);          break;        default: -        g_writeln("xrdp-chansrv: error in process_message unknown msg %d", -                  id); +        g_writeln("xrdp-chansrv: process_message: error in process_message " +                  "unknown msg %d", id);          break;      }      if (rv != 0) @@ -338,7 +339,7 @@ my_trans_data_in(struct trans* trans)    {      return 1;    } -  g_writeln("xrdp-chansrv: my_trans_data_in"); +  g_writeln("xrdp-chansrv: my_trans_data_in:");    s = trans_get_in_s(trans);    in_uint32_le(s, id);    in_uint32_le(s, size); @@ -371,7 +372,7 @@ my_trans_conn_in(struct trans* trans, struct trans* new_trans)    {      return 1;    } -  g_writeln("xrdp-chansrv: my_trans_conn_in"); +  g_writeln("xrdp-chansrv: my_trans_conn_in:");    g_con_trans = new_trans;    g_con_trans->trans_data_in = my_trans_data_in;    g_con_trans->header_size = 8; @@ -394,11 +395,11 @@ setup_listen(void)    }    g_lis_trans = trans_create(1, 8192, 8192);    g_lis_trans->trans_conn_in = my_trans_conn_in; -  g_snprintf(text, 255, "%d", 7200 + g_display); +  g_snprintf(text, 255, "%d", 7200 + g_display_num);    error = trans_listen(g_lis_trans, text);    if (error != 0)    { -    g_writeln("xrdp-chansrv: trans_listen failed"); +    g_writeln("xrdp-chansrv: setup_listen: trans_listen failed");      return 1;    }    return 0; @@ -414,7 +415,7 @@ channel_thread_loop(void* in_val)    int error;    THREAD_RV rv; -  g_writeln("xrdp-chansrv: thread start"); +  g_writeln("xrdp-chansrv: channel_thread_loop: thread start");    rv = 0;    error = setup_listen();    if (error == 0) @@ -428,21 +429,26 @@ channel_thread_loop(void* in_val)      {        if (g_is_wait_obj_set(g_term_event))        { -        g_writeln("xrdp-chansrv: g_term_event set"); +        g_writeln("xrdp-chansrv: channel_thread_loop: g_term_event set"); +        clipboard_deinit(); +        sound_deinit(); +        dev_redir_deinit();          break;        }        if (g_lis_trans != 0)        {          if (trans_check_wait_objs(g_lis_trans) != 0)          { -          g_writeln("xrdp-chansrv: trans_check_wait_objs error"); +          g_writeln("xrdp-chansrv: channel_thread_loop: " +                    "trans_check_wait_objs error");          }        }        if (g_con_trans != 0)        {          if (trans_check_wait_objs(g_con_trans) != 0)          { -          g_writeln("xrdp-chansrv: trans_check_wait_objs error resetting"); +          g_writeln("xrdp-chansrv: channel_thread_loop: " +                    "trans_check_wait_objs error resetting");            /* delete g_con_trans */            trans_delete(g_con_trans);            g_con_trans = 0; @@ -472,7 +478,7 @@ channel_thread_loop(void* in_val)    g_lis_trans = 0;    trans_delete(g_con_trans);    g_con_trans = 0; -  g_writeln("xrdp-chansrv: thread stop"); +  g_writeln("xrdp-chansrv: channel_thread_loop: thread stop");    g_set_wait_obj(g_thread_done_event);    return rv;  } @@ -493,6 +499,58 @@ nil_signal_handler(int sig)  }  /*****************************************************************************/ +static int APP_CC +get_display_num_from_display(char* display_text) +{ +  int index; +  int mode; +  int host_index; +  int disp_index; +  int scre_index; +  char host[256]; +  char disp[256]; +  char scre[256]; + +  index = 0; +  host_index = 0; +  disp_index = 0; +  scre_index = 0; +  mode = 0; +  while (display_text[index] != 0) +  { +    if (display_text[index] == ':') +    { +      mode = 1; +    } +    else if (display_text[index] == '.') +    { +      mode = 2; +    } +    else if (mode == 0) +    { +      host[host_index] = display_text[index]; +      host_index++; +    } +    else if (mode == 1) +    { +      disp[disp_index] = display_text[index]; +      disp_index++; +    } +    else if (mode == 2) +    { +      scre[scre_index] = display_text[index]; +      scre_index++; +    } +    index++; +  } +  host[host_index] = 0; +  disp[disp_index] = 0; +  scre[scre_index] = 0; +  g_display_num = g_atoi(disp); +  return 0; +} + +/*****************************************************************************/  int DEFAULT_CC  main(int argc, char** argv)  { @@ -500,45 +558,48 @@ main(int argc, char** argv)    char text[256];    char* display_text; +  g_init(); /* os_calls */    pid = g_getpid(); -  g_writeln("xrdp-chansrv: app started pid %d(0x%8.8x)", pid, pid); +  g_writeln("xrdp-chansrv: main: app started pid %d(0x%8.8x)", pid, pid);    g_signal_kill(term_signal_handler); /* SIGKILL */    g_signal_terminate(term_signal_handler); /* SIGTERM */    g_signal_user_interrupt(term_signal_handler); /* SIGINT */    g_signal_pipe(nil_signal_handler); /* SIGPIPE */ -  display_text = g_getenv("XRDP_SESSVC_DISPLAY"); -  if (display_text == 0) +  display_text = g_getenv("DISPLAY"); +  g_writeln("xrdp-chansrv: main: DISPLAY env var set to %s", display_text); +  get_display_num_from_display(display_text); +  if (g_display_num == 0)    { -    g_writeln("xrdp-chansrv: error, XRDP_SESSVC_DISPLAY not set"); +    g_writeln("xrdp-chansrv: main: error, display is zero");      return 1;    } -  else -  { -    g_display = g_atoi(display_text); -  } -  if (g_display == 0) -  { -    g_writeln("xrdp-chansrv: error, display is zero"); -    return 1; -  } -  g_writeln("xrdp-chansrv: using DISPLAY %d", g_display); +  g_writeln("xrdp-chansrv: main: using DISPLAY %d", g_display_num);    g_snprintf(text, 255, "xrdp_chansrv_%8.8x_main_term", pid);    g_term_event = g_create_wait_obj(text);    g_snprintf(text, 255, "xrdp_chansrv_%8.8x_thread_done", pid);    g_thread_done_event = g_create_wait_obj(text);    tc_thread_create(channel_thread_loop, 0); -  if (g_obj_wait(&g_term_event, 1, 0, 0, 0) != 0) +  while (!g_is_wait_obj_set(g_term_event))    { -    g_writeln("xrdp-chansrv: error, g_obj_wait failed"); +    if (g_obj_wait(&g_term_event, 1, 0, 0, 0) != 0) +    { +      g_writeln("xrdp-chansrv: main: error, g_obj_wait failed"); +      break; +    }    } -  /* wait for thread to exit */ -  if (g_obj_wait(&g_thread_done_event, 1, 0, 0, 0) != 0) +  while (!g_is_wait_obj_set(g_thread_done_event))    { -    g_writeln("xrdp-chansrv: error, g_obj_wait failed"); +    /* wait for thread to exit */ +    if (g_obj_wait(&g_thread_done_event, 1, 0, 0, 0) != 0) +    { +      g_writeln("xrdp-chansrv: main: error, g_obj_wait failed"); +      break; +    }    }    /* cleanup */    g_delete_wait_obj(g_term_event);    g_delete_wait_obj(g_thread_done_event); -  g_writeln("xrdp-chansrv: app exiting pid %d(0x%8.8x)", pid, pid); +  g_writeln("xrdp-chansrv: main: app exiting pid %d(0x%8.8x)", pid, pid); +  g_deinit(); /* os_calls */    return 0;  } diff --git a/sesman/chansrv/clipboard.c b/sesman/chansrv/clipboard.c index 59d39fbd..a38ff471 100644 --- a/sesman/chansrv/clipboard.c +++ b/sesman/chansrv/clipboard.c @@ -15,18 +15,375 @@     xrdp: A Remote Desktop Protocol server.     Copyright (C) Jay Sorg 2009 + +   for help see +   http://tronche.com/gui/x/icccm/sec-2.html#s-2 +   .../kde/kdebase/workspace/klipper/clipboardpoll.cpp +  */ +#include <X11/Xlib.h> +#include <X11/Xatom.h> +#include <X11/extensions/Xfixes.h>  #include "arch.h"  #include "parse.h"  #include "os_calls.h" +#include "chansrv.h" + +static Display* g_display = 0; +static Atom g_clipboard_atom = 0; +static Atom g_clip_property_atom = 0; +static Atom g_timestamp_atom = 0; +static Atom g_multiple_atom = 0; +static Atom g_targets_atom = 0; +static Atom g_primary_atom = 0; +static int g_x_socket = 0; +static tbus g_x_wait_obj = 0; +static int g_clip_up = 0; +static Window g_wnd = 0; +static Screen* g_screen = 0; +static int g_screen_num = 0; +static int g_xfixes_event_base = 0; +static int g_sck_closed = 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_got_selection = 0; /* boolean */ +static Time g_selection_time = 0;  extern int g_cliprdr_chan_id; /* in chansrv.c */  /*****************************************************************************/ +/* returns time in miliseconds +   this is like g_time2 in os_calls, but not miliseconds since machine was +   up, something else +   this is a time value similar to what the xserver uses */ +static Time APP_CC +clipboard_get_time(void) +{ +  return g_time3(); +} + +/*****************************************************************************/ +/* returns error */  int APP_CC  clipboard_init(void)  { +  struct stream* s; +  int size; +  int rv; +  int input_mask; +  int dummy; +  int ver_maj; +  int ver_min; +  Status st; + +  if (g_clip_up) +  { +    return 0; +  } +  rv = 0; +  g_sleep(500); +  g_display = XOpenDisplay(0); +  if (g_display == 0) +  { +    g_writeln("xrdp-chansrv: clipboard_init: XOpenDisplay failed"); +    rv = 1; +  } +  if (rv == 0) +  { +    g_x_socket = XConnectionNumber(g_display); +    if (g_x_socket == 0) +    { +      g_writeln("xrdp-chansrv: clipboard_init: XConnectionNumber failed"); +      rv = 2; +    } +    g_x_wait_obj = g_create_wait_obj_from_socket(g_x_socket, 0); +  } +  if (rv == 0) +  { +    g_clipboard_atom = XInternAtom(g_display, "CLIPBOARD", False); +    if (g_clipboard_atom == None) +    { +      g_writeln("xrdp-chansrv: clipboard_init: XInternAtom failed"); +      rv = 3; +    } +  } +  if (rv == 0) +  { +    if (!XFixesQueryExtension(g_display, &g_xfixes_event_base, &dummy)) +    { +      g_writeln("xrdp-chansrv: clipboard_init: no xfixes"); +      rv = 5; +    } +  } +  if (rv == 0) +  { +    g_writeln("xrdp-chansrv: clipboard_init: g_xfixes_event_base %d", +              g_xfixes_event_base); +    st = XFixesQueryVersion(g_display, &ver_maj, &ver_min); +    g_writeln("xrdp-chansrv: clipboard_init st %d, maj %d min %d", +              st, ver_maj, ver_min); +    g_screen_num = DefaultScreen(g_display); +    g_screen = ScreenOfDisplay(g_display, g_screen_num); +    g_clip_property_atom = XInternAtom(g_display, "XRDP_CLIP_PROPERTY_ATOM", +                                       False); +    g_timestamp_atom = XInternAtom(g_display, "TIMESTAMP", False); +    g_targets_atom = XInternAtom(g_display, "TARGETS", False); +    g_multiple_atom = XInternAtom(g_display, "MULTIPLE", False); +    g_primary_atom = XInternAtom(g_display, "PRIMARY", False); +    g_wnd = XCreateSimpleWindow(g_display, RootWindowOfScreen(g_screen), +                                0, 0, 4, 4, 0, 0, 0); +    input_mask = StructureNotifyMask; +    XSelectInput(g_display, g_wnd, input_mask); +    //XMapWindow(g_display, g_wnd); +    XFixesSelectSelectionInput(g_display, g_wnd, +                               g_clipboard_atom, +                               XFixesSetSelectionOwnerNotifyMask | +                               XFixesSelectionWindowDestroyNotifyMask | +                               XFixesSelectionClientCloseNotifyMask); +  } +  if (rv == 0) +  { +    make_stream(s); +    init_stream(s, 8192); +    out_uint16_le(s, 1); /* CLIPRDR_CONNECT */ +    out_uint16_le(s, 0); /* status */ +    out_uint32_le(s, 0); /* length */ +    out_uint32_le(s, 0); /* extra 4 bytes ? */ +    s_mark_end(s); +    size = (int)(s->end - s->data); +    g_writeln("xrdp-chansrv: clipboard_init: data out, sending " +              "CLIPRDR_CONNECT (clip_msg_id = 1)"); +    rv = send_channel_data(g_cliprdr_chan_id, s->data, size); +    if (rv != 0) +    { +      g_writeln("xrdp-chansrv: clipboard_init: send_channel_data failed " +                "rv = %d", rv); +      rv = 4; +    } +    free_stream(s); +  } +  if (rv == 0) +  { +    g_clip_up = 1; +    g_writeln("xrdp-chansrv: clipboard_init: dumping env"); +    g_system("env"); +  } +  return rv; +} + +/*****************************************************************************/ +int APP_CC +clipboard_deinit(void) +{ +  if (!g_clip_up) +  { +    return 0; +  } +  if (!g_sck_closed) +  { +    g_delete_wait_obj_from_socket(g_x_wait_obj); +    g_x_wait_obj = 0; +    XDestroyWindow(g_display, g_wnd); +    g_wnd = 0; +    XCloseDisplay(g_display); +    g_display = 0; +    g_x_socket = 0; +    g_sck_closed = 1; +  } +  g_free(g_last_clip_data); +  g_last_clip_data = 0; +  g_clip_up = 0; +  return 0; +} + +/*****************************************************************************/ +static int APP_CC +clipboard_send_data_request(void) +{ +  struct stream* s; +  int size; +  int rv; +  int num_chars; + +  g_writeln("xrdp-chansrv: clipboard_send_data_request:"); +  make_stream(s); +  init_stream(s, 8192); +  out_uint16_le(s, 4); /* CLIPRDR_DATA_REQUEST */ +  out_uint16_le(s, 0); /* status */ +  out_uint32_le(s, 4); /* length */ +  out_uint32_le(s, 0x0d); +  s_mark_end(s); +  size = (int)(s->end - s->data); +  g_writeln("xrdp-chansrv: clipboard_send_data_request: data out, sending " +            "CLIPRDR_DATA_REQUEST (clip_msg_id = 4)"); +  rv = send_channel_data(g_cliprdr_chan_id, s->data, size); +  free_stream(s); +  return rv; +} + +/*****************************************************************************/ +static int APP_CC +clipboard_send_format_ack(void) +{ +  struct stream* s; +  int size; +  int rv; + +  make_stream(s); +  init_stream(s, 8192); +  out_uint16_le(s, 3); /* CLIPRDR_FORMAT_ACK */ +  out_uint16_le(s, 1); /* status */ +  out_uint32_le(s, 0); /* length */ +  out_uint32_le(s, 0); /* extra 4 bytes ? */ +  s_mark_end(s); +  size = (int)(s->end - s->data); +  g_writeln("xrdp-chansrv: clipboard_send_format_ack: data out, sending " +            "CLIPRDR_FORMAT_ACK (clip_msg_id = 3)"); +  rv = send_channel_data(g_cliprdr_chan_id, s->data, size); +  free_stream(s); +  return rv; +} + +/*****************************************************************************/ +static int APP_CC +clipboard_send_format_announce(void) +{ +  struct stream* s; +  int size; +  int rv; + +  make_stream(s); +  init_stream(s, 8192); +  out_uint16_le(s, 2); /* CLIPRDR_FORMAT_ANNOUNCE */ +  out_uint16_le(s, 0); /* status */ +  out_uint32_le(s, 0x90); /* length */ +  out_uint32_le(s, 0x0d); /* extra 4 bytes ? */ +  out_uint8s(s, 0x90); +  s_mark_end(s); +  size = (int)(s->end - s->data); +  g_writeln("xrdp-chansrv: clipboard_send_format_announce: data out, sending " +            "CLIPRDR_FORMAT_ANNOUNCE (clip_msg_id = 2)"); +  rv = send_channel_data(g_cliprdr_chan_id, s->data, size); +  free_stream(s); +  return rv; +} + +/*****************************************************************************/ +/* returns number of bytes written */ +static int APP_CC +clipboard_out_unicode(struct stream* s, char* text, int num_chars) +{ +  int index; +  int lnum_chars; +  twchar* ltext; + +  if (num_chars < 1) +  { +    return 0; +  } +  lnum_chars = g_mbstowcs(0, text, num_chars); +  if (lnum_chars < 0) +  { +    return 0; +  } +  ltext = g_malloc((num_chars + 1) * sizeof(twchar), 1); +  g_mbstowcs(ltext, text, num_chars); +  index = 0; +  while (index < num_chars) +  { +    out_uint16_le(s, ltext[index]); +    index++; +  } +  g_free(ltext); +  return index * 2; +} + +/*****************************************************************************/ +static int APP_CC +clipboard_send_data_response(void) +{ +  struct stream* s; +  int size; +  int rv; +  int num_chars; + +  g_writeln("xrdp-chansrv: clipboard_send_data_response:"); +  num_chars = 0; +  if (g_last_clip_type == XA_STRING) +  { +    num_chars = g_mbstowcs(0, g_last_clip_data, 1024); +    if (num_chars < 0) +    { +      g_writeln("xrdp-chansrv: clipboard_send_data_response: bad string"); +      num_chars = 0; +    } +  } +  make_stream(s); +  init_stream(s, 8192); +  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) +  { +    g_writeln("xrdp-chansrv: clipboard_send_data_response: 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); +  g_writeln("xrdp-chansrv: clipboard_send_format_announce: data out, sending " +            "CLIPRDR_DATA_RESPONSE (clip_msg_id = 5)"); +  rv = send_channel_data(g_cliprdr_chan_id, s->data, size); +  free_stream(s); +  return rv; +} + +/*****************************************************************************/ +static int APP_CC +clipboard_process_format_announce(struct stream* s) +{ +  Time now; + +  g_writeln("xrdp-chansrv: clipboard_process_format_announce:"); +  g_hexdump(s->p, s->end - s->p); +  clipboard_send_format_ack(); +  g_writeln("------------------------------"); +  now = clipboard_get_time(); +  XSetSelectionOwner(g_display, g_clipboard_atom, g_wnd, now); +  //XSetSelectionOwner(g_display, g_primary_atom, g_wnd, CurrentTime); +  return 0; +} + +/*****************************************************************************/ +static int APP_CC +clipboard_prcoess_format_ack(struct stream* s) +{ +  g_writeln("xrdp-chansrv: clipboard_prcoess_format_ack:"); +  g_hexdump(s->p, s->end - s->p); +  return 0; +} + +/*****************************************************************************/ +static int APP_CC +clipboard_process_data_request(struct stream* s) +{ +  g_writeln("xrdp-chansrv: clipboard_process_data_request:"); +  g_hexdump(s->p, s->end - s->p); +  clipboard_send_data_response(); +  return 0; +} + +/*****************************************************************************/ +static int APP_CC +clipboard_process_data_response(struct stream* s) +{ +  g_writeln("xrdp-chansrv: clipboard_process_data_response:"); +  g_hexdump(s->p, s->end - s->p);    return 0;  } @@ -35,13 +392,320 @@ int APP_CC  clipboard_data_in(struct stream* s, int chan_id, int chan_flags, int length,                    int total_length)  { +  int clip_msg_id; +  int clip_msg_len; +  int clip_msg_status; +  int rv; + +  in_uint16_le(s, clip_msg_id); +  in_uint16_le(s, clip_msg_status); +  in_uint32_le(s, clip_msg_len); +  g_writeln("xrdp-chansrv: clipboard_data_in: clip_msg_id %d " +            "clip_msg_status %d clip_msg_len %d", +            clip_msg_id, clip_msg_status, clip_msg_len); +  rv = 0; +  switch (clip_msg_id) +  { +    case 2: /* CLIPRDR_FORMAT_ANNOUNCE */ +      rv = clipboard_process_format_announce(s); +      break; +    case 3: /* CLIPRDR_FORMAT_ACK */ +      rv = clipboard_prcoess_format_ack(s); +      break; +    case 4: /* CLIPRDR_DATA_REQUEST */ +      rv = clipboard_process_data_request(s); +      break; +    case 5: /* CLIPRDR_DATA_RESPONSE */ +      rv = clipboard_process_data_response(s); +      break; +    default: +      g_writeln("xrdp-chansrv: clipboard_data_in: unknown clip_msg_id %d", +                clip_msg_id); +      break; +  } +  return rv; +} + +/*****************************************************************************/ +static int APP_CC +clipboard_process_selection_owner_notify(XEvent* xevent) +{ +  XFixesSelectionNotifyEvent* lxevent; + +  lxevent = (XFixesSelectionNotifyEvent*)xevent; +  g_writeln("xrdp-chansrv: clipboard_process_selection_owner_notify: " +            "window %d subtype %d owner %d", +            lxevent->window, lxevent->subtype, lxevent->owner); +  if (lxevent->subtype == 0) +  { +    XConvertSelection(g_display, g_clipboard_atom, XA_STRING, +                      g_clip_property_atom, g_wnd, CurrentTime); +  }    return 0;  }  /*****************************************************************************/ +/* returns error +   get a window property from g_wnd */ +static int APP_CC +clipboard_get_window_property(Atom prop, Atom* type, int* fmt, int* n_items, +                              char** xdata, int* xdata_size) +{ +  int lfmt; +  int lxdata_size; +  unsigned long ln_items; +  unsigned long llen_after; +  tui8* lxdata; +  Atom ltype; + +  lxdata = 0; +  ltype = 0; +  XGetWindowProperty(g_display, g_wnd, prop, 0, 0, 0, +                     AnyPropertyType, <ype, &lfmt, &ln_items, +                     &llen_after, &lxdata); +  XFree(lxdata); +  if (ltype == 0) +  { +    /* XGetWindowProperty failed */ +    return 1; +  } +  if (llen_after < 1) +  { +    /* no data, ok */ +    return 0; +  } +  lxdata = 0; +  ltype = 0; +  XGetWindowProperty(g_display, g_wnd, prop, 0, (llen_after + 3) / 4, 0, +                     AnyPropertyType, <ype, &lfmt, &ln_items, +                     &llen_after, &lxdata); +  if (ltype == 0) +  { +    /* XGetWindowProperty failed */ +    XFree(lxdata); +    return 1; +  } +  lxdata_size = (lfmt / 8) * ln_items; +  if (lxdata_size < 1) +  { +    /* should not happen */ +    XFree(lxdata); +    return 2; +  } +  if (llen_after > 0) +  { +    /* should not happen */ +    XFree(lxdata); +    return 3; +  } +  if (xdata != 0) +  { +    *xdata = (char*)g_malloc(lxdata_size, 0); +    g_memcpy(*xdata, lxdata, lxdata_size); +  } +  XFree(lxdata); +  if (xdata_size != 0) +  { +    *xdata_size = lxdata_size; +  } +  if (fmt != 0) +  { +    *fmt = (int)lfmt; +  } +  if (n_items != 0) +  { +    *n_items = (int)ln_items; +  } +  if (type != 0) +  { +    *type = ltype; +  } +  return 0; +} + +/*****************************************************************************/ +/* returns error +   process the SelectionNotify X event, uses XSelectionEvent +   typedef struct { +     int type;             // SelectionNotify +     unsigned long serial; // # of last request processed by server +     Bool send_event;      // true if this came from a SendEvent request +     Display *display;     // Display the event was read from +     Window requestor; +     Atom selection; +     Atom target; +     Atom property;        // atom or None +     Time time; +   } XSelectionEvent; */ +static int APP_CC +clipboard_process_selection_notify(XEvent* xevent) +{ +  XSelectionEvent* lxevent; +  char* data; +  int data_size; +  int n_items; +  int fmt; +  int rv; +  Atom type; + +  rv = 0; +  data = 0; +  type = 0; +  lxevent = (XSelectionEvent*)xevent; +  if (lxevent->property == None) +  { +    g_writeln("xrdp-chansrv: clipboard_process_selection_notify: clip cound " +              "not be converted"); +    rv = 1; +  } +  if (rv == 0) +  { +    rv = clipboard_get_window_property(lxevent->property, &type, &fmt, +                                       &n_items, &data, &data_size); +    if (rv != 0) +    { +      g_writeln("xrdp-chansrv: clipboard_process_selection_notify: " +                "clipboard_get_window_property failed error %d", rv); +    } +  } +  if (rv == 0) +  { +    g_writeln("xrdp-chansrv: clipboard_process_selection_notify: got  " +              "not be converted"); +    if (type == XA_STRING) +    { +      g_free(g_last_clip_data); +      g_last_clip_size = data_size; +      g_last_clip_data = 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; +    } +    else +    { +      g_writeln("xrdp-chansrv: clipboard_process_selection_notify: unknown " +                "clipboard data type %d", type); +      rv = 3;  +    } +  } +  XDeleteProperty(g_display, g_wnd, g_clip_property_atom); +  if (rv == 0) +  { +    if (clipboard_send_format_announce() != 0) +    { +      rv = 4; +    } +  } +  g_free(data); +  return rv; +} + +/*****************************************************************************/ +/* returns error +   process the SelectionRequest X event, uses XSelectionRequestEvent +   typedef struct { +     int type;             // SelectionRequest +     unsigned long serial; // # of last request processed by server +     Bool send_event;      // true if this came from a SendEvent request +     Display *display;     // Display the event was read from +     Window owner; +     Window requestor; +     Atom selection; +     Atom target; +     Atom property; +     Time time; +   } XSelectionRequestEvent; */ +static int APP_CC +clipboard_process_selection_request(XEvent* xevent) +{ +  XEvent xev; +  XSelectionRequestEvent* lxevent; + +  lxevent = (XSelectionRequestEvent*)xevent; +  g_writeln("xrdp-chansrv: clipboard_process_selection_request: g_wnd %d, " +            ".requestor %d .owner %d .select %d .target %d .property %d", +            g_wnd, lxevent->requestor, lxevent->owner, lxevent->selection, +            lxevent->target, lxevent->property); +  /* requestor is asking what the selection can be converted to */ +  if (lxevent->target == g_targets_atom) +  { +    g_writeln("xrdp-chansrv: clipboard_process_selection_request: g_targets_atom"); +  } +  /* requestor is asking the time I got the selection */ +  else if (lxevent->target == g_timestamp_atom) +  { +    g_writeln("xrdp-chansrv: clipboard_process_selection_request: g_timestamp_atom"); +  } +  else if (lxevent->target == g_multiple_atom) +  { +    g_writeln("xrdp-chansrv: clipboard_process_selection_request: g_multiple_atom"); +  } +  else if (lxevent->target == XA_STRING) +  { +    g_writeln("xrdp-chansrv: clipboard_process_selection_request: XA_STRING"); +    //XChangeProperty(g_display, lxevent->requestor, lxevent->property, +    //                XA_STRING, 8, PropModeReplace, "tes", 4); +    //xev.xselection.property = lxevent->property; +  } +  else +  { +    g_writeln("xrdp-chansrv: clipboard_process_selection_request: unknown " +              "target %s", XGetAtomName(g_display, lxevent->target)); +  } +  g_memset(&xev, 0, sizeof(xev)); +  xev.xselection.type = SelectionNotify; +  xev.xselection.serial = 0; +  xev.xselection.send_event = True; +  xev.xselection.requestor = lxevent->requestor; +  xev.xselection.selection = lxevent->selection; +  xev.xselection.target = lxevent->target; +  xev.xselection.property = None; +  xev.xselection.time = lxevent->time; +  XSendEvent(g_display, lxevent->requestor, False, NoEventMask, &xev); +  return 0; +} + +/*****************************************************************************/ +/* returns error +   process the SelectionClear X event, uses XSelectionClearEvent +   typedef struct { +     int type;                // SelectionClear +     unsigned long serial;    // # of last request processed by server +     Bool send_event;         // true if this came from a SendEvent request +     Display *display;        // Display the event was read from +     Window window; +     Atom selection; +     Time time; +} XSelectionClearEvent; */ +static int APP_CC +clipboard_process_selection_clear(XEvent* xevent) +{ +  g_writeln("xrdp-chansrv: clipboard_process_selection_clear:"); +  g_got_selection = 0; +  return 0; +} + +/*****************************************************************************/ +/* returns error +   this is called to get any wait objects for the main loop +   timeout can be nil */  int APP_CC  clipboard_get_wait_objs(tbus* objs, int* count, int* timeout)  { +  int lcount; + +  if ((!g_clip_up) || (objs == 0) || (count == 0)) +  { +    return 0; +  } +  if (g_sck_closed) +  { +    return 0; +  } +  lcount = *count; +  objs[lcount] = g_x_wait_obj; +  lcount++; +  *count = lcount;    return 0;  } @@ -49,5 +713,51 @@ clipboard_get_wait_objs(tbus* objs, int* count, int* timeout)  int APP_CC  clipboard_check_wait_objs(void)  { +  XEvent xevent; + +  if (!g_clip_up) +  { +    return 0; +  } +  if (g_sck_closed) +  { +    return 0; +  } +  if (g_is_wait_obj_set(g_x_wait_obj)) +  { +    if (XPending(g_display) < 1) +    { +      /* something is wrong, should not get here */ +      g_writeln("xrdp-chansrv: clipboard_check_wait_objs: sck closed"); +      g_sck_closed = 1; +      return 0; +    } +    while (XPending(g_display) > 0) +    { +      XNextEvent(g_display, &xevent); +      switch (xevent.type) +      { +        case SelectionNotify: +          clipboard_process_selection_notify(&xevent); +          break; +        case SelectionRequest: +          clipboard_process_selection_request(&xevent); +          break; +        case SelectionClear: +          clipboard_process_selection_clear(&xevent); +          break; +        default: +          if (xevent.type == g_xfixes_event_base + +                             XFixesSetSelectionOwnerNotify) +          { +            clipboard_process_selection_owner_notify(&xevent); +            break; +          } +          g_writeln("xrdp-chansrv: clipboard_check_wait_objs type %d", +                    xevent.type); +          break; +      } +    } +  }    return 0;  } diff --git a/sesman/chansrv/clipboard.h b/sesman/chansrv/clipboard.h index c0db098f..d6c74403 100644 --- a/sesman/chansrv/clipboard.h +++ b/sesman/chansrv/clipboard.h @@ -8,6 +8,8 @@  int APP_CC  clipboard_init(void);  int APP_CC +clipboard_deinit(void); +int APP_CC  clipboard_data_in(struct stream* s, int chan_id, int chan_flags, int length,                    int total_length);  int APP_CC diff --git a/sesman/chansrv/devredir.c b/sesman/chansrv/devredir.c index d938b5c4..988d923a 100644 --- a/sesman/chansrv/devredir.c +++ b/sesman/chansrv/devredir.c @@ -32,6 +32,13 @@ dev_redir_init(void)  /*****************************************************************************/  int APP_CC +dev_redir_deinit(void) +{ +  return 0; +} + +/*****************************************************************************/ +int APP_CC  dev_redir_data_in(struct stream* s, int chan_id, int chan_flags, int length,                    int total_length)  { diff --git a/sesman/chansrv/devredir.h b/sesman/chansrv/devredir.h index 43af7838..e0279093 100644 --- a/sesman/chansrv/devredir.h +++ b/sesman/chansrv/devredir.h @@ -8,6 +8,8 @@  int APP_CC  dev_redir_init(void);  int APP_CC +dev_redir_deinit(void); +int APP_CC  dev_redir_data_in(struct stream* s, int chan_id, int chan_flags, int length,                    int total_length);  int APP_CC diff --git a/sesman/chansrv/sound.c b/sesman/chansrv/sound.c index 87832209..bcf0b0fe 100644 --- a/sesman/chansrv/sound.c +++ b/sesman/chansrv/sound.c @@ -32,6 +32,13 @@ sound_init(void)  /*****************************************************************************/  int APP_CC +sound_deinit(void) +{ +  return 0; +} + +/*****************************************************************************/ +int APP_CC  sound_data_in(struct stream* s, int chan_id, int chan_flags, int length,                int total_length)  { diff --git a/sesman/chansrv/sound.h b/sesman/chansrv/sound.h index 9764ed87..45448a5a 100644 --- a/sesman/chansrv/sound.h +++ b/sesman/chansrv/sound.h @@ -8,6 +8,8 @@  int APP_CC  sound_init(void);  int APP_CC +sound_deinit(void); +int APP_CC  sound_data_in(struct stream* s, int chan_id, int chan_flags, int length,                int total_length);  int APP_CC | 
