Fix FSF address (Tobias Mueller, #470445)
[platform/upstream/evolution-data-server.git] / libedataserver / e-data-server-util.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2003 Novell Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of version 2 of the GNU Lesser General Public
7  * License as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  *
19  * Authors: Rodrigo Moya <rodrigo@ximian.com>
20  */
21
22 #include "config.h"
23
24 #include <string.h>
25 #include <sys/stat.h>
26 #include <time.h>
27 #include <unistd.h>
28
29 #include <glib.h>
30
31 #include "e-data-server-util.h"
32
33 /**
34  * e_util_mkdir_hier:
35  * @path: The directory hierarchy to create.
36  * @mode: The permissions to use for the directories.
37  *
38  * Creates a directory hierarchy based on the string @path. If @path
39  * is an absolute path, the directories will be created relative to
40  * the root of the file system; otherwise, the directories will be
41  * created relative to the current directory.
42  *
43  * Returns: 0 on success; -1 on failure.
44  **/
45 int
46 e_util_mkdir_hier (const char *path, mode_t mode)
47 {
48         return g_mkdir_with_parents (path, mode);
49 }
50
51 /**
52  * e_util_strstrcase:
53  * @haystack: The string to search in.
54  * @needle: The string to search for.
55  *
56  * Find the first instance of @needle in @haystack, ignoring case for
57  * bytes that are ASCII characters.
58  *
59  * Returns: A pointer to the start of @needle in @haystack, or NULL if
60  *          @needle is not found.
61  **/
62 gchar *
63 e_util_strstrcase (const gchar *haystack, const gchar *needle)
64 {
65         /* find the needle in the haystack neglecting case */
66         const gchar *ptr;
67         guint len;
68
69         g_return_val_if_fail (haystack != NULL, NULL);
70         g_return_val_if_fail (needle != NULL, NULL);
71
72         len = strlen(needle);
73         if (len > strlen(haystack))
74                 return NULL;
75
76         if (len == 0)
77                 return (gchar *) haystack;
78
79         for (ptr = haystack; *(ptr + len - 1) != '\0'; ptr++)
80                 if (!g_ascii_strncasecmp (ptr, needle, len))
81                         return (gchar *) ptr;
82
83         return NULL;
84 }
85
86 /** 
87  * e_util_unicode_get_utf8:
88  * @text: The string to take the UTF-8 character from.
89  * @out: The location to store the UTF-8 character in.
90  * 
91  * Get a UTF-8 character from the beginning of @text.
92  *
93  * Returns: A pointer to the next character in @text after @out. 
94  **/
95 gchar *
96 e_util_unicode_get_utf8 (const gchar *text, gunichar *out)
97 {
98         *out = g_utf8_get_char (text);
99         return (*out == (gunichar)-1) ? NULL : g_utf8_next_char (text);
100 }
101
102 /** 
103  * e_util_utf8_strstrcase:
104  * @haystack: The string to search in.
105  * @needle: The string to search for.
106  * 
107  * Find the first instance of @needle in @haystack, ignoring case. (No
108  * proper case folding or decomposing is done.) Both @needle and
109  * @haystack are UTF-8 strings.
110  *
111  * Returns: A pointer to the first instance of @needle in @haystack, or
112  *          %NULL if no match is found, or if either of the strings are
113  *          not legal UTF-8 strings.
114  **/
115 const gchar *
116 e_util_utf8_strstrcase (const gchar *haystack, const gchar *needle)
117 {
118         gunichar *nuni;
119         gunichar unival;
120         gint nlen;
121         const gchar *o, *p;
122
123         if (haystack == NULL) return NULL;
124         if (needle == NULL) return NULL;
125         if (strlen (needle) == 0) return haystack;
126         if (strlen (haystack) == 0) return NULL;
127
128         nuni = g_alloca (sizeof (gunichar) * strlen (needle));
129
130         nlen = 0;
131         for (p = e_util_unicode_get_utf8 (needle, &unival); p && unival; p = e_util_unicode_get_utf8 (p, &unival)) {
132                 nuni[nlen++] = g_unichar_tolower (unival);
133         }
134         /* NULL means there was illegal utf-8 sequence */
135         if (!p) return NULL;
136
137         o = haystack;
138         for (p = e_util_unicode_get_utf8 (o, &unival); p && unival; p = e_util_unicode_get_utf8 (p, &unival)) {
139                 gint sc;
140                 sc = g_unichar_tolower (unival);
141                 /* We have valid stripped char */
142                 if (sc == nuni[0]) {
143                         const gchar *q = p;
144                         gint npos = 1;
145                         while (npos < nlen) {
146                                 q = e_util_unicode_get_utf8 (q, &unival);
147                                 if (!q || !unival) return NULL;
148                                 sc = g_unichar_tolower (unival);
149                                 if (sc != nuni[npos]) break;
150                                 npos++;
151                         }
152                         if (npos == nlen) {
153                                 return o;
154                         }
155                 }
156                 o = p;
157         }
158
159         return NULL;
160 }
161
162
163 static gunichar
164 stripped_char (gunichar ch)
165 {
166         gunichar *decomp, retval;
167         GUnicodeType utype;
168         gsize dlen;
169
170         utype = g_unichar_type (ch);
171
172         switch (utype) {
173         case G_UNICODE_CONTROL:
174         case G_UNICODE_FORMAT:
175         case G_UNICODE_UNASSIGNED:
176         case G_UNICODE_COMBINING_MARK:
177                 /* Ignore those */
178                 return 0;
179                break;
180         default:
181                 /* Convert to lowercase, fall through */
182                 ch = g_unichar_tolower (ch);
183         case G_UNICODE_LOWERCASE_LETTER:
184                 if ((decomp = g_unicode_canonical_decomposition (ch, &dlen))) {
185                         retval = decomp[0];
186                         g_free (decomp);
187                         return retval;
188                 }
189                 break;
190         }
191
192         return 0;
193 }
194
195 /** 
196  * e_util_utf8_strstrcasedecomp:
197  * @haystack: The string to search in.
198  * @needle: The string to search for.
199  * 
200  * Find the first instance of @needle in @haystack, where both @needle
201  * and @haystack are UTF-8 strings. Both strings are stripped and
202  * decomposed for comparison, and case is ignored.
203  *
204  * Returns: A pointer to the first instance of @needle in @haystack, or
205  *          %NULL if either of the strings are not legal UTF-8 strings.
206  **/
207 const gchar *
208 e_util_utf8_strstrcasedecomp (const gchar *haystack, const gchar *needle)
209 {
210         gunichar *nuni;
211         gunichar unival;
212         gint nlen;
213         const gchar *o, *p;
214
215         if (haystack == NULL) return NULL;
216         if (needle == NULL) return NULL;
217         if (strlen (needle) == 0) return haystack;
218         if (strlen (haystack) == 0) return NULL;
219
220         nuni = g_alloca (sizeof (gunichar) * strlen (needle));
221
222         nlen = 0;
223         for (p = e_util_unicode_get_utf8 (needle, &unival); p && unival; p = e_util_unicode_get_utf8 (p, &unival)) {
224                 gint sc;
225                 sc = stripped_char (unival);
226                 if (sc) {
227                        nuni[nlen++] = sc;
228                 }
229         }
230         /* NULL means there was illegal utf-8 sequence */
231         if (!p) return NULL;
232         /* If everything is correct, we have decomposed, lowercase, stripped needle */
233         if (nlen < 1) return haystack;
234
235         o = haystack;
236         for (p = e_util_unicode_get_utf8 (o, &unival); p && unival; p = e_util_unicode_get_utf8 (p, &unival)) {
237                 gint sc;
238                 sc = stripped_char (unival);
239                 if (sc) {
240                         /* We have valid stripped char */
241                         if (sc == nuni[0]) {
242                                 const gchar *q = p;
243                                 gint npos = 1;
244                                 while (npos < nlen) {
245                                         q = e_util_unicode_get_utf8 (q, &unival);
246                                         if (!q || !unival) return NULL;
247                                         sc = stripped_char (unival);
248                                         if ((!sc) || (sc != nuni[npos])) break;
249                                         npos++;
250                                 }
251                                 if (npos == nlen) {
252                                         return o;
253                                 }
254                         }
255                 }
256                 o = p;
257         }
258
259         return NULL;
260 }
261
262 int
263 e_util_utf8_strcasecmp (const gchar *s1, const gchar *s2)
264 {
265         gchar *folded_s1, *folded_s2;
266         int retval;
267
268         g_return_val_if_fail (s1 != NULL && s2 != NULL, -1);
269         
270         if (strcmp (s1, s2) == 0)
271                 return 0;
272
273         folded_s1 = g_utf8_casefold (s1, -1);
274         folded_s2 = g_utf8_casefold (s2, -1);
275
276         retval = g_utf8_collate (folded_s1, folded_s2);
277
278         g_free (folded_s2);
279         g_free (folded_s1);
280
281         return retval;
282 }
283
284 /** 
285  * e_strftime:
286  * @s: The string array to store the result in.
287  * @max: The size of array @s.
288  * @fmt: The formatting to use on @tm.
289  * @tm: The time value to format.
290  *
291  * This function is a wrapper around the strftime(3) function, which
292  * converts the &percnt;l and &percnt;k (12h and 24h) format variables if necessary.
293  *
294  * Returns: The number of characters placed in @s.
295  **/
296 size_t e_strftime(char *s, size_t max, const char *fmt, const struct tm *tm)
297 {
298         size_t ret;
299 #ifdef HAVE_LKSTRFTIME
300         ret = strftime(s, max, fmt, tm);
301 #else
302         char *c, *ffmt, *ff;
303
304         ffmt = g_strdup(fmt);
305         ff = ffmt;
306         while ((c = strstr(ff, "%l")) != NULL) {
307                 c[1] = 'I';
308                 ff = c;
309         }
310
311         ff = ffmt;
312         while ((c = strstr(ff, "%k")) != NULL) {
313                 c[1] = 'H';
314                 ff = c;
315         }
316
317 #ifdef G_OS_WIN32
318         /* The Microsoft strftime() doesn't have %e either */
319         ff = ffmt;
320         while ((c = strstr(ff, "%e")) != NULL) {
321                 c[1] = 'd';
322                 ff = c;
323         }
324 #endif
325
326         ret = strftime(s, max, ffmt, tm);
327         g_free(ffmt);
328 #endif
329         if (ret == 0 && max > 0)
330                 s[0] = '\0';
331         return ret;
332 }
333
334 /** 
335  * e_utf8_strftime:
336  * @s: The string array to store the result in.
337  * @max: The size of array @s.
338  * @fmt: The formatting to use on @tm.
339  * @tm: The time value to format.
340  *
341  * The UTF-8 equivalent of e_strftime().
342  *
343  * Returns: The number of characters placed in @s.
344  **/
345 size_t 
346 e_utf8_strftime(char *s, size_t max, const char *fmt, const struct tm *tm)
347 {
348         size_t sz, ret;
349         char *locale_fmt, *buf;
350
351         locale_fmt = g_locale_from_utf8(fmt, -1, NULL, &sz, NULL);
352         if (!locale_fmt)
353                 return 0;
354
355         ret = e_strftime(s, max, locale_fmt, tm);
356         if (!ret) {
357                 g_free (locale_fmt);
358                 return 0;
359         }
360
361         buf = g_locale_to_utf8(s, ret, NULL, &sz, NULL);
362         if (!buf) {
363                 g_free (locale_fmt);
364                 return 0;
365         }
366
367         if (sz >= max) {
368                 char *tmp = buf + max - 1;
369                 tmp = g_utf8_find_prev_char(buf, tmp);
370                 if (tmp)
371                         sz = tmp - buf;
372                 else
373                         sz = 0;
374         }
375         memcpy(s, buf, sz);
376         s[sz] = '\0';
377         g_free(locale_fmt);
378         g_free(buf);
379         return sz;
380 }
381
382 /**
383  * e_util_pthread_id:
384  * @t: A pthread_t value
385  *
386  * Returns a 64-bit integer hopefully uniquely identifying the
387  * thread. To be used in debugging output and logging only. To test
388  * whether two pthread_t values refer to the same thread, use
389  * pthread_equal().
390  *
391  * There is no guarantee that calling e_util_pthread_id() on one
392  * thread first and later after that thread has dies on another won't
393  * return the same integer.
394  *
395  * On some platforms it might even be that when called two times on
396  * the same thread's pthread_t (with some pthread API calls inbetween)
397  * we will return different values (this of course makes this function
398  * rather useless on such platforms).
399  *
400  * On Linux and Win32, known to really return a unique id for each
401  * thread existing at a certain time. No guarantee that ids won't be
402  * reused after a thread has terminated, though.
403  *
404  * Returns: A 64-bit integer.
405  */
406 guint64
407 e_util_pthread_id (pthread_t t)
408 {
409 #ifdef HAVE_GUINT64_CASTABLE_PTHREAD_T
410         /* We know that pthread_t is an integral type, or at least
411          * castable to such without loss of precision.
412          */
413         return (guint64) t;
414 #elif defined (PTW32_VERSION)
415         /* pthreads-win32 implementation on Windows: Return the
416          * pointer to the "actual object" (see pthread.h)
417          */
418 #if GLIB_SIZEOF_VOID_P == 8
419         /* 64-bit Windows */
420         return (guint64) t.p;
421 #else
422         return (int) t.p;
423 #endif
424 #else
425         /* Just return a checksum of the contents of the pthread_t */
426         {
427                 guint64 retval = 0;
428                 guchar *const tend = (guchar *) ((&t)+1);
429                 guchar *tp = (guchar *) &t;
430
431                 while (tp < tend)
432                         retval = (retval << 5) - retval * *tp++;
433
434                 return retval;
435         }
436 #endif
437 }
438
439 /* This only makes a filename safe for usage as a filename.  It still may have shell meta-characters in it. */
440
441 /* This code is rather misguided and mostly pointless, but can't be
442  * changed because of backward compatibility, I guess.
443  *
444  * It replaces some perfectly safe characters like '%' with an
445  * underscore. (Recall that on Unix, the only bytes not allowed in a
446  * file name component are '\0' and '/'.) On the other hand, the UTF-8
447  * for a printable non-ASCII Unicode character (that thus consists of
448  * several very nonprintable non-ASCII bytes) is let through as
449  * such. But those bytes are of course also allowed in filenames, so
450  * it doesn't matter as such...
451  */
452 void
453 e_filename_make_safe (gchar *string)
454 {
455         gchar *p, *ts;
456         gunichar c;
457 #ifdef G_OS_WIN32
458         const char *unsafe_chars = " /'\"`&();|<>$%{}!\\:*?#";
459 #else
460         const char *unsafe_chars = " /'\"`&();|<>$%{}!#";
461 #endif  
462         
463         g_return_if_fail (string != NULL);
464         p = string;
465
466         while(p && *p) {
467                 c = g_utf8_get_char (p);
468                 ts = p;
469                 p = g_utf8_next_char (p);
470                 /* I wonder what this code is supposed to actually
471                  * achieve, and whether it does that as currently
472                  * written?
473                  */
474                 if (!g_unichar_isprint(c) || ( c < 0xff && strchr (unsafe_chars, c&0xff ))) {
475                         while (ts<p)    
476                                 *ts++ = '_';
477                 }
478         }
479 }
480
481 #ifdef G_OS_WIN32
482
483 #include <windows.h>
484
485 /* The following function is lifted from libgnome. We don't want
486  * libedataserver to depend on libgnome, especially as libgnome is
487  * being deprecated. This function will move to GLib, presumably, but
488  * isn't there yet.
489  */
490
491 /**
492  * gnome_win32_get_prefixes:
493  * @hmodule: The handle to a DLL (a HMODULE).
494  * @full_prefix: Where the full UTF-8 path to the DLL's installation folder
495  *               will be returned.
496  * @cp_prefix: Where a system codepage version of
497  *             the installation folder will be returned.
498  *
499  * This function looks up the installation prefix of the DLL (or EXE)
500  * with handle @hmodule. The prefix using long filenames and in UTF-8
501  * form is returned in @full_prefix. The prefix using short file names
502  * (if present in the file system) and in the system codepage is
503  * returned in @cp_prefix. To determine the installation prefix, the
504  * full path to the DLL or EXE is first fetched. If the last folder
505  * component in that path is called "bin", its parent folder is used,
506  * otherwise the folder itself.
507  *
508  * If either can't be obtained, %NULL is stored. The caller should be
509  * prepared to handle that.
510  *
511  * The returned character pointers are newly allocated and should be
512  * freed with g_free when not longer needed.
513  */
514 static void
515 get_prefixes (gpointer  hmodule,
516               char    **full_prefix,
517               char    **cp_prefix)
518 {
519         wchar_t wcbfr[1000];
520         char cpbfr[1000];
521
522         g_return_if_fail (full_prefix != NULL);
523         g_return_if_fail (cp_prefix != NULL);
524
525         *full_prefix = NULL;
526         *cp_prefix = NULL;
527
528         if (G_WIN32_HAVE_WIDECHAR_API ()) {
529                 /* NT-based Windows has wide char API */
530                 if (GetModuleFileNameW ((HMODULE) hmodule, wcbfr, G_N_ELEMENTS (wcbfr))) {
531                         *full_prefix = g_utf16_to_utf8 (wcbfr, -1,
532                                                         NULL, NULL, NULL);
533                         if (GetShortPathNameW (wcbfr, wcbfr, G_N_ELEMENTS (wcbfr)) &&
534                             /* Short pathnames always contain only
535                              * ASCII, I think, but just in case, be
536                              * prepared.
537                              */
538                             WideCharToMultiByte (CP_ACP, 0, wcbfr, -1,
539                                                  cpbfr, G_N_ELEMENTS (cpbfr),
540                                                  NULL, NULL))
541                                 *cp_prefix = g_strdup (cpbfr);
542                         else if (*full_prefix)
543                                 *cp_prefix = g_locale_from_utf8 (*full_prefix, -1,
544                                                                  NULL, NULL, NULL);
545                 }
546         } else {
547                 /* Win9x */
548                 if (GetModuleFileNameA ((HMODULE) hmodule, cpbfr, G_N_ELEMENTS (cpbfr))) {
549                         *full_prefix = g_locale_to_utf8 (cpbfr, -1,
550                                                          NULL, NULL, NULL);
551                         *cp_prefix = g_strdup (cpbfr);
552                 }
553         }
554
555         if (*full_prefix != NULL) {
556                 gchar *p = strrchr (*full_prefix, '\\');
557                 if (p != NULL)
558                         *p = '\0';
559       
560                 p = strrchr (*full_prefix, '\\');
561                 if (p && (g_ascii_strcasecmp (p + 1, "bin") == 0))
562                         *p = '\0';
563         }
564
565         /* cp_prefix is in system codepage */
566         if (*cp_prefix != NULL) {
567                 gchar *p = _mbsrchr (*cp_prefix, '\\');
568                 if (p != NULL)
569                         *p = '\0';
570       
571                 p = _mbsrchr (*cp_prefix, '\\');
572                 if (p && (g_ascii_strcasecmp (p + 1, "bin") == 0))
573                         *p = '\0';
574         }
575 }
576
577 static const char *prefix = NULL;
578 static const char *cp_prefix;
579
580 static const char *localedir;
581 static const char *extensiondir;
582 static const char *imagesdir;
583 static const char *ui_gladedir;
584
585 static HMODULE hmodule;
586 G_LOCK_DEFINE_STATIC (mutex);
587
588 /* Silence gcc with a prototype. Yes, this is silly. */
589 BOOL WINAPI DllMain (HINSTANCE hinstDLL,
590                      DWORD     fdwReason,
591                      LPVOID    lpvReserved);
592
593 /* Minimal DllMain that just tucks away the DLL's HMODULE */
594 BOOL WINAPI
595 DllMain (HINSTANCE hinstDLL,
596          DWORD     fdwReason,
597          LPVOID    lpvReserved)
598 {
599         switch (fdwReason) {
600         case DLL_PROCESS_ATTACH:
601                 hmodule = hinstDLL;
602                 break;
603         }
604         return TRUE;
605 }
606
607 char *
608 e_util_replace_prefix (const char *configure_time_prefix,
609                        const char *runtime_prefix,
610                        const char *configure_time_path)
611 {
612         char *c_t_prefix_slash = g_strconcat (configure_time_prefix, "/",
613                                               NULL);
614         char *retval;
615
616         if (runtime_prefix &&
617             g_str_has_prefix (configure_time_path, c_t_prefix_slash)) {
618                 retval = g_strconcat (runtime_prefix,
619                                       configure_time_path + strlen (configure_time_prefix),
620                                       NULL);
621         } else
622                 retval = g_strdup (configure_time_path);
623
624         g_free (c_t_prefix_slash);
625
626         return retval;
627 }
628
629 static char *
630 replace_prefix (const char *runtime_prefix,
631                 const char *configure_time_path)
632 {
633         return e_util_replace_prefix (E_DATA_SERVER_PREFIX,
634                                       runtime_prefix,
635                                       configure_time_path);
636 }
637
638 static void
639 setup (void)
640 {
641         char *full_pfx;  
642         char *cp_pfx; 
643
644         G_LOCK (mutex);
645         if (prefix != NULL) {
646                 G_UNLOCK (mutex);
647                 return;
648         }
649
650         /* This requires that the libedataserver DLL is installed in $bindir */
651         get_prefixes (hmodule, &full_pfx, &cp_pfx);
652
653         prefix = g_strdup (full_pfx);
654         cp_prefix = g_strdup (cp_pfx);
655
656         g_free (full_pfx);
657         g_free (cp_pfx);
658
659         localedir = replace_prefix (cp_prefix, EVOLUTION_LOCALEDIR);
660         extensiondir = replace_prefix (prefix, E_DATA_SERVER_EXTENSIONDIR);
661         imagesdir = replace_prefix (prefix, E_DATA_SERVER_IMAGESDIR);
662         ui_gladedir = replace_prefix (prefix, E_DATA_SERVER_UI_GLADEDIR);
663
664         G_UNLOCK (mutex);
665 }
666
667 #include "libedataserver-private.h" /* For prototypes */
668
669 #define GETTER_IMPL(varbl)                      \
670 {                                               \
671         setup ();                               \
672         return varbl;                           \
673 }
674
675 #define PRIVATE_GETTER(varbl)                   \
676 const char *                                    \
677 _libedataserver_get_##varbl (void)              \
678         GETTER_IMPL(varbl)
679
680 #define PUBLIC_GETTER(varbl)                    \
681 const char *                                    \
682 e_util_get_##varbl (void)                       \
683         GETTER_IMPL(varbl)
684
685 PRIVATE_GETTER(extensiondir)
686 PRIVATE_GETTER(imagesdir)
687 PRIVATE_GETTER(ui_gladedir)
688
689 PUBLIC_GETTER(prefix)
690 PUBLIC_GETTER(cp_prefix)
691 PUBLIC_GETTER(localedir)
692
693 #endif  /* G_OS_WIN32 */