1 /*
2  * $Id: irc.c,v 1.156 2005/04/21 06:58:50 nohar Exp $
3  *
4  * This file is part of the bip project
5  * Copyright (C) 2004 2005 Arnaud Cornet and Loïc Gomez
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  * See the file "COPYING" for the exact licensing terms.
12  */
13 
14 #include "config.h"
15 #include <stdlib.h>
16 #include <string.h>
17 #include <stdio.h>
18 #include "util.h"
19 #include "irc.h"
20 #include "bip.h"
21 #include "log.h"
22 #include "connection.h"
23 #include "md5.h"
24 
25 #define S_CONN_DELAY (10)
26 
27 extern int sighup;
28 extern bip_t *_bip;
29 
30 static int irc_join(struct link_server *server, struct line *line);
31 static int irc_part(struct link_server *server, struct line *line);
32 static int irc_mode(struct link_server *server, struct line *line);
33 static int irc_mode_channel(struct link_server *s, struct channel *channel,
34 				struct line *line, const char* mode, int add, int cur_arg);
35 static int irc_kick(struct link_server *server, struct line *line);
36 static int irc_privmsg(struct link_server *server, struct line *line);
37 static int irc_notice(struct link_server *server, struct line *line);
38 static int irc_quit(struct link_server *server, struct line *line);
39 static int irc_nick(struct link_server *server, struct line *line);
40 static int irc_generic_quit(struct link_server *server, struct line *line);
41 static int irc_topic(struct link_server *server, struct line *line);
42 static int irc_332(struct link_server *server, struct line *line);
43 static int irc_333(struct link_server *server, struct line *line);
44 static int irc_353(struct link_server *server, struct line *line);
45 static int irc_366(struct link_server *server, struct line *line);
46 static int irc_367(struct link_server *server, struct line *l);
47 static int irc_368(struct link_server *server, struct line *l);
48 void irc_server_shutdown(struct link_server *s);
49 static int origin_is_me(struct line *l, struct link_server *server);
50 static void ls_set_nick(struct link_server *ircs, char *nick);
51 static void server_set_chanmodes(struct link_server *l, const char *chanmodes);
52 static void server_set_prefix(struct link_server *l, const char *prefix);
53 static void server_init_modes(struct link_server *s);
54 static int bip_get_index(const char* str, char car);
55 static int bip_fls(int v);
56 
57 void oidentd_dump(bip_t *bip);
58 
59 void irc_client_free(struct link_client *cli);
60 extern int conf_log_sync_interval;
61 extern int conf_reconn_timer;
62 
63 void write_user_list(connection_t *c, char *dest);
64 
65 static void irc_copy_cli(struct link_client *src, struct link_client *dest,
66 		struct line *line);
67 static void irc_cli_make_join(struct link_client *ic);
68 static void server_setup_reconnect_timer(struct link *link);
69 int irc_cli_bip(bip_t *bip, struct link_client *ic, struct line *line);
70 
71 #define LAGOUT_TIME 480
72 #define LAGCHECK_TIME (90)
73 #define RECONN_TIMER_MAX (600)
74 #define LOGGING_TIMEOUT (360)
75 #define CONN_INTERVAL 60
76 #define CONNECT_TIMEOUT 60
77 
channel_new(const char * name)78 struct channel *channel_new(const char *name)
79 {
80 	struct channel *chan;
81 	chan = bip_calloc(sizeof(struct channel), 1);
82 	chan->name = bip_strdup(name);
83 	hash_init(&chan->ovmasks, HASH_NOCASE);
84 	return chan;
85 }
86 
nick_from_ircmask(const char * mask)87 char *nick_from_ircmask(const char *mask)
88 {
89 	const char *nick = mask;
90 	char *ret;
91 	size_t len;
92 
93 	assert(mask);
94 
95 	while (*nick && *nick != '!')
96 		nick++;
97 	if (!*nick)
98 		return bip_strdup(mask);
99 	len = nick - mask;
100 	ret = bip_malloc(len + 1);
101 	memcpy(ret, mask, len);
102 	ret[len] = 0;
103 	return ret;
104 }
105 
106 #define NAMESIZE 256
107 
channel_name_list(struct link_server * server,struct channel * c)108 list_t *channel_name_list(struct link_server *server, struct channel *c)
109 {
110 	list_t *ret;
111 	hash_iterator_t hi;
112 	size_t len = 0;
113 	char *str = bip_malloc(NAMESIZE + 1);
114 
115 	ret = list_new(NULL);
116 	*str = 0;
117 	for (hash_it_init(&c->ovmasks, &hi); hash_it_key(&hi);
118 			hash_it_next(&hi)){
119 		const char *nick = hash_it_key(&hi);
120 		long int ovmask = (long int)hash_it_item(&hi);
121 
122 		assert(strlen(nick) + 2 < NAMESIZE);
123 
124 		if (len + strlen(nick) + 2 + (ovmask ? 1 : 0) >= NAMESIZE) {
125 			list_add_last(ret, str);
126 			str = bip_malloc(NAMESIZE + 1);
127 			*str = 0;
128 			len = 0;
129 		}
130 		if (len != 0) {
131 			strcat(str, " ");
132 			len++;
133 		}
134 
135 		// prepend symbol corresponding to the usermode
136 		int msb;
137 		if ((msb = bip_fls(ovmask))) {
138 			str[len] = server->prefixes[msb - 1];
139 			str[++len] = 0;
140 		}
141 
142 		strcat(str, nick);
143 		len += strlen(nick);
144 		assert(len < NAMESIZE);
145 	}
146 	list_add_last(ret, str);
147 	return ret;
148 }
149 
link_name(struct link_any * l)150 char *link_name(struct link_any *l)
151 {
152 	if (LINK(l))
153 		return LINK(l)->name ? LINK(l)->name : "(null)";
154 	return "*connecting*";
155 }
156 
irc_001(struct link_server * server,struct line * line)157 static int irc_001(struct link_server *server, struct line *line)
158 {
159 	(void)line;
160 
161 	if (LINK(server)->s_state == IRCS_WAS_CONNECTED)
162 		LINK(server)->s_state = IRCS_RECONNECTING;
163 	else
164 		LINK(server)->s_state = IRCS_CONNECTING;
165 
166 	/* change nick on client */
167 	int i;
168 	for (i = 0; i < LINK(server)->l_clientc; i++) {
169 		struct link_client *c = LINK(server)->l_clientv[i];
170 		WRITE_LINE1(CONN(c), LINK(server)->cli_nick, "NICK",
171 				server->nick);
172 	}
173 	return OK_COPY;
174 }
175 
irc_start_lagtest(struct link_server * l)176 void irc_start_lagtest(struct link_server *l)
177 {
178 	l->laginit_ts = time(NULL);
179 	write_line_fast(CONN(l), "PING :" S_PING "\r\n");
180 }
181 
182 /*
183  * returns 0 if we ping timeout
184  */
irc_compute_lag(struct link_server * is)185 void irc_compute_lag(struct link_server *is)
186 {
187 	assert(is->laginit_ts != -1);
188 	is->lag = time(NULL) - is->laginit_ts;
189 }
190 
irc_lags_out(struct link_server * is)191 int irc_lags_out(struct link_server *is)
192 {
193 	if (is->lag > LAGOUT_TIME) {
194 		mylog(LOG_ERROR, "[%s] Lags out! closing", LINK(is)->name);
195 		return 1;
196 	} else {
197 		mylog(LOG_DEBUG, "[%s] lag : %d\n", LINK(is)->name, is->lag);
198 		return 0;
199 	}
200 }
201 
irc_lag_init(struct link_server * is)202 void irc_lag_init(struct link_server *is)
203 {
204 	is->lagtest_timeout = LAGCHECK_TIME;
205 	is->laginit_ts = -1;
206 }
207 
irc_server_join(struct link_server * s)208 static void irc_server_join(struct link_server *s)
209 {
210 	list_iterator_t it;
211 	for (list_it_init(&LINK(s)->chan_infos_order, &it); list_it_item(&it);
212 			list_it_next(&it)) {
213 		struct chan_info *ci = list_it_item(&it);
214 		if (!ci->key)
215 			WRITE_LINE1(CONN(s), NULL, "JOIN", ci->name);
216 		else
217 			WRITE_LINE2(CONN(s), NULL, "JOIN", ci->name, ci->key);
218 	}
219 }
220 
irc_server_connected(struct link_server * server)221 static void irc_server_connected(struct link_server *server)
222 {
223 	int i;
224 
225         LINK(server)->s_state = IRCS_CONNECTED;
226         LINK(server)->s_conn_attempt = 0;
227 
228 	mylog(LOG_INFO, "[%s] Connected for user %s",
229 			LINK(server)->name, LINK(server)->user->name);
230 
231         irc_server_join(server);
232         log_connected(LINK(server)->log);
233 
234 	if (LINK(server)->cli_nick) {
235 		/* we change nick on client */
236 		for (i = 0; i < LINK(server)->l_clientc; i++) {
237 			struct link_client *ic = LINK(server)->l_clientv[i];
238 			WRITE_LINE1(CONN(ic), LINK(server)->cli_nick, "NICK",
239 					server->nick);
240 		}
241 		free(LINK(server)->cli_nick);
242 		LINK(server)->cli_nick = NULL;
243 	}
244 
245 	/* basic helper for nickserv and co */
246 	list_iterator_t itocs;
247 	for (list_it_init(&LINK(server)->on_connect_send, &itocs);
248 				list_it_item(&itocs); list_it_next(&itocs)) {
249 		ssize_t len = strlen(list_it_item(&itocs)) + 2;
250 		char *str = bip_malloc(len + 1);
251 		sprintf(str, "%s\r\n", (char *)list_it_item(&itocs));
252 		write_line(CONN(server), str);
253 		free(str);
254         }
255 
256 	if (LINK(server)->l_clientc == 0) {
257 		if (LINK(server)->away_nick)
258 			WRITE_LINE1(CONN(server), NULL, "NICK",
259 					LINK(server)->away_nick);
260 		if (LINK(server)->no_client_away_msg)
261 			WRITE_LINE1(CONN(server), NULL, "AWAY",
262 					LINK(server)->no_client_away_msg);
263 	}
264 }
265 
266 /*
267  * Given the way irc nets disrespect the rfc, we completely forget
268  * about this damn ircmask...
269 :irc.iiens.net 352 pwet * ~a je.suis.t1r.net irc.iiens.net pwet H :0 d
270 -> nohar!~nohar@haruka.t1r.net
271 */
irc_352(struct link_server * server,struct line * line)272 static int irc_352(struct link_server *server, struct line *line)
273 {
274 	(void)server;
275 	if (!irc_line_includes(line, 6))
276 		return ERR_PROTOCOL;
277 
278 #if 0
279 	if (irc_line_elem_case_equals(line, 6, server->nick)) {
280 		const char *nick = server->nick;
281 		const char *iname = irc_line_elem(line, 3);
282 		const char *ihost = irc_line_elem(line, 4);
283 		char *ircmask = bip_malloc(strlen(nick) + strlen(iname) +
284 				strlen(ihost) + 3);
285 		strcpy(ircmask, nick);
286 		strcat(ircmask, "!");
287 		strcat(ircmask, iname);
288 		strcat(ircmask, "@");
289 		strcat(ircmask, ihost);
290 		if (server->ircmask)
291 			free(server->ircmask);
292 		server->ircmask = ircmask;
293 	}
294 #endif
295 
296 #if 0
297 	if (!origin_is_me(line, server)) {
298 		struct channel *channel;
299 		struct nick *nick;
300 
301 		channel = hash_get(&server->channels, irc_line_elem(line, 2));
302 		if (!channel)
303 			return OK_COPY_WHO;
304 
305 		nick = hash_get(&channel->nicks, irc_line_elem(line, 6));
306 		if (!nick)
307 			return OK_COPY_WHO;
308 	}
309 
310 #endif
311 	return OK_COPY_WHO;
312 }
313 
irc_315(struct link_server * server,struct line * l)314 static int irc_315(struct link_server *server, struct line *l)
315 {
316 	(void)l;
317 	struct link *link = LINK(server);
318 	if (link->who_client) {
319 		if (link->who_client->who_count == 0) {
320 			mylog(LOG_DEBUG, "Spurious irc_315");
321 			return OK_COPY_WHO;
322 		}
323 		link->who_client->whoc_tstamp = time(NULL);
324 		if (link->who_client->who_count > 0) {
325 			--link->who_client->who_count;
326 			mylog(LOG_DEBUG,
327 				"RPL_ENDOFWHO: "
328 				"Decrementing who count for %p: %d",
329 				link->who_client, link->who_client->who_count);
330 		}
331 	}
332 
333 	return OK_COPY_WHO;
334 }
335 
rotate_who_client(struct link * link)336 void rotate_who_client(struct link *link)
337 {
338 	int i;
339 	mylog(LOG_DEBUG, "rotate_who_client %p", link->who_client);
340 	/* find a client with non-null who_count */
341 	link->who_client = NULL;
342 	for (i = 0; i < link->l_clientc; i++) {
343 		struct link_client *ic = link->l_clientv[i];
344 		if (!list_is_empty(&ic->who_queue)) {
345 			char *l;
346 			while ((l = list_remove_first(&ic->who_queue))) {
347 				write_line(CONN(link->l_server), l);
348 				free(l);
349 			}
350 			link->who_client = ic;
351 			break;
352 		}
353 	}
354 }
355 
irc_dispatch_server(bip_t * bip,struct link_server * server,struct line * line)356 int irc_dispatch_server(bip_t *bip, struct link_server *server,
357 		struct line *line)
358 {
359 	int ret = OK_COPY;
360 	/* shut gcc up */
361 	(void)bip;
362 
363 	if (!irc_line_includes(line, 0))
364 		return ERR_PROTOCOL;
365 
366 	if (irc_line_elem_equals(line, 0, "PING")) {
367 		if (!irc_line_includes(line, 1))
368 			return ERR_PROTOCOL;
369 		struct line *resp = irc_line_new();
370 		char *resps;
371 		irc_line_append(resp, "PONG");
372 		irc_line_append(resp, irc_line_elem(line, 1));
373 		resp->colon = 1; /* it seems some ircds want it */
374 		resps = irc_line_to_string(resp);
375 		write_line_fast(CONN(server), resps);
376 		irc_line_free(resp);
377 		free(resps);
378 		ret = OK_FORGET;
379 	} else if (irc_line_elem_equals(line, 0, "PONG")) {
380 		/* not all server reply with PONG <servername> <our string>
381 		 * so we blindly assume the PONG is ours. */
382 		if (irc_line_count(line) == 2 || irc_line_count(line) == 3) {
383 			if (server->laginit_ts != -1) {
384 				irc_compute_lag(server);
385 				irc_lag_init(server);
386 			}
387 			ret = OK_FORGET;
388 		}
389 	} else if (irc_line_elem_equals(line, 0, "433")) {
390 		if (LINK(server)->s_state != IRCS_CONNECTED) {
391 			size_t nicklen = strlen(server->nick);
392 			char *newnick = bip_malloc(nicklen + 2);
393 
394 			strcpy(newnick, server->nick);
395 			if (strlen(server->nick) < 9) {
396 				strcat(newnick, "`");
397 			} else {
398 				if (newnick[7] != '`') {
399 					if (newnick[8] != '`') {
400 						newnick[8] = '`';
401 					} else {
402 						newnick[7] = '`';
403 					}
404 				} else {
405 					newnick[8] = rand() *
406 						('z' - 'a') / RAND_MAX + 'a';
407 				}
408 				newnick[9] = 0;
409 			}
410 			ls_set_nick(server, newnick);
411 
412 			WRITE_LINE1(CONN(server), NULL, "NICK", server->nick);
413 			ret = OK_FORGET;
414 		}
415 	} else if (LINK(server)->s_state == IRCS_RECONNECTING) {
416 		ret = OK_FORGET;
417 		if (irc_line_elem_equals(line, 0, "376")) /* end of motd */
418 			irc_server_connected(server);
419 		else if (irc_line_elem_equals(line, 0, "422")) /* no motd */
420 				irc_server_connected(server);
421 
422 	} else if (LINK(server)->s_state == IRCS_CONNECTING) {
423 		ret = OK_FORGET;
424 			if (irc_line_elem_equals(line, 0, "005")) {
425 			int i;
426 			for (i = irc_line_count(line) - 1; i > 0; i--) {
427 				if (LINK(server)->ignore_server_capab &&
428 						irc_line_elem_equals(line, i, "CAPAB"))
429 					irc_line_drop(line, i);
430 				else if (!strncmp(irc_line_elem(line, i), "CHANMODES=", 10))
431 					server_set_chanmodes(server, irc_line_elem(line, i) + 10);
432 				else if (!strncmp(irc_line_elem(line, i), "PREFIX=(", 8))
433 					server_set_prefix(server, irc_line_elem(line, i) + 7);
434 			}
435 		}
436 		if (irc_line_elem_equals(line, 0, "NOTICE")) {
437 		} else if (irc_line_elem_equals(line, 0, "376")) {
438 							/* end of motd */
439 			irc_server_connected(server);
440 			list_add_last(&LINK(server)->init_strings,
441 					irc_line_dup(line));
442 		} else if (irc_line_elem_equals(line, 0, "422")) { /* no motd */
443 			irc_server_connected(server);
444 			list_add_last(&LINK(server)->init_strings,
445 					irc_line_dup(line));
446 		} else {
447 			list_add_last(&LINK(server)->init_strings,
448 					irc_line_dup(line));
449 		}
450 	} else if (irc_line_elem_equals(line, 0, "001")) {
451 		ret = irc_001(server, line);
452 		if (LINK(server)->s_state == IRCS_CONNECTING) {
453 			if (!list_is_empty(&LINK(server)->init_strings))
454 				return ERR_PROTOCOL;
455 			/* update the irc mask */
456 			list_add_last(&LINK(server)->init_strings,
457 					irc_line_dup(line));
458 		}
459 	} else if (irc_line_elem_equals(line, 0, "JOIN")) {
460 		ret = irc_join(server, line);
461 	} else if (irc_line_elem_equals(line, 0, "332")) {
462 		ret = irc_332(server, line);
463 	} else if (irc_line_elem_equals(line, 0, "333")) {
464 		ret = irc_333(server, line);
465 	} else if (irc_line_elem_equals(line, 0, "352")) {
466 		ret = irc_352(server, line);
467 	} else if (irc_line_elem_equals(line, 0, "315")) {
468 		ret = irc_315(server, line);
469 	} else if (irc_line_elem_equals(line, 0, "353")) {
470 		ret = irc_353(server, line);
471 	} else if (irc_line_elem_equals(line, 0, "366")) {
472 		ret = irc_366(server, line);
473 	} else if (irc_line_elem_equals(line, 0, "367")) {
474 		ret = irc_367(server, line);
475 	} else if (irc_line_elem_equals(line, 0, "368")) {
476 		ret = irc_368(server, line);
477 	} else if (irc_line_elem_equals(line, 0, "PART")) {
478 		ret = irc_part(server, line);
479 	} else if (irc_line_elem_equals(line, 0, "MODE")) {
480 		ret = irc_mode(server, line);
481 	} else if (irc_line_elem_equals(line, 0, "TOPIC")) {
482 		ret = irc_topic(server, line);
483 	} else if (irc_line_elem_equals(line, 0, "KICK")) {
484 		ret = irc_kick(server, line);
485 	} else if (irc_line_elem_equals(line, 0, "PRIVMSG")) {
486 		ret = irc_privmsg(server, line);
487 	} else if (irc_line_elem_equals(line, 0, "NOTICE")) {
488 		ret = irc_notice(server, line);
489 	} else if (irc_line_elem_equals(line, 0, "QUIT")) {
490 		ret = irc_quit(server, line);
491 	} else if (irc_line_elem_equals(line, 0, "NICK")) {
492 		ret = irc_nick(server, line);
493 	}
494 
495 	if (ret == OK_COPY) {
496 		int i;
497 		for (i = 0; i < LINK(server)->l_clientc; i++) {
498 			if (TYPE(LINK(server)->l_clientv[i]) ==
499 					IRC_TYPE_CLIENT) {
500 				char *s = irc_line_to_string(line);
501 				write_line(CONN(LINK(server)->l_clientv[i]), s);
502 				free(s);
503 			}
504 		}
505 	}
506 	if (ret == OK_COPY_WHO && LINK(server)->who_client) {
507 		char *s;
508 
509 		s = irc_line_to_string(line);
510 		write_line(CONN(LINK(server)->who_client), s);
511 		free(s);
512 	}
513 	if (LINK(server)->who_client &&
514 			LINK(server)->who_client->who_count == 0) {
515 		mylog(LOG_DEBUG, "OK_COPY_WHO: who_count for %p is nul",
516 			LINK(server)->who_client);
517 		rotate_who_client(LINK(server));
518 	}
519 	return ret;
520 }
521 
522 /* send join and related stuff to client */
irc_send_join(struct link_client * ic,struct channel * chan)523 static void irc_send_join(struct link_client *ic, struct channel *chan)
524 {
525 	struct bipuser *user;
526 	char *ircmask;
527 
528 	user = LINK(ic)->user;
529 	assert(user);
530 
531 	/* user ircmask here for rbot */
532 	ircmask = bip_malloc(strlen(LINK(ic)->l_server->nick) +
533 			strlen(BIP_FAKEMASK) + 1);
534 	strcpy(ircmask, LINK(ic)->l_server->nick);
535 	strcat(ircmask, BIP_FAKEMASK);
536 	WRITE_LINE1(CONN(ic), ircmask, "JOIN", chan->name);
537 	free(ircmask);
538 
539 	if (chan->topic)
540 		WRITE_LINE3(CONN(ic), P_SERV, "332", LINK(ic)->l_server->nick,
541 				chan->name, chan->topic);
542 	if (chan->creator && chan->create_ts)
543 		WRITE_LINE4(CONN(ic), P_SERV, "333", LINK(ic)->l_server->nick,
544 				chan->name, chan->creator, chan->create_ts);
545 
546 	list_t *name_list = channel_name_list(LINK(ic)->l_server, chan);
547 	char *s;
548 	while ((s = list_remove_first(name_list))) {
549 		char tmptype[2];
550 		tmptype[0] = chan->type;
551 		tmptype[1] = 0;
552 		WRITE_LINE4(CONN(ic), P_SERV, "353", LINK(ic)->l_server->nick,
553 				tmptype, chan->name, s);
554 		free(s);
555 	}
556 	list_free(name_list);
557 
558 	WRITE_LINE3(CONN(ic), P_SERV, "366", LINK(ic)->l_server->nick,
559 			chan->name, "End of /NAMES list.");
560 }
561 
write_init_string(connection_t * c,struct line * line,char * nick)562 static void write_init_string(connection_t *c, struct line *line, char *nick)
563 {
564 	char *l;
565 
566 	l = irc_line_to_string_to(line, nick);
567 	write_line(c, l);
568 	free(l);
569 }
570 
bind_to_link(struct link * l,struct link_client * ic)571 static void bind_to_link(struct link *l, struct link_client *ic)
572 {
573 	int i = l->l_clientc;
574 
575 	LINK(ic) = l;
576 	l->l_clientc++;
577 	l->l_clientv = bip_realloc(l->l_clientv, l->l_clientc *
578 			sizeof(struct link_client *));
579 	l->l_clientv[i] = ic;
580 }
581 
unbind_from_link(struct link_client * ic)582 void unbind_from_link(struct link_client *ic)
583 {
584 	struct link *l = LINK(ic);
585 	int i;
586 
587 	for (i = 0; i < l->l_clientc; i++)
588 		if (l->l_clientv[i] == ic)
589 			break;
590 
591 	assert(i != l->l_clientc);
592 
593 	if (l->who_client == ic) {
594 		mylog(LOG_DEBUG, "unbind_from_link:  %p: %d", l->who_client,
595 				ic->who_count);
596 		l->who_client = NULL;
597 	}
598 
599 	for (i = i + 1; i < l->l_clientc; i++)
600 		l->l_clientv[i - 1] = l->l_clientv[i];
601 
602 	l->l_clientc--;
603 	l->l_clientv = bip_realloc(l->l_clientv, l->l_clientc *
604 			sizeof(struct link_client *));
605 	if (l->l_clientc == 0) { /* bip_realloc was equiv to free() */
606 		l->l_clientv = NULL;
607 		return;
608 	}
609 }
610 
irc_cli_bip(bip_t * bip,struct link_client * ic,struct line * line)611 int irc_cli_bip(bip_t *bip, struct link_client *ic, struct line *line)
612 {
613 	return adm_bip(bip, ic, line, 0);
614 }
615 
616 #define PASS_SEP ':'
617 
get_str_elem(char * str,int num)618 static char *get_str_elem(char *str, int num)
619 {
620 	char *ret;
621 	char *c;
622 	char *cur = str;
623 	int index = 0;
624 
625 	while ((c = strchr(cur, PASS_SEP))) {
626 		if (index < num) {
627 			index++;
628 			cur = c + 1;
629 			continue;
630 		}
631 		if (c - cur < 1)
632 			return NULL;
633 		ret = bip_malloc(c - cur + 1);
634 		memcpy(ret, cur, c - cur);
635 		ret[c - cur] = 0;
636 		return ret;
637 	}
638 	if (index == num) {
639 		c = str + strlen(str);
640 		if (c - cur < 1)
641 			return NULL;
642 		ret = bip_malloc(c - cur + 1);
643 		memcpy(ret, cur, c - cur);
644 		ret[c - cur] = 0;
645 		return ret;
646 	}
647 	return NULL;
648 }
649 
irc_cli_make_join(struct link_client * ic)650 static void irc_cli_make_join(struct link_client *ic)
651 {
652 	if (LINK(ic)->l_server) {
653 		/* join channels, step one, those in conf, in order */
654 		list_iterator_t li;
655 		for (list_it_init(&LINK(ic)->chan_infos_order, &li);
656 				list_it_item(&li); list_it_next(&li)) {
657 			struct chan_info *ci = (struct chan_info *)
658 				list_it_item(&li);
659 			struct channel *chan;
660 			if ((chan = hash_get(&LINK(ic)->l_server->channels,
661 							ci->name)))
662 				irc_send_join(ic, chan);
663 		}
664 
665 		/* step two, those not in conf */
666 		hash_iterator_t hi;
667 		for (hash_it_init(&LINK(ic)->l_server->channels, &hi);
668 				hash_it_item(&hi); hash_it_next(&hi)) {
669 			struct channel *chan = (struct channel *)
670 				hash_it_item(&hi);
671 			if (!hash_get(&LINK(ic)->chan_infos, chan->name))
672 				irc_send_join(ic, chan);
673 		}
674 	}
675 }
676 
irc_cli_backlog(struct link_client * ic,int hours)677 void irc_cli_backlog(struct link_client *ic, int hours)
678 {
679 	struct bipuser *user;
680 
681 	user = LINK(ic)->user;
682 	assert(user);
683 	assert(LINK(ic)->l_server);
684 
685 	if (!user->backlog) {
686 		mylog(LOG_DEBUG, "Backlog disabled for %s, not backlogging",
687 				user->name);
688 		return;
689 	}
690 
691 	if (hours != 0) {
692 		/* have some limit */
693 		if (hours > 24 * 366)
694 			hours = 24 * 366;
695 	}
696 
697 	list_t *backlogl;
698 	char *bl;
699 	list_t *bllines;
700 
701 	backlogl = log_backlogs(LINK(ic)->log);
702 	while ((bl = list_remove_first(backlogl))) {
703 		bllines = backlog_lines(LINK(ic)->log, bl,
704 				LINK(ic)->l_server->nick, hours);
705 		if (bllines) {
706 			if (!list_is_empty(bllines)) {
707 				mylog(LOG_INFO, "[%s] backlogging: %s",
708 						LINK(ic)->name, bl);
709 				write_lines(CONN(ic), bllines);
710 			}
711 			list_free(bllines);
712 		}
713 		free(bl);
714 	}
715 	list_free(backlogl);
716 }
717 
irc_cli_startup(bip_t * bip,struct link_client * ic,struct line * line)718 static int irc_cli_startup(bip_t *bip, struct link_client *ic,
719 		struct line *line)
720 {
721 	char *init_nick;
722 	char *user, *pass, *connname;
723 	(void)line;
724 
725 	assert(ic->init_pass);
726 
727 	user = get_str_elem(ic->init_pass, 0);
728 	if (!user)
729 		return ERR_AUTH;
730 	pass = get_str_elem(ic->init_pass, 1);
731 	if (!pass) {
732 		free(user);
733 		return ERR_AUTH;
734 	}
735 	connname = get_str_elem(ic->init_pass, 2);
736 	if (!connname) {
737 		free(pass);
738 		free(user);
739 		return ERR_AUTH;
740 	}
741 
742 	list_iterator_t it;
743 	for (list_it_init(&bip->link_list, &it); list_it_item(&it);
744 			list_it_next(&it)) {
745 		struct link *l = list_it_item(&it);
746 		if (strcmp(user, l->user->name) == 0 &&
747 				strcmp(connname, l->name) == 0) {
748 			if (chash_cmp(pass, l->user->password,
749 						l->user->seed) == 0) {
750 				bind_to_link(l, ic);
751 				break;
752 			}
753 		}
754 	}
755 
756 	if (!LINK(ic))
757 		mylog(LOG_ERROR, "[%s] Invalid credentials (user: %s)",
758 				 connname, user);
759 	free(user);
760 	free(connname);
761 	free(pass);
762 
763 	free(ic->init_pass);
764 	ic->init_pass = NULL;
765 	init_nick = ic->init_nick;
766 	ic->init_nick = NULL;
767 
768 	if (!LINK(ic)) {
769 		free(init_nick);
770 		return ERR_AUTH;
771 	}
772 
773 #ifdef HAVE_LIBSSL
774 	if (LINK(ic)->s_state != IRCS_CONNECTED) {
775 		/* Check if we have an untrusted certificate from the server */
776 		if (ssl_check_trust(ic)) {
777 			free(init_nick);
778 			return OK_FORGET;
779 		}
780 	}
781 #endif
782 
783 	if (LINK(ic)->s_state == IRCS_NONE) {
784 		/* drop it if corresponding server hasn't connected at all. */
785 		write_line_fast(CONN(ic), ":irc.bip.net NOTICE pouet "
786 				":ERROR Proxy not yet connected, try again "
787 				"later\r\n");
788 		unbind_from_link(ic);
789 		free(init_nick);
790 		return OK_CLOSE;
791 	}
792 
793 	list_remove(&bip->connecting_client_list, ic);
794 	TYPE(ic) = IRC_TYPE_CLIENT;
795 
796 	for (list_it_init(&LINK(ic)->init_strings, &it);
797 			list_it_item(&it); list_it_next(&it))
798 		write_init_string(CONN(ic), list_it_item(&it), init_nick);
799 
800 	/* we change nick on server */
801 	if (LINK(ic)->l_server) {
802 		struct link_server *server = LINK(ic)->l_server;
803 		WRITE_LINE1(CONN(ic), init_nick, "NICK", server->nick);
804 
805 		if (!LINK(ic)->ignore_first_nick)
806 			WRITE_LINE1(CONN(server), NULL, "NICK", init_nick);
807 		else if (LINK(ic)->away_nick &&
808 				strcmp(LINK(ic)->away_nick, server->nick) == 0)
809 			WRITE_LINE1(CONN(server), NULL, "NICK",
810 					LINK(server)->connect_nick);
811 
812 		/* change away status */
813 		if (server && LINK(ic)->no_client_away_msg)
814 			WRITE_LINE0(CONN(server), NULL, "AWAY");
815 	}
816 
817 	if (!LINK(ic)->l_server) {
818 		free(init_nick);
819 		return OK_FORGET;
820 	}
821 
822 	irc_cli_make_join(ic);
823 	irc_cli_backlog(ic, 0);
824 
825 	log_client_connected(LINK(ic)->log);
826 	free(init_nick);
827 
828 	return OK_FORGET;
829 }
830 
irc_cli_nick(bip_t * bip,struct link_client * ic,struct line * line)831 static int irc_cli_nick(bip_t *bip, struct link_client *ic, struct line *line)
832 {
833 	if (irc_line_count(line) != 2)
834 		return ERR_PROTOCOL;
835 
836 	if ((ic->state & IRCC_READY) == IRCC_READY)
837 		return OK_COPY;
838 
839 	ic->state |= IRCC_NICK;
840 	if (ic->init_nick)
841 		free(ic->init_nick);
842 	ic->init_nick = bip_strdup(irc_line_elem(line, 1));
843 
844 	if ((ic->state & IRCC_READY) == IRCC_READY)
845 		return irc_cli_startup(bip, ic, line);
846 
847 	if ((ic->state & IRCC_PASS) != IRCC_PASS)
848 		WRITE_LINE2(CONN(ic), P_SERV, "NOTICE", ic->init_nick,
849 				"You should type /QUOTE PASS your_username:"
850 				"your_password:your_connection_name");
851 
852 	return OK_FORGET;
853 }
854 
irc_cli_user(bip_t * bip,struct link_client * ic,struct line * line)855 static int irc_cli_user(bip_t *bip, struct link_client *ic, struct line *line)
856 {
857 	if (irc_line_count(line) != 5)
858 		return ERR_PROTOCOL;
859 
860 	if ((ic->state & IRCC_READY) == IRCC_READY)
861 		return ERR_PROTOCOL;
862 
863 	ic->state |= IRCC_USER;
864 	if ((ic->state & IRCC_READY) == IRCC_READY)
865 		return irc_cli_startup(bip, ic, line);
866 	return OK_FORGET;
867 }
868 
irc_cli_pass(bip_t * bip,struct link_client * ic,struct line * line)869 static int irc_cli_pass(bip_t *bip, struct link_client *ic, struct line *line)
870 {
871 	if (irc_line_count(line) != 2)
872 		return ERR_PROTOCOL;
873 
874 	if ((ic->state & IRCC_READY) == IRCC_READY)
875 		return ERR_PROTOCOL;
876 
877 	ic->state |= IRCC_PASS;
878 	if (ic->init_pass)
879 		free(ic->init_pass);
880 	ic->init_pass = bip_strdup(irc_line_elem(line, 1));
881 	if ((ic->state & IRCC_READY) == IRCC_READY)
882 		return irc_cli_startup(bip, ic, line);
883 	return OK_FORGET;
884 }
885 
irc_cli_quit(struct link_client * ic,struct line * line)886 static int irc_cli_quit(struct link_client *ic, struct line *line)
887 {
888 	(void)ic;
889 	(void)line;
890 	return OK_CLOSE;
891 }
892 
irc_cli_privmsg(bip_t * bip,struct link_client * ic,struct line * line)893 static int irc_cli_privmsg(bip_t *bip, struct link_client *ic,
894 		struct line *line)
895 {
896 	if (!irc_line_includes(line, 2))
897 		return OK_FORGET;
898 
899 	if (irc_line_elem_equals(line, 1, "-bip"))
900 		return adm_bip(bip, ic, line, 1);
901 	else
902 		log_cli_privmsg(LINK(ic)->log, LINK(ic)->l_server->nick,
903 			irc_line_elem(line, 1), irc_line_elem(line, 2));
904 
905 	if (LINK(ic)->user->blreset_on_talk) {
906 		if (LINK(ic)->user->blreset_connection)
907 			log_reset_all(LINK(ic)->log);
908 		else
909 			log_reset_store(LINK(ic)->log, irc_line_elem(line, 1));
910 	}
911 	return OK_COPY_CLI;
912 }
913 
irc_cli_notice(struct link_client * ic,struct line * line)914 static int irc_cli_notice(struct link_client *ic, struct line *line)
915 {
916 	if (!irc_line_includes(line, 2))
917 		return OK_FORGET;
918 	log_cli_notice(LINK(ic)->log, LINK(ic)->l_server->nick,
919 				irc_line_elem(line, 1), irc_line_elem(line, 2));
920 	if (LINK(ic)->user->blreset_on_talk) {
921 		if (LINK(ic)->user->blreset_connection)
922 			log_reset_all(LINK(ic)->log);
923 		else
924 			log_reset_store(LINK(ic)->log, irc_line_elem(line, 1));
925 	}
926 	return OK_COPY_CLI;
927 }
928 
irc_cli_who(struct link_client * ic,struct line * line)929 static int irc_cli_who(struct link_client *ic, struct line *line)
930 {
931 	struct link *l = LINK(ic);
932 
933 	++ic->who_count;
934 	if (ic->who_count == 1)
935 		ic->whoc_tstamp = time(NULL);
936 	mylog(LOG_DEBUG, "cli_who: Incrementing who count for %p: %d",
937 				ic, ic->who_count);
938 
939 	if (l->who_client && l->who_client != ic) {
940 		list_add_first(&ic->who_queue, irc_line_to_string(line));
941 		return OK_FORGET;
942 	}
943 
944 	if (!l->who_client)
945 		l->who_client = ic;
946 
947 	return OK_COPY;
948 }
949 
irc_cli_mode(struct link_client * ic,struct line * line)950 static int irc_cli_mode(struct link_client *ic, struct line *line)
951 {
952 	struct link *l = LINK(ic);
953 
954 	if (irc_line_count(line) != 3)
955 		return OK_COPY;
956 
957 	/* This is a wild guess and that sucks. */
958 	if (!irc_line_elem_equals(line, 0, "MODE") ||
959 			strchr(irc_line_elem(line, 2), 'b') == NULL)
960 		return OK_COPY;
961 
962 	++ic->who_count;
963 	if (ic->who_count == 1)
964 		ic->whoc_tstamp = time(NULL);
965 	mylog(LOG_DEBUG, "cli_mode: Incrementing who count for %p: %d",
966 				l->who_client, ic->who_count);
967 
968 	if (l->who_client && l->who_client != ic) {
969 		list_add_first(&ic->who_queue, irc_line_to_string(line));
970 		return OK_FORGET;
971 	}
972 
973 	if (!l->who_client)
974 		l->who_client = ic;
975 
976 	return OK_COPY;
977 }
978 
979 
irc_notify_disconnection(struct link_server * is)980 static void irc_notify_disconnection(struct link_server *is)
981 {
982 	int i;
983 	LINK(is)->cli_nick = bip_strdup(is->nick);
984 
985 	for (i = 0; i < LINK(is)->l_clientc; i++) {
986 		struct link_client *ic = LINK(is)->l_clientv[i];
987 		hash_iterator_t hi;
988 		for (hash_it_init(&is->channels, &hi); hash_it_item(&hi);
989 			hash_it_next(&hi)) {
990 			struct channel *c = (struct channel *)hash_it_item(&hi);
991 			WRITE_LINE3(CONN(ic), P_IRCMASK, "KICK",
992 					c->name, is->nick,
993 					"Server disconnected, reconnecting");
994 		}
995 		bip_notify(ic, "Server disconnected, reconnecting");
996 	}
997 }
998 
irc_add_channel_info(struct link_server * ircs,const char * chan,const char * key)999 void irc_add_channel_info(struct link_server *ircs, const char *chan,
1000 		const char *key)
1001 {
1002 	struct chan_info *ci;
1003 	if (!ischannel(*chan))
1004 		return;
1005 
1006 	ci = hash_get(&LINK(ircs)->chan_infos, chan);
1007 	if (!ci) {
1008 		struct chan_info *ci;
1009 		ci = chan_info_new();
1010 		ci->name = bip_strdup(chan);
1011 		ci->key = key ? bip_strdup(key) : NULL;
1012 		ci->backlog = 1;
1013 		hash_insert(&LINK(ircs)->chan_infos, chan, ci);
1014 		list_add_last(&LINK(ircs)->chan_infos_order, ci);
1015 	} else {
1016 		if (ci->key) {
1017 			free(ci->key);
1018 			ci->key = NULL;
1019 		}
1020 		ci->key = key ? bip_strdup(key) : NULL;
1021 	}
1022 }
1023 
irc_cli_join(struct link_client * irc,struct line * line)1024 static int irc_cli_join(struct link_client *irc, struct line *line)
1025 {
1026 	if (irc_line_count(line) != 2 && irc_line_count(line) != 3)
1027 		return ERR_PROTOCOL;
1028 
1029 	const char *s, *e, *ks, *ke = NULL;
1030 	s = irc_line_elem(line, 1);
1031 	if (irc_line_count(line) == 3)
1032 		ks = irc_line_elem(line, 2);
1033 	else
1034 		ks = NULL;
1035 
1036 	while ((e = strchr(s, ','))) {
1037 		size_t len = e - s;
1038 		char *p = bip_malloc(len + 1);
1039 		size_t klen;
1040 		char *kp = NULL;
1041 
1042 		memcpy(p, s, len);
1043 		p[len] = 0;
1044 		if (ks) {
1045 			if (strlen(ks)) {
1046 				ke = strchr(ks, ',');
1047 				if (!ke)
1048 					ke = ks + strlen(ks);
1049 				klen = ke - ks;
1050 				kp = bip_malloc(klen + 1);
1051 				memcpy(kp, ks, klen);
1052 				kp[klen] = 0;
1053 				if (*ke == 0)
1054 					ks = NULL;
1055 			} else {
1056 				kp = NULL;
1057 				ks = NULL;
1058 			}
1059 		}
1060 
1061 		irc_add_channel_info(LINK(irc)->l_server, p, kp);
1062 		free(p);
1063 		if (kp) {
1064 			free(kp);
1065 			if (ks)
1066 				ks = ke + 1;
1067 		}
1068 		s = e + 1;
1069 	}
1070 
1071 	irc_add_channel_info(LINK(irc)->l_server, s, ks);
1072 	return OK_COPY;
1073 }
1074 
irc_cli_part(struct link_client * irc,struct line * line)1075 static int irc_cli_part(struct link_client *irc, struct line *line)
1076 {
1077 	struct chan_info *ci;
1078 	char *cname;
1079 
1080 	if (irc_line_count(line) != 2 && irc_line_count(line) != 3)
1081 		return ERR_PROTOCOL;
1082 
1083 	cname = (char *)irc_line_elem(line, 1);
1084 
1085 	if ((ci = hash_remove_if_exists(&LINK(irc)->chan_infos,
1086 					cname)) != NULL) {
1087 		list_remove(&LINK(irc)->chan_infos_order, ci);
1088 		free(ci->name);
1089 		if (ci->key)
1090 			free(ci->key);
1091 		free(ci);
1092 	}
1093 	return OK_COPY;
1094 }
1095 
1096 #ifdef HAVE_LIBSSL
irc_dispatch_trust_client(struct link_client * ic,struct line * line)1097 static int irc_dispatch_trust_client(struct link_client *ic, struct line *line)
1098 {
1099 	int r = OK_COPY;
1100 	if (!irc_line_includes(line, 1))
1101 		return ERR_PROTOCOL;
1102 
1103 	if (strcasecmp(irc_line_elem(line, 0), "BIP") == 0 &&
1104 	    strcasecmp(irc_line_elem(line, 1), "TRUST") == 0)
1105 		r = adm_trust(ic, line);
1106 
1107 	return r;
1108 }
1109 #endif
1110 
irc_dispatch_client(bip_t * bip,struct link_client * ic,struct line * line)1111 static int irc_dispatch_client(bip_t *bip, struct link_client *ic,
1112 		struct line *line)
1113 {
1114 	int r = OK_COPY;
1115 	if (irc_line_count(line) == 0)
1116 		return ERR_PROTOCOL;
1117 
1118 	if (irc_line_elem_equals(line, 0, "PING")) {
1119 		if (!irc_line_includes(line, 1))
1120 			return ERR_PROTOCOL;
1121 		WRITE_LINE1(CONN(ic), link_name((struct link_any *)ic), "PONG",
1122 				irc_line_elem(line, 1));
1123 		r = OK_FORGET;
1124 	} else if (LINK(ic)->s_state != IRCS_CONNECTED) {
1125 		write_line_fast(CONN(ic), ":irc.bip.net NOTICE pouet "
1126 				":ERROR Proxy not connected, please wait "
1127 				"before sending commands\r\n");
1128 		r = OK_FORGET;
1129 	} else if (strcasecmp(irc_line_elem(line, 0), "BIP") == 0) {
1130 		r = irc_cli_bip(bip, ic, line);
1131 	} else if (irc_line_elem_equals(line, 0, "JOIN")) {
1132 		r = irc_cli_join(ic, line);
1133 	} else if (irc_line_elem_equals(line, 0, "PART")) {
1134 		r = irc_cli_part(ic, line);
1135 	} else if (irc_line_elem_equals(line, 0, "NICK")) {
1136 		r = irc_cli_nick(bip, ic, line);
1137 	} else if (irc_line_elem_equals(line, 0, "QUIT")) {
1138 		r = irc_cli_quit(ic, line);
1139 	} else if (irc_line_elem_equals(line, 0, "PRIVMSG")) {
1140 		r = irc_cli_privmsg(bip, ic, line);
1141 	} else if (irc_line_elem_equals(line, 0, "NOTICE")) {
1142 		r = irc_cli_notice(ic, line);
1143 	} else if (irc_line_elem_equals(line, 0, "WHO")) {
1144 		r = irc_cli_who(ic, line);
1145 	} else if (irc_line_elem_equals(line, 0, "MODE")) {
1146 		r = irc_cli_mode(ic, line);
1147 	}
1148 
1149 	if (r == OK_COPY || r == OK_COPY_CLI) {
1150 		char *str = irc_line_to_string(line);
1151 		if (LINK(ic)->s_state == IRCS_CONNECTED &&
1152 				LINK(ic)->l_server->nick)
1153 			write_line(CONN(LINK(ic)->l_server), str);
1154 		else if (LINK(ic)->l_server->nick)
1155 			WRITE_LINE2(CONN(ic), P_IRCMASK,
1156 					(LINK(ic)->user->bip_use_notice ?
1157 						"NOTICE" : "PRIVMSG"),
1158 					LINK(ic)->l_server->nick,
1159 					":Not connected please try again "
1160 					"later...\r\n");
1161 
1162 		free(str);
1163 		if (r == OK_COPY_CLI) {
1164 			int i;
1165 			struct link_server *s = LINK(ic)->l_server;
1166 
1167 			for (i = 0; i < LINK(s)->l_clientc; i++)
1168 				irc_copy_cli(ic, LINK(s)->l_clientv[i], line);
1169 		}
1170 	}
1171 	return r;
1172 }
1173 
irc_copy_cli(struct link_client * src,struct link_client * dest,struct line * line)1174 static void irc_copy_cli(struct link_client *src, struct link_client *dest,
1175 		struct line *line)
1176 {
1177 	char *str;
1178 
1179 	if (src == dest)
1180 		return;
1181 
1182 	if (!irc_line_includes(line, 1) ||
1183 			!irc_line_elem_equals(line, 0, "PRIVMSG")) {
1184 		str = irc_line_to_string(line);
1185 		write_line(CONN(dest), str);
1186 		free(str);
1187 		return;
1188 	}
1189 
1190 	if (ischannel(*irc_line_elem(line, 1)) || LINK(src) != LINK(dest)) {
1191 		assert(!line->origin);
1192 		line->origin = LINK(src)->l_server->nick;
1193 		str = irc_line_to_string(line);
1194 		line->origin = NULL;
1195 		write_line(CONN(dest), str);
1196 		free(str);
1197 		return;
1198 	}
1199 
1200 	/* LINK(src) == LINK(dest) */
1201 	size_t len = strlen(irc_line_elem(line, 2)) + 5;
1202 	char *tmp;
1203 
1204 	if (len == 0)
1205 		return;
1206 
1207 	tmp = bip_malloc(len);
1208 
1209 	snprintf(tmp, len, " -> %s", irc_line_elem(line, 2));
1210 	tmp[len - 1] = 0;
1211 
1212 	struct line *retline = irc_line_new();
1213 
1214 	retline->origin = bip_strdup(irc_line_elem(line, 1));
1215 	irc_line_append(retline, irc_line_elem(line, 0));
1216 	irc_line_append(retline, LINK(src)->l_server->nick);
1217 	irc_line_append(retline, tmp);
1218 	free(tmp);
1219 	str = irc_line_to_string(retline);
1220 	irc_line_free(retline);
1221 #if 0
1222 	/* tricky: */
1223 	irc_line_elem(line, 1) = LINK(src)->l_server->nick;
1224 
1225 	oldelem = irc_line_elem(line, 2);
1226 	irc_line_elem(line, 2) = tmp;
1227 	str = irc_line_to_string(line);
1228 	/* end of trick: */
1229 	irc_line_elem(line, 1) = line->origin;
1230 	irc_line_elem(line, 2) = oldelem;
1231 	line->origin = NULL;
1232 #endif
1233 	write_line(CONN(dest), str);
1234 	free(str);
1235 	return;
1236 }
1237 
irc_dispatch_loging_client(bip_t * bip,struct link_client * ic,struct line * line)1238 static int irc_dispatch_loging_client(bip_t *bip, struct link_client *ic,
1239 		struct line *line)
1240 {
1241 	if (irc_line_count(line) == 0)
1242 		return ERR_PROTOCOL;
1243 
1244 	if (irc_line_elem_equals(line, 0, "NICK")) {
1245 		return irc_cli_nick(bip, ic, line);
1246 	} else if (irc_line_elem_equals(line, 0, "USER")) {
1247 		return irc_cli_user(bip, ic, line);
1248 	} else if (irc_line_elem_equals(line, 0, "PASS")) {
1249 		return irc_cli_pass(bip, ic, line);
1250 	}
1251 	return OK_FORGET;
1252 }
1253 
irc_dispatch(bip_t * bip,struct link_any * l,struct line * line)1254 int irc_dispatch(bip_t *bip, struct link_any *l, struct line *line)
1255 {
1256 	switch (TYPE(l)) {
1257 	case IRC_TYPE_SERVER:
1258 		return irc_dispatch_server(bip, (struct link_server*)l, line);
1259 		break;
1260 	case IRC_TYPE_CLIENT:
1261 		return irc_dispatch_client(bip, (struct link_client*)l, line);
1262 		break;
1263 	case IRC_TYPE_LOGING_CLIENT:
1264 		return irc_dispatch_loging_client(bip, (struct link_client*)l,
1265 				line);
1266 		break;
1267 #ifdef HAVE_LIBSSL
1268 	case IRC_TYPE_TRUST_CLIENT:
1269 		return irc_dispatch_trust_client((struct link_client*)l, line);
1270 		break;
1271 #endif
1272 	default:
1273 		fatal("gnéééééé");
1274 	}
1275 	return ERR_PROTOCOL; /* never reached */
1276 }
1277 
origin_is_me(struct line * l,struct link_server * server)1278 static int origin_is_me(struct line *l, struct link_server *server)
1279 {
1280 	char *nick;
1281 
1282 	if (!l->origin)
1283 		return 0;
1284 	nick = nick_from_ircmask(l->origin);
1285 	if (strcasecmp(nick, server->nick) == 0) {
1286 		free(nick);
1287 		return 1;
1288 	}
1289 	free(nick);
1290 	return 0;
1291 }
1292 
irc_join(struct link_server * server,struct line * line)1293 static int irc_join(struct link_server *server, struct line *line)
1294 {
1295 	char *s_nick;
1296 	const char *s_chan;
1297 	struct channel *channel;
1298 
1299 	if (irc_line_count(line) != 2 && irc_line_count(line) != 3)
1300 		return ERR_PROTOCOL;
1301 
1302 	s_chan = irc_line_elem(line, 1);
1303 	log_join(LINK(server)->log, line->origin, s_chan);
1304 
1305 	channel = hash_get(&server->channels, s_chan);
1306 	if (origin_is_me(line, server)) {
1307 		if (!channel) {
1308 			channel = channel_new(s_chan);
1309 			hash_insert(&server->channels, s_chan, channel);
1310 		}
1311 		return OK_COPY;
1312 	}
1313 	/* if we're not on channel and !origin_is_me, we should not get any
1314 	 * JOIN */
1315 	if (!channel)
1316 		return ERR_PROTOCOL;
1317 	if (!line->origin)
1318 		return ERR_PROTOCOL;
1319 
1320 	s_nick = nick_from_ircmask(line->origin);
1321 	hash_insert(&channel->ovmasks, s_nick, 0);
1322 	free(s_nick);
1323 	return OK_COPY;
1324 }
1325 
irc_332(struct link_server * server,struct line * line)1326 static int irc_332(struct link_server *server, struct line *line)
1327 {
1328 	struct channel *channel;
1329 	if (irc_line_count(line) != 4)
1330 		return ERR_PROTOCOL;
1331 
1332 	channel = hash_get(&server->channels, irc_line_elem(line, 2));
1333 	/* we can get topic reply for chans we're not on */
1334 	if (!channel)
1335 		return OK_COPY;
1336 
1337 	if (channel->topic)
1338 		free(channel->topic);
1339 	channel->topic = bip_strdup(irc_line_elem(line, 3));
1340 
1341 	log_init_topic(LINK(server)->log, channel->name, channel->topic);
1342 	return OK_COPY;
1343 }
1344 
irc_333(struct link_server * server,struct line * line)1345 static int irc_333(struct link_server *server, struct line *line)
1346 {
1347 	struct channel *channel;
1348 	if (!irc_line_includes(line, 2))
1349 		return ERR_PROTOCOL;
1350 
1351 	channel = hash_get(&server->channels, irc_line_elem(line, 2));
1352 	/* we can get topic info reply for chans we're not on */
1353 	if (!channel)
1354 		return OK_COPY;
1355 	if (channel->creator)
1356 		free(channel->creator);
1357 	if (channel->create_ts)
1358 		free(channel->create_ts);
1359 	if (irc_line_count(line) == 5) {
1360 		channel->creator = bip_strdup(irc_line_elem(line, 3));
1361 		channel->create_ts = bip_strdup(irc_line_elem(line, 4));
1362 	} else {
1363 		channel->creator = bip_strdup("");
1364 		channel->create_ts = bip_strdup("0");
1365 	}
1366 	log_init_topic_time(LINK(server)->log, channel->name, channel->creator,
1367 			channel->create_ts);
1368 	return OK_COPY;
1369 }
1370 
irc_353(struct link_server * server,struct line * line)1371 static int irc_353(struct link_server *server, struct line *line)
1372 {
1373 	struct channel *channel;
1374 	const char *names, *eon;
1375 	size_t len;
1376 	char *nick;
1377 
1378 	if (irc_line_count(line) != 5)
1379 		return ERR_PROTOCOL;
1380 
1381 	channel = hash_get(&server->channels, irc_line_elem(line, 3));
1382 	/* we can get names reply for chans we're not on */
1383 	if (!channel)
1384 		return OK_COPY;
1385 
1386 	if (!channel->running_names) {
1387 		channel->running_names = 1;
1388 		hash_clean(&channel->ovmasks);
1389 	}
1390 
1391 	/* TODO check that type is one of "=" / "*" / "@" */
1392 	channel->type = irc_line_elem(line, 2)[0];
1393 
1394 	names = irc_line_elem(line, 4);
1395 
1396 	int index;
1397 	while (*names) {
1398 		long int ovmask = 0;
1399 		/* some ircds (e.g. unreal) may display several flags for the
1400                    same nick */
1401 		while ((index = bip_get_index(server->prefixes, *names))) {
1402 			ovmask |= 1 << index;
1403 			names++;
1404 		}
1405 		eon = names;
1406 		while (*eon && *eon != ' ')
1407 			eon++;
1408 
1409 		len = eon - names;
1410 		nick = bip_malloc(len + 1);
1411 		memcpy(nick, names, len);
1412 		nick[len] = 0;
1413 
1414 		/* we just ignore names for nicks that are crazy long */
1415 		if (len + 2 < NAMESIZE)
1416 			hash_insert(&channel->ovmasks, nick, (void *)ovmask);
1417 		free(nick);
1418 
1419 		while (*eon && *eon == ' ')
1420 			eon++;
1421 		names = eon;
1422 	}
1423 	return OK_COPY;
1424 }
1425 
irc_366(struct link_server * server,struct line * line)1426 static int irc_366(struct link_server *server, struct line *line)
1427 {
1428 	struct channel *channel;
1429 
1430 	if (irc_line_count(line) != 4)
1431 		return ERR_PROTOCOL;
1432 
1433 	channel = hash_get(&server->channels, irc_line_elem(line, 2));
1434 	if (channel && channel->running_names)
1435 		channel->running_names = 0;
1436 	return OK_COPY;
1437 }
1438 
irc_367(struct link_server * server,struct line * l)1439 static int irc_367(struct link_server *server, struct line *l)
1440 {
1441 	(void)server;
1442 	(void)l;
1443 	return OK_COPY_WHO;
1444 }
1445 
1446 /* same as irc_315 */
irc_368(struct link_server * server,struct line * l)1447 static int irc_368(struct link_server *server, struct line *l)
1448 {
1449 	(void)l;
1450 	struct link *link = LINK(server);
1451 	if (link->who_client) {
1452 		if (link->who_client->who_count == 0) {
1453 			mylog(LOG_DEBUG, "Spurious irc_368");
1454 			return OK_COPY_WHO;
1455 		}
1456 		link->who_client->whoc_tstamp = time(NULL);
1457 
1458 		if (link->who_client->who_count > 0) {
1459 			--link->who_client->who_count;
1460 			mylog(LOG_DEBUG,
1461 				"RPL_ENDOFBANLIST: "
1462 				"Decrementing who count for %p: %d",
1463 				link->who_client, link->who_client->who_count);
1464 		}
1465 	}
1466 
1467 	return OK_COPY_WHO;
1468 }
1469 
channel_free(struct channel * c)1470 static void channel_free(struct channel *c)
1471 {
1472 	if (c->name)
1473 		free(c->name);
1474 	if (c->mode)
1475 		free(c->mode);
1476 	if (c->key)
1477 		free(c->key);
1478 	if (c->topic)
1479 		free(c->topic);
1480 	if (c->creator)
1481 		free(c->creator);
1482 	if (c->create_ts)
1483 		free(c->create_ts);
1484 
1485 	hash_clean(&c->ovmasks);
1486 	free(c);
1487 }
1488 
irc_part(struct link_server * server,struct line * line)1489 static int irc_part(struct link_server *server, struct line *line)
1490 {
1491 	char *s_nick;
1492 	const char *s_chan;
1493 	struct channel *channel;
1494 
1495 	if (irc_line_count(line) != 2 && irc_line_count(line) != 3)
1496 		return ERR_PROTOCOL;
1497 
1498 	s_chan = irc_line_elem(line, 1);
1499 
1500 	channel = hash_get(&server->channels, s_chan);
1501 	/* we can't get part message for chans we're not on */
1502 	if (!channel)
1503 		return ERR_PROTOCOL;
1504 
1505 	if (origin_is_me(line, server)) {
1506 		log_part(LINK(server)->log, line->origin, s_chan,
1507 			irc_line_count(line) == 3 ? irc_line_elem(line, 2) :
1508 				NULL);
1509 		log_reset_store(LINK(server)->log, s_chan);
1510 		log_drop(LINK(server)->log, s_chan);
1511 
1512 		hash_remove(&server->channels, s_chan);
1513 		channel_free(channel);
1514 		return OK_COPY;
1515 	}
1516 
1517 	if (!line->origin)
1518 		return ERR_PROTOCOL;
1519 	s_nick = nick_from_ircmask(line->origin);
1520 	if (!hash_includes(&channel->ovmasks, s_nick)) {
1521 		free(s_nick);
1522 		return ERR_PROTOCOL;
1523 	}
1524 	hash_remove(&channel->ovmasks, s_nick);
1525 	free(s_nick);
1526 
1527 	log_part(LINK(server)->log, line->origin, s_chan,
1528 			irc_line_count(line) == 3 ?
1529 				irc_line_elem(line, 2) : NULL);
1530 
1531 	return OK_COPY;
1532 }
1533 
mode_add_letter_uniq(struct link_server * s,char c)1534 static void mode_add_letter_uniq(struct link_server *s, char c)
1535 {
1536 	int i;
1537 	for (i = 0; i < s->user_mode_len; i++) {
1538 		if (s->user_mode[i] == c)
1539 			return;
1540 	}
1541 	s->user_mode = bip_realloc(s->user_mode, s->user_mode_len + 1);
1542 	s->user_mode[s->user_mode_len++] = c;
1543 }
1544 
mode_remove_letter(struct link_server * s,char c)1545 static void mode_remove_letter(struct link_server *s, char c)
1546 {
1547 	int i;
1548 	for (i = 0; i < s->user_mode_len; i++) {
1549 		if (s->user_mode[i] == c) {
1550 			for (; i < s->user_mode_len - 1; i++)
1551 				s->user_mode[i] = s->user_mode[i + 1];
1552 			s->user_mode_len--;
1553 			s->user_mode = bip_realloc(s->user_mode,
1554 					s->user_mode_len);
1555 			return;
1556 		}
1557 	}
1558 }
1559 
irc_user_mode(struct link_server * server,struct line * line)1560 static void irc_user_mode(struct link_server *server, struct line *line)
1561 {
1562 	const char *mode;
1563 	int add = 1;
1564 
1565 	for (mode = irc_line_elem(line, 2); *mode; mode++) {
1566 		if (*mode == '-')
1567 			add = 0;
1568 		else if (*mode == '+')
1569 			add = 1;
1570 		else {
1571 			if (add) {
1572 				mode_add_letter_uniq(server, *mode);
1573 			} else {
1574 				mode_remove_letter(server, *mode);
1575 			}
1576 		}
1577 	}
1578 }
1579 
irc_mode(struct link_server * server,struct line * line)1580 static int irc_mode(struct link_server *server, struct line *line)
1581 {
1582 	struct channel *channel;
1583 	const char *mode;
1584 	int add = 1;
1585 	unsigned cur_arg = 0;
1586 	array_t *mode_args = NULL;
1587 	int ret;
1588 
1589 	if (!irc_line_includes(line, 2))
1590 		return ERR_PROTOCOL;
1591 
1592 	/* nick mode change */
1593 	if (irc_line_elem_equals(line, 1, server->nick)) {
1594 		if (irc_line_includes(line, 3))
1595 			mode_args = array_extract(&line->words, 3, -1);
1596 		log_mode(LINK(server)->log, line->origin,
1597 				irc_line_elem(line, 1), irc_line_elem(line, 2),
1598 				mode_args);
1599 		if (mode_args)
1600 			array_free(mode_args);
1601 		irc_user_mode(server, line);
1602 		return OK_COPY;
1603 	}
1604 
1605 	if (!ischannel(irc_line_elem(line, 1)[0]))
1606 		return ERR_PROTOCOL;
1607 
1608 	/* channel mode change */
1609 	channel = hash_get(&server->channels, irc_line_elem(line, 1));
1610 	/* we can't get mode message for chans we're not on */
1611 	if (!channel)
1612 		return ERR_PROTOCOL;
1613 
1614 	mode_args = NULL;
1615 	if (irc_line_includes(line, 3))
1616 		mode_args = array_extract(&line->words, 3, -1);
1617 	log_mode(LINK(server)->log, line->origin, irc_line_elem(line, 1),
1618 			irc_line_elem(line, 2), mode_args);
1619 	if (mode_args)
1620 		array_free(mode_args);
1621 
1622 	/*
1623 	 * MODE -a+b.. #channel args
1624 	 *         ^            ^
1625 	 *       mode         cur_arg
1626 	 */
1627 	for (mode = irc_line_elem(line, 2); *mode; mode++) {
1628 		if (*mode == '-')
1629 			add = 0;
1630 		else if (*mode == '+')
1631 			add = 1;
1632 		else {
1633 			int i = 0;
1634 			char *str = 0;
1635 
1636 			// Check if mode is known: first user modes then
1637 			// server modes
1638 			if (!(str = strchr(server->usermodes, *mode))) {
1639 				array_each(&server->chanmodes, i, str) {
1640 					if ((str = strchr(str, *mode)))
1641 						break;
1642 				}
1643 			}
1644 
1645 			if (str) {
1646 				// Usermodes, types A & B always take a parameter
1647 				// Type C take a parameter only when set
1648 				if (i <= 1 || (i == 2 && add)) {
1649 					if (!irc_line_includes(line, cur_arg + 3)) {
1650 						return ERR_PROTOCOL;
1651 					} else {
1652 						ret = irc_mode_channel(server, channel, line, mode,
1653 								add, cur_arg);
1654 						cur_arg++;
1655 					}
1656 				} else {
1657 					ret = irc_mode_channel(server, channel, line, mode, add,
1658 							cur_arg);
1659 				}
1660 			}
1661 		}
1662 		if (ret == ERR_PROTOCOL)
1663 			return ret;
1664 	}
1665 	return OK_COPY;
1666 }
1667 
irc_mode_channel(struct link_server * s,struct channel * channel,struct line * line,const char * mode,int add,int cur_arg)1668 static int irc_mode_channel(struct link_server *s, struct channel *channel,
1669 				struct line *line, const char* mode, int add, int cur_arg)
1670 {
1671 	const char *nick;
1672 	long int ovmask;
1673 	int index;
1674 
1675 	if (*mode == 'k') {
1676 		if (add) {
1677 			channel->key = bip_strdup(
1678 				irc_line_elem(line, cur_arg + 3));
1679 		} else {
1680 			if (channel->key) {
1681 				free(channel->key);
1682 				channel->key = NULL;
1683 			}
1684 		}
1685 	} else if ((index = bip_get_index(s->usermodes, *mode))) {
1686 		nick = irc_line_elem(line, cur_arg + 3);
1687 
1688 		if (!hash_includes(&channel->ovmasks, nick))
1689 			return ERR_PROTOCOL;
1690 		ovmask = (long int)hash_remove(&channel->ovmasks, nick);
1691 
1692 		if (add)
1693 			ovmask |= 1 << index;
1694 		else
1695 			ovmask &= ~(1 << index);
1696 		hash_insert(&channel->ovmasks, nick, (void *)ovmask);
1697 	}
1698 	return OK_COPY;
1699 }
1700 
irc_timestamp(void)1701 static char *irc_timestamp(void)
1702 {
1703 	char *ts = bip_malloc(21);
1704 	snprintf(ts, 20, "%ld", (long int)time(NULL));
1705 	return ts;
1706 }
1707 
irc_topic(struct link_server * server,struct line * line)1708 static int irc_topic(struct link_server *server, struct line *line)
1709 {
1710 	struct channel *channel;
1711 	const char *topic;
1712 
1713 	if (irc_line_count(line) != 3)
1714 		return ERR_PROTOCOL;
1715 
1716 	channel = hash_get(&server->channels, irc_line_elem(line, 1));
1717 	/* we can't get topic message for chans we're not on */
1718 	if (!channel)
1719 		return ERR_PROTOCOL;
1720 
1721 	if (channel->topic)
1722 		free(channel->topic);
1723 	topic = irc_line_elem(line, 2);
1724 	if (*topic == ':')
1725 		topic++;
1726 	channel->topic = bip_strdup(topic);
1727 
1728 	/*
1729 	 * :arion.oftc.net 333 bip`luser #bipqSDFQE3
1730 	 * nohar!~nohar@borne28.noc.nerim.net 1107338095
1731 	 */
1732 
1733 	if (channel->creator)
1734 		free(channel->creator);
1735 	channel->creator = bip_strmaydup(line->origin);
1736 	if (channel->create_ts)
1737 		free(channel->create_ts);
1738 	channel->create_ts = irc_timestamp();
1739 
1740 	log_topic(LINK(server)->log, line->origin, irc_line_elem(line, 1),
1741 			topic);
1742 	return OK_COPY;
1743 }
1744 
irc_kick(struct link_server * server,struct line * line)1745 static int irc_kick(struct link_server *server, struct line *line)
1746 {
1747 	struct channel *channel;
1748 
1749 	if (irc_line_count(line) != 3 && irc_line_count(line) != 4)
1750 		return ERR_PROTOCOL;
1751 
1752 	channel = hash_get(&server->channels, irc_line_elem(line, 1));
1753 	/* we can't get kick message for chans we're not on */
1754 	if (!channel)
1755 		return ERR_PROTOCOL;
1756 
1757 	if (!hash_includes(&channel->ovmasks, irc_line_elem(line, 2)))
1758 		return ERR_PROTOCOL;
1759 
1760 	if (strcasecmp(irc_line_elem(line, 2), server->nick) == 0) {
1761 		/* we get kicked !! */
1762 		log_kick(LINK(server)->log, line->origin, channel->name,
1763 				irc_line_elem(line, 2),
1764 				irc_line_count(line) == 4 ?
1765 					irc_line_elem(line, 3) : NULL);
1766 		log_reset_store(LINK(server)->log, channel->name);
1767 		log_drop(LINK(server)->log, channel->name);
1768 
1769 		if (LINK(server)->autojoin_on_kick) {
1770 			if (!channel->key)
1771 				WRITE_LINE1(CONN(server), NULL, "JOIN",
1772 						channel->name);
1773 			else
1774 				WRITE_LINE2(CONN(server), NULL, "JOIN",
1775 						channel->name, channel->key);
1776 		}
1777 
1778 		hash_remove(&server->channels, channel->name);
1779 		channel_free(channel);
1780 		return OK_COPY;
1781 	}
1782 
1783 	hash_remove(&channel->ovmasks, irc_line_elem(line, 2));
1784 	log_kick(LINK(server)->log, line->origin, irc_line_elem(line, 1),
1785 		irc_line_elem(line, 2),
1786 		irc_line_count(line) == 4 ? irc_line_elem(line, 3) : NULL);
1787 
1788 
1789 	return OK_COPY;
1790 }
1791 
irc_privmsg_check_ctcp(struct link_server * server,struct line * line)1792 static void irc_privmsg_check_ctcp(struct link_server *server,
1793 				   struct line *line)
1794 {
1795 	if (irc_line_count(line) != 3)
1796 		return;
1797 
1798 	if (!line->origin)
1799 		return;
1800 
1801 	char *nick;
1802 	nick = nick_from_ircmask(line->origin);
1803 	if (irc_line_elem_equals(line, 2, "\001VERSION\001")) {
1804 		WRITE_LINE2(CONN(server), NULL, "NOTICE", nick,
1805 				"\001VERSION bip-" PACKAGE_VERSION "\001");
1806 	}
1807 	free(nick);
1808 }
1809 
irc_privmsg(struct link_server * server,struct line * line)1810 static int irc_privmsg(struct link_server *server, struct line *line)
1811 {
1812 	if (!irc_line_includes(line, 2))
1813 		return ERR_PROTOCOL;
1814 	if (LINK(server)->s_state == IRCS_CONNECTED)
1815 		log_privmsg(LINK(server)->log, line->origin,
1816 				irc_line_elem(line, 1), irc_line_elem(line, 2));
1817 	irc_privmsg_check_ctcp(server, line);
1818 	return OK_COPY;
1819 }
1820 
irc_notice(struct link_server * server,struct line * line)1821 static int irc_notice(struct link_server *server, struct line *line)
1822 {
1823 	if (!irc_line_includes(line, 2))
1824 		return ERR_PROTOCOL;
1825 	if (LINK(server)->s_state == IRCS_CONNECTED)
1826 		log_notice(LINK(server)->log, line->origin,
1827 				irc_line_elem(line, 1), irc_line_elem(line, 2));
1828 	return OK_COPY;
1829 }
1830 
irc_quit(struct link_server * server,struct line * line)1831 static int irc_quit(struct link_server *server, struct line *line)
1832 {
1833 	return irc_generic_quit(server, line);
1834 }
1835 
irc_nick(struct link_server * server,struct line * line)1836 static int irc_nick(struct link_server *server, struct line *line)
1837 {
1838 	struct channel *channel;
1839 	hash_iterator_t hi;
1840 	char *org_nick;
1841 	const char *dst_nick;
1842 
1843 	if (irc_line_count(line) != 2)
1844 		return ERR_PROTOCOL;
1845 
1846 	if (!line->origin)
1847 		return ERR_PROTOCOL;
1848 
1849 	org_nick = nick_from_ircmask(line->origin);
1850 	dst_nick = irc_line_elem(line, 1);
1851 
1852 	for (hash_it_init(&server->channels, &hi); hash_it_item(&hi);
1853 			hash_it_next(&hi)) {
1854 		channel = hash_it_item(&hi);
1855 		if (!hash_includes(&channel->ovmasks, org_nick))
1856 			continue;
1857 		hash_rename_key(&channel->ovmasks, org_nick, dst_nick);
1858 		log_nick(LINK(server)->log, org_nick, channel->name, dst_nick);
1859 	}
1860 
1861 	if (origin_is_me(line, server)) {
1862 		free(server->nick);
1863 		server->nick = bip_strdup(dst_nick);
1864 		if (LINK(server)->follow_nick &&
1865 				(LINK(server)->away_nick == NULL ||
1866 				strcmp(server->nick, LINK(server)->away_nick))
1867 				!= 0) {
1868 			free(LINK(server)->connect_nick);
1869 			LINK(server)->connect_nick = bip_strdup(server->nick);
1870 		}
1871 	}
1872 
1873 	free(org_nick);
1874 	return OK_COPY;
1875 }
1876 
irc_generic_quit(struct link_server * server,struct line * line)1877 static int irc_generic_quit(struct link_server *server, struct line *line)
1878 {
1879 	struct channel *channel;
1880 	hash_iterator_t hi;
1881 	char *s_nick;
1882 
1883 	if (irc_line_count(line) != 2 && irc_line_count(line) != 1)
1884 		return ERR_PROTOCOL;
1885 
1886 	if (!line->origin)
1887 		return ERR_PROTOCOL;
1888 	s_nick = nick_from_ircmask(line->origin);
1889 	for (hash_it_init(&server->channels, &hi); hash_it_item(&hi);
1890 			hash_it_next(&hi)) {
1891 		channel = hash_it_item(&hi);
1892 		if (!hash_includes(&channel->ovmasks, s_nick))
1893 			continue;
1894 		hash_remove(&channel->ovmasks, s_nick);
1895 		log_quit(LINK(server)->log, line->origin, channel->name,
1896 			irc_line_includes(line, 1) ?
1897 				irc_line_elem(line, 1) : NULL);
1898 	}
1899 	free(s_nick);
1900 	return OK_COPY;
1901 }
1902 
ls_set_nick(struct link_server * ircs,char * nick)1903 static void ls_set_nick(struct link_server *ircs, char *nick)
1904 {
1905 	if (ircs->nick)
1906 		free(ircs->nick);
1907 	ircs->nick = nick;
1908 #if 0
1909 	if (ircs->ircmask) {
1910 		char *eom = strchr(ircs->ircmask, '!');
1911 		if (!eom) {
1912 			free(ircs->ircmask);
1913 			goto fake;
1914 		}
1915 		eom = bip_strdup(eom);
1916 		free(ircs->ircmask);
1917 		ircs->ircmask = bip_malloc(strlen(nick) + strlen(eom) + 1);
1918 		strcpy(ircs->ircmask, nick);
1919 		strcat(ircs->ircmask, eom);
1920 		free(eom);
1921 		return;
1922 	}
1923 fake:
1924 	ircs->ircmask = bip_malloc(strlen(nick) + strlen(BIP_FAKEMASK) + 1);
1925 	strcpy(ircs->ircmask, nick);
1926 	strcat(ircs->ircmask, BIP_FAKEMASK);
1927 #endif
1928 }
1929 
irc_server_startup(struct link_server * ircs)1930 static void irc_server_startup(struct link_server *ircs)
1931 {
1932 	char *nick;
1933 	char *username, *realname;
1934 
1935 	/* lower the token number as freenode hates fast login */
1936         CONN(ircs)->token = 1;
1937 
1938 	if (LINK(ircs)->s_password)
1939 		WRITE_LINE1(CONN(ircs), NULL, "PASS", LINK(ircs)->s_password);
1940 
1941 	username = LINK(ircs)->username;
1942 	if (!username)
1943 		username = LINK(ircs)->user->default_username;
1944 	realname = LINK(ircs)->realname;
1945 	if (!realname)
1946 		realname = LINK(ircs)->user->default_realname;
1947 	WRITE_LINE4(CONN(ircs), NULL, "USER", username, "0", "*", realname);
1948 
1949 	nick = ircs->nick;
1950 	if (LINK(ircs)->away_nick && LINK(ircs)->l_clientc == 0) {
1951 		if (nick)
1952 			free(nick);
1953 		nick = bip_strdup(LINK(ircs)->away_nick);
1954 	}
1955 	if ((!LINK(ircs)->follow_nick && !LINK(ircs)->away_nick)
1956 			|| nick == NULL) {
1957 		if (nick)
1958 			free(nick);
1959 		if (!LINK(ircs)->connect_nick)
1960 			LINK(ircs)->connect_nick =
1961 				bip_strdup(LINK(ircs)->user->default_nick);
1962 		nick = bip_strdup(LINK(ircs)->connect_nick);
1963 	}
1964 
1965 	ls_set_nick(ircs, nick);
1966 	WRITE_LINE1(CONN(ircs), NULL, "NICK", ircs->nick);
1967 }
1968 
server_next(struct link * l)1969 static void server_next(struct link *l)
1970 {
1971 	l->cur_server++;
1972 	if (l->cur_server >= l->network->serverc)
1973 		l->cur_server = 0;
1974 }
1975 
irc_accept_new(connection_t * conn)1976 static struct link_client *irc_accept_new(connection_t *conn)
1977 {
1978 	struct link_client *ircc;
1979 	connection_t *newconn;
1980 
1981 	newconn = accept_new(conn);
1982 	if (!newconn)
1983 		return NULL;
1984 
1985 	ircc = bip_calloc(sizeof(struct link_client), 1);
1986 	CONN(ircc) = newconn;
1987 	TYPE(ircc) = IRC_TYPE_LOGING_CLIENT;
1988 	CONN(ircc)->user_data = ircc;
1989 	return ircc;
1990 }
1991 
server_cleanup(struct link_server * server)1992 void server_cleanup(struct link_server *server)
1993 {
1994 	if (server->nick) {
1995 		free(server->nick);
1996 		server->nick = NULL;
1997 	}
1998 	if (LINK(server)->s_state == IRCS_CONNECTED) {
1999 		LINK(server)->s_state = IRCS_WAS_CONNECTED;
2000 	} else {
2001 		struct line *s;
2002 		LINK(server)->s_state = IRCS_NONE;
2003 		while ((s = list_remove_first(&LINK(server)->init_strings)))
2004 			irc_line_free(s);
2005 	}
2006 
2007 	hash_iterator_t hi;
2008 	for (hash_it_init(&server->channels, &hi); hash_it_item(&hi);
2009 			hash_it_next(&hi))
2010 		channel_free(hash_it_item(&hi));
2011 	hash_clean(&server->channels);
2012 
2013 	if (CONN(server)) {
2014 		connection_free(CONN(server));
2015 		CONN(server) = NULL;
2016 	}
2017 	irc_lag_init(server);
2018 }
2019 
irc_client_close(struct link_client * ic)2020 void irc_client_close(struct link_client *ic)
2021 {
2022 	if (TYPE(ic) == IRC_TYPE_CLIENT) {
2023 		struct link_server *is = LINK(ic)->l_server;
2024 		log_client_disconnected(LINK(ic)->log);
2025 		unbind_from_link(ic);
2026 		if (LINK(ic)->l_clientc == 0) {
2027 			if (is && LINK(ic)->away_nick)
2028 				WRITE_LINE1(CONN(is), NULL, "NICK",
2029 						LINK(ic)->away_nick);
2030 			if (is && LINK(ic)->no_client_away_msg)
2031 				WRITE_LINE1(CONN(is), NULL, "AWAY",
2032 						LINK(ic)->no_client_away_msg);
2033 			log_client_none_connected(LINK(ic)->log);
2034 		}
2035 		irc_client_free(ic);
2036 	} else if (TYPE(ic) == IRC_TYPE_TRUST_CLIENT) {
2037 		unbind_from_link(ic);
2038 		irc_client_free(ic);
2039 	} else if (TYPE(ic) == IRC_TYPE_LOGING_CLIENT) {
2040 		irc_client_free(ic);
2041 	}
2042 }
2043 
server_setup_reconnect_timer(struct link * link)2044 static void server_setup_reconnect_timer(struct link *link)
2045 {
2046 	int timer = 0;
2047 
2048 	if (link->last_connection_attempt &&
2049 			time(NULL) - link->last_connection_attempt
2050 				< CONN_INTERVAL) {
2051 		timer = conf_reconn_timer * (link->s_conn_attempt);
2052 		if (timer > RECONN_TIMER_MAX)
2053 			timer = RECONN_TIMER_MAX;
2054 	}
2055 	mylog(LOG_ERROR, "[%s] reconnecting in %d seconds", link->name,
2056 			timer);
2057 	link->recon_timer = timer;
2058 }
2059 
irc_close(struct link_any * l)2060 static void irc_close(struct link_any *l)
2061 {
2062 	if (CONN(l)) {
2063 		connection_free(CONN(l));
2064 		CONN(l) = NULL;
2065 	}
2066 	if (TYPE(l) == IRC_TYPE_SERVER) {
2067 		/* TODO: free link_server as a whole */
2068 		struct link_server *is = (struct link_server *)l;
2069 
2070 		if (LINK(is)->s_state == IRCS_CONNECTED)
2071 			irc_notify_disconnection(is);
2072 		irc_server_shutdown(is);
2073 		log_disconnected(LINK(is)->log);
2074 
2075 		server_next(LINK(is));
2076 		server_cleanup(is);
2077 		server_setup_reconnect_timer(LINK(is));
2078 
2079 		LINK(is)->l_server = NULL;
2080 		irc_server_free((struct link_server *)is);
2081 	} else {
2082 		irc_client_close((struct link_client *)l);
2083 	}
2084 }
2085 
irc_client_new(void)2086 struct link_client *irc_client_new(void)
2087 {
2088 	struct link_client *c;
2089 
2090 	c = bip_calloc(sizeof(struct link_client), 1);
2091 	list_init(&c->who_queue, list_ptr_cmp);
2092 
2093 	return c;
2094 }
2095 
irc_server_new(struct link * link,connection_t * conn)2096 struct link_server *irc_server_new(struct link *link, connection_t *conn)
2097 {
2098 	struct link_server *s;
2099 
2100 	s = bip_calloc(sizeof(struct link_server), 1);
2101 
2102 	TYPE(s) = IRC_TYPE_SERVER;
2103 	hash_init(&s->channels, HASH_NOCASE);
2104 
2105 	link->l_server = s;
2106 	LINK(s) = link;
2107 	CONN(s) = conn;
2108 
2109 	irc_lag_init(s);
2110 	array_init(&s->chanmodes);
2111 	s->prefixes = NULL;
2112 	s->usermodes = NULL;
2113 	server_init_modes(s);
2114 
2115 	return s;
2116 }
2117 
server_init_modes(struct link_server * s)2118 static void server_init_modes(struct link_server *s)
2119 {
2120 	// Default values used if CHANMODES is not specified by the server
2121 	array_push(&s->chanmodes, bip_strdup("beHIq"));
2122 	array_push(&s->chanmodes, bip_strdup("k"));
2123 	array_push(&s->chanmodes, bip_strdup("fjl"));
2124 	array_push(&s->chanmodes, bip_strdup("fjl"));
2125 
2126 	// Default values used if prefix is not specified by the server
2127 	s->prefixes = bip_realloc(s->prefixes, sizeof(*s->prefixes) * 3);
2128 	s->usermodes = bip_realloc(s->usermodes, sizeof(s->usermodes) * 3);
2129 	strcpy(s->prefixes, "@+");
2130 	strcpy(s->usermodes, "ov");
2131 }
2132 
irc_server_free(struct link_server * s)2133 void irc_server_free(struct link_server *s)
2134 {
2135 	if (CONN(s))
2136 		connection_free(CONN(s));
2137 	if (s->nick)
2138 		free(s->nick);
2139 	if (s->user_mode)
2140 		free(s->user_mode);
2141 
2142 	int i;
2143 	char *ptr;
2144 	array_each(&s->chanmodes, i, ptr)
2145 		free(ptr);
2146 
2147 	MAYFREE(s->prefixes);
2148 	MAYFREE(s->usermodes);
2149 
2150 	hash_iterator_t hi;
2151 	for (hash_it_init(&s->channels, &hi); hash_it_item(&hi);
2152 			hash_it_next(&hi)) {
2153 		struct channel *chan = hash_it_item(&hi);
2154 		channel_free(chan);
2155 	}
2156 	hash_clean(&s->channels);
2157 
2158 	free(s);
2159 }
2160 
irc_server_connect(struct link * link)2161 connection_t *irc_server_connect(struct link *link)
2162 {
2163 	struct link_server *ls;
2164 	connection_t *conn;
2165 
2166 	link->s_conn_attempt++;
2167 
2168 	mylog(LOG_INFO, "[%s] Connecting user '%s' using server "
2169 		"%s:%d", link->name, link->user->name,
2170 		link->network->serverv[link->cur_server].host,
2171 		link->network->serverv[link->cur_server].port);
2172 	conn = connection_new(link->network->serverv[link->cur_server].host,
2173 				link->network->serverv[link->cur_server].port,
2174 				link->vhost, link->bind_port,
2175 #ifdef HAVE_LIBSSL
2176 				link->network->ssl,
2177 				link->network->ciphers,
2178 				link->ssl_check_mode,
2179 				link->user->ssl_check_store,
2180 				link->user->ssl_client_certfile,
2181 #else
2182 				0, NULL, 0, NULL, NULL,
2183 #endif
2184 				CONNECT_TIMEOUT);
2185 	assert(conn);
2186 	if (conn->handle == -1) {
2187 		mylog(LOG_INFO, "[%s] Cannot connect.", link->name);
2188 		connection_free(conn);
2189 		server_next(link);
2190 		return NULL;
2191 	}
2192 
2193 	ls = irc_server_new(link, conn);
2194 	conn->user_data = ls;
2195 
2196 	list_add_last(&_bip->conn_list, conn);
2197 	oidentd_dump(_bip);
2198 	irc_server_startup(ls);
2199 	return conn;
2200 }
2201 
irc_server_lag_compute(struct link * l)2202 int irc_server_lag_compute(struct link *l)
2203 {
2204 	struct link_server *server = l->l_server;
2205 
2206 	if (LINK(server)->s_state == IRCS_CONNECTED) {
2207 		if (server->laginit_ts != -1) {
2208 			irc_compute_lag(server);
2209 			if (!irc_lags_out(server))
2210 				return 0;
2211 			return 1;
2212 		} else {
2213 			server->lagtest_timeout--;
2214 			if (server->lagtest_timeout == 0)
2215 				irc_start_lagtest(server);
2216 		}
2217 	}
2218 	return 0;
2219 }
2220 
irc_server_shutdown(struct link_server * s)2221 void irc_server_shutdown(struct link_server *s)
2222 {
2223 	int i;
2224 	char *cur;
2225 	array_each(&s->chanmodes, i, cur)
2226 		free(cur);
2227 	array_deinit(&s->chanmodes);
2228 
2229 	server_init_modes(s);
2230 
2231 	if (!s->nick)
2232 		return;
2233 	if (LINK(s)->prev_nick)
2234 		free(LINK(s)->prev_nick);
2235 	LINK(s)->prev_nick = bip_strdup(s->nick);
2236 }
2237 
2238 #define BIP_OIDENTD_START "## AUTOGENERATED BY BIP. DO NOT EDIT ##\n"
2239 #define BIP_OIDENTD_END "## END OF AUTOGENERATED STUFF ##\n"
2240 #define BIP_OIDENTD_END_LENGTH strlen(BIP_OIDENTD_END)
2241 
oidentd_dump(bip_t * bip)2242 void oidentd_dump(bip_t *bip)
2243 {
2244 	mylog(LOG_ERROR, "%d %s", bip->write_oidentd, bip->oidentdpath);
2245 	if (!bip->write_oidentd || bip->oidentdpath == NULL) {
2246 		return;
2247 	}
2248 	list_iterator_t it;
2249 	FILE *f;
2250 	char *bipstart = NULL, *bipend = NULL;
2251 	struct stat stats;
2252 	char tag_written = 0;
2253 
2254 	if (stat(bip->oidentdpath, &stats) == -1) {
2255 		if (errno == ENOENT && (f = fopen(bip->oidentdpath, "w+"))) {
2256 			fchmod(fileno(f), 0644);
2257 		} else {
2258 			mylog(LOG_WARN, "Can't open/create %s",
2259 					bip->oidentdpath);
2260 			return;
2261 		}
2262 	} else {
2263 		/* strip previously autogenerated content */
2264 		char *content;
2265 		f = fopen(bip->oidentdpath, "r+");
2266 
2267 		if (!f) {
2268 			mylog(LOG_WARN, "Can't open/create %s",
2269 					bip->oidentdpath);
2270 			return;
2271 		}
2272 
2273 		content = (char *)bip_malloc(stats.st_size + 1);
2274 
2275 		if (fread(content, 1, stats.st_size, f) !=
2276 				(size_t)stats.st_size) {
2277 			mylog(LOG_WARN, "Can't read %s fully",
2278 					bip->oidentdpath);
2279 			free(content);
2280 			goto clean_oidentd;
2281 		}
2282 
2283 		/* Set terminating zero for strstr */
2284 		content[stats.st_size] = '\0';
2285 
2286 		bipstart = strstr(content, BIP_OIDENTD_START);
2287 		if (bipstart != NULL) {
2288 			/* We have some config left, rewrite the file
2289 			 * completely */
2290 			fseek(f, SEEK_SET, 0);
2291 			if (ftruncate(fileno(f), 0) == -1) {
2292 				mylog(LOG_DEBUG, "Can't reset %s size",
2293 						bip->oidentdpath);
2294 				free(content);
2295 				goto clean_oidentd;
2296 			}
2297 
2298 			bipend = strstr(bipstart, BIP_OIDENTD_END);
2299 
2300 			/* data preceeding the tag */
2301 			fwrite(content, 1, bipstart - content, f);
2302 
2303 			/* data following the tag, if any */
2304 			if (bipend != NULL)
2305 				fwrite(bipend + BIP_OIDENTD_END_LENGTH, 1,
2306 						stats.st_size -
2307 						(bipend - content) -
2308 						BIP_OIDENTD_END_LENGTH, f);
2309 			else
2310 				mylog(LOG_WARN, "No %s mark found in %s",
2311 						BIP_OIDENTD_END,
2312 						bip->oidentdpath);
2313 		} else {
2314 			/* No previous conf */
2315 			if (stats.st_size != 0 &&
2316 					content[stats.st_size - 1] != '\n')
2317 				fprintf(f, "\n");
2318 		}
2319 		free(content);
2320 	}
2321 
2322 	for (list_it_init(&bip->conn_list, &it); list_it_item(&it);
2323 			list_it_next(&it)) {
2324 		connection_t *c = list_it_item(&it);
2325 		struct link_any *la = c->user_data;
2326 		if (la && TYPE(la) == IRC_TYPE_SERVER && (
2327 				c->connected == CONN_OK ||
2328 				c->connected == CONN_NEED_SSLIZE ||
2329 				c->connected == CONN_UNTRUSTED)) {
2330 			struct link_server *ls;
2331 			struct link *l;
2332 
2333 			if (!tag_written) {
2334 				fprintf(f, BIP_OIDENTD_START);
2335 				tag_written = 1;
2336 			}
2337 
2338 			ls = (struct link_server*)la;
2339 			l = LINK(ls);
2340 
2341 			fprintf(f, "to %s fport %d from %s lport %d {\n",
2342 					c->remoteip, c->remoteport, c->localip,
2343 					c->localport);
2344 			fprintf(f, "\treply \"%s\"\n", l->username);
2345 			fprintf(f, "}\n");
2346 		}
2347 	}
2348 	if (tag_written)
2349 		fprintf(f, BIP_OIDENTD_END);
2350 
2351 clean_oidentd:
2352 	fclose(f);
2353 }
2354 
timeout_clean_who_counts(list_t * conns)2355 void timeout_clean_who_counts(list_t *conns)
2356 {
2357 	list_iterator_t it;
2358 	for (list_it_init(conns, &it); list_it_item(&it); list_it_next(&it)) {
2359 		struct link *l = list_it_item(&it);
2360 		struct link_client *client = l->who_client;
2361 
2362 		if (client && client->whoc_tstamp) {
2363 			time_t now;
2364 			now = time(NULL);
2365 			if (now - client->whoc_tstamp > 10) {
2366 				mylog(LOG_DEBUG, "Yawn, "
2367 						"forgetting one who reply");
2368 				if (client->who_count > 0)
2369 					--client->who_count;
2370 				client->whoc_tstamp = time(NULL);
2371 				if (client->who_count == 0)
2372 					rotate_who_client(l);
2373 			}
2374 		}
2375 	}
2376 }
2377 
bip_init(bip_t * bip)2378 void bip_init(bip_t *bip)
2379 {
2380 	memset(bip, 0, sizeof(bip_t));
2381 	list_init(&bip->link_list, list_ptr_cmp);
2382 	list_init(&bip->conn_list, list_ptr_cmp);
2383 	list_init(&bip->connecting_client_list, list_ptr_cmp);
2384 
2385 	hash_init(&bip->users, HASH_NOCASE);
2386 	hash_init(&bip->networks, HASH_NOCASE);
2387 }
2388 
2389 /* Called each second. */
bip_tick(bip_t * bip)2390 void bip_tick(bip_t *bip)
2391 {
2392 	static int logflush_timer = 0;
2393 	struct link *link;
2394 	list_iterator_t li;
2395 
2396 	/* log flushs */
2397 	if (logflush_timer-- <= 0) {
2398 		logflush_timer = conf_log_sync_interval;
2399 		log_flush_all();
2400 	}
2401 
2402 	/* handle tick for links: detect lags or start a reconnection */
2403 	for (list_it_init(&bip->link_list, &li); (link = list_it_item(&li));
2404 			list_it_next(&li)) {
2405 		if (link->l_server) {
2406 			if (irc_server_lag_compute(link)) {
2407 				log_ping_timeout(link->log);
2408 				list_remove(&bip->conn_list,
2409 						CONN(link->l_server));
2410 				irc_close((struct link_any *) link->l_server);
2411 			}
2412 		} else {
2413 			if (link->recon_timer == 0) {
2414 				connection_t *conn;
2415 				link->last_connection_attempt = time(NULL);
2416 				conn = irc_server_connect(link);
2417 				if (!conn)
2418 					server_setup_reconnect_timer(link);
2419 			} else {
2420 				link->recon_timer--;
2421 			}
2422 		}
2423 	}
2424 
2425 	/* drop lagging connecting client */
2426 	for (list_it_init(&bip->connecting_client_list, &li); list_it_item(&li);
2427 			list_it_next(&li)) {
2428 		struct link_client *ic = list_it_item(&li);
2429 		ic->logging_timer++;
2430 		if (ic->logging_timer > LOGGING_TIMEOUT) {
2431 			if (CONN(ic))
2432 				list_remove(&bip->conn_list, CONN(ic));
2433 			irc_close((struct link_any *)ic);
2434 			list_it_remove(&li);
2435 		}
2436 	}
2437 
2438 	/*
2439 	 * Cleanup lagging or dangling who_count buffers
2440 	 */
2441 	timeout_clean_who_counts(&bip->link_list);
2442 }
2443 
bip_on_event(bip_t * bip,connection_t * conn)2444 void bip_on_event(bip_t *bip, connection_t *conn)
2445 {
2446 	struct link_any *lc = (struct link_any *)conn->user_data;
2447 
2448 	if (conn == bip->listener) {
2449 		struct link_client *n = irc_accept_new(conn);
2450 		if (n) {
2451 			list_add_last(&bip->conn_list, CONN(n));
2452 			list_add_last(&bip->connecting_client_list, n);
2453 		}
2454 		return;
2455 	}
2456 
2457 	/* reached only if socket is not listening */
2458 	int err;
2459 	list_t *linel = read_lines(conn, &err);
2460 	if (err) {
2461 		if (TYPE(lc) == IRC_TYPE_SERVER) {
2462 			mylog(LOG_ERROR, "[%s] read_lines error, closing...",
2463 					link_name(lc));
2464 			irc_server_shutdown(LINK(lc)->l_server);
2465 		} else {
2466 			mylog(LOG_ERROR, "client read_lines error, closing...");
2467 		}
2468 		goto prot_err;
2469 	}
2470 	if (!linel)
2471 		return;
2472 
2473 	char *line_s;
2474 	while ((line_s = list_remove_first(linel))) {
2475 		struct line *line;
2476 		mylog(LOG_DEBUG, "\"%s\"", line_s);
2477 		if (*line_s == 0) { /* irssi does that.*/
2478 			free(line_s);
2479 			continue;
2480 		}
2481 
2482 		line = irc_line_new_from_string(line_s);
2483 		if (!line) {
2484 			mylog(LOG_ERROR, "[%s] Error in protocol, closing...",
2485 					link_name(lc));
2486 			free(line_s);
2487 			goto prot_err_lines;
2488 		}
2489 		int r;
2490 		r = irc_dispatch(bip, lc, line);
2491 		irc_line_free(line);
2492 		free(line_s);
2493 		if (r == ERR_PROTOCOL) {
2494 			mylog(LOG_ERROR, "[%s] Error in protocol, closing...",
2495 					link_name(lc));
2496 			goto prot_err_lines;
2497 		}
2498 		if (r == ERR_AUTH)
2499 			goto prot_err_lines;
2500 		/* XXX: not real error */
2501 		if (r == OK_CLOSE)
2502 			goto prot_err_lines;
2503 
2504 	}
2505 	list_free(linel);
2506 	return;
2507 prot_err_lines:
2508 	while ((line_s = list_remove_first(linel)))
2509 		free(line_s);
2510 prot_err:
2511 	list_remove(&bip->conn_list, conn);
2512 	if (linel)
2513 		list_free(linel);
2514 	if (lc) {
2515 		if (TYPE(lc) == IRC_TYPE_LOGING_CLIENT || TYPE(lc) ==
2516 				IRC_TYPE_TRUST_CLIENT)
2517 			list_remove(&bip->connecting_client_list, lc);
2518 		irc_close(lc);
2519 	}
2520 }
2521 
2522 /*
2523  * The main loop
2524  * inc is the incoming connection, clientl list a list of client struct that
2525  * represent the accepcted credentials
2526  */
irc_main(bip_t * bip)2527 void irc_main(bip_t *bip)
2528 {
2529 	int timeleft = 1000;
2530 
2531 	if (bip->reloading_client) {
2532 		char *l;
2533 
2534 		while ((l = list_remove_first(&bip->errors)))
2535 			bip_notify(bip->reloading_client, "%s", l);
2536 		bip->reloading_client = NULL;
2537 	}
2538 
2539 	/*
2540 	 * If the list is empty, we are starting. Otherwise we are reloading,
2541 	 * and conn_list is kept accross reloads.
2542 	 */
2543 	if (list_is_empty(&bip->conn_list))
2544 		list_add_first(&bip->conn_list, bip->listener);
2545 
2546 	while (!sighup) {
2547 		connection_t *conn;
2548 
2549 		if (timeleft == 0) {
2550 			/*
2551 			 * Compute timeouts for next reconnections and lagouts
2552 			 */
2553 
2554 			timeleft = 1000;
2555 			bip_tick(bip);
2556 		}
2557 
2558 		int nc;
2559 		/* Da main loop */
2560 		list_t *ready = wait_event(&bip->conn_list, &timeleft, &nc);
2561 		if (nc)
2562 			oidentd_dump(bip);
2563 		while ((conn = list_remove_first(ready)))
2564 			bip_on_event(bip, conn);
2565 		list_free(ready);
2566 	}
2567 	while (list_remove_first(&bip->connecting_client_list))
2568 		;
2569 	return;
2570 }
2571 
irc_client_free(struct link_client * cli)2572 void irc_client_free(struct link_client *cli)
2573 {
2574 	if (CONN(cli))
2575 		connection_free(CONN(cli));
2576 	if (cli->init_pass)
2577 		free(cli->init_pass);
2578 	if (cli->init_nick)
2579 		free(cli->init_nick);
2580 	free(cli);
2581 }
2582 
irc_link_new()2583 struct link *irc_link_new()
2584 {
2585 	struct link *link;
2586 	link = bip_calloc(sizeof(struct link), 1);
2587 
2588 	link->l_server = NULL;
2589 	hash_init(&link->chan_infos, HASH_NOCASE);
2590 	list_init(&link->chan_infos_order, list_ptr_cmp);
2591 	list_init(&link->on_connect_send, list_ptr_cmp);
2592 	link->autojoin_on_kick = 1;
2593 	link->ignore_server_capab = 1;
2594 	return link;
2595 }
2596 
link_kill(bip_t * bip,struct link * link)2597 void link_kill(bip_t *bip, struct link *link)
2598 {
2599 	/* in case in never got connected */
2600 	if (link->l_server) {
2601 		list_remove(&bip->conn_list, CONN(link->l_server));
2602 		server_cleanup(link->l_server);
2603 		irc_server_free(link->l_server);
2604 	}
2605 	while (link->l_clientc) {
2606 		struct link_client *lc = link->l_clientv[0];
2607 		if (lc == bip->reloading_client)
2608 			bip->reloading_client = NULL;
2609 		list_remove(&bip->conn_list, CONN(lc));
2610 		unbind_from_link(lc);
2611 		irc_client_free(lc);
2612 	}
2613 
2614 	hash_remove(&link->user->connections, link->name);
2615 	free(link->name);
2616 	log_free(link->log);
2617 	MAYFREE(link->prev_nick);
2618 	MAYFREE(link->cli_nick);
2619 
2620 	void *p;
2621 	while ((p = list_remove_first(&link->init_strings)))
2622 		free(p);
2623 	while ((p = list_remove_first(&link->on_connect_send)))
2624 		free(p);
2625 	MAYFREE(link->no_client_away_msg);
2626 	MAYFREE(link->away_nick);
2627 	hash_clean(&link->chan_infos);
2628 
2629 	struct chan_infos *ci;
2630 	while ((ci = list_remove_first(&link->chan_infos_order)))
2631 		free(ci);
2632 
2633 	list_remove(&bip->link_list, link);
2634 
2635 	MAYFREE(link->username);
2636 	MAYFREE(link->realname);
2637 	MAYFREE(link->s_password);
2638 	MAYFREE(link->connect_nick);
2639 	MAYFREE(link->vhost);
2640 #ifdef HAVE_LIBSSL
2641 	sk_X509_free(link->untrusted_certs);
2642 #endif
2643 	free(link);
2644 }
2645 
server_set_chanmodes(struct link_server * l,const char * modes)2646 static void server_set_chanmodes(struct link_server *l, const char *modes)
2647 {
2648 	int i;
2649 	char *cur;
2650 	char *dup;
2651 
2652 	mylog(LOG_DEBUG, "[%s] Set chanmodes", LINK(l)->name);
2653 
2654 	array_each(&l->chanmodes, i, cur)
2655 		free(cur);
2656 	array_deinit(&l->chanmodes);
2657 
2658 	// handle four categories, ignore all others
2659 	for (i = 0; i < 4; i++) {
2660 		cur = strchr(modes, ',');
2661 		if (cur || modes) {
2662 			size_t len;
2663 			if (cur)
2664 				len = cur - modes;
2665 			else
2666 				len = strlen(modes); // last piece
2667 			dup = bip_malloc(len + 1);
2668 			memcpy(dup, modes, len);
2669 			dup[len] = 0;
2670 			modes = cur + 1;
2671 		} else {
2672 			// emptry string
2673 			dup = bip_calloc(1, sizeof(char));
2674 		}
2675 		mylog(LOG_DEBUGVERB, "[%s] Modes: '%s'", LINK(l)->name, dup);
2676 		array_push(&l->chanmodes, dup);
2677 	}
2678 }
2679 
2680 
server_set_prefix(struct link_server * s,const char * modes)2681 static void server_set_prefix(struct link_server *s, const char *modes)
2682 {
2683 	char * end_mode;
2684 	unsigned int len;
2685 
2686 	mylog(LOG_DEBUG, "[%s] Set user modes", LINK(s)->name);
2687 
2688 	// PREFIX=(mode)prefix
2689 
2690 	end_mode = strchr(modes + 1, ')'); // skip '('
2691 	if (*modes != '(' || !end_mode) {
2692 		mylog(LOG_WARN, "[%s] Unable to parse PREFIX parameter", LINK(s)->name);
2693 		return;
2694 	}
2695 
2696 	len = end_mode - modes - 1; // len of mode without '('
2697 	if (len * 2 + 2 != strlen(modes)) {
2698 		mylog(LOG_WARN, "[%s] Unable to parse PREFIX parameter", LINK(s)->name);
2699 		return;
2700 	}
2701 
2702 	s->prefixes = bip_realloc(s->prefixes, sizeof(*s->prefixes) * (len + 1));
2703 	s->usermodes = bip_realloc(s->usermodes, sizeof(s->usermodes) * (len + 1));
2704 
2705 	memcpy(s->usermodes, modes + 1, len);
2706 	s->usermodes[len] = 0;
2707 	memcpy(s->prefixes, end_mode + 1, len);
2708 	s->prefixes[len] = 0;
2709 
2710 	mylog(LOG_DEBUGVERB, "[%s] user prefix: '%s'", LINK(s)->name, s->prefixes);
2711 	mylog(LOG_DEBUGVERB, "[%s] user modes: '%s'", LINK(s)->name, s->usermodes);
2712 }
2713 
2714 // Return the position (*1 based*) of car in str, else -1
bip_get_index(const char * str,char car)2715 static int bip_get_index(const char* str, char car)
2716 {
2717 	char *cur;
2718 	if ((cur = strchr(str, car)))
2719 		return cur - str + 1;
2720 	else
2721 		return 0;
2722 }
2723 
bip_fls(int v)2724 static int bip_fls(int v)
2725 {
2726 	unsigned int r = 0;
2727 	while (v >>= 1)
2728 		r++;
2729 
2730 	return r;
2731 }
2732