| 21 | | #include "config.h" |
|---|
| 22 | | |
|---|
| 23 | | #include "syncml_common.h" |
|---|
| 24 | | |
|---|
| 25 | | #ifdef ENABLE_HTTP |
|---|
| 26 | | # include "syncml_http_client.h" |
|---|
| 27 | | # include "syncml_http_server.h" |
|---|
| 28 | | #endif |
|---|
| 29 | | |
|---|
| 30 | | #ifdef ENABLE_OBEX |
|---|
| 31 | | # include "syncml_obex_client.h" |
|---|
| 32 | | #endif |
|---|
| | 21 | #include "syncml_plugin.h" |
|---|
| | 22 | |
|---|
| | 23 | static void syncml_free_database(SmlDatabase *database) |
|---|
| | 24 | { |
|---|
| | 25 | if (database->url) |
|---|
| | 26 | g_free(database->url); |
|---|
| | 27 | |
|---|
| | 28 | if (database->objtype) |
|---|
| | 29 | g_free(database->objtype); |
|---|
| | 30 | |
|---|
| | 31 | if (database->objformat_name) |
|---|
| | 32 | g_free(database->objformat_name); |
|---|
| | 33 | |
|---|
| | 34 | if (database->sink) |
|---|
| | 35 | osync_objtype_sink_unref(database->sink); |
|---|
| | 36 | |
|---|
| | 37 | g_free(database); |
|---|
| | 38 | } |
|---|
| | 39 | |
|---|
| | 40 | static SmlChangeType _get_changetype(OSyncChange *change) |
|---|
| | 41 | { |
|---|
| | 42 | switch (osync_change_get_changetype(change)) { |
|---|
| | 43 | case OSYNC_CHANGE_TYPE_ADDED: |
|---|
| | 44 | return SML_CHANGE_ADD; |
|---|
| | 45 | case OSYNC_CHANGE_TYPE_MODIFIED: |
|---|
| | 46 | return SML_CHANGE_REPLACE; |
|---|
| | 47 | case OSYNC_CHANGE_TYPE_DELETED: |
|---|
| | 48 | return SML_CHANGE_DELETE; |
|---|
| | 49 | default: |
|---|
| | 50 | ; |
|---|
| | 51 | } |
|---|
| | 52 | return SML_CHANGE_UNKNOWN; |
|---|
| | 53 | } |
|---|
| | 54 | |
|---|
| | 55 | static const char *_objtype_to_contenttype(const char *objtype) |
|---|
| | 56 | { |
|---|
| | 57 | if (!strcmp(objtype, "contact")) { |
|---|
| | 58 | return SML_ELEMENT_TEXT_VCARD; |
|---|
| | 59 | } |
|---|
| | 60 | if (!strcmp(objtype, "event")) { |
|---|
| | 61 | return SML_ELEMENT_TEXT_VCAL; |
|---|
| | 62 | } |
|---|
| | 63 | if (!strcmp(objtype, "todo")) { |
|---|
| | 64 | return SML_ELEMENT_TEXT_VCAL; |
|---|
| | 65 | } |
|---|
| | 66 | if (!strcmp(objtype, "note")) { |
|---|
| | 67 | return SML_ELEMENT_TEXT_PLAIN; |
|---|
| | 68 | } |
|---|
| | 69 | if (!strcmp(objtype, "data")) { |
|---|
| | 70 | return SML_ELEMENT_TEXT_PLAIN; |
|---|
| | 71 | } |
|---|
| | 72 | return NULL; |
|---|
| | 73 | } |
|---|
| | 74 | |
|---|
| | 75 | static const char *_format_to_contenttype(OSyncChange *change) |
|---|
| | 76 | { |
|---|
| | 77 | return _objtype_to_contenttype(osync_change_get_objtype(change)); |
|---|
| | 78 | } |
|---|
| | 79 | |
|---|
| | 80 | static osync_bool syncml_config_parse_database(SmlPluginEnv *env, xmlNode *cur, OSyncError **error) |
|---|
| | 81 | { |
|---|
| | 82 | osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, env, cur, error); |
|---|
| | 83 | |
|---|
| | 84 | SmlDatabase *database = osync_try_malloc0(sizeof(SmlDatabase), error); |
|---|
| | 85 | if (!database) |
|---|
| | 86 | goto error; |
|---|
| | 87 | |
|---|
| | 88 | database->env = env; |
|---|
| | 89 | |
|---|
| | 90 | while (cur != NULL) { |
|---|
| | 91 | char *str = (char*)xmlNodeGetContent(cur); |
|---|
| | 92 | if (str) { |
|---|
| | 93 | if (!xmlStrcmp(cur->name, (const xmlChar *)"name")) { |
|---|
| | 94 | database->url = g_strdup(str); |
|---|
| | 95 | } else if (!xmlStrcmp(cur->name, (const xmlChar *)"objtype")) { |
|---|
| | 96 | database->objtype = g_strdup(str); |
|---|
| | 97 | } else if (!xmlStrcmp(cur->name, (const xmlChar *)"objformat")) { |
|---|
| | 98 | database->objformat_name = g_strdup(str);; |
|---|
| | 99 | } |
|---|
| | 100 | |
|---|
| | 101 | xmlFree(str); |
|---|
| | 102 | } |
|---|
| | 103 | cur = cur->next; |
|---|
| | 104 | } |
|---|
| | 105 | |
|---|
| | 106 | if (!database->url) { |
|---|
| | 107 | osync_error_set(error, OSYNC_ERROR_GENERIC, "Database name not set"); |
|---|
| | 108 | goto error_free_database; |
|---|
| | 109 | } |
|---|
| | 110 | |
|---|
| | 111 | if (!database->objtype) { |
|---|
| | 112 | osync_error_set(error, OSYNC_ERROR_GENERIC, "\"objtype\" of a database not set"); |
|---|
| | 113 | goto error_free_database; |
|---|
| | 114 | } |
|---|
| | 115 | |
|---|
| | 116 | if (!database->objformat_name) { |
|---|
| | 117 | osync_error_set(error, OSYNC_ERROR_GENERIC, "Object Fomrat \"%s\" of a database not set", database->objformat_name); |
|---|
| | 118 | goto error_free_database; |
|---|
| | 119 | } |
|---|
| | 120 | |
|---|
| | 121 | env->databases = g_list_append(env->databases, database); |
|---|
| | 122 | |
|---|
| | 123 | osync_trace(TRACE_EXIT, "%s", __func__); |
|---|
| | 124 | return TRUE; |
|---|
| | 125 | |
|---|
| | 126 | error_free_database: |
|---|
| | 127 | syncml_free_database(database); |
|---|
| | 128 | error: |
|---|
| | 129 | osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error)); |
|---|
| | 130 | return FALSE; |
|---|
| | 131 | } |
|---|
| | 132 | |
|---|
| | 133 | static const char *_contenttype_to_format(const char *contenttype) |
|---|
| | 134 | { |
|---|
| | 135 | if (!strcmp(contenttype, SML_ELEMENT_TEXT_VCARD)) { |
|---|
| | 136 | return "contact"; |
|---|
| | 137 | } |
|---|
| | 138 | if (!strcmp(contenttype, SML_ELEMENT_TEXT_VCAL)) { |
|---|
| | 139 | return "event"; |
|---|
| | 140 | } |
|---|
| | 141 | if (!strcmp(contenttype, SML_ELEMENT_TEXT_PLAIN)) { |
|---|
| | 142 | return "note"; |
|---|
| | 143 | } |
|---|
| | 144 | return NULL; |
|---|
| | 145 | } |
|---|
| | 146 | |
|---|
| | 147 | static OSyncChangeType _to_osync_changetype(SmlChangeType type) |
|---|
| | 148 | { |
|---|
| | 149 | switch (type) { |
|---|
| | 150 | case SML_CHANGE_ADD: |
|---|
| | 151 | return OSYNC_CHANGE_TYPE_ADDED; |
|---|
| | 152 | case SML_CHANGE_REPLACE: |
|---|
| | 153 | return OSYNC_CHANGE_TYPE_MODIFIED; |
|---|
| | 154 | case SML_CHANGE_DELETE: |
|---|
| | 155 | return OSYNC_CHANGE_TYPE_DELETED; |
|---|
| | 156 | default: |
|---|
| | 157 | ; |
|---|
| | 158 | } |
|---|
| | 159 | return OSYNC_CHANGE_TYPE_UNKNOWN; |
|---|
| | 160 | } |
|---|
| | 161 | |
|---|
| | 162 | static void _ds_event(SmlDsSession *dsession, SmlDsEvent event, void *userdata) |
|---|
| | 163 | { |
|---|
| | 164 | osync_trace(TRACE_ENTRY, "%s(%p, %i, %p)", __func__, dsession, event, userdata); |
|---|
| | 165 | |
|---|
| | 166 | SmlDatabase *database = (SmlDatabase *)userdata; |
|---|
| | 167 | |
|---|
| | 168 | osync_trace(TRACE_INTERNAL, "database: %s", database->objtype); |
|---|
| | 169 | switch (event) { |
|---|
| | 170 | case SML_DS_EVENT_GOTCHANGES: |
|---|
| | 171 | database->gotChanges = TRUE; |
|---|
| | 172 | if (database->gotChanges && database->finalChanges) { |
|---|
| | 173 | osync_trace(TRACE_INTERNAL,"getChangesCtx report success at _recv_change"); |
|---|
| | 174 | osync_context_report_success(database->getChangesCtx); |
|---|
| | 175 | database->getChangesCtx = NULL; |
|---|
| | 176 | } |
|---|
| | 177 | break; |
|---|
| | 178 | case SML_DS_EVENT_COMMITEDCHANGES: |
|---|
| | 179 | break; |
|---|
| | 180 | } |
|---|
| | 181 | |
|---|
| | 182 | osync_trace(TRACE_EXIT, "%s", __func__); |
|---|
| | 183 | } |
|---|
| | 184 | |
|---|
| | 185 | static SmlBool _recv_change(SmlDsSession *dsession, SmlChangeType type, const char *uid, char *data, unsigned int size, const char *contenttype, void *userdata, SmlError **smlerror) |
|---|
| | 186 | { |
|---|
| | 187 | osync_trace(TRACE_ENTRY, "%s(%p, %i, %s, %p, %i, %s, %p, %p)", __func__, dsession, type, uid, data, size, contenttype, userdata, smlerror); |
|---|
| | 188 | SmlDatabase *database = (SmlDatabase *)userdata; |
|---|
| | 189 | OSyncError *error = NULL; |
|---|
| | 190 | g_assert(database->getChangesCtx); |
|---|
| | 191 | |
|---|
| | 192 | if (!type) { |
|---|
| | 193 | osync_context_report_success(database->getChangesCtx); |
|---|
| | 194 | osync_trace(TRACE_EXIT, "%s", __func__); |
|---|
| | 195 | return TRUE; |
|---|
| | 196 | } |
|---|
| | 197 | |
|---|
| | 198 | OSyncChange *change = osync_change_new(&error); |
|---|
| | 199 | if (!change) { |
|---|
| | 200 | osync_error_set(&error, OSYNC_ERROR_GENERIC, "No change created: %s", osync_error_print(&error)); |
|---|
| | 201 | goto error; |
|---|
| | 202 | } |
|---|
| | 203 | |
|---|
| | 204 | // osync_change_set_member(change, env->member); |
|---|
| | 205 | |
|---|
| | 206 | osync_change_set_uid(change, uid); |
|---|
| | 207 | if (contenttype != NULL) { |
|---|
| | 208 | /* We specify the objformat plain for vcard and vcal |
|---|
| | 209 | * since we cannot be really sure what the device sends |
|---|
| | 210 | * us, without looking at the devinf. Since we dont use |
|---|
| | 211 | * the devinf yet, we let the opensync detector decide |
|---|
| | 212 | * what format the item is. |
|---|
| | 213 | * |
|---|
| | 214 | * For text/plain (notes) we specify the memo format, |
|---|
| | 215 | * so that it does not get detected */ |
|---|
| | 216 | |
|---|
| | 217 | /* |
|---|
| | 218 | if (!strcmp(contenttype, SML_ELEMENT_TEXT_VCARD)) |
|---|
| | 219 | objformat = g_strdup("plain"); |
|---|
| | 220 | else if (!strcmp(contenttype, SML_ELEMENT_TEXT_VCAL)) |
|---|
| | 221 | objformat = g_strdup("plain"); |
|---|
| | 222 | else if (!strcmp(contenttype, SML_ELEMENT_TEXT_PLAIN)) |
|---|
| | 223 | objformat = g_strdup("memo"); |
|---|
| | 224 | */ |
|---|
| | 225 | |
|---|
| | 226 | } |
|---|
| | 227 | |
|---|
| | 228 | /* XXX Workaround for mobiles which only handle localtime! TODO: make use of UTC field in DevCap and handle it is OpenSync framework! */ |
|---|
| | 229 | /* |
|---|
| | 230 | if (!strcmp(contenttype, SML_ELEMENT_TEXT_VCAL) && env->onlyLocaltime && type != SML_CHANGE_DELETE) { |
|---|
| | 231 | char *_data = osync_time_vcal2utc(data); |
|---|
| | 232 | g_free(data); |
|---|
| | 233 | data = _data; |
|---|
| | 234 | size = strlen(data); |
|---|
| | 235 | } |
|---|
| | 236 | */ |
|---|
| | 237 | |
|---|
| | 238 | OSyncData *odata = osync_data_new(data, size+1, database->objformat, &error); |
|---|
| | 239 | if (!odata) { |
|---|
| | 240 | osync_change_unref(change); |
|---|
| | 241 | goto error; |
|---|
| | 242 | } |
|---|
| | 243 | |
|---|
| | 244 | |
|---|
| | 245 | // if (_to_osync_changetype(type) == OSYNC_CHANGE_TYPE_DELETED) |
|---|
| | 246 | if(contenttype) |
|---|
| | 247 | osync_data_set_objtype(odata, _contenttype_to_format(contenttype)); |
|---|
| | 248 | else |
|---|
| | 249 | osync_data_set_objtype(odata, database->objtype); |
|---|
| | 250 | |
|---|
| | 251 | |
|---|
| | 252 | osync_change_set_data(change, odata); |
|---|
| | 253 | osync_change_set_changetype(change, _to_osync_changetype(type)); |
|---|
| | 254 | |
|---|
| | 255 | osync_data_unref(odata); |
|---|
| | 256 | |
|---|
| | 257 | osync_context_report_change(database->getChangesCtx, change); |
|---|
| | 258 | |
|---|
| | 259 | osync_change_unref(change); |
|---|
| | 260 | |
|---|
| | 261 | osync_trace(TRACE_EXIT, "%s", __func__); |
|---|
| | 262 | return TRUE; |
|---|
| | 263 | |
|---|
| | 264 | error: |
|---|
| | 265 | // osync_context_report_osyncwarning(ctx, error); |
|---|
| | 266 | osync_error_unref(&error); |
|---|
| | 267 | |
|---|
| | 268 | osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(&error)); |
|---|
| | 269 | return FALSE; |
|---|
| | 270 | } |
|---|
| | 271 | |
|---|
| | 272 | static void _recv_change_reply(SmlDsSession *dsession, SmlStatus *status, const char *newuid, void *userdata) |
|---|
| | 273 | { |
|---|
| | 274 | osync_trace(TRACE_ENTRY, "%s(%p, %p, %s, %p)", __func__, dsession, status, newuid, userdata); |
|---|
| | 275 | struct commitContext *ctx = userdata; |
|---|
| | 276 | OSyncContext *context = ctx->context; |
|---|
| | 277 | |
|---|
| | 278 | if (smlStatusGetClass(status) != SML_ERRORCLASS_SUCCESS) { |
|---|
| | 279 | osync_context_report_error(context, OSYNC_ERROR_GENERIC, "Unable to commit change. Error %i", smlStatusGetCode(status)); |
|---|
| | 280 | } else { |
|---|
| | 281 | if (newuid) |
|---|
| | 282 | osync_change_set_uid(ctx->change, newuid); |
|---|
| | 283 | g_free(ctx); |
|---|
| | 284 | |
|---|
| | 285 | osync_context_report_success(context); |
|---|
| | 286 | } |
|---|
| | 287 | |
|---|
| | 288 | osync_trace(TRACE_EXIT, "%s", __func__); |
|---|
| | 289 | } |
|---|
| | 290 | |
|---|
| | 291 | static void _recv_sync_reply(SmlSession *session, SmlStatus *status, void *userdata) |
|---|
| | 292 | { |
|---|
| | 293 | osync_trace(TRACE_ENTRY, "%s(%p, %p)", __func__, session, status, userdata); |
|---|
| | 294 | |
|---|
| | 295 | printf("Received an reply to our sync\n"); |
|---|
| | 296 | |
|---|
| | 297 | osync_trace(TRACE_EXIT, "%s", __func__); |
|---|
| | 298 | } |
|---|
| | 299 | |
|---|
| | 300 | static void _recv_sync(SmlDsSession *dsession, unsigned int numchanges, void *userdata) |
|---|
| | 301 | { |
|---|
| | 302 | osync_trace(TRACE_ENTRY, "%s(%p, %i, %p)", __func__, dsession, numchanges, userdata); |
|---|
| | 303 | SmlDatabase *database = (SmlDatabase *)userdata; |
|---|
| | 304 | |
|---|
| | 305 | osync_trace(TRACE_INTERNAL,"Going to receive %i changes - objtype: %s", numchanges, database->objtype); |
|---|
| | 306 | printf("Going to receive %i changes\n", numchanges); |
|---|
| | 307 | |
|---|
| | 308 | osync_trace(TRACE_EXIT, "%s", __func__); |
|---|
| | 309 | } |
|---|
| | 310 | |
|---|
| | 311 | static void _recv_alert_reply(SmlSession *session, SmlStatus *status, void *userdata) |
|---|
| | 312 | { |
|---|
| | 313 | osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, session, status, userdata); |
|---|
| | 314 | |
|---|
| | 315 | SmlDatabase *database = (SmlDatabase*) userdata; |
|---|
| | 316 | |
|---|
| | 317 | osync_trace(TRACE_INTERNAL, "Received an reply to our Alert - %s\n", database->objtype); |
|---|
| | 318 | |
|---|
| | 319 | |
|---|
| | 320 | osync_trace(TRACE_EXIT, "%s", __func__); |
|---|
| | 321 | } |
|---|
| | 322 | |
|---|
| | 323 | static SmlBool _recv_alert(SmlDsSession *dsession, SmlAlertType type, const char *last, const char *next, void *userdata) |
|---|
| | 324 | { |
|---|
| | 325 | osync_trace(TRACE_ENTRY, "%s(%p, %i, %s, %s, %p)", __func__, dsession, type, last, next, userdata); |
|---|
| | 326 | SmlDatabase *database = (SmlDatabase*) userdata; |
|---|
| | 327 | SmlPluginEnv *env = database->env; |
|---|
| | 328 | SmlBool ret = TRUE; |
|---|
| | 329 | |
|---|
| | 330 | char *key = g_strdup_printf("remoteanchor%s", smlDsSessionGetLocation(dsession)); |
|---|
| | 331 | |
|---|
| | 332 | if ((!last || !osync_anchor_compare(env->anchor_path, key, last)) && type == SML_ALERT_TWO_WAY) |
|---|
| | 333 | ret = FALSE; |
|---|
| | 334 | |
|---|
| | 335 | osync_bool ans = osync_objtype_sink_get_slowsync(database->sink); |
|---|
| | 336 | if (ans) |
|---|
| | 337 | ret = FALSE; |
|---|
| | 338 | |
|---|
| | 339 | if (!ret || type != SML_ALERT_TWO_WAY) |
|---|
| | 340 | osync_objtype_sink_set_slowsync(database->sink, TRUE); |
|---|
| | 341 | |
|---|
| | 342 | osync_anchor_update(env->anchor_path, key, next); |
|---|
| | 343 | g_free(key); |
|---|
| | 344 | |
|---|
| | 345 | if (!ret) { |
|---|
| | 346 | smlDsSessionSendAlert(dsession, SML_ALERT_SLOW_SYNC, last, next, _recv_alert_reply, database, NULL); |
|---|
| | 347 | } else { |
|---|
| | 348 | smlDsSessionSendAlert(dsession, SML_ALERT_TWO_WAY, last, next, _recv_alert_reply, database, NULL); |
|---|
| | 349 | } |
|---|
| | 350 | |
|---|
| | 351 | smlDevInfAgentGetDevInf(env->agent); |
|---|
| | 352 | |
|---|
| | 353 | osync_trace(TRACE_EXIT, "%s: %i", __func__, ret); |
|---|
| | 354 | return ret; |
|---|
| | 355 | } |
|---|
| | 356 | |
|---|
| | 357 | static void _ds_alert(SmlDsSession *dsession, void *userdata) |
|---|
| | 358 | { |
|---|
| | 359 | osync_trace(TRACE_ENTRY, "%s(%p, %p)", __func__, dsession, userdata); |
|---|
| | 360 | |
|---|
| | 361 | SmlDatabase *database = (SmlDatabase *)userdata; |
|---|
| | 362 | |
|---|
| | 363 | database->session = dsession; |
|---|
| | 364 | smlDsSessionRef(dsession); |
|---|
| | 365 | |
|---|
| | 366 | osync_trace(TRACE_EXIT, "%s", __func__); |
|---|
| | 367 | } |
|---|
| | 368 | |
|---|
| | 369 | static void _manager_event(SmlManager *manager, SmlManagerEventType type, SmlSession *session, SmlError *error, void *userdata) |
|---|
| | 370 | { |
|---|
| | 371 | osync_trace(TRACE_ENTRY, "%s(%p, %i, %p, %p, %p)", __func__, manager, type, session, error, userdata); |
|---|
| | 372 | SmlPluginEnv *env = userdata; |
|---|
| | 373 | GList *o = NULL; |
|---|
| | 374 | |
|---|
| | 375 | switch (type) { |
|---|
| | 376 | case SML_MANAGER_SESSION_FLUSH: |
|---|
| | 377 | case SML_MANAGER_CONNECT_DONE: |
|---|
| | 378 | env->gotDisconnect = FALSE; |
|---|
| | 379 | break; |
|---|
| | 380 | case SML_MANAGER_DISCONNECT_DONE: |
|---|
| | 381 | osync_trace(TRACE_INTERNAL, "connection with device has ended"); |
|---|
| | 382 | env->gotDisconnect = TRUE; |
|---|
| | 383 | |
|---|
| | 384 | o = env->databases; |
|---|
| | 385 | for (; o; o = o->next) { |
|---|
| | 386 | SmlDatabase *database = o->data; |
|---|
| | 387 | |
|---|
| | 388 | if (database->disconnectCtx) { |
|---|
| | 389 | osync_context_report_success(database->disconnectCtx); |
|---|
| | 390 | database->disconnectCtx = NULL; |
|---|
| | 391 | } |
|---|
| | 392 | } |
|---|
| | 393 | |
|---|
| | 394 | break; |
|---|
| | 395 | case SML_MANAGER_TRANSPORT_ERROR: |
|---|
| | 396 | osync_trace(TRACE_INTERNAL, "There was an error in the transport: %s", smlErrorPrint(&error)); |
|---|
| | 397 | if (!env->gotDisconnect) { |
|---|
| | 398 | if (env->tryDisconnect == FALSE) { |
|---|
| | 399 | env->tryDisconnect = TRUE; |
|---|
| | 400 | smlTransportDisconnect(env->tsp, NULL, NULL); |
|---|
| | 401 | while (!env->gotDisconnect) { |
|---|
| | 402 | smlManagerDispatch(manager); |
|---|
| | 403 | } |
|---|
| | 404 | } else { |
|---|
| | 405 | env->gotDisconnect = TRUE; |
|---|
| | 406 | osync_trace(TRACE_EXIT_ERROR, "%s: error while disconnecting: %s", __func__, smlErrorPrint(&error)); |
|---|
| | 407 | return; |
|---|
| | 408 | } |
|---|
| | 409 | } |
|---|
| | 410 | goto error; |
|---|
| | 411 | break; |
|---|
| | 412 | case SML_MANAGER_SESSION_NEW: |
|---|
| | 413 | osync_trace(TRACE_INTERNAL, "Just received a new session with ID %s\n", smlSessionGetSessionID(session)); |
|---|
| | 414 | smlSessionUseStringTable(session, env->useStringtable); |
|---|
| | 415 | smlSessionUseOnlyReplace(session, env->onlyReplace); |
|---|
| | 416 | |
|---|
| | 417 | if (env->recvLimit) |
|---|
| | 418 | smlSessionSetReceivingLimit(session, env->recvLimit); |
|---|
| | 419 | |
|---|
| | 420 | if (env->maxObjSize) |
|---|
| | 421 | smlSessionSetReceivingMaxObjSize(session, env->maxObjSize); |
|---|
| | 422 | |
|---|
| | 423 | env->session = session; |
|---|
| | 424 | smlSessionRef(session); |
|---|
| | 425 | break; |
|---|
| | 426 | case SML_MANAGER_SESSION_FINAL: |
|---|
| | 427 | osync_trace(TRACE_INTERNAL, "Session %s reported final\n", smlSessionGetSessionID(session)); |
|---|
| | 428 | env->gotFinal = TRUE; |
|---|
| | 429 | |
|---|
| | 430 | if (env->connectCtx) { |
|---|
| | 431 | osync_context_report_success(env->connectCtx); |
|---|
| | 432 | env->connectCtx = NULL; |
|---|
| | 433 | } |
|---|
| | 434 | |
|---|
| | 435 | o = env->databases; |
|---|
| | 436 | for (; o; o = o->next) { |
|---|
| | 437 | SmlDatabase *database = o->data; |
|---|
| | 438 | |
|---|
| | 439 | osync_trace(TRACE_INTERNAL, "gotChanges: %i getChangesCtx: %p objtype: %s", |
|---|
| | 440 | database->gotChanges, database->getChangesCtx, database->objtype); |
|---|
| | 441 | |
|---|
| | 442 | if (database->getChangesCtx) { |
|---|
| | 443 | database->finalChanges = TRUE; |
|---|
| | 444 | if (database->gotChanges && database->finalChanges) { |
|---|
| | 445 | osync_trace(TRACE_INTERNAL,"getChangesCtx report success at final"); |
|---|
| | 446 | osync_context_report_success(database->getChangesCtx); |
|---|
| | 447 | database->getChangesCtx = NULL; |
|---|
| | 448 | } |
|---|
| | 449 | |
|---|
| | 450 | } |
|---|
| | 451 | |
|---|
| | 452 | |
|---|
| | 453 | if (database->commitCtx) { |
|---|
| | 454 | osync_context_report_success(database->commitCtx); |
|---|
| | 455 | database->commitCtx = NULL; |
|---|
| | 456 | } |
|---|
| | 457 | |
|---|
| | 458 | |
|---|
| | 459 | } |
|---|
| | 460 | break; |
|---|
| | 461 | case SML_MANAGER_SESSION_END: |
|---|
| | 462 | osync_trace(TRACE_INTERNAL, "Session %s has ended\n", smlSessionGetSessionID(session)); |
|---|
| | 463 | if (!smlTransportDisconnect(env->tsp, NULL, &error)) |
|---|
| | 464 | goto error; |
|---|
| | 465 | break; |
|---|
| | 466 | case SML_MANAGER_SESSION_ERROR: |
|---|
| | 467 | osync_trace(TRACE_INTERNAL, "There was an error in the session %s: %s", smlSessionGetSessionID(session), smlErrorPrint(&error)); |
|---|
| | 468 | goto error; |
|---|
| | 469 | break; |
|---|
| | 470 | case SML_MANAGER_SESSION_WARNING: |
|---|
| | 471 | printf("WARNING: %s\n", smlErrorPrint(&error)); |
|---|
| | 472 | break; |
|---|
| | 473 | } |
|---|
| | 474 | |
|---|
| | 475 | osync_trace(TRACE_EXIT, "%s", __func__); |
|---|
| | 476 | return; |
|---|
| | 477 | |
|---|
| | 478 | error:; |
|---|
| | 479 | OSyncError *oserror = NULL; |
|---|
| | 480 | osync_error_set(&oserror, OSYNC_ERROR_GENERIC, smlErrorPrint(&error)); |
|---|
| | 481 | |
|---|
| | 482 | if (env->connectCtx) { |
|---|
| | 483 | osync_context_report_osyncerror(env->connectCtx, oserror); |
|---|
| | 484 | env->connectCtx = NULL; |
|---|
| | 485 | } |
|---|
| | 486 | |
|---|
| | 487 | |
|---|
| | 488 | o = env->databases; |
|---|
| | 489 | for (; o; o = o->next) { |
|---|
| | 490 | SmlDatabase *database = o->data; |
|---|
| | 491 | |
|---|
| | 492 | |
|---|
| | 493 | if (database->getChangesCtx) { |
|---|
| | 494 | osync_context_report_osyncerror(database->getChangesCtx, oserror); |
|---|
| | 495 | database->getChangesCtx = NULL; |
|---|
| | 496 | } |
|---|
| | 497 | |
|---|
| | 498 | if (database->commitCtx) { |
|---|
| | 499 | osync_context_report_osyncerror(database->commitCtx, oserror); |
|---|
| | 500 | database->commitCtx = NULL; |
|---|
| | 501 | } |
|---|
| | 502 | |
|---|
| | 503 | if (database->disconnectCtx) { |
|---|
| | 504 | osync_context_report_osyncerror(database->disconnectCtx, oserror); |
|---|
| | 505 | database->disconnectCtx = NULL; |
|---|
| | 506 | } |
|---|
| | 507 | |
|---|
| | 508 | |
|---|
| | 509 | } |
|---|
| | 510 | |
|---|
| | 511 | osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(&oserror)); |
|---|
| | 512 | } |
|---|
| | 513 | |
|---|
| | 514 | static gboolean _sessions_prepare(GSource *source, gint *timeout_) |
|---|
| | 515 | { |
|---|
| | 516 | *timeout_ = 50; |
|---|
| | 517 | return FALSE; |
|---|
| | 518 | } |
|---|
| | 519 | |
|---|
| | 520 | static gboolean _sessions_check(GSource *source) |
|---|
| | 521 | { |
|---|
| | 522 | SmlPluginEnv *env = *((SmlPluginEnv **)(source + 1)); |
|---|
| | 523 | |
|---|
| | 524 | GList *o = env->databases; |
|---|
| | 525 | for (; o; o = o->next) { |
|---|
| | 526 | SmlDatabase *database = o->data; |
|---|
| | 527 | if (database->session && smlDsSessionCheck(database->session)) |
|---|
| | 528 | return TRUE; |
|---|
| | 529 | } |
|---|
| | 530 | |
|---|
| | 531 | if (smlManagerCheck(env->manager)) |
|---|
| | 532 | return TRUE; |
|---|
| | 533 | |
|---|
| | 534 | return FALSE; |
|---|
| | 535 | } |
|---|
| | 536 | |
|---|
| | 537 | static gboolean _sessions_dispatch(GSource *source, GSourceFunc callback, gpointer user_data) |
|---|
| | 538 | { |
|---|
| | 539 | SmlPluginEnv *env = user_data; |
|---|
| | 540 | |
|---|
| | 541 | GList *o = env->databases; |
|---|
| | 542 | for (; o; o = o->next) { |
|---|
| | 543 | SmlDatabase *database = o->data; |
|---|
| | 544 | if (database->session) |
|---|
| | 545 | smlDsSessionDispatch(database->session); |
|---|
| | 546 | } |
|---|
| | 547 | |
|---|
| | 548 | smlManagerDispatch(env->manager); |
|---|
| | 549 | return TRUE; |
|---|
| | 550 | } |
|---|
| | 551 | |
|---|
| | 552 | static void _verify_user(SmlAuthenticator *auth, const char *username, const char *password, void *userdata, SmlErrorType *reply) |
|---|
| | 553 | { |
|---|
| | 554 | osync_trace(TRACE_ENTRY, "%s(%p, %s, %s, %p, %p)", __func__, auth, username, password, userdata, reply); |
|---|
| | 555 | SmlPluginEnv *env = userdata; |
|---|
| | 556 | |
|---|
| | 557 | osync_trace(TRACE_SENSITIVE, "configured is %s, %s", env->username, env->password); |
|---|
| | 558 | if (env->username && (!env->password || !username || !password || strcmp(env->username, username) || strcmp(env->password, password))) { |
|---|
| | 559 | *reply = SML_ERROR_AUTH_REJECTED; |
|---|
| | 560 | } else { |
|---|
| | 561 | *reply = SML_AUTH_ACCEPTED; |
|---|
| | 562 | } |
|---|
| | 563 | osync_trace(TRACE_EXIT, "%s: %i", __func__, *reply); |
|---|
| | 564 | } |
|---|
| | 565 | |
|---|
| | 566 | static void connect_http_server(void *data, OSyncPluginInfo *info, OSyncContext *ctx) |
|---|
| | 567 | { |
|---|
| | 568 | osync_trace(TRACE_ENTRY, "%s(%p)", __func__, ctx); |
|---|
| | 569 | SmlPluginEnv *env = (SmlPluginEnv *)data; |
|---|
| | 570 | |
|---|
| | 571 | env->tryDisconnect = FALSE; |
|---|
| | 572 | |
|---|
| | 573 | /* For the obex client, we will store the context at this point since |
|---|
| | 574 | * we can only answer it as soon as the device returned an answer to our san */ |
|---|
| | 575 | env->connectCtx = ctx; |
|---|
| | 576 | |
|---|
| | 577 | /* This ref counting is needed to avoid a segfault. TODO: review if this is really needed. |
|---|
| | 578 | * To reproduce the segfault - just remove the osync_context_ref() call in the next line. */ |
|---|
| | 579 | osync_context_ref(env->connectCtx); |
|---|
| | 580 | |
|---|
| | 581 | /* For the http server we can report success right away since we know |
|---|
| | 582 | * that we already received an alert (otherwise we could not have triggered |
|---|
| | 583 | * the synchronization) */ |
|---|
| | 584 | GList *o = env->databases; |
|---|
| | 585 | for (; o; o = o->next) { |
|---|
| | 586 | SmlDatabase *database = o->data; |
|---|
| | 587 | |
|---|
| | 588 | if (database->session) |
|---|
| | 589 | smlDsSessionGetAlert(database->session, _recv_alert, database); |
|---|
| | 590 | } |
|---|
| | 591 | |
|---|
| | 592 | /* If we already received the final, we just report success. otherwise |
|---|
| | 593 | * we let the final report success */ |
|---|
| | 594 | if (env->gotFinal) |
|---|
| | 595 | osync_context_report_success(ctx); |
|---|
| | 596 | else |
|---|
| | 597 | env->connectCtx = ctx; |
|---|
| | 598 | |
|---|
| | 599 | osync_trace(TRACE_EXIT, "%s", __func__); |
|---|
| | 600 | return; |
|---|
| | 601 | } |
|---|
| | 602 | |
|---|
| | 603 | static void connect_obex_client(void *data, OSyncPluginInfo *info, OSyncContext *ctx) |
|---|
| | 604 | { |
|---|
| | 605 | osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, data, info, ctx); |
|---|
| | 606 | |
|---|
| | 607 | SmlPluginEnv *env = (SmlPluginEnv *)data; |
|---|
| | 608 | |
|---|
| | 609 | SmlError *error = NULL; |
|---|
| | 610 | OSyncError *oserror = NULL; |
|---|
| | 611 | |
|---|
| | 612 | if (env->isConnected) { |
|---|
| | 613 | osync_context_report_success(ctx); |
|---|
| | 614 | osync_trace(TRACE_EXIT, "%s", __func__); |
|---|
| | 615 | return; |
|---|
| | 616 | } |
|---|
| | 617 | |
|---|
| | 618 | env->tryDisconnect = FALSE; |
|---|
| | 619 | |
|---|
| | 620 | /* For the obex client, we will store the context at this point since |
|---|
| | 621 | * we can only answer it as soon as the device returned an answer to our san */ |
|---|
| | 622 | env->connectCtx = ctx; |
|---|
| | 623 | |
|---|
| | 624 | /* This ref counting is needed to avoid a segfault. TODO: review if this is really needed. |
|---|
| | 625 | To reproduce the segfault - just remove the osync_context_ref() call in the next line. */ |
|---|
| | 626 | osync_context_ref(env->connectCtx); |
|---|
| | 627 | |
|---|
| | 628 | if (!smlTransportConnect(env->tsp, &error)) |
|---|
| | 629 | goto error; |
|---|
| | 630 | else |
|---|
| | 631 | env->isConnected = TRUE; |
|---|
| | 632 | |
|---|
| | 633 | if (!smlNotificationSend(env->san, env->tsp, &error)) |
|---|
| | 634 | goto error_free_san; |
|---|
| | 635 | |
|---|
| | 636 | smlNotificationFree(env->san); |
|---|
| | 637 | env->san = NULL; |
|---|
| | 638 | |
|---|
| | 639 | osync_trace(TRACE_EXIT, "%s", __func__); |
|---|
| | 640 | return; |
|---|
| | 641 | |
|---|
| | 642 | error_free_san: |
|---|
| | 643 | smlNotificationFree(env->san); |
|---|
| | 644 | env->san = NULL; |
|---|
| | 645 | error: |
|---|
| | 646 | osync_error_set(&oserror, OSYNC_ERROR_GENERIC, "%s", smlErrorPrint(&error)); |
|---|
| | 647 | smlErrorDeref(&error); |
|---|
| | 648 | osync_context_report_osyncerror(ctx, oserror); |
|---|
| | 649 | osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(&oserror)); |
|---|
| | 650 | } |
|---|
| | 651 | |
|---|
| | 652 | static void get_changeinfo(void *data, OSyncPluginInfo *info, OSyncContext *ctx) |
|---|
| | 653 | { |
|---|
| | 654 | osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, data, info, ctx); |
|---|
| | 655 | SmlPluginEnv *env = (SmlPluginEnv *)data; |
|---|
| | 656 | |
|---|
| | 657 | OSyncObjTypeSink *sink = osync_plugin_info_get_sink(info); |
|---|
| | 658 | SmlDatabase *database = osync_objtype_sink_get_userdata(sink); |
|---|
| | 659 | |
|---|
| | 660 | database->getChangesCtx = ctx; |
|---|
| | 661 | osync_context_ref(database->getChangesCtx); |
|---|
| | 662 | |
|---|
| | 663 | SmlError *error = NULL; |
|---|
| | 664 | OSyncError *oserror = NULL; |
|---|
| | 665 | |
|---|
| | 666 | if (smlTransportGetType(env->tsp) == SML_TRANSPORT_OBEX_CLIENT) { |
|---|
| | 667 | smlDsSessionGetAlert(database->session, _recv_alert, database); |
|---|
| | 668 | } |
|---|
| | 669 | |
|---|
| | 670 | smlDsSessionGetEvent(database->session, _ds_event, database); |
|---|
| | 671 | smlDsSessionGetSync(database->session, _recv_sync, database); |
|---|
| | 672 | smlDsSessionGetChanges(database->session, _recv_change, database); |
|---|
| | 673 | |
|---|
| | 674 | // avoid flushing to early |
|---|
| | 675 | env->num++; |
|---|
| | 676 | |
|---|
| | 677 | if (env->num >= g_list_length(env->databases)) { |
|---|
| | 678 | env->num = 0; |
|---|
| | 679 | if (!smlSessionFlush(env->session, TRUE, &error)) |
|---|
| | 680 | goto error; |
|---|
| | 681 | } |
|---|
| | 682 | |
|---|
| | 683 | osync_trace(TRACE_EXIT, "%s", __func__); |
|---|
| | 684 | return; |
|---|
| | 685 | |
|---|
| | 686 | error: |
|---|
| | 687 | osync_error_set(&oserror, OSYNC_ERROR_GENERIC, "%s", smlErrorPrint(&error)); |
|---|
| | 688 | smlErrorDeref(&error); |
|---|
| | 689 | osync_context_report_osyncerror(ctx, oserror); |
|---|
| | 690 | osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(&oserror)); |
|---|
| | 691 | } |
|---|
| | 692 | |
|---|
| | 693 | static void sync_done(void *data, OSyncPluginInfo *info, OSyncContext *ctx) |
|---|
| | 694 | { |
|---|
| | 695 | osync_context_report_success(ctx); |
|---|
| | 696 | } |
|---|
| | 697 | |
|---|
| | 698 | static void disconnect(void *data, OSyncPluginInfo *info, OSyncContext *ctx) |
|---|
| | 699 | { |
|---|
| | 700 | osync_trace(TRACE_ENTRY, "%s(%p)", __func__, ctx); |
|---|
| | 701 | SmlPluginEnv *env = (SmlPluginEnv *)data; |
|---|
| | 702 | |
|---|
| | 703 | OSyncObjTypeSink *sink = osync_plugin_info_get_sink(info); |
|---|
| | 704 | SmlDatabase *database = osync_objtype_sink_get_userdata(sink); |
|---|
| | 705 | |
|---|
| | 706 | OSyncError *oserror = NULL; |
|---|
| | 707 | SmlError *error = NULL; |
|---|
| | 708 | |
|---|
| | 709 | env->gotFinal = FALSE; |
|---|
| | 710 | |
|---|
| | 711 | if (!smlSessionEnd(env->session, &error)) |
|---|
| | 712 | goto error; |
|---|
| | 713 | |
|---|
| | 714 | if (env->gotDisconnect) { |
|---|
| | 715 | osync_context_report_success(ctx); |
|---|
| | 716 | } else { |
|---|
| | 717 | database->disconnectCtx = ctx; |
|---|
| | 718 | osync_context_ref(database->disconnectCtx); |
|---|
| | 719 | } |
|---|
| | 720 | |
|---|
| | 721 | |
|---|
| | 722 | osync_trace(TRACE_EXIT, "%s", __func__); |
|---|
| | 723 | return; |
|---|
| | 724 | |
|---|
| | 725 | error: |
|---|
| | 726 | osync_error_set(&oserror, OSYNC_ERROR_GENERIC, "%s", smlErrorPrint(&error)); |
|---|
| | 727 | smlErrorDeref(&error); |
|---|
| | 728 | osync_context_report_osyncerror(ctx, oserror); |
|---|
| | 729 | osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(&oserror)); |
|---|
| | 730 | } |
|---|
| | 731 | |
|---|
| | 732 | static void finalize(void *data) |
|---|
| | 733 | { |
|---|
| | 734 | osync_trace(TRACE_ENTRY, "%s(%p)", __func__, data); |
|---|
| | 735 | SmlPluginEnv *env = (SmlPluginEnv *)data; |
|---|
| | 736 | |
|---|
| | 737 | /* Stop the manager */ |
|---|
| | 738 | if (env->manager) |
|---|
| | 739 | smlManagerStop(env->manager); |
|---|
| | 740 | |
|---|
| | 741 | if (env->tsp) |
|---|
| | 742 | smlTransportFinalize(env->tsp, NULL); |
|---|
| | 743 | |
|---|
| | 744 | if (env->tsp) |
|---|
| | 745 | smlTransportFree(env->tsp); |
|---|
| | 746 | |
|---|
| | 747 | if (env->san) |
|---|
| | 748 | smlNotificationFree(env->san); |
|---|
| | 749 | |
|---|
| | 750 | if (env->identifier) |
|---|
| | 751 | g_free(env->identifier); |
|---|
| | 752 | |
|---|
| | 753 | if (env->username) |
|---|
| | 754 | g_free(env->username); |
|---|
| | 755 | |
|---|
| | 756 | if (env->password) |
|---|
| | 757 | g_free(env->password); |
|---|
| | 758 | |
|---|
| | 759 | if (env->bluetoothAddress) |
|---|
| | 760 | g_free(env->bluetoothAddress); |
|---|
| | 761 | |
|---|
| | 762 | if (env->url) |
|---|
| | 763 | g_free(env->url); |
|---|
| | 764 | |
|---|
| | 765 | if (env->anchor_path) |
|---|
| | 766 | g_free(env->anchor_path); |
|---|
| | 767 | |
|---|
| | 768 | if (env->source) { |
|---|
| | 769 | g_source_destroy(env->source); |
|---|
| | 770 | g_source_unref(env->source); |
|---|
| | 771 | g_free(env->source_functions); |
|---|
| | 772 | } |
|---|
| | 773 | |
|---|
| | 774 | while (env->databases) { |
|---|
| | 775 | SmlDatabase *db = env->databases->data; |
|---|
| | 776 | syncml_free_database(db); |
|---|
| | 777 | |
|---|
| | 778 | env->databases = g_list_remove(env->databases, db); |
|---|
| | 779 | } |
|---|
| | 780 | |
|---|
| | 781 | g_free(env); |
|---|
| | 782 | |
|---|
| | 783 | osync_trace(TRACE_EXIT, "%s", __func__); |
|---|
| | 784 | } |
|---|
| | 785 | |
|---|
| | 786 | static void batch_commit(void *data, OSyncPluginInfo *info, OSyncContext *ctx, OSyncContext **contexts, OSyncChange **changes) |
|---|
| | 787 | { |
|---|
| | 788 | osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, ctx, contexts, changes); |
|---|
| | 789 | SmlPluginEnv *env = (SmlPluginEnv *)data; |
|---|
| | 790 | |
|---|
| | 791 | OSyncObjTypeSink *sink = osync_plugin_info_get_sink(info); |
|---|
| | 792 | SmlDatabase *database = osync_objtype_sink_get_userdata(sink); |
|---|
| | 793 | |
|---|
| | 794 | SmlError *error = NULL; |
|---|
| | 795 | OSyncError *oserror = NULL; |
|---|
| | 796 | int i = 0; |
|---|
| | 797 | int num = 0; |
|---|
| | 798 | |
|---|
| | 799 | database->commitCtx = ctx; |
|---|
| | 800 | osync_context_ref(database->commitCtx); |
|---|
| | 801 | |
|---|
| | 802 | for (i = 0; changes[i]; i++) { |
|---|
| | 803 | /* |
|---|
| | 804 | if (!strcmp(_format_to_contenttype(changes[i]), SML_ELEMENT_TEXT_VCARD)) |
|---|
| | 805 | numContact++; |
|---|
| | 806 | else if (!strcmp(_format_to_contenttype(changes[i]), SML_ELEMENT_TEXT_VCAL)) |
|---|
| | 807 | numCalendar++; |
|---|
| | 808 | else if (!strcmp(_format_to_contenttype(changes[i]), SML_ELEMENT_TEXT_PLAIN)) |
|---|
| | 809 | numNote++; |
|---|
| | 810 | */ |
|---|
| | 811 | num++; |
|---|
| | 812 | } |
|---|
| | 813 | |
|---|
| | 814 | if (!smlDsSessionSendSync(database->session, num, _recv_sync_reply, NULL, &error)) |
|---|
| | 815 | goto error; |
|---|
| | 816 | |
|---|
| | 817 | for (i = 0; changes[i]; i++) { |
|---|
| | 818 | OSyncChange *change = changes[i]; |
|---|
| | 819 | OSyncContext *context = contexts[i]; |
|---|
| | 820 | |
|---|
| | 821 | osync_trace(TRACE_INTERNAL, "Uid: \"%s\", Format: \"%s\", Changetype: \"%i\"", osync_change_get_uid(change), osync_change_get_objtype(change), osync_change_get_changetype(change)); |
|---|
| | 822 | |
|---|
| | 823 | struct commitContext *tracer = osync_try_malloc0(sizeof(struct commitContext), &oserror); |
|---|
| | 824 | if (!tracer) |
|---|
| | 825 | goto oserror; |
|---|
| | 826 | |
|---|
| | 827 | tracer->change = change; |
|---|
| | 828 | tracer->context = context; |
|---|
| | 829 | |
|---|
| | 830 | OSyncData *data = osync_change_get_data(change); |
|---|
| | 831 | char *buf = NULL; |
|---|
| | 832 | unsigned int size = 0; |
|---|
| | 833 | osync_data_get_data(data, &buf, &size); |
|---|
| | 834 | |
|---|
| | 835 | osync_trace(TRACE_INTERNAL, "Committing entry \"%s\": \"%s\"", osync_change_get_uid(change), buf); |
|---|
| | 836 | <
|---|