+/* search the eventid */
+static struct dbus_event *api_dbus_client_event_search(struct api_dbus *api, int id, const char *name)
+{
+ struct dbus_event *ev;
+
+ ev = api->client.events;
+ while (ev != NULL && (ev->id != id || 0 != strcmp(afb_evt_event_x2_fullname(ev->event), name)))
+ ev = ev->next;
+
+ return ev;
+}
+
+/* adds an eventid */
+static void api_dbus_client_event_create(struct api_dbus *api, int id, const char *name)
+{
+ struct dbus_event *ev;
+
+ /* check conflicts */
+ ev = api_dbus_client_event_search(api, id, name);
+ if (ev != NULL) {
+ ev->refcount++;
+ return;
+ }
+
+ /* no conflict, try to add it */
+ ev = malloc(sizeof *ev);
+ if (ev != NULL) {
+ ev->event = afb_evt_event_x2_create(name);
+ if (ev->event == NULL)
+ free(ev);
+ else {
+ ev->refcount = 1;
+ ev->id = id;
+ ev->next = api->client.events;
+ api->client.events = ev;
+ return;
+ }
+ }
+ ERROR("can't create event %s, out of memory", name);
+}
+
+/* removes an eventid */
+static void api_dbus_client_event_drop(struct api_dbus *api, int id, const char *name)
+{
+ struct dbus_event *ev, **prv;
+
+ /* retrieves the event */
+ ev = api_dbus_client_event_search(api, id, name);
+ if (ev == NULL) {
+ ERROR("event %s not found", name);
+ return;
+ }
+
+ /* decrease the reference count */
+ if (--ev->refcount)
+ return;
+
+ /* unlinks the event */
+ prv = &api->client.events;
+ while (*prv != ev)
+ prv = &(*prv)->next;
+ *prv = ev->next;
+
+ /* destroys the event */
+ afb_evt_event_x2_unref(ev->event);
+ free(ev);
+}
+
+/* pushs an event */
+static void api_dbus_client_event_push(struct api_dbus *api, int id, const char *name, const char *data)
+{
+ struct json_object *object;
+ struct dbus_event *ev;
+ enum json_tokener_error jerr;
+
+ /* retrieves the event */
+ ev = api_dbus_client_event_search(api, id, name);
+ if (ev == NULL) {
+ ERROR("event %s not found", name);
+ return;
+ }
+
+ /* destroys the event */
+ object = json_tokener_parse_verbose(data, &jerr);
+ if (jerr != json_tokener_success)
+ object = json_object_new_string(data);
+ afb_evt_event_x2_push(ev->event, object);
+}
+
+/* subscribes an event */
+static void api_dbus_client_event_subscribe(struct api_dbus *api, int id, const char *name, uint64_t msgid)
+{
+ int rc;
+ struct dbus_event *ev;
+ struct dbus_memo *memo;
+
+ /* retrieves the event */
+ ev = api_dbus_client_event_search(api, id, name);
+ if (ev == NULL) {
+ ERROR("event %s not found", name);
+ return;
+ }
+
+ /* retrieves the memo */
+ memo = api_dbus_client_memo_search(api, msgid);
+ if (memo == NULL) {
+ ERROR("message not found");
+ return;
+ }
+
+ /* subscribe the request to the event */
+ rc = afb_xreq_subscribe(memo->xreq, ev->event);
+ if (rc < 0)
+ ERROR("can't subscribe: %m");
+}
+
+/* unsubscribes an event */
+static void api_dbus_client_event_unsubscribe(struct api_dbus *api, int id, const char *name, uint64_t msgid)
+{
+ int rc;
+ struct dbus_event *ev;
+ struct dbus_memo *memo;
+
+ /* retrieves the event */
+ ev = api_dbus_client_event_search(api, id, name);
+ if (ev == NULL) {
+ ERROR("event %s not found", name);
+ return;
+ }
+
+ /* retrieves the memo */
+ memo = api_dbus_client_memo_search(api, msgid);
+ if (memo == NULL) {
+ ERROR("message not found");
+ return;
+ }
+
+ /* unsubscribe the request from the event */
+ rc = afb_xreq_unsubscribe(memo->xreq, ev->event);
+ if (rc < 0)
+ ERROR("can't unsubscribe: %m");
+}
+
+/* receives calls for event */
+static int api_dbus_client_on_manage_event(sd_bus_message *m, void *userdata, sd_bus_error *ret_error)
+{
+ const char *eventname, *data;
+ int rc;
+ int32_t eventid;
+ uint8_t order;
+ struct api_dbus *api;
+ uint64_t msgid;
+
+ /* check if expected message */
+ api = userdata;
+ if (0 != strcmp(api->name, sd_bus_message_get_interface(m)))
+ return 0; /* not the expected interface */
+ if (0 != strcmp("event", sd_bus_message_get_member(m)))
+ return 0; /* not the expected member */
+ if (sd_bus_message_get_expect_reply(m))
+ return 0; /* not the expected type of message */
+
+ /* reads the message */
+ rc = sd_bus_message_read(m, "yisst", &order, &eventid, &eventname, &data, &msgid);
+ if (rc < 0) {
+ ERROR("unreadable event");
+ return 1;
+ }
+
+ /* what is the order ? */
+ switch ((char)order) {
+ case '+': /* creates the event */
+ api_dbus_client_event_create(api, eventid, eventname);
+ break;
+ case '-': /* drops the event */
+ api_dbus_client_event_drop(api, eventid, eventname);
+ break;
+ case '!': /* pushs the event */
+ api_dbus_client_event_push(api, eventid, eventname, data);
+ break;
+ case 'S': /* subscribe event for a request */
+ api_dbus_client_event_subscribe(api, eventid, eventname, msgid);
+ break;
+ case 'U': /* unsubscribe event for a request */
+ api_dbus_client_event_unsubscribe(api, eventid, eventname, msgid);
+ break;
+ default:
+ /* unexpected order */
+ ERROR("unexpected order '%c' received", (char)order);
+ break;
+ }
+ return 1;
+}
+
+static struct afb_api_itf dbus_api_itf = {
+ .call = api_dbus_client_call
+};
+