#include "e_dbus_private.h"
#include "dbus/dbus.h"
-static Ecore_List *signal_handlers = NULL;
-
-static Ecore_Event_Handler *event_handler = NULL;
static int init = 0;
-
struct E_DBus_Signal_Handler
{
char *sender;
static int cb_signal_event(void *data, int type, void *event);
-void e_dbus_signal_handler_free(E_DBus_Signal_Handler *sh);
-
-
-/**
- * Initialize the signal subsystem
- * @internal
- */
-int
-e_dbus_signal_init(void)
-{
- if (++init != 1) return init;
- signal_handlers = ecore_list_new();
- if (!signal_handlers) {--init; return 0;};
- ecore_list_free_cb_set(signal_handlers, ECORE_FREE_CB(e_dbus_signal_handler_free));
-
- event_handler = ecore_event_handler_add(E_DBUS_EVENT_SIGNAL, cb_signal_event, NULL);
- return init;
-}
-
-/**
- * Shutdown the signal subsystem
- * @internal
- */
-void
-e_dbus_signal_shutdown(void)
-{
- if (--init) return;
- ecore_list_destroy(signal_handlers);
-
- if (event_handler) ecore_event_handler_del(event_handler);
- event_handler = NULL;
-}
-
/**
* Free a signal handler
* @param sh the signal handler to free
*/
-void
+static void
e_dbus_signal_handler_free(E_DBus_Signal_Handler *sh)
{
- if (sh->sender) free(sh->sender);
- if (sh->path) free(sh->path);
- if (sh->interface) free(sh->interface);
- if (sh->member) free(sh->member);
-
+ free(sh->sender);
free(sh);
}
+struct cb_name_owner_data
+{
+ E_DBus_Connection *conn;
+ E_DBus_Signal_Handler *sh;
+};
+
static void
cb_name_owner(void *data, DBusMessage *msg, DBusError *err)
{
const char *unique_name = NULL;
+ struct cb_name_owner_data *d = data;
+ E_DBus_Connection *conn;
E_DBus_Signal_Handler *sh;
- sh = data;
+ conn = d->conn;
+ sh = d->sh;
+ free(d);
if (dbus_error_is_set(err))
- {
- if (ecore_list_goto(signal_handlers, sh))
- ecore_list_remove(signal_handlers);
- dbus_error_free(err);
- return;
- }
+ goto error;
dbus_message_get_args(msg, err, DBUS_TYPE_STRING, &unique_name, DBUS_TYPE_INVALID);
if (dbus_error_is_set(err))
- {
- DEBUG(1, "Invalid signature in reply to name owner call\n");
- dbus_error_free(err);
- return;
- }
+ goto error;
- if (unique_name)
- {
- if (sh->sender) free(sh->sender);
- sh->sender = strdup(unique_name);
- }
- else DEBUG(1, "Error, no unique name?\n");
+ if (!unique_name)
+ goto error;
+
+ free(sh->sender);
+ sh->sender = strdup(unique_name);
+
+ return;
+
+ error:
+ if (err)
+ DEBUG(1, "ERROR: %s %s\n", err->name, err->message);
+
+ if (ecore_list_goto(conn->signal_handlers, sh))
+ ecore_list_remove(conn->signal_handlers);
+ e_dbus_signal_handler_free(sh);
+ dbus_error_free(err);
+}
+
+static int
+_match_append(char *buf, int size, int *used, const char *keyword, int keyword_size, const char *value, int value_size)
+{
+ if (*used + keyword_size + value_size + sizeof(",=''") >= size)
+ {
+ DEBUG(1, "ERROR: cannot add match %s='%s': too long!\n", keyword, value);
+ return 0;
+ }
+
+ buf += *used;
+
+ *buf = ',';
+ buf++;
+
+ memcpy(buf, keyword, keyword_size);
+ buf += keyword_size;
+
+ *buf = '=';
+ buf++;
+ *buf = '\'';
+ buf++;
+
+ memcpy(buf, value, value_size);
+ buf += value_size;
+
+ *buf = '\'';
+ buf++;
+
+ *buf = '\0';
+
+ *used += keyword_size + value_size + sizeof(",=''") - 1;
+
+ return 1;
}
/**
{
E_DBus_Signal_Handler *sh;
char match[DBUS_MAXIMUM_MATCH_RULE_LENGTH];
- int started = 0;
- int len = 0;
+ int len, sender_len, path_len, interface_len, member_len;
DBusError err;
- sh = calloc(1, sizeof(E_DBus_Signal_Handler));
-
strcpy(match, "type='signal'");
- len = 13;
-
+ len = sizeof("type='signal'") - 1;
+
+#define ADD_MATCH_PIECE(PIECE) \
+ do { \
+ PIECE ## _len = PIECE ? strlen(PIECE) : 0; \
+ if (!_match_append(match, sizeof(match), &len, #PIECE, sizeof(#PIECE) - 1, PIECE, PIECE ## _len)) \
+ return NULL; \
+ } while (0)
+
+ ADD_MATCH_PIECE(sender);
+ ADD_MATCH_PIECE(path);
+ ADD_MATCH_PIECE(interface);
+ ADD_MATCH_PIECE(member);
#undef ADD_MATCH_PIECE
-#define ADD_MATCH_PIECE(PIECE) \
- if (PIECE) \
- {\
- len += strlen("," #PIECE "=''") + strlen(PIECE);\
- if (len >= sizeof(match)) return NULL;\
- strcat(match, "," #PIECE "='");\
- strcat(match, PIECE);\
- strcat(match, "'");\
- sh->PIECE = strdup(PIECE);\
- started = 1;\
- }
- ADD_MATCH_PIECE(sender)
- ADD_MATCH_PIECE(path)
- ADD_MATCH_PIECE(interface)
- ADD_MATCH_PIECE(member)
+ len = path_len + interface_len + member_len + 4;
+ sh = malloc(sizeof(*sh) + len);
+ if (!sh)
+ {
+ DEBUG(1, "ERROR: could not allocate signal handler.\n");
+ return NULL;
+ }
+
+ len = sizeof(*sh);
+
+#define SET_STRING(PIECE) \
+ do { \
+ sh->PIECE = (char *)sh + len; \
+ if (PIECE) \
+ memcpy(sh->PIECE, PIECE, PIECE ## _len + 1); \
+ else \
+ sh->PIECE = NULL; \
+ len += PIECE ## _len + 1; \
+ } while (0)
+
+ SET_STRING(path);
+ SET_STRING(interface);
+ SET_STRING(member);
+#undef SET_STRING
+
+ sh->sender = strdup(sender);
sh->cb_signal = cb_signal;
sh->data = data;
+ sh->delete_me = 0;
dbus_error_init(&err);
dbus_bus_add_match(conn->conn, match, NULL);
- ecore_list_append(signal_handlers, sh);
+
+ if (!conn->signal_handlers)
+ {
+ conn->signal_handlers = ecore_list_new();
+ ecore_list_free_cb_set
+ (conn->signal_handlers, ECORE_FREE_CB(e_dbus_signal_handler_free));
+ conn->signal_dispatcher = ecore_event_handler_add
+ (E_DBUS_EVENT_SIGNAL, cb_signal_event, conn);
+ }
/* if we have a sender, and it is not a unique name, we need to know the unique name to match since signals will have the name owner as ther sender. */
if (sender && sender[0] != ':')
- e_dbus_get_name_owner(conn, sender, cb_name_owner, sh);
-
+ {
+ struct cb_name_owner_data *data;
+ data = malloc(sizeof(*data));
+ if (!data)
+ {
+ e_dbus_signal_handler_free(sh);
+ return NULL;
+ }
+ data->conn = conn;
+ data->sh = sh;
+ e_dbus_get_name_owner(conn, sender, cb_name_owner, data);
+ }
+
+ ecore_list_append(conn->signal_handlers, sh);
return sh;
}
e_dbus_signal_handler_del(E_DBus_Connection *conn, E_DBus_Signal_Handler *sh)
{
char match[DBUS_MAXIMUM_MATCH_RULE_LENGTH];
- int len = 0;
+ int len, sender_len, path_len, interface_len, member_len;
sh->delete_me = 1;
if (e_dbus_idler_active)
}
strcpy(match, "type='signal'");
- len = 13;
-
+ len = sizeof("type='signal'") - 1;
+
+#define ADD_MATCH_PIECE(PIECE) \
+ do { \
+ PIECE ## _len = sh->PIECE ? strlen(sh->PIECE) : 0; \
+ if (!_match_append(match, sizeof(match), &len, #PIECE, sizeof(#PIECE) - 1, sh->PIECE, PIECE ## _len)) \
+ return; \
+ } while (0)
+
+ ADD_MATCH_PIECE(sender);
+ ADD_MATCH_PIECE(path);
+ ADD_MATCH_PIECE(interface);
+ ADD_MATCH_PIECE(member);
#undef ADD_MATCH_PIECE
-#define ADD_MATCH_PIECE(PIECE) \
- if (PIECE) \
- {\
- len += strlen("," #PIECE "=''") + strlen(PIECE);\
- if (len >= sizeof(match)) return;\
- strcat(match, "," #PIECE "='");\
- strcat(match, PIECE);\
- strcat(match, "'");\
- }
-
- ADD_MATCH_PIECE(sh->sender)
- ADD_MATCH_PIECE(sh->path)
- ADD_MATCH_PIECE(sh->interface)
- ADD_MATCH_PIECE(sh->member)
dbus_bus_remove_match(conn->conn, match, NULL);
- if (!ecore_list_goto(signal_handlers, sh)) return;
- ecore_list_remove(signal_handlers);
- free(sh->sender);
- free(sh->path);
- free(sh->interface);
- free(sh->member);
- free(sh);
+ if (!conn->signal_handlers) return;
+ if (!ecore_list_goto(conn->signal_handlers, sh)) return;
+ ecore_list_remove(conn->signal_handlers);
+ e_dbus_signal_handler_free(sh);
}
static int
cb_signal_event(void *data, int type, void *event)
{
+ E_DBus_Connection *conn = data;
DBusMessage *msg = event;
E_DBus_Signal_Handler *sh;
- ecore_list_first_goto(signal_handlers);
- while ((sh = ecore_list_next(signal_handlers)))
+ ecore_list_first_goto(conn->signal_handlers);
+ while ((sh = ecore_list_next(conn->signal_handlers)))
{
if ((!sh->cb_signal) || (sh->delete_me)) continue;
E_DBus_Signal_Handler *sh;
if (!e_dbus_handler_deletions) return;
- ecore_list_first_goto(signal_handlers);
- while ((sh = ecore_list_next(signal_handlers)))
+ if (!conn->signal_handlers) return;
+ ecore_list_first_goto(conn->signal_handlers);
+ while ((sh = ecore_list_next(conn->signal_handlers)))
{
if (sh->delete_me)
e_dbus_signal_handler_del(conn, sh);