fa268bfe6f00b61373f48a549bb59acc7900f210
[oweals/cde.git] / cde / programs / dtimsstart / start.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 libraries 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: start.c /main/9 1998/04/06 13:36:49 mgreess $ */
24
25 #include        "xims.h"
26 #include        <signal.h>
27 #include        <sys/wait.h>
28 #include        <setjmp.h>
29 #include        <unistd.h>
30
31 #if (defined(USL) || defined(linux) || defined(CSRG_BASED)) && !defined(_NFILE)
32 #define _NFILE FOPEN_MAX
33 #endif
34
35 #if !defined(linux) && !defined(CSRG_BASED)
36 extern char     *sys_errlist[];
37 extern int      sys_nerr;
38 #endif
39
40     /* local functions */
41 static int      check_ims_opt(/* ptr */);
42 static char     *find_session_resfile(/* res_type */);
43 static int      check_selection(/* sel */);
44 static int      build_run_env(/* sel */);
45 static int      run_ims(/* sel */);
46 static int      invoke_ims(/* sel */);
47 static void     on_sig_chld(/* sig */);
48 static bool     is_ims_running(/* renv, ims */);
49 static int      settle_ims(/* sel */);
50 static Window   property_owner(/* prop_atom, prop_str */);
51 # ifdef old_hpux
52 static void     catch_alarm(/* sig */);
53 static int      try_connection(/* sel */);
54 static int      create_dummy_ic(/* xim */);
55 # endif /* old_hpux */
56
57
58 void    ximsStart()
59 {
60     int         ret;
61     UserSelection       *sel = &userSel;
62     OpStateVal  oldOpState = OpState;
63
64     DPR(("ximsStart(): OpState=%s  OpErrCode=%s[%d]\n",
65                         StateName(), error_name(OpErrCode), OpErrCode));
66
67     OpState = State_Start;
68
69 #ifdef  DEBUG
70     if (DebugLvl > 1)   pr_UserSelection(sel);
71 #endif
72
73     ret = NoError;
74     if (oldOpState == State_Select_Err) {
75         /* don't change OpErrCode */
76         OpState = State_Start_Err;
77         return;
78     }
79     if (oldOpState == State_Select_Canceled) {
80         clear_UserSelection(sel);
81         ret = ErrNoSelection;
82     } else {                                    /* save selection */
83         if (!(OpFlag & FLAG_NOSAVE) && (sel->flag & F_SELECT_CHANGED)) {
84             if (save_user_selection(sel, NULL) != NoError) {
85                 DPR(("save_user_selection(): failed\n"));
86                 put_xims_warnmsg(ErrSaveSelection, 0, 0, 0);
87                 /* ret = ErrSaveSelection; */
88             }
89         }
90     }
91
92     if (ret != NoError) {
93         OpErrCode = ret;
94         OpState = State_Start_Err;
95         return;
96     }
97
98     if ((ret = check_selection(sel)) != NoError) {
99         if (ret == ErrIsNone || ret == ErrNotRun) {
100             build_run_env(sel);         /* for make_new_environ() */
101         }
102         OpErrCode = ret;
103         OpState = State_Start_Done;
104         return;
105     }
106
107     build_run_env(sel);
108
109     if (useWINDOW())            /* initilaize Xt */
110         init_window_env();
111
112     ret = run_ims(sel);
113
114     OpErrCode = ret;
115     OpState = ret == NoError ? State_Start_Done : State_Start_Err;
116
117     return;
118 }
119
120
121 void    ximsWait()
122 {
123     OpStateVal  oldOpState = OpState;
124     UserSelection       *sel = &userSel;
125     struct timeval      interval;
126     time_t      start_tm = 0;
127     int         lapse;
128
129     DPR(("ximsWait(): OpState=%s  OpErrCode=%s[%d]\n",
130                                 StateName(), error_name(OpErrCode), OpErrCode));
131
132     OpState = State_Wait;
133
134     if (oldOpState == State_Start_Err) {
135         /* don't change OpErrCode */
136         OpState = State_Wait_Err;
137         return;
138     }
139
140     if (!is_waiting() || (OpFlag & FLAG_NOWAIT)) {
141         ximsWaitDone();
142     }
143
144     if (im_mod_available(sel->renv) != 1) {
145
146         if (useWINDOW()) {
147             xt_start_waiting(); /* never returns unless failed */
148         }
149
150             /* waiting */
151         lapse = 0;
152         interval.tv_sec = Opt.Interval / 1000;
153         interval.tv_usec = (Opt.Interval % 1000) * 1000;
154         start_tm = time((time_t) 0);
155
156         while (is_waiting()) {
157             select(0, 0, 0, 0, &interval);              /* usleep */
158             lapse = (int) time((time_t) 0) - start_tm;
159
160             if (im_mod_available(sel->renv) != 0 || lapse >= Opt.Timeout) {
161                 DPR(("ximsWait(tmout=%d): wait done (%d sec.)\n",
162                                                         Opt.Timeout, lapse));
163                 break;
164             }
165         }
166     }
167
168     ximsWaitDone();
169 }
170
171
172 void    ximsWaitDone()
173 {
174     int         ret;
175     UserSelection       *sel = &userSel;
176
177     DPR(("ximsWaitDone():\tOpState=%s  OpErrCode=%s[%d]\n",
178                                 StateName(), error_name(OpErrCode), OpErrCode));
179
180     set_sig_chld(False);
181
182     ret = sel->renv->status;
183     switch (ret) {
184         case ErrImsWaiting:
185                 sel->status = ErrImsTimeout;
186                 put_xims_log("'%s' timed-out.", sel->name, 0, 0);
187                 break;
188
189         case ErrImsWaitDone:
190                 sel->status = NoError;
191 # ifdef old_hpux
192                 if ((OpFlag & FLAG_CONNECT)
193                                 || (sel->ent->ims->flags & F_TRY_CONNECT)) {
194                     sel->status = try_connection(sel);
195                 }
196 # endif /* old_hpux */
197                 break;
198
199         case ErrImsConnecting:
200         case ErrImsConnectDone:
201                 sel->status = NoError;
202                 break;
203
204         case ErrImsAborted:
205                 /* put_xims_log("'%s' aborted.", sel->name, 0, 0); */
206         case ErrImsExecution:
207         default:
208                 sel->status = ret;
209                 break;
210     }
211
212     if (sel->status != NoError) {
213         OpErrCode = sel->status;
214         DPR(("ximsWaitDone(): OpErrCode=%s[%d]\n",
215                                         error_name(OpErrCode), OpErrCode));
216     }
217
218     restore_resources();
219
220     settle_ims(sel);            /* clear WM_COMMAND property */
221
222     OpState = OpErrCode == NoError ? State_Wait_Done : State_Wait_Err;
223
224     ximsMain();
225 }
226
227 int     is_waiting()
228 {
229     return userSel.renv && userSel.renv->status == ErrImsWaiting;
230 }
231
232 void    set_sig_chld(enable)
233     int         enable;
234 {
235     DPR(("set_sig_chld(%s)\n", enable ? "Enabled" : "Disabled"));
236     signal(SIGCHLD, enable ? on_sig_chld : SIG_IGN);
237 }
238
239 int     im_mod_available(renv)
240     RunEnv      *renv;
241 {
242     Window      owner;
243
244     if (!renv) {
245         if (!(renv = userSel.renv))
246             return -1;
247     }
248     if (renv->status != ErrImsWaiting)
249         return -1;
250
251 #ifdef  DEBUG
252     if (DebugLvl >= 1)  putc('.', LogFp), fflush(LogFp);
253 #endif
254
255     owner = property_owner(&renv->prop_atom, renv->atom_name);
256
257     if (owner != None) {
258
259 #ifdef  ReconfirmProperty
260         {
261             int wait_period = 2;        /* 2 sec. */
262
263             DPR(("im_mod_available(): [RECONFIRM] sleep(%d)\n", wait_period));
264             sleep(wait_period);
265             if (property_owner(&renv->prop_atom, renv->atom_name) == None) {
266                 DPR(("\t[RECONFIRM] owner lost\n"));
267                 return 0;
268             }
269         }
270 #endif  /* ReconfirmProperty */
271
272 #ifdef  DEBUG
273         if (DebugLvl >= 1)      putc('\n', LogFp), fflush(LogFp);
274 #endif
275         DPR2(("check_im_mod(): wait done\n"));
276         renv->status = ErrImsWaitDone;
277         return 1;
278     }
279
280     return 0;
281 }
282
283
284         /* ***** IMS options ***** */
285
286 int     mk_ims_option(ptr, sel)
287     char        *ptr;
288     UserSelection       *sel;
289 {
290     char        *bp = ptr;
291     FileSel     *fsel = sel->fsel;
292     ImsConf     *ims = sel->ent->ims;
293
294     *bp = 0;
295     if (ims->flags & F_NO_OPTION)       /* not applicable */
296         return 0;
297
298     if (fsel) {
299         if (fsel->com_opt       /* common option */
300                         && check_ims_opt(fsel->com_opt)) {
301              /* bp = strcpyx(bp, fsel->com_opt); */
302             bp += expand_string(fsel->com_opt, bp, BUFSIZ, ims);
303             *bp++ = ' ';
304         }
305         if (fsel->opts) {               /* individual option */
306             ImsOpt      **op;
307             for (op = fsel->opts; *op; op++) {
308                 if (strcmp((*op)->ims_name, sel->name) == 0
309                         && check_ims_opt((*op)->opt_str)) {
310                     /* bp = strcpyx(bp, (*op)->opt_str); */
311                     bp += expand_string((*op)->opt_str, bp, BUFSIZ, ims);
312                     *bp++ = ' ';
313                 }
314             }
315         }
316     }
317     if (Opt.ImsOption && check_ims_opt(Opt.ImsOption)) {
318         /* bp = strcpyx(bp, Opt.ImsOption); */
319         bp += expand_string(Opt.ImsOption, bp, BUFSIZ, ims);
320     }
321     if (sel->iconic > 0 && strstr(ptr, STR_ICONIC_OPT) == NULL) {
322         bp = strcpyx(bp, STR_ICONIC_OPT);
323     }
324     *bp = 0;
325
326     return (int) (bp - ptr);
327 }
328
329 static int      check_ims_opt(ptr)
330     char        *ptr;
331 {
332         /* option string must not contain any of shell's metacaharacters */
333     if (strpbrk(ptr, "`'\"#;&()|<>\n")) {
334         put_xims_log("ims option ignored: %s", ptr, 0, 0);
335         DPR(("\tshell's meta-char in option \"%s\" -- ignored\n", ptr));
336         return False;
337     }
338     return True;
339 }
340
341
342         /* ********  resource  ******** */
343
344 #define RES_TYPE_DT             0
345 #define RES_TYPE_VUE            1
346
347 static bool     resource_loaded = False;
348
349 int     load_resources()
350 {
351     int         ret;
352     int         empty;
353     char        *sess_res, *res_file;
354
355     if (resource_loaded) {
356         DPR2(("load_resources: already done -- not loaded\n"));
357         return False;
358     }
359
360     empty = !save_RM();
361     if (!empty) {               /* load if RESOURCE_MANAGER is empty */
362         DPR2(("load_resources: RESOURCE_MANGER is not empty -- not loaded\n"));
363         return False;
364     }
365
366     sess_res = res_file = NULL;
367     if (!(OpFlag & FLAG_NORESOURCE)) {
368         if (isDT()) {
369             sess_res = find_session_resfile(RES_TYPE_DT);
370         }
371 # ifdef old_hpux
372         else if (isVUE()) {
373             sess_res = find_session_resfile(RES_TYPE_VUE);
374         }
375 # endif /* old_hpux */
376         if (sess_res && !is_readable(sess_res, False)) {
377             FREE(sess_res);
378             sess_res = NULL;
379         }
380     }
381
382     if (Opt.ResourceFile && is_readable(Opt.ResourceFile, False))
383         res_file = Opt.ResourceFile;
384
385     DPR(("load_resources():\tsess='%s'  res='%s'\n", sess_res, res_file));
386
387     if (!isDT() && !sess_res && !res_file)      return False;
388     if ((ret = open_display()) != NoError)      return False;
389
390     ret = merge_RM(sess_res, res_file);
391     resource_loaded = True;
392
393     if (sess_res)       FREE(sess_res);
394
395     return ret;
396 }
397
398 int     restore_resources()
399 {
400     if (!resource_loaded) {
401         DPR2(("restore_resources: not loaded yet -- not restored\n"));
402         return False;
403     }
404     resource_loaded = False;
405     return restore_RM();
406 }
407
408 static char     *find_session_resfile(res_type)
409     int         res_type;
410 {
411     char        path[MAXPATHLEN];
412     char        **ls = (char **) 0, **pp;
413     char        *res = NULL;
414     bool        found = False;
415
416     if (res_type == RES_TYPE_DT) {      /* DT */
417         res = Conf.dt ? (Conf.dt)->resPath : NULL;
418     }
419 # ifdef old_hpux
420     else if (res_type == RES_TYPE_VUE && Conf.vue) {    /* VUE */
421         VueEnv  *vue = Conf.vue;
422         res = vue->resPath;
423         if (vue->uselite) {
424             expand_string(vue->uselite, path, MAXPATHLEN, (ImsConf *)0);
425             if (access(path, R_OK) == 0)
426                 res = vue->litePath;
427         }
428     }
429 # endif /* old_hpux */
430
431     if (!res)   return NULL;
432     if (ls = parse_strlist(res, ':')) {
433         for (pp = ls; *pp; pp++) {
434             expand_string(*pp, path, MAXPATHLEN, (ImsConf *)0);
435             if (access(path, R_OK) == 0) {
436                 found = True;
437                 break;
438             }
439         }
440         FREE_LIST(ls);
441     }
442     /* DPR2(("find_session_resfile(): '%s'\n", path)); */
443
444     if (found)
445         return NEWSTR(path);
446     return NULL;
447 }
448
449
450         /* ***** local functions ***** */
451
452 static int      check_selection(sel)
453     UserSelection       *sel;
454 {
455     int         ret = NoError;
456
457     if (!sel->name || !sel->list)
458         ret = ErrNoSelection;
459     else if (sel->ims_idx < 0 || sel->ims_idx >= sel->list->num_ent)
460         ret = ErrNoSelection;
461     else if (sel->status != NoError)
462         ret = sel->status;
463     else if (strcmp(sel->name, NAME_NONE) == 0)
464         ret = sel->status = ErrIsNone;
465     else if (sel->ent->ims->flags & F_NO_SERVER)
466         ret = sel->status = ErrNotRun;
467     else if (OpFlag & FLAG_NOSTART)
468         ret = sel->status = ErrNotRun;
469
470     return ret;
471 }
472
473 static int      build_run_env(sel)
474     UserSelection       *sel;
475 {
476     char        *p;
477     int         proto;
478     int         len;
479     int         tmout, intv;
480     char        *log_path;
481     char        *bp;
482     char        envbuf[BUFSIZ], optbuf[BUFSIZ];
483     RunEnv      *renv;
484     ImsConf     *ims = sel->ent->ims;
485     char        *cmd_param = ims->cmd_param ? ims->cmd_param : "";
486
487     renv = ALLOC(1, RunEnv);
488
489     renv->is_remote = sel->host_type == HOST_REMOTE ? True : False;
490
491         /* proto, im_mod  & atom */
492     proto = renv->proto = default_protocol(ims);
493     if (p = Conf.xmod[proto]) {
494         char    buf[BUFSIZ];
495         expand_string(p, buf, BUFSIZ, ims);
496         renv->im_mod = NEWSTR(buf);
497     }
498     if (p = Conf.atom[proto]) {
499         char    buf[BUFSIZ];
500         expand_string(p, buf, BUFSIZ, ims);
501         renv->atom_name = NEWSTR(buf);
502     } else {            /* copy im_mod, instead */
503         renv->atom_name = NEWSTR(renv->im_mod);
504 # ifdef old_hpux
505         if ((p = renv->atom_name) && strchr(p, '#')) {
506             while (p = strchr(p, '#'))          /* replace '#' with '@' */
507                 *p++ = '@';
508         }
509 # endif /* old_hpux */
510     }
511
512         /* others */
513     renv->pid = (pid_t) 0;
514     renv->status = NoError;
515     renv->wait_status = 0;
516
517     sel->renv = renv;
518
519     if (sel->status != NoError)         /* ErrIsNone or ErrNotRun */
520         return sel->status;
521
522     if (renv->is_remote)
523         return NoError;
524
525         /* command line */
526     optbuf[0] = envbuf[0] = 0;
527     log_path = Opt.LogPath;
528
529     bp = envbuf;
530         /* set XMODIFIERS */
531     bp = strcpyx(bp, "XMODIFIERS='");
532     bp = strcpyx(bp, ENV_MOD_IM);
533     bp = strcpyx(bp, renv->im_mod);
534     bp = strcpyx(bp, "'");
535     *bp = 0;
536     /* Local, LANG & DISPLAY have been already set to *environ by putenv() */
537
538         /* IMS options */
539     mk_ims_option(optbuf, sel);
540
541     /* len = sysconf(_SC_ARG_MAX) / 2; len = Max(len, BUFSIZ); */
542     len = strlen(envbuf) + strlen(ims->cmd_path)
543             + strlen(cmd_param) + strlen(optbuf) + strlen(log_path) + 40;
544
545     /* for local execution */
546     renv->cmdbuf = ALLOC(len, char);
547     sprintf(renv->cmdbuf, " %s; export XMODIFIERS; exec  %s %s %s >> %s 2>&1 ",
548         envbuf, ims->cmd_path, cmd_param, optbuf, log_path);
549
550         /* timeout & interval */
551     if (Opt.Timeout > 0)        tmout = Opt.Timeout;
552     else if (ims->timeout > 0)  tmout = ims->timeout;
553     else                        tmout = DEFAULT_TIMEOUT;
554     if (Opt.Interval > 0)       intv = Opt.Interval;
555     else if (ims->interval > 0) intv = ims->interval;
556     else                        intv = DEFAULT_INTERVAL;
557     tmout = Max(tmout,  MIN_TIMEOUT);
558     intv = Max(intv, MIN_INTERVAL);
559     if (intv/1000 > tmout)      intv = tmout * 1000;
560     /* else if (intv/10 < tmout)        intv = tmout * 10; */
561     Opt.Timeout = tmout;
562     Opt.Interval = intv;
563
564 #ifdef  DEBUG
565     if (DebugLvl >= 1)  pr_RunEnv(sel->renv);
566     DPR(("build_run_env(): Timeout=%d (sec)  Interval=%d (msec)\n",
567                                         tmout, intv));
568 #endif
569
570     return NoError;
571 }
572
573 static int      run_ims(sel)
574     UserSelection       *sel;
575 {
576     int         ret = NoError;
577
578     if ((ret = open_display()) != NoError)
579         return ret;
580
581     if (is_ims_running(sel->renv, sel->ent->ims)) {
582         sel->status = ErrImsRunning;
583         DPR(("run_ims(): '%s' is already running\n", sel->name));
584         return sel->status;
585     }
586
587     load_resources();
588
589     if (sel->renv->is_remote) {
590         /* ret = set_host_acss(sel->hostname); */
591
592         ret = exec_remote_ims(sel);
593         return ret;
594     }
595
596     ret = invoke_ims(sel);
597
598     return ret;
599 }
600
601 static int      invoke_ims(sel)
602     UserSelection       *sel;
603 {
604     RunEnv      *renv = sel->renv;
605     pid_t       pid;
606     int         i;
607
608     set_sig_chld(True);
609
610     pid = fork();
611     if (pid == (pid_t) -1) {
612         put_xims_log("fork failed [%s]",
613                 (errno <= sys_nerr) ? sys_errlist[errno] : NULL, 0, 0);
614 #ifdef  DEBUG
615         perror("fork");
616 #endif
617         return renv->status = ErrImsExecution;
618     }
619     if (pid == (pid_t) 0) {     /* child */
620         for (i = 0; i < _NFILE; i++)
621             (void) close(i);
622
623 #if defined(__osf__) || defined(CSRG_BASED)
624         setsid();
625 #else
626         setpgrp();
627 #endif
628         execl(SH_PATH, "sh", "-c", renv->cmdbuf, NULL);
629
630         put_xims_log("%s: exec failed [%s]", SH_PATH,
631                 (errno <= sys_nerr) ? sys_errlist[errno] : NULL, 0, 0);
632         /* perror(SH_PATH); */
633         sleep(1);
634         _exit(1);
635     }
636
637     /* parent */
638     renv->pid = pid;
639     renv->wait_status = 0;
640     renv->status = ErrImsWaiting;
641
642     put_xims_log("'%s' started for %s", sel->name, userEnv.displayname, 0);
643
644     DPR(("invoke_ims(%s): pid=%d\n", sel->name, pid));
645
646     return NoError;
647 }
648
649 static void     on_sig_chld(sig)
650     int sig;
651 {
652     int         wait_status = 0;
653     pid_t       pid;
654     int         cause;
655     RunEnv      *renv = userSel.renv;
656
657     errno = 0;
658     do {
659 #ifdef  _XPG4_EXTENDED
660         pid = wait3(&wait_status, WNOHANG, (struct rusage *)NULL);
661 #else
662         pid = waitpid((pid_t) -1, &wait_status, WNOHANG);
663 #endif  /* _XPG4_EXTENDED */
664     } while (pid == -1 && errno == EINTR);
665
666     DPR(("\ton_sig_chld(): pid=%d  errno=%d\n", pid, errno));
667
668     if (pid == -1)
669         return;
670
671     signal(SIGCHLD, on_sig_chld);
672
673     if (WIFEXITED(wait_status)) {
674         cause = ErrImsAborted;
675     } else if (WIFSIGNALED(wait_status)) {
676         cause = ErrImsAborted;
677     } else {    /* WIFSTOPPED(wait_status) */
678         return;
679     }
680
681     if (renv->pid == pid) {
682         if (renv->status == ErrImsWaiting || renv->status == ErrImsConnecting) {
683             renv->status = cause;
684             renv->wait_status = wait_status;
685             DPR(("on_sig_chld(): '%s' aborts (wait_status=%#x)\n",
686                                             userSel.name, wait_status));
687             put_xims_log("'%s' aborted.", userSel.name, 0, 0);
688             ximsWaitDone();
689         }
690 #ifdef  DEBUG
691         else {
692             DPR(("\tsig_chld: renv->state=%s is not ErrImsWaiting\n",
693                                     error_name(renv->status)));
694         }
695 #endif
696     }
697 #ifdef  DEBUG
698     else {
699         DPR(("\tsig_chld: pid=%d != renv->pid=%d\n", pid, renv->pid));
700     }
701 #endif
702
703     return;
704 }
705
706 static bool     is_ims_running(renv, ims)
707     RunEnv      *renv;
708     ImsConf     *ims;
709 {
710     char        *prop_str;
711     Window      owner;
712     Atom        *atomp;
713
714     if (prop_str = ims->property) {
715         atomp = (Atom *)0;
716     } else {
717         if (!(prop_str = renv->atom_name))
718             return False;
719         atomp = &renv->prop_atom;
720     }
721
722     owner = property_owner(atomp, prop_str);
723
724     DPR2(("is_ims_running(): prop='%s'[%d] owned by %#x\n",
725                                 prop_str, atomp ? *atomp : -1, owner));
726
727 #ifdef  unused
728         /* check primary server name for XIM */
729     if (owner == None && !ims->property && renv->proto == Proto_XIM
730         && ims->server_name2 && strstr(renv->atom_name, ims->server_name2) {
731         char    buf[BUFSIZ], *p;
732
733         prop_str = strcpy(buf, renv->atom_name);
734         if (p = strchr(prop_str, '=')) {
735             strcpy(p + 1, ims->servername);
736             atomp = (Atom *)0;
737             owner = property_owner(atomp, prop_str);
738             DPR2(("is_ims_running(): prop='%s'[%d] owned by %#x\n",
739                                 prop_str, atomp ? *atomp : -1, owner));
740         }
741     }
742 #endif
743
744     return owner == None ? False : True;
745 }
746
747
748 static int      settle_ims(sel)
749     UserSelection       *sel;
750 {
751
752     if (isXsession()) {
753         char    *prop_str;
754         Window  owner;
755         Atom    *atomp;
756         ImsConf *ims = sel->ent->ims;
757
758         owner = None;
759         if (prop_str = ims->property) {
760             atomp = (Atom *)0;
761             owner = property_owner(atomp, prop_str);
762         }
763 #if     0
764         else if (sel->renv) {
765             if (prop_str = sel->renv->atom_name)
766                 owner = search_clear_cmd_property(prop_str);
767         }
768 #endif
769
770         if (owner)
771             clear_cmd_property(owner);
772     }
773
774     return NoError;
775 }
776
777 static Window   property_owner(prop_atom, prop_str)
778     Atom        *prop_atom;
779     char        *prop_str;
780 {
781     Atom        property = prop_atom ? *prop_atom : None;
782
783     if (property == None) {
784         property = XInternAtom(Dpy, prop_str, True);
785         if (property == None)
786             return None;
787         if (prop_atom)
788             *prop_atom = property;
789     }
790     return XGetSelectionOwner(Dpy, property);
791 }
792
793
794 # ifdef old_hpux
795         /* ***** try_connection ***** */
796
797 #define MAX_RETRY       5
798
799 static jmp_buf  jmp_env;
800 static Window   dmy_win = 0;    /* temporary window used for XCreateIC() */
801
802 static void     catch_alarm(sig)
803     int sig;
804 {
805     signal(SIGALRM, SIG_IGN);
806     alarm(0);
807     longjmp(jmp_env, 1);
808 }
809
810 static int      try_connection(sel)
811     UserSelection       *sel;
812 {
813     RunEnv      *renv = sel->renv;
814     ImsConf     *ims = sel->ent->ims;
815     char        envbuf[BUFSIZ], *bp;
816     XIM         xim;
817     int         ic_ok, retry_cnt;
818     static char *saved_xmod = NULL;
819 #ifdef  DEBUG
820     time_t      last_time;
821 #endif
822
823     DPR(("try_connection(%s):\n", sel->name));
824
825     if (sel->status != NoError || !renv->im_mod)
826         return sel->status;
827
828     renv->status = ErrImsConnecting;
829     set_sig_chld(True);
830
831         /* set XMODIFIERS */
832     saved_xmod = NULL;
833     bp = strcpyx(envbuf, ENV_MOD_IM);
834     bp = strcpyx(bp, renv->im_mod);
835     saved_xmod = XSetLocaleModifiers(envbuf);
836     DPR(("\tXSetLocaleModifiers(%s)\n", envbuf));
837
838     ic_ok = False;
839     if (setjmp(jmp_env) == 0) {
840         signal(SIGALRM, catch_alarm);
841         alarm(Opt.Timeout);
842
843         for (retry_cnt = 0; !ic_ok && retry_cnt <= MAX_RETRY; retry_cnt++) {
844             if (retry_cnt)      sleep(retry_cnt * retry_cnt);
845
846 #ifdef  DEBUG
847             last_time = time((time_t)0);
848 #endif
849             xim = XOpenIM(Dpy, (XrmDatabase)0, ims->servername, ims->classname);
850             if (xim) {
851                 DPR(("try_connection(%d): XOpenIM() OK [%d sec.]",
852                                 retry_cnt, time((time_t)0) - last_time));
853 #ifdef  DEBUG
854                 last_time = time((time_t)0);
855 #endif
856                 ic_ok = create_dummy_ic(xim);
857                 DPR(("\tXCreateIC() %s [%d sec.]\n",
858                         ic_ok ? "OK" : "Failed", time((time_t)0) - last_time));
859                 XCloseIM(xim); xim = 0;
860             } else {
861                 DPR(("try_connection(%d): XOpenIM() failed.\n", retry_cnt));
862                 ic_ok = False;
863             }
864         }
865     } else {            /* long_jmp() by alarm [timeout] */
866         alarm(0); signal(SIGALRM, SIG_IGN);
867         DPR(("try_connection(): XOpenIM() & XCreateIC() timed-out.\n"));
868         if (dmy_win) {
869             XDestroyWindow(Dpy, dmy_win); dmy_win = 0;
870         }
871             /* neither XDestroyIC() nor XCloseIM() should be called */
872         xim = 0;
873         ic_ok = False;
874     }
875     alarm(0); signal(SIGALRM, SIG_IGN);
876
877         /* restore XMODIFIERS */
878     if (saved_xmod) {
879         DPR2(("\tXSetLocaleModifiers(save='%s')\n", saved_xmod));
880         XSetLocaleModifiers(saved_xmod);
881     }
882
883     set_sig_chld(False);
884     renv->status = ErrImsConnectDone;
885
886     return ic_ok ? NoError : ErrImsTimeout;     /* ErrImsConnect; */
887 }
888
889 static int      create_dummy_ic(xim)
890     XIM         xim;
891 {
892     int         scr;
893     XFontSet    fset;
894     XIMStyles   *im_styles;
895     XIMStyle    style;
896     XIC         ic;
897     unsigned long       fg, bg;
898     XRectangle  area;
899     XVaNestedList       status_attr;
900
901     scr = DefaultScreen(Dpy);
902     fg = BlackPixel(Dpy, scr);
903     bg = WhitePixel(Dpy, scr);
904     dmy_win = XCreateSimpleWindow(Dpy, RootWindow(Dpy, scr),
905                                                         0, 0, 1, 1, 0, bg, fg);
906
907         /* search (PreeditNothing | StatusNothing [or StatusArea]) style */
908     ic = 0;
909     style = (XIMStyle) 0;
910     im_styles = (XIMStyles *) 0;
911     if (XGetIMValues(xim, XNQueryInputStyle, &im_styles, NULL)) {
912         DPR(("create_dummy_ic(): XGetIMValues(XNQueryInutStyle) failed.\n"));
913         goto _err;
914     }
915     if (!im_styles || !im_styles->count_styles) {
916         DPR(("create_dummy_ic(): No input styles supported on IMS.\n"));
917         if (im_styles)  XFree(im_styles);
918         goto _err;
919     }
920     if ((int)im_styles->count_styles > 0) {
921         int     i, alt;
922         for (i = 0, alt = -1; i < (int)im_styles->count_styles; i++)
923             if (im_styles->supported_styles[i] & XIMPreeditNothing) {
924                 if (im_styles->supported_styles[i] & XIMStatusNothing) {
925                     style = im_styles->supported_styles[i];
926                     break;
927                 } else if (im_styles->supported_styles[i] & XIMStatusArea) {
928                     alt = i;
929                 }
930             }
931         if (!style && alt >= 0) style = im_styles->supported_styles[alt];
932         XFree(im_styles);
933     }
934     if (!style) {
935         DPR(("create_dummy_ic(): 'PreeditNothing' styles not supported.\n"));
936         goto _err;
937         /* style = XIMPreeditNothing | XIMStatusNothing; */
938     }
939
940     fset = 0;
941     status_attr = (XVaNestedList) 0;
942     if (style & XIMStatusArea) {
943         area.x = area.y = 0; area.width = area.height = 1;
944         status_attr = XVaCreateNestedList(NULL,
945                         XNArea, &area,
946                         XNForeground, fg,
947                         XNBackground, bg,
948                         XNFontSet, fset,
949                         NULL );
950     }
951
952     ic = XCreateIC(xim, XNInputStyle, style,
953                         XNClientWindow, dmy_win,
954                         XNStatusAttributes, status_attr,
955                         XNFocusWindow, dmy_win,
956                         NULL );
957
958     /* if (fset)        XFreeFontSet(Dpy, fset); */
959     if (ic)     XDestroyIC(ic);
960
961 _err:
962     if (dmy_win)        XDestroyWindow(Dpy, dmy_win);
963     dmy_win = 0;
964
965     return ic ? True : False;
966 }
967
968 # endif /* old_hpux */