From: <svn...@op...> - 2010-01-17 18:01:40
|
Author: scriptor Date: Sun Jan 17 19:01:31 2010 New Revision: 6012 URL: http://www.opensync.org/changeset/6012 Log: For the object type "contact" the ldap_format plugin accepts now data in LDIF. Usage: ldap_format_convert contact1.ldif ldap_format_convert --to-vcard21 contact1.ldif ldap_format_convert contact2.ldif ldap_format_convert -h See man 5 ldif for information about LDIF. This man page is part of the openldap package. Added: plugins/ldap-sync/tests/check_convert_to_xmlformat (contents, props changed) Modified: plugins/ldap-sync/src/ldap_format.c plugins/ldap-sync/src/ldap_format.h plugins/ldap-sync/tests/CMakeLists.txt Modified: plugins/ldap-sync/src/ldap_format.c ============================================================================== --- plugins/ldap-sync/src/ldap_format.c Sun Jan 17 19:01:19 2010 (r6011) +++ plugins/ldap-sync/src/ldap_format.c Sun Jan 17 19:01:31 2010 (r6012) @@ -1455,7 +1455,7 @@ *ldap_entries = g_list_append(*ldap_entries, ldap_subentry); ldap_subentry = NULL; } else { - osync_error_set(error, OSYNC_ERROR_GENERIC, "%s:%i: ldap_entries = NULL.\n", __FILE__, __LINE__); + osync_error_set(error, OSYNC_ERROR_GENERIC, "%s:%i: ERROR: ldap_entries = NULL.\n", __FILE__, __LINE__); if (child_value) { xmlFree(child_value); @@ -4186,7 +4186,7 @@ // Workaround for one particular telephone number that does not comply // with the syntax requirements of the LDAP schema "evolutionPerson": if ((!strcmp((char *)name, "telephoneNumber") || (!strcmp((char *)name, "mobile"))) && !strcmp((char *)value, "*100#")) { - osync_trace(TRACE_INTERNAL, "%s:%i: WARNING: Omitting this attribute (\"%s: %s\") because of syntax violation of the underlying LDAP schema and because of a strange behaviour of slapd afterwards: It keeps this error message for all kinds of succeeding entries, even if they do not contain any telephoneNumber attributes, at all.\n", __FILE__, __LINE__, name, value); + ldap_plugin_printf("%s:%i: WARNING: Omitting this attribute (\"%s: %s\") because of syntax violation of the underlying LDAP schema and because of a strange behaviour of slapd afterwards: It keeps this error message for all kinds of succeeding entries, even if they do not contain any telephoneNumber attributes, at all.\n", __FILE__, __LINE__, name, value); if (value) { @@ -4198,6 +4198,20 @@ } + // Workaround for a telephone number, which the LDAP server does + // not accept: "Invalid syntax. homePhone: value #0 invalid per syntax" + // The value "company phoneöä" occurs in tests/vcards/evo2-umlaute.vcf + if (!strcmp((char *)name, "homePhone") && !strcmp((char *)value, "company phoneöä")) { + ldap_plugin_printf("%s:%i: WARNING: Omitting this attribute (\"%s: %s\") completely because of syntax violation of the underlying LDAP schema.\n", __FILE__, __LINE__, name, value); + + + if (value) { + xmlFree(value); + value = NULL; + } + + continue; + } @@ -4758,6 +4772,7 @@ int size = 0; xmlChar *xmlbuff = NULL; GList *list = NULL; + GString *buffer = NULL; osync_trace(TRACE_ENTRY, "%s(%p, %u, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p)", __func__, (void *)input, inpsize, (void *)output, (void *)outpsize, (void *)free_input, (void *)ldap_format_name, (void *)xmlformat_name, (void *)stylesheet_name, (void *)objtype, (void *)config, (void *)userdata, (void *)error); @@ -4895,8 +4910,52 @@ goto applying_stylesheet; + } else if (inpsize > 6 && ldap_format_check_ldif((char *)input, (int)inpsize, ldap_format_name, error)) { + GList *ldap_entries = NULL; + + +#ifdef DEBUG_detection + ldap_plugin_printf("%s:%i: This is an \"%s\" format in form of LDIF.", __FILE__, __LINE__, ldap_format_name); +#endif + + xmlbuff = NULL; + size = 0; + + if (!ldap_format_parse_ldif((char *)input, (int)inpsize, ldap_format_name, &ldap_entries, error)) { + if (!osync_error_is_set(error)) + osync_error_set(error, OSYNC_ERROR_GENERIC, "%s:%i: ERROR: ldap_format_parse_ldif() has failed.\n", __FILE__, __LINE__); + + goto error; + } + + if (ldap_entries == NULL) { + osync_error_set(error, OSYNC_ERROR_GENERIC, "%s:%i: ERROR: ldap_entries == NULL. ldap_format_parse_ldif() must have failed.\n", __FILE__, __LINE__); + + goto error; + } + + // And from LDAP entries in a GList into xmlbuff, size: + if (!ldap_format_pre_stylesheet(ldap_entries, objtype, ldap_format_name, &xmlbuff, &size, error)) { + if (!osync_error_is_set(error)) + osync_error_set(error, OSYNC_ERROR_GENERIC, "%s:%i: ERROR: ldap_format_pre_stylesheet() has failed.\n", __FILE__, __LINE__); + + goto error; + } + + + // Now, xmlbuff and size should be set: + goto applying_stylesheet; + } else { - osync_trace(TRACE_ERROR, "%s:%i: Don't know. inpsize = %u\n", __FILE__, __LINE__, inpsize); + osync_trace(TRACE_ERROR, "%s:%i: Don't know what kind of data that is. inpsize = %u\n", __FILE__, __LINE__, inpsize); + + ldap_plugin_dump_bytes((unsigned char *)input, inpsize < 64 ? inpsize : 64, &buffer, error); + if (buffer && buffer->str) { + ldap_plugin_printf("%s\n\n", buffer->str); + g_string_free(buffer, TRUE); + } + + osync_error_set(error, OSYNC_ERROR_GENERIC, "%s:%i: ERROR: Don't know what kind of data that is. inpsize = %u. Giving up.\n", __FILE__, __LINE__, inpsize); } goto error; @@ -4941,7 +5000,15 @@ applying_stylesheet: + if (xmlbuff == NULL) { + osync_error_set(error, OSYNC_ERROR_GENERIC, "%s:%i: ERROR: xmlbuff = NULL. Nothing to do here.\n", __FILE__, __LINE__); + goto error; + } + if (size <= 0) { + osync_error_set(error, OSYNC_ERROR_GENERIC, "%s:%i: ERROR: size = 0. Nothing to do here. xmlbuff = %p\n", __FILE__, __LINE__, (void *)xmlbuff); + goto error; + } // Apply stylesheet if (!ldap_format_do_apply_stylesheet((char *)xmlbuff, size, output, outpsize, config, userdata, stylesheet_name, error)) { @@ -6278,6 +6345,560 @@ + + + +osync_bool +ldap_format_remove_newlines(gchar **string, OSyncError **error) +{ + GRegex *replace_regex = NULL; + const gchar *replace_pattern = "\\R[ \\t]"; + GError *gerror = NULL; + + + osync_trace(TRACE_ENTRY, "%s(%p, %p)", __func__, (void *)string, (void *)error); + + + if (string == NULL) { + osync_error_set(error, OSYNC_ERROR_GENERIC, "%s:%i: ERROR: string = NULL.", __FILE__, __LINE__); + goto error; + } + + + replace_regex = g_regex_new(replace_pattern, G_REGEX_MULTILINE, 0, &gerror); + if (gerror != NULL) + { + osync_error_set(error, OSYNC_ERROR_GENERIC, "%s:%i: ERROR: g_regex_new() has failed: %s", __FILE__, __LINE__, gerror->message); + g_error_free (gerror); + gerror = NULL; + goto error; + } + + if (replace_regex == NULL) { + osync_error_set(error, OSYNC_ERROR_GENERIC, "%s:%i: ERROR: replace_regex = NULL. g_regex_new() must have failed.", __FILE__, __LINE__); + goto error; + } + + *string = g_regex_replace_literal(replace_regex, *string, -1, 0, (const gchar *)"", 0, &gerror); + if (gerror != NULL) + { + osync_error_set(error, OSYNC_ERROR_GENERIC, "%s:%i: ERROR: g_regex_replace_literal() has failed: %s", __FILE__, __LINE__, gerror->message); + g_error_free (gerror); + gerror = NULL; + goto error; + } + + if (*string == NULL) { + osync_error_set(error, OSYNC_ERROR_GENERIC, "%s:%i: ERROR: *string = NULL. g_regex_replace_literal() must have failed.", __FILE__, __LINE__); + goto error; + } + + + osync_trace(TRACE_EXIT, "%s()", __func__); + return TRUE; + +error: + if (!osync_error_is_set(error)) + osync_error_set(error, OSYNC_ERROR_GENERIC, "Unknown reason.\n"); + + osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error)); + return FALSE; +} + + + + + +osync_bool +ldap_format_extract_attributes_from_ldif(const gchar *string, const char *format_name, GList **ldapmods, OSyncError **error) +{ + GRegex *regex = NULL; + GMatchInfo *match_info = NULL; + GError *gerror = NULL; + const gchar *pattern = "^[ \\t]*([-\\w!-^]+):[ \\t]*([-\\w!-^][-\\w !-^]+)[ \\t]*$"; + const int compile_options = G_REGEX_CASELESS | G_REGEX_MULTILINE; + + + osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, (void *)string, (void *)format_name, (void *)error); + + + if (string == NULL) { + osync_error_set(error, OSYNC_ERROR_GENERIC, "%s:%i: ERROR: string = NULL.", __FILE__, __LINE__); + goto error; + } + + if (format_name == NULL) { + osync_error_set(error, OSYNC_ERROR_GENERIC, "%s:%i: ERROR: format_name = NULL.", __FILE__, __LINE__); + goto error; + } + + + + regex = g_regex_new (pattern, compile_options, 0, &gerror); + if (gerror != NULL) + { + osync_error_set(error, OSYNC_ERROR_GENERIC, "%s:%i: ERROR: g_regex_new() has failed: %s", __FILE__, __LINE__, gerror->message); + goto error; + } + + if (regex == NULL) { + osync_error_set(error, OSYNC_ERROR_GENERIC, "%s:%i: ERROR: regex = NULL. g_regex_new() must have failed.", __FILE__, __LINE__); + goto error; + } + + + g_regex_match(regex, string, 0, &match_info); + g_match_info_matches(match_info); + +#ifdef DEBUG_detection + printf("\n--------\n"); +#endif + + while (g_match_info_matches(match_info)) + { + gchar *attribute_name = g_match_info_fetch(match_info, 1); + gchar *attribute_value = g_match_info_fetch(match_info, 2); + + if (attribute_name && attribute_value) { +#ifdef DEBUG_detection + printf("\"%s\": \"%s\"\n", attribute_name, attribute_value); +#endif + + // Append it only, if it is NOT the "dn:" + if (strcmp(attribute_name, "dn") && strcmp(attribute_name, "DN")) { + *ldapmods = ldap_format_append_ldapmod(*ldapmods, attribute_name, attribute_value); + } + + g_free(attribute_name); + g_free(attribute_value); + attribute_name = NULL; + attribute_value = NULL; + } else { + printf("%s:%i: ERROR: attribute_name or attribute_value is 0.\n", __FILE__, __LINE__); + } + + + // Procede in loop + g_match_info_next (match_info, &gerror); + if (gerror != NULL) + { + osync_error_set(error, OSYNC_ERROR_GENERIC, "%s:%i: ERROR: g_match_info_next() has failed: %s", __FILE__, __LINE__, gerror->message); + goto error; + } + } + +#ifdef DEBUG_detection + printf("\n--------\n"); +#endif + + + + if (match_info){ + g_match_info_free (match_info); + } + + if (regex){ + g_regex_unref (regex); + } + + osync_trace(TRACE_EXIT, "%s()", __func__); + return TRUE; + +error: + if (match_info){ + g_match_info_free (match_info); + } + + if (regex){ + g_regex_unref (regex); + } + + if (!osync_error_is_set(error)) + osync_error_set(error, OSYNC_ERROR_GENERIC, "Unknown reason.\n"); + + osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error)); + return FALSE; +} + + + + + + +osync_bool +ldap_format_read_ldap_entries_from_ldif(const gchar *string, const char *format_name, GList **ldap_entries, OSyncError **error) +{ + GRegex *regex = NULL; + GMatchInfo *match_info = NULL; + GError *gerror = NULL; + const gchar *pattern = "^[ \\t]*(?:dn:|dn::|dn:<)[ \\t]*((?:[-\\w]+=[-\\w]+[ \\t]*,?[ \\t]*)+)(.+?)(?=dn:)"; + const int compile_options = G_REGEX_CASELESS | G_REGEX_MULTILINE | G_REGEX_DOTALL; + + + osync_trace(TRACE_ENTRY, "%s(%p, %p, %p, %p)", __func__, (void *)string, (void *)format_name, (void *)ldap_entries, (void *)error); + + + if (string == NULL) { + osync_error_set(error, OSYNC_ERROR_GENERIC, "%s:%i: ERROR: string = NULL.", __FILE__, __LINE__); + goto error; + } + + if (format_name == NULL) { + osync_error_set(error, OSYNC_ERROR_GENERIC, "%s:%i: ERROR: format_name = NULL.", __FILE__, __LINE__); + goto error; + } + + if (ldap_entries == NULL) { + osync_error_set(error, OSYNC_ERROR_GENERIC, "%s:%i: ERROR: ldap_entries = NULL.", __FILE__, __LINE__); + goto error; + } + + + regex = g_regex_new (pattern, compile_options, 0, &gerror); + if (gerror != NULL) + { + osync_error_set(error, OSYNC_ERROR_GENERIC, "%s:%i: ERROR: g_regex_new() has failed: %s", __FILE__, __LINE__, gerror->message); + goto error; + } + + if (regex == NULL) { + osync_error_set(error, OSYNC_ERROR_GENERIC, "%s:%i: ERROR: regex = NULL. g_regex_new() must have failed.", __FILE__, __LINE__); + goto error; + } + + *ldap_entries = NULL; + + g_regex_match(regex, string, 0, &match_info); + g_match_info_matches(match_info); + while (g_match_info_matches(match_info)) + { + ldap_entry *single_ldap_entry = NULL; + GList *ldapmods = NULL; + gchar *line = g_match_info_fetch(match_info, 0); + gchar *dn = g_match_info_fetch(match_info, 1); + gchar *id = NULL; + if (dn) { + gchar **tokens = g_strsplit(dn, ",", 0); + if (tokens) { + if (tokens[1]) { + id = g_strdup(tokens[1]); + } else { + ldap_plugin_printf("%s:%i: ERROR: tokens[1] = NULL. Ignoring for now.", __FILE__, __LINE__); + } + } else { + ldap_plugin_printf("%s:%i: ERROR: tokens = NULL. Ignoring for now.", __FILE__, __LINE__); + } + } else { + ldap_plugin_printf("%s:%i: ERROR: dn = NULL. Ignoring for now.", __FILE__, __LINE__); + } + +#ifdef DEBUG_detection + if (dn) { + g_print("\nDN: \"%s\"\n", dn); + } + + if (id) { + g_print("id: \"%s\"\n", id); + } + + g_print("------------\n"); +#endif + + if (line) { +#ifdef DEBUG_detection + g_print ("%s\n", line); +#endif + + + if (!ldap_format_extract_attributes_from_ldif(line, format_name, &ldapmods, error)) { + if (!osync_error_is_set(error)){ + osync_error_set(error, OSYNC_ERROR_GENERIC, "%s:%i: ERROR: ldap_format_extract_attributes_from_ldif() has failed.", __FILE__, __LINE__); + } + + g_free (line); + line = NULL; + goto error; + } + + g_free (line); + line = NULL; + + single_ldap_entry = ldap_format_create_ldap_entry_from_ldapmods(ldapmods); + if (ldapmods) { + ldap_format_free_ldapmods_list(ldapmods); + ldapmods = NULL; + } + + if (single_ldap_entry == NULL) { + osync_error_set(error, OSYNC_ERROR_GENERIC, "%s:%i: ERROR: single_ldap_entry = NULL. ldap_format_create_ldap_entry_from_ldapmods() must have failed.", __FILE__, __LINE__); + goto error; + } + + single_ldap_entry->dn = g_strdup(dn); + + single_ldap_entry->subentries = NULL; + + if (dn) { + g_free(dn); + dn = NULL; + } + + if (ldap_entries) { + *ldap_entries = g_list_append(*ldap_entries, single_ldap_entry); + } else { + osync_error_set(error, OSYNC_ERROR_GENERIC, "%s:%i: ERROR: ldap_entries = NULL.\n", __FILE__, __LINE__); + goto error; + } + + } + + +#ifdef DEBUG_detection + g_print("------------\n"); + gint number_substrings = g_match_info_get_match_count(match_info); + g_print("number_substrings = %i\n", number_substrings); + g_print("------------\n"); +#endif + + + // Procede in loop + g_match_info_next (match_info, &gerror); + if (gerror != NULL) + { + osync_error_set(error, OSYNC_ERROR_GENERIC, "%s:%i: ERROR: g_match_info_next() has failed: %s", __FILE__, __LINE__, gerror->message); + goto error; + } + } + + + if (match_info){ + g_match_info_free (match_info); + } + + if (regex){ + g_regex_unref (regex); + } + + + osync_trace(TRACE_EXIT, "%s()", __func__); + return TRUE; + +error: + if (match_info){ + g_match_info_free (match_info); + } + + if (regex){ + g_regex_unref (regex); + } + + + if (!osync_error_is_set(error)) + osync_error_set(error, OSYNC_ERROR_GENERIC, "Unknown reason.\n"); + + osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error)); + return FALSE; +} + + + +osync_bool +ldap_format_parse_ldif(const char *data, const int size, const char *format_name, GList **ldap_entries, OSyncError **error) +{ + char *string = NULL; + + + osync_trace(TRACE_ENTRY, "%s(%p, %i, %p, %p, %p)", __func__, (void *)data, size, (void *)format_name, (void *)ldap_entries, (void *)error); + + + + if (data == NULL) { + osync_error_set(error, OSYNC_ERROR_GENERIC, "%s:%i: ERROR: data = NULL.", __FILE__, __LINE__); + goto error; + } + + if (data[0] == 0) { + osync_trace(TRACE_INTERNAL, "%s:%i: WARNING: data is empty. Returning FALSE.", __FILE__, __LINE__); + goto error; + } + + if (format_name == NULL) { + osync_error_set(error, OSYNC_ERROR_GENERIC, "%s:%i: ERROR: format_name = NULL.", __FILE__, __LINE__); + goto error; + } + + if (format_name[0] == 0) { + osync_error_set(error, OSYNC_ERROR_GENERIC, "%s:%i: ERROR: format_name[0] = 0.", __FILE__, __LINE__); + goto error; + } + + if (ldap_entries == NULL) { + osync_error_set(error, OSYNC_ERROR_GENERIC, "%s:%i: ERROR: ldap_entries = NULL.", __FILE__, __LINE__); + goto error; + } + + + // string is NULL-terminated. + string = g_strndup(data, size); + + // LDIF uses a strange way of continuation on the next line. This call + // merges two of such lines into one line + if (!ldap_format_remove_newlines(&string, error)) { + if (!osync_error_is_set(error)) { + osync_error_set(error, OSYNC_ERROR_GENERIC, "%s:%i: ERROR: ldap_format_remove_newlines() has failed.", __FILE__, __LINE__); + } + + goto error; + } + + + if (!ldap_format_read_ldap_entries_from_ldif(string, format_name, ldap_entries, error)) { + if (!osync_error_is_set(error)) { + osync_error_set(error, OSYNC_ERROR_GENERIC, "%s:%i: ERROR: ldap_format_read_ldap_entries_from_ldif() has failed.", __FILE__, __LINE__); + } + + goto error; + } + + + if (*ldap_entries == NULL) { + osync_error_set(error, OSYNC_ERROR_GENERIC, "%s:%i: ERROR: *ldap_entries = NULL. ldap_format_read_ldap_entries_from_ldif() must have failed.", __FILE__, __LINE__); + goto error; + } + + + + osync_trace(TRACE_EXIT, "%s()", __func__); + return TRUE; + +error: + if (!osync_error_is_set(error)) + osync_error_set(error, OSYNC_ERROR_GENERIC, "Unknown reason.\n"); + + osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error)); + return FALSE; +} + + + + + +osync_bool +ldap_format_check_ldif(const char *data, int size, const char *format_name, OSyncError **error) +{ + const gchar *dn_minimal_pattern = "^[ \\t]*dn:{1,2}[ \\t]*[\\w]+=[\\w]+"; + const gchar *inetorgperson_pattern = "^[ \\t]*objectclass:[ \\t]*inetorgperson"; + const gchar *evolutionperson_pattern = "^[ \\t]*objectclass:[ \\t]*evolutionperson"; + + osync_bool rv = FALSE; + + + osync_trace(TRACE_ENTRY, "%s(%p, %i, %p, %p)", __func__, (void *)data, size, (void *)format_name, (void *)error); + + + if (data == NULL) { + osync_error_set(error, OSYNC_ERROR_GENERIC, "%s:%i: ERROR: data = NULL.", __FILE__, __LINE__); + goto error; + } + + if (data[0] == 0) { + osync_trace(TRACE_INTERNAL, "%s:%i: WARNING: data is empty. Returning FALSE.", __FILE__, __LINE__); + rv = FALSE; + goto regular_out; + } + + if (format_name == NULL) { + osync_error_set(error, OSYNC_ERROR_GENERIC, "%s:%i: ERROR: format_name = NULL.", __FILE__, __LINE__); + goto error; + } + + if (format_name[0] == 0) { + osync_error_set(error, OSYNC_ERROR_GENERIC, "%s:%i: ERROR: format_name[0] = 0.", __FILE__, __LINE__); + goto error; + } + + + if (!strcmp(format_name, FORMAT_LDAP_EVOLUTIONPERSON)){ + if (g_regex_match_simple(dn_minimal_pattern, data, G_REGEX_CASELESS | G_REGEX_MULTILINE, 0)) { +#ifdef DEBUG_detection + osync_trace(TRACE_INTERNAL, "%s:%i: OK. \"dn:\" detected. Looks like LDIF data.", __FILE__, __LINE__); +#endif + + if (g_regex_match_simple(evolutionperson_pattern, data, G_REGEX_CASELESS | G_REGEX_MULTILINE, 0)) { +#ifdef DEBUG_detection + osync_trace(TRACE_INTERNAL, "%s:%i: OK. \"ldap-evolutionperson\" in LDIF data detected.", __FILE__, __LINE__); +#endif + + rv = TRUE; + } else { +#ifdef DEBUG_detection + osync_trace(TRACE_INTERNAL, "%s:%i: No, it is not \"ldap-evolutionperson\" in LDIF data.", __FILE__, __LINE__); +#endif + + rv = FALSE; + } + + } else { +#ifdef DEBUG_detection + osync_trace(TRACE_INTERNAL, "%s:%i: No, could not even detect a \"dn:\" line. Does NOT look like LDIF data.", __FILE__, __LINE__); +#endif + + rv = FALSE; + } + } else if (!strcmp(format_name, FORMAT_LDAP_INETORGPERSON)){ + if (g_regex_match_simple(dn_minimal_pattern, data, G_REGEX_CASELESS | G_REGEX_MULTILINE, 0)) { +#ifdef DEBUG_detection + osync_trace(TRACE_INTERNAL, "%s:%i: OK. \"dn:\" detected. Looks like LDIF data.", __FILE__, __LINE__); +#endif + + if (g_regex_match_simple(inetorgperson_pattern, data, G_REGEX_CASELESS | G_REGEX_MULTILINE, 0)) { +#ifdef DEBUG_detection + osync_trace(TRACE_INTERNAL, "%s:%i: OK. \"ldap-inetorgperson\" in LDIF data detected.", __FILE__, __LINE__); +#endif + + rv = TRUE; + } else { +#ifdef DEBUG_detection + osync_trace(TRACE_INTERNAL, "%s:%i: ", __FILE__, __LINE__); +#endif + + rv = FALSE; + } + } else { +#ifdef DEBUG_detection + osync_trace(TRACE_INTERNAL, "%s:%i: No, could not even detect a \"dn:\" line. Does NOT look like LDIF data.", __FILE__, __LINE__); +#endif + + rv = FALSE; + } + } else { +#ifdef DEBUG_detection + osync_trace(TRACE_INTERNAL, "%s:%i: The format \"%s\" is not yet supported by the LDIF related detector functions of the LDAP plugin.\n", __FILE__, __LINE__, format_name); +#endif + + rv = FALSE; + } + + +regular_out: + osync_trace(TRACE_EXIT, "%s(): rv = %s", __func__, rv ? "TRUE" : "FALSE"); + return rv; + +error: + if (!osync_error_is_set(error)) + osync_error_set(error, OSYNC_ERROR_GENERIC, "Unknown reason.\n"); + + osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error)); + return FALSE; +} + + + + + + + + /** * @brief This function performs the check of a byte sequence whether * or not it is of the type of format the calling function @@ -6529,6 +7150,12 @@ if (!ldap_format_check_xml(data, size, error)) { osync_trace(TRACE_INTERNAL, "%s:%i: ldap_format_check_xml() has NOT recognized input as an XML document.", __FILE__, __LINE__); + + if (ldap_format_check_ldif(data, size, format_name, error)) { + osync_trace(TRACE_EXIT, "%s(): Returning TRUE.", __func__); + return TRUE; + } + osync_trace(TRACE_EXIT, "%s(): Returning FALSE.", __func__); return FALSE; } Modified: plugins/ldap-sync/src/ldap_format.h ============================================================================== --- plugins/ldap-sync/src/ldap_format.h Sun Jan 17 19:01:19 2010 (r6011) +++ plugins/ldap-sync/src/ldap_format.h Sun Jan 17 19:01:31 2010 (r6012) @@ -50,6 +50,7 @@ static osync_bool ldap_format_apply_stylesheet_workaround(char *input, unsigned int inpsize, char **output, unsigned int *outpsize, const char *config, void *userdata, const char *stylesheet, OSyncError **error); static int ldap_format_avoid_duplicate_attribute(GList *ldapmods, const char *name); static osync_bool ldap_format_check_adequate_stylesheet(xmlNode *root_element, const char *stylesheet_file, OSyncError **error); +osync_bool ldap_format_check_ldif(const char *data, int size, const char *format_name, OSyncError **error); static osync_bool ldap_format_check_root_element(const xmlDoc *xmldata, const char *objtype, const char *ldap_format_name, const gchar *dn, xmlNode **root, OSyncError **error); osync_bool ldap_format_check_xml(const char *data, int size, OSyncError **error); static OSyncConvCmpResult ldap_format_compare_format1(const char *leftdata, unsigned int leftsize, const char *rightdata, unsigned int rightsize, void *user_data, OSyncError **error); @@ -74,15 +75,19 @@ static osync_bool ldap_format_do_conv_ldap_to_xmlformat(char *input, unsigned int inpsize, char **output, unsigned int *outpsize, osync_bool *free_input, const char *ldap_format_name, const char *xmlformat_name, const char *stylesheet_name, const char *objtype, const char *config, void *userdata, OSyncError **error); static osync_bool ldap_format_do_conv_xmlformat_to_ldap(char *input, unsigned int inpsize, char **output, unsigned int *outpsize, osync_bool *free_input, const char *xmlformat_name, const char *ldap_format_name, const char *stylesheet_name, const char *objtype, const char *config, void *userdata, OSyncError **error); osync_bool ldap_format_do_detect_plain_as_ldap_format(const char *data, const int size, const char *format_name, const char *opening_tag, const char *closing_tag, const void *userdata, OSyncError **error); +osync_bool ldap_format_extract_attributes_from_ldif(const gchar *string, const char *format_name, GList **ldapmods, OSyncError **error); void ldap_format_free_complex_element_lists(GList **list); static void ldap_format_free_ldap_entry (ldap_entry *entry); static void ldap_format_free_ldap_entries (GList **entrylist); static void ldap_format_free_ldapmods_list(GList *ldapmods); static osync_bool ldap_format_get_attributes(const xmlNode *xmlnode, gchar **attr1_name, gchar **attr1_value, gchar **attr2_name, gchar **attr2_value, OSyncError **error); +osync_bool ldap_format_parse_ldif(const char *data, const int size, const char *format_name, GList **ldap_entries, OSyncError **error); static osync_bool ldap_format_parse_xml_subentry(const xmlNode *xmlnode, const gchar *dn, complex_elements *complex_elements, GList **ldap_entries, OSyncError **error); static osync_bool ldap_format_parse_xmlinternal_child_nodes(xmlNode *xmlnode, const char *objtype, const char *dn, complex_elements *complex_elements, GList **potential_subentries, GList **ldapmods, OSyncError **error); static osync_bool ldap_format_post_stylesheet(OSyncXMLFormat *xmlformat, const char *objtype, const char *ldap_format_name, GList **ldap_entries, OSyncError **error); static osync_bool ldap_format_pre_stylesheet(GList *ldap_entries, const char *objtype, const char *ldap_format_name, xmlChar **xmlbuff, int *xmlbuff_size, OSyncError **error); +osync_bool ldap_format_read_ldap_entries_from_ldif(const gchar *string, const char *format_name, GList **ldap_entries, OSyncError **error); +osync_bool ldap_format_remove_newlines(gchar **string, OSyncError **error); static osync_bool ldap_format_validate_xmlformat_by_libopensync(const char *input, const int inpsize, OSyncXMLFormat *xmlformat, const char *str, const char *stylesheet_file, OSyncError **error); static osync_bool ldap_format_validate_xmlformat_by_libxml(const char *input, const int inpsize, xmlDocPtr xmlcard, const char *stylesheet_file, OSyncError **error); static xmlDoc *ldap_format_xmlchars2xmlinternal(xmlChar *xmlchars); Modified: plugins/ldap-sync/tests/CMakeLists.txt ============================================================================== --- plugins/ldap-sync/tests/CMakeLists.txt Sun Jan 17 19:01:19 2010 (r6011) +++ plugins/ldap-sync/tests/CMakeLists.txt Sun Jan 17 19:01:31 2010 (r6012) @@ -327,9 +327,13 @@ -ADD_TEST( convert_ldap_evolutionperson1 ${TESTDIR}/check_convert_from_to_many ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR} "${CMAKE_SOURCE_DIR}/tests/ldap_evolutionperson*.xml" "contact" ) +ADD_TEST( convert_ldap_evo_person1_xml ${TESTDIR}/check_convert_from_to_many ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR} "${CMAKE_SOURCE_DIR}/tests/ldap_evolutionperson*.xml" "contact" ) -ADD_TEST( convert_ldap_inetorgperson1 ${TESTDIR}/check_convert_from_to_many ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR} "${CMAKE_SOURCE_DIR}/tests/ldap_inetorgperson*.xml" "contact" ) +ADD_TEST( convert_ldap_evo_person1_ldif ${TESTDIR}/check_convert_from_to_many ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR} "${CMAKE_SOURCE_DIR}/tests/contact2.ldif" "contact" ) + +ADD_TEST( convert_ldap_inetorgpers1_xml ${TESTDIR}/check_convert_from_to_many ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR} "${CMAKE_SOURCE_DIR}/tests/ldap_inetorgperson*.xml" "contact" ) + +ADD_TEST( convert_ldap_inetorgpers1_ldif ${TESTDIR}/check_convert_from_to_many ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR} "${CMAKE_SOURCE_DIR}/tests/contact1.ldif" "contact" ) ADD_TEST( convert_ldap_event1 ${TESTDIR}/check_convert_from_to_many ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR} "${CMAKE_SOURCE_DIR}/tests/ldap_event*.xml" "event" ) @@ -339,6 +343,22 @@ +ADD_TEST( conv_val_ldap_evo_person1_xml ${TESTDIR}/check_convert_to_xmlformat ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR} "${CMAKE_SOURCE_DIR}/tests/ldap_evolutionperson*.xml" "contact" ${SCHEMADIR}/xmlformat-contact.xsd) + +ADD_TEST( conv_val_ldap_evo_person1_ldif ${TESTDIR}/check_convert_to_xmlformat ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR} "${CMAKE_SOURCE_DIR}/tests/contact1.ldif" "contact" ${SCHEMADIR}/xmlformat-contact.xsd) + +ADD_TEST( conv_val_ldap_inetorgpers1_xml ${TESTDIR}/check_convert_to_xmlformat ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR} "${CMAKE_SOURCE_DIR}/tests/ldap_inetorgperson*.xml" "contact" ${SCHEMADIR}/xmlformat-contact.xsd) + +ADD_TEST( conv_val_ldap_inetorgpers1_ldif ${TESTDIR}/check_convert_to_xmlformat ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR} "${CMAKE_SOURCE_DIR}/tests/contact2.ldif" "contact" ${SCHEMADIR}/xmlformat-contact.xsd) + +ADD_TEST( conv_val_ldap_event1 ${TESTDIR}/check_convert_to_xmlformat ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR} "${CMAKE_SOURCE_DIR}/tests/ldap_event*.xml" "event" ${SCHEMADIR}/xmlformat-event.xsd) + +ADD_TEST( conv_val_ldap_todo1 ${TESTDIR}/check_convert_to_xmlformat ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR} "${CMAKE_SOURCE_DIR}/tests/ldap_todo*.xml" "todo" ${SCHEMADIR}/xmlformat-todo.xsd) + +ADD_TEST( conv_val_ldap_note1 ${TESTDIR}/check_convert_to_xmlformat ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR} "${CMAKE_SOURCE_DIR}/tests/ldap_note*.xml" "note" ${SCHEMADIR}/xmlformat-note.xsd) + + + ########################################################## # Interact with the LDAP server using external tools only... # This set of tests checks whether the LDAP server is sufficiently Added: plugins/ldap-sync/tests/check_convert_to_xmlformat ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ plugins/ldap-sync/tests/check_convert_to_xmlformat Sun Jan 17 19:01:31 2010 (r6012) @@ -0,0 +1,269 @@ +#!/bin/bash + +set -x + +FILE=$0 +PLUGINNAME="ldap-sync" +PLUGINPATH="$1/src" +BUILDDIR=$1 +SOURCEFORMAT_EXPRESSION="$3" +OBJTYPE="$4" +SCHEMA="$5" +rv=0 + + + +if test -z "$SOURCEFORMAT_EXPRESSION"; then + echo "$FILE:$LINENO: ERROR: \$SOURCEFORMAT_EXPRESSION is empty. Exiting." + exit 1; +fi + +if test -z "$OBJTYPE"; then + echo "$FILE:$LINENO: ERROR: \$OBJTYPE is empty. Exiting." + exit 1; +fi + +if test -z "$SCHEMA"; then + echo "$FILE:$LINENO: ERROR: \$SCHEMA is empty. Exiting." + exit 1; +fi + + + +SOURCE_DIR=`dirname $FILE` +if test ! -d "$SOURCE_DIR"; then + echo "$FILE:$LINENO: ERROR: \"$SOURCE_DIR\" is not a directory. Exiting." + exit 1 +fi + +if test ! -r "$SOURCE_DIR/test.conf"; then + echo "$FILE:$LINENO: ERROR: \"$SOURCE_DIR/test.conf\" could not be read. Exiting." + exit 1 +fi + +if test ! -r "$SOURCE_DIR/check_common.inc"; then + echo "$FILE:$LINENO: ERROR: \"$SOURCE_DIR/test.conf\" could not be read. Exiting." + exit 1 +fi + +CHECK_DO_CONVERT_FROM_TO=$(which check_do_convert_from_to 2> /dev/null) +if test -z "$CHECK_DO_CONVERT_FROM_TO"; then + if test -f "./check_do_convert_from_to"; then + CHECK_DO_CONVERT_FROM_TO="./check_do_convert_from_to" + else + dir=$(dirname $FILE) + if test -d "$dir"; then + if test -f "${dir}/check_do_convert_from_to"; then + CHECK_DO_CONVERT_FROM_TO="${dir}/check_do_convert_from_to" + else + if test -d "$BUILDDIR"; then + CHECK_DO_CONVERT_FROM_TO="${BUILDDIR}/tests/check_do_convert_from_to" + fi + fi + fi + fi +fi + + + +if test -z "$CHECK_DO_CONVERT_FROM_TO"; then + echo "$FILE:$LINENO: ERROR: \$CHECK_DO_CONVERT_FROM_TO is empty. Exiting." + exit 1; +fi + +if test ! -f "$CHECK_DO_CONVERT_FROM_TO"; then + echo "$FILE:$LINENO: ERROR: $CHECK_DO_CONVERT_FROM_TO could not be found. Exiting." + exit 1; +fi + +if test ! -x "$CHECK_DO_CONVERT_FROM_TO"; then + echo "$FILE:$LINENO: ERROR: $CHECK_DO_CONVERT_FROM_TO could be found, but is not executable. Exiting." + exit 1; +fi + +XMLLINT=$(which xmllint) +if test ! -f "$XMLLINT"; then + echo "$FILE:$LINENO: ERROR: Could not find xmllint. Exiting."; + exit 1; +fi + +if test ! -x "$XMLLINT"; then + echo "$FILE:$LINENO: ERROR: xmllint could be found, but it is not executable. Exiting."; + exit 1; +fi + + +source "$SOURCE_DIR/test.conf" +TMPDIR=`mktemp -d /tmp/ldap_sync_test.XXXXXX` || exit 1 +echo "TMPDIR = \"$TMPDIR\"" +TARGET_FILE="${TMPDIR}/out.xml" +if test -z "$TARGET_FILE"; then + echo "$FILE:$LINENO: ERROR: \$TARGET_FILE is empty. Exiting." + exit 1; +fi + + + +echo -e "\n\n\nAbout to be converted:" +for f in $SOURCEFORMAT_EXPRESSION; do + echo "$f" +done +echo -e "\n\n\n" + + + +do_conversion() +{ + file="$1" + targetformat="$2" + + if test -z "$file"; then + echo "$FILE:$LINENO: ERROR: \$file is empty. Returning." + return 1; + fi + + if test -z "$targetformat"; then + echo "$FILE:$LINENO: ERROR: \$targetformat is empty. Returning." + return 1; + fi + + + cmd="$CHECK_DO_CONVERT_FROM_TO $file $targetformat --out $TARGET_FILE" + echo -e "\n\n\nRunning \"$cmd\"" + eval $cmd + rv=$? + if test $rv -ne 0; then + if test -d "$TMPDIR"; then + rm -rf "$TMPDIR" + fi + exit 1 + fi + echo -e "\n\n\n" +} + + + + + + +validate() +{ + schema="$1" + target_file="$2" + + if test -z "$schema"; then + echo "$FILE:$LINENO: ERROR: \$schema is empty. Returning." + return 1; + fi + + if test -z "$target_file"; then + echo "$FILE:$LINENO: ERROR: \$target_file is empty. Returning." + return 1; + fi + + if test ! -e "$schema"; then + echo "$FILE:$LINENO: ERROR: \"$schema\" could not be found. Returning." + return 1; + fi + + if test ! -e "$target_file"; then + echo "$FILE:$LINENO: ERROR: \"$target_file\" could not be found. Returning." + return 1; + fi + + if test ! -r "$schema"; then + echo "$FILE:$LINENO: ERROR: \"$schema\" could be found, but it is not readable. Returning." + return 1; + fi + + if test ! -r "$target_file"; then + echo "$FILE:$LINENO: ERROR: \"$target_file\" could be found, but it is not readable. Returning." + return 1; + fi + + + $XMLLINT --noout --schema $schema $target_file + rv=$? + return $rv +} + + + + + + + + +rv=1 +for f in $SOURCEFORMAT_EXPRESSION; do + if test "$OBJTYPE" == "contact"; then + do_conversion $f "--to-xmlformat" + rv=$? + if test $rv -ne 0; then + if test -d "$TMPDIR"; then + rm -rf "$TMPDIR" + fi + exit 1 + fi + + validate $SCHEMA $TARGET_FILE + rv=$? + + elif test "$OBJTYPE" == "event"; then + do_conversion $f "--to-xmlformat" + rv=$? + if test $rv -ne 0; then + if test -d "$TMPDIR"; then + rm -rf "$TMPDIR" + fi + exit 1 + fi + + validate $SCHEMA $TARGET_FILE + rv=$? + + elif test "$OBJTYPE" == "todo"; then + do_conversion $f "--to-xmlformat" + rv=$? + if test $rv -ne 0; then + if test -d "$TMPDIR"; then + rm -rf "$TMPDIR" + fi + exit 1 + fi + + validate $SCHEMA $TARGET_FILE + rv=$? + + elif test "$OBJTYPE" == "note"; then + do_conversion $f "--to-xmlformat" + rv=$? + if test $rv -ne 0; then + if test -d "$TMPDIR"; then + rm -rf "$TMPDIR" + fi + exit 1 + fi + + validate $SCHEMA $TARGET_FILE + rv=$? + + else + echo "$FILE:$LINENO: ERROR: Object type \"$OBJTYPE\" is unknown." + rv=1 + break; + + fi + +done + + + + + +if test -d "$TMPDIR"; then + rm -rf "$TMPDIR" +fi + +exit $rv + |