aboutsummaryrefslogblamecommitdiffstats
path: root/e-util/e-bconf-map.c
blob: 43a39a3fa3a0f815316ec23f66ddf42934d623eb (plain) (tree)










































                                                                           
                                  

















                                                             
                                                                    



































                                                                  
                                                                





                                                         

                                                                                       


















                                                               

                                                                                       
















                                                               
                                                                                         


































































































































                                                                                             
                                                                                        








                                                                                                     
                                                                                                                       
                                
                                                                                                    



































                                                                                        

                                                                                      






                                                                       
                                                                                                  






















































































































                                                                                                                                    
                                                                           

















                                                                                                    
                                                                                    

                                                          

                                                                                                                       












                                                                      
                                                                                            








                                                                  
                                                                                              







                                                                  
                                                                                              






























                                                                                                               
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
 *  Authors: Jeffrey Stedfast <fejj@ximian.com>
 *
 *  Copyright 2004 Ximian, Inc. (www.ximian.com)
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
 *
 */


#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <glib.h>

#include <libxml/tree.h>
#include <libxml/parser.h>
#include <libxml/xmlmemory.h>

#include "e-bconf-map.h"


#define d(x)


static signed char hexnib[256] = {
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
     0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1,
    -1,10,11,12,13,14,15,16,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,10,11,12,13,14,15,16,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
};

char *
e_bconf_hex_decode (const char *val)
{
    const unsigned char *p = (const unsigned char *) val;
    char *o, *res;
    
    o = res = g_malloc (strlen (val) / 2 + 1);
    for (p = (const unsigned char *)val; (p[0] && p[1]); p += 2)
        *o++ = (hexnib[p[0]] << 4) | hexnib[p[1]];
    *o = 0;
    
    return res;
}

char *
e_bconf_url_decode (const char *val)
{
    const unsigned char *p = (const unsigned char *) val;
    char *o, *res, c;
    
    o = res = g_malloc (strlen (val) + 1);
    while (*p) {
        c = *p++;
        if (c == '%'
            && hexnib[p[0]] != -1 && hexnib[p[1]] != -1) {
            *o++ = (hexnib[p[0]] << 4) | hexnib[p[1]];
            p+=2;
        } else
            *o++ = c;
    }
    *o = 0;
    
    return res;
}


xmlNodePtr
e_bconf_get_path (xmlDocPtr doc, const char *path)
{
    xmlNodePtr root;
    char *val;
    int found;
    
    root = doc->children;
    if (strcmp ((char *)root->name, "bonobo-config") != 0) {
        g_warning ("not bonobo-config xml file");
        return NULL;
    }
    
    root = root->children;
    while (root) {
        if (!strcmp ((char *)root->name, "section")) {
            val = (char *)xmlGetProp (root, (const unsigned char *)"path");
            found = val && strcmp (val, path) == 0;
            xmlFree (val);
            if (found)
                break;
        }
        root = root->next;
    }
    
    return root;
}

xmlNodePtr
e_bconf_get_entry (xmlNodePtr root, const char *name)
{
    xmlNodePtr node = root->children;
    int found;
    char *val;
    
    while (node) {
        if (!strcmp ((char *)node->name, "entry")) {
            val = (char *)xmlGetProp (node, (const unsigned char *)"name");
            found = val && strcmp (val, name) == 0;
            xmlFree (val);
            if (found)
                break;
        }
        node = node->next;
    }
    
    return node;
}

char *
e_bconf_get_value (xmlNodePtr root, const char *name)
{
    xmlNodePtr node = e_bconf_get_entry (root, name);
    char *prop, *val = NULL;
    
    if (node && (prop = (char *)xmlGetProp (node, (const unsigned char *)"value"))) {
        val = g_strdup (prop);
        xmlFree (prop);
    }
    
    return val;
}

char *
e_bconf_get_bool (xmlNodePtr root, const char *name)
{
    char *val, *res;
    
    if ((val = e_bconf_get_value (root, name))) {
        res = g_strdup (val[0] == '1' ? "true" : "false");
        g_free (val);
    } else
        res = NULL;
    
    return res;
}

char *
e_bconf_get_long (xmlNodePtr root, const char *name)
{
    char *val, *res;
    
    if ((val = e_bconf_get_value (root, name))) {
        res = g_strdup (val);
        g_free (val);
    } else
        res = NULL;
    
    return res;
}

char *
e_bconf_get_string (xmlNodePtr root, const char *name)
{
    char *val, *res;
    
    if ((val = e_bconf_get_value (root, name))) {
        res = e_bconf_hex_decode (val);
        g_free (val);
    } else
        res = NULL;
    
    return res;
}


/* lookup functions */
typedef char * (* bconf_lookup_func) (xmlNodePtr root, const char *name, e_bconf_map_t *nap);

static char *
bconf_lookup_bool (xmlNodePtr root, const char *name, e_bconf_map_t *map)
{
    return e_bconf_get_bool (root, name);
}

static char *
bconf_lookup_long (xmlNodePtr root, const char *name, e_bconf_map_t *map)
{
    return e_bconf_get_long (root, name);
}

static char *
bconf_lookup_string (xmlNodePtr root, const char *name, e_bconf_map_t *map)
{
    return e_bconf_get_string (root, name);
}

static char *
bconf_lookup_enum (xmlNodePtr root, const char *name, e_bconf_map_t *map)
{
    int index = 0, i;
    char *val;
    
    if ((val = e_bconf_get_value (root, name))) {
        index = atoi (val);
        g_free (val);
    }
    
    for (i = 0; map->child[i].from; i++) {
        if (i == index)
            return g_strdup (map->child[i].from);
    }
    
    return NULL;
}


static bconf_lookup_func lookup_table[] = {
    bconf_lookup_bool, bconf_lookup_long, bconf_lookup_string, bconf_lookup_enum
};

static char *
get_name (const char *in, int index)
{
    GString *out = g_string_new ("");
    char c, *res;
    
    while ((c = *in++)) {
        if (c == '%') {
            c = *in++;
            switch (c) {
            case '%':
                g_string_append_c (out, '%');
                break;
            case 'i':
                g_string_append_printf (out, "%d", index);
                break;
            }
        } else {
            g_string_append_c (out, c);
        }
    }
    
    res = out->str;
    g_string_free (out, FALSE);
    
    return res;
}

static void
build_xml (xmlNodePtr root, e_bconf_map_t *map, int index, xmlNodePtr source)
{
    char *name, *value;
    xmlNodePtr node;
    
    while (map->type != E_BCONF_MAP_END) {
        if ((map->type & E_BCONF_MAP_MASK) == E_BCONF_MAP_CHILD) {
            node = xmlNewChild (root, NULL, (unsigned char *)map->to, NULL);
            build_xml (node, map->child, index, source);
        } else {
            name = get_name (map->from, index);
            value = lookup_table[(map->type & E_BCONF_MAP_MASK) - 1] (source, name, map);
            
            d(printf ("key '%s=%s' -> ", name, value));
            
            if (map->type & E_BCONF_MAP_CONTENT) {
                if (value && value[0])
                    xmlNewTextChild (root, NULL, (unsigned char *)map->to, (unsigned char *)value);
            } else {
                xmlSetProp (root, (unsigned char *)map->to, (unsigned char *)value);
            }
            
            g_free (value);
            g_free (name);
        }
        map++;
    }
}


int
e_bconf_import_xml_blob (GConfClient *gconf, xmlDocPtr config_xmldb, e_bconf_map_t *map,
             const char *bconf_path, const char *gconf_path,
             const char *name, const char *idparam)
{
    xmlNodePtr source;
    int count = 0, i;
    GSList *list, *l;
    char *val;
    
    source = e_bconf_get_path (config_xmldb, bconf_path);
    if (source) {
        list = NULL;
        if ((val = e_bconf_get_value (source, "num"))) {
            count = atoi (val);
            g_free (val);
        }
        
        d(printf("Found %d blobs at %s\n", count, bconf_path));
        
        for (i = 0; i < count; i++) {
            xmlDocPtr doc;
            xmlNodePtr root;
            xmlChar *xmlbuf;
            int n;
            
            doc = xmlNewDoc ((const unsigned char *)"1.0");
            root = xmlNewDocNode (doc, NULL, (unsigned char *)name, NULL);
            xmlDocSetRootElement (doc, root);
            
            /* This could be set with a MAP_UID type ... */
            if (idparam) {
                char buf[16];
                
                sprintf (buf, "%d", i);
                xmlSetProp (root, (unsigned char *)idparam, (unsigned char *)buf);
            }
            
            build_xml (root, map, i, source);
            
            xmlDocDumpMemory (doc, &xmlbuf, &n);
            xmlFreeDoc (doc);
            
            list = g_slist_append (list, xmlbuf);
        }
        
        gconf_client_set_list (gconf, gconf_path, GCONF_VALUE_STRING, list, NULL);
        
        while (list) {
            l = list->next;
            xmlFree (list->data);
            g_slist_free_1 (list);
            list = l;
        }
    } else {
        g_warning ("could not find '%s' in old config database, skipping", bconf_path);
    }
    
    return 0;
}


static int gconf_type[] = { GCONF_VALUE_BOOL, GCONF_VALUE_BOOL, GCONF_VALUE_INT, GCONF_VALUE_STRING, GCONF_VALUE_STRING };

int
e_bconf_import (GConfClient *gconf, xmlDocPtr config_xmldb, e_gconf_map_list_t *remap_list)
{
    char *path, *val, *tmp;
    e_gconf_map_t *map;
    xmlNodePtr source;
    GSList *list, *l;
    char buf[32];
    int i, j, k;
    
    /* process all flat config */
    for (i = 0; remap_list[i].root; i++) {
        d(printf ("Path: %s\n", remap_list[i].root));
        if (!(source = e_bconf_get_path (config_xmldb, remap_list[i].root)))
            continue;
        
        map = remap_list[i].map;
        for (j = 0; map[j].from; j++) {
            if (map[j].type & E_GCONF_MAP_LIST) {
                /* collapse a multi-entry indexed field into a list */
                list = NULL;
                k = 0;
                do {
                    path = get_name (map[j].from, k);
                    val = e_bconf_get_value (source, path);
                    d(printf ("finding path '%s' = '%s'\n", path, val));
                    g_free (path);
                    if (val) {
                        switch (map[j].type & E_GCONF_MAP_MASK) {
                        case E_GCONF_MAP_BOOL:
                        case E_GCONF_MAP_INT:
                            list = g_slist_append (list, GINT_TO_POINTER (atoi (val)));
                            break;
                        case E_GCONF_MAP_STRING:
                            d(printf (" -> '%s'\n", e_bconf_hex_decode (val)));
                            list = g_slist_append (list, e_bconf_hex_decode (val));
                            break;
                        }
                        
                        g_free (val);
                        k++;
                    }
                } while (val);
                
                if (list) {
                    path = g_strdup_printf ("/apps/evolution/%s", map[j].to);
                    gconf_client_set_list (gconf, path, gconf_type[map[j].type & E_GCONF_MAP_MASK], list, NULL);
                    g_free (path);
                    if ((map[j].type & E_GCONF_MAP_MASK) == E_GCONF_MAP_STRING)
                        g_slist_foreach (list, (GFunc) g_free, NULL);
                    g_slist_free (list);
                }
                
                continue;
            } else if (map[j].type == E_GCONF_MAP_ANYLIST) {
                val = NULL;
            } else {
                if (!(val = e_bconf_get_value (source, map[j].from)))
                    continue;
            }
            
            d(printf (" %s = '%s' -> %s [%d]\n",
                  map[j].from,
                  val == NULL ? "(null)" : val,
                  map[j].to,
                  map[j].type));
            
            path = g_strdup_printf ("/apps/evolution/%s", map[j].to);
            switch (map[j].type) {
            case E_GCONF_MAP_BOOL:
                gconf_client_set_bool (gconf, path, atoi (val), NULL);
                break;
            case E_GCONF_MAP_BOOLNOT:
                gconf_client_set_bool (gconf, path, !atoi (val), NULL);
                break;
            case E_GCONF_MAP_INT:
                gconf_client_set_int (gconf, path, atoi (val), NULL);
                break;
            case E_GCONF_MAP_STRING:
                tmp = e_bconf_hex_decode (val);
                gconf_client_set_string (gconf, path, tmp, NULL);
                g_free (tmp);
                break;
            case E_GCONF_MAP_SIMPLESTRING:
                gconf_client_set_string (gconf, path, val, NULL);
                break;
            case E_GCONF_MAP_FLOAT:
                gconf_client_set_float (gconf, path, strtod (val, NULL), NULL);
                break;
            case E_GCONF_MAP_STRLIST: {
                char *v = e_bconf_hex_decode (val);
                char **t = g_strsplit (v, " !<-->!", 8196);
                
                list = NULL;
                for (k = 0; t[k]; k++) {
                    list = g_slist_append (list, t[k]);
                    d(printf ("  [%d] = '%s'\n", k, t[k]));
                }
                
                gconf_client_set_list (gconf, path, GCONF_VALUE_STRING, list, NULL);
                g_slist_free (list);
                g_strfreev (t);
                g_free (v);
                break; }
            case E_GCONF_MAP_ANYLIST: {
                xmlNodePtr node = source->children;
                list = NULL;
                
                /* find the entry node */
                while (node) {
                    if (!strcmp ((char *)node->name, "entry")) {
                        int found;
                        
                        if ((tmp = (char *)xmlGetProp (node, (const unsigned char *)"name"))) {
                            found = strcmp ((char *)tmp, map[j].from) == 0;
                            xmlFree (tmp);
                            if (found)
                                break;
                        }
                    }
                    
                    node = node->next;
                }
                
                /* find the the any block */
                if (node) {
                    node = node->children;
                    while (node) {
                        if (strcmp ((char *)node->name, "any") == 0)
                            break;
                        node = node->next;
                    }
                }
                
                /* skip to the value inside it */
                if (node) {
                    node = node->children;
                    while (node) {
                        if (strcmp ((char *)node->name, "value") == 0)
                            break;
                        node = node->next;
                    }
                }
                
                if (node) {
                    node = node->children;
                    while (node) {
                        if (strcmp ((char *)node->name, "value") == 0)
                            list = g_slist_append (list, xmlNodeGetContent (node));
                        node = node->next;
                    }
                }
                
                /* & store */
                if (list) {
                    gconf_client_set_list (gconf, path, GCONF_VALUE_STRING, list, NULL);
                    while (list) {
                        l = list->next;
                        xmlFree (list->data);
                        g_slist_free_1 (list);
                        list = l;
                    }
                }
                
                break; }
            case E_GCONF_MAP_COLOUR:
                sprintf (buf, "#%06x", atoi (val) & 0xffffff);
                gconf_client_set_string (gconf, path, buf, NULL);
                break;
            }
            
            /* FIXME: handle errors */
            g_free (path);
            g_free (val);
        }
    }
    
    return 0;
}