415 lines
12 KiB
C++
415 lines
12 KiB
C++
/*********************************************************************
|
||
*
|
||
* AUTHORIZATION TO USE AND DISTRIBUTE
|
||
*
|
||
* Redistribution and use in source and binary forms, with or without
|
||
* modification, are permitted provided that:
|
||
*
|
||
* (1) source code distributions retain this paragraph in its entirety,
|
||
*
|
||
* (2) distributions including binary code include this paragraph in
|
||
* its entirety in the documentation or other materials provided
|
||
* with the distribution, and
|
||
*
|
||
* (3) all advertising materials mentioning features or use of this
|
||
* software display the following acknowledgment:
|
||
*
|
||
* "This product includes software written and developed
|
||
* by Brian Adamson and Joe Macker of the Naval Research
|
||
* Laboratory (NRL)."
|
||
*
|
||
* The name of NRL, the name(s) of NRL employee(s), or any entity
|
||
* of the United States Government may not be used to endorse or
|
||
* promote products derived from this software, nor does the
|
||
* inclusion of the NRL written and developed software directly or
|
||
* indirectly suggest NRL or United States Government endorsement
|
||
* of this product.
|
||
*
|
||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
|
||
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||
********************************************************************/
|
||
|
||
// This file contains code for various UNIX MDP post processor options
|
||
|
||
|
||
/*******************************************************************
|
||
* Netscape[tm] post processor routines
|
||
*/
|
||
|
||
// Some portions of this code
|
||
// Copyright <20> 1996 Netscape Communications Corporation,
|
||
// all rights reserved.
|
||
|
||
#include "normPostProcess.h"
|
||
#include "protoDebug.h"
|
||
|
||
#include <errno.h>
|
||
#include <string.h> // for strerror()
|
||
#include <signal.h>
|
||
#include <ctype.h>
|
||
#include <unistd.h>
|
||
#include <sys/types.h>
|
||
#include <sys/wait.h>
|
||
#include <stdlib.h> // for exit()
|
||
#include <stdio.h>
|
||
|
||
#ifndef sighandler_t
|
||
#ifndef sig_t
|
||
typedef void (*sighandler_t)(int);
|
||
#else
|
||
typedef sig_t sighandler_t;
|
||
#endif // if/else !sig_t
|
||
#endif // !sighandler_t
|
||
|
||
#ifdef NETSCAPE_SUPPORT
|
||
#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"
|
||
#define MOZILLA_VERSION_PROP "_MOZILLA_VERSION"
|
||
static Atom XA_MOZILLA_VERSION = 0;
|
||
bool CheckForNetscape(const char* cmd);
|
||
bool NetscapeIsRunning(Window *result);
|
||
bool NetscapeCheckWindow(Window window);
|
||
#endif // NETSCAPE_SUPPORT
|
||
|
||
class UnixPostProcessor : public NormPostProcessor
|
||
{
|
||
public:
|
||
~UnixPostProcessor();
|
||
bool IsActive() {return (0 != process_id);}
|
||
bool ProcessFile(const char* path);
|
||
void Kill();
|
||
|
||
void OnSIGCHLD();
|
||
|
||
private:
|
||
friend class NormPostProcessor;
|
||
UnixPostProcessor();
|
||
|
||
int process_id;
|
||
#ifdef NETSCAPE_SUPPORT
|
||
Window window_id;
|
||
#endif // NETSCAPE_SUPPORT
|
||
}; // end class UnixPostProcessor
|
||
|
||
UnixPostProcessor::UnixPostProcessor()
|
||
: process_id(0)
|
||
#ifdef NETSCAPE_SUPPORT
|
||
,window_id(0)
|
||
#endif // NETSCAPE_SUPPORT
|
||
{
|
||
}
|
||
|
||
NormPostProcessor* NormPostProcessor::Create()
|
||
{
|
||
return static_cast<NormPostProcessor*>(new UnixPostProcessor);
|
||
} // end NormPostProcessor::Create()
|
||
|
||
UnixPostProcessor::~UnixPostProcessor()
|
||
{
|
||
if (IsActive()) Kill();
|
||
}
|
||
|
||
bool UnixPostProcessor::ProcessFile(const char* path)
|
||
{
|
||
const char** argv = (const char**)process_argv;
|
||
int argc = process_argc;
|
||
#ifdef NETSCAPE_SUPPORT
|
||
// Special support for finding a Netscape window and
|
||
// use the openURL remote command to display received file
|
||
#define USE_ACTIVE_WINDOW 0xffffffff
|
||
const char* myArgs[32];
|
||
char wid_text[32], url_text[PATH_MAX+64];
|
||
if (CheckForNetscape(argv[0]))
|
||
{
|
||
int i = 0;
|
||
myArgs[i++] = process_argv[0];
|
||
Window w = 0;
|
||
// (TBD) We could put in a hack to look for the old
|
||
// window if we made "w" static when "window_id" = 0xffffffff
|
||
// This would help us capture the proper window for file display
|
||
// It's still a hack but it might work a little better without
|
||
// too much trouble
|
||
if (NetscapeIsRunning(&w))
|
||
{
|
||
// Use -remote command to display file in current
|
||
// or new window
|
||
if (window_id)
|
||
{
|
||
if (NetscapeCheckWindow(window_id))
|
||
{
|
||
// Use the same window as last time
|
||
myArgs[i++] = "-id";
|
||
sprintf(wid_text, "0x%lx", window_id);
|
||
myArgs[i++] = wid_text;
|
||
myArgs[i++] = "-noraise";
|
||
myArgs[i++] = "-remote";
|
||
sprintf(url_text, "openURL(file://%s)", path);
|
||
myArgs[i++] = url_text;
|
||
}
|
||
else if (USE_ACTIVE_WINDOW == window_id)
|
||
{
|
||
// Capture the open window we found
|
||
myArgs[i++] = "-id";
|
||
sprintf(wid_text, "0x%lx", w);
|
||
myArgs[i++] = wid_text;
|
||
window_id = w;
|
||
myArgs[i++] = "-noraise";
|
||
myArgs[i++] = "-remote";
|
||
sprintf(url_text, "openURL(file://%s)", path);
|
||
myArgs[i++] = url_text;
|
||
}
|
||
else // user must have closed old window so open another
|
||
{
|
||
window_id = USE_ACTIVE_WINDOW;
|
||
//myArgs[i++] = "-raise";
|
||
myArgs[i++] = "-remote";
|
||
sprintf(url_text, "openURL(file://%s,new-window)", path);
|
||
myArgs[i++] = url_text;
|
||
}
|
||
|
||
}
|
||
else
|
||
{
|
||
// We're starting fresh, open a new window
|
||
window_id = USE_ACTIVE_WINDOW;
|
||
//myArgs[i++] = "-raise";
|
||
myArgs[i++] = "-remote";
|
||
sprintf(url_text, "openURL(file://%s,new-window)", path);
|
||
myArgs[i++] = url_text;
|
||
}
|
||
argv = myArgs;
|
||
|
||
}
|
||
else
|
||
{
|
||
if (IsActive()) Kill();
|
||
window_id = USE_ACTIVE_WINDOW;
|
||
myArgs[i++] = path;
|
||
} // end if/else (NetscapeIsRunning())
|
||
myArgs[i] = NULL;
|
||
argc = i - 1;
|
||
argv = myArgs;
|
||
}
|
||
else
|
||
#endif // NETSCAPE_SUPPORT
|
||
{
|
||
if (IsActive()) Kill();
|
||
argv[argc] = path;
|
||
}
|
||
|
||
// 1) temporarily disable signal handling
|
||
sighandler_t sigtermHandler = signal(SIGTERM, SIG_DFL);
|
||
sighandler_t sigintHandler = signal(SIGINT, SIG_DFL);
|
||
sighandler_t sigchldHandler = signal(SIGCHLD, SIG_DFL);
|
||
|
||
switch((process_id = fork()))
|
||
{
|
||
case -1: // error
|
||
DMSG(0, "UnixPostProcessor::ProcessFile fork() error: %s\n", strerror(errno));
|
||
process_id = 0;
|
||
process_argv[process_argc] = NULL;
|
||
return false;
|
||
|
||
case 0: // child
|
||
if (execvp((char*)argv[0], (char**)argv) < 0)
|
||
{
|
||
DMSG(0, "UnixPostProcessor::ProcessFile execvp() error: %s\n", strerror(errno));
|
||
exit(-1);
|
||
}
|
||
break;
|
||
|
||
default: // parent
|
||
process_argv[process_argc] = NULL;
|
||
// Restore signal handlers for parent
|
||
signal(SIGTERM, sigtermHandler);
|
||
signal(SIGINT, sigintHandler);
|
||
// The use of "waitpid()" here is a work-around
|
||
// for an IRIX SIGCHLD issue
|
||
int status;
|
||
while (waitpid(-1, &status, WNOHANG) > 0);
|
||
signal(SIGCHLD, sigchldHandler);
|
||
break;
|
||
}
|
||
return true;
|
||
} // end UnixPostProcessor::ProcessFile()
|
||
|
||
void UnixPostProcessor::Kill()
|
||
{
|
||
if (!IsActive()) return;
|
||
int count = 0;
|
||
while((kill(process_id, SIGTERM) != 0) && count < 10)
|
||
{
|
||
if (errno == ESRCH) break;
|
||
count++;
|
||
DMSG(0, "UnixPostProcessor::Kill kill() error: %s\n", strerror(errno));
|
||
}
|
||
count = 0;
|
||
int status;
|
||
while((waitpid(process_id, &status, 0) != process_id) && count < 10)
|
||
{
|
||
if (errno == ECHILD) break;
|
||
count++;
|
||
DMSG(0, "UnixPostProcessor::Kill waitpid() error: %s\n", strerror(errno));
|
||
}
|
||
process_id = 0;
|
||
} // end UnixPostProcessor::Kill()
|
||
|
||
void UnixPostProcessor::OnSIGCHLD()
|
||
{
|
||
// See if post processor exited itself
|
||
int status;
|
||
if (wait(&status) == process_id) process_id = 0;
|
||
} // end UnixPostProcessor::HandleSIGCHLD()
|
||
|
||
|
||
#ifdef NETSCAPE_SUPPORT
|
||
bool CheckForNetscape(const char* cmd)
|
||
{
|
||
// See if it's Netscape post processing
|
||
// for which we provide special support
|
||
char txt[8];
|
||
const char *ptr = strrchr(cmd, PROTO_PATH_DELIMITER);
|
||
if (ptr)
|
||
ptr++;
|
||
else
|
||
ptr = cmd;
|
||
strncpy(txt, ptr, 8);
|
||
for (int i=0; i<8; i++) txt[i] = toupper(txt[i]);
|
||
if (!strncmp(txt, "NETSCAPE", 8))
|
||
return true;
|
||
else
|
||
return false;
|
||
} // end CheckForNetscape()
|
||
|
||
bool NetscapeIsRunning(Window *result)
|
||
{
|
||
int i;
|
||
|
||
Window root2, parent, *kids;
|
||
unsigned int nkids;
|
||
*result = 0;
|
||
|
||
Display *dpy = XOpenDisplay(NULL);
|
||
if (!dpy)
|
||
{
|
||
fprintf(stderr, "mdp: XOpenDisplay() error\n");
|
||
return false;
|
||
}
|
||
|
||
if (!XA_MOZILLA_VERSION)
|
||
XA_MOZILLA_VERSION = XInternAtom(dpy, MOZILLA_VERSION_PROP, False);
|
||
|
||
Window root = RootWindowOfScreen(DefaultScreenOfDisplay(dpy));
|
||
|
||
if (!XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
|
||
{
|
||
fprintf(stderr, "mdp: XQueryTree failed on display %s\n", DisplayString (dpy));
|
||
XCloseDisplay(dpy);
|
||
return false;
|
||
}
|
||
|
||
// Note: root != root2 is possible with virtual root WMs.
|
||
if (!(kids && nkids))
|
||
{
|
||
fprintf(stderr, "mdp: root window has no children on display %s\n",
|
||
DisplayString (dpy));
|
||
XCloseDisplay(dpy);
|
||
return false;
|
||
}
|
||
|
||
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;
|
||
XFree (version);
|
||
if (status == Success && type != None)
|
||
{
|
||
*result = w;
|
||
break;
|
||
}
|
||
}
|
||
XCloseDisplay(dpy);
|
||
return (*result ? true : false);
|
||
|
||
} // end NetscapeIsRunning()
|
||
|
||
bool NetscapeCheckWindow(Window window)
|
||
{
|
||
int i;
|
||
Window root2, parent, *kids;
|
||
unsigned int nkids;
|
||
|
||
Display *dpy = XOpenDisplay(NULL);
|
||
if (!dpy)
|
||
{
|
||
fprintf(stderr, "mdp: XOpenDisplay() error\n");
|
||
return false;
|
||
}
|
||
|
||
if (!XA_MOZILLA_VERSION)
|
||
XA_MOZILLA_VERSION = XInternAtom(dpy, MOZILLA_VERSION_PROP, False);
|
||
|
||
Window root = RootWindowOfScreen(DefaultScreenOfDisplay (dpy));
|
||
|
||
if (!XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
|
||
{
|
||
fprintf(stderr, "mdp: XQueryTree failed on display %s\n", DisplayString (dpy));
|
||
XCloseDisplay(dpy);
|
||
return false;
|
||
}
|
||
|
||
// Note: root != root2 is possible with virtual root WMs.
|
||
if (!(kids && nkids)) return false;
|
||
|
||
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;
|
||
XFree (version);
|
||
if (status == Success && type != None)
|
||
{
|
||
if (w == window)
|
||
{
|
||
XCloseDisplay(dpy);
|
||
return true;
|
||
}
|
||
else
|
||
{
|
||
continue;
|
||
}
|
||
}
|
||
}
|
||
XCloseDisplay(dpy);
|
||
return false;
|
||
|
||
} // end NetscapeCheckWindow()
|
||
#endif // NETSCAPE_SUPPORT
|