1 /* iksemel (XML parser for Jabber)
2 ** Copyright (C) 2000-2003 Gurer Ozen <madcat@e-kolay.net>
3 ** This code is free software; you can redistribute it and/or
4 ** modify it under the terms of GNU Lesser General Public License.
5 */
6
7 #include "common.h"
8 #include "iksemel.h"
9
10 iksid *
iks_id_new(ikstack * s,const char * jid)11 iks_id_new (ikstack *s, const char *jid)
12 {
13 iksid *id;
14 char *src, *tmp;
15
16 /* FIXME: add jabber id validity checks to this function */
17 /* which characters are allowed in id parts? */
18
19 if (!jid) return NULL;
20 id = iks_stack_alloc (s, sizeof (iksid));
21 if (!id) return NULL;
22 memset (id, 0, sizeof (iksid));
23
24 /* skip scheme */
25 if (strncmp ("jabber:", jid, 7) == 0) jid += 7;
26
27 id->full = iks_stack_strdup (s, jid, 0);
28 src = id->full;
29
30 /* split resource */
31 tmp = strchr (src, '/');
32 if (tmp) {
33 id->partial = iks_stack_strdup (s, src, tmp - src);
34 id->resource = tmp + 1;
35 src = id->partial;
36 } else {
37 id->partial = src;
38 }
39
40 /* split user */
41 tmp = strchr (src, '@');
42 if (tmp) {
43 id->user = iks_stack_strdup (s, src, tmp - src);
44 src = ++tmp;
45 }
46
47 id->server = src;
48
49 return id;
50 }
51
52 int
iks_id_cmp(iksid * a,iksid * b,int parts)53 iks_id_cmp (iksid *a, iksid *b, int parts)
54 {
55 int diff;
56
57 if (!a || !b) return (IKS_ID_RESOURCE | IKS_ID_USER | IKS_ID_SERVER);
58 diff = 0;
59 if (parts & IKS_ID_RESOURCE && !(!a->resource && !b->resource) && iks_strcmp (a->resource, b->resource) != 0)
60 diff += IKS_ID_RESOURCE;
61 if (parts & IKS_ID_USER && !(!a->user && !b->user) && iks_strcasecmp (a->user, b->user) != 0)
62 diff += IKS_ID_USER;
63 if (parts & IKS_ID_SERVER && !(!a->server && !b->server) && iks_strcmp (a->server, b->server) != 0)
64 diff += IKS_ID_SERVER;
65 return diff;
66 }
67
68 ikspak *
iks_packet(iks * x)69 iks_packet (iks *x)
70 {
71 ikspak *pak;
72 ikstack *s;
73 char *tmp;
74
75 s = iks_stack (x);
76 pak = iks_stack_alloc (s, sizeof (ikspak));
77 if (!pak) return NULL;
78 memset (pak, 0, sizeof (ikspak));
79 pak->x = x;
80 tmp = iks_find_attrib (x, "from");
81 if (tmp) pak->from = iks_id_new (s, tmp);
82 pak->id = iks_find_attrib (x, "id");
83
84 tmp = iks_find_attrib (x, "type");
85 if (strcmp (iks_name (x), "message") == 0) {
86 pak->type = IKS_PAK_MESSAGE;
87 if (tmp) {
88 if (strcmp (tmp, "chat") == 0)
89 pak->subtype = IKS_TYPE_CHAT;
90 else if (strcmp (tmp, "groupchat") == 0)
91 pak->subtype = IKS_TYPE_GROUPCHAT;
92 else if (strcmp (tmp, "headline") == 0)
93 pak->subtype = IKS_TYPE_HEADLINE;
94 else if (strcmp (tmp, "error") == 0)
95 pak->subtype = IKS_TYPE_ERROR;
96 }
97 } else if (strcmp (iks_name (x), "presence") == 0) {
98 pak->type = IKS_PAK_S10N;
99 if (tmp) {
100 if (strcmp (tmp, "unavailable") == 0) {
101 pak->type = IKS_PAK_PRESENCE;
102 pak->subtype = IKS_TYPE_UNAVAILABLE;
103 pak->show = IKS_SHOW_UNAVAILABLE;
104 } else if (strcmp (tmp, "probe") == 0) {
105 pak->type = IKS_PAK_PRESENCE;
106 pak->subtype = IKS_TYPE_PROBE;
107 } else if(strcmp(tmp, "subscribe") == 0)
108 pak->subtype = IKS_TYPE_SUBSCRIBE;
109 else if(strcmp(tmp, "subscribed") == 0)
110 pak->subtype = IKS_TYPE_SUBSCRIBED;
111 else if(strcmp(tmp, "unsubscribe") == 0)
112 pak->subtype = IKS_TYPE_UNSUBSCRIBE;
113 else if(strcmp(tmp, "unsubscribed") == 0)
114 pak->subtype = IKS_TYPE_UNSUBSCRIBED;
115 else if(strcmp(tmp, "error") == 0)
116 pak->subtype = IKS_TYPE_ERROR;
117 } else {
118 pak->type = IKS_PAK_PRESENCE;
119 pak->subtype = IKS_TYPE_AVAILABLE;
120 tmp = iks_find_cdata (x, "show");
121 pak->show = IKS_SHOW_AVAILABLE;
122 if (tmp) {
123 if (strcmp (tmp, "chat") == 0)
124 pak->show = IKS_SHOW_CHAT;
125 else if (strcmp (tmp, "away") == 0)
126 pak->show = IKS_SHOW_AWAY;
127 else if (strcmp (tmp, "xa") == 0)
128 pak->show = IKS_SHOW_XA;
129 else if (strcmp (tmp, "dnd") == 0)
130 pak->show = IKS_SHOW_DND;
131 }
132 }
133 } else if (strcmp (iks_name (x), "iq") == 0) {
134 iks *q;
135 pak->type = IKS_PAK_IQ;
136 if (tmp) {
137 if (strcmp (tmp, "get") == 0)
138 pak->subtype = IKS_TYPE_GET;
139 else if (strcmp (tmp, "set") == 0)
140 pak->subtype = IKS_TYPE_SET;
141 else if (strcmp (tmp, "result") == 0)
142 pak->subtype = IKS_TYPE_RESULT;
143 else if (strcmp (tmp, "error") == 0)
144 pak->subtype = IKS_TYPE_ERROR;
145 }
146 for (q = iks_child (x); q; q = iks_next (q)) {
147 if (IKS_TAG == iks_type (q)) {
148 char *ns;
149 ns = iks_find_attrib (q, "xmlns");
150 if (ns) {
151 pak->query = q;
152 pak->ns = ns;
153 break;
154 }
155 }
156 }
157 }
158 return pak;
159 }
160
161 iks *
iks_make_auth(iksid * id,const char * pass,const char * sid)162 iks_make_auth (iksid *id, const char *pass, const char *sid)
163 {
164 iks *x, *y;
165
166 x = iks_new ("iq");
167 iks_insert_attrib (x, "type", "set");
168 y = iks_insert (x, "query");
169 iks_insert_attrib (y, "xmlns", IKS_NS_AUTH);
170 iks_insert_cdata (iks_insert (y, "username"), id->user, 0);
171 iks_insert_cdata (iks_insert (y, "resource"), id->resource, 0);
172 if(sid) {
173 char buf[41];
174 iksha *sha;
175 sha = iks_sha_new ();
176 iks_sha_hash (sha, (const unsigned char*)sid, strlen (sid), 0);
177 iks_sha_hash (sha, (const unsigned char*)pass, strlen (pass), 1);
178 iks_sha_print (sha, buf);
179 iks_sha_delete (sha);
180 iks_insert_cdata (iks_insert (y, "digest"), buf, 40);
181 } else {
182 iks_insert_cdata (iks_insert (y, "password"), pass, 0);
183 }
184 return x;
185 }
186
187 iks *
iks_make_msg(enum iksubtype type,const char * to,const char * body)188 iks_make_msg (enum iksubtype type, const char *to, const char *body)
189 {
190 iks *x;
191 char *t = NULL;
192
193 x = iks_new ("message");
194 switch (type) {
195 case IKS_TYPE_CHAT: t = "chat"; break;
196 case IKS_TYPE_GROUPCHAT: t = "groupchat"; break;
197 case IKS_TYPE_HEADLINE: t = "headline"; break;
198 default: break;
199 }
200 if (t) iks_insert_attrib (x, "type", t);
201 if (to) iks_insert_attrib (x, "to", to);
202 if (body) iks_insert_cdata (iks_insert (x, "body"), body, 0);
203 return x;
204 }
205
206 iks *
iks_make_s10n(enum iksubtype type,const char * to,const char * msg)207 iks_make_s10n (enum iksubtype type, const char *to, const char *msg)
208 {
209 iks *x;
210 char *t;
211
212 x = iks_new ("presence");
213 switch (type) {
214 case IKS_TYPE_SUBSCRIBE: t = "subscribe"; break;
215 case IKS_TYPE_SUBSCRIBED: t = "subscribed"; break;
216 case IKS_TYPE_UNSUBSCRIBE: t = "unsubscribe"; break;
217 case IKS_TYPE_UNSUBSCRIBED: t = "unsubscribed"; break;
218 case IKS_TYPE_PROBE: t = "probe"; break;
219 default: t = NULL; break;
220 }
221 if (t) iks_insert_attrib (x, "type", t);
222 if (to) iks_insert_attrib (x, "to", to);
223 if (msg) iks_insert_cdata(iks_insert (x, "status"), msg, 0);
224 return x;
225 }
226
227 iks *
iks_make_pres(enum ikshowtype show,const char * status)228 iks_make_pres (enum ikshowtype show, const char *status)
229 {
230 iks *x;
231 char *t;
232
233 x = iks_new ("presence");
234 switch (show) {
235 case IKS_SHOW_CHAT: t = "chat"; break;
236 case IKS_SHOW_AWAY: t = "away"; break;
237 case IKS_SHOW_XA: t = "xa"; break;
238 case IKS_SHOW_DND: t = "dnd"; break;
239 case IKS_SHOW_UNAVAILABLE:
240 t = NULL;
241 iks_insert_attrib (x, "type", "unavailable");
242 break;
243 default: t = NULL; break;
244 }
245 if (t) iks_insert_cdata (iks_insert (x, "show"), t, 0);
246 if (status) iks_insert_cdata(iks_insert (x, "status"), status, 0);
247 return x;
248 }
249
250 iks *
iks_make_iq(enum iksubtype type,const char * xmlns)251 iks_make_iq (enum iksubtype type, const char *xmlns)
252 {
253 iks *x;
254 char *t = NULL;
255
256 x = iks_new ("iq");
257 switch (type) {
258 case IKS_TYPE_GET: t = "get"; break;
259 case IKS_TYPE_SET: t = "set"; break;
260 case IKS_TYPE_RESULT: t = "result"; break;
261 case IKS_TYPE_ERROR: t = "error"; break;
262 default: break;
263 }
264 if (t) iks_insert_attrib (x, "type", t);
265 iks_insert_attrib (iks_insert (x, "query"), "xmlns", xmlns);
266
267 return x;
268 }
269
270 iks *
iks_make_resource_bind(iksid * id)271 iks_make_resource_bind (iksid *id)
272 {
273 iks *x, *y, *z;
274
275 x = iks_new("iq");
276 iks_insert_attrib(x, "type", "set");
277 y = iks_insert(x, "bind");
278 iks_insert_attrib(y, "xmlns", IKS_NS_XMPP_BIND);
279 if (id->resource && iks_strcmp(id->resource, "")) {
280 z = iks_insert(y, "resource");
281 iks_insert_cdata(z, id->resource, 0);
282 }
283 return x;
284 }
285
286 iks *
iks_make_session(void)287 iks_make_session (void)
288 {
289 iks *x, *y;
290
291 x = iks_new ("iq");
292 iks_insert_attrib (x, "type", "set");
293 y = iks_insert (x, "session");
294 iks_insert_attrib (y, "xmlns", IKS_NS_XMPP_SESSION);
295 return x;
296 }
297
298 static int
iks_sasl_mechanisms(iks * x)299 iks_sasl_mechanisms (iks *x)
300 {
301 int sasl_mech = 0;
302
303 while (x) {
304 if (!iks_strcmp(iks_cdata(iks_child(x)), "DIGEST-MD5"))
305 sasl_mech |= IKS_STREAM_SASL_MD5;
306 else if (!iks_strcmp(iks_cdata(iks_child(x)), "PLAIN"))
307 sasl_mech |= IKS_STREAM_SASL_PLAIN;
308 x = iks_next_tag(x);
309 }
310 return sasl_mech;
311 }
312
313 int
iks_stream_features(iks * x)314 iks_stream_features (iks *x)
315 {
316 int features = 0;
317
318 if (iks_strcmp(iks_name(x), "stream:features"))
319 return 0;
320 for (x = iks_child(x); x; x = iks_next_tag(x))
321 if (!iks_strcmp(iks_name(x), "starttls"))
322 features |= IKS_STREAM_STARTTLS;
323 else if (!iks_strcmp(iks_name(x), "bind"))
324 features |= IKS_STREAM_BIND;
325 else if (!iks_strcmp(iks_name(x), "session"))
326 features |= IKS_STREAM_SESSION;
327 else if (!iks_strcmp(iks_name(x), "mechanisms"))
328 features |= iks_sasl_mechanisms(iks_child(x));
329 return features;
330 }
331