#include <sys/param.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <pwd.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xlibint.h>
#include <X11/Xatom.h>
#include <X11/Xresource.h>
#include "csfindNX.h"
#include "dpsNXprops.h"
#include "Xlibnet.h"
#include "DPS/dpsXclient.h"
#include "DPS/dpsNXargs.h"
#include <DPS/XDPSlib.h>
#include "dpsassert.h"
#include "cslibint.h"
#define CANTSTARTAGENT "Unable to start agent.\n"
typedef struct {
Window id;
int willingness;
} Agent, *AgentIdList;
static char *XDPSLNXHost = NULL;
static int XDPSLNXPort = 0;
static int XDPSLNXTrans = XDPSNX_TRANS_UNIX;
static int gXDPSNXLaunchedAgentTrans = XDPSNX_USE_BEST;
static int gXDPSNXLaunchedAgentPort = XDPSNX_USE_BEST;
static char *gXDPSNXExecObj = XDPSNX_DEFAULT_EXEC_NAME;
static char **gXDPSNXExecArgs = NULL;
static Bool gWasAgentSet = False;
static Bool gXDPSNXAutoLaunch = False;
unsigned char gXDPSNXErrorCode;
extern int gNXSndBufSize;
static char *getHomeDir(char *);
static int
TmpErrorHandler(
Display *dpy,
XErrorEvent *err)
{
gXDPSNXErrorCode = err->error_code;
return 0;
}
static int
GetProperty(
Display *dpy,
Window w,
Atom prop,
Atom type,
unsigned long *nitems,
char **data)
{
long largest_len = ((((unsigned long) -1) >> 1) / 4);
Atom actual_type;
int actual_format;
unsigned long actual_number;
unsigned long remaining;
if (type == None) return(!Success);
if ((XGetWindowProperty(dpy, w, prop, 0, largest_len, False, type,
&actual_type, &actual_format, &actual_number,
&remaining, (unsigned char **) data) == Success)
&& (actual_type == type)) {
if (nitems != NULL) *nitems = actual_number;
return(Success);
} else {
if (*nitems != 0) {
XFree(*data);
*data = NULL;
*nitems = 0;
}
return(!Success);
}
}
static AgentIdList
GetAgentIdList(
Display *dpy,
unsigned long *nAgents)
{
Atom serverListAtom = XInternAtom(dpy, XDPSNX_BILLBOARD_PROP, True);
Window *agents = NULL;
AgentIdList agentList = NULL;
int (*oldErrorHandler)(Display *, XErrorEvent *) = 0;
unsigned long i, current;
if (serverListAtom == None) {
goto failed;
}
XSync(dpy, False);
if (GetProperty(dpy, RootWindow(dpy, DefaultScreen(dpy)),
serverListAtom, XA_WINDOW, nAgents,
(char **) &agents) != Success) {
goto failed;
}
if ((agentList = (AgentIdList)
Xcalloc(*nAgents, (unsigned) sizeof(Agent))) == NULL)
goto failed;
oldErrorHandler = XSetErrorHandler(TmpErrorHandler);
current = 0;
for (i=0; i < *nAgents; i++) {
unsigned long len;
int *agentWillingness;
unsigned long k;
for (k=0; k < i; k++)
if (agents[i] == agents[k]) {
agents[i] = None;
break;
}
if (k == i) {
if (GetProperty(dpy, agents[i],
XInternAtom(dpy, XDPSNX_WILLINGNESS_PROP, True),
XA_INTEGER, &len, (char **) &agentWillingness)
!= Success) {
agents[i] = None;
gXDPSNXErrorCode = None;
} else {
unsigned long j = 0;
while ((j < current) && (agentList[j].willingness > *agentWillingness))
j++;
if (j < current)
(void) bcopy((char *) &agentList[j], (char *) &agentList[j+1],
sizeof(Agent) * (*nAgents - j - 1));
agents[current] = agents[i];
agentList[j].id = agents[current++];
agentList[j].willingness = *agentWillingness;
XFree(agentWillingness);
}
}
}
(void) XSetErrorHandler(oldErrorHandler);
oldErrorHandler = NULL;
if (*nAgents != current) {
if (current > 0) {
*nAgents = current;
(void) XChangeProperty(dpy, RootWindow(dpy, DefaultScreen(dpy)),
serverListAtom, XA_WINDOW, 32,
PropModeReplace, (unsigned char *) agents, *nAgents);
} else {
(void) XDeleteProperty(dpy, RootWindow(dpy, DefaultScreen(dpy)),
serverListAtom);
goto failed;
}
}
(void) XFree(agents);
return(agentList);
failed:
if (agents != NULL) XFree(agents);
if (agentList != NULL) XFree(agentList);
if (oldErrorHandler != NULL) (void) XSetErrorHandler(oldErrorHandler);
*nAgents = 0;
return(NULL);
}
static int
XDPSNXOnDisplay(
Display *dpy,
char *licenseMethod,
char **host,
int *transport,
int *port)
{
unsigned long nAgents = 0;
AgentIdList agentList = NULL;
Bool match = False;
unsigned long i = 0;
int status = !Success;
#ifdef DPSLNKL
extern unsigned ANXKFunc();
#endif
(void) XGrabServer(dpy);
if ((agentList = GetAgentIdList(dpy, &nAgents)) == NULL)
goto cleanup;
if (agentList[i].willingness <= 0) {
DPSWarnProc(NULL, "Found agent(s) for display, but none willing to accept connections.\n");
goto cleanup;
}
#ifdef DPSLNKL
if (ANXKFunc() != 0) {
match = True;
} else
#endif
{
Atom desiredLicenseMethod, openLicenseMethod;
char openLicenseString[256];
(void) sprintf(openLicenseString, "%s:%d",
LICENSE_METHOD_OPEN,
OPEN_LICENSE_VERSION);
openLicenseMethod = XInternAtom(dpy, openLicenseString, True);
if (licenseMethod != NULL)
desiredLicenseMethod = XInternAtom(dpy, licenseMethod, True);
else
desiredLicenseMethod = None;
if ((desiredLicenseMethod != None) || (openLicenseMethod != None)) {
for (i=0;
(i < nAgents) && (agentList[i].willingness > 0) && (match == False);
i++) {
Atom *licenseMethods = NULL;
unsigned long nMethods;
unsigned long j;
if (GetProperty(dpy, agentList[i].id,
XInternAtom(dpy, XDPSNX_LICENSE_METHOD_PROP, True),
XA_ATOM,
&nMethods, (char **) &licenseMethods) != Success)
goto cleanup;
j = 0;
while((j < nMethods)
&& (licenseMethods[j] != desiredLicenseMethod)
&& (licenseMethods[j] != openLicenseMethod)) j++;
if (j < nMethods) {
match = True;
break;
}
(void) XFree(licenseMethods);
}
}
}
if (match) {
TransportInfo *transInfo;
if (GetProperty(dpy, agentList[i].id,
XInternAtom(dpy, XDPSNX_TRANSPORT_INFO_PROP, True),
XA_INTEGER, NULL, (char **) &transInfo) != Success) {
goto cleanup;
} else {
*transport = transInfo->transport;
*port = transInfo->port;
match = True;
XFree(transInfo);
}
if (GetProperty(dpy, agentList[i].id,
XInternAtom(dpy, XDPSNX_HOST_NAME_PROP, True), XA_STRING,
NULL, (char **) host) == Success) {
status = Success;
if (*transport == XDPSNX_TRANS_TCP) {
char hostname[MAXHOSTNAMELEN];
(void) N_XGetHostname(hostname, MAXHOSTNAMELEN);
if (strcmp(hostname, *host) == 0)
*transport = XDPSNX_TRANS_UNIX;
}
}
}
cleanup:
(void) XUngrabServer(dpy);
(void) XDPSLFlush(dpy);
if (agentList != NULL) XFree(agentList);
return(status);
}
static int
ParseAgentString(
char *string,
char **hostname,
int *transport,
int *port)
{
int dnet = 0;
Bool transportSpecified = False;
char namebuf[255];
char *p;
(void) strncpy(namebuf, string, strlen(string)+1);
p = &namebuf[0];
for (; *p && *p != ':'; p++);
if (!*p) return(!Success);
if (*(p+1) == ':') {
dnet++;
*(p++) = '\0';
}
*(p++) = '\0';
if (*p == '\0')
return(!Success);
*port = atoi(p);
if (namebuf[0] == '\0') {
if (dnet)
(void) strcpy(namebuf, "0");
else {
*hostname = NULL;
*transport = XDPSNX_TRANS_UNIX;
return(Success);
}
} else {
for (p = &namebuf[0]; *p && *p != '/'; p++);
if (*p == '/') {
transportSpecified = True;
*p = '\0';
p++;
} else
p = &namebuf[0];
if ((*hostname = (char *) Xmalloc(strlen(p))) == NULL)
return(!Success);
(void) strcpy(*hostname, p);
if (dnet)
*transport = XDPSNX_TRANS_DECNET;
else if (transportSpecified) {
if (strcmp(namebuf, "unix") == 0)
*transport = XDPSNX_TRANS_UNIX;
else
*transport = XDPSNX_TRANS_TCP;
} else
*transport = XDPSNX_TRANS_TCP;
}
return(Success);
}
static int
FindXDPSNXInXrmDatabase(
Display *dpy,
char **host,
int *transport,
int *port)
{
XrmDatabase rDB = NULL;
XrmDatabase serverDB;
char filenamebuf[1024];
char *filename = &filenamebuf[0];
char *env, *str_type;
char name[255];
XrmValue value;
int retVal = !Success;
XrmInitialize();
(void) strcpy(name, "/usr/lib/X11/app-defaults/");
(void) strcat(name, XDPSNX_X_CLASS_NAME);
XrmMergeDatabases(XrmGetFileDatabase(name), &rDB);
if (XResourceManagerString(dpy) != NULL) {
serverDB = XrmGetStringDatabase(XResourceManagerString(dpy));
} else {
(void) getHomeDir(filename);
(void) strcat(filename, "/.Xdefaults");
serverDB = XrmGetFileDatabase(filename);
}
XrmMergeDatabases(serverDB, &rDB);
if ((env = getenv("XENVIRONMENT")) == NULL) {
int len;
env = getHomeDir(filename);
(void) strcat(filename, "/.Xdefaults-");
len = strlen(env);
(void) gethostname(env+len, 1024-len);
}
XrmMergeDatabases(XrmGetFileDatabase(env), &rDB);
if (XrmGetResource(rDB, XDPSNX_X_RESOURCE, XDPSNX_X_CLASS_NAME, &str_type,
&value) == True) {
retVal = ParseAgentString((char *) value.addr, host, transport, port);
}
(void) XrmDestroyDatabase(rDB);
return(retVal);
}
static char *
getHomeDir(char *dest)
{
register char *ptr;
if ((ptr = getenv("HOME")) != NULL) {
(void) strcpy(dest, ptr);
} else {
struct passwd *pw;
if ((ptr = getenv("USER")) != NULL) {
pw = getpwnam(ptr);
} else {
pw = getpwuid(getuid());
}
if (pw) {
(void) strcpy(dest, pw->pw_dir);
} else {
*dest = ' ';
}
}
return (dest);
}
int gForceLaunchHack = 0;
XDPSNXFindNXResult
XDPSNXFindNX(
Display *dpy,
char *licenseMethod,
char **host,
int *transport,
int *port)
{
char *agentenv;
if (gForceLaunchHack)
return(findnx_not_found);
if (gWasAgentSet) {
*host = XDPSLNXHost;
*transport = XDPSLNXTrans;
*port = XDPSLNXPort;
return(findnx_found);
} else if ((agentenv = getenv(AGENT_ENV_VAR)) != NULL) {
int status = ParseAgentString(agentenv, host, transport, port);
if (status != Success) {
DPSWarnProc((DPSContext) NULL, "Illegal syntax for DPSNXHOST");
return(findnx_error);
} else return(findnx_found);
} else if (XDPSNXOnDisplay(dpy, licenseMethod, host, transport, port) ==
Success) {
return(findnx_found);
} else if (FindXDPSNXInXrmDatabase(dpy, host, transport, port) == Success) {
return(findnx_found);
}
return(findnx_not_found);
}
Status
XDPSNXSetClientArg(int arg, void *value)
{
Display *dpy;
if (arg == XDPSNX_AGENT) {
gWasAgentSet = True;
return(ParseAgentString(value,
&XDPSLNXHost, &XDPSLNXTrans, &XDPSLNXPort));
}
else if (arg == XDPSNX_EXEC_FILE) {
if ((gXDPSNXExecObj = Xmalloc(strlen((char *) value) + 1)) == NULL) {
return(!Success);
}
gXDPSNXExecObj = strcpy(gXDPSNXExecObj, (char *) value);
} else if (arg == XDPSNX_EXEC_ARGS) {
int i;
char **cpp, **execInfo;
execInfo = (char **) value;
for(cpp = execInfo, i = 1; *cpp != NULL; i++, cpp++);
gXDPSNXExecArgs = (char **) Xcalloc(i, sizeof(char *));
if (gXDPSNXExecArgs == NULL) return(!Success);
for(cpp = gXDPSNXExecArgs; *execInfo != NULL;
execInfo++, cpp++) {
if ((*cpp = Xmalloc(strlen(*execInfo) + 1)) == NULL)
return(!Success);
*cpp = strcpy(*cpp, *execInfo);
}
} else if (arg == XDPSNX_AUTO_LAUNCH) {
gXDPSNXAutoLaunch = (Bool)(long) value;
} else if (arg == XDPSNX_LAUNCHED_AGENT_TRANS) {
gXDPSNXLaunchedAgentTrans = (long) value;
} else if (arg == XDPSNX_LAUNCHED_AGENT_PORT) {
gXDPSNXLaunchedAgentPort = (long) value;
} else if (arg == XDPSNX_REQUEST_XSYNC) {
dpy = (Display *) value;
if (dpy == (Display *)NULL)
return(Success);
XDPSLSetSyncMask(dpy, DPSCAP_SYNCMASK_SYNC);
} else if (arg == XDPSNX_REQUEST_RECONCILE) {
dpy = (Display *) value;
if (dpy == (Display *)NULL)
return(Success);
XDPSLSetSyncMask(dpy, DPSCAP_SYNCMASK_RECONCILE);
} else if (arg == XDPSNX_REQUEST_BUFFER) {
dpy = (Display *) value;
if (dpy == (Display *)NULL)
return(Success);
XDPSLSetSyncMask(dpy, DPSCAP_SYNCMASK_BUFFER);
} else if (arg == XDPSNX_GC_UPDATES_SLOW) {
dpy = (Display *) value;
if (dpy == (Display *)NULL)
return(Success);
XDPSLSetGCFlushMode(dpy, XDPSNX_GC_UPDATES_SLOW);
} else if (arg == XDPSNX_GC_UPDATES_FAST) {
dpy = (Display *) value;
if (dpy == (Display *)NULL)
return(Success);
XDPSLSetGCFlushMode(dpy, XDPSNX_GC_UPDATES_FAST);
} else if (arg == XDPSNX_SEND_BUF_SIZE) {
int i = (long)value;
if (i >= 4096 && i <= 65536) gNXSndBufSize = i;
}
return(Success);
}
void
XDPSGetNXArg(int arg, void **value)
{
static char agentBuffer[255];
if (arg == XDPSNX_AGENT) {
switch(XDPSLNXTrans) {
case XDPSNX_TRANS_UNIX:
(void) sprintf(agentBuffer, "unix/");
break;
case XDPSNX_TRANS_TCP:
(void) sprintf(agentBuffer, "tcp/");
break;
case XDPSNX_TRANS_DECNET:
(void) sprintf(agentBuffer, "decnet/");
break;
default:
DPSWarnProc(NULL, "Unknown transport passed to XDPSGetNXArg ignored.\n");
agentBuffer[0] = '\0';
break;
}
(void) strcat(agentBuffer, XDPSLNXHost);
(void) strcat(agentBuffer,
(XDPSLNXTrans == XDPSNX_TRANS_DECNET ? "::" : ":"));
(void) sprintf(&agentBuffer[strlen(agentBuffer)], "%d", XDPSLNXPort);
*value = (void *) agentBuffer;
}
else if (arg == XDPSNX_EXEC_FILE) {
*value = (void *) gXDPSNXExecObj;
} else if (arg == XDPSNX_EXEC_ARGS) {
*value = (void *) gXDPSNXExecArgs;
} else if (arg == XDPSNX_AUTO_LAUNCH) {
*value = (void *) (long)gXDPSNXAutoLaunch;
} else if (arg == XDPSNX_LAUNCHED_AGENT_TRANS) {
*value = (void *) (long)gXDPSNXLaunchedAgentTrans;
} else if (arg == XDPSNX_LAUNCHED_AGENT_PORT) {
*value = (void *) (long)gXDPSNXLaunchedAgentPort;
}
}