handler: allow to add same handler callback with different userdata
According to #97. A single callback can distinguish different cases using the userdata. Current implementation doesn't allow to delete a particular couple (handler, userdata), but rather deletes all handlers regardless of the userdata.
This commit is contained in:
194
src/handler.c
194
src/handler.c
@@ -40,14 +40,22 @@ void handler_fire_stanza(xmpp_conn_t * const conn,
|
|||||||
/* call id handlers */
|
/* call id handlers */
|
||||||
id = xmpp_stanza_get_id(stanza);
|
id = xmpp_stanza_get_id(stanza);
|
||||||
if (id) {
|
if (id) {
|
||||||
|
/* enable all added handlers */
|
||||||
|
item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
|
||||||
|
for (; item; item = item->next)
|
||||||
|
item->enabled = 1;
|
||||||
|
|
||||||
prev = NULL;
|
prev = NULL;
|
||||||
item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
|
item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
|
||||||
while (item) {
|
while (item) {
|
||||||
xmpp_handlist_t *next = item->next;
|
xmpp_handlist_t *next = item->next;
|
||||||
|
|
||||||
if (item->user_handler && !conn->authenticated) {
|
/* don't fire user handlers until authentication succeeds and
|
||||||
|
and skip newly added handlers */
|
||||||
|
if ((item->user_handler && !conn->authenticated) || !item->enabled) {
|
||||||
|
prev = item;
|
||||||
item = next;
|
item = next;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!((xmpp_handler)(item->handler))(conn, stanza, item->userdata)) {
|
if (!((xmpp_handler)(item->handler))(conn, stanza, item->userdata)) {
|
||||||
@@ -80,15 +88,9 @@ void handler_fire_stanza(xmpp_conn_t * const conn,
|
|||||||
prev = NULL;
|
prev = NULL;
|
||||||
item = conn->handlers;
|
item = conn->handlers;
|
||||||
while (item) {
|
while (item) {
|
||||||
/* skip newly added handlers */
|
/* don't fire user handlers until authentication succeeds and
|
||||||
if (!item->enabled) {
|
skip newly added handlers */
|
||||||
prev = item;
|
if ((item->user_handler && !conn->authenticated) || !item->enabled) {
|
||||||
item = item->next;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* don't call user handlers until authentication succeeds */
|
|
||||||
if (item->user_handler && !conn->authenticated) {
|
|
||||||
prev = item;
|
prev = item;
|
||||||
item = item->next;
|
item = item->next;
|
||||||
continue;
|
continue;
|
||||||
@@ -114,10 +116,8 @@ void handler_fire_stanza(xmpp_conn_t * const conn,
|
|||||||
if (item) {
|
if (item) {
|
||||||
prev = item;
|
prev = item;
|
||||||
item = item->next;
|
item = item->next;
|
||||||
} else if (prev)
|
} else
|
||||||
item = prev->next;
|
item = prev ? prev->next : conn->handlers;
|
||||||
else
|
|
||||||
item = conn->handlers;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,54 +131,58 @@ void handler_fire_stanza(xmpp_conn_t * const conn,
|
|||||||
uint64_t handler_fire_timed(xmpp_ctx_t * const ctx)
|
uint64_t handler_fire_timed(xmpp_ctx_t * const ctx)
|
||||||
{
|
{
|
||||||
xmpp_connlist_t *connitem;
|
xmpp_connlist_t *connitem;
|
||||||
xmpp_handlist_t *handitem, *temp;
|
xmpp_handlist_t *item, *prev;
|
||||||
int ret, fired;
|
xmpp_conn_t *conn;
|
||||||
uint64_t elapsed, min;
|
uint64_t elapsed, min;
|
||||||
|
int ret;
|
||||||
|
|
||||||
min = (uint64_t)(-1);
|
min = (uint64_t)(-1);
|
||||||
|
|
||||||
connitem = ctx->connlist;
|
connitem = ctx->connlist;
|
||||||
while (connitem) {
|
while (connitem) {
|
||||||
if (connitem->conn->state != XMPP_STATE_CONNECTED) {
|
conn = connitem->conn;
|
||||||
|
if (conn->state != XMPP_STATE_CONNECTED) {
|
||||||
connitem = connitem->next;
|
connitem = connitem->next;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* enable all handlers that were added */
|
/* enable all handlers that were added */
|
||||||
for (handitem = connitem->conn->timed_handlers; handitem;
|
for (item = conn->timed_handlers; item; item = item->next)
|
||||||
handitem = handitem->next)
|
item->enabled = 1;
|
||||||
handitem->enabled = 1;
|
|
||||||
|
|
||||||
handitem = connitem->conn->timed_handlers;
|
prev = NULL;
|
||||||
while (handitem) {
|
item = conn->timed_handlers;
|
||||||
/* skip newly added handlers */
|
while (item) {
|
||||||
if (!handitem->enabled) {
|
/* don't fire user handlers until authentication succeeds and
|
||||||
handitem = handitem->next;
|
skip newly added handlers */
|
||||||
|
if ((item->user_handler && !conn->authenticated) || !item->enabled) {
|
||||||
|
prev = item;
|
||||||
|
item = item->next;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* only fire user handlers after authentication */
|
elapsed = time_elapsed(item->last_stamp, time_stamp());
|
||||||
if (handitem->user_handler && !connitem->conn->authenticated) {
|
if (elapsed >= item->period) {
|
||||||
handitem = handitem->next;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
fired = 0;
|
|
||||||
elapsed = time_elapsed(handitem->last_stamp, time_stamp());
|
|
||||||
if (elapsed >= handitem->period) {
|
|
||||||
/* fire! */
|
/* fire! */
|
||||||
fired = 1;
|
item->last_stamp = time_stamp();
|
||||||
handitem->last_stamp = time_stamp();
|
ret = ((xmpp_timed_handler)item->handler)(conn, item->userdata);
|
||||||
ret = ((xmpp_timed_handler)handitem->handler)(connitem->conn, handitem->userdata);
|
if (!ret) {
|
||||||
} else if (min > (handitem->period - elapsed))
|
/* delete handler if it returned false */
|
||||||
min = handitem->period - elapsed;
|
if (prev)
|
||||||
|
prev->next = item->next;
|
||||||
|
else
|
||||||
|
conn->timed_handlers = item->next;
|
||||||
|
xmpp_free(conn->ctx, item);
|
||||||
|
item = NULL;
|
||||||
|
}
|
||||||
|
} else if (min > (item->period - elapsed))
|
||||||
|
min = item->period - elapsed;
|
||||||
|
|
||||||
temp = handitem;
|
if (item) {
|
||||||
handitem = handitem->next;
|
prev = item;
|
||||||
|
item = item->next;
|
||||||
/* delete handler if it returned false */
|
} else
|
||||||
if (fired && !ret)
|
item = prev ? prev->next : conn->timed_handlers;
|
||||||
xmpp_timed_handler_delete(connitem->conn, temp->handler);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
connitem = connitem->next;
|
connitem = connitem->next;
|
||||||
@@ -216,8 +220,10 @@ static void _timed_handler_add(xmpp_conn_t * const conn,
|
|||||||
|
|
||||||
/* check if handler is already in the list */
|
/* check if handler is already in the list */
|
||||||
for (item = conn->timed_handlers; item; item = item->next) {
|
for (item = conn->timed_handlers; item; item = item->next) {
|
||||||
if (item->handler == (void *)handler)
|
if (item->handler == (void *)handler && item->userdata == userdata) {
|
||||||
|
xmpp_warn(conn->ctx, "xmpp", "Timed handler already exists.");
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (item) return;
|
if (item) return;
|
||||||
|
|
||||||
@@ -262,19 +268,18 @@ void xmpp_timed_handler_delete(xmpp_conn_t * const conn,
|
|||||||
prev = NULL;
|
prev = NULL;
|
||||||
item = conn->timed_handlers;
|
item = conn->timed_handlers;
|
||||||
while (item) {
|
while (item) {
|
||||||
if (item->handler == (void *)handler)
|
if (item->handler == (void *)handler) {
|
||||||
break;
|
if (prev)
|
||||||
prev = item;
|
prev->next = item->next;
|
||||||
item = item->next;
|
else
|
||||||
}
|
conn->timed_handlers = item->next;
|
||||||
|
|
||||||
if (item) {
|
xmpp_free(conn->ctx, item);
|
||||||
if (prev)
|
item = prev ? prev->next : conn->timed_handlers;
|
||||||
prev->next = item->next;
|
} else {
|
||||||
else
|
prev = item;
|
||||||
conn->timed_handlers = item->next;
|
item = item->next;
|
||||||
|
}
|
||||||
xmpp_free(conn->ctx, item);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,8 +293,10 @@ static void _id_handler_add(xmpp_conn_t * const conn,
|
|||||||
/* check if handler is already in the list */
|
/* check if handler is already in the list */
|
||||||
item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
|
item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
|
||||||
while (item) {
|
while (item) {
|
||||||
if (item->handler == (void *)handler)
|
if (item->handler == (void *)handler && item->userdata == userdata) {
|
||||||
|
xmpp_warn(conn->ctx, "xmpp", "Id handler already exists.");
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
item = item->next;
|
item = item->next;
|
||||||
}
|
}
|
||||||
if (item) return;
|
if (item) return;
|
||||||
@@ -333,29 +340,30 @@ void xmpp_id_handler_delete(xmpp_conn_t * const conn,
|
|||||||
xmpp_handler handler,
|
xmpp_handler handler,
|
||||||
const char * const id)
|
const char * const id)
|
||||||
{
|
{
|
||||||
xmpp_handlist_t *item, *prev;
|
xmpp_handlist_t *item, *prev, *next;
|
||||||
|
|
||||||
prev = NULL;
|
prev = NULL;
|
||||||
item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
|
item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
|
||||||
if (!item) return;
|
if (!item) return;
|
||||||
|
|
||||||
while (item) {
|
while (item) {
|
||||||
if (item->handler == (void *)handler)
|
next = item->next;
|
||||||
break;
|
|
||||||
|
|
||||||
prev = item;
|
if (item->handler == (void *)handler) {
|
||||||
item = item->next;
|
if (prev)
|
||||||
}
|
prev->next = next;
|
||||||
|
else {
|
||||||
|
hash_drop(conn->id_handlers, id);
|
||||||
|
hash_add(conn->id_handlers, id, next);
|
||||||
|
}
|
||||||
|
|
||||||
if (item) {
|
xmpp_free(conn->ctx, item->id);
|
||||||
if (prev)
|
xmpp_free(conn->ctx, item);
|
||||||
prev->next = item->next;
|
item = next;
|
||||||
else {
|
} else {
|
||||||
hash_drop(conn->id_handlers, id);
|
prev = item;
|
||||||
hash_add(conn->id_handlers, id, item->next);
|
item = next;
|
||||||
}
|
}
|
||||||
xmpp_free(conn->ctx, item->id);
|
|
||||||
xmpp_free(conn->ctx, item);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -371,8 +379,12 @@ static void _handler_add(xmpp_conn_t * const conn,
|
|||||||
|
|
||||||
/* check if handler already in list */
|
/* check if handler already in list */
|
||||||
for (item = conn->handlers; item; item = item->next) {
|
for (item = conn->handlers; item; item = item->next) {
|
||||||
if (item->handler == (void *)handler)
|
/* same handler function can process different stanzas and
|
||||||
|
distinguish them according to userdata. */
|
||||||
|
if (item->handler == (void *)handler && item->userdata == userdata) {
|
||||||
|
xmpp_warn(conn->ctx, "xmpp", "Stanza handler already exists.");
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (item) return;
|
if (item) return;
|
||||||
|
|
||||||
@@ -441,23 +453,21 @@ void xmpp_handler_delete(xmpp_conn_t * const conn,
|
|||||||
prev = NULL;
|
prev = NULL;
|
||||||
item = conn->handlers;
|
item = conn->handlers;
|
||||||
while (item) {
|
while (item) {
|
||||||
if (item->handler == (void *)handler)
|
if (item->handler == (void *)handler) {
|
||||||
break;
|
if (prev)
|
||||||
|
prev->next = item->next;
|
||||||
|
else
|
||||||
|
conn->handlers = item->next;
|
||||||
|
|
||||||
prev = item;
|
if (item->ns) xmpp_free(conn->ctx, item->ns);
|
||||||
item = item->next;
|
if (item->name) xmpp_free(conn->ctx, item->name);
|
||||||
}
|
if (item->type) xmpp_free(conn->ctx, item->type);
|
||||||
|
xmpp_free(conn->ctx, item);
|
||||||
if (item) {
|
item = prev ? prev->next : conn->handlers;
|
||||||
if (prev)
|
} else {
|
||||||
prev->next = item->next;
|
prev = item;
|
||||||
else
|
item = item->next;
|
||||||
conn->handlers = item->next;
|
}
|
||||||
|
|
||||||
if (item->ns) xmpp_free(conn->ctx, item->ns);
|
|
||||||
if (item->name) xmpp_free(conn->ctx, item->name);
|
|
||||||
if (item->type) xmpp_free(conn->ctx, item->type);
|
|
||||||
xmpp_free(conn->ctx, item);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user