--- a/disco.c Thu Oct 18 22:47:45 2012 +0300
+++ b/disco.c Sun Feb 17 05:59:50 2013 +0200
@@ -62,19 +62,20 @@
// private types
//
-// lm message handler userdata
-typedef struct {
- disco_info_handler_t handler;
- gpointer data;
- GDestroyNotify notify;
-} disco_info_reply_handler_t;
+#define DISCO_INFO_REQUEST ( 0 )
+#define DISCO_ITEMS_REQUEST ( 1 )
// lm message handler userdata
typedef struct {
- disco_items_handler_t handler;
- gpointer data;
- GDestroyNotify notify;
-} disco_items_reply_handler_t;
+ LmMessageHandler * reply_handler;
+ gpointer data;
+ GDestroyNotify notify;
+ guint type;
+ union {
+ disco_info_handler_t info;
+ disco_items_handler_t items;
+ } handler;
+} disco_request_t;
// user request disco handler userdata (common for info and items)
typedef struct {
@@ -87,41 +88,39 @@
//
#ifdef MCABBER_API_HAVE_CMD_ID
-static gpointer disco_cmid = NULL;
+static gpointer disco_cmid = NULL;
#endif
-
-static guint disco_cid = 0;
-static guint disco_hid = 0;
-static GSList *reply_handlers = NULL;
+static guint disco_cid = 0;
+static guint disco_hid = 0;
+static GSList * disco_requests = NULL;
//
// destroyers
//
-static void disco_info_reply_handler_destroy_notify (gpointer data)
+static void disco_request_free ( disco_request_t * cb )
{
- disco_info_reply_handler_t *cb = data;
- if (cb -> notify)
- cb -> notify (cb -> data);
- g_slice_free (disco_info_reply_handler_t, cb);
+ disco_requests = g_slist_remove ( disco_requests, cb );
+
+ if ( cb -> reply_handler ) {
+ lm_message_handler_invalidate ( cb -> reply_handler );
+#ifdef HAVE_LM_CONNECTION_UNREGISTER_REPLY_HANDLER
+ if ( lconnection )
+ lm_connection_unregister_reply_handler ( lconnection, cb -> reply_handler );
+#endif
+ }
+ if ( cb -> notify )
+ cb -> notify ( cb -> data );
+ g_slice_free ( disco_request_t, cb );
return;
}
-static void disco_items_reply_handler_destroy_notify (gpointer data)
+static void disco_handler_destroy_notify ( gpointer data )
{
- disco_items_reply_handler_t *cb = data;
- if (cb -> notify)
- cb -> notify (cb -> data);
- g_slice_free (disco_items_reply_handler_t, cb);
- return;
-}
-
-static void disco_handler_destroy_notify (gpointer data)
-{
- disco_handler_t *cb = data;
- g_free (cb -> jid);
- g_free (cb -> node);
- g_slice_free (disco_handler_t, cb);
+ disco_handler_t * cb = data;
+ g_free ( cb -> jid );
+ g_free ( cb -> node );
+ g_slice_free ( disco_handler_t, cb );
return;
}
@@ -129,52 +128,88 @@
// lm reply handlers
//
-static LmHandlerResult disco_info_reply_handler (LmMessageHandler *handler, LmConnection *connection, LmMessage *message, gpointer udata)
+static LmHandlerResult disco_reply_handler (LmMessageHandler *handler, LmConnection *connection, LmMessage *message, gpointer udata)
{
- disco_info_reply_handler_t *cb = udata;
-
- reply_handlers = g_slist_remove (reply_handlers, handler);
+ disco_request_t * cb = udata;
+ LmHandlerResult result = LM_HANDLER_RESULT_REMOVE_MESSAGE;
switch (lm_message_get_sub_type (message)) {
case LM_MESSAGE_SUB_TYPE_RESULT:
{
- LmMessageNode *node = lm_message_get_node (message);
- GSList *identities = NULL;
- GSList *features = NULL;
+ LmMessageNode *node = lm_message_get_node (message);
node = lm_message_node_get_child (node, "query");
- // check xmlns
- if (!node || g_strcmp0 (lm_message_node_get_attribute (node, "xmlns"), NS_DISCO_INFO))
- break;
+ if ( cb -> type == DISCO_INFO_REQUEST ) {
+
+ GSList * identities = NULL;
+ GSList * features = NULL;
+
+ // check xmlns
+ if (!node || g_strcmp0 (lm_message_node_get_attribute (node, "xmlns"), NS_DISCO_INFO))
+ break;
+
+ // parse request results
+ if (node->children)
+ for (node = node->children; node; node = node->next)
+ if (!strcasecmp (node->name, "identity")) {
+ disco_identity_t *identity = g_slice_new (disco_identity_t);
- // parse request results
- if (node->children)
- for (node = node->children; node; node = node->next)
- if (!strcasecmp (node->name, "identity")) {
- disco_identity_t *identity = g_slice_new (disco_identity_t);
+ identity -> category = lm_message_node_get_attribute (node, "category");
+ identity -> type = lm_message_node_get_attribute (node, "type");
+ identity -> name = lm_message_node_get_attribute (node, "name");
+ identity -> reserved = NULL;
+
+ identities = g_slist_append (identities, identity);
+ } else if (!strcasecmp (node->name, "feature"))
+ features = g_slist_insert_sorted (features, (gpointer) lm_message_node_get_attribute (node, "var"), (GCompareFunc) g_strcmp0);
- identity -> category = lm_message_node_get_attribute (node, "category");
- identity -> type = lm_message_node_get_attribute (node, "type");
- identity -> name = lm_message_node_get_attribute (node, "name");
- identity -> reserved = NULL;
+ // call handler
+ cb -> handler.info (identities, features, cb -> data);
+
+ { // free resources
+ GSList *iel;
+
+ for (iel = identities; iel; iel = iel -> next)
+ g_slice_free (disco_identity_t, iel -> data);
- identities = g_slist_append (identities, identity);
- } else if (!strcasecmp (node->name, "feature"))
- features = g_slist_insert_sorted (features, (gpointer) lm_message_node_get_attribute (node, "var"), (GCompareFunc) g_strcmp0);
+ g_slist_free (identities);
+ g_slist_free (features);
+ }
+
+ } else { // items request
+
+ GSList * items = NULL;
- // call handler
- cb -> handler (identities, features, cb -> data);
+ // check xmlns
+ if (!node || g_strcmp0 (lm_message_node_get_attribute (node, "xmlns"), NS_DISCO_ITEMS))
+ break;
+
+ // parse request results
+ if (node->children)
+ for (node = node->children; node; node = node->next)
+ if (!strcasecmp (node->name, "item")) {
+ disco_item_t *item = g_slice_new (disco_item_t);
- { // free resources
- GSList *iel;
+ item -> name = lm_message_node_get_attribute (node, "name");
+ item -> jid = lm_message_node_get_attribute (node, "jid");
+ item -> node = lm_message_node_get_attribute (node, "node");
+
+ items = g_slist_append (items, item);
+ }
- for (iel = identities; iel; iel = iel -> next)
- g_slice_free (disco_identity_t, iel -> data);
+ // call handler
+ cb -> handler.items (items, cb -> data);
+
+ { // free resources
+ GSList *iel;
- g_slist_free (identities);
- g_slist_free (features);
+ for (iel = items; iel; iel = iel -> next)
+ g_slice_free (disco_item_t, iel -> data);
+
+ g_slist_free (items);
+ }
}
}
@@ -196,95 +231,30 @@
reason = "undefined";
// XXX: we need to inform user, but do we really need to print this on every possible error?
- scr_log_print (LPRINT_LOGNORM, "disco: Service info discovery for %s failed: %s - %s", from, type, reason);
+ if ( cb -> type == DISCO_INFO_REQUEST ) {
+
+ scr_log_print (LPRINT_LOGNORM, "disco: Service info discovery for %s failed: %s - %s", from, type, reason);
+ cb -> handler.info (NULL, NULL, cb -> data);
- cb -> handler (NULL, NULL, cb -> data);
+ } else {
+
+ scr_log_print (LPRINT_LOGNORM, "disco: Service items discovery for %s failed: %s - %s", from, type, reason);
+ cb -> handler.items (NULL, cb -> data);
+ }
}
break;
default:
- return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
+
+ result = LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
+
+ break;
}
- return LM_HANDLER_RESULT_REMOVE_MESSAGE;
-}
-
-static LmHandlerResult disco_items_reply_handler (LmMessageHandler *handler, LmConnection *connection, LmMessage *message, gpointer udata)
-{
- disco_items_reply_handler_t *cb = udata;
-
- reply_handlers = g_slist_remove (reply_handlers, handler);
-
- switch (lm_message_get_sub_type (message)) {
- case LM_MESSAGE_SUB_TYPE_RESULT:
-
- {
- LmMessageNode *node = lm_message_get_node (message);
- GSList *items = NULL;
-
- node = lm_message_node_get_child (node, "query");
-
- // check xmlns
- if (!node || g_strcmp0 (lm_message_node_get_attribute (node, "xmlns"), NS_DISCO_ITEMS))
- break;
-
- // parse request results
- if (node->children)
- for (node = node->children; node; node = node->next)
- if (!strcasecmp (node->name, "item")) {
- disco_item_t *item = g_slice_new (disco_item_t);
-
- item -> name = lm_message_node_get_attribute (node, "name");
- item -> jid = lm_message_node_get_attribute (node, "jid");
- item -> node = lm_message_node_get_attribute (node, "node");
-
- items = g_slist_append (items, item);
- }
-
- // call handler
- cb -> handler (items, cb -> data);
-
- { // free resources
- GSList *iel;
-
- for (iel = items; iel; iel = iel -> next)
- g_slice_free (disco_item_t, iel -> data);
-
- g_slist_free (items);
- }
- }
-
- break;
-
- case LM_MESSAGE_SUB_TYPE_ERROR:
-
- {
- LmMessageNode *node = lm_message_get_node (message);
- const gchar *from = lm_message_node_get_attribute (node, "from");
- const gchar *type;
- const gchar *reason;
-
- node = lm_message_node_get_child (node, "error");
- type = lm_message_node_get_attribute (node, "type");
- if (node->children)
- reason = node->children->name;
- else
- reason = "undefined";
-
- // XXX: we need to inform user, but do we really need to print this on every possible error?
- scr_log_print (LPRINT_LOGNORM, "disco: Service items discovery for %s failed: %s - %s", from, type, reason);
-
- cb -> handler (NULL, cb -> data);
- }
-
- break;
-
- default:
- return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
- }
-
- return LM_HANDLER_RESULT_REMOVE_MESSAGE;
+ disco_request_free ( cb );
+
+ return result;
}
//
@@ -304,8 +274,10 @@
gpointer disco_info_request (const gchar *jid, const gchar *dnode, disco_info_handler_t handler, gpointer userdata, GDestroyNotify notify)
{
if (!handler || !xmpp_is_online ()) {
- if (notify)
- notify (userdata);
+ if ( handler )
+ handler ( NULL, NULL, userdata ); // XXX
+ if ( notify )
+ notify ( userdata );
return NULL;
}
@@ -333,10 +305,11 @@
#endif
{ // send request
- LmMessage *request;
- LmMessageNode *node;
- LmMessageHandler *lhandler;
- GError *error = NULL;
+ LmMessage * request;
+ LmMessageNode * node;
+ LmMessageHandler * lhandler;
+ GError * error = NULL;
+ disco_request_t * cb = g_slice_new ( disco_request_t );
request = lm_message_new_with_sub_type (jid, LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_GET);
node = lm_message_get_node (request);
@@ -345,47 +318,49 @@
if (dnode)
lm_message_node_set_attribute (node, "node", dnode);
- {
- disco_info_reply_handler_t *cb = g_slice_new (disco_info_reply_handler_t);
+ lhandler = lm_message_handler_new (disco_reply_handler, cb, NULL);
- lhandler = lm_message_handler_new (disco_info_reply_handler, cb, disco_info_reply_handler_destroy_notify);
-
- cb -> handler = handler;
- cb -> data = userdata;
- cb -> notify = notify;
+ cb -> reply_handler = lhandler;
+ cb -> type = DISCO_INFO_REQUEST;
+ cb -> handler.info = handler;
+ cb -> data = userdata;
+ cb -> notify = notify;
- reply_handlers = g_slist_append (reply_handlers, lhandler);
+ disco_requests = g_slist_append ( disco_requests, cb );
- lm_connection_send_with_reply (lconnection, request, lhandler, &error);
+ lm_connection_send_with_reply (lconnection, request, lhandler, &error);
- if (error) {
- // XXX destroy handler and return NULL?
- scr_log_print (LPRINT_DEBUG, "disco: Error sending disco request: %s.", error -> message);
- g_error_free (error);
- }
-
- lm_message_handler_unref (lhandler);
+ if (error) {
+ scr_log_print (LPRINT_DEBUG, "disco: Error sending disco request: %s.", error -> message);
+ g_error_free (error);
+ handler ( NULL, NULL, userdata ); // XXX
+ disco_request_free ( cb );
+ cb = NULL;
}
+ lm_message_handler_unref (lhandler);
lm_message_unref (request);
- return lhandler;
+ return cb;
}
}
gpointer disco_items_request (const gchar *jid, const gchar *dnode, disco_items_handler_t handler, gpointer userdata, GDestroyNotify notify)
{
if (!handler || !xmpp_is_online ()) {
- if (notify)
- notify (userdata);
+ if ( handler )
+ handler ( NULL, userdata ); // XXX
+ if ( notify )
+ notify ( userdata );
return NULL;
}
{ // send request
- LmMessage *request;
- LmMessageNode *node;
- GError *error = NULL;
- LmMessageHandler *lhandler;
+ LmMessage * request;
+ LmMessageNode * node;
+ LmMessageHandler * lhandler;
+ GError * error = NULL;
+ disco_request_t * cb = g_slice_new (disco_request_t);
request = lm_message_new_with_sub_type (jid, LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_GET);
node = lm_message_get_node (request);
@@ -394,49 +369,38 @@
if (dnode)
lm_message_node_set_attribute (node, "node", dnode);
- {
- disco_items_reply_handler_t *cb = g_slice_new (disco_items_reply_handler_t);
+ lhandler = lm_message_handler_new (disco_reply_handler, cb, NULL);
- lhandler = lm_message_handler_new (disco_items_reply_handler, cb, disco_items_reply_handler_destroy_notify);
-
- cb -> handler = handler;
- cb -> data = userdata;
- cb -> notify = notify;
+ cb -> reply_handler = lhandler;
+ cb -> type = DISCO_ITEMS_REQUEST;
+ cb -> handler.items = handler;
+ cb -> data = userdata;
+ cb -> notify = notify;
- reply_handlers = g_slist_append (reply_handlers, lhandler);
+ disco_requests = g_slist_append ( disco_requests, cb );
- lm_connection_send_with_reply (lconnection, request, lhandler, &error);
+ lm_connection_send_with_reply (lconnection, request, lhandler, &error);
- if (error) {
- // XXX destroy handler and return NULL?
- scr_log_print (LPRINT_DEBUG, "disco: Error sending disco request: %s.", error -> message);
- g_error_free (error);
- }
-
- lm_message_handler_unref (lhandler);
+ if (error) {
+ scr_log_print (LPRINT_DEBUG, "disco: Error sending disco request: %s.", error -> message);
+ g_error_free (error);
+ handler ( NULL, userdata );
+ disco_request_free ( cb );
+ cb = NULL;
}
+ lm_message_handler_unref (lhandler);
lm_message_unref (request);
- return lhandler;
+ return cb;
}
}
-void disco_cancel_request (gpointer id)
+void disco_cancel_request ( gpointer id )
{
- GSList *hel;
-
- for (hel = reply_handlers; hel; hel = hel -> next) {
- if (hel -> data == id) {
- LmMessageHandler *handler = id;
- reply_handlers = g_slist_remove (reply_handlers, handler);
- lm_message_handler_invalidate (handler);
-#ifdef HAVE_LM_CONNECTION_UNREGISTER_REPLY_HANDLER
- if (lconnection)
- lm_connection_unregister_reply_handler (lconnection, handler);
-#endif
- return;
- }
+ if ( g_slist_find ( disco_requests, id ) ) {
+ disco_request_t * cb = id;
+ disco_request_free ( cb );
}
return;
@@ -620,28 +584,27 @@
// module mechanics
//
-static void disco_unregister_handlers (void)
+static void disco_cancel_requests (void)
{
- GSList *hel;
+ GSList * rel = disco_requests;
- for (hel = reply_handlers; hel; hel = hel -> next) {
- LmMessageHandler *handler = hel -> data;
- lm_message_handler_invalidate (handler);
-#ifdef HAVE_LM_CONNECTION_UNREGISTER_REPLY_HANDLER
- if (lconnection)
- lm_connection_unregister_reply_handler (lconnection, handler);
-#endif
+ while ( rel ) {
+ disco_request_t * cb = rel -> data;
+ rel = rel -> next;
+ if ( cb -> type == DISCO_INFO_REQUEST )
+ cb -> handler.info ( NULL, NULL, cb -> data );
+ else
+ cb -> handler.items ( NULL, cb -> data );
+ disco_request_free ( cb );
}
- g_slist_free (reply_handlers);
- reply_handlers = NULL;
-
return;
}
static guint disco_hh (const gchar *htype, hk_arg_t *args, gpointer ignore)
{
- disco_unregister_handlers ();
+ disco_cancel_requests ();
+
return HOOK_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
}
@@ -689,7 +652,7 @@
hk_del_handler (HOOK_PRE_DISCONNECT, disco_hid);
// unregister handlers
- disco_unregister_handlers ();
+ disco_cancel_requests ();
return;
}