1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-03-09 15:50:02 +00:00
cde/cde/programs/dtimsstart/remote.c
2021-12-24 10:50:28 -07:00

876 lines
22 KiB
C

/*
* CDE - Common Desktop Environment
*
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with these libraries and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*/
/* @(#)$TOG: remote.c /main/9 1998/04/06 13:36:26 mgreess $ */
#include "xims.h"
#include <signal.h>
#include <sys/wait.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/errno.h>
#include <setjmp.h>
#include <fcntl.h>
#include <limits.h>
#include <X11/Xproto.h> /* for X_ChangeHosts */
#include <X11/Xatom.h> /* for XA_STRING */
static char *conf_msg_id = STR_CONFDATA;
#define CONF_MSG_ID_LEN strlen(conf_msg_id)
#define CONF_MSG_DATASIZE_LEN 8
#define CONF_MSG_HEADER_LEN (CONF_MSG_ID_LEN + CONF_MSG_DATASIZE_LEN)
#define CONF_MSG_SIZE_MAX (8*1024 - 64) /* < PIPE_BUF (PIPSIZ) */
static int mk_remote_conf(/* list, locale, ims_name, status, confbuf, conflen */);
static char *mk_ims_ent(/* bp, idx, ent */);
static int parse_ims_list(/* ptr, list */);
static int parse_remote_conf(/* listp, locale, confbuf, conflen */);
static int prepare_action(/* act_typ, av, ac */);
static int read_property(/* prop, type, format, remove, datapp, lenp */);
#if 0 /* README */
Atom:
_DTIMSSTART_MAIN _DTIMSSTART_STATUS _DTIMSSTART_DATA
Property:
_DTIMSSTART_STATUS (format: 32) _DTIMSSTART_DATA (format: 8)
ClientMessage:
message_type: _DTIMSSTART_STATUS
format: 32
data.l[0]: _REMOTE_CONF or _REMOTE_RUN
data.l[1]: ErrorCode
data.l[2-4]: 0 (unused)
Status:
_NONE _INIT _REMOTE_CONF _REMOTE_RUN
Actions:
DtImsGetRemoteConf DtImsRunRemoteIms
Procedure:
<initialization>
* own _MAIN property
* set _STATUS property to _INIT
* set _DATA property to _INIT
<get remote configuratuon (DtImsGetRemoteConf)>
* clear _DATA property
* change _STATUS property to _REMOTE_CONF
* set additional command line options to _DATA property
* invoke DtImsGetRemoteConf action
[on remote dtimsstart]
- collect data
- check _STATUS property whether its value is _REMOTE_CONF
- set collected data to _DATA property of owner of _MAIN (Replace)
- send ClientMessage of ErrorCode to owner of _MAIN
- exit
* receive ClientMessage from remote dtimsstart (or action finished)
* change _STATUS property to _INIT
* read data from _DATA property (Delete)
* parse ErrCode and data (conf data or ErrorPath)
* update selection window
<run IMS on remote host (DtImsRunRemoteIms)>
* change _STATUS property to _REMOTE_RUN
* set additional command line options to _DATA property
* invoke DtImsRunRemoteIms action
* popdown selection window (if sucessfully invoked)
[on remote dtimsstart]
- check _STATUS property whether its value is _REMOTE_RUN
- invoke IMS and wait its preparation
- set ErrorPath to _DATA property of owner of _MAIN (Replace)
- send ClientMessage of ErrorCode to owner of _MAIN
- exit
* receive ClientMessage from remote dtimsstart (or action finished)
* change _STATUS property to _INIT
* parse ErrCode and data (ErrorPath)
<termination>
* disown _MAIN property
* exit
#endif /* README */
#ifdef NEED_STRCASECMP
/*
* In case strcasecmp is not provided by the system here is one
* which does the trick.
*/
static int
strcasecmp(const char *s1,
const char *s2)
{
int c1, c2;
while (*s1 && *s2) {
c1 = isupper(*s1) ? tolower(*s1) : *s1;
c2 = isupper(*s2) ? tolower(*s2) : *s2;
if (c1 != c2)
return (c1 - c2);
s1++;
s2++;
}
return (int) (*s1 - *s2);
}
#endif
int put_remote_conf(char *locale, char *ims_name)
{
int ret;
int msg_status = NoError;
int conflen;
char confbuf[CONF_MSG_SIZE_MAX];
ImsList *list = (ImsList *) 0;
DPR(("put_remote_conf(locale=%s, ims=%s)\n", locale, ims_name));
ret = get_ims_list(&list, NULL, True);
msg_status = ret;
ret = mk_remote_conf(list, locale, ims_name, msg_status, confbuf, &conflen);
if (list) {
clear_ImsList(list);
FREE(list);
}
ret = set_remote_confdata(confbuf, conflen);
send_dtims_msg(WIN_ST_REMOTE_CONF, ret);
#if 0
NotifyErrCode(NoError);
(void) fwrite((void *)confbuf, (size_t)conflen, (size_t)1, stdout);
fflush(stdout);
#endif
return ret;
}
int get_remote_conf(ImsList **listp, char *hostname, char *locale, char *ims_name)
{
int ret = NoError;
int conflen = 0;
char *confbuf = 0;
char *opts[16];
int n, num_opts;
char *CDE_locale = NULL;
if (!locale)
locale = userEnv.real_locale ? userEnv.real_locale : userEnv.locale;
CDE_locale = userEnv.CDE_locale;
if (CDE_locale)
DPR2(("get_remote_conf(%s, %s, %s)\n",
hostname, CDE_locale, ims_name ? ims_name : "<all>"));
else
DPR2(("get_remote_conf(%s, %s, %s)\n",
hostname, locale, ims_name ? ims_name : "<all>"));
n = 0;
/* Try to first use the CDE locale, else fallback to the locale. */
if (CDE_locale) {
opts[n++] = "-CDE_locale";
opts[n++] = CDE_locale;
}
else {
if (locale) {
opts[n++] = "-locale";
opts[n++] = locale;
}
}
if (ims_name) {
opts[n++] = "-ims";
opts[n++] = ims_name;
}
#ifdef DEBUG
if (DebugLvl >= 1) {
int i;
for (i = 0; i < DebugLvl; i++) opts[n++] = "-debug";
}
#endif
opts[n] = NULL;
num_opts = n;
ret = prepare_action(ACT_GETREMCONF, opts, num_opts);
if (ret != NoError) return ret;
ret = invoke_action(Conf.action[ACT_GETREMCONF], hostname);
change_window_status(WIN_ST_INIT);
if (ret != NoError) return ret;
ret = read_remote_confdata(&confbuf, &conflen);
if (ret != NoError) return ret;
if (ret == NoError) {
ret = parse_remote_conf(listp, locale, confbuf, conflen);
FREE(confbuf);
if (ims_name && ret == ErrRemoteNoIms)
ret = ErrRemoteMissIms;
}
return ret;
}
#define PUT_DATA(nm, val) *bp++ = ' ', bp = strcpyx(bp, (nm)), \
*bp++ = '=', bp = strcpyx(bp, (val)), *bp++ = '\n'
static int mk_remote_conf(ImsList *list, char *locale,
char *ims_name, int status,
char *confbuf, int *conflen)
{
int num_ent;
int i, j;
char *bp;
int len;
int data_sz;
char sz_ptr[20];
ImsEnt *ent;
char var[20];
DPR(("mk_remote_conf(locale=%s, ims=%s)\n", locale, ims_name));
#ifdef DEBUG
if (DebugLvl >= 2 && list) pr_ImsList(list);
#endif
bp = confbuf + CONF_MSG_HEADER_LEN;
num_ent = 0;
if (status == NoError) {
for (i = 0; i < list->num_ent; i++) {
ent = list->elist[i];
if ((ims_name && strcmp(ent->name, ims_name))
|| (ent->ims && (ent->ims->flags & F_NO_REMOTE)))
ent->status = ErrRemoteIms;
else
num_ent++;
}
if (num_ent <= 0)
status = ErrRemoteNoIms;
}
bp = strcpyx(bp, "ImsList: "); bp = strcpyx(bp, locale); *bp++ = '\n';
sprintf(var, "%ld", (long) status);
PUT_DATA("ST", var);
if (num_ent > 0) {
sprintf(var, "%ld", (long) num_ent);
PUT_DATA("ne", var);
if (list->elist[list->default_idx]->status != ErrRemoteIms) {
PUT_DATA("df", list->elist[list->default_idx]->name);
}
sprintf(var, "%ld", (long) (list->def_selmode));
PUT_DATA("sm", var);
for (i = j = 0; i < list->num_ent; i++)
if (list->elist[i]->status != ErrRemoteIms)
bp = mk_ims_ent(bp, j++, list->elist[i]);
}
bp = strcpyx(bp, "END"); *bp++ = '\n';
data_sz = bp - (confbuf + CONF_MSG_HEADER_LEN);
/* header (conf_msg_id & data_sz) */
bp = confbuf;
memset((void *) bp, (int) ' ', (size_t) CONF_MSG_HEADER_LEN);
memcpy((void *) bp, conf_msg_id, CONF_MSG_ID_LEN);
sprintf(sz_ptr, "%ld", (long) data_sz);
len = strlen(sz_ptr);
bp = confbuf + CONF_MSG_HEADER_LEN - 1 - len;
memcpy((void *) bp, (void *) sz_ptr, (size_t) len);
confbuf[CONF_MSG_HEADER_LEN - 1] = '\n';
*conflen = CONF_MSG_HEADER_LEN + data_sz;
DPR2(("mk_remote_conf(): conflen=%d data_sz=%d\n confbuf=%s",
*conflen, data_sz, confbuf));
return NoError;
}
static char *mk_ims_ent(char *bp, int idx, ImsEnt *ent)
{
ImsConf *ims = ent->ims;
char val[20];
sprintf(val, "%ld", (long) idx);
bp = strcpyx(bp, "Ent-"); bp = strcpyx(bp, val); *bp++ = '\n';
PUT_DATA("nm", ent->name);
sprintf(val, "%ld", (long) ent->status);
PUT_DATA("st", val);
sprintf(val, "%ld", (long) ims->flags);
PUT_DATA("fg", val);
sprintf(val, "%ld", (long) ims->protocols);
PUT_DATA("pr", val);
if (ent->label) { PUT_DATA("lb", ent->label); }
if (ims->timeout)
{
sprintf(val, "%ld", (long) ims->timeout);
PUT_DATA("to", val);
}
if (ims->interval)
{
sprintf(val, "%ld", (long) ims->interval);
PUT_DATA("it", val);
}
if (ims->servername) { PUT_DATA("sn", ims->servername); }
if (ims->servername2) { PUT_DATA("sN", ims->servername2); }
if (ims->classname) { PUT_DATA("cn", ims->classname); }
if (ims->property) { PUT_DATA("pp", ims->property); }
if (ims->cmd_path) { PUT_DATA("cp", ims->cmd_path); }
if (ims->cmd_param) { PUT_DATA("cr", ims->cmd_param); }
if (ims->env_set) { PUT_DATA("es", ims->env_set); }
if (ims->env_unset) { PUT_DATA("eu", ims->env_unset); }
if (ims->env_pass) { PUT_DATA("ep", ims->env_pass); }
return bp;
}
#undef PUT_DATA
static int parse_ims_list(char *ptr, ImsList *list)
{
char *bp = ptr;
char *np, *vp;
char *def_name;
int i, num_ent;
ImsEnt *ent = 0;
ImsConf *ims = NULL;
CLR(list, ImsList);
list->default_idx = -1;
list->def_selmode = SEL_MODE_NOAUTO;
list->num_ent = 0;
def_name = NULL;
num_ent = 0;
while (np = strchr(bp, '\n')) {
if (np == bp) {
bp++;
continue;
}
*np = 0;
if (strncmp(bp, "Ent-", 4) == 0) {
#ifdef DEBUG
if (list->num_ent <= 0) {
DPR(("parse_ims_list(): ImsEnt: list->num_ent=%d\n", list->num_ent));
}
#endif
if (!list->elist)
list->elist = ALLOC(list->num_ent, ImsEnt *);
if (num_ent >= list->num_ent) {
DPR(("parse_ims_list(): too many entry: '%s'\n", bp));
break;
}
ent = list->elist[num_ent] = ALLOC(1, ImsEnt);
ims = ent->ims = ALLOC(1, ImsConf);
num_ent++;
} else if (strncmp(bp, "END", 3) == 0) {
break;
} else if (bp[0] == ' ' && bp[3] == '=') {
bp++; vp = bp + 3;
/*list */
if (strncmp(bp, "ST", 2) == 0) list->status = atoi(vp);
else if (strncmp(bp, "ne", 2) == 0) list->num_ent = atoi(vp);
else if (strncmp(bp, "df", 2) == 0) def_name = vp;
else if (strncmp(bp, "sm", 2) == 0) list->def_selmode = atoi(vp);
#ifdef DEBUG
else if (!ent) {
DPR(("parse_ims_list(): ImsEnt: list->elist[%d]=%%x\n", num_ent, ent));
}
#endif
/* ent */
else if (strncmp(bp, "nm", 2) == 0) { RENEWSTR(ent->name, vp); }
else if (strncmp(bp, "lb", 2) == 0) { RENEWSTR(ent->label, vp); }
else if (strncmp(bp, "st", 2) == 0) { ent->status = atoi(vp); }
else if (strncmp(bp, "fg", 2) == 0) { ims->flags = atoi(vp); }
else if (strncmp(bp, "pr", 2) == 0) { ims->protocols = atoi(vp); }
else if (strncmp(bp, "to", 2) == 0) { ims->timeout = atoi(vp); }
else if (strncmp(bp, "it", 2) == 0) { ims->interval = atoi(vp); }
else if (strncmp(bp, "sn", 2) == 0) { RENEWSTR(ims->servername, vp); }
else if (strncmp(bp, "sN", 2) == 0) { RENEWSTR(ims->servername2, vp); }
else if (strncmp(bp, "cn", 2) == 0) { RENEWSTR(ims->classname, vp); }
else if (strncmp(bp, "pp", 2) == 0) { RENEWSTR(ims->property, vp); }
else if (strncmp(bp, "cp", 2) == 0) { RENEWSTR(ims->cmd_path, vp); }
else if (strncmp(bp, "cr", 2) == 0) { RENEWSTR(ims->cmd_param, vp); }
else if (strncmp(bp, "es", 2) == 0) { RENEWSTR(ims->env_set, vp); }
else if (strncmp(bp, "eu", 2) == 0) { RENEWSTR(ims->env_unset, vp); }
else if (strncmp(bp, "ep", 2) == 0) { RENEWSTR(ims->env_pass, vp); }
else {
DPR(("parse_ims_list(): invalid line '%s'\n", bp - 1));
}
} else {
DPR(("parse_ims_list(): invalid line '%s'\n", bp));
}
bp = np + 1;
}
#ifdef DEBUG
if (num_ent != list->num_ent) {
DPR(("parse_ims_list(): num_ent(%d) != list->num_ent(%d)\n",
num_ent, list->num_ent));
}
#endif
list->num_ent = num_ent;
list->default_idx = -1;
if (num_ent > 0) {
for (i = 0; i < num_ent; i++) { /* check indispensable entry */
ent = list->elist[i];
if (ent->status == NoError)
ent->status = check_ims_conf(ent->ims, ent->name);
}
if (def_name) { /* set default_idx */
for (i = 0; i < num_ent; i++)
if (strcmp(list->elist[i]->name, def_name) == 0) {
list->default_idx = i;
break;
}
}
}
return list->status;
}
static int parse_remote_conf(ImsList **listp, char *locale, char *confbuf, int conflen)
{
int ret = NoError;
char *bp = confbuf;
ImsList *list;
int data_sz = 0;
DPR(("parse_remote_conf(%s)\n", locale));
if (conflen < (int) CONF_MSG_HEADER_LEN /* check header */
|| strncmp(confbuf, conf_msg_id, CONF_MSG_ID_LEN)) {
ret = ErrNoImsstart;
} else {
confbuf[CONF_MSG_HEADER_LEN - 1] = 0; /* <= '\n' */
bp = confbuf + CONF_MSG_ID_LEN;
while (*bp == ' ') bp++;
if (!str_to_int(bp, &data_sz) || data_sz < 0) {
ret = ErrNoImsstart;
} else if (conflen < data_sz + (int) CONF_MSG_HEADER_LEN) {
DPR(("\tconflen(%d) != data_sz(%d) + HDR\n", conflen, data_sz));
data_sz = conflen - CONF_MSG_HEADER_LEN;
ret = ErrNoImsstart;
}
}
#ifdef DEBUG
if (ret != NoError && conflen > (int) CONF_MSG_HEADER_LEN) {
if (!confbuf[CONF_MSG_HEADER_LEN - 1])
confbuf[CONF_MSG_HEADER_LEN - 1] = '@';
confbuf[conflen] = 0;
DPR(("\tinvalid header[len=%d]: %s\n", conflen, confbuf));
}
#endif
if (ret != NoError) return ErrRemoteAction;
bp = confbuf + CONF_MSG_HEADER_LEN;
bp[data_sz] = 0;
if (strncmp(bp, "ImsList:", 8)
/* || strncmp(bp + 9, locale, strlen(locale)) */
|| !(bp = strchr(bp, '\n'))) {
return ErrRemoteAction;
}
/* confbuf[conflen] = 0; */
list = ALLOC(1, ImsList);
ret = parse_ims_list(bp, list);
if (ret != NoError || list->num_ent == 0) {
clear_ImsList(list);
FREE(list);
list = (ImsList *) 0;
ret = ErrRemoteNoIms;
}
*listp = list;
return ret;
}
int exec_remote_ims(UserSelection *sel)
{
int ret = NoError;
int n, num_opts, binc;
char *bp, *np;
char envbuf[BUFSIZ];
char tmpbuf[BUFSIZ];
char *opts[32];
char **av;
int ac;
char *ims_name = sel->name;
ImsConf *ims = sel->ent->ims;
char val[20];
DPR(("exec_remote_ims(): '%s' on %s\n", ims_name, sel->hostname));
/* build options */
n = 0;
bp = tmpbuf; tmpbuf[0] = 0;
opts[n++] = "-ims"; opts[n++] = ims_name;
opts[n++] = "-notify";
opts[n++] = "-nosave";
opts[n++] = "-nowindow";
#if 0
binc = expand_string(bp, "%L", BUFSIZ, 0);
opts[n++] = "-locale";
opts[n++] = bp; bp += binc + 1;
binc = expand_string(bp, "%d.%s", BUFSIZ, 0);
opts[n++] = "-display";
opts[n++] = bp; bp += binc = 1;
#endif
#ifdef DEBUG
if (DebugLvl >= 1) {
int i;
for (i = 0; i < DebugLvl; i++) opts[n++] = "-debug";
}
#endif
/* options */
if (OpFlag & FLAG_NOWAIT) opts[n++] = "-nowait";
if (OpFlag & FLAG_NOTIMEOUT) opts[n++] = "-notimeout";
if (OpFlag & FLAG_CONNECT) opts[n++] = "-connect";
if (Opt.Timeout > 0) {
sprintf(val, "%ld", (long)Opt.Timeout);
np = strcpyx(bp, val);
opts[n++] = "-timeout";
opts[n++] = bp; bp = np + 1;
}
if (Opt.Interval > 0) {
sprintf(val, "%ld", (long)Opt.Interval);
np = strcpyx(bp, val);
opts[n++] = "-interval";
opts[n++] = bp; bp = np + 1;
}
if (mk_ims_option(bp, sel)) {
sprintf(val, "%ld", (long)Opt.Interval);
np = strcpyx(bp, val);
opts[n++] = "-imsopt";
opts[n++] = bp; bp = np + 1;
}
bp = NULL;
opts[n] = NULL;
num_opts = n;
/* env variables */
set_remote_env(envbuf, ims->env_pass);
ret = prepare_action(ACT_RUNREMIMS, opts, num_opts);
if (ret != NoError) return ret;
ret = invoke_action(Conf.action[ACT_RUNREMIMS], sel->hostname);
change_window_status(WIN_ST_INIT);
if (ret != NoError) return ret;
ac = 0;
av = NULL;
ret = get_window_data(&ac, &av);
put_xims_log("'%s' started for %s on %s.",
sel->name, userEnv.displayname, sel->hostname);
DPR2(("exec_remote_ims(): ret=%s[%d]\n", error_name(ret), ret));
return ret;
}
int check_hostname(char *hostname)
{
int host_type = HOST_UNKNOWN;
char *local = userEnv.hostname;
struct hostent *hp;
unsigned long addr = 0L;
static unsigned long local_addr = 0L;
if (!hostname || !*hostname || strcasecmp(hostname, "local") == 0
|| strcasecmp(hostname, userEnv.hostname) == 0) {
host_type = HOST_LOCAL;
} else { /* compare inet address */
if (!local_addr) {
if ((hp = gethostbyname(local)) && hp->h_addrtype == AF_INET) {
local_addr = *((unsigned long *) hp->h_addr_list[0]);
} else {
DPR(("check_hostname(%s)\tgethostbyname() failed\n", local));
host_type = HOST_REMOTE;
}
}
if (host_type == HOST_UNKNOWN) {
if ((hp = gethostbyname(hostname)) && hp->h_addrtype == AF_INET) {
addr = *((unsigned long *) hp->h_addr_list[0]);
if (addr == local_addr)
host_type = HOST_LOCAL;
else
host_type = HOST_REMOTE;
} else {
DPR(("check_hostname(%s)\tunknown\n", hostname));
host_type = HOST_UNKNOWN;
}
}
}
DPR(("check_hostname(%s): [%s] addr=%#x, local=%#x\n", hostname,
host_type == HOST_LOCAL ? "LOCAL" :
(host_type == HOST_REMOTE ? "REMOTE" : "UNKNOWN"),
addr, local_addr));
return host_type;
}
int set_remote_confdata(char *confbuf, int conflen)
{
char *av[2];
av[0] = confbuf; av[1] = NULL;
return set_window_data(1, av);
}
int read_remote_confdata(char **confbuf, int *conflen)
{
char **av = NULL;
int ac = 0;
int ret;
ret = get_window_data(&ac, &av);
/* if (ac != 1) { FREE av[i]; return ErrBabData; } */
*confbuf = av[0];
*conflen = strlen(av[0]);
return NoError;
}
static int prepare_action(int act_typ, char **av, int ac)
{
int ret;
ret = init_window_env();
if (ret != NoError) return ret;
switch (act_typ) {
case ACT_GETREMCONF:
change_window_status(WIN_ST_REMOTE_CONF);
break;
case ACT_RUNREMIMS:
change_window_status(WIN_ST_REMOTE_RUN);
break;
default: return ErrInternal;
}
ret = set_window_data(ac, av);
return NoError;
}
int get_window_status(void)
{
long *datap;
int len = 0;
int win_st;
if (winEnv.atom_status == None || winEnv.atom_owner == None)
return WIN_ST_NONE;
if (winEnv.atom_owner == None) return WIN_ST_NONE;
#if 0
if (winEnv.atom_owner == XtWindow(winEnv.TopW))
return winEnv.status;
#endif
win_st = WIN_ST_NONE;
if (read_property(winEnv.atom_status, XA_INTEGER, 32, False,
(char **)&datap, &len) == True && len > 0) {
win_st = datap[0];
FREE(datap);
}
return win_st;
}
int change_window_status(int status)
{
if (winEnv.atom_status == None || winEnv.atom_owner == None)
return ErrInternal;
winEnv.status = status;
(void)XChangeProperty(winEnv.Dpy, winEnv.atom_owner,
winEnv.atom_status, XA_INTEGER,
32, PropModeReplace, (unsigned char *)&status, 1);
XSync(winEnv.Dpy, False);
DPR(("change_window_status(): new status=%d\n", status));
return NoError;
}
int set_window_data(int ac, char **av)
{
int i;
int nbytes;
char *buf, *bp;
if (winEnv.atom_data == None || winEnv.atom_owner == None)
return ErrInternal;
#ifdef DEBUG
if (DebugLvl >= 1) {
int i;
printf("set_window_data() av[%d] = { ", ac);
for (i = 0; i < ac; i++)
printf("\"%s\", ", av[i]);
printf("}\n");
}
#endif
for (i = 0, nbytes = 1; i < ac; i++)
nbytes += strlen(av[i]) + 1;
if (bp = buf = XtMalloc(nbytes)) { /* copy args into single buffer */
for (i = 0; i < ac; i++) {
if (av[i]) {
(void) strcpy(bp, av[i]);
bp += strlen(av[i]) + 1;
} else
*bp++ = '\0';
}
(void)XChangeProperty(winEnv.Dpy, winEnv.atom_owner,
winEnv.atom_data, XA_STRING, 8,
PropModeReplace, (unsigned char *)buf, nbytes);
XSync(winEnv.Dpy, False);
XtFree(buf);
}
DPR(("set_window_data(): len=%d data=\"%s\"\n", nbytes, buf));
return NoError;
}
int get_window_data(int *acp, char ***avp)
{
int ac;
char *data;
char **av;
int len = 0;
int i, j;
if (winEnv.atom_data == None || winEnv.atom_owner == None)
return ErrInternal;
if (read_property(winEnv.atom_data, XA_STRING, 8, True, &data, &len) != True) {
*acp = 0;
*avp = NULL;
return ErrRemoteData;
}
ac = 0; av = NULL;
if (len > 0) {
for (i = 1; i < len - 1; i++) if (data[i] == '\0') ac++;
av = (char **) ALLOC(ac + 1, char *);
j = 0;
if (ac == 1) {
av[j++] = data;
} else {
av[j++] = NEWSTR(data);
for (i = 1; i < len - 1; i++)
if (data[i] == '\0') {
av[j++] = NEWSTR(data + i + 1);
}
FREE(data);
}
av[j] = NULL;
}
#ifdef DEBUG
if (DebugLvl >= 2) {
int i;
printf("get_window_data() av[%d] = { ", ac);
for (i = 0; i < ac; i++)
printf("\"%s\", ", av[i]);
printf("}\n");
}
#endif
*acp = ac;
*avp = av;
return NoError;
}
static int read_property(Atom prop, Atom type, int format,
int del_flag, unsigned char **datapp,
unsigned long *lenp)
{
Atom realtype;
int realformat;
unsigned long bytesafter;
*datapp = NULL;
(void)XGetWindowProperty(winEnv.Dpy, winEnv.atom_owner,
prop, 0L, 1000000L, del_flag, type,
&realtype, &realformat, lenp,
&bytesafter, datapp);
if (realtype == None) {
return False;
} else if (realtype != type) { /* wrong type */
return False;
} else if (realformat != format) { /* wrong format */
if (*datapp != NULL) XtFree((char *)*datapp);
*datapp = NULL;
return False;
}
return True;
}