From: <svn...@op...> - 2010-02-11 02:02:51
|
Author: paule Date: Thu Feb 11 01:52:36 2010 New Revision: 6036 URL: http://www.opensync.org/changeset/6036 Log: opie-sync: support new synchronisation protocol in upcoming Opie 1.2.5 version; detect and handle base64 encoded QCop messages Modified: plugins/opie-sync/src/opie_qcop.c plugins/opie-sync/src/opie_qcop.h plugins/opie-sync/src/opie_sync.c plugins/opie-sync/src/opie_sync.h plugins/opie-sync/src/opie_xml.c plugins/opie-sync/src/opie_xml.h Modified: plugins/opie-sync/src/opie_qcop.c ============================================================================== --- plugins/opie-sync/src/opie_qcop.c Wed Feb 10 23:07:08 2010 (r6035) +++ plugins/opie-sync/src/opie_qcop.c Thu Feb 11 01:52:36 2010 (r6036) @@ -1,7 +1,8 @@ /* MultiSync Opie Plugin - Synchronize Opie/Zaurus Devices Copyright (C) 2003 Tom Foottit <to...@fo...> - Eike M. Lang <ma...@el...> + Eike M. Lang <ma...@el...> + Copyright (C) 2009 Paul Eggleton <blu...@bl...> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as @@ -45,6 +46,9 @@ #include <errno.h> #include <unistd.h> +#include <opensync/opensync.h> +#include <opensync/opensync-common.h> + #include "opie_qcop.h" #define OPIEQCOP_BUFLEN (1024) /* maximum response size */ @@ -282,7 +286,17 @@ if(!expect(qconn, "230", "530", "Failed to log into server - please check username / password")) return qconn; - + + /* Check if the other end is using old Sharp argument style */ + send_allof(qconn, "CALL QPE/System sendVersionInfo()\n"); + if (!expect(qconn, "200", NULL, "Failed to obtain versionInfo")) + return NULL; + char *pc = get_line(qconn); + if(strstr(pc, ") AAA")) + qconn->compatmode = TRUE; + else + qconn->compatmode = FALSE; + /* connected OK */ qconn->result = TRUE; } @@ -326,63 +340,278 @@ /* - * + * Send a QCop message */ -char* qcop_get_root(qcop_conn* qconn) +gboolean qcop_send(qcop_conn* qconn, const char *message, gchar **args) +{ + gchar *output; + if(args) { + /* FIXME: the Opie code uses this send method no matter what mode + is in use. Not sure about Qtopia. */ + + /* Replace special characters with their entity equivalents */ + int argc = g_strv_length(args); + gchar **args2 = g_new(gchar*, argc+1); + int i; + for(i=0; args[i] != NULL; i++) { + gchar *item = args[i]; + int count = 1; + int j; + for(j=0; item[j]; j++) { + if(strchr("\n\r& ", item[j])) + count+=6; + else + count++; + } + + gchar *item2 = (gchar *)g_malloc0(count); + gchar *ptr = item2; + for(j=0; item[j]; j++) { + if(item[j] == '\n') + ptr = g_stpcpy(ptr, "&0x0a;"); + else if(item[j] == '\r') + ptr = g_stpcpy(ptr, "&0x0d;"); + else if(item[j] == '&') + ptr = g_stpcpy(ptr, "&"); + else if(item[j] == ' ') + ptr = g_stpcpy(ptr, "&0x20;"); + else { + *ptr = item[j]; + ptr++; + } + } + args2[i] = item2; + } + args2[argc] = NULL; + gchar *argstr = g_strjoinv(" ", args2); + if(argc > 0) + g_strfreev(args2); + + output = g_strdup_printf("CALL %s %s\n", message, argstr); + g_free(argstr); + } + else + output = g_strdup_printf("CALL %s\n", message); + gboolean result = send_allof(qconn, output); + g_free(output); + return result; +} + +int decode_int_arg(guchar *data) +{ + return (data[0] >> 24) + (data[1] >> 16) + (data[2] >> 8) + data[3]; +} + +gchar *decode_string_arg(gchar *data, gsize *len) { + char *startc; + gsize outlen = 0; + GError *err = NULL; gchar* temp = NULL; - char* start; - gchar* pc; - - send_allof(qconn, "CALL QPE/System sendHandshakeInfo()\n"); - - if (!expect(qconn, "200", NULL, "Failed to obtain HandshakeInfo")) + + /* first four bytes are the string length */ + *len = decode_int_arg(data); + startc = data + 4; + temp = g_convert(startc, *len, "UTF8", "UTF16BE", NULL, &outlen, &err); + if (err != NULL) { + fprintf(stderr, "UTF16 convert error: %s\n", err->message); + g_error_free(err); + if(temp) { + /* Don't accept partial conversions */ + g_free(temp); + temp = NULL; + } + } + return temp; +} + +/* + * Wait for a QCop response message + */ +gchar **qcop_wait_for(qcop_conn* qconn, const char *message) +{ + if (!expect(qconn, "200", NULL, "Failed to retrieve expected result")) return NULL; - pc = get_line(qconn); - if(!strstr(pc, "handshakeInfo(QString,bool)")) - { + gchar *pc = get_line(qconn); + if(!strstr(pc, message)) { qconn->resultmsg = g_strdup_printf("Unrecognised response: %s", pc); g_free(pc); return NULL; } - - if ((start=strstr(strstr(pc,"/")+1,"/"))) /* We need the second slash */ - { - /* caller responsible for free()ing temp */ - temp = g_strndup(start,strstr(start," ")-start); /* from slash to blank is our path */ + + gchar **response = NULL; + if( qconn->compatmode ) { + gchar **parts = g_strsplit(pc, " ", 0); + gchar *msg = parts[2]; + char *ptr = strchr(msg, '('); + char *ptr2 = strchr(msg, ')'); + if(ptr && ptr2) { + *ptr2 = 0; + ptr++; + gchar **argtypes = g_strsplit(ptr, ",", 0); + *ptr2 = ')'; + + int argc = g_strv_length(argtypes); + response = g_new (gchar*, argc+4); + int i; + for(i=0; i<3; i++) + response[i] = g_strdup(parts[i]); + + gsize declen = 0; + guchar *decoded = g_base64_decode(parts[3], &declen); + if(declen > 0) { + ptr = decoded; + for(i=0; i<argc; i++) { + gchar *argtype = argtypes[i]; + if( strcmp(argtype, "QString") == 0 ) { + gsize outlen; + response[i+3] = decode_string_arg(ptr, &outlen); + ptr += (outlen+4); + } + else if( strcmp(argtype, "bool") == 0 || strcmp(argtype, "int") == 0 ) { + response[i+3] = g_strdup_printf("%d", decode_int_arg(ptr)); + ptr += 4; + } + else + response[i+3] = g_strdup(""); + } + } + response[argc+3] = NULL; + } + g_strfreev(parts); } - else if((start=strstr(pc,") ")+2)) - { - /* Qtopia sends back a base64 encoded utf-16 (big-endian) string */ - guchar *decoded; - char *startc; - gsize len = 0; - gsize len2 = 0; - GError *err = NULL; - - decoded = g_base64_decode(start, &len); - if(len > 0) { - /* first four bytes seem to be \0 \0 \0 (string length) */ - len = decoded[3]; - startc = decoded + 4; - temp = g_convert(startc, len, "UTF8", "UTF16BE", NULL, &len2, &err); - if (err != NULL) { - fprintf(stderr, "UTF16 convert error: %s\n", err->message); - g_error_free(err); - if(temp) { - /* Don't accept partial conversions */ - g_free(temp); - temp = NULL; + else { + response = g_strsplit(pc, " ", 0); + g_free(pc); + if( !qconn->compatmode ) { + int i; + for(i=0; response[i]; i++) { + if(i > 1 && strchr(response[i], '&')) { + /* Replace entities in arguments with their corresponding characters */ + gchar *item1 = osync_strreplace(response[i], "&0x20;", " "); + g_free(response[i]); + gchar *item2 = osync_strreplace(item1, "&0x0d;", "\n"); + g_free(item1); + item1 = osync_strreplace(item2, "&0x0a;", "\r"); + g_free(item2); + item2 = osync_strreplace(item1, "&", "&"); + g_free(item1); + response[i] = item2; } } } } + + return response; +} - if(!temp) - qconn->resultmsg = g_strdup_printf("Unrecognised response: %s", pc); - g_free(pc); - return temp; +/* + * Get the root path on the remote device (ie, the user's home directory) + */ +char* qcop_get_root(qcop_conn* qconn) +{ + qcop_send(qconn, "QPE/System sendHandshakeInfo()", NULL ); + + gchar **resp = qcop_wait_for(qconn, "QPE/Desktop handshakeInfo(QString,bool)"); + if(!resp) + return NULL; + + gchar *rootpath; + if( g_strv_length(resp) > 3 ) + rootpath = g_strdup(resp[3]); + else + rootpath = NULL; + g_strfreev(resp); + + return rootpath; +} + + +/* + * Get the version of Opie on the remote device + */ +gboolean qcop_get_version(qcop_conn* qconn, qcop_version_info *version) +{ + qcop_send(qconn, "QPE/System sendVersionInfo()", NULL ); + gchar **resp = qcop_wait_for(qconn, "QPE/Desktop versionInfo(QString,QString)"); + if(!resp) + return FALSE; + + version->opie_major_version = 0; + version->opie_minor_version = 0; + version->opie_sub_version = 0; + if( g_strv_length(resp) > 4 ) { + gchar **verparts = g_strsplit(resp[4], " ", 0); + if( g_strv_length(verparts) > 1 && strcmp(verparts[0], "Opie") == 0 ) { + gchar **vernumparts = g_strsplit(verparts[1], ".", 0); + if( g_strv_length(vernumparts) > 2 ) { + version->opie_major_version = atoi(vernumparts[0]); + version->opie_minor_version = atoi(vernumparts[1]); + version->opie_sub_version = atoi(vernumparts[2]); + } + g_strfreev(vernumparts); + } + g_strfreev(verparts); + } + g_strfreev(resp); + + return TRUE; +} + +gboolean qcop_set_peer_info(qcop_conn* qconn, const char *peer_id, const char *peer_name) +{ + gchar **args = g_new (gchar*, 3); + args[0] = g_strdup(peer_id); + args[1] = g_strdup(peer_name); + args[2] = NULL; + qcop_send(qconn, "QPE/System setSyncPeerInfo(QString,QString)", args); + gchar **resp = qcop_wait_for(qconn, "QPE/Desktop syncPeerInfoSet()"); + g_strfreev(args); + if(!resp) + return FALSE; + + g_strfreev(resp); + return TRUE; +} + +gboolean qcop_start_app_sync(qcop_conn* qconn, const char *appname, gboolean request_slow_sync_read, gboolean request_slow_sync_write, gboolean *has_changelog, gboolean *slow_sync_read) +{ + gchar **args = g_new (gchar*, 4); + args[0] = g_strdup(appname); + args[1] = g_strdup_printf("%d", request_slow_sync_read); + args[2] = g_strdup_printf("%d", request_slow_sync_write); + args[3] = NULL; + qcop_send(qconn, "QPE/System startAppSync(QString,bool,bool)", args); + gchar **resp = qcop_wait_for(qconn, "QPE/Desktop appSyncStarted(bool,bool)"); + g_strfreev(args); + if(!resp) + return FALSE; + + gboolean result = FALSE; + if( g_strv_length(resp) > 4 ) { + result = TRUE; + *has_changelog = (atoi(resp[3]) != 0); + *slow_sync_read = (atoi(resp[4]) != 0); + } + + g_strfreev(resp); + return result; +} + +gboolean qcop_finish_app_sync(qcop_conn* qconn, const char *appname) +{ + gchar **args = g_new (gchar*, 2); + args[0] = g_strdup(appname); + args[1] = NULL; + qcop_send(qconn, "QPE/System finishAppSync(QString)", args); + gchar **resp = qcop_wait_for(qconn, "QPE/Desktop appSyncDone(QString)"); + g_strfreev(args); + if(!resp) + return FALSE; + + g_strfreev(resp); + return TRUE; } Modified: plugins/opie-sync/src/opie_qcop.h ============================================================================== --- plugins/opie-sync/src/opie_qcop.h Wed Feb 10 23:07:08 2010 (r6035) +++ plugins/opie-sync/src/opie_qcop.h Thu Feb 11 01:52:36 2010 (r6036) @@ -36,6 +36,7 @@ char* resultmsg; /* string associated with the result (error msg, etc) */ int socket; /* socket open to the QCopBridge server */ gboolean syncing; /* Tells us whether we are currently syncing */ + gboolean compatmode; /* True if we need to use base64 for arguments */ pthread_mutex_t access_mutex; /* At times we have two threads sharing access, so we need this */ } qcop_conn; @@ -47,12 +48,24 @@ } qcop_monitor_data; +typedef struct +{ + int opie_major_version; + int opie_minor_version; + int opie_sub_version; +} qcop_version_info; + + qcop_conn* qcop_connect(gchar* addr, gchar* username, gchar* password); void qcop_disconnect(qcop_conn* qconn); void qcop_freeqconn(qcop_conn* qconn); -gboolean qcop_send(qcop_conn* qconn, const char *message, const char *args); -char *qcop_wait_for(qcop_conn* qconn, const char *message); +gboolean qcop_send(qcop_conn* qconn, const char *message, gchar **args); +gchar **qcop_wait_for(qcop_conn* qconn, const char *message); char* qcop_get_root(qcop_conn* qconn); +gboolean qcop_get_version(qcop_conn* qconn, qcop_version_info *version); +gboolean qcop_set_peer_info(qcop_conn* qconn, const char *peer_id, const char *peer_name); +gboolean qcop_start_app_sync(qcop_conn* qconn, const char *appname, gboolean request_slow_sync_read, gboolean request_slow_sync_write, gboolean *has_changelog, gboolean *slow_sync_read); +gboolean qcop_finish_app_sync(qcop_conn* qconn, const char *appname); void qcop_start_sync(qcop_conn* qconn, void (*cancel_routine)()); void qcop_stop_sync(qcop_conn* qconn); Modified: plugins/opie-sync/src/opie_sync.c ============================================================================== --- plugins/opie-sync/src/opie_sync.c Wed Feb 10 23:07:08 2010 (r6035) +++ plugins/opie-sync/src/opie_sync.c Thu Feb 11 01:52:36 2010 (r6036) @@ -262,6 +262,7 @@ g_free(key); key = osync_rand_str(10, &error); env->plugin_env->password = g_strdup_printf("QtopiaXX%s", key); + osync_sink_state_set(state_db, "sync_key", env->plugin_env->password, &error); } else env->plugin_env->password = g_strdup(key); @@ -275,6 +276,56 @@ goto error; } env->plugin_env->connected = TRUE; + + env->plugin_env->opie_v1_2_5 = FALSE; + if(env->plugin_env->use_qcop) { + qcop_version_info version; + if(!qcop_get_version(env->plugin_env->qcopconn, &version)) { + char *errmsg = g_strdup_printf("qcop_get_version failed: %s", env->plugin_env->qcopconn->resultmsg); + osync_error_set(&error, OSYNC_ERROR_GENERIC, errmsg); + g_free(errmsg); + g_mutex_unlock(env->plugin_env->plugin_mutex); + goto error; + } + osync_trace(TRACE_INTERNAL, "Opie version is %d.%d.%d", + version.opie_major_version, + version.opie_minor_version, + version.opie_sub_version); + + if(version.opie_major_version > 1 || version.opie_minor_version > 2 || + (version.opie_major_version == 1 && version.opie_minor_version == 2 && version.opie_sub_version >= 5)) + env->plugin_env->opie_v1_2_5 = TRUE; + } + } + + if(env->plugin_env->opie_v1_2_5) { + /* Get the peer ID */ + char *peer_id = osync_sink_state_get(state_db, "peer_id", &error); + if(!peer_id) { + g_mutex_unlock(env->plugin_env->plugin_mutex); + goto error; + } + g_free(env->plugin_env->peer_id); + if(strlen(peer_id) == 0) { + g_free(peer_id); + peer_id = osync_rand_str(20, &error); + env->plugin_env->peer_id = g_strdup(peer_id); + osync_sink_state_set(state_db, "peer_id", env->plugin_env->peer_id, &error); + } + else + env->plugin_env->peer_id = g_strdup(peer_id); + osync_free(peer_id); + /* FIXME: do we need to keep the peer ID global? */ + + /* Get hostname */ + const gchar *hostname = g_get_host_name(); + if(!qcop_set_peer_info(env->plugin_env->qcopconn, env->plugin_env->peer_id, hostname)) { + char *errmsg = g_strdup_printf("qcop_set_peer_info failed: %s", env->plugin_env->qcopconn->resultmsg); + osync_error_set(&error, OSYNC_ERROR_GENERIC, errmsg); + g_free(errmsg); + g_mutex_unlock(env->plugin_env->plugin_mutex); + goto error; + } } if(!env->plugin_env->categories_doc) { @@ -298,10 +349,68 @@ { osync_trace(TRACE_ENTRY, "%s(%p, %p, %p, %p)", __func__, sink, info, ctx, data); OpieSinkEnv *env = (OpieSinkEnv *)data; + OSyncSinkStateDB *state_db = osync_objtype_sink_get_state_db(sink); OSyncError *error = NULL; + g_mutex_lock(env->plugin_env->plugin_mutex); + gboolean connected = env->plugin_env->connected; + g_mutex_unlock(env->plugin_env->plugin_mutex); + + if(!connected) { + char *errmsg; + errmsg = g_strdup_printf("Device not connected"); + osync_error_set(&error, OSYNC_ERROR_GENERIC, errmsg); + g_free(errmsg); + goto error; + } + + if(env->objtype == OPIE_OBJECT_TYPE_NOTE) { + /* Check if the notes resource has changed since the last sync */ + osync_bool state_match = FALSE; + if(!osync_sink_state_equal(state_db, "notes_path", env->plugin_env->notes_path, &state_match, &error)) + goto error; + if(!state_match) + osync_context_report_slowsync(ctx); + } + + env->fastcapable = FALSE; + gboolean force_slowsync = FALSE; + if(env->plugin_env->opie_v1_2_5 && env->plugin_env->use_qcop) { + env->slow_sync_en = FALSE; + if(!qcop_start_app_sync(env->plugin_env->qcopconn, env->appname, env->slow_sync_en, FALSE, &env->fastcapable, &force_slowsync)) { + char *errmsg; + errmsg = g_strdup_printf("Couldn't start application sync for %s: %s", env->appname, env->plugin_env->qcopconn->resultmsg); + osync_error_set(&error, OSYNC_ERROR_GENERIC, errmsg); + g_free(errmsg); + goto error; + } + if(env->fastcapable) { + osync_trace(TRACE_INTERNAL, "%s is fast capable", env->appname); + /* We won't be using the hashtable, so if Opie says we need to + slow-sync then we really do need to do that */ + if(force_slowsync) { + osync_trace(TRACE_INTERNAL, "%s - force slow-sync", env->appname); + env->slow_sync_en = TRUE; + } + if(env->slow_sync_en) { + osync_trace(TRACE_INTERNAL, "%s - reqesting slow-sync", env->appname); + osync_context_report_slowsync(ctx); + } + } + } + gchar *fastcapablestr = g_strdup_printf("%d", env->fastcapable); + char *lastfastcapablestr = osync_sink_state_get(state_db, "fastcapable", &error); + printf("&&&&& %s == %s\n", lastfastcapablestr, fastcapablestr); + if( !env->slow_sync_en && strcmp(lastfastcapablestr, fastcapablestr) ) { + /* We have changed between 1.2.5 and earlier or SQL and text backends + (one way or the other) so force a slow-sync */ + osync_trace(TRACE_INTERNAL, "%s - fast capable change - requesting slow-sync", env->appname); + osync_context_report_slowsync(ctx); + } + g_free(fastcapablestr); + osync_context_report_success(ctx); osync_trace(TRACE_EXIT, "%s", __func__); return; @@ -320,18 +429,19 @@ OSyncError *error = NULL; - g_mutex_lock(env->plugin_env->plugin_mutex); - gboolean connected = env->plugin_env->connected; - g_mutex_unlock(env->plugin_env->plugin_mutex); - - if(!connected) { - char *errmsg; - errmsg = g_strdup_printf("Device not connected"); - osync_error_set(&error, OSYNC_ERROR_GENERIC, errmsg); - g_free(errmsg); - goto error; + if(slow_sync && !env->slow_sync_en && env->fastcapable) { + gboolean unused1, unused2; + /* Slow-sync requested by someone else, we have to tell Opie about it */ + if(!qcop_start_app_sync(env->plugin_env->qcopconn, env->appname, TRUE, FALSE, &unused1, &unused2)) { + char *errmsg; + errmsg = g_strdup_printf("Couldn't start application slow-sync for %s: %s", env->appname, env->plugin_env->qcopconn->resultmsg); + osync_error_set(&error, OSYNC_ERROR_GENERIC, errmsg); + g_free(errmsg); + goto error; + } + env->slow_sync_en = TRUE; } - + /* pull the required data back */ if(!opie_fetch_sink(env, ctx)) { @@ -345,23 +455,15 @@ goto error; } - if(env->objtype == OPIE_OBJECT_TYPE_NOTE) { - /* Check if the notes resource has changed since the last sync */ - OSyncSinkStateDB *state_db = osync_objtype_sink_get_state_db(sink); - osync_bool state_match = FALSE; - if(!osync_sink_state_equal(state_db, "notes_path", env->plugin_env->notes_path, &state_match, &error)) - goto error; - if(!state_match) - osync_context_report_slowsync(ctx); - } - if (slow_sync) { osync_trace(TRACE_INTERNAL, "Slow sync requested"); - if (!osync_hashtable_slowsync(hashtable, &error)) { - osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(&error)); - osync_context_report_osyncerror(ctx, error); - return; + if( !env->fastcapable ) { + if (!osync_hashtable_slowsync(hashtable, &error)) { + osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(&error)); + osync_context_report_osyncerror(ctx, error); + return; + } } } @@ -389,14 +491,23 @@ char *hash = hash_xml_node(env->doc, item_node); osync_change_set_hash(change, hash); g_free(hash); + + OSyncChangeType changetype; + if( env->fastcapable ) { + /* Detect the type of change */ + changetype = opie_xml_get_change_type(item_node); + } + else { + /* Detect the type of change */ + changetype = osync_hashtable_get_changetype(hashtable, change); + + /* Update the hashtable with the hash of the object */ + osync_hashtable_update_change(hashtable, change); + } - /* Detect and set the type of change */ - OSyncChangeType changetype = osync_hashtable_get_changetype(hashtable, change); + /* Set the type of change */ osync_change_set_changetype(change, changetype); - - /* Update the hashtable with the hash of the object */ - osync_hashtable_update_change(hashtable, change); - + if (changetype != OSYNC_CHANGE_TYPE_UNMODIFIED) { /* Convert category IDs to names that other systems can use */ g_mutex_lock(env->plugin_env->plugin_mutex); @@ -437,40 +548,42 @@ item_node = opie_xml_get_next(item_node); } - /* Check for deleted entries using the hashtable */ - OSyncList *u, *uids = osync_hashtable_get_deleted(hashtable); - for (u = uids; u; u = u->next) { - const char *uid = u->data; - - OSyncChange *change = osync_change_new(&error); - if (!change) { - osync_context_report_osyncwarning(ctx, error); - osync_error_unref(&error); - continue; - } + if( !env->fastcapable ) { + /* Check for deleted entries using the hashtable */ + OSyncList *u, *uids = osync_hashtable_get_deleted(hashtable); + for (u = uids; u; u = u->next) { + const char *uid = u->data; + + OSyncChange *change = osync_change_new(&error); + if (!change) { + osync_context_report_osyncwarning(ctx, error); + osync_error_unref(&error); + continue; + } - osync_change_set_uid(change, uid); - osync_change_set_changetype(change, OSYNC_CHANGE_TYPE_DELETED); + osync_change_set_uid(change, uid); + osync_change_set_changetype(change, OSYNC_CHANGE_TYPE_DELETED); - OSyncData *odata = osync_data_new(NULL, 0, env->objformat, &error); - if (!odata) { - osync_change_unref(change); - osync_context_report_osyncwarning(ctx, error); - osync_error_unref(&error); - continue; - } + OSyncData *odata = osync_data_new(NULL, 0, env->objformat, &error); + if (!odata) { + osync_change_unref(change); + osync_context_report_osyncwarning(ctx, error); + osync_error_unref(&error); + continue; + } - osync_data_set_objtype(odata, osync_objtype_sink_get_name(sink)); - osync_change_set_data(change, odata); - osync_data_unref(odata); + osync_data_set_objtype(odata, osync_objtype_sink_get_name(sink)); + osync_change_set_data(change, odata); + osync_data_unref(odata); - osync_context_report_change(ctx, change); + osync_context_report_change(ctx, change); - osync_hashtable_update_change(hashtable, change); + osync_hashtable_update_change(hashtable, change); - osync_change_unref(change); + osync_change_unref(change); + } + osync_list_free(uids); } - osync_list_free(uids); //Now we need to answer the call osync_context_report_success(ctx); @@ -525,8 +638,11 @@ hash = hash_xml_node(env->doc, change_node); } } - - switch (osync_change_get_changetype(change)) { + + OSyncChangeType changetype = osync_change_get_changetype(change); + if( env->fastcapable ) + opie_xml_set_change_type(change_node, changetype); + switch (changetype) { case OSYNC_CHANGE_TYPE_DELETED: if(!opie_uid) { if(!strcmp(env->itemelement, "note")) @@ -573,7 +689,8 @@ if(change_doc) xmlFreeDoc(change_doc); - osync_hashtable_update_change(hashtable, change); + if( !env->fastcapable ) + osync_hashtable_update_change(hashtable, change); //Answer the call osync_context_report_success(ctx); @@ -594,7 +711,7 @@ OSyncError *error = NULL; if ( !opie_put_sink(env) ) { - osync_trace( TRACE_INTERNAL, "opie_connect_and_put failed" ); + osync_trace( TRACE_INTERNAL, "opie_put_sink failed" ); char *errmsg = g_strdup_printf( "Failed to send data to device %s", env->plugin_env->host ); /* FIXME specify which data */ osync_error_set(&error, OSYNC_ERROR_GENERIC, errmsg); g_free(errmsg); @@ -607,6 +724,22 @@ goto error; } + if(env->plugin_env->opie_v1_2_5 && env->plugin_env->use_qcop) { + if(!qcop_finish_app_sync(env->plugin_env->qcopconn, env->appname)) { + osync_trace( TRACE_INTERNAL, "qcop_finish_app_sync failed" ); + char *errmsg; + errmsg = g_strdup_printf("Couldn't finish application sync for %s: %s", env->appname, env->plugin_env->qcopconn->resultmsg); + osync_error_set(&error, OSYNC_ERROR_GENERIC, errmsg); + g_free(errmsg); + goto error; + } + } + + gchar *fastcapablestr = g_strdup_printf("%d", env->fastcapable); + OSyncSinkStateDB *state_db = osync_objtype_sink_get_state_db(sink); + osync_sink_state_set(state_db, "fastcapable", fastcapablestr, &error); + g_free(fastcapablestr); + osync_context_report_success(ctx); osync_trace(TRACE_EXIT, "%s", __func__); return; @@ -659,7 +792,7 @@ osync_context_report_success(ctx); } -OpieSinkEnv *opie_sync_create_sink_env(OpiePluginEnv *env, OSyncPluginInfo *info, const char *objtype, const char *objformat, OPIE_OBJECT_TYPE opie_objtype, const char *remotefile, const char *listelement, const char *itemelement, OSyncError **error) +OpieSinkEnv *opie_sync_create_sink_env(OpiePluginEnv *env, OSyncPluginInfo *info, const char *appname, const char *objtype, const char *objformat, OPIE_OBJECT_TYPE opie_objtype, const char *remotefile, const char *listelement, const char *itemelement, OSyncError **error) { OSyncObjTypeSink *sink = osync_plugin_info_find_objtype(info, objtype); if (!sink) { @@ -675,6 +808,7 @@ sink_env->listelement = listelement; sink_env->itemelement = itemelement; sink_env->remotefile = remotefile; + sink_env->appname = appname; sink_env->objtype = opie_objtype; OSyncFormatEnv *formatenv = osync_plugin_info_get_format_env(info); @@ -693,6 +827,9 @@ /* Request a hashtable from the framework. */ osync_objtype_sink_enable_hashtable(sink, TRUE); + + /* Request a state db from the framework. */ + osync_objtype_sink_enable_state_db(sink, TRUE); return sink_env; } @@ -727,25 +864,24 @@ osync_plugin_info_set_main_sink(info, env->main_sink_env->sink); /* Contacts sink */ - env->contact_env = opie_sync_create_sink_env(env, info, "contact", OPIE_FORMAT_XML_CONTACT, OPIE_OBJECT_TYPE_CONTACT, OPIE_ADDRESS_FILE, "Contacts", "Contact", error); + env->contact_env = opie_sync_create_sink_env(env, info, "addressbook", "contact", OPIE_FORMAT_XML_CONTACT, OPIE_OBJECT_TYPE_CONTACT, OPIE_ADDRESS_FILE, "Contacts", "Contact", error); if(!env->contact_env) goto error_free_env; /* Todos sink */ - env->todo_env = opie_sync_create_sink_env(env, info, "todo", OPIE_FORMAT_XML_TODO, OPIE_OBJECT_TYPE_TODO, OPIE_TODO_FILE, "Tasks", "Task", error); + env->todo_env = opie_sync_create_sink_env(env, info, "todolist", "todo", OPIE_FORMAT_XML_TODO, OPIE_OBJECT_TYPE_TODO, OPIE_TODO_FILE, "Tasks", "Task", error); if(!env->todo_env) goto error_free_env; /* Events sink */ - env->event_env = opie_sync_create_sink_env(env, info, "event", OPIE_FORMAT_XML_EVENT, OPIE_OBJECT_TYPE_EVENT, OPIE_CALENDAR_FILE, "events", "event", error); + env->event_env = opie_sync_create_sink_env(env, info, "datebook", "event", OPIE_FORMAT_XML_EVENT, OPIE_OBJECT_TYPE_EVENT, OPIE_CALENDAR_FILE, "events", "event", error); if(!env->event_env) goto error_free_env; /* Notes sink */ - env->note_env = opie_sync_create_sink_env(env, info, "note", OPIE_FORMAT_XML_NOTE, OPIE_OBJECT_TYPE_NOTE, NULL, "notes", "note", error); + env->note_env = opie_sync_create_sink_env(env, info, "notes", "note", OPIE_FORMAT_XML_NOTE, OPIE_OBJECT_TYPE_NOTE, NULL, "memos", "memo", error); if(!env->note_env) goto error_free_env; - osync_objtype_sink_enable_state_db(env->note_env->sink, TRUE); env->qcopconn = NULL; env->connected = FALSE; Modified: plugins/opie-sync/src/opie_sync.h ============================================================================== --- plugins/opie-sync/src/opie_sync.h Wed Feb 10 23:07:08 2010 (r6035) +++ plugins/opie-sync/src/opie_sync.h Thu Feb 11 01:52:36 2010 (r6036) @@ -71,9 +71,12 @@ gchar* localdir; /* path to local files if conntype = OPIE_CONN_NONE (for debugging) */ gchar* notes_path; + gchar* peer_id; + gboolean use_qcop; qcop_conn* qcopconn; gboolean connected; + gboolean opie_v1_2_5; gchar* dev_root_path; xmlDoc* categories_doc; @@ -92,9 +95,12 @@ OSyncObjTypeSink* sink; xmlDoc* doc; OSyncObjFormat* objformat; + const char* appname; const char* listelement; const char* itemelement; const char* remotefile; + gboolean fastcapable; /* Whether or not fast-sync is available for this sink */ + gboolean slow_sync_en; /* Whether or not Opie has been told we are slow-syncing */ OPIE_OBJECT_TYPE objtype; }; Modified: plugins/opie-sync/src/opie_xml.c ============================================================================== --- plugins/opie-sync/src/opie_xml.c Wed Feb 10 23:07:08 2010 (r6035) +++ plugins/opie-sync/src/opie_xml.c Thu Feb 11 01:52:36 2010 (r6036) @@ -392,8 +392,7 @@ uidattr = "uid"; } else if(!strcasecmp(node->name, "note")) { - /* Notes don't have a UID on the Opie side, but the name should be unique */ - uidattr = "name"; + uidattr = "uid"; } else if(!strcasecmp(node->name, "Category")) { uidattr = "id"; @@ -547,7 +546,7 @@ void opie_xml_set_categories(xmlNode *item_node, const char *value) { char *attr_name; - if(!strcasecmp(item_node->name, "event")) { + if(!strcasecmp(item_node->name, "event") || !strcasecmp(item_node->name, "memo")) { attr_name = "categories"; } else { @@ -557,6 +556,35 @@ xmlSetProp(item_node, attr_name, value); } +OSyncChangeType opie_xml_get_change_type(xmlNode *item_node) { + OSyncChangeType changetype = OSYNC_CHANGE_TYPE_ADDED; + char *value = xmlGetProp(item_node, "change_action"); + if(value) { + if(!strcmp(value, "U")) + changetype = OSYNC_CHANGE_TYPE_MODIFIED; + if(!strcmp(value, "D")) + changetype = OSYNC_CHANGE_TYPE_DELETED; + xmlFree(value); + } + return changetype; +} + +void opie_xml_set_change_type(xmlNode *item_node, OSyncChangeType changetype) { + const char * action; + switch(changetype) { + case OSYNC_CHANGE_TYPE_MODIFIED: + action = "U"; + break; + case OSYNC_CHANGE_TYPE_DELETED: + action = "D"; + break; + default: + action = "A"; + break; + } + xmlSetProp(item_node, "change_action", action); +} + xmlDoc *opie_xml_create_contacts_doc(void) { xmlDoc *doc = xmlNewDoc((xmlChar*)"1.0"); @@ -623,6 +651,8 @@ xmlNode *root = xmlNewNode(NULL, "notes"); xmlDocSetRootElement(doc, root); + xmlNode *cur = xmlNewNode(NULL, "memos"); + xmlAddChild(root, cur); return doc; } @@ -647,12 +677,12 @@ } xmlNode *opie_xml_add_note_node(xmlDoc *doc, const char *name, const char *direntry, const char *content) { - xmlNode *notes_node = opie_xml_get_collection(doc, "notes"); + xmlNode *notes_node = opie_xml_get_collection(doc, "memos"); if(!notes_node) { osync_trace(TRACE_INTERNAL, "Unable to create new XML document"); return NULL; } - xmlNode *note_node = xmlNewTextChild(notes_node, NULL, (xmlChar*)"note", NULL); + xmlNode *note_node = xmlNewTextChild(notes_node, NULL, (xmlChar*)"memo", NULL); /* FIXME this needs implementing @@ -681,8 +711,9 @@ } } */ - xmlSetProp(note_node, (xmlChar*)"name", name); - xmlNewTextChild(note_node, NULL, (xmlChar*)"content", content); + xmlSetProp(note_node, (xmlChar*)"uid", name); + xmlSetProp(note_node, (xmlChar*)"text", content); + // FIXME categories return note_node; } Modified: plugins/opie-sync/src/opie_xml.h ============================================================================== --- plugins/opie-sync/src/opie_xml.h Wed Feb 10 23:07:08 2010 (r6035) +++ plugins/opie-sync/src/opie_xml.h Thu Feb 11 01:52:36 2010 (r6036) @@ -54,6 +54,8 @@ void opie_xml_category_names_to_ids(xmlDoc *categories_doc, xmlNode *change_node); char *opie_xml_get_categories(xmlNode *item_node); void opie_xml_set_categories(xmlNode *item_node, const char *value); +OSyncChangeType opie_xml_get_change_type(xmlNode *item_node); +void opie_xml_set_change_type(xmlNode *item_node, OSyncChangeType changetype); xmlDoc *opie_xml_create_contacts_doc(void); xmlDoc *opie_xml_create_todos_doc(void); xmlDoc *opie_xml_create_calendar_doc(void); |