/* xmpp-disco.c - XMPP Service Discovery support * * Copyright 2008 OpenMoko, Inc. * Authored by Daniel Willmann * * 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 #include #include #include #include #include #include /* FIXME&TODO: Better make this a subclass of discoinfo */ /*enum { LAST_SIGNAL }; static guint xmpp_disco_signals[LAST_SIGNAL] = { 0 }; */ G_DEFINE_TYPE(XmppDisco, xmpp_disco, G_TYPE_OBJECT); #define XMPP_DISCO_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), XMPP_TYPE_DISCO, XmppDiscoPrivate)) typedef struct _XmppDiscoPrivate XmppDiscoPrivate; struct _XmppDiscoPrivate { XmppDiscoinfo *discoinfo; LmConnection *connection; LmMessageHandler *msghandle; }; static void xmpp_disco_finalize(GObject *obj) { GError *error = NULL; XmppDiscoPrivate *priv = XMPP_DISCO_GET_PRIVATE(obj); /* Unregister message handlers */ lm_connection_unregister_message_handler(priv->connection, priv->msghandle, LM_MESSAGE_TYPE_IQ); lm_message_handler_unref(priv->msghandle); priv->msghandle = NULL; lm_connection_unref(priv->connection); ((GObjectClass *) xmpp_disco_parent_class)->finalize(obj); } static void xmpp_disco_class_init(XmppDiscoClass *klass) { GObjectClass *o_class = (GObjectClass *) klass; //o_class->dispose = diversity_xmpp_dispose; o_class->finalize = xmpp_disco_finalize; g_type_class_add_private(klass, sizeof(XmppDiscoPrivate)); } static void xmpp_disco_init(XmppDisco *disco) { XmppDiscoPrivate *priv = XMPP_DISCO_GET_PRIVATE(disco); priv->discoinfo = NULL; priv->msghandle = NULL; priv->connection = NULL; } LmHandlerResult xmpp_disco_handle_msg (LmMessageHandler *handler, LmConnection *connection, LmMessage *message, XmppDisco *disco); XmppDisco *xmpp_disco_new(LmConnection *connection, GError **error) { XmppDisco * disco; XmppDiscoPrivate *priv; disco = g_object_new(XMPP_TYPE_DISCO, NULL); priv = XMPP_DISCO_GET_PRIVATE(disco); priv->discoinfo = xmpp_discoinfo_new(NULL); // TODO: Make this configurable from the outside xmpp_discoinfo_add_identity(priv->discoinfo, "client", "pc", NULL); // XEP-0030 says we MUST at least support disco#info xmpp_discoinfo_add_feature(priv->discoinfo, XMPP_NS_DISCO_INFO); priv->connection = connection; lm_connection_ref(priv->connection); /* Add message handler for incoming location events */ priv->msghandle = lm_message_handler_new(xmpp_disco_handle_msg, disco, NULL); lm_connection_register_message_handler(priv->connection, priv->msghandle, LM_MESSAGE_TYPE_IQ, LM_HANDLER_PRIORITY_NORMAL); return disco; } LmHandlerResult xmpp_disco_handle_msg (LmMessageHandler *handler, LmConnection *connection, LmMessage *message, XmppDisco *disco) { XmppDiscoPrivate *priv = XMPP_DISCO_GET_PRIVATE(disco); LmMessage *msg; LmMessageNode *temp; GList *discoinfolist; const gchar *from, *id; LmMessageNode *node = lm_message_get_node(message); from = lm_message_node_get_attribute(node, "from"); id = lm_message_node_get_attribute(node, "id"); if (strcmp(lm_message_node_get_attribute(node, "type"), "get") != 0) return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS; if (!(node = lm_message_node_get_child(node, "query"))) return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS; if (!strcmp(lm_message_node_get_attribute(node, "xmlns"), XMPP_NS_DISCO_INFO)) { msg = lm_message_new_with_sub_type(from, LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_RESULT); node = lm_message_get_node(msg); /* This is a direct answer, so include the given ID */ if (id) { lm_message_node_set_attribute(node, "id", id); } temp = lm_message_node_add_child(node, "query", NULL); lm_message_node_set_attribute(temp, "xmlns", XMPP_NS_DISCO_INFO); /* Add identities */ discoinfolist = xmpp_discoinfo_get_identities(priv->discoinfo); g_list_foreach(discoinfolist, xmpp_discoinfo_ident_to_node, temp); /* Add features */ discoinfolist = xmpp_discoinfo_get_features(priv->discoinfo); g_list_foreach(discoinfolist, xmpp_discoinfo_feat_to_node, temp); lm_connection_send(connection, msg, NULL); lm_message_unref(msg); return LM_HANDLER_RESULT_REMOVE_MESSAGE; } return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS; } void xmpp_disco_add_identity(XmppDisco *disco, const gchar *category, const gchar *type, const gchar *name) { XmppDiscoPrivate *priv = XMPP_DISCO_GET_PRIVATE(disco); xmpp_discoinfo_add_identity(priv->discoinfo, category, type, name); } void xmpp_disco_add_feature(XmppDisco *disco, const gchar *var) { XmppDiscoPrivate *priv = XMPP_DISCO_GET_PRIVATE(disco); xmpp_discoinfo_add_feature(priv->discoinfo, var); } XmppDiscoinfo *xmpp_disco_get_discoinfo(XmppDisco *disco) { XmppDiscoPrivate *priv = XMPP_DISCO_GET_PRIVATE(disco); return priv->discoinfo; }