Author: ArcRiley Date: 2009-01-08 15:16:43 -0500 (Thu, 08 Jan 2009) New Revision: 1445
Modified: trunk/concordance/src/Core.c Log: * now recompiles <iq/> <message/> & <presence/> tags for routing or callback * fixed switch statements (forgot to break; at the end of each case) Modified: trunk/concordance/src/Core.c =================================================================== --- trunk/concordance/src/Core.c 2009-01-08 20:14:53 UTC (rev 1444) +++ trunk/concordance/src/Core.c 2009-01-08 20:16:43 UTC (rev 1445) @@ -256,30 +256,42 @@ ret = getaddrinfo(sock->addr, NULL, NULL, &resinfo); if (ret != 0) { switch (ret) { - case EAI_AGAIN : + case EAI_AGAIN : { /* EAI_AGAIN The name server returned a temporary failure indication. Try again later. */ PyErr_SetString(PyExc_OSError, "temporary dns failure"); - case EAI_FAIL : + break; + } + case EAI_FAIL : { /* EAI_FAIL The name server returned a permanent failure indication. */ PyErr_SetString(PyExc_OSError, "permanent dns failure"); - case EAI_FAMILY : + break; + } + case EAI_FAMILY : { /* EAI_FAMILY The requested address family is not supported. */ PyErr_SetString(PyExc_OSError, "address family not supported"); - case EAI_MEMORY : + break; + } + case EAI_MEMORY : { /* EAI_MEMORY Out of memory. */ PyErr_SetString(PyExc_MemoryError, "out of memory on getaddrinfo"); - case EAI_NODATA : + break; + } + case EAI_NODATA : { /* EAI_NODATA The specified network host exists, but does not have any network addresses defined. */ PyErr_SetString(PyExc_AttributeError, "host lacks IP address"); - default : + break; + } + default : { PyErr_SetString(PyExc_AttributeError, "invalid address/hostname"); + break; + } } return FALSE; } @@ -463,12 +475,14 @@ g_io_channel_set_buffered(newSession->chan, FALSE); - /* initialize session write and element buffers + /* initialize session strings GString* g_string_new (const gchar *init); */ - newSession->wbuff = g_string_new(""); - newSession->ebuff = g_string_new(""); + newSession->wbuff = g_string_new(""); /* write buffer */ + newSession->ebuff = g_string_new(""); /* element buffer */ + newSession->efrom = g_string_new(""); /* element origin */ + newSession->eto = g_string_new(""); /* element destination */ /* initialize session state */ newSession->state = CON_E_OPEN; @@ -624,34 +638,8 @@ # Element responses # */ static void - conCore_saslFailure(conSession* session, gchar* failure) { /*\ + conCore_reply_stream(conSession* session) { /*\ cdef : \*/ - GString* buff; - /* printf failure to a GString, then send it - - GString* g_string_new (const gchar *init); - void g_string_printf (GString *string, - const gchar *format, - ...); - gchar* g_string_free (GString *string, - gboolean free_segment); - */ - buff = g_string_new(""); - g_string_printf(buff, "<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>" - "%s</failure>", failure); - conCore_sessionSend(session, buff->str, buff->len); - g_string_free(buff, TRUE); - } - - /* - # - ########################################################################### - # - # Element handlers - # */ - static void - conCore_stream(conSession* session) { /*\ - cdef : \*/ conCoreObject* self = session->core; GString* buff; @@ -667,13 +655,13 @@ const gchar *format, ...); */ - g_string_printf(buff, "<?xml version='1.0' encoding='UTF-8'?>" - "<stream:stream xmlns='jabber:client'" - " xmlns:stream='http://etherx.jabber.org/streams'" - " from='%s' id='%s'>" - "<stream:features><mechanisms" - " xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>", - "selket.apogean.org", "concordance-1"); + g_string_printf(buff, + "<?xml version='1.0' encoding='UTF-8'?>" + "<stream:stream xmlns='jabber:client'" + " xmlns:stream='http://etherx.jabber.org/streams'" + " from='%s' id='%s'><stream:features><mechanisms" + " xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>", + "selket.apogean.org", "concordance-1"); /* add a <mechanism> element for each supported SASL mechanism @@ -701,27 +689,98 @@ static void - conCore_saslChallenge(conSession* session) { /*\ + conCore_reply_streamError(conSession* session, gchar* err, gchar* txt) {/*\ cdef : \*/ + GString* buff; + + /* initialize response buffer + + GString* g_string_new (const gchar *init); + */ + buff = g_string_new(""); + + /* printf error and send it + + void g_string_printf (GString *string, + const gchar *format, + ...); + */ + g_string_printf(buff, + "<stream:error><%s" + " xmlns='urn:ietf:params:xml:ns:xmpp-streams'/>" + "<text xmlns='urn:ietf:params:xml:ns:xmpp-streams'>" + "%s</text></stream:error></stream:stream>", + err, txt); + conCore_sessionSend(session, buff->str, buff->len); + + /* CLOSE the session state so the socket will close properly */ + session->state = CON_E_CLOSE; + + /* free response buffer before returning + + gchar* g_string_free (GString *string, + gboolean free_segment); + */ + g_string_free(buff, TRUE); + } + + + static void + conCore_reply_saslChallenge(conSession* session) { /*\ + cdef : \*/ conCoreObject* self = session->core; - - return; /* unfinished */ - /* gchar* g_base64_encode (const guchar *data, + + return; + /* + gchar* g_base64_encode (const guchar *data, gsize len); */ + /*g_string_printf(buff, "<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>" "%s</challenge>", ""); */ } + static void + conCore_reply_saslFailure(conSession* session, gchar* failure) { /*\ + cdef : \*/ + GString* buff; + /* printf failure to a GString, then send it + GString* g_string_new (const gchar *init); + void g_string_printf (GString *string, + const gchar *format, + ...); + gchar* g_string_free (GString *string, + gboolean free_segment); + */ + buff = g_string_new(""); + g_string_printf(buff, "<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>" + "%s</failure>", failure); + conCore_sessionSend(session, buff->str, buff->len); + g_string_free(buff, TRUE); + } + /* # ########################################################################### # + # Python Handles + # */ + static void + conCore_handle_client(conSession* session) { /*\ + cdef : \*/ + GString* buff; + printf("------ client callback: \"%s\"\n", session->ebuff->str); + } + + /* + # + ########################################################################### + # # XML Callbacks # */ static void @@ -751,22 +810,73 @@ printf(">\n"); switch (session->depth) { - case 0 : + /* match element by depth, namespace, and finally element name + + gint g_ascii_strcasecmp (const gchar* str1, + const gchar* str2); + Returns -1, 0 or 1, if str1 is <, == or > than str2. + */ + case 0 : { /* only stream:stream element is valid at depth == 0 if anything else is sent, session->state will be changed from CON_E_OPEN to CON_E_CLOSE and the session will be cleanly closed in the conCore_sessionRead just after the XMLParse call (above). */ - if (strcmp(name, "http://etherx.jabber.org/streams stream") == 0) + if (g_ascii_strcasecmp(name, + "http://etherx.jabber.org/streams stream") == 0) /* need to test version and other important attributes */ - conCore_stream(session); + conCore_reply_stream(session); else session->state = CON_E_CLOSE; + break; + } case 1 : { - if (strcmp(element[0], "urn:ietf:params:xml:ns:xmpp-sasl") == 0) { - if (strcmp(element[1], "auth") == 0) { + if (g_ascii_strcasecmp(element[0], "jabber:client") == 0) { + /* ensure it's a valid element for the jabber:client namespace + + see http://xmpp.org/rfcs/rfc3920.html#def + */ + if (g_ascii_strcasecmp(element[1], "iq") == 0 || + g_ascii_strcasecmp(element[1], "message") == 0 || + g_ascii_strcasecmp(element[1], "presence") == 0) { + /* set the client mode */ + session->state = CON_E_CLIENT; + + /* copy "from" and "to" attributes, will verify in conCore_xmlEnd + + GString* g_string_assign (GString *string, + const gchar *rval); + */ + session->eto = g_string_assign(session->eto, + conSearchAttributes(atts, "to")); + session->efrom = g_string_assign(session->efrom, + conSearchAttributes(atts, "from")); + + + /* copy element and attributes to ebuff + + void g_string_printf (GString *string, + const gchar *format, + ...); + void g_string_append_printf (GString *string, + const gchar *format, + ...); + */ + g_string_printf(session->ebuff, "<%s", element[1]); + for (i = 0; atts[i]; i += 2) + g_string_append_printf(session->ebuff, " %s='%s'", + atts[i], atts[i+1]); + g_string_append_printf(session->ebuff, ">"); + } + else + conCore_reply_streamError(session, "invalid-xml", "invalid element" + "for jabber:client namespace"); + } + if (g_ascii_strcasecmp(element[0], + "urn:ietf:params:xml:ns:xmpp-sasl") == 0) { + if (g_ascii_strcasecmp(element[1], "auth") == 0) { const gchar* mech = conSearchAttributes(atts, "mechanism"); if (gsasl_server_support_p(self->saslCntx, mech)) { /* initiate server session @@ -780,19 +890,35 @@ session->state = CON_E_SASL; } else { - conCore_saslFailure(session, "<invalid-mechanism/>"); + conCore_reply_saslFailure(session, "<invalid-mechanism/>"); session->state = CON_E_CLOSE; } } /* remaining: response, abort */ } - + /* other depth=1 namespaces */ + break; } default : { /* process inner tags depending on state */ + if (session->state == CON_E_CLIENT) { + /* copy element and attributes to ebuff + + void g_string_append_printf (GString *string, + const gchar *format, + ...); + */ + g_string_append_printf(session->ebuff, "<%s xmlns='%s'", + element[1], element[0]); + for (i = 0; atts[i]; i += 2) + g_string_append_printf(session->ebuff, " %s='%s'", + atts[i], atts[i+1]); + g_string_append_printf(session->ebuff, ">"); + } + break; } } @@ -818,6 +944,7 @@ /* decrease XML depth */ session->depth--; + /* split name by namespace and element gchar** g_strsplit (const gchar *string, @@ -826,25 +953,60 @@ */ element = g_strsplit(name, " ", 2); - if (session->depth == 1) { - switch (session->state) { - case CON_E_SASL : - conCore_saslChallenge(session); + for (i = 0; i < session->depth; i++) + printf(" "); + printf("</%s>\n", element[1]); + + switch (session->depth) { + case 0 : { + /* close session when </stream:stream> is sent */ + session->state = CON_E_CLOSE; + break; } + case 1 : { + switch (session->state) { + case CON_E_CLIENT : { + /* copy final element close to ebuff - /* reset the element chardata buffer when returning to stream depth + void g_string_append_printf (GString *string, + const gchar *format, + ...); + */ + g_string_append_printf(session->ebuff, "</%s>", element[1]); + conCore_handle_client(session); + break; + } + case CON_E_SASL : { + conCore_reply_saslChallenge(session); + break; + } + } - GString* g_string_assign (GString *string, + /* reset the element strings when returning to depth 1 + + GString* g_string_assign (GString *string, const gchar *rval); - */ - session->ebuff = g_string_assign(session->ebuff, ""); + */ + session->ebuff = g_string_assign(session->ebuff, ""); + session->efrom = g_string_assign(session->efrom, ""); + session->eto = g_string_assign(session->eto, ""); + + break; + } + default : { + if (session->state == CON_E_CLIENT) { + /* copy element close to ebuff + + void g_string_append_printf (GString *string, + const gchar *format, + ...); + */ + g_string_append_printf(session->ebuff, "</%s>", element[1]); + } + break; + } } - - for (i = 0; i < session->depth; i++) - printf(" "); - printf("</%s>\n", element[1]); - /* free the element string array before returning void g_strfreev (gchar **str_array); @@ -861,24 +1023,24 @@ gint i; gchar* strn; - /* This is used repeatedly in the following code - - GString* g_string_append_len (GString *string, - const gchar *val, - gssize len); - */ - switch (session->state) { - case CON_E_SASL : - /* append Base64 (p)response data to element buffer */ - session->ebuff = g_string_append_len(session->ebuff, str, str_len); - } - + /* output to stdout for debugging */ strn = g_strndup(str, str_len); for (i = 0; i < session->depth; i++) printf(" "); printf("\"%s\"\n", strn); g_free(strn); + if (session->state == CON_E_OPEN) + /* character data should be ignored at the stream level */ + return; + + /* append character data to element buffer + + GString* g_string_append_len (GString *string, + const gchar *val, + gssize len); + */ + session->ebuff = g_string_append_len(session->ebuff, str, str_len); } /* _______________________________________________ PySoy-SVN mailing list PySoy-SVN@pysoy.org http://www.pysoy.org/mailman/listinfo/pysoy-svn