OpenSync  0.22
opensync_member.c
1 /*
2  * libopensync - A synchronization framework
3  * Copyright (C) 2004-2005 Armin Bauer <armin.bauer@opensync.org>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  *
19  */
20 
21 #include "opensync.h"
22 #include "opensync_internals.h"
23 
31 
32 #ifndef DOXYGEN_SHOULD_SKIP_THIS
33 OSyncMemberFunctions *osync_memberfunctions_new()
34 {
35  OSyncMemberFunctions *functions = g_malloc0(sizeof(OSyncMemberFunctions));
36  return functions;
37 }
38 
39 OSyncMemberFunctions *osync_member_get_memberfunctions(OSyncMember *member)
40 {
41  return member->memberfunctions;
42 }
43 
44 OSyncFormatEnv *osync_member_get_format_env(OSyncMember *member)
45 {
46  g_assert(member);
47  return osync_group_get_format_env(member->group);
48 }
49 
54 OSyncObjTypeSink *osync_member_find_objtype_sink(OSyncMember *member, const char *objtypestr)
55 {
56  GList *o;
57  for (o = member->objtype_sinks; o; o = o->next) {
58  OSyncObjTypeSink *sink = o->data;
59  if (osync_conv_objtype_is_any(sink->objtype->name) || !strcmp(sink->objtype->name, objtypestr))
60  return sink;
61  }
62  return NULL;
63 }
64 
74 osync_bool osync_member_require_sink_info(OSyncMember *member, OSyncError **error)
75 {
76  // Currently, the only way to get the objtype_sink information
77  // is loading the plugin
78  if (!osync_member_instance_default_plugin(member, error))
79  return FALSE;
80 
81  return TRUE;
82 }
83 
92 osync_bool osync_member_get_objtype_sinks(OSyncMember *member, GList **list_ptr, OSyncError **error)
93 {
94  if (!osync_member_require_sink_info(member, error))
95  return FALSE;
96 
97  *list_ptr = member->objtype_sinks;
98  return TRUE;
99 }
100 
120 osync_bool osync_member_read_config(OSyncMember *member, char **data, int *size, OSyncError **error)
121 {
122  osync_trace(TRACE_ENTRY, "osync_member_read_config(%p, %p, %p, %p)", member, data, size, error);
123 
124  if (!osync_member_instance_default_plugin(member, error)) {
125  osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
126  return FALSE;
127  }
128 
129  OSyncPluginFunctions functions = member->plugin->info.functions;
130  osync_bool ret = FALSE;
131  if (!member->configdir) {
132  osync_error_set(error, OSYNC_ERROR_GENERIC, "Member has no config directory set");
133  osync_trace(TRACE_EXIT_ERROR, "osync_member_read_config: %i", osync_error_print(error));
134  return FALSE;
135  }
136 
137  if (functions.get_config) {
138  ret = functions.get_config(member->configdir, data, size);
139  } else {
140  char *filename = g_strdup_printf("%s/%s.conf", member->configdir, osync_plugin_get_name(member->plugin));
141  ret = osync_file_read(filename, data, size, error);
142  g_free(filename);
143  }
144 
145  if (ret)
146  osync_trace(TRACE_EXIT, "osync_member_read_config: TRUE");
147  else
148  osync_trace(TRACE_EXIT_ERROR, "osync_member_read_config: %s", osync_error_print(error));
149  return ret;
150 }
151 
152 #endif
153 
163 
171 {
172  OSyncMember *member = g_malloc0(sizeof(OSyncMember));
173  if (group) {
174  osync_group_add_member(group, member);
175  member->group = group;
176  }
177 
178  member->memberfunctions = osync_memberfunctions_new();
179  member->name = NULL;
180 
181  return member;
182 }
183 
190 {
191  osync_assert_msg(member, "You must set a member to free");
192 
193  if (member->group)
194  osync_group_remove_member(member->group, member);
195 
196  //Free the plugin if we are not thread-safe
197  /*if (member->plugin && !member->plugin->info.is_threadsafe) {
198  osync_plugin_unload(member->plugin);
199  osync_plugin_free(member->plugin);
200  }*/
201 
202  if (member->pluginname)
203  g_free(member->pluginname);
204 
205  g_free(member->memberfunctions);
206  g_free(member);
207 }
208 
215 {
216  g_assert(member);
217  if (!member->plugin)
218  return;
219 
220  /*if (!member->plugin->info.is_threadsafe) {
221  osync_plugin_unload(member->plugin);
222  osync_plugin_free(member->plugin);
223  }*/
224 
225  g_list_free(member->objtype_sinks);
226  g_list_free(member->format_sinks);
227  //Really free the formats!
228 
229  member->objtype_sinks = NULL;
230  member->format_sinks = NULL;
231  member->plugin = NULL;
232 }
233 
242 osync_bool osync_member_instance_plugin(OSyncMember *member, const char *pluginname, OSyncError **error)
243 {
244  g_assert(member);
245  g_assert(member->group);
246  g_assert(pluginname);
247 
248  OSyncPlugin *plugin = osync_env_find_plugin(member->group->env, pluginname);
249  if (!plugin) {
250  osync_debug("OSPLG", 0, "Couldn't find the plugin %s for member", pluginname);
251  osync_error_set(error, OSYNC_ERROR_MISCONFIGURATION, "Unable to find the plugin \"%s\"", pluginname);
252  return FALSE;
253  }
254 
256 
257  //For now we disable the threadsafety feature since dlopen doesnt like it
258  member->plugin = plugin;
259  /*if (plugin->info.is_threadsafe) {
260  member->plugin = plugin;
261  } else {
262  member->plugin = osync_plugin_load(NULL, plugin->path, error);
263  if (!member->plugin)
264  return FALSE;
265  }*/
266  member->pluginname = g_strdup(osync_plugin_get_name(member->plugin));
267 
268  //Prepare the sinks;
269  GList *o;
270  for (o = member->plugin->accepted_objtypes; o; o = o->next) {
271  OSyncObjTypeTemplate *objtemplate = o->data;
272  OSyncObjTypeSink *objsink = osync_objtype_sink_from_template(member->group, objtemplate);
273  if (!objsink) {
274  osync_error_set(error, OSYNC_ERROR_GENERIC, "Could not find object type \"%s\"", objtemplate->name);
275  return FALSE;
276  }
277  member->objtype_sinks = g_list_append(member->objtype_sinks, objsink);
278  GList *f;
279  for (f = objtemplate->formats; f; f = f->next) {
280  OSyncObjFormatTemplate *frmtemplate = f->data;
281  OSyncObjFormatSink *format_sink = osync_objformat_sink_from_template(member->group, frmtemplate);
282  if (!format_sink) {
283  osync_error_set(error, OSYNC_ERROR_GENERIC, "Could not find format \"%s\"", frmtemplate->name);
284  return FALSE;
285  }
286  objsink->formatsinks = g_list_append(objsink->formatsinks, format_sink);
287  format_sink->objtype_sink = objsink;
288  member->format_sinks = g_list_append(member->format_sinks, format_sink);
289  if (frmtemplate->extension_name)
290  member->extension = g_strdup(frmtemplate->extension_name);
291  }
292  }
293 
294  member->pluginname = g_strdup(pluginname);
295  return TRUE;
296 }
297 
306 {
307  if (member->plugin)
308  return TRUE;
309 
310  if (!member->pluginname) {
311  osync_error_set(error, OSYNC_ERROR_GENERIC, "No default plugin set while instancing");
312  return FALSE;
313  }
314 
315  return osync_member_instance_plugin(member, member->pluginname, error);
316 }
317 
325 {
326  g_assert(member);
328  return member->plugin;
329 }
330 
338 {
339  g_assert(member);
340  return member->pluginname;
341 }
342 
349 void osync_member_set_pluginname(OSyncMember *member, const char *pluginname)
350 {
351  g_assert(member);
352  if (member->pluginname)
353  g_free(member->pluginname);
354  member->pluginname = g_strdup(pluginname);
355 }
356 
368 {
369  g_assert(member);
370  OSyncPlugin *plugin = osync_member_get_plugin(member);
371  return osync_plugin_get_plugin_data(plugin);
372 }
373 
381 {
382  g_assert(member);
383  return member->configdir;
384 }
385 
392 void osync_member_set_configdir(OSyncMember *member, const char *configdir)
393 {
394  g_assert(member);
395  if (member->configdir)
396  g_free(member->configdir);
397  member->configdir = g_strdup(configdir);
398 }
399 
400 osync_bool osync_member_need_config(OSyncMember *member, OSyncConfigurationTypes *type, OSyncError **error)
401 {
402  osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, member, type, error);
403  g_assert(member);
404  g_assert(type);
405  *type = NO_CONFIGURATION;
406 
407  if (!osync_member_instance_default_plugin(member, error))
408  goto error;
409 
410  *type = member->plugin->info.config_type;
411 
412  osync_trace(TRACE_EXIT, "%s: %i", __func__, *type);
413  return TRUE;
414 
415 error:
416  osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
417  return FALSE;
418 }
419 
437 osync_bool osync_member_get_config_or_default(OSyncMember *member, char **data, int *size, OSyncError **error)
438 {
439  osync_trace(TRACE_ENTRY, "%s(%p, %p, %p, %p)", __func__, member, data, size, error);
440  g_assert(member);
441  osync_bool ret = TRUE;
442 
443  if (member->configdata) {
444  *data = member->configdata;
445  *size = member->configsize;
446  osync_trace(TRACE_EXIT, "%s: Configdata already in memory", __func__);
447  return TRUE;
448  }
449 
450  if (!osync_member_read_config(member, data, size, error)) {
451  if (osync_error_is_set(error)) {
452  osync_trace(TRACE_INTERNAL, "Read config not successfull: %s", osync_error_print(error));
453  osync_error_free(error);
454  }
455 
456  char *filename = g_strdup_printf(OPENSYNC_CONFIGDIR"/%s", member->pluginname);
457  osync_debug("OSMEM", 3, "Reading default2 config file for member %lli from %s", member->id, filename);
458  ret = osync_file_read(filename, data, size, error);
459  g_free(filename);
460  }
461  osync_trace(TRACE_EXIT, "%s: %i", __func__, ret);
462  return ret;
463 }
464 
483 osync_bool osync_member_get_config(OSyncMember *member, char **data, int *size, OSyncError **error)
484 {
485  osync_trace(TRACE_ENTRY, "%s(%p, %p, %p, %p)", __func__, member, data, size, error);
486  g_assert(member);
487  osync_bool ret = TRUE;
488 
489  if (!osync_member_instance_default_plugin(member, error)) {
490  osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
491  return FALSE;
492  }
493 
494  if (member->plugin->info.config_type == NO_CONFIGURATION) {
495  osync_error_set(error, OSYNC_ERROR_GENERIC, "This member has no configuration options");
496  osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
497  return FALSE;
498  }
499 
500  if (member->configdata) {
501  *data = member->configdata;
502  *size = member->configsize;
503  osync_trace(TRACE_EXIT, "%s: Configdata already in memory", __func__);
504  return TRUE;
505  }
506 
507  if (!osync_member_read_config(member, data, size, error)) {
508  if (osync_error_is_set(error)) {
509  osync_trace(TRACE_INTERNAL, "Read config not successfull: %s", osync_error_print(error));
510  osync_error_free(error);
511  }
512 
513  if (member->plugin->info.config_type == NEEDS_CONFIGURATION) {
514  //We dont load the default config for these
515  osync_error_set(error, OSYNC_ERROR_MISCONFIGURATION, "Member has not been configured");
516  osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
517  return FALSE;
518  }
519 
520  char *filename = g_strdup_printf(OPENSYNC_CONFIGDIR"/%s", member->pluginname);
521  osync_debug("OSMEM", 3, "Reading default2 config file for member %lli from %s", member->id, filename);
522  ret = osync_file_read(filename, data, size, error);
523  g_free(filename);
524  }
525  osync_trace(TRACE_EXIT, "%s: %i", __func__, ret);
526  return ret;
527 }
528 
538 void osync_member_set_config(OSyncMember *member, const char *data, int size)
539 {
540  osync_trace(TRACE_ENTRY, "%s(%p, %p, %i)", __func__, member, data, size);
541  g_assert(member);
542  //FIXME free old data
543  member->configdata = g_strdup(data);
544  member->configsize = size;
545 
546  osync_trace(TRACE_EXIT, "%s", __func__);
547 }
548 
556 {
557  g_assert(member);
558  osync_trace(TRACE_INTERNAL, "%s: %p %p", __func__, member, member->loop);
559  return member->loop;
560 }
561 
568 void osync_member_set_loop(OSyncMember *member, void *loop)
569 {
570  g_assert(member);
571  osync_trace(TRACE_INTERNAL, "%s: %p %p", __func__, member, loop);
572  member->loop = loop;
573 }
574 
575 
583 {
584  osync_trace(TRACE_ENTRY, "%s(%p)", __func__, member);
585  g_assert(member);
586 
587  osync_bool ret = (member->plugin->info.config_type == NEEDS_CONFIGURATION || member->plugin->info.config_type == OPTIONAL_CONFIGURATION);
588 
589  osync_trace(TRACE_EXIT, "%s: %i", __func__, ret);
590  return ret;
591 }
592 
601 OSyncMember *osync_member_load(OSyncGroup *group, const char *path, OSyncError **error)
602 {
603  osync_trace(TRACE_ENTRY, "%s(%p, %s, %p)", __func__, group, path, error);
604  xmlDocPtr doc;
605  xmlNodePtr cur;
606  char *filename = NULL;
607 
608  filename = g_strdup_printf ("%s/syncmember.conf", path);
609 
610  OSyncMember *member = osync_member_new(group);
611  char *basename = g_path_get_basename(path);
612  member->id = atoi(basename);
613  g_free(basename);
614  member->configdir = g_strdup(path);
615 
616  if (!_osync_open_xml_file(&doc, &cur, filename, "syncmember", error)) {
617  osync_member_free(member);
618  osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
619  return NULL;
620  }
621 
622  while (cur != NULL) {
623  char *str = (char*)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
624  if (str) {
625  if (!xmlStrcmp(cur->name, (const xmlChar *)"pluginname"))
626  member->pluginname = g_strdup(str);
627  if (!xmlStrcmp(cur->name, (const xmlChar *)"name"))
628  member->name = g_strdup(str);
629  xmlFree(str);
630  }
631  cur = cur->next;
632  }
633  xmlFreeDoc(doc);
634  g_free(filename);
635 
636  osync_trace(TRACE_EXIT, "%s: Loaded member: %p", __func__, member);
637  return member;
638 }
639 
647 osync_bool osync_member_save(OSyncMember *member, OSyncError **error)
648 {
649  osync_trace(TRACE_ENTRY, "%s(%p:(%lli), %p)", __func__, member, member ? member->id : 0, error);
650  char *filename = NULL;
651 
652  if (!osync_member_instance_default_plugin(member, error)) {
653  osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
654  return FALSE;
655  }
656 
657  if (!member->id) {
658  member->id = osync_group_create_member_id(member->group);
659  member->configdir = g_strdup_printf("%s/%lli", member->group->configdir, member->id);
660  }
661 
662  g_assert(member->configdir);
663  if (!g_file_test(member->configdir, G_FILE_TEST_IS_DIR)) {
664  osync_debug("OSMEM", 3, "Creating config directory: %s for member %i", member->configdir, member->id);
665  if (mkdir(member->configdir, 0700)) {
666  osync_error_set(error, OSYNC_ERROR_IO_ERROR, "Unable to create directory for member %li\n", member->id);
667  osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
668  return FALSE;
669  }
670  }
671 
672  //Saving the syncmember.conf
673  filename = g_strdup_printf ("%s/syncmember.conf", member->configdir);
674  xmlDocPtr doc;
675  doc = xmlNewDoc((xmlChar*)"1.0");
676  doc->children = xmlNewDocNode(doc, NULL, (xmlChar*)"syncmember", NULL);
677  //The plugin name
678  xmlNewTextChild(doc->children, NULL, (xmlChar*)"pluginname", (xmlChar*)member->pluginname);
679  //The name
680  xmlNewTextChild(doc->children, NULL, (xmlChar*)"name", (xmlChar*)member->name);
681  xmlSaveFile(filename, doc);
682  xmlFreeDoc(doc);
683  g_free(filename);
684 
685  //Saving the config if it exists
686  osync_bool ret = TRUE;
687  if (member->configdata) {
688  OSyncPluginFunctions functions = member->plugin->info.functions;
689 
690  if (functions.store_config) {
691  ret = functions.store_config(member->configdir, member->configdata, member->configsize);
692  } else {
693  filename = g_strdup_printf("%s/%s.conf", member->configdir, osync_plugin_get_name(member->plugin));
694  if (!osync_file_write(filename, member->configdata, member->configsize, 0600, error)) {
695  ret = FALSE;
696  }
697  g_free(filename);
698  }
699  g_free(member->configdata);
700  member->configdata = NULL;
701  member->configsize = 0;
702  }
703 
704  osync_trace(TRACE_EXIT, "%s: %s", __func__, osync_error_print(error));
705  return ret;
706 }
707 
714 long long int osync_member_get_id(OSyncMember *member)
715 {
716  g_assert(member);
717  return member->id;
718 }
719 
731 void *osync_member_call_plugin(OSyncMember *member, const char *function, void *data, OSyncError **error)
732 {
733  if (!osync_member_instance_default_plugin(member, error))
734  return FALSE;
735 
736  void *(*plgfunc) (void *, void *, OSyncError **);
737  if (!(plgfunc = osync_plugin_get_function(member->plugin, function, error)))
738  return NULL;
739  return plgfunc(member->plugindata, data, error);
740 }
741 
749 void osync_member_set_slow_sync(OSyncMember *member, const char *objtypestr, osync_bool slow_sync)
750 {
751  g_assert(member);
752  OSyncGroup *group = osync_member_get_group(member);
753  g_assert(group);
754 
755  osync_group_set_slow_sync(group, objtypestr, slow_sync);
756 }
757 
765 osync_bool osync_member_get_slow_sync(OSyncMember *member, const char *objtypestr)
766 {
767  osync_trace(TRACE_ENTRY, "%s(%p, %s)", __func__, member, objtypestr);
768  g_assert(member);
769  OSyncGroup *group = osync_member_get_group(member);
770  g_assert(group);
771 
772  osync_bool needs_slow_sync = osync_group_get_slow_sync(group, objtypestr);
773 
774  osync_trace(TRACE_EXIT, "%s: %i", __func__, needs_slow_sync);
775  return needs_slow_sync;
776 }
777 
784 {
785  osync_trace(TRACE_ENTRY, "%s(%p)", __func__, member);
786  g_assert(member);
787 
788  if (member->memberfunctions->rf_sync_alert)
789  member->memberfunctions->rf_sync_alert(member);
790  else {
791  osync_trace(TRACE_EXIT_ERROR, "%s: Alert not handled", __func__);
792  return;
793  }
794  osync_trace(TRACE_EXIT, "%s", __func__);
795 }
796 
797 
806 OSyncObjFormatSink *osync_member_make_random_data(OSyncMember *member, OSyncChange *change, const char *objtypename)
807 {
808  int retry = 0;
809  g_assert(member);
810  OSyncFormatEnv *env = osync_member_get_format_env(member);
811 
812  OSyncObjFormatSink *format_sink = NULL;
813 
814  for (retry = 0; retry < 100; retry++) {
815  if (retry > 20) {
816  osync_trace(TRACE_INTERNAL, "%s: Giving up", __func__);
817  return NULL; //Giving up
818  }
819 
820  //Select a random objtype
821  OSyncObjType *objtype = NULL;
822  int selected = 0;
823  if (!objtypename) {
824  selected = g_random_int_range(0, g_list_length(env->objtypes));
825  objtype = g_list_nth_data(env->objtypes, selected);
826  } else
827  objtype = osync_conv_find_objtype(member->group->conv_env, objtypename);
828  osync_change_set_objtype(change, objtype);
829 
830  //Select a random objformat
831  if (!g_list_length(objtype->formats)) {
832  osync_trace(TRACE_INTERNAL, "%s: Next. No formats", __func__);
833  continue;
834  }
835  OSyncObjFormat *format = NULL;
836  selected = g_random_int_range(0, g_list_length(objtype->formats));
837  format = g_list_nth_data(objtype->formats, selected);
838 
839  if (!format->create_func) {
840  osync_trace(TRACE_INTERNAL, "%s: Next. Format %s has no create function", __func__, format->name);
841  continue;
842  }
843  //Create the data
844  format->create_func(change);
845 
846  osync_change_set_objformat(change, format);
847  //Convert the data to a format the plugin understands
848  OSyncObjTypeSink *objtype_sink = osync_member_find_objtype_sink(member, objtype->name);
849  if (!objtype_sink) {
850  osync_trace(TRACE_INTERNAL, "%s: Next. No objtype sink for %s", __func__, objtype->name);
851  continue; //We had a objtype we cannot add
852  }
853 
854  selected = g_random_int_range(0, g_list_length(objtype_sink->formatsinks));
855  format_sink = g_list_nth_data(objtype_sink->formatsinks, selected);
856  /*FIXME: use multiple sinks, or what? */
857  OSyncError *error = NULL;
858  if (!osync_change_convert(env, change, format_sink->format, &error)) {
859  osync_trace(TRACE_INTERNAL, "%s: Next. Unable to convert: %s", __func__, osync_error_print(&error));
860  continue; //Unable to convert to selected format
861  }
862 
863  break;
864  }
865  return format_sink;
866 }
867 
868 
876 {
877  g_assert(member);
878  return member->enginedata;
879 }
880 
887 void osync_member_set_data(OSyncMember *member, void *data)
888 {
889  g_assert(member);
890  member->enginedata = data;
891 }
892 
900 {
901  g_assert(member);
902  return member->group;
903 }
904 
913 {
914  OSyncMember *member;
915  int i;
916  for (i = 0; i < osync_group_num_members(group); i++) {
917  member = osync_group_nth_member(group, i);
918  if (member->id == id) {
919  return member;
920  }
921  }
922  osync_debug("OSPLG", 0, "Couldnt find the member with the id %i", id);
923  return NULL;
924 }
925 
926 
927 
935 osync_bool osync_member_objtype_enabled(OSyncMember *member, const char *objtype)
936 {
937  g_assert(member);
938  OSyncObjTypeSink *sink = osync_member_find_objtype_sink(member, objtype);
939  g_assert(sink);
940  return sink->enabled;
941 }
942 
955 void osync_member_set_objtype_enabled(OSyncMember *member, const char *objtypestr, osync_bool enabled)
956 {
957  osync_trace(TRACE_ENTRY, "%s(%p, %s, %i)", __func__, member, objtypestr, enabled);
958  OSyncObjTypeSink *sink = NULL;
959  g_assert(member);
960 
961  if (osync_conv_objtype_is_any(objtypestr)) {
962  GList *o = NULL;
963  for (o = member->objtype_sinks; o; o = o->next) {
964  OSyncObjTypeSink *sink = o->data;
965  sink->enabled = enabled;
966  }
967  } else {
968  GList *o = NULL;
969  for (o = member->objtype_sinks; o; o = o->next) {
970  sink = o->data;
971  if (!strcmp(sink->objtype->name, objtypestr))
972  break;
973  sink = NULL;
974  }
975 
976  if (!sink) {
977  osync_trace(TRACE_EXIT_ERROR, "Unable to find sink with name \"%s\"", objtypestr);
978  return;
979  }
980  sink->enabled = enabled;
981  }
982  osync_trace(TRACE_EXIT, "%s", __func__);
983 }
984 
994 
1004 osync_bool osync_member_initialize(OSyncMember *member, OSyncError **error)
1005 {
1006  osync_trace(TRACE_ENTRY, "%s(%p, %p)", __func__, member, error);
1007  if (!osync_member_instance_default_plugin(member, error)) {
1008  osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
1009  return FALSE;
1010  }
1011 
1012  g_assert(member);
1013  g_assert(member->plugin);
1014  OSyncPluginFunctions functions = member->plugin->info.functions;
1015  g_assert(functions.initialize);
1016  if (!(member->plugindata = functions.initialize(member, error))) {
1017  osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
1018  return FALSE;
1019  }
1020 
1021  osync_trace(TRACE_EXIT, "%s", __func__);
1022  return TRUE;
1023 }
1024 
1033 {
1034  osync_trace(TRACE_ENTRY, "%s(%p)", __func__, member);
1035  g_assert(member);
1036  g_assert(member->plugin);
1037  OSyncPluginFunctions functions = member->plugin->info.functions;
1038  if (functions.finalize)
1039  functions.finalize(member->plugindata);
1040  osync_trace(TRACE_EXIT, "%s", __func__);
1041 }
1042 
1052 void osync_member_get_changeinfo(OSyncMember *member, OSyncEngCallback function, void *user_data)
1053 {
1054  osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, member, function, user_data);
1055  OSyncPluginFunctions functions = member->plugin->info.functions;
1056  OSyncContext *context = osync_context_new(member);
1057  context->callback_function = function;
1058  context->calldata = user_data;
1059  if (!functions.get_changeinfo) {
1060  osync_context_report_error(context, OSYNC_ERROR_GENERIC, "No get_changeinfo function was given");
1061  osync_trace(TRACE_EXIT_ERROR, "%s: No get_changeinfo function was given", __func__);
1062  return;
1063  }
1064  functions.get_changeinfo(context);
1065  osync_trace(TRACE_EXIT, "%s", __func__);
1066 }
1067 
1078 void osync_member_read_change(OSyncMember *member, OSyncChange *change, OSyncEngCallback function, void *user_data)
1079 {
1080  osync_trace(TRACE_ENTRY, "%s(%p, %p, %p, %p)", __func__, member, change, function, user_data);
1081 
1082  g_assert(change);
1083  g_assert(change->uid);
1084  g_assert(osync_change_get_objformat(change));
1085 
1086  OSyncContext *context = osync_context_new(member);
1087  context->callback_function = function;
1088  context->calldata = user_data;
1089 
1090  //search for the right formatsink
1091  GList *i;
1092  osync_debug("OSYNC", 2, "Searching for sink");
1093  for (i = member->format_sinks; i; i = i->next) {
1094  OSyncObjFormatSink *fmtsink = i->data;
1095 
1096  if (fmtsink->format == osync_change_get_objformat(change)) {
1097  //Read the change
1098  g_assert(fmtsink->functions.read != NULL);
1099  fmtsink->functions.read(context, change);
1100  osync_trace(TRACE_EXIT, "%s", __func__);
1101  return;
1102  }
1103  }
1104 
1105  osync_context_report_error(context, OSYNC_ERROR_CONVERT, "Unable to send changes");
1106  osync_trace(TRACE_EXIT_ERROR, "%s: Unable to find a sink", __func__);
1107 }
1108 
1117 {
1118  GList *i;
1119  for (i = member->format_sinks; i; i = i->next) {
1120  OSyncObjFormatSink *fmtsink = i->data;
1121 
1122  if (osync_objformat_get_objtype(fmtsink->format) == objtype)
1123  return fmtsink->functions.read ? TRUE : FALSE;
1124  }
1125  return FALSE;
1126 }
1127 
1138 void osync_member_get_change_data(OSyncMember *member, OSyncChange *change, OSyncEngCallback function, void *user_data)
1139 {
1140  osync_trace(TRACE_ENTRY, "%s(%p, %p, %p, %p)", __func__, member, change, function, user_data);
1141  OSyncPluginFunctions functions = member->plugin->info.functions;
1142  g_assert(change != NULL);
1143  OSyncContext *context = osync_context_new(member);
1144  context->callback_function = function;
1145  context->calldata = user_data;
1146  functions.get_data(context, change);
1147  osync_trace(TRACE_EXIT, "%s", __func__);
1148 }
1149 
1159 void osync_member_connect(OSyncMember *member, OSyncEngCallback function, void *user_data)
1160 {
1161  osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, member, function, user_data);
1162  OSyncPluginFunctions functions = member->plugin->info.functions;
1163  OSyncContext *context = osync_context_new(member);
1164  context->callback_function = function;
1165  context->calldata = user_data;
1166  if (!functions.connect) {
1167  osync_context_report_error(context, OSYNC_ERROR_GENERIC, "No connect function was given");
1168  osync_trace(TRACE_EXIT_ERROR, "%s: No connect function was given", __func__);
1169  return;
1170  }
1171  functions.connect(context);
1172  osync_trace(TRACE_EXIT, "%s", __func__);
1173 }
1174 
1184 void osync_member_disconnect(OSyncMember *member, OSyncEngCallback function, void *user_data)
1185 {
1186  osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, member, function, user_data);
1187  OSyncPluginFunctions functions = member->plugin->info.functions;
1188  OSyncContext *context = osync_context_new(member);
1189  context->callback_function = function;
1190  context->calldata = user_data;
1191  if (!functions.disconnect) {
1192  osync_context_report_error(context, OSYNC_ERROR_GENERIC, "No disconnect function was given");
1193  osync_trace(TRACE_EXIT_ERROR, "%s: No disconnect function was given", __func__);
1194  return;
1195  }
1196  functions.disconnect(context);
1197  osync_trace(TRACE_EXIT, "%s", __func__);
1198 }
1199 
1209 void osync_member_sync_done(OSyncMember *member, OSyncEngCallback function, void *user_data)
1210 {
1211  osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, member, function, user_data);
1212  OSyncPluginFunctions functions = member->plugin->info.functions;
1213  OSyncContext *context = osync_context_new(member);
1214  context->callback_function = function;
1215  context->calldata = user_data;
1216  osync_member_set_slow_sync(member, "data", FALSE);
1217  if (functions.sync_done) {
1218  functions.sync_done(context);
1219  } else {
1220  osync_context_report_success(context);
1221  }
1222  osync_trace(TRACE_EXIT, "%s", __func__);
1223 }
1224 
1235 void osync_member_commit_change(OSyncMember *member, OSyncChange *change, OSyncEngCallback function, void *user_data)
1236 {
1237  osync_trace(TRACE_ENTRY, "%s(%p, %p, %p, %p)", __func__, member, change, function, user_data);
1238  g_assert(member);
1239  g_assert(change);
1240 
1241  OSyncContext *context = osync_context_new(member);
1242  context->callback_function = function;
1243  context->calldata = user_data;
1244 
1245 
1246  OSyncObjType *type = osync_change_get_objtype(change);
1247 
1248  /* This is just an optmization:
1249  *
1250  * the path search function will avoid doing
1251  * cross-objtype conversions, so
1252  * if we already have a sink for the original objtype,
1253  * and it is disabled, we can drop the change
1254  * without doing detection/conversion first.
1255  *
1256  * If the objtype will change during conversion,
1257  * we check the right objtype sink later,
1258  * anyway
1259  */
1260  OSyncObjTypeSink *sink = osync_member_find_objtype_sink(member, type->name);
1261  if (sink && !sink->enabled) {
1262  osync_context_report_success(context);
1263  osync_trace(TRACE_EXIT, "%s: Sink not enabled", __func__);
1264  return;
1265  }
1266 
1267 
1268  //The destobjtype is the objtype of the format to which
1269  //the change was just converted
1270  change->destobjtype = g_strdup(osync_change_get_objtype(change)->name);
1271 
1272  //Filter the change.
1273  if (!osync_filter_change_allowed(member, change)) {
1274  osync_context_report_success(context);
1275  osync_trace(TRACE_EXIT, "%s: Change filtered", __func__);
1276  return;
1277  }
1278 
1279  //search for the right formatsink, now that
1280  //the change was converted
1281  GList *i;
1282  osync_debug("OSYNC", 2, "Searching for sink");
1283  for (i = member->format_sinks; i; i = i->next) {
1284  OSyncObjFormatSink *fmtsink = i->data;
1285 
1286  osync_debug("OSYNC", 2, "Comparing change %s with sink %s", osync_change_get_objformat(change)->name, fmtsink->format ? fmtsink->format->name : "None");
1287  if (fmtsink->format == osync_change_get_objformat(change)) {
1288  if (fmtsink->functions.batch_commit) {
1289  //Append to the stored changes
1290  fmtsink->commit_changes = g_list_append(fmtsink->commit_changes, change);
1291  fmtsink->commit_contexts = g_list_append(fmtsink->commit_contexts, context);
1292  osync_trace(TRACE_EXIT, "%s: Waiting for batch processing", __func__);
1293  return;
1294  } else {
1295  // Send the change
1296  if (!fmtsink->functions.commit_change) {
1297  osync_context_report_error(context, OSYNC_ERROR_GENERIC, "No commit_change function was given");
1298  osync_trace(TRACE_EXIT_ERROR, "%s: No commit_change function was given", __func__);
1299  return;
1300  }
1301  fmtsink->functions.commit_change(context, change);
1302  osync_trace(TRACE_EXIT, "%s", __func__);
1303  return;
1304  }
1305  }
1306  }
1307 
1308  osync_context_report_error(context, OSYNC_ERROR_CONVERT, "Unable to send changes");
1309  osync_trace(TRACE_EXIT_ERROR, "%s: Unable to find a sink", __func__);
1310 }
1311 
1322 void osync_member_committed_all(OSyncMember *member, OSyncEngCallback function, void *user_data)
1323 {
1324  osync_trace(TRACE_ENTRY, "%s(%p)", __func__, member);
1325  OSyncChange **changes = NULL;
1326  OSyncContext **contexts = NULL;
1327 
1328  OSyncContext *context = osync_context_new(member);
1329  context->callback_function = function;
1330  context->calldata = user_data;
1331 
1332  GList *pendingchanges = NULL;
1333  GList *pendingcontexts = NULL;
1334 
1335  GList *f;
1336  for (f = member->format_sinks; f; f = f->next) {
1337  OSyncObjFormatSink *fmtsink = f->data;
1338  osync_debug("OSYNC", 2, "Sending changes to sink %p:%s", fmtsink, fmtsink->format ? fmtsink->format->name : "None");
1339 
1340  OSyncFormatFunctions functions = fmtsink->functions;
1341 
1342  if (functions.batch_commit) {
1343  pendingchanges = g_list_concat(pendingchanges, fmtsink->commit_changes);
1344  pendingcontexts = g_list_concat(pendingcontexts, fmtsink->commit_contexts);
1345 
1346  fmtsink->commit_changes = NULL;
1347  fmtsink->commit_contexts = NULL;
1348  }
1349  }
1350 
1351  f = member->format_sinks;
1352  if (f) {
1353  OSyncObjFormatSink *fmtsink = f->data;
1354  osync_debug("OSYNC", 2, "Sending committed all to sink %p:%s", fmtsink, fmtsink->format ? fmtsink->format->name : "None");
1355 
1356  OSyncFormatFunctions functions = fmtsink->functions;
1357 
1358  if (functions.batch_commit) {
1359  int i = 0;
1360  changes = g_malloc0(sizeof(OSyncChange *) * (g_list_length(pendingchanges) + 1));
1361  contexts = g_malloc0(sizeof(OSyncContext *) * (g_list_length(pendingcontexts) + 1));;
1362  GList *o = pendingcontexts;
1363  GList *c = NULL;
1364 
1365  for (c = pendingchanges; c && o; c = c->next) {
1366  OSyncChange *change = c->data;
1367  OSyncContext *context = o->data;
1368 
1369  changes[i] = change;
1370  contexts[i] = context;
1371 
1372  i++;
1373  o = o->next;
1374  }
1375 
1376  g_list_free(pendingchanges);
1377  g_list_free(pendingcontexts);
1378 
1379  functions.batch_commit(context, contexts, changes);
1380 
1381  g_free(changes);
1382  g_free(contexts);
1383  } else if (functions.committed_all) {
1384  functions.committed_all(context);
1385  } else {
1386  osync_context_report_success(context);
1387  }
1388  }
1389 
1390  osync_trace(TRACE_EXIT, "%s", __func__);
1391 }
1392 
1393 void osync_member_set_name(OSyncMember *member, const char *name)
1394 {
1395  g_assert(member);
1396  if (member->name)
1397  g_free(member->name);
1398  member->name = g_strdup(name);
1399 }
1400 
1401 const char *osync_member_get_name(OSyncMember *member)
1402 {
1403  return member->name;
1404 }
1405 
1417 {
1418  osync_trace(TRACE_ENTRY, "%s(%p)", __func__, member);
1419  OSyncContext *context = osync_context_new(member);
1420  OSyncChange *change = osync_change_new();
1421  change->changetype = CHANGE_ADDED;
1422  OSyncObjFormatSink *format_sink;
1423  if (!(format_sink = osync_member_make_random_data(member, change, objtype))) {
1424  osync_trace(TRACE_EXIT_ERROR, "%s: Unable to make random data", __func__);
1425  return NULL;
1426  }
1427 
1428  if (!format_sink->functions.access) {
1429  osync_trace(TRACE_EXIT_ERROR, "%s: No access function", __func__);
1430  return NULL;
1431  }
1432 
1433  if (!format_sink->functions.access(context, change)) {
1434  osync_trace(TRACE_EXIT_ERROR, "%s: Unable to write change", __func__);
1435  return NULL;
1436  }
1437 
1438  osync_trace(TRACE_EXIT, "%s: %p", __func__, change);
1439  return change;
1440 }
1441 
1453 {
1454  osync_trace(TRACE_ENTRY, "%s(%p, %p)", __func__, member, change);
1455  OSyncContext *context = osync_context_new(member);
1456  change->changetype = CHANGE_MODIFIED;
1457  OSyncObjFormatSink *format_sink;
1458  char *uid = g_strdup(osync_change_get_uid(change));
1459 
1460  if (!(format_sink = osync_member_make_random_data(member, change, osync_change_get_objtype(change)->name))) {
1461  osync_trace(TRACE_EXIT_ERROR, "%s: Unable to make random data", __func__);
1462  return FALSE;
1463  }
1464 
1465  osync_change_set_uid(change, uid);
1466 
1467  if (!format_sink->functions.access) {
1468  osync_trace(TRACE_EXIT_ERROR, "%s: No access function", __func__);
1469  return FALSE;
1470  }
1471 
1472  if (!format_sink->functions.access(context, change)) {
1473  osync_trace(TRACE_EXIT_ERROR, "%s: Unable to modify change", __func__);
1474  return FALSE;
1475  }
1476 
1477  osync_trace(TRACE_EXIT, "%s", __func__);
1478  return TRUE;
1479 }
1480 
1492 {
1493  osync_trace(TRACE_ENTRY, "%s(%p, %p)", __func__, member, change);
1494  OSyncContext *context = osync_context_new(member);
1495  change->changetype = CHANGE_DELETED;
1496 
1497  OSyncObjTypeSink *objtype_sink = osync_member_find_objtype_sink(member, osync_change_get_objtype(change)->name);
1498  if (!objtype_sink) {
1499  osync_trace(TRACE_EXIT_ERROR, "%s: Unable to find objsink for %s", __func__, osync_change_get_objtype(change)->name);
1500  return FALSE;
1501  }
1502 
1503  OSyncObjFormat *format = osync_change_get_objformat(change);
1504  OSyncObjFormatSink *format_sink = osync_objtype_find_format_sink(objtype_sink, format->name);
1505  if (!format_sink) {
1506  osync_trace(TRACE_EXIT_ERROR, "%s: Unable to find format sink for %s", __func__, format->name);
1507  return FALSE;
1508  }
1509 
1510  if (format_sink->functions.batch_commit) {
1511  //Append to the stored changes
1512  format_sink->commit_changes = g_list_append(format_sink->commit_changes, change);
1513  format_sink->commit_contexts = g_list_append(format_sink->commit_contexts, context);
1514  osync_trace(TRACE_EXIT, "%s: Waiting for batch processing", __func__);
1515  return TRUE;
1516  } else {
1517  if (!format_sink->functions.access) {
1518  osync_trace(TRACE_EXIT_ERROR, "%s: No access function", __func__);
1519  return FALSE;
1520  }
1521 
1522  if (!format_sink->functions.access(context, change)) {
1523  osync_trace(TRACE_EXIT_ERROR, "%s: Unable to modify change", __func__);
1524  return FALSE;
1525  }
1526  }
1527 
1528  osync_trace(TRACE_EXIT, "%s", __func__);
1529  return TRUE;
1530 }
1531 
1536 void osync_member_write_sink_info(OSyncMember *member, OSyncMessage *message)
1537 {
1538  GList *obj = NULL;
1539  for (osync_member_get_objtype_sinks(member, &obj, NULL); obj; obj = obj->next) {
1540  OSyncObjTypeSink *sink = obj->data;
1541  int slow;
1542  slow = osync_member_get_slow_sync(member, sink->objtype->name);
1543  osync_message_write_string(message, sink->objtype->name);
1544  osync_message_write_int(message, sink->read);
1545  osync_message_write_int(message, sink->write);
1546  osync_message_write_int(message, sink->enabled);
1547  osync_message_write_int(message, slow);
1548  }
1549  osync_message_write_string(message, NULL);
1550 }
1551 
1556 int __sync_member_read_sink_info(OSyncMember *member, OSyncMessage *message)
1557 {
1558  char *objtypestr;
1559  int r = 0;
1560  for (;;) {
1561  int read, write, enabled, slow;
1562  osync_message_read_string(message, &objtypestr);
1563  if (!objtypestr)
1564  break;
1565 
1566  osync_message_read_int(message, &read);
1567  osync_message_read_int(message, &write);
1568  osync_message_read_int(message, &enabled);
1569  osync_message_read_int(message, &slow);
1570 
1571  OSyncObjTypeSink *sink = osync_member_find_objtype_sink(member, objtypestr);
1572  if (!sink)
1573  continue;
1574 
1575  sink->read = read;
1576  sink->write = write;
1577  sink->enabled = enabled;
1578 
1579  if (slow) {
1580  osync_member_set_slow_sync(member, objtypestr, TRUE);
1581  r++;
1582  }
1583 
1584  free(objtypestr);
1585  }
1586  return r;
1587 }
1588 
1589 
1603 void osync_member_read_sink_info_full(OSyncMember *member, OSyncMessage *message)
1604 {
1605  osync_group_reset_slow_sync(member->group, "data");
1606  __sync_member_read_sink_info(member, message);
1607 }
1608 
1621 void osync_member_read_sink_info(OSyncMember *member, OSyncMessage *message)
1622 {
1623  int set_for_any;
1624 
1625  set_for_any = __sync_member_read_sink_info(member, message);
1626 
1627  if (set_for_any) {
1628  /* FIXME: We must force slow-sync in "data" when some
1629  * objtype is marked to slow-sync
1630  *
1631  * (See ticket #1011)
1632  */
1633  osync_member_set_slow_sync(member, "data", TRUE);
1634  }
1635 }
1636