bluemon-1.4/0000755000175000017500000000000010526351214011466 5ustar mjj29mjj29bluemon-1.4/bluemon-query.c0000644000175000017500000000703710515164535014453 0ustar mjj29mjj29/* * * 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. * */ #define DBUS_API_SUBJECT_TO_CHANGE #include #include #include #include #include //#define DEBUG int main(int argc, char ** argv) { DBusMessage* msg; DBusMessageIter args; DBusConnection* conn; DBusError err; DBusPendingCall* pending; int ret; dbus_uint32_t level = -1; dbus_bool_t stat = FALSE; char* address = ""; if (2 == argc && NULL != argv[1] && 0 == strncmp("--help", argv[1], 7)) { printf ("Syntax: bluemon-query [
]\n"); return 1; } if (2 == argc && NULL != argv[1]) address = argv[1]; dbus_error_init(&err); conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err); if (dbus_error_is_set(&err)) { fprintf(stderr, "Connection Error (%s)\n", err.message); dbus_error_free(&err); } if (NULL == conn) { exit(1); } msg = dbus_message_new_method_call("cx.ath.matthew.bluemon.server", "/cx/ath/matthew/bluemon/Bluemon", "cx.ath.matthew.bluemon.Bluemon", "Status"); if (NULL == msg) { fprintf(stderr, "Message Null\n"); exit(1); } dbus_message_iter_init_append(msg, &args); dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &address); dbus_connection_send_with_reply (conn, msg, &pending, -1); // -1 is default timeout if (NULL == pending) { fprintf(stderr, "Pending Call Null\n"); exit(1); } dbus_connection_flush(conn); dbus_message_unref(msg); dbus_pending_call_block(pending); msg = dbus_pending_call_steal_reply(pending); if (NULL == msg) { fprintf(stderr, "Reply Null\n"); exit(1); } dbus_pending_call_unref(pending); if (DBUS_MESSAGE_TYPE_ERROR == dbus_message_get_type(msg)) { dbus_message_iter_init(msg, &args); dbus_message_iter_get_basic(&args, &address); fprintf(stderr, "Error querying status: %s\n", address); exit(1); } dbus_message_iter_init(msg, &args); if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_INVALID) { dbus_message_iter_get_basic(&args, &address); dbus_message_iter_next(&args); } if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_INVALID) { dbus_message_iter_get_basic(&args, &stat); dbus_message_iter_next(&args); } if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_INVALID) { dbus_message_iter_get_basic(&args, &level); } if (stat) printf("%s connected with level %d\n", address, level); else if (strncmp(address, "", 1)) printf("nothing connected\n", address); else printf("%s not connected\n", address); dbus_message_unref(msg); dbus_connection_close(conn); } bluemon-1.4/bluetooth-monitor.c0000644000175000017500000005677210526351051015344 0ustar mjj29mjj29/* * * 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. * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DBUS_API_SUBJECT_TO_CHANGE #include #include #include #include #include #define BTCONNECTTIMEOUT 5000 #define DEFAULTTHRESHOLD 200 #define DEFAULTINTERVAL 100 //#define DEBUG #define DBUS_INTROSPECTION_DATA " \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ " struct devstruct; typedef struct devstruct { char* btid; bdaddr_t bdaddr; int dd; int track; bool connected; struct devstruct* next; } btdev_t; btdev_t* btdev_append_new(btdev_t* current, char* btid) { btdev_t* temp; if (NULL == current) { temp = malloc(sizeof(btdev_t)); temp->btid = btid; temp->dd = 0; temp->connected = false; temp->next = NULL; temp->track = -1; return temp; } else { current->next = btdev_append_new(current->next, btid); return current; } } typedef struct { char* config; btdev_t* btdevroot; int threshold; int interval; bool stdout; bool fork; bool verbose; bool authenticate; int uid; int gid; bool disconnecthack; bool linkquality; } arg_t; arg_t opts; arg_t args; DBusConnection* conn = NULL; void message(bool verbose, char* msg, ...); void sendsignal(bool connected, btdev_t* btdev); #define assert(a, b) if(!(a)) real_assert(b) void real_assert (char* msg) { if (0 != errno) { char* errstr = strerror(errno); message(false, "[Assert] failed with errno %d/%s: %s\n", errno, errstr, msg); } else message(false, "[Assert] failed: %s\n", msg); #ifdef DEBUG exit(1); #endif } static int find_conn(int s, int dev_id, long arg) { struct hci_conn_list_req *cl; struct hci_conn_info *ci; int i; if (!(cl = malloc(10 * sizeof(*ci) + sizeof(*cl)))) { perror("Can't allocate memory"); exit(1); } cl->dev_id = dev_id; cl->conn_num = 10; ci = cl->conn_info; if (ioctl(s, HCIGETCONNLIST, (void*)cl)) { perror("Can't get connection list"); exit(1); } for (i=0; i < cl->conn_num; i++, ci++) if (!bacmp((bdaddr_t *)arg, &ci->bdaddr)) { free(cl); return 1; } free(cl); return 0; } // open connection bool btconnect(btdev_t* btdev) { int ptype; uint16_t handle = 0; uint8_t role; bool rval; struct hci_conn_info_req *cr; struct hci_request rq; auth_requested_cp acp; evt_auth_complete arp; evt_encrypt_change erp; set_conn_encrypt_cp ecp; role = 0x01; ptype = HCI_DM1 | HCI_DM3 | HCI_DM5 | HCI_DH1 | HCI_DH3 | HCI_DH5; int dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &(btdev->bdaddr)); if (dev_id < 0) { message(true, "Connecting to: %x:%x:%x:%x:%x:%x\n", btdev->bdaddr.b[5], btdev->bdaddr.b[4], btdev->bdaddr.b[3], btdev->bdaddr.b[2], btdev->bdaddr.b[1], btdev->bdaddr.b[0]); if (hci_create_connection(btdev->dd, &(btdev->bdaddr), htobs(ptype), 0, role, &handle, BTCONNECTTIMEOUT) < 0) { message(true, "Can't create connection\n"); return false; } btdev->connected = true; } else btdev->connected = false; if (0 == handle) { cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info)); bacpy(&cr->bdaddr, &(btdev->bdaddr)); cr->type = ACL_LINK; if (ioctl(btdev->dd, HCIGETCONNINFO, (unsigned long) cr) < 0) { message(true, "Get connection info failed"); return false; } handle = htobs(cr->conn_info->handle); free(cr); } if (opts.authenticate || args.authenticate) { acp.handle = htobs(handle); memset(&rq, 0, sizeof(rq)); rq.ogf = OGF_LINK_CTL; rq.ocf = OCF_AUTH_REQUESTED; rq.cparam = &acp; rq.clen = AUTH_REQUESTED_CP_SIZE; rq.rparam = &arp; rq.rlen = EVT_AUTH_COMPLETE_SIZE; rq.event = EVT_AUTH_COMPLETE; if (hci_send_req(btdev->dd, &rq, 25000) < 0) { #ifdef DEBUG message(true, "Can't authenticate link\n"); #endif return false; } ecp.handle = htobs(handle); ecp.encrypt = 1; memset(&rq, 0, sizeof(rq)); rq.ogf = OGF_LINK_CTL; rq.ocf = OCF_SET_CONN_ENCRYPT; rq.cparam = &ecp; rq.clen = SET_CONN_ENCRYPT_CP_SIZE; rq.rparam = &erp; rq.rlen = EVT_ENCRYPT_CHANGE_SIZE; rq.event = EVT_ENCRYPT_CHANGE; if (hci_send_req(btdev->dd, &rq, 25000) < 0) { #ifdef DEBUG message(true, "Can't encrypt link\n"); #endif return false; } } return true; } // close connection void btdisconnect(btdev_t* btdev) { struct hci_conn_info_req *cr; cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info)); if (!cr) return; bacpy(&cr->bdaddr, &(btdev->bdaddr)); cr->type = ACL_LINK; if (ioctl(btdev->dd, HCIGETCONNINFO, (unsigned long) cr) < 0) { message(false, "Get connection info failed\n"); exit(1); } if (hci_disconnect(btdev->dd, htobs(cr->conn_info->handle), HCI_OE_USER_ENDED_CONNECTION, 100) < 0) message(false, "Disconnect failed\n"); free(cr); } // query link quality int get_link_qual(btdev_t* btdev) { struct hci_conn_info_req *cr; struct hci_request rq; #ifdef OCF_GET_LINK_QUALITY get_link_quality_rp rp; #else read_link_quality_rp rp; #endif uint16_t handle; int qual; // check the quality if (opts.linkquality || args.linkquality) { cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info)); if (!cr) return; bacpy(&cr->bdaddr, &(btdev->bdaddr)); cr->type = ACL_LINK; if (ioctl(btdev->dd, HCIGETCONNINFO, (unsigned long) cr) < 0) { #ifdef DEBUG message(true, "Get connection info failed, trying reconnect\n"); #endif return -1; } handle = htobs(cr->conn_info->handle); memset(&rq, 0, sizeof(rq)); rq.ogf = OGF_STATUS_PARAM; #ifdef OCF_GET_LINK_QUALITY rq.ocf = OCF_GET_LINK_QUALITY; #else rq.ocf = OCF_READ_LINK_QUALITY; #endif rq.cparam = &handle; rq.clen = 2; rq.rparam = &rp; #ifdef OCF_GET_LINK_QUALITY_RP_SIZE rq.rlen = GET_LINK_QUALITY_RP_SIZE; #else rq.rlen = READ_LINK_QUALITY_RP_SIZE; #endif if (hci_send_req(btdev->dd, &rq, 100) < 0) { message(true, "HCI get_link_quality request failed, trying reconnect\n"); free(cr); return -1; } if (rp.status) { #ifdef DEBUG message(true, "HCI get_link_quality cmd failed (0x%2.2X), trying reconnect\n", rp.status); #endif free(cr); return -1; } qual = rp.link_quality; free(cr); return qual; } // just check for connection else { qual = hci_for_each_dev(HCI_UP, find_conn, (long) &(btdev->bdaddr)); return qual < 0 ? qual : 255; } } void readoptions(arg_t args, arg_t* opts) { opts->config = NULL; opts->btdevroot = NULL; opts->threshold = DEFAULTTHRESHOLD; opts->interval = DEFAULTINTERVAL; opts->stdout = false; opts->fork = true; opts->verbose = false; opts->uid = 0; opts->gid = 0; opts->authenticate = false; opts->linkquality = false; } char* progname; void syntax() { printf("Syntax: %s \n", progname); //printf(" -c configfile --config=configfile\n"); printf(" -b aa:bb:cc:dd:ee:ff --btid=aa:bb:cc:dd:ee:ff\n"); printf(" -t threshold --threshold=threshold\n"); printf(" -i interval --interval=interval\n"); printf(" -s --stdout --no-syslog\n"); printf(" -n --no-fork\n"); printf(" -v --verbose\n"); printf(" -V --version\n"); printf(" -d --disconnect-hack\n"); printf(" -q --link-quality\n"); printf(" -a --authenticate\n"); printf(" -h --help\n"); exit(1); } /* * -c --config * -b --btid * -t --threshold * -i --interval * -s --stdout --no-syslog * -n --no-fork * -v --verbose * -a --authenticate * -h --help */ void readargs(int argc, char** argv, arg_t* args) { args->config = NULL; args->btdevroot = NULL; args->threshold = DEFAULTTHRESHOLD; args->interval = DEFAULTINTERVAL; args->stdout = false; args->fork = true; args->verbose = false; args->authenticate = false; args->disconnecthack = false; args->linkquality = false; args->uid = 0; args->gid = 0; int c; static struct option long_opts[] = { {"config", 1, 0, 'c'}, {"btid", 1, 0, 'b'}, {"threshold", 1, 0, 't'}, {"interval", 1, 0, 'i'}, {"stdout", 0, 0, 's'}, {"help", 0, 0, 'h'}, {"no-fork", 0, 0, 'n'}, {"verbose", 0, 0, 'v'}, {"version", 0, 0, 'V'}, {"authenticate", 0, 0, 'a'}, {"no-syslog", 0, 0, 's'}, {"uid", 1, 0, 'u'}, {"gid", 1, 0, 'u'}, {"disconnect-hack", 1, 0, 'd'}, {"link-quality", 1, 0, 'q'} }; int idx = 0; while (-1 != (c = getopt_long(argc, argv, "-c:b:t:i:o:sqhVndvag:u:",long_opts, &idx))) { switch (c) { case 'c': args->config = optarg; break; case 'b': args->btdevroot = btdev_append_new(args->btdevroot, optarg); break; case 't': args->threshold = atoi(optarg); break; case 'i': args->interval = atoi(optarg); break; case 'u': args->uid = atoi(optarg); break; case 'g': args->gid = atoi(optarg); break; case 's': args->stdout = true; break; case 'n': args->fork = false; break; case 'v': args->verbose = true; break; case 'd': args->disconnecthack = true; break; case 'a': args->authenticate = true; break; case 'q': args->linkquality = true; break; case 'V': printf("Bluemon version %s.\n", VERSION); break; case 'h': case ':': case '?': case 1: syntax(); break; } idx = 0; } } int testint(int a, int b, char* errormsg) { if (0 != a) return a; if (0 != b) return b; message(false, "%s\n", errormsg); exit(1); } btdev_t* testdev(btdev_t* a, btdev_t* b, char* errormsg) { if (NULL != a) return a; if (NULL != b) return b; message(false, "%s\n", errormsg); exit(1); } char* testchar(char* a, char* b, char* errormsg) { if (NULL != a) return a; if (NULL != b) return b; message(false, "%s\n", errormsg); exit(1); } // write a message to syslog or stdout depending on setup void message(bool verbose, char* msg, ...) { if (!args.verbose && !opts.verbose && verbose) return; va_list vargs; va_start(vargs, msg); if (args.stdout || opts.stdout) vprintf(msg, vargs); else vsyslog(LOG_NOTICE, msg, vargs); va_end(vargs); } void sighandle(int signum) { btdev_t* btdev; switch (signum) { case SIGINT: case SIGTERM: btdev = testdev(args.btdevroot, opts.btdevroot, "No Devices Specified"); while (NULL != btdev) { if (btdev->connected) { // disconnect bluetooth btdisconnect(btdev); message(true, "Disconnected %s\n", btdev->btid); } if (NULL != conn) sendsignal(false, btdev); hci_close_dev(btdev->dd); btdev_t* temp = btdev->next; free(btdev); btdev = temp; } message(false, "Caught SIGTERM, announcing our demise\n"); if (NULL != conn) dbus_connection_unref(conn); exit(0); case SIGHUP: readoptions(args, &opts); break; } } void writepidfile(void) { FILE* fd; fd = fopen("/var/run/bluemon.pid", "w"); if (NULL != fd) { fprintf(fd, "%d", getpid()); fclose(fd); } else { message(true, "Could not write PID file, quitting\n"); exit(1); } } DBusConnection* register_dbus() { DBusError err; DBusConnection* conn; int ret; dbus_error_init(&err); conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err); if (dbus_error_is_set(&err)) { message(true, "DBUS Connection Error (%s)\n", err.message); dbus_error_free(&err); } if (NULL == conn) { exit(1); } ret = dbus_bus_request_name(conn, "cx.ath.matthew.bluemon.server", DBUS_NAME_FLAG_REPLACE_EXISTING, &err); if (dbus_error_is_set(&err)) { message(true, "DBUS Name Error (%s)\n", err.message); dbus_error_free(&err); } if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) { exit(1); } return conn; } void sendsignal(bool inrange, btdev_t* btdev) { DBusMessage* msg; DBusMessageIter it; dbus_uint32_t serial; if (inrange) msg = dbus_message_new_signal("/cx/ath/matthew/bluemon/Bluemon", "cx.ath.matthew.bluemon.ProximitySignal", "Connect"); else msg = dbus_message_new_signal("/cx/ath/matthew/bluemon/Bluemon", "cx.ath.matthew.bluemon.ProximitySignal", "Disconnect"); if (NULL == msg) { message(true, "DBUS Message Null, ALIEN INVASION\n"); exit(1); } dbus_message_iter_init_append(msg, &it); if (!dbus_message_iter_append_basic(&it, DBUS_TYPE_STRING, &(btdev->btid))) { message(true, "Out Of Memory!"); exit(1); } if (!dbus_connection_send(conn, msg, &serial)) { message(true, "Out Of Memory!"); exit(1); } //dbus_connection_flush(conn); dbus_message_unref(msg); message(true, "Signal sent (%s, %s)\n", inrange?"true":"false", btdev->btid); } void handle_dbus_message(DBusMessage* msg, int threshold) { DBusMessage* reply; DBusMessageIter it; dbus_uint32_t serial, level; dbus_bool_t stat; char* address; if (!dbus_message_iter_init(msg, &it)) { message(true, "Bad parameter count for Status message"); return; } if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&it)) { message(true, "Bad parameter type (%d) for Status message", dbus_message_iter_get_arg_type(&it)); return; } dbus_message_iter_get_basic(&it, &address); message(true, "Handling dbus status query for %d\n", address); reply = dbus_message_new_method_return(msg); if (NULL == reply) { message(true, "Reply is NULL!! You have been eaten by a GRUE!"); return; } dbus_message_iter_init_append(reply, &it); btdev_t* btdev = testdev(args.btdevroot, opts.btdevroot, "No Devices Specified"); for (; NULL != btdev; btdev = btdev->next) { if (0 == strncmp("", address, 1) || 0 == strncasecmp(btdev->btid, address, strlen(btdev->btid))) { if (!dbus_message_iter_append_basic(&it, DBUS_TYPE_STRING, &(btdev->btid))) { message(true, "Out Of Memory! Lock me in the cellar and feed me pins, PINS!!"); dbus_message_unref(reply); return; } if (btdev->track >= threshold) { stat = TRUE; level = btdev->track; } else { stat = FALSE; level = -1; } break; } else { //address = ""; stat = FALSE; level = -1; dbus_message_iter_append_basic(&it, DBUS_TYPE_STRING, &address); } } if (!dbus_message_iter_append_basic(&it, DBUS_TYPE_BOOLEAN, &stat)){ message(true, "Out Of Memory! The bells! the bells!"); dbus_message_unref(reply); return; } if (!dbus_message_iter_append_basic(&it, DBUS_TYPE_UINT32, &level)){ message(true, "Out Of Memory! Every night the steam part of my brain and feed it to their mum!"); dbus_message_unref(reply); return; } if (!dbus_connection_send(conn, reply, &serial)){ message(true, "Out Of Memory! Universe error, redo from start!"); dbus_message_unref(reply); return; } dbus_connection_flush(conn); dbus_message_unref(reply); } void handle_introspection_message(DBusMessage* msg) { DBusMessage* reply; DBusMessageIter it; dbus_uint32_t serial; char* xml = DBUS_INTROSPECTION_DATA; message(true, "Handling dbus introspection query\n"); reply = dbus_message_new_method_return(msg); if (NULL == reply) { message(true, "Reply is NULL!! You have been eaten by a GRUE!"); return; } dbus_message_iter_init_append(reply, &it); if (!dbus_message_iter_append_basic(&it, DBUS_TYPE_STRING, &xml)){ message(true, "Out Of Memory! The bells! the bells!"); dbus_message_unref(reply); return; } if (!dbus_connection_send(conn, reply, &serial)){ message(true, "Out Of Memory! Universe error, redo from start!"); dbus_message_unref(reply); return; } dbus_connection_flush(conn); dbus_message_unref(reply); } int main(int argc, char ** argv) { int dev_id, pid; int track, threshold, interval; char* btid; int ret; int lq = 0; bool run = true; bool foo = false; DBusMessage* msg; DBusMessage* err; dbus_uint32_t serial; progname = argv[0]; readargs(argc, argv, &args); readoptions(args, &opts); // fork if (args.fork && opts.fork) { pid = fork(); if (pid < 0) printf("Cannot fork"); if (pid > 0) exit(0); else { setsid(); chdir("/"); umask(0); } } writepidfile(); // syslog if (!(args.stdout || opts.stdout)) openlog("bluetooth-monitor",0, LOG_DAEMON); message(false, "Bluetooth monitoring system startup, version %s\n", VERSION); // register cleanup code signal(SIGTERM, sighandle); signal(SIGINT, sighandle); signal(SIGHUP, sighandle); conn = register_dbus(); threshold = testint(args.threshold, opts.threshold, "No Link Quality Threshold Specified"); btdev_t* btdev = testdev(args.btdevroot, opts.btdevroot, "No Devices Specified"); for (; NULL != btdev; btdev = btdev->next) { str2ba(btdev->btid, &(btdev->bdaddr)); message(true, "Connecting to address %x:%x:%x:%x:%x:%x\n", btdev->bdaddr.b[5], btdev->bdaddr.b[4], btdev->bdaddr.b[3], btdev->bdaddr.b[2], btdev->bdaddr.b[1], btdev->bdaddr.b[0]); dev_id = hci_get_route(&(btdev->bdaddr)); if (dev_id < 0) { message(false, "Device is not available.\n"); exit(1); } btdev->dd = hci_open_dev(dev_id); if (btdev->dd < 0) { message(false, "HCI device open failed\n"); exit(1); } foo = btconnect(btdev); if (!btdev->connected) message(true, "Using existing connection\n"); if (!foo) lq = -1; message(true, "Monitoring link quality\n"); btdev->track = get_link_qual(btdev); if (btdev->track >= threshold) sendsignal(true, btdev); } // drop privs if ((args.uid || opts.uid) && (args.gid || opts.gid)) setreuid(args.uid?args.uid:opts.uid, args.gid?args.gid:opts.gid); while (run) { threshold = testint(args.threshold, opts.threshold, "No Link Quality Threshold Specified"); interval = testint(args.interval, opts.interval, "No Interval Specified"); btdev_t* btdev = testdev(args.btdevroot, opts.btdevroot, "No Devices Specified"); for (; NULL != btdev; btdev = btdev->next) { // if device disconnects every 54s check before reconnect statement if (args.disconnecthack || opts.disconnecthack) lq = get_link_qual(btdev); if (-1 == lq) btconnect(btdev); lq = get_link_qual(btdev); if (lq >= threshold && btdev->track < threshold) { // good quality, stop the screensaver sendsignal(true, btdev); message(false, "Device %s Connected\n", btdev->btid); } else if (lq < threshold && btdev->track >= threshold) { // bad quality, start the screensaver sendsignal(false, btdev); message(false, "Device %s Disconnected\n", btdev->btid); } btdev->track = lq; } dbus_connection_read_write(conn, interval); while (NULL != (msg = dbus_connection_pop_message(conn))) { if (dbus_message_is_method_call(msg, "cx.ath.matthew.bluemon.Bluemon", "Status")) handle_dbus_message(msg, threshold); else if (dbus_message_is_method_call(msg, "org.freedesktop.DBus.Introspectable", "Introspect")) handle_introspection_message(msg); else if (dbus_message_is_method_call(msg, "org.freedesktop.DBus.Peer", "Ping")) { err = dbus_message_new_method_return (msg); dbus_connection_send(conn, err, &serial); dbus_message_unref(err); } else if (DBUS_MESSAGE_TYPE_METHOD_CALL == dbus_message_get_type(msg)) { err = dbus_message_new_error (msg, "cx.ath.matthew.bluemon.error", "Unknown Method"); dbus_connection_send(conn, err, &serial); dbus_message_unref(err); } dbus_message_unref(msg); } } btdev = testdev(args.btdevroot, opts.btdevroot, "No Devices Specified"); while (NULL != btdev) { if (btdev->connected) { // disconnect bluetooth btdisconnect(btdev); if (NULL != conn) sendsignal(false, btdev); message(true, "Disconnected %s\n", btdev->btid); } hci_close_dev(btdev->dd); btdev_t* temp = btdev->next; free(btdev); btdev = temp; } // disconnect socket if (NULL != conn) dbus_connection_unref(conn); } bluemon-1.4/Makefile0000644000175000017500000000705010526345171013135 0ustar mjj29mjj29LIBRARYPATH ?= /usr/lib LIBS = -L$(LIBRARYPATH) -lbluetooth `pkg-config --libs dbus-1` INCLUDES=`pkg-config --cflags dbus-1` # Where to put stuff on 'make install'? PREFIX ?= $(DESTDIR)/usr SBIN ?= $(PREFIX)/sbin BIN ?= $(PREFIX)/bin MAN ?= $(PREFIX)/share/man DOC ?= $(PREFIX)/share/doc/bluemon CONFIG ?= $(DESTDIR)/etc/bluemon DBUSCONFIG ?= $(DESTDIR)/etc/dbus-1/system.d VERSION = 1.4 DEB_VER = -1 DEB_ARCH ?= $(shell dpkg-architecture -qDEB_BUILD_ARCH) DEB_RELEASE ?= $(shell sh -c '(lsb_release -c || echo unknown) | cut -f2' 2>/dev/null) all: bluemon bluemon-client bluemon-query bluemon.1 bluemon-client.1 bluemon-query.1 bluemon-dbus.7 print-release-name: echo $(DEB_RELEASE) bluemon: bluetooth-monitor.c $(CC) $(CFLAGS) $(INCLUDES) $(LIBS) -DVERSION=\"$(VERSION)\" -o $@ $< bluemon-query: bluemon-query.c $(CC) $(CFLAGS) $(INCLUDES) $(LIBS) -DVERSION=\"$(VERSION)\" -o $@ $< bluemon-client: bluemon-client.c $(CC) $(CFLAGS) $(INCLUDES) $(LIBS) -DVERSION=\"$(VERSION)\" -o $@ $< %.1: %.sgml docbook-to-man $< > $@ %.7: %.sgml docbook-to-man $< > $@ uninstall: rm -f $(CONFIG)/bluemon.conf rm -f $(DOC)/examples/bluemon.conf rm -f $(DOC)/examples/bluemon.init rm -f $(DOC)/README rm -f $(DOC)/bluemon-dbus.xml rm -f $(DOC)/INSTALL rm -f $(DOC)/COPYING rm -f $(DOC)/changelog rm -f $(MAN)/man1/bluemon.1 rm -f $(MAN)/man1/bluemon-query.1 rm -f $(MAN)/man1/bluemon-client.1 rm -f $(MAN)/man7/bluemon-dbus.7 rm -f $(SBIN)/bluemon rm -f $(BIN)/bluemon-query rm -f $(BIN)/bluemon-client install: install-bin install-man install-config install-doc install-examples install-readme install-config: bluemon.default install -d $(CONFIG) install -m 644 $< $(CONFIG)/bluemon.conf install-dbus: bluemon-dbus.conf install -d $(DBUSCONFIG) install -m 644 $< $(DBUSCONFIG)/bluemon.conf install-readme: README install -d $(DOC) install -m 644 README $(DOC)/README install -m 644 bluemon-dbus.xml $(DOC)/bluemon-dbus.xml install -m 644 changelog $(DOC)/changelog install-doc: INSTALL COPYING install -d $(DOC) install -m 644 INSTALL $(DOC)/INSTALL install -m 644 COPYING $(DOC)/COPYING install-examples: bluemon.default bluemon.init install -d $(DOC) install -d $(DOC)/examples install -m 644 bluemon.default $(DOC)/examples/bluemon.conf install -m 644 bluemon.init $(DOC)/examples/bluemon.init install-man: bluemon.1 bluemon-query.1 bluemon-dbus.7 bluemon-client.1 install -d $(MAN) install -d $(MAN)/man1 install -d $(MAN)/man7 install -m 644 bluemon.1 $(MAN)/man1/bluemon.1 install -m 644 bluemon-query.1 $(MAN)/man1/bluemon-query.1 install -m 644 bluemon-client.1 $(MAN)/man1/bluemon-client.1 install -m 644 bluemon-dbus.7 $(MAN)/man7/bluemon-dbus.7 install-bin: bluemon bluemon-query bluemon-client install -d $(BIN) install -d $(SBIN) install ./bluemon $(SBIN)/bluemon install ./bluemon-query $(BIN)/bluemon-query install ./bluemon-client $(BIN)/bluemon-client clean: rm -f bluemon rm -f bluemon-query rm -f bluemon-client rm -f bluemon.1 rm -f bluemon-query.1 rm -f bluemon-client.1 rm -f bluemon-dbus.7 dist-clean: clean rm -f .dist rm -rf bluemon-$(VERSION) rm -f bluemon_$(VERSION).orig.tar.gz dist: .dist .dist: bluemon-query.c bluetooth-monitor.c Makefile bluemon-query.sgml bluemon.sgml README INSTALL COPYING bluemon.default bluemon.init bluemon-client.c bluemon-client.sgml bluemon-dbus.sgml bluemon-dbus.xml bluemon-dbus.conf changelog rm -rf bluemon-$(VERSION) mkdir bluemon-$(VERSION) cp -af $^ bluemon-$(VERSION) touch .dist bluemon-$(VERSION): .dist bluemon-$(VERSION).tar.gz: .dist tar zcf $@ bluemon-$(VERSION) bluemon-1.4/bluemon-query.sgml0000644000175000017500000000720710515164535015172 0ustar mjj29mjj29 manpage.1'. You may view the manual page with: `docbook-to-man manpage.sgml | nroff -man | less'. A typical entry in a Makefile or Makefile.am is: manpage.1: manpage.sgml docbook-to-man $< > $@ The docbook-to-man binary is found in the docbook-to-man package. Please remember that if you create the nroff version in one of the debian/rules file targets (such as build), you will need to include docbook-to-man in your Build-Depends control field. --> Matthew"> Johnson"> November 1, 2005"> 1"> <debian@matthew.ath.cx>"> BLUEMON-QUERY"> Debian"> GNU"> GPL"> ]>
&dhemail;
&dhfirstname; &dhsurname; 2005 &dhusername; &dhdate;
&dhucpackage; &dhsection; &dhpackage; Query the state of and send commands to bluemon(1) &dhpackage; [<address>] DESCRIPTION This manual page documents briefly the &dhpackage; command. &dhpackage; sends queries to the bluemon(1) program over DBUS. QUERIES running &dhpackage; with no arguments will cause it to query for the first connected device. Giving the parameter of a bluetooth ID will query for that ID. It will print the ID and signal strength if connected. SEE ALSO bluemon (1), bluemon-client(1), bluemon-dbus(7). AUTHOR This manual page was written by &dhusername; &dhemail; for the &debian; system (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the &gnu; General Public License, Version 2 any later version published by the Free Software Foundation. On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL.
bluemon-1.4/bluemon.sgml0000644000175000017500000001713410515164535014027 0ustar mjj29mjj29 manpage.1'. You may view the manual page with: `docbook-to-man manpage.sgml | nroff -man | less'. A typical entry in a Makefile or Makefile.am is: manpage.1: manpage.sgml docbook-to-man $< > $@ The docbook-to-man binary is found in the docbook-to-man package. Please remember that if you create the nroff version in one of the debian/rules file targets (such as build), you will need to include docbook-to-man in your Build-Depends control field. --> Matthew"> Johnson"> November 1, 2005"> 1"> <debian@matthew.ath.cx>"> BLUEMON"> Debian"> GNU"> GPL"> ]>
&dhemail;
&dhfirstname; &dhsurname; 2005 &dhusername; &dhdate;
&dhucpackage; &dhsection; &dhpackage; Activate or deactivate programs based on bluetooth link quality &dhpackage; DESCRIPTION This manual page documents briefly the &dhpackage; command. &dhpackage; monitors the quality of the link to a bluetooth device and emits dbus signals when it drops below a given threshold or disconnects. Used with the bluemon-client program, This can be used to perform actions like locking the terminal when you walk away from it. OPTIONS These programs follow the usual &gnu; command line syntax, with long options starting with two dashes (`-'). A summary of options is included below. The check interval, in ms. The link quality threshold, out of 255 The bluetooth ID to monitor (e.g. aa:bb:cc:dd:ee:ff). This parameter may be specified multiple times to monitor multiple devices. Log to stdout rather than syslog Do not become a daemon Enable this if your bluetooth device disconnects regularly while still in range, adds a small delay into noticing device abscence upon disconnect. Enable verbose output Check for link quality to device. Default only checks for presence of connection. Show summary of options. print version. SEE ALSO hcitool (1), bluemon-client(1), bluemon-query(1), bluemon-dbus(7). AUTHOR This manual page was written by &dhusername; &dhemail; for the &debian; system (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the &gnu; General Public License, Version 2 any later version published by the Free Software Foundation. On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL.
bluemon-1.4/README0000644000175000017500000000675010515164535012364 0ustar mjj29mjj29Bluetooth Monitor System ------------------------ This comprises a daemon which monitors the status of a Bluetooth device (such as a mobile phone) and emits DBUS signals when the device gets within a certain threshold distance of the computer, a client program can start and stop programs in response to these signals and a program which can query the status of a device. The device must be paired with your computer. When starting the daemon you specify the Bluetooth address of the device and a threshold; the client you start with the Bluetooth address and programs to run whenever it crosses the threshold. IPC is done over DBUS, so anything which can use DBUS can trap signals from the daemon and query the status (see bluemon-dbus(7)) The XML protocol description file is installed to $PREFIX/usr/share/doc/bluemon/bluemon-dbus.xml Installation ------------ See INSTALL Configuration ------------- There is an example config file and init script in bluemon.default and bluemon.init (these are installed in $PREFIX/usr/share/doc/bluemon/examples/). The config file is just a convenience since all parameters must be passed on the command line. The command line syntax for bluemon, bluemon-client and bluemon-query is documented in the section 1 manpages. Starting Bluemon ---------------- The sample initscript should be copied to the system initscript directory and used to start the program. It uses a config file to read the parameters to pass to the program. The config file is searched for as /etc/default/bluemon, /etc/bluemon.conf or /etc/bluemon/bluemon.conf. If not, use man or --help to decide which parameters you wish to use. A good sample command line is: bluemon -qai 100 -t 210 -b BLUETOOTHADDR as root, and then as a user: bluemon-client -u "UP COMMAND" -d "DOWN COMMAND" -b BLUETOOTHADDR where UP COMMAND is executed when the signal passes the threshold upwards and DOWN COMMAND when it passes the threshold downwards. Running bluemon with no session ------------------------------- If you want to run bluemon as a purely system component, without having a session or a login to run the client program, you can. Simply run the client command from an initscript in the background: start-stop-daemon --start -x /usr/bin/bluemon-client -p /var/run/bluemon-client.pid -b -d / -m -- -u "UP COMMAND" -d "DOWN COMMAND" -b BLUETOOTHADDR and to stop it: start-stop-daemon --stop -x /usr/bin/bluemon-client -p /var/run/bluemon-client.pid you can add a -c parameter to start-stop-daemon to run it as a non-root user. Up/Down Commands ---------------- The Up command is executed when the link quality becomes good. The Down command is executed when the link quality becomes bad. Thresholds ---------- The system works by sampling the signal strength of the Bluetooth connection and then using a user-defined threshold to decide on whether the device is 'in range' or not. Threshold values are in the range 0-255. Higher values indicate a more sensitive system which requires the device to be in close proximity. Lower values are less sensitive and will consider the device to be `in range' even if it is quite a long way away. Features such as doors and walls cut the signal strength such that a threshold of 'in the same room' is easy to achieve. Testing suggests that values of around 210 for the threshold is good. For more detail you can read section 4.1 of my paper on the subject (http://www.matthew.ath.cx/publications/2005-JohnsonSta-hats.pdf) Comments Etc ------------ To Matthew Johnson bluemon-1.4/INSTALL0000644000175000017500000000347410515164535012535 0ustar mjj29mjj29Installation Instructions. ------------------------- See below for installation on debian systems. This package requires docbook-to-man, libbluetooth, dbus plus make and a C compiler. To compile it use `make' To install it use `make install'. The default installation directories are /usr/share, /usr/sbin, /etc/bluemon. To install into /usr/local use `make PREFIX=/usr/local install'. Individual files can be relocated by setting the appropriate make variables: SBIN - binaries ($PREFIX/sbin) BIN - binaries ($PREFIX/bin) MAN - man pages ($PREFIX/share/man) DOC - documentation and examples ($PREFIX/share/doc/bluemon) CONFIG - config file (/etc/bluemon) It can be uninstalled with `make uninstall' with the same make variables set. Starting Bluemon ---------------- The sample initscript should be copied to the system initscript directory and used to start the program. It uses a config file to read the parameters to pass to the program. The config file is searched for as /etc/default/bluemon, /etc/bluemon.conf or /etc/bluemon/bluemon.conf. If not, use man or --help to decide which parameters you wish to use. A good sample command line is: bluemon -qai 100 -t 210 -b BLUETOOTHADDR as root, and then as a user: bluemon-client -u "UP COMMAND" -d "DOWN COMMAND" -b BLUETOOTHADDR where UP COMMAND is executed when the signal passes the threshold upwards and DOWN COMMAND when it passes the threshold downwards. Debian ------ This packages build-depends on docbook-to-man, libbluetooth1-dev, debhelper, devscripts, dbus-1-dev, fakeroot and build-essential. You will need to apply the debian diff first (should be distributed with the sources), then you can build a Debian package with either `make deb' or any of the normal methods of building a deb package (I suggest `debuild -rfakeroot -us -uc') bluemon-1.4/COPYING0000644000175000017500000004313310515164535012533 0ustar mjj29mjj29 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. bluemon-1.4/bluemon.default0000644000175000017500000000167410526342264014512 0ustar mjj29mjj29# # BlueMon sample config file # # Disable bluemon by default, # WARNING: Enabling bluemon can break other bluetooth applications # as it hooks on the bluetooth stack with a fake MAC address. # kbluetoothd is confirmed to stop working if bluemon is enabled. # Taking this in consideration, you can change 'no' to 'yes' below # to enable bluemon. BLUEMON_ENABLE='no' # Bluetooth ID of the device to monitor. # Multiple devices may be separated by spaces. # EG: BLUETOOTHID='aa:bb:cc:dd:ee:ff 00:00:00:00:00:00:00' BLUETOOTHID='aa:bb:cc:dd:ee:ff' # Signal threshold (out of 255) THRESHOLD=200 # Interval in ms to check the signal INTERVAL=100 # Uncomment to enable link-quality checking QUALITY=-q # Uncomment to log to stdout not to syslog # STDOUT=-s # Uncomment to prevent running in daemon mode # NOFORK=-n # Uncomment to enable verbose output # VERBOSE=-v # Uncomment to enable anti-disconnect hack # DISCONNECTHACK=-d bluemon-1.4/bluemon.init0000644000175000017500000000377310526342267014036 0ustar mjj29mjj29#! /bin/sh # # Init script for bluemon # Config in /etc/default/bluemon # PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin DAEMON=/usr/sbin/bluemon NAME=bluemon DESC=bluemon test -x $DAEMON || exit 0 # Include bluemon defaults if available if [ -f /etc/default/$NAME ] ; then . /etc/default/$NAME elif [ -f /etc/$NAME.conf ] ; then . /etc/$NAME.conf elif [ -f /etc/$NAME/$NAME.conf ] ; then . /etc/$NAME/$NAME.conf fi BTIDS="" for i in $BLUETOOTHID; do BTIDS="$BTIDS -b $i" done set -e case "$1" in start) echo -n "Starting $DESC: " if [ "$BLUEMON_ENABLE" != "yes" ]; then echo "disabled in /etc/default/bluemon" exit 0 fi start-stop-daemon --start --quiet --pidfile /var/run/$NAME.pid \ --exec $DAEMON -- -t $THRESHOLD $BTIDS -i $INTERVAL $STDOUT $NOFORK $VERBOSE $DISCONNECTHACK $QUALITY echo "$NAME." ;; stop) echo -n "Stopping $DESC: " start-stop-daemon --stop --quiet --pidfile /var/run/$NAME.pid \ --oknodo --exec $DAEMON echo "$NAME." ;; #reload) # # If the daemon can reload its config files on the fly # for example by sending it SIGHUP, do it here. # # If the daemon responds to changes in its config file # directly anyway, make this a do-nothing entry. # # echo "Reloading $DESC configuration files." # start-stop-daemon --stop --signal 1 --quiet --pidfile \ # /var/run/$NAME.pid --exec $DAEMON #;; restart|force-reload) # # If the "reload" option is implemented, move the "force-reload" # option to the "reload" entry above. If not, "force-reload" is # just the same as "restart". # echo -n "Restarting $DESC: " start-stop-daemon --stop --quiet --pidfile /var/run/$NAME.pid \ --oknodo --exec $DAEMON start-stop-daemon --start --quiet --pidfile \ /var/run/$NAME.pid --exec $DAEMON -- -t $THRESHOLD $BTIDS -i $INTERVAL $STDOUT $NOFORK $DISCONNECTHACK $QUALITY echo "$NAME." ;; *) N=/etc/init.d/$NAME # echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2 echo "Usage: $N {start|stop|restart|force-reload}" >&2 exit 1 ;; esac exit 0 bluemon-1.4/bluemon-client.c0000644000175000017500000002232110515164535014555 0ustar mjj29mjj29/* * * 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. * */ #define DBUS_API_SUBJECT_TO_CHANGE #include #include #include #include #include #include #include #include #include #include #include #include char* progname = NULL; bool verbose = false; void syntax() { printf("Syntax: %s \n", progname); printf(" -u upcmd --upcmd=upcmd\n"); printf(" -d downcmd --downcmd=downcmd\n"); printf(" -b aa:bb:cc:dd:ee:ff --btid=aa:bb:cc:dd:ee:ff\n"); printf(" -v --verbose\n"); printf(" -V --version\n"); printf(" -p --protect\n"); printf(" -h --help\n"); exit(1); } void message(bool verb, char* msg, ...) { if (!verbose && verb) return; va_list vargs; va_start(vargs, msg); vprintf(msg, vargs); va_end(vargs); } #define assert(a, b) if(!(a)) real_assert(b) void real_assert (char* msg) { if (0 != errno) { char* errstr = strerror(errno); message(false, "[Assert] failed with errno %d/%s: %s\n", errno, errstr, msg); } else message(false, "[Assert] failed: %s\n", msg); #ifdef DEBUG exit(1); #endif } void fork_and_run(char* cmd) { pid_t pid; pid = fork(); assert(0 <= pid, "Could not fork"); if (0 == pid) { system(cmd); exit(0); } } uint32_t getConnectionUnixUser(const char* service, DBusConnection* conn) { DBusMessage* msg; DBusMessageIter args; DBusPendingCall* pending; uint32_t uid; char* errmsg; if (NULL == service) return -1; msg = dbus_message_new_method_call("org.freedesktop.DBus", // target for the method call "/org/freedesktop/DBus", // object to call on "org.freedesktop.DBus", // interface to call on "GetConnectionUnixUser"); // method name if (NULL == msg) { message(false, "Message Null\n"); exit(1); } // append arguments dbus_message_iter_init_append(msg, &args); if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &service)) { message(false, "Out Of Memory!\n"); exit(1); } // send message and get a handle for a reply if (!dbus_connection_send_with_reply (conn, msg, &pending, -1)) { // -1 is default timeout message(false, "Out Of Memory!\n"); exit(1); } if (NULL == pending) { message(false, "Pending Call Null\n"); exit(1); } dbus_connection_flush(conn); // free message dbus_message_unref(msg); // block until we recieve a reply dbus_pending_call_block(pending); // get the reply message msg = dbus_pending_call_steal_reply(pending); if (NULL == msg) { message(false, "Reply Null\n"); exit(1); } // free the pending message handle dbus_pending_call_unref(pending); if (DBUS_MESSAGE_TYPE_ERROR == dbus_message_get_type(msg)) { message(false, "Failed to check owner\n"); } // read the parameters else if (!dbus_message_iter_init(msg, &args)) message(false, "Message has no arguments!\n"); else if (DBUS_TYPE_UINT32 != dbus_message_iter_get_arg_type(&args)) message(false, "Argument is not uint32 (is %c)!\n", dbus_message_iter_get_arg_type(&args)); else { dbus_message_iter_get_basic(&args, &uid); dbus_message_unref(msg); return uid; } dbus_message_unref(msg); return -1; } DBusConnection* dbusConnect() { DBusConnection* conn; DBusError err; int ret; // initialise the errors dbus_error_init(&err); // connect to the bus and check for errors conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err); if (dbus_error_is_set(&err)) { message(false, "Connection Error (%s)\n", err.message); dbus_error_free(&err); } if (NULL == conn) { exit(1); } // add a rule for which messages we want to see dbus_bus_add_match(conn, "type='signal',interface='cx.ath.matthew.bluemon.ProximitySignal'", &err); // see signals from the given interface dbus_connection_flush(conn); if (dbus_error_is_set(&err)) { message(false, "Match Error (%s)\n", err.message); exit(1); } return conn; } void spurn_children() { struct sigaction act; act.sa_flags = SA_NOCLDWAIT; act.sa_handler = SIG_IGN; sigaction(SIGCHLD, &act, NULL); } int main(int argc, char ** argv) { DBusMessage* msg; DBusMessageIter args; DBusConnection* conn; char* sigvalue; char* upcmd = NULL; char* downcmd = NULL; char* btid = NULL; char* servicename = NULL; char s[30]; time_t t; bool protect = false; uint32_t uid; spurn_children(); progname = argv[0]; static struct option long_opts[] = { {"help", 0, 0, 'h'}, {"verbose", 0, 0, 'v'}, {"version", 0, 0, 'V'}, {"upcmd", 0, 0, 'u'}, {"downcmd", 0, 0, 'd'}, {"btid", 0, 0, 'b'}, {"protect", 0, 0, 'p'}, }; int c; int idx = 0; while (-1 != (c = getopt_long(argc, argv, "-u:d:b:hVvp",long_opts, &idx))) { switch (c) { case 'u': upcmd = optarg; break; case 'd': downcmd = optarg; break; case 'b': btid = optarg; break; case 'p': protect = true; break; case 'v': verbose = true; break; case 'V': printf("Bluemon client version %s.\n", VERSION); break; case 'h': case ':': case '?': case 1: syntax(); break; } } if (NULL == upcmd || NULL == downcmd || btid == NULL) syntax(); conn = dbusConnect(); // loop listening for signals being emmitted while (true) { // non blocking read of the next available message dbus_connection_read_write(conn, -1); while (NULL != (msg = dbus_connection_pop_message(conn))) { message(true, "Got Message: %s.%s\n", dbus_message_get_interface(msg), dbus_message_get_member(msg)); // check if the message is a signal from the correct interface and with the correct name // and from the correct source on the bus if (dbus_message_is_signal(msg, "cx.ath.matthew.bluemon.ProximitySignal", "Connect")) { if (!protect || 0 == (uid = getConnectionUnixUser(dbus_message_get_sender(msg), conn))) { // read the parameters if (!dbus_message_iter_init(msg, &args)) message(true, "Message Has No Parameters\n"); else if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args)) message(true, "Argument is not string!\n"); else { dbus_message_iter_get_basic(&args, &sigvalue); time(&t); strftime(s, 30, "%H:%M", localtime(&t)); message(true, "[%s] Got Connect Signal for %s\n", s, sigvalue); if (0 == strncasecmp(btid, sigvalue, strlen(btid))) fork_and_run(upcmd); } } else message(true, "Got signal from %d, not root\n", uid); } else if (dbus_message_is_signal(msg, "cx.ath.matthew.bluemon.ProximitySignal", "Disconnect")) { if (!protect || 0 == (uid = getConnectionUnixUser(dbus_message_get_sender(msg), conn))) { // read the parameters if (!dbus_message_iter_init(msg, &args)) message(true, "Message Has No Parameters\n"); else if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args)) message(true, "Argument is not string!\n"); else { dbus_message_iter_get_basic(&args, &sigvalue); time(&t); strftime(s, 30, "%H:%M", localtime(&t)); message(true, "[%s] Got Disconnect Signal for %s\n", s, sigvalue); if (0 == strncasecmp(btid, sigvalue, strlen(btid))) fork_and_run(downcmd); } } else message(true, "Got signal from %d, not root\n", uid); } else message(true, "Spurious message from %s\n", dbus_message_get_sender(msg)); // free the message dbus_message_unref(msg); } } // close the connection dbus_connection_close(conn); } bluemon-1.4/bluemon-client.sgml0000644000175000017500000001434510515164535015304 0ustar mjj29mjj29 manpage.1'. You may view the manual page with: `docbook-to-man manpage.sgml | nroff -man | less'. A typical entry in a Makefile or Makefile.am is: manpage.1: manpage.sgml docbook-to-man $< > $@ The docbook-to-man binary is found in the docbook-to-man package. Please remember that if you create the nroff version in one of the debian/rules file targets (such as build), you will need to include docbook-to-man in your Build-Depends control field. --> Matthew"> Johnson"> November 1, 2005"> 1"> <debian@matthew.ath.cx>"> BLUEMON-CLIENT"> Debian"> GNU"> GPL"> ]>
&dhemail;
&dhfirstname; &dhsurname; 2005 &dhusername; &dhdate;
&dhucpackage; &dhsection; &dhpackage; Activate or deactivate programs based on bluetooth link quality &dhpackage; DESCRIPTION This manual page documents briefly the &dhpackage; command. &dhpackage; listens for events from the bluemon daemon and can start or stop programs when the given device is connected or disconnected. This can be used to perform actions like locking the terminal when you walk away from it. OPTIONS These programs follow the usual &gnu; command line syntax, with long options starting with two dashes (`-'). A summary of options is included below. The command to be run when the device is connected. The command to be run when the device is disconnected. The bluetooth ID to monitor (e.g. aa:bb:cc:dd:ee:ff) Try and protect against spoofing on the DBUS. Requires signals to come from a process owned by the root user. Enable verbose output Show summary of options. Print version SEE ALSO bluemon (1), bluemon-query(1), bluemon-dbus(7). AUTHOR This manual page was written by &dhusername; &dhemail; for the &debian; system (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the &gnu; General Public License, Version 2 any later version published by the Free Software Foundation. On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL.
bluemon-1.4/bluemon-dbus.sgml0000644000175000017500000001054010515164535014754 0ustar mjj29mjj29 manpage.1'. You may view the manual page with: `docbook-to-man manpage.sgml | nroff -man | less'. A typical entry in a Makefile or Makefile.am is: manpage.1: manpage.sgml docbook-to-man $< > $@ The docbook-to-man binary is found in the docbook-to-man package. Please remember that if you create the nroff version in one of the debian/rules file targets (such as build), you will need to include docbook-to-man in your Build-Depends control field. --> Matthew"> Johnson"> November 1, 2005"> 7"> <debian@matthew.ath.cx>"> BLUEMON DBUS INTERFACES"> Debian"> GNU"> GPL"> ]>
&dhemail;
&dhfirstname; &dhsurname; 2005 &dhusername; &dhdate;
&dhucpackage; &dhsection; &dhpackage; DBUS interface to bluemon(1) DESCRIPTION This manual page documents briefly the DBUS interface to bluemon(1) INTERFACE Bluemon exposes 2 signals and 1 method. The bluemon process is registered on the system bus as cx.ath.matthew.bluemon.server. The exposed object is /cx/ath/matthew/bluemon/Bluemon and the exposed interface is cx.ath.matthew.bluemon.Bluemon. The signal interface is cx.ath.matthew.bluemon.ProximitySignal and have the names Connect and Disconnect which both have 1 parameter, which is the string representation of the bluetooth device ID which has been connected or disconnected. The method has the signature Status(IN STRING address, OUT STRING address, OUT BOOLEAN status, OUT UINT32 level). The in parameter may be blank in which case the first connected device will be returned. If status is true (device is connected) then the address and level will correspond to the device address and the reported link quality. Otherwise they will set to the address asked for and -1 respectively. This information is also available as an XML protocol description in /usr/share/doc/bluemon/bluemon-dbus.xml SEE ALSO bluemon (1), bluemon-client(1), bluemon-query(1). AUTHOR This manual page was written by &dhusername; &dhemail; for the &debian; system (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the &gnu; General Public License, Version 2 any later version published by the Free Software Foundation. On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL.
bluemon-1.4/bluemon-dbus.xml0000644000175000017500000000164210515164535014615 0ustar mjj29mjj29 bluemon-1.4/bluemon-dbus.conf0000644000175000017500000000114010515164535014733 0ustar mjj29mjj29 bluemon-1.4/changelog0000644000175000017500000000202710526351074013345 0ustar mjj29mjj29Version 1.4: * Print version numbers * check source address is owned by root. * read all pending messages before blocking again! * some makefile restructuring * dbus_connection_close is deprecated, use dbus_connection_unref Version 1.3: * fix debian bug #348693 - put section 7 manpages in man7 * put config and dbus config in the correct place * put client programs in bin Version 1.2: * Added support for monitoring multiple devices * Added disabling of link quality monitoring for hardware which doesn't support it * Added defaults for threshold and interval Version 1.1: * DBUS integration, removed socket-based communication * Separate client and server binaries, client runs as a user * added fix for regular disconnects * Authentication/Encryption fixed * Threading issues fixed * More docs and updated initscript & config file Version 1.0-1: * Released version 1.0, documentation and build fixes. Version 0.02-1: * Many fixes and upgrades. * Query infrastructure. Version 0.01-1: * Initial Release.