home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / xfe / remote-s.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  9.7 KB  |  367 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. /* remote-s.c --- remote control of netscape.
  20.    Created: Jamie Zawinski <jwz@netscape.com>
  21.  */
  22.  
  23.  
  24. #include "mozilla.h"
  25. #include "xfe.h"
  26.  
  27. #define progname fe_progname
  28. #define mozilla_remote_init_atoms fe_init_atoms
  29. #define mozilla_remote_commands fe_RemoteCommands
  30. static const char *expected_mozilla_version = fe_version;
  31. #include "remote.c"
  32.  
  33. /* for XP_GetString() */
  34. #include <xpgetstr.h>
  35. extern int XFE_REMOTE_S_UNABLE_TO_READ_PROPERTY;
  36. extern int XFE_REMOTE_S_INVALID_DATA_ON_PROPERTY;
  37. extern int XFE_REMOTE_S_509_INTERNAL_ERROR;
  38. extern int XFE_REMOTE_S_500_UNPARSABLE_COMMAND;
  39. extern int XFE_REMOTE_S_501_UNRECOGNIZED_COMMAND;
  40. extern int XFE_REMOTE_S_502_NO_APPROPRIATE_WINDOW;
  41. extern int XFE_REMOTE_S_200_EXECUTED_COMMAND;
  42.  
  43.  
  44. /* server side */
  45.  
  46. static void fe_property_change_action (Widget widget, XEvent *event,
  47.                        String *av, Cardinal *ac);
  48.  
  49. static char *fe_server_handle_command (Display *dpy, Window window,
  50.                        XEvent *event, char *command);
  51.  
  52. static XtTranslations fe_prop_translations;
  53.  
  54. void
  55. fe_InitRemoteServer (Display *dpy)
  56. {
  57.   static Boolean done = False;
  58.   static XtActionsRec actions [] =
  59.     { { "HandleMozillaCommand", fe_property_change_action } };
  60.  
  61.   if (done) return;
  62.   done = True;
  63.   fe_init_atoms (dpy);
  64.  
  65.   XtAppAddActions (fe_XtAppContext, actions, countof (actions));
  66.  
  67.   fe_prop_translations =
  68.     XtParseTranslationTable ("<PropertyNotify>: HandleMozillaCommand()");
  69. }
  70.  
  71. void
  72. fe_InitRemoteServerWindow (MWContext *context)
  73. {
  74.   Widget widget = CONTEXT_WIDGET (context);
  75.   Display *dpy = XtDisplay (widget);
  76.   Window window = XtWindow (widget);
  77.   XWindowAttributes attrs;
  78.   unsigned char *data = (unsigned char *) fe_version;
  79.  
  80.   XtOverrideTranslations (widget, fe_prop_translations);
  81.  
  82.   XChangeProperty (dpy, window, XA_MOZILLA_VERSION, XA_STRING,
  83.            8, PropModeReplace, data, strlen (data));
  84.  
  85.   XGetWindowAttributes (dpy, window, &attrs);
  86.   if (! (attrs.your_event_mask & PropertyChangeMask))
  87.     XSelectInput (dpy, window, attrs.your_event_mask | PropertyChangeMask);
  88. }
  89.  
  90.  
  91. void
  92. fe_server_handle_property_change (Display *dpy, Window window, XEvent *event)
  93. {
  94.   if (event->xany.type == PropertyNotify &&
  95.       event->xproperty.state == PropertyNewValue &&
  96.       event->xproperty.window == window &&
  97.       event->xproperty.atom == XA_MOZILLA_COMMAND)
  98.     {
  99.       int result;
  100.       Atom actual_type;
  101.       int actual_format;
  102.       unsigned long nitems, bytes_after;
  103.       unsigned char *data = 0;
  104.  
  105.       result = XGetWindowProperty (dpy, window, XA_MOZILLA_COMMAND,
  106.                    0, (65536 / sizeof (long)),
  107.                    True, /* atomic delete after */
  108.                    XA_STRING,
  109.                    &actual_type, &actual_format,
  110.                    &nitems, &bytes_after,
  111.                    &data);
  112.       if (result != Success)
  113.     {
  114.       fprintf (stderr,
  115.            XP_GetString(XFE_REMOTE_S_UNABLE_TO_READ_PROPERTY),
  116.            fe_progname,
  117.            MOZILLA_COMMAND_PROP);
  118.       return;
  119.     }
  120.       else if (!data || !*data)
  121.     {
  122.       fprintf (stderr, 
  123.            XP_GetString(XFE_REMOTE_S_INVALID_DATA_ON_PROPERTY),
  124.            fe_progname,
  125.            MOZILLA_COMMAND_PROP,
  126.            (unsigned int) window);
  127.       return;
  128.     }
  129.       else
  130.     {
  131.       char *response =
  132.         fe_server_handle_command (dpy, window, event, (char *) data);
  133.       if (! response) abort ();
  134.       XChangeProperty (dpy, window, XA_MOZILLA_RESPONSE, XA_STRING,
  135.                8, PropModeReplace, response, strlen (response));
  136.       free (response);
  137.     }
  138.  
  139.       if (data)
  140.     XFree (data);
  141.     }
  142. #ifdef DEBUG_PROPS
  143.   else if (event->xany.type == PropertyNotify &&
  144.        event->xproperty.window == window &&
  145.        event->xproperty.state == PropertyDelete &&
  146.        event->xproperty.atom == XA_MOZILLA_RESPONSE)
  147.     {
  148.       fprintf (stderr, "%s: (client has accepted the response on 0x%x.)\n",
  149.            fe_progname, (unsigned int) window);
  150.     }
  151.   else if (event->xany.type == PropertyNotify &&
  152.        event->xproperty.window == window &&
  153.        event->xproperty.atom == XA_MOZILLA_LOCK)
  154.     {
  155.       fprintf (stderr, "%s: (client has %s a lock on 0x%x.)\n",
  156.            fe_progname,
  157.            (event->xproperty.state == PropertyNewValue
  158.         ? "obtained" : "freed"),
  159.            (unsigned int) window);
  160.     }
  161. #endif /* DEBUG_PROPS */
  162.  
  163. }
  164.  
  165. static void
  166. fe_property_change_action (Widget widget, XEvent *event,
  167.                String *av, Cardinal *ac)
  168. {
  169.   MWContext *context = fe_WidgetToMWContext (widget);
  170.   if (! context) return;
  171.   fe_server_handle_property_change (XtDisplay (CONTEXT_WIDGET (context)),
  172.                     XtWindow (CONTEXT_WIDGET (context)),
  173.                     event);
  174. }
  175.  
  176. static char *
  177. fe_server_handle_command (Display *dpy, Window window, XEvent *event,
  178.               char *command)
  179. {
  180.     char *name = 0;
  181.     char **av = 0;
  182.     int ac = 0;
  183.     int avsize = 0;
  184.     Boolean raise_p = True;
  185.     int i;
  186.     char *buf;
  187.     char *buf2;
  188.     int32 buf2_size;
  189.     char *head, *tail;
  190.     XtActionProc action = 0;
  191.     Widget widget = XtWindowToWidget (dpy, window);
  192.     MWContext *context = fe_WidgetToMWContext (widget);
  193.     XP_Bool mail_or_news_required = FALSE;
  194.     MWContextType required_type = (MWContextType) (~0);
  195.     XP_Bool make_context_if_necessary = FALSE;
  196.     MWContext *target_context = context;
  197.  
  198.     XP_ASSERT(context);
  199.  
  200.     buf = fe_StringTrim (strdup (command));
  201.     buf2_size = strlen (buf) + 200;
  202.     buf2 = (char *) malloc (buf2_size);
  203.  
  204.     head = buf;
  205.     tail = buf;
  206.  
  207.     if (! widget)
  208.         {
  209.             PR_snprintf (buf2, buf2_size,
  210.                          XP_GetString(XFE_REMOTE_S_509_INTERNAL_ERROR),
  211.                          (unsigned int) window);
  212.             free (buf);
  213.             return buf2;
  214.         }
  215.  
  216.     /* extract the name (everything before the first '(', trimmed.) */
  217.     while (1)
  218.         if (*tail == '(' || isspace (*tail) || !*tail)
  219.             {
  220.                 *tail = 0;
  221.                 tail++;
  222.                 name = fe_StringTrim (head);
  223.                 break;
  224.             }
  225.         else
  226.             tail++;
  227.  
  228.     if (!name || !*name)
  229.         {
  230.             PR_snprintf (buf2, buf2_size,
  231.                          XP_GetString(XFE_REMOTE_S_500_UNPARSABLE_COMMAND), 
  232.                          command);
  233.             free (buf);
  234.             return buf2;
  235.         }
  236.  
  237.     /* look for it in the old remote actions. */
  238.     for (i = 0; i < fe_CommandActionsSize; i++)
  239.         if (!XP_STRCASECMP(name, fe_CommandActions [i].string))
  240.             {
  241.                 name = fe_CommandActions [i].string;
  242.                 action = fe_CommandActions [i].proc;
  243.                 break;
  244.             }
  245.  
  246.     if (!av)
  247.         {
  248.             avsize = 20;
  249.             av = (char **) calloc (avsize, sizeof (char *));
  250.  
  251.             /* if it's not an old action, we need to know the name of the
  252.                command, so we stick it on the front.  This will be dealt
  253.                with in xfeDoRemoteCommand. */
  254.             if (!action)
  255.                 av[ ac++ ] = name;
  256.  
  257.             while (*tail == '(' || isspace (*tail))
  258.                 tail++;
  259.  
  260.             head = tail;
  261.             while (1)
  262.                 {
  263.                     if (*tail == ')' || *tail == ',' || *tail == 0)
  264.                         {
  265.                             char delim = *tail;
  266.                             if (ac >= (avsize - 2))
  267.                                 {
  268.                                     avsize += 20;
  269.                                     av = (char **) realloc (av, avsize * sizeof (char *));
  270.                                 }
  271.                             *tail = 0;
  272.  
  273.                             av [ac++] = fe_StringTrim (head);
  274.  
  275.                             if (delim != ',' && !*av[ac-1])
  276.                                 ac--;
  277.                             else if (!strcasecomp (av [ac-1], "noraise"))
  278.                                 {
  279.                                     raise_p = False;
  280.                                     ac--;
  281.                                 }
  282.                             else if (!strcasecomp (av [ac-1], "raise"))
  283.                                 {
  284.                                     raise_p = True;
  285.                                     ac--;
  286.                                 }
  287.  
  288.                             head = tail+1;
  289.                             if (delim != ',')
  290.                                 break;
  291.                         }
  292.                     tail++;
  293.                 }
  294.  
  295.             av [ac++] = "<remote>";
  296.         }
  297.  
  298.     /* If this is GetURL or something like it, make sure the context we pick
  299.        matches the URL.
  300.        */
  301.     if (strstr(name, "URL"))
  302.         {
  303.             const char *url = av[0];
  304.             mail_or_news_required = FALSE;
  305.             required_type = (MWContextType) (~0);
  306. #ifdef MOZ_MAIL_NEWS
  307.             if (MSG_RequiresMailWindow (url))
  308.                 required_type = MWContextMail;
  309.             else if (MSG_RequiresNewsWindow (url))
  310.                 required_type = MWContextNews;
  311.             else if (MSG_RequiresBrowserWindow (url))
  312. #endif
  313.                 required_type = MWContextBrowser;
  314.             /* Nothing to do for MSG_RequiresComposeWindow compose. */
  315.  
  316.             if (required_type != (MWContextType) (~0))
  317.                 {
  318.                     make_context_if_necessary = TRUE;
  319.                 }
  320.         }
  321.     else if (!strcasecomp(name, "openfile"))
  322.       {
  323.         required_type = MWContextBrowser;
  324.         make_context_if_necessary = TRUE;
  325.       }
  326.  
  327.     if (raise_p)
  328.         XMapRaised (dpy, window);
  329.  
  330.     if (required_type != (MWContextType) (~0))
  331.       target_context = XP_FindContextOfType(context, required_type);
  332.             
  333.     if (make_context_if_necessary && !target_context)
  334.       target_context = FE_MakeNewWindow(context, NULL, NULL, NULL);
  335.  
  336.     if (target_context) 
  337.       {
  338.         Cardinal ac2 = ac; /* why is this passed as a pointer??? */
  339.         if (name && action)
  340.           {
  341.             (*action) (CONTEXT_WIDGET(target_context), event, av, &ac2);
  342.           }
  343.         else
  344.           /* now we call our new xfe2 interface to the command mechanism */
  345.           {
  346.             xfeDoRemoteCommand (CONTEXT_WIDGET(target_context),
  347.                                 event, av, &ac2);
  348.           }
  349.       }
  350.  
  351.     PR_snprintf (buf2, buf2_size,
  352.                  XP_GetString(XFE_REMOTE_S_200_EXECUTED_COMMAND),
  353.                  name);
  354.     for (i = 0; i < ac-1; i++)
  355.         {
  356.             strcat (buf2, av [i]);
  357.             if (i < ac-2)
  358.                 strcat (buf2, ", ");
  359.         }
  360.     strcat (buf2, ")");
  361.  
  362.     free (av);
  363.  
  364.     free (buf);
  365.     return buf2;
  366. }
  367.