1 /***************************************************************************\
2 *                                                                           *
3 *  BitlBee - An IRC to IM gateway                                           *
4 *  Jabber module - IQ packets                                               *
5 *                                                                           *
6 *  Copyright 2006-2012 Wilmer van der Gaast <wilmer@gaast.net>              *
7 *                                                                           *
8 *  This program is free software; you can redistribute it and/or modify     *
9 *  it under the terms of the GNU General Public License as published by     *
10 *  the Free Software Foundation; either version 2 of the License, or        *
11 *  (at your option) any later version.                                      *
12 *                                                                           *
13 *  This program is distributed in the hope that it will be useful,          *
14 *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
15 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
16 *  GNU General Public License for more details.                             *
17 *                                                                           *
18 *  You should have received a copy of the GNU General Public License along  *
19 *  with this program; if not, write to the Free Software Foundation, Inc.,  *
20 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.              *
21 *                                                                           *
22 \***************************************************************************/
23 
24 #include "jabber.h"
25 #include "sha1.h"
26 
27 static xt_status jabber_parse_roster(struct im_connection *ic, struct xt_node *node, struct xt_node *orig);
28 static xt_status jabber_iq_display_vcard(struct im_connection *ic, struct xt_node *node, struct xt_node *orig);
29 static xt_status jabber_gmail_handle_new(struct im_connection *ic, struct xt_node *node);
30 static xt_status jabber_iq_carbons_response(struct im_connection *ic, struct xt_node *node, struct xt_node *orig);
31 
jabber_pkt_iq(struct xt_node * node,gpointer data)32 xt_status jabber_pkt_iq(struct xt_node *node, gpointer data)
33 {
34 	struct im_connection *ic = data;
35 	struct jabber_data *jd = ic->proto_data;
36 	struct xt_node *c, *reply = NULL;
37 	char *type, *s;
38 	int st, pack = 1;
39 
40 	type = xt_find_attr(node, "type");
41 
42 	if (!type) {
43 		imcb_error(ic, "Received IQ packet without type.");
44 		imc_logout(ic, TRUE);
45 		return XT_ABORT;
46 	}
47 
48 	if (strcmp(type, "result") == 0 || strcmp(type, "error") == 0) {
49 		return jabber_cache_handle_packet(ic, node);
50 	} else if (strcmp(type, "get") == 0) {
51 		if (!((c = xt_find_node(node->children, "query")) ||
52 		      (c = xt_find_node(node->children, "ping")) ||
53 		      (c = xt_find_node(node->children, "time"))) ||
54 		    !(s = xt_find_attr(c, "xmlns"))) {
55 
56 			reply = jabber_make_error_packet(node, "service-unavailable", "cancel", NULL);
57 			st = jabber_write_packet(ic, reply);
58 			xt_free_node(reply);
59 			return st;
60 		}
61 
62 		reply = xt_new_node("query", NULL, NULL);
63 		xt_add_attr(reply, "xmlns", s);
64 
65 		/* Of course this is a very essential query to support. ;-) */
66 		if (strcmp(s, XMLNS_VERSION) == 0) {
67 			xt_add_child(reply, xt_new_node("name", set_getstr(&ic->acc->set, "user_agent"), NULL));
68 			xt_add_child(reply, xt_new_node("version", BITLBEE_VERSION, NULL));
69 		} else if (strcmp(s, XMLNS_TIME_OLD) == 0) {
70 			time_t time_ep;
71 			char buf[1024];
72 
73 			buf[sizeof(buf) - 1] = 0;
74 			time_ep = time(NULL);
75 
76 			strftime(buf, sizeof(buf) - 1, "%Y%m%dT%H:%M:%S", gmtime(&time_ep));
77 			xt_add_child(reply, xt_new_node("utc", buf, NULL));
78 
79 			strftime(buf, sizeof(buf) - 1, "%Z", localtime(&time_ep));
80 			xt_add_child(reply, xt_new_node("tz", buf, NULL));
81 		} else if (strcmp(s, XMLNS_TIME) == 0) {
82 			time_t time_ep;
83 			char buf[1024];
84 
85 			buf[sizeof(buf) - 1] = 0;
86 			time_ep = time(NULL);
87 
88 			xt_free_node(reply);
89 			reply = xt_new_node("time", NULL, NULL);
90 			xt_add_attr(reply, "xmlns", XMLNS_TIME);
91 
92 			strftime(buf, sizeof(buf) - 1, "%Y%m%dT%H:%M:%SZ", gmtime(&time_ep));
93 			xt_add_child(reply, xt_new_node("utc", buf, NULL));
94 
95 			strftime(buf, sizeof(buf) - 1, "%z", localtime(&time_ep));
96 			if (strlen(buf) >= 5) {
97 				buf[6] = '\0';
98 				buf[5] = buf[4];
99 				buf[4] = buf[3];
100 				buf[3] = ':';
101 			}
102 			xt_add_child(reply, xt_new_node("tzo", buf, NULL));
103 		} else if (strcmp(s, XMLNS_PING) == 0) {
104 			xt_free_node(reply);
105 			reply = jabber_make_packet("iq", "result", xt_find_attr(node, "from"), NULL);
106 			if ((s = xt_find_attr(node, "id"))) {
107 				xt_add_attr(reply, "id", s);
108 			}
109 			pack = 0;
110 		} else if (strcmp(s, XMLNS_DISCO_INFO) == 0) {
111 			const char *features[] = { XMLNS_DISCO_INFO,
112 				                   XMLNS_VERSION,
113 				                   XMLNS_TIME_OLD,
114 				                   XMLNS_TIME,
115 				                   XMLNS_CHATSTATES,
116 				                   XMLNS_MUC,
117 				                   XMLNS_PING,
118 				                   XMLNS_RECEIPTS,
119 				                   XMLNS_SI,
120 				                   XMLNS_BYTESTREAMS,
121 				                   XMLNS_FILETRANSFER,
122 				                   XMLNS_CARBONS,
123 				                   NULL };
124 			const char **f;
125 
126 			c = xt_new_node("identity", NULL, NULL);
127 			xt_add_attr(c, "category", "client");
128 			xt_add_attr(c, "type", "pc");
129 			xt_add_attr(c, "name", set_getstr(&ic->acc->set, "user_agent"));
130 			xt_add_child(reply, c);
131 
132 			for (f = features; *f; f++) {
133 				c = xt_new_node("feature", NULL, NULL);
134 				xt_add_attr(c, "var", *f);
135 				xt_add_child(reply, c);
136 			}
137 		} else {
138 			xt_free_node(reply);
139 			reply = jabber_make_error_packet(node, "service-unavailable", "cancel", NULL);
140 			pack = 0;
141 		}
142 	} else if (strcmp(type, "set") == 0) {
143 		if ((c = xt_find_node(node->children, "si")) &&
144 		    (s = xt_find_attr(c, "xmlns")) &&
145 		    (strcmp(s, XMLNS_SI) == 0)) {
146 			return jabber_si_handle_request(ic, node, c);
147 		} else if ((c = xt_find_node(node->children, "new-mail")) &&
148 		           (s = xt_find_attr(c, "xmlns")) &&
149 		           (strcmp(s, XMLNS_GMAILNOTIFY) == 0)) {
150 			return jabber_gmail_handle_new(ic, node);
151 		} else if (!(c = xt_find_node(node->children, "query")) ||
152 		           !(s = xt_find_attr(c, "xmlns"))) {
153 			return XT_HANDLED;
154 		} else if (strcmp(s, XMLNS_ROSTER) == 0) {
155 			/* This is a roster push. XMPP servers send this when someone
156 			   was added to (or removed from) the buddy list. AFAIK they're
157 			   sent even if we added this buddy in our own session. */
158 			int bare_len = strlen(jd->me);
159 
160 			if ((s = xt_find_attr(node, "from")) == NULL ||
161 			    (strncmp(s, jd->me, bare_len) == 0 &&
162 			     (s[bare_len] == 0 || s[bare_len] == '/'))) {
163 				jabber_parse_roster(ic, node, NULL);
164 
165 				/* Should we generate a reply here? Don't think it's
166 				   very important... */
167 			} else {
168 				imcb_log(ic, "Warning: %s tried to fake a roster push!", s ? s : "(unknown)");
169 
170 				xt_free_node(reply);
171 				reply = jabber_make_error_packet(node, "not-allowed", "cancel", NULL);
172 				pack = 0;
173 			}
174 		} else if (strcmp(s, XMLNS_BYTESTREAMS) == 0) {
175 			/* Bytestream Request (stage 2 of file transfer) */
176 			return jabber_bs_recv_request(ic, node, c);
177 		} else {
178 			xt_free_node(reply);
179 			reply = jabber_make_error_packet(node, "feature-not-implemented", "cancel", NULL);
180 			pack = 0;
181 		}
182 	}
183 
184 	/* If we recognized the xmlns and managed to generate a reply,
185 	   finish and send it. */
186 	if (reply) {
187 		/* Normally we still have to pack it into an iq-result
188 		   packet, but for errors, for example, we don't. */
189 		if (pack) {
190 			reply = jabber_make_packet("iq", "result", xt_find_attr(node, "from"), reply);
191 			if ((s = xt_find_attr(node, "id"))) {
192 				xt_add_attr(reply, "id", s);
193 			}
194 		}
195 
196 		st = jabber_write_packet(ic, reply);
197 		xt_free_node(reply);
198 		if (!st) {
199 			return XT_ABORT;
200 		}
201 	}
202 
203 	return XT_HANDLED;
204 }
205 
206 static xt_status jabber_do_iq_auth(struct im_connection *ic, struct xt_node *node, struct xt_node *orig);
207 static xt_status jabber_finish_iq_auth(struct im_connection *ic, struct xt_node *node, struct xt_node *orig);
208 
jabber_init_iq_auth(struct im_connection * ic)209 int jabber_init_iq_auth(struct im_connection *ic)
210 {
211 	struct jabber_data *jd = ic->proto_data;
212 	struct xt_node *node;
213 	int st;
214 
215 	node = xt_new_node("query", NULL, xt_new_node("username", jd->username, NULL));
216 	xt_add_attr(node, "xmlns", XMLNS_AUTH);
217 	node = jabber_make_packet("iq", "get", NULL, node);
218 
219 	jabber_cache_add(ic, node, jabber_do_iq_auth);
220 	st = jabber_write_packet(ic, node);
221 
222 	return st;
223 }
224 
jabber_do_iq_auth(struct im_connection * ic,struct xt_node * node,struct xt_node * orig)225 static xt_status jabber_do_iq_auth(struct im_connection *ic, struct xt_node *node, struct xt_node *orig)
226 {
227 	struct jabber_data *jd = ic->proto_data;
228 	struct xt_node *reply, *query;
229 	xt_status st;
230 	char *s;
231 
232 	if (!(query = xt_find_node(node->children, "query"))) {
233 		imcb_log(ic, "Warning: Received incomplete IQ packet while authenticating");
234 		imc_logout(ic, FALSE);
235 		return XT_ABORT;
236 	}
237 
238 	/* Time to authenticate ourselves! */
239 	reply = xt_new_node("query", NULL, NULL);
240 	xt_add_attr(reply, "xmlns", XMLNS_AUTH);
241 	xt_add_child(reply, xt_new_node("username", jd->username, NULL));
242 	xt_add_child(reply, xt_new_node("resource", set_getstr(&ic->acc->set, "resource"), NULL));
243 
244 	if (xt_find_node(query->children, "digest") && (s = xt_find_attr(jd->xt->root, "id"))) {
245 		/* We can do digest authentication, it seems, and of
246 		   course we prefer that. */
247 		sha1_state_t sha;
248 		char hash_hex[41];
249 		unsigned char hash[20];
250 		int i;
251 
252 		sha1_init(&sha);
253 		sha1_append(&sha, (unsigned char *) s, strlen(s));
254 		sha1_append(&sha, (unsigned char *) ic->acc->pass, strlen(ic->acc->pass));
255 		sha1_finish(&sha, hash);
256 
257 		for (i = 0; i < 20; i++) {
258 			sprintf(hash_hex + i * 2, "%02x", hash[i]);
259 		}
260 
261 		xt_add_child(reply, xt_new_node("digest", hash_hex, NULL));
262 	} else if (xt_find_node(query->children, "password")) {
263 		/* We'll have to stick with plaintext. Let's hope we're using SSL/TLS... */
264 		xt_add_child(reply, xt_new_node("password", ic->acc->pass, NULL));
265 	} else {
266 		xt_free_node(reply);
267 
268 		imcb_error(ic, "Can't find suitable authentication method");
269 		imc_logout(ic, FALSE);
270 		return XT_ABORT;
271 	}
272 
273 	reply = jabber_make_packet("iq", "set", NULL, reply);
274 	jabber_cache_add(ic, reply, jabber_finish_iq_auth);
275 	st = jabber_write_packet(ic, reply);
276 
277 	return st ? XT_HANDLED : XT_ABORT;
278 }
279 
jabber_finish_iq_auth(struct im_connection * ic,struct xt_node * node,struct xt_node * orig)280 static xt_status jabber_finish_iq_auth(struct im_connection *ic, struct xt_node *node, struct xt_node *orig)
281 {
282 	struct jabber_data *jd = ic->proto_data;
283 	char *type;
284 
285 	if (!(type = xt_find_attr(node, "type"))) {
286 		imcb_log(ic, "Warning: Received incomplete IQ packet while authenticating");
287 		imc_logout(ic, FALSE);
288 		return XT_ABORT;
289 	}
290 
291 	if (strcmp(type, "error") == 0) {
292 		imcb_error(ic, "Authentication failure");
293 		imc_logout(ic, FALSE);
294 		return XT_ABORT;
295 	} else if (strcmp(type, "result") == 0) {
296 		/* This happens when we just successfully authenticated the
297 		   old (non-SASL) way. */
298 		jd->flags |= JFLAG_AUTHENTICATED;
299 		if (!jabber_get_roster(ic)) {
300 			return XT_ABORT;
301 		}
302 		if (!jabber_iq_disco_server(ic)) {
303 			return XT_ABORT;
304 		}
305 	}
306 
307 	return XT_HANDLED;
308 }
309 
jabber_pkt_bind_sess(struct im_connection * ic,struct xt_node * node,struct xt_node * orig)310 xt_status jabber_pkt_bind_sess(struct im_connection *ic, struct xt_node *node, struct xt_node *orig)
311 {
312 	struct jabber_data *jd = ic->proto_data;
313 	struct xt_node *c, *reply = NULL;
314 	char *s;
315 
316 	if (node && (c = xt_find_node(node->children, "bind"))) {
317 		c = xt_find_node(c->children, "jid");
318 		if (!c || !c->text) {
319 			/* Server is crap, but this is no disaster. */
320 		} else if (jabber_compare_jid(jd->me, c->text) == 0) {
321 			s = strchr(c->text, '/');
322 			if (s) {
323 				*s = '\0';
324 			}
325 			jabber_set_me(ic, c->text);
326 			if (s) {
327 				*s = '/';
328 			}
329 		} else if (c && c->text_len && (s = strchr(c->text, '/')) &&
330 		           strcmp(s + 1, set_getstr(&ic->acc->set, "resource")) != 0) {
331 			imcb_log(ic, "Server changed session resource string to `%s'", s + 1);
332 		}
333 	}
334 
335 	if (jd->flags & JFLAG_WANT_BIND) {
336 		reply = xt_new_node("bind", NULL, xt_new_node("resource", set_getstr(&ic->acc->set, "resource"), NULL));
337 		xt_add_attr(reply, "xmlns", XMLNS_BIND);
338 		jd->flags &= ~JFLAG_WANT_BIND;
339 	} else if (jd->flags & JFLAG_WANT_SESSION) {
340 		reply = xt_new_node("session", NULL, NULL);
341 		xt_add_attr(reply, "xmlns", XMLNS_SESSION);
342 		jd->flags &= ~JFLAG_WANT_SESSION;
343 	}
344 
345 	if (reply != NULL) {
346 		reply = jabber_make_packet("iq", "set", NULL, reply);
347 		jabber_cache_add(ic, reply, jabber_pkt_bind_sess);
348 
349 		if (!jabber_write_packet(ic, reply)) {
350 			return XT_ABORT;
351 		}
352 		if (jd->flags & JFLAG_GMAILNOTIFY && node == NULL) {
353 			jabber_iq_query_server(ic, jd->server, XMLNS_DISCO_INFO);
354 		}
355 	} else if ((jd->flags & (JFLAG_WANT_BIND | JFLAG_WANT_SESSION)) == 0) {
356 		if (!jabber_get_roster(ic)) {
357 			return XT_ABORT;
358 		}
359 		if (!jabber_iq_disco_server(ic)) {
360 			return XT_ABORT;
361 		}
362 	}
363 
364 	return XT_HANDLED;
365 }
366 
jabber_get_roster(struct im_connection * ic)367 int jabber_get_roster(struct im_connection *ic)
368 {
369 	struct xt_node *node;
370 	int st;
371 
372 	imcb_log(ic, "Authenticated, requesting buddy list");
373 
374 	node = xt_new_node("query", NULL, NULL);
375 	xt_add_attr(node, "xmlns", XMLNS_ROSTER);
376 	node = jabber_make_packet("iq", "get", NULL, node);
377 
378 	jabber_cache_add(ic, node, jabber_parse_roster);
379 	st = jabber_write_packet(ic, node);
380 
381 	return st;
382 }
383 
384 xt_status jabber_iq_query_gmail(struct im_connection *ic);
385 
jabber_gmail_handle_new(struct im_connection * ic,struct xt_node * node)386 static xt_status jabber_gmail_handle_new(struct im_connection *ic, struct xt_node *node)
387 {
388 	struct xt_node *response;
389 	struct jabber_data *jd = ic->proto_data;
390 
391 	response = jabber_make_packet("iq", "result", jd->me, NULL);
392 
393 	jabber_cache_add(ic, response, NULL);
394 	if (!jabber_write_packet(ic, response)) {
395 		return XT_ABORT;
396 	}
397 
398 	jabber_iq_query_gmail(ic);
399 
400 	return XT_HANDLED;
401 }
402 
jabber_parse_roster(struct im_connection * ic,struct xt_node * node,struct xt_node * orig)403 static xt_status jabber_parse_roster(struct im_connection *ic, struct xt_node *node, struct xt_node *orig)
404 {
405 	struct jabber_data *jd = ic->proto_data;
406 	struct xt_node *query, *c;
407 	int initial = (orig != NULL);
408 
409 	if (!(query = xt_find_node(node->children, "query"))) {
410 		imcb_log(ic, "Warning: Received NULL roster packet");
411 		return XT_HANDLED;
412 	}
413 
414 	c = query->children;
415 	while ((c = xt_find_node(c, "item"))) {
416 		struct xt_node *group = xt_find_node(c->children, "group");
417 		char *jid = xt_find_attr(c, "jid");
418 		char *name = xt_find_attr(c, "name");
419 		char *sub = xt_find_attr(c, "subscription");
420 		char *mention_name = xt_find_attr(c, "mention_name");
421 
422 		if (jid && sub) {
423 			if ((strcmp(sub, "both") == 0 || strcmp(sub, "to") == 0)) {
424 				imcb_add_buddy(ic, jid, (group && group->text_len) ?
425 				               group->text : NULL);
426 
427 				if (name) {
428 					imcb_rename_buddy(ic, jid, name);
429 				}
430 
431 				/* This could also be used to set the full name as nick for fb/gtalk,
432 				 * but i'm keeping the old (ugly?) default behavior just to be safe */
433 				if (mention_name && (jd->flags & JFLAG_HIPCHAT)) {
434 					imcb_buddy_nick_hint(ic, jid, mention_name);
435 				}
436 			} else if (strcmp(sub, "remove") == 0) {
437 				jabber_buddy_remove_bare(ic, jid);
438 				imcb_remove_buddy(ic, jid, NULL);
439 			}
440 		}
441 
442 		c = c->next;
443 	}
444 
445 	if (initial) {
446 		imcb_connected(ic);
447 	}
448 
449 	return XT_HANDLED;
450 }
451 
jabber_get_vcard(struct im_connection * ic,char * bare_jid)452 int jabber_get_vcard(struct im_connection *ic, char *bare_jid)
453 {
454 	struct xt_node *node;
455 
456 	if (strchr(bare_jid, '/')) {
457 		return 1;       /* This was an error, but return 0 should only be done if the connection died... */
458 
459 	}
460 	node = xt_new_node("vCard", NULL, NULL);
461 	xt_add_attr(node, "xmlns", XMLNS_VCARD);
462 	node = jabber_make_packet("iq", "get", bare_jid, node);
463 
464 	jabber_cache_add(ic, node, jabber_iq_display_vcard);
465 	return jabber_write_packet(ic, node);
466 }
467 
jabber_iq_display_vcard(struct im_connection * ic,struct xt_node * node,struct xt_node * orig)468 static xt_status jabber_iq_display_vcard(struct im_connection *ic, struct xt_node *node, struct xt_node *orig)
469 {
470 	struct xt_node *vc, *c, *sc; /* subchild, ic is already in use ;-) */
471 	GString *reply;
472 	char *s;
473 
474 	if ((s = xt_find_attr(node, "type")) == NULL ||
475 	    strcmp(s, "result") != 0 ||
476 	    (vc = xt_find_node(node->children, "vCard")) == NULL) {
477 		s = xt_find_attr(orig, "to");   /* If this returns NULL something's wrong.. */
478 		imcb_log(ic, "Could not retrieve vCard of %s", s ? s : "(NULL)");
479 		return XT_HANDLED;
480 	}
481 
482 	s = xt_find_attr(orig, "to");
483 	reply = g_string_new("vCard information for ");
484 	reply = g_string_append(reply, s ? s : "(NULL)");
485 	reply = g_string_append(reply, ":\n");
486 
487 	/* I hate this format, I really do... */
488 
489 	if ((c = xt_find_node(vc->children, "FN")) && c->text_len) {
490 		g_string_append_printf(reply, "Name: %s\n", c->text);
491 	}
492 
493 	if ((c = xt_find_node(vc->children, "N")) && c->children) {
494 		reply = g_string_append(reply, "Full name:");
495 
496 		if ((sc = xt_find_node(c->children, "PREFIX")) && sc->text_len) {
497 			g_string_append_printf(reply, " %s", sc->text);
498 		}
499 		if ((sc = xt_find_node(c->children, "GIVEN")) && sc->text_len) {
500 			g_string_append_printf(reply, " %s", sc->text);
501 		}
502 		if ((sc = xt_find_node(c->children, "MIDDLE")) && sc->text_len) {
503 			g_string_append_printf(reply, " %s", sc->text);
504 		}
505 		if ((sc = xt_find_node(c->children, "FAMILY")) && sc->text_len) {
506 			g_string_append_printf(reply, " %s", sc->text);
507 		}
508 		if ((sc = xt_find_node(c->children, "SUFFIX")) && sc->text_len) {
509 			g_string_append_printf(reply, " %s", sc->text);
510 		}
511 
512 		reply = g_string_append_c(reply, '\n');
513 	}
514 
515 	if ((c = xt_find_node(vc->children, "NICKNAME")) && c->text_len) {
516 		g_string_append_printf(reply, "Nickname: %s\n", c->text);
517 	}
518 
519 	if ((c = xt_find_node(vc->children, "BDAY")) && c->text_len) {
520 		g_string_append_printf(reply, "Date of birth: %s\n", c->text);
521 	}
522 
523 	/* Slightly alternative use of for... ;-) */
524 	for (c = vc->children; (c = xt_find_node(c, "EMAIL")); c = c->next) {
525 		if ((sc = xt_find_node(c->children, "USERID")) == NULL || sc->text_len == 0) {
526 			continue;
527 		}
528 
529 		if (xt_find_node(c->children, "HOME")) {
530 			s = "Home";
531 		} else if (xt_find_node(c->children, "WORK")) {
532 			s = "Work";
533 		} else {
534 			s = "Misc.";
535 		}
536 
537 		g_string_append_printf(reply, "%s e-mail address: %s\n", s, sc->text);
538 	}
539 
540 	if ((c = xt_find_node(vc->children, "URL")) && c->text_len) {
541 		g_string_append_printf(reply, "Homepage: %s\n", c->text);
542 	}
543 
544 	/* Slightly alternative use of for... ;-) */
545 	for (c = vc->children; (c = xt_find_node(c, "ADR")); c = c->next) {
546 		if (xt_find_node(c->children, "HOME")) {
547 			s = "Home";
548 		} else if (xt_find_node(c->children, "WORK")) {
549 			s = "Work";
550 		} else {
551 			s = "Misc.";
552 		}
553 
554 		g_string_append_printf(reply, "%s address: ", s);
555 
556 		if ((sc = xt_find_node(c->children, "STREET")) && sc->text_len) {
557 			g_string_append_printf(reply, "%s ", sc->text);
558 		}
559 		if ((sc = xt_find_node(c->children, "EXTADR")) && sc->text_len) {
560 			g_string_append_printf(reply, "%s, ", sc->text);
561 		}
562 		if ((sc = xt_find_node(c->children, "PCODE")) && sc->text_len) {
563 			g_string_append_printf(reply, "%s, ", sc->text);
564 		}
565 		if ((sc = xt_find_node(c->children, "LOCALITY")) && sc->text_len) {
566 			g_string_append_printf(reply, "%s, ", sc->text);
567 		}
568 		if ((sc = xt_find_node(c->children, "REGION")) && sc->text_len) {
569 			g_string_append_printf(reply, "%s, ", sc->text);
570 		}
571 		if ((sc = xt_find_node(c->children, "CTRY")) && sc->text_len) {
572 			g_string_append_printf(reply, "%s", sc->text);
573 		}
574 
575 		if (reply->str[reply->len - 2] == ',') {
576 			reply = g_string_truncate(reply, reply->len - 2);
577 		}
578 
579 		reply = g_string_append_c(reply, '\n');
580 	}
581 
582 	for (c = vc->children; (c = xt_find_node(c, "TEL")); c = c->next) {
583 		if ((sc = xt_find_node(c->children, "NUMBER")) == NULL || sc->text_len == 0) {
584 			continue;
585 		}
586 
587 		if (xt_find_node(c->children, "HOME")) {
588 			s = "Home";
589 		} else if (xt_find_node(c->children, "WORK")) {
590 			s = "Work";
591 		} else {
592 			s = "Misc.";
593 		}
594 
595 		g_string_append_printf(reply, "%s phone number: %s\n", s, sc->text);
596 	}
597 
598 	if ((c = xt_find_node(vc->children, "DESC")) && c->text_len) {
599 		g_string_append_printf(reply, "Other information:\n%s", c->text);
600 	}
601 
602 	/* *sigh* */
603 
604 	imcb_log(ic, "%s", reply->str);
605 	g_string_free(reply, TRUE);
606 
607 	return XT_HANDLED;
608 }
609 
610 static xt_status jabber_add_to_roster_callback(struct im_connection *ic, struct xt_node *node, struct xt_node *orig);
611 
jabber_add_to_roster(struct im_connection * ic,const char * handle,const char * name,const char * group)612 int jabber_add_to_roster(struct im_connection *ic, const char *handle, const char *name, const char *group)
613 {
614 	struct xt_node *node;
615 	int st;
616 
617 	/* Build the item entry */
618 	node = xt_new_node("item", NULL, NULL);
619 	xt_add_attr(node, "jid", handle);
620 	if (name) {
621 		xt_add_attr(node, "name", name);
622 	}
623 	if (group) {
624 		xt_add_child(node, xt_new_node("group", group, NULL));
625 	}
626 
627 	/* And pack it into a roster-add packet */
628 	node = xt_new_node("query", NULL, node);
629 	xt_add_attr(node, "xmlns", XMLNS_ROSTER);
630 	node = jabber_make_packet("iq", "set", NULL, node);
631 	jabber_cache_add(ic, node, jabber_add_to_roster_callback);
632 
633 	st = jabber_write_packet(ic, node);
634 
635 	return st;
636 }
637 
jabber_add_to_roster_callback(struct im_connection * ic,struct xt_node * node,struct xt_node * orig)638 static xt_status jabber_add_to_roster_callback(struct im_connection *ic, struct xt_node *node, struct xt_node *orig)
639 {
640 	char *s, *jid = NULL;
641 	struct xt_node *c;
642 
643 	if ((c = xt_find_node(orig->children, "query")) &&
644 	    (c = xt_find_node(c->children, "item")) &&
645 	    (jid = xt_find_attr(c, "jid")) &&
646 	    (s = xt_find_attr(node, "type")) &&
647 	    strcmp(s, "result") == 0) {
648 		if (bee_user_by_handle(ic->bee, ic, jid) == NULL) {
649 			imcb_add_buddy(ic, jid, NULL);
650 		}
651 	} else {
652 		imcb_log(ic, "Error while adding `%s' to your contact list.",
653 		         jid ? jid : "(unknown handle)");
654 	}
655 
656 	return XT_HANDLED;
657 }
658 
jabber_remove_from_roster(struct im_connection * ic,char * handle)659 int jabber_remove_from_roster(struct im_connection *ic, char *handle)
660 {
661 	struct xt_node *node;
662 	int st;
663 
664 	/* Build the item entry */
665 	node = xt_new_node("item", NULL, NULL);
666 	xt_add_attr(node, "jid", handle);
667 	xt_add_attr(node, "subscription", "remove");
668 
669 	/* And pack it into a roster-add packet */
670 	node = xt_new_node("query", NULL, node);
671 	xt_add_attr(node, "xmlns", XMLNS_ROSTER);
672 	node = jabber_make_packet("iq", "set", NULL, node);
673 
674 	st = jabber_write_packet(ic, node);
675 
676 	xt_free_node(node);
677 	return st;
678 }
679 
680 xt_status jabber_iq_parse_features(struct im_connection *ic, struct xt_node *node, struct xt_node *orig);
681 
jabber_iq_query_features(struct im_connection * ic,char * bare_jid)682 xt_status jabber_iq_query_features(struct im_connection *ic, char *bare_jid)
683 {
684 	struct xt_node *node, *query;
685 	struct jabber_buddy *bud;
686 
687 	if ((bud = jabber_buddy_by_jid(ic, bare_jid, 0)) == NULL) {
688 		/* Who cares about the unknown... */
689 		imcb_log(ic, "Couldn't find buddy: %s", bare_jid);
690 		return XT_HANDLED;
691 	}
692 
693 	if (bud->features) { /* been here already */
694 		return XT_HANDLED;
695 	}
696 
697 	node = xt_new_node("query", NULL, NULL);
698 	xt_add_attr(node, "xmlns", XMLNS_DISCO_INFO);
699 
700 	if (!(query = jabber_make_packet("iq", "get", bare_jid, node))) {
701 		imcb_log(ic, "WARNING: Couldn't generate feature query");
702 		xt_free_node(node);
703 		return XT_HANDLED;
704 	}
705 
706 	jabber_cache_add(ic, query, jabber_iq_parse_features);
707 
708 	return jabber_write_packet(ic, query) ? XT_HANDLED : XT_ABORT;
709 }
710 
jabber_iq_parse_features(struct im_connection * ic,struct xt_node * node,struct xt_node * orig)711 xt_status jabber_iq_parse_features(struct im_connection *ic, struct xt_node *node, struct xt_node *orig)
712 {
713 	struct xt_node *c;
714 	struct jabber_buddy *bud;
715 	char *feature, *xmlns, *from;
716 
717 	if (!(from = xt_find_attr(node, "from")) ||
718 	    !(c = xt_find_node(node->children, "query")) ||
719 	    !(xmlns = xt_find_attr(c, "xmlns")) ||
720 	    !(strcmp(xmlns, XMLNS_DISCO_INFO) == 0)) {
721 		imcb_log(ic, "WARNING: Received incomplete IQ-result packet for discover");
722 		return XT_HANDLED;
723 	}
724 	if ((bud = jabber_buddy_by_jid(ic, from, 0)) == NULL) {
725 		/* Who cares about the unknown... */
726 		imcb_log(ic, "Couldn't find buddy: %s", from);
727 		return XT_HANDLED;
728 	}
729 
730 	c = c->children;
731 	while ((c = xt_find_node(c, "feature"))) {
732 		feature = xt_find_attr(c, "var");
733 		if (feature) {
734 			bud->features = g_slist_append(bud->features, g_strdup(feature));
735 		}
736 		c = c->next;
737 	}
738 
739 	return XT_HANDLED;
740 }
741 
742 xt_status jabber_iq_parse_gmail(struct im_connection *ic, struct xt_node *node, struct xt_node *orig);
743 
jabber_iq_query_gmail(struct im_connection * ic)744 xt_status jabber_iq_query_gmail(struct im_connection *ic)
745 {
746 	struct xt_node *node, *query;
747 	struct jabber_data *jd = ic->proto_data;
748 
749 	node = xt_new_node("query", NULL, NULL);
750 	xt_add_attr(node, "xmlns", XMLNS_GMAILNOTIFY);
751 	if (jd->gmail_time) {
752 		char *formatted = g_strdup_printf("%" G_GUINT64_FORMAT, (jd->gmail_time + 1));
753 		xt_add_attr(node, "newer-than-time", formatted);
754 		g_free(formatted);
755 	}
756 	if (jd->gmail_tid) {
757 		xt_add_attr(node, "newer-than-tid", jd->gmail_tid);
758 	}
759 
760 	if (!(query = jabber_make_packet("iq", "get", jd->me, node))) {
761 		imcb_log(ic, "WARNING: Couldn't generate server query");
762 		xt_free_node(node);
763 	}
764 
765 	jabber_cache_add(ic, query, jabber_iq_parse_gmail);
766 
767 	return jabber_write_packet(ic, query) ? XT_HANDLED : XT_ABORT;
768 }
769 
770 xt_status jabber_iq_parse_server_features(struct im_connection *ic, struct xt_node *node, struct xt_node *orig);
771 
jabber_iq_query_server(struct im_connection * ic,char * jid,char * xmlns)772 xt_status jabber_iq_query_server(struct im_connection *ic, char *jid, char *xmlns)
773 {
774 	struct xt_node *node, *query;
775 	struct jabber_data *jd = ic->proto_data;
776 
777 	node = xt_new_node("query", NULL, NULL);
778 	xt_add_attr(node, "xmlns", xmlns);
779 
780 	if (!(query = jabber_make_packet("iq", "get", jid, node))) {
781 		imcb_log(ic, "WARNING: Couldn't generate server query");
782 		xt_free_node(node);
783 	}
784 
785 	jd->have_streamhosts--;
786 	jabber_cache_add(ic, query, jabber_iq_parse_server_features);
787 
788 	return jabber_write_packet(ic, query) ? XT_HANDLED : XT_ABORT;
789 }
790 
jabber_iq_parse_gmail(struct im_connection * ic,struct xt_node * node,struct xt_node * orig)791 xt_status jabber_iq_parse_gmail(struct im_connection *ic, struct xt_node *node, struct xt_node *orig)
792 {
793 	struct xt_node *c;
794 	struct jabber_data *jd = ic->proto_data;
795 	char *xmlns, *from;
796 	guint64 l_time = 0;
797 	char *tid = NULL;
798 	int max = 0;
799 
800 	if (!(c = xt_find_node(node->children, "mailbox")) ||
801 	    !(from = xt_find_attr(node, "from")) ||
802 	    !(xmlns = xt_find_attr(c, "xmlns")) ||
803 	    (g_strcmp0(xmlns, XMLNS_GMAILNOTIFY) != 0)) {
804 		imcb_log(ic, "WARNING: Received incomplete mailbox packet for gmail notify");
805 		return XT_HANDLED;
806 	}
807 
808 	max = set_getint(&ic->acc->set, "mail_notifications_limit");
809 	c = c->children;
810 
811 	while ((max-- > 0) && (c = xt_find_node(c, "mail-thread-info"))) {
812 		struct xt_node *s;
813 		char *subject = "<no subject>";
814 		char *sender = "<no sender>";
815 		guint64 t_time;
816 
817 		t_time = g_ascii_strtoull(xt_find_attr(c, "date"), NULL, 10);
818 		if (t_time && t_time > l_time) {
819 			l_time = t_time;
820 			tid = xt_find_attr(c, "tid");
821 		}
822 
823 		if ((s = xt_find_node(c->children, "senders")) &&
824 		    (s = xt_find_node_by_attr(s->children, "sender", "unread", "1"))) {
825 			sender = xt_find_attr(s, "name");
826 		}
827 
828 		if ((s = xt_find_node(c->children, "subject")) && s->text) {
829 			subject = s->text;
830 		}
831 
832 		imcb_notify_email(ic, "New mail from %s: %s", sender, subject);
833 
834 		c = c->next;
835 	}
836 
837 	if (l_time && (!jd->gmail_time || l_time > jd->gmail_time)) {
838 		jd->gmail_time = l_time;
839 		if (tid) {
840 			g_free(jd->gmail_tid);
841 			jd->gmail_tid = g_strdup(tid);
842 		}
843 	}
844 
845 	return XT_HANDLED;
846 }
847 
848 /*
849  * Query the server for "items", query each "item" for identities, query each "item" that's a proxy for it's bytestream info
850  */
jabber_iq_parse_server_features(struct im_connection * ic,struct xt_node * node,struct xt_node * orig)851 xt_status jabber_iq_parse_server_features(struct im_connection *ic, struct xt_node *node, struct xt_node *orig)
852 {
853 	struct xt_node *c;
854 	struct jabber_data *jd = ic->proto_data;
855 	char *xmlns, *from;
856 
857 	if (!(c = xt_find_node(node->children, "query")) ||
858 	    !(from = xt_find_attr(node, "from")) ||
859 	    !(xmlns = xt_find_attr(c, "xmlns"))) {
860 		imcb_log(ic, "WARNING: Received incomplete IQ-result packet for discover");
861 		return XT_HANDLED;
862 	}
863 
864 	jd->have_streamhosts++;
865 
866 	if (strcmp(xmlns, XMLNS_DISCO_ITEMS) == 0) {
867 		char *itemjid;
868 
869 		/* answer from server */
870 
871 		c = c->children;
872 		while ((c = xt_find_node(c, "item"))) {
873 			itemjid = xt_find_attr(c, "jid");
874 
875 			if (itemjid) {
876 				jabber_iq_query_server(ic, itemjid, XMLNS_DISCO_INFO);
877 			}
878 
879 			c = c->next;
880 		}
881 	} else if (strcmp(xmlns, XMLNS_DISCO_INFO) == 0) {
882 		char *category, *type;
883 
884 		/* answer from potential proxy */
885 
886 		c = c->children;
887 		while ((c = xt_find_node(c, "identity"))) {
888 			category = xt_find_attr(c, "category");
889 			type = xt_find_attr(c, "type");
890 
891 			if (type && (strcmp(type, "bytestreams") == 0) &&
892 			    category && (strcmp(category, "proxy") == 0)) {
893 				jabber_iq_query_server(ic, from, XMLNS_BYTESTREAMS);
894 			}
895 
896 			c = c->next;
897 		}
898 
899 		if (jd->flags & JFLAG_GMAILNOTIFY) {
900 			/* search for gmail notification feature */
901 			c = xt_find_node(node->children, "query");
902 			c = c->children;
903 			while ((c = xt_find_node(c, "feature"))) {
904 				if (strcmp(xt_find_attr(c, "var"), XMLNS_GMAILNOTIFY) == 0) {
905 					jabber_iq_query_gmail(ic);
906 				}
907 				c = c->next;
908 			}
909 		}
910 
911 	} else if (strcmp(xmlns, XMLNS_BYTESTREAMS) == 0) {
912 		char *host, *jid, *port_s;
913 		int port;
914 
915 		/* answer from proxy */
916 
917 		if ((c = xt_find_node(c->children, "streamhost")) &&
918 		    (host = xt_find_attr(c, "host")) &&
919 		    (port_s = xt_find_attr(c, "port")) &&
920 		    (sscanf(port_s, "%d", &port) == 1) &&
921 		    (jid = xt_find_attr(c, "jid"))) {
922 			jabber_streamhost_t *sh = g_new0(jabber_streamhost_t, 1);
923 
924 			sh->jid = g_strdup(jid);
925 			sh->host = g_strdup(host);
926 			g_snprintf(sh->port, sizeof(sh->port), "%u", port);
927 
928 			imcb_log(ic, "Proxy found: jid %s host %s port %u", jid, host, port);
929 			jd->streamhosts = g_slist_append(jd->streamhosts, sh);
930 		}
931 	}
932 
933 	if (jd->have_streamhosts == 0) {
934 		jd->have_streamhosts++;
935 	}
936 
937 	return XT_HANDLED;
938 }
939 
940 static xt_status jabber_iq_version_response(struct im_connection *ic,
941                                             struct xt_node *node, struct xt_node *orig);
942 
jabber_iq_version_send(struct im_connection * ic,struct jabber_buddy * bud,void * data)943 void jabber_iq_version_send(struct im_connection *ic, struct jabber_buddy *bud, void *data)
944 {
945 	struct xt_node *node, *query;
946 
947 	node = xt_new_node("query", NULL, NULL);
948 	xt_add_attr(node, "xmlns", XMLNS_VERSION);
949 	query = jabber_make_packet("iq", "get", bud->full_jid, node);
950 	jabber_cache_add(ic, query, jabber_iq_version_response);
951 
952 	jabber_write_packet(ic, query);
953 }
954 
jabber_iq_version_response(struct im_connection * ic,struct xt_node * node,struct xt_node * orig)955 static xt_status jabber_iq_version_response(struct im_connection *ic,
956                                             struct xt_node *node, struct xt_node *orig)
957 {
958 	struct xt_node *query;
959 	GString *rets;
960 	char *s;
961 	char *ret[2] = {};
962 	bee_user_t *bu;
963 	struct jabber_buddy *bud = NULL;
964 
965 	if ((s = xt_find_attr(node, "from")) &&
966 	    (bud = jabber_buddy_by_jid(ic, s, 0)) &&
967 	    (query = xt_find_node(node->children, "query")) &&
968 	    (bu = bee_user_by_handle(ic->bee, ic, bud->bare_jid))) {
969 		rets = g_string_new("Resource ");
970 		g_string_append(rets, bud->resource);
971 	} else {
972 		return XT_HANDLED;
973 	}
974 
975 	for (query = query->children; query; query = query->next) {
976 		if (query->text_len > 0) {
977 			g_string_append_printf(rets, " %s: %s,", query->name, query->text);
978 		}
979 	}
980 
981 	g_string_truncate(rets, rets->len - 1);
982 	ret[0] = rets->str;
983 	imcb_buddy_action_response(bu, "VERSION", ret, NULL);
984 	g_string_free(rets, TRUE);
985 
986 	return XT_HANDLED;
987 }
988 
989 static xt_status jabber_iq_disco_server_response(struct im_connection *ic,
990                                                  struct xt_node *node, struct xt_node *orig);
991 
jabber_iq_disco_server(struct im_connection * ic)992 int jabber_iq_disco_server(struct im_connection *ic)
993 {
994 	struct xt_node *node, *iq;
995 	struct jabber_data *jd = ic->proto_data;
996 
997 	node = xt_new_node("query", NULL, NULL);
998 	xt_add_attr(node, "xmlns", XMLNS_DISCO_INFO);
999 	iq = jabber_make_packet("iq", "get", jd->server, node);
1000 
1001 	jabber_cache_add(ic, iq, jabber_iq_disco_server_response);
1002 	return jabber_write_packet(ic, iq);
1003 }
1004 
jabber_iq_disco_server_response(struct im_connection * ic,struct xt_node * node,struct xt_node * orig)1005 static xt_status jabber_iq_disco_server_response(struct im_connection *ic,
1006                                                  struct xt_node *node, struct xt_node *orig)
1007 {
1008 	struct jabber_data *jd = ic->proto_data;
1009 	struct xt_node *query, *id;
1010 
1011 	if (!(query = xt_find_node(node->children, "query"))) {
1012 		return XT_HANDLED;
1013 	}
1014 
1015 	if (xt_find_node_by_attr(query->children, "feature", "var", XMLNS_CARBONS) &&
1016 	    set_getbool(&ic->acc->set, "carbons")) {
1017 
1018 		struct xt_node *enable, *iq;
1019 
1020 		enable = xt_new_node("enable", NULL, NULL);
1021 		xt_add_attr(enable, "xmlns", XMLNS_CARBONS);
1022 		iq = jabber_make_packet("iq", "set", NULL, enable);
1023 
1024 		jabber_cache_add(ic, iq, jabber_iq_carbons_response);
1025 		jabber_write_packet(ic, iq);
1026 	}
1027 
1028 	if ((id = xt_find_node(query->children, "identity"))) {
1029 		char *cat, *type, *name;
1030 
1031 		if (!(cat = xt_find_attr(id, "category")) ||
1032 		    !(type = xt_find_attr(id, "type")) ||
1033 		    !(name = xt_find_attr(id, "name"))) {
1034 			return XT_HANDLED;
1035 		}
1036 
1037 		if (strcmp(cat, "server") == 0 && strcmp(type, "im") == 0 &&
1038 		    strstr(name, "Google") != NULL) {
1039 			jd->flags |= JFLAG_GTALK;
1040 		}
1041 	}
1042 
1043 	return XT_HANDLED;
1044 }
1045 
jabber_iq_carbons_response(struct im_connection * ic,struct xt_node * node,struct xt_node * orig)1046 static xt_status jabber_iq_carbons_response(struct im_connection *ic,
1047                                             struct xt_node *node, struct xt_node *orig)
1048 {
1049 	struct jabber_error *err;
1050 
1051 	if ((err = jabber_error_parse(xt_find_node(node->children, "error"), XMLNS_STANZA_ERROR))) {
1052 		imcb_error(ic, "Error enabling carbons: %s%s%s",
1053 		           err->code, err->text ? ": " : "", err->text ? err->text : "");
1054 		jabber_error_free(err);
1055 	} else {
1056 		imcb_log(ic, "Carbons enabled");
1057 	}
1058 
1059 	return XT_HANDLED;
1060 }
1061 
1062 xt_status jabber_iq_disco_muc_response(struct im_connection *ic, struct xt_node *node, struct xt_node *orig);
1063 
jabber_iq_disco_muc(struct im_connection * ic,const char * muc_server)1064 int jabber_iq_disco_muc(struct im_connection *ic, const char *muc_server)
1065 {
1066 	struct xt_node *node;
1067 	int st;
1068 
1069 	node = xt_new_node("query", NULL, NULL);
1070 	xt_add_attr(node, "xmlns", XMLNS_DISCO_ITEMS);
1071 	node = jabber_make_packet("iq", "get", (char *) muc_server, node);
1072 
1073 	jabber_cache_add(ic, node, jabber_iq_disco_muc_response);
1074 	st = jabber_write_packet(ic, node);
1075 
1076 	return st;
1077 }
1078 
jabber_iq_disco_muc_response(struct im_connection * ic,struct xt_node * node,struct xt_node * orig)1079 xt_status jabber_iq_disco_muc_response(struct im_connection *ic, struct xt_node *node, struct xt_node *orig)
1080 {
1081 	struct xt_node *query, *c;
1082 	struct jabber_error *err;
1083 	GSList *rooms =  NULL;
1084 
1085 	if ((err = jabber_error_parse(xt_find_node(node->children, "error"), XMLNS_STANZA_ERROR))) {
1086 		imcb_error(ic, "The server replied with an error: %s%s%s",
1087 		           err->code, err->text ? ": " : "", err->text ? err->text : "");
1088 		jabber_error_free(err);
1089 		return XT_HANDLED;
1090 	}
1091 
1092 	if (!(query = xt_find_node(node->children, "query"))) {
1093 		imcb_error(ic, "Received incomplete MUC list reply");
1094 		return XT_HANDLED;
1095 	}
1096 
1097 	c = query->children;
1098 	while ((c = xt_find_node(c, "item"))) {
1099 		char *jid = xt_find_attr(c, "jid");
1100 
1101 		if (!jid || !strchr(jid, '@')) {
1102 			c = c->next;
1103 			continue;
1104 		}
1105 
1106 		bee_chat_info_t *ci = g_new(bee_chat_info_t, 1);
1107 		ci->title = g_strdup(xt_find_attr(c, "jid"));
1108 		ci->topic = g_strdup(xt_find_attr(c, "name"));
1109 		rooms = g_slist_prepend(rooms, ci);
1110 
1111 		c = c->next;
1112 	}
1113 
1114 	imcb_chat_list_free(ic);
1115 	ic->chatlist = g_slist_reverse(rooms);
1116 	imcb_chat_list_finish(ic);
1117 
1118 	return XT_HANDLED;
1119 }
1120