1 /***************************************************************************\
2 *                                                                           *
3 *  BitlBee - An IRC to IM gateway                                           *
4 *  Jabber module - Misc. stuff                                              *
5 *                                                                           *
6 *  Copyright 2006-2010 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 "md5.h"
26 #include "base64.h"
27 
28 static unsigned int next_id = 1;
29 
set_eval_priority(set_t * set,char * value)30 char *set_eval_priority(set_t *set, char *value)
31 {
32 	account_t *acc = set->data;
33 	int i;
34 
35 	if (sscanf(value, "%d", &i) == 1) {
36 		/* Priority is a signed 8-bit integer, according to RFC 3921. */
37 		if (i < -128 || i > 127) {
38 			return SET_INVALID;
39 		}
40 	} else {
41 		return SET_INVALID;
42 	}
43 
44 	/* Only run this stuff if the account is online ATM,
45 	   and if the setting seems to be acceptable. */
46 	if (acc->ic) {
47 		/* Although set_eval functions usually are very nice and
48 		   convenient, they have one disadvantage: If I would just
49 		   call p_s_u() now to send the new prio setting, it would
50 		   send the old setting because the set->value gets changed
51 		   after the (this) eval returns a non-NULL value.
52 
53 		   So now I can choose between implementing post-set
54 		   functions next to evals, or just do this little hack: */
55 
56 		g_free(set->value);
57 		set->value = g_strdup(value);
58 
59 		/* (Yes, sorry, I prefer the hack. :-P) */
60 
61 		presence_send_update(acc->ic);
62 	}
63 
64 	return value;
65 }
66 
set_eval_tls(set_t * set,char * value)67 char *set_eval_tls(set_t *set, char *value)
68 {
69 	if (g_strcasecmp(value, "try") == 0) {
70 		return value;
71 	} else {
72 		return set_eval_bool(set, value);
73 	}
74 }
75 
jabber_make_packet(char * name,char * type,char * to,struct xt_node * children)76 struct xt_node *jabber_make_packet(char *name, char *type, char *to, struct xt_node *children)
77 {
78 	struct xt_node *node;
79 
80 	node = xt_new_node(name, NULL, children);
81 
82 	if (type) {
83 		xt_add_attr(node, "type", type);
84 	}
85 	if (to) {
86 		xt_add_attr(node, "to", to);
87 	}
88 
89 	/* IQ packets should always have an ID, so let's generate one. It
90 	   might get overwritten by jabber_cache_add() if this packet has
91 	   to be saved until we receive a response. Cached packets get
92 	   slightly different IDs so we can recognize them. */
93 	if (strcmp(name, "iq") == 0) {
94 		char *id = g_strdup_printf("%s%05x", JABBER_PACKET_ID, (next_id++) & 0xfffff);
95 		xt_add_attr(node, "id", id);
96 		g_free(id);
97 	}
98 
99 	return node;
100 }
101 
jabber_make_error_packet(struct xt_node * orig,char * err_cond,char * err_type,char * err_code)102 struct xt_node *jabber_make_error_packet(struct xt_node *orig, char *err_cond, char *err_type, char *err_code)
103 {
104 	struct xt_node *node, *c;
105 	char *to;
106 
107 	/* Create the "defined-condition" tag. */
108 	c = xt_new_node(err_cond, NULL, NULL);
109 	xt_add_attr(c, "xmlns", XMLNS_STANZA_ERROR);
110 
111 	/* Put it in an <error> tag. */
112 	c = xt_new_node("error", NULL, c);
113 	xt_add_attr(c, "type", err_type);
114 
115 	/* Add the error code, if present */
116 	if (err_code) {
117 		xt_add_attr(c, "code", err_code);
118 	}
119 
120 	/* To make the actual error packet, we copy the original packet and
121 	   add our <error>/type="error" tag. Including the original packet
122 	   is recommended, so let's just do it. */
123 	node = xt_dup(orig);
124 	xt_add_child(node, c);
125 	xt_add_attr(node, "type", "error");
126 
127 	/* Return to sender. */
128 	if ((to = xt_find_attr(node, "from"))) {
129 		xt_add_attr(node, "to", to);
130 		xt_remove_attr(node, "from");
131 	}
132 
133 	return node;
134 }
135 
136 /* Cache a node/packet for later use. Mainly useful for IQ packets if you need
137    them when you receive the response. Use this BEFORE sending the packet so
138    it'll get a new id= tag, and do NOT free() the packet after sending it! */
jabber_cache_add(struct im_connection * ic,struct xt_node * node,jabber_cache_event func)139 void jabber_cache_add(struct im_connection *ic, struct xt_node *node, jabber_cache_event func)
140 {
141 	struct jabber_data *jd = ic->proto_data;
142 	struct jabber_cache_entry *entry = g_new0(struct jabber_cache_entry, 1);
143 	md5_state_t id_hash;
144 	md5_byte_t id_sum[16];
145 	char *id, *asc_hash;
146 
147 	next_id++;
148 
149 	id_hash = jd->cached_id_prefix;
150 	md5_append(&id_hash, (md5_byte_t *) &next_id, sizeof(next_id));
151 	md5_digest_keep(&id_hash, id_sum);
152 	asc_hash = base64_encode(id_sum, 12);
153 
154 	id = g_strdup_printf("%s%s", JABBER_CACHED_ID, asc_hash);
155 	xt_add_attr(node, "id", id);
156 	g_free(id);
157 	g_free(asc_hash);
158 
159 	entry->node = node;
160 	entry->func = func;
161 	entry->saved_at = time(NULL);
162 	g_hash_table_insert(jd->node_cache, xt_find_attr(node, "id"), entry);
163 }
164 
jabber_cache_entry_free(gpointer data)165 void jabber_cache_entry_free(gpointer data)
166 {
167 	struct jabber_cache_entry *entry = data;
168 
169 	xt_free_node(entry->node);
170 	g_free(entry);
171 }
172 
173 gboolean jabber_cache_clean_entry(gpointer key, gpointer entry, gpointer nullpointer);
174 
175 /* This one should be called from time to time (from keepalive, in this case)
176    to make sure things don't stay in the node cache forever. By marking nodes
177    during the first run and deleting marked nodes during a next run, every
178    node should be available in the cache for at least a minute (assuming the
179    function is indeed called every minute). */
jabber_cache_clean(struct im_connection * ic)180 void jabber_cache_clean(struct im_connection *ic)
181 {
182 	struct jabber_data *jd = ic->proto_data;
183 	time_t threshold = time(NULL) - JABBER_CACHE_MAX_AGE;
184 
185 	g_hash_table_foreach_remove(jd->node_cache, jabber_cache_clean_entry, &threshold);
186 }
187 
jabber_cache_clean_entry(gpointer key,gpointer entry_,gpointer threshold_)188 gboolean jabber_cache_clean_entry(gpointer key, gpointer entry_, gpointer threshold_)
189 {
190 	struct jabber_cache_entry *entry = entry_;
191 	time_t *threshold = threshold_;
192 
193 	return entry->saved_at < *threshold;
194 }
195 
jabber_cache_handle_packet(struct im_connection * ic,struct xt_node * node)196 xt_status jabber_cache_handle_packet(struct im_connection *ic, struct xt_node *node)
197 {
198 	struct jabber_data *jd = ic->proto_data;
199 	struct jabber_cache_entry *entry;
200 	char *s;
201 
202 	if ((s = xt_find_attr(node, "id")) == NULL ||
203 	    strncmp(s, JABBER_CACHED_ID, strlen(JABBER_CACHED_ID)) != 0) {
204 		/* Silently ignore it, without an ID (or a non-cache
205 		   ID) we don't know how to handle the packet and we
206 		   probably don't have to. */
207 		return XT_HANDLED;
208 	}
209 
210 	entry = g_hash_table_lookup(jd->node_cache, s);
211 
212 	if (entry == NULL) {
213 		/*
214 		There's no longer an easy way to see if we generated this
215 		one or someone else, and there's a ten-minute timeout anyway,
216 		so meh.
217 
218 		imcb_log( ic, "Warning: Received %s-%s packet with unknown/expired ID %s!",
219 		              node->name, xt_find_attr( node, "type" ) ? : "(no type)", s );
220 		*/
221 	} else if (entry->func) {
222 		return entry->func(ic, node, entry->node);
223 	}
224 
225 	return XT_HANDLED;
226 }
227 
228 const struct jabber_away_state jabber_away_state_list[] =
229 {
230 	{ "away",  "Away" },
231 	{ "chat",  "Free for Chat" },   /* WTF actually uses this? */
232 	{ "dnd",   "Do not Disturb" },
233 	{ "xa",    "Extended Away" },
234 	{ "",      NULL }
235 };
236 
jabber_away_state_by_code(char * code)237 const struct jabber_away_state *jabber_away_state_by_code(char *code)
238 {
239 	int i;
240 
241 	if (code == NULL) {
242 		return NULL;
243 	}
244 
245 	for (i = 0; jabber_away_state_list[i].full_name; i++) {
246 		if (g_strcasecmp(jabber_away_state_list[i].code, code) == 0) {
247 			return jabber_away_state_list + i;
248 		}
249 	}
250 
251 	return NULL;
252 }
253 
jabber_away_state_by_name(char * name)254 const struct jabber_away_state *jabber_away_state_by_name(char *name)
255 {
256 	int i;
257 
258 	if (name == NULL) {
259 		return NULL;
260 	}
261 
262 	for (i = 0; jabber_away_state_list[i].full_name; i++) {
263 		if (g_strcasecmp(jabber_away_state_list[i].full_name, name) == 0) {
264 			return jabber_away_state_list + i;
265 		}
266 	}
267 
268 	return NULL;
269 }
270 
271 struct jabber_buddy_ask_data {
272 	struct im_connection *ic;
273 	char *handle;
274 	char *realname;
275 };
276 
jabber_buddy_ask_yes(void * data)277 static void jabber_buddy_ask_yes(void *data)
278 {
279 	struct jabber_buddy_ask_data *bla = data;
280 
281 	presence_send_request(bla->ic, bla->handle, "subscribed");
282 
283 	imcb_ask_add(bla->ic, bla->handle, NULL);
284 
285 	g_free(bla->handle);
286 	g_free(bla);
287 }
288 
jabber_buddy_ask_no(void * data)289 static void jabber_buddy_ask_no(void *data)
290 {
291 	struct jabber_buddy_ask_data *bla = data;
292 
293 	presence_send_request(bla->ic, bla->handle, "unsubscribed");
294 
295 	g_free(bla->handle);
296 	g_free(bla);
297 }
298 
jabber_buddy_ask(struct im_connection * ic,char * handle)299 void jabber_buddy_ask(struct im_connection *ic, char *handle)
300 {
301 	struct jabber_buddy_ask_data *bla = g_new0(struct jabber_buddy_ask_data, 1);
302 	char *buf;
303 
304 	bla->ic = ic;
305 	bla->handle = g_strdup(handle);
306 
307 	buf = g_strdup_printf("The user %s wants to add you to his/her buddy list.", handle);
308 	imcb_ask(ic, buf, bla, jabber_buddy_ask_yes, jabber_buddy_ask_no);
309 	g_free(buf);
310 }
311 
312 /* Compares just the bare portions of two Jabber IDs. */
jabber_compare_jid(const char * jid1,const char * jid2)313 int jabber_compare_jid(const char *jid1, const char *jid2)
314 {
315 	int i;
316 
317 	if (!jid1 || !jid2) {
318 		return FALSE;
319 	}
320 
321 	for (i = 0;; i++) {
322 		if (jid1[i] == '\0' || jid1[i] == '/' || jid2[i] == '\0' || jid2[i] == '/') {
323 			if ((jid1[i] == '\0' || jid1[i] == '/') && (jid2[i] == '\0' || jid2[i] == '/')) {
324 				break;
325 			}
326 			return FALSE;
327 		}
328 		if (g_ascii_tolower(jid1[i]) != g_ascii_tolower(jid2[i])) {
329 			return FALSE;
330 		}
331 	}
332 
333 	return TRUE;
334 }
335 
336 /* The /resource part is case sensitive. This stops once we see a slash.
337    Returns a new string. Don't leak it! */
jabber_normalize(const char * orig)338 char *jabber_normalize(const char *orig)
339 {
340 	char *lower, *new, *s;
341 
342 	if (!(s = strchr(orig, '/'))) {
343 		return g_utf8_strdown(orig, -1);
344 	}
345 
346 	lower = g_utf8_strdown(orig, (s - orig));    /* stop in s */
347 	new = g_strconcat(lower, s, NULL);
348 	g_free(lower);
349 	return new;
350 }
351 
352 /* Similar to jabber_normalize, but works with addresses in the form
353  * resource=chatroom@example.com */
jabber_normalize_ext(const char * orig)354 char *jabber_normalize_ext(const char *orig)
355 {
356 	char *lower, *new, *s;
357 
358 	if (!(s = strchr(orig, '='))) {
359 		return g_utf8_strdown(orig, -1);
360 	}
361 
362 	lower = g_utf8_strdown(s, -1);   /* start in s */
363 
364 	*s = 0;
365 	new = g_strconcat(orig, lower, NULL);
366 	*s = '=';
367 
368 	g_free(lower);
369 	return new;
370 }
371 
372 /* Adds a buddy/resource to our list. Returns NULL if full_jid is not really a
373    FULL jid or if we already have this buddy/resource. XXX: No, great, actually
374    buddies from transports don't (usually) have resources. So we'll really have
375    to deal with that properly. Set their ->resource property to NULL. Do *NOT*
376    allow to mix this stuff, though... */
jabber_buddy_add(struct im_connection * ic,char * full_jid_)377 struct jabber_buddy *jabber_buddy_add(struct im_connection *ic, char *full_jid_)
378 {
379 	struct jabber_data *jd = ic->proto_data;
380 	struct jabber_buddy *bud, *new, *bi;
381 	char *s, *full_jid;
382 
383 	full_jid = jabber_normalize(full_jid_);
384 
385 	if ((s = strchr(full_jid, '/'))) {
386 		*s = 0;
387 	}
388 
389 	new = g_new0(struct jabber_buddy, 1);
390 
391 	if ((bud = g_hash_table_lookup(jd->buddies, full_jid))) {
392 		/* The first entry is always a bare JID. If there are more, we
393 		   should ignore the first one here. */
394 		if (bud->next) {
395 			bud = bud->next;
396 		}
397 
398 		/* If this is a transport buddy or whatever, it can't have more
399 		   than one instance, so this is always wrong: */
400 		if (s == NULL || bud->resource == NULL) {
401 			if (s) {
402 				*s = '/';
403 			}
404 			g_free(new);
405 			g_free(full_jid);
406 			return NULL;
407 		}
408 
409 		new->bare_jid = bud->bare_jid;
410 
411 		/* We already have another resource for this buddy, add the
412 		   new one to the list. */
413 		for (bi = bud; bi; bi = bi->next) {
414 			/* Check for dupes. */
415 			if (strcmp(bi->resource, s + 1) == 0) {
416 				*s = '/';
417 				g_free(new);
418 				g_free(full_jid);
419 				return NULL;
420 			}
421 			/* Append the new item to the list. */
422 			else if (bi->next == NULL) {
423 				bi->next = new;
424 				break;
425 			}
426 		}
427 	} else {
428 		new->full_jid = new->bare_jid = g_strdup(full_jid);
429 		g_hash_table_insert(jd->buddies, new->bare_jid, new);
430 
431 		if (s) {
432 			new->next = g_new0(struct jabber_buddy, 1);
433 			new->next->bare_jid = new->bare_jid;
434 			new = new->next;
435 		}
436 	}
437 
438 	if (s) {
439 		*s = '/';
440 		new->full_jid = full_jid;
441 		new->resource = strchr(new->full_jid, '/') + 1;
442 	} else {
443 		/* Let's waste some more bytes of RAM instead of to make
444 		   memory management a total disaster here. And it saves
445 		   me one g_free() call in this function. :-P */
446 		new->full_jid = full_jid;
447 	}
448 
449 	return new;
450 }
451 
452 /* Finds a buddy from our structures. Can find both full- and bare JIDs. When
453    asked for a bare JID, it uses the "resource_select" setting to see which
454    resource to pick. */
jabber_buddy_by_jid(struct im_connection * ic,char * jid_,get_buddy_flags_t flags)455 struct jabber_buddy *jabber_buddy_by_jid(struct im_connection *ic, char *jid_, get_buddy_flags_t flags)
456 {
457 	struct jabber_data *jd = ic->proto_data;
458 	struct jabber_buddy *bud, *head;
459 	char *s, *jid;
460 
461 	jid = jabber_normalize(jid_);
462 
463 	if ((s = strchr(jid, '/'))) {
464 		int bare_exists = 0;
465 
466 		*s = 0;
467 		if ((bud = g_hash_table_lookup(jd->buddies, jid))) {
468 			bare_exists = 1;
469 
470 			if (bud->next) {
471 				bud = bud->next;
472 			}
473 
474 			/* Just return the first one for this bare JID. */
475 			if (flags & GET_BUDDY_FIRST) {
476 				*s = '/';
477 				g_free(jid);
478 				return bud;
479 			}
480 
481 			/* Is this one of those no-resource buddies? */
482 			if (bud->resource == NULL) {
483 				*s = '/';
484 				g_free(jid);
485 				return NULL;
486 			}
487 
488 			/* See if there's an exact match. */
489 			for (; bud; bud = bud->next) {
490 				if (strcmp(bud->resource, s + 1) == 0) {
491 					break;
492 				}
493 			}
494 		}
495 
496 		if (bud == NULL && (flags & GET_BUDDY_CREAT) &&
497 		    (bare_exists || bee_user_by_handle(ic->bee, ic, jid))) {
498 			*s = '/';
499 			bud = jabber_buddy_add(ic, jid);
500 		}
501 
502 		g_free(jid);
503 		return bud;
504 	} else {
505 		struct jabber_buddy *best_prio, *best_time;
506 		char *set;
507 
508 		head = g_hash_table_lookup(jd->buddies, jid);
509 		bud = (head && head->next) ? head->next : head;
510 
511 		g_free(jid);
512 
513 		if (bud == NULL) {
514 			/* No match. Create it now? */
515 			return ((flags & GET_BUDDY_CREAT) &&
516 			        bee_user_by_handle(ic->bee, ic, jid_)) ?
517 			       jabber_buddy_add(ic, jid_) : NULL;
518 		} else if (bud->resource && (flags & GET_BUDDY_EXACT)) {
519 			/* We want an exact match, so in thise case there shouldn't be a /resource. */
520 			if (head != bud && head->resource == NULL) {
521 				return head;
522 			} else {
523 				return NULL;
524 			}
525 		} else if (bud->resource == NULL || bud->next == NULL) {
526 			/* No need for selection if there's only one option. */
527 			return bud;
528 		} else if (flags & GET_BUDDY_FIRST) {
529 			/* Looks like the caller doesn't care about details. */
530 			return bud;
531 		} else if (flags & GET_BUDDY_BARE) {
532 			return head;
533 		}
534 
535 		best_prio = best_time = bud;
536 		for (; bud; bud = bud->next) {
537 			if (bud->priority > best_prio->priority) {
538 				best_prio = bud;
539 			}
540 			if (bud->last_msg > best_time->last_msg) {
541 				best_time = bud;
542 			}
543 		}
544 
545 		if ((set = set_getstr(&ic->acc->set, "resource_select")) == NULL) {
546 			return NULL;
547 		} else if (strcmp(set, "priority") == 0) {
548 			return best_prio;
549 		} else if (flags & GET_BUDDY_BARE_OK) { /* && strcmp( set, "activity" ) == 0 */
550 			if (best_time->last_msg + set_getint(&ic->acc->set, "activity_timeout") >= time(NULL)) {
551 				return best_time;
552 			} else {
553 				return head;
554 			}
555 		} else {
556 			return best_time;
557 		}
558 	}
559 }
560 
561 /* I'm keeping a separate ext_jid attribute to save a JID that makes sense
562    to export to BitlBee. This is mainly for groupchats right now. It's
563    a bit of a hack, but I just think having the user nickname in the hostname
564    part of the hostmask doesn't look nice on IRC. Normally you can convert
565    a normal JID to ext_jid by swapping the part before and after the / and
566    replacing the / with a =. But there should be some stripping (@s are
567    allowed in Jabber nicks...). */
jabber_buddy_by_ext_jid(struct im_connection * ic,char * jid_,get_buddy_flags_t flags)568 struct jabber_buddy *jabber_buddy_by_ext_jid(struct im_connection *ic, char *jid_, get_buddy_flags_t flags)
569 {
570 	struct jabber_buddy *bud;
571 	char *s, *jid;
572 
573 	jid = jabber_normalize_ext(jid_);
574 
575 	if ((s = strchr(jid, '=')) == NULL) {
576 		g_free(jid);
577 		return NULL;
578 	}
579 
580 	for (bud = jabber_buddy_by_jid(ic, s + 1, GET_BUDDY_FIRST); bud; bud = bud->next) {
581 		/* Hmmm, could happen if not all people in the chat are anonymized? */
582 		if (bud->ext_jid == NULL) {
583 			continue;
584 		}
585 
586 		if (strcmp(bud->ext_jid, jid) == 0) {
587 			break;
588 		}
589 	}
590 
591 	g_free(jid);
592 
593 	return bud;
594 }
595 
596 /* Remove one specific full JID from our list. Use this when a buddy goes
597    off-line (because (s)he can still be online from a different location.
598    XXX: See above, we should accept bare JIDs too... */
jabber_buddy_remove(struct im_connection * ic,char * full_jid_)599 int jabber_buddy_remove(struct im_connection *ic, char *full_jid_)
600 {
601 	struct jabber_data *jd = ic->proto_data;
602 	struct jabber_buddy *bud, *prev = NULL, *bi;
603 	char *s, *full_jid;
604 
605 	full_jid = jabber_normalize(full_jid_);
606 
607 	if ((s = strchr(full_jid, '/'))) {
608 		*s = 0;
609 	}
610 
611 	if ((bud = g_hash_table_lookup(jd->buddies, full_jid))) {
612 		if (bud->next) {
613 			bud = (prev = bud)->next;
614 		}
615 
616 		/* If there's only one item in the list (and if the resource
617 		   matches), removing it is simple. (And the hash reference
618 		   should be removed too!) */
619 		if (bud->next == NULL &&
620 		    ((s == NULL && bud->resource == NULL) ||
621 		     (bud->resource && s && strcmp(bud->resource, s + 1) == 0))) {
622 			int st = jabber_buddy_remove_bare(ic, full_jid);
623 			g_free(full_jid);
624 			return st;
625 		} else if (s == NULL || bud->resource == NULL) {
626 			/* Tried to remove a bare JID while this JID does seem
627 			   to have resources... (Or the opposite.) *sigh* */
628 			g_free(full_jid);
629 			return 0;
630 		} else {
631 			for (bi = bud; bi; bi = (prev = bi)->next) {
632 				if (strcmp(bi->resource, s + 1) == 0) {
633 					break;
634 				}
635 			}
636 
637 			g_free(full_jid);
638 
639 			if (bi) {
640 				if (prev) {
641 					prev->next = bi->next;
642 				} else {
643 					/* Don't think this should ever happen anymore. */
644 					g_hash_table_replace(jd->buddies, bi->bare_jid, bi->next);
645 				}
646 
647 				g_free(bi->ext_jid);
648 				g_free(bi->full_jid);
649 				g_free(bi->away_message);
650 				g_free(bi);
651 
652 				return 1;
653 			} else {
654 				return 0;
655 			}
656 		}
657 	} else {
658 		g_free(full_jid);
659 		return 0;
660 	}
661 }
662 
663 /* Remove a buddy completely; removes all resources that belong to the
664    specified bare JID. Use this when removing someone from the contact
665    list, for example. */
jabber_buddy_remove_bare(struct im_connection * ic,char * bare_jid)666 int jabber_buddy_remove_bare(struct im_connection *ic, char *bare_jid)
667 {
668 	struct jabber_data *jd = ic->proto_data;
669 	struct jabber_buddy *bud, *next;
670 
671 	if (strchr(bare_jid, '/')) {
672 		return 0;
673 	}
674 
675 	if ((bud = jabber_buddy_by_jid(ic, bare_jid, GET_BUDDY_FIRST))) {
676 		/* Most important: Remove the hash reference. We don't know
677 		   this buddy anymore. */
678 		g_hash_table_remove(jd->buddies, bud->bare_jid);
679 		g_free(bud->bare_jid);
680 
681 		/* Deallocate the linked list of resources. */
682 		while (bud) {
683 			/* ext_jid && anonymous means that this buddy is
684 			   specific to one groupchat (the one we're
685 			   currently cleaning up) so it can be deleted
686 			   completely. */
687 			if (bud->ext_jid && bud->flags & JBFLAG_IS_ANONYMOUS) {
688 				imcb_remove_buddy(ic, bud->ext_jid, NULL);
689 			}
690 
691 			next = bud->next;
692 			g_free(bud->ext_jid);
693 			g_free(bud->full_jid);
694 			g_free(bud->away_message);
695 			g_free(bud);
696 			bud = next;
697 		}
698 
699 		return 1;
700 	} else {
701 		return 0;
702 	}
703 }
704 
jabber_buddy_remove_all_cb(gpointer key,gpointer value,gpointer data)705 static gboolean jabber_buddy_remove_all_cb(gpointer key, gpointer value, gpointer data)
706 {
707 	struct jabber_buddy *bud, *next;
708 
709 	bud = value;
710 	if (bud->bare_jid != bud->full_jid) {
711 		g_free(bud->bare_jid);
712 	}
713 	while (bud) {
714 		next = bud->next;
715 		g_free(bud->ext_jid);
716 		g_free(bud->full_jid);
717 		g_free(bud->away_message);
718 		g_free(bud);
719 		bud = next;
720 	}
721 
722 	return TRUE;
723 }
724 
jabber_buddy_remove_all(struct im_connection * ic)725 void jabber_buddy_remove_all(struct im_connection *ic)
726 {
727 	struct jabber_data *jd = ic->proto_data;
728 
729 	g_hash_table_foreach_remove(jd->buddies, jabber_buddy_remove_all_cb, NULL);
730 	g_hash_table_destroy(jd->buddies);
731 }
732 
jabber_get_timestamp(struct xt_node * xt)733 time_t jabber_get_timestamp(struct xt_node *xt)
734 {
735 	struct xt_node *c;
736 	char *s = NULL;
737 	struct tm tp;
738 	gboolean is_old = TRUE;
739 	const char *format;
740 
741 	/* XEP-0091 has <x> */
742 	c = xt_find_node_by_attr(xt->children, "x", "xmlns", XMLNS_DELAY_OLD);
743 
744 	if (!c || !(s = xt_find_attr(c, "stamp"))) {
745 		is_old = FALSE;
746 
747 		/* XEP-0203 has <delay> */
748 		c = xt_find_node_by_attr(xt->children, "delay", "xmlns", XMLNS_DELAY);
749 		if (!c || !(s = xt_find_attr(c, "stamp"))) {
750 			return 0;
751 		}
752 	}
753 
754 	memset(&tp, 0, sizeof(tp));
755 
756 	/* The other main difference between XEPs is the timestamp format */
757 	format = (is_old) ? "%4d%2d%2dT%2d:%2d:%2d" : "%4d-%2d-%2dT%2d:%2d:%2dZ";
758 
759 	if (sscanf(s, format, &tp.tm_year, &tp.tm_mon, &tp.tm_mday,
760 	           &tp.tm_hour, &tp.tm_min, &tp.tm_sec) != 6) {
761 		return 0;
762 	}
763 
764 	tp.tm_year -= 1900;
765 	tp.tm_mon--;
766 
767 	return mktime_utc(&tp);
768 }
769 
jabber_error_parse(struct xt_node * node,char * xmlns)770 struct jabber_error *jabber_error_parse(struct xt_node *node, char *xmlns)
771 {
772 	struct jabber_error *err;
773 	struct xt_node *c;
774 	char *s;
775 
776 	if (node == NULL) {
777 		return NULL;
778 	}
779 
780 	err = g_new0(struct jabber_error, 1);
781 	err->type = xt_find_attr(node, "type");
782 
783 	for (c = node->children; c; c = c->next) {
784 		if (!(s = xt_find_attr(c, "xmlns")) ||
785 		    strcmp(s, xmlns) != 0) {
786 			continue;
787 		}
788 
789 		if (strcmp(c->name, "text") != 0) {
790 			err->code = c->name;
791 		}
792 		/* Only use the text if it doesn't have an xml:lang attribute,
793 		   if it's empty or if it's set to something English. */
794 		else if (!(s = xt_find_attr(c, "xml:lang")) ||
795 		         !*s || strncmp(s, "en", 2) == 0) {
796 			err->text = c->text;
797 		}
798 	}
799 
800 	return err;
801 }
802 
jabber_error_free(struct jabber_error * err)803 void jabber_error_free(struct jabber_error *err)
804 {
805 	g_free(err);
806 }
807 
jabber_set_me(struct im_connection * ic,const char * me)808 gboolean jabber_set_me(struct im_connection *ic, const char *me)
809 {
810 	struct jabber_data *jd = ic->proto_data;
811 
812 	if (strchr(me, '@') == NULL) {
813 		return FALSE;
814 	}
815 
816 	g_free(jd->username);
817 	g_free(jd->me);
818 
819 	jd->me = jabber_normalize(me);
820 	jd->server = strchr(jd->me, '@');
821 	jd->username = g_strndup(jd->me, jd->server - jd->me);
822 	jd->server++;
823 
824 	/* Set the "internal" account username, for groupchats */
825 	g_free(jd->internal_jid);
826 	jd->internal_jid = g_strdup(jd->me);
827 
828 	return TRUE;
829 }
830 
831 /* Returns new reference! g_free() afterwards. */
jabber_get_bare_jid(char * jid)832 char *jabber_get_bare_jid(char *jid)
833 {
834 	char *s = NULL;
835 
836 	if (jid == NULL) {
837 		return NULL;
838 	}
839 
840 	if ((s = strchr(jid, '/'))) {
841 		return g_strndup(jid, s - jid);
842 	} else {
843 		return g_strdup(jid);
844 	}
845 }
846