* $Id$
*
* XMPP (Jabber) service for the Citadel system
- * Copyright (c) 2007 by Art Cancro
- * This code is released under the terms of the GNU General Public License.
+ * Copyright (c) 2007-2009 by Art Cancro
*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "sysdep.h"
#include <limits.h>
#include <ctype.h>
#include <libcitadel.h>
+#include <expat.h>
#include "citadel.h"
#include "server.h"
#include "citserver.h"
#include "internet_addressing.h"
#include "md5.h"
#include "ctdl_module.h"
-
-#ifdef HAVE_EXPAT
-#include <expat.h>
#include "serv_xmpp.h"
struct xmpp_event *xmpp_queue = NULL;
void xmpp_stream_start(void *data, const char *supplied_el, const char **attr)
{
-
- lprintf(CTDL_DEBUG, "New stream detected.\n");
-
while (*attr) {
if (!strcasecmp(attr[0], "to")) {
safestrncpy(XMPP->server_name, attr[1], sizeof XMPP->server_name);
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\"/>");
}
- else {
- /* If we've logged in, now offer binding and sessions as our feature set */
- cprintf("<bind xmlns=\"urn:ietf:params:xml:ns:xmpp-bind\"/>");
- cprintf("<session xmlns=\"urn:ietf:params:xml:ns:xmpp-session\"/>");
- }
+
+ /* 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>");
strcpy(el, ++sep);
}
- lprintf(CTDL_DEBUG, "XMPP ELEMENT START: <%s>\n", el);
-
+ /*
+ CtdlLogPrintf(CTDL_DEBUG, "XMPP ELEMENT START: <%s>\n", el);
for (i=0; attr[i] != NULL; i+=2) {
- lprintf(CTDL_DEBUG, " Attribute '%s' = '%s'\n", attr[i], attr[i+1]);
+ CtdlLogPrintf(CTDL_DEBUG, " Attribute '%s' = '%s'\n", attr[i], attr[i+1]);
}
+ uncomment for more verbosity */
if (!strcasecmp(el, "stream")) {
xmpp_stream_start(data, supplied_el, attr);
safestrncpy(XMPP->iq_query_xmlns, supplied_el, sizeof XMPP->iq_query_xmlns);
}
+ else if (!strcasecmp(el, "bind")) {
+ XMPP->bind_requested = 1;
+ }
+
else if (!strcasecmp(el, "iq")) {
for (i=0; attr[i] != NULL; i+=2) {
if (!strcasecmp(attr[i], "type")) {
strcpy(el, ++sep);
}
- lprintf(CTDL_DEBUG, "XMPP ELEMENT END : <%s>\n", el);
+ /*
+ CtdlLogPrintf(CTDL_DEBUG, "XMPP ELEMENT END : <%s>\n", el);
if (XMPP->chardata_len > 0) {
- lprintf(CTDL_DEBUG, " chardata: %s\n", XMPP->chardata);
+ CtdlLogPrintf(CTDL_DEBUG, " chardata: %s\n", XMPP->chardata);
}
+ uncomment for more verbosity */
if (!strcasecmp(el, "resource")) {
if (XMPP->chardata_len > 0) {
safestrncpy(XMPP->iq_client_resource, XMPP->chardata,
sizeof XMPP->iq_client_resource);
+ striplt(XMPP->iq_client_resource);
+ }
+ }
+
+ if (!strcasecmp(el, "username")) { /* NON SASL ONLY */
+ if (XMPP->chardata_len > 0) {
+ safestrncpy(XMPP->iq_client_username, XMPP->chardata,
+ sizeof XMPP->iq_client_username);
+ striplt(XMPP->iq_client_username);
+ }
+ }
+
+ if (!strcasecmp(el, "password")) { /* NON SASL ONLY */
+ if (XMPP->chardata_len > 0) {
+ safestrncpy(XMPP->iq_client_password, XMPP->chardata,
+ sizeof XMPP->iq_client_password);
+ striplt(XMPP->iq_client_password);
}
}
}
}
+ /*
+ * Non SASL authentication
+ */
+ else if (
+ (!strcasecmp(XMPP->iq_type, "set"))
+ && (!strcasecmp(XMPP->iq_query_xmlns, "jabber:iq:auth:query"))
+ ) {
+
+ jabber_non_sasl_authenticate(
+ XMPP->iq_id,
+ XMPP->iq_client_username,
+ XMPP->iq_client_password,
+ XMPP->iq_client_resource
+ );
+ }
+
/*
* If this <iq> stanza was a "bind" attempt, process it ...
*/
- else if ( (!IsEmptyStr(XMPP->iq_id)) && (!IsEmptyStr(XMPP->iq_client_resource)) ) {
+ else if (
+ (XMPP->bind_requested)
+ && (!IsEmptyStr(XMPP->iq_id))
+ && (!IsEmptyStr(XMPP->iq_client_resource))
+ && (CC->logged_in)
+ ) {
/* Generate the "full JID" of the client resource */
XMPP->iq_client_resource[0] = 0;
XMPP->iq_session = 0;
XMPP->iq_query_xmlns[0] = 0;
+ XMPP->bind_requested = 0;
}
else if (!strcasecmp(el, "auth")) {
/* Don't do this stuff if this is not a XMPP session! */
if (CC->h_command_function != xmpp_command_loop) return;
- lprintf(CTDL_DEBUG, "Performing XMPP cleanup hook\n");
if (XMPP->chardata != NULL) {
free(XMPP->chardata);
XMPP->chardata = NULL;
XMPP->xp = XML_ParserCreateNS("UTF-8", ':');
if (XMPP->xp == NULL) {
- lprintf(CTDL_ALERT, "Cannot create XML parser!\n");
+ CtdlLogPrintf(CTDL_ALERT, "Cannot create XML parser!\n");
CC->kill_me = 1;
return;
}
XML_SetElementHandler(XMPP->xp, xmpp_xml_start, xmpp_xml_end);
XML_SetCharacterDataHandler(XMPP->xp, xmpp_xml_chardata);
// XML_SetUserData(XMPP->xp, something...);
+
+ CC->can_receive_im = 1; /* This protocol is capable of receiving instant messages */
}
memset(cmdbuf, 0, sizeof cmdbuf); /* Clear it, just in case */
retval = client_read(cmdbuf, 1);
if (retval != 1) {
- lprintf(CTDL_ERR, "Client disconnected: ending session.\r\n");
+ CtdlLogPrintf(CTDL_ERR, "Client disconnected: ending session.\r\n");
CC->kill_me = 1;
return;
}
const char *CitadelServiceXMPP="XMPP";
-#endif /* HAVE_EXPAT */
-
CTDL_MODULE_INIT(jabber)
{
-#ifdef HAVE_EXPAT
if (!threading) {
CtdlRegisterServiceHook(config.c_xmpp_c2s_port,
NULL,
CtdlRegisterSessionHook(xmpp_logout_hook, EVT_LOGOUT);
CtdlRegisterSessionHook(xmpp_login_hook, EVT_UNSTEALTH);
CtdlRegisterSessionHook(xmpp_logout_hook, EVT_STEALTH);
- #else
- lprintf(CTDL_INFO, "This server is missing the Expat XML parser. Jabber service will be disabled.\n");
-#endif
}
/* return our Subversion id for the Log */