source: trunk/third/bonobo-activation/server/object-directory-load.c @ 18311

Revision 18311, 20.7 KB checked in by ghudson, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18310, which included commits to RCS files with non-trunk default branches.
Line 
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
2/*
3 *  oafd: OAF CORBA dameon.
4 *
5 *  Copyright (C) 1999, 2000 Red Hat, Inc.
6 *  Copyright (C) 1999, 2000 Eazel, Inc.
7 *
8 *  This library is free software; you can redistribute it and/or
9 *  modify it under the terms of the GNU General Public License as
10 *  published by the Free Software Foundation; either version 2 of the
11 *  License, or (at your option) any later version.
12 *
13 *  This library is distributed in the hope that it will be useful,
14 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 *  General Public License for more details.
17 *
18 *  You should have received a copy of the GNU General Public License
19 *  along with this library; if not, write to the Free Software
20 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 *  Authors: Elliot Lee <sopwith@redhat.com>
23 *           Maciej Stachowiak <mjs@eazel.com>
24 *
25 */
26
27#ifdef HAVE_CONFIG_H
28#include <config.h>
29#endif
30
31#include <stdlib.h>
32#include <sys/types.h>
33#include <dirent.h>
34#include <string.h>
35#include <libxml/parser.h>
36#include <libxml/parserInternals.h>
37#include <libxml/xmlmemory.h>
38
39#include "bonobo-activation/bonobo-activation-i18n.h"
40#include "server.h"
41
42/* SAX Parser */
43typedef enum {
44        STATE_START,
45        STATE_OAF_INFO,
46        STATE_OAF_SERVER,
47        STATE_OAF_ATTRIBUTE,
48        STATE_ITEM,
49        STATE_UNKNOWN,
50        STATE_ERROR
51} ParseState;
52
53typedef struct {
54        ParseState state;
55        ParseState prev_state;
56        int unknown_depth;
57       
58        const char *host;
59        const char *domain;
60        GSList **entries;
61       
62        Bonobo_ServerInfo *cur_server;
63        Bonobo_ActivationProperty *cur_prop;
64        GList *cur_props;
65        GList *cur_items;
66       
67} ParseInfo;
68
69#define IS_ELEMENT(x) (!strcmp (name, x))
70
71static ParseInfo *
72parse_info_new (void)
73{
74        ParseInfo *info = g_new0 (ParseInfo, 1);
75
76        info->prev_state = STATE_UNKNOWN;
77        info->state = STATE_START;
78       
79        return info;
80}
81
82static void
83parse_info_free (ParseInfo *info)
84{
85        g_free (info);
86}
87
88static char *
89od_validate (const char *iid, const char *type, const char *location)
90{
91        int i;
92
93        if (iid == NULL) {
94                return g_strdup (_("a NULL iid is not valid"));
95        }
96
97        if (type == NULL) {
98                return g_strdup_printf (_("iid %s has a NULL type"), iid);
99        }
100
101        if (location == NULL) {
102                return g_strdup_printf (_("iid %s has a NULL location"), iid);
103        }
104
105        for (i = 0; iid && iid [i]; i++) {
106                char c = iid [i];
107
108                if (c == ',' || c == '[' || c == ']' ||
109                    /* Reserved for future expansion */
110                    c == '!' || c == '#' || c == '|') {
111                        return g_strdup_printf (_("invalid character '%c' in iid '%s'"),
112                                                c, iid);
113                }
114        }
115
116        return NULL;
117}
118
119static void
120parse_oaf_server_attrs (ParseInfo      *info,
121                        const xmlChar **attrs)
122{
123        const char *iid = NULL;
124        const char *type = NULL;
125        const char *location = NULL;
126        const char *att, *val;
127        char *error;
128        int i = 0;
129
130        info->state = STATE_OAF_SERVER;
131       
132        if (!attrs)
133                return;
134
135        do {
136                att = attrs[i++];
137                val = attrs[i++];
138
139                if (att && val) {
140                        if (!iid && !strcmp (att, "iid"))
141                                iid = val;
142                        else if (!type && !strcmp (att, "type"))
143                                type = val;
144                        else if (!location && !strcmp (att, "location"))
145                                location = val;
146                }
147               
148        } while (att && val);
149
150        error = od_validate (iid, type, location);
151       
152        if (error != NULL) {
153                /* FIXME: should syslog */
154                g_print ("%s\n", error);
155               
156                g_free (error);
157
158                return;
159        }
160
161        /* Now create the ServerInfo object */
162        info->cur_server = g_new0 (Bonobo_ServerInfo, 1);
163
164        info->cur_server->iid = CORBA_string_dup (iid);
165        info->cur_server->server_type = CORBA_string_dup (type);
166        info->cur_server->location_info = CORBA_string_dup (location);
167        info->cur_server->hostname = CORBA_string_dup (info->host);
168        info->cur_server->domain = CORBA_string_dup (info->domain);
169        info->cur_server->username = CORBA_string_dup (g_get_user_name ());
170}
171
172static GHashTable *interesting_locales = NULL;
173
174void
175add_initial_locales (void)
176{
177        const char *tmp;
178        char *tmp2, *lang, *lang_with_locale, *equal_char;
179
180        if (!interesting_locales) {
181                interesting_locales = g_hash_table_new (
182                        g_str_hash, g_str_equal);
183        }
184        lang_with_locale = NULL;
185       
186        tmp = g_getenv ("LANGUAGE");
187
188        if (!tmp)
189                tmp = g_getenv ("LANG");
190       
191        lang = g_strdup (tmp);
192        tmp2 = lang;
193
194        if (lang) {
195                /* envs can be in NAME=VALUE form */
196                equal_char = strchr (lang, '=');
197                if (equal_char)
198                        lang = equal_char + 1;
199
200                /* check if the locale has a _ */
201                equal_char = strchr (lang, '_');
202                if (equal_char != NULL) {
203                        lang_with_locale = g_strdup (lang);
204                        *equal_char = 0;
205                }
206
207                if (lang_with_locale && strcmp (lang_with_locale, "")) {
208                        g_hash_table_insert (interesting_locales,
209                                             lang_with_locale,
210                                             GUINT_TO_POINTER (1));
211#ifdef LOCALE_DEBUG
212                        g_warning ("Init lang '%s'", lang_with_locale);
213#endif
214                }
215
216                if (lang && strcmp (lang, "")) {
217                        g_hash_table_insert (interesting_locales,
218                                             g_strdup (lang),
219                                             GUINT_TO_POINTER (1));
220#ifdef LOCALE_DEBUG
221                        g_warning ("Init lang(2) '%s'", lang);
222#endif
223                }
224        }
225
226        g_free (tmp2);
227}
228
229gboolean
230register_interest_in_locales (const char *locales)
231{
232        int i;
233        char **localev;
234        gboolean new_locale = FALSE;
235
236        localev = g_strsplit (locales, ",", 0);
237
238        for (i = 0; localev[i]; i++) {
239                if (!g_hash_table_lookup (interesting_locales, localev[i])) {
240#ifdef LOCALE_DEBUG
241                        g_warning ("New locale '%s' (%d)!",
242                                   localev[i], g_list_length (locale_list));
243#endif
244                        g_hash_table_insert (interesting_locales,
245                                             g_strdup (localev[i]),
246                                             GUINT_TO_POINTER (1));
247                        new_locale = TRUE;
248                }
249        }
250        g_strfreev (localev);
251
252        return new_locale;
253}
254
255static gboolean
256is_locale_interesting (const char *name_with_locale)
257{
258        const char *locale;
259
260        if (!name_with_locale)
261                return FALSE;
262
263        if (!(locale = strchr (name_with_locale, '-')))
264                return TRUE;
265        locale++;
266
267        return g_hash_table_lookup (interesting_locales, locale) != NULL;
268}
269
270static gboolean
271od_string_to_boolean (const char *str)
272{
273        if (!g_ascii_strcasecmp (str, "true") ||
274            !g_ascii_strcasecmp (str, "yes") ||
275            !strcmp (str, "1"))
276                return TRUE;
277        else
278                return FALSE;
279}
280
281static void
282parse_oaf_attribute (ParseInfo     *info,
283                     const xmlChar **attrs)
284{
285        int i = 0;
286        const char *type = NULL;
287        const char *name = NULL;
288        const char *value = NULL;
289        const char *att, *val;
290       
291        g_assert (info->cur_server);
292
293        info->state = STATE_OAF_ATTRIBUTE;
294       
295        if (!attrs)
296                return;
297
298        do {
299                att = attrs[i++];
300                val = attrs[i++];
301               
302                if (att && val) {
303                        if (!strcmp (att, "type"))
304                                type = val;
305
306                        else if (!strcmp (att, "name")) {
307                                name = val;
308                                if (!is_locale_interesting (name))
309                                        return;
310                               
311                        } else if (!strcmp (att, "value"))
312                                value = val;
313                }
314
315        } while (att && val);
316
317        if (!type || !name)
318                return;
319       
320        if (name[0] == '_')
321                g_error ("%s is an invalid property name "
322                         "- property names beginning with '_' are reserved",
323                         name);
324       
325        info->cur_prop = g_new0 (Bonobo_ActivationProperty, 1);
326        info->cur_prop->name = CORBA_string_dup (name);
327
328        if (g_ascii_strcasecmp (type, "stringv") == 0) {
329                info->cur_prop->v._d = Bonobo_ACTIVATION_P_STRINGV;
330
331        } else if (g_ascii_strcasecmp (type, "number") == 0) {
332                info->cur_prop->v._d = Bonobo_ACTIVATION_P_NUMBER;
333                info->cur_prop->v._u.value_number = atof (value);
334
335        } else if (g_ascii_strcasecmp (type, "boolean") == 0) {
336                info->cur_prop->v._d = Bonobo_ACTIVATION_P_BOOLEAN;
337                info->cur_prop->v._u.value_boolean = od_string_to_boolean (value);
338
339        } else {
340                /* Assume string */
341                info->cur_prop->v._d = Bonobo_ACTIVATION_P_STRING;
342                if (value != NULL) {
343                        info->cur_prop->v._u.value_string = CORBA_string_dup (value);
344                } else {
345                        g_warning (_("Property '%s' has no value"),
346                                   info->cur_prop->name);
347                        info->cur_prop->v._u.value_string =
348                                CORBA_string_dup ("");
349                }
350        }
351}
352
353static void
354parse_stringv_item (ParseInfo     *info,
355                    const xmlChar **attrs)
356{
357        const char *value = NULL;
358        const char *att, *val;
359        int i = 0;
360
361        if (!attrs)
362                return;
363
364        do {
365                att = attrs[i++];
366                val = attrs[i++];
367               
368                if (att && val) {
369                        if (!value && !strcmp (att, "value")) {
370                                value = val;
371                                break;
372                        }
373
374                }
375               
376        } while (att && val);
377
378        if (value)
379                info->cur_items = g_list_prepend (info->cur_items, CORBA_string_dup (value));
380
381        info->state = STATE_ITEM;
382       
383}
384
385static void
386od_StartElement (ParseInfo     *info,
387                 const xmlChar *name,
388                 const xmlChar **attrs)
389{
390        switch (info->state) {
391        case STATE_START:
392                if (IS_ELEMENT ("oaf_info"))
393                        info->state = STATE_OAF_INFO;
394                else {
395                        info->prev_state = info->state;
396                        info->state = STATE_UNKNOWN;
397                        info->unknown_depth++;
398                }
399                break;
400        case STATE_OAF_INFO:
401                if (IS_ELEMENT ("oaf_server"))
402                        parse_oaf_server_attrs (info, attrs);
403                else {
404                        info->prev_state = info->state;
405                        info->state = STATE_UNKNOWN;
406                        info->unknown_depth++;
407                }
408                break;
409        case STATE_OAF_SERVER:
410                if (IS_ELEMENT ("oaf_attribute"))
411                        parse_oaf_attribute (info, attrs);
412                else {
413                        info->prev_state = info->state;
414                        info->state = STATE_UNKNOWN;
415                        info->unknown_depth++;
416                }
417                break;
418        case STATE_OAF_ATTRIBUTE:
419                if (IS_ELEMENT ("item"))
420                        parse_stringv_item (info, attrs);
421                else {
422                        info->prev_state = info->state;
423                        info->state = STATE_UNKNOWN;
424                        info->unknown_depth++;
425                }
426                break;
427        case STATE_UNKNOWN:
428                info->unknown_depth++;
429                break;
430        case STATE_ERROR:
431                break;
432                break;
433        default:
434                g_error ("start element, unknown state: %d", info->state);
435        }
436}
437
438static void
439add_entry (ParseInfo *info)
440{
441        GSList *l;
442
443        for (l = *(info->entries); l; l = l->next) {
444                Bonobo_ServerInfo *si = l->data;
445
446                if (!strcmp (si->iid, info->cur_server->iid))
447                        return;
448        }
449
450        *(info->entries) = g_slist_prepend (*(info->entries), info->cur_server);
451}
452
453static void
454od_EndElement (ParseInfo     *info,
455               const xmlChar *name)
456{
457
458        switch (info->state) {
459        case STATE_ITEM:
460                info->state = STATE_OAF_ATTRIBUTE;
461                break;
462        case STATE_OAF_ATTRIBUTE: {
463                if (info->cur_prop && info->cur_prop->v._d == Bonobo_ACTIVATION_P_STRINGV) {
464                        gint i, len;
465                        GList *p;
466                       
467                        len = g_list_length (info->cur_items);
468
469                        info->cur_prop->v._u.value_stringv._length = len;
470                        info->cur_prop->v._u.value_stringv._buffer =
471                                CORBA_sequence_CORBA_string_allocbuf (len);
472                       
473                        for (i = 0, p = g_list_reverse (info->cur_items); p; p = p->next, i++)
474                                info->cur_prop->v._u.
475                                        value_stringv._buffer[i] = p->data;
476                        g_list_free (info->cur_items);
477                        info->cur_items = NULL;
478                }
479
480                if (info->cur_prop) {
481                        info->cur_props = g_list_prepend (info->cur_props, info->cur_prop);
482                        info->cur_prop = NULL;
483                }
484               
485                info->state = STATE_OAF_SERVER;
486                break;
487        }
488        case STATE_OAF_SERVER: {
489                if (info->cur_server) {
490                        GList *p;
491                        gint len, i;
492
493                        len = g_list_length (info->cur_props);
494
495                        info->cur_server->props._length = len;
496                        info->cur_server->props._buffer = g_new0 (Bonobo_ActivationProperty, len);
497
498                        for (i = 0, p = g_list_reverse (info->cur_props); p; p = p->next, i++) {
499                                info->cur_server->props._buffer[i] = *((Bonobo_ActivationProperty *)p->data);
500                                g_free (p->data);
501                        }
502                        g_list_free (info->cur_props);
503                        info->cur_props = NULL;
504
505                        add_entry (info);
506                        info->cur_server = NULL;
507                }
508                info->state = STATE_OAF_INFO;
509                break;
510        }
511        case STATE_OAF_INFO: {
512                info->state = STATE_START;
513                break;
514        }
515        case STATE_UNKNOWN:
516                info->unknown_depth--;
517                if (info->unknown_depth == 0)
518                        info->state = info->prev_state;
519                break;
520        case STATE_START:
521                break;
522        default:
523                g_error ("end element, unknown state: %d", info->state);
524        }
525}
526
527static xmlEntityPtr
528od_GetEntity (ParseState *ps, const xmlChar *name)
529{
530        return xmlGetPredefinedEntity (name);
531}
532
533static void
534od_Warning (ParseInfo *ps,
535            const char *msg,
536            ...)
537{
538        va_list args;
539
540        va_start (args, msg);
541        g_logv   ("XML", G_LOG_LEVEL_WARNING, msg, args);
542        va_end   (args);
543}
544
545static void
546od_Error (ParseInfo *ps, const char *msg, ...)
547{
548        va_list args;
549
550        va_start (args, msg);
551        g_logv   ("XML", G_LOG_LEVEL_CRITICAL, msg, args);
552        va_end   (args);
553}
554
555static void
556od_FatalError (ParseInfo *ps, const char *msg, ...)
557{
558        va_list args;
559
560        va_start (args, msg);
561        g_logv   ("XML", G_LOG_LEVEL_ERROR, msg, args);
562        va_end   (args);
563}
564
565static xmlSAXHandler od_SAXParser = {
566        NULL, /* internalSubset */
567        NULL, /* isStandalone */
568        NULL, /* hasInternalSubset */
569        NULL, /* hasExternalSubset */
570        NULL, /* resolveEntity */
571        (getEntitySAXFunc) od_GetEntity, /* getEntity */
572        NULL, /* entityDecl */
573        NULL, /* notationDecl */
574        NULL, /* attributeDecl */
575        NULL, /* elementDecl */
576        NULL, /* unparsedEntityDecl */
577        NULL, /* setDocumentLocator */
578        NULL, /* startDocument */
579        (endDocumentSAXFunc) NULL, /* endDocument */
580        (startElementSAXFunc) od_StartElement, /* startElement */
581        (endElementSAXFunc) od_EndElement, /* endElement */
582        NULL, /* reference */
583        NULL, /* characters */
584        NULL, /* ignorableWhitespace */
585        NULL, /* processingInstruction */
586        NULL, /* comment */
587        (warningSAXFunc) od_Warning, /* warning */
588        (errorSAXFunc) od_Error, /* error */
589        (fatalErrorSAXFunc) od_FatalError, /* fatalError */
590};
591
592static void
593od_load_file (const char *file,
594              GSList    **entries,
595              const char *host,
596              const char *domain)
597{
598        ParseInfo *info;
599        xmlSAXHandlerPtr oldsax;
600        xmlParserCtxt *ctxt;
601        int ret = 0;
602       
603        info = parse_info_new ();
604        info->host = host;
605        info->domain = domain;
606        info->entries = entries;
607
608        ctxt = xmlCreateFileParserCtxt (file);
609        oldsax = ctxt->sax;
610        ctxt->sax = &od_SAXParser;
611        ctxt->userData = info;
612        /* Magic to make entities work as expected */
613        ctxt->replaceEntities = TRUE;
614
615        xmlParseDocument (ctxt);
616
617        if (ctxt->wellFormed)
618                ret = 0;
619        else {
620                if (ctxt->errNo != 0)
621                        ret = ctxt->errNo;
622                else
623                        ret = -1;
624        }
625        ctxt->sax = oldsax;
626        xmlFreeParserCtxt (ctxt);
627
628        parse_info_free (info);
629
630        if (ret < 0) {
631                /* FIXME: syslog the error */
632                return;
633        }
634}
635
636static gboolean
637od_filename_has_extension (const char *filename,
638                           const char *extension)
639{
640        char *last_dot;
641       
642        last_dot = strrchr (filename, '.');
643
644        return last_dot != NULL && strcmp (last_dot, extension) == 0;
645}
646
647static void
648od_load_directory (const char *directory,
649                   GSList    **entries,
650                   const char *host,
651                   const char *domain)
652{
653        DIR *directory_handle;
654        struct dirent *directory_entry;
655        char *pathname;
656
657       
658        /* FIXME: Should be a syslog message. */
659        /* g_print (_("Trying dir %s\n"), directory); */
660
661        directory_handle = opendir (directory);
662
663        if (directory_handle == NULL) {
664                /* FIXME */
665                return;
666        }
667       
668        for (directory_entry = readdir (directory_handle);
669             directory_entry != NULL;
670             directory_entry = readdir (directory_handle)) {
671                pathname = g_strdup_printf ("%s/%s", directory, directory_entry->d_name);
672
673                if (od_filename_has_extension (pathname, ".server")) {
674                        od_load_file (pathname, entries, host, domain);
675                }
676
677                g_free (pathname);
678        }
679
680        closedir (directory_handle);
681}
682
683
684void
685bonobo_server_info_load (char **directories,
686                         Bonobo_ServerInfoList   *servers,
687                         GHashTable **iid_to_server_info_map,
688                         const char *host, const char *domain)
689{
690        GSList *entries;
691        int length;
692        GSList *p;
693        int i, j;
694       
695        g_return_if_fail (directories);
696        g_return_if_fail (iid_to_server_info_map);
697
698        entries = NULL;
699
700        if (*iid_to_server_info_map != NULL) {
701                g_hash_table_destroy (*iid_to_server_info_map);
702        }
703
704        *iid_to_server_info_map = g_hash_table_new (g_str_hash, g_str_equal);
705
706        /* Load each directory */
707        for (i = 0; directories[i] != NULL; i++)
708                od_load_directory (directories[i], &entries, host, domain);
709
710        /* Now convert 'entries' into something that the server can store and pass back */
711        length = g_slist_length (entries);
712
713        servers->_buffer = CORBA_sequence_Bonobo_ServerInfo_allocbuf (length);
714        servers->_length = length;
715
716        for (j = 0, p = entries; j < length; j++, p = p->next) {
717                memcpy (&servers->_buffer[j], p->data, sizeof (Bonobo_ServerInfo));
718                g_hash_table_insert (*iid_to_server_info_map,
719                                     servers->_buffer[j].iid,
720                                     &servers->_buffer[j]);
721        }
722
723        g_slist_foreach (entries, (GFunc) g_free, NULL);
724        g_slist_free (entries);
725}
Note: See TracBrowser for help on using the repository browser.