Link with C++ linker
[oweals/cde.git] / cde / programs / dtimsstart / remote.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* @(#)$TOG: remote.c /main/9 1998/04/06 13:36:26 mgreess $ */
24
25 #include        "xims.h"
26
27 #include        <signal.h>
28 #include        <sys/wait.h>
29 #include        <netdb.h>
30 #include        <netinet/in.h>
31 #include        <arpa/inet.h>
32 #include        <sys/socket.h>
33 #include        <sys/errno.h>
34 #include        <setjmp.h>
35 #include        <fcntl.h>
36 #include        <limits.h>
37 #include        <X11/Xproto.h>          /* for X_ChangeHosts */
38 #include        <X11/Xatom.h>           /* for XA_STRING */
39
40 #if !defined(linux)
41 extern char     *sys_errlist[];
42 #endif
43
44 static char     *conf_msg_id = STR_CONFDATA;
45
46 #define CONF_MSG_ID_LEN         strlen(conf_msg_id)
47 #define CONF_MSG_DATASIZE_LEN   8
48 #define CONF_MSG_HEADER_LEN     (CONF_MSG_ID_LEN + CONF_MSG_DATASIZE_LEN)
49 #define CONF_MSG_SIZE_MAX       (8*1024 - 64)   /* < PIPE_BUF (PIPSIZ) */
50
51 static int      mk_remote_conf(/* list, locale, ims_name, status, confbuf, conflen */);
52 static char     *mk_ims_ent(/* bp, idx, ent */);
53 static int      parse_ims_list(/* ptr, list */);
54 static int      parse_remote_conf(/* listp, locale, confbuf, conflen */);
55 static int      prepare_action(/* act_typ, av, ac */);
56 static int      read_property(/* prop, type, format, remove, datapp, lenp */);
57
58 #if     0       /* README */
59
60 Atom:
61     _DTIMSSTART_MAIN  _DTIMSSTART_STATUS  _DTIMSSTART_DATA
62
63 Property:
64     _DTIMSSTART_STATUS (format: 32)     _DTIMSSTART_DATA (format: 8)
65
66 ClientMessage:
67     message_type:       _DTIMSSTART_STATUS
68     format:             32
69     data.l[0]:          _REMOTE_CONF or _REMOTE_RUN
70     data.l[1]:          ErrorCode
71     data.l[2-4]:        0 (unused)
72
73 Status:
74     _NONE  _INIT  _REMOTE_CONF  _REMOTE_RUN
75
76 Actions:
77     DtImsGetRemoteConf  DtImsRunRemoteIms
78
79 Procedure:
80     
81   <initialization>
82     * own _MAIN property
83     * set _STATUS property to _INIT
84     * set _DATA property to _INIT
85
86   <get remote configuratuon (DtImsGetRemoteConf)>
87     * clear _DATA property
88     * change _STATUS property to _REMOTE_CONF
89     * set additional command line options to _DATA property
90     * invoke DtImsGetRemoteConf action
91
92       [on remote dtimsstart]
93         - collect data
94         - check _STATUS property whether its value is _REMOTE_CONF
95         - set collected data to _DATA property of owner of _MAIN (Replace)
96         - send ClientMessage of ErrorCode to owner of _MAIN
97         - exit
98
99     * receive ClientMessage from remote dtimsstart (or action finished)
100     * change _STATUS property to _INIT
101     * read data from _DATA property (Delete)
102     * parse ErrCode and data (conf data or ErrorPath)
103     * update selection window
104
105   <run IMS on remote host (DtImsRunRemoteIms)>
106     * change _STATUS property to _REMOTE_RUN
107     * set additional command line options to _DATA property
108     * invoke DtImsRunRemoteIms action
109     * popdown selection window (if sucessfully invoked)
110
111       [on remote dtimsstart]
112         - check _STATUS property whether its value is _REMOTE_RUN
113         - invoke IMS and wait its preparation
114         - set ErrorPath to _DATA property of owner of _MAIN (Replace)
115         - send ClientMessage of ErrorCode to owner of _MAIN
116         - exit
117
118     * receive ClientMessage from remote dtimsstart (or action finished)
119     * change _STATUS property to _INIT
120     * parse ErrCode and data (ErrorPath)
121
122   <termination>
123     * disown _MAIN property
124     * exit
125
126 #endif  /* README */
127
128
129 #ifdef NEED_STRCASECMP
130 /*
131  * In case strcasecmp is not provided by the system here is one
132  * which does the trick.
133  */
134 static int
135 strcasecmp(register const char *s1,
136            register const char *s2)
137 {
138     register int c1, c2;
139
140     while (*s1 && *s2) {
141         c1 = isupper(*s1) ? tolower(*s1) : *s1;
142         c2 = isupper(*s2) ? tolower(*s2) : *s2;
143         if (c1 != c2)
144             return (c1 - c2);
145         s1++;
146         s2++;
147     }
148     return (int) (*s1 - *s2);
149 }
150 #endif
151
152 int     put_remote_conf(locale, ims_name)
153     char        *locale, *ims_name;
154 {
155     int         ret;
156     int         msg_status = NoError;
157     int         conflen;
158     char        confbuf[CONF_MSG_SIZE_MAX];
159     ImsList     *list = (ImsList *) 0;
160
161     DPR(("put_remote_conf(locale=%s, ims=%s)\n", locale, ims_name));
162
163     ret = get_ims_list(&list, NULL, True);
164     msg_status = ret;
165
166     ret = mk_remote_conf(list, locale, ims_name, msg_status, confbuf, &conflen);
167     if (list) {
168         clear_ImsList(list);
169         FREE(list);
170     }
171
172     ret = set_remote_confdata(confbuf, conflen);
173
174     send_dtims_msg(WIN_ST_REMOTE_CONF, ret);
175
176 #if     0
177     NotifyErrCode(NoError);
178     (void) fwrite((void *)confbuf, (size_t)conflen, (size_t)1, stdout);
179     fflush(stdout);
180 #endif
181
182     return ret;
183 }
184
185 int     get_remote_conf(listp, hostname, locale, ims_name)
186     ImsList     **listp;
187     char        *hostname, *locale, *ims_name;
188 {
189     int         ret = NoError;
190     int         conflen = 0;
191     char        *confbuf = 0;
192     char        *opts[16];
193     int         n, num_opts;
194     char        *CDE_locale = NULL;
195
196     if (!locale)
197         locale = userEnv.real_locale ? userEnv.real_locale : userEnv.locale;
198
199     CDE_locale = userEnv.CDE_locale;
200
201     if (CDE_locale)
202         DPR2(("get_remote_conf(%s, %s, %s)\n",
203                         hostname, CDE_locale, ims_name ? ims_name : "<all>"));
204     else
205         DPR2(("get_remote_conf(%s, %s, %s)\n",
206                         hostname, locale, ims_name ? ims_name : "<all>"));
207
208     n = 0;
209     /* Try to first use the CDE locale, else fallback to the locale. */
210     if (CDE_locale) {
211         opts[n++] = "-CDE_locale";
212         opts[n++] = CDE_locale;
213     }
214     else {
215         if (locale) { 
216             opts[n++] = "-locale"; 
217             opts[n++] = locale; 
218         }
219     }
220
221     if (ims_name) { 
222         opts[n++] = "-ims"; 
223         opts[n++] = ims_name; 
224     }
225 #ifdef  DEBUG
226     if (DebugLvl >= 1) {
227         int i;
228         for (i = 0; i < DebugLvl; i++)  opts[n++] = "-debug";
229     }
230 #endif
231     opts[n] = NULL;
232     num_opts = n;
233
234     ret = prepare_action(ACT_GETREMCONF, opts, num_opts);
235     if (ret != NoError) return ret;
236
237     ret = invoke_action(Conf.action[ACT_GETREMCONF], hostname);
238     change_window_status(WIN_ST_INIT);
239
240     if (ret != NoError) return ret;
241
242     ret = read_remote_confdata(&confbuf, &conflen);
243     if (ret != NoError) return ret;
244
245     if (ret == NoError) {
246         ret = parse_remote_conf(listp, locale, confbuf, conflen);
247         FREE(confbuf);
248         if (ims_name && ret == ErrRemoteNoIms)
249             ret = ErrRemoteMissIms;
250     }
251
252     return ret;
253 }
254
255
256 #define PUT_DATA(nm, val)       *bp++ = ' ', bp = strcpyx(bp, (nm)), \
257                         *bp++ = '=', bp = strcpyx(bp, (val)), *bp++ = '\n'
258
259 static int      mk_remote_conf(list, locale, ims_name, status, confbuf, conflen)
260     ImsList     *list;
261     int         status;
262     char        *locale, *ims_name, *confbuf;
263     int         *conflen;
264 {
265     int         num_ent;
266     int         i, j;
267     char        *bp;
268     int         len;
269     int         data_sz;
270     char        sz_ptr[20];
271     ImsEnt      *ent;
272     char        var[20];
273
274     DPR(("mk_remote_conf(locale=%s, ims=%s)\n", locale, ims_name));
275
276 #ifdef  DEBUG
277     if (DebugLvl >= 2 && list)  pr_ImsList(list);
278 #endif
279
280     bp = confbuf + CONF_MSG_HEADER_LEN;
281
282     num_ent = 0;
283     if (status == NoError) {
284         for (i = 0; i < list->num_ent; i++) {
285             ent = list->elist[i];
286             if ((ims_name && strcmp(ent->name, ims_name))
287                 || (ent->ims && (ent->ims->flags & F_NO_REMOTE)))
288                 ent->status = ErrRemoteIms;
289             else
290                 num_ent++;
291         }
292         if (num_ent <= 0)
293             status = ErrRemoteNoIms;
294     }
295
296     bp = strcpyx(bp, "ImsList: "); bp = strcpyx(bp, locale); *bp++ = '\n';
297     sprintf(var, "%ld", (long) status);
298     PUT_DATA("ST", var);
299
300     if (num_ent > 0) {
301         sprintf(var, "%ld", (long) num_ent);
302         PUT_DATA("ne", var);
303         if (list->elist[list->default_idx]->status != ErrRemoteIms) {
304             PUT_DATA("df", list->elist[list->default_idx]->name);
305         }
306         sprintf(var, "%ld", (long) (list->def_selmode));
307         PUT_DATA("sm", var);
308
309         for (i = j = 0; i < list->num_ent; i++)
310             if (list->elist[i]->status != ErrRemoteIms)
311                 bp = mk_ims_ent(bp, j++, list->elist[i]);
312     }
313     bp = strcpyx(bp, "END"); *bp++ = '\n';
314
315     data_sz = bp - (confbuf + CONF_MSG_HEADER_LEN);
316
317         /* header (conf_msg_id & data_sz) */
318     bp = confbuf;
319     memset((void *) bp, (int) ' ', (size_t) CONF_MSG_HEADER_LEN);
320     memcpy((void *) bp, conf_msg_id, CONF_MSG_ID_LEN);
321     sprintf(sz_ptr, "%ld", (long) data_sz);
322     len = strlen(sz_ptr);
323     bp = confbuf + CONF_MSG_HEADER_LEN - 1 - len;
324     memcpy((void *) bp, (void *) sz_ptr, (size_t) len);
325     confbuf[CONF_MSG_HEADER_LEN - 1] = '\n';
326
327     *conflen = CONF_MSG_HEADER_LEN + data_sz;
328
329     DPR2(("mk_remote_conf(): conflen=%d data_sz=%d\n confbuf=%s",
330                                                 *conflen, data_sz, confbuf));
331
332     return NoError;
333 }
334
335 static char     *mk_ims_ent(bp, idx, ent)
336     ImsEnt      *ent;
337     int         idx;
338     register char       *bp;
339 {
340     ImsConf     *ims = ent->ims;
341     char        val[20];
342
343     sprintf(val, "%ld", (long) idx);
344     bp = strcpyx(bp, "Ent-"); bp = strcpyx(bp, val); *bp++ = '\n';    
345     PUT_DATA("nm", ent->name);
346     sprintf(val, "%ld", (long) ent->status);
347     PUT_DATA("st", val);
348     sprintf(val, "%ld", (long) ims->flags);
349     PUT_DATA("fg", val);
350     sprintf(val, "%ld", (long) ims->protocols); 
351     PUT_DATA("pr", val);
352     if (ent->label)             { PUT_DATA("lb", ent->label); }
353     if (ims->timeout)           
354       { 
355         sprintf(val, "%ld", (long) ims->timeout);
356         PUT_DATA("to", val); 
357        }
358     if (ims->interval)
359       { 
360         sprintf(val, "%ld", (long) ims->interval);
361         PUT_DATA("it", val); 
362       }
363     if (ims->servername)        { PUT_DATA("sn", ims->servername); }
364     if (ims->servername2)       { PUT_DATA("sN", ims->servername2); }
365     if (ims->classname)         { PUT_DATA("cn", ims->classname); }
366     if (ims->property)          { PUT_DATA("pp", ims->property); }
367     if (ims->cmd_path)          { PUT_DATA("cp", ims->cmd_path); }
368     if (ims->cmd_param)         { PUT_DATA("cr", ims->cmd_param); }
369     if (ims->env_set)           { PUT_DATA("es", ims->env_set); }
370     if (ims->env_unset)         { PUT_DATA("eu", ims->env_unset); }
371     if (ims->env_pass)          { PUT_DATA("ep", ims->env_pass); }
372
373     return bp;
374 }
375
376 #undef  PUT_DATA
377
378 static int      parse_ims_list(ptr, list)
379     char        *ptr;
380     ImsList     *list;
381 {
382     register char       *bp = ptr;
383     char        *np, *vp;
384     char        *def_name;
385     int         i, num_ent;
386     ImsEnt      *ent = 0;
387     ImsConf     *ims;
388
389     CLR(list, ImsList);
390     list->default_idx = -1;
391     list->def_selmode = SEL_MODE_NOAUTO;
392     list->num_ent = 0;
393
394     def_name = NULL;
395     num_ent = 0;
396     while (np = strchr(bp, '\n')) {
397         if (np == bp) {
398             bp++;
399             continue;
400         }
401         *np = 0;
402         if (strncmp(bp, "Ent-", 4) == 0) {
403 #ifdef  DEBUG
404             if (list->num_ent <= 0) {
405                 DPR(("parse_ims_list(): ImsEnt: list->num_ent=%d\n", list->num_ent));
406             }
407 #endif
408             if (!list->elist)
409                 list->elist = ALLOC(list->num_ent, ImsEnt *);
410             if (num_ent >= list->num_ent) {
411                 DPR(("parse_ims_list(): too many entry: '%s'\n", bp));
412                 break;
413             }
414             ent = list->elist[num_ent] = ALLOC(1, ImsEnt);
415             ims = ent->ims = ALLOC(1, ImsConf);
416             num_ent++;
417         } else if (strncmp(bp, "END", 3) == 0) {
418             break;
419         } else if (bp[0] == ' ' && bp[3] == '=') {
420             bp++; vp = bp + 3;
421                 /*list */
422             if (strncmp(bp, "ST", 2) == 0)      list->status = atoi(vp);
423             else if (strncmp(bp, "ne", 2) == 0) list->num_ent = atoi(vp);
424             else if (strncmp(bp, "df", 2) == 0) def_name = vp;
425             else if (strncmp(bp, "sm", 2) == 0) list->def_selmode = atoi(vp);
426 #ifdef  DEBUG
427             else if (!ent) {
428                 DPR(("parse_ims_list(): ImsEnt: list->elist[%d]=%%x\n", num_ent, ent));
429             }
430 #endif
431                 /* ent */
432             else if (strncmp(bp, "nm", 2) == 0) { RENEWSTR(ent->name, vp); }
433             else if (strncmp(bp, "lb", 2) == 0) { RENEWSTR(ent->label, vp); }
434             else if (strncmp(bp, "st", 2) == 0) { ent->status = atoi(vp); }
435             else if (strncmp(bp, "fg", 2) == 0) { ims->flags = atoi(vp); }
436             else if (strncmp(bp, "pr", 2) == 0) { ims->protocols = atoi(vp); }
437             else if (strncmp(bp, "to", 2) == 0) { ims->timeout = atoi(vp); }
438             else if (strncmp(bp, "it", 2) == 0) { ims->interval = atoi(vp); }
439             else if (strncmp(bp, "sn", 2) == 0) { RENEWSTR(ims->servername, vp); }
440             else if (strncmp(bp, "sN", 2) == 0) { RENEWSTR(ims->servername2, vp); }
441             else if (strncmp(bp, "cn", 2) == 0) { RENEWSTR(ims->classname, vp); }
442             else if (strncmp(bp, "pp", 2) == 0) { RENEWSTR(ims->property, vp); }
443             else if (strncmp(bp, "cp", 2) == 0) { RENEWSTR(ims->cmd_path, vp); }
444             else if (strncmp(bp, "cr", 2) == 0) { RENEWSTR(ims->cmd_param, vp); }
445             else if (strncmp(bp, "es", 2) == 0) { RENEWSTR(ims->env_set, vp); }
446             else if (strncmp(bp, "eu", 2) == 0) { RENEWSTR(ims->env_unset, vp); }
447             else if (strncmp(bp, "ep", 2) == 0) { RENEWSTR(ims->env_pass, vp); }
448             else {
449                 DPR(("parse_ims_list(): invalid line '%s'\n", bp - 1));
450             }
451         } else {
452             DPR(("parse_ims_list(): invalid line '%s'\n", bp));
453         }
454         bp = np + 1;
455     }
456
457 #ifdef  DEBUG
458     if (num_ent != list->num_ent) {
459         DPR(("parse_ims_list(): num_ent(%d) != list->num_ent(%d)\n",
460                                                                 num_ent, list->num_ent));
461     }
462 #endif
463
464     list->num_ent = num_ent;
465     list->default_idx = -1;
466     if (num_ent > 0) {
467         for (i = 0; i < num_ent; i++) {         /* check indispensable entry */
468             ent = list->elist[i];
469             if (ent->status == NoError)
470                 ent->status = check_ims_conf(ent->ims, ent->name);
471         }
472
473         if (def_name) {                         /* set default_idx */
474             for (i = 0; i < num_ent; i++)
475                 if (strcmp(list->elist[i]->name, def_name) == 0) {
476                     list->default_idx = i;
477                     break;
478                 }
479         }
480     }
481
482     return list->status;
483 }
484
485
486 static int      parse_remote_conf(listp, locale, confbuf, conflen)
487     ImsList     **listp;
488     char        *locale, *confbuf;
489     int         conflen;
490 {
491     int         ret = NoError;
492     char        *bp = confbuf;
493     ImsList     *list;
494     int         data_sz = 0;
495
496     DPR(("parse_remote_conf(%s)\n", locale));
497
498     if (conflen < (int) CONF_MSG_HEADER_LEN             /* check header */
499                 || strncmp(confbuf, conf_msg_id, CONF_MSG_ID_LEN)) {
500             ret = ErrNoImsstart;
501     } else {
502         confbuf[CONF_MSG_HEADER_LEN - 1] = 0;   /* <= '\n' */
503         bp = confbuf + CONF_MSG_ID_LEN;
504         while (*bp == ' ')      bp++;
505         if (!str_to_int(bp, &data_sz) || data_sz < 0) {
506             ret = ErrNoImsstart;
507         } else if (conflen < data_sz + (int) CONF_MSG_HEADER_LEN) {
508             DPR(("\tconflen(%d) != data_sz(%d) + HDR\n", conflen, data_sz));
509             data_sz =  conflen - CONF_MSG_HEADER_LEN;
510             ret = ErrNoImsstart;
511         }
512     }
513
514 #ifdef  DEBUG
515     if (ret != NoError && conflen > (int) CONF_MSG_HEADER_LEN) {
516         if (!confbuf[CONF_MSG_HEADER_LEN - 1])
517             confbuf[CONF_MSG_HEADER_LEN - 1] = '@';
518         confbuf[conflen] = 0;
519         DPR(("\tinvalid header[len=%d]: %s\n", conflen, confbuf));
520     }
521 #endif
522     if (ret != NoError) return ErrRemoteAction;
523
524     bp = confbuf + CONF_MSG_HEADER_LEN;
525     bp[data_sz] = 0;
526     if (strncmp(bp, "ImsList:", 8)
527     /*          || strncmp(bp + 9, locale, strlen(locale)) */
528                 || !(bp = strchr(bp, '\n'))) {
529         return ErrRemoteAction;
530     }
531     /* confbuf[conflen] = 0; */
532
533     list = ALLOC(1, ImsList);
534     ret = parse_ims_list(bp, list);
535
536     if (ret != NoError || list->num_ent == 0) {
537         clear_ImsList(list);
538         FREE(list);
539         list = (ImsList *) 0;
540         ret = ErrRemoteNoIms;
541     }
542     *listp = list;
543
544     return ret;
545 }
546
547
548 int     exec_remote_ims(sel)
549     UserSelection       *sel;
550 {
551     int         ret = NoError;
552     int         n, num_opts, binc;
553     char        *bp, *np;
554     char        envbuf[BUFSIZ];
555     char        tmpbuf[BUFSIZ];
556     char        *opts[32];
557     char        **av;
558     int         ac;
559     char        *ims_name = sel->name;
560     ImsConf     *ims = sel->ent->ims;
561     char        val[20];
562
563     DPR(("exec_remote_ims(): '%s' on %s\n", ims_name, sel->hostname));
564
565         /* build options */
566     n = 0;
567     bp = tmpbuf; tmpbuf[0] = 0;
568
569     opts[n++] = "-ims"; opts[n++] = ims_name;
570     opts[n++] = "-notify";
571     opts[n++] = "-nosave";
572     opts[n++] = "-nowindow";
573
574 #if     0
575     binc = expand_string(bp, "%L", BUFSIZ, 0);
576     opts[n++] = "-locale";
577     opts[n++] = bp; bp += binc + 1;
578     binc = expand_string(bp, "%d.%s", BUFSIZ, 0);
579     opts[n++] = "-display";
580     opts[n++] = bp; bp += binc = 1;
581 #endif
582
583 #ifdef  DEBUG
584     if (DebugLvl >= 1) {
585         int i;
586         for (i = 0; i < DebugLvl; i++)  opts[n++] = "-debug";
587     }
588 #endif
589
590         /* options */
591     if (OpFlag & FLAG_NOWAIT)           opts[n++] = "-nowait";
592     if (OpFlag & FLAG_NOTIMEOUT)        opts[n++] = "-notimeout";
593     if (OpFlag & FLAG_CONNECT)          opts[n++] = "-connect";
594     if (Opt.Timeout > 0) {
595         sprintf(val, "%ld", (long)Opt.Timeout);
596         np = strcpyx(bp, val);
597         opts[n++] = "-timeout";
598         opts[n++] = bp; bp = np + 1;
599     }
600     if (Opt.Interval > 0) {
601         sprintf(val, "%ld", (long)Opt.Interval);
602         np = strcpyx(bp, val);
603         opts[n++] = "-interval";
604         opts[n++] = bp; bp = np + 1;
605     }
606     if (mk_ims_option(bp, sel)) {
607         sprintf(val, "%ld", (long)Opt.Interval);
608         np = strcpyx(bp, val);
609         opts[n++] = "-imsopt";
610         opts[n++] = bp; bp = np + 1;
611     }
612     bp = NULL;
613     opts[n] = NULL;
614     num_opts = n;
615
616         /* env variables */
617     set_remote_env(envbuf, ims->env_pass);
618
619     ret = prepare_action(ACT_RUNREMIMS, opts, num_opts);
620     if (ret != NoError) return ret;
621
622     ret = invoke_action(Conf.action[ACT_RUNREMIMS], sel->hostname);
623     change_window_status(WIN_ST_INIT);
624
625     if (ret != NoError) return ret;
626
627     if (ret == NoError) {
628         ac = 0; av = NULL;
629         ret = get_window_data(&ac, &av);
630         ret = NoError;
631
632         if (ret != NoError) return ret;
633     }
634
635     if (ret == NoError) {
636         put_xims_log("'%s' started for %s on %s.",
637                                 sel->name, userEnv.displayname, sel->hostname);
638     }
639
640     DPR2(("exec_remote_ims(): ret=%s[%d]\n", error_name(ret), ret));
641
642     return ret;
643 }
644
645
646 int     check_hostname(hostname)
647     char        *hostname;
648 {
649     int         host_type = HOST_UNKNOWN;
650     char        *local = userEnv.hostname;
651     struct hostent      *hp;
652     unsigned long       addr = 0L;
653     static unsigned long        local_addr = 0L;
654
655     if (!hostname || !*hostname || strcasecmp(hostname, "local") == 0
656                         || strcasecmp(hostname, userEnv.hostname) == 0) {
657         host_type =  HOST_LOCAL;
658     } else {            /* compare inet address */
659         if (!local_addr) {
660             if ((hp = gethostbyname(local)) && hp->h_addrtype == AF_INET) {
661                 local_addr = *((unsigned long *) hp->h_addr_list[0]);
662             } else {
663                 DPR(("check_hostname(%s)\tgethostbyname() failed\n", local));
664                 host_type = HOST_REMOTE;
665             }
666         }
667         if (host_type == HOST_UNKNOWN) {
668             if ((hp = gethostbyname(hostname)) && hp->h_addrtype == AF_INET) {
669                 addr = *((unsigned long *) hp->h_addr_list[0]);
670                 if (addr == local_addr)
671                     host_type = HOST_LOCAL;
672                 else
673                     host_type = HOST_REMOTE;
674             } else {
675                 DPR(("check_hostname(%s)\tunknown\n", hostname));
676                 host_type = HOST_UNKNOWN;
677             }
678         }
679     }
680
681     DPR(("check_hostname(%s): [%s]  addr=%#x, local=%#x\n", hostname,
682                         host_type == HOST_LOCAL ? "LOCAL" :
683                         (host_type == HOST_REMOTE ? "REMOTE" : "UNKNOWN"),
684                         addr, local_addr));
685
686     return host_type;
687 }
688
689
690
691 int     set_remote_confdata(confbuf, conflen)
692     char *confbuf;
693     int conflen;
694 {
695     char *av[2];
696
697     av[0] = confbuf; av[1] = NULL;
698
699     return set_window_data(1, av);
700 }
701
702 int     read_remote_confdata(confbuf, conflen)
703     char **confbuf;
704     int *conflen;
705 {
706     char **av = NULL;
707     int ac = 0;
708     int ret;
709
710     ret = get_window_data(&ac, &av);
711     /* if (ac != 1) {  FREE  av[i]; return ErrBabData; } */
712
713     *confbuf = av[0];
714     *conflen = strlen(av[0]);
715
716     return NoError;
717 }
718
719
720 static int      prepare_action(act_typ, av, ac)
721     int act_typ;
722     char        **av;
723     int         ac;
724 {
725     int ret;
726
727     ret = init_window_env();
728     if (ret != NoError) return ret;
729
730     switch (act_typ) {
731         case ACT_GETREMCONF:
732                 change_window_status(WIN_ST_REMOTE_CONF);
733                 break;
734
735         case ACT_RUNREMIMS:
736                 change_window_status(WIN_ST_REMOTE_RUN);
737                 break;
738
739         default:        return ErrInternal;
740     }
741
742     ret = set_window_data(ac, av);
743
744     return NoError;
745 }
746
747
748 int     get_window_status()
749 {
750     long        *datap;
751     int         len = 0;
752     int         win_st;
753
754     if (winEnv.atom_status == None || winEnv.atom_owner == None)
755         return WIN_ST_NONE;
756
757     if (winEnv.atom_owner == None)      return WIN_ST_NONE;
758 #if     0
759     if (winEnv.atom_owner == XtWindow(winEnv.TopW))
760         return winEnv.status;
761 #endif
762
763     win_st = WIN_ST_NONE;
764     if (read_property(winEnv.atom_status, XA_INTEGER, 32, False,
765             (char **)&datap, &len) == True && len > 0) {
766             win_st = datap[0];
767             FREE(datap);
768     }
769     return win_st;
770 }
771
772 int     change_window_status(status)
773     int status;
774 {
775     if (winEnv.atom_status == None || winEnv.atom_owner == None)
776         return ErrInternal;
777
778     winEnv.status = status;
779
780     (void)XChangeProperty(winEnv.Dpy, winEnv.atom_owner,
781                 winEnv.atom_status, XA_INTEGER,
782                 32, PropModeReplace, (unsigned char *)&status, 1);
783
784     XSync(winEnv.Dpy, False);
785
786     DPR(("change_window_status(): new status=%d\n", status));
787     return NoError;
788 }
789
790 int     set_window_data(ac, av)
791     int ac;
792     char **av;
793 {
794     register int i;
795     register int nbytes;
796     register char *buf, *bp;
797
798     if (winEnv.atom_data == None || winEnv.atom_owner == None)
799         return ErrInternal;
800
801 #ifdef  DEBUG
802     if (DebugLvl >= 1) {
803         int i;
804         printf("set_window_data() av[%d] = { ", ac);
805         for (i = 0; i < ac; i++)        
806             printf("\"%s\", ", av[i]);
807         printf("}\n");
808     }
809 #endif
810
811     for (i = 0, nbytes = 1; i < ac; i++)
812         nbytes += strlen(av[i]) + 1;
813     if (bp = buf = XtMalloc(nbytes)) {  /* copy args into single buffer */
814         for (i = 0; i < ac; i++) {
815             if (av[i]) {
816                 (void) strcpy(bp, av[i]);
817                 bp += strlen(av[i]) + 1;
818             } else
819                 *bp++ = '\0';
820         }
821         (void)XChangeProperty(winEnv.Dpy, winEnv.atom_owner,
822                         winEnv.atom_data, XA_STRING, 8,
823                         PropModeReplace, (unsigned char *)buf, nbytes);
824         XSync(winEnv.Dpy, False);
825         XtFree(buf);
826     }
827     DPR(("set_window_data(): len=%d data=\"%s\"\n", nbytes, buf));
828
829     return NoError;
830 }
831
832
833 int     get_window_data(acp, avp)
834     int *acp;
835     char ***avp;
836 {
837     int ac;
838     char *data;
839     char **av;
840     int len = 0;
841     int i, j;
842
843     if (winEnv.atom_data == None || winEnv.atom_owner == None)
844         return ErrInternal;
845
846     if (read_property(winEnv.atom_data, XA_STRING, 8, True, &data, &len) != True) {
847         *acp = 0;
848         *avp = NULL;
849         return ErrRemoteData;
850     }
851
852     ac = 0; av = NULL;
853     if (len > 0) {
854         for (i = 1; i < len - 1; i++)   if (data[i] == '\0')    ac++;
855         av = (char **) ALLOC(ac + 1, char *);
856
857         j = 0;
858         if (ac == 1) {
859             av[j++] = data;
860         } else {
861             av[j++] = NEWSTR(data);
862             for (i = 1; i < len - 1; i++)
863                 if (data[i] == '\0') {
864                     av[j++] = NEWSTR(data + i + 1);
865                 }
866             FREE(data);
867         }
868         av[j] = NULL;
869     }
870
871 #ifdef  DEBUG
872     if (DebugLvl >= 2) {
873         int i;
874         printf("get_window_data() av[%d] = { ", ac);
875         for (i = 0; i < ac; i++)        
876             printf("\"%s\", ", av[i]);
877         printf("}\n");
878     }
879 #endif
880
881     *acp = ac;
882     *avp = av;
883
884     return NoError;
885 }
886
887
888 static int      read_property(prop, type, format, del_flag, datapp, lenp)
889     Atom prop;
890     Atom type;
891     int format;
892     int del_flag;
893     unsigned char **datapp;
894     unsigned long *lenp;
895 {
896     Atom realtype;
897     int realformat;
898     unsigned long bytesafter;
899
900     *datapp = NULL;
901
902     (void)XGetWindowProperty(winEnv.Dpy, winEnv.atom_owner,
903                              prop, 0L, 1000000L, del_flag, type,
904                              &realtype, &realformat, lenp,
905                              &bytesafter, datapp);
906
907     if (realtype == None) {     
908         return False;
909     } else if (realtype != type) {      /* wrong type */
910         return False;
911     } else if (realformat != format) {  /* wrong format */
912         if (*datapp != NULL) XtFree((char *)*datapp);
913         *datapp = NULL;
914         return False;
915     }
916     return True;
917 }
918