diff --git a/src/usb_moded-dbus-private.h b/src/usb_moded-dbus-private.h index 176a840..ee44dd2 100644 --- a/src/usb_moded-dbus-private.h +++ b/src/usb_moded-dbus-private.h @@ -23,6 +23,12 @@ 02110-1301 USA */ +/** Logical name for org.freedesktop.DBus.GetNameOwner method */ +#define DBUS_GET_NAME_OWNER_REQ "GetNameOwner" + +/** Logical name for org.freedesktop.DBus.NameOwnerChanged signal */ +#define DBUS_NAME_OWNER_CHANGED_SIG "NameOwnerChanged" + /* Connect to D-Bus System Bus */ gboolean usb_moded_dbus_init_connection(void); @@ -47,3 +53,10 @@ int usb_moded_send_supported_modes_signal(const char *supported_modes); /* send hidden modes signal system bus */ int usb_moded_send_hidden_modes_signal(const char *hidden_modes); +/* Callback function type used with usb_moded_get_name_owner_async() */ +typedef void (*usb_moded_get_name_owner_fn)(const char *owner); + +/* Asynchronous GetNameOwner query */ +gboolean usb_moded_get_name_owner_async(const char *name, + usb_moded_get_name_owner_fn cb, + DBusPendingCall **ppc); diff --git a/src/usb_moded-dbus.c b/src/usb_moded-dbus.c index 537893f..2dd40df 100644 --- a/src/usb_moded-dbus.c +++ b/src/usb_moded-dbus.c @@ -452,7 +452,6 @@ static DBusHandlerResult msg_handler(DBusConnection *const connection, DBusMessa } } - EXIT: if(reply) @@ -659,3 +658,104 @@ int usb_moded_send_hidden_modes_signal(const char *hidden_modes) { return(usb_moded_dbus_signal(USB_MODE_HIDDEN_MODES_SIGNAL_NAME, hidden_modes)); } + +/** Async reply handler for usb_moded_get_name_owner_async() + * + * @param pc Pending call object pointer + * @param aptr Notify function to call (as a void pointer) + */ +static void usb_moded_get_name_owner_cb(DBusPendingCall *pc, void *aptr) +{ + usb_moded_get_name_owner_fn cb = aptr; + + DBusMessage *rsp = 0; + const char *dta = 0; + DBusError err = DBUS_ERROR_INIT; + + if( !(rsp = dbus_pending_call_steal_reply(pc)) ) { + log_err("did not get reply"); + goto EXIT; + } + + if( dbus_set_error_from_message(&err, rsp) ) + { + if( strcmp(err.name, DBUS_ERROR_NAME_HAS_NO_OWNER) ) + log_err("error reply: %s: %s", err.name, err.message); + goto EXIT; + } + + if( !dbus_message_get_args(rsp, &err, + DBUS_TYPE_STRING, &dta, + DBUS_TYPE_INVALID) ) + { + if( strcmp(err.name, DBUS_ERROR_NAME_HAS_NO_OWNER) ) + log_warning("parse error: %s: %s", err.name, err.message); + goto EXIT; + } + +EXIT: + /* Allways call the notification function. Equate any error + * situations with "service does not have an owner". */ + cb(dta ?: ""); + + if( rsp ) dbus_message_unref(rsp); + + dbus_error_free(&err); +} + +/** Helper function for making async dbus name owner queries + * + * @param name D-Bus name to query + * @param cb Function to call when async reply is received + * @param ppc Where to store pending call object, or NULL + * + * @return TRUE if method call was sent, FALSE otherwise + */ +gboolean usb_moded_get_name_owner_async(const char *name, + usb_moded_get_name_owner_fn cb, + DBusPendingCall **ppc) +{ + gboolean ack = FALSE; + DBusMessage *req = 0; + DBusPendingCall *pc = 0; + + if(!dbus_connection_sys) + goto EXIT; + + req = dbus_message_new_method_call(DBUS_INTERFACE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + DBUS_GET_NAME_OWNER_REQ); + if( !req ) { + log_err("could not create method call message"); + goto EXIT; + } + + if( !dbus_message_append_args(req, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_INVALID) ) { + log_err("could not add method call parameters"); + goto EXIT; + } + + if( !dbus_connection_send_with_reply(dbus_connection_sys, req, &pc, -1) ) + goto EXIT; + + if( !pc ) + goto EXIT; + + if( !dbus_pending_call_set_notify(pc, usb_moded_get_name_owner_cb, cb, 0) ) + goto EXIT; + + ack = TRUE; + + if( ppc ) + *ppc = pc, pc = 0; + +EXIT: + + if( pc ) dbus_pending_call_unref(pc); + if( req ) dbus_message_unref(req); + + return ack; +}