Removed ical_dezonify() from the citserver build ... it isn't used anymore
[citadel.git] / citadel / modules / xmpp / serv_xmpp.c
index 795112b1c50e16835e428234223049dc1c95aefd..34c6e5d2e7c767a0c3f5cc490cd842ef13609b0b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * XMPP (Jabber) service for the Citadel system
- * Copyright (c) 2007-2011 by Art Cancro
+ * Copyright (c) 2007-2017 by Art Cancro and citadel.org
  *
  * This program is open source software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 #include "ctdl_module.h"
 #include "serv_xmpp.h"
 
-#if XML_MAJOR_VERSION > 0
+/* uncomment for more verbosity - it will log all received XML tags */
+#define XMPP_XML_DEBUG
+
 /* XML_StopParser is present in expat 2.x */
+#if XML_MAJOR_VERSION > 1
 #define HAVE_XML_STOPPARSER
 #endif
 
@@ -66,6 +69,7 @@ struct xmpp_event *xmpp_queue = NULL;
 
 
 
+
 #ifdef HAVE_XML_STOPPARSER
 /* Stop the parser if an entity declaration is hit. */
 static void xmpp_entity_declaration(void *userData, const XML_Char *entityName,
@@ -74,7 +78,7 @@ static void xmpp_entity_declaration(void *userData, const XML_Char *entityName,
                                const XML_Char *systemId, const XML_Char *publicId,
                                const XML_Char *notationName
 ) {
-       syslog(LOG_WARNING, "Illegal entity declaration encountered; stopping parser.");
+       syslog(LOG_WARNING, "xmpp: illegal entity declaration encountered; stopping parser.");
        XML_StopParser(XMPP->xp, XML_FALSE);
 }
 #endif
@@ -85,13 +89,32 @@ static void xmpp_entity_declaration(void *userData, const XML_Char *entityName,
  * 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
  */
+static inline int Ctdl_GetUtf8SequenceLength(const char *CharS, const char *CharE)
+{
+       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;
+}
+
 char *xmlesc(char *buf, char *str, int bufsiz)
 {
-       char *ptr;
+       int IsUtf8Sequence;
+       char *ptr, *pche;
        unsigned char ch;
+       int inlen;
        int len = 0;
 
        if (!buf) return(NULL);
@@ -100,6 +123,8 @@ char *xmlesc(char *buf, char *str, int bufsiz)
        if (!str) {
                return(buf);
        }
+       inlen = strlen(str);
+       pche = str + inlen;
 
        for (ptr=str; *ptr; ptr++) {
                ch = *ptr;
@@ -125,10 +150,24 @@ char *xmlesc(char *buf, char *str, int bufsiz)
                        buf[len] = 0;
                }
                else {
-                       char oct[10];
-                       sprintf(oct, "&#%o;", ch);
-                       strcpy(&buf[len], oct);
-                       len += strlen(oct);
+                       IsUtf8Sequence =  Ctdl_GetUtf8SequenceLength(ptr, pche);
+                       if (IsUtf8Sequence)
+                       {
+                               while ((IsUtf8Sequence > 0) && 
+                                      (ptr < pche))
+                               {
+                                       buf[len] = *ptr;
+                                       ptr ++;
+                                       --IsUtf8Sequence;
+                               }
+                       }
+                       else
+                       {
+                               char oct[10];
+                               sprintf(oct, "&#%o;", ch);
+                               strcpy(&buf[len], oct);
+                               len += strlen(oct);
+                       }
                }
                if ((len + 6) > bufsiz) {
                        return(buf);
@@ -202,12 +241,12 @@ void xmpp_xml_start(void *data, const char *supplied_el, const char **attr) {
                strcpy(el, ++sep);
        }
 
-       /*
-       syslog(LOG_DEBUG, "XMPP ELEMENT START: <%s>\n", el);
+#ifdef XMPP_XML_DEBUG
+       syslog(LOG_DEBUG, "xmpp: ELEMENT START: <%s>", el);
        for (i=0; attr[i] != NULL; i+=2) {
-               syslog(LOG_DEBUG, "                    Attribute '%s' = '%s'\n", attr[i], attr[i+1]);
+               syslog(LOG_DEBUG, "xmpp: Attribute '%s' = '%s'", attr[i], attr[i+1]);
        }
-       uncomment for more verbosity */
+#endif
 
        if (!strcasecmp(el, "stream")) {
                xmpp_stream_start(data, supplied_el, attr);
@@ -274,12 +313,12 @@ void xmpp_xml_end(void *data, const char *supplied_el) {
                strcpy(el, ++sep);
        }
 
-       /*
-       syslog(LOG_DEBUG, "XMPP ELEMENT END  : <%s>\n", el);
+#ifdef XMPP_XML_DEBUG
+       syslog(LOG_DEBUG, "xmpp: ELEMENT END  : <%s>", el);
        if (XMPP->chardata_len > 0) {
-               syslog(LOG_DEBUG, "          chardata: %s\n", XMPP->chardata);
+               syslog(LOG_DEBUG, "xmpp: chardata: %s", XMPP->chardata);
        }
-       uncomment for more verbosity */
+#endif
 
        if (!strcasecmp(el, "resource")) {
                if (XMPP->chardata_len > 0) {
@@ -338,10 +377,7 @@ void xmpp_xml_end(void *data, const char *supplied_el) {
                         * Unknown query ... return the XML equivalent of a blank stare
                         */
                        else {
-                               syslog(LOG_DEBUG,
-                                       "Unknown query <%s> - returning <service-unavailable/>\n",
-                                       el
-                               );
+                               syslog(LOG_DEBUG, "xmpp: Unknown query <%s> - returning <service-unavailable/>", 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\"/>"
@@ -401,8 +437,9 @@ void xmpp_xml_end(void *data, const char *supplied_el) {
 
                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("<error>Don't know how to do '%s'!</error>", xmlesc(xmlbuf, XMPP->iq_type, sizeof xmlbuf));
                        cprintf("</iq>");
+                       syslog(LOG_DEBUG, "XMPP: don't know how to do iq_type='%s' with iq_query_xmlns='%s'", XMPP->iq_type, XMPP->iq_query_xmlns);
                }
 
                /* Now clear these fields out so they don't get used by a future stanza */
@@ -473,14 +510,22 @@ void xmpp_xml_end(void *data, const char *supplied_el) {
        }
 
        else if (!strcasecmp(el, "stream")) {
-               syslog(LOG_DEBUG, "XMPP client shut down their stream\n");
+               syslog(LOG_DEBUG, "xmpp: client shut down their stream");
                xmpp_massacre_roster();
                cprintf("</stream>\n");
                CC->kill_me = KILLME_CLIENT_LOGGED_OUT;
        }
 
+       else if (!strcasecmp(el, "query")) {
+               /* already processed , no further action needed here */
+       }
+
+       else if (!strcasecmp(el, "bind")) {
+               /* already processed , no further action needed here */
+       }
+
        else {
-               syslog(LOG_DEBUG, "Ignoring unknown tag <%s>\n", el);
+               syslog(LOG_DEBUG, "xmpp: ignoring unknown tag <%s>", el);
        }
 
        XMPP->chardata_len = 0;
@@ -545,7 +590,7 @@ void xmpp_greeting(void) {
 
        XMPP->xp = XML_ParserCreateNS("UTF-8", ':');
        if (XMPP->xp == NULL) {
-               syslog(LOG_ALERT, "Cannot create XML parser!\n");
+               syslog(LOG_ERR, "xmpp: cannot create XML parser");
                CC->kill_me = KILLME_XML_PARSER;
                return;
        }
@@ -582,7 +627,7 @@ void xmpp_command_loop(void) {
                XML_Parse(XMPP->xp, ChrPtr(stream_input), rc, 0);
        }
        else {
-               syslog(LOG_ERR, "XMPP: client disconnected: ending session.\n");
+               syslog(LOG_ERR, "xmpp: client disconnected: ending session.");
                CC->kill_me = KILLME_CLIENT_DISCONNECTED;
        }
        FreeStrBuf(&stream_input);
@@ -619,22 +664,22 @@ extern void xmpp_cleanup_events(void);
 CTDL_MODULE_INIT(xmpp)
 {
        if (!threading) {
-               CtdlRegisterServiceHook(config.c_xmpp_c2s_port,
+               CtdlRegisterServiceHook(CtdlGetConfigInt("c_xmpp_c2s_port"),
                                        NULL,
                                        xmpp_greeting,
                                        xmpp_command_loop,
                                        xmpp_async_loop,
                                        CitadelServiceXMPP
                );
-               CtdlRegisterSessionHook(xmpp_cleanup_function, EVT_STOP);
-                CtdlRegisterSessionHook(xmpp_login_hook, EVT_LOGIN);
-                CtdlRegisterSessionHook(xmpp_logout_hook, EVT_LOGOUT);
-                CtdlRegisterSessionHook(xmpp_login_hook, EVT_UNSTEALTH);
-                CtdlRegisterSessionHook(xmpp_logout_hook, EVT_STEALTH);
+               CtdlRegisterSessionHook(xmpp_cleanup_function, EVT_STOP, PRIO_STOP + 70);
+                CtdlRegisterSessionHook(xmpp_login_hook, EVT_LOGIN, PRIO_LOGIN + 90);
+                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);
 
        }
 
-       /* return our Subversion id for the Log */
+       /* return our module name for the log */
        return "xmpp";
 }