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, ...)
{
/*
* 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)
{
+ HashList *ThisNamespace = NULL;
const char *pToken;
const char *pch;
+ const char *NS = NULL;
+ long NSLen;
long len;
void *pv;
while (pch != NULL)
{
pToken = pch;
- pch = strchr(pToken, ':');
+ 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) {
/*
* 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;
while (pch != NULL)
{
pToken = pch;
- pch = strchr(pToken, ':');
+ pch = strchr(pToken + 1, ':');
}
+
+ if (*pToken == ':')
+ pToken ++;
+
len = strlen(pToken);
/*
free(XMPP->message_body);
}
}
+ free_buf_iq(&XMPP->IQ);
+
XML_ParserFree(XMPP->xp);
FreeStrBuf(&XMPP->OutBuf);
free(XMPP);
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";
}
+
+
*
*/
+#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 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 */
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_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);
"XMPP: " FORMAT);
-void XUnbuffer(void);
-void XPutBody(const char *Str, long Len);
-void XPutProp(const char *Str, long Len);
-void XPut(const char *Str, long Len);
-#define XPUT(CONSTSTR) XPut(CONSTSTR, sizeof(CONSTSTR) -1)
-
-void XPrintf(const char *Format, ...);
-
-
void AddXMPPStartHandler(const char *key,
long len,
xmpp_handler_func Handler,
int Flags);
-#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 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
+
+
--- /dev/null
+
+#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);
+ })
*
*/
-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;
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.
XPrint(HKEY("iq"), 0,
XPROPERTY("type", TypeStr, TLen),
- XOPROPERTY("to", iq_from, strlen(iq_from)),
- XPROPERTY("id", iq_id, strlen(iq_id)));
+ XSPROPERTY("to", IQ->from),
+ XSPROPERTY("id", IQ->id));
/*
* Is this a query we know how to handle?
/*
* 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;
if (CC->logged_in) CtdlUserLogout(); /* Client may try to log in twice. Handle this. */
if (result == pass_ok) {
XPrint(HKEY("iq"), XCLOSED,
XCPROPERTY("type", "result"),
- XPROPERTY("ID", iq_id, strlen(iq_id)),
+ XSPROPERTY("ID", IQ_id),
TYPE_ARGEND);
/* success */
return;
/* failure */
XPrint(HKEY("iq"), 0,
XCPROPERTY("type", "error"),
- XPROPERTY("ID", iq_id, strlen(iq_id)),
+ XSPROPERTY("ID", IQ_id),
TYPE_ARGEND);
XPUT("<error code=\"401\" type=\"auth\">"
"<not-authorized xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"/>"
--- /dev/null
+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);
--- /dev/null
+#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;
+}
+
+
+#define STRPROP(STRUCTNAME, NAME) \
+ if (StrLength(pdata->NAME) > 0) \
+ { \
+ XPut(#NAME, sizeof(#NAME) - 1); \
+ XPut("=\"", 2); \
+ XPutProp(SKEY(pdata->NAME)); \
+ XPut("\" ", 2); \
+ }
+
+#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 TOKEN
+
+
+#define STRPROP(STRUCTNAME, NAME) \
+ FreeStrBuf(&pdata->NAME);
+
+#define TOKEN(NAME, STRUCT) \
+ void free_buf_##NAME(TheToken_##NAME *pdata) \
+ { \
+ STRUCT ; \
+ }
+
+#include "token.def"
+#undef STRPROP
+#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 TOKEN(NAME, STRUCT) STRUCT
+#include "token.def"
+#undef STRPROP
+#undef TOKEN
+ }
+
+ /* return our module name for the log */
+ return "xmpp_xmacros";
+}
--- /dev/null
+
+/*
+ * define the structures for one token each
+ * typename: TheToken_<Tokenname>
+ */
+#define STRPROP(STRUCTNAME, NAME) StrBuf *NAME;
+#define TOKEN(NAME, STRUCT) typedef struct __##NAME \
+ STRUCT \
+ TheToken_##NAME;
+#include "token.def"
+#undef STRPROP
+#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 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 TOKEN