/*
* pep.c -- Common pep routines
*
* Copyright (C) 2009 Myhailo Danylenko <isbear@ukrpost.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
#include <glib.h>
#include <loudmouth/loudmouth.h>
#include <string.h>
#include <mcabber/xmpp.h>
#include <mcabber/hooks.h>
#include <mcabber/modules.h>
#include "pep.h"
#include "config.h"
void pep_init (void);
void pep_uninit (void);
#define DESCRIPTION ( PEP_DESCRIPTION )
module_info_t info_pep = {
.branch = MCABBER_BRANCH,
.api = MCABBER_API_VERSION,
.version = PROJECT_VERSION,
.description = DESCRIPTION,
.requires = NULL,
.init = pep_init,
.uninit = pep_uninit,
.next = NULL,
};
typedef struct pep_handler_struct pep_handler_t;
struct pep_handler_struct {
gchar *xmlns;
gpointer data;
pep_xmlns_handler_t handler;
GDestroyNotify destroy_notify;
};
static GSList *pep_xmlns_handlers = NULL;
static guint pep_hid_connect = 0;
static guint pep_hid_disconnect = 0;
static LmMessageHandler *pep_message_handler = NULL;
static LmMessageHandler *pep_iq_handler = NULL;
static pep_handler_t *pep_find_handler (const gchar *xmlns)
{
GSList *hel;
for (hel = pep_xmlns_handlers; hel; hel = hel->next) {
pep_handler_t *handler = (pep_handler_t *) hel->data;
if (!g_strcmp0 (handler->xmlns, xmlns))
return handler;
}
return NULL;
}
static void pep_handler_free (pep_handler_t *handler)
{
if (handler -> destroy_notify)
handler -> destroy_notify (handler -> data);
g_free (handler -> xmlns);
g_slice_free (pep_handler_t, handler);
return;
}
static LmHandlerResult pep_handler (const gchar *from, LmMessageNode *mnode)
{
LmMessageNode *node = lm_message_node_get_child (mnode, "items");
if (node) {
LmMessageNode *item;
const gchar *inode = lm_message_node_get_attribute (node, "node");
for (item = node->children; item; item = item->next) {
const gchar *id = lm_message_node_get_attribute (item, "id");
LmMessageNode *n;
for (n = item->children; n; n = n->next) {
const gchar *xmlns = lm_message_node_get_attribute (n, "xmlns");
if (xmlns) {
pep_handler_t *handler = pep_find_handler (xmlns);
if (handler)
handler->handler (from, inode, n, id, handler->data);
}
}
}
} // XXX else
return LM_HANDLER_RESULT_REMOVE_MESSAGE;
}
static LmHandlerResult pep_iq_pubsub_handler (LmMessageHandler *handler, LmConnection *connectio, LmMessage *message, gpointer udata)
{
LmMessageNode *node = lm_message_get_node (message);
const gchar *from = lm_message_node_get_attribute (node, "from");
node = lm_message_node_get_child (node, "pubsub");
if (node && !g_strcmp0 (lm_message_node_get_attribute (node, "xmlns"), NS_PUBSUB)) {
return pep_handler (from, node);
}
return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
}
static LmHandlerResult pep_message_event_handler (LmMessageHandler *handler, LmConnection *connectio, LmMessage *message, gpointer udata)
{
LmMessageNode *node = lm_message_get_node (message);
const gchar *from = lm_message_node_get_attribute (node, "from");
node = lm_message_node_get_child (node, "event");
if (node && !g_strcmp0 (lm_message_node_get_attribute (node, "xmlns"), NS_PUBSUB_EVENT)) {
return pep_handler (from, node);
}
return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
}
void pep_register_xmlns_handler (const gchar *xmlns, pep_xmlns_handler_t handler, gpointer udata, GDestroyNotify notify)
{
pep_handler_t *h = g_slice_new (pep_handler_t);
h->xmlns = g_strdup (xmlns);
h->handler = handler;
h->data = udata;
h->destroy_notify = notify;
pep_xmlns_handlers = g_slist_append (pep_xmlns_handlers, h);
return;
}
void pep_unregister_xmlns_handler (const gchar *xmlns)
{
pep_handler_t *handler = pep_find_handler (xmlns);
if (handler) {
pep_handler_free (handler);
pep_xmlns_handlers = g_slist_remove (pep_xmlns_handlers, handler);
}
}
static void pep_register_handlers (void)
{
if (lconnection) { // XXX
lm_connection_register_message_handler (lconnection, pep_message_handler, LM_MESSAGE_TYPE_MESSAGE, LM_HANDLER_PRIORITY_FIRST);
lm_connection_register_message_handler (lconnection, pep_iq_handler, LM_MESSAGE_TYPE_IQ, LM_HANDLER_PRIORITY_FIRST);
}
}
static void pep_unregister_handlers (void)
{
if (lconnection) { // XXX
lm_connection_unregister_message_handler (lconnection, pep_message_handler, LM_MESSAGE_TYPE_MESSAGE);
lm_connection_unregister_message_handler (lconnection, pep_iq_handler, LM_MESSAGE_TYPE_IQ);
}
}
// release handlers before reconnect
static guint pep_hch (const gchar *hid, hk_arg_t *args, gpointer userdata)
{
pep_register_handlers ();
return HOOK_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
}
static guint pep_hdh (const gchar *hid, hk_arg_t *args, gpointer userdata)
{
pep_unregister_handlers ();
return HOOK_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
}
void pep_init (void)
{
// create handlers
pep_message_handler = lm_message_handler_new (pep_message_event_handler, NULL, NULL);
pep_iq_handler = lm_message_handler_new (pep_iq_pubsub_handler, NULL, NULL);
// register hook handler
pep_hid_connect = hk_add_handler (pep_hch, HOOK_POST_CONNECT, G_PRIORITY_DEFAULT, NULL);
pep_hid_disconnect = hk_add_handler (pep_hdh, HOOK_PRE_DISCONNECT, G_PRIORITY_DEFAULT, NULL);
// register handlers to connection
pep_register_handlers ();
}
void pep_uninit (void)
{
// release handlers
pep_unregister_handlers ();
// remove hook
hk_del_handler (HOOK_POST_CONNECT, pep_hid_connect);
hk_del_handler (HOOK_PRE_DISCONNECT, pep_hid_disconnect);
{ // unregister xmlns handlers
GSList *hel;
for (hel = pep_xmlns_handlers; hel; hel = hel -> next) {
pep_handler_t *handler = hel -> data;
pep_handler_free (handler);
}
g_slist_free (pep_xmlns_handlers);
}
// destroy handlers (invalidate it just to be sure, though this should not happen :)
lm_message_handler_invalidate (pep_message_handler);
lm_message_handler_invalidate (pep_iq_handler);
lm_message_handler_unref (pep_message_handler);
lm_message_handler_unref (pep_iq_handler);
}
/* vim: se ts=4 sw=4: */