OpenSync  0.22
osengine_mapcmds.c
1 /*
2  * libosengine - A synchronization engine for the opensync framework
3  * Copyright (C) 2004-2005 Armin Bauer <armin.bauer@opensync.org>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  *
19  */
20 
21 #include "engine.h"
22 #include "engine_internals.h"
23 
28 
29 static OSyncMappingEntry *_osync_find_next_diff(OSyncMapping *mapping, OSyncMappingEntry *orig_entry)
30 {
31  GList *e;
32  for (e = mapping->entries; e; e = e->next) {
33  OSyncMappingEntry *entry = e->data;
34  if (osync_change_get_changetype(entry->change) == CHANGE_UNKNOWN)
35  continue;
36  if ((entry->change != orig_entry->change) && osync_change_compare(orig_entry->change, entry->change) != CONV_DATA_SAME)
37  return entry;
38  }
39  osync_debug("MAP", 3, "Could not find next diff");
40  return NULL;
41 }
42 
43 static OSyncMappingEntry *_osync_find_next_same(OSyncMapping *mapping, OSyncMappingEntry *orig_entry)
44 {
45  GList *e;
46  for (e = mapping->entries; e; e = e->next) {
47  OSyncMappingEntry *entry = e->data;
48  if (osync_change_get_changetype(entry->change) == CHANGE_UNKNOWN)
49  continue;
50  if ((entry->change != orig_entry->change) && osync_change_compare(orig_entry->change, entry->change) == CONV_DATA_SAME)
51  return entry;
52  }
53  osync_debug("MAP", 3, "Could not find next diff");
54  return NULL;
55 }
56 
57 static OSyncMappingEntry *_osync_change_clone(OSyncEngine *engine, OSyncMapping *new_mapping, OSyncMappingEntry *comp_entry)
58 {
59  OSyncMappingEntry *newentry = osengine_mappingentry_new(NULL);
60  newentry->change = osync_change_new();
61  newentry->client = comp_entry->client;
62  osengine_mapping_add_entry(new_mapping, newentry);
63  osengine_mappingview_add_entry(comp_entry->view, newentry);
64  osengine_mappingentry_update(newentry, comp_entry->change);
65  osync_change_set_uid(newentry->change, osync_change_get_uid(comp_entry->change));
66  osync_flag_set(newentry->fl_has_data);
67  osync_flag_set(newentry->fl_mapped);
68  osync_flag_set(newentry->fl_has_info);
69  osync_flag_set(newentry->fl_dirty);
70  osync_flag_unset(newentry->fl_synced);
71  osync_change_save(newentry->change, TRUE, NULL);
72  return newentry;
73 }
74 
75 osync_bool osync_change_elevate(OSyncEngine *engine, OSyncChange *change, int level)
76 {
77  osync_debug("MAP", 3, "elevating change %s (%p) to level %i", osync_change_get_uid(change), change, level);
78  int i = 0;
79  for (i = 0; i < level; i++) {
80  if (!osync_change_duplicate(change))
81  return FALSE;
82  }
83  osync_debug("MAP", 3, "change after being elevated %s (%p)", osync_change_get_uid(change), change);
84  osync_change_save(change, TRUE, NULL);
85  return TRUE;
86 }
87 
88 osync_bool osync_change_check_level(OSyncEngine *engine, OSyncMappingEntry *entry)
89 {
90  GList *c;
91  osync_debug("MAP", 3, "checking level for change %s (%p)", osync_change_get_uid(entry->change), entry);
92  for (c = engine->clients; c; c = c->next) {
93  OSyncClient *client = c->data;
94  OSyncMappingView *view = osengine_mappingtable_find_view(engine->maptable, client->member);
95  if (!osengine_mappingview_uid_is_unique(view, entry, TRUE))
96  return FALSE;
97  }
98  return TRUE;
99 }
100 
101 static int prod(int n)
102 {
103  int ret;
104  for (ret = 0; n > 0; n--)
105  ret += n;
106  return ret;
107 }
108 
109 void osengine_mapping_multiply_master(OSyncEngine *engine, OSyncMapping *mapping)
110 {
111  osync_trace(TRACE_ENTRY, "%s(%p, %p)", __func__, engine, mapping);
112  g_assert(engine);
113 
114  OSyncMappingTable *table = engine->maptable;
115  OSyncMappingEntry *entry = NULL;
116  OSyncMappingEntry *master = NULL;
117 
118  master = mapping->master;
119  g_assert(master);
120  if (osync_flag_is_not_set(master->fl_dirty))
121  osync_flag_set(master->fl_synced);
122  else
123  osync_flag_attach(master->fl_committed, table->engine->cmb_committed_all);
124 
125  //Send the change to every source that is different to the master source and set state to writing in the changes
126  GList *v;
127  for (v = table->views; v; v = v->next) {
128  OSyncMappingView *view = v->data;
129  //Check if this client is already listed in the mapping
130  entry = osengine_mapping_find_entry(mapping, NULL, view);
131  if (entry == master)
132  continue;
133  if (entry && (osync_change_compare(entry->change, master->change) == CONV_DATA_SAME)) {
134  if (osync_flag_is_not_set(entry->fl_dirty))
135  osync_flag_set(entry->fl_synced);
136  continue;
137  }
138  if (!entry) {
139  entry = osengine_mappingentry_new(NULL);
140  entry->change = osync_change_new();
141  entry->client = view->client;
142  osengine_mappingview_add_entry(view, entry);
143  osengine_mappingentry_update(entry, master->change);
144  osync_change_set_uid(entry->change, osync_change_get_uid(master->change));
145  osync_change_set_member(entry->change, view->client->member);
146  osengine_mapping_add_entry(mapping, entry);
147  } else {
148  osync_bool had_data = osync_change_has_data(entry->change);
149  osengine_mappingentry_update(entry, master->change);
150  if (osync_change_get_changetype(entry->change) == CHANGE_ADDED || osync_change_get_changetype(entry->change) == CHANGE_UNKNOWN) {
152  }
153 
154  if (osync_member_get_slow_sync(view->client->member, osync_objtype_get_name(osync_change_get_objtype(entry->change))) && !had_data) {
156  }
157  }
158  if (osync_flag_is_set(view->client->fl_sent_changes)) {
159  //osync_change_flags_attach(change, mapping);
160  osync_flag_set(entry->fl_dirty);
161  osync_flag_set(entry->fl_has_data);
162  osync_flag_set(entry->fl_mapped);
163  osync_flag_set(entry->fl_has_info);
164  osync_flag_unset(entry->fl_synced);
165  OSyncError *error = NULL;
166  osync_change_save(entry->change, TRUE, &error);
167  osync_flag_attach(entry->fl_committed, table->engine->cmb_committed_all);
168  }
169  }
170 
171  OSyncError *error = NULL;
172  osync_change_save(master->change, TRUE, &error);
173 
174  osync_flag_set(mapping->fl_multiplied);
175  osync_trace(TRACE_EXIT, "%s", __func__);
176 }
177 
178 
179 
180 void osengine_mapping_check_conflict(OSyncEngine *engine, OSyncMapping *mapping)
181 {
182  osync_trace(TRACE_ENTRY, "%s(%p, %p)", __func__, engine, mapping);
183  GList *e;
184  GList *n;
185  osync_bool is_conflict = FALSE;
186  int is_same = 0;
187  OSyncMappingEntry *leftentry = NULL;
188  OSyncMappingEntry *rightentry = NULL;
189 
190  g_assert(engine != NULL);
191  g_assert(mapping != NULL);
192  g_assert(!mapping->master);
193 
194  for (e = mapping->entries; e; e = e->next) {
195  leftentry = e->data;
196  if (osync_change_get_changetype(leftentry->change) == CHANGE_UNKNOWN)
197  continue;
198  mapping->master = leftentry;
199  for (n = e->next; n; n = n->next) {
200  rightentry = n->data;
201  if (osync_change_get_changetype(rightentry->change) == CHANGE_UNKNOWN)
202  continue;
203 
204  if (osync_change_compare(leftentry->change, rightentry->change) != CONV_DATA_SAME) {
205  is_conflict = TRUE;
206  goto conflict;
207  } else {
208  is_same++;
209  }
210  }
211  }
212 
213  conflict:
214  if (is_conflict) {
215  //conflict, solve conflict
216  osync_debug("MAP", 2, "Got conflict for mapping %p", mapping);
217  osync_status_conflict(engine, mapping);
218  osync_flag_set(mapping->fl_chkconflict);
219  osync_trace(TRACE_EXIT, "%s: Got conflict", __func__);
220  return;
221  }
222  g_assert(mapping->master);
223  osync_flag_set(mapping->fl_chkconflict);
224 
225  //Our mapping is already solved since there is no conflict
226  osync_flag_set(mapping->fl_solved);
227 
228  if (is_same == prod(g_list_length(engine->maptable->views) - 1)) {
229  osync_trace(TRACE_INTERNAL, "No need to sync. All entries are the same");
230  osync_flag_set(mapping->cmb_synced);
231  osync_flag_set(mapping->fl_multiplied);
232  }
233 
234  send_mapping_changed(engine, mapping);
235  osync_trace(TRACE_EXIT, "%s: No conflict", __func__);
236 }
237 
238 static OSyncMapping *_osengine_mapping_find(OSyncMappingTable *table, OSyncMappingEntry *orig_entry)
239 {
240  GList *i;
241  GList *n;
242  osync_bool mapping_found = FALSE;
243 
244  for (i = table->mappings; i; i = i->next) {
245  OSyncMapping *mapping = i->data;
246  //We only need mapping where our member isnt listed yet.
247  if (!osengine_mapping_find_entry(mapping, NULL, orig_entry->view)) {
248  mapping_found = TRUE;
249  for (n = mapping->entries; n; n = n->next) {
250  OSyncMappingEntry *entry = n->data;
251  if (osync_change_compare_data(entry->change, orig_entry->change) == CONV_DATA_MISMATCH) {
252  mapping_found = FALSE;
253  continue;
254  }
255  }
256  if (mapping_found)
257  return mapping;
258  }
259  }
260  return NULL;
261 }
262 
263 void osengine_change_map(OSyncEngine *engine, OSyncMappingEntry *entry)
264 {
265  osync_trace(TRACE_ENTRY, "osengine_change_map(%p, %p)", engine, entry);
266  OSyncMapping *mapping = NULL;
267  if (!(mapping = _osengine_mapping_find(engine->maptable, entry))) {
268  mapping = osengine_mapping_new(engine->maptable);
269  osync_flag_unset(mapping->fl_chkconflict);
270  osync_flag_unset(mapping->fl_multiplied);
271  mapping->id = osengine_mappingtable_get_next_id(engine->maptable);
272  osync_trace(TRACE_INTERNAL, "No previous mapping found. Creating new one: %p", mapping);
273  }
274  osengine_mapping_add_entry(mapping, entry);
275  osync_flag_set(entry->fl_mapped);
276  osync_change_save(entry->change, FALSE, NULL);
277  osync_trace(TRACE_EXIT, "osengine_change_map");
278 }
279 
289 
296 void osengine_mapping_duplicate(OSyncEngine *engine, OSyncMapping *dupe_mapping)
297 {
298  osync_trace(TRACE_ENTRY, "osengine_mapping_duplicate(%p, %p)", engine, dupe_mapping);
299  g_assert(dupe_mapping);
300  int elevation = 0;
301  OSyncMappingEntry *orig_entry = NULL;
302  OSyncMappingEntry *first_diff_entry = NULL;
303  OSyncMappingEntry *next_entry = NULL;
304  OSyncMapping *new_mapping = NULL;
305 
306  //Remove all deleted items first.
307  GList *entries, *e;
308  entries = g_list_copy(dupe_mapping->entries);
309  for (e = entries; e; e = e->next) {
310  OSyncMappingEntry *entry = e->data;
311  if (osync_change_get_changetype(entry->change) == CHANGE_DELETED) {
312  osync_change_delete(entry->change, NULL);
313  osengine_mappingentry_free(entry);
314  }
315  }
316  g_list_free(entries);
317 
318  //Choose the first modified change as the master of the mapping to duplicate
319  GList *i = dupe_mapping->entries;
320  do {
321  orig_entry = i->data;
322  i = i->next;
323  } while (osync_change_get_changetype(orig_entry->change) != CHANGE_MODIFIED && osync_change_get_changetype(orig_entry->change) != CHANGE_ADDED);
324  dupe_mapping->master = orig_entry;
325  osync_change_set_changetype(orig_entry->change, CHANGE_MODIFIED);
326 
327  /* Now we go through the list of changes in the mapping to
328  * duplicate and search for the next entry that is different
329  * to our choosen master. This entry then has to be moved to a
330  * new mapping along with all changes to are the same as this next
331  * different change
332  */
333  while ((first_diff_entry = _osync_find_next_diff(dupe_mapping, orig_entry))) {
334  //We found a different change
335  elevation = 0;
336  new_mapping = osengine_mapping_new(engine->maptable);
337  new_mapping->id = osengine_mappingtable_get_next_id(engine->maptable);
338  osync_flag_unset(new_mapping->cmb_synced);
339  osync_flag_set(new_mapping->fl_chkconflict);
340  osync_flag_unset(new_mapping->fl_multiplied);
341  osync_flag_set(new_mapping->fl_solved);
342  send_mapping_changed(engine, new_mapping);
343  osync_debug("MAP", 3, "Created new mapping for duplication %p with mappingid %lli", new_mapping, new_mapping->id);
344 
345  /* Now we copy the change that differs, and set it as the master of the new
346  * mapping.*/
347  OSyncMappingEntry *newentry = osengine_mappingentry_copy(first_diff_entry);
348  new_mapping->master = newentry;
349  osengine_mapping_add_entry(new_mapping, newentry);
350  osync_change_set_changetype(newentry->change, CHANGE_ADDED);
351  osync_flag_set(newentry->fl_has_data);
352  osync_flag_set(newentry->fl_mapped);
353  osync_flag_set(newentry->fl_has_info);
354  osync_flag_set(newentry->fl_dirty);
355  osync_flag_unset(newentry->fl_synced);
356 
357  /* Now we elevate the change (which might be done by adding a -dupe
358  * or a (2) to the change uid. We then check if there is already
359  * another change on this level and if there is, we elevate again */
360  do {
361  if (!osync_change_elevate(engine, newentry->change, 1))
362  break;
363  elevation += 1;
364  } while (!osync_change_check_level(engine, newentry));
365  OSyncError *error = NULL;
366  osync_change_save(newentry->change, TRUE, &error);
367 
368  /* Now we search for all changes to belong to the new mapping, so
369  * we are searching for changes to do not differ from the change we found
370  * to be different from the master of the mapping to duplicate */
371  while ((next_entry = _osync_find_next_same(dupe_mapping, first_diff_entry))) {
372  newentry = _osync_change_clone(engine, new_mapping, first_diff_entry);
373  osync_change_elevate(engine, newentry->change, elevation);
374  osengine_mappingentry_update(orig_entry, next_entry->change);
375  osync_change_save(next_entry->change, TRUE, NULL);
376  }
377 
378  /* Now we can reset the different change and prepare it for
379  * being overwriten during mulitply_master */
380  osync_change_set_changetype(first_diff_entry->change, CHANGE_UNKNOWN);
381 
382  //We can now add the new mapping into the queue so it get processed
383  send_mapping_changed(engine, new_mapping);
384  }
385 
386  //Multiply our original mapping
387  osync_flag_set(dupe_mapping->fl_solved);
388  send_mapping_changed(engine, dupe_mapping);
389  osync_trace(TRACE_EXIT, "osengine_mapping_duplicate");
390 }
391 
401 void osengine_mapping_solve(OSyncEngine *engine, OSyncMapping *mapping, OSyncChange *change)
402 {
403  osync_trace(TRACE_ENTRY, "osengine_mapping_solve(%p, %p, %p)", engine, mapping, change);
404  OSyncMappingEntry *entry = osengine_mapping_find_entry(mapping, change, NULL);
405  mapping->master = entry;
406  osync_flag_set(mapping->fl_solved);
407  send_mapping_changed(engine, mapping);
408  osync_trace(TRACE_EXIT, "osengine_mapping_solve");
409 }
410 
420 osync_bool osengine_mapping_ignore_conflict(OSyncEngine *engine, OSyncMapping *mapping, OSyncError **error)
421 {
422  osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, engine, mapping, error);
423 
424  if (!osengine_mapping_ignore_supported(engine, mapping)) {
425  osync_error_set(error, OSYNC_ERROR_GENERIC, "Ignore is not supported for this mapping");
426  osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
427  return FALSE;
428  }
429 
430  GList *e = NULL;
431  for (e = mapping->entries; e; e = e->next) {
432  OSyncMappingEntry *entry = e->data;
433  osync_trace(TRACE_INTERNAL, "Adding %p to logchanges", entry);
434  OSyncError *error = NULL;
435  if (osync_change_get_changetype(entry->change) != CHANGE_UNKNOWN)
436  osync_group_save_changelog(engine->group, entry->change, &error);
437  }
438 
439  //And make sure we dont synchronize it this time
440  //osengine_mapping_reset(mapping);
441  osync_flag_set(mapping->fl_multiplied);
442  osync_flag_set(mapping->cmb_synced);
443  osync_flag_set(mapping->cmb_has_info);
444  osync_trace(TRACE_EXIT, "%s", __func__);
445  return TRUE;
446 }
447 
461 osync_bool osengine_mapping_ignore_supported(OSyncEngine *engine, OSyncMapping *mapping)
462 {
463  osync_trace(TRACE_ENTRY, "%s(%p, %p)", __func__, engine, mapping);
464 
465  int i, count = 0;
466  OSyncChange *change = NULL;
467  OSyncMember *member = NULL;
468  OSyncObjType *objtype = NULL;
469 
470  count = osengine_mapping_num_changes(mapping);
471  for (i = 0; i < count; ++i) {
472  change = osengine_mapping_nth_change(mapping, i);
473  objtype = osync_change_get_objtype(change);
474 
475  member = osync_change_get_member(change);
476 
477  if (!osync_member_has_read_function(member, objtype)) {
478  osync_trace(TRACE_EXIT, "%s: Ignore NOT supported", __func__);
479  return FALSE;
480  }
481  }
482 
483  osync_trace(TRACE_EXIT, "%s: Ignore supported", __func__);
484  return TRUE;
485 }
486 
499 osync_bool osengine_mapping_solve_latest(OSyncEngine *engine, OSyncMapping *mapping, OSyncError **error)
500 {
501  osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, engine, mapping, error);
502 
503  time_t time = 0;
504  time_t latesttime = 0;
505  osync_bool preveq = FALSE;
506 
507  GList *e = NULL;
508  for (e = mapping->entries; e; e = e->next) {
509  OSyncMappingEntry *entry = e->data;
510 
511  if (osync_change_get_changetype(entry->change) != CHANGE_UNKNOWN) {
512  time = osync_change_get_revision(entry->change, error);
513  if (time == -1) {
514  osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
515  mapping->master = NULL;
516  return FALSE;
517  }
518 
519  if (time > latesttime) {
520  latesttime = time;
521  mapping->master = entry;
522  preveq = FALSE;
523  } else if (time == latesttime)
524  preveq = TRUE;
525  }
526  }
527 
528  if (preveq == TRUE) {
529  osync_error_set(error, OSYNC_ERROR_GENERIC, "Could not decide for one entry. Timestamps where equal");
530  mapping->master = NULL;
531  osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
532  return FALSE;
533  }
534 
535  osync_flag_set(mapping->fl_solved);
536  send_mapping_changed(engine, mapping);
537 
538  osync_trace(TRACE_EXIT, "%s: %p", __func__, mapping->master);
539  return TRUE;
540 }
541 
554 osync_bool osengine_mapping_check_timestamps(OSyncEngine *engine, OSyncMapping *mapping, OSyncError **error)
555 {
556  osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, engine, mapping, error);
557 
558  time_t time = 0;
559  time_t latesttime = 0;
560  osync_bool preveq = FALSE;
561 
562  GList *e = NULL;
563  for (e = mapping->entries; e; e = e->next) {
564  OSyncMappingEntry *entry = e->data;
565 
566  if (osync_change_get_changetype(entry->change) != CHANGE_UNKNOWN) {
567  time = osync_change_get_revision(entry->change, error);
568  if (time == -1) {
569  osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
570  return FALSE;
571  }
572 
573  if (time > latesttime) {
574  latesttime = time;
575  preveq = FALSE;
576  } else if (time == latesttime)
577  preveq = TRUE;
578  }
579  }
580 
581  if (preveq == TRUE) {
582  osync_error_set(error, OSYNC_ERROR_GENERIC, "Could not decide for one entry. Timestamps where equal");
583  osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
584  return FALSE;
585  }
586 
587  osync_trace(TRACE_EXIT, "%s", __func__);
588  return TRUE;
589 }
590 
601 void osengine_mapping_solve_updated(OSyncEngine *engine, OSyncMapping *mapping, OSyncChange *change)
602 {
603  osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, engine, mapping, change);
604  OSyncMappingEntry *entry = osengine_mapping_find_entry(mapping, change, NULL);
605  mapping->master = entry;
606 
607  osync_flag_set(entry->fl_dirty);
608  osync_flag_unset(entry->fl_synced);
609  send_mappingentry_changed(engine, entry);
610 
611  osync_flag_set(mapping->fl_solved);
612  send_mapping_changed(engine, mapping);
613  osync_trace(TRACE_EXIT, "%s", __func__);
614 }
615 
OSyncChangeType osync_change_get_changetype(OSyncChange *change)
Gets the changetype of a change.
osync_bool osync_change_duplicate(OSyncChange *change)
Duplicates the uid of the change.
void osengine_mapping_solve_updated(OSyncEngine *engine, OSyncMapping *mapping, OSyncChange *change)
Solves a mapping by setting an updated change.
osync_bool osengine_mapping_ignore_conflict(OSyncEngine *engine, OSyncMapping *mapping, OSyncError **error)
Ignores a conflict.
osync_bool osync_member_get_slow_sync(OSyncMember *member, const char *objtypestr)
Returns if slow-sync has been set for a object type.
Represent an error.
void osync_change_set_uid(OSyncChange *change, const char *uid)
Sets the uid of a change.
osync_bool osync_member_has_read_function(OSyncMember *member, OSyncObjType *objtype)
Checks if the member has a read method for the given objtype.
OSyncChange * osync_change_new(void)
Spawns a new change object.
osync_bool osync_group_save_changelog(OSyncGroup *group, OSyncChange *change, OSyncError **error)
Saves a change to the changelog.
const char * osync_change_get_uid(OSyncChange *change)
Gets the uid of a change.
osync_bool osync_change_has_data(OSyncChange *change)
Returns wether the complete data already has been set.
A member of a group which represent a single device.
void osengine_mapping_duplicate(OSyncEngine *engine, OSyncMapping *dupe_mapping)
Solves the conflict by duplicating the conflicting entries.
void osync_change_set_changetype(OSyncChange *change, OSyncChangeType type)
Sets the changetype of a change.
osync_bool osengine_mapping_solve_latest(OSyncEngine *engine, OSyncMapping *mapping, OSyncError **error)
Solves a mapping by choosing the entry that was last modified.
void osync_debug(const char *subpart, int level, const char *message,...)
Used for debugging.
osync_bool osengine_mapping_ignore_supported(OSyncEngine *engine, OSyncMapping *mapping)
Checks if a conflict can be ignore.
OSyncMember * osync_change_get_member(OSyncChange *change)
Gets the member which reported a change.
A change object.
time_t osync_change_get_revision(OSyncChange *change, OSyncError **error)
Returns the revision of the object.
void osync_change_set_member(OSyncChange *change, OSyncMember *member)
Sets the member of a change.
osync_bool osengine_mapping_check_timestamps(OSyncEngine *engine, OSyncMapping *mapping, OSyncError **error)
Checks if the mapping could be solved with solve_latest.
void osync_error_set(OSyncError **error, OSyncErrorType type, const char *format,...)
Sets the error.
const char * osync_error_print(OSyncError **error)
Returns the message of the error.
void osync_trace(OSyncTraceType type, const char *message,...)
Used for tracing the application.
void osengine_mapping_solve(OSyncEngine *engine, OSyncMapping *mapping, OSyncChange *change)
Solves the mapping by choosing a winner.
const char * osync_objtype_get_name(OSyncObjType *type)
Returns the name of a object type.
OSyncObjType * osync_change_get_objtype(OSyncChange *change)
Gets the object type of a change.
Represent a abstract object type (like "contact")
osync_bool osync_change_delete(OSyncChange *change, OSyncError **error)
This will delete a change from the database.
OSyncConvCmpResult osync_change_compare(OSyncChange *leftchange, OSyncChange *rightchange)
Compares 2 changes.
OSyncConvCmpResult osync_change_compare_data(OSyncChange *leftchange, OSyncChange *rightchange)
Compares the data of 2 changes.
osync_bool osync_change_save(OSyncChange *change, osync_bool save_format, OSyncError **error)
This will save a change into the database.