OpenSync  0.22
opensync_plugin.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 
24 
32 
33 #ifndef DOXYGEN_SHOULD_SKIP_THIS
34 OSyncObjTypeSink *osync_objtype_sink_from_template(OSyncGroup *group, OSyncObjTypeTemplate *template)
35 {
36  g_assert(group);
37  g_assert(template);
38  OSyncObjTypeSink *sink = g_malloc0(sizeof(OSyncObjTypeSink));
39  OSyncObjType *type = osync_conv_find_objtype(group->conv_env, template->name);
40  if (!type) {
41  osync_debug("OSYNC", 0, "Unable to find objtype named %s to create objtype sink", template->name);
42  return NULL;
43  }
44  sink->objtype = type;
45  sink->enabled = TRUE;
46  sink->write = TRUE;
47  sink->read = TRUE;
48  return sink;
49 }
50 
51 OSyncObjFormatSink *osync_objformat_sink_from_template(OSyncGroup *group, OSyncObjFormatTemplate *template)
52 {
53  OSyncObjFormatSink *sink = g_malloc0(sizeof(OSyncObjFormatSink));
54  OSyncObjFormat *format = osync_conv_find_objformat(group->conv_env, template->name);
55  if (!format)
56  return NULL;
57  sink->format = format;
58  sink->functions.commit_change = template->commit_change;
59  sink->functions.access = template->access;
60  sink->functions.read = template->read;
61  sink->functions.committed_all = template->committed_all;
62  sink->functions.batch_commit = template->batch_commit;
63  sink->extension_name = g_strdup(template->extension_name);
64  return sink;
65 }
66 
67 OSyncObjTypeTemplate *osync_plugin_find_objtype_template(OSyncPlugin *plugin, const char *objtypestr)
68 {
69  GList *o;
70  for (o = plugin->accepted_objtypes; o; o = o->next) {
71  OSyncObjTypeTemplate *template = o->data;
72  if (!strcmp(template->name, objtypestr))
73  return template;
74  }
75  return NULL;
76 }
77 
78 OSyncObjFormatTemplate *osync_plugin_find_objformat_template(OSyncObjTypeTemplate *type_template, const char *objformatstr)
79 {
80  GList *f;
81  for (f = type_template->formats; f; f = f->next) {
82  OSyncObjFormatTemplate *template = f->data;
83  if (!strcmp(template->name, objformatstr))
84  return template;
85  }
86  return NULL;
87 }
88 
89 OSyncObjFormatSink *osync_objtype_find_format_sink(OSyncObjTypeSink *sink, const char *formatstr)
90 {
91  GList *f;
92  for (f = sink->formatsinks; f; f = f->next) {
93  OSyncObjFormatSink *sink = f->data;
94  if (!strcmp(sink->format->name, formatstr))
95  return sink;
96  }
97  return NULL;
98 }
99 
100 void _osync_format_set_commit(OSyncObjTypeTemplate *template, const char *formatstr, OSyncFormatCommitFn commit_change)
101 {
102  OSyncObjFormatTemplate *format_template = NULL;
103  if (formatstr) {
104  OSyncObjFormatTemplate *format_template = osync_plugin_find_objformat_template(template, formatstr);
105  osync_assert_msg(format_template, "Unable to set commit function. Did you forget to add the objformat?");
106  format_template->commit_change = commit_change;
107  } else {
108  GList *f = NULL;
109  for (f = template->formats; f; f = f->next) {
110  format_template = f->data;
111  format_template->commit_change = commit_change;
112  }
113  }
114 }
115 
116 void _osync_format_set_access(OSyncObjTypeTemplate *template, const char *formatstr, OSyncFormatAccessFn access)
117 {
118  OSyncObjFormatTemplate *format_template = NULL;
119  if (formatstr) {
120  format_template = osync_plugin_find_objformat_template(template, formatstr);
121  osync_assert_msg(format_template, "Unable to set commit function. Did you forget to add the objformat?");
122  format_template->access = access;
123  } else {
124  GList *f = NULL;
125  for (f = template->formats; f; f = f->next) {
126  format_template = f->data;
127  format_template->access = access;
128  }
129  }
130 }
131 
132 void _osync_format_set_batch(OSyncObjTypeTemplate *template, const char *formatstr, OSyncFormatBatchCommitFn batch)
133 {
134  OSyncObjFormatTemplate *format_template = NULL;
135  if (formatstr) {
136  format_template = osync_plugin_find_objformat_template(template, formatstr);
137  osync_assert_msg(format_template, "Unable to set batch commit function. Did you forget to add the objformat?");
138  format_template->batch_commit = batch;
139  } else {
140  GList *f = NULL;
141  for (f = template->formats; f; f = f->next) {
142  format_template = f->data;
143  format_template->batch_commit = batch;
144  }
145  }
146 }
147 #endif
148 
158 
168 {
169  OSyncPlugin *plugin = g_malloc0(sizeof(OSyncPlugin));
170  g_assert(plugin);
171  memset(&(plugin->info), 0, sizeof(plugin->info));
172  memset(&(plugin->info.functions), 0, sizeof(plugin->info.functions));
173  memset(&(plugin->info.timeouts), 0, sizeof(plugin->info.timeouts));
174 
175  //Set the default timeouts;
176  plugin->info.timeouts.connect_timeout = 60;
177  plugin->info.timeouts.sync_done_timeout = 60;
178  plugin->info.timeouts.disconnect_timeout = 60;
179  plugin->info.timeouts.get_changeinfo_timeout = 60;
180  plugin->info.timeouts.get_data_timeout = 60;
181  plugin->info.timeouts.commit_timeout = 60;
182  plugin->info.timeouts.read_change_timeout = 60;
183 
184  plugin->info.plugin = plugin;
185  plugin->info.config_type = NEEDS_CONFIGURATION;
186 
187  if (env) {
188  env->plugins = g_list_append(env->plugins, plugin);
189  plugin->env = env;
190  plugin->real_plugin = env->current_module;
191  }
192 
193  return plugin;
194 }
195 
196 
206 {
207  OSyncPlugin *plg = osync_plugin_new(env);
208  osync_trace(TRACE_INTERNAL, "%s(%p): %p", __func__, env, plg);
209  if (!plg)
210  return NULL;
211 
212  return &plg->info;
213 }
214 
223 {
224  osync_trace(TRACE_INTERNAL, "osync_plugin_free(%p)", plugin);
225  g_assert(plugin);
226  if (plugin->env)
227  plugin->env->plugins = g_list_remove(plugin->env->plugins, plugin);
228 
229  //FIXME Free more stuff?
230  g_free(plugin);
231 }
232 
243 void *osync_plugin_get_function(OSyncPlugin *plugin, const char *name, OSyncError **error)
244 {
245  void *function;
246  if (!plugin->real_plugin) {
247  osync_debug("OSPLG", 1, "You need to load a plugin before getting a function");
248  osync_error_set(error, OSYNC_ERROR_MISCONFIGURATION, "You need to load a plugin before getting a function");
249  return NULL;
250  }
251 
252  if (!g_module_symbol (plugin->real_plugin, name, &function)) {
253  osync_debug("OSPLG", 0, "Unable to locate symbol %s on plugin", name);
254  osync_error_set(error, OSYNC_ERROR_PARAMETER, "Unable to locate symbol %s: %s", name, g_module_error());
255  return NULL;
256  }
257  return function;
258 }
259 
270 osync_bool osync_module_load(OSyncEnv *env, const char *path, OSyncError **error)
271 {
272  osync_trace(TRACE_ENTRY, "%s(%p, %s, %p)", __func__, env, path, error);
273  /* Check if this platform supports dynamic
274  * loading of modules */
275 
276  if (!g_module_supported()) {
277  osync_error_set(error, OSYNC_ERROR_GENERIC, "This platform does not support loading of modules");
278  osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
279  return FALSE;
280  }
281 
282  /* Try to open the module or fail if an error occurs */
283  GModule *module = g_module_open(path, 0);
284  if (!module) {
285  osync_error_set(error, OSYNC_ERROR_GENERIC, "Unable to open module %s: %s", path, g_module_error());
286  osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
287  return FALSE;
288  }
289 
290  /* Load the get_info symbol */
291  void (* fct_info)(OSyncEnv *env) = NULL;
292  void (** fct_infop)(OSyncEnv *env) = &fct_info;
293  if (!g_module_symbol(module, "get_info", (void **)fct_infop)) {
294  /* If there is no get_info symbol, the file must be a implementation library
295  * for one of the other modules. So dont throw an error error since it has been
296  * confusing users */
297  osync_trace(TRACE_EXIT, "%s: Not loading implementation library", __func__);
298  return TRUE;
299  }
300  env->modules = g_list_append(env->modules, module);
301 
302  /* Call the get_info function */
303  env->current_module = module;
304  fct_info(env);
305  env->current_module = NULL;
306 
307  osync_trace(TRACE_EXIT, "%s: %p", __func__, module);
308  return TRUE;
309 }
310 
317 void osync_module_unload(OSyncEnv *env, GModule *module)
318 {
319  osync_trace(TRACE_INTERNAL, "%s(%p, %p)", __func__, env, module);
320  //FIXME Close the module! This crashes the evo2 plugin at the moment, i have no idea why...
321  //g_module_close(plugin->real_plugin);
322  env->modules = g_list_remove(env->modules, module);
323 }
324 
336 osync_bool osync_module_load_dir(OSyncEnv *env, const char *path, osync_bool must_exist, OSyncError **error)
337 {
338  osync_trace(TRACE_ENTRY, "%s(%p, %s, %p)", __func__, env, path, error);
339  GDir *dir;
340  GError *gerror = NULL;
341  char *filename = NULL;
342 
343  if (!path) {
344  osync_error_set(error, OSYNC_ERROR_GENERIC, "Not path given to load the modules from");
345  osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
346  return FALSE;
347  }
348 
349  //Load all available shared libraries (plugins)
350  if (!g_file_test(path, G_FILE_TEST_IS_DIR)) {
351  if (must_exist) {
352  osync_error_set(error, OSYNC_ERROR_GENERIC, "Path is not loadable");
353  osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
354  return FALSE;
355  } else {
356  osync_trace(TRACE_EXIT, "%s: Directory does not exist (non-fatal)", __func__);
357  return TRUE;
358  }
359  }
360 
361  dir = g_dir_open(path, 0, &gerror);
362  if (!dir) {
363  osync_error_set(error, OSYNC_ERROR_IO_ERROR, "Unable to open directory %s: %s", path, gerror->message);
364  g_error_free(gerror);
365  osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
366  return FALSE;
367  }
368 
369  const gchar *de = NULL;
370  while ((de = g_dir_read_name(dir))) {
371  filename = g_strdup_printf ("%s/%s", path, de);
372 
373  if (!g_file_test(filename, G_FILE_TEST_IS_REGULAR) || g_file_test(filename, G_FILE_TEST_IS_SYMLINK) || !g_pattern_match_simple("*.so", filename)) {
374  g_free(filename);
375  continue;
376  }
377 
378  OSyncError *error = NULL;
379  if (!osync_module_load(env, filename, &error)) {
380  osync_debug("OSPLG", 0, "Unable to load plugin %s: %s", filename, error->message);
381  osync_error_free(&error);
382  }
383  g_free(filename);
384  }
385  g_dir_close(dir);
386 
387  osync_trace(TRACE_EXIT, "%s", __func__);
388  return TRUE;
389 }
390 
397 const char *osync_plugin_get_name(OSyncPlugin *plugin)
398 {
399  g_assert(plugin);
400  return plugin->info.name;
401 }
402 
410 {
411  g_assert(plugin);
412  return plugin->info.longname;
413 }
414 
422 {
423  g_assert(plugin);
424  return plugin->info.description;
425 }
426 
434 {
435  g_assert(plugin);
436  return plugin->info.timeouts;
437 }
438 
445 {
446  g_assert(plugin);
447  return plugin->info.plugin_data;
448 }
449 
455 const char *osync_plugin_get_path(OSyncPlugin *plugin)
456 {
457  g_assert(plugin);
458  return g_module_name(plugin->real_plugin);
459 }
460 
469 void osync_plugin_set_commit_objformat(OSyncPluginInfo *info, const char *objtypestr, const char *formatstr, OSyncFormatCommitFn commit_change)
470 {
471  OSyncObjTypeTemplate *template = NULL;
472 
473  if (objtypestr) {
474  OSyncObjTypeTemplate *template = osync_plugin_find_objtype_template(info->plugin, objtypestr);
475  osync_assert_msg(template, "Unable to accept objformat. Did you forget to add the objtype?");
476  _osync_format_set_commit(template, formatstr, commit_change);
477  } else {
478  GList *o = NULL;
479  for (o = info->plugin->accepted_objtypes; o; o = o->next) {
480  template = o->data;
481  _osync_format_set_commit(template, formatstr, commit_change);
482  }
483  }
484 }
485 
494 void osync_plugin_set_access_objformat(OSyncPluginInfo *info, const char *objtypestr, const char *formatstr, OSyncFormatAccessFn access)
495 {
496  OSyncObjTypeTemplate *template = NULL;
497 
498  if (objtypestr) {
499  //template = osync_plugin_find_objtype_template(info->plugin, objtypestr);
500  //osync_assert_msg(template, "Unable to accept objformat. Did you forget to add the objtype?");
501  //_osync_format_set_access(template, formatstr, access);
502  } else {
503  GList *o = NULL;
504  for (o = info->plugin->accepted_objtypes; o; o = o->next) {
505  template = o->data;
506  _osync_format_set_access(template, formatstr, access);
507  }
508  }
509 }
510 
519 void osync_plugin_set_read_objformat(OSyncPluginInfo *info, const char *objtypestr, const char *formatstr, OSyncFormatReadFn read)
520 {
521  OSyncObjTypeTemplate *template = osync_plugin_find_objtype_template(info->plugin, objtypestr);
522  osync_assert_msg(template, "Unable to accept objformat. Did you forget to add the objtype?");
523  OSyncObjFormatTemplate *format_template = osync_plugin_find_objformat_template(template, formatstr);
524  osync_assert_msg(format_template, "Unable to set commit function. Did you forget to add the objformat?");
525  format_template->read = read;
526 }
527 
536 void osync_plugin_set_batch_commit_objformat(OSyncPluginInfo *info, const char *objtypestr, const char *formatstr, OSyncFormatBatchCommitFn batch)
537 {
538  OSyncObjTypeTemplate *template = NULL;
539 
540  if (objtypestr) {
541  template = osync_plugin_find_objtype_template(info->plugin, objtypestr);
542  osync_assert_msg(template, "Unable to accept objformat. Did you forget to add the objtype?");
543  _osync_format_set_batch(template, formatstr, batch);
544  } else {
545  GList *o = NULL;
546  for (o = info->plugin->accepted_objtypes; o; o = o->next) {
547  template = o->data;
548  _osync_format_set_batch(template, formatstr, batch);
549  }
550  }
551 }
552 
561 void osync_plugin_set_committed_all_objformat(OSyncPluginInfo *info, const char *objtypestr, const char *formatstr, OSyncFormatCommittedAllFn committed_all)
562 {
563  OSyncObjTypeTemplate *template = osync_plugin_find_objtype_template(info->plugin, objtypestr);
564  osync_assert_msg(template, "Unable to accept objformat. Did you forget to add the objtype?");
565  OSyncObjFormatTemplate *format_template = osync_plugin_find_objformat_template(template, formatstr);
566  osync_assert_msg(format_template, "Unable to set committed_all function. Did you forget to add the objformat?");
567  format_template->committed_all = committed_all;
568 }
569 
579 void osync_plugin_accept_objtype(OSyncPluginInfo *info, const char *objtypestr)
580 {
581  OSyncObjTypeTemplate *template = g_malloc0(sizeof(OSyncObjTypeTemplate));
582  template->name = g_strdup(objtypestr);
583  info->plugin->accepted_objtypes = g_list_append(info->plugin->accepted_objtypes, template);
584 }
585 
597 void osync_plugin_accept_objformat(OSyncPluginInfo *info, const char *objtypestr, const char *formatstr, const char *extension)
598 {
599  OSyncObjTypeTemplate *template = osync_plugin_find_objtype_template(info->plugin, objtypestr);
600  osync_assert_msg(template, "Unable to accept objformat. Did you forget to add the objtype?");
601  OSyncObjFormatTemplate *format_template = g_malloc0(sizeof(OSyncObjFormatTemplate));
602  format_template->name = g_strdup(formatstr);
603  if (extension)
604  format_template->extension_name = g_strdup(extension);
605  template->formats = g_list_append(template->formats, format_template);
606 }
607 
void osync_plugin_free(OSyncPlugin *plugin)
Used to free a plugin.
void osync_plugin_set_access_objformat(OSyncPluginInfo *info, const char *objtypestr, const char *formatstr, OSyncFormatAccessFn access)
Sets the access function of a format.
OSyncPluginTimeouts osync_plugin_get_timeouts(OSyncPlugin *plugin)
Returns the timeouts of the plugin.
void osync_module_unload(OSyncEnv *env, GModule *module)
Closes a module.
Represent an error.
OSyncPluginInfo * osync_plugin_new_info(OSyncEnv *env)
Registers a new plugin.
OSyncObjFormat * osync_conv_find_objformat(OSyncFormatEnv *env, const char *name)
Finds the object format with the given name.
osync_bool osync_module_load(OSyncEnv *env, const char *path, OSyncError **error)
dlopen()s a format plugin
void osync_plugin_set_commit_objformat(OSyncPluginInfo *info, const char *objtypestr, const char *formatstr, OSyncFormatCommitFn commit_change)
Sets the commit function of a format.
OSyncPlugin * osync_plugin_new(OSyncEnv *env)
This will create a new plugin struct.
Represent a synchronzation plugin.
OSyncPlugin * plugin
Represent a group of members that should be synchronized.
void * osync_plugin_get_function(OSyncPlugin *plugin, const char *name, OSyncError **error)
Used to look up a symbol on the plugin.
void osync_plugin_accept_objtype(OSyncPluginInfo *info, const char *objtypestr)
Tells opensync that the plugin can accepts this object.
void * osync_plugin_get_plugin_data(OSyncPlugin *plugin)
Returns the plugin_info data, set by the plugin.
void osync_error_free(OSyncError **error)
Frees the error so it can be reused.
void osync_plugin_set_committed_all_objformat(OSyncPluginInfo *info, const char *objtypestr, const char *formatstr, OSyncFormatCommittedAllFn committed_all)
Sets the committed_all function of a format.
const char * osync_plugin_get_name(OSyncPlugin *plugin)
Returns the name of the loaded plugin.
osync_bool osync_module_load_dir(OSyncEnv *env, const char *path, osync_bool must_exist, OSyncError **error)
Loads the modules from a given directory.
OSyncObjType * osync_conv_find_objtype(OSyncFormatEnv *env, const char *name)
Finds the object type with the given name.
void osync_plugin_set_read_objformat(OSyncPluginInfo *info, const char *objtypestr, const char *formatstr, OSyncFormatReadFn read)
Sets the read function of a format.
void osync_debug(const char *subpart, int level, const char *message,...)
Used for debugging.
Gives information about a plugin.
const char * osync_plugin_get_description(OSyncPlugin *plugin)
Returns the description of the plugin.
const char * osync_plugin_get_path(OSyncPlugin *plugin)
Get full path for plugin module.
void osync_plugin_accept_objformat(OSyncPluginInfo *info, const char *objtypestr, const char *formatstr, const char *extension)
Tells opensync that the plugin can accepts this format for the given object.
void osync_error_set(OSyncError **error, OSyncErrorType type, const char *format,...)
Sets the error.
const char * osync_error_print(OSyncError **error)
Returns the message of the error.
void osync_trace(OSyncTraceType type, const char *message,...)
Used for tracing the application.
void osync_plugin_set_batch_commit_objformat(OSyncPluginInfo *info, const char *objtypestr, const char *formatstr, OSyncFormatBatchCommitFn batch)
Sets the batch_commit function of a format.
Represent a abstract object type (like "contact")
Represent a format for a object type.
The timeouts for the asynchronous functions of a plugin.
const char * osync_plugin_get_longname(OSyncPlugin *plugin)
Returns the long name of the loaded plugin.