source: trunk/third/evolution/e-util/e-pilot-map.c @ 17188

Revision 17188, 9.7 KB checked in by ghudson, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r17187, which included commits to RCS files with non-trunk default branches.
Line 
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2/* Evolution Conduits - Pilot Map routines
3 *
4 * Copyright (C) 2000 Ximian, Inc.
5 *
6 * Authors: JP Rosevear <jpr@ximian.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of version 2 of the GNU General Public
10 * License as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public
18 * License along with this program; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
21 */
22
23#include "e-pilot-map.h"
24
25#include <string.h> /* memset(), strcmp() */
26#include <stdlib.h>
27#include <glib.h>
28#include <gnome-xml/parser.h>
29#include <libgnome/gnome-defs.h>
30#include <libgnome/gnome-util.h>
31
32typedef struct
33{
34        char *uid;
35        gboolean archived;
36        gboolean touched;
37} EPilotMapPidNode;
38
39typedef struct
40{
41        guint32 pid;
42        gboolean archived;
43        gboolean touched;
44} EPilotMapUidNode;
45
46typedef struct
47{
48        gboolean touched_only;
49        xmlNodePtr root;
50} EPilotMapWriteData;
51
52static void
53real_e_pilot_map_insert (EPilotMap *map, guint32 pid, const char *uid, gboolean archived, gboolean touch)
54{
55        char *new_uid;
56        guint32 *new_pid;
57        EPilotMapPidNode *pnode;
58        EPilotMapUidNode *unode;
59
60        g_return_if_fail (map != NULL);
61        g_return_if_fail (uid != NULL);
62
63        /* Keys */
64        if (pid != 0) {
65                new_pid = g_new (guint32, 1);
66                *new_pid = pid;
67        }       
68        new_uid = g_strdup (uid);
69
70        /* Values */
71        if (pid != 0) {
72                pnode = g_new0 (EPilotMapPidNode, 1);
73                pnode->uid = new_uid;
74                pnode->archived = archived;
75                if (touch)
76                        pnode->touched = TRUE;
77        }
78       
79        unode = g_new0 (EPilotMapUidNode, 1);
80        unode->pid = pid;
81        unode->archived = archived;
82        if (touch)
83                unode->touched = TRUE;
84       
85        /* Insertion */
86        if (pid != 0)
87                g_hash_table_insert (map->pid_map, new_pid, pnode);
88        g_hash_table_insert (map->uid_map, new_uid, unode);
89}
90
91static void
92map_set_node_timet (xmlNodePtr node, const char *name, time_t t)
93{
94        char *tstring;
95       
96        tstring = g_strdup_printf ("%ld", t);
97        xmlSetProp (node, name, tstring);
98        g_free (tstring);
99}
100
101static void
102map_sax_start_element (void *data, const xmlChar *name,
103                       const xmlChar **attrs)
104{
105        EPilotMap *map = (EPilotMap *)data;
106
107        if (!strcmp (name, "PilotMap")) {
108                while (attrs && *attrs != NULL) {
109                        const xmlChar **val = attrs;
110                       
111                        val++;
112                        if (!strcmp (*attrs, "timestamp"))
113                                map->since = (time_t)strtoul (*val, NULL, 0);
114
115                        attrs = ++val;
116                }
117        }
118         
119        if (!strcmp (name, "map")) {
120                const char *uid = NULL;
121                guint32 pid = 0;
122                gboolean archived = FALSE;
123
124                while (attrs && *attrs != NULL) {
125                        const xmlChar **val = attrs;
126                       
127                        val++;
128                        if (!strcmp (*attrs, "uid"))
129                                uid = *val;
130                       
131                        if (!strcmp (*attrs, "pilot_id"))
132                                pid = strtoul (*val, NULL, 0);
133
134                        if (!strcmp (*attrs, "archived"))
135                                archived = strtoul (*val, NULL, 0)== 1 ? TRUE : FALSE;
136                               
137                        attrs = ++val;
138                }
139
140                g_assert (uid != NULL);
141                g_assert (pid != 0 || archived);
142
143                real_e_pilot_map_insert (map, pid, uid, archived, FALSE);
144        }
145}
146
147static void
148map_write_foreach (gpointer key, gpointer value, gpointer data)
149{
150        EPilotMapWriteData *wd = data;
151        xmlNodePtr root = wd->root;
152        char *uid = key;
153        EPilotMapUidNode *unode = value;
154        xmlNodePtr mnode;
155
156        if (wd->touched_only && !unode->touched)
157                return;
158       
159        mnode = xmlNewChild (root, NULL, "map", NULL);
160        xmlSetProp (mnode, "uid", uid);
161
162        if (unode->archived) {
163                xmlSetProp (mnode, "archived", "1");
164        } else {
165                char *pidstr;
166
167                pidstr = g_strdup_printf ("%d", unode->pid);
168                xmlSetProp (mnode, "pilot_id", pidstr);
169                g_free (pidstr);
170                xmlSetProp (mnode, "archived", "0");
171        }
172}
173
174gboolean
175e_pilot_map_pid_is_archived (EPilotMap *map, guint32 pid)
176{
177        EPilotMapPidNode *pnode;
178
179        g_return_val_if_fail (map != NULL, FALSE);
180       
181        pnode = g_hash_table_lookup (map->pid_map, &pid);
182
183        if (pnode == NULL)
184                return FALSE;
185       
186        return pnode->archived;
187}
188
189gboolean
190e_pilot_map_uid_is_archived (EPilotMap *map, const char *uid)
191{
192        EPilotMapUidNode *unode;
193
194        g_return_val_if_fail (map != NULL, FALSE);
195        g_return_val_if_fail (uid != NULL, FALSE);
196       
197        unode = g_hash_table_lookup (map->uid_map, uid);
198
199        if (unode == NULL)
200                return FALSE;
201       
202        return unode->archived;
203}
204
205void
206e_pilot_map_insert (EPilotMap *map, guint32 pid, const char *uid, gboolean archived)
207{
208        gpointer key, value;
209       
210        if (g_hash_table_lookup_extended (map->pid_map, &pid, &key, &value)) {
211                EPilotMapPidNode *pnode = value;
212                gpointer other_key, other_value;
213
214                g_hash_table_remove (map->pid_map, &pid);
215
216                /* In case the pid<->uid mapping is not the same anymore */
217                if (g_hash_table_lookup_extended (map->uid_map, pnode->uid, &other_key, &other_value)) {
218                        g_hash_table_remove (map->uid_map, pnode->uid);
219                        g_free (other_key);
220                        g_free (other_value);
221                }
222
223                g_free (key);
224                g_free (value);
225        }
226        if (g_hash_table_lookup_extended (map->uid_map, uid, &key, &value)) {
227                EPilotMapUidNode *unode = value;
228                gpointer other_key, other_value;
229
230                g_hash_table_remove (map->uid_map, uid);
231
232                /* In case the pid<->uid mapping is not the same anymore */
233                if (g_hash_table_lookup_extended (map->pid_map, &unode->pid, &other_key, &other_value)) {
234                        g_hash_table_remove (map->pid_map, &unode->pid);
235                        g_free (other_key);
236                        g_free (other_value);
237                }
238
239                g_free (key);
240                g_free (value);
241        }
242
243        real_e_pilot_map_insert (map, pid, uid, archived, TRUE);
244}
245
246void
247e_pilot_map_remove_by_pid (EPilotMap *map, guint32 pid)
248{
249        EPilotMapPidNode *pnode = NULL;
250        EPilotMapUidNode *unode = NULL;
251        gpointer pkey, ukey;
252       
253        g_return_if_fail (map != NULL);
254
255        if (!g_hash_table_lookup_extended (map->pid_map, &pid,
256                                           &pkey, (gpointer *)&pnode))
257                return;
258       
259        g_hash_table_lookup_extended (map->uid_map, pnode->uid, &ukey,
260                                      (gpointer *)&unode);
261        g_assert (unode != NULL);
262       
263        g_hash_table_remove (map->pid_map, &pid);
264        g_hash_table_remove (map->uid_map, pnode->uid);
265
266        g_free (pkey);
267        g_free (ukey);
268        g_free (pnode);
269        g_free (unode);
270}
271
272void
273e_pilot_map_remove_by_uid (EPilotMap *map, const char *uid)
274{
275        EPilotMapPidNode *pnode = NULL;
276        EPilotMapUidNode *unode = NULL;
277        gpointer pkey, ukey;
278       
279        g_return_if_fail (map != NULL);
280        g_return_if_fail (uid != NULL);
281
282        if (!g_hash_table_lookup_extended (map->uid_map, uid, &ukey, (gpointer *)&unode))
283                return;
284
285        g_hash_table_lookup_extended (map->pid_map, &unode->pid, &pkey, (gpointer *)&pnode);
286
287        g_hash_table_remove (map->uid_map, uid);
288        g_hash_table_remove (map->pid_map, &unode->pid);
289
290        if (unode->pid != 0)
291                g_free (pkey);
292        g_free (ukey);
293
294        if (unode->pid != 0)
295                g_free (pnode);
296        g_free (unode);
297}
298
299
300guint32
301e_pilot_map_lookup_pid (EPilotMap *map, const char *uid, gboolean touch)
302{
303        EPilotMapUidNode *unode = NULL;
304
305        g_return_val_if_fail (map != NULL, 0);
306        g_return_val_if_fail (uid != NULL, 0);
307       
308        unode = g_hash_table_lookup (map->uid_map, uid);
309
310        if (unode == NULL)
311                return 0;
312       
313        if (touch) {
314                EPilotMapPidNode *pnode = NULL;
315               
316                pnode = g_hash_table_lookup (map->pid_map, &unode->pid);
317                if (pnode != NULL)
318                        pnode->touched = TRUE;
319                unode->touched = TRUE; 
320        }
321       
322        return unode->pid;
323}
324
325const char *
326e_pilot_map_lookup_uid (EPilotMap *map, guint32 pid, gboolean touch)
327{
328        EPilotMapPidNode *pnode = NULL;
329
330        g_return_val_if_fail (map != NULL, NULL);
331       
332        pnode = g_hash_table_lookup (map->pid_map, &pid);
333
334        if (pnode == NULL)
335                return NULL;
336       
337        if (touch) {
338                EPilotMapUidNode *unode = NULL;
339               
340                unode = g_hash_table_lookup (map->uid_map, pnode->uid);
341                g_assert (unode != NULL);
342               
343                unode->touched = TRUE;
344                pnode->touched = TRUE;
345        }
346       
347        return pnode->uid;
348}
349
350int
351e_pilot_map_read (const char *filename, EPilotMap **map)
352{
353        xmlSAXHandler handler;
354        EPilotMap *new_map;
355
356        g_return_val_if_fail (filename != NULL, -1);
357        g_return_val_if_fail (map != NULL, -1);
358
359        *map = NULL;
360        new_map = g_new0 (EPilotMap, 1);
361
362        memset (&handler, 0, sizeof (xmlSAXHandler));
363        handler.startElement = map_sax_start_element;
364
365        new_map->pid_map = g_hash_table_new (g_int_hash, g_int_equal);
366        new_map->uid_map = g_hash_table_new (g_str_hash, g_str_equal);
367
368        if (g_file_exists (filename)) {
369                if (xmlSAXUserParseFile (&handler, new_map, filename) < 0) {
370                        g_free (new_map);
371                        return -1;
372                }
373        }
374
375        new_map->write_touched_only = FALSE;
376       
377        *map = new_map;
378       
379        return 0;
380}
381               
382int
383e_pilot_map_write (const char *filename, EPilotMap *map)
384{
385        EPilotMapWriteData wd;
386        xmlDocPtr doc;
387        int ret;
388
389        g_return_val_if_fail (filename != NULL, -1);
390        g_return_val_if_fail (map != NULL, -1);
391       
392        doc = xmlNewDoc ("1.0");
393        if (doc == NULL) {
394                g_warning ("Pilot map file could not be created\n");
395                return -1;
396        }
397        doc->root = xmlNewDocNode(doc, NULL, "PilotMap", NULL);
398        map->since = time (NULL);
399        map_set_node_timet (doc->root, "timestamp", map->since);
400
401        wd.touched_only = map->write_touched_only;
402        wd.root = doc->root;
403        g_hash_table_foreach (map->uid_map, map_write_foreach, &wd);
404       
405        /* Write the file */
406        xmlSetDocCompressMode (doc, 0);
407        ret = xmlSaveFile (filename, doc);
408        if (ret < 0) {
409                g_warning ("Pilot map file '%s' could not be saved\n", filename);
410                return -1;
411        }
412       
413        xmlFreeDoc (doc);
414
415        return 0;
416}
417
418static gboolean
419foreach_remove (gpointer key, gpointer value, gpointer data)
420{
421        g_free (key);
422        g_free (value);
423
424        return TRUE;
425}
426
427void
428e_pilot_map_clear (EPilotMap *map)
429{
430        g_return_if_fail (map != NULL);
431
432        g_hash_table_foreach_remove (map->pid_map, foreach_remove, NULL);
433        g_hash_table_foreach_remove (map->uid_map, foreach_remove, NULL);
434
435        map->since = 0;
436        map->write_touched_only = FALSE;
437}
438
439void
440e_pilot_map_destroy (EPilotMap *map)
441{
442        g_return_if_fail (map != NULL);
443
444        g_hash_table_foreach_remove (map->pid_map, foreach_remove, NULL);
445        g_hash_table_foreach_remove (map->uid_map, foreach_remove, NULL);
446       
447        g_hash_table_destroy (map->pid_map);
448        g_hash_table_destroy (map->uid_map);
449        g_free (map);
450}
Note: See TracBrowser for help on using the repository browser.