Remove redundant hourglass functions
[oweals/cde.git] / cde / programs / dtlogin / util.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 /* (c) Copyright 1997 The Open Group */
24 /*                                                                      *
25  * (c) Copyright 1993, 1994 Hewlett-Packard Company                     *
26  * (c) Copyright 1993, 1994 International Business Machines Corp.       *
27  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.                      *
28  * (c) Copyright 1993, 1994 Novell, Inc.                                *
29  */
30 /*
31  * xdm - display manager daemon
32  *
33  * $TOG: util.c /main/15 1998/04/06 13:22:20 mgreess $
34  *
35  * Copyright 1988 Massachusetts Institute of Technology
36  *
37  * Permission to use, copy, modify, and distribute this software and its
38  * documentation for any purpose and without fee is hereby granted, provided
39  * that the above copyright notice appear in all copies and that both that
40  * copyright notice and this permission notice appear in supporting
41  * documentation, and that the name of M.I.T. not be used in advertising or
42  * publicity pertaining to distribution of the software without specific,
43  * written prior permission.  M.I.T. makes no representations about the
44  * suitability of this software for any purpose.  It is provided "as is"
45  * without express or implied warranty.
46  *
47  * Author:  Keith Packard, MIT X Consortium
48  */
49
50 /*
51  * util.c
52  *
53  * various utility routines
54  */
55
56
57 #include    <sys/stat.h>
58 #include    <setjmp.h>
59 #include    <string.h>
60 #include    <dirent.h>
61 #include    <nl_types.h>
62
63 # include   <sys/signal.h>
64
65 # ifndef NULL
66 #  define NULL 0
67 # endif
68
69
70 # include       "dm.h"
71 # include       "vgmsg.h"
72 nl_catd         nl_fd = (nl_catd)-1;    /* message catalog file descriptor */
73
74 #if !defined(NL_CAT_LOCALE)
75 #define NL_CAT_LOCALE 0
76 #endif
77
78 #if !defined (ENABLE_DYNAMIC_LANGLIST)
79 #define LANGLISTSIZE    2048
80 char    languageList[LANGLISTSIZE];     /* global list of languages     */
81 #endif /* ENABLE_DYNAMIC_LANGLIST */
82
83 /***************************************************************************
84  *
85  *  Local procedure declarations
86  *
87  ***************************************************************************/
88
89 static char * makeEnv( 
90                         char *name,
91                         char *value) ;
92
93 static SIGVAL MakeLangAbort(
94                         int arg );
95                         
96 static int MatchesFileSuffix(const char *filename, const char *suffix);
97
98 static void   ScanNLSDir(
99                         char * dirname );
100
101 /********    End Local Function Declarations    ********/
102
103
104 /***************************************************************************
105  *
106  *  ReadCatalog
107  *
108  *  read a string from the message catalog
109  ***************************************************************************/
110
111 unsigned char *
112 ReadCatalog( int set_num, int msg_num, char *def_str )
113 {
114     static Bool alreadyopen = False;
115     char *s;
116
117     if (alreadyopen == False)
118     {
119       char *curNlsPath, *newNlsPath;
120       int newNlsPathLen;
121
122       alreadyopen = True;
123
124      /*
125       * Desktop message catalogs are in DT directory, so append desktop
126       * search paths to current NLSPATH.
127       */
128       #define NLS_PATH_STRING  CDE_INSTALLATION_TOP "/nls/msg/%L/%N.cat:" \
129                          CDE_INSTALLATION_TOP "/lib/nls/msg/%L/%N.cat:" \
130                          CDE_INSTALLATION_TOP "/lib/nls/msg/%l/%t/%c/%N.cat:" \
131                          CDE_INSTALLATION_TOP "/lib/nls/msg/%l/%c/%N.cat"
132
133       curNlsPath = getenv("NLSPATH");
134       if (curNlsPath && strlen(curNlsPath) == 0)
135       {
136         curNlsPath = NULL;
137       }
138  
139      /*
140       * 7 is "NLSPATH"
141       * 1 is "="
142       * <length of NLS_PATH_STRING>
143       * 1 for null byte
144       */
145       newNlsPathLen = 7 + 1 + strlen(NLS_PATH_STRING) + 1;
146
147       if (curNlsPath != NULL)
148       {
149        /*
150         * 1 is ":"
151         * <length of curNlsPath>
152         */
153         newNlsPathLen += (1 + strlen(curNlsPath));
154       }
155
156       newNlsPath = malloc(newNlsPathLen);  /* placed in environ, do not free */
157       
158       if (curNlsPath != NULL)
159       {
160         sprintf(newNlsPath, "NLSPATH=%s:%s", curNlsPath, NLS_PATH_STRING);
161       }
162       else
163       {
164         sprintf(newNlsPath, "NLSPATH=%s", NLS_PATH_STRING);
165       }
166      
167      /*
168       * Store new NLSPATH in environment. Note this memory cannot be freed 
169       */
170       putenv(newNlsPath);
171   
172      /*
173       * Open message catalog. Note, if invalid descriptor returned (ie
174       * msg catalog could not be opened), subsequent call to catgets() using
175       * that descriptor will return 'def_str'.
176       */
177       nl_fd = catopen("dtlogin", NL_CAT_LOCALE);
178     }
179
180     s = catgets(nl_fd,set_num,msg_num,def_str);
181     
182     return((unsigned char *)s);
183 }
184
185 void
186 printEnv( char **e )
187 {
188         while (*e)
189                 Debug ("    %s\n", *e++);
190 }
191
192 static char * 
193 makeEnv( char *name, char *value )
194 {
195         char    *result;
196
197         result = malloc ((unsigned) (strlen (name) + strlen (value) + 2));
198         if (!result) {
199                 LogOutOfMem(
200                   ReadCatalog(MC_LOG_SET,MC_LOG_MAKEENV,MC_DEF_LOG_MAKEENV));
201                 return 0;
202         }
203
204         if (*value) {
205                    sprintf (result, "%s=%s", name, value);
206         }
207         else {
208                 sprintf (result, "%s", name);
209         }
210
211         return result;
212 }
213
214 char * 
215 getEnv( char **e, char *name )
216 {
217     int l = strlen (name);
218
219     while (*e) {
220         if ((int) strlen (*e) > l &&
221             !strncmp (*e, name, l) &&
222             (*e)[l] == '=')
223           return (*e) + l + 1;
224
225         ++e;
226     }
227     return 0;
228 }
229
230 char ** 
231 setEnv( char **e, char *name, char *value )
232 {
233     char        **new, **old;
234     char        *newe;
235     int         envsize;
236     int         l;
237
238     l = strlen (name);
239     newe = makeEnv (name, value);
240     if (!newe) {
241         LogOutOfMem(ReadCatalog(MC_LOG_SET,MC_LOG_SETENV,MC_DEF_LOG_SETENV));
242         return e;
243     }
244     if (e) {
245         for (old = e; *old; old++)
246             if ((int) strlen (*old) > l &&
247                 !strncmp (*old, name, l) &&
248                 (*old)[l] == '=')
249               break;
250
251         if (*old) {
252                 free (*old);
253                 *old = newe;
254                 return e;
255         }
256         envsize = old - e;
257         new = (char **)
258               realloc((char *) e, (unsigned) ((envsize + 2) * sizeof (char *)));
259     } else {
260         envsize = 0;
261         new = (char **) malloc (2 * sizeof (char *));
262     }
263     if (!new) {
264         LogOutOfMem(ReadCatalog(MC_LOG_SET,MC_LOG_SETENV,MC_DEF_LOG_SETENV));
265         free (newe);
266         return e;
267     }
268     new[envsize] = newe;
269     new[envsize+1] = 0;
270     return new;
271 }
272
273 void
274 freeEnv (char **env)
275 {
276     char    **e;
277
278     if (env)
279     {
280         for (e = env; *e; e++)
281             free (*e);
282         free (env);
283     }
284 }
285
286 # define isblank(c)     ((c) == ' ' || c == '\t')
287
288 char ** 
289 parseArgs( char **argv, char *string )
290 {
291         char    *word;
292         char    *save;
293         int     i;
294
295         i = 0;
296         while (argv && argv[i])
297                 ++i;
298         if (!argv) {
299                 argv = (char **) malloc (sizeof (char *));
300                 if (!argv) {
301                         LogOutOfMem(ReadCatalog(
302                           MC_LOG_SET,MC_LOG_PARSEARGS,MC_DEF_LOG_PARSEARGS));
303                         return 0;
304                 }
305         }
306         word = string;
307         for (;;) {
308                 if (!*string || isblank (*string)) {
309                         if (word != string) {
310                                 argv = (char **) realloc ((char *) argv,
311                                         (unsigned) ((i + 2) * sizeof (char *)));
312                                 save = malloc ((unsigned) (string - word + 1));
313                                 if (!argv || !save) {
314                                         LogOutOfMem(ReadCatalog(MC_LOG_SET,
315                                           MC_LOG_PARSEARGS,
316                                           MC_DEF_LOG_PARSEARGS));
317                                         if (argv)
318                                                 free ((char *) argv);
319                                         if (save)
320                                                 free (save);
321                                         return 0;
322                                 }
323                                 argv[i] = strncpy (save, word, string-word);
324                                 argv[i][string-word] = '\0';
325                                 i++;
326                         }
327                         if (!*string)
328                                 break;
329                         word = string + 1;
330                 }
331                 ++string;
332         }
333         argv[i] = 0;
334         return argv;
335 }
336
337 void
338 CleanUpChild( void )
339 {
340 /*
341  *  On i386/i486 platforms setprrp() functions causes the mouse not
342  *  to work.  Since in the daemon mode the parent daemon has already
343  *  executed a setpgrp it is a process and session leader. Since it
344  *  has also gotten rid of the controlling terminal there is no great
345  *  harm in not making the sub-daemons as leaders.
346  */
347 #if defined (SYSV) || defined (SVR4) || defined(__linux__)
348         setpgrp ();
349 #else
350         setpgrp (0, getpid ());
351         sigsetmask (0);
352 #endif
353 #ifdef SIGCHLD
354         (void) signal (SIGCHLD, SIG_DFL);
355 #endif
356         (void) signal (SIGTERM, SIG_DFL);
357         (void) signal (SIGPIPE, SIG_DFL);
358         (void) signal (SIGALRM, SIG_DFL);
359         (void) signal (SIGHUP, SIG_DFL);
360         CloseOnFork ();
361 }
362
363 char * * 
364 parseEnv( char **e, char *string )
365 {
366
367     char *s1, *s2, *t1, *t2;
368     
369     s1 = s2 = strdup(string);
370     
371     while ((t1 = strtok(s1," \t")) != NULL ) {
372         if ( (t2 = strchr(t1,'=')) != NULL ) {
373             *t2++ = '\0';
374             e = setEnv(e, t1, t2);
375         }
376         
377         s1 = NULL;
378     }
379
380     free(s2);
381     return (e);
382 }    
383
384 /*************************************<->*************************************
385  *
386  *  void SetHourGlassCursor
387  *
388  *
389  *  Description:
390  *  -----------
391  *  sets the window cursor to an hourglass
392  *
393  *
394  *  Inputs:
395  *  ------
396  *  dpy = display
397  *  w   = window
398  * 
399  *  Outputs:
400  *  -------
401  *  None
402  *
403  *  Comments:
404  *  --------
405  *  None. (None doesn't count as a comment)
406  * 
407  *************************************<->***********************************/
408
409 void 
410 SetHourGlassCursor( Display *dpy, Window w )
411 {
412     Cursor      cursor;
413     
414     XUndefineCursor(dpy, w);
415     
416     cursor = _DtGetHourGlassCursor(dpy);
417
418     XDefineCursor(dpy, w, cursor);
419     XFreeCursor(dpy, cursor);
420     XFlush(dpy);
421 }
422
423 #if !defined (ENABLE_DYNAMIC_LANGLIST)
424 /***************************************************************************
425  *
426  *  MakeLangList
427  *
428  *  Generate the list of languages installed on the host.
429  *  Result is stored the global array "languageList"
430  *  
431  ***************************************************************************/
432
433 #define DELIM           " \t"   /* delimiters in language list             */
434
435 static jmp_buf  langJump;
436
437 static SIGVAL
438 MakeLangAbort( int arg )
439
440 {
441     longjmp (langJump, 1);
442 }
443
444 void
445 MakeLangList( void )
446 {
447     int i, j;
448
449     char        *lang[500];             /* sort list for languages         */
450     int         nlang;                  /* total number of languages       */
451     char        *p, *s;
452     char        *savelist;
453
454     /*
455      *  build language list from set of languages installed on the host...
456      *  Wrap a timer around it so it doesn't hang things up too long.
457      *  langListTimeout resource  by default is 30 seconds to scan NLS dir. 
458      */
459
460     p = languageList;
461     strcpy( p, "C");
462
463     signal (SIGALRM, MakeLangAbort);
464     alarm ((unsigned) langListTimeout);
465
466     if (!setjmp (langJump)) {
467         ScanNLSDir(DEF_NLS_DIR);
468     }
469     else {
470         LogError(ReadCatalog(MC_LOG_SET,MC_LOG_NO_SCAN,MC_DEF_LOG_NO_SCAN),
471                    DEF_NLS_DIR, langListTimeout);
472     }
473
474     alarm (0);
475     signal (SIGALRM, SIG_DFL);
476
477
478     /*
479      *  sort the list to eliminate duplicates and replace in global array...
480      */
481
482     p = savelist = strdup(languageList);
483     nlang = 0;
484
485     while ( (s = strtok(p, DELIM)) != NULL ) {
486
487         if ( nlang == 0 ) {
488             lang[0] = s;
489             lang[++nlang] = 0;
490             p = NULL;
491             continue;
492         }
493
494         for (i = nlang; i > 0 && strcmp(s,lang[i-1]) < 0; i--);
495
496         if (i==0 || strcmp(s,lang[i-1]) != 0 ) {
497             for (j = nlang; j > i; j--)
498                 lang[j] = lang[j-1];
499
500             lang[i] = s;
501             lang[++nlang] = 0;
502         }
503
504         p = NULL;
505     }
506
507
508     p = languageList;
509     strcpy(p,"");
510
511     for ( i = 0; i < nlang; i++) {
512         strcat(p, lang[i]);
513         strcat(p, " ");
514     }
515
516     free(savelist);
517
518 }        
519
520
521 static int
522 MatchesFileSuffix(const char *filename, const char *suffix)
523 {
524     int         retval = 0;
525 #if defined(_AIX) || defined(SVR4) || defined(__linux__) || defined(CSRG_BASED)
526     int         different = 1;
527              
528     /*
529      * The assumption here is that the use of strrstr is
530      * to determine if "dp->d_name" ends in ".cat".
531      */
532     if (strlen(filename) >= strlen(suffix)) {
533       different = strcmp(filename + (strlen(filename) - strlen (suffix)), suffix);
534     }
535
536     return (different == 0);
537 #else
538     return (strrstr(filename, suffix) != NULL);
539 #endif
540 }
541
542 /***************************************************************************
543  *
544  *  ScanNLSDir
545  *
546  *  Scan a directory structure to see if it contains an installed language.
547  *  If so, the name of the language is appended to a global list of languages.
548  *
549  *  Scan method and scan directory will vary by platform. 
550  *
551  ***************************************************************************/
552
553
554 static void
555 ScanNLSDir(char *dirname)
556
557 #if defined(_AIX)
558 /*
559  * Search installed locale names for AIX 3.2.5
560  */
561 {
562     DIR *dirp;
563     struct dirent *dp;
564
565     /*  Search valid locales which are locale database files in
566      *  /usr/lib/nls/loc.
567      *  File name is "??_??" which can be used as LANG variable.
568      */
569     if((dirp = opendir(dirname)) != NULL)
570     {
571         while((dp = readdir(dirp)) != NULL)
572         {
573             if(strlen(dp->d_name) == 5 && dp->d_name[2] == '_')
574             {
575                 if((int) strlen(languageList) + 7 < LANGLISTSIZE )
576                 {
577                     strcat(languageList, " ");
578                     strcat(languageList, dp->d_name);
579                 }
580             }
581         }
582         closedir(dirp);
583     }
584 }
585
586 #elif defined(hpV4)
587
588 #define LOCALE          "locale.inf"
589 #define LOCALEOLD       "locale.def"
590 #define COLLATE8        "collate8"
591 #define MAILX           "mailx"
592 #define ELM             "elm"
593 #define MSGCAT          ".cat"
594 #define DOT             "."
595 #define DOTDOT          ".."
596
597 /*
598  * Scan for installed locales on HP platform.
599  */
600 {
601     /***************************************************************************
602      *  Scan supplied NLS directory structure to see if it contains an
603      *  installed language.  If so, the name of the language is appended
604      *  to a global list of languages.
605      *
606      *  This routine is recursively called as a directory structure is
607      *  traversed.
608      *
609      *************************************************************************/
610
611     DIR *dirp;
612     struct dirent *dp;
613     struct stat statb;
614
615     char buf[1024];
616     
617     /*
618      *  Scan input directory, looking for a LOCALE file. If a sub-directory
619      *  is found, recurse down into it...
620      */
621     if ( (dirp = opendir(dirname)) != NULL )
622     {
623         while ( (dp = readdir(dirp)) != NULL )
624         {
625             /*
626              *  ignore files that are known not to be candidates...
627              */
628             if ( MatchesFileSuffix(dp->d_name, MSGCAT) ||
629                  (strcmp (dp->d_name, COLLATE8) == 0 ) ||
630                  (strcmp (dp->d_name, MAILX)    == 0 ) ||
631                  (strcmp (dp->d_name, ELM)      == 0 ) ||
632                  (strcmp (dp->d_name, DOT)      == 0 ) ||
633                  (strcmp (dp->d_name, DOTDOT)   == 0 ) )
634               continue;
635
636
637             /*
638              *  check to see if this is the locale file...
639              */
640             if ( (strcmp(dp->d_name, LOCALEOLD) == 0 ) ||
641                  (strcmp(dp->d_name, LOCALE)    == 0 ) )
642             {
643                 char *p, *s;
644
645                 /*
646                  *  Convert directory name to language name...
647                  */
648                 if ( (p = strstr(dirname, DEF_NLS_DIR)) != NULL )
649                 {
650                     p += strlen(DEF_NLS_DIR);
651                     if ( *p == '/' )
652                       p++;
653
654                     s = p;
655                     while ( (p = strchr(s,'/')) != NULL )
656                       *p = '.';
657
658                     /*
659                      *  append to global list of languages...
660                      */
661                     if ((int) (strlen(languageList)+strlen(s)+2) < LANGLISTSIZE)
662                     {
663                         strcat(languageList, " ");
664                         strcat(languageList, s);
665                     }
666                 }
667
668                 continue;
669             }
670         
671             /*
672              *  if this file is a directory, scan it also...
673              */
674             strcpy(buf, dirname);
675             strcat(buf, "/");
676             strcat(buf, dp->d_name);
677
678             if  (stat(buf, &statb) == 0  &&  S_ISDIR(statb.st_mode))
679               ScanNLSDir(buf);
680         }
681
682         closedir(dirp);
683     }
684 }
685
686 #else /* !_AIX && !hpV4 */
687 /*
688  * Scan for installed locales on generic platform
689  */
690 {
691     DIR *dirp;
692     struct dirent *dp;
693     char* locale; 
694     char locale_path[MAXPATHLEN];
695     struct stat locale_stat;
696     int retval;
697
698     /* 
699      * To determin the fully installed locale list, check several locations.
700      */
701     if(NULL != (dirp = opendir(dirname)))
702     {
703         while((dp = readdir(dirp)) != NULL)
704         {
705             locale = dp->d_name;
706
707             if ( (strcmp(dp->d_name, ".") == 0) ||
708                  (strcmp(dp->d_name, "..") == 0) )
709               continue;
710
711             if (locale[0] != '.' &&
712                 LANGLISTSIZE > (int) (strlen(languageList)+strlen(locale)+2));
713             {
714                 (void) sprintf(locale_path, "%s/%s", dirname, locale);
715                 retval = stat(locale_path, &locale_stat);
716
717                 if (0 == retval && S_ISDIR(locale_stat.st_mode))
718                 {
719                     strcat(languageList, " ");
720                     strcat(languageList, locale);
721                 }
722             }
723         }
724         closedir(dirp);
725     }
726 }
727
728 #endif
729
730 #endif /* ENABLE_DYNAMIC_LANGLIST */
731
732 #ifdef _AIX
733 #define ENVFILE "/etc/environment"
734
735 /* Refer to the LANG environment variable, first.
736  * Or, search a line which includes "LANG=XX_XX" in /etc/environment.
737  * If succeeded, set the value to d->language.
738  */
739 void
740 SetDefaultLanguage(struct display *d)
741 {
742     FILE *file;
743     char lineBuf[160];
744     int n;
745     char *p;
746     char *lang = NULL;
747
748     if((lang = getenv( "LANG" )) == NULL ) {
749         if((file = fopen(ENVFILE, "r")) != NULL) {
750             while(fgets(lineBuf, sizeof(lineBuf) - 1, file)) {
751                 n = strlen(lineBuf);
752                 if(n > 1 && lineBuf[0] != '#') {
753                     if(lineBuf[n - 1] == '\n')
754                         lineBuf[n - 1] = '\0';
755                     if((p = strstr(lineBuf, "LANG=")) != NULL) {
756                         p += 5;
757                         if(strlen(p) == 5 && p[2] == '_') {
758                             lang = p;
759                             break;
760                         }
761                     }
762                 }
763             }
764             fclose(file);
765         }
766     }
767     if(lang != NULL && strlen(lang) > 0) {
768     /*
769      * If LANG is set for hft, we need to change it for X.
770      * Currently there are four hft LANG variables.
771      */
772         d->language = (char *)malloc(strlen(lang)+1);
773         if(strcmp(lang, "En_JP") == 0)
774             strcpy(d->language, "Ja_JP");
775         else if(strcmp(lang, "en_JP") == 0)
776             strcpy(d->language, "ja_JP");
777         else if(strcmp(lang, "en_KR") == 0)
778             strcpy(d->language, "ko_KR");
779         else if(strcmp(lang, "en_TW") == 0)
780             strcpy(d->language, "zh_TW");
781         else
782             strcpy(d->language, lang);
783     }
784 }
785 #endif /* _AIX */
786
787
788 char **
789 setLang( struct display *d, char **env , char *langptr)
790 {
791     char  langlist[LANGLISTSIZE];
792     int   s = 0;
793     char *element = NULL;
794     int   set_def_lang = FALSE;
795  
796  
797     if (NULL != langptr)
798       Debug("setLang():  langlist = %s\n", langptr);
799     else
800       Debug("setLang():  langlist = NULL\n");
801
802     if (langptr)
803       snprintf(langlist, sizeof(langlist), "%s", langptr);
804     else
805       snprintf(langlist, sizeof(langlist), "%s", getEnv(env, "LANGLIST"));
806
807     if (strlen(langlist) > 0) {
808         element = strtok(langlist, DELIM);
809         while(element) {
810             set_def_lang = FALSE;
811             if (strcmp(element,d->language) == 0){
812                 env = setEnv(env, "LANG",  d->language);
813                 break;
814             }
815             else
816               set_def_lang = TRUE;
817  
818             s += strlen(element) +1;
819             element = strtok(langlist+s, DELIM);
820         }
821     } else
822       set_def_lang = TRUE;
823  
824     if (set_def_lang) {
825         env = setEnv(env, "LANG", "C");
826         d->language = strdup("C");
827     }
828     return env;
829 }
830
831 static char localHostbuf[256];
832 static int  gotLocalHostname;
833
834 char *
835 localHostname (void)
836 {
837     if (!gotLocalHostname)
838     {
839         XmuGetHostname (localHostbuf, sizeof (localHostbuf) - 1);
840         gotLocalHostname = 1;
841     }
842     return localHostbuf;
843 }
844