source: trunk/third/evolution/shell/e-local-folder.c @ 16787

Revision 16787, 13.2 KB checked in by ghudson, 23 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r16786, which included commits to RCS files with non-trunk default branches.
Line 
1/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2/* e-local-folder.c
3 *
4 * Copyright (C) 2000  Ximian, Inc.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public
16 * License along with this program; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
19 *
20 * Author: Ettore Perazzoli
21 */
22
23/* The metafile goes like this:
24
25   <?xml version="1.0"?>
26   <efolder>
27           <type>mail</type>
28
29           <name>Inbox</name>
30           <name locale="it">Posta in Arrivo</name>
31
32           <description>This is the default folder for incoming messages</description>
33           <description locale="it">Cartella che contiene i messaggi in arrivo</description>
34
35           <homepage>http://www.somewhere.net</homepage>
36   </efolder>
37
38   FIXME: Do we want to use a namespace for this?
39 */
40
41#ifdef HAVE_CONFIG_H
42#include <config.h>
43#endif
44
45#include <string.h>
46#include <unistd.h>
47
48#include <gnome-xml/parser.h>
49#include <gnome-xml/xmlmemory.h>
50
51#include <libgnome/gnome-defs.h>
52#include <libgnome/gnome-util.h>
53#include <gal/util/e-util.h>
54#include <gal/util/e-xml-utils.h>
55
56#include <libgnome/gnome-util.h>
57
58#include "e-local-folder.h"
59
60
61#define PARENT_TYPE E_TYPE_FOLDER
62static EFolderClass *parent_class = NULL;
63
64#define URI_PREFIX     "file://"
65#define URI_PREFIX_LEN 7
66
67/* This provides the name and the description for a specific locale.  */
68struct _I18nInfo {
69        char *language_id;
70        char *name;
71        char *description;
72};
73typedef struct _I18nInfo I18nInfo;
74
75struct _ELocalFolderPrivate {
76        GHashTable *language_id_to_i18n_info;
77};
78
79
80/* Locale information.  */
81
82static char *global_language_id = NULL;
83
84
85/* I18nInfo handling.  */
86
87static I18nInfo *
88i18n_info_new (const char *language_id,
89               const char *name,
90               const char *description)
91{
92        I18nInfo *info;
93
94        info = g_new (I18nInfo, 1);
95        info->language_id = g_strdup (language_id);
96        info->name        = g_strdup (name);
97        info->description = g_strdup (description);
98
99        return info;
100}
101
102static void
103i18n_info_free (I18nInfo *info)
104{
105        g_free (info->language_id);
106        g_free (info->name);
107        g_free (info->description);
108
109        g_free (info);
110}
111
112
113/* Language ID -> I18nInfo hash table handling.  */
114
115static void
116add_i18n_info_to_hash (GHashTable *language_id_to_i18n_info_hash,
117                       I18nInfo *i18n_info)
118{
119        I18nInfo *existing_i18n_info;
120
121        existing_i18n_info = (I18nInfo *) g_hash_table_lookup (language_id_to_i18n_info_hash,
122                                                               i18n_info->language_id);
123        if (existing_i18n_info != NULL) {
124                g_hash_table_remove (language_id_to_i18n_info_hash,
125                                     i18n_info->language_id);
126                i18n_info_free (existing_i18n_info);
127        }
128
129        g_hash_table_insert (language_id_to_i18n_info_hash, i18n_info->language_id, i18n_info);
130}
131
132static void
133language_id_to_i18n_info_hash_foreach_free (void *key,
134                                            void *value,
135                                            void *data)
136{
137        i18n_info_free ((I18nInfo *) value);
138}
139
140static I18nInfo *
141get_i18n_info_for_language (ELocalFolder *local_folder,
142                            const char *language_id)
143{
144        ELocalFolderPrivate *priv;
145        I18nInfo *i18n_info;
146
147        priv = local_folder->priv;
148
149        if (language_id == NULL)
150                language_id = global_language_id;
151
152        i18n_info = g_hash_table_lookup (priv->language_id_to_i18n_info, language_id);
153
154        /* For locale info like `en_UK@yadda', we try to use `en' as a backup.  */
155        /* Note: this is exactly the same thing that gnome-config does with the
156           I18N value handling.  I hope it works.  */
157        if (i18n_info == NULL) {
158                size_t n;
159
160                n = strcspn (language_id, "@_");
161                if (language_id[n] != '\0') {
162                        char *simplified_language_id;
163
164                        simplified_language_id = g_strndup (language_id, n);
165                        i18n_info = g_hash_table_lookup (priv->language_id_to_i18n_info,
166                                                         simplified_language_id);
167                }
168        }
169
170        return i18n_info;
171}
172
173
174/* Locale handling.  */
175
176static void
177setup_global_language_id (void)
178{
179        /* FIXME: Implement.  */
180        global_language_id = "C";
181}
182
183/* Update the EFolder attributes according to the current locale.  */
184static void
185update_for_global_locale (ELocalFolder *local_folder)
186{
187        I18nInfo *i18n_info;
188
189        i18n_info = get_i18n_info_for_language (local_folder, NULL);
190
191        if (i18n_info == NULL)
192                i18n_info = get_i18n_info_for_language (local_folder, "C");
193
194        g_assert (i18n_info != NULL);
195
196        e_folder_set_name        (E_FOLDER (local_folder), i18n_info->name);
197        e_folder_set_description (E_FOLDER (local_folder), i18n_info->description);
198}
199
200
201/* XML tree handling.  */
202
203static char *
204get_string_value (xmlNode *node,
205                  const char *name)
206{
207        xmlNode *p;
208        xmlChar *xml_string;
209        char *retval;
210
211        p = e_xml_get_child_by_name (node, (xmlChar *) name);
212        if (p == NULL)
213                return NULL;
214
215        p = e_xml_get_child_by_name (p, (xmlChar *) "text");
216        if (p == NULL)
217                return NULL;
218
219        xml_string = xmlNodeListGetString (node->doc, p, TRUE);
220        retval = g_strdup ((char *) xml_string);
221        xmlFree (xml_string);
222
223        return retval;
224}
225
226static void
227retrieve_info_item (ELocalFolder *local_folder,
228                    xmlNode *node)
229{
230        xmlChar *lang;
231        char *name;
232        char *description;
233
234        lang        = xmlGetProp (node, "lang");
235        name        = get_string_value (node, "name");
236        description = get_string_value (node, "description");
237
238        if (lang == NULL) {
239                e_local_folder_add_i18n_info (local_folder, "C", name, description);
240        } else {
241                e_local_folder_add_i18n_info (local_folder, lang, name, description);
242                xmlFree (lang);
243        }
244
245        g_free (name);
246        g_free (description);
247}
248
249static void
250retrieve_info (ELocalFolder *local_folder,
251               xmlNode *root_xml_node)
252{
253        ELocalFolderPrivate *priv;
254        xmlNode *p;
255
256        priv = local_folder->priv;
257
258        for (p = root_xml_node->childs; p != NULL; p = p->next) {
259                if (xmlStrcmp (p->name, "info") == 0)
260                        retrieve_info_item (local_folder, p);
261        }
262}
263
264static gboolean
265construct_loading_metadata (ELocalFolder *local_folder,
266                            const char *path)
267{
268        EFolder *folder;
269        xmlDoc *doc;
270        xmlNode *root;
271        char *type;
272        char *metadata_path;
273        char *physical_uri;
274
275        folder = E_FOLDER (local_folder);
276
277        metadata_path = g_concat_dir_and_file (path, E_LOCAL_FOLDER_METADATA_FILE_NAME);
278
279        doc = xmlParseFile (metadata_path);
280        if (doc == NULL) {
281                g_free (metadata_path);
282                return FALSE;
283        }
284
285        root = xmlDocGetRootElement (doc);
286        if (root == NULL || strcmp (root->name, "efolder") != 0) {
287                g_free (metadata_path);
288                xmlFreeDoc (doc);
289                return FALSE;
290        }
291
292        type = get_string_value (root, "type");
293        if (type == NULL) {
294                g_free (metadata_path);
295                xmlFreeDoc (doc);
296                return FALSE;
297        }
298
299        e_local_folder_construct (local_folder, g_basename (path), type, NULL);
300        g_free (type);
301
302        retrieve_info (local_folder, root);
303
304        xmlFreeDoc (doc);
305
306        physical_uri = g_strconcat (URI_PREFIX, path, NULL);
307        e_folder_set_physical_uri (folder, physical_uri);
308        g_free (physical_uri);
309
310        g_free (metadata_path);
311
312        return TRUE;
313}
314
315static gboolean
316save_metadata (ELocalFolder *local_folder)
317{
318        EFolder *folder;
319        xmlDoc *doc;
320        xmlNode *root;
321        const char *physical_directory;
322        char *physical_path;
323
324        folder = E_FOLDER (local_folder);
325
326        doc = xmlNewDoc ((xmlChar *) "1.0");
327        root = xmlNewDocNode (doc, NULL, (xmlChar *) "efolder", NULL);
328        xmlDocSetRootElement (doc, root);
329
330        xmlNewChild (root, NULL, (xmlChar *) "type",
331                     (xmlChar *) e_folder_get_type_string (folder));
332
333        if (e_folder_get_description (folder) != NULL)
334                xmlNewTextChild (root, NULL, (xmlChar *) "description",
335                                 (xmlChar *) e_folder_get_description (folder));
336
337        physical_directory = e_folder_get_physical_uri (folder) + URI_PREFIX_LEN - 1;
338        physical_path = g_concat_dir_and_file (physical_directory, E_LOCAL_FOLDER_METADATA_FILE_NAME);
339
340        if (xmlSaveFile (physical_path, doc) < 0) {
341                unlink (physical_path);
342                g_free (physical_path);
343                xmlFreeDoc (doc);
344                return FALSE;
345        }
346
347        g_free (physical_path);
348
349        xmlFreeDoc (doc);
350        return TRUE;
351}
352
353
354/* GtkObject methods.  */
355
356static void
357destroy (GtkObject *object)
358{
359        ELocalFolder *local_folder;
360        ELocalFolderPrivate *priv;
361
362        local_folder = E_LOCAL_FOLDER (object);
363        priv = local_folder->priv;
364
365        g_hash_table_foreach (priv->language_id_to_i18n_info,
366                              language_id_to_i18n_info_hash_foreach_free,
367                              NULL);
368        g_hash_table_destroy (priv->language_id_to_i18n_info);
369
370        g_free (priv);
371
372        (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
373}
374
375
376static void
377class_init (ELocalFolderClass *klass)
378{
379        GtkObjectClass *object_class;
380
381        parent_class = gtk_type_class (e_folder_get_type ());
382
383        object_class = GTK_OBJECT_CLASS (klass);
384        object_class->destroy = destroy;
385
386        setup_global_language_id ();
387}
388
389static void
390init (ELocalFolder *local_folder)
391{
392        ELocalFolderPrivate *priv;
393
394        priv = g_new (ELocalFolderPrivate, 1);
395        priv->language_id_to_i18n_info = g_hash_table_new (g_str_hash, g_str_equal);
396
397        local_folder->priv = priv;
398}
399
400
401void
402e_local_folder_construct (ELocalFolder *local_folder,
403                          const char *name,
404                          const char *type,
405                          const char *description)
406{
407        ELocalFolderPrivate *priv;
408        I18nInfo *i18n_info;
409
410        g_return_if_fail (local_folder != NULL);
411        g_return_if_fail (E_IS_LOCAL_FOLDER (local_folder));
412        g_return_if_fail (name != NULL);
413        g_return_if_fail (type != NULL);
414
415        priv = local_folder->priv;
416
417        e_folder_construct (E_FOLDER (local_folder), name, type, description);
418
419        i18n_info = i18n_info_new ("C", name, description);
420        add_i18n_info_to_hash (priv->language_id_to_i18n_info, i18n_info);
421}
422
423EFolder *
424e_local_folder_new (const char *name,
425                    const char *type,
426                    const char *description)
427{
428        ELocalFolder *local_folder;
429
430        g_return_val_if_fail (name != NULL, NULL);
431        g_return_val_if_fail (type != NULL, NULL);
432
433        local_folder = gtk_type_new (e_local_folder_get_type ());
434
435        e_local_folder_construct (local_folder, name, type, description);
436
437        return E_FOLDER (local_folder);
438}
439
440EFolder *
441e_local_folder_new_from_path (const char *path)
442{
443        EFolder *folder;
444
445        g_return_val_if_fail (g_path_is_absolute (path), NULL);
446
447        folder = gtk_type_new (e_local_folder_get_type ());
448
449        if (! construct_loading_metadata (E_LOCAL_FOLDER (folder), path)) {
450                gtk_object_unref (GTK_OBJECT (folder));
451                return NULL;
452        }
453
454        return folder;
455}
456
457gboolean
458e_local_folder_save (ELocalFolder *local_folder)
459{
460        g_return_val_if_fail (local_folder != NULL, FALSE);
461        g_return_val_if_fail (E_IS_LOCAL_FOLDER (local_folder), FALSE);
462        g_return_val_if_fail (e_folder_get_physical_uri (E_FOLDER (local_folder)) != NULL, FALSE);
463
464        return save_metadata (local_folder);
465}
466
467
468/**
469 * e_local_folder_add_i18n_info:
470 * @local_folder: A pointer to an ELocalFolder object
471 * @language_id: An I1I8N locale ID
472 * @name: Name for @local_folder in the specified @language_id
473 * @description: Description for @local_folder in the specified @language_id
474 *
475 * Set the @name and @description for the specified @language_id locale.
476 **/
477void
478e_local_folder_add_i18n_info (ELocalFolder *local_folder,
479                              const char *language_id,
480                              const char *name,
481                              const char *description)
482{
483        ELocalFolderPrivate *priv;
484        I18nInfo *info;
485
486        g_return_if_fail (local_folder != NULL);
487        g_return_if_fail (E_IS_LOCAL_FOLDER (local_folder));
488        g_return_if_fail (language_id != NULL);
489        g_return_if_fail (name != NULL || description != NULL);
490
491        priv = local_folder->priv;
492
493        info = i18n_info_new (language_id, name, description);
494        add_i18n_info_to_hash (priv->language_id_to_i18n_info, info);
495
496        update_for_global_locale (local_folder);
497}
498
499/**
500 * e_local_folder_get_i18n_info:
501 * @local_folder: A pointer to an ELocalFolder object
502 * @language_id: The ID of the language whose locale we want to retrieve name
503 * and description for
504 * @language_id_return: The actual locale ID that the name and description are
505 * saved under (e.g. if you ask for an "en_UK@yadda", we might give you the
506 * info for just "en")
507 * @name_return: A pointer to a pointer that will point to the i18nized name on
508 * return.  Can be NULL.
509 * @description_return: A pointer to a pointer that will point to the i18n
510 * description on return.  Can be NULL.
511 *
512 * Retrieve the name and description for @local_folder in the specified locale.
513 *
514 * Return value: %TRUE if some info is found for that @language_id, %FALSE
515 * otherwise.
516 **/
517gboolean
518e_local_folder_get_i18n_info (ELocalFolder *local_folder,
519                              const char *language_id,
520                              const char **language_id_return,
521                              const char **name_return,
522                              const char **description_return)
523{
524        ELocalFolderPrivate *priv;
525        I18nInfo *i18n_info;
526
527        g_return_val_if_fail (local_folder != NULL, FALSE);
528        g_return_val_if_fail (E_IS_LOCAL_FOLDER (local_folder), FALSE);
529        g_return_val_if_fail (language_id != NULL, FALSE);
530
531        priv = local_folder->priv;
532
533        i18n_info = get_i18n_info_for_language (local_folder, language_id);
534
535        if (i18n_info == NULL) {
536                if (language_id_return != NULL)
537                        *language_id_return = NULL;
538                if (name_return != NULL)
539                        *name_return = NULL;
540                if (description_return != NULL)
541                        *description_return = NULL;
542
543                return FALSE;
544        }
545
546        if (language_id_return != NULL)
547                *language_id_return = i18n_info->language_id;
548        if (name_return != NULL)
549                *name_return = i18n_info->name;
550        if (description_return != NULL)
551                *description_return = i18n_info->description;
552
553        return TRUE;
554}
555
556
557E_MAKE_TYPE (e_local_folder, "ELocalFolder", ELocalFolder, class_init, init, PARENT_TYPE)
Note: See TracBrowser for help on using the repository browser.