freeswitch/libs/iksemel/src/jabber.c

331 lines
8.2 KiB
C

/* iksemel (XML parser for Jabber)
** Copyright (C) 2000-2003 Gurer Ozen <madcat@e-kolay.net>
** This code is free software; you can redistribute it and/or
** modify it under the terms of GNU Lesser General Public License.
*/
#include "common.h"
#include "iksemel.h"
iksid *
iks_id_new (ikstack *s, const char *jid)
{
iksid *id;
char *src, *tmp;
/* FIXME: add jabber id validity checks to this function */
/* which characters are allowed in id parts? */
if (!jid) return NULL;
id = iks_stack_alloc (s, sizeof (iksid));
if (!id) return NULL;
memset (id, 0, sizeof (iksid));
/* skip scheme */
if (strncmp ("jabber:", jid, 7) == 0) jid += 7;
id->full = iks_stack_strdup (s, jid, 0);
src = id->full;
/* split resource */
tmp = strchr (src, '/');
if (tmp) {
id->partial = iks_stack_strdup (s, src, tmp - src);
id->resource = tmp + 1;
src = id->partial;
} else {
id->partial = src;
}
/* split user */
tmp = strchr (src, '@');
if (tmp) {
id->user = iks_stack_strdup (s, src, tmp - src);
src = ++tmp;
}
id->server = src;
return id;
}
int
iks_id_cmp (iksid *a, iksid *b, int parts)
{
int diff;
if (!a || !b) return (IKS_ID_RESOURCE | IKS_ID_USER | IKS_ID_SERVER);
diff = 0;
if (parts & IKS_ID_RESOURCE && !(!a->resource && !b->resource) && iks_strcmp (a->resource, b->resource) != 0)
diff += IKS_ID_RESOURCE;
if (parts & IKS_ID_USER && !(!a->user && !b->user) && iks_strcasecmp (a->user, b->user) != 0)
diff += IKS_ID_USER;
if (parts & IKS_ID_SERVER && !(!a->server && !b->server) && iks_strcmp (a->server, b->server) != 0)
diff += IKS_ID_SERVER;
return diff;
}
ikspak *
iks_packet (iks *x)
{
ikspak *pak;
ikstack *s;
char *tmp;
s = iks_stack (x);
pak = iks_stack_alloc (s, sizeof (ikspak));
if (!pak) return NULL;
memset (pak, 0, sizeof (ikspak));
pak->x = x;
tmp = iks_find_attrib (x, "from");
if (tmp) pak->from = iks_id_new (s, tmp);
pak->id = iks_find_attrib (x, "id");
tmp = iks_find_attrib (x, "type");
if (strcmp (iks_name (x), "message") == 0) {
pak->type = IKS_PAK_MESSAGE;
if (tmp) {
if (strcmp (tmp, "chat") == 0)
pak->subtype = IKS_TYPE_CHAT;
else if (strcmp (tmp, "groupchat") == 0)
pak->subtype = IKS_TYPE_GROUPCHAT;
else if (strcmp (tmp, "headline") == 0)
pak->subtype = IKS_TYPE_HEADLINE;
else if (strcmp (tmp, "error") == 0)
pak->subtype = IKS_TYPE_ERROR;
}
} else if (strcmp (iks_name (x), "presence") == 0) {
pak->type = IKS_PAK_S10N;
if (tmp) {
if (strcmp (tmp, "unavailable") == 0) {
pak->type = IKS_PAK_PRESENCE;
pak->subtype = IKS_TYPE_UNAVAILABLE;
pak->show = IKS_SHOW_UNAVAILABLE;
} else if (strcmp (tmp, "probe") == 0) {
pak->type = IKS_PAK_PRESENCE;
pak->subtype = IKS_TYPE_PROBE;
} else if(strcmp(tmp, "subscribe") == 0)
pak->subtype = IKS_TYPE_SUBSCRIBE;
else if(strcmp(tmp, "subscribed") == 0)
pak->subtype = IKS_TYPE_SUBSCRIBED;
else if(strcmp(tmp, "unsubscribe") == 0)
pak->subtype = IKS_TYPE_UNSUBSCRIBE;
else if(strcmp(tmp, "unsubscribed") == 0)
pak->subtype = IKS_TYPE_UNSUBSCRIBED;
else if(strcmp(tmp, "error") == 0)
pak->subtype = IKS_TYPE_ERROR;
} else {
pak->type = IKS_PAK_PRESENCE;
pak->subtype = IKS_TYPE_AVAILABLE;
tmp = iks_find_cdata (x, "show");
pak->show = IKS_SHOW_AVAILABLE;
if (tmp) {
if (strcmp (tmp, "chat") == 0)
pak->show = IKS_SHOW_CHAT;
else if (strcmp (tmp, "away") == 0)
pak->show = IKS_SHOW_AWAY;
else if (strcmp (tmp, "xa") == 0)
pak->show = IKS_SHOW_XA;
else if (strcmp (tmp, "dnd") == 0)
pak->show = IKS_SHOW_DND;
}
}
} else if (strcmp (iks_name (x), "iq") == 0) {
iks *q;
pak->type = IKS_PAK_IQ;
if (tmp) {
if (strcmp (tmp, "get") == 0)
pak->subtype = IKS_TYPE_GET;
else if (strcmp (tmp, "set") == 0)
pak->subtype = IKS_TYPE_SET;
else if (strcmp (tmp, "result") == 0)
pak->subtype = IKS_TYPE_RESULT;
else if (strcmp (tmp, "error") == 0)
pak->subtype = IKS_TYPE_ERROR;
}
for (q = iks_child (x); q; q = iks_next (q)) {
if (IKS_TAG == iks_type (q)) {
char *ns;
ns = iks_find_attrib (q, "xmlns");
if (ns) {
pak->query = q;
pak->ns = ns;
break;
}
}
}
}
return pak;
}
iks *
iks_make_auth (iksid *id, const char *pass, const char *sid)
{
iks *x, *y;
x = iks_new ("iq");
iks_insert_attrib (x, "type", "set");
y = iks_insert (x, "query");
iks_insert_attrib (y, "xmlns", IKS_NS_AUTH);
iks_insert_cdata (iks_insert (y, "username"), id->user, 0);
iks_insert_cdata (iks_insert (y, "resource"), id->resource, 0);
if(sid) {
char buf[41];
iksha *sha;
sha = iks_sha_new ();
iks_sha_hash (sha, (const unsigned char*)sid, strlen (sid), 0);
iks_sha_hash (sha, (const unsigned char*)pass, strlen (pass), 1);
iks_sha_print (sha, buf);
iks_sha_delete (sha);
iks_insert_cdata (iks_insert (y, "digest"), buf, 40);
} else {
iks_insert_cdata (iks_insert (y, "password"), pass, 0);
}
return x;
}
iks *
iks_make_msg (enum iksubtype type, const char *to, const char *body)
{
iks *x;
char *t = NULL;
x = iks_new ("message");
switch (type) {
case IKS_TYPE_CHAT: t = "chat"; break;
case IKS_TYPE_GROUPCHAT: t = "groupchat"; break;
case IKS_TYPE_HEADLINE: t = "headline"; break;
default: break;
}
if (t) iks_insert_attrib (x, "type", t);
if (to) iks_insert_attrib (x, "to", to);
if (body) iks_insert_cdata (iks_insert (x, "body"), body, 0);
return x;
}
iks *
iks_make_s10n (enum iksubtype type, const char *to, const char *msg)
{
iks *x;
char *t;
x = iks_new ("presence");
switch (type) {
case IKS_TYPE_SUBSCRIBE: t = "subscribe"; break;
case IKS_TYPE_SUBSCRIBED: t = "subscribed"; break;
case IKS_TYPE_UNSUBSCRIBE: t = "unsubscribe"; break;
case IKS_TYPE_UNSUBSCRIBED: t = "unsubscribed"; break;
case IKS_TYPE_PROBE: t = "probe"; break;
default: t = NULL; break;
}
if (t) iks_insert_attrib (x, "type", t);
if (to) iks_insert_attrib (x, "to", to);
if (msg) iks_insert_cdata(iks_insert (x, "status"), msg, 0);
return x;
}
iks *
iks_make_pres (enum ikshowtype show, const char *status)
{
iks *x;
char *t;
x = iks_new ("presence");
switch (show) {
case IKS_SHOW_CHAT: t = "chat"; break;
case IKS_SHOW_AWAY: t = "away"; break;
case IKS_SHOW_XA: t = "xa"; break;
case IKS_SHOW_DND: t = "dnd"; break;
case IKS_SHOW_UNAVAILABLE:
t = NULL;
iks_insert_attrib (x, "type", "unavailable");
break;
default: t = NULL; break;
}
if (t) iks_insert_cdata (iks_insert (x, "show"), t, 0);
if (status) iks_insert_cdata(iks_insert (x, "status"), status, 0);
return x;
}
iks *
iks_make_iq (enum iksubtype type, const char *xmlns)
{
iks *x;
char *t = NULL;
x = iks_new ("iq");
switch (type) {
case IKS_TYPE_GET: t = "get"; break;
case IKS_TYPE_SET: t = "set"; break;
case IKS_TYPE_RESULT: t = "result"; break;
case IKS_TYPE_ERROR: t = "error"; break;
default: break;
}
if (t) iks_insert_attrib (x, "type", t);
iks_insert_attrib (iks_insert (x, "query"), "xmlns", xmlns);
return x;
}
iks *
iks_make_resource_bind (iksid *id)
{
iks *x, *y, *z;
x = iks_new("iq");
iks_insert_attrib(x, "type", "set");
y = iks_insert(x, "bind");
iks_insert_attrib(y, "xmlns", IKS_NS_XMPP_BIND);
if (id->resource && iks_strcmp(id->resource, "")) {
z = iks_insert(y, "resource");
iks_insert_cdata(z, id->resource, 0);
}
return x;
}
iks *
iks_make_session (void)
{
iks *x, *y;
x = iks_new ("iq");
iks_insert_attrib (x, "type", "set");
y = iks_insert (x, "session");
iks_insert_attrib (y, "xmlns", IKS_NS_XMPP_SESSION);
return x;
}
static int
iks_sasl_mechanisms (iks *x)
{
int sasl_mech = 0;
while (x) {
if (!iks_strcmp(iks_cdata(iks_child(x)), "DIGEST-MD5"))
sasl_mech |= IKS_STREAM_SASL_MD5;
else if (!iks_strcmp(iks_cdata(iks_child(x)), "PLAIN"))
sasl_mech |= IKS_STREAM_SASL_PLAIN;
x = iks_next_tag(x);
}
return sasl_mech;
}
int
iks_stream_features (iks *x)
{
int features = 0;
if (iks_strcmp(iks_name(x), "stream:features"))
return 0;
for (x = iks_child(x); x; x = iks_next_tag(x))
if (!iks_strcmp(iks_name(x), "starttls"))
features |= IKS_STREAM_STARTTLS;
else if (!iks_strcmp(iks_name(x), "bind"))
features |= IKS_STREAM_BIND;
else if (!iks_strcmp(iks_name(x), "session"))
features |= IKS_STREAM_SESSION;
else if (!iks_strcmp(iks_name(x), "mechanisms"))
features |= iks_sasl_mechanisms(iks_child(x));
return features;
}