• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List

opensync/opensync_member.c

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 

Generated on Sat Aug 13 2011 for OpenSync by  doxygen 1.7.1