]> git.0d.be Git - empathy.git/blob - libempathy/empathy-contact-groups.c
Put configuration data in XDG_CONFIG_DIRS (GNOME bug 494007)
[empathy.git] / libempathy / empathy-contact-groups.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2005-2007 Imendio AB
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
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., 51 Franklin St, Fifth Floor,
18  * Boston, MA  02110-1301  USA
19  *
20  * Authors: Martyn Russell <martyn@imendio.com>
21  */
22
23 #include "config.h"
24
25 #include <string.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28
29 #include <glib.h>
30 #include <glib/gi18n-lib.h>
31
32 #include <libxml/parser.h>
33 #include <libxml/tree.h>
34
35 #include "empathy-utils.h"
36 #include "empathy-contact-groups.h"
37
38 #define DEBUG_FLAG EMPATHY_DEBUG_CONTACT
39 #include "empathy-debug.h"
40
41 #define CONTACT_GROUPS_XML_FILENAME "contact-groups.xml"
42 #define CONTACT_GROUPS_DTD_FILENAME "empathy-contact-groups.dtd"
43
44 typedef struct {
45         gchar    *name;
46         gboolean  expanded;
47 } ContactGroup;
48
49 static void          contact_groups_file_parse (const gchar  *filename);
50 static gboolean      contact_groups_file_save  (void);
51 static ContactGroup *contact_group_new         (const gchar  *name,
52                                                 gboolean      expanded);
53 static void          contact_group_free        (ContactGroup *group);
54
55 static GList *groups = NULL;
56
57 void
58 empathy_contact_groups_get_all (void)
59 {
60         gchar *dir;
61         gchar *file_with_path;
62
63         /* If already set up clean up first */
64         if (groups) {
65                 g_list_foreach (groups, (GFunc)contact_group_free, NULL);
66                 g_list_free (groups);
67                 groups = NULL;
68         }
69
70         dir = g_build_filename (g_get_user_config_dir (), PACKAGE_NAME, NULL);
71         file_with_path = g_build_filename (dir, CONTACT_GROUPS_XML_FILENAME, NULL);
72         g_free (dir);
73
74         if (g_file_test (file_with_path, G_FILE_TEST_EXISTS)) {
75                 contact_groups_file_parse (file_with_path);
76         }
77
78         g_free (file_with_path);
79 }
80
81 static void
82 contact_groups_file_parse (const gchar *filename)
83 {
84         xmlParserCtxtPtr ctxt;
85         xmlDocPtr        doc;
86         xmlNodePtr       contacts;
87         xmlNodePtr       account;
88         xmlNodePtr       node;
89
90         DEBUG ("Attempting to parse file:'%s'...", filename);
91
92         ctxt = xmlNewParserCtxt ();
93
94         /* Parse and validate the file. */
95         doc = xmlCtxtReadFile (ctxt, filename, NULL, 0);
96         if (!doc) {
97                 g_warning ("Failed to parse file:'%s'", filename);
98                 xmlFreeParserCtxt (ctxt);
99                 return;
100         }
101
102         if (!empathy_xml_validate (doc, CONTACT_GROUPS_DTD_FILENAME)) {
103                 g_warning ("Failed to validate file:'%s'", filename);
104                 xmlFreeDoc (doc);
105                 xmlFreeParserCtxt (ctxt);
106                 return;
107         }
108
109         /* The root node, contacts. */
110         contacts = xmlDocGetRootElement (doc);
111
112         account = NULL;
113         node = contacts->children;
114         while (node) {
115                 if (strcmp ((gchar *) node->name, "account") == 0) {
116                         account = node;
117                         break;
118                 }
119                 node = node->next;
120         }
121
122         node = NULL;
123         if (account) {
124                 node = account->children;
125         }
126
127         while (node) {
128                 if (strcmp ((gchar *) node->name, "group") == 0) {
129                         gchar        *name;
130                         gchar        *expanded_str;
131                         gboolean      expanded;
132                         ContactGroup *contact_group;
133
134                         name = (gchar *) xmlGetProp (node, "name");
135                         expanded_str = (gchar *) xmlGetProp (node, "expanded");
136
137                         if (expanded_str && strcmp (expanded_str, "yes") == 0) {
138                                 expanded = TRUE;
139                         } else {
140                                 expanded = FALSE;
141                         }
142
143                         contact_group = contact_group_new (name, expanded);
144                         groups = g_list_append (groups, contact_group);
145
146                         xmlFree (name);
147                         xmlFree (expanded_str);
148                 }
149
150                 node = node->next;
151         }
152
153         DEBUG ("Parsed %d contact groups", g_list_length (groups));
154
155         xmlFreeDoc (doc);
156         xmlFreeParserCtxt (ctxt);
157 }
158
159 static ContactGroup *
160 contact_group_new (const gchar *name,
161                    gboolean     expanded)
162 {
163         ContactGroup *group;
164
165         group = g_new0 (ContactGroup, 1);
166
167         group->name = g_strdup (name);
168         group->expanded = expanded;
169
170         return group;
171 }
172
173 static void
174 contact_group_free (ContactGroup *group)
175 {
176         g_return_if_fail (group != NULL);
177
178         g_free (group->name);
179
180         g_free (group);
181 }
182
183 static gboolean
184 contact_groups_file_save (void)
185 {
186         xmlDocPtr   doc;
187         xmlNodePtr  root;
188         xmlNodePtr  node;
189         GList      *l;
190         gchar      *dir;
191         gchar      *file;
192
193         dir = g_build_filename (g_get_user_config_dir (), PACKAGE_NAME, NULL);
194         g_mkdir_with_parents (dir, S_IRUSR | S_IWUSR | S_IXUSR);
195         file = g_build_filename (dir, CONTACT_GROUPS_XML_FILENAME, NULL);
196         g_free (dir);
197
198         doc = xmlNewDoc ("1.0");
199         root = xmlNewNode (NULL, "contacts");
200         xmlDocSetRootElement (doc, root);
201
202         node = xmlNewChild (root, NULL, "account", NULL);
203         xmlNewProp (node, "name", "Default");
204
205         for (l = groups; l; l = l->next) {
206                 ContactGroup *cg;
207                 xmlNodePtr    subnode;
208
209                 cg = l->data;
210
211                 subnode = xmlNewChild (node, NULL, "group", NULL);
212                 xmlNewProp (subnode, "expanded", cg->expanded ? "yes" : "no");
213                 xmlNewProp (subnode, "name", cg->name);
214         }
215
216         /* Make sure the XML is indented properly */
217         xmlIndentTreeOutput = 1;
218
219         DEBUG ("Saving file:'%s'", file);
220         xmlSaveFormatFileEnc (file, doc, "utf-8", 1);
221         xmlFreeDoc (doc);
222
223         xmlCleanupParser ();
224         xmlMemoryDump ();
225
226         g_free (file);
227
228         return TRUE;
229 }
230
231 gboolean
232 empathy_contact_group_get_expanded (const gchar *group)
233 {
234         GList    *l;
235         gboolean  default_val = TRUE;
236
237         g_return_val_if_fail (group != NULL, default_val);
238
239         for (l = groups; l; l = l->next) {
240                 ContactGroup *cg = l->data;
241
242                 if (!cg || !cg->name) {
243                         continue;
244                 }
245
246                 if (strcmp (cg->name, group) == 0) {
247                         return cg->expanded;
248                 }
249         }
250
251         return default_val;
252 }
253
254 void
255 empathy_contact_group_set_expanded (const gchar *group,
256                                    gboolean     expanded)
257 {
258         GList        *l;
259         ContactGroup *cg;
260         gboolean      changed = FALSE;
261
262         g_return_if_fail (group != NULL);
263
264         for (l = groups; l; l = l->next) {
265                 ContactGroup *cg = l->data;
266
267                 if (!cg || !cg->name) {
268                         continue;
269                 }
270
271                 if (strcmp (cg->name, group) == 0) {
272                         cg->expanded = expanded;
273                         changed = TRUE;
274                         break;
275                 }
276         }
277
278         /* if here... we don't have a ContactGroup for the group. */
279         if (!changed) {
280                 cg = contact_group_new (group, expanded);
281                 groups = g_list_append (groups, cg);
282         }
283
284         contact_groups_file_save ();
285 }