20#include "../../sysdep.h"
34#include <libcitadel.h>
36#include "../../citadel.h"
37#include "../../server.h"
38#include "../../citserver.h"
39#include "../../support.h"
40#include "../../config.h"
41#include "../../user_ops.h"
42#include "../../database.h"
43#include "../../msgbase.h"
44#include "../../internet_addressing.h"
45#include "../../ctdl_module.h"
52#if XML_MAJOR_VERSION > 1
53#define HAVE_XML_STOPPARSER
58#ifdef HAVE_XML_STOPPARSER
60static void xmpp_entity_declaration(
void *userData,
const XML_Char *entityName,
61 int is_parameter_entity,
const XML_Char *value,
62 int value_length,
const XML_Char *base,
63 const XML_Char *systemId,
const XML_Char *publicId,
64 const XML_Char *notationName
66 syslog(LOG_WARNING,
"xmpp: illegal entity declaration encountered; stopping parser.");
67 XML_StopParser(
XMPP->xp, XML_FALSE);
78 unsigned char test = (1<<7);
80 if ((*CharS & 0xC0) != 0xC0) {
84 while ((n < 8) && ((test & ((
unsigned char)*CharS)) != 0)) {
88 if ((n > 6) || ((CharE - CharS) < n)) {
100char *
xmlesc(
char *buf,
char *str,
int bufsiz)
108 if (!buf)
return(NULL);
117 for (ptr=str; *ptr; ptr++) {
120 strcpy(&buf[len],
"<");
123 else if (ch ==
'>') {
124 strcpy(&buf[len],
">");
127 else if (ch ==
'&') {
128 strcpy(&buf[len],
"&");
131 else if ((ch >= 0x20) && (ch <= 0x7F)) {
135 else if (ch < 0x20) {
143 while ((IsUtf8Sequence > 0) &&
154 sprintf(oct,
"&#%o;", ch);
155 strcpy(&buf[len], oct);
159 if ((len + 6) > bufsiz) {
175 if (!strcasecmp(attr[0],
"to")) {
176 safestrncpy(
XMPP->server_name, attr[1],
sizeof XMPP->server_name);
181 cprintf(
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
186 cprintf(
"xmlns:stream=\"http://etherx.jabber.org/streams\" ");
187 cprintf(
"xmlns=\"jabber:client\">");
196 if (!
CC->redirect_ssl) {
197 cprintf(
"<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'></starttls>");
201 if (!
CC->logged_in) {
206 cprintf(
"<auth xmlns=\"http://jabber.org/features/iq-auth\"/>");
210 cprintf(
"<bind xmlns=\"urn:ietf:params:xml:ns:xmpp-bind\"/>");
211 cprintf(
"<session xmlns=\"urn:ietf:params:xml:ns:xmpp-session\"/>");
226 safestrncpy(el, supplied_el,
sizeof el);
227 while (sep = strchr(el,
':'), sep) {
232 syslog(LOG_DEBUG,
"xmpp: ELEMENT START: <%s>", el);
233 for (i=0; attr[i] != NULL; i+=2) {
234 syslog(LOG_DEBUG,
"xmpp: Attribute '%s' = '%s'", attr[i], attr[i+1]);
238 if (!strcasecmp(el,
"stream")) {
242 else if (!strcasecmp(el,
"query")) {
243 XMPP->iq_query_xmlns[0] = 0;
244 safestrncpy(
XMPP->iq_query_xmlns, supplied_el,
sizeof XMPP->iq_query_xmlns);
247 else if (!strcasecmp(el,
"bind")) {
248 XMPP->bind_requested = 1;
251 else if (!strcasecmp(el,
"iq")) {
252 for (i=0; attr[i] != NULL; i+=2) {
253 if (!strcasecmp(attr[i],
"type")) {
254 safestrncpy(
XMPP->iq_type, attr[i+1],
sizeof XMPP->iq_type);
256 else if (!strcasecmp(attr[i],
"id")) {
257 safestrncpy(
XMPP->iq_id, attr[i+1],
sizeof XMPP->iq_id);
259 else if (!strcasecmp(attr[i],
"from")) {
260 safestrncpy(
XMPP->iq_from, attr[i+1],
sizeof XMPP->iq_from);
262 else if (!strcasecmp(attr[i],
"to")) {
263 safestrncpy(
XMPP->iq_to, attr[i+1],
sizeof XMPP->iq_to);
268 else if (!strcasecmp(el,
"auth")) {
269 XMPP->sasl_auth_mech[0] = 0;
270 for (i=0; attr[i] != NULL; i+=2) {
271 if (!strcasecmp(attr[i],
"mechanism")) {
272 safestrncpy(
XMPP->sasl_auth_mech, attr[i+1],
sizeof XMPP->sasl_auth_mech);
277 else if (!strcasecmp(el,
"message")) {
278 for (i=0; attr[i] != NULL; i+=2) {
279 if (!strcasecmp(attr[i],
"to")) {
280 safestrncpy(
XMPP->message_to, attr[i+1],
sizeof XMPP->message_to);
285 else if (!strcasecmp(el,
"html")) {
286 ++
XMPP->html_tag_level;
299 safestrncpy(el, supplied_el,
sizeof el);
300 while (sep = strchr(el,
':'), sep) {
305 syslog(LOG_DEBUG,
"xmpp: ELEMENT END : <%s>", el);
306 if (
XMPP->chardata_len > 0) {
307 syslog(LOG_DEBUG,
"xmpp: chardata: %s",
XMPP->chardata);
311 if (!strcasecmp(el,
"resource")) {
312 if (
XMPP->chardata_len > 0) {
313 safestrncpy(
XMPP->iq_client_resource,
XMPP->chardata,
sizeof XMPP->iq_client_resource);
314 string_trim(
XMPP->iq_client_resource);
318 else if (!strcasecmp(el,
"username")) {
319 if (
XMPP->chardata_len > 0) {
320 safestrncpy(
XMPP->iq_client_username,
XMPP->chardata,
sizeof XMPP->iq_client_username);
321 string_trim(
XMPP->iq_client_username);
325 else if (!strcasecmp(el,
"password")) {
326 if (
XMPP->chardata_len > 0) {
327 safestrncpy(
XMPP->iq_client_password,
XMPP->chardata,
sizeof XMPP->iq_client_password);
328 string_trim(
XMPP->iq_client_password);
332 else if (!strcasecmp(el,
"iq")) {
337 if (!strcasecmp(
XMPP->iq_type,
"get")) {
342 if (!IsEmptyStr(
XMPP->iq_query_xmlns)) {
349 else if (
XMPP->ping_requested) {
350 cprintf(
"<iq type=\"result\" ");
351 if (!IsEmptyStr(
XMPP->iq_from)) {
354 if (!IsEmptyStr(
XMPP->iq_to)) {
364 else if (
XMPP->iq_vcard) {
365 cprintf(
"<iq type=\"result\" id=\"%s\" ",
xmlesc(xmlbuf,
XMPP->iq_id,
sizeof xmlbuf));
367 cprintf(
"<vCard xmlns=\"vcard-temp\">");
368 cprintf(
"<fn>%s</fn>",
xmlesc(xmlbuf,
CC->user.fullname,
sizeof xmlbuf));
369 cprintf(
"<nickname>%s</nickname>",
xmlesc(xmlbuf,
CC->user.fullname,
sizeof xmlbuf));
378 syslog(LOG_DEBUG,
"xmpp: Unknown query <%s> - returning <service-unavailable/>", el);
379 cprintf(
"<iq type=\"error\" id=\"%s\">",
xmlesc(xmlbuf,
XMPP->iq_id,
sizeof xmlbuf));
380 cprintf(
"<error code=\"503\" type=\"cancel\">"
381 "<service-unavailable xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"/>"
392 (!strcasecmp(
XMPP->iq_type,
"set"))
393 && (!strcasecmp(
XMPP->iq_query_xmlns,
"jabber:iq:auth:query"))
402 (
XMPP->bind_requested)
403 && (!IsEmptyStr(
XMPP->iq_id))
407 if (IsEmptyStr(
XMPP->iq_client_resource)) {
408 snprintf(
XMPP->iq_client_resource,
sizeof XMPP->iq_client_resource,
"%d",
CC->cs_pid);
412 snprintf(
XMPP->client_jid,
sizeof XMPP->client_jid,
"%s/%s",
CC->cs_principal_id,
XMPP->iq_client_resource);
415 cprintf(
"<iq type=\"result\" id=\"%s\">",
xmlesc(xmlbuf,
XMPP->iq_id,
sizeof xmlbuf));
416 cprintf(
"<bind xmlns=\"urn:ietf:params:xml:ns:xmpp-bind\">");
422 else if (
XMPP->iq_session) {
423 cprintf(
"<iq type=\"result\" id=\"%s\">",
xmlesc(xmlbuf,
XMPP->iq_id,
sizeof xmlbuf));
428 cprintf(
"<iq type=\"error\" id=\"%s\">",
xmlesc(xmlbuf,
XMPP->iq_id,
sizeof xmlbuf));
429 cprintf(
"<error>Don't know how to do '%s'!</error>",
xmlesc(xmlbuf,
XMPP->iq_type,
sizeof xmlbuf));
431 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);
436 XMPP->iq_from[0] = 0;
438 XMPP->iq_type[0] = 0;
439 XMPP->iq_client_resource[0] = 0;
440 XMPP->iq_session = 0;
442 XMPP->iq_query_xmlns[0] = 0;
443 XMPP->bind_requested = 0;
444 XMPP->ping_requested = 0;
447 else if (!strcasecmp(el,
"auth")) {
452 XMPP->sasl_auth_mech[0] = 0;
455 else if (!strcasecmp(el,
"session")) {
456 XMPP->iq_session = 1;
459 else if (!strcasecmp(supplied_el,
"vcard-temp:vCard")) {
463 else if (!strcasecmp(el,
"presence")) {
470 else if ( (!strcasecmp(el,
"body")) && (
XMPP->html_tag_level == 0) ) {
471 if (
XMPP->message_body != NULL) {
473 XMPP->message_body = NULL;
475 if (
XMPP->chardata_len > 0) {
476 XMPP->message_body = strdup(
XMPP->chardata);
480 else if (!strcasecmp(el,
"message")) {
482 XMPP->html_tag_level = 0;
485 else if (!strcasecmp(el,
"html")) {
486 --
XMPP->html_tag_level;
489 else if (!strcasecmp(el,
"starttls")) {
491 cprintf(
"<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>");
495 cprintf(
"<failure xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>");
500 else if (!strcasecmp(el,
"ping")) {
501 XMPP->ping_requested = 1;
504 else if (!strcasecmp(el,
"stream")) {
505 syslog(LOG_DEBUG,
"xmpp: client shut down their stream");
511 else if (!strcasecmp(el,
"query")) {
515 else if (!strcasecmp(el,
"bind")) {
520 syslog(LOG_DEBUG,
"xmpp: ignoring unknown tag <%s>", el);
523 XMPP->chardata_len = 0;
524 if (
XMPP->chardata_alloc > 0) {
525 XMPP->chardata[0] = 0;
556 if (
XMPP->chardata != NULL) {
558 XMPP->chardata = NULL;
559 XMPP->chardata_len = 0;
560 XMPP->chardata_alloc = 0;
561 if (
XMPP->message_body != NULL) {
565 XML_ParserFree(
XMPP->xp);
575 strcpy(
CC->cs_clientname,
"XMPP session");
582 XMPP->xp = XML_ParserCreateNS(
"UTF-8",
':');
583 if (
XMPP->xp == NULL) {
584 syslog(LOG_ERR,
"xmpp: cannot create XML parser");
598#ifdef HAVE_XML_STOPPARSER
599 XML_SetEntityDeclHandler(
XMPP->xp, xmpp_entity_declaration);
601 XML_SetDefaultHandler(
XMPP->xp, NULL);
604 CC->can_receive_im = 1;
613 StrBuf *stream_input = NewStrBuf();
618 XML_Parse(
XMPP->xp, ChrPtr(stream_input), rc, 0);
621 syslog(LOG_ERR,
"xmpp: client disconnected: ending session.");
624 FreeStrBuf(&stream_input);
int CtdlGetConfigInt(char *key)
void CtdlModuleStartCryptoMsgs(char *ok_response, char *nosup_response, char *error_response)
void CtdlRegisterServiceHook(int tcp_port, char *sockpath, void(*h_greeting_function)(void), void(*h_command_function)(void), void(*h_async_function)(void), const char *ServiceName)
void CtdlRegisterSessionHook(void(*fcn_ptr)(void), int EventType, int Priority)
void xmpp_cleanup_function(void)
void xmpp_async_loop(void)
struct xmpp_event * xmpp_queue
void xmpp_xml_end(void *data, const char *supplied_el)
void xmpp_command_loop(void)
void xmpp_xml_chardata(void *data, const XML_Char *s, int len)
void xmpp_xml_start(void *data, const char *supplied_el, const char **attr)
static int Ctdl_GetUtf8SequenceLength(const char *CharS, const char *CharE)
void xmpp_login_hook(void)
void xmpp_logout_hook(void)
char * ctdl_module_init_xmpp()
char * xmlesc(char *buf, char *str, int bufsiz)
void xmpp_stream_start(void *data, const char *supplied_el, const char **attr)
const char * CitadelServiceXMPP
void xmpp_output_incoming_messages(void)
void xmpp_output_auth_mechs(void)
void xmpp_process_events(void)
void xmpp_non_sasl_authenticate(char *, char *, char *)
void xmpp_send_message(char *, char *)
void xmpp_sasl_auth(char *, char *)
void xmpp_wholist_presence_dump(void)
void xmpp_massacre_roster(void)
void xmpp_queue_event(int, char *)
void xmpp_query_namespace(char *, char *, char *, char *)
@ KILLME_CLIENT_DISCONNECTED
@ KILLME_CLIENT_LOGGED_OUT
void cprintf(const char *format,...)
int client_read_random_blob(StrBuf *Target, int timeout)
void client_set_inbound_buf(long N)