OpenSync
0.22
|
00001 /* 00002 * libopensync - A synchronization framework 00003 * Copyright (C) 2004-2005 Armin Bauer <armin.bauer@opensync.org> 00004 * 00005 * This library is free software; you can redistribute it and/or 00006 * modify it under the terms of the GNU Lesser General Public 00007 * License as published by the Free Software Foundation; either 00008 * version 2.1 of the License, or (at your option) any later version. 00009 * 00010 * This library is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 * Lesser General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU Lesser General Public 00016 * License along with this library; if not, write to the Free Software 00017 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00018 * 00019 */ 00020 00021 #include "opensync.h" 00022 #include "opensync_internals.h" 00023 00028 00029 #ifndef DOXYGEN_SHOULD_SKIP_THIS 00030 typedef struct conv_tree { 00031 OSyncFormatEnv *env; 00032 OSyncObjType *type; 00033 00034 /* The converters that weren't reached yet */ 00035 GList *unused; 00036 /* The search queue for the Breadth-first search */ 00037 GList *search; 00038 } conv_tree; 00039 00040 typedef struct vertice { 00041 OSyncObjFormat *format; 00042 00043 /* The invoke_decap will return a new change everytime 00044 * we run it so that the original change does not get 00045 * changed. We also need to track if the data of this change 00046 * should be freed or if it contains a reference into data of 00047 * a previous change */ 00048 OSyncChange *change; 00049 osync_bool free_change_data; 00050 osync_bool free_change; 00051 00057 size_t references; 00058 00060 GList *path; 00061 00062 unsigned losses; 00063 unsigned objtype_changes; 00064 unsigned conversions; 00065 00066 } vertice; 00067 #endif 00068 00069 static OSyncFormatConverter *osync_conv_find_converter_objformat(OSyncFormatEnv *env, OSyncObjFormat *fmt_src, OSyncObjFormat *fmt_trg) 00070 { 00071 GList *element = NULL; 00072 for (element = env->converters; element; element = element->next) { 00073 OSyncFormatConverter *converter = element->data; 00074 if (fmt_src == converter->source_format && fmt_trg == converter->target_format) 00075 return converter; 00076 } 00077 return NULL; 00078 } 00079 00080 osync_bool osync_converter_invoke(OSyncFormatConverter *converter, OSyncChange *change, void *converter_data, OSyncError **error) 00081 { 00082 osync_trace(TRACE_ENTRY, "osync_converter_invoke(%p, %p, %p)", converter, change, error); 00083 osync_trace(TRACE_INTERNAL, "converter: Type: %i, source: %s, target %s", converter->type, converter->source_format->name, converter->target_format->name); 00084 char *data = NULL; 00085 int datasize = 0; 00086 osync_bool ret = TRUE; 00087 if (converter->type == CONVERTER_DETECTOR && !converter->convert_func) { 00088 change->format = converter->target_format; 00089 change->objtype = osync_change_get_objformat(change)->objtype; 00090 osync_trace(TRACE_EXIT, "osync_converter_invoke: TRUE: Detector path"); 00091 return TRUE; 00092 } 00093 00094 if (!converter->convert_func) { 00095 osync_error_set(error, OSYNC_ERROR_GENERIC, "Invalid converter"); 00096 osync_trace(TRACE_EXIT_ERROR, "osync_converter_invoke: %s", osync_error_print(error)); 00097 return FALSE; 00098 } 00099 00100 if (change->data) { 00101 //Invoke the converter and all extensions 00102 //osync_conv_invoke_extensions(converter->source_format, FALSE, change); 00103 osync_bool free_input = FALSE; 00104 if ((ret = converter->convert_func(converter_data, change->data, change->size, &data, &datasize, &free_input, error))) { 00105 00106 if (converter->type == CONVERTER_DECAP) { 00107 if (!free_input) { 00108 /* Duplicate the returned data, as the original data will be destroyed */ 00109 if (!converter->target_format->copy_func) { 00110 /* There is nothing we can do, here. The returned data is a reference, but 00111 * we can't copy the data before destroying it 00112 */ 00113 osync_debug("OSYNC", 0, "Format %s don't have a copy function, but a no-copy converter was registered", converter->target_format->name); 00114 osync_error_set(error, OSYNC_ERROR_GENERIC, "Format %s don't have a copy function, but a no-copy converter was registered", converter->target_format->name); 00115 osync_trace(TRACE_EXIT_ERROR, "osync_converter_invoke: %s", osync_error_print(error)); 00116 return FALSE; 00117 } 00118 converter->target_format->copy_func(data, datasize, &data, &datasize); 00119 } 00120 } 00121 /* Free the data, unless the converter took the ownership of the data */ 00122 if (free_input) { 00123 if (converter->source_format->destroy_func) { 00124 converter->source_format->destroy_func(change->data, change->size); 00125 } else 00126 osync_debug("OSYNC", 1, "Format %s don't have a destroy function. Possible memory leak", converter->source_format->name); 00127 } 00128 change->data = data; 00129 change->size = datasize; 00130 00131 //osync_conv_invoke_extensions(converter->target_format, TRUE, change); 00132 } 00133 } 00134 00135 if (ret) { 00136 osync_debug("OSYNC", 3, "Converting! replacing format %s with %s", converter->source_format->name, converter->target_format->name); 00137 change->format = converter->target_format; 00138 change->objtype = osync_change_get_objformat(change)->objtype; 00139 osync_trace(TRACE_EXIT, "osync_converter_invoke: TRUE"); 00140 } else 00141 osync_trace(TRACE_EXIT_ERROR, "osync_converter_invoke: %s", osync_error_print(error)); 00142 return ret; 00143 } 00144 00145 OSyncChange *osync_converter_invoke_decap(OSyncFormatConverter *converter, OSyncChange *change, osync_bool *free_output) 00146 { 00147 osync_trace(TRACE_ENTRY, "osync_converter_invoke_decap(%p, %p, %p)", converter, change, free_output); 00148 00149 *free_output = FALSE; 00150 00151 if (!converter->convert_func) { 00152 osync_trace(TRACE_EXIT_ERROR, "osync_converter_invoke_decap: No convert function"); 00153 return NULL; 00154 } 00155 00156 if (converter->type != CONVERTER_DECAP) { 00157 osync_trace(TRACE_EXIT_ERROR, "osync_converter_invoke_decap: Not a decap"); 00158 return NULL; 00159 } 00160 00161 OSyncChange *new_change = osync_change_new(); 00162 00163 00164 if (change->changetype != CHANGE_DELETED && change->data) { 00165 //Invoke the converter and all extensions 00166 OSyncError *error = NULL; 00167 if (!converter->convert_func(NULL, change->data, change->size, &(new_change->data), &(new_change->size), free_output, &error)) { 00168 osync_trace(TRACE_EXIT_ERROR, "osync_converter_invoke_decap: %s", osync_error_print(&error)); 00169 osync_error_free(&error); 00170 return NULL; 00171 } 00172 new_change->has_data = change->has_data; 00173 } 00174 osync_debug("OSYNC", 3, "Converting! replacing format %s with %s", converter->source_format->name, converter->target_format->name); 00175 new_change->format = converter->target_format; 00176 new_change->objtype = osync_change_get_objformat(new_change)->objtype; 00177 new_change->changetype = change->changetype; 00178 osync_trace(TRACE_EXIT, "osync_converter_invoke_decap: %p", new_change); 00179 return new_change; 00180 } 00181 00189 int compare_vertice_distance(const void *a, const void *b) 00190 { 00191 const vertice *va = a; 00192 const vertice *vb = b; 00193 if (va->losses < vb->losses) 00194 return -1; 00195 else if (va->losses > vb->losses) 00196 return 1; 00197 else if (va->objtype_changes < vb->objtype_changes) 00198 return -1; 00199 else if (va->objtype_changes > vb->objtype_changes) 00200 return 1; 00201 else if (va->conversions < vb->conversions) 00202 return -1; 00203 else if (va->conversions > vb->conversions) 00204 return 1; 00205 else 00206 return 0; 00207 } 00208 00210 /*static void ref_vertice(vertice *v) 00211 { 00212 v->references++; 00213 }*/ 00214 00217 static void deref_vertice(vertice *vertice) 00218 { 00219 /* Decrement the reference count, 00220 * and just return if we still 00221 * have a reference 00222 */ 00223 if (--vertice->references > 0) 00224 return; 00225 00226 g_list_free(vertice->path); 00227 if (vertice->change && vertice->free_change) { 00228 if (vertice->free_change_data) 00229 osync_change_free_data(vertice->change); 00230 osync_change_free(vertice->change); 00231 } 00232 00233 g_free(vertice); 00234 } 00235 00241 vertice *get_next_vertice_neighbour(OSyncFormatEnv *env, conv_tree *tree, vertice *ve) 00242 { 00243 GList *c = NULL; 00244 osync_trace(TRACE_ENTRY, "get_next_vertice_neighbour(%p, %p, %p:%s)", env, tree, ve, ve->format ? ve->format->name : "None"); 00245 00246 for (c = tree->unused; c; c = c->next) { 00247 OSyncFormatConverter *converter = c->data; 00248 OSyncObjFormat *fmt_target = converter->target_format; 00249 00250 /* Check only valid converters, from the right format */ 00251 if (strcmp(converter->source_format->name, ve->format->name)) 00252 continue; 00253 00254 // If the converter type is a detector we need to know wether the input is correct 00255 if (converter->detect_func) { 00256 if (!ve->change) { 00257 osync_trace(TRACE_INTERNAL, 00258 "We would call a converter to %s, but there is no change data on vertice", fmt_target->name); 00259 continue; 00260 } 00261 00262 if (ve->change->changetype != CHANGE_DELETED) { 00263 if (!converter->detect_func(env, ve->change->data, ve->change->size)) { 00264 osync_trace(TRACE_INTERNAL, "Invoked detector for converter from %s to %s: FALSE", converter->source_format->name, converter->target_format->name); 00265 continue; 00266 } 00267 } 00268 00269 osync_trace(TRACE_INTERNAL, "Invoked detector for converter from %s to %s: TRUE", converter->source_format->name, converter->target_format->name); 00270 } 00271 00272 OSyncChange *new_change = NULL; 00273 osync_bool free_output = TRUE; 00274 if (converter->type == CONVERTER_DECAP) { 00275 if (!ve->change) { 00276 osync_trace(TRACE_INTERNAL, "A desencapsulator to %s would be called, but we can't because the data on this vertice wasn't converted", fmt_target->name); 00277 continue; 00278 } 00279 00280 if (!(new_change = osync_converter_invoke_decap(converter, ve->change, &free_output))) 00281 continue; 00282 } 00283 00284 /* From this point, we already found an edge (i.e. a converter) that may 00285 * be used 00286 */ 00287 00288 /* Remove the converter from the unused list */ 00289 tree->unused = g_list_remove(tree->unused, converter); 00290 00291 /* Allocate the new neighbour */ 00292 vertice *neigh = g_malloc0(sizeof(vertice)); 00293 /* Start with a reference count = 1 */ 00294 neigh->references = 1; 00295 neigh->format = fmt_target; 00296 neigh->path = g_list_copy(ve->path); 00297 neigh->path = g_list_append(neigh->path, converter); 00298 00299 if (new_change) { 00300 neigh->change = new_change; 00301 neigh->free_change = TRUE; 00302 neigh->free_change_data = free_output; 00303 } else { 00304 neigh->change = NULL; 00305 neigh->free_change = FALSE; 00306 neigh->free_change_data = FALSE; 00307 } 00308 00309 /* Distance calculation */ 00310 neigh->conversions = ve->conversions + 1; 00311 neigh->losses = ve->losses; 00312 if (converter->type == CONVERTER_DECAP) 00313 neigh->losses++; 00314 neigh->objtype_changes = ve->objtype_changes; 00315 if (converter->source_format->objtype != converter->target_format->objtype) 00316 neigh->objtype_changes++; 00317 00318 osync_trace(TRACE_EXIT, "get_next_vertice_neighbour: %p:%s", neigh, neigh->format ? neigh->format->name : "None"); 00319 return neigh; 00320 } 00321 osync_trace(TRACE_EXIT, "get_next_vertice_neighbour: None found"); 00322 return NULL; 00323 } 00324 00348 static osync_bool osync_conv_find_path_fn(OSyncFormatEnv *env, OSyncChange *start, OSyncPathTargetFn target_fn, const void *fndata, GList/* OSyncConverter * */ **path_edges) 00349 { 00350 osync_trace(TRACE_ENTRY, "osync_conv_find_path_fn(%p, %p(%s, %s), %p, %p, %p)", env, start, start ? start->uid : "None", start ? start->format->name : "None", target_fn, fndata, path_edges); 00351 00352 g_assert(start->format); 00353 00354 *path_edges = NULL; 00355 osync_bool ret = FALSE; 00356 vertice *result = NULL; 00357 00358 //Vertice = Spitze = Format 00359 //edge = Kante = Converter 00360 00361 //Make a new search tree 00362 conv_tree *tree = g_malloc0(sizeof(conv_tree)); 00363 tree->unused = g_list_copy(env->converters); 00364 00365 //We make our starting point (which is the current format of the 00366 //change of course 00367 vertice *begin = g_malloc0(sizeof(vertice)); 00368 begin->format = start->format; 00369 begin->path = NULL; 00370 begin->references = 1; 00371 begin->change = start; 00372 begin->free_change_data = FALSE; 00373 begin->free_change = FALSE; 00374 00375 tree->search = g_list_append(NULL, begin); 00376 00377 while (g_list_length(tree->search)) { 00378 vertice *neighbour = NULL; 00379 00380 //Get the first vertice and remove it from the queue 00381 vertice *current = tree->search->data; 00382 tree->search = g_list_remove(tree->search, current); 00383 00384 osync_debug("OSCONV", 4, "Next vertice: %s.", current->format->name); 00385 /* Check if we have reached a target format */ 00386 if (target_fn(fndata, current->format)) { 00387 /* Done. return the result */ 00388 result = current; 00389 break; 00390 } 00391 osync_debug("OSCONV", 4, "Looking at %s's neighbours.", current->format->name); 00392 while ((neighbour = get_next_vertice_neighbour(env, tree, current))) { 00393 osync_debug("OSCONV", 4, "%s's neighbour: %s", current->format->name, neighbour->format->name); 00394 tree->search = g_list_insert_sorted(tree->search, neighbour, compare_vertice_distance); 00395 } 00396 /* Done, drop the reference to the vertice */ 00397 deref_vertice(current); 00398 } 00399 /* Remove the references on the search queue */ 00400 g_list_foreach(tree->search, (GFunc)deref_vertice, NULL); 00401 00402 if (result) { 00403 /* Found it. Copy the conversion path */ 00404 *path_edges = g_list_copy(result->path); 00405 /* Drop the reference to the result vertice */ 00406 deref_vertice(result); 00407 ret = TRUE; 00408 goto free_tree; 00409 } 00410 00411 free_tree: 00412 g_list_free(tree->unused); 00413 g_list_free(tree->search); 00414 g_free(tree); 00415 if (ret) 00416 osync_trace(TRACE_EXIT, "osync_conv_find_path_fn: TRUE"); 00417 else 00418 osync_trace(TRACE_EXIT_ERROR, "osync_conv_find_path_fn: FALSE"); 00419 return ret; 00420 } 00421 00422 osync_bool osync_conv_convert_fn(OSyncFormatEnv *env, OSyncChange *change, OSyncPathTargetFn target_fn, const void *fndata, const char *extension_name, OSyncError **error) 00423 { 00424 osync_trace(TRACE_ENTRY, "osync_conv_convert_fn(%p, %p, %p, %p, %p)", env, change, target_fn, fndata, error); 00425 g_assert(change); 00426 g_assert(target_fn); 00427 OSyncObjFormat *source = osync_change_get_objformat(change); 00428 osync_assert_msg(source, "Cannot convert! change has no objformat!"); 00429 GList *path = NULL; 00430 osync_bool ret = TRUE; 00431 00432 /* Optimization: check if the format is already valid */ 00433 if (target_fn(fndata, source)) { 00434 osync_trace(TRACE_EXIT, "osync_conv_convert_fn: Target already valid"); 00435 return TRUE; 00436 } 00437 00438 //We can convert the deleted change directly since it has no data 00439 /*if (change->changetype == CHANGE_DELETED) { 00440 change->format = osync_change_get_initial_objformat(change); 00441 change->objtype = osync_change_get_objformat(change)->objtype; 00442 if (!target_fn(fndata, source)) { 00443 osync_error_set(error, OSYNC_ERROR_GENERIC, "converted delete target would not be valid"); 00444 osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error)); 00445 return FALSE; 00446 } 00447 osync_trace(TRACE_EXIT, "osync_conv_convert_fn: converted deleted change"); 00448 return TRUE; 00449 }*/ 00450 00451 ret = FALSE; 00452 if (!osync_conv_find_path_fn(env, change, target_fn, fndata, &path)) { 00453 osync_error_set(error, OSYNC_ERROR_GENERIC, "Unable to find a conversion path to the format requested"); 00454 osync_trace(TRACE_EXIT_ERROR, "osync_conv_convert_fn: %s", osync_error_print(error)); 00455 goto out; 00456 } 00457 00458 if (change->changetype == CHANGE_DELETED) { 00459 OSyncFormatConverter *converter = g_list_last(path)->data; 00460 change->format = converter->target_format; 00461 change->objtype = osync_change_get_objformat(change)->objtype; 00462 } else { 00463 for (; path; path = path->next) { 00464 OSyncFormatConverter *converter = path->data; 00465 00466 osync_trace(TRACE_INTERNAL, "initialize converter: %p", converter->init_func); 00467 00468 //Initialize the converter 00469 void *converter_data = NULL; 00470 if (converter->init_func) 00471 converter_data = converter->init_func(); 00472 00473 if (extension_name) { 00474 osync_trace(TRACE_INTERNAL, "initialize extension: %s", extension_name); 00475 00476 //Initialize the requested extension 00477 OSyncFormatExtension *extension = osync_conv_find_extension(env, converter->source_format, converter->target_format, extension_name); 00478 osync_trace(TRACE_INTERNAL, "extension: %p", extension); 00479 if (extension) 00480 extension->init_func(converter_data); 00481 } else { 00482 00483 osync_trace(TRACE_INTERNAL, "initialize all extensions"); 00484 //Initialize all available from extensions 00485 GList *e; 00486 for (e = env->extensions; e; e = e->next) { 00487 OSyncFormatExtension *extension = e->data; 00488 osync_trace(TRACE_INTERNAL, "extension: %s", extension->name); 00489 osync_trace(TRACE_INTERNAL, "%p:%p %p:%p", extension->from_format, converter->source_format, extension->to_format, converter->target_format); 00490 if (extension->from_format == converter->source_format && extension->to_format == converter->target_format) 00491 extension->init_func(converter_data); 00492 } 00493 } 00494 00495 if (!osync_converter_invoke(converter, change, converter_data, error)) { 00496 osync_trace(TRACE_EXIT_ERROR, "osync_conv_convert_fn: %s", osync_error_print(error)); 00497 goto out_free_path; 00498 } 00499 00500 //Finalize the converter data 00501 if (converter->fin_func) 00502 converter->fin_func(converter_data); 00503 00504 } 00505 } 00506 ret = TRUE; 00507 00508 osync_trace(TRACE_EXIT, "osync_conv_convert_fn: TRUE"); 00509 out_free_path: 00510 g_list_free(path); 00511 out: 00512 return ret; 00513 } 00514 00519 static osync_bool target_fn_fmtlist(const void *data, OSyncObjFormat *fmt) 00520 { 00521 const GList/*OSyncObjFormat * */ *l = data; 00522 const GList *i; 00523 for (i = l; i; i = i->next) { 00524 OSyncObjFormat *f = i->data; 00525 if (!strcmp(fmt->name, f->name)) 00526 return TRUE; 00527 } 00528 /* else */ 00529 return FALSE; 00530 } 00531 00534 osync_bool osync_conv_convert_fmtlist(OSyncFormatEnv *env, OSyncChange *change, GList/*OSyncObjFormat * */ *targets) 00535 { 00536 return osync_conv_convert_fn(env, change, target_fn_fmtlist, targets, NULL, NULL); 00537 } 00538 00539 osync_bool osync_conv_find_path_fmtlist(OSyncFormatEnv *env, OSyncChange *start, GList/*OSyncObjFormat * */ *targets, GList **retlist) 00540 { 00541 return osync_conv_find_path_fn(env, start, target_fn_fmtlist, targets, retlist); 00542 } 00543 00544 osync_bool osync_conv_objtype_is_any(const char *objstr) 00545 { 00546 if (!strcmp(objstr, "data")) 00547 return TRUE; 00548 return FALSE; 00549 } 00550 00560 00568 OSyncFormatEnv *osync_conv_env_new(OSyncEnv *env) 00569 { 00570 osync_trace(TRACE_ENTRY, "%s(%p)", __func__, env); 00571 OSyncFormatEnv *conv_env = g_malloc0(sizeof(OSyncFormatEnv)); 00572 GList *o; 00573 00574 //Now we resolve all format plugin stuff for the conv env 00575 //First the objecttypes 00576 OSyncObjType *type = NULL; 00577 for (o = env->objtype_templates; o; o = o->next) { 00578 OSyncObjTypeTemplate *otempl = o->data; 00579 type = g_malloc0(sizeof(OSyncObjType)); 00580 type->name = g_strdup(otempl->name); 00581 type->env = conv_env; 00582 conv_env->objtypes = g_list_append(conv_env->objtypes, type); 00583 } 00584 00585 //The formats 00586 GList *f = NULL; 00587 for (f = env->format_templates; f; f = f->next) { 00588 OSyncObjFormatTemplate *ftempl = f->data; 00589 OSyncObjType *type = osync_conv_find_objtype(conv_env, ftempl->objtype); 00590 g_assert(type); 00591 OSyncObjFormat *format = g_malloc0(sizeof(OSyncObjFormat)); 00592 format->env = conv_env; 00593 format->name = g_strdup(ftempl->name); 00594 format->objtype = type; 00595 00596 format->cmp_func = ftempl->cmp_func; 00597 format->merge_func = ftempl->merge_func; 00598 format->duplicate_func = ftempl->duplicate_func; 00599 format->copy_func = ftempl->copy_func; 00600 format->create_func = ftempl->create_func; 00601 format->destroy_func = ftempl->destroy_func; 00602 format->print_func = ftempl->print_func; 00603 format->revision_func = ftempl->revision_func; 00604 format->marshall_func = ftempl->marshall_func; 00605 format->demarshall_func = ftempl->demarshall_func; 00606 type->formats = g_list_append(type->formats, format); 00607 conv_env->objformats = g_list_append(conv_env->objformats, format); 00608 } 00609 00610 //The extension 00611 GList *i; 00612 for (i = env->extension_templates; i; i = i->next) { 00613 OSyncFormatExtensionTemplate *extension_template = i->data; 00614 OSyncObjFormat *from_format = osync_conv_find_objformat(conv_env, extension_template->from_formatname); 00615 OSyncObjFormat *to_format = osync_conv_find_objformat(conv_env, extension_template->to_formatname); 00616 if (!from_format || !to_format) 00617 continue; 00618 00619 OSyncFormatExtension *extension = g_malloc0(sizeof(OSyncFormatExtension)); 00620 extension->name = g_strdup(extension_template->name); 00621 extension->init_func = extension_template->init_func; 00622 extension->from_format = from_format; 00623 extension->to_format = to_format; 00624 00625 conv_env->extensions = g_list_append(conv_env->extensions, extension); 00626 } 00627 00628 //Converter templates 00629 for (i = env->converter_templates; i; i = i->next) { 00630 OSyncConverterTemplate *convtmpl = i->data; 00631 00632 osync_trace(TRACE_INTERNAL, "New converter from %s to %s", convtmpl->source_format, convtmpl->target_format); 00633 00634 OSyncObjFormat *fmt_src = osync_conv_find_objformat(conv_env, convtmpl->source_format); 00635 OSyncObjFormat *fmt_trg = osync_conv_find_objformat(conv_env, convtmpl->target_format); 00636 if (!fmt_src || !fmt_trg) 00637 continue; 00638 OSyncFormatConverter *converter = g_malloc0(sizeof(OSyncFormatConverter)); 00639 converter->source_format = fmt_src; 00640 converter->target_format = fmt_trg; 00641 converter->convert_func = convtmpl->convert_func; 00642 converter->type = convtmpl->type; 00643 converter->init_func = convtmpl->init_func; 00644 00645 conv_env->converters = g_list_append(conv_env->converters, converter); 00646 } 00647 00648 //The detectors 00649 for (i = env->data_detectors; i; i = i->next) { 00650 OSyncDataDetector *detector = i->data; 00651 OSyncFormatConverter *converter = osync_conv_find_converter(conv_env, detector->sourceformat, detector->targetformat); 00652 if (!converter) { 00653 OSyncObjFormat *fmt_src = osync_conv_find_objformat(conv_env, detector->sourceformat); 00654 OSyncObjFormat *fmt_trg = osync_conv_find_objformat(conv_env, detector->targetformat); 00655 if (!fmt_src || !fmt_trg) 00656 continue; 00657 converter = g_malloc0(sizeof(OSyncFormatConverter)); 00658 converter->source_format = fmt_src; 00659 converter->target_format = fmt_trg; 00660 converter->type = CONVERTER_DETECTOR; 00661 } 00662 converter->detect_func = detector->detect_func; 00663 conv_env->converters = g_list_append(conv_env->converters, converter); 00664 } 00665 00666 //The filters 00667 conv_env->filter_functions = g_list_copy(env->filter_functions); 00668 00669 osync_conv_set_common_format(conv_env, "contact", "xml-contact", NULL); 00670 osync_conv_set_common_format(conv_env, "event", "xml-event", NULL); 00671 osync_conv_set_common_format(conv_env, "todo", "xml-todo", NULL); 00672 osync_conv_set_common_format(conv_env, "note", "xml-note", NULL); 00673 00674 osync_trace(TRACE_EXIT, "%s: %p", __func__, conv_env); 00675 return conv_env; 00676 } 00677 00685 void osync_conv_env_free(OSyncFormatEnv *env) 00686 { 00687 g_assert(env); 00688 00689 //We need to go through the loaded objtypes and free them. 00690 00691 g_free(env); 00692 } 00693 00703 osync_bool osync_conv_set_common_format(OSyncFormatEnv *env, const char *objtypestr, const char *formatname, OSyncError **error) 00704 { 00705 OSyncObjType *type = osync_conv_find_objtype(env, objtypestr); 00706 if (!type) { 00707 osync_error_set(error, OSYNC_ERROR_GENERIC, "Unable to set a common format: Unable to find the object-type \"%s\"", objtypestr); 00708 return FALSE; 00709 } 00710 OSyncObjFormat *format = osync_conv_find_objformat(env, formatname); 00711 if (!format) { 00712 osync_error_set(error, OSYNC_ERROR_GENERIC, "Unable to set a common format: Unable to find the format \"%s\"", formatname); 00713 return FALSE; 00714 } 00715 type->common_format = format; 00716 return TRUE; 00717 } 00718 00726 OSyncObjType *osync_conv_find_objtype(OSyncFormatEnv *env, const char *name) 00727 { 00728 g_assert(env); 00729 g_assert(name); 00730 00731 GList *element = NULL; 00732 for (element = env->objtypes; element; element = element->next) { 00733 OSyncObjType *type = element->data; 00734 if (!strcmp(type->name, name)) 00735 return type; 00736 } 00737 osync_debug("CONV", 1, "Unable to find the requested objtype \"%s\"", name); 00738 return NULL; 00739 } 00740 00747 int osync_conv_num_objtypes(OSyncFormatEnv *env) 00748 { 00749 g_assert(env); 00750 return g_list_length(env->objtypes); 00751 } 00752 00760 OSyncObjType *osync_conv_nth_objtype(OSyncFormatEnv *env, int nth) 00761 { 00762 g_assert(env); 00763 return g_list_nth_data(env->objtypes, nth); 00764 } 00765 00773 OSyncObjFormat *osync_conv_find_objformat(OSyncFormatEnv *env, const char *name) 00774 { 00775 g_assert(env); 00776 g_assert(name); 00777 00778 GList *element = NULL; 00779 for (element = env->objformats; element; element = element->next) { 00780 OSyncObjFormat *format = element->data; 00781 if (!strcmp(format->name, name)) 00782 return format; 00783 } 00784 return NULL; 00785 } 00786 00793 int osync_conv_num_objformats(OSyncObjType *type) 00794 { 00795 g_assert(type); 00796 return g_list_length(type->formats); 00797 } 00798 00806 OSyncObjFormat *osync_conv_nth_objformat(OSyncObjType *type, int nth) 00807 { 00808 g_assert(type); 00809 return g_list_nth_data(type->formats, nth); 00810 } 00811 00820 OSyncFormatConverter *osync_conv_find_converter(OSyncFormatEnv *env, const char *sourcename, const char *targetname) 00821 { 00822 g_assert(env); 00823 g_assert(sourcename); 00824 g_assert(targetname); 00825 00826 OSyncObjFormat *fmt_src = osync_conv_find_objformat(env, sourcename); 00827 if (!fmt_src) 00828 return NULL; 00829 OSyncObjFormat *fmt_trg = osync_conv_find_objformat(env, targetname); 00830 if (!fmt_trg) 00831 return NULL; 00832 00833 return osync_conv_find_converter_objformat(env, fmt_src, fmt_trg); 00834 } 00835 00845 OSyncFormatExtension *osync_conv_find_extension(OSyncFormatEnv *env, OSyncObjFormat *from_format, OSyncObjFormat *to_format, const char *extension_name) 00846 { 00847 g_assert(env); 00848 g_assert(extension_name); 00849 00850 GList *i = NULL; 00851 for (i = env->extensions; i; i = i->next) { 00852 OSyncFormatExtension *extension = i->data; 00853 osync_trace(TRACE_INTERNAL, "comparing format %p:%p %p:%p name %s:%s", extension->from_format, from_format, extension->to_format, to_format, extension->name, extension_name); 00854 if ((extension->from_format == from_format || !from_format) && (extension->to_format == to_format || !to_format) && !strcmp(extension->name, extension_name)) 00855 return extension; 00856 } 00857 return NULL; 00858 } 00859 00866 const char *osync_objtype_get_name(OSyncObjType *type) 00867 { 00868 g_assert(type); 00869 return type->name; 00870 } 00871 00878 const char *osync_objformat_get_name(OSyncObjFormat *format) 00879 { 00880 g_assert(format); 00881 return format->name; 00882 } 00883 00890 OSyncObjType *osync_objformat_get_objtype(OSyncObjFormat *format) 00891 { 00892 g_assert(format); 00893 return format->objtype; 00894 } 00895