/* * xmlformat-common - common code for all xmlformat converter * Copyright (C) 2004-2005 Armin Bauer * Copyright (C) 2006 Daniel Friedrich * Copyright (C) 2007 Daniel Gollub * Copyright (C) 2007 Jerry Yu * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "xmlformat-common.h" /* Attributes */ OSyncXMLField *handle_attribute_simple_content_timestamp(OSyncXMLFormat *xmlformat, VFormatAttribute *attr, const char *name, OSyncError **error) { osync_trace(TRACE_INTERNAL, "Handling %s attribute with timestamp", name); OSyncXMLField *xmlfield = osync_xmlfield_new(xmlformat, name, error); if (!xmlfield) goto error; char *timestamp = osync_time_timestamp(vformat_attribute_get_nth_value(attr, 0)); if (!osync_xmlfield_set_key_value(xmlfield, "Content", timestamp, error)) goto error; osync_free(timestamp); return xmlfield; error: osync_trace(TRACE_ERROR, "%s: %s" , __func__, osync_error_print(error)); return NULL; } OSyncXMLField *handle_attribute_simple_content(OSyncXMLFormat *xmlformat, VFormatAttribute *attr, const char *name, OSyncError **error) { osync_trace(TRACE_INTERNAL, "Handling %s attribute", name); OSyncXMLField *xmlfield = osync_xmlfield_new(xmlformat, name, error); if (!xmlfield) goto error; if (!osync_xmlfield_set_key_value(xmlfield, "Content", vformat_attribute_get_nth_value(attr, 0), error)) goto error; return xmlfield; error: osync_trace(TRACE_ERROR, "%s: %s" , __func__, osync_error_print(error)); return NULL; } OSyncXMLField *handle_categories_attribute(OSyncXMLFormat *xmlformat, VFormatAttribute *attr, OSyncError **error) { osync_trace(TRACE_INTERNAL, "Handling Categories attribute"); OSyncXMLField *xmlfield = osync_xmlfield_new(xmlformat, "Categories", error); if (!xmlfield) goto error; GList *values = vformat_attribute_get_values_decoded(attr); for (; values; values = values->next) { GString *retstr = (GString *)values->data; g_assert(retstr); osync_xmlfield_add_key_value(xmlfield, "Category", retstr->str, error); } return xmlfield; error: osync_trace(TRACE_ERROR, "%s: %s" , __func__, osync_error_print(error)); return NULL; } OSyncXMLField *handle_class_attribute(OSyncXMLFormat *xmlformat, VFormatAttribute *attr, OSyncError **error) { osync_trace(TRACE_INTERNAL, "Handling Class attribute"); OSyncXMLField *xmlfield = osync_xmlfield_new(xmlformat, "Class", error); if (!xmlfield) goto error; if (!osync_xmlfield_set_key_value(xmlfield, "Content", vformat_attribute_get_nth_value(attr, 0), error)) goto error; return xmlfield; error: osync_trace(TRACE_ERROR, "%s: %s" , __func__, osync_error_print(error)); return NULL; } OSyncXMLField *handle_uid_attribute(OSyncXMLFormat *xmlformat, VFormatAttribute *attr, OSyncError **error) { return handle_attribute_simple_content(xmlformat, attr, "Uid", error); } OSyncXMLField *handle_url_attribute(OSyncXMLFormat *xmlformat, VFormatAttribute *attr, OSyncError **error) { return handle_attribute_simple_content(xmlformat, attr, "Url", error); } /* TODO: changed prototype to: * osync_bool handle_simple_xmlfield(OSyncXMLField *xmlfield, VFormatAttribute *attr, const char *name, OSyncError **error) */ osync_bool handle_simple_xmlfield(OSyncXMLField *xmlfield, VFormatAttribute *attr, const char *name) { osync_trace(TRACE_INTERNAL, "Handling %s component attribute", name); if (!osync_xmlfield_set_key_value(xmlfield, name, vformat_attribute_get_nth_value(attr, 0), NULL)) goto error; return TRUE; error: return FALSE; } /* FIXME - replace all callers with proper error handling code! */ osync_bool FIXME_xmlfield_set_key_value(OSyncXMLField *xmlfield, const char *key, const char *value) { return osync_xmlfield_set_key_value(xmlfield, key, value, NULL /* ERROR */); } /* XML Attributes */ VFormatAttribute *handle_xml_attribute_simple_content(VFormat *vformat, OSyncXMLField *xmlfield, const char *name, const char *encoding) { g_assert(vformat); g_assert(xmlfield); g_assert(name); osync_trace(TRACE_INTERNAL, "Handling \"%s\" xml attribute", name); VFormatAttribute *attr = vformat_attribute_new(NULL, name); add_values(attr, xmlfield, encoding); vformat_add_attribute(vformat, attr); return attr; } VFormatAttribute *handle_xml_attribute_simple_content_timestamp(VFormat *vformat, OSyncXMLField *xmlfield, const char *name, const char *encoding) { g_assert(vformat); g_assert(xmlfield); g_assert(name); VFormatAttribute *attr = vformat_attribute_new(NULL, name); const char *tmp = osync_xmlfield_get_key_value(xmlfield, "Content"); char *timestamp = NULL; if( tmp ) { // vformat must not have any separators in its timestamp, // so run the timestamp through osync_time_timestamp() // just to make sure it is in a valid state, in case // a plugin gave us an ISO 8601 timestamp timestamp = osync_time_timestamp(tmp); } else { timestamp = strdup(""); } add_value_data(attr, xmlfield, timestamp, encoding); // TODO timezone // char *tzid = osxml_find_node(xmlfield, "TimezoneID") // vformat_attribute_add_param_with_value(attr, "TZID", tzid); // g_free(tzid); vformat_add_attribute(vformat, attr); osync_free(timestamp); return attr; } VFormatAttribute *handle_xml_categories_attribute(VFormat *vformat, OSyncXMLField *xmlfield, const char *encoding) { return handle_xml_attribute_simple_content(vformat, xmlfield, "CATEGORIES", encoding); } VFormatAttribute *handle_xml_class_attribute(VFormat *vformat, OSyncXMLField *xmlfield, const char *encoding) { return handle_xml_attribute_simple_content(vformat, xmlfield, "CLASS", encoding); } VFormatAttribute *handle_xml_uid_attribute(VFormat *vformat, OSyncXMLField *xmlfield, const char *encoding) { return handle_xml_attribute_simple_content(vformat, xmlfield, "UID", encoding); } VFormatAttribute *handle_xml_url_attribute(VFormat *vformat, OSyncXMLField *xmlfield, const char *encoding) { return handle_xml_attribute_simple_content(vformat, xmlfield, "URL", encoding); } /* Encoding helpers */ osync_bool needs_encoding(const unsigned char *tmp, const char *encoding) { int i = 0; if (!strcmp(encoding, "QUOTED-PRINTABLE")) { while (tmp[i] != 0) { if (tmp[i] > 127 || tmp[i] == 10 || tmp[i] == 13) return TRUE; i++; } } else { return !g_utf8_validate((gchar*)tmp, -1, NULL); } return FALSE; } osync_bool needs_charset(const unsigned char *tmp) { int i = 0; while (tmp[i] != 0) { if (tmp[i] > 127) return TRUE; i++; } return FALSE; } /* Attribute helpers */ void add_value(VFormatAttribute *attr, OSyncXMLField *xmlfield, const char *name, const char *encoding) { g_assert(xmlfield); g_assert(name); const char *tmp = osync_xmlfield_get_key_value(xmlfield, name); if (!tmp) { /* If there is no node with the given name, add an empty value to the list. * This is necessary because some fields (N and ADR, for example) need * a specific order of the values */ tmp = ""; } add_value_data(attr, xmlfield, tmp, encoding); } void add_value_data(VFormatAttribute *attr, OSyncXMLField *xmlfield, const char *data, const char *encoding) { g_assert(xmlfield); g_assert(data); const char *tmp = data; if (needs_charset((unsigned char*)tmp)) if (!vformat_attribute_has_param (attr, "CHARSET")) vformat_attribute_add_param_with_value(attr, "CHARSET", "UTF-8"); /* XXX: This one breaks unit test case: conv_vcard_evolution2_special TODO: Combine this with converter extension/config ... e.g. if a mobile needs QP! */ if (needs_encoding((unsigned char*)tmp, encoding)) { if (!vformat_attribute_has_param (attr, "ENCODING")) vformat_attribute_add_param_with_value(attr, "ENCODING", encoding); vformat_attribute_add_value_decoded(attr, tmp, strlen(tmp) + 1); } else vformat_attribute_add_value(attr, tmp); } void add_value_array(VFormatAttribute *attr, OSyncXMLField *xmlfield, const char *parameterNameArray[], int nParameters, const char *encoding) { const char **parameterValueArray = malloc(nParameters*sizeof(char*)); int n=-1; int i; for (i=0; inext) { char *value = v->data; if (strlen(value) != 0) goto has_value; } osync_trace(TRACE_EXIT, "%s: No values", __func__); return; has_value:; //We need to find the handler for this attribute OSyncXMLField *(* attr_handler)(OSyncXMLFormat *, VFormatAttribute *, OSyncError **) = g_hash_table_lookup(attrtable, vformat_attribute_get_name(attr)); osync_trace(TRACE_INTERNAL, "Hook is: %p", attr_handler); if (attr_handler == HANDLE_IGNORE || attr_handler == NULL) { osync_trace(TRACE_EXIT, "%s: Ignored", __func__); return; } if (attr_handler) xmlfield = attr_handler(xmlformat, attr, error); // else // xmlfield = handle_unknown_attribute(xmlformat, attr, error); //Handle all parameters of this attribute GList *params = vformat_attribute_get_params(attr); GList *p = NULL; osync_trace(TRACE_INTERNAL, "Number of parameters: %i", g_list_length(params)); for (p = params; p; p = p->next) { VFormatParam *param = p->data; handle_parameter(paramtable, xmlfield, param); } osync_trace(TRACE_EXIT, "%s", __func__); } void handle_component_attribute(GHashTable *attrtable, GHashTable *paramtable, OSyncXMLField *xmlfield, VFormatAttribute *attr, OSyncError **error) { osync_trace(TRACE_ENTRY, "%s(%p, %p, %p, %p:%s, %p)", __func__, attrtable, paramtable, xmlfield, attr, attr ? vformat_attribute_get_name(attr) : "None", error); //Dont add empty stuff GList *v; for (v = vformat_attribute_get_values(attr); v; v = v->next) { char *value = v->data; if (strlen(value) != 0) goto has_value; } osync_trace(TRACE_EXIT, "%s: No values", __func__); return; has_value:; //We need to find the handler for this attribute void (* attr_handler)(OSyncXMLField *, VFormatAttribute *) = g_hash_table_lookup(attrtable, vformat_attribute_get_name(attr)); osync_trace(TRACE_INTERNAL, "Hook is: %p", attr_handler); if (attr_handler == HANDLE_IGNORE) { osync_trace(TRACE_EXIT, "%s: Ignored", __func__); return; } if (attr_handler) attr_handler(xmlfield, attr); // else // xmlfield = handle_unknown_attribute(xmlfield, attr, error); //Handle all parameters of this attribute GList *params = vformat_attribute_get_params(attr); GList *p = NULL; osync_trace(TRACE_INTERNAL, "Number of parameters: %i", g_list_length(params)); for (p = params; p; p = p->next) { VFormatParam *param = p->data; handle_parameter(paramtable, xmlfield, param); } osync_trace(TRACE_EXIT, "%s", __func__); } void xml_handle_parameter(OSyncHookTables *hooks, VFormatAttribute *attr, OSyncXMLField *xmlfield, int attr_nr) { osync_trace(TRACE_ENTRY, "%s(%p, %p, %p:%s, %i)", __func__, hooks, attr, xmlfield, xmlfield ? osync_xmlfield_get_name(xmlfield) : "None", attr_nr); //Find the handler for this parameter const char* par_name = osync_xmlfield_get_nth_attr_name(xmlfield, attr_nr); const char* par_value = osync_xmlfield_get_nth_attr_value(xmlfield, attr_nr); void (* xml_param_handler)(VFormatAttribute *attr, OSyncXMLField *); char *paramname = g_strdup_printf("%s=%s", par_name, par_value); xml_param_handler = g_hash_table_lookup(hooks->parameters, paramname); g_free(paramname); if (!xml_param_handler) xml_param_handler = g_hash_table_lookup(hooks->parameters, par_name); if (xml_param_handler == HANDLE_IGNORE) { osync_trace(TRACE_EXIT, "%s: Ignored", __func__); return; } if (xml_param_handler) xml_param_handler(attr, xmlfield); else osync_trace(TRACE_INTERNAL, "No handler found!!!"); osync_trace(TRACE_EXIT, "%s", __func__); } void xml_handle_attribute(OSyncHookTables *hooks, VFormat *vformat, OSyncXMLField *xmlfield, const char *encoding) { osync_trace(TRACE_ENTRY, "%s(%p, %p, %p:%s)", __func__, hooks, vformat, xmlfield, xmlfield ? osync_xmlfield_get_name(xmlfield) : "None"); VFormatAttribute *attr = NULL; //We need to find the handler for this attribute VFormatAttribute *(* xml_attr_handler)(VFormat *vformat, OSyncXMLField *xmlfield, const char *) = g_hash_table_lookup(hooks->attributes, osync_xmlfield_get_name(xmlfield)); osync_trace(TRACE_INTERNAL, "xml hook is: %p", xml_attr_handler); if (xml_attr_handler == HANDLE_IGNORE) { osync_trace(TRACE_EXIT, "%s: Ignored", __func__); return; } if (xml_attr_handler) attr = xml_attr_handler(vformat, xmlfield, encoding); else { osync_trace(TRACE_EXIT, "%s: Ignored2", __func__); return; } //Handle all parameters of this attribute int i, c = osync_xmlfield_get_attr_count(xmlfield); for(i=0; iattributes, name); osync_trace(TRACE_INTERNAL, "xml hook is: %p", xml_attr_handler); if (xml_attr_handler == HANDLE_IGNORE) { osync_trace(TRACE_INTERNAL, "%s: Ignored", name); continue; } if (xml_attr_handler) { osync_trace(TRACE_INTERNAL, "Handling \"%s\" xml attribute", name); attr = xml_attr_handler(vformat, xmlfield, encoding); } else { osync_trace(TRACE_INTERNAL, "%s: Ignored2", name); } } /* * component attributes handle parameter directly * //Handle all parameters of this attribute int i, c = osync_xmlfield_get_attr_count(xmlfield); for(i=0; i