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.
This commit is contained in:
Cedric Bail 2013-03-18 00:07:34 +09:00
parent 1a472d475e
commit 2f6fcf4228
8 changed files with 320 additions and 39 deletions

View File

@ -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, [

View File

@ -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

View File

@ -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 = \

101
src/bin/e_sys_l2ping.c Normal file
View File

@ -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
}

View File

@ -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)

View File

@ -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);
#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_name && dev->name &&
!strcmp(dev->name, ebluez4_config->unlock_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_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;

View File

@ -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;

View File

@ -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);
}