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

Revision 18563, 19.4 KB checked in by ghudson, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18562, which included commits to RCS files with non-trunk default branches.
RevLine 
[18310]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"
[18562]40#include "bonobo-activation/bonobo-activation-private.h"
[18310]41#include "server.h"
42
43/* SAX Parser */
44typedef enum {
45        STATE_START,
46        STATE_OAF_INFO,
47        STATE_OAF_SERVER,
48        STATE_OAF_ATTRIBUTE,
49        STATE_ITEM,
50        STATE_UNKNOWN,
51        STATE_ERROR
52} ParseState;
53
54typedef struct {
55        ParseState state;
56        ParseState prev_state;
57        int unknown_depth;
58       
59        const char *host;
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->username = CORBA_string_dup (g_get_user_name ());
[18562]169        info->cur_server->domain = CORBA_string_dup ("unused");
[18310]170}
171
172static GHashTable *interesting_locales = NULL;
173
174void
175add_initial_locales (void)
176{
[18562]177        const GList *l;
[18310]178
[18562]179        if (!interesting_locales)
[18310]180                interesting_locales = g_hash_table_new (
181                        g_str_hash, g_str_equal);
182
[18562]183        for (l = bonobo_activation_i18n_get_language_list (NULL);
184             l; l = l->next)
185                g_hash_table_insert (interesting_locales,
186                                     g_strdup ((char *) l->data),
187                                     GUINT_TO_POINTER (1));
[18310]188}
189
190gboolean
191register_interest_in_locales (const char *locales)
192{
193        int i;
194        char **localev;
195        gboolean new_locale = FALSE;
196
197        localev = g_strsplit (locales, ",", 0);
198
199        for (i = 0; localev[i]; i++) {
200                if (!g_hash_table_lookup (interesting_locales, localev[i])) {
201#ifdef LOCALE_DEBUG
202                        g_warning ("New locale '%s' (%d)!",
203                                   localev[i], g_list_length (locale_list));
204#endif
205                        g_hash_table_insert (interesting_locales,
206                                             g_strdup (localev[i]),
207                                             GUINT_TO_POINTER (1));
208                        new_locale = TRUE;
209                }
210        }
211        g_strfreev (localev);
212
213        return new_locale;
214}
215
216static gboolean
217is_locale_interesting (const char *name_with_locale)
218{
219        const char *locale;
220
221        if (!name_with_locale)
222                return FALSE;
223
224        if (!(locale = strchr (name_with_locale, '-')))
225                return TRUE;
226        locale++;
227
228        return g_hash_table_lookup (interesting_locales, locale) != NULL;
229}
230
231static gboolean
232od_string_to_boolean (const char *str)
233{
234        if (!g_ascii_strcasecmp (str, "true") ||
235            !g_ascii_strcasecmp (str, "yes") ||
236            !strcmp (str, "1"))
237                return TRUE;
238        else
239                return FALSE;
240}
241
242static void
243parse_oaf_attribute (ParseInfo     *info,
244                     const xmlChar **attrs)
245{
246        int i = 0;
247        const char *type = NULL;
248        const char *name = NULL;
249        const char *value = NULL;
250        const char *att, *val;
251       
252        g_assert (info->cur_server);
253
254        info->state = STATE_OAF_ATTRIBUTE;
255       
256        if (!attrs)
257                return;
258
259        do {
260                att = attrs[i++];
261                val = attrs[i++];
262               
263                if (att && val) {
264                        if (!strcmp (att, "type"))
265                                type = val;
266
267                        else if (!strcmp (att, "name")) {
268                                name = val;
269                                if (!is_locale_interesting (name))
270                                        return;
271                               
272                        } else if (!strcmp (att, "value"))
273                                value = val;
274                }
275
276        } while (att && val);
277
278        if (!type || !name)
279                return;
280       
281        if (name[0] == '_')
282                g_error ("%s is an invalid property name "
283                         "- property names beginning with '_' are reserved",
284                         name);
285       
286        info->cur_prop = g_new0 (Bonobo_ActivationProperty, 1);
287        info->cur_prop->name = CORBA_string_dup (name);
288
289        if (g_ascii_strcasecmp (type, "stringv") == 0) {
290                info->cur_prop->v._d = Bonobo_ACTIVATION_P_STRINGV;
291
292        } else if (g_ascii_strcasecmp (type, "number") == 0) {
293                info->cur_prop->v._d = Bonobo_ACTIVATION_P_NUMBER;
294                info->cur_prop->v._u.value_number = atof (value);
295
296        } else if (g_ascii_strcasecmp (type, "boolean") == 0) {
297                info->cur_prop->v._d = Bonobo_ACTIVATION_P_BOOLEAN;
298                info->cur_prop->v._u.value_boolean = od_string_to_boolean (value);
299
300        } else {
301                /* Assume string */
302                info->cur_prop->v._d = Bonobo_ACTIVATION_P_STRING;
303                if (value != NULL) {
304                        info->cur_prop->v._u.value_string = CORBA_string_dup (value);
305                } else {
306                        g_warning (_("Property '%s' has no value"),
307                                   info->cur_prop->name);
308                        info->cur_prop->v._u.value_string =
309                                CORBA_string_dup ("");
310                }
311        }
312}
313
314static void
315parse_stringv_item (ParseInfo     *info,
316                    const xmlChar **attrs)
317{
318        const char *value = NULL;
319        const char *att, *val;
320        int i = 0;
321
322        if (!attrs)
323                return;
324
325        do {
326                att = attrs[i++];
327                val = attrs[i++];
328               
329                if (att && val) {
330                        if (!value && !strcmp (att, "value")) {
331                                value = val;
332                                break;
333                        }
334
335                }
336               
337        } while (att && val);
338
339        if (value)
340                info->cur_items = g_list_prepend (info->cur_items, CORBA_string_dup (value));
341
342        info->state = STATE_ITEM;
343       
344}
345
346static void
347od_StartElement (ParseInfo     *info,
348                 const xmlChar *name,
349                 const xmlChar **attrs)
350{
351        switch (info->state) {
352        case STATE_START:
353                if (IS_ELEMENT ("oaf_info"))
354                        info->state = STATE_OAF_INFO;
355                else {
356                        info->prev_state = info->state;
357                        info->state = STATE_UNKNOWN;
358                        info->unknown_depth++;
359                }
360                break;
361        case STATE_OAF_INFO:
362                if (IS_ELEMENT ("oaf_server"))
363                        parse_oaf_server_attrs (info, attrs);
364                else {
365                        info->prev_state = info->state;
366                        info->state = STATE_UNKNOWN;
367                        info->unknown_depth++;
368                }
369                break;
370        case STATE_OAF_SERVER:
371                if (IS_ELEMENT ("oaf_attribute"))
372                        parse_oaf_attribute (info, attrs);
373                else {
374                        info->prev_state = info->state;
375                        info->state = STATE_UNKNOWN;
376                        info->unknown_depth++;
377                }
378                break;
379        case STATE_OAF_ATTRIBUTE:
380                if (IS_ELEMENT ("item"))
381                        parse_stringv_item (info, attrs);
382                else {
383                        info->prev_state = info->state;
384                        info->state = STATE_UNKNOWN;
385                        info->unknown_depth++;
386                }
387                break;
388        case STATE_UNKNOWN:
389                info->unknown_depth++;
390                break;
391        case STATE_ERROR:
392                break;
393                break;
394        default:
395                g_error ("start element, unknown state: %d", info->state);
396        }
397}
398
399static void
400add_entry (ParseInfo *info)
401{
402        GSList *l;
403
404        for (l = *(info->entries); l; l = l->next) {
405                Bonobo_ServerInfo *si = l->data;
406
407                if (!strcmp (si->iid, info->cur_server->iid))
408                        return;
409        }
410
411        *(info->entries) = g_slist_prepend (*(info->entries), info->cur_server);
412}
413
414static void
415od_EndElement (ParseInfo     *info,
416               const xmlChar *name)
417{
418
419        switch (info->state) {
420        case STATE_ITEM:
421                info->state = STATE_OAF_ATTRIBUTE;
422                break;
423        case STATE_OAF_ATTRIBUTE: {
424                if (info->cur_prop && info->cur_prop->v._d == Bonobo_ACTIVATION_P_STRINGV) {
425                        gint i, len;
426                        GList *p;
427                       
428                        len = g_list_length (info->cur_items);
429
430                        info->cur_prop->v._u.value_stringv._length = len;
431                        info->cur_prop->v._u.value_stringv._buffer =
432                                CORBA_sequence_CORBA_string_allocbuf (len);
433                       
434                        for (i = 0, p = g_list_reverse (info->cur_items); p; p = p->next, i++)
435                                info->cur_prop->v._u.
436                                        value_stringv._buffer[i] = p->data;
437                        g_list_free (info->cur_items);
438                        info->cur_items = NULL;
439                }
440
441                if (info->cur_prop) {
442                        info->cur_props = g_list_prepend (info->cur_props, info->cur_prop);
443                        info->cur_prop = NULL;
444                }
445               
446                info->state = STATE_OAF_SERVER;
447                break;
448        }
449        case STATE_OAF_SERVER: {
450                if (info->cur_server) {
451                        GList *p;
452                        gint len, i;
453
454                        len = g_list_length (info->cur_props);
455
456                        info->cur_server->props._length = len;
457                        info->cur_server->props._buffer = g_new0 (Bonobo_ActivationProperty, len);
458
459                        for (i = 0, p = g_list_reverse (info->cur_props); p; p = p->next, i++) {
460                                info->cur_server->props._buffer[i] = *((Bonobo_ActivationProperty *)p->data);
461                                g_free (p->data);
462                        }
463                        g_list_free (info->cur_props);
464                        info->cur_props = NULL;
465
466                        add_entry (info);
467                        info->cur_server = NULL;
468                }
469                info->state = STATE_OAF_INFO;
470                break;
471        }
472        case STATE_OAF_INFO: {
473                info->state = STATE_START;
474                break;
475        }
476        case STATE_UNKNOWN:
477                info->unknown_depth--;
478                if (info->unknown_depth == 0)
479                        info->state = info->prev_state;
480                break;
481        case STATE_START:
482                break;
483        default:
484                g_error ("end element, unknown state: %d", info->state);
485        }
486}
487
488static xmlEntityPtr
489od_GetEntity (ParseState *ps, const xmlChar *name)
490{
491        return xmlGetPredefinedEntity (name);
492}
493
494static void
495od_Warning (ParseInfo *ps,
496            const char *msg,
497            ...)
498{
499        va_list args;
500
501        va_start (args, msg);
502        g_logv   ("XML", G_LOG_LEVEL_WARNING, msg, args);
503        va_end   (args);
504}
505
506static void
507od_Error (ParseInfo *ps, const char *msg, ...)
508{
509        va_list args;
510
511        va_start (args, msg);
512        g_logv   ("XML", G_LOG_LEVEL_CRITICAL, msg, args);
513        va_end   (args);
514}
515
516static void
517od_FatalError (ParseInfo *ps, const char *msg, ...)
518{
519        va_list args;
520
521        va_start (args, msg);
522        g_logv   ("XML", G_LOG_LEVEL_ERROR, msg, args);
523        va_end   (args);
524}
525
526static xmlSAXHandler od_SAXParser = {
527        NULL, /* internalSubset */
528        NULL, /* isStandalone */
529        NULL, /* hasInternalSubset */
530        NULL, /* hasExternalSubset */
531        NULL, /* resolveEntity */
532        (getEntitySAXFunc) od_GetEntity, /* getEntity */
533        NULL, /* entityDecl */
534        NULL, /* notationDecl */
535        NULL, /* attributeDecl */
536        NULL, /* elementDecl */
537        NULL, /* unparsedEntityDecl */
538        NULL, /* setDocumentLocator */
539        NULL, /* startDocument */
540        (endDocumentSAXFunc) NULL, /* endDocument */
541        (startElementSAXFunc) od_StartElement, /* startElement */
542        (endElementSAXFunc) od_EndElement, /* endElement */
543        NULL, /* reference */
544        NULL, /* characters */
545        NULL, /* ignorableWhitespace */
546        NULL, /* processingInstruction */
547        NULL, /* comment */
548        (warningSAXFunc) od_Warning, /* warning */
549        (errorSAXFunc) od_Error, /* error */
550        (fatalErrorSAXFunc) od_FatalError, /* fatalError */
551};
552
553static void
554od_load_file (const char *file,
555              GSList    **entries,
[18562]556              const char *host)
[18310]557{
558        ParseInfo *info;
559        xmlSAXHandlerPtr oldsax;
560        xmlParserCtxt *ctxt;
561        int ret = 0;
562       
563        info = parse_info_new ();
564        info->host = host;
565        info->entries = entries;
566
567        ctxt = xmlCreateFileParserCtxt (file);
568        oldsax = ctxt->sax;
569        ctxt->sax = &od_SAXParser;
570        ctxt->userData = info;
571        /* Magic to make entities work as expected */
572        ctxt->replaceEntities = TRUE;
573
574        xmlParseDocument (ctxt);
575
576        if (ctxt->wellFormed)
577                ret = 0;
578        else {
579                if (ctxt->errNo != 0)
580                        ret = ctxt->errNo;
581                else
582                        ret = -1;
583        }
584        ctxt->sax = oldsax;
585        xmlFreeParserCtxt (ctxt);
586
587        parse_info_free (info);
588
589        if (ret < 0) {
590                /* FIXME: syslog the error */
591                return;
592        }
593}
594
595static gboolean
596od_filename_has_extension (const char *filename,
597                           const char *extension)
598{
599        char *last_dot;
600       
601        last_dot = strrchr (filename, '.');
602
603        return last_dot != NULL && strcmp (last_dot, extension) == 0;
604}
605
606static void
607od_load_directory (const char *directory,
608                   GSList    **entries,
[18562]609                   const char *host)
[18310]610{
611        DIR *directory_handle;
612        struct dirent *directory_entry;
613        char *pathname;
614
615       
616        /* FIXME: Should be a syslog message. */
617        /* g_print (_("Trying dir %s\n"), directory); */
618
619        directory_handle = opendir (directory);
620
621        if (directory_handle == NULL) {
622                /* FIXME */
623                return;
624        }
625       
626        for (directory_entry = readdir (directory_handle);
627             directory_entry != NULL;
628             directory_entry = readdir (directory_handle)) {
629                pathname = g_strdup_printf ("%s/%s", directory, directory_entry->d_name);
630
631                if (od_filename_has_extension (pathname, ".server")) {
[18562]632                        od_load_file (pathname, entries, host);
[18310]633                }
634
635                g_free (pathname);
636        }
637
638        closedir (directory_handle);
639}
640
641
642void
643bonobo_server_info_load (char **directories,
644                         Bonobo_ServerInfoList   *servers,
645                         GHashTable **iid_to_server_info_map,
[18562]646                         const char *host)
[18310]647{
648        GSList *entries;
649        int length;
650        GSList *p;
651        int i, j;
652       
653        g_return_if_fail (directories);
654        g_return_if_fail (iid_to_server_info_map);
655
656        entries = NULL;
657
658        if (*iid_to_server_info_map != NULL) {
659                g_hash_table_destroy (*iid_to_server_info_map);
660        }
661
662        *iid_to_server_info_map = g_hash_table_new (g_str_hash, g_str_equal);
663
664        /* Load each directory */
665        for (i = 0; directories[i] != NULL; i++)
[18562]666                od_load_directory (directories[i], &entries, host);
[18310]667
668        /* Now convert 'entries' into something that the server can store and pass back */
669        length = g_slist_length (entries);
670
671        servers->_buffer = CORBA_sequence_Bonobo_ServerInfo_allocbuf (length);
672        servers->_length = length;
673
674        for (j = 0, p = entries; j < length; j++, p = p->next) {
675                memcpy (&servers->_buffer[j], p->data, sizeof (Bonobo_ServerInfo));
676                g_hash_table_insert (*iid_to_server_info_map,
677                                     servers->_buffer[j].iid,
678                                     &servers->_buffer[j]);
679        }
680
681        g_slist_foreach (entries, (GFunc) g_free, NULL);
682        g_slist_free (entries);
683}
Note: See TracBrowser for help on using the repository browser.