summaryrefslogtreecommitdiffstats
path: root/src/jabber.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/jabber.c')
-rw-r--r--src/jabber.c330
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;
+}