Link with C++ linker
[oweals/cde.git] / cde / programs / dtimsstart / file.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 /* @(#)$XConsortium: file.c /main/7 1996/05/07 13:59:24 drk $ */
24
25 #include        "xims.h"
26 #include        <fcntl.h>
27 #include        <sys/stat.h>
28
29     /* local func */
30 static void     put_selection_entry(/* fp, ent_type, is_valid, val, val2 */);
31 static void     put_ims_conf(/* fp, sel */);
32 static void     put_select_mode(/* fp, select_mode */);
33 static void     put_selection_header(/* fp */);
34 static void     put_selection_sep(/* fp */);
35 static int      user_selection_fname(/* buf, buf_len, dpy_specific */);
36
37 static char     *SelectFileFormat = NULL;
38 static bool     cmdconf_initialized = False;
39
40
41 int     create_xims_dir()
42 {
43     int         ret = NoError;
44     char        path[MAXPATHLEN];
45
46     /* if (!userEnv.homedir || !Conf.userImsDir)        return ErrNoHome; */
47            /*   get_user_environ() & read_cmd_conf() must be successfully */
48            /*   executed prior to calling this function */
49
50         /* check directory */
51     expand_string("%S", path, MAXPATHLEN, 0);
52     if (!make_user_dir(path)) {
53         setErrFile(path);
54         expand_string("%U", path, MAXPATHLEN, 0);
55         if (!make_user_dir(path))
56             return ErrDirCreate;
57         expand_string("%S", path, MAXPATHLEN, 0);
58         if (!make_user_dir(path))
59             return ErrDirCreate;
60     }
61 #if     0
62     expand_string("%T", path, MAXPATHLEN, 0);
63     if (!make_user_dir(path)) {
64         /* setErrFile(path); return ErrDirCreate; */    /* ignore */
65     }
66 #endif
67
68     if (OpMode == MODE_START) {
69         ret = init_log_file(Opt.LogPath, True);
70         if (ret != NoError && Opt.LogPath)      /* try default log file */
71             ret = init_log_file(NULL, True);
72         if (ret != NoError)                     /* try alternate log file */
73             ret = init_log_file(ALT_LOGPATH, True);
74         DPR(("Opt.LogPath='%s'\n", Opt.LogPath));
75     }
76
77     return ret;
78 }
79
80 int     init_log_file(org_path, check_size)
81     char        *org_path;
82     int         check_size;
83 {
84     char        path[MAXPATHLEN];
85     bool        log_exists = False;
86     int         fd;
87     struct stat stb;
88
89         /* check log file */    /* if not writable, ims execution will abort */
90     if (!org_path)      org_path = DEFAULT_LOGPATH;
91     expand_string(org_path, path, MAXPATHLEN, 0);
92     log_exists = stat(path, &stb) == 0; /* access(path, F_OK) == 0; */
93
94     if (log_exists) {
95         if (access(path, W_OK) == -1
96                         || stat(path, &stb) == -1 || !S_ISREG(stb.st_mode))
97             goto _err;
98
99             /* rename log file if its size is larger than MAX_LOGSIZE (20 KB) */
100         if (check_size && stb.st_size > MAX_LOGSIZE) {
101             char        save_path[MAXPATHLEN], *bp;
102             bp = strcpyx(save_path, path); strcpyx(bp, ".old");
103             if (rename(path, save_path) == 0) {
104                 log_exists = False;
105                 DPR(("init_log_file(): %s renamed.\n", path));
106             } else {
107                 DPR(("init_log_file(): rename(to: %s) failed.\n", save_path));
108             }
109         }
110     }
111     if (!log_exists) {
112         if ((fd = creat(path, 0666)) == -1)
113             goto _err;
114         (void) close(fd);
115     }
116
117     Opt.LogPath = NEWSTR(path);
118     return NoError;
119
120 _err:
121     if (Verbose > 1)    perror(path);
122     setErrFile(path);
123     return ErrFileCreate;
124 }
125
126
127 int     set_errorlog(path)
128     char        *path;
129 {
130     int fd;
131
132     /* if (!path)       return; */
133     (void) make_user_dir(dirname(path));
134     fd = open(Opt.LogPath, O_WRONLY|O_CREAT|O_APPEND, 0666);
135     if (fd >= 0) {
136         if (dup2(fd, 2) >= 0) {
137             /* LogFp = stderr; */
138             return NoError;
139         }
140         close(fd);
141     }
142
143     if (Verbose > 1)    perror(path);
144     setErrFile(path);
145     return ErrFileCreate;
146 }
147
148
149 int     read_cmd_conf()
150 {
151     char        buf[MAXPATHLEN];
152     CmdConf     *conf = &Conf;
153     char        *conf_dir, *path;
154     char        *p, *lp, *valp;
155     int         line_num, num_alias;
156     DtEnv       *dt;
157     RemoteEnv   *remote;
158     FILE        *fp;
159 # ifdef old_hpux
160     VueEnv      *vue;
161     LocaleAlias *tmp_alias[MAXIMSENT], *ap;
162 # endif /* old_hpux */
163
164     conf_dir = DTIMS_CONFDIR;
165     if (!(path = Opt.ConfPath) || !*path) {
166         if (!(path = getenv("DTIMS_STARTCONF")) || !*path) {
167             if ((p = getenv("DTIMS_CONFDIR")) && *p)
168                 conf_dir = p;
169             sprintf(path = buf, "%s/%s", conf_dir, DTIMS_CONFFILE);
170         }
171     }
172     DPR3(("read_cmd_conf(): path=%s\n", path));
173
174     if ((fp = fopen(path, "r")) == NULL) {
175         DPR3(("\tcannot open '%s'\n", path));
176 #ifdef  DEBUG2
177         DPR(("cannot open '%s' -- continue with default config\n", path));
178         goto _default;
179 #else
180         setErrFile(path);
181         return ErrFileOpen;
182 #endif
183     }
184
185     remote = conf->remote = ALLOC(1, RemoteEnv);
186     remote->disabled = remote->useRemsh = False;
187     remote->timeout = REMOTE_TIMEOUT;
188     remote->passEnv = NULL;
189
190     num_alias = 0;
191     start_tag_line(path);
192     while ((line_num = read_tag_line(fp, &lp, &valp)) > 0) {
193         if (!valp) {
194             DPR3(("\t[line=%d] no value for '%s'\n", line_num, lp));
195             continue;
196         }
197
198         if (strncmp(lp, "Ims", 3) == 0) {
199             p = lp + 3;
200             if (strncmp(p, "ConfigDir", 4) == 0) {
201                 RENEWSTR(conf->imsConfDir, valp);
202             } else if (strncmp(p, "AppDefDir", 4) == 0) {
203                 RENEWSTR(conf->imsAppDir, valp);
204             } else if (strncmp(p, "LogDir", 4) == 0) {
205                 RENEWSTR(conf->imsLogDir, valp);
206             } else if (strncmp(p, "LogFile", 4) == 0) {
207                 RENEWSTR(conf->imsLogFile, valp);
208             } else if (strncmp(p, "DirName", 3) == 0) {
209                 RENEWSTR(conf->imsDir, valp);
210             } else
211                 goto _inv;
212         } else if (strncmp(lp, "User", 4) == 0) {
213             p = lp + 4;
214             if (strncmp(p, "ImsDir", 4) == 0) {
215                 RENEWSTR(conf->userImsDir, valp);
216             } else if (strncmp(p, "TmpDir", 4) == 0) {
217                 RENEWSTR(conf->userTmpDir, valp);
218             } else if (strncmp(p, "AltTmpDir", 3) == 0) {
219                 RENEWSTR(conf->userAltDir, valp);
220             } else
221                 goto _inv;
222         } else if (strncmp(lp, "Dt", 2) == 0) {
223             p = lp + 2;
224             if (!conf->dt)      dt = conf->dt = ALLOC(1, DtEnv);
225             if (strncmp(p, "ConfigDir", 4) == 0) {
226                 RENEWSTR(dt->confDir, valp);
227             } else if (strncmp(p, "UserDir", 5) == 0) {
228                 RENEWSTR(dt->userDir, valp);
229             } else if (strncmp(p, "ResourcePath", 4) == 0) {
230                 RENEWSTR(dt->resPath, valp);
231             } else
232                 goto _inv;
233         } else if (strncmp(lp, "ImXmod.", 7) == 0) {
234             p = lp + 7;
235             if (strncmp(p, "XIM", 3) == 0) {
236                 RENEWSTR(conf->xmod[Proto_XIM], valp);
237             } else if (strncmp(p, "Ximp", 4) == 0) {
238                 RENEWSTR(conf->xmod[Proto_Ximp], valp);
239             } else if (strncmp(p, "Xsi", 3) == 0) {
240                 RENEWSTR(conf->xmod[Proto_Xsi], valp);
241 # ifdef old_hpux
242             } else if (strncmp(p, "Xhp", 3) == 0) {
243                 RENEWSTR(conf->xmod[Proto_Xhp], valp);
244 # endif /* old_hpux */
245             } else if (strncmp(p, "None", 3) == 0) {
246                 RENEWSTR(conf->xmod[Proto_None], valp);
247             } else
248                 goto _inv;
249         } else if (strncmp(lp, "ImAtom.", 7) == 0) {
250             p = lp + 7;
251             if (strncmp(p, "XIM", 3) == 0) {
252                 RENEWSTR(conf->atom[Proto_XIM], valp);
253             } else if (strncmp(p, "Ximp", 4) == 0) {
254                 RENEWSTR(conf->atom[Proto_Ximp], valp);
255             } else if (strncmp(p, "Xsi", 3) == 0) {
256                 RENEWSTR(conf->atom[Proto_Xsi], valp);
257 # ifdef old_hpux
258             } else if (strncmp(p, "Xhp", 3) == 0) {
259                 RENEWSTR(conf->atom[Proto_Xhp], valp);
260 # endif /* old_hpux */
261             } else if (strncmp(p, "None", 3) == 0) {
262                 RENEWSTR(conf->atom[Proto_None], valp);
263             } else
264                 goto _inv;
265         } else if (strncmp(lp, "Action.", 7) == 0) {
266             p = lp + 7;
267             if (strncmp(p, "GetRemoteConf", 8) == 0) {
268                 RENEWSTR(conf->action[ACT_GETREMCONF], valp);
269             } else if (strncmp(p, "RunRemoteIMs", 8) == 0) {
270                 RENEWSTR(conf->action[ACT_RUNREMIMS], valp);
271             } else
272                 goto _inv;
273         } else if (strncmp(lp, "Remote", 6) == 0) {
274             p = lp + 6;
275             if (strncmp(p, "Disabled", 3) == 0) {
276                 remote->disabled = str_to_bool(valp, False);
277             } else if (strncmp(p, "UseRemsh", 4) == 0) {
278                 remote->useRemsh = str_to_bool(valp, False);
279             } else if (strncmp(p, "Timeout", 3) == 0) {
280                 int     n = 0;
281                 if (str_to_int(valp, &n) && n >= 0)
282                     remote->timeout = n;
283             } else if (strncmp(p, "Environment", 3) == 0) {
284                 RENEWSTR(remote->passEnv, valp);
285             } else
286                 goto _inv;
287 # ifdef old_hpux
288         } else if (strncmp(lp, "Vue", 3) == 0) {
289             p = lp + 3;
290             if (!conf->vue)     vue = conf->vue = ALLOC(1, VueEnv);
291             if (strncmp(p, "ConfigDir", 4) == 0) {
292                 RENEWSTR(vue->confDir, valp);
293             } else if (strncmp(p, "UserDir", 5) == 0) {
294                 RENEWSTR(vue->userDir, valp);
295             } else if (strncmp(p, "UseLiteFile", 5) == 0) {
296                 RENEWSTR(vue->uselite, valp);
297             } else if (strncmp(p, "LiteResourcePath", 5) == 0) {
298                 RENEWSTR(vue->litePath, valp);
299             } else if (strncmp(p, "ResourcePath", 5) == 0) {
300                 RENEWSTR(vue->resPath, valp);
301             } else
302                 goto _inv;
303         } else if (strncmp(lp, "LocaleAlias", 6) == 0) {
304             ap = ALLOC(1, LocaleAlias);
305             p = valp; cut_field(valp);
306             ap->name = NEWSTR(p);
307             ap->aliases = NEWSTR(valp);
308             tmp_alias[num_alias++] = ap;
309         } else if (strncmp(lp, "XhpLocales", 3) == 0) {
310             int idx = 0;
311             p = strrchr(lp, '.');
312             if (!p)     continue;       /* invalid */
313             switch (p[1]) {
314                 case 'J':       idx = XHP_JPN; break;
315                 case 'K':       idx = XHP_KOR; break;
316                 case 'C':       idx = XHP_CHS; break;
317                 case 'T':       idx = XHP_CHT; break;
318                 default:                goto _inv;
319             }
320             if (!conf->xhp)
321                 conf->xhp = ALLOC(XHP_LANG_NUM, XhpLocale);
322             else if (conf->xhp[idx].locales) {
323                 FREE(conf->xhp[idx].locales);
324             }
325             conf->xhp[idx].type = p[1];
326             conf->xhp[idx].locales = NEWSTR(valp);
327 # endif /* old_hpux */
328         } else {
329         _inv:
330             DPR(("\t[line=%d] invalid entry '%s'\n", line_num, lp));
331         }
332     }
333     fclose(fp);
334
335 # ifdef old_hpux
336     if (num_alias > 0) {
337         conf->alias = ALLOC(num_alias + 1, LocaleAlias *);
338         memcpy((void *)conf->alias, (void *)tmp_alias,
339                                 num_alias*sizeof(LocaleAlias *));
340         conf->alias[num_alias] = (LocaleAlias *)0;
341     }
342 # endif /* old_hpux */
343
344     /* if (remote->disabled)    FREE(remote->passEnv); */
345
346 _default:
347         /* set default value unless set */
348     if (!conf->imsConfDir)      conf->imsConfDir = NEWSTR(conf_dir);
349     if (!conf->imsAppDir)       conf->imsAppDir = NEWSTR(DTIMS_APPDIR);
350     if (!conf->imsLogDir)       conf->imsLogDir = NEWSTR(DTIMS_LOGDIR);
351     if (!conf->imsLogFile)      conf->imsLogFile = NEWSTR(DTIMS_LOGFILE);
352     if (!conf->imsDir)          conf->imsDir = NEWSTR(DTIMS_IMSDIR);
353     if (!conf->userImsDir)      conf->userImsDir = NEWSTR(DTIMS_USRIMSDIR);
354     if (!conf->userTmpDir)      conf->userTmpDir = NEWSTR(DTIMS_USRTMPDIR);
355     if (!conf->userAltDir)      conf->userAltDir = NEWSTR(DTIMS_USRALTDIR);
356     if (!conf->dt)              conf->dt = ALLOC(1, DtEnv);
357     if (!conf->dt->confDir)     conf->dt->confDir = NEWSTR(DT_CONFDIR);
358     if (!conf->dt->userDir)     conf->dt->userDir = NEWSTR(DT_USERDIR);
359 # ifdef old_hpux
360     if (!conf->vue)             conf->vue = ALLOC(1, VueEnv);
361     if (!conf->vue->confDir)    conf->vue->confDir = NEWSTR(VUE_CONFDIR);
362     if (!conf->vue->userDir)    conf->vue->userDir = NEWSTR(VUE_USERDIR);
363 # endif /* old_hpux */
364     if (!conf->xmod[Proto_XIM]) conf->xmod[Proto_XIM] = NEWSTR(IM_XMOD_XIM);
365     if (!conf->xmod[Proto_Ximp]) conf->xmod[Proto_Ximp] = NEWSTR(IM_XMOD_XIMP);
366     if (!conf->xmod[Proto_Xsi]) conf->xmod[Proto_Xsi] = NEWSTR(IM_XMOD_XSI);
367     if (!conf->atom[Proto_XIM]) conf->atom[Proto_XIM] = NEWSTR(IM_ATOM_XIM);
368     if (!conf->atom[Proto_Ximp]) conf->atom[Proto_Ximp] = NEWSTR(IM_ATOM_XIMP);
369     if (!conf->atom[Proto_Xsi]) conf->atom[Proto_Xsi] = NEWSTR(IM_ATOM_XSI);
370         /* default value of {xmod,atom}[Proto_None/Xhp] is NULL */
371     if (!conf->action[ACT_GETREMCONF])
372                 conf->action[ACT_GETREMCONF] = NEWSTR(NAME_ACT_GETREMCONF);
373     if (!conf->action[ACT_RUNREMIMS])
374                 conf->action[ACT_RUNREMIMS] = NEWSTR(NAME_ACT_RUNREMIMS);
375
376     cmdconf_initialized = True;
377     return NoError;
378 }
379
380 int     expand_cmd_conf()
381 {
382     char        **pp[20 + NUM_ACTIONS], *p, buf[BUFSIZ];
383     int         i, j, n;
384     CmdConf     *conf = &Conf;
385
386 #define CHK_ADD(p)      if (strchr(p, '%')) pp[n++] = &(p);
387
388 #ifdef  DEBUG
389     if (DebugLvl > 1)   { pr_CmdConf(); }
390 #endif
391
392     n = 0;
393     CHK_ADD(conf->imsConfDir);
394     CHK_ADD(conf->imsAppDir);
395     CHK_ADD(conf->imsLogDir);
396     CHK_ADD(conf->imsLogFile);
397     CHK_ADD(conf->imsDir);
398     CHK_ADD(conf->userImsDir)
399     CHK_ADD(conf->userTmpDir)
400     CHK_ADD(conf->userAltDir)
401     for (j = 0; j < NUM_ACTIONS; j++)   CHK_ADD(conf->action[j])
402     if (conf->dt) {
403         CHK_ADD(conf->dt->confDir)
404         CHK_ADD(conf->dt->userDir)
405         CHK_ADD(conf->dt->resPath)
406     }
407 # ifdef old_hpux
408     if (conf->vue) {
409         CHK_ADD(conf->vue->confDir)
410         CHK_ADD(conf->vue->userDir)
411         CHK_ADD(conf->vue->uselite)
412         CHK_ADD(conf->vue->resPath)
413         CHK_ADD(conf->vue->litePath)
414     }
415 # endif /* old_hpux */
416         /* xmod[] & atom[] must not be expanded, since no ims selected */
417         /* remote->* should be expanded at preparation of remote exec */ 
418
419 #undef  CHK_ADD
420
421     for (i = j = 0; i < n; i++) {
422         p = *(pp[i]);
423         expand_string(*(pp[i]), buf, BUFSIZ, 0);
424 #ifdef  DEBUG
425         if (strcmp(p, buf))     j++;
426 #endif
427         FREE(p);
428         *(pp[i]) = NEWSTR(buf);
429     }
430
431     DPR(("expand_cmd_conf(): %d / %d entries modified\n", j, n));
432
433     return n;
434 }
435
436
437 int     read_imsconf(conf, ims_name, ims_fname)
438     ImsConf     *conf;
439     char        *ims_name, *ims_fname;
440 {
441     int         ret = NoError;
442     char        path[MAXPATHLEN];
443     char        *lp, *valp, *p;
444     int         len, n, line_num;
445     FILE        *fp;
446
447     if (!ims_fname)     ims_fname = ims_name;
448     len = expand_string("%I/", path, MAXPATHLEN, 0);
449     strcpyx(path + len, ims_fname);
450
451     DPR3(("read_imsconf(%s): path=%s\n", ims_name, path));
452
453     CLR(conf, ImsConf);
454     if ((fp = fopen(path, "r")) == NULL) {
455         DPR3(("\tcannot open '%s'\n", path));
456         return ErrNoImsConf;
457     }
458
459     start_tag_line(path);
460     while ((line_num = read_tag_line(fp, &lp, &valp)) > 0) {
461         if (!valp) {
462             DPR3(("\t[line=%d] no value for '%s'\n", line_num, lp));
463             continue;
464         }
465         /* valp = trim_line(valp); */
466
467         /* TYP_NAME */
468         if (strcmp(lp, "name") == 0)
469             ;   /* conf->name = NEWSTR(valp); */
470         else if (strcmp(lp, "server_name") == 0) {
471             if (p = strchr(valp, ',')) {        /* contain secondary names */
472                 conf->servername2 = NEWSTR(valp);       /* save full name */
473                 *p = 0;
474             }
475             conf->servername = NEWSTR(valp);    /* save primary name only */
476         } else if (strcmp(lp, "class_name") == 0)
477             conf->classname = NEWSTR(valp);
478         else if (strcmp(lp, "property") == 0)
479             conf->property = NEWSTR(valp);
480         /* TYP_PATH */
481         else if (strcmp(lp, "cmd_path") == 0)
482             conf->cmd_path = NEWSTR(valp);
483         /* TYP_STRING */
484         else if (strcmp(lp, "cmd_param") == 0)
485             conf->cmd_param = NEWSTR(valp);
486
487         /* TYP_NUMERIC */
488         else if (strcmp(lp, "chk_timeout") == 0) {
489             if (str_to_int(valp, &n))
490                 conf->timeout = n;
491         } else if (strcmp(lp, "chk_interval") == 0) {
492             if (str_to_int(valp, &n))   
493                 conf->interval = n;
494         }
495
496         /* TYP_BOOL */
497 #define SET_FLAG(f)     \
498         (str_to_bool(valp, False) ? (conf->flags |= (f)) : (conf->flags &= ~(f)))
499
500         else if (strcmp(lp, "no_server") == 0)
501             SET_FLAG(F_NO_SERVER);
502         else if (strcmp(lp, "no_remote") == 0)
503             SET_FLAG(F_NO_REMOTE);
504         else if (strcmp(lp, "no_option") == 0)
505             SET_FLAG(F_NO_OPTION);
506 # ifdef old_hpux
507         else if (strcmp(lp, "try_connect") == 0)
508             SET_FLAG(F_TRY_CONNECT);
509 # endif /* old_hpux */
510         else if (strcmp(lp, "has_window") == 0)
511             SET_FLAG(F_HAS_WINDOW);
512 #undef  SET_FLAG
513
514         /* TYP_NAMELIST */
515         else if (strcmp(lp, "env_set") == 0)
516             conf->env_set = NEWSTR(valp);
517         else if (strcmp(lp, "env_unset") == 0)
518             conf->env_unset = NEWSTR(valp);
519         else if (strcmp(lp, "env_pass") == 0)
520             conf->env_pass = NEWSTR(valp);
521         else if (strcmp(lp, "protocols") == 0)
522             conf->protocols = parse_protolist(valp);
523         else {
524             DPR3(("\t[line=%d] invalid entry '%s'\n", line_num, lp));
525         }
526     }
527     fclose(fp);
528
529     ret = check_ims_conf(conf, ims_name);
530     if (ret != NoError)
531         setErrFile(path);
532
533     return ret;
534 }
535
536 int     check_ims_conf(ims, ims_name)
537     ImsConf     *ims;
538     char        *ims_name;
539 {
540     int         ret = NoError;
541     char        *missing_entry = NULL;
542
543     if (strcmp(ims_name, NAME_NONE) == 0)       return NoError;
544
545     if ((ims->cmd_path) && strcmp(ims->cmd_path, NAME_BUILTIN) == 0) {
546         ims->flags |= (F_BUILTIN | F_NO_SERVER | F_NO_REMOTE | F_NO_OPTION);
547         ims->flags &= ~F_TRY_CONNECT;
548         FREE(ims->cmd_path);
549     }
550
551         /* check indispensable entry */
552     if (!ims->cmd_path && !(ims->flags & F_BUILTIN)) {
553         missing_entry = "cmd_path";
554         DPR(("read_imsconf(%s): no '%s' entry\n", ims_name, missing_entry));
555     }
556     if (!ims->servername) {
557         DPR(("read_imsconf(%s): no '%s' entry\n", ims_name, missing_entry));
558         missing_entry = "servername";
559     }
560     if (!ims->protocols) {
561         DPR(("read_imsconf(%s): no '%s' entry\n", ims_name, missing_entry));
562         missing_entry = "protocols";
563     }
564
565     if (missing_entry) {
566         setErrArg1(missing_entry);
567         ret = ErrMissEntry;
568     }
569
570     return ret;
571 }
572
573 int     read_localeconf(list, locale_name)
574     ImsList     *list;
575     char        *locale_name;
576 {
577     char        path[MAXPATHLEN];
578     char        *lp, *valp, *pp;
579     char        *def_name;
580     int         sel_mode;
581     int         len, line_num, num_ent;
582     ImsEnt      *ent, *etmp[MAXIMSENT];
583     FILE        *fp;
584     UserEnv     *uenv = &userEnv;
585
586     len = expand_string("%I/", path, MAXPATHLEN, 0);
587     if (!locale_name || !*locale_name) {
588         locale_name = uenv->real_locale ? uenv->real_locale : uenv->locale;
589     }
590     strcpyx(path + len, locale_name);
591
592     DPR3(("read_localeconf(%s): path=%s\n", locale_name, path));
593
594     CLR(list, ImsList);
595     list->status = NoError;
596     list->default_idx = -1;
597     list->def_selmode = SEL_MODE_NOAUTO;
598
599     if ((fp = fopen(path, "r")) == NULL) {
600         DPR3(("\tcannot open '%s'\n", path));
601         list->status = ErrNoLocaleConf;
602         return ErrNoLocaleConf;
603     }
604
605     def_name = NULL;
606     sel_mode = SEL_MODE_NONE;
607     num_ent = 0;
608     start_tag_line(path);
609     while ((line_num = read_tag_line(fp, &lp, &valp)) > 0) {
610
611         if (lp[0] == STR_PREFIX_CHAR) {
612             if (!valp) {
613                 DPR3(("\t[line=%d] no value for '%s'\n", line_num, lp));
614                 continue;
615             }
616             if (strncmp(lp + 1, STR_DEFAULTIMS, 3) == 0) {
617                 RENEWSTR(def_name, valp);
618             } else if (strncmp(lp + 1, STR_SELECTMODE, 3) == 0) {
619                 int     m = SEL_MODE_NONE;
620                 if (str_to_int(valp, &m) && m >= 0)
621                     sel_mode = m;
622             } else {
623                 DPR2(("\t[line=%d] invalid entry '%s'\n", line_num, lp));
624             }
625         } else {        /* ims name entry */
626             if (num_ent >= MAXIMSENT) {
627                 DPR(("\ttoo many IMS defined: '%s' ignored\n", lp));
628                 break;
629             }
630             ent = ALLOC(1, ImsEnt);
631             if (pp = strchr(lp, STR_PREFIX_CHAR)) {
632                 *pp++ = 0;
633                 if (*pp)
634                     ent->fname = NEWSTR(pp);
635                 else {
636                     DPR(("\tempty file name for '%s' -- ignored\n", lp));
637                 }
638             }
639             ent->name = NEWSTR(lp);
640             if (valp)   ent->label = NEWSTR(valp);
641             etmp[num_ent++] = ent;
642         }
643     }
644     fclose(fp);
645
646     if (num_ent) {
647         list->num_ent = num_ent;
648         list->elist = ALLOC(num_ent, ImsEnt *);
649         memcpy((void *)list->elist, (void *)etmp, num_ent*sizeof(ImsEnt *));
650
651         list->def_selmode =
652                 (sel_mode != SEL_MODE_NONE) ? sel_mode : SEL_MODE_NOAUTO;
653
654         if (def_name) {
655             int i;
656             for (i = 0; i < list->num_ent; i++)
657                 if (strcmp(def_name, list->elist[i]->name) == 0) {
658                     list->default_idx = i;
659                     break;
660             }
661             FREE(def_name);
662         }
663     }
664
665 #ifdef  DEBUG
666     if (DebugLvl > 2)   pr_ImsList(list);
667 #endif
668
669     return list->status;
670 }
671
672 int     read_user_selection(fselp, locale_name)
673     FileSel     **fselp;
674     char        *locale_name;
675 {
676     char        path[MAXPATHLEN];
677     int         ret;
678     int         dpy_specific;
679     FILE        *fp;
680     FileSel     *fsel;
681
682     dpy_specific = user_selection_fname(path, MAXPATHLEN, -1);
683
684     DPR3(("read_user_selection(): path=%s\n", path));
685
686     if ((fp = fopen(path, "r")) == NULL) {
687         DPR3(("\tcannot open '%s'\n", path));
688         /* *fselp = (FileSel *) 0; */
689         return ErrNoSelectionFile;
690     }
691
692     fsel = ALLOC(1, FileSel);
693
694     start_tag_line(path);
695     ret = read_selection_file(fsel, fp);
696     fclose(fp);
697
698     fsel->dpy_specific = dpy_specific;
699     fsel->real_fname = NEWSTR(locale_name);
700     *fselp = fsel;
701
702     return NoError;
703 }
704
705 int     read_selection_file(fsel, fp)
706     FileSel     *fsel;
707     FILE        *fp;
708 {
709     char        *lp, *valp, *vp, *p;
710     int         i, nopts, line_num;
711     int         select_mode, iconic;
712     char        *imsname, *hostname, *com_opt;
713     ImsOpt      *opts[MAXIMSENT], *op;
714
715     select_mode = SEL_MODE_NONE;
716     imsname = hostname = com_opt = NULL;
717     iconic = -1;
718     nopts = 0;
719     opts[0] = (ImsOpt *)NULL;
720
721     while ((line_num = read_tag_line(fp, &lp, &valp)) > 0) {
722         if (!valp) {
723             DPR3(("\t[line=%d] no value for '%s'\n", line_num, lp));
724             continue;
725         }
726         if (lp[0] != STR_PREFIX_CHAR) {
727             DPR3(("\t[line=%d] invalid name '%s'\n", line_num, lp));
728             continue;
729         }
730         if (strncmp(lp + 1, STR_SELECTMODE, 3) == 0) {
731             if (str_to_int(valp, &i) && i >= 0)
732                 select_mode = i;
733         } else if (strncmp(lp + 1, STR_IMSNAME, 4) == 0) {
734             vp = valp; cut_field(valp);
735             RENEWSTR(imsname, vp);
736         } else if (strncmp(lp + 1, STR_HOSTNAME, 4) == 0) {
737             vp = valp; cut_field(valp);
738             FREE(hostname);
739             if (strcmp(vp, NAME_LOCAL))
740                 hostname = NEWSTR(vp);
741         } else if (strncmp(lp + 1, STR_ICONIC, 3) == 0) {
742             if (*valp)
743                 iconic = str_to_bool(valp, False);
744         } else if (strncmp(lp + 1, STR_IMSOPTION, 4) == 0) {
745             if (p = strchr(lp + 1, STR_PREFIX_CHAR)) {  /* indiv. opt */
746                 if (nopts >= MAXIMSENT) {
747                     DPR(("\t[line=%d] too many options - '%s' ignored\n",
748                                                                 line_num, lp));
749                     continue;
750                 }
751                 if (!*(++p)) {
752                     DPR(("\t[line=%d] no ims name - '%s' ignored\n",
753                                                                 line_num, lp));
754                     continue;
755                 }
756                 for (op = 0, i = 0; i < nopts; i++)
757                     if (strcmp(p, opts[i]->ims_name) == 0) {
758                         op = opts[i];
759                         FREE(op->ims_name);
760                         FREE(op->opt_str);
761                         break;
762                     }
763                 if (!op) {
764                     op = ALLOC(1, ImsOpt);
765                     opts[nopts++] = op;
766                 }
767                 op->ims_name = NEWSTR(p);
768                 op->opt_str = NEWSTR(valp);
769             } else {                                    /* common opt */
770                 RENEWSTR(com_opt, valp);
771             }
772         } else {
773             DPR3(("\t[line=%d] unknow name '%s'\n", line_num, lp));
774         }
775     }
776
777     fsel->name = imsname;
778     fsel->hostname = hostname;
779     fsel->com_opt = com_opt;
780     fsel->select_mode = select_mode;
781     fsel->iconic = iconic;
782
783     if (nopts > 0) {
784         fsel->opts = ALLOC(nopts + 1, ImsOpt *);
785         COPY(fsel->opts, opts, nopts, ImsOpt *);
786         fsel->opts[nopts] = (ImsOpt *)0;
787     }
788
789     return NoError;
790 }
791
792 int     save_user_selection(sel, locale_name)
793     UserSelection       *sel;
794     char        *locale_name;
795 {
796     char        path[MAXPATHLEN];
797     int         dpy_specific;
798     FILE        *fp;
799     FileSel     *fsel = sel->fsel;
800
801     dpy_specific = user_selection_fname(path, MAXPATHLEN, -1);
802
803     if ((fp = fopen(path, "w")) == NULL) {
804         DPR(("\tcannot create '%s'\n", path));
805         setErrFile(path);
806         return ErrFileCreate;
807     }
808
809     put_selection_header(fp);
810     if (fsel)
811         put_select_mode(fp, fsel->select_mode);
812     put_ims_conf(fp, sel);
813     put_selection_sep(fp);
814     fclose(fp);
815
816     DPR3(("save_user_selection(): '%s' saved on '%s'\n", sel->name, path));
817
818     return NoError;
819 }
820
821 #define _SELECTMODE     0
822 #define _IMSNAME        1
823 #define _HOSTNAME       2
824 #define _ICONIC         3
825 #define _IMSOPTION      4
826 #define _IMSOPT2        5
827
828 static void     put_selection_entry(fp, ent_type, is_valid, val, val2)
829     FILE        *fp;
830     int         ent_type;
831     bool        is_valid;
832     char        *val, *val2;
833 {
834     char        *name = NULL;
835
836     switch (ent_type) {
837         case _SELECTMODE:       name = STR_SELECTMODE; break;
838         case _IMSNAME:          name = STR_IMSNAME; break;
839         case _HOSTNAME:         name = STR_HOSTNAME; break;
840         case _ICONIC:           name = STR_ICONIC; break;
841         case _IMSOPT2:
842         case _IMSOPTION:        name = STR_IMSOPTION; break;
843         /* default:             is_valid = False; */
844     }
845
846     if (!is_valid)      putc(COMMENT_CHAR, fp);
847     if (ent_type == _IMSOPT2)
848         fprintf(fp, "%c%s%c%s%c\t%s\n", STR_PREFIX_CHAR, name,
849                                 STR_PREFIX_CHAR, val2, TAG_END_CHAR, val);
850     else
851         fprintf(fp, "%c%s%c\t%s\n", STR_PREFIX_CHAR, name, TAG_END_CHAR, val);
852
853 }
854
855 static void     put_ims_conf(fp, sel)
856     FILE        *fp;
857     UserSelection       *sel;
858 {
859     char        *valp, val[20];
860
861     if ((valp = sel->name) && *valp)
862         put_selection_entry(fp, _IMSNAME, True, valp, NULL);
863     else {
864         DPR(("put_ims_conf(): no ims name\n"));
865         if (sel->fsel && (valp = sel->fsel->name) && *valp)
866             put_selection_entry(fp, _IMSNAME, False, valp, NULL);
867     }
868     if ((valp = sel->hostname) && *valp)
869         put_selection_entry(fp, _HOSTNAME, True, valp, NULL);
870     else if (sel->fsel && (valp = sel->fsel->hostname) && *valp)
871         put_selection_entry(fp, _HOSTNAME, False, valp, NULL);
872
873     if (sel->iconic != -1) {
874         sprintf(val, "%ld", (long)sel->iconic);
875         put_selection_entry(fp, _ICONIC, True, val, NULL);
876     }
877
878     if (sel->fsel && (valp = sel->fsel->com_opt) && *valp) {
879         bool    opt_valid = True;
880 #if     0
881         opt_valid = !sel->fsel->name || strcmp(sel->name, sel->fsel->name) == 0;
882 #endif
883         put_selection_entry(fp, _IMSOPTION, opt_valid, valp, NULL);
884     }
885
886     if (sel->fsel && sel->fsel->opts) {
887         ImsOpt  **op;
888         for (op = sel->fsel->opts; *op; op++)
889             put_selection_entry(fp, _IMSOPT2, True,
890                                         (*op)->opt_str, (*op)->ims_name);
891     }
892 }
893
894 static void     put_select_mode(fp, select_mode)
895     FILE        *fp;
896     int         select_mode;
897 {
898     char val[20];
899     if (select_mode != SEL_MODE_NOAUTO && select_mode != SEL_MODE_AUTO
900 #ifdef  SelectMode_ONCE
901             && select_mode != SEL_MODE_ONCE
902 #endif  /* SelectMode_ONCE */
903         )
904         select_mode = SEL_MODE_NOAUTO;
905
906     sprintf(val, "%ld", (long)select_mode);
907     put_selection_entry(fp, _SELECTMODE, True, val, NULL);
908
909 }
910
911 static void     put_selection_header(fp)
912     FILE        *fp;
913 {
914     fprintf(fp, "%s %s\n", COMMENT_CHARS, ProgramRevision);
915     if (SelectFileFormat)
916         fprintf(fp, "%s%s\n", COMMENT_CHARS, SelectFileFormat);
917 }
918
919 static void     put_selection_sep(fp)
920     FILE        *fp;
921 {
922     fprintf(fp, "%s\n", COMMENT_CHARS);
923 }
924
925
926 int     get_select_mode()
927 {
928     char        path[MAXPATHLEN];
929     char        *lp, *valp;
930     int         select_mode, dpy_specific;
931     int         n, line_num;
932     FILE        *fp;
933
934     select_mode = SEL_MODE_NONE;
935     dpy_specific = user_selection_fname(path, MAXPATHLEN, -1);
936
937     DPR3(("get_select_mode(): path=%s\n", path));
938
939     if ((fp = fopen(path, "r")) == NULL) {
940         DPR3(("\tcannot open '%s'\n", path));
941         return select_mode;
942     }
943     start_tag_line(path);
944
945     while ((line_num = read_tag_line(fp, &lp, &valp)) > 0) {
946         if (lp[0] == STR_PREFIX_CHAR
947                         && strncmp(lp + 1, STR_SELECTMODE, 3) == 0) {
948             if (str_to_int(valp, &n))
949                 select_mode = n;
950         }
951     }
952     fclose(fp);
953
954     DPR3(("get_select_mode(%s): select_mode=%d\n",
955                                 dpy_specific ? "dpy" : NULL, select_mode));
956
957     return select_mode;
958 }
959
960 int     set_select_mode(cur_mode, new_mode)
961     int         cur_mode, new_mode;
962 {
963     char        path[MAXPATHLEN];
964     int         dpy_specific;
965     FILE        *fp;
966
967     switch (new_mode) {
968         case SEL_MODE_NOAUTO:   break;
969         case SEL_MODE_AUTO:     break;
970 #ifdef  SelectMode_ONCE
971         case SEL_MODE_ONCE:     break;
972 #endif  /* SelectMode_ONCE */
973         case SEL_MODE_NONE:
974         default:                new_mode = SEL_MODE_NOAUTO; break;
975     }
976
977     dpy_specific = user_selection_fname(path, MAXPATHLEN, -1);
978
979     DPR3(("set_selection_mode(): path=%s\n", path));
980
981 #if     0
982     if (!make_user_dir(dirname(path))) {
983         setErrFile(dirname(path));
984         return ErrDirCreate;
985     }
986 #endif
987
988     if ((fp = fopen(path, "r+")) == NULL) {
989         DPR3(("\tcannot open '%s'\n", path));
990         if ((fp = fopen(path, "w")) == NULL) {
991             setErrFile(path);
992             return ErrFileCreate;
993         }
994         cur_mode = SEL_MODE_NONE;
995     }
996
997     if (cur_mode == SEL_MODE_NONE) {    /* append '@SelectMode' line */
998         fseek(fp, 0, SEEK_END);
999         put_select_mode(fp, new_mode);
1000         fclose(fp);
1001     } else {
1002         FILE    *new_fp;
1003         char    new_fname[MAXPATHLEN];
1004         char    line_buf[BUFSIZ];
1005         char    *lp, *valp;
1006         int     n, line_num, mode_line;
1007
1008         sprintf(new_fname, "%s,tmp", path);
1009         if (!(new_fp = fopen(new_fname, "w"))) {
1010             fclose(fp);
1011             DPR(("set_select_mode(): cannot create %s\n", new_fname));
1012             setErrFile(path);
1013             return ErrFileCreate;
1014         }
1015
1016         line_num = mode_line = 0;
1017         while (fgets(lp = line_buf, BUFSIZ, fp)) {
1018             line_num++;
1019             skip_white(lp);
1020             if (*lp == STR_PREFIX_CHAR) {
1021                 if (strncmp(lp + 1, STR_SELECTMODE, 3) == 0) {
1022                     if (mode_line)      continue;       /* ignore this line */
1023                     if (valp = strchr(lp, TAG_END_CHAR)) {
1024                         valp++;
1025                         skip_white(valp);
1026                         if (str_to_int(valp, &n) && n == new_mode)
1027                             mode_line = -1;
1028                     }
1029                     put_select_mode(new_fp, new_mode);
1030                     mode_line = line_num;
1031                 } else
1032                     fputs(line_buf, new_fp);
1033             } else
1034                 fputs(line_buf, new_fp);
1035         }
1036         if (!mode_line)
1037             put_select_mode(new_fp, new_mode);
1038
1039         fclose(new_fp);
1040         fclose(fp);
1041         if (mode_line == -1) {          /* not changed */
1042             (void) unlink(new_fname);
1043         } else {
1044             if (rename(new_fname, path) == -1) {
1045                 setErrFile(path);
1046                 return ErrFileCreate;
1047             }
1048         }
1049         (void) unlink(new_fname);
1050     }
1051
1052     DPR2(("set_select_mode(%s): new_mode=%d <- %d\n",
1053                         dpy_specific ? "dpy" : NULL, new_mode, cur_mode));
1054
1055     return NoError;
1056 }
1057
1058 static int      user_selection_fname(buf, buf_len, dpy_specific)
1059     char        *buf;
1060     int         buf_len, dpy_specific;
1061 {
1062     int         len;
1063     UserEnv     *uenv = &userEnv;
1064     static bool real_done = False;
1065
1066     if (Opt.UserPath) {
1067         strncpy(buf, Opt.UserPath, buf_len);
1068         buf[buf_len-1] = 0;
1069         dpy_specific = 0;
1070     } else {
1071         if (dpy_specific == -1) {
1072             len = expand_string("%S/%d", buf, buf_len, 0);
1073             dpy_specific = is_directory(buf, False) ? 1 : 0;
1074         }
1075         len = expand_string(dpy_specific ? "%S/%d/" : "%S/", buf, buf_len, 0);
1076
1077 # ifdef old_hpux
1078         if (!real_done && uenv->real_locale) {
1079             real_done = True;
1080             strcpy(buf + len, uenv->real_locale);
1081             if (!is_readable(buf, True)) {
1082                 bool    rename_done = False;
1083                 char    buf2[MAXPATHLEN], *bp;
1084
1085                 strncpy(buf2, buf, len);
1086                 bp = buf2 + len; *bp = 0;
1087                 if (strcmp(uenv->locale, uenv->real_locale)) {
1088                     strcpy(bp, uenv->locale);
1089                     if (is_readable(buf2, False)) {
1090                         rename_done = rename(buf2, buf) == 0;
1091                         DPR(("user_selection_fname(): rename(%s, %s) %s\n",
1092                                         uenv->locale, uenv->real_locale,
1093                                         rename_done ? "OK" : "Failed"));
1094                     }
1095                 }
1096
1097                 if (uenv->locale_aliases) {
1098                     char        **ap;
1099                     for (ap = uenv->locale_aliases; *ap; ap++) {
1100                         strcpy(bp, *ap);
1101                         if (!is_readable(buf2, False))  continue;
1102                         if (rename_done) {
1103                             (void) unlink(buf2);
1104                             DPR(("user_selection_fname(): unlink(%s) %s\n",
1105                                                                         *ap));
1106                         } else {
1107                             rename_done = rename(buf2, buf) == 0;
1108                             DPR(("user_selection_fname(): rename(%s, %s) %s\n",
1109                                 *ap, uenv->real_locale,
1110                                                 rename_done ? "OK" : "Failed"));
1111                         }
1112                     }
1113                 }
1114                 /* real_done = rename_done; */
1115             }
1116         }
1117 # endif /* old_hpux */
1118
1119         /* Add the CDE-generic locale name */
1120         strcpy(buf + len, real_done ? uenv->real_locale : uenv->CDE_locale);
1121         buf[buf_len-1] = 0;
1122     }
1123
1124     return dpy_specific;
1125 }
1126
1127
1128 int     parse_protolist(valp)
1129     char        *valp;
1130 {
1131     int         proto_bits = 0;
1132
1133     if (strstr(valp, "XIM"))    proto_bits |= ProtoBit(Proto_XIM);
1134     if (strstr(valp, "Ximp"))   proto_bits |= ProtoBit(Proto_Ximp);
1135     if (strstr(valp, "Xsi"))    proto_bits |= ProtoBit(Proto_Xsi);
1136 # ifdef old_hpux
1137     if (strstr(valp, "Xhp"))    proto_bits |= ProtoBit(Proto_Xhp);
1138 # endif /* old_hpux */
1139     if (strstr(valp, "None"))   proto_bits |= ProtoBit(Proto_None);
1140     return proto_bits;
1141 }
1142
1143 int     default_protocol(conf)
1144     ImsConf     *conf;
1145 {
1146     if (conf->protocols & ProtoBit(Proto_XIM))          return Proto_XIM;
1147     else if (conf->protocols & ProtoBit(Proto_Ximp))    return Proto_Ximp;
1148     else if (conf->protocols & ProtoBit(Proto_Xsi))     return Proto_Xsi;
1149 # ifdef old_hpux
1150     else if (conf->protocols & ProtoBit(Proto_Xhp))     return Proto_Xhp;
1151 # endif /* old_hpux */
1152     else                                                return Proto_None;
1153 }
1154