# HG changeset patch # User Nicolas Cornu # Date 1275385885 -7200 # Node ID eb167636e5bcb028f41a25b89624d770178883d4 # Parent 5ec956706f0c7ac045e51e0d84463fea09317a6c Use GError to pass errors, rename parse.c in check.c diff -r 5ec956706f0c -r eb167636e5bc CMakeLists.txt --- a/CMakeLists.txt Tue Jun 01 09:24:02 2010 +0200 +++ b/CMakeLists.txt Tue Jun 01 11:51:25 2010 +0200 @@ -35,7 +35,7 @@ ${MCABBER_LIBRARY_DIRS}) ## Target definitions -add_library(jingle MODULE jingle.c parse.c jingle_register.c error.c) +add_library(jingle MODULE jingle.c check.c register.c) ## Compiler setup configure_file(config.h.in config.h) diff -r 5ec956706f0c -r eb167636e5bc check.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/check.c Tue Jun 01 11:51:25 2010 +0200 @@ -0,0 +1,90 @@ +/* + * check.c + * + * Copyrigth (C) 2010 Nicolas Cornu + * + * 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 "check.h" +#include "jingle.h" + + +const gchar *jingle_content_creator[] = { + "initiator", + "responder", + NULL +}; + +const gchar *jingle_content_senders[] = { + "both", + "initiator", + "none", + "responder", + NULL +}; + + +/** + * Populate a jingle_data struct from a element. + * Check if the element is in compliance with the XEP. + */ +gboolean check_jingle(LmMessageNode *node, JingleData *jd, GError **err) +{ + gint nb_reason = 0; + LmMessageNode *child = NULL; + const gchar *actionstr; + + actionstr = lm_message_node_get_attribute(node, "action"); + jd->initiator = lm_message_node_get_attribute(node, "initiator"); + jd->responder = lm_message_node_get_attribute(node, "responder"); + jd->sid = lm_message_node_get_attribute(node, "sid"); + + if (actionstr == NULL || jd->sid == NULL) { + g_set_error(err, JINGLE_CHECK_ERROR, JINGLE_CHECK_ERROR_MISSING, + "an attribute of the jingle element is missing"); + return FALSE; + } + + jd->action = jingle_action_from_str(actionstr); + if (jd->action == JINGLE_UNKNOWN_ACTION) { + g_set_error(err, JINGLE_CHECK_ERROR, JINGLE_CHECK_ERROR_BADVALUE, + "the action attribute is invalid"); + return FALSE; + } + + // check childs + for (child = node->children; child; child = child->next) { + if (!g_strcmp0(child->name, "reason")) + nb_reason++; + } + + if (nb_reason > 1) { + g_set_error(err, JINGLE_CHECK_ERROR, JINGLE_CHECK_ERROR_BADELEM, + "too many reason elements"); + return FALSE; + } + + return TRUE; +} + +GQuark jingle_check_error_quark() +{ + return g_quark_from_string("JINGLE_CHECK_ERROR"); +} diff -r 5ec956706f0c -r eb167636e5bc check.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/check.h Tue Jun 01 11:51:25 2010 +0200 @@ -0,0 +1,36 @@ +#ifndef __PARSE_H__ +#define __PARSE_H__ 1 + +#include +#include + +#include "jingle.h" + +#define JINGLE_CHECK_ERROR jingle_check_error_quark() + + +typedef enum { + JINGLE_CHECK_ERROR_MISSING, // an element or attribute is missing + JINGLE_CHECK_ERROR_BADELEM, // an element is not where it is supposed to be + JINGLE_CHECK_ERROR_BADVALUE // the value of an attribute is incorrect +} JingleCheckError; + +typedef struct { + JingleAction action; + const gchar* initiator; // optional + const gchar* responder; // optional + const gchar* sid; // required +} JingleData; + +typedef struct { + const gchar* creator; // required (initiator, responder) + const gchar* disposition; // optional, default=session + const gchar* name; // required + const gchar* senders; // optional (both, initiator, none, responder) +} ContentData; + + +int check_jingle(LmMessageNode* node, JingleData *jd, GError **err); +GQuark jingle_check_error_quark(); + +#endif diff -r 5ec956706f0c -r eb167636e5bc error.c --- a/error.c Tue Jun 01 09:24:02 2010 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +0,0 @@ -/** - * Reply to a Jingle IQ with an error. - */ -void jingle_error_iq(LmMessage *m, const gchar *errtype, - const gchar *cond, const gchar *jinglecond) -{ - LmMessage *r; - LmMessageNode *err, *tmpnode; - - r = lm_message_new_iq_from_query(m, LM_MESSAGE_SUB_TYPE_ERROR); - err = lm_message_node_add_child(r->node, "error", NULL); - lm_message_node_set_attribute(err, "type", errtype); - - // error condition as defined by RFC 3920bis section 8.3.3 - tmpnode = lm_message_node_add_child(err, cond, NULL); - lm_message_node_set_attribute(tmpnode, "xmlns", NS_XMPP_STANZAS); - - // jingle error condition as defined by XEP-0166 section 10 - tmpnode = lm_message_node_add_child(err, jinglecond, NULL); - lm_message_node_set_attribute(tmpnode, "xmlns", NS_JINGLE_ERRORS); - - lm_connection_send(lconnection, r, NULL); - lm_message_unref(r); -} - -/** - * Send a bad-request error (really usefull) - */ -void jingle_error_bad_request(LmMessage *m) -{ - LmMessage *r; - LmMessageNode *err, *tmpnode; - - r = lm_message_new_iq_from_query(m, LM_MESSAGE_SUB_TYPE_ERROR); - err = lm_message_node_add_child(r->node, "error", NULL); - lm_message_node_set_attribute(err, "type", "cancel"); - - // error condition as defined by RFC 3920bis section 8.3.3 - tmpnode = lm_message_node_add_child(err, "bad-request", NULL); - lm_message_node_set_attribute(tmpnode, "xmlns", NS_XMPP_STANZAS); - - lm_connection_send(lconnection, r, NULL); - lm_message_unref(r); -} diff -r 5ec956706f0c -r eb167636e5bc error.h --- a/error.h Tue Jun 01 09:24:02 2010 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -#ifndef __ERROR_H__ -#define __ERROR_H__ - -void jingle_error_iq(LmMessage *m, const gchar *errtype, - const gchar *cond, const gchar *jinglecond); - -void jingle_error_bad_request(LmMessage *m); - -#endif diff -r 5ec956706f0c -r eb167636e5bc jingle.c --- a/jingle.c Tue Jun 01 09:24:02 2010 +0200 +++ b/jingle.c Tue Jun 01 11:51:25 2010 +0200 @@ -1,7 +1,7 @@ /* - * jingle.c -- Base jingle functions + * jingle.c * - * Copyrigth (C) 2010 Nicolas Cornu + * Copyrigth (C) 2010 Nicolas Cornu * * 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 @@ -21,7 +21,6 @@ #include #include -#include #include #include @@ -31,9 +30,9 @@ #include #include "jingle.h" -#include "jingle_register.h" -#include "parse.h" -#include "error.h" +#include "check.h" +#include "register.h" + static void jingle_register_lm_handlers(void); static void jingle_unregister_lm_handlers(void); @@ -47,6 +46,28 @@ static guint connect_hid = 0; static guint disconn_hid = 0; +/** + * Must be aligned with the values in JingleAction + * for easy acces. + */ +struct JingleActionList jingle_action_list[] = { + { NULL, NULL }, // for JINGLE_UNKNOWN_ACTION + { "content-accept", NULL }, + { "content-add", NULL }, + { "content-modify", NULL }, + { "content-reject", NULL }, + { "content-remove", NULL }, + { "description-info", NULL }, + { "security-info", NULL }, + { "session-accept", NULL }, + { "session-info", NULL }, + { "session-initiate", NULL }, + { "session-terminate", NULL }, + { "transport-accept", NULL }, + { "transport-info", NULL }, + { "transport-reject", NULL }, + { "transport-replace", NULL }, +}; module_info_t info_jingle = { .branch = MCABBER_BRANCH, @@ -70,7 +91,8 @@ if (iqtype != LM_MESSAGE_SUB_TYPE_SET) return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS; - struct jingle_data ij; + JingleData jd; + GError *error; LmMessageNode *root = lm_message_get_node(message)->children; LmMessageNode *node = lm_message_node_get_child(root, "jingle"); @@ -82,14 +104,21 @@ return LM_HANDLER_RESULT_REMOVE_MESSAGE; } - if (parse_jingle(node, &ij) != PARSE_OK) { - jingle_error_bad_request(message); + check_jingle(node, &jd, &error); + if (error != NULL) { + if (error->code == JINGLE_CHECK_ERROR) { + // request malformed, we reply with a bad-request + jingle_error_iq(message, "cancel", "bad-request", NULL); + } return LM_HANDLER_RESULT_REMOVE_MESSAGE; } - - scr_log_print(LPRINT_DEBUG, "jingle: Received a jingle IQ"); - - jingle_error_iq(message, "cancel", "feature-not-implemented", "unsupported-info"); + + scr_log_print(LPRINT_DEBUG, "jingle: Received a valid jingle IQ"); + + if (jingle_action_list[jd.action].handler != NULL) + jingle_action_list[jd.action].handler(NULL); + else + jingle_error_iq(message, "cancel", "feature-not-implemented", "unsupported-info"); return LM_HANDLER_RESULT_REMOVE_MESSAGE; } @@ -110,6 +139,48 @@ lm_message_unref(r); } +/** + * Reply to a Jingle IQ with an error. + */ +void jingle_error_iq(LmMessage *m, const gchar *errtype, + const gchar *cond, const gchar *jinglecond) +{ + LmMessage *r; + LmMessageNode *err, *tmpnode; + + r = lm_message_new_iq_from_query(m, LM_MESSAGE_SUB_TYPE_ERROR); + err = lm_message_node_add_child(r->node, "error", NULL); + lm_message_node_set_attribute(err, "type", errtype); + + // error condition as defined by RFC 3920bis section 8.3.3 + if (cond != NULL) { + tmpnode = lm_message_node_add_child(err, cond, NULL); + lm_message_node_set_attribute(tmpnode, "xmlns", NS_XMPP_STANZAS); + } + + // jingle error condition as defined by XEP-0166 section 10 + if (jinglecond != NULL) { + tmpnode = lm_message_node_add_child(err, jinglecond, NULL); + lm_message_node_set_attribute(tmpnode, "xmlns", NS_JINGLE_ERRORS); + } + + lm_connection_send(lconnection, r, NULL); + lm_message_unref(r); +} + +/** + * Find the jingle_action corresponding to a string + */ +JingleAction jingle_action_from_str(const gchar* string) +{ + guint i, actstrlen = sizeof(jingle_action_list)/sizeof(struct JingleActionList); + for (i = 0; i < actstrlen; i++) + if (!g_strcmp0(jingle_action_list[i].name, string)) + return (JingleAction) i; + + return JINGLE_UNKNOWN_ACTION; +} + static void jingle_unregister_lm_handlers(void) { if (lconnection) { diff -r 5ec956706f0c -r eb167636e5bc jingle.h --- a/jingle.h Tue Jun 01 09:24:02 2010 +0200 +++ b/jingle.h Tue Jun 01 11:51:25 2010 +0200 @@ -1,13 +1,15 @@ #ifndef __JINGLE_H__ #define __JINGLE_H__ 1 +#include +#include + #define NS_JINGLE "urn:xmpp:jingle:1" #define NS_JINGLE_ERRORS "urn:xmpp:jingle:errors:1" -void jingle_ack_iq(LmMessage *m); typedef enum { - JINGLE_UNKNOWN, + JINGLE_UNKNOWN_ACTION, JINGLE_CONTENT_ACCEPT, JINGLE_CONTENT_ADD, JINGLE_CONTENT_MODIFY, @@ -25,4 +27,14 @@ JINGLE_TRANSPORT_REPLACE, } JingleAction; +struct JingleActionList { + const gchar *name; + void (*handler)(void *arg1); +}; + +void jingle_error_iq(LmMessage *m, const gchar *errtype, + const gchar *cond, const gchar *jinglecond); +void jingle_ack_iq(LmMessage *m); +JingleAction jingle_action_from_str(const gchar* string); + #endif diff -r 5ec956706f0c -r eb167636e5bc jingle_register.c --- a/jingle_register.c Tue Jun 01 09:24:02 2010 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -#include -#include - -GHashTable *hk_jingle_apps_handler_hash = NULL; -GHashTable *hk_jingle_transports_handler_hash = NULL; - -gchar* jingle_register_apps(const gchar* namespace) -{ - gchar* hookname = NULL; - - // On l'enregistre dans la table - // Si la table n'est pas encore créé c'est le moment - if (!hk_jingle_apps_handler_hash) { - hk_jingle_apps_handler_hash = g_hash_table_new_full(&g_str_hash, &g_str_equal, &g_free, &g_free); - if (!hk_jingle_apps_hander_hash) { - scr_log_print(LPRINT_LOGNORM, "Couldn't create hook hash table for jingle apps!"); - return NULL; - } - } - - hookname = g_strdup_printf("%s%s", "hook_jingle_apps_", namespace); - - // On insert la donnée - g_hash_table_insert(hk_jingle_apps_handler_hash, g_strdup(namespace), hook_name); - - return hookname; -} - -gchar* jingle_register_transports(const gchar* namespace) { - gchar* hookname = NULL; - - // On l'enregistre dans la table - // Si la table n'est pas encore créé c'est le moment - if (!hk_jingle_transports_handler_hash) { - hk_jingle_transports_handler_hash = g_hash_table_new_full(&g_str_hash, &g_str_equal, &g_free, &g_free); - if (!hk_jingle_transports_handler_hash) { - scr_log_print(LPRINT_LOGNORM, "Couldn't create hook hash table for jingle transports!"); - return NULL; - } - } - - hookname = g_strdup_printf("%s%s", "hook_jingle_transports_", namespace); - - // On insert la donnée - g_hash_table_insert(hk_jingle_transporst_handler_hash, g_strdup(namespace), hook_name); - - return hookname; -} diff -r 5ec956706f0c -r eb167636e5bc jingle_register.h --- a/jingle_register.h Tue Jun 01 09:24:02 2010 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -#ifndef __JINGLE_REGISTER_H__ -#define __JINGLE_REGISTER_H__ - -gchar* jingle_resigter_apps(const gchar* namespace); - -gchar* jingle_register_transports(const gchar* namespace); - - - - -#endif diff -r 5ec956706f0c -r eb167636e5bc parse.c --- a/parse.c Tue Jun 01 09:24:02 2010 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,117 +0,0 @@ -#include -#include - -#include "parse.h" -#include "jingle.h" - - -static JingleAction action_from_str(const gchar* string); - - -struct JingleActionStr { - JingleAction act; - const gchar *name; -} jingle_actions_str[] = { - { JINGLE_CONTENT_ACCEPT, "content-accept" }, - { JINGLE_CONTENT_ADD, "content-add" }, - { JINGLE_CONTENT_MODIFY, "content-modify" }, - { JINGLE_CONTENT_REJECT, "content-reject" }, - { JINGLE_CONTENT_REMOVE, "content-remove" }, - { JINGLE_DESCRIPTION_INFO, "description-info" }, - { JINGLE_SECURITY_INFO, "security-info" }, - { JINGLE_SESSION_ACCEPT, "session-accept" }, - { JINGLE_SESSION_INFO, "session-info" }, - { JINGLE_SESSION_INITIATE, "session-initiate" }, - { JINGLE_SESSION_TERMINATE, "session-terminate" }, - { JINGLE_TRANSPORT_ACCEPT, "transport-accept" }, - { JINGLE_TRANSPORT_INFO, "transport-info" }, - { JINGLE_TRANSPORT_REJECT, "transport-reject" }, - { JINGLE_TRANSPORT_REPLACE, "transport-replace" }, -}; - -const gchar *jingle_content_creator[] = { - "initiator", - "responder", - NULL -}; - -const gchar *jingle_content_senders[] = { - "both", - "initiator", - "none", - "responder", - NULL -}; - - -/** - * Populate a jingle_data struct from a element. - * Check if the element is in compliance with the XEP. - */ -gint check_jingle(LmMessageNode *node, struct jingle_data *ij) -{ - int nb_reason = 0; - LmMessageNode *child = NULL; - gchar *actionstr; - - actionstr = lm_message_node_get_attribute(node, "action"); - ij->initiator = lm_message_node_get_attribute(node, "initiator"); - ij->responder = lm_message_node_get_attribute(node, "responder"); - ij->sid = lm_message_node_get_attribute(node, "sid"); - - if (action == NULL || ij->sid == NULL) - return PARSE_ERROR_REQUIRED; // those elements are required - - ij->action = action_from_str(actionstr); - if (ij->action == JINGLE_UNKNOWN) - return PARSE_ERROR_RESTRICTION; - - // check childs - for (child = node->children; child; child = child->next) { - if (!strcmp(child->name, "reason")) - nb_reason++; - } - - if (nb_reason > 1) - return PARSE_ERROR_TOO_MANY_CHILDS; - - return PARSE_OK; -} - -gint check_content(LmMessageNode* node, struct content_data* ic) -{ - if (!strcmp(ic->name, "content")) - return PARSE_ERROR_NAME; - - ic->creator = lm_message_node_get_attribute(node, "creator"); - ic->disposition = lm_message_node_get_attribute(node, "disposition"); - ic->name = lm_message_node_get_attribute(node, "name"); - ic->senders = lm_message_node_get_attribute(node, "senders"); - - if (ic->disposition == NULL) - ic->disposition = "session"; - - if (ic->creator == NULL || ic->name == NULL) - return PARSE_ERROR_REQUIRED; - - if (!str_in_array(ic->creator, jingle_content_creator)) - return PARSE_ERROR_RESTRICTION; - if (!str_in_array(ic->senders, jingle_content_senders)) - ic->senders = NULL; - - return PARSE_OK; -} - - -/** - * Find the jingle_action corresponding to a string - */ -static JingleAction action_from_str(const gchar* string) -{ - guint i, actstrlen = sizeof(jingle_actions_str)/sizeof(struct JingleActionStr); - for (i = 0; i < actstrlen; i++) - if (!g_strcmp0(jingle_actions_str[i].name, string)) - return jingle_actions_str[i].act; - - return JINGLE_UNKNOWN; -} diff -r 5ec956706f0c -r eb167636e5bc parse.h --- a/parse.h Tue Jun 01 09:24:02 2010 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +0,0 @@ -#ifndef __PARSE_H__ -#define __PARSE_H__ 1 - -#include -#include - -#define PARSE_OK 0 -#define PARSE_ERROR_NAME 1 -#define PARSE_ERROR_REQUIRED 2 -#define PARSE_ERROR_RESTRICTION 3 -#define PARSE_ERROR_TOO_MANY_CHILDS 4 - - -struct jingle_data { - JingleAction action; - const gchar* initiator; // optional - const gchar* responder; // optional - const gchar* sid; // required -}; - -struct content_data { - const gchar* creator; // required (initiator, responder) - const gchar* disposition; // optional, default=session - const gchar* name; // required - const gchar* senders; // optional (both, initiator, none, responder) -}; - - -int parse_jingle(LmMessageNode* node, struct jingle_data* ij); -int parse_content(LmMessageNode* node, struct content_data* ic); - -gint str_in_array(const gchar* needle, const gchar** haystack); - -#endif diff -r 5ec956706f0c -r eb167636e5bc register.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/register.c Tue Jun 01 11:51:25 2010 +0200 @@ -0,0 +1,66 @@ +/* + * register.c + * + * Copyrigth (C) 2010 Nicolas Cornu + * + * 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 "jingle.h" + +GHashTable *hk_jingle_apps_handler_hash = NULL; +GHashTable *hk_jingle_transports_handler_hash = NULL; + +gchar* jingle_register_apps(const gchar* namespace) +{ + gchar* hookname = NULL; + + if (!hk_jingle_apps_handler_hash) { + hk_jingle_apps_handler_hash = g_hash_table_new_full(&g_str_hash, &g_str_equal, &g_free, &g_free); + if (!hk_jingle_apps_handler_hash) { + scr_log_print(LPRINT_LOGNORM, "Couldn't create hook hash table for jingle apps!"); + return NULL; + } + } + + hookname = g_strdup_printf("%s%s", "hook_jingle_apps_", namespace); + + g_hash_table_insert(hk_jingle_apps_handler_hash, g_strdup(namespace), hookname); + + return hookname; +} + +gchar* jingle_register_transports(const gchar* namespace) { + gchar* hookname = NULL; + + if (!hk_jingle_transports_handler_hash) { + hk_jingle_transports_handler_hash = g_hash_table_new_full(&g_str_hash, &g_str_equal, &g_free, &g_free); + if (!hk_jingle_transports_handler_hash) { + scr_log_print(LPRINT_LOGNORM, "Couldn't create hook hash table for jingle transports!"); + return NULL; + } + } + + hookname = g_strdup_printf("%s%s", "hook_jingle_transports_", namespace); + + g_hash_table_insert(hk_jingle_transports_handler_hash, g_strdup(namespace), hookname); + + return hookname; +} diff -r 5ec956706f0c -r eb167636e5bc register.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/register.h Tue Jun 01 11:51:25 2010 +0200 @@ -0,0 +1,7 @@ +#ifndef __JINGLE_REGISTER_H__ +#define __JINGLE_REGISTER_H__ + +gchar* jingle_resigter_apps(const gchar* namespace); +gchar* jingle_register_transports(const gchar* namespace); + +#endif diff -r 5ec956706f0c -r eb167636e5bc sessions.c --- a/sessions.c Tue Jun 01 09:24:02 2010 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -// Session for manipulate sessions -struct session_info { - gchar* initiator; - - gchar* transport_namespace; -}