static void *initialize(OSyncPlugin *plugin, OSyncPluginInfo *info, OSyncError **error)
{
	OSyncList *sinks, *s;
	OSyncPluginConfig *config;

	osync_trace(TRACE_ENTRY, "%s(%p, %p)", __func__, info, error);

	printf("[EXTERNAL-DEMO]: %s\n", __func__);

	/*
	 * get the config
	 */
	config = osync_plugin_info_get_config(info);
	if (!config) {
		osync_error_set(error, OSYNC_ERROR_GENERIC, "Unable to get config.");
		goto error;
	}

	sinks = osync_plugin_info_get_objtype_sinks(info);
	for (s = sinks; s; s = s->next) {
		OSyncObjTypeSink *sink = s->data;

		/* Here you register all your objtype sink functions ... */
		osync_objtype_sink_set_get_changes_func(sink, get_changes);
		/* You can also add sink function for
		 * - connect()
		 * - disconnect()
		 * - commit()
		 * - sync_done()
		 * - ...
		 */
	}

	osync_trace(TRACE_EXIT, "%s: %p", __func__, NULL);
	return (void *) NULL;

error:
	osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
	return NULL;
}
示例#2
0
int osync_db_table_exists(OSyncDB *db, const char *tablename, OSyncError **error)
{
	sqlite3_stmt *ppStmt = NULL;
	char *query = NULL;

	osync_trace(TRACE_ENTRY, "%s(%p, %s, %p)", __func__, db, tablename, error);

	osync_assert(db);
	osync_assert(tablename);

	query = osync_strdup_printf("SELECT name FROM (SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE type='table' AND name='%s'",
	                        tablename);

	if (sqlite3_prepare(db->sqlite3db, query, -1, &ppStmt, NULL) != SQLITE_OK) {
		sqlite3_finalize(ppStmt);
		osync_free(query);

		osync_error_set(error, OSYNC_ERROR_GENERIC, "Query Error: %s", sqlite3_errmsg(db->sqlite3db));
		osync_trace(TRACE_EXIT_ERROR, "Database query error: %s", sqlite3_errmsg(db->sqlite3db));
		return -1;
	}


	if (sqlite3_step(ppStmt) != SQLITE_ROW) {
		sqlite3_finalize(ppStmt);
		osync_free(query);

		osync_trace(TRACE_EXIT, "%s: table \"%s\" doesn't exist.", __func__, tablename);
		return 0;
	}

	sqlite3_finalize(ppStmt);
	osync_free(query);
	
	osync_trace(TRACE_EXIT, "%s: table \"%s\" exists.", __func__, tablename);
	return 1;
}
static int _osync_queue_write_data(OSyncQueue *queue, const void *vptr, size_t n, OSyncError **error)
{
#ifdef _WIN32
  return FALSE;
#else //_WIN32

  ssize_t nwritten = 0;

  while (n > 0) {
    if ((nwritten = write(queue->fd, vptr, n)) <= 0) {
      if (errno == EINTR)
        nwritten = 0;  /* and call write() again */
      else {
        osync_error_set(error, OSYNC_ERROR_IO_ERROR, "Unable to write IPC data: %i: %s", errno, g_strerror(errno));
        return (-1);  /* error */
      }
    }
		
    n -= nwritten;
    vptr += nwritten;
  }
  return (nwritten);
#endif //_WIN32
}
/*! @brief Loads a group from a directory
 * 
 * Loads a group from a directory
 * 
 * @param group The group object to load into
 * @param path The path to the config directory of the group
 * @param error Pointer to an error struct
 * @returns TRUE on success, FALSE otherwise
 * 
 */
osync_bool osync_group_load(OSyncGroup *group, const char *path, OSyncError **error)
{
  char *filename = NULL;
  char *real_path = NULL;
  xmlDocPtr doc;
  xmlNodePtr cur;
  //xmlNodePtr filternode;
	
  osync_assert(group);
  osync_assert(path);
  osync_trace(TRACE_ENTRY, "%s(%p, %s, %p)", __func__, group, path, error);
	
  if (!g_path_is_absolute(path)) {
    char *curdir = g_get_current_dir();
    real_path = g_strdup_printf("%s%c%s", curdir, G_DIR_SEPARATOR, path);
    g_free(curdir);
  } else {
    real_path = g_strdup(path);
  }
	
  osync_group_set_configdir(group, real_path);
  filename = g_strdup_printf("%s%csyncgroup.conf", real_path, G_DIR_SEPARATOR);
  g_free(real_path);
	
  if (!osync_xml_open_file(&doc, &cur, filename, "syncgroup", error)) {
    g_free(filename);
    goto error;
  }
  g_free(filename);
	
  while (cur != NULL) {
    char *str = (char*)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
    if (str) {
      if (!xmlStrcmp(cur->name, (const xmlChar *)"groupname"))
        osync_group_set_name(group, str);
	
      if (!xmlStrcmp(cur->name, (const xmlChar *)"last_sync"))
        group->last_sync = (time_t)atoi(str);
			
      //TODO: remove the next 2 lines later
      if (!xmlStrcmp(cur->name, (const xmlChar *)"enable_merger"))
        group->merger_enabled = (!g_ascii_strcasecmp("true", str)) ? TRUE : FALSE;
      //TODO: remove the next 2 lines later
      if (!xmlStrcmp(cur->name, (const xmlChar *)"enable_converter"))
        group->converter_enabled = (!g_ascii_strcasecmp("true", str)) ? TRUE : FALSE;

      if (!xmlStrcmp(cur->name, (const xmlChar *)"merger_enabled"))
        group->merger_enabled = (!g_ascii_strcasecmp("true", str)) ? TRUE : FALSE;

      if (!xmlStrcmp(cur->name, (const xmlChar *)"converter_enabled"))
        group->converter_enabled = (!g_ascii_strcasecmp("true", str)) ? TRUE : FALSE;

      // TODO: reimplement the filter!
      /*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);
        osync_xml_free(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);
        osync_xml_free(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);
        osync_xml_free(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);
        osync_xml_free(str);
        }
        filternode = filternode->next;
        }
        osync_filter_register(group, filter);
        }*/
		
      osync_xml_free(str);
    }
    cur = cur->next;
  }
  osync_xml_free_doc(doc);
	
  /* Check for sanity */
  if (!group->name) {
    osync_error_set(error, OSYNC_ERROR_MISCONFIGURATION, "Loaded a group without a name");
    goto error;
  }
	
  if (!_osync_group_load_members(group, group->configdir, error))
    goto error;
	
  osync_trace(TRACE_EXIT, "%s: %p", __func__, group);
  return TRUE;

 error:
  osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
  return FALSE;
}
/*! @brief Saves the group to disc
 * 
 * Saves the group to disc possibly creating the configdirectory
 * 
 * @param group The group
 * @param error Pointer to an error struct
 * @returns TRUE on success, FALSE otherwise
 * 
 */
osync_bool osync_group_save(OSyncGroup *group, OSyncError **error)
{
  char *filename = NULL;
  int i;
  xmlDocPtr doc;
  char *tmstr = NULL;
  char *version_str = NULL;
	
  osync_trace(TRACE_ENTRY, "%s(%p, %p)", __func__, group, error);
  osync_assert(group);
  osync_assert(group->configdir);
	
  osync_trace(TRACE_INTERNAL, "Trying to open configdirectory %s to save group %s", group->configdir, group->name);
	
  if (!g_file_test(group->configdir, G_FILE_TEST_IS_DIR)) {
    osync_trace(TRACE_INTERNAL, "Creating group configdirectory %s", group->configdir);
    if (g_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%csyncgroup.conf", group->configdir, G_DIR_SEPARATOR);
  osync_trace(TRACE_INTERNAL, "Saving group to file %s", filename);
	
  doc = xmlNewDoc((xmlChar*)"1.0");
  doc->children = xmlNewDocNode(doc, NULL, (xmlChar*)"syncgroup", NULL);

  version_str = g_strdup_printf("%u.%u", OSYNC_GROUP_MAJOR_VERSION, OSYNC_GROUP_MINOR_VERSION);
  xmlSetProp(doc->children, (const xmlChar*)"version", (const xmlChar *)version_str);	
  g_free(version_str);
	
  // TODO: reimplement the filter!
  //The filters
  /*GList *f;
    for (f = group->filters; f; f = f->next) {
    OSyncFilter *filter = f->data;
    xmlNodePtr child = xmlNewChild(doc->children, NULL, (xmlChar*)"filter", NULL);
		
    if (filter->sourcememberid) {
    char *sourcememberid = g_strdup_printf("%lli", filter->sourcememberid);
    xmlNewChild(child, NULL, (xmlChar*)"sourcemember", (xmlChar*)sourcememberid);
    g_free(sourcememberid);
    }
    if (filter->destmemberid) {
    char *destmemberid = g_strdup_printf("%lli", filter->destmemberid);
    xmlNewChild(child, NULL, (xmlChar*)"destmember", (xmlChar*)destmemberid);
    g_free(destmemberid);
    }
    if (filter->sourceobjtype)
    xmlNewChild(child, NULL, (xmlChar*)"sourceobjtype", (xmlChar*)filter->sourceobjtype);
    if (filter->destobjtype)
    xmlNewChild(child, NULL, (xmlChar*)"destobjtype", (xmlChar*)filter->destobjtype);
    if (filter->detectobjtype)
    xmlNewChild(child, NULL, (xmlChar*)"detectobjtype", (xmlChar*)filter->detectobjtype);
    if (filter->action) {
    char *action = g_strdup_printf("%i", filter->action);
    xmlNewChild(child, NULL, (xmlChar*)"action", (xmlChar*)action);
    g_free(action);
    }
    if (filter->function_name)
    xmlNewChild(child, NULL, (xmlChar*)"function_name", (xmlChar*)filter->function_name);
    if (filter->config)
    xmlNewChild(child, NULL, (xmlChar*)"config", (xmlChar*)filter->config);
    }*/

  xmlNewChild(doc->children, NULL, (xmlChar*)"groupname", (xmlChar*)group->name);

  tmstr = g_strdup_printf("%i", (int)group->last_sync);
  xmlNewChild(doc->children, NULL, (xmlChar*)"last_sync", (xmlChar*)tmstr);
  g_free(tmstr);

  xmlNewChild(doc->children, NULL, (xmlChar*)"merger_enabled", (xmlChar*) (group->merger_enabled ? "true" : "false"));
  xmlNewChild(doc->children, NULL, (xmlChar*)"converter_enabled", (xmlChar*) (group->converter_enabled ? "true" : "false"));


  xmlSaveFormatFile(filename, doc, 1);
  osync_xml_free_doc(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;
}
示例#6
0
void claws_mail_event_commit_change(void *userdata, OSyncPluginInfo *info,
																		OSyncContext *ctx, OSyncChange *change)
{
	gboolean retVal;
	gchar *vevent;
	char *uid;
	char *hash;
	char *new_event = NULL;
	OSyncError *error = NULL;

	osync_trace(TRACE_ENTRY, "%s(%p, %p, %p, %p)",
							__func__, userdata, info, ctx, change);
	
	OSyncObjTypeSink *sink = osync_plugin_info_get_sink(info);
	ClawsMailSinkEnv *sinkenv = osync_objtype_sink_get_userdata(sink);
	
	osync_data_get_data(osync_change_get_data(change), &vevent, NULL);

	switch (osync_change_get_changetype(change)) {
		
	case OSYNC_CHANGE_TYPE_DELETED:
		retVal = claws_mail_connect_delete_event(osync_change_get_uid(change));
		if(!retVal) {
			osync_error_set(&error, OSYNC_ERROR_GENERIC,
											"Unable to delete event.");
			goto error;
		}
		break;

	case OSYNC_CHANGE_TYPE_ADDED:
		if((new_event = claws_mail_connect_add_event(vevent)) == NULL) {
			osync_error_set(&error, OSYNC_ERROR_GENERIC, "Unable to write event.");
			goto error;
		}

		/* generate and set hash of entry */
		hash = event_hash(new_event);
		osync_change_set_hash(change, hash);
		g_free(hash);
		g_free(new_event);
		break;
		
	case OSYNC_CHANGE_TYPE_MODIFIED:
		uid = (gchar*) osync_change_get_uid(change);
		new_event = claws_mail_connect_modify_event(uid,vevent);
		if(!new_event) {
			osync_error_set(&error, OSYNC_ERROR_GENERIC,
											"Unable to modify event.");
			goto error;
		}
		hash = event_hash(new_event);
		osync_change_set_hash(change, hash);
		g_free(hash);
		g_free(new_event);
		break;

	default:
		osync_trace(TRACE_INTERNAL, "Unknown change type");
		break;
	}

	/* Calculate the hash */
	osync_hashtable_update_hash(sinkenv->hashtable,
															osync_change_get_changetype(change),
															osync_change_get_uid(change),
															osync_change_get_hash(change));

	/* Answer the call */
	osync_context_report_success(ctx);

	osync_trace(TRACE_EXIT, "%s", __func__);
	return;

 error:

	osync_context_report_osyncerror(ctx, error);
	osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(&error));
	osync_error_unref(&error);
}
示例#7
0
static osync_bool osync_format_env_load_modules(OSyncFormatEnv *env, const char *path, osync_bool must_exist, OSyncError **error)
{
  GDir *dir = NULL;
  GError *gerror = NULL;
  char *filename = NULL;
  OSyncModule *module = NULL;
  const gchar *de = NULL;
  GList *m = NULL;
	
  osync_trace(TRACE_ENTRY, "%s(%p, %s, %i, %p)", __func__, env, path, must_exist, error);
  osync_assert(env);
  osync_assert(path);
	
  //Load all available shared libraries (plugins)
  if (!g_file_test(path, G_FILE_TEST_IS_DIR)) {
    if (must_exist) {
      osync_error_set(error, OSYNC_ERROR_GENERIC, "Path is not loadable");
      goto error;
    } else {
      osync_trace(TRACE_EXIT, "%s: Directory does not exist (non-fatal)", __func__);
      return TRUE;
    }
  }
	
  dir = g_dir_open(path, 0, &gerror);
  if (!dir) {
    osync_error_set(error, OSYNC_ERROR_IO_ERROR, "Unable to open directory %s: %s", path, gerror->message);
    g_error_free(gerror);
    goto error;
  }
	
  while ((de = g_dir_read_name(dir))) {
    filename = g_strdup_printf ("%s%c%s", path, G_DIR_SEPARATOR, de);
		
    if (!g_file_test(filename, G_FILE_TEST_IS_REGULAR) || !g_pattern_match_simple("*."G_MODULE_SUFFIX, filename)) {
      g_free(filename);
      continue;
    }
		
    module = osync_module_new(error);
    if (!module)
      goto error_free_filename;
		
    if (!osync_module_load(module, filename, error)) {
      osync_trace(TRACE_INTERNAL, "Unable to load module %s: %s", filename, osync_error_print(error));
      osync_module_free(module);
      g_free(filename);
      continue;
    }
		
    if (!osync_module_check(module, error)) {
      if (osync_error_is_set(error)) {
        osync_trace(TRACE_INTERNAL, "Module check error for %s: %s", filename, osync_error_print(error));
      }
      osync_module_free(module);
      g_free(filename);
      continue;
    }
	
    if (!osync_module_get_format_info(module, env, error) && !osync_module_get_function(module, "get_conversion_info", NULL)) {
      if (osync_error_is_set(error)) {
        osync_trace(TRACE_ERROR, "Module load format plugin error for %s: %s", filename, osync_error_print(error));
      }
      osync_error_set(error, OSYNC_ERROR_GENERIC, "Unable to load format plugin %s. Neither a converter nor a format could be initialized.", __NULLSTR(filename));
      osync_trace(TRACE_ERROR, "%s", osync_error_print(error));
      osync_module_free(module);
      g_free(filename);
      continue;
    }
		
    env->modules = g_list_append(env->modules, module);
		
    g_free(filename);
  }
	
  g_dir_close(dir);
	
  /* Load the converters, filters, etc */
  for (m = env->modules; m; m = m->next) {
    module = m->data;
    if (!osync_module_get_conversion_info(module, env, error)) {
      osync_trace(TRACE_INTERNAL, "Module get conversion error %s", osync_error_print(error));
      osync_error_unref(error);
    }
  }
	
  osync_trace(TRACE_EXIT, "%s", __func__);
  return TRUE;

 error_free_filename:
  g_free(filename);
  g_dir_close(dir);
 error:
  osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
  return FALSE;
}
static OSyncMappingEntryEngine *_osync_mapping_engine_get_latest_entry(OSyncMappingEngine *engine, OSyncError **error)
{
  OSyncMappingEntryEngine *latest_entry = NULL; 
  OSyncChange *latest_change = NULL;
  time_t latest = 0;
  int i;

  osync_trace(TRACE_ENTRY, "%s(%p, %p)", __func__, engine, error);
  osync_trace(TRACE_INTERNAL, "mapping number: %i", osync_mapping_engine_num_changes(engine));
  for (i=0; i < osync_mapping_engine_num_changes(engine); i++) {
    OSyncChange *change = osync_mapping_engine_nth_change(engine, i); 
    OSyncData *data = NULL;
    time_t cur = 0;

    if (osync_change_get_changetype(change) == OSYNC_CHANGE_TYPE_UNKNOWN)
      continue;

    data = osync_change_get_data(change);

    if (!osync_data_has_data(data))
      continue;

    cur = osync_data_get_revision(data, error);

    if (cur < 0)
      goto error;
		
    /* If there are several changes/entries having the
       same _and_ the latest revision -> don't declare
       a latest_change. Since it's not guranteed that those are
       equal, even with the _same_ revision.
    */
    if (cur == latest)
      latest_change = NULL;

    if (cur <= latest)
      continue;

    latest = cur;
    latest_change = change;
  }

  if (!latest_change) {
    osync_trace(TRACE_EXIT, "%s: Can't find the latest change.",
                __func__);
    return NULL;
  }

  latest_entry = _osync_mapping_engine_find_entry(engine, latest_change);

  if (!latest_entry) {
    osync_error_set(error, OSYNC_ERROR_GENERIC, "Can't find the latest entry of the latest change.");
    goto error;
  }

  osync_trace(TRACE_EXIT, "%s: %p", __func__, latest_entry);
  return latest_entry;

 error:
  osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
  return NULL;
}
示例#9
0
static void *initialize(OSyncPlugin *plugin, OSyncPluginInfo *info, OSyncError **error)
{
	/*
	 * get the config
	 */
	OSyncPluginConfig *config = osync_plugin_info_get_config(info);
	if (!config) {
		osync_error_set(error, OSYNC_ERROR_GENERIC, "Unable to get config.");
		goto error;
	}
	/*
	 * You need to specify the <some name>_environment somewhere with
	 * all the members you need
	*/
	plugin_environment *env = osync_try_malloc0(sizeof(plugin_environment), error);
	if (!env)
		goto error;

	env->sink_envs = NULL;
	
	osync_trace(TRACE_INTERNAL, "The config: %s", osync_plugin_info_get_config(info));

	/* 
	 * Process the config here and set the options on your environment
	*/
	/*
	 * Process plugin specific advanced options 
	 */
	OSyncList *optslist = osync_plugin_config_get_advancedoptions(config);
	for (; optslist; optslist = optslist->next) {
		OSyncPluginAdvancedOption *option = optslist->data;

		const char *val = osync_plugin_advancedoption_get_value(option);
		const char *name = osync_plugin_advancedoption_get_name(option);

		if (!strcmp(name,"<your-option>")) {
			if (!strcmp(val, "<your-value>")) {
				/*
				 * set a varaible to a specific value
				 */;
			}
		}
	}
	/*
	 * Process Ressource options
	 */
	int i, numobjs = osync_plugin_info_num_objtypes(info);
	for (i = 0; i < numobjs; i++) {
		sink_environment *sinkenv = osync_try_malloc0(sizeof(sink_environment), error);
		if (!sinkenv)
			goto error_free_env;

		sinkenv->sink = osync_plugin_info_nth_objtype(info, i);
		osync_assert(sinkenv->sink);

		const char *objtype = osync_objtype_sink_get_name(sinkenv->sink);
		OSyncPluginResource *res = osync_plugin_config_find_active_resource(config, objtype);
		
		/* get objformat sinks */
		OSyncList *s = osync_plugin_resource_get_objformat_sinks(res);
		for (; s; s = s->next) {
			OSyncObjFormatSink *fsink = s->data; // there could be only one sink
			const char *objformat = osync_objformat_sink_get_objformat(fsink);
			osync_assert(objformat);
			osync_trace(TRACE_INTERNAL, "objtype %s has objformat %s", objtype, objformat);
		}	

		/* Every sink can have different functions ... */
		OSyncObjTypeSinkFunctions functions;
		memset(&functions, 0, sizeof(functions));
		functions.connect = connect;
		functions.disconnect = disconnect;
		functions.get_changes = get_changes;
		functions.commit = commit_change;
		functions.sync_done = sync_done;

		/* We pass the OSyncFileDir object to the sink, so we dont have to look it up
		 * again once the functions are called */
		osync_objtype_sink_set_functions(sinkenv->sink, functions, sinkenv);
		
		osync_trace(TRACE_INTERNAL, "The configdir: %s", osync_plugin_info_get_configdir(info));
		char *tablepath = osync_strdup_printf("%s/hashtable.db", osync_plugin_info_get_configdir(info));
		sinkenv->hashtable = osync_hashtable_new(tablepath, objtype, error);
		osync_free(tablepath);
		env->sink_envs = osync_list_append(env->sink_envs, sinkenv);
	}
	
	//Now your return your struct.
	return (void *) env;

error_free_env:
	free_env(env);
error:
	osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
	return NULL;
}
示例#10
0
int osync_db_get_blob(OSyncDB *db, const char *query, char **data, unsigned int *size, OSyncError **error)
{
	sqlite3_stmt *sqlite_stmt = NULL;
	int rc = 0;
	const char *tmp = NULL;

	osync_trace(TRACE_ENTRY, "%s(%p, %s, %p, %p, %p)", __func__, db, query, data, size, error);

	osync_assert(db);
	osync_assert(query);
	osync_assert(data);
	osync_assert(size);

	rc = sqlite3_prepare(db->sqlite3db, query, -1, &sqlite_stmt, NULL);
	if(rc != SQLITE_OK)
		goto error_msg;
	
	rc = sqlite3_step(sqlite_stmt);
	if(rc != SQLITE_ROW) {
		sqlite3_reset(sqlite_stmt);
		sqlite3_finalize(sqlite_stmt);
		osync_trace(TRACE_EXIT, "%s: no result!", __func__);
		return 0;
	}
	
	tmp = sqlite3_column_blob(sqlite_stmt, 0);
	*size = sqlite3_column_bytes(sqlite_stmt, 0);
	if (*size == 0) {
		sqlite3_reset(sqlite_stmt);
		sqlite3_finalize(sqlite_stmt);
		osync_trace(TRACE_EXIT, "%s: no data!", __func__);
		return 0;
	}

	*data = osync_try_malloc0(*size, error);

	if(!*data)
		goto error;

	memcpy(*data, tmp, *size);
	
	if (sqlite3_step(sqlite_stmt) == SQLITE_ROW) {
		osync_error_set(error, OSYNC_ERROR_GENERIC, "Returned more than one result for a uid");
		goto error;
	}
	
	sqlite3_reset(sqlite_stmt);
	sqlite3_finalize(sqlite_stmt);

	osync_trace(TRACE_EXIT, "%s", __func__);
	return 1; 
	
 error_msg:
	osync_error_set(error, OSYNC_ERROR_GENERIC, "Unable to get data: %s", sqlite3_errmsg(db->sqlite3db));
 error:
	if(sqlite_stmt) {
		sqlite3_reset(sqlite_stmt);
		sqlite3_finalize(sqlite_stmt);	
	}
	osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
	return -1;
}
static
gboolean _source_check(GSource *source)
{
  OSyncQueue *queue = *((OSyncQueue **)(source + 1));
  OSyncMessage *message = NULL;
  OSyncError *error = NULL;
	
  if (queue->connected == FALSE) {
    /* Ok. so we arent connected. lets check if there are pending replies. We cannot
     * receive any data on the pipe, therefore, any pending replies will never
     * be answered. So we return error messages for all of them. */
    if (queue->pendingReplies) {
      GList *p = NULL;
      g_mutex_lock(queue->pendingLock);
      osync_error_set(&error, OSYNC_ERROR_IO_ERROR, "Broken Pipe");
      for (p = queue->pendingReplies; p; p = p->next) {
        OSyncPendingMessage *pending = p->data;
				
        message = osync_message_new_errorreply(NULL, error, NULL);
        if (message) {
          osync_message_set_id(message, pending->id);
					
          g_async_queue_push(queue->incoming, message);
        }
      }
			
      osync_error_unref(&error);
      g_mutex_unlock(queue->pendingLock);
    }
		
    return FALSE;
  }
	
  switch (osync_queue_poll(queue)) {
  case OSYNC_QUEUE_EVENT_NONE:
    return FALSE;
  case OSYNC_QUEUE_EVENT_READ:
    return TRUE;
  case OSYNC_QUEUE_EVENT_HUP:
  case OSYNC_QUEUE_EVENT_ERROR:
    queue->connected = FALSE;
			
    /* Now we can send the hup message, and wake up the consumer thread so
     * it can pickup the messages in the incoming queue */
    message = osync_message_new(OSYNC_MESSAGE_QUEUE_HUP, 0, &error);
    if (!message)
      goto error;
			
    g_async_queue_push(queue->incoming, message);
			
    if (queue->incomingContext)
      g_main_context_wakeup(queue->incomingContext);
    return FALSE;
  }
	
  return FALSE;

 error:
  message = osync_message_new_queue_error(error, NULL);
  if (message) 
    g_async_queue_push(queue->incoming, message);
	
  osync_error_unref(&error);
  return FALSE;
}
/* This function sends the data to the remote side. If there is an error, it sends an error
 * message to the incoming queue */
static
gboolean _queue_dispatch(GSource *source, GSourceFunc callback, gpointer user_data)
{
  OSyncQueue *queue = user_data;
  OSyncError *error = NULL;
	
  OSyncMessage *message = NULL;
	
  while ((message = g_async_queue_try_pop(queue->outgoing))) {
    char *data = NULL;
    unsigned int length = 0;

    /* Check if the queue is connected */
    if (!queue->connected) {
      osync_error_set(&error, OSYNC_ERROR_GENERIC, "Trying to send to a queue thats not connected");
      goto error;
    }
		
    /* The size of the message */
    if (!_osync_queue_write_int(queue, osync_message_get_message_size(message), &error))
      goto error;
		
    /* The command type (integer) */
    if (!_osync_queue_write_int(queue, osync_message_get_cmd(message), &error))
      goto error;

    /* The id (long long int) */
    if (!_osync_queue_write_long_long_int(queue, osync_message_get_id(message), &error))
      goto error;
		
    osync_message_get_buffer(message, &data, &length);
		
    if (length) {
      int sent = 0;
      do {
        int written = _osync_queue_write_data(queue, data + sent, length - sent, &error);
        if (written < 0)
          goto error;
				
        sent += written;
      } while (sent < length);
    }
		
    osync_message_unref(message);
  }
	
  return TRUE;
	
 error:
  if (message)
    osync_message_unref(message);
	
  if (error) {
    message = osync_message_new_queue_error(error, NULL);
    if (message)
      g_async_queue_push(queue->incoming, message);
		
    osync_error_unref(&error);
  }
  return FALSE;
}
示例#13
0
/* In initialize, we get the config for the plugin. Here we also must register
 * all _possible_ objtype sinks. */
static void *mock_initialize(OSyncPlugin *plugin, OSyncPluginInfo *info, OSyncError **error)
{
	osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, plugin, info, error);

	if (mock_get_error(info->memberid, "INIT_NULL_NOERROR")) {
		osync_trace(TRACE_EXIT, "%s: %s", __func__, "Everything is fine. I don't need plugin userdata.");
		return NULL;
	}

	if (mock_get_error(info->memberid, "INIT_NULL")) {
		osync_error_set(error, OSYNC_ERROR_EXPECTED, "Triggering INIT_NULL error");
		osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
		return NULL;
	}

	mock_env *env = osync_try_malloc0(sizeof(mock_env), error);
	osync_assert(env);

	OSyncFormatEnv *formatenv = osync_plugin_info_get_format_env(info);
	osync_assert(formatenv);

	OSyncPluginConfig *config = osync_plugin_info_get_config(info);
	osync_assert(config);

	if (mock_get_error(info->memberid, "MAINSINK_CONNECT")) {
		env->mainsink = osync_objtype_main_sink_new(error);

		osync_objtype_sink_set_connect_func(env->mainsink, mock_connect);
		osync_objtype_sink_set_disconnect_func(env->mainsink, mock_mainsink_disconnect);

		osync_objtype_sink_set_userdata(env->mainsink, env);

		osync_plugin_info_set_main_sink(info, env->mainsink);
	}

	/* Now we register the objtypes that we can sync. This plugin is special. It can
	 * synchronize any objtype we configure it to sync and where a conversion
	 * path to the file format can be found */
	OSyncList *objtypesinks = osync_plugin_info_get_objtype_sinks(info);
	OSyncList *list = NULL;
	for (list = objtypesinks;list; list = list->next) {
		MockDir *dir = osync_try_malloc0(sizeof(MockDir), error);
		osync_assert(dir);

		dir->committed_all = TRUE;

		OSyncObjTypeSink *sink = (OSyncObjTypeSink*)list->data;
		osync_assert(sink);

		const char *objtype = osync_objtype_sink_get_name(sink);
		dir->res = osync_plugin_config_find_active_resource(config, objtype);
		osync_plugin_resource_ref(dir->res);
		dir->path = osync_plugin_resource_get_path(dir->res);
		osync_assert(dir->path);

		OSyncList *format_sinks = osync_plugin_resource_get_objformat_sinks(dir->res);
		osync_assert(osync_list_length(format_sinks) == 1);
		OSyncObjFormatSink *format_sink = osync_list_nth_data(format_sinks, 0);
		const char *objformat_str = osync_objformat_sink_get_objformat(format_sink);
		osync_assert(objformat_str);
		dir->objformat = osync_format_env_find_objformat(formatenv, objformat_str);
		osync_assert(dir->objformat);
		osync_objformat_ref(dir->objformat);

		osync_list_free(format_sinks);
		/*
		const char *objformat = osync_objformat_get_name(dir->objformat);
		OSyncObjFormatSink *format_sink = osync_objformat_sink_new(objformat, error);
		if (!format_sink)
			return NULL;

		osync_objtype_sink_add_objformat_sink(sink, format_sink);
		*/

		/* Sanity check for connect_done */
		dir->connect_done = TRUE;

		if (!mock_get_error(info->memberid, "MAINSINK_CONNECT")) {
			osync_objtype_sink_set_connect_func(sink, mock_connect);
			osync_objtype_sink_set_connect_done_func(sink, mock_connect_done);
			osync_objtype_sink_set_disconnect_func(sink, mock_disconnect);
		}

		osync_objtype_sink_set_get_changes_func(sink, mock_get_changes);

		osync_objtype_sink_set_committed_all_func(sink, mock_committed_all);
		osync_objtype_sink_set_commit_func(sink, mock_commit_change);
		osync_objtype_sink_set_read_func(sink, mock_read);
		osync_objtype_sink_set_sync_done_func(sink, mock_sync_done);

		/* We pass the MockDir object to the sink, so we dont have to look it up
		 * again once the functions are called */
		osync_objtype_sink_set_userdata(sink, dir);

		/* Request an Anchor */
		osync_objtype_sink_enable_state_db(sink, TRUE);

		/* Request an Hashtable */
		osync_objtype_sink_enable_hashtable(sink, TRUE);

		//Lets reduce the timeouts a bit so the checks work faster
		osync_objtype_sink_set_connect_timeout(sink, 2);
		osync_objtype_sink_set_getchanges_timeout(sink, 2);
		osync_objtype_sink_set_commit_timeout(sink, 4);
		osync_objtype_sink_set_committedall_timeout(sink, 4);
		osync_objtype_sink_set_syncdone_timeout(sink, 2);
		osync_objtype_sink_set_disconnect_timeout(sink, 2);

		osync_objtype_sink_set_read_timeout(sink, 2);


/* XXX No testcase is currently using this at all! */
#if 0

		if (g_getenv("NO_TIMEOUTS")) {

			/* XXX Timeout value of wouldn't work out, since
			   the Sink object would fallback to the default timeout value:

			 sink->timeout.connect ? sink->timeout.connect : OSYNC_SINK_TIMEOUT_CONNECT;

			 Really needed?!
			 */

			osync_objtype_sink_set_connect_timeout(sink, 0);
			osync_objtype_sink_set_getchanges_timeout(sink, 0);
			osync_objtype_sink_set_commit_timeout(sink, 0);
			osync_objtype_sink_set_committedall_timeout(sink, 0);
			osync_objtype_sink_set_syncdone_timeout(sink, 0);
			osync_objtype_sink_set_disconnect_timeout(sink, 0);

			osync_objtype_sink_set_read_timeout(sink, 0);
		}

		/* What is meant by this?! Maybe OSyncPlugin.useable?! Not used at all...
		if (g_getenv("IS_AVAILABLE"))
			info->functions.is_available = mock_is_available;
		*/

#endif
		env->directories = g_list_append(env->directories, dir);
	}
	osync_list_free(objtypesinks);
	osync_trace(TRACE_EXIT, "%s: %p", __func__, env);
	return (void *)env;
}
示例#14
0
static OSyncFormatConverterPath *osync_format_env_find_path_fn(OSyncFormatEnv *env, OSyncData *sourcedata, OSyncPathTargetFn target_fn, OSyncTargetLastConverterFn last_converter_fn, const void *fndata, const char * preferred_format, OSyncError **error)
{
  OSyncFormatConverterPath *path = NULL;
  OSyncFormatConverterTree *tree = NULL;
  OSyncFormatConverterPathVertice *begin = NULL;
  OSyncFormatConverterPathVertice *result = NULL;
  OSyncFormatConverterPathVertice *neighbour = NULL;
  GList *e, *v;
  guint vertice_id = 0;
	
  osync_trace(TRACE_ENTRY, "%s(%p, %p, %p, %p, %p)", __func__, env, sourcedata, target_fn, fndata, error);
  osync_assert(env);
  osync_assert(sourcedata);
  osync_assert(target_fn);
	
  //Vertice = Spitze = Format
  //edge = Kante = Converter

  /* Optimization: check if the format is already valid */
  if (target_fn(fndata, osync_data_get_objformat(sourcedata))) {
    path = osync_converter_path_new(error);
    if (!path)
      goto error;
		
    osync_trace(TRACE_EXIT, "%s: Target already valid", __func__);
    return path;
  }

  /* Make a new search tree */
  tree = osync_try_malloc0(sizeof(OSyncFormatConverterTree), error);
  if (!tree)
    goto error;
  tree->unused = g_list_copy(env->converters);
	
  /* We make our starting point (which is the current format of the 
   * change of course */
  begin = osync_format_converter_path_vertice_new(error);
  if (!begin)
    goto error_free_tree;
	
  begin->format = osync_data_get_objformat(sourcedata);
  begin->path = NULL;
  begin->id = vertice_id;
  begin->neighbour_id = 0;
	
  tree->search = g_list_append(NULL, begin);
	
  /* While there are still vertices in our
   * search queue */
  while (g_list_length(tree->search)) {
    /* log current tree search list */
    GString *string = g_string_new("");
    guint size = g_list_length(tree->search);
    guint count = 0;
    guint neighbour_id = 0;
    OSyncFormatConverterPathVertice *current = NULL;
    OSyncFormatConverterPath *path_tmp = NULL;
    for (v = tree->search; v; v = v->next) {
      OSyncFormatConverterPathVertice *vertice = v->data;
      GString *string2 = g_string_new("");
      guint size2 = g_list_length(vertice->path);
      guint count2 = 0;
      count ++;
      for (e = vertice->path; e; e = e->next) {
        OSyncFormatConverter *edge = e->data;
        count2 ++;
        if (count2 == 1) {
          g_string_append(string2, osync_objformat_get_name(osync_converter_get_sourceformat(edge)));
          g_string_append(string2, " -> ");
        }
        g_string_append(string2, osync_objformat_get_name(osync_converter_get_targetformat(edge)));
        if (size2 > 1 && count2 < size2)
          g_string_append(string2, " -> ");
      }
      g_string_append(string, osync_objformat_get_name(vertice->format));
      g_string_append(string, " ( ");
      g_string_append(string, string2->str);
      g_string_append(string, " ) ");

      g_string_free(string2, TRUE);

      if (size > 1 && count < size)
        g_string_append(string, " -> ");
    }
    osync_trace(TRACE_INTERNAL, "Tree : %s", string->str);
    g_string_free(string, TRUE);

    /* Get the first OSyncFormatConverterPathVertice from the search queue
     * and remove it from the queue */
    current = tree->search->data;
    tree->search = g_list_remove(tree->search, current);
		
    /* log current OSyncFormatConverterPathVertice */
    string = g_string_new("");
    size = g_list_length(current->path);
    count = 0;
    for (e = current->path; e; e = e->next) {
      OSyncFormatConverter *edge = e->data;
      count ++;
      if (count == 1) {
        g_string_append(string, osync_objformat_get_name(osync_converter_get_sourceformat(edge)));
        g_string_append(string, " -> ");
      }
      g_string_append(string, osync_objformat_get_name(osync_converter_get_targetformat(edge)));
      if (size > 1 && count < size)
        g_string_append(string, " -> ");
    }
    osync_trace(TRACE_INTERNAL, "Next vertice : %s (%s).", osync_objformat_get_name(current->format), string->str);
    g_string_free(string, TRUE);

    current->neighbour_id = 0;
    vertice_id++; // current OSyncFormatConverterPathVertice id for its neighbours

    /* Check if we have reached a target format */
    if (target_fn(fndata, current->format)) {
      osync_trace(TRACE_INTERNAL, "Target %s found", osync_objformat_get_name(current->format));
      /* Done. return the result */
      result = current;
      break;
    }
		
    /*
     * Optimizations : 
     */
    if (last_converter_fn(fndata, tree)) {
      osync_trace(TRACE_INTERNAL, "Last converter for target format reached: %s.", (result)?osync_objformat_get_name(result->format):"null");
      osync_format_converter_path_vertice_unref(current);
      break;
    }
    /* Check if saved result is equal to current regarding losses, objtype_changes
     * and conversions. If yes, we can skip further searches and break here */
    if (result) {
      if (result->losses <= current->losses && result->objtype_changes <= current->objtype_changes && result->conversions <= current->conversions) {
        osync_trace(TRACE_INTERNAL, "Target %s found in queue", osync_objformat_get_name(result->format));
        tree->search = g_list_remove(tree->search, result);
        break;
      } else {
        result = NULL;
      }
    }


    /*
     * If we dont have reached a target, we look at our neighbours 
     */
    osync_trace(TRACE_INTERNAL, "Looking at %s's neighbours.", osync_objformat_get_name(current->format));

    /* Convert the "current" data to the last edge found in the "current" conversion path  */
    current->data = osync_data_clone(sourcedata, error);
    path_tmp = osync_converter_path_new(error);
    if (!path_tmp)
      goto error;
    for (e = current->path; e; e = e->next) {
      OSyncFormatConverter *edge = e->data;
      osync_converter_path_add_edge(path_tmp, edge);
    }
    if (!(osync_format_env_convert(env, path_tmp, current->data, error))) {
      osync_trace(TRACE_INTERNAL, "osync format env convert on this path failed - skipping the conversion");
      continue;
    }
    osync_converter_path_unref(path_tmp);

    /* Find all the neighboors or "current" at its current conversion point */
    while ((neighbour = osync_format_converter_path_vertice_get_next_vertice_neighbour(env, tree, current, error))) {
      GString *string = g_string_new("");
      guint size = g_list_length(neighbour->path);
      guint count = 0;

      neighbour->id = vertice_id;
      neighbour_id++;
      neighbour->neighbour_id = neighbour_id;

      neighbour->preferred = FALSE;
      if (current->preferred)	  /* preferred is inherited by the neighbours */
        neighbour->preferred = TRUE;
      if(preferred_format && !strcmp(preferred_format, osync_objformat_get_name(neighbour->format)))
        neighbour->preferred = TRUE;

      /* log neighbour to be added to the tree search list */
      for (e = neighbour->path; e; e = e->next) {
        OSyncFormatConverter *edge = e->data;
        count ++;
        if (count == 1) {
          g_string_append(string, osync_objformat_get_name(osync_converter_get_sourceformat(edge)));
          g_string_append(string, " -> ");
        }
        g_string_append(string, osync_objformat_get_name(osync_converter_get_targetformat(edge)));
        if (size > 1 && count < size)
          g_string_append(string, " -> ");
      }
      osync_trace(TRACE_INTERNAL, "%s's neighbour : %s (%s)", osync_objformat_get_name(current->format), osync_objformat_get_name(neighbour->format), string->str);
      g_string_free(string, TRUE);

      /* We found a neighbour and insert it sorted in our search queue 
         If vertices are equals in losses, objtypes and conversions, first registered is inserted before the others 
         in the same OSyncFormatConverterPathVertice group (vertice_id) */
      tree->search = g_list_insert_sorted(tree->search, neighbour, osync_format_converter_path_vertice_compare_distance); 

      /* Optimization:
       * We found a possible target. Save it. */
      if (target_fn(fndata, neighbour->format)) {
        osync_trace(TRACE_INTERNAL, "Possible target found.");
        result = neighbour;
        osync_format_converter_path_vertice_ref(result);
      }
    }

    if (osync_error_is_set(error))
      goto error_free_tree;
		
    /* Done, drop the reference to the OSyncFormatConverterPathVertice */
    osync_format_converter_path_vertice_unref(current);
  }
			
  if (!result) {
    osync_error_set(error, OSYNC_ERROR_GENERIC, "Unable to find conversion path");
    goto error_free_tree;
  }
	
  /* Found it. Create a path object */
  path = osync_converter_path_new(error);
  if (!path)
    goto error;
	
  for (e = result->path; e; e = e->next) {
    OSyncFormatConverter *edge = e->data;
    osync_converter_path_add_edge(path, edge);
  }
	
  /* Drop the reference to the result OSyncFormatConverterPathVertice */
  osync_format_converter_path_vertice_unref(result);
	
  /* Free the tree */
  osync_converter_tree_free(tree);
	
  osync_trace(TRACE_EXIT, "%s: %p", __func__, path);
  return path;

 error_free_tree:
  osync_converter_tree_free(tree);
 error:
  osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
  return NULL;
}
示例#15
0
static void *initialize(OSyncPlugin *plugin, OSyncPluginInfo *info, OSyncError **error)
{
	/*
	 * get the config
	 */
	OSyncPluginConfig *config = osync_plugin_info_get_config(info);
	if (!config) {
		osync_error_set(error, OSYNC_ERROR_GENERIC, "Unable to get config.");
		goto error;
	}
	/*
	 * You need to specify the <some name>_environment somewhere with
	 * all the members you need
	*/
	plugin_environment *env = osync_try_malloc0(sizeof(plugin_environment), error);
	if (!env)
		goto error;

	/* 
	 * Process the config here and set the options on your environment
	 * if required.
	*/
	/*
	 * Process plugin specific advanced options 
	 */
	OSyncList *optslist = osync_plugin_config_get_advancedoptions(config);
	OSyncList *o;
	for (o = optslist; o; o = o->next) {
		OSyncPluginAdvancedOption *option = o->data;

		const char *val = osync_plugin_advancedoption_get_value(option);
		const char *name = osync_plugin_advancedoption_get_name(option);

		if (!strcmp(name,"<your-option>")) {
			if (!strcmp(val, "<your-value>")) {
				/*
				 * set a varaible to a specific value
				 */;
			}
		}
	}
	osync_list_free(optslist);
	
	/*
	 * Process Ressource options
	 */
	OSyncList *l, *list = NULL;
	list = osync_plugin_info_get_objtype_sinks(info);
	for (l=list; l; l = l->next) {
		OSyncObjTypeSink *sink = (OSyncObjTypeSink *) l->data;

		const char *objtype = osync_objtype_sink_get_name(sink);
		OSyncPluginResource *res = osync_plugin_config_find_active_resource(config, objtype);
		
		/* get objformat sinks */
		OSyncList *s = NULL;
		OSyncList *objformats = osync_plugin_resource_get_objformat_sinks(res);
		for (s = objformats; s; s = s->next) {
			OSyncObjFormatSink *fsink = s->data; // there could be only one sink
			const char *objformat = osync_objformat_sink_get_objformat(fsink);
			osync_assert(objformat);
			osync_trace(TRACE_INTERNAL, "objtype %s has objformat %s", objtype, objformat);
		}	
		osync_list_free(objformats);
		/* Every sink can have different functions ... */
		osync_objtype_sink_set_connect_func(sink, connect);
		osync_objtype_sink_set_disconnect_func(sink, disconnect);
		osync_objtype_sink_set_get_changes_func(sink, get_changes);
		osync_objtype_sink_set_commit_func(sink, commit_change);
		osync_objtype_sink_set_sync_done_func(sink, sync_done);

		/*
		 * If you need plugin specific userdata passed to this
		 * plugin sink functions. You can set it with:
		 *
		 * osync_objtype_sink_set_userdata(sink, userdata_pointer);
		 */

		/* Request a Hahstable here - if you need it.
		 * It will be later available via osync_objtype_sink_get_hashtable(OSyncObjTypeSink *)
		 * in the plugin sink functions (e.g. connect, get_changes, commit, ...)
		 */ 
		osync_objtype_sink_enable_hashtable(sink, TRUE);

	}

	osync_list_free(list);
	
	//Now your return your environemtn struct.
	return (void *) env;

error:
	osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
	return NULL;
}
/* This function reads from the file descriptor and inserts incoming data into the
 * incoming queue */
static
gboolean _source_dispatch(GSource *source, GSourceFunc callback, gpointer user_data)
{
  OSyncQueue *queue = user_data;
  OSyncMessage *message = NULL;
  OSyncError *error = NULL;
	
  do {
    int size = 0;
    int cmd = 0;
    long long int id = 0;
    char *buffer = NULL;
		
    /* The size of the buffer */
    if (!_osync_queue_read_int(queue, &size, &error))
      goto error;
		
    /* The command */
    if (!_osync_queue_read_int(queue, &cmd, &error))
      goto error;
		
    /* The id */
    if (!_osync_queue_read_long_long_int(queue, &id, &error))
      goto error;
		
    message = osync_message_new(cmd, size, &error);
    if (!message)
      goto error;
	
    osync_message_set_id(message, id);
		
    /* We now get the buffer from the message which will already
     * have the correct size for the read */
    osync_message_get_buffer(message, &buffer, NULL);
    if (size) {
      unsigned int read = 0;
      do {
        int inc = _osync_queue_read_data(queue, buffer + read, size - read, &error);
				
        if (inc < 0)
          goto error_free_message;
				
        if (inc == 0) {
          osync_error_set(&error, OSYNC_ERROR_IO_ERROR, "Encountered EOF while data was missing");
          goto error_free_message;
        }
				
        read += inc;
      } while (read < size);
    }
    osync_message_set_message_size(message, size);
		
    g_async_queue_push(queue->incoming, message);
		
    if (queue->incomingContext)
      g_main_context_wakeup(queue->incomingContext);
  } while (_source_check(queue->read_source));
	
  return TRUE;

 error_free_message:
  osync_message_unref(message);
 error:
  if (error) {
    message = osync_message_new_queue_error(error, NULL);
    if (message)
      g_async_queue_push(queue->incoming, message);
		
		
    osync_error_unref(&error);
  }
	
  return FALSE;
}
osync_bool osync_queue_connect(OSyncQueue *queue, OSyncQueueType type, OSyncError **error)
{
#ifdef _WIN32
  return FALSE;
#else //_WIN32
  OSyncQueue **queueptr = NULL;
  osync_trace(TRACE_ENTRY, "%s(%p, %i, %p)", __func__, queue, type, error);
  osync_assert(queue);
  osync_assert(queue->connected == FALSE);
	
  queue->type = type;
	
  if (queue->fd == -1) {
    /* First, open the queue with the flags provided by the user */
    int fd = open(queue->name, type == OSYNC_QUEUE_SENDER ? O_WRONLY : O_RDONLY);
    if (fd == -1) {
      osync_error_set(error, OSYNC_ERROR_GENERIC, "Unable to open fifo");
      goto error;
    }
    queue->fd = fd;
  }

  int oldflags = fcntl(queue->fd, F_GETFD);
  if (oldflags == -1) {
    osync_error_set(error, OSYNC_ERROR_GENERIC, "Unable to get fifo flags");
    goto error_close;
  }
  if (fcntl(queue->fd, F_SETFD, oldflags|FD_CLOEXEC) == -1) {
    osync_error_set(error, OSYNC_ERROR_GENERIC, "Unable to set fifo flags");
    goto error_close;
  }

  queue->connected = TRUE;
  signal(SIGPIPE, SIG_IGN);
	
  /* now we start a thread which handles reading/writing of the queue */
  queue->thread = osync_thread_new(queue->context, error);

  if (!queue->thread)
    goto error;
	
  queue->write_functions = g_malloc0(sizeof(GSourceFuncs));
  queue->write_functions->prepare = _queue_prepare;
  queue->write_functions->check = _queue_check;
  queue->write_functions->dispatch = _queue_dispatch;
  queue->write_functions->finalize = NULL;

  queue->write_source = g_source_new(queue->write_functions, sizeof(GSource) + sizeof(OSyncQueue *));
  queueptr = (OSyncQueue **)(queue->write_source + 1);
  *queueptr = queue;
  g_source_set_callback(queue->write_source, NULL, queue, NULL);
  g_source_attach(queue->write_source, queue->context);
  if (queue->context)
    g_main_context_ref(queue->context);

  queue->read_functions = g_malloc0(sizeof(GSourceFuncs));
  queue->read_functions->prepare = _source_prepare;
  queue->read_functions->check = _source_check;
  queue->read_functions->dispatch = _source_dispatch;
  queue->read_functions->finalize = NULL;

  queue->read_source = g_source_new(queue->read_functions, sizeof(GSource) + sizeof(OSyncQueue *));
  queueptr = (OSyncQueue **)(queue->read_source + 1);
  *queueptr = queue;
  g_source_set_callback(queue->read_source, NULL, queue, NULL);
  g_source_attach(queue->read_source, queue->context);
  if (queue->context)
    g_main_context_ref(queue->context);

  queue->timeout_functions = g_malloc0(sizeof(GSourceFuncs));
  queue->timeout_functions->prepare = _timeout_prepare;
  queue->timeout_functions->check = _timeout_check;
  queue->timeout_functions->dispatch = _timeout_dispatch;
  queue->timeout_functions->finalize = NULL;

  queue->timeout_source = g_source_new(queue->timeout_functions, sizeof(GSource) + sizeof(OSyncQueue *));
  queueptr = (OSyncQueue **)(queue->timeout_source + 1);
  *queueptr = queue;
  g_source_set_callback(queue->timeout_source, NULL, queue, NULL);
  g_source_attach(queue->timeout_source, queue->context);
  if (queue->context)
    g_main_context_ref(queue->context);
	
  osync_thread_start(queue->thread);
	
  osync_trace(TRACE_EXIT, "%s", __func__);
  return TRUE;

 error_close:
  close(queue->fd);
 error:
  osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
  return FALSE;
#endif //_WIN32
}
osync_bool osync_obj_engine_command(OSyncObjEngine *engine, OSyncEngineCmd cmd, OSyncError **error)
{
  GList *p = NULL;
  GList *m = NULL;
  GList *e = NULL;
  OSyncSinkEngine *sinkengine =  NULL;

	
  osync_trace(TRACE_ENTRY, "%s(%p, %i, %p)", __func__, engine, cmd, error);
  osync_assert(engine);
	
  switch (cmd) {
    int write_sinks = 0;
    osync_bool proxy_disconnect = FALSE;
  case OSYNC_ENGINE_COMMAND_CONNECT:
    for (p = engine->sink_engines; p; p = p->next) {
      sinkengine = p->data;

      if (!osync_client_proxy_connect(sinkengine->proxy, _osync_obj_engine_connect_callback, sinkengine, engine->objtype, engine->slowsync, error))
        goto error;
    }
    break;
  case OSYNC_ENGINE_COMMAND_READ:
    for (p = engine->sink_engines; p; p = p->next) {
      sinkengine = p->data;
      for (m = sinkengine->entries; m; m = m->next) {
        OSyncMappingEntryEngine *entry = m->data;
        OSyncChange *change = entry->change;

        if (!change)
          continue;

        if (!osync_client_proxy_read(sinkengine->proxy, _osync_obj_engine_read_ignored_callback, sinkengine, change, error))
          goto error;
      }
    }

    if (engine->archive) {
      /* Flush the changelog - to avoid double entries of ignored entries */
      if (!osync_archive_flush_ignored_conflict(engine->archive, engine->objtype, error))
        goto error;
    }

    write_sinks = _osync_obj_engine_num_write_sinks(engine);

    /* Get change entries since last sync. (get_changes) */
    for (p = engine->sink_engines; p; p = p->next) {
      OSyncMember *member = NULL;
      OSyncObjTypeSink *objtype_sink = NULL;

      sinkengine = p->data;

      member = osync_client_proxy_get_member(sinkengine->proxy);
      objtype_sink = osync_member_find_objtype_sink(member, engine->objtype);

      /* Is there at least one other writeable sink? */
      if (objtype_sink && osync_objtype_sink_get_write(objtype_sink) && write_sinks) {
        _osync_obj_engine_read_callback(sinkengine->proxy, sinkengine, *error);
        osync_trace(TRACE_INTERNAL, "no other writable sinks .... SKIP");
        continue;
      }

      if (!osync_client_proxy_get_changes(sinkengine->proxy, _osync_obj_engine_read_callback, sinkengine, engine->objtype, engine->slowsync, error))
        goto error;
    }

    break;
  case OSYNC_ENGINE_COMMAND_WRITE:
    if (engine->conflicts) {
      osync_trace(TRACE_INTERNAL, "We still have conflict. Delaying write");
      break;
    }
		
    if (engine->written) {
      osync_trace(TRACE_INTERNAL, "Already written");
      break;
    }
				
    engine->written = TRUE;
		
    /* Write the changes. First, we can multiply the winner in the mapping */
    osync_trace(TRACE_INTERNAL, "Preparing write. multiplying %i mappings", g_list_length(engine->mapping_engines));
    for (m = engine->mapping_engines; m; m = m->next) {
      OSyncMappingEngine *mapping_engine = m->data;
      if (!osync_mapping_engine_multiply(mapping_engine, error))
        goto error;
    }
			
    osync_trace(TRACE_INTERNAL, "Starting to write");
    for (p = engine->sink_engines; p; p = p->next) {
      OSyncMember *member = NULL;
      long long int memberid = 0;
      OSyncObjTypeSink *objtype_sink = NULL;
      OSyncFormatConverterPath *path = NULL;

      sinkengine = p->data;
      member = osync_client_proxy_get_member(sinkengine->proxy);
      memberid = osync_member_get_id(member);
      objtype_sink = osync_member_find_objtype_sink(member, engine->objtype);
				
      /* If sink could not be found use "data" sink if available */
      if (!objtype_sink)
        objtype_sink = osync_member_find_objtype_sink(member, "data");
      /* TODO: Review if objtype_sink = NULL is valid at all. */

      for (e = sinkengine->entries; e; e = e->next) {
        OSyncMappingEntryEngine *entry_engine = e->data;
        osync_assert(entry_engine);

        /* Merger - Save the entire xml and demerge */
        /* TODO: is here the right place to save the xml???? */
        if (osync_group_get_merger_enabled(osync_engine_get_group(engine->parent)) &&
            osync_group_get_converter_enabled(osync_engine_get_group(engine->parent)) &&	
            entry_engine->change &&
            (osync_change_get_changetype(entry_engine->change) != OSYNC_CHANGE_TYPE_DELETED) &&
            !strncmp(osync_objformat_get_name(osync_change_get_objformat(entry_engine->change)), "xmlformat-", 10) )
          {
            char *buffer = NULL;
            unsigned int xmlformat_size = 0, size = 0;
            OSyncXMLFormat *xmlformat = NULL;
            const char *objtype = NULL;
            OSyncMapping *mapping = NULL;
            OSyncMerger *merger = NULL; 

            osync_trace(TRACE_INTERNAL, "Entry %s for member %lli: Dirty: %i", osync_change_get_uid(entry_engine->change), memberid, osync_entry_engine_is_dirty(entry_engine));

            osync_trace(TRACE_INTERNAL, "Save the entire XMLFormat and demerge.");
            objtype = osync_change_get_objtype(entry_engine->change);
            mapping = entry_engine->mapping_engine->mapping;
						
            osync_data_get_data(osync_change_get_data(entry_engine->change), (char **) &xmlformat, &xmlformat_size);
            osync_assert(xmlformat_size == osync_xmlformat_size());

            if(!osync_xmlformat_assemble(xmlformat, &buffer, &size)) {
              osync_error_set(error, OSYNC_ERROR_GENERIC, "Could not assamble the xmlformat");
              goto error;	
            }

            if(!osync_archive_save_data(engine->archive, osync_mapping_get_id(mapping), objtype, buffer, size, error)) {
              g_free(buffer);	
              goto error;			
            }
            g_free(buffer);
						
            merger = osync_member_get_merger(osync_client_proxy_get_member(sinkengine->proxy));
            if(merger)
              osync_merger_demerge(merger, xmlformat);
          }


        /* Only commit change if the objtype sink is able/allowed to write. */
        if (objtype_sink && osync_objtype_sink_get_write(objtype_sink) && osync_entry_engine_is_dirty(entry_engine)) {
          OSyncChange *change = entry_engine->change;
          osync_assert(entry_engine->change);

          /* Convert to requested target format if the changetype is not DELETED */
          if (osync_group_get_converter_enabled(osync_engine_get_group(engine->parent)) && (osync_change_get_changetype(change) != OSYNC_CHANGE_TYPE_DELETED)) {

            char *objtype = NULL;
            OSyncList *format_sinks = NULL;
            unsigned int length = 0;
            OSyncFormatConverter *converter = NULL;

            osync_trace(TRACE_INTERNAL, "Starting to convert from objtype %s and format %s", osync_change_get_objtype(entry_engine->change), osync_objformat_get_name(osync_change_get_objformat(entry_engine->change)));
            /* We have to save the objtype of the change so that it does not get
             * overwritten by the conversion */
            objtype = g_strdup(osync_change_get_objtype(change));
							
            /* Now we have to convert to one of the formats
             * that the client can understand */
            format_sinks = osync_objtype_sink_get_objformat_sinks(objtype_sink);
            if (!format_sinks) {
              osync_error_set(error, OSYNC_ERROR_GENERIC, "There are no available format sinks.");
              goto error;
            }
						
            /* We cache the converter path for each sink/member couple */
            if (!path) {
              path = osync_format_env_find_path_formats_with_detectors(engine->formatenv, osync_change_get_data(entry_engine->change), format_sinks, osync_objtype_sink_get_preferred_format(objtype_sink), error);
            }
            if (!path)
              goto error;

            length = osync_converter_path_num_edges(path);
            converter = osync_converter_path_nth_edge(path, length - 1);
            if (converter) {
              OSyncObjFormat *format = osync_converter_get_targetformat(converter);
              OSyncObjFormatSink *formatsink = osync_objtype_sink_find_objformat_sink(objtype_sink, format);
              osync_converter_path_set_config(path, osync_objformat_sink_get_config(formatsink));
            }

            if (!osync_format_env_convert(engine->formatenv, path, osync_change_get_data(entry_engine->change), error)) {
              osync_converter_path_unref(path);
              goto error;
            }
            osync_trace(TRACE_INTERNAL, "converted to format %s", osync_objformat_get_name(osync_change_get_objformat(entry_engine->change)));
							
							
            osync_change_set_objtype(change, objtype);
            g_free(objtype);
          }
						
          osync_trace(TRACE_INTERNAL, "Writing change %s, changetype %i, format %s , objtype %s from member %lli", 
                      osync_change_get_uid(change), 
                      osync_change_get_changetype(change), 
                      osync_objformat_get_name(osync_change_get_objformat(change)), 
                      osync_change_get_objtype(change), 
                      osync_member_get_id(osync_client_proxy_get_member(sinkengine->proxy)));
	
          if (!osync_client_proxy_commit_change(sinkengine->proxy, _osync_obj_engine_commit_change_callback, entry_engine, osync_entry_engine_get_change(entry_engine), error))
            goto error;
        } else if (entry_engine->change) {
          OSyncMapping *mapping = entry_engine->mapping_engine->mapping;
          OSyncMember *member = osync_client_proxy_get_member(sinkengine->proxy);
          OSyncMappingEntry *entry = entry_engine->entry;
          const char *objtype = osync_change_get_objtype(entry_engine->change);
						
          if (engine->archive) {
            if (osync_change_get_changetype(entry_engine->change) == OSYNC_CHANGE_TYPE_DELETED) {
              if (!osync_archive_delete_change(engine->archive, osync_mapping_entry_get_id(entry), objtype, error))
                goto error;
            } else {
              if (!osync_archive_save_change(engine->archive, osync_mapping_entry_get_id(entry), osync_change_get_uid(entry_engine->change), objtype, osync_mapping_get_id(mapping), osync_member_get_id(member), error))
                goto error;
            }
          }
        }
      }
			
      if (path)
        osync_converter_path_unref(path);

      if (!osync_client_proxy_committed_all(sinkengine->proxy, _osync_obj_engine_written_callback, sinkengine, engine->objtype, error))
        goto error;
    }
    break;
  case OSYNC_ENGINE_COMMAND_SYNC_DONE:
    for (p = engine->sink_engines; p; p = p->next) {
      sinkengine = p->data;
      if (!osync_client_proxy_sync_done(sinkengine->proxy, _osync_obj_engine_sync_done_callback, sinkengine, engine->objtype, error))
        goto error;
    }
    break;
  case OSYNC_ENGINE_COMMAND_DISCONNECT:;
    for (p = engine->sink_engines; p; p = p->next) {
      sinkengine = p->data;

      /* Don't call client disconnect functions if the sink is already disconnected.
         This avoids unintended disconnect calls of clients/plugins which might not prepared
         for a disconnect call when their never got connected. (testcases: *_connect_error, *_connect_timeout ..) */
      if (!osync_sink_engine_is_connected(sinkengine))
        continue;

      proxy_disconnect = TRUE;

      if (!osync_client_proxy_disconnect(sinkengine->proxy, _osync_obj_engine_disconnect_callback, sinkengine, engine->objtype, error))
        goto error;
    }
			
    /* If no client needs to be disconnected, we MUST NOT expected any 
       disconnected_callback which generates an OSYNC_ENGINE_EVENT_DISCONNECTED event.
       So we directly generate such event on our own. (testcases: double_connect_*, triple_connnect_*) */ 
    if (!proxy_disconnect)
      _osync_obj_engine_generate_event_disconnected(engine, NULL);

    break;
  case OSYNC_ENGINE_COMMAND_SOLVE:
  case OSYNC_ENGINE_COMMAND_DISCOVER:
  case OSYNC_ENGINE_COMMAND_ABORT:
    break;
  }
	
  osync_trace(TRACE_EXIT, "%s", __func__);
  return TRUE;

 error:
  osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
  return FALSE;
}
static
gboolean _timeout_dispatch(GSource *source, GSourceFunc callback, gpointer user_data)
{
  GList *p;
  OSyncPendingMessage *pending;
  OSyncTimeoutInfo *toinfo;
  OSyncQueue *queue = NULL;
  GTimeVal current_time;

  osync_trace(TRACE_INTERNAL, "%s(%p)", __func__, user_data);

  queue = *((OSyncQueue **)(source + 1));

  g_source_get_current_time (source, &current_time);

  /* Search for the pending reply. We have to lock the
   * list since another thread might be duing the updates */
  g_mutex_lock(queue->pendingLock);

  for (p = queue->pendingReplies; p; p = p->next) {
    pending = p->data;

    if (!pending->timeout_info)
      continue;

    toinfo = pending->timeout_info;

    if (current_time.tv_sec == toinfo->expiration.tv_sec ||
        (current_time.tv_sec >= toinfo->expiration.tv_sec 
         && current_time.tv_usec >= toinfo->expiration.tv_usec)) {
      OSyncError *error = NULL;
      OSyncError *timeouterr = NULL;
      OSyncMessage *errormsg = NULL;

      /* Call the callback of the pending message */
      osync_assert(pending->callback);
      osync_error_set(&timeouterr, OSYNC_ERROR_IO_ERROR, "Timeout.");
      errormsg = osync_message_new_errorreply(NULL, timeouterr, &error);
      osync_error_unref(&timeouterr);

      /* Remove first the pending message!
         To avoid that _incoming_dispatch catchs this message
         when we're releasing the lock. If _incoming_dispatch
         would catch this message, the pending callback
         gets called twice! */

      queue->pendingReplies = g_list_remove(queue->pendingReplies, pending);
      /* Unlock the pending lock since the messages might be sent during the callback */
      g_mutex_unlock(queue->pendingLock);

      pending->callback(errormsg, pending->user_data);
      if (errormsg != NULL)
        osync_message_unref(errormsg);

      // TODO: Refcounting for OSyncPendingMessage
      g_free(pending->timeout_info);
      g_free(pending);

      /* Lock again, to keep the iteration of the pendingReplies list atomic. */
      g_mutex_lock(queue->pendingLock);

      break;
    }
  }
	
  g_mutex_unlock(queue->pendingLock);

  return TRUE;
}
OSyncXMLFieldList *osync_xmlformat_search_field(OSyncXMLFormat *xmlformat, const char *name, OSyncError **error, ...)
{
  int index;
  void *ret;
  OSyncXMLField *cur, *key, *res;
  OSyncXMLFieldList *xmlfieldlist = NULL;
  void **liste = NULL;
  osync_bool all_attr_equal;

  osync_trace(TRACE_ENTRY, "%s(%p, %s, %p, ...)", __func__, xmlformat, name, error);
  osync_assert(xmlformat);
  osync_assert(name);
	
  /* Searching breaks if the xmlformat is not sorted (bsearch!).
     ASSERT in development builds (when NDEBUG is not defined) - see ticket #754. */
  osync_assert(xmlformat->sorted);
  if (!xmlformat->sorted) {
    osync_error_set(error, OSYNC_ERROR_GENERIC, "XMLFormat is unsorted. Search result would be not valid.");
    goto error;
  }

  xmlfieldlist = osync_xmlfieldlist_new(error);
  if (!xmlfieldlist)
    goto error;

  liste = osync_try_malloc0(sizeof(OSyncXMLField *) * xmlformat->child_count, error);
  if (!liste)
    goto error;

  index = 0;
  cur = osync_xmlformat_get_first_field(xmlformat);
  for (; cur != NULL; cur = osync_xmlfield_get_next(cur)) {
    liste[index] = cur;
    index++;
  }

  key = osync_try_malloc0(sizeof(OSyncXMLField), error);
  if (!key) {
    g_free(liste);
    goto error;
  }

  key->node = xmlNewNode(NULL, BAD_CAST name);
	
  ret = bsearch(&key, liste, xmlformat->child_count, sizeof(OSyncXMLField *), osync_xmlfield_compare_stdlib);

  /* no result - return empty xmlfieldlist */
  if (!ret)
    goto end;

  /* if ret is valid pointer (not NULL!) - reference it here. avoid segfaults */
  res = *(OSyncXMLField **) ret;

  /* we set the cur ptr to the first field from the fields with name name because -> bsearch -> more than one field with the same name*/
  for (cur = res; cur->prev != NULL && !strcmp(osync_xmlfield_get_name(cur->prev), name); cur = cur->prev) ;

  for (; cur != NULL && !strcmp(osync_xmlfield_get_name(cur), name); cur = cur->next) {
    const char *attr, *value;
    va_list args;
    all_attr_equal = TRUE;
    va_start(args, error);
    do {
      attr = va_arg(args, char *);
      value = va_arg(args, char *);
      if (attr == NULL || value == NULL)
        break;

      if (strcmp(value, osync_xmlfield_get_attr(cur, attr)) != 0)
        all_attr_equal = FALSE;
    } while (1);
    va_end(args);

    if(all_attr_equal)
      osync_xmlfieldlist_add(xmlfieldlist, cur);
  }

 end:	
  /* free lists here (later) - bsearch result is still pointing in liste array */
  xmlFreeNode(key->node);
  g_free(key);
  g_free(liste);

  osync_trace(TRACE_EXIT, "%s: %p", __func__, xmlfieldlist);
  return xmlfieldlist;

 error:
  osync_trace(TRACE_EXIT_ERROR, "%s: %s" , __func__, osync_error_print(error));
  return NULL;
}
示例#21
0
/*Load the state from a xml file and return it in the conn struct*/
osync_bool synce_parse_settings(SyncePluginPtr *env, char *data, int size, OSyncError **error)
{
	osync_trace(TRACE_ENTRY, "%s(%p, %p, %i)", __func__, env, data, size);
	xmlDocPtr doc;
	xmlNodePtr cur;
        int i;

	/* set defaults */
        for (i = 0; i < TYPE_INDEX_MAX; i++)
                env->config_types[i] = FALSE;
	env->config_file = NULL;

	doc = xmlParseMemory(data, size);

	if (!doc) {
		osync_error_set(error, OSYNC_ERROR_GENERIC, "Unable to parse settings");
		osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
		return FALSE;
	}

	cur = xmlDocGetRootElement(doc);

	if (!cur) {
		xmlFreeDoc(doc);
		osync_error_set(error, OSYNC_ERROR_GENERIC, "Unable to get root element of the settings");
		osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
		return FALSE;
	}

	if (xmlStrcmp(cur->name, (xmlChar*)"config")) {
		xmlFreeDoc(doc);
		osync_error_set(error, OSYNC_ERROR_GENERIC, "Config valid is not valid");
		osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
		return FALSE;
	}

	cur = cur->xmlChildrenNode;

	while (cur != NULL) {
		char *str = (char*)xmlNodeGetContent(cur);
		if (str) {
			if (!xmlStrcmp(cur->name, (const xmlChar *)"contact")) {
				/* Disable by mentioning NO or FALSE, otherwise enable. */
				env->config_types[TYPE_INDEX_CONTACT] = TRUE;
				if (g_ascii_strcasecmp(str, "FALSE") == 0)
					env->config_types[TYPE_INDEX_CONTACT] = FALSE;
				if (g_ascii_strcasecmp(str, "NO") == 0)
					env->config_types[TYPE_INDEX_CONTACT] = FALSE;
			}
			if (!xmlStrcmp(cur->name, (const xmlChar *)"file")) {
				env->config_file = g_strdup(str);
			}
			if (!xmlStrcmp(cur->name, (const xmlChar *)"calendar")) {
				/* Disable by mentioning NO or FALSE, otherwise enable. */
				env->config_types[TYPE_INDEX_CALENDAR] = TRUE;
				if (g_ascii_strcasecmp(str, "FALSE") == 0)
					env->config_types[TYPE_INDEX_CALENDAR] = FALSE;
				if (g_ascii_strcasecmp(str, "NO") == 0)
					env->config_types[TYPE_INDEX_CALENDAR] = FALSE;
			}
			if (!xmlStrcmp(cur->name, (const xmlChar *)"todos")) {
				/* Disable by mentioning NO or FALSE, otherwise enable. */
				env->config_types[TYPE_INDEX_TODO] = TRUE;
				if (g_ascii_strcasecmp(str, "FALSE") == 0)
					env->config_types[TYPE_INDEX_CALENDAR] = FALSE;
				if (g_ascii_strcasecmp(str, "NO") == 0)
					env->config_types[TYPE_INDEX_CALENDAR] = FALSE;
			}
			xmlFree(str);
		}
		cur = cur->next;
	}

	xmlFreeDoc(doc);

	/* This belongs in XXX_connect()
	 * if (!osync_member_objtype_enabled(env->member, "contact"))
	 * 	env->config_contacts = FALSE;
	 * if (!osync_member_objtype_enabled(env->member, "todos"))
	 * 	env->config_todos = FALSE;
	 * if (!osync_member_objtype_enabled(env->member, "calendar"))
	 * 	env->config_calendar = FALSE;
	 */

	if (env->config_types[0] == 0 && env->config_types[1] == 0
			&& env->config_types[2] == 0 && env->config_file == NULL) {
		osync_error_set(error, OSYNC_ERROR_GENERIC, "Nothing was configured");
		osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
		return FALSE;
	}

	osync_trace(TRACE_EXIT, "%s", __func__);
	return TRUE;
}
osync_bool osync_mapping_engine_multiply(OSyncMappingEngine *engine, OSyncError **error)
{
  GList *e = NULL;
  osync_assert(engine);
  osync_assert(engine->mapping);
	
  osync_trace(TRACE_ENTRY, "%s(%p(%lli), %p)", __func__, engine, osync_mapping_get_id(engine->mapping), error);
		
  if (engine->synced) {
    osync_trace(TRACE_EXIT, "%s: No need to multiply. Already synced", __func__);
    return TRUE;
  }

  if (!engine->master) {
    osync_error_set(error, OSYNC_ERROR_GENERIC, "No master set");
    goto error;
  }

  for (e = engine->entries; e; e = e->next) {
    OSyncChange *existChange = NULL, *masterChange = NULL;
    OSyncData *masterData = NULL, *newData = NULL;
    OSyncMappingEntryEngine *entry_engine = e->data;
    OSyncChangeType existChangeType = 0, newChangeType = 0;
    if (entry_engine == engine->master)
      continue;
		
    osync_trace(TRACE_INTERNAL, "Propagating change %s to %p from %p", osync_mapping_entry_get_uid(entry_engine->entry), entry_engine, engine->master);
		
    /* Input is:
     * masterChange -> change that solved the mapping
     * masterData -> data of masterChange
     * existChange -> change that will be overwritten (if any) */
		
    existChange = entry_engine->change;
    masterChange = osync_entry_engine_get_change(engine->master);
    masterData = osync_change_get_data(masterChange);
		
    /* Clone the masterData. This has to be done since the data
     * might get changed (converted) and we dont want to touch the 
     * original data */
    newData = osync_data_clone(masterData, error);
    if (!newData)
      goto error;
		
    if (!existChange) {
      existChange = osync_change_new(error);
      if (!existChange)
        goto error;
			
      osync_change_set_changetype(existChange, OSYNC_CHANGE_TYPE_UNKNOWN);
    } else {
      /* Ref the change so that we can unref it later */
      osync_change_ref(existChange);
    }
		
    /* Save the changetypes, so that we can calculate the correct changetype later */
    existChangeType = osync_change_get_changetype(existChange);
    newChangeType = osync_change_get_changetype(masterChange);
		
    osync_trace(TRACE_INTERNAL, "Orig change type: %i New change type: %i", existChangeType, newChangeType);

    /* Now update the entry with the change */
    osync_entry_engine_update(entry_engine, existChange);
		
    /* We have to use the uid of the entry, so that the member
     * can correctly identify the entry 
     *
     * prahal: added a check if the entry has a uid to send the existing uid
     * to the plugins in case we have a slow-sync (both are added and have a uid) 
     * This to avoid creating duplicates by sending the plugins a different uid 
     * with the same or merged data 
     *
     * dgollub: enhanced the check if the entry has a uid to send the existing uid
     * to the plugins in case we have a slow-sync - both have changetype ADDED - and
     * for odd plugins/protocolls which mark new entries as MODIFIED all the time.
     * Changetype MODIFIED of new entries has atleast the IrMC plugin and likely some
     * SE SyncML implementation...
     * 
     * ^^irmc hacks in the irmc plugin ;-)
     *
     * dgollub: Set masterChange UID for existChange if entry_engine->entry doesn't have 
     * mapping uid, even if the newChangeType is UNKOWN. Bug: #571  
     *
     * prahal : rely on the fact that there are no mapping nor the entry existed to detect new change
     *	    Also avoid changing the id of the change if one existed and there where no mapping :
     *	    this way we send the id known to the member in case of a "modify". Fixing syncml plugin
     *	    freezing the phone and mozilla sync receiving an id it cannot do anything with for modify
     *	    in slow sync (no existing mapping).
     *
     */
    if ((!osync_mapping_entry_get_uid(entry_engine->entry) && !osync_change_get_uid(existChange))  ) 
      osync_change_set_uid(existChange, osync_change_get_uid(masterChange));
    else if(osync_mapping_entry_get_uid(entry_engine->entry)) 
      osync_change_set_uid(existChange, osync_mapping_entry_get_uid(entry_engine->entry));

    osync_change_set_data(existChange, newData);
    osync_change_set_changetype(existChange, osync_change_get_changetype(masterChange));
		
    /* We also have to update the changetype of the new change */
    if (newChangeType == OSYNC_CHANGE_TYPE_ADDED && (existChangeType != OSYNC_CHANGE_TYPE_DELETED && existChangeType != OSYNC_CHANGE_TYPE_UNKNOWN)) {
      osync_trace(TRACE_INTERNAL, "Updating change type to MODIFIED");
      osync_change_set_changetype(existChange, OSYNC_CHANGE_TYPE_MODIFIED);
      /* Only adapt the change to ADDED if the existing Change got deleted. Don't update it to ADDED if existChangeType is UNKOWN.
         The exitChangeType is at least also UNKOWN if the file-sync has only one modified entry. */
    } else if (newChangeType == OSYNC_CHANGE_TYPE_MODIFIED && (existChangeType == OSYNC_CHANGE_TYPE_DELETED)) {
      osync_trace(TRACE_INTERNAL, "Updating change type to ADDED");
      osync_change_set_changetype(existChange, OSYNC_CHANGE_TYPE_ADDED);
    }
		
    osync_change_unref(existChange);
    /* Also unref newData. Otherwise this cannot be freed when it is written. */
    osync_data_unref(newData);
			
    osync_entry_engine_set_dirty(entry_engine, TRUE);
  }
	
  osync_trace(TRACE_EXIT, "%s", __func__);
  return TRUE;

 error:
  osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
  return FALSE;
}
示例#23
0
static osync_bool init(OSyncError **error) {
	OSyncPluginConfig *config;
	assert(!plugin);
	assert(!plugin_env);

	if (!(plugin_env = osync_plugin_env_new(error)))
		goto error;

	if (!(format_env = osync_format_env_new(error)))
		goto error_free_pluginenv;

	if (!osync_format_env_load_plugins(format_env, formatpath, error))
		goto error_free_formatenv;

	if (osync_error_is_set(error)) {
		fprintf(stderr, "WARNING! Some plugins couldn't get loaded in "
				"format plugin environment: %s\n", osync_error_print(error));
		osync_error_unref(error);
	}

	if (!osync_plugin_env_load(plugin_env, pluginpath, error))
		goto error_free_pluginenv;

	if (osync_error_is_set(error)) {
		fprintf(stderr, "WARNING! Some plugins couldn't get loaded in "
				"plugin environment: %s\n", osync_error_print(error));
		osync_error_unref(error);
	}

	if (!(plugin = osync_plugin_env_find_plugin(plugin_env, pluginname))) {
		osync_error_set(error, OSYNC_ERROR_PLUGIN_NOT_FOUND, "Plugin not found: \"%s\"", pluginname);
		goto error_free_pluginenv;
	}

	if (!(plugin_info = osync_plugin_info_new(error)))
		goto error_free_pluginenv;

	config = osync_plugin_config_new(error);
	if (!config)
		goto error_free_plugininfo;

	if (osync_plugin_get_config_type(plugin) != OSYNC_PLUGIN_NO_CONFIGURATION && configfile) {
		OSyncList *r = NULL;
		if (!osync_plugin_config_file_load(config, configfile, error))
			goto error_free_pluginconfig;

		osync_plugin_info_set_config(plugin_info, config);

		/** Redudant(aka. stolen) code from opensync/client/opensync_client.c */
		/* Enable active sinks */

		if (config)
			r = osync_plugin_config_get_resources(config);

		for (; r; r = r->next) {
			OSyncPluginResource *res = r->data;
			OSyncObjTypeSink *sink;

			const char *objtype = osync_plugin_resource_get_objtype(res); 
			OSyncList *o = NULL;
			/* Check for ObjType sink */
			if (!(sink = osync_plugin_info_find_objtype(plugin_info, objtype))) {
				sink = osync_objtype_sink_new(objtype, error);
				if (!sink)
					goto error_free_pluginconfig;

				osync_plugin_info_add_objtype(plugin_info, sink);
			}
			OSyncList *objformats = osync_plugin_resource_get_objformat_sinks(res);
			for ( o = objformats; o; o = o->next) {
				OSyncObjFormatSink *format_sink = (OSyncObjFormatSink *) o->data; 
				osync_objtype_sink_add_objformat_sink(sink, format_sink);
			}
			osync_list_free(objformats);
		}

		osync_plugin_config_unref(config);

	}

	if (!configfile && osync_plugin_get_config_type(plugin) == OSYNC_PLUGIN_NEEDS_CONFIGURATION) {
		osync_error_set(error, OSYNC_ERROR_MISCONFIGURATION, "Plugin \"%s\" requires configuration!", pluginname); 
		goto error_free_pluginconfig;
	}

	assert(!ctx);
	ctx = g_main_context_new();

	osync_plugin_info_set_configdir(plugin_info, configdir);
	osync_plugin_info_set_loop(plugin_info, ctx);
	osync_plugin_info_set_format_env(plugin_info, format_env);
	osync_plugin_info_set_groupname(plugin_info, syncgroup);

	return TRUE;

	/*
		error_free_loop:
		g_main_context_unref(ctx);
	*/
 error_free_pluginconfig:
	osync_plugin_config_unref(config);
 error_free_plugininfo:
	osync_plugin_info_unref(plugin_info);
 error_free_formatenv:
	osync_format_env_unref(format_env);
	format_env = NULL;
 error_free_pluginenv:
	osync_plugin_env_unref(plugin_env);
	plugin_env = NULL;
 error:	
	return FALSE;
}