/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): */ /* */ /* remote-s.c --- remote control of netscape. Created: Jamie Zawinski */ #include "mozilla.h" #include "xfe.h" #define progname fe_progname #define mozilla_remote_init_atoms fe_init_atoms #define mozilla_remote_commands fe_RemoteCommands static const char *expected_mozilla_version = fe_version; #include "remote.c" /* for XP_GetString() */ #include extern int XFE_REMOTE_S_UNABLE_TO_READ_PROPERTY; extern int XFE_REMOTE_S_INVALID_DATA_ON_PROPERTY; extern int XFE_REMOTE_S_509_INTERNAL_ERROR; extern int XFE_REMOTE_S_500_UNPARSABLE_COMMAND; extern int XFE_REMOTE_S_501_UNRECOGNIZED_COMMAND; extern int XFE_REMOTE_S_502_NO_APPROPRIATE_WINDOW; extern int XFE_REMOTE_S_200_EXECUTED_COMMAND; /* server side */ static void fe_property_change_action (Widget widget, XEvent *event, String *av, Cardinal *ac); static char *fe_server_handle_command (Display *dpy, Window window, XEvent *event, char *command); static XtTranslations fe_prop_translations; void fe_InitRemoteServer (Display *dpy) { static Boolean done = False; static XtActionsRec actions [] = { { "HandleMozillaCommand", fe_property_change_action } }; if (done) return; done = True; fe_init_atoms (dpy); XtAppAddActions (fe_XtAppContext, actions, countof (actions)); fe_prop_translations = XtParseTranslationTable (": HandleMozillaCommand()"); } void fe_InitRemoteServerWindow (MWContext *context) { Widget widget = CONTEXT_WIDGET (context); Display *dpy = XtDisplay (widget); Window window = XtWindow (widget); XWindowAttributes attrs; unsigned char *data = (unsigned char *) fe_version; XtOverrideTranslations (widget, fe_prop_translations); XChangeProperty (dpy, window, XA_MOZILLA_VERSION, XA_STRING, 8, PropModeReplace, data, strlen (data)); XGetWindowAttributes (dpy, window, &attrs); if (! (attrs.your_event_mask & PropertyChangeMask)) XSelectInput (dpy, window, attrs.your_event_mask | PropertyChangeMask); } void fe_server_handle_property_change (Display *dpy, Window window, XEvent *event) { if (event->xany.type == PropertyNotify && event->xproperty.state == PropertyNewValue && event->xproperty.window == window && event->xproperty.atom == XA_MOZILLA_COMMAND) { int result; Atom actual_type; int actual_format; unsigned long nitems, bytes_after; unsigned char *data = 0; result = XGetWindowProperty (dpy, window, XA_MOZILLA_COMMAND, 0, (65536 / sizeof (long)), True, /* atomic delete after */ XA_STRING, &actual_type, &actual_format, &nitems, &bytes_after, &data); if (result != Success) { fprintf (stderr, XP_GetString(XFE_REMOTE_S_UNABLE_TO_READ_PROPERTY), fe_progname, MOZILLA_COMMAND_PROP); return; } else if (!data || !*data) { fprintf (stderr, XP_GetString(XFE_REMOTE_S_INVALID_DATA_ON_PROPERTY), fe_progname, MOZILLA_COMMAND_PROP, (unsigned int) window); return; } else { char *response = fe_server_handle_command (dpy, window, event, (char *) data); if (! response) abort (); XChangeProperty (dpy, window, XA_MOZILLA_RESPONSE, XA_STRING, 8, PropModeReplace, response, strlen (response)); free (response); } 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_RESPONSE) { fprintf (stderr, "%s: (client has accepted the response on 0x%x.)\n", fe_progname, (unsigned int) window); } else if (event->xany.type == PropertyNotify && event->xproperty.window == window && event->xproperty.atom == XA_MOZILLA_LOCK) { fprintf (stderr, "%s: (client has %s a lock on 0x%x.)\n", fe_progname, (event->xproperty.state == PropertyNewValue ? "obtained" : "freed"), (unsigned int) window); } #endif /* DEBUG_PROPS */ } static void fe_property_change_action (Widget widget, XEvent *event, String *av, Cardinal *ac) { MWContext *context = fe_WidgetToMWContext (widget); if (! context) return; fe_server_handle_property_change (XtDisplay (CONTEXT_WIDGET (context)), XtWindow (CONTEXT_WIDGET (context)), event); } static char * fe_server_handle_command (Display *dpy, Window window, XEvent *event, char *command) { char *name = 0; char **av = 0; int ac = 0; int avsize = 0; Boolean raise_p = True; int i; char *buf; char *buf2; int32 buf2_size; char *head, *tail; XtActionProc action = 0; Widget widget = XtWindowToWidget (dpy, window); MWContext *context = fe_WidgetToMWContext (widget); XP_Bool mail_or_news_required = FALSE; MWContextType required_type = (MWContextType) (~0); XP_Bool make_context_if_necessary = FALSE; MWContext *target_context = context; XP_ASSERT(context); buf = fe_StringTrim (strdup (command)); buf2_size = strlen (buf) + 200; buf2 = (char *) malloc (buf2_size); head = buf; tail = buf; if (! widget) { PR_snprintf (buf2, buf2_size, XP_GetString(XFE_REMOTE_S_509_INTERNAL_ERROR), (unsigned int) window); free (buf); return buf2; } /* extract the name (everything before the first '(', trimmed.) */ while (1) if (*tail == '(' || isspace (*tail) || !*tail) { *tail = 0; tail++; name = fe_StringTrim (head); break; } else tail++; if (!name || !*name) { PR_snprintf (buf2, buf2_size, XP_GetString(XFE_REMOTE_S_500_UNPARSABLE_COMMAND), command); free (buf); return buf2; } /* look for it in the old remote actions. */ for (i = 0; i < fe_CommandActionsSize; i++) if (!XP_STRCASECMP(name, fe_CommandActions [i].string)) { name = fe_CommandActions [i].string; action = fe_CommandActions [i].proc; break; } if (!av) { avsize = 20; av = (char **) calloc (avsize, sizeof (char *)); /* if it's not an old action, we need to know the name of the command, so we stick it on the front. This will be dealt with in xfeDoRemoteCommand. */ if (!action) av[ ac++ ] = name; while (*tail == '(' || isspace (*tail)) tail++; head = tail; while (1) { if (*tail == ')' || *tail == ',' || *tail == 0) { char delim = *tail; if (ac >= (avsize - 2)) { avsize += 20; av = (char **) realloc (av, avsize * sizeof (char *)); } *tail = 0; av [ac++] = fe_StringTrim (head); if (delim != ',' && !*av[ac-1]) ac--; else if (!strcasecomp (av [ac-1], "noraise")) { raise_p = False; ac--; } else if (!strcasecomp (av [ac-1], "raise")) { raise_p = True; ac--; } head = tail+1; if (delim != ',') break; } tail++; } av [ac++] = ""; } /* If this is GetURL or something like it, make sure the context we pick matches the URL. */ if (strstr(name, "URL")) { #ifdef MOZ_MAIL_NEWS const char *url = av[0]; #endif mail_or_news_required = FALSE; required_type = (MWContextType) (~0); #ifdef MOZ_MAIL_NEWS if (MSG_RequiresMailWindow (url)) required_type = MWContextMail; else if (MSG_RequiresNewsWindow (url)) required_type = MWContextNews; else if (MSG_RequiresBrowserWindow (url)) #endif required_type = MWContextBrowser; /* Nothing to do for MSG_RequiresComposeWindow compose. */ if (required_type != (MWContextType) (~0)) { make_context_if_necessary = TRUE; } } else if (!strcasecomp(name, "openfile")) { required_type = MWContextBrowser; make_context_if_necessary = TRUE; } if (raise_p) XMapRaised (dpy, window); if (required_type != (MWContextType) (~0)) target_context = XP_FindContextOfType(context, required_type); if (make_context_if_necessary && !target_context) target_context = FE_MakeNewWindow(context, NULL, NULL, NULL); if (target_context) { Cardinal ac2 = ac; /* why is this passed as a pointer??? */ if (name && action) { (*action) (CONTEXT_WIDGET(target_context), event, av, &ac2); } else /* now we call our new xfe2 interface to the command mechanism */ { xfeDoRemoteCommand (CONTEXT_WIDGET(target_context), event, av, &ac2); } } PR_snprintf (buf2, buf2_size, XP_GetString(XFE_REMOTE_S_200_EXECUTED_COMMAND), name); for (i = 0; i < ac-1; i++) { strcat (buf2, av [i]); if (i < ac-2) strcat (buf2, ", "); } strcat (buf2, ")"); free (av); free (buf); return buf2; }