/* * libsyncml - A syncml protocol implementation * Copyright (C) 2005 Armin Bauer * Copyright (C) 2008 Michael Bell * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include #include #include #include #include #include #include #include #ifdef ENABLE_OBEX #include #endif #include GList *sessions = NULL; SmlManager *manager = NULL; SmlDevInfAgent *agent = NULL; GMainLoop *loop = NULL; GList *dbLocations = NULL; GList *dbSlow = NULL; GList *dbTypes = NULL; gboolean onlyInfo = FALSE; char *useTimeAnchor = NULL; unsigned int recvLimit = 65535; unsigned int maxObjSize = 3000000; static void usage (char *name, int ecode) { fprintf (stderr, "Usage: %s\n\n", name); fprintf (stderr, "--sync \t\tEmulate a database of the given type on the url.\n"); fprintf (stderr, "--slow-sync \tEmulate a database of the given type on the url and use slow-sync\n"); fprintf (stderr, "\t\t\t\tType should be a IANA registered mimetype or your own type. Common types are:\n"); fprintf (stderr, "\t\t\t\t\t\"text/x-vcard\" for contacts, \"text/x-vcalendar\" for events, \"text/plain\" for\n"); fprintf (stderr, "\t\t\t\t\tnotes and \"text/x-vMessage\" for SMS\n"); fprintf (stderr, "\t\t\t\tPath is the local name of the database. You can choose something there\n\n"); fprintf (stderr, "[-s ]\t\tConnect to the serial device\n\n"); fprintf (stderr, "[-u ]\t\t\tConnect to the given usb interface number\n"); fprintf (stderr, "\t\t\t\tIf you dont specify an id, all available interface will be listed\n\n"); fprintf (stderr, "[-b ]\t\tConnect to the given bluetooth device\n\n"); fprintf (stderr, "[--identifier ]\t\tUse the given identifier in the initial alert.\n"); fprintf (stderr, "\t\t\t\tSome devices require a special string here. Nokias for example require \"PC Suite\"\n\n"); fprintf (stderr, "[--version ]\t\tSet the given version. can be \"1.0\", \"1.1\" or \"1.2\"\n"); fprintf (stderr, "\t\t\t\tThe default is \"1.1\"\n\n"); fprintf (stderr, "--add \t\tAdd the file given in path to the device as the given type\n"); fprintf (stderr, "\t\t\t\tType should be a IANA registered mimetype or your own type. Common types are:\n"); fprintf (stderr, "\t\t\t\t\t\"text/x-vcard\" for contacts, \"text/x-vcalendar\" for events, \"text/plain\" for\n"); fprintf (stderr, "\t\t\t\t\tnotes and \"text/x-vMessage\" for SMS\n"); fprintf (stderr, "\t\t\t\tPath to the file to add. The file has to be a VCard, VCalendar, etc.\n\n"); fprintf (stderr, "[--wbxml]\t\t\tUse wbxml (WAP Binary XML) instead of plain xml\n\n"); fprintf (stderr, "[--recvLimit ]\t\t\tLimit the size of the receiving buffer to this size (default: %d)\n\n", recvLimit); fprintf (stderr, "[--maxObjSize ]\t\t\tThe maximum size of a object that we can receive (default: %d)\n\n", maxObjSize); fprintf (stderr, "[--useStringTable]\t\t\tUse wbxml string tables (Improves transmission size, but not supported by some phones)\n\n"); fprintf (stderr, "[--disableNumberOfChanges]\t\t\tDisable NumberOfChanges feature (the most new phones need it) (default: enabled)\n\n"); fprintf (stderr, "[--useTimeAnchor]\t\t\tUse timestamps as anchors (only for new Nokia series 40 phones)\n\n"); fprintf (stderr, "[--dumpinfo]\t\t\tPrint info about the phone at the end which can be sent to the developers\n"); exit (ecode); } static gboolean _recv_change(SmlDsSession *dsession, SmlChangeType type, const char *uid, char *data, unsigned int size, const char *contenttype, void *userdata, SmlError **error) { smlTrace(TRACE_ENTRY, "%s(%p, %i, %s, %p, %i, %s, %p, %p)", __func__, dsession, type, VA_STRING(uid), data, size, VA_STRING(contenttype), userdata, error); printf("Received a "); switch (type) { case SML_CHANGE_ADD: printf("added entry"); break; case SML_CHANGE_REPLACE: printf("modified entry"); break; case SML_CHANGE_DELETE: printf("deleted entry"); break; default: ; } printf(" %s of size %i and type %s\n", uid, size, contenttype); printf("\t\tData: %s\n", data); g_free(data); smlTrace(TRACE_EXIT, "%s", __func__); return TRUE; } static void _recv_sync_reply(SmlSession *session, SmlStatus *status, void *userdata) { smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, session, status, userdata); printf("Received an reply to our Sync: %i\n", smlStatusGetCode(status)); smlTrace(TRACE_EXIT, "%s", __func__); } static void _add_reply(SmlDsSession *session, SmlStatus *status, const char *newuid, void *userdata) { smlTrace(TRACE_ENTRY, "%s(%p, %p, %s, %p)", __func__, session, status, VA_STRING(newuid), userdata); printf("Received an reply to our Add command: %i. The new uid is %s\n", smlStatusGetCode(status), newuid); smlTrace(TRACE_EXIT, "%s", __func__); } GList *types = NULL; GList *paths = NULL; static void _recv_sync(SmlDsSession *dsession, unsigned int numchanges, void *userdata) { smlTrace(TRACE_ENTRY, "%s(%p, %i, %p)", __func__, dsession, numchanges, userdata); SmlError *error = NULL; printf("Going to receive %i changes\n", numchanges); GList *t = types; int num = 0; while (t) { if (!strcmp(smlDsSessionGetContentType(dsession), t->data)) num++; t = t->next; } if (!onlyInfo) { if (!smlDsSessionSendSync(dsession, num, _recv_sync_reply, NULL, &error)) goto error; t = types; GList *p = paths; while (t) { if (!strcmp(smlDsSessionGetContentType(dsession), t->data)) { char *filename = (char *)p->data; printf("Adding file %s\n", filename); GError *gerror = NULL; gsize sz = 0; char *data = NULL; GIOChannel *chan = g_io_channel_new_file(filename, "r", &gerror); if (!chan) { printf("Unable to open file %s for reading: %s\n", filename, gerror->message); } else { g_io_channel_set_encoding(chan, NULL, NULL); if (g_io_channel_read_to_end(chan, &data, &sz, &gerror) != G_IO_STATUS_NORMAL) { printf("Unable to read contents of file %s: %s\n", filename, gerror->message); } else { if (!smlDsSessionQueueChange(dsession, SML_CHANGE_ADD, filename, data, (int)sz, t->data, _add_reply, NULL, NULL)) printf("Unable to queue change\n"); } g_io_channel_shutdown(chan, FALSE, NULL); g_io_channel_unref(chan); } } t = t->next; p = p->next; } if (!smlDsSessionCloseSync(dsession, &error)) goto error; } smlTrace(TRACE_EXIT, "%s", __func__); error: smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(&error)); smlErrorDeref(&error); } static void _recv_alert_reply(SmlSession *session, SmlStatus *status, void *userdata) { smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, session, status, userdata); printf("Received an reply to our Alert\n"); smlTrace(TRACE_EXIT, "%s", __func__); } static gboolean _recv_alert(SmlDsSession *dsession, SmlAlertType type, const char *last, const char *next, void *userdata) { smlTrace(TRACE_ENTRY, "%s(%p, %i, %s, %s, %p)", __func__, dsession, type, VA_STRING(last), VA_STRING(next), userdata); SmlError *error = NULL; const char *anchor = next; if (useTimeAnchor) anchor = useTimeAnchor; printf("Received an Alert for the DS Server at %s: Type: %i, Last %s, Next %s\n", smlDsSessionGetLocation(dsession), type, last, next); gboolean slow = FALSE; int i = 0; for (i = 0; i < g_list_length(dbTypes); i++) { if (!strcmp(smlDsSessionGetContentType(dsession), g_list_nth_data(dbTypes, i))) { slow = GPOINTER_TO_INT(g_list_nth_data(dbSlow, i)); break; } } if (onlyInfo) { if (!smlDsSessionSendAlert(dsession, SML_ALERT_ONE_WAY_FROM_SERVER_BY_SERVER, last, next, _recv_alert_reply, NULL, &error)) goto error; } else if (slow && type != SML_ALERT_SLOW_SYNC) { /* SLOW-SYNC enforced by tool */ printf("Enforcing SLOW-SYNC\n"); if (!smlDsSessionSendAlert(dsession, SML_ALERT_SLOW_SYNC, NULL, anchor, _recv_alert_reply, NULL, &error)) goto error; smlTrace(TRACE_EXIT, "%s: Slow syncing", __func__); return FALSE; } else { /* We only support SLOW-SYNC and TWO-WAY-SYNC */ /* FIXME: Why do we use alert 206? */ /* FIXME: Usually 200 and 201 are the correct alert codes. */ /* FIXME: 206 is only useful in SANs */ if (type != SML_ALERT_SLOW_SYNC && type != SML_ALERT_TWO_WAY && type != SML_ALERT_TWO_WAY_BY_SERVER) { smlErrorSet(&error, SML_ERROR_GENERIC, "Unsupported alert type %d.", type); goto error; } if (!smlDsSessionSendAlert(dsession, type, last, anchor, _recv_alert_reply, NULL, &error)) goto error; } smlTrace(TRACE_EXIT, "%s", __func__); return TRUE; error: //smlDsSessionSetError(dsession, error); smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(&error)); smlErrorDeref(&error); return TRUE; } static void _ds_alert(SmlDsSession *dsession, void *userdata) { smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, dsession, userdata); smlDsSessionGetAlert(dsession, _recv_alert, NULL); smlDsSessionGetSync(dsession, _recv_sync, NULL); smlDsSessionGetChanges(dsession, _recv_change, NULL); smlDsSessionRef(dsession); sessions = g_list_append(sessions, dsession); smlTrace(TRACE_EXIT, "%s", __func__); } gboolean dumpinfo = FALSE; gboolean useStringTable = FALSE; gboolean useNumberOfChanges = TRUE; gboolean useLargeObjs = TRUE; SmlProtocolVersion sessionVersion = SML_VERSION_UNKNOWN; SmlDevInf *deviceDevinf = NULL; SmlDevInf *devinf = NULL; static void _manager_event(SmlManager *manager, SmlManagerEventType type, SmlSession *session, SmlError *error, void *userdata) { smlTrace(TRACE_ENTRY, "%s(%p, %i, %p, %p, %p)", __func__, manager, type, session, error, userdata); SmlError *locerror = NULL; switch (type) { case SML_MANAGER_CONNECT_DONE: printf("connection with device succeeded\n"); break; case SML_MANAGER_SESSION_ESTABLISHED: printf("session incl. authentication successfully established\n"); break; case SML_MANAGER_DISCONNECT_DONE: printf("connection with device has ended\n"); break; case SML_MANAGER_TRANSPORT_ERROR: printf("Received an transport error: %s\n", smlErrorPrint(&error)); smlManagerQuit(manager); g_main_loop_quit(loop); break; case SML_MANAGER_SESSION_NEW: printf("Just received a new session with ID %s\n", smlSessionGetSessionID(session)); sessionVersion = smlSessionGetVersion(session); if (smlSessionGetRemoteMaxMsgSize(session) > recvLimit && recvLimit > 0) recvLimit = smlSessionGetRemoteMaxMsgSize(session); if (recvLimit) smlSessionSetLocalMaxMsgSize(session, recvLimit); if (smlSessionGetRemoteMaxObjSize(session) > maxObjSize && maxObjSize > 0) maxObjSize = smlSessionGetRemoteMaxObjSize(session); if (maxObjSize) smlSessionSetLocalMaxObjSize(session, maxObjSize); if (useStringTable) smlSessionUseStringTable(session, TRUE); smlSessionUseNumberOfChanges(session, useNumberOfChanges); smlSessionUseLargeObjects(session, useLargeObjs); break; case SML_MANAGER_SESSION_FINAL: if (!deviceDevinf && (deviceDevinf = smlDevInfAgentGetDevInf(agent))) { printf("Received the DevInf\n"); smlSessionUseNumberOfChanges(session, smlDevInfSupportsNumberOfChanges(deviceDevinf)); smlDevInfSetSupportsNumberOfChanges(devinf, smlDevInfSupportsNumberOfChanges(deviceDevinf)); } if ((deviceDevinf && smlDevInfSupportsLargeObjs(deviceDevinf)) || (!deviceDevinf && useLargeObjs)) { /* enable standard compliant large object support */ if (recvLimit) smlSessionSetLocalMaxMsgSize(session, recvLimit); if (maxObjSize) smlSessionSetLocalMaxObjSize(session, maxObjSize); smlSessionUseLargeObjects(session, TRUE); smlDevInfSetSupportsLargeObjs(devinf, TRUE); } /* We want to know about the device so we check if we received * the devinf already */ if (dumpinfo && !deviceDevinf) { printf("Going to request the devinf\n"); if (!smlDevInfAgentRequestDevInf(agent, session, &locerror)) goto error; } printf("Session %s reported final. flushing\n", smlSessionGetSessionID(session)); SmlError *locerror = NULL; if (onlyInfo && deviceDevinf) smlSessionEnd(session, &locerror); else smlSessionFlush(session, TRUE, &locerror); break; case SML_MANAGER_SESSION_END: printf("Session %s has ended\n", smlSessionGetSessionID(session)); smlManagerQuit(manager); g_main_loop_quit(loop); break; case SML_MANAGER_SESSION_ERROR: printf("There was an error in the session %s: %s", smlSessionGetSessionID(session), smlErrorPrint(&error)); smlManagerQuit(manager); g_main_loop_quit(loop); break; case SML_MANAGER_SESSION_WARNING: printf("WARNING: %s", smlErrorPrint(&error)); break; case SML_MANAGER_SESSION_FLUSH: break; } smlTrace(TRACE_EXIT, "%s", __func__); return; error: printf("An error occured while handling events: %s\n", smlErrorPrint(&locerror)); smlManagerQuit(manager); g_main_loop_quit(loop); smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(&locerror)); smlErrorDeref(&locerror); } #ifdef ENABLE_OBEX static void discover_cb(obex_t *handle, obex_object_t *object, int mode, int event, int obex_cmd, int obex_rsp) { (void) handle; (void) object; (void) mode; (void) event; (void) obex_cmd; (void) obex_rsp; } void list_interfaces() { obex_t *handle; obex_interface_t* obex_intf; int i, interfaces_number = 0; if(!(handle = OBEX_Init(OBEX_TRANS_USB, discover_cb, 0))) { printf("OBEX_Init failed\n"); return; } if (geteuid() != 0) fprintf(stderr, "Superuser privileges are required to access complete USB information.\n"); interfaces_number = OBEX_FindInterfaces(handle, &obex_intf); printf("Found %d USB OBEX interfaces\n", interfaces_number); for (i = 0; i < interfaces_number; i++) printf("Interface %d:\n\tManufacturer: %s\n\tProduct: %s\n\tInterface description: %s\n", i, obex_intf[i].usb.manufacturer, obex_intf[i].usb.product, obex_intf[i].usb.control_interface); printf("Use '-u interface_number' to connect\n"); OBEX_Cleanup(handle); } #endif gboolean _sessions_prepare(GSource *source, gint *timeout_) { *timeout_ = 50; return FALSE; } gboolean _sessions_check(GSource *source) { GList *s = NULL; for (s = sessions; s; s = s->next) { SmlDsSession *session = s->data; if (smlDsSessionCheck(session)) return TRUE; } if (smlManagerCheck(manager)) return TRUE; return FALSE; } gboolean _sessions_dispatch(GSource *source, GSourceFunc callback, gpointer user_data) { GList *s = NULL; for (s = sessions; s; s = s->next) { SmlDsSession *session = s->data; smlDsSessionDispatch(session); } smlManagerDispatch(manager); return TRUE; } GMainContext *_sessions_attach() { GMainContext *context = g_main_context_new(); GSourceFuncs *functions = g_malloc0(sizeof(GSourceFuncs)); functions->prepare = _sessions_prepare; functions->check = _sessions_check; functions->dispatch = _sessions_dispatch; functions->finalize = NULL; GSource *source = g_source_new(functions, sizeof(GSource)); g_source_set_callback(source, NULL, NULL, NULL); g_source_attach(source, context); return context; } int main(int argc, char *argv[]) { SmlTransportConnectionType type = SML_TRANSPORT_CONNECTION_TYPE_USB; char *url = NULL; char *port = NULL; SmlMimeType mimeType = SML_MIMETYPE_XML; SmlError *error = NULL; char *identifier = NULL; char *username = NULL; char *password = NULL; SmlNotificationVersion sanVersion = SML_SAN_VERSION_11; if (!g_thread_supported ()) g_thread_init (NULL); if (argc == 1) usage (argv[0], 1); int i = 0; for (i = 1; i < argc; i++) { char *arg = argv[i]; if (!strcmp (arg, "--sync") || !strcmp(arg, "--slow-sync") || !strcmp(arg, "--add")) { i += 2; continue; } else if (!strcmp (arg, "-u")) { i++; if (!argv[i]) { #ifdef ENABLE_OBEX list_interfaces(); return 0; #else printf("OBEX not available in this build\n"); return 1; #endif } errno = 0; port = argv[i]; if (!port) usage (argv[0], 1); } else if (!strcmp (arg, "-b")) { #ifdef ENABLE_BLUETOOTH type = SML_TRANSPORT_CONNECTION_TYPE_BLUETOOTH; i++; if (!argv[i]) usage (argv[0], 1); url = g_strdup(argv[i]); i++; if (!argv[i]) usage (argv[0], 1); errno = 0; port = argv[i]; if (!port) usage (argv[0], 1); #else printf("Bluetooth not available in this build\n"); return 1; #endif } else if (!strcmp (arg, "-s")) { type = SML_TRANSPORT_CONNECTION_TYPE_SERIAL; i++; if (!argv[i]) usage (argv[0], 1); url = g_strdup(argv[i]); } else if (!strcmp (arg, "--identifier")) { i++; if (!argv[i]) usage (argv[0], 1); identifier = g_strdup(argv[i]); } else if (!strcmp (arg, "--username")) { i++; if (!argv[i]) usage (argv[0], 1); username = g_strdup(argv[i]); } else if (!strcmp (arg, "--password")) { i++; if (!argv[i]) usage (argv[0], 1); password = g_strdup(argv[i]); } else if (!strcmp (arg, "--recvLimit")) { i++; if (!argv[i]) usage (argv[0], 1); recvLimit = atoi(argv[i]); } else if (!strcmp (arg, "--maxObjSize")) { i++; if (!argv[i]) usage (argv[0], 1); maxObjSize = atoi(argv[i]); } else if (!strcmp (arg, "--useStringTable")) { useStringTable = TRUE; } else if (!strcmp (arg, "--disableNumberOfChanges")) { useNumberOfChanges = FALSE; } else if (!strcmp (arg, "--useTimeAnchor")) { useTimeAnchor = malloc(sizeof(char)*17); time_t htime = time(NULL); strftime(useTimeAnchor, 17, "%Y%m%dT%H%M%SZ", gmtime(&htime)); } else if (!strcmp (arg, "--version")) { i++; if (!argv[i]) usage (argv[0], 1); if (!strcmp (argv[i], "1.0")) { sanVersion = SML_SAN_VERSION_10; } else if (!strcmp (argv[i], "1.1")) { sanVersion = SML_SAN_VERSION_11; } else if (!strcmp (argv[i], "1.2")) { sanVersion = SML_SAN_VERSION_12; } else usage (argv[0], 1); } else if (!strcmp (arg, "--help")) { usage (argv[0], 0); } else if (!strcmp (arg, "--wbxml")) { mimeType = SML_MIMETYPE_WBXML; } else if (!strcmp (arg, "--dumpinfo")) { dumpinfo = TRUE; } else if (!strcmp (arg, "--onlyinfo")) { onlyInfo = TRUE; } else if (!strcmp (arg, "--")) { break; } else if (arg[0] == '-') { usage (argv[0], 1); } else { usage (argv[0], 1); } } /* The transport needed to transport the data */ SmlTransport *client = smlTransportNew(SML_TRANSPORT_OBEX_CLIENT, &error); if (!client) goto error; /* The manager responsible for handling the other objects */ manager = smlManagerNew(client, &error); if (!manager) goto error; smlManagerSetEventCallback(manager, _manager_event, NULL); if (useLargeObjs) { /* This is a server which supports SyncML 1.1 or higher. * So large objects must be supported. */ smlManagerSetLocalMaxMsgSize(manager, recvLimit); smlManagerSetLocalMaxObjSize(manager, maxObjSize); } /* The authenticator */ SmlAuthenticator *auth = smlAuthNew(&error); if (!auth) goto error; if (!username) smlAuthSetEnable(auth, FALSE); if (!smlAuthRegister(auth, manager, &error)) goto error_free_auth; /* Now create the devinf handler */ devinf = smlDevInfNew("LibSyncmML", SML_DEVINF_DEVTYP_WORKSTATION, &error); if (!devinf) goto error_free_manager; smlDevInfSetSupportsNumberOfChanges(devinf, useNumberOfChanges); smlDevInfSetSupportsLargeObjs(devinf, useLargeObjs); smlDevInfSetSupportsUTC(devinf, TRUE); agent = smlDevInfAgentNew(devinf, &error); if (!agent) goto error_free_manager; if (!smlDevInfAgentRegister(agent, manager, &error)) goto error_free_manager; /* Create the alert for the remote device */ if (!identifier) identifier = g_strdup("LibSyncML Test Suite"); SmlNotification *san = smlNotificationNew(sanVersion, SML_SAN_UIMODE_UNSPECIFIED, SML_SAN_INITIATOR_USER, 1, identifier, "/", mimeType, &error); if (!san) goto error; smlNotificationSetManager(san, manager); for (i = 1; i < argc; i++) { char *arg = argv[i]; if (!strcmp (arg, "--sync") || !strcmp(arg, "--slow-sync")) { i++; if (!argv[i]) usage (argv[0], 1); dbTypes = g_list_append(dbTypes, argv[i]); if (!strstr(argv[i], "/")) fprintf(stderr, "WARNING: Specified database type \"%s\" doesn't look like a valid MIME type!\n" "WARNING: (Mixed up database path/location with database type?)\n", argv[i] ? argv[i] : ""); i++; if (!argv[i]) usage (argv[0], 1); dbLocations = g_list_append(dbLocations, argv[i]); if (!strcmp(arg, "--slow-sync")) dbSlow = g_list_append(dbSlow, GINT_TO_POINTER(TRUE)); else dbSlow = g_list_append(dbSlow, GINT_TO_POINTER(FALSE)); /* We now create the ds server hat the given location */ SmlLocation *loc = smlLocationNew(g_list_last(dbLocations)->data, NULL, &error); if (!loc) goto error; SmlDsServer *dsserver = smlDsServerNew(g_list_last(dbTypes)->data, loc, &error); if (!dsserver) goto error_free_manager; if (!smlDsServerRegister(dsserver, manager, &error)) goto error_free_auth; smlDsServerSetConnectCallback(dsserver, _ds_alert, NULL); /* Then we add the alert to the SAN */ if (!smlDsServerAddSan(dsserver, san, &error)) goto error; /* And we also add the devinfo to the devinf agent */ SmlDevInfDataStore *datastore = smlDevInfDataStoreNew(smlLocationGetURI(loc), &error); if (!datastore) goto error; if (!strcmp(g_list_last(dbTypes)->data, SML_ELEMENT_TEXT_VCARD)) { smlDevInfDataStoreSetRxPref(datastore, SML_ELEMENT_TEXT_VCARD, "2.1"); smlDevInfDataStoreSetTxPref(datastore, SML_ELEMENT_TEXT_VCARD, "2.1"); } else if (!strcmp(g_list_last(dbTypes)->data, SML_ELEMENT_TEXT_VCAL)) { smlDevInfDataStoreSetRxPref(datastore, SML_ELEMENT_TEXT_VCAL, "1.0"); smlDevInfDataStoreSetTxPref(datastore, SML_ELEMENT_TEXT_VCAL, "1.0"); } else if (!strcmp(g_list_last(dbTypes)->data, SML_ELEMENT_TEXT_PLAIN)) { smlDevInfDataStoreSetRxPref(datastore, SML_ELEMENT_TEXT_PLAIN, "1.0"); smlDevInfDataStoreSetTxPref(datastore, SML_ELEMENT_TEXT_PLAIN, "1.0"); } smlDevInfDataStoreSetSyncCap(datastore, SML_DEVINF_SYNCTYPE_TWO_WAY, TRUE); smlDevInfDataStoreSetSyncCap(datastore, SML_DEVINF_SYNCTYPE_SLOW_SYNC, TRUE); smlDevInfDataStoreSetSyncCap(datastore, SML_DEVINF_SYNCTYPE_SERVER_ALERTED_SYNC, TRUE); smlDevInfAddDataStore(devinf, datastore); } else if (!strcmp (arg, "--add")) { i++; if (!argv[i]) usage (argv[0], 1); types = g_list_append(types, argv[i]); i++; if (!argv[i]) usage (argv[0], 1); paths = g_list_append(paths, argv[i]); } } if (g_list_length(dbLocations) == 0) { smlErrorSet(&error, SML_ERROR_GENERIC, "You have to configure at least one database"); goto error; } /* Initialize the Transport */ if (!smlTransportSetConfigOption(client, "PORT", port, &error) || !smlTransportSetConfigOption(client, "URL", url, &error) || !smlTransportSetConnectionType(client, type, &error) || !smlTransportInitialize(client, &error)) goto error; /* Run the manager */ if (!smlManagerStart(manager, &error)) goto error; if (!smlTransportConnect(client, &error)) goto error; if (!smlNotificationSend(san, client, &error)) goto error; smlNotificationFree(san); GMainContext *context = _sessions_attach(); loop = g_main_loop_new(context, TRUE); g_main_loop_run(loop); if (!smlTransportDisconnect(client, NULL, &error)) goto error; /* Stop the manager */ smlManagerStop(manager); smlTransportFinalize(client, &error); smlTransportFree(client); if (dumpinfo) { if (!deviceDevinf) { printf("Didnt receive the devinf though it was requested\n"); } else { printf("Send the output below to the libsyncml developers\n"); printf("\n========================================\n"); printf("Man: %s\n", smlDevInfGetManufacturer(deviceDevinf)); printf("Mod: %s\n", smlDevInfGetModel(deviceDevinf)); printf("FirmwareVersion: %s\n", smlDevInfGetFirmwareVersion(deviceDevinf)); printf("SoftwareVersion: %s\n", smlDevInfGetSoftwareVersion(deviceDevinf)); printf("HardwareVersion: %s\n", smlDevInfGetHardwareVersion(deviceDevinf)); printf("\n"); printf("ReceiveLimit: %i\n", recvLimit); printf("MaxObjSize: %i\n", maxObjSize); printf("Connection used: OBEX Client\n"); printf("Identifier: %s\n", identifier); printf("\nDatabases:\n"); int i = 0; for (i = 0; i < g_list_length(dbLocations); i++) { printf("DB Locations: %s\n", (char *)g_list_nth_data(dbLocations, i)); printf("DB Type: %s\n", (char *)g_list_nth_data(dbTypes, i)); printf("DB Slow: %i\n\n", GPOINTER_TO_INT(g_list_nth_data(dbSlow, i))); } printf("Bluetooth: %s\n", type == SML_TRANSPORT_CONNECTION_TYPE_BLUETOOTH ? "Yes" : "Unknown"); printf("Wbxml: %s\n", mimeType == SML_MIMETYPE_WBXML ? "Yes" : "No"); printf("SyncML Version: 1.%i\n", sessionVersion - 1); printf("SupportsNumberOfChanges: %s\n", smlDevInfSupportsNumberOfChanges(deviceDevinf) ? "Yes" : "No"); printf("SupportsLargeObjects: %s\n", smlDevInfSupportsLargeObjs(deviceDevinf) ? "Yes" : "No"); } } g_free(identifier); g_free(url); return 0; error_free_auth: smlAuthFree(auth); error_free_manager: smlManagerFree(manager); error: printf("Failed to start the client: %s\n", smlErrorPrint(&error)); smlErrorDeref(&error); return -1; }