Merge branch 'master' of ssh://git.citadel.org/appl/gitroot/citadel
authorArt Cancro <ajc@uncensored.citadel.org>
Tue, 19 Nov 2013 16:49:48 +0000 (11:49 -0500)
committerArt Cancro <ajc@uncensored.citadel.org>
Tue, 19 Nov 2013 16:49:48 +0000 (11:49 -0500)
19 files changed:
citadel/ldap.c
citadel/modules/network/serv_netspool.c
citadel/modules/pop3/serv_pop3.c
citadel/modules/smtp/serv_smtp.c
citadel/modules/xmpp/serv_xmpp.c
citadel/modules/xmpp/serv_xmpp.h
citadel/modules/xmpp/token.def [new file with mode: 0644]
citadel/modules/xmpp/xmpp_messages.c
citadel/modules/xmpp/xmpp_presence.c
citadel/modules/xmpp/xmpp_query_namespace.c
citadel/modules/xmpp/xmpp_queue.c
citadel/modules/xmpp/xmpp_sasl_service.c
citadel/modules/xmpp/xmpp_util.h [new file with mode: 0644]
citadel/modules/xmpp/xmpp_xmacros.c [new file with mode: 0644]
citadel/modules/xmpp/xmpp_xmacros.h [new file with mode: 0644]
citadel/msgbase.c
libcitadel/lib/libcitadel.h
libcitadel/lib/mime_parser.c
libcitadel/lib/stringbuf.c

index a6f3db3c275f035e4a570b7664a2a18d6acfc008..864ab4807230af05da9e63e6871f781defc19383 100644 (file)
@@ -42,6 +42,7 @@ int CtdlTryUserLDAP(char *username,
        char **values;
        char *user_dn = NULL;
 
+#ifndef LDAP_INITIALIZE
        if (fullname) safestrncpy(fullname, username, fullname_size);
 
        ldserver = ldap_init(config.c_ldap_host, config.c_ldap_port);
@@ -67,6 +68,31 @@ int CtdlTryUserLDAP(char *username,
                syslog(LOG_ALERT, "LDAP: Cannot bind: %s (%d)\n", ldap_err2string(i), i);
                return(i);
        }
+#else
+       if (ldap_initialize(&ldserver, config.c_ldap_host))
+       {
+               syslog(LOG_ALERT, "LDAP: Could not connect to %s:%d : %s\n",
+                      config.c_ldap_host, config.c_ldap_port,
+                      strerror(errno)
+                       );
+               return(errno);
+       }
+
+       striplt(config.c_ldap_bind_dn);
+       striplt(config.c_ldap_bind_pw);
+
+       syslog(LOG_DEBUG, "LDAP bind DN: %s\n", config.c_ldap_bind_dn);
+       i = ldap_simple_bind_s(ldserver,
+               (!IsEmptyStr(config.c_ldap_bind_dn) ? config.c_ldap_bind_dn : NULL),
+               (!IsEmptyStr(config.c_ldap_bind_pw) ? config.c_ldap_bind_pw : NULL)
+       );
+
+       if (i != LDAP_SUCCESS) {
+               syslog(LOG_ALERT, "LDAP: Cannot bind: %s (%d)\n", ldap_err2string(i), i);
+               return(i);
+       }
+#endif
+
 
        tv.tv_sec = 10;
        tv.tv_usec = 0;
index 62afec686cb53afa4307133f25e5b9ce4c180893..96ac8bf6ced32492f229f914ba0ea7dc098db553 100644 (file)
@@ -978,7 +978,7 @@ void network_consolidate_spoolout(HashList *working_ignetcfg, HashList *the_netm
               (filedir_entry != NULL))
        {
 #ifdef _DIRENT_HAVE_D_NAMLEN
-               d_namelen = filedir_entry->d_namelen;
+               d_namelen = filedir_entry->d_namlen;
 
 #else
                d_namelen = strlen(filedir_entry->d_name);
index 97681da8366e36b2fa5be74b9b936b79af9f9cda..5468af94bacecb2f092579dd44c17a33fdcaf49f 100644 (file)
 
 #include "ctdl_module.h"
 
+int POP3DebugEnabled = 0;
 
+#define POP3DBGLOG(LEVEL) if ((LEVEL != LOG_DEBUG) || (POP3DebugEnabled != 0))
+#define CCCID CCC->cs_pid
+#define POP3_syslog(LEVEL, FORMAT, ...)                        \
+       POP3DBGLOG(LEVEL) syslog(LEVEL,                 \
+                                "POP3CC[%d] " FORMAT,  \
+                                CCCID, __VA_ARGS__)
+
+#define POP3M_syslog(LEVEL, FORMAT)                    \
+       POP3DBGLOG(LEVEL) syslog(LEVEL,                 \
+                                "POP3CC[%d] " FORMAT,  \
+                                CCCID)
 
 /*
  * This cleanup function blows away the temporary memory and files used by
  * the POP3 server.
  */
-void pop3_cleanup_function(void) {
+void pop3_cleanup_function(void)
+{
+       struct CitContext *CCC = CC;
 
        /* Don't do this stuff if this is not a POP3 session! */
-       if (CC->h_command_function != pop3_command_loop) return;
+       if (CCC->h_command_function != pop3_command_loop) return;
 
-       syslog(LOG_DEBUG, "Performing POP3 cleanup hook");
+       POP3M_syslog(LOG_DEBUG, "Performing POP3 cleanup hook");
        if (POP3->msgs != NULL) free(POP3->msgs);
 
        free(POP3);
@@ -92,10 +106,13 @@ void pop3_cleanup_function(void) {
 /*
  * Here's where our POP3 session begins its happy day.
  */
-void pop3_greeting(void) {
-       strcpy(CC->cs_clientname, "POP3 session");
-       CC->internal_pgm = 1;
-       CC->session_specific_data = malloc(sizeof(struct citpop3));
+void pop3_greeting(void)
+{
+       struct CitContext *CCC = CC;
+
+       strcpy(CCC->cs_clientname, "POP3 session");
+       CCC->internal_pgm = 1;
+       CCC->session_specific_data = malloc(sizeof(struct citpop3));
        memset(POP3, 0, sizeof(struct citpop3));
 
        cprintf("+OK Citadel POP3 server ready.\r\n");
@@ -105,14 +122,16 @@ void pop3_greeting(void) {
 /*
  * POP3S is just like POP3, except it goes crypto right away.
  */
-void pop3s_greeting(void) {
+void pop3s_greeting(void)
+{
+       struct CitContext *CCC = CC;
        CtdlModuleStartCryptoMsgs(NULL, NULL, NULL);
 
 /* kill session if no crypto */
 #ifdef HAVE_OPENSSL
-       if (!CC->redirect_ssl) CC->kill_me = KILLME_NO_CRYPTO;
+       if (!CCC->redirect_ssl) CCC->kill_me = KILLME_NO_CRYPTO;
 #else
-       CC->kill_me = KILLME_NO_CRYPTO;
+       CCC->kill_me = KILLME_NO_CRYPTO;
 #endif
 
        pop3_greeting();
@@ -123,10 +142,12 @@ void pop3s_greeting(void) {
 /*
  * Specify user name (implements POP3 "USER" command)
  */
-void pop3_user(char *argbuf) {
+void pop3_user(char *argbuf)
+{
+       struct CitContext *CCC = CC;
        char username[SIZ];
 
-       if (CC->logged_in) {
+       if (CCC->logged_in) {
                cprintf("-ERR You are already logged in.\r\n");
                return;
        }
@@ -134,7 +155,7 @@ void pop3_user(char *argbuf) {
        strcpy(username, argbuf);
        striplt(username);
 
-       /* syslog(LOG_DEBUG, "Trying <%s>", username); */
+       /* POP3_syslog(LOG_DEBUG, "Trying <%s>", username); */
        if (CtdlLoginExistingUser(NULL, username) == login_ok) {
                cprintf("+OK Password required for %s\r\n", username);
        }
@@ -148,7 +169,9 @@ void pop3_user(char *argbuf) {
 /*
  * Back end for pop3_grab_mailbox()
  */
-void pop3_add_message(long msgnum, void *userdata) {
+void pop3_add_message(long msgnum, void *userdata)
+{
+       struct CitContext *CCC = CC;
        struct MetaData smi;
 
        ++POP3->num_msgs;
@@ -165,7 +188,7 @@ void pop3_add_message(long msgnum, void *userdata) {
         */
        GetMetaData(&smi, msgnum);
        if (smi.meta_rfc822_length <= 0L) {
-               CC->redirect_buffer = NewStrBufPlain(NULL, SIZ);
+               CCC->redirect_buffer = NewStrBufPlain(NULL, SIZ);
 
                CtdlOutputMsg(msgnum,
                              MT_RFC822,
@@ -174,8 +197,8 @@ void pop3_add_message(long msgnum, void *userdata) {
                              SUPPRESS_ENV_TO,
                              NULL, NULL);
 
-               smi.meta_rfc822_length = StrLength(CC->redirect_buffer);
-               FreeStrBuf(&CC->redirect_buffer); /* TODO: WHEW, all this for just knowing the length???? */
+               smi.meta_rfc822_length = StrLength(CCC->redirect_buffer);
+               FreeStrBuf(&CCC->redirect_buffer); /* TODO: WHEW, all this for just knowing the length???? */
                PutMetaData(&smi);
        }
        POP3->msgs[POP3->num_msgs-1].rfc822_length = smi.meta_rfc822_length;
@@ -188,18 +211,20 @@ void pop3_add_message(long msgnum, void *userdata) {
  * (This should be called only once, by pop3_pass(), and returns the number
  * of messages in the inbox, or -1 for error)
  */
-int pop3_grab_mailbox(void) {
+int pop3_grab_mailbox(void)
+{
+       struct CitContext *CCC = CC;
         visit vbuf;
        int i;
 
-       if (CtdlGetRoom(&CC->room, MAILROOM) != 0) return(-1);
+       if (CtdlGetRoom(&CCC->room, MAILROOM) != 0) return(-1);
 
        /* Load up the messages */
        CtdlForEachMessage(MSGS_ALL, 0L, NULL, NULL, NULL,
                pop3_add_message, NULL);
 
        /* Figure out which are old and which are new */
-        CtdlGetRelationship(&vbuf, &CC->user, &CC->room);
+        CtdlGetRelationship(&vbuf, &CCC->user, &CCC->room);
        POP3->lastseen = (-1);
        if (POP3->num_msgs) for (i=0; i<POP3->num_msgs; ++i) {
                if (is_msg_in_sequence_set(vbuf.v_seen,
@@ -213,13 +238,14 @@ int pop3_grab_mailbox(void) {
 
 void pop3_login(void)
 {
+       struct CitContext *CCC = CC;
        int msgs;
        
        msgs = pop3_grab_mailbox();
        if (msgs >= 0) {
                cprintf("+OK %s is logged in (%d messages)\r\n",
-                       CC->user.fullname, msgs);
-               syslog(LOG_NOTICE, "POP3 authenticated %s", CC->user.fullname);
+                       CCC->user.fullname, msgs);
+               POP3_syslog(LOG_DEBUG, "POP3 authenticated %s", CCC->user.fullname);
        }
        else {
                cprintf("-ERR Can't open your mailbox\r\n");
@@ -237,7 +263,7 @@ void pop3_pass(char *argbuf) {
        safestrncpy(password, argbuf, sizeof password);
        striplt(password);
 
-       /* syslog(LOG_DEBUG, "Trying <%s>", password); */
+       /* POP3_syslog(LOG_DEBUG, "Trying <%s>", password); */
        if (CtdlTryPassword(password, strlen(password)) == pass_ok) {
                pop3_login();
        }
@@ -341,7 +367,9 @@ void pop3_retr(char *argbuf) {
 /*
  * TOP command (dumb way of fetching a partial message or headers-only)
  */
-void pop3_top(char *argbuf) {
+void pop3_top(char *argbuf)
+{
+       struct CitContext *CCC = CC;
        int which_one;
        int lines_requested = 0;
        int lines_dumped = 0;
@@ -362,7 +390,7 @@ void pop3_top(char *argbuf) {
                return;
        }
 
-       CC->redirect_buffer = NewStrBufPlain(NULL, SIZ);
+       CCC->redirect_buffer = NewStrBufPlain(NULL, SIZ);
 
        CtdlOutputMsg(POP3->msgs[which_one - 1].msgnum,
                      MT_RFC822,
@@ -371,8 +399,8 @@ void pop3_top(char *argbuf) {
                      SUPPRESS_ENV_TO,
                      NULL, NULL);
 
-       msgtext = CC->redirect_buffer;
-       CC->redirect_buffer = NULL;
+       msgtext = CCC->redirect_buffer;
+       CCC->redirect_buffer = NULL;
 
        cprintf("+OK Message %d:\r\n", which_one);
        
@@ -427,7 +455,9 @@ void pop3_dele(char *argbuf) {
 
 /* Perform "UPDATE state" stuff
  */
-void pop3_update(void) {
+void pop3_update(void)
+{
+       struct CitContext *CCC = CC;
        int i;
         visit vbuf;
 
@@ -450,14 +480,14 @@ void pop3_update(void) {
 
        /* Set last read pointer */
        if (POP3->num_msgs > 0) {
-               CtdlGetUserLock(&CC->user, CC->curr_user);
+               CtdlGetUserLock(&CCC->user, CCC->curr_user);
 
-               CtdlGetRelationship(&vbuf, &CC->user, &CC->room);
+               CtdlGetRelationship(&vbuf, &CCC->user, &CCC->room);
                snprintf(vbuf.v_seen, sizeof vbuf.v_seen, "*:%ld",
                        POP3->msgs[POP3->num_msgs-1].msgnum);
-               CtdlSetRelationship(&vbuf, &CC->user, &CC->room);
+               CtdlSetRelationship(&vbuf, &CCC->user, &CCC->room);
 
-               CtdlPutUserLock(&CC->user);
+               CtdlPutUserLock(&CCC->user);
        }
 
 }
@@ -577,21 +607,23 @@ void pop3_stls(void)
 /* 
  * Main command loop for POP3 sessions.
  */
-void pop3_command_loop(void) {
+void pop3_command_loop(void)
+{
+       struct CitContext *CCC = CC;
        char cmdbuf[SIZ];
 
-       time(&CC->lastcmd);
+       time(&CCC->lastcmd);
        memset(cmdbuf, 0, sizeof cmdbuf); /* Clear it, just in case */
        if (client_getln(cmdbuf, sizeof cmdbuf) < 1) {
-               syslog(LOG_ERR, "POP3 client disconnected: ending session.");
-               CC->kill_me = KILLME_CLIENT_DISCONNECTED;
+               POP3M_syslog(LOG_INFO, "POP3 client disconnected: ending session.");
+               CCC->kill_me = KILLME_CLIENT_DISCONNECTED;
                return;
        }
        if (!strncasecmp(cmdbuf, "PASS", 4)) {
-               syslog(LOG_INFO, "POP3: PASS...");
+               POP3M_syslog(LOG_DEBUG, "POP3: PASS...");
        }
        else {
-               syslog(LOG_INFO, "POP3: %s", cmdbuf);
+               POP3_syslog(LOG_DEBUG, "POP3: %s", cmdbuf);
        }
        while (strlen(cmdbuf) < 5) strcat(cmdbuf, " ");
 
@@ -606,7 +638,7 @@ void pop3_command_loop(void) {
        else if (!strncasecmp(cmdbuf, "QUIT", 4)) {
                cprintf("+OK Goodbye...\r\n");
                pop3_update();
-               CC->kill_me = KILLME_CLIENT_LOGGED_OUT;
+               CCC->kill_me = KILLME_CLIENT_LOGGED_OUT;
                return;
        }
 
@@ -624,13 +656,13 @@ void pop3_command_loop(void) {
        }
 #endif
 
-       else if (!CC->logged_in) {
+       else if (!CCC->logged_in) {
                cprintf("-ERR Not logged in.\r\n");
        }
        
-       else if (CC->nologin) {
+       else if (CCC->nologin) {
                cprintf("-ERR System busy, try later.\r\n");
-               CC->kill_me = KILLME_NOLOGIN;
+               CCC->kill_me = KILLME_NOLOGIN;
        }
 
        else if (!strncasecmp(cmdbuf, "LIST", 4)) {
@@ -674,11 +706,18 @@ void pop3_command_loop(void) {
 const char *CitadelServicePop3="POP3";
 const char *CitadelServicePop3S="POP3S";
 
+void SetPOP3DebugEnabled(const int n)
+{
+       POP3DebugEnabled = n;
+}
+
 
 CTDL_MODULE_INIT(pop3)
 {
        if(!threading)
        {
+               CtdlRegisterDebugFlagHook(HKEY("pop3srv"), SetPOP3DebugEnabled, &POP3DebugEnabled);
+
                CtdlRegisterServiceHook(config.c_pop3_port,
                                        NULL,
                                        pop3_greeting,
index 6a06515c3b7d88407deced7d631a9ccca0da67df..58457b180cdc8ff50cab65801207ee31c4044dca 100644 (file)
@@ -996,10 +996,12 @@ void smtp_command_loop(void)
 
        if (sSMTP->command_state == smtp_user) {
                smtp_get_user(0);
+               return;
        }
 
        else if (sSMTP->command_state == smtp_password) {
                smtp_get_pass(0, 0);
+               return;
        }
 
        else if (sSMTP->command_state == smtp_plain) {
index e696069a171ece7b5cac38dc2cb25abe09335231..63b27c5138936a650f58d9a4eecae8a45a2d0a1b 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"
 #define HAVE_XML_STOPPARSER
 #endif
 
-struct xmpp_event *xmpp_queue = NULL;
 HashList *XMPP_StartHandlers = NULL;
 HashList *XMPP_EndHandlers = NULL;
+HashList *XMPP_SupportedNamespaces = NULL;
+HashList *XMPP_NameSpaces = NULL;
+HashList *FlatToken = NULL;
 
 int XMPPSrvDebugEnable = 0;
 
+void XUnbuffer(void)
+{
+       citxmpp *Xmpp = XMPP;
 
+       cputbuf(Xmpp->OutBuf);
+       FlushStrBuf(Xmpp->OutBuf);
+}
 
-#ifdef HAVE_XML_STOPPARSER
-/* Stop the parser if an entity declaration is hit. */
-static void xmpp_entity_declaration(void *userData, const XML_Char *entityName,
-                               int is_parameter_entity, const XML_Char *value,
-                               int value_length, const XML_Char *base,
-                               const XML_Char *systemId, const XML_Char *publicId,
-                               const XML_Char *notationName
-) {
-       XMPPM_syslog(LOG_WARNING, "Illegal entity declaration encountered; stopping parser.");
-       XML_StopParser(XMPP->xp, XML_FALSE);
+void XPutBody(const char *Str, long Len)
+{
+       StrBufXMLEscAppend(XMPP->OutBuf, NULL, Str, Len, 0);
 }
-#endif
 
-static inline int XMPP_GetUtf8SequenceLength(const char *CharS, const char *CharE)
+void XPutProp(const char *Str, long Len)
 {
-       /* if this is is migrated to strbuf, remove this copy. */
-       int n = 0;
-        unsigned char test = (1<<7);
+       StrEscAppend(XMPP->OutBuf, NULL, Str, 0, 1);
+}
 
-       if ((*CharS & 0xC0) != 0xC0) 
-               return 1;
+void XPut(const char *Str, long Len)
+{
+       StrBufAppendBufPlain(XMPP->OutBuf, Str, Len, 0);
+}
 
-       while ((n < 8) && 
-              ((test & ((unsigned char)*CharS)) != 0)) 
-       {
-               test = test >> 1;
-               n ++;
-       }
-       if ((n > 6) || ((CharE - CharS) < n))
-               n = 0;
-       return n;
+void XPrintf(const char *Format, ...)
+{
+        va_list arg_ptr;
+        va_start(arg_ptr, Format);
+       StrBufVAppendPrintf(XMPP->OutBuf, Format, arg_ptr);
+       va_end(arg_ptr);
 }
 
 
-/*
- * 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];
+void XPrint(const char *Token, long tlen,
+           int Flags,
+           ...)
 
-                       IsUtf8Sequence =  XMPP_GetUtf8SequenceLength(&buf[len], eiptr);
-                       if (IsUtf8Sequence)
-                       {
-                               while (IsUtf8Sequence > 0){
-                                       buf[len] = *ptr;
-                                       len ++;
-                                       if (--IsUtf8Sequence)
-                                               ptr++;
-                               }
-                               buf[len] = '\0';
-                       }
-                       else
+{
+       int BodySeen = 0;
+       int ArgType;
+       int Finished = 0;
+       char *PName;
+       long PLen;
+       char *Val;
+       long VLen;
+        va_list arg_ptr;
+
+       XPUT("<");
+       XPut(Token, tlen);
+
+        va_start(arg_ptr, Flags);
+       while (!Finished)
+       {
+               ArgType = va_arg(arg_ptr, int);
+               switch (ArgType)
+               {
+               case TYPE_STR:
+                       PName = va_arg(arg_ptr, char*);
+                       PLen  = va_arg(arg_ptr, long);
+                       Val   = va_arg(arg_ptr, char*);
+                       VLen  = va_arg(arg_ptr, long);
+                       XPUT(" ");
+                       XPut(PName, PLen);
+                       XPUT("=\"");
+                       XPutProp(Val, VLen);
+                       XPUT("\"");
+                       break;
+               case TYPE_OPTSTR:
+                       PName = va_arg(arg_ptr, char*);
+                       PLen  = va_arg(arg_ptr, long);
+                       Val   = va_arg(arg_ptr, char*);
+                       VLen  = va_arg(arg_ptr, long);
+                       if (VLen > 0)
                        {
-                               sprintf(oct, "&#%o;", ch);
-                               strcpy(&buf[len], oct);
-                               len += strlen(oct);
+                               XPUT(" ");
+                               XPut(PName, PLen);
+                               XPUT("=\"");
+                               XPutProp(Val, VLen);
+                               XPUT("\"");
                        }
+                       break;
+               case TYPE_INT:
+                       PName = va_arg(arg_ptr, char*);
+                       PLen  = va_arg(arg_ptr, long);
+                       VLen  = va_arg(arg_ptr, long);
+                       XPUT(" ");
+                       XPut(PName, PLen);
+                       XPUT("=\"");
+                       XPrintf("%ld", VLen);
+                       XPUT("\"");
+                       break;
+               case TYPE_BODYSTR:
+                       BodySeen = 1;
+                       XPUT(">");
+                       Val   = va_arg(arg_ptr, char*);
+                       VLen  = va_arg(arg_ptr, long);
+                       XPutBody(Val, VLen);
+                       break;
+               case TYPE_ARGEND:
+                       Finished = 1;
+                       break;
                }
-               if ((len + 6) > bufsiz) {
-                       return(buf);
+       }
+       if (Flags == XCLOSED)
+       {
+               if (BodySeen)
+               {
+                       XPUT("</");
+                       XPut(Token, tlen);
+                       XPUT(">");
+               }
+               else
+               {
+                       XPUT("></");
+                       XPut(Token, tlen);
+                       XPUT(">");
                }
        }
-       return(buf);
+       else
+               XPUT(">");
+       va_end(arg_ptr);
 }
 
+#ifdef HAVE_XML_STOPPARSER
+/* Stop the parser if an entity declaration is hit. */
+static void xmpp_entity_declaration(void *userData, const XML_Char *entityName,
+                               int is_parameter_entity, const XML_Char *value,
+                               int value_length, const XML_Char *base,
+                               const XML_Char *systemId, const XML_Char *publicId,
+                               const XML_Char *notationName
+) {
+       XMPPM_syslog(LOG_WARNING, "Illegal entity declaration encountered; stopping parser.");
+       XML_StopParser(XMPP->xp, XML_FALSE);
+}
+#endif
 
 /*
  * 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\"?>");
-
-       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("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
 
+       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>");
+            "<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
-
+*/
        if (!CC->logged_in) {
                /* If we're not logged in yet, offer SASL as our feature set */
                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 */
 }
@@ -245,25 +271,6 @@ void xmpp_start_bind(void *data, const char *supplied_el, const char **attr)
        XMPP->bind_requested = 1;
 }
 
-void xmpp_start_iq(void *data, const char *supplied_el, const char **attr)
-{
-       int i;
-       for (i=0; attr[i] != NULL; i+=2) {
-               if (!strcasecmp(attr[i], "type")) {
-                       safestrncpy(XMPP->iq_type, attr[i+1], sizeof XMPP->iq_type);
-               }
-               else if (!strcasecmp(attr[i], "id")) {
-                       safestrncpy(XMPP->iq_id, attr[i+1], sizeof XMPP->iq_id);
-               }
-               else if (!strcasecmp(attr[i], "from")) {
-                       safestrncpy(XMPP->iq_from, attr[i+1], sizeof XMPP->iq_from);
-               }
-               else if (!strcasecmp(attr[i], "to")) {
-                       safestrncpy(XMPP->iq_to, attr[i+1], sizeof XMPP->iq_to);
-               }
-       }
-}
-
 void xmpp_start_auth(void *data, const char *supplied_el, const char **attr)
 {
        int i;
@@ -294,21 +301,75 @@ void xmpp_start_html(void *data, const char *supplied_el, const char **attr)
 
 void xmpp_xml_start(void *data, const char *supplied_el, const char **attr)
 {
-       char el[256];
-       long newlen;
+       HashList *ThisNamespace = NULL;
+       const char *pToken;
+       const char *pch;
+       const char *NS = NULL;
+       long NSLen;
        long len;
-       char *sep = NULL;
        void *pv;
        
        /* Axe the namespace, we don't care about it */
-       newlen = len = safestrncpy(el, supplied_el, sizeof el);
-       while (sep = strchr(el, ':'), sep)
+       pToken = supplied_el;
+       pch = strchr(pToken, ':');
+       while (pch != NULL)
        {
-               newlen -= ++sep - el;
-               memmove(el, sep, newlen + 1);
-               len = newlen;
+               pToken = pch;
+               pch = strchr(pToken  + 1, ':');
        }
 
+       if (*pToken == ':')
+       {
+               NS = supplied_el;
+               NSLen = pToken - supplied_el;
+               if (GetHash(XMPP_NameSpaces, NS, NSLen, &pv))
+               {
+                       ThisNamespace = pv;
+
+               }
+               
+               pToken ++;
+       }
+
+       len = strlen(pToken);
+
+
+       if (ThisNamespace != NULL)
+       {
+               if (GetHash(ThisNamespace, pToken, len, &pv))
+               {
+                       TokenHandler *th;
+                       void *value;
+                       long i = 0;
+
+                       th = (TokenHandler*) pv;
+                       value = th->GetToken();
+
+                       while (attr[i] != NULL)
+                       {
+
+                               if (GetHash(th->Properties, attr[i], strlen(attr[i]), &pv))
+                               {
+                                       PropertyHandler* ph = pv;
+                                       char *val;
+                                       StrBuf **pVal;
+                                       long len;
+
+                                       len = strlen(attr[i+1]);
+                                       val = value;
+                                       val += ph->offset;
+                                       pVal = (StrBuf**) val;
+                                       if (*pVal != NULL)
+                                               StrBufPlain(*pVal, attr[i+1], len);
+                                       else
+                                               *pVal = NewStrBufPlain(attr[i+1], len);
+                               }
+                               i+=2;
+                       }
+                       return;
+               }
+
+       }
        /*
        XMPP_syslog(LOG_DEBUG, "XMPP ELEMENT START: <%s>\n", el);
        for (i=0; attr[i] != NULL; i+=2) {
@@ -316,13 +377,12 @@ void xmpp_xml_start(void *data, const char *supplied_el, const char **attr)
        }
        uncomment for more verbosity */
 
-       if (GetHash(XMPP_StartHandlers, el, len, &pv))
+       if (GetHash(XMPP_StartHandlers, pToken, len, &pv))
        {
                xmpp_handler *h;
                h = (xmpp_handler*) pv;
                h->Handler(data, supplied_el, attr);
        }
-
 }
 
 void xmpp_end_resource(void *data, const char *supplied_el, const char **attr)
@@ -355,32 +415,38 @@ 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(ChrPtr(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, 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 (StrLength(Xmpp->IQ.from) > 0) {
+                               XPUT("to=\"");
+                               XPutSProp(Xmpp->IQ.from);
+                               XPUT("\" ");
                        }
-                       if (!IsEmptyStr(XMPP->iq_to)) {
-                               cprintf("from=\"%s\" ", xmlesc(xmlbuf, XMPP->iq_to, sizeof xmlbuf));
+                       if (StrLength(Xmpp->IQ.to)>0) {
+                               XPUT("from=\"");
+                               XPutSProp(Xmpp->IQ.to);
+                               XPUT("\" ");
                        }
-                       cprintf("id=\"%s\"/>", xmlesc(xmlbuf, XMPP->iq_id, sizeof xmlbuf));
+                       XPUT("id=\"");
+                       XPutSProp(Xmpp->IQ.id);
+                       XPUT("\"/>");
                }
 
                /*
@@ -388,17 +454,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=\"");
+                       XPutSProp(Xmpp->IQ.id);
+                       XPUT("\">"
+                            "<error code=\"503\" type=\"cancel\">"
+                            "<service-unavailable xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"/>"
+                            "</error>"
+                            "</iq>");
                }
        }
 
@@ -406,15 +473,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(ChrPtr(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 +489,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)
+               && (StrLength(Xmpp->IQ.id)>0)
+               && (!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=\"");
+               XPutSProp(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=\"");
+               XPutSProp(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=\"");
+               XPutSProp(Xmpp->IQ.id);
+               XPUT("\">");
+               XPUT("<error>Don't know howto do '");
+               XPutBody(SKEY(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;
+       FlushStrBuf(Xmpp->IQ.id);
+       FlushStrBuf(Xmpp->IQ.from);
+       FlushStrBuf(Xmpp->IQ.to);
+       FlushStrBuf(Xmpp->IQ.type);
+       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 +560,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 +575,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 +583,12 @@ 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'/>");
+       XUnbuffer();
        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,27 +602,31 @@ 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;
 }
 
 void xmpp_xml_end(void *data, const char *supplied_el)
 {
-       char el[256];
+       const char *pToken;
+       const char *pch;
        long len;
-       long newlen;
-       char *sep = NULL;
        void *pv;
 
        /* Axe the namespace, we don't care about it */
-       newlen = len = safestrncpy(el, supplied_el, sizeof el);
-       while (sep = strchr(el, ':'), sep) {
-
-               newlen -= ++sep - el;
-               memmove(el, sep, newlen + 1);
-               len = newlen;
+       pToken = supplied_el;
+       pch = strchr(pToken, ':');
+       while (pch != NULL)
+       {
+               pToken = pch;
+               pch = strchr(pToken  + 1, ':');
        }
 
+       if (*pToken == ':')
+               pToken ++;
+
+       len = strlen(pToken);
+
        /*
        XMPP_syslog(LOG_DEBUG, "XMPP ELEMENT END  : <%s>\n", el);
        if (XMPP->chardata_len > 0) {
@@ -566,7 +634,7 @@ void xmpp_xml_end(void *data, const char *supplied_el)
        }
        uncomment for more verbosity */
 
-       if (GetHash(XMPP_EndHandlers, el, len, &pv))
+       if (GetHash(XMPP_EndHandlers, pToken, len, &pv))
        {
                xmpp_handler *h;
                h = (xmpp_handler*) pv;
@@ -574,7 +642,7 @@ void xmpp_xml_end(void *data, const char *supplied_el)
        }
        else
        {
-               XMPP_syslog(LOG_DEBUG, "Ignoring unknown tag <%s>\n", el);
+               XMPP_syslog(LOG_DEBUG, "Ignoring unknown tag <%s>\n", pToken);
        }
 
        XMPP->chardata_len = 0;
@@ -619,7 +687,10 @@ void xmpp_cleanup_function(void) {
                        free(XMPP->message_body);
                }
        }
+       free_buf_iq(&XMPP->IQ);
+
        XML_ParserFree(XMPP->xp);
+       FreeStrBuf(&XMPP->OutBuf);
        free(XMPP);
 }
 
@@ -634,7 +705,7 @@ void xmpp_greeting(void) {
        CC->session_specific_data = malloc(sizeof(citxmpp));
        memset(XMPP, 0, sizeof(citxmpp));
        XMPP->last_event_processed = queue_event_seq;
-
+       XMPP->OutBuf = NewStrBufPlain(NULL, SIZ);
        /* XMPP does not use a greeting, but we still have to initialize some things. */
 
        XMPP->xp = XML_ParserCreateNS("UTF-8", ':');
@@ -660,6 +731,7 @@ void xmpp_greeting(void) {
 #endif
 
        CC->can_receive_im = 1;         /* This protocol is capable of receiving instant messages */
+       XUnbuffer();
 }
 
 
@@ -680,6 +752,7 @@ void xmpp_command_loop(void) {
                CC->kill_me = KILLME_CLIENT_DISCONNECTED;
        }
        FreeStrBuf(&stream_input);
+       XUnbuffer();
 }
 
 
@@ -713,7 +786,6 @@ void LogXMPPSrvDebugEnable(const int n)
        XMPPSrvDebugEnable = n;
 }
 const char *CitadelServiceXMPP="XMPP";
-extern void xmpp_cleanup_events(void);
 
 
 
@@ -745,6 +817,87 @@ void AddXMPPEndHandler(const char *key,
        Put(XMPP_EndHandlers, key, len, h, NULL);
 }
 
+void HFreePropertyHandler(void *FreeMe)
+{
+       free(FreeMe);
+}
+
+void HDeleteTokenHandler(void *FreeMe)
+{
+       TokenHandler *th = (TokenHandler *) FreeMe;
+       DeleteHash(&th->Properties);
+       free(th);
+}
+
+void XMPP_RegisterTokenProperty(const char *NS, long NSLen,
+                               const char *Token, long TLen,
+                               const char *Property, long PLen,
+                               GetTokenDataFunc GetToken,
+                               long offset)
+{
+       void *pv;
+       HashList *ThisNamespace = NULL;
+       PropertyHandler *h;
+       TokenHandler *th;
+
+       h = (PropertyHandler*) malloc(sizeof(PropertyHandler));
+       h->NameSpace = NS;
+       h->NameSpaceLen = NSLen;
+       h->Token = Token;
+       h->TokenLen = TLen;
+       h->Property = Property;
+       h->PropertyLen = PLen;
+       h->offset = offset;
+
+       if (!GetHash(XMPP_SupportedNamespaces, NS, NSLen, &pv))
+       {
+               Put(XMPP_SupportedNamespaces, NS, NSLen, NewStrBufPlain(NS, NSLen), HFreeStrBuf);
+       }
+               
+       
+       if (GetHash(XMPP_NameSpaces, NS, NSLen, &pv))
+       {
+               ThisNamespace = pv;
+       }
+       else
+       {
+               ThisNamespace = NewHash(1, NULL);
+               Put(XMPP_NameSpaces, NS, NSLen, ThisNamespace, HDeleteHash);
+       }
+
+       if (GetHash(ThisNamespace, Token, TLen, &pv))
+       {
+               th = pv;
+       }
+       else
+       {
+               th = (TokenHandler*) malloc (sizeof(TokenHandler));
+               th->GetToken = GetToken;
+               th->Properties = NewHash(1, NULL);
+               Put(ThisNamespace, Token, TLen, th, HDeleteTokenHandler);
+       }
+
+
+       if (PLen > 0)
+               Put(th->Properties, Property, PLen, h, HFreePropertyHandler);
+       /*
+       if (!GetHash(FlatToken, Token, TLen, &pv))
+       {
+               // todo mark pv as non uniq
+               Put(FlatToken, Token, TLen, ThisToken, reference_free_handler);
+       }       
+       */
+}
+
+void xmpp_cleanup(void)
+{
+       DeleteHash(&XMPP_StartHandlers);
+       DeleteHash(&XMPP_EndHandlers);
+       DeleteHash(&XMPP_SupportedNamespaces);
+       DeleteHash(&XMPP_NameSpaces);
+       DeleteHash(&FlatToken);
+}
+
 CTDL_MODULE_INIT(xmpp)
 {
        if (!threading) {
@@ -758,6 +911,9 @@ CTDL_MODULE_INIT(xmpp)
 
                XMPP_StartHandlers = NewHash(1, NULL);
                XMPP_EndHandlers = NewHash(1, NULL);
+               XMPP_NameSpaces = NewHash(1, NULL);
+               XMPP_SupportedNamespaces = NewHash(1, NULL);
+               FlatToken = NewHash(1, NULL);
 
                AddXMPPEndHandler(HKEY("resource"),      xmpp_end_resource, 0);
                AddXMPPEndHandler(HKEY("username"),      xmpp_end_username, 0);
@@ -765,19 +921,15 @@ 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);
-               AddXMPPStartHandler(HKEY("iq"),         xmpp_start_iq, 0);
                AddXMPPStartHandler(HKEY("auth"),       xmpp_start_auth, 0);
                AddXMPPStartHandler(HKEY("message"),    xmpp_start_message, 0);
                AddXMPPStartHandler(HKEY("html"),       xmpp_start_html, 0);
@@ -789,10 +941,11 @@ CTDL_MODULE_INIT(xmpp)
                 CtdlRegisterSessionHook(xmpp_logout_hook, EVT_LOGOUT, PRIO_LOGOUT + 90);
                 CtdlRegisterSessionHook(xmpp_login_hook, EVT_UNSTEALTH, PRIO_UNSTEALTH + 1);
                 CtdlRegisterSessionHook(xmpp_logout_hook, EVT_STEALTH, PRIO_STEALTH + 1);
-               CtdlRegisterCleanupHook(xmpp_cleanup_events);
-
+               CtdlRegisterCleanupHook(xmpp_cleanup);
        }
 
        /* return our module name for the log */
        return "xmpp";
 }
+
+
index faebc3615aea668b6df7a5d153318e2e3ed4b552..ba19e7af26265f92f62c8edb615b3e3ad811fa63 100644 (file)
  *  
  */
 
+#include "xmpp_xmacros.h"
+#include "xmpp_util.h"
+
+
 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;
@@ -25,10 +30,8 @@ typedef struct _citxmpp {                    /* Information about the current session */
        char client_jid[256];           /* "full JID" of the client */
        int last_event_processed;
 
-       char iq_type[256];              /* for <iq> stanzas */
-       char iq_id[256];
-       char iq_from[256];
-       char iq_to[256];
+       TheToken_iq IQ;
+
        char iq_client_username[256];   /* username requested by the client (NON SASL ONLY) */
        char iq_client_password[256];   /* password requested by the client (NON SASL ONLY) */
        char iq_client_resource[256];   /* resource name requested by the client */
@@ -56,7 +59,6 @@ struct xmpp_event {
        int session_which_generated_this_event;
 };
 
-extern struct xmpp_event *xmpp_queue;
 extern int queue_event_seq;
 
 enum {
@@ -79,15 +81,14 @@ void xmpp_command_loop(void);
 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_query_namespace(TheToken_iq *iq, char *);
 void xmpp_output_incoming_messages(void);
 void xmpp_queue_event(int, char *);
 void xmpp_process_events(void);
 void xmpp_presence_notify(char *, int);
 void xmpp_roster_item(struct CitContext *);
 void xmpp_send_message(char *, char *);
-void xmpp_non_sasl_authenticate(char *, char *, char *, char *);
+void xmpp_non_sasl_authenticate(StrBuf *IQ_id, char *, char *, char *);
 void xmpp_massacre_roster(void);
 void xmpp_delete_old_buddies_who_no_longer_exist_from_the_client_roster(void);
 int xmpp_is_visible(struct CitContext *from, struct CitContext *to_whom);
@@ -105,3 +106,17 @@ extern int XMPPSrvDebugEnable;
        DBGLOG(LEVEL) syslog(LEVEL,             \
                             "XMPP: " 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);
+
+
+
+
diff --git a/citadel/modules/xmpp/token.def b/citadel/modules/xmpp/token.def
new file mode 100644 (file)
index 0000000..26345c6
--- /dev/null
@@ -0,0 +1,32 @@
+
+#define NAMESPACE_iq "jabber:client"
+TOKEN(iq,
+      {
+             STRPROP(iq, type);
+             STRPROP(iq, id);
+             STRPROP(iq, from);
+             STRPROP(iq, to);
+      })
+
+
+#define NAMESPACE_piq "bub"
+
+TOKEN(piq,
+      {
+             STRPROP(piq, type);
+             STRPROP(piq, id);
+             STRPROP(piq, from);
+             STRPROP(piq, to);
+      })
+
+#define NAMESPACE_message "jabber:client"
+TOKEN(message,
+       {
+               STRPROP(message, to);
+               STRPROP(message, type);
+               STRPROP(message, id);
+               PAYLOAD(message, body);
+       })
+
+
+// <message type='chat' id='purplef5a7ed34' to='testuser@blarg.potzblitz.outgesourced.org'><active xmlns='http://jabber.org/protocol/chatstates'/><body>gci</body></message>
index 8b8b43f6b8d87706edfed58238c8ccf426660946..b2e2dadf4869736fa5bc15a409f77505842d7917 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)
-               );
+               XPrint(HKEY("message"), 0,
+                      XCPROPERTY("type", "chat"),
+                      XPROPERTY("to", Xmpp->client_jid, strlen(Xmpp->client_jid)),
+                      XPROPERTY("from", ptr->sender_email, strlen(ptr->sender_email)),
+                      TYPE_ARGEND);
+
                if (ptr->text != NULL) {
                        striplt(ptr->text);
-                       cprintf("<body>%s</body>", xmlesc(xmlbuf1, ptr->text, sizeof xmlbuf1));
+                       XPrint(HKEY("body"), XCLOSED,
+                              XBODY(ptr->text, strlen(ptr->text)),
+                              TYPE_ARGEND);
                        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 +117,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..9191f8f65561b413cc28c4b7e2938e360be6f105 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));
+       XPrint(HKEY("presence"),
+              XPROPERTY("from", presence_jid, strlen(presence_jid)),
+              XPROPERTY("to",  XMPP->client_jid, strlen(XMPP->client_jid)),
+              TYPE_ARGEND);
 }
 
 
@@ -95,8 +95,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 +123,20 @@ 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;
+       char Buf[64];
+       long blen;
 
        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)
-       );
+       XPrint(HKEY("presence"), XCLOSED,
+              XCPROPERTY("type", "unavailable"),
+              XPROPERTY("from", presence_jid, strlen(presence_jid)),
+              XPROPERTY("to",  XMPP->client_jid, strlen(XMPP->client_jid)),
+              TYPE_ARGEND);
 
        /*
         * Setting the "aggressively" flag also sends an "unsubscribed" presence update.
@@ -141,26 +145,40 @@ 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)
-               );
+               XPrint(HKEY("presence"), XCLOSED,
+                      XCPROPERTY("type", "unsubscribed"),
+                      XPROPERTY("from", presence_jid, strlen(presence_jid)),
+                      XPROPERTY("to",  XMPP->client_jid, strlen(XMPP->client_jid)),
+                      TYPE_ARGEND);
        }
 
        // FIXME ... we should implement xmpp_indicate_nonpresence so we can use it elsewhere
 
+       blen = snprintf(Buf, sizeof(Buf), "unbuddy_%x", ++unsolicited_id);
+
        /* 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>"
+       XPrint(HKEY("iq"), 0,
+              XCPROPERTY("type", "result"),
+              XPROPERTY("from", CCC->cs_inet_email, strlen(CCC->cs_inet_email)),
+              XPROPERTY("to",  XMPP->client_jid, strlen(XMPP->client_jid)),
+              XPROPERTY("id",  Buf, blen),
+              TYPE_ARGEND);
+
+       XPrint(HKEY("query"), 0,
+              XCPROPERTY("xmlns", "jabber:iq:roster"),
+              TYPE_ARGEND);
+
+       XPrint(HKEY("item"), 0,
+              XCPROPERTY("subscription", "remove"),
+              XPROPERTY("jid", presence_jid, strlen(presence_jid)),
+              TYPE_ARGEND);
+
+       XPrint(HKEY("group"), XCLOSED,
+              XCFGBODY(c_humannode),
+              TYPE_ARGEND);
+       XPUT("</item>"
+            "</query>"
+            "</iq>"
        );
 }
 
@@ -198,16 +216,28 @@ void xmpp_presence_notify(char *presence_jid, int event_type) {
                    visible_sessions, presence_jid, CC->cs_pid);
 
        if ( (event_type == XMPP_EVT_LOGIN) && (visible_sessions == 1) ) {
+               long blen;
+               char Buf[64];
 
                XMPP_syslog(LOG_DEBUG, "Telling session %d that <%s> logged in\n",
                            CC->cs_pid, presence_jid);
 
                /* 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\">");
+
+               blen = snprintf(Buf, sizeof(Buf), "unsolicited_%x", ++unsolicited_id);
+
+               XPrint(HKEY("iq"), 0,
+                      XCPROPERTY("type", "result"),
+                      XPROPERTY("id", Buf, blen),
+                      TYPE_ARGEND);
+
+               XPrint(HKEY("query"), 0,
+                      XCPROPERTY("xmlns", "jabber:iq:roster"),
+                      TYPE_ARGEND);
+
                xmpp_roster_item(&cptr[which_cptr_is_relevant]);
-               cprintf("</query></iq>");
+               XPUT("</query></iq>");
 
                /* Transmit presence information */
                xmpp_indicate_presence(presence_jid);
@@ -410,3 +440,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..e7fcc0c8a98bba7a336e646ec46fc17a8005bbb2 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)
+{
+       struct CitContext *CCC=CC;
+
+       XPrint(HKEY("item"), 0,
+              XCPROPERTY("subscription", "both"),
+              XPROPERTY("jid",  CCC->cs_inet_email, strlen(CCC->cs_inet_email)),
+              XPROPERTY("name", cptr->user.fullname, strlen(cptr->user.fullname)),
+              TYPE_ARGEND);
+
+       XPrint(HKEY("group"), XCLOSED,
+              XCFGBODY(c_humannode),
+              TYPE_ARGEND);
+
+       XPUT("</item>");
 }
 
 /* 
@@ -83,7 +88,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 +99,7 @@ void xmpp_iq_roster_query(void)
                }
                free (cptr);
        }
-       cprintf("</query>");
+       XPUT("</query>");
 }
 
 
@@ -107,12 +112,17 @@ xmpp_query_namespace(purple5b5c1e5a, , vcard-temp:query)
  *
  */
 
-void xmpp_query_namespace(char *iq_id, char *iq_from, char *iq_to, char *query_xmlns)
+void xmpp_query_namespace(TheToken_iq *IQ/*char *iq_id, char *iq_from, char *iq_to*/, char *query_xmlns)
 {
        int supported_namespace = 0;
        int roster_query = 0;
-       char xmlbuf[256];
-
+       const char *TypeStr;
+       long TLen;
+       ConstStr Type[] = {
+               {HKEY("result")},
+               {HKEY("error")}
+       };
+       
        /* 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
         * they are handled.
@@ -124,21 +134,25 @@ void xmpp_query_namespace(char *iq_id, char *iq_from, char *iq_to, char *query_x
                supported_namespace = 1;
        }
 
-       XMPP_syslog(LOG_DEBUG, "xmpp_query_namespace(%s, %s, %s, %s)\n", iq_id, iq_from, iq_to, query_xmlns);
+       XMPP_syslog(LOG_DEBUG, "xmpp_query_namespace(%s, %s, %s, %s)\n", ChrPtr(IQ->id), ChrPtr(IQ->from), ChrPtr(IQ->to), query_xmlns);
 
        /*
         * Beginning of query result.
         */
        if (supported_namespace) {
-               cprintf("<iq type=\"result\" ");
+               TypeStr = Type[0].Key;
+               TLen    = Type[0].len;
        }
        else {
-               cprintf("<iq type=\"error\" ");
-       }
-       if (!IsEmptyStr(iq_from)) {
-               cprintf("to=\"%s\" ", xmlesc(xmlbuf, iq_from, sizeof xmlbuf));
+               TypeStr = Type[1].Key;
+               TLen    = Type[1].len;
        }
-       cprintf("id=\"%s\">", xmlesc(xmlbuf, iq_id, sizeof xmlbuf));
+
+       XPrint(HKEY("iq"), 0,
+              XPROPERTY("type", TypeStr, TLen),
+              XSPROPERTY("to",  IQ->from),
+              XSPROPERTY("id",   IQ->id),
+              TYPE_ARGEND);
 
        /*
         * Is this a query we know how to handle?
@@ -150,9 +164,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 +180,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 8cb5662d89f846728c2b53140692325e18553b79..024336df871e7de743e3bebd19bbcbba902b45f9 100644 (file)
@@ -57,6 +57,7 @@
 #include "serv_xmpp.h"
 
 int queue_event_seq = 0;
+struct xmpp_event *xmpp_queue = NULL;
 
 void xmpp_queue_event(int event_type, char *email_addr) {
 
@@ -162,3 +163,14 @@ void xmpp_cleanup_events(void)
         end_critical_section(S_XMPP_QUEUE);
 
 }
+
+CTDL_MODULE_INIT(xmpp_queue)
+{
+       if (!threading) {
+
+               CtdlRegisterCleanupHook(xmpp_cleanup_events);
+       }
+
+       /* return our module name for the log */
+       return "xmpp_queue";
+}
index 393174dce18b2cf78901e61aa1955743d84f08fc..ba6dba137446d4705e18a1db083e6e4a455f7478 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>");
        }
 }
 
@@ -154,9 +154,8 @@ void xmpp_sasl_auth(char *sasl_auth_mech, char *authstring) {
 /*
  * Non-SASL authentication
  */
-void xmpp_non_sasl_authenticate(char *iq_id, char *username, char *password, char *resource) {
+void xmpp_non_sasl_authenticate(StrBuf *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,23 @@ 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 */
+                       XPrint(HKEY("iq"), XCLOSED,
+                              XCPROPERTY("type", "result"),
+                              XSPROPERTY("ID", IQ_id),
+                              TYPE_ARGEND);
+                              /* 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>"
+       XPrint(HKEY("iq"), 0,
+              XCPROPERTY("type", "error"),
+              XSPROPERTY("ID", IQ_id),
+              TYPE_ARGEND);
+       XPUT("<error code=\"401\" type=\"auth\">"
+            "<not-authorized xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"/>"
+            "</error>"
+            "</iq>"
        );
 }
diff --git a/citadel/modules/xmpp/xmpp_util.h b/citadel/modules/xmpp/xmpp_util.h
new file mode 100644 (file)
index 0000000..1485c77
--- /dev/null
@@ -0,0 +1,49 @@
+typedef void* (*GetTokenDataFunc)(void);
+
+typedef struct __TokenHandler {
+       HashList *Properties;
+       GetTokenDataFunc GetToken;
+}TokenHandler;
+
+typedef struct __PropertyHandler {
+       const char *NameSpace;
+       long NameSpaceLen;
+       const char *Token;
+       long TokenLen;
+       const char *Property;
+       long PropertyLen;
+       long offset;
+} PropertyHandler;
+
+void XUnbuffer(void);
+void XPutBody(const char *Str, long Len);
+void XPutProp(const char *Str, long Len);
+#define XPutSProp(STR) XPutProp(ChrPtr(STR), StrLength(STR))
+void XPut(const char *Str, long Len);
+#define XPUT(CONSTSTR) XPut(CONSTSTR, sizeof(CONSTSTR) -1)
+
+void XPrintf(const char *Format, ...);
+
+#define XCLOSED (1<<0)
+void XPrint(const char *Token, long tlen,
+           int Flags,
+           ...);
+
+#define TYPE_STR 1
+#define TYPE_OPTSTR 2
+#define TYPE_INT 3
+#define TYPE_BODYSTR 4
+#define TYPE_ARGEND 5
+#define XPROPERTY(NAME, VALUE, VLEN) TYPE_STR, NAME, sizeof(NAME)-1, VALUE, VLEN
+#define XSPROPERTY(NAME, VALUE) TYPE_STR, NAME, sizeof(NAME)-1, ChrPtr(VALUE), StrLength(VALUE)
+#define XOPROPERTY(NAME, VALUE, VLEN) TYPE_OPTSTR, NAME, sizeof(NAME)-1, VALUE, VLEN
+#define XCPROPERTY(NAME, VALUE) TYPE_STR, NAME, sizeof(NAME)-1, VALUE, sizeof(VALUE) - 1
+#define XIPROPERTY(NAME, LVALUE) TYPE_INT, NAME, SIZEOF(NAME)-1
+#define XBODY(VALUE, VLEN) TYPE_BODYSTR, VALUE, VLEN
+#define XCFGBODY(WHICH) TYPE_BODYSTR, config.WHICH, configlen.WHICH
+
+void XMPP_RegisterTokenProperty(const char *NS, long NSLen,
+                               const char *Token, long TLen,
+                               const char *Property, long PLen,
+                               GetTokenDataFunc GetToken,
+                               long offset);
diff --git a/citadel/modules/xmpp/xmpp_xmacros.c b/citadel/modules/xmpp/xmpp_xmacros.c
new file mode 100644 (file)
index 0000000..3ef9f31
--- /dev/null
@@ -0,0 +1,127 @@
+#include <stdio.h>
+#include <expat.h>
+#include <libcitadel.h>
+#include "ctdl_module.h"
+#include "serv_xmpp.h"
+
+void *GetToken_iq(void)
+{
+       return &XMPP->IQ;
+}
+void *GetToken_piq(void)
+{
+       return NULL;
+}
+
+void *GetToken_message(void)
+{
+       return NULL;
+}
+
+
+#define STRPROP(STRUCTNAME, NAME)                                      \
+       if (StrLength(pdata->NAME) > 0)                                 \
+       {                                                               \
+       XPut(#NAME, sizeof(#NAME) - 1);                                 \
+       XPut("=\"", 2);                                                 \
+       XPutProp(SKEY(pdata->NAME));                                    \
+       XPut("\" ", 2);                                                 \
+       }
+
+#define PAYLOAD(STRUCTNAME, NAME)                                      \
+       XPrint(#NAME, sizeof(#NAME) -1,                                 \
+              XCLOSED,                                                 \
+              TYPE_BODYSTR, SKEY(pdata->NAME),                         \
+              TYPE_ARGEND);
+
+#define THENAMESPACE(STRUCTNAME, NAME)                                 \
+       XPut(#NAME, sizeof(#NAME) - 1);                                 \
+       XPut("=\"", 2);                                                 \
+       XPutProp(NAMESPACE_##STRUCTNAME,                                \
+                sizeof(NAMESPACE_##STRUCTNAME)-1);                     \
+       XPut("\" ", 2);                                                 
+
+#define TOKEN(NAME, STRUCT)                                            \
+       void serialize_##NAME(TheToken_##NAME *pdata, int Close)        \
+       {                                                               \
+       XPUT("<");                                                      \
+       XPut(#NAME, sizeof(#NAME));                                     \
+       XPUT(" ");                                                      \
+       STRUCT ;                                                        \
+       XPUT(">");                                                      \
+       if (Close)                                                      \
+       {                                                               \
+               XPut("</", 2);                                          \
+               XPut(#NAME, sizeof(#NAME));                             \
+               XPut(">", 1);                                           \
+       }                                                               \
+       }
+
+#include "token.def"
+#undef STRPROP
+#undef PAYLOAD
+#undef TOKEN
+
+
+#define STRPROP(STRUCTNAME, NAME)                                      \
+       FreeStrBuf(&pdata->NAME);
+
+#define PAYLOAD(STRUCTNAME, NAME)                                      \
+       FreeStrBuf(&pdata->NAME);
+
+#define TOKEN(NAME, STRUCT)                                            \
+       void free_buf_##NAME(TheToken_##NAME *pdata)                    \
+       {                                                               \
+               STRUCT ;                                                \
+       }
+
+#include "token.def"
+#undef STRPROP
+#undef PAYLOAD
+#undef TOKEN
+
+#define TOKEN(NAME, STRUCT)                                            \
+       void free_##NAME(TheToken_##NAME *pdata)                        \
+       {                                                               \
+               free_buf_##NAME(pdata);                                 \
+               free(pdata);                                            \
+       }
+
+#include "token.def"
+#undef STRPROP
+#undef TOKEN
+
+
+
+CTDL_MODULE_INIT(xmpp_xmacros)
+{
+       if (!threading) {
+#define STRPROP(TOKENNAME, PROPERTYNAME)                               \
+               long offset##PROPERTYNAME =                             \
+                       offsetof(TheToken_##TOKENNAME, PROPERTYNAME);   \
+               XMPP_RegisterTokenProperty(                             \
+                       NAMESPACE_##TOKENNAME,                          \
+                       sizeof(NAMESPACE_##TOKENNAME)-1,                \
+                       #TOKENNAME, sizeof(#TOKENNAME)-1,               \
+                       #PROPERTYNAME, sizeof(#PROPERTYNAME)-1,         \
+                       GetToken_##TOKENNAME,                           \
+                       offset##PROPERTYNAME);
+#define PAYLOAD(TOKENNAME, PROPERTYNAME)                               \
+               long offset##PROPERTYNAME =                             \
+                       offsetof(TheToken_##TOKENNAME, PROPERTYNAME);   \
+               XMPP_RegisterTokenProperty(                             \
+                       NAMESPACE_##TOKENNAME,                          \
+                       sizeof(NAMESPACE_##TOKENNAME)-1,                \
+                       #TOKENNAME, sizeof(#TOKENNAME)-1,               \
+                       NULL, 0,                                        \
+                       GetToken_##TOKENNAME,                           \
+                       offset##PROPERTYNAME);
+#define TOKEN(NAME, STRUCT) STRUCT
+#include "token.def"
+#undef STRPROP
+#undef TOKEN
+       }
+
+       /* return our module name for the log */
+       return "xmpp_xmacros";
+}
diff --git a/citadel/modules/xmpp/xmpp_xmacros.h b/citadel/modules/xmpp/xmpp_xmacros.h
new file mode 100644 (file)
index 0000000..f7427b8
--- /dev/null
@@ -0,0 +1,39 @@
+
+/*
+ * define the structures for one token each
+ * typename: TheToken_<Tokenname>
+ */
+#define PAYLOAD(STRUCTNAME, NAME) StrBuf *NAME;int encoding_##NAME;
+#define STRPROP(STRUCTNAME, NAME) StrBuf *NAME;
+#define TOKEN(NAME, STRUCT) typedef struct __##NAME    \
+       STRUCT                                          \
+       TheToken_##NAME;
+#include "token.def"
+#undef STRPROP
+#undef PAYLOAD
+#undef TOKEN
+
+
+/*
+ * forward declarations for freeing the members of one struct instance
+ # name: free_buf_<Tokenname>
+ */
+
+#define TOKEN(NAME, STRUCT)                                            \
+       void free_buf_##NAME(TheToken_##NAME *pdata);
+#include "token.def"
+#undef STRPROP
+#undef PAYLOAD
+#undef TOKEN
+
+/*
+ * forward declarations, freeing structs and member. 
+ * name: free_<Tokenname>
+ */
+#define TOKEN(NAME, STRUCT)                                            \
+       void free_##NAME(TheToken_##NAME *pdata);
+
+#include "token.def"
+#undef STRPROP
+#undef PAYLOAD
+#undef TOKEN
index 776680b6df7cd5dd04f16bd04979fe23cf07cff6..21c1aabb41bb16ff61581832b76673965439f7c0 100644 (file)
@@ -1129,6 +1129,13 @@ struct CtdlMessage *CtdlFetchMessage(long msgnum, int with_body)
        ret->cm_anon_type = *mptr++;    /* Anon type byte */
        ret->cm_format_type = *mptr++;  /* Format type byte */
 
+
+       if (dmsgtext->ptr[dmsgtext->len - 1] != '\0')
+       {
+               MSG_syslog(LOG_ERR, "CtdlFetchMessage(%ld, %d) Forcefully terminating message!!\n", msgnum, with_body);
+               dmsgtext->ptr[dmsgtext->len - 1] = '\0';
+       }
+
        /*
         * The rest is zero or more arbitrary fields.  Load them in.
         * We're done when we encounter either a zero-length field or
@@ -1158,7 +1165,7 @@ struct CtdlMessage *CtdlFetchMessage(long msgnum, int with_body)
        if ( (CM_IsEmpty(ret, eMesageText)) && (with_body) ) {
                dmsgtext = cdb_fetch(CDB_BIGMSGS, &msgnum, sizeof(long));
                if (dmsgtext != NULL) {
-                       CM_SetAsField(ret, eMesageText, &dmsgtext->ptr, dmsgtext->len);
+                       CM_SetAsField(ret, eMesageText, &dmsgtext->ptr, dmsgtext->len - 1);
                        cdb_free(dmsgtext);
                }
        }
@@ -3429,6 +3436,7 @@ struct CtdlMessage *CtdlMakeMessageLen(
        }
        StrBufRFC2047encode(&FakeEncAuthor, FakeAuthor);
        CM_SetAsFieldSB(msg, eAuthor, &FakeEncAuthor);
+       FreeStrBuf(&FakeAuthor);
 
        if (CCC->room.QRflags & QR_MAILBOX) {           /* room */
                CM_SetField(msg, eOriginalRoom, &CCC->room.QRname[11], strlen(&CCC->room.QRname[11]));
@@ -3489,9 +3497,10 @@ struct CtdlMessage *CtdlMakeMessageLen(
                CM_SetField(msg, eMesageText, preformatted_text, textlen);
        }
        else {
-               preformatted_text = CtdlReadMessageBody(HKEY("000"), config.c_maxmsglen, NULL, 0, 0);
-               if (preformatted_text != NULL) {
-                       CM_SetField(msg, eMesageText, preformatted_text, strlen(preformatted_text));
+               StrBuf *MsgBody;
+               MsgBody = CtdlReadMessageBodyBuf(HKEY("000"), config.c_maxmsglen, NULL, 0, 0);
+               if (MsgBody != NULL) {
+                       CM_SetAsFieldSB(msg, eMesageText, &MsgBody);
                }
        }
 
index 4e8500293205b54de9f6bccdc8bcbc486d4f34a6..6d4e2181cb26b4ebb315179619c5c1eb168835ee 100644 (file)
@@ -351,6 +351,7 @@ int StrBufSanitizeAscii(StrBuf *Buf, const char Mute);
 #define QU                     (3)
 void StrBufUrlescAppend(StrBuf *OutBuf, const StrBuf *In, const char *PlainIn);
 void StrBufUrlescUPAppend(StrBuf *OutBuf, const StrBuf *In, const char *PlainIn);
+void StrBufXMLEscAppend(StrBuf *OutBuf, const StrBuf *In, const char *PlainIn, long PlainInLen, int OverrideLowChars);
 void StrBufHexescAppend(StrBuf *OutBuf, const StrBuf *In, const char *PlainIn);
 void StrBufHexEscAppend(StrBuf *OutBuf, const StrBuf *In, const unsigned char *PlainIn, long PlainInLen);
 void StrBufBase64Append(StrBuf *OutBuf, const StrBuf *In, const char *PlainIn, long PlainInLen, int linebreaks);
index 723140d98a5d524af8c5fd5159fd30a51dcd5656..1fc037d43ffd77462434eb93f645001f4dbb251a 100644 (file)
@@ -1057,8 +1057,8 @@ int LoadIconDir(const char *DirName)
        {
                char *MinorPtr;
                char *PStart;
-#ifdef _DIRENT_HAVE_D_NAMELEN
-               d_namelen = filedir_entry->d_namelen;
+#ifdef _DIRENT_HAVE_D_NAMLEN
+               d_namelen = filedir_entry->d_namlen;
 #else
                d_namelen = strlen(filedir_entry->d_name);
 #endif
index 86f83d805cd8869072214f6725765bb2b0d5d12b..dd15b0801807788bff5a248e45c5584253cfb86e 100644 (file)
@@ -1925,6 +1925,129 @@ void StrBufUrlescUPAppend(StrBuf *OutBuf, const StrBuf *In, const char *PlainIn)
        *pt = '\0';
 }
 
+/** 
+ * @ingroup StrBuf_DeEnCoder
+ * @brief append a string with characters having a special meaning in xml encoded to the buffer
+ * @param OutBuf the output buffer
+ * @param In Buffer to encode
+ * @param PlainIn way in from plain old c strings
+ * @param PlainInLen way in from plain old c strings; maybe you've got binary data or know the length?
+ * @param OverrideLowChars should chars < 0x20 be replaced by _ or escaped as xml entity?
+ */
+void StrBufXMLEscAppend(StrBuf *OutBuf,
+                       const StrBuf *In,
+                       const char *PlainIn,
+                       long PlainInLen,
+                       int OverrideLowChars)
+{
+       const char *pch, *pche;
+       char *pt, *pte;
+       int IsUtf8Sequence;
+       int len;
+
+       if (((In == NULL) && (PlainIn == NULL)) || (OutBuf == NULL) )
+               return;
+       if (PlainIn != NULL) {
+               if (PlainInLen < 0)
+                       len = strlen((const char*)PlainIn);
+               else
+                       len = PlainInLen;
+               pch = PlainIn;
+               pche = pch + len;
+       }
+       else {
+               pch = (const char*)In->buf;
+               pche = pch + In->BufUsed;
+               len = In->BufUsed;
+       }
+
+       if (len == 0)
+               return;
+
+       pt = OutBuf->buf + OutBuf->BufUsed;
+       /**< we max append 6 chars at once plus the \0 */
+       pte = OutBuf->buf + OutBuf->BufSize - 6;
+
+       while (pch < pche) {
+               if (pt >= pte) {
+                       OutBuf->BufUsed = pt - OutBuf->buf;
+                       IncreaseBuf(OutBuf, 1, -1);
+                       pte = OutBuf->buf + OutBuf->BufSize - 6;
+                       /**< we max append 3 chars at once plus the \0 */
+
+                       pt = OutBuf->buf + OutBuf->BufUsed;
+               }
+
+               if (*pch == '<') {
+                       memcpy(pt, HKEY("&lt;"));
+                       pt += 4;
+                       pch ++;
+               }
+               else if (*pch == '>') {
+                       memcpy(pt, HKEY("&gt;"));
+                       pt += 4;
+                       pch ++;
+               }
+               else if (*pch == '&') {
+                       memcpy(pt, HKEY("&amp;"));
+                       pt += 5;
+                       pch++;
+               }
+               else if ((*pch >= 0x20) && (*pch <= 0x7F)) {
+                       *pt = *pch;
+                       pt++; pch++;
+               }
+               else if (*pch < 0x20) {
+                       /* we probably shouldn't be doing this */
+                       if (OverrideLowChars)
+                       {
+                               *pt = '_';
+                               pt ++;
+                               pch ++;
+                       }
+                       else
+                       {
+                               *pt = '&';
+                               pt++;
+                               *pt = HexList[*(unsigned char*)pch][0];
+                               pt ++;
+                               *pt = HexList[*(unsigned char*)pch][1];
+                               pt ++; pch ++;
+                               *pt = '&';
+                               pt++;
+                               pch ++;
+                       }
+               }
+               else {
+                       IsUtf8Sequence =  Ctdl_GetUtf8SequenceLength(pch, pche);
+                       if (IsUtf8Sequence)
+                       {
+                               while (IsUtf8Sequence > 0){
+                                       *pt = *pch;
+                                       pt ++;
+                                       pch ++;
+                                       --IsUtf8Sequence;
+                               }
+                       }
+                       else
+                       {
+                               *pt = '&';
+                               pt++;
+                               *pt = HexList[*(unsigned char*)pch][0];
+                               pt ++;
+                               *pt = HexList[*(unsigned char*)pch][1];
+                               pt ++; pch ++;
+                               *pt = '&';
+                               pt++;
+                               pch ++;
+                       }
+               }
+       }
+       *pt = '\0';
+       OutBuf->BufUsed = pt - OutBuf->buf;
+}
+
+
 /** 
  * @ingroup StrBuf_DeEnCoder
  * @brief append a string in hex encoding to the buffer
@@ -2909,6 +3032,7 @@ StrBuf *StrBufRFC2047encodeMessage(const StrBuf *EncodeMe)
                {
                        long Offset;
                        Offset = Optr - OutBuf->buf;
+                       OutBuf->BufUsed = Optr - OutBuf->buf;
                        IncreaseBuf(OutBuf, 1, 0);
                        Optr = OutBuf->buf + Offset;
                        OEptr = OutBuf->buf + OutBuf->BufSize;