summaryrefslogtreecommitdiffstats
path: root/contrib/global/gozilla/remote.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/global/gozilla/remote.c')
-rw-r--r--contrib/global/gozilla/remote.c717
1 files changed, 717 insertions, 0 deletions
diff --git a/contrib/global/gozilla/remote.c b/contrib/global/gozilla/remote.c
new file mode 100644
index 0000000..d2e6a34
--- /dev/null
+++ b/contrib/global/gozilla/remote.c
@@ -0,0 +1,717 @@
+/* -*- Mode:C; tab-width: 8 -*-
+ * remote.c --- remote control of Netscape Navigator for Unix.
+ * version 1.1.3, for Netscape Navigator 1.1 and newer.
+ *
+ * Copyright © 1996 Netscape Communications Corporation, all rights reserved.
+ * Created: Jamie Zawinski <jwz@netscape.com>, 24-Dec-94.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation. No representations are made about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * To compile:
+ *
+ * cc -o netscape-remote remote.c -DSTANDALONE -lXmu -lX11
+ *
+ * To use:
+ *
+ * netscape-remote -help
+ *
+ * Documentation for the protocol which this code implements may be found at:
+ *
+ * http://home.netscape.com/newsref/std/x-remote.html
+ *
+ * Bugs and commentary to x_cbug@netscape.com.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/Xmu/WinUtil.h> /* for XmuClientWindow() */
+
+
+/* vroot.h is a header file which lets a client get along with `virtual root'
+ window managers like swm, tvtwm, olvwm, etc. If you don't have this header
+ file, you can find it at "http://home.netscape.com/newsref/std/vroot.h".
+ If you don't care about supporting virtual root window managers, you can
+ comment this line out.
+ */
+#include "vroot.h"
+
+
+#ifdef STANDALONE
+#ifdef GLOBAL
+ extern char *progname;
+#else
+ static const char *progname = 0;
+#endif
+ static const char *expected_mozilla_version = "1.1";
+#else /* !STANDALONE */
+ extern const char *progname;
+ extern const char *expected_mozilla_version;
+#endif /* !STANDALONE */
+
+#define MOZILLA_VERSION_PROP "_MOZILLA_VERSION"
+#define MOZILLA_LOCK_PROP "_MOZILLA_LOCK"
+#define MOZILLA_COMMAND_PROP "_MOZILLA_COMMAND"
+#define MOZILLA_RESPONSE_PROP "_MOZILLA_RESPONSE"
+static Atom XA_MOZILLA_VERSION = 0;
+static Atom XA_MOZILLA_LOCK = 0;
+static Atom XA_MOZILLA_COMMAND = 0;
+static Atom XA_MOZILLA_RESPONSE = 0;
+
+static void
+mozilla_remote_init_atoms (Display *dpy)
+{
+ if (! XA_MOZILLA_VERSION)
+ XA_MOZILLA_VERSION = XInternAtom (dpy, MOZILLA_VERSION_PROP, False);
+ if (! XA_MOZILLA_LOCK)
+ XA_MOZILLA_LOCK = XInternAtom (dpy, MOZILLA_LOCK_PROP, False);
+ if (! XA_MOZILLA_COMMAND)
+ XA_MOZILLA_COMMAND = XInternAtom (dpy, MOZILLA_COMMAND_PROP, False);
+ if (! XA_MOZILLA_RESPONSE)
+ XA_MOZILLA_RESPONSE = XInternAtom (dpy, MOZILLA_RESPONSE_PROP, False);
+}
+
+static Window
+mozilla_remote_find_window (Display *dpy)
+{
+ int i;
+ Window root = RootWindowOfScreen (DefaultScreenOfDisplay (dpy));
+ Window root2, parent, *kids;
+ unsigned int nkids;
+ Window result = 0;
+ Window tenative = 0;
+ unsigned char *tenative_version = 0;
+
+ if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
+ {
+ fprintf (stderr, "%s: XQueryTree failed on display %s\n", progname,
+ DisplayString (dpy));
+ exit (2);
+ }
+
+ /* root != root2 is possible with virtual root WMs. */
+
+ if (! (kids && nkids))
+ {
+ fprintf (stderr, "%s: root window has no children on display %s\n",
+ progname, DisplayString (dpy));
+ exit (2);
+ }
+
+ for (i = nkids-1; i >= 0; i--)
+ {
+ Atom type;
+ int format;
+ unsigned long nitems, bytesafter;
+ unsigned char *version = 0;
+ Window w = XmuClientWindow (dpy, kids[i]);
+ int status = XGetWindowProperty (dpy, w, XA_MOZILLA_VERSION,
+ 0, (65536 / sizeof (long)),
+ False, XA_STRING,
+ &type, &format, &nitems, &bytesafter,
+ &version);
+ if (! version)
+ continue;
+ if (strcmp ((char *) version, expected_mozilla_version) &&
+ !tenative)
+ {
+ tenative = w;
+ tenative_version = version;
+ continue;
+ }
+ XFree (version);
+ if (status == Success && type != None)
+ {
+ result = w;
+ break;
+ }
+ }
+
+ if (result && tenative)
+ {
+#ifndef GLOBAL
+ fprintf (stderr,
+ "%s: warning: both version %s (0x%x) and version\n"
+ "\t%s (0x%x) are running. Using version %s.\n",
+ progname, tenative_version, (unsigned int) tenative,
+ expected_mozilla_version, (unsigned int) result,
+ expected_mozilla_version);
+#endif
+ XFree (tenative_version);
+ return result;
+ }
+ else if (tenative)
+ {
+#ifndef GLOBAL
+ fprintf (stderr,
+ "%s: warning: expected version %s but found version\n"
+ "\t%s (0x%x) instead.\n",
+ progname, expected_mozilla_version,
+ tenative_version, (unsigned int) tenative);
+#endif
+ XFree (tenative_version);
+ return tenative;
+ }
+ else if (result)
+ {
+ return result;
+ }
+ else
+ {
+#ifdef GLOBAL
+ return 0;
+#else
+ fprintf (stderr, "%s: not running on display %s\n", progname,
+ DisplayString (dpy));
+ exit (1);
+#endif
+ }
+}
+
+static void
+mozilla_remote_check_window (Display *dpy, Window window)
+{
+ Atom type;
+ int format;
+ unsigned long nitems, bytesafter;
+ unsigned char *version = 0;
+ int status = XGetWindowProperty (dpy, window, XA_MOZILLA_VERSION,
+ 0, (65536 / sizeof (long)),
+ False, XA_STRING,
+ &type, &format, &nitems, &bytesafter,
+ &version);
+ if (status != Success || !version)
+ {
+ fprintf (stderr, "%s: window 0x%x is not a Netscape window.\n",
+ progname, (unsigned int) window);
+ exit (6);
+ }
+ else if (strcmp ((char *) version, expected_mozilla_version))
+ {
+ fprintf (stderr,
+ "%s: warning: window 0x%x is Netscape version %s;\n"
+ "\texpected version %s.\n",
+ progname, (unsigned int) window,
+ version, expected_mozilla_version);
+ }
+ XFree (version);
+}
+
+
+static char *lock_data = 0;
+
+static void
+mozilla_remote_obtain_lock (Display *dpy, Window window)
+{
+ Bool locked = False;
+ Bool waited = False;
+
+ if (! lock_data)
+ {
+ lock_data = (char *) malloc (255);
+ sprintf (lock_data, "pid%d@", getpid ());
+ if (gethostname (lock_data + strlen (lock_data), 100))
+ {
+ perror ("gethostname");
+ exit (-1);
+ }
+ }
+
+ do
+ {
+ int result;
+ Atom actual_type;
+ int actual_format;
+ unsigned long nitems, bytes_after;
+ unsigned char *data = 0;
+
+ XGrabServer (dpy); /* ################################# DANGER! */
+
+ result = XGetWindowProperty (dpy, window, XA_MOZILLA_LOCK,
+ 0, (65536 / sizeof (long)),
+ False, /* don't delete */
+ XA_STRING,
+ &actual_type, &actual_format,
+ &nitems, &bytes_after,
+ &data);
+ if (result != Success || actual_type == None)
+ {
+ /* It's not now locked - lock it. */
+#ifdef DEBUG_PROPS
+ fprintf (stderr, "%s: (writing " MOZILLA_LOCK_PROP
+ " \"%s\" to 0x%x)\n",
+ progname, lock_data, (unsigned int) window);
+#endif
+ XChangeProperty (dpy, window, XA_MOZILLA_LOCK, XA_STRING, 8,
+ PropModeReplace, (unsigned char *) lock_data,
+ strlen (lock_data));
+ locked = True;
+ }
+
+ XUngrabServer (dpy); /* ################################# danger over */
+ XSync (dpy, False);
+
+ if (! locked)
+ {
+ /* We tried to grab the lock this time, and failed because someone
+ else is holding it already. So, wait for a PropertyDelete event
+ to come in, and try again. */
+
+ fprintf (stderr, "%s: window 0x%x is locked by %s; waiting...\n",
+ progname, (unsigned int) window, data);
+ waited = True;
+
+ while (1)
+ {
+ XEvent event;
+ XNextEvent (dpy, &event);
+ if (event.xany.type == DestroyNotify &&
+ event.xdestroywindow.window == window)
+ {
+ fprintf (stderr, "%s: window 0x%x unexpectedly destroyed.\n",
+ progname, (unsigned int) window);
+ exit (6);
+ }
+ else if (event.xany.type == PropertyNotify &&
+ event.xproperty.state == PropertyDelete &&
+ event.xproperty.window == window &&
+ event.xproperty.atom == XA_MOZILLA_LOCK)
+ {
+ /* Ok! Someone deleted their lock, so now we can try
+ again. */
+#ifdef DEBUG_PROPS
+ fprintf (stderr, "%s: (0x%x unlocked, trying again...)\n",
+ progname, (unsigned int) window);
+#endif
+ break;
+ }
+ }
+ }
+ if (data)
+ XFree (data);
+ }
+ while (! locked);
+
+ if (waited)
+ fprintf (stderr, "%s: obtained lock.\n", progname);
+}
+
+
+static void
+mozilla_remote_free_lock (Display *dpy, Window window)
+{
+ int result;
+ Atom actual_type;
+ int actual_format;
+ unsigned long nitems, bytes_after;
+ unsigned char *data = 0;
+
+#ifdef DEBUG_PROPS
+ fprintf (stderr, "%s: (deleting " MOZILLA_LOCK_PROP
+ " \"%s\" from 0x%x)\n",
+ progname, lock_data, (unsigned int) window);
+#endif
+
+ result = XGetWindowProperty (dpy, window, XA_MOZILLA_LOCK,
+ 0, (65536 / sizeof (long)),
+ True, /* atomic delete after */
+ XA_STRING,
+ &actual_type, &actual_format,
+ &nitems, &bytes_after,
+ &data);
+ if (result != Success)
+ {
+ fprintf (stderr, "%s: unable to read and delete " MOZILLA_LOCK_PROP
+ " property\n",
+ progname);
+ return;
+ }
+ else if (!data || !*data)
+ {
+ fprintf (stderr, "%s: invalid data on " MOZILLA_LOCK_PROP
+ " of window 0x%x.\n",
+ progname, (unsigned int) window);
+ return;
+ }
+ else if (strcmp ((char *) data, lock_data))
+ {
+ fprintf (stderr, "%s: " MOZILLA_LOCK_PROP
+ " was stolen! Expected \"%s\", saw \"%s\"!\n",
+ progname, lock_data, data);
+ return;
+ }
+
+ if (data)
+ XFree (data);
+}
+
+
+static int
+mozilla_remote_command (Display *dpy, Window window, const char *command,
+ Bool raise_p)
+{
+ int result;
+ Bool done = False;
+ char *new_command = 0;
+
+ /* The -noraise option is implemented by passing a "noraise" argument
+ to each command to which it should apply.
+ */
+ if (! raise_p)
+ {
+ char *close;
+ new_command = (char *) malloc (strlen (command) + 20);
+ strcpy (new_command, command);
+ close = strrchr (new_command, ')');
+ if (close)
+ strcpy (close, ", noraise)");
+ else
+ strcat (new_command, "(noraise)");
+ command = new_command;
+ }
+
+#ifdef DEBUG_PROPS
+ fprintf (stderr, "%s: (writing " MOZILLA_COMMAND_PROP " \"%s\" to 0x%x)\n",
+ progname, command, (unsigned int) window);
+#endif
+
+ XChangeProperty (dpy, window, XA_MOZILLA_COMMAND, XA_STRING, 8,
+ PropModeReplace, (unsigned char *) command,
+ strlen (command));
+
+ while (!done)
+ {
+ XEvent event;
+ XNextEvent (dpy, &event);
+ if (event.xany.type == DestroyNotify &&
+ event.xdestroywindow.window == window)
+ {
+ /* Print to warn user...*/
+ fprintf (stderr, "%s: window 0x%x was destroyed.\n",
+ progname, (unsigned int) window);
+ result = 6;
+ goto DONE;
+ }
+ else if (event.xany.type == PropertyNotify &&
+ event.xproperty.state == PropertyNewValue &&
+ event.xproperty.window == window &&
+ event.xproperty.atom == XA_MOZILLA_RESPONSE)
+ {
+ Atom actual_type;
+ int actual_format;
+ unsigned long nitems, bytes_after;
+ unsigned char *data = 0;
+
+ result = XGetWindowProperty (dpy, window, XA_MOZILLA_RESPONSE,
+ 0, (65536 / sizeof (long)),
+ True, /* atomic delete after */
+ XA_STRING,
+ &actual_type, &actual_format,
+ &nitems, &bytes_after,
+ &data);
+#ifdef DEBUG_PROPS
+ if (result == Success && data && *data)
+ {
+ fprintf (stderr, "%s: (server sent " MOZILLA_RESPONSE_PROP
+ " \"%s\" to 0x%x.)\n",
+ progname, data, (unsigned int) window);
+ }
+#endif
+
+ if (result != Success)
+ {
+ fprintf (stderr, "%s: failed reading " MOZILLA_RESPONSE_PROP
+ " from window 0x%0x.\n",
+ progname, (unsigned int) window);
+ result = 6;
+ done = True;
+ }
+ else if (!data || strlen((char *) data) < 5)
+ {
+ fprintf (stderr, "%s: invalid data on " MOZILLA_RESPONSE_PROP
+ " property of window 0x%0x.\n",
+ progname, (unsigned int) window);
+ result = 6;
+ done = True;
+ }
+ else if (*data == '1') /* positive preliminary reply */
+ {
+ fprintf (stderr, "%s: %s\n", progname, data + 4);
+ /* keep going */
+ done = False;
+ }
+#if 1
+ else if (!strncmp ((char *)data, "200", 3)) /* positive completion */
+ {
+ result = 0;
+ done = True;
+ }
+#endif
+ else if (*data == '2') /* positive completion */
+ {
+ fprintf (stderr, "%s: %s\n", progname, data + 4);
+ result = 0;
+ done = True;
+ }
+ else if (*data == '3') /* positive intermediate reply */
+ {
+ fprintf (stderr, "%s: internal error: "
+ "server wants more information? (%s)\n",
+ progname, data);
+ result = 3;
+ done = True;
+ }
+ else if (*data == '4' || /* transient negative completion */
+ *data == '5') /* permanent negative completion */
+ {
+ fprintf (stderr, "%s: %s\n", progname, data + 4);
+ result = (*data - '0');
+ done = True;
+ }
+ else
+ {
+ fprintf (stderr,
+ "%s: unrecognised " MOZILLA_RESPONSE_PROP
+ " from window 0x%x: %s\n",
+ progname, (unsigned int) window, data);
+ result = 6;
+ done = True;
+ }
+
+ if (data)
+ XFree (data);
+ }
+#ifdef DEBUG_PROPS
+ else if (event.xany.type == PropertyNotify &&
+ event.xproperty.window == window &&
+ event.xproperty.state == PropertyDelete &&
+ event.xproperty.atom == XA_MOZILLA_COMMAND)
+ {
+ fprintf (stderr, "%s: (server 0x%x has accepted "
+ MOZILLA_COMMAND_PROP ".)\n",
+ progname, (unsigned int) window);
+ }
+#endif /* DEBUG_PROPS */
+ }
+
+ DONE:
+
+ if (new_command)
+ free (new_command);
+
+ return result;
+}
+
+int
+mozilla_remote_commands (Display *dpy, Window window, char **commands)
+{
+ Bool raise_p = True;
+ int status = 0;
+ mozilla_remote_init_atoms (dpy);
+
+ if (window == 0)
+ window = mozilla_remote_find_window (dpy);
+ else
+ mozilla_remote_check_window (dpy, window);
+#ifdef GLOBAL
+ if (window == 0)
+ return -1;
+#endif
+
+ XSelectInput (dpy, window, (PropertyChangeMask|StructureNotifyMask));
+
+ mozilla_remote_obtain_lock (dpy, window);
+
+ while (*commands)
+ {
+ if (!strcmp (*commands, "-raise"))
+ raise_p = True;
+ else if (!strcmp (*commands, "-noraise"))
+ raise_p = False;
+ else
+ status = mozilla_remote_command (dpy, window, *commands, raise_p);
+
+ if (status != 0)
+ break;
+ commands++;
+ }
+
+ /* When status = 6, it means the window has been destroyed */
+ /* It is invalid to free the lock when window is destroyed. */
+
+ if ( status != 6 )
+ mozilla_remote_free_lock (dpy, window);
+
+ return status;
+}
+
+
+#ifdef STANDALONE
+
+static void
+usage (void)
+{
+ fprintf (stderr, "usage: %s [ options ... ]\n\
+ where options include:\n\
+\n\
+ -help to show this message.\n\
+ -display <dpy> to specify the X server to use.\n\
+ -remote <remote-command> to execute a command in an already-running\n\
+ Netscape process. See the manual for a\n\
+ list of valid commands.\n\
+ -id <window-id> the id of an X window to which the -remote\n\
+ commands should be sent; if unspecified,\n\
+ the first window found will be used.\n\
+ -raise whether following -remote commands should\n\
+ cause the window to raise itself to the top\n\
+ (this is the default.)\n\
+ -noraise the opposite of -raise: following -remote\n\
+ commands will not auto-raise the window.\n\
+",
+ progname);
+}
+
+
+#ifdef GLOBAL
+int
+netscape_remote(int argc, char **argv)
+#else
+void
+main (int argc, char **argv)
+#endif
+{
+ Display *dpy;
+ char *dpy_string = 0;
+ char **remote_commands = 0;
+ int remote_command_count = 0;
+ int remote_command_size = 0;
+ unsigned long remote_window = 0;
+ Bool sync_p = False;
+ int i;
+
+ progname = strrchr (argv[0], '/');
+ if (progname)
+ progname++;
+ else
+ progname = argv[0];
+
+ /* Hack the -help and -version arguments before opening the display. */
+ for (i = 1; i < argc; i++)
+ {
+ if (!strcasecmp (argv [i], "-h") ||
+ !strcasecmp (argv [i], "-help"))
+ {
+ usage ();
+ exit (0);
+ }
+ else if (!strcmp (argv [i], "-d") ||
+ !strcmp (argv [i], "-dpy") ||
+ !strcmp (argv [i], "-disp") ||
+ !strcmp (argv [i], "-display"))
+ {
+ i++;
+ dpy_string = argv [i];
+ }
+ else if (!strcmp (argv [i], "-sync") ||
+ !strcmp (argv [i], "-synchronize"))
+ {
+ sync_p = True;
+ }
+ else if (!strcmp (argv [i], "-remote"))
+ {
+ if (remote_command_count == remote_command_size)
+ {
+ remote_command_size += 20;
+ remote_commands =
+ (remote_commands
+ ? realloc (remote_commands,
+ remote_command_size * sizeof (char *))
+ : calloc (remote_command_size, sizeof (char *)));
+ }
+ i++;
+ if (!argv[i] || *argv[i] == '-' || *argv[i] == 0)
+ {
+ fprintf (stderr, "%s: invalid `-remote' option \"%s\"\n",
+ progname, argv[i] ? argv[i] : "");
+ usage ();
+ exit (-1);
+ }
+ remote_commands [remote_command_count++] = argv[i];
+ }
+ else if (!strcmp (argv [i], "-raise") ||
+ !strcmp (argv [i], "-noraise"))
+ {
+ char *r = argv [i];
+ if (remote_command_count == remote_command_size)
+ {
+ remote_command_size += 20;
+ remote_commands =
+ (remote_commands
+ ? realloc (remote_commands,
+ remote_command_size * sizeof (char *))
+ : calloc (remote_command_size, sizeof (char *)));
+ }
+ remote_commands [remote_command_count++] = r;
+ }
+ else if (!strcmp (argv [i], "-id"))
+ {
+ char c;
+ if (remote_command_count > 0)
+ {
+ fprintf (stderr,
+ "%s: the `-id' option must preceed all `-remote' options.\n",
+ progname);
+ usage ();
+ exit (-1);
+ }
+ else if (remote_window != 0)
+ {
+ fprintf (stderr, "%s: only one `-id' option may be used.\n",
+ progname);
+ usage ();
+ exit (-1);
+ }
+ i++;
+ if (argv[i] &&
+ 1 == sscanf (argv[i], " %ld %c", &remote_window, &c))
+ ;
+ else if (argv[i] &&
+ 1 == sscanf (argv[i], " 0x%lx %c", &remote_window, &c))
+ ;
+ else
+ {
+ fprintf (stderr, "%s: invalid `-id' option \"%s\"\n",
+ progname, argv[i] ? argv[i] : "");
+ usage ();
+ exit (-1);
+ }
+ }
+ }
+
+ dpy = XOpenDisplay (dpy_string);
+ if (! dpy)
+ exit (-1);
+
+ if (sync_p)
+ XSynchronize (dpy, True);
+
+#ifdef GLOBAL
+ return mozilla_remote_commands (dpy, (Window) remote_window,
+ remote_commands);
+#else
+ exit (mozilla_remote_commands (dpy, (Window) remote_window,
+ remote_commands));
+#endif
+}
+
+#endif /* STANDALONE */
OpenPOWER on IntegriCloud