OpenSync 0.22

opensync/opensync_plugin.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 
00024 
00032 
00033 #ifndef DOXYGEN_SHOULD_SKIP_THIS
00034 OSyncObjTypeSink *osync_objtype_sink_from_template(OSyncGroup *group, OSyncObjTypeTemplate *template)
00035 {
00036         g_assert(group);
00037         g_assert(template);
00038         OSyncObjTypeSink *sink = g_malloc0(sizeof(OSyncObjTypeSink));
00039         OSyncObjType *type = osync_conv_find_objtype(group->conv_env, template->name);
00040         if (!type) {
00041                 osync_debug("OSYNC", 0, "Unable to find objtype named %s to create objtype sink", template->name);
00042                 return NULL;
00043         }
00044         sink->objtype = type;
00045         sink->enabled = TRUE;
00046         sink->write = TRUE;
00047         sink->read = TRUE;
00048         return sink;
00049 }
00050 
00051 OSyncObjFormatSink *osync_objformat_sink_from_template(OSyncGroup *group, OSyncObjFormatTemplate *template)
00052 {
00053         OSyncObjFormatSink *sink = g_malloc0(sizeof(OSyncObjFormatSink));
00054         OSyncObjFormat *format = osync_conv_find_objformat(group->conv_env, template->name);
00055         if (!format)
00056                 return NULL;
00057         sink->format = format;
00058         sink->functions.commit_change = template->commit_change;
00059         sink->functions.access = template->access;
00060         sink->functions.read = template->read;
00061         sink->functions.committed_all = template->committed_all;
00062         sink->functions.batch_commit = template->batch_commit;
00063         sink->extension_name = g_strdup(template->extension_name);
00064         return sink;
00065 }
00066 
00067 OSyncObjTypeTemplate *osync_plugin_find_objtype_template(OSyncPlugin *plugin, const char *objtypestr)
00068 {
00069         GList *o;
00070         for (o = plugin->accepted_objtypes; o; o = o->next) {
00071                 OSyncObjTypeTemplate *template = o->data;
00072                 if (!strcmp(template->name, objtypestr))
00073                         return template;
00074         }
00075         return NULL;
00076 }
00077 
00078 OSyncObjFormatTemplate *osync_plugin_find_objformat_template(OSyncObjTypeTemplate *type_template, const char *objformatstr)
00079 {
00080         GList *f;
00081         for (f = type_template->formats; f; f = f->next) {
00082                 OSyncObjFormatTemplate *template = f->data;
00083                 if (!strcmp(template->name, objformatstr))
00084                         return template;
00085         }
00086         return NULL;
00087 }
00088 
00089 OSyncObjFormatSink *osync_objtype_find_format_sink(OSyncObjTypeSink *sink, const char *formatstr)
00090 {
00091         GList *f;
00092         for (f = sink->formatsinks; f; f = f->next) {
00093                 OSyncObjFormatSink *sink = f->data;
00094                 if (!strcmp(sink->format->name, formatstr))
00095                         return sink;
00096         }
00097         return NULL;
00098 }
00099 
00100 void _osync_format_set_commit(OSyncObjTypeTemplate *template, const char *formatstr, OSyncFormatCommitFn commit_change)
00101 {
00102         OSyncObjFormatTemplate *format_template = NULL;
00103         if (formatstr) {
00104                 OSyncObjFormatTemplate *format_template = osync_plugin_find_objformat_template(template, formatstr);
00105                 osync_assert_msg(format_template, "Unable to set commit function. Did you forget to add the objformat?");
00106                 format_template->commit_change = commit_change;
00107         } else {
00108                 GList *f = NULL;
00109                 for (f = template->formats; f; f = f->next) {
00110                         format_template = f->data;
00111                         format_template->commit_change = commit_change;
00112                 }
00113         }
00114 }
00115 
00116 void _osync_format_set_access(OSyncObjTypeTemplate *template, const char *formatstr, OSyncFormatAccessFn access)
00117 {
00118         OSyncObjFormatTemplate *format_template = NULL;
00119         if (formatstr) {
00120                 format_template = osync_plugin_find_objformat_template(template, formatstr);
00121                 osync_assert_msg(format_template, "Unable to set commit function. Did you forget to add the objformat?");
00122                 format_template->access = access;
00123         } else {
00124                 GList *f = NULL;
00125                 for (f = template->formats; f; f = f->next) {
00126                         format_template = f->data;
00127                         format_template->access = access;
00128                 }
00129         }
00130 }
00131 
00132 void _osync_format_set_batch(OSyncObjTypeTemplate *template, const char *formatstr, OSyncFormatBatchCommitFn batch)
00133 {
00134         OSyncObjFormatTemplate *format_template = NULL;
00135         if (formatstr) {
00136                 format_template = osync_plugin_find_objformat_template(template, formatstr);
00137                 osync_assert_msg(format_template, "Unable to set batch commit function. Did you forget to add the objformat?");
00138                 format_template->batch_commit = batch;
00139         } else {
00140                 GList *f = NULL;
00141                 for (f = template->formats; f; f = f->next) {
00142                         format_template = f->data;
00143                         format_template->batch_commit = batch;
00144                 }
00145         }
00146 }
00147 #endif
00148 
00158 
00167 OSyncPlugin *osync_plugin_new(OSyncEnv *env)
00168 {
00169         OSyncPlugin *plugin = g_malloc0(sizeof(OSyncPlugin));
00170         g_assert(plugin);
00171         memset(&(plugin->info), 0, sizeof(plugin->info));
00172         memset(&(plugin->info.functions), 0, sizeof(plugin->info.functions));
00173         memset(&(plugin->info.timeouts), 0, sizeof(plugin->info.timeouts));
00174         
00175         //Set the default timeouts;
00176         plugin->info.timeouts.connect_timeout = 60;
00177         plugin->info.timeouts.sync_done_timeout = 60;
00178         plugin->info.timeouts.disconnect_timeout = 60;
00179         plugin->info.timeouts.get_changeinfo_timeout = 60;
00180         plugin->info.timeouts.get_data_timeout = 60;
00181         plugin->info.timeouts.commit_timeout = 60;
00182         plugin->info.timeouts.read_change_timeout = 60;
00183         
00184         plugin->info.plugin = plugin;
00185         plugin->info.config_type = NEEDS_CONFIGURATION;
00186         
00187         if (env) {
00188                 env->plugins = g_list_append(env->plugins, plugin);
00189                 plugin->env = env;
00190                 plugin->real_plugin = env->current_module;
00191         }
00192         
00193         return plugin;
00194 }
00195 
00196 
00205 OSyncPluginInfo *osync_plugin_new_info(OSyncEnv *env)
00206 {
00207         OSyncPlugin *plg = osync_plugin_new(env);
00208         osync_trace(TRACE_INTERNAL, "%s(%p): %p", __func__, env, plg);
00209         if (!plg)
00210                 return NULL;
00211 
00212         return &plg->info;
00213 }
00214 
00222 void osync_plugin_free(OSyncPlugin *plugin)
00223 {
00224         osync_trace(TRACE_INTERNAL, "osync_plugin_free(%p)", plugin);
00225         g_assert(plugin);
00226         if (plugin->env)
00227                 plugin->env->plugins = g_list_remove(plugin->env->plugins, plugin);
00228 
00229         //FIXME Free more stuff?
00230         g_free(plugin);
00231 }
00232 
00243 void *osync_plugin_get_function(OSyncPlugin *plugin, const char *name, OSyncError **error)
00244 {
00245         void *function;
00246         if (!plugin->real_plugin) {
00247                 osync_debug("OSPLG", 1, "You need to load a plugin before getting a function");
00248                 osync_error_set(error, OSYNC_ERROR_MISCONFIGURATION, "You need to load a plugin before getting a function");
00249                 return NULL;
00250         }
00251         
00252         if (!g_module_symbol (plugin->real_plugin, name, &function)) {
00253                 osync_debug("OSPLG", 0, "Unable to locate symbol %s on plugin", name);
00254                 osync_error_set(error, OSYNC_ERROR_PARAMETER, "Unable to locate symbol %s: %s", name, g_module_error());
00255                 return NULL;
00256         }
00257         return function;
00258 }
00259 
00270 osync_bool osync_module_load(OSyncEnv *env, const char *path, OSyncError **error)
00271 {
00272         osync_trace(TRACE_ENTRY, "%s(%p, %s, %p)", __func__, env, path, error);
00273         /* Check if this platform supports dynamic
00274          * loading of modules */
00275          
00276         if (!g_module_supported()) {
00277                 osync_error_set(error, OSYNC_ERROR_GENERIC, "This platform does not support loading of modules");
00278                 osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
00279                 return FALSE;
00280         }
00281 
00282         /* Try to open the module or fail if an error occurs */
00283         GModule *module = g_module_open(path, 0);
00284         if (!module) {
00285                 osync_error_set(error, OSYNC_ERROR_GENERIC, "Unable to open module %s: %s", path, g_module_error());
00286                 osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
00287                 return FALSE;
00288         }
00289         
00290         /* Load the get_info symbol */
00291         void (* fct_info)(OSyncEnv *env) = NULL;
00292         void (** fct_infop)(OSyncEnv *env) = &fct_info;
00293         if (!g_module_symbol(module, "get_info", (void **)fct_infop)) {
00294                 /* If there is no get_info symbol, the file must be a implementation library
00295                  * for one of the other modules. So dont throw an error error since it has been
00296                  * confusing users */
00297                 osync_trace(TRACE_EXIT, "%s: Not loading implementation library", __func__);
00298                 return TRUE;
00299         }
00300         env->modules = g_list_append(env->modules, module);
00301         
00302         /* Call the get_info function */
00303         env->current_module = module;
00304         fct_info(env);
00305         env->current_module = NULL;
00306         
00307         osync_trace(TRACE_EXIT, "%s: %p", __func__, module);
00308         return TRUE;
00309 }
00310 
00317 void osync_module_unload(OSyncEnv *env, GModule *module)
00318 {
00319         osync_trace(TRACE_INTERNAL, "%s(%p, %p)", __func__, env, module);
00320         //FIXME Close the module! This crashes the evo2 plugin at the moment, i have no idea why...
00321         //g_module_close(plugin->real_plugin);
00322         env->modules = g_list_remove(env->modules, module);
00323 }
00324 
00336 osync_bool osync_module_load_dir(OSyncEnv *env, const char *path, osync_bool must_exist, OSyncError **error)
00337 {
00338         osync_trace(TRACE_ENTRY, "%s(%p, %s, %p)", __func__, env, path, error);
00339         GDir *dir;
00340         GError *gerror = NULL;
00341         char *filename = NULL;
00342 
00343         if (!path) {
00344                 osync_error_set(error, OSYNC_ERROR_GENERIC, "Not path given to load the modules from");
00345                 osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
00346                 return FALSE;
00347         }
00348         
00349         //Load all available shared libraries (plugins)
00350         if (!g_file_test(path, G_FILE_TEST_IS_DIR)) {
00351                 if (must_exist) {
00352                         osync_error_set(error, OSYNC_ERROR_GENERIC, "Path is not loadable");
00353                         osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
00354                         return FALSE;
00355                 } else {
00356                         osync_trace(TRACE_EXIT, "%s: Directory does not exist (non-fatal)", __func__);
00357                         return TRUE;
00358                 }
00359         }
00360         
00361         dir = g_dir_open(path, 0, &gerror);
00362         if (!dir) {
00363                 osync_error_set(error, OSYNC_ERROR_IO_ERROR, "Unable to open directory %s: %s", path, gerror->message);
00364                 g_error_free(gerror);
00365                 osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
00366                 return FALSE;
00367         }
00368   
00369         const gchar *de = NULL;
00370         while ((de = g_dir_read_name(dir))) {
00371                 filename = g_strdup_printf ("%s/%s", path, de);
00372                 
00373                 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)) {
00374                         g_free(filename);
00375                         continue;
00376                 }
00377                 
00378                 OSyncError *error = NULL;
00379                 if (!osync_module_load(env, filename, &error)) {
00380                         osync_debug("OSPLG", 0, "Unable to load plugin %s: %s", filename, error->message);
00381                         osync_error_free(&error);
00382                 }
00383                 g_free(filename);
00384         }
00385         g_dir_close(dir);
00386         
00387         osync_trace(TRACE_EXIT, "%s", __func__);
00388         return TRUE;
00389 }
00390 
00397 const char *osync_plugin_get_name(OSyncPlugin *plugin)
00398 {
00399         g_assert(plugin);
00400         return plugin->info.name;
00401 }
00402 
00409 const char *osync_plugin_get_longname(OSyncPlugin *plugin)
00410 {
00411         g_assert(plugin);
00412         return plugin->info.longname;
00413 }
00414 
00421 const char *osync_plugin_get_description(OSyncPlugin *plugin)
00422 {
00423         g_assert(plugin);
00424         return plugin->info.description;
00425 }
00426 
00433 OSyncPluginTimeouts osync_plugin_get_timeouts(OSyncPlugin *plugin)
00434 {
00435         g_assert(plugin);
00436         return plugin->info.timeouts;
00437 }
00438 
00444 void *osync_plugin_get_plugin_data(OSyncPlugin *plugin)
00445 {
00446         g_assert(plugin);
00447         return plugin->info.plugin_data;
00448 }
00449 
00455 const char *osync_plugin_get_path(OSyncPlugin *plugin)
00456 {
00457         g_assert(plugin);
00458         return g_module_name(plugin->real_plugin);
00459 }
00460 
00469 void osync_plugin_set_commit_objformat(OSyncPluginInfo *info, const char *objtypestr, const char *formatstr, OSyncFormatCommitFn commit_change)
00470 {
00471         OSyncObjTypeTemplate *template = NULL;
00472         
00473         if (objtypestr) {
00474                 OSyncObjTypeTemplate *template = osync_plugin_find_objtype_template(info->plugin, objtypestr);
00475                 osync_assert_msg(template, "Unable to accept objformat. Did you forget to add the objtype?");
00476                 _osync_format_set_commit(template, formatstr, commit_change);
00477         } else {
00478                 GList *o = NULL;
00479                 for (o = info->plugin->accepted_objtypes; o; o = o->next) {
00480                         template = o->data;
00481                         _osync_format_set_commit(template, formatstr, commit_change);
00482                 }
00483         }
00484 }
00485 
00494 void osync_plugin_set_access_objformat(OSyncPluginInfo *info, const char *objtypestr, const char *formatstr, OSyncFormatAccessFn access)
00495 {
00496         OSyncObjTypeTemplate *template = NULL;
00497         
00498         if (objtypestr) {
00499                 //template = osync_plugin_find_objtype_template(info->plugin, objtypestr);
00500                 //osync_assert_msg(template, "Unable to accept objformat. Did you forget to add the objtype?");
00501                 //_osync_format_set_access(template, formatstr, access);
00502         } else {
00503                 GList *o = NULL;
00504                 for (o = info->plugin->accepted_objtypes; o; o = o->next) {
00505                         template = o->data;
00506                         _osync_format_set_access(template, formatstr, access);
00507                 }
00508         }
00509 }
00510 
00519 void osync_plugin_set_read_objformat(OSyncPluginInfo *info, const char *objtypestr, const char *formatstr, OSyncFormatReadFn read)
00520 {
00521         OSyncObjTypeTemplate *template = osync_plugin_find_objtype_template(info->plugin, objtypestr);
00522         osync_assert_msg(template, "Unable to accept objformat. Did you forget to add the objtype?");
00523         OSyncObjFormatTemplate *format_template = osync_plugin_find_objformat_template(template, formatstr);
00524         osync_assert_msg(format_template, "Unable to set commit function. Did you forget to add the objformat?");
00525         format_template->read = read;
00526 }
00527 
00536 void osync_plugin_set_batch_commit_objformat(OSyncPluginInfo *info, const char *objtypestr, const char *formatstr, OSyncFormatBatchCommitFn batch)
00537 {
00538         OSyncObjTypeTemplate *template = NULL;
00539         
00540         if (objtypestr) {
00541                 template = osync_plugin_find_objtype_template(info->plugin, objtypestr);
00542                 osync_assert_msg(template, "Unable to accept objformat. Did you forget to add the objtype?");
00543                 _osync_format_set_batch(template, formatstr, batch);
00544         } else {
00545                 GList *o = NULL;
00546                 for (o = info->plugin->accepted_objtypes; o; o = o->next) {
00547                         template = o->data;
00548                         _osync_format_set_batch(template, formatstr, batch);
00549                 }
00550         }
00551 }
00552 
00561 void osync_plugin_set_committed_all_objformat(OSyncPluginInfo *info, const char *objtypestr, const char *formatstr, OSyncFormatCommittedAllFn committed_all)
00562 {
00563         OSyncObjTypeTemplate *template = osync_plugin_find_objtype_template(info->plugin, objtypestr);
00564         osync_assert_msg(template, "Unable to accept objformat. Did you forget to add the objtype?");
00565         OSyncObjFormatTemplate *format_template = osync_plugin_find_objformat_template(template, formatstr);
00566         osync_assert_msg(format_template, "Unable to set committed_all function. Did you forget to add the objformat?");
00567         format_template->committed_all = committed_all;
00568 }
00569 
00579 void osync_plugin_accept_objtype(OSyncPluginInfo *info, const char *objtypestr)
00580 {
00581         OSyncObjTypeTemplate *template = g_malloc0(sizeof(OSyncObjTypeTemplate));
00582         template->name = g_strdup(objtypestr);
00583         info->plugin->accepted_objtypes = g_list_append(info->plugin->accepted_objtypes, template);
00584 }
00585 
00597 void osync_plugin_accept_objformat(OSyncPluginInfo *info, const char *objtypestr, const char *formatstr, const char *extension)
00598 {
00599         OSyncObjTypeTemplate *template = osync_plugin_find_objtype_template(info->plugin, objtypestr);
00600         osync_assert_msg(template, "Unable to accept objformat. Did you forget to add the objtype?");
00601         OSyncObjFormatTemplate *format_template = g_malloc0(sizeof(OSyncObjFormatTemplate));
00602         format_template->name = g_strdup(formatstr);
00603         if (extension)
00604                 format_template->extension_name = g_strdup(extension);
00605         template->formats = g_list_append(template->formats, format_template);
00606 }
00607