00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "opensync.h"
00022 #include "opensync_internals.h"
00023
00046
00047
00048
00049
00050
00051
00052
00053 static const char *osync_env_query_option(OSyncEnv *env, const char *name)
00054 {
00055 const char *value;
00056 value = g_hash_table_lookup(env->options, name);
00057 if (value)
00058 return value;
00059
00060 gchar *env_name = g_strdup_printf("OSYNC_%s", name);
00061 value = getenv(env_name);
00062 g_free(env_name);
00063
00064 if (value)
00065 return value;
00066
00067 return NULL;
00068 }
00069
00070 static osync_bool osync_env_query_option_bool(OSyncEnv *env, const char *name)
00071 {
00072 const char *get_value;
00073 if (!(get_value = osync_env_query_option(env, name)))
00074 return FALSE;
00075 if (!strcmp(get_value, "TRUE"))
00076 return TRUE;
00077 return FALSE;
00078 }
00079
00083 void osync_env_export_loaded_modules(OSyncEnv *env)
00084 {
00085 int num_modules = g_list_length(env->modules);
00086
00087
00088 gchar **path_array = g_malloc0(sizeof(gchar*)*(num_modules + 1));
00089 int i;
00090 for (i = 0; i < num_modules; i++) {
00091 GModule *module = g_list_nth_data(env->modules, i);
00092 const gchar *path = g_module_name(module);
00093
00094
00095
00096
00097
00098
00099 path_array[i] = (gchar*)path;
00100 }
00101
00102
00103 gchar *list_str = g_strjoinv(":", path_array);
00104 setenv("OSYNC_FORMAT_LIST", list_str, 1);
00105 g_free(list_str);
00106 }
00107
00108 static void export_option_to_env(gpointer key, gpointer data, gpointer user_data)
00109 {
00110 const char *name = (const char*)key;
00111 const char *value = (const char*)data;
00112 gchar *env_name = g_strdup_printf("OSYNC_%s", name);
00113 setenv(env_name, value, 1);
00114 g_free(env_name);
00115 }
00116
00120 void osync_env_export_all_options(OSyncEnv *env)
00121 {
00122 g_hash_table_foreach(env->options, export_option_to_env, NULL);
00123 }
00124
00125 static void free_hash(char *key, char *value, void *data)
00126 {
00127 g_free(key);
00128 g_free(value);
00129 }
00130
00139 long long int _osync_env_create_group_id(OSyncEnv *env)
00140 {
00141 char *filename = NULL;
00142 long long int i = 0;
00143 do {
00144 i++;
00145 if (filename)
00146 g_free(filename);
00147 filename = g_strdup_printf("%s/group%lli", env->groupsdir, i);
00148 } while (g_file_test(filename, G_FILE_TEST_EXISTS));
00149 g_free(filename);
00150 return i;
00151 }
00152
00177
00178
00186 OSyncEnv *osync_env_new(void)
00187 {
00188 OSyncEnv *env = g_malloc0(sizeof(OSyncEnv));
00189 env->is_initialized = FALSE;
00190 env->options = g_hash_table_new(g_str_hash, g_str_equal);
00191
00192
00193 osync_env_set_option(env, "LOAD_GROUPS", "TRUE");
00194 osync_env_set_option(env, "LOAD_FORMATS", "TRUE");
00195 osync_env_set_option(env, "LOAD_PLUGINS", "TRUE");
00196
00197 return env;
00198 }
00199
00207 void osync_env_free(OSyncEnv *env)
00208 {
00209 g_assert(env);
00210 g_hash_table_foreach(env->options, (GHFunc)free_hash, NULL);
00211 g_hash_table_destroy(env->options);
00212 g_free(env);
00213 }
00214
00222 void osync_env_set_option(OSyncEnv *env, const char *name, const char *value)
00223 {
00224 if (value)
00225 g_hash_table_insert(env->options, g_strdup(name), g_strdup(value));
00226 else
00227 g_hash_table_remove(env->options, name);
00228 }
00229
00240 osync_bool osync_env_initialize(OSyncEnv *env, OSyncError **error)
00241 {
00242 osync_trace(TRACE_ENTRY, "osync_env_initialize(%p, %p)", env, error);
00243 g_assert(env);
00244
00245 if (env->is_initialized) {
00246 osync_error_set(error, OSYNC_ERROR_INITIALIZATION, "Cannot initialize the same environment twice");
00247 osync_trace(TRACE_EXIT_ERROR, "osync_env_initialize: %s", osync_error_print(error));
00248 return FALSE;
00249 }
00250
00251
00252 if (osync_env_query_option_bool(env, "LOAD_PLUGINS")) {
00253 if (!osync_env_load_plugins(env, osync_env_query_option(env, "PLUGINS_DIRECTORY"), error)) {
00254 osync_trace(TRACE_EXIT_ERROR, "osync_env_initialize: %s", osync_error_print(error));
00255 return FALSE;
00256 }
00257 }
00258
00259
00260 if (osync_env_query_option_bool(env, "LOAD_FORMATS")) {
00261 if (!osync_env_load_formats(env, osync_env_query_option(env, "FORMATS_DIRECTORY"), error)) {
00262 osync_trace(TRACE_EXIT_ERROR, "osync_env_initialize: %s", osync_error_print(error));
00263 return FALSE;
00264 }
00265 }
00266
00267
00268 if (osync_env_query_option_bool(env, "LOAD_GROUPS")) {
00269 if (!osync_env_load_groups(env, osync_env_query_option(env, "GROUPS_DIRECTORY"), error)) {
00270 osync_trace(TRACE_EXIT_ERROR, "osync_env_initialize: %s", osync_error_print(error));
00271 return FALSE;
00272 }
00273 }
00274
00275 env->is_initialized = TRUE;
00276 osync_trace(TRACE_EXIT, "osync_env_initialize");
00277 return TRUE;
00278 }
00279
00289 osync_bool osync_env_finalize(OSyncEnv *env, OSyncError **error)
00290 {
00291 osync_trace(TRACE_ENTRY, "osync_env_finalize(%p, %p)", env, error);
00292 g_assert(env);
00293
00294 if (!env->is_initialized) {
00295 osync_error_set(error, OSYNC_ERROR_INITIALIZATION, "Environment has to be initialized before");
00296 return FALSE;
00297 }
00298
00299 while (osync_env_nth_group(env, 0))
00300 osync_group_free(osync_env_nth_group(env, 0));
00301
00302 GList *plugins = g_list_copy(env->plugins);
00303 GList *p;
00304 for (p = plugins; p; p = p->next) {
00305 OSyncPlugin *plugin = p->data;
00306 osync_plugin_free(plugin);
00307 }
00308 g_list_free(plugins);
00309
00310
00311 GList *modules = g_list_copy(env->modules);
00312 for (p = modules; p; p = p->next) {
00313 GModule *module = p->data;
00314 osync_module_unload(env, module);
00315 }
00316 g_list_free(modules);
00317
00318 osync_trace(TRACE_EXIT, "osync_env_finalize");
00319 return TRUE;
00320 }
00321
00334 osync_bool osync_env_load_formats(OSyncEnv *env, const char *path, OSyncError **error)
00335 {
00336 osync_trace(TRACE_ENTRY, "%s(%p, %s, %p)", __func__, env, path, error);
00337 osync_bool must_exist = TRUE;
00338
00339 if (!path) {
00340 path = OPENSYNC_FORMATSDIR;
00341 must_exist = FALSE;
00342 }
00343
00344 if (!osync_module_load_dir(env, path, must_exist, error)) {
00345 osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
00346 return FALSE;
00347 }
00348
00349 osync_trace(TRACE_EXIT, "%s", __func__);
00350 return TRUE;
00351 }
00352
00363 osync_bool osync_env_load_plugins(OSyncEnv *env, const char *path, OSyncError **error)
00364 {
00365 osync_trace(TRACE_ENTRY, "%s(%p, %s, %p)", __func__, env, path, error);
00366 osync_bool must_exist = TRUE;
00367
00368 if (!path) {
00369 path = OPENSYNC_PLUGINDIR;
00370 must_exist = FALSE;
00371 }
00372
00373 if (!osync_module_load_dir(env, path, must_exist, error)) {
00374 osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
00375 return FALSE;
00376 }
00377
00378 osync_trace(TRACE_EXIT, "%s", __func__);
00379 return TRUE;
00380 }
00381
00391 OSyncPlugin *osync_env_find_plugin(OSyncEnv *env, const char *name)
00392 {
00393 g_assert(env);
00394 OSyncPlugin *plugin;
00395 int i;
00396 for (i = 0; i < osync_env_num_plugins(env); i++) {
00397 plugin = osync_env_nth_plugin(env, i);
00398 if (g_ascii_strcasecmp(plugin->info.name, name) == 0) {
00399 return plugin;
00400 }
00401 }
00402 return NULL;
00403 }
00404
00413 int osync_env_num_plugins(OSyncEnv *env)
00414 {
00415 return g_list_length(env->plugins);
00416 }
00417
00427 OSyncPlugin *osync_env_nth_plugin(OSyncEnv *env, int nth)
00428 {
00429 return (OSyncPlugin *)g_list_nth_data(env->plugins, nth);
00430 }
00431
00440 osync_bool osync_env_plugin_is_usable(OSyncEnv *env, const char *pluginname, OSyncError **error)
00441 {
00442 osync_trace(TRACE_ENTRY, "%s(%p, %s, %p)", __func__, env, pluginname, error);
00443
00444 OSyncPlugin *plugin = osync_env_find_plugin(env, pluginname);
00445 if (!plugin) {
00446 osync_error_set(error, OSYNC_ERROR_PLUGIN_NOT_FOUND, "Unable to find plugin \"%s\". This can be caused by unresolved symbols", pluginname);
00447 osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
00448 return FALSE;
00449 }
00450
00451 if (plugin->info.functions.is_available) {
00452 osync_bool ret = plugin->info.functions.is_available(error);
00453 osync_trace(ret ? TRACE_EXIT : TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
00454 return ret;
00455 }
00456
00457 osync_trace(TRACE_EXIT, "%s: TRUE: No is_available function", __func__);
00458 return TRUE;
00459 }
00460
00472 osync_bool osync_env_load_groups(OSyncEnv *env, const char *p, OSyncError **error)
00473 {
00474 GDir *dir;
00475 GError *gerror = NULL;
00476 char *filename = NULL;
00477 char *real_path = NULL;
00478 char *path = g_strdup(p);
00479
00480 if (!path) {
00481 OSyncUserInfo *user = osync_user_new(error);
00482 if (!user)
00483 return FALSE;
00484 path = g_strdup(osync_user_get_confdir(user));
00485
00486 if (!g_file_test(path, G_FILE_TEST_EXISTS)) {
00487 if (mkdir(path, 0700) == -1) {
00488 osync_error_set(error, OSYNC_ERROR_GENERIC, "Unable to create group directory at %s: %s", path, strerror(errno));
00489 g_free(path);
00490 return FALSE;
00491 }
00492 char *enginepath = g_strdup_printf("%s/engines", path);
00493 if (mkdir(enginepath, 0700) == -1) {
00494 osync_error_set(error, OSYNC_ERROR_GENERIC, "Unable to create engine group directory at %s: %s", enginepath, strerror(errno));
00495 g_free(path);
00496 g_free(enginepath);
00497 return FALSE;
00498 }
00499 g_free(enginepath);
00500 osync_debug("OSGRP", 3, "Created groups configdir %s\n", path);
00501 }
00502 osync_user_free(user);
00503 }
00504
00505 if (!g_path_is_absolute(path)) {
00506 real_path = g_strdup_printf("%s/%s", g_get_current_dir(), path);
00507 } else {
00508 real_path = g_strdup(path);
00509 }
00510
00511 if (!g_file_test(real_path, G_FILE_TEST_IS_DIR)) {
00512 osync_debug("OSGRP", 0, "%s exists, but is no dir", real_path);
00513 osync_error_set(error, OSYNC_ERROR_INITIALIZATION, "%s exists, but is no dir", real_path);
00514 g_free(real_path);
00515 g_free(path);
00516 return FALSE;
00517 }
00518
00519 dir = g_dir_open(real_path, 0, &gerror);
00520 if (!dir) {
00521 osync_debug("OSGRP", 0, "Unable to open main configdir %s: %s", real_path, gerror->message);
00522 osync_error_set(error, OSYNC_ERROR_IO_ERROR, "Unable to open main configdir %s: %s", real_path, gerror->message);
00523 g_error_free (gerror);
00524 g_free(real_path);
00525 g_free(path);
00526 return FALSE;
00527 }
00528
00529 const gchar *de = NULL;
00530 while ((de = g_dir_read_name(dir))) {
00531 filename = g_strdup_printf ("%s/%s", real_path, de);
00532
00533 if (!g_file_test(filename, G_FILE_TEST_IS_DIR) || g_file_test(filename, G_FILE_TEST_IS_SYMLINK) || !g_pattern_match_simple("group*", de)) {
00534 g_free(filename);
00535 continue;
00536 }
00537
00538
00539 OSyncError *error = NULL;
00540 if (!osync_group_load(env, filename, &error)) {
00541 osync_debug("OSGRP", 0, "Unable to load group from %s: %s", filename, error->message);
00542 osync_error_free(&error);
00543 }
00544
00545 g_free(filename);
00546 }
00547 g_free(real_path);
00548 g_dir_close(dir);
00549
00550 env->groupsdir = path;
00551 return TRUE;
00552 }
00553
00563 OSyncGroup *osync_env_find_group(OSyncEnv *env, const char *name)
00564 {
00565 OSyncGroup *group;
00566 int i;
00567 for (i = 0; i < osync_env_num_groups(env); i++) {
00568 group = osync_env_nth_group(env, i);
00569 if (g_ascii_strcasecmp(group->name, name) == 0) {
00570 return group;
00571 }
00572 }
00573 osync_debug("OSPLG", 0, "Couldnt find the group with the name %s", name);
00574 return NULL;
00575 }
00576
00585 void osync_env_append_group(OSyncEnv *env, OSyncGroup *group)
00586 {
00587 env->groups = g_list_append(env->groups, group);
00588 }
00589
00598 void osync_env_remove_group(OSyncEnv *env, OSyncGroup *group)
00599 {
00600 env->groups = g_list_remove(env->groups, group);
00601 }
00602
00611 int osync_env_num_groups(OSyncEnv *env)
00612 {
00613 return g_list_length(env->groups);
00614 }
00615
00625 OSyncGroup *osync_env_nth_group(OSyncEnv *env, int nth)
00626 {
00627 return (OSyncGroup *)g_list_nth_data(env->groups, nth);;
00628 }
00629
00639
00652 osync_bool _osync_open_xml_file(xmlDocPtr *doc, xmlNodePtr *cur, const char *path, const char *topentry, OSyncError **error)
00653 {
00654 if (!g_file_test(path, G_FILE_TEST_EXISTS)) {
00655 osync_debug("OSXML", 1, "File %s does not exist", path);
00656 osync_error_set(error, OSYNC_ERROR_IO_ERROR, "File %s does not exist", path);
00657 return FALSE;
00658 }
00659
00660 *doc = xmlParseFile(path);
00661
00662 if (!*doc) {
00663 osync_debug("OSXML", 1, "Could not open: %s", path);
00664 osync_error_set(error, OSYNC_ERROR_IO_ERROR, "Could not open: %s", path);
00665 return FALSE;
00666 }
00667
00668 *cur = xmlDocGetRootElement(*doc);
00669
00670 if (!*cur) {
00671 osync_debug("OSXML", 0, "%s seems to be empty", path);
00672 osync_error_set(error, OSYNC_ERROR_IO_ERROR, "%s seems to be empty", path);
00673 xmlFreeDoc(*doc);
00674 return FALSE;
00675 }
00676
00677 if (xmlStrcmp((*cur)->name, (const xmlChar *) topentry)) {
00678 osync_debug("OSXML", 0, "%s seems not to be a valid configfile.\n", path);
00679 osync_error_set(error, OSYNC_ERROR_IO_ERROR, "%s seems not to be a valid configfile.\n", path);
00680 xmlFreeDoc(*doc);
00681 return FALSE;
00682 }
00683
00684 *cur = (*cur)->xmlChildrenNode;
00685 return TRUE;
00686 }
00687
00700 osync_bool osync_file_write(const char *filename, const char *data, int size, int mode, OSyncError **oserror)
00701 {
00702 osync_bool ret = FALSE;
00703 GError *error = NULL;
00704 GIOChannel *chan = g_io_channel_new_file(filename, "w", &error);
00705 if (!chan) {
00706 osync_debug("OSYNC", 3, "Unable to open file %s for writing: %s", filename, error->message);
00707 osync_error_set(oserror, OSYNC_ERROR_IO_ERROR, "Unable to open file %s for writing: %s", filename, error->message);
00708 return FALSE;
00709 }
00710 if (mode) {
00711 int fd = g_io_channel_unix_get_fd(chan);
00712 if (fchmod(fd, mode)) {
00713 osync_debug("OSYNC", 3, "Unable to set file permissions %i for file %s", mode, filename);
00714 osync_error_set(oserror, OSYNC_ERROR_IO_ERROR, "Unable to set file permissions %i for file %s", mode, filename);
00715 return FALSE;
00716 }
00717 }
00718 gsize writen;
00719 g_io_channel_set_encoding(chan, NULL, NULL);
00720 if (g_io_channel_write_chars(chan, data, size, &writen, &error) != G_IO_STATUS_NORMAL) {
00721 osync_debug("OSYNC", 3, "Unable to write contents of file %s: %s", filename, error->message);
00722 osync_error_set(oserror, OSYNC_ERROR_IO_ERROR, "Unable to write contents of file %s: %s", filename, error->message);
00723 } else {
00724 g_io_channel_flush(chan, NULL);
00725 ret = TRUE;
00726 }
00727 g_io_channel_shutdown(chan, FALSE, NULL);
00728 g_io_channel_unref(chan);
00729 return ret;
00730 }
00731
00743 osync_bool osync_file_read(const char *filename, char **data, int *size, OSyncError **oserror)
00744 {
00745 osync_bool ret = FALSE;
00746 GError *error = NULL;
00747 gsize sz = 0;
00748
00749 if (!filename) {
00750 osync_debug("OSYNC", 3, "No file open specified");
00751 osync_error_set(oserror, OSYNC_ERROR_IO_ERROR, "No file to open specified");
00752 return FALSE;
00753 }
00754 GIOChannel *chan = g_io_channel_new_file(filename, "r", &error);
00755 if (!chan) {
00756 osync_debug("OSYNC", 3, "Unable to read file %s: %s", filename, error->message);
00757 osync_error_set(oserror, OSYNC_ERROR_IO_ERROR, "Unable to open file %s for reading: %s", filename, error->message);
00758 return FALSE;
00759 }
00760 g_io_channel_set_encoding(chan, NULL, NULL);
00761 if (g_io_channel_read_to_end(chan, data, &sz, &error) != G_IO_STATUS_NORMAL) {
00762 osync_debug("OSYNC", 3, "Unable to read contents of file %s: %s", filename, error->message);
00763 osync_error_set(oserror, OSYNC_ERROR_IO_ERROR, "Unable to read contents of file %s: %s", filename, error->message);
00764 } else {
00765 ret = TRUE;
00766 *size = (int)sz;
00767 }
00768 g_io_channel_shutdown(chan, FALSE, NULL);
00769 g_io_channel_unref(chan);
00770 return ret;
00771 }
00772
00781 const char *osync_get_version(void)
00782 {
00783 return VERSION;
00784 }
00785
00796 void *osync_try_malloc0(unsigned int size, OSyncError **error)
00797 {
00798 void *result = g_try_malloc(size);
00799 if (!result) {
00800 osync_error_set(error, OSYNC_ERROR_GENERIC, "No memory left");
00801 return NULL;
00802 }
00803 memset(result, 0, size);
00804 return result;
00805 }
00806
00807 char *osync_strreplace(const char *input, const char *delimiter, const char *replacement)
00808 {
00809 osync_return_val_if_fail(input != NULL, NULL);
00810 osync_return_val_if_fail(delimiter != NULL, NULL);
00811 osync_return_val_if_fail(replacement != NULL, NULL);
00812
00813 gchar **array = g_strsplit(input, delimiter, 0);
00814 gchar *ret = g_strjoinv(replacement, array);
00815 g_strfreev(array);
00816
00817 return ret;
00818 }
00819
00822 OSyncThread *osync_thread_new(GMainContext *context, OSyncError **error)
00823 {
00824 osync_trace(TRACE_ENTRY, "%s(%p, %p)", __func__, context, error);
00825
00826 OSyncThread *thread = osync_try_malloc0(sizeof(OSyncThread), error);
00827 if (!thread)
00828 goto error;
00829
00830 if (!g_thread_supported ()) g_thread_init (NULL);
00831
00832 thread->started_mutex = g_mutex_new();
00833 thread->started = g_cond_new();
00834 thread->context = context;
00835 if (thread->context)
00836 g_main_context_ref(thread->context);
00837 thread->loop = g_main_loop_new(thread->context, FALSE);
00838
00839 osync_trace(TRACE_EXIT, "%s: %p", __func__, thread);
00840 return thread;
00841
00842 error:
00843 osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
00844 return NULL;
00845 }
00846
00847 void osync_thread_free(OSyncThread *thread)
00848 {
00849 osync_trace(TRACE_ENTRY, "%s(%p)", __func__, thread);
00850 osync_assert(thread);
00851
00852 if (thread->started_mutex)
00853 g_mutex_free(thread->started_mutex);
00854
00855 if (thread->started)
00856 g_cond_free(thread->started);
00857
00858 if (thread->loop)
00859 g_main_loop_unref(thread->loop);
00860
00861 if (thread->context)
00862 g_main_context_unref(thread->context);
00863
00864 g_free(thread);
00865 osync_trace(TRACE_EXIT, "%s", __func__);
00866 }
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881 static gboolean osyncThreadStopCallback(gpointer data)
00882 {
00883 OSyncThread *thread = data;
00884
00885 g_main_loop_quit(thread->loop);
00886
00887 return FALSE;
00888 }
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904 static gboolean osyncThreadStartCallback(gpointer data)
00905 {
00906 OSyncThread *thread = data;
00907
00908 g_mutex_lock(thread->started_mutex);
00909 g_cond_signal(thread->started);
00910 g_mutex_unlock(thread->started_mutex);
00911 return FALSE;
00912 }
00913
00914 void osync_thread_start(OSyncThread *thread)
00915 {
00916 osync_trace(TRACE_ENTRY, "%s(%p)", __func__, thread);
00917
00918 g_mutex_lock(thread->started_mutex);
00919 GSource *idle = g_idle_source_new();
00920 g_source_set_callback(idle, osyncThreadStartCallback, thread, NULL);
00921 g_source_attach(idle, thread->context);
00922 thread->thread = g_thread_create ((GThreadFunc)g_main_loop_run, thread->loop, TRUE, NULL);
00923 g_cond_wait(thread->started, thread->started_mutex);
00924 g_mutex_unlock(thread->started_mutex);
00925
00926 osync_trace(TRACE_EXIT, "%s", __func__);
00927 }
00928
00929 void osync_thread_stop(OSyncThread *thread)
00930 {
00931 osync_trace(TRACE_ENTRY, "%s(%p)", __func__, thread);
00932 osync_assert(thread);
00933
00934 GSource *source = g_idle_source_new();
00935 g_source_set_callback(source, osyncThreadStopCallback, thread, NULL);
00936 g_source_attach(source, thread->context);
00937
00938 g_thread_join(thread->thread);
00939 thread->thread = NULL;
00940
00941 g_source_unref(source);
00942
00943 osync_trace(TRACE_EXIT, "%s", __func__);
00944 }
00945
00946 osync_bool osync_pattern_match(const char *pattern, const char *data, int size)
00947 {
00948 GPatternSpec *spec = g_pattern_spec_new(pattern);
00949 osync_bool result = g_pattern_match(spec, size, data, NULL);
00950 g_pattern_spec_free(spec);
00951 return result;
00952 }