struct xmpp_event *xmpp_queue = NULL;
HashList *XMPP_StartHandlers = NULL;
HashList *XMPP_EndHandlers = NULL;
+HashList *XMPP_SupportedNamespaces = NULL;
+HashList *XMPP_NameSpaces = 0;
+HashList *FlatToken = NULL;
int XMPPSrvDebugEnable = 0;
{
StrBufAppendBufPlain(XMPP->OutBuf, Str, Len, 0);
}
-#define XPUT(CONSTSTR) XPut(CONSTSTR, sizeof(CONSTSTR) -1)
void XPrintf(const char *Format, ...)
{
}
+void XPrint(const char *Token, long tlen,
+ int Flags,
+ ...)
+
+{
+ 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)
+ {
+ 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 (Flags == XCLOSED)
+ {
+ if (BodySeen)
+ {
+ XPUT("</");
+ XPut(Token, tlen);
+ XPUT(">");
+ }
+ else
+ {
+ XPUT("></");
+ XPut(Token, tlen);
+ XPUT(">");
+ }
+ }
+ 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,
XPrintf("%08x\" ", CC->cs_pid);
XPUT("version=\"1.0\" "
"xmlns:stream=\"http://etherx.jabber.org/streams\" "
- "xmlns=\"jabber:client\">");
-
+ "xmlns=\"jabber:client\">"
/* The features of this stream are... */
- XPUT("<stream:features>");
+ "<stream:features>");
/*
* TLS encryption (but only if it isn't already active)
*/
+/*
#ifdef HAVE_OPENSSL
if (!CC->redirect_ssl) {
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();
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_to, attr[i+1], sizeof XMPP->iq_to);
}
}
+*/
}
void xmpp_start_auth(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) {
}
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);
}
- XUnbuffer();
}
void xmpp_end_resource(void *data, const char *supplied_el, const char **attr)
/*
* 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);
+ xmpp_query_namespace(&Xmpp->IQ, Xmpp->iq_query_xmlns);
}
/*
*/
else if (Xmpp->ping_requested) {
XPUT("<iq type=\"result\" ");
- if (!IsEmptyStr(Xmpp->iq_from)) {
+ if (StrLength(Xmpp->IQ.from) > 0) {
XPUT("to=\"");
- XPutProp(Xmpp->iq_from, strlen(Xmpp->iq_from));
+ XPutSProp(Xmpp->IQ.from);
XPUT("\" ");
}
- if (!IsEmptyStr(Xmpp->iq_to)) {
+ if (StrLength(Xmpp->IQ.to)>0) {
XPUT("from=\"");
- XPutProp(Xmpp->iq_to, strlen(Xmpp->iq_to));
+ XPutSProp(Xmpp->IQ.to);
XPUT("\" ");
}
XPUT("id=\"");
- XPutProp(Xmpp->iq_id, strlen(Xmpp->iq_id));
+ XPutSProp(Xmpp->IQ.id);
XPUT("\"/>");
}
);
*/
XPUT("<iq type=\"error\" id=\"");
- XPutProp(Xmpp->iq_id, strlen(Xmpp->iq_id));
+ XPutSProp(Xmpp->IQ.id);
XPUT("\">"
"<error code=\"503\" type=\"cancel\">"
"<service-unavailable xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"/>"
* Non SASL authentication
*/
else if (
- (!strcasecmp(Xmpp->iq_type, "set"))
+ (!strcasecmp(ChrPtr(Xmpp->IQ.type), "set"))
&& (!strcasecmp(Xmpp->iq_query_xmlns, "jabber:iq:auth:query"))
) {
xmpp_non_sasl_authenticate(
- Xmpp->iq_id,
+ Xmpp->IQ.id,
Xmpp->iq_client_username,
Xmpp->iq_client_password,
Xmpp->iq_client_resource
*/
else if (
(Xmpp->bind_requested)
- && (!IsEmptyStr(Xmpp->iq_id))
+ && (StrLength(Xmpp->IQ.id)>0)
&& (!IsEmptyStr(Xmpp->iq_client_resource))
&& (CC->logged_in)
) {
/* Tell the client what its JID is */
XPUT("<iq type=\"result\" id=\"");
- XPutProp(Xmpp->iq_id, strlen(Xmpp->iq_id));
+ XPutSProp(Xmpp->IQ.id);
XPUT("\">"
"<bind xmlns=\"urn:ietf:params:xml:ns:xmpp-bind\">");
XPUT("<jid>");
else if (Xmpp->iq_session) {
XPUT("<iq type=\"result\" id=\"");
- XPutProp(Xmpp->iq_id, strlen(Xmpp->iq_id));
+ XPutSProp(Xmpp->IQ.id);
XPUT("\">"
"</iq>");
}
else {
XPUT("<iq type=\"error\" id=\"");
- XPutProp(Xmpp->iq_id, strlen(Xmpp->iq_id));
+ XPutSProp(Xmpp->IQ.id);
XPUT("\">");
XPUT("<error>Don't know howto do '");
- XPutBody(Xmpp->iq_type, strlen(Xmpp->iq_type));
+ 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;
+ 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;
{
#ifdef HAVE_OPENSSL
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
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) {
}
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;
}
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;
if (XMPP->chardata_alloc > 0) {
XMPP->chardata[0] = 0;
}
- XUnbuffer();
}
free(XMPP->message_body);
}
}
+ free_buf_iq(&XMPP->IQ);
+
XML_ParserFree(XMPP->xp);
+ FreeStrBuf(&XMPP->OutBuf);
free(XMPP);
}
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", ':');
#endif
CC->can_receive_im = 1; /* This protocol is capable of receiving instant messages */
+ XUnbuffer();
}
CC->kill_me = KILLME_CLIENT_DISCONNECTED;
}
FreeStrBuf(&stream_input);
+ XUnbuffer();
}
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);
+ }
+
+ 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);
+ }
+ */
+}
+
+
+
CTDL_MODULE_INIT(xmpp)
{
if (!threading) {
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);
CtdlRegisterSessionHook(xmpp_login_hook, EVT_UNSTEALTH, PRIO_UNSTEALTH + 1);
CtdlRegisterSessionHook(xmpp_logout_hook, EVT_STEALTH, PRIO_STEALTH + 1);
CtdlRegisterCleanupHook(xmpp_cleanup_events);
-
}
/* return our module name for the log */
return "xmpp";
}
+
+