/* MultiSync IrMC Plugin - Synchronize IrMC (mobile) devices Copyright (C) 2002-2003 Bo Lincoln This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS SOFTWARE IS DISCLAIMED. */ /* * $Id: irmc_bluetooth.c,v 1.21 2003/09/09 19:49:03 lincoln Exp $ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "irmc_obex.h" #include "irmc_bluetooth.h" #include #include #include #include #include #include #include extern gboolean multisync_debug; int rfcomm_connect(struct bt_unit *btu, int channel) { struct sockaddr_rc svr_addr, my_addr; int s; bdaddr_t tmp; svr_addr.rc_family = AF_BLUETOOTH; bacpy(&svr_addr.rc_bdaddr, &btu->bdaddr); svr_addr.rc_channel = channel; my_addr.rc_family = AF_BLUETOOTH; my_addr.rc_channel = channel; bacpy(&my_addr.rc_bdaddr, BDADDR_ANY); baswap(&tmp, &btu->bdaddr); dd(printf("Trying to connect on to %s... ", batostr(&tmp))); fflush(stdout); if( (s = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM))==-1 ) { dd(printf("Can't create socket. %s(%d)\n", strerror(errno), errno)); return(-1); } if( !connect(s, (struct sockaddr *) &svr_addr, sizeof(svr_addr)) ){ dd(printf("OK.\n")); } else { dd(printf("Connect failed. %s(%d)\n", strerror(errno), errno)); close(s); return(-1); } return(s); } void plugin_init(void) { } GList *find_bt_units() { GList *unitlist = NULL; inquiry_info ii[10]; int numfound = 0; if (!sdp_general_inquiry(ii, 10, 10000, (uint8_t*)&numfound)) { int t; for (t = 0; t < numfound; t++) { bdaddr_t tmp; int retries = 3; irmc_bt_unit *irbt = g_malloc0(sizeof(irmc_bt_unit)); int dd = hci_open_dev(0); // Open first HCI device sdp_list_t *services = NULL; sdp_list_t *attributes = NULL; sdp_list_t *reclist = NULL; uint16_t len = 0; uuid_t serviceuuid; uint32_t attributeid = 0x0000ffff; sdp_list_t *protodescs = NULL; sdp_session_t *sess = NULL; g_assert(irbt); baswap(&tmp, &ii[t].bdaddr); strncpy(irbt->address, batostr(&tmp), 20); irbt->channel = -1; irbt->name[0] = 0; if (dd >= 0) { hci_read_remote_name(dd, &ii[t].bdaddr, 32, irbt->name, 10000); hci_close_dev(dd); } // Now lookup the RFCOMM channel for IrMC Sync using SDP while (retries-- > 0 && !(sess = sdp_connect(BDADDR_ANY, &ii[t].bdaddr, 0))) sleep(1); if (sess) { sdp_uuid16_create(&serviceuuid, IRMC_SYNC_SVCLASS_ID); services = sdp_list_append(0, &serviceuuid); attributes = sdp_list_append(0, &attributeid); sdp_service_search_attr_req(sess, services, SDP_ATTR_REQ_RANGE, attributes, &reclist); sdp_list_free(services, 0); sdp_list_free(attributes, 0); if (reclist) { sdp_record_t *rec = (sdp_record_t*) reclist->data; sdp_list_t *access = NULL; sdp_get_access_protos(rec, &access); if (access) { irbt->channel = sdp_get_proto_port(access, RFCOMM_UUID); } } sdp_close(sess); } else { dd(printf("Could not connect to device to fetch synchronization information.\nMake sure that the computer and device are 'paired', and try again.")); } unitlist = g_list_append(unitlist, irbt); } } return(unitlist); } gint obex_connect(obex_t *handle, gpointer ud) { obexdata_t *userdata; userdata = (obexdata_t*) ud; userdata->fd = rfcomm_connect(&userdata->btu, userdata->channel); if (userdata->fd < 0) { return(-1); } fcntl(userdata->fd, F_SETFL, O_NONBLOCK); return(0); } gint obex_disconnect(obex_t *handle, gpointer ud) { obexdata_t *userdata; userdata = (obexdata_t*) ud; close(userdata->fd); return(0); } gint obex_listen(obex_t *handle, gpointer ud) { obexdata_t *userdata; userdata = (obexdata_t*) ud; return(0); } gint obex_write(obex_t *handle, gpointer ud, guint8 *buf, gint buflen) { int written = 0; int ret = 0; obexdata_t *userdata; userdata = (obexdata_t*) ud; while (ret >= 0 && written < buflen) { ret=write(userdata->fd,buf+written,buflen-written); if (ret >= 0) written+=ret; } return(written); } gint obex_handleinput(obex_t *handle, gpointer ud, gint timeout) { int n; struct timeval to; fd_set readfds; char buf[2048]; int tot=0; int ret = 0; obexdata_t *userdata; userdata = (obexdata_t*) ud; n = userdata->fd + 1; FD_ZERO(&readfds); FD_SET(userdata->fd, &readfds); to.tv_sec = timeout; to.tv_usec = 0; while (userdata->state >= 0 && (ret = select(n, &readfds, NULL, NULL, &to)) > 0) { if((tot = read(userdata->fd, buf, 2048)) > 0) { OBEX_CustomDataFeed(handle, buf, tot); } else { userdata->state = IRMC_OBEX_REQFAILED; userdata->error = SYNC_MSG_CONNECTIONERROR; } to.tv_sec = timeout; to.tv_usec = 0; } if (userdata->state >= 0 && ret == 0) { userdata->state = IRMC_OBEX_REQFAILED; userdata->error = SYNC_MSG_CONNECTIONERROR; } return(0); } void irmc_strtoba(bdaddr_t *bdaddr,char *str ) { baswap(bdaddr, strtoba(str)); } char *irmc_batostr(bdaddr_t *bdaddr) { bdaddr_t tmp; baswap(&tmp, bdaddr); return(batostr(&tmp)); }