#define _GNU_SOURCE #include #include #include #include #include "live.h" #include "livebus.h" DBusConnection* openbus(char *address, char *where) { DBusConnection *conn; DBusError err; dbus_error_init(&err); conn = dbus_connection_open_private(address, &err); if(conn == NULL){ fail("open %s private IBus connection: %s", where, err.message != NULL ? err.message : "D-Bus error"); dbus_error_free(&err); return NULL; } dbus_error_free(&err); dbus_connection_set_exit_on_disconnect(conn, FALSE); return conn; } void closebus(DBusConnection **conn) { if(*conn == NULL) return; dbus_connection_close(*conn); dbus_connection_unref(*conn); *conn = NULL; } DBusMessage* contextcall(char *path, char *member) { return dbus_message_new_method_call("org.freedesktop.IBus", path, "org.freedesktop.IBus.InputContext", member); } DBusMessage* sendcall(DBusConnection *conn, DBusMessage *m, char *where) { DBusMessage *reply; DBusPendingCall *pending; int timeout; int64_t deadline; if(m == NULL){ fail("allocate %s call", where); return NULL; } pending = NULL; if(!dbus_connection_send_with_reply(conn, m, &pending, Calltimeout) || pending == NULL){ dbus_message_unref(m); fail("queue %s call", where); return NULL; } dbus_message_unref(m); deadline = nowms() + Calltimeout; while(!dbus_pending_call_get_completed(pending)){ timeout = leftms(deadline); if(timeout == 0){ fail("timed out waiting for %s", where); goto out; } if(!dbus_connection_read_write_dispatch(conn, timeout)){ fail("connection closed waiting for %s", where); goto out; } } reply = dbus_pending_call_steal_reply(pending); dbus_pending_call_unref(pending); if(reply == NULL) fail("%s completed without a reply", where); return reply; out: dbus_pending_call_cancel(pending); dbus_pending_call_unref(pending); return NULL; } DBusMessage* callret(DBusConnection *conn, DBusMessage *m, char *where) { DBusMessage *reply; reply = sendcall(conn, m, where); if(reply == NULL) return NULL; if(dbus_message_get_type(reply) != DBUS_MESSAGE_TYPE_METHOD_RETURN){ fail("%s returned D-Bus message type %d", where, dbus_message_get_type(reply)); dbus_message_unref(reply); return NULL; } return reply; } int hello(DBusConnection *conn, char *name, size_t nname, char *where) { DBusMessage *m, *reply; DBusError err; const char *s; int ok; m = dbus_message_new_method_call("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "Hello"); reply = callret(conn, m, where); if(reply == NULL) return 0; dbus_error_init(&err); ok = dbus_message_has_signature(reply, "s") && dbus_message_get_args(reply, &err, DBUS_TYPE_STRING, &s, DBUS_TYPE_INVALID); if(!ok) fail("%s returned an invalid Hello reply", where); else if(s[0] != ':') ok = fail("%s returned invalid Hello name %s", where, s); else if(name != NULL && snprintf(name, nname, "%s", s) >= (int)nname) ok = fail("%s Hello name is too long", where); dbus_error_free(&err); dbus_message_unref(reply); return ok; } int createcontext(DBusConnection *conn, char *path, size_t npath, char *where) { DBusMessage *m, *reply; DBusError err; const char *client, *p; int ok; client = testname; m = dbus_message_new_method_call("org.freedesktop.IBus", "/org/freedesktop/IBus", "org.freedesktop.IBus", "CreateInputContext"); if(m == NULL || !dbus_message_append_args(m, DBUS_TYPE_STRING, &client, DBUS_TYPE_INVALID)){ if(m != NULL) dbus_message_unref(m); return fail("build %s CreateInputContext call", where); } reply = callret(conn, m, where); if(reply == NULL) return 0; dbus_error_init(&err); ok = dbus_message_has_signature(reply, "o") && dbus_message_get_args(reply, &err, DBUS_TYPE_OBJECT_PATH, &p, DBUS_TYPE_INVALID); if(!ok) fail("%s returned an invalid context reply", where); else if(p[0] != '/') ok = fail("%s returned invalid context path %s", where, p); else if(path != NULL && snprintf(path, npath, "%s", p) >= (int)npath) ok = fail("%s context path is too long", where); dbus_error_free(&err); dbus_message_unref(reply); return ok; }