+int ctxClientEventListenerAdd(struct AFB_clientCtx *clientCtx, struct afb_event_listener listener)
+{
+ struct afb_event_listener_list *iter, **prv;
+
+ prv = &clientCtx->listeners;
+ for (;;) {
+ iter = *prv;
+ if (iter == NULL) {
+ iter = calloc(1, sizeof *iter);
+ if (iter == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+ iter->listener = listener;
+ iter->refcount = 1;
+ *prv = iter;
+ return 0;
+ }
+ if (iter->listener.itf == listener.itf && iter->listener.closure == listener.closure) {
+ iter->refcount++;
+ return 0;
+ }
+ prv = &iter->next;
+ }
+}
+
+void ctxClientEventListenerRemove(struct AFB_clientCtx *clientCtx, struct afb_event_listener listener)
+{
+ struct afb_event_listener_list *iter, **prv;
+
+ prv = &clientCtx->listeners;
+ for (;;) {
+ iter = *prv;
+ if (iter == NULL)
+ return;
+ if (iter->listener.itf == listener.itf && iter->listener.closure == listener.closure) {
+ if (!--iter->refcount) {
+ *prv = iter->next;
+ free(iter);
+ }
+ return;
+ }
+ prv = &iter->next;
+ }
+}
+
+static int send(struct AFB_clientCtx *clientCtx, const char *event, struct json_object *object)
+{
+ struct afb_event_listener_list *iter;
+ int result;
+
+ result = 0;
+ iter = clientCtx->listeners;
+ while (iter != NULL) {
+ iter->listener.itf->send(iter->listener.closure, event, json_object_get(object));
+ result++;
+ iter = iter->next;
+ }
+
+ return result;
+}
+
+int ctxClientEventSend(struct AFB_clientCtx *clientCtx, const char *event, struct json_object *object)
+{
+ long idx;
+ time_t now;
+ int result;
+
+ if (clientCtx != NULL)
+ result = send(clientCtx, event, object);
+ else {
+ result = 0;
+ now = NOW;
+ for (idx=0; idx < sessions.max; idx++) {
+ clientCtx = sessions.store[idx];
+ if (clientCtx != NULL && !ctxStoreTooOld(clientCtx, now)) {
+ clientCtx = ctxClientAddRef(clientCtx);
+ result += send(clientCtx, event, object);
+ ctxClientUnref(clientCtx);
+ }
+ }
+ }
+ return result;
+}
+
+const char *ctxClientGetUuid (struct AFB_clientCtx *clientCtx)
+{
+ assert(clientCtx != NULL);
+ return clientCtx->uuid;
+}
+
+const char *ctxClientGetToken (struct AFB_clientCtx *clientCtx)
+{
+ assert(clientCtx != NULL);
+ return clientCtx->token;
+}
+
+void *ctxClientValueGet(struct AFB_clientCtx *clientCtx, int index)
+{
+ assert(clientCtx != NULL);
+ assert(index >= 0);
+ assert(index < sessions.apicount);
+ return clientCtx->values[index].value;
+}
+
+void ctxClientValueSet(struct AFB_clientCtx *clientCtx, int index, void *value, void (*free_value)(void*))
+{
+ struct client_value prev;
+ assert(clientCtx != NULL);
+ assert(index >= 0);
+ assert(index < sessions.apicount);
+ prev = clientCtx->values[index];
+ clientCtx->values[index] = (struct client_value){.value = value, .free_value = free_value};
+ if (prev.value != NULL && prev.free_value != NULL)
+ prev.free_value(prev.value);
+}