00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <libsyncml/syncml.h>
00023 #include <libsyncml/syncml_internals.h>
00024
00025 #include <libsyncml/sml_error_internals.h>
00026 #include <libsyncml/sml_transport_internals.h>
00027
00028 #include "obex_internals.h"
00029 #include "obex_client_internals.h"
00030 #include "obex_client_vendor_internals.h"
00031
00032 #ifdef ENABLE_BLUETOOTH_SDPLIB
00033
00034 #include <bluetooth/sdp.h>
00035 #include <bluetooth/sdp_lib.h>
00036
00037 #endif
00038
00039 #include <fcntl.h>
00040 #ifndef WIN32
00041 #include <sys/poll.h>
00042 #include <sys/stat.h>
00043 #include <termios.h>
00044 #include <sys/socket.h>
00045 #include <netinet/in.h>
00046 #include <netdb.h>
00047 #include <sys/socket.h>
00048 #include <arpa/inet.h>
00049 #include <netinet/in.h>
00050 #endif
00051
00052 #include <sys/types.h>
00053 #include <stdio.h>
00054 #include <stdlib.h>
00055 #include <string.h>
00056 #include <unistd.h>
00057 #include <strings.h>
00058
00059 #ifndef WIN32
00060
00061 static SmlBool obex_cable_at(
00062 SmlTransportObexClientEnv *userdata,
00063 const char *cmd,
00064 char *rspbuf,
00065 int rspbuflen,
00066 int timeout,
00067 SmlError **error)
00068 {
00069 smlTrace(TRACE_ENTRY, "%s(%p, %s, %p, %i, %i, %p)", __func__, userdata, VA_STRING(cmd), rspbuf, rspbuflen, timeout, error);
00070 CHECK_ERROR_REF
00071
00072 fd_set ttyset;
00073 struct timeval tv;
00074 gint fd;
00075
00076 SmlBool statusOnly = FALSE;
00077
00078 char *answer = NULL;
00079 char *answer_end = NULL;
00080 int answer_size;
00081
00082 char tmpbuf[100] = {0,};
00083 int actual;
00084 int total = 0;
00085 int done = 0;
00086
00087 if (!strncasecmp("ATZ", cmd, 3)) {
00088 smlTrace(TRACE_INTERNAL, "%s: detected standard ATZ command", __func__);
00089 statusOnly = TRUE;
00090 }
00091 if (!strncasecmp("AT+CPROT=0", cmd, 10)) {
00092 smlTrace(TRACE_INTERNAL, "%s: detected standard AT+CPROT=0 command", __func__);
00093 statusOnly = TRUE;
00094 }
00095
00096
00097 fd = userdata->fd;
00098 rspbuf[0] = 0;
00099 if(fd < 0) {
00100 smlErrorSet(error, SML_ERROR_GENERIC,
00101 "The file descriptor for the cable AT command is not legal (%d).",
00102 fd);
00103 goto error;
00104 }
00105 if(cmd != NULL) {
00106
00107 gint cmdlen;
00108
00109 cmdlen = strlen(cmd);
00110 if(write(fd, cmd, cmdlen) < cmdlen) {
00111 smlErrorSet(error, SML_ERROR_GENERIC,
00112 "The command cannot be written (completely) to the file descriptor.");
00113 goto error;
00114 }
00115 }
00116
00117
00118
00119
00120 while(!done) {
00121 FD_ZERO(&ttyset);
00122 FD_SET(fd, &ttyset);
00123 tv.tv_sec = timeout;
00124 tv.tv_usec = 0;
00125 if(select(fd+1, &ttyset, NULL, NULL, &tv)) {
00126 actual = read(fd, &tmpbuf[total], sizeof(tmpbuf) - total);
00127 if(actual < 0) {
00128 smlErrorSet(error, SML_ERROR_GENERIC,
00129 "read failed with return code %i.",
00130 actual);
00131 goto error;
00132 }
00133 total += actual;
00134
00135
00136 if(total == sizeof(tmpbuf)) {
00137 smlErrorSet(error, SML_ERROR_NOT_IMPLEMENTED,
00138 "The size of the answer to the AT command %s was too large for the internal buffer.",
00139 VA_STRING(cmd));
00140 goto error;
00141 }
00142
00143 if( (answer = index(tmpbuf, '\n')) &&
00144 (answer_end = index(answer+1, '\n'))
00145 ) {
00146
00147 if (!strncasecmp("ERROR", answer+1, 5)) {
00148 smlErrorSet(error, SML_ERROR_GENERIC,
00149 "The AT command %s failed.",
00150 VA_STRING(cmd));
00151 goto error;
00152 }
00153
00154
00155 if (statusOnly) {
00156
00157 done = 1;
00158 } else {
00159 char *ok = NULL;
00160 char *ok_end = NULL;
00161 if ( (ok = index(answer_end+1, '\n')) &&
00162 (ok_end = index(ok+1, '\n'))
00163 ) {
00164
00165 done = 1;
00166 }
00167 }
00168 }
00169 } else {
00170
00171 smlErrorSet(error, SML_ERROR_INTERNAL_IO_ERROR,
00172 "The read operation for the answer of the AT command was timed out.");
00173 goto error;
00174 }
00175 }
00176 smlTrace(TRACE_INTERNAL, "%s: answer: %s", __func__, VA_STRING(answer));
00177
00178
00179 if((*answer_end == '\r') || (*answer_end == '\n'))
00180 answer_end--;
00181 if((*answer_end == '\r') || (*answer_end == '\n'))
00182 answer_end--;
00183 if((*answer == '\r') || (*answer == '\n'))
00184 answer++;
00185 if((*answer == '\r') || (*answer == '\n'))
00186 answer++;
00187
00188 answer_size = (answer_end) - answer +1;
00189
00190 smlTrace(TRACE_INTERNAL, "%s: answer size=%d", __func__, answer_size);
00191 if( (answer_size) >= rspbuflen ) {
00192 smlErrorSet(error, SML_ERROR_NOT_IMPLEMENTED,
00193 "The size of the answer to the AT command %s was too large.",
00194 VA_STRING(cmd));
00195 goto error;
00196 }
00197
00198 strncpy(rspbuf, answer, answer_size);
00199 rspbuf[answer_size] = 0;
00200 smlTrace(TRACE_EXIT, "%s", __func__);
00201 return TRUE;
00202 error:
00203 smlTrace(TRACE_EXIT, "%s - %s", __func__, smlErrorPrint(error));
00204 return FALSE;
00205 }
00206
00207 static int smlTransportObexClientCableDisconnect(obex_t *handle, gpointer ud) {
00208
00209 smlTrace(TRACE_INTERNAL, "%s(%p, %p)", __func__, handle, ud);
00210
00211 SmlTransportObexClientEnv *userdata = (SmlTransportObexClientEnv *) ud;
00212 if (userdata->fd >= 0) {
00213
00214 #ifdef TCSBRKP
00215 if(ioctl(userdata->fd, TCSBRKP, 0) < 0) {
00216 #elif defined(TCSBRK)
00217 if(ioctl(userdata->fd, TCSBRK, 0) < 0) {
00218 #else
00219 if(tcsendbreak(userdata->fd, 0) < 0) {
00220 #endif
00221 smlTrace(TRACE_INTERNAL, "%s: Unable to send break!", __func__);
00222 }
00223
00224 tcsetattr(userdata->fd, TCSANOW, &userdata->oldtio);
00225 close(userdata->fd);
00226 }
00227
00228 return 0;
00229 }
00230
00231 SmlTransportObexVendorType smlTransportObexClientGetVendor(const char *manufacturer)
00232 {
00233 smlTrace(TRACE_ENTRY, "%s(%s)", __func__, VA_STRING(manufacturer));
00234 smlAssert(manufacturer);
00235 SmlTransportObexVendorType vendor = SML_OBEX_VENDOR_UNKNOWN;
00236
00237 char *big = g_ascii_strup(manufacturer, -1);
00238
00239 if (strstr(big, "SAMSUNG") != NULL) {
00240 smlTrace(TRACE_INTERNAL, "%s - Samsung found.", __func__);
00241 vendor = SML_OBEX_VENDOR_SAMSUNG;
00242 }
00243
00244 smlSafeCFree(&big);
00245
00246 smlTrace(TRACE_EXIT, "%s - %d", __func__, vendor);
00247 return vendor;
00248 }
00249
00250 static int smlTransportObexClientCableConnect(obex_t *handle, gpointer ud)
00251 {
00252 smlTrace(TRACE_ENTRY, "%s", __func__);
00253
00254 SmlError *error = NULL;
00255 SmlTransportObexClientEnv *userdata = (SmlTransportObexClientEnv *) ud;
00256 struct termios newtio;
00257 char rspbuf[201];
00258 rspbuf[sizeof(rspbuf)-1] = 0;
00259
00260 userdata->fd = open(userdata->path, O_RDWR|O_NONBLOCK|O_NOCTTY);
00261 if (userdata->fd < 0) {
00262 smlErrorSet(&error, SML_ERROR_INTERNAL_IO_ERROR,
00263 "A valid file descriptor must be non-negative.");
00264 goto error;
00265 }
00266
00267 tcgetattr(userdata->fd, &userdata->oldtio);
00268 bzero(&newtio, sizeof(struct termios));
00269 newtio.c_cflag = B115200 | CLOCAL | CS8 | CREAD | CRTSCTS;
00270 newtio.c_cc[VMIN] = 1;
00271 newtio.c_cc[VTIME] = 0;
00272 newtio.c_iflag = IGNPAR;
00273 newtio.c_oflag = 0;
00274 tcflush(userdata->fd, TCIFLUSH);
00275 tcsetattr(userdata->fd, TCSANOW, &newtio);
00276
00277
00278 if (!obex_cable_at(userdata, "ATZ\r", rspbuf, sizeof(rspbuf) - 1, 1, &error))
00279 goto error;
00280
00281 if (strcasecmp("OK", rspbuf)) {
00282 smlErrorSet(&error, SML_ERROR_GENERIC,
00283 "The ATZ command was answered with %s.",
00284 rspbuf);
00285 goto error;
00286 }
00287
00288 if (!userdata->at_command && !userdata->manufacturer)
00289 {
00290
00291 if (!obex_cable_at(userdata, "AT+CGMI\r", rspbuf, sizeof(rspbuf), 1, &error)) {
00292 smlTrace(TRACE_ERROR, "%s: Comm-error sending AT+CGMI\\r", __func__);
00293 goto error;
00294 }
00295 userdata->manufacturer = g_strdup(rspbuf);
00296 smlTrace(TRACE_ERROR, "%s: manufacturer %s", __func__, VA_STRING(userdata->manufacturer));
00297 }
00298 if (!userdata->at_command && !userdata->model)
00299 {
00300
00301 if (!obex_cable_at(userdata, "AT+CGMM\r", rspbuf, sizeof(rspbuf), 1, &error)) {
00302 smlTrace(TRACE_ERROR, "%s: Comm-error sending AT+CGMM\\r", __func__);
00303 goto error;
00304 }
00305 userdata->model = g_strdup(rspbuf);
00306 smlTrace(TRACE_ERROR, "%s: model %s", __func__, VA_STRING(userdata->model));
00307 }
00308 if (!userdata->at_command)
00309 {
00310
00311 SmlTransportObexVendorType vendor = SML_OBEX_VENDOR_UNKNOWN;
00312 if (userdata->manufacturer) {
00313 smlTrace(TRACE_INTERNAL, "%s: Try to find an appropriate AT command", __func__);
00314 vendor = smlTransportObexClientGetVendor(userdata->manufacturer);
00315 }
00316 if (vendor) {
00317 switch(vendor) {
00318 case SML_OBEX_VENDOR_SAMSUNG:
00319 smlTrace(TRACE_INTERNAL, "%s: Samsung detected", __func__);
00320 if (!smlTransportObexVendorSamsungInit(userdata)) {
00321 smlErrorSet(&error, SML_ERROR_GENERIC,
00322 "The intialization for Samsung failed.");
00323 goto error;
00324 }
00325 break;
00326 default:
00327 smlTrace(TRACE_ERROR, "%s: Ups, vendor defined but not handled.", __func__);
00328 break;
00329 }
00330 }
00331 }
00332 if (!userdata->at_command) {
00333
00334 smlTrace(TRACE_INTERNAL, "%s: Setting up default AT command AT+CPROT=0\\r", __func__);
00335 userdata->at_command = g_strdup("AT+CPROT=0\r");
00336 }
00337
00338
00339 if (!obex_cable_at(userdata, userdata->at_command, rspbuf, sizeof(rspbuf) - 1, 1, &error))
00340 goto error;
00341
00342 if (strcasecmp("CONNECT", rspbuf)) {
00343 smlErrorSet(&error, SML_ERROR_GENERIC,
00344 "The command AT+CPROT=0 failed with answer %s.",
00345 rspbuf);
00346 goto error;
00347 }
00348
00349 return 0;
00350 error:
00351 perror(smlErrorPrint(&error));
00352 smlTransportObexClientCableDisconnect(handle, userdata);
00353 smlTrace(TRACE_ERROR, "%s - %s", __func__, smlErrorPrint(&error));
00354 smlErrorDeref(&error);
00355 return -1;
00356 }
00357
00358 static int smlTransportObexClientCableWrite(obex_t *handle, gpointer ud, guint8 *buf, int buflen) {
00359
00360 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p, %i)", __func__, handle, ud, buf, buflen);
00361 SmlTransportObexClientEnv *userdata = (SmlTransportObexClientEnv *) ud;
00362 int written = 0;
00363 int ret = 0;
00364
00365 while (ret >= 0 && written < buflen) {
00366 ret = write(userdata->fd, buf + written, buflen - written);
00367 if (ret >= 0)
00368 written += ret;
00369 }
00370
00371 smlTrace(TRACE_EXIT, "%s: %i", __func__, written);
00372 return written;
00373 }
00374
00375 gint obex_cable_handleinput(obex_t *handle, gpointer ud, gint timeout) {
00376 smlTrace(TRACE_ENTRY, "%s(%p, %p, %i)", __func__, handle, ud, timeout);
00377 struct timeval to;
00378 fd_set readfds;
00379 char buf[512];
00380 SmlTransportObexClientEnv *userdata;
00381 int ret = 0;
00382 int actual = 0;
00383
00384 userdata = (SmlTransportObexClientEnv*) ud;
00385 FD_ZERO(&readfds);
00386 FD_SET(userdata->fd, &readfds);
00387 to.tv_sec = timeout;
00388 to.tv_usec = 0;
00389
00390
00391 smlTrace(TRACE_INTERNAL, "%s - %i", __func__, __LINE__);
00392 ret = select(userdata->fd + 1, &readfds, NULL, NULL, &to);
00393
00394 if (ret < 1)
00395 goto error;
00396
00397 smlTrace(TRACE_INTERNAL, "%s - %i", __func__, __LINE__);
00398 if ((actual = read(userdata->fd, buf, sizeof(buf))) <= 0)
00399 goto end;
00400
00401 smlTrace(TRACE_INTERNAL, "%s - %i", __func__, __LINE__);
00402 OBEX_CustomDataFeed(handle, (unsigned char *) buf, actual);
00403
00404 end:
00405 smlTrace(TRACE_EXIT, "%s(%p, %p, %i)", __func__, handle, ud, timeout);
00406 return actual;
00407
00408 error:
00409
00410 smlTrace(TRACE_EXIT_ERROR, "%s: %i", __func__, ret);
00411 return ret;
00412
00413 }
00414
00415 #endif
00416
00417 static void smlTransportObexClientEvent(obex_t *handle, obex_object_t *object, int mode, int event, int obex_cmd, int obex_rsp)
00418 {
00419 smlTrace(TRACE_ENTRY, "%s(%p, %p, %i, %i, %i, %i)", __func__, handle, object, mode, event, obex_cmd, obex_rsp);
00420 SmlTransportObexClientEnv *env = OBEX_GetUserData(handle);
00421 SmlError *error = NULL;
00422
00423 switch (event) {
00424 case OBEX_EV_PROGRESS:
00425 smlTrace(TRACE_INTERNAL, "%s: Progress", __func__);
00426 break;
00427 case OBEX_EV_REQDONE:
00428 smlTrace(TRACE_INTERNAL, "%s: Request Done", __func__);
00429 env->busy = FALSE;
00430
00431 if (obex_rsp != OBEX_RSP_SUCCESS) {
00432 switch(obex_cmd) {
00433 case OBEX_CMD_CONNECT:
00434 smlErrorSet(&error, SML_ERROR_INTERNAL_MISCONFIGURATION,
00435 "The OBEX client cannot connect to the configured device or resource (%s - 0x%x).",
00436 OBEX_ResponseToString(obex_rsp),
00437 obex_rsp);
00438 break;
00439 default:
00440 smlErrorSet(&error, SML_ERROR_INTERNAL_IO_ERROR,
00441 "%s (0x%x)",
00442 OBEX_ResponseToString(obex_rsp),
00443 obex_rsp);
00444 break;
00445 }
00446 goto error;
00447 }
00448
00449
00450 switch (obex_cmd) {
00451 case OBEX_CMD_CONNECT:;
00452 uint8_t headertype = 0;
00453 obex_headerdata_t header;
00454 uint32_t len;
00455 char *who = NULL;
00456
00457 while (OBEX_ObjectGetNextHeader(env->obexhandle, object, &headertype, &header, &len)) {
00458 smlTrace(TRACE_INTERNAL, "%s: Next header %i, %d, %p", __func__, headertype, header.bq4, header.bs);
00459 switch (headertype) {
00460 case OBEX_HDR_CONNECTION:
00461 smlTrace(TRACE_INTERNAL, "%s: Found connection number: %d", __func__, header.bq4);
00462 env->connection_id = header.bq4;
00463 break;
00464 case OBEX_HDR_WHO:
00465 who = g_strndup((char *)header.bs, len);
00466 smlTrace(TRACE_INTERNAL, "%s: Found who: %s", __func__, VA_STRING(who));
00467 break;
00468 default:
00469 smlTrace(TRACE_INTERNAL, "%s: Unknown header", __func__);
00470 }
00471 }
00472
00473 if (!env->connection_id) {
00474 smlErrorSet(&error, SML_ERROR_GENERIC, "Missing connection id");
00475 smlSafeCFree(&who);
00476 goto error;
00477 }
00478
00479 smlTrace(TRACE_INTERNAL, "%s: Got who: %s", __func__, VA_STRING(who));
00480 if (!who || strcmp(who, "SYNCML-SYNC")) {
00481 smlErrorSet(&error, SML_ERROR_GENERIC, "Missing or wrong who response");
00482 smlSafeCFree(&who);
00483 goto error;
00484 }
00485 smlSafeCFree(&who);
00486
00487 smlTransportReceiveEvent(env->tsp, NULL, SML_TRANSPORT_EVENT_CONNECT_DONE, NULL, NULL);
00488 break;
00489 case OBEX_CMD_DISCONNECT:;
00490 if (!env->isDisconnected)
00491 {
00492 env->busy = FALSE;
00493 env->isDisconnected = TRUE;
00494 OBEX_TransportDisconnect(env->obexhandle);
00495 smlTransportReceiveEvent(env->tsp, NULL, SML_TRANSPORT_EVENT_DISCONNECT_DONE, NULL, NULL);
00496 }
00497 break;
00498 case OBEX_CMD_GET:;
00499 smlTrace(TRACE_INTERNAL, "%s: Got GET command done", __func__);
00500 uint32_t length = 0;
00501 char *body = NULL;
00502
00503 while (OBEX_ObjectGetNextHeader(handle, object, &headertype, &header, &len)) {
00504 smlTrace(TRACE_INTERNAL, "%s: Next header %i, %d, %p, len %i", __func__, headertype, header.bq4, header.bs, len);
00505 switch (headertype) {
00506 case OBEX_HDR_LENGTH:
00507 smlTrace(TRACE_INTERNAL, "%s: Found length: %d", __func__, header.bq4);
00508 length = header.bq4;
00509 break;
00510 case OBEX_HDR_BODY:
00511 if (!length) {
00512 smlTrace(TRACE_INTERNAL, "%s: Length not given. Calculating it to: %i", __func__, len);
00513 length = len;
00514 }
00515
00516 if (!length) {
00517 smlErrorSet(&error, SML_ERROR_GENERIC, "Got zero length!");
00518 goto error;
00519 }
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529 body = smlTryMalloc0(length + 1, &error);
00530 if (!body)
00531 goto error;
00532
00533 memcpy(body, header.bs, length);
00534 break;
00535 default:
00536 smlTrace(TRACE_INTERNAL, "%s: Unknown header", __func__);
00537 }
00538 }
00539
00540 if (!length) {
00541 smlErrorSet(&error, SML_ERROR_GENERIC, "Missing length");
00542 goto error;
00543 }
00544
00545 if (!body) {
00546 smlErrorSet(&error, SML_ERROR_GENERIC, "Missing body");
00547 goto error;
00548 }
00549
00550 SmlTransportData *tspdata = smlTransportDataNew(body, length, env->mimetype, TRUE, &error);
00551 if (!tspdata)
00552 goto error;
00553
00554 smlTransportReceiveEvent(env->tsp, NULL, SML_TRANSPORT_EVENT_DATA, tspdata, NULL);
00555 smlTransportDataDeref(tspdata);
00556 break;
00557 }
00558 break;
00559 case OBEX_EV_LINKERR:
00560 if (obex_rsp == 0)
00561 {
00562
00563 if (!env->isDisconnected)
00564 {
00565 env->busy = FALSE;
00566 env->isDisconnected = TRUE;
00567 OBEX_TransportDisconnect(env->obexhandle);
00568 smlTransportReceiveEvent(env->tsp, NULL, SML_TRANSPORT_EVENT_DISCONNECT_DONE, NULL, NULL);
00569 }
00570 } else {
00571
00572 smlErrorSet(&error, SML_ERROR_GENERIC,
00573 "Link Error: %s - 0x%x",
00574 OBEX_ResponseToString(obex_rsp), obex_rsp);
00575 smlTrace(TRACE_INTERNAL, "%s - %s",
00576 __func__, smlErrorPrint(&error));
00577 goto error;
00578 }
00579 break;
00580 case OBEX_EV_STREAMEMPTY:
00581 smlTrace(TRACE_INTERNAL, "%s: Empty Stream", __func__);
00582 break;
00583 }
00584
00585 smlTrace(TRACE_EXIT, "%s", __func__);
00586 return;
00587
00588 error:
00589 smlTransportReceiveEvent(env->tsp, NULL, SML_TRANSPORT_EVENT_ERROR, NULL, error);
00590 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(&error));
00591 smlErrorDeref(&error);
00592 env->busy = FALSE;
00593 env->error = TRUE;
00594 return;
00595 }
00596
00597 static SmlBool smlTransportObexClientSetConfigOption(
00598 SmlTransport *tsp,
00599 const char *name,
00600 const char *value,
00601 SmlError **error)
00602 {
00603 smlTrace(TRACE_ENTRY, "%s(%p, %s, %s, %p)", __func__, tsp, VA_STRING(name), VA_STRING(value), error);
00604 CHECK_ERROR_REF
00605 smlAssert(tsp);
00606 smlAssert(tsp->transport_data);
00607 smlAssert(name);
00608 SmlTransportObexClientEnv *env = tsp->transport_data;
00609
00610
00611 if (!value)
00612 {
00613 smlErrorSet(error, SML_ERROR_INTERNAL_MISCONFIGURATION,
00614 "The configuration option %s requires a value.", name);
00615 goto error;
00616 }
00617
00618 if (!strcmp(name, SML_TRANSPORT_CONFIG_BLUETOOTH_CHANNEL)) {
00619 env->port = atoi(value);
00620 smlTrace(TRACE_INTERNAL, "%s: Bluetooth channel %i detected", __func__, env->port);
00621 } else if (!strcmp(name, SML_TRANSPORT_CONFIG_BLUETOOTH_ADDRESS)) {
00622
00623 env->path = g_strdup(value);
00624 smlTrace(TRACE_INTERNAL, "%s: Bluetooth MAC %s detected", __func__, VA_STRING(env->path));
00625 } else if (!strcmp(name, SML_TRANSPORT_CONFIG_PORT)) {
00626 if (env->type == SML_TRANSPORT_CONNECTION_TYPE_BLUETOOTH)
00627 g_warning("Please use %s instead of %s.",
00628 SML_TRANSPORT_CONFIG_BLUETOOTH_CHANNEL,
00629 SML_TRANSPORT_CONFIG_PORT);
00630 env->port = atoi(value);
00631 smlTrace(TRACE_INTERNAL, "%s: Port or Bluetooth channel %i detected",
00632 __func__, env->port);
00633 } else if (!strcmp(name, SML_TRANSPORT_CONFIG_URL)) {
00634 if (env->type == SML_TRANSPORT_CONNECTION_TYPE_BLUETOOTH)
00635 g_warning("Please use %s instead of %s.",
00636 SML_TRANSPORT_CONFIG_BLUETOOTH_ADDRESS,
00637 SML_TRANSPORT_CONFIG_URL);
00638 env->path = g_strdup(value);
00639 smlTrace(TRACE_INTERNAL, "%s: URL or Bluetooth MAC %s detected",
00640 __func__, VA_STRING(env->path));
00641 } else if (!strcmp(name, SML_TRANSPORT_CONFIG_IRDA_SERVICE)) {
00642 if (env->irda_service)
00643 smlSafeCFree(&(env->irda_service));
00644 env->irda_service = g_strdup(value);
00645 smlTrace(TRACE_INTERNAL, "%s: IrDA service %s detected", __func__, VA_STRING(env->irda_service));
00646 } else if (!strcmp(name, SML_TRANSPORT_CONFIG_AT_COMMAND)) {
00647 if (env->at_command)
00648 smlSafeCFree(&(env->at_command));
00649 env->at_command = g_strdup(value);
00650 smlTrace(TRACE_INTERNAL, "%s: AT command %s detected", __func__, VA_STRING(env->at_command));
00651 } else if (!strcmp(name, SML_TRANSPORT_CONFIG_AT_MANUFACTURER)) {
00652 if (env->manufacturer)
00653 smlSafeCFree(&(env->manufacturer));
00654 env->manufacturer = g_strdup(value);
00655 smlTrace(TRACE_INTERNAL, "%s: AT manufacturer %s detected", __func__, VA_STRING(env->manufacturer));
00656 } else if (!strcmp(name, SML_TRANSPORT_CONFIG_AT_MODEL)) {
00657 if (env->model)
00658 smlSafeCFree(&(env->model));
00659 env->model = g_strdup(value);
00660 smlTrace(TRACE_INTERNAL, "%s: AT model %s detected", __func__, VA_STRING(env->model));
00661 } else if (!strcmp(name, SML_TRANSPORT_CONFIG_DATASTORE)) {
00662
00663 SmlTransportObexDatastoreType datastore = SML_TRANSPORT_OBEX_DATASTORE_UNKNOWN;
00664 if (!strcasecmp(SML_TRANSPORT_CONFIG_DATASTORE_EVENT, value))
00665 datastore = SML_TRANSPORT_OBEX_DATASTORE_EVENT;
00666 if (!strcasecmp(SML_TRANSPORT_CONFIG_DATASTORE_TODO, value))
00667 datastore = SML_TRANSPORT_OBEX_DATASTORE_TODO;
00668 if (!strcasecmp(SML_TRANSPORT_CONFIG_DATASTORE_CONTACT, value))
00669 datastore = SML_TRANSPORT_OBEX_DATASTORE_CONTACT;
00670 if (!strcasecmp(SML_TRANSPORT_CONFIG_DATASTORE_NOTE, value))
00671 datastore = SML_TRANSPORT_OBEX_DATASTORE_NOTE;
00672 if (!datastore) {
00673 smlErrorSet(error, SML_ERROR_INTERNAL_MISCONFIGURATION, "Unknown datastore %s found.", value);
00674 goto error;
00675 }
00676 SmlTransportObexDatastoreType *type = smlTryMalloc0(sizeof(SmlTransportObexDatastoreType), error);
00677 if (!type)
00678 goto error;
00679 *type = datastore;
00680 env->datastores = g_list_append(env->datastores, type);
00681 smlTrace(TRACE_INTERNAL, "%s: Datastore %i detected", __func__, datastore);
00682 } else {
00683 smlErrorSet(error, SML_ERROR_INTERNAL_MISCONFIGURATION, "Unknown parameter %s found.", name);
00684 goto error;
00685 }
00686
00687 smlTrace(TRACE_EXIT, "%s", __func__);
00688 return TRUE;
00689 error:
00690 smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(error));
00691 return FALSE;
00692
00693 }
00694
00695 static SmlBool smlTransportObexClientSetConnectionType(
00696 SmlTransport *tsp,
00697 SmlTransportConnectionType type,
00698 SmlError **error)
00699 {
00700 smlTrace(TRACE_ENTRY, "%s(%p, %i, %p)", __func__, tsp, type, error);
00701 CHECK_ERROR_REF
00702 smlAssert(tsp);
00703 smlAssert(tsp->transport_data);
00704 SmlTransportObexClientEnv *env = tsp->transport_data;
00705
00706 env->type = type;
00707
00708 switch (env->type) {
00709 case SML_TRANSPORT_CONNECTION_TYPE_NET:
00710 env->obexhandle = OBEX_Init(OBEX_TRANS_FD, smlTransportObexClientEvent, 0);
00711 break;
00712 case SML_TRANSPORT_CONNECTION_TYPE_IRDA:
00713 env->obexhandle = OBEX_Init(OBEX_TRANS_IRDA, smlTransportObexClientEvent, 0);
00714 break;
00715 case SML_TRANSPORT_CONNECTION_TYPE_BLUETOOTH:
00716 env->obexhandle = OBEX_Init(OBEX_TRANS_BLUETOOTH, smlTransportObexClientEvent, 0);
00717 break;
00718 case SML_TRANSPORT_CONNECTION_TYPE_SERIAL:
00719 env->obexhandle = OBEX_Init(OBEX_TRANS_CUST, smlTransportObexClientEvent, 0);
00720 break;
00721 case SML_TRANSPORT_CONNECTION_TYPE_USB:
00722 env->obexhandle = OBEX_Init(OBEX_TRANS_USB, smlTransportObexClientEvent, 0);
00723 break;
00724 default:
00725 smlErrorSet(error, SML_ERROR_GENERIC, "Unknown obex type");
00726 smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(error));
00727 return FALSE;
00728 }
00729
00730 if (!env->obexhandle) {
00731 smlErrorSet(error, SML_ERROR_GENERIC, "Unable to open connection");
00732 smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(error));
00733 return FALSE;
00734 }
00735
00736 #ifndef WIN32
00737 if (env->type == SML_TRANSPORT_CONNECTION_TYPE_SERIAL) {
00738 obex_ctrans_t cabletrans = {
00739 smlTransportObexClientCableConnect,
00740 smlTransportObexClientCableDisconnect,
00741 NULL,
00742 smlTransportObexClientCableWrite,
00743 obex_cable_handleinput,
00744 env};
00745 OBEX_RegisterCTransport(env->obexhandle, &cabletrans);
00746 }
00747 #endif
00748
00749 smlTrace(TRACE_EXIT, "%s", __func__);
00750 return TRUE;
00751 }
00752
00753 static SmlBool smlTransportObexClientInit(SmlTransport *tsp, SmlError **error)
00754 {
00755 smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, tsp, error);
00756 CHECK_ERROR_REF
00757 smlAssert(tsp);
00758 smlAssert(tsp->transport_data);
00759 SmlTransportObexClientEnv *env = tsp->transport_data;
00760
00761 OBEX_SetUserData(env->obexhandle, env);
00762
00763 switch (env->type) {
00764 case SML_TRANSPORT_CONNECTION_TYPE_NET:
00765 if (!env->path) {
00766 smlErrorSet(error, SML_ERROR_GENERIC,
00767 "The hostname or address is missing.");
00768 goto error;
00769 }
00770 break;
00771 case SML_TRANSPORT_CONNECTION_TYPE_BLUETOOTH:
00772 if (!env->path) {
00773 smlErrorSet(error, SML_ERROR_GENERIC,
00774 "The bluetooth address is missing.");
00775 goto error;
00776 }
00777 #ifndef ENABLE_BLUETOOTH_SDPLIB
00778 if (!env->port) {
00779 smlErrorSet(error, SML_ERROR_GENERIC,
00780 "The bluetooth channel is missing.");
00781 goto error;
00782 }
00783 #endif
00784 break;
00785 default:
00786
00787 break;
00788 }
00789
00790 smlTrace(TRACE_EXIT, "%s - TRUE", __func__);
00791 return TRUE;
00792 error:
00793 OBEX_Cleanup(env->obexhandle);
00794 if (env->path)
00795 smlSafeCFree(&(env->path));
00796 if (env->at_command)
00797 smlSafeCFree(&(env->at_command));
00798 if (env->manufacturer)
00799 smlSafeCFree(&(env->manufacturer));
00800 if (env->model)
00801 smlSafeCFree(&(env->model));
00802 smlSafeFree((gpointer *)&env);
00803 smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(error));
00804 return FALSE;
00805 }
00806
00807 static SmlBool smlTransportObexClientFinalize(void *data, SmlError **error)
00808 {
00809 smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, data, error);
00810 CHECK_ERROR_REF
00811 smlAssert(data);
00812 SmlTransportObexClientEnv *env = data;
00813
00814 smlAssert(env->tsp);
00815 if (env->path) smlSafeCFree(&(env->path));
00816
00817 OBEX_Cleanup(env->obexhandle);
00818
00819 if (env->irda_service)
00820 smlSafeCFree(&(env->irda_service));
00821 if (env->at_command)
00822 smlSafeCFree(&(env->at_command));
00823 if (env->manufacturer)
00824 smlSafeCFree(&(env->manufacturer));
00825 if (env->model)
00826 smlSafeCFree(&(env->model));
00827 while (env->datastores) {
00828 SmlTransportObexDatastoreType *type = env->datastores->data;
00829 env->datastores = g_list_remove(env->datastores, type);
00830 smlSafeFree((gpointer *) &type);
00831 }
00832
00833 smlSafeFree((gpointer *)&env);
00834
00835 smlTrace(TRACE_EXIT, "%s", __func__);
00836 return TRUE;
00837 }
00838
00839 static void smlTransportObexClientConnect(void *data)
00840 {
00841 smlTrace(TRACE_ENTRY, "%s(%p)", __func__, data);
00842 smlAssert(data);
00843 SmlTransportObexClientEnv *env = data;
00844 int fd = 0;
00845 SmlError *error = NULL;
00846 unsigned int obex_intf_cnt;
00847 obex_interface_t *obex_intf;
00848 env->isDisconnected = FALSE;
00849
00850 if (env->type == SML_TRANSPORT_CONNECTION_TYPE_NET) {
00851 smlTrace(TRACE_INTERNAL, "%s: connecting to inet address %s:%d",
00852 __func__, VA_STRING(env->path), env->port);
00853 struct sockaddr_in addr;
00854 memset(&addr, 0, sizeof(addr));
00855 addr.sin_family = AF_INET;
00856 addr.sin_port = htons(env->port);
00857
00858 struct hostent *hostinfo = gethostbyname (env->path);
00859 if (!hostinfo) {
00860 smlErrorSet(&error, SML_ERROR_GENERIC, "Unknown host %s", env->path);
00861 goto error;
00862 }
00863 addr.sin_addr = *(struct in_addr *) hostinfo->h_addr_list[0];
00864
00865 fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
00866 if (fd < 0) {
00867 smlErrorSet(&error, SML_ERROR_GENERIC, "Cannot create socket: %s", strerror(errno));
00868 goto error;
00869 }
00870
00871 smlTrace(TRACE_INTERNAL, "%s: socket %i", __func__, fd);
00872
00873 char *addrstr = inet_ntoa(addr.sin_addr);
00874 smlTrace(TRACE_INTERNAL, "%s: peer addr = %d %s %i", __func__, hostinfo->h_addr_list[0], VA_STRING(addrstr), env->port);
00875
00876 if (connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) {
00877 smlErrorSet(&error, SML_ERROR_GENERIC, "Cannot connect socket: %s", strerror(errno));
00878 goto error_close;
00879 }
00880 smlTrace(TRACE_INTERNAL, "%s: connect done", __func__);
00881
00882 } else if (env->type == SML_TRANSPORT_CONNECTION_TYPE_USB) {
00883 smlTrace(TRACE_INTERNAL, "%s: connecting to usb interface %i", __func__, env->port);
00884
00885 obex_intf_cnt = OBEX_FindInterfaces(env->obexhandle, &obex_intf);
00886 smlTrace(TRACE_INTERNAL, "%s: found %i interfaces", __func__, obex_intf_cnt);
00887
00888 if (obex_intf_cnt <= 0) {
00889 smlErrorSet(&error, SML_ERROR_GENERIC, "There are no valid USB interfaces.");
00890 goto error;
00891 } else if (env->port >= obex_intf_cnt) {
00892 smlErrorSet(&error, SML_ERROR_GENERIC, "Unable to find the USB interface number %i", env->port);
00893 goto error;
00894 } else {
00895 if (GET_OBEX_RESULT(OBEX_InterfaceConnect(env->obexhandle, &obex_intf[env->port])) < 0) {
00896 smlErrorSet(&error, SML_ERROR_GENERIC,
00897 "The interface cannot be connected. %s (%i).",
00898 strerror(errno), errno);
00899 goto error;
00900 }
00901 }
00902 smlTrace(TRACE_INTERNAL, "%s: usb connect done", __func__);
00903 } else if (env->type == SML_TRANSPORT_CONNECTION_TYPE_BLUETOOTH) {
00904 #ifdef ENABLE_BLUETOOTH
00905 smlTrace(TRACE_INTERNAL, "%s: connecting to bluetooth device %s channel %i", __func__, VA_STRING(env->path), env->port);
00906
00907 uint8_t channel = env->port;
00908 bdaddr_t bdaddr;
00909 str2ba(env->path, &bdaddr);
00910
00911 #ifdef ENABLE_BLUETOOTH_SDPLIB
00912 if (channel == 0) {
00913
00914
00915 sdp_session_t *sdp_session = sdp_connect(BDADDR_ANY, &bdaddr, SDP_RETRY_IF_BUSY);
00916 if (!sdp_session) {
00917 smlErrorSet(&error, SML_ERROR_GENERIC, "The Bluetooth connect to search for the channel failed.");
00918 goto error;
00919 }
00920 unsigned char syncml_client_uuid[] = {
00921 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x10, 0x00,
00922 0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x02};
00923 uuid_t uuid;
00924 uint32_t range = SDP_ATTR_PROTO_DESC_LIST;
00925 sdp_uuid128_create(&uuid, syncml_client_uuid);
00926 sdp_list_t *attribute = sdp_list_append(0, &range);
00927 sdp_list_t *class = sdp_list_append(0, &uuid);
00928
00929 sdp_list_t *list;
00930 if (sdp_service_search_attr_req(sdp_session, class, SDP_ATTR_REQ_INDIVIDUAL, attribute, &list) < 0) {
00931 sdp_close(sdp_session);
00932 sdp_list_free(attribute, 0);
00933 sdp_list_free(class, 0);
00934
00935 smlErrorSet(
00936 &error, SML_ERROR_GENERIC,
00937 "The service search on the Bluetooth device failed.");
00938 goto error;
00939 }
00940 sdp_list_free(attribute, 0);
00941 sdp_list_free(class, 0);
00942
00943 sdp_list_t *iterator;
00944 for(iterator = list; iterator; iterator = iterator->next) {
00945 sdp_record_t *item = (sdp_record_t *) iterator->data;
00946 sdp_list_t *protos = NULL;
00947
00948 sdp_get_access_protos(item, &protos);
00949 if(protos) {
00950 channel = sdp_get_proto_port(protos, RFCOMM_UUID);
00951 }
00952 sdp_record_free(item);
00953 }
00954 sdp_list_free(list, 0);
00955 sdp_close(sdp_session);
00956 sleep(1);
00957 smlTrace(TRACE_INTERNAL,
00958 "%s: SDP SyncML channel for %s: %d",
00959 __func__, env->path, channel);
00960
00961 }
00962 #endif
00963
00964 if (GET_OBEX_RESULT(BtOBEX_TransportConnect(env->obexhandle, BDADDR_ANY, &bdaddr, channel)) < 0) {
00965 smlErrorSet(&error, SML_ERROR_GENERIC,
00966 "The Bluetooth connect failed. %s (%i).",
00967 strerror(errno), errno);
00968 goto error;
00969 }
00970
00971 smlTrace(TRACE_INTERNAL, "%s: bluetooth connect done", __func__);
00972 #else
00973 smlErrorSet(&error, SML_ERROR_GENERIC, "Bluetooth not enabled");
00974 goto error;
00975 #endif
00976 } else if (env->type == SML_TRANSPORT_CONNECTION_TYPE_IRDA) {
00977 smlTrace(TRACE_INTERNAL, "%s: connecting to IrDA service %s", __func__, env->irda_service ? env->irda_service : "OBEX");
00978
00979 if (GET_OBEX_RESULT(IrOBEX_TransportConnect(env->obexhandle, env->irda_service)) < 0) {
00980 smlErrorSet(&error, SML_ERROR_GENERIC,
00981 "The IrDA connect failed. %s (%i).",
00982 strerror(errno), errno);
00983 goto error;
00984 }
00985
00986 smlTrace(TRACE_INTERNAL, "%s: IrDA connect done", __func__);
00987 } else {
00988 #ifndef WIN32
00989 struct termios tio;
00990 memset(&tio, 0, sizeof(tio));
00991
00992
00993 fd = open(env->path, O_RDWR | O_NOCTTY);
00994 if (fd == -1) {
00995 smlErrorSet(&error, SML_ERROR_GENERIC, "Unable to open %s: %s", env->path, strerror(errno));
00996 goto error;
00997 }
00998
00999
01000 if (lockf(fd, F_TLOCK, 0)) {
01001 smlErrorSet(&error, SML_ERROR_GENERIC, "Unable to lock %s: %s", env->path, strerror(errno));
01002 goto error_close;
01003 }
01004
01005 if (tcgetattr(fd, &tio)) {
01006 smlErrorSet(&error, SML_ERROR_GENERIC, "Unable to get attr from %s", env->path);
01007 goto error_unlock;
01008 }
01009
01010
01011
01012
01013 #if defined(sun) && defined(__SVR4)
01014 tio.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
01015 tio.c_oflag &= ~OPOST;
01016 tio.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
01017 tio.c_cflag &= ~(CSIZE|PARENB);
01018 tio.c_cflag |= CS8;
01019 #else
01020 cfmakeraw(&tio);
01021 #endif
01022
01023 cfsetispeed(&tio, B115200);
01024 cfsetospeed(&tio, B115200);
01025
01026 if (tcsetattr(fd, TCSANOW, &tio)) {
01027 smlErrorSet(&error, SML_ERROR_GENERIC, "Unable to set attr from %s", env->path);
01028 goto error_unlock;
01029 }
01030 tcflush(fd, TCIFLUSH);
01031 #endif
01032 }
01033
01034 if (env->type != SML_TRANSPORT_CONNECTION_TYPE_USB
01035 && env->type != SML_TRANSPORT_CONNECTION_TYPE_BLUETOOTH
01036 && env->type != SML_TRANSPORT_CONNECTION_TYPE_IRDA) {
01037
01038 if (GET_OBEX_RESULT(FdOBEX_TransportSetup(env->obexhandle, fd, fd, 4096)) < 0) {
01039 smlErrorSet(&error, SML_ERROR_GENERIC,
01040 "The OBEX transport setup failed. %s (%i).",
01041 strerror(errno), errno);
01042 goto error_unlock;
01043 }
01044 }
01045
01046
01047 obex_object_t *obj = OBEX_ObjectNew(env->obexhandle, OBEX_CMD_CONNECT);
01048 if (!obj) {
01049 smlErrorSet(&error, SML_ERROR_GENERIC, "Unable to create new connect object");
01050 goto error_transport_close;
01051 }
01052
01053
01054 obex_headerdata_t header;
01055 header.bs = (unsigned char *)"SYNCML-SYNC";
01056 OBEX_ObjectAddHeader(env->obexhandle, obj, OBEX_HDR_TARGET, header, strlen((char *)header.bs), OBEX_FL_FIT_ONE_PACKET);
01057
01058 env->busy = TRUE;
01059
01060 if (GET_OBEX_RESULT(OBEX_Request(env->obexhandle, obj)) < 0) {
01061 smlErrorSet(&error, SML_ERROR_GENERIC,
01062 "The OBEX request failed. %s (%i).",
01063 strerror(errno), errno);
01064 goto error_free_obj;
01065 }
01066
01067 if (env->error) {
01068 smlTrace(TRACE_EXIT, "%s: Unable to send connect request. Bailing out", __func__);
01069 return;
01070 }
01071
01072
01073 while (env->busy) {
01074 int result = OBEX_HandleInput(env->obexhandle, 20);
01075 if (result < 0) {
01076 smlErrorSet(&error, SML_ERROR_GENERIC,
01077 "The connect request was not successful (%i).",
01078 result);
01079 goto error;
01080 } else if (result == 0) {
01081 smlErrorSet(&error, SML_ERROR_GENERIC,
01082 "The connect request was timed out.");
01083 goto error;
01084 }
01085 }
01086
01087 smlTrace(TRACE_EXIT, "%s", __func__);
01088 return;
01089
01090 error_free_obj:
01091 OBEX_ObjectDelete(env->obexhandle, obj);
01092 error_transport_close:
01093 OBEX_Cleanup(env->obexhandle);
01094 error_unlock:
01095 #ifndef WIN32
01096 if (!lockf(fd, F_ULOCK, 0))
01097 smlTrace(TRACE_ERROR, "%s: error_unlock failed.", __func__);
01098 #endif
01099 error_close:
01100 close(fd);
01101 error:
01102 smlTransportReceiveEvent(env->tsp, NULL, SML_TRANSPORT_EVENT_ERROR, NULL, error);
01103 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(&error));
01104 smlErrorDeref(&error);
01105 }
01106
01107 static void smlTransportObexClientDisconnect(void *data, void *linkdata)
01108 {
01109 smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, data, linkdata);
01110 smlAssert(data);
01111 SmlTransportObexClientEnv *env = data;
01112 SmlError *error = NULL;
01113
01114 if (env->isDisconnected) {
01115
01116
01117
01118
01119 smlTrace(TRACE_EXIT_ERROR,
01120 "%s - disconnect called on already disconnected transport",
01121 __func__);
01122 g_warning("%s called on disconnected OBEX connection.", __func__);
01123 return;
01124 }
01125
01126 env->error = FALSE;
01127
01128
01129 obex_object_t *obj = OBEX_ObjectNew(env->obexhandle, OBEX_CMD_DISCONNECT);
01130 if (!obj) {
01131 smlErrorSet(&error, SML_ERROR_GENERIC, "Unable to create new disconnect object");
01132 goto error;
01133 }
01134
01135
01136 obex_headerdata_t header;
01137 header.bq4 = env->connection_id;
01138 OBEX_ObjectAddHeader(env->obexhandle, obj, OBEX_HDR_CONNECTION, header, sizeof(env->connection_id), OBEX_FL_FIT_ONE_PACKET);
01139
01140 env->busy = TRUE;
01141
01142 if (GET_OBEX_RESULT(OBEX_Request(env->obexhandle, obj)) < 0) {
01143 smlErrorSet(&error, SML_ERROR_GENERIC,
01144 "The OBEX request cannot be sent. %s (%i).",
01145 strerror(errno), errno);
01146 goto error_free_obj;
01147 }
01148
01149 if (env->error) {
01150 smlErrorSet(&error, SML_ERROR_GENERIC, "Unable to send disconnect request. Bailing out");
01151 goto error;
01152 }
01153
01154
01155
01156
01157
01158
01159 int maxLoop = 3;
01160 int i = 0;
01161 while (env->busy) {
01162 smlTrace(TRACE_INTERNAL, "%s: Disconnect loop %i", __func__, i);
01163 int result = OBEX_HandleInput(env->obexhandle, 1);
01164
01165 if (result < 0) {
01166 smlErrorSet(&error, SML_ERROR_GENERIC,
01167 "The disconnect request was not accepted (%i).",
01168 result);
01169 goto error;
01170 } else if (result == 0 && !env->busy && !env->isDisconnected) {
01171 smlErrorSet(&error, SML_ERROR_GENERIC,
01172 "The disconnect request was timed out.");
01173 goto error;
01174 }
01175
01176 if (i == maxLoop) {
01177 smlTrace(TRACE_INTERNAL, "%s: Did not receive a response to our disconnect", __func__);
01178 break;
01179 }
01180 i++;
01181 }
01182
01183
01184
01185 if (!env->isDisconnected)
01186 {
01187 env->busy = FALSE;
01188 env->isDisconnected = TRUE;
01189 OBEX_TransportDisconnect(env->obexhandle);
01190 smlTransportReceiveEvent(env->tsp, NULL, SML_TRANSPORT_EVENT_DISCONNECT_DONE, NULL, NULL);
01191 }
01192
01193 smlTrace(TRACE_EXIT, "%s", __func__);
01194 return;
01195
01196 error_free_obj:
01197 OBEX_ObjectDelete(env->obexhandle, obj);
01198 error:
01199 smlTransportReceiveEvent(env->tsp, NULL, SML_TRANSPORT_EVENT_ERROR, NULL, error);
01200 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(&error));
01201 smlErrorDeref(&error);
01202 }
01203
01204 static void smlTransportObexClientSend(void *userdata, void *link_, SmlTransportData *data, SmlError *error)
01205 {
01206 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p, %p)", __func__, userdata, link_, data, error);
01207 smlAssert(error || data);
01208 smlAssert(userdata);
01209 SmlTransportObexClientEnv *env = userdata;
01210 smlAssert(env);
01211
01212 if (error)
01213 goto error;
01214
01215 env->error = FALSE;
01216 env->mimetype = data->type;
01217
01218
01219 obex_object_t *obj = OBEX_ObjectNew(env->obexhandle, OBEX_CMD_PUT);
01220 if (!obj) {
01221 smlErrorSet(&error, SML_ERROR_GENERIC, "Unable to create new put object");
01222 goto error;
01223 }
01224
01225
01226 obex_headerdata_t header;
01227
01228 smlTrace(TRACE_INTERNAL, "%s: Adding connection id %i", __func__, env->connection_id);
01229
01230
01231 header.bq4 = env->connection_id;
01232 OBEX_ObjectAddHeader(env->obexhandle, obj, OBEX_HDR_CONNECTION, header, sizeof(env->connection_id), OBEX_FL_FIT_ONE_PACKET);
01233
01234 const char *target = NULL;
01235 switch (data->type) {
01236 case SML_MIMETYPE_WBXML:
01237 target = SML_ELEMENT_WBXML;
01238 break;
01239 case SML_MIMETYPE_XML:
01240 target = SML_ELEMENT_XML;
01241 break;
01242 case SML_MIMETYPE_SAN:
01243 target = SML_ELEMENT_SAN;
01244 break;
01245 default:
01246 smlErrorSet(&error, SML_ERROR_GENERIC, "Unknown mime type");
01247 goto error_free_obj;
01248 }
01249 smlTrace(TRACE_INTERNAL, "%s: Target %s", __func__, VA_STRING(target));
01250
01251
01252
01253
01254
01255
01256
01257
01258
01259
01260
01261
01262
01263 header.bs = (unsigned char *)target;
01264 OBEX_ObjectAddHeader(env->obexhandle, obj, OBEX_HDR_TYPE, header, strlen(target) + 1, 0);
01265
01266
01267 header.bq4 = (uint32_t)data->size;
01268 OBEX_ObjectAddHeader(env->obexhandle, obj, OBEX_HDR_LENGTH, header, sizeof(uint32_t), 0);
01269
01270 header.bs = (unsigned char *)data->data;
01271 OBEX_ObjectAddHeader(env->obexhandle, obj, OBEX_HDR_BODY, header, data->size, 0);
01272
01273 env->busy = TRUE;
01274
01275 if (GET_OBEX_RESULT(OBEX_Request(env->obexhandle, obj)) < 0) {
01276 smlErrorSet(&error, SML_ERROR_GENERIC,
01277 "The OBEX request cannot be sent. %s (%i).",
01278 strerror(errno), errno);
01279 goto error_free_obj;
01280 }
01281
01282
01283 while (env->busy) {
01284 int result = OBEX_HandleInput(env->obexhandle, 20);
01285 if (result < 0) {
01286 smlErrorSet(&error, SML_ERROR_GENERIC,
01287 "The request was not successful (%d).",
01288 result);
01289 goto error;
01290 } else if (result == 0 && !env->busy) {
01291 smlErrorSet(&error, SML_ERROR_GENERIC,
01292 "The request was timed out.");
01293 goto error;
01294 }
01295 }
01296
01297 if (env->error) {
01298 smlErrorSet(&error, SML_ERROR_GENERIC, "Unable to send put request. Bailing out");
01299 goto error;
01300 }
01301
01302 smlTrace(TRACE_INTERNAL, "%s: Done sending the put request", __func__);
01303
01304 if (!data->needsAnswer) {
01305 smlTrace(TRACE_EXIT, "%s: No answer is needed", __func__);
01306 return;
01307 }
01308
01309
01310 obj = OBEX_ObjectNew(env->obexhandle, OBEX_CMD_GET);
01311 if (!obj) {
01312 smlErrorSet(&error, SML_ERROR_GENERIC, "Unable to create new get object");
01313 goto error;
01314 }
01315
01316
01317 smlTrace(TRACE_INTERNAL, "%s: Adding connection id %i", __func__, env->connection_id);
01318
01319
01320 header.bq4 = env->connection_id;
01321 OBEX_ObjectAddHeader(env->obexhandle, obj, OBEX_HDR_CONNECTION, header, sizeof(env->connection_id), OBEX_FL_FIT_ONE_PACKET);
01322
01323
01324
01325
01326
01327
01328
01329
01330 if (data->type_get != SML_MIMETYPE_UNKNOWN)
01331 {
01332 switch (data->type_get) {
01333 case SML_MIMETYPE_WBXML:
01334 target = SML_ELEMENT_WBXML;
01335 break;
01336 case SML_MIMETYPE_XML:
01337 target = SML_ELEMENT_XML;
01338 break;
01339 case SML_MIMETYPE_SAN:
01340 target = SML_ELEMENT_SAN;
01341 break;
01342 default:
01343 smlErrorSet(&error, SML_ERROR_GENERIC, "Unknown mime type");
01344 goto error_free_obj;
01345 }
01346
01347
01348 env->mimetype = data->type_get;
01349
01350 smlTrace(TRACE_INTERNAL, "%s: Switch to new target: %s", __func__, VA_STRING(target));
01351 }
01352
01353
01354
01355
01356
01357 header.bs = (unsigned char *)target;
01358 OBEX_ObjectAddHeader(env->obexhandle, obj, OBEX_HDR_TYPE, header, strlen(target) + 1, 0);
01359
01360 env->busy = TRUE;
01361
01362 if (GET_OBEX_RESULT(OBEX_Request(env->obexhandle, obj)) < 0) {
01363 smlErrorSet(&error, SML_ERROR_GENERIC,
01364 "The OBEX request cannot be sent. %s (%i).",
01365 strerror(errno), errno);
01366 goto error_free_obj;
01367 }
01368
01369
01370 smlTrace(TRACE_INTERNAL, "%s: Wait for the answer ...", __func__);
01371 while (env->busy) {
01372 int result = OBEX_HandleInput(env->obexhandle, 20);
01373 if (result < 0) {
01374 smlErrorSet(&error, SML_ERROR_GENERIC,
01375 "The answer was not received successfully (%i).",
01376 result);
01377 goto error;
01378 } else if (result == 0 && !env->busy) {
01379 smlErrorSet(&error, SML_ERROR_GENERIC,
01380 "The answer was timed out.");
01381 goto error;
01382 }
01383 }
01384
01385 smlTrace(TRACE_EXIT, "%s", __func__);
01386 return;
01387
01388 error_free_obj:
01389 OBEX_ObjectDelete(env->obexhandle, obj);
01390 error:
01391 smlTransportReceiveEvent(env->tsp, NULL, SML_TRANSPORT_EVENT_ERROR, NULL, error);
01392 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(&error));
01393 return;
01394 }
01395
01396 SmlBool smlTransportObexClientNew(SmlTransport *tsp, SmlError **error)
01397 {
01398 CHECK_ERROR_REF
01399 smlAssert(tsp);
01400
01401 tsp->functions.set_config_option = smlTransportObexClientSetConfigOption;
01402 tsp->functions.set_connection_type = smlTransportObexClientSetConnectionType;
01403 tsp->functions.initialize = smlTransportObexClientInit;
01404 tsp->functions.finalize = smlTransportObexClientFinalize;
01405 tsp->functions.connect = smlTransportObexClientConnect;
01406 tsp->functions.disconnect = smlTransportObexClientDisconnect;
01407 tsp->functions.send = smlTransportObexClientSend;
01408
01409 SmlTransportObexClientEnv *env = smlTryMalloc0(sizeof(SmlTransportObexClientEnv), error);
01410 if (!env)
01411 return FALSE;
01412 tsp->transport_data = env;
01413 env->tsp = tsp;
01414
01415 return TRUE;
01416 }
01417