home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / xfe / remote.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  19.6 KB  |  721 lines

  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18. /* */
  19. /**/
  20.  
  21. #ifdef NON_SOURCE_RELEASE
  22. /*
  23.      WARNING WARNING WARNING!
  24.      ========================
  25.  
  26.      This file is the same as our remote control reference implementation.
  27.  
  28.      That means that it must compile standalone as per the instructions
  29.      below.  That means that this code can't depend on any of the private,
  30.      internal Netscape libraries: only libc and libX11.
  31.  
  32.      That means that if you make any changes to this file, you must also
  33.      update "http://home.netscape.com/newsref/std/remote.c".  Also, tick
  34.      the minor-minor version number, below.
  35. */
  36. #endif
  37.  
  38. /*
  39.  * remote.c --- remote control of Netscape Navigator for Unix.
  40.  * version 1.1.3, for Netscape Navigator 1.1 and newer.
  41.  *
  42.  * Created: Jamie Zawinski <jwz@netscape.com>, 24-Dec-94.
  43.  *
  44.  * To compile:
  45.  *
  46.  *    cc -o netscape-remote remote.c -DSTANDALONE -lXmu -lX11
  47.  *
  48.  * To use:
  49.  *
  50.  *    netscape-remote -help
  51.  *
  52.  * Documentation for the protocol which this code implements may be found at:
  53.  *
  54.  *    http://home.netscape.com/newsref/std/x-remote.html
  55.  *
  56.  * Bugs and commentary to x_cbug@netscape.com.
  57.  */
  58.  
  59.  
  60. #include <stdio.h>
  61. #include <stdlib.h>
  62. #include <unistd.h>
  63. #include <string.h>
  64.  
  65. #include <X11/Xlib.h>
  66. #include <X11/Xatom.h>
  67. #include <X11/Xmu/WinUtil.h>    /* for XmuClientWindow() */
  68.  
  69.  
  70. /* vroot.h is a header file which lets a client get along with `virtual root'
  71.    window managers like swm, tvtwm, olvwm, etc.  If you don't have this header
  72.    file, you can find it at "http://home.netscape.com/newsref/std/vroot.h".
  73.    If you don't care about supporting virtual root window managers, you can
  74.    comment this line out.
  75.  */
  76. #include "vroot.h"
  77.  
  78.  
  79. #ifdef STANDALONE
  80.  static const char *progname = 0;
  81.  static const char *expected_mozilla_version = "1.1";
  82. #else  /* !STANDALONE */
  83.  extern const char *progname;
  84.  extern const char *expected_mozilla_version;
  85. #endif /* !STANDALONE */
  86.  
  87. #define MOZILLA_VERSION_PROP   "_MOZILLA_VERSION"
  88. #define MOZILLA_LOCK_PROP      "_MOZILLA_LOCK"
  89. #define MOZILLA_COMMAND_PROP   "_MOZILLA_COMMAND"
  90. #define MOZILLA_RESPONSE_PROP  "_MOZILLA_RESPONSE"
  91. static Atom XA_MOZILLA_VERSION  = 0;
  92. static Atom XA_MOZILLA_LOCK     = 0;
  93. static Atom XA_MOZILLA_COMMAND  = 0;
  94. static Atom XA_MOZILLA_RESPONSE = 0;
  95.  
  96. static void
  97. mozilla_remote_init_atoms (Display *dpy)
  98. {
  99.   if (! XA_MOZILLA_VERSION)
  100.     XA_MOZILLA_VERSION = XInternAtom (dpy, MOZILLA_VERSION_PROP, False);
  101.   if (! XA_MOZILLA_LOCK)
  102.     XA_MOZILLA_LOCK = XInternAtom (dpy, MOZILLA_LOCK_PROP, False);
  103.   if (! XA_MOZILLA_COMMAND)
  104.     XA_MOZILLA_COMMAND = XInternAtom (dpy, MOZILLA_COMMAND_PROP, False);
  105.   if (! XA_MOZILLA_RESPONSE)
  106.     XA_MOZILLA_RESPONSE = XInternAtom (dpy, MOZILLA_RESPONSE_PROP, False);
  107. }
  108.  
  109. static Window
  110. mozilla_remote_find_window (Display *dpy)
  111. {
  112.   int i;
  113.   Window root = RootWindowOfScreen (DefaultScreenOfDisplay (dpy));
  114.   Window root2, parent, *kids;
  115.   unsigned int nkids;
  116.   Window result = 0;
  117.   Window tenative = 0;
  118.   unsigned char *tenative_version = 0;
  119.  
  120.   if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
  121.     {
  122.       fprintf (stderr, "%s: XQueryTree failed on display %s\n", progname,
  123.            DisplayString (dpy));
  124.       exit (2);
  125.     }
  126.  
  127.   /* root != root2 is possible with virtual root WMs. */
  128.  
  129.   if (! (kids && nkids))
  130.     {
  131.       fprintf (stderr, "%s: root window has no children on display %s\n",
  132.            progname, DisplayString (dpy));
  133.       exit (2);
  134.     }
  135.  
  136.   for (i = nkids-1; i >= 0; i--)
  137.     {
  138.       Atom type;
  139.       int format;
  140.       unsigned long nitems, bytesafter;
  141.       unsigned char *version = 0;
  142.       Window w = XmuClientWindow (dpy, kids[i]);
  143.       int status = XGetWindowProperty (dpy, w, XA_MOZILLA_VERSION,
  144.                        0, (65536 / sizeof (long)),
  145.                        False, XA_STRING,
  146.                        &type, &format, &nitems, &bytesafter,
  147.                        &version);
  148.       if (! version)
  149.     continue;
  150.       if (strcmp ((char *) version, expected_mozilla_version) &&
  151.       !tenative)
  152.     {
  153.       tenative = w;
  154.       tenative_version = version;
  155.       continue;
  156.     }
  157.       XFree (version);
  158.       if (status == Success && type != None)
  159.     {
  160.       result = w;
  161.       break;
  162.     }
  163.     }
  164.  
  165.   if (result && tenative)
  166.     {
  167.       fprintf (stderr,
  168.            "%s: warning: both version %s (0x%x) and version\n"
  169.            "\t%s (0x%x) are running.  Using version %s.\n",
  170.            progname, tenative_version, (unsigned int) tenative,
  171.            expected_mozilla_version, (unsigned int) result,
  172.            expected_mozilla_version);
  173.       XFree (tenative_version);
  174.       return result;
  175.     }
  176.   else if (tenative)
  177.     {
  178.       fprintf (stderr,
  179.            "%s: warning: expected version %s but found version\n"
  180.            "\t%s (0x%x) instead.\n",
  181.            progname, expected_mozilla_version,
  182.            tenative_version, (unsigned int) tenative);
  183.       XFree (tenative_version);
  184.       return tenative;
  185.     }
  186.   else if (result)
  187.     {
  188.       return result;
  189.     }
  190.   else
  191.     {
  192.       fprintf (stderr, "%s: not running on display %s\n", progname,
  193.            DisplayString (dpy));
  194.       exit (1);
  195.     }
  196. }
  197.  
  198. static void
  199. mozilla_remote_check_window (Display *dpy, Window window)
  200. {
  201.   Atom type;
  202.   int format;
  203.   unsigned long nitems, bytesafter;
  204.   unsigned char *version = 0;
  205.   int status = XGetWindowProperty (dpy, window, XA_MOZILLA_VERSION,
  206.                    0, (65536 / sizeof (long)),
  207.                    False, XA_STRING,
  208.                    &type, &format, &nitems, &bytesafter,
  209.                    &version);
  210.   if (status != Success || !version)
  211.     {
  212.       fprintf (stderr, "%s: window 0x%x is not a Netscape window.\n",
  213.            progname, (unsigned int) window);
  214.       exit (6);
  215.     }
  216.   else if (strcmp ((char *) version, expected_mozilla_version))
  217.     {
  218.       fprintf (stderr,
  219.            "%s: warning: window 0x%x is Netscape version %s;\n"
  220.            "\texpected version %s.\n",
  221.            progname, (unsigned int) window,
  222.            version, expected_mozilla_version);
  223.     }
  224.   XFree (version);
  225. }
  226.  
  227.  
  228. static char *lock_data = 0;
  229.  
  230. static void
  231. mozilla_remote_obtain_lock (Display *dpy, Window window)
  232. {
  233.   Bool locked = False;
  234.   Bool waited = False;
  235.  
  236.   if (! lock_data)
  237.     {
  238.       lock_data = (char *) malloc (255);
  239.       sprintf (lock_data, "pid%d@", getpid ());
  240.       if (gethostname (lock_data + strlen (lock_data), 100))
  241.     {
  242.       perror ("gethostname");
  243.       exit (-1);
  244.     }
  245.     }
  246.  
  247.   do
  248.     {
  249.       int result;
  250.       Atom actual_type;
  251.       int actual_format;
  252.       unsigned long nitems, bytes_after;
  253.       unsigned char *data = 0;
  254.  
  255.       XGrabServer (dpy);   /* ################################# DANGER! */
  256.  
  257.       result = XGetWindowProperty (dpy, window, XA_MOZILLA_LOCK,
  258.                    0, (65536 / sizeof (long)),
  259.                    False, /* don't delete */
  260.                    XA_STRING,
  261.                    &actual_type, &actual_format,
  262.                    &nitems, &bytes_after,
  263.                    &data);
  264.       if (result != Success || actual_type == None)
  265.     {
  266.       /* It's not now locked - lock it. */
  267. #ifdef DEBUG_PROPS
  268.       fprintf (stderr, "%s: (writing " MOZILLA_LOCK_PROP
  269.            " \"%s\" to 0x%x)\n",
  270.            progname, lock_data, (unsigned int) window);
  271. #endif
  272.       XChangeProperty (dpy, window, XA_MOZILLA_LOCK, XA_STRING, 8,
  273.                PropModeReplace, (unsigned char *) lock_data,
  274.                strlen (lock_data));
  275.       locked = True;
  276.     }
  277.  
  278.       XUngrabServer (dpy); /* ################################# danger over */
  279.       XSync (dpy, False);
  280.  
  281.       if (! locked)
  282.     {
  283.       /* We tried to grab the lock this time, and failed because someone
  284.          else is holding it already.  So, wait for a PropertyDelete event
  285.          to come in, and try again. */
  286.  
  287.       fprintf (stderr, "%s: window 0x%x is locked by %s; waiting...\n",
  288.            progname, (unsigned int) window, data);
  289.       waited = True;
  290.  
  291.       while (1)
  292.         {
  293.           XEvent event;
  294.           XNextEvent (dpy, &event);
  295.           if (event.xany.type == DestroyNotify &&
  296.           event.xdestroywindow.window == window)
  297.         {
  298.           fprintf (stderr, "%s: window 0x%x unexpectedly destroyed.\n",
  299.                progname, (unsigned int) window);
  300.           exit (6);
  301.         }
  302.           else if (event.xany.type == PropertyNotify &&
  303.                event.xproperty.state == PropertyDelete &&
  304.                event.xproperty.window == window &&
  305.                event.xproperty.atom == XA_MOZILLA_LOCK)
  306.         {
  307.           /* Ok!  Someone deleted their lock, so now we can try
  308.              again. */
  309. #ifdef DEBUG_PROPS
  310.           fprintf (stderr, "%s: (0x%x unlocked, trying again...)\n",
  311.                progname, (unsigned int) window);
  312. #endif
  313.           break;
  314.         }
  315.         }
  316.     }
  317.       if (data)
  318.     XFree (data);
  319.     }
  320.   while (! locked);
  321.  
  322.   if (waited)
  323.     fprintf (stderr, "%s: obtained lock.\n", progname);
  324. }
  325.  
  326.  
  327. static void
  328. mozilla_remote_free_lock (Display *dpy, Window window)
  329. {
  330.   int result;
  331.   Atom actual_type;
  332.   int actual_format;
  333.   unsigned long nitems, bytes_after;
  334.   unsigned char *data = 0;
  335.  
  336. #ifdef DEBUG_PROPS
  337.       fprintf (stderr, "%s: (deleting " MOZILLA_LOCK_PROP
  338.            " \"%s\" from 0x%x)\n",
  339.            progname, lock_data, (unsigned int) window);
  340. #endif
  341.  
  342.   result = XGetWindowProperty (dpy, window, XA_MOZILLA_LOCK,
  343.                    0, (65536 / sizeof (long)),
  344.                    True, /* atomic delete after */
  345.                    XA_STRING,
  346.                    &actual_type, &actual_format,
  347.                    &nitems, &bytes_after,
  348.                    &data);
  349.   if (result != Success)
  350.     {
  351.       fprintf (stderr, "%s: unable to read and delete " MOZILLA_LOCK_PROP
  352.            " property\n",
  353.            progname);
  354.       return;
  355.     }
  356.   else if (!data || !*data)
  357.     {
  358.       fprintf (stderr, "%s: invalid data on " MOZILLA_LOCK_PROP
  359.            " of window 0x%x.\n",
  360.            progname, (unsigned int) window);
  361.       return;
  362.     }
  363.   else if (strcmp ((char *) data, lock_data))
  364.     {
  365.       fprintf (stderr, "%s: " MOZILLA_LOCK_PROP
  366.            " was stolen!  Expected \"%s\", saw \"%s\"!\n",
  367.            progname, lock_data, data);
  368.       return;
  369.     }
  370.  
  371.   if (data)
  372.     XFree (data);
  373. }
  374.  
  375.  
  376. static int
  377. mozilla_remote_command (Display *dpy, Window window, const char *command,
  378.             Bool raise_p)
  379. {
  380.   int result = 6;
  381.   Bool done = False;
  382.   char *new_command = 0;
  383.  
  384.   /* The -noraise option is implemented by passing a "noraise" argument
  385.      to each command to which it should apply.
  386.    */
  387.   if (! raise_p)
  388.     {
  389.       char *close;
  390.       new_command = (char *) malloc (strlen (command) + 20);
  391.       strcpy (new_command, command);
  392.       close = strrchr (new_command, ')');
  393.       if (close)
  394.     strcpy (close, ", noraise)");
  395.       else
  396.     strcat (new_command, "(noraise)");
  397.       command = new_command;
  398.     }
  399.  
  400. #ifdef DEBUG_PROPS
  401.   fprintf (stderr, "%s: (writing " MOZILLA_COMMAND_PROP " \"%s\" to 0x%x)\n",
  402.        progname, command, (unsigned int) window);
  403. #endif
  404.  
  405.   XChangeProperty (dpy, window, XA_MOZILLA_COMMAND, XA_STRING, 8,
  406.            PropModeReplace, (unsigned char *) command,
  407.            strlen (command));
  408.  
  409.   while (!done)
  410.     {
  411.       XEvent event;
  412.       XNextEvent (dpy, &event);
  413.       if (event.xany.type == DestroyNotify &&
  414.       event.xdestroywindow.window == window)
  415.     {
  416.       /* Print to warn user...*/
  417.       fprintf (stderr, "%s: window 0x%x was destroyed.\n",
  418.            progname, (unsigned int) window);
  419.       result = 6;
  420.       goto DONE;
  421.     }
  422.       else if (event.xany.type == PropertyNotify &&
  423.            event.xproperty.state == PropertyNewValue &&
  424.            event.xproperty.window == window &&
  425.            event.xproperty.atom == XA_MOZILLA_RESPONSE)
  426.     {
  427.       Atom actual_type;
  428.       int actual_format;
  429.       unsigned long nitems, bytes_after;
  430.       unsigned char *data = 0;
  431.  
  432.       result = XGetWindowProperty (dpy, window, XA_MOZILLA_RESPONSE,
  433.                        0, (65536 / sizeof (long)),
  434.                        True, /* atomic delete after */
  435.                        XA_STRING,
  436.                        &actual_type, &actual_format,
  437.                        &nitems, &bytes_after,
  438.                        &data);
  439. #ifdef DEBUG_PROPS
  440.       if (result == Success && data && *data)
  441.         {
  442.           fprintf (stderr, "%s: (server sent " MOZILLA_RESPONSE_PROP
  443.                " \"%s\" to 0x%x.)\n",
  444.                progname, data, (unsigned int) window);
  445.         }
  446. #endif
  447.  
  448.       if (result != Success)
  449.         {
  450.           fprintf (stderr, "%s: failed reading " MOZILLA_RESPONSE_PROP
  451.                " from window 0x%0x.\n",
  452.                progname, (unsigned int) window);
  453.           result = 6;
  454.           done = True;
  455.         }
  456.       else if (!data || strlen((char *) data) < 5)
  457.         {
  458.           fprintf (stderr, "%s: invalid data on " MOZILLA_RESPONSE_PROP
  459.                " property of window 0x%0x.\n",
  460.                progname, (unsigned int) window);
  461.           result = 6;
  462.           done = True;
  463.         }
  464.       else if (*data == '1')    /* positive preliminary reply */
  465.         {
  466.           fprintf (stderr, "%s: %s\n", progname, data + 4);
  467.           /* keep going */
  468.           done = False;
  469.         }
  470. #if 1
  471.       else if (!strncmp ((char *)data, "200", 3)) /* positive completion */
  472.         {
  473.           result = 0;
  474.           done = True;
  475.         }
  476. #endif
  477.       else if (*data == '2')        /* positive completion */
  478.         {
  479.           fprintf (stderr, "%s: %s\n", progname, data + 4);
  480.           result = 0;
  481.           done = True;
  482.         }
  483.       else if (*data == '3')    /* positive intermediate reply */
  484.         {
  485.           fprintf (stderr, "%s: internal error: "
  486.                "server wants more information?  (%s)\n",
  487.                progname, data);
  488.           result = 3;
  489.           done = True;
  490.         }
  491.       else if (*data == '4' ||    /* transient negative completion */
  492.            *data == '5')    /* permanent negative completion */
  493.         {
  494.           fprintf (stderr, "%s: %s\n", progname, data + 4);
  495.           result = (*data - '0');
  496.           done = True;
  497.         }
  498.       else
  499.         {
  500.           fprintf (stderr,
  501.                "%s: unrecognized " MOZILLA_RESPONSE_PROP
  502.                " from window 0x%x: %s\n",
  503.                progname, (unsigned int) window, data);
  504.           result = 6;
  505.           done = True;
  506.         }
  507.  
  508.       if (data)
  509.         XFree (data);
  510.     }
  511. #ifdef DEBUG_PROPS
  512.       else if (event.xany.type == PropertyNotify &&
  513.            event.xproperty.window == window &&
  514.            event.xproperty.state == PropertyDelete &&
  515.            event.xproperty.atom == XA_MOZILLA_COMMAND)
  516.     {
  517.       fprintf (stderr, "%s: (server 0x%x has accepted "
  518.            MOZILLA_COMMAND_PROP ".)\n",
  519.            progname, (unsigned int) window);
  520.     }
  521. #endif /* DEBUG_PROPS */
  522.     }
  523.  
  524.  DONE:
  525.  
  526.   if (new_command)
  527.     free (new_command);
  528.  
  529.   return result;
  530. }
  531.  
  532. int
  533. mozilla_remote_commands (Display *dpy, Window window, char **commands)
  534. {
  535.   Bool raise_p = True;
  536.   int status = 0;
  537.   mozilla_remote_init_atoms (dpy);
  538.  
  539.   if (window == 0)
  540.     window = mozilla_remote_find_window (dpy);
  541.   else
  542.     mozilla_remote_check_window (dpy, window);
  543.  
  544.   XSelectInput (dpy, window, (PropertyChangeMask|StructureNotifyMask));
  545.  
  546.   mozilla_remote_obtain_lock (dpy, window);
  547.  
  548.   while (*commands)
  549.     {
  550.       if (!strcmp (*commands, "-raise"))
  551.     raise_p = True;
  552.       else if (!strcmp (*commands, "-noraise"))
  553.     raise_p = False;
  554.       else
  555.     status = mozilla_remote_command (dpy, window, *commands, raise_p);
  556.  
  557.       if (status != 0)
  558.     break;
  559.       commands++;
  560.     }
  561.  
  562.   /* When status = 6, it means the window has been destroyed */
  563.   /* It is invalid to free the lock when window is destroyed. */
  564.  
  565.   if ( status != 6 )
  566.   mozilla_remote_free_lock (dpy, window);
  567.  
  568.   return status;
  569. }
  570.  
  571.  
  572. #ifdef STANDALONE
  573.  
  574. static void
  575. usage (void)
  576. {
  577.   fprintf (stderr, "usage: %s [ options ... ]\n\
  578.        where options include:\n\
  579. \n\
  580.        -help                     to show this message.\n\
  581.        -display <dpy>            to specify the X server to use.\n\
  582.        -remote <remote-command>  to execute a command in an already-running\n\
  583.                                  Netscape process.  See the manual for a\n\
  584.                                  list of valid commands.\n\
  585.        -id <window-id>           the id of an X window to which the -remote\n\
  586.                                  commands should be sent; if unspecified,\n\
  587.                                  the first window found will be used.\n\
  588.        -raise                    whether following -remote commands should\n\
  589.                                  cause the window to raise itself to the top\n\
  590.                                  (this is the default.)\n\
  591.        -noraise                  the opposite of -raise: following -remote\n\
  592.                                  commands will not auto-raise the window.\n\
  593. ",
  594.        progname);
  595. }
  596.  
  597.  
  598. void
  599. main (int argc, char **argv)
  600. {
  601.   Display *dpy;
  602.   char *dpy_string = 0;
  603.   char **remote_commands = 0;
  604.   int remote_command_count = 0;
  605.   int remote_command_size = 0;
  606.   unsigned long remote_window = 0;
  607.   Bool sync_p = False;
  608.   int i;
  609.  
  610.   progname = strrchr (argv[0], '/');
  611.   if (progname)
  612.     progname++;
  613.   else
  614.     progname = argv[0];
  615.  
  616.   /* Hack the -help and -version arguments before opening the display. */
  617.   for (i = 1; i < argc; i++)
  618.     {
  619.       if (!strcasecmp (argv [i], "-h") ||
  620.       !strcasecmp (argv [i], "-help"))
  621.     {
  622.       usage ();
  623.       exit (0);
  624.     }
  625.       else if (!strcmp (argv [i], "-d") ||
  626.            !strcmp (argv [i], "-dpy") ||
  627.            !strcmp (argv [i], "-disp") ||
  628.            !strcmp (argv [i], "-display"))
  629.     {
  630.       i++;
  631.       dpy_string = argv [i];
  632.     }
  633.       else if (!strcmp (argv [i], "-sync") ||
  634.            !strcmp (argv [i], "-synchronize"))
  635.     {
  636.       sync_p = True;
  637.     }
  638.       else if (!strcmp (argv [i], "-remote"))
  639.     {
  640.       if (remote_command_count == remote_command_size)
  641.         {
  642.           remote_command_size += 20;
  643.           remote_commands =
  644.         (remote_commands
  645.          ? realloc (remote_commands,
  646.                 remote_command_size * sizeof (char *))
  647.          : calloc (remote_command_size, sizeof (char *)));
  648.         }
  649.       i++;
  650.       if (!argv[i] || *argv[i] == '-' || *argv[i] == 0)
  651.         {
  652.           fprintf (stderr, "%s: invalid `-remote' option \"%s\"\n",
  653.                progname, argv[i] ? argv[i] : "");
  654.           usage ();
  655.           exit (-1);
  656.         }
  657.       remote_commands [remote_command_count++] = argv[i];
  658.     }
  659.       else if (!strcmp (argv [i], "-raise") ||
  660.            !strcmp (argv [i], "-noraise"))
  661.     {
  662.       char *r = argv [i];
  663.       if (remote_command_count == remote_command_size)
  664.         {
  665.           remote_command_size += 20;
  666.           remote_commands =
  667.         (remote_commands
  668.          ? realloc (remote_commands,
  669.                 remote_command_size * sizeof (char *))
  670.          : calloc (remote_command_size, sizeof (char *)));
  671.         }
  672.       remote_commands [remote_command_count++] = r;
  673.     }
  674.       else if (!strcmp (argv [i], "-id"))
  675.     {
  676.       char c;
  677.       if (remote_command_count > 0)
  678.         {
  679.           fprintf (stderr,
  680.         "%s: the `-id' option must preceed all `-remote' options.\n",
  681.                progname);
  682.           usage ();
  683.           exit (-1);
  684.         }
  685.       else if (remote_window != 0)
  686.         {
  687.           fprintf (stderr, "%s: only one `-id' option may be used.\n",
  688.                progname);
  689.           usage ();
  690.           exit (-1);
  691.         }
  692.       i++;
  693.       if (argv[i] &&
  694.           1 == sscanf (argv[i], " %ld %c", &remote_window, &c))
  695.         ;
  696.       else if (argv[i] &&
  697.            1 == sscanf (argv[i], " 0x%lx %c", &remote_window, &c))
  698.         ;
  699.       else
  700.         {
  701.           fprintf (stderr, "%s: invalid `-id' option \"%s\"\n",
  702.                progname, argv[i] ? argv[i] : "");
  703.           usage ();
  704.           exit (-1);
  705.         }
  706.     }
  707.     }
  708.  
  709.   dpy = XOpenDisplay (dpy_string);
  710.   if (! dpy)
  711.     exit (-1);
  712.  
  713.   if (sync_p)
  714.     XSynchronize (dpy, True);
  715.  
  716.   exit (mozilla_remote_commands (dpy, (Window) remote_window,
  717.                  remote_commands));
  718. }
  719.  
  720. #endif /* STANDALONE */
  721.