cedric pushed a commit to branch master.
commit 2f6fcf42287f177587373c0704ee6d5679fca261
Author: Cedric Bail <[email protected]>
Date: Mon Mar 18 00:07:34 2013 +0900
e: add automatic desktop lock/unlock when a bluetooth device disapear.
This use a custom implementation of l2ping to ping known device and do
proper action when they go away. I don't recommend to use the auto unlonck,
but it is there if someone need it.
---
configure.ac | 11 ++-
data/etc/sysactions.conf.in | 1 +
src/bin/Makefile.am | 6 +-
src/bin/e_sys_l2ping.c | 101 +++++++++++++++++++
src/bin/e_sys_main.c | 19 ++++
src/modules/bluez4/e_mod_main.c | 211 +++++++++++++++++++++++++++++++++++-----
src/modules/bluez4/e_mod_main.h | 4 +-
src/modules/bluez4/ebluez4.c | 8 --
8 files changed, 321 insertions(+), 40 deletions(-)
diff --git a/configure.ac b/configure.ac
index 82c0a5b..b3dbcec 100644
--- a/configure.ac
+++ b/configure.ac
@@ -197,9 +197,13 @@ CPPFLAGS="${PCPPFLAGS}"
AC_SUBST(cf_cflags)
AC_SUBST(cf_libs)
-AC_CHECK_HEADERS([bluetooth/bluetooth.h],
- [have_bluetooth_h="yes"],
- [have_bluetooth_h="no"])
+PKG_CHECK_MODULES([BLUEZ], [bluez],
+ [have_bluetooth="yes"],
+ [have_bluetooth="no"])
+AM_CONDITIONAL([HAVE_BLUETOOTH], [test "x${have_bluetooth}"])
+if test "x${have_bluetooth}"; then
+ AC_DEFINE_UNQUOTED([HAVE_BLUETOOTH], [1], [Bluetooth is there])
+fi
execinfo_libs=""
AC_CHECK_HEADERS([execinfo.h], [have_execinfo="yes"], [have_execinfo="no"])
@@ -487,6 +491,7 @@ PKG_CHECK_MODULES(E_FM_OPEN, [
PKG_CHECK_MODULES(E_SYS, [
eina >= ${efl_version}
+ ecore >= ${efl_version}
])
PKG_CHECK_MODULES(E_INIT, [
diff --git a/data/etc/sysactions.conf.in b/data/etc/sysactions.conf.in
index 6054a04..b0dfab5 100644
--- a/data/etc/sysactions.conf.in
+++ b/data/etc/sysactions.conf.in
@@ -51,6 +51,7 @@ action: /bin/mount /bin/mount
action: /bin/umount /bin/umount
action: /usr/bin/eject /usr/bin/eject
action: gdb gdb
+action: l2ping l2ping
# on FreeBSD use this instead of the above.
#action suspend /usr/sbin/zzz
diff --git a/src/bin/Makefile.am b/src/bin/Makefile.am
index fd930ef..dfdb96b 100644
--- a/src/bin/Makefile.am
+++ b/src/bin/Makefile.am
@@ -422,10 +422,10 @@ e_fm_op.c
enlightenment_fm_op_LDADD = @E_FM_OP_LIBS@ -lm
enlightenment_sys_SOURCES = \
-e_sys_main.c
+e_sys_main.c e_sys_l2ping.c
-enlightenment_sys_LDADD = @SUID_LDFLAGS@ @E_SYS_LIBS@
-enlightenment_sys_CFLAGS = @SUID_CFLAGS@ @E_SYS_CFLAGS@
+enlightenment_sys_LDADD = @SUID_LDFLAGS@ @E_SYS_LIBS@ @BLUEZ_LIBS@
+enlightenment_sys_CFLAGS = @SUID_CFLAGS@ @E_SYS_CFLAGS@ @BLUEZ_CFLAGS@
if HAVE_EEZE
enlightenment_backlight_SOURCES = \
diff --git a/src/bin/e_sys_l2ping.c b/src/bin/e_sys_l2ping.c
new file mode 100644
index 0000000..ac826ea
--- /dev/null
+++ b/src/bin/e_sys_l2ping.c
@@ -0,0 +1,101 @@
+#include "config.h"
+
+#include <Ecore.h>
+
+#ifdef HAVE_BLUETOOTH
+#include <unistd.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/l2cap.h>
+#endif
+
+double
+e_sys_l2ping(const char *bluetooth_mac)
+{
+#ifdef HAVE_BLUETOOTH
+ char send_buf[L2CAP_CMD_HDR_SIZE + 1];
+ char recv_buf[L2CAP_CMD_HDR_SIZE + 1];
+ char tmp[18];
+ l2cap_cmd_hdr *send_cmd;
+ l2cap_cmd_hdr *recv_cmd;
+ struct sockaddr_l2 addr;
+ struct timeval tv;
+ socklen_t optlen;
+ fd_set rfds;
+ double start;
+ int fd;
+
+ /* Create socket */
+ fd = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_L2CAP);
+ if (fd < 0) {
+ perror("Can't create socket");
+ return -1;
+ }
+
+ /* Bind to local address */
+ memset(&addr, 0, sizeof(addr));
+ addr.l2_family = AF_BLUETOOTH;
+ bacpy(&addr.l2_bdaddr, BDADDR_ANY);
+
+ if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0)
+ {
+ perror("Can't bind socket");
+ return -1;
+ }
+
+ /* Connect to remote device */
+ memset(&addr, 0, sizeof(addr));
+ addr.l2_family = AF_BLUETOOTH;
+ str2ba(bluetooth_mac, &addr.l2_bdaddr);
+
+ if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0)
+ {
+ perror("Can't connect");
+ return -1;
+ }
+
+ start = ecore_time_get();
+
+ /* Get local address */
+ memset(&addr, 0, sizeof(addr));
+ optlen = sizeof(addr);
+
+ if (getsockname(fd, (struct sockaddr *) &addr, &optlen) < 0)
+ {
+ perror("Can't get local address");
+ return -1;
+ }
+
+ ba2str(&addr.l2_bdaddr, tmp);
+
+ send_cmd = (l2cap_cmd_hdr *) send_buf;
+ send_cmd->ident = 200;
+ send_cmd->len = htobs(1);
+ send_cmd->code = L2CAP_ECHO_REQ;
+ send_buf[L2CAP_CMD_HDR_SIZE] = 'A';
+
+ if (send(fd, send_buf, L2CAP_CMD_HDR_SIZE + 1, 0) <= 0)
+ {
+ perror("Send failed");
+ return -1;
+ }
+
+ if (recv(fd, recv_buf, L2CAP_CMD_HDR_SIZE + 1, 0) < 0)
+ {
+ perror("Recv failed");
+ return -1;
+ }
+
+ recv_cmd = (l2cap_cmd_hdr *) recv_buf;
+ recv_cmd->len = btohs(recv_cmd->len);
+ if (recv_cmd->ident != 200)
+ return -1; /* Wrong packet */
+
+ close(fd);
+
+ return ecore_time_get() - start;
+#else
+ fprintf(stderr, "e_sys_l2ping nop\n");
+ return -1;
+#endif
+}
diff --git a/src/bin/e_sys_main.c b/src/bin/e_sys_main.c
index 747836d..1805706 100644
--- a/src/bin/e_sys_main.c
+++ b/src/bin/e_sys_main.c
@@ -16,6 +16,8 @@
#endif
#include <Eina.h>
+double e_sys_l2ping(const char *bluetooth_mac);
+
/* local subsystem functions */
#ifdef HAVE_EEZE_MOUNT
static Eina_Bool mountopts_check(const char *opts);
@@ -88,6 +90,11 @@ main(int argc,
output = argv[3];
}
+ else if (!strcmp(argv[1], "l2ping"))
+ {
+ action = argv[1];
+ output = argv[2];
+ }
#ifdef HAVE_EEZE_MOUNT
else
{
@@ -173,6 +180,18 @@ main(int argc,
exit(WEXITSTATUS(r));
}
+ else if (!test && !strcmp(action, "l2ping"))
+ {
+ char tmp[128];
+ double latency;
+
+ latency = e_sys_l2ping(output);
+
+ eina_convert_dtoa(latency, tmp);
+ fprintf(stdout, tmp);
+
+ return (latency < 0) ? 1 : 0;
+ }
if ((!test)
#ifdef HAVE_EEZE_MOUNT
&& (!mnt)
diff --git a/src/modules/bluez4/e_mod_main.c b/src/modules/bluez4/e_mod_main.c
index f294ae9..594a3a0 100644
--- a/src/modules/bluez4/e_mod_main.c
+++ b/src/modules/bluez4/e_mod_main.c
@@ -4,6 +4,14 @@
#include "ebluez4.h"
/* Local Variables */
+static Ecore_Exe *autolock_exe = NULL;
+static Ecore_Poller *autolock_poller = NULL;
+static Ecore_Event_Handler *autolock_die = NULL;
+static Ecore_Event_Handler *autolock_out = NULL;
+static Ecore_Event_Handler *autolock_desklock = NULL;
+static Eina_Bool autolock_initted = EINA_FALSE;
+static Eina_Bool autolock_waiting = EINA_TRUE;
+
static Eina_List *instances = NULL;
static E_Module *mod = NULL;
static char tmpbuf[1024];
@@ -15,6 +23,42 @@ Config *ebluez4_config = NULL;
EAPI E_Module_Api e_modapi = {E_MODULE_API_VERSION, "Bluez4"};
/* Local Functions */
+static Eina_Bool
+_ebluez_l2ping_poller(void *data EINA_UNUSED)
+{
+ Eina_Strbuf *buf;
+ const char *tmp = NULL;
+
+ autolock_poller = NULL;
+
+ buf = eina_strbuf_new();
+ if (e_desklock_state_get())
+ {
+ if (!autolock_waiting)
+ tmp = ebluez4_config->unlock_dev_addr;
+ else
+ tmp = ebluez4_config->lock_dev_addr;
+ }
+ else
+ {
+ if (!autolock_waiting)
+ tmp = ebluez4_config->lock_dev_addr;
+ else
+ tmp = ebluez4_config->unlock_dev_addr;
+ }
+
+ if (tmp)
+ {
+ eina_strbuf_append_printf(buf,
"%s/enlightenment/utils/enlightenment_sys l2ping %s",
+ e_prefix_lib_get(), tmp);
+ autolock_exe = ecore_exe_run(eina_strbuf_string_get(buf), NULL);
+ }
+
+ eina_strbuf_free(buf);
+
+ return 0;
+}
+
static void
_ebluez4_search_dialog_del(Instance *inst)
{
@@ -262,9 +306,15 @@ _ebluez4_cb_lock(void *data,
int tog;
tog = e_menu_item_toggle_get(mi);
- eina_stringshare_replace(&ebluez4_config->lock_dev_name,
- tog ? dev->name : NULL);
+ eina_stringshare_replace(&ebluez4_config->lock_dev_addr,
+ tog ? dev->addr : NULL);
e_config_save_queue();
+
+ if (autolock_exe)
+ ecore_exe_kill(autolock_exe);
+ autolock_exe = NULL;
+ if (!autolock_poller && (ebluez4_config->lock_dev_addr ||
ebluez4_config->unlock_dev_addr))
+ autolock_poller = ecore_poller_add(ECORE_POLLER_CORE, 32,
_ebluez_l2ping_poller, NULL);
}
static void
@@ -276,9 +326,15 @@ _ebluez4_cb_unlock(void *data,
int tog;
tog = e_menu_item_toggle_get(mi);
- eina_stringshare_replace(&ebluez4_config->unlock_dev_name,
- tog ? dev->name : NULL);
+ eina_stringshare_replace(&ebluez4_config->unlock_dev_addr,
+ tog ? dev->addr : NULL);
e_config_save_queue();
+
+ if (autolock_exe)
+ ecore_exe_kill(autolock_exe);
+ autolock_exe = NULL;
+ if (!autolock_poller && (ebluez4_config->lock_dev_addr ||
ebluez4_config->unlock_dev_addr))
+ autolock_poller = ecore_poller_add(ECORE_POLLER_CORE, 32,
_ebluez_l2ping_poller, NULL);
}
static void
@@ -348,22 +404,27 @@ _ebluez4_add_devices(Instance *inst)
e_menu_item_label_set(submi, "Forget");
e_menu_item_callback_set(submi, _ebluez4_cb_forget, dev);
- /* Auto lock when away */
- submi = e_menu_item_new(subm);
- e_menu_item_check_set(submi, 1);
- e_menu_item_label_set(submi, "Lock on disconnect");
- e_menu_item_callback_set(submi, _ebluez4_cb_lock, dev);
- chk = ebluez4_config->lock_dev_name && dev->name &&
- !strcmp(dev->name, ebluez4_config->lock_dev_name);
- e_menu_item_toggle_set(submi, !!chk);
-
- submi = e_menu_item_new(subm);
- e_menu_item_check_set(submi, 1);
- e_menu_item_label_set(submi, "Unlock on disconnect");
- e_menu_item_callback_set(submi, _ebluez4_cb_unlock, dev);
- chk = ebluez4_config->unlock_dev_name && dev->name &&
- !strcmp(dev->name, ebluez4_config->unlock_dev_name);
- e_menu_item_toggle_set(submi, !!chk);
+#ifdef HAVE_BLUETOOTH
+ if (autolock_initted)
+ {
+ /* Auto lock when away */
+ submi = e_menu_item_new(subm);
+ e_menu_item_check_set(submi, 1);
+ e_menu_item_label_set(submi, "Lock on disconnect");
+ e_menu_item_callback_set(submi, _ebluez4_cb_lock, dev);
+ chk = ebluez4_config->lock_dev_addr && dev->addr &&
+ !strcmp(dev->addr, ebluez4_config->lock_dev_addr);
+ e_menu_item_toggle_set(submi, !!chk);
+
+ submi = e_menu_item_new(subm);
+ e_menu_item_check_set(submi, 1);
+ e_menu_item_label_set(submi, "Unlock on disconnect");
+ e_menu_item_callback_set(submi, _ebluez4_cb_unlock, dev);
+ chk = ebluez4_config->unlock_dev_addr && dev->addr &&
+ !strcmp(dev->addr, ebluez4_config->unlock_dev_addr);
+ e_menu_item_toggle_set(submi, !!chk);
+ }
+#endif
}
return ret;
@@ -520,10 +581,93 @@ static const E_Gadcon_Client_Class _gc_class =
E_GADCON_CLIENT_STYLE_PLAIN
};
+static Eina_Bool
+_ebluez_exe_die(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void
*event_info)
+{
+ Ecore_Exe_Event_Del *ev = event_info;
+
+ if (ev->exe != autolock_exe)
+ return ECORE_CALLBACK_PASS_ON;
+
+ if (!autolock_initted)
+ {
+ if (ev->exit_code == 0)
+ {
+ autolock_initted = EINA_TRUE;
+ }
+ }
+ else
+ {
+ if (e_desklock_state_get()) // Locked state ?
+ {
+ if (!autolock_waiting)
+ {
+ // Not waiting yet for the auto unlock device to appear
before unlock
+ if (ev->exit_code == 0 && ebluez4_config->unlock_dev_addr)
+ {
+ e_desklock_hide();
+ }
+ }
+ else if (ev->exit_code == 1)
+ {
+ // The device just disapeared, now we can wait for it to
disapear
+ autolock_waiting = EINA_FALSE;
+ }
+ }
+ else
+ {
+ if (!autolock_waiting)
+ {
+ // Not waiting yet for the auto lock device to disappear
before locking
+ if (ev->exit_code == 1 && ebluez4_config->lock_dev_addr)
+ {
+ e_desklock_show(EINA_FALSE);
+ }
+ }
+ else if (ev->exit_code == 0)
+ {
+ // The device just appeared, now we can wait for it to disapear
+ autolock_waiting = EINA_FALSE;
+ }
+ }
+ }
+
+ if (autolock_initted)
+ autolock_poller = ecore_poller_add(ECORE_POLLER_CORE, 32,
_ebluez_l2ping_poller, NULL);
+
+ autolock_exe = NULL;
+
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_ebluez_exe_out(void *data, int ev_type, void *ev)
+{
+ /* FIXME: Need experiment, but we should be able to use latency to somehow
estimate distance, right ? */
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_ebluez_desklock(void *data, int ev_type, void *ev)
+{
+ if (autolock_exe)
+ ecore_exe_kill(autolock_exe);
+ autolock_exe = NULL;
+
+ if (!autolock_poller && autolock_initted && (ebluez4_config->lock_dev_addr
|| ebluez4_config->unlock_dev_addr))
+ autolock_poller = ecore_poller_add(ECORE_POLLER_CORE, 32,
_ebluez_l2ping_poller, NULL);
+
+ autolock_waiting = EINA_TRUE;
+
+ return ECORE_CALLBACK_PASS_ON;
+}
+
/* Module Functions */
EAPI void *
e_modapi_init(E_Module *m)
{
+ Eina_Strbuf *buf;
+
mod = m;
conf_edd = E_CONFIG_DD_NEW("Config", Config);
@@ -531,8 +675,8 @@ e_modapi_init(E_Module *m)
#undef D
#define T Config
#define D conf_edd
- E_CONFIG_VAL(D, T, lock_dev_name, STR);
- E_CONFIG_VAL(D, T, unlock_dev_name, STR);
+ E_CONFIG_VAL(D, T, lock_dev_addr, STR);
+ E_CONFIG_VAL(D, T, unlock_dev_addr, STR);
ebluez4_config = e_config_domain_load("module.ebluez4", conf_edd);
if (!ebluez4_config)
@@ -542,6 +686,16 @@ e_modapi_init(E_Module *m)
e_gadcon_provider_register(&_gc_class);
+ autolock_die = ecore_event_handler_add(ECORE_EXE_EVENT_DEL,
_ebluez_exe_die, NULL);
+ autolock_out = ecore_event_handler_add(ECORE_EXE_EVENT_DATA,
_ebluez_exe_out, NULL);
+ autolock_desklock = ecore_event_handler_add(E_EVENT_DESKLOCK,
_ebluez_desklock, NULL);
+
+ buf = eina_strbuf_new();
+ eina_strbuf_append_printf(buf, "%s/enlightenment/utils/enlightenment_sys -t
l2ping",
+ e_prefix_lib_get());
+ autolock_exe = ecore_exe_run(eina_strbuf_string_get(buf), NULL);
+ eina_strbuf_free(buf);
+
return m;
}
@@ -550,8 +704,17 @@ e_modapi_shutdown(E_Module *m)
{
E_CONFIG_DD_FREE(conf_edd);
- eina_stringshare_del(ebluez4_config->lock_dev_name);
- eina_stringshare_del(ebluez4_config->unlock_dev_name);
+ if (autolock_exe) ecore_exe_kill(autolock_exe);
+ autolock_exe = NULL;
+ if (autolock_poller) ecore_timer_del(autolock_poller);
+ autolock_poller = NULL;
+
+ ecore_event_handler_del(autolock_die);
+ ecore_event_handler_del(autolock_out);
+ ecore_event_handler_del(autolock_desklock);
+
+ eina_stringshare_del(ebluez4_config->lock_dev_addr);
+ eina_stringshare_del(ebluez4_config->unlock_dev_addr);
free(ebluez4_config);
ebluez4_config = NULL;
diff --git a/src/modules/bluez4/e_mod_main.h b/src/modules/bluez4/e_mod_main.h
index c8d713b..dc48b3d 100644
--- a/src/modules/bluez4/e_mod_main.h
+++ b/src/modules/bluez4/e_mod_main.h
@@ -16,8 +16,8 @@ struct _Instance
typedef struct _Config Config;
struct _Config
{
- const char *lock_dev_name;
- const char *unlock_dev_name;
+ const char *lock_dev_addr;
+ const char *unlock_dev_addr;
};
extern Config *ebluez4_config;
diff --git a/src/modules/bluez4/ebluez4.c b/src/modules/bluez4/ebluez4.c
index 2347808..e10ccbe 100644
--- a/src/modules/bluez4/ebluez4.c
+++ b/src/modules/bluez4/ebluez4.c
@@ -385,10 +385,6 @@ _on_removed(void *context, const EDBus_Message *msg)
fdev = eina_list_search_unsorted(ctxt->found_devices, _dev_addr_cmp,
dev->addr);
- if (dev->name && ebluez4_config->lock_dev_name &&
- !strcmp(dev->name, ebluez4_config->lock_dev_name))
- e_desklock_show(EINA_FALSE);
-
_unset_dev(dev, &ctxt->devices);
_unset_dev(fdev, &ctxt->found_devices);
}
@@ -427,10 +423,6 @@ _on_device_found(void *context, const EDBus_Message *msg)
dev->paired = paired;
ctxt->found_devices = eina_list_append(ctxt->found_devices, dev);
- if (dev->name && ebluez4_config->unlock_dev_name &&
- !strcmp(dev->name, ebluez4_config->unlock_dev_name))
- e_desklock_hide();
-
ebluez4_update_instances(ctxt->found_devices);
}
--
------------------------------------------------------------------------------
Everyone hates slow websites. So do we.
Make your web apps faster with AppDynamics
Download AppDynamics Lite for free today:
http://p.sf.net/sfu/appdyn_d2d_mar