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

Revision 16865, 9.5 KB checked in by ghudson, 23 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r16864, 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        gboolean found;
279       
280        g_return_if_fail (map != NULL);
281        g_return_if_fail (uid != NULL);
282
283        if (!g_hash_table_lookup_extended (map->uid_map, uid, &ukey, (gpointer *)&unode))
284                return;
285
286        g_hash_table_lookup_extended (map->pid_map, &unode->pid, &pkey, (gpointer *)&pnode);
287
288        g_hash_table_remove (map->uid_map, uid);
289        g_hash_table_remove (map->pid_map, &unode->pid);
290
291        if (unode->pid != 0)
292                g_free (pkey);
293        g_free (ukey);
294
295        if (unode->pid != 0)
296                g_free (pnode);
297        g_free (unode);
298}
299
300
301guint32
302e_pilot_map_lookup_pid (EPilotMap *map, const char *uid, gboolean touch)
303{
304        EPilotMapUidNode *unode = NULL;
305
306        g_return_val_if_fail (map != NULL, 0);
307        g_return_val_if_fail (uid != NULL, 0);
308       
309        unode = g_hash_table_lookup (map->uid_map, uid);
310
311        if (unode == NULL)
312                return 0;
313       
314        if (touch) {
315                EPilotMapPidNode *pnode = NULL;
316               
317                pnode = g_hash_table_lookup (map->pid_map, &unode->pid);
318                if (pnode != NULL)
319                        pnode->touched = TRUE;
320                unode->touched = TRUE; 
321        }
322       
323        return unode->pid;
324}
325
326const char *
327e_pilot_map_lookup_uid (EPilotMap *map, guint32 pid, gboolean touch)
328{
329        EPilotMapPidNode *pnode = NULL;
330
331        g_return_val_if_fail (map != NULL, NULL);
332       
333        pnode = g_hash_table_lookup (map->pid_map, &pid);
334
335        if (pnode == NULL)
336                return NULL;
337       
338        if (touch) {
339                EPilotMapUidNode *unode = NULL;
340               
341                unode = g_hash_table_lookup (map->uid_map, pnode->uid);
342                g_assert (unode != NULL);
343               
344                unode->touched = TRUE;
345                pnode->touched = TRUE;
346        }
347       
348        return pnode->uid;
349}
350
351int
352e_pilot_map_read (const char *filename, EPilotMap **map)
353{
354        xmlSAXHandler handler;
355        EPilotMap *new_map;
356
357        g_return_val_if_fail (filename != NULL, -1);
358        g_return_val_if_fail (map != NULL, -1);
359
360        *map = NULL;
361        new_map = g_new0 (EPilotMap, 1);
362
363        memset (&handler, 0, sizeof (xmlSAXHandler));
364        handler.startElement = map_sax_start_element;
365
366        new_map->pid_map = g_hash_table_new (g_int_hash, g_int_equal);
367        new_map->uid_map = g_hash_table_new (g_str_hash, g_str_equal);
368
369        if (g_file_exists (filename)) {
370                if (xmlSAXUserParseFile (&handler, new_map, filename) < 0) {
371                        g_free (new_map);
372                        return -1;
373                }
374        }
375
376        new_map->write_touched_only = FALSE;
377       
378        *map = new_map;
379       
380        return 0;
381}
382               
383int
384e_pilot_map_write (const char *filename, EPilotMap *map)
385{
386        EPilotMapWriteData wd;
387        xmlDocPtr doc;
388        int ret;
389
390        g_return_val_if_fail (filename != NULL, -1);
391        g_return_val_if_fail (map != NULL, -1);
392       
393        doc = xmlNewDoc ("1.0");
394        if (doc == NULL) {
395                g_warning ("Pilot map file could not be created\n");
396                return -1;
397        }
398        doc->root = xmlNewDocNode(doc, NULL, "PilotMap", NULL);
399        map->since = time (NULL);
400        map_set_node_timet (doc->root, "timestamp", map->since);
401
402        wd.touched_only = map->write_touched_only;
403        wd.root = doc->root;
404        g_hash_table_foreach (map->uid_map, map_write_foreach, &wd);
405       
406        /* Write the file */
407        xmlSetDocCompressMode (doc, 0);
408        ret = xmlSaveFile (filename, doc);
409        if (ret < 0) {
410                g_warning ("Pilot map file '%s' could not be saved\n", filename);
411                return -1;
412        }
413       
414        xmlFreeDoc (doc);
415
416        return 0;
417}
418
419static gboolean
420foreach_remove (gpointer key, gpointer value, gpointer data)
421{
422        g_free (key);
423        g_free (value);
424
425        return TRUE;
426}
427
428void
429e_pilot_map_destroy (EPilotMap *map)
430{
431        g_return_if_fail (map != NULL);
432
433        g_hash_table_foreach_remove (map->pid_map, foreach_remove, NULL);
434        g_hash_table_foreach_remove (map->uid_map, foreach_remove, NULL);
435       
436        g_hash_table_destroy (map->pid_map);
437        g_hash_table_destroy (map->uid_map);
438        g_free (map);
439}
Note: See TracBrowser for help on using the repository browser.