XMPP: Cleanup
authorWilfried Goesgens <dothebart@citadel.org>
Fri, 1 Nov 2013 19:45:08 +0000 (20:45 +0100)
committerWilfried Goesgens <dothebart@citadel.org>
Fri, 1 Nov 2013 19:45:08 +0000 (20:45 +0100)
  - remove temporary utf8-save body append function
  - properly escape properties
  - use session local buffer

citadel/modules/xmpp/serv_xmpp.c
citadel/modules/xmpp/serv_xmpp.h
citadel/modules/xmpp/xmpp_messages.c
citadel/modules/xmpp/xmpp_presence.c
citadel/modules/xmpp/xmpp_query_namespace.c
citadel/modules/xmpp/xmpp_sasl_service.c

index e696069a171ece7b5cac38dc2cb25abe09335231..cfad3489f7f0ec024834a97b54aea5b9c63a798c 100644 (file)
@@ -21,6 +21,7 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <stdio.h>
+#include <stdarg.h>
 #include <fcntl.h>
 #include <signal.h>
 #include <pwd.h>
@@ -42,6 +43,7 @@
 #include <string.h>
 #include <limits.h>
 #include <ctype.h>
+#define SHOW_ME_VAPPEND_PRINTF
 #include <libcitadel.h>
 #include <expat.h>
 #include "citadel.h"
@@ -68,6 +70,37 @@ HashList *XMPP_EndHandlers = NULL;
 
 int XMPPSrvDebugEnable = 0;
 
+void XUnbuffer(void)
+{
+       citxmpp *Xmpp = XMPP;
+
+       cputbuf(Xmpp->OutBuf);
+       FlushStrBuf(Xmpp->OutBuf);
+}
+
+void XPutBody(const char *Str, long Len)
+{
+       StrBufXMLEscAppend(XMPP->OutBuf, NULL, Str, Len, 0);
+}
+
+void XPutProp(const char *Str, long Len)
+{
+       StrEscAppend(XMPP->OutBuf, NULL, Str, 0, 1);
+}
+
+void XPut(const char *Str, long Len)
+{
+       StrBufAppendBufPlain(XMPP->OutBuf, Str, Len, 0);
+}
+#define XPUT(CONSTSTR) XPut(CONSTSTR, sizeof(CONSTSTR) -1)
+
+void XPrintf(const char *Format, ...)
+{
+        va_list arg_ptr;
+        va_start(arg_ptr, Format);
+       StrBufVAppendPrintf(XMPP->OutBuf, Format, arg_ptr);
+       va_end(arg_ptr);
+}
 
 
 #ifdef HAVE_XML_STOPPARSER
@@ -83,137 +116,40 @@ static void xmpp_entity_declaration(void *userData, const XML_Char *entityName,
 }
 #endif
 
-static inline int XMPP_GetUtf8SequenceLength(const char *CharS, const char *CharE)
-{
-       /* if this is is migrated to strbuf, remove this copy. */
-       int n = 0;
-        unsigned char test = (1<<7);
-
-       if ((*CharS & 0xC0) != 0xC0) 
-               return 1;
-
-       while ((n < 8) && 
-              ((test & ((unsigned char)*CharS)) != 0)) 
-       {
-               test = test >> 1;
-               n ++;
-       }
-       if ((n > 6) || ((CharE - CharS) < n))
-               n = 0;
-       return n;
-}
-
-
-/*
- * Given a source string and a target buffer, returns the string
- * properly escaped for insertion into an XML stream.  Returns a
- * pointer to the target buffer for convenience.
- *
- * BUG: this does not properly handle UTF-8
- */
-char *xmlesc(char *buf, char *str, int bufsiz)
-{
-       char *ptr;
-       char *eiptr;
-       unsigned char ch;
-       int inlen;
-       int len = 0;
-       int IsUtf8Sequence;
-
-       if (!buf) return(NULL);
-       buf[0] = 0;
-       len = 0;
-       if (!str) {
-               return(buf);
-       }
-
-       inlen = strlen(str);
-       eiptr = str + inlen;
-
-       for (ptr=str; *ptr; ptr++) {
-               ch = *ptr;
-               if (ch == '<') {
-                       strcpy(&buf[len], "&lt;");
-                       len += 4;
-               }
-               else if (ch == '>') {
-                       strcpy(&buf[len], "&gt;");
-                       len += 4;
-               }
-               else if (ch == '&') {
-                       strcpy(&buf[len], "&amp;");
-                       len += 5;
-               }
-               else if ((ch >= 0x20) && (ch <= 0x7F)) {
-                       buf[len++] = ch;
-                       buf[len] = 0;
-               }
-               else if (ch < 0x20) {
-                       /* we probably shouldn't be doing this */
-                       buf[len++] = '_';
-                       buf[len] = 0;
-               }
-               else {
-                       char oct[32];
-
-                       IsUtf8Sequence =  XMPP_GetUtf8SequenceLength(&buf[len], eiptr);
-                       if (IsUtf8Sequence)
-                       {
-                               while (IsUtf8Sequence > 0){
-                                       buf[len] = *ptr;
-                                       len ++;
-                                       if (--IsUtf8Sequence)
-                                               ptr++;
-                               }
-                               buf[len] = '\0';
-                       }
-                       else
-                       {
-                               sprintf(oct, "&#%o;", ch);
-                               strcpy(&buf[len], oct);
-                               len += strlen(oct);
-                       }
-               }
-               if ((len + 6) > bufsiz) {
-                       return(buf);
-               }
-       }
-       return(buf);
-}
-
-
 /*
  * We have just received a <stream> tag from the client, so send them ours
  */
 void xmpp_stream_start(void *data, const char *supplied_el, const char **attr)
 {
-       char xmlbuf[256];
+       citxmpp *Xmpp = XMPP;
 
        while (*attr) {
                if (!strcasecmp(attr[0], "to")) {
-                       safestrncpy(XMPP->server_name, attr[1], sizeof XMPP->server_name);
+                       safestrncpy(Xmpp->server_name, attr[1], sizeof Xmpp->server_name);
                }
                attr += 2;
        }
 
-       cprintf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+       XPUT("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
 
-       cprintf("<stream:stream ");
-       cprintf("from=\"%s\" ", xmlesc(xmlbuf, XMPP->server_name, sizeof xmlbuf));
-       cprintf("id=\"%08x\" ", CC->cs_pid);
-       cprintf("version=\"1.0\" ");
-       cprintf("xmlns:stream=\"http://etherx.jabber.org/streams\" ");
-       cprintf("xmlns=\"jabber:client\">");
+       XPUT("<stream:stream ");
+       XPUT("from=\"");
+       XPutProp(Xmpp->server_name, strlen(Xmpp->server_name));
+       XPUT("\" id=\"");
+       XPrintf("%08x\" ", CC->cs_pid);
+       XPUT("version=\"1.0\" "
+                 "xmlns:stream=\"http://etherx.jabber.org/streams\" "
+                 "xmlns=\"jabber:client\">");
 
        /* The features of this stream are... */
-       cprintf("<stream:features>");
+       XPUT("<stream:features>");
 
        /*
         * TLS encryption (but only if it isn't already active)
         */ 
 #ifdef HAVE_OPENSSL
        if (!CC->redirect_ssl) {
-               cprintf("<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'></starttls>");
+               XPUT("<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'></starttls>");
        }
 #endif
 
@@ -222,14 +158,13 @@ void xmpp_stream_start(void *data, const char *supplied_el, const char **attr)
                xmpp_output_auth_mechs();
 
                /* Also offer non-SASL authentication */
-               cprintf("<auth xmlns=\"http://jabber.org/features/iq-auth\"/>");
+               XPUT("<auth xmlns=\"http://jabber.org/features/iq-auth\"/>");
        }
 
        /* Offer binding and sessions as part of our feature set */
-       cprintf("<bind xmlns=\"urn:ietf:params:xml:ns:xmpp-bind\"/>");
-       cprintf("<session xmlns=\"urn:ietf:params:xml:ns:xmpp-session\"/>");
-
-       cprintf("</stream:features>");
+       XPUT("<bind xmlns=\"urn:ietf:params:xml:ns:xmpp-bind\"/>"
+                 "<session xmlns=\"urn:ietf:params:xml:ns:xmpp-session\"/>"
+                 "</stream:features>");
 
        CC->is_async = 1;               /* XMPP sessions are inherently async-capable */
 }
@@ -322,7 +257,7 @@ void xmpp_xml_start(void *data, const char *supplied_el, const char **attr)
                h = (xmpp_handler*) pv;
                h->Handler(data, supplied_el, attr);
        }
-
+       XUnbuffer();
 }
 
 void xmpp_end_resource(void *data, const char *supplied_el, const char **attr)
@@ -355,32 +290,39 @@ void xmpp_end_password(void *data, const char *supplied_el, const char **attr)
 
 void xmpp_end_iq(void *data, const char *supplied_el, const char **attr)
 {
-       char xmlbuf[256];
+       citxmpp *Xmpp = XMPP;
+
        /*
         * iq type="get" (handle queries)
         */
-       if (!strcasecmp(XMPP->iq_type, "get"))
+       if (!strcasecmp(Xmpp->iq_type, "get"))
        {
                /*
                 * Query on a namespace
                 */
-               if (!IsEmptyStr(XMPP->iq_query_xmlns)) {
-                       xmpp_query_namespace(XMPP->iq_id, XMPP->iq_from,
-                                            XMPP->iq_to, XMPP->iq_query_xmlns);
+               if (!IsEmptyStr(Xmpp->iq_query_xmlns)) {
+                       xmpp_query_namespace(Xmpp->iq_id, Xmpp->iq_from,
+                                            Xmpp->iq_to, Xmpp->iq_query_xmlns);
                }
                
                /*
                 * ping ( http://xmpp.org/extensions/xep-0199.html )
                 */
-               else if (XMPP->ping_requested) {
-                       cprintf("<iq type=\"result\" ");
-                       if (!IsEmptyStr(XMPP->iq_from)) {
-                               cprintf("to=\"%s\" ", xmlesc(xmlbuf, XMPP->iq_from, sizeof xmlbuf));
+               else if (Xmpp->ping_requested) {
+                       XPUT("<iq type=\"result\" ");
+                       if (!IsEmptyStr(Xmpp->iq_from)) {
+                               XPUT("to=\"");
+                               XPutProp(Xmpp->iq_from, strlen(Xmpp->iq_from));
+                               XPUT("\" ");
                        }
-                       if (!IsEmptyStr(XMPP->iq_to)) {
-                               cprintf("from=\"%s\" ", xmlesc(xmlbuf, XMPP->iq_to, sizeof xmlbuf));
+                       if (!IsEmptyStr(Xmpp->iq_to)) {
+                               XPUT("from=\"");
+                               XPutProp(Xmpp->iq_to, strlen(Xmpp->iq_to));
+                               XPUT("\" ");
                        }
-                       cprintf("id=\"%s\"/>", xmlesc(xmlbuf, XMPP->iq_id, sizeof xmlbuf));
+                       XPUT("id=\"");
+                       XPutProp(Xmpp->iq_id, strlen(Xmpp->iq_id));
+                       XPUT("\"/>");
                }
 
                /*
@@ -388,17 +330,18 @@ void xmpp_end_iq(void *data, const char *supplied_el, const char **attr)
                 */
                else {
 /*
-                       XMPP_syslog(LOG_DEBUG,
+                       Xmpp_syslog(LOG_DEBUG,
                                    "Unknown query <%s> - returning <service-unavailable/>\n",
                                    el
                                );
 */
-                       cprintf("<iq type=\"error\" id=\"%s\">", xmlesc(xmlbuf, XMPP->iq_id, sizeof xmlbuf));
-                       cprintf("<error code=\"503\" type=\"cancel\">"
-                               "<service-unavailable xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"/>"
-                               "</error>"
-                               );
-                       cprintf("</iq>");
+                       XPUT("<iq type=\"error\" id=\"");
+                       XPutProp(Xmpp->iq_id, strlen(Xmpp->iq_id));
+                       XPUT("\">"
+                            "<error code=\"503\" type=\"cancel\">"
+                            "<service-unavailable xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"/>"
+                            "</error>"
+                            "</iq>");
                }
        }
 
@@ -406,15 +349,15 @@ void xmpp_end_iq(void *data, const char *supplied_el, const char **attr)
         * Non SASL authentication
         */
        else if (
-               (!strcasecmp(XMPP->iq_type, "set"))
-               && (!strcasecmp(XMPP->iq_query_xmlns, "jabber:iq:auth:query"))
+               (!strcasecmp(Xmpp->iq_type, "set"))
+               && (!strcasecmp(Xmpp->iq_query_xmlns, "jabber:iq:auth:query"))
                ) {
                
                xmpp_non_sasl_authenticate(
-                       XMPP->iq_id,
-                       XMPP->iq_client_username,
-                       XMPP->iq_client_password,
-                       XMPP->iq_client_resource
+                       Xmpp->iq_id,
+                       Xmpp->iq_client_username,
+                       Xmpp->iq_client_password,
+                       Xmpp->iq_client_resource
                        );
        }
 
@@ -422,50 +365,60 @@ void xmpp_end_iq(void *data, const char *supplied_el, const char **attr)
         * If this <iq> stanza was a "bind" attempt, process it ...
         */
        else if (
-               (XMPP->bind_requested)
-               && (!IsEmptyStr(XMPP->iq_id))
-               && (!IsEmptyStr(XMPP->iq_client_resource))
+               (Xmpp->bind_requested)
+               && (!IsEmptyStr(Xmpp->iq_id))
+               && (!IsEmptyStr(Xmpp->iq_client_resource))
                && (CC->logged_in)
                ) {
 
                /* Generate the "full JID" of the client resource */
 
-               snprintf(XMPP->client_jid, sizeof XMPP->client_jid,
+               snprintf(Xmpp->client_jid, sizeof Xmpp->client_jid,
                         "%s/%s",
                         CC->cs_inet_email,
-                        XMPP->iq_client_resource
+                        Xmpp->iq_client_resource
                        );
 
                /* Tell the client what its JID is */
 
-               cprintf("<iq type=\"result\" id=\"%s\">", xmlesc(xmlbuf, XMPP->iq_id, sizeof xmlbuf));
-               cprintf("<bind xmlns=\"urn:ietf:params:xml:ns:xmpp-bind\">");
-               cprintf("<jid>%s</jid>", xmlesc(xmlbuf, XMPP->client_jid, sizeof xmlbuf));
-               cprintf("</bind>");
-               cprintf("</iq>");
+               XPUT("<iq type=\"result\" id=\"");
+               XPutProp(Xmpp->iq_id, strlen(Xmpp->iq_id));
+               XPUT("\">"
+                    "<bind xmlns=\"urn:ietf:params:xml:ns:xmpp-bind\">");
+               XPUT("<jid>");
+               XPutBody(Xmpp->client_jid, strlen(Xmpp->client_jid));
+               XPUT("</jid>"
+                    "</bind>"
+                    "</iq>");
        }
 
-       else if (XMPP->iq_session) {
-               cprintf("<iq type=\"result\" id=\"%s\">", xmlesc(xmlbuf, XMPP->iq_id, sizeof xmlbuf));
-               cprintf("</iq>");
+       else if (Xmpp->iq_session) {
+               XPUT("<iq type=\"result\" id=\"");
+               XPutProp(Xmpp->iq_id, strlen(Xmpp->iq_id));
+               XPUT("\">"
+                    "</iq>");
        }
 
        else {
-               cprintf("<iq type=\"error\" id=\"%s\">", xmlesc(xmlbuf, XMPP->iq_id, sizeof xmlbuf));
-               cprintf("<error>Don't know howto do '%s'!</error>", xmlesc(xmlbuf, XMPP->iq_type, sizeof xmlbuf));
-               cprintf("</iq>");
+               XPUT("<iq type=\"error\" id=\"");
+               XPutProp(Xmpp->iq_id, strlen(Xmpp->iq_id));
+               XPUT("\">");
+               XPUT("<error>Don't know howto do '");
+               XPutBody(Xmpp->iq_type, strlen(Xmpp->iq_type));
+               XPUT("'!</error>"
+                    "</iq>");
        }
 
        /* Now clear these fields out so they don't get used by a future stanza */
-       XMPP->iq_id[0] = 0;
-       XMPP->iq_from[0] = 0;
-       XMPP->iq_to[0] = 0;
-       XMPP->iq_type[0] = 0;
-       XMPP->iq_client_resource[0] = 0;
-       XMPP->iq_session = 0;
-       XMPP->iq_query_xmlns[0] = 0;
-       XMPP->bind_requested = 0;
-       XMPP->ping_requested = 0;
+       Xmpp->iq_id[0] = 0;
+       Xmpp->iq_from[0] = 0;
+       Xmpp->iq_to[0] = 0;
+       Xmpp->iq_type[0] = 0;
+       Xmpp->iq_client_resource[0] = 0;
+       Xmpp->iq_session = 0;
+       Xmpp->iq_query_xmlns[0] = 0;
+       Xmpp->bind_requested = 0;
+       Xmpp->ping_requested = 0;
 }
 
 
@@ -483,14 +436,6 @@ void xmpp_end_session(void *data, const char *supplied_el, const char **attr)
        XMPP->iq_session = 1;
 }
 
-void xmpp_end_presence(void *data, const char *supplied_el, const char **attr)
-{
-       /* Respond to a <presence> update by firing back with presence information
-        * on the entire wholist.  Check this assumption, it's probably wrong.
-        */
-       xmpp_wholist_presence_dump();
-}
-
 void xmpp_end_body(void *data, const char *supplied_el, const char **attr)
 {
        if (XMPP->html_tag_level == 0)
@@ -506,12 +451,6 @@ void xmpp_end_body(void *data, const char *supplied_el, const char **attr)
        }
 }
 
-void xmpp_end_message(void *data, const char *supplied_el, const char **attr)
-{
-       xmpp_send_message(XMPP->message_to, XMPP->message_body);
-       XMPP->html_tag_level = 0;
-}
-
 void xmpp_end_html(void *data, const char *supplied_el, const char **attr)
 {
        --XMPP->html_tag_level;
@@ -520,11 +459,11 @@ void xmpp_end_html(void *data, const char *supplied_el, const char **attr)
 void xmpp_end_starttls(void *data, const char *supplied_el, const char **attr)
 {
 #ifdef HAVE_OPENSSL
-       cprintf("<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>");
+       XPUT("<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>");
        CtdlModuleStartCryptoMsgs(NULL, NULL, NULL);
        if (!CC->redirect_ssl) CC->kill_me = KILLME_NO_CRYPTO;
 #else
-       cprintf("<failure xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>");
+       XPUT("<failure xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>");
        CC->kill_me = KILLME_NO_CRYPTO;
 #endif
 }
@@ -538,7 +477,7 @@ void xmpp_end_stream(void *data, const char *supplied_el, const char **attr)
 {
        XMPPM_syslog(LOG_DEBUG, "XMPP client shut down their stream\n");
        xmpp_massacre_roster();
-       cprintf("</stream>\n");
+       XPUT("</stream>\n");
        CC->kill_me = KILLME_CLIENT_LOGGED_OUT;
 }
 
@@ -581,6 +520,7 @@ void xmpp_xml_end(void *data, const char *supplied_el)
        if (XMPP->chardata_alloc > 0) {
                XMPP->chardata[0] = 0;
        }
+       XUnbuffer();
 }
 
 
@@ -765,15 +705,12 @@ CTDL_MODULE_INIT(xmpp)
                AddXMPPEndHandler(HKEY("iq"),            xmpp_end_iq, 0);
                AddXMPPEndHandler(HKEY("auth"),          xmpp_end_auth, 0);
                AddXMPPEndHandler(HKEY("session"),       xmpp_end_session, 0);
-               AddXMPPEndHandler(HKEY("presence"),      xmpp_end_presence, 0);
                AddXMPPEndHandler(HKEY("body"),          xmpp_end_body, 0);
-               AddXMPPEndHandler(HKEY("message"),       xmpp_end_message, 0);
                AddXMPPEndHandler(HKEY("html"),          xmpp_end_html, 0);
                AddXMPPEndHandler(HKEY("starttls"),      xmpp_end_starttls, 0);
                AddXMPPEndHandler(HKEY("ping"),          xmpp_end_ping, 0);
                AddXMPPEndHandler(HKEY("stream"),        xmpp_end_stream, 0);
 
-
                AddXMPPStartHandler(HKEY("stream"),     xmpp_stream_start, 0);
                AddXMPPStartHandler(HKEY("query"),      xmpp_start_query, 0);
                AddXMPPStartHandler(HKEY("bind"),       xmpp_start_bind, 0);
index faebc3615aea668b6df7a5d153318e2e3ed4b552..84bc29d5cf9a04386d08b89510c7492ffc4d1cd0 100644 (file)
@@ -17,6 +17,7 @@
  */
 
 typedef struct _citxmpp {                      /* Information about the current session */
+       StrBuf *OutBuf;
        XML_Parser xp;                  /* XML parser instance for incoming client stream */
        char server_name[256];          /* who they think we are */
        char *chardata;
@@ -80,7 +81,6 @@ void xmpp_async_loop(void);
 void xmpp_sasl_auth(char *, char *);
 void xmpp_output_auth_mechs(void);
 void xmpp_query_namespace(char *, char *, char *, char *);
-void xmpp_wholist_presence_dump(void);
 void xmpp_output_incoming_messages(void);
 void xmpp_queue_event(int, char *);
 void xmpp_process_events(void);
@@ -105,3 +105,22 @@ extern int XMPPSrvDebugEnable;
        DBGLOG(LEVEL) syslog(LEVEL,             \
                             "XMPP: " FORMAT);
 
+
+void XUnbuffer(void);
+void XPutBody(const char *Str, long Len);
+void XPutProp(const char *Str, long Len);
+void XPut(const char *Str, long Len);
+#define XPUT(CONSTSTR) XPut(CONSTSTR, sizeof(CONSTSTR) -1)
+
+void XPrintf(const char *Format, ...);
+
+
+void AddXMPPStartHandler(const char *key,
+                        long len,
+                        xmpp_handler_func Handler,
+                        int Flags);
+
+void AddXMPPEndHandler(const char *key,
+                      long len,
+                      xmpp_handler_func Handler,
+                      int Flags);
index 8b8b43f6b8d87706edfed58238c8ccf426660946..33a2e1ddbeb548c3ba4335960763eda1bc431a12 100644 (file)
  * If the client session has instant messages waiting, it outputs
  * unsolicited XML stanzas containing them.
  */
-void xmpp_output_incoming_messages(void) {
-
+void xmpp_output_incoming_messages(void)
+{
+       struct CitContext *CCC = CC;
+       citxmpp *Xmpp = XMPP;
        struct ExpressMessage *ptr;
-       char xmlbuf1[4096];
-       char xmlbuf2[4096];
 
-       while (CC->FirstExpressMessage != NULL) {
+       while (CCC->FirstExpressMessage != NULL) {
 
                begin_critical_section(S_SESSION_TABLE);
-               ptr = CC->FirstExpressMessage;
-               CC->FirstExpressMessage = CC->FirstExpressMessage->next;
+               ptr = CCC->FirstExpressMessage;
+               CCC->FirstExpressMessage = CCC->FirstExpressMessage->next;
                end_critical_section(S_SESSION_TABLE);
 
-               cprintf("<message to=\"%s\" from=\"%s\" type=\"chat\">",
-                       xmlesc(xmlbuf1, XMPP->client_jid, sizeof xmlbuf1),
-                       xmlesc(xmlbuf2, ptr->sender_email, sizeof xmlbuf2)
-               );
+               
+               XPUT("<message type=\"chat\" to=\"");
+               XPutProp(Xmpp->client_jid, strlen(Xmpp->client_jid));
+               XPUT("\" from=\"");
+               XPutProp(ptr->sender_email, strlen(ptr->sender_email));
+               XPUT("\" >");
+
                if (ptr->text != NULL) {
                        striplt(ptr->text);
-                       cprintf("<body>%s</body>", xmlesc(xmlbuf1, ptr->text, sizeof xmlbuf1));
+                       XPUT("<body>");
+                       XPutBody(ptr->text, strlen(ptr->text));
+                       XPUT("</body>");
                        free(ptr->text);
                }
-               cprintf("</message>");
+               XPUT("</message>");
                free(ptr);
        }
+       XUnbuffer();
 }
 
 /*
  * Client is sending a message.
  */
 void xmpp_send_message(char *message_to, char *message_body) {
+       struct CitContext *CCC = CC;
        char *recp = NULL;
        struct CitContext *cptr;
 
        if (message_body == NULL) return;
        if (message_to == NULL) return;
        if (IsEmptyStr(message_to)) return;
-       if (!CC->logged_in) return;
+       if (!CCC->logged_in) return;
 
        for (cptr = ContextList; cptr != NULL; cptr = cptr->next) {
                if (    (cptr->logged_in)
@@ -111,12 +118,26 @@ void xmpp_send_message(char *message_to, char *message_body) {
        }
 
        if (recp) {
-               PerformXmsgHooks(CC->user.fullname, CC->cs_inet_email, recp, message_body);
+               PerformXmsgHooks(CCC->user.fullname, CCC->cs_inet_email, recp, message_body);
        }
 
        free(XMPP->message_body);
        XMPP->message_body = NULL;
        XMPP->message_to[0] = 0;
-       time(&CC->lastidle);
+       time(&CCC->lastidle);
 }
+void xmpp_end_message(void *data, const char *supplied_el, const char **attr)
+{
+       xmpp_send_message(XMPP->message_to, XMPP->message_body);
+       XMPP->html_tag_level = 0;
+}
+
 
+
+CTDL_MODULE_INIT(xmpp_message)
+{
+       if (!threading) {
+               AddXMPPEndHandler(HKEY("message"),       xmpp_end_message, 0);
+       }
+       return "xmpp_message";
+}
index ca8a95949d8d95b10dc7e8d679787ab072a600ac..521d257c4cb386d1e1c8a027f5b4a5331794cf16 100644 (file)
  */
 void xmpp_indicate_presence(char *presence_jid)
 {
-       char xmlbuf[256];
-
-       cprintf("<presence from=\"%s\" ", xmlesc(xmlbuf, presence_jid, sizeof xmlbuf));
-       cprintf("to=\"%s\"></presence>", xmlesc(xmlbuf, XMPP->client_jid, sizeof xmlbuf));
+       XPUT("<presence from=\"");
+       XPutProp(presence_jid, strlen(presence_jid));
+       XPUT("\" to=\"");
+       XPutProp(XMPP->client_jid, strlen(XMPP->client_jid));
+       XPUT("\"></presence>");
 }
 
 
@@ -95,8 +96,10 @@ int xmpp_is_visible(struct CitContext *cptr, struct CitContext *to_whom) {
 
 /* 
  * Initial dump of the entire wholist
+ * Respond to a <presence> update by firing back with presence information
+ * on the entire wholist.  Check this assumption, it's probably wrong.  
  */
-void xmpp_wholist_presence_dump(void)
+void xmpp_wholist_presence_dump(void *data, const char *supplied_el, const char **attr)
 {
        struct CitContext *cptr = NULL;
        int nContexts, i;
@@ -121,18 +124,18 @@ void xmpp_wholist_presence_dump(void)
  */
 void xmpp_destroy_buddy(char *presence_jid, int aggressively) {
        static int unsolicited_id = 1;
-       char xmlbuf1[256];
-       char xmlbuf2[256];
+       struct CitContext *CCC = CC;
 
        if (!presence_jid) return;
        if (!XMPP) return;
        if (!XMPP->client_jid) return;
 
        /* Transmit non-presence information */
-       cprintf("<presence type=\"unavailable\" from=\"%s\" to=\"%s\"></presence>",
-               xmlesc(xmlbuf1, presence_jid, sizeof xmlbuf1),
-               xmlesc(xmlbuf2, XMPP->client_jid, sizeof xmlbuf2)
-       );
+       XPUT("<presence type=\"unavailable\" from=\"");
+       XPutProp(presence_jid, strlen(presence_jid));
+       XPUT("\" to=\"");
+       XPutProp(XMPP->client_jid, strlen(XMPP->client_jid));
+       XPUT("\"></presence>");
 
        /*
         * Setting the "aggressively" flag also sends an "unsubscribed" presence update.
@@ -141,26 +144,34 @@ void xmpp_destroy_buddy(char *presence_jid, int aggressively) {
         * it as a rejection of a subscription request.
         */
        if (aggressively) {
-               cprintf("<presence type=\"unsubscribed\" from=\"%s\" to=\"%s\"></presence>",
-                       xmlesc(xmlbuf1, presence_jid, sizeof xmlbuf1),
-                       xmlesc(xmlbuf2, XMPP->client_jid, sizeof xmlbuf2)
-               );
+               XPUT("<presence type=\"unsubscribed\" from=\"");
+               XPutProp(presence_jid, strlen(presence_jid));
+               XPUT("\" to=\"");
+               XPutProp(XMPP->client_jid, strlen(XMPP->client_jid));
+               XPUT("\"></presence>");
        }
 
        // FIXME ... we should implement xmpp_indicate_nonpresence so we can use it elsewhere
 
        /* Do an unsolicited roster update that deletes the contact. */
-       cprintf("<iq from=\"%s\" to=\"%s\" id=\"unbuddy_%x\" type=\"result\">",
-               xmlesc(xmlbuf1, CC->cs_inet_email, sizeof xmlbuf1),
-               xmlesc(xmlbuf2, XMPP->client_jid, sizeof xmlbuf2),
-               ++unsolicited_id
-       );
-       cprintf("<query xmlns=\"jabber:iq:roster\">");
-       cprintf("<item jid=\"%s\" subscription=\"remove\">", xmlesc(xmlbuf1, presence_jid, sizeof xmlbuf1));
-       cprintf("<group>%s</group>", xmlesc(xmlbuf1, config.c_humannode, sizeof xmlbuf1));
-       cprintf("</item>");
-       cprintf("</query>"
-               "</iq>"
+       XPUT("<iq type=\"result\" from=\"");
+       XPutProp(CCC->cs_inet_email, strlen(CCC->cs_inet_email));
+       XPUT("\" to=\"");
+       XPutProp(XMPP->client_jid, strlen(XMPP->client_jid));
+       XPUT("\" id=\"unbuddy_");
+       XPrintf("%x", ++unsolicited_id);
+       XPUT("\">");
+       
+       XPUT("<query xmlns=\"jabber:iq:roster\">"
+            "<item subscription=\"remove\" jid=\"");
+       XPutProp(presence_jid, strlen(presence_jid));
+       XPUT("\">" 
+            "<group>");
+       XPutBody(CFG_KEY(c_humannode));
+       XPUT("</group>"
+            "</item>"
+            "</query>"
+            "</iq>"
        );
 }
 
@@ -204,10 +215,12 @@ void xmpp_presence_notify(char *presence_jid, int event_type) {
 
                /* Do an unsolicited roster update that adds a new contact. */
                assert(which_cptr_is_relevant >= 0);
-               cprintf("<iq id=\"unsolicited_%x\" type=\"result\">", ++unsolicited_id);
-               cprintf("<query xmlns=\"jabber:iq:roster\">");
+               XPUT("<iq type=\"result\" id=\"unsolicited_");
+               XPrintf("%x", ++unsolicited_id);
+               XPUT("\" >"
+                    "<query xmlns=\"jabber:iq:roster\">");
                xmpp_roster_item(&cptr[which_cptr_is_relevant]);
-               cprintf("</query></iq>");
+               XPUT("</query></iq>");
 
                /* Transmit presence information */
                xmpp_indicate_presence(presence_jid);
@@ -410,3 +423,11 @@ void xmpp_delete_old_buddies_who_no_longer_exist_from_the_client_roster(void)
        free(cptr);
 }
 
+
+CTDL_MODULE_INIT(xmpp_presence)
+{
+       if (!threading) {
+               AddXMPPEndHandler(HKEY("presence"), xmpp_wholist_presence_dump, 0);
+       }
+       return "xmpp_presence";
+}
index cf6f423a56516cd392ce78ae9c79f93d486ff2f5..e791f3e6bcac09305038cb502165288ee9976b4a 100644 (file)
 /*
  * Output a single roster item, for roster queries or pushes
  */
-void xmpp_roster_item(struct CitContext *cptr) {
-       char xmlbuf1[256];
-       char xmlbuf2[256];
-
-       cprintf("<item jid=\"%s\" name=\"%s\" subscription=\"both\">",
-               xmlesc(xmlbuf1, cptr->cs_inet_email, sizeof xmlbuf1),
-               xmlesc(xmlbuf2, cptr->user.fullname, sizeof xmlbuf2)
-       );
-       cprintf("<group>%s</group>", xmlesc(xmlbuf1, config.c_humannode, sizeof xmlbuf1));
-       cprintf("</item>");
+void xmpp_roster_item(struct CitContext *cptr)
+{
+
+       XPUT("<item subscription=\"both\" jid=\"");
+       XPutProp(cptr->cs_inet_email, strlen(cptr->cs_inet_email));
+       XPUT("\" name=\"");
+       XPutProp(cptr->user.fullname, strlen(cptr->user.fullname));
+       XPUT("\">"
+            "<group>");
+       XPutBody(CFG_KEY(c_humannode));
+       XPUT("</group>"
+            "</item>");
 }
 
 /* 
@@ -83,7 +85,7 @@ void xmpp_iq_roster_query(void)
        struct CitContext *cptr;
        int nContexts, i;
 
-       cprintf("<query xmlns=\"jabber:iq:roster\">");
+       XPUT("<query xmlns=\"jabber:iq:roster\">");
        cptr = CtdlGetContextArray(&nContexts);
        if (cptr) {
                for (i=0; i<nContexts; i++) {
@@ -94,7 +96,7 @@ void xmpp_iq_roster_query(void)
                }
                free (cptr);
        }
-       cprintf("</query>");
+       XPUT("</query>");
 }
 
 
@@ -111,7 +113,6 @@ void xmpp_query_namespace(char *iq_id, char *iq_from, char *iq_to, char *query_x
 {
        int supported_namespace = 0;
        int roster_query = 0;
-       char xmlbuf[256];
 
        /* We need to know before we begin the response whether this is a supported namespace, so
         * unfortunately all supported namespaces need to be defined here *and* down below where
@@ -130,15 +131,19 @@ void xmpp_query_namespace(char *iq_id, char *iq_from, char *iq_to, char *query_x
         * Beginning of query result.
         */
        if (supported_namespace) {
-               cprintf("<iq type=\"result\" ");
+               XPUT("<iq type=\"result\" ");
        }
        else {
-               cprintf("<iq type=\"error\" ");
+                XPUT("<iq type=\"error\" ");
        }
        if (!IsEmptyStr(iq_from)) {
-               cprintf("to=\"%s\" ", xmlesc(xmlbuf, iq_from, sizeof xmlbuf));
+               XPUT("to=\"");
+               XPutProp(iq_from, strlen(iq_from));
+               XPUT("\" ");
        }
-       cprintf("id=\"%s\">", xmlesc(xmlbuf, iq_id, sizeof xmlbuf));
+       XPUT("id=\"");
+       XPutProp(iq_id, strlen(iq_id));
+       XPUT("\">");
 
        /*
         * Is this a query we know how to handle?
@@ -150,9 +155,9 @@ void xmpp_query_namespace(char *iq_id, char *iq_from, char *iq_to, char *query_x
        }
 
        else if (!strcasecmp(query_xmlns, "jabber:iq:auth:query")) {
-               cprintf("<query xmlns=\"jabber:iq:auth\">"
-                       "<username/><password/><resource/>"
-                       "</query>"
+               XPUT("<query xmlns=\"jabber:iq:auth\">"
+                    "<username/><password/><resource/>"
+                    "</query>"
                );
        }
 
@@ -166,13 +171,13 @@ void xmpp_query_namespace(char *iq_id, char *iq_from, char *iq_to, char *query_x
                            "Unknown query namespace '%s' - returning <service-unavailable/>\n",
                            query_xmlns
                );
-               cprintf("<error code=\"503\" type=\"cancel\">"
-                       "<service-unavailable xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"/>"
-                       "</error>"
+               XPUT("<error code=\"503\" type=\"cancel\">"
+                    "<service-unavailable xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"/>"
+                    "</error>"
                );
        }
 
-       cprintf("</iq>");
+       XPUT("</iq>");
 
        /* If we told the client who is on the roster, we also need to tell the client
         * who is *not* on the roster.  (It's down here because we can't do it in the same
index 393174dce18b2cf78901e61aa1955743d84f08fc..968cef950025830a79e5491153be821a8d0b7a2b 100644 (file)
@@ -113,9 +113,9 @@ int xmpp_auth_plain(char *authstring)
  * Output the list of SASL mechanisms offered by this stream.
  */
 void xmpp_output_auth_mechs(void) {
-       cprintf("<mechanisms xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">");
-       cprintf("<mechanism>PLAIN</mechanism>");
-       cprintf("</mechanisms>");
+       XPUT("<mechanisms xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">"
+            "<mechanism>PLAIN</mechanism>"
+            "</mechanisms>");
 }
 
 /*
@@ -124,28 +124,28 @@ void xmpp_output_auth_mechs(void) {
 void xmpp_sasl_auth(char *sasl_auth_mech, char *authstring) {
 
        if (strcasecmp(sasl_auth_mech, "PLAIN")) {
-               cprintf("<failure xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">");
-               cprintf("<invalid-mechanism/>");
-               cprintf("</failure>");
+               XPUT("<failure xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">"
+                    "<invalid-mechanism/>"
+                    "</failure>");
                return;
        }
 
         if (CC->logged_in) CtdlUserLogout();  /* Client may try to log in twice.  Handle this. */
 
        if (CC->nologin) {
-               cprintf("<failure xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">");
-               cprintf("<system-shutdown/>");
-               cprintf("</failure>");
+               XPUT("<failure xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">"
+                    "<system-shutdown/>"
+                    "</failure>");
        }
 
        else if (xmpp_auth_plain(authstring) == 0) {
-               cprintf("<success xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\"/>");
+               XPUT("<success xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\"/>");
        }
 
        else {
-               cprintf("<failure xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">");
-               cprintf("<not-authorized/>");
-               cprintf("</failure>");
+               XPUT("<failure xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">"
+                    "<not-authorized/>"
+                    "</failure>");
        }
 }
 
@@ -156,7 +156,6 @@ void xmpp_sasl_auth(char *sasl_auth_mech, char *authstring) {
  */
 void xmpp_non_sasl_authenticate(char *iq_id, char *username, char *password, char *resource) {
        int result;
-       char xmlbuf[256];
 
         if (CC->logged_in) CtdlUserLogout();  /* Client may try to log in twice.  Handle this. */
 
@@ -164,16 +163,20 @@ void xmpp_non_sasl_authenticate(char *iq_id, char *username, char *password, cha
        if (result == login_ok) {
                result = CtdlTryPassword(password, strlen(password));
                if (result == pass_ok) {
-                       cprintf("<iq type=\"result\" id=\"%s\"></iq>", xmlesc(xmlbuf, iq_id, sizeof xmlbuf));   /* success */
+                       XPUT("<iq type=\"result\" id=\"");
+                       XPutProp(iq_id, strlen(iq_id));
+                       XPUT("\"></iq>"); /* success */
                        return;
                }
        }
 
        /* failure */
-       cprintf("<iq type=\"error\" id=\"%s\">", xmlesc(xmlbuf, iq_id, sizeof xmlbuf));
-       cprintf("<error code=\"401\" type=\"auth\">"
-               "<not-authorized xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"/>"
-               "</error>"
-               "</iq>"
+       XPUT("<iq type=\"error\" id=\"");
+       XPutProp(iq_id, strlen(iq_id));
+       XPUT("\">"
+            "<error code=\"401\" type=\"auth\">"
+            "<not-authorized xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"/>"
+            "</error>"
+            "</iq>"
        );
 }