* [Bluez-devel] [PATCH] Split agents
@ 2008-02-01 17:44 Bastien Nocera
2008-02-06 13:46 ` Bastien Nocera
0 siblings, 1 reply; 6+ messages in thread
From: Bastien Nocera @ 2008-02-01 17:44 UTC (permalink / raw)
To: BlueZ Hackers
[-- Attachment #1: Type: text/plain, Size: 156 bytes --]
Heya,
First draft patch to split the agents away from the main program. Seems
to work fine for me.
This is mostly moving functions around though.
Cheers
[-- Attachment #2: bluez-gnome-split-agents.patch --]
[-- Type: text/x-patch, Size: 55280 bytes --]
Index: Makefile.am
===================================================================
RCS file: /cvsroot/bluez/gnome/applet/Makefile.am,v
retrieving revision 1.21
diff -u -p -r1.21 Makefile.am
--- Makefile.am 28 Jul 2007 23:57:16 -0000 1.21
+++ Makefile.am 1 Feb 2008 17:40:38 -0000
@@ -1,7 +1,7 @@
bin_PROGRAMS = bluetooth-applet
-bluetooth_applet_SOURCES = main.c
+bluetooth_applet_SOURCES = main.c main.h agents.c agents.h
bluetooth_applet_LDADD = \
@NOTIFY_LIBS@ @GCONF_LIBS@ \
Index: main.c
===================================================================
RCS file: /cvsroot/bluez/gnome/applet/main.c,v
retrieving revision 1.98
diff -u -p -r1.98 main.c
--- main.c 1 Feb 2008 15:54:58 -0000 1.98
+++ main.c 1 Feb 2008 17:40:38 -0000
@@ -47,16 +47,14 @@
#include "bluetooth-instance.h"
#include "bluetooth-device-selection.h"
+#include "agents.h"
+#include "main.h"
-static gboolean singleton = FALSE;
-
-#define PASSKEY_AGENT_PATH "/org/bluez/passkey"
-#define AUTH_AGENT_PATH "/org/bluez/auth"
+/* Shared variables */
+DBusGConnection *conn = NULL;
+GtkStatusIcon *statusicon = NULL;
-static int volatile registered_passkey = 0;
-static int volatile registered_auth = 0;
-
-static DBusGConnection *conn;
+static gboolean singleton = FALSE;
#ifdef HAVE_HAL
static gboolean use_hal = FALSE;
@@ -78,8 +76,6 @@ typedef enum {
static int icon_policy = ICON_POLICY_PRESENT;
-static gboolean auto_authorize = FALSE;
-
#define PREF_DIR "/apps/bluetooth-manager"
#define PREF_USE_HAL PREF_DIR "/use_hal"
#define PREF_ICON_POLICY PREF_DIR "/icon_policy"
@@ -87,565 +83,16 @@ static gboolean auto_authorize = FALSE;
static GConfClient* gconf;
-static GtkStatusIcon *statusicon = NULL;
-
static GtkWidget *menuitem_browse = NULL;
-typedef enum {
- AGENT_ERROR_REJECT
-} AgentError;
-
-#define AGENT_ERROR (agent_error_quark())
-
-#define AGENT_ERROR_TYPE (agent_error_get_type())
-
-static GQuark agent_error_quark(void)
-{
- static GQuark quark = 0;
- if (!quark)
- quark = g_quark_from_static_string("agent");
-
- return quark;
-}
-
-#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
-
-static GType agent_error_get_type(void)
-{
- static GType etype = 0;
- if (etype == 0) {
- static const GEnumValue values[] = {
- ENUM_ENTRY(AGENT_ERROR_REJECT, "Rejected"),
- { 0, 0, 0 }
- };
-
- etype = g_enum_register_static("agent", values);
- }
-
- return etype;
-}
-
-static GList *input_list = NULL;
-
-struct input_data {
- char *path;
- char *address;
- char *service;
- char *uuid;
- DBusGMethodInvocation *context;
- GtkWidget *dialog;
- GtkWidget *button;
- GtkWidget *entry;
-};
-
-static gint input_compare(gconstpointer a, gconstpointer b)
-{
- struct input_data *a_data = (struct input_data *) a;
- struct input_data *b_data = (struct input_data *) b;
-
- return strcmp(a_data->address, b_data->address);
-}
-
-static void input_free(struct input_data *input)
-{
- gtk_widget_destroy(input->dialog);
-
- input_list = g_list_remove(input_list, input);
-
- g_free(input->uuid);
- g_free(input->service);
- g_free(input->address);
- g_free(input->path);
- g_free(input);
-
- if (g_list_length(input_list) == 0)
- gtk_status_icon_set_blinking(statusicon, FALSE);
-}
-
-static void passkey_callback(GtkWidget *dialog,
- gint response, gpointer user_data)
-{
- struct input_data *input = user_data;
-
- if (response == GTK_RESPONSE_ACCEPT) {
- const char *passkey;
- passkey = gtk_entry_get_text(GTK_ENTRY(input->entry));
- dbus_g_method_return(input->context, passkey);
- } else {
- GError *error;
- error = g_error_new(AGENT_ERROR, AGENT_ERROR_REJECT,
- "Pairing request rejected");
- dbus_g_method_return_error(input->context, error);
- }
-
- input_free(input);
-}
-
-static void confirm_callback(GtkWidget *dialog,
- gint response, gpointer user_data)
-{
- struct input_data *input = user_data;
-
- if (response != GTK_RESPONSE_YES) {
- GError *error;
- error = g_error_new(AGENT_ERROR, AGENT_ERROR_REJECT,
- "Confirmation request rejected");
- dbus_g_method_return_error(input->context, error);
- } else
- dbus_g_method_return(input->context);
-
- input_free(input);
-}
-
-static void set_trusted(struct input_data *input)
-{
- DBusGProxy *object;
- gboolean active;
-
- active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(input->button));
- if (active == FALSE)
- return;
-
- object = dbus_g_proxy_new_for_name(conn, "org.bluez",
- input->path, "org.bluez.Adapter");
-
- dbus_g_proxy_call(object, "SetTrusted", NULL,
- G_TYPE_STRING, input->address, G_TYPE_INVALID,
- G_TYPE_INVALID);
-}
-
-static void auth_callback(GtkWidget *dialog,
- gint response, gpointer user_data)
-{
- struct input_data *input = user_data;
-
- if (response == GTK_RESPONSE_YES) {
- set_trusted(input);
- dbus_g_method_return(input->context);
- } else {
- GError *error;
- error = g_error_new(AGENT_ERROR, AGENT_ERROR_REJECT,
- "Authorization request rejected");
- dbus_g_method_return_error(input->context, error);
- }
-
- input_free(input);
-}
-
-static void changed_callback(GtkWidget *editable, gpointer user_data)
-{
- struct input_data *input = user_data;
- const gchar *text;
-
- text = gtk_entry_get_text(GTK_ENTRY(input->entry));
-
- gtk_widget_set_sensitive(input->button, strlen(text) ? TRUE : FALSE);
-}
-
-static void toggled_callback(GtkWidget *button, gpointer user_data)
-{
- struct input_data *input = user_data;
- gboolean mode;
-
- mode = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
-
- gtk_entry_set_visibility(GTK_ENTRY(input->entry), mode);
-}
-
-static void passkey_dialog(const char *path, const char *address,
- const gchar *device, DBusGMethodInvocation *context)
-{
- GtkWidget *dialog;
- GtkWidget *button;
- GtkWidget *image;
- GtkWidget *label;
- GtkWidget *entry;
- GtkWidget *table;
- GtkWidget *vbox;
- struct input_data *input;
- gchar *markup;
-
- input = g_try_malloc0(sizeof(*input));
- if (!input)
- return;
-
- input->path = g_strdup(path);
- input->address = g_strdup(address);
-
- input->context = context;
-
- dialog = gtk_dialog_new();
-
- gtk_window_set_title(GTK_WINDOW(dialog), _("Authentication request"));
-
- gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
-
- gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
-
- gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE);
-
- gtk_window_set_urgency_hint(GTK_WINDOW(dialog), TRUE);
-
- gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
-
- input->dialog = dialog;
-
- button = gtk_dialog_add_button(GTK_DIALOG(dialog),
- GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT);
-
- button = gtk_dialog_add_button(GTK_DIALOG(dialog),
- GTK_STOCK_OK, GTK_RESPONSE_ACCEPT);
-
- gtk_widget_grab_default(button);
-
- gtk_widget_set_sensitive(button, FALSE);
-
- input->button = button;
-
- table = gtk_table_new(5, 2, FALSE);
-
- gtk_table_set_row_spacings(GTK_TABLE(table), 4);
- gtk_table_set_col_spacings(GTK_TABLE(table), 20);
-
- gtk_container_set_border_width(GTK_CONTAINER(table), 12);
-
- gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table);
-
- image = gtk_image_new_from_icon_name(GTK_STOCK_DIALOG_AUTHENTICATION,
- GTK_ICON_SIZE_DIALOG);
-
- gtk_misc_set_alignment(GTK_MISC(image), 0.0, 0.0);
-
- gtk_table_attach(GTK_TABLE(table), image, 0, 1, 0, 5,
- GTK_SHRINK, GTK_FILL, 0, 0);
-
- vbox = gtk_vbox_new(FALSE, 6);
-
- label = gtk_label_new(_("Pairing request for device:"));
-
- gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
-
- gtk_container_add(GTK_CONTAINER(vbox), label);
-
- gtk_table_attach(GTK_TABLE(table), vbox, 1, 2, 0, 1,
- GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0);
-
- label = gtk_label_new(NULL);
-
- markup = g_strdup_printf("<b>%s</b>", device);
- gtk_label_set_markup(GTK_LABEL(label), markup);
- g_free(markup);
-
- gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
-
- gtk_label_set_selectable(GTK_LABEL(label), TRUE);
-
- gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
-
- gtk_widget_set_size_request(GTK_WIDGET(label), 280, -1);
-
- gtk_container_add(GTK_CONTAINER(vbox), label);
-
- vbox = gtk_vbox_new(FALSE, 6);
-
- label = gtk_label_new(_("Enter passkey for authentication:"));
-
- gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
-
- gtk_container_add(GTK_CONTAINER(vbox), label);
-
- gtk_table_attach(GTK_TABLE(table), vbox, 1, 2, 2, 3,
- GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0);
-
- entry = gtk_entry_new();
-
- gtk_entry_set_max_length(GTK_ENTRY(entry), 16);
-
- gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
-
- gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
-
- input->entry = entry;
-
- g_signal_connect(G_OBJECT(entry), "changed",
- G_CALLBACK(changed_callback), input);
-
- gtk_container_add(GTK_CONTAINER(vbox), entry);
-
- button = gtk_check_button_new_with_label(_("Show input"));
-
- g_signal_connect(G_OBJECT(button), "toggled",
- G_CALLBACK(toggled_callback), input);
-
- gtk_container_add(GTK_CONTAINER(vbox), button);
-
- input_list = g_list_append(input_list, input);
-
- g_signal_connect(G_OBJECT(dialog), "response",
- G_CALLBACK(passkey_callback), input);
-
- gtk_status_icon_set_blinking(statusicon, TRUE);
-}
-
-static void confirm_dialog(const char *path, const char *address,
- const char *value, const gchar *device,
- DBusGMethodInvocation *context)
-{
- GtkWidget *dialog;
- GtkWidget *button;
- GtkWidget *image;
- GtkWidget *label;
- GtkWidget *table;
- GtkWidget *vbox;
- gchar *markup;
- struct input_data *input;
-
- input = g_try_malloc0(sizeof(*input));
- if (!input)
- return;
-
- input->path = g_strdup(path);
- input->address = g_strdup(address);
-
- input->context = context;
-
- dialog = gtk_dialog_new();
-
- gtk_window_set_title(GTK_WINDOW(dialog), _("Confirmation request"));
-
- gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
-
- gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
-
- gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE);
-
- gtk_window_set_urgency_hint(GTK_WINDOW(dialog), TRUE);
-
- gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
-
- input->dialog = dialog;
-
- button = gtk_dialog_add_button(GTK_DIALOG(dialog),
- GTK_STOCK_NO, GTK_RESPONSE_NO);
-
- button = gtk_dialog_add_button(GTK_DIALOG(dialog),
- GTK_STOCK_YES, GTK_RESPONSE_YES);
-
- table = gtk_table_new(5, 2, FALSE);
-
- gtk_table_set_row_spacings(GTK_TABLE(table), 4);
- gtk_table_set_col_spacings(GTK_TABLE(table), 20);
-
- gtk_container_set_border_width(GTK_CONTAINER(table), 12);
-
- gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table);
-
- image = gtk_image_new_from_icon_name(GTK_STOCK_DIALOG_AUTHENTICATION,
- GTK_ICON_SIZE_DIALOG);
-
- gtk_misc_set_alignment(GTK_MISC(image), 0.0, 0.0);
-
- gtk_table_attach(GTK_TABLE(table), image, 0, 1, 0, 5,
- GTK_SHRINK, GTK_FILL, 0, 0);
-
- vbox = gtk_vbox_new(FALSE, 6);
- label = gtk_label_new(_("Pairing request for device:"));
-
- gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
-
- gtk_container_add(GTK_CONTAINER(vbox), label);
-
- gtk_table_attach(GTK_TABLE(table), vbox, 1, 2, 0, 1,
- GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0);
-
- label = gtk_label_new(NULL);
-
- markup = g_strdup_printf("<b>%s</b>", device);
- gtk_label_set_markup(GTK_LABEL(label), markup);
- g_free(markup);
-
- gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
-
- gtk_label_set_selectable(GTK_LABEL(label), TRUE);
-
- gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
-
- gtk_widget_set_size_request(GTK_WIDGET(label), 280, -1);
-
- gtk_container_add(GTK_CONTAINER(vbox), label);
-
- vbox = gtk_vbox_new(FALSE, 6);
-
- label = gtk_label_new(_("Confirm value for authentication:"));
-
- gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
-
- gtk_container_add(GTK_CONTAINER(vbox), label);
-
- gtk_table_attach(GTK_TABLE(table), vbox, 1, 2, 2, 3,
- GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0);
-
- label = gtk_label_new(NULL);
-
- markup = g_strdup_printf("<b>%s</b>\n", value);
-
- gtk_label_set_markup(GTK_LABEL(label), markup);
-
- g_free(markup);
-
- gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
-
- gtk_container_add(GTK_CONTAINER(vbox), label);
-
- input_list = g_list_append(input_list, input);
-
- g_signal_connect(G_OBJECT(dialog), "response",
- G_CALLBACK(confirm_callback), input);
-
- gtk_status_icon_set_blinking(statusicon, TRUE);
-}
-
-static void auth_dialog(const char *path, const char *address,
- const char *service, const char *uuid, const gchar *device,
- const gchar *profile, DBusGMethodInvocation *context)
-{
- GtkWidget *dialog;
- GtkWidget *button;
- GtkWidget *image;
- GtkWidget *label;
- GtkWidget *table;
- GtkWidget *vbox;
- gchar *markup, *text;
- struct input_data *input;
-
- input = g_try_malloc0(sizeof(*input));
- if (!input)
- return;
-
- input->path = g_strdup(path);
- input->address = g_strdup(address);
- input->service = g_strdup(service);
- input->uuid = g_strdup(uuid);
-
- input->context = context;
-
- dialog = gtk_dialog_new();
-
- gtk_window_set_title(GTK_WINDOW(dialog), _("Authorization request"));
-
- gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
-
- gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
-
- gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE);
-
- gtk_window_set_urgency_hint(GTK_WINDOW(dialog), TRUE);
-
- gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
-
- input->dialog = dialog;
-
- button = gtk_dialog_add_button(GTK_DIALOG(dialog),
- GTK_STOCK_NO, GTK_RESPONSE_NO);
-
- button = gtk_dialog_add_button(GTK_DIALOG(dialog),
- GTK_STOCK_YES, GTK_RESPONSE_YES);
-
- table = gtk_table_new(5, 2, FALSE);
-
- gtk_table_set_row_spacings(GTK_TABLE(table), 4);
- gtk_table_set_col_spacings(GTK_TABLE(table), 20);
-
- gtk_container_set_border_width(GTK_CONTAINER(table), 12);
-
- gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table);
-
- image = gtk_image_new_from_icon_name(GTK_STOCK_DIALOG_AUTHENTICATION,
- GTK_ICON_SIZE_DIALOG);
-
- gtk_misc_set_alignment(GTK_MISC(image), 0.0, 0.0);
-
- gtk_table_attach(GTK_TABLE(table), image, 0, 1, 0, 5,
- GTK_SHRINK, GTK_FILL, 0, 0);
-
- vbox = gtk_vbox_new(FALSE, 6);
-
- label = gtk_label_new(_("Authorization request for device:"));
-
- gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
-
- gtk_table_attach(GTK_TABLE(table), label, 1, 2, 0, 1,
- GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0);
-
- label = gtk_label_new(NULL);
-
- markup = g_strdup_printf("<b>%s</b>", device);
- gtk_label_set_markup(GTK_LABEL(label), markup);
- g_free(markup);
-
- gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
-
- gtk_label_set_selectable(GTK_LABEL(label), TRUE);
-
- gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
-
- gtk_widget_set_size_request(GTK_WIDGET(label), 280, -1);
-
- gtk_container_add(GTK_CONTAINER(vbox), label);
-
- gtk_table_attach(GTK_TABLE(table), vbox, 1, 2, 2, 3,
- GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0);
-
- label = gtk_label_new(NULL);
-
- /* translators: Whether to grant access to a particular service
- * to the device mentioned */
- markup = g_strdup_printf("<i>%s</i>", profile);
- text = g_strdup_printf(_("Grant access to %s?"), markup);
- g_free(markup);
-
- markup = g_strdup_printf("%s\n", text);
- gtk_label_set_markup(GTK_LABEL(label), markup);
- g_free(markup);
-
- g_free(text);
-
- gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
-
- gtk_container_add(GTK_CONTAINER(vbox), label);
-
- button = gtk_check_button_new_with_label(_("Always grant access"));
-
- input->button = button;
-
- gtk_container_add(GTK_CONTAINER(vbox), button);
-
- input_list = g_list_append(input_list, input);
-
- g_signal_connect(G_OBJECT(dialog), "response",
- G_CALLBACK(auth_callback), input);
-
- gtk_status_icon_set_blinking(statusicon, TRUE);
-}
-
-static void show_dialog(gpointer data, gpointer user_data)
-{
- struct input_data *input = data;
-
- gtk_widget_show_all(input->dialog);
-
- gtk_window_present(GTK_WINDOW(input->dialog));
-}
-
static NotifyNotification *notify = NULL;
static void notify_action(NotifyNotification *notify,
gchar *action, gpointer user_data)
{
}
-
-static void show_notification(const gchar *summary, const gchar *message,
- const gchar *action, gint timeout, GCallback handler)
+void show_notification(const gchar *summary, const gchar *message,
+ const gchar *action, gint timeout, GCallback handler)
{
NotifyActionCallback callback;
GdkScreen *screen;
@@ -683,7 +130,7 @@ static void show_notification(const gcha
notify_notification_show(notify, NULL);
}
-static void close_notification(void)
+void close_notification(void)
{
if (notify) {
g_signal_handlers_destroy(notify);
@@ -692,378 +139,6 @@ static void close_notification(void)
}
}
-typedef struct {
- GObject parent;
-} PasskeyAgent;
-
-typedef struct {
- GObjectClass parent;
-} PasskeyAgentClass;
-
-static GObjectClass *passkey_agent_parent;
-
-G_DEFINE_TYPE(PasskeyAgent, passkey_agent, G_TYPE_OBJECT)
-
-#define PASSKEY_AGENT_OBJECT_TYPE (passkey_agent_get_type())
-
-#define PASSKEY_AGENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
- PASSKEY_AGENT_OBJECT_TYPE, PasskeyAgent))
-
-static void passkey_agent_finalize(GObject *obj)
-{
- passkey_agent_parent->finalize(obj);
-}
-
-static void passkey_agent_init(PasskeyAgent *obj)
-{
-}
-
-static void passkey_agent_class_init(PasskeyAgentClass *klass)
-{
- GObjectClass *gobject_class;
-
- passkey_agent_parent = g_type_class_peek_parent(klass);
-
- gobject_class = G_OBJECT_CLASS(klass);
- gobject_class->finalize = passkey_agent_finalize;
-}
-
-static PasskeyAgent *passkey_agent_new(const char *path)
-{
- PasskeyAgent *agent;
-
- agent = g_object_new(PASSKEY_AGENT_OBJECT_TYPE, NULL);
-
- dbus_g_connection_register_g_object(conn, path, G_OBJECT(agent));
-
- return agent;
-}
-
-static void notification_closed(GObject *object, gpointer user_data)
-{
- g_list_foreach(input_list, show_dialog, NULL);
-
- gtk_status_icon_set_blinking(statusicon, FALSE);
-}
-
-static gboolean passkey_agent_request(PasskeyAgent *agent,
- const char *path, const char *address,
- DBusGMethodInvocation *context)
-{
- DBusGProxy *object;
- const char *adapter = NULL, *name = NULL;
- gchar *device, *line;
-
- object = dbus_g_proxy_new_for_name(conn, "org.bluez",
- path, "org.bluez.Adapter");
-
- dbus_g_proxy_call(object, "GetName", NULL, G_TYPE_INVALID,
- G_TYPE_STRING, &adapter, G_TYPE_INVALID);
-
- dbus_g_proxy_call(object, "GetRemoteName", NULL,
- G_TYPE_STRING, address, G_TYPE_INVALID,
- G_TYPE_STRING, &name, G_TYPE_INVALID);
-
- if (name) {
- if (g_strrstr(name, address))
- device = g_strdup(name);
- else
- device = g_strdup_printf("%s (%s)", name, address);
- } else
- device = g_strdup(address);
-
- passkey_dialog(path, address, device, context);
-
- /* translators: this is a popup telling you a particular device
- * has asked for pairing */
- line = g_strdup_printf(_("Pairing request for '%s'"), device);
- g_free(device);
-
- show_notification(adapter ? adapter : _("Bluetooth device"),
- line, _("Enter passkey"), 0,
- G_CALLBACK(notification_closed));
-
- g_free(line);
-
- return TRUE;
-}
-
-static gboolean passkey_agent_confirm(PasskeyAgent *agent,
- const char *path, const char *address,
- const char *value, DBusGMethodInvocation *context)
-{
- DBusGProxy *object;
- const char *adapter = NULL, *name = NULL;
- gchar *device, *line;
-
- object = dbus_g_proxy_new_for_name(conn, "org.bluez",
- path, "org.bluez.Adapter");
-
- dbus_g_proxy_call(object, "GetName", NULL, G_TYPE_INVALID,
- G_TYPE_STRING, &adapter, G_TYPE_INVALID);
-
- dbus_g_proxy_call(object, "GetRemoteName", NULL,
- G_TYPE_STRING, address, G_TYPE_INVALID,
- G_TYPE_STRING, &name, G_TYPE_INVALID);
-
- if (name) {
- if (g_strrstr(name, address))
- device = g_strdup(name);
- else
- device = g_strdup_printf("%s (%s)", name, address);
- } else
- device = g_strdup(address);
-
- confirm_dialog(path, address, value, device, context);
-
- line = g_strdup_printf(_("Pairing request for '%s'"), device);
- g_free(device);
-
- show_notification(adapter ? adapter : _("Bluetooth device"),
- line, _("Confirm pairing"), 0,
- G_CALLBACK(notification_closed));
-
- g_free (line);
-
- return TRUE;
-}
-
-static gboolean passkey_agent_cancel(PasskeyAgent *agent,
- const char *path, const char *address, GError **error)
-{
- GList *list;
- GError *result;
- struct input_data *input;
-
- input = g_try_malloc0(sizeof(*input));
- if (!input)
- return FALSE;
-
- input->path = g_strdup(path);
- input->address = g_strdup(address);
-
- list = g_list_find_custom(input_list, input, input_compare);
-
- g_free(input->address);
- g_free(input->path);
- g_free(input);
-
- if (!list || !list->data)
- return FALSE;
-
- input = list->data;
-
- close_notification();
-
- result = g_error_new(AGENT_ERROR, AGENT_ERROR_REJECT,
- "Agent callback canceled");
-
- dbus_g_method_return_error(input->context, result);
-
- input_free(input);
-
- return TRUE;
-}
-
-static gboolean passkey_agent_release(PasskeyAgent *agent, GError **error)
-{
- registered_passkey = 0;
-
- return TRUE;
-}
-
-#include "passkey-agent-glue.h"
-
-typedef struct {
- GObject parent;
-} AuthAgent;
-
-typedef struct {
- GObjectClass parent;
-} AuthAgentClass;
-
-static GObjectClass *auth_agent_parent;
-
-G_DEFINE_TYPE(AuthAgent, auth_agent, G_TYPE_OBJECT)
-
-#define AUTH_AGENT_OBJECT_TYPE (auth_agent_get_type())
-
-#define AUTH_AGENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
- AUTH_AGENT_OBJECT_TYPE, AuthAgent))
-
-static void auth_agent_finalize(GObject *obj)
-{
- auth_agent_parent->finalize(obj);
-}
-
-static void auth_agent_init(AuthAgent *obj)
-{
-}
-
-static void auth_agent_class_init(AuthAgentClass *klass)
-{
- GObjectClass *gobject_class;
-
- auth_agent_parent = g_type_class_peek_parent(klass);
-
- gobject_class = G_OBJECT_CLASS(klass);
- gobject_class->finalize = auth_agent_finalize;
-}
-
-static AuthAgent *auth_agent_new(const char *path)
-{
- AuthAgent *agent;
-
- agent = g_object_new(AUTH_AGENT_OBJECT_TYPE, NULL);
-
- dbus_g_connection_register_g_object(conn, path, G_OBJECT(agent));
-
- return agent;
-}
-
-static gboolean auth_agent_authorize(PasskeyAgent *agent,
- const char *path, const char *address, const char *service,
- const char *uuid, DBusGMethodInvocation *context)
-{
- DBusGProxy *object;
- const char *adapter = NULL, *name = NULL;
- gchar *device, *profile, *line;
-
- if (auto_authorize == TRUE) {
- dbus_g_method_return(context);
- return TRUE;
- }
-
- object = dbus_g_proxy_new_for_name(conn, "org.bluez",
- path, "org.bluez.Adapter");
-
- dbus_g_proxy_call(object, "GetName", NULL, G_TYPE_INVALID,
- G_TYPE_STRING, &adapter, G_TYPE_INVALID);
-
- dbus_g_proxy_call(object, "GetRemoteName", NULL,
- G_TYPE_STRING, address, G_TYPE_INVALID,
- G_TYPE_STRING, &name, G_TYPE_INVALID);
-
- object = dbus_g_proxy_new_for_name(conn, "org.bluez",
- service, "org.bluez.Service");
-
- dbus_g_proxy_call(object, "GetName", NULL, G_TYPE_INVALID,
- G_TYPE_STRING, &profile, G_TYPE_INVALID);
-
- if (name) {
- if (g_strrstr(name, address))
- device = g_strdup(name);
- else
- device = g_strdup_printf("%s (%s)", name, address);
- } else
- device = g_strdup(address);
-
- auth_dialog(path, address, service, uuid, device, profile, context);
-
- line = g_strdup_printf(_("Authorization request for %s"), device);
- g_free(device);
-
- show_notification(adapter ? adapter : _("Bluetooth device"),
- line, _("Check authorization"), 0,
- G_CALLBACK(notification_closed));
-
- g_free(line);
-
- return TRUE;
-}
-
-static gboolean auth_agent_cancel(PasskeyAgent *agent,
- const char *path, const char *address, const char *service,
- const char *uuid, DBusGMethodInvocation *context)
-{
- GList *list;
- GError *result;
- struct input_data *input;
-
- input = g_try_malloc0(sizeof(*input));
- if (!input)
- return FALSE;
-
- input->path = g_strdup(path);
- input->address = g_strdup(address);
- input->service = g_strdup(service);
- input->uuid = g_strdup(uuid);
-
- list = g_list_find_custom(input_list, input, input_compare);
-
- g_free(input->uuid);
- g_free(input->service);
- g_free(input->address);
- g_free(input->path);
- g_free(input);
-
- if (!list || !list->data)
- return FALSE;
-
- input = list->data;
-
- close_notification();
-
- result = g_error_new(AGENT_ERROR, AGENT_ERROR_REJECT,
- "Agent callback canceled");
-
- dbus_g_method_return_error(input->context, result);
-
- input_free(input);
-
- return TRUE;
-}
-
-static gboolean auth_agent_release(PasskeyAgent *agent, GError **error)
-{
- registered_auth = 0;
-
- return TRUE;
-}
-
-#include "auth-agent-glue.h"
-
-static int register_agents(void)
-{
- DBusGProxy *object;
- GError *error = NULL;
-
- if (registered_passkey && registered_auth)
- return 0;
-
- object = dbus_g_proxy_new_for_name(conn, "org.bluez",
- "/org/bluez", "org.bluez.Security");
-
- if (!registered_passkey) {
-
- dbus_g_proxy_call(object, "RegisterDefaultPasskeyAgent",
- &error, G_TYPE_STRING, PASSKEY_AGENT_PATH,
- G_TYPE_INVALID, G_TYPE_INVALID);
-
- if (error != NULL) {
- g_error_free(error);
- return -1;
- }
-
- registered_passkey = 1;
- }
-
- if (!registered_auth) {
- dbus_g_proxy_call(object, "RegisterDefaultAuthorizationAgent",
- &error, G_TYPE_STRING, AUTH_AGENT_PATH,
- G_TYPE_INVALID, G_TYPE_INVALID);
-
- if (error != NULL) {
- g_error_free(error);
- return -1;
- }
-
- registered_auth = 1;
- }
-
- return 0;
-}
-
static void bonding_created(DBusGProxy *object,
const char *address, gpointer user_data)
{
@@ -1436,8 +511,7 @@ static void name_owner_changed(DBusGProx
const char *prev, const char *new, gpointer user_data)
{
if (!strcmp(name, "org.bluez") && *new == '\0') {
- registered_passkey = 0;
- registered_auth = 0;
+ unregister_agents();
g_list_foreach(adapter_list, adapter_disable, NULL);
@@ -1462,7 +536,6 @@ static gboolean obexftp_available(void)
static int setup_dbus(void)
{
DBusGProxy *object;
- void *agent;
object = dbus_g_proxy_new_for_name(conn, DBUS_SERVICE_DBUS,
DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS);
@@ -1473,18 +546,7 @@ static int setup_dbus(void)
dbus_g_proxy_connect_signal(object, "NameOwnerChanged",
G_CALLBACK(name_owner_changed), NULL, NULL);
- dbus_g_object_type_install_info(PASSKEY_AGENT_OBJECT_TYPE,
- &dbus_glib_passkey_agent_object_info);
-
- dbus_g_object_type_install_info(AUTH_AGENT_OBJECT_TYPE,
- &dbus_glib_auth_agent_object_info);
-
- dbus_g_error_domain_register(AGENT_ERROR, "org.bluez.Error",
- AGENT_ERROR_TYPE);
-
- agent = passkey_agent_new(PASSKEY_AGENT_PATH);
-
- agent = auth_agent_new(AUTH_AGENT_PATH);
+ setup_agent_dbus();
return 0;
}
@@ -1655,11 +717,7 @@ static void wizard_callback(GObject *wid
static void activate_callback(GObject *widget, gpointer user_data)
{
- close_notification();
-
- g_list_foreach(input_list, show_dialog, NULL);
-
- gtk_status_icon_set_blinking(statusicon, FALSE);
+ flush_input();
}
static void popup_callback(GObject *widget, guint button,
@@ -1784,7 +842,7 @@ static void gconf_callback(GConfClient *
}
if (strcmp(entry->key, PREF_AUTO_AUTHORIZE) == 0)
- auto_authorize = gconf_value_get_bool(value);
+ set_auto_authorize (gconf_value_get_bool(value));
}
static GOptionEntry options[] = {
@@ -1843,8 +901,8 @@ int main(int argc, char *argv[])
g_free(str);
}
- auto_authorize = gconf_client_get_bool(gconf,
- PREF_AUTO_AUTHORIZE, NULL);
+ set_auto_authorize (gconf_client_get_bool(gconf,
+ PREF_AUTO_AUTHORIZE, NULL));
gconf_client_add_dir(gconf, PREF_DIR, GCONF_CLIENT_PRELOAD_NONE, NULL);
@@ -1872,17 +930,13 @@ int main(int argc, char *argv[])
register_agents();
- //passkey_dialog("/org/bluez/hci0", "00:11:22:33:44:55", "Test", NULL);
- //confirm_dialog("/org/bluez/hci0", "00:11:22:33:44:55", "123456", "Test", NULL);
- //auth_dialog("/org/bluez/hci0", "00:11:22:33:44:55", "/org/bluez/echo", "", "Test", "Echo service", NULL);
-
gtk_main();
gtk_widget_destroy(menu);
g_object_unref(gconf);
- close_notification();
+ flush_input();
g_list_foreach(adapter_list, adapter_free, NULL);
--- /dev/null 2008-01-24 17:45:36.352009045 +0000
+++ main.h 2008-02-01 17:33:58.000000000 +0000
@@ -0,0 +1,4 @@
+void show_notification(const gchar *summary, const gchar *message,
+ const gchar *action, gint timeout, GCallback handler);
+void close_notification(void);
+
--- /dev/null 2008-01-24 17:45:36.352009045 +0000
+++ agents.c 2008-02-01 17:40:23.000000000 +0000
@@ -0,0 +1,1013 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2005-2007 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2006-2007 Bastien Nocera <hadess@hadess.net>
+ *
+ *
+ * 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
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <dbus/dbus-glib.h>
+
+#include <glib/gi18n.h>
+
+#include <gtk/gtk.h>
+
+#include "agents.h"
+#include "main.h"
+
+extern GtkStatusIcon *statusicon;
+extern DBusGConnection *conn;
+
+#define PASSKEY_AGENT_PATH "/org/bluez/passkey"
+#define AUTH_AGENT_PATH "/org/bluez/auth"
+
+static int volatile registered_passkey = 0;
+static int volatile registered_auth = 0;
+
+static gboolean auto_authorize = FALSE;
+
+typedef enum {
+ AGENT_ERROR_REJECT
+} AgentError;
+
+#define AGENT_ERROR (agent_error_quark())
+
+#define AGENT_ERROR_TYPE (agent_error_get_type())
+
+static GQuark agent_error_quark(void)
+{
+ static GQuark quark = 0;
+ if (!quark)
+ quark = g_quark_from_static_string("agent");
+
+ return quark;
+}
+
+#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
+
+static GType agent_error_get_type(void)
+{
+ static GType etype = 0;
+ if (etype == 0) {
+ static const GEnumValue values[] = {
+ ENUM_ENTRY(AGENT_ERROR_REJECT, "Rejected"),
+ { 0, 0, 0 }
+ };
+
+ etype = g_enum_register_static("agent", values);
+ }
+
+ return etype;
+}
+
+static GList *input_list = NULL;
+
+struct input_data {
+ char *path;
+ char *address;
+ char *service;
+ char *uuid;
+ DBusGMethodInvocation *context;
+ GtkWidget *dialog;
+ GtkWidget *button;
+ GtkWidget *entry;
+};
+
+static gint input_compare(gconstpointer a, gconstpointer b)
+{
+ struct input_data *a_data = (struct input_data *) a;
+ struct input_data *b_data = (struct input_data *) b;
+
+ return strcmp(a_data->address, b_data->address);
+}
+
+static void input_free(struct input_data *input)
+{
+ gtk_widget_destroy(input->dialog);
+
+ input_list = g_list_remove(input_list, input);
+
+ g_free(input->uuid);
+ g_free(input->service);
+ g_free(input->address);
+ g_free(input->path);
+ g_free(input);
+
+ if (g_list_length(input_list) == 0)
+ gtk_status_icon_set_blinking(statusicon, FALSE);
+}
+
+static void passkey_callback(GtkWidget *dialog,
+ gint response, gpointer user_data)
+{
+ struct input_data *input = user_data;
+
+ if (response == GTK_RESPONSE_ACCEPT) {
+ const char *passkey;
+ passkey = gtk_entry_get_text(GTK_ENTRY(input->entry));
+ dbus_g_method_return(input->context, passkey);
+ } else {
+ GError *error;
+ error = g_error_new(AGENT_ERROR, AGENT_ERROR_REJECT,
+ "Pairing request rejected");
+ dbus_g_method_return_error(input->context, error);
+ }
+
+ input_free(input);
+}
+
+static void confirm_callback(GtkWidget *dialog,
+ gint response, gpointer user_data)
+{
+ struct input_data *input = user_data;
+
+ if (response != GTK_RESPONSE_YES) {
+ GError *error;
+ error = g_error_new(AGENT_ERROR, AGENT_ERROR_REJECT,
+ "Confirmation request rejected");
+ dbus_g_method_return_error(input->context, error);
+ } else
+ dbus_g_method_return(input->context);
+
+ input_free(input);
+}
+
+static void set_trusted(struct input_data *input)
+{
+ DBusGProxy *object;
+ gboolean active;
+
+ active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(input->button));
+ if (active == FALSE)
+ return;
+
+ object = dbus_g_proxy_new_for_name(conn, "org.bluez",
+ input->path, "org.bluez.Adapter");
+
+ dbus_g_proxy_call(object, "SetTrusted", NULL,
+ G_TYPE_STRING, input->address, G_TYPE_INVALID,
+ G_TYPE_INVALID);
+}
+
+static void auth_callback(GtkWidget *dialog,
+ gint response, gpointer user_data)
+{
+ struct input_data *input = user_data;
+
+ if (response == GTK_RESPONSE_YES) {
+ set_trusted(input);
+ dbus_g_method_return(input->context);
+ } else {
+ GError *error;
+ error = g_error_new(AGENT_ERROR, AGENT_ERROR_REJECT,
+ "Authorization request rejected");
+ dbus_g_method_return_error(input->context, error);
+ }
+
+ input_free(input);
+}
+
+static void changed_callback(GtkWidget *editable, gpointer user_data)
+{
+ struct input_data *input = user_data;
+ const gchar *text;
+
+ text = gtk_entry_get_text(GTK_ENTRY(input->entry));
+
+ gtk_widget_set_sensitive(input->button, strlen(text) ? TRUE : FALSE);
+}
+
+static void toggled_callback(GtkWidget *button, gpointer user_data)
+{
+ struct input_data *input = user_data;
+ gboolean mode;
+
+ mode = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
+
+ gtk_entry_set_visibility(GTK_ENTRY(input->entry), mode);
+}
+
+static void passkey_dialog(const char *path, const char *address,
+ const gchar *device, DBusGMethodInvocation *context)
+{
+ GtkWidget *dialog;
+ GtkWidget *button;
+ GtkWidget *image;
+ GtkWidget *label;
+ GtkWidget *entry;
+ GtkWidget *table;
+ GtkWidget *vbox;
+ struct input_data *input;
+ gchar *markup;
+
+ input = g_try_malloc0(sizeof(*input));
+ if (!input)
+ return;
+
+ input->path = g_strdup(path);
+ input->address = g_strdup(address);
+
+ input->context = context;
+
+ dialog = gtk_dialog_new();
+
+ gtk_window_set_title(GTK_WINDOW(dialog), _("Authentication request"));
+
+ gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
+
+ gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
+
+ gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE);
+
+ gtk_window_set_urgency_hint(GTK_WINDOW(dialog), TRUE);
+
+ gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
+
+ input->dialog = dialog;
+
+ button = gtk_dialog_add_button(GTK_DIALOG(dialog),
+ GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT);
+
+ button = gtk_dialog_add_button(GTK_DIALOG(dialog),
+ GTK_STOCK_OK, GTK_RESPONSE_ACCEPT);
+
+ gtk_widget_grab_default(button);
+
+ gtk_widget_set_sensitive(button, FALSE);
+
+ input->button = button;
+
+ table = gtk_table_new(5, 2, FALSE);
+
+ gtk_table_set_row_spacings(GTK_TABLE(table), 4);
+ gtk_table_set_col_spacings(GTK_TABLE(table), 20);
+
+ gtk_container_set_border_width(GTK_CONTAINER(table), 12);
+
+ gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table);
+
+ image = gtk_image_new_from_icon_name(GTK_STOCK_DIALOG_AUTHENTICATION,
+ GTK_ICON_SIZE_DIALOG);
+
+ gtk_misc_set_alignment(GTK_MISC(image), 0.0, 0.0);
+
+ gtk_table_attach(GTK_TABLE(table), image, 0, 1, 0, 5,
+ GTK_SHRINK, GTK_FILL, 0, 0);
+
+ vbox = gtk_vbox_new(FALSE, 6);
+
+ label = gtk_label_new(_("Pairing request for device:"));
+
+ gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
+
+ gtk_container_add(GTK_CONTAINER(vbox), label);
+
+ gtk_table_attach(GTK_TABLE(table), vbox, 1, 2, 0, 1,
+ GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0);
+
+ label = gtk_label_new(NULL);
+
+ markup = g_strdup_printf("<b>%s</b>", device);
+ gtk_label_set_markup(GTK_LABEL(label), markup);
+ g_free(markup);
+
+ gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
+
+ gtk_label_set_selectable(GTK_LABEL(label), TRUE);
+
+ gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
+
+ gtk_widget_set_size_request(GTK_WIDGET(label), 280, -1);
+
+ gtk_container_add(GTK_CONTAINER(vbox), label);
+
+ vbox = gtk_vbox_new(FALSE, 6);
+
+ label = gtk_label_new(_("Enter passkey for authentication:"));
+
+ gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
+
+ gtk_container_add(GTK_CONTAINER(vbox), label);
+
+ gtk_table_attach(GTK_TABLE(table), vbox, 1, 2, 2, 3,
+ GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0);
+
+ entry = gtk_entry_new();
+
+ gtk_entry_set_max_length(GTK_ENTRY(entry), 16);
+
+ gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
+
+ gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
+
+ input->entry = entry;
+
+ g_signal_connect(G_OBJECT(entry), "changed",
+ G_CALLBACK(changed_callback), input);
+
+ gtk_container_add(GTK_CONTAINER(vbox), entry);
+
+ button = gtk_check_button_new_with_label(_("Show input"));
+
+ g_signal_connect(G_OBJECT(button), "toggled",
+ G_CALLBACK(toggled_callback), input);
+
+ gtk_container_add(GTK_CONTAINER(vbox), button);
+
+ input_list = g_list_append(input_list, input);
+
+ g_signal_connect(G_OBJECT(dialog), "response",
+ G_CALLBACK(passkey_callback), input);
+
+ gtk_status_icon_set_blinking(statusicon, TRUE);
+}
+
+static void confirm_dialog(const char *path, const char *address,
+ const char *value, const gchar *device,
+ DBusGMethodInvocation *context)
+{
+ GtkWidget *dialog;
+ GtkWidget *button;
+ GtkWidget *image;
+ GtkWidget *label;
+ GtkWidget *table;
+ GtkWidget *vbox;
+ gchar *markup;
+ struct input_data *input;
+
+ input = g_try_malloc0(sizeof(*input));
+ if (!input)
+ return;
+
+ input->path = g_strdup(path);
+ input->address = g_strdup(address);
+
+ input->context = context;
+
+ dialog = gtk_dialog_new();
+
+ gtk_window_set_title(GTK_WINDOW(dialog), _("Confirmation request"));
+
+ gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
+
+ gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
+
+ gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE);
+
+ gtk_window_set_urgency_hint(GTK_WINDOW(dialog), TRUE);
+
+ gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
+
+ input->dialog = dialog;
+
+ button = gtk_dialog_add_button(GTK_DIALOG(dialog),
+ GTK_STOCK_NO, GTK_RESPONSE_NO);
+
+ button = gtk_dialog_add_button(GTK_DIALOG(dialog),
+ GTK_STOCK_YES, GTK_RESPONSE_YES);
+
+ table = gtk_table_new(5, 2, FALSE);
+
+ gtk_table_set_row_spacings(GTK_TABLE(table), 4);
+ gtk_table_set_col_spacings(GTK_TABLE(table), 20);
+
+ gtk_container_set_border_width(GTK_CONTAINER(table), 12);
+
+ gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table);
+
+ image = gtk_image_new_from_icon_name(GTK_STOCK_DIALOG_AUTHENTICATION,
+ GTK_ICON_SIZE_DIALOG);
+
+ gtk_misc_set_alignment(GTK_MISC(image), 0.0, 0.0);
+
+ gtk_table_attach(GTK_TABLE(table), image, 0, 1, 0, 5,
+ GTK_SHRINK, GTK_FILL, 0, 0);
+
+ vbox = gtk_vbox_new(FALSE, 6);
+ label = gtk_label_new(_("Pairing request for device:"));
+
+ gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
+
+ gtk_container_add(GTK_CONTAINER(vbox), label);
+
+ gtk_table_attach(GTK_TABLE(table), vbox, 1, 2, 0, 1,
+ GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0);
+
+ label = gtk_label_new(NULL);
+
+ markup = g_strdup_printf("<b>%s</b>", device);
+ gtk_label_set_markup(GTK_LABEL(label), markup);
+ g_free(markup);
+
+ gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
+
+ gtk_label_set_selectable(GTK_LABEL(label), TRUE);
+
+ gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
+
+ gtk_widget_set_size_request(GTK_WIDGET(label), 280, -1);
+
+ gtk_container_add(GTK_CONTAINER(vbox), label);
+
+ vbox = gtk_vbox_new(FALSE, 6);
+
+ label = gtk_label_new(_("Confirm value for authentication:"));
+
+ gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
+
+ gtk_container_add(GTK_CONTAINER(vbox), label);
+
+ gtk_table_attach(GTK_TABLE(table), vbox, 1, 2, 2, 3,
+ GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0);
+
+ label = gtk_label_new(NULL);
+
+ markup = g_strdup_printf("<b>%s</b>\n", value);
+
+ gtk_label_set_markup(GTK_LABEL(label), markup);
+
+ g_free(markup);
+
+ gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
+
+ gtk_container_add(GTK_CONTAINER(vbox), label);
+
+ input_list = g_list_append(input_list, input);
+
+ g_signal_connect(G_OBJECT(dialog), "response",
+ G_CALLBACK(confirm_callback), input);
+
+ gtk_status_icon_set_blinking(statusicon, TRUE);
+}
+
+static void auth_dialog(const char *path, const char *address,
+ const char *service, const char *uuid, const gchar *device,
+ const gchar *profile, DBusGMethodInvocation *context)
+{
+ GtkWidget *dialog;
+ GtkWidget *button;
+ GtkWidget *image;
+ GtkWidget *label;
+ GtkWidget *table;
+ GtkWidget *vbox;
+ gchar *markup, *text;
+ struct input_data *input;
+
+ input = g_try_malloc0(sizeof(*input));
+ if (!input)
+ return;
+
+ input->path = g_strdup(path);
+ input->address = g_strdup(address);
+ input->service = g_strdup(service);
+ input->uuid = g_strdup(uuid);
+
+ input->context = context;
+
+ dialog = gtk_dialog_new();
+
+ gtk_window_set_title(GTK_WINDOW(dialog), _("Authorization request"));
+
+ gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
+
+ gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
+
+ gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE);
+
+ gtk_window_set_urgency_hint(GTK_WINDOW(dialog), TRUE);
+
+ gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
+
+ input->dialog = dialog;
+
+ button = gtk_dialog_add_button(GTK_DIALOG(dialog),
+ GTK_STOCK_NO, GTK_RESPONSE_NO);
+
+ button = gtk_dialog_add_button(GTK_DIALOG(dialog),
+ GTK_STOCK_YES, GTK_RESPONSE_YES);
+
+ table = gtk_table_new(5, 2, FALSE);
+
+ gtk_table_set_row_spacings(GTK_TABLE(table), 4);
+ gtk_table_set_col_spacings(GTK_TABLE(table), 20);
+
+ gtk_container_set_border_width(GTK_CONTAINER(table), 12);
+
+ gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table);
+
+ image = gtk_image_new_from_icon_name(GTK_STOCK_DIALOG_AUTHENTICATION,
+ GTK_ICON_SIZE_DIALOG);
+
+ gtk_misc_set_alignment(GTK_MISC(image), 0.0, 0.0);
+
+ gtk_table_attach(GTK_TABLE(table), image, 0, 1, 0, 5,
+ GTK_SHRINK, GTK_FILL, 0, 0);
+
+ vbox = gtk_vbox_new(FALSE, 6);
+
+ label = gtk_label_new(_("Authorization request for device:"));
+
+ gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
+
+ gtk_table_attach(GTK_TABLE(table), label, 1, 2, 0, 1,
+ GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0);
+
+ label = gtk_label_new(NULL);
+
+ markup = g_strdup_printf("<b>%s</b>", device);
+ gtk_label_set_markup(GTK_LABEL(label), markup);
+ g_free(markup);
+
+ gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
+
+ gtk_label_set_selectable(GTK_LABEL(label), TRUE);
+
+ gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
+
+ gtk_widget_set_size_request(GTK_WIDGET(label), 280, -1);
+
+ gtk_container_add(GTK_CONTAINER(vbox), label);
+
+ gtk_table_attach(GTK_TABLE(table), vbox, 1, 2, 2, 3,
+ GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0);
+
+ label = gtk_label_new(NULL);
+
+ /* translators: Whether to grant access to a particular service
+ * to the device mentioned */
+ markup = g_strdup_printf("<i>%s</i>", profile);
+ text = g_strdup_printf(_("Grant access to %s?"), markup);
+ g_free(markup);
+
+ markup = g_strdup_printf("%s\n", text);
+ gtk_label_set_markup(GTK_LABEL(label), markup);
+ g_free(markup);
+
+ g_free(text);
+
+ gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
+
+ gtk_container_add(GTK_CONTAINER(vbox), label);
+
+ button = gtk_check_button_new_with_label(_("Always grant access"));
+
+ input->button = button;
+
+ gtk_container_add(GTK_CONTAINER(vbox), button);
+
+ input_list = g_list_append(input_list, input);
+
+ g_signal_connect(G_OBJECT(dialog), "response",
+ G_CALLBACK(auth_callback), input);
+
+ gtk_status_icon_set_blinking(statusicon, TRUE);
+}
+
+static void show_dialog(gpointer data, gpointer user_data)
+{
+ struct input_data *input = data;
+
+ gtk_widget_show_all(input->dialog);
+
+ gtk_window_present(GTK_WINDOW(input->dialog));
+}
+
+typedef struct {
+ GObject parent;
+} PasskeyAgent;
+
+typedef struct {
+ GObjectClass parent;
+} PasskeyAgentClass;
+
+static GObjectClass *passkey_agent_parent;
+
+G_DEFINE_TYPE(PasskeyAgent, passkey_agent, G_TYPE_OBJECT)
+
+#define PASSKEY_AGENT_OBJECT_TYPE (passkey_agent_get_type())
+
+#define PASSKEY_AGENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
+ PASSKEY_AGENT_OBJECT_TYPE, PasskeyAgent))
+
+static void passkey_agent_finalize(GObject *obj)
+{
+ passkey_agent_parent->finalize(obj);
+}
+
+static void passkey_agent_init(PasskeyAgent *obj)
+{
+}
+
+static void passkey_agent_class_init(PasskeyAgentClass *klass)
+{
+ GObjectClass *gobject_class;
+
+ passkey_agent_parent = g_type_class_peek_parent(klass);
+
+ gobject_class = G_OBJECT_CLASS(klass);
+ gobject_class->finalize = passkey_agent_finalize;
+}
+
+static PasskeyAgent *passkey_agent_new(const char *path)
+{
+ PasskeyAgent *agent;
+
+ agent = g_object_new(PASSKEY_AGENT_OBJECT_TYPE, NULL);
+
+ dbus_g_connection_register_g_object(conn, path, G_OBJECT(agent));
+
+ return agent;
+}
+
+static void notification_closed(GObject *object, gpointer user_data)
+{
+ g_list_foreach(input_list, show_dialog, NULL);
+
+ gtk_status_icon_set_blinking(statusicon, FALSE);
+}
+
+static gboolean passkey_agent_request(PasskeyAgent *agent,
+ const char *path, const char *address,
+ DBusGMethodInvocation *context)
+{
+ DBusGProxy *object;
+ const char *adapter = NULL, *name = NULL;
+ gchar *device, *line;
+
+ object = dbus_g_proxy_new_for_name(conn, "org.bluez",
+ path, "org.bluez.Adapter");
+
+ dbus_g_proxy_call(object, "GetName", NULL, G_TYPE_INVALID,
+ G_TYPE_STRING, &adapter, G_TYPE_INVALID);
+
+ dbus_g_proxy_call(object, "GetRemoteName", NULL,
+ G_TYPE_STRING, address, G_TYPE_INVALID,
+ G_TYPE_STRING, &name, G_TYPE_INVALID);
+
+ if (name) {
+ if (g_strrstr(name, address))
+ device = g_strdup(name);
+ else
+ device = g_strdup_printf("%s (%s)", name, address);
+ } else
+ device = g_strdup(address);
+
+ passkey_dialog(path, address, device, context);
+
+ /* translators: this is a popup telling you a particular device
+ * has asked for pairing */
+ line = g_strdup_printf(_("Pairing request for '%s'"), device);
+ g_free(device);
+
+ show_notification(adapter ? adapter : _("Bluetooth device"),
+ line, _("Enter passkey"), 0,
+ G_CALLBACK(notification_closed));
+
+ g_free(line);
+
+ return TRUE;
+}
+
+static gboolean passkey_agent_confirm(PasskeyAgent *agent,
+ const char *path, const char *address,
+ const char *value, DBusGMethodInvocation *context)
+{
+ DBusGProxy *object;
+ const char *adapter = NULL, *name = NULL;
+ gchar *device, *line;
+
+ object = dbus_g_proxy_new_for_name(conn, "org.bluez",
+ path, "org.bluez.Adapter");
+
+ dbus_g_proxy_call(object, "GetName", NULL, G_TYPE_INVALID,
+ G_TYPE_STRING, &adapter, G_TYPE_INVALID);
+
+ dbus_g_proxy_call(object, "GetRemoteName", NULL,
+ G_TYPE_STRING, address, G_TYPE_INVALID,
+ G_TYPE_STRING, &name, G_TYPE_INVALID);
+
+ if (name) {
+ if (g_strrstr(name, address))
+ device = g_strdup(name);
+ else
+ device = g_strdup_printf("%s (%s)", name, address);
+ } else
+ device = g_strdup(address);
+
+ confirm_dialog(path, address, value, device, context);
+
+ line = g_strdup_printf(_("Pairing request for '%s'"), device);
+ g_free(device);
+
+ show_notification(adapter ? adapter : _("Bluetooth device"),
+ line, _("Confirm pairing"), 0,
+ G_CALLBACK(notification_closed));
+
+ g_free (line);
+
+ return TRUE;
+}
+
+static gboolean passkey_agent_cancel(PasskeyAgent *agent,
+ const char *path, const char *address, GError **error)
+{
+ GList *list;
+ GError *result;
+ struct input_data *input;
+
+ input = g_try_malloc0(sizeof(*input));
+ if (!input)
+ return FALSE;
+
+ input->path = g_strdup(path);
+ input->address = g_strdup(address);
+
+ list = g_list_find_custom(input_list, input, input_compare);
+
+ g_free(input->address);
+ g_free(input->path);
+ g_free(input);
+
+ if (!list || !list->data)
+ return FALSE;
+
+ input = list->data;
+
+ close_notification();
+
+ result = g_error_new(AGENT_ERROR, AGENT_ERROR_REJECT,
+ "Agent callback canceled");
+
+ dbus_g_method_return_error(input->context, result);
+
+ input_free(input);
+
+ return TRUE;
+}
+
+static gboolean passkey_agent_release(PasskeyAgent *agent, GError **error)
+{
+ registered_passkey = 0;
+
+ return TRUE;
+}
+
+#include "passkey-agent-glue.h"
+
+typedef struct {
+ GObject parent;
+} AuthAgent;
+
+typedef struct {
+ GObjectClass parent;
+} AuthAgentClass;
+
+static GObjectClass *auth_agent_parent;
+
+G_DEFINE_TYPE(AuthAgent, auth_agent, G_TYPE_OBJECT)
+
+#define AUTH_AGENT_OBJECT_TYPE (auth_agent_get_type())
+
+#define AUTH_AGENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
+ AUTH_AGENT_OBJECT_TYPE, AuthAgent))
+
+static void auth_agent_finalize(GObject *obj)
+{
+ auth_agent_parent->finalize(obj);
+}
+
+static void auth_agent_init(AuthAgent *obj)
+{
+}
+
+static void auth_agent_class_init(AuthAgentClass *klass)
+{
+ GObjectClass *gobject_class;
+
+ auth_agent_parent = g_type_class_peek_parent(klass);
+
+ gobject_class = G_OBJECT_CLASS(klass);
+ gobject_class->finalize = auth_agent_finalize;
+}
+
+static AuthAgent *auth_agent_new(const char *path)
+{
+ AuthAgent *agent;
+
+ agent = g_object_new(AUTH_AGENT_OBJECT_TYPE, NULL);
+
+ dbus_g_connection_register_g_object(conn, path, G_OBJECT(agent));
+
+ return agent;
+}
+
+static gboolean auth_agent_authorize(PasskeyAgent *agent,
+ const char *path, const char *address, const char *service,
+ const char *uuid, DBusGMethodInvocation *context)
+{
+ DBusGProxy *object;
+ const char *adapter = NULL, *name = NULL;
+ gchar *device, *profile, *line;
+
+ if (auto_authorize == TRUE) {
+ dbus_g_method_return(context);
+ return TRUE;
+ }
+
+ object = dbus_g_proxy_new_for_name(conn, "org.bluez",
+ path, "org.bluez.Adapter");
+
+ dbus_g_proxy_call(object, "GetName", NULL, G_TYPE_INVALID,
+ G_TYPE_STRING, &adapter, G_TYPE_INVALID);
+
+ dbus_g_proxy_call(object, "GetRemoteName", NULL,
+ G_TYPE_STRING, address, G_TYPE_INVALID,
+ G_TYPE_STRING, &name, G_TYPE_INVALID);
+
+ object = dbus_g_proxy_new_for_name(conn, "org.bluez",
+ service, "org.bluez.Service");
+
+ dbus_g_proxy_call(object, "GetName", NULL, G_TYPE_INVALID,
+ G_TYPE_STRING, &profile, G_TYPE_INVALID);
+
+ if (name) {
+ if (g_strrstr(name, address))
+ device = g_strdup(name);
+ else
+ device = g_strdup_printf("%s (%s)", name, address);
+ } else
+ device = g_strdup(address);
+
+ auth_dialog(path, address, service, uuid, device, profile, context);
+
+ line = g_strdup_printf(_("Authorization request for %s"), device);
+ g_free(device);
+
+ show_notification(adapter ? adapter : _("Bluetooth device"),
+ line, _("Check authorization"), 0,
+ G_CALLBACK(notification_closed));
+
+ g_free(line);
+
+ return TRUE;
+}
+
+static gboolean auth_agent_cancel(PasskeyAgent *agent,
+ const char *path, const char *address, const char *service,
+ const char *uuid, DBusGMethodInvocation *context)
+{
+ GList *list;
+ GError *result;
+ struct input_data *input;
+
+ input = g_try_malloc0(sizeof(*input));
+ if (!input)
+ return FALSE;
+
+ input->path = g_strdup(path);
+ input->address = g_strdup(address);
+ input->service = g_strdup(service);
+ input->uuid = g_strdup(uuid);
+
+ list = g_list_find_custom(input_list, input, input_compare);
+
+ g_free(input->uuid);
+ g_free(input->service);
+ g_free(input->address);
+ g_free(input->path);
+ g_free(input);
+
+ if (!list || !list->data)
+ return FALSE;
+
+ input = list->data;
+
+ close_notification();
+
+ result = g_error_new(AGENT_ERROR, AGENT_ERROR_REJECT,
+ "Agent callback canceled");
+
+ dbus_g_method_return_error(input->context, result);
+
+ input_free(input);
+
+ return TRUE;
+}
+
+static gboolean auth_agent_release(PasskeyAgent *agent, GError **error)
+{
+ registered_auth = 0;
+
+ return TRUE;
+}
+
+#include "auth-agent-glue.h"
+
+int register_agents(void)
+{
+ DBusGProxy *object;
+ GError *error = NULL;
+
+ if (registered_passkey && registered_auth)
+ return 0;
+
+ object = dbus_g_proxy_new_for_name(conn, "org.bluez",
+ "/org/bluez", "org.bluez.Security");
+
+ if (!registered_passkey) {
+
+ dbus_g_proxy_call(object, "RegisterDefaultPasskeyAgent",
+ &error, G_TYPE_STRING, PASSKEY_AGENT_PATH,
+ G_TYPE_INVALID, G_TYPE_INVALID);
+
+ if (error != NULL) {
+ g_error_free(error);
+ return -1;
+ }
+
+ registered_passkey = 1;
+ }
+
+ if (!registered_auth) {
+ dbus_g_proxy_call(object, "RegisterDefaultAuthorizationAgent",
+ &error, G_TYPE_STRING, AUTH_AGENT_PATH,
+ G_TYPE_INVALID, G_TYPE_INVALID);
+
+ if (error != NULL) {
+ g_error_free(error);
+ return -1;
+ }
+
+ registered_auth = 1;
+ }
+
+ /* To test a particular type of authorization or pairing question */
+ //passkey_dialog("/org/bluez/hci0", "00:11:22:33:44:55", "Test", NULL);
+ //confirm_dialog("/org/bluez/hci0", "00:11:22:33:44:55", "123456", "Test", NULL);
+ //auth_dialog("/org/bluez/hci0", "00:11:22:33:44:55", "/org/bluez/echo", "", "Test", "Echo service", NULL);
+
+ return 0;
+}
+
+void unregister_agents(void)
+{
+ registered_passkey = 0;
+ registered_auth = 0;
+}
+
+void flush_input(void)
+{
+ close_notification();
+
+ g_list_foreach(input_list, show_dialog, NULL);
+
+ gtk_status_icon_set_blinking(statusicon, FALSE);
+}
+
+void setup_agent_dbus(void)
+{
+ void *agent;
+
+ dbus_g_object_type_install_info(PASSKEY_AGENT_OBJECT_TYPE,
+ &dbus_glib_passkey_agent_object_info);
+
+ dbus_g_object_type_install_info(AUTH_AGENT_OBJECT_TYPE,
+ &dbus_glib_auth_agent_object_info);
+
+ dbus_g_error_domain_register(AGENT_ERROR, "org.bluez.Error",
+ AGENT_ERROR_TYPE);
+
+ agent = passkey_agent_new(PASSKEY_AGENT_PATH);
+
+ agent = auth_agent_new(AUTH_AGENT_PATH);
+}
+void set_auto_authorize(gboolean value)
+{
+ auto_authorize = value;
+}
+
--- /dev/null 2008-01-24 17:45:36.352009045 +0000
+++ agents.h 2008-02-01 17:25:58.000000000 +0000
@@ -0,0 +1,29 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2005-2007 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2006-2007 Bastien Nocera <hadess@hadess.net>
+ *
+ *
+ * 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
+ *
+ */
+
+int register_agents(void);
+void unregister_agents(void);
+void flush_input(void);
+void setup_agent_dbus(void);
+void set_auto_authorize(gboolean auto_authorize);
[-- Attachment #3: Type: text/plain, Size: 228 bytes --]
-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
[-- Attachment #4: Type: text/plain, Size: 164 bytes --]
_______________________________________________
Bluez-devel mailing list
Bluez-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bluez-devel
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [Bluez-devel] [PATCH] Split agents 2008-02-01 17:44 [Bluez-devel] [PATCH] Split agents Bastien Nocera @ 2008-02-06 13:46 ` Bastien Nocera 2008-02-07 1:13 ` Bastien Nocera 0 siblings, 1 reply; 6+ messages in thread From: Bastien Nocera @ 2008-02-06 13:46 UTC (permalink / raw) To: BlueZ development [-- Attachment #1: Type: text/plain, Size: 277 bytes --] On Fri, 2008-02-01 at 17:44 +0000, Bastien Nocera wrote: > Heya, > > First draft patch to split the agents away from the main program. Seems > to work fine for me. > > This is mostly moving functions around though. Updated patch following the comments from Marcel. Cheers [-- Attachment #2: bluez-gnome-split-agents-2.patch --] [-- Type: text/x-patch, Size: 59370 bytes --] Index: Makefile.am =================================================================== RCS file: /cvsroot/bluez/gnome/applet/Makefile.am,v retrieving revision 1.21 diff -u -p -r1.21 Makefile.am --- Makefile.am 28 Jul 2007 23:57:16 -0000 1.21 +++ Makefile.am 6 Feb 2008 13:45:52 -0000 @@ -1,7 +1,7 @@ bin_PROGRAMS = bluetooth-applet -bluetooth_applet_SOURCES = main.c +bluetooth_applet_SOURCES = main.c agent.c agent.h notifications.c notifications.h bluetooth_applet_LDADD = \ @NOTIFY_LIBS@ @GCONF_LIBS@ \ Index: main.c =================================================================== RCS file: /cvsroot/bluez/gnome/applet/main.c,v retrieving revision 1.102 diff -u -p -r1.102 main.c --- main.c 2 Feb 2008 16:42:50 -0000 1.102 +++ main.c 6 Feb 2008 13:45:52 -0000 @@ -47,17 +47,13 @@ #include "bluetooth-instance.h" #include "bluetooth-device-selection.h" +#include "agent.h" +#include "notifications.h" +static DBusGConnection *conn = NULL; +static GtkStatusIcon *statusicon = NULL; static gboolean singleton = FALSE; -#define PASSKEY_AGENT_PATH "/org/bluez/passkey" -#define AUTH_AGENT_PATH "/org/bluez/auth" - -static int volatile registered_passkey = 0; -static int volatile registered_auth = 0; - -static DBusGConnection *conn; - #ifdef HAVE_HAL static gboolean use_hal = FALSE; #endif @@ -78,8 +74,6 @@ typedef enum { static int icon_policy = ICON_POLICY_PRESENT; -static gboolean auto_authorize = FALSE; - #define PREF_DIR "/apps/bluetooth-manager" #define PREF_USE_HAL PREF_DIR "/use_hal" #define PREF_ICON_POLICY PREF_DIR "/icon_policy" @@ -87,983 +81,8 @@ static gboolean auto_authorize = FALSE; static GConfClient* gconf; -static GtkStatusIcon *statusicon = NULL; - static GtkWidget *menuitem_browse = NULL; -typedef enum { - AGENT_ERROR_REJECT -} AgentError; - -#define AGENT_ERROR (agent_error_quark()) - -#define AGENT_ERROR_TYPE (agent_error_get_type()) - -static GQuark agent_error_quark(void) -{ - static GQuark quark = 0; - if (!quark) - quark = g_quark_from_static_string("agent"); - - return quark; -} - -#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC } - -static GType agent_error_get_type(void) -{ - static GType etype = 0; - if (etype == 0) { - static const GEnumValue values[] = { - ENUM_ENTRY(AGENT_ERROR_REJECT, "Rejected"), - { 0, 0, 0 } - }; - - etype = g_enum_register_static("agent", values); - } - - return etype; -} - -static GList *input_list = NULL; - -struct input_data { - char *path; - char *address; - char *service; - char *uuid; - DBusGMethodInvocation *context; - GtkWidget *dialog; - GtkWidget *button; - GtkWidget *entry; -}; - -static gint input_compare(gconstpointer a, gconstpointer b) -{ - struct input_data *a_data = (struct input_data *) a; - struct input_data *b_data = (struct input_data *) b; - - return strcmp(a_data->address, b_data->address); -} - -static void input_free(struct input_data *input) -{ - gtk_widget_destroy(input->dialog); - - input_list = g_list_remove(input_list, input); - - g_free(input->uuid); - g_free(input->service); - g_free(input->address); - g_free(input->path); - g_free(input); - - if (g_list_length(input_list) == 0) - gtk_status_icon_set_blinking(statusicon, FALSE); -} - -static void passkey_callback(GtkWidget *dialog, - gint response, gpointer user_data) -{ - struct input_data *input = user_data; - - if (response == GTK_RESPONSE_ACCEPT) { - const char *passkey; - passkey = gtk_entry_get_text(GTK_ENTRY(input->entry)); - dbus_g_method_return(input->context, passkey); - } else { - GError *error; - error = g_error_new(AGENT_ERROR, AGENT_ERROR_REJECT, - "Pairing request rejected"); - dbus_g_method_return_error(input->context, error); - } - - input_free(input); -} - -static void confirm_callback(GtkWidget *dialog, - gint response, gpointer user_data) -{ - struct input_data *input = user_data; - - if (response != GTK_RESPONSE_YES) { - GError *error; - error = g_error_new(AGENT_ERROR, AGENT_ERROR_REJECT, - "Confirmation request rejected"); - dbus_g_method_return_error(input->context, error); - } else - dbus_g_method_return(input->context); - - input_free(input); -} - -static void set_trusted(struct input_data *input) -{ - DBusGProxy *object; - gboolean active; - - active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(input->button)); - if (active == FALSE) - return; - - object = dbus_g_proxy_new_for_name(conn, "org.bluez", - input->path, "org.bluez.Adapter"); - - dbus_g_proxy_call(object, "SetTrusted", NULL, - G_TYPE_STRING, input->address, G_TYPE_INVALID, - G_TYPE_INVALID); -} - -static void auth_callback(GtkWidget *dialog, - gint response, gpointer user_data) -{ - struct input_data *input = user_data; - - if (response == GTK_RESPONSE_YES) { - set_trusted(input); - dbus_g_method_return(input->context); - } else { - GError *error; - error = g_error_new(AGENT_ERROR, AGENT_ERROR_REJECT, - "Authorization request rejected"); - dbus_g_method_return_error(input->context, error); - } - - input_free(input); -} - -static void changed_callback(GtkWidget *editable, gpointer user_data) -{ - struct input_data *input = user_data; - const gchar *text; - - text = gtk_entry_get_text(GTK_ENTRY(input->entry)); - - gtk_widget_set_sensitive(input->button, strlen(text) ? TRUE : FALSE); -} - -static void toggled_callback(GtkWidget *button, gpointer user_data) -{ - struct input_data *input = user_data; - gboolean mode; - - mode = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)); - - gtk_entry_set_visibility(GTK_ENTRY(input->entry), mode); -} - -static void passkey_dialog(const char *path, const char *address, - const gchar *device, DBusGMethodInvocation *context) -{ - GtkWidget *dialog; - GtkWidget *button; - GtkWidget *image; - GtkWidget *label; - GtkWidget *entry; - GtkWidget *table; - GtkWidget *vbox; - struct input_data *input; - gchar *markup; - - input = g_try_malloc0(sizeof(*input)); - if (!input) - return; - - input->path = g_strdup(path); - input->address = g_strdup(address); - - input->context = context; - - dialog = gtk_dialog_new(); - - gtk_window_set_title(GTK_WINDOW(dialog), _("Authentication request")); - - gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); - - gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER); - - gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE); - - gtk_window_set_urgency_hint(GTK_WINDOW(dialog), TRUE); - - gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE); - - input->dialog = dialog; - - button = gtk_dialog_add_button(GTK_DIALOG(dialog), - GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT); - - button = gtk_dialog_add_button(GTK_DIALOG(dialog), - GTK_STOCK_OK, GTK_RESPONSE_ACCEPT); - - gtk_widget_grab_default(button); - - gtk_widget_set_sensitive(button, FALSE); - - input->button = button; - - table = gtk_table_new(5, 2, FALSE); - - gtk_table_set_row_spacings(GTK_TABLE(table), 4); - gtk_table_set_col_spacings(GTK_TABLE(table), 20); - - gtk_container_set_border_width(GTK_CONTAINER(table), 12); - - gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table); - - image = gtk_image_new_from_icon_name(GTK_STOCK_DIALOG_AUTHENTICATION, - GTK_ICON_SIZE_DIALOG); - - gtk_misc_set_alignment(GTK_MISC(image), 0.0, 0.0); - - gtk_table_attach(GTK_TABLE(table), image, 0, 1, 0, 5, - GTK_SHRINK, GTK_FILL, 0, 0); - - vbox = gtk_vbox_new(FALSE, 6); - - label = gtk_label_new(_("Pairing request for device:")); - - gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); - - gtk_container_add(GTK_CONTAINER(vbox), label); - - gtk_table_attach(GTK_TABLE(table), vbox, 1, 2, 0, 1, - GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0); - - label = gtk_label_new(NULL); - - markup = g_strdup_printf("<b>%s</b>", device); - gtk_label_set_markup(GTK_LABEL(label), markup); - g_free(markup); - - gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); - - gtk_label_set_selectable(GTK_LABEL(label), TRUE); - - gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); - - gtk_widget_set_size_request(GTK_WIDGET(label), 280, -1); - - gtk_container_add(GTK_CONTAINER(vbox), label); - - vbox = gtk_vbox_new(FALSE, 6); - - label = gtk_label_new(_("Enter passkey for authentication:")); - - gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); - - gtk_container_add(GTK_CONTAINER(vbox), label); - - gtk_table_attach(GTK_TABLE(table), vbox, 1, 2, 2, 3, - GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0); - - entry = gtk_entry_new(); - - gtk_entry_set_max_length(GTK_ENTRY(entry), 16); - - gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE); - - gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE); - - input->entry = entry; - - g_signal_connect(G_OBJECT(entry), "changed", - G_CALLBACK(changed_callback), input); - - gtk_container_add(GTK_CONTAINER(vbox), entry); - - button = gtk_check_button_new_with_label(_("Show input")); - - g_signal_connect(G_OBJECT(button), "toggled", - G_CALLBACK(toggled_callback), input); - - gtk_container_add(GTK_CONTAINER(vbox), button); - - input_list = g_list_append(input_list, input); - - g_signal_connect(G_OBJECT(dialog), "response", - G_CALLBACK(passkey_callback), input); - - gtk_status_icon_set_blinking(statusicon, TRUE); -} - -static void confirm_dialog(const char *path, const char *address, - const char *value, const gchar *device, - DBusGMethodInvocation *context) -{ - GtkWidget *dialog; - GtkWidget *button; - GtkWidget *image; - GtkWidget *label; - GtkWidget *table; - GtkWidget *vbox; - gchar *markup; - struct input_data *input; - - input = g_try_malloc0(sizeof(*input)); - if (!input) - return; - - input->path = g_strdup(path); - input->address = g_strdup(address); - - input->context = context; - - dialog = gtk_dialog_new(); - - gtk_window_set_title(GTK_WINDOW(dialog), _("Confirmation request")); - - gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); - - gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER); - - gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE); - - gtk_window_set_urgency_hint(GTK_WINDOW(dialog), TRUE); - - gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE); - - input->dialog = dialog; - - button = gtk_dialog_add_button(GTK_DIALOG(dialog), - GTK_STOCK_NO, GTK_RESPONSE_NO); - - button = gtk_dialog_add_button(GTK_DIALOG(dialog), - GTK_STOCK_YES, GTK_RESPONSE_YES); - - table = gtk_table_new(5, 2, FALSE); - - gtk_table_set_row_spacings(GTK_TABLE(table), 4); - gtk_table_set_col_spacings(GTK_TABLE(table), 20); - - gtk_container_set_border_width(GTK_CONTAINER(table), 12); - - gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table); - - image = gtk_image_new_from_icon_name(GTK_STOCK_DIALOG_AUTHENTICATION, - GTK_ICON_SIZE_DIALOG); - - gtk_misc_set_alignment(GTK_MISC(image), 0.0, 0.0); - - gtk_table_attach(GTK_TABLE(table), image, 0, 1, 0, 5, - GTK_SHRINK, GTK_FILL, 0, 0); - - vbox = gtk_vbox_new(FALSE, 6); - label = gtk_label_new(_("Pairing request for device:")); - - gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); - - gtk_container_add(GTK_CONTAINER(vbox), label); - - gtk_table_attach(GTK_TABLE(table), vbox, 1, 2, 0, 1, - GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0); - - label = gtk_label_new(NULL); - - markup = g_strdup_printf("<b>%s</b>", device); - gtk_label_set_markup(GTK_LABEL(label), markup); - g_free(markup); - - gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); - - gtk_label_set_selectable(GTK_LABEL(label), TRUE); - - gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); - - gtk_widget_set_size_request(GTK_WIDGET(label), 280, -1); - - gtk_container_add(GTK_CONTAINER(vbox), label); - - vbox = gtk_vbox_new(FALSE, 6); - - label = gtk_label_new(_("Confirm value for authentication:")); - - gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); - - gtk_container_add(GTK_CONTAINER(vbox), label); - - gtk_table_attach(GTK_TABLE(table), vbox, 1, 2, 2, 3, - GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0); - - label = gtk_label_new(NULL); - - markup = g_strdup_printf("<b>%s</b>\n", value); - - gtk_label_set_markup(GTK_LABEL(label), markup); - - g_free(markup); - - gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); - - gtk_container_add(GTK_CONTAINER(vbox), label); - - input_list = g_list_append(input_list, input); - - g_signal_connect(G_OBJECT(dialog), "response", - G_CALLBACK(confirm_callback), input); - - gtk_status_icon_set_blinking(statusicon, TRUE); -} - -static void auth_dialog(const char *path, const char *address, - const char *service, const char *uuid, const gchar *device, - const gchar *profile, DBusGMethodInvocation *context) -{ - GtkWidget *dialog; - GtkWidget *button; - GtkWidget *image; - GtkWidget *label; - GtkWidget *table; - GtkWidget *vbox; - gchar *markup, *text; - struct input_data *input; - - input = g_try_malloc0(sizeof(*input)); - if (!input) - return; - - input->path = g_strdup(path); - input->address = g_strdup(address); - input->service = g_strdup(service); - input->uuid = g_strdup(uuid); - - input->context = context; - - dialog = gtk_dialog_new(); - - gtk_window_set_title(GTK_WINDOW(dialog), _("Authorization request")); - - gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); - - gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER); - - gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE); - - gtk_window_set_urgency_hint(GTK_WINDOW(dialog), TRUE); - - gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE); - - input->dialog = dialog; - - button = gtk_dialog_add_button(GTK_DIALOG(dialog), - GTK_STOCK_NO, GTK_RESPONSE_NO); - - button = gtk_dialog_add_button(GTK_DIALOG(dialog), - GTK_STOCK_YES, GTK_RESPONSE_YES); - - table = gtk_table_new(5, 2, FALSE); - - gtk_table_set_row_spacings(GTK_TABLE(table), 4); - gtk_table_set_col_spacings(GTK_TABLE(table), 20); - - gtk_container_set_border_width(GTK_CONTAINER(table), 12); - - gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table); - - image = gtk_image_new_from_icon_name(GTK_STOCK_DIALOG_AUTHENTICATION, - GTK_ICON_SIZE_DIALOG); - - gtk_misc_set_alignment(GTK_MISC(image), 0.0, 0.0); - - gtk_table_attach(GTK_TABLE(table), image, 0, 1, 0, 5, - GTK_SHRINK, GTK_FILL, 0, 0); - - vbox = gtk_vbox_new(FALSE, 6); - - label = gtk_label_new(_("Authorization request for device:")); - - gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); - - gtk_table_attach(GTK_TABLE(table), label, 1, 2, 0, 1, - GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0); - - label = gtk_label_new(NULL); - - markup = g_strdup_printf("<b>%s</b>", device); - gtk_label_set_markup(GTK_LABEL(label), markup); - g_free(markup); - - gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); - - gtk_label_set_selectable(GTK_LABEL(label), TRUE); - - gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); - - gtk_widget_set_size_request(GTK_WIDGET(label), 280, -1); - - gtk_container_add(GTK_CONTAINER(vbox), label); - - gtk_table_attach(GTK_TABLE(table), vbox, 1, 2, 2, 3, - GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0); - - label = gtk_label_new(NULL); - - /* translators: Whether to grant access to a particular service - * to the device mentioned */ - markup = g_strdup_printf("<i>%s</i>", profile); - text = g_strdup_printf(_("Grant access to %s?"), markup); - g_free(markup); - - markup = g_strdup_printf("%s\n", text); - gtk_label_set_markup(GTK_LABEL(label), markup); - g_free(markup); - - g_free(text); - - gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); - - gtk_container_add(GTK_CONTAINER(vbox), label); - - button = gtk_check_button_new_with_label(_("Always grant access")); - - input->button = button; - - gtk_container_add(GTK_CONTAINER(vbox), button); - - input_list = g_list_append(input_list, input); - - g_signal_connect(G_OBJECT(dialog), "response", - G_CALLBACK(auth_callback), input); - - gtk_status_icon_set_blinking(statusicon, TRUE); -} - -static void show_dialog(gpointer data, gpointer user_data) -{ - struct input_data *input = data; - - gtk_widget_show_all(input->dialog); - - gtk_window_present(GTK_WINDOW(input->dialog)); -} - -static NotifyNotification *notify = NULL; - -static void notify_action(NotifyNotification *notify, - gchar *action, gpointer user_data) -{ -} - -static void show_notification(const gchar *summary, const gchar *message, - const gchar *action, gint timeout, GCallback handler) -{ - NotifyActionCallback callback; - GdkScreen *screen; - GdkRectangle area; - - if (notify) { - g_signal_handlers_destroy(notify); - notify_notification_close(notify, NULL); - } - - notify = notify_notification_new(summary, message, - "stock_bluetooth", NULL); - - notify_notification_set_timeout(notify, timeout); - - if (gtk_status_icon_get_visible(statusicon) == TRUE) { - gtk_status_icon_get_geometry(statusicon, &screen, &area, NULL); - - notify_notification_set_hint_int32(notify, - "x", area.x + area.width / 2); - notify_notification_set_hint_int32(notify, - "y", area.y + area.height / 2); - } - - notify_notification_set_urgency(notify, NOTIFY_URGENCY_NORMAL); - - callback = handler ? NOTIFY_ACTION_CALLBACK(handler) : notify_action; - - notify_notification_add_action(notify, "default", "action", - callback, NULL, NULL); - if (action != NULL) - notify_notification_add_action(notify, "button", action, - callback, NULL, NULL); - - notify_notification_show(notify, NULL); -} - -static void close_notification(void) -{ - if (notify) { - g_signal_handlers_destroy(notify); - notify_notification_close(notify, NULL); - notify = NULL; - } -} - -typedef struct { - GObject parent; -} PasskeyAgent; - -typedef struct { - GObjectClass parent; -} PasskeyAgentClass; - -static GObjectClass *passkey_agent_parent; - -G_DEFINE_TYPE(PasskeyAgent, passkey_agent, G_TYPE_OBJECT) - -#define PASSKEY_AGENT_OBJECT_TYPE (passkey_agent_get_type()) - -#define PASSKEY_AGENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \ - PASSKEY_AGENT_OBJECT_TYPE, PasskeyAgent)) - -static void passkey_agent_finalize(GObject *obj) -{ - passkey_agent_parent->finalize(obj); -} - -static void passkey_agent_init(PasskeyAgent *obj) -{ -} - -static void passkey_agent_class_init(PasskeyAgentClass *klass) -{ - GObjectClass *gobject_class; - - passkey_agent_parent = g_type_class_peek_parent(klass); - - gobject_class = G_OBJECT_CLASS(klass); - gobject_class->finalize = passkey_agent_finalize; -} - -static PasskeyAgent *passkey_agent_new(const char *path) -{ - PasskeyAgent *agent; - - agent = g_object_new(PASSKEY_AGENT_OBJECT_TYPE, NULL); - - dbus_g_connection_register_g_object(conn, path, G_OBJECT(agent)); - - return agent; -} - -static void notification_closed(GObject *object, gpointer user_data) -{ - g_list_foreach(input_list, show_dialog, NULL); - - gtk_status_icon_set_blinking(statusicon, FALSE); -} - -static gboolean passkey_agent_request(PasskeyAgent *agent, - const char *path, const char *address, - DBusGMethodInvocation *context) -{ - DBusGProxy *object; - const char *adapter = NULL, *name = NULL; - gchar *device, *line; - - object = dbus_g_proxy_new_for_name(conn, "org.bluez", - path, "org.bluez.Adapter"); - - dbus_g_proxy_call(object, "GetName", NULL, G_TYPE_INVALID, - G_TYPE_STRING, &adapter, G_TYPE_INVALID); - - dbus_g_proxy_call(object, "GetRemoteName", NULL, - G_TYPE_STRING, address, G_TYPE_INVALID, - G_TYPE_STRING, &name, G_TYPE_INVALID); - - if (name) { - if (g_strrstr(name, address)) - device = g_strdup(name); - else - device = g_strdup_printf("%s (%s)", name, address); - } else - device = g_strdup(address); - - passkey_dialog(path, address, device, context); - - /* translators: this is a popup telling you a particular device - * has asked for pairing */ - line = g_strdup_printf(_("Pairing request for '%s'"), device); - g_free(device); - - show_notification(adapter ? adapter : _("Bluetooth device"), - line, _("Enter passkey"), 0, - G_CALLBACK(notification_closed)); - - g_free(line); - - return TRUE; -} - -static gboolean passkey_agent_confirm(PasskeyAgent *agent, - const char *path, const char *address, - const char *value, DBusGMethodInvocation *context) -{ - DBusGProxy *object; - const char *adapter = NULL, *name = NULL; - gchar *device, *line; - - object = dbus_g_proxy_new_for_name(conn, "org.bluez", - path, "org.bluez.Adapter"); - - dbus_g_proxy_call(object, "GetName", NULL, G_TYPE_INVALID, - G_TYPE_STRING, &adapter, G_TYPE_INVALID); - - dbus_g_proxy_call(object, "GetRemoteName", NULL, - G_TYPE_STRING, address, G_TYPE_INVALID, - G_TYPE_STRING, &name, G_TYPE_INVALID); - - if (name) { - if (g_strrstr(name, address)) - device = g_strdup(name); - else - device = g_strdup_printf("%s (%s)", name, address); - } else - device = g_strdup(address); - - confirm_dialog(path, address, value, device, context); - - line = g_strdup_printf(_("Pairing request for '%s'"), device); - g_free(device); - - show_notification(adapter ? adapter : _("Bluetooth device"), - line, _("Confirm pairing"), 0, - G_CALLBACK(notification_closed)); - - g_free (line); - - return TRUE; -} - -static gboolean passkey_agent_cancel(PasskeyAgent *agent, - const char *path, const char *address, GError **error) -{ - GList *list; - GError *result; - struct input_data *input; - - input = g_try_malloc0(sizeof(*input)); - if (!input) - return FALSE; - - input->path = g_strdup(path); - input->address = g_strdup(address); - - list = g_list_find_custom(input_list, input, input_compare); - - g_free(input->address); - g_free(input->path); - g_free(input); - - if (!list || !list->data) - return FALSE; - - input = list->data; - - close_notification(); - - result = g_error_new(AGENT_ERROR, AGENT_ERROR_REJECT, - "Agent callback canceled"); - - dbus_g_method_return_error(input->context, result); - - input_free(input); - - return TRUE; -} - -static gboolean passkey_agent_release(PasskeyAgent *agent, GError **error) -{ - registered_passkey = 0; - - return TRUE; -} - -#include "passkey-agent-glue.h" - -typedef struct { - GObject parent; -} AuthAgent; - -typedef struct { - GObjectClass parent; -} AuthAgentClass; - -static GObjectClass *auth_agent_parent; - -G_DEFINE_TYPE(AuthAgent, auth_agent, G_TYPE_OBJECT) - -#define AUTH_AGENT_OBJECT_TYPE (auth_agent_get_type()) - -#define AUTH_AGENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \ - AUTH_AGENT_OBJECT_TYPE, AuthAgent)) - -static void auth_agent_finalize(GObject *obj) -{ - auth_agent_parent->finalize(obj); -} - -static void auth_agent_init(AuthAgent *obj) -{ -} - -static void auth_agent_class_init(AuthAgentClass *klass) -{ - GObjectClass *gobject_class; - - auth_agent_parent = g_type_class_peek_parent(klass); - - gobject_class = G_OBJECT_CLASS(klass); - gobject_class->finalize = auth_agent_finalize; -} - -static AuthAgent *auth_agent_new(const char *path) -{ - AuthAgent *agent; - - agent = g_object_new(AUTH_AGENT_OBJECT_TYPE, NULL); - - dbus_g_connection_register_g_object(conn, path, G_OBJECT(agent)); - - return agent; -} - -static gboolean auth_agent_authorize(PasskeyAgent *agent, - const char *path, const char *address, const char *service, - const char *uuid, DBusGMethodInvocation *context) -{ - DBusGProxy *object; - const char *adapter = NULL, *name = NULL; - gchar *device, *profile, *line; - - if (auto_authorize == TRUE) { - dbus_g_method_return(context); - return TRUE; - } - - object = dbus_g_proxy_new_for_name(conn, "org.bluez", - path, "org.bluez.Adapter"); - - dbus_g_proxy_call(object, "GetName", NULL, G_TYPE_INVALID, - G_TYPE_STRING, &adapter, G_TYPE_INVALID); - - dbus_g_proxy_call(object, "GetRemoteName", NULL, - G_TYPE_STRING, address, G_TYPE_INVALID, - G_TYPE_STRING, &name, G_TYPE_INVALID); - - object = dbus_g_proxy_new_for_name(conn, "org.bluez", - service, "org.bluez.Service"); - - dbus_g_proxy_call(object, "GetName", NULL, G_TYPE_INVALID, - G_TYPE_STRING, &profile, G_TYPE_INVALID); - - if (name) { - if (g_strrstr(name, address)) - device = g_strdup(name); - else - device = g_strdup_printf("%s (%s)", name, address); - } else - device = g_strdup(address); - - auth_dialog(path, address, service, uuid, device, profile, context); - - line = g_strdup_printf(_("Authorization request for %s"), device); - g_free(device); - - show_notification(adapter ? adapter : _("Bluetooth device"), - line, _("Check authorization"), 0, - G_CALLBACK(notification_closed)); - - g_free(line); - - return TRUE; -} - -static gboolean auth_agent_cancel(PasskeyAgent *agent, - const char *path, const char *address, const char *service, - const char *uuid, DBusGMethodInvocation *context) -{ - GList *list; - GError *result; - struct input_data *input; - - input = g_try_malloc0(sizeof(*input)); - if (!input) - return FALSE; - - input->path = g_strdup(path); - input->address = g_strdup(address); - input->service = g_strdup(service); - input->uuid = g_strdup(uuid); - - list = g_list_find_custom(input_list, input, input_compare); - - g_free(input->uuid); - g_free(input->service); - g_free(input->address); - g_free(input->path); - g_free(input); - - if (!list || !list->data) - return FALSE; - - input = list->data; - - close_notification(); - - result = g_error_new(AGENT_ERROR, AGENT_ERROR_REJECT, - "Agent callback canceled"); - - dbus_g_method_return_error(input->context, result); - - input_free(input); - - return TRUE; -} - -static gboolean auth_agent_release(PasskeyAgent *agent, GError **error) -{ - registered_auth = 0; - - return TRUE; -} - -#include "auth-agent-glue.h" - -static int register_agents(void) -{ - DBusGProxy *object; - GError *error = NULL; - - if (registered_passkey && registered_auth) - return 0; - - object = dbus_g_proxy_new_for_name(conn, "org.bluez", - "/org/bluez", "org.bluez.Security"); - - if (!registered_passkey) { - - dbus_g_proxy_call(object, "RegisterDefaultPasskeyAgent", - &error, G_TYPE_STRING, PASSKEY_AGENT_PATH, - G_TYPE_INVALID, G_TYPE_INVALID); - - if (error != NULL) { - g_error_free(error); - return -1; - } - - registered_passkey = 1; - } - - if (!registered_auth) { - dbus_g_proxy_call(object, "RegisterDefaultAuthorizationAgent", - &error, G_TYPE_STRING, AUTH_AGENT_PATH, - G_TYPE_INVALID, G_TYPE_INVALID); - - if (error != NULL) { - g_error_free(error); - return -1; - } - - registered_auth = 1; - } - - return 0; -} - static void bonding_created(DBusGProxy *object, const char *address, gpointer user_data) { @@ -1376,7 +395,7 @@ static void add_adapter(const char *path static void adapter_added(DBusGProxy *object, const char *path, gpointer user_data) { - register_agents(); + register_agents(statusicon); add_adapter(path); } @@ -1436,8 +455,7 @@ static void name_owner_changed(DBusGProx const char *prev, const char *new, gpointer user_data) { if (!strcmp(name, "org.bluez") && *new == '\0') { - registered_passkey = 0; - registered_auth = 0; + unregister_agents(); g_list_foreach(adapter_list, adapter_disable, NULL); @@ -1462,7 +480,6 @@ static gboolean obexftp_available(void) static int setup_dbus(void) { DBusGProxy *object; - void *agent; object = dbus_g_proxy_new_for_name(conn, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS); @@ -1473,18 +490,7 @@ static int setup_dbus(void) dbus_g_proxy_connect_signal(object, "NameOwnerChanged", G_CALLBACK(name_owner_changed), NULL, NULL); - dbus_g_object_type_install_info(PASSKEY_AGENT_OBJECT_TYPE, - &dbus_glib_passkey_agent_object_info); - - dbus_g_object_type_install_info(AUTH_AGENT_OBJECT_TYPE, - &dbus_glib_auth_agent_object_info); - - dbus_g_error_domain_register(AGENT_ERROR, "org.bluez.Error", - AGENT_ERROR_TYPE); - - agent = passkey_agent_new(PASSKEY_AGENT_PATH); - - agent = auth_agent_new(AUTH_AGENT_PATH); + setup_agent_dbus(conn); return 0; } @@ -1653,11 +659,7 @@ static void wizard_callback(GObject *wid static void activate_callback(GObject *widget, gpointer user_data) { - close_notification(); - - g_list_foreach(input_list, show_dialog, NULL); - - gtk_status_icon_set_blinking(statusicon, FALSE); + flush_input(); } static void popup_callback(GObject *widget, guint button, @@ -1780,7 +782,7 @@ static void gconf_callback(GConfClient * } if (strcmp(entry->key, PREF_AUTO_AUTHORIZE) == 0) - auto_authorize = gconf_value_get_bool(value); + set_auto_authorize (gconf_value_get_bool(value)); } static GOptionEntry options[] = { @@ -1839,8 +841,8 @@ int main(int argc, char *argv[]) g_free(str); } - auto_authorize = gconf_client_get_bool(gconf, - PREF_AUTO_AUTHORIZE, NULL); + set_auto_authorize (gconf_client_get_bool(gconf, + PREF_AUTO_AUTHORIZE, NULL)); gconf_client_add_dir(gconf, PREF_DIR, GCONF_CLIENT_PRELOAD_NONE, NULL); @@ -1866,11 +868,7 @@ int main(int argc, char *argv[]) setup_manager(); - register_agents(); - - //passkey_dialog("/org/bluez/hci0", "00:11:22:33:44:55", "Test", NULL); - //confirm_dialog("/org/bluez/hci0", "00:11:22:33:44:55", "123456", "Test", NULL); - //auth_dialog("/org/bluez/hci0", "00:11:22:33:44:55", "/org/bluez/echo", "", "Test", "Echo service", NULL); + register_agents(statusicon); gtk_main(); @@ -1878,7 +876,7 @@ int main(int argc, char *argv[]) g_object_unref(gconf); - close_notification(); + flush_input(); g_list_foreach(adapter_list, adapter_free, NULL); --- /dev/null 2008-01-24 17:45:36.352009045 +0000 +++ agent.c 2008-02-06 13:43:46.000000000 +0000 @@ -0,0 +1,1026 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2005-2007 Marcel Holtmann <marcel@holtmann.org> + * Copyright (C) 2006-2007 Bastien Nocera <hadess@hadess.net> + * + * + * 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 + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#include <dbus/dbus-glib.h> + +#include <glib/gi18n.h> + +#include <gtk/gtk.h> + +#include "agent.h" +#include "notifications.h" + +static GtkStatusIcon *statusicon = NULL; +static DBusGConnection *conn = NULL; + +#define PASSKEY_AGENT_PATH "/org/bluez/passkey" +#define AUTH_AGENT_PATH "/org/bluez/auth" + +static int volatile registered_passkey = 0; +static int volatile registered_auth = 0; + +static gboolean auto_authorize = FALSE; + +typedef enum { + AGENT_ERROR_REJECT +} AgentError; + +#define AGENT_ERROR (agent_error_quark()) + +#define AGENT_ERROR_TYPE (agent_error_get_type()) + +static GQuark agent_error_quark(void) +{ + static GQuark quark = 0; + if (!quark) + quark = g_quark_from_static_string("agent"); + + return quark; +} + +#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC } + +static GType agent_error_get_type(void) +{ + static GType etype = 0; + if (etype == 0) { + static const GEnumValue values[] = { + ENUM_ENTRY(AGENT_ERROR_REJECT, "Rejected"), + { 0, 0, 0 } + }; + + etype = g_enum_register_static("agent", values); + } + + return etype; +} + +static GList *input_list = NULL; + +struct input_data { + char *path; + char *address; + char *service; + char *uuid; + DBusGMethodInvocation *context; + GtkWidget *dialog; + GtkWidget *button; + GtkWidget *entry; +}; + +static gint input_compare(gconstpointer a, gconstpointer b) +{ + struct input_data *a_data = (struct input_data *) a; + struct input_data *b_data = (struct input_data *) b; + + return strcmp(a_data->address, b_data->address); +} + +static void input_free(struct input_data *input) +{ + gtk_widget_destroy(input->dialog); + + input_list = g_list_remove(input_list, input); + + g_free(input->uuid); + g_free(input->service); + g_free(input->address); + g_free(input->path); + g_free(input); + + if (g_list_length(input_list) == 0) + gtk_status_icon_set_blinking(statusicon, FALSE); +} + +static void passkey_callback(GtkWidget *dialog, + gint response, gpointer user_data) +{ + struct input_data *input = user_data; + + if (response == GTK_RESPONSE_ACCEPT) { + const char *passkey; + passkey = gtk_entry_get_text(GTK_ENTRY(input->entry)); + dbus_g_method_return(input->context, passkey); + } else { + GError *error; + error = g_error_new(AGENT_ERROR, AGENT_ERROR_REJECT, + "Pairing request rejected"); + dbus_g_method_return_error(input->context, error); + } + + input_free(input); +} + +static void confirm_callback(GtkWidget *dialog, + gint response, gpointer user_data) +{ + struct input_data *input = user_data; + + if (response != GTK_RESPONSE_YES) { + GError *error; + error = g_error_new(AGENT_ERROR, AGENT_ERROR_REJECT, + "Confirmation request rejected"); + dbus_g_method_return_error(input->context, error); + } else + dbus_g_method_return(input->context); + + input_free(input); +} + +static void set_trusted(struct input_data *input) +{ + DBusGProxy *object; + gboolean active; + + active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(input->button)); + if (active == FALSE) + return; + + object = dbus_g_proxy_new_for_name(conn, "org.bluez", + input->path, "org.bluez.Adapter"); + + dbus_g_proxy_call(object, "SetTrusted", NULL, + G_TYPE_STRING, input->address, G_TYPE_INVALID, + G_TYPE_INVALID); +} + +static void auth_callback(GtkWidget *dialog, + gint response, gpointer user_data) +{ + struct input_data *input = user_data; + + if (response == GTK_RESPONSE_YES) { + set_trusted(input); + dbus_g_method_return(input->context); + } else { + GError *error; + error = g_error_new(AGENT_ERROR, AGENT_ERROR_REJECT, + "Authorization request rejected"); + dbus_g_method_return_error(input->context, error); + } + + input_free(input); +} + +static void changed_callback(GtkWidget *editable, gpointer user_data) +{ + struct input_data *input = user_data; + const gchar *text; + + text = gtk_entry_get_text(GTK_ENTRY(input->entry)); + + gtk_widget_set_sensitive(input->button, strlen(text) ? TRUE : FALSE); +} + +static void toggled_callback(GtkWidget *button, gpointer user_data) +{ + struct input_data *input = user_data; + gboolean mode; + + mode = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)); + + gtk_entry_set_visibility(GTK_ENTRY(input->entry), mode); +} + +static void passkey_dialog(const char *path, const char *address, + const gchar *device, DBusGMethodInvocation *context) +{ + GtkWidget *dialog; + GtkWidget *button; + GtkWidget *image; + GtkWidget *label; + GtkWidget *entry; + GtkWidget *table; + GtkWidget *vbox; + struct input_data *input; + gchar *markup; + + input = g_try_malloc0(sizeof(*input)); + if (!input) + return; + + input->path = g_strdup(path); + input->address = g_strdup(address); + + input->context = context; + + dialog = gtk_dialog_new(); + + gtk_window_set_title(GTK_WINDOW(dialog), _("Authentication request")); + + gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); + + gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER); + + gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE); + + gtk_window_set_urgency_hint(GTK_WINDOW(dialog), TRUE); + + gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE); + + input->dialog = dialog; + + button = gtk_dialog_add_button(GTK_DIALOG(dialog), + GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT); + + button = gtk_dialog_add_button(GTK_DIALOG(dialog), + GTK_STOCK_OK, GTK_RESPONSE_ACCEPT); + + gtk_widget_grab_default(button); + + gtk_widget_set_sensitive(button, FALSE); + + input->button = button; + + table = gtk_table_new(5, 2, FALSE); + + gtk_table_set_row_spacings(GTK_TABLE(table), 4); + gtk_table_set_col_spacings(GTK_TABLE(table), 20); + + gtk_container_set_border_width(GTK_CONTAINER(table), 12); + + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table); + + image = gtk_image_new_from_icon_name(GTK_STOCK_DIALOG_AUTHENTICATION, + GTK_ICON_SIZE_DIALOG); + + gtk_misc_set_alignment(GTK_MISC(image), 0.0, 0.0); + + gtk_table_attach(GTK_TABLE(table), image, 0, 1, 0, 5, + GTK_SHRINK, GTK_FILL, 0, 0); + + vbox = gtk_vbox_new(FALSE, 6); + + label = gtk_label_new(_("Pairing request for device:")); + + gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); + + gtk_container_add(GTK_CONTAINER(vbox), label); + + gtk_table_attach(GTK_TABLE(table), vbox, 1, 2, 0, 1, + GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0); + + label = gtk_label_new(NULL); + + markup = g_strdup_printf("<b>%s</b>", device); + gtk_label_set_markup(GTK_LABEL(label), markup); + g_free(markup); + + gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); + + gtk_label_set_selectable(GTK_LABEL(label), TRUE); + + gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); + + gtk_widget_set_size_request(GTK_WIDGET(label), 280, -1); + + gtk_container_add(GTK_CONTAINER(vbox), label); + + vbox = gtk_vbox_new(FALSE, 6); + + label = gtk_label_new(_("Enter passkey for authentication:")); + + gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); + + gtk_container_add(GTK_CONTAINER(vbox), label); + + gtk_table_attach(GTK_TABLE(table), vbox, 1, 2, 2, 3, + GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0); + + entry = gtk_entry_new(); + + gtk_entry_set_max_length(GTK_ENTRY(entry), 16); + + gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE); + + gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE); + + input->entry = entry; + + g_signal_connect(G_OBJECT(entry), "changed", + G_CALLBACK(changed_callback), input); + + gtk_container_add(GTK_CONTAINER(vbox), entry); + + button = gtk_check_button_new_with_label(_("Show input")); + + g_signal_connect(G_OBJECT(button), "toggled", + G_CALLBACK(toggled_callback), input); + + gtk_container_add(GTK_CONTAINER(vbox), button); + + input_list = g_list_append(input_list, input); + + g_signal_connect(G_OBJECT(dialog), "response", + G_CALLBACK(passkey_callback), input); + + gtk_status_icon_set_blinking(statusicon, TRUE); +} + +static void confirm_dialog(const char *path, const char *address, + const char *value, const gchar *device, + DBusGMethodInvocation *context) +{ + GtkWidget *dialog; + GtkWidget *button; + GtkWidget *image; + GtkWidget *label; + GtkWidget *table; + GtkWidget *vbox; + gchar *markup; + struct input_data *input; + + input = g_try_malloc0(sizeof(*input)); + if (!input) + return; + + input->path = g_strdup(path); + input->address = g_strdup(address); + + input->context = context; + + dialog = gtk_dialog_new(); + + gtk_window_set_title(GTK_WINDOW(dialog), _("Confirmation request")); + + gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); + + gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER); + + gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE); + + gtk_window_set_urgency_hint(GTK_WINDOW(dialog), TRUE); + + gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE); + + input->dialog = dialog; + + button = gtk_dialog_add_button(GTK_DIALOG(dialog), + GTK_STOCK_NO, GTK_RESPONSE_NO); + + button = gtk_dialog_add_button(GTK_DIALOG(dialog), + GTK_STOCK_YES, GTK_RESPONSE_YES); + + table = gtk_table_new(5, 2, FALSE); + + gtk_table_set_row_spacings(GTK_TABLE(table), 4); + gtk_table_set_col_spacings(GTK_TABLE(table), 20); + + gtk_container_set_border_width(GTK_CONTAINER(table), 12); + + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table); + + image = gtk_image_new_from_icon_name(GTK_STOCK_DIALOG_AUTHENTICATION, + GTK_ICON_SIZE_DIALOG); + + gtk_misc_set_alignment(GTK_MISC(image), 0.0, 0.0); + + gtk_table_attach(GTK_TABLE(table), image, 0, 1, 0, 5, + GTK_SHRINK, GTK_FILL, 0, 0); + + vbox = gtk_vbox_new(FALSE, 6); + label = gtk_label_new(_("Pairing request for device:")); + + gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); + + gtk_container_add(GTK_CONTAINER(vbox), label); + + gtk_table_attach(GTK_TABLE(table), vbox, 1, 2, 0, 1, + GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0); + + label = gtk_label_new(NULL); + + markup = g_strdup_printf("<b>%s</b>", device); + gtk_label_set_markup(GTK_LABEL(label), markup); + g_free(markup); + + gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); + + gtk_label_set_selectable(GTK_LABEL(label), TRUE); + + gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); + + gtk_widget_set_size_request(GTK_WIDGET(label), 280, -1); + + gtk_container_add(GTK_CONTAINER(vbox), label); + + vbox = gtk_vbox_new(FALSE, 6); + + label = gtk_label_new(_("Confirm value for authentication:")); + + gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); + + gtk_container_add(GTK_CONTAINER(vbox), label); + + gtk_table_attach(GTK_TABLE(table), vbox, 1, 2, 2, 3, + GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0); + + label = gtk_label_new(NULL); + + markup = g_strdup_printf("<b>%s</b>\n", value); + + gtk_label_set_markup(GTK_LABEL(label), markup); + + g_free(markup); + + gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); + + gtk_container_add(GTK_CONTAINER(vbox), label); + + input_list = g_list_append(input_list, input); + + g_signal_connect(G_OBJECT(dialog), "response", + G_CALLBACK(confirm_callback), input); + + gtk_status_icon_set_blinking(statusicon, TRUE); +} + +static void auth_dialog(const char *path, const char *address, + const char *service, const char *uuid, const gchar *device, + const gchar *profile, DBusGMethodInvocation *context) +{ + GtkWidget *dialog; + GtkWidget *button; + GtkWidget *image; + GtkWidget *label; + GtkWidget *table; + GtkWidget *vbox; + gchar *markup, *text; + struct input_data *input; + + input = g_try_malloc0(sizeof(*input)); + if (!input) + return; + + input->path = g_strdup(path); + input->address = g_strdup(address); + input->service = g_strdup(service); + input->uuid = g_strdup(uuid); + + input->context = context; + + dialog = gtk_dialog_new(); + + gtk_window_set_title(GTK_WINDOW(dialog), _("Authorization request")); + + gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); + + gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER); + + gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE); + + gtk_window_set_urgency_hint(GTK_WINDOW(dialog), TRUE); + + gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE); + + input->dialog = dialog; + + button = gtk_dialog_add_button(GTK_DIALOG(dialog), + GTK_STOCK_NO, GTK_RESPONSE_NO); + + button = gtk_dialog_add_button(GTK_DIALOG(dialog), + GTK_STOCK_YES, GTK_RESPONSE_YES); + + table = gtk_table_new(5, 2, FALSE); + + gtk_table_set_row_spacings(GTK_TABLE(table), 4); + gtk_table_set_col_spacings(GTK_TABLE(table), 20); + + gtk_container_set_border_width(GTK_CONTAINER(table), 12); + + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table); + + image = gtk_image_new_from_icon_name(GTK_STOCK_DIALOG_AUTHENTICATION, + GTK_ICON_SIZE_DIALOG); + + gtk_misc_set_alignment(GTK_MISC(image), 0.0, 0.0); + + gtk_table_attach(GTK_TABLE(table), image, 0, 1, 0, 5, + GTK_SHRINK, GTK_FILL, 0, 0); + + vbox = gtk_vbox_new(FALSE, 6); + + label = gtk_label_new(_("Authorization request for device:")); + + gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); + + gtk_table_attach(GTK_TABLE(table), label, 1, 2, 0, 1, + GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0); + + label = gtk_label_new(NULL); + + markup = g_strdup_printf("<b>%s</b>", device); + gtk_label_set_markup(GTK_LABEL(label), markup); + g_free(markup); + + gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); + + gtk_label_set_selectable(GTK_LABEL(label), TRUE); + + gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); + + gtk_widget_set_size_request(GTK_WIDGET(label), 280, -1); + + gtk_container_add(GTK_CONTAINER(vbox), label); + + gtk_table_attach(GTK_TABLE(table), vbox, 1, 2, 2, 3, + GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0); + + label = gtk_label_new(NULL); + + /* translators: Whether to grant access to a particular service + * to the device mentioned */ + markup = g_strdup_printf("<i>%s</i>", profile); + text = g_strdup_printf(_("Grant access to %s?"), markup); + g_free(markup); + + markup = g_strdup_printf("%s\n", text); + gtk_label_set_markup(GTK_LABEL(label), markup); + g_free(markup); + + g_free(text); + + gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); + + gtk_container_add(GTK_CONTAINER(vbox), label); + + button = gtk_check_button_new_with_label(_("Always grant access")); + + input->button = button; + + gtk_container_add(GTK_CONTAINER(vbox), button); + + input_list = g_list_append(input_list, input); + + g_signal_connect(G_OBJECT(dialog), "response", + G_CALLBACK(auth_callback), input); + + gtk_status_icon_set_blinking(statusicon, TRUE); +} + +static void show_dialog(gpointer data, gpointer user_data) +{ + struct input_data *input = data; + + gtk_widget_show_all(input->dialog); + + gtk_window_present(GTK_WINDOW(input->dialog)); +} + +typedef struct { + GObject parent; +} PasskeyAgent; + +typedef struct { + GObjectClass parent; +} PasskeyAgentClass; + +static GObjectClass *passkey_agent_parent; + +G_DEFINE_TYPE(PasskeyAgent, passkey_agent, G_TYPE_OBJECT) + +#define PASSKEY_AGENT_OBJECT_TYPE (passkey_agent_get_type()) + +#define PASSKEY_AGENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + PASSKEY_AGENT_OBJECT_TYPE, PasskeyAgent)) + +static void passkey_agent_finalize(GObject *obj) +{ + passkey_agent_parent->finalize(obj); +} + +static void passkey_agent_init(PasskeyAgent *obj) +{ +} + +static void passkey_agent_class_init(PasskeyAgentClass *klass) +{ + GObjectClass *gobject_class; + + passkey_agent_parent = g_type_class_peek_parent(klass); + + gobject_class = G_OBJECT_CLASS(klass); + gobject_class->finalize = passkey_agent_finalize; +} + +static PasskeyAgent *passkey_agent_new(const char *path) +{ + PasskeyAgent *agent; + + agent = g_object_new(PASSKEY_AGENT_OBJECT_TYPE, NULL); + + dbus_g_connection_register_g_object(conn, path, G_OBJECT(agent)); + + return agent; +} + +static void notification_closed(GObject *object, gpointer user_data) +{ + g_list_foreach(input_list, show_dialog, NULL); + + gtk_status_icon_set_blinking(statusicon, FALSE); +} + +static gboolean passkey_agent_request(PasskeyAgent *agent, + const char *path, const char *address, + DBusGMethodInvocation *context) +{ + DBusGProxy *object; + const char *adapter = NULL, *name = NULL; + gchar *device, *line; + + object = dbus_g_proxy_new_for_name(conn, "org.bluez", + path, "org.bluez.Adapter"); + + dbus_g_proxy_call(object, "GetName", NULL, G_TYPE_INVALID, + G_TYPE_STRING, &adapter, G_TYPE_INVALID); + + dbus_g_proxy_call(object, "GetRemoteName", NULL, + G_TYPE_STRING, address, G_TYPE_INVALID, + G_TYPE_STRING, &name, G_TYPE_INVALID); + + if (name) { + if (g_strrstr(name, address)) + device = g_strdup(name); + else + device = g_strdup_printf("%s (%s)", name, address); + } else + device = g_strdup(address); + + passkey_dialog(path, address, device, context); + + /* translators: this is a popup telling you a particular device + * has asked for pairing */ + line = g_strdup_printf(_("Pairing request for '%s'"), device); + g_free(device); + + show_notification(adapter ? adapter : _("Bluetooth device"), + line, _("Enter passkey"), 0, + G_CALLBACK(notification_closed)); + + g_free(line); + + return TRUE; +} + +static gboolean passkey_agent_confirm(PasskeyAgent *agent, + const char *path, const char *address, + const char *value, DBusGMethodInvocation *context) +{ + DBusGProxy *object; + const char *adapter = NULL, *name = NULL; + gchar *device, *line; + + object = dbus_g_proxy_new_for_name(conn, "org.bluez", + path, "org.bluez.Adapter"); + + dbus_g_proxy_call(object, "GetName", NULL, G_TYPE_INVALID, + G_TYPE_STRING, &adapter, G_TYPE_INVALID); + + dbus_g_proxy_call(object, "GetRemoteName", NULL, + G_TYPE_STRING, address, G_TYPE_INVALID, + G_TYPE_STRING, &name, G_TYPE_INVALID); + + if (name) { + if (g_strrstr(name, address)) + device = g_strdup(name); + else + device = g_strdup_printf("%s (%s)", name, address); + } else + device = g_strdup(address); + + confirm_dialog(path, address, value, device, context); + + line = g_strdup_printf(_("Pairing request for '%s'"), device); + g_free(device); + + show_notification(adapter ? adapter : _("Bluetooth device"), + line, _("Confirm pairing"), 0, + G_CALLBACK(notification_closed)); + + g_free (line); + + return TRUE; +} + +static gboolean passkey_agent_cancel(PasskeyAgent *agent, + const char *path, const char *address, GError **error) +{ + GList *list; + GError *result; + struct input_data *input; + + input = g_try_malloc0(sizeof(*input)); + if (!input) + return FALSE; + + input->path = g_strdup(path); + input->address = g_strdup(address); + + list = g_list_find_custom(input_list, input, input_compare); + + g_free(input->address); + g_free(input->path); + g_free(input); + + if (!list || !list->data) + return FALSE; + + input = list->data; + + close_notification(); + + result = g_error_new(AGENT_ERROR, AGENT_ERROR_REJECT, + "Agent callback canceled"); + + dbus_g_method_return_error(input->context, result); + + input_free(input); + + return TRUE; +} + +static gboolean passkey_agent_release(PasskeyAgent *agent, GError **error) +{ + registered_passkey = 0; + + return TRUE; +} + +#include "passkey-agent-glue.h" + +typedef struct { + GObject parent; +} AuthAgent; + +typedef struct { + GObjectClass parent; +} AuthAgentClass; + +static GObjectClass *auth_agent_parent; + +G_DEFINE_TYPE(AuthAgent, auth_agent, G_TYPE_OBJECT) + +#define AUTH_AGENT_OBJECT_TYPE (auth_agent_get_type()) + +#define AUTH_AGENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + AUTH_AGENT_OBJECT_TYPE, AuthAgent)) + +static void auth_agent_finalize(GObject *obj) +{ + auth_agent_parent->finalize(obj); +} + +static void auth_agent_init(AuthAgent *obj) +{ +} + +static void auth_agent_class_init(AuthAgentClass *klass) +{ + GObjectClass *gobject_class; + + auth_agent_parent = g_type_class_peek_parent(klass); + + gobject_class = G_OBJECT_CLASS(klass); + gobject_class->finalize = auth_agent_finalize; +} + +static AuthAgent *auth_agent_new(const char *path) +{ + AuthAgent *agent; + + agent = g_object_new(AUTH_AGENT_OBJECT_TYPE, NULL); + + dbus_g_connection_register_g_object(conn, path, G_OBJECT(agent)); + + return agent; +} + +static gboolean auth_agent_authorize(PasskeyAgent *agent, + const char *path, const char *address, const char *service, + const char *uuid, DBusGMethodInvocation *context) +{ + DBusGProxy *object; + const char *adapter = NULL, *name = NULL; + gchar *device, *profile, *line; + + if (auto_authorize == TRUE) { + dbus_g_method_return(context); + return TRUE; + } + + object = dbus_g_proxy_new_for_name(conn, "org.bluez", + path, "org.bluez.Adapter"); + + dbus_g_proxy_call(object, "GetName", NULL, G_TYPE_INVALID, + G_TYPE_STRING, &adapter, G_TYPE_INVALID); + + dbus_g_proxy_call(object, "GetRemoteName", NULL, + G_TYPE_STRING, address, G_TYPE_INVALID, + G_TYPE_STRING, &name, G_TYPE_INVALID); + + object = dbus_g_proxy_new_for_name(conn, "org.bluez", + service, "org.bluez.Service"); + + dbus_g_proxy_call(object, "GetName", NULL, G_TYPE_INVALID, + G_TYPE_STRING, &profile, G_TYPE_INVALID); + + if (name) { + if (g_strrstr(name, address)) + device = g_strdup(name); + else + device = g_strdup_printf("%s (%s)", name, address); + } else + device = g_strdup(address); + + auth_dialog(path, address, service, uuid, device, profile, context); + + line = g_strdup_printf(_("Authorization request for %s"), device); + g_free(device); + + show_notification(adapter ? adapter : _("Bluetooth device"), + line, _("Check authorization"), 0, + G_CALLBACK(notification_closed)); + + g_free(line); + + return TRUE; +} + +static gboolean auth_agent_cancel(PasskeyAgent *agent, + const char *path, const char *address, const char *service, + const char *uuid, DBusGMethodInvocation *context) +{ + GList *list; + GError *result; + struct input_data *input; + + input = g_try_malloc0(sizeof(*input)); + if (!input) + return FALSE; + + input->path = g_strdup(path); + input->address = g_strdup(address); + input->service = g_strdup(service); + input->uuid = g_strdup(uuid); + + list = g_list_find_custom(input_list, input, input_compare); + + g_free(input->uuid); + g_free(input->service); + g_free(input->address); + g_free(input->path); + g_free(input); + + if (!list || !list->data) + return FALSE; + + input = list->data; + + close_notification(); + + result = g_error_new(AGENT_ERROR, AGENT_ERROR_REJECT, + "Agent callback canceled"); + + dbus_g_method_return_error(input->context, result); + + input_free(input); + + return TRUE; +} + +static gboolean auth_agent_release(PasskeyAgent *agent, GError **error) +{ + registered_auth = 0; + + return TRUE; +} + +#include "auth-agent-glue.h" + +int register_agents(GtkStatusIcon *_statusicon) +{ + DBusGProxy *object; + GError *error = NULL; + + if (registered_passkey && registered_auth) + return 0; + + object = dbus_g_proxy_new_for_name(conn, "org.bluez", + "/org/bluez", "org.bluez.Security"); + + if (!registered_passkey) { + dbus_g_proxy_call(object, "RegisterDefaultPasskeyAgent", + &error, G_TYPE_STRING, PASSKEY_AGENT_PATH, + G_TYPE_INVALID, G_TYPE_INVALID); + + if (error != NULL) { + g_error_free(error); + return -1; + } + + registered_passkey = 1; + } + + if (!registered_auth) { + dbus_g_proxy_call(object, "RegisterDefaultAuthorizationAgent", + &error, G_TYPE_STRING, AUTH_AGENT_PATH, + G_TYPE_INVALID, G_TYPE_INVALID); + + if (error != NULL) { + g_error_free(error); + return -1; + } + + registered_auth = 1; + } + + /* To test a particular type of authorization or pairing question */ + //passkey_dialog("/org/bluez/hci0", "00:11:22:33:44:55", "Test", NULL); + //confirm_dialog("/org/bluez/hci0", "00:11:22:33:44:55", "123456", "Test", NULL); + //auth_dialog("/org/bluez/hci0", "00:11:22:33:44:55", "/org/bluez/echo", "", "Test", "Echo service", NULL); + + statusicon = g_object_ref(_statusicon); + + return 0; +} + +void unregister_agents(void) +{ + registered_passkey = 0; + registered_auth = 0; + + if (conn) { + dbus_g_connection_unref(conn); + conn = NULL; + } + if (statusicon) { + g_object_unref(statusicon); + statusicon = NULL; + } +} + +void flush_input(void) +{ + close_notification(); + + g_list_foreach(input_list, show_dialog, NULL); + + gtk_status_icon_set_blinking(statusicon, FALSE); +} + +void setup_agent_dbus(DBusGConnection *_conn) +{ + void *agent; + + dbus_g_object_type_install_info(PASSKEY_AGENT_OBJECT_TYPE, + &dbus_glib_passkey_agent_object_info); + + dbus_g_object_type_install_info(AUTH_AGENT_OBJECT_TYPE, + &dbus_glib_auth_agent_object_info); + + dbus_g_error_domain_register(AGENT_ERROR, "org.bluez.Error", + AGENT_ERROR_TYPE); + + conn = dbus_g_connection_ref(_conn); + + agent = passkey_agent_new(PASSKEY_AGENT_PATH); + + agent = auth_agent_new(AUTH_AGENT_PATH); +} + +void set_auto_authorize(gboolean value) +{ + auto_authorize = value; +} + --- /dev/null 2008-01-24 17:45:36.352009045 +0000 +++ agent.h 2008-02-06 13:41:18.000000000 +0000 @@ -0,0 +1,29 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2005-2007 Marcel Holtmann <marcel@holtmann.org> + * Copyright (C) 2006-2007 Bastien Nocera <hadess@hadess.net> + * + * + * 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 + * + */ + +int register_agents(GtkStatusIcon *_statusicon); +void unregister_agents(void); +void flush_input(void); +void setup_agent_dbus(DBusGConnection *_conn); +void set_auto_authorize(gboolean auto_authorize); --- /dev/null 2008-01-24 17:45:36.352009045 +0000 +++ notifications.c 2008-02-01 18:01:34.000000000 +0000 @@ -0,0 +1,91 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2005-2007 Marcel Holtmann <marcel@holtmann.org> + * Copyright (C) 2006-2007 Bastien Nocera <hadess@hadess.net> + * + * + * 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 + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <glib/gi18n.h> + +#include <gtk/gtk.h> +#include <libnotify/notify.h> + +#include "notifications.h" + +extern GtkStatusIcon *statusicon; + +static NotifyNotification *notify = NULL; + +static void notify_action(NotifyNotification *notify, + gchar *action, gpointer user_data) +{ +} +void show_notification(const gchar *summary, const gchar *message, + const gchar *action, gint timeout, GCallback handler) +{ + NotifyActionCallback callback; + GdkScreen *screen; + GdkRectangle area; + + if (notify) { + g_signal_handlers_destroy(notify); + notify_notification_close(notify, NULL); + } + + notify = notify_notification_new(summary, message, + "stock_bluetooth", NULL); + + notify_notification_set_timeout(notify, timeout); + + if (gtk_status_icon_get_visible(statusicon) == TRUE) { + gtk_status_icon_get_geometry(statusicon, &screen, &area, NULL); + + notify_notification_set_hint_int32(notify, + "x", area.x + area.width / 2); + notify_notification_set_hint_int32(notify, + "y", area.y + area.height / 2); + } + + notify_notification_set_urgency(notify, NOTIFY_URGENCY_NORMAL); + + callback = handler ? NOTIFY_ACTION_CALLBACK(handler) : notify_action; + + notify_notification_add_action(notify, "default", "action", + callback, NULL, NULL); + if (action != NULL) + notify_notification_add_action(notify, "button", action, + callback, NULL, NULL); + + notify_notification_show(notify, NULL); +} + +void close_notification(void) +{ + if (notify) { + g_signal_handlers_destroy(notify); + notify_notification_close(notify, NULL); + notify = NULL; + } +} + --- /dev/null 2008-01-24 17:45:36.352009045 +0000 +++ notifications.h 2008-02-01 17:33:58.000000000 +0000 @@ -0,0 +1,4 @@ +void show_notification(const gchar *summary, const gchar *message, + const gchar *action, gint timeout, GCallback handler); +void close_notification(void); + [-- Attachment #3: Type: text/plain, Size: 228 bytes --] ------------------------------------------------------------------------- This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2008. http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ [-- Attachment #4: Type: text/plain, Size: 164 bytes --] _______________________________________________ Bluez-devel mailing list Bluez-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/bluez-devel ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Bluez-devel] [PATCH] Split agents 2008-02-06 13:46 ` Bastien Nocera @ 2008-02-07 1:13 ` Bastien Nocera 2008-02-10 1:21 ` Marcel Holtmann 0 siblings, 1 reply; 6+ messages in thread From: Bastien Nocera @ 2008-02-07 1:13 UTC (permalink / raw) To: BlueZ development [-- Attachment #1: Type: text/plain, Size: 372 bytes --] On Wed, 2008-02-06 at 13:46 +0000, Bastien Nocera wrote: > On Fri, 2008-02-01 at 17:44 +0000, Bastien Nocera wrote: > > Heya, > > > > First draft patch to split the agents away from the main program. Seems > > to work fine for me. > > > > This is mostly moving functions around though. > > Updated patch following the comments from Marcel. Patch that compiles again. [-- Attachment #2: bluez-gnome-split-agents-3.patch --] [-- Type: text/x-patch, Size: 61089 bytes --] Index: Makefile.am =================================================================== RCS file: /cvsroot/bluez/gnome/applet/Makefile.am,v retrieving revision 1.21 diff -u -p -r1.21 Makefile.am --- Makefile.am 28 Jul 2007 23:57:16 -0000 1.21 +++ Makefile.am 7 Feb 2008 01:12:36 -0000 @@ -1,7 +1,7 @@ bin_PROGRAMS = bluetooth-applet -bluetooth_applet_SOURCES = main.c +bluetooth_applet_SOURCES = main.c agent.c agent.h notifications.c notifications.h bluetooth_applet_LDADD = \ @NOTIFY_LIBS@ @GCONF_LIBS@ \ Index: main.c =================================================================== RCS file: /cvsroot/bluez/gnome/applet/main.c,v retrieving revision 1.103 diff -u -p -r1.103 main.c --- main.c 7 Feb 2008 00:14:32 -0000 1.103 +++ main.c 7 Feb 2008 01:12:36 -0000 @@ -3,7 +3,7 @@ * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2005-2008 Marcel Holtmann <marcel@holtmann.org> - * Copyright (C) 2006-2007 Bastien Nocera <hadess@hadess.net> + * Copyright (C) 2006-2008 Bastien Nocera <hadess@hadess.net> * * * This program is free software; you can redistribute it and/or modify @@ -47,17 +47,13 @@ #include "bluetooth-instance.h" #include "bluetooth-device-selection.h" +#include "agent.h" +#include "notifications.h" +static DBusGConnection *conn = NULL; +static GtkStatusIcon *statusicon = NULL; static gboolean singleton = FALSE; -#define PASSKEY_AGENT_PATH "/org/bluez/passkey" -#define AUTH_AGENT_PATH "/org/bluez/auth" - -static int volatile registered_passkey = 0; -static int volatile registered_auth = 0; - -static DBusGConnection *conn; - #ifdef HAVE_HAL static gboolean use_hal = FALSE; #endif @@ -78,8 +74,6 @@ typedef enum { static int icon_policy = ICON_POLICY_PRESENT; -static gboolean auto_authorize = FALSE; - #define PREF_DIR "/apps/bluetooth-manager" #define PREF_USE_HAL PREF_DIR "/use_hal" #define PREF_ICON_POLICY PREF_DIR "/icon_policy" @@ -87,984 +81,9 @@ static gboolean auto_authorize = FALSE; static GConfClient* gconf; -static GtkStatusIcon *statusicon = NULL; - static GtkWidget *menuitem_sendto = NULL; static GtkWidget *menuitem_browse = NULL; -typedef enum { - AGENT_ERROR_REJECT -} AgentError; - -#define AGENT_ERROR (agent_error_quark()) - -#define AGENT_ERROR_TYPE (agent_error_get_type()) - -static GQuark agent_error_quark(void) -{ - static GQuark quark = 0; - if (!quark) - quark = g_quark_from_static_string("agent"); - - return quark; -} - -#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC } - -static GType agent_error_get_type(void) -{ - static GType etype = 0; - if (etype == 0) { - static const GEnumValue values[] = { - ENUM_ENTRY(AGENT_ERROR_REJECT, "Rejected"), - { 0, 0, 0 } - }; - - etype = g_enum_register_static("agent", values); - } - - return etype; -} - -static GList *input_list = NULL; - -struct input_data { - char *path; - char *address; - char *service; - char *uuid; - DBusGMethodInvocation *context; - GtkWidget *dialog; - GtkWidget *button; - GtkWidget *entry; -}; - -static gint input_compare(gconstpointer a, gconstpointer b) -{ - struct input_data *a_data = (struct input_data *) a; - struct input_data *b_data = (struct input_data *) b; - - return strcmp(a_data->address, b_data->address); -} - -static void input_free(struct input_data *input) -{ - gtk_widget_destroy(input->dialog); - - input_list = g_list_remove(input_list, input); - - g_free(input->uuid); - g_free(input->service); - g_free(input->address); - g_free(input->path); - g_free(input); - - if (g_list_length(input_list) == 0) - gtk_status_icon_set_blinking(statusicon, FALSE); -} - -static void passkey_callback(GtkWidget *dialog, - gint response, gpointer user_data) -{ - struct input_data *input = user_data; - - if (response == GTK_RESPONSE_ACCEPT) { - const char *passkey; - passkey = gtk_entry_get_text(GTK_ENTRY(input->entry)); - dbus_g_method_return(input->context, passkey); - } else { - GError *error; - error = g_error_new(AGENT_ERROR, AGENT_ERROR_REJECT, - "Pairing request rejected"); - dbus_g_method_return_error(input->context, error); - } - - input_free(input); -} - -static void confirm_callback(GtkWidget *dialog, - gint response, gpointer user_data) -{ - struct input_data *input = user_data; - - if (response != GTK_RESPONSE_YES) { - GError *error; - error = g_error_new(AGENT_ERROR, AGENT_ERROR_REJECT, - "Confirmation request rejected"); - dbus_g_method_return_error(input->context, error); - } else - dbus_g_method_return(input->context); - - input_free(input); -} - -static void set_trusted(struct input_data *input) -{ - DBusGProxy *object; - gboolean active; - - active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(input->button)); - if (active == FALSE) - return; - - object = dbus_g_proxy_new_for_name(conn, "org.bluez", - input->path, "org.bluez.Adapter"); - - dbus_g_proxy_call(object, "SetTrusted", NULL, - G_TYPE_STRING, input->address, G_TYPE_INVALID, - G_TYPE_INVALID); -} - -static void auth_callback(GtkWidget *dialog, - gint response, gpointer user_data) -{ - struct input_data *input = user_data; - - if (response == GTK_RESPONSE_YES) { - set_trusted(input); - dbus_g_method_return(input->context); - } else { - GError *error; - error = g_error_new(AGENT_ERROR, AGENT_ERROR_REJECT, - "Authorization request rejected"); - dbus_g_method_return_error(input->context, error); - } - - input_free(input); -} - -static void changed_callback(GtkWidget *editable, gpointer user_data) -{ - struct input_data *input = user_data; - const gchar *text; - - text = gtk_entry_get_text(GTK_ENTRY(input->entry)); - - gtk_widget_set_sensitive(input->button, strlen(text) ? TRUE : FALSE); -} - -static void toggled_callback(GtkWidget *button, gpointer user_data) -{ - struct input_data *input = user_data; - gboolean mode; - - mode = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)); - - gtk_entry_set_visibility(GTK_ENTRY(input->entry), mode); -} - -static void passkey_dialog(const char *path, const char *address, - const gchar *device, DBusGMethodInvocation *context) -{ - GtkWidget *dialog; - GtkWidget *button; - GtkWidget *image; - GtkWidget *label; - GtkWidget *entry; - GtkWidget *table; - GtkWidget *vbox; - struct input_data *input; - gchar *markup; - - input = g_try_malloc0(sizeof(*input)); - if (!input) - return; - - input->path = g_strdup(path); - input->address = g_strdup(address); - - input->context = context; - - dialog = gtk_dialog_new(); - - gtk_window_set_title(GTK_WINDOW(dialog), _("Authentication request")); - - gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); - - gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER); - - gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE); - - gtk_window_set_urgency_hint(GTK_WINDOW(dialog), TRUE); - - gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE); - - input->dialog = dialog; - - button = gtk_dialog_add_button(GTK_DIALOG(dialog), - GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT); - - button = gtk_dialog_add_button(GTK_DIALOG(dialog), - GTK_STOCK_OK, GTK_RESPONSE_ACCEPT); - - gtk_widget_grab_default(button); - - gtk_widget_set_sensitive(button, FALSE); - - input->button = button; - - table = gtk_table_new(5, 2, FALSE); - - gtk_table_set_row_spacings(GTK_TABLE(table), 4); - gtk_table_set_col_spacings(GTK_TABLE(table), 20); - - gtk_container_set_border_width(GTK_CONTAINER(table), 12); - - gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table); - - image = gtk_image_new_from_icon_name(GTK_STOCK_DIALOG_AUTHENTICATION, - GTK_ICON_SIZE_DIALOG); - - gtk_misc_set_alignment(GTK_MISC(image), 0.0, 0.0); - - gtk_table_attach(GTK_TABLE(table), image, 0, 1, 0, 5, - GTK_SHRINK, GTK_FILL, 0, 0); - - vbox = gtk_vbox_new(FALSE, 6); - - label = gtk_label_new(_("Pairing request for device:")); - - gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); - - gtk_container_add(GTK_CONTAINER(vbox), label); - - gtk_table_attach(GTK_TABLE(table), vbox, 1, 2, 0, 1, - GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0); - - label = gtk_label_new(NULL); - - markup = g_strdup_printf("<b>%s</b>", device); - gtk_label_set_markup(GTK_LABEL(label), markup); - g_free(markup); - - gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); - - gtk_label_set_selectable(GTK_LABEL(label), TRUE); - - gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); - - gtk_widget_set_size_request(GTK_WIDGET(label), 280, -1); - - gtk_container_add(GTK_CONTAINER(vbox), label); - - vbox = gtk_vbox_new(FALSE, 6); - - label = gtk_label_new(_("Enter passkey for authentication:")); - - gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); - - gtk_container_add(GTK_CONTAINER(vbox), label); - - gtk_table_attach(GTK_TABLE(table), vbox, 1, 2, 2, 3, - GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0); - - entry = gtk_entry_new(); - - gtk_entry_set_max_length(GTK_ENTRY(entry), 16); - - gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE); - - gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE); - - input->entry = entry; - - g_signal_connect(G_OBJECT(entry), "changed", - G_CALLBACK(changed_callback), input); - - gtk_container_add(GTK_CONTAINER(vbox), entry); - - button = gtk_check_button_new_with_label(_("Show input")); - - g_signal_connect(G_OBJECT(button), "toggled", - G_CALLBACK(toggled_callback), input); - - gtk_container_add(GTK_CONTAINER(vbox), button); - - input_list = g_list_append(input_list, input); - - g_signal_connect(G_OBJECT(dialog), "response", - G_CALLBACK(passkey_callback), input); - - gtk_status_icon_set_blinking(statusicon, TRUE); -} - -static void confirm_dialog(const char *path, const char *address, - const char *value, const gchar *device, - DBusGMethodInvocation *context) -{ - GtkWidget *dialog; - GtkWidget *button; - GtkWidget *image; - GtkWidget *label; - GtkWidget *table; - GtkWidget *vbox; - gchar *markup; - struct input_data *input; - - input = g_try_malloc0(sizeof(*input)); - if (!input) - return; - - input->path = g_strdup(path); - input->address = g_strdup(address); - - input->context = context; - - dialog = gtk_dialog_new(); - - gtk_window_set_title(GTK_WINDOW(dialog), _("Confirmation request")); - - gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); - - gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER); - - gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE); - - gtk_window_set_urgency_hint(GTK_WINDOW(dialog), TRUE); - - gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE); - - input->dialog = dialog; - - button = gtk_dialog_add_button(GTK_DIALOG(dialog), - GTK_STOCK_NO, GTK_RESPONSE_NO); - - button = gtk_dialog_add_button(GTK_DIALOG(dialog), - GTK_STOCK_YES, GTK_RESPONSE_YES); - - table = gtk_table_new(5, 2, FALSE); - - gtk_table_set_row_spacings(GTK_TABLE(table), 4); - gtk_table_set_col_spacings(GTK_TABLE(table), 20); - - gtk_container_set_border_width(GTK_CONTAINER(table), 12); - - gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table); - - image = gtk_image_new_from_icon_name(GTK_STOCK_DIALOG_AUTHENTICATION, - GTK_ICON_SIZE_DIALOG); - - gtk_misc_set_alignment(GTK_MISC(image), 0.0, 0.0); - - gtk_table_attach(GTK_TABLE(table), image, 0, 1, 0, 5, - GTK_SHRINK, GTK_FILL, 0, 0); - - vbox = gtk_vbox_new(FALSE, 6); - label = gtk_label_new(_("Pairing request for device:")); - - gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); - - gtk_container_add(GTK_CONTAINER(vbox), label); - - gtk_table_attach(GTK_TABLE(table), vbox, 1, 2, 0, 1, - GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0); - - label = gtk_label_new(NULL); - - markup = g_strdup_printf("<b>%s</b>", device); - gtk_label_set_markup(GTK_LABEL(label), markup); - g_free(markup); - - gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); - - gtk_label_set_selectable(GTK_LABEL(label), TRUE); - - gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); - - gtk_widget_set_size_request(GTK_WIDGET(label), 280, -1); - - gtk_container_add(GTK_CONTAINER(vbox), label); - - vbox = gtk_vbox_new(FALSE, 6); - - label = gtk_label_new(_("Confirm value for authentication:")); - - gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); - - gtk_container_add(GTK_CONTAINER(vbox), label); - - gtk_table_attach(GTK_TABLE(table), vbox, 1, 2, 2, 3, - GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0); - - label = gtk_label_new(NULL); - - markup = g_strdup_printf("<b>%s</b>\n", value); - - gtk_label_set_markup(GTK_LABEL(label), markup); - - g_free(markup); - - gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); - - gtk_container_add(GTK_CONTAINER(vbox), label); - - input_list = g_list_append(input_list, input); - - g_signal_connect(G_OBJECT(dialog), "response", - G_CALLBACK(confirm_callback), input); - - gtk_status_icon_set_blinking(statusicon, TRUE); -} - -static void auth_dialog(const char *path, const char *address, - const char *service, const char *uuid, const gchar *device, - const gchar *profile, DBusGMethodInvocation *context) -{ - GtkWidget *dialog; - GtkWidget *button; - GtkWidget *image; - GtkWidget *label; - GtkWidget *table; - GtkWidget *vbox; - gchar *markup, *text; - struct input_data *input; - - input = g_try_malloc0(sizeof(*input)); - if (!input) - return; - - input->path = g_strdup(path); - input->address = g_strdup(address); - input->service = g_strdup(service); - input->uuid = g_strdup(uuid); - - input->context = context; - - dialog = gtk_dialog_new(); - - gtk_window_set_title(GTK_WINDOW(dialog), _("Authorization request")); - - gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); - - gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER); - - gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE); - - gtk_window_set_urgency_hint(GTK_WINDOW(dialog), TRUE); - - gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE); - - input->dialog = dialog; - - button = gtk_dialog_add_button(GTK_DIALOG(dialog), - GTK_STOCK_NO, GTK_RESPONSE_NO); - - button = gtk_dialog_add_button(GTK_DIALOG(dialog), - GTK_STOCK_YES, GTK_RESPONSE_YES); - - table = gtk_table_new(5, 2, FALSE); - - gtk_table_set_row_spacings(GTK_TABLE(table), 4); - gtk_table_set_col_spacings(GTK_TABLE(table), 20); - - gtk_container_set_border_width(GTK_CONTAINER(table), 12); - - gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table); - - image = gtk_image_new_from_icon_name(GTK_STOCK_DIALOG_AUTHENTICATION, - GTK_ICON_SIZE_DIALOG); - - gtk_misc_set_alignment(GTK_MISC(image), 0.0, 0.0); - - gtk_table_attach(GTK_TABLE(table), image, 0, 1, 0, 5, - GTK_SHRINK, GTK_FILL, 0, 0); - - vbox = gtk_vbox_new(FALSE, 6); - - label = gtk_label_new(_("Authorization request for device:")); - - gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); - - gtk_table_attach(GTK_TABLE(table), label, 1, 2, 0, 1, - GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0); - - label = gtk_label_new(NULL); - - markup = g_strdup_printf("<b>%s</b>", device); - gtk_label_set_markup(GTK_LABEL(label), markup); - g_free(markup); - - gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); - - gtk_label_set_selectable(GTK_LABEL(label), TRUE); - - gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); - - gtk_widget_set_size_request(GTK_WIDGET(label), 280, -1); - - gtk_container_add(GTK_CONTAINER(vbox), label); - - gtk_table_attach(GTK_TABLE(table), vbox, 1, 2, 2, 3, - GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0); - - label = gtk_label_new(NULL); - - /* translators: Whether to grant access to a particular service - * to the device mentioned */ - markup = g_strdup_printf("<i>%s</i>", profile); - text = g_strdup_printf(_("Grant access to %s?"), markup); - g_free(markup); - - markup = g_strdup_printf("%s\n", text); - gtk_label_set_markup(GTK_LABEL(label), markup); - g_free(markup); - - g_free(text); - - gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); - - gtk_container_add(GTK_CONTAINER(vbox), label); - - button = gtk_check_button_new_with_label(_("Always grant access")); - - input->button = button; - - gtk_container_add(GTK_CONTAINER(vbox), button); - - input_list = g_list_append(input_list, input); - - g_signal_connect(G_OBJECT(dialog), "response", - G_CALLBACK(auth_callback), input); - - gtk_status_icon_set_blinking(statusicon, TRUE); -} - -static void show_dialog(gpointer data, gpointer user_data) -{ - struct input_data *input = data; - - gtk_widget_show_all(input->dialog); - - gtk_window_present(GTK_WINDOW(input->dialog)); -} - -static NotifyNotification *notify = NULL; - -static void notify_action(NotifyNotification *notify, - gchar *action, gpointer user_data) -{ -} - -static void show_notification(const gchar *summary, const gchar *message, - const gchar *action, gint timeout, GCallback handler) -{ - NotifyActionCallback callback; - GdkScreen *screen; - GdkRectangle area; - - if (notify) { - g_signal_handlers_destroy(notify); - notify_notification_close(notify, NULL); - } - - notify = notify_notification_new(summary, message, - "stock_bluetooth", NULL); - - notify_notification_set_timeout(notify, timeout); - - if (gtk_status_icon_get_visible(statusicon) == TRUE) { - gtk_status_icon_get_geometry(statusicon, &screen, &area, NULL); - - notify_notification_set_hint_int32(notify, - "x", area.x + area.width / 2); - notify_notification_set_hint_int32(notify, - "y", area.y + area.height / 2); - } - - notify_notification_set_urgency(notify, NOTIFY_URGENCY_NORMAL); - - callback = handler ? NOTIFY_ACTION_CALLBACK(handler) : notify_action; - - notify_notification_add_action(notify, "default", "action", - callback, NULL, NULL); - if (action != NULL) - notify_notification_add_action(notify, "button", action, - callback, NULL, NULL); - - notify_notification_show(notify, NULL); -} - -static void close_notification(void) -{ - if (notify) { - g_signal_handlers_destroy(notify); - notify_notification_close(notify, NULL); - notify = NULL; - } -} - -typedef struct { - GObject parent; -} PasskeyAgent; - -typedef struct { - GObjectClass parent; -} PasskeyAgentClass; - -static GObjectClass *passkey_agent_parent; - -G_DEFINE_TYPE(PasskeyAgent, passkey_agent, G_TYPE_OBJECT) - -#define PASSKEY_AGENT_OBJECT_TYPE (passkey_agent_get_type()) - -#define PASSKEY_AGENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \ - PASSKEY_AGENT_OBJECT_TYPE, PasskeyAgent)) - -static void passkey_agent_finalize(GObject *obj) -{ - passkey_agent_parent->finalize(obj); -} - -static void passkey_agent_init(PasskeyAgent *obj) -{ -} - -static void passkey_agent_class_init(PasskeyAgentClass *klass) -{ - GObjectClass *gobject_class; - - passkey_agent_parent = g_type_class_peek_parent(klass); - - gobject_class = G_OBJECT_CLASS(klass); - gobject_class->finalize = passkey_agent_finalize; -} - -static PasskeyAgent *passkey_agent_new(const char *path) -{ - PasskeyAgent *agent; - - agent = g_object_new(PASSKEY_AGENT_OBJECT_TYPE, NULL); - - dbus_g_connection_register_g_object(conn, path, G_OBJECT(agent)); - - return agent; -} - -static void notification_closed(GObject *object, gpointer user_data) -{ - g_list_foreach(input_list, show_dialog, NULL); - - gtk_status_icon_set_blinking(statusicon, FALSE); -} - -static gboolean passkey_agent_request(PasskeyAgent *agent, - const char *path, const char *address, - DBusGMethodInvocation *context) -{ - DBusGProxy *object; - const char *adapter = NULL, *name = NULL; - gchar *device, *line; - - object = dbus_g_proxy_new_for_name(conn, "org.bluez", - path, "org.bluez.Adapter"); - - dbus_g_proxy_call(object, "GetName", NULL, G_TYPE_INVALID, - G_TYPE_STRING, &adapter, G_TYPE_INVALID); - - dbus_g_proxy_call(object, "GetRemoteName", NULL, - G_TYPE_STRING, address, G_TYPE_INVALID, - G_TYPE_STRING, &name, G_TYPE_INVALID); - - if (name) { - if (g_strrstr(name, address)) - device = g_strdup(name); - else - device = g_strdup_printf("%s (%s)", name, address); - } else - device = g_strdup(address); - - passkey_dialog(path, address, device, context); - - /* translators: this is a popup telling you a particular device - * has asked for pairing */ - line = g_strdup_printf(_("Pairing request for '%s'"), device); - g_free(device); - - show_notification(adapter ? adapter : _("Bluetooth device"), - line, _("Enter passkey"), 0, - G_CALLBACK(notification_closed)); - - g_free(line); - - return TRUE; -} - -static gboolean passkey_agent_confirm(PasskeyAgent *agent, - const char *path, const char *address, - const char *value, DBusGMethodInvocation *context) -{ - DBusGProxy *object; - const char *adapter = NULL, *name = NULL; - gchar *device, *line; - - object = dbus_g_proxy_new_for_name(conn, "org.bluez", - path, "org.bluez.Adapter"); - - dbus_g_proxy_call(object, "GetName", NULL, G_TYPE_INVALID, - G_TYPE_STRING, &adapter, G_TYPE_INVALID); - - dbus_g_proxy_call(object, "GetRemoteName", NULL, - G_TYPE_STRING, address, G_TYPE_INVALID, - G_TYPE_STRING, &name, G_TYPE_INVALID); - - if (name) { - if (g_strrstr(name, address)) - device = g_strdup(name); - else - device = g_strdup_printf("%s (%s)", name, address); - } else - device = g_strdup(address); - - confirm_dialog(path, address, value, device, context); - - line = g_strdup_printf(_("Pairing request for '%s'"), device); - g_free(device); - - show_notification(adapter ? adapter : _("Bluetooth device"), - line, _("Confirm pairing"), 0, - G_CALLBACK(notification_closed)); - - g_free (line); - - return TRUE; -} - -static gboolean passkey_agent_cancel(PasskeyAgent *agent, - const char *path, const char *address, GError **error) -{ - GList *list; - GError *result; - struct input_data *input; - - input = g_try_malloc0(sizeof(*input)); - if (!input) - return FALSE; - - input->path = g_strdup(path); - input->address = g_strdup(address); - - list = g_list_find_custom(input_list, input, input_compare); - - g_free(input->address); - g_free(input->path); - g_free(input); - - if (!list || !list->data) - return FALSE; - - input = list->data; - - close_notification(); - - result = g_error_new(AGENT_ERROR, AGENT_ERROR_REJECT, - "Agent callback canceled"); - - dbus_g_method_return_error(input->context, result); - - input_free(input); - - return TRUE; -} - -static gboolean passkey_agent_release(PasskeyAgent *agent, GError **error) -{ - registered_passkey = 0; - - return TRUE; -} - -#include "passkey-agent-glue.h" - -typedef struct { - GObject parent; -} AuthAgent; - -typedef struct { - GObjectClass parent; -} AuthAgentClass; - -static GObjectClass *auth_agent_parent; - -G_DEFINE_TYPE(AuthAgent, auth_agent, G_TYPE_OBJECT) - -#define AUTH_AGENT_OBJECT_TYPE (auth_agent_get_type()) - -#define AUTH_AGENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \ - AUTH_AGENT_OBJECT_TYPE, AuthAgent)) - -static void auth_agent_finalize(GObject *obj) -{ - auth_agent_parent->finalize(obj); -} - -static void auth_agent_init(AuthAgent *obj) -{ -} - -static void auth_agent_class_init(AuthAgentClass *klass) -{ - GObjectClass *gobject_class; - - auth_agent_parent = g_type_class_peek_parent(klass); - - gobject_class = G_OBJECT_CLASS(klass); - gobject_class->finalize = auth_agent_finalize; -} - -static AuthAgent *auth_agent_new(const char *path) -{ - AuthAgent *agent; - - agent = g_object_new(AUTH_AGENT_OBJECT_TYPE, NULL); - - dbus_g_connection_register_g_object(conn, path, G_OBJECT(agent)); - - return agent; -} - -static gboolean auth_agent_authorize(PasskeyAgent *agent, - const char *path, const char *address, const char *service, - const char *uuid, DBusGMethodInvocation *context) -{ - DBusGProxy *object; - const char *adapter = NULL, *name = NULL; - gchar *device, *profile, *line; - - if (auto_authorize == TRUE) { - dbus_g_method_return(context); - return TRUE; - } - - object = dbus_g_proxy_new_for_name(conn, "org.bluez", - path, "org.bluez.Adapter"); - - dbus_g_proxy_call(object, "GetName", NULL, G_TYPE_INVALID, - G_TYPE_STRING, &adapter, G_TYPE_INVALID); - - dbus_g_proxy_call(object, "GetRemoteName", NULL, - G_TYPE_STRING, address, G_TYPE_INVALID, - G_TYPE_STRING, &name, G_TYPE_INVALID); - - object = dbus_g_proxy_new_for_name(conn, "org.bluez", - service, "org.bluez.Service"); - - dbus_g_proxy_call(object, "GetName", NULL, G_TYPE_INVALID, - G_TYPE_STRING, &profile, G_TYPE_INVALID); - - if (name) { - if (g_strrstr(name, address)) - device = g_strdup(name); - else - device = g_strdup_printf("%s (%s)", name, address); - } else - device = g_strdup(address); - - auth_dialog(path, address, service, uuid, device, profile, context); - - line = g_strdup_printf(_("Authorization request for %s"), device); - g_free(device); - - show_notification(adapter ? adapter : _("Bluetooth device"), - line, _("Check authorization"), 0, - G_CALLBACK(notification_closed)); - - g_free(line); - - return TRUE; -} - -static gboolean auth_agent_cancel(PasskeyAgent *agent, - const char *path, const char *address, const char *service, - const char *uuid, DBusGMethodInvocation *context) -{ - GList *list; - GError *result; - struct input_data *input; - - input = g_try_malloc0(sizeof(*input)); - if (!input) - return FALSE; - - input->path = g_strdup(path); - input->address = g_strdup(address); - input->service = g_strdup(service); - input->uuid = g_strdup(uuid); - - list = g_list_find_custom(input_list, input, input_compare); - - g_free(input->uuid); - g_free(input->service); - g_free(input->address); - g_free(input->path); - g_free(input); - - if (!list || !list->data) - return FALSE; - - input = list->data; - - close_notification(); - - result = g_error_new(AGENT_ERROR, AGENT_ERROR_REJECT, - "Agent callback canceled"); - - dbus_g_method_return_error(input->context, result); - - input_free(input); - - return TRUE; -} - -static gboolean auth_agent_release(PasskeyAgent *agent, GError **error) -{ - registered_auth = 0; - - return TRUE; -} - -#include "auth-agent-glue.h" - -static int register_agents(void) -{ - DBusGProxy *object; - GError *error = NULL; - - if (registered_passkey && registered_auth) - return 0; - - object = dbus_g_proxy_new_for_name(conn, "org.bluez", - "/org/bluez", "org.bluez.Security"); - - if (!registered_passkey) { - - dbus_g_proxy_call(object, "RegisterDefaultPasskeyAgent", - &error, G_TYPE_STRING, PASSKEY_AGENT_PATH, - G_TYPE_INVALID, G_TYPE_INVALID); - - if (error != NULL) { - g_error_free(error); - return -1; - } - - registered_passkey = 1; - } - - if (!registered_auth) { - dbus_g_proxy_call(object, "RegisterDefaultAuthorizationAgent", - &error, G_TYPE_STRING, AUTH_AGENT_PATH, - G_TYPE_INVALID, G_TYPE_INVALID); - - if (error != NULL) { - g_error_free(error); - return -1; - } - - registered_auth = 1; - } - - return 0; -} - static void bonding_created(DBusGProxy *object, const char *address, gpointer user_data) { @@ -1377,7 +396,7 @@ static void add_adapter(const char *path static void adapter_added(DBusGProxy *object, const char *path, gpointer user_data) { - register_agents(); + register_agents(statusicon); add_adapter(path); } @@ -1437,8 +456,7 @@ static void name_owner_changed(DBusGProx const char *prev, const char *new, gpointer user_data) { if (!strcmp(name, "org.bluez") && *new == '\0') { - registered_passkey = 0; - registered_auth = 0; + unregister_agents(); g_list_foreach(adapter_list, adapter_disable, NULL); @@ -1463,7 +481,6 @@ static gboolean program_available(const static int setup_dbus(void) { DBusGProxy *object; - void *agent; object = dbus_g_proxy_new_for_name(conn, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS); @@ -1474,18 +491,7 @@ static int setup_dbus(void) dbus_g_proxy_connect_signal(object, "NameOwnerChanged", G_CALLBACK(name_owner_changed), NULL, NULL); - dbus_g_object_type_install_info(PASSKEY_AGENT_OBJECT_TYPE, - &dbus_glib_passkey_agent_object_info); - - dbus_g_object_type_install_info(AUTH_AGENT_OBJECT_TYPE, - &dbus_glib_auth_agent_object_info); - - dbus_g_error_domain_register(AGENT_ERROR, "org.bluez.Error", - AGENT_ERROR_TYPE); - - agent = passkey_agent_new(PASSKEY_AGENT_PATH); - - agent = auth_agent_new(AUTH_AGENT_PATH); + setup_agent_dbus(conn); return 0; } @@ -1654,11 +660,7 @@ static void wizard_callback(GObject *wid static void activate_callback(GObject *widget, gpointer user_data) { - close_notification(); - - g_list_foreach(input_list, show_dialog, NULL); - - gtk_status_icon_set_blinking(statusicon, FALSE); + flush_input(); } static void popup_callback(GObject *widget, guint button, @@ -1788,7 +790,7 @@ static void gconf_callback(GConfClient * } if (strcmp(entry->key, PREF_AUTO_AUTHORIZE) == 0) - auto_authorize = gconf_value_get_bool(value); + set_auto_authorize (gconf_value_get_bool(value)); } static GOptionEntry options[] = { @@ -1847,8 +849,8 @@ int main(int argc, char *argv[]) g_free(str); } - auto_authorize = gconf_client_get_bool(gconf, - PREF_AUTO_AUTHORIZE, NULL); + set_auto_authorize (gconf_client_get_bool(gconf, + PREF_AUTO_AUTHORIZE, NULL)); gconf_client_add_dir(gconf, PREF_DIR, GCONF_CLIENT_PRELOAD_NONE, NULL); @@ -1874,11 +876,8 @@ int main(int argc, char *argv[]) setup_manager(); - register_agents(); - - //passkey_dialog("/org/bluez/hci0", "00:11:22:33:44:55", "Test", NULL); - //confirm_dialog("/org/bluez/hci0", "00:11:22:33:44:55", "123456", "Test", NULL); - //auth_dialog("/org/bluez/hci0", "00:11:22:33:44:55", "/org/bluez/echo", "", "Test", "Echo service", NULL); + register_agents(statusicon); + register_notifications(statusicon); gtk_main(); @@ -1886,7 +885,9 @@ int main(int argc, char *argv[]) g_object_unref(gconf); - close_notification(); + flush_input(); + + unregister_notifications(); g_list_foreach(adapter_list, adapter_free, NULL); --- /dev/null 2008-01-24 17:45:36.352009045 +0000 +++ notifications.c 2008-02-07 01:11:47.000000000 +0000 @@ -0,0 +1,101 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2005-2008 Marcel Holtmann <marcel@holtmann.org> + * Copyright (C) 2006-2008 Bastien Nocera <hadess@hadess.net> + * + * + * 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 + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <glib/gi18n.h> + +#include <gtk/gtk.h> +#include <libnotify/notify.h> + +#include "notifications.h" + +static GtkStatusIcon *statusicon = NULL; +static NotifyNotification *notify = NULL; + +static void notify_action(NotifyNotification *notify, + gchar *action, gpointer user_data) +{ +} +void show_notification(const gchar *summary, const gchar *message, + const gchar *action, gint timeout, GCallback handler) +{ + NotifyActionCallback callback; + GdkScreen *screen; + GdkRectangle area; + + if (notify) { + g_signal_handlers_destroy(notify); + notify_notification_close(notify, NULL); + } + + notify = notify_notification_new(summary, message, + "stock_bluetooth", NULL); + + notify_notification_set_timeout(notify, timeout); + + if (gtk_status_icon_get_visible(statusicon) == TRUE) { + gtk_status_icon_get_geometry(statusicon, &screen, &area, NULL); + + notify_notification_set_hint_int32(notify, + "x", area.x + area.width / 2); + notify_notification_set_hint_int32(notify, + "y", area.y + area.height / 2); + } + + notify_notification_set_urgency(notify, NOTIFY_URGENCY_NORMAL); + + callback = handler ? NOTIFY_ACTION_CALLBACK(handler) : notify_action; + + notify_notification_add_action(notify, "default", "action", + callback, NULL, NULL); + if (action != NULL) + notify_notification_add_action(notify, "button", action, + callback, NULL, NULL); + + notify_notification_show(notify, NULL); +} + +void close_notification(void) +{ + if (notify) { + g_signal_handlers_destroy(notify); + notify_notification_close(notify, NULL); + notify = NULL; + } +} + +void register_notifications(GtkStatusIcon *_statusicon) +{ + statusicon = g_object_ref(_statusicon); +} + +void unregister_notifications(void) +{ + g_object_unref (statusicon); + statusicon = NULL; +} + --- /dev/null 2008-01-24 17:45:36.352009045 +0000 +++ notifications.h 2008-02-07 01:11:53.000000000 +0000 @@ -0,0 +1,30 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2005-2008 Marcel Holtmann <marcel@holtmann.org> + * Copyright (C) 2006-2008 Bastien Nocera <hadess@hadess.net> + * + * + * 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 + * + */ + +void show_notification(const gchar *summary, const gchar *message, + const gchar *action, gint timeout, GCallback handler); +void close_notification(void); +void register_notifications(GtkStatusIcon *_statusicon); +void unregister_notifications(void); + --- /dev/null 2008-01-24 17:45:36.352009045 +0000 +++ agent.c 2008-02-07 01:11:58.000000000 +0000 @@ -0,0 +1,1026 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2005-2008 Marcel Holtmann <marcel@holtmann.org> + * Copyright (C) 2006-2008 Bastien Nocera <hadess@hadess.net> + * + * + * 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 + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#include <dbus/dbus-glib.h> + +#include <glib/gi18n.h> + +#include <gtk/gtk.h> + +#include "agent.h" +#include "notifications.h" + +static GtkStatusIcon *statusicon = NULL; +static DBusGConnection *conn = NULL; + +#define PASSKEY_AGENT_PATH "/org/bluez/passkey" +#define AUTH_AGENT_PATH "/org/bluez/auth" + +static int volatile registered_passkey = 0; +static int volatile registered_auth = 0; + +static gboolean auto_authorize = FALSE; + +typedef enum { + AGENT_ERROR_REJECT +} AgentError; + +#define AGENT_ERROR (agent_error_quark()) + +#define AGENT_ERROR_TYPE (agent_error_get_type()) + +static GQuark agent_error_quark(void) +{ + static GQuark quark = 0; + if (!quark) + quark = g_quark_from_static_string("agent"); + + return quark; +} + +#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC } + +static GType agent_error_get_type(void) +{ + static GType etype = 0; + if (etype == 0) { + static const GEnumValue values[] = { + ENUM_ENTRY(AGENT_ERROR_REJECT, "Rejected"), + { 0, 0, 0 } + }; + + etype = g_enum_register_static("agent", values); + } + + return etype; +} + +static GList *input_list = NULL; + +struct input_data { + char *path; + char *address; + char *service; + char *uuid; + DBusGMethodInvocation *context; + GtkWidget *dialog; + GtkWidget *button; + GtkWidget *entry; +}; + +static gint input_compare(gconstpointer a, gconstpointer b) +{ + struct input_data *a_data = (struct input_data *) a; + struct input_data *b_data = (struct input_data *) b; + + return strcmp(a_data->address, b_data->address); +} + +static void input_free(struct input_data *input) +{ + gtk_widget_destroy(input->dialog); + + input_list = g_list_remove(input_list, input); + + g_free(input->uuid); + g_free(input->service); + g_free(input->address); + g_free(input->path); + g_free(input); + + if (g_list_length(input_list) == 0) + gtk_status_icon_set_blinking(statusicon, FALSE); +} + +static void passkey_callback(GtkWidget *dialog, + gint response, gpointer user_data) +{ + struct input_data *input = user_data; + + if (response == GTK_RESPONSE_ACCEPT) { + const char *passkey; + passkey = gtk_entry_get_text(GTK_ENTRY(input->entry)); + dbus_g_method_return(input->context, passkey); + } else { + GError *error; + error = g_error_new(AGENT_ERROR, AGENT_ERROR_REJECT, + "Pairing request rejected"); + dbus_g_method_return_error(input->context, error); + } + + input_free(input); +} + +static void confirm_callback(GtkWidget *dialog, + gint response, gpointer user_data) +{ + struct input_data *input = user_data; + + if (response != GTK_RESPONSE_YES) { + GError *error; + error = g_error_new(AGENT_ERROR, AGENT_ERROR_REJECT, + "Confirmation request rejected"); + dbus_g_method_return_error(input->context, error); + } else + dbus_g_method_return(input->context); + + input_free(input); +} + +static void set_trusted(struct input_data *input) +{ + DBusGProxy *object; + gboolean active; + + active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(input->button)); + if (active == FALSE) + return; + + object = dbus_g_proxy_new_for_name(conn, "org.bluez", + input->path, "org.bluez.Adapter"); + + dbus_g_proxy_call(object, "SetTrusted", NULL, + G_TYPE_STRING, input->address, G_TYPE_INVALID, + G_TYPE_INVALID); +} + +static void auth_callback(GtkWidget *dialog, + gint response, gpointer user_data) +{ + struct input_data *input = user_data; + + if (response == GTK_RESPONSE_YES) { + set_trusted(input); + dbus_g_method_return(input->context); + } else { + GError *error; + error = g_error_new(AGENT_ERROR, AGENT_ERROR_REJECT, + "Authorization request rejected"); + dbus_g_method_return_error(input->context, error); + } + + input_free(input); +} + +static void changed_callback(GtkWidget *editable, gpointer user_data) +{ + struct input_data *input = user_data; + const gchar *text; + + text = gtk_entry_get_text(GTK_ENTRY(input->entry)); + + gtk_widget_set_sensitive(input->button, strlen(text) ? TRUE : FALSE); +} + +static void toggled_callback(GtkWidget *button, gpointer user_data) +{ + struct input_data *input = user_data; + gboolean mode; + + mode = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)); + + gtk_entry_set_visibility(GTK_ENTRY(input->entry), mode); +} + +static void passkey_dialog(const char *path, const char *address, + const gchar *device, DBusGMethodInvocation *context) +{ + GtkWidget *dialog; + GtkWidget *button; + GtkWidget *image; + GtkWidget *label; + GtkWidget *entry; + GtkWidget *table; + GtkWidget *vbox; + struct input_data *input; + gchar *markup; + + input = g_try_malloc0(sizeof(*input)); + if (!input) + return; + + input->path = g_strdup(path); + input->address = g_strdup(address); + + input->context = context; + + dialog = gtk_dialog_new(); + + gtk_window_set_title(GTK_WINDOW(dialog), _("Authentication request")); + + gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); + + gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER); + + gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE); + + gtk_window_set_urgency_hint(GTK_WINDOW(dialog), TRUE); + + gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE); + + input->dialog = dialog; + + button = gtk_dialog_add_button(GTK_DIALOG(dialog), + GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT); + + button = gtk_dialog_add_button(GTK_DIALOG(dialog), + GTK_STOCK_OK, GTK_RESPONSE_ACCEPT); + + gtk_widget_grab_default(button); + + gtk_widget_set_sensitive(button, FALSE); + + input->button = button; + + table = gtk_table_new(5, 2, FALSE); + + gtk_table_set_row_spacings(GTK_TABLE(table), 4); + gtk_table_set_col_spacings(GTK_TABLE(table), 20); + + gtk_container_set_border_width(GTK_CONTAINER(table), 12); + + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table); + + image = gtk_image_new_from_icon_name(GTK_STOCK_DIALOG_AUTHENTICATION, + GTK_ICON_SIZE_DIALOG); + + gtk_misc_set_alignment(GTK_MISC(image), 0.0, 0.0); + + gtk_table_attach(GTK_TABLE(table), image, 0, 1, 0, 5, + GTK_SHRINK, GTK_FILL, 0, 0); + + vbox = gtk_vbox_new(FALSE, 6); + + label = gtk_label_new(_("Pairing request for device:")); + + gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); + + gtk_container_add(GTK_CONTAINER(vbox), label); + + gtk_table_attach(GTK_TABLE(table), vbox, 1, 2, 0, 1, + GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0); + + label = gtk_label_new(NULL); + + markup = g_strdup_printf("<b>%s</b>", device); + gtk_label_set_markup(GTK_LABEL(label), markup); + g_free(markup); + + gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); + + gtk_label_set_selectable(GTK_LABEL(label), TRUE); + + gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); + + gtk_widget_set_size_request(GTK_WIDGET(label), 280, -1); + + gtk_container_add(GTK_CONTAINER(vbox), label); + + vbox = gtk_vbox_new(FALSE, 6); + + label = gtk_label_new(_("Enter passkey for authentication:")); + + gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); + + gtk_container_add(GTK_CONTAINER(vbox), label); + + gtk_table_attach(GTK_TABLE(table), vbox, 1, 2, 2, 3, + GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0); + + entry = gtk_entry_new(); + + gtk_entry_set_max_length(GTK_ENTRY(entry), 16); + + gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE); + + gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE); + + input->entry = entry; + + g_signal_connect(G_OBJECT(entry), "changed", + G_CALLBACK(changed_callback), input); + + gtk_container_add(GTK_CONTAINER(vbox), entry); + + button = gtk_check_button_new_with_label(_("Show input")); + + g_signal_connect(G_OBJECT(button), "toggled", + G_CALLBACK(toggled_callback), input); + + gtk_container_add(GTK_CONTAINER(vbox), button); + + input_list = g_list_append(input_list, input); + + g_signal_connect(G_OBJECT(dialog), "response", + G_CALLBACK(passkey_callback), input); + + gtk_status_icon_set_blinking(statusicon, TRUE); +} + +static void confirm_dialog(const char *path, const char *address, + const char *value, const gchar *device, + DBusGMethodInvocation *context) +{ + GtkWidget *dialog; + GtkWidget *button; + GtkWidget *image; + GtkWidget *label; + GtkWidget *table; + GtkWidget *vbox; + gchar *markup; + struct input_data *input; + + input = g_try_malloc0(sizeof(*input)); + if (!input) + return; + + input->path = g_strdup(path); + input->address = g_strdup(address); + + input->context = context; + + dialog = gtk_dialog_new(); + + gtk_window_set_title(GTK_WINDOW(dialog), _("Confirmation request")); + + gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); + + gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER); + + gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE); + + gtk_window_set_urgency_hint(GTK_WINDOW(dialog), TRUE); + + gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE); + + input->dialog = dialog; + + button = gtk_dialog_add_button(GTK_DIALOG(dialog), + GTK_STOCK_NO, GTK_RESPONSE_NO); + + button = gtk_dialog_add_button(GTK_DIALOG(dialog), + GTK_STOCK_YES, GTK_RESPONSE_YES); + + table = gtk_table_new(5, 2, FALSE); + + gtk_table_set_row_spacings(GTK_TABLE(table), 4); + gtk_table_set_col_spacings(GTK_TABLE(table), 20); + + gtk_container_set_border_width(GTK_CONTAINER(table), 12); + + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table); + + image = gtk_image_new_from_icon_name(GTK_STOCK_DIALOG_AUTHENTICATION, + GTK_ICON_SIZE_DIALOG); + + gtk_misc_set_alignment(GTK_MISC(image), 0.0, 0.0); + + gtk_table_attach(GTK_TABLE(table), image, 0, 1, 0, 5, + GTK_SHRINK, GTK_FILL, 0, 0); + + vbox = gtk_vbox_new(FALSE, 6); + label = gtk_label_new(_("Pairing request for device:")); + + gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); + + gtk_container_add(GTK_CONTAINER(vbox), label); + + gtk_table_attach(GTK_TABLE(table), vbox, 1, 2, 0, 1, + GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0); + + label = gtk_label_new(NULL); + + markup = g_strdup_printf("<b>%s</b>", device); + gtk_label_set_markup(GTK_LABEL(label), markup); + g_free(markup); + + gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); + + gtk_label_set_selectable(GTK_LABEL(label), TRUE); + + gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); + + gtk_widget_set_size_request(GTK_WIDGET(label), 280, -1); + + gtk_container_add(GTK_CONTAINER(vbox), label); + + vbox = gtk_vbox_new(FALSE, 6); + + label = gtk_label_new(_("Confirm value for authentication:")); + + gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); + + gtk_container_add(GTK_CONTAINER(vbox), label); + + gtk_table_attach(GTK_TABLE(table), vbox, 1, 2, 2, 3, + GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0); + + label = gtk_label_new(NULL); + + markup = g_strdup_printf("<b>%s</b>\n", value); + + gtk_label_set_markup(GTK_LABEL(label), markup); + + g_free(markup); + + gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); + + gtk_container_add(GTK_CONTAINER(vbox), label); + + input_list = g_list_append(input_list, input); + + g_signal_connect(G_OBJECT(dialog), "response", + G_CALLBACK(confirm_callback), input); + + gtk_status_icon_set_blinking(statusicon, TRUE); +} + +static void auth_dialog(const char *path, const char *address, + const char *service, const char *uuid, const gchar *device, + const gchar *profile, DBusGMethodInvocation *context) +{ + GtkWidget *dialog; + GtkWidget *button; + GtkWidget *image; + GtkWidget *label; + GtkWidget *table; + GtkWidget *vbox; + gchar *markup, *text; + struct input_data *input; + + input = g_try_malloc0(sizeof(*input)); + if (!input) + return; + + input->path = g_strdup(path); + input->address = g_strdup(address); + input->service = g_strdup(service); + input->uuid = g_strdup(uuid); + + input->context = context; + + dialog = gtk_dialog_new(); + + gtk_window_set_title(GTK_WINDOW(dialog), _("Authorization request")); + + gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); + + gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER); + + gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE); + + gtk_window_set_urgency_hint(GTK_WINDOW(dialog), TRUE); + + gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE); + + input->dialog = dialog; + + button = gtk_dialog_add_button(GTK_DIALOG(dialog), + GTK_STOCK_NO, GTK_RESPONSE_NO); + + button = gtk_dialog_add_button(GTK_DIALOG(dialog), + GTK_STOCK_YES, GTK_RESPONSE_YES); + + table = gtk_table_new(5, 2, FALSE); + + gtk_table_set_row_spacings(GTK_TABLE(table), 4); + gtk_table_set_col_spacings(GTK_TABLE(table), 20); + + gtk_container_set_border_width(GTK_CONTAINER(table), 12); + + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table); + + image = gtk_image_new_from_icon_name(GTK_STOCK_DIALOG_AUTHENTICATION, + GTK_ICON_SIZE_DIALOG); + + gtk_misc_set_alignment(GTK_MISC(image), 0.0, 0.0); + + gtk_table_attach(GTK_TABLE(table), image, 0, 1, 0, 5, + GTK_SHRINK, GTK_FILL, 0, 0); + + vbox = gtk_vbox_new(FALSE, 6); + + label = gtk_label_new(_("Authorization request for device:")); + + gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); + + gtk_table_attach(GTK_TABLE(table), label, 1, 2, 0, 1, + GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0); + + label = gtk_label_new(NULL); + + markup = g_strdup_printf("<b>%s</b>", device); + gtk_label_set_markup(GTK_LABEL(label), markup); + g_free(markup); + + gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); + + gtk_label_set_selectable(GTK_LABEL(label), TRUE); + + gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); + + gtk_widget_set_size_request(GTK_WIDGET(label), 280, -1); + + gtk_container_add(GTK_CONTAINER(vbox), label); + + gtk_table_attach(GTK_TABLE(table), vbox, 1, 2, 2, 3, + GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0); + + label = gtk_label_new(NULL); + + /* translators: Whether to grant access to a particular service + * to the device mentioned */ + markup = g_strdup_printf("<i>%s</i>", profile); + text = g_strdup_printf(_("Grant access to %s?"), markup); + g_free(markup); + + markup = g_strdup_printf("%s\n", text); + gtk_label_set_markup(GTK_LABEL(label), markup); + g_free(markup); + + g_free(text); + + gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); + + gtk_container_add(GTK_CONTAINER(vbox), label); + + button = gtk_check_button_new_with_label(_("Always grant access")); + + input->button = button; + + gtk_container_add(GTK_CONTAINER(vbox), button); + + input_list = g_list_append(input_list, input); + + g_signal_connect(G_OBJECT(dialog), "response", + G_CALLBACK(auth_callback), input); + + gtk_status_icon_set_blinking(statusicon, TRUE); +} + +static void show_dialog(gpointer data, gpointer user_data) +{ + struct input_data *input = data; + + gtk_widget_show_all(input->dialog); + + gtk_window_present(GTK_WINDOW(input->dialog)); +} + +typedef struct { + GObject parent; +} PasskeyAgent; + +typedef struct { + GObjectClass parent; +} PasskeyAgentClass; + +static GObjectClass *passkey_agent_parent; + +G_DEFINE_TYPE(PasskeyAgent, passkey_agent, G_TYPE_OBJECT) + +#define PASSKEY_AGENT_OBJECT_TYPE (passkey_agent_get_type()) + +#define PASSKEY_AGENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + PASSKEY_AGENT_OBJECT_TYPE, PasskeyAgent)) + +static void passkey_agent_finalize(GObject *obj) +{ + passkey_agent_parent->finalize(obj); +} + +static void passkey_agent_init(PasskeyAgent *obj) +{ +} + +static void passkey_agent_class_init(PasskeyAgentClass *klass) +{ + GObjectClass *gobject_class; + + passkey_agent_parent = g_type_class_peek_parent(klass); + + gobject_class = G_OBJECT_CLASS(klass); + gobject_class->finalize = passkey_agent_finalize; +} + +static PasskeyAgent *passkey_agent_new(const char *path) +{ + PasskeyAgent *agent; + + agent = g_object_new(PASSKEY_AGENT_OBJECT_TYPE, NULL); + + dbus_g_connection_register_g_object(conn, path, G_OBJECT(agent)); + + return agent; +} + +static void notification_closed(GObject *object, gpointer user_data) +{ + g_list_foreach(input_list, show_dialog, NULL); + + gtk_status_icon_set_blinking(statusicon, FALSE); +} + +static gboolean passkey_agent_request(PasskeyAgent *agent, + const char *path, const char *address, + DBusGMethodInvocation *context) +{ + DBusGProxy *object; + const char *adapter = NULL, *name = NULL; + gchar *device, *line; + + object = dbus_g_proxy_new_for_name(conn, "org.bluez", + path, "org.bluez.Adapter"); + + dbus_g_proxy_call(object, "GetName", NULL, G_TYPE_INVALID, + G_TYPE_STRING, &adapter, G_TYPE_INVALID); + + dbus_g_proxy_call(object, "GetRemoteName", NULL, + G_TYPE_STRING, address, G_TYPE_INVALID, + G_TYPE_STRING, &name, G_TYPE_INVALID); + + if (name) { + if (g_strrstr(name, address)) + device = g_strdup(name); + else + device = g_strdup_printf("%s (%s)", name, address); + } else + device = g_strdup(address); + + passkey_dialog(path, address, device, context); + + /* translators: this is a popup telling you a particular device + * has asked for pairing */ + line = g_strdup_printf(_("Pairing request for '%s'"), device); + g_free(device); + + show_notification(adapter ? adapter : _("Bluetooth device"), + line, _("Enter passkey"), 0, + G_CALLBACK(notification_closed)); + + g_free(line); + + return TRUE; +} + +static gboolean passkey_agent_confirm(PasskeyAgent *agent, + const char *path, const char *address, + const char *value, DBusGMethodInvocation *context) +{ + DBusGProxy *object; + const char *adapter = NULL, *name = NULL; + gchar *device, *line; + + object = dbus_g_proxy_new_for_name(conn, "org.bluez", + path, "org.bluez.Adapter"); + + dbus_g_proxy_call(object, "GetName", NULL, G_TYPE_INVALID, + G_TYPE_STRING, &adapter, G_TYPE_INVALID); + + dbus_g_proxy_call(object, "GetRemoteName", NULL, + G_TYPE_STRING, address, G_TYPE_INVALID, + G_TYPE_STRING, &name, G_TYPE_INVALID); + + if (name) { + if (g_strrstr(name, address)) + device = g_strdup(name); + else + device = g_strdup_printf("%s (%s)", name, address); + } else + device = g_strdup(address); + + confirm_dialog(path, address, value, device, context); + + line = g_strdup_printf(_("Pairing request for '%s'"), device); + g_free(device); + + show_notification(adapter ? adapter : _("Bluetooth device"), + line, _("Confirm pairing"), 0, + G_CALLBACK(notification_closed)); + + g_free (line); + + return TRUE; +} + +static gboolean passkey_agent_cancel(PasskeyAgent *agent, + const char *path, const char *address, GError **error) +{ + GList *list; + GError *result; + struct input_data *input; + + input = g_try_malloc0(sizeof(*input)); + if (!input) + return FALSE; + + input->path = g_strdup(path); + input->address = g_strdup(address); + + list = g_list_find_custom(input_list, input, input_compare); + + g_free(input->address); + g_free(input->path); + g_free(input); + + if (!list || !list->data) + return FALSE; + + input = list->data; + + close_notification(); + + result = g_error_new(AGENT_ERROR, AGENT_ERROR_REJECT, + "Agent callback canceled"); + + dbus_g_method_return_error(input->context, result); + + input_free(input); + + return TRUE; +} + +static gboolean passkey_agent_release(PasskeyAgent *agent, GError **error) +{ + registered_passkey = 0; + + return TRUE; +} + +#include "passkey-agent-glue.h" + +typedef struct { + GObject parent; +} AuthAgent; + +typedef struct { + GObjectClass parent; +} AuthAgentClass; + +static GObjectClass *auth_agent_parent; + +G_DEFINE_TYPE(AuthAgent, auth_agent, G_TYPE_OBJECT) + +#define AUTH_AGENT_OBJECT_TYPE (auth_agent_get_type()) + +#define AUTH_AGENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + AUTH_AGENT_OBJECT_TYPE, AuthAgent)) + +static void auth_agent_finalize(GObject *obj) +{ + auth_agent_parent->finalize(obj); +} + +static void auth_agent_init(AuthAgent *obj) +{ +} + +static void auth_agent_class_init(AuthAgentClass *klass) +{ + GObjectClass *gobject_class; + + auth_agent_parent = g_type_class_peek_parent(klass); + + gobject_class = G_OBJECT_CLASS(klass); + gobject_class->finalize = auth_agent_finalize; +} + +static AuthAgent *auth_agent_new(const char *path) +{ + AuthAgent *agent; + + agent = g_object_new(AUTH_AGENT_OBJECT_TYPE, NULL); + + dbus_g_connection_register_g_object(conn, path, G_OBJECT(agent)); + + return agent; +} + +static gboolean auth_agent_authorize(PasskeyAgent *agent, + const char *path, const char *address, const char *service, + const char *uuid, DBusGMethodInvocation *context) +{ + DBusGProxy *object; + const char *adapter = NULL, *name = NULL; + gchar *device, *profile, *line; + + if (auto_authorize == TRUE) { + dbus_g_method_return(context); + return TRUE; + } + + object = dbus_g_proxy_new_for_name(conn, "org.bluez", + path, "org.bluez.Adapter"); + + dbus_g_proxy_call(object, "GetName", NULL, G_TYPE_INVALID, + G_TYPE_STRING, &adapter, G_TYPE_INVALID); + + dbus_g_proxy_call(object, "GetRemoteName", NULL, + G_TYPE_STRING, address, G_TYPE_INVALID, + G_TYPE_STRING, &name, G_TYPE_INVALID); + + object = dbus_g_proxy_new_for_name(conn, "org.bluez", + service, "org.bluez.Service"); + + dbus_g_proxy_call(object, "GetName", NULL, G_TYPE_INVALID, + G_TYPE_STRING, &profile, G_TYPE_INVALID); + + if (name) { + if (g_strrstr(name, address)) + device = g_strdup(name); + else + device = g_strdup_printf("%s (%s)", name, address); + } else + device = g_strdup(address); + + auth_dialog(path, address, service, uuid, device, profile, context); + + line = g_strdup_printf(_("Authorization request for %s"), device); + g_free(device); + + show_notification(adapter ? adapter : _("Bluetooth device"), + line, _("Check authorization"), 0, + G_CALLBACK(notification_closed)); + + g_free(line); + + return TRUE; +} + +static gboolean auth_agent_cancel(PasskeyAgent *agent, + const char *path, const char *address, const char *service, + const char *uuid, DBusGMethodInvocation *context) +{ + GList *list; + GError *result; + struct input_data *input; + + input = g_try_malloc0(sizeof(*input)); + if (!input) + return FALSE; + + input->path = g_strdup(path); + input->address = g_strdup(address); + input->service = g_strdup(service); + input->uuid = g_strdup(uuid); + + list = g_list_find_custom(input_list, input, input_compare); + + g_free(input->uuid); + g_free(input->service); + g_free(input->address); + g_free(input->path); + g_free(input); + + if (!list || !list->data) + return FALSE; + + input = list->data; + + close_notification(); + + result = g_error_new(AGENT_ERROR, AGENT_ERROR_REJECT, + "Agent callback canceled"); + + dbus_g_method_return_error(input->context, result); + + input_free(input); + + return TRUE; +} + +static gboolean auth_agent_release(PasskeyAgent *agent, GError **error) +{ + registered_auth = 0; + + return TRUE; +} + +#include "auth-agent-glue.h" + +int register_agents(GtkStatusIcon *_statusicon) +{ + DBusGProxy *object; + GError *error = NULL; + + if (registered_passkey && registered_auth) + return 0; + + object = dbus_g_proxy_new_for_name(conn, "org.bluez", + "/org/bluez", "org.bluez.Security"); + + if (!registered_passkey) { + dbus_g_proxy_call(object, "RegisterDefaultPasskeyAgent", + &error, G_TYPE_STRING, PASSKEY_AGENT_PATH, + G_TYPE_INVALID, G_TYPE_INVALID); + + if (error != NULL) { + g_error_free(error); + return -1; + } + + registered_passkey = 1; + } + + if (!registered_auth) { + dbus_g_proxy_call(object, "RegisterDefaultAuthorizationAgent", + &error, G_TYPE_STRING, AUTH_AGENT_PATH, + G_TYPE_INVALID, G_TYPE_INVALID); + + if (error != NULL) { + g_error_free(error); + return -1; + } + + registered_auth = 1; + } + + /* To test a particular type of authorization or pairing question */ + //passkey_dialog("/org/bluez/hci0", "00:11:22:33:44:55", "Test", NULL); + //confirm_dialog("/org/bluez/hci0", "00:11:22:33:44:55", "123456", "Test", NULL); + //auth_dialog("/org/bluez/hci0", "00:11:22:33:44:55", "/org/bluez/echo", "", "Test", "Echo service", NULL); + + statusicon = g_object_ref(_statusicon); + + return 0; +} + +void unregister_agents(void) +{ + registered_passkey = 0; + registered_auth = 0; + + if (conn) { + dbus_g_connection_unref(conn); + conn = NULL; + } + if (statusicon) { + g_object_unref(statusicon); + statusicon = NULL; + } +} + +void flush_input(void) +{ + close_notification(); + + g_list_foreach(input_list, show_dialog, NULL); + + gtk_status_icon_set_blinking(statusicon, FALSE); +} + +void setup_agent_dbus(DBusGConnection *_conn) +{ + void *agent; + + dbus_g_object_type_install_info(PASSKEY_AGENT_OBJECT_TYPE, + &dbus_glib_passkey_agent_object_info); + + dbus_g_object_type_install_info(AUTH_AGENT_OBJECT_TYPE, + &dbus_glib_auth_agent_object_info); + + dbus_g_error_domain_register(AGENT_ERROR, "org.bluez.Error", + AGENT_ERROR_TYPE); + + conn = dbus_g_connection_ref(_conn); + + agent = passkey_agent_new(PASSKEY_AGENT_PATH); + + agent = auth_agent_new(AUTH_AGENT_PATH); +} + +void set_auto_authorize(gboolean value) +{ + auto_authorize = value; +} + --- /dev/null 2008-01-24 17:45:36.352009045 +0000 +++ agent.h 2008-02-07 01:12:05.000000000 +0000 @@ -0,0 +1,29 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2005-2008 Marcel Holtmann <marcel@holtmann.org> + * Copyright (C) 2006-2008 Bastien Nocera <hadess@hadess.net> + * + * + * 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 + * + */ + +int register_agents(GtkStatusIcon *_statusicon); +void unregister_agents(void); +void flush_input(void); +void setup_agent_dbus(DBusGConnection *_conn); +void set_auto_authorize(gboolean auto_authorize); [-- Attachment #3: Type: text/plain, Size: 228 bytes --] ------------------------------------------------------------------------- This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2008. http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ [-- Attachment #4: Type: text/plain, Size: 164 bytes --] _______________________________________________ Bluez-devel mailing list Bluez-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/bluez-devel ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Bluez-devel] [PATCH] Split agents 2008-02-07 1:13 ` Bastien Nocera @ 2008-02-10 1:21 ` Marcel Holtmann 2008-02-10 2:02 ` Marcel Holtmann 0 siblings, 1 reply; 6+ messages in thread From: Marcel Holtmann @ 2008-02-10 1:21 UTC (permalink / raw) To: BlueZ development Hi Bastien, > > > First draft patch to split the agents away from the main program. Seems > > > to work fine for me. > > > > > > This is mostly moving functions around though. > > > > Updated patch following the comments from Marcel. > > Patch that compiles again. I like the split of the notifications. Can we do that first in a separate patch. Looks simple enough and makes the history a lot cleaner compared to a big one. Three small things with it: * Please use notify.[ch] as filename. I don't like too long file names. * No need to include <glib/gi18n.h>. No translations in this file. * I saw some whitespaces and empty line things mistakes. Regards Marcel ------------------------------------------------------------------------- This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2008. http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ _______________________________________________ Bluez-devel mailing list Bluez-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/bluez-devel ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Bluez-devel] [PATCH] Split agents 2008-02-10 1:21 ` Marcel Holtmann @ 2008-02-10 2:02 ` Marcel Holtmann 2008-02-10 4:00 ` Marcel Holtmann 0 siblings, 1 reply; 6+ messages in thread From: Marcel Holtmann @ 2008-02-10 2:02 UTC (permalink / raw) To: BlueZ development Hi Bastien, > > > > First draft patch to split the agents away from the main program. Seems > > > > to work fine for me. > > > > > > > > This is mostly moving functions around though. > > > > > > Updated patch following the comments from Marcel. > > > > Patch that compiles again. > > I like the split of the notifications. Can we do that first in a > separate patch. Looks simple enough and makes the history a lot cleaner > compared to a big one. actually just did it by myself. Care to update the split agents patch. Regards Marcel ------------------------------------------------------------------------- This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2008. http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ _______________________________________________ Bluez-devel mailing list Bluez-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/bluez-devel ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Bluez-devel] [PATCH] Split agents 2008-02-10 2:02 ` Marcel Holtmann @ 2008-02-10 4:00 ` Marcel Holtmann 0 siblings, 0 replies; 6+ messages in thread From: Marcel Holtmann @ 2008-02-10 4:00 UTC (permalink / raw) To: BlueZ development Hi Bastien, > > > > > First draft patch to split the agents away from the main program. Seems > > > > > to work fine for me. > > > > > > > > > > This is mostly moving functions around though. > > > > > > > > Updated patch following the comments from Marcel. > > > > > > Patch that compiles again. > > > > I like the split of the notifications. Can we do that first in a > > separate patch. Looks simple enough and makes the history a lot cleaner > > compared to a big one. > > actually just did it by myself. Care to update the split agents patch. and did the agent split by myself, too. Ended up in bluez-gnome-0.18 release. Please test :) Regards Marcel ------------------------------------------------------------------------- This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2008. http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ _______________________________________________ Bluez-devel mailing list Bluez-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/bluez-devel ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2008-02-10 4:00 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2008-02-01 17:44 [Bluez-devel] [PATCH] Split agents Bastien Nocera 2008-02-06 13:46 ` Bastien Nocera 2008-02-07 1:13 ` Bastien Nocera 2008-02-10 1:21 ` Marcel Holtmann 2008-02-10 2:02 ` Marcel Holtmann 2008-02-10 4:00 ` Marcel Holtmann
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox