diff options
Diffstat (limited to 'src/jabber.c')
-rw-r--r-- | src/jabber.c | 330 |
1 files changed, 330 insertions, 0 deletions
diff --git a/src/jabber.c b/src/jabber.c new file mode 100644 index 0000000..9143751 --- /dev/null +++ b/src/jabber.c @@ -0,0 +1,330 @@ +/* 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; +} |