dthelp: Change to ANSI function definitions
[oweals/cde.git] / cde / programs / dtstyle / I18nEnv.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: I18nEnv.c /main/4 1997/08/11 12:31:10 samborn $ */
24 /*
25  * (c) Copyright 1996 Digital Equipment Corporation.
26  * (c) Copyright 1996 Hewlett-Packard Company.
27  * (c) Copyright 1996 International Business Machines Corp.
28  * (c) Copyright 1996 Sun Microsystems, Inc.
29  * (c) Copyright 1996 Novell, Inc. 
30  * (c) Copyright 1996 FUJITSU LIMITED.
31  * (c) Copyright 1996 Hitachi.
32  */
33 /************************************<+>*************************************
34  ****************************************************************************
35  **
36  **   File:        I18nEnv.c
37  **
38  **   Description: Controls the Dtstyle I18N component interaction with 
39  **                the environment.
40  **
41  **
42  ****************************************************************************
43  ************************************<+>*************************************/
44
45 /*+++++++++++++++++++++++++++++++++++++++*/
46 /* include files                         */
47 /*+++++++++++++++++++++++++++++++++++++++*/
48
49 #include <pwd.h>
50 #include <X11/Xlib.h>
51 #include <X11/Intrinsic.h>
52
53 #include <DtHelp/LocaleXlate.h>  /* for locale equivalence between platforms */
54
55 #include "Main.h"
56 #include "I18nEnv.h"
57
58 /*+++++++++++++++++++++++++++++++++++++++*/
59 /* include extern functions              */
60 /*+++++++++++++++++++++++++++++++++++++++*/
61
62 /*+++++++++++++++++++++++++++++++++++++++*/
63 /* Local #defines                        */
64 /*+++++++++++++++++++++++++++++++++++++++*/
65
66
67 /*+++++++++++++++++++++++++++++++++++++++*/
68 /* Internal Functions                    */
69 /*+++++++++++++++++++++++++++++++++++++++*/
70
71 static int GetUserEnv(I18nEnv *env);
72 static int FindCDELocaleName(UserEnv *uenv);
73 static int GetUserIMSelectionFile(I18nEnv *env);
74 static int GetUserFileName(I18nEnv *env);
75 static int ReadImSelectionFile(FileSel *fsel, FILE *fp);
76 static int GetImsList(I18nEnv *env, char *hostname);
77 static void TimeOutProc(XtPointer client_data, XtIntervalId* timer);
78 static void ReadPipe(XtPointer client_data, int *fd, XtInputId *id);
79 static int ProcessBuf(char *savebuf, I18nEnv *env);
80 static int CheckHostname(I18nEnv *env, char *hostname);
81 static void PutSelectMode(FILE *fp, int start_mode);
82 static void PutImsName(FILE *fp, char *im_name);
83 static void PutHostname(FILE *fp, char *hostname);
84 static void PutSelectionEntry(FILE *fp, char *tag, char *value);
85
86
87 /*+++++++++++++++++++++++++++++++++++++++*/
88 /* Internal Variables                    */
89 /*+++++++++++++++++++++++++++++++++++++++*/
90
91 /*+++++++++++++++++++++++++++++++++++++++*/
92 /* Global Variables                      */
93 /*+++++++++++++++++++++++++++++++++++++++*/
94
95 I18nEnv i18n_env;
96
97
98 /*+++++++++++++++++++++++++++++++++++++++*/
99 /* strcasecmp                            */
100 /*+++++++++++++++++++++++++++++++++++++++*/
101
102 #ifdef NEED_STRCASECMP
103 /*
104  * In case strcasecmp is not provided by the system here is one
105  * which does the trick.
106  */
107 static int
108 strcasecmp(register const char *s1,
109            register const char *s2)
110 {
111     register int c1, c2;
112
113     while (*s1 && *s2) {
114         c1 = isupper(*s1) ? tolower(*s1) : *s1;
115         c2 = isupper(*s2) ? tolower(*s2) : *s2;
116         if (c1 != c2)
117             return (c1 - c2);
118         s1++;
119         s2++;
120     }
121     return (int) (*s1 - *s2);
122 }
123 #endif
124
125
126 /*+++++++++++++++++++++++++++++++++++++++*/
127 /* _DtI18nGetEnvValues                   */
128 /*+++++++++++++++++++++++++++++++++++++++*/
129
130 int
131 _DtI18nGetEnvValues(
132     I18nEnv *env
133 )
134 {
135     int ret = NoError;
136
137     /* Get the user environment */
138     env->user_env = (UserEnv *) XtMalloc(sizeof(UserEnv));    
139     ret = GetUserEnv(env);
140
141     /* Get the user selection stored in the IM Selection File */
142     if (ret == NoError) {
143         env->file_sel = (FileSel *) XtMalloc(sizeof(FileSel));    
144         ret = GetUserIMSelectionFile(env);
145     }
146
147     /* Alloc the user selection */
148     env->ims_sel = (ImsSel *) XtMalloc(sizeof(ImsSel)); 
149     env->ims_sel->ims_list = NULL;
150     env->ims_sel->ims_list_size = 0 ;
151     env->ims_sel->host_name = NULL ;
152
153     /* Get the Input Method available on the selected host.
154      * The selected host is the one stored in the IMS Selection File.
155      */
156     if (ret == NoError)
157         ret = _DtI18nGetImList(env, env->file_sel->hostname);
158
159     return ret;
160 }
161
162 /*+++++++++++++++++++++++++++++++++++++++*/
163 /* GetUserEnv                            */
164 /*+++++++++++++++++++++++++++++++++++++++*/
165 static int
166 GetUserEnv(
167      I18nEnv *env
168 )
169 {
170     UserEnv *uenv = env->user_env ;
171     int ret = NoError;
172     char buf[BUFSIZ], *p;
173
174     /* get the host name */
175     gethostname(buf, BUFSIZ);
176     uenv->localhostname = XtNewString(buf);
177
178     /* get the user name */
179     if ((p = getlogin()) == NULL) {
180       struct passwd *pw;
181
182       pw = getpwuid(getuid());
183       p = pw->pw_name;
184     }
185     
186     uenv->username = XtNewString(p);
187
188     /* get the display name */
189     uenv->displayname = XtNewString(XDisplayString(XtDisplay(env->shell)));
190     
191     /* get the locale */
192     if ((p = getenv("LANG")) && *p)
193         uenv->locale = XtNewString(p);
194     else
195         return ErrNoLocale;
196     
197     /* find the CDE generic locale name */
198     if (FindCDELocaleName(uenv) != NoError)
199         return ErrNoCDELocale;
200     
201     /* get the home directory */
202     if ((p = getenv("HOME")) && *p)
203         uenv->homedir = XtNewString(p);
204     else 
205         ret = ErrNoHome;
206
207     return ret;
208 }
209
210 static int
211 FindCDELocaleName(
212     UserEnv *uenv
213 )
214 {
215    _DtXlateDb db = NULL;
216    int  ret = NoError;
217    char plat[_DtPLATFORM_MAX_LEN];
218    int  execver;
219    int  compver;
220
221    ret = _DtLcxOpenAllDbs(&db);
222
223    if (ret == NoError)
224        ret = _DtXlateGetXlateEnv(db, plat, &execver, &compver);
225
226    if (ret == NoError)
227        ret = _DtLcxXlateOpToStd(db, plat, compver, DtLCX_OPER_SETLOCALE,
228                                 uenv->locale, &uenv->CDE_locale,
229                                 NULL, NULL, NULL);
230    if (ret == NoError)
231        ret = _DtLcxCloseDb(&db);
232
233    return ret;
234 }
235
236 static int
237 GetUserIMSelectionFile(
238     I18nEnv *env
239 )
240 {
241     int         ret = NoError;
242     FILE        *fp;
243
244     ret = GetUserFileName(env);
245     
246         if (ret == NoError) {
247                 /* Look if this file is readable */
248                 if ((fp = fopen(env->file_sel->fname, "r")) == NULL) {
249                         env->file_sel->start_mode = -1;
250                         return ErrNoSelectionFile;
251                 }
252         }
253
254     start_tag_line(env->file_sel->fname);
255     ret = ReadImSelectionFile(env->file_sel, fp);
256     
257     return ret;
258 }
259
260 static int 
261 GetUserFileName(
262     I18nEnv *env
263 )
264 {
265     int                status, ret = NoError;
266     char               *path, *tmp_path;
267     int                len = 0;
268     struct stat        buf;
269
270     /* The user IMS Selection File should be of the following form:
271      * $HOME/.dt/ims/[display-name]/CDE-locale
272      */
273
274     path = (char *) XtMalloc((MAXPATHLEN + 1) * sizeof(char));
275
276     strcpy(path, env->user_env->homedir);
277     strcat(path, DtUSER_IMSFS_DIR);
278
279     /* Look if there is a display specific directory */
280
281     tmp_path = (char *) XtMalloc((MAXPATHLEN + 1) * sizeof(char));
282     
283     strcpy(tmp_path, path);
284     strcat(tmp_path, "/");
285     strcat(tmp_path, env->user_env->displayname);
286
287     if ((status = stat (tmp_path, &buf)) == 0) {
288         strcat(path, "/");
289         strcat(path, env->user_env->displayname);
290     }
291
292     XtFree(tmp_path);
293
294     /* Now add the CDE-specific locale name */
295
296     strcat(path, "/");
297     strcat(path, env->user_env->CDE_locale);
298
299     env->file_sel->fname = path;
300
301     return ret;
302 }           
303
304 static int
305 ReadImSelectionFile(
306     FileSel     *fsel,
307     FILE        *fp
308 )
309 {
310     int         ret = NoError;
311     char        *lp, *valp, *vp, *p;
312     int         select_mode = 0;
313     char        *imsname, *hostname;
314     int         line_num, i;
315
316     imsname = hostname = NULL;
317
318         while ((line_num = read_tag_line(fp, &lp, &valp)) > 0) {
319                 if (!valp) {
320                         continue;
321                 }
322                 if (lp[0] != STR_PREFIX_CHAR) {
323                         continue;
324                 }
325                 if (strncmp(lp + 1, STR_SELECTMODE, 3) == 0) {
326                         if (str_to_int(valp, &i) && i >= 0) {
327                                 select_mode = i;
328                         }
329                 } else if (strncmp(lp + 1, STR_IMSNAME, 4) == 0) {
330                         vp = valp; cut_field(valp);
331                         if (*vp) {
332                                 XtFree(imsname);
333                                 imsname = XtNewString(vp);
334                         }
335                 } else if (strncmp(lp + 1, STR_HOSTNAME, 4) == 0) {
336                         vp = valp; cut_field(valp);
337                         if (*vp) {
338                                 XtFree(hostname);
339                                 if (strcmp(vp, NAME_LOCAL)) {
340                                         hostname = XtNewString(vp);
341                                 }
342                         }
343                 }
344         }
345
346     fsel->im_name = imsname;
347     fsel->hostname = hostname;
348     fsel->start_mode = select_mode;
349
350     return ret;
351
352 }
353
354 int 
355 _DtI18nGetImList(
356     I18nEnv *env,
357     char    *hostname )
358 {
359     int         ret = NoError;
360     int         host_type = HOST_LOCAL;
361
362     if (hostname)
363         host_type = CheckHostname(env, hostname);
364
365     switch (host_type) {
366         case HOST_UNKNOWN:
367             ret = ErrUnknownHost;
368             break;
369
370         case HOST_REMOTE:
371             /* Put the host name in the ImsSel structure */
372             env->ims_sel->host_name = hostname;
373             ret = GetImsList(env, hostname);
374             break;
375
376         case HOST_LOCAL:
377             if (hostname && strcasecmp(hostname, "local") != 0)
378                 env->ims_sel->host_name = hostname;
379             ret = GetImsList(env, env->user_env->localhostname);
380             break;
381     }
382
383     return ret;
384 }
385
386
387 static int 
388 GetImsList(
389     I18nEnv     *env,
390     char        *hostname )
391 {
392     int         ret = NoError;
393     char        pipe_command[255];
394     FILE        *fp;
395     struct stat  buf;
396     unsigned long timeout;
397
398     /* First check if dtimsstart is installed correctly */
399
400     if ((ret = stat ("/usr/dt/bin/dtimsstart", &buf)) != NoError) {
401         return ErrNoDtimsstart;
402     }
403     
404     sprintf(pipe_command, "/usr/dt/bin/dtimsstart -listname -hostname %s", 
405             hostname);
406
407     if (fp = popen(pipe_command, "r")) {
408
409         /* Set the sensitivity of the InputMethod Title Box to False until we
410          * are done reading the new information. */
411         _DtI18nSetSensitiveImTB(env, False);
412
413         /* Initialize the pipe record. */
414         if (!(env->pipe_info))
415             env->pipe_info = (PipeRec *) XtMalloc(sizeof(PipeRec));
416         
417         env->pipe_info->pipe = fp;  /* to close it */
418         env->pipe_info->input_id =  /* to remove it */
419             XtAppAddInput (XtWidgetToApplicationContext(env->shell), 
420                            fileno(fp), (XtPointer) XtInputReadMask, 
421                            ReadPipe, (XtPointer) env); 
422
423         /* Also add a timeout in case the pipe ain't talk */
424         timeout = (unsigned long) (style.xrdb.pipeTimeOut) * 1000;
425         env->pipe_info->timer_id = 
426             XtAppAddTimeOut(XtWidgetToApplicationContext(env->shell), 
427                             timeout, TimeOutProc, (XtPointer)env);
428     } else {
429         ret = ErrNoPopen;
430     }
431
432     return ret;
433 }
434     
435 static void TimeOutProc (XtPointer client_data, 
436                          XtIntervalId* timer)
437 {
438     I18nEnv *env = (I18nEnv *) client_data;
439
440     /* the command is not fast enough,  but calling pclose blocks
441        and then print "Broken Pipe". I need to kill the child somehow 
442     pclose(env->pipe_info->pipe);*/
443
444     XtRemoveInput(env->pipe_info->input_id);
445
446     /* Set the sensitivity of the InputMethod Title Box back to True. */
447     _DtI18nSetSensitiveImTB(env, True);
448
449     _DtI18nErrorDialog(ErrTimeOut) ;
450 }
451
452 static void
453 ReadPipe (
454     XtPointer    client_data,
455     int          *fd,
456     XtInputId    *id )
457
458 {
459     char      buf[512];
460     int       i, nbytes;
461     int       status = NoError;
462     static    char * savebuf = NULL; 
463     static    int savebuf_bytes = 0 ;
464     I18nEnv   *env = (I18nEnv *) client_data;
465         
466     nbytes = read (*fd, buf, 512);
467
468     if (nbytes) {
469         savebuf = XtRealloc(savebuf, savebuf_bytes + nbytes);
470         memcpy(savebuf+savebuf_bytes, buf, nbytes);
471         savebuf_bytes += nbytes ;
472     } else {
473         if (savebuf)
474             *(savebuf + savebuf_bytes)  = '\0';
475         status = ProcessBuf(savebuf, client_data);
476         savebuf_bytes = 0;
477         if (savebuf) {
478             XtFree(savebuf);
479             savebuf = NULL;
480         }
481
482         pclose(env->pipe_info->pipe);
483         XtRemoveInput(*id);
484
485         /* Set the sensitivity of the InputMethod Title Box back to True. */
486         _DtI18nSetSensitiveImTB(env, True);
487
488         /* Remove timer too */
489         XtRemoveTimeOut(env->pipe_info->timer_id);
490
491         if (status != NoError)
492             _DtI18nErrorDialog(status) ;
493     }
494
495 }
496
497 static int
498 ProcessBuf(
499      char    *savebuf, 
500      I18nEnv *env )
501 {
502     int    i, n = 0;
503     int    ret = NoError;
504     ImsEnt *ims_ent;
505     char * filename, * label ;
506
507     /* The dtimsstart execution gave back an empty buffer */
508     if (!savebuf)
509         return(ErrRemoteFailed);
510         
511     /* parse savebuf: The lines have the following syntax: 
512      * [#](im_filename) im_label  or
513      * [#]im_filename im_label
514      * where "#" if present means the default IM,
515      *       im_filename is the file name where all the IM info is stored,
516      *       im_label is the label to present to the user.
517      */
518     while (*savebuf) {
519         /* We're at the beginning of a new line */
520
521         /* grow the array */
522         env->ims_sel->ims_list = 
523             (ImsEnt *) XtRealloc((char *) env->ims_sel->ims_list,
524                                  sizeof(ImsEnt)*(n+1));
525
526         ims_ent = &(env->ims_sel->ims_list[n]);
527
528         /* Look to see if this is the default one. */
529         if (*savebuf == '#') {
530             ims_ent->im_default = 1;
531             savebuf++;
532         } else
533             ims_ent->im_default = 0;
534
535         /* Look to see if it is not reachable. */
536         if (*savebuf == '(') {
537             ims_ent->inactive = 1;
538             savebuf++ ;
539         } else 
540              ims_ent->inactive = 0 ;
541
542         /* Mark begin of im filename */
543         filename = savebuf ;
544         /* Go to the end of it */
545         while (!isspace(*savebuf++)) ;
546         /* We're on the first space, mark the end of the im filename,
547          * don't forget to count the ')' if inactive. */
548         *(savebuf - ims_ent->inactive - 1) = '\0';
549
550         /* Mark the beginning of the im name */
551         label = savebuf ;
552         while (*savebuf != '\n') savebuf++ ;
553         /* mark the end */
554         *savebuf = '\0';
555         savebuf++;
556
557         /* copy the string data here. it's gonna be freed after that */
558         ims_ent->im_name = XtNewString(filename) ;
559         ims_ent->im_label = XtNewString(label) ;
560         n++;
561     }      
562
563     env->ims_sel->ims_list_size = n;
564
565     return(ret);
566 }
567
568
569 static int      
570 CheckHostname(
571     I18nEnv     *env,
572     char        *hostname
573 )
574 {
575     int         host_type = HOST_UNKNOWN;
576     char        *local = env->user_env->localhostname;
577     struct hostent      *hp;
578     unsigned long       addr = 0L;
579     static unsigned long  local_addr = 0L;
580
581     if (!hostname || !*hostname || strcasecmp(hostname, "local") == 0
582                         || strcasecmp(hostname, local) == 0) {
583         host_type =  HOST_LOCAL;
584     } else {            /* compare inet address */
585         if (!local_addr) {
586             if ((hp = gethostbyname(local)) && hp->h_addrtype == AF_INET) {
587                 local_addr = *((unsigned long *) hp->h_addr_list[0]);
588             } else {
589                 host_type = HOST_REMOTE;
590             }
591         }
592         if (host_type == HOST_UNKNOWN) {
593             if ((hp = gethostbyname(hostname)) && hp->h_addrtype == AF_INET) {
594                 addr = *((unsigned long *) hp->h_addr_list[0]);
595                 if (addr == local_addr)
596                     host_type = HOST_LOCAL;
597                 else
598                     host_type = HOST_REMOTE;
599             } else {
600                 host_type = HOST_UNKNOWN;
601             }
602         }
603     }
604
605     return host_type;
606 }
607
608
609 /*+++++++++++++++++++++++++++++++++++++++*/
610 /* _DtI18nWriteImSelectionFile - writes  */
611 /* the values saved in the FileSel       */
612 /* structure to the IMS Selection File.  */
613 /*+++++++++++++++++++++++++++++++++++++++*/
614 int
615 _DtI18nWriteImSelectionFile(
616      I18nEnv *env
617 )
618 {
619     FILE        *fp;
620
621     
622     /* Look if this file is writable */
623     if ((fp = fopen(env->file_sel->fname, "w")) == NULL)
624         return ErrFileCreate;
625
626     /* Write the select mode */
627     PutSelectMode(fp, env->file_sel->start_mode);
628
629     /* Write the IM selected if not null */
630     PutImsName(fp, env->file_sel->im_name);
631
632     /* Write the hostname if not null */
633     PutHostname(fp, env->file_sel->hostname);
634     
635     /* Close the file */
636     fclose(fp);
637
638         return NoError;
639 }
640
641 static void
642 PutSelectMode(
643      FILE *fp,
644      int  start_mode
645 )
646 {
647     char val[20];
648     
649     sprintf(val, "%ld", (long)start_mode);
650     PutSelectionEntry(fp, STR_SELECTMODE, val);
651 }
652
653 static void
654 PutImsName(
655      FILE *fp,
656      char *im_name
657 )
658 {
659     char *valp;
660
661     if ((valp = im_name) && *valp)
662         PutSelectionEntry(fp, STR_IMSNAME, valp);
663 }
664
665 static void
666 PutHostname(
667      FILE *fp,
668      char *hostname
669 )
670 {
671     char *valp;
672
673     if ((valp = hostname) && *valp)
674         PutSelectionEntry(fp, STR_HOSTNAME, valp);
675 }
676
677
678 static void 
679 PutSelectionEntry(
680      FILE *fp,
681      char *tag,
682      char *value
683 )
684 {
685     fprintf(fp, "%c%s%c\t%s\n", STR_PREFIX_CHAR, tag, TAG_END_CHAR, value);
686 }