diff options
author | runge <runge> | 2004-03-11 00:57:59 +0000 |
---|---|---|
committer | runge <runge> | 2004-03-11 00:57:59 +0000 |
commit | ed986a0bbe9b8cfc084e70f6eb32368ea2e2b11a (patch) | |
tree | d436c46479c96039c62cc1e4549d645009023995 /contrib | |
parent | 74b9f7de2ef8f0fe431eb4f4c18332eb207ad8a2 (diff) | |
download | libtdevnc-ed986a0bbe9b8cfc084e70f6eb32368ea2e2b11a.tar.gz libtdevnc-ed986a0bbe9b8cfc084e70f6eb32368ea2e2b11a.zip |
x11vnc options -vncconnect, -connect, -remap,
-debug_pointer, and -debug_keyboard
add reverse connections, keysym remapping,
and debug output option
Diffstat (limited to 'contrib')
-rw-r--r-- | contrib/ChangeLog | 8 | ||||
-rw-r--r-- | contrib/x11vnc.c | 559 |
2 files changed, 511 insertions, 56 deletions
diff --git a/contrib/ChangeLog b/contrib/ChangeLog index aa3ba54..4f0c67c 100644 --- a/contrib/ChangeLog +++ b/contrib/ChangeLog @@ -1,3 +1,11 @@ +2004-03-10 Karl Runge <runge@karlrunge.com> + * added reverse connection for vncconnect(1) and other means + -vncconnect, -connect host:port, and -connect watchfile + * added first pass at user keysym remapping feature via + -remap file. Ignores modifier state, need to generalize. + * debugging options for users -debug_pointer and -debug_keyboard + * clear -passwd from argv for privacy (if OS allows). + 2004-02-19 Karl Runge <runge@karlrunge.com> * added handling of clipboard/selection exchange to/from clients, even holds PRIMARY which Xvnc does not do. disable with -nosel. diff --git a/contrib/x11vnc.c b/contrib/x11vnc.c index ef71357..c094147 100644 --- a/contrib/x11vnc.c +++ b/contrib/x11vnc.c @@ -180,8 +180,13 @@ int flash_cmap = 0; /* follow installed colormaps */ int force_indexed_color = 0; /* whether to force indexed color for 8bpp */ int use_modifier_tweak = 0; /* use the altgr_keyboard modifier tweak */ +char *remap_file = NULL; /* user supplied remapping file */ int nofb = 0; /* do not send any fb updates */ +char *client_connect = NULL; /* strings for -connect option */ +char *client_connect_file = NULL; +int vnc_connect = 0; /* -vncconnect option */ + int local_cursor = 1; /* whether the viewer draws a local cursor */ int show_mouse = 0; /* display a cursor for the real mouse */ int show_root_cursor = 0; /* show X when on root background */ @@ -213,7 +218,7 @@ VisualID visual_id = (VisualID) 0; int visual_depth = 0; int nap_ok = 0, nap_diff_count = 0; -time_t last_event, last_input; +time_t last_event, last_input, last_client = 0; /* tile heuristics: */ double fs_frac = 0.75; /* threshold tile fraction to do fullscreen updates. */ @@ -241,6 +246,9 @@ int scan_in_progress = 0; int fb_copy_in_progress = 0; int shut_down = 0; +int debug_pointer = 0; +int debug_keyboard = 0; + int quiet = 0; double dtime(double *); @@ -419,6 +427,197 @@ int check_access(char *addr) { } /* + * For the -connect <file> option: periodically read the file looking for + * a connect string. If one is found set client_connect to it. + */ +void check_connect_file(char *file) { + FILE *in; + char line[512], host[512]; + static int first_warn = 1, truncate_ok = 1; + static time_t last_time = 0; + time_t now = time(0); + + if (now - last_time < 1) { + /* check only once a second */ + return; + } + last_time = now; + + if (! truncate_ok) { + /* check if permissions changed */ + if (access(file, W_OK) == 0) { + truncate_ok = 1; + } else { + return; + } + } + + in = fopen(file, "r"); + if (in == NULL) { + if (first_warn) { + rfbLog("check_connect_file: fopen failure: %s\n", file); + perror("fopen"); + first_warn = 0; + } + return; + } + + if (fgets(line, 512, in) != NULL) { + if (sscanf(line, "%s", host) == 1) { + if (strlen(host) > 0) { + client_connect = strdup(host); + rfbLog("read connect file: %s\n", host); + } + } + } + fclose(in); + + /* truncate file */ + in = fopen(file, "w"); + if (in != NULL) { + fclose(in); + } else { + /* disable if we cannot truncate */ + rfbLog("check_connect_file: could not truncate %s, " + "disabling checking.\n", file); + truncate_ok = 0; + } +} + +/* Do a reverse connect for a single "host" or "host:port" */ +int do_reverse_connect(char *str) { + rfbClientPtr cl; + char *host, *p; + int port = 5500, len = strlen(str); + + if (len < 1) { + return; + } + if (len > 512) { + rfbLog("reverse_connect: string too long: %d bytes\n", len); + return; + } + + /* copy in to host */ + host = (char *) malloc((size_t) len+1); + if (! host) { + rfbLog("reverse_connect: could not malloc string %d\n", len); + return; + } + strncpy(host, str, len); + host[len] = '\0'; + + /* extract port, if any */ + if ((p = strchr(host, ':')) != NULL) { + port = atoi(p+1); + *p = '\0'; + } + + cl = rfbReverseConnection(screen, host, port); + free(host); + + if (cl == NULL) { + rfbLog("reverse_connect: %s failed\n", str); + return 0; + } else { + rfbLog("reverse_connect: %s/%s OK\n", str, cl->host); + return 1; + } +} + +void rfbPE(rfbScreenInfoPtr scr, long us) { + if (! use_threads) { + return rfbProcessEvents(scr, us); + } +} + +/* break up comma separated list of hosts and call do_reverse_connect() */ + +void reverse_connect(char *str) { + char *p, *tmp = strdup(str); + int sleep_between_host = 300; + int sleep_min = 1500, sleep_max = 4500, n_max = 5; + int n, tot, t, dt = 100, cnt = 0; + + p = strtok(tmp, ","); + while (p) { + if ((n = do_reverse_connect(p)) != 0) { + rfbPE(screen, -1); + } + cnt += n; + + p = strtok(NULL, ","); + if (p) { + t = 0; + while (t < sleep_between_host) { + usleep(dt * 1000); + rfbPE(screen, -1); + t += dt; + } + } + } + free(tmp); + + if (cnt == 0) { + return; + } + + /* + * XXX: we need to process some of the initial handshaking + * events, otherwise the client can get messed up (why??) + * so we send rfbProcessEvents() all over the place. + */ + + n = cnt; + if (n >= n_max) { + n = n_max; + } + t = sleep_max - sleep_min; + tot = sleep_min + ((n-1) * t) / (n_max-1); + + t = 0; + while (t < tot) { + rfbPE(screen, -1); + usleep(dt * 1000); + t += dt; + } +} + +/* check if client_connect has been set, if so make the reverse connections. */ + +void send_client_connect() { + if (client_connect != NULL) { + reverse_connect(client_connect); + free(client_connect); + client_connect = NULL; + } +} + +/* string for the VNC_CONNECT property */ +#define VNC_CONNECT_MAX 512 +char vnc_connect_str[VNC_CONNECT_MAX+1]; + +/* monitor the various input methods */ +void check_connect_inputs() { + + /* flush any already set: */ + send_client_connect(); + + /* connect file: */ + if (client_connect_file != NULL) { + check_connect_file(client_connect_file); + } + send_client_connect(); + + /* VNC_CONNECT property (vncconnect program) */ + if (vnc_connect && *vnc_connect_str != '\0') { + client_connect = strdup(vnc_connect_str); + vnc_connect_str[0] = '\0'; + } + send_client_connect(); +} + +/* * libvncserver callback for when a new client connects */ enum rfbNewClientAction new_client(rfbClientPtr client) { @@ -446,6 +645,7 @@ enum rfbNewClientAction new_client(rfbClientPtr client) { client->clientData = (void *) 0; } accepted_client = 1; + last_client = time(0); return(RFB_CLIENT_ACCEPT); } @@ -460,7 +660,7 @@ char mod_state = 0; char modifiers[0x100]; KeyCode keycodes[0x100], left_shift_code, right_shift_code, altgr_code; -void initialize_keycodes() { +void initialize_modtweak() { KeySym key, *keymap; int i, j, minkey, maxkey, syms_per_keycode; @@ -508,25 +708,105 @@ void initialize_keycodes() { XFree ((void *) keymap); } -void DebugXTestFakeKeyEvent(Display* dpy, KeyCode keysym, Bool down, time_t cur_time) +/* + * The following is for an experimental -remap option to allow the user + * to remap keystrokes. It is currently confusing wrt modifiers... + */ +typedef struct keyremap { + KeySym before; + KeySym after; + struct keyremap *next; +} keyremap_t; + +keyremap_t *keyremaps = NULL; + +void initialize_remap(char *infile) { + FILE *in; + char *p, line[256], str1[256], str2[256]; + int i; + KeySym ksym1, ksym2; + keyremap_t *remap, *current; + + in = fopen(infile, "r"); + if (in == NULL) { + rfbLog("remap: cannot open: %s\n", infile); + perror("fopen"); + clean_up_exit(1); + } + while (fgets(line, 256, in) != NULL) { + int blank = 1; + p = line; + while (*p) { + if (! isspace(*p)) { + blank = 0; + break; + } + p++; + } + if (blank) { + continue; + } + if (strchr(line, '#')) { + continue; + } + + if (sscanf(line, "%s %s", str1, str2) != 2) { + rfbLog("remap: bad line: %s\n", line); + fclose(in); + clean_up_exit(1); + } + if (sscanf(str1, "0x%x", &i) == 1) { + ksym1 = (KeySym) i; + } else { + ksym1 = XStringToKeysym(str1); + } + if (sscanf(str2, "0x%x", &i) == 1) { + ksym2 = (KeySym) i; + } else { + ksym2 = XStringToKeysym(str2); + } + if (ksym1 == NoSymbol || ksym2 == NoSymbol) { + rfbLog("warning: skipping bad remap line: %s", line); + continue; + } + remap = (keyremap_t *) malloc((size_t) sizeof(keyremap_t)); + remap->before = ksym1; + remap->after = ksym2; + remap->next = NULL; + rfbLog("remapping: (%s, 0x%x) -> (%s, 0x%x)\n", str1, ksym1, + str2, ksym2); + if (keyremaps == NULL) { + keyremaps = remap; + } else { + current->next = remap; + + } + current = remap; + } + fclose(in); +} + +void DebugXTestFakeKeyEvent(Display* dpy, KeyCode key, Bool down, time_t cur_time) { - rfbLog("XTestFakeKeyEvent(dpy,%s(0x%x),%s,CurrentTime)\n", - XKeysymToString(XKeycodeToKeysym(dpy,keysym,0)),keysym, - down?"down":"up"); - XTestFakeKeyEvent(dpy,keysym,down,cur_time); + if (debug_keyboard) { + rfbLog("XTestFakeKeyEvent(dpy, keycode=0x%x \"%s\", %s)\n", + key, XKeysymToString(XKeycodeToKeysym(dpy, key, 0)), + down ? "down":"up"); + } + XTestFakeKeyEvent(dpy, key, down, cur_time); } /* - * Uncomment the two lines to aid in debugging keymapping problems. + * This is to allow debug_keyboard option trap everything: */ -/* #define XTestFakeKeyEvent DebugXTestFakeKeyEvent -#define DebugKeyEvent -*/ void tweak_mod(signed char mod, rfbBool down) { rfbBool is_shift = mod_state & (LEFTSHIFT|RIGHTSHIFT); Bool dn = (Bool) down; + if (debug_keyboard) { + rfbLog("tweak_mod: down=%d mod=0x%x\n", down, mod); + } if (mod < 0) { return; @@ -556,6 +836,10 @@ void tweak_mod(signed char mod, rfbBool down) { static void modifier_tweak_keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) { KeyCode k; int tweak = 0; + if (debug_keyboard) { + rfbLog("modifier_tweak_keyboard: %s keysym=0x%x\n", + down ? "down" : "up", (int) keysym); + } if (view_only) { return; @@ -601,17 +885,36 @@ static void modifier_tweak_keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr static void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) { KeyCode k; -#ifdef DebugKeyEvent - X_LOCK; - rfbLog("keyboard(%s,%s(0x%x),client)\n", - down?"down":"up",XKeysymToString(keysym),(int)keysym); - X_UNLOCK; -#endif + if (debug_keyboard) { + X_LOCK; + rfbLog("keyboard(%s, 0x%x \"%s\")\n", down ? "down":"up", + (int) keysym, XKeysymToString(keysym)); + X_UNLOCK; + } if (view_only) { return; } + if (keyremaps) { + keyremap_t *remap = keyremaps; + while (remap != NULL) { + if (remap->before == keysym) { + keysym = remap->after; + if (debug_keyboard) { + rfbLog("keyboard(): remapping keysym: " + "0x%x \"%s\" -> 0x%x \"%s\"\n", + (int) remap->before, + XKeysymToString(remap->before), + (int) remap->after, + XKeysymToString(remap->after)); + } + break; + } + remap = remap->next; + } + } + if (use_modifier_tweak) { modifier_tweak_keyboard(down, keysym, client); X_LOCK; @@ -624,6 +927,11 @@ static void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) { k = XKeysymToKeycode(dpy, (KeySym) keysym); + if (debug_keyboard) { + rfbLog("keyboard(): KeySym 0x%x \"%s\" -> KeyCode 0x%x\n", + (int) keysym, XKeysymToString(keysym), (int) k); + } + if ( k != NoSymbol ) { XTestFakeKeyEvent(dpy, k, (Bool) down, CurrentTime); XFlush(dpy); @@ -677,6 +985,10 @@ void init_pointer(void) { n = atoi(p+1); if (n < num_buttons || num_buttons == 0) { num_buttons = n; + } else { + rfbLog("warning: increasing number of mouse " + "buttons from %d to %d\n", num_buttons, n); + num_buttons = n; } } if ((q = strchr(pointer_remap, '-')) != NULL) { @@ -710,6 +1022,10 @@ void init_pointer(void) { */ static void pointer(int mask, int x, int y, rfbClientPtr client) { + if (debug_pointer && mask >= 0) { + rfbLog("pointer(mask: 0x%x, x:%4d, y:%4d)\n", mask, x, y); + } + if (view_only) { return; } @@ -777,12 +1093,19 @@ static void pointer(int mask, int x, int y, rfbClientPtr client) { ev[i][1] = x; ev[i][2] = y; UNLOCK(pointerMutex); + if (debug_pointer) { + rfbLog("pointer(): deferring event " + "%d\n", i); + } return; } } /* time to send the queue */ for (i=0; i<nevents; i++) { + if (debug_pointer) { + rfbLog("pointer(): sending event %d\n", i+1); + } update_pointer(ev[i][0], ev[i][1], ev[i][2]); } if (nevents && dt > maxwait) { @@ -798,6 +1121,9 @@ static void pointer(int mask, int x, int y, rfbClientPtr client) { UNLOCK(pointerMutex); } if (mask < 0) { /* -1 just means flush the event queue */ + if (debug_pointer > 1) { + rfbLog("pointer(): flush only.\n"); + } return; } @@ -824,6 +1150,10 @@ void update_pointer(int mask, int x, int y) { for (i=0; i < MAX_BUTTONS; i++) { /* look for buttons that have be clicked or released: */ if ( (button_mask & (1<<i)) != (mask & (1<<i)) ) { + if (debug_pointer) { + rfbLog("pointer(): mask change: mask: 0x%x -> " + "0x%x button: %d\n", button_mask, mask,i+1); + } mb = pointer_map[i+1]; if (num_buttons && mb > num_buttons) { rfbLog("ignoring mouse button out of bounds: %d" @@ -1128,62 +1458,132 @@ void selection_send(XEvent *ev) { rfbSendServerCutText(screen, selection_str, newlen); } + +/* + * Routines for monitoring the VNC_CONNECT property for changes. + * The vncconnect(1) will set it on our X display. + */ + +Atom vnc_connect_prop = None; + +void read_vnc_connect_prop() { + Atom type; + int format, slen, dlen; + unsigned long nitems = 0, bytes_after = 0; + unsigned char* data = NULL; + + vnc_connect_str[0] = '\0'; + slen = 0; + + if (! vnc_connect || vnc_connect_prop == None) { + /* not active or problem with VNC_CONNECT atom */ + return; + } + + /* read the property value into vnc_connect_str: */ + do { + if (XGetWindowProperty(dpy, DefaultRootWindow(dpy), + vnc_connect_prop, nitems/4, VNC_CONNECT_MAX/16, False, + AnyPropertyType, &type, &format, &nitems, &bytes_after, + &data) == Success) { + + dlen = nitems * (format/8); + if (slen + dlen > VNC_CONNECT_MAX) { + /* too big */ + rfbLog("warning: truncating large VNC_CONNECT" + " string > %d bytes.\n", VNC_CONNECT_MAX); + XFree(data); + break; + } + memcpy(vnc_connect_str+slen, data, dlen); + slen += dlen; + vnc_connect_str[slen] = '\0'; + XFree(data); + } + } while (bytes_after > 0); + + vnc_connect_str[VNC_CONNECT_MAX] = '\0'; + rfbLog("read property VNC_CONNECT: %s\n", vnc_connect_str); +} + /* * This routine is periodically called to check for selection related - * X11 events and respond to them as needed. + * and other X11 events and respond to them as needed. */ -void watch_selection_event() { +void watch_xevents() { XEvent xev; - static int last_request = 0, first = 1, sent_sel = 0, starttime; + static int first = 1, sent_sel = 0; + int have_clients = screen->rfbClientHead ? 1 : 0; + time_t last_request = 0, now = time(0); X_LOCK; - if (first) { - /* create fake window for our selection ownership, etc */ - selwin = XCreateSimpleWindow(dpy, rootwin, 0, 0, 1, 1, 0, 0, 0); - + if (first && (watch_selection || vnc_connect)) { /* * register desired event(s) for notification. * PropertyChangeMask is for CUT_BUFFER0 changes. * TODO: does this cause a flood of other stuff? */ XSelectInput(dpy, rootwin, PropertyChangeMask); - - starttime = time(0); - - first = 0; } + if (first && watch_selection) { + /* create fake window for our selection ownership, etc */ + selwin = XCreateSimpleWindow(dpy, rootwin, 0, 0, 1, 1, 0, 0, 0); + } + if (first && vnc_connect) { + vnc_connect_str[0] = '\0'; + vnc_connect_prop = XInternAtom(dpy, "VNC_CONNECT", False); + } + first = 0; /* * There is a bug where we have to wait before sending text to * the client... so instead of sending right away we wait a * the few seconds. */ - if (! sent_sel && time(0) > starttime + sel_waittime) { + if (have_clients && watch_selection && ! sent_sel + && now > last_client + sel_waittime) { if (XGetSelectionOwner(dpy, XA_PRIMARY) == None) { cutbuffer_send(); } sent_sel = 1; } - /* check for CUT_BUFFER0 change: */ + /* check for CUT_BUFFER0 and VNC_CONNECT changes: */ if (XCheckTypedEvent(dpy, PropertyNotify, &xev)) { - if (xev.type == PropertyNotify && - xev.xproperty.atom == XA_CUT_BUFFER0) { + if (xev.type == PropertyNotify) { + if (xev.xproperty.atom == XA_CUT_BUFFER0) { + /* + * Go retrieve CUT_BUFFER0 and send it. + * + * set_cutbuffer is a flag to try to avoid + * processing our own cutbuffer changes. + */ + if (have_clients && watch_selection + && ! set_cutbuffer) { + cutbuffer_send(); + sent_sel = 1; + } + set_cutbuffer = 0; + } else if (vnc_connect && vnc_connect_prop != None + && xev.xproperty.atom == vnc_connect_prop) { - /* - * Go retrieve CUT_BUFFER0 and send it. - * - * set_cutbuffer is a flag to try to avoid processing - * our own cutbuffer changes. - */ - if (! set_cutbuffer) { - cutbuffer_send(); - sent_sel = 1; + /* + * Go retrieve VNC_CONNECT string. + */ + read_vnc_connect_prop(); } - set_cutbuffer = 0; } } + if (! have_clients || ! watch_selection) { + /* + * no need to monitor selections if no current clients + * or -nosel. + */ + X_UNLOCK; + return; + } + /* check for our PRIMARY request notification: */ if (watch_primary) { if (XCheckTypedEvent(dpy, SelectionNotify, &xev)) { @@ -1194,20 +1594,20 @@ void watch_selection_event() { xev.xselection.target == XA_STRING) { /* go retrieve PRIMARY and check it */ - if (sent_sel || - time(0) > starttime + sel_waittime) { + if (now > last_client + sel_waittime + || sent_sel) { selection_send(&xev); } } } - if (time(0) > last_request + 1) { + if (now > last_request + 1) { /* * Every second or two, request PRIMARY, unless we * already own it or there is no owner. * TODO: even at this low rate we should look into * and performance problems in odds cases, etc. */ - last_request = time(0); + last_request = now; if (! own_selection && XGetSelectionOwner(dpy, XA_PRIMARY) != None) { XConvertSelection(dpy, XA_PRIMARY, XA_STRING, @@ -3588,15 +3988,14 @@ void watch_loop(void) { clean_up_exit(0); } + watch_xevents(); + check_connect_inputs(); + if (! screen->rfbClientHead) { /* waiting for a client */ usleep(200 * 1000); continue; } - if (watch_selection) { - watch_selection_event(); - } - if (nofb) { /* no framebuffer polling needed */ continue; } @@ -3694,7 +4093,6 @@ int check_user_input(double dt, int *cnt) { * likely they have all be sent already. */ while (1) { - //rfbProcessEvents(screen, 1000); rfbCheckFds(screen, 1000); XFlush(dpy); @@ -3754,7 +4152,6 @@ int check_user_input(double dt, int *cnt) { miss = 0; for (i=0; i<split; i++) { usleep(ms * 1000); - //rfbProcessEvents(screen, 1000); rfbCheckFds(screen, 1000); spin += dtime(&tm); if (got_pointer_input > g) { @@ -3822,6 +4219,12 @@ void print_help() { "-shared VNC display is shared (default %s).\n" "-forever Keep listening for more connections rather than exiting\n" " as soon as the first client(s) disconnect. Same as -many\n" +"-connect string For use with \"vncviewer -listen\" reverse connections. If\n" +" string has the form \"host\" or \"host:port\" the connection\n" +" is made once at startup. Use commas for a list. If string\n" +" contains \"/\" it is a file to periodically check for new\n" +" hosts. The first line is read and then file is truncated.\n" +"-vncconnect Monitor the VNC_CONNECT X property set by vncconnect(1).\n" "-allow addr1[,addr2..] Only allow client connections from IP addresses matching\n" " the comma separated list of numerical addresses. Can be\n" " a prefix, e.g. \"192.168.100.\" to match a simple subnet,\n" @@ -3845,10 +4248,13 @@ void print_help() { "-modtweak Handle AltGr/Shift modifiers for differing languages\n" " between client and host (default %s).\n" "-nomodtweak Send the keysym directly to the X server.\n" +"-remap file Read keysym remappings from file. Format is one pair\n" +" of keysyms per line (can be string or the hex value).\n" "-nobell Do not watch for XBell events.\n" "-nofb Ignore framebuffer: only process keyboard and pointer.\n" "-nosel Do not manage exchange of X selection/cutbuffer.\n" -"-noprimary Exchange X cutbuffer changes but not PRIMARY selection.\n" +"-noprimary Do not poll the PRIMARY selection for changes and send\n" +" back to clients. PRIMARY is set for received changes.\n" "\n" "-nocursor Do not have the viewer show a local cursor.\n" "-mouse Draw a 2nd cursor at the current X pointer position.\n" @@ -3865,6 +4271,8 @@ void print_help() { " read n user input events before scanning display. n < 0\n" " means to act as though there is always user input.\n" "-old_copytile Do not use the new copy_tiles() framebuffer mechanism.\n" +"-debug_pointer Print debugging output for every pointer event.\n" +"-debug_keyboard Print debugging output for every keyboard event.\n" "\n" "-defer time Time in ms to wait for updates before sending to\n" " client [rfbDeferUpdateTime] (default %d).\n" @@ -3959,6 +4367,7 @@ int main(int argc, char** argv) { int i, op, ev, er, maj, min; char *use_dpy = NULL; char *visual_str = NULL; + int pw_loc = -1; int dt = 0; int bg = 0; int got_waitms = 0; @@ -3996,6 +4405,15 @@ int main(int argc, char** argv) { } else if (!strcmp(argv[i], "-many") || !strcmp(argv[i], "-forever")) { connect_once = 0; + } else if (!strcmp(argv[i], "-connect")) { + i++; + if (strchr(argv[i], '/')) { + client_connect_file = argv[i]; + } else { + client_connect = strdup(argv[i]); + } + } else if (!strcmp(argv[i], "-vncconnect")) { + vnc_connect = 1; } else if (!strcmp(argv[i], "-inetd")) { inetd = 1; } else if (!strcmp(argv[i], "-noshm")) { @@ -4006,6 +4424,8 @@ int main(int argc, char** argv) { use_modifier_tweak = 1; } else if (!strcmp(argv[i], "-nomodtweak")) { use_modifier_tweak = 0; + } else if (!strcmp(argv[i], "-remap")) { + remap_file = argv[++i]; } else if (!strcmp(argv[i], "-nobell")) { watch_bell = 0; } else if (!strcmp(argv[i], "-nofb")) { @@ -4036,6 +4456,10 @@ int main(int argc, char** argv) { old_pointer = 1; } else if (!strcmp(argv[i], "-old_copytile")) { single_copytile = 1; + } else if (!strcmp(argv[i], "-debug_pointer")) { + debug_pointer++; + } else if (!strcmp(argv[i], "-debug_keyboard")) { + debug_keyboard++; } else if (!strcmp(argv[i], "-defer")) { defer_update = atoi(argv[++i]); } else if (!strcmp(argv[i], "-wait")) { @@ -4074,13 +4498,33 @@ int main(int argc, char** argv) { if (!strcmp(argv[i], "-desktop")) { dt = 1; } + if (!strcmp(argv[i], "-passwd")) { + pw_loc = i; + } /* otherwise copy it for use below. */ - if (! quiet) { + if (! quiet && i != pw_loc && i != pw_loc+1) { fprintf(stderr, "passing arg to libvncserver: %s\n", argv[i]); } if (argc2 < 100) { - argv2[argc2++] = argv[i]; + argv2[argc2++] = strdup(argv[i]); + } + } + } + + /* + * If -passwd was used, clear it out of argv. This does not + * work on all UNIX, have to use execvp() in general... + */ + if (pw_loc > 0) { + char *p = argv[pw_loc]; + while (*p != '\0') { + *p++ = '\0'; + } + if (pw_loc+1 < argc) { + p = argv[pw_loc+1]; + while (*p != '\0') { + *p++ = '\0'; } } } @@ -4312,7 +4756,10 @@ int main(int argc, char** argv) { set_signals(); if (use_modifier_tweak) { - initialize_keycodes(); + initialize_modtweak(); + } + if (remap_file != NULL) { + initialize_remap(remap_file); } if (screen->rfbPort) { |