1 /********************************************************************\
2   * BitlBee -- An IRC to other IM-networks gateway                     *
3   *                                                                    *
4   * Copyright 2002-2013 Wilmer van der Gaast and others                *
5   \********************************************************************/
6 
7 /* The IRC-based UI - Representing (virtual) channels.                  */
8 
9 /*
10   This program is free software; you can redistribute it and/or modify
11   it under the terms of the GNU General Public License as published by
12   the Free Software Foundation; either version 2 of the License, or
13   (at your option) any later version.
14 
15   This program is distributed in the hope that it will be useful,
16   but WITHOUT ANY WARRANTY; without even the implied warranty of
17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18   GNU General Public License for more details.
19 
20   You should have received a copy of the GNU General Public License with
21   the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
22   if not, write to the Free Software Foundation, Inc., 51 Franklin St.,
23   Fifth Floor, Boston, MA  02110-1301  USA
24 */
25 
26 #include "bitlbee.h"
27 
28 static char *set_eval_channel_type(set_t *set, char *value);
29 static gint irc_channel_user_cmp(gconstpointer a_, gconstpointer b_);
30 static const struct irc_channel_funcs control_channel_funcs;
31 
32 extern const struct irc_channel_funcs irc_channel_im_chat_funcs;
33 
irc_channel_new(irc_t * irc,const char * name)34 irc_channel_t *irc_channel_new(irc_t *irc, const char *name)
35 {
36 	irc_channel_t *ic;
37 	set_t *s;
38 
39 	if (!irc_channel_name_ok(name) || irc_channel_by_name(irc, name)) {
40 		return NULL;
41 	}
42 
43 	ic = g_new0(irc_channel_t, 1);
44 	ic->irc = irc;
45 	ic->name = g_strdup(name);
46 	strcpy(ic->mode, CMODE);
47 
48 	irc_channel_add_user(ic, irc->root);
49 
50 	irc->channels = g_slist_append(irc->channels, ic);
51 
52 	set_add(&ic->set, "auto_join", "false", set_eval_bool, ic);
53 
54 	s = set_add(&ic->set, "type", "control", set_eval_channel_type, ic);
55 	s->flags |= SET_NOSAVE;    /* Layer violation (XML format detail) */
56 
57 	if (name[0] == '&') {
58 		set_setstr(&ic->set, "type", "control");
59 	} else { /* if( name[0] == '#' ) */
60 		set_setstr(&ic->set, "type", "chat");
61 	}
62 
63 	return ic;
64 }
65 
irc_channel_by_name(irc_t * irc,const char * name)66 irc_channel_t *irc_channel_by_name(irc_t *irc, const char *name)
67 {
68 	GSList *l;
69 
70 	for (l = irc->channels; l; l = l->next) {
71 		irc_channel_t *ic = l->data;
72 
73 		if (irc_channel_name_cmp(name, ic->name) == 0) {
74 			return ic;
75 		}
76 	}
77 
78 	return NULL;
79 }
80 
irc_channel_get(irc_t * irc,char * id)81 irc_channel_t *irc_channel_get(irc_t *irc, char *id)
82 {
83 	irc_channel_t *ic, *ret = NULL;
84 	GSList *l;
85 	int nr;
86 
87 	if (sscanf(id, "%d", &nr) == 1 && nr < 1000) {
88 		for (l = irc->channels; l; l = l->next) {
89 			ic = l->data;
90 			if ((nr--) == 0) {
91 				return ic;
92 			}
93 		}
94 
95 		return NULL;
96 	}
97 
98 	/* Exact match first: Partial match only sucks if there's a channel
99 	   #aa and #aabb */
100 	if ((ret = irc_channel_by_name(irc, id))) {
101 		return ret;
102 	}
103 
104 	for (l = irc->channels; l; l = l->next) {
105 		ic = l->data;
106 
107 		if (strstr(ic->name, id)) {
108 			/* Make sure it's a unique match. */
109 			if (!ret) {
110 				ret = ic;
111 			} else {
112 				return NULL;
113 			}
114 		}
115 	}
116 
117 	return ret;
118 }
119 
irc_channel_free(irc_channel_t * ic)120 int irc_channel_free(irc_channel_t *ic)
121 {
122 	irc_t *irc;
123 	GHashTableIter iter;
124 	gpointer itervalue;
125 
126 	if (ic == NULL) {
127 		return 0;
128 	}
129 	irc = ic->irc;
130 
131 	if (ic->flags & IRC_CHANNEL_JOINED) {
132 		irc_channel_del_user(ic, irc->user, IRC_CDU_KICK, "Cleaning up channel");
133 	}
134 
135 	if (ic->f->_free) {
136 		ic->f->_free(ic);
137 	}
138 
139 	while (ic->set) {
140 		set_del(&ic->set, ic->set->key);
141 	}
142 
143 	irc->channels = g_slist_remove(irc->channels, ic);
144 	while (ic->users) {
145 		g_free(ic->users->data);
146 		ic->users = g_slist_remove(ic->users, ic->users->data);
147 	}
148 
149 	g_hash_table_iter_init(&iter, irc->nick_user_hash);
150 
151 	while (g_hash_table_iter_next(&iter, NULL, &itervalue)) {
152 		irc_user_t *iu = itervalue;
153 
154 		if (iu->last_channel == ic) {
155 			iu->last_channel = irc->default_channel;
156 		}
157 	}
158 
159 	if (ic->pastebuf_timer) {
160 		b_event_remove(ic->pastebuf_timer);
161 	}
162 
163 	g_free(ic->name);
164 	g_free(ic->topic);
165 	g_free(ic->topic_who);
166 	g_free(ic);
167 
168 	return 1;
169 }
170 
171 struct irc_channel_free_data {
172 	irc_t *irc;
173 	irc_channel_t *ic;
174 	char *name;
175 };
176 
irc_channel_free_callback(gpointer data,gint fd,b_input_condition cond)177 static gboolean irc_channel_free_callback(gpointer data, gint fd, b_input_condition cond)
178 {
179 	struct irc_channel_free_data *d = data;
180 
181 	if (g_slist_find(irc_connection_list, d->irc) &&
182 	    irc_channel_by_name(d->irc, d->name) == d->ic &&
183 	    !(d->ic->flags & IRC_CHANNEL_JOINED)) {
184 		irc_channel_free(d->ic);
185 	}
186 
187 	g_free(d->name);
188 	g_free(d);
189 	return FALSE;
190 }
191 
192 /* Free the channel, but via the event loop, so after finishing whatever event
193    we're currently handling. */
irc_channel_free_soon(irc_channel_t * ic)194 void irc_channel_free_soon(irc_channel_t *ic)
195 {
196 	struct irc_channel_free_data *d = g_new0(struct irc_channel_free_data, 1);
197 
198 	d->irc = ic->irc;
199 	d->ic = ic;
200 	d->name = g_strdup(ic->name);
201 
202 	b_timeout_add(0, irc_channel_free_callback, d);
203 }
204 
set_eval_channel_type(set_t * set,char * value)205 static char *set_eval_channel_type(set_t *set, char *value)
206 {
207 	struct irc_channel *ic = set->data;
208 	const struct irc_channel_funcs *new;
209 
210 	if (strcmp(value, "control") == 0) {
211 		new = &control_channel_funcs;
212 	} else if (ic != ic->irc->default_channel && strcmp(value, "chat") == 0) {
213 		new = &irc_channel_im_chat_funcs;
214 	} else {
215 		return SET_INVALID;
216 	}
217 
218 	/* Skip the free/init if nothing is being changed */
219 	if (ic->f == new) {
220 		return value;
221 	}
222 
223 	/* TODO: Return values. */
224 	if (ic->f && ic->f->_free) {
225 		ic->f->_free(ic);
226 	}
227 
228 	ic->f = new;
229 
230 	if (ic->f && ic->f->_init) {
231 		ic->f->_init(ic);
232 	}
233 
234 	return value;
235 }
236 
irc_channel_add_user(irc_channel_t * ic,irc_user_t * iu)237 int irc_channel_add_user(irc_channel_t *ic, irc_user_t *iu)
238 {
239 	irc_channel_user_t *icu;
240 
241 	if (irc_channel_has_user(ic, iu)) {
242 		return 0;
243 	}
244 
245 	icu = g_new0(irc_channel_user_t, 1);
246 	icu->iu = iu;
247 
248 	ic->users = g_slist_insert_sorted(ic->users, icu, irc_channel_user_cmp);
249 
250 	if (iu == ic->irc->user || iu == ic->irc->root) {
251 		irc_channel_update_ops(ic, set_getstr(&ic->irc->b->set, "ops"));
252 	}
253 
254 	if (iu == ic->irc->user || ic->flags & IRC_CHANNEL_JOINED) {
255 		ic->flags |= IRC_CHANNEL_JOINED;
256 		irc_send_join(ic, iu);
257 	}
258 
259 	return 1;
260 }
261 
irc_channel_del_user(irc_channel_t * ic,irc_user_t * iu,irc_channel_del_user_type_t type,const char * msg)262 int irc_channel_del_user(irc_channel_t *ic, irc_user_t *iu, irc_channel_del_user_type_t type, const char *msg)
263 {
264 	irc_channel_user_t *icu;
265 
266 	if (!(icu = irc_channel_has_user(ic, iu))) {
267 		if (iu == ic->irc->user && type == IRC_CDU_KICK) {
268 			/* an error happened before joining, inform the client with a numeric */
269 			irc_send_num(ic->irc, 403, "%s :Error joining channel (check control channel?)", ic->name);
270 		}
271 		return 0;
272 	}
273 
274 	ic->users = g_slist_remove(ic->users, icu);
275 	g_free(icu);
276 
277 	if (!(ic->flags & IRC_CHANNEL_JOINED) || type == IRC_CDU_SILENT) {
278 	}
279 	/* Do nothing. The caller should promise it won't screw
280 	   up state of the IRC client. :-) */
281 	else if (type == IRC_CDU_PART) {
282 		irc_send_part(ic, iu, msg);
283 	} else if (type == IRC_CDU_KICK) {
284 		irc_send_kick(ic, iu, ic->irc->root, msg);
285 	}
286 
287 	if (iu == ic->irc->user) {
288 		ic->flags &= ~IRC_CHANNEL_JOINED;
289 
290 		if (ic->irc->status & USTATUS_SHUTDOWN) {
291 			/* Don't do anything fancy when we're shutting down anyway. */
292 		} else if (ic->flags & IRC_CHANNEL_TEMP) {
293 			irc_channel_free_soon(ic);
294 		} else {
295 			/* Flush userlist now. The user won't see it anyway. */
296 			while (ic->users) {
297 				g_free(ic->users->data);
298 				ic->users = g_slist_remove(ic->users, ic->users->data);
299 			}
300 			irc_channel_add_user(ic, ic->irc->root);
301 		}
302 	}
303 
304 	return 1;
305 }
306 
irc_channel_has_user(irc_channel_t * ic,irc_user_t * iu)307 irc_channel_user_t *irc_channel_has_user(irc_channel_t *ic, irc_user_t *iu)
308 {
309 	GSList *l;
310 
311 	for (l = ic->users; l; l = l->next) {
312 		irc_channel_user_t *icu = l->data;
313 
314 		if (icu->iu == iu) {
315 			return icu;
316 		}
317 	}
318 
319 	return NULL;
320 }
321 
322 /* Find a channel we're currently in, that currently has iu in it. */
irc_channel_with_user(irc_t * irc,irc_user_t * iu)323 struct irc_channel *irc_channel_with_user(irc_t *irc, irc_user_t *iu)
324 {
325 	GSList *l;
326 
327 	for (l = irc->channels; l; l = l->next) {
328 		irc_channel_t *ic = l->data;
329 
330 		if (strcmp(set_getstr(&ic->set, "type"), "control") != 0) {
331 			continue;
332 		}
333 
334 		if ((ic->flags & IRC_CHANNEL_JOINED) &&
335 		    irc_channel_has_user(ic, iu)) {
336 			return ic;
337 		}
338 	}
339 
340 	/* If there was no match, try once more but just see if the user
341 	   *would* be in the channel, i.e. if s/he were online. */
342 	if (iu->bu == NULL) {
343 		return NULL;
344 	}
345 
346 	for (l = irc->channels; l; l = l->next) {
347 		irc_channel_t *ic = l->data;
348 
349 		if (strcmp(set_getstr(&ic->set, "type"), "control") != 0) {
350 			continue;
351 		}
352 
353 		if ((ic->flags & IRC_CHANNEL_JOINED) &&
354 		    irc_channel_wants_user(ic, iu)) {
355 			return ic;
356 		}
357 	}
358 
359 	return NULL;
360 }
361 
irc_channel_set_topic(irc_channel_t * ic,const char * topic,const irc_user_t * iu)362 int irc_channel_set_topic(irc_channel_t *ic, const char *topic, const irc_user_t *iu)
363 {
364 	g_free(ic->topic);
365 	ic->topic = g_strdup(topic);
366 
367 	g_free(ic->topic_who);
368 	if (iu) {
369 		ic->topic_who = g_strdup_printf("%s!%s@%s", iu->nick, iu->user, iu->host);
370 	} else {
371 		ic->topic_who = NULL;
372 	}
373 
374 	ic->topic_time = time(NULL);
375 
376 	if (ic->flags & IRC_CHANNEL_JOINED) {
377 		irc_send_topic(ic, TRUE);
378 	}
379 
380 	return 1;
381 }
382 
irc_channel_user_set_mode(irc_channel_t * ic,irc_user_t * iu,irc_channel_user_flags_t flags)383 void irc_channel_user_set_mode(irc_channel_t *ic, irc_user_t *iu, irc_channel_user_flags_t flags)
384 {
385 	irc_channel_user_t *icu = irc_channel_has_user(ic, iu);
386 
387 	if (!icu || icu->flags == flags) {
388 		return;
389 	}
390 
391 	if (ic->flags & IRC_CHANNEL_JOINED) {
392 		irc_send_channel_user_mode_diff(ic, iu, icu->flags, flags);
393 	}
394 
395 	icu->flags = flags;
396 }
397 
irc_channel_set_mode(irc_channel_t * ic,const char * s)398 void irc_channel_set_mode(irc_channel_t *ic, const char *s)
399 {
400 	irc_t *irc = ic->irc;
401 	char m[128], st = 1;
402 	const char *t;
403 	int i;
404 	char changes[512], *p, st2 = 2;
405 
406 	memset(m, 0, sizeof(m));
407 
408 	for (t = ic->mode; *t; t++) {
409 		if (*t < sizeof(m)) {
410 			m[(int) *t] = 1;
411 		}
412 	}
413 
414 	p = changes;
415 	for (t = s; *t; t++) {
416 		if (*t == '+' || *t == '-') {
417 			st = *t == '+';
418 		} else if (strchr(CMODES, *t)) {
419 			if (m[(int) *t] != st) {
420 				if (st != st2) {
421 					st2 = st, *p++ = st ? '+' : '-';
422 				}
423 				*p++ = *t;
424 			}
425 			m[(int) *t] = st;
426 		}
427 	}
428 	*p = '\0';
429 
430 	memset(ic->mode, 0, sizeof(ic->mode));
431 
432 	for (i = 'A'; i <= 'z' && strlen(ic->mode) < (sizeof(ic->mode) - 1); i++) {
433 		if (m[i]) {
434 			ic->mode[strlen(ic->mode)] = i;
435 		}
436 	}
437 
438 	if (*changes && (ic->flags & IRC_CHANNEL_JOINED)) {
439 		irc_write(irc, ":%s!%s@%s MODE %s :%s", irc->root->nick,
440 		          irc->root->user, irc->root->host, ic->name,
441 		          changes);
442 	}
443 }
444 
irc_channel_user_get_prefix(irc_channel_user_t * icu)445 char irc_channel_user_get_prefix(irc_channel_user_t *icu)
446 {
447 	if (icu->flags & IRC_CHANNEL_USER_OP) {
448 		return '@';
449 	} else if (icu->flags & IRC_CHANNEL_USER_HALFOP) {
450 		return '%';
451 	} else if (icu->flags & IRC_CHANNEL_USER_VOICE) {
452 		return '+';
453 	}
454 	return 0;
455 }
456 
irc_channel_auto_joins(irc_t * irc,account_t * acc)457 void irc_channel_auto_joins(irc_t *irc, account_t *acc)
458 {
459 	GSList *l;
460 
461 	for (l = irc->channels; l; l = l->next) {
462 		irc_channel_t *ic = l->data;
463 		gboolean aj = set_getbool(&ic->set, "auto_join");
464 		char *type;
465 
466 		if (acc &&
467 		    (type = set_getstr(&ic->set, "chat_type")) &&
468 		    strcmp(type, "room") == 0) {
469 			/* Bit of an ugly special case: Handle chatrooms here, we
470 			   can only auto-join them if their account is online. */
471 			char *acc_s;
472 
473 			if (!aj && !(ic->flags & IRC_CHANNEL_JOINED)) {
474 				/* Only proceed if this one's marked as auto_join
475 				   or if we're in it already. (Very likely the IRC
476 				   client auto-(re)joining at reconnect time.) */
477 				continue;
478 			} else if (!(acc_s = set_getstr(&ic->set, "account"))) {
479 				continue;
480 			} else if (account_get(irc->b, acc_s) != acc) {
481 				continue;
482 			} else if (acc->ic == NULL || !(acc->ic->flags & OPT_LOGGED_IN)) {
483 				continue;
484 			} else {
485 				ic->f->join(ic);
486 			}
487 		} else if (aj) {
488 			irc_channel_add_user(ic, irc->user);
489 		}
490 	}
491 }
492 
irc_channel_printf(irc_channel_t * ic,char * format,...)493 void irc_channel_printf(irc_channel_t *ic, char *format, ...)
494 {
495 	va_list params;
496 	char *text;
497 
498 	va_start(params, format);
499 	text = g_strdup_vprintf(format, params);
500 	va_end(params);
501 
502 	irc_send_msg(ic->irc->root, "PRIVMSG", ic->name, text, NULL);
503 	g_free(text);
504 }
505 
irc_channel_name_ok(const char * name_)506 gboolean irc_channel_name_ok(const char *name_)
507 {
508 	const unsigned char *name = (unsigned char *) name_;
509 	int i;
510 
511 	if (name_[0] == '\0') {
512 		return FALSE;
513 	}
514 
515 	/* Check if the first character is in CTYPES (#&) */
516 	if (strchr(CTYPES, name_[0]) == NULL) {
517 		return FALSE;
518 	}
519 
520 	/* RFC 1459 keeps amazing me: While only a "few" chars are allowed
521 	   in nicknames, channel names can be pretty much anything as long
522 	   as they start with # or &. I'll be a little bit more strict and
523 	   disallow all non-printable characters. */
524 	for (i = 1; name[i]; i++) {
525 		if (name[i] <= ' ' || name[i] == ',') {
526 			return FALSE;
527 		}
528 	}
529 
530 	return TRUE;
531 }
532 
irc_channel_name_strip(char * name)533 void irc_channel_name_strip(char *name)
534 {
535 	int i, j;
536 
537 	for (i = j = 0; name[i]; i++) {
538 		if (name[i] > ' ' && name[i] != ',') {
539 			name[j++] = name[i];
540 		}
541 	}
542 
543 	name[j] = '\0';
544 }
545 
irc_channel_name_cmp(const char * a_,const char * b_)546 int irc_channel_name_cmp(const char *a_, const char *b_)
547 {
548 	static unsigned char case_map[256];
549 	const unsigned char *a = (unsigned char *) a_, *b = (unsigned char *) b_;
550 	int i;
551 
552 	if (case_map['A'] == '\0') {
553 		for (i = 33; i < 256; i++) {
554 			if (i != ',') {
555 				case_map[i] = i;
556 			}
557 		}
558 
559 		for (i = 0; i < 26; i++) {
560 			case_map['A' + i] = 'a' + i;
561 		}
562 
563 		case_map['['] = '{';
564 		case_map[']'] = '}';
565 		case_map['~'] = '`';
566 		case_map['\\'] = '|';
567 	}
568 
569 	if (!irc_channel_name_ok(a_) || !irc_channel_name_ok(b_)) {
570 		return -1;
571 	}
572 
573 	for (i = 0; a[i] && b[i] && case_map[a[i]] && case_map[b[i]]; i++) {
574 		if (case_map[a[i]] == case_map[b[i]]) {
575 			continue;
576 		} else {
577 			return case_map[a[i]] - case_map[b[i]];
578 		}
579 	}
580 
581 	return case_map[a[i]] - case_map[b[i]];
582 }
583 
irc_channel_is_unused(irc_t * irc,char * name)584 gboolean irc_channel_is_unused(irc_t *irc, char *name)
585 {
586 	char *type, *chat_type;
587 	irc_channel_t *oic;
588 
589 	if (!irc_channel_name_ok(name)) {
590 		return FALSE;
591 	}
592 
593 	if (!(oic = irc_channel_by_name(irc, name))) {
594 		return TRUE;
595 	}
596 
597 	type = set_getstr(&oic->set, "type");
598 	chat_type = set_getstr(&oic->set, "chat_type");
599 
600 	if (type && chat_type && oic->data == FALSE &&
601 	    strcmp(type, "chat") == 0 &&
602 	    strcmp(chat_type, "groupchat") == 0) {
603 		/* There's a channel with this name already, but it looks
604 		   like it's not in use yet. Most likely the IRC client
605 		   rejoined the channel after a reconnect. Remove it so
606 		   we can reuse its name. */
607 		irc_channel_free(oic);
608 		return TRUE;
609 	}
610 
611 	return FALSE;
612 }
613 
irc_channel_name_gen(irc_t * irc,const char * hint)614 char *irc_channel_name_gen(irc_t *irc, const char *hint)
615 {
616 	char name[MAX_NICK_LENGTH + 1] = { 0 };
617 	char *translit_name;
618 	gsize bytes_written;
619 
620 	translit_name = g_convert_with_fallback(hint, -1, "ASCII//TRANSLIT", "UTF-8", "", NULL, &bytes_written, NULL);
621 
622 	if (!translit_name) {
623 		/* Same thing as in nick_gen() in nick.c, try again without //TRANSLIT */
624 		translit_name = g_convert_with_fallback(hint, -1, "ASCII", "UTF-8", "", NULL, &bytes_written, NULL);
625 	}
626 
627 	if (!translit_name) {
628 		return NULL;
629 	}
630 
631 	if (bytes_written > MAX_NICK_LENGTH) {
632 		translit_name[MAX_NICK_LENGTH] = '\0';
633 	}
634 
635 	name[0] = '#';
636 	strncpy(name + 1, translit_name, MAX_NICK_LENGTH - 1);
637 	name[MAX_NICK_LENGTH] = '\0';
638 
639 	g_free(translit_name);
640 
641 	irc_channel_name_strip(name);
642 
643 	if (set_getbool(&irc->b->set, "nick_lowercase")) {
644 		nick_lc(irc, name + 1);
645 	}
646 
647 	while (!irc_channel_is_unused(irc, name)) {
648 		underscore_dedupe(name);
649 	}
650 
651 	return g_strdup(name);
652 }
653 
irc_channel_name_hint(irc_channel_t * ic,const char * name)654 gboolean irc_channel_name_hint(irc_channel_t *ic, const char *name)
655 {
656 	irc_t *irc = ic->irc;
657 	char *full_name;
658 
659 	/* Don't rename a channel if the user's in it already. */
660 	if (ic->flags & IRC_CHANNEL_JOINED) {
661 		return FALSE;
662 	}
663 
664 	if (!(full_name = irc_channel_name_gen(irc, name))) {
665 		return FALSE;
666 	}
667 
668 	g_free(ic->name);
669 	ic->name = full_name;
670 
671 	return TRUE;
672 }
673 
irc_channel_user_cmp(gconstpointer a_,gconstpointer b_)674 static gint irc_channel_user_cmp(gconstpointer a_, gconstpointer b_)
675 {
676 	const irc_channel_user_t *a = a_, *b = b_;
677 
678 	return irc_user_cmp(a->iu, b->iu);
679 }
680 
irc_channel_update_ops(irc_channel_t * ic,char * value)681 void irc_channel_update_ops(irc_channel_t *ic, char *value)
682 {
683 	irc_channel_user_set_mode(ic, ic->irc->root,
684 	                          (strcmp(value, "both") == 0 ||
685 	                           strcmp(value, "root") == 0) ? IRC_CHANNEL_USER_OP : 0);
686 	irc_channel_user_set_mode(ic, ic->irc->user,
687 	                          (strcmp(value, "both") == 0 ||
688 	                           strcmp(value, "user") == 0) ? IRC_CHANNEL_USER_OP : 0);
689 }
690 
set_eval_irc_channel_ops(set_t * set,char * value)691 char *set_eval_irc_channel_ops(set_t *set, char *value)
692 {
693 	irc_t *irc = set->data;
694 	GSList *l;
695 
696 	if (strcmp(value, "both") != 0 && strcmp(value, "none") != 0 &&
697 	    strcmp(value, "user") != 0 && strcmp(value, "root") != 0) {
698 		return SET_INVALID;
699 	}
700 
701 	for (l = irc->channels; l; l = l->next) {
702 		irc_channel_update_ops(l->data, value);
703 	}
704 
705 	return value;
706 }
707 
708 /* Channel-type dependent functions, for control channels: */
control_channel_privmsg(irc_channel_t * ic,const char * msg)709 static gboolean control_channel_privmsg(irc_channel_t *ic, const char *msg)
710 {
711 	irc_t *irc = ic->irc;
712 	irc_user_t *iu;
713 	const char *s;
714 
715 	/* Scan for non-whitespace chars followed by a colon: */
716 	for (s = msg; *s && !g_ascii_isspace(*s) && *s != ':' && *s != ','; s++) {
717 	}
718 
719 	if (*s == ':' || *s == ',') {
720 		char to[s - msg + 1];
721 
722 		memset(to, 0, sizeof(to));
723 		strncpy(to, msg, s - msg);
724 		while (*(++s) && g_ascii_isspace(*s)) {
725 		}
726 		msg = s;
727 
728 		if (!(iu = irc_user_by_name(irc, to))) {
729 			irc_channel_printf(ic, "User does not exist: %s", to);
730 		} else {
731 			ic->last_target = iu;
732 		}
733 	} else if (g_strcasecmp(set_getstr(&irc->b->set, "default_target"), "last") == 0 &&
734 	           ic->last_target && g_hash_table_contains(irc->nick_user_hash, ic->last_target->key)) {
735 		iu = ic->last_target;
736 	} else {
737 		iu = irc->root;
738 	}
739 
740 	if (iu && iu->f->privmsg) {
741 		iu->last_channel = ic;
742 		iu->f->privmsg(iu, msg);
743 	}
744 
745 	return TRUE;
746 }
747 
control_channel_invite(irc_channel_t * ic,irc_user_t * iu)748 static gboolean control_channel_invite(irc_channel_t *ic, irc_user_t *iu)
749 {
750 	struct irc_control_channel *icc = ic->data;
751 	bee_user_t *bu = iu->bu;
752 
753 	if (bu == NULL) {
754 		return FALSE;
755 	}
756 
757 	if (icc->type != IRC_CC_TYPE_GROUP) {
758 		irc_send_num(ic->irc, 482, "%s :Invitations are only possible to fill_by=group channels", ic->name);
759 		return FALSE;
760 	}
761 
762 	bu->ic->acc->prpl->add_buddy(bu->ic, bu->handle,
763 	                             icc->group ? icc->group->name : NULL);
764 
765 	return TRUE;
766 }
767 
control_channel_kick(irc_channel_t * ic,irc_user_t * iu,const char * msg)768 static void control_channel_kick(irc_channel_t *ic, irc_user_t *iu, const char *msg)
769 {
770 	struct irc_control_channel *icc = ic->data;
771 	bee_user_t *bu = iu->bu;
772 
773 	if (bu == NULL) {
774 		return;
775 	}
776 
777 	if (icc->type != IRC_CC_TYPE_GROUP) {
778 		irc_send_num(ic->irc, 482, "%s :Kicks are only possible to fill_by=group channels", ic->name);
779 		return;
780 	}
781 
782 	bu->ic->acc->prpl->remove_buddy(bu->ic, bu->handle,
783 	                                icc->group ? icc->group->name : NULL);
784 }
785 
786 static char *set_eval_by_account(set_t *set, char *value);
787 static char *set_eval_fill_by(set_t *set, char *value);
788 static char *set_eval_by_group(set_t *set, char *value);
789 static char *set_eval_by_protocol(set_t *set, char *value);
790 static char *set_eval_show_users(set_t *set, char *value);
791 
control_channel_init(irc_channel_t * ic)792 static gboolean control_channel_init(irc_channel_t *ic)
793 {
794 	struct irc_control_channel *icc;
795 
796 	set_add(&ic->set, "account", NULL, set_eval_by_account, ic);
797 	set_add(&ic->set, "fill_by", "all", set_eval_fill_by, ic);
798 	set_add(&ic->set, "group", NULL, set_eval_by_group, ic);
799 	set_add(&ic->set, "protocol", NULL, set_eval_by_protocol, ic);
800 
801 	/* When changing the default, also change it below. */
802 	set_add(&ic->set, "show_users", "online+,special%,away", set_eval_show_users, ic);
803 
804 	ic->data = icc = g_new0(struct irc_control_channel, 1);
805 	icc->type = IRC_CC_TYPE_DEFAULT;
806 
807 	/* Have to run the evaluator to initialize icc->modes. */
808 	set_setstr(&ic->set, "show_users", "online+,special%,away");
809 
810 	/* For scripts that care. */
811 	irc_channel_set_mode(ic, "+C");
812 
813 	return TRUE;
814 }
815 
control_channel_join(irc_channel_t * ic)816 static gboolean control_channel_join(irc_channel_t *ic)
817 {
818 	bee_irc_channel_update(ic->irc, ic, NULL);
819 
820 	return TRUE;
821 }
822 
set_eval_by_account(set_t * set,char * value)823 static char *set_eval_by_account(set_t *set, char *value)
824 {
825 	struct irc_channel *ic = set->data;
826 	struct irc_control_channel *icc = ic->data;
827 	account_t *acc;
828 
829 	if (!(acc = account_get(ic->irc->b, value))) {
830 		return SET_INVALID;
831 	}
832 
833 	icc->account = acc;
834 	if ((icc->type & IRC_CC_TYPE_MASK) == IRC_CC_TYPE_ACCOUNT) {
835 		bee_irc_channel_update(ic->irc, ic, NULL);
836 	}
837 
838 	return g_strdup(acc->tag);
839 }
840 
set_eval_fill_by(set_t * set,char * value)841 static char *set_eval_fill_by(set_t *set, char *value)
842 {
843 	struct irc_channel *ic = set->data;
844 	struct irc_control_channel *icc = ic->data;
845 	char *s;
846 
847 	icc->type &= ~(IRC_CC_TYPE_MASK | IRC_CC_TYPE_INVERT);
848 
849 	s = value;
850 	if (s[0] == '!') {
851 		icc->type |= IRC_CC_TYPE_INVERT;
852 		s++;
853 	}
854 
855 	if (strcmp(s, "all") == 0) {
856 		icc->type |= IRC_CC_TYPE_DEFAULT;
857 	} else if (strcmp(s, "rest") == 0) {
858 		icc->type |= IRC_CC_TYPE_REST;
859 	} else if (strcmp(s, "group") == 0) {
860 		icc->type |= IRC_CC_TYPE_GROUP;
861 	} else if (strcmp(s, "account") == 0) {
862 		icc->type |= IRC_CC_TYPE_ACCOUNT;
863 	} else if (strcmp(s, "protocol") == 0) {
864 		icc->type |= IRC_CC_TYPE_PROTOCOL;
865 	} else {
866 		return SET_INVALID;
867 	}
868 
869 	bee_irc_channel_update(ic->irc, ic, NULL);
870 	return value;
871 }
872 
set_eval_by_group(set_t * set,char * value)873 static char *set_eval_by_group(set_t *set, char *value)
874 {
875 	struct irc_channel *ic = set->data;
876 	struct irc_control_channel *icc = ic->data;
877 
878 	icc->group = bee_group_by_name(ic->irc->b, value, TRUE);
879 	if ((icc->type & IRC_CC_TYPE_MASK) == IRC_CC_TYPE_GROUP) {
880 		bee_irc_channel_update(ic->irc, ic, NULL);
881 	}
882 
883 	return g_strdup(icc->group->name);
884 }
885 
set_eval_by_protocol(set_t * set,char * value)886 static char *set_eval_by_protocol(set_t *set, char *value)
887 {
888 	struct irc_channel *ic = set->data;
889 	struct irc_control_channel *icc = ic->data;
890 	struct prpl *prpl;
891 
892 	if (!(prpl = find_protocol(value))) {
893 		return SET_INVALID;
894 	}
895 
896 	icc->protocol = prpl;
897 	if ((icc->type & IRC_CC_TYPE_MASK) == IRC_CC_TYPE_PROTOCOL) {
898 		bee_irc_channel_update(ic->irc, ic, NULL);
899 	}
900 
901 	return value;
902 }
903 
set_eval_show_users(set_t * set,char * value)904 static char *set_eval_show_users(set_t *set, char *value)
905 {
906 	struct irc_channel *ic = set->data;
907 	struct irc_control_channel *icc = ic->data;
908 	char **parts = g_strsplit(value, ",", 0), **part;
909 	char modes[5];
910 
911 	memset(modes, 0, 5);
912 	for (part = parts; *part; part++) {
913 		char last, modechar = IRC_CHANNEL_USER_NONE;
914 
915 		if (**part == '\0') {
916 			goto fail;
917 		}
918 
919 		last = (*part)[strlen(*part + 1)];
920 		if (last == '+') {
921 			modechar = IRC_CHANNEL_USER_VOICE;
922 		} else if (last == '%') {
923 			modechar = IRC_CHANNEL_USER_HALFOP;
924 		} else if (last == '@') {
925 			modechar = IRC_CHANNEL_USER_OP;
926 		}
927 
928 		if (strncmp(*part, "offline", 7) == 0) {
929 			modes[0] = modechar;
930 		} else if (strncmp(*part, "away", 4) == 0) {
931 			modes[1] = modechar;
932 		} else if (strncmp(*part, "special", 7) == 0) {
933 			modes[2] = modechar;
934 		} else if (strncmp(*part, "online", 6) == 0) {
935 			modes[3] = modechar;
936 		} else {
937 			goto fail;
938 		}
939 	}
940 	memcpy(icc->modes, modes, 5);
941 	bee_irc_channel_update(ic->irc, ic, NULL);
942 
943 	g_strfreev(parts);
944 	return value;
945 
946 fail:
947 	g_strfreev(parts);
948 	return SET_INVALID;
949 }
950 
951 /* Figure out if a channel is supposed to have the user, assuming s/he is
952    online or otherwise also selected by the show_users setting. Only works
953    for control channels, but does *not* check if this channel is of that
954    type. Beware! */
irc_channel_wants_user(irc_channel_t * ic,irc_user_t * iu)955 gboolean irc_channel_wants_user(irc_channel_t *ic, irc_user_t *iu)
956 {
957 	struct irc_control_channel *icc = ic->data;
958 	gboolean ret = FALSE;
959 
960 	if (iu->bu == NULL) {
961 		return FALSE;
962 	}
963 
964 	switch (icc->type & IRC_CC_TYPE_MASK) {
965 	case IRC_CC_TYPE_GROUP:
966 		ret = iu->bu->group == icc->group;
967 		break;
968 	case IRC_CC_TYPE_ACCOUNT:
969 		ret = iu->bu->ic->acc == icc->account;
970 		break;
971 	case IRC_CC_TYPE_PROTOCOL:
972 		ret = iu->bu->ic->acc->prpl == icc->protocol;
973 		break;
974 	case IRC_CC_TYPE_DEFAULT:
975 	default:
976 		ret = TRUE;
977 		break;
978 	}
979 
980 	if (icc->type & IRC_CC_TYPE_INVERT) {
981 		ret = !ret;
982 	}
983 
984 	return ret;
985 }
986 
control_channel_free(irc_channel_t * ic)987 static gboolean control_channel_free(irc_channel_t *ic)
988 {
989 	struct irc_control_channel *icc = ic->data;
990 
991 	set_del(&ic->set, "account");
992 	set_del(&ic->set, "fill_by");
993 	set_del(&ic->set, "group");
994 	set_del(&ic->set, "protocol");
995 	set_del(&ic->set, "show_users");
996 
997 	g_free(icc);
998 	ic->data = NULL;
999 
1000 	/* For scripts that care. */
1001 	irc_channel_set_mode(ic, "-C");
1002 
1003 	return TRUE;
1004 }
1005 
1006 static const struct irc_channel_funcs control_channel_funcs = {
1007 	control_channel_privmsg,
1008 	control_channel_join,
1009 	NULL,
1010 	NULL,
1011 	control_channel_invite,
1012 	control_channel_kick,
1013 
1014 	control_channel_init,
1015 	control_channel_free,
1016 };
1017