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 00031 00032 #ifndef DOXYGEN_SHOULD_SKIP_THIS 00033 OSyncMemberFunctions *osync_memberfunctions_new() 00034 { 00035 OSyncMemberFunctions *functions = g_malloc0(sizeof(OSyncMemberFunctions)); 00036 return functions; 00037 } 00038 00039 OSyncMemberFunctions *osync_member_get_memberfunctions(OSyncMember *member) 00040 { 00041 return member->memberfunctions; 00042 } 00043 00044 OSyncFormatEnv *osync_member_get_format_env(OSyncMember *member) 00045 { 00046 g_assert(member); 00047 return osync_group_get_format_env(member->group); 00048 } 00049 00054 OSyncObjTypeSink *osync_member_find_objtype_sink(OSyncMember *member, const char *objtypestr) 00055 { 00056 GList *o; 00057 for (o = member->objtype_sinks; o; o = o->next) { 00058 OSyncObjTypeSink *sink = o->data; 00059 if (osync_conv_objtype_is_any(sink->objtype->name) || !strcmp(sink->objtype->name, objtypestr)) 00060 return sink; 00061 } 00062 return NULL; 00063 } 00064 00074 osync_bool osync_member_require_sink_info(OSyncMember *member, OSyncError **error) 00075 { 00076 // Currently, the only way to get the objtype_sink information 00077 // is loading the plugin 00078 if (!osync_member_instance_default_plugin(member, error)) 00079 return FALSE; 00080 00081 return TRUE; 00082 } 00083 00092 osync_bool osync_member_get_objtype_sinks(OSyncMember *member, GList **list_ptr, OSyncError **error) 00093 { 00094 if (!osync_member_require_sink_info(member, error)) 00095 return FALSE; 00096 00097 *list_ptr = member->objtype_sinks; 00098 return TRUE; 00099 } 00100 00120 osync_bool osync_member_read_config(OSyncMember *member, char **data, int *size, OSyncError **error) 00121 { 00122 osync_trace(TRACE_ENTRY, "osync_member_read_config(%p, %p, %p, %p)", member, data, size, error); 00123 00124 if (!osync_member_instance_default_plugin(member, error)) { 00125 osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error)); 00126 return FALSE; 00127 } 00128 00129 OSyncPluginFunctions functions = member->plugin->info.functions; 00130 osync_bool ret = FALSE; 00131 if (!member->configdir) { 00132 osync_error_set(error, OSYNC_ERROR_GENERIC, "Member has no config directory set"); 00133 osync_trace(TRACE_EXIT_ERROR, "osync_member_read_config: %i", osync_error_print(error)); 00134 return FALSE; 00135 } 00136 00137 if (functions.get_config) { 00138 ret = functions.get_config(member->configdir, data, size); 00139 } else { 00140 char *filename = g_strdup_printf("%s/%s.conf", member->configdir, osync_plugin_get_name(member->plugin)); 00141 ret = osync_file_read(filename, data, size, error); 00142 g_free(filename); 00143 } 00144 00145 if (ret) 00146 osync_trace(TRACE_EXIT, "osync_member_read_config: TRUE"); 00147 else 00148 osync_trace(TRACE_EXIT_ERROR, "osync_member_read_config: %s", osync_error_print(error)); 00149 return ret; 00150 } 00151 00152 #endif 00153 00163 00170 OSyncMember *osync_member_new(OSyncGroup *group) 00171 { 00172 OSyncMember *member = g_malloc0(sizeof(OSyncMember)); 00173 if (group) { 00174 osync_group_add_member(group, member); 00175 member->group = group; 00176 } 00177 00178 member->memberfunctions = osync_memberfunctions_new(); 00179 member->name = NULL; 00180 00181 return member; 00182 } 00183 00189 void osync_member_free(OSyncMember *member) 00190 { 00191 osync_assert_msg(member, "You must set a member to free"); 00192 00193 if (member->group) 00194 osync_group_remove_member(member->group, member); 00195 00196 //Free the plugin if we are not thread-safe 00197 /*if (member->plugin && !member->plugin->info.is_threadsafe) { 00198 osync_plugin_unload(member->plugin); 00199 osync_plugin_free(member->plugin); 00200 }*/ 00201 00202 if (member->pluginname) 00203 g_free(member->pluginname); 00204 00205 g_free(member->memberfunctions); 00206 g_free(member); 00207 } 00208 00214 void osync_member_unload_plugin(OSyncMember *member) 00215 { 00216 g_assert(member); 00217 if (!member->plugin) 00218 return; 00219 00220 /*if (!member->plugin->info.is_threadsafe) { 00221 osync_plugin_unload(member->plugin); 00222 osync_plugin_free(member->plugin); 00223 }*/ 00224 00225 g_list_free(member->objtype_sinks); 00226 g_list_free(member->format_sinks); 00227 //Really free the formats! 00228 00229 member->objtype_sinks = NULL; 00230 member->format_sinks = NULL; 00231 member->plugin = NULL; 00232 } 00233 00242 osync_bool osync_member_instance_plugin(OSyncMember *member, const char *pluginname, OSyncError **error) 00243 { 00244 g_assert(member); 00245 g_assert(member->group); 00246 g_assert(pluginname); 00247 00248 OSyncPlugin *plugin = osync_env_find_plugin(member->group->env, pluginname); 00249 if (!plugin) { 00250 osync_debug("OSPLG", 0, "Couldn't find the plugin %s for member", pluginname); 00251 osync_error_set(error, OSYNC_ERROR_MISCONFIGURATION, "Unable to find the plugin \"%s\"", pluginname); 00252 return FALSE; 00253 } 00254 00255 osync_member_unload_plugin(member); 00256 00257 //For now we disable the threadsafety feature since dlopen doesnt like it 00258 member->plugin = plugin; 00259 /*if (plugin->info.is_threadsafe) { 00260 member->plugin = plugin; 00261 } else { 00262 member->plugin = osync_plugin_load(NULL, plugin->path, error); 00263 if (!member->plugin) 00264 return FALSE; 00265 }*/ 00266 member->pluginname = g_strdup(osync_plugin_get_name(member->plugin)); 00267 00268 //Prepare the sinks; 00269 GList *o; 00270 for (o = member->plugin->accepted_objtypes; o; o = o->next) { 00271 OSyncObjTypeTemplate *objtemplate = o->data; 00272 OSyncObjTypeSink *objsink = osync_objtype_sink_from_template(member->group, objtemplate); 00273 if (!objsink) { 00274 osync_error_set(error, OSYNC_ERROR_GENERIC, "Could not find object type \"%s\"", objtemplate->name); 00275 return FALSE; 00276 } 00277 member->objtype_sinks = g_list_append(member->objtype_sinks, objsink); 00278 GList *f; 00279 for (f = objtemplate->formats; f; f = f->next) { 00280 OSyncObjFormatTemplate *frmtemplate = f->data; 00281 OSyncObjFormatSink *format_sink = osync_objformat_sink_from_template(member->group, frmtemplate); 00282 if (!format_sink) { 00283 osync_error_set(error, OSYNC_ERROR_GENERIC, "Could not find format \"%s\"", frmtemplate->name); 00284 return FALSE; 00285 } 00286 objsink->formatsinks = g_list_append(objsink->formatsinks, format_sink); 00287 format_sink->objtype_sink = objsink; 00288 member->format_sinks = g_list_append(member->format_sinks, format_sink); 00289 if (frmtemplate->extension_name) 00290 member->extension = g_strdup(frmtemplate->extension_name); 00291 } 00292 } 00293 00294 member->pluginname = g_strdup(pluginname); 00295 return TRUE; 00296 } 00297 00305 osync_bool osync_member_instance_default_plugin(OSyncMember *member, OSyncError **error) 00306 { 00307 if (member->plugin) 00308 return TRUE; 00309 00310 if (!member->pluginname) { 00311 osync_error_set(error, OSYNC_ERROR_GENERIC, "No default plugin set while instancing"); 00312 return FALSE; 00313 } 00314 00315 return osync_member_instance_plugin(member, member->pluginname, error); 00316 } 00317 00324 OSyncPlugin *osync_member_get_plugin(OSyncMember *member) 00325 { 00326 g_assert(member); 00327 osync_member_instance_default_plugin(member, NULL); 00328 return member->plugin; 00329 } 00330 00337 const char *osync_member_get_pluginname(OSyncMember *member) 00338 { 00339 g_assert(member); 00340 return member->pluginname; 00341 } 00342 00349 void osync_member_set_pluginname(OSyncMember *member, const char *pluginname) 00350 { 00351 g_assert(member); 00352 if (member->pluginname) 00353 g_free(member->pluginname); 00354 member->pluginname = g_strdup(pluginname); 00355 } 00356 00367 void *osync_member_get_plugindata(OSyncMember *member) 00368 { 00369 g_assert(member); 00370 OSyncPlugin *plugin = osync_member_get_plugin(member); 00371 return osync_plugin_get_plugin_data(plugin); 00372 } 00373 00380 const char *osync_member_get_configdir(OSyncMember *member) 00381 { 00382 g_assert(member); 00383 return member->configdir; 00384 } 00385 00392 void osync_member_set_configdir(OSyncMember *member, const char *configdir) 00393 { 00394 g_assert(member); 00395 if (member->configdir) 00396 g_free(member->configdir); 00397 member->configdir = g_strdup(configdir); 00398 } 00399 00400 osync_bool osync_member_need_config(OSyncMember *member, OSyncConfigurationTypes *type, OSyncError **error) 00401 { 00402 osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, member, type, error); 00403 g_assert(member); 00404 g_assert(type); 00405 *type = NO_CONFIGURATION; 00406 00407 if (!osync_member_instance_default_plugin(member, error)) 00408 goto error; 00409 00410 *type = member->plugin->info.config_type; 00411 00412 osync_trace(TRACE_EXIT, "%s: %i", __func__, *type); 00413 return TRUE; 00414 00415 error: 00416 osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error)); 00417 return FALSE; 00418 } 00419 00437 osync_bool osync_member_get_config_or_default(OSyncMember *member, char **data, int *size, OSyncError **error) 00438 { 00439 osync_trace(TRACE_ENTRY, "%s(%p, %p, %p, %p)", __func__, member, data, size, error); 00440 g_assert(member); 00441 osync_bool ret = TRUE; 00442 00443 if (member->configdata) { 00444 *data = member->configdata; 00445 *size = member->configsize; 00446 osync_trace(TRACE_EXIT, "%s: Configdata already in memory", __func__); 00447 return TRUE; 00448 } 00449 00450 if (!osync_member_read_config(member, data, size, error)) { 00451 if (osync_error_is_set(error)) { 00452 osync_trace(TRACE_INTERNAL, "Read config not successfull: %s", osync_error_print(error)); 00453 osync_error_free(error); 00454 } 00455 00456 char *filename = g_strdup_printf(OPENSYNC_CONFIGDIR"/%s", member->pluginname); 00457 osync_debug("OSMEM", 3, "Reading default2 config file for member %lli from %s", member->id, filename); 00458 ret = osync_file_read(filename, data, size, error); 00459 g_free(filename); 00460 } 00461 osync_trace(TRACE_EXIT, "%s: %i", __func__, ret); 00462 return ret; 00463 } 00464 00483 osync_bool osync_member_get_config(OSyncMember *member, char **data, int *size, OSyncError **error) 00484 { 00485 osync_trace(TRACE_ENTRY, "%s(%p, %p, %p, %p)", __func__, member, data, size, error); 00486 g_assert(member); 00487 osync_bool ret = TRUE; 00488 00489 if (!osync_member_instance_default_plugin(member, error)) { 00490 osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error)); 00491 return FALSE; 00492 } 00493 00494 if (member->plugin->info.config_type == NO_CONFIGURATION) { 00495 osync_error_set(error, OSYNC_ERROR_GENERIC, "This member has no configuration options"); 00496 osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error)); 00497 return FALSE; 00498 } 00499 00500 if (member->configdata) { 00501 *data = member->configdata; 00502 *size = member->configsize; 00503 osync_trace(TRACE_EXIT, "%s: Configdata already in memory", __func__); 00504 return TRUE; 00505 } 00506 00507 if (!osync_member_read_config(member, data, size, error)) { 00508 if (osync_error_is_set(error)) { 00509 osync_trace(TRACE_INTERNAL, "Read config not successfull: %s", osync_error_print(error)); 00510 osync_error_free(error); 00511 } 00512 00513 if (member->plugin->info.config_type == NEEDS_CONFIGURATION) { 00514 //We dont load the default config for these 00515 osync_error_set(error, OSYNC_ERROR_MISCONFIGURATION, "Member has not been configured"); 00516 osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error)); 00517 return FALSE; 00518 } 00519 00520 char *filename = g_strdup_printf(OPENSYNC_CONFIGDIR"/%s", member->pluginname); 00521 osync_debug("OSMEM", 3, "Reading default2 config file for member %lli from %s", member->id, filename); 00522 ret = osync_file_read(filename, data, size, error); 00523 g_free(filename); 00524 } 00525 osync_trace(TRACE_EXIT, "%s: %i", __func__, ret); 00526 return ret; 00527 } 00528 00538 void osync_member_set_config(OSyncMember *member, const char *data, int size) 00539 { 00540 osync_trace(TRACE_ENTRY, "%s(%p, %p, %i)", __func__, member, data, size); 00541 g_assert(member); 00542 //FIXME free old data 00543 member->configdata = g_strdup(data); 00544 member->configsize = size; 00545 00546 osync_trace(TRACE_EXIT, "%s", __func__); 00547 } 00548 00555 void *osync_member_get_loop(OSyncMember *member) 00556 { 00557 g_assert(member); 00558 osync_trace(TRACE_INTERNAL, "%s: %p %p", __func__, member, member->loop); 00559 return member->loop; 00560 } 00561 00568 void osync_member_set_loop(OSyncMember *member, void *loop) 00569 { 00570 g_assert(member); 00571 osync_trace(TRACE_INTERNAL, "%s: %p %p", __func__, member, loop); 00572 member->loop = loop; 00573 } 00574 00575 00582 osync_bool osync_member_has_configuration(OSyncMember *member) 00583 { 00584 osync_trace(TRACE_ENTRY, "%s(%p)", __func__, member); 00585 g_assert(member); 00586 00587 osync_bool ret = (member->plugin->info.config_type == NEEDS_CONFIGURATION || member->plugin->info.config_type == OPTIONAL_CONFIGURATION); 00588 00589 osync_trace(TRACE_EXIT, "%s: %i", __func__, ret); 00590 return ret; 00591 } 00592 00601 OSyncMember *osync_member_load(OSyncGroup *group, const char *path, OSyncError **error) 00602 { 00603 osync_trace(TRACE_ENTRY, "%s(%p, %s, %p)", __func__, group, path, error); 00604 xmlDocPtr doc; 00605 xmlNodePtr cur; 00606 char *filename = NULL; 00607 00608 filename = g_strdup_printf ("%s/syncmember.conf", path); 00609 00610 OSyncMember *member = osync_member_new(group); 00611 char *basename = g_path_get_basename(path); 00612 member->id = atoi(basename); 00613 g_free(basename); 00614 member->configdir = g_strdup(path); 00615 00616 if (!_osync_open_xml_file(&doc, &cur, filename, "syncmember", error)) { 00617 osync_member_free(member); 00618 osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error)); 00619 return NULL; 00620 } 00621 00622 while (cur != NULL) { 00623 char *str = (char*)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); 00624 if (str) { 00625 if (!xmlStrcmp(cur->name, (const xmlChar *)"pluginname")) 00626 member->pluginname = g_strdup(str); 00627 if (!xmlStrcmp(cur->name, (const xmlChar *)"name")) 00628 member->name = g_strdup(str); 00629 xmlFree(str); 00630 } 00631 cur = cur->next; 00632 } 00633 xmlFreeDoc(doc); 00634 g_free(filename); 00635 00636 osync_trace(TRACE_EXIT, "%s: Loaded member: %p", __func__, member); 00637 return member; 00638 } 00639 00647 osync_bool osync_member_save(OSyncMember *member, OSyncError **error) 00648 { 00649 osync_trace(TRACE_ENTRY, "%s(%p:(%lli), %p)", __func__, member, member ? member->id : 0, error); 00650 char *filename = NULL; 00651 00652 if (!osync_member_instance_default_plugin(member, error)) { 00653 osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error)); 00654 return FALSE; 00655 } 00656 00657 if (!member->id) { 00658 member->id = osync_group_create_member_id(member->group); 00659 member->configdir = g_strdup_printf("%s/%lli", member->group->configdir, member->id); 00660 } 00661 00662 g_assert(member->configdir); 00663 if (!g_file_test(member->configdir, G_FILE_TEST_IS_DIR)) { 00664 osync_debug("OSMEM", 3, "Creating config directory: %s for member %i", member->configdir, member->id); 00665 if (mkdir(member->configdir, 0700)) { 00666 osync_error_set(error, OSYNC_ERROR_IO_ERROR, "Unable to create directory for member %li\n", member->id); 00667 osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error)); 00668 return FALSE; 00669 } 00670 } 00671 00672 //Saving the syncmember.conf 00673 filename = g_strdup_printf ("%s/syncmember.conf", member->configdir); 00674 xmlDocPtr doc; 00675 doc = xmlNewDoc((xmlChar*)"1.0"); 00676 doc->children = xmlNewDocNode(doc, NULL, (xmlChar*)"syncmember", NULL); 00677 //The plugin name 00678 xmlNewTextChild(doc->children, NULL, (xmlChar*)"pluginname", (xmlChar*)member->pluginname); 00679 //The name 00680 xmlNewTextChild(doc->children, NULL, (xmlChar*)"name", (xmlChar*)member->name); 00681 xmlSaveFile(filename, doc); 00682 xmlFreeDoc(doc); 00683 g_free(filename); 00684 00685 //Saving the config if it exists 00686 osync_bool ret = TRUE; 00687 if (member->configdata) { 00688 OSyncPluginFunctions functions = member->plugin->info.functions; 00689 00690 if (functions.store_config) { 00691 ret = functions.store_config(member->configdir, member->configdata, member->configsize); 00692 } else { 00693 filename = g_strdup_printf("%s/%s.conf", member->configdir, osync_plugin_get_name(member->plugin)); 00694 if (!osync_file_write(filename, member->configdata, member->configsize, 0600, error)) { 00695 ret = FALSE; 00696 } 00697 g_free(filename); 00698 } 00699 g_free(member->configdata); 00700 member->configdata = NULL; 00701 member->configsize = 0; 00702 } 00703 00704 osync_trace(TRACE_EXIT, "%s: %s", __func__, osync_error_print(error)); 00705 return ret; 00706 } 00707 00714 long long int osync_member_get_id(OSyncMember *member) 00715 { 00716 g_assert(member); 00717 return member->id; 00718 } 00719 00731 void *osync_member_call_plugin(OSyncMember *member, const char *function, void *data, OSyncError **error) 00732 { 00733 if (!osync_member_instance_default_plugin(member, error)) 00734 return FALSE; 00735 00736 void *(*plgfunc) (void *, void *, OSyncError **); 00737 if (!(plgfunc = osync_plugin_get_function(member->plugin, function, error))) 00738 return NULL; 00739 return plgfunc(member->plugindata, data, error); 00740 } 00741 00749 void osync_member_set_slow_sync(OSyncMember *member, const char *objtypestr, osync_bool slow_sync) 00750 { 00751 g_assert(member); 00752 OSyncGroup *group = osync_member_get_group(member); 00753 g_assert(group); 00754 00755 osync_group_set_slow_sync(group, objtypestr, slow_sync); 00756 } 00757 00765 osync_bool osync_member_get_slow_sync(OSyncMember *member, const char *objtypestr) 00766 { 00767 osync_trace(TRACE_ENTRY, "%s(%p, %s)", __func__, member, objtypestr); 00768 g_assert(member); 00769 OSyncGroup *group = osync_member_get_group(member); 00770 g_assert(group); 00771 00772 osync_bool needs_slow_sync = osync_group_get_slow_sync(group, objtypestr); 00773 00774 osync_trace(TRACE_EXIT, "%s: %i", __func__, needs_slow_sync); 00775 return needs_slow_sync; 00776 } 00777 00783 void osync_member_request_synchronization(OSyncMember *member) 00784 { 00785 osync_trace(TRACE_ENTRY, "%s(%p)", __func__, member); 00786 g_assert(member); 00787 00788 if (member->memberfunctions->rf_sync_alert) 00789 member->memberfunctions->rf_sync_alert(member); 00790 else { 00791 osync_trace(TRACE_EXIT_ERROR, "%s: Alert not handled", __func__); 00792 return; 00793 } 00794 osync_trace(TRACE_EXIT, "%s", __func__); 00795 } 00796 00797 00806 OSyncObjFormatSink *osync_member_make_random_data(OSyncMember *member, OSyncChange *change, const char *objtypename) 00807 { 00808 int retry = 0; 00809 g_assert(member); 00810 OSyncFormatEnv *env = osync_member_get_format_env(member); 00811 00812 OSyncObjFormatSink *format_sink = NULL; 00813 00814 for (retry = 0; retry < 100; retry++) { 00815 if (retry > 20) { 00816 osync_trace(TRACE_INTERNAL, "%s: Giving up", __func__); 00817 return NULL; //Giving up 00818 } 00819 00820 //Select a random objtype 00821 OSyncObjType *objtype = NULL; 00822 int selected = 0; 00823 if (!objtypename) { 00824 selected = g_random_int_range(0, g_list_length(env->objtypes)); 00825 objtype = g_list_nth_data(env->objtypes, selected); 00826 } else 00827 objtype = osync_conv_find_objtype(member->group->conv_env, objtypename); 00828 osync_change_set_objtype(change, objtype); 00829 00830 //Select a random objformat 00831 if (!g_list_length(objtype->formats)) { 00832 osync_trace(TRACE_INTERNAL, "%s: Next. No formats", __func__); 00833 continue; 00834 } 00835 OSyncObjFormat *format = NULL; 00836 selected = g_random_int_range(0, g_list_length(objtype->formats)); 00837 format = g_list_nth_data(objtype->formats, selected); 00838 00839 if (!format->create_func) { 00840 osync_trace(TRACE_INTERNAL, "%s: Next. Format %s has no create function", __func__, format->name); 00841 continue; 00842 } 00843 //Create the data 00844 format->create_func(change); 00845 00846 osync_change_set_objformat(change, format); 00847 //Convert the data to a format the plugin understands 00848 OSyncObjTypeSink *objtype_sink = osync_member_find_objtype_sink(member, objtype->name); 00849 if (!objtype_sink) { 00850 osync_trace(TRACE_INTERNAL, "%s: Next. No objtype sink for %s", __func__, objtype->name); 00851 continue; //We had a objtype we cannot add 00852 } 00853 00854 selected = g_random_int_range(0, g_list_length(objtype_sink->formatsinks)); 00855 format_sink = g_list_nth_data(objtype_sink->formatsinks, selected); 00856 /*FIXME: use multiple sinks, or what? */ 00857 OSyncError *error = NULL; 00858 if (!osync_change_convert(env, change, format_sink->format, &error)) { 00859 osync_trace(TRACE_INTERNAL, "%s: Next. Unable to convert: %s", __func__, osync_error_print(&error)); 00860 continue; //Unable to convert to selected format 00861 } 00862 00863 break; 00864 } 00865 return format_sink; 00866 } 00867 00868 00875 void *osync_member_get_data(OSyncMember *member) 00876 { 00877 g_assert(member); 00878 return member->enginedata; 00879 } 00880 00887 void osync_member_set_data(OSyncMember *member, void *data) 00888 { 00889 g_assert(member); 00890 member->enginedata = data; 00891 } 00892 00899 OSyncGroup *osync_member_get_group(OSyncMember *member) 00900 { 00901 g_assert(member); 00902 return member->group; 00903 } 00904 00912 OSyncMember *osync_member_from_id(OSyncGroup *group, int id) 00913 { 00914 OSyncMember *member; 00915 int i; 00916 for (i = 0; i < osync_group_num_members(group); i++) { 00917 member = osync_group_nth_member(group, i); 00918 if (member->id == id) { 00919 return member; 00920 } 00921 } 00922 osync_debug("OSPLG", 0, "Couldnt find the member with the id %i", id); 00923 return NULL; 00924 } 00925 00926 00927 00935 osync_bool osync_member_objtype_enabled(OSyncMember *member, const char *objtype) 00936 { 00937 g_assert(member); 00938 OSyncObjTypeSink *sink = osync_member_find_objtype_sink(member, objtype); 00939 g_assert(sink); 00940 return sink->enabled; 00941 } 00942 00955 void osync_member_set_objtype_enabled(OSyncMember *member, const char *objtypestr, osync_bool enabled) 00956 { 00957 osync_trace(TRACE_ENTRY, "%s(%p, %s, %i)", __func__, member, objtypestr, enabled); 00958 OSyncObjTypeSink *sink = NULL; 00959 g_assert(member); 00960 00961 if (osync_conv_objtype_is_any(objtypestr)) { 00962 GList *o = NULL; 00963 for (o = member->objtype_sinks; o; o = o->next) { 00964 OSyncObjTypeSink *sink = o->data; 00965 sink->enabled = enabled; 00966 } 00967 } else { 00968 GList *o = NULL; 00969 for (o = member->objtype_sinks; o; o = o->next) { 00970 sink = o->data; 00971 if (!strcmp(sink->objtype->name, objtypestr)) 00972 break; 00973 sink = NULL; 00974 } 00975 00976 if (!sink) { 00977 osync_trace(TRACE_EXIT_ERROR, "Unable to find sink with name \"%s\"", objtypestr); 00978 return; 00979 } 00980 sink->enabled = enabled; 00981 } 00982 osync_trace(TRACE_EXIT, "%s", __func__); 00983 } 00984 00994 01004 osync_bool osync_member_initialize(OSyncMember *member, OSyncError **error) 01005 { 01006 osync_trace(TRACE_ENTRY, "%s(%p, %p)", __func__, member, error); 01007 if (!osync_member_instance_default_plugin(member, error)) { 01008 osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error)); 01009 return FALSE; 01010 } 01011 01012 g_assert(member); 01013 g_assert(member->plugin); 01014 OSyncPluginFunctions functions = member->plugin->info.functions; 01015 g_assert(functions.initialize); 01016 if (!(member->plugindata = functions.initialize(member, error))) { 01017 osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error)); 01018 return FALSE; 01019 } 01020 01021 osync_trace(TRACE_EXIT, "%s", __func__); 01022 return TRUE; 01023 } 01024 01032 void osync_member_finalize(OSyncMember *member) 01033 { 01034 osync_trace(TRACE_ENTRY, "%s(%p)", __func__, member); 01035 g_assert(member); 01036 g_assert(member->plugin); 01037 OSyncPluginFunctions functions = member->plugin->info.functions; 01038 if (functions.finalize) 01039 functions.finalize(member->plugindata); 01040 osync_trace(TRACE_EXIT, "%s", __func__); 01041 } 01042 01052 void osync_member_get_changeinfo(OSyncMember *member, OSyncEngCallback function, void *user_data) 01053 { 01054 osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, member, function, user_data); 01055 OSyncPluginFunctions functions = member->plugin->info.functions; 01056 OSyncContext *context = osync_context_new(member); 01057 context->callback_function = function; 01058 context->calldata = user_data; 01059 if (!functions.get_changeinfo) { 01060 osync_context_report_error(context, OSYNC_ERROR_GENERIC, "No get_changeinfo function was given"); 01061 osync_trace(TRACE_EXIT_ERROR, "%s: No get_changeinfo function was given", __func__); 01062 return; 01063 } 01064 functions.get_changeinfo(context); 01065 osync_trace(TRACE_EXIT, "%s", __func__); 01066 } 01067 01078 void osync_member_read_change(OSyncMember *member, OSyncChange *change, OSyncEngCallback function, void *user_data) 01079 { 01080 osync_trace(TRACE_ENTRY, "%s(%p, %p, %p, %p)", __func__, member, change, function, user_data); 01081 01082 g_assert(change); 01083 g_assert(change->uid); 01084 g_assert(osync_change_get_objformat(change)); 01085 01086 OSyncContext *context = osync_context_new(member); 01087 context->callback_function = function; 01088 context->calldata = user_data; 01089 01090 //search for the right formatsink 01091 GList *i; 01092 osync_debug("OSYNC", 2, "Searching for sink"); 01093 for (i = member->format_sinks; i; i = i->next) { 01094 OSyncObjFormatSink *fmtsink = i->data; 01095 01096 if (fmtsink->format == osync_change_get_objformat(change)) { 01097 //Read the change 01098 g_assert(fmtsink->functions.read != NULL); 01099 fmtsink->functions.read(context, change); 01100 osync_trace(TRACE_EXIT, "%s", __func__); 01101 return; 01102 } 01103 } 01104 01105 osync_context_report_error(context, OSYNC_ERROR_CONVERT, "Unable to send changes"); 01106 osync_trace(TRACE_EXIT_ERROR, "%s: Unable to find a sink", __func__); 01107 } 01108 01116 osync_bool osync_member_has_read_function(OSyncMember *member, OSyncObjType *objtype) 01117 { 01118 GList *i; 01119 for (i = member->format_sinks; i; i = i->next) { 01120 OSyncObjFormatSink *fmtsink = i->data; 01121 01122 if (osync_objformat_get_objtype(fmtsink->format) == objtype) 01123 return fmtsink->functions.read ? TRUE : FALSE; 01124 } 01125 return FALSE; 01126 } 01127 01138 void osync_member_get_change_data(OSyncMember *member, OSyncChange *change, OSyncEngCallback function, void *user_data) 01139 { 01140 osync_trace(TRACE_ENTRY, "%s(%p, %p, %p, %p)", __func__, member, change, function, user_data); 01141 OSyncPluginFunctions functions = member->plugin->info.functions; 01142 g_assert(change != NULL); 01143 OSyncContext *context = osync_context_new(member); 01144 context->callback_function = function; 01145 context->calldata = user_data; 01146 functions.get_data(context, change); 01147 osync_trace(TRACE_EXIT, "%s", __func__); 01148 } 01149 01159 void osync_member_connect(OSyncMember *member, OSyncEngCallback function, void *user_data) 01160 { 01161 osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, member, function, user_data); 01162 OSyncPluginFunctions functions = member->plugin->info.functions; 01163 OSyncContext *context = osync_context_new(member); 01164 context->callback_function = function; 01165 context->calldata = user_data; 01166 if (!functions.connect) { 01167 osync_context_report_error(context, OSYNC_ERROR_GENERIC, "No connect function was given"); 01168 osync_trace(TRACE_EXIT_ERROR, "%s: No connect function was given", __func__); 01169 return; 01170 } 01171 functions.connect(context); 01172 osync_trace(TRACE_EXIT, "%s", __func__); 01173 } 01174 01184 void osync_member_disconnect(OSyncMember *member, OSyncEngCallback function, void *user_data) 01185 { 01186 osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, member, function, user_data); 01187 OSyncPluginFunctions functions = member->plugin->info.functions; 01188 OSyncContext *context = osync_context_new(member); 01189 context->callback_function = function; 01190 context->calldata = user_data; 01191 if (!functions.disconnect) { 01192 osync_context_report_error(context, OSYNC_ERROR_GENERIC, "No disconnect function was given"); 01193 osync_trace(TRACE_EXIT_ERROR, "%s: No disconnect function was given", __func__); 01194 return; 01195 } 01196 functions.disconnect(context); 01197 osync_trace(TRACE_EXIT, "%s", __func__); 01198 } 01199 01209 void osync_member_sync_done(OSyncMember *member, OSyncEngCallback function, void *user_data) 01210 { 01211 osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, member, function, user_data); 01212 OSyncPluginFunctions functions = member->plugin->info.functions; 01213 OSyncContext *context = osync_context_new(member); 01214 context->callback_function = function; 01215 context->calldata = user_data; 01216 osync_member_set_slow_sync(member, "data", FALSE); 01217 if (functions.sync_done) { 01218 functions.sync_done(context); 01219 } else { 01220 osync_context_report_success(context); 01221 } 01222 osync_trace(TRACE_EXIT, "%s", __func__); 01223 } 01224 01235 void osync_member_commit_change(OSyncMember *member, OSyncChange *change, OSyncEngCallback function, void *user_data) 01236 { 01237 osync_trace(TRACE_ENTRY, "%s(%p, %p, %p, %p)", __func__, member, change, function, user_data); 01238 g_assert(member); 01239 g_assert(change); 01240 01241 OSyncContext *context = osync_context_new(member); 01242 context->callback_function = function; 01243 context->calldata = user_data; 01244 01245 01246 OSyncObjType *type = osync_change_get_objtype(change); 01247 01248 /* This is just an optmization: 01249 * 01250 * the path search function will avoid doing 01251 * cross-objtype conversions, so 01252 * if we already have a sink for the original objtype, 01253 * and it is disabled, we can drop the change 01254 * without doing detection/conversion first. 01255 * 01256 * If the objtype will change during conversion, 01257 * we check the right objtype sink later, 01258 * anyway 01259 */ 01260 OSyncObjTypeSink *sink = osync_member_find_objtype_sink(member, type->name); 01261 if (sink && !sink->enabled) { 01262 osync_context_report_success(context); 01263 osync_trace(TRACE_EXIT, "%s: Sink not enabled", __func__); 01264 return; 01265 } 01266 01267 01268 //The destobjtype is the objtype of the format to which 01269 //the change was just converted 01270 change->destobjtype = g_strdup(osync_change_get_objtype(change)->name); 01271 01272 //Filter the change. 01273 if (!osync_filter_change_allowed(member, change)) { 01274 osync_context_report_success(context); 01275 osync_trace(TRACE_EXIT, "%s: Change filtered", __func__); 01276 return; 01277 } 01278 01279 //search for the right formatsink, now that 01280 //the change was converted 01281 GList *i; 01282 osync_debug("OSYNC", 2, "Searching for sink"); 01283 for (i = member->format_sinks; i; i = i->next) { 01284 OSyncObjFormatSink *fmtsink = i->data; 01285 01286 osync_debug("OSYNC", 2, "Comparing change %s with sink %s", osync_change_get_objformat(change)->name, fmtsink->format ? fmtsink->format->name : "None"); 01287 if (fmtsink->format == osync_change_get_objformat(change)) { 01288 if (fmtsink->functions.batch_commit) { 01289 //Append to the stored changes 01290 fmtsink->commit_changes = g_list_append(fmtsink->commit_changes, change); 01291 fmtsink->commit_contexts = g_list_append(fmtsink->commit_contexts, context); 01292 osync_trace(TRACE_EXIT, "%s: Waiting for batch processing", __func__); 01293 return; 01294 } else { 01295 // Send the change 01296 if (!fmtsink->functions.commit_change) { 01297 osync_context_report_error(context, OSYNC_ERROR_GENERIC, "No commit_change function was given"); 01298 osync_trace(TRACE_EXIT_ERROR, "%s: No commit_change function was given", __func__); 01299 return; 01300 } 01301 fmtsink->functions.commit_change(context, change); 01302 osync_trace(TRACE_EXIT, "%s", __func__); 01303 return; 01304 } 01305 } 01306 } 01307 01308 osync_context_report_error(context, OSYNC_ERROR_CONVERT, "Unable to send changes"); 01309 osync_trace(TRACE_EXIT_ERROR, "%s: Unable to find a sink", __func__); 01310 } 01311 01322 void osync_member_committed_all(OSyncMember *member, OSyncEngCallback function, void *user_data) 01323 { 01324 osync_trace(TRACE_ENTRY, "%s(%p)", __func__, member); 01325 OSyncChange **changes = NULL; 01326 OSyncContext **contexts = NULL; 01327 01328 OSyncContext *context = osync_context_new(member); 01329 context->callback_function = function; 01330 context->calldata = user_data; 01331 01332 GList *pendingchanges = NULL; 01333 GList *pendingcontexts = NULL; 01334 01335 GList *f; 01336 for (f = member->format_sinks; f; f = f->next) { 01337 OSyncObjFormatSink *fmtsink = f->data; 01338 osync_debug("OSYNC", 2, "Sending changes to sink %p:%s", fmtsink, fmtsink->format ? fmtsink->format->name : "None"); 01339 01340 OSyncFormatFunctions functions = fmtsink->functions; 01341 01342 if (functions.batch_commit) { 01343 pendingchanges = g_list_concat(pendingchanges, fmtsink->commit_changes); 01344 pendingcontexts = g_list_concat(pendingcontexts, fmtsink->commit_contexts); 01345 01346 fmtsink->commit_changes = NULL; 01347 fmtsink->commit_contexts = NULL; 01348 } 01349 } 01350 01351 f = member->format_sinks; 01352 if (f) { 01353 OSyncObjFormatSink *fmtsink = f->data; 01354 osync_debug("OSYNC", 2, "Sending committed all to sink %p:%s", fmtsink, fmtsink->format ? fmtsink->format->name : "None"); 01355 01356 OSyncFormatFunctions functions = fmtsink->functions; 01357 01358 if (functions.batch_commit) { 01359 int i = 0; 01360 changes = g_malloc0(sizeof(OSyncChange *) * (g_list_length(pendingchanges) + 1)); 01361 contexts = g_malloc0(sizeof(OSyncContext *) * (g_list_length(pendingcontexts) + 1));; 01362 GList *o = pendingcontexts; 01363 GList *c = NULL; 01364 01365 for (c = pendingchanges; c && o; c = c->next) { 01366 OSyncChange *change = c->data; 01367 OSyncContext *context = o->data; 01368 01369 changes[i] = change; 01370 contexts[i] = context; 01371 01372 i++; 01373 o = o->next; 01374 } 01375 01376 g_list_free(pendingchanges); 01377 g_list_free(pendingcontexts); 01378 01379 functions.batch_commit(context, contexts, changes); 01380 01381 g_free(changes); 01382 g_free(contexts); 01383 } else if (functions.committed_all) { 01384 functions.committed_all(context); 01385 } else { 01386 osync_context_report_success(context); 01387 } 01388 } 01389 01390 osync_trace(TRACE_EXIT, "%s", __func__); 01391 } 01392 01393 void osync_member_set_name(OSyncMember *member, const char *name) 01394 { 01395 g_assert(member); 01396 if (member->name) 01397 g_free(member->name); 01398 member->name = g_strdup(name); 01399 } 01400 01401 const char *osync_member_get_name(OSyncMember *member) 01402 { 01403 return member->name; 01404 } 01405 01416 OSyncChange *osync_member_add_random_data(OSyncMember *member, const char *objtype) 01417 { 01418 osync_trace(TRACE_ENTRY, "%s(%p)", __func__, member); 01419 OSyncContext *context = osync_context_new(member); 01420 OSyncChange *change = osync_change_new(); 01421 change->changetype = CHANGE_ADDED; 01422 OSyncObjFormatSink *format_sink; 01423 if (!(format_sink = osync_member_make_random_data(member, change, objtype))) { 01424 osync_trace(TRACE_EXIT_ERROR, "%s: Unable to make random data", __func__); 01425 return NULL; 01426 } 01427 01428 if (!format_sink->functions.access) { 01429 osync_trace(TRACE_EXIT_ERROR, "%s: No access function", __func__); 01430 return NULL; 01431 } 01432 01433 if (!format_sink->functions.access(context, change)) { 01434 osync_trace(TRACE_EXIT_ERROR, "%s: Unable to write change", __func__); 01435 return NULL; 01436 } 01437 01438 osync_trace(TRACE_EXIT, "%s: %p", __func__, change); 01439 return change; 01440 } 01441 01452 osync_bool osync_member_modify_random_data(OSyncMember *member, OSyncChange *change) 01453 { 01454 osync_trace(TRACE_ENTRY, "%s(%p, %p)", __func__, member, change); 01455 OSyncContext *context = osync_context_new(member); 01456 change->changetype = CHANGE_MODIFIED; 01457 OSyncObjFormatSink *format_sink; 01458 char *uid = g_strdup(osync_change_get_uid(change)); 01459 01460 if (!(format_sink = osync_member_make_random_data(member, change, osync_change_get_objtype(change)->name))) { 01461 osync_trace(TRACE_EXIT_ERROR, "%s: Unable to make random data", __func__); 01462 return FALSE; 01463 } 01464 01465 osync_change_set_uid(change, uid); 01466 01467 if (!format_sink->functions.access) { 01468 osync_trace(TRACE_EXIT_ERROR, "%s: No access function", __func__); 01469 return FALSE; 01470 } 01471 01472 if (!format_sink->functions.access(context, change)) { 01473 osync_trace(TRACE_EXIT_ERROR, "%s: Unable to modify change", __func__); 01474 return FALSE; 01475 } 01476 01477 osync_trace(TRACE_EXIT, "%s", __func__); 01478 return TRUE; 01479 } 01480 01491 osync_bool osync_member_delete_data(OSyncMember *member, OSyncChange *change) 01492 { 01493 osync_trace(TRACE_ENTRY, "%s(%p, %p)", __func__, member, change); 01494 OSyncContext *context = osync_context_new(member); 01495 change->changetype = CHANGE_DELETED; 01496 01497 OSyncObjTypeSink *objtype_sink = osync_member_find_objtype_sink(member, osync_change_get_objtype(change)->name); 01498 if (!objtype_sink) { 01499 osync_trace(TRACE_EXIT_ERROR, "%s: Unable to find objsink for %s", __func__, osync_change_get_objtype(change)->name); 01500 return FALSE; 01501 } 01502 01503 OSyncObjFormat *format = osync_change_get_objformat(change); 01504 OSyncObjFormatSink *format_sink = osync_objtype_find_format_sink(objtype_sink, format->name); 01505 if (!format_sink) { 01506 osync_trace(TRACE_EXIT_ERROR, "%s: Unable to find format sink for %s", __func__, format->name); 01507 return FALSE; 01508 } 01509 01510 if (format_sink->functions.batch_commit) { 01511 //Append to the stored changes 01512 format_sink->commit_changes = g_list_append(format_sink->commit_changes, change); 01513 format_sink->commit_contexts = g_list_append(format_sink->commit_contexts, context); 01514 osync_trace(TRACE_EXIT, "%s: Waiting for batch processing", __func__); 01515 return TRUE; 01516 } else { 01517 if (!format_sink->functions.access) { 01518 osync_trace(TRACE_EXIT_ERROR, "%s: No access function", __func__); 01519 return FALSE; 01520 } 01521 01522 if (!format_sink->functions.access(context, change)) { 01523 osync_trace(TRACE_EXIT_ERROR, "%s: Unable to modify change", __func__); 01524 return FALSE; 01525 } 01526 } 01527 01528 osync_trace(TRACE_EXIT, "%s", __func__); 01529 return TRUE; 01530 } 01531 01536 void osync_member_write_sink_info(OSyncMember *member, OSyncMessage *message) 01537 { 01538 GList *obj = NULL; 01539 for (osync_member_get_objtype_sinks(member, &obj, NULL); obj; obj = obj->next) { 01540 OSyncObjTypeSink *sink = obj->data; 01541 int slow; 01542 slow = osync_member_get_slow_sync(member, sink->objtype->name); 01543 osync_message_write_string(message, sink->objtype->name); 01544 osync_message_write_int(message, sink->read); 01545 osync_message_write_int(message, sink->write); 01546 osync_message_write_int(message, sink->enabled); 01547 osync_message_write_int(message, slow); 01548 } 01549 osync_message_write_string(message, NULL); 01550 } 01551 01556 int __sync_member_read_sink_info(OSyncMember *member, OSyncMessage *message) 01557 { 01558 char *objtypestr; 01559 int r = 0; 01560 for (;;) { 01561 int read, write, enabled, slow; 01562 osync_message_read_string(message, &objtypestr); 01563 if (!objtypestr) 01564 break; 01565 01566 osync_message_read_int(message, &read); 01567 osync_message_read_int(message, &write); 01568 osync_message_read_int(message, &enabled); 01569 osync_message_read_int(message, &slow); 01570 01571 OSyncObjTypeSink *sink = osync_member_find_objtype_sink(member, objtypestr); 01572 if (!sink) 01573 continue; 01574 01575 sink->read = read; 01576 sink->write = write; 01577 sink->enabled = enabled; 01578 01579 if (slow) { 01580 osync_member_set_slow_sync(member, objtypestr, TRUE); 01581 r++; 01582 } 01583 01584 free(objtypestr); 01585 } 01586 return r; 01587 } 01588 01589 01603 void osync_member_read_sink_info_full(OSyncMember *member, OSyncMessage *message) 01604 { 01605 osync_group_reset_slow_sync(member->group, "data"); 01606 __sync_member_read_sink_info(member, message); 01607 } 01608 01621 void osync_member_read_sink_info(OSyncMember *member, OSyncMessage *message) 01622 { 01623 int set_for_any; 01624 01625 set_for_any = __sync_member_read_sink_info(member, message); 01626 01627 if (set_for_any) { 01628 /* FIXME: We must force slow-sync in "data" when some 01629 * objtype is marked to slow-sync 01630 * 01631 * (See ticket #1011) 01632 */ 01633 osync_member_set_slow_sync(member, "data", TRUE); 01634 } 01635 } 01636