diff -ur rdesktop-1.6.0-orig/channels.c rdesktop-1.6.0/channels.c --- rdesktop-1.6.0-orig/channels.c 2007-01-08 07:47:05.000000000 +0300 +++ rdesktop-1.6.0/channels.c 2008-12-05 18:58:00.000000000 +0300 @@ -19,6 +19,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include +#include +#include #include "rdesktop.h" #define MAX_CHANNELS 6 @@ -44,7 +47,7 @@ */ VCHANNEL * -channel_register(char *name, uint32 flags, void (*callback) (STREAM)) +channel_register(char *name, uint32 flags, void (*callback) (STREAM,char*)) { VCHANNEL *channel; @@ -159,7 +162,7 @@ if ((flags & CHANNEL_FLAG_FIRST) && (flags & CHANNEL_FLAG_LAST)) { /* single fragment - pass straight up */ - channel->process(s); + channel->process(s, channel->name); } else { @@ -183,7 +186,109 @@ { in->end = in->p; in->p = in->data; - channel->process(in); + channel->process(in, channel->name); } } } + +/* Generic callback for delivering data to third party add-ins */ +void addin_callback(STREAM s, char *name) +{ + pid_t pid; + int pipe_read; + int pipe_write; + uint32 blocksize; + + blocksize = s->end - s->p; + + lookup_addin(name, &pid, &pipe_read, &pipe_write); + if (pid > 0) { + /* Prepend the block with the block size so the + add-in can identify blocks */ + write(pipe_write, &blocksize, sizeof(uint32)); + write(pipe_write, s->p, blocksize); + } +} + +void addin_add_fds(int *n, fd_set *rfds, fd_set *wfds, struct timeval *tv) +{ + extern ADDIN_DATA addin_data[]; + extern int addin_count; + int i; + + for (i = 0; i < addin_count; i++) { + /* Take in account only live addins. */ + if (addin_data[i].pid > 0) { + int addin_fd = addin_data[i].pipe_read; + + FD_SET(addin_fd, rfds); + if (*n < addin_fd) + *n = addin_fd; + } + } +} + +/* Process outgoing addin data */ +void addin_check_fds(fd_set *rfds, fd_set *wfds) +{ + extern ADDIN_DATA addin_data[]; + extern int addin_count; + int i; + unsigned int block_len; + ssize_t bytes_read; + STREAM s; + + for (i = 0; i < addin_count; i++) { + int addin_fd = addin_data[i].pipe_read; + + if (!FD_ISSET(addin_fd, rfds)) { + continue; + } + + bytes_read = read(addin_fd, &block_len, sizeof(block_len)); + if (bytes_read <= 0) { + addin_check_terminated(&addin_data[i]); + continue; + } + + if (block_len > 0xffff) { + warning("received too much data (%d) from addin %s\n", + block_len, addin_data[i].name); + addin_check_terminated(&addin_data[i]); + continue; + } + + if (block_len > addin_data[i].buf_len) { + addin_data[i].buf = (unsigned char *)xrealloc( + addin_data[i].buf, + block_len); + addin_data[i].buf_len = block_len; + } + + bytes_read = read(addin_fd, addin_data[i].buf, block_len); + if (bytes_read > 0) { + s = channel_init(addin_data[i].vchannel, bytes_read); + memcpy(s->p, addin_data[i].buf, bytes_read); + s->p += bytes_read; + s->end = s->p; + + channel_send(s, addin_data[i].vchannel); + } + } +} + +void addin_check_terminated(ADDIN_DATA *addin) +{ + int status = 0; + + pid_t result = waitpid(addin->pid, &status, WNOHANG); + if (result <= 0) + return; + + if (WIFEXITED(status) || WIFSIGNALED(status)) { + warning("Addin %s is suddenly terminated\n", addin->name); + /* Mark this addin as terminated to exclude + it from processing. */ + addin->pid = 0; + } +} diff -ur rdesktop-1.6.0-orig/cliprdr.c rdesktop-1.6.0/cliprdr.c --- rdesktop-1.6.0-orig/cliprdr.c 2007-01-08 07:47:05.000000000 +0300 +++ rdesktop-1.6.0/cliprdr.c 2008-12-05 18:42:40.000000000 +0300 @@ -111,7 +111,7 @@ } static void -cliprdr_process(STREAM s) +cliprdr_process(STREAM s, char *name) { uint16 type, status; uint32 length, format; Only in rdesktop-1.6.0/doc: .svn Only in rdesktop-1.6.0/keymaps: .svn diff -ur rdesktop-1.6.0-orig/lspci.c rdesktop-1.6.0/lspci.c --- rdesktop-1.6.0-orig/lspci.c 2007-01-08 07:47:05.000000000 +0300 +++ rdesktop-1.6.0/lspci.c 2008-12-05 18:42:40.000000000 +0300 @@ -128,7 +128,7 @@ /* Process new data from the virtual channel */ static void -lspci_process(STREAM s) +lspci_process(STREAM s, char *name) { unsigned int pkglen; static char *rest = NULL; diff -ur rdesktop-1.6.0-orig/proto.h rdesktop-1.6.0/proto.h --- rdesktop-1.6.0-orig/proto.h 2008-04-02 15:13:22.000000000 +0400 +++ rdesktop-1.6.0/proto.h 2008-12-05 18:58:00.000000000 +0300 @@ -45,7 +45,7 @@ RD_HCURSOR cache_get_cursor(uint16 cache_idx); void cache_put_cursor(uint16 cache_idx, RD_HCURSOR cursor); /* channels.c */ -VCHANNEL *channel_register(char *name, uint32 flags, void (*callback) (STREAM)); +VCHANNEL *channel_register(char *name, uint32 flags, void (*callback) (STREAM,char *)); STREAM channel_init(VCHANNEL * channel, uint32 length); void channel_send(STREAM s, VCHANNEL * channel); void channel_process(STREAM s, uint16 mcs_channel); @@ -314,6 +314,21 @@ void scard_lock(int lock); void scard_unlock(int lock); +/* External addins */ +void init_external_addin(char * addin_name, char * addin_path, char * args, ADDIN_DATA * addin_data); + +/* Generic callback for delivering data to third party add-ins */ +void addin_callback(STREAM s, char *name); + +/* Find an external add-in registration by virtual channel name */ +void lookup_addin(char *name, pid_t * pid, int * pipe_read, int * pipe_write); + +void addin_add_fds(int *n, fd_set *rfds, fd_set *wfds, struct timeval *tv); + +void addin_check_fds(fd_set *rfds, fd_set *wfds); + +void addin_check_terminated(ADDIN_DATA *addin); + /* *INDENT-OFF* */ #ifdef __cplusplus } diff -ur rdesktop-1.6.0-orig/rdesktop.c rdesktop-1.6.0/rdesktop.c --- rdesktop-1.6.0-orig/rdesktop.c 2008-04-05 09:22:26.000000000 +0400 +++ rdesktop-1.6.0/rdesktop.c 2008-12-05 18:58:00.000000000 +0300 @@ -28,6 +28,7 @@ #include /* times */ #include /* toupper */ #include +#include /* kill */ #include "rdesktop.h" #ifdef HAVE_LOCALE_H @@ -115,6 +116,9 @@ extern uint32 g_num_devices; extern char *g_rdpdr_clientname; +ADDIN_DATA addin_data[MAX_ADDINS]; +int addin_count = 0; + #ifdef RDP2VNC extern int rfb_port; extern int defer_time; @@ -208,6 +212,9 @@ fprintf(stderr, " \"AKS\" -> Device vendor name \n"); #endif + fprintf(stderr, + " '-r addin::[:arg1[:arg2:]...]': enable third\n"); + fprintf(stderr, " party virtual channel add-in.\n"); fprintf(stderr, " -0: attach to console\n"); fprintf(stderr, " -4: use RDP version 4\n"); fprintf(stderr, " -5: use RDP version 5 (default)\n"); @@ -417,6 +424,8 @@ struct passwd *pw; uint32 flags, ext_disc_reason = 0; char *p; + char *addin_name; + char *addin_path; int c; char *locale = NULL; int username_option = 0; @@ -672,8 +681,58 @@ break; case 'r': + if (str_startswith(optarg, "addin")) + { + if (addin_count >= MAX_ADDINS) + { + error("Add-ins data table full, increase MAX_ADDINS\n"); + return 1; + } + + optarg += 5; - if (str_startswith(optarg, "sound")) + if (*optarg == ':') + { + addin_name = optarg + 1; + if (*addin_name != '\0') + { + addin_path = next_arg(addin_name, ':'); + } + else + { + addin_path = 0; + } + if (addin_path != 0) + { + p = next_arg(addin_path, ':'); + } + if (*addin_name != '\0' && addin_path != 0 && *addin_path != '\0') + { + init_external_addin(addin_name, addin_path, + p, &addin_data[addin_count]); + if (addin_data[addin_count].pid != 0) + { + addin_count++; + } + else + { + error("Failed to initialise add-in [%s]\n", addin_name); + return 1; + } + } + else + { + usage(argv[0]); + return(1); + } + } + else + { + usage(argv[0]); + return(1); + } + } + else if (str_startswith(optarg, "sound")) { optarg += 5; @@ -982,6 +1041,17 @@ cache_save_state(); ui_deinit(); + /* Send a SIGUSR1 to all addins to close and sleep for a couple of secs + to give them a chance to stop */ + for (c = 0; c < addin_count; c++) + { + if (addin_data[c].pid != 0) + { + kill(addin_data[c].pid,SIGUSR1); + sleep(2); + } + } + if (ext_disc_reason >= 2) print_disconnect_reason(ext_disc_reason); @@ -1625,3 +1695,105 @@ return False; return True; } + +/* Initialise external addin */ +void init_external_addin(char * addin_name, char * addin_path, char * args, ADDIN_DATA * addin_data) +{ + char *p; + char *current_arg; + char * argv[256]; + char argv_buffer[256][256]; + int i; + int readpipe[2],writepipe[2]; + pid_t child; + + /* Initialise addin structure */ + memset(addin_data, 0, sizeof(ADDIN_DATA)); + /* Go through the list of args, adding each to argv */ + argv[0] = addin_path; + i = 1; + p=current_arg=args; + while (current_arg != 0 && current_arg[0] != '\0') + { + p=next_arg(p, ':');; + if (p != 0 && *p != '\0') + *(p - 1) = '\0'; + strcpy(argv_buffer[i], current_arg); + argv[i]=argv_buffer[i]; + i++; + current_arg=p; + } + argv[i] = NULL; + + + /* Create pipes */ + if (pipe(readpipe) < 0 || pipe(writepipe) < 0) + { + perror("pipes for addin"); + return; + } + + /* Fork process */ + if ((child = fork()) < 0) + { + perror("fork for addin"); + return; + } + + /* Child */ + if (child == 0) + { + /* Set stdin and stdout of child to relevant pipe ends */ + dup2(writepipe[0],0); + dup2(readpipe[1],1); + + /* Close all fds as they are not needed now */ + close(readpipe[0]); + close(readpipe[1]); + close(writepipe[0]); + close(writepipe[1]); + execvp((char *)argv[0], (char **)argv); + perror("Error executing child"); + _exit(128); + } + else + { + strcpy(addin_data->name, addin_name); + /* Close child end fd's */ + close(readpipe[1]); + close(writepipe[0]); + addin_data->pipe_read=readpipe[0]; + addin_data->pipe_write=writepipe[1]; + addin_data->vchannel=channel_register(addin_name, + CHANNEL_OPTION_INITIALIZED | + CHANNEL_OPTION_ENCRYPT_RDP | + CHANNEL_OPTION_COMPRESS_RDP, + addin_callback); + if (!addin_data->vchannel) + { + perror("Channel register failed"); + return; + } + else + addin_data->pid=child; + + } + +} + +/* Find an external add-in registration by virtual channel name */ +void lookup_addin(char *name, pid_t * pid, int * pipe_read, int * pipe_write) +{ + int i; + + *pid = 0; + + for (i = 0; i < addin_count; i++) { + if (!strcmp(name,addin_data[i].name)) { + *pid=addin_data[i].pid; + *pipe_read=addin_data[i].pipe_read; + *pipe_write=addin_data[i].pipe_write; + break; + } + } +} diff -ur rdesktop-1.6.0-orig/rdesktop.h rdesktop-1.6.0/rdesktop.h --- rdesktop-1.6.0-orig/rdesktop.h 2008-04-05 08:54:10.000000000 +0400 +++ rdesktop-1.6.0/rdesktop.h 2008-12-05 18:42:40.000000000 +0300 @@ -41,6 +41,8 @@ #define VERSION "1.6.0" +#define MAX_ADDINS 20 + #ifdef WITH_DEBUG #define DEBUG(args) printf args; #else diff -ur rdesktop-1.6.0-orig/rdpdr.c rdesktop-1.6.0/rdpdr.c --- rdesktop-1.6.0-orig/rdpdr.c 2008-02-14 14:37:17.000000000 +0300 +++ rdesktop-1.6.0/rdpdr.c 2008-12-05 18:42:40.000000000 +0300 @@ -781,7 +781,7 @@ } static void -rdpdr_process(STREAM s) +rdpdr_process(STREAM s, char *name) { uint32 handle; uint8 *magic; diff -ur rdesktop-1.6.0-orig/rdpsnd.c rdesktop-1.6.0/rdpsnd.c --- rdesktop-1.6.0-orig/rdpsnd.c 2008-02-14 14:37:17.000000000 +0300 +++ rdesktop-1.6.0/rdpsnd.c 2008-12-05 18:42:40.000000000 +0300 @@ -544,7 +544,7 @@ } static void -rdpsnd_process(STREAM s) +rdpsnd_process(STREAM s, char *name) { uint16 len; @@ -611,7 +611,7 @@ } static void -rdpsnddbg_process(STREAM s) +rdpsnddbg_process(STREAM s, char *name) { unsigned int pkglen; static char *rest = NULL; diff -ur rdesktop-1.6.0-orig/seamless.c rdesktop-1.6.0/seamless.c --- rdesktop-1.6.0-orig/seamless.c 2008-04-02 15:13:22.000000000 +0400 +++ rdesktop-1.6.0/seamless.c 2008-12-05 18:42:40.000000000 +0300 @@ -370,7 +370,7 @@ static void -seamless_process(STREAM s) +seamless_process(STREAM s, char *name) { unsigned int pkglen; static char *rest = NULL; Only in rdesktop-1.6.0: .svn diff -ur rdesktop-1.6.0-orig/types.h rdesktop-1.6.0/types.h --- rdesktop-1.6.0-orig/types.h 2007-01-08 07:47:06.000000000 +0300 +++ rdesktop-1.6.0/types.h 2008-12-05 18:42:40.000000000 +0300 @@ -125,7 +125,7 @@ char name[8]; uint32 flags; struct stream in; - void (*process) (STREAM); + void (*process) (STREAM,char *); } VCHANNEL; @@ -265,4 +265,15 @@ } FILEINFO; +typedef struct _ADDIN_DATA +{ + char name[255]; + unsigned char *buf; + unsigned int buf_len; + pid_t pid; + int pipe_read; + int pipe_write; + VCHANNEL *vchannel; +} ADDIN_DATA; + typedef RD_BOOL(*str_handle_lines_t) (const char *line, void *data); diff -ur rdesktop-1.6.0-orig/xwin.c rdesktop-1.6.0/xwin.c --- rdesktop-1.6.0-orig/xwin.c 2008-05-11 10:14:38.000000000 +0400 +++ rdesktop-1.6.0/xwin.c 2008-12-05 18:42:40.000000000 +0300 @@ -2620,6 +2620,9 @@ rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout); seamless_select_timeout(&tv); + /* add addins handles */ + addin_add_fds(&n, &rfds, &wfds, &tv); + n++; switch (select(n, &rfds, &wfds, NULL, &tv)) @@ -2642,6 +2645,8 @@ rdpsnd_check_fds(&rfds, &wfds); #endif + addin_check_fds(&rfds, &wfds); + rdpdr_check_fds(&rfds, &wfds, (RD_BOOL) False); if (FD_ISSET(rdp_socket, &rfds))