/*
* libopensync - A synchronization framework
* Copyright (C) 2004-2005 Armin Bauer <armin.bauer@opensync.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "opensync.h"
#include "opensync_internals.h"
#include <errno.h>
#include <sys/file.h>
extern int errno;
/*
* On Solaris no flock function exists,
* we must implenet it here
*/
#ifdef SOLARIS
#define LOCK_SH 1
#define LOCK_EX 2
#define LOCK_NB 4
#define LOCK_UN 8
static int
flock(int fd, int operation)
{
struct flock flock;
switch (operation & ~LOCK_NB) {
case LOCK_SH:
flock.l_type = F_RDLCK;
break;
case LOCK_EX:
flock.l_type = F_WRLCK;
break;
case LOCK_UN:
flock.l_type = F_UNLCK;
break;
default:
errno = EINVAL;
return -1;
}
flock.l_whence = 0;
flock.l_start = 0;
flock.l_len = 0;
return fcntl(fd, (operation & LOCK_NB) ? F_SETLK : F_SETLKW, &flock);
}
#endif
/**
* @defgroup OSyncGroupPrivateAPI OpenSync Group Internals
* @ingroup OSyncPrivate
* @brief The private API of opensync
*
* This gives you an insight in the private API of opensync.
*
*/
/*@{*/
/*! @brief Returns the environment in which a group is registered
*
* @param group The group
* @returns The environment
*
*/
OSyncEnv *osync_group_get_env(OSyncGroup *group)
{
return group->env;
}
/*! @brief Gets the custom data of a group
*
* @param group The group
* @returns The custom data of this group
*
*/
void *osync_group_get_data(OSyncGroup *group)
{
return group->data;
}
/*! @brief Sets the custom data of a group
*
* @param group The group
* @param data The custom data
*
*/
void osync_group_set_data(OSyncGroup *group, void *data)
{
group->data = data;
}
/*! @brief Creates a new unique member if in this group
*
* @param group The group
* @returns A new unique member id
*
*/
long long int osync_group_create_member_id(OSyncGroup *group)
{
char *filename = NULL;
long long int i = 0;
do {
i++;
if (filename)
g_free(filename);
filename = g_strdup_printf("%s/%lli", group->configdir, i);
} while (g_file_test(filename, G_FILE_TEST_EXISTS));
g_free(filename);
return i;
}
/*! @brief Returns the format environment of a group
*
* @param group The group
* @returns The format environment
*
*/
OSyncFormatEnv *osync_group_get_format_env(OSyncGroup *group)
{
g_assert(group);
return group->conv_env;
}
/*! @brief Loads all members of a group
*
* Loads all members of a group
*
* @param group The group
* @param path The path from which to load the members
* @param error Pointer to a error
* @returns True if the members were loaded successfully, FALSE otherwise
*
*/
osync_bool osync_group_load_members(OSyncGroup *group, const char *path, OSyncError **error)
{
GDir *dir = NULL;
GError *gerror = NULL;
char *filename = NULL;
dir = g_dir_open(path, 0, &gerror);
if (!dir) {
osync_debug("OSGRP", 3, "Unable to open group configdir %s", gerror->message);
osync_error_set(error, OSYNC_ERROR_IO_ERROR, "Unable to open group configdir %s", gerror->message);
g_error_free (gerror);
return FALSE;
}
const gchar *de = NULL;
while ((de = g_dir_read_name(dir))) {
filename = g_strdup_printf ("%s/%s", osync_group_get_configdir(group), de);
if (!g_file_test(filename, G_FILE_TEST_IS_DIR) || g_file_test(filename, G_FILE_TEST_IS_SYMLINK) || g_pattern_match_simple(".*", de) || !strcmp("db", de)) {
g_free(filename);
continue;
}
if (!osync_member_load(group, filename, error)) {
osync_debug("OSGRP", 0, "Unable to load one of the members");
g_free(filename);
g_dir_close(dir);
return FALSE;
}
g_free(filename);
}
g_dir_close(dir);
return TRUE;
}
/*@}*/
/**
* @defgroup OSyncGroupAPI OpenSync Groups
* @ingroup OSyncPublic
* @brief A groups represent several device or application that should be synchronized
*
*/
/*@{*/
/*! @brief Creates a new group for the given environment
*
* Creates a newly allocated group
*
* @param env The environment for which to create the group. Might be NULL if you which to not add the group at the point of creation
* @returns Pointer to a new group
*
*/
OSyncGroup *osync_group_new(OSyncEnv *env)
{
OSyncGroup *group = g_malloc0(sizeof(OSyncGroup));
group->conv_env = osync_conv_env_new(env);
if (env) {
osync_env_append_group(env, group);
group->env = env;
}
return group;
}
/*! @brief Frees the given group
*
* Frees the given group
*
* @param group The group
*
*/
void osync_group_free(OSyncGroup *group)
{
g_assert(group);
if (group->conv_env)
osync_conv_env_free(group->conv_env);
if (group->lock_fd)
osync_group_unlock(group, FALSE);
while (osync_group_nth_member(group, 0))
osync_member_free(osync_group_nth_member(group, 0));
if (group->env)
osync_env_remove_group(group->env, group);
if (group->name)
g_free(group->name);
if (group->configdir)
g_free(group->configdir);
g_free(group);
}
/*! @brief Locks a group
*
* Tries to acquire a lock for the given group.
*
* If the lock was successfully acquired, OSYNC_LOCK_OK will
* be returned.
*
* If the lock was acquired, but a old lock file was detected,
* OSYNC_LOCK_STALE will be returned. Use this to detect if the
* last sync of this group was successfull, or if this something crashed.
* If you get this answer you should perform a slow-sync
*
* If the group is locked, OSYNC_LOCKED is returned
*
* @param group The group
* @returns if the lockfile was acquired
*
*/
OSyncLockState osync_group_lock(OSyncGroup *group)
{
osync_trace(TRACE_ENTRY, "osync_group_lock(%p)", group);
g_assert(group);
g_assert(group->configdir);
osync_bool exists = FALSE;
osync_bool locked = FALSE;
if (group->lock_fd) {
osync_trace(TRACE_EXIT, "osync_group_lock: OSYNC_LOCKED, lock_fd existed");
return OSYNC_LOCKED;
}
char *lockfile = g_strdup_printf("%s/lock", group->configdir);
osync_debug("GRP", 4, "locking file %s", lockfile);
if (g_file_test(lockfile, G_FILE_TEST_EXISTS)) {
osync_debug("GRP", 4, "locking group: file exists");
exists = TRUE;
}
if ((group->lock_fd = open(lockfile, O_CREAT | O_WRONLY, 00700)) == -1) {
group->lock_fd = 0;
osync_debug("GRP", 1, "error opening file: %s", strerror(errno));
g_free(lockfile);
osync_trace(TRACE_EXIT_ERROR, "osync_group_lock: %s", strerror(errno));
return OSYNC_LOCK_STALE;
} else {
/* Set FD_CLOEXEC flags for the lock file descriptor. We don't want the
* subprocesses created by plugins or the engine to keep holding the lock
*/
int oldflags = fcntl(group->lock_fd, F_GETFD);
if (oldflags == -1) {
osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, "Unable to get fd flags");
return OSYNC_LOCK_STALE;
}
if (fcntl(group->lock_fd, F_SETFD, oldflags|FD_CLOEXEC) == -1) {
osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, "Unable to set fd flags");
return OSYNC_LOCK_STALE;
}
if (flock(group->lock_fd, LOCK_EX | LOCK_NB) == -1) {
if (errno == EWOULDBLOCK) {
osync_debug("GRP", 4, "locking group: is locked2");
locked = TRUE;
close(group->lock_fd);
group->lock_fd = 0;
} else
osync_debug("GRP", 1, "error setting lock: %s", strerror(errno));
} else
osync_debug("GRP", 4, "Successfully locked");
}
g_free(lockfile);
if (!exists) {
osync_trace(TRACE_EXIT, "osync_group_lock: OSYNC_LOCK_OK");
return OSYNC_LOCK_OK;
} else {
if (locked) {
osync_trace(TRACE_EXIT, "osync_group_lock: OSYNC_LOCKED");
return OSYNC_LOCKED;
} else {
osync_trace(TRACE_EXIT, "osync_group_lock: OSYNC_LOCK_STALE");
return OSYNC_LOCK_STALE;
}
}
}
/*! @brief Unlocks a group
*
* if you set remove = FALSE, the lock file will not be removed
* and the next call to osync_lock_group() for this group will
* return OSYNC_LOCK_STALE.
*
* @param group The group
* @param remove If the lockfile should be removed
*
*/
void osync_group_unlock(OSyncGroup *group, osync_bool remove)
{
g_assert(group);
g_assert(group->configdir);
osync_debug("GRP", 4, "unlocking group %s", group->name);
if (!group->lock_fd) {
osync_debug("GRP", 1, "You have to lock the group before unlocking");
return;
}
if (flock(group->lock_fd, LOCK_UN) == -1) {
osync_debug("GRP", 1, "error releasing lock: %s", strerror(errno));
return;
}
fsync(group->lock_fd);
close(group->lock_fd);
group->lock_fd = 0;
if (remove) {
char *lockfile = g_strdup_printf("%s/lock", group->configdir);
unlink(lockfile);
g_free(lockfile);
}
}
/*! @brief Sets the name for the group
*
* Sets the name for a group
*
* @param group The group
* @param name The name to set
*
*/
void osync_group_set_name(OSyncGroup *group, const char *name)
{
g_assert(group);
if (group->name)
g_free(group->name);
group->name = g_strdup(name);
}
/*! @brief Returns the name of a group
*
* Returns the name of a group
*
* @param group The group
* @returns Name of the group
*
*/
const char *osync_group_get_name(OSyncGroup *group)
{
g_assert(group);
return group->name;
}
/*! @brief Saves the group to disc
*
* Saves the group to disc possibly creating the configdirectory
*
* @param group The group
* @param error Pointer to a error struct
* @returns TRUE on success, FALSE otherwise
*
*/
osync_bool osync_group_save(OSyncGroup *group, OSyncError **error)
{
osync_trace(TRACE_ENTRY, "%s(%p, %p)", __func__, group, error);
g_assert(group);
osync_assert_msg(group->env, "You must specify a Environment prior to saving the group");
if (!group->configdir) {
group->id = _osync_env_create_group_id(group->env);
group->configdir = g_strdup_printf("%s/group%lli", group->env->groupsdir, group->id);
}
char *filename = NULL;
osync_debug("OSGRP", 3, "Trying to open configdirectory %s to save group %s", group->configdir, group->name);
int i;
if (!g_file_test(group->configdir, G_FILE_TEST_IS_DIR)) {
osync_debug("OSGRP", 3, "Creating group configdirectory %s", group->configdir);
if (mkdir(group->configdir, 0700)) {
osync_error_set(error, OSYNC_ERROR_IO_ERROR, "Unable to create directory for group %s\n", group->name);
goto error;
}
}
filename = g_strdup_printf ("%s/syncgroup.conf", group->configdir);
osync_debug("OSGRP", 3, "Saving group to file %s", filename);
xmlDocPtr doc;
doc = xmlNewDoc((xmlChar*)"1.0");
doc->children = xmlNewDocNode(doc, NULL, (xmlChar*)"syncgroup", NULL);
//The filters
GList *f;
for (f = group->filters; f; f = f->next) {
OSyncFilter *filter = f->data;
xmlNodePtr child = xmlNewTextChild(doc->children, NULL, (xmlChar*)"filter", NULL);
if (filter->sourcememberid) {
char *sourcememberid = g_strdup_printf("%lli", filter->sourcememberid);
xmlNewTextChild(child, NULL, (xmlChar*)"sourcemember", (xmlChar*)sourcememberid);
g_free(sourcememberid);
}
if (filter->destmemberid) {
char *destmemberid = g_strdup_printf("%lli", filter->destmemberid);
xmlNewTextChild(child, NULL, (xmlChar*)"destmember", (xmlChar*)destmemberid);
g_free(destmemberid);
}
if (filter->sourceobjtype)
xmlNewTextChild(child, NULL, (xmlChar*)"sourceobjtype", (xmlChar*)filter->sourceobjtype);
if (filter->destobjtype)
xmlNewTextChild(child, NULL, (xmlChar*)"destobjtype", (xmlChar*)filter->destobjtype);
if (filter->detectobjtype)
xmlNewTextChild(child, NULL, (xmlChar*)"detectobjtype", (xmlChar*)filter->detectobjtype);
if (filter->action) {
char *action = g_strdup_printf("%i", filter->action);
xmlNewTextChild(child, NULL, (xmlChar*)"action", (xmlChar*)action);
g_free(action);
}
if (filter->function_name)
xmlNewTextChild(child, NULL, (xmlChar*)"function_name", (xmlChar*)filter->function_name);
if (filter->config)
xmlNewTextChild(child, NULL, (xmlChar*)"config", (xmlChar*)filter->config);
}
xmlNewTextChild(doc->children, NULL, (xmlChar*)"groupname", (xmlChar*)group->name);
char *tmstr = g_strdup_printf("%i", (int)group->last_sync);
xmlNewTextChild(doc->children, NULL, (xmlChar*)"last_sync", (xmlChar*)tmstr);
g_free(tmstr);
xmlSaveFile(filename, doc);
xmlFreeDoc(doc);
g_free(filename);
for (i = 0; i < osync_group_num_members(group); i++) {
OSyncMember *member = osync_group_nth_member(group, i);
if (!osync_member_save(member, error))
goto error;
}
osync_trace(TRACE_EXIT, "%s", __func__);
return TRUE;
error:
osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
return FALSE;
}
/*! @brief Deletes a group from disc
*
* Deletes to group directories and removes it from its environment
*
* @param group The group
* @param error Pointer to a error struct
* @returns TRUE on success, FALSE otherwise
*
*/
osync_bool osync_group_delete(OSyncGroup *group, OSyncError **error)
{
g_assert(group);
char *delcmd = g_strdup_printf("rm -rf %s", group->configdir);
if (system(delcmd)) {
osync_error_set(error, OSYNC_ERROR_GENERIC, "Failed to delete group. command %s failed", delcmd);
g_free(delcmd);
return FALSE;
}
g_free(delcmd);
osync_group_free(group);
return TRUE;
}
/*! @brief Loads a group from a directory
*
* Loads a group from a directory
*
* @param env The environment in which to create the group. Can be NULL
* @param path The path to the config directory of the group
* @param error Pointer to a error struct
* @returns Pointer to the loaded group
*
*/
OSyncGroup *osync_group_load(OSyncEnv *env, const char *path, OSyncError **error)
{
g_assert(env);
char *filename = NULL;
char *real_path = NULL;
osync_trace(TRACE_ENTRY, "osync_group_load(%p, %s, %p)", env, path, error);
osync_debug("OSGRP", 3, "Trying to load group from directory %s", path);
if (!g_path_is_absolute(path)) {
real_path = g_strdup_printf("%s/%s", g_get_current_dir(), path);
} else {
real_path = g_strdup(path);
}
filename = g_strdup_printf("%s/syncgroup.conf", real_path);
OSyncGroup *group = osync_group_new(env);
group->configdir = real_path;
xmlDocPtr doc;
xmlNodePtr cur;
xmlNodePtr filternode;
if (!_osync_open_xml_file(&doc, &cur, filename, "syncgroup", error)) {
osync_group_free(group);
g_free(filename);
osync_trace(TRACE_EXIT_ERROR, "osync_group_load");
return NULL;
}
while (cur != NULL) {
if (!xmlStrcmp(cur->name, (const xmlChar *)"groupname"))
group->name = (char*)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
if (!xmlStrcmp(cur->name, (const xmlChar *)"last_sync"))
group->last_sync = (time_t)atoi((char*)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1));
if (!xmlStrcmp(cur->name, (const xmlChar *)"filter")) {
filternode = cur->xmlChildrenNode;
OSyncFilter *filter = osync_filter_new();
filter->group = group;
while (filternode != NULL) {
if (!xmlStrcmp(filternode->name, (const xmlChar *)"sourceobjtype"))
filter->sourceobjtype = (char*)xmlNodeListGetString(doc, filternode->xmlChildrenNode, 1);
if (!xmlStrcmp(filternode->name, (const xmlChar *)"destobjtype"))
filter->destobjtype = (char*)xmlNodeListGetString(doc, filternode->xmlChildrenNode, 1);
if (!xmlStrcmp(filternode->name, (const xmlChar *)"detectobjtype"))
filter->detectobjtype = (char*)xmlNodeListGetString(doc, filternode->xmlChildrenNode, 1);
if (!xmlStrcmp(filternode->name, (const xmlChar *)"config"))
filter->config = (char*)xmlNodeListGetString(doc, filternode->xmlChildrenNode, 1);
if (!xmlStrcmp(filternode->name, (const xmlChar *)"function_name")) {
char *str = (char*)xmlNodeListGetString(doc, filternode->xmlChildrenNode, 1);
if (!str) {
filternode = filternode->next;
continue;
}
osync_filter_update_hook(filter, group, str);
xmlFree(str);
}
if (!xmlStrcmp(filternode->name, (const xmlChar *)"sourcemember")) {
char *str = (char*)xmlNodeListGetString(doc, filternode->xmlChildrenNode, 1);
if (!str) {
filternode = filternode->next;
continue;
}
filter->sourcememberid = atoll(str);
xmlFree(str);
}
if (!xmlStrcmp(filternode->name, (const xmlChar *)"destmember")) {
char *str = (char*)xmlNodeListGetString(doc, filternode->xmlChildrenNode, 1);
if (!str) {
filternode = filternode->next;
continue;
}
filter->destmemberid = atoll(str);
xmlFree(str);
}
if (!xmlStrcmp(filternode->name, (const xmlChar *)"action")) {
char *str = (char*)xmlNodeListGetString(doc, filternode->xmlChildrenNode, 1);
if (!str) {
filternode = filternode->next;
continue;
}
filter->action = atoi(str);
xmlFree(str);
}
filternode = filternode->next;
}
osync_filter_register(group, filter);
}
cur = cur->next;
}
xmlFreeDoc(doc);
g_free(filename);
//Check for sanity
if (!group->name) {
osync_error_set(error, OSYNC_ERROR_MISCONFIGURATION, "Loaded a group without a name");
osync_debug("OSGRP", 0, "Loaded a group without a name");
osync_group_free(group);
osync_trace(TRACE_EXIT_ERROR, "osync_group_load");
return NULL;
}
if (!osync_group_load_members(group, real_path, error)) {
osync_group_free(group);
osync_trace(TRACE_EXIT_ERROR, "osync_group_load");
return NULL;
}
osync_trace(TRACE_EXIT, "osync_group_load");
return group;
}
/*! @brief Resets all databases of a group
*
* This will reset all databases of a group. So all anchors, mappings
* hashtables etc will be forgotten (as if the group was never synced)
*
* @param group The group to reset
*
*/
void osync_group_reset(OSyncGroup *group)
{
OSyncError *error = NULL;
osync_db_reset_group(group, &error);
GList *m = NULL;
for (m = group->members; m; m = m->next) {
OSyncMember *member = m->data;
osync_db_reset_member(member, &error);
}
}
/*! @brief Appends a member to the group
*
* Appends a member to the group
*
* @param group The group to which to append
* @param member The member to append
*
*/
void osync_group_add_member(OSyncGroup *group, OSyncMember *member)
{
g_assert(group);
group->members = g_list_append(group->members, member);
}
/*! @brief Removes a member from the group
*
* @param group The group from which to remove
* @param member The member to remove
*
*/
void osync_group_remove_member(OSyncGroup *group, OSyncMember *member)
{
g_assert(group);
group->members = g_list_remove(group->members, member);
}
/*! @brief Returns the nth member of the group
*
* Returns a pointer to the nth member of the group
*
* @param group The group
* @param nth Which member to return
* @returns Pointer to the member
*
*/
OSyncMember *osync_group_nth_member(OSyncGroup *group, int nth)
{
g_assert(group);
return (OSyncMember *)g_list_nth_data(group->members, nth);
}
/*! @brief Counts the members of the group
*
* Returns the number of members in the group
*
* @param group The group
* @returns Number of members
*
*/
int osync_group_num_members(OSyncGroup *group)
{
g_assert(group);
return g_list_length(group->members);
}
/*! @brief Returns the configdir for the group
*
* Returns the configdir for the group
*
* @param group The group
* @returns String with the path of the config directory
*
*/
const char *osync_group_get_configdir(OSyncGroup *group)
{
g_assert(group);
return group->configdir;
}
/*! @brief Sets the configdir of the group
*
* @param group The group
* @param directory The new configdir
* @returns String with the path of the config directory
*
*/
void osync_group_set_configdir(OSyncGroup *group, const char *directory)
{
g_assert(group);
if (group->configdir)
g_free(group->configdir);
group->configdir = g_strdup(directory);
}
/*! @brief Sets if the group requires slow-sync for the given object type
*
* Sets if the group requires slow-sync for the given object type. This will be
* reset once the group performs a successfull slow-sync.
*
* @param group The group
* @param objtypestr The name of the object type
* @param slow_sync Set to TRUE if you want to perform a slow-sync, FALSE otherwise
*
*/
void osync_group_set_slow_sync(OSyncGroup *group, const char *objtypestr, osync_bool slow_sync)
{
osync_trace(TRACE_ENTRY, "%s(%p, %s, %i)", __func__, group, objtypestr, slow_sync);
g_assert(group);
OSyncFormatEnv *conv_env = group->conv_env;
//FIXME Remove the slow_sync bool since you are not allowed to reset
//the slow-sync manually anyways.
//FIXME Race Condition!!!
if (!osync_group_get_slow_sync(group, objtypestr)) {
if (osync_conv_objtype_is_any(objtypestr)) {
GList *element;
for (element = conv_env->objtypes; element; element = element->next) {
OSyncObjType *objtype = element->data;
objtype->needs_slow_sync = slow_sync;
}
} else {
OSyncObjType *objtype = osync_conv_find_objtype(conv_env, objtypestr);
g_assert(objtype);
objtype->needs_slow_sync = slow_sync;
}
}
osync_trace(TRACE_EXIT, "%s", __func__);
}
/** @brief Reset slow-sync for this group
*
* You can use this function to reset the slow-sync status for the given group. This is normally
* done if a synchronization succeeds.
*
* @param group The group to reset slow-sync on
* @param objtypestr The name of the object type
*/
void osync_group_reset_slow_sync(OSyncGroup *group, const char *objtypestr)
{
osync_trace(TRACE_ENTRY, "%s(%p, %s)", __func__, group, objtypestr);
g_assert(group);
OSyncFormatEnv *conv_env = group->conv_env;
if (osync_conv_objtype_is_any(objtypestr)) {
GList *element;
for (element = conv_env->objtypes; element; element = element->next) {
OSyncObjType *objtype = element->data;
objtype->needs_slow_sync = FALSE;
}
} else {
OSyncObjType *objtype = osync_conv_find_objtype(conv_env, objtypestr);
g_assert(objtype);
objtype->needs_slow_sync = FALSE;
}
osync_trace(TRACE_EXIT, "%s", __func__);
}
/*! @brief Returns if the group will perform a slow-sync for the object type
*
* Returns if the group will perform a slow-sync for the object type
*
* @param group The group
* @param objtype The name of the object type
* @returns TRUE if a slow-sync will be performed, FALSE otherwise
*
*/
osync_bool osync_group_get_slow_sync(OSyncGroup *group, const char *objtype)
{
osync_trace(TRACE_ENTRY, "%s(%p, %s)", __func__, group, objtype);
g_assert(group);
OSyncFormatEnv *env = group->conv_env;
g_assert(env);
OSyncObjType *osync_objtype = osync_conv_find_objtype(env, "data");
if (osync_objtype && osync_objtype->needs_slow_sync) {
osync_trace(TRACE_EXIT, "%s: Data objtype needs slow-sync", __func__);
return TRUE;
}
osync_objtype = osync_conv_find_objtype(env, objtype);
g_assert(osync_objtype);
osync_trace(TRACE_EXIT, "%s: %i", __func__, osync_objtype->needs_slow_sync);
return osync_objtype->needs_slow_sync;
}
/*! @brief Returns if the object type is enabled for the group
*
* Returns TRUE if the object type is enabled for the group. Note that this
* information is saved on a per member basis. If one of the members has this object type enabled
* this function will return TRUE
*
* @param group The group
* @param objtype The name of the object type
* @returns TRUE if the object type is enabled for at least one member. FALSE if for none
*
*/
osync_bool osync_group_objtype_enabled(OSyncGroup *group, const char *objtype)
{
//FIXME We should actually return a 3-state here.
//0 if none is enabled
//"0.5" if some are enabled, some are not
//1 if all are enabled
g_assert(group);
GList *m;
for (m = group->members; m; m = m->next) {
OSyncMember *member = m->data;
if (osync_member_objtype_enabled(member, objtype))
return TRUE;
}
return FALSE;
}
/*! @brief Sets if the object type is accepted for ALL members
*
* BUG We loose information if only some members are enabled
*
* @param group The group
* @param objtypestr The name of the object type
* @param enabled What do you want to set today?
*
* Note: the plugin needs to be instanced for this function to be called
*
* @todo Change interface to remove requirement to instance the plugin manually.
* It needs to be able to return error in order to load the plugin
*/
void osync_group_set_objtype_enabled(OSyncGroup *group, const char *objtypestr, osync_bool enabled)
{
g_assert(group);
GList *m;
for (m = group->members; m; m = m->next) {
OSyncMember *member = m->data;
/*TODO: What this function should do if we don't have
* any objtype sink information?
* It can't return error currently. We should either
* require that the plugin is instanced, or change the function
* interface. As changing the function interface require more
* care, currently the function is marked as requiring the plugin to be instanced
*/
if (!osync_member_require_sink_info(member, NULL)) {
osync_debug("OSGRP", 0, "%s: No sink information, can't load plugin, and I can't return error");
continue;
}
osync_member_set_objtype_enabled(member, objtypestr, enabled);
}
}
/*! @brief Returns the number of filters registered in a group
*
* @param group The group
* @returns The number of filters
*
*/
int osync_group_num_filters(OSyncGroup *group)
{
g_assert(group);
return g_list_length(group->filters);
}
/*! @brief Gets the nth filter of a group
*
* Note that you should not add or delete filters while
* iterating over them
*
* @param group The group
* @param nth Which filter to return
* @returns The filter or NULL if not found
*
*/
OSyncFilter *osync_group_nth_filter(OSyncGroup *group, int nth)
{
g_assert(group);
return g_list_nth_data(group->filters, nth);
}
/*! @brief Flushes the list of filters for a group
*
* Clean the list of filters on the group
*/
void osync_group_flush_filters(OSyncGroup *group)
{
g_assert(group);
while (group->filters) {
OSyncFilter *f = g_list_nth_data(group->filters, 0);
osync_filter_free(f);
/* Delete the first item */
group->filters = g_list_delete_link(group->filters, group->filters);
}
}
/*! @brief Can be used to load all items from the changelog. Loaded items will be removed
*
* @param group The group for which to load the log
* @param uids Place to return an array with the saved uids
* @param objtype Place to return an array with the saved objtypes
* @param memberids Place to return an array with the saved memberids
* @param changetypes Place to return an array with the saved changetypes. Same size as uids
* @param error Place to return the error
* @returns TRUE if successfull, FALSE otherwise
*/
osync_bool osync_group_open_changelog(OSyncGroup *group, char ***uids, char ***objtype, long long int **memberids, int **changetypes, OSyncError **error)
{
return osync_db_open_changelog(group, uids, objtype, memberids, changetypes, error);
}
/*! @brief Saves a change to the changelog.
*
* @param group The group in which to save
* @param change The change to save
* @param error Place to return the error
* @returns TRUE if successfull, FALSE otherwise
*/
osync_bool osync_group_save_changelog(OSyncGroup *group, OSyncChange *change, OSyncError **error)
{
return osync_db_save_changelog(group, change, error);
}
/*! @brief Removes a change from the changelog.
*
* @param group The group in which to save
* @param change The change to remove
* @param error Place to return the error
* @returns TRUE if successfull, FALSE otherwise
*/
osync_bool osync_group_remove_changelog(OSyncGroup *group, OSyncChange *change, OSyncError **error)
{
return osync_db_remove_changelog(group, change, error);
}
/*! @brief Sets the last synchronization date of this group
*
* The information will be stored on disc after osync_group_save()
*
* @param group The group in which to save
* @param tm The time info to set
*/
void osync_group_set_last_synchronization(OSyncGroup *group, time_t last_sync)
{
osync_trace(TRACE_ENTRY, "%s(%p, not shown)", __func__, last_sync);
osync_assert_msg(group, "Group missing");
group->last_sync = last_sync;
osync_trace(TRACE_EXIT, "%s", __func__);
}
/*! @brief Gets the last synchronization date from this group
*
* The information will available on the group after osync_group_load()
*
* @param group The group
* @return The synchronization info
*/
time_t osync_group_get_last_synchronization(OSyncGroup *group)
{
osync_assert_msg(group, "Group missing");
return group->last_sync;
}
/*@}*/
syntax highlighted by Code2HTML, v. 0.9.1