OpenSync  0.22
opensync/opensync_group.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 #include <errno.h>
00024 #include <sys/file.h>
00025 
00026 extern int errno;
00027 
00028 /*
00029  * On Solaris no flock function exists,
00030  * we must implenet it here
00031  */
00032 #ifdef SOLARIS
00033 
00034 #define LOCK_SH 1
00035 #define LOCK_EX 2
00036 #define LOCK_NB 4
00037 #define LOCK_UN 8
00038 
00039 static int
00040 flock(int fd, int operation)
00041 {
00042        struct flock flock;
00043 
00044        switch (operation & ~LOCK_NB) {
00045        case LOCK_SH:
00046                flock.l_type = F_RDLCK;
00047                break;
00048        case LOCK_EX:
00049                flock.l_type = F_WRLCK;
00050                break;
00051        case LOCK_UN:
00052                flock.l_type = F_UNLCK;
00053                break;
00054        default:
00055                errno = EINVAL;
00056                return -1;
00057        }
00058 
00059        flock.l_whence = 0;
00060        flock.l_start = 0;
00061        flock.l_len = 0;
00062 
00063        return fcntl(fd, (operation & LOCK_NB) ? F_SETLK : F_SETLKW, &flock);
00064 }
00065 #endif
00066 
00076 
00083 OSyncEnv *osync_group_get_env(OSyncGroup *group)
00084 {
00085         return group->env;
00086 }
00087 
00094 void *osync_group_get_data(OSyncGroup *group)
00095 {
00096         return group->data;
00097 }
00098 
00105 void osync_group_set_data(OSyncGroup *group, void *data)
00106 {
00107         group->data = data;
00108 }
00109 
00116 long long int osync_group_create_member_id(OSyncGroup *group)
00117 {
00118         char *filename = NULL;
00119         long long int i = 0;
00120         do {
00121                 i++;
00122                 if (filename)
00123                         g_free(filename);
00124                 filename = g_strdup_printf("%s/%lli", group->configdir, i);
00125         } while (g_file_test(filename, G_FILE_TEST_EXISTS));
00126         g_free(filename);
00127         return i;
00128 }
00129 
00136 OSyncFormatEnv *osync_group_get_format_env(OSyncGroup *group)
00137 {
00138         g_assert(group);
00139         return group->conv_env;
00140 }
00141 
00152 osync_bool osync_group_load_members(OSyncGroup *group, const char *path, OSyncError **error)
00153 {
00154         GDir *dir = NULL;
00155         GError *gerror = NULL;
00156         char *filename = NULL;
00157         
00158         dir = g_dir_open(path, 0, &gerror);
00159         if (!dir) {
00160                 osync_debug("OSGRP", 3, "Unable to open group configdir %s", gerror->message);
00161                 osync_error_set(error, OSYNC_ERROR_IO_ERROR, "Unable to open group configdir %s", gerror->message);
00162                 g_error_free (gerror);
00163                 return FALSE;
00164         }
00165 
00166         const gchar *de = NULL;
00167         while ((de = g_dir_read_name(dir))) {
00168                 filename = g_strdup_printf ("%s/%s", osync_group_get_configdir(group), de);
00169                 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)) {
00170                         g_free(filename);
00171                         continue;
00172                 }
00173 
00174                 if (!osync_member_load(group, filename, error)) {
00175                         osync_debug("OSGRP", 0, "Unable to load one of the members");
00176                         g_free(filename);
00177                         g_dir_close(dir);
00178                         return FALSE;
00179                 }
00180                 g_free(filename);
00181         }
00182         g_dir_close(dir);
00183         return TRUE;
00184 }
00185 
00195 
00204 OSyncGroup *osync_group_new(OSyncEnv *env)
00205 {
00206         OSyncGroup *group = g_malloc0(sizeof(OSyncGroup));
00207         group->conv_env = osync_conv_env_new(env);
00208         
00209         if (env) {
00210                 osync_env_append_group(env, group);
00211                 group->env = env;
00212         }
00213         
00214         return group;
00215 }
00216 
00224 void osync_group_free(OSyncGroup *group)
00225 {
00226         g_assert(group);
00227         
00228         if (group->conv_env)
00229                 osync_conv_env_free(group->conv_env);
00230         
00231         if (group->lock_fd)
00232                 osync_group_unlock(group, FALSE);
00233         
00234         while (osync_group_nth_member(group, 0))
00235                 osync_member_free(osync_group_nth_member(group, 0));
00236         
00237         if (group->env)
00238                 osync_env_remove_group(group->env, group);
00239         
00240         if (group->name)
00241                 g_free(group->name);
00242         
00243         if (group->configdir)
00244                 g_free(group->configdir);
00245                 
00246         g_free(group);
00247 }
00248 
00267 OSyncLockState osync_group_lock(OSyncGroup *group)
00268 {
00269         osync_trace(TRACE_ENTRY, "osync_group_lock(%p)", group);
00270         g_assert(group);
00271         g_assert(group->configdir);
00272         
00273         osync_bool exists = FALSE;
00274         osync_bool locked = FALSE;
00275         
00276         if (group->lock_fd) {
00277                 osync_trace(TRACE_EXIT, "osync_group_lock: OSYNC_LOCKED, lock_fd existed");
00278                 return OSYNC_LOCKED;
00279         }
00280         
00281         char *lockfile = g_strdup_printf("%s/lock", group->configdir);
00282         osync_debug("GRP", 4, "locking file %s", lockfile);
00283 
00284         if (g_file_test(lockfile, G_FILE_TEST_EXISTS)) {
00285                 osync_debug("GRP", 4, "locking group: file exists");
00286                 exists = TRUE;
00287         }
00288         
00289         if ((group->lock_fd = open(lockfile, O_CREAT | O_WRONLY, 00700)) == -1) {
00290                 group->lock_fd = 0;
00291                 osync_debug("GRP", 1, "error opening file: %s", strerror(errno));
00292                 g_free(lockfile);
00293                 osync_trace(TRACE_EXIT_ERROR, "osync_group_lock: %s", strerror(errno));
00294                 return OSYNC_LOCK_STALE;
00295         } else {
00296 
00297                 /* Set FD_CLOEXEC flags for the lock file descriptor. We don't want the
00298                  * subprocesses created by plugins or the engine to keep holding the lock
00299                  */
00300                 int oldflags = fcntl(group->lock_fd, F_GETFD);
00301                 if (oldflags == -1) {
00302                         osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, "Unable to get fd flags");
00303                         return OSYNC_LOCK_STALE;
00304                 }
00305 
00306                 if (fcntl(group->lock_fd, F_SETFD, oldflags|FD_CLOEXEC) == -1) {
00307                         osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, "Unable to set fd flags");
00308                         return OSYNC_LOCK_STALE;
00309                 }
00310 
00311                 if (flock(group->lock_fd, LOCK_EX | LOCK_NB) == -1) {
00312                         if (errno == EWOULDBLOCK) {
00313                                 osync_debug("GRP", 4, "locking group: is locked2");
00314                                 locked = TRUE;
00315                                 close(group->lock_fd);
00316                                 group->lock_fd = 0;
00317                         } else
00318                                 osync_debug("GRP", 1, "error setting lock: %s", strerror(errno));
00319                 } else
00320                         osync_debug("GRP", 4, "Successfully locked");
00321         }
00322         g_free(lockfile);
00323         
00324         if (!exists) {
00325                 osync_trace(TRACE_EXIT, "osync_group_lock: OSYNC_LOCK_OK");
00326                 return OSYNC_LOCK_OK;
00327         } else {
00328                 if (locked) {
00329                         osync_trace(TRACE_EXIT, "osync_group_lock: OSYNC_LOCKED");
00330                         return OSYNC_LOCKED;
00331                 } else {
00332                         osync_trace(TRACE_EXIT, "osync_group_lock: OSYNC_LOCK_STALE");
00333                         return OSYNC_LOCK_STALE;
00334                 }
00335         }
00336 }
00337 
00348 void osync_group_unlock(OSyncGroup *group, osync_bool remove)
00349 {
00350         g_assert(group);
00351         g_assert(group->configdir);
00352         osync_debug("GRP", 4, "unlocking group %s", group->name);
00353         
00354         if (!group->lock_fd) {
00355                 osync_debug("GRP", 1, "You have to lock the group before unlocking");
00356                 return;
00357         }
00358     
00359         if (flock(group->lock_fd, LOCK_UN) == -1) {
00360                 osync_debug("GRP", 1, "error releasing lock: %s", strerror(errno));
00361                 return;
00362         }
00363         
00364         fsync(group->lock_fd);
00365         close(group->lock_fd);
00366         
00367         group->lock_fd = 0;
00368         
00369         if (remove) {
00370                 char *lockfile = g_strdup_printf("%s/lock", group->configdir);
00371                 unlink(lockfile);
00372                 g_free(lockfile);
00373         }
00374 }
00375 
00384 void osync_group_set_name(OSyncGroup *group, const char *name)
00385 {
00386         g_assert(group);
00387         if (group->name)
00388                 g_free(group->name);
00389         group->name = g_strdup(name);
00390 }
00391 
00400 const char *osync_group_get_name(OSyncGroup *group)
00401 {
00402         g_assert(group);
00403         return group->name;
00404 }
00405 
00415 osync_bool osync_group_save(OSyncGroup *group, OSyncError **error)
00416 {
00417         osync_trace(TRACE_ENTRY, "%s(%p, %p)", __func__, group, error);
00418         g_assert(group);
00419         osync_assert_msg(group->env, "You must specify a Environment prior to saving the group");
00420         
00421         if (!group->configdir) {
00422                 group->id = _osync_env_create_group_id(group->env);
00423                 group->configdir = g_strdup_printf("%s/group%lli", group->env->groupsdir, group->id);
00424         }
00425                 
00426         char *filename = NULL;
00427         osync_debug("OSGRP", 3, "Trying to open configdirectory %s to save group %s", group->configdir, group->name);
00428         int i;
00429         
00430         if (!g_file_test(group->configdir, G_FILE_TEST_IS_DIR)) {
00431                 osync_debug("OSGRP", 3, "Creating group configdirectory %s", group->configdir);
00432                 if (mkdir(group->configdir, 0700)) {
00433                         osync_error_set(error, OSYNC_ERROR_IO_ERROR, "Unable to create directory for group %s\n", group->name);
00434                         goto error;
00435                 }
00436         }
00437         
00438         filename = g_strdup_printf ("%s/syncgroup.conf", group->configdir);
00439         osync_debug("OSGRP", 3, "Saving group to file %s", filename);
00440         
00441         xmlDocPtr doc;
00442 
00443         doc = xmlNewDoc((xmlChar*)"1.0");
00444         doc->children = xmlNewDocNode(doc, NULL, (xmlChar*)"syncgroup", NULL);
00445         
00446         //The filters
00447         GList *f;
00448         for (f = group->filters; f; f = f->next) {
00449                 OSyncFilter *filter = f->data;
00450                 xmlNodePtr child = xmlNewTextChild(doc->children, NULL, (xmlChar*)"filter", NULL);
00451                 
00452                 if (filter->sourcememberid) {
00453                         char *sourcememberid = g_strdup_printf("%lli", filter->sourcememberid);
00454                         xmlNewTextChild(child, NULL, (xmlChar*)"sourcemember", (xmlChar*)sourcememberid);
00455                         g_free(sourcememberid);
00456                 }
00457                 if (filter->destmemberid) {
00458                         char *destmemberid = g_strdup_printf("%lli", filter->destmemberid);
00459                         xmlNewTextChild(child, NULL, (xmlChar*)"destmember", (xmlChar*)destmemberid);
00460                         g_free(destmemberid);
00461                 }
00462                 if (filter->sourceobjtype)
00463                         xmlNewTextChild(child, NULL, (xmlChar*)"sourceobjtype", (xmlChar*)filter->sourceobjtype);
00464                 if (filter->destobjtype)
00465                         xmlNewTextChild(child, NULL, (xmlChar*)"destobjtype", (xmlChar*)filter->destobjtype);
00466                 if (filter->detectobjtype)
00467                         xmlNewTextChild(child, NULL, (xmlChar*)"detectobjtype", (xmlChar*)filter->detectobjtype);
00468                 if (filter->action) {
00469                         char *action = g_strdup_printf("%i", filter->action);
00470                         xmlNewTextChild(child, NULL, (xmlChar*)"action", (xmlChar*)action);
00471                         g_free(action);
00472                 }
00473                 if (filter->function_name)
00474                         xmlNewTextChild(child, NULL, (xmlChar*)"function_name", (xmlChar*)filter->function_name);
00475                 if (filter->config)
00476                         xmlNewTextChild(child, NULL, (xmlChar*)"config", (xmlChar*)filter->config);
00477         }
00478 
00479         xmlNewTextChild(doc->children, NULL, (xmlChar*)"groupname", (xmlChar*)group->name);
00480 
00481         char *tmstr = g_strdup_printf("%i", (int)group->last_sync);
00482         xmlNewTextChild(doc->children, NULL, (xmlChar*)"last_sync", (xmlChar*)tmstr);
00483         g_free(tmstr);
00484 
00485         xmlSaveFile(filename, doc);
00486         xmlFreeDoc(doc);
00487         g_free(filename);
00488 
00489         for (i = 0; i < osync_group_num_members(group); i++) {
00490                 OSyncMember *member = osync_group_nth_member(group, i);
00491                 if (!osync_member_save(member, error))
00492                         goto error;
00493         }
00494         
00495         osync_trace(TRACE_EXIT, "%s", __func__);
00496         return TRUE;
00497 
00498 error:
00499         osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
00500         return FALSE;
00501 }
00502 
00512 osync_bool osync_group_delete(OSyncGroup *group, OSyncError **error)
00513 {
00514         g_assert(group);
00515         char *delcmd = g_strdup_printf("rm -rf %s", group->configdir);
00516         if (system(delcmd)) {
00517                 osync_error_set(error, OSYNC_ERROR_GENERIC, "Failed to delete group. command %s failed", delcmd);
00518                 g_free(delcmd);
00519                 return FALSE;
00520         }
00521         g_free(delcmd);
00522         osync_group_free(group);
00523         return TRUE;
00524 }
00525 
00536 OSyncGroup *osync_group_load(OSyncEnv *env, const char *path, OSyncError **error)
00537 {
00538         g_assert(env);
00539         char *filename = NULL;
00540         char *real_path = NULL;
00541         
00542         osync_trace(TRACE_ENTRY, "osync_group_load(%p, %s, %p)", env, path, error);
00543         
00544         osync_debug("OSGRP", 3, "Trying to load group from directory %s", path);
00545         
00546         if (!g_path_is_absolute(path)) {
00547                 real_path = g_strdup_printf("%s/%s", g_get_current_dir(), path);
00548         } else {
00549                 real_path = g_strdup(path);
00550         }
00551         filename = g_strdup_printf("%s/syncgroup.conf", real_path);
00552                 
00553         OSyncGroup *group = osync_group_new(env);
00554         group->configdir = real_path;
00555 
00556         xmlDocPtr doc;
00557         xmlNodePtr cur;
00558         xmlNodePtr filternode;
00559         
00560         if (!_osync_open_xml_file(&doc, &cur, filename, "syncgroup", error)) {
00561                 osync_group_free(group);
00562                 g_free(filename);
00563                 osync_trace(TRACE_EXIT_ERROR, "osync_group_load");
00564                 return NULL;
00565         }
00566 
00567         while (cur != NULL) {
00568                 if (!xmlStrcmp(cur->name, (const xmlChar *)"groupname"))
00569                         group->name = (char*)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
00570 
00571                 if (!xmlStrcmp(cur->name, (const xmlChar *)"last_sync"))
00572                         group->last_sync = (time_t)atoi((char*)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1));
00573 
00574                 if (!xmlStrcmp(cur->name, (const xmlChar *)"filter")) {
00575                         filternode = cur->xmlChildrenNode;
00576                         OSyncFilter *filter = osync_filter_new();
00577                         filter->group = group;
00578                         
00579                         while (filternode != NULL) {
00580                                 if (!xmlStrcmp(filternode->name, (const xmlChar *)"sourceobjtype"))
00581                                         filter->sourceobjtype = (char*)xmlNodeListGetString(doc, filternode->xmlChildrenNode, 1);
00582                                 
00583                                 if (!xmlStrcmp(filternode->name, (const xmlChar *)"destobjtype"))
00584                                         filter->destobjtype = (char*)xmlNodeListGetString(doc, filternode->xmlChildrenNode, 1);
00585                                 
00586                                 if (!xmlStrcmp(filternode->name, (const xmlChar *)"detectobjtype"))
00587                                         filter->detectobjtype = (char*)xmlNodeListGetString(doc, filternode->xmlChildrenNode, 1);
00588                                 
00589                                 if (!xmlStrcmp(filternode->name, (const xmlChar *)"config"))
00590                                         filter->config = (char*)xmlNodeListGetString(doc, filternode->xmlChildrenNode, 1);
00591                                 
00592                                 if (!xmlStrcmp(filternode->name, (const xmlChar *)"function_name")) {
00593                                         char *str = (char*)xmlNodeListGetString(doc, filternode->xmlChildrenNode, 1);
00594                                         if (!str) {
00595                                                 filternode = filternode->next;
00596                                                 continue;
00597                                         }
00598                                         osync_filter_update_hook(filter, group, str);
00599                                         xmlFree(str);
00600                                 }
00601                                 
00602                                 if (!xmlStrcmp(filternode->name, (const xmlChar *)"sourcemember")) {
00603                                         char *str = (char*)xmlNodeListGetString(doc, filternode->xmlChildrenNode, 1);
00604                                         if (!str) {
00605                                                 filternode = filternode->next;
00606                                                 continue;
00607                                         }
00608                                         filter->sourcememberid = atoll(str);
00609                                         xmlFree(str);
00610                                 }
00611                                 
00612                                 if (!xmlStrcmp(filternode->name, (const xmlChar *)"destmember")) {
00613                                         char *str = (char*)xmlNodeListGetString(doc, filternode->xmlChildrenNode, 1);
00614                                         if (!str) {
00615                                                 filternode = filternode->next;
00616                                                 continue;
00617                                         }
00618                                         filter->destmemberid = atoll(str);
00619                                         xmlFree(str);
00620                                 }
00621                                 
00622                                 if (!xmlStrcmp(filternode->name, (const xmlChar *)"action")) {
00623                                         char *str = (char*)xmlNodeListGetString(doc, filternode->xmlChildrenNode, 1);
00624                                         if (!str) {
00625                                                 filternode = filternode->next;
00626                                                 continue;
00627                                         }
00628                                         filter->action = atoi(str);
00629                                         xmlFree(str);
00630                                 }
00631                                 filternode = filternode->next;
00632                         }
00633                         osync_filter_register(group, filter);
00634                 }
00635                 cur = cur->next;
00636         }
00637         xmlFreeDoc(doc);
00638         g_free(filename);
00639         
00640         //Check for sanity
00641         if (!group->name) {
00642                 osync_error_set(error, OSYNC_ERROR_MISCONFIGURATION, "Loaded a group without a name");
00643                 osync_debug("OSGRP", 0, "Loaded a group without a name");
00644                 osync_group_free(group);
00645                 osync_trace(TRACE_EXIT_ERROR, "osync_group_load");
00646                 return NULL;
00647         }
00648         
00649         if (!osync_group_load_members(group, real_path, error)) {
00650                 osync_group_free(group);
00651                 osync_trace(TRACE_EXIT_ERROR, "osync_group_load");
00652                 return NULL;
00653         }
00654         
00655         osync_trace(TRACE_EXIT, "osync_group_load");
00656         return group;
00657 }
00658 
00667 void osync_group_reset(OSyncGroup *group)
00668 {
00669         OSyncError *error = NULL;
00670         osync_db_reset_group(group, &error);
00671         
00672         GList *m = NULL;
00673         for (m = group->members; m; m = m->next) {
00674                 OSyncMember *member = m->data;
00675                 osync_db_reset_member(member, &error);
00676         }
00677 }
00678 
00687 void osync_group_add_member(OSyncGroup *group, OSyncMember *member)
00688 {
00689         g_assert(group);
00690         group->members = g_list_append(group->members, member);
00691 }
00692 
00699 void osync_group_remove_member(OSyncGroup *group, OSyncMember *member)
00700 {
00701         g_assert(group);
00702         group->members = g_list_remove(group->members, member);
00703 }
00704 
00714 OSyncMember *osync_group_nth_member(OSyncGroup *group, int nth)
00715 {
00716         g_assert(group);
00717         return (OSyncMember *)g_list_nth_data(group->members, nth);
00718 }
00719 
00728 int osync_group_num_members(OSyncGroup *group)
00729 {
00730         g_assert(group);
00731         return g_list_length(group->members);
00732 }
00733 
00742 const char *osync_group_get_configdir(OSyncGroup *group)
00743 {
00744         g_assert(group);
00745         return group->configdir;
00746 }
00747 
00755 void osync_group_set_configdir(OSyncGroup *group, const char *directory)
00756 {
00757         g_assert(group);
00758         if (group->configdir)
00759                 g_free(group->configdir);
00760         group->configdir = g_strdup(directory);
00761 }
00762 
00773 void osync_group_set_slow_sync(OSyncGroup *group, const char *objtypestr, osync_bool slow_sync)
00774 {
00775         osync_trace(TRACE_ENTRY, "%s(%p, %s, %i)", __func__, group, objtypestr, slow_sync);
00776         
00777         g_assert(group);
00778         OSyncFormatEnv *conv_env = group->conv_env;
00779 
00780         //FIXME Remove the slow_sync bool since you are not allowed to reset
00781         //the slow-sync manually anyways.
00782         
00783         //FIXME Race Condition!!!
00784         if (!osync_group_get_slow_sync(group, objtypestr)) {
00785                 if (osync_conv_objtype_is_any(objtypestr)) {
00786                         GList *element;
00787                         for (element = conv_env->objtypes; element; element = element->next) {
00788                                 OSyncObjType *objtype = element->data;
00789                                 objtype->needs_slow_sync = slow_sync;
00790                         }
00791                 } else {
00792                         OSyncObjType *objtype = osync_conv_find_objtype(conv_env, objtypestr);
00793                         g_assert(objtype);
00794                         objtype->needs_slow_sync = slow_sync;
00795                 }
00796         }
00797         
00798         osync_trace(TRACE_EXIT, "%s", __func__);
00799 }
00800 
00809 void osync_group_reset_slow_sync(OSyncGroup *group, const char *objtypestr)
00810 {
00811         osync_trace(TRACE_ENTRY, "%s(%p, %s)", __func__, group, objtypestr);
00812         g_assert(group);
00813         OSyncFormatEnv *conv_env = group->conv_env;
00814 
00815         if (osync_conv_objtype_is_any(objtypestr)) {
00816                 GList *element;
00817                 for (element = conv_env->objtypes; element; element = element->next) {
00818                         OSyncObjType *objtype = element->data;
00819                         objtype->needs_slow_sync = FALSE;
00820                 }
00821         } else {
00822                 OSyncObjType *objtype = osync_conv_find_objtype(conv_env, objtypestr);
00823                 g_assert(objtype);
00824                 objtype->needs_slow_sync = FALSE;
00825         }
00826         
00827         osync_trace(TRACE_EXIT, "%s", __func__);
00828 }
00829 
00839 osync_bool osync_group_get_slow_sync(OSyncGroup *group, const char *objtype)
00840 {
00841         osync_trace(TRACE_ENTRY, "%s(%p, %s)", __func__, group, objtype);
00842         
00843         g_assert(group);
00844         OSyncFormatEnv *env = group->conv_env;
00845         g_assert(env);
00846         
00847         OSyncObjType *osync_objtype = osync_conv_find_objtype(env, "data");
00848         if (osync_objtype && osync_objtype->needs_slow_sync) {
00849                 osync_trace(TRACE_EXIT, "%s: Data objtype needs slow-sync", __func__);
00850                 return TRUE;
00851         }
00852         osync_objtype = osync_conv_find_objtype(env, objtype);
00853         g_assert(osync_objtype);
00854         
00855         osync_trace(TRACE_EXIT, "%s: %i", __func__, osync_objtype->needs_slow_sync);
00856         return osync_objtype->needs_slow_sync;
00857 }
00858 
00870 osync_bool osync_group_objtype_enabled(OSyncGroup *group, const char *objtype)
00871 {
00872         //FIXME We should actually return a 3-state here.
00873         //0 if none is enabled
00874         //"0.5" if some are enabled, some are not
00875         //1 if all are enabled
00876         g_assert(group);
00877         GList *m;
00878         for (m = group->members; m; m = m->next) {
00879                 OSyncMember *member = m->data;
00880                 if (osync_member_objtype_enabled(member, objtype))
00881                         return TRUE;
00882         }
00883         return FALSE;
00884 }
00885 
00899 void osync_group_set_objtype_enabled(OSyncGroup *group, const char *objtypestr, osync_bool enabled)
00900 {
00901         g_assert(group);
00902         GList *m;
00903         for (m = group->members; m; m = m->next) {
00904                 OSyncMember *member = m->data;
00905 
00906                 /*TODO: What this function should do if we don't have
00907                  *      any objtype sink information?
00908                  *      It can't return error currently. We should either
00909                  *      require that the plugin is instanced, or change the function
00910                  *      interface. As changing the function interface require more
00911                  *      care, currently the function is marked as requiring the plugin to be instanced
00912                  */
00913                 if (!osync_member_require_sink_info(member, NULL)) {
00914                         osync_debug("OSGRP", 0, "%s: No sink information, can't load plugin, and I can't return error");
00915                         continue;
00916                 }
00917 
00918                 osync_member_set_objtype_enabled(member, objtypestr, enabled);
00919         }
00920 }
00921 
00928 int osync_group_num_filters(OSyncGroup *group)
00929 {
00930         g_assert(group);
00931         return g_list_length(group->filters);
00932 }
00933 
00944 OSyncFilter *osync_group_nth_filter(OSyncGroup *group, int nth)
00945 {
00946         g_assert(group);
00947         return g_list_nth_data(group->filters, nth);
00948 }
00949 
00954 void osync_group_flush_filters(OSyncGroup *group)
00955 {
00956         g_assert(group);
00957         while (group->filters) {
00958                 OSyncFilter *f = g_list_nth_data(group->filters, 0);
00959                 osync_filter_free(f);
00960 
00961                 /* Delete the first item */
00962                 group->filters = g_list_delete_link(group->filters, group->filters);
00963         }
00964 }
00965 
00976 osync_bool osync_group_open_changelog(OSyncGroup *group, char ***uids, char ***objtype, long long int **memberids, int **changetypes, OSyncError **error)
00977 {
00978         return osync_db_open_changelog(group, uids, objtype, memberids, changetypes, error);
00979 }
00980 
00988 osync_bool osync_group_save_changelog(OSyncGroup *group, OSyncChange *change, OSyncError **error)
00989 {
00990         return osync_db_save_changelog(group, change, error);
00991 }
00992 
01000 osync_bool osync_group_remove_changelog(OSyncGroup *group, OSyncChange *change, OSyncError **error)
01001 {
01002         return osync_db_remove_changelog(group, change, error);
01003 }
01004 
01012 void osync_group_set_last_synchronization(OSyncGroup *group, time_t last_sync)
01013 {
01014         osync_trace(TRACE_ENTRY, "%s(%p, not shown)", __func__, last_sync);
01015         osync_assert_msg(group, "Group missing");
01016         
01017         group->last_sync = last_sync;
01018                
01019         osync_trace(TRACE_EXIT, "%s", __func__);
01020 }
01021 
01029 time_t osync_group_get_last_synchronization(OSyncGroup *group)
01030 {
01031         osync_assert_msg(group, "Group missing");
01032         return group->last_sync;
01033 }
01034